From 44575d7e2cf8f9b267645d0b257ad37ec74235ea Mon Sep 17 00:00:00 2001 From: terminx Date: Sat, 5 Dec 2009 09:22:43 +0000 Subject: [PATCH] Ball-busting true client-server multiplayer prototype/alpha/whatever git-svn-id: https://svn.eduke32.com/eduke32@1552 1a8010ca-5511-0410-912e-c29ae57300e0 --- polymer/eduke32/Makefile | 24 +- polymer/eduke32/Makefile.msvc | 14 +- polymer/eduke32/build/Makefile | 2 +- polymer/eduke32/build/Makefile.deps | 4 +- polymer/eduke32/build/Makefile.msvc | 2 +- polymer/eduke32/build/Makefile.shared | 4 +- polymer/eduke32/build/include/build.h | 2 +- polymer/eduke32/build/include/compat.h | 5 +- polymer/eduke32/build/include/fastlz.h | 100 - polymer/eduke32/build/include/malloc.c.h | 21 +- polymer/eduke32/build/include/mmultimsgs.h | 65 - polymer/eduke32/build/include/nedmalloc.h | 106 +- polymer/eduke32/build/include/quicklz.h | 150 + polymer/eduke32/build/src/defs.c | 6 +- polymer/eduke32/build/src/engine.c | 13 +- polymer/eduke32/build/src/fastlz.c | 551 ---- polymer/eduke32/build/src/hightile.c | 29 +- polymer/eduke32/build/src/nedmalloc.c | 553 ++-- polymer/eduke32/build/src/polymer.c | 151 +- polymer/eduke32/build/src/polymost.c | 22 +- polymer/eduke32/build/src/quicklz.c | 854 ++++++ polymer/eduke32/build/src/sdlayer.c | 5 +- polymer/eduke32/build/src/winlayer.c | 2 + polymer/eduke32/eduke32.vcproj | 100 +- polymer/eduke32/source/actors.c | 10 +- polymer/eduke32/source/astub.c | 20 +- polymer/eduke32/source/duke3d.h | 32 +- polymer/eduke32/source/enet/Makefile | 60 + polymer/eduke32/source/enet/Makefile.msvc | 45 + .../source/enet/include/enet/callbacks.h | 28 + .../eduke32/source/enet/include/enet/enet.h | 492 ++++ .../eduke32/source/enet/include/enet/list.h | 42 + .../source/enet/include/enet/protocol.h | 174 ++ .../eduke32/source/enet/include/enet/time.h | 18 + .../eduke32/source/enet/include/enet/types.h | 13 + .../eduke32/source/enet/include/enet/unix.h | 45 + .../source/enet/include/enet/utility.h | 12 + .../eduke32/source/enet/include/enet/win32.h | 58 + polymer/eduke32/source/enet/src/callbacks.c | 53 + polymer/eduke32/source/enet/src/host.c | 401 +++ polymer/eduke32/source/enet/src/list.c | 57 + polymer/eduke32/source/enet/src/packet.c | 155 + polymer/eduke32/source/enet/src/peer.c | 700 +++++ polymer/eduke32/source/enet/src/protocol.c | 1577 ++++++++++ polymer/eduke32/source/enet/src/unix.c | 438 +++ polymer/eduke32/source/enet/src/win32.c | 348 +++ polymer/eduke32/source/funct.h | 1 + polymer/eduke32/source/game.c | 2543 ++++++++--------- polymer/eduke32/source/gamedef.c | 11 +- polymer/eduke32/source/gamedefs.h | 4 - polymer/eduke32/source/gameexec.c | 15 +- polymer/eduke32/source/global.c | 5 +- .../source/jaudiolib/src/driver_directsound.c | 10 +- .../eduke32/source/jaudiolib/src/multivoc.c | 129 +- polymer/eduke32/source/jmact/_control.h | 10 +- polymer/eduke32/source/jmact/control.c | 2 +- polymer/eduke32/source/jmact/control.h | 1 + polymer/eduke32/source/macros.h | 2 +- polymer/eduke32/source/menus.c | 121 +- polymer/eduke32/source/osdcmds.c | 19 +- polymer/eduke32/source/player.c | 16 +- polymer/eduke32/source/premap.c | 169 +- polymer/eduke32/source/sector.c | 6 +- polymer/eduke32/source/sync.c | 2 +- 64 files changed, 7858 insertions(+), 2771 deletions(-) delete mode 100644 polymer/eduke32/build/include/fastlz.h delete mode 100644 polymer/eduke32/build/include/mmultimsgs.h create mode 100644 polymer/eduke32/build/include/quicklz.h delete mode 100644 polymer/eduke32/build/src/fastlz.c create mode 100644 polymer/eduke32/build/src/quicklz.c create mode 100644 polymer/eduke32/source/enet/Makefile create mode 100644 polymer/eduke32/source/enet/Makefile.msvc create mode 100644 polymer/eduke32/source/enet/include/enet/callbacks.h create mode 100644 polymer/eduke32/source/enet/include/enet/enet.h create mode 100644 polymer/eduke32/source/enet/include/enet/list.h create mode 100644 polymer/eduke32/source/enet/include/enet/protocol.h create mode 100644 polymer/eduke32/source/enet/include/enet/time.h create mode 100644 polymer/eduke32/source/enet/include/enet/types.h create mode 100644 polymer/eduke32/source/enet/include/enet/unix.h create mode 100644 polymer/eduke32/source/enet/include/enet/utility.h create mode 100644 polymer/eduke32/source/enet/include/enet/win32.h create mode 100644 polymer/eduke32/source/enet/src/callbacks.c create mode 100644 polymer/eduke32/source/enet/src/host.c create mode 100644 polymer/eduke32/source/enet/src/list.c create mode 100644 polymer/eduke32/source/enet/src/packet.c create mode 100644 polymer/eduke32/source/enet/src/peer.c create mode 100644 polymer/eduke32/source/enet/src/protocol.c create mode 100644 polymer/eduke32/source/enet/src/unix.c create mode 100644 polymer/eduke32/source/enet/src/win32.c diff --git a/polymer/eduke32/Makefile b/polymer/eduke32/Makefile index 67b5e184a..a456e6a75 100644 --- a/polymer/eduke32/Makefile +++ b/polymer/eduke32/Makefile @@ -51,6 +51,9 @@ endif JAUDIOLIBDIR=$(SRC)/jaudiolib JAUDIOLIB=libjfaudiolib.a +ENETDIR=$(SRC)/enet +ENETLIB=libenet.a + CC=gcc CXX=g++ AS=nasm @@ -73,7 +76,7 @@ endif OURCFLAGS=$(debug) -W -Wall -Wimplicit -Werror-implicit-function-declaration \ -funsigned-char -fno-strict-aliasing -DNO_GCC_BUILTINS \ - -I$(INC) -I$(EINC) -I$(SRC)/jmact -I$(JAUDIOLIBDIR)/include -D_FORTIFY_SOURCE=2 \ + -I$(INC) -I$(EINC) -I$(SRC)/jmact -I$(JAUDIOLIBDIR)/include -I$(ENETDIR)/include -D_FORTIFY_SOURCE=2 \ -fjump-tables -fno-stack-protector # -march=pentium3 -mtune=generic -mmmx -m3dnow -msse -mfpmath=sse OURCXXFLAGS=-fno-exceptions -fno-rtti @@ -168,6 +171,7 @@ ifeq ($(PLATFORM),WINDOWS) GAMEOBJS+= $(OBJ)/gameres.$o $(OBJ)/winbits.$o $(OBJ)/startwin.game.$o $(OBJ)/music.$o $(OBJ)/midi.$o $(OBJ)/mpu401.$o EDITOROBJS+= $(OBJ)/buildres.$o JAUDIOLIB=libjfaudiolib_win32.a + ENETLIB=libenet_win32.a else ifeq ($(RENDERTYPE),SDL) ifeq (0,$(SDL_FRAMEWORK)) @@ -198,7 +202,7 @@ OURCXXFLAGS+= $(BUILDCFLAGS) ifeq ($(PRETTY_OUTPUT),1) .SILENT: endif -.PHONY: clean all engine $(EOBJ)/$(ENGINELIB) $(EOBJ)/$(EDITORLIB) $(JAUDIOLIBDIR)/$(JAUDIOLIB) +.PHONY: clean all engine $(EOBJ)/$(ENGINELIB) $(EOBJ)/$(EDITORLIB) $(JAUDIOLIBDIR)/$(JAUDIOLIB) $(ENETDIR)/$(ENETLIB) # TARGETS @@ -212,7 +216,7 @@ all: notice: $(BUILD_STARTED) -eduke32$(EXESUFFIX): $(GAMEOBJS) $(EOBJ)/$(ENGINELIB) $(JAUDIOLIBDIR)/$(JAUDIOLIB) +eduke32$(EXESUFFIX): $(GAMEOBJS) $(EOBJ)/$(ENGINELIB) $(JAUDIOLIBDIR)/$(JAUDIOLIB) $(ENETDIR)/$(ENETLIB) $(LINK_STATUS) if $(CC) -o $@ $^ $(LIBS) $(STDCPPLIB); then $(LINK_OK); else $(LINK_FAILED); fi ifeq (1,$(RELEASE)) @@ -221,7 +225,7 @@ ifeq (1,$(RELEASE)) endif endif -mapster32$(EXESUFFIX): $(EDITOROBJS) $(EOBJ)/$(EDITORLIB) $(EOBJ)/$(ENGINELIB) $(JAUDIOLIBDIR)/$(JAUDIOLIB) +mapster32$(EXESUFFIX): $(EDITOROBJS) $(EOBJ)/$(EDITORLIB) $(EOBJ)/$(ENGINELIB) $(JAUDIOLIBDIR)/$(JAUDIOLIB) $(ENETDIR)/$(ENETLIB) $(LINK_STATUS) if $(CC) $(CFLAGS) $(OURCFLAGS) -o $@ $^ $(LIBS) $(STDCPPLIB); then $(LINK_OK); else $(LINK_FAILED); fi ifeq (1,$(RELEASE)) @@ -268,6 +272,16 @@ ifeq ($(PRETTY_OUTPUT),1) printf "\033[K\033[0;35mChanging dir to \033[1;35m$(CURDIR)\033[0;35m \033[0m\n" endif +$(ENETDIR)/$(ENETLIB): +ifeq ($(PRETTY_OUTPUT),1) + printf "\033[K\033[0;35mChanging dir to \033[1;35m$(CURDIR)/$(ENETDIR)\033[0;35m \033[0m\n" +endif + $(MAKE) -C $(ENETDIR) PRETTY_OUTPUT=$(PRETTY_OUTPUT) EROOT=$(EROOT) RELEASE=$(RELEASE) OPTLEVEL=$(OPTLEVEL) +ifeq ($(PRETTY_OUTPUT),1) + printf "\033[K\033[0;35mChanging dir to \033[1;35m$(CURDIR)\033[0;35m \033[0m\n" +endif + + # RULES $(OBJ)/%.$o: $(SRC)/%.nasm $(COMPILE_STATUS) @@ -309,7 +323,7 @@ $(RSRC)/editor_banner.c: $(RSRC)/build.bmp # PHONIES clean: - -rm -f $(OBJ)/* eduke32$(EXESUFFIX) mapster32$(EXESUFFIX) core* duke3d_w32$(EXESUFFIX) && $(MAKE) -C $(JAUDIOLIBDIR) clean + -rm -f $(OBJ)/* eduke32$(EXESUFFIX) mapster32$(EXESUFFIX) core* duke3d_w32$(EXESUFFIX) && $(MAKE) -C $(JAUDIOLIBDIR) clean && $(MAKE) -C $(ENETDIR) clean veryclean: clean -rm -f $(EOBJ)/* $(RSRC)/*banner* diff --git a/polymer/eduke32/Makefile.msvc b/polymer/eduke32/Makefile.msvc index 19dd3e7df..05f92990a 100644 --- a/polymer/eduke32/Makefile.msvc +++ b/polymer/eduke32/Makefile.msvc @@ -12,6 +12,9 @@ o=obj JAUDIOLIBDIR=$(SRC)\jaudiolib JAUDIOLIB=libjfaudiolib.lib +ENETDIR=$(SRC)\enet +ENETLIB=libenet.lib + ENGINELIB=engine.lib EDITORLIB=build.lib @@ -37,7 +40,7 @@ AS=ml LINK=link /nologo /opt:ref MT=mt CFLAGS= /MT /J /nologo $(flags_cl) \ - /I$(INC) /I$(EINC)\msvc /I$(EINC)\ /I$(SRC)\jmact /I$(JAUDIOLIBDIR)\include /I$(MSSDKROOT)\include" /I$(PLATFORMSDK)\include" \ + /I$(INC) /I$(EINC)\msvc /I$(EINC)\ /I$(SRC)\jmact /I$(JAUDIOLIBDIR)\include /I$(ENETDIR)\include /I$(MSSDKROOT)\include" /I$(PLATFORMSDK)\include" \ /D "_CRT_SECURE_NO_DEPRECATE" /W2 $(ENGINEOPTS) \ /I$(DXROOT)\include" /DRENDERTYPEWIN=1 LIBS=user32.lib gdi32.lib shell32.lib dxguid.lib winmm.lib wsock32.lib comctl32.lib \ @@ -131,7 +134,7 @@ EDITOROBJS=$(OBJ)\astub.$o \ # TARGETS all: eduke32$(EXESUFFIX) mapster32$(EXESUFFIX) # duke3d_w32$(EXESUFFIX); -eduke32$(EXESUFFIX): $(GAMEOBJS) $(EOBJ)\$(ENGINELIB) $(JAUDIOLIBDIR)\$(JAUDIOLIB) +eduke32$(EXESUFFIX): $(GAMEOBJS) $(EOBJ)\$(ENGINELIB) $(JAUDIOLIBDIR)\$(JAUDIOLIB) $(ENETDIR)\$(ENETLIB) $(LINK) /OUT:$@ /SUBSYSTEM:WINDOWS /LIBPATH:$(DXROOT)\lib\x86" /LIBPATH:$(PLATFORMSDK)\lib" /LIBPATH:$(MSSDKROOT)\lib" $(flags_link) /MAP $** $(LIBS) $(MT) -manifest $(RSRC)\manifest.game.xml -hashupdate -outputresource:$@ -out:$@.manifest @@ -158,11 +161,16 @@ jaudiolib: nmake /f Makefile.msvc cd $(MAKEDIR) +enet: + cd $(ENETDIR) + nmake /f Makefile.msvc + cd $(MAKEDIR) AlwaysBuild: ; $(EOBJ)\$(EDITORLIB): editorlib ; $(EOBJ)\$(ENGINELIB): enginelib ; $(JAUDIOLIBDIR)\$(JAUDIOLIB): jaudiolib ; +$(ENETDIR)\$(ENETLIB): enet ; # PHONIES clean: @@ -170,6 +178,8 @@ clean: *.pdb *.map *.manifest cd $(JAUDIOLIBDIR) nmake /f Makefile.msvc clean + cd $(MAKEDIR)\$(ENETDIR) + nmake /f Makefile.msvc clean cd $(MAKEDIR) veryclean: clean diff --git a/polymer/eduke32/build/Makefile b/polymer/eduke32/build/Makefile index 73c7a2c6e..c814cf685 100644 --- a/polymer/eduke32/build/Makefile +++ b/polymer/eduke32/build/Makefile @@ -127,7 +127,7 @@ ENGINEOBJS+= \ $(OBJ)/textfont.$o \ $(OBJ)/smalltextfont.$o \ $(OBJ)/kplib.$o \ - $(OBJ)/fastlz.$o \ + $(OBJ)/quicklz.$o \ $(OBJ)/md4.$o \ $(OBJ)/osd.$o \ $(OBJ)/pragmas.$o \ diff --git a/polymer/eduke32/build/Makefile.deps b/polymer/eduke32/build/Makefile.deps index 642fb3c1c..042661455 100644 --- a/polymer/eduke32/build/Makefile.deps +++ b/polymer/eduke32/build/Makefile.deps @@ -10,14 +10,14 @@ $(OBJ)/config.$o: $(SRC)/config.c $(INC)/compat.h $(INC)/osd.h $(INC)/editor.h $(OBJ)/crc32.$o: $(SRC)/crc32.c $(INC)/crc32.h $(OBJ)/defs.$o: $(SRC)/defs.c $(INC)/build.h $(INC)/baselayer.h $(INC)/scriptfile.h $(INC)/compat.h $(OBJ)/engine.$o: $(SRC)/engine.c $(INC)/compat.h $(INC)/build.h $(INC)/pragmas.h $(INC)/cache1d.h $(INC)/a.h $(INC)/osd.h $(INC)/baselayer.h $(SRC)/engine_priv.h $(INC)/polymost.h $(INC)/hightile.h $(INC)/mdsprite.h $(INC)/polymer.h -$(OBJ)/polymost.$o: $(SRC)/polymost.c $(INC)/md4.h $(INC)/fastlz.h $(INC)/lzwnew.h $(SRC)/engine_priv.h $(INC)/polymost.h $(INC)/hightile.h $(INC)/mdsprite.h +$(OBJ)/polymost.$o: $(SRC)/polymost.c $(INC)/md4.h $(INC)/quicklz.h $(INC)/lzwnew.h $(SRC)/engine_priv.h $(INC)/polymost.h $(INC)/hightile.h $(INC)/mdsprite.h $(OBJ)/hightile.$o: $(SRC)/hightile.c $(INC)/kplib.h $(INC)/hightile.h $(OBJ)/mdsprite.$o: $(SRC)/mdsprite.c $(SRC)/engine_priv.h $(INC)/polymost.h $(INC)/hightile.h $(INC)/mdsprite.h $(OBJ)/textfont.$o: $(SRC)/textfont.c $(OBJ)/smalltextfont.$o: $(SRC)/smalltextfont.c $(OBJ)/glbuild.$o: $(SRC)/glbuild.c $(INC)/glbuild.h $(INC)/baselayer.h $(OBJ)/kplib.$o: $(SRC)/kplib.c $(INC)/compat.h -$(OBJ)/fastlz.$o: $(SRC)/fastlz.c $(INC)/fastlz.h +$(OBJ)/quicklz.$o: $(SRC)/quicklz.c $(INC)/quicklz.h $(OBJ)/lzwnew.$o: $(SRC)/lzwnew.c $(OBJ)/md4.$o: $(SRC)/md4.c $(INC)/md4.h $(INC)/compat.h $(OBJ)/mmulti_unstable.$o: $(SRC)/mmulti_unstable.c $(INC)/mmulti_unstable.h diff --git a/polymer/eduke32/build/Makefile.msvc b/polymer/eduke32/build/Makefile.msvc index 6332fbc66..685aa9d83 100644 --- a/polymer/eduke32/build/Makefile.msvc +++ b/polymer/eduke32/build/Makefile.msvc @@ -72,7 +72,7 @@ ENGINEOBJS= \ $(OBJ)\smalltextfont.$o \ $(OBJ)\glbuild.$o \ $(OBJ)\kplib.$o \ - $(OBJ)\fastlz.$o \ + $(OBJ)\quicklz.$o \ $(OBJ)\lzwnew.$o \ $(OBJ)\md4.$o \ $(OBJ)\mmulti_unstable.$o \ diff --git a/polymer/eduke32/build/Makefile.shared b/polymer/eduke32/build/Makefile.shared index 6e8cf5b18..8b3243215 100644 --- a/polymer/eduke32/build/Makefile.shared +++ b/polymer/eduke32/build/Makefile.shared @@ -3,8 +3,8 @@ ENGINELIB=libengine.a EDITORLIB=libbuild.a -SDLCONFIG = /usr/local/bin/sdl-config -# SDLCONFIG = sdl-config +# SDLCONFIG = /usr/local/bin/sdl-config +SDLCONFIG = sdl-config ifeq ($(wildcard $(SDLCONFIG)),$(SDLCONFIG)) SDLROOT = /usr/local diff --git a/polymer/eduke32/build/include/build.h b/polymer/eduke32/build/include/build.h index 6a385a806..1b43c1b76 100644 --- a/polymer/eduke32/build/include/build.h +++ b/polymer/eduke32/build/include/build.h @@ -40,7 +40,7 @@ extern "C" { #define MAXSPRITESONSCREEN 4096 #define MAXUNIQHUDID 256 //Extra slots so HUD models can store animation state without messing game sprites -#define RESERVEDPALS 2 // don't forget to increment this when adding reserved pals +#define RESERVEDPALS 4 // don't forget to increment this when adding reserved pals #define DETAILPAL (MAXPALOOKUPS - 1) #define GLOWPAL (MAXPALOOKUPS - 2) #define SPECULARPAL (MAXPALOOKUPS - 3) diff --git a/polymer/eduke32/build/include/compat.h b/polymer/eduke32/build/include/compat.h index 318ed8543..765e13e49 100644 --- a/polymer/eduke32/build/include/compat.h +++ b/polymer/eduke32/build/include/compat.h @@ -36,8 +36,9 @@ #endif #define USE_ALLOCATOR 1 -// #define REPLACE_SYSTEM_ALLOCATOR -#define USE_MAGIC_HEADERS 0 +#define USE_MAGIC_HEADERS 1 +#define ENABLE_FAST_HEAP_DETECTION 1 + #include "nedmalloc.h" #ifndef TRUE diff --git a/polymer/eduke32/build/include/fastlz.h b/polymer/eduke32/build/include/fastlz.h deleted file mode 100644 index f87bc7be3..000000000 --- a/polymer/eduke32/build/include/fastlz.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - FastLZ - lightning-fast lossless compression library - - Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) - Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) - Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -#ifndef FASTLZ_H -#define FASTLZ_H - -#define FASTLZ_VERSION 0x000100 - -#define FASTLZ_VERSION_MAJOR 0 -#define FASTLZ_VERSION_MINOR 0 -#define FASTLZ_VERSION_REVISION 0 - -#define FASTLZ_VERSION_STRING "0.1.0" - -#if defined (__cplusplus) -extern "C" { -#endif - -/** - Compress a block of data in the input buffer and returns the size of - compressed block. The size of input buffer is specified by length. The - minimum input buffer size is 16. - - The output buffer must be at least 5% larger than the input buffer - and can not be smaller than 66 bytes. - - If the input is not compressible, the return value might be larger than - length (input buffer size). - - The input buffer and the output buffer can not overlap. -*/ - -int fastlz_compress(const void* input, int length, void* output); - -/** - Decompress a block of compressed data and returns the size of the - decompressed block. If error occurs, e.g. the compressed data is - corrupted or the output buffer is not large enough, then 0 (zero) - will be returned instead. - - The input buffer and the output buffer can not overlap. - - Decompression is memory safe and guaranteed not to write the output buffer - more than what is specified in maxout. - */ - -int fastlz_decompress(const void* input, int length, void* output, int maxout); - -/** - Compress a block of data in the input buffer and returns the size of - compressed block. The size of input buffer is specified by length. The - minimum input buffer size is 16. - - The output buffer must be at least 5% larger than the input buffer - and can not be smaller than 66 bytes. - - If the input is not compressible, the return value might be larger than - length (input buffer size). - - The input buffer and the output buffer can not overlap. - - Compression level can be specified in parameter level. At the moment, - only level 1 and level 2 are supported. - Level 1 is the fastest compression and generally useful for short data. - Level 2 is slightly slower but it gives better compression ratio. - - Note that the compressed data, regardless of the level, can always be - decompressed using the function fastlz_decompress above. -*/ - -int fastlz_compress_level(int level, const void* input, int length, void* output); - -#if defined (__cplusplus) -} -#endif - -#endif /* FASTLZ_H */ diff --git a/polymer/eduke32/build/include/malloc.c.h b/polymer/eduke32/build/include/malloc.c.h index c26b6a97a..29455bd0c 100644 --- a/polymer/eduke32/build/include/malloc.c.h +++ b/polymer/eduke32/build/include/malloc.c.h @@ -502,7 +502,6 @@ MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP */ /* Version identifier to allow people to support multiple versions */ - #ifndef DLMALLOC_VERSION #define DLMALLOC_VERSION 20804 #endif /* DLMALLOC_VERSION */ @@ -1543,9 +1542,7 @@ unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); initialized in init_mparams. Note that the non-zeroness of "magic" also serves as an initialization flag. */ - -typedef unsigned int flag_t; /* The type of various bit flag sets */ - +typedef unsigned int flag_t; struct malloc_params { volatile size_t magic; size_t page_size; @@ -1634,16 +1631,14 @@ static void* lastWin32mmap; /* Used as a hint */ #endif /* DEFAULT_GRANULARITY_ALIGNED */ #ifdef ENABLE_LARGE_PAGES int largepagesavailable = 1; +#ifndef MEM_LARGE_PAGES + #define MEM_LARGE_PAGES 0x20000000 +#endif #endif /* ENABLE_LARGE_PAGES */ static FORCEINLINE void* win32mmap(size_t size) { void* baseaddress = 0; void* ptr = 0; #ifdef ENABLE_LARGE_PAGES - -#ifndef MEM_LARGE_PAGES - #define MEM_LARGE_PAGES 0x20000000 -#endif - /* Note that large pages are *always* allocated on a large page boundary. If however granularity is small then don't waste a kernel call if size isn't around the size of a large page */ @@ -1677,7 +1672,11 @@ static FORCEINLINE void* win32mmap(size_t size) { #endif } #if DEBUG +#ifdef ENABLE_LARGE_PAGES + printf("VirtualAlloc returns %p size %u. LargePagesAvailable=%d\n", ptr, size, largepagesavailable); +#else printf("VirtualAlloc returns %p size %u\n", ptr, size); +#endif #endif return (ptr != 0)? ptr: MFAIL; } @@ -1825,6 +1824,7 @@ static FORCEINLINE int win32munmap(void* ptr, size_t size) { /* Custom pthread-style spin locks on x86 and x64 for gcc */ struct pthread_mlock_t { volatile unsigned int l; + char cachelinepadding[64]; unsigned int c; pthread_t threadid; }; @@ -1836,7 +1836,7 @@ struct pthread_mlock_t { #define TRY_LOCK(sl) pthread_try_lock(sl) #define SPINS_PER_YIELD 63 -static MLOCK_T malloc_global_mutex = { 0, 0, 0}; +static MLOCK_T malloc_global_mutex = { 0, "", 0, 0}; static FORCEINLINE int pthread_acquire_lock (MLOCK_T *sl) { int spins = 0; @@ -1924,6 +1924,7 @@ static FORCEINLINE int pthread_try_lock (MLOCK_T *sl) { /* Custom win32-style spin locks on x86 and x64 for MSC */ struct win32_mlock_t { volatile long l; + char cachelinepadding[64]; unsigned int c; long threadid; }; diff --git a/polymer/eduke32/build/include/mmultimsgs.h b/polymer/eduke32/build/include/mmultimsgs.h deleted file mode 100644 index 9fb1adb87..000000000 --- a/polymer/eduke32/build/include/mmultimsgs.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef __MMULTIMSGS_H__ -#define __MMULTIMSGS_H__ - -/* - * Ok, so this header file defines the message bytes and outlines the basic - * message descriptions for out-of-band messages that are common to all games - * that utilize my net code. Once a game determines that it is indeed talking - * to another peer of the same genus, the rest is up to the game itself to - * decide, but for basic stuff, the interfaces will be identical. - * - * Why am I not choosing to implement all this engine-side? Because all the - * games are different and about the only thing they are guaranteed to use in - * common that I can be certain of is the services my net code will provide. - * So, since I can't code anything in particular with every Build game in mind, - * I'm putting handling all the game-visible messages into the game's domain. - * The engine will still handle its own internal messages because the game - * never sees them. Ever. - * - * CMDs are messages sent by a peer to another, and RSPs are the replies. - * - * The master of the network game, regardless if the eventual game is talking - * with a peer-to-peer design or not, shall enumerate each peer as it joins - * and the master will always assign itself peer number 0. This simplifies - * things all-round because each peer that joins automatically knows that - * id 0 is its master and it already knows the master's address. Technically - * every other peer who joins may get a sequential number for its id so maybe - * even transmitting the peer unique ids is unnecessary and we'd be easier - * just sending a number of players, but the less craftiness at this point - * in time, the better. - * - * -- Jonathon - */ - -#define MSGPROTOVER 0x00 - // 0x00 20031209 - - -#define MSG_CMD_GETGAMEINFO 0x10 - // char MSG_CMD_GETGAMEINFO - // char MSGPROTOVER -#define MSG_RSP_BADPROTO 0x11 - // char MSG_RSP_BADPROTO -#define MSG_RSP_NOGAME 0x12 - // char MSG_RSP_NOGAME - // char[8] gamename -#define MSG_RSP_GAMEINFO 0x13 - // char MSG_RSP_GAMEINFO - // char[8] gamename eg. DUKE3DSW/DUKE3D\x00\x00/DUKE3DAT - // ... other information particular to the game - - -#define MSG_CMD_JOINGAME 0x20 - // char MSG_CMD_JOINGAME -#define MSG_RSP_GAMEINPROG 0x21 - // char MSG_RSP_GAMEINPROG -#define MSG_RSP_JOINACCEPTED 0x22 - // char MSG_RSP_JOINACCEPTED - // short uniqueid - // char numtofollow - // short[numtofollow] peeruid - // ... other information particular to the game -#define MSG_RSP_GAMEFULL 0x23 - // char MSG_RSP_GAMEFULL - -#endif diff --git a/polymer/eduke32/build/include/nedmalloc.h b/polymer/eduke32/build/include/nedmalloc.h index 94c95e1d8..ff3320a12 100644 --- a/polymer/eduke32/build/include/nedmalloc.h +++ b/polymer/eduke32/build/include/nedmalloc.h @@ -32,8 +32,10 @@ DEALINGS IN THE SOFTWARE. /* See malloc.c.h for what each function does. -REPLACE_SYSTEM_ALLOCATOR causes nedalloc's functions to be called malloc, -free etc. instead of nedmalloc, nedfree etc. You may or may not want this. +REPLACE_SYSTEM_ALLOCATOR on POSIX causes nedalloc's functions to be called +malloc, free etc. instead of nedmalloc, nedfree etc. You may or may not want +this. On Windows it causes nedmalloc to patch all loaded DLLs and binaries +to replace usage of the system allocator. NO_NED_NAMESPACE prevents the functions from being defined in the nedalloc namespace when in C++ (uses the global namespace instead). @@ -51,25 +53,62 @@ to each block. nedpfree() and nedprealloc() can then automagically know when to free a system allocated block. Enabling this typically adds 20-50% to application memory usage. -USE_ALLOCATOR can be one of these settings: +ENABLE_TOLERANT_NEDMALLOC is automatically turned on if REPLACE_SYSTEM_ALLOCATOR +is set or the Windows DLL is being built. This causes nedmalloc to detect when a +system allocator block is passed to it and to handle it appropriately. Note that +without USE_MAGIC_HEADERS there is a very tiny chance that nedmalloc will segfault +on non-Windows builds (it uses Win32 SEH to trap segfaults on Windows and there +is no comparable system on POSIX). + +USE_ALLOCATOR can be one of these settings (it defaults to 1): 0: System allocator (nedmalloc now simply acts as a threadcache). WARNING: Intended for DEBUG USE ONLY - not all functions work correctly. 1: dlmalloc +ENABLE_LARGE_PAGES enables support for requesting memory from the system in large +(typically >=2Mb) pages if the host OS supports this. These occupy just a single +TLB entry and can significantly improve performance in large working set applications. + +ENABLE_FAST_HEAP_DETECTION enables special logic to detect blocks allocated +by the system heap. This avoids 1.5%-2% overhead when checking for non-nedmalloc +blocks, but it assumes that the NT and glibc heaps function in a very specific +fashion which may not hold true across OS upgrades. */ #include /* for size_t */ #ifndef NEDMALLOCEXTSPEC #ifdef NEDMALLOC_DLL_EXPORTS - #define NEDMALLOCEXTSPEC extern __declspec(dllexport) + #ifdef WIN32 + #define NEDMALLOCEXTSPEC extern __declspec(dllexport) + #elif defined(__GNUC__) + #define NEDMALLOCEXTSPEC extern __attribute__ ((visibility("default"))) + #endif + #ifndef ENABLE_TOLERANT_NEDMALLOC + #define ENABLE_TOLERANT_NEDMALLOC 1 + #endif #else #define NEDMALLOCEXTSPEC extern #endif #endif +#if __STDC_VERSION__ >= 199901L /* C99 or better */ + #define RESTRICT restrict +#else + #if defined(_MSC_VER) && _MSC_VER>=1400 + #define RESTRICT __restrict + #endif + #ifdef __GNUC__ + #define RESTRICT __restrict + #endif +#endif +#ifndef RESTRICT + #define RESTRICT +#endif + #if defined(_MSC_VER) && _MSC_VER>=1400 #define NEDMALLOCPTRATTR __declspec(restrict) + #define NEDMALLOCNOALIASATTR __declspec(noalias) #endif #ifdef __GNUC__ #define NEDMALLOCPTRATTR __attribute__ ((malloc)) @@ -77,6 +116,9 @@ USE_ALLOCATOR can be one of these settings: #ifndef NEDMALLOCPTRATTR #define NEDMALLOCPTRATTR #endif +#ifndef NEDMALLOCNOALIASATTR + #define NEDMALLOCNOALIASATTR +#endif #ifndef USE_MAGIC_HEADERS #define USE_MAGIC_HEADERS 0 @@ -94,7 +136,10 @@ USE_ALLOCATOR can be one of these settings: #if USE_ALLOCATOR==0 #error Cannot combine using the system allocator with replacing the system allocator #endif - #ifndef _WIN32 /* We have a dedidicated patcher for Windows */ + #ifndef ENABLE_TOLERANT_NEDMALLOC + #define ENABLE_TOLERANT_NEDMALLOC 1 + #endif + #ifndef WIN32 /* We have a dedicated patcher for Windows */ #define nedmalloc malloc #define nedcalloc calloc #define nedrealloc realloc @@ -107,23 +152,30 @@ USE_ALLOCATOR can be one of these settings: #define nedmalloc_footprint malloc_footprint #define nedindependent_calloc independent_calloc #define nedindependent_comalloc independent_comalloc + #ifdef _MSC_VER + #define nedblksize _msize + #endif #endif #endif - -#ifndef NO_MALLINFO - #define NO_MALLINFO 0 -#endif - -#if !NO_MALLINFO #if defined(__cplusplus) extern "C" { #endif -struct mallinfo; +struct nedmallinfo { + size_t arena; /* non-mmapped space allocated from system */ + size_t ordblks; /* number of free chunks */ + size_t smblks; /* always 0 */ + size_t hblks; /* always 0 */ + size_t hblkhd; /* space in mmapped regions */ + size_t usmblks; /* maximum total allocated space */ + size_t fsmblks; /* always 0 */ + size_t uordblks; /* total allocated space */ + size_t fordblks; /* total free space */ + size_t keepcost; /* releasable (via malloc_trim) space */ +}; #if defined(__cplusplus) } #endif -#endif #if defined(__cplusplus) #if !defined(NO_NED_NAMESPACE) @@ -139,11 +191,11 @@ extern "C" { /* These are the global functions */ /* Gets the usable size of an allocated block. Note this will always be bigger than what was -asked for due to rounding etc. Tries to return zero if this is not a nedmalloc block (though -one could see a segfault up to 6.25% of the time). On Win32 SEH is used to guarantee that a -segfault never happens. +asked for due to rounding etc. Optionally returns 1 in isforeign if the block came from the +system allocator - note that there is a small (>0.01%) but real chance of segfault on non-Windows +systems when passing non-nedmalloc blocks if you don't use USE_MAGIC_HEADERS. */ -NEDMALLOCEXTSPEC size_t nedblksize(void *mem) THROWSPEC; +NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR size_t nedblksize(int *RESTRICT isforeign, void *RESTRICT mem) THROWSPEC; NEDMALLOCEXTSPEC void nedsetvalue(void *v) THROWSPEC; @@ -152,9 +204,7 @@ NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedcalloc(size_t no, size_t size) THROW NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedrealloc(void *mem, size_t size) THROWSPEC; NEDMALLOCEXTSPEC void nedfree(void *mem) THROWSPEC; NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC; -#if !NO_MALLINFO -NEDMALLOCEXTSPEC struct mallinfo nedmallinfo(void) THROWSPEC; -#endif +NEDMALLOCEXTSPEC struct nedmallinfo nedmallinfo(void) THROWSPEC; NEDMALLOCEXTSPEC int nedmallopt(int parno, int value) THROWSPEC; NEDMALLOCEXTSPEC void* nedmalloc_internals(size_t *granularity, size_t *magic) THROWSPEC; NEDMALLOCEXTSPEC int nedmalloc_trim(size_t pad) THROWSPEC; @@ -187,12 +237,20 @@ NEDMALLOCEXTSPEC NEDMALLOCPTRATTR nedpool *nedcreatepool(size_t capacity, int th */ NEDMALLOCEXTSPEC void neddestroypool(nedpool *p) THROWSPEC; +/* Returns a zero terminated snapshot of threadpools existing at the time of call. Call +nedfree() on the returned list when you are done. Returns zero if there is only the +system pool in existence. +*/ +NEDMALLOCEXTSPEC nedpool **nedpoollist() THROWSPEC; + /* Sets a value to be associated with a pool. You can retrieve this value by passing any memory block allocated from that pool. */ NEDMALLOCEXTSPEC void nedpsetvalue(nedpool *p, void *v) THROWSPEC; + /* Gets a previously set value using nedpsetvalue() or zero if memory is unknown. -Optionally can also retrieve pool. +Optionally can also retrieve pool. You can detect an unknown block by the return +being zero and *p being unmodifed. */ NEDMALLOCEXTSPEC void *nedgetvalue(nedpool **p, void *mem) THROWSPEC; @@ -208,14 +266,13 @@ system pool. */ NEDMALLOCEXTSPEC void neddisablethreadcache(nedpool *p) THROWSPEC; + NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedpmalloc(nedpool *p, size_t size) THROWSPEC; NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC; NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPEC; NEDMALLOCEXTSPEC void nedpfree(nedpool *p, void *mem) THROWSPEC; NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC; -#if !NO_MALLINFO -NEDMALLOCEXTSPEC struct mallinfo nedpmallinfo(nedpool *p) THROWSPEC; -#endif +NEDMALLOCEXTSPEC struct nedmallinfo nedpmallinfo(nedpool *p) THROWSPEC; NEDMALLOCEXTSPEC int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC; NEDMALLOCEXTSPEC int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC; NEDMALLOCEXTSPEC void nedpmalloc_stats(nedpool *p) THROWSPEC; @@ -223,6 +280,7 @@ NEDMALLOCEXTSPEC size_t nedpmalloc_footprint(nedpool *p) THROWSPEC; NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_t elemsize, void **chunks) THROWSPEC; NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC; NEDMALLOCEXTSPEC NEDMALLOCPTRATTR char * nedstrdup(const char *str) THROWSPEC; + #if defined(__cplusplus) } #endif diff --git a/polymer/eduke32/build/include/quicklz.h b/polymer/eduke32/build/include/quicklz.h new file mode 100644 index 000000000..e004907b4 --- /dev/null +++ b/polymer/eduke32/build/include/quicklz.h @@ -0,0 +1,150 @@ +#ifndef QLZ_HEADER +#define QLZ_HEADER + +// Fast data compression library +// Copyright (C) 2006-2009 Lasse Mikkel Reinhold +// lar@quicklz.com +// +// QuickLZ can be used for free under the GPL-1 or GPL-2 license (where anything +// released into public must be open source) or under a commercial license if such +// has been acquired (see http://www.quicklz.com/order.html). The commercial license +// does not cover derived or ported versions created by third parties under GPL. + +// You can edit following user settings. Data must be decompressed with the same +// setting of QLZ_COMPRESSION_LEVEL and QLZ_STREAMING_BUFFER as it was compressed +// (see manual). If QLZ_STREAMING_BUFFER > 0, scratch buffers must be initially +// zeroed out (see manual). First #ifndef makes it possible to define settings from +// the outside like the compiler command line. + +// BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION +// BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION +// BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION +// BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION +// BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION + +// 1.5.0 BETA 2 + +#ifndef QLZ_COMPRESSION_LEVEL + #define QLZ_COMPRESSION_LEVEL 1 + //#define QLZ_COMPRESSION_LEVEL 2 + //#define QLZ_COMPRESSION_LEVEL 3 + + #define QLZ_STREAMING_BUFFER 0 + //#define QLZ_STREAMING_BUFFER 100000 + //#define QLZ_STREAMING_BUFFER 1000000 + + //#define QLZ_MEMORY_SAFE +#endif + +#define QLZ_VERSION_MAJOR 1 +#define QLZ_VERSION_MINOR 5 +#define QLZ_VERSION_REVISION 0 + +// Using size_t, memset() and memcpy() +#include + +// Verify compression level +#if QLZ_COMPRESSION_LEVEL != 1 && QLZ_COMPRESSION_LEVEL != 2 && QLZ_COMPRESSION_LEVEL != 3 +#error QLZ_COMPRESSION_LEVEL must be 1, 2 or 3 +#endif + +typedef unsigned int ui32; +typedef unsigned short int ui16; + +// Decrease QLZ_POINTERS for level 3 to increase compression speed. Do not touch any other values! +#if QLZ_COMPRESSION_LEVEL == 1 +#define QLZ_POINTERS 1 +#define QLZ_HASH_VALUES 4096 +#elif QLZ_COMPRESSION_LEVEL == 2 +#define QLZ_POINTERS 4 +#define QLZ_HASH_VALUES 2048 +#elif QLZ_COMPRESSION_LEVEL == 3 +#define QLZ_POINTERS 16 +#define QLZ_HASH_VALUES 4096 +#endif + +// Detect if pointer size is 64-bit. It's not fatal if some 64-bit target is not detected because this is only for adding an optional 64-bit optimization. +#if defined _LP64 || defined __LP64__ || defined __64BIT__ || _ADDR64 || defined _WIN64 || defined __arch64__ || __WORDSIZE == 64 || (defined __sparc && defined __sparcv9) || defined __x86_64 || defined __amd64 || defined __x86_64__ || defined _M_X64 || defined _M_IA64 || defined __ia64 || defined __IA64__ + #define QLZ_PTR_64 +#endif + +// hash entry +typedef struct +{ +#if QLZ_COMPRESSION_LEVEL == 1 + ui32 cache; +#if defined QLZ_PTR_64 && QLZ_STREAMING_BUFFER == 0 + unsigned int offset; +#else + const unsigned char *offset; +#endif +#else + const unsigned char *offset[QLZ_POINTERS]; +#endif + +} qlz_hash_compress; + +typedef struct +{ +#if QLZ_COMPRESSION_LEVEL == 1 + const unsigned char *offset; +#else + const unsigned char *offset[QLZ_POINTERS]; +#endif +} qlz_hash_decompress; + + +// states +typedef struct +{ + #if QLZ_STREAMING_BUFFER > 0 + unsigned char stream_buffer[QLZ_STREAMING_BUFFER]; + #endif + size_t stream_counter; + qlz_hash_compress hash[QLZ_HASH_VALUES]; + unsigned char hash_counter[QLZ_HASH_VALUES]; +} qlz_state_compress; + + +#if QLZ_COMPRESSION_LEVEL == 1 || QLZ_COMPRESSION_LEVEL == 2 + typedef struct + { +#if QLZ_STREAMING_BUFFER > 0 + unsigned char stream_buffer[QLZ_STREAMING_BUFFER]; +#endif + qlz_hash_decompress hash[QLZ_HASH_VALUES]; + unsigned char hash_counter[QLZ_HASH_VALUES]; + size_t stream_counter; + } qlz_state_decompress; +#elif QLZ_COMPRESSION_LEVEL == 3 + typedef struct + { +#if QLZ_STREAMING_BUFFER > 0 + unsigned char stream_buffer[QLZ_STREAMING_BUFFER]; +#endif + qlz_hash_decompress hash[QLZ_HASH_VALUES]; + size_t stream_counter; + } qlz_state_decompress; +#endif + + +#if defined (__cplusplus) +extern "C" { +#endif + +// Public functions of QuickLZ +size_t qlz_size_decompressed(const char *source); +size_t qlz_size_compressed(const char *source); +size_t qlz_compress(const void *source, char *destination, size_t size, qlz_state_compress *state); +size_t qlz_decompress(const char *source, void *destination, qlz_state_decompress *state); +int qlz_get_setting(int setting); + +extern qlz_state_compress *state_compress; +extern qlz_state_decompress *state_decompress; + +#if defined (__cplusplus) +} +#endif + +#endif + diff --git a/polymer/eduke32/build/src/defs.c b/polymer/eduke32/build/src/defs.c index c53e5c21d..4cc0d80ed 100644 --- a/polymer/eduke32/build/src/defs.c +++ b/polymer/eduke32/build/src/defs.c @@ -11,7 +11,7 @@ #include "scriptfile.h" #include "cache1d.h" #include "kplib.h" -#include "fastlz.h" +#include "quicklz.h" enum { @@ -677,7 +677,7 @@ static int32_t defsparser(scriptfile *script) tilesizx[tile] = xsiz; tilesizy[tile] = ysiz; - faketilesiz[tile] = fastlz_compress(ftd, xsiz*ysiz, faketiledata[tile]); + faketilesiz[tile] = qlz_compress(ftd, faketiledata[tile], xsiz*ysiz, state_compress); xoffset = clamp(xoffset, -128, 127); picanm[tile] = (picanm[tile]&0xffff00ff)+((xoffset&255)<<8); @@ -728,7 +728,7 @@ static int32_t defsparser(scriptfile *script) { tilesizx[tile] = xsiz; tilesizy[tile] = ysiz; - faketilesiz[tile] = fastlz_compress(ftd, xsiz*ysiz, faketiledata[tile]); + faketilesiz[tile] = qlz_compress(ftd, faketiledata[tile], xsiz*ysiz, state_compress); picanm[tile] = 0; j = 15; while ((j > 1) && (pow2long[j] > xsiz)) j--; diff --git a/polymer/eduke32/build/src/engine.c b/polymer/eduke32/build/src/engine.c index 54e114b71..4427ebaed 100644 --- a/polymer/eduke32/build/src/engine.c +++ b/polymer/eduke32/build/src/engine.c @@ -17,7 +17,7 @@ #include "a.h" #include "osd.h" #include "crc32.h" -#include "fastlz.h" +#include "quicklz.h" #include "baselayer.h" #include "scriptfile.h" @@ -132,6 +132,9 @@ int32_t circlewall=-1; char cachedebug = 0; +qlz_state_compress *state_compress = NULL; +qlz_state_decompress *state_decompress = NULL; + #if defined(_MSC_VER) && !defined(NOASM) // @@ -5493,6 +5496,9 @@ int32_t preinitengine(void) // this shite is to help get around data segment size limits on some platforms + state_compress = (qlz_state_compress *)Bmalloc(sizeof(qlz_state_compress)); + state_decompress = (qlz_state_decompress *)Bmalloc(sizeof(qlz_state_decompress)); + #ifdef DYNALLOC_ARRAYS sector = Bcalloc(MAXSECTORS,sizeof(sectortype)); wall = Bcalloc(MAXWALLS,sizeof(walltype)); @@ -5657,6 +5663,9 @@ void uninitengine(void) if (spritesmooth != NULL) Bfree(spritesmooth); #endif + + if (state_compress) Bfree(state_compress); + if (state_decompress) Bfree(state_decompress); } @@ -7967,7 +7976,7 @@ void loadtile(int16_t tilenume) if (faketilesiz[tilenume] == -1) Bmemset((char *)waloff[tilenume],0,dasiz); else if (faketiledata[tilenume] != NULL) - fastlz_decompress(faketiledata[tilenume], faketilesiz[tilenume], (char *)waloff[tilenume], dasiz); + qlz_decompress(faketiledata[tilenume], (char *)waloff[tilenume], state_decompress); faketimerhandler(); return; } diff --git a/polymer/eduke32/build/src/fastlz.c b/polymer/eduke32/build/src/fastlz.c deleted file mode 100644 index 3c9d6f6f8..000000000 --- a/polymer/eduke32/build/src/fastlz.c +++ /dev/null @@ -1,551 +0,0 @@ -/* - FastLZ - lightning-fast lossless compression library - - Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) - Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) - Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -#if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) - -/* - * Always check for bound when decompressing. - * Generally it is best to leave it defined. - */ -#define FASTLZ_SAFE - -/* - * Give hints to the compiler for branch prediction optimization. - */ -#if defined(__GNUC__) && (__GNUC__ > 2) -#define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1)) -#define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0)) -#else -#define FASTLZ_EXPECT_CONDITIONAL(c) (c) -#define FASTLZ_UNEXPECT_CONDITIONAL(c) (c) -#endif - -/* - * Use inlined functions for supported systems. - */ -#if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C) -#define FASTLZ_INLINE inline -#elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__) -#define FASTLZ_INLINE __inline -#else -#define FASTLZ_INLINE -#endif - -/* - * Prevent accessing more than 8-bit at once, except on x86 architectures. - */ -#if !defined(FASTLZ_STRICT_ALIGN) -#define FASTLZ_STRICT_ALIGN -#if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */ -#undef FASTLZ_STRICT_ALIGN -#elif defined(__i486__) || defined(__i586__) || defined(__i686__) /* GNU C */ -#undef FASTLZ_STRICT_ALIGN -#elif defined(_M_IX86) /* Intel, MSVC */ -#undef FASTLZ_STRICT_ALIGN -#elif defined(__386) -#undef FASTLZ_STRICT_ALIGN -#elif defined(_X86_) /* MinGW */ -#undef FASTLZ_STRICT_ALIGN -#elif defined(__I86__) /* Digital Mars */ -#undef FASTLZ_STRICT_ALIGN -#endif -#endif - -/* - * FIXME: use preprocessor magic to set this on different platforms! - */ -typedef unsigned char flzuint8; -typedef unsigned short flzuint16; -typedef unsigned int flzuint32; - -/* prototypes */ -int fastlz_compress(const void* input, int length, void* output); -int fastlz_compress_level(int level, const void* input, int length, void* output); -int fastlz_decompress(const void* input, int length, void* output, int maxout); - -#define MAX_COPY 32 -#define MAX_LEN 264 /* 256 + 8 */ -#define MAX_DISTANCE 8192 - -#if !defined(FASTLZ_STRICT_ALIGN) -#define FASTLZ_READU16(p) *((const flzuint16*)(p)) -#else -#define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8) -#endif - -#define HASH_LOG 13 -#define HASH_SIZE (1<< HASH_LOG) -#define HASH_MASK (HASH_SIZE-1) -#define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; } - -#undef FASTLZ_LEVEL -#define FASTLZ_LEVEL 1 - -#undef FASTLZ_COMPRESSOR -#undef FASTLZ_DECOMPRESSOR -#define FASTLZ_COMPRESSOR fastlz1_compress -#define FASTLZ_DECOMPRESSOR fastlz1_decompress -static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); -static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); -#include "fastlz.c" - -#undef FASTLZ_LEVEL -#define FASTLZ_LEVEL 2 - -#undef MAX_DISTANCE -#define MAX_DISTANCE 8191 -#define MAX_FARDISTANCE (65535+MAX_DISTANCE-1) - -#undef FASTLZ_COMPRESSOR -#undef FASTLZ_DECOMPRESSOR -#define FASTLZ_COMPRESSOR fastlz2_compress -#define FASTLZ_DECOMPRESSOR fastlz2_decompress -static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); -static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); -#include "fastlz.c" - -int fastlz_compress(const void* input, int length, void* output) -{ - /* for short block, choose fastlz1 */ - if(length < 65536) - return fastlz1_compress(input, length, output); - - /* else... */ - return fastlz2_compress(input, length, output); -} - -int fastlz_decompress(const void* input, int length, void* output, int maxout) -{ - /* magic identifier for compression level */ - int level = ((*(const flzuint8*)input) >> 5) + 1; - - if(level == 1) - return fastlz1_decompress(input, length, output, maxout); - if(level == 2) - return fastlz2_decompress(input, length, output, maxout); - - /* unknown level, trigger error */ - return 0; -} - -int fastlz_compress_level(int level, const void* input, int length, void* output) -{ - if(level == 1) - return fastlz1_compress(input, length, output); - if(level == 2) - return fastlz2_compress(input, length, output); - - return 0; -} - -#else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ - -static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output) -{ - const flzuint8* ip = (const flzuint8*) input; - const flzuint8* ip_bound = ip + length - 2; - const flzuint8* ip_limit = ip + length - 12; - flzuint8* op = (flzuint8*) output; - - const flzuint8* htab[HASH_SIZE]; - const flzuint8** hslot; - flzuint32 hval; - - flzuint32 copy; - - /* sanity check */ - if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4)) - { - if(length) - { - /* create literal copy only */ - *op++ = length-1; - ip_bound++; - while(ip <= ip_bound) - *op++ = *ip++; - return length+1; - } - else - return 0; - } - - /* initializes hash table */ - for (hslot = htab; hslot < htab + HASH_SIZE; hslot++) - *hslot = ip; - - /* we start with literal copy */ - copy = 2; - *op++ = MAX_COPY-1; - *op++ = *ip++; - *op++ = *ip++; - - /* main loop */ - while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) - { - const flzuint8* ref; - flzuint32 distance; - - /* minimum match length */ - flzuint32 len = 3; - - /* comparison starting-point */ - const flzuint8* anchor = ip; - - /* check for a run */ -#if FASTLZ_LEVEL==2 - if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1)) - { - distance = 1; - ip += 3; - ref = anchor - 1 + 3; - goto match; - } -#endif - - /* find potential match */ - HASH_FUNCTION(hval,ip); - hslot = htab + hval; - ref = htab[hval]; - - /* calculate distance to the match */ - distance = anchor - ref; - - /* update hash table */ - *hslot = anchor; - - /* is this a match? check the first 3 bytes */ - if(distance==0 || -#if FASTLZ_LEVEL==1 - (distance >= MAX_DISTANCE) || -#else - (distance >= MAX_FARDISTANCE) || -#endif - *ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++) - goto literal; - -#if FASTLZ_LEVEL==2 - /* far, needs at least 5-byte match */ - if(distance >= MAX_DISTANCE) - { - if(*ip++ != *ref++ || *ip++!= *ref++) - goto literal; - len += 2; - } - - match: -#endif - - /* last matched byte */ - ip = anchor + len; - - /* distance is biased */ - distance--; - - if(!distance) - { - /* zero distance means a run */ - flzuint8 x = ip[-1]; - while(ip < ip_bound) - if(*ref++ != x) break; else ip++; - } - else - for(;;) - { - /* safe because the outer check against ip limit */ - if(*ref++ != *ip++) break; - if(*ref++ != *ip++) break; - if(*ref++ != *ip++) break; - if(*ref++ != *ip++) break; - if(*ref++ != *ip++) break; - if(*ref++ != *ip++) break; - if(*ref++ != *ip++) break; - if(*ref++ != *ip++) break; - while(ip < ip_bound) - if(*ref++ != *ip++) break; - break; - } - - /* if we have copied something, adjust the copy count */ - if(copy) - /* copy is biased, '0' means 1 byte copy */ - *(op-copy-1) = copy-1; - else - /* back, to overwrite the copy count */ - op--; - - /* reset literal counter */ - copy = 0; - - /* length is biased, '1' means a match of 3 bytes */ - ip -= 3; - len = ip - anchor; - - /* encode the match */ -#if FASTLZ_LEVEL==2 - if(distance < MAX_DISTANCE) - { - if(len < 7) - { - *op++ = (len << 5) + (distance >> 8); - *op++ = (distance & 255); - } - else - { - *op++ = (7 << 5) + (distance >> 8); - for(len-=7; len >= 255; len-= 255) - *op++ = 255; - *op++ = len; - *op++ = (distance & 255); - } - } - else - { - /* far away, but not yet in the another galaxy... */ - if(len < 7) - { - distance -= MAX_DISTANCE; - *op++ = (len << 5) + 31; - *op++ = 255; - *op++ = distance >> 8; - *op++ = distance & 255; - } - else - { - distance -= MAX_DISTANCE; - *op++ = (7 << 5) + 31; - for(len-=7; len >= 255; len-= 255) - *op++ = 255; - *op++ = len; - *op++ = 255; - *op++ = distance >> 8; - *op++ = distance & 255; - } - } -#else - - if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2)) - while(len > MAX_LEN-2) - { - *op++ = (7 << 5) + (distance >> 8); - *op++ = MAX_LEN - 2 - 7 -2; - *op++ = (distance & 255); - len -= MAX_LEN-2; - } - - if(len < 7) - { - *op++ = (len << 5) + (distance >> 8); - *op++ = (distance & 255); - } - else - { - *op++ = (7 << 5) + (distance >> 8); - *op++ = len - 7; - *op++ = (distance & 255); - } -#endif - - /* update the hash at match boundary */ - HASH_FUNCTION(hval,ip); - htab[hval] = ip++; - HASH_FUNCTION(hval,ip); - htab[hval] = ip++; - - /* assuming literal copy */ - *op++ = MAX_COPY-1; - - continue; - - literal: - *op++ = *anchor++; - ip = anchor; - copy++; - if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) - { - copy = 0; - *op++ = MAX_COPY-1; - } - } - - /* left-over as literal copy */ - ip_bound++; - while(ip <= ip_bound) - { - *op++ = *ip++; - copy++; - if(copy == MAX_COPY) - { - copy = 0; - *op++ = MAX_COPY-1; - } - } - - /* if we have copied something, adjust the copy length */ - if(copy) - *(op-copy-1) = copy-1; - else - op--; - -#if FASTLZ_LEVEL==2 - /* marker for fastlz2 */ - *(flzuint8*)output |= (1 << 5); -#endif - - return op - (flzuint8*)output; -} - -static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout) -{ - const flzuint8* ip = (const flzuint8*) input; - const flzuint8* ip_limit = ip + length; - flzuint8* op = (flzuint8*) output; - flzuint8* op_limit = op + maxout; - flzuint32 ctrl = (*ip++) & 31; - int loop = 1; - - do - { - const flzuint8* ref = op; - flzuint32 len = ctrl >> 5; - flzuint32 ofs = (ctrl & 31) << 8; - - if(ctrl >= 32) - { -#if FASTLZ_LEVEL==2 - flzuint8 code; -#endif - len--; - ref -= ofs; - if (len == 7-1) -#if FASTLZ_LEVEL==1 - len += *ip++; - ref -= *ip++; -#else - do - { - code = *ip++; - len += code; - } while (code==255); - code = *ip++; - ref -= code; - - /* match from 16-bit distance */ - if(FASTLZ_UNEXPECT_CONDITIONAL(code==255)) - if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8))) - { - ofs = (*ip++) << 8; - ofs += *ip++; - ref = op - ofs - MAX_DISTANCE; - } -#endif - -#ifdef FASTLZ_SAFE - if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit)) - return 0; - - if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output)) - return 0; -#endif - - if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) - ctrl = *ip++; - else - loop = 0; - - if(ref == op) - { - /* optimize copy for a run */ - flzuint8 b = ref[-1]; - *op++ = b; - *op++ = b; - *op++ = b; - for(; len; --len) - *op++ = b; - } - else - { -#if !defined(FASTLZ_STRICT_ALIGN) - const flzuint16* p; - flzuint16* q; -#endif - /* copy from reference */ - ref--; - *op++ = *ref++; - *op++ = *ref++; - *op++ = *ref++; - -#if !defined(FASTLZ_STRICT_ALIGN) - /* copy a byte, so that now it's word aligned */ - if(len & 1) - { - *op++ = *ref++; - len--; - } - - /* copy 16-bit at once */ - q = (flzuint16*) op; - op += len; - p = (const flzuint16*) ref; - for(len>>=1; len > 4; len-=4) - { - *q++ = *p++; - *q++ = *p++; - *q++ = *p++; - *q++ = *p++; - } - for(; len; --len) - *q++ = *p++; -#else - for(; len; --len) - *op++ = *ref++; -#endif - } - } - else - { - ctrl++; -#ifdef FASTLZ_SAFE - if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit)) - return 0; - if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit)) - return 0; -#endif - - *op++ = *ip++; - for(--ctrl; ctrl; ctrl--) - *op++ = *ip++; - - loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit); - if(loop) - ctrl = *ip++; - } - } - while(FASTLZ_EXPECT_CONDITIONAL(loop)); - - return op - (flzuint8*)output; -} - -#endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ diff --git a/polymer/eduke32/build/src/hightile.c b/polymer/eduke32/build/src/hightile.c index d154e2a33..861be5a49 100644 --- a/polymer/eduke32/build/src/hightile.c +++ b/polymer/eduke32/build/src/hightile.c @@ -22,26 +22,23 @@ char hicfirstinit = 0; // hicreplctyp * hicfindsubst(int32_t picnum, int32_t palnum, int32_t skybox) { - hicreplctyp *hr; - - if (!hicfirstinit) return NULL; - if ((uint32_t)picnum >= (uint32_t)MAXTILES) return NULL; + if (!hicfirstinit || (uint32_t)picnum >= (uint32_t)MAXTILES) return NULL; do { - for (hr = hicreplc[picnum]; hr; hr = hr->next) + if (skybox) { - if (hr->palnum == palnum) - { - if (skybox) - { - if (hr->skybox && !hr->skybox->ignore) return hr; - } - else - { - if (!hr->ignore) return hr; - } - } + hicreplctyp *hr = hicreplc[picnum]; + for (; hr; hr = hr->next) + if (hr->palnum == palnum && hr->skybox && !hr->skybox->ignore) + return hr; + } + else + { + hicreplctyp *hr = hicreplc[picnum]; + for (; hr; hr = hr->next) + if (hr->palnum == palnum && !hr->ignore) + return hr; } if (!palnum || palnum >= (MAXPALOOKUPS - RESERVEDPALS)) break; diff --git a/polymer/eduke32/build/src/nedmalloc.c b/polymer/eduke32/build/src/nedmalloc.c index d8b8738b5..9c9cc6dfa 100644 --- a/polymer/eduke32/build/src/nedmalloc.c +++ b/polymer/eduke32/build/src/nedmalloc.c @@ -35,20 +35,25 @@ DEALINGS IN THE SOFTWARE. #pragma warning(disable:4706) /* assignment within conditional expression */ #endif -/*#define FULLSANITYCHECKS*/ #define USE_ALLOCATOR 1 -// #define REPLACE_SYSTEM_ALLOCATOR -#define USE_MAGIC_HEADERS 0 +#define USE_MAGIC_HEADERS 1 #define MAXTHREADSINPOOL 1 #define FINEGRAINEDBINS 1 -#define ENABLE_LARGE_PAGES +#define ENABLE_LARGE_PAGES 1 +#define ENABLE_FAST_HEAP_DETECTION 1 -#ifndef UNREFERENCED_PARAMETER -#define UNREFERENCED_PARAMETER(x) x=x +/*#define ENABLE_TOLERANT_NEDMALLOC 1*/ +/*#define ENABLE_FAST_HEAP_DETECTION 1*/ + +/*#define FULLSANITYCHECKS*/ +/* If link time code generation is on, don't force or prevent inlining */ +#if defined(_MSC_VER) && defined(NEDMALLOC_DLL_EXPORTS) +#define FORCEINLINE +#define NOINLINE #endif #include "nedmalloc.h" -#ifdef _WIN32 +#ifdef WIN32 #include #include #endif @@ -85,7 +90,6 @@ DEALINGS IN THE SOFTWARE. /*#define USE_SPIN_LOCKS 0*/ -/*#define FORCEINLINE*/ #include "malloc.c.h" #ifdef NDEBUG /* Disable assert checking on release builds */ #undef DEBUG @@ -118,7 +122,8 @@ DEALINGS IN THE SOFTWARE. #define THREADCACHEMAXFREESPACE (512*1024*4) #endif -#ifdef _WIN32 + +#ifdef WIN32 #define TLSVAR DWORD #define TLSALLOC(k) (*(k)=TlsAlloc(), TLS_OUT_OF_INDEXES==*(k)) #define TLSFREE(k) (!TlsFree(k)) @@ -159,11 +164,14 @@ static void *unsupported_operation(const char *opname) THROWSPEC } static size_t mspacecounter=(size_t) 0xdeadbeef; #endif +#ifndef ENABLE_FAST_HEAP_DETECTION +static void *RESTRICT leastusedaddress; +static size_t largestusedblock; +#endif -static FORCEINLINE void *CallMalloc(void *mspace, size_t size, size_t alignment) THROWSPEC +static FORCEINLINE void *CallMalloc(void *RESTRICT mspace, size_t size, size_t alignment) THROWSPEC { - void *ret=0; - UNREFERENCED_PARAMETER(alignment); + void *RESTRICT ret=0; #if USE_MAGIC_HEADERS size_t *_ret=0; size+=alignment+3*sizeof(size_t); @@ -172,6 +180,14 @@ static FORCEINLINE void *CallMalloc(void *mspace, size_t size, size_t alignment) ret=malloc(size); #elif USE_ALLOCATOR==1 ret=mspace_malloc((mstate) mspace, size); +#ifndef ENABLE_FAST_HEAP_DETECTION + if(ret) + { + size_t truesize=chunksize(mem2chunk(ret)); + if(!leastusedaddress || (void *)((mstate) mspace)->least_addrleast_addr; + if(!largestusedblock || truesize>largestusedblock) largestusedblock=(truesize+mparams.page_size) & ~(mparams.page_size-1); + } +#endif #endif if(!ret) return 0; #if USE_MAGIC_HEADERS @@ -180,23 +196,30 @@ static FORCEINLINE void *CallMalloc(void *mspace, size_t size, size_t alignment) if(alignment) ret=(void *)(((size_t) ret+alignment-1)&~(alignment-1)); for(; _ret<(size_t *)ret-2; _ret++) *_ret=*(size_t *)"NEDMALOC"; _ret[0]=(size_t) mspace; - _ret[1]=size; + _ret[1]=size-3*sizeof(size_t); #endif return ret; } -static FORCEINLINE void *CallCalloc(void *mspace, size_t no, size_t size, size_t alignment) THROWSPEC +static FORCEINLINE void *CallCalloc(void *RESTRICT mspace, size_t size, size_t alignment) THROWSPEC { - void *ret=0; - UNREFERENCED_PARAMETER(alignment); + void *RESTRICT ret=0; #if USE_MAGIC_HEADERS size_t *_ret=0; size+=alignment+3*sizeof(size_t); #endif #if USE_ALLOCATOR==0 - ret=calloc(no, size); + ret=calloc(1, size); #elif USE_ALLOCATOR==1 - ret=mspace_calloc((mstate) mspace, no, size); + ret=mspace_calloc((mstate) mspace, 1, size); +#ifndef ENABLE_FAST_HEAP_DETECTION + if(ret) + { + size_t truesize=chunksize(mem2chunk(ret)); + if(!leastusedaddress || (void *)((mstate) mspace)->least_addrleast_addr; + if(!largestusedblock || truesize>largestusedblock) largestusedblock=(truesize+mparams.page_size) & ~(mparams.page_size-1); + } +#endif #endif if(!ret) return 0; #if USE_MAGIC_HEADERS @@ -205,39 +228,52 @@ static FORCEINLINE void *CallCalloc(void *mspace, size_t no, size_t size, size_t if(alignment) ret=(void *)(((size_t) ret+alignment-1)&~(alignment-1)); for(; _ret<(size_t *)ret-2; _ret++) *_ret=*(size_t *) "NEDMALOC"; _ret[0]=(size_t) mspace; - _ret[1]=size; + _ret[1]=size-3*sizeof(size_t); #endif return ret; } -static FORCEINLINE void *CallRealloc(void *mspace, void *mem, size_t size) THROWSPEC +static FORCEINLINE void *CallRealloc(void *RESTRICT mspace, void *RESTRICT mem, int isforeign, size_t oldsize, size_t newsize) THROWSPEC { - void *ret=0; + void *RESTRICT ret=0; #if USE_MAGIC_HEADERS mstate oldmspace=0; - size_t *_ret=0, *_mem=(size_t *) mem-3, oldsize=0; - if(_mem[0]!=*(size_t *) "NEDMALOC") + size_t *_ret=0, *_mem=(size_t *) mem-3; +#endif + if(isforeign) { /* Transfer */ - if((ret=CallMalloc(mspace, size, 0))) - { /* It's probably safe to copy size bytes from mem - can't do much different */ +#if USE_MAGIC_HEADERS + assert(_mem[0]!=*(size_t *) "NEDMALOC"); +#endif + if((ret=CallMalloc(mspace, newsize, 0))) + { #if defined(DEBUG) printf("*** nedmalloc frees system allocated block %p\n", mem); #endif - memcpy(ret, mem, size); + memcpy(ret, mem, oldsize=_mem[2]); + for(; *_mem==*(size_t *) "NEDMALOC"; *_mem--=*(size_t *) "nedmaloc"); mem=(void *)(++_mem); #endif #if USE_ALLOCATOR==0 - ret=realloc(mem, size); + ret=realloc(mem, newsize); #elif USE_ALLOCATOR==1 - ret=mspace_realloc((mstate) mspace, mem, size); + ret=mspace_realloc((mstate) mspace, mem, newsize); +#ifndef ENABLE_FAST_HEAP_DETECTION + if(ret) + { + size_t truesize=chunksize(mem2chunk(ret)); + if(!largestusedblock || truesize>largestusedblock) largestusedblock=(truesize+mparams.page_size) & ~(mparams.page_size-1); + } +#endif #endif if(!ret) { /* Put it back the way it was */ @@ -251,27 +287,33 @@ static FORCEINLINE void *CallRealloc(void *mspace, void *mem, size_t size) THROW ret=(void *)(_ret+3); for(; _ret<(size_t *)ret-2; _ret++) *_ret=*(size_t *) "NEDMALOC"; _ret[0]=(size_t) mspace; - _ret[1]=size; + _ret[1]=newsize-3*sizeof(size_t); #endif return ret; } -static FORCEINLINE void CallFree(void *mspace, void *mem) THROWSPEC +static FORCEINLINE void CallFree(void *RESTRICT mspace, void *RESTRICT mem, int isforeign) THROWSPEC { #if USE_MAGIC_HEADERS mstate oldmspace=0; size_t *_mem=(size_t *) mem-3, oldsize=0; - if(_mem[0]!=*(size_t *) "NEDMALOC") +#endif + if(isforeign) { +#if USE_MAGIC_HEADERS + assert(_mem[0]!=*(size_t *) "NEDMALOC"); +#endif #if defined(DEBUG) printf("*** nedmalloc frees system allocated block %p\n", mem); #endif free(mem); return; } +#if USE_MAGIC_HEADERS + assert(_mem[0]==*(size_t *) "NEDMALOC"); oldmspace=(mstate) _mem[1]; oldsize=_mem[2]; - for(; *_mem==*(size_t *) "NEDMALOC"; *_mem--=0); + for(; *_mem==*(size_t *) "NEDMALOC"; *_mem--=*(size_t *) "nedmaloc"); mem=(void *)(++_mem); #endif #if USE_ALLOCATOR==0 @@ -281,7 +323,7 @@ static FORCEINLINE void CallFree(void *mspace, void *mem) THROWSPEC #endif } -size_t nedblksize(void *mem) THROWSPEC +static NEDMALLOCNOALIASATTR mstate nedblkmstate(void *RESTRICT mem) THROWSPEC { if(mem) { @@ -289,9 +331,7 @@ size_t nedblksize(void *mem) THROWSPEC size_t *_mem=(size_t *) mem-3; if(_mem[0]==*(size_t *) "NEDMALOC") { -// mstate mspace=(mstate) _mem[1]; - size_t size=_mem[2]; - return size-3*sizeof(size_t); + return (mstate) _mem[1]; } else return 0; #else @@ -299,6 +339,58 @@ size_t nedblksize(void *mem) THROWSPEC /* Fail everything */ return 0; #elif USE_ALLOCATOR==1 +#ifdef ENABLE_FAST_HEAP_DETECTION +#ifdef WIN32 + /* On Windows for RELEASE both x86 and x64 the NT heap precedes each block with an eight byte header + which looks like: + normal: 4 bytes of size, 4 bytes of [char < 64, char < 64, char < 64 bit 0 always set, char random ] + mmaped: 4 bytes of size 4 bytes of [zero, zero, 0xb, zero ] + + On Windows for DEBUG both x86 and x64 the preceding four bytes is always 0xfdfdfdfd (no man's land). + */ +#pragma pack(push, 1) + struct _HEAP_ENTRY + { + USHORT Size; + USHORT PreviousSize; + UCHAR Cookie; /* SegmentIndex */ + UCHAR Flags; /* always bit 0 (HEAP_ENTRY_BUSY). bit 1=(HEAP_ENTRY_EXTRA_PRESENT), bit 2=normal block (HEAP_ENTRY_FILL_PATTERN), bit 3=mmap block (HEAP_ENTRY_VIRTUAL_ALLOC). Bit 4 (HEAP_ENTRY_LAST_ENTRY) could be set */ + UCHAR UnusedBytes; + UCHAR SmallTagIndex; /* fastbin index. Always one of 0x02, 0x03, 0x04 < 0x80 */ + } *RESTRICT he=((struct _HEAP_ENTRY *) mem)-1; +#pragma pack(pop) + unsigned int header=((unsigned int *)mem)[-1], mask1=0x8080E100, result1, mask2=0xFFFFFF06, result2; + result1=header & mask1; /* Positive testing for NT heap */ + result2=header & mask2; /* Positive testing for dlmalloc */ + if(result1==0x00000100 && result2!=0x00000102) + { /* This is likely a NT heap block */ + return 0; + } +#endif +#ifdef __linux__ + /* On Linux glibc uses ptmalloc2 (really dlmalloc) just as we do, but prev_foot contains rubbish + when the preceding block is allocated because ptmalloc2 finds the local mstate by rounding the ptr + down to the nearest megabyte. It's like dlmalloc with FOOTERS disabled. */ + mchunkptr p=mem2chunk(mem); + mstate fm=get_mstate_for(p); + /* If it's a ptmalloc2 block, fm is likely to be some crazy value */ + if(!is_aligned(fm)) return 0; + if((size_t)mem-(size_t)fm>=(size_t)1<<(SIZE_T_BITSIZE-1)) return 0; + if(ok_magic(fm)) + return fm; + else + return 0; + if(1) { } +#endif + else + { + mchunkptr p=mem2chunk(mem); + mstate fm=get_mstate_for(p); + assert(ok_magic(fm)); /* If this fails, someone tried to free a block twice */ + if(ok_magic(fm)) + return fm; + } +#else #ifdef _MSC_VER __try #endif @@ -309,44 +401,109 @@ size_t nedblksize(void *mem) THROWSPEC mchunkptr->prev_foot = mem-(2*size_t) = mstate ^ mparams.magic for PRECEDING block; mchunkptr->head = mem-(1*size_t) = 8 multiple size of this block with bottom three bits = FLAG_BITS + FLAG_BITS = bit 0 is CINUSE (currently in use unless is mmap), bit 1 is PINUSE (previous block currently + in use unless mmap), bit 2 is UNUSED and currently is always zero. */ - mchunkptr p=mem2chunk(mem); - mstate fm=0; - if(!is_inuse(p)) return 0; - /* The following isn't safe but is probably true: unlikely to allocate - a 2Gb block on a 32bit system or a 8Eb block on a 64 bit system */ - if(p->head & ((size_t)1)<<(SIZE_T_BITSIZE-SIZE_T_ONE)) return 0; - /* We have now reduced our chances of being wrong to 0.5^4 = 6.25%. - We could start comparing prev_foot's for similarity but it starts getting slow. */ - fm = get_mstate_for(p); - assert(ok_magic(fm)); /* If this fails, someone tried to free a block twice */ - if(ok_magic(fm)) - return chunksize(p)-overhead_for(p); + register void *RESTRICT leastusedaddress_=leastusedaddress; /* Cache these to avoid register reloading */ + register size_t largestusedblock_=largestusedblock; + if(!is_aligned(mem)) return 0; /* Would fail very rarely as all allocators return aligned blocks */ + if(memhead & FLAG4_BIT)) return 0; + /* Reduced uncertainty by 0.5^2 = 25.0% */ + /* size should never exceed largestusedblock */ + if(chunksize(p)>largestusedblock_) return 0; + /* Reduced uncertainty by a minimum of 0.5^3 = 12.5%, maximum 0.5^16 = 0.0015% */ + /* Having sanity checked prev_foot and head, check next block */ + if(!ismmapped && (!next_pinuse(p) || (next_chunk(p)->head & FLAG4_BIT))) return 0; + /* Reduced uncertainty by 0.5^5 = 3.13% or 0.5^18 = 0.00038% */ + #if 0 + /* If previous block is free, check that its next block pointer equals us */ + if(!ismmapped && !pinuse(p)) + if(next_chunk(prev_chunk(p))!=p) return 0; + /* We could start comparing prev_foot's for similarity but it starts getting slow. */ + #endif + fm = get_mstate_for(p); + if(!is_aligned(fm) || (void *)fm=(size_t)1<<(SIZE_T_BITSIZE-1)) return 0; + assert(ok_magic(fm)); /* If this fails, someone tried to free a block twice */ + if(ok_magic(fm)) + return fm; + } } #ifdef _MSC_VER __except(1) { } #endif #endif +#endif +#endif + } + return 0; +} +NEDMALLOCNOALIASATTR size_t nedblksize(int *RESTRICT isforeign, void *RESTRICT mem) THROWSPEC +{ + if(mem) + { + if(isforeign) *isforeign=1; +#if USE_MAGIC_HEADERS + { + size_t *_mem=(size_t *) mem-3; + if(_mem[0]==*(size_t *) "NEDMALOC") + { + mstate mspace=(mstate) _mem[1]; + size_t size=_mem[2]; + if(isforeign) *isforeign=0; + return size; + } + } +#elif USE_ALLOCATOR==1 + if(nedblkmstate(mem)) + { + mchunkptr p=mem2chunk(mem); + if(isforeign) *isforeign=0; + return chunksize(p)-overhead_for(p); + } +#ifdef DEBUG + else + { + int a=1; /* Set breakpoints here if needed */ + } +#endif +#endif +#if defined(ENABLE_TOLERANT_NEDMALLOC) || USE_ALLOCATOR==0 +#ifdef WIN32 + /* This is the MSVCRT equivalent */ + return _msize(mem); +#elif defined(__linux__) + /* This is the glibc/ptmalloc2/dlmalloc equivalent. */ + return malloc_usable_size(mem); +#elif defined(__FreeBSD__) || defined(__APPLE__) + /* This is the BSD libc equivalent. */ + return malloc_size(mem); +#else +#error Cannot tolerate the memory allocator of an unknown system! +#endif #endif } return 0; } -void nedsetvalue(void *v) THROWSPEC { nedpsetvalue((nedpool *) 0, v); } -NEDMALLOCPTRATTR void * nedmalloc(size_t size) THROWSPEC { return nedpmalloc((nedpool *) 0, size); } -NEDMALLOCPTRATTR void * nedcalloc(size_t no, size_t size) THROWSPEC { return nedpcalloc((nedpool *) 0, no, size); } -NEDMALLOCPTRATTR void * nedrealloc(void *mem, size_t size) THROWSPEC { return nedprealloc((nedpool *) 0, mem, size); } -void nedfree(void *mem) THROWSPEC { nedpfree((nedpool *) 0, mem); } -NEDMALLOCPTRATTR void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC { return nedpmemalign((nedpool *) 0, alignment, bytes); } -#if !NO_MALLINFO -struct mallinfo nedmallinfo(void) THROWSPEC { return nedpmallinfo((nedpool *) 0); } -#endif -int nedmallopt(int parno, int value) THROWSPEC { return nedpmallopt((nedpool *) 0, parno, value); } -int nedmalloc_trim(size_t pad) THROWSPEC { return nedpmalloc_trim((nedpool *) 0, pad); } -void nedmalloc_stats() THROWSPEC { nedpmalloc_stats((nedpool *) 0); } -size_t nedmalloc_footprint() THROWSPEC { return nedpmalloc_footprint((nedpool *) 0); } +void nedsetvalue(void *v) THROWSPEC { nedpsetvalue((nedpool *) 0, v); } +NEDMALLOCPTRATTR void * nedmalloc(size_t size) THROWSPEC { return nedpmalloc((nedpool *) 0, size); } +NEDMALLOCPTRATTR void * nedcalloc(size_t no, size_t size) THROWSPEC { return nedpcalloc((nedpool *) 0, no, size); } +NEDMALLOCPTRATTR void * nedrealloc(void *mem, size_t size) THROWSPEC { return nedprealloc((nedpool *) 0, mem, size); } +void nedfree(void *mem) THROWSPEC { nedpfree((nedpool *) 0, mem); } +NEDMALLOCPTRATTR void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC { return nedpmemalign((nedpool *) 0, alignment, bytes); } +struct nedmallinfo nedmallinfo(void) THROWSPEC { return nedpmallinfo((nedpool *) 0); } +int nedmallopt(int parno, int value) THROWSPEC { return nedpmallopt((nedpool *) 0, parno, value); } +int nedmalloc_trim(size_t pad) THROWSPEC { return nedpmalloc_trim((nedpool *) 0, pad); } +void nedmalloc_stats() THROWSPEC { nedpmalloc_stats((nedpool *) 0); } +size_t nedmalloc_footprint() THROWSPEC { return nedpmalloc_footprint((nedpool *) 0); } NEDMALLOCPTRATTR void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC { return nedpindependent_calloc((nedpool *) 0, elemsno, elemsize, chunks); } -NEDMALLOCPTRATTR void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC { return nedpindependent_comalloc((nedpool *) 0, elems, sizes, chunks); } +// NEDMALLOCPTRATTR void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC { return nedpindependent_comalloc((nedpool *) 0, elems, sizes, chunks); } struct threadcacheblk_t; typedef struct threadcacheblk_t threadcacheblk; @@ -383,7 +540,7 @@ struct nedpool_t }; static nedpool syspool; -static FORCEINLINE unsigned int size2binidx(size_t _size) THROWSPEC +static FORCEINLINE NEDMALLOCNOALIASATTR unsigned int size2binidx(size_t _size) THROWSPEC { /* 8=1000 16=10000 20=10100 24=11000 32=100000 48=110000 4096=1000000000000 */ unsigned int topbit, size=(unsigned int)(_size>>4); /* 16=1 20=1 24=1 32=10 48=11 64=100 96=110 128=1000 4096=100000000 */ @@ -467,9 +624,8 @@ static void tcfullsanitycheck(threadcache *tc) THROWSPEC } #endif -static NOINLINE void RemoveCacheEntries(nedpool *p, threadcache *tc, unsigned int age) THROWSPEC +static NOINLINE void RemoveCacheEntries(nedpool *RESTRICT p, threadcache *RESTRICT tc, unsigned int age) THROWSPEC { - UNREFERENCED_PARAMETER(p); #ifdef FULLSANITYCHECKS tcfullsanitycheck(tc); #endif @@ -485,7 +641,7 @@ static NOINLINE void RemoveCacheEntries(nedpool *p, threadcache *tc, unsigned in { threadcacheblk *f=*tcb; size_t blksize=f->size; /*nedblksize(f);*/ - assert(blksize<=nedblksize(f)); + assert(blksize<=nedblksize(0, f)); assert(blksize); #ifdef FULLSANITYCHECKS assert(*(unsigned int *) "NEDN"==(*tcb)->magic); @@ -497,7 +653,7 @@ static NOINLINE void RemoveCacheEntries(nedpool *p, threadcache *tc, unsigned in *tcbptr=0; tc->freeInCache-=blksize; assert((long) tc->freeInCache>=0); - CallFree(0, f); + CallFree(0, f, 0); /*tcsanitycheck(tcbptr);*/ } } @@ -506,7 +662,7 @@ static NOINLINE void RemoveCacheEntries(nedpool *p, threadcache *tc, unsigned in tcfullsanitycheck(tc); #endif } -static void DestroyCaches(nedpool *p) THROWSPEC +static void DestroyCaches(nedpool *RESTRICT p) THROWSPEC { if(p->caches) { @@ -521,14 +677,14 @@ static void DestroyCaches(nedpool *p) THROWSPEC assert(!tc->freeInCache); tc->mymspace=-1; tc->threadid=0; - CallFree(0, tc); + CallFree(0, tc, 0); p->caches[n]=0; } } } } -static NOINLINE threadcache *AllocCache(nedpool *p) THROWSPEC +static NOINLINE threadcache *AllocCache(nedpool *RESTRICT p) THROWSPEC { threadcache *tc=0; int n, end; @@ -539,7 +695,7 @@ static NOINLINE threadcache *AllocCache(nedpool *p) THROWSPEC RELEASE_LOCK(&p->mutex); return 0; } - tc=p->caches[n]=(threadcache *) CallCalloc(p->m[0], 1, sizeof(threadcache), 0); + tc=p->caches[n]=(threadcache *) CallCalloc(p->m[0], sizeof(threadcache), 0); if(!tc) { RELEASE_LOCK(&p->mutex); @@ -557,14 +713,13 @@ static NOINLINE threadcache *AllocCache(nedpool *p) THROWSPEC return tc; } -static void *threadcache_malloc(nedpool *p, threadcache *tc, size_t *size) THROWSPEC +static void *threadcache_malloc(nedpool *RESTRICT p, threadcache *RESTRICT tc, size_t *RESTRICT _size) THROWSPEC { - void *ret=0; + void *RESTRICT ret=0; + size_t size=*_size, blksize=0; unsigned int bestsize; - unsigned int idx=size2binidx(*size); - size_t blksize=0; - threadcacheblk *blk, **binsptr; - UNREFERENCED_PARAMETER(p); + unsigned int idx=size2binidx(size); + threadcacheblk *RESTRICT blk, **RESTRICT binsptr; #ifdef FULLSANITYCHECKS tcfullsanitycheck(tc); #endif @@ -573,31 +728,31 @@ static void *threadcache_malloc(nedpool *p, threadcache *tc, size_t *size) THROW #ifdef FINEGRAINEDBINS /* Finer grained bin fit */ idx<<=1; - if(*size>bestsize) + if(size>bestsize) { idx++; bestsize+=bestsize>>1; } - if(*size>bestsize) + if(size>bestsize) { idx++; bestsize=1<<(4+(idx>>1)); } #else - if(*size>bestsize) + if(size>bestsize) { idx++; bestsize<<=1; } #endif - assert(bestsize>=*size); - if(*size=size); + if(sizebins[idx*2]; /* Try to match close, but move up a bin if necessary */ blk=*binsptr; - if(!blk || blk->size<*size) + if(!blk || blk->sizesize; /*nedblksize(blk);*/ - assert(nedblksize(blk)>=blksize); - assert(blksize>=*size); + assert(nedblksize(0, blk)>=blksize); + assert(blksize>=size); if(blk->next) blk->next->prev=0; *binsptr=blk->next; @@ -620,14 +775,14 @@ static void *threadcache_malloc(nedpool *p, threadcache *tc, size_t *size) THROW blk->magic=0; #endif assert(binsptr[0]!=blk && binsptr[1]!=blk); - assert(nedblksize(blk)>=sizeof(threadcacheblk) && nedblksize(blk)<=THREADCACHEMAX+CHUNK_OVERHEAD); - /*printf("malloc: %p, %p, %p, %lu\n", p, tc, blk, (long) size);*/ + assert(nedblksize(0, blk)>=sizeof(threadcacheblk) && nedblksize(0, blk)<=THREADCACHEMAX+CHUNK_OVERHEAD); + /*printf("malloc: %p, %p, %p, %lu\n", p, tc, blk, (long) _size);*/ ret=(void *) blk; } ++tc->mallocs; if(ret) { - assert(blksize>=*size); + assert(blksize>=size); ++tc->successes; tc->freeInCache-=blksize; assert((long) tc->freeInCache>=0); @@ -642,13 +797,13 @@ static void *threadcache_malloc(nedpool *p, threadcache *tc, size_t *size) THROW #ifdef FULLSANITYCHECKS tcfullsanitycheck(tc); #endif + *_size=size; return ret; } -static NOINLINE void ReleaseFreeInCache(nedpool *p, threadcache *tc, int mymspace) THROWSPEC +static NOINLINE void ReleaseFreeInCache(nedpool *RESTRICT p, threadcache *RESTRICT tc, int mymspace) THROWSPEC { unsigned int age=THREADCACHEMAXFREESPACE/8192; /*ACQUIRE_LOCK(&p->m[mymspace]->mutex);*/ - UNREFERENCED_PARAMETER(mymspace); while(age && tc->freeInCache>=THREADCACHEMAXFREESPACE) { RemoveCacheEntries(p, tc, age); @@ -657,15 +812,15 @@ static NOINLINE void ReleaseFreeInCache(nedpool *p, threadcache *tc, int mymspac } /*RELEASE_LOCK(&p->m[mymspace]->mutex);*/ } -static void threadcache_free(nedpool *p, threadcache *tc, int mymspace, void *mem, size_t size) THROWSPEC +static void threadcache_free(nedpool *RESTRICT p, threadcache *RESTRICT tc, int mymspace, void *RESTRICT mem, size_t size) THROWSPEC { unsigned int bestsize; unsigned int idx=size2binidx(size); - threadcacheblk **binsptr, *tck=(threadcacheblk *) mem; + threadcacheblk **RESTRICT binsptr, *RESTRICT tck=(threadcacheblk *) mem; assert(size>=sizeof(threadcacheblk) && size<=THREADCACHEMAX+CHUNK_OVERHEAD); #ifdef DEBUG /* Make sure this is a valid memory block */ - assert(nedblksize(mem)); + assert(nedblksize(0, mem)); #endif #ifdef FULLSANITYCHECKS tcfullsanitycheck(tc); @@ -677,7 +832,7 @@ static void threadcache_free(nedpool *p, threadcache *tc, int mymspace, void *me idx<<=1; if(size>bestsize) { - unsigned int biggerbestsize=bestsize+(bestsize<<1); + unsigned int biggerbestsize=bestsize+bestsize<<1; if(size>=biggerbestsize) { idx++; @@ -723,7 +878,7 @@ static void threadcache_free(nedpool *p, threadcache *tc, int mymspace, void *me -static NOINLINE int InitPool(nedpool *p, size_t capacity, int threads) THROWSPEC +static NOINLINE int InitPool(nedpool *RESTRICT p, size_t capacity, int threads) THROWSPEC { /* threads is -1 for system pool */ ensure_initialization(); ACQUIRE_MALLOC_GLOBAL_LOCK(); @@ -759,7 +914,7 @@ err: RELEASE_MALLOC_GLOBAL_LOCK(); return 0; } -static NOINLINE mstate FindMSpace(nedpool *p, threadcache *tc, int *lastUsed, size_t size) THROWSPEC +static NOINLINE mstate FindMSpace(nedpool *RESTRICT p, threadcache *RESTRICT tc, int *RESTRICT lastUsed, size_t size) THROWSPEC { /* Gets called when thread's last used mspace is in use. The strategy is to run through the list of all available mspaces looking for an unlocked one and if we fail, we create a new one so long as we don't @@ -818,20 +973,57 @@ found: return p->m[n]; } +typedef struct PoolList_t +{ + size_t size; /* Size of list */ + size_t length; /* Actual entries in list */ +#ifdef DEBUG + nedpool *list[1]; /* Force testing of list expansion */ +#else + nedpool *list[16]; +#endif +} PoolList; +static MLOCK_T poollistlock; +static PoolList *poollist; NEDMALLOCPTRATTR nedpool *nedcreatepool(size_t capacity, int threads) THROWSPEC { - nedpool *ret; - if(!(ret=(nedpool *) nedpcalloc(0, 1, sizeof(nedpool)))) return 0; + nedpool *ret=0; + if(!poollist) + { + PoolList *newpoollist=0; + if(!(newpoollist=(PoolList *) nedpcalloc(0, 1, sizeof(PoolList)+sizeof(nedpool *)))) return 0; + INITIAL_LOCK(&poollistlock); + ACQUIRE_LOCK(&poollistlock); + poollist=newpoollist; + poollist->size=sizeof(poollist->list)/sizeof(nedpool *); + } + else + ACQUIRE_LOCK(&poollistlock); + if(poollist->length==poollist->size) + { + PoolList *newpoollist=0; + size_t newsize=0; + newsize=sizeof(PoolList)+(poollist->size+1)*sizeof(nedpool *); + if(!(newpoollist=(PoolList *) nedprealloc(0, poollist, newsize))) goto badexit; + poollist=newpoollist; + memset(&poollist->list[poollist->size], 0, newsize-((size_t)&poollist->list[poollist->size]-(size_t)&poollist->list[0])); + poollist->size=((newsize-((char *)&poollist->list[0]-(char *)poollist))/sizeof(nedpool *))-1; + assert(poollist->size>poollist->length); + } + if(!(ret=(nedpool *) nedpcalloc(0, 1, sizeof(nedpool)))) goto badexit; if(!InitPool(ret, capacity, threads)) { nedpfree(0, ret); - return 0; + goto badexit; } + poollist->list[poollist->length++]=ret; +badexit: + RELEASE_LOCK(&poollistlock); return ret; } void neddestroypool(nedpool *p) THROWSPEC { - int n; + unsigned int n; ACQUIRE_LOCK(&p->mutex); DestroyCaches(p); for(n=0; p->m[n]; n++) @@ -844,6 +1036,18 @@ void neddestroypool(nedpool *p) THROWSPEC RELEASE_LOCK(&p->mutex); if(TLSFREE(p->mycache)) abort(); nedpfree(0, p); + ACQUIRE_LOCK(&poollistlock); + assert(poollist); + for(n=0; nlength && poollist->list[n]!=p; n++); + assert(n!=poollist->length); + memmove(&poollist->list[n], &poollist->list[n+1], (size_t)&poollist->list[poollist->length]-(size_t)&poollist->list[n]); + if(!--poollist->length) + { + assert(!poollist->list[0]); + nedpfree(0, poollist); + poollist=0; + } + RELEASE_LOCK(&poollistlock); } void neddestroysyspool() THROWSPEC { @@ -860,35 +1064,36 @@ void neddestroysyspool() THROWSPEC } /* Render syspool unusable */ for(n=0; ncaches[n]=(threadcache *)0xdeadbeef; + p->caches[n]=(threadcache *)(size_t)(sizeof(size_t)>4 ? 0xdeadbeefdeadbeefULL : 0xdeadbeefUL); for(n=0; nm[n]=(mstate)0xdeadbeef; + p->m[n]=(mstate)(size_t)(sizeof(size_t)>4 ? 0xdeadbeefdeadbeefULL : 0xdeadbeefUL); if(TLSFREE(p->mycache)) abort(); RELEASE_LOCK(&p->mutex); } +nedpool **nedpoollist() THROWSPEC +{ + nedpool **ret=0; + if(poollist) + { + ACQUIRE_LOCK(&poollistlock); + if(!(ret=(nedpool **) nedmalloc((poollist->length+1)*sizeof(nedpool *)))) goto badexit; + memcpy(ret, poollist->list, (poollist->length+1)*sizeof(nedpool *)); +badexit: + RELEASE_LOCK(&poollistlock); + } + return ret; +} void nedpsetvalue(nedpool *p, void *v) THROWSPEC { if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); } p->uservalue=v; } - void *nedgetvalue(nedpool **p, void *mem) THROWSPEC { nedpool *np=0; - mchunkptr mcp=mem2chunk(mem); - mstate fm; - if(!(is_aligned(chunk2mem(mcp))) && mcp->head != FENCEPOST_HEAD) return 0; - if(!cinuse(mcp)) return 0; - if(!next_pinuse(mcp)) return 0; - if(!is_mmapped(mcp) && !pinuse(mcp)) - { - if(next_chunk(prev_chunk(mcp))!=mcp) return 0; - } - fm=get_mstate_for(mcp); - if(!ok_magic(fm)) return 0; - if(!ok_address(fm, mcp)) return 0; - if(!fm->extp) return 0; + mstate fm=nedblkmstate(mem); + if(!fm || !fm->extp) return 0; np=(nedpool *) fm->extp; if(p) *p=np; return np->uservalue; @@ -922,7 +1127,7 @@ void nedtrimthreadcache(nedpool *p, int disable) THROWSPEC { tc->mymspace=-1; tc->threadid=0; - CallFree(0, p->caches[mycache-1]); + CallFree(0, p->caches[mycache-1], 0); p->caches[mycache-1]=0; } } @@ -940,7 +1145,7 @@ void neddisablethreadcache(nedpool *p) THROWSPEC if(USE_ALLOCATOR==1) { RELEASE_LOCK(&m->mutex); } \ } while (0) -static FORCEINLINE mstate GetMSpace(nedpool *p, threadcache *tc, int mymspace, size_t size) THROWSPEC +static FORCEINLINE mstate GetMSpace(nedpool *RESTRICT p, threadcache *RESTRICT tc, int mymspace, size_t size) THROWSPEC { /* Returns a locked and ready for use mspace */ mstate m=p->m[mymspace]; assert(m); @@ -950,22 +1155,14 @@ static FORCEINLINE mstate GetMSpace(nedpool *p, threadcache *tc, int mymspace, s #endif return m; } -static FORCEINLINE void GetThreadCache(nedpool **p, threadcache **tc, int *mymspace, size_t *size) THROWSPEC +static NOINLINE void GetThreadCache_cold1(nedpool *RESTRICT *RESTRICT p) THROWSPEC { - int mycache; - if(size && *sizemycache); - if(mycache>0) - { /* Already have a cache */ - *tc=(*p)->caches[mycache-1]; - *mymspace=(*tc)->mymspace; - } - else if(!mycache) + *p=&syspool; + if(!syspool.threads) InitPool(&syspool, 0, -1); +} +static NOINLINE void GetThreadCache_cold2(nedpool *RESTRICT *RESTRICT p, threadcache *RESTRICT *RESTRICT tc, int *RESTRICT mymspace, int mycache) THROWSPEC +{ + if(!mycache) { /* Need to allocate a new cache */ *tc=AllocCache(*p); if(!*tc) @@ -981,6 +1178,20 @@ static FORCEINLINE void GetThreadCache(nedpool **p, threadcache **tc, int *mymsp *tc=0; *mymspace=-mycache-1; } +} +static FORCEINLINE void GetThreadCache(nedpool *RESTRICT *RESTRICT p, threadcache *RESTRICT *RESTRICT tc, int *RESTRICT mymspace, size_t *RESTRICT size) THROWSPEC +{ + int mycache; + if(size && *sizemycache); + if(mycache>0) + { /* Already have a cache */ + *tc=(*p)->caches[mycache-1]; + *mymspace=(*tc)->mymspace; + } + else GetThreadCache_cold2(p, tc, mymspace, mycache); assert(*mymspace>=0); assert(!(*tc) || (long)(size_t)CURRENT_THREAD==(*tc)->threadid); #ifdef FULLSANITYCHECKS @@ -1030,7 +1241,7 @@ NEDMALLOCPTRATTR void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC if(!ret) { /* Use this thread's mspace */ GETMSPACE(m, p, tc, mymspace, rsize, - ret=CallCalloc(m, 1, rsize, 0)); + ret=CallCalloc(m, rsize, 0)); } return ret; } @@ -1038,35 +1249,42 @@ NEDMALLOCPTRATTR void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPE { void *ret=0; threadcache *tc; - int mymspace; + int mymspace, isforeign=1; + size_t memsize; if(!mem) return nedpmalloc(p, size); + memsize=nedblksize(&isforeign, mem); + assert(memsize); + if(!memsize) + { + fprintf(stderr, "nedmalloc: nedprealloc() called with a block not created by nedmalloc!\n"); + abort(); + } + else if(size<=memsize && memsize-size< +#ifdef DEBUG + 32 +#else + 1024 +#endif + ) /* If realloc size is within 1Kb smaller than existing, noop it */ + return mem; GetThreadCache(&p, &tc, &mymspace, &size); #if THREADCACHEMAX if(tc && size && size<=THREADCACHEMAX) { /* Use the thread cache */ - size_t memsize=nedblksize(mem); -#if !USE_MAGIC_HEADERS - assert(memsize); - if(!memsize) - { - fprintf(stderr, "nedmalloc: nedprealloc() called with a block not created by nedmalloc!\n"); - abort(); - } -#endif if((ret=threadcache_malloc(p, tc, &size))) { memcpy(ret, mem, memsize=sizeof(threadcacheblk) && memsize<=(THREADCACHEMAX+CHUNK_OVERHEAD)) threadcache_free(p, tc, mymspace, mem, memsize); else - CallFree(0, mem); + CallFree(0, mem, isforeign); } } #endif if(!ret) { /* Reallocs always happen in the mspace they happened in, so skip locking the preferred mspace for this thread */ - ret=CallRealloc(0, mem, size); + ret=CallRealloc(p->m[mymspace], mem, isforeign, memsize, size); } return ret; } @@ -1074,30 +1292,29 @@ void nedpfree(nedpool *p, void *mem) THROWSPEC { /* Frees always happen in the mspace they happened in, so skip locking the preferred mspace for this thread */ threadcache *tc; - int mymspace; + int mymspace, isforeign=1; size_t memsize; if(!mem) - { /* You'd be surprised the number of times this happens as so many - allocators are non-conformant here */ -// fprintf(stderr, "nedmalloc: WARNING nedpfree() called with zero. This is not portable behaviour!\n"); + { /* If you tried this on FreeBSD you'd be sorry! */ +#ifdef DEBUG + fprintf(stderr, "nedmalloc: WARNING nedpfree() called with zero. This is not portable behaviour!\n"); +#endif return; } - GetThreadCache(&p, &tc, &mymspace, 0); -#if THREADCACHEMAX - memsize=nedblksize(mem); -#if !USE_MAGIC_HEADERS + memsize=nedblksize(&isforeign, mem); assert(memsize); if(!memsize) { fprintf(stderr, "nedmalloc: nedpfree() called with a block not created by nedmalloc!\n"); abort(); } -#endif - if(mem && tc && memsize && memsize<=(THREADCACHEMAX+CHUNK_OVERHEAD)) + GetThreadCache(&p, &tc, &mymspace, 0); +#if THREADCACHEMAX + if(mem && tc && memsize>=sizeof(threadcacheblk) && memsize<=(THREADCACHEMAX+CHUNK_OVERHEAD)) threadcache_free(p, tc, mymspace, mem, memsize); else #endif - CallFree(0, mem); + CallFree(0, mem, isforeign); } NEDMALLOCPTRATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC { @@ -1111,15 +1328,14 @@ NEDMALLOCPTRATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) } return ret; } -#if !NO_MALLINFO -struct mallinfo nedpmallinfo(nedpool *p) THROWSPEC +struct nedmallinfo nedpmallinfo(nedpool *p) THROWSPEC { int n; - struct mallinfo ret={0,0,0,0,0,0,0,0,0,0}; + struct nedmallinfo ret={0}; if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); } for(n=0; p->m[n]; n++) { -#if USE_ALLOCATOR==1 +#if USE_ALLOCATOR==1 && !NO_MALLINFO struct mallinfo t=mspace_mallinfo(p->m[n]); ret.arena+=t.arena; ret.ordblks+=t.ordblks; @@ -1132,10 +1348,8 @@ struct mallinfo nedpmallinfo(nedpool *p) THROWSPEC } return ret; } -#endif int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC { - UNREFERENCED_PARAMETER(p); #if USE_ALLOCATOR==1 return mspace_mallopt(parno, value); #else @@ -1205,6 +1419,8 @@ NEDMALLOCPTRATTR void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_ #endif return ret; } + +#if 0 NEDMALLOCPTRATTR void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC { void **ret; @@ -1224,6 +1440,7 @@ NEDMALLOCPTRATTR void **nedpindependent_comalloc(nedpool *p, size_t elems, size_ #endif return ret; } +#endif // 0 // cheap replacement for strdup so we aren't feeding system allocated blocks into nedmalloc diff --git a/polymer/eduke32/build/src/polymer.c b/polymer/eduke32/build/src/polymer.c index 49a157b94..c67f9ed53 100644 --- a/polymer/eduke32/build/src/polymer.c +++ b/polymer/eduke32/build/src/polymer.c @@ -4290,109 +4290,84 @@ static void polymer_getscratchmaterial(_prmaterial* material) static void polymer_getbuildmaterial(_prmaterial* material, int16_t tilenum, char pal, int8_t shade) { pthtyp* pth; - pthtyp* detailpth; - pthtyp* glowpth; - + polymer_getscratchmaterial(material); - - // PR_BIT_NORMAL_MAP - if (hicfindsubst(tilenum, NORMALPAL, 0)) - { - glowpth = NULL; - glowpth = gltexcache(tilenum, NORMALPAL, 0); - - if (glowpth && glowpth->hicr && (glowpth->hicr->palnum == NORMALPAL)) { - material->normalmap = glowpth->glpic; - material->normalbias[0] = glowpth->hicr->specpower; - material->normalbias[1] = glowpth->hicr->specfactor; - } - } - + // PR_BIT_DIFFUSE_MAP if (!waloff[tilenum]) loadtile(tilenum); - - pth = NULL; - pth = gltexcache(tilenum, pal, (material == &spriteplane.material) ? 4 : 0); - - if (pth) + + if ((pth = gltexcache(tilenum, pal, (material == &spriteplane.material) ? 4 : 0))) + { material->diffusemap = pth->glpic; - - if (pth->hicr) - { - material->diffusescale[0] = pth->hicr->xscale; - material->diffusescale[1] = pth->hicr->yscale; - } - - // PR_BIT_DIFFUSE_DETAIL_MAP - if (hicfindsubst(tilenum, DETAILPAL, 0)) - { - detailpth = NULL; - detailpth = gltexcache(tilenum, DETAILPAL, 0); - - if (detailpth && detailpth->hicr && (detailpth->hicr->palnum == DETAILPAL)) + + if (pth->hicr) { - material->detailmap = detailpth->glpic; - - material->detailscale[0] = detailpth->hicr->xscale; - material->detailscale[1] = detailpth->hicr->yscale; + material->diffusescale[0] = pth->hicr->xscale; + material->diffusescale[1] = pth->hicr->yscale; + + // PR_BIT_SPECULAR_MATERIAL + if (pth->hicr->specpower != 1.0f) + material->specmaterial[0] = pth->hicr->specpower; + material->specmaterial[1] = pth->hicr->specfactor; } - } - - // PR_BIT_DIFFUSE_MODULATION - material->diffusemodulation[0] = + + // PR_BIT_DIFFUSE_MODULATION + material->diffusemodulation[0] = material->diffusemodulation[1] = material->diffusemodulation[2] = ((float)(numpalookups-min(max(shade*shadescale,0),numpalookups)))/((float)numpalookups); + + if (pth->flags & 2) + { + if (pth->palnum != pal) + { + material->diffusemodulation[0] *= (float)hictinting[pal].r / 255.0; + material->diffusemodulation[1] *= (float)hictinting[pal].g / 255.0; + material->diffusemodulation[2] *= (float)hictinting[pal].b / 255.0; + } - if (pth && (pth->flags & 2)) - { - if (pth->palnum != pal) - { - material->diffusemodulation[0] *= (float)hictinting[pal].r / 255.0; - material->diffusemodulation[1] *= (float)hictinting[pal].g / 255.0; - material->diffusemodulation[2] *= (float)hictinting[pal].b / 255.0; - } - // fullscreen tint on global palette change - if (hictinting[MAXPALOOKUPS-1].r != 255 || - hictinting[MAXPALOOKUPS-1].g != 255 || - hictinting[MAXPALOOKUPS-1].b != 255) - { - material->diffusemodulation[0] *= hictinting[MAXPALOOKUPS-1].r / 255.0; - material->diffusemodulation[1] *= hictinting[MAXPALOOKUPS-1].g / 255.0; - material->diffusemodulation[2] *= hictinting[MAXPALOOKUPS-1].b / 255.0; + // fullscreen tint on global palette change... this is used for nightvision and underwater tinting + // if ((hictinting[MAXPALOOKUPS-1].r + hictinting[MAXPALOOKUPS-1].g + hictinting[MAXPALOOKUPS-1].b) != 0x2FD) + if (((uint32_t)hictinting[MAXPALOOKUPS-1].r & 0xFFFFFF00) != 0xFFFFFF00) + { + material->diffusemodulation[0] *= hictinting[MAXPALOOKUPS-1].r / 255.0; + material->diffusemodulation[1] *= hictinting[MAXPALOOKUPS-1].g / 255.0; + material->diffusemodulation[2] *= hictinting[MAXPALOOKUPS-1].b / 255.0; + } } + + // PR_BIT_GLOW_MAP + if (r_fullbrights && pth->flags & 16) + material->glowmap = pth->ofb->glpic; } - + + // PR_BIT_DIFFUSE_DETAIL_MAP + if (hicfindsubst(tilenum, DETAILPAL, 0) && (pth = gltexcache(tilenum, DETAILPAL, 0)) && + pth->hicr && (pth->hicr->palnum == DETAILPAL)) + { + material->detailmap = pth->glpic; + material->detailscale[0] = pth->hicr->xscale; + material->detailscale[1] = pth->hicr->yscale; + } + + // PR_BIT_GLOW_MAP + if (hicfindsubst(tilenum, GLOWPAL, 0) && (pth = gltexcache(tilenum, GLOWPAL, 0)) && + pth->hicr && (pth->hicr->palnum == GLOWPAL)) + material->glowmap = pth->glpic; + // PR_BIT_SPECULAR_MAP - if (hicfindsubst(tilenum, SPECULARPAL, 0)) + if (hicfindsubst(tilenum, SPECULARPAL, 0) && (pth = gltexcache(tilenum, SPECULARPAL, 0)) && + pth->hicr && (pth->hicr->palnum == SPECULARPAL)) + material->specmap = pth->glpic; + + // PR_BIT_NORMAL_MAP + if (hicfindsubst(tilenum, NORMALPAL, 0) && (pth = gltexcache(tilenum, NORMALPAL, 0)) && + pth->hicr && (pth->hicr->palnum == NORMALPAL)) { - glowpth = NULL; - glowpth = gltexcache(tilenum, SPECULARPAL, 0); - - if (glowpth && glowpth->hicr && (glowpth->hicr->palnum == SPECULARPAL)) - material->specmap = glowpth->glpic; - } - - // PR_BIT_SPECULAR_MATERIAL - if (pth->hicr) - { - if (pth->hicr->specpower != 1.0f) - material->specmaterial[0] = pth->hicr->specpower; - material->specmaterial[1] = pth->hicr->specfactor; - } - - // PR_BIT_GLOW_MAP - if (r_fullbrights && pth && pth->flags & 16) - material->glowmap = pth->ofb->glpic; - - if (hicfindsubst(tilenum, GLOWPAL, 0)) - { - glowpth = NULL; - glowpth = gltexcache(tilenum, GLOWPAL, 0); - - if (glowpth && glowpth->hicr && (glowpth->hicr->palnum == GLOWPAL)) - material->glowmap = glowpth->glpic; + material->normalmap = pth->glpic; + material->normalbias[0] = pth->hicr->specpower; + material->normalbias[1] = pth->hicr->specfactor; } } diff --git a/polymer/eduke32/build/src/polymost.c b/polymer/eduke32/build/src/polymost.c index c1856cc95..7831da483 100644 --- a/polymer/eduke32/build/src/polymost.c +++ b/polymer/eduke32/build/src/polymost.c @@ -247,7 +247,7 @@ void drawline2d(float x0, float y0, float x1, float y1, char col) #define USEKENFILTER 1 #ifdef USELZF -# include "fastlz.h" +# include "quicklz.h" #else # include "lzwnew.h" #endif @@ -4283,8 +4283,8 @@ void polymost_drawrooms() w2d = -w2d; if ((w1d==0 && w2d==0) || (w1d<0 || w2d<0)) continue; - ptonline[0] = w2[0]+(w2d/(w1d+w2d))*w21[0]; - ptonline[1] = w2[1]+(w2d/(w1d+w2d))*w21[1]; + ptonline[0] = (int32_t)(w2[0]+(w2d/(w1d+w2d))*w21[0]); + ptonline[1] = (int32_t)(w2[1]+(w2d/(w1d+w2d))*w21[1]); scrp[0] = ptonline[0]-vect.x; scrp[1] = ptonline[1]-vect.y; if (scrv[0]*scrp[0] + scrv[1]*scrp[1] <= 0) @@ -6096,7 +6096,7 @@ int32_t dxtfilter(int32_t fil, texcachepicture *pict, char *pic, void *midbuf, c if (glusetexcache == 2) { #ifdef USELZF - cleng = fastlz_compress(pic, miplen, packbuf/*, miplen-1*/); + cleng = qlz_compress(pic, packbuf, miplen, state_compress); if (cleng == 0 || cleng > j-1) { // failed to compress @@ -6138,7 +6138,7 @@ int32_t dxtfilter(int32_t fil, texcachepicture *pict, char *pic, void *midbuf, c { #ifdef USELZF j = (miplen/stride)<<3; - cleng = fastlz_compress(midbuf,j,packbuf/*,j-1*/); + cleng = qlz_compress(midbuf,packbuf,j,state_compress); if (cleng == 0 || cleng > j-1) { cleng = j; @@ -6169,7 +6169,7 @@ int32_t dxtfilter(int32_t fil, texcachepicture *pict, char *pic, void *midbuf, c { #ifdef USELZF j = (miplen/stride)<<2; - cleng = fastlz_compress(midbuf,j,packbuf/*,j-1*/); + cleng = qlz_compress(midbuf,packbuf,j,state_compress); if (cleng == 0 || cleng > j-1) { cleng = j; @@ -6205,7 +6205,7 @@ int32_t dxtfilter(int32_t fil, texcachepicture *pict, char *pic, void *midbuf, c { #ifdef USELZF j = (miplen/stride)<<2; - cleng = fastlz_compress(midbuf,j,packbuf/*,j-1*/); + cleng = qlz_compress(midbuf,packbuf,j,state_compress); if (cleng == 0 || cleng > j-1) { cleng = j; @@ -6239,7 +6239,7 @@ int32_t dedxtfilter(int32_t fil, texcachepicture *pict, char *pic, void *midbuf, if (ispacked && cleng < pict->size) inbuf = packbuf; else inbuf = pic; if (kread(fil, inbuf, cleng) != cleng) return -1; if (ispacked && cleng < pict->size) - if (fastlz_decompress(packbuf, cleng, pic, pict->size) == 0) return -1; + if (qlz_decompress(packbuf, pic, state_decompress) == 0) return -1; #else if (ispacked) inbuf = packbuf; else inbuf = pic; if (kread(fil, inbuf, cleng) != cleng) return -1; @@ -6266,7 +6266,7 @@ int32_t dedxtfilter(int32_t fil, texcachepicture *pict, char *pic, void *midbuf, if (ispacked && cleng < j) inbuf = packbuf; else inbuf = midbuf; if (Bread(fil,inbuf,cleng) < cleng) return -1; if (ispacked && cleng < j) - if (fastlz_decompress(packbuf,cleng,midbuf,j) == 0) return -1; + if (qlz_decompress(packbuf,midbuf,state_decompress) == 0) return -1; #else if (Bread(fil,inbuf,cleng) < cleng) return -1; if (ispacked && lzwuncompress(packbuf,cleng,midbuf,j) != j) return -1; @@ -6284,7 +6284,7 @@ int32_t dedxtfilter(int32_t fil, texcachepicture *pict, char *pic, void *midbuf, if (ispacked && cleng < j) inbuf = packbuf; else inbuf = midbuf; if (Bread(fil,inbuf,cleng) < cleng) return -1; if (ispacked && cleng < j) - if (fastlz_decompress(packbuf,cleng,midbuf,j) == 0) return -1; + if (qlz_decompress(packbuf,midbuf,state_decompress) == 0) return -1; #else if (Bread(fil,inbuf,cleng) < cleng) return -1; if (ispacked && lzwuncompress(packbuf,cleng,midbuf,j) != j) return -1; @@ -6304,7 +6304,7 @@ int32_t dedxtfilter(int32_t fil, texcachepicture *pict, char *pic, void *midbuf, if (ispacked && cleng < j) inbuf = packbuf; else inbuf = midbuf; if (Bread(fil,inbuf,cleng) < cleng) return -1; if (ispacked && cleng < j) - if (fastlz_decompress(packbuf,cleng,midbuf,j) == 0) return -1; + if (qlz_decompress(packbuf,midbuf,state_decompress) == 0) return -1; #else if (Bread(fil,inbuf,cleng) < cleng) return -1; if (ispacked && lzwuncompress(packbuf,cleng,midbuf,j) != j) return -1; diff --git a/polymer/eduke32/build/src/quicklz.c b/polymer/eduke32/build/src/quicklz.c new file mode 100644 index 000000000..d98d56fbc --- /dev/null +++ b/polymer/eduke32/build/src/quicklz.c @@ -0,0 +1,854 @@ +// Fast data compression library +// Copyright (C) 2006-2009 Lasse Mikkel Reinhold +// lar@quicklz.com +// +// QuickLZ can be used for free under the GPL-1 or GPL-2 license (where anything +// released into public must be open source) or under a commercial license if such +// has been acquired (see http://www.quicklz.com/order.html). The commercial license +// does not cover derived or ported versions created by third parties under GPL. + +// BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION +// BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION +// BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION +// BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION +// BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION + +// 1.5.0 BETA 2 + +#include "quicklz.h" + +#if QLZ_VERSION_MAJOR != 1 || QLZ_VERSION_MINOR != 5 || QLZ_VERSION_REVISION != 0 + #error quicklz.c and quicklz.h have different versions +#endif + +#if (defined(__X86__) || defined(__i386__) || defined(i386) || defined(_M_IX86) || defined(__386__) || defined(__x86_64__) || defined(_M_X64)) + #define X86X64 +#endif + +#define MINOFFSET 2 +#define UNCONDITIONAL_MATCHLEN 6 +#define UNCOMPRESSED_END 4 +#define CWORD_LEN 4 + +#if QLZ_COMPRESSION_LEVEL == 1 && defined QLZ_PTR_64 && QLZ_STREAMING_BUFFER == 0 + #define OFFSET_BASE source + #define CAST (ui32)(size_t) +#else + #define OFFSET_BASE 0 + #define CAST +#endif + +int qlz_get_setting(int setting) +{ + switch (setting) + { + case 0: return QLZ_COMPRESSION_LEVEL; + case 1: return sizeof(qlz_state_compress); + case 2: return sizeof(qlz_state_decompress); + case 3: return QLZ_STREAMING_BUFFER; +#ifdef QLZ_MEMORY_SAFE + case 6: return 1; +#else + case 6: return 0; +#endif + case 7: return QLZ_VERSION_MAJOR; + case 8: return QLZ_VERSION_MINOR; + case 9: return QLZ_VERSION_REVISION; + } + return -1; +} + +#if QLZ_COMPRESSION_LEVEL == 1 +static int same(const unsigned char *src, size_t n) +{ + while(n > 0 && *(src + n) == *src) + n--; + return n == 0 ? 1 : 0; +} +#endif + +static void reset_table_compress(qlz_state_compress *state) +{ + int i; + for(i = 0; i < QLZ_HASH_VALUES; i++) + { +#if QLZ_COMPRESSION_LEVEL == 1 + state->hash[i].offset = 0; +#else + state->hash_counter[i] = 0; +#endif + } +} + +static void reset_table_decompress(qlz_state_decompress *state) +{ + int i; + (void)state; + (void)i; +#if QLZ_COMPRESSION_LEVEL == 2 + for(i = 0; i < QLZ_HASH_VALUES; i++) + { + state->hash_counter[i] = 0; + } +#endif +} + +static __inline ui32 hash_func(ui32 i) +{ +#if QLZ_COMPRESSION_LEVEL == 2 + return ((i >> 9) ^ (i >> 13) ^ i) & (QLZ_HASH_VALUES - 1); +#else + return ((i >> 12) ^ i) & (QLZ_HASH_VALUES - 1); +#endif +} + +static __inline ui32 fast_read(void const *src, ui32 bytes) +{ +#ifndef X86X64 + unsigned char *p = (unsigned char*)src; + switch (bytes) + { + case 4: + return(*p | *(p + 1) << 8 | *(p + 2) << 16 | *(p + 3) << 24); + case 3: + return(*p | *(p + 1) << 8 | *(p + 2) << 16); + case 2: + return(*p | *(p + 1) << 8); + case 1: + return(*p); + } + return 0; +#else + if (bytes >= 1 && bytes <= 4) + return *((ui32*)src); + else + return 0; +#endif +} + +static __inline ui32 hashat(const unsigned char *src) +{ + ui32 fetch, hash; + fetch = fast_read(src, 3); + hash = hash_func(fetch); + return hash; +} + +static __inline void fast_write(ui32 f, void *dst, size_t bytes) +{ +#ifndef X86X64 + unsigned char *p = (unsigned char*)dst; + + switch (bytes) + { + case 4: + *p = (unsigned char)f; + *(p + 1) = (unsigned char)(f >> 8); + *(p + 2) = (unsigned char)(f >> 16); + *(p + 3) = (unsigned char)(f >> 24); + return; + case 3: + *p = (unsigned char)f; + *(p + 1) = (unsigned char)(f >> 8); + *(p + 2) = (unsigned char)(f >> 16); + return; + case 2: + *p = (unsigned char)f; + *(p + 1) = (unsigned char)(f >> 8); + return; + case 1: + *p = (unsigned char)f; + return; + } +#else + switch (bytes) + { + case 4: + *((ui32*)dst) = f; + return; + case 3: + *((ui32*)dst) = f; + return; + case 2: + *((ui16 *)dst) = (ui16)f; + return; + case 1: + *((unsigned char*)dst) = (unsigned char)f; + return; + } +#endif +} + + +size_t qlz_size_decompressed(const char *source) +{ + ui32 n, r; + n = (((*source) & 2) == 2) ? 4 : 1; + r = fast_read(source + 1 + n, n); + r = r & (0xffffffff >> ((4 - n)*8)); + return r; +} + +size_t qlz_size_compressed(const char *source) +{ + ui32 n, r; + n = (((*source) & 2) == 2) ? 4 : 1; + r = fast_read(source + 1, n); + r = r & (0xffffffff >> ((4 - n)*8)); + return r; +} + +size_t qlz_size_header(const char *source) +{ + size_t n = 2*((((*source) & 2) == 2) ? 4 : 1) + 1; + return n; +} + + +static __inline void memcpy_up(unsigned char *dst, const unsigned char *src, ui32 n) +{ + // Caution if modifying memcpy_up! Overlap of dst and src must be special handled. +#ifndef X86X64 + unsigned char *end = dst + n; + while(dst < end) + { + *dst = *src; + dst++; + src++; + } +#else + ui32 f = 0; + do + { + *(ui32 *)(dst + f) = *(ui32 *)(src + f); + f += MINOFFSET + 1; + } + while (f < n); +#endif +} + +static __inline void update_hash(qlz_state_decompress *state, const unsigned char *s) +{ +#if QLZ_COMPRESSION_LEVEL == 1 + ui32 hash; + hash = hashat(s); + state->hash[hash].offset = s; + state->hash_counter[hash] = 1; +#elif QLZ_COMPRESSION_LEVEL == 2 + ui32 hash; + unsigned char c; + hash = hashat(s); + c = state->hash_counter[hash]; + state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = s; + c++; + state->hash_counter[hash] = c; +#endif + (void)state; + (void)s; +} + +#if QLZ_COMPRESSION_LEVEL <= 2 +static void update_hash_upto(qlz_state_decompress *state, unsigned char **lh, const unsigned char *max) +{ + while(*lh < max) + { + (*lh)++; + update_hash(state, *lh); + } +} +#endif + +static size_t qlz_compress_core(const unsigned char *source, unsigned char *destination, size_t size, qlz_state_compress *state) +{ + const unsigned char *last_byte = source + size - 1; + const unsigned char *src = source; + unsigned char *cword_ptr = destination; + unsigned char *dst = destination + CWORD_LEN; + ui32 cword_val = 1U << 31; + const unsigned char *last_matchstart = last_byte - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END; + ui32 fetch = 0; + unsigned int lits = 0; + + (void) lits; + + if(src <= last_matchstart) + fetch = fast_read(src, 3); + + while(src <= last_matchstart) + { + if ((cword_val & 1) == 1) + { + // store uncompressed if compression ratio is too low + if (src > source + (size >> 1) && dst - destination > src - source - ((src - source) >> 5)) + return 0; + + fast_write((cword_val >> 1) | (1U << 31), cword_ptr, CWORD_LEN); + + cword_ptr = dst; + dst += CWORD_LEN; + cword_val = 1U << 31; + fetch = fast_read(src, 3); + } +#if QLZ_COMPRESSION_LEVEL == 1 + { + const unsigned char *o; + ui32 hash, cached; + + hash = hash_func(fetch); + cached = fetch ^ state->hash[hash].cache; + state->hash[hash].cache = fetch; + + o = state->hash[hash].offset + OFFSET_BASE; + state->hash[hash].offset = CAST(src - OFFSET_BASE); + +#ifdef X86X64 + if ((cached & 0xffffff) == 0 && o != OFFSET_BASE && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > source + 3 && same(src - 3, 6)))) + { + if(cached != 0) + { +#else + if (cached == 0 && o != OFFSET_BASE && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > source + 3 && same(src - 3, 6)))) + { + if (*(o + 3) != *(src + 3)) + { +#endif + hash <<= 4; + cword_val = (cword_val >> 1) | (1U << 31); + fast_write((3 - 2) | hash, dst, 2); + src += 3; + dst += 2; + } + else + { + const unsigned char *old_src = src; + size_t matchlen; + hash <<= 4; + + cword_val = (cword_val >> 1) | (1U << 31); + src += 4; + + if(*(o + (src - old_src)) == *src) + { + src++; + if(*(o + (src - old_src)) == *src) + { + size_t q = last_byte - UNCOMPRESSED_END - (src - 5) + 1; + size_t remaining = q > 255 ? 255 : q; + src++; + while(*(o + (src - old_src)) == *src && (size_t)(src - old_src) < remaining) + src++; + } + } + + matchlen = src - old_src; + if (matchlen < 18) + { + fast_write((ui32)(matchlen - 2) | hash, dst, 2); + dst += 2; + } + else + { + fast_write((ui32)(matchlen << 16) | hash, dst, 3); + dst += 3; + } + } + fetch = fast_read(src, 3); + lits = 0; + } + else + { + lits++; + *dst = *src; + src++; + dst++; + cword_val = (cword_val >> 1); +#ifdef X86X64 + fetch = fast_read(src, 3); +#else + fetch = (fetch >> 8 & 0xffff) | (*(src + 2) << 16); +#endif + } + } +#elif QLZ_COMPRESSION_LEVEL >= 2 + { + const unsigned char *o, *offset2; + ui32 hash, matchlen, k, m, best_k = 0; + unsigned char c; + size_t remaining = (last_byte - UNCOMPRESSED_END - src + 1) > 255 ? 255 : (last_byte - UNCOMPRESSED_END - src + 1); + (void)best_k; + + + //hash = hashat(src); + fetch = fast_read(src, 3); + hash = hash_func(fetch); + + c = state->hash_counter[hash]; + + offset2 = state->hash[hash].offset[0]; + if(offset2 < src - MINOFFSET && c > 0 && ((fast_read(offset2, 3) ^ fetch) & 0xffffff) == 0) + { + matchlen = 3; + if(*(offset2 + matchlen) == *(src + matchlen)) + { + matchlen = 4; + while(*(offset2 + matchlen) == *(src + matchlen) && matchlen < remaining) + matchlen++; + } + } + else + matchlen = 0; + for(k = 1; k < QLZ_POINTERS && c > k; k++) + { + o = state->hash[hash].offset[k]; +#if QLZ_COMPRESSION_LEVEL == 3 + if(((fast_read(o, 3) ^ fetch) & 0xffffff) == 0 && o < src - MINOFFSET) +#elif QLZ_COMPRESSION_LEVEL == 2 + if(*(src + matchlen) == *(o + matchlen) && ((fast_read(o, 3) ^ fetch) & 0xffffff) == 0 && o < src - MINOFFSET) +#endif + { + m = 3; + while(*(o + m) == *(src + m) && m < remaining) + m++; +#if QLZ_COMPRESSION_LEVEL == 3 + if ((m > matchlen) || (m == matchlen && o > offset2)) +#elif QLZ_COMPRESSION_LEVEL == 2 + if (m > matchlen) +#endif + { + offset2 = o; + matchlen = m; + best_k = k; + } + } + } + o = offset2; + state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = src; + c++; + state->hash_counter[hash] = c; + +#if QLZ_COMPRESSION_LEVEL == 3 + if(matchlen > 2 && src - o < 131071) + { + ui32 u; + size_t offset = src - o; + + for(u = 1; u < matchlen; u++) + { + hash = hashat(src + u); + c = state->hash_counter[hash]++; + state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = src + u; + } + + cword_val = (cword_val >> 1) | (1U << 31); + src += matchlen; + + if(matchlen == 3 && offset <= 63) + { + *dst = (unsigned char)(offset << 2); + dst++; + } + else if (matchlen == 3 && offset <= 16383) + { + ui32 f = (ui32)((offset << 2) | 1); + fast_write(f, dst, 2); + dst += 2; + } + else if (matchlen <= 18 && offset <= 1023) + { + ui32 f = ((matchlen - 3) << 2) | ((ui32)offset << 6) | 2; + fast_write(f, dst, 2); + dst += 2; + } + + else if(matchlen <= 33) + { + ui32 f = ((matchlen - 2) << 2) | ((ui32)offset << 7) | 3; + fast_write(f, dst, 3); + dst += 3; + } + else + { + ui32 f = ((matchlen - 3) << 7) | ((ui32)offset << 15) | 3; + fast_write(f, dst, 4); + dst += 4; + } + } + else + { + *dst = *src; + src++; + dst++; + cword_val = (cword_val >> 1); + } +#elif QLZ_COMPRESSION_LEVEL == 2 + + if(matchlen > 2) + { + cword_val = (cword_val >> 1) | (1U << 31); + src += matchlen; + + if (matchlen < 10) + { + ui32 f = best_k | ((matchlen - 2) << 2) | (hash << 5); + fast_write(f, dst, 2); + dst += 2; + } + else + { + ui32 f = best_k | (matchlen << 16) | (hash << 5); + fast_write(f, dst, 3); + dst += 3; + } + } + else + { + *dst = *src; + src++; + dst++; + cword_val = (cword_val >> 1); + } +#endif + } +#endif + } + while (src <= last_byte) + { + if ((cword_val & 1) == 1) + { + fast_write((cword_val >> 1) | (1U << 31), cword_ptr, CWORD_LEN); + cword_ptr = dst; + dst += CWORD_LEN; + cword_val = 1U << 31; + } +#if QLZ_COMPRESSION_LEVEL < 3 + if (src <= last_byte - 3) + { +#if QLZ_COMPRESSION_LEVEL == 1 + ui32 hash, fetch; + fetch = fast_read(src, 3); + hash = hash_func(fetch); + state->hash[hash].offset = CAST(src - OFFSET_BASE); + state->hash[hash].cache = fetch; +#elif QLZ_COMPRESSION_LEVEL == 2 + ui32 hash; + unsigned char c; + hash = hashat(src); + c = state->hash_counter[hash]; + state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = src; + c++; + state->hash_counter[hash] = c; +#endif + } +#endif + *dst = *src; + src++; + dst++; + cword_val = (cword_val >> 1); + } + + while((cword_val & 1) != 1) + cword_val = (cword_val >> 1); + + fast_write((cword_val >> 1) | (1U << 31), cword_ptr, CWORD_LEN); + + // min. size must be 9 bytes so that the qlz_size functions can take 9 bytes as argument + return dst - destination < 9 ? 9 : dst - destination; +} + +static size_t qlz_decompress_core(const unsigned char *source, unsigned char *destination, size_t size, qlz_state_decompress *state, const unsigned char *history) +{ + const unsigned char *src = source + qlz_size_header((const char *)source); + unsigned char *dst = destination; + const unsigned char *last_destination_byte = destination + size - 1; + ui32 cword_val = 1; + const unsigned char *last_matchstart = last_destination_byte - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END; + unsigned char *last_hashed = destination - 1; + const unsigned char *last_source_byte = source + qlz_size_compressed((const char *)source) - 1; + static const ui32 bitlut[16] = {4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0}; + + (void) last_source_byte; + (void) last_hashed; + (void) state; + (void) history; + + for(;;) + { + ui32 fetch; + + if (cword_val == 1) + { +#ifdef QLZ_MEMORY_SAFE + if(src + CWORD_LEN - 1 > last_source_byte) + return 0; +#endif + cword_val = fast_read(src, CWORD_LEN); + src += CWORD_LEN; + } + +#ifdef QLZ_MEMORY_SAFE + if(src + 4 - 1 > last_source_byte) + return 0; +#endif + + fetch = fast_read(src, 4); + + if ((cword_val & 1) == 1) + { + ui32 matchlen; + const unsigned char *offset2; + +#if QLZ_COMPRESSION_LEVEL == 1 + ui32 hash; + cword_val = cword_val >> 1; + hash = (fetch >> 4) & 0xfff; + offset2 = (const unsigned char *)(size_t)state->hash[hash].offset; + + if((fetch & 0xf) != 0) + { + matchlen = (fetch & 0xf) + 2; + src += 2; + } + else + { + matchlen = *(src + 2); + src += 3; + } + +#elif QLZ_COMPRESSION_LEVEL == 2 + ui32 hash; + unsigned char c; + cword_val = cword_val >> 1; + hash = (fetch >> 5) & 0x7ff; + c = (unsigned char)(fetch & 0x3); + offset2 = state->hash[hash].offset[c]; + + if((fetch & (28)) != 0) + { + matchlen = ((fetch >> 2) & 0x7) + 2; + src += 2; + } + else + { + matchlen = *(src + 2); + src += 3; + } + +#elif QLZ_COMPRESSION_LEVEL == 3 + ui32 offset; + cword_val = cword_val >> 1; + if ((fetch & 3) == 0) + { + offset = (fetch & 0xff) >> 2; + matchlen = 3; + src++; + } + else if ((fetch & 2) == 0) + { + offset = (fetch & 0xffff) >> 2; + matchlen = 3; + src += 2; + } + else if ((fetch & 1) == 0) + { + offset = (fetch & 0xffff) >> 6; + matchlen = ((fetch >> 2) & 15) + 3; + src += 2; + } + else if ((fetch & 127) != 3) + { + offset = (fetch >> 7) & 0x1ffff; + matchlen = ((fetch >> 2) & 0x1f) + 2; + src += 3; + } + else + { + offset = (fetch >> 15); + matchlen = ((fetch >> 7) & 255) + 3; + src += 4; + } + + offset2 = dst - offset; +#endif + +#ifdef QLZ_MEMORY_SAFE + if(offset2 < history || offset2 > dst - MINOFFSET - 1) + return 0; + + if(matchlen > (ui32)(last_destination_byte - dst - UNCOMPRESSED_END + 1)) + return 0; +#endif + + memcpy_up(dst, offset2, matchlen); + dst += matchlen; + +#if QLZ_COMPRESSION_LEVEL <= 2 + update_hash_upto(state, &last_hashed, dst - matchlen); + last_hashed = dst - 1; +#endif + } + else + { + if (dst < last_matchstart) + { + unsigned int n = bitlut[cword_val & 0xf]; +#ifdef X86X64 + *(ui32 *)dst = *(ui32 *)src; +#else + memcpy_up(dst, src, 4); +#endif + cword_val = cword_val >> n; + dst += n; + src += n; +#if QLZ_COMPRESSION_LEVEL <= 2 + update_hash_upto(state, &last_hashed, dst - 3); +#endif + } + else + { + while(dst <= last_destination_byte) + { + if (cword_val == 1) + { + src += CWORD_LEN; + cword_val = 1U << 31; + } +#ifdef QLZ_MEMORY_SAFE + if(src >= last_source_byte + 1) + return 0; +#endif + *dst = *src; + dst++; + src++; + cword_val = cword_val >> 1; + } + +#if QLZ_COMPRESSION_LEVEL <= 2 + update_hash_upto(state, &last_hashed, last_destination_byte - 3); // todo, use constant +#endif + return size; + } + + } + } +} + +size_t qlz_compress(const void *source, char *destination, size_t size, qlz_state_compress *state) +{ + size_t r; + ui32 compressed; + size_t base; + + if(size == 0 || size > 0xffffffff - 400) + return 0; + + if(size < 216) + base = 3; + else + base = 9; + +#if QLZ_STREAMING_BUFFER > 0 + if (state->stream_counter + size - 1 >= QLZ_STREAMING_BUFFER) +#endif + { + reset_table_compress(state); + r = base + qlz_compress_core((const unsigned char *)source, (unsigned char*)destination + base, size, state); +#if QLZ_STREAMING_BUFFER > 0 + reset_table_compress(state); +#endif + if(r == base) + { + memcpy(destination + base, source, size); + r = size + base; + compressed = 0; + } + else + { + compressed = 1; + } + state->stream_counter = 0; + } +#if QLZ_STREAMING_BUFFER > 0 + else + { + unsigned char *src = state->stream_buffer + state->stream_counter; + + memcpy(src, source, size); + r = base + qlz_compress_core(src, (unsigned char*)destination + base, size, state); + + if(r == base) + { + memcpy(destination + base, src, size); + r = size + base; + compressed = 0; + reset_table_compress(state); + } + else + { + compressed = 1; + } + state->stream_counter += size; + } +#endif + if(base == 3) + { + *destination = (unsigned char)(0 | compressed); + *(destination + 1) = (unsigned char)r; + *(destination + 2) = (unsigned char)size; + } + else + { + *destination = (unsigned char)(2 | compressed); + fast_write((ui32)r, destination + 1, 4); + fast_write((ui32)size, destination + 5, 4); + } + + *destination |= (QLZ_COMPRESSION_LEVEL << 2); + *destination |= (1 << 6); + *destination |= ((QLZ_STREAMING_BUFFER == 0 ? 0 : (QLZ_STREAMING_BUFFER == 100000 ? 1 : (QLZ_STREAMING_BUFFER == 1000000 ? 2 : 3))) << 4); + +// 76543210 +// 01SSLLHC + + return r; +} + +size_t qlz_decompress(const char *source, void *destination, qlz_state_decompress *state) +{ + size_t dsiz = qlz_size_decompressed(source); + +#if QLZ_STREAMING_BUFFER > 0 + if (state->stream_counter + qlz_size_decompressed(source) - 1 >= QLZ_STREAMING_BUFFER) +#endif + { + if((*source & 1) == 1) + { + reset_table_decompress(state); + dsiz = qlz_decompress_core((const unsigned char *)source, (unsigned char *)destination, dsiz, state, (const unsigned char *)destination); + } + else + { + memcpy(destination, source + qlz_size_header(source), dsiz); + } + state->stream_counter = 0; + reset_table_decompress(state); + } +#if QLZ_STREAMING_BUFFER > 0 + else + { + unsigned char *dst = state->stream_buffer + state->stream_counter; + if((*source & 1) == 1) + { + dsiz = qlz_decompress_core((const unsigned char *)source, dst, dsiz, state, (const unsigned char *)state->stream_buffer); + } + else + { + memcpy(dst, source + qlz_size_header(source), dsiz); + reset_table_decompress(state); + } + memcpy(destination, dst, dsiz); + state->stream_counter += dsiz; + } +#endif + return dsiz; +} + diff --git a/polymer/eduke32/build/src/sdlayer.c b/polymer/eduke32/build/src/sdlayer.c index 6830bfe79..82e9cd858 100644 --- a/polymer/eduke32/build/src/sdlayer.c +++ b/polymer/eduke32/build/src/sdlayer.c @@ -89,7 +89,7 @@ static char keytranslation[SDL_NUM_SCANCODES]; static int32_t buildkeytranslationtable(void); //static SDL_Surface * loadtarga(const char *fn); // for loading the icon -static SDL_Surface * appicon; +static SDL_Surface * appicon = NULL; static SDL_Surface * loadappicon(void); int32_t wm_msgbox(char *name, char *fmt, ...) @@ -337,7 +337,10 @@ void uninitsystem(void) uninittimer(); if (appicon) + { SDL_FreeSurface(appicon); + appicon = NULL; + } SDL_Quit(); diff --git a/polymer/eduke32/build/src/winlayer.c b/polymer/eduke32/build/src/winlayer.c index 9a2643baf..1b0f8407d 100644 --- a/polymer/eduke32/build/src/winlayer.c +++ b/polymer/eduke32/build/src/winlayer.c @@ -3405,6 +3405,8 @@ static int32_t SetupOpenGL(int32_t width, int32_t height, int32_t bitspp) { if (!Bstrcmp(glinfo.renderer,"Intel 865G")) err = 0; + else if (!Bstrcmp(glinfo.renderer,"Intel 915G")) + err = 0; else if (!Bstrcmp(glinfo.renderer,"Intel 945GM")) err = 0; else if (!Bstrcmp(glinfo.renderer,"Intel 965/963 Graphics Media Accelerator")) diff --git a/polymer/eduke32/eduke32.vcproj b/polymer/eduke32/eduke32.vcproj index 5a7a4e006..f992eacc0 100644 --- a/polymer/eduke32/eduke32.vcproj +++ b/polymer/eduke32/eduke32.vcproj @@ -108,10 +108,6 @@ RelativePath=".\build\include\enet_mmulti.h" > - - @@ -152,10 +148,6 @@ RelativePath=".\build\include\mmulti_unstable.h" > - - @@ -184,6 +176,10 @@ RelativePath=".\build\include\pragmas.h" > + + @@ -260,10 +256,6 @@ RelativePath=".\build\src\engine_priv.h" > - - @@ -316,6 +308,10 @@ RelativePath=".\build\src\pragmas.c" > + + @@ -778,6 +774,86 @@ Name="Misc" > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/polymer/eduke32/source/actors.c b/polymer/eduke32/source/actors.c index 97011658e..889056319 100644 --- a/polymer/eduke32/source/actors.c +++ b/polymer/eduke32/source/actors.c @@ -29,6 +29,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. extern int32_t g_numEnvSoundsPlaying; extern int32_t g_noEnemies; +extern int32_t ticrandomseed; inline void G_UpdateInterpolations(void) //Stick at beginning of G_DoMoveThings { @@ -4832,6 +4833,9 @@ static void G_MoveMisc(void) // STATNUM 5 ActorExtra[i].floorz = s->z = getflorzofslope(s->sectnum,s->x,s->y); else switch (DynamicTileMap[switchpicnum]) { + case APLAYER__STATIC: + s->cstat = 32768; + goto BOLT; case NEON1__STATIC: case NEON2__STATIC: case NEON3__STATIC: @@ -5670,7 +5674,7 @@ static void G_MoveEffectors(void) //STATNUM 3 m = (s->xvel*sintable[(s->ang+512)&2047])>>14; x = (s->xvel*sintable[s->ang&2047])>>14; - for (p = connecthead; p >= 0; p=connectpoint2[p]) + TRAVERSE_CONNECT(p) if (sector[g_player[p].ps->cursectnum].lotag != 2) { if (g_playerSpawnPoints[p].os == s->sectnum) @@ -5849,7 +5853,7 @@ static void G_MoveEffectors(void) //STATNUM 3 } } - for (p = connecthead; p >= 0; p = connectpoint2[p]) + TRAVERSE_CONNECT(p) { if (sprite[g_player[p].ps->i].sectnum == s->sectnum) { @@ -7135,7 +7139,7 @@ static void G_MoveEffectors(void) //STATNUM 3 fricyv += x<<5; } - for (p = connecthead; p >= 0; p = connectpoint2[p]) + TRAVERSE_CONNECT(p) if (sprite[g_player[p].ps->i].sectnum == s->sectnum && g_player[p].ps->on_ground) g_player[p].ps->posz += s->zvel; diff --git a/polymer/eduke32/source/astub.c b/polymer/eduke32/source/astub.c index d0a2c9b96..f9c4a0fa2 100644 --- a/polymer/eduke32/source/astub.c +++ b/polymer/eduke32/source/astub.c @@ -42,7 +42,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "fx_man.h" #include "macros.h" -#include "fastlz.h" +#include "quicklz.h" #include "m32script.h" #include "m32def.h" @@ -244,8 +244,8 @@ void create_map_snapshot(void) else { mapstate->sectors = (sectortype *)Bcalloc(1, sizeof(sectortype) * numsectors); - mapstate->sectsiz = j = fastlz_compress(§or[0], sizeof(sectortype) * numsectors, - &mapstate->sectors[0]/*, sizeof(sectortype) * numsectors*/); + mapstate->sectsiz = j = qlz_compress(§or[0], (char *)&mapstate->sectors[0], + sizeof(sectortype) * numsectors, state_compress); mapstate->sectors = (sectortype *)Brealloc(mapstate->sectors, j); mapstate->sectcrc = tempcrc; } @@ -265,8 +265,8 @@ void create_map_snapshot(void) else { mapstate->walls = (walltype *)Bcalloc(1, sizeof(walltype) * numwalls); - mapstate->wallsiz = j = fastlz_compress(&wall[0], sizeof(walltype) * numwalls, - &mapstate->walls[0]/*, sizeof(walltype) * numwalls*/); + mapstate->wallsiz = j = qlz_compress(&wall[0], (char *)&mapstate->walls[0], + sizeof(walltype) * numwalls, state_compress); mapstate->walls = (walltype *)Brealloc(mapstate->walls, j); mapstate->wallcrc = tempcrc; } @@ -298,8 +298,8 @@ void create_map_snapshot(void) i++; } } - mapstate->spritesiz = j = fastlz_compress(&tspri[0], sizeof(spritetype) * numsprites, - &mapstate->sprites[0]/*, sizeof(spritetype) * numsprites*/); + mapstate->spritesiz = j = qlz_compress(&tspri[0], (char *)&mapstate->sprites[0], + sizeof(spritetype) * numsprites, state_compress); mapstate->sprites = (spritetype *)Brealloc(mapstate->sprites, j); mapstate->spritecrc = tempcrc; Bfree(tspri); @@ -370,13 +370,13 @@ int32_t map_undoredo(int32_t dir) if (mapstate->numsectors) { - fastlz_decompress(&mapstate->sectors[0], mapstate->sectsiz, §or[0], sizeof(sectortype) * numsectors); + qlz_decompress((const char *)&mapstate->sectors[0], §or[0], state_decompress); if (mapstate->numwalls) - fastlz_decompress(&mapstate->walls[0], mapstate->wallsiz, &wall[0], sizeof(walltype) * numwalls); + qlz_decompress((const char *)&mapstate->walls[0], &wall[0], state_decompress); if (mapstate->numsprites) - fastlz_decompress(&mapstate->sprites[0], mapstate->spritesiz, &sprite[0], sizeof(spritetype) * numsprites); + qlz_decompress((const char *)&mapstate->sprites[0], &sprite[0], state_decompress); } updatenumsprites(); diff --git a/polymer/eduke32/source/duke3d.h b/polymer/eduke32/source/duke3d.h index d73804000..3a47940bb 100644 --- a/polymer/eduke32/source/duke3d.h +++ b/polymer/eduke32/source/duke3d.h @@ -47,6 +47,12 @@ extern "C" { #include "macros.h" +#include "enet/enet.h" + +extern ENetHost * net_server; +extern ENetHost * net_client; +extern ENetPeer * net_peer; + #define APPNAME "EDuke32" #define VERSION " 2.0.0devel" // this is checked against http://eduke32.com/VERSION @@ -83,7 +89,7 @@ extern int32_t g_scriptVersion, g_Shareware, g_gameType; #define AUTO_AIM_ANGLE 48 #define RECSYNCBUFSIZ 2520 //2520 is the (LCM of 1-8)*3 -#define MOVEFIFOSIZ 256 +#define MOVEFIFOSIZ 2 #define FOURSLEIGHT (1<<8) @@ -422,9 +428,9 @@ extern int32_t fricxv,fricyv; // mywhatever type globals typedef struct { - int32_t posx, posy, posz, horiz, ohoriz, ohorizoff, invdisptime; - int32_t bobposx, bobposy, oposx, oposy, oposz, pyoff, opyoff; - int32_t posxv, posyv, poszv, last_pissed_time, truefz, truecz; + int32_t posx, posy, posz, oposx, oposy, oposz, posxv, posyv, poszv; + int32_t bobposx, bobposy, pyoff, opyoff, horiz, ohoriz, ohorizoff, invdisptime; + int32_t last_pissed_time, truefz, truecz; int32_t player_par, visibility; int32_t bobcounter, weapon_sway; int32_t pals_time, randomflamex, crack_time; @@ -485,7 +491,7 @@ typedef struct { char name[32]; } DukePlayer_t; -extern char tempbuf[2048], packbuf[576], menutextbuf[128]; +extern char tempbuf[2048], packbuf[4096], menutextbuf[128]; extern int32_t g_spriteGravity; @@ -559,9 +565,9 @@ typedef struct { void *lightptr; #endif - int8_t filler[16]; // pad struct to 128 bytes - projectile_t *projectile; //4b/8b + + int8_t filler[16]; // pad struct to 128 bytes } ActorData_t; extern ActorData_t ActorExtra[MAXSPRITES]; @@ -638,8 +644,6 @@ extern char boardfilename[BMAX_PATH]; extern uint8_t waterpal[768],slimepal[768],titlepal[768],drealms[768],endingpal[768],animpal[768]; extern char currentboardfilename[BMAX_PATH]; extern char cachedebug,g_earthquakeTime; -// 0: master/slave, 1: peer-to-peer -extern int32_t g_networkBroadcastMode; extern char lumplockbyte[11]; //DUKE3D.H - replace the end "my's" with this @@ -670,7 +674,6 @@ typedef struct { extern DukeStatus_t sbar; extern int32_t g_cameraDistance, g_cameraClock, g_playerFriction,g_showShareware; -extern int32_t g_networkBroadcastMode, g_movesPerPacket; extern int32_t g_gameQuit; extern int32_t playerswhenstarted; @@ -1042,6 +1045,9 @@ typedef struct { walltype wall[MAXWALLS]; } mapstate_t; +extern void G_SaveMapState(mapstate_t *save); +extern void G_RestoreMapState(mapstate_t *save); + typedef struct { int32_t partime, designertime; char *name, *filename, *musicfn, *alt_musicfn; @@ -1088,12 +1094,13 @@ enum DukePacket_t { PACKET_MASTER_TO_SLAVE, PACKET_SLAVE_TO_MASTER, - PACKET_BROADCAST, - SERVER_GENERATED_BROADCAST, PACKET_VERSION, /* don't change anything above this line */ + PACKET_NUM_PLAYERS, + PACKET_PLAYER_INDEX, + PACKET_PLAYER_DISCONNECTED, PACKET_MESSAGE, PACKET_NEW_GAME, @@ -1103,6 +1110,7 @@ enum DukePacket_t PACKET_PLAYER_OPTIONS, PACKET_PLAYER_NAME, + PACKET_REQUEST_GAMESTATE, PACKET_USER_MAP, PACKET_MAP_VOTE, diff --git a/polymer/eduke32/source/enet/Makefile b/polymer/eduke32/source/enet/Makefile new file mode 100644 index 000000000..e7558d5b7 --- /dev/null +++ b/polymer/eduke32/source/enet/Makefile @@ -0,0 +1,60 @@ +CC=gcc +OBJ=obj +OBJNAME?=libenet.a +PRETTY_OUTPUT?=1 +EROOT?=build +RELEASE?=1 +OPTLEVEL?=2 +SRC=src + +include ../../$(EROOT)/Makefile.shared + +ifneq (0,$(RELEASE)) + # Debugging disabled + debug=-fomit-frame-pointer -funswitch-loops -O$(OPTLEVEL) +else + # Debugging enabled + debug=-ggdb -O0 -DDEBUGGINGAIDS +endif + +ifneq (0,$(DEBUGANYWAY)) + debug+=-ggdb +endif + +CFLAGS=$(debug) -W -Wall -Wimplicit -Werror-implicit-function-declaration \ + -funsigned-char -fno-strict-aliasing -DNO_GCC_BUILTINS -D_FORTIFY_SOURCE=2 \ + -fjump-tables -fno-stack-protector + +CPPFLAGS=-Iinclude -Isrc -DHAVE_VORBIS + +OBJECTS=$(OBJ)/callbacks.o \ + $(OBJ)/host.o \ + $(OBJ)/list.o \ + $(OBJ)/packet.o \ + $(OBJ)/peer.o \ + $(OBJ)/protocol.o + +ifeq ($(PLATFORM),WINDOWS) + OBJECTS+= $(OBJ)/win32.o + OBJNAME=libenet_win32.a + OBJ=obj_win +else + OBJECTS+= $(OBJ)/unix.o +endif + +# OBJECTS=$(SOURCES:%.c=$(OBJ)/%.o) + +$(OBJNAME): $(OBJECTS) + $(AR) cr $@ $^ + +$(OBJECTS): $(OBJ)/%.o: $(SRC)/%.c + -mkdir -p $(OBJ) + $(COMPILE_STATUS) + if $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@; then $(COMPILE_OK); else $(COMPILE_FAILED); fi + +ifeq ($(PRETTY_OUTPUT),1) +.SILENT: +endif +.PHONY: clean +clean: + -rm -f $(OBJECTS) $(OBJNAME) diff --git a/polymer/eduke32/source/enet/Makefile.msvc b/polymer/eduke32/source/enet/Makefile.msvc new file mode 100644 index 000000000..9de19bd0a --- /dev/null +++ b/polymer/eduke32/source/enet/Makefile.msvc @@ -0,0 +1,45 @@ +OBJ=obj.msc +INC=include +SRC=src +ENETLIB=libenet.lib + +!ifdef DEBUG +# debugging options +flags_cl=/Od /Zi +flags_link=/DEBUG +flags_lib= +!else +# release options +flags_cl=/Ox /GL /arch:SSE +flags_link=/RELEASE /LTCG +flags_lib=/LTCG +!endif + +CC=cl +LINK=link /opt:ref /nologo + +CFLAGS=$(CFLAGS) /nologo /MT /J $(flags_cl) $(TARGETOPTS) /I$(INC) /I$(SRC) +!ifdef DEBUG +CFLAGS=$(CFLAGS) /DDEBUGGINGAIDS +!endif + +CFLAGS=$(CFLAGS) /DRENDERTYPE$(RENDERTYPE)=1 /D "_CRT_SECURE_NO_DEPRECATE" /W2 /DHAVE_VORBIS /Iinclude/msvc /DWIN32 + +OBJECTS=$(OBJ)\callbacks.o \ + $(OBJ)\host.o \ + $(OBJ)\list.o \ + $(OBJ)\packet.o \ + $(OBJ)\peer.o \ + $(OBJ)\protocol.o \ + $(OBJ)\win32.o + +{$(SRC)}.c{$(OBJ)}.o: + $(CC) /c $(CFLAGS) /Fo$@ $< + +enet: $(ENETLIB) +$(ENETLIB): $(OBJECTS) + lib $(flags_lib) /out:$@ /nologo $** + +clean: + -del /Q $(OBJ)\* $(ENETLIB) + diff --git a/polymer/eduke32/source/enet/include/enet/callbacks.h b/polymer/eduke32/source/enet/include/enet/callbacks.h new file mode 100644 index 000000000..be29ae057 --- /dev/null +++ b/polymer/eduke32/source/enet/include/enet/callbacks.h @@ -0,0 +1,28 @@ +/** + @file callbacks.h + @brief ENet callbacks +*/ +#ifndef __ENET_CALLBACKS_H__ +#define __ENET_CALLBACKS_H__ + +#include + +typedef struct +{ + void * (ENET_CALLBACK * malloc) (size_t size); + void (ENET_CALLBACK * free) (void * memory); + int (ENET_CALLBACK * rand) (void); +} ENetCallbacks; + +/** @defgroup callbacks ENet internal callbacks + @{ + @ingroup private +*/ +extern void * enet_malloc (size_t); +extern void enet_free (void *); +extern int enet_rand (void); + +/** @} */ + +#endif /* __ENET_CALLBACKS_H__ */ + diff --git a/polymer/eduke32/source/enet/include/enet/enet.h b/polymer/eduke32/source/enet/include/enet/enet.h new file mode 100644 index 000000000..cf7b2d078 --- /dev/null +++ b/polymer/eduke32/source/enet/include/enet/enet.h @@ -0,0 +1,492 @@ +/** + @file enet.h + @brief ENet public header file +*/ +#ifndef __ENET_ENET_H__ +#define __ENET_ENET_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#ifdef WIN32 +#include "enet/win32.h" +#else +#include "enet/unix.h" +#endif + +#include "enet/types.h" +#include "enet/protocol.h" +#include "enet/list.h" +#include "enet/callbacks.h" + +typedef enum +{ + ENET_VERSION = 1 +} ENetVersion; + +typedef enum +{ + ENET_SOCKET_TYPE_STREAM = 1, + ENET_SOCKET_TYPE_DATAGRAM = 2 +} ENetSocketType; + +typedef enum +{ + ENET_SOCKET_WAIT_NONE = 0, + ENET_SOCKET_WAIT_SEND = (1 << 0), + ENET_SOCKET_WAIT_RECEIVE = (1 << 1) +} ENetSocketWait; + +typedef enum +{ + ENET_SOCKOPT_NONBLOCK = 1, + ENET_SOCKOPT_BROADCAST = 2, + ENET_SOCKOPT_RCVBUF = 3, + ENET_SOCKOPT_SNDBUF = 4, + ENET_SOCKOPT_REUSEADDR = 5 +} ENetSocketOption; + +enum +{ + ENET_HOST_ANY = 0, /**< specifies the default server host */ + ENET_HOST_BROADCAST = 0xFFFFFFFF, /**< specifies a subnet-wide broadcast */ + + ENET_PORT_ANY = 0 /**< specifies that a port should be automatically chosen */ +}; + +/** + * Portable internet address structure. + * + * The host must be specified in network byte-order, and the port must be in host + * byte-order. The constant ENET_HOST_ANY may be used to specify the default + * server host. The constant ENET_HOST_BROADCAST may be used to specify the + * broadcast address (255.255.255.255). This makes sense for enet_host_connect, + * but not for enet_host_create. Once a server responds to a broadcast, the + * address is updated from ENET_HOST_BROADCAST to the server's actual IP address. + */ +typedef struct _ENetAddress +{ + enet_uint32 host; + enet_uint16 port; +} ENetAddress; + +/** + * Packet flag bit constants. + * + * The host must be specified in network byte-order, and the port must be in + * host byte-order. The constant ENET_HOST_ANY may be used to specify the + * default server host. + + @sa ENetPacket +*/ +typedef enum +{ + /** packet must be received by the target peer and resend attempts should be + * made until the packet is delivered */ + ENET_PACKET_FLAG_RELIABLE = (1 << 0), + /** packet will not be sequenced with other packets + * not supported for reliable packets + */ + ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1), + /** packet will not allocate data, and user must supply it instead */ + ENET_PACKET_FLAG_NO_ALLOCATE = (1 << 2) +} ENetPacketFlag; + +struct _ENetPacket; +typedef void (ENET_CALLBACK * ENetPacketFreeCallback) (struct _ENetPacket *); + +/** + * ENet packet structure. + * + * An ENet data packet that may be sent to or received from a peer. The shown + * fields should only be read and never modified. The data field contains the + * allocated data for the packet. The dataLength fields specifies the length + * of the allocated data. The flags field is either 0 (specifying no flags), + * or a bitwise-or of any combination of the following flags: + * + * ENET_PACKET_FLAG_RELIABLE - packet must be received by the target peer + * and resend attempts should be made until the packet is delivered + * + * ENET_PACKET_FLAG_UNSEQUENCED - packet will not be sequenced with other packets + * (not supported for reliable packets) + * + * ENET_PACKET_FLAG_NO_ALLOCATE - packet will not allocate data, and user must supply it instead + + @sa ENetPacketFlag + */ +typedef struct _ENetPacket +{ + size_t referenceCount; /**< internal use only */ + enet_uint32 flags; /**< bitwise-or of ENetPacketFlag constants */ + enet_uint8 * data; /**< allocated data for packet */ + size_t dataLength; /**< length of data */ + ENetPacketFreeCallback freeCallback; /**< function to be called when the packet is no longer in use */ +} ENetPacket; + +typedef struct _ENetAcknowledgement +{ + ENetListNode acknowledgementList; + enet_uint32 sentTime; + ENetProtocol command; +} ENetAcknowledgement; + +typedef struct _ENetOutgoingCommand +{ + ENetListNode outgoingCommandList; + enet_uint16 reliableSequenceNumber; + enet_uint16 unreliableSequenceNumber; + enet_uint32 sentTime; + enet_uint32 roundTripTimeout; + enet_uint32 roundTripTimeoutLimit; + enet_uint32 fragmentOffset; + enet_uint16 fragmentLength; + enet_uint16 sendAttempts; + ENetProtocol command; + ENetPacket * packet; +} ENetOutgoingCommand; + +typedef struct _ENetIncomingCommand +{ + ENetListNode incomingCommandList; + enet_uint16 reliableSequenceNumber; + enet_uint16 unreliableSequenceNumber; + ENetProtocol command; + enet_uint32 fragmentCount; + enet_uint32 fragmentsRemaining; + enet_uint32 * fragments; + ENetPacket * packet; +} ENetIncomingCommand; + +typedef enum +{ + ENET_PEER_STATE_DISCONNECTED = 0, + ENET_PEER_STATE_CONNECTING = 1, + ENET_PEER_STATE_ACKNOWLEDGING_CONNECT = 2, + ENET_PEER_STATE_CONNECTION_PENDING = 3, + ENET_PEER_STATE_CONNECTION_SUCCEEDED = 4, + ENET_PEER_STATE_CONNECTED = 5, + ENET_PEER_STATE_DISCONNECT_LATER = 6, + ENET_PEER_STATE_DISCONNECTING = 7, + ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT = 8, + ENET_PEER_STATE_ZOMBIE = 9 +} ENetPeerState; + +#ifndef ENET_BUFFER_MAXIMUM +#define ENET_BUFFER_MAXIMUM (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS) +#endif + +enum +{ + ENET_HOST_RECEIVE_BUFFER_SIZE = 256 * 1024, + ENET_HOST_SEND_BUFFER_SIZE = 256 * 1024, + ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL = 1000, + ENET_HOST_DEFAULT_MTU = 1400, + + ENET_PEER_DEFAULT_ROUND_TRIP_TIME = 500, + ENET_PEER_DEFAULT_PACKET_THROTTLE = 32, + ENET_PEER_PACKET_THROTTLE_SCALE = 32, + ENET_PEER_PACKET_THROTTLE_COUNTER = 7, + ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2, + ENET_PEER_PACKET_THROTTLE_DECELERATION = 2, + ENET_PEER_PACKET_THROTTLE_INTERVAL = 5000, + ENET_PEER_PACKET_LOSS_SCALE = (1 << 16), + ENET_PEER_PACKET_LOSS_INTERVAL = 10000, + ENET_PEER_WINDOW_SIZE_SCALE = 64 * 1024, + ENET_PEER_TIMEOUT_LIMIT = 32, + ENET_PEER_TIMEOUT_MINIMUM = 5000, + ENET_PEER_TIMEOUT_MAXIMUM = 30000, + ENET_PEER_PING_INTERVAL = 500, + ENET_PEER_UNSEQUENCED_WINDOWS = 64, + ENET_PEER_UNSEQUENCED_WINDOW_SIZE = 1024, + ENET_PEER_FREE_UNSEQUENCED_WINDOWS = 32, + ENET_PEER_RELIABLE_WINDOWS = 16, + ENET_PEER_RELIABLE_WINDOW_SIZE = 0x1000, + ENET_PEER_FREE_RELIABLE_WINDOWS = 8 +}; + +typedef struct _ENetChannel +{ + enet_uint16 outgoingReliableSequenceNumber; + enet_uint16 outgoingUnreliableSequenceNumber; + enet_uint16 usedReliableWindows; + enet_uint16 reliableWindows [ENET_PEER_RELIABLE_WINDOWS]; + enet_uint16 incomingReliableSequenceNumber; + ENetList incomingReliableCommands; + ENetList incomingUnreliableCommands; +} ENetChannel; + +/** + * An ENet peer which data packets may be sent or received from. + * + * No fields should be modified unless otherwise specified. + */ +typedef struct _ENetPeer +{ + struct _ENetHost * host; + enet_uint16 outgoingPeerID; + enet_uint16 incomingPeerID; + enet_uint32 sessionID; + ENetAddress address; /**< Internet address of the peer */ + void * data; /**< Application private data, may be freely modified */ + ENetPeerState state; + ENetChannel * channels; + size_t channelCount; /**< Number of channels allocated for communication with peer */ + enet_uint32 incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */ + enet_uint32 outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */ + enet_uint32 incomingBandwidthThrottleEpoch; + enet_uint32 outgoingBandwidthThrottleEpoch; + enet_uint32 incomingDataTotal; + enet_uint32 outgoingDataTotal; + enet_uint32 lastSendTime; + enet_uint32 lastReceiveTime; + enet_uint32 nextTimeout; + enet_uint32 earliestTimeout; + enet_uint32 packetLossEpoch; + enet_uint32 packetsSent; + enet_uint32 packetsLost; + enet_uint32 packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */ + enet_uint32 packetLossVariance; + enet_uint32 packetThrottle; + enet_uint32 packetThrottleLimit; + enet_uint32 packetThrottleCounter; + enet_uint32 packetThrottleEpoch; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 packetThrottleInterval; + enet_uint32 lastRoundTripTime; + enet_uint32 lowestRoundTripTime; + enet_uint32 lastRoundTripTimeVariance; + enet_uint32 highestRoundTripTimeVariance; + enet_uint32 roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgement */ + enet_uint32 roundTripTimeVariance; + enet_uint16 mtu; + enet_uint32 windowSize; + enet_uint32 reliableDataInTransit; + enet_uint16 outgoingReliableSequenceNumber; + ENetList acknowledgements; + ENetList sentReliableCommands; + ENetList sentUnreliableCommands; + ENetList outgoingReliableCommands; + ENetList outgoingUnreliableCommands; + enet_uint16 incomingUnsequencedGroup; + enet_uint16 outgoingUnsequencedGroup; + enet_uint32 unsequencedWindow [ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32]; + enet_uint32 disconnectData; +} ENetPeer; + +/** An ENet host for communicating with peers. + * + * No fields should be modified. + + @sa enet_host_create() + @sa enet_host_destroy() + @sa enet_host_connect() + @sa enet_host_service() + @sa enet_host_flush() + @sa enet_host_broadcast() + @sa enet_host_bandwidth_limit() + @sa enet_host_bandwidth_throttle() + */ +typedef struct _ENetHost +{ + ENetSocket socket; + ENetAddress address; /**< Internet address of the host */ + enet_uint32 incomingBandwidth; /**< downstream bandwidth of the host */ + enet_uint32 outgoingBandwidth; /**< upstream bandwidth of the host */ + enet_uint32 bandwidthThrottleEpoch; + enet_uint32 mtu; + int recalculateBandwidthLimits; + ENetPeer * peers; /**< array of peers allocated for this host */ + size_t peerCount; /**< number of peers allocated for this host */ + enet_uint32 serviceTime; + ENetPeer * lastServicedPeer; + int continueSending; + size_t packetSize; + enet_uint16 headerFlags; + ENetProtocol commands [ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS]; + size_t commandCount; + ENetBuffer buffers [ENET_BUFFER_MAXIMUM]; + size_t bufferCount; + ENetAddress receivedAddress; + enet_uint8 receivedData [ENET_PROTOCOL_MAXIMUM_MTU]; + size_t receivedDataLength; +} ENetHost; + +/** + * An ENet event type, as specified in @ref ENetEvent. + */ +typedef enum +{ + /** no event occurred within the specified time limit */ + ENET_EVENT_TYPE_NONE = 0, + + /** a connection request initiated by enet_host_connect has completed. + * The peer field contains the peer which successfully connected. + */ + ENET_EVENT_TYPE_CONNECT = 1, + + /** a peer has disconnected. This event is generated on a successful + * completion of a disconnect initiated by enet_pper_disconnect, if + * a peer has timed out, or if a connection request intialized by + * enet_host_connect has timed out. The peer field contains the peer + * which disconnected. The data field contains user supplied data + * describing the disconnection, or 0, if none is available. + */ + ENET_EVENT_TYPE_DISCONNECT = 2, + + /** a packet has been received from a peer. The peer field specifies the + * peer which sent the packet. The channelID field specifies the channel + * number upon which the packet was received. The packet field contains + * the packet that was received; this packet must be destroyed with + * enet_packet_destroy after use. + */ + ENET_EVENT_TYPE_RECEIVE = 3 +} ENetEventType; + +/** + * An ENet event as returned by enet_host_service(). + + @sa enet_host_service + */ +typedef struct _ENetEvent +{ + ENetEventType type; /**< type of the event */ + ENetPeer * peer; /**< peer that generated a connect, disconnect or receive event */ + enet_uint8 channelID; /**< channel on the peer that generated the event, if appropriate */ + enet_uint32 data; /**< data associated with the event, if appropriate */ + ENetPacket * packet; /**< packet associated with the event, if appropriate */ +} ENetEvent; + +/** @defgroup global ENet global functions + @{ +*/ + +/** + Initializes ENet globally. Must be called prior to using any functions in + ENet. + @returns 0 on success, < 0 on failure +*/ +ENET_API int enet_initialize (void); + +/** + Initializes ENet globally and supplies user-overridden callbacks. Must be called prior to using any functions in ENet. Do not use enet_initialize() if you use this variant. + + @param version the constant ENET_VERSION should be supplied so ENet knows which version of ENetCallbacks struct to use + @param inits user-overriden callbacks where any NULL callbacks will use ENet's defaults + @returns 0 on success, < 0 on failure +*/ +ENET_API int enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits); + +/** + Shuts down ENet globally. Should be called when a program that has + initialized ENet exits. +*/ +ENET_API void enet_deinitialize (void); + +/** @} */ + +/** @defgroup private ENet private implementation functions */ + +/** + Returns the wall-time in milliseconds. Its initial value is unspecified + unless otherwise set. + */ +ENET_API enet_uint32 enet_time_get (void); +/** + Sets the current wall-time in milliseconds. + */ +ENET_API void enet_time_set (enet_uint32); + +/** @defgroup socket ENet socket functions + @{ +*/ +ENET_API ENetSocket enet_socket_create (ENetSocketType); +ENET_API int enet_socket_bind (ENetSocket, const ENetAddress *); +ENET_API int enet_socket_listen (ENetSocket, int); +ENET_API ENetSocket enet_socket_accept (ENetSocket, ENetAddress *); +ENET_API int enet_socket_connect (ENetSocket, const ENetAddress *); +ENET_API int enet_socket_send (ENetSocket, const ENetAddress *, const ENetBuffer *, size_t); +ENET_API int enet_socket_receive (ENetSocket, ENetAddress *, ENetBuffer *, size_t); +ENET_API int enet_socket_wait (ENetSocket, enet_uint32 *, enet_uint32); +ENET_API int enet_socket_set_option (ENetSocket, ENetSocketOption, int); +ENET_API void enet_socket_destroy (ENetSocket); +ENET_API int enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSocketSet *, enet_uint32); + +/** @} */ + +/** @defgroup Address ENet address functions + @{ +*/ +/** Attempts to resolve the host named by the parameter hostName and sets + the host field in the address parameter if successful. + @param address destination to store resolved address + @param hostName host name to lookup + @retval 0 on success + @retval < 0 on failure + @returns the address of the given hostName in address on success +*/ +ENET_API int enet_address_set_host (ENetAddress * address, const char * hostName); + +/** Gives the printable form of the ip address specified in the address parameter. + @param address address printed + @param hostName destination for name, must not be NULL + @param nameLength maximum length of hostName. + @returns the null-terminated name of the host in hostName on success + @retval 0 on success + @retval < 0 on failure +*/ +ENET_API int enet_address_get_host_ip (const ENetAddress * address, char * hostName, size_t nameLength); + +/** Attempts to do a reverse lookup of the host field in the address parameter. + @param address address used for reverse lookup + @param hostName destination for name, must not be NULL + @param nameLength maximum length of hostName. + @returns the null-terminated name of the host in hostName on success + @retval 0 on success + @retval < 0 on failure +*/ +ENET_API int enet_address_get_host (const ENetAddress * address, char * hostName, size_t nameLength); + +/** @} */ + +ENET_API ENetPacket * enet_packet_create (const void *, size_t, enet_uint32); +ENET_API void enet_packet_destroy (ENetPacket *); +ENET_API int enet_packet_resize (ENetPacket *, size_t); +extern enet_uint32 enet_crc32 (const ENetBuffer *, size_t); + +ENET_API ENetHost * enet_host_create (const ENetAddress *, size_t, enet_uint32, enet_uint32); +ENET_API void enet_host_destroy (ENetHost *); +ENET_API ENetPeer * enet_host_connect (ENetHost *, const ENetAddress *, size_t); +ENET_API int enet_host_check_events (ENetHost *, ENetEvent *); +ENET_API int enet_host_service (ENetHost *, ENetEvent *, enet_uint32); +ENET_API void enet_host_flush (ENetHost *); +ENET_API void enet_host_broadcast (ENetHost *, enet_uint8, ENetPacket *); +ENET_API void enet_host_bandwidth_limit (ENetHost *, enet_uint32, enet_uint32); +extern void enet_host_bandwidth_throttle (ENetHost *); + +ENET_API int enet_peer_send (ENetPeer *, enet_uint8, ENetPacket *); +ENET_API ENetPacket * enet_peer_receive (ENetPeer *, enet_uint8); +ENET_API void enet_peer_ping (ENetPeer *); +ENET_API void enet_peer_reset (ENetPeer *); +ENET_API void enet_peer_disconnect (ENetPeer *, enet_uint32); +ENET_API void enet_peer_disconnect_now (ENetPeer *, enet_uint32); +ENET_API void enet_peer_disconnect_later (ENetPeer *, enet_uint32); +ENET_API void enet_peer_throttle_configure (ENetPeer *, enet_uint32, enet_uint32, enet_uint32); +extern int enet_peer_throttle (ENetPeer *, enet_uint32); +extern void enet_peer_reset_queues (ENetPeer *); +extern ENetOutgoingCommand * enet_peer_queue_outgoing_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32, enet_uint16); +extern ENetIncomingCommand * enet_peer_queue_incoming_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32); +extern ENetAcknowledgement * enet_peer_queue_acknowledgement (ENetPeer *, const ENetProtocol *, enet_uint16); + +extern size_t enet_protocol_command_size (enet_uint8); + +#ifdef __cplusplus +} +#endif + +#endif /* __ENET_ENET_H__ */ + diff --git a/polymer/eduke32/source/enet/include/enet/list.h b/polymer/eduke32/source/enet/include/enet/list.h new file mode 100644 index 000000000..99bc4aeee --- /dev/null +++ b/polymer/eduke32/source/enet/include/enet/list.h @@ -0,0 +1,42 @@ +/** + @file list.h + @brief ENet list management +*/ +#ifndef __ENET_LIST_H__ +#define __ENET_LIST_H__ + +#include + +typedef struct _ENetListNode +{ + struct _ENetListNode * next; + struct _ENetListNode * previous; +} ENetListNode; + +typedef ENetListNode * ENetListIterator; + +typedef struct _ENetList +{ + ENetListNode sentinel; +} ENetList; + +extern void enet_list_clear (ENetList *); + +extern ENetListIterator enet_list_insert (ENetListIterator, void *); +extern void * enet_list_remove (ENetListIterator); + +extern size_t enet_list_size (ENetList *); + +#define enet_list_begin(list) ((list) -> sentinel.next) +#define enet_list_end(list) (& (list) -> sentinel) + +#define enet_list_empty(list) (enet_list_begin (list) == enet_list_end (list)) + +#define enet_list_next(iterator) ((iterator) -> next) +#define enet_list_previous(iterator) ((iterator) -> previous) + +#define enet_list_front(list) ((void *) (list) -> sentinel.next) +#define enet_list_back(list) ((void *) (list) -> sentinel.previous) + +#endif /* __ENET_LIST_H__ */ + diff --git a/polymer/eduke32/source/enet/include/enet/protocol.h b/polymer/eduke32/source/enet/include/enet/protocol.h new file mode 100644 index 000000000..363857bcc --- /dev/null +++ b/polymer/eduke32/source/enet/include/enet/protocol.h @@ -0,0 +1,174 @@ +/** + @file protocol.h + @brief ENet protocol +*/ +#ifndef __ENET_PROTOCOL_H__ +#define __ENET_PROTOCOL_H__ + +#include "enet/types.h" + +enum +{ + ENET_PROTOCOL_MINIMUM_MTU = 576, + ENET_PROTOCOL_MAXIMUM_MTU = 4096, + ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS = 32, + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE = 4096, + ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE = 32768, + ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT = 1, + ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT = 255, + ENET_PROTOCOL_MAXIMUM_PEER_ID = 0x7FFF +}; + +typedef enum +{ + ENET_PROTOCOL_COMMAND_NONE = 0, + ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1, + ENET_PROTOCOL_COMMAND_CONNECT = 2, + ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3, + ENET_PROTOCOL_COMMAND_DISCONNECT = 4, + ENET_PROTOCOL_COMMAND_PING = 5, + ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6, + ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7, + ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8, + ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9, + ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10, + ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11, + ENET_PROTOCOL_COMMAND_COUNT = 12, + + ENET_PROTOCOL_COMMAND_MASK = 0x0F +} ENetProtocolCommand; + +typedef enum +{ + ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7), + ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6), + + ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15), + ENET_PROTOCOL_HEADER_FLAG_MASK = 0x8000 +} ENetProtocolFlag; + +typedef struct +{ + enet_uint32 checksum; + enet_uint16 peerID; + enet_uint16 sentTime; +} ENetProtocolHeader; + +typedef struct +{ + enet_uint8 command; + enet_uint8 channelID; + enet_uint16 reliableSequenceNumber; +} ENetProtocolCommandHeader; + +typedef struct +{ + ENetProtocolCommandHeader header; + enet_uint16 receivedReliableSequenceNumber; + enet_uint16 receivedSentTime; +} ENetProtocolAcknowledge; + +typedef struct +{ + ENetProtocolCommandHeader header; + enet_uint16 outgoingPeerID; + enet_uint16 mtu; + enet_uint32 windowSize; + enet_uint32 channelCount; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 sessionID; +} ENetProtocolConnect; + +typedef struct +{ + ENetProtocolCommandHeader header; + enet_uint16 outgoingPeerID; + enet_uint16 mtu; + enet_uint32 windowSize; + enet_uint32 channelCount; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; +} ENetProtocolVerifyConnect; + +typedef struct +{ + ENetProtocolCommandHeader header; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; +} ENetProtocolBandwidthLimit; + +typedef struct +{ + ENetProtocolCommandHeader header; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; +} ENetProtocolThrottleConfigure; + +typedef struct +{ + ENetProtocolCommandHeader header; + enet_uint32 data; +} ENetProtocolDisconnect; + +typedef struct +{ + ENetProtocolCommandHeader header; +} ENetProtocolPing; + +typedef struct +{ + ENetProtocolCommandHeader header; + enet_uint16 dataLength; +} ENetProtocolSendReliable; + +typedef struct +{ + ENetProtocolCommandHeader header; + enet_uint16 unreliableSequenceNumber; + enet_uint16 dataLength; +} ENetProtocolSendUnreliable; + +typedef struct +{ + ENetProtocolCommandHeader header; + enet_uint16 unsequencedGroup; + enet_uint16 dataLength; +} ENetProtocolSendUnsequenced; + +typedef struct +{ + ENetProtocolCommandHeader header; + enet_uint16 startSequenceNumber; + enet_uint16 dataLength; + enet_uint32 fragmentCount; + enet_uint32 fragmentNumber; + enet_uint32 totalLength; + enet_uint32 fragmentOffset; +} ENetProtocolSendFragment; + +typedef union +{ + ENetProtocolCommandHeader header; + ENetProtocolAcknowledge acknowledge; + ENetProtocolConnect connect; + ENetProtocolVerifyConnect verifyConnect; + ENetProtocolDisconnect disconnect; + ENetProtocolPing ping; + ENetProtocolSendReliable sendReliable; + ENetProtocolSendUnreliable sendUnreliable; + ENetProtocolSendUnsequenced sendUnsequenced; + ENetProtocolSendFragment sendFragment; + ENetProtocolBandwidthLimit bandwidthLimit; + ENetProtocolThrottleConfigure throttleConfigure; +} ENetProtocol; + +#endif /* __ENET_PROTOCOL_H__ */ + diff --git a/polymer/eduke32/source/enet/include/enet/time.h b/polymer/eduke32/source/enet/include/enet/time.h new file mode 100644 index 000000000..c82a54603 --- /dev/null +++ b/polymer/eduke32/source/enet/include/enet/time.h @@ -0,0 +1,18 @@ +/** + @file time.h + @brief ENet time constants and macros +*/ +#ifndef __ENET_TIME_H__ +#define __ENET_TIME_H__ + +#define ENET_TIME_OVERFLOW 86400000 + +#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) +#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) + +#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) + +#endif /* __ENET_TIME_H__ */ + diff --git a/polymer/eduke32/source/enet/include/enet/types.h b/polymer/eduke32/source/enet/include/enet/types.h new file mode 100644 index 000000000..ab010a4b1 --- /dev/null +++ b/polymer/eduke32/source/enet/include/enet/types.h @@ -0,0 +1,13 @@ +/** + @file types.h + @brief type definitions for ENet +*/ +#ifndef __ENET_TYPES_H__ +#define __ENET_TYPES_H__ + +typedef unsigned char enet_uint8; /**< unsigned 8-bit type */ +typedef unsigned short enet_uint16; /**< unsigned 16-bit type */ +typedef unsigned int enet_uint32; /**< unsigned 32-bit type */ + +#endif /* __ENET_TYPES_H__ */ + diff --git a/polymer/eduke32/source/enet/include/enet/unix.h b/polymer/eduke32/source/enet/include/enet/unix.h new file mode 100644 index 000000000..087015e51 --- /dev/null +++ b/polymer/eduke32/source/enet/include/enet/unix.h @@ -0,0 +1,45 @@ +/** + @file unix.h + @brief ENet Unix header +*/ +#ifndef __ENET_UNIX_H__ +#define __ENET_UNIX_H__ + +#include +#include +#include +#include +#include + +typedef int ENetSocket; + +enum +{ + ENET_SOCKET_NULL = -1 +}; + +#define ENET_HOST_TO_NET_16(value) (htons (value)) /**< macro that converts host to net byte-order of a 16-bit value */ +#define ENET_HOST_TO_NET_32(value) (htonl (value)) /**< macro that converts host to net byte-order of a 32-bit value */ + +#define ENET_NET_TO_HOST_16(value) (ntohs (value)) /**< macro that converts net to host byte-order of a 16-bit value */ +#define ENET_NET_TO_HOST_32(value) (ntohl (value)) /**< macro that converts net to host byte-order of a 32-bit value */ + +typedef struct +{ + void * data; + size_t dataLength; +} ENetBuffer; + +#define ENET_CALLBACK + +#define ENET_API extern + +typedef fd_set ENetSocketSet; + +#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) +#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) +#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLEAR (socket, & (sockset)) +#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) + +#endif /* __ENET_UNIX_H__ */ + diff --git a/polymer/eduke32/source/enet/include/enet/utility.h b/polymer/eduke32/source/enet/include/enet/utility.h new file mode 100644 index 000000000..e48a476be --- /dev/null +++ b/polymer/eduke32/source/enet/include/enet/utility.h @@ -0,0 +1,12 @@ +/** + @file utility.h + @brief ENet utility header +*/ +#ifndef __ENET_UTILITY_H__ +#define __ENET_UTILITY_H__ + +#define ENET_MAX(x, y) ((x) > (y) ? (x) : (y)) +#define ENET_MIN(x, y) ((x) < (y) ? (x) : (y)) + +#endif /* __ENET_UTILITY_H__ */ + diff --git a/polymer/eduke32/source/enet/include/enet/win32.h b/polymer/eduke32/source/enet/include/enet/win32.h new file mode 100644 index 000000000..0e1cf0c5a --- /dev/null +++ b/polymer/eduke32/source/enet/include/enet/win32.h @@ -0,0 +1,58 @@ +/** + @file win32.h + @brief ENet Win32 header +*/ +#ifndef __ENET_WIN32_H__ +#define __ENET_WIN32_H__ + +#ifdef ENET_BUILDING_LIB +#pragma warning (disable: 4996) // 'strncpy' was declared deprecated +#pragma warning (disable: 4267) // size_t to int conversion +#pragma warning (disable: 4244) // 64bit to 32bit int +#pragma warning (disable: 4018) // signed/unsigned mismatch +#endif + +#include +#include + +typedef SOCKET ENetSocket; + +enum +{ + ENET_SOCKET_NULL = INVALID_SOCKET +}; + +#define ENET_HOST_TO_NET_16(value) (htons (value)) +#define ENET_HOST_TO_NET_32(value) (htonl (value)) + +#define ENET_NET_TO_HOST_16(value) (ntohs (value)) +#define ENET_NET_TO_HOST_32(value) (ntohl (value)) + +typedef struct +{ + size_t dataLength; + void * data; +} ENetBuffer; + +#define ENET_CALLBACK __cdecl + +#if defined ENET_DLL +#if defined ENET_BUILDING_LIB +#define ENET_API __declspec( dllexport ) +#else +#define ENET_API __declspec( dllimport ) +#endif /* ENET_BUILDING_LIB */ +#else /* !ENET_DLL */ +#define ENET_API extern +#endif /* ENET_DLL */ + +typedef fd_set ENetSocketSet; + +#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) +#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) +#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLEAR (socket, & (sockset)) +#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) + +#endif /* __ENET_WIN32_H__ */ + + diff --git a/polymer/eduke32/source/enet/src/callbacks.c b/polymer/eduke32/source/enet/src/callbacks.c new file mode 100644 index 000000000..7f960af3f --- /dev/null +++ b/polymer/eduke32/source/enet/src/callbacks.c @@ -0,0 +1,53 @@ +/** + @file callbacks.c + @brief ENet callback functions +*/ +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +static ENetCallbacks callbacks = { malloc, free, rand }; + +int +enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits) +{ + if (version != ENET_VERSION) + return -1; + + if (inits -> malloc != NULL || inits -> free != NULL) + { + if (inits -> malloc == NULL || inits -> free == NULL) + return -1; + + callbacks.malloc = inits -> malloc; + callbacks.free = inits -> free; + } + + if (inits -> rand != NULL) + callbacks.rand = inits -> rand; + + return enet_initialize (); +} + +void * +enet_malloc (size_t size) +{ + void * memory = callbacks.malloc (size); + + if (memory == NULL) + abort (); + + return memory; +} + +void +enet_free (void * memory) +{ + callbacks.free (memory); +} + +int +enet_rand (void) +{ + return callbacks.rand (); +} + diff --git a/polymer/eduke32/source/enet/src/host.c b/polymer/eduke32/source/enet/src/host.c new file mode 100644 index 000000000..30eaded90 --- /dev/null +++ b/polymer/eduke32/source/enet/src/host.c @@ -0,0 +1,401 @@ +/** + @file host.c + @brief ENet host management functions +*/ +#define ENET_BUILDING_LIB 1 +#include +#include "enet/enet.h" + +/** @defgroup host ENet host functions + @{ +*/ + +/** Creates a host for communicating to peers. + + @param address the address at which other peers may connect to this host. If NULL, then no peers may connect to the host. + @param peerCount the maximum number of peers that should be allocated for the host. + @param incomingBandwidth downstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth. + @param outgoingBandwidth upstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth. + + @returns the host on success and NULL on failure + + @remarks ENet will strategically drop packets on specific sides of a connection between hosts + to ensure the host's bandwidth is not overwhelmed. The bandwidth parameters also determine + the window size of a connection which limits the amount of reliable packets that may be in transit + at any given time. +*/ +ENetHost * +enet_host_create (const ENetAddress * address, size_t peerCount, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) +{ + ENetHost * host = (ENetHost *) enet_malloc (sizeof (ENetHost)); + ENetPeer * currentPeer; + + if (peerCount > ENET_PROTOCOL_MAXIMUM_PEER_ID) + return NULL; + + host -> peers = (ENetPeer *) enet_malloc (peerCount * sizeof (ENetPeer)); + memset (host -> peers, 0, peerCount * sizeof (ENetPeer)); + + host -> socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM); + if (host -> socket == ENET_SOCKET_NULL || (address != NULL && enet_socket_bind (host -> socket, address) < 0)) + { + if (host -> socket != ENET_SOCKET_NULL) + enet_socket_destroy (host -> socket); + + enet_free (host -> peers); + enet_free (host); + + return NULL; + } + + enet_socket_set_option (host -> socket, ENET_SOCKOPT_NONBLOCK, 1); + enet_socket_set_option (host -> socket, ENET_SOCKOPT_BROADCAST, 1); + enet_socket_set_option (host -> socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE); + enet_socket_set_option (host -> socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE); + + if (address != NULL) + host -> address = * address; + + host -> incomingBandwidth = incomingBandwidth; + host -> outgoingBandwidth = outgoingBandwidth; + host -> bandwidthThrottleEpoch = 0; + host -> recalculateBandwidthLimits = 0; + host -> mtu = ENET_HOST_DEFAULT_MTU; + host -> peerCount = peerCount; + host -> lastServicedPeer = host -> peers; + host -> commandCount = 0; + host -> bufferCount = 0; + host -> receivedAddress.host = ENET_HOST_ANY; + host -> receivedAddress.port = 0; + host -> receivedDataLength = 0; + + for (currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + currentPeer -> host = host; + currentPeer -> incomingPeerID = currentPeer - host -> peers; + currentPeer -> data = NULL; + + enet_list_clear (& currentPeer -> acknowledgements); + enet_list_clear (& currentPeer -> sentReliableCommands); + enet_list_clear (& currentPeer -> sentUnreliableCommands); + enet_list_clear (& currentPeer -> outgoingReliableCommands); + enet_list_clear (& currentPeer -> outgoingUnreliableCommands); + + enet_peer_reset (currentPeer); + } + + return host; +} + +/** Destroys the host and all resources associated with it. + @param host pointer to the host to destroy +*/ +void +enet_host_destroy (ENetHost * host) +{ + ENetPeer * currentPeer; + + enet_socket_destroy (host -> socket); + + for (currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + enet_peer_reset (currentPeer); + } + + enet_free (host -> peers); + enet_free (host); +} + +/** Initiates a connection to a foreign host. + @param host host seeking the connection + @param address destination for the connection + @param channelCount number of channels to allocate + @returns a peer representing the foreign host on success, NULL on failure + @remarks The peer returned will have not completed the connection until enet_host_service() + notifies of an ENET_EVENT_TYPE_CONNECT event for the peer. +*/ +ENetPeer * +enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelCount) +{ + ENetPeer * currentPeer; + ENetChannel * channel; + ENetProtocol command; + + if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) + channelCount = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; + else + if (channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) + channelCount = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; + + for (currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED) + break; + } + + if (currentPeer >= & host -> peers [host -> peerCount]) + return NULL; + + currentPeer -> state = ENET_PEER_STATE_CONNECTING; + currentPeer -> address = * address; + currentPeer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel)); + currentPeer -> channelCount = channelCount; + currentPeer -> sessionID = (enet_uint32) enet_rand (); + + if (host -> outgoingBandwidth == 0) + currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + else + currentPeer -> windowSize = (host -> outgoingBandwidth / + ENET_PEER_WINDOW_SIZE_SCALE) * + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + + if (currentPeer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) + currentPeer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + else + if (currentPeer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) + currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + + for (channel = currentPeer -> channels; + channel < & currentPeer -> channels [channelCount]; + ++ channel) + { + channel -> outgoingReliableSequenceNumber = 0; + channel -> outgoingUnreliableSequenceNumber = 0; + channel -> incomingReliableSequenceNumber = 0; + + enet_list_clear (& channel -> incomingReliableCommands); + enet_list_clear (& channel -> incomingUnreliableCommands); + + channel -> usedReliableWindows = 0; + memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows)); + } + + command.header.command = ENET_PROTOCOL_COMMAND_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.header.channelID = 0xFF; + command.connect.outgoingPeerID = ENET_HOST_TO_NET_16 (currentPeer -> incomingPeerID); + command.connect.mtu = ENET_HOST_TO_NET_16 (currentPeer -> mtu); + command.connect.windowSize = ENET_HOST_TO_NET_32 (currentPeer -> windowSize); + command.connect.channelCount = ENET_HOST_TO_NET_32 (channelCount); + command.connect.incomingBandwidth = ENET_HOST_TO_NET_32 (host -> incomingBandwidth); + command.connect.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth); + command.connect.packetThrottleInterval = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleInterval); + command.connect.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleAcceleration); + command.connect.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleDeceleration); + command.connect.sessionID = currentPeer -> sessionID; + + enet_peer_queue_outgoing_command (currentPeer, & command, NULL, 0, 0); + + return currentPeer; +} + +/** Queues a packet to be sent to all peers associated with the host. + @param host host on which to broadcast the packet + @param channelID channel on which to broadcast + @param packet packet to broadcast +*/ +void +enet_host_broadcast (ENetHost * host, enet_uint8 channelID, ENetPacket * packet) +{ + ENetPeer * currentPeer; + + for (currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + if (currentPeer -> state != ENET_PEER_STATE_CONNECTED) + continue; + + enet_peer_send (currentPeer, channelID, packet); + } + + if (packet -> referenceCount == 0) + enet_packet_destroy (packet); +} + +/** Adjusts the bandwidth limits of a host. + @param host host to adjust + @param incomingBandwidth new incoming bandwidth + @param outgoingBandwidth new outgoing bandwidth + @remarks the incoming and outgoing bandwidth parameters are identical in function to those + specified in enet_host_create(). +*/ +void +enet_host_bandwidth_limit (ENetHost * host, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) +{ + host -> incomingBandwidth = incomingBandwidth; + host -> outgoingBandwidth = outgoingBandwidth; + host -> recalculateBandwidthLimits = 1; +} + +void +enet_host_bandwidth_throttle (ENetHost * host) +{ + enet_uint32 timeCurrent = enet_time_get (), + elapsedTime = timeCurrent - host -> bandwidthThrottleEpoch, + peersTotal = 0, + dataTotal = 0, + peersRemaining, + bandwidth, + throttle = 0, + bandwidthLimit = 0; + int needsAdjustment; + ENetPeer * peer; + ENetProtocol command; + + if (elapsedTime < ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL) + return; + + for (peer = host -> peers; + peer < & host -> peers [host -> peerCount]; + ++ peer) + { + if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) + continue; + + ++ peersTotal; + dataTotal += peer -> outgoingDataTotal; + } + + if (peersTotal == 0) + return; + + peersRemaining = peersTotal; + needsAdjustment = 1; + + if (host -> outgoingBandwidth == 0) + bandwidth = ~0; + else + bandwidth = (host -> outgoingBandwidth * elapsedTime) / 1000; + + while (peersRemaining > 0 && needsAdjustment != 0) + { + needsAdjustment = 0; + + if (dataTotal < bandwidth) + throttle = ENET_PEER_PACKET_THROTTLE_SCALE; + else + throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal; + + for (peer = host -> peers; + peer < & host -> peers [host -> peerCount]; + ++ peer) + { + enet_uint32 peerBandwidth; + + if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) || + peer -> incomingBandwidth == 0 || + peer -> outgoingBandwidthThrottleEpoch == timeCurrent) + continue; + + peerBandwidth = (peer -> incomingBandwidth * elapsedTime) / 1000; + if ((throttle * peer -> outgoingDataTotal) / ENET_PEER_PACKET_THROTTLE_SCALE <= peerBandwidth) + continue; + + peer -> packetThrottleLimit = (peerBandwidth * + ENET_PEER_PACKET_THROTTLE_SCALE) / peer -> outgoingDataTotal; + + if (peer -> packetThrottleLimit == 0) + peer -> packetThrottleLimit = 1; + + if (peer -> packetThrottle > peer -> packetThrottleLimit) + peer -> packetThrottle = peer -> packetThrottleLimit; + + peer -> outgoingBandwidthThrottleEpoch = timeCurrent; + + + needsAdjustment = 1; + -- peersRemaining; + bandwidth -= peerBandwidth; + dataTotal -= peerBandwidth; + } + } + + if (peersRemaining > 0) + for (peer = host -> peers; + peer < & host -> peers [host -> peerCount]; + ++ peer) + { + if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) || + peer -> outgoingBandwidthThrottleEpoch == timeCurrent) + continue; + + peer -> packetThrottleLimit = throttle; + + if (peer -> packetThrottle > peer -> packetThrottleLimit) + peer -> packetThrottle = peer -> packetThrottleLimit; + } + + if (host -> recalculateBandwidthLimits) + { + host -> recalculateBandwidthLimits = 0; + + peersRemaining = peersTotal; + bandwidth = host -> incomingBandwidth; + needsAdjustment = 1; + + if (bandwidth == 0) + bandwidthLimit = 0; + else + while (peersRemaining > 0 && needsAdjustment != 0) + { + needsAdjustment = 0; + bandwidthLimit = bandwidth / peersRemaining; + + for (peer = host -> peers; + peer < & host -> peers [host -> peerCount]; + ++ peer) + { + if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) || + peer -> incomingBandwidthThrottleEpoch == timeCurrent) + continue; + + if (peer -> outgoingBandwidth > 0 && + peer -> outgoingBandwidth >= bandwidthLimit) + continue; + + peer -> incomingBandwidthThrottleEpoch = timeCurrent; + + needsAdjustment = 1; + -- peersRemaining; + bandwidth -= peer -> outgoingBandwidth; + } + } + + for (peer = host -> peers; + peer < & host -> peers [host -> peerCount]; + ++ peer) + { + if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) + continue; + + command.header.command = ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.header.channelID = 0xFF; + command.bandwidthLimit.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth); + + if (peer -> incomingBandwidthThrottleEpoch == timeCurrent) + command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (peer -> outgoingBandwidth); + else + command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (bandwidthLimit); + + enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); + } + } + + host -> bandwidthThrottleEpoch = timeCurrent; + + for (peer = host -> peers; + peer < & host -> peers [host -> peerCount]; + ++ peer) + { + peer -> incomingDataTotal = 0; + peer -> outgoingDataTotal = 0; + } +} + +/** @} */ diff --git a/polymer/eduke32/source/enet/src/list.c b/polymer/eduke32/source/enet/src/list.c new file mode 100644 index 000000000..1a4aa3ae7 --- /dev/null +++ b/polymer/eduke32/source/enet/src/list.c @@ -0,0 +1,57 @@ +/** + @file list.c + @brief ENet linked list functions +*/ +#define ENET_BUILDING_LIB 1 +#include "enet/list.h" + +/** + @defgroup list ENet linked list utility functions + @ingroup private + @{ +*/ +void +enet_list_clear (ENetList * list) +{ + list -> sentinel.next = & list -> sentinel; + list -> sentinel.previous = & list -> sentinel; +} + +ENetListIterator +enet_list_insert (ENetListIterator position, void * data) +{ + ENetListIterator result = (ENetListIterator) data; + + result -> previous = position -> previous; + result -> next = position; + + result -> previous -> next = result; + position -> previous = result; + + return result; +} + +void * +enet_list_remove (ENetListIterator position) +{ + position -> previous -> next = position -> next; + position -> next -> previous = position -> previous; + + return position; +} + +size_t +enet_list_size (ENetList * list) +{ + size_t size = 0; + ENetListIterator position; + + for (position = enet_list_begin (list); + position != enet_list_end (list); + position = enet_list_next (position)) + ++ size; + + return size; +} + +/** @} */ diff --git a/polymer/eduke32/source/enet/src/packet.c b/polymer/eduke32/source/enet/src/packet.c new file mode 100644 index 000000000..7f18e49eb --- /dev/null +++ b/polymer/eduke32/source/enet/src/packet.c @@ -0,0 +1,155 @@ +/** + @file packet.c + @brief ENet packet management functions +*/ +#include +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +/** @defgroup Packet ENet packet functions + @{ +*/ + +/** Creates a packet that may be sent to a peer. + @param dataContents initial contents of the packet's data; the packet's data will remain uninitialized if dataContents is NULL. + @param dataLength size of the data allocated for this packet + @param flags flags for this packet as described for the ENetPacket structure. + @returns the packet on success, NULL on failure +*/ +ENetPacket * +enet_packet_create (const void * data, size_t dataLength, enet_uint32 flags) +{ + ENetPacket * packet = (ENetPacket *) enet_malloc (sizeof (ENetPacket)); + + if (flags & ENET_PACKET_FLAG_NO_ALLOCATE) + packet -> data = (enet_uint8 *) data; + else + { + packet -> data = (enet_uint8 *) enet_malloc (dataLength); + if (packet -> data == NULL) + { + enet_free (packet); + return NULL; + } + + if (data != NULL) + memcpy (packet -> data, data, dataLength); + } + + packet -> referenceCount = 0; + packet -> flags = flags; + packet -> dataLength = dataLength; + packet -> freeCallback = NULL; + + return packet; +} + +/** Destroys the packet and deallocates its data. + @param packet packet to be destroyed +*/ +void +enet_packet_destroy (ENetPacket * packet) +{ + if (packet -> freeCallback != NULL) + (* packet -> freeCallback) (packet); + if (! (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE)) + enet_free (packet -> data); + enet_free (packet); +} + +/** Attempts to resize the data in the packet to length specified in the + dataLength parameter + @param packet packet to resize + @param dataLength new size for the packet data + @returns 0 on success, < 0 on failure +*/ +int +enet_packet_resize (ENetPacket * packet, size_t dataLength) +{ + enet_uint8 * newData; + + if (dataLength <= packet -> dataLength || (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE)) + { + packet -> dataLength = dataLength; + + return 0; + } + + newData = (enet_uint8 *) enet_malloc (dataLength); + if (newData == NULL) + return -1; + + memcpy (newData, packet -> data, packet -> dataLength); + enet_free (packet -> data); + + packet -> data = newData; + packet -> dataLength = dataLength; + + return 0; +} + +static int initializedCRC32 = 0; +static enet_uint32 crcTable [256]; + +static enet_uint32 +reflect_crc (int val, int bits) +{ + int result = 0, bit; + + for (bit = 0; bit < bits; bit ++) + { + if(val & 1) result |= 1 << (bits - 1 - bit); + val >>= 1; + } + + return result; +} + +static void +initialize_crc32 () +{ + int byte; + + for (byte = 0; byte < 256; ++ byte) + { + enet_uint32 crc = reflect_crc (byte, 8) << 24; + int offset; + + for(offset = 0; offset < 8; ++ offset) + { + if (crc & 0x80000000) + crc = (crc << 1) ^ 0x04c11db7; + else + crc <<= 1; + } + + crcTable [byte] = reflect_crc (crc, 32); + } + + initializedCRC32 = 1; +} + +enet_uint32 +enet_crc32 (const ENetBuffer * buffers, size_t bufferCount) +{ + enet_uint32 crc = 0xFFFFFFFF; + + if (! initializedCRC32) initialize_crc32 (); + + while (bufferCount -- > 0) + { + const enet_uint8 * data = (const enet_uint8 *) buffers -> data, + * dataEnd = & data [buffers -> dataLength]; + + while (data < dataEnd) + { + crc = (crc >> 8) ^ crcTable [(crc & 0xFF) ^ *data++]; + } + + ++ buffers; + } + + return ENET_HOST_TO_NET_32 (~ crc); +} + +/** @} */ diff --git a/polymer/eduke32/source/enet/src/peer.c b/polymer/eduke32/source/enet/src/peer.c new file mode 100644 index 000000000..52e34a51f --- /dev/null +++ b/polymer/eduke32/source/enet/src/peer.c @@ -0,0 +1,700 @@ +/** + @file peer.c + @brief ENet peer management functions +*/ +#include +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +/** @defgroup peer ENet peer functions + @{ +*/ + +/** Configures throttle parameter for a peer. + + Unreliable packets are dropped by ENet in response to the varying conditions + of the Internet connection to the peer. The throttle represents a probability + that an unreliable packet should not be dropped and thus sent by ENet to the peer. + The lowest mean round trip time from the sending of a reliable packet to the + receipt of its acknowledgement is measured over an amount of time specified by + the interval parameter in milliseconds. If a measured round trip time happens to + be significantly less than the mean round trip time measured over the interval, + then the throttle probability is increased to allow more traffic by an amount + specified in the acceleration parameter, which is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE + constant. If a measured round trip time happens to be significantly greater than + the mean round trip time measured over the interval, then the throttle probability + is decreased to limit traffic by an amount specified in the deceleration parameter, which + is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE constant. When the throttle has + a value of ENET_PEER_PACKET_THROTTLE_SCALE, on unreliable packets are dropped by + ENet, and so 100% of all unreliable packets will be sent. When the throttle has a + value of 0, all unreliable packets are dropped by ENet, and so 0% of all unreliable + packets will be sent. Intermediate values for the throttle represent intermediate + probabilities between 0% and 100% of unreliable packets being sent. The bandwidth + limits of the local and foreign hosts are taken into account to determine a + sensible limit for the throttle probability above which it should not raise even in + the best of conditions. + + @param peer peer to configure + @param interval interval, in milliseconds, over which to measure lowest mean RTT; the default value is ENET_PEER_PACKET_THROTTLE_INTERVAL. + @param acceleration rate at which to increase the throttle probability as mean RTT declines + @param deceleration rate at which to decrease the throttle probability as mean RTT increases +*/ +void +enet_peer_throttle_configure (ENetPeer * peer, enet_uint32 interval, enet_uint32 acceleration, enet_uint32 deceleration) +{ + ENetProtocol command; + + peer -> packetThrottleInterval = interval; + peer -> packetThrottleAcceleration = acceleration; + peer -> packetThrottleDeceleration = deceleration; + + command.header.command = ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.header.channelID = 0xFF; + + command.throttleConfigure.packetThrottleInterval = ENET_HOST_TO_NET_32 (interval); + command.throttleConfigure.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (acceleration); + command.throttleConfigure.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (deceleration); + + enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); +} + +int +enet_peer_throttle (ENetPeer * peer, enet_uint32 rtt) +{ + if (peer -> lastRoundTripTime <= peer -> lastRoundTripTimeVariance) + { + peer -> packetThrottle = peer -> packetThrottleLimit; + } + else + if (rtt < peer -> lastRoundTripTime) + { + peer -> packetThrottle += peer -> packetThrottleAcceleration; + + if (peer -> packetThrottle > peer -> packetThrottleLimit) + peer -> packetThrottle = peer -> packetThrottleLimit; + + return 1; + } + else + if (rtt > peer -> lastRoundTripTime + 2 * peer -> lastRoundTripTimeVariance) + { + if (peer -> packetThrottle > peer -> packetThrottleDeceleration) + peer -> packetThrottle -= peer -> packetThrottleDeceleration; + else + peer -> packetThrottle = 0; + + return -1; + } + + return 0; +} + +/** Queues a packet to be sent. + @param peer destination for the packet + @param channelID channel on which to send + @param packet packet to send + @retval 0 on success + @retval < 0 on failure +*/ +int +enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet) +{ + ENetChannel * channel = & peer -> channels [channelID]; + ENetProtocol command; + size_t fragmentLength; + + if (peer -> state != ENET_PEER_STATE_CONNECTED || + channelID >= peer -> channelCount) + return -1; + + fragmentLength = peer -> mtu - sizeof (ENetProtocolHeader) - sizeof (ENetProtocolSendFragment); + + if (packet -> dataLength > fragmentLength) + { + enet_uint16 startSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingReliableSequenceNumber + 1); + enet_uint32 fragmentCount = ENET_HOST_TO_NET_32 ((packet -> dataLength + fragmentLength - 1) / fragmentLength), + fragmentNumber, + fragmentOffset; + + packet -> flags |= ENET_PACKET_FLAG_RELIABLE; + packet -> flags &= ~ENET_PACKET_FLAG_UNSEQUENCED; + + for (fragmentNumber = 0, + fragmentOffset = 0; + fragmentOffset < packet -> dataLength; + ++ fragmentNumber, + fragmentOffset += fragmentLength) + { + if (packet -> dataLength - fragmentOffset < fragmentLength) + fragmentLength = packet -> dataLength - fragmentOffset; + + command.header.command = ENET_PROTOCOL_COMMAND_SEND_FRAGMENT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.header.channelID = channelID; + command.sendFragment.startSequenceNumber = startSequenceNumber; + command.sendFragment.dataLength = ENET_HOST_TO_NET_16 (fragmentLength); + command.sendFragment.fragmentCount = fragmentCount; + command.sendFragment.fragmentNumber = ENET_HOST_TO_NET_32 (fragmentNumber); + command.sendFragment.totalLength = ENET_HOST_TO_NET_32 (packet -> dataLength); + command.sendFragment.fragmentOffset = ENET_NET_TO_HOST_32 (fragmentOffset); + + enet_peer_queue_outgoing_command (peer, & command, packet, fragmentOffset, fragmentLength); + } + + return 0; + } + + command.header.channelID = channelID; + + if (! (packet -> flags & (ENET_PACKET_FLAG_RELIABLE | ENET_PACKET_FLAG_UNSEQUENCED)) && channel -> outgoingUnreliableSequenceNumber >= 0xFFFF) + packet -> flags |= ENET_PACKET_FLAG_RELIABLE; + + if (packet -> flags & ENET_PACKET_FLAG_RELIABLE) + { + command.header.command = ENET_PROTOCOL_COMMAND_SEND_RELIABLE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.sendReliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength); + } + else + if (packet -> flags & ENET_PACKET_FLAG_UNSEQUENCED) + { + command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; + command.sendUnsequenced.unsequencedGroup = ENET_HOST_TO_NET_16 (peer -> outgoingUnsequencedGroup + 1); + command.sendUnsequenced.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength); + } + else + { + command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE; + command.sendUnreliable.unreliableSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingUnreliableSequenceNumber + 1); + command.sendUnreliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength); + } + + enet_peer_queue_outgoing_command (peer, & command, packet, 0, packet -> dataLength); + + return 0; +} + +/** Attempts to dequeue any incoming queued packet. + @param peer peer to dequeue packets from + @param channelID channel on which to receive + @returns a pointer to the packet, or NULL if there are no available incoming queued packets +*/ +ENetPacket * +enet_peer_receive (ENetPeer * peer, enet_uint8 channelID) +{ + ENetChannel * channel = & peer -> channels [channelID]; + ENetIncomingCommand * incomingCommand = NULL; + ENetPacket * packet; + + if (! enet_list_empty (& channel -> incomingUnreliableCommands)) + { + incomingCommand = (ENetIncomingCommand *) enet_list_front (& channel -> incomingUnreliableCommands); + + if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE) + { + if (incomingCommand -> reliableSequenceNumber != channel -> incomingReliableSequenceNumber) + incomingCommand = NULL; + } + } + + if (incomingCommand == NULL && + ! enet_list_empty (& channel -> incomingReliableCommands)) + { + incomingCommand = (ENetIncomingCommand *) enet_list_front (& channel -> incomingReliableCommands); + + if (incomingCommand -> fragmentsRemaining > 0 || + incomingCommand -> reliableSequenceNumber != (enet_uint16) (channel -> incomingReliableSequenceNumber + 1)) + return NULL; + + channel -> incomingReliableSequenceNumber = incomingCommand -> reliableSequenceNumber; + + if (incomingCommand -> fragmentCount > 0) + channel -> incomingReliableSequenceNumber += incomingCommand -> fragmentCount - 1; + } + + if (incomingCommand == NULL) + return NULL; + + enet_list_remove (& incomingCommand -> incomingCommandList); + + packet = incomingCommand -> packet; + + -- packet -> referenceCount; + + if (incomingCommand -> fragments != NULL) + enet_free (incomingCommand -> fragments); + + enet_free (incomingCommand); + + return packet; +} + +static void +enet_peer_reset_outgoing_commands (ENetList * queue) +{ + ENetOutgoingCommand * outgoingCommand; + + while (! enet_list_empty (queue)) + { + outgoingCommand = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (queue)); + + if (outgoingCommand -> packet != NULL) + { + -- outgoingCommand -> packet -> referenceCount; + + if (outgoingCommand -> packet -> referenceCount == 0) + enet_packet_destroy (outgoingCommand -> packet); + } + + enet_free (outgoingCommand); + } +} + +static void +enet_peer_reset_incoming_commands (ENetList * queue) +{ + ENetIncomingCommand * incomingCommand; + + while (! enet_list_empty (queue)) + { + incomingCommand = (ENetIncomingCommand *) enet_list_remove (enet_list_begin (queue)); + + if (incomingCommand -> packet != NULL) + { + -- incomingCommand -> packet -> referenceCount; + + if (incomingCommand -> packet -> referenceCount == 0) + enet_packet_destroy (incomingCommand -> packet); + } + + if (incomingCommand -> fragments != NULL) + enet_free (incomingCommand -> fragments); + + enet_free (incomingCommand); + } +} + +void +enet_peer_reset_queues (ENetPeer * peer) +{ + ENetChannel * channel; + + while (! enet_list_empty (& peer -> acknowledgements)) + enet_free (enet_list_remove (enet_list_begin (& peer -> acknowledgements))); + + enet_peer_reset_outgoing_commands (& peer -> sentReliableCommands); + enet_peer_reset_outgoing_commands (& peer -> sentUnreliableCommands); + enet_peer_reset_outgoing_commands (& peer -> outgoingReliableCommands); + enet_peer_reset_outgoing_commands (& peer -> outgoingUnreliableCommands); + + if (peer -> channels != NULL && peer -> channelCount > 0) + { + for (channel = peer -> channels; + channel < & peer -> channels [peer -> channelCount]; + ++ channel) + { + enet_peer_reset_incoming_commands (& channel -> incomingReliableCommands); + enet_peer_reset_incoming_commands (& channel -> incomingUnreliableCommands); + } + + enet_free (peer -> channels); + } + + peer -> channels = NULL; + peer -> channelCount = 0; +} + +/** Forcefully disconnects a peer. + @param peer peer to forcefully disconnect + @remarks The foreign host represented by the peer is not notified of the disconnection and will timeout + on its connection to the local host. +*/ +void +enet_peer_reset (ENetPeer * peer) +{ + peer -> outgoingPeerID = ENET_PROTOCOL_MAXIMUM_PEER_ID; + peer -> sessionID = 0; + + peer -> state = ENET_PEER_STATE_DISCONNECTED; + + peer -> incomingBandwidth = 0; + peer -> outgoingBandwidth = 0; + peer -> incomingBandwidthThrottleEpoch = 0; + peer -> outgoingBandwidthThrottleEpoch = 0; + peer -> incomingDataTotal = 0; + peer -> outgoingDataTotal = 0; + peer -> lastSendTime = 0; + peer -> lastReceiveTime = 0; + peer -> nextTimeout = 0; + peer -> earliestTimeout = 0; + peer -> packetLossEpoch = 0; + peer -> packetsSent = 0; + peer -> packetsLost = 0; + peer -> packetLoss = 0; + peer -> packetLossVariance = 0; + peer -> packetThrottle = ENET_PEER_DEFAULT_PACKET_THROTTLE; + peer -> packetThrottleLimit = ENET_PEER_PACKET_THROTTLE_SCALE; + peer -> packetThrottleCounter = 0; + peer -> packetThrottleEpoch = 0; + peer -> packetThrottleAcceleration = ENET_PEER_PACKET_THROTTLE_ACCELERATION; + peer -> packetThrottleDeceleration = ENET_PEER_PACKET_THROTTLE_DECELERATION; + peer -> packetThrottleInterval = ENET_PEER_PACKET_THROTTLE_INTERVAL; + peer -> lastRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; + peer -> lowestRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; + peer -> lastRoundTripTimeVariance = 0; + peer -> highestRoundTripTimeVariance = 0; + peer -> roundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; + peer -> roundTripTimeVariance = 0; + peer -> mtu = peer -> host -> mtu; + peer -> reliableDataInTransit = 0; + peer -> outgoingReliableSequenceNumber = 0; + peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + peer -> incomingUnsequencedGroup = 0; + peer -> outgoingUnsequencedGroup = 0; + peer -> disconnectData = 0; + + memset (peer -> unsequencedWindow, 0, sizeof (peer -> unsequencedWindow)); + + enet_peer_reset_queues (peer); +} + +/** Sends a ping request to a peer. + @param peer destination for the ping request + @remarks ping requests factor into the mean round trip time as designated by the + roundTripTime field in the ENetPeer structure. Enet automatically pings all connected + peers at regular intervals, however, this function may be called to ensure more + frequent ping requests. +*/ +void +enet_peer_ping (ENetPeer * peer) +{ + ENetProtocol command; + + if (peer -> state != ENET_PEER_STATE_CONNECTED) + return; + + command.header.command = ENET_PROTOCOL_COMMAND_PING | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.header.channelID = 0xFF; + + enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); +} + +/** Force an immediate disconnection from a peer. + @param peer peer to disconnect + @param data data describing the disconnection + @remarks No ENET_EVENT_DISCONNECT event will be generated. The foreign peer is not + guarenteed to receive the disconnect notification, and is reset immediately upon + return from this function. +*/ +void +enet_peer_disconnect_now (ENetPeer * peer, enet_uint32 data) +{ + ENetProtocol command; + + if (peer -> state == ENET_PEER_STATE_DISCONNECTED) + return; + + if (peer -> state != ENET_PEER_STATE_ZOMBIE && + peer -> state != ENET_PEER_STATE_DISCONNECTING) + { + enet_peer_reset_queues (peer); + + command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; + command.header.channelID = 0xFF; + command.disconnect.data = ENET_HOST_TO_NET_32 (data); + + enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); + + enet_host_flush (peer -> host); + } + + enet_peer_reset (peer); +} + +/** Request a disconnection from a peer. + @param peer peer to request a disconnection + @param data data describing the disconnection + @remarks An ENET_EVENT_DISCONNECT event will be generated by enet_host_service() + once the disconnection is complete. +*/ +void +enet_peer_disconnect (ENetPeer * peer, enet_uint32 data) +{ + ENetProtocol command; + + if (peer -> state == ENET_PEER_STATE_DISCONNECTING || + peer -> state == ENET_PEER_STATE_DISCONNECTED || + peer -> state == ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT || + peer -> state == ENET_PEER_STATE_ZOMBIE) + return; + + enet_peer_reset_queues (peer); + + command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT; + command.header.channelID = 0xFF; + command.disconnect.data = ENET_HOST_TO_NET_32 (data); + + if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) + command.header.command |= ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + else + command.header.command |= ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; + + enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); + + if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) + peer -> state = ENET_PEER_STATE_DISCONNECTING; + else + { + enet_host_flush (peer -> host); + enet_peer_reset (peer); + } +} + +/** Request a disconnection from a peer, but only after all queued outgoing packets are sent. + @param peer peer to request a disconnection + @param data data describing the disconnection + @remarks An ENET_EVENT_DISCONNECT event will be generated by enet_host_service() + once the disconnection is complete. +*/ +void +enet_peer_disconnect_later (ENetPeer * peer, enet_uint32 data) +{ + if ((peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) && + ! (enet_list_empty (& peer -> outgoingReliableCommands) && + enet_list_empty (& peer -> outgoingUnreliableCommands) && + enet_list_empty (& peer -> sentReliableCommands))) + { + peer -> state = ENET_PEER_STATE_DISCONNECT_LATER; + peer -> disconnectData = data; + } + else + enet_peer_disconnect (peer, data); +} + +ENetAcknowledgement * +enet_peer_queue_acknowledgement (ENetPeer * peer, const ENetProtocol * command, enet_uint16 sentTime) +{ + ENetAcknowledgement * acknowledgement; + + if (command -> header.channelID < peer -> channelCount) + { + ENetChannel * channel = & peer -> channels [command -> header.channelID]; + enet_uint16 reliableWindow = command -> header.reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE, + currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + + if (command -> header.reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + reliableWindow += ENET_PEER_RELIABLE_WINDOWS; + + if (reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1 && reliableWindow <= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS) + return NULL; + } + + peer -> outgoingDataTotal += sizeof (ENetProtocolAcknowledge); + + acknowledgement = (ENetAcknowledgement *) enet_malloc (sizeof (ENetAcknowledgement)); + + acknowledgement -> sentTime = sentTime; + acknowledgement -> command = * command; + + enet_list_insert (enet_list_end (& peer -> acknowledgements), acknowledgement); + + return acknowledgement; +} + +ENetOutgoingCommand * +enet_peer_queue_outgoing_command (ENetPeer * peer, const ENetProtocol * command, ENetPacket * packet, enet_uint32 offset, enet_uint16 length) +{ + ENetChannel * channel = & peer -> channels [command -> header.channelID]; + ENetOutgoingCommand * outgoingCommand; + + peer -> outgoingDataTotal += enet_protocol_command_size (command -> header.command) + length; + + outgoingCommand = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand)); + + if (command -> header.channelID == 0xFF) + { + ++ peer -> outgoingReliableSequenceNumber; + + outgoingCommand -> reliableSequenceNumber = peer -> outgoingReliableSequenceNumber; + outgoingCommand -> unreliableSequenceNumber = 0; + } + else + if (command -> header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) + { + ++ channel -> outgoingReliableSequenceNumber; + channel -> outgoingUnreliableSequenceNumber = 0; + + outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber; + outgoingCommand -> unreliableSequenceNumber = 0; + } + else + if (command -> header.command & ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED) + { + ++ peer -> outgoingUnsequencedGroup; + + outgoingCommand -> reliableSequenceNumber = 0; + outgoingCommand -> unreliableSequenceNumber = 0; + } + else + { + ++ channel -> outgoingUnreliableSequenceNumber; + + outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber; + outgoingCommand -> unreliableSequenceNumber = channel -> outgoingUnreliableSequenceNumber; + } + + outgoingCommand -> sendAttempts = 0; + outgoingCommand -> sentTime = 0; + outgoingCommand -> roundTripTimeout = 0; + outgoingCommand -> roundTripTimeoutLimit = 0; + outgoingCommand -> fragmentOffset = offset; + outgoingCommand -> fragmentLength = length; + outgoingCommand -> packet = packet; + outgoingCommand -> command = * command; + outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> reliableSequenceNumber); + + if (packet != NULL) + ++ packet -> referenceCount; + + if (command -> header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) + enet_list_insert (enet_list_end (& peer -> outgoingReliableCommands), outgoingCommand); + else + enet_list_insert (enet_list_end (& peer -> outgoingUnreliableCommands), outgoingCommand); + + return outgoingCommand; +} + +ENetIncomingCommand * +enet_peer_queue_incoming_command (ENetPeer * peer, const ENetProtocol * command, ENetPacket * packet, enet_uint32 fragmentCount) +{ + ENetChannel * channel = & peer -> channels [command -> header.channelID]; + enet_uint32 unreliableSequenceNumber = 0, reliableSequenceNumber; + enet_uint16 reliableWindow, currentWindow; + ENetIncomingCommand * incomingCommand; + ENetListIterator currentCommand; + + if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) + goto freePacket; + + if ((command -> header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED) + { + reliableSequenceNumber = command -> header.reliableSequenceNumber; + reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + + if (reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + reliableWindow += ENET_PEER_RELIABLE_WINDOWS; + + if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) + goto freePacket; + } + + switch (command -> header.command & ENET_PROTOCOL_COMMAND_MASK) + { + case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: + case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: + if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber) + goto freePacket; + + for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingReliableCommands)); + currentCommand != enet_list_end (& channel -> incomingReliableCommands); + currentCommand = enet_list_previous (currentCommand)) + { + incomingCommand = (ENetIncomingCommand *) currentCommand; + + if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) + { + if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + continue; + } + else + if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) + break; + + if (incomingCommand -> reliableSequenceNumber <= reliableSequenceNumber) + { + if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber) + break; + + goto freePacket; + } + } + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: + unreliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendUnreliable.unreliableSequenceNumber); + + for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingUnreliableCommands)); + currentCommand != enet_list_end (& channel -> incomingUnreliableCommands); + currentCommand = enet_list_previous (currentCommand)) + { + incomingCommand = (ENetIncomingCommand *) currentCommand; + + if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE) + continue; + + if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) + { + if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + continue; + } + else + if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) + break; + + if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber) + break; + + if (incomingCommand -> reliableSequenceNumber > reliableSequenceNumber) + continue; + + if (incomingCommand -> unreliableSequenceNumber <= unreliableSequenceNumber) + { + if (incomingCommand -> unreliableSequenceNumber < unreliableSequenceNumber) + break; + + goto freePacket; + } + } + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: + currentCommand = enet_list_end (& channel -> incomingUnreliableCommands); + break; + + default: + goto freePacket; + } + + incomingCommand = (ENetIncomingCommand *) enet_malloc (sizeof (ENetIncomingCommand)); + + incomingCommand -> reliableSequenceNumber = command -> header.reliableSequenceNumber; + incomingCommand -> unreliableSequenceNumber = unreliableSequenceNumber & 0xFFFF; + incomingCommand -> command = * command; + incomingCommand -> fragmentCount = fragmentCount; + incomingCommand -> fragmentsRemaining = fragmentCount; + incomingCommand -> packet = packet; + incomingCommand -> fragments = NULL; + + if (fragmentCount > 0) + { + incomingCommand -> fragments = (enet_uint32 *) enet_malloc ((fragmentCount + 31) / 32 * sizeof (enet_uint32)); + memset (incomingCommand -> fragments, 0, (fragmentCount + 31) / 32 * sizeof (enet_uint32)); + } + + if (packet != NULL) + ++ packet -> referenceCount; + + enet_list_insert (enet_list_next (currentCommand), incomingCommand); + + return incomingCommand; + +freePacket: + if (packet != NULL) + { + if (packet -> referenceCount == 0) + enet_packet_destroy (packet); + } + + return NULL; +} + +/** @} */ diff --git a/polymer/eduke32/source/enet/src/protocol.c b/polymer/eduke32/source/enet/src/protocol.c new file mode 100644 index 000000000..47bf8447a --- /dev/null +++ b/polymer/eduke32/source/enet/src/protocol.c @@ -0,0 +1,1577 @@ +/** + @file protocol.c + @brief ENet protocol functions +*/ +#include +#include +#define ENET_BUILDING_LIB 1 +#include "enet/utility.h" +#include "enet/time.h" +#include "enet/enet.h" + +static size_t commandSizes [ENET_PROTOCOL_COMMAND_COUNT] = +{ + 0, + sizeof (ENetProtocolAcknowledge), + sizeof (ENetProtocolConnect), + sizeof (ENetProtocolVerifyConnect), + sizeof (ENetProtocolDisconnect), + sizeof (ENetProtocolPing), + sizeof (ENetProtocolSendReliable), + sizeof (ENetProtocolSendUnreliable), + sizeof (ENetProtocolSendFragment), + sizeof (ENetProtocolSendUnsequenced), + sizeof (ENetProtocolBandwidthLimit), + sizeof (ENetProtocolThrottleConfigure), +}; + +size_t +enet_protocol_command_size (enet_uint8 commandNumber) +{ + return commandSizes [commandNumber & ENET_PROTOCOL_COMMAND_MASK]; +} + +static int +enet_protocol_dispatch_incoming_commands (ENetHost * host, ENetEvent * event) +{ + ENetPeer * currentPeer = host -> lastServicedPeer; + ENetChannel * channel; + + do + { + ++ currentPeer; + + if (currentPeer >= & host -> peers [host -> peerCount]) + currentPeer = host -> peers; + + switch (currentPeer -> state) + { + case ENET_PEER_STATE_CONNECTION_PENDING: + case ENET_PEER_STATE_CONNECTION_SUCCEEDED: + currentPeer -> state = ENET_PEER_STATE_CONNECTED; + + event -> type = ENET_EVENT_TYPE_CONNECT; + event -> peer = currentPeer; + + return 1; + + case ENET_PEER_STATE_ZOMBIE: + host -> recalculateBandwidthLimits = 1; + + event -> type = ENET_EVENT_TYPE_DISCONNECT; + event -> peer = currentPeer; + event -> data = currentPeer -> disconnectData; + + enet_peer_reset (currentPeer); + + host -> lastServicedPeer = currentPeer; + + return 1; + } + + if (currentPeer -> state != ENET_PEER_STATE_CONNECTED) + continue; + + for (channel = currentPeer -> channels; + channel < & currentPeer -> channels [currentPeer -> channelCount]; + ++ channel) + { + if (enet_list_empty (& channel -> incomingReliableCommands) && + enet_list_empty (& channel -> incomingUnreliableCommands)) + continue; + + event -> packet = enet_peer_receive (currentPeer, channel - currentPeer -> channels); + if (event -> packet == NULL) + continue; + + event -> type = ENET_EVENT_TYPE_RECEIVE; + event -> peer = currentPeer; + event -> channelID = (enet_uint8) (channel - currentPeer -> channels); + + host -> lastServicedPeer = currentPeer; + + return 1; + } + } while (currentPeer != host -> lastServicedPeer); + + return 0; +} + +static void +enet_protocol_notify_connect (ENetHost * host, ENetPeer * peer, ENetEvent * event) +{ + host -> recalculateBandwidthLimits = 1; + + if (event == NULL) + peer -> state = (peer -> state == ENET_PEER_STATE_CONNECTING ? ENET_PEER_STATE_CONNECTION_SUCCEEDED : ENET_PEER_STATE_CONNECTION_PENDING); + else + { + peer -> state = ENET_PEER_STATE_CONNECTED; + + event -> type = ENET_EVENT_TYPE_CONNECT; + event -> peer = peer; + } +} + +static void +enet_protocol_notify_disconnect (ENetHost * host, ENetPeer * peer, ENetEvent * event) +{ + if (peer -> state >= ENET_PEER_STATE_CONNECTION_PENDING) + host -> recalculateBandwidthLimits = 1; + + if (peer -> state != ENET_PEER_STATE_CONNECTING && peer -> state < ENET_PEER_STATE_CONNECTION_SUCCEEDED) + enet_peer_reset (peer); + else + if (event == NULL) + peer -> state = ENET_PEER_STATE_ZOMBIE; + else + { + event -> type = ENET_EVENT_TYPE_DISCONNECT; + event -> peer = peer; + event -> data = 0; + + enet_peer_reset (peer); + } +} + +static void +enet_protocol_remove_sent_unreliable_commands (ENetPeer * peer) +{ + ENetOutgoingCommand * outgoingCommand; + + while (! enet_list_empty (& peer -> sentUnreliableCommands)) + { + outgoingCommand = (ENetOutgoingCommand *) enet_list_front (& peer -> sentUnreliableCommands); + + enet_list_remove (& outgoingCommand -> outgoingCommandList); + + if (outgoingCommand -> packet != NULL) + { + -- outgoingCommand -> packet -> referenceCount; + + if (outgoingCommand -> packet -> referenceCount == 0) + enet_packet_destroy (outgoingCommand -> packet); + } + + enet_free (outgoingCommand); + } +} + +static ENetProtocolCommand +enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint16 reliableSequenceNumber, enet_uint8 channelID) +{ + ENetOutgoingCommand * outgoingCommand; + ENetListIterator currentCommand; + ENetProtocolCommand commandNumber; + + for (currentCommand = enet_list_begin (& peer -> sentReliableCommands); + currentCommand != enet_list_end (& peer -> sentReliableCommands); + currentCommand = enet_list_next (currentCommand)) + { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + if (outgoingCommand -> reliableSequenceNumber == reliableSequenceNumber && + outgoingCommand -> command.header.channelID == channelID) + break; + } + + if (currentCommand == enet_list_end (& peer -> sentReliableCommands)) + { + for (currentCommand = enet_list_begin (& peer -> outgoingReliableCommands); + currentCommand != enet_list_end (& peer -> outgoingReliableCommands); + currentCommand = enet_list_next (currentCommand)) + { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + if (outgoingCommand -> sendAttempts < 1) return ENET_PROTOCOL_COMMAND_NONE; + + if (outgoingCommand -> reliableSequenceNumber == reliableSequenceNumber && + outgoingCommand -> command.header.channelID == channelID) + break; + } + + if (currentCommand == enet_list_end (& peer -> outgoingReliableCommands)) + return ENET_PROTOCOL_COMMAND_NONE; + } + + if (channelID < peer -> channelCount) + { + ENetChannel * channel = & peer -> channels [channelID]; + enet_uint16 reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + if (channel -> reliableWindows [reliableWindow] > 0) + { + -- channel -> reliableWindows [reliableWindow]; + if (! channel -> reliableWindows [reliableWindow]) + channel -> usedReliableWindows &= ~ (1 << reliableWindow); + } + } + + commandNumber = (ENetProtocolCommand) (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK); + + enet_list_remove (& outgoingCommand -> outgoingCommandList); + + if (outgoingCommand -> packet != NULL) + { + peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength; + + -- outgoingCommand -> packet -> referenceCount; + + if (outgoingCommand -> packet -> referenceCount == 0) + enet_packet_destroy (outgoingCommand -> packet); + } + + enet_free (outgoingCommand); + + if (enet_list_empty (& peer -> sentReliableCommands)) + return commandNumber; + + outgoingCommand = (ENetOutgoingCommand *) enet_list_front (& peer -> sentReliableCommands); + + peer -> nextTimeout = outgoingCommand -> sentTime + outgoingCommand -> roundTripTimeout; + + return commandNumber; +} + +static ENetPeer * +enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENetProtocol * command) +{ + enet_uint16 mtu; + enet_uint32 windowSize; + ENetChannel * channel; + size_t channelCount; + ENetPeer * currentPeer; + ENetProtocol verifyCommand; + +#ifdef USE_CRC32 + { + enet_uint32 crc = header -> checksum; + ENetBuffer buffer; + + command -> header.reliableSequenceNumber = ENET_HOST_TO_NET_16 (command -> header.reliableSequenceNumber); + + header -> checksum = command -> connect.sessionID; + + buffer.data = host -> receivedData; + buffer.dataLength = host -> receivedDataLength; + + if (enet_crc32 (& buffer, 1) != crc) + return NULL; + + command -> header.reliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> header.reliableSequenceNumber); + } +#endif + + channelCount = ENET_NET_TO_HOST_32 (command -> connect.channelCount); + + if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT || + channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) + return NULL; + + for (currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + if (currentPeer -> state != ENET_PEER_STATE_DISCONNECTED && + currentPeer -> address.host == host -> receivedAddress.host && + currentPeer -> address.port == host -> receivedAddress.port && + currentPeer -> sessionID == command -> connect.sessionID) + return NULL; + } + + for (currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED) + break; + } + + if (currentPeer >= & host -> peers [host -> peerCount]) + return NULL; + + currentPeer -> state = ENET_PEER_STATE_ACKNOWLEDGING_CONNECT; + currentPeer -> sessionID = command -> connect.sessionID; + currentPeer -> address = host -> receivedAddress; + currentPeer -> outgoingPeerID = ENET_NET_TO_HOST_16 (command -> connect.outgoingPeerID); + currentPeer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> connect.incomingBandwidth); + currentPeer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> connect.outgoingBandwidth); + currentPeer -> packetThrottleInterval = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleInterval); + currentPeer -> packetThrottleAcceleration = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleAcceleration); + currentPeer -> packetThrottleDeceleration = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleDeceleration); + currentPeer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel)); + currentPeer -> channelCount = channelCount; + + for (channel = currentPeer -> channels; + channel < & currentPeer -> channels [channelCount]; + ++ channel) + { + channel -> outgoingReliableSequenceNumber = 0; + channel -> outgoingUnreliableSequenceNumber = 0; + channel -> incomingReliableSequenceNumber = 0; + + enet_list_clear (& channel -> incomingReliableCommands); + enet_list_clear (& channel -> incomingUnreliableCommands); + + channel -> usedReliableWindows = 0; + memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows)); + } + + mtu = ENET_NET_TO_HOST_16 (command -> connect.mtu); + + if (mtu < ENET_PROTOCOL_MINIMUM_MTU) + mtu = ENET_PROTOCOL_MINIMUM_MTU; + else + if (mtu > ENET_PROTOCOL_MAXIMUM_MTU) + mtu = ENET_PROTOCOL_MAXIMUM_MTU; + + currentPeer -> mtu = mtu; + + if (host -> outgoingBandwidth == 0 && + currentPeer -> incomingBandwidth == 0) + currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + else + if (host -> outgoingBandwidth == 0 || + currentPeer -> incomingBandwidth == 0) + currentPeer -> windowSize = (ENET_MAX (host -> outgoingBandwidth, currentPeer -> incomingBandwidth) / + ENET_PEER_WINDOW_SIZE_SCALE) * + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + else + currentPeer -> windowSize = (ENET_MIN (host -> outgoingBandwidth, currentPeer -> incomingBandwidth) / + ENET_PEER_WINDOW_SIZE_SCALE) * + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + + if (currentPeer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) + currentPeer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + else + if (currentPeer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) + currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + + if (host -> incomingBandwidth == 0) + windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + else + windowSize = (host -> incomingBandwidth / ENET_PEER_WINDOW_SIZE_SCALE) * + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + + if (windowSize > ENET_NET_TO_HOST_32 (command -> connect.windowSize)) + windowSize = ENET_NET_TO_HOST_32 (command -> connect.windowSize); + + if (windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) + windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + else + if (windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) + windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + + verifyCommand.header.command = ENET_PROTOCOL_COMMAND_VERIFY_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + verifyCommand.header.channelID = 0xFF; + verifyCommand.verifyConnect.outgoingPeerID = ENET_HOST_TO_NET_16 (currentPeer -> incomingPeerID); + verifyCommand.verifyConnect.mtu = ENET_HOST_TO_NET_16 (currentPeer -> mtu); + verifyCommand.verifyConnect.windowSize = ENET_HOST_TO_NET_32 (windowSize); + verifyCommand.verifyConnect.channelCount = ENET_HOST_TO_NET_32 (channelCount); + verifyCommand.verifyConnect.incomingBandwidth = ENET_HOST_TO_NET_32 (host -> incomingBandwidth); + verifyCommand.verifyConnect.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth); + verifyCommand.verifyConnect.packetThrottleInterval = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleInterval); + verifyCommand.verifyConnect.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleAcceleration); + verifyCommand.verifyConnect.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleDeceleration); + + enet_peer_queue_outgoing_command (currentPeer, & verifyCommand, NULL, 0, 0); + + return currentPeer; +} + +static int +enet_protocol_handle_send_reliable (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) +{ + ENetPacket * packet; + size_t dataLength; + + if (command -> header.channelID >= peer -> channelCount || + (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) + return -1; + + dataLength = ENET_NET_TO_HOST_16 (command -> sendReliable.dataLength); + * currentData += dataLength; + if (* currentData > & host -> receivedData [host -> receivedDataLength]) + return -1; + + packet = enet_packet_create ((const enet_uint8 *) command + sizeof (ENetProtocolSendReliable), + dataLength, + ENET_PACKET_FLAG_RELIABLE); + if (packet == NULL) + return -1; + + enet_peer_queue_incoming_command (peer, command, packet, 0); + return 0; +} + +static int +enet_protocol_handle_send_unsequenced (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) +{ + ENetPacket * packet; + enet_uint32 unsequencedGroup, index; + size_t dataLength; + + if (command -> header.channelID >= peer -> channelCount || + (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) + return -1; + + dataLength = ENET_NET_TO_HOST_16 (command -> sendUnsequenced.dataLength); + * currentData += dataLength; + if (* currentData > & host -> receivedData [host -> receivedDataLength]) + return -1; + + unsequencedGroup = ENET_NET_TO_HOST_16 (command -> sendUnsequenced.unsequencedGroup); + index = unsequencedGroup % ENET_PEER_UNSEQUENCED_WINDOW_SIZE; + + if (unsequencedGroup < peer -> incomingUnsequencedGroup) + unsequencedGroup += 0x10000; + + if (unsequencedGroup >= (enet_uint32) peer -> incomingUnsequencedGroup + ENET_PEER_FREE_UNSEQUENCED_WINDOWS * ENET_PEER_UNSEQUENCED_WINDOW_SIZE) + return 0; + + unsequencedGroup &= 0xFFFF; + + if (unsequencedGroup - index != peer -> incomingUnsequencedGroup) + { + peer -> incomingUnsequencedGroup = unsequencedGroup - index; + + memset (peer -> unsequencedWindow, 0, sizeof (peer -> unsequencedWindow)); + } + else + if (peer -> unsequencedWindow [index / 32] & (1 << (index % 32))) + return 0; + + peer -> unsequencedWindow [index / 32] |= 1 << (index % 32); + + + packet = enet_packet_create ((const enet_uint8 *) command + sizeof (ENetProtocolSendUnsequenced), + dataLength, + ENET_PACKET_FLAG_UNSEQUENCED); + if (packet == NULL) + return -1; + + enet_peer_queue_incoming_command (peer, command, packet, 0); + return 0; +} + +static int +enet_protocol_handle_send_unreliable (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) +{ + ENetPacket * packet; + size_t dataLength; + + if (command -> header.channelID >= peer -> channelCount || + (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) + return -1; + + dataLength = ENET_NET_TO_HOST_16 (command -> sendUnreliable.dataLength); + * currentData += dataLength; + if (* currentData > & host -> receivedData [host -> receivedDataLength]) + return -1; + + packet = enet_packet_create ((const enet_uint8 *) command + sizeof (ENetProtocolSendUnreliable), + dataLength, + 0); + if (packet == NULL) + return -1; + + enet_peer_queue_incoming_command (peer, command, packet, 0); + return 0; +} + +static int +enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) +{ + enet_uint32 fragmentNumber, + fragmentCount, + fragmentOffset, + fragmentLength, + startSequenceNumber, + totalLength; + ENetChannel * channel; + enet_uint16 startWindow, currentWindow; + ENetListIterator currentCommand; + ENetIncomingCommand * startCommand = NULL; + + if (command -> header.channelID >= peer -> channelCount || + (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) + return -1; + + fragmentLength = ENET_NET_TO_HOST_16 (command -> sendFragment.dataLength); + * currentData += fragmentLength; + if (* currentData > & host -> receivedData [host -> receivedDataLength]) + return -1; + + channel = & peer -> channels [command -> header.channelID]; + startSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendFragment.startSequenceNumber); + startWindow = startSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + + if (startSequenceNumber < channel -> incomingReliableSequenceNumber) + startWindow += ENET_PEER_RELIABLE_WINDOWS; + + if (startWindow < currentWindow || startWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) + return 0; + + fragmentNumber = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentNumber); + fragmentCount = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentCount); + fragmentOffset = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentOffset); + totalLength = ENET_NET_TO_HOST_32 (command -> sendFragment.totalLength); + + if (fragmentOffset >= totalLength || + fragmentOffset + fragmentLength > totalLength || + fragmentNumber >= fragmentCount) + return -1; + + for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingReliableCommands)); + currentCommand != enet_list_end (& channel -> incomingReliableCommands); + currentCommand = enet_list_previous (currentCommand)) + { + ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand; + + if (startSequenceNumber >= channel -> incomingReliableSequenceNumber) + { + if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + continue; + } + else + if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) + break; + + if (incomingCommand -> reliableSequenceNumber <= startSequenceNumber) + { + if (incomingCommand -> reliableSequenceNumber < startSequenceNumber) + break; + + if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_FRAGMENT || + totalLength != incomingCommand -> packet -> dataLength || + fragmentCount != incomingCommand -> fragmentCount) + return -1; + + startCommand = incomingCommand; + break; + } + } + + if (startCommand == NULL) + { + ENetProtocol hostCommand = * command; + ENetPacket * packet = enet_packet_create (NULL, totalLength, ENET_PACKET_FLAG_RELIABLE); + if (packet == NULL) + return -1; + + hostCommand.header.reliableSequenceNumber = startSequenceNumber; + hostCommand.sendFragment.startSequenceNumber = startSequenceNumber; + hostCommand.sendFragment.dataLength = fragmentLength; + hostCommand.sendFragment.fragmentNumber = fragmentNumber; + hostCommand.sendFragment.fragmentCount = fragmentCount; + hostCommand.sendFragment.fragmentOffset = fragmentOffset; + hostCommand.sendFragment.totalLength = totalLength; + + startCommand = enet_peer_queue_incoming_command (peer, & hostCommand, packet, fragmentCount); + if (startCommand == NULL) + return -1; + } + + if ((startCommand -> fragments [fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0) + { + -- startCommand -> fragmentsRemaining; + + startCommand -> fragments [fragmentNumber / 32] |= (1 << (fragmentNumber % 32)); + + if (fragmentOffset + fragmentLength > startCommand -> packet -> dataLength) + fragmentLength = startCommand -> packet -> dataLength - fragmentOffset; + + memcpy (startCommand -> packet -> data + fragmentOffset, + (enet_uint8 *) command + sizeof (ENetProtocolSendFragment), + fragmentLength); + } + + return 0; +} + +static int +enet_protocol_handle_ping (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) +{ + return 0; +} + +static int +enet_protocol_handle_bandwidth_limit (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) +{ + peer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> bandwidthLimit.incomingBandwidth); + peer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> bandwidthLimit.outgoingBandwidth); + + if (peer -> incomingBandwidth == 0 && host -> outgoingBandwidth == 0) + peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + else + peer -> windowSize = (ENET_MIN (peer -> incomingBandwidth, host -> outgoingBandwidth) / + ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + + if (peer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) + peer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + else + if (peer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) + peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + + return 0; +} + +static int +enet_protocol_handle_throttle_configure (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) +{ + peer -> packetThrottleInterval = ENET_NET_TO_HOST_32 (command -> throttleConfigure.packetThrottleInterval); + peer -> packetThrottleAcceleration = ENET_NET_TO_HOST_32 (command -> throttleConfigure.packetThrottleAcceleration); + peer -> packetThrottleDeceleration = ENET_NET_TO_HOST_32 (command -> throttleConfigure.packetThrottleDeceleration); + + return 0; +} + +static int +enet_protocol_handle_disconnect (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) +{ + if (peer -> state == ENET_PEER_STATE_ZOMBIE || peer -> state == ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT) + return 0; + + enet_peer_reset_queues (peer); + + if (peer -> state == ENET_PEER_STATE_CONNECTION_SUCCEEDED) + peer -> state = ENET_PEER_STATE_ZOMBIE; + else + if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) + { + if (peer -> state == ENET_PEER_STATE_CONNECTION_PENDING) host -> recalculateBandwidthLimits = 1; + + enet_peer_reset (peer); + } + else + if (command -> header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) + peer -> state = ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT; + else + peer -> state = ENET_PEER_STATE_ZOMBIE; + + peer -> disconnectData = ENET_NET_TO_HOST_32 (command -> disconnect.data); + return 0; +} + +static int +enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer * peer, const ENetProtocol * command) +{ + enet_uint32 roundTripTime, + receivedSentTime, + receivedReliableSequenceNumber; + ENetProtocolCommand commandNumber; + + receivedSentTime = ENET_NET_TO_HOST_16 (command -> acknowledge.receivedSentTime); + receivedSentTime |= host -> serviceTime & 0xFFFF0000; + if ((receivedSentTime & 0x8000) > (host -> serviceTime & 0x8000)) + receivedSentTime -= 0x10000; + + if (ENET_TIME_LESS (host -> serviceTime, receivedSentTime)) + return 0; + + peer -> lastReceiveTime = host -> serviceTime; + peer -> earliestTimeout = 0; + + roundTripTime = ENET_TIME_DIFFERENCE (host -> serviceTime, receivedSentTime); + + enet_peer_throttle (peer, roundTripTime); + + peer -> roundTripTimeVariance -= peer -> roundTripTimeVariance / 4; + + if (roundTripTime >= peer -> roundTripTime) + { + peer -> roundTripTime += (roundTripTime - peer -> roundTripTime) / 8; + peer -> roundTripTimeVariance += (roundTripTime - peer -> roundTripTime) / 4; + } + else + { + peer -> roundTripTime -= (peer -> roundTripTime - roundTripTime) / 8; + peer -> roundTripTimeVariance += (peer -> roundTripTime - roundTripTime) / 4; + } + + if (peer -> roundTripTime < peer -> lowestRoundTripTime) + peer -> lowestRoundTripTime = peer -> roundTripTime; + + if (peer -> roundTripTimeVariance > peer -> highestRoundTripTimeVariance) + peer -> highestRoundTripTimeVariance = peer -> roundTripTimeVariance; + + if (peer -> packetThrottleEpoch == 0 || + ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> packetThrottleEpoch) >= peer -> packetThrottleInterval) + { + peer -> lastRoundTripTime = peer -> lowestRoundTripTime; + peer -> lastRoundTripTimeVariance = peer -> highestRoundTripTimeVariance; + peer -> lowestRoundTripTime = peer -> roundTripTime; + peer -> highestRoundTripTimeVariance = peer -> roundTripTimeVariance; + peer -> packetThrottleEpoch = host -> serviceTime; + } + + receivedReliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> acknowledge.receivedReliableSequenceNumber); + + commandNumber = enet_protocol_remove_sent_reliable_command (peer, receivedReliableSequenceNumber, command -> header.channelID); + + switch (peer -> state) + { + case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT: + if (commandNumber != ENET_PROTOCOL_COMMAND_VERIFY_CONNECT) + return -1; + + enet_protocol_notify_connect (host, peer, event); + break; + + case ENET_PEER_STATE_DISCONNECTING: + if (commandNumber != ENET_PROTOCOL_COMMAND_DISCONNECT) + return -1; + + enet_protocol_notify_disconnect (host, peer, event); + break; + + case ENET_PEER_STATE_DISCONNECT_LATER: + if (enet_list_empty (& peer -> outgoingReliableCommands) && + enet_list_empty (& peer -> outgoingUnreliableCommands) && + enet_list_empty (& peer -> sentReliableCommands)) + enet_peer_disconnect (peer, peer -> disconnectData); + break; + } + + return 0; +} + +static int +enet_protocol_handle_verify_connect (ENetHost * host, ENetEvent * event, ENetPeer * peer, const ENetProtocol * command) +{ + enet_uint16 mtu; + enet_uint32 windowSize; + + if (peer -> state != ENET_PEER_STATE_CONNECTING) + return 0; + + if (ENET_NET_TO_HOST_32 (command -> verifyConnect.channelCount) != peer -> channelCount || + ENET_NET_TO_HOST_32 (command -> verifyConnect.packetThrottleInterval) != peer -> packetThrottleInterval || + ENET_NET_TO_HOST_32 (command -> verifyConnect.packetThrottleAcceleration) != peer -> packetThrottleAcceleration || + ENET_NET_TO_HOST_32 (command -> verifyConnect.packetThrottleDeceleration) != peer -> packetThrottleDeceleration) + { + peer -> state = ENET_PEER_STATE_ZOMBIE; + + return -1; + } + + enet_protocol_remove_sent_reliable_command (peer, 1, 0xFF); + + peer -> outgoingPeerID = ENET_NET_TO_HOST_16 (command -> verifyConnect.outgoingPeerID); + + mtu = ENET_NET_TO_HOST_16 (command -> verifyConnect.mtu); + + if (mtu < ENET_PROTOCOL_MINIMUM_MTU) + mtu = ENET_PROTOCOL_MINIMUM_MTU; + else + if (mtu > ENET_PROTOCOL_MAXIMUM_MTU) + mtu = ENET_PROTOCOL_MAXIMUM_MTU; + + if (mtu < peer -> mtu) + peer -> mtu = mtu; + + windowSize = ENET_NET_TO_HOST_32 (command -> verifyConnect.windowSize); + + if (windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) + windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + + if (windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) + windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + + if (windowSize < peer -> windowSize) + peer -> windowSize = windowSize; + + peer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> verifyConnect.incomingBandwidth); + peer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> verifyConnect.outgoingBandwidth); + + enet_protocol_notify_connect (host, peer, event); + return 0; +} + +static int +enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event) +{ + ENetProtocolHeader * header; + ENetProtocol * command; + ENetPeer * peer; + enet_uint8 * currentData; + size_t headerSize; + enet_uint16 peerID, flags; + + if (host -> receivedDataLength < sizeof (ENetProtocolHeader)) + return 0; + + header = (ENetProtocolHeader *) host -> receivedData; + + peerID = ENET_NET_TO_HOST_16 (header -> peerID); + flags = peerID & ENET_PROTOCOL_HEADER_FLAG_MASK; + peerID &= ~ ENET_PROTOCOL_HEADER_FLAG_MASK; + + if (peerID == ENET_PROTOCOL_MAXIMUM_PEER_ID) + peer = NULL; + else + if (peerID >= host -> peerCount) + return 0; + else + { + peer = & host -> peers [peerID]; + + if (peer -> state == ENET_PEER_STATE_DISCONNECTED || + peer -> state == ENET_PEER_STATE_ZOMBIE || + (host -> receivedAddress.host != peer -> address.host && + peer -> address.host != ENET_HOST_BROADCAST)) + return 0; + +#ifdef USE_CRC32 + { + enet_uint32 crc = header -> checksum; + ENetBuffer buffer; + + header -> checksum = peer -> sessionID; + + buffer.data = host -> receivedData; + buffer.dataLength = host -> receivedDataLength; + + if (enet_crc32 (& buffer, 1) != crc) + return 0; + } +#else + if (header -> checksum != peer -> sessionID) + return 0; +#endif + + peer -> address.host = host -> receivedAddress.host; + peer -> address.port = host -> receivedAddress.port; + peer -> incomingDataTotal += host -> receivedDataLength; + } + + headerSize = (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME ? sizeof (ENetProtocolHeader) : (size_t) & ((ENetProtocolHeader *) 0) -> sentTime); + currentData = host -> receivedData + headerSize; + + while (currentData < & host -> receivedData [host -> receivedDataLength]) + { + enet_uint8 commandNumber; + size_t commandSize; + + command = (ENetProtocol *) currentData; + + if (currentData + sizeof (ENetProtocolCommandHeader) > & host -> receivedData [host -> receivedDataLength]) + break; + + commandNumber = command -> header.command & ENET_PROTOCOL_COMMAND_MASK; + if (commandNumber >= ENET_PROTOCOL_COMMAND_COUNT) + break; + + commandSize = commandSizes [commandNumber]; + if (commandSize == 0 || currentData + commandSize > & host -> receivedData [host -> receivedDataLength]) + break; + + currentData += commandSize; + + if (peer == NULL && commandNumber != ENET_PROTOCOL_COMMAND_CONNECT) + break; + + command -> header.reliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> header.reliableSequenceNumber); + + switch (command -> header.command & ENET_PROTOCOL_COMMAND_MASK) + { + case ENET_PROTOCOL_COMMAND_ACKNOWLEDGE: + if (enet_protocol_handle_acknowledge (host, event, peer, command)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_CONNECT: + peer = enet_protocol_handle_connect (host, header, command); + if (peer == NULL) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_VERIFY_CONNECT: + if (enet_protocol_handle_verify_connect (host, event, peer, command)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_DISCONNECT: + if (enet_protocol_handle_disconnect (host, peer, command)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_PING: + if (enet_protocol_handle_ping (host, peer, command)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: + if (enet_protocol_handle_send_reliable (host, peer, command, & currentData)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: + if (enet_protocol_handle_send_unreliable (host, peer, command, & currentData)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: + if (enet_protocol_handle_send_unsequenced (host, peer, command, & currentData)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: + if (enet_protocol_handle_send_fragment (host, peer, command, & currentData)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT: + if (enet_protocol_handle_bandwidth_limit (host, peer, command)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE: + if (enet_protocol_handle_throttle_configure (host, peer, command)) + goto commandError; + break; + + default: + goto commandError; + } + + if (peer != NULL && + (command -> header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) != 0) + { + enet_uint16 sentTime; + + if (! (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME)) + break; + + sentTime = ENET_NET_TO_HOST_16 (header -> sentTime); + + switch (peer -> state) + { + case ENET_PEER_STATE_DISCONNECTING: + case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT: + break; + + case ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT: + if ((command -> header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_DISCONNECT) + enet_peer_queue_acknowledgement (peer, command, sentTime); + break; + + default: + enet_peer_queue_acknowledgement (peer, command, sentTime); + break; + } + } + } + +commandError: + if (event != NULL && event -> type != ENET_EVENT_TYPE_NONE) + return 1; + + return 0; +} + +static int +enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event) +{ + for (;;) + { + int receivedLength; + ENetBuffer buffer; + + buffer.data = host -> receivedData; + buffer.dataLength = sizeof (host -> receivedData); + + receivedLength = enet_socket_receive (host -> socket, + & host -> receivedAddress, + & buffer, + 1); + + if (receivedLength < 0) + return -1; + + if (receivedLength == 0) + return 0; + + host -> receivedDataLength = receivedLength; + + switch (enet_protocol_handle_incoming_commands (host, event)) + { + case 1: + return 1; + + case -1: + return -1; + + default: + break; + } + } + + return -1; +} + +static void +enet_protocol_send_acknowledgements (ENetHost * host, ENetPeer * peer) +{ + ENetProtocol * command = & host -> commands [host -> commandCount]; + ENetBuffer * buffer = & host -> buffers [host -> bufferCount]; + ENetAcknowledgement * acknowledgement; + ENetListIterator currentAcknowledgement; + + currentAcknowledgement = enet_list_begin (& peer -> acknowledgements); + + while (currentAcknowledgement != enet_list_end (& peer -> acknowledgements)) + { + if (command >= & host -> commands [sizeof (host -> commands) / sizeof (ENetProtocol)] || + buffer >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] || + peer -> mtu - host -> packetSize < sizeof (ENetProtocolAcknowledge)) + { + host -> continueSending = 1; + + break; + } + + acknowledgement = (ENetAcknowledgement *) currentAcknowledgement; + + currentAcknowledgement = enet_list_next (currentAcknowledgement); + + buffer -> data = command; + buffer -> dataLength = sizeof (ENetProtocolAcknowledge); + + host -> packetSize += buffer -> dataLength; + + command -> header.command = ENET_PROTOCOL_COMMAND_ACKNOWLEDGE; + command -> header.channelID = acknowledgement -> command.header.channelID; + command -> acknowledge.receivedReliableSequenceNumber = ENET_HOST_TO_NET_16 (acknowledgement -> command.header.reliableSequenceNumber); + command -> acknowledge.receivedSentTime = ENET_HOST_TO_NET_16 (acknowledgement -> sentTime); + + if ((acknowledgement -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_DISCONNECT) + peer -> state = ENET_PEER_STATE_ZOMBIE; + + enet_list_remove (& acknowledgement -> acknowledgementList); + enet_free (acknowledgement); + + ++ command; + ++ buffer; + } + + host -> commandCount = command - host -> commands; + host -> bufferCount = buffer - host -> buffers; +} + +static void +enet_protocol_send_unreliable_outgoing_commands (ENetHost * host, ENetPeer * peer) +{ + ENetProtocol * command = & host -> commands [host -> commandCount]; + ENetBuffer * buffer = & host -> buffers [host -> bufferCount]; + ENetOutgoingCommand * outgoingCommand; + ENetListIterator currentCommand; + + currentCommand = enet_list_begin (& peer -> outgoingUnreliableCommands); + + while (currentCommand != enet_list_end (& peer -> outgoingUnreliableCommands)) + { + size_t commandSize; + + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + commandSize = commandSizes [outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK]; + + if (command >= & host -> commands [sizeof (host -> commands) / sizeof (ENetProtocol)] || + buffer + 1 >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] || + peer -> mtu - host -> packetSize < commandSize || + (outgoingCommand -> packet != NULL && + peer -> mtu - host -> packetSize < commandSize + outgoingCommand -> packet -> dataLength)) + { + host -> continueSending = 1; + + break; + } + + currentCommand = enet_list_next (currentCommand); + + if (outgoingCommand -> packet != NULL) + { + peer -> packetThrottleCounter += ENET_PEER_PACKET_THROTTLE_COUNTER; + peer -> packetThrottleCounter %= ENET_PEER_PACKET_THROTTLE_SCALE; + + if (peer -> packetThrottleCounter > peer -> packetThrottle) + { + -- outgoingCommand -> packet -> referenceCount; + + if (outgoingCommand -> packet -> referenceCount == 0) + enet_packet_destroy (outgoingCommand -> packet); + + enet_list_remove (& outgoingCommand -> outgoingCommandList); + enet_free (outgoingCommand); + + continue; + } + } + + buffer -> data = command; + buffer -> dataLength = commandSize; + + host -> packetSize += buffer -> dataLength; + + * command = outgoingCommand -> command; + + enet_list_remove (& outgoingCommand -> outgoingCommandList); + + if (outgoingCommand -> packet != NULL) + { + ++ buffer; + + buffer -> data = outgoingCommand -> packet -> data; + buffer -> dataLength = outgoingCommand -> packet -> dataLength; + + host -> packetSize += buffer -> dataLength; + + enet_list_insert (enet_list_end (& peer -> sentUnreliableCommands), outgoingCommand); + } + else + enet_free (outgoingCommand); + + ++ command; + ++ buffer; + } + + host -> commandCount = command - host -> commands; + host -> bufferCount = buffer - host -> buffers; + + if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER && + enet_list_empty (& peer -> outgoingReliableCommands) && + enet_list_empty (& peer -> outgoingUnreliableCommands) && + enet_list_empty (& peer -> sentReliableCommands)) + enet_peer_disconnect (peer, peer -> disconnectData); +} + +static int +enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * event) +{ + ENetOutgoingCommand * outgoingCommand; + ENetListIterator currentCommand, insertPosition; + + currentCommand = enet_list_begin (& peer -> sentReliableCommands); + insertPosition = enet_list_begin (& peer -> outgoingReliableCommands); + + while (currentCommand != enet_list_end (& peer -> sentReliableCommands)) + { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + currentCommand = enet_list_next (currentCommand); + + if (ENET_TIME_DIFFERENCE (host -> serviceTime, outgoingCommand -> sentTime) < outgoingCommand -> roundTripTimeout) + continue; + + if (peer -> earliestTimeout == 0 || + ENET_TIME_LESS (outgoingCommand -> sentTime, peer -> earliestTimeout)) + peer -> earliestTimeout = outgoingCommand -> sentTime; + + if (peer -> earliestTimeout != 0 && + (ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= ENET_PEER_TIMEOUT_MAXIMUM || + (outgoingCommand -> roundTripTimeout >= outgoingCommand -> roundTripTimeoutLimit && + ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= ENET_PEER_TIMEOUT_MINIMUM))) + { + enet_protocol_notify_disconnect (host, peer, event); + + return 1; + } + + if (outgoingCommand -> packet != NULL) + peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength; + + ++ peer -> packetsLost; + + outgoingCommand -> roundTripTimeout *= 2; + + enet_list_insert (insertPosition, enet_list_remove (& outgoingCommand -> outgoingCommandList)); + + if (currentCommand == enet_list_begin (& peer -> sentReliableCommands) && + ! enet_list_empty (& peer -> sentReliableCommands)) + { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + peer -> nextTimeout = outgoingCommand -> sentTime + outgoingCommand -> roundTripTimeout; + } + } + + return 0; +} + +static void +enet_protocol_send_reliable_outgoing_commands (ENetHost * host, ENetPeer * peer) +{ + ENetProtocol * command = & host -> commands [host -> commandCount]; + ENetBuffer * buffer = & host -> buffers [host -> bufferCount]; + ENetOutgoingCommand * outgoingCommand; + ENetListIterator currentCommand; + ENetChannel *channel; + enet_uint16 reliableWindow; + size_t commandSize; + + currentCommand = enet_list_begin (& peer -> outgoingReliableCommands); + + while (currentCommand != enet_list_end (& peer -> outgoingReliableCommands)) + { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + channel = outgoingCommand -> command.header.channelID < peer -> channelCount ? & peer -> channels [outgoingCommand -> command.header.channelID] : NULL; + reliableWindow = outgoingCommand -> reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + if (channel != NULL && + outgoingCommand -> sendAttempts < 1 && + ! (outgoingCommand -> reliableSequenceNumber % ENET_PEER_RELIABLE_WINDOW_SIZE) && + (channel -> reliableWindows [(reliableWindow + ENET_PEER_RELIABLE_WINDOWS - 1) % ENET_PEER_RELIABLE_WINDOWS] >= ENET_PEER_RELIABLE_WINDOW_SIZE || + channel -> usedReliableWindows & ((((1 << ENET_PEER_FREE_RELIABLE_WINDOWS) - 1) << reliableWindow) | + (((1 << ENET_PEER_FREE_RELIABLE_WINDOWS) - 1) >> (ENET_PEER_RELIABLE_WINDOW_SIZE - reliableWindow))))) + break; + + commandSize = commandSizes [outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK]; + if (command >= & host -> commands [sizeof (host -> commands) / sizeof (ENetProtocol)] || + buffer + 1 >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] || + peer -> mtu - host -> packetSize < commandSize) + { + host -> continueSending = 1; + + break; + } + + if (outgoingCommand -> packet != NULL) + { + if (peer -> reliableDataInTransit + outgoingCommand -> fragmentLength > peer -> windowSize) + break; + + if ((enet_uint16) (peer -> mtu - host -> packetSize) < (enet_uint16) (commandSize + outgoingCommand -> fragmentLength)) + { + host -> continueSending = 1; + + break; + } + } + + currentCommand = enet_list_next (currentCommand); + + if (channel != NULL && outgoingCommand -> sendAttempts < 1) + { + channel -> usedReliableWindows |= 1 << reliableWindow; + ++ channel -> reliableWindows [reliableWindow]; + } + + ++ outgoingCommand -> sendAttempts; + + if (outgoingCommand -> roundTripTimeout == 0) + { + outgoingCommand -> roundTripTimeout = peer -> roundTripTime + 4 * peer -> roundTripTimeVariance; + outgoingCommand -> roundTripTimeoutLimit = ENET_PEER_TIMEOUT_LIMIT * outgoingCommand -> roundTripTimeout; + } + + if (enet_list_empty (& peer -> sentReliableCommands)) + peer -> nextTimeout = host -> serviceTime + outgoingCommand -> roundTripTimeout; + + enet_list_insert (enet_list_end (& peer -> sentReliableCommands), + enet_list_remove (& outgoingCommand -> outgoingCommandList)); + + outgoingCommand -> sentTime = host -> serviceTime; + + buffer -> data = command; + buffer -> dataLength = commandSize; + + host -> packetSize += buffer -> dataLength; + host -> headerFlags |= ENET_PROTOCOL_HEADER_FLAG_SENT_TIME; + + * command = outgoingCommand -> command; + + if (outgoingCommand -> packet != NULL) + { + ++ buffer; + + buffer -> data = outgoingCommand -> packet -> data + outgoingCommand -> fragmentOffset; + buffer -> dataLength = outgoingCommand -> fragmentLength; + + host -> packetSize += outgoingCommand -> fragmentLength; + + peer -> reliableDataInTransit += outgoingCommand -> fragmentLength; + } + + ++ peer -> packetsSent; + + ++ command; + ++ buffer; + } + + host -> commandCount = command - host -> commands; + host -> bufferCount = buffer - host -> buffers; +} + +static int +enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int checkForTimeouts) +{ + ENetProtocolHeader header; + ENetPeer * currentPeer; + int sentLength; + + host -> continueSending = 1; + + while (host -> continueSending) + for (host -> continueSending = 0, + currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) + { + if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED || + currentPeer -> state == ENET_PEER_STATE_ZOMBIE) + continue; + + host -> headerFlags = 0; + host -> commandCount = 0; + host -> bufferCount = 1; + host -> packetSize = sizeof (ENetProtocolHeader); + + if (! enet_list_empty (& currentPeer -> acknowledgements)) + enet_protocol_send_acknowledgements (host, currentPeer); + + if (checkForTimeouts != 0 && + ! enet_list_empty (& currentPeer -> sentReliableCommands) && + ENET_TIME_GREATER_EQUAL (host -> serviceTime, currentPeer -> nextTimeout) && + enet_protocol_check_timeouts (host, currentPeer, event) == 1) + return 1; + + if (! enet_list_empty (& currentPeer -> outgoingReliableCommands)) + enet_protocol_send_reliable_outgoing_commands (host, currentPeer); + else + if (enet_list_empty (& currentPeer -> sentReliableCommands) && + ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> lastReceiveTime) >= ENET_PEER_PING_INTERVAL && + currentPeer -> mtu - host -> packetSize >= sizeof (ENetProtocolPing)) + { + enet_peer_ping (currentPeer); + enet_protocol_send_reliable_outgoing_commands (host, currentPeer); + } + + if (! enet_list_empty (& currentPeer -> outgoingUnreliableCommands)) + enet_protocol_send_unreliable_outgoing_commands (host, currentPeer); + + if (host -> commandCount == 0) + continue; + + if (currentPeer -> packetLossEpoch == 0) + currentPeer -> packetLossEpoch = host -> serviceTime; + else + if (ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> packetLossEpoch) >= ENET_PEER_PACKET_LOSS_INTERVAL && + currentPeer -> packetsSent > 0) + { + enet_uint32 packetLoss = currentPeer -> packetsLost * ENET_PEER_PACKET_LOSS_SCALE / currentPeer -> packetsSent; + +#ifdef ENET_DEBUG +#ifdef WIN32 + printf ( +#else + fprintf (stderr, +#endif + "peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u/%u outgoing, %u/%u incoming\n", currentPeer -> incomingPeerID, currentPeer -> packetLoss / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> packetLossVariance / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> roundTripTime, currentPeer -> roundTripTimeVariance, currentPeer -> packetThrottle / (float) ENET_PEER_PACKET_THROTTLE_SCALE, enet_list_size (& currentPeer -> outgoingReliableCommands), enet_list_size (& currentPeer -> outgoingUnreliableCommands), currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingReliableCommands) : 0, currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingUnreliableCommands) : 0); +#endif + + currentPeer -> packetLossVariance -= currentPeer -> packetLossVariance / 4; + + if (packetLoss >= currentPeer -> packetLoss) + { + currentPeer -> packetLoss += (packetLoss - currentPeer -> packetLoss) / 8; + currentPeer -> packetLossVariance += (packetLoss - currentPeer -> packetLoss) / 4; + } + else + { + currentPeer -> packetLoss -= (currentPeer -> packetLoss - packetLoss) / 8; + currentPeer -> packetLossVariance += (currentPeer -> packetLoss - packetLoss) / 4; + } + + currentPeer -> packetLossEpoch = host -> serviceTime; + currentPeer -> packetsSent = 0; + currentPeer -> packetsLost = 0; + } + + header.checksum = currentPeer -> sessionID; + header.peerID = ENET_HOST_TO_NET_16 (currentPeer -> outgoingPeerID | host -> headerFlags); + + host -> buffers -> data = & header; + if (host -> headerFlags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME) + { + header.sentTime = ENET_HOST_TO_NET_16 (host -> serviceTime & 0xFFFF); + + host -> buffers -> dataLength = sizeof (ENetProtocolHeader); + } + else + host -> buffers -> dataLength = (size_t) & ((ENetProtocolHeader *) 0) -> sentTime; + +#ifdef USE_CRC32 + header.checksum = enet_crc32 (host -> buffers, host -> bufferCount); +#endif + + currentPeer -> lastSendTime = host -> serviceTime; + + sentLength = enet_socket_send (host -> socket, & currentPeer -> address, host -> buffers, host -> bufferCount); + + enet_protocol_remove_sent_unreliable_commands (currentPeer); + + if (sentLength < 0) + return -1; + } + + return 0; +} + +/** Sends any queued packets on the host specified to its designated peers. + + @param host host to flush + @remarks this function need only be used in circumstances where one wishes to send queued packets earlier than in a call to enet_host_service(). + @ingroup host +*/ +void +enet_host_flush (ENetHost * host) +{ + host -> serviceTime = enet_time_get (); + + enet_protocol_send_outgoing_commands (host, NULL, 0); +} + +/** Checks for any queued events on the host and dispatches one if available. + + @param host host to check for events + @param event an event structure where event details will be placed if available + @retval > 0 if an event was dispatched + @retval 0 if no events are available + @retval < 0 on failure + @ingroup host +*/ +int +enet_host_check_events (ENetHost * host, ENetEvent * event) +{ + if (event == NULL) return -1; + + event -> type = ENET_EVENT_TYPE_NONE; + event -> peer = NULL; + event -> packet = NULL; + + return enet_protocol_dispatch_incoming_commands (host, event); +} + +/** Waits for events on the host specified and shuttles packets between + the host and its peers. + + @param host host to service + @param event an event structure where event details will be placed if one occurs + if event == NULL then no events will be delivered + @param timeout number of milliseconds that ENet should wait for events + @retval > 0 if an event occurred within the specified time limit + @retval 0 if no event occurred + @retval < 0 on failure + @remarks enet_host_service should be called fairly regularly for adequate performance + @ingroup host +*/ +int +enet_host_service (ENetHost * host, ENetEvent * event, enet_uint32 timeout) +{ + enet_uint32 waitCondition; + + if (event != NULL) + { + event -> type = ENET_EVENT_TYPE_NONE; + event -> peer = NULL; + event -> packet = NULL; + + switch (enet_protocol_dispatch_incoming_commands (host, event)) + { + case 1: + return 1; + + case -1: + perror ("Error dispatching incoming packets"); + + return -1; + + default: + break; + } + } + + host -> serviceTime = enet_time_get (); + + timeout += host -> serviceTime; + + do + { + if (ENET_TIME_DIFFERENCE (host -> serviceTime, host -> bandwidthThrottleEpoch) >= ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL) + enet_host_bandwidth_throttle (host); + + switch (enet_protocol_send_outgoing_commands (host, event, 1)) + { + case 1: + return 1; + + case -1: + perror ("Error sending outgoing packets"); + + return -1; + + default: + break; + } + + switch (enet_protocol_receive_incoming_commands (host, event)) + { + case 1: + return 1; + + case -1: + perror ("Error receiving incoming packets"); + + return -1; + + default: + break; + } + + switch (enet_protocol_send_outgoing_commands (host, event, 1)) + { + case 1: + return 1; + + case -1: + perror ("Error sending outgoing packets"); + + return -1; + + default: + break; + } + + if (event != NULL) + { + switch (enet_protocol_dispatch_incoming_commands (host, event)) + { + case 1: + return 1; + + case -1: + perror ("Error dispatching incoming packets"); + + return -1; + + default: + break; + } + } + + host -> serviceTime = enet_time_get (); + + if (ENET_TIME_GREATER_EQUAL (host -> serviceTime, timeout)) + return 0; + + waitCondition = ENET_SOCKET_WAIT_RECEIVE; + + if (enet_socket_wait (host -> socket, & waitCondition, ENET_TIME_DIFFERENCE (timeout, host -> serviceTime)) != 0) + return -1; + + host -> serviceTime = enet_time_get (); + } while (waitCondition == ENET_SOCKET_WAIT_RECEIVE); + + return 0; +} + diff --git a/polymer/eduke32/source/enet/src/unix.c b/polymer/eduke32/source/enet/src/unix.c new file mode 100644 index 000000000..a7943c39d --- /dev/null +++ b/polymer/eduke32/source/enet/src/unix.c @@ -0,0 +1,438 @@ +/** + @file unix.c + @brief ENet Unix system specific functions +*/ +#ifndef WIN32 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +#ifdef HAS_FCNTL +#include +#endif + +#ifdef __APPLE__ +#undef HAS_POLL +#endif + +#ifdef HAS_POLL +#include +#endif + +#ifndef HAS_SOCKLEN_T +// typedef int socklen_t; +#endif + +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif + +static enet_uint32 timeBase = 0; + +int +enet_initialize (void) +{ + return 0; +} + +void +enet_deinitialize (void) +{ +} + +enet_uint32 +enet_time_get (void) +{ + struct timeval timeVal; + + gettimeofday (& timeVal, NULL); + + return timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - timeBase; +} + +void +enet_time_set (enet_uint32 newTimeBase) +{ + struct timeval timeVal; + + gettimeofday (& timeVal, NULL); + + timeBase = timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - newTimeBase; +} + +int +enet_address_set_host (ENetAddress * address, const char * name) +{ + struct hostent * hostEntry = NULL; +#ifdef HAS_GETHOSTBYNAME_R + struct hostent hostData; + char buffer [2048]; + int errnum; + +#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) + gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum); +#else + hostEntry = gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & errnum); +#endif +#else + hostEntry = gethostbyname (name); +#endif + + if (hostEntry == NULL || + hostEntry -> h_addrtype != AF_INET) + { +#ifdef HAS_INET_PTON + if (! inet_pton (AF_INET, name, & address -> host)) +#else + if (! inet_aton (name, (struct in_addr *) & address -> host)) +#endif + return -1; + return 0; + } + + address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0]; + + return 0; +} + +int +enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength) +{ +#ifdef HAS_INET_NTOP + if (inet_ntop (AF_INET, & address -> host, name, nameLength) == NULL) +#else + char * addr = inet_ntoa (* (struct in_addr *) & address -> host); + if (addr != NULL) + strncpy (name, addr, nameLength); + else +#endif + return -1; + return 0; +} + +int +enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength) +{ + struct in_addr in; + struct hostent * hostEntry = NULL; +#ifdef HAS_GETHOSTBYADDR_R + struct hostent hostData; + char buffer [2048]; + int errnum; + + in.s_addr = address -> host; + +#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) + gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum); +#else + hostEntry = gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & errnum); +#endif +#else + in.s_addr = address -> host; + + hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET); +#endif + + if (hostEntry == NULL) + return enet_address_get_host_ip (address, name, nameLength); + + strncpy (name, hostEntry -> h_name, nameLength); + + return 0; +} + +int +enet_socket_bind (ENetSocket socket, const ENetAddress * address) +{ + struct sockaddr_in sin; + + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + + if (address != NULL) + { + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + } + else + { + sin.sin_port = 0; + sin.sin_addr.s_addr = INADDR_ANY; + } + + return bind (socket, + (struct sockaddr *) & sin, + sizeof (struct sockaddr_in)); +} + +int +enet_socket_listen (ENetSocket socket, int backlog) +{ + return listen (socket, backlog < 0 ? SOMAXCONN : backlog); +} + +ENetSocket +enet_socket_create (ENetSocketType type) +{ + return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); +} + +int +enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value) +{ + int result = -1; + switch (option) + { + case ENET_SOCKOPT_NONBLOCK: +#ifdef HAS_FCNTL + result = fcntl (socket, F_SETFL, O_NONBLOCK | fcntl (socket, F_GETFL)); +#else + result = ioctl (socket, FIONBIO, & value); +#endif + break; + + case ENET_SOCKOPT_BROADCAST: + result = setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_REUSEADDR: + result = setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_RCVBUF: + result = setsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_SNDBUF: + result = setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (char *) & value, sizeof (int)); + break; + + default: + break; + } + return result == -1 ? -1 : 0; +} + +int +enet_socket_connect (ENetSocket socket, const ENetAddress * address) +{ + struct sockaddr_in sin; + + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + + return connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in)); +} + +ENetSocket +enet_socket_accept (ENetSocket socket, ENetAddress * address) +{ + int result; + struct sockaddr_in sin; + socklen_t sinLength = sizeof (struct sockaddr_in); + + result = accept (socket, + address != NULL ? (struct sockaddr *) & sin : NULL, + address != NULL ? & sinLength : NULL); + + if (result == -1) + return ENET_SOCKET_NULL; + + if (address != NULL) + { + address -> host = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + } + + return result; +} + +void +enet_socket_destroy (ENetSocket socket) +{ + close (socket); +} + +int +enet_socket_send (ENetSocket socket, + const ENetAddress * address, + const ENetBuffer * buffers, + size_t bufferCount) +{ + struct msghdr msgHdr; + struct sockaddr_in sin; + int sentLength; + + memset (& msgHdr, 0, sizeof (struct msghdr)); + + if (address != NULL) + { + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + + msgHdr.msg_name = & sin; + msgHdr.msg_namelen = sizeof (struct sockaddr_in); + } + + msgHdr.msg_iov = (struct iovec *) buffers; + msgHdr.msg_iovlen = bufferCount; + + sentLength = sendmsg (socket, & msgHdr, MSG_NOSIGNAL); + + if (sentLength == -1) + { + if (errno == EWOULDBLOCK) + return 0; + + return -1; + } + + return sentLength; +} + +int +enet_socket_receive (ENetSocket socket, + ENetAddress * address, + ENetBuffer * buffers, + size_t bufferCount) +{ + struct msghdr msgHdr; + struct sockaddr_in sin; + int recvLength; + + memset (& msgHdr, 0, sizeof (struct msghdr)); + + if (address != NULL) + { + msgHdr.msg_name = & sin; + msgHdr.msg_namelen = sizeof (struct sockaddr_in); + } + + msgHdr.msg_iov = (struct iovec *) buffers; + msgHdr.msg_iovlen = bufferCount; + + recvLength = recvmsg (socket, & msgHdr, MSG_NOSIGNAL); + + if (recvLength == -1) + { + if (errno == EWOULDBLOCK) + return 0; + + return -1; + } + +#ifdef HAS_MSGHDR_FLAGS + if (msgHdr.msg_flags & MSG_TRUNC) + return -1; +#endif + + if (address != NULL) + { + address -> host = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + } + + return recvLength; +} + +int +enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocketSet * writeSet, enet_uint32 timeout) +{ + struct timeval timeVal; + + timeVal.tv_sec = timeout / 1000; + timeVal.tv_usec = (timeout % 1000) * 1000; + + return select (maxSocket + 1, readSet, writeSet, NULL, & timeVal); +} + +int +enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeout) +{ +#ifdef HAS_POLL + struct pollfd pollSocket; + int pollCount; + + pollSocket.fd = socket; + pollSocket.events = 0; + + if (* condition & ENET_SOCKET_WAIT_SEND) + pollSocket.events |= POLLOUT; + + if (* condition & ENET_SOCKET_WAIT_RECEIVE) + pollSocket.events |= POLLIN; + + pollCount = poll (& pollSocket, 1, timeout); + + if (pollCount < 0) + return -1; + + * condition = ENET_SOCKET_WAIT_NONE; + + if (pollCount == 0) + return 0; + + if (pollSocket.revents & POLLOUT) + * condition |= ENET_SOCKET_WAIT_SEND; + + if (pollSocket.revents & POLLIN) + * condition |= ENET_SOCKET_WAIT_RECEIVE; + + return 0; +#else + fd_set readSet, writeSet; + struct timeval timeVal; + int selectCount; + + timeVal.tv_sec = timeout / 1000; + timeVal.tv_usec = (timeout % 1000) * 1000; + + FD_ZERO (& readSet); + FD_ZERO (& writeSet); + + if (* condition & ENET_SOCKET_WAIT_SEND) + FD_SET (socket, & writeSet); + + if (* condition & ENET_SOCKET_WAIT_RECEIVE) + FD_SET (socket, & readSet); + + selectCount = select (socket + 1, & readSet, & writeSet, NULL, & timeVal); + + if (selectCount < 0) + return -1; + + * condition = ENET_SOCKET_WAIT_NONE; + + if (selectCount == 0) + return 0; + + if (FD_ISSET (socket, & writeSet)) + * condition |= ENET_SOCKET_WAIT_SEND; + + if (FD_ISSET (socket, & readSet)) + * condition |= ENET_SOCKET_WAIT_RECEIVE; + + return 0; +#endif +} + +#endif + diff --git a/polymer/eduke32/source/enet/src/win32.c b/polymer/eduke32/source/enet/src/win32.c new file mode 100644 index 000000000..e1fae2330 --- /dev/null +++ b/polymer/eduke32/source/enet/src/win32.c @@ -0,0 +1,348 @@ +/** + @file win32.c + @brief ENet Win32 system specific functions +*/ +#ifdef WIN32 + +#include +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +static enet_uint32 timeBase = 0; + +int +enet_initialize (void) +{ + WORD versionRequested = MAKEWORD (1, 1); + WSADATA wsaData; + + if (WSAStartup (versionRequested, & wsaData)) + return -1; + + if (LOBYTE (wsaData.wVersion) != 1|| + HIBYTE (wsaData.wVersion) != 1) + { + WSACleanup (); + + return -1; + } + + timeBeginPeriod (1); + + return 0; +} + +void +enet_deinitialize (void) +{ + timeEndPeriod (1); + + WSACleanup (); +} + +enet_uint32 +enet_time_get (void) +{ + return (enet_uint32) timeGetTime () - timeBase; +} + +void +enet_time_set (enet_uint32 newTimeBase) +{ + timeBase = (enet_uint32) timeGetTime () - newTimeBase; +} + +int +enet_address_set_host (ENetAddress * address, const char * name) +{ + struct hostent * hostEntry; + + hostEntry = gethostbyname (name); + if (hostEntry == NULL || + hostEntry -> h_addrtype != AF_INET) + { + unsigned long host = inet_addr (name); + if (host == INADDR_NONE) + return -1; + address -> host = host; + return 0; + } + + address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0]; + + return 0; +} + +int +enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength) +{ + char * addr = inet_ntoa (* (struct in_addr *) & address -> host); + if (addr == NULL) + return -1; + strncpy (name, addr, nameLength); + return 0; +} + +int +enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength) +{ + struct in_addr in; + struct hostent * hostEntry; + + in.s_addr = address -> host; + + hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET); + if (hostEntry == NULL) + return enet_address_get_host_ip (address, name, nameLength); + + strncpy (name, hostEntry -> h_name, nameLength); + + return 0; +} + +int +enet_socket_bind (ENetSocket socket, const ENetAddress * address) +{ + struct sockaddr_in sin; + + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + + if (address != NULL) + { + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + } + else + { + sin.sin_port = 0; + sin.sin_addr.s_addr = INADDR_ANY; + } + + return bind (socket, + (struct sockaddr *) & sin, + sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 0; +} + +int +enet_socket_listen (ENetSocket socket, int backlog) +{ + return listen (socket, backlog < 0 ? SOMAXCONN : backlog) == SOCKET_ERROR ? -1 : 0; +} + +ENetSocket +enet_socket_create (ENetSocketType type) +{ + return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); +} + +int +enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value) +{ + int result = SOCKET_ERROR; + switch (option) + { + case ENET_SOCKOPT_NONBLOCK: + { + u_long nonBlocking = (u_long) value; + result = ioctlsocket (socket, FIONBIO, & nonBlocking); + break; + } + + case ENET_SOCKOPT_BROADCAST: + result = setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_REUSEADDR: + result = setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_RCVBUF: + result = setsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_SNDBUF: + result = setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (char *) & value, sizeof (int)); + break; + + default: + break; + } + return result == SOCKET_ERROR ? -1 : 0; +} + +int +enet_socket_connect (ENetSocket socket, const ENetAddress * address) +{ + struct sockaddr_in sin; + + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + + return connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 0; +} + +ENetSocket +enet_socket_accept (ENetSocket socket, ENetAddress * address) +{ + SOCKET result; + struct sockaddr_in sin; + int sinLength = sizeof (struct sockaddr_in); + + result = accept (socket, + address != NULL ? (struct sockaddr *) & sin : NULL, + address != NULL ? & sinLength : NULL); + + if (result == INVALID_SOCKET) + return ENET_SOCKET_NULL; + + if (address != NULL) + { + address -> host = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + } + + return result; +} + +void +enet_socket_destroy (ENetSocket socket) +{ + closesocket (socket); +} + +int +enet_socket_send (ENetSocket socket, + const ENetAddress * address, + const ENetBuffer * buffers, + size_t bufferCount) +{ + struct sockaddr_in sin; + DWORD sentLength; + + if (address != NULL) + { + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + } + + if (WSASendTo (socket, + (LPWSABUF) buffers, + (DWORD) bufferCount, + & sentLength, + 0, + address != NULL ? (struct sockaddr *) & sin : 0, + address != NULL ? sizeof (struct sockaddr_in) : 0, + NULL, + NULL) == SOCKET_ERROR) + { + if (WSAGetLastError () == WSAEWOULDBLOCK) + return 0; + + return -1; + } + + return (int) sentLength; +} + +int +enet_socket_receive (ENetSocket socket, + ENetAddress * address, + ENetBuffer * buffers, + size_t bufferCount) +{ + INT sinLength = sizeof (struct sockaddr_in); + DWORD flags = 0, + recvLength; + struct sockaddr_in sin; + + if (WSARecvFrom (socket, + (LPWSABUF) buffers, + (DWORD) bufferCount, + & recvLength, + & flags, + address != NULL ? (struct sockaddr *) & sin : NULL, + address != NULL ? & sinLength : NULL, + NULL, + NULL) == SOCKET_ERROR) + { + switch (WSAGetLastError ()) + { + case WSAEWOULDBLOCK: + case WSAECONNRESET: + return 0; + } + + return -1; + } + + if (flags & MSG_PARTIAL) + return -1; + + if (address != NULL) + { + address -> host = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + } + + return (int) recvLength; +} + +int +enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocketSet * writeSet, enet_uint32 timeout) +{ + struct timeval timeVal; + + timeVal.tv_sec = timeout / 1000; + timeVal.tv_usec = (timeout % 1000) * 1000; + + return select (maxSocket + 1, readSet, writeSet, NULL, & timeVal); +} + +int +enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeout) +{ + fd_set readSet, writeSet; + struct timeval timeVal; + int selectCount; + + timeVal.tv_sec = timeout / 1000; + timeVal.tv_usec = (timeout % 1000) * 1000; + + FD_ZERO (& readSet); + FD_ZERO (& writeSet); + + if (* condition & ENET_SOCKET_WAIT_SEND) + FD_SET (socket, & writeSet); + + if (* condition & ENET_SOCKET_WAIT_RECEIVE) + FD_SET (socket, & readSet); + + selectCount = select (socket + 1, & readSet, & writeSet, NULL, & timeVal); + + if (selectCount < 0) + return -1; + + * condition = ENET_SOCKET_WAIT_NONE; + + if (selectCount == 0) + return 0; + + if (FD_ISSET (socket, & writeSet)) + * condition |= ENET_SOCKET_WAIT_SEND; + + if (FD_ISSET (socket, & readSet)) + * condition |= ENET_SOCKET_WAIT_RECEIVE; + + return 0; +} + +#endif + diff --git a/polymer/eduke32/source/funct.h b/polymer/eduke32/source/funct.h index b5c0de1b7..07fc9d06e 100644 --- a/polymer/eduke32/source/funct.h +++ b/polymer/eduke32/source/funct.h @@ -183,6 +183,7 @@ extern int32_t A_IncurDamage(int32_t sn); extern void G_MoveWorld(void); extern void A_MoveCyclers(void); extern void A_MoveDummyPlayers(void); +extern void P_ResetStatus(int32_t snum); // game.c extern inline void G_SetStatusBarScale(int32_t sc); diff --git a/polymer/eduke32/source/game.c b/polymer/eduke32/source/game.c index 757955b41..96a988e6c 100644 --- a/polymer/eduke32/source/game.c +++ b/polymer/eduke32/source/game.c @@ -42,10 +42,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "grpscan.h" #include "gamedef.h" #include "kplib.h" -//#include "crc32.h" +#include "crc32.h" #include "util_lib.h" #include "hightile.h" +#include "enet/enet.h" +#include "quicklz.h" + +ENetHost * net_server = NULL; +ENetHost * net_client = NULL; +ENetPeer * net_peer = NULL; + #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include @@ -86,9 +93,6 @@ uint8_t waterpal[768], slimepal[768], titlepal[768], drealms[768], endingpal[768 static char firstdemofile[80] = { '\0' }; static int32_t userconfiles = 0; -static int32_t netparamcount = 0; -static char **netparam = NULL; - int32_t voting = -1; int32_t vote_map = -1, vote_episode = -1; @@ -140,11 +144,11 @@ int32_t tempwallptr; static int32_t nonsharedtimer; +int32_t ticrandomseed; + static void G_DrawCameraText(int16_t i); static inline int32_t G_MoveLoop(void); static void G_DoOrderScreen(void); -static void Net_DoPrediction(void); -static void Net_CorrectPrediction(void); static int32_t G_DoMoveThings(void); static int32_t G_PlaybackDemo(void); @@ -155,6 +159,8 @@ extern void computergetinput(int32_t snum, input_t *syn); #define USERQUOTE_LEFTOFFSET 5 #define USERQUOTE_RIGHTOFFSET 14 +#define quotepulseshade (sintable[(totalclock<<5)&2047]>>11) + int32_t althud_numbertile = 2930; int32_t althud_numberpal = 0; int32_t althud_shadows = 1; @@ -529,10 +535,15 @@ void G_AddUserQuote(const char *daquote) int32_t lastpackettime = 0; -#include "sync.c" - void G_HandleSpecialKeys(void) { + // we need CONTROL_GetInput in order to pick up joystick button presses + if (CONTROL_Started && !(g_player[myconnectindex].ps->gm & MODE_GAME)) + { + ControlInfo noshareinfo; + CONTROL_GetInput(&noshareinfo); + } + CONTROL_ProcessBinds(); if (ALT_IS_PRESSED && KB_KeyPressed(sc_Enter)) @@ -569,179 +580,482 @@ void G_HandleSpecialKeys(void) } } -void Net_GetPackets(void) +void Net_Disconnect(void) { - int32_t i, j, k, l; - int32_t other; - int32_t packbufleng; + if (net_client) + { + ENetEvent event; - input_t *osyn, *nsyn; + if (net_peer) + enet_peer_disconnect(net_peer, 0); - sampletimer(); - MUSIC_Update(); + while (enet_host_service (net_client, & event, 3000) > 0) + { + switch (event.type) + { + case ENET_EVENT_TYPE_CONNECT: + case ENET_EVENT_TYPE_NONE: + case ENET_EVENT_TYPE_RECEIVE: + enet_packet_destroy (event.packet); + break; + + case ENET_EVENT_TYPE_DISCONNECT: + G_GameExit(" "); + break; + } + } + + enet_peer_reset(net_peer); + net_peer = NULL; + enet_host_destroy(net_client); + } - G_HandleSpecialKeys(); + if (net_server) + { + ENetPeer * currentPeer; + ENetEvent event; + + for (currentPeer = net_server -> peers; + currentPeer < & net_server -> peers [net_server -> peerCount]; + ++ currentPeer) + { + enet_peer_disconnect (currentPeer, 0); + } + + while (enet_host_service (net_server, & event, 3000) > 0) + { + switch (event.type) + { + case ENET_EVENT_TYPE_CONNECT: + case ENET_EVENT_TYPE_NONE: + case ENET_EVENT_TYPE_RECEIVE: + case ENET_EVENT_TYPE_DISCONNECT: + if (event.packet) + enet_packet_destroy (event.packet); + break; + } + } + enet_host_destroy(net_server); + } +} + +int32_t quittimer = 0; + +void Net_SendQuit(void) +{ + if (g_gameQuit == 0 && (numplayers > 1)) + { + g_gameQuit = 1; + quittimer = totalclock+120; + Net_Disconnect(); + G_GameExit(" "); + } + else if (numplayers < 2) + G_GameExit(" "); + + if ((totalclock > quittimer) && (g_gameQuit == 1)) + G_GameExit("Timed out."); +} + +static void Net_SendWeaponChoice(void) +{ + int32_t i,l; + + buf[0] = PACKET_WEAPON_CHOICE; + buf[1] = myconnectindex; + l = 2; + + for (i=0; i<10; i++) + { + g_player[myconnectindex].wchoice[i] = g_player[0].wchoice[i]; + buf[l++] = (uint8_t)g_player[0].wchoice[i]; + } + + buf[l++] = myconnectindex; + if (net_client) + enet_peer_send(net_peer, 0, enet_packet_create(&buf[0], l, ENET_PACKET_FLAG_RELIABLE)); + else if (net_server) + enet_host_broadcast(net_server, 0, enet_packet_create(&buf[0], l, ENET_PACKET_FLAG_RELIABLE)); +} + +static void Net_SendVersion(void) +{ + if (numplayers < 2) return; + + buf[0] = PACKET_VERSION; + buf[1] = myconnectindex; + buf[2] = (uint8_t)atoi(s_buildDate); + buf[3] = BYTEVERSION; + buf[4] = myconnectindex; + + if (net_client) + enet_peer_send(net_peer, 0, enet_packet_create(&buf[0], 5, ENET_PACKET_FLAG_RELIABLE)); + else if (net_server) + enet_host_broadcast(net_server, 0, enet_packet_create(&buf[0], 5, ENET_PACKET_FLAG_RELIABLE)); +} + +static void Net_SendPlayerOptions(void) +{ + int32_t l; + + buf[0] = PACKET_PLAYER_OPTIONS; + buf[1] = myconnectindex; + l = 2; + + //null terminated player name to send + // for (i=0;szPlayerName[i];i++) buf[l++] = Btoupper(szPlayerName[i]); + // buf[l++] = 0; + + buf[l++] = g_player[myconnectindex].ps->aim_mode = ud.mouseaiming; + buf[l++] = g_player[myconnectindex].ps->auto_aim = ud.config.AutoAim; + buf[l++] = g_player[myconnectindex].ps->weaponswitch = ud.weaponswitch; + buf[l++] = g_player[myconnectindex].ps->palookup = g_player[myconnectindex].pcolor = ud.color; + + buf[l++] = g_player[myconnectindex].pteam = ud.team; + + buf[l++] = myconnectindex; + + if (net_client) + enet_peer_send(net_peer, 0, enet_packet_create(&buf[0], l, ENET_PACKET_FLAG_RELIABLE)); + else if (net_server) + enet_host_broadcast(net_server, 0, enet_packet_create(&buf[0], l, ENET_PACKET_FLAG_RELIABLE)); +} + +void Net_SendPlayerName(void) +{ + int32_t i,l; + + for (l=0; (unsigned)l 0) + + buf[0] = PACKET_PLAYER_NAME; + buf[1] = myconnectindex; + l = 2; + + //null terminated player name to send + for (i=0; szPlayerName[i]; i++) buf[l++] = Btoupper(szPlayerName[i]); + buf[l++] = 0; + + buf[l++] = myconnectindex; + + if (net_client) + enet_peer_send(net_peer, 0, enet_packet_create(&buf[0], l, ENET_PACKET_FLAG_RELIABLE)); + else if (net_server) + enet_host_broadcast(net_server, 0, enet_packet_create(&buf[0], l, ENET_PACKET_FLAG_RELIABLE)); +} + +void Net_SendUserMapName(void) +{ + if (numplayers > 1) { - lastpackettime = totalclock; + int32_t j; + + packbuf[0] = PACKET_USER_MAP; + packbuf[1] = 0; + + Bcorrectfilename(boardfilename,0); + + j = Bstrlen(boardfilename); + boardfilename[j++] = 0; + Bstrcat(packbuf+1,boardfilename); + + packbuf[j++] = myconnectindex; + + if (net_client) + enet_peer_send(net_peer, 0, enet_packet_create(packbuf, j, ENET_PACKET_FLAG_RELIABLE)); + else if (net_server) + enet_host_broadcast(net_server, 0, enet_packet_create(packbuf, j, ENET_PACKET_FLAG_RELIABLE)); + + } +} + +void Net_NewGame(int32_t volume, int32_t level) +{ + packbuf[0] = PACKET_NEW_GAME; + packbuf[1] = ud.m_level_number = level; + packbuf[2] = ud.m_volume_number = volume; + packbuf[3] = ud.m_player_skill+1; + packbuf[4] = ud.m_monsters_off; + packbuf[5] = ud.m_respawn_monsters; + packbuf[6] = ud.m_respawn_items; + packbuf[7] = ud.m_respawn_inventory; + packbuf[8] = ud.m_coop; + packbuf[9] = ud.m_marker; + packbuf[10] = ud.m_ffire; + packbuf[11] = ud.m_noexits; + packbuf[12] = myconnectindex; + + if (net_client) + enet_peer_send(net_peer, 0, enet_packet_create(packbuf, 13, ENET_PACKET_FLAG_RELIABLE)); + else if (net_server) + enet_host_broadcast(net_server, 0, enet_packet_create(packbuf, 13, ENET_PACKET_FLAG_RELIABLE)); +} + +static mapstate_t *g_multiMapState = NULL; +static int32_t spritecrc[MAXSPRITES], lastupdate[MAXSPRITES]; +static int32_t peractorvals[MAXGAMEVARS][MAXSPRITES], perplayervals[MAXGAMEVARS][MAXPLAYERS]; + +void Net_ParsePacket(ENetEvent * event) +{ + uint8_t * packbuf = event->packet->data; + int32_t packbufleng = event->packet->dataLength; + int32_t i, j, l; + int32_t other = packbuf[--packbufleng]; + input_t *nsyn; + #if 0 initprintf("RECEIVED PACKET: type: %d : len %d\n", packbuf[0], packbufleng); #endif switch (packbuf[0]) { case PACKET_MASTER_TO_SLAVE: //[0] (receive master sync buffer) + + if (!(g_player[myconnectindex].ps->gm & MODE_GAME)) return; + j = 1; - if ((g_player[other].movefifoend&(TIMERUPDATESIZ-1)) == 0) - for (i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i]) - { - if (g_player[i].playerquitflag == 0) continue; - if (i == myconnectindex) - otherminlag = (int32_t)((int8_t)packbuf[j]); - j++; - } + packbufleng = qlz_size_decompressed((char *)packbuf+1); + packbuf = Bcalloc(1, packbufleng); + packbufleng = qlz_decompress((char *)event->packet->data+1, packbuf+1, state_decompress); - osyn = (input_t *)&inputfifo[(g_player[connecthead].movefifoend-1)&(MOVEFIFOSIZ-1)][0]; - nsyn = (input_t *)&inputfifo[(g_player[connecthead].movefifoend)&(MOVEFIFOSIZ-1)][0]; + Bmemcpy(&ticrandomseed, &packbuf[j], sizeof(ticrandomseed)); + j += sizeof(ticrandomseed); - k = j; - TRAVERSE_CONNECT(i) - j += g_player[i].playerquitflag+g_player[i].playerquitflag; TRAVERSE_CONNECT(i) { if (g_player[i].playerquitflag == 0) continue; - l = packbuf[k]+(int32_t)(packbuf[k+1]<<8); - k += 2; - if (i == myconnectindex) { - j += ((l&1)<<1)+(l&2)+((l&4)>>2)+((l&8)>>3)+((l&16)>>4)+((l&32)>>5)+((l&64)>>6)+((l&128)>>7)+((l&256)>>8)/*+((l&512)>>9)+((l&1024)>>10)+((l&2048)>>11)*/; - continue; + j += sizeof(input_t)-sizeof(loc.filler)+(sizeof(vec3_t)*3) + 4; + goto process; } - copybufbyte(&osyn[i],&nsyn[i],sizeof(input_t)); - if (l&1) nsyn[i].fvel = packbuf[j]+((int16_t)packbuf[j+1]<<8), j += 2; - if (l&2) nsyn[i].svel = packbuf[j]+((int16_t)packbuf[j+1]<<8), j += 2; - if (l&4) nsyn[i].avel = (int8_t)packbuf[j++]; - if (l&8) nsyn[i].bits = ((nsyn[i].bits&0xffffff00)|((int32_t)packbuf[j++])); - if (l&16) nsyn[i].bits = ((nsyn[i].bits&0xffff00ff)|((int32_t)packbuf[j++])<<8); - if (l&32) nsyn[i].bits = ((nsyn[i].bits&0xff00ffff)|((int32_t)packbuf[j++])<<16); - if (l&64) nsyn[i].bits = ((nsyn[i].bits&0x00ffffff)|((int32_t)packbuf[j++])<<24); - if (l&128) nsyn[i].horz = (int8_t)packbuf[j++]; - if (l&256) nsyn[i].extbits = (uint8_t)packbuf[j++]; - /* if (l&256) nsyn[i].extbits = ((nsyn[i].extbits&0xffffff00)|((int32_t)packbuf[j++])); - if (l&512) nsyn[i].extbits = ((nsyn[i].extbits&0xffff00ff)|((int32_t)packbuf[j++])<<8); - if (l&1024) nsyn[i].extbits = ((nsyn[i].extbits&0xff00ffff)|((int32_t)packbuf[j++])<<16); - if (l&2048) nsyn[i].extbits = ((nsyn[i].extbits&0x00ffffff)|((int32_t)packbuf[j++])<<24); */ + nsyn = (input_t *)&inputfifo[0][0]; + + Bmemcpy(&nsyn[i], &packbuf[j], sizeof(input_t)); + + j += sizeof(input_t)-sizeof(loc.filler); if (TEST_SYNC_KEY(nsyn[i].bits,SK_GAMEQUIT)) g_player[i].playerquitflag = 0; g_player[i].movefifoend++; + + Bmemcpy(&g_player[i].ps->posx, &packbuf[j], sizeof(vec3_t) * 3); + Bmemcpy(&sprite[g_player[i].ps->i], &packbuf[j], sizeof(vec3_t)); + sprite[g_player[i].ps->i].z += PHEIGHT; + j += sizeof(vec3_t) * 3; + Bmemcpy(&g_player[i].ps->ang, &packbuf[j], sizeof(int16_t) * 2); + Bmemcpy(&sprite[g_player[i].ps->i].ang, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t) * 2; + +process: + Bmemcpy(&sprite[g_player[i].ps->i].extra, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&g_player[i].ps->kickback_pic, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&g_player[i].ps->shield_amount, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&ActorExtra[g_player[i].ps->i].owner, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&ActorExtra[g_player[i].ps->i].picnum, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&g_player[i].ps->gotweapon[0], &packbuf[j], sizeof(g_player[i].ps->gotweapon)); + j += sizeof(g_player[i].ps->gotweapon); + Bmemcpy(&g_player[i].ps->curr_weapon, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&g_player[i].ps->ammo_amount[0], &packbuf[j], sizeof(g_player[i].ps->ammo_amount)); + j += sizeof(g_player[i].ps->ammo_amount); + Bmemcpy(&g_player[i].ps->last_weapon, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&g_player[i].ps->wantweaponfire, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&g_player[i].ps->frag_ps, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&g_player[i].ps->fraggedself, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&g_player[i].ps->last_extra, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&g_player[i].ps->dead_flag, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + + l = i; + + do + { + int16_t var_id; + + Bmemcpy(&var_id, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + + if (var_id == MAXGAMEVARS) break; + + Bmemcpy(&aGameVars[var_id].val.plValues[i], &packbuf[j], sizeof(int32_t)); + j += sizeof(int32_t); + } + while (1); + + i = l; + + do + { + int16_t var_id; + + Bmemcpy(&var_id, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + + if (var_id == MAXGAMEVARS) break; + + Bmemcpy(&aGameVars[var_id].val.plValues[i], &packbuf[j], sizeof(int32_t)); + j += sizeof(int32_t); + } + while (1); } - Net_GetSyncData(packbuf, packbufleng, &j, other); + { + int16_t ahead, zhead, phead; - TRAVERSE_CONNECT(i) - if (i != myconnectindex) - for (j=g_movesPerPacket-1; j>=1; j--) + Bmemcpy(&ahead, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + + Bmemcpy(&zhead, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + + Bmemcpy(&phead, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + + if (ahead != -1 && sprite[ahead].statnum != STAT_ACTOR && sprite[ahead].statnum != STAT_ZOMBIEACTOR) + deletesprite(ahead); + + if (zhead != -1 && sprite[zhead].statnum != STAT_ACTOR && sprite[zhead].statnum != STAT_ZOMBIEACTOR) + deletesprite(ahead); + + if (phead != -1 && sprite[phead].statnum != STAT_PROJECTILE) + deletesprite(ahead); + + // sprite updates tacked on to the end of the packet + while ((unsigned)(packbufleng-j) > sizeof(spritetype)+sizeof(ActorData_t)) { - copybufbyte(&nsyn[i],&inputfifo[g_player[i].movefifoend&(MOVEFIFOSIZ-1)][i],sizeof(input_t)); - g_player[i].movefifoend++; - } + int16_t i, sect, statnum, osect, ostatnum, jj, lightid, opicnum; + _prlight *mylight; - movefifosendplc += g_movesPerPacket; + Bmemcpy(&i, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + + osect = sprite[i].sectnum; + ostatnum = sprite[i].statnum; + opicnum = sprite[i].picnum; + + Bmemcpy(&sprite[i], &packbuf[j], sizeof(spritetype)); + + if (sprite[i].picnum != opicnum) + { + sect = sprite[i].sectnum; + statnum = sprite[i].statnum; + + sprite[i].sectnum = osect; + sprite[i].statnum = ostatnum; + + deletesprite(i); + insertsprite(sect, statnum); + } + else + { + sect = sprite[i].sectnum; + statnum = sprite[i].statnum; + sprite[i].sectnum = osect; + sprite[i].statnum = ostatnum; + if (sect != osect) changespritesect(i, sect); + if (statnum != ostatnum) changespritestat(i, statnum); + } + + j += sizeof(spritetype); + + jj = j++; + + mylight = ActorExtra[i].lightptr; + lightid = ActorExtra[i].lightId; + Bmemcpy(&ActorExtra[i], &packbuf[j], sizeof(ActorData_t)-sizeof(ActorExtra[0].filler)); + j += sizeof(ActorData_t)-sizeof(ActorExtra[0].filler); + + ActorExtra[i].projectile = &SpriteProjectile[i]; + ActorExtra[i].lightptr = mylight; + ActorExtra[i].lightId = lightid; + + if (packbuf[jj] & 1) T2 += (intptr_t)&script[0]; + if (packbuf[jj] & 2) T5 += (intptr_t)&script[0]; + if (packbuf[jj] & 4) T6 += (intptr_t)&script[0]; + + do + { + int16_t var_id; + + Bmemcpy(&var_id, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t); + + if (var_id == MAXGAMEVARS) break; + + Bmemcpy(&aGameVars[var_id].val.plValues[i], &packbuf[j], sizeof(int32_t)); + j += sizeof(int32_t); + } + while (1); + } + } + + Bfree(packbuf); +// movefifosendplc++; break; case PACKET_SLAVE_TO_MASTER: //[1] (receive slave sync buffer) - j = 3; - k = packbuf[1] + (int32_t)(packbuf[2]<<8); - - osyn = (input_t *)&inputfifo[(g_player[other].movefifoend-1)&(MOVEFIFOSIZ-1)][0]; - nsyn = (input_t *)&inputfifo[(g_player[other].movefifoend)&(MOVEFIFOSIZ-1)][0]; - - copybufbyte(&osyn[other],&nsyn[other],sizeof(input_t)); - if (k&1) nsyn[other].fvel = packbuf[j]+((int16_t)packbuf[j+1]<<8), j += 2; - if (k&2) nsyn[other].svel = packbuf[j]+((int16_t)packbuf[j+1]<<8), j += 2; - if (k&4) nsyn[other].avel = (int8_t)packbuf[j++]; - if (k&8) nsyn[other].bits = ((nsyn[other].bits&0xffffff00)|((int32_t)packbuf[j++])); - if (k&16) nsyn[other].bits = ((nsyn[other].bits&0xffff00ff)|((int32_t)packbuf[j++])<<8); - if (k&32) nsyn[other].bits = ((nsyn[other].bits&0xff00ffff)|((int32_t)packbuf[j++])<<16); - if (k&64) nsyn[other].bits = ((nsyn[other].bits&0x00ffffff)|((int32_t)packbuf[j++])<<24); - if (k&128) nsyn[other].horz = (int8_t)packbuf[j++]; - if (k&256) nsyn[other].extbits = (uint8_t)packbuf[j++]; - /* if (k&256) nsyn[other].extbits = ((nsyn[other].extbits&0xffffff00)|((int32_t)packbuf[j++])); - if (k&512) nsyn[other].extbits = ((nsyn[other].extbits&0xffff00ff)|((int32_t)packbuf[j++])<<8); - if (k&1024) nsyn[other].extbits = ((nsyn[other].extbits&0xff00ffff)|((int32_t)packbuf[j++])<<16); - if (k&2048) nsyn[other].extbits = ((nsyn[other].extbits&0x00ffffff)|((int32_t)packbuf[j++])<<24); */ - g_player[other].movefifoend++; - - Net_GetSyncData(packbuf, packbufleng, &j, other); - - for (i=g_movesPerPacket-1; i>=1; i--) - { - copybufbyte(&nsyn[other],&inputfifo[g_player[other].movefifoend&(MOVEFIFOSIZ-1)][other],sizeof(input_t)); - g_player[other].movefifoend++; - } - - break; - - case PACKET_BROADCAST: - g_player[other].movefifoend = movefifoplc = movefifosendplc = predictfifoplc = 0; - g_player[other].syncvalhead = syncvaltottail = 0L; - case SERVER_GENERATED_BROADCAST: j = 1; - if ((g_player[other].movefifoend&(TIMERUPDATESIZ-1)) == 0) - if (other == connecthead) - for (i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i]) - { - if (i == myconnectindex) - otherminlag = (int32_t)((int8_t)packbuf[j]); - j++; - } + packbufleng = qlz_size_decompressed((char *)packbuf+1); + packbuf = Bcalloc(1, packbufleng); + packbufleng = qlz_decompress((char *)event->packet->data+1, packbuf+1, state_decompress); - osyn = (input_t *)&inputfifo[(g_player[other].movefifoend-1)&(MOVEFIFOSIZ-1)][0]; - nsyn = (input_t *)&inputfifo[(g_player[other].movefifoend)&(MOVEFIFOSIZ-1)][0]; + nsyn = (input_t *)&inputfifo[0][0]; - copybufbyte(&osyn[other],&nsyn[other],sizeof(input_t)); - k = packbuf[j] + (int32_t)(packbuf[j+1]<<8); - j += 2; + Bmemcpy(&nsyn[other], &packbuf[j], sizeof(input_t)); + + j += sizeof(input_t)-sizeof(loc.filler); - if (k&1) nsyn[other].fvel = packbuf[j]+((int16_t)packbuf[j+1]<<8), j += 2; - if (k&2) nsyn[other].svel = packbuf[j]+((int16_t)packbuf[j+1]<<8), j += 2; - if (k&4) nsyn[other].avel = (int8_t)packbuf[j++]; - if (k&8) nsyn[other].bits = ((nsyn[other].bits&0xffffff00)|((int32_t)packbuf[j++])); - if (k&16) nsyn[other].bits = ((nsyn[other].bits&0xffff00ff)|((int32_t)packbuf[j++])<<8); - if (k&32) nsyn[other].bits = ((nsyn[other].bits&0xff00ffff)|((int32_t)packbuf[j++])<<16); - if (k&64) nsyn[other].bits = ((nsyn[other].bits&0x00ffffff)|((int32_t)packbuf[j++])<<24); - if (k&128) nsyn[other].horz = (int8_t)packbuf[j++]; - if (k&256) nsyn[other].extbits = (uint8_t)packbuf[j++]; - /* if (k&256) nsyn[other].extbits = ((nsyn[other].extbits&0xffffff00)|((int32_t)packbuf[j++])); - if (k&512) nsyn[other].extbits = ((nsyn[other].extbits&0xffff00ff)|((int32_t)packbuf[j++])<<8); - if (k&1024) nsyn[other].extbits = ((nsyn[other].extbits&0xff00ffff)|((int32_t)packbuf[j++])<<16); - if (k&2048) nsyn[other].extbits = ((nsyn[other].extbits&0x00ffffff)|((int32_t)packbuf[j++])<<24); */ g_player[other].movefifoend++; - for (i=g_movesPerPacket-1; i>=1; i--) + Bmemcpy(&g_player[other].ps->posx, &packbuf[j], sizeof(vec3_t) * 3); + Bmemcpy(&sprite[g_player[other].ps->i], &packbuf[j], sizeof(vec3_t)); + sprite[g_player[other].ps->i].z += PHEIGHT; + j += sizeof(vec3_t) * 3; + + Bmemcpy(&g_player[other].ps->ang, &packbuf[j], sizeof(int16_t) * 2); + Bmemcpy(&sprite[g_player[other].ps->i].ang, &packbuf[j], sizeof(int16_t)); + j += sizeof(int16_t) * 2; + { - copybufbyte(&nsyn[other],&inputfifo[g_player[other].movefifoend&(MOVEFIFOSIZ-1)][other],sizeof(input_t)); - g_player[other].movefifoend++; + int16_t i = g_player[other].ps->i, jj = j++; + + Bmemcpy(&T3, &packbuf[j], sizeof(T3)); + j += sizeof(T3); + Bmemcpy(&T4, &packbuf[j], sizeof(T4)); + j += sizeof(T4); + Bmemcpy(&T5, &packbuf[j], sizeof(T5)); + j += sizeof(T5); + + if (packbuf[jj] & 2) T5 += (intptr_t)&script[0]; } - - Net_GetSyncData(packbuf, packbufleng, &j, other); - - if (j > packbufleng) - initprintf("INVALID GAME PACKET!!! (packet %d, %d too many bytes (%d %d))\n",packbuf[0],j-packbufleng,packbufleng,k); - + Bfree(packbuf); break; + case PACKET_NULL_PACKET: break; case PACKET_PLAYER_READY: - if (g_player[other].playerreadyflag == 0) - initprintf("Player %d is ready\n", other); + if (net_server) + { + packbuf[0] = PACKET_PLAYER_READY; + packbuf[1] = myconnectindex; + enet_host_broadcast(net_server, 0, enet_packet_create(packbuf, 2, ENET_PACKET_FLAG_RELIABLE)); + } g_player[other].playerreadyflag++; return; case PACKET_QUIT: @@ -752,24 +1066,7 @@ void Net_GetPackets(void) { case PACKET_MESSAGE: //slaves in M/S mode only send to master - if ((!g_networkBroadcastMode) && (myconnectindex == connecthead)) - { - if (packbuf[1] == 255) - { - //Master re-transmits message to all others - for (i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i]) - if (i != other) - mmulti_sendpacket(i,packbuf,packbufleng); - } - else if (((int32_t)packbuf[1]) != myconnectindex) - { - //Master re-transmits message not intended for master - mmulti_sendpacket((int32_t)packbuf[1],packbuf,packbufleng); - break; - } - } - - Bstrcpy(recbuf,packbuf+2); + Bstrcpy(recbuf,(char *)packbuf+2); recbuf[packbufleng-2] = 0; G_AddUserQuote(recbuf); @@ -781,13 +1078,7 @@ void Net_GetPackets(void) break; case PACKET_NEW_GAME: - //Slaves in M/S mode only send to master - //Master re-transmits message to all others - if ((!g_networkBroadcastMode) && (myconnectindex == connecthead)) - for (i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i]) - if (i != other) mmulti_sendpacket(i,packbuf,packbufleng); - - if (vote_map != -1 || vote_episode != -1 || voting != -1) + if ((vote_map + vote_episode + voting) != -3) G_AddUserQuote("VOTE SUCCEEDED"); ud.m_level_number = ud.level_number = packbuf[1]; @@ -816,12 +1107,6 @@ void Net_GetPackets(void) break; case PACKET_VERSION: - //slaves in M/S mode only send to master - //Master re-transmits message to all others - if ((!g_networkBroadcastMode) && (myconnectindex == connecthead)) - for (i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i]) - if (i != other) mmulti_sendpacket(i,packbuf,packbufleng); - if (packbuf[2] != (uint8_t)atoi(s_buildDate)) { initprintf("Player %d has version %d, expecting %d\n",packbuf[2],(uint8_t)atoi(s_buildDate)); @@ -832,21 +1117,47 @@ void Net_GetPackets(void) initprintf("Player %d has version %d, expecting %d\n",packbuf[3],BYTEVERSION); G_GameExit("You cannot play Duke with different versions!"); } - if (packbuf[4] > g_numSyncBytes) + break; + + case PACKET_NUM_PLAYERS: + numplayers = packbuf[1]; + playerswhenstarted = packbuf[2]; + ud.multimode = packbuf[3]; + if (packbuf[4]) // ID of new player + clearbufbyte(&g_player[packbuf[4]].playerquitflag,1,0x01010101); + + for (i=1; i=0; i=connectpoint2[i]) - if (i != other) mmulti_sendpacket(i,packbuf,packbufleng); + // receive client player index from server + case PACKET_PLAYER_INDEX: + myconnectindex = packbuf[1]; + clearbufbyte(&g_player[myconnectindex].playerquitflag,1,0x01010101); + + Net_SendVersion(); + Net_SendPlayerName(); + Net_SendPlayerOptions(); + Net_SendWeaponChoice(); + Net_SendUserMapName(); + + break; + + case PACKET_PLAYER_DISCONNECTED: + numplayers--; + ud.multimode--; + g_player[packbuf[1]].playerquitflag = 0; + break; + + case PACKET_PLAYER_OPTIONS: other = packbuf[1]; i = 2; @@ -859,12 +1170,6 @@ void Net_GetPackets(void) break; case PACKET_PLAYER_NAME: - //slaves in M/S mode only send to master - //Master re-transmits message to all others - if ((!g_networkBroadcastMode) && (myconnectindex == connecthead)) - for (i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i]) - if (i != other) mmulti_sendpacket(i,packbuf,packbufleng); - other = packbuf[1]; for (i=2; packbuf[i]; i++) @@ -875,12 +1180,6 @@ void Net_GetPackets(void) break; case PACKET_WEAPON_CHOICE: - //slaves in M/S mode only send to master - //Master re-transmits message to all others - if ((!g_networkBroadcastMode) && (myconnectindex == connecthead)) - for (i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i]) - if (i != other) mmulti_sendpacket(i,packbuf,packbufleng); - other = packbuf[1]; i = 2; @@ -891,12 +1190,6 @@ void Net_GetPackets(void) break; case PACKET_RTS: - //slaves in M/S mode only send to master - //Master re-transmits message to all others - if ((!g_networkBroadcastMode) && (myconnectindex == connecthead)) - for (i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i]) - if (i != other) mmulti_sendpacket(i,packbuf,packbufleng); - if (numlumps == 0) break; if (ud.config.SoundToggle == 0 || ud.lockout == 1 || ud.config.FXDevice < 0 || !(ud.config.VoiceToggle & 4)) @@ -909,51 +1202,11 @@ void Net_GetPackets(void) case PACKET_MENU_LEVEL_QUIT: //slaves in M/S mode only send to master - if (myconnectindex == connecthead) - { - //Master re-transmits message to all others - for (i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i]) - if (i != other) - mmulti_sendpacket(i,packbuf,packbufleng); - } - /* - j = packbuf[1]; - playerquitflag[j] = 0; - - j = -1; - for(i=connecthead;i>=0;i=connectpoint2[i]) - { - if (g_player[i].playerquitflag) { j = i; continue; } - - if (i == connecthead) connecthead = connectpoint2[connecthead]; - else connectpoint2[j] = connectpoint2[i]; - - numplayers--; - ud.multimode--; - - Bsprintf(buf,"%s is history!",g_player[i].user_name); - G_AddUserQuote(buf); - - if (numplayers < 2) - S_PlaySound(GENERIC_AMBIENCE17); - - if(i == 0 && g_networkBroadcastMode == 0) */ - G_GameExit("Game aborted from menu; disconnected."); - // } break; case PACKET_USER_MAP: - //slaves in M/S mode only send to master - if (myconnectindex == connecthead) - { - //Master re-transmits message to all others - for (i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i]) - if (i != other) - mmulti_sendpacket(i,packbuf,packbufleng); - } - - Bstrcpy(boardfilename,packbuf+1); + Bstrcpy(boardfilename,(char *)packbuf+1); boardfilename[packbufleng-1] = 0; Bcorrectfilename(boardfilename,0); if (boardfilename[0] != 0) @@ -974,15 +1227,6 @@ void Net_GetPackets(void) case PACKET_MAP_VOTE: case PACKET_MAP_VOTE_INITIATE: case PACKET_MAP_VOTE_CANCEL: - - if (myconnectindex == connecthead) - { - //Master re-transmits message to all others - for (i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i]) - if (i != other) - mmulti_sendpacket(i,packbuf,packbufleng); - } - switch (packbuf[0]) { case PACKET_MAP_VOTE: @@ -996,8 +1240,6 @@ void Net_GetPackets(void) break; case PACKET_MAP_VOTE_INITIATE: // call map vote - /* if (g_networkBroadcastMode == 0 && packbuf[1] == connecthead) - break; // ignore this from master */ voting = packbuf[1]; vote_episode = packbuf[2]; vote_map = packbuf[3]; @@ -1042,12 +1284,6 @@ void Net_GetPackets(void) break; case PACKET_LOAD_GAME: - //Slaves in M/S mode only send to master - //Master re-transmits message to all others - if ((!g_networkBroadcastMode) && (myconnectindex == connecthead)) - for (i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i]) - if (i != other) mmulti_sendpacket(i,packbuf,packbufleng); - multiflag = 2; multiwhat = 0; multiwho = packbuf[2]; //other: need to send in m/s mode because of possible re-transmit @@ -1055,17 +1291,258 @@ void Net_GetPackets(void) G_LoadPlayer(multipos); multiflag = 0; break; + + case PACKET_REQUEST_GAMESTATE: + if (net_server && g_player[0].ps->gm & MODE_GAME) + { + packbuf[0] = PACKET_NEW_GAME; + packbuf[1] = ud.level_number; + packbuf[2] = ud.volume_number; + packbuf[3] = ud.player_skill+1; + packbuf[4] = ud.monsters_off; + packbuf[5] = ud.respawn_monsters; + packbuf[6] = ud.respawn_items; + packbuf[7] = ud.respawn_inventory; + packbuf[8] = ud.coop; + packbuf[9] = ud.marker; + packbuf[10] = ud.ffire; + packbuf[11] = ud.noexits; + packbuf[12] = myconnectindex; + + enet_peer_send(event->peer, 0, enet_packet_create(packbuf, 13, ENET_PACKET_FLAG_RELIABLE)); + + // a player connecting is a good time to mark everything as needing to be updated + Bmemset(spritecrc, 0, sizeof(spritecrc)); + Bmemset(peractorvals, 0, sizeof(peractorvals)); + Bmemset(perplayervals, 0, sizeof(perplayervals)); + } + break; } break; } +} + +void Net_GetPackets(void) +{ + int32_t i, j; + + sampletimer(); + MUSIC_Update(); + + G_HandleSpecialKeys(); + + if (net_server) + { + ENetEvent event; + + while (enet_host_service (net_server, & event, 0) > 0) + { + switch (event.type) + { + case ENET_EVENT_TYPE_CONNECT: + initprintf ("A new client connected from %x:%u.\n", + event.peer -> address.host, + event.peer -> address.port); + + TRAVERSE_CONNECT(i) + if (!g_player[i].playerquitflag) + break; + + // no slots empty from players quitting, so open a new one + if (i == -1) + i = playerswhenstarted++; + event.peer->data = (void *)i; + + clearbufbyte(&g_player[i].playerquitflag,1,0x01010101); + g_player[i].movefifoend = 1; + + for (j=0; jgm & MODE_GAME) + { + j = g_player[i].ps->i; + Bmemcpy(g_player[i].ps, g_player[0].ps, sizeof(DukePlayer_t)); + g_player[i].ps->i = j; + changespritestat(j, STAT_PLAYER); + P_ResetStatus(i); + P_ResetWeapons(i); + P_ResetInventory(i); + + g_player[i].ps->last_extra = g_player[i].ps->max_player_health; + sprite[g_player[i].ps->i].extra = g_player[i].ps->max_player_health; + g_player[i].ps->runspeed = g_playerFriction; + + if (g_multiMapState == NULL) g_multiMapState = Bcalloc(1, sizeof(mapstate_t)); + if (g_multiMapState) + { + char * buf = Bmalloc(sizeof(mapstate_t)<<1); + G_SaveMapState(g_multiMapState); + j = qlz_compress((char *)g_multiMapState, buf, sizeof(mapstate_t), state_compress); + while (j > 1024) + { + enet_peer_send(event.peer, 1, enet_packet_create((char *)(buf)+qlz_size_compressed(buf)-j, 1024, ENET_PACKET_FLAG_RELIABLE)); + j -= 1024; + } + enet_peer_send(event.peer, 1, enet_packet_create((char *)(buf)+qlz_size_compressed(buf)-j, j, ENET_PACKET_FLAG_RELIABLE)); + Bfree(buf); + Bfree(g_multiMapState); + g_multiMapState = NULL; + } + } + break; + case ENET_EVENT_TYPE_RECEIVE: +/* + initprintf ("A packet of length %u containing %s was received from player %d on channel %u.\n", + event.packet -> dataLength, + event.packet -> data, + event.peer -> data, + event.channelID); +*/ + Net_ParsePacket(&event); + // broadcast takes care of enet_packet_destroy itself + // we set the state to disconnected so enet_host_broadcast doesn't send the player back his own packets + // SLAVE_TO_MASTER packets are channelID 1, so they aren't broadcast anywhere + if (event.channelID == 0) + { + event.peer->state = ENET_PEER_STATE_DISCONNECTED; + enet_host_broadcast(net_server, 0, event.packet); + event.peer->state = ENET_PEER_STATE_CONNECTED; + } + else enet_packet_destroy(event.packet); + lastpackettime = totalclock; + break; + case ENET_EVENT_TYPE_DISCONNECT: + g_player[(int32_t)event.peer->data].playerquitflag = 0; + numplayers--; + ud.multimode--; + + packbuf[0] = PACKET_PLAYER_DISCONNECTED; + packbuf[1] = (int32_t)event.peer->data; + packbuf[2] = myconnectindex; + enet_host_broadcast(net_server, 0, enet_packet_create(packbuf, 3, ENET_PACKET_FLAG_RELIABLE)); + + initprintf ("Player %d disconnected.\n", event.peer -> data); + event.peer->data = NULL; + break; + default: + break; + } + } + } + else if (net_client) + { + ENetEvent event; + + while (enet_host_service (net_client, & event, 0) > 0) + { + switch (event.type) + { + case ENET_EVENT_TYPE_RECEIVE: +/* + initprintf ("A packet of length %u was received from player %d on channel %u.\n", + event.packet -> dataLength, + event.peer -> data, + event.channelID); +*/ + // channelID 1 is the map state transfer from the server + if (event.channelID == 1) + { + static int32_t datasiz = 0; + static char * buf = NULL; + + if (buf == NULL) + { + datasiz = 0; + + if (g_multiMapState == NULL) + g_multiMapState = (mapstate_t *)Bcalloc(1, sizeof(mapstate_t)); + + buf = Bcalloc(1, sizeof(mapstate_t)<<1); + } + + if (buf && event.packet->dataLength == 1024) + { + Bmemcpy((char *)(buf)+datasiz, event.packet->data, event.packet->dataLength); + datasiz += 1024; + } + // last packet of mapstate sequence + else if (buf) + { + Bmemcpy((char *)(buf)+datasiz, event.packet->data, event.packet->dataLength); + datasiz = 0; + if (qlz_size_decompressed(buf) == sizeof(mapstate_t)) + { + qlz_decompress(buf, g_multiMapState, state_decompress); + + packbuf[0] = PACKET_REQUEST_GAMESTATE; + packbuf[1] = myconnectindex; + enet_peer_send(net_peer, 0, enet_packet_create(&packbuf[0], 2, ENET_PACKET_FLAG_RELIABLE)); + } + else + { + initprintf("Invalid map state from server!\n"); + Net_Disconnect(); + } + } + else + { + initprintf("Error allocating memory!\n"); + return; + } + } + else Net_ParsePacket(&event); + enet_packet_destroy (event.packet); + lastpackettime = totalclock; + break; + case ENET_EVENT_TYPE_DISCONNECT: + numplayers = ud.multimode = playerswhenstarted = 1; + event.peer -> data = NULL; + enet_host_destroy(net_client); + net_client = NULL; + G_BackToMenu(); + initprintf ("Disconnected.\n"); + return; + default: + break; + } + } } } void faketimerhandler(void) { - int32_t i, j, k; + int32_t i, j; // short who; - input_t *osyn, *nsyn; + input_t *nsyn; if (qe == 0 && KB_KeyPressed(sc_LeftControl) && KB_KeyPressed(sc_LeftAlt) && KB_KeyPressed(sc_Delete)) { @@ -1081,9 +1558,6 @@ void faketimerhandler(void) Net_GetPackets(); - if (g_player[myconnectindex].movefifoend - movefifoplc >= 100) - return; - getinput(myconnectindex); avgfvel += loc.fvel; @@ -1093,19 +1567,11 @@ void faketimerhandler(void) avgbits |= loc.bits; avgextbits |= loc.extbits; - if (g_player[myconnectindex].movefifoend&(g_movesPerPacket-1)) - { - copybufbyte(&inputfifo[(g_player[myconnectindex].movefifoend-1)&(MOVEFIFOSIZ-1)][myconnectindex], - &inputfifo[g_player[myconnectindex].movefifoend&(MOVEFIFOSIZ-1)][myconnectindex],sizeof(input_t)); - g_player[myconnectindex].movefifoend++; - return; - } - - nsyn = &inputfifo[g_player[myconnectindex].movefifoend&(MOVEFIFOSIZ-1)][myconnectindex]; - nsyn[0].fvel = avgfvel/g_movesPerPacket; - nsyn[0].svel = avgsvel/g_movesPerPacket; - nsyn[0].avel = avgavel/g_movesPerPacket; - nsyn[0].horz = avghorz/g_movesPerPacket; + nsyn = &inputfifo[0][myconnectindex]; + nsyn[0].fvel = avgfvel; + nsyn[0].svel = avgsvel; + nsyn[0].avel = avgavel; + nsyn[0].horz = avghorz; nsyn[0].bits = avgbits; nsyn[0].extbits = avgextbits; avgfvel = avgsvel = avgavel = avghorz = avgbits = avgextbits = 0; @@ -1119,290 +1585,272 @@ void faketimerhandler(void) { //clearbufbyte(&inputfifo[g_player[i].movefifoend&(MOVEFIFOSIZ-1)][i],sizeof(input_t),0L); if (ud.playerai) - computergetinput(i,&inputfifo[g_player[i].movefifoend&(MOVEFIFOSIZ-1)][i]); - inputfifo[g_player[i].movefifoend&(MOVEFIFOSIZ-1)][i].svel++; - inputfifo[g_player[i].movefifoend&(MOVEFIFOSIZ-1)][i].fvel++; - g_player[i].movefifoend++; + computergetinput(i,&inputfifo[0][i]); } - return; } - TRAVERSE_CONNECT(i) - if (i != myconnectindex) + if (net_client) //Slave { - k = (g_player[myconnectindex].movefifoend-1)-g_player[i].movefifoend; - g_player[i].myminlag = min(g_player[i].myminlag,k); - mymaxlag = max(mymaxlag,k); - } - -#if 0 - if (((g_player[myconnectindex].movefifoend - 1) & (TIMERUPDATESIZ - 1)) == 0) - { - i = mymaxlag - bufferjitter; - mymaxlag = 0; - if (i > 0) - bufferjitter += ((2 + i) >> 2); - else if (i < 0) - bufferjitter -= ((2 - i) >> 2); - } -#else - if (((g_player[myconnectindex].movefifoend-1)&(TIMERUPDATESIZ-1)) == 0) - { - i = mymaxlag-bufferjitter; mymaxlag = 0; - if (i > 0) bufferjitter += ((3+i)>>2); - else if (i < 0) bufferjitter -= ((1-i)>>2); - } -#endif - - if (g_networkBroadcastMode == 1) - { - packbuf[0] = SERVER_GENERATED_BROADCAST; - if ((g_player[myconnectindex].movefifoend-1) == 0) packbuf[0] = PACKET_BROADCAST; - j = 1; - - //Fix timers and buffer/jitter value - if (((g_player[myconnectindex].movefifoend-1)&(TIMERUPDATESIZ-1)) == 0) - { - if (myconnectindex != connecthead) - { - i = g_player[connecthead].myminlag-otherminlag; - if (klabs(i) > 8) i >>= 1; - else if (klabs(i) > 2) i = ksgn(i); - else i = 0; - - totalclock -= TICSPERFRAME*i; - g_player[connecthead].myminlag -= i; otherminlag += i; - } - else - { - for (i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i]) - packbuf[j++] = min(max(g_player[i].myminlag,-128),127); - } - - TRAVERSE_CONNECT(i) - g_player[i].myminlag = 0x7fffffff; - } - - osyn = (input_t *)&inputfifo[(g_player[myconnectindex].movefifoend-2)&(MOVEFIFOSIZ-1)][myconnectindex]; - nsyn = (input_t *)&inputfifo[(g_player[myconnectindex].movefifoend-1)&(MOVEFIFOSIZ-1)][myconnectindex]; - - k = j; - packbuf[j++] = 0; - packbuf[j++] = 0; - - if (nsyn[0].fvel != osyn[0].fvel) - { - packbuf[j++] = (uint8_t)nsyn[0].fvel; - packbuf[j++] = (uint8_t)(nsyn[0].fvel>>8); - packbuf[k] |= 1; - } - if (nsyn[0].svel != osyn[0].svel) - { - packbuf[j++] = (uint8_t)nsyn[0].svel; - packbuf[j++] = (uint8_t)(nsyn[0].svel>>8); - packbuf[k] |= 2; - } - if (nsyn[0].avel != osyn[0].avel) - { - packbuf[j++] = (int8_t)nsyn[0].avel; - packbuf[k] |= 4; - } - if ((nsyn[0].bits^osyn[0].bits)&0x000000ff) packbuf[j++] = (nsyn[0].bits&255), packbuf[k] |= 8; - if ((nsyn[0].bits^osyn[0].bits)&0x0000ff00) packbuf[j++] = ((nsyn[0].bits>>8)&255), packbuf[k] |= 16; - if ((nsyn[0].bits^osyn[0].bits)&0x00ff0000) packbuf[j++] = ((nsyn[0].bits>>16)&255), packbuf[k] |= 32; - if ((nsyn[0].bits^osyn[0].bits)&0xff000000) packbuf[j++] = ((nsyn[0].bits>>24)&255), packbuf[k] |= 64; - if (nsyn[0].horz != osyn[0].horz) - { - packbuf[j++] = (uint8_t)nsyn[0].horz; - packbuf[k] |= 128; - } - packbuf[++k] = 0; - - if (nsyn[0].extbits != osyn[0].extbits) packbuf[j++] = nsyn[0].extbits, packbuf[k] |= 1; - /* if ((nsyn[0].extbits^osyn[0].extbits)&0x000000ff) packbuf[j++] = (nsyn[0].extbits&255), packbuf[k] |= 1; - if ((nsyn[0].extbits^osyn[0].extbits)&0x0000ff00) packbuf[j++] = ((nsyn[0].extbits>>8)&255), packbuf[k] |= 2; - if ((nsyn[0].extbits^osyn[0].extbits)&0x00ff0000) packbuf[j++] = ((nsyn[0].extbits>>16)&255), packbuf[k] |= 4; - if ((nsyn[0].extbits^osyn[0].extbits)&0xff000000) packbuf[j++] = ((nsyn[0].extbits>>24)&255), packbuf[k] |= 8; */ - - /* while (g_player[myconnectindex].syncvalhead != syncvaltail) - { - packbuf[j++] = g_player[myconnectindex].syncval[syncvaltail&(MOVEFIFOSIZ-1)]; - syncvaltail++; - } */ - - Net_AddSyncData(&j); - - TRAVERSE_CONNECT(i) - if (i != myconnectindex) - mmulti_sendpacket(i,packbuf,j); - - return; - } - if (myconnectindex != connecthead) //Slave - { - //Fix timers and buffer/jitter value - if (((g_player[myconnectindex].movefifoend-1)&(TIMERUPDATESIZ-1)) == 0) - { - i = g_player[connecthead].myminlag-otherminlag; - if (klabs(i) > 8) i >>= 1; - else if (klabs(i) > 2) i = ksgn(i); - else i = 0; - - totalclock -= TICSPERFRAME*i; - g_player[connecthead].myminlag -= i; otherminlag += i; - - TRAVERSE_CONNECT(i) - g_player[i].myminlag = 0x7fffffff; - } + int32_t jj = 0; packbuf[0] = PACKET_SLAVE_TO_MASTER; - packbuf[1] = 0; - packbuf[2] = 0; - j = 3; + j = 1; - osyn = (input_t *)&inputfifo[(g_player[myconnectindex].movefifoend-2)&(MOVEFIFOSIZ-1)][myconnectindex]; - nsyn = (input_t *)&inputfifo[(g_player[myconnectindex].movefifoend-1)&(MOVEFIFOSIZ-1)][myconnectindex]; + nsyn = (input_t *)&inputfifo[0][myconnectindex]; - if (nsyn[0].fvel != osyn[0].fvel) - { - packbuf[j++] = (uint8_t)nsyn[0].fvel; - packbuf[j++] = (uint8_t)(nsyn[0].fvel>>8); - packbuf[1] |= 1; - } - if (nsyn[0].svel != osyn[0].svel) - { - packbuf[j++] = (uint8_t)nsyn[0].svel; - packbuf[j++] = (uint8_t)(nsyn[0].svel>>8); - packbuf[1] |= 2; - } - if (nsyn[0].avel != osyn[0].avel) - { - packbuf[j++] = (int8_t)nsyn[0].avel; - packbuf[1] |= 4; - } - if ((nsyn[0].bits^osyn[0].bits)&0x000000ff) packbuf[j++] = (nsyn[0].bits&255), packbuf[1] |= 8; - if ((nsyn[0].bits^osyn[0].bits)&0x0000ff00) packbuf[j++] = ((nsyn[0].bits>>8)&255), packbuf[1] |= 16; - if ((nsyn[0].bits^osyn[0].bits)&0x00ff0000) packbuf[j++] = ((nsyn[0].bits>>16)&255), packbuf[1] |= 32; - if ((nsyn[0].bits^osyn[0].bits)&0xff000000) packbuf[j++] = ((nsyn[0].bits>>24)&255), packbuf[1] |= 64; - if (nsyn[0].horz != osyn[0].horz) - { - packbuf[j++] = (uint8_t)nsyn[0].horz; - packbuf[1] |= 128; - } - packbuf[2] = 0; - if (nsyn[0].extbits != osyn[0].extbits) packbuf[j++] = nsyn[0].extbits, packbuf[2] |= 1; - /* if ((nsyn[0].extbits^osyn[0].extbits)&0x000000ff) packbuf[j++] = (nsyn[0].extbits&255), packbuf[2] |= 1; - if ((nsyn[0].extbits^osyn[0].extbits)&0x0000ff00) packbuf[j++] = ((nsyn[0].extbits>>8)&255), packbuf[2] |= 2; - if ((nsyn[0].extbits^osyn[0].extbits)&0x00ff0000) packbuf[j++] = ((nsyn[0].extbits>>16)&255), packbuf[2] |= 4; - if ((nsyn[0].extbits^osyn[0].extbits)&0xff000000) packbuf[j++] = ((nsyn[0].extbits>>24)&255), packbuf[2] |= 8; */ + Bmemcpy(&packbuf[j], &nsyn[0], sizeof(input_t)); + j += sizeof(input_t)-sizeof(loc.filler); + Bmemcpy(&packbuf[j], &g_player[myconnectindex].ps->posx, sizeof(vec3_t) * 3); + j += sizeof(vec3_t) * 3; + Bmemcpy(&packbuf[j], &g_player[myconnectindex].ps->ang, sizeof(int16_t) * 2); + j += sizeof(int16_t) * 2; - /* while (g_player[myconnectindex].syncvalhead != syncvaltail) - { - packbuf[j++] = g_player[myconnectindex].syncval[syncvaltail&(MOVEFIFOSIZ-1)]; - syncvaltail++; - } */ - Net_AddSyncData(&j); + i = g_player[myconnectindex].ps->i; + + packbuf[(jj = j++)] = 0; + + if (T5 >= (intptr_t)&script[0] && T5 < (intptr_t)(&script[g_scriptSize])) + { + packbuf[jj] |= 2; + T5 -= (intptr_t)&script[0]; + } + + Bmemcpy(&packbuf[j], &T3, sizeof(T3)); + j += sizeof(T3); + Bmemcpy(&packbuf[j], &T4, sizeof(T4)); + j += sizeof(T4); + Bmemcpy(&packbuf[j], &T5, sizeof(T5)); + j += sizeof(T5); + + if (packbuf[jj] & 2) T5 += (intptr_t)&script[0]; + + { + char buf[1024]; + + j = qlz_compress((char *)packbuf+1, (char *)buf, j, state_compress); + Bmemcpy((char *)packbuf+1, (char *)buf, j); + j++; + } + + packbuf[j++] = myconnectindex; + + enet_peer_send(net_peer, 1, enet_packet_create(packbuf, j, 0)); + + movefifosendplc++; - mmulti_sendpacket(connecthead,packbuf,j); return; } - //This allows allow packet resends - TRAVERSE_CONNECT(i) - if (g_player[i].movefifoend <= movefifosendplc) + if (net_server) { - packbuf[0] = PACKET_NULL_PACKET; - for (i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i]) - mmulti_sendpacket(i,packbuf,1); - return; - } - - while (1) //Master - { - TRAVERSE_CONNECT(i) - if (g_player[i].playerquitflag && (g_player[i].movefifoend <= movefifosendplc)) return; - - osyn = (input_t *)&inputfifo[(movefifosendplc-1)&(MOVEFIFOSIZ-1)][0]; - nsyn = (input_t *)&inputfifo[(movefifosendplc)&(MOVEFIFOSIZ-1)][0]; + input_t * osyn = (input_t *)&inputfifo[1][0]; + int16_t i, nexti, k = 0, l; //MASTER -> SLAVE packet packbuf[0] = PACKET_MASTER_TO_SLAVE; j = 1; - //Fix timers and buffer/jitter value - if ((movefifosendplc&(TIMERUPDATESIZ-1)) == 0) - { - for (i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i]) - if (g_player[i].playerquitflag) - packbuf[j++] = min(max(g_player[i].myminlag,-128),127); - - TRAVERSE_CONNECT(i) - g_player[i].myminlag = 0x7fffffff; - } - - k = j; - - TRAVERSE_CONNECT(i) - j += g_player[i].playerquitflag + g_player[i].playerquitflag; + ticrandomseed = randomseed; + Bmemcpy(&packbuf[j], &ticrandomseed, sizeof(ticrandomseed)); + j += sizeof(ticrandomseed); + nsyn = (input_t *)&inputfifo[0][0]; + TRAVERSE_CONNECT(i) { if (g_player[i].playerquitflag == 0) continue; - packbuf[k] = 0; - if (nsyn[i].fvel != osyn[i].fvel) + Bmemcpy(&osyn[i], &nsyn[i], sizeof(input_t)); + + Bmemcpy(&packbuf[j], &nsyn[i], sizeof(input_t)); + j += sizeof(input_t)-sizeof(loc.filler); + Bmemcpy(&packbuf[j], &g_player[i].ps->posx, sizeof(vec3_t) * 3); + j += sizeof(vec3_t) * 3; + Bmemcpy(&packbuf[j], &g_player[i].ps->ang, sizeof(int16_t) * 2); + j += sizeof(int16_t) * 2; + Bmemcpy(&packbuf[j], &sprite[g_player[i].ps->i].extra, sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&packbuf[j], &g_player[i].ps->kickback_pic, sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&packbuf[j], &g_player[i].ps->shield_amount, sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&packbuf[j], &ActorExtra[g_player[i].ps->i].owner, sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&packbuf[j], &ActorExtra[g_player[i].ps->i].picnum, sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&packbuf[j], &g_player[i].ps->gotweapon[0], sizeof(g_player[i].ps->gotweapon)); + j += sizeof(g_player[i].ps->gotweapon); + Bmemcpy(&packbuf[j], &g_player[i].ps->curr_weapon, sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&packbuf[j], &g_player[i].ps->ammo_amount[0], sizeof(g_player[i].ps->ammo_amount)); + j += sizeof(g_player[i].ps->ammo_amount); + Bmemcpy(&packbuf[j], &g_player[i].ps->last_weapon, sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&packbuf[j], &g_player[i].ps->wantweaponfire, sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&packbuf[j], &g_player[i].ps->frag_ps, sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&packbuf[j], &g_player[i].ps->fraggedself, sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&packbuf[j], &g_player[i].ps->last_extra, sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&packbuf[j], &g_player[i].ps->dead_flag, sizeof(int16_t)); + j += sizeof(int16_t); + + l = i; { - packbuf[j++] = (uint8_t)nsyn[i].fvel; - packbuf[j++] = (uint8_t)(nsyn[i].fvel>>8); - packbuf[k] |= 1; + int16_t ii=g_gameVarCount-1, kk = 0; + + for (; ii>=0; ii--) + { + if ((aGameVars[ii].dwFlags & GAMEVAR_PERACTOR) && aGameVars[ii].val.plValues) + { + if (peractorvals[ii][i] != aGameVars[ii].val.plValues[i]) + { + peractorvals[ii][i] = aGameVars[ii].val.plValues[i]; + + Bmemcpy(&packbuf[j], &ii, sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&packbuf[j], &aGameVars[ii].val.plValues[i], sizeof(int32_t)); + j += sizeof(int32_t); + kk++; + } + } + if (kk > 64) break; + } + ii = MAXGAMEVARS; + Bmemcpy(&packbuf[j], &ii, sizeof(int16_t)); + j += sizeof(int16_t); } - if (nsyn[i].svel != osyn[i].svel) + i = l; + { - packbuf[j++] = (uint8_t)nsyn[i].svel; - packbuf[j++] = (uint8_t)(nsyn[i].svel>>8); - packbuf[k] |= 2; + int16_t ii=g_gameVarCount-1, kk = 0; + + for (; ii>=0; ii--) + { + if ((aGameVars[ii].dwFlags & GAMEVAR_PERPLAYER) && aGameVars[ii].val.plValues) + { + if (perplayervals[ii][i] != aGameVars[ii].val.plValues[i]) + { + perplayervals[ii][i] = aGameVars[ii].val.plValues[i]; + + Bmemcpy(&packbuf[j], &ii, sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&packbuf[j], &aGameVars[ii].val.plValues[i], sizeof(int32_t)); + j += sizeof(int32_t); + kk++; + } + } + if (kk > 64) break; + } + ii = MAXGAMEVARS; + Bmemcpy(&packbuf[j], &ii, sizeof(int16_t)); + j += sizeof(int16_t); } - if (nsyn[i].avel != osyn[i].avel) - { - packbuf[j++] = (int8_t)nsyn[i].avel; - packbuf[k] |= 4; - } - if ((nsyn[i].bits^osyn[i].bits)&0x000000ff) packbuf[j++] = (nsyn[i].bits&255), packbuf[k] |= 8; - if ((nsyn[i].bits^osyn[i].bits)&0x0000ff00) packbuf[j++] = ((nsyn[i].bits>>8)&255), packbuf[k] |= 16; - if ((nsyn[i].bits^osyn[i].bits)&0x00ff0000) packbuf[j++] = ((nsyn[i].bits>>16)&255), packbuf[k] |= 32; - if ((nsyn[i].bits^osyn[i].bits)&0xff000000) packbuf[j++] = ((nsyn[i].bits>>24)&255), packbuf[k] |= 64; - if (nsyn[i].horz != osyn[i].horz) - { - packbuf[j++] = (uint8_t)nsyn[i].horz; - packbuf[k] |= 128; - } - k++; - packbuf[k] = 0; - if (nsyn[i].extbits != osyn[i].extbits) packbuf[j++] = nsyn[i].extbits, packbuf[k] |= 1; - /* - if ((nsyn[i].extbits^osyn[i].extbits)&0x000000ff) packbuf[j++] = (nsyn[i].extbits&255), packbuf[k] |= 1; - if ((nsyn[i].extbits^osyn[i].extbits)&0x0000ff00) packbuf[j++] = ((nsyn[i].extbits>>8)&255), packbuf[k] |= 2; - if ((nsyn[i].extbits^osyn[i].extbits)&0x00ff0000) packbuf[j++] = ((nsyn[i].extbits>>16)&255), packbuf[k] |= 4; - if ((nsyn[i].extbits^osyn[i].extbits)&0xff000000) packbuf[j++] = ((nsyn[i].extbits>>24)&255), packbuf[k] |= 8; */ - k++; } - /* while (g_player[myconnectindex].syncvalhead != syncvaltail) - { - packbuf[j++] = g_player[myconnectindex].syncval[syncvaltail&(MOVEFIFOSIZ-1)]; - syncvaltail++; - } */ - Net_AddSyncData(&j); + Bmemcpy(&packbuf[j], &headspritestat[STAT_ACTOR], sizeof(int16_t)); + j += sizeof(int16_t); - for (i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i]) - if (g_player[i].playerquitflag) + Bmemcpy(&packbuf[j], &headspritestat[STAT_ZOMBIEACTOR], sizeof(int16_t)); + j += sizeof(int16_t); + + Bmemcpy(&packbuf[j], &headspritestat[STAT_PROJECTILE], sizeof(int16_t)); + j += sizeof(int16_t); + + k = 0; + + { + int32_t lists[] = { STAT_STANDABLE, STAT_EFFECTOR, STAT_ACTOR, STAT_ZOMBIEACTOR, STAT_PROJECTILE }, zz; + + for (zz = 0; (unsigned)zz < (sizeof(lists)/sizeof(lists[0])); zz++) + TRAVERSE_SPRITE_STAT(headspritestat[lists[zz]], i, nexti) { - mmulti_sendpacket(i,packbuf,j); - if (TEST_SYNC_KEY(nsyn[i].bits,SK_GAMEQUIT)) - g_player[i].playerquitflag = 0; - } + if (totalclock > (lastupdate[i] + (TICSPERFRAME * 6))) + { + l = crc32once((uint8_t *)&sprite[i], sizeof(spritetype)); - movefifosendplc += g_movesPerPacket; + if (spritecrc[i] != l) + { + int32_t jj = 0; + + spritecrc[i] = l; + lastupdate[i] = totalclock; + Bmemcpy(&packbuf[j], &i, sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&packbuf[j], &sprite[i], sizeof(spritetype)); + j += sizeof(spritetype); + + packbuf[(jj = j++)] = 0; + + if (T2 >= (intptr_t)&script[0] && T2 < (intptr_t)(&script[g_scriptSize])) + { + packbuf[jj] |= 1; + T2 -= (intptr_t)&script[0]; + } + if (T5 >= (intptr_t)&script[0] && T5 < (intptr_t)(&script[g_scriptSize])) + { + packbuf[jj] |= 2; + T5 -= (intptr_t)&script[0]; + } + if (T6 >= (intptr_t)&script[0] && T6 < (intptr_t)(&script[g_scriptSize])) + { + packbuf[jj] |= 4; + T6 -= (intptr_t)&script[0]; + } + Bmemcpy(&packbuf[j], &ActorExtra[i], sizeof(ActorData_t)-sizeof(ActorExtra[0].filler)); + j += sizeof(ActorData_t)-sizeof(ActorExtra[0].filler); + + if (packbuf[jj] & 1) T2 += (intptr_t)&script[0]; + if (packbuf[jj] & 2) T5 += (intptr_t)&script[0]; + if (packbuf[jj] & 4) T6 += (intptr_t)&script[0]; + + { + int16_t ii=g_gameVarCount-1, kk = 0; + + for (; ii>=0; ii--) + { + if ((aGameVars[ii].dwFlags & GAMEVAR_PERACTOR) && aGameVars[ii].val.plValues) + { + if (peractorvals[ii][i] != aGameVars[ii].val.plValues[i]) + { + peractorvals[ii][i] = aGameVars[ii].val.plValues[i]; + + Bmemcpy(&packbuf[j], &ii, sizeof(int16_t)); + j += sizeof(int16_t); + Bmemcpy(&packbuf[j], &aGameVars[ii].val.plValues[i], sizeof(int32_t)); + j += sizeof(int32_t); + kk++; + } + } + if (kk > 64) break; + } + ii = MAXGAMEVARS; + Bmemcpy(&packbuf[j], &ii, sizeof(int16_t)); + j += sizeof(int16_t); + } + + k++; + } + } + if (k > 4) break; + } + } + + { + char buf[4096]; + + j = qlz_compress((char *)packbuf+1, (char *)buf, j, state_compress); + Bmemcpy((char *)packbuf+1, (char *)buf, j); + j++; + } + + packbuf[j++] = myconnectindex; + + enet_host_broadcast(net_server, 0, enet_packet_create(packbuf, j, 0)); + + movefifosendplc++; } } @@ -2645,9 +3093,9 @@ static void G_PrintGameQuotes(void) else gametext(320>>1,k,ScriptQuotes[g_player[screenpeek].ps->ftq],0,2+8+16+1+32); return; } - if (j > 4) gametext(320>>1,k,ScriptQuotes[g_player[screenpeek].ps->ftq],(sintable[(totalclock<<5)&2047]>>11),2+8+16); - else if (j > 2) gametext(320>>1,k,ScriptQuotes[g_player[screenpeek].ps->ftq],(sintable[(totalclock<<5)&2047]>>11),2+8+16+1); - else gametext(320>>1,k,ScriptQuotes[g_player[screenpeek].ps->ftq],(sintable[(totalclock<<5)&2047]>>11),2+8+16+1+32); + if (j > 4) gametext(320>>1,k,ScriptQuotes[g_player[screenpeek].ps->ftq],quotepulseshade,2+8+16); + else if (j > 2) gametext(320>>1,k,ScriptQuotes[g_player[screenpeek].ps->ftq],quotepulseshade,2+8+16+1); + else gametext(320>>1,k,ScriptQuotes[g_player[screenpeek].ps->ftq],quotepulseshade,2+8+16+1+32); } void P_DoQuote(int32_t q, DukePlayer_t *p) @@ -2759,6 +3207,7 @@ void G_GameExit(const char *t) { if (*t != 0) g_player[myconnectindex].ps->palette = (uint8_t *) &palette[0]; +/* if (numplayers > 1) { int32_t i, j, oldtotalclock; @@ -2777,15 +3226,14 @@ void G_GameExit(const char *t) if (KB_KeyPressed(sc_Escape)) return; packbuf[0] = PACKET_NULL_PACKET; - TRAVERSE_CONNECT(i) - { - if (i != myconnectindex) mmulti_sendpacket(i,packbuf,1); - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master - } + + if (net_client) + enet_peer_send(net_peer, 0, enet_packet_create(packbuf, 1, ENET_PACKET_FLAG_RELIABLE)); + else if (net_server) + enet_host_broadcast(net_server, 0, enet_packet_create(packbuf, 1, ENET_PACKET_FLAG_RELIABLE)); } } - - mmulti_uninitmultiplayers(); +*/ if (ud.recstat == 1) G_CloseDemoWrite(); else if (ud.recstat == 2) @@ -2912,11 +3360,11 @@ int32_t _EnterText(int32_t small,int32_t x,int32_t y,char *t,int32_t dalen,int32 static void Net_EnterMessage(void) { - int16_t ch, hitstate, i, j, l; + int16_t hitstate, i, j, l; if (g_player[myconnectindex].ps->gm&MODE_SENDTOWHOM) { - if (g_chatPlayer != -1 || ud.multimode < 3 || g_movesPerPacket == 4) + if (g_chatPlayer != -1 || ud.multimode < 3) { tempbuf[0] = PACKET_MESSAGE; tempbuf[2] = 0; @@ -2950,14 +3398,13 @@ static void Net_EnterMessage(void) recbuf[j] = 0; Bstrcat(tempbuf+2,recbuf); - if (g_chatPlayer >= ud.multimode || g_movesPerPacket == 4) + if (g_chatPlayer >= ud.multimode) { tempbuf[1] = 255; - TRAVERSE_CONNECT(ch) - { - if (ch != myconnectindex) mmulti_sendpacket(ch,tempbuf,j+2); - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master - } + tempbuf[j+2] = myconnectindex; + j++; + if (net_server) enet_host_broadcast(net_server, 0, enet_packet_create(tempbuf, j+2, ENET_PACKET_FLAG_UNSEQUENCED)); + else if (net_client) enet_peer_send(net_peer, 0, enet_packet_create(tempbuf, j+2, ENET_PACKET_FLAG_UNSEQUENCED)); G_AddUserQuote(recbuf); quotebot += 8; l = G_GameTextLen(USERQUOTE_LEFTOFFSET,stripcolorcodes(tempbuf,recbuf)); @@ -2968,6 +3415,7 @@ static void Net_EnterMessage(void) } quotebotgoal = quotebot; } +/* else if (g_chatPlayer >= 0) { tempbuf[1] = (uint8_t)g_chatPlayer; @@ -2976,6 +3424,7 @@ static void Net_EnterMessage(void) mmulti_sendpacket(g_chatPlayer,tempbuf,j+2); } +*/ g_chatPlayer = -1; g_player[myconnectindex].ps->gm &= ~(MODE_TYPE|MODE_SENDTOWHOM); } @@ -3615,6 +4064,7 @@ void G_DisplayRest(int32_t smoothratio) { if (pp->newowner == -1 && !ud.pause_on) { +/* if (screenpeek == myconnectindex && numplayers > 1) { cposx = omy.x+mulscale16((int32_t)(my.x-omy.x),smoothratio); @@ -3622,6 +4072,7 @@ void G_DisplayRest(int32_t smoothratio) cang = omyang+mulscale16((int32_t)(((myang+1024-omyang)&2047)-1024),smoothratio); } else +*/ { cposx = pp->oposx+mulscale16((int32_t)(pp->posx-pp->oposx),smoothratio); cposy = pp->oposy+mulscale16((int32_t)(pp->posy-pp->oposy),smoothratio); @@ -3689,8 +4140,8 @@ void G_DisplayRest(int32_t smoothratio) if (MapInfo[(ud.volume_number*MAXLEVELS) + ud.level_number].name != NULL) { if (currentboardfilename[0] != 0 && ud.volume_number == 0 && ud.level_number == 7) - menutext_(160,75,-g_levelTextTime+22/*(sintable[(totalclock<<5)&2047]>>11)*/,0,currentboardfilename,bits); - else menutext_(160,75,-g_levelTextTime+22/*(sintable[(totalclock<<5)&2047]>>11)*/,0,MapInfo[(ud.volume_number*MAXLEVELS) + ud.level_number].name,bits); + menutext_(160,75,-g_levelTextTime+22/*quotepulseshade*/,0,currentboardfilename,bits); + else menutext_(160,75,-g_levelTextTime+22/*quotepulseshade*/,0,MapInfo[(ud.volume_number*MAXLEVELS) + ud.level_number].name,bits); } } @@ -4291,6 +4742,7 @@ void G_DrawRooms(int32_t snum, int32_t smoothratio) p->orotscrnang = p->rotscrnang; // JBF: save it for next time } +/* if ((snum == myconnectindex) && (numplayers > 1)) { vec3_t cam = { omy.x+mulscale16((int32_t)(my.x-omy.x),smoothratio), @@ -4303,6 +4755,7 @@ void G_DrawRooms(int32_t snum, int32_t smoothratio) ud.camerasect = mycursectnum; } else +*/ { vec3_t cam = { p->oposx+mulscale16((int32_t)(p->posx-p->oposx),smoothratio), p->oposy+mulscale16((int32_t)(p->posy-p->oposy),smoothratio), @@ -5441,13 +5894,11 @@ int32_t A_Spawn(int32_t j, int32_t pn) case APLAYER__STATIC: sp->xrepeat = sp->yrepeat = 0; - //j = ud.coop; - //if(j == 2) j = 0; - j=(GametypeFlags[ud.coop] & GAMETYPE_COOPSPAWN) / GAMETYPE_COOPSPAWN ; - if (ud.multimode < 2 || (ud.multimode > 1 && j != sp->lotag)) - changespritestat(i,5); + sp->cstat = 32768; + if (ud.multimode < 2 || ((GametypeFlags[ud.coop] & GAMETYPE_COOPSPAWN)/GAMETYPE_COOPSPAWN) != sp->lotag) + changespritestat(i,STAT_MISC); else - changespritestat(i,10); + changespritestat(i,STAT_PLAYER); break; case WATERBUBBLE__STATIC: if (j >= 0 && sprite[j].picnum == APLAYER) @@ -5517,7 +5968,7 @@ int32_t A_Spawn(int32_t j, int32_t pn) sp->z -= (18<<8); } else sp->z -= (13<<8); - sp->ang = getangle(g_player[connecthead].ps->posx-sp->x,g_player[connecthead].ps->posy-sp->y); + sp->ang = getangle(g_player[0].ps->posx-sp->x,g_player[0].ps->posy-sp->y); sp->xvel = 48-(krand()&31); A_SetSprite(i,CLIPMASK0); } @@ -6895,15 +7346,17 @@ void G_DoSpriteAnimations(int32_t x,int32_t y,int32_t a,int32_t smoothratio) if (g_player[p].ps->over_shoulder_on > 0 && g_player[p].ps->newowner < 0) { - if (screenpeek == myconnectindex && numplayers >= 2) - { - t->x = omy.x+mulscale16((int32_t)(my.x-omy.x),smoothratio); - t->y = omy.y+mulscale16((int32_t)(my.y-omy.y),smoothratio); - t->z = omy.z+mulscale16((int32_t)(my.z-omy.z),smoothratio)+(40<<8); - t->ang = omyang+mulscale16((int32_t)(((myang+1024-omyang)&2047)-1024),smoothratio); - t->sectnum = mycursectnum; - } - else t->ang = g_player[p].ps->ang+mulscale16((int32_t)(((g_player[p].ps->ang+1024- g_player[p].ps->oang)&2047)-1024),smoothratio); +/* + if (screenpeek == myconnectindex && numplayers >= 2) + { + t->x = omy.x+mulscale16((int32_t)(my.x-omy.x),smoothratio); + t->y = omy.y+mulscale16((int32_t)(my.y-omy.y),smoothratio); + t->z = omy.z+mulscale16((int32_t)(my.z-omy.z),smoothratio)+(40<<8); + t->ang = omyang+mulscale16((int32_t)(((myang+1024-omyang)&2047)-1024),smoothratio); + t->sectnum = mycursectnum; + } + else*/ + t->ang = g_player[p].ps->ang+mulscale16((int32_t)(((g_player[p].ps->ang+1024- g_player[p].ps->oang)&2047)-1024),smoothratio); #if defined(POLYMOST) && defined(USE_OPENGL) if (bpp > 8 && usemodels && md_tilehasmodel(t->picnum, t->pal) >= 0) { @@ -6985,7 +7438,6 @@ void G_DoSpriteAnimations(int32_t x,int32_t y,int32_t a,int32_t smoothratio) if (s->owner == -1) { - #if defined(POLYMOST) && defined(USE_OPENGL) if (getrendermode() >= 3 && usemodels && md_tilehasmodel(s->picnum,t->pal) >= 0 && !(spriteext[i].flags&SPREXT_NOTMD)) { @@ -7312,6 +7764,9 @@ PALONLY: t->shade = -127; t->cstat |= 8192; break; + case SMALLSMOKE__STATIC: + t->cstat |= 8192; + break; case COOLEXPLOSION1__STATIC: t->shade = -127; t->cstat |= 8192; @@ -7854,7 +8309,7 @@ FOUNDCHEAT: i = Bstrlen(CheatStrings[k])-1; ud.m_player_skill = ud.player_skill = cheatbuf[i] - '1'; } - if (numplayers > 1 && myconnectindex == connecthead) + if (numplayers > 1 && net_server) Net_NewGame(ud.m_volume_number,ud.m_level_number); else g_player[myconnectindex].ps->gm |= MODE_RESTART; @@ -8083,7 +8538,7 @@ static void G_ShowScores(void) xfragtotal += g_player[i].frags[y]; } - if (myconnectindex == connecthead) + if (net_server) { Bsprintf(tempbuf,"stats %d killed %d %d\n",i+1,y+1,g_player[i].frags[y]); sendscore(tempbuf); @@ -8135,12 +8590,14 @@ static void G_HandleLocalKeys(void) tempbuf[0] = PACKET_MAP_VOTE; tempbuf[1] = myconnectindex; tempbuf[2] = (KB_UnBoundKeyPressed(sc_F1) || ud.autovote ? ud.autovote-1 : 0); + tempbuf[3] = myconnectindex; + + if (net_client) + enet_peer_send(net_peer, 0, enet_packet_create(tempbuf, 4, ENET_PACKET_FLAG_RELIABLE)); + else if (net_server) + enet_host_broadcast(net_server, 0, enet_packet_create(tempbuf, 4, ENET_PACKET_FLAG_RELIABLE)); + - TRAVERSE_CONNECT(i) - { - if (i != myconnectindex) mmulti_sendpacket(i,tempbuf,3); - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master - } G_AddUserQuote("VOTE CAST"); g_player[myconnectindex].gotvote = 1; KB_ClearKeyDown(sc_F1); @@ -8203,7 +8660,7 @@ static void G_HandleLocalKeys(void) { CONTROL_ClearButton(gamefunc_See_Coop_View); screenpeek = connectpoint2[screenpeek]; - if (screenpeek == -1) screenpeek = connecthead; + if (screenpeek == -1) screenpeek = 0; g_restorePalette = 1; } @@ -8379,12 +8836,12 @@ static void G_HandleLocalKeys(void) i = 2+strlen(ud.ridecule[i-1]); - if (ud.multimode > 1) - TRAVERSE_CONNECT(ch) - { - if (ch != myconnectindex) mmulti_sendpacket(ch,tempbuf,i); - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master - } + tempbuf[i++] = myconnectindex; + + if (net_client) + enet_peer_send(net_peer, 0, enet_packet_create(tempbuf, i, ENET_PACKET_FLAG_UNSEQUENCED)); + else if (net_server) + enet_host_broadcast(net_server, 0, enet_packet_create(tempbuf, i, ENET_PACKET_FLAG_UNSEQUENCED)); pus = NUMPAGES; pub = NUMPAGES; @@ -8405,12 +8862,12 @@ static void G_HandleLocalKeys(void) { tempbuf[0] = PACKET_RTS; tempbuf[1] = i; + tempbuf[2] = myconnectindex; - TRAVERSE_CONNECT(ch) - { - if (ch != myconnectindex) mmulti_sendpacket(ch,tempbuf,2); - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master - } + if (net_client) + enet_peer_send(net_peer, 0, enet_packet_create(tempbuf, 3, ENET_PACKET_FLAG_UNSEQUENCED)); + else if (net_server) + enet_host_broadcast(net_server, 0, enet_packet_create(tempbuf, 3, ENET_PACKET_FLAG_UNSEQUENCED)); } pus = NUMPAGES; @@ -8465,9 +8922,6 @@ static void G_HandleLocalKeys(void) { KB_ClearKeyDown(sc_F2); - if (g_movesPerPacket == 4 && connecthead != myconnectindex) - return; - FAKE_F2: if (sprite[g_player[myconnectindex].ps->i].extra <= 0) { @@ -8497,8 +8951,6 @@ FAKE_F2: { KB_ClearKeyDown(sc_F3); - if (g_movesPerPacket == 4 && connecthead != myconnectindex) - return; FAKE_F3: ChangeToMenu(300); FX_StopAllSounds(); @@ -8536,9 +8988,6 @@ FAKE_F3: KB_ClearKeyDown(sc_F6); g_doQuickSave = 0; - if (g_movesPerPacket == 4 && connecthead != myconnectindex) - return; - if (g_lastSaveSlot == -1) goto FAKE_F2; KB_FlushKeyboardQueue(); @@ -8609,9 +9058,6 @@ FAKE_F3: KB_ClearKeyDown(sc_F9); g_doQuickSave = 0; - if (g_movesPerPacket == 4 && myconnectindex != connecthead) - return; - if (g_lastSaveSlot == -1) goto FAKE_F3; if (g_lastSaveSlot >= 0) @@ -9184,7 +9630,6 @@ static void G_AddPath(const char *buffer) static void G_CheckCommandLine(int32_t argc, const char **argv) { - int32_t firstnet = 0; int16_t i = 1, j; char *c, *k; @@ -9218,7 +9663,7 @@ static void G_CheckCommandLine(int32_t argc, const char **argv) while (i < argc) { c = (char *)argv[i]; - if (((*c == '/') || (*c == '-')) && (!firstnet)) + if (((*c == '/') || (*c == '-'))) { if (!Bstrcasecmp(c+1,"?") || !Bstrcasecmp(c+1,"help") || !Bstrcasecmp(c+1,"-help")) { @@ -9321,18 +9766,73 @@ static void G_CheckCommandLine(int32_t argc, const char **argv) i++; continue; } - if (!Bstrcasecmp(c+1,"debugsync")) + if (!Bstrcasecmp(c+1,"server")) { - g_numSyncBytes = 6; + ENetAddress address; + + /* Bind the server to the default localhost. */ + /* A specific host address can be specified by */ + /* enet_address_set_host (& address, "x.x.x.x"); */ + + address.host = ENET_HOST_ANY; + address.port = 23513; + + net_server = enet_host_create (&address, MAXPLAYERS, 0, 0); + + if (net_server == NULL) + initprintf("An error occurred while trying to create an ENet server host.\n"); + + g_noSetup = g_noLogo = TRUE; i++; continue; } - if (!Bstrcasecmp(c+1,"net") || !Bstrcasecmp(c+1,"rmnet")) + if (!Bstrcasecmp(c+1,"connect")) { - g_noSetup = TRUE; - firstnet = i; - netparamcount = argc - i - 1; - netparam = (char **)Bcalloc(netparamcount, sizeof(char**)); + if (argc > i+1) + { + ENetAddress address; + ENetEvent event; + + Net_Disconnect(); + + net_client = enet_host_create (NULL, 1, 0, 0); + + if (net_client == NULL) + { + initprintf ("An error occurred while trying to create an ENet client host.\n"); + i += 2; + continue; + } + + enet_address_set_host (&address, (char *)argv[i+1]); + address.port = 23513; + + // use 2 channels for easy packet sorting at a lower level than the game later + net_peer = enet_host_connect (net_client, &address, 2); + + if (net_peer == NULL) + { + initprintf ("No available peers for initiating an ENet connection.\n"); + i += 2; + continue; + } + + /* Wait up to 5 seconds for the connection attempt to succeed. */ + if (enet_host_service (net_client, & event, 5000) > 0 && + event.type == ENET_EVENT_TYPE_CONNECT) + initprintf("Connection to %s:%d succeeded.\n",(char *)argv[i+1],address.port); + else + { + /* Either the 5 seconds are up or a disconnect event was */ + /* received. Reset the peer in the event the 5 seconds */ + /* had run out without any significant event. */ + enet_peer_reset (net_peer); + Net_Disconnect(); + initprintf("Connection to %s:%d failed.\n",(char *)argv[i+1],address.port); + } + + i++; + } i++; continue; } @@ -9417,28 +9917,6 @@ static void G_CheckCommandLine(int32_t argc, const char **argv) #endif } - if (firstnet > 0) - { - if (*c == '-' || *c == '/') - { - c++; - if (((c[0] == 'n') || (c[0] == 'N')) && (c[1] == '0')) - { - g_networkBroadcastMode = 0; - initprintf("Network mode: master/slave\n"); - } - else if (((c[0] == 'n') || (c[0] == 'N')) && (c[1] == '1')) - { - g_networkBroadcastMode = 1; - initprintf("Network mode: peer-to-peer\n"); - } - - } - netparam[i-firstnet-1] = (char *)argv[i]; - i++; - continue; - } - if ((*c == '/') || (*c == '-')) { c++; @@ -9483,18 +9961,6 @@ static void G_CheckCommandLine(int32_t argc, const char **argv) initprintf("Play demo %s.\n",c); Bstrcpy(firstdemofile,c); break; - case 'f': - c++; - if (*c == '1') - g_movesPerPacket = 1; - if (*c == '2') - g_movesPerPacket = 2; - if (*c == '4') - { - g_movesPerPacket = 4; - mmulti_setpackettimeout(0x3fffffff,0x3fffffff); // this doesn't do anything anymore - } - break; case 'g': c++; if (!*c) break; @@ -9508,12 +9974,6 @@ static void G_CheckCommandLine(int32_t argc, const char **argv) initprintf("Using DEF file: %s.\n",duke3ddef); } break; - case 'i': - c++; - if (*c == '0') g_networkBroadcastMode = 0; - if (*c == '1') g_networkBroadcastMode = 1; - initprintf("Network Mode %d\n",g_networkBroadcastMode); - break; case 'j': c++; if (!*c) break; @@ -9790,7 +10250,7 @@ static void G_DisplayLogo(void) fadepal(0,0,0, 63,0,-7); totalclock = 0; - while (totalclock < (860+120) && !KB_KeyWaiting() && !MOUSE_GetButtons()&LEFT_MOUSE) + while (totalclock < (860+120) && !KB_KeyWaiting() && !MOUSE_GetButtons()&LEFT_MOUSE && !BUTTON(gamefunc_Fire) && !BUTTON(gamefunc_Open)) { rotatesprite(0,0,65536L,0,BETASCREEN,0,0,2+8+16+64,0,0,xdim-1,ydim-1); if (logoflags & LOGO_DUKENUKEM) @@ -10100,6 +10560,8 @@ static void G_Startup(void) inittimer(TICRATE); + initcrc32table(); + G_CompileScripts(); CONFIG_ReadKeys(); // we re-read the keys after compiling the CONs @@ -10179,19 +10641,13 @@ static void G_Startup(void) for (i=0; i 1) initprintf("Multiplayer initialized.\n"); @@ -10226,9 +10682,6 @@ static void G_Startup(void) tilesizx[MIRROR] = tilesizy[MIRROR] = 0; screenpeek = myconnectindex; - - if (g_networkBroadcastMode == 255) - g_networkBroadcastMode = 1; } void sendscore(const char *s) @@ -10238,178 +10691,6 @@ void sendscore(const char *s) // genericmultifunction(-1,(char *)s,strlen(s)+1,5); } -int32_t quittimer = 0; - -void Net_SendQuit(void) -{ - if (g_gameQuit == 0 && (numplayers > 1)) - { - if (g_player[myconnectindex].ps->gm&MODE_GAME) - { - g_gameQuit = 1; - quittimer = totalclock+120; - } - else - { - int32_t i; - - tempbuf[0] = PACKET_MENU_LEVEL_QUIT; - tempbuf[1] = myconnectindex; - - TRAVERSE_CONNECT(i) - { - if (i != myconnectindex) mmulti_sendpacket(i,tempbuf,2); - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master - } - G_GameExit(" "); - } - } - else if (numplayers < 2) - G_GameExit(" "); - - if ((totalclock > quittimer) && (g_gameQuit == 1)) - G_GameExit("Timed out."); -} - -static void Net_SendWeaponChoice(void) -{ - int32_t i,l; - - buf[0] = PACKET_WEAPON_CHOICE; - buf[1] = myconnectindex; - l = 2; - - for (i=0; i<10; i++) - { - g_player[myconnectindex].wchoice[i] = g_player[0].wchoice[i]; - buf[l++] = (uint8_t)g_player[0].wchoice[i]; - } - - TRAVERSE_CONNECT(i) - { - if (i != myconnectindex) mmulti_sendpacket(i,&buf[0],l); - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master - } -} - -static void Net_SendVersion(void) -{ - int32_t i; - - if (numplayers < 2) return; - - buf[0] = PACKET_VERSION; - buf[1] = myconnectindex; - buf[2] = (uint8_t)atoi(s_buildDate); - buf[3] = BYTEVERSION; - buf[4] = g_numSyncBytes; - - TRAVERSE_CONNECT(i) - { - if (i != myconnectindex) mmulti_sendpacket(i,&buf[0],5); - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master - } - Net_WaitForEverybody(); -} - -static void Net_SendPlayerOptions(void) -{ - int32_t i,l; - - buf[0] = PACKET_PLAYER_OPTIONS; - buf[1] = myconnectindex; - l = 2; - - //null terminated player name to send -// for (i=0;szPlayerName[i];i++) buf[l++] = Btoupper(szPlayerName[i]); -// buf[l++] = 0; - - buf[l++] = g_player[myconnectindex].ps->aim_mode = ud.mouseaiming; - buf[l++] = g_player[myconnectindex].ps->auto_aim = ud.config.AutoAim; - buf[l++] = g_player[myconnectindex].ps->weaponswitch = ud.weaponswitch; - buf[l++] = g_player[myconnectindex].ps->palookup = g_player[myconnectindex].pcolor = ud.color; - - buf[l++] = g_player[myconnectindex].pteam = ud.team; - - TRAVERSE_CONNECT(i) - { - if (i != myconnectindex) mmulti_sendpacket(i,&buf[0],l); - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master - } -} - -void Net_SendPlayerName(void) -{ - int32_t i,l; - - for (l=0; (unsigned)l 1) - { - int32_t j; - int32_t ch; - - packbuf[0] = PACKET_USER_MAP; - packbuf[1] = 0; - - Bcorrectfilename(boardfilename,0); - - j = Bstrlen(boardfilename); - boardfilename[j++] = 0; - Bstrcat(packbuf+1,boardfilename); - - TRAVERSE_CONNECT(ch) - { - if (ch != myconnectindex) mmulti_sendpacket(ch,packbuf,j); - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master - } - } -} - -void Net_NewGame(int32_t volume, int32_t level) -{ - int32_t i; - - packbuf[0] = PACKET_NEW_GAME; - packbuf[1] = ud.m_level_number = level; - packbuf[2] = ud.m_volume_number = volume; - packbuf[3] = ud.m_player_skill+1; - packbuf[4] = ud.m_monsters_off; - packbuf[5] = ud.m_respawn_monsters; - packbuf[6] = ud.m_respawn_items; - packbuf[7] = ud.m_respawn_inventory; - packbuf[8] = ud.m_coop; - packbuf[9] = ud.m_marker; - packbuf[10] = ud.m_ffire; - packbuf[11] = ud.m_noexits; - - TRAVERSE_CONNECT(i) - { - if (i != myconnectindex) mmulti_sendpacket(i,packbuf,12); - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master - } -} - void G_UpdatePlayerFromMenu(void) { if (ud.recstat != 0) @@ -10481,6 +10762,10 @@ void app_main(int32_t argc,const char **argv) } #endif + if (enet_initialize () != 0) + initprintf("An error occurred while initializing ENet.\n"); + else atexit (enet_deinitialize); + #ifdef RENDERTYPEWIN backgroundidle = 0; #endif @@ -10488,7 +10773,7 @@ void app_main(int32_t argc,const char **argv) #ifdef _WIN32 tempbuf[GetModuleFileName(NULL,root,BMAX_PATH)] = 0; Bcorrectfilename(root,1); - //chdir(root); + chdir(root); #else getcwd(root,BMAX_PATH); strcat(root,"/"); @@ -10526,8 +10811,6 @@ void app_main(int32_t argc,const char **argv) ud.multimode = 1; - initsynccrc(); - G_CheckCommandLine(argc,argv); #if defined(RENDERTYPEWIN) && defined(USE_OPENGL) @@ -10916,8 +11199,6 @@ CLEAN_DIRECTORY: kclose(i); } - if (netparamcount > 0) _buildargc = (argc -= netparamcount+1); // crop off the net parameters - // gotta set the proper title after we compile the CONs if this is the full version Bsprintf(tempbuf,"%s - " APPNAME,duke3dgrpstring); @@ -10928,15 +11209,19 @@ CLEAN_DIRECTORY: RegisterShutdownFunction(G_Shutdown); + numplayers = 1; + + connectpoint2[0] = -1; + + Net_GetPackets(); + G_Startup(); // a bunch of stuff including compiling cons - if (numplayers > 1) - ud.multimode = numplayers; - - for (i=1; ipalette = (uint8_t *) &palette[0]; @@ -10959,17 +11244,20 @@ CLEAN_DIRECTORY: loaddefinitions_game(duke3ddef, FALSE); } - if (numplayers > 1) - { - Net_SendVersion(); - Net_SendPlayerName(); - Net_SendPlayerOptions(); - Net_SendWeaponChoice(); - Net_SendUserMapName(); - Net_GetPackets(); - Net_WaitForEverybody(); - } - else if (boardfilename[0] != 0) +/* + if (numplayers > 1) + { + Net_SendVersion(); + Net_SendPlayerName(); + Net_SendPlayerOptions(); + Net_SendWeaponChoice(); + Net_SendUserMapName(); + Net_GetPackets(); + Net_WaitForEverybody(); + } + else*/ + + if (numplayers == 1 && boardfilename[0] != 0) { ud.m_level_number = 7; ud.m_volume_number = 0; @@ -11257,6 +11545,21 @@ MAIN_LOOP_RESTART: G_UpdateScreenArea(); } + if (net_client && g_multiMapState) + { + for (i=g_gameVarCount-1; i>=0; i--) + { + if (aGameVars[i].dwFlags & GAMEVAR_PERPLAYER) + g_multiMapState->vars[i] = NULL; + else if (aGameVars[i].dwFlags & GAMEVAR_PERACTOR) + g_multiMapState->vars[i] = NULL; + } + + G_RestoreMapState(g_multiMapState); + Bfree(g_multiMapState); + g_multiMapState = NULL; + } + { static uint32_t nextrender = 0; uint32_t j = getticks(); @@ -11287,8 +11590,6 @@ MAIN_LOOP_RESTART: if (debug_on) G_ShowCacheLocks(); - Net_DisplaySyncMsg(); - if (VOLUMEONE) { if (ud.show_help == 0 && g_showShareware > 0 && (g_player[myconnectindex].ps->gm&MODE_MENU) == 0) @@ -11608,7 +11909,7 @@ RECHECK: TRAVERSE_CONNECT(j) { - copybufbyte(&recsync[i],&inputfifo[g_player[j].movefifoend&(MOVEFIFOSIZ-1)][j],sizeof(input_t)); + copybufbyte(&recsync[i],&inputfifo[0][j],sizeof(input_t)); g_player[j].movefifoend++; i++; ud.reccnt--; @@ -11757,502 +12058,25 @@ RECHECK: static inline int32_t G_MoveLoop() { - int32_t i; - +/* if (numplayers > 1) - while (predictfifoplc < g_player[myconnectindex].movefifoend) Net_DoPrediction(); + Net_DoPrediction(); +*/ Net_GetPackets(); - if (numplayers < 2) bufferjitter = 0; - while (g_player[myconnectindex].movefifoend-movefifoplc > bufferjitter) + while (g_player[myconnectindex].movefifoend-movefifoplc > 0) { +/* TRAVERSE_CONNECT(i) if (movefifoplc == g_player[i].movefifoend) break; - if (i >= 0) break; + if (i != ud.multimode) break; +*/ if (G_DoMoveThings()) return 1; } return 0; } -static void Net_CorrectPrediction(void) -{ - int32_t i; - DukePlayer_t *p; - - if (numplayers < 2) return; - - i = ((movefifoplc-1)&(MOVEFIFOSIZ-1)); - p = g_player[myconnectindex].ps; - - if (p->posx == myxbak[i] && p->posy == myybak[i] && p->posz == myzbak[i] - && p->horiz == myhorizbak[i] && p->ang == myangbak[i]) - return; - - Bmemcpy(&my, p, sizeof(vec3_t)); - Bmemcpy(&omy, &p->oposx, sizeof(vec3_t)); - Bmemcpy(&myvel, &p->posxv, sizeof(vec3_t)); - - myang = p->ang; - omyang = p->oang; - mycursectnum = p->cursectnum; - myhoriz = p->horiz; - omyhoriz = p->ohoriz; - myhorizoff = p->horizoff; - omyhorizoff = p->ohorizoff; - myjumpingcounter = p->jumping_counter; - myjumpingtoggle = p->jumping_toggle; - myonground = p->on_ground; - myhardlanding = p->hard_landing; - myreturntocenter = p->return_to_center; - - predictfifoplc = movefifoplc; - while (predictfifoplc < g_player[myconnectindex].movefifoend) - Net_DoPrediction(); -} - -static void Net_DoPrediction(void) -{ - input_t *syn; - DukePlayer_t *p; - int32_t i, j, k, doubvel, fz, cz, hz, lz, x, y; - uint32_t sb_snum; - int16_t psect, psectlotag, tempsect, backcstat; - char shrunk, spritebridge; - - syn = (input_t *)&inputfifo[predictfifoplc&(MOVEFIFOSIZ-1)][myconnectindex]; - - p = g_player[myconnectindex].ps; - - backcstat = sprite[p->i].cstat; - sprite[p->i].cstat &= ~257; - - sb_snum = syn->bits; - - psect = mycursectnum; - psectlotag = sector[psect].lotag; - spritebridge = 0; - - shrunk = (sprite[p->i].yrepeat < 32); - - if (ud.clipping == 0 && (sector[psect].floorpicnum == MIRROR || psect < 0 || psect >= MAXSECTORS)) - { - my.x = omy.x; - my.y = omy.y; - } - else - { - omy.x = my.x; - omy.y = my.y; - } - - omyhoriz = myhoriz; - omyhorizoff = myhorizoff; - omy.z = my.z; - omyang = myang; - - getzrange(&my,psect,&cz,&hz,&fz,&lz,163L,CLIPMASK0); - - j = getflorzofslope(psect,my.x,my.y); - - if ((lz&49152) == 16384 && psectlotag == 1 && klabs(my.z-j) > PHEIGHT+(16<<8)) - psectlotag = 0; - - if (p->aim_mode == 0 && myonground && psectlotag != 2 && (sector[psect].floorstat&2)) - { - x = my.x+(sintable[(myang+512)&2047]>>5); - y = my.y+(sintable[myang&2047]>>5); - tempsect = psect; - updatesector(x,y,&tempsect); - if (tempsect >= 0) - { - k = getflorzofslope(psect,x,y); - if (psect == tempsect) - myhorizoff += mulscale16(j-k,160); - else if (klabs(getflorzofslope(tempsect,x,y)-k) <= (4<<8)) - myhorizoff += mulscale16(j-k,160); - } - } - if (myhorizoff > 0) myhorizoff -= ((myhorizoff>>3)+1); - else if (myhorizoff < 0) myhorizoff += (((-myhorizoff)>>3)+1); - - if (hz >= 0 && (hz&49152) == 49152) - { - hz &= (MAXSPRITES-1); - if (sprite[hz].statnum == STAT_ACTOR && sprite[hz].extra >= 0) - { - hz = 0; - cz = getceilzofslope(psect,my.x,my.y); - } - } - - if (lz >= 0 && (lz&49152) == 49152) - { - j = lz&(MAXSPRITES-1); - if ((sprite[j].cstat&33) == 33 || (sprite[j].cstat&17) == 17) - { - psectlotag = 0; - spritebridge = 1; - } - if (A_CheckEnemySprite(&sprite[j]) && sprite[j].xrepeat > 24 && klabs(sprite[p->i].z-sprite[j].z) < (84<<8)) - { - j = getangle(sprite[j].x-my.x,sprite[j].y-my.y); - myvel.x -= sintable[(j+512)&2047]<<4; - myvel.y -= sintable[j&2047]<<4; - } - } - - if (sprite[p->i].extra <= 0) - { - if (psectlotag == 2) - { - if (p->on_warping_sector == 0) - { - if (klabs(my.z-fz) > (PHEIGHT>>1)) - my.z += 348; - } - clipmove(&my,&mycursectnum,0,0,164L,(4L<<8),(4L<<8),CLIPMASK0); - } - - updatesector(my.x,my.y,&mycursectnum); - pushmove(&my,&mycursectnum,128L,(4L<<8),(20L<<8),CLIPMASK0); - - myhoriz = 100; - myhorizoff = 0; - - goto ENDFAKEPROCESSINPUT; - } - - doubvel = TICSPERFRAME; - - if (p->on_crane >= 0) goto FAKEHORIZONLY; - - if (p->one_eighty_count < 0) myang += 128; - - i = 40; - - if (psectlotag == 2) - { - myjumpingcounter = 0; - - if (TEST_SYNC_KEY(sb_snum, SK_JUMP)) - { - if (myvel.z > 0) myvel.z = 0; - myvel.z -= 348; - if (myvel.z < -(256*6)) myvel.z = -(256*6); - } - else if (TEST_SYNC_KEY(sb_snum, SK_CROUCH)) - { - if (myvel.z < 0) myvel.z = 0; - myvel.z += 348; - if (myvel.z > (256*6)) myvel.z = (256*6); - } - else - { - if (myvel.z < 0) - { - myvel.z += 256; - if (myvel.z > 0) - myvel.z = 0; - } - if (myvel.z > 0) - { - myvel.z -= 256; - if (myvel.z < 0) - myvel.z = 0; - } - } - - if (myvel.z > 2048) myvel.z >>= 1; - - my.z += myvel.z; - - if (my.z > (fz-(15<<8))) - my.z += ((fz-(15<<8))-my.z)>>1; - - /* - if (my.z < (cz+(4<<8))) - { - my.z = cz+(4<<8); - myvel.z = 0; - } - */ - } - - else if (p->jetpack_on) - { - myonground = 0; - myjumpingcounter = 0; - myhardlanding = 0; - - if (p->jetpack_on < 11) - my.z -= (p->jetpack_on<<7); //Goin up - - if (shrunk) j = 512; - else j = 2048; - - if (TEST_SYNC_KEY(sb_snum, SK_JUMP)) //A - my.z -= j; - if (TEST_SYNC_KEY(sb_snum, SK_CROUCH)) //Z - my.z += j; - - if (shrunk == 0 && (psectlotag == 0 || psectlotag == 2)) k = 32; - else k = 16; - - if (my.z > (fz-(k<<8))) - my.z += ((fz-(k<<8))-my.z)>>1; - if (my.z < (cz+(18<<8))) - my.z = cz+(18<<8); - } - else if (psectlotag != 2) - { - if (psectlotag == 1 && p->spritebridge == 0) - { - if (shrunk == 0) i = 34; - else i = 12; - } - if (my.z < (fz-(i<<8)) && (G_CheckForSpaceFloor(psect)|G_CheckForSpaceCeiling(psect)) == 0) //falling - { - if (!TEST_SYNC_KEY(sb_snum, SK_JUMP) && !TEST_SYNC_KEY(sb_snum, SK_CROUCH) && - myonground && (sector[psect].floorstat&2) && my.z >= (fz-(i<<8)-(16<<8))) - my.z = fz-(i<<8); - else - { - myonground = 0; - - myvel.z += (g_spriteGravity+80); - - if (myvel.z >= (4096+2048)) myvel.z = (4096+2048); - } - } - - else - { - if (psectlotag != 1 && psectlotag != 2 && myonground == 0 && myvel.z > (6144>>1)) - myhardlanding = myvel.z>>10; - myonground = 1; - - if (i==40) - { - //Smooth on the ground - - k = ((fz-(i<<8))-my.z)>>1; - if (klabs(k) < 256) k = 0; - my.z += k; // ((fz-(i<<8))-my.z)>>1; - myvel.z -= 768; // 412; - if (myvel.z < 0) myvel.z = 0; - } - else if (myjumpingcounter == 0) - { - my.z += ((fz-(i<<7))-my.z)>>1; //Smooth on the water - if (p->on_warping_sector == 0 && my.z > fz-(16<<8)) - { - my.z = fz-(16<<8); - myvel.z >>= 1; - } - } - - if (TEST_SYNC_KEY(sb_snum, SK_CROUCH)) - my.z += (2048+768); - - if (TEST_SYNC_KEY(sb_snum, SK_JUMP) == 0 && myjumpingtoggle == 1) - myjumpingtoggle = 0; - - else if (TEST_SYNC_KEY(sb_snum, SK_JUMP) && myjumpingtoggle == 0) - { - if (myjumpingcounter == 0) - if ((fz-cz) > (56<<8)) - { - myjumpingcounter = 1; - myjumpingtoggle = 1; - } - } - if (myjumpingcounter && TEST_SYNC_KEY(sb_snum, SK_JUMP) == 0) - myjumpingcounter = 0; - } - - if (myjumpingcounter) - { - if (TEST_SYNC_KEY(sb_snum, SK_JUMP) == 0 && myjumpingtoggle == 1) - myjumpingtoggle = 0; - - if (myjumpingcounter < (1024+256)) - { - if (psectlotag == 1 && myjumpingcounter > 768) - { - myjumpingcounter = 0; - myvel.z = -512; - } - else - { - myvel.z -= (sintable[(2048-128+myjumpingcounter)&2047])/12; - myjumpingcounter += 180; - - myonground = 0; - } - } - else - { - myjumpingcounter = 0; - myvel.z = 0; - } - } - - my.z += myvel.z; - - if (my.z < (cz+(4<<8))) - { - myjumpingcounter = 0; - if (myvel.z < 0) myvel.x = myvel.y = 0; - myvel.z = 128; - my.z = cz+(4<<8); - } - } - - if (p->fist_incs || - p->transporter_hold > 2 || - myhardlanding || - p->access_incs > 0 || - p->knee_incs > 0 || - (p->curr_weapon == TRIPBOMB_WEAPON && - p->kickback_pic > 1 && - p->kickback_pic < 4)) - { - doubvel = 0; - myvel.x = 0; - myvel.y = 0; - } - else if (syn->avel) //p->ang += syncangvel * constant - { - //ENGINE calculates angvel for you - int32_t tempang = syn->avel<<1; - - if (psectlotag == 2) - myang += (tempang-(tempang>>3))*ksgn(doubvel); - else myang += (tempang)*ksgn(doubvel); - myang &= 2047; - } - - if (myvel.x || myvel.y || syn->fvel || syn->svel) - { - if (p->jetpack_on == 0 && p->steroids_amount > 0 && p->steroids_amount < 400) - doubvel <<= 1; - - myvel.x += ((syn->fvel*doubvel)<<6); - myvel.y += ((syn->svel*doubvel)<<6); - - if ((p->curr_weapon == KNEE_WEAPON && p->kickback_pic > 10 && myonground) || (myonground && TEST_SYNC_KEY(sb_snum, SK_CROUCH))) - { - myvel.x = mulscale16(myvel.x,p->runspeed-0x2000); - myvel.y = mulscale16(myvel.y,p->runspeed-0x2000); - } - else - { - if (psectlotag == 2) - { - myvel.x = mulscale16(myvel.x,p->runspeed-0x1400); - myvel.y = mulscale16(myvel.y,p->runspeed-0x1400); - } - else - { - myvel.x = mulscale16(myvel.x,p->runspeed); - myvel.y = mulscale16(myvel.y,p->runspeed); - } - } - - if (klabs(myvel.x) < 2048 && klabs(myvel.y) < 2048) - myvel.x = myvel.y = 0; - - if (shrunk) - { - myvel.x = - mulscale16(myvel.x,(p->runspeed)-(p->runspeed>>1)+(p->runspeed>>2)); - myvel.y = - mulscale16(myvel.y,(p->runspeed)-(p->runspeed>>1)+(p->runspeed>>2)); - } - } - -FAKEHORIZONLY: - if (psectlotag == 1 || spritebridge == 1) i = (4L<<8); - else i = (20L<<8); - - clipmove(&my,&mycursectnum,myvel.x,myvel.y,164L,4L<<8,i,CLIPMASK0); - pushmove(&my,&mycursectnum,164L,4L<<8,4L<<8,CLIPMASK0); - - if (p->jetpack_on == 0 && psectlotag != 1 && psectlotag != 2 && shrunk) - my.z += 30<<8; - - if (TEST_SYNC_KEY(sb_snum, SK_CENTER_VIEW) || myhardlanding) - myreturntocenter = 9; - - if (TEST_SYNC_KEY(sb_snum, SK_LOOK_UP)) - { - myreturntocenter = 9; - if (TEST_SYNC_KEY(sb_snum, SK_RUN)) myhoriz += 6; - myhoriz += 6; - } - else if (TEST_SYNC_KEY(sb_snum, SK_LOOK_DOWN)) - { - myreturntocenter = 9; - if (TEST_SYNC_KEY(sb_snum, SK_RUN)) myhoriz -= 6; - myhoriz -= 6; - } - else if (TEST_SYNC_KEY(sb_snum, SK_AIM_UP)) - { - if (TEST_SYNC_KEY(sb_snum, SK_RUN)) myhoriz += 6; - myhoriz += 6; - } - else if (TEST_SYNC_KEY(sb_snum, SK_AIM_DOWN)) - { - if (TEST_SYNC_KEY(sb_snum, SK_RUN)) myhoriz -= 6; - myhoriz -= 6; - } - - if (myreturntocenter > 0) - if (TEST_SYNC_KEY(sb_snum, SK_LOOK_UP) == 0 && TEST_SYNC_KEY(sb_snum, SK_LOOK_DOWN) == 0) - { - myreturntocenter--; - myhoriz += 33-(myhoriz/3); - } - - if (p->aim_mode) - myhoriz += syn->horz; - else - { - if (myhoriz > 95 && myhoriz < 105) myhoriz = 100; - if (myhorizoff > -5 && myhorizoff < 5) myhorizoff = 0; - } - - if (myhardlanding > 0) - { - myhardlanding--; - myhoriz -= (myhardlanding<<4); - } - - if (myhoriz > HORIZ_MAX) myhoriz = HORIZ_MAX; - else if (myhoriz < HORIZ_MIN) myhoriz = HORIZ_MIN; - - if (p->knee_incs > 0) - { - myhoriz -= 48; - myreturntocenter = 9; - } - -ENDFAKEPROCESSINPUT: - - if (apScriptGameEvent[EVENT_FAKEDOMOVETHINGS]) - X_OnEvent(EVENT_FAKEDOMOVETHINGS, g_player[myconnectindex].ps->i, myconnectindex, -1); - - myxbak[predictfifoplc&(MOVEFIFOSIZ-1)] = my.x; - myybak[predictfifoplc&(MOVEFIFOSIZ-1)] = my.y; - myzbak[predictfifoplc&(MOVEFIFOSIZ-1)] = my.z; - myangbak[predictfifoplc&(MOVEFIFOSIZ-1)] = myang; - myhorizbak[predictfifoplc&(MOVEFIFOSIZ-1)] = myhoriz; - predictfifoplc++; - - sprite[p->i].cstat = backcstat; -} - static int32_t G_DoMoveThings(void) { int32_t i, j; @@ -12368,8 +12192,12 @@ static int32_t G_DoMoveThings(void) everyothertime++; + if (net_server || net_client) + randomseed = ticrandomseed; + TRAVERSE_CONNECT(i) - copybufbyte(&inputfifo[movefifoplc&(MOVEFIFOSIZ-1)][i],g_player[i].sync,sizeof(input_t)); + copybufbyte(&inputfifo[(net_server && myconnectindex == i) ? 1 : 0][i],g_player[i].sync,sizeof(input_t)); + movefifoplc++; G_UpdateInterpolations(); @@ -12377,7 +12205,7 @@ static int32_t G_DoMoveThings(void) j = -1; TRAVERSE_CONNECT(i) { - if (TEST_SYNC_KEY(g_player[i].sync->bits,SK_GAMEQUIT) == 0) + if (g_player[i].playerquitflag == 0 || TEST_SYNC_KEY(g_player[i].sync->bits,SK_GAMEQUIT) == 0) { j = i; continue; @@ -12385,20 +12213,15 @@ static int32_t G_DoMoveThings(void) G_CloseDemoWrite(); - if (i == myconnectindex) G_GameExit(" "); + g_player[i].playerquitflag = 0; + if (screenpeek == i) { - screenpeek = connectpoint2[i]; - if (screenpeek < 0) screenpeek = connecthead; + screenpeek = 0; + if (screenpeek < 0) screenpeek = 0; } - if (i == connecthead) connecthead = connectpoint2[connecthead]; - else connectpoint2[j] = connectpoint2[i]; - - numplayers--; - ud.multimode--; - - if (numplayers < 2) + if (numplayers == 2) S_PlaySound(GENERIC_AMBIENCE17); pub = NUMPAGES; @@ -12409,6 +12232,7 @@ static int32_t G_DoMoveThings(void) deletesprite(g_player[i].ps->i); Bsprintf(buf,"%s^00 is history!",g_player[i].user_name); + G_AddUserQuote(buf); Bstrcpy(ScriptQuotes[116],buf); @@ -12423,22 +12247,7 @@ static int32_t G_DoMoveThings(void) } g_player[myconnectindex].ps->ftq = 116, g_player[myconnectindex].ps->fta = 180; - - if (j < 0 && g_networkBroadcastMode == 0) - G_GameExit("Server terminated"); } - /* - if ((numplayers >= 2) && ((movefifoplc&7) == 7)) - { - ch = (uint8_t)(randomseed&255); - for (i=connecthead;i>=0;i=connectpoint2[i]) - ch += ((g_player[i].ps->posx+g_player[i].ps->posy+g_player[i].ps->posz+g_player[i].ps->ang+g_player[i].ps->horiz)&255); - g_player[myconnectindex].syncval[g_player[myconnectindex].syncvalhead&(MOVEFIFOSIZ-1)] = ch; - g_player[myconnectindex].syncvalhead++; - } - */ - - Net_GetSyncStat(); g_moveThingsCount++; @@ -12484,7 +12293,7 @@ static int32_t G_DoMoveThings(void) if (ud.pause_on == 0) G_MoveWorld(); - Net_CorrectPrediction(); +// Net_CorrectPrediction(); if ((everyothertime&1) == 0) { @@ -12669,7 +12478,7 @@ void G_BonusScreen(int32_t bonusonly) rotatesprite(0,0,65536L,0,3292,0,0,2+8+16+64, 0,0,xdim-1,ydim-1); IFISSOFTMODE fadepal(0,0,0, 63,0,-1); else nextpage(); - while (!KB_KeyWaiting() && !MOUSE_GetButtons()&LEFT_MOUSE) + while (!KB_KeyWaiting() && !MOUSE_GetButtons()&LEFT_MOUSE && !BUTTON(gamefunc_Fire) && !BUTTON(gamefunc_Open)) { handleevents(); Net_GetPackets(); @@ -12702,7 +12511,7 @@ void G_BonusScreen(int32_t bonusonly) rotatesprite(0,0,65536L,0,3293,0,0,2+8+16+64, 0,0,xdim-1,ydim-1); IFISSOFTMODE fadepal(0,0,0, 63,0,-1); else nextpage(); - while (!KB_KeyWaiting() && !MOUSE_GetButtons()&LEFT_MOUSE) + while (!KB_KeyWaiting() && !MOUSE_GetButtons()&LEFT_MOUSE && !BUTTON(gamefunc_Fire) && !BUTTON(gamefunc_Open)) { handleevents(); Net_GetPackets(); @@ -12751,7 +12560,7 @@ void G_BonusScreen(int32_t bonusonly) fadepal(0,0,0, 63,0,-3); KB_FlushKeyboardQueue(); - while (!KB_KeyWaiting() && !MOUSE_GetButtons()&LEFT_MOUSE) + while (!KB_KeyWaiting() && !MOUSE_GetButtons()&LEFT_MOUSE && !BUTTON(gamefunc_Fire) && !BUTTON(gamefunc_Open)) { handleevents(); Net_GetPackets(); @@ -12765,7 +12574,7 @@ void G_BonusScreen(int32_t bonusonly) G_PlayAnim("DUKETEAM.ANM",4); KB_FlushKeyBoardQueue(); - while (!KB_KeyWaiting() && !MOUSE_GetButtons()&LEFT_MOUSE) + while (!KB_KeyWaiting() && !MOUSE_GetButtons()&LEFT_MOUSE && !BUTTON(gamefunc_Fire) && !BUTTON(gamefunc_Open)) { handleevents(); Net_GetPackets(); @@ -12807,7 +12616,7 @@ void G_BonusScreen(int32_t bonusonly) G_PlayAnim("RADLOGO.ANM",3); - if (ud.lockout == 0 && !KB_KeyWaiting() && !MOUSE_GetButtons()&LEFT_MOUSE) + if (ud.lockout == 0 && !KB_KeyWaiting() && !MOUSE_GetButtons()&LEFT_MOUSE && !BUTTON(gamefunc_Fire) && !BUTTON(gamefunc_Open)) { S_PlaySound(ENDSEQVOL3SND5); while (S_CheckSoundPlaying(-1,ENDSEQVOL3SND5)) @@ -12815,28 +12624,28 @@ void G_BonusScreen(int32_t bonusonly) handleevents(); Net_GetPackets(); } - if (KB_KeyWaiting() || MOUSE_GetButtons()&LEFT_MOUSE) goto ENDANM; + if (KB_KeyWaiting() || MOUSE_GetButtons()&LEFT_MOUSE || BUTTON(gamefunc_Fire) || BUTTON(gamefunc_Open)) goto ENDANM; S_PlaySound(ENDSEQVOL3SND6); while (S_CheckSoundPlaying(-1,ENDSEQVOL3SND6)) { handleevents(); Net_GetPackets(); } - if (KB_KeyWaiting() || MOUSE_GetButtons()&LEFT_MOUSE) goto ENDANM; + if (KB_KeyWaiting() || MOUSE_GetButtons()&LEFT_MOUSE || BUTTON(gamefunc_Fire) || BUTTON(gamefunc_Open)) goto ENDANM; S_PlaySound(ENDSEQVOL3SND7); while (S_CheckSoundPlaying(-1,ENDSEQVOL3SND7)) { handleevents(); Net_GetPackets(); } - if (KB_KeyWaiting() || MOUSE_GetButtons()&LEFT_MOUSE) goto ENDANM; + if (KB_KeyWaiting() || MOUSE_GetButtons()&LEFT_MOUSE || BUTTON(gamefunc_Fire) || BUTTON(gamefunc_Open)) goto ENDANM; S_PlaySound(ENDSEQVOL3SND8); while (S_CheckSoundPlaying(-1,ENDSEQVOL3SND8)) { handleevents(); Net_GetPackets(); } - if (KB_KeyWaiting() || MOUSE_GetButtons()&LEFT_MOUSE) goto ENDANM; + if (KB_KeyWaiting() || MOUSE_GetButtons()&LEFT_MOUSE || BUTTON(gamefunc_Fire) || BUTTON(gamefunc_Open)) goto ENDANM; S_PlaySound(ENDSEQVOL3SND9); while (S_CheckSoundPlaying(-1,ENDSEQVOL3SND9)) { @@ -12848,7 +12657,7 @@ void G_BonusScreen(int32_t bonusonly) MOUSE_ClearButton(LEFT_MOUSE); KB_FlushKeyBoardQueue(); totalclock = 0; - while (!KB_KeyWaiting() && totalclock < 120 && !MOUSE_GetButtons()&LEFT_MOUSE) + while (!KB_KeyWaiting() && totalclock < 120 && !MOUSE_GetButtons()&LEFT_MOUSE && !BUTTON(gamefunc_Fire) && !BUTTON(gamefunc_Open)) { handleevents(); Net_GetPackets(); @@ -12892,7 +12701,7 @@ FRAGBONUS: gametext(160,58+2,"MULTIPLAYER TOTALS",0,2+8+16); gametext(160,58+10,MapInfo[(ud.volume_number*MAXLEVELS)+ud.last_level-1].name,0,2+8+16); - gametext(160,165,"PRESS ANY KEY TO CONTINUE",0,2+8+16); + gametext(160,165,"PRESS ANY KEY OR BUTTON TO CONTINUE",quotepulseshade,2+8+16); t = 0; minitext(23,80," NAME KILLS",8,2+8+16+128); @@ -12925,7 +12734,7 @@ FRAGBONUS: xfragtotal += g_player[i].frags[y]; } - if (myconnectindex == connecthead) + if (net_server) { Bsprintf(tempbuf,"stats %d killed %d %d\n",i+1,y+1,g_player[i].frags[y]); sendscore(tempbuf); @@ -12991,7 +12800,7 @@ FRAGBONUS: menutext(160,20-6,0,0,lastmapname); menutext(160,36-6,0,0,"COMPLETED"); - gametext(160,192,"PRESS ANY KEY TO CONTINUE",16,2+8+16); + gametext(160,192,"PRESS ANY KEY OR BUTTON TO CONTINUE",quotepulseshade,2+8+16); if (!(ud.config.MusicToggle == 0 || ud.config.MusicDevice < 0)) S_PlaySound(BONUSMUSIC); @@ -13097,7 +12906,7 @@ FRAGBONUS: menutext(160,20-6,0,0,lastmapname); menutext(160,36-6,0,0,"COMPLETED"); - gametext(160,192,"PRESS ANY KEY TO CONTINUE",16,2+8+16); + gametext(160,192,"PRESS ANY KEY OR BUTTON TO CONTINUE",quotepulseshade,2+8+16); if (totalclock > (60*3)) { @@ -13248,7 +13057,7 @@ FRAGBONUS: if (totalclock > 10240 && totalclock < 10240+10240) totalclock = 1024; - if (((MOUSE_GetButtons()&7) || KB_KeyWaiting()) && totalclock > (60*2)) // JBF 20030809 + if (((MOUSE_GetButtons()&7) || KB_KeyWaiting() || BUTTON(gamefunc_Fire) || BUTTON(gamefunc_Open)) && totalclock > (60*2)) // JBF 20030809 { MOUSE_ClearButton(7); if (totalclock < (60*13)) diff --git a/polymer/eduke32/source/gamedef.c b/polymer/eduke32/source/gamedef.c index 893fd703f..8863c239e 100644 --- a/polymer/eduke32/source/gamedef.c +++ b/polymer/eduke32/source/gamedef.c @@ -5358,8 +5358,6 @@ repeatcase: else if ((Bstrlen(tempbuf)+1) > sizeof(MapInfo[j*MAXLEVELS+k].filename)) MapInfo[j*MAXLEVELS+k].filename = Brealloc(MapInfo[j*MAXLEVELS+k].filename,(Bstrlen(tempbuf)+1)); - /* initprintf("level file name string len: %d\n",Bstrlen(tempbuf)); */ - Bstrcpy(MapInfo[j*MAXLEVELS+k].filename,tempbuf); C_SkipComments(); @@ -5581,19 +5579,15 @@ repeatcase: C_GetNextValue(LABEL_DEFINE); g_sounds[k].ps = *(g_scriptPtr-1); - g_scriptPtr--; C_GetNextValue(LABEL_DEFINE); g_sounds[k].pe = *(g_scriptPtr-1); - g_scriptPtr--; C_GetNextValue(LABEL_DEFINE); g_sounds[k].pr = *(g_scriptPtr-1); - g_scriptPtr--; C_GetNextValue(LABEL_DEFINE); g_sounds[k].m = *(g_scriptPtr-1); - g_scriptPtr--; C_GetNextValue(LABEL_DEFINE); g_sounds[k].vo = *(g_scriptPtr-1); - g_scriptPtr--; + g_scriptPtr -= 5; if (k > g_maxSoundPos) g_maxSoundPos = k; @@ -5627,8 +5621,7 @@ repeatcase: *(g_scriptPtr++) = CON_ENDEVENT; previous_event = NULL; } - g_parsingEventPtr = 0; - g_parsingActorPtr = 0; + g_parsingEventPtr = g_parsingActorPtr = 0; g_currentEvent = -1; Bsprintf(g_szCurrentBlockName,"(none)"); return 0; diff --git a/polymer/eduke32/source/gamedefs.h b/polymer/eduke32/source/gamedefs.h index 70cdf7b41..f818e2e87 100644 --- a/polymer/eduke32/source/gamedefs.h +++ b/polymer/eduke32/source/gamedefs.h @@ -105,10 +105,6 @@ extern "C" { #define MAXJOYAXES 8 -// Number of GAMEPAD axes - -#define MAXGAMEPADAXES 2 - // MIN/MAX scale value for controller scales #define MAXCONTROLSCALEVALUE (1<<19) diff --git a/polymer/eduke32/source/gameexec.c b/polymer/eduke32/source/gameexec.c index 723d5bbd7..7079f6bcd 100644 --- a/polymer/eduke32/source/gameexec.c +++ b/polymer/eduke32/source/gameexec.c @@ -39,6 +39,7 @@ vmstate_t vm; int32_t g_errorLineNum; int32_t g_tw; +extern int32_t ticrandomseed; static int32_t X_DoExecute(int32_t once); @@ -1824,7 +1825,7 @@ nullquote: ud.m_volume_number = ud.volume_number = volnume; ud.m_level_number = ud.level_number = levnume; - if (numplayers > 1 && myconnectindex == connecthead) + if (numplayers > 1 && net_server) Net_NewGame(volnume,levnume); else { @@ -2712,7 +2713,7 @@ nullquote: g_lastSaveSlot = *insptr++; - if ((g_movesPerPacket == 4 && connecthead != myconnectindex) || g_lastSaveSlot > 9) + if (g_lastSaveSlot > 9) continue; if ((tw == CON_SAVE) || !(ud.savegame[g_lastSaveSlot][0])) { @@ -4703,6 +4704,9 @@ void A_Execute(int32_t iActor,int32_t iPlayer,int32_t lDist) // if (actorscrptr[sprite[iActor].picnum] == 0) return; + if (net_server || net_client) + randomseed = ticrandomseed; + vm.g_i = iActor; // Sprite ID vm.g_p = iPlayer; // Player ID vm.g_x = lDist; // ? @@ -4996,9 +5000,15 @@ void G_RestoreMapState(mapstate_t *save) { if (aGameVars[i].dwFlags & GAMEVAR_NORESET) continue; if (aGameVars[i].dwFlags & GAMEVAR_PERPLAYER) + { + if (!save->vars[i]) continue; Bmemcpy(&aGameVars[i].val.plValues[0],&save->vars[i][0],sizeof(intptr_t) * MAXPLAYERS); + } else if (aGameVars[i].dwFlags & GAMEVAR_PERACTOR) + { + if (!save->vars[i]) continue; Bmemcpy(&aGameVars[i].val.plValues[0],&save->vars[i][0],sizeof(intptr_t) * MAXSPRITES); + } else aGameVars[i].val.lValue = (intptr_t)save->vars[i]; } @@ -5082,7 +5092,6 @@ void G_RestoreMapState(mapstate_t *save) Net_ResetPrediction(); Net_WaitForEverybody(); - mmulti_flushpackets(); clearfifo(); G_ResetTimers(); } diff --git a/polymer/eduke32/source/global.c b/polymer/eduke32/source/global.c index cb6f3bcef..ef29d02ff 100644 --- a/polymer/eduke32/source/global.c +++ b/polymer/eduke32/source/global.c @@ -49,7 +49,7 @@ int16_t cyclers[MAXCYCLERS][6],g_numCyclers; char *ScriptQuotes[MAXQUOTES], *ScriptQuoteRedefinitions[MAXQUOTES]; -char tempbuf[2048], packbuf[576], menutextbuf[128], buf[1024]; +char tempbuf[2048], packbuf[4096], menutextbuf[128], buf[1024]; int16_t camsprite; int16_t g_mirrorWall[64], g_mirrorSector[64], g_mirrorCount; @@ -163,7 +163,7 @@ int32_t myhorizbak[MOVEFIFOSIZ],g_playerFriction = 0xcc00, g_showShareware; int16_t myangbak[MOVEFIFOSIZ]; char szPlayerName[32]; int32_t g_damageCameras,g_freezerSelfDamage=0,g_tripbombLaserMode=0; -int32_t g_networkBroadcastMode = 255, g_movesPerPacket = 1,g_gameQuit = 0,everyothertime; +int32_t g_gameQuit = 0,everyothertime; int32_t g_numFreezeBounces=3,g_rpgBlastRadius,g_pipebombBlastRadius,g_tripbombBlastRadius, g_shrinkerBlastRadius,g_morterBlastRadius,g_bouncemineBlastRadius,g_seenineBlastRadius; DukeStatus_t sbar; @@ -185,7 +185,6 @@ projectile_t ProjectileData[MAXTILES], DefaultProjectileData[MAXTILES], SpritePr char CheatKeys[2] = { sc_D, sc_N }; char setupfilename[BMAX_PATH]= SETUPFILENAME; -// char datetimestring[] = ""__DATE__" "__TIME__""; int32_t g_doQuickSave = 0; uint32_t g_moveThingsCount = 0; diff --git a/polymer/eduke32/source/jaudiolib/src/driver_directsound.c b/polymer/eduke32/source/jaudiolib/src/driver_directsound.c index ae02367f5..4e65880ea 100644 --- a/polymer/eduke32/source/jaudiolib/src/driver_directsound.c +++ b/polymer/eduke32/source/jaudiolib/src/driver_directsound.c @@ -318,7 +318,10 @@ int32_t DirectSoundDrv_PCM_Init(int32_t *mixrate, int32_t *numchannels, int32_t memset(&bufdesc, 0, sizeof(DSBUFFERDESC)); bufdesc.dwSize = sizeof(DSBUFFERDESC); - bufdesc.dwFlags = DSBCAPS_PRIMARYBUFFER; + bufdesc.dwFlags = DSBCAPS_LOCSOFTWARE | + DSBCAPS_PRIMARYBUFFER | + DSBCAPS_GETCURRENTPOSITION2 | + DSBCAPS_STICKYFOCUS ; err = IDirectSound_CreateSoundBuffer(lpds, &bufdesc, &lpdsbprimary, 0); if (FAILED( err )) { @@ -344,8 +347,9 @@ int32_t DirectSoundDrv_PCM_Init(int32_t *mixrate, int32_t *numchannels, int32_t bufdesc.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_CTRLPOSITIONNOTIFY | - DSBCAPS_GETCURRENTPOSITION2; - bufdesc.dwBufferBytes = wfex.nBlockAlign * 2048 * 2; + DSBCAPS_GETCURRENTPOSITION2 | + DSBCAPS_STICKYFOCUS ; + bufdesc.dwBufferBytes = wfex.nBlockAlign * 2560 * 2; bufdesc.lpwfxFormat = &wfex; err = IDirectSound_CreateSoundBuffer(lpds, &bufdesc, &lpdsbsec, 0); diff --git a/polymer/eduke32/source/jaudiolib/src/multivoc.c b/polymer/eduke32/source/jaudiolib/src/multivoc.c index 9232964fa..bcd02a346 100644 --- a/polymer/eduke32/source/jaudiolib/src/multivoc.c +++ b/polymer/eduke32/source/jaudiolib/src/multivoc.c @@ -159,22 +159,18 @@ uint32_t MV_MixPosition; int32_t MV_ErrorCode = MV_Ok; static int32_t lockdepth = 0; -static int32_t DisableInterrupts(void) +static void DisableInterrupts(void) { if (lockdepth++ > 0) - { - return 0; - } + return; SoundDriver_Lock(); - return 0; + return; } -static void RestoreInterrupts(int32_t a) +static void RestoreInterrupts(void) { if (--lockdepth > 0) - { return; - } SoundDriver_Unlock(); } @@ -361,12 +357,11 @@ void MV_PlayVoice ) { - int32_t flags; - flags = DisableInterrupts(); + DisableInterrupts(); LL_SortedInsertion(&VoiceList, voice, prev, next, VoiceNode, priority); - RestoreInterrupts(flags); + RestoreInterrupts(); } @@ -382,15 +377,13 @@ void MV_StopVoice ) { - int32_t flags; - - flags = DisableInterrupts(); + DisableInterrupts(); // move the voice from the play list to the free list LL_Remove(voice, next, prev); LL_Add((VoiceNode*) &VoicePool, voice, next, prev); - RestoreInterrupts(flags); + RestoreInterrupts(); if (voice->wavetype == Vorbis) { @@ -501,49 +494,47 @@ void MV_ServiceVoc } // Play any waiting voices - //flags = DisableInterrupts(); + //DisableInterrupts(); - if (!VoiceList.next) + if (!VoiceList.next || (voice = VoiceList.next) == &VoiceList) return; - for (voice = VoiceList.next; voice != &VoiceList; voice = next) + do { - if ( voice->Paused ) - { - next = voice->next; + next = voice->next; + + if (voice->Paused) continue; - } MV_BufferEmpty[ MV_MixPage ] = FALSE; -// if (!voice->Paused) - MV_MixFunction(voice, MV_MixPage); - - next = voice->next; + MV_MixFunction(voice, MV_MixPage); // Is this voice done? - if (!voice->Playing/* && !voice->Paused*/) + if (!voice->Playing) { //JBF: prevent a deadlock caused by MV_StopVoice grabbing the mutex again //MV_StopVoice( voice ); LL_Remove(voice, next, prev); LL_Add((VoiceNode*) &VoicePool, voice, next, prev); + if (voice->wavetype == Vorbis) + MV_ReleaseVorbisVoice(voice); + if (MV_CallBackFunc) - { MV_CallBackFunc(voice->callbackval); - } } } + while ((voice = next) != &VoiceList); - //RestoreInterrupts(flags); + //RestoreInterrupts(); } /*--------------------------------------------------------------------- Function: MV_GetNextVOCBlock - Interperate the information of a VOC format sound file. + Interpret the information of a VOC format sound file. ---------------------------------------------------------------------*/ playbackstatus MV_GetNextVOCBlock @@ -585,7 +576,8 @@ playbackstatus MV_GetNextVOCBlock packtype = 0; done = FALSE; - while (!done) + + do { // Stop playing if we get a NULL pointer if (ptr == NULL) @@ -753,6 +745,7 @@ playbackstatus MV_GetNextVOCBlock lastblocktype = blocktype; } + while (!done); if (voice->Playing) { @@ -963,9 +956,8 @@ VoiceNode *MV_GetVoice { VoiceNode *voice; - int32_t flags; - flags = DisableInterrupts(); + DisableInterrupts(); for (voice = VoiceList.next; voice != &VoiceList; voice = voice->next) { @@ -975,7 +967,7 @@ VoiceNode *MV_GetVoice } } - RestoreInterrupts(flags); + RestoreInterrupts(); if (voice == &VoiceList) { @@ -1031,8 +1023,7 @@ int32_t MV_KillAllVoices ) { - VoiceNode * voice, * next; - int32_t flags; + VoiceNode * voice = VoiceList.prev; if (!MV_Installed) { @@ -1040,19 +1031,25 @@ int32_t MV_KillAllVoices return(MV_Error); } - flags = DisableInterrupts(); + if (&VoiceList == VoiceList.next) + return(MV_Ok); + + DisableInterrupts(); // Remove all the voices from the list - for (voice = VoiceList.next; voice != &VoiceList; voice = next) + while (voice != &VoiceList) { - next = voice->next; - if (voice->priority < MV_MUSIC_PRIORITY) + if (voice->priority == MV_MUSIC_PRIORITY) { - MV_Kill(voice->handle); + voice = voice->prev; + continue; } + + MV_Kill(voice->handle); + voice = VoiceList.prev; } - RestoreInterrupts(flags); + RestoreInterrupts(); return(MV_Ok); } @@ -1071,7 +1068,6 @@ int32_t MV_Kill { VoiceNode *voice; - int32_t flags; uint32_t callbackval; if (!MV_Installed) @@ -1080,12 +1076,12 @@ int32_t MV_Kill return(MV_Error); } - flags = DisableInterrupts(); + DisableInterrupts(); voice = MV_GetVoice(handle); if (voice == NULL) { - RestoreInterrupts(flags); + RestoreInterrupts(); MV_SetErrorCode(MV_VoiceNotFound); return(MV_Error); } @@ -1094,7 +1090,7 @@ int32_t MV_Kill MV_StopVoice(voice); - RestoreInterrupts(flags); + RestoreInterrupts(); if (MV_CallBackFunc) { @@ -1119,7 +1115,6 @@ int32_t MV_VoicesPlaying { VoiceNode *voice; int32_t NumVoices = 0; - int32_t flags; if (!MV_Installed) { @@ -1127,14 +1122,14 @@ int32_t MV_VoicesPlaying return(0); } - flags = DisableInterrupts(); + DisableInterrupts(); for (voice = VoiceList.next; voice != &VoiceList; voice = voice->next) { NumVoices++; } - RestoreInterrupts(flags); + RestoreInterrupts(); return(NumVoices); } @@ -1154,15 +1149,13 @@ VoiceNode *MV_AllocVoice { VoiceNode *voice; VoiceNode *node; - int32_t flags; -//return( NULL ); if (MV_Recording) { return(NULL); } - flags = DisableInterrupts(); + DisableInterrupts(); // Check if we have any free voices if (LL_Empty(&VoicePool, next, prev)) @@ -1187,13 +1180,13 @@ VoiceNode *MV_AllocVoice if (LL_Empty(&VoicePool, next, prev)) { // No free voices - RestoreInterrupts(flags); + RestoreInterrupts(); return(NULL); } voice = VoicePool.next; LL_Remove(voice, next, prev); - RestoreInterrupts(flags); + RestoreInterrupts(); // Find a free voice handle do @@ -1226,7 +1219,6 @@ int32_t MV_VoiceAvailable { VoiceNode *voice; VoiceNode *node; - int32_t flags; // Check if we have any free voices if (!LL_Empty(&VoicePool, next, prev)) @@ -1234,7 +1226,7 @@ int32_t MV_VoiceAvailable return(TRUE); } - flags = DisableInterrupts(); + DisableInterrupts(); // check if we have a higher priority than a voice that is playing. voice = VoiceList.next; @@ -1246,7 +1238,7 @@ int32_t MV_VoiceAvailable } } - RestoreInterrupts(flags); + RestoreInterrupts(); if ((voice != &VoiceList) && (priority >= voice->priority)) { @@ -1411,7 +1403,7 @@ void MV_SetVoiceMixMode //int32_t flags; int32_t test; - //flags = DisableInterrupts(); + //DisableInterrupts(); test = T_DEFAULT; if (MV_Bits == 8) @@ -1608,7 +1600,6 @@ int32_t MV_PauseVoice { VoiceNode *voice; - int32_t flags; if (!MV_Installed) { @@ -1616,19 +1607,19 @@ int32_t MV_PauseVoice return(MV_Error); } - flags = DisableInterrupts(); + DisableInterrupts(); voice = MV_GetVoice(handle); if (voice == NULL) { - RestoreInterrupts(flags); + RestoreInterrupts(); MV_SetErrorCode(MV_VoiceNotFound); return(MV_Warning); } voice->Paused = pause; - RestoreInterrupts(flags); + RestoreInterrupts(); return(MV_Ok); } @@ -1648,7 +1639,6 @@ int32_t MV_EndLooping { VoiceNode *voice; - int32_t flags; if (!MV_Installed) { @@ -1656,12 +1646,12 @@ int32_t MV_EndLooping return(MV_Error); } - flags = DisableInterrupts(); + DisableInterrupts(); voice = MV_GetVoice(handle); if (voice == NULL) { - RestoreInterrupts(flags); + RestoreInterrupts(); MV_SetErrorCode(MV_VoiceNotFound); return(MV_Warning); } @@ -1670,7 +1660,7 @@ int32_t MV_EndLooping voice->LoopStart = NULL; voice->LoopEnd = NULL; - RestoreInterrupts(flags); + RestoreInterrupts(); return(MV_Ok); } @@ -1974,13 +1964,12 @@ void MV_StopPlayback { VoiceNode *voice; VoiceNode *next; - int32_t flags; // Stop sound playback SoundDriver_StopPlayback(); // Make sure all callbacks are done. - flags = DisableInterrupts(); + DisableInterrupts(); for (voice = VoiceList.next; voice != &VoiceList; voice = next) { @@ -1994,7 +1983,7 @@ void MV_StopPlayback } } - RestoreInterrupts(flags); + RestoreInterrupts(); } diff --git a/polymer/eduke32/source/jmact/_control.h b/polymer/eduke32/source/jmact/_control.h index ea413bd99..7c610939a 100644 --- a/polymer/eduke32/source/jmact/_control.h +++ b/polymer/eduke32/source/jmact/_control.h @@ -94,15 +94,7 @@ extern "C" { // Number of JOY axes -#define MAXJOYAXES 6 - -// Number of GamePad axes - -#define MAXGAMEPADAXES 2 - -// Number of axes - -#define MAXAXES 6 +#define MAXJOYAXES 8 // NORMAL axis scale diff --git a/polymer/eduke32/source/jmact/control.c b/polymer/eduke32/source/jmact/control.c index 0b85e8c6d..0e4eabb82 100644 --- a/polymer/eduke32/source/jmact/control.c +++ b/polymer/eduke32/source/jmact/control.c @@ -50,7 +50,7 @@ static int32_t CONTROL_MouseButtonClicked[MAXMOUSEBUTTONS], CONTROL_JoyButt static uint8_t CONTROL_MouseButtonClickedCount[MAXMOUSEBUTTONS], CONTROL_JoyButtonClickedCount[MAXJOYBUTTONS]; static int32_t CONTROL_UserInputCleared[3]; static int32_t(*GetTime)(void); -static int32_t CONTROL_Started = FALSE; +int32_t CONTROL_Started = FALSE; static int32_t ticrate; static int32_t CONTROL_DoubleClickSpeed; diff --git a/polymer/eduke32/source/jmact/control.h b/polymer/eduke32/source/jmact/control.h index 2dff02bab..2641ea275 100644 --- a/polymer/eduke32/source/jmact/control.h +++ b/polymer/eduke32/source/jmact/control.h @@ -132,6 +132,7 @@ typedef enum // //*************************************************************************** +extern int32_t CONTROL_Started; extern int32_t CONTROL_MousePresent; extern int32_t CONTROL_JoyPresent; extern int32_t CONTROL_MouseEnabled; diff --git a/polymer/eduke32/source/macros.h b/polymer/eduke32/source/macros.h index 3a7a9464b..eaba40340 100644 --- a/polymer/eduke32/source/macros.h +++ b/polymer/eduke32/source/macros.h @@ -4,7 +4,7 @@ #define TRAVERSE_SPRITE_SECT(l, o, n) for ((o) = (l); (n) = nextspritesect[o], (o) != -1; (o) = (n)) #define TRAVERSE_SPRITE_STAT(l, o, n) for ((o) = (l); (n) = nextspritestat[o], (o) != -1; (o) = (n)) -#define TRAVERSE_CONNECT(i) for (i = connecthead; i != -1; i = connectpoint2[i]) +#define TRAVERSE_CONNECT(i) for (i = 0; i != -1; i = connectpoint2[i]) #define TEST(flags,mask) ((flags) & (mask)) #define SET(flags,mask) ((flags) |= (mask)) diff --git a/polymer/eduke32/source/menus.c b/polymer/eduke32/source/menus.c index 45b76f5ae..bf75fb799 100644 --- a/polymer/eduke32/source/menus.c +++ b/polymer/eduke32/source/menus.c @@ -1460,11 +1460,12 @@ void M_DisplayMenus(void) tempbuf[0] = PACKET_LOAD_GAME; tempbuf[1] = g_lastSaveSlot; tempbuf[2] = myconnectindex; - TRAVERSE_CONNECT(x) - { - if (x != myconnectindex) mmulti_sendpacket(x,tempbuf,3); - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master - } + + if (net_client) + enet_peer_send(net_peer, 0, enet_packet_create(tempbuf, 3, ENET_PACKET_FLAG_RELIABLE)); + else if (net_server) + enet_host_broadcast(net_server, 0, enet_packet_create(tempbuf, 3, ENET_PACKET_FLAG_RELIABLE)); + Net_GetPackets(); G_LoadPlayer(g_lastSaveSlot); @@ -1789,26 +1790,25 @@ void M_DisplayMenus(void) cheat_for_port_credits: if (g_scriptVersion == 13) l = (-2); - mgametext(160,38-l,"GAME PROGRAMMING",0,2+8+16); + mgametext(160,38-l,"PROGRAMMING AND PROJECT MANAGEMENT",0,2+8+16); p = "Richard \"TerminX\" Gobeille"; minitext(161-(Bstrlen(p)<<1), 39+10-l, p, 4, 10+16+128); minitext(160-(Bstrlen(p)<<1), 38+10-l, p, 8, 10+16+128); - mgametext(160,57-l,"\"JFDUKE3D\" AND \"JFBUILD\" CODE",0,2+8+16); - p = "Jonathon \"JonoF\" Fowler"; + mgametext(160,57-l,"POLYMER RENDERING SYSTEM",0,2+8+16); + p = "Pierre-Loup \"Plagman\" Griffais"; minitext(161-(Bstrlen(p)<<1), 58+10-l, p, 4, 10+16+128); minitext(160-(Bstrlen(p)<<1), 57+10-l, p, 8, 10+16+128); - mgametext(160,76-l,"BUILD ENGINE, \"POLYMOST\" RENDERER",0,2+8+16); - mgametext(160,76+8-l,"NETWORKING, OTHER CODE",0,2+8+16); - p = "Ken \"Awesoken\" Silverman"; - minitext(161-(Bstrlen(p)<<1), 77+8+10-l, p, 4, 10+16+128); - minitext(160-(Bstrlen(p)<<1), 76+8+10-l, p, 8, 10+16+128); + mgametext(160,76-l,"ENGINE AND GAME PORTING WORK",0,2+8+16); + p = "Jonathon \"JonoF\" Fowler"; + minitext(161-(Bstrlen(p)<<1), 77+10-l, p, 4, 10+16+128); + minitext(160-(Bstrlen(p)<<1), 76+10-l, p, 8, 10+16+128); - mgametext(160,103-l,"ADDITIONAL RENDERING FEATURES",0,2+8+16); - p = "Pierre-Loup \"Plagman\" Griffais"; - minitext(161-(Bstrlen(p)<<1), 104+10-l, p, 4, 10+16+128); - minitext(160-(Bstrlen(p)<<1), 103+10-l, p, 8, 10+16+128); + mgametext(160,95-l,"BUILD ENGINE AND POLYMOST RENDERER",0,2+8+16); + p = "Ken \"Awesoken\" Silverman"; + minitext(161-(Bstrlen(p)<<1), 96+10-l, p, 4, 10+16+128); + minitext(160-(Bstrlen(p)<<1), 95+10-l, p, 8, 10+16+128); mgametext(160,122-l,"LICENSE AND OTHER CONTRIBUTORS",0,2+8+16); { @@ -1836,11 +1836,15 @@ cheat_for_port_credits: "Ozkan Sezer", // SDL/GTK version checking improvements "Peter Green", // dynamic remapping, custom gametypes "Peter Veenstra", // port to 64-bit + "Randy Heit", // random snippets of ZDoom here and there + "Robin Green", // CON array support "Philipp Kutin", // Mapster32 improvements "Ryan Gordon", // icculus.org Duke3D port sound code "Stephen Anthony", // early 64-bit porting work " ", - "EDuke originally by Matt Saettler", + "EDuke originally by Matt Saettler.", + " ", + "BUILD engine technology available under BUILDLIC.", " ", "--x--", " ", @@ -1862,9 +1866,6 @@ cheat_for_port_credits: p = "Visit www.eduke32.com for news and updates"; minitext(161-(Bstrlen(p)<<1), 136+10+10+10+10+4-l, p, 4, 10+16+128); minitext(160-(Bstrlen(p)<<1), 135+10+10+10+10+4-l, p, 8, 10+16+128); - p = "See wiki.eduke32.com/stuff for new releases"; - minitext(161-(Bstrlen(p)<<1), 143+10+10+10+10+4-l, p, 4, 10+16+128); - minitext(160-(Bstrlen(p)<<1), 142+10+10+10+10+4-l, p, 8, 10+16+128); } break; @@ -1878,9 +1879,6 @@ cheat_for_port_credits: { if (ud.multimode > 1 && x == 0 && ud.recstat != 2) { - if (g_movesPerPacket == 4 && myconnectindex != connecthead) - break; - last_zero = 0; ChangeToMenu(600); } @@ -1897,8 +1895,6 @@ cheat_for_port_credits: ChangeToMenu(202); break; // JBF 20031205: was 200 case 2: - if (g_movesPerPacket == 4 && connecthead != myconnectindex) - break; ChangeToMenu(300); break; case 3: @@ -1927,23 +1923,13 @@ cheat_for_port_credits: } } - if (g_movesPerPacket == 4) - { - if (myconnectindex == connecthead) - menutext(c,67,MENUHIGHLIGHT(0),PHX(-2),"NEW GAME"); - else - menutext(c,67,MENUHIGHLIGHT(0),1,"NEW GAME"); - } - else - menutext(c,67,MENUHIGHLIGHT(0),PHX(-2),"NEW GAME"); + menutext(c,67,MENUHIGHLIGHT(0),PHX(-2),"NEW GAME"); // menutext(c,67+16,0,1,"NETWORK GAME"); menutext(c,67+16/*+16*/,MENUHIGHLIGHT(1),PHX(-3),"OPTIONS"); - if (g_movesPerPacket == 4 && connecthead != myconnectindex) - menutext(c,67+16+16/*+16*/,MENUHIGHLIGHT(2),1,"LOAD GAME"); - else menutext(c,67+16+16/*+16*/,MENUHIGHLIGHT(2),PHX(-4),"LOAD GAME"); + menutext(c,67+16+16/*+16*/,MENUHIGHLIGHT(2),PHX(-4),"LOAD GAME"); if (!VOLUMEALL) { @@ -1971,8 +1957,6 @@ cheat_for_port_credits: switch (x) { case 0: - if (g_movesPerPacket == 4 && myconnectindex != connecthead) - break; if (ud.multimode < 2 || ud.recstat == 2) ChangeToMenu(1500); else @@ -1982,8 +1966,6 @@ cheat_for_port_credits: } break; case 1: - if (g_movesPerPacket == 4 && connecthead != myconnectindex) - break; if (ud.recstat != 2) { last_fifty = 1; @@ -1992,8 +1974,6 @@ cheat_for_port_credits: } break; case 2: - if (g_movesPerPacket == 4 && connecthead != myconnectindex) - break; last_fifty = 2; ChangeToMenu(300); break; @@ -2030,18 +2010,9 @@ cheat_for_port_credits: if (KB_KeyPressed(sc_Q)) ChangeToMenu(500); - if (g_movesPerPacket == 4 && connecthead != myconnectindex) - { - menutext(c,67 ,MENUHIGHLIGHT(0),1,"NEW GAME"); - menutext(c,67+16 ,MENUHIGHLIGHT(1),1,"SAVE GAME"); - menutext(c,67+16+16 ,MENUHIGHLIGHT(2),1,"LOAD GAME"); - } - else - { - menutext(c,67 ,MENUHIGHLIGHT(0),PHX(-2),"NEW GAME"); - menutext(c,67+16 ,MENUHIGHLIGHT(1),PHX(-3),"SAVE GAME"); - menutext(c,67+16+16 ,MENUHIGHLIGHT(2),PHX(-4),"LOAD GAME"); - } + menutext(c,67 ,MENUHIGHLIGHT(0),PHX(-2),"NEW GAME"); + menutext(c,67+16 ,MENUHIGHLIGHT(1),PHX(-3),"SAVE GAME"); + menutext(c,67+16+16 ,MENUHIGHLIGHT(2),PHX(-4),"LOAD GAME"); menutext(c,67+16+16+16 ,MENUHIGHLIGHT(3),PHX(-5),"OPTIONS"); if (!VOLUMEALL) @@ -5102,11 +5073,11 @@ VOLUME_ALL_40x: tempbuf[0] = PACKET_MAP_VOTE_CANCEL; tempbuf[1] = myconnectindex; - TRAVERSE_CONNECT(c) - { - if (c != myconnectindex) mmulti_sendpacket(c,tempbuf,2); - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master - } + if (net_client) + enet_peer_send(net_peer, 0, enet_packet_create(tempbuf, 2, ENET_PACKET_FLAG_RELIABLE)); + else if (net_server) + enet_host_broadcast(net_server, 0, enet_packet_create(tempbuf, 2, ENET_PACKET_FLAG_RELIABLE)); + voting = -1; } ChangeToMenu(0); @@ -5117,9 +5088,9 @@ VOLUME_ALL_40x: plrvotes += g_player[i].vote; j += g_player[i].gotvote; } - if (j == numplayers || !g_player[myconnectindex].ps->i || (plrvotes > (numplayers>>1)) || (!g_networkBroadcastMode && myconnectindex == connecthead)) + if (j == numplayers || !g_player[myconnectindex].ps->i || (plrvotes > (numplayers>>1)) || (net_server)) { - if (plrvotes > (numplayers>>1) || !g_player[myconnectindex].ps->i || (!g_networkBroadcastMode && myconnectindex == connecthead)) + if (plrvotes > (numplayers>>1) || !g_player[myconnectindex].ps->i || (net_server)) { if (ud.m_player_skill == 3) ud.m_respawn_monsters = 1; else ud.m_respawn_monsters = 0; @@ -5138,7 +5109,7 @@ VOLUME_ALL_40x: Net_NewGame(ud.m_volume_number,ud.m_level_number); - if (voting == myconnectindex && !(!g_networkBroadcastMode && myconnectindex == connecthead)) + if (voting == myconnectindex && !(net_server)) G_AddUserQuote("VOTE SUCCEEDED"); G_NewGame(ud.m_volume_number,ud.m_level_number,ud.m_player_skill+1); @@ -5159,12 +5130,12 @@ VOLUME_ALL_40x: tempbuf[0] = PACKET_MAP_VOTE_CANCEL; tempbuf[1] = myconnectindex; tempbuf[2] = 1; + tempbuf[3] = myconnectindex; - TRAVERSE_CONNECT(c) - { - if (c != myconnectindex) mmulti_sendpacket(c,tempbuf,3); - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master - } + if (net_client) + enet_peer_send(net_peer, 0, enet_packet_create(tempbuf, 4, ENET_PACKET_FLAG_RELIABLE)); + else if (net_server) + enet_host_broadcast(net_server, 0, enet_packet_create(tempbuf, 4, ENET_PACKET_FLAG_RELIABLE)); Bsprintf(ScriptQuotes[116],"VOTE FAILED"); P_DoQuote(116,g_player[myconnectindex].ps); @@ -5290,7 +5261,7 @@ VOLUME_ALL_40x: break; case 7: // master does whatever it wants - if (!g_networkBroadcastMode && myconnectindex == connecthead) + if (net_server) { ChangeToMenu(603); break; @@ -5311,12 +5282,12 @@ VOLUME_ALL_40x: tempbuf[1] = myconnectindex; tempbuf[2] = ud.m_volume_number; tempbuf[3] = ud.m_level_number; + tempbuf[4] = myconnectindex; - TRAVERSE_CONNECT(c) - { - if (c != myconnectindex) mmulti_sendpacket(c,tempbuf,4); - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master - } + if (net_client) + enet_peer_send(net_peer, 0, enet_packet_create(tempbuf, 5, ENET_PACKET_FLAG_RELIABLE)); + else if (net_server) + enet_host_broadcast(net_server, 0, enet_packet_create(tempbuf, 5, ENET_PACKET_FLAG_RELIABLE)); } if ((GametypeFlags[ud.m_coop] & GAMETYPE_PLAYERSFRIENDLY) && !(GametypeFlags[ud.m_coop] & GAMETYPE_TDM)) ud.m_noexits = 0; diff --git a/polymer/eduke32/source/osdcmds.c b/polymer/eduke32/source/osdcmds.c index a2138a309..0a00c1359 100644 --- a/polymer/eduke32/source/osdcmds.c +++ b/polymer/eduke32/source/osdcmds.c @@ -102,7 +102,7 @@ static int32_t osdcmd_changelevel(const osdfuncparm_t *parm) if (numplayers > 1) { - if (myconnectindex == connecthead && g_networkBroadcastMode == 0) + if (net_server) Net_NewGame(volume,level); else if (voting == -1) { @@ -128,11 +128,7 @@ static int32_t osdcmd_changelevel(const osdfuncparm_t *parm) tempbuf[2] = ud.m_volume_number; tempbuf[3] = ud.m_level_number; - TRAVERSE_CONNECT(i) - { - if (i != myconnectindex) mmulti_sendpacket(i,tempbuf,4); - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master - } + enet_peer_send(net_peer, 0, enet_packet_create(tempbuf, 4, ENET_PACKET_FLAG_RELIABLE)); } if ((GametypeFlags[ud.m_coop] & GAMETYPE_PLAYERSFRIENDLY) && !(GametypeFlags[ud.m_coop] & GAMETYPE_TDM)) ud.m_noexits = 0; @@ -254,7 +250,7 @@ static int32_t osdcmd_map(const osdfuncparm_t *parm) if (numplayers > 1) { - if (myconnectindex == connecthead && g_networkBroadcastMode == 0) + if (net_server) { Net_SendUserMapName(); ud.m_volume_number = 0; @@ -286,11 +282,7 @@ static int32_t osdcmd_map(const osdfuncparm_t *parm) tempbuf[2] = ud.m_volume_number; tempbuf[3] = ud.m_level_number; - TRAVERSE_CONNECT(i) - { - if (i != myconnectindex) mmulti_sendpacket(i,tempbuf,4); - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master - } + enet_peer_send(net_peer, 0, enet_packet_create(tempbuf, 4, ENET_PACKET_FLAG_RELIABLE)); } if ((GametypeFlags[ud.m_coop] & GAMETYPE_PLAYERSFRIENDLY) && !(GametypeFlags[ud.m_coop] & GAMETYPE_TDM)) ud.m_noexits = 0; @@ -1115,9 +1107,6 @@ static int32_t osdcmd_screenshot(const osdfuncparm_t *parm) return OSDCMD_OK; } -extern void G_SaveMapState(mapstate_t *save); -extern void G_RestoreMapState(mapstate_t *save); - /* static int32_t osdcmd_savestate(const osdfuncparm_t *parm) { diff --git a/polymer/eduke32/source/player.c b/polymer/eduke32/source/player.c index c950012d7..1a7210860 100644 --- a/polymer/eduke32/source/player.c +++ b/polymer/eduke32/source/player.c @@ -3317,9 +3317,11 @@ void getinput(int32_t snum) return; } - if (numplayers > 1) - daang = myang; - else daang = p->ang; +/* + if (numplayers > 1) + daang = myang; + else*/ + daang = p->ang; momx = mulscale9(vel,sintable[(daang+2560)&2047]); momy = mulscale9(vel,sintable[(daang+2048)&2047]); @@ -4142,14 +4144,6 @@ void P_ProcessInput(int32_t snum) G_AddUserQuote(tempbuf); } } - - if (myconnectindex == connecthead) - { - Bsprintf(tempbuf,"frag %d killed %d\n",p->frag_ps+1,snum+1); - sendscore(tempbuf); - // printf(tempbuf); - } - p->frag_ps = snum; pus = NUMPAGES; } diff --git a/polymer/eduke32/source/premap.c b/polymer/eduke32/source/premap.c index 6f5db5c2d..e4d25296b 100644 --- a/polymer/eduke32/source/premap.c +++ b/polymer/eduke32/source/premap.c @@ -621,7 +621,7 @@ void P_RandomSpawnPoint(int32_t snum) p->cursectnum = g_playerSpawnPoints[i].os; } -static void P_ResetStatus(int32_t snum) +void P_ResetStatus(int32_t snum) { DukePlayer_t *p = g_player[snum].ps; @@ -1304,20 +1304,6 @@ quick: display_mirror = 0; - if (ud.multimode > 1) - { - if (numplayers < 2) - { - connecthead = 0; - for (i=0; ii, screenpeek, -1); } @@ -1333,7 +1319,7 @@ static void resetpspritevars(char g) APLAYER,0,0,0,g_player[0].ps->ang,0,0,0,10); if (ud.recstat != 2) - for (i=0; iaim_mode; autoaim[i] = g_player[i].ps->auto_aim; @@ -1362,11 +1348,11 @@ static void resetpspritevars(char g) P_ResetStatus(0); - for (i=1; iaim_mode = aimmode[i]; g_player[i].ps->auto_aim = autoaim[i]; @@ -1396,7 +1382,7 @@ static void resetpspritevars(char g) circ = 2048/ud.multimode; g_whichPalForPlayer = 9; - j = connecthead; + j = 0; i = headspritestat[STAT_PLAYER]; while (i >= 0) { @@ -1419,73 +1405,76 @@ static void resetpspritevars(char g) g_playerSpawnPoints[(uint8_t)g_numPlayerSprites].os = s->sectnum; g_numPlayerSprites++; - if (j >= 0) + + if (j < MAXPLAYERS) { s->owner = i; s->shade = 0; s->xrepeat = 42; s->yrepeat = 36; - s->cstat = 1+256; + s->cstat = j < numplayers ? 1+256 : 32768; s->xoffset = 0; s->clipdist = 64; - if ((g&MODE_EOL) != MODE_EOL || g_player[j].ps->last_extra == 0) +// if (j < playerswhenstarted) { - g_player[j].ps->last_extra = g_player[j].ps->max_player_health; - s->extra = g_player[j].ps->max_player_health; - g_player[j].ps->runspeed = g_playerFriction; - } - else s->extra = g_player[j].ps->last_extra; - - s->yvel = j; - - if (!g_player[j].pcolor && ud.multimode > 1 && !(GametypeFlags[ud.coop] & GAMETYPE_TDM)) - { - if (s->pal == 0) + if ((g&MODE_EOL) != MODE_EOL || g_player[j].ps->last_extra == 0) { - int32_t k = 0; + g_player[j].ps->last_extra = g_player[j].ps->max_player_health; + s->extra = g_player[j].ps->max_player_health; + g_player[j].ps->runspeed = g_playerFriction; + } + else s->extra = g_player[j].ps->last_extra; - for (; kyvel = j; + + if (!g_player[j].pcolor && ud.multimode > 1 && !(GametypeFlags[ud.coop] & GAMETYPE_TDM)) + { + if (s->pal == 0) { - if (g_whichPalForPlayer == g_player[k].ps->palookup) + int32_t k = 0; + + for (; k= 17) - g_whichPalForPlayer = 9; - k=0; + if (g_whichPalForPlayer == g_player[k].ps->palookup) + { + g_whichPalForPlayer++; + if (g_whichPalForPlayer >= 17) + g_whichPalForPlayer = 9; + k=0; + } } + g_player[j].pcolor = s->pal = g_player[j].ps->palookup = g_whichPalForPlayer++; + if (g_whichPalForPlayer >= 17) + g_whichPalForPlayer = 9; } - g_player[j].pcolor = s->pal = g_player[j].ps->palookup = g_whichPalForPlayer++; - if (g_whichPalForPlayer >= 17) - g_whichPalForPlayer = 9; + else g_player[j].pcolor = g_player[j].ps->palookup = s->pal; } - else g_player[j].pcolor = g_player[j].ps->palookup = s->pal; - } - else - { - int32_t k = g_player[j].pcolor; - - if (GametypeFlags[ud.coop] & GAMETYPE_TDM) + else { - k = G_GetTeamPalette(g_player[j].pteam); - g_player[j].ps->team = g_player[j].pteam; + int32_t k = g_player[j].pcolor; + + if (GametypeFlags[ud.coop] & GAMETYPE_TDM) + { + k = G_GetTeamPalette(g_player[j].pteam); + g_player[j].ps->team = g_player[j].pteam; + } + s->pal = g_player[j].ps->palookup = k; } - s->pal = g_player[j].ps->palookup = k; + + g_player[j].ps->i = i; + g_player[j].ps->frag_ps = j; + ActorExtra[i].owner = i; + + ActorExtra[i].bposx = g_player[j].ps->bobposx = g_player[j].ps->oposx = g_player[j].ps->posx = s->x; + ActorExtra[i].bposy = g_player[j].ps->bobposy = g_player[j].ps->oposy = g_player[j].ps->posy = s->y; + ActorExtra[i].bposz = g_player[j].ps->oposz = g_player[j].ps->posz = s->z; + g_player[j].ps->oang = g_player[j].ps->ang = s->ang; + + updatesector(s->x,s->y,&g_player[j].ps->cursectnum); } - g_player[j].ps->i = i; - g_player[j].ps->frag_ps = j; - ActorExtra[i].owner = i; - - ActorExtra[i].bposx = g_player[j].ps->bobposx = g_player[j].ps->oposx = g_player[j].ps->posx = s->x; - ActorExtra[i].bposy = g_player[j].ps->bobposy = g_player[j].ps->oposy = g_player[j].ps->posy = s->y; - ActorExtra[i].bposz = g_player[j].ps->oposz = g_player[j].ps->posz = s->z; - g_player[j].ps->oang = g_player[j].ps->ang = s->ang; - - updatesector(s->x,s->y,&g_player[j].ps->cursectnum); - - j = connectpoint2[j]; - + j++; } else deletesprite(i); i = nexti; @@ -1518,20 +1507,15 @@ void G_ResetTimers(void) void Net_WaitForEverybody(void) { - int32_t i; + int32_t server_ready = g_player[0].playerreadyflag; + + if (numplayers < 2 || net_server) return; - if (numplayers < 2) return; packbuf[0] = PACKET_PLAYER_READY; + packbuf[1] = myconnectindex; - g_player[myconnectindex].playerreadyflag++; - - // if we're a peer or slave, not a master - if ((g_networkBroadcastMode == 1) || (!g_networkBroadcastMode && (myconnectindex != connecthead))) - TRAVERSE_CONNECT(i) - { - if (i != myconnectindex) mmulti_sendpacket(i,packbuf,1); - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master - } + if (net_client) + enet_peer_send(net_peer, 0, enet_packet_create(packbuf, 2, ENET_PACKET_FLAG_RELIABLE)); if (ud.multimode > 1) { @@ -1543,7 +1527,7 @@ void Net_WaitForEverybody(void) if (PLUTOPAK) // JBF 20030804 rotatesprite(160<<16,(151)<<16,30<<11,0,PLUTOPAKSPRITE+1,0,0,2+8,0,0,xdim-1,ydim-1); - gametext(160,190,"WAITING FOR PLAYERS",14,2); + gametext(160,190,"WAITING FOR SERVER",14,2); nextpage(); } @@ -1551,28 +1535,11 @@ void Net_WaitForEverybody(void) { if (quitevent || keystatus[1]) G_GameExit(""); + handleevents(); Net_GetPackets(); - TRAVERSE_CONNECT(i) + if (g_player[0].playerreadyflag > server_ready) { - if (g_player[i].playerreadyflag < g_player[myconnectindex].playerreadyflag) break; - if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) - { - // we're a slave - i = -1; break; - } - //slaves in M/S mode only wait for master - } - if (i < 0) - { - // master sends ready packet once it hears from all slaves - if (!g_networkBroadcastMode && myconnectindex == connecthead) - TRAVERSE_CONNECT(i) - { - packbuf[0] = PACKET_PLAYER_READY; - if (i != myconnectindex) mmulti_sendpacket(i,packbuf,1); - } - P_SetGamePalette(g_player[myconnectindex].ps, palette, 11); return; } @@ -1580,8 +1547,6 @@ void Net_WaitForEverybody(void) } extern int32_t jump_input; -extern char g_szfirstSyncMsg[MAXSYNCBYTES][60]; -extern int32_t g_foundSyncError; void clearfifo(void) { @@ -1590,8 +1555,6 @@ void clearfifo(void) syncvaltail = 0L; syncvaltottail = 0L; memset(&syncstat, 0, sizeof(syncstat)); - memset(&g_szfirstSyncMsg, 0, sizeof(g_szfirstSyncMsg)); - g_foundSyncError = 0; bufferjitter = 1; mymaxlag = otherminlag = 0; jump_input = 0; @@ -1952,7 +1915,7 @@ int32_t G_EnterLevel(int32_t g) if (!premap_quickenterlevel) { Net_WaitForEverybody(); - mmulti_flushpackets(); +// mmulti_flushpackets(); G_FadePalette(0,0,0,0); G_UpdateScreenArea(); @@ -1961,8 +1924,6 @@ int32_t G_EnterLevel(int32_t g) G_DrawRooms(myconnectindex,65536); } - for (i=0; iover_shoulder_on = 0; clearfrags(); diff --git a/polymer/eduke32/source/sector.c b/polymer/eduke32/source/sector.c index 76aa6be4d..4f6d07419 100644 --- a/polymer/eduke32/source/sector.c +++ b/polymer/eduke32/source/sector.c @@ -190,8 +190,8 @@ int32_t isanearoperator(int32_t lotag) inline int32_t G_CheckPlayerInSector(int32_t sect) { - int32_t i = connecthead; - for (; i>=0; i=connectpoint2[i]) + int32_t i; + TRAVERSE_CONNECT(i) if (sprite[g_player[i].ps->i].sectnum == sect) return i; return -1; } @@ -310,7 +310,7 @@ void G_DoSectorAnimations(void) { my.z += v; myvel.z = 0; - myzbak[((movefifoplc-1)&(MOVEFIFOSIZ-1))] = g_player[p].ps->posz; + myzbak[0] = g_player[p].ps->posz; } } diff --git a/polymer/eduke32/source/sync.c b/polymer/eduke32/source/sync.c index 90551c913..940933159 100644 --- a/polymer/eduke32/source/sync.c +++ b/polymer/eduke32/source/sync.c @@ -386,7 +386,7 @@ void Net_GetSyncData(char *packbuf, int32_t packbufleng, int32_t *j, int32_t oth while (1) { - for (i = connectpoint2[connecthead]; i >= 0; i = connectpoint2[i]) + TRAVERSE_CONNECT(i) { for (sb = 0; sb < g_numSyncBytes; sb++) {