Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiplayer in Emscripten builds! #673

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 46 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@ ifndef USE_RENDERER_DLOPEN
USE_RENDERER_DLOPEN=1
endif

ifndef USE_HUMBLENET
USE_HUMBLENET=0
endif

ifndef USE_YACC
USE_YACC=0
endif
Expand Down Expand Up @@ -281,6 +285,7 @@ OPUSDIR=$(MOUNT_DIR)/opus-1.2.1
OPUSFILEDIR=$(MOUNT_DIR)/opusfile-0.9
ZDIR=$(MOUNT_DIR)/zlib
TOOLSDIR=$(MOUNT_DIR)/tools
HDIR=$(MOUNT_DIR)/humblenet
Q3ASMDIR=$(MOUNT_DIR)/tools/asm
LBURGDIR=$(MOUNT_DIR)/tools/lcc/lburg
Q3CPPDIR=$(MOUNT_DIR)/tools/lcc/cpp
Expand Down Expand Up @@ -1063,12 +1068,12 @@ ifeq ($(PLATFORM),emscripten)
ARCH=wasm32
BINEXT=.js

# dlopen(), opengl1, and networking are not functional
# dlopen() and opengl1 are not functional
USE_RENDERER_DLOPEN=0
USE_OPENAL_DLOPEN=0
USE_HUMBLENET=1
BUILD_GAME_SO=0
BUILD_RENDERER_OPENGL1=0
BUILD_SERVER=0

CLIENT_CFLAGS+=-s USE_SDL=2

Expand All @@ -1077,11 +1082,19 @@ ifeq ($(PLATFORM),emscripten)
CLIENT_LDFLAGS+=-s MIN_WEBGL_VERSION=1 -s MAX_WEBGL_VERSION=2

# The HTML file can use these functions to load extra files before the game starts.
CLIENT_LDFLAGS+=-s EXPORTED_RUNTIME_METHODS=FS,addRunDependency,removeRunDependency
CLIENT_LDFLAGS+=-s EXPORTED_RUNTIME_METHODS=FS,addRunDependency,removeRunDependency,cwrap,stackAlloc,out
CLIENT_LDFLAGS+=-s EXIT_RUNTIME=1
CLIENT_LDFLAGS+=-s EXPORT_ES6
CLIENT_LDFLAGS+=-s EXPORT_NAME=ioquake3

SERVER_LDFLAGS+=-s TOTAL_MEMORY=256mb
SERVER_LDFLAGS+=-s STACK_SIZE=5MB
SERVER_LDFLAGS+=-s EXPORTED_RUNTIME_METHODS=FS,addRunDependency,removeRunDependency,cwrap,stackAlloc,out
SERVER_LDFLAGS+=-s EXIT_RUNTIME=1
SERVER_LDFLAGS+=-s EXPORT_ES6
SERVER_LDFLAGS+=-s EXPORT_NAME=ioq3ded


# Game data files can be packaged by emcc into a .data file that lives next to the wasm bundle
# and added to the virtual filesystem before the game starts. This requires the game data to be
# present at build time and it can't be changed afterward.
Expand All @@ -1093,6 +1106,7 @@ ifeq ($(PLATFORM),emscripten)
$(error "No files in '$(BASEGAME)' directory for emscripten to preload.")
endif
CLIENT_LDFLAGS+=--preload-file $(BASEGAME)
SERVER_LDFLAGS+=--preload-file $(BASEGAME)
endif

OPTIMIZEVM = -O3
Expand Down Expand Up @@ -1254,6 +1268,10 @@ ifeq ($(PLATFORM),emscripten)
endif
endif

ifeq ($(USE_HUMBLENET),1)
BASE_CFLAGS += -DUSE_HUMBLENET
endif

ifeq ($(USE_OPENAL),1)
CLIENT_CFLAGS += -DUSE_OPENAL
ifeq ($(USE_OPENAL_DLOPEN),1)
Expand Down Expand Up @@ -2405,6 +2423,11 @@ ifeq ($(PLATFORM),darwin)
$(B)/client/sys_osx.o
endif

