mirror of
https://git.do.srb2.org/KartKrew/Kart-Public.git
synced 2025-01-27 11:40:52 +00:00
Merge branch 'next' into touching_fixes
This commit is contained in:
commit
5feccaad2a
55 changed files with 2692 additions and 4388 deletions
63
.circleci/config.yml
Normal file
63
.circleci/config.yml
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
version: 2
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
working_directory: /root/SRB2
|
||||||
|
docker:
|
||||||
|
- image: debian:jessie
|
||||||
|
environment:
|
||||||
|
CC: ccache gcc -m32
|
||||||
|
PKG_CONFIG_LIBDIR: /usr/lib/i386-linux-gnu/pkgconfig
|
||||||
|
LIBGME_CFLAGS: -I/usr/include
|
||||||
|
LIBGME_LDFLAGS: -lgme
|
||||||
|
CCACHE_COMPRESS: true
|
||||||
|
WFLAGS: -Wno-unsuffixed-float-constants
|
||||||
|
GCC49: true
|
||||||
|
#- image: ubuntu:trusty
|
||||||
|
# environment:
|
||||||
|
# CC: ccache gcc -m32
|
||||||
|
# PKG_CONFIG_LIBDIR: /usr/lib/i386-linux-gnu/pkgconfig
|
||||||
|
# LIBGME_CFLAGS: -I/usr/include
|
||||||
|
# LIBGME_LDFLAGS: -lgme
|
||||||
|
# CCACHE_COMPRESS: true
|
||||||
|
# WFLAGS: -Wno-unsuffixed-float-constants
|
||||||
|
# GCC48: true
|
||||||
|
steps:
|
||||||
|
- run:
|
||||||
|
name: Add i386 arch
|
||||||
|
command: dpkg --add-architecture i386
|
||||||
|
- run:
|
||||||
|
name: Update APT listing
|
||||||
|
command: apt-get -qq update
|
||||||
|
- run:
|
||||||
|
name: Support S3 upload
|
||||||
|
command: apt-get -qq -y install ca-certificates
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- v1-SRB2-APT
|
||||||
|
- run:
|
||||||
|
name: Install SDK
|
||||||
|
command: apt-get -qq -y install git build-essential nasm libpng12-dev:i386 libsdl2-mixer-dev:i386 libgme-dev:i386 gettext ccache wget gcc-multilib upx
|
||||||
|
- save_cache:
|
||||||
|
key: v1-SRB2-APT
|
||||||
|
paths:
|
||||||
|
- /var/cache/apt/archives
|
||||||
|
- checkout
|
||||||
|
- run:
|
||||||
|
name: Clean build
|
||||||
|
command: make -C src LINUX=1 clean
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- v1-SRB2-{{ .Branch }}-{{ checksum "objs/Linux/SDL/Release/depend.dep" }}
|
||||||
|
- run:
|
||||||
|
name: Compile
|
||||||
|
command: make -C src LINUX=1 ERRORMODE=1 -k
|
||||||
|
- store_artifacts:
|
||||||
|
path: /root/SRB2/bin/Linux/Release/
|
||||||
|
destination: bin
|
||||||
|
- save_cache:
|
||||||
|
key: v1-SRB2-{{ .Branch }}-{{ checksum "objs/Linux/SDL/Release/depend.dep" }}
|
||||||
|
paths:
|
||||||
|
- /root/.ccache
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.0)
|
||||||
project(SRB2
|
project(SRB2
|
||||||
VERSION 2.1.14
|
VERSION 2.1.17
|
||||||
LANGUAGES C)
|
LANGUAGES C)
|
||||||
|
|
||||||
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})
|
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
[![Build status](https://ci.appveyor.com/api/projects/status/399d4hcw9yy7hg2y?svg=true)](https://ci.appveyor.com/project/STJr/srb2)
|
[![Build status](https://ci.appveyor.com/api/projects/status/399d4hcw9yy7hg2y?svg=true)](https://ci.appveyor.com/project/STJr/srb2)
|
||||||
[![Build status](https://travis-ci.org/STJr/SRB2.svg?branch=master)](https://travis-ci.org/STJr/SRB2)
|
[![Build status](https://travis-ci.org/STJr/SRB2.svg?branch=master)](https://travis-ci.org/STJr/SRB2)
|
||||||
|
[![CircleCI](https://circleci.com/gh/STJr/SRB2/tree/master.svg?style=svg)](https://circleci.com/gh/STJr/SRB2/tree/master)
|
||||||
|
|
||||||
[Sonic Robo Blast 2](https://srb2.org/) is a 3D Sonic the Hedgehog fangame based on a modified version of [Doom Legacy](http://doomlegacy.sourceforge.net/).
|
[Sonic Robo Blast 2](https://srb2.org/) is a 3D Sonic the Hedgehog fangame based on a modified version of [Doom Legacy](http://doomlegacy.sourceforge.net/).
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
version: 2.1.16.{branch}-{build}
|
version: 2.1.17.{branch}-{build}
|
||||||
os: MinGW
|
os: MinGW
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
@ -47,7 +47,7 @@ before_build:
|
||||||
- upx -V
|
- upx -V
|
||||||
- ccache -V
|
- ccache -V
|
||||||
- ccache -s
|
- ccache -s
|
||||||
- set SRB2_MFLAGS=-C src MINGW=1 WARNINGMODE=1 GCC53=1 CCACHE=1
|
- set SRB2_MFLAGS=-C src MINGW=1 WARNINGMODE=1 GCC63=1 CCACHE=1
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
- cmd: mingw32-make.exe %SRB2_MFLAGS% %CONFIGURATION%=1 clean
|
- cmd: mingw32-make.exe %SRB2_MFLAGS% %CONFIGURATION%=1 clean
|
||||||
|
|
|
@ -390,18 +390,25 @@ if(${SRB2_CONFIG_HWRENDER} AND ${SRB2_CONFIG_STATIC_OPENGL})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(${SRB2_CONFIG_USEASM})
|
if(${SRB2_CONFIG_USEASM})
|
||||||
|
#SRB2_ASM_FLAGS can be used to pass flags to either nasm or yasm.
|
||||||
|
if(${CMAKE_SYSTEM} MATCHES "Linux")
|
||||||
|
set(SRB2_ASM_FLAGS "-DLINUX ${SRB2_ASM_FLAGS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(${SRB2_CONFIG_YASM})
|
if(${SRB2_CONFIG_YASM})
|
||||||
set(CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS} nas)
|
set(CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS} nas)
|
||||||
|
set(CMAKE_ASM_YASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.")
|
||||||
enable_language(ASM_YASM)
|
enable_language(ASM_YASM)
|
||||||
else()
|
else()
|
||||||
set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS} nas)
|
set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS} nas)
|
||||||
|
set(CMAKE_ASM_NASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.")
|
||||||
enable_language(ASM_NASM)
|
enable_language(ASM_NASM)
|
||||||
endif()
|
endif()
|
||||||
set(SRB2_USEASM ON)
|
set(SRB2_USEASM ON)
|
||||||
add_definitions(-DUSEASM)
|
add_definitions(-DUSEASM)
|
||||||
else()
|
else()
|
||||||
set(SRB2_USEASM OFF)
|
set(SRB2_USEASM OFF)
|
||||||
add_definitions(-DNOASM -DNONX86)
|
add_definitions(-DNONX86 -DNORUSEASM)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Targets
|
# Targets
|
||||||
|
|
10
src/Makefile
10
src/Makefile
|
@ -376,6 +376,14 @@ endif
|
||||||
|
|
||||||
OPTS:=-fno-exceptions $(OPTS)
|
OPTS:=-fno-exceptions $(OPTS)
|
||||||
|
|
||||||
|
ifdef MOBJCONSISTANCY
|
||||||
|
OPTS+=-DMOBJCONSISTANCY
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef PACKETDROP
|
||||||
|
OPTS+=-DPACKETDROP
|
||||||
|
endif
|
||||||
|
|
||||||
ifdef DEBUGMODE
|
ifdef DEBUGMODE
|
||||||
|
|
||||||
# build with debugging information
|
# build with debugging information
|
||||||
|
@ -385,7 +393,7 @@ ifdef GCC48
|
||||||
else
|
else
|
||||||
CFLAGS+=-O0
|
CFLAGS+=-O0
|
||||||
endif
|
endif
|
||||||
CFLAGS+= -Wall -DPARANOIA -DRANGECHECK
|
CFLAGS+= -Wall -DPARANOIA -DRANGECHECK -DPACKETDROP -DMOBJCONSISTANCY
|
||||||
else
|
else
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,23 @@
|
||||||
# and other things
|
# and other things
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
|
ifdef GCC63
|
||||||
|
GCC62=1
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef GCC62
|
||||||
|
GCC61=1
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef GCC61
|
||||||
|
GCC54=1
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef GCC54
|
||||||
|
GCC53=1
|
||||||
|
endif
|
||||||
|
|
||||||
ifdef GCC53
|
ifdef GCC53
|
||||||
GCC52=1
|
GCC52=1
|
||||||
endif
|
endif
|
||||||
|
@ -164,19 +181,29 @@ ifdef GCC45
|
||||||
WFLAGS+=-Wunsuffixed-float-constants
|
WFLAGS+=-Wunsuffixed-float-constants
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef NOLDWARNING
|
ifdef NOLDWARNING
|
||||||
LDFLAGS+=-Wl,--as-needed
|
LDFLAGS+=-Wl,--as-needed
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef ERRORMODE
|
ifdef ERRORMODE
|
||||||
WFLAGS+=-Werror
|
WFLAGS+=-Werror
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
WFLAGS+=$(OLDWFLAGS)
|
||||||
|
|
||||||
ifdef GCC43
|
ifdef GCC43
|
||||||
#WFLAGS+=-Wno-error=clobbered
|
#WFLAGS+=-Wno-error=clobbered
|
||||||
endif
|
endif
|
||||||
ifdef GCC46
|
ifdef GCC46
|
||||||
WFLAGS+=-Wno-error=suggest-attribute=noreturn
|
WFLAGS+=-Wno-error=suggest-attribute=noreturn
|
||||||
endif
|
endif
|
||||||
WFLAGS+=$(OLDWFLAGS)
|
ifdef GCC54
|
||||||
|
WFLAGS+=-Wno-logical-op -Wno-error=logical-op
|
||||||
|
endif
|
||||||
|
ifdef GCC61
|
||||||
|
WFLAGS+=-Wno-tautological-compare -Wno-error=tautological-compare
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
#indicate platform and what interface use with
|
#indicate platform and what interface use with
|
||||||
|
|
1878
src/d_clisrv.c
1878
src/d_clisrv.c
File diff suppressed because it is too large
Load diff
124
src/d_clisrv.h
124
src/d_clisrv.h
|
@ -59,7 +59,7 @@ typedef enum
|
||||||
// Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility.
|
// Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility.
|
||||||
|
|
||||||
PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL
|
PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL
|
||||||
// allows HSendPacket(,true,,) to return false.
|
// allows HSendPacket(*, true, *, *) to return false.
|
||||||
// In addition, this packet can't occupy all the available slots.
|
// In addition, this packet can't occupy all the available slots.
|
||||||
|
|
||||||
PT_FILEFRAGMENT = PT_CANFAIL, // A part of a file.
|
PT_FILEFRAGMENT = PT_CANFAIL, // A part of a file.
|
||||||
|
@ -76,11 +76,19 @@ typedef enum
|
||||||
NUMPACKETTYPE
|
NUMPACKETTYPE
|
||||||
} packettype_t;
|
} packettype_t;
|
||||||
|
|
||||||
|
#ifdef PACKETDROP
|
||||||
|
void Command_Drop(void);
|
||||||
|
void Command_Droprate(void);
|
||||||
|
#endif
|
||||||
|
#ifdef _DEBUG
|
||||||
|
void Command_Numnodes(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// client to server packet
|
// Client to server packet
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
UINT8 client_tic;
|
UINT8 client_tic;
|
||||||
|
@ -89,7 +97,7 @@ typedef struct
|
||||||
ticcmd_t cmd;
|
ticcmd_t cmd;
|
||||||
} ATTRPACK clientcmd_pak;
|
} ATTRPACK clientcmd_pak;
|
||||||
|
|
||||||
// splitscreen packet
|
// Splitscreen packet
|
||||||
// WARNING: must have the same format of clientcmd_pak, for more easy use
|
// WARNING: must have the same format of clientcmd_pak, for more easy use
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -110,16 +118,16 @@ typedef struct
|
||||||
UINT8 starttic;
|
UINT8 starttic;
|
||||||
UINT8 numtics;
|
UINT8 numtics;
|
||||||
UINT8 numslots; // "Slots filled": Highest player number in use plus one.
|
UINT8 numslots; // "Slots filled": Highest player number in use plus one.
|
||||||
ticcmd_t cmds[45]; // normally [BACKUPTIC][MAXPLAYERS] but too large
|
ticcmd_t cmds[45]; // Normally [BACKUPTIC][MAXPLAYERS] but too large
|
||||||
} ATTRPACK servertics_pak;
|
} ATTRPACK servertics_pak;
|
||||||
|
|
||||||
// sent to client when all consistency data
|
// Sent to client when all consistency data
|
||||||
// for players has been restored
|
// for players has been restored
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
UINT32 randomseed;
|
UINT32 randomseed;
|
||||||
|
|
||||||
//ctf flag stuff
|
// CTF flag stuff
|
||||||
SINT8 flagplayer[2];
|
SINT8 flagplayer[2];
|
||||||
INT32 flagloose[2];
|
INT32 flagloose[2];
|
||||||
INT32 flagflags[2];
|
INT32 flagflags[2];
|
||||||
|
@ -127,11 +135,11 @@ typedef struct
|
||||||
fixed_t flagy[2];
|
fixed_t flagy[2];
|
||||||
fixed_t flagz[2];
|
fixed_t flagz[2];
|
||||||
|
|
||||||
UINT32 ingame; // spectator bit for each player
|
UINT32 ingame; // Spectator bit for each player
|
||||||
UINT32 ctfteam; // if not spectator, then which team?
|
INT32 ctfteam[MAXPLAYERS]; // Which team? (can't be 1 bit, since in regular Match there are no teams)
|
||||||
|
|
||||||
// Resynch game scores and the like all at once
|
// Resynch game scores and the like all at once
|
||||||
UINT32 score[MAXPLAYERS]; // Everyone's score.
|
UINT32 score[MAXPLAYERS]; // Everyone's score
|
||||||
INT16 numboxes[MAXPLAYERS];
|
INT16 numboxes[MAXPLAYERS];
|
||||||
INT16 totalring[MAXPLAYERS];
|
INT16 totalring[MAXPLAYERS];
|
||||||
tic_t realtime[MAXPLAYERS];
|
tic_t realtime[MAXPLAYERS];
|
||||||
|
@ -140,14 +148,14 @@ typedef struct
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
//player stuff
|
// Player stuff
|
||||||
UINT8 playernum;
|
UINT8 playernum;
|
||||||
|
|
||||||
// Do not send anything visual related.
|
// Do not send anything visual related.
|
||||||
// Only send data that we need to know for physics.
|
// Only send data that we need to know for physics.
|
||||||
UINT8 playerstate; //playerstate_t
|
UINT8 playerstate; // playerstate_t
|
||||||
UINT32 pflags; //pflags_t
|
UINT32 pflags; // pflags_t
|
||||||
UINT8 panim; //panim_t
|
UINT8 panim; // panim_t
|
||||||
|
|
||||||
angle_t aiming;
|
angle_t aiming;
|
||||||
INT32 currentweapon;
|
INT32 currentweapon;
|
||||||
|
@ -174,9 +182,9 @@ typedef struct
|
||||||
UINT8 charability;
|
UINT8 charability;
|
||||||
UINT8 charability2;
|
UINT8 charability2;
|
||||||
UINT32 charflags;
|
UINT32 charflags;
|
||||||
UINT32 thokitem; //mobjtype_t
|
UINT32 thokitem; // mobjtype_t
|
||||||
UINT32 spinitem; //mobjtype_t
|
UINT32 spinitem; // mobjtype_t
|
||||||
UINT32 revitem; //mobjtype_t
|
UINT32 revitem; // mobjtype_t
|
||||||
fixed_t actionspd;
|
fixed_t actionspd;
|
||||||
fixed_t mindash;
|
fixed_t mindash;
|
||||||
fixed_t maxdash;
|
fixed_t maxdash;
|
||||||
|
@ -230,7 +238,7 @@ typedef struct
|
||||||
INT32 onconveyor;
|
INT32 onconveyor;
|
||||||
|
|
||||||
//player->mo stuff
|
//player->mo stuff
|
||||||
UINT8 hasmo; //boolean
|
UINT8 hasmo; // Boolean
|
||||||
|
|
||||||
angle_t angle;
|
angle_t angle;
|
||||||
fixed_t x;
|
fixed_t x;
|
||||||
|
@ -257,10 +265,10 @@ typedef struct
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
UINT8 version; // different versions don't work
|
UINT8 version; // Different versions don't work
|
||||||
UINT8 subversion; // contains build version
|
UINT8 subversion; // Contains build version
|
||||||
|
|
||||||
// server launch stuffs
|
// Server launch stuffs
|
||||||
UINT8 serverplayer;
|
UINT8 serverplayer;
|
||||||
UINT8 totalslotnum; // "Slots": highest player number in use plus one.
|
UINT8 totalslotnum; // "Slots": highest player number in use plus one.
|
||||||
|
|
||||||
|
@ -274,18 +282,18 @@ typedef struct
|
||||||
|
|
||||||
UINT8 gametype;
|
UINT8 gametype;
|
||||||
UINT8 modifiedgame;
|
UINT8 modifiedgame;
|
||||||
SINT8 adminplayer; // needs to be signed
|
SINT8 adminplayer; // Needs to be signed
|
||||||
|
|
||||||
char server_context[8]; // unique context id, generated at server startup.
|
char server_context[8]; // Unique context id, generated at server startup.
|
||||||
|
|
||||||
UINT8 varlengthinputs[0]; // playernames and netvars
|
UINT8 varlengthinputs[0]; // Playernames and netvars
|
||||||
} ATTRPACK serverconfig_pak;
|
} ATTRPACK serverconfig_pak;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
UINT8 fileid;
|
UINT8 fileid;
|
||||||
UINT32 position;
|
UINT32 position;
|
||||||
UINT16 size;
|
UINT16 size;
|
||||||
UINT8 data[0]; // size is variable using hardware_MAXPACKETLENGTH
|
UINT8 data[0]; // Size is variable using hardware_MAXPACKETLENGTH
|
||||||
} ATTRPACK filetx_pak;
|
} ATTRPACK filetx_pak;
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
@ -294,14 +302,14 @@ typedef struct {
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
UINT8 version; // different versions don't work
|
UINT8 version; // Different versions don't work
|
||||||
UINT8 subversion; // contains build version
|
UINT8 subversion; // Contains build version
|
||||||
UINT8 localplayers;
|
UINT8 localplayers;
|
||||||
UINT8 mode;
|
UINT8 mode;
|
||||||
} ATTRPACK clientconfig_pak;
|
} ATTRPACK clientconfig_pak;
|
||||||
|
|
||||||
#define MAXSERVERNAME 32
|
#define MAXSERVERNAME 32
|
||||||
// this packet is too large
|
// This packet is too large
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
UINT8 version;
|
UINT8 version;
|
||||||
|
@ -367,45 +375,45 @@ typedef struct
|
||||||
} ATTRPACK plrconfig;
|
} ATTRPACK plrconfig;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Network packet data.
|
// Network packet data
|
||||||
//
|
//
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
UINT32 checksum;
|
UINT32 checksum;
|
||||||
UINT8 ack; // if not null the node asks for acknowledgement, the receiver must resend the ack
|
UINT8 ack; // If not zero the node asks for acknowledgement, the receiver must resend the ack
|
||||||
UINT8 ackreturn; // the return of the ack number
|
UINT8 ackreturn; // The return of the ack number
|
||||||
|
|
||||||
UINT8 packettype;
|
UINT8 packettype;
|
||||||
UINT8 reserved; // padding
|
UINT8 reserved; // Padding
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
clientcmd_pak clientpak; // 144 bytes
|
clientcmd_pak clientpak; // 144 bytes
|
||||||
client2cmd_pak client2pak; // 200 bytes
|
client2cmd_pak client2pak; // 200 bytes
|
||||||
servertics_pak serverpak; // 132495 bytes
|
servertics_pak serverpak; // 132495 bytes (more around 360, no?)
|
||||||
serverconfig_pak servercfg; // 773 bytes
|
serverconfig_pak servercfg; // 773 bytes
|
||||||
resynchend_pak resynchend; //
|
resynchend_pak resynchend; //
|
||||||
resynch_pak resynchpak; //
|
resynch_pak resynchpak; //
|
||||||
UINT8 resynchgot; //
|
UINT8 resynchgot; //
|
||||||
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes
|
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...)
|
||||||
filetx_pak filetxpak; // 139 bytes
|
filetx_pak filetxpak; // 139 bytes
|
||||||
clientconfig_pak clientcfg; // 136 bytes
|
clientconfig_pak clientcfg; // 136 bytes
|
||||||
serverinfo_pak serverinfo; // 1024 bytes
|
serverinfo_pak serverinfo; // 1024 bytes
|
||||||
serverrefuse_pak serverrefuse; // 65025 bytes
|
serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...)
|
||||||
askinfo_pak askinfo; // 61 bytes
|
askinfo_pak askinfo; // 61 bytes
|
||||||
msaskinfo_pak msaskinfo; // 22 bytes
|
msaskinfo_pak msaskinfo; // 22 bytes
|
||||||
plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes
|
plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes (I'd say 36~38)
|
||||||
plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes
|
plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes (welp they ARE)
|
||||||
#ifdef NEWPING
|
#ifdef NEWPING
|
||||||
UINT32 pingtable[MAXPLAYERS]; // 128 bytes
|
UINT32 pingtable[MAXPLAYERS]; // 128 bytes
|
||||||
#endif
|
#endif
|
||||||
} u; // this is needed to pack diff packet types data together
|
} u; // This is needed to pack diff packet types data together
|
||||||
} ATTRPACK doomdata_t;
|
} ATTRPACK doomdata_t;
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAXSERVERLIST 64 // depends only on the display
|
#define MAXSERVERLIST 64 // Depends only on the display
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
SINT8 node;
|
SINT8 node;
|
||||||
|
@ -416,7 +424,7 @@ extern serverelem_t serverlist[MAXSERVERLIST];
|
||||||
extern UINT32 serverlistcount;
|
extern UINT32 serverlistcount;
|
||||||
extern INT32 mapchangepending;
|
extern INT32 mapchangepending;
|
||||||
|
|
||||||
// points inside doomcom
|
// Points inside doomcom
|
||||||
extern doomdata_t *netbuffer;
|
extern doomdata_t *netbuffer;
|
||||||
|
|
||||||
extern consvar_t cv_playbackspeed;
|
extern consvar_t cv_playbackspeed;
|
||||||
|
@ -437,26 +445,28 @@ extern consvar_t cv_playbackspeed;
|
||||||
#define KICK_MSG_CUSTOM_BAN 8
|
#define KICK_MSG_CUSTOM_BAN 8
|
||||||
|
|
||||||
extern boolean server;
|
extern boolean server;
|
||||||
extern boolean dedicated; // for dedicated server
|
#define client (!server)
|
||||||
|
extern boolean dedicated; // For dedicated server
|
||||||
extern UINT16 software_MAXPACKETLENGTH;
|
extern UINT16 software_MAXPACKETLENGTH;
|
||||||
extern boolean acceptnewnode;
|
extern boolean acceptnewnode;
|
||||||
extern SINT8 servernode;
|
extern SINT8 servernode;
|
||||||
|
|
||||||
void Command_Ping_f(void);
|
void Command_Ping_f(void);
|
||||||
extern tic_t connectiontimeout;
|
extern tic_t connectiontimeout;
|
||||||
|
extern tic_t jointimeout;
|
||||||
#ifdef NEWPING
|
#ifdef NEWPING
|
||||||
extern UINT16 pingmeasurecount;
|
extern UINT16 pingmeasurecount;
|
||||||
extern UINT32 realpingtable[MAXPLAYERS];
|
extern UINT32 realpingtable[MAXPLAYERS];
|
||||||
extern UINT32 playerpingtable[MAXPLAYERS];
|
extern UINT32 playerpingtable[MAXPLAYERS];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend;
|
extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed;
|
||||||
|
|
||||||
// used in d_net, the only dependence
|
// Used in d_net, the only dependence
|
||||||
tic_t ExpandTics(INT32 low);
|
tic_t ExpandTics(INT32 low);
|
||||||
void D_ClientServerInit(void);
|
void D_ClientServerInit(void);
|
||||||
|
|
||||||
// initialise the other field
|
// Initialise the other field
|
||||||
void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum));
|
void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum));
|
||||||
void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam);
|
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 SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player
|
||||||
|
@ -474,14 +484,14 @@ void CL_RemoveSplitscreenPlayer(void);
|
||||||
void CL_Reset(void);
|
void CL_Reset(void);
|
||||||
void CL_ClearPlayer(INT32 playernum);
|
void CL_ClearPlayer(INT32 playernum);
|
||||||
void CL_UpdateServerList(boolean internetsearch, INT32 room);
|
void CL_UpdateServerList(boolean internetsearch, INT32 room);
|
||||||
// is there a game running
|
// Is there a game running
|
||||||
boolean Playing(void);
|
boolean Playing(void);
|
||||||
|
|
||||||
// Broadcasts special packets to other players
|
// Broadcasts special packets to other players
|
||||||
// to notify of game exit
|
// to notify of game exit
|
||||||
void D_QuitNetGame(void);
|
void D_QuitNetGame(void);
|
||||||
|
|
||||||
//? how many ticks to run?
|
//? How many ticks to run?
|
||||||
void TryRunTics(tic_t realtic);
|
void TryRunTics(tic_t realtic);
|
||||||
|
|
||||||
// extra data for lmps
|
// extra data for lmps
|
||||||
|
|
|
@ -187,7 +187,7 @@ UINT8 altdown = 0; // 0x1 left, 0x2 right
|
||||||
//
|
//
|
||||||
static inline void D_ModifierKeyResponder(event_t *ev)
|
static inline void D_ModifierKeyResponder(event_t *ev)
|
||||||
{
|
{
|
||||||
if (ev->type == ev_keydown) switch (ev->data1)
|
if (ev->type == ev_keydown || ev->type == ev_console) switch (ev->data1)
|
||||||
{
|
{
|
||||||
case KEY_LSHIFT: shiftdown |= 0x1; return;
|
case KEY_LSHIFT: shiftdown |= 0x1; return;
|
||||||
case KEY_RSHIFT: shiftdown |= 0x2; return;
|
case KEY_RSHIFT: shiftdown |= 0x2; return;
|
||||||
|
|
424
src/d_net.c
424
src/d_net.c
|
@ -31,18 +31,18 @@
|
||||||
//
|
//
|
||||||
// NETWORKING
|
// NETWORKING
|
||||||
//
|
//
|
||||||
// gametic is the tic about to be (or currently being) run
|
// gametic is the tic about to (or currently being) run
|
||||||
// server:
|
// Server:
|
||||||
// maketic is the tic that hasn't had control made for it yet
|
// maketic is the tic that hasn't had control made for it yet
|
||||||
// nettics: is the tic for each node
|
// nettics is the tic for each node
|
||||||
// firsttictosend: is the lowest value of nettics
|
// firstticstosend is the lowest value of nettics
|
||||||
// client:
|
// Client:
|
||||||
// neededtic: is the tic needed by the client to run the game
|
// neededtic is the tic needed by the client to run the game
|
||||||
// firsttictosend: is used to optimize a condition
|
// firstticstosend is used to optimize a condition
|
||||||
// normally maketic >= gametic > 0
|
// Normally maketic >= gametic > 0
|
||||||
|
|
||||||
#define FORCECLOSE 0x8000
|
#define FORCECLOSE 0x8000
|
||||||
tic_t connectiontimeout = (15*TICRATE);
|
tic_t connectiontimeout = (10*TICRATE);
|
||||||
|
|
||||||
/// \brief network packet
|
/// \brief network packet
|
||||||
doomcom_t *doomcom = NULL;
|
doomcom_t *doomcom = NULL;
|
||||||
|
@ -62,7 +62,7 @@ INT32 net_bandwidth;
|
||||||
/// \brief max length per packet
|
/// \brief max length per packet
|
||||||
INT16 hardware_MAXPACKETLENGTH;
|
INT16 hardware_MAXPACKETLENGTH;
|
||||||
|
|
||||||
void (*I_NetGet)(void) = NULL;
|
boolean (*I_NetGet)(void) = NULL;
|
||||||
void (*I_NetSend)(void) = NULL;
|
void (*I_NetSend)(void) = NULL;
|
||||||
boolean (*I_NetCanSend)(void) = NULL;
|
boolean (*I_NetCanSend)(void) = NULL;
|
||||||
boolean (*I_NetCanGet)(void) = NULL;
|
boolean (*I_NetCanGet)(void) = NULL;
|
||||||
|
@ -129,9 +129,9 @@ boolean Net_GetNetStat(void)
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
// Some structs and functions for acknowledgement of packets
|
// Some structs and functions for acknowledgement of packets
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
#define MAXACKPACKETS 96 // minimum number of nodes
|
#define MAXACKPACKETS 96 // Minimum number of nodes (wat)
|
||||||
#define MAXACKTOSEND 96
|
#define MAXACKTOSEND 96
|
||||||
#define URGENTFREESLOTENUM 10
|
#define URGENTFREESLOTNUM 10
|
||||||
#define ACKTOSENDTIMEOUT (TICRATE/11)
|
#define ACKTOSENDTIMEOUT (TICRATE/11)
|
||||||
|
|
||||||
#ifndef NONET
|
#ifndef NONET
|
||||||
|
@ -139,10 +139,10 @@ typedef struct
|
||||||
{
|
{
|
||||||
UINT8 acknum;
|
UINT8 acknum;
|
||||||
UINT8 nextacknum;
|
UINT8 nextacknum;
|
||||||
UINT8 destinationnode;
|
UINT8 destinationnode; // The node to send the ack to
|
||||||
tic_t senttime;
|
tic_t senttime; // The time when the ack was sent
|
||||||
UINT16 length;
|
UINT16 length; // The packet size
|
||||||
UINT16 resentnum;
|
UINT16 resentnum; // The number of times the ack has been resent
|
||||||
union {
|
union {
|
||||||
SINT8 raw[MAXPACKETLENGTH];
|
SINT8 raw[MAXPACKETLENGTH];
|
||||||
doomdata_t data;
|
doomdata_t data;
|
||||||
|
@ -152,11 +152,12 @@ typedef struct
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
CLOSE = 1, // flag is set when connection is closing
|
NF_CLOSE = 1, // Flag is set when connection is closing
|
||||||
|
NF_TIMEOUT = 2, // Flag is set when the node got a timeout
|
||||||
} node_flags_t;
|
} node_flags_t;
|
||||||
|
|
||||||
#ifndef NONET
|
#ifndef NONET
|
||||||
// table of packet that was not acknowleged can be resend (the sender window)
|
// Table of packets that were not acknowleged can be resent (the sender window)
|
||||||
static ackpak_t ackpak[MAXACKPACKETS];
|
static ackpak_t ackpak[MAXACKPACKETS];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -212,11 +213,16 @@ FUNCMATH static INT32 cmpack(UINT8 a, UINT8 b)
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return a free acknum and copy netbuffer in the ackpak table
|
/** Sets freeack to a free acknum and copies the netbuffer in the ackpak table
|
||||||
|
*
|
||||||
|
* \param freeack The address to store the free acknum at
|
||||||
|
* \param lowtimer ???
|
||||||
|
* \return True if a free acknum was found
|
||||||
|
*/
|
||||||
static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
||||||
{
|
{
|
||||||
node_t *node = &nodes[doomcom->remotenode];
|
node_t *node = &nodes[doomcom->remotenode];
|
||||||
INT32 i, numfreeslote = 0;
|
INT32 i, numfreeslot = 0;
|
||||||
|
|
||||||
if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0)
|
if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0)
|
||||||
{
|
{
|
||||||
|
@ -227,10 +233,13 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
||||||
for (i = 0; i < MAXACKPACKETS; i++)
|
for (i = 0; i < MAXACKPACKETS; i++)
|
||||||
if (!ackpak[i].acknum)
|
if (!ackpak[i].acknum)
|
||||||
{
|
{
|
||||||
// for low priority packet, make sure let freeslotes so urgents packets can be sent
|
// For low priority packets, make sure to let freeslots so urgent packets can be sent
|
||||||
numfreeslote++;
|
if (netbuffer->packettype >= PT_CANFAIL)
|
||||||
if (netbuffer->packettype >= PT_CANFAIL && numfreeslote < URGENTFREESLOTENUM)
|
{
|
||||||
continue;
|
numfreeslot++;
|
||||||
|
if (numfreeslot <= URGENTFREESLOTNUM)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
ackpak[i].acknum = node->nextacknum;
|
ackpak[i].acknum = node->nextacknum;
|
||||||
ackpak[i].nextacknum = node->nextacknum;
|
ackpak[i].nextacknum = node->nextacknum;
|
||||||
|
@ -241,7 +250,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
||||||
ackpak[i].length = doomcom->datalength;
|
ackpak[i].length = doomcom->datalength;
|
||||||
if (lowtimer)
|
if (lowtimer)
|
||||||
{
|
{
|
||||||
// lowtime mean can't be sent now so try it soon as possible
|
// Lowtime means can't be sent now so try it as soon as possible
|
||||||
ackpak[i].senttime = 0;
|
ackpak[i].senttime = 0;
|
||||||
ackpak[i].resentnum = 1;
|
ackpak[i].resentnum = 1;
|
||||||
}
|
}
|
||||||
|
@ -254,7 +263,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
||||||
|
|
||||||
*freeack = ackpak[i].acknum;
|
*freeack = ackpak[i].acknum;
|
||||||
|
|
||||||
sendackpacket++; // for stat
|
sendackpacket++; // For stat
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -266,14 +275,46 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a ack to send in the queu of this node
|
/** Counts how many acks are free
|
||||||
|
*
|
||||||
|
* \param urgent True if the type of the packet meant to
|
||||||
|
* use an ack is lower than PT_CANFAIL
|
||||||
|
* If for some reason you don't want use it
|
||||||
|
* for any packet type in particular,
|
||||||
|
* just set to false
|
||||||
|
* \return The number of free acks
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
INT32 Net_GetFreeAcks(boolean urgent)
|
||||||
|
{
|
||||||
|
INT32 i, numfreeslot = 0;
|
||||||
|
INT32 n = 0; // Number of free acks found
|
||||||
|
|
||||||
|
for (i = 0; i < MAXACKPACKETS; i++)
|
||||||
|
if (!ackpak[i].acknum)
|
||||||
|
{
|
||||||
|
// For low priority packets, make sure to let freeslots so urgent packets can be sent
|
||||||
|
if (!urgent)
|
||||||
|
{
|
||||||
|
numfreeslot++;
|
||||||
|
if (numfreeslot <= URGENTFREESLOTNUM)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a ack to send in the queue of this node
|
||||||
static UINT8 GetAcktosend(INT32 node)
|
static UINT8 GetAcktosend(INT32 node)
|
||||||
{
|
{
|
||||||
nodes[node].lasttimeacktosend_sent = I_GetTime();
|
nodes[node].lasttimeacktosend_sent = I_GetTime();
|
||||||
return nodes[node].firstacktosend;
|
return nodes[node].firstacktosend;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Removeack(INT32 i)
|
static void RemoveAck(INT32 i)
|
||||||
{
|
{
|
||||||
INT32 node = ackpak[i].destinationnode;
|
INT32 node = ackpak[i].destinationnode;
|
||||||
#ifndef NEWPING
|
#ifndef NEWPING
|
||||||
|
@ -290,31 +331,31 @@ static void Removeack(INT32 i)
|
||||||
DEBFILE(va("Remove ack %d\n",ackpak[i].acknum));
|
DEBFILE(va("Remove ack %d\n",ackpak[i].acknum));
|
||||||
#endif
|
#endif
|
||||||
ackpak[i].acknum = 0;
|
ackpak[i].acknum = 0;
|
||||||
if (nodes[node].flags & CLOSE)
|
if (nodes[node].flags & NF_CLOSE)
|
||||||
Net_CloseConnection(node);
|
Net_CloseConnection(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we have got a packet proceed the ack request and ack return
|
// We have got a packet, proceed the ack request and ack return
|
||||||
static boolean Processackpak(void)
|
static boolean Processackpak(void)
|
||||||
{
|
{
|
||||||
INT32 i;
|
INT32 i;
|
||||||
boolean goodpacket = true;
|
boolean goodpacket = true;
|
||||||
node_t *node = &nodes[doomcom->remotenode];
|
node_t *node = &nodes[doomcom->remotenode];
|
||||||
|
|
||||||
// received an ack return, so remove the ack in the list
|
// Received an ack return, so remove the ack in the list
|
||||||
if (netbuffer->ackreturn && cmpack(node->remotefirstack, netbuffer->ackreturn) < 0)
|
if (netbuffer->ackreturn && cmpack(node->remotefirstack, netbuffer->ackreturn) < 0)
|
||||||
{
|
{
|
||||||
node->remotefirstack = netbuffer->ackreturn;
|
node->remotefirstack = netbuffer->ackreturn;
|
||||||
// search the ackbuffer and free it
|
// Search the ackbuffer and free it
|
||||||
for (i = 0; i < MAXACKPACKETS; i++)
|
for (i = 0; i < MAXACKPACKETS; i++)
|
||||||
if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes
|
if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes
|
||||||
&& cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0)
|
&& cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0)
|
||||||
{
|
{
|
||||||
Removeack(i);
|
RemoveAck(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// received a packet with ack, queue it to send the ack back
|
// Received a packet with ack, queue it to send the ack back
|
||||||
if (netbuffer->ack)
|
if (netbuffer->ack)
|
||||||
{
|
{
|
||||||
UINT8 ack = netbuffer->ack;
|
UINT8 ack = netbuffer->ack;
|
||||||
|
@ -323,23 +364,23 @@ static boolean Processackpak(void)
|
||||||
{
|
{
|
||||||
DEBFILE(va("Discard(1) ack %d (duplicated)\n", ack));
|
DEBFILE(va("Discard(1) ack %d (duplicated)\n", ack));
|
||||||
duppacket++;
|
duppacket++;
|
||||||
goodpacket = false; // discard packet (duplicate)
|
goodpacket = false; // Discard packet (duplicate)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// check if it is not already in the queue
|
// Check if it is not already in the queue
|
||||||
for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND)
|
for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND)
|
||||||
if (node->acktosend[i] == ack)
|
if (node->acktosend[i] == ack)
|
||||||
{
|
{
|
||||||
DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack));
|
DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack));
|
||||||
duppacket++;
|
duppacket++;
|
||||||
goodpacket = false; // discard packet (duplicate)
|
goodpacket = false; // Discard packet (duplicate)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (goodpacket)
|
if (goodpacket)
|
||||||
{
|
{
|
||||||
// is a good packet so increment the acknowledge number,
|
// Is a good packet so increment the acknowledge number,
|
||||||
// then search for a "hole" in the queue
|
// Then search for a "hole" in the queue
|
||||||
UINT8 nextfirstack = (UINT8)(node->firstacktosend + 1);
|
UINT8 nextfirstack = (UINT8)(node->firstacktosend + 1);
|
||||||
if (!nextfirstack)
|
if (!nextfirstack)
|
||||||
nextfirstack = 1;
|
nextfirstack = 1;
|
||||||
|
@ -383,10 +424,10 @@ static boolean Processackpak(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // out of order packet
|
else // Out of order packet
|
||||||
{
|
{
|
||||||
// don't increment firsacktosend, put it in asktosend queue
|
// Don't increment firsacktosend, put it in asktosend queue
|
||||||
// will be incremented when the nextfirstack comes (code above)
|
// Will be incremented when the nextfirstack comes (code above)
|
||||||
UINT8 newhead = (UINT8)((node->acktosend_head+1) % MAXACKTOSEND);
|
UINT8 newhead = (UINT8)((node->acktosend_head+1) % MAXACKTOSEND);
|
||||||
DEBFILE(va("out of order packet (%d expected)\n", nextfirstack));
|
DEBFILE(va("out of order packet (%d expected)\n", nextfirstack));
|
||||||
if (newhead != node->acktosend_tail)
|
if (newhead != node->acktosend_tail)
|
||||||
|
@ -394,8 +435,8 @@ static boolean Processackpak(void)
|
||||||
node->acktosend[node->acktosend_head] = ack;
|
node->acktosend[node->acktosend_head] = ack;
|
||||||
node->acktosend_head = newhead;
|
node->acktosend_head = newhead;
|
||||||
}
|
}
|
||||||
else // buffer full discard packet, sender will resend it
|
else // Buffer full discard packet, sender will resend it
|
||||||
{ // we can admit the packet but we will not detect the duplication after :(
|
{ // We can admit the packet but we will not detect the duplication after :(
|
||||||
DEBFILE("no more freeackret\n");
|
DEBFILE("no more freeackret\n");
|
||||||
goodpacket = false;
|
goodpacket = false;
|
||||||
}
|
}
|
||||||
|
@ -430,25 +471,29 @@ static void GotAcks(void)
|
||||||
if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode)
|
if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode)
|
||||||
{
|
{
|
||||||
if (ackpak[i].acknum == netbuffer->u.textcmd[j])
|
if (ackpak[i].acknum == netbuffer->u.textcmd[j])
|
||||||
Removeack(i);
|
RemoveAck(i);
|
||||||
else
|
// nextacknum is first equal to acknum, then when receiving bigger ack
|
||||||
// nextacknum is first equal to acknum, then when receiving bigger ack
|
// there is big chance the packet is lost
|
||||||
// there is big chance the packet is lost
|
// When resent, nextacknum = nodes[node].nextacknum
|
||||||
// when resent, nextacknum = nodes[node].nextacknum
|
// will redo the same but with different value
|
||||||
// will redo the same but with different value
|
else if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0
|
||||||
if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0
|
&& ackpak[i].senttime > 0)
|
||||||
&& ackpak[i].senttime > 0)
|
{
|
||||||
{
|
ackpak[i].senttime--; // hurry up
|
||||||
ackpak[i].senttime--; // hurry up
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline void Net_ConnectionTimeout(INT32 node)
|
void Net_ConnectionTimeout(INT32 node)
|
||||||
{
|
{
|
||||||
// send a very special packet to self (hack the reboundstore queue)
|
// Don't timeout several times
|
||||||
// main code will handle it
|
if (nodes[node].flags & NF_TIMEOUT)
|
||||||
|
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].packettype = PT_NODETIMEOUT;
|
||||||
reboundstore[rebound_head].ack = 0;
|
reboundstore[rebound_head].ack = 0;
|
||||||
reboundstore[rebound_head].ackreturn = 0;
|
reboundstore[rebound_head].ackreturn = 0;
|
||||||
|
@ -456,12 +501,12 @@ static inline void Net_ConnectionTimeout(INT32 node)
|
||||||
reboundsize[rebound_head] = (INT16)(BASEPACKETSIZE + 1);
|
reboundsize[rebound_head] = (INT16)(BASEPACKETSIZE + 1);
|
||||||
rebound_head = (rebound_head+1) % MAXREBOUND;
|
rebound_head = (rebound_head+1) % MAXREBOUND;
|
||||||
|
|
||||||
// do not redo it quickly (if we do not close connection it is
|
// Do not redo it quickly (if we do not close connection it is
|
||||||
// for a good reason!)
|
// for a good reason!)
|
||||||
nodes[node].lasttimepacketreceived = I_GetTime();
|
nodes[node].lasttimepacketreceived = I_GetTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
// resend the data if needed
|
// Resend the data if needed
|
||||||
void Net_AckTicker(void)
|
void Net_AckTicker(void)
|
||||||
{
|
{
|
||||||
#ifndef NONET
|
#ifndef NONET
|
||||||
|
@ -477,7 +522,7 @@ void Net_AckTicker(void)
|
||||||
if (ackpak[i].acknum && ackpak[i].senttime + node->timeout < I_GetTime())
|
if (ackpak[i].acknum && ackpak[i].senttime + node->timeout < I_GetTime())
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (ackpak[i].resentnum > 10 && (node->flags & CLOSE))
|
if (ackpak[i].resentnum > 10 && (node->flags & NF_CLOSE))
|
||||||
{
|
{
|
||||||
DEBFILE(va("ack %d sent 10 times so connection is supposed lost: node %d\n",
|
DEBFILE(va("ack %d sent 10 times so connection is supposed lost: node %d\n",
|
||||||
i, nodei));
|
i, nodei));
|
||||||
|
@ -497,7 +542,7 @@ void Net_AckTicker(void)
|
||||||
ackpak[i].senttime = I_GetTime();
|
ackpak[i].senttime = I_GetTime();
|
||||||
ackpak[i].resentnum++;
|
ackpak[i].resentnum++;
|
||||||
ackpak[i].nextacknum = node->nextacknum;
|
ackpak[i].nextacknum = node->nextacknum;
|
||||||
retransmit++; // for stat
|
retransmit++; // For stat
|
||||||
HSendPacket((INT32)(node - nodes), false, ackpak[i].acknum,
|
HSendPacket((INT32)(node - nodes), false, ackpak[i].acknum,
|
||||||
(size_t)(ackpak[i].length - BASEPACKETSIZE));
|
(size_t)(ackpak[i].length - BASEPACKETSIZE));
|
||||||
}
|
}
|
||||||
|
@ -505,15 +550,15 @@ void Net_AckTicker(void)
|
||||||
|
|
||||||
for (i = 1; i < MAXNETNODES; i++)
|
for (i = 1; i < MAXNETNODES; i++)
|
||||||
{
|
{
|
||||||
// this is something like node open flag
|
// This is something like node open flag
|
||||||
if (nodes[i].firstacktosend)
|
if (nodes[i].firstacktosend)
|
||||||
{
|
{
|
||||||
// we haven't sent a packet for a long time
|
// We haven't sent a packet for a long time
|
||||||
// acknowledge packet if needed
|
// Acknowledge packet if needed
|
||||||
if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime())
|
if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime())
|
||||||
Net_SendAcks(i);
|
Net_SendAcks(i);
|
||||||
|
|
||||||
if (!(nodes[i].flags & CLOSE)
|
if (!(nodes[i].flags & NF_CLOSE)
|
||||||
&& nodes[i].lasttimepacketreceived + connectiontimeout < I_GetTime())
|
&& nodes[i].lasttimepacketreceived + connectiontimeout < I_GetTime())
|
||||||
{
|
{
|
||||||
Net_ConnectionTimeout(i);
|
Net_ConnectionTimeout(i);
|
||||||
|
@ -523,9 +568,9 @@ void Net_AckTicker(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove last packet received ack before resending the ackret
|
// Remove last packet received ack before resending the ackreturn
|
||||||
// (the higher layer doesn't have room, or something else ....)
|
// (the higher layer doesn't have room, or something else ....)
|
||||||
void Net_UnAcknowledgPacket(INT32 node)
|
void Net_UnAcknowledgePacket(INT32 node)
|
||||||
{
|
{
|
||||||
#ifdef NONET
|
#ifdef NONET
|
||||||
(void)node;
|
(void)node;
|
||||||
|
@ -564,20 +609,29 @@ void Net_UnAcknowledgPacket(INT32 node)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean Net_AllAckReceived(void)
|
|
||||||
{
|
|
||||||
#ifndef NONET
|
#ifndef NONET
|
||||||
|
/** Checks if all acks have been received
|
||||||
|
*
|
||||||
|
* \return True if all acks have been received
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static boolean Net_AllAcksReceived(void)
|
||||||
|
{
|
||||||
INT32 i;
|
INT32 i;
|
||||||
|
|
||||||
for (i = 0; i < MAXACKPACKETS; i++)
|
for (i = 0; i < MAXACKPACKETS; i++)
|
||||||
if (ackpak[i].acknum)
|
if (ackpak[i].acknum)
|
||||||
return false;
|
return false;
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// wait for all ackreturns with timeout in seconds
|
/** Waits for all ackreturns
|
||||||
|
*
|
||||||
|
* \param timeout Timeout in seconds
|
||||||
|
*
|
||||||
|
*/
|
||||||
void Net_WaitAllAckReceived(UINT32 timeout)
|
void Net_WaitAllAckReceived(UINT32 timeout)
|
||||||
{
|
{
|
||||||
#ifdef NONET
|
#ifdef NONET
|
||||||
|
@ -587,7 +641,7 @@ void Net_WaitAllAckReceived(UINT32 timeout)
|
||||||
timeout = tictac + timeout*NEWTICRATE;
|
timeout = tictac + timeout*NEWTICRATE;
|
||||||
|
|
||||||
HGetPacket();
|
HGetPacket();
|
||||||
while (timeout > I_GetTime() && !Net_AllAckReceived())
|
while (timeout > I_GetTime() && !Net_AllAcksReceived())
|
||||||
{
|
{
|
||||||
while (tictac == I_GetTime())
|
while (tictac == I_GetTime())
|
||||||
I_Sleep();
|
I_Sleep();
|
||||||
|
@ -598,18 +652,18 @@ void Net_WaitAllAckReceived(UINT32 timeout)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InitNode(INT32 node)
|
static void InitNode(node_t *node)
|
||||||
{
|
{
|
||||||
nodes[node].acktosend_head = nodes[node].acktosend_tail = 0;
|
node->acktosend_head = node->acktosend_tail = 0;
|
||||||
#ifndef NEWPING
|
#ifndef NEWPING
|
||||||
nodes[node].ping = PINGDEFAULT;
|
node->ping = PINGDEFAULT;
|
||||||
nodes[node].varping = VARPINGDEFAULT;
|
node->varping = VARPINGDEFAULT;
|
||||||
nodes[node].timeout = TIMEOUT(nodes[node].ping,nodes[node].varping);
|
node->timeout = TIMEOUT(node->ping, node->varping);
|
||||||
#endif
|
#endif
|
||||||
nodes[node].firstacktosend = 0;
|
node->firstacktosend = 0;
|
||||||
nodes[node].nextacknum = 1;
|
node->nextacknum = 1;
|
||||||
nodes[node].remotefirstack = 0;
|
node->remotefirstack = 0;
|
||||||
nodes[node].flags = 0;
|
node->flags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InitAck(void)
|
static void InitAck(void)
|
||||||
|
@ -622,9 +676,14 @@ static void InitAck(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (i = 0; i < MAXNETNODES; i++)
|
for (i = 0; i < MAXNETNODES; i++)
|
||||||
InitNode(i);
|
InitNode(&nodes[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Removes all acks of a given packet type
|
||||||
|
*
|
||||||
|
* \param packettype The packet type to forget
|
||||||
|
*
|
||||||
|
*/
|
||||||
void Net_AbortPacketType(UINT8 packettype)
|
void Net_AbortPacketType(UINT8 packettype)
|
||||||
{
|
{
|
||||||
#ifdef NONET
|
#ifdef NONET
|
||||||
|
@ -657,7 +716,7 @@ void Net_CloseConnection(INT32 node)
|
||||||
if (!node)
|
if (!node)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
nodes[node].flags |= CLOSE;
|
nodes[node].flags |= NF_CLOSE;
|
||||||
|
|
||||||
// try to Send ack back (two army problem)
|
// try to Send ack back (two army problem)
|
||||||
if (GetAcktosend(node))
|
if (GetAcktosend(node))
|
||||||
|
@ -676,8 +735,8 @@ void Net_CloseConnection(INT32 node)
|
||||||
ackpak[i].acknum = 0;
|
ackpak[i].acknum = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
InitNode(node);
|
InitNode(&nodes[node]);
|
||||||
AbortSendFiles(node);
|
SV_AbortSendFiles(node);
|
||||||
I_NetFreeNodenum(node);
|
I_NetFreeNodenum(node);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -729,9 +788,15 @@ static void fprintfstring(char *s, size_t len)
|
||||||
}
|
}
|
||||||
if (mode)
|
if (mode)
|
||||||
fprintf(debugfile, "]");
|
fprintf(debugfile, "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fprintfstringnewline(char *s, size_t len)
|
||||||
|
{
|
||||||
|
fprintfstring(s, len);
|
||||||
fprintf(debugfile, "\n");
|
fprintf(debugfile, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \warning Keep this up-to-date if you add/remove/rename packet types
|
||||||
static const char *packettypename[NUMPACKETTYPE] =
|
static const char *packettypename[NUMPACKETTYPE] =
|
||||||
{
|
{
|
||||||
"NOTHING",
|
"NOTHING",
|
||||||
|
@ -749,15 +814,22 @@ static const char *packettypename[NUMPACKETTYPE] =
|
||||||
|
|
||||||
"ASKINFO",
|
"ASKINFO",
|
||||||
"SERVERINFO",
|
"SERVERINFO",
|
||||||
|
"PLAYERINFO",
|
||||||
"REQUESTFILE",
|
"REQUESTFILE",
|
||||||
"ASKINFOVIAMS",
|
"ASKINFOVIAMS",
|
||||||
|
|
||||||
"PLAYERCONFIGS",
|
"RESYNCHEND",
|
||||||
|
"RESYNCHGET",
|
||||||
|
|
||||||
"FILEFRAGMENT",
|
"FILEFRAGMENT",
|
||||||
"TEXTCMD",
|
"TEXTCMD",
|
||||||
"TEXTCMD2",
|
"TEXTCMD2",
|
||||||
"CLIENTJOIN",
|
"CLIENTJOIN",
|
||||||
"NODETIMEOUT",
|
"NODETIMEOUT",
|
||||||
|
"RESYNCHING",
|
||||||
|
#ifdef NEWPING
|
||||||
|
"PING"
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static void DebugPrintpacket(const char *header)
|
static void DebugPrintpacket(const char *header)
|
||||||
|
@ -770,20 +842,31 @@ static void DebugPrintpacket(const char *header)
|
||||||
{
|
{
|
||||||
case PT_ASKINFO:
|
case PT_ASKINFO:
|
||||||
case PT_ASKINFOVIAMS:
|
case PT_ASKINFOVIAMS:
|
||||||
fprintf(debugfile, " time %u\n", (tic_t)LONG(netbuffer->u.askinfo.time) );
|
fprintf(debugfile, " time %u\n", (tic_t)LONG(netbuffer->u.askinfo.time));
|
||||||
break;
|
break;
|
||||||
case PT_CLIENTJOIN:
|
case PT_CLIENTJOIN:
|
||||||
fprintf(debugfile, " number %d mode %d\n", netbuffer->u.clientcfg.localplayers,
|
fprintf(debugfile, " number %d mode %d\n", netbuffer->u.clientcfg.localplayers,
|
||||||
netbuffer->u.clientcfg.mode);
|
netbuffer->u.clientcfg.mode);
|
||||||
break;
|
break;
|
||||||
case PT_SERVERTICS:
|
case PT_SERVERTICS:
|
||||||
|
{
|
||||||
|
servertics_pak *serverpak = &netbuffer->u.serverpak;
|
||||||
|
UINT8 *cmd = (UINT8 *)(&serverpak->cmds[serverpak->numslots * serverpak->numtics]);
|
||||||
|
size_t ntxtcmd = &((UINT8 *)netbuffer)[doomcom->datalength] - cmd;
|
||||||
|
|
||||||
fprintf(debugfile, " firsttic %u ply %d tics %d ntxtcmd %s\n ",
|
fprintf(debugfile, " firsttic %u ply %d tics %d ntxtcmd %s\n ",
|
||||||
(UINT32)ExpandTics(netbuffer->u.serverpak.starttic), netbuffer->u.serverpak.numslots,
|
(UINT32)ExpandTics(serverpak->starttic), serverpak->numslots, serverpak->numtics, sizeu1(ntxtcmd));
|
||||||
netbuffer->u.serverpak.numtics,
|
/// \todo Display more readable information about net commands
|
||||||
sizeu1((size_t)(&((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics])));
|
fprintfstringnewline((char *)cmd, ntxtcmd);
|
||||||
fprintfstring((char *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics],(size_t)(
|
/*fprintfstring((char *)cmd, 3);
|
||||||
&((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics]));
|
if (ntxtcmd > 4)
|
||||||
|
{
|
||||||
|
fprintf(debugfile, "[%s]", netxcmdnames[*((cmd) + 3) - 1]);
|
||||||
|
fprintfstring(((char *)cmd) + 4, ntxtcmd - 4);
|
||||||
|
}
|
||||||
|
fprintf(debugfile, "\n");*/
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case PT_CLIENTCMD:
|
case PT_CLIENTCMD:
|
||||||
case PT_CLIENT2CMD:
|
case PT_CLIENT2CMD:
|
||||||
case PT_CLIENTMIS:
|
case PT_CLIENTMIS:
|
||||||
|
@ -797,7 +880,8 @@ static void DebugPrintpacket(const char *header)
|
||||||
case PT_TEXTCMD:
|
case PT_TEXTCMD:
|
||||||
case PT_TEXTCMD2:
|
case PT_TEXTCMD2:
|
||||||
fprintf(debugfile, " length %d\n ", netbuffer->u.textcmd[0]);
|
fprintf(debugfile, " length %d\n ", netbuffer->u.textcmd[0]);
|
||||||
fprintfstring((char *)netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]);
|
fprintf(debugfile, "[%s]", netxcmdnames[netbuffer->u.textcmd[1] - 1]);
|
||||||
|
fprintfstringnewline((char *)netbuffer->u.textcmd + 2, netbuffer->u.textcmd[0] - 1);
|
||||||
break;
|
break;
|
||||||
case PT_SERVERCFG:
|
case PT_SERVERCFG:
|
||||||
fprintf(debugfile, " playerslots %d clientnode %d serverplayer %d "
|
fprintf(debugfile, " playerslots %d clientnode %d serverplayer %d "
|
||||||
|
@ -813,7 +897,7 @@ static void DebugPrintpacket(const char *header)
|
||||||
netbuffer->u.serverinfo.maxplayer, netbuffer->u.serverinfo.mapname,
|
netbuffer->u.serverinfo.maxplayer, netbuffer->u.serverinfo.mapname,
|
||||||
netbuffer->u.serverinfo.fileneedednum,
|
netbuffer->u.serverinfo.fileneedednum,
|
||||||
(UINT32)LONG(netbuffer->u.serverinfo.time));
|
(UINT32)LONG(netbuffer->u.serverinfo.time));
|
||||||
fprintfstring((char *)netbuffer->u.serverinfo.fileneeded,
|
fprintfstringnewline((char *)netbuffer->u.serverinfo.fileneeded,
|
||||||
(UINT8)((UINT8 *)netbuffer + doomcom->datalength
|
(UINT8)((UINT8 *)netbuffer + doomcom->datalength
|
||||||
- (UINT8 *)netbuffer->u.serverinfo.fileneeded));
|
- (UINT8 *)netbuffer->u.serverinfo.fileneeded));
|
||||||
break;
|
break;
|
||||||
|
@ -827,20 +911,102 @@ static void DebugPrintpacket(const char *header)
|
||||||
break;
|
break;
|
||||||
case PT_REQUESTFILE:
|
case PT_REQUESTFILE:
|
||||||
default: // write as a raw packet
|
default: // write as a raw packet
|
||||||
fprintfstring((char *)netbuffer->u.textcmd,
|
fprintfstringnewline((char *)netbuffer->u.textcmd,
|
||||||
(UINT8)((UINT8 *)netbuffer + doomcom->datalength - (UINT8 *)netbuffer->u.textcmd));
|
(UINT8)((UINT8 *)netbuffer + doomcom->datalength - (UINT8 *)netbuffer->u.textcmd));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef PACKETDROP
|
||||||
|
static INT32 packetdropquantity[NUMPACKETTYPE] = {0};
|
||||||
|
static INT32 packetdroprate = 0;
|
||||||
|
|
||||||
|
void Command_Drop(void)
|
||||||
|
{
|
||||||
|
INT32 packetquantity;
|
||||||
|
const char *packetname;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (COM_Argc() < 2)
|
||||||
|
{
|
||||||
|
CONS_Printf("drop <packettype> [quantity]: drop packets\n"
|
||||||
|
"drop reset: cancel all packet drops\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(stricmp(COM_Argv(1), "reset") && stricmp(COM_Argv(1), "cancel") && stricmp(COM_Argv(1), "stop")))
|
||||||
|
{
|
||||||
|
memset(packetdropquantity, 0, sizeof(packetdropquantity));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (COM_Argc() >= 3)
|
||||||
|
{
|
||||||
|
packetquantity = atoi(COM_Argv(2));
|
||||||
|
if (packetquantity <= 0 && COM_Argv(2)[0] != '0')
|
||||||
|
{
|
||||||
|
CONS_Printf("Invalid quantity\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
packetquantity = -1;
|
||||||
|
|
||||||
|
packetname = COM_Argv(1);
|
||||||
|
|
||||||
|
if (!(stricmp(packetname, "all") && stricmp(packetname, "any")))
|
||||||
|
for (i = 0; i < NUMPACKETTYPE; i++)
|
||||||
|
packetdropquantity[i] = packetquantity;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; i < NUMPACKETTYPE; i++)
|
||||||
|
if (!stricmp(packetname, packettypename[i]))
|
||||||
|
{
|
||||||
|
packetdropquantity[i] = packetquantity;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CONS_Printf("Unknown packet name\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Command_Droprate(void)
|
||||||
|
{
|
||||||
|
INT32 droprate;
|
||||||
|
|
||||||
|
if (COM_Argc() < 2)
|
||||||
|
{
|
||||||
|
CONS_Printf("Packet drop rate: %d%%\n", packetdroprate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
droprate = atoi(COM_Argv(1));
|
||||||
|
if ((droprate <= 0 && COM_Argv(1)[0] != '0') || droprate > 100)
|
||||||
|
{
|
||||||
|
CONS_Printf("Packet drop rate must be between 0 and 100!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
// HSendPacket
|
||||||
//
|
//
|
||||||
boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlength)
|
boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlength)
|
||||||
{
|
{
|
||||||
doomcom->datalength = (INT16)(packetlength + BASEPACKETSIZE);
|
doomcom->datalength = (INT16)(packetlength + BASEPACKETSIZE);
|
||||||
if (node == 0) // packet is to go back to us
|
if (node == 0) // Packet is to go back to us
|
||||||
{
|
{
|
||||||
if ((rebound_head+1) % MAXREBOUND == rebound_tail)
|
if ((rebound_head+1) % MAXREBOUND == rebound_tail)
|
||||||
{
|
{
|
||||||
|
@ -871,7 +1037,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
||||||
(void)reliable;
|
(void)reliable;
|
||||||
(void)acknum;
|
(void)acknum;
|
||||||
#else
|
#else
|
||||||
// do this before GetFreeAcknum because this function backup
|
// do this before GetFreeAcknum because this function backups
|
||||||
// the current packet
|
// the current packet
|
||||||
doomcom->remotenode = (INT16)node;
|
doomcom->remotenode = (INT16)node;
|
||||||
if (doomcom->datalength <= 0)
|
if (doomcom->datalength <= 0)
|
||||||
|
@ -884,7 +1050,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node < MAXNETNODES) // can be a broadcast
|
if (node < MAXNETNODES) // Can be a broadcast
|
||||||
netbuffer->ackreturn = GetAcktosend(node);
|
netbuffer->ackreturn = GetAcktosend(node);
|
||||||
else
|
else
|
||||||
netbuffer->ackreturn = 0;
|
netbuffer->ackreturn = 0;
|
||||||
|
@ -905,20 +1071,30 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
||||||
netbuffer->ack = acknum;
|
netbuffer->ack = acknum;
|
||||||
|
|
||||||
netbuffer->checksum = NetbufferChecksum();
|
netbuffer->checksum = NetbufferChecksum();
|
||||||
sendbytes += packetheaderlength + doomcom->datalength; // for stat
|
sendbytes += packetheaderlength + doomcom->datalength; // For stat
|
||||||
|
|
||||||
// simulate internet :)
|
#ifdef PACKETDROP
|
||||||
if (true || rand()<(INT32)RAND_MAX/5)
|
// Simulate internet :)
|
||||||
|
//if (rand() >= (INT32)(RAND_MAX * (PACKETLOSSRATE / 100.f)))
|
||||||
|
if (!ShouldDropPacket())
|
||||||
{
|
{
|
||||||
|
#endif
|
||||||
#ifdef DEBUGFILE
|
#ifdef DEBUGFILE
|
||||||
if (debugfile)
|
if (debugfile)
|
||||||
DebugPrintpacket("SEND");
|
DebugPrintpacket("SENT");
|
||||||
#endif
|
#endif
|
||||||
I_NetSend();
|
I_NetSend();
|
||||||
|
#ifdef PACKETDROP
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (packetdropquantity[netbuffer->packettype] > 0)
|
||||||
|
packetdropquantity[netbuffer->packettype]--;
|
||||||
#ifdef DEBUGFILE
|
#ifdef DEBUGFILE
|
||||||
else if (debugfile)
|
if (debugfile)
|
||||||
DebugPrintpacket("NOTSEND");
|
DebugPrintpacket("NOT SENT");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // ndef NONET
|
#endif // ndef NONET
|
||||||
|
@ -933,7 +1109,9 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
||||||
//
|
//
|
||||||
boolean HGetPacket(void)
|
boolean HGetPacket(void)
|
||||||
{
|
{
|
||||||
// get a packet from self
|
//boolean nodejustjoined;
|
||||||
|
|
||||||
|
// Get a packet from self
|
||||||
if (rebound_tail != rebound_head)
|
if (rebound_tail != rebound_head)
|
||||||
{
|
{
|
||||||
M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]);
|
M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]);
|
||||||
|
@ -958,16 +1136,17 @@ boolean HGetPacket(void)
|
||||||
|
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
|
//nodejustjoined = I_NetGet();
|
||||||
I_NetGet();
|
I_NetGet();
|
||||||
|
|
||||||
if (doomcom->remotenode == -1)
|
if (doomcom->remotenode == -1) // No packet received
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
getbytes += packetheaderlength + doomcom->datalength; // for stat
|
getbytes += packetheaderlength + doomcom->datalength; // For stat
|
||||||
|
|
||||||
if (doomcom->remotenode >= MAXNETNODES)
|
if (doomcom->remotenode >= MAXNETNODES)
|
||||||
{
|
{
|
||||||
DEBFILE(va("receive packet from node %d !\n", doomcom->remotenode));
|
DEBFILE(va("Received packet from node %d!\n", doomcom->remotenode));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -976,6 +1155,7 @@ boolean HGetPacket(void)
|
||||||
if (netbuffer->checksum != NetbufferChecksum())
|
if (netbuffer->checksum != NetbufferChecksum())
|
||||||
{
|
{
|
||||||
DEBFILE("Bad packet checksum\n");
|
DEBFILE("Bad packet checksum\n");
|
||||||
|
//Net_CloseConnection(nodejustjoined ? (doomcom->remotenode | FORCECLOSE) : doomcom->remotenode);
|
||||||
Net_CloseConnection(doomcom->remotenode);
|
Net_CloseConnection(doomcom->remotenode);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -985,11 +1165,26 @@ boolean HGetPacket(void)
|
||||||
DebugPrintpacket("GET");
|
DebugPrintpacket("GET");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// proceed the ack and ackreturn field
|
/*// If a new node sends an unexpected packet, just ignore it
|
||||||
|
if (nodejustjoined && server
|
||||||
|
&& !(netbuffer->packettype == PT_ASKINFO
|
||||||
|
|| netbuffer->packettype == PT_SERVERINFO
|
||||||
|
|| netbuffer->packettype == PT_PLAYERINFO
|
||||||
|
|| netbuffer->packettype == PT_REQUESTFILE
|
||||||
|
|| netbuffer->packettype == PT_ASKINFOVIAMS
|
||||||
|
|| netbuffer->packettype == PT_CLIENTJOIN))
|
||||||
|
{
|
||||||
|
DEBFILE(va("New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype]));
|
||||||
|
//CONS_Alert(CONS_NOTICE, "New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype]);
|
||||||
|
Net_CloseConnection(doomcom->remotenode | FORCECLOSE);
|
||||||
|
continue;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// Proceed the ack and ackreturn field
|
||||||
if (!Processackpak())
|
if (!Processackpak())
|
||||||
continue; // discarded (duplicated)
|
continue; // discarded (duplicated)
|
||||||
|
|
||||||
// a packet with just ackreturn
|
// A packet with just ackreturn
|
||||||
if (netbuffer->packettype == PT_NOTHING)
|
if (netbuffer->packettype == PT_NOTHING)
|
||||||
{
|
{
|
||||||
GotAcks();
|
GotAcks();
|
||||||
|
@ -1002,9 +1197,10 @@ boolean HGetPacket(void)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Internal_Get(void)
|
static boolean Internal_Get(void)
|
||||||
{
|
{
|
||||||
doomcom->remotenode = -1;
|
doomcom->remotenode = -1;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCNORETURN static ATTRNORETURN void Internal_Send(void)
|
FUNCNORETURN static ATTRNORETURN void Internal_Send(void)
|
||||||
|
@ -1089,7 +1285,7 @@ boolean D_CheckNetGame(void)
|
||||||
|
|
||||||
if (netgame)
|
if (netgame)
|
||||||
ret = true;
|
ret = true;
|
||||||
if (!server && netgame)
|
if (client && netgame)
|
||||||
netgame = false;
|
netgame = false;
|
||||||
server = true; // WTF? server always true???
|
server = true; // WTF? server always true???
|
||||||
// no! The deault mode is server. Client is set elsewhere
|
// no! The deault mode is server. Client is set elsewhere
|
||||||
|
@ -1230,4 +1426,6 @@ void D_CloseConnection(void)
|
||||||
netgame = false;
|
netgame = false;
|
||||||
addedtogame = false;
|
addedtogame = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
D_ResetTiccmds();
|
||||||
}
|
}
|
||||||
|
|
20
src/d_net.h
20
src/d_net.h
|
@ -18,10 +18,10 @@
|
||||||
#ifndef __D_NET__
|
#ifndef __D_NET__
|
||||||
#define __D_NET__
|
#define __D_NET__
|
||||||
|
|
||||||
// Max computers in a game.
|
// Max computers in a game
|
||||||
#define MAXNETNODES 32
|
#define MAXNETNODES 32
|
||||||
#define BROADCASTADDR MAXNETNODES
|
#define BROADCASTADDR MAXNETNODES
|
||||||
#define MAXSPLITSCREENPLAYERS 2 // max number of players on a single computer
|
#define MAXSPLITSCREENPLAYERS 2 // Max number of players on a single computer
|
||||||
|
|
||||||
#define STATLENGTH (TICRATE*2)
|
#define STATLENGTH (TICRATE*2)
|
||||||
|
|
||||||
|
@ -32,17 +32,17 @@ extern float lostpercent, duppercent, gamelostpercent;
|
||||||
extern INT32 packetheaderlength;
|
extern INT32 packetheaderlength;
|
||||||
boolean Net_GetNetStat(void);
|
boolean Net_GetNetStat(void);
|
||||||
extern INT32 getbytes;
|
extern INT32 getbytes;
|
||||||
extern INT64 sendbytes; // realtime updated
|
extern INT64 sendbytes; // Realtime updated
|
||||||
|
|
||||||
extern SINT8 nodetoplayer[MAXNETNODES];
|
extern SINT8 nodetoplayer[MAXNETNODES];
|
||||||
extern SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen)
|
extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if any (splitscreen)
|
||||||
extern UINT8 playerpernode[MAXNETNODES]; // used specialy for scplitscreen
|
extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen
|
||||||
extern boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
|
extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game
|
||||||
|
|
||||||
|
INT32 Net_GetFreeAcks(boolean urgent);
|
||||||
void Net_AckTicker(void);
|
void Net_AckTicker(void);
|
||||||
boolean Net_AllAckReceived(void);
|
|
||||||
|
|
||||||
// if reliable return true if packet sent, 0 else
|
// If reliable return true if packet sent, 0 else
|
||||||
boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum,
|
boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum,
|
||||||
size_t packetlength);
|
size_t packetlength);
|
||||||
boolean HGetPacket(void);
|
boolean HGetPacket(void);
|
||||||
|
@ -52,9 +52,11 @@ void D_SaveBan(void);
|
||||||
#endif
|
#endif
|
||||||
boolean D_CheckNetGame(void);
|
boolean D_CheckNetGame(void);
|
||||||
void D_CloseConnection(void);
|
void D_CloseConnection(void);
|
||||||
void Net_UnAcknowledgPacket(INT32 node);
|
void Net_UnAcknowledgePacket(INT32 node);
|
||||||
void Net_CloseConnection(INT32 node);
|
void Net_CloseConnection(INT32 node);
|
||||||
|
void Net_ConnectionTimeout(INT32 node);
|
||||||
void Net_AbortPacketType(UINT8 packettype);
|
void Net_AbortPacketType(UINT8 packettype);
|
||||||
void Net_SendAcks(INT32 node);
|
void Net_SendAcks(INT32 node);
|
||||||
void Net_WaitAllAckReceived(UINT32 timeout);
|
void Net_WaitAllAckReceived(UINT32 timeout);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -82,6 +82,7 @@ static void AutoBalance_OnChange(void);
|
||||||
static void TeamScramble_OnChange(void);
|
static void TeamScramble_OnChange(void);
|
||||||
|
|
||||||
static void NetTimeout_OnChange(void);
|
static void NetTimeout_OnChange(void);
|
||||||
|
static void JoinTimeout_OnChange(void);
|
||||||
|
|
||||||
static void Ringslinger_OnChange(void);
|
static void Ringslinger_OnChange(void);
|
||||||
static void Gravity_OnChange(void);
|
static void Gravity_OnChange(void);
|
||||||
|
@ -340,7 +341,9 @@ consvar_t cv_killingdead = {"killingdead", "Off", CV_NETVAR, CV_OnOff, NULL, 0,
|
||||||
|
|
||||||
consvar_t cv_netstat = {"netstat", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; // show bandwidth statistics
|
consvar_t cv_netstat = {"netstat", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; // show bandwidth statistics
|
||||||
static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
|
static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
|
||||||
consvar_t cv_nettimeout = {"nettimeout", "525", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
|
consvar_t cv_nettimeout = {"nettimeout", "350", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
|
||||||
|
static CV_PossibleValue_t jointimeout_cons_t[] = {{5*TICRATE, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
|
||||||
|
consvar_t cv_jointimeout = {"jointimeout", "350", CV_CALL|CV_SAVE, jointimeout_cons_t, JoinTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
|
||||||
#ifdef NEWPING
|
#ifdef NEWPING
|
||||||
consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
|
consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||||
#endif
|
#endif
|
||||||
|
@ -365,6 +368,35 @@ boolean splitscreen = false;
|
||||||
boolean circuitmap = false;
|
boolean circuitmap = false;
|
||||||
INT32 adminplayer = -1;
|
INT32 adminplayer = -1;
|
||||||
|
|
||||||
|
/// \warning Keep this up-to-date if you add/remove/rename net text commands
|
||||||
|
const char *netxcmdnames[MAXNETXCMD - 1] =
|
||||||
|
{
|
||||||
|
"NAMEANDCOLOR",
|
||||||
|
"WEAPONPREF",
|
||||||
|
"KICK",
|
||||||
|
"NETVAR",
|
||||||
|
"SAY",
|
||||||
|
"MAP",
|
||||||
|
"EXITLEVEL",
|
||||||
|
"ADDFILE",
|
||||||
|
"PAUSE",
|
||||||
|
"ADDPLAYER",
|
||||||
|
"TEAMCHANGE",
|
||||||
|
"CLEARSCORES",
|
||||||
|
"LOGIN",
|
||||||
|
"VERIFIED",
|
||||||
|
"RANDOMSEED",
|
||||||
|
"RUNSOC",
|
||||||
|
"REQADDFILE",
|
||||||
|
"DELFILE",
|
||||||
|
"SETMOTD",
|
||||||
|
"SUICIDE",
|
||||||
|
#ifdef HAVE_BLUA
|
||||||
|
"LUACMD",
|
||||||
|
"LUAVAR"
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// SERVER STARTUP
|
// SERVER STARTUP
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
@ -517,9 +549,12 @@ void D_RegisterServerCommands(void)
|
||||||
// d_clisrv
|
// d_clisrv
|
||||||
CV_RegisterVar(&cv_maxplayers);
|
CV_RegisterVar(&cv_maxplayers);
|
||||||
CV_RegisterVar(&cv_maxsend);
|
CV_RegisterVar(&cv_maxsend);
|
||||||
|
CV_RegisterVar(&cv_noticedownload);
|
||||||
|
CV_RegisterVar(&cv_downloadspeed);
|
||||||
|
|
||||||
COM_AddCommand("ping", Command_Ping_f);
|
COM_AddCommand("ping", Command_Ping_f);
|
||||||
CV_RegisterVar(&cv_nettimeout);
|
CV_RegisterVar(&cv_nettimeout);
|
||||||
|
CV_RegisterVar(&cv_jointimeout);
|
||||||
|
|
||||||
CV_RegisterVar(&cv_skipmapcheck);
|
CV_RegisterVar(&cv_skipmapcheck);
|
||||||
CV_RegisterVar(&cv_sleep);
|
CV_RegisterVar(&cv_sleep);
|
||||||
|
@ -976,7 +1011,7 @@ UINT8 CanChangeSkin(INT32 playernum)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Force skin in effect.
|
// Force skin in effect.
|
||||||
if (!server && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1))
|
if (client && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Can change skin in intermission and whatnot.
|
// Can change skin in intermission and whatnot.
|
||||||
|
@ -1587,7 +1622,7 @@ static void Command_Map_f(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!server && !(adminplayer == consoleplayer))
|
if (client && !(adminplayer == consoleplayer))
|
||||||
{
|
{
|
||||||
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
|
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
|
||||||
return;
|
return;
|
||||||
|
@ -1914,7 +1949,7 @@ static void Got_Suicide(UINT8 **cp, INT32 playernum)
|
||||||
// You can't suicide someone else. Nice try, there.
|
// You can't suicide someone else. Nice try, there.
|
||||||
if (suicideplayer != playernum || (!G_PlatformGametype()))
|
if (suicideplayer != playernum || (!G_PlatformGametype()))
|
||||||
{
|
{
|
||||||
CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command recieved from %s\n"), player_names[playernum]);
|
CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command received from %s\n"), player_names[playernum]);
|
||||||
if (server)
|
if (server)
|
||||||
{
|
{
|
||||||
XBOXSTATIC UINT8 buf[2];
|
XBOXSTATIC UINT8 buf[2];
|
||||||
|
@ -2629,7 +2664,7 @@ static void Command_Changepassword_f(void)
|
||||||
// If we have no MD5 support then completely disable XD_LOGIN responses for security.
|
// If we have no MD5 support then completely disable XD_LOGIN responses for security.
|
||||||
CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n");
|
CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n");
|
||||||
#else
|
#else
|
||||||
if (!server) // cannot change remotely
|
if (client) // cannot change remotely
|
||||||
{
|
{
|
||||||
CONS_Printf(M_GetText("Only the server can use this.\n"));
|
CONS_Printf(M_GetText("Only the server can use this.\n"));
|
||||||
return;
|
return;
|
||||||
|
@ -2688,7 +2723,7 @@ static void Got_Login(UINT8 **cp, INT32 playernum)
|
||||||
|
|
||||||
READMEM(*cp, sentmd5, 16);
|
READMEM(*cp, sentmd5, 16);
|
||||||
|
|
||||||
if (!server)
|
if (client)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Do the final pass to compare with the sent md5
|
// Do the final pass to compare with the sent md5
|
||||||
|
@ -2710,7 +2745,7 @@ static void Command_Verify_f(void)
|
||||||
char *temp;
|
char *temp;
|
||||||
INT32 playernum;
|
INT32 playernum;
|
||||||
|
|
||||||
if (!server)
|
if (client)
|
||||||
{
|
{
|
||||||
CONS_Printf(M_GetText("Only the server can use this.\n"));
|
CONS_Printf(M_GetText("Only the server can use this.\n"));
|
||||||
return;
|
return;
|
||||||
|
@ -2794,7 +2829,7 @@ static void Command_MotD_f(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((netgame || multiplayer) && !server)
|
if ((netgame || multiplayer) && client)
|
||||||
SendNetXCmd(XD_SETMOTD, mymotd, sizeof(motd));
|
SendNetXCmd(XD_SETMOTD, mymotd, sizeof(motd));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3051,7 +3086,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
|
||||||
READMEM(*cp, md5sum, 16);
|
READMEM(*cp, md5sum, 16);
|
||||||
|
|
||||||
// Only the server processes this message.
|
// Only the server processes this message.
|
||||||
if (!server)
|
if (client)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Disallow non-printing characters and semicolons.
|
// Disallow non-printing characters and semicolons.
|
||||||
|
@ -3318,6 +3353,11 @@ static void NetTimeout_OnChange(void)
|
||||||
connectiontimeout = (tic_t)cv_nettimeout.value;
|
connectiontimeout = (tic_t)cv_nettimeout.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void JoinTimeout_OnChange(void)
|
||||||
|
{
|
||||||
|
jointimeout = (tic_t)cv_jointimeout.value;
|
||||||
|
}
|
||||||
|
|
||||||
UINT32 timelimitintics = 0;
|
UINT32 timelimitintics = 0;
|
||||||
|
|
||||||
/** Deals with a timelimit change by printing the change to the console.
|
/** Deals with a timelimit change by printing the change to the console.
|
||||||
|
|
|
@ -162,6 +162,8 @@ typedef enum
|
||||||
MAXNETXCMD
|
MAXNETXCMD
|
||||||
} netxcmd_t;
|
} netxcmd_t;
|
||||||
|
|
||||||
|
extern const char *netxcmdnames[MAXNETXCMD - 1];
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
#endif
|
#endif
|
||||||
|
|
495
src/d_netfil.c
495
src/d_netfil.c
|
@ -62,44 +62,48 @@
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
static void SendFile(INT32 node, const char *filename, UINT8 fileid);
|
static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid);
|
||||||
|
|
||||||
// sender structure
|
// Sender structure
|
||||||
typedef struct filetx_s
|
typedef struct filetx_s
|
||||||
{
|
{
|
||||||
INT32 ram;
|
INT32 ram;
|
||||||
char *filename; // name of the file or ptr of the data in ram
|
union {
|
||||||
UINT32 size;
|
char *filename; // Name of the file
|
||||||
|
char *ram; // Pointer to the data in RAM
|
||||||
|
} id;
|
||||||
|
UINT32 size; // Size of the file
|
||||||
UINT8 fileid;
|
UINT8 fileid;
|
||||||
INT32 node; // destination
|
INT32 node; // Destination
|
||||||
struct filetx_s *next; // a queue
|
struct filetx_s *next; // Next file in the list
|
||||||
} filetx_t;
|
} filetx_t;
|
||||||
|
|
||||||
// current transfers (one for each node)
|
// Current transfers (one for each node)
|
||||||
typedef struct filetran_s
|
typedef struct filetran_s
|
||||||
{
|
{
|
||||||
filetx_t *txlist;
|
filetx_t *txlist; // Linked list of all files for the node
|
||||||
UINT32 position;
|
UINT32 position; // The current position in the file
|
||||||
FILE *currentfile;
|
FILE *currentfile; // The file currently being sent/received
|
||||||
} filetran_t;
|
} filetran_t;
|
||||||
static filetran_t transfer[MAXNETNODES];
|
static filetran_t transfer[MAXNETNODES];
|
||||||
|
|
||||||
// read time of file: stat _stmtime
|
// Read time of file: stat _stmtime
|
||||||
// write time of file: utime
|
// Write time of file: utime
|
||||||
|
|
||||||
// receiver structure
|
// Receiver structure
|
||||||
INT32 fileneedednum;
|
INT32 fileneedednum; // Number of files needed to join the server
|
||||||
fileneeded_t fileneeded[MAX_WADFILES];
|
fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files
|
||||||
char downloaddir[256] = "DOWNLOAD";
|
char downloaddir[256] = "DOWNLOAD";
|
||||||
|
|
||||||
#ifdef CLIENT_LOADINGSCREEN
|
#ifdef CLIENT_LOADINGSCREEN
|
||||||
// for cl loading screen
|
// for cl loading screen
|
||||||
INT32 lastfilenum = 0;
|
INT32 lastfilenum = -1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Fills a serverinfo packet with information about wad files loaded.
|
/** Fills a serverinfo packet with information about wad files loaded.
|
||||||
*
|
*
|
||||||
* \todo Give this function a better name since it is in global scope.
|
* \todo Give this function a better name since it is in global scope.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
UINT8 *PutFileNeeded(void)
|
UINT8 *PutFileNeeded(void)
|
||||||
{
|
{
|
||||||
|
@ -111,19 +115,19 @@ UINT8 *PutFileNeeded(void)
|
||||||
|
|
||||||
for (i = 0; i < numwadfiles; i++)
|
for (i = 0; i < numwadfiles; i++)
|
||||||
{
|
{
|
||||||
// if it has only music/sound lumps, mark it as unimportant
|
// If it has only music/sound lumps, mark it as unimportant
|
||||||
if (W_VerifyNMUSlumps(wadfiles[i]->filename))
|
if (W_VerifyNMUSlumps(wadfiles[i]->filename))
|
||||||
filestatus = 0;
|
filestatus = 0;
|
||||||
else
|
else
|
||||||
filestatus = 1; // important
|
filestatus = 1; // Important
|
||||||
|
|
||||||
// Store in the upper four bits
|
// Store in the upper four bits
|
||||||
if (!cv_downloading.value)
|
if (!cv_downloading.value)
|
||||||
filestatus += (2 << 4); // won't send
|
filestatus += (2 << 4); // Won't send
|
||||||
else if ((wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024))
|
else if ((wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024))
|
||||||
filestatus += (0 << 4); // won't send
|
filestatus += (0 << 4); // Won't send
|
||||||
else
|
else
|
||||||
filestatus += (1 << 4); // will send if requested
|
filestatus += (1 << 4); // Will send if requested
|
||||||
|
|
||||||
bytesused += (nameonlylength(wadfilename) + 22);
|
bytesused += (nameonlylength(wadfilename) + 22);
|
||||||
|
|
||||||
|
@ -144,7 +148,12 @@ UINT8 *PutFileNeeded(void)
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse the serverinfo packet and fill fileneeded table on client
|
/** Parses the serverinfo packet and fills the fileneeded table on client
|
||||||
|
*
|
||||||
|
* \param fileneedednum_parm The number of files needed to join the server
|
||||||
|
* \param fileneededstr The memory block containing the list of needed files
|
||||||
|
*
|
||||||
|
*/
|
||||||
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
|
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
|
||||||
{
|
{
|
||||||
INT32 i;
|
INT32 i;
|
||||||
|
@ -155,14 +164,14 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
|
||||||
p = (UINT8 *)fileneededstr;
|
p = (UINT8 *)fileneededstr;
|
||||||
for (i = 0; i < fileneedednum; i++)
|
for (i = 0; i < fileneedednum; i++)
|
||||||
{
|
{
|
||||||
fileneeded[i].status = FS_NOTFOUND;
|
fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet
|
||||||
filestatus = READUINT8(p);
|
filestatus = READUINT8(p); // The first byte is the file status
|
||||||
fileneeded[i].important = (UINT8)(filestatus & 3);
|
fileneeded[i].important = (UINT8)(filestatus & 3);
|
||||||
fileneeded[i].willsend = (UINT8)(filestatus >> 4);
|
fileneeded[i].willsend = (UINT8)(filestatus >> 4);
|
||||||
fileneeded[i].totalsize = READUINT32(p);
|
fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size
|
||||||
fileneeded[i].phandle = NULL;
|
fileneeded[i].file = NULL; // The file isn't open yet
|
||||||
READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH);
|
READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH); // The next bytes are the file name
|
||||||
READMEM(p, fileneeded[i].md5sum, 16);
|
READMEM(p, fileneeded[i].md5sum, 16); // The last 16 bytes are the file checksum
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,13 +180,16 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave)
|
||||||
fileneedednum = 1;
|
fileneedednum = 1;
|
||||||
fileneeded[0].status = FS_REQUESTED;
|
fileneeded[0].status = FS_REQUESTED;
|
||||||
fileneeded[0].totalsize = UINT32_MAX;
|
fileneeded[0].totalsize = UINT32_MAX;
|
||||||
fileneeded[0].phandle = NULL;
|
fileneeded[0].file = NULL;
|
||||||
memset(fileneeded[0].md5sum, 0, 16);
|
memset(fileneeded[0].md5sum, 0, 16);
|
||||||
strcpy(fileneeded[0].filename, tmpsave);
|
strcpy(fileneeded[0].filename, tmpsave);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Checks the server to see if we CAN download all the files,
|
/** Checks the server to see if we CAN download all the files,
|
||||||
* before starting to create them and requesting.
|
* before starting to create them and requesting.
|
||||||
|
*
|
||||||
|
* \return True if we can download all the files
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
boolean CL_CheckDownloadable(void)
|
boolean CL_CheckDownloadable(void)
|
||||||
{
|
{
|
||||||
|
@ -239,8 +251,12 @@ boolean CL_CheckDownloadable(void)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Send requests for files in the ::fileneeded table with a status of
|
/** Sends requests for files in the ::fileneeded table with a status of
|
||||||
* ::FS_NOTFOUND.
|
* ::FS_NOTFOUND.
|
||||||
|
*
|
||||||
|
* \return True if the packet was successfully sent
|
||||||
|
* \note Sends a PT_REQUESTFILE packet
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
boolean CL_SendRequestFile(void)
|
boolean CL_SendRequestFile(void)
|
||||||
{
|
{
|
||||||
|
@ -298,11 +314,17 @@ void Got_RequestFilePak(INT32 node)
|
||||||
if (id == 0xFF)
|
if (id == 0xFF)
|
||||||
break;
|
break;
|
||||||
READSTRINGN(p, wad, MAX_WADPATH);
|
READSTRINGN(p, wad, MAX_WADPATH);
|
||||||
SendFile(node, wad, id);
|
SV_SendFile(node, wad, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// client check if the fileneeded aren't already loaded or on the disk
|
/** Checks if the files needed aren't already loaded or on the disk
|
||||||
|
*
|
||||||
|
* \return 0 if some files are missing
|
||||||
|
* 1 if all files exist
|
||||||
|
* 2 if some already loaded files are not requested or are in a different order
|
||||||
|
*
|
||||||
|
*/
|
||||||
INT32 CL_CheckFiles(void)
|
INT32 CL_CheckFiles(void)
|
||||||
{
|
{
|
||||||
INT32 i, j;
|
INT32 i, j;
|
||||||
|
@ -333,7 +355,7 @@ INT32 CL_CheckFiles(void)
|
||||||
}
|
}
|
||||||
if (j < numwadfiles && W_VerifyNMUSlumps(wadfiles[j]->filename))
|
if (j < numwadfiles && W_VerifyNMUSlumps(wadfiles[j]->filename))
|
||||||
{
|
{
|
||||||
// unimportant on our side. still don't care.
|
// Unimportant on our side. still don't care.
|
||||||
++j;
|
++j;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -343,11 +365,11 @@ INT32 CL_CheckFiles(void)
|
||||||
if (i >= fileneedednum || j >= numwadfiles)
|
if (i >= fileneedednum || j >= numwadfiles)
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
// for the sake of speed, only bother with a md5 check
|
// For the sake of speed, only bother with a md5 check
|
||||||
if (memcmp(wadfiles[j]->md5sum, fileneeded[i].md5sum, 16))
|
if (memcmp(wadfiles[j]->md5sum, fileneeded[i].md5sum, 16))
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
// it's accounted for! let's keep going.
|
// It's accounted for! let's keep going.
|
||||||
CONS_Debug(DBG_NETPLAY, "'%s' accounted for\n", fileneeded[i].filename);
|
CONS_Debug(DBG_NETPLAY, "'%s' accounted for\n", fileneeded[i].filename);
|
||||||
fileneeded[i].status = FS_OPEN;
|
fileneeded[i].status = FS_OPEN;
|
||||||
++i;
|
++i;
|
||||||
|
@ -360,7 +382,7 @@ INT32 CL_CheckFiles(void)
|
||||||
{
|
{
|
||||||
CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
|
CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
|
||||||
|
|
||||||
// check in allready loaded files
|
// Check in already loaded files
|
||||||
for (j = 1; wadfiles[j]; j++)
|
for (j = 1; wadfiles[j]; j++)
|
||||||
{
|
{
|
||||||
nameonly(strcpy(wadfilename, wadfiles[j]->filename));
|
nameonly(strcpy(wadfilename, wadfiles[j]->filename));
|
||||||
|
@ -383,7 +405,7 @@ INT32 CL_CheckFiles(void)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// load it now
|
// Load it now
|
||||||
void CL_LoadServerFiles(void)
|
void CL_LoadServerFiles(void)
|
||||||
{
|
{
|
||||||
INT32 i;
|
INT32 i;
|
||||||
|
@ -394,7 +416,7 @@ void CL_LoadServerFiles(void)
|
||||||
for (i = 1; i < fileneedednum; i++)
|
for (i = 1; i < fileneedednum; i++)
|
||||||
{
|
{
|
||||||
if (fileneeded[i].status == FS_OPEN)
|
if (fileneeded[i].status == FS_OPEN)
|
||||||
continue; // already loaded
|
continue; // Already loaded
|
||||||
else if (fileneeded[i].status == FS_FOUND)
|
else if (fileneeded[i].status == FS_FOUND)
|
||||||
{
|
{
|
||||||
P_AddWadFile(fileneeded[i].filename, NULL);
|
P_AddWadFile(fileneeded[i].filename, NULL);
|
||||||
|
@ -423,172 +445,269 @@ void CL_LoadServerFiles(void)
|
||||||
DEBFILE(va("File %s found but with different md5sum\n", fileneeded[i].filename));
|
DEBFILE(va("File %s found but with different md5sum\n", fileneeded[i].filename));
|
||||||
}
|
}
|
||||||
else if (fileneeded[i].important)
|
else if (fileneeded[i].important)
|
||||||
I_Error("Try to load file %s with status of %d\n", fileneeded[i].filename,
|
{
|
||||||
fileneeded[i].status);
|
const char *s;
|
||||||
|
switch(fileneeded[i].status)
|
||||||
|
{
|
||||||
|
case FS_NOTFOUND:
|
||||||
|
s = "FS_NOTFOUND";
|
||||||
|
break;
|
||||||
|
case FS_REQUESTED:
|
||||||
|
s = "FS_REQUESTED";
|
||||||
|
break;
|
||||||
|
case FS_DOWNLOADING:
|
||||||
|
s = "FS_DOWNLOADING";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s = "unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
I_Error("Try to load file \"%s\" with status of %d (%s)\n", fileneeded[i].filename,
|
||||||
|
fileneeded[i].status, s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// little optimization to test if there is a file in the queue
|
// Number of files to send
|
||||||
static INT32 filetosend = 0;
|
// Little optimization to quickly test if there is a file in the queue
|
||||||
|
static INT32 filestosend = 0;
|
||||||
|
|
||||||
static void SendFile(INT32 node, const char *filename, UINT8 fileid)
|
/** Adds a file to the file list for a node
|
||||||
|
*
|
||||||
|
* \param node The node to send the file to
|
||||||
|
* \param filename The file to send
|
||||||
|
* \param fileid ???
|
||||||
|
* \sa SV_SendRam
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
|
||||||
{
|
{
|
||||||
filetx_t **q;
|
filetx_t **q; // A pointer to the "next" field of the last file in the list
|
||||||
filetx_t *p;
|
filetx_t *p; // The new file request
|
||||||
INT32 i;
|
INT32 i;
|
||||||
char wadfilename[MAX_WADPATH];
|
char wadfilename[MAX_WADPATH];
|
||||||
|
|
||||||
|
if (cv_noticedownload.value)
|
||||||
|
CONS_Printf("Sending file \"%s\" to node %d\n", filename, node);
|
||||||
|
|
||||||
|
// Find the last file in the list and set a pointer to its "next" field
|
||||||
q = &transfer[node].txlist;
|
q = &transfer[node].txlist;
|
||||||
while (*q)
|
while (*q)
|
||||||
q = &((*q)->next);
|
q = &((*q)->next);
|
||||||
|
|
||||||
|
// Allocate a file request and append it to the file list
|
||||||
p = *q = (filetx_t *)malloc(sizeof (filetx_t));
|
p = *q = (filetx_t *)malloc(sizeof (filetx_t));
|
||||||
if (p)
|
if (!p)
|
||||||
memset(p, 0, sizeof (filetx_t));
|
I_Error("SV_SendFile: No more memory\n");
|
||||||
else
|
|
||||||
I_Error("SendFile: No more ram\n");
|
|
||||||
p->filename = (char *)malloc(MAX_WADPATH);
|
|
||||||
if (!p->filename)
|
|
||||||
I_Error("SendFile: No more ram\n");
|
|
||||||
|
|
||||||
// a minimum of security, can get only file in srb2 direcory
|
// Initialise with zeros
|
||||||
strlcpy(p->filename, filename, MAX_WADPATH);
|
memset(p, 0, sizeof (filetx_t));
|
||||||
nameonly(p->filename);
|
|
||||||
|
|
||||||
// check first in wads loaded the majority of case
|
// Allocate the file name
|
||||||
|
p->id.filename = (char *)malloc(MAX_WADPATH);
|
||||||
|
if (!p->id.filename)
|
||||||
|
I_Error("SV_SendFile: No more memory\n");
|
||||||
|
|
||||||
|
// Set the file name and get rid of the path
|
||||||
|
strlcpy(p->id.filename, filename, MAX_WADPATH);
|
||||||
|
nameonly(p->id.filename);
|
||||||
|
|
||||||
|
// Look for the requested file through all loaded files
|
||||||
for (i = 0; wadfiles[i]; i++)
|
for (i = 0; wadfiles[i]; i++)
|
||||||
{
|
{
|
||||||
strlcpy(wadfilename, wadfiles[i]->filename, MAX_WADPATH);
|
strlcpy(wadfilename, wadfiles[i]->filename, MAX_WADPATH);
|
||||||
nameonly(wadfilename);
|
nameonly(wadfilename);
|
||||||
if (!stricmp(wadfilename, p->filename))
|
if (!stricmp(wadfilename, p->id.filename))
|
||||||
{
|
{
|
||||||
// copy filename with full path
|
// Copy file name with full path
|
||||||
strlcpy(p->filename, wadfiles[i]->filename, MAX_WADPATH);
|
strlcpy(p->id.filename, wadfiles[i]->filename, MAX_WADPATH);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle non-loaded file requests
|
||||||
if (!wadfiles[i])
|
if (!wadfiles[i])
|
||||||
{
|
{
|
||||||
DEBFILE(va("%s not found in wadfiles\n", filename));
|
DEBFILE(va("%s not found in wadfiles\n", filename));
|
||||||
// this formerly checked if (!findfile(p->filename, NULL, true))
|
// This formerly checked if (!findfile(p->id.filename, NULL, true))
|
||||||
|
|
||||||
// not found
|
// Not found
|
||||||
// don't inform client (probably hacker)
|
// Don't inform client (probably someone who thought they could leak 2.2 ACZ)
|
||||||
DEBFILE(va("Client %d request %s: not found\n", node, filename));
|
DEBFILE(va("Client %d request %s: not found\n", node, filename));
|
||||||
free(p->filename);
|
free(p->id.filename);
|
||||||
free(p);
|
free(p);
|
||||||
*q = NULL;
|
*q = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle huge file requests (i.e. bigger than cv_maxsend.value KB)
|
||||||
if (wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)
|
if (wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)
|
||||||
{
|
{
|
||||||
// too big
|
// Too big
|
||||||
// don't inform client (client sucks, man)
|
// Don't inform client (client sucks, man)
|
||||||
DEBFILE(va("Client %d request %s: file too big, not sending\n", node, filename));
|
DEBFILE(va("Client %d request %s: file too big, not sending\n", node, filename));
|
||||||
free(p->filename);
|
free(p->id.filename);
|
||||||
free(p);
|
free(p);
|
||||||
*q = NULL;
|
*q = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node));
|
DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node));
|
||||||
p->ram = SF_FILE;
|
p->ram = SF_FILE; // It's a file, we need to close it and free its name once we're done sending it
|
||||||
p->fileid = fileid;
|
p->fileid = fileid;
|
||||||
p->next = NULL; // end of list
|
p->next = NULL; // End of list
|
||||||
filetosend++;
|
filestosend++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid)
|
/** Adds a memory block to the file list for a node
|
||||||
|
*
|
||||||
|
* \param node The node to send the memory block to
|
||||||
|
* \param data The memory block to send
|
||||||
|
* \param size The size of the block in bytes
|
||||||
|
* \param freemethod How to free the block after it has been sent
|
||||||
|
* \param fileid ???
|
||||||
|
* \sa SV_SendFile
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid)
|
||||||
{
|
{
|
||||||
filetx_t **q;
|
filetx_t **q; // A pointer to the "next" field of the last file in the list
|
||||||
filetx_t *p;
|
filetx_t *p; // The new file request
|
||||||
|
|
||||||
|
// Find the last file in the list and set a pointer to its "next" field
|
||||||
q = &transfer[node].txlist;
|
q = &transfer[node].txlist;
|
||||||
while (*q)
|
while (*q)
|
||||||
q = &((*q)->next);
|
q = &((*q)->next);
|
||||||
|
|
||||||
|
// Allocate a file request and append it to the file list
|
||||||
p = *q = (filetx_t *)malloc(sizeof (filetx_t));
|
p = *q = (filetx_t *)malloc(sizeof (filetx_t));
|
||||||
if (p)
|
if (!p)
|
||||||
memset(p, 0, sizeof (filetx_t));
|
I_Error("SV_SendRam: No more memory\n");
|
||||||
else
|
|
||||||
I_Error("SendRam: No more ram\n");
|
// Initialise with zeros
|
||||||
p->ram = freemethod;
|
memset(p, 0, sizeof (filetx_t));
|
||||||
p->filename = data;
|
|
||||||
|
p->ram = freemethod; // Remember how to free the memory block for when we're done sending it
|
||||||
|
p->id.ram = data;
|
||||||
p->size = (UINT32)size;
|
p->size = (UINT32)size;
|
||||||
p->fileid = fileid;
|
p->fileid = fileid;
|
||||||
p->next = NULL; // end of list
|
p->next = NULL; // End of list
|
||||||
|
|
||||||
DEBFILE(va("Sending ram %p(size:%u) to %d (id=%u)\n",p->filename,p->size,node,fileid));
|
DEBFILE(va("Sending ram %p(size:%u) to %d (id=%u)\n",p->id.ram,p->size,node,fileid));
|
||||||
|
|
||||||
filetosend++;
|
filestosend++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EndSend(INT32 node)
|
/** Stops sending a file for a node, and removes the file request from the list,
|
||||||
|
* either because the file has been fully sent or because the node was disconnected
|
||||||
|
*
|
||||||
|
* \param node The destination
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void SV_EndFileSend(INT32 node)
|
||||||
{
|
{
|
||||||
filetx_t *p = transfer[node].txlist;
|
filetx_t *p = transfer[node].txlist;
|
||||||
|
|
||||||
|
// Free the file request according to the freemethod parameter used with SV_SendFile/Ram
|
||||||
switch (p->ram)
|
switch (p->ram)
|
||||||
{
|
{
|
||||||
case SF_FILE:
|
case SF_FILE: // It's a file, close it and free its filename
|
||||||
|
if (cv_noticedownload.value)
|
||||||
|
CONS_Printf("Ending file transfer for node %d\n", node);
|
||||||
if (transfer[node].currentfile)
|
if (transfer[node].currentfile)
|
||||||
fclose(transfer[node].currentfile);
|
fclose(transfer[node].currentfile);
|
||||||
free(p->filename);
|
free(p->id.filename);
|
||||||
break;
|
break;
|
||||||
case SF_Z_RAM:
|
case SF_Z_RAM: // It's a memory block allocated with Z_Alloc or the likes, use Z_Free
|
||||||
Z_Free(p->filename);
|
Z_Free(p->id.ram);
|
||||||
break;
|
break;
|
||||||
case SF_RAM:
|
case SF_RAM: // It's a memory block allocated with malloc, use free
|
||||||
free(p->filename);
|
free(p->id.ram);
|
||||||
case SF_NOFREERAM:
|
case SF_NOFREERAM: // Nothing to free
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the file request from the list
|
||||||
transfer[node].txlist = p->next;
|
transfer[node].txlist = p->next;
|
||||||
transfer[node].currentfile = NULL;
|
|
||||||
free(p);
|
free(p);
|
||||||
filetosend--;
|
|
||||||
|
// Indicate that the transmission is over
|
||||||
|
transfer[node].currentfile = NULL;
|
||||||
|
|
||||||
|
filestosend--;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PACKETPERTIC net_bandwidth/(TICRATE*software_MAXPACKETLENGTH)
|
#define PACKETPERTIC net_bandwidth/(TICRATE*software_MAXPACKETLENGTH)
|
||||||
|
|
||||||
void FiletxTicker(void)
|
/** Handles file transmission
|
||||||
|
*
|
||||||
|
* \todo Use an acknowledging method more adapted to file transmission
|
||||||
|
* The current download speed suffers from lack of ack packets,
|
||||||
|
* especially when the one downloading has high latency
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void SV_FileSendTicker(void)
|
||||||
{
|
{
|
||||||
static INT32 currentnode = 0;
|
static INT32 currentnode = 0;
|
||||||
filetx_pak *p;
|
filetx_pak *p;
|
||||||
size_t size;
|
size_t size;
|
||||||
filetx_t *f;
|
filetx_t *f;
|
||||||
INT32 packetsent = PACKETPERTIC, ram, i;
|
INT32 packetsent, ram, i, j;
|
||||||
|
INT32 maxpacketsent;
|
||||||
|
|
||||||
if (!filetosend)
|
if (!filestosend) // No file to send
|
||||||
return;
|
return;
|
||||||
if (!packetsent)
|
|
||||||
packetsent++;
|
if (cv_downloadspeed.value) // New (and experimental) behavior
|
||||||
// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
|
|
||||||
while (packetsent-- && filetosend != 0)
|
|
||||||
{
|
{
|
||||||
for (i = currentnode, ram = 0; ram < MAXNETNODES;
|
packetsent = cv_downloadspeed.value;
|
||||||
i = (i+1) % MAXNETNODES, ram++)
|
// Don't send more packets than we have free acks
|
||||||
|
#ifndef NONET
|
||||||
|
maxpacketsent = Net_GetFreeAcks(false) - 5; // Let 5 extra acks just in case
|
||||||
|
#else
|
||||||
|
maxpacketsent = 1;
|
||||||
|
#endif
|
||||||
|
if (packetsent > maxpacketsent && maxpacketsent > 0) // Send at least one packet
|
||||||
|
packetsent = maxpacketsent;
|
||||||
|
}
|
||||||
|
else // Old behavior
|
||||||
|
{
|
||||||
|
packetsent = PACKETPERTIC;
|
||||||
|
if (!packetsent)
|
||||||
|
packetsent = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
netbuffer->packettype = PT_FILEFRAGMENT;
|
||||||
|
|
||||||
|
// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
|
||||||
|
while (packetsent-- && filestosend != 0)
|
||||||
|
{
|
||||||
|
for (i = currentnode, j = 0; j < MAXNETNODES;
|
||||||
|
i = (i+1) % MAXNETNODES, j++)
|
||||||
{
|
{
|
||||||
if (transfer[i].txlist)
|
if (transfer[i].txlist)
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
// no transfer to do
|
// no transfer to do
|
||||||
I_Error("filetosend=%d but no filetosend found\n", filetosend);
|
I_Error("filestosend=%d but no file to send found\n", filestosend);
|
||||||
found:
|
found:
|
||||||
currentnode = (i+1) % MAXNETNODES;
|
currentnode = (i+1) % MAXNETNODES;
|
||||||
f = transfer[i].txlist;
|
f = transfer[i].txlist;
|
||||||
ram = f->ram;
|
ram = f->ram;
|
||||||
|
|
||||||
if (!transfer[i].currentfile) // file not already open
|
// Open the file if it isn't open yet, or
|
||||||
|
if (!transfer[i].currentfile)
|
||||||
{
|
{
|
||||||
if (!ram)
|
if (!ram) // Sending a file
|
||||||
{
|
{
|
||||||
long filesize;
|
long filesize;
|
||||||
|
|
||||||
transfer[i].currentfile =
|
transfer[i].currentfile =
|
||||||
fopen(f->filename, "rb");
|
fopen(f->id.filename, "rb");
|
||||||
|
|
||||||
if (!transfer[i].currentfile)
|
if (!transfer[i].currentfile)
|
||||||
I_Error("File %s does not exist",
|
I_Error("File %s does not exist",
|
||||||
f->filename);
|
f->id.filename);
|
||||||
|
|
||||||
fseek(transfer[i].currentfile, 0, SEEK_END);
|
fseek(transfer[i].currentfile, 0, SEEK_END);
|
||||||
filesize = ftell(transfer[i].currentfile);
|
filesize = ftell(transfer[i].currentfile);
|
||||||
|
@ -596,45 +715,47 @@ void FiletxTicker(void)
|
||||||
// Nobody wants to transfer a file bigger
|
// Nobody wants to transfer a file bigger
|
||||||
// than 4GB!
|
// than 4GB!
|
||||||
if (filesize >= LONG_MAX)
|
if (filesize >= LONG_MAX)
|
||||||
I_Error("filesize of %s is too large", f->filename);
|
I_Error("filesize of %s is too large", f->id.filename);
|
||||||
if (-1 == filesize)
|
if (filesize == -1)
|
||||||
I_Error("Error getting filesize of %s", f->filename);
|
I_Error("Error getting filesize of %s", f->id.filename);
|
||||||
|
|
||||||
f->size = (UINT32)filesize;
|
f->size = (UINT32)filesize;
|
||||||
fseek(transfer[i].currentfile, 0, SEEK_SET);
|
fseek(transfer[i].currentfile, 0, SEEK_SET);
|
||||||
}
|
}
|
||||||
else
|
else // Sending RAM
|
||||||
transfer[i].currentfile = (FILE *)1;
|
transfer[i].currentfile = (FILE *)1; // Set currentfile to a non-null value to indicate that it is open
|
||||||
transfer[i].position = 0;
|
transfer[i].position = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build a packet containing a file fragment
|
||||||
p = &netbuffer->u.filetxpak;
|
p = &netbuffer->u.filetxpak;
|
||||||
size = software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE);
|
size = software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE);
|
||||||
if (f->size-transfer[i].position < size)
|
if (f->size-transfer[i].position < size)
|
||||||
size = f->size-transfer[i].position;
|
size = f->size-transfer[i].position;
|
||||||
if (ram)
|
if (ram)
|
||||||
M_Memcpy(p->data, &f->filename[transfer[i].position], size);
|
M_Memcpy(p->data, &f->id.ram[transfer[i].position], size);
|
||||||
else if (fread(p->data, 1, size, transfer[i].currentfile) != size)
|
else if (fread(p->data, 1, size, transfer[i].currentfile) != size)
|
||||||
I_Error("FiletxTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->filename, transfer[i].position, strerror(ferror(transfer[i].currentfile)));
|
I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, strerror(ferror(transfer[i].currentfile)));
|
||||||
p->position = LONG(transfer[i].position);
|
p->position = LONG(transfer[i].position);
|
||||||
// put flag so receiver know the totalsize
|
// Put flag so receiver knows the total size
|
||||||
if (transfer[i].position + size == f->size)
|
if (transfer[i].position + size == f->size)
|
||||||
p->position |= LONG(0x80000000);
|
p->position |= LONG(0x80000000);
|
||||||
p->fileid = f->fileid;
|
p->fileid = f->fileid;
|
||||||
p->size = SHORT((UINT16)size);
|
p->size = SHORT((UINT16)size);
|
||||||
netbuffer->packettype = PT_FILEFRAGMENT;
|
|
||||||
if (!HSendPacket(i, true, 0, FILETXHEADER + size)) // reliable SEND
|
// Send the packet
|
||||||
{ // not sent for some odd reason, retry at next call
|
if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND
|
||||||
if (!ram)
|
{ // Success
|
||||||
fseek(transfer[i].currentfile,transfer[i].position,SEEK_SET);
|
transfer[i].position = (UINT32)(transfer[i].position + size);
|
||||||
// exit the while (can't send this one so why should i send the next?)
|
if (transfer[i].position == f->size) // Finish?
|
||||||
break;
|
SV_EndFileSend(i);
|
||||||
}
|
}
|
||||||
else // success
|
else
|
||||||
{
|
{ // Not sent for some odd reason, retry at next call
|
||||||
transfer[i].position = (UINT32)(size+transfer[i].position);
|
if (!ram)
|
||||||
if (transfer[i].position == f->size) // finish ?
|
fseek(transfer[i].currentfile,transfer[i].position, SEEK_SET);
|
||||||
EndSend(i);
|
// Exit the while (can't send this one so why should i send the next?)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -642,55 +763,90 @@ void FiletxTicker(void)
|
||||||
void Got_Filetxpak(void)
|
void Got_Filetxpak(void)
|
||||||
{
|
{
|
||||||
INT32 filenum = netbuffer->u.filetxpak.fileid;
|
INT32 filenum = netbuffer->u.filetxpak.fileid;
|
||||||
|
fileneeded_t *file = &fileneeded[filenum];
|
||||||
|
char *filename = file->filename;
|
||||||
static INT32 filetime = 0;
|
static INT32 filetime = 0;
|
||||||
|
|
||||||
|
if (!(strcmp(filename, "srb2.srb")
|
||||||
|
&& strcmp(filename, "srb2.wad")
|
||||||
|
&& strcmp(filename, "zones.dta")
|
||||||
|
&& strcmp(filename, "player.dta")
|
||||||
|
&& strcmp(filename, "rings.dta")
|
||||||
|
&& strcmp(filename, "patch.dta")
|
||||||
|
&& strcmp(filename, "music.dta")
|
||||||
|
))
|
||||||
|
I_Error("Tried to download \"%s\"", filename);
|
||||||
|
|
||||||
if (filenum >= fileneedednum)
|
if (filenum >= fileneedednum)
|
||||||
{
|
{
|
||||||
DEBFILE(va("fileframent not needed %d>%d\n",filenum, fileneedednum));
|
DEBFILE(va("fileframent not needed %d>%d\n", filenum, fileneedednum));
|
||||||
|
//I_Error("Received an unneeded file fragment (file id received: %d, file id needed: %d)\n", filenum, fileneedednum);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileneeded[filenum].status == FS_REQUESTED)
|
if (file->status == FS_REQUESTED)
|
||||||
{
|
{
|
||||||
if (fileneeded[filenum].phandle) I_Error("Got_Filetxpak: allready open file\n");
|
if (file->file)
|
||||||
fileneeded[filenum].phandle = fopen(fileneeded[filenum].filename, "wb");
|
I_Error("Got_Filetxpak: already open file\n");
|
||||||
if (!fileneeded[filenum].phandle) I_Error("Can't create file %s: %s",fileneeded[filenum].filename, strerror(errno));
|
file->file = fopen(filename, "wb");
|
||||||
CONS_Printf("\r%s...\n",fileneeded[filenum].filename);
|
if (!file->file)
|
||||||
fileneeded[filenum].currentsize = 0;
|
I_Error("Can't create file %s: %s", filename, strerror(errno));
|
||||||
fileneeded[filenum].status = FS_DOWNLOADING;
|
CONS_Printf("\r%s...\n",filename);
|
||||||
|
file->currentsize = 0;
|
||||||
|
file->status = FS_DOWNLOADING;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileneeded[filenum].status == FS_DOWNLOADING)
|
if (file->status == FS_DOWNLOADING)
|
||||||
{
|
{
|
||||||
UINT32 pos = LONG(netbuffer->u.filetxpak.position);
|
UINT32 pos = LONG(netbuffer->u.filetxpak.position);
|
||||||
UINT16 size = SHORT(netbuffer->u.filetxpak.size);
|
UINT16 size = SHORT(netbuffer->u.filetxpak.size);
|
||||||
// use a special tric to know when file is finished (not allways used)
|
// Use a special trick to know when the file is complete (not always used)
|
||||||
// WARNING: filepak can arrive out of order so don't stop now !
|
// WARNING: file fragments can arrive out of order so don't stop yet!
|
||||||
if (pos & 0x80000000)
|
if (pos & 0x80000000)
|
||||||
{
|
{
|
||||||
pos &= ~0x80000000;
|
pos &= ~0x80000000;
|
||||||
fileneeded[filenum].totalsize = pos + size;
|
file->totalsize = pos + size;
|
||||||
}
|
}
|
||||||
// we can receive packet in the wrong order, anyway all os support gaped file
|
// We can receive packet in the wrong order, anyway all os support gaped file
|
||||||
fseek(fileneeded[filenum].phandle,pos,SEEK_SET);
|
fseek(file->file, pos, SEEK_SET);
|
||||||
if (fwrite(netbuffer->u.filetxpak.data,size,1,fileneeded[filenum].phandle)!=1)
|
if (fwrite(netbuffer->u.filetxpak.data,size,1,file->file) != 1)
|
||||||
I_Error("Can't write to %s: %s\n",fileneeded[filenum].filename, strerror(ferror(fileneeded[filenum].phandle)));
|
I_Error("Can't write to %s: %s\n",filename, strerror(ferror(file->file)));
|
||||||
fileneeded[filenum].currentsize += size;
|
file->currentsize += size;
|
||||||
|
|
||||||
// finished?
|
// Finished?
|
||||||
if (fileneeded[filenum].currentsize == fileneeded[filenum].totalsize)
|
if (file->currentsize == file->totalsize)
|
||||||
{
|
{
|
||||||
fclose(fileneeded[filenum].phandle);
|
fclose(file->file);
|
||||||
fileneeded[filenum].phandle = NULL;
|
file->file = NULL;
|
||||||
fileneeded[filenum].status = FS_FOUND;
|
file->status = FS_FOUND;
|
||||||
CONS_Printf(M_GetText("Downloading %s...(done)\n"),
|
CONS_Printf(M_GetText("Downloading %s...(done)\n"),
|
||||||
fileneeded[filenum].filename);
|
filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
I_Error("Received a file not requested\n");
|
{
|
||||||
// send ack back quickly
|
const char *s;
|
||||||
|
switch(file->status)
|
||||||
|
{
|
||||||
|
case FS_NOTFOUND:
|
||||||
|
s = "FS_NOTFOUND";
|
||||||
|
break;
|
||||||
|
case FS_FOUND:
|
||||||
|
s = "FS_FOUND";
|
||||||
|
break;
|
||||||
|
case FS_OPEN:
|
||||||
|
s = "FS_OPEN";
|
||||||
|
break;
|
||||||
|
case FS_MD5SUMBAD:
|
||||||
|
s = "FS_MD5SUMBAD";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s = "unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
I_Error("Received a file not requested (file id: %d, file status: %s)\n", filenum, s);
|
||||||
|
}
|
||||||
|
// Send ack back quickly
|
||||||
if (++filetime == 3)
|
if (++filetime == 3)
|
||||||
{
|
{
|
||||||
Net_SendAcks(servernode);
|
Net_SendAcks(servernode);
|
||||||
|
@ -702,33 +858,50 @@ void Got_Filetxpak(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbortSendFiles(INT32 node)
|
/** \brief Checks if a node is downloading a file
|
||||||
|
*
|
||||||
|
* \param node The node to check for
|
||||||
|
* \return True if the node is downloading a file
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
boolean SV_SendingFile(INT32 node)
|
||||||
|
{
|
||||||
|
return transfer[node].txlist != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Cancels all file requests for a node
|
||||||
|
*
|
||||||
|
* \param node The destination
|
||||||
|
* \sa SV_EndFileSend
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void SV_AbortSendFiles(INT32 node)
|
||||||
{
|
{
|
||||||
while (transfer[node].txlist)
|
while (transfer[node].txlist)
|
||||||
EndSend(node);
|
SV_EndFileSend(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CloseNetFile(void)
|
void CloseNetFile(void)
|
||||||
{
|
{
|
||||||
INT32 i;
|
INT32 i;
|
||||||
// is sending?
|
// Is sending?
|
||||||
for (i = 0; i < MAXNETNODES; i++)
|
for (i = 0; i < MAXNETNODES; i++)
|
||||||
AbortSendFiles(i);
|
SV_AbortSendFiles(i);
|
||||||
|
|
||||||
// receiving a file?
|
// Receiving a file?
|
||||||
for (i = 0; i < MAX_WADFILES; i++)
|
for (i = 0; i < MAX_WADFILES; i++)
|
||||||
if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].phandle)
|
if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file)
|
||||||
{
|
{
|
||||||
fclose(fileneeded[i].phandle);
|
fclose(fileneeded[i].file);
|
||||||
// file is not complete delete it
|
// File is not complete delete it
|
||||||
remove(fileneeded[i].filename);
|
remove(fileneeded[i].filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove FILEFRAGMENT from acknledge list
|
// Remove PT_FILEFRAGMENT from acknowledge list
|
||||||
Net_AbortPacketType(PT_FILEFRAGMENT);
|
Net_AbortPacketType(PT_FILEFRAGMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// functions cut and pasted from doomatic :)
|
// Functions cut and pasted from Doomatic :)
|
||||||
|
|
||||||
void nameonly(char *s)
|
void nameonly(char *s)
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,21 +29,21 @@ typedef enum
|
||||||
FS_FOUND,
|
FS_FOUND,
|
||||||
FS_REQUESTED,
|
FS_REQUESTED,
|
||||||
FS_DOWNLOADING,
|
FS_DOWNLOADING,
|
||||||
FS_OPEN, // is opened and used in w_wad
|
FS_OPEN, // Is opened and used in w_wad
|
||||||
FS_MD5SUMBAD
|
FS_MD5SUMBAD
|
||||||
} filestatus_t;
|
} filestatus_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
UINT8 important;
|
UINT8 important;
|
||||||
UINT8 willsend; // is the server willing to send it?
|
UINT8 willsend; // Is the server willing to send it?
|
||||||
char filename[MAX_WADPATH];
|
char filename[MAX_WADPATH];
|
||||||
UINT8 md5sum[16];
|
UINT8 md5sum[16];
|
||||||
// used only for download
|
// Used only for download
|
||||||
FILE *phandle;
|
FILE *file;
|
||||||
UINT32 currentsize;
|
UINT32 currentsize;
|
||||||
UINT32 totalsize;
|
UINT32 totalsize;
|
||||||
filestatus_t status; // the value returned by recsearch
|
filestatus_t status; // The value returned by recsearch
|
||||||
} fileneeded_t;
|
} fileneeded_t;
|
||||||
|
|
||||||
extern INT32 fileneedednum;
|
extern INT32 fileneedednum;
|
||||||
|
@ -58,28 +58,25 @@ UINT8 *PutFileNeeded(void);
|
||||||
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr);
|
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr);
|
||||||
void CL_PrepareDownloadSaveGame(const char *tmpsave);
|
void CL_PrepareDownloadSaveGame(const char *tmpsave);
|
||||||
|
|
||||||
// check file list in wadfiles return 0 when a file is not found
|
|
||||||
// 1 if all file are found
|
|
||||||
// 2 if you cannot connect (different wad version or
|
|
||||||
// no enought space to download files)
|
|
||||||
INT32 CL_CheckFiles(void);
|
INT32 CL_CheckFiles(void);
|
||||||
void CL_LoadServerFiles(void);
|
void CL_LoadServerFiles(void);
|
||||||
void SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod,
|
void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod,
|
||||||
UINT8 fileid);
|
UINT8 fileid);
|
||||||
|
|
||||||
void FiletxTicker(void);
|
void SV_FileSendTicker(void);
|
||||||
void Got_Filetxpak(void);
|
void Got_Filetxpak(void);
|
||||||
|
boolean SV_SendingFile(INT32 node);
|
||||||
|
|
||||||
boolean CL_CheckDownloadable(void);
|
boolean CL_CheckDownloadable(void);
|
||||||
boolean CL_SendRequestFile(void);
|
boolean CL_SendRequestFile(void);
|
||||||
void Got_RequestFilePak(INT32 node);
|
void Got_RequestFilePak(INT32 node);
|
||||||
|
|
||||||
void AbortSendFiles(INT32 node);
|
void SV_AbortSendFiles(INT32 node);
|
||||||
void CloseNetFile(void);
|
void CloseNetFile(void);
|
||||||
|
|
||||||
boolean fileexist(char *filename, time_t ptime);
|
boolean fileexist(char *filename, time_t ptime);
|
||||||
|
|
||||||
// search a file in the wadpath, return FS_FOUND when found
|
// Search a file in the wadpath, return FS_FOUND when found
|
||||||
filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum,
|
filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum,
|
||||||
boolean completepath);
|
boolean completepath);
|
||||||
filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum);
|
filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum);
|
||||||
|
|
|
@ -150,9 +150,9 @@ extern FILE *logstream;
|
||||||
// we use comprevision and compbranch instead.
|
// we use comprevision and compbranch instead.
|
||||||
#else
|
#else
|
||||||
#define VERSION 201 // Game version
|
#define VERSION 201 // Game version
|
||||||
#define SUBVERSION 16 // more precise version number
|
#define SUBVERSION 17 // more precise version number
|
||||||
#define VERSIONSTRING "v2.1.16"
|
#define VERSIONSTRING "v2.1.17"
|
||||||
#define VERSIONSTRINGW L"v2.1.16"
|
#define VERSIONSTRINGW L"v2.1.17"
|
||||||
// Hey! If you change this, add 1 to the MODVERSION below!
|
// Hey! If you change this, add 1 to the MODVERSION below!
|
||||||
// Otherwise we can't force updates!
|
// Otherwise we can't force updates!
|
||||||
#endif
|
#endif
|
||||||
|
@ -214,7 +214,7 @@ extern FILE *logstream;
|
||||||
// it's only for detection of the version the player is using so the MS can alert them of an update.
|
// it's only for detection of the version the player is using so the MS can alert them of an update.
|
||||||
// Only set it higher, not lower, obviously.
|
// Only set it higher, not lower, obviously.
|
||||||
// Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1".
|
// Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1".
|
||||||
#define MODVERSION 21
|
#define MODVERSION 22
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
|
|
|
@ -974,7 +974,7 @@ static const char *credits[] = {
|
||||||
"Scott \"Graue\" Feeney",
|
"Scott \"Graue\" Feeney",
|
||||||
"Nathan \"Jazz\" Giroux",
|
"Nathan \"Jazz\" Giroux",
|
||||||
"Thomas \"Shadow Hog\" Igoe",
|
"Thomas \"Shadow Hog\" Igoe",
|
||||||
"\"Monster\" Iestyn Jealous",
|
"Iestyn \"Monster Iestyn\" Jealous",
|
||||||
"Ronald \"Furyhunter\" Kinard", // The SDL2 port
|
"Ronald \"Furyhunter\" Kinard", // The SDL2 port
|
||||||
"John \"JTE\" Muniz",
|
"John \"JTE\" Muniz",
|
||||||
"Ehab \"Wolfy\" Saeed",
|
"Ehab \"Wolfy\" Saeed",
|
||||||
|
@ -986,6 +986,7 @@ static const char *credits[] = {
|
||||||
"\"chi.miru\"", // Red's secret weapon, the REAL reason slopes exist (also helped port drawing code from ZDoom)
|
"\"chi.miru\"", // Red's secret weapon, the REAL reason slopes exist (also helped port drawing code from ZDoom)
|
||||||
"Andrew \"orospakr\" Clunis",
|
"Andrew \"orospakr\" Clunis",
|
||||||
"Gregor \"Oogaland\" Dick",
|
"Gregor \"Oogaland\" Dick",
|
||||||
|
"Louis-Antoine \"LJSonic\" de Moulins", // for fixing 2.1's netcode (de Rochefort doesn't quite fit on the screen sorry lol)
|
||||||
"Vivian \"toaster\" Grannell",
|
"Vivian \"toaster\" Grannell",
|
||||||
"Julio \"Chaos Zero 64\" Guir",
|
"Julio \"Chaos Zero 64\" Guir",
|
||||||
"\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog
|
"\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog
|
||||||
|
@ -1020,7 +1021,7 @@ static const char *credits[] = {
|
||||||
"Paul \"Boinciel\" Clempson",
|
"Paul \"Boinciel\" Clempson",
|
||||||
"Cyan Helkaraxe",
|
"Cyan Helkaraxe",
|
||||||
"Kepa \"Nev3r\" Iceta",
|
"Kepa \"Nev3r\" Iceta",
|
||||||
"\"Monster\" Iestyn Jealous",
|
"Iestyn \"Monster Iestyn\" Jealous",
|
||||||
"Jarel \"Arrow\" Jones",
|
"Jarel \"Arrow\" Jones",
|
||||||
"Stefan \"Stuf\" Rimalia",
|
"Stefan \"Stuf\" Rimalia",
|
||||||
"Shane Mychal Sexton",
|
"Shane Mychal Sexton",
|
||||||
|
|
|
@ -2888,7 +2888,7 @@ static void G_DoCompleted(void)
|
||||||
if (nextmap < NUMMAPS && !mapheaderinfo[nextmap])
|
if (nextmap < NUMMAPS && !mapheaderinfo[nextmap])
|
||||||
P_AllocMapHeader(nextmap);
|
P_AllocMapHeader(nextmap);
|
||||||
|
|
||||||
if (skipstats)
|
if (skipstats && !modeattacking) // Don't skip stats if we're in record attack
|
||||||
G_AfterIntermission();
|
G_AfterIntermission();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -1558,6 +1558,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
||||||
|
|
||||||
if (gr_backsector)
|
if (gr_backsector)
|
||||||
{
|
{
|
||||||
|
INT32 gr_toptexture, gr_bottomtexture;
|
||||||
// two sided line
|
// two sided line
|
||||||
if (gr_backsector->heightsec != -1)
|
if (gr_backsector->heightsec != -1)
|
||||||
{
|
{
|
||||||
|
@ -1608,19 +1609,22 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gr_toptexture = R_GetTextureNum(gr_sidedef->toptexture);
|
||||||
|
gr_bottomtexture = R_GetTextureNum(gr_sidedef->bottomtexture);
|
||||||
|
|
||||||
// check TOP TEXTURE
|
// check TOP TEXTURE
|
||||||
if ((
|
if ((
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
worldhighslope < worldtopslope ||
|
worldhighslope < worldtopslope ||
|
||||||
#endif
|
#endif
|
||||||
worldhigh < worldtop
|
worldhigh < worldtop
|
||||||
) && texturetranslation[gr_sidedef->toptexture])
|
) && gr_toptexture)
|
||||||
{
|
{
|
||||||
if (drawtextured)
|
if (drawtextured)
|
||||||
{
|
{
|
||||||
fixed_t texturevpegtop; // top
|
fixed_t texturevpegtop; // top
|
||||||
|
|
||||||
grTex = HWR_GetTexture(texturetranslation[gr_sidedef->toptexture]);
|
grTex = HWR_GetTexture(gr_toptexture);
|
||||||
|
|
||||||
// PEGGING
|
// PEGGING
|
||||||
if (gr_linedef->flags & ML_DONTPEGTOP)
|
if (gr_linedef->flags & ML_DONTPEGTOP)
|
||||||
|
@ -1638,7 +1642,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
||||||
texturevpegtop += gr_sidedef->rowoffset;
|
texturevpegtop += gr_sidedef->rowoffset;
|
||||||
|
|
||||||
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
|
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
|
||||||
texturevpegtop %= SHORT(textures[texturetranslation[gr_sidedef->toptexture]]->height)<<FRACBITS;
|
texturevpegtop %= SHORT(textures[gr_toptexture]->height)<<FRACBITS;
|
||||||
|
|
||||||
wallVerts[3].t = wallVerts[2].t = texturevpegtop * grTex->scaleY;
|
wallVerts[3].t = wallVerts[2].t = texturevpegtop * grTex->scaleY;
|
||||||
wallVerts[0].t = wallVerts[1].t = (texturevpegtop + gr_frontsector->ceilingheight - gr_backsector->ceilingheight) * grTex->scaleY;
|
wallVerts[0].t = wallVerts[1].t = (texturevpegtop + gr_frontsector->ceilingheight - gr_backsector->ceilingheight) * grTex->scaleY;
|
||||||
|
@ -1683,9 +1687,9 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (gr_frontsector->numlights)
|
if (gr_frontsector->numlights)
|
||||||
HWR_SplitWall(gr_frontsector, wallVerts, texturetranslation[gr_sidedef->toptexture], &Surf, FF_CUTSOLIDS);
|
HWR_SplitWall(gr_frontsector, wallVerts, gr_toptexture, &Surf, FF_CUTSOLIDS);
|
||||||
else if (grTex->mipmap.flags & TF_TRANSPARENT)
|
else if (grTex->mipmap.flags & TF_TRANSPARENT)
|
||||||
HWR_AddTransparentWall(wallVerts, &Surf, texturetranslation[gr_sidedef->toptexture], PF_Environment, false, lightnum, colormap);
|
HWR_AddTransparentWall(wallVerts, &Surf, gr_toptexture, PF_Environment, false, lightnum, colormap);
|
||||||
else
|
else
|
||||||
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
|
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
|
||||||
}
|
}
|
||||||
|
@ -1695,13 +1699,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
worldlowslope > worldbottomslope ||
|
worldlowslope > worldbottomslope ||
|
||||||
#endif
|
#endif
|
||||||
worldlow > worldbottom) && texturetranslation[gr_sidedef->bottomtexture]) //only if VISIBLE!!!
|
worldlow > worldbottom) && gr_bottomtexture) //only if VISIBLE!!!
|
||||||
{
|
{
|
||||||
if (drawtextured)
|
if (drawtextured)
|
||||||
{
|
{
|
||||||
fixed_t texturevpegbottom = 0; // bottom
|
fixed_t texturevpegbottom = 0; // bottom
|
||||||
|
|
||||||
grTex = HWR_GetTexture(texturetranslation[gr_sidedef->bottomtexture]);
|
grTex = HWR_GetTexture(gr_bottomtexture);
|
||||||
|
|
||||||
// PEGGING
|
// PEGGING
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
|
@ -1721,7 +1725,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
||||||
texturevpegbottom += gr_sidedef->rowoffset;
|
texturevpegbottom += gr_sidedef->rowoffset;
|
||||||
|
|
||||||
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
|
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
|
||||||
texturevpegbottom %= SHORT(textures[texturetranslation[gr_sidedef->bottomtexture]]->height)<<FRACBITS;
|
texturevpegbottom %= SHORT(textures[gr_bottomtexture]->height)<<FRACBITS;
|
||||||
|
|
||||||
wallVerts[3].t = wallVerts[2].t = texturevpegbottom * grTex->scaleY;
|
wallVerts[3].t = wallVerts[2].t = texturevpegbottom * grTex->scaleY;
|
||||||
wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + gr_backsector->floorheight - gr_frontsector->floorheight) * grTex->scaleY;
|
wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + gr_backsector->floorheight - gr_frontsector->floorheight) * grTex->scaleY;
|
||||||
|
@ -1766,13 +1770,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (gr_frontsector->numlights)
|
if (gr_frontsector->numlights)
|
||||||
HWR_SplitWall(gr_frontsector, wallVerts, texturetranslation[gr_sidedef->bottomtexture], &Surf, FF_CUTSOLIDS);
|
HWR_SplitWall(gr_frontsector, wallVerts, gr_bottomtexture, &Surf, FF_CUTSOLIDS);
|
||||||
else if (grTex->mipmap.flags & TF_TRANSPARENT)
|
else if (grTex->mipmap.flags & TF_TRANSPARENT)
|
||||||
HWR_AddTransparentWall(wallVerts, &Surf, texturetranslation[gr_sidedef->bottomtexture], PF_Environment, false, lightnum, colormap);
|
HWR_AddTransparentWall(wallVerts, &Surf, gr_bottomtexture, PF_Environment, false, lightnum, colormap);
|
||||||
else
|
else
|
||||||
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
|
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
|
||||||
}
|
}
|
||||||
gr_midtexture = texturetranslation[gr_sidedef->midtexture];
|
gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
|
||||||
if (gr_midtexture)
|
if (gr_midtexture)
|
||||||
{
|
{
|
||||||
FBITFIELD blendmode;
|
FBITFIELD blendmode;
|
||||||
|
@ -2134,7 +2138,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Single sided line... Deal only with the middletexture (if one exists)
|
// Single sided line... Deal only with the middletexture (if one exists)
|
||||||
gr_midtexture = texturetranslation[gr_sidedef->midtexture];
|
gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
|
||||||
if (gr_midtexture)
|
if (gr_midtexture)
|
||||||
{
|
{
|
||||||
if (drawtextured)
|
if (drawtextured)
|
||||||
|
@ -2232,13 +2236,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
||||||
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
|
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture];
|
texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
|
||||||
|
|
||||||
if (rover->master->flags & ML_TFERLINE)
|
if (rover->master->flags & ML_TFERLINE)
|
||||||
{
|
{
|
||||||
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
|
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
|
||||||
newline = rover->master->frontsector->lines[0] + linenum;
|
newline = rover->master->frontsector->lines[0] + linenum;
|
||||||
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
|
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
|
@ -2366,13 +2370,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
||||||
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
|
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture];
|
texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
|
||||||
|
|
||||||
if (rover->master->flags & ML_TFERLINE)
|
if (rover->master->flags & ML_TFERLINE)
|
||||||
{
|
{
|
||||||
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
|
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
|
||||||
newline = rover->master->frontsector->lines[0] + linenum;
|
newline = rover->master->frontsector->lines[0] + linenum;
|
||||||
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
|
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
|
||||||
}
|
}
|
||||||
#ifdef ESLOPE //backsides
|
#ifdef ESLOPE //backsides
|
||||||
h = *rover->t_slope ? P_GetZAt(*rover->t_slope, v1x, v1y) : *rover->topheight;
|
h = *rover->t_slope ? P_GetZAt(*rover->t_slope, v1x, v1y) : *rover->topheight;
|
||||||
|
@ -4519,8 +4523,8 @@ static void HWR_SortVisSprites(void)
|
||||||
gr_vissprite_t *ds, *dsprev, *dsnext, *dsfirst;
|
gr_vissprite_t *ds, *dsprev, *dsnext, *dsfirst;
|
||||||
gr_vissprite_t *best = NULL;
|
gr_vissprite_t *best = NULL;
|
||||||
gr_vissprite_t unsorted;
|
gr_vissprite_t unsorted;
|
||||||
float bestdist;
|
float bestdist = 0.0f;
|
||||||
INT32 bestdispoffset;
|
INT32 bestdispoffset = 0;
|
||||||
|
|
||||||
if (!gr_visspritecount)
|
if (!gr_visspritecount)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1836,7 +1836,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration, UINT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color)
|
static void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration, UINT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color)
|
||||||
{
|
{
|
||||||
INT32 val, count, pindex;
|
INT32 val, count, pindex;
|
||||||
GLfloat s, t;
|
GLfloat s, t;
|
||||||
|
|
|
@ -470,7 +470,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
||||||
boolean action = false;
|
boolean action = false;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
|
||||||
CONS_Debug(DBG_NETPLAY,"Recieved SAY cmd from Player %d (%s)\n", playernum+1, player_names[playernum]);
|
CONS_Debug(DBG_NETPLAY,"Received SAY cmd from Player %d (%s)\n", playernum+1, player_names[playernum]);
|
||||||
|
|
||||||
target = READSINT8(*p);
|
target = READSINT8(*p);
|
||||||
flags = READUINT8(*p);
|
flags = READUINT8(*p);
|
||||||
|
@ -790,6 +790,14 @@ boolean HU_Responder(event_t *ev)
|
||||||
}
|
}
|
||||||
else // if chat_on
|
else // if chat_on
|
||||||
{
|
{
|
||||||
|
// Ignore modifier keys
|
||||||
|
// Note that we do this here so users can still set
|
||||||
|
// their chat keys to one of these, if they so desire.
|
||||||
|
if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT
|
||||||
|
|| ev->data1 == KEY_LCTRL || ev->data1 == KEY_RCTRL
|
||||||
|
|| ev->data1 == KEY_LALT || ev->data1 == KEY_RALT)
|
||||||
|
return true;
|
||||||
|
|
||||||
c = (UINT8)ev->data1;
|
c = (UINT8)ev->data1;
|
||||||
|
|
||||||
// use console translations
|
// use console translations
|
||||||
|
@ -1094,7 +1102,19 @@ void HU_Drawer(void)
|
||||||
|
|
||||||
// draw desynch text
|
// draw desynch text
|
||||||
if (hu_resynching)
|
if (hu_resynching)
|
||||||
V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP, "Resynching...");
|
{
|
||||||
|
static UINT32 resynch_ticker = 0;
|
||||||
|
char resynch_text[14];
|
||||||
|
UINT32 i;
|
||||||
|
|
||||||
|
// Animate the dots
|
||||||
|
resynch_ticker++;
|
||||||
|
strcpy(resynch_text, "Resynching");
|
||||||
|
for (i = 0; i < (resynch_ticker / 16) % 4; i++)
|
||||||
|
strcat(resynch_text, ".");
|
||||||
|
|
||||||
|
V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP | V_ALLOWLOWERCASE, resynch_text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
|
@ -85,7 +85,7 @@ extern doomcom_t *doomcom;
|
||||||
|
|
||||||
/** \brief return packet in doomcom struct
|
/** \brief return packet in doomcom struct
|
||||||
*/
|
*/
|
||||||
extern void (*I_NetGet)(void);
|
extern boolean (*I_NetGet)(void);
|
||||||
|
|
||||||
/** \brief ask to driver if there is data waiting
|
/** \brief ask to driver if there is data waiting
|
||||||
*/
|
*/
|
||||||
|
|
97
src/i_tcp.c
97
src/i_tcp.c
|
@ -179,6 +179,7 @@ static UINT8 UPNP_support = TRUE;
|
||||||
#include "i_system.h"
|
#include "i_system.h"
|
||||||
#include "i_net.h"
|
#include "i_net.h"
|
||||||
#include "d_net.h"
|
#include "d_net.h"
|
||||||
|
#include "d_netfil.h"
|
||||||
#include "i_tcp.h"
|
#include "i_tcp.h"
|
||||||
#include "m_argv.h"
|
#include "m_argv.h"
|
||||||
|
|
||||||
|
@ -482,21 +483,12 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SINT8 getfreenode(void)
|
|
||||||
{
|
|
||||||
SINT8 j;
|
|
||||||
|
|
||||||
for (j = 0; j < MAXNETNODES; j++)
|
|
||||||
if (!nodeconnected[j])
|
|
||||||
{
|
|
||||||
nodeconnected[j] = true;
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a hack. For some reason, nodes aren't being freed properly.
|
// This is a hack. For some reason, nodes aren't being freed properly.
|
||||||
// This goes through and cleans up what nodes were supposed to be freed.
|
// This goes through and cleans up what nodes were supposed to be freed.
|
||||||
|
/** \warning This function causes the file downloading to stop if someone joins.
|
||||||
|
* How? Because it removes nodes that are connected but not in game,
|
||||||
|
* which is exactly what clients downloading a file are.
|
||||||
|
*/
|
||||||
static void cleanupnodes(void)
|
static void cleanupnodes(void)
|
||||||
{
|
{
|
||||||
SINT8 j;
|
SINT8 j;
|
||||||
|
@ -506,13 +498,81 @@ static void cleanupnodes(void)
|
||||||
|
|
||||||
// Why can't I start at zero?
|
// Why can't I start at zero?
|
||||||
for (j = 1; j < MAXNETNODES; j++)
|
for (j = 1; j < MAXNETNODES; j++)
|
||||||
|
//if (!(nodeingame[j] || SV_SendingFile(j)))
|
||||||
if (!nodeingame[j])
|
if (!nodeingame[j])
|
||||||
nodeconnected[j] = false;
|
nodeconnected[j] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SINT8 getfreenode(void)
|
||||||
|
{
|
||||||
|
SINT8 j;
|
||||||
|
|
||||||
|
cleanupnodes();
|
||||||
|
|
||||||
|
for (j = 0; j < MAXNETNODES; j++)
|
||||||
|
if (!nodeconnected[j])
|
||||||
|
{
|
||||||
|
nodeconnected[j] = true;
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \warning No free node? Just in case a node might not have been freed properly,
|
||||||
|
* look if there are connected nodes that aren't in game, and forget them.
|
||||||
|
* It's dirty, and might result in a poor guy having to restart
|
||||||
|
* 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])
|
||||||
|
return j;*/
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
void Command_Numnodes(void)
|
||||||
|
{
|
||||||
|
INT32 connected = 0;
|
||||||
|
INT32 ingame = 0;
|
||||||
|
INT32 i;
|
||||||
|
|
||||||
|
for (i = 1; i < MAXNETNODES; i++)
|
||||||
|
{
|
||||||
|
if (!(nodeconnected[i] || nodeingame[i]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (nodeconnected[i])
|
||||||
|
connected++;
|
||||||
|
if (nodeingame[i])
|
||||||
|
ingame++;
|
||||||
|
|
||||||
|
CONS_Printf("%2d - ", i);
|
||||||
|
if (nodetoplayer[i] != -1)
|
||||||
|
CONS_Printf("player %.2d", nodetoplayer[i]);
|
||||||
|
else
|
||||||
|
CONS_Printf(" ");
|
||||||
|
if (nodeconnected[i])
|
||||||
|
CONS_Printf(" - connected");
|
||||||
|
else
|
||||||
|
CONS_Printf(" - ");
|
||||||
|
if (nodeingame[i])
|
||||||
|
CONS_Printf(" - ingame");
|
||||||
|
else
|
||||||
|
CONS_Printf(" - ");
|
||||||
|
CONS_Printf(" - %s\n", I_GetNodeAddress(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
CONS_Printf("\n"
|
||||||
|
"Connected: %d\n"
|
||||||
|
"Ingame: %d\n",
|
||||||
|
connected, ingame);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef NONET
|
#ifndef NONET
|
||||||
static void SOCK_Get(void)
|
// 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, n;
|
||||||
int j;
|
int j;
|
||||||
|
@ -535,13 +595,12 @@ static void SOCK_Get(void)
|
||||||
doomcom->remotenode = (INT16)j; // good packet from a game player
|
doomcom->remotenode = (INT16)j; // good packet from a game player
|
||||||
doomcom->datalength = (INT16)c;
|
doomcom->datalength = (INT16)c;
|
||||||
nodesocket[j] = mysockets[n];
|
nodesocket[j] = mysockets[n];
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// not found
|
// not found
|
||||||
|
|
||||||
// find a free slot
|
// find a free slot
|
||||||
cleanupnodes();
|
|
||||||
j = getfreenode();
|
j = getfreenode();
|
||||||
if (j > 0)
|
if (j > 0)
|
||||||
{
|
{
|
||||||
|
@ -564,14 +623,15 @@ static void SOCK_Get(void)
|
||||||
}
|
}
|
||||||
if (i == numbans)
|
if (i == numbans)
|
||||||
SOCK_bannednode[j] = false;
|
SOCK_bannednode[j] = false;
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
DEBFILE("New node detected: No more free slots\n");
|
DEBFILE("New node detected: No more free slots\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doomcom->remotenode = -1; // no packet
|
doomcom->remotenode = -1; // no packet
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1256,7 +1316,6 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
|
||||||
gaie = I_getaddrinfo(address, port, &hints, &ai);
|
gaie = I_getaddrinfo(address, port, &hints, &ai);
|
||||||
if (gaie == 0)
|
if (gaie == 0)
|
||||||
{
|
{
|
||||||
cleanupnodes();
|
|
||||||
newnode = getfreenode();
|
newnode = getfreenode();
|
||||||
}
|
}
|
||||||
if (newnode == -1)
|
if (newnode == -1)
|
||||||
|
|
|
@ -348,22 +348,12 @@ static int sector_get(lua_State *L)
|
||||||
case sector_ceilingheight:
|
case sector_ceilingheight:
|
||||||
lua_pushfixed(L, sector->ceilingheight);
|
lua_pushfixed(L, sector->ceilingheight);
|
||||||
return 1;
|
return 1;
|
||||||
case sector_floorpic: { // floorpic
|
case sector_floorpic: // floorpic
|
||||||
levelflat_t *levelflat;
|
lua_pushlstring(L, levelflats[sector->floorpic].name, 8);
|
||||||
INT16 i;
|
|
||||||
for (i = 0, levelflat = levelflats; i != sector->floorpic; i++, levelflat++)
|
|
||||||
;
|
|
||||||
lua_pushlstring(L, levelflat->name, 8);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
case sector_ceilingpic: // ceilingpic
|
||||||
case sector_ceilingpic: { // ceilingpic
|
lua_pushlstring(L, levelflats[sector->ceilingpic].name, 8);
|
||||||
levelflat_t *levelflat;
|
|
||||||
INT16 i;
|
|
||||||
for (i = 0, levelflat = levelflats; i != sector->ceilingpic; i++, levelflat++)
|
|
||||||
;
|
|
||||||
lua_pushlstring(L, levelflat->name, 8);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
case sector_lightlevel:
|
case sector_lightlevel:
|
||||||
lua_pushinteger(L, sector->lightlevel);
|
lua_pushinteger(L, sector->lightlevel);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -400,46 +390,6 @@ static int sector_get(lua_State *L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// help function for P_LoadSectors, find a flat in the active wad files,
|
|
||||||
// allocate an id for it, and set the levelflat (to speedup search)
|
|
||||||
//
|
|
||||||
static INT32 P_AddLevelFlatRuntime(const char *flatname)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
levelflat_t *levelflat = levelflats;
|
|
||||||
|
|
||||||
//
|
|
||||||
// first scan through the already found flats
|
|
||||||
//
|
|
||||||
for (i = 0; i < numlevelflats; i++, levelflat++)
|
|
||||||
if (strnicmp(levelflat->name,flatname,8)==0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// that flat was already found in the level, return the id
|
|
||||||
if (i == numlevelflats)
|
|
||||||
{
|
|
||||||
// allocate new flat memory
|
|
||||||
levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
|
|
||||||
levelflat = levelflats+i;
|
|
||||||
|
|
||||||
// store the name
|
|
||||||
strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
|
|
||||||
strupr(levelflat->name);
|
|
||||||
|
|
||||||
// store the flat lump number
|
|
||||||
levelflat->lumpnum = R_GetFlatNumForName(flatname);
|
|
||||||
|
|
||||||
#ifndef ZDEBUG
|
|
||||||
CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
numlevelflats++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// level flat id
|
|
||||||
return (INT32)i;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sector_set(lua_State *L)
|
static int sector_set(lua_State *L)
|
||||||
{
|
{
|
||||||
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
|
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
|
||||||
|
|
|
@ -28,4 +28,4 @@ void M_AATreeSet(aatree_t *aatree, INT32 key, void* value);
|
||||||
void *M_AATreeGet(aatree_t *aatree, INT32 key);
|
void *M_AATreeGet(aatree_t *aatree, INT32 key);
|
||||||
void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
|
void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -46,41 +46,6 @@ typedef INT32 fixed_t;
|
||||||
#define FLOAT_TO_FIXED(f) (fixed_t)((f) * ((float)FRACUNIT))
|
#define FLOAT_TO_FIXED(f) (fixed_t)((f) * ((float)FRACUNIT))
|
||||||
|
|
||||||
|
|
||||||
/** \brief The TMulScale16 function
|
|
||||||
|
|
||||||
\param a a parameter of type fixed_t
|
|
||||||
\param b a parameter of type fixed_t
|
|
||||||
\param c a parameter of type fixed_t
|
|
||||||
\param d a parameter of type fixed_t
|
|
||||||
\param e a parameter of type fixed_t
|
|
||||||
\param f a parameter of type fixed_t
|
|
||||||
|
|
||||||
\return fixed_t
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t TMulScale16(fixed_t a, fixed_t b, fixed_t c, fixed_t d, fixed_t e, fixed_t f) \
|
|
||||||
{ \
|
|
||||||
return (fixed_t)((((INT64)a * (INT64)b) + ((INT64)c * (INT64)d) \
|
|
||||||
+ ((INT64)e * (INT64)f)) >> 16); \
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \brief The DMulScale16 function
|
|
||||||
|
|
||||||
\param a a parameter of type fixed_t
|
|
||||||
\param b a parameter of type fixed_t
|
|
||||||
\param c a parameter of type fixed_t
|
|
||||||
\param d a parameter of type fixed_t
|
|
||||||
|
|
||||||
\return fixed_t
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t DMulScale16(fixed_t a, fixed_t b, fixed_t c, fixed_t d) \
|
|
||||||
{ \
|
|
||||||
return (fixed_t)((((INT64)a * (INT64)b) + ((INT64)c * (INT64)d)) >> 16); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined (__WATCOMC__) && FRACBITS == 16
|
#if defined (__WATCOMC__) && FRACBITS == 16
|
||||||
#pragma aux FixedMul = \
|
#pragma aux FixedMul = \
|
||||||
"imul ebx", \
|
"imul ebx", \
|
||||||
|
@ -283,9 +248,16 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedFloor(fixed_t x)
|
||||||
{
|
{
|
||||||
const fixed_t a = abs(x); //absolute of x
|
const fixed_t a = abs(x); //absolute of x
|
||||||
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
|
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
|
||||||
const fixed_t f = i-a; // cut out the integral part
|
const fixed_t f = a-i; // cut out the integral part
|
||||||
|
if (f == 0)
|
||||||
|
return x;
|
||||||
if (x != INT32_MIN)
|
if (x != INT32_MIN)
|
||||||
return x-f; // return largest integral value not greater than argument
|
{ // return rounded down to nearest whole number
|
||||||
|
if (x > 0)
|
||||||
|
return x-f;
|
||||||
|
else
|
||||||
|
return x-(FRACUNIT-f);
|
||||||
|
}
|
||||||
return INT32_MIN;
|
return INT32_MIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,7 +273,7 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedTrunc(fixed_t x)
|
||||||
{
|
{
|
||||||
const fixed_t a = abs(x); //absolute of x
|
const fixed_t a = abs(x); //absolute of x
|
||||||
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
|
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
|
||||||
const fixed_t f = i-a; // cut out the integral part
|
const fixed_t f = a-i; // cut out the integral part
|
||||||
if (x != INT32_MIN)
|
if (x != INT32_MIN)
|
||||||
{ // return rounded to nearest whole number, towards zero
|
{ // return rounded to nearest whole number, towards zero
|
||||||
if (x > 0)
|
if (x > 0)
|
||||||
|
@ -324,11 +296,18 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedCeil(fixed_t x)
|
||||||
{
|
{
|
||||||
const fixed_t a = abs(x); //absolute of x
|
const fixed_t a = abs(x); //absolute of x
|
||||||
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
|
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
|
||||||
const fixed_t f = i-a; // cut out the integral part
|
const fixed_t f = a-i; // cut out the integral part
|
||||||
|
if (f == 0)
|
||||||
|
return x;
|
||||||
if (x == INT32_MIN)
|
if (x == INT32_MIN)
|
||||||
return INT32_MIN;
|
return INT32_MIN;
|
||||||
else if (x < FixedFloor(INT32_MAX))
|
else if (x < FixedFloor(INT32_MAX))
|
||||||
return x+(FRACUNIT-f); // return smallest integral value not less than argument
|
{ // return rounded up to nearest whole number
|
||||||
|
if (x > 0)
|
||||||
|
return x+(FRACUNIT-f);
|
||||||
|
else
|
||||||
|
return x+f;
|
||||||
|
}
|
||||||
return INT32_MAX;
|
return INT32_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,7 +323,9 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedRound(fixed_t x)
|
||||||
{
|
{
|
||||||
const fixed_t a = abs(x); //absolute of x
|
const fixed_t a = abs(x); //absolute of x
|
||||||
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
|
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
|
||||||
const fixed_t f = i-a; // cut out the integral part
|
const fixed_t f = a-i; // cut out the integral part
|
||||||
|
if (f == 0)
|
||||||
|
return x;
|
||||||
if (x == INT32_MIN)
|
if (x == INT32_MIN)
|
||||||
return INT32_MIN;
|
return INT32_MIN;
|
||||||
else if (x < FixedFloor(INT32_MAX))
|
else if (x < FixedFloor(INT32_MAX))
|
||||||
|
|
|
@ -7644,7 +7644,7 @@ void A_SetObjectFlags(mobj_t *actor)
|
||||||
else if (locvar2 == 1)
|
else if (locvar2 == 1)
|
||||||
locvar1 = actor->flags & ~locvar1;
|
locvar1 = actor->flags & ~locvar1;
|
||||||
|
|
||||||
if ((locvar1 & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (actor->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) // Blockmap/sector status has changed, so reset the links
|
if ((UINT32)(locvar1 & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (actor->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) // Blockmap/sector status has changed, so reset the links
|
||||||
unlinkthings = true;
|
unlinkthings = true;
|
||||||
|
|
||||||
if (unlinkthings) {
|
if (unlinkthings) {
|
||||||
|
|
|
@ -1684,7 +1684,7 @@ void P_CheckTimeLimit(void)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//Tagmode round end but only on the tic before the
|
//Tagmode round end but only on the tic before the
|
||||||
//XD_EXITLEVEL packet is recieved by all players.
|
//XD_EXITLEVEL packet is received by all players.
|
||||||
if (G_TagGametype())
|
if (G_TagGametype())
|
||||||
{
|
{
|
||||||
if (leveltime == (timelimitintics + 1))
|
if (leveltime == (timelimitintics + 1))
|
||||||
|
@ -1695,7 +1695,7 @@ void P_CheckTimeLimit(void)
|
||||||
|| (players[i].pflags & PF_TAGGED) || (players[i].pflags & PF_TAGIT))
|
|| (players[i].pflags & PF_TAGGED) || (players[i].pflags & PF_TAGIT))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
CONS_Printf(M_GetText("%s recieved double points for surviving the round.\n"), player_names[i]);
|
CONS_Printf(M_GetText("%s received double points for surviving the round.\n"), player_names[i]);
|
||||||
P_AddPlayerScore(&players[i], players[i].score);
|
P_AddPlayerScore(&players[i], players[i].score);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -994,7 +994,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
||||||
if (tmthing->player && tmthing->z + tmthing->height > topz
|
if (tmthing->player && tmthing->z + tmthing->height > topz
|
||||||
&& tmthing->z + tmthing->height < tmthing->ceilingz)
|
&& tmthing->z + tmthing->height < tmthing->ceilingz)
|
||||||
{
|
{
|
||||||
tmfloorz = tmceilingz = INT32_MIN; // block while in air
|
tmfloorz = tmceilingz = topz; // block while in air
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
tmceilingslope = NULL;
|
tmceilingslope = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1037,7 +1037,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
||||||
if (tmthing->player && tmthing->z < topz
|
if (tmthing->player && tmthing->z < topz
|
||||||
&& tmthing->z > tmthing->floorz)
|
&& tmthing->z > tmthing->floorz)
|
||||||
{
|
{
|
||||||
tmfloorz = tmceilingz = INT32_MAX; // block while in air
|
tmfloorz = tmceilingz = topz; // block while in air
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
tmfloorslope = NULL;
|
tmfloorslope = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -572,51 +572,54 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
|
||||||
side_t *side = &sides[linedef->sidenum[0]];
|
side_t *side = &sides[linedef->sidenum[0]];
|
||||||
fixed_t textop, texbottom, texheight;
|
fixed_t textop, texbottom, texheight;
|
||||||
fixed_t texmid, delta1, delta2;
|
fixed_t texmid, delta1, delta2;
|
||||||
|
INT32 texnum = R_GetTextureNum(side->midtexture); // make sure the texture is actually valid
|
||||||
|
|
||||||
// Get the midtexture's height
|
if (texnum) {
|
||||||
texheight = textures[texturetranslation[side->midtexture]]->height << FRACBITS;
|
// Get the midtexture's height
|
||||||
|
texheight = textures[texnum]->height << FRACBITS;
|
||||||
|
|
||||||
// Set texbottom and textop to the Z coordinates of the texture's boundaries
|
// Set texbottom and textop to the Z coordinates of the texture's boundaries
|
||||||
#if 0 // #ifdef POLYOBJECTS
|
#if 0 // #ifdef POLYOBJECTS
|
||||||
// don't remove this code unless solid midtextures
|
// don't remove this code unless solid midtextures
|
||||||
// on non-solid polyobjects should NEVER happen in the future
|
// on non-solid polyobjects should NEVER happen in the future
|
||||||
if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
|
if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
|
||||||
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
|
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
|
||||||
texbottom = back->floorheight + side->rowoffset;
|
texbottom = back->floorheight + side->rowoffset;
|
||||||
textop = back->ceilingheight + side->rowoffset;
|
textop = back->ceilingheight + side->rowoffset;
|
||||||
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
|
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
|
||||||
texbottom = back->floorheight + side->rowoffset;
|
texbottom = back->floorheight + side->rowoffset;
|
||||||
textop = texbottom + texheight*(side->repeatcnt+1);
|
textop = texbottom + texheight*(side->repeatcnt+1);
|
||||||
} else {
|
} else {
|
||||||
textop = back->ceilingheight + side->rowoffset;
|
textop = back->ceilingheight + side->rowoffset;
|
||||||
texbottom = textop - texheight*(side->repeatcnt+1);
|
texbottom = textop - texheight*(side->repeatcnt+1);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
|
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
|
||||||
texbottom = openbottom + side->rowoffset;
|
texbottom = openbottom + side->rowoffset;
|
||||||
textop = opentop + side->rowoffset;
|
textop = opentop + side->rowoffset;
|
||||||
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
|
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
|
||||||
texbottom = openbottom + side->rowoffset;
|
texbottom = openbottom + side->rowoffset;
|
||||||
textop = texbottom + texheight*(side->repeatcnt+1);
|
textop = texbottom + texheight*(side->repeatcnt+1);
|
||||||
} else {
|
} else {
|
||||||
textop = opentop + side->rowoffset;
|
textop = opentop + side->rowoffset;
|
||||||
texbottom = textop - texheight*(side->repeatcnt+1);
|
texbottom = textop - texheight*(side->repeatcnt+1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
texmid = texbottom+(textop-texbottom)/2;
|
texmid = texbottom+(textop-texbottom)/2;
|
||||||
|
|
||||||
delta1 = abs(mobj->z - texmid);
|
delta1 = abs(mobj->z - texmid);
|
||||||
delta2 = abs(thingtop - texmid);
|
delta2 = abs(thingtop - texmid);
|
||||||
|
|
||||||
if (delta1 > delta2) { // Below
|
if (delta1 > delta2) { // Below
|
||||||
if (opentop > texbottom)
|
if (opentop > texbottom)
|
||||||
opentop = texbottom;
|
opentop = texbottom;
|
||||||
} else { // Above
|
} else { // Above
|
||||||
if (openbottom < textop)
|
if (openbottom < textop)
|
||||||
openbottom = textop;
|
openbottom = textop;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
14
src/p_mobj.c
14
src/p_mobj.c
|
@ -4450,7 +4450,7 @@ static void P_Boss4MoveSpikeballs(mobj_t *mobj, angle_t angle, fixed_t fz)
|
||||||
{
|
{
|
||||||
INT32 s;
|
INT32 s;
|
||||||
mobj_t *base = mobj, *seg;
|
mobj_t *base = mobj, *seg;
|
||||||
fixed_t dist, bz = (mobj->spawnpoint->z+16)<<FRACBITS;
|
fixed_t dist, bz = mobj->watertop+(16<<FRACBITS);
|
||||||
while ((base = base->tracer))
|
while ((base = base->tracer))
|
||||||
{
|
{
|
||||||
for (seg = base, dist = 172*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 124*FRACUNIT, --s)
|
for (seg = base, dist = 172*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 124*FRACUNIT, --s)
|
||||||
|
@ -4464,7 +4464,7 @@ static void P_Boss4PinchSpikeballs(mobj_t *mobj, angle_t angle, fixed_t fz)
|
||||||
{
|
{
|
||||||
INT32 s;
|
INT32 s;
|
||||||
mobj_t *base = mobj, *seg;
|
mobj_t *base = mobj, *seg;
|
||||||
fixed_t dist, bz = (mobj->spawnpoint->z+16)<<FRACBITS;
|
fixed_t dist, bz = mobj->watertop+(16<<FRACBITS);
|
||||||
while ((base = base->tracer))
|
while ((base = base->tracer))
|
||||||
{
|
{
|
||||||
for (seg = base, dist = 112*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 132*FRACUNIT, --s)
|
for (seg = base, dist = 112*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 132*FRACUNIT, --s)
|
||||||
|
@ -4580,7 +4580,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
|
||||||
INT32 i, arm;
|
INT32 i, arm;
|
||||||
mobj_t *seg, *base = mobj;
|
mobj_t *seg, *base = mobj;
|
||||||
// First frame init, spawn all the things.
|
// First frame init, spawn all the things.
|
||||||
mobj->spawnpoint->z = mobj->z>>FRACBITS;
|
mobj->watertop = mobj->z;
|
||||||
z = mobj->z + mobj->height/2 - mobjinfo[MT_EGGMOBILE4_MACE].height/2;
|
z = mobj->z + mobj->height/2 - mobjinfo[MT_EGGMOBILE4_MACE].height/2;
|
||||||
for (arm = 0; arm <3 ; arm++)
|
for (arm = 0; arm <3 ; arm++)
|
||||||
{
|
{
|
||||||
|
@ -4636,7 +4636,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
|
||||||
case 3:
|
case 3:
|
||||||
{
|
{
|
||||||
fixed_t z;
|
fixed_t z;
|
||||||
if (mobj->z < (mobj->spawnpoint->z+512)<<FRACBITS)
|
if (mobj->z < mobj->watertop+(512<<FRACBITS))
|
||||||
mobj->momz = 8*FRACUNIT;
|
mobj->momz = 8*FRACUNIT;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -4645,7 +4645,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
|
||||||
}
|
}
|
||||||
mobj->movecount += 400<<(FRACBITS>>1);
|
mobj->movecount += 400<<(FRACBITS>>1);
|
||||||
mobj->movecount %= 360*FRACUNIT;
|
mobj->movecount %= 360*FRACUNIT;
|
||||||
z = mobj->z - (mobj->spawnpoint->z<<FRACBITS) - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2;
|
z = mobj->z - mobj->watertop - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2;
|
||||||
if (z < 0) // We haven't risen high enough to pull the spikeballs along yet
|
if (z < 0) // We haven't risen high enough to pull the spikeballs along yet
|
||||||
P_Boss4MoveSpikeballs(mobj, FixedAngle(mobj->movecount), 0); // So don't pull the spikeballs along yet.
|
P_Boss4MoveSpikeballs(mobj, FixedAngle(mobj->movecount), 0); // So don't pull the spikeballs along yet.
|
||||||
else
|
else
|
||||||
|
@ -4655,13 +4655,13 @@ static void P_Boss4Thinker(mobj_t *mobj)
|
||||||
// Pinch phase!
|
// Pinch phase!
|
||||||
case 4:
|
case 4:
|
||||||
{
|
{
|
||||||
if (mobj->z < (mobj->spawnpoint->z+512+128*(mobj->info->damage-mobj->health))<<FRACBITS)
|
if (mobj->z < (mobj->watertop + ((512+128*(mobj->info->damage-mobj->health))<<FRACBITS)))
|
||||||
mobj->momz = 8*FRACUNIT;
|
mobj->momz = 8*FRACUNIT;
|
||||||
else
|
else
|
||||||
mobj->momz = 0;
|
mobj->momz = 0;
|
||||||
mobj->movecount += (800+800*(mobj->info->damage-mobj->health))<<(FRACBITS>>1);
|
mobj->movecount += (800+800*(mobj->info->damage-mobj->health))<<(FRACBITS>>1);
|
||||||
mobj->movecount %= 360*FRACUNIT;
|
mobj->movecount %= 360*FRACUNIT;
|
||||||
P_Boss4PinchSpikeballs(mobj, FixedAngle(mobj->movecount), mobj->z - (mobj->spawnpoint->z<<FRACBITS) - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2);
|
P_Boss4PinchSpikeballs(mobj, FixedAngle(mobj->movecount), mobj->z - mobj->watertop - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2);
|
||||||
|
|
||||||
if (!mobj->target || !mobj->target->health)
|
if (!mobj->target || !mobj->target->health)
|
||||||
P_SupermanLook4Players(mobj);
|
P_SupermanLook4Players(mobj);
|
||||||
|
|
|
@ -460,6 +460,7 @@ static void P_NetUnArchivePlayers(void)
|
||||||
#define SD_TAG 0x10
|
#define SD_TAG 0x10
|
||||||
#define SD_FLOORANG 0x20
|
#define SD_FLOORANG 0x20
|
||||||
#define SD_CEILANG 0x40
|
#define SD_CEILANG 0x40
|
||||||
|
#define SD_TAGLIST 0x80
|
||||||
|
|
||||||
#define LD_FLAG 0x01
|
#define LD_FLAG 0x01
|
||||||
#define LD_SPECIAL 0x02
|
#define LD_SPECIAL 0x02
|
||||||
|
@ -509,10 +510,9 @@ static void P_NetArchiveWorld(void)
|
||||||
//
|
//
|
||||||
// flats
|
// flats
|
||||||
//
|
//
|
||||||
// P_AddLevelFlat should not add but just return the number
|
if (ss->floorpic != P_CheckLevelFlat(ms->floorpic))
|
||||||
if (ss->floorpic != P_AddLevelFlat(ms->floorpic, levelflats))
|
|
||||||
diff |= SD_FLOORPIC;
|
diff |= SD_FLOORPIC;
|
||||||
if (ss->ceilingpic != P_AddLevelFlat(ms->ceilingpic, levelflats))
|
if (ss->ceilingpic != P_CheckLevelFlat(ms->ceilingpic))
|
||||||
diff |= SD_CEILPIC;
|
diff |= SD_CEILPIC;
|
||||||
|
|
||||||
if (ss->lightlevel != SHORT(ms->lightlevel))
|
if (ss->lightlevel != SHORT(ms->lightlevel))
|
||||||
|
@ -535,6 +535,8 @@ static void P_NetArchiveWorld(void)
|
||||||
|
|
||||||
if (ss->tag != SHORT(ms->tag))
|
if (ss->tag != SHORT(ms->tag))
|
||||||
diff2 |= SD_TAG;
|
diff2 |= SD_TAG;
|
||||||
|
if (ss->nexttag != ss->spawn_nexttag || ss->firsttag != ss->spawn_firsttag)
|
||||||
|
diff2 |= SD_TAGLIST;
|
||||||
|
|
||||||
// Check if any of the sector's FOFs differ from how they spawned
|
// Check if any of the sector's FOFs differ from how they spawned
|
||||||
if (ss->ffloors)
|
if (ss->ffloors)
|
||||||
|
@ -582,16 +584,17 @@ static void P_NetArchiveWorld(void)
|
||||||
WRITEFIXED(put, ss->ceiling_xoffs);
|
WRITEFIXED(put, ss->ceiling_xoffs);
|
||||||
if (diff2 & SD_CYOFFS)
|
if (diff2 & SD_CYOFFS)
|
||||||
WRITEFIXED(put, ss->ceiling_yoffs);
|
WRITEFIXED(put, ss->ceiling_yoffs);
|
||||||
if (diff2 & SD_TAG)
|
if (diff2 & SD_TAG) // save only the tag
|
||||||
{
|
|
||||||
WRITEINT16(put, ss->tag);
|
WRITEINT16(put, ss->tag);
|
||||||
WRITEINT32(put, ss->firsttag);
|
|
||||||
WRITEINT32(put, ss->nexttag);
|
|
||||||
}
|
|
||||||
if (diff2 & SD_FLOORANG)
|
if (diff2 & SD_FLOORANG)
|
||||||
WRITEANGLE(put, ss->floorpic_angle);
|
WRITEANGLE(put, ss->floorpic_angle);
|
||||||
if (diff2 & SD_CEILANG)
|
if (diff2 & SD_CEILANG)
|
||||||
WRITEANGLE(put, ss->ceilingpic_angle);
|
WRITEANGLE(put, ss->ceilingpic_angle);
|
||||||
|
if (diff2 & SD_TAGLIST) // save both firsttag and nexttag
|
||||||
|
{ // either of these could be changed even if tag isn't
|
||||||
|
WRITEINT32(put, ss->firsttag);
|
||||||
|
WRITEINT32(put, ss->nexttag);
|
||||||
|
}
|
||||||
|
|
||||||
// Special case: save the stats of all modified ffloors along with their ffloor "number"s
|
// Special case: save the stats of all modified ffloors along with their ffloor "number"s
|
||||||
// we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed
|
// we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed
|
||||||
|
@ -752,12 +755,12 @@ static void P_NetUnArchiveWorld(void)
|
||||||
sectors[i].ceilingheight = READFIXED(get);
|
sectors[i].ceilingheight = READFIXED(get);
|
||||||
if (diff & SD_FLOORPIC)
|
if (diff & SD_FLOORPIC)
|
||||||
{
|
{
|
||||||
sectors[i].floorpic = P_AddLevelFlat((char *)get, levelflats);
|
sectors[i].floorpic = P_AddLevelFlatRuntime((char *)get);
|
||||||
get += 8;
|
get += 8;
|
||||||
}
|
}
|
||||||
if (diff & SD_CEILPIC)
|
if (diff & SD_CEILPIC)
|
||||||
{
|
{
|
||||||
sectors[i].ceilingpic = P_AddLevelFlat((char *)get, levelflats);
|
sectors[i].ceilingpic = P_AddLevelFlatRuntime((char *)get);
|
||||||
get += 8;
|
get += 8;
|
||||||
}
|
}
|
||||||
if (diff & SD_LIGHT)
|
if (diff & SD_LIGHT)
|
||||||
|
@ -774,12 +777,11 @@ static void P_NetUnArchiveWorld(void)
|
||||||
if (diff2 & SD_CYOFFS)
|
if (diff2 & SD_CYOFFS)
|
||||||
sectors[i].ceiling_yoffs = READFIXED(get);
|
sectors[i].ceiling_yoffs = READFIXED(get);
|
||||||
if (diff2 & SD_TAG)
|
if (diff2 & SD_TAG)
|
||||||
|
sectors[i].tag = READINT16(get); // DON'T use P_ChangeSectorTag
|
||||||
|
if (diff2 & SD_TAGLIST)
|
||||||
{
|
{
|
||||||
INT16 tag;
|
|
||||||
tag = READINT16(get);
|
|
||||||
sectors[i].firsttag = READINT32(get);
|
sectors[i].firsttag = READINT32(get);
|
||||||
sectors[i].nexttag = READINT32(get);
|
sectors[i].nexttag = READINT32(get);
|
||||||
P_ChangeSectorTag(i, tag);
|
|
||||||
}
|
}
|
||||||
if (diff2 & SD_FLOORANG)
|
if (diff2 & SD_FLOORANG)
|
||||||
sectors[i].floorpic_angle = READANGLE(get);
|
sectors[i].floorpic_angle = READANGLE(get);
|
||||||
|
@ -2607,6 +2609,7 @@ static void P_NetUnArchiveThinkers(void)
|
||||||
thinker_t *next;
|
thinker_t *next;
|
||||||
UINT8 tclass;
|
UINT8 tclass;
|
||||||
UINT8 restoreNum = false;
|
UINT8 restoreNum = false;
|
||||||
|
UINT32 i;
|
||||||
|
|
||||||
if (READUINT32(save_p) != ARCHIVEBLOCK_THINKERS)
|
if (READUINT32(save_p) != ARCHIVEBLOCK_THINKERS)
|
||||||
I_Error("Bad $$$.sav at archive block Thinkers");
|
I_Error("Bad $$$.sav at archive block Thinkers");
|
||||||
|
@ -2627,6 +2630,12 @@ static void P_NetUnArchiveThinkers(void)
|
||||||
iquetail = iquehead = 0;
|
iquetail = iquehead = 0;
|
||||||
P_InitThinkers();
|
P_InitThinkers();
|
||||||
|
|
||||||
|
// clear sector thinker pointers so they don't point to non-existant thinkers for all of eternity
|
||||||
|
for (i = 0; i < numsectors; i++)
|
||||||
|
{
|
||||||
|
sectors[i].floordata = sectors[i].ceilingdata = sectors[i].lightingdata = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// read in saved thinkers
|
// read in saved thinkers
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
|
|
@ -574,6 +574,69 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat)
|
||||||
return (INT32)i;
|
return (INT32)i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// help function for Lua and $$$.sav reading
|
||||||
|
// same as P_AddLevelFlat, except this is not setup so we must realloc levelflats to fit in the new flat
|
||||||
|
// no longer a static func in lua_maplib.c because p_saveg.c also needs it
|
||||||
|
//
|
||||||
|
INT32 P_AddLevelFlatRuntime(const char *flatname)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
levelflat_t *levelflat = levelflats;
|
||||||
|
|
||||||
|
//
|
||||||
|
// first scan through the already found flats
|
||||||
|
//
|
||||||
|
for (i = 0; i < numlevelflats; i++, levelflat++)
|
||||||
|
if (strnicmp(levelflat->name,flatname,8)==0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// that flat was already found in the level, return the id
|
||||||
|
if (i == numlevelflats)
|
||||||
|
{
|
||||||
|
// allocate new flat memory
|
||||||
|
levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
|
||||||
|
levelflat = levelflats+i;
|
||||||
|
|
||||||
|
// store the name
|
||||||
|
strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
|
||||||
|
strupr(levelflat->name);
|
||||||
|
|
||||||
|
// store the flat lump number
|
||||||
|
levelflat->lumpnum = R_GetFlatNumForName(flatname);
|
||||||
|
|
||||||
|
#ifndef ZDEBUG
|
||||||
|
CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
numlevelflats++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// level flat id
|
||||||
|
return (INT32)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// help function for $$$.sav checking
|
||||||
|
// this simply returns the flat # for the name given
|
||||||
|
//
|
||||||
|
INT32 P_CheckLevelFlat(const char *flatname)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
levelflat_t *levelflat = levelflats;
|
||||||
|
|
||||||
|
//
|
||||||
|
// scan through the already found flats
|
||||||
|
//
|
||||||
|
for (i = 0; i < numlevelflats; i++, levelflat++)
|
||||||
|
if (strnicmp(levelflat->name,flatname,8)==0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (i == numlevelflats)
|
||||||
|
return 0; // ??? flat was not found, this should not happen!
|
||||||
|
|
||||||
|
// level flat id
|
||||||
|
return (INT32)i;
|
||||||
|
}
|
||||||
|
|
||||||
static void P_LoadSectors(lumpnum_t lumpnum)
|
static void P_LoadSectors(lumpnum_t lumpnum)
|
||||||
{
|
{
|
||||||
UINT8 *data;
|
UINT8 *data;
|
||||||
|
@ -614,6 +677,7 @@ static void P_LoadSectors(lumpnum_t lumpnum)
|
||||||
ss->special = SHORT(ms->special);
|
ss->special = SHORT(ms->special);
|
||||||
ss->tag = SHORT(ms->tag);
|
ss->tag = SHORT(ms->tag);
|
||||||
ss->nexttag = ss->firsttag = -1;
|
ss->nexttag = ss->firsttag = -1;
|
||||||
|
ss->spawn_nexttag = ss->spawn_firsttag = -1;
|
||||||
|
|
||||||
memset(&ss->soundorg, 0, sizeof(ss->soundorg));
|
memset(&ss->soundorg, 0, sizeof(ss->soundorg));
|
||||||
ss->validcount = 0;
|
ss->validcount = 0;
|
||||||
|
|
|
@ -47,6 +47,8 @@ typedef struct
|
||||||
extern size_t numlevelflats;
|
extern size_t numlevelflats;
|
||||||
extern levelflat_t *levelflats;
|
extern levelflat_t *levelflats;
|
||||||
INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat);
|
INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat);
|
||||||
|
INT32 P_AddLevelFlatRuntime(const char *flatname);
|
||||||
|
INT32 P_CheckLevelFlat(const char *flatname);
|
||||||
|
|
||||||
extern size_t nummapthings;
|
extern size_t nummapthings;
|
||||||
extern mapthing_t *mapthings;
|
extern mapthing_t *mapthings;
|
||||||
|
|
|
@ -1519,6 +1519,8 @@ static inline void P_InitTagLists(void)
|
||||||
size_t j = (unsigned)sectors[i].tag % numsectors;
|
size_t j = (unsigned)sectors[i].tag % numsectors;
|
||||||
sectors[i].nexttag = sectors[j].firsttag;
|
sectors[i].nexttag = sectors[j].firsttag;
|
||||||
sectors[j].firsttag = (INT32)i;
|
sectors[j].firsttag = (INT32)i;
|
||||||
|
sectors[i].spawn_nexttag = sectors[i].nexttag;
|
||||||
|
sectors[j].spawn_firsttag = sectors[j].firsttag;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = numlines - 1; i != (size_t)-1; i--)
|
for (i = numlines - 1; i != (size_t)-1; i--)
|
||||||
|
@ -5385,6 +5387,10 @@ void T_LaserFlash(laserthink_t *flash)
|
||||||
&& thing->flags & MF_BOSS)
|
&& thing->flags & MF_BOSS)
|
||||||
continue; // Don't hurt bosses
|
continue; // Don't hurt bosses
|
||||||
|
|
||||||
|
// Don't endlessly kill egg guard shields (or anything else for that matter)
|
||||||
|
if (thing->health <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
top = P_GetSpecialTopZ(thing, sourcesec, sector);
|
top = P_GetSpecialTopZ(thing, sourcesec, sector);
|
||||||
bottom = P_GetSpecialBottomZ(thing, sourcesec, sector);
|
bottom = P_GetSpecialBottomZ(thing, sourcesec, sector);
|
||||||
|
|
||||||
|
|
69
src/r_bsp.c
69
src/r_bsp.c
|
@ -210,7 +210,7 @@ void R_PortalClearClipSegs(INT32 start, INT32 end)
|
||||||
//
|
//
|
||||||
// It assumes that Doom has already ruled out a door being closed because
|
// It assumes that Doom has already ruled out a door being closed because
|
||||||
// of front-back closure (e.g. front floor is taller than back ceiling).
|
// of front-back closure (e.g. front floor is taller than back ceiling).
|
||||||
static inline INT32 R_DoorClosed(void)
|
static INT32 R_DoorClosed(void)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -859,6 +859,7 @@ static void R_Subsector(size_t num)
|
||||||
static sector_t tempsec; // Deep water hack
|
static sector_t tempsec; // Deep water hack
|
||||||
extracolormap_t *floorcolormap;
|
extracolormap_t *floorcolormap;
|
||||||
extracolormap_t *ceilingcolormap;
|
extracolormap_t *ceilingcolormap;
|
||||||
|
fixed_t floorcenterz, ceilingcenterz;
|
||||||
|
|
||||||
#ifdef RANGECHECK
|
#ifdef RANGECHECK
|
||||||
if (num >= numsubsectors)
|
if (num >= numsubsectors)
|
||||||
|
@ -879,6 +880,18 @@ static void R_Subsector(size_t num)
|
||||||
|
|
||||||
floorcolormap = ceilingcolormap = frontsector->extra_colormap;
|
floorcolormap = ceilingcolormap = frontsector->extra_colormap;
|
||||||
|
|
||||||
|
floorcenterz =
|
||||||
|
#ifdef ESLOPE
|
||||||
|
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
|
||||||
|
#endif
|
||||||
|
frontsector->floorheight;
|
||||||
|
|
||||||
|
ceilingcenterz =
|
||||||
|
#ifdef ESLOPE
|
||||||
|
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
|
||||||
|
#endif
|
||||||
|
frontsector->ceilingheight;
|
||||||
|
|
||||||
// Check and prep all 3D floors. Set the sector floor/ceiling light levels and colormaps.
|
// Check and prep all 3D floors. Set the sector floor/ceiling light levels and colormaps.
|
||||||
if (frontsector->ffloors)
|
if (frontsector->ffloors)
|
||||||
{
|
{
|
||||||
|
@ -891,19 +904,11 @@ static void R_Subsector(size_t num)
|
||||||
sub->sector->moved = frontsector->moved = false;
|
sub->sector->moved = frontsector->moved = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
light = R_GetPlaneLight(frontsector,
|
light = R_GetPlaneLight(frontsector, floorcenterz, false);
|
||||||
#ifdef ESLOPE
|
|
||||||
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
|
|
||||||
#endif
|
|
||||||
frontsector->floorheight, false);
|
|
||||||
if (frontsector->floorlightsec == -1)
|
if (frontsector->floorlightsec == -1)
|
||||||
floorlightlevel = *frontsector->lightlist[light].lightlevel;
|
floorlightlevel = *frontsector->lightlist[light].lightlevel;
|
||||||
floorcolormap = frontsector->lightlist[light].extra_colormap;
|
floorcolormap = frontsector->lightlist[light].extra_colormap;
|
||||||
light = R_GetPlaneLight(frontsector,
|
light = R_GetPlaneLight(frontsector, ceilingcenterz, false);
|
||||||
#ifdef ESLOPE
|
|
||||||
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
|
|
||||||
#endif
|
|
||||||
frontsector->ceilingheight, false);
|
|
||||||
if (frontsector->ceilinglightsec == -1)
|
if (frontsector->ceilinglightsec == -1)
|
||||||
ceilinglightlevel = *frontsector->lightlist[light].lightlevel;
|
ceilinglightlevel = *frontsector->lightlist[light].lightlevel;
|
||||||
ceilingcolormap = frontsector->lightlist[light].extra_colormap;
|
ceilingcolormap = frontsector->lightlist[light].extra_colormap;
|
||||||
|
@ -920,6 +925,9 @@ static void R_Subsector(size_t num)
|
||||||
{
|
{
|
||||||
floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, floorlightlevel,
|
floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, floorlightlevel,
|
||||||
frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL
|
frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL
|
||||||
|
#ifdef POLYOBJECTS_PLANES
|
||||||
|
, NULL
|
||||||
|
#endif
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
, frontsector->f_slope
|
, frontsector->f_slope
|
||||||
#endif
|
#endif
|
||||||
|
@ -939,6 +947,9 @@ static void R_Subsector(size_t num)
|
||||||
ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic,
|
ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic,
|
||||||
ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle,
|
ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle,
|
||||||
ceilingcolormap, NULL
|
ceilingcolormap, NULL
|
||||||
|
#ifdef POLYOBJECTS_PLANES
|
||||||
|
, NULL
|
||||||
|
#endif
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
, frontsector->c_slope
|
, frontsector->c_slope
|
||||||
#endif
|
#endif
|
||||||
|
@ -956,7 +967,7 @@ static void R_Subsector(size_t num)
|
||||||
if (frontsector->ffloors)
|
if (frontsector->ffloors)
|
||||||
{
|
{
|
||||||
ffloor_t *rover;
|
ffloor_t *rover;
|
||||||
fixed_t heightcheck, planecenterz, floorcenterz, ceilingcenterz;
|
fixed_t heightcheck, planecenterz;
|
||||||
|
|
||||||
for (rover = frontsector->ffloors; rover && numffloors < MAXFFLOORS; rover = rover->next)
|
for (rover = frontsector->ffloors; rover && numffloors < MAXFFLOORS; rover = rover->next)
|
||||||
{
|
{
|
||||||
|
@ -975,18 +986,6 @@ static void R_Subsector(size_t num)
|
||||||
ffloor[numffloors].plane = NULL;
|
ffloor[numffloors].plane = NULL;
|
||||||
ffloor[numffloors].polyobj = NULL;
|
ffloor[numffloors].polyobj = NULL;
|
||||||
|
|
||||||
floorcenterz =
|
|
||||||
#ifdef ESLOPE
|
|
||||||
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
|
|
||||||
#endif
|
|
||||||
frontsector->floorheight;
|
|
||||||
|
|
||||||
ceilingcenterz =
|
|
||||||
#ifdef ESLOPE
|
|
||||||
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
|
|
||||||
#endif
|
|
||||||
frontsector->ceilingheight;
|
|
||||||
|
|
||||||
heightcheck =
|
heightcheck =
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) :
|
*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) :
|
||||||
|
@ -1009,6 +1008,9 @@ static void R_Subsector(size_t num)
|
||||||
ffloor[numffloors].plane = R_FindPlane(*rover->bottomheight, *rover->bottompic,
|
ffloor[numffloors].plane = R_FindPlane(*rover->bottomheight, *rover->bottompic,
|
||||||
*frontsector->lightlist[light].lightlevel, *rover->bottomxoffs,
|
*frontsector->lightlist[light].lightlevel, *rover->bottomxoffs,
|
||||||
*rover->bottomyoffs, *rover->bottomangle, frontsector->lightlist[light].extra_colormap, rover
|
*rover->bottomyoffs, *rover->bottomangle, frontsector->lightlist[light].extra_colormap, rover
|
||||||
|
#ifdef POLYOBJECTS_PLANES
|
||||||
|
, NULL
|
||||||
|
#endif
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
, *rover->b_slope
|
, *rover->b_slope
|
||||||
#endif
|
#endif
|
||||||
|
@ -1052,6 +1054,9 @@ static void R_Subsector(size_t num)
|
||||||
ffloor[numffloors].plane = R_FindPlane(*rover->topheight, *rover->toppic,
|
ffloor[numffloors].plane = R_FindPlane(*rover->topheight, *rover->toppic,
|
||||||
*frontsector->lightlist[light].lightlevel, *rover->topxoffs, *rover->topyoffs, *rover->topangle,
|
*frontsector->lightlist[light].lightlevel, *rover->topxoffs, *rover->topyoffs, *rover->topangle,
|
||||||
frontsector->lightlist[light].extra_colormap, rover
|
frontsector->lightlist[light].extra_colormap, rover
|
||||||
|
#ifdef POLYOBJECTS_PLANES
|
||||||
|
, NULL
|
||||||
|
#endif
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
, *rover->t_slope
|
, *rover->t_slope
|
||||||
#endif
|
#endif
|
||||||
|
@ -1093,8 +1098,8 @@ static void R_Subsector(size_t num)
|
||||||
polysec = po->lines[0]->backsector;
|
polysec = po->lines[0]->backsector;
|
||||||
ffloor[numffloors].plane = NULL;
|
ffloor[numffloors].plane = NULL;
|
||||||
|
|
||||||
if (polysec->floorheight <= frontsector->ceilingheight
|
if (polysec->floorheight <= ceilingcenterz
|
||||||
&& polysec->floorheight >= frontsector->floorheight
|
&& polysec->floorheight >= floorcenterz
|
||||||
&& (viewz < polysec->floorheight))
|
&& (viewz < polysec->floorheight))
|
||||||
{
|
{
|
||||||
fixed_t xoff, yoff;
|
fixed_t xoff, yoff;
|
||||||
|
@ -1118,11 +1123,13 @@ static void R_Subsector(size_t num)
|
||||||
polysec->floorpic_angle-po->angle,
|
polysec->floorpic_angle-po->angle,
|
||||||
NULL,
|
NULL,
|
||||||
NULL
|
NULL
|
||||||
|
#ifdef POLYOBJECTS_PLANES
|
||||||
|
, po
|
||||||
|
#endif
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
, NULL // will ffloors be slopable eventually?
|
, NULL // will ffloors be slopable eventually?
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
//ffloor[numffloors].plane->polyobj = po;
|
|
||||||
|
|
||||||
ffloor[numffloors].height = polysec->floorheight;
|
ffloor[numffloors].height = polysec->floorheight;
|
||||||
ffloor[numffloors].polyobj = po;
|
ffloor[numffloors].polyobj = po;
|
||||||
|
@ -1139,8 +1146,8 @@ static void R_Subsector(size_t num)
|
||||||
|
|
||||||
ffloor[numffloors].plane = NULL;
|
ffloor[numffloors].plane = NULL;
|
||||||
|
|
||||||
if (polysec->ceilingheight >= frontsector->floorheight
|
if (polysec->ceilingheight >= floorcenterz
|
||||||
&& polysec->ceilingheight <= frontsector->ceilingheight
|
&& polysec->ceilingheight <= ceilingcenterz
|
||||||
&& (viewz > polysec->ceilingheight))
|
&& (viewz > polysec->ceilingheight))
|
||||||
{
|
{
|
||||||
fixed_t xoff, yoff;
|
fixed_t xoff, yoff;
|
||||||
|
@ -1162,11 +1169,13 @@ static void R_Subsector(size_t num)
|
||||||
ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic,
|
ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic,
|
||||||
polysec->lightlevel, xoff, yoff, polysec->ceilingpic_angle-po->angle,
|
polysec->lightlevel, xoff, yoff, polysec->ceilingpic_angle-po->angle,
|
||||||
NULL, NULL
|
NULL, NULL
|
||||||
|
#ifdef POLYOBJECTS_PLANES
|
||||||
|
, po
|
||||||
|
#endif
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
, NULL // will ffloors be slopable eventually?
|
, NULL // will ffloors be slopable eventually?
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
//ffloor[numffloors].plane->polyobj = po;
|
|
||||||
|
|
||||||
ffloor[numffloors].polyobj = po;
|
ffloor[numffloors].polyobj = po;
|
||||||
ffloor[numffloors].height = polysec->ceilingheight;
|
ffloor[numffloors].height = polysec->ceilingheight;
|
||||||
|
|
26
src/r_data.c
26
src/r_data.c
|
@ -303,6 +303,32 @@ done:
|
||||||
return blocktex;
|
return blocktex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// R_GetTextureNum
|
||||||
|
//
|
||||||
|
// Returns the actual texture id that we should use.
|
||||||
|
// This can either be texnum, the current frame for texnum's anim (if animated),
|
||||||
|
// or 0 if not valid.
|
||||||
|
//
|
||||||
|
INT32 R_GetTextureNum(INT32 texnum)
|
||||||
|
{
|
||||||
|
if (texnum < 0 || texnum >= numtextures)
|
||||||
|
return 0;
|
||||||
|
return texturetranslation[texnum];
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// R_CheckTextureCache
|
||||||
|
//
|
||||||
|
// Use this if you need to make sure the texture is cached before R_GetColumn calls
|
||||||
|
// e.g.: midtextures and FOF walls
|
||||||
|
//
|
||||||
|
void R_CheckTextureCache(INT32 tex)
|
||||||
|
{
|
||||||
|
if (!texturecache[tex])
|
||||||
|
R_GenerateTexture(tex);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// R_GetColumn
|
// R_GetColumn
|
||||||
//
|
//
|
||||||
|
|
|
@ -65,6 +65,9 @@ extern CV_PossibleValue_t Color_cons_t[];
|
||||||
void R_LoadTextures(void);
|
void R_LoadTextures(void);
|
||||||
void R_FlushTextureCache(void);
|
void R_FlushTextureCache(void);
|
||||||
|
|
||||||
|
INT32 R_GetTextureNum(INT32 texnum);
|
||||||
|
void R_CheckTextureCache(INT32 tex);
|
||||||
|
|
||||||
// Retrieve column data for span blitting.
|
// Retrieve column data for span blitting.
|
||||||
UINT8 *R_GetColumn(fixed_t tex, INT32 col);
|
UINT8 *R_GetColumn(fixed_t tex, INT32 col);
|
||||||
|
|
||||||
|
|
11
src/r_defs.h
11
src/r_defs.h
|
@ -203,6 +203,7 @@ typedef struct r_lightlist_s
|
||||||
fixed_t heightstep;
|
fixed_t heightstep;
|
||||||
fixed_t botheight;
|
fixed_t botheight;
|
||||||
fixed_t botheightstep;
|
fixed_t botheightstep;
|
||||||
|
fixed_t startheight; // for repeating midtextures
|
||||||
INT16 lightlevel;
|
INT16 lightlevel;
|
||||||
extracolormap_t *extra_colormap;
|
extracolormap_t *extra_colormap;
|
||||||
lighttable_t *rcolormap;
|
lighttable_t *rcolormap;
|
||||||
|
@ -224,15 +225,6 @@ typedef struct linechain_s
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ZDoom C++ to Legacy C conversion Tails 04-29-2002 (for slopes)
|
|
||||||
typedef struct secplane_t
|
|
||||||
{
|
|
||||||
// the plane is defined as a*x + b*y + c*z + d = 0
|
|
||||||
// ic is 1/c, for faster Z calculations
|
|
||||||
|
|
||||||
fixed_t a, b, c, d, ic;
|
|
||||||
} secplane_t;
|
|
||||||
|
|
||||||
// Slopes
|
// Slopes
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -392,6 +384,7 @@ typedef struct sector_s
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// these are saved for netgames, so do not let Lua touch these!
|
// these are saved for netgames, so do not let Lua touch these!
|
||||||
|
INT32 spawn_nexttag, spawn_firsttag; // the actual nexttag/firsttag values may differ if the sector's tag was changed
|
||||||
|
|
||||||
// offsets sector spawned with (via linedef type 7)
|
// offsets sector spawned with (via linedef type 7)
|
||||||
fixed_t spawn_flr_xoffs, spawn_flr_yoffs;
|
fixed_t spawn_flr_xoffs, spawn_flr_yoffs;
|
||||||
|
|
63
src/r_main.c
63
src/r_main.c
|
@ -366,69 +366,6 @@ fixed_t R_PointToDist(fixed_t x, fixed_t y)
|
||||||
return R_PointToDist2(viewx, viewy, x, y);
|
return R_PointToDist2(viewx, viewy, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************
|
|
||||||
*** Zdoom C++ to Legacy C conversion ***
|
|
||||||
****************************************/
|
|
||||||
|
|
||||||
// Utility to find the Z height at an XY location in a sector (for slopes)
|
|
||||||
fixed_t R_SecplaneZatPoint(secplane_t *secplane, fixed_t x, fixed_t y)
|
|
||||||
{
|
|
||||||
return FixedMul(secplane->ic, -secplane->d - DMulScale16(secplane->a, x, secplane->b, y));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the value of z at (x,y) if d is equal to dist
|
|
||||||
fixed_t R_SecplaneZatPointDist (secplane_t *secplane, fixed_t x, fixed_t y, fixed_t dist)
|
|
||||||
{
|
|
||||||
return FixedMul(secplane->ic, -dist - DMulScale16(secplane->a, x, secplane->b, y));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flips the plane's vertical orientiation, so that if it pointed up,
|
|
||||||
// it will point down, and vice versa.
|
|
||||||
void R_SecplaneFlipVert(secplane_t *secplane)
|
|
||||||
{
|
|
||||||
secplane->a = -secplane->a;
|
|
||||||
secplane->b = -secplane->b;
|
|
||||||
secplane->c = -secplane->c;
|
|
||||||
secplane->d = -secplane->d;
|
|
||||||
secplane->ic = -secplane->ic;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if 2 planes are the same
|
|
||||||
boolean R_ArePlanesSame(secplane_t *original, secplane_t *other)
|
|
||||||
{
|
|
||||||
return original->a == other->a && original->b == other->b
|
|
||||||
&& original->c == other->c && original->d == other->d;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if 2 planes are different
|
|
||||||
boolean R_ArePlanesDifferent(secplane_t *original, secplane_t *other)
|
|
||||||
{
|
|
||||||
return original->a != other->a || original->b != other->b
|
|
||||||
|| original->c != other->c || original->d != other->d;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Moves a plane up/down by hdiff units
|
|
||||||
void R_SecplaneChangeHeight(secplane_t *secplane, fixed_t hdiff)
|
|
||||||
{
|
|
||||||
secplane->d = secplane->d - FixedMul(hdiff, secplane->c);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns how much this plane's height would change if d were set to oldd
|
|
||||||
fixed_t R_SecplaneHeightDiff(secplane_t *secplane, fixed_t oldd)
|
|
||||||
{
|
|
||||||
return FixedMul(oldd - secplane->d, secplane->ic);
|
|
||||||
}
|
|
||||||
|
|
||||||
fixed_t R_SecplanePointToDist(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z)
|
|
||||||
{
|
|
||||||
return -TMulScale16(secplane->a, x, y, secplane->b, z, secplane->c);
|
|
||||||
}
|
|
||||||
|
|
||||||
fixed_t R_SecplanePointToDist2(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z)
|
|
||||||
{
|
|
||||||
return -TMulScale16(secplane->a, x, secplane->b, y, z, secplane->c);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// R_ScaleFromGlobalAngle
|
// R_ScaleFromGlobalAngle
|
||||||
// Returns the texture mapping scale for the current line (horizontal span)
|
// Returns the texture mapping scale for the current line (horizontal span)
|
||||||
|
|
12
src/r_main.h
12
src/r_main.h
|
@ -61,18 +61,6 @@ angle_t R_PointToAngle2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
|
||||||
fixed_t R_PointToDist(fixed_t x, fixed_t y);
|
fixed_t R_PointToDist(fixed_t x, fixed_t y);
|
||||||
fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
|
fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
|
||||||
|
|
||||||
// ZDoom C++ to Legacy C conversion Tails 04-29-2002
|
|
||||||
fixed_t R_SecplaneZatPoint(secplane_t *secplane, fixed_t x, fixed_t y);
|
|
||||||
fixed_t R_SecplaneZatPointDist(secplane_t *secplane, fixed_t x, fixed_t y,
|
|
||||||
fixed_t dist);
|
|
||||||
void R_SecplaneFlipVert(secplane_t *secplane);
|
|
||||||
boolean R_ArePlanesSame(secplane_t *original, secplane_t *other);
|
|
||||||
boolean R_ArePlanesDifferent(secplane_t *original, secplane_t *other);
|
|
||||||
void R_SecplaneChangeHeight(secplane_t *secplane, fixed_t hdiff);
|
|
||||||
fixed_t R_SecplaneHeightDiff(secplane_t *secplane, fixed_t oldd);
|
|
||||||
fixed_t R_SecplanePointToDist(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z);
|
|
||||||
fixed_t R_SecplanePointToDist2(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z);
|
|
||||||
|
|
||||||
fixed_t R_ScaleFromGlobalAngle(angle_t visangle);
|
fixed_t R_ScaleFromGlobalAngle(angle_t visangle);
|
||||||
subsector_t *R_PointInSubsector(fixed_t x, fixed_t y);
|
subsector_t *R_PointInSubsector(fixed_t x, fixed_t y);
|
||||||
subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y);
|
subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y);
|
||||||
|
|
|
@ -431,6 +431,9 @@ static visplane_t *new_visplane(unsigned hash)
|
||||||
visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
|
visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
|
||||||
fixed_t xoff, fixed_t yoff, angle_t plangle, extracolormap_t *planecolormap,
|
fixed_t xoff, fixed_t yoff, angle_t plangle, extracolormap_t *planecolormap,
|
||||||
ffloor_t *pfloor
|
ffloor_t *pfloor
|
||||||
|
#ifdef POLYOBJECTS_PLANES
|
||||||
|
, polyobj_t *polyobj
|
||||||
|
#endif
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
, pslope_t *slope
|
, pslope_t *slope
|
||||||
#endif
|
#endif
|
||||||
|
@ -470,6 +473,8 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
|
||||||
#ifdef POLYOBJECTS_PLANES
|
#ifdef POLYOBJECTS_PLANES
|
||||||
if (check->polyobj && pfloor)
|
if (check->polyobj && pfloor)
|
||||||
continue;
|
continue;
|
||||||
|
if (polyobj != check->polyobj)
|
||||||
|
continue;
|
||||||
#endif
|
#endif
|
||||||
if (height == check->height && picnum == check->picnum
|
if (height == check->height && picnum == check->picnum
|
||||||
&& lightlevel == check->lightlevel
|
&& lightlevel == check->lightlevel
|
||||||
|
@ -504,7 +509,7 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
|
||||||
check->viewangle = viewangle;
|
check->viewangle = viewangle;
|
||||||
check->plangle = plangle;
|
check->plangle = plangle;
|
||||||
#ifdef POLYOBJECTS_PLANES
|
#ifdef POLYOBJECTS_PLANES
|
||||||
check->polyobj = NULL;
|
check->polyobj = polyobj;
|
||||||
#endif
|
#endif
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
check->slope = slope;
|
check->slope = slope;
|
||||||
|
@ -719,7 +724,11 @@ void R_DrawPlanes(void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pl->ffloor != NULL)
|
if (pl->ffloor != NULL
|
||||||
|
#ifdef POLYOBJECTS_PLANES
|
||||||
|
|| pl->polyobj != NULL
|
||||||
|
#endif
|
||||||
|
)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
R_DrawSinglePlane(pl);
|
R_DrawSinglePlane(pl);
|
||||||
|
|
|
@ -97,6 +97,9 @@ void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2);
|
||||||
void R_DrawPlanes(void);
|
void R_DrawPlanes(void);
|
||||||
visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, angle_t plangle,
|
visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, angle_t plangle,
|
||||||
extracolormap_t *planecolormap, ffloor_t *ffloor
|
extracolormap_t *planecolormap, ffloor_t *ffloor
|
||||||
|
#ifdef POLYOBJECTS_PLANES
|
||||||
|
, polyobj_t *polyobj
|
||||||
|
#endif
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
, pslope_t *slope
|
, pslope_t *slope
|
||||||
#endif
|
#endif
|
||||||
|
|
132
src/r_segs.c
132
src/r_segs.c
|
@ -300,7 +300,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
||||||
curline = ds->curline;
|
curline = ds->curline;
|
||||||
frontsector = curline->frontsector;
|
frontsector = curline->frontsector;
|
||||||
backsector = curline->backsector;
|
backsector = curline->backsector;
|
||||||
texnum = texturetranslation[curline->sidedef->midtexture];
|
texnum = R_GetTextureNum(curline->sidedef->midtexture);
|
||||||
windowbottom = windowtop = sprbotscreen = INT32_MAX;
|
windowbottom = windowtop = sprbotscreen = INT32_MAX;
|
||||||
|
|
||||||
// hack translucent linedef types (900-909 for transtables 1-9)
|
// hack translucent linedef types (900-909 for transtables 1-9)
|
||||||
|
@ -344,6 +344,9 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
||||||
rw_scalestep = ds->scalestep;
|
rw_scalestep = ds->scalestep;
|
||||||
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
|
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
|
||||||
|
|
||||||
|
// Texture must be cached before setting colfunc_2s,
|
||||||
|
// otherwise texture[texnum]->holes may be false when it shouldn't be
|
||||||
|
R_CheckTextureCache(texnum);
|
||||||
// handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
|
// handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
|
||||||
// are not stored per-column with post info in SRB2
|
// are not stored per-column with post info in SRB2
|
||||||
if (textures[texnum]->holes)
|
if (textures[texnum]->holes)
|
||||||
|
@ -391,6 +394,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
||||||
rlight->height = (centeryfrac) - FixedMul((light->height - viewz), spryscale);
|
rlight->height = (centeryfrac) - FixedMul((light->height - viewz), spryscale);
|
||||||
rlight->heightstep = -FixedMul(rw_scalestep, (light->height - viewz));
|
rlight->heightstep = -FixedMul(rw_scalestep, (light->height - viewz));
|
||||||
#endif
|
#endif
|
||||||
|
rlight->startheight = rlight->height; // keep starting value here to reset for each repeat
|
||||||
rlight->lightlevel = *light->lightlevel;
|
rlight->lightlevel = *light->lightlevel;
|
||||||
rlight->extra_colormap = light->extra_colormap;
|
rlight->extra_colormap = light->extra_colormap;
|
||||||
rlight->flags = light->flags;
|
rlight->flags = light->flags;
|
||||||
|
@ -484,6 +488,14 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
||||||
{
|
{
|
||||||
rw_scalestep = ds->scalestep;
|
rw_scalestep = ds->scalestep;
|
||||||
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
|
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
|
||||||
|
if (dc_numlights)
|
||||||
|
{ // reset all lights to their starting heights
|
||||||
|
for (i = 0; i < dc_numlights; i++)
|
||||||
|
{
|
||||||
|
rlight = &dc_lightlist[i];
|
||||||
|
rlight->height = rlight->startheight;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef ESLOPE
|
#ifndef ESLOPE
|
||||||
|
@ -694,10 +706,13 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
||||||
// Loop through R_DrawMaskedColumn calls
|
// Loop through R_DrawMaskedColumn calls
|
||||||
static void R_DrawRepeatMaskedColumn(column_t *col)
|
static void R_DrawRepeatMaskedColumn(column_t *col)
|
||||||
{
|
{
|
||||||
do {
|
while (sprtopscreen < sprbotscreen) {
|
||||||
R_DrawMaskedColumn(col);
|
R_DrawMaskedColumn(col);
|
||||||
sprtopscreen += dc_texheight*spryscale;
|
if ((INT64)sprtopscreen + dc_texheight*spryscale > (INT64)INT32_MAX) // prevent overflow
|
||||||
} while (sprtopscreen < sprbotscreen);
|
sprtopscreen = INT32_MAX;
|
||||||
|
else
|
||||||
|
sprtopscreen += dc_texheight*spryscale;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -740,7 +755,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
|
||||||
curline = ds->curline;
|
curline = ds->curline;
|
||||||
backsector = pfloor->target;
|
backsector = pfloor->target;
|
||||||
frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector;
|
frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector;
|
||||||
texnum = texturetranslation[sides[pfloor->master->sidenum[0]].midtexture];
|
texnum = R_GetTextureNum(sides[pfloor->master->sidenum[0]].midtexture);
|
||||||
|
|
||||||
colfunc = wallcolfunc;
|
colfunc = wallcolfunc;
|
||||||
|
|
||||||
|
@ -748,7 +763,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
|
||||||
{
|
{
|
||||||
size_t linenum = curline->linedef-backsector->lines[0];
|
size_t linenum = curline->linedef-backsector->lines[0];
|
||||||
newline = pfloor->master->frontsector->lines[0] + linenum;
|
newline = pfloor->master->frontsector->lines[0] + linenum;
|
||||||
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
|
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pfloor->flags & FF_TRANSLUCENT)
|
if (pfloor->flags & FF_TRANSLUCENT)
|
||||||
|
@ -968,6 +983,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
|
||||||
|
|
||||||
dc_texturemid += offsetvalue;
|
dc_texturemid += offsetvalue;
|
||||||
|
|
||||||
|
// Texture must be cached before setting colfunc_2s,
|
||||||
|
// otherwise texture[texnum]->holes may be false when it shouldn't be
|
||||||
|
R_CheckTextureCache(texnum);
|
||||||
//faB: handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
|
//faB: handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
|
||||||
// are not stored per-column with post info anymore in Doom Legacy
|
// are not stored per-column with post info anymore in Doom Legacy
|
||||||
if (textures[texnum]->holes)
|
if (textures[texnum]->holes)
|
||||||
|
@ -1878,14 +1896,16 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
||||||
|
|
||||||
if (!backsector)
|
if (!backsector)
|
||||||
{
|
{
|
||||||
|
fixed_t texheight;
|
||||||
// single sided line
|
// single sided line
|
||||||
midtexture = texturetranslation[sidedef->midtexture];
|
midtexture = R_GetTextureNum(sidedef->midtexture);
|
||||||
|
texheight = textureheight[midtexture];
|
||||||
// a single sided line is terminal, so it must mark ends
|
// a single sided line is terminal, so it must mark ends
|
||||||
markfloor = markceiling = true;
|
markfloor = markceiling = true;
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
if (linedef->flags & ML_EFFECT2) {
|
if (linedef->flags & ML_EFFECT2) {
|
||||||
if (linedef->flags & ML_DONTPEGBOTTOM)
|
if (linedef->flags & ML_DONTPEGBOTTOM)
|
||||||
rw_midtexturemid = frontsector->floorheight + textureheight[sidedef->midtexture] - viewz;
|
rw_midtexturemid = frontsector->floorheight + texheight - viewz;
|
||||||
else
|
else
|
||||||
rw_midtexturemid = frontsector->ceilingheight - viewz;
|
rw_midtexturemid = frontsector->ceilingheight - viewz;
|
||||||
}
|
}
|
||||||
|
@ -1894,10 +1914,10 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
||||||
if (linedef->flags & ML_DONTPEGBOTTOM)
|
if (linedef->flags & ML_DONTPEGBOTTOM)
|
||||||
{
|
{
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
rw_midtexturemid = worldbottom + textureheight[sidedef->midtexture];
|
rw_midtexturemid = worldbottom + texheight;
|
||||||
rw_midtextureslide = floorfrontslide;
|
rw_midtextureslide = floorfrontslide;
|
||||||
#else
|
#else
|
||||||
vtop = frontsector->floorheight + textureheight[sidedef->midtexture];
|
vtop = frontsector->floorheight + texheight;
|
||||||
// bottom of texture at bottom
|
// bottom of texture at bottom
|
||||||
rw_midtexturemid = vtop - viewz;
|
rw_midtexturemid = vtop - viewz;
|
||||||
#endif
|
#endif
|
||||||
|
@ -2129,76 +2149,50 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
fixed_t texheight;
|
||||||
// top texture
|
// top texture
|
||||||
if ((linedef->flags & (ML_DONTPEGTOP) && (linedef->flags & ML_DONTPEGBOTTOM))
|
if ((linedef->flags & (ML_DONTPEGTOP) && (linedef->flags & ML_DONTPEGBOTTOM))
|
||||||
&& linedef->sidenum[1] != 0xffff)
|
&& linedef->sidenum[1] != 0xffff)
|
||||||
{
|
{
|
||||||
// Special case... use offsets from 2nd side but only if it has a texture.
|
// Special case... use offsets from 2nd side but only if it has a texture.
|
||||||
side_t *def = &sides[linedef->sidenum[1]];
|
side_t *def = &sides[linedef->sidenum[1]];
|
||||||
toptexture = texturetranslation[def->toptexture];
|
toptexture = R_GetTextureNum(def->toptexture);
|
||||||
|
|
||||||
if (!toptexture) //Second side has no texture, use the first side's instead.
|
if (!toptexture) //Second side has no texture, use the first side's instead.
|
||||||
toptexture = texturetranslation[sidedef->toptexture];
|
toptexture = R_GetTextureNum(sidedef->toptexture);
|
||||||
|
texheight = textureheight[toptexture];
|
||||||
#ifdef ESLOPE
|
|
||||||
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
|
|
||||||
if (linedef->flags & ML_DONTPEGTOP)
|
|
||||||
rw_toptexturemid = frontsector->ceilingheight - viewz;
|
|
||||||
else
|
|
||||||
rw_toptexturemid = backsector->ceilingheight - viewz;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
if (linedef->flags & ML_DONTPEGTOP)
|
|
||||||
{
|
|
||||||
// top of texture at top
|
|
||||||
rw_toptexturemid = worldtop;
|
|
||||||
#ifdef ESLOPE
|
|
||||||
rw_toptextureslide = ceilingfrontslide;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#ifdef ESLOPE
|
|
||||||
rw_toptexturemid = worldhigh + textureheight[def->toptexture];
|
|
||||||
rw_toptextureslide = ceilingbackslide;
|
|
||||||
#else
|
|
||||||
vtop = backsector->ceilingheight + textureheight[def->toptexture];
|
|
||||||
// bottom of texture
|
|
||||||
rw_toptexturemid = vtop - viewz;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
toptexture = texturetranslation[sidedef->toptexture];
|
toptexture = R_GetTextureNum(sidedef->toptexture);
|
||||||
|
texheight = textureheight[toptexture];
|
||||||
|
}
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
|
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
|
||||||
if (linedef->flags & ML_DONTPEGTOP)
|
|
||||||
rw_toptexturemid = frontsector->ceilingheight - viewz;
|
|
||||||
else
|
|
||||||
rw_toptexturemid = backsector->ceilingheight - viewz;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
if (linedef->flags & ML_DONTPEGTOP)
|
if (linedef->flags & ML_DONTPEGTOP)
|
||||||
{
|
rw_toptexturemid = frontsector->ceilingheight - viewz;
|
||||||
// top of texture at top
|
|
||||||
rw_toptexturemid = worldtop;
|
|
||||||
#ifdef ESLOPE
|
|
||||||
rw_toptextureslide = ceilingfrontslide;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
rw_toptexturemid = backsector->ceilingheight - viewz;
|
||||||
#ifdef ESLOPE
|
} else
|
||||||
rw_toptexturemid = worldhigh + textureheight[sidedef->toptexture];
|
#endif
|
||||||
rw_toptextureslide = ceilingbackslide;
|
if (linedef->flags & ML_DONTPEGTOP)
|
||||||
#else
|
{
|
||||||
vtop = backsector->ceilingheight + textureheight[sidedef->toptexture];
|
// top of texture at top
|
||||||
// bottom of texture
|
rw_toptexturemid = worldtop;
|
||||||
rw_toptexturemid = vtop - viewz;
|
#ifdef ESLOPE
|
||||||
|
rw_toptextureslide = ceilingfrontslide;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef ESLOPE
|
||||||
|
rw_toptexturemid = worldhigh + texheight;
|
||||||
|
rw_toptextureslide = ceilingbackslide;
|
||||||
|
#else
|
||||||
|
vtop = backsector->ceilingheight + texheight;
|
||||||
|
// bottom of texture
|
||||||
|
rw_toptexturemid = vtop - viewz;
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check BOTTOM TEXTURE
|
// check BOTTOM TEXTURE
|
||||||
|
@ -2209,7 +2203,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
||||||
) //seulement si VISIBLE!!!
|
) //seulement si VISIBLE!!!
|
||||||
{
|
{
|
||||||
// bottom texture
|
// bottom texture
|
||||||
bottomtexture = texturetranslation[sidedef->bottomtexture];
|
bottomtexture = R_GetTextureNum(sidedef->bottomtexture);
|
||||||
|
|
||||||
#ifdef ESLOPE
|
#ifdef ESLOPE
|
||||||
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
|
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
|
||||||
|
@ -2494,7 +2488,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
||||||
|
|
||||||
ds_p->numthicksides = numthicksides = i;
|
ds_p->numthicksides = numthicksides = i;
|
||||||
}
|
}
|
||||||
if (sidedef->midtexture)
|
if (sidedef->midtexture > 0 && sidedef->midtexture < numtextures)
|
||||||
{
|
{
|
||||||
// masked midtexture
|
// masked midtexture
|
||||||
if (!ds_p->thicksidecol)
|
if (!ds_p->thicksidecol)
|
||||||
|
@ -3101,12 +3095,12 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
||||||
if (maskedtexture && !(ds_p->silhouette & SIL_TOP))
|
if (maskedtexture && !(ds_p->silhouette & SIL_TOP))
|
||||||
{
|
{
|
||||||
ds_p->silhouette |= SIL_TOP;
|
ds_p->silhouette |= SIL_TOP;
|
||||||
ds_p->tsilheight = sidedef->midtexture ? INT32_MIN: INT32_MAX;
|
ds_p->tsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MIN: INT32_MAX;
|
||||||
}
|
}
|
||||||
if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM))
|
if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM))
|
||||||
{
|
{
|
||||||
ds_p->silhouette |= SIL_BOTTOM;
|
ds_p->silhouette |= SIL_BOTTOM;
|
||||||
ds_p->bsilheight = sidedef->midtexture ? INT32_MAX: INT32_MIN;
|
ds_p->bsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MAX: INT32_MIN;
|
||||||
}
|
}
|
||||||
ds_p++;
|
ds_p++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -891,12 +891,18 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis)
|
||||||
#endif
|
#endif
|
||||||
fixed_t frac;
|
fixed_t frac;
|
||||||
patch_t *patch;
|
patch_t *patch;
|
||||||
|
INT64 overflow_test;
|
||||||
|
|
||||||
//Fab : R_InitSprites now sets a wad lump number
|
//Fab : R_InitSprites now sets a wad lump number
|
||||||
patch = W_CacheLumpNum(vis->patch, PU_CACHE);
|
patch = W_CacheLumpNum(vis->patch, PU_CACHE);
|
||||||
if (!patch)
|
if (!patch)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Check for overflow
|
||||||
|
overflow_test = (INT64)centeryfrac - (((INT64)vis->texturemid*vis->scale)>>FRACBITS);
|
||||||
|
if (overflow_test < 0) overflow_test = -overflow_test;
|
||||||
|
if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // fixed point mult would overflow
|
||||||
|
|
||||||
if (vis->transmap)
|
if (vis->transmap)
|
||||||
{
|
{
|
||||||
colfunc = fuzzcolfunc;
|
colfunc = fuzzcolfunc;
|
||||||
|
@ -1699,21 +1705,25 @@ static void R_CreateDrawNodes(void)
|
||||||
entry->ffloor = ds->thicksides[i];
|
entry->ffloor = ds->thicksides[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef POLYOBJECTS_PLANES
|
||||||
|
// Check for a polyobject plane, but only if this is a front line
|
||||||
|
if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) {
|
||||||
|
plane = ds->curline->polyseg->visplane;
|
||||||
|
R_PlaneBounds(plane);
|
||||||
|
|
||||||
|
if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low)
|
||||||
|
;
|
||||||
|
else {
|
||||||
|
// Put it in!
|
||||||
|
entry = R_CreateDrawNode(&nodehead);
|
||||||
|
entry->plane = plane;
|
||||||
|
entry->seg = ds;
|
||||||
|
}
|
||||||
|
ds->curline->polyseg->visplane = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (ds->maskedtexturecol)
|
if (ds->maskedtexturecol)
|
||||||
{
|
{
|
||||||
#ifdef POLYOBJECTS_PLANES
|
|
||||||
// Check for a polyobject plane, but only if this is a front line
|
|
||||||
if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) {
|
|
||||||
// Put it in!
|
|
||||||
|
|
||||||
entry = R_CreateDrawNode(&nodehead);
|
|
||||||
entry->plane = ds->curline->polyseg->visplane;
|
|
||||||
entry->seg = ds;
|
|
||||||
ds->curline->polyseg->visplane->polyobj = ds->curline->polyseg;
|
|
||||||
ds->curline->polyseg->visplane = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
entry = R_CreateDrawNode(&nodehead);
|
entry = R_CreateDrawNode(&nodehead);
|
||||||
entry->seg = ds;
|
entry->seg = ds;
|
||||||
}
|
}
|
||||||
|
@ -1756,6 +1766,29 @@ static void R_CreateDrawNodes(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef POLYOBJECTS_PLANES
|
||||||
|
// find all the remaining polyobject planes and add them on the end of the list
|
||||||
|
// probably this is a terrible idea if we wanted them to be sorted properly
|
||||||
|
// but it works getting them in for now
|
||||||
|
for (i = 0; i < numPolyObjects; i++)
|
||||||
|
{
|
||||||
|
if (!PolyObjects[i].visplane)
|
||||||
|
continue;
|
||||||
|
plane = PolyObjects[i].visplane;
|
||||||
|
R_PlaneBounds(plane);
|
||||||
|
|
||||||
|
if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low)
|
||||||
|
{
|
||||||
|
PolyObjects[i].visplane = NULL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
entry = R_CreateDrawNode(&nodehead);
|
||||||
|
entry->plane = plane;
|
||||||
|
// note: no seg is set, for what should be obvious reasons
|
||||||
|
PolyObjects[i].visplane = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (visspritecount == 0)
|
if (visspritecount == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1812,13 +1845,16 @@ static void R_CreateDrawNodes(void)
|
||||||
if (x1 < r2->plane->minx) x1 = r2->plane->minx;
|
if (x1 < r2->plane->minx) x1 = r2->plane->minx;
|
||||||
if (x2 > r2->plane->maxx) x2 = r2->plane->maxx;
|
if (x2 > r2->plane->maxx) x2 = r2->plane->maxx;
|
||||||
|
|
||||||
for (i = x1; i <= x2; i++)
|
if (r2->seg) // if no seg set, assume the whole thing is in front or something stupid
|
||||||
{
|
{
|
||||||
if (r2->seg->frontscale[i] > rover->scale)
|
for (i = x1; i <= x2; i++)
|
||||||
break;
|
{
|
||||||
|
if (r2->seg->frontscale[i] > rover->scale)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i > x2)
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (i > x2)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
entry = R_CreateDrawNode(NULL);
|
entry = R_CreateDrawNode(NULL);
|
||||||
(entry->prev = r2->prev)->next = entry;
|
(entry->prev = r2->prev)->next = entry;
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
#include "f_finale.h"
|
#include "f_finale.h"
|
||||||
|
|
||||||
|
|
||||||
#if defined (USEASM) //&& (!defined (_MSC_VER) || (_MSC_VER <= 1200))
|
#if defined (USEASM) && !defined (NORUSEASM)//&& (!defined (_MSC_VER) || (_MSC_VER <= 1200))
|
||||||
#define RUSEASM //MSC.NET can't patch itself
|
#define RUSEASM //MSC.NET can't patch itself
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1214,7 +1214,7 @@
|
||||||
C01FCF4B08A954540054247B /* Debug */ = {
|
C01FCF4B08A954540054247B /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CURRENT_PROJECT_VERSION = 2.1.14;
|
CURRENT_PROJECT_VERSION = 2.1.17;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
NORMALSRB2,
|
NORMALSRB2,
|
||||||
|
@ -1226,7 +1226,7 @@
|
||||||
C01FCF4C08A954540054247B /* Release */ = {
|
C01FCF4C08A954540054247B /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CURRENT_PROJECT_VERSION = 2.1.14;
|
CURRENT_PROJECT_VERSION = 2.1.17;
|
||||||
GCC_ENABLE_FIX_AND_CONTINUE = NO;
|
GCC_ENABLE_FIX_AND_CONTINUE = NO;
|
||||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
|
|
@ -1214,7 +1214,7 @@
|
||||||
C01FCF4B08A954540054247B /* Debug */ = {
|
C01FCF4B08A954540054247B /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CURRENT_PROJECT_VERSION = 2.1.14;
|
CURRENT_PROJECT_VERSION = 2.1.17;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
NORMALSRB2,
|
NORMALSRB2,
|
||||||
|
@ -1226,7 +1226,7 @@
|
||||||
C01FCF4C08A954540054247B /* Release */ = {
|
C01FCF4C08A954540054247B /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CURRENT_PROJECT_VERSION = 2.1.14;
|
CURRENT_PROJECT_VERSION = 2.1.17;
|
||||||
GCC_ENABLE_FIX_AND_CONTINUE = NO;
|
GCC_ENABLE_FIX_AND_CONTINUE = NO;
|
||||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
|
|
@ -267,7 +267,7 @@ static void CV_Gammaxxx_ONChange(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined (__GNUC__) && defined (__i386__) && !defined (NOASM) && !defined (__APPLE__)
|
#if defined (__GNUC__) && defined (__i386__) && !defined (NOASM) && !defined (__APPLE__) && !defined (NORUSEASM)
|
||||||
void VID_BlitLinearScreen_ASM(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT32 height, size_t srcrowbytes,
|
void VID_BlitLinearScreen_ASM(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT32 height, size_t srcrowbytes,
|
||||||
size_t destrowbytes);
|
size_t destrowbytes);
|
||||||
#define HAVE_VIDCOPY
|
#define HAVE_VIDCOPY
|
||||||
|
|
|
@ -1223,6 +1223,7 @@ int W_VerifyNMUSlumps(const char *filename)
|
||||||
{"COLORMAP", 8},
|
{"COLORMAP", 8},
|
||||||
{"PAL", 3},
|
{"PAL", 3},
|
||||||
{"CLM", 3},
|
{"CLM", 3},
|
||||||
|
{"TRANS", 5},
|
||||||
{NULL, 0},
|
{NULL, 0},
|
||||||
};
|
};
|
||||||
return W_VerifyFile(filename, NMUSlist, false);
|
return W_VerifyFile(filename, NMUSlist, false);
|
||||||
|
|
|
@ -20,7 +20,9 @@
|
||||||
|
|
||||||
|
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
|
#ifndef HAVE_SDL
|
||||||
#include "win_main.h"
|
#include "win_main.h"
|
||||||
|
#endif
|
||||||
#include "../doomdef.h" //just for VERSION
|
#include "../doomdef.h" //just for VERSION
|
||||||
#include "win_dbg.h"
|
#include "win_dbg.h"
|
||||||
#include "../m_argv.h" //print the parameter in the log
|
#include "../m_argv.h" //print the parameter in the log
|
||||||
|
|
|
@ -69,7 +69,7 @@ static HCURSOR windowCursor = NULL; // main window cursor
|
||||||
|
|
||||||
static LPCSTR wClassName = "SRB2WC";
|
static LPCSTR wClassName = "SRB2WC";
|
||||||
|
|
||||||
boolean appActive = false; // app window is active
|
INT appActive = false; // app window is active
|
||||||
|
|
||||||
#ifdef LOGMESSAGES
|
#ifdef LOGMESSAGES
|
||||||
FILE *logstream;
|
FILE *logstream;
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
extern HWND hWndMain;
|
extern HWND hWndMain;
|
||||||
|
|
||||||
extern boolean appActive;
|
extern INT appActive;
|
||||||
|
|
||||||
VOID I_GetSysMouseEvents(INT mouse_state);
|
VOID I_GetSysMouseEvents(INT mouse_state);
|
||||||
extern UINT MSHWheelMessage;
|
extern UINT MSHWheelMessage;
|
||||||
|
|
Loading…
Reference in a new issue