ifeq ($(USE_HUMBLENET),1)
Q3OBJ += \
$(B)/client/humblenet_asmjs_amalgam.o
endif

ifeq ($(USE_MUMBLE),1)
Q3OBJ += \
$(B)/client/libmumblelink.o
Expand Down Expand Up @@ -2574,18 +2597,29 @@ ifdef MINGW
$(B)/ded/con_win32.o
else
Q3DOBJ += \
$(B)/ded/sys_unix.o \
$(B)/ded/con_tty.o
$(B)/ded/sys_unix.o
ifeq ($(PLATFORM),emscripten)
Q3DOBJ += \
$(B)/ded/con_passive.o
else
Q3DOBJ += \
$(B)/ded/con_tty.o
endif
endif

ifeq ($(PLATFORM),darwin)
Q3DOBJ += \
$(B)/ded/sys_osx.o
endif

ifeq ($(USE_HUMBLENET),1)
Q3DOBJ += \
$(B)/ded/humblenet_asmjs_amalgam.o
endif

$(B)/$(SERVERBIN)$(FULLBINEXT): $(Q3DOBJ)
$(echo_cmd) "LD $@"
$(Q)$(CC) $(CFLAGS) $(LDFLAGS) $(NOTSHLIBLDFLAGS) -o $@ $(Q3DOBJ) $(LIBS)
$(Q)$(CC) $(CFLAGS) $(LDFLAGS) $(NOTSHLIBLDFLAGS) $(SERVER_LDFLAGS) -o $@ $(Q3DOBJ) $(LIBS)



Expand Down Expand Up @@ -2894,6 +2928,9 @@ $(B)/client/%.o: $(CDIR)/%.c
$(B)/client/%.o: $(SDIR)/%.c
$(DO_CC)

$(B)/client/%.o: $(HDIR)/%.cpp
$(DO_CC)

$(B)/client/%.o: $(CMDIR)/%.c
$(DO_CC)

Expand Down Expand Up @@ -2978,6 +3015,9 @@ $(B)/ded/%.o: $(ASMDIR)/%.c
$(B)/ded/%.o: $(SDIR)/%.c
$(DO_DED_CC)

$(B)/ded/%.o: $(HDIR)/%.cpp
$(DO_DED_CC)

$(B)/ded/%.o: $(CMDIR)/%.c
$(DO_DED_CC)

Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ For Web, building with Emscripten
in a web browser. Open the developer console to see errors and warnings.
6. Debugging the C code is possible using a Chrome extension. For details
see https://developer.chrome.com/blog/wasm-debugging-2020
7. Multiplayer is supported over WebRTC DataChannel UDP. WebRTC requires
a separate signaling server to establish connections. This server is
provided by [HumbleNet](https://github.com/jdarpinian/HumbleNet) and
must be built separately. The default signaling server address is
`ws://localhost:8080`. You can change this using the `net_peer_server`
cvar. The signaling server assigns peers virtual hostnames of the form
`peer_1.humblenet` and these hostnames can be used to connect peers to
each other.

Installation, for *nix
1. Set the COPYDIR variable in the shell to be where you installed Quake 3
Expand Down
40 changes: 40 additions & 0 deletions code/humblenet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
HumbleNet is a networking library that supports emulating BSD sockets on top
of WebRTC DataChannel. This enables both client-server and peer-to-peer
networking using actual unreliable UDP packets in web browsers with the
Emscripten build of ioquake3.

WebRTC requires an out-of-band connection to exchange messages before the
peer-to-peer connection can be established. HumbleNet requires a WebSocket
based signaling server for this. The code for the signaling server is not
copied into the ioquake3 repo. It can be built from the HumbleNet repository.

The code here is from this commit:

https://github.com/jdarpinian/HumbleNet/tree/2bc0627451eefe3c33e94817acebc05f0a637956


HumbleNet is licensed under the BSD 3-Clause License reproduced below:

Copyright (c) 2016, Humble Bundle, Inc.
Copyright (c) 2017, OutOfOrder.cc

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

* Neither the name of HumbleNet nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
133 changes: 133 additions & 0 deletions code/humblenet/humblenet.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#ifndef HUMBLENET_H
#define HUMBLENET_H


#include <stddef.h>
#include <stdint.h>

#ifdef HUMBLENET_STATIC
#define HUMBLENET_DLL_EXPORT
#else
#ifdef WIN32
#ifdef HUMBLENET_DLL_BUILD
#define HUMBLENET_DLL_EXPORT __declspec(dllexport)
#else
#define HUMBLENET_DLL_EXPORT __declspec(dllimport)
#endif
#else // GCC
#if defined(__GNUC__) && __GNUC__ >= 4
# define HUMBLENET_DLL_EXPORT __attribute__ ((visibility("default")))
#else
# define HUMBLENET_DLL_EXPORT
#endif
#endif
#endif

#if defined(WIN32)
#define HUMBLENET_CALL __cdecl
#elif defined(__GNUC__)
#if defined(__LP64__)
#define HUMBLENET_CALL
#else
#define HUMBLENET_CALL __attribute__((cdecl))
#endif
#else
#define HUMBLENET_CALL
#endif

#define HUMBLENET_API HUMBLENET_DLL_EXPORT

#define HUMBLENET_MAJOR_VERSION 1
#define HUMBLENET_MINOR_VERSION 0
#define HUMBLENET_PATCHLEVEL 0

/**
* Create a comparable version number value
*
* e.g. (1,2,3) -> (0x010203)
*/
#define HUMBLENET_VERSIONNUM(X, Y, Z) \
(((X) << 16) | ((Y) << 8) | (Z))

/**
* this is the version that we are currently compiling against
*/
#define HUMBLENET_COMPILEDVERSION \
HUMBLENET_VERSIONNUM(HUMBLENET_MAJOR_VERSION, HUMBLENET_MINOR_VERSION, HUMBLENET_PATCHLEVEL)

/**
* check if compiled with HumbleNet version of at least X.Y.Z
*/
#define HUMBLENET_VERSION_ATLEAST(X, Y, Z) \
(HUMBLENET_COMPILEDVERSION >= HUMBLENET_VERSIONNUM(X, Y, Z))

#ifdef __cplusplus
extern "C" {
#endif

typedef uint8_t ha_bool;
typedef uint32_t PeerId;

/*
* Get the version of the humblenet library we are linked to
*/
HUMBLENET_API uint32_t HUMBLENET_CALL humblenet_version();

/*
* Initialize the core humblenet library
*/
HUMBLENET_API ha_bool HUMBLENET_CALL humblenet_init();

/*
* Shutdown the entire humblenet library
*/
HUMBLENET_API void HUMBLENET_CALL humblenet_shutdown();

/*
* Allow network polling to occur. This is already thread safe and must NOT be within a lock/unlock block
*/
HUMBLENET_API void HUMBLENET_CALL humblenet_poll(int ms);

/*
* Get error string
* Return value will stay valid until next call to humblenet_set_error
* or humblenet_clear_error() is called
*/
HUMBLENET_API const char * HUMBLENET_CALL humblenet_get_error();

/*
* Set error string
* Parameter is copied to private storage
* Must not be NULL
*/
HUMBLENET_API void HUMBLENET_CALL humblenet_set_error(const char *error);

/*
* Clear error string
*/
HUMBLENET_API void HUMBLENET_CALL humblenet_clear_error();

/*
* Set the value of a hint
*/
HUMBLENET_API ha_bool HUMBLENET_CALL humblenet_set_hint(const char* name, const char* value);

/*
* Get the value of a hint
*/
HUMBLENET_API const char* HUMBLENET_CALL humblenet_get_hint(const char* name);

/*
* If using the loader this will set the loader path.
* If using the loading returns 1 if the library loads or 0 if it fails to load.
* Use humblenet_get_error() to see why loading failed.
* If not using the loader, simply returns 1
*/
HUMBLENET_API ha_bool HUMBLENET_CALL humblenet_loader_init(const char* libpath);

#ifdef __cplusplus
}
#endif


#endif /*HUMBLENET_H */
Loading