Compare commits
1
Commits
networking2
...
server
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c4eeb9793 |
No files matched your search
@@ -0,0 +1,47 @@
|
|||||||
|
# cmake/FetchDependenciesServer.cmake
|
||||||
|
#
|
||||||
|
# Downloads only what the headless GameServer needs (Eigen + Boost headers).
|
||||||
|
# Skips anything already present in thirdparty/. Works on Windows and Linux.
|
||||||
|
|
||||||
|
set(THIRDPARTY_DIR "${CMAKE_CURRENT_LIST_DIR}/../thirdparty")
|
||||||
|
file(MAKE_DIRECTORY "${THIRDPARTY_DIR}")
|
||||||
|
|
||||||
|
macro(server_check_and_download URL ARCHIVE_NAME EXTRACTED_DIR_NAME CHECK_FILE)
|
||||||
|
set(_archive_path "${THIRDPARTY_DIR}/${ARCHIVE_NAME}")
|
||||||
|
set(_src_path "${THIRDPARTY_DIR}/${EXTRACTED_DIR_NAME}")
|
||||||
|
|
||||||
|
if(NOT EXISTS "${_src_path}/${CHECK_FILE}")
|
||||||
|
if(NOT EXISTS "${_archive_path}")
|
||||||
|
message(STATUS "Downloading ${ARCHIVE_NAME}...")
|
||||||
|
file(DOWNLOAD "${URL}" "${_archive_path}"
|
||||||
|
SHOW_PROGRESS STATUS _dl_status)
|
||||||
|
list(GET _dl_status 0 _dl_code)
|
||||||
|
if(NOT _dl_code EQUAL 0)
|
||||||
|
file(REMOVE "${_archive_path}")
|
||||||
|
message(FATAL_ERROR "Failed to download ${URL}: ${_dl_status}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
message(STATUS "Extracting ${ARCHIVE_NAME}...")
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E tar xf "${_archive_path}"
|
||||||
|
WORKING_DIRECTORY "${THIRDPARTY_DIR}"
|
||||||
|
RESULT_VARIABLE _tar_res)
|
||||||
|
if(NOT _tar_res EQUAL 0)
|
||||||
|
message(FATAL_ERROR "Failed to extract ${_archive_path}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Eigen: only needed if no system install is available.
|
||||||
|
find_package(Eigen3 3.3 CONFIG QUIET)
|
||||||
|
if(NOT TARGET Eigen3::Eigen)
|
||||||
|
server_check_and_download(
|
||||||
|
"https://gitlab.com/libeigen/eigen/-/archive/5.0.0/eigen-5.0.0.zip"
|
||||||
|
"eigen-5.0.0.zip" "eigen-5.0.0" "signature_of_eigen3_matrix_library")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Boost (header-only usage: asio + beast). Use bundled copy always so the
|
||||||
|
# version matches the Windows build.
|
||||||
|
server_check_and_download(
|
||||||
|
"https://archives.boost.io/release/1.90.0/source/boost_1_90_0.zip"
|
||||||
|
"boost_1_90_0.zip" "boost_1_90_0" "boost/asio.hpp")
|
||||||
+28
-13
@@ -9,6 +9,7 @@ set(CMAKE_CXX_EXTENSIONS OFF)
|
|||||||
set(GAME_ROOT "${CMAKE_CURRENT_LIST_DIR}/..")
|
set(GAME_ROOT "${CMAKE_CURRENT_LIST_DIR}/..")
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
include("${GAME_ROOT}/cmake/FetchDependenciesServer.cmake")
|
||||||
find_package(Eigen3 3.3 CONFIG QUIET)
|
find_package(Eigen3 3.3 CONFIG QUIET)
|
||||||
if(NOT TARGET Eigen3::Eigen)
|
if(NOT TARGET Eigen3::Eigen)
|
||||||
set(EIGEN_BUNDLED_DIR "${GAME_ROOT}/thirdparty/eigen-5.0.0")
|
set(EIGEN_BUNDLED_DIR "${GAME_ROOT}/thirdparty/eigen-5.0.0")
|
||||||
@@ -105,24 +106,32 @@ endif()
|
|||||||
add_executable(GameServer src/main.cpp README.md)
|
add_executable(GameServer src/main.cpp README.md)
|
||||||
source_group("Server" FILES src/main.cpp README.md)
|
source_group("Server" FILES src/main.cpp README.md)
|
||||||
target_link_libraries(GameServer PRIVATE game_server_core)
|
target_link_libraries(GameServer PRIVATE game_server_core)
|
||||||
if(WIN32)
|
set(BOOST_BUNDLED_DIR "${GAME_ROOT}/thirdparty/boost_1_90_0")
|
||||||
set(BOOST_BUNDLED_DIR "${GAME_ROOT}/thirdparty/boost_1_90_0")
|
if(NOT EXISTS "${BOOST_BUNDLED_DIR}/boost/asio.hpp")
|
||||||
if(NOT EXISTS "${BOOST_BUNDLED_DIR}/boost/asio.hpp")
|
|
||||||
message(FATAL_ERROR
|
message(FATAL_ERROR
|
||||||
"Boost was not found at thirdparty/boost_1_90_0. Configure the "
|
"Boost was not found at thirdparty/boost_1_90_0 and could not be "
|
||||||
"graphical project once to populate it.")
|
"downloaded.")
|
||||||
endif()
|
endif()
|
||||||
target_sources(GameServer PRIVATE
|
target_sources(GameServer PRIVATE
|
||||||
"${GAME_ROOT}/src/game_server/NetworkProtocol.cpp"
|
"${GAME_ROOT}/src/game_server/NetworkProtocol.cpp"
|
||||||
"${GAME_ROOT}/src/game_server/NetworkProtocol.h"
|
"${GAME_ROOT}/src/game_server/NetworkProtocol.h"
|
||||||
"${GAME_ROOT}/src/game_server/WebsocketGameServer.cpp"
|
"${GAME_ROOT}/src/game_server/WebsocketGameServer.cpp"
|
||||||
"${GAME_ROOT}/src/game_server/WebsocketGameServer.h")
|
"${GAME_ROOT}/src/game_server/WebsocketGameServer.h")
|
||||||
target_include_directories(GameServer PRIVATE "${BOOST_BUNDLED_DIR}")
|
target_include_directories(GameServer PRIVATE "${BOOST_BUNDLED_DIR}")
|
||||||
|
target_compile_definitions(GameServer PRIVATE NETWORK)
|
||||||
|
if(WIN32)
|
||||||
target_compile_definitions(
|
target_compile_definitions(
|
||||||
GameServer PRIVATE NETWORK WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0A00)
|
GameServer PRIVATE WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0A00)
|
||||||
target_link_libraries(GameServer PRIVATE ws2_32 mswsock)
|
target_link_libraries(GameServer PRIVATE ws2_32 mswsock)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# The server reads configs from ./resources relative to its working directory,
|
||||||
|
# so keep a copy next to the binary after every build.
|
||||||
|
add_custom_command(TARGET GameServer POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
|
"${GAME_ROOT}/resources" "$<TARGET_FILE_DIR:GameServer>/resources"
|
||||||
|
COMMENT "Copying resources next to GameServer")
|
||||||
|
|
||||||
include(CTest)
|
include(CTest)
|
||||||
if(BUILD_TESTING)
|
if(BUILD_TESTING)
|
||||||
add_executable(
|
add_executable(
|
||||||
@@ -141,7 +150,8 @@ if(BUILD_TESTING)
|
|||||||
add_test(
|
add_test(
|
||||||
NAME GameServer.LocationState
|
NAME GameServer.LocationState
|
||||||
COMMAND GameServerStateTests)
|
COMMAND GameServerStateTests)
|
||||||
if(WIN32)
|
# network tests (all platforms)
|
||||||
|
if(TRUE)
|
||||||
add_executable(
|
add_executable(
|
||||||
GameServerNetworkProtocolTests
|
GameServerNetworkProtocolTests
|
||||||
tests/NetworkProtocolTests.cpp
|
tests/NetworkProtocolTests.cpp
|
||||||
@@ -161,11 +171,16 @@ if(BUILD_TESTING)
|
|||||||
target_include_directories(
|
target_include_directories(
|
||||||
GameServerWebsocketLockstepTests PRIVATE "${BOOST_BUNDLED_DIR}")
|
GameServerWebsocketLockstepTests PRIVATE "${BOOST_BUNDLED_DIR}")
|
||||||
target_compile_definitions(
|
target_compile_definitions(
|
||||||
GameServerWebsocketLockstepTests PRIVATE
|
GameServerWebsocketLockstepTests PRIVATE NETWORK)
|
||||||
NETWORK WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0A00)
|
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
|
GameServerWebsocketLockstepTests PRIVATE game_server_core)
|
||||||
|
if(WIN32)
|
||||||
|
target_compile_definitions(
|
||||||
GameServerWebsocketLockstepTests PRIVATE
|
GameServerWebsocketLockstepTests PRIVATE
|
||||||
game_server_core ws2_32 mswsock)
|
WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0A00)
|
||||||
|
target_link_libraries(
|
||||||
|
GameServerWebsocketLockstepTests PRIVATE ws2_32 mswsock)
|
||||||
|
endif()
|
||||||
add_test(
|
add_test(
|
||||||
NAME GameServer.WebsocketLockstep
|
NAME GameServer.WebsocketLockstep
|
||||||
COMMAND GameServerWebsocketLockstepTests)
|
COMMAND GameServerWebsocketLockstepTests)
|
||||||
|
|||||||
+123
-62
@@ -1,11 +1,37 @@
|
|||||||
# Headless GameServer
|
# Headless GameServer
|
||||||
|
|
||||||
This target runs the authoritative `InternalGameServer` without SDL, OpenGL,
|
This target runs the authoritative `InternalGameServer` without SDL, OpenGL,
|
||||||
audio, Lua, or rendering dependencies. On Windows it exposes a deterministic
|
audio, Lua, or rendering dependencies. It exposes a deterministic lockstep
|
||||||
lockstep session through a Boost.Beast WebSocket listener.
|
session through a Boost.Beast WebSocket listener (Windows and Linux).
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- CMake >= 3.16, a C++17 compiler (MSVC, or GCC/Clang on Linux)
|
||||||
|
- Ubuntu: `sudo apt install build-essential cmake git unzip curl`
|
||||||
|
- Internet access on the first configure (see below)
|
||||||
|
|
||||||
|
Eigen and Boost are **downloaded automatically** by
|
||||||
|
`cmake/FetchDependenciesServer.cmake` into `thirdparty/` the first time CMake
|
||||||
|
configures the project (Boost zip is ~200 MB). A system Eigen3 is used if
|
||||||
|
installed; Boost is always taken from `thirdparty/boost_1_90_0` so versions match
|
||||||
|
the Windows build. Nothing else (SDL, zlib, libzip, ...) is needed.
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
|
Linux (recommended helper, 1 compile job to stay within low RAM):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
server/scripts/build.sh # JOBS=2 server/scripts/build.sh for more
|
||||||
|
```
|
||||||
|
|
||||||
|
Or manually:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -S server -B server/build -DCMAKE_BUILD_TYPE=Release
|
||||||
|
cmake --build server/build --target GameServer --parallel 1
|
||||||
|
ctest --test-dir server/build --output-on-failure
|
||||||
|
```
|
||||||
|
|
||||||
Windows:
|
Windows:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
@@ -14,91 +40,126 @@ cmake --build server/build --config Release --target GameServer
|
|||||||
ctest --test-dir server/build -C Release --output-on-failure
|
ctest --test-dir server/build -C Release --output-on-failure
|
||||||
```
|
```
|
||||||
|
|
||||||
Linux:
|
> **Memory note:** compiling Boost.Beast code can use 1-1.5 GB per translation
|
||||||
|
> unit. On a small VDS keep `--parallel 1`; if the compiler gets OOM-killed, add
|
||||||
|
> temporary swap (`sudo fallocate -l 2G /swapfile && sudo chmod 600 /swapfile &&
|
||||||
|
> sudo mkswap /swapfile && sudo swapon /swapfile`). The running server itself
|
||||||
|
> needs only a few tens of MB.
|
||||||
|
|
||||||
|
After every build the repository's `resources/` directory is copied next to the
|
||||||
|
binary (`server/build/resources`, or `server/build/Release/resources` on
|
||||||
|
Windows). Content paths are resolved from the process working directory, so the
|
||||||
|
server must be started from the directory that contains `resources/`.
|
||||||
|
|
||||||
|
## Run
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cmake -S server -B server/build -DCMAKE_BUILD_TYPE=Release
|
server/scripts/run-server.sh
|
||||||
cmake --build server/build --target GameServer --parallel
|
|
||||||
ctest --test-dir server/build --output-on-failure
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Eigen3 must either be installed or be available at
|
This does `cd server/build` and runs
|
||||||
`thirdparty/eigen-5.0.0`. The headless target reads ordinary filesystem resources
|
|
||||||
only; ZIP-backed campaign loading belongs to the later content-loading
|
|
||||||
milestone.
|
|
||||||
|
|
||||||
Run until interrupted:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./server/build/GameServer
|
./GameServer --campaign battle_zone_multiplayer --address 127.0.0.1 --port 8081
|
||||||
```
|
```
|
||||||
|
|
||||||
For a multi-configuration Windows build, the executable is normally
|
Environment overrides: `CAMPAIGN`, `LOCATION`, `ADDRESS`, `PORT`, `BUILD_DIR`.
|
||||||
`server/build/Release/GameServer.exe`.
|
|
||||||
|
|
||||||
For smoke tests, `--ticks N` limits execution and `--no-sleep` skips the
|
Windows equivalent:
|
||||||
real-time delay.
|
|
||||||
|
|
||||||
Start the multiplayer lockstep server:
|
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\server\build\Release\GameServer.exe --campaign battle_zone_multiplayer --location uni_exterior
|
.\server\build\Release\GameServer.exe --campaign battle_zone_multiplayer
|
||||||
```
|
```
|
||||||
|
|
||||||
The listener defaults to `ws://0.0.0.0:8080`. Launch the Windows graphical game
|
Command line options: `--campaign ID`, `--location ID`, `--campaigns PATH`
|
||||||
afterward and select `battle_zone_multiplayer`; that campaign connects to
|
(default `resources/config/campaigns.json`), `--address IP` (default `0.0.0.0`),
|
||||||
`ws://127.0.0.1:8080`. Other campaigns continue to use the in-process server.
|
`--port N` (default `8080`), `--ticks N` and `--no-sleep` (smoke tests).
|
||||||
|
|
||||||
The server sends one state snapshot when a player connects, then broadcasts one
|
The server sends one state snapshot when a player connects, then broadcasts one
|
||||||
numbered command bundle every 100 ms. Bundles may be empty. Destination input is
|
numbered command bundle every 100 ms. Bundles may be empty. Destination input is
|
||||||
scheduled two ticks (200 ms) in the future. Tick IDs, rather than server or
|
scheduled two ticks (200 ms) in the future. Tick IDs, rather than server or
|
||||||
client wall-clock values, define simulation time.
|
client wall-clock values, define simulation time.
|
||||||
|
|
||||||
If `--location` is omitted, the campaign's configured start location is used.
|
## Production deployment (Ubuntu, systemd + nginx)
|
||||||
`--campaigns PATH` selects a different campaign registry. Content paths are
|
|
||||||
resolved from the process working directory, so run from the repository root
|
|
||||||
when using the bundled `resources/` tree.
|
|
||||||
|
|
||||||
Available startup options:
|
The server listens on loopback only (`127.0.0.1:8081`); nginx terminates TLS and
|
||||||
|
proxies WebSocket traffic.
|
||||||
|
|
||||||
```text
|
### 1. systemd service
|
||||||
--campaign ID
|
|
||||||
--location ID
|
```bash
|
||||||
--campaigns PATH
|
sudo cp server/deploy/shadow-gameserver.service /etc/systemd/system/
|
||||||
--address IP
|
sudo systemctl daemon-reload
|
||||||
--port N
|
sudo systemctl enable --now shadow-gameserver
|
||||||
--tick-ms 100
|
systemctl status shadow-gameserver
|
||||||
--ticks N
|
journalctl -u shadow-gameserver -f # logs
|
||||||
--no-sleep
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Network mode requires a 100 ms tick; another `--tick-ms` value is rejected.
|
The unit caps memory at 512 MB and restarts on failure. After rebuilding run
|
||||||
The selected campaign's `networkPlayerSlots` lists pre-existing character IDs
|
`sudo systemctl restart shadow-gameserver`. Edit `User=`/paths in the unit if the
|
||||||
assigned to connections in order. `networkCompatibility` is a release token
|
repository lives elsewhere. To run a second server, copy the unit with another
|
||||||
that must be changed whenever deterministic content changes; clients reject a
|
`PORT` (and campaign) and add a matching `/server002/` location.
|
||||||
different token. The bundled multiplayer Battle Zone has two slots (`player`
|
|
||||||
and `player2`) and rejects additional clients. Disconnecting
|
|
||||||
releases the slot. The bot's random autonomous controller is disabled in
|
|
||||||
multiplayer.
|
|
||||||
|
|
||||||
The graphical client executes presentation behavior after building its runtime
|
### 2. nginx
|
||||||
`Location`; the headless content pass loads authoritative navigation, NPC,
|
|
||||||
interactive-object, trigger, teleport, taxi, and animation metadata. Lua and
|
|
||||||
dialogue-driven shared multiplayer behavior is not yet supported.
|
|
||||||
|
|
||||||
## Tests
|
```bash
|
||||||
|
sudo cp server/deploy/nginx-api.shadowoverbishkek.com.conf \
|
||||||
|
/etc/nginx/sites-available/api.shadowoverbishkek.com
|
||||||
|
sudo ln -s /etc/nginx/sites-available/api.shadowoverbishkek.com \
|
||||||
|
/etc/nginx/sites-enabled/
|
||||||
|
sudo nginx -t && sudo systemctl reload nginx
|
||||||
|
```
|
||||||
|
|
||||||
CTest covers:
|
`location /server001/` proxies to `http://127.0.0.1:8081/` with WebSocket
|
||||||
|
upgrade headers and a 1 hour read/send timeout (the trailing slashes strip the
|
||||||
|
`/server001` prefix).
|
||||||
|
|
||||||
- repeated `LocationGameState::setup()` preserving mutable runtime state;
|
### 3. HTTPS certificate
|
||||||
- ticking a prepared location with zero players;
|
|
||||||
- deterministic fixed-100 ms replay behavior;
|
|
||||||
- protocol-v2 parsing, validation, target normalization, state hashing, and
|
|
||||||
two-tick command ordering;
|
|
||||||
- a WebSocket initial-state/slot/destination/tick integration test;
|
|
||||||
- idle server startup;
|
|
||||||
- headless loading of `battle_zone_multiplayer/uni_exterior`.
|
|
||||||
|
|
||||||
The lockstep implementation currently targets identical executable and content
|
DNS for `api.shadowoverbishkek.com` must point at the VDS first.
|
||||||
builds. Diagnostic state hashes detect divergence, but there is no automatic
|
|
||||||
checkpoint resynchronization or reconnect input history yet.
|
```bash
|
||||||
|
sudo certbot --nginx -d api.shadowoverbishkek.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Certbot issues a Let's Encrypt certificate, adds the `443 ssl` block and an HTTP
|
||||||
|
to HTTPS redirect, and installs auto-renewal (`systemctl list-timers | grep certbot`).
|
||||||
|
|
||||||
|
## Connecting
|
||||||
|
|
||||||
|
Public endpoint: **`wss://api.shadowoverbishkek.com/server001/`**
|
||||||
|
|
||||||
|
Handshake check from any machine (expects `HTTP/1.1 101 Switching Protocols`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -i -N --max-time 3 \
|
||||||
|
-H "Connection: Upgrade" -H "Upgrade: websocket" \
|
||||||
|
-H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==" \
|
||||||
|
https://api.shadowoverbishkek.com/server001/
|
||||||
|
```
|
||||||
|
|
||||||
|
Or interactively: `npx wscat -c wss://api.shadowoverbishkek.com/server001/`.
|
||||||
|
|
||||||
|
Locally on the VDS, bypassing nginx: `ws://127.0.0.1:8081`.
|
||||||
|
|
||||||
|
> **Client limitation:** `src/game_server/WebsocketGameClient.cpp` currently
|
||||||
|
> speaks plain `ws://host:port` to `/` (no TLS, no path). Until TLS and path
|
||||||
|
> support are added to the client, the graphical game can only connect directly
|
||||||
|
> to a non-proxied server (e.g. `ws://127.0.0.1:8080`), not to the `wss://` URL.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
- `Animation metadata failed ... Invalid animation file`: the `.anim` files are
|
||||||
|
Git LFS pointer stubs (`version https://git-lfs...`). Fetch the real files with
|
||||||
|
`git lfs pull` (or copy `resources/` from a full checkout) and rebuild.
|
||||||
|
- `GameServer.LocationState` test currently fails on every platform: it expects
|
||||||
|
`battle_zone` and `battle_zone_multiplayer` to share a start-state file, but
|
||||||
|
`campaigns.json` points them to different files.
|
||||||
|
|
||||||
|
- `Server content setup failed`: the server was not started from the directory
|
||||||
|
containing `resources/` (use `run-server.sh`).
|
||||||
|
- `WebSocket listener setup failed`: port already in use (`ss -ltnp | grep 8081`).
|
||||||
|
- `502 Bad Gateway` from nginx: service not running (`systemctl status
|
||||||
|
shadow-gameserver`).
|
||||||
|
- Connection drops after ~60 s: check `proxy_read_timeout` in the nginx location.
|
||||||
|
- Compiler "Killed" / `internal compiler error`: out of memory, see the memory note.
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# Install to /etc/nginx/sites-available/api.shadowoverbishkek.com and symlink
|
||||||
|
# into sites-enabled. Then: sudo certbot --nginx -d api.shadowoverbishkek.com
|
||||||
|
server {
|
||||||
|
server_name api.shadowoverbishkek.com;
|
||||||
|
|
||||||
|
access_log /var/log/nginx/api.shadowoverbishkek.com-access.log;
|
||||||
|
error_log /var/log/nginx/api.shadowoverbishkek.com-error.log;
|
||||||
|
|
||||||
|
# wss://api.shadowoverbishkek.com/server001/ -> 127.0.0.1:8081
|
||||||
|
location /server001/ {
|
||||||
|
proxy_pass http://127.0.0.1:8081/;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_read_timeout 3600s;
|
||||||
|
proxy_send_timeout 3600s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
|
||||||
|
listen 443 ssl; # managed by Certbot
|
||||||
|
ssl_certificate /etc/letsencrypt/live/api.shadowoverbishkek.com/fullchain.pem; # managed by Certbot
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/api.shadowoverbishkek.com/privkey.pem; # managed by Certbot
|
||||||
|
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||||
|
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
if ($host = api.shadowoverbishkek.com) {
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
} # managed by Certbot
|
||||||
|
|
||||||
|
|
||||||
|
server_name api.shadowoverbishkek.com;
|
||||||
|
|
||||||
|
listen 80;
|
||||||
|
return 404; # managed by Certbot
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Shadow Over Bishkek GameServer (server001)
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=ubuntu
|
||||||
|
ExecStart=/home/ubuntu/shadowoverbishkek-work/shadow-over-bishkek001/server/scripts/run-server.sh
|
||||||
|
Environment=PORT=8081
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=3
|
||||||
|
MemoryMax=512M
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
Executable
+9
@@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Configure and build the headless GameServer (Release).
|
||||||
|
# Usage: server/scripts/build.sh (uses 1 job: safe for 2 GB RAM hosts)
|
||||||
|
# JOBS=4 server/scripts/build.sh
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
|
cmake -S "$ROOT/server" -B "$ROOT/server/build" -DCMAKE_BUILD_TYPE=Release
|
||||||
|
cmake --build "$ROOT/server/build" --target GameServer --parallel "${JOBS:-1}"
|
||||||
|
echo "Built: $ROOT/server/build/GameServer"
|
||||||
Executable
+16
@@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Start the multiplayer GameServer. Listens on loopback only; nginx proxies
|
||||||
|
# wss://api.shadowoverbishkek.com/server001/ to it.
|
||||||
|
# Overrides: CAMPAIGN, LOCATION, ADDRESS, PORT, BUILD_DIR
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
|
BUILD_DIR="${BUILD_DIR:-$ROOT/server/build}"
|
||||||
|
CAMPAIGN="${CAMPAIGN:-battle_zone_multiplayer}"
|
||||||
|
ADDRESS="${ADDRESS:-127.0.0.1}"
|
||||||
|
PORT="${PORT:-8081}"
|
||||||
|
|
||||||
|
# Content paths are resolved from the working directory.
|
||||||
|
cd "$BUILD_DIR"
|
||||||
|
ARGS=(--campaign "$CAMPAIGN" --address "$ADDRESS" --port "$PORT")
|
||||||
|
[ -n "${LOCATION:-}" ] && ARGS+=(--location "$LOCATION")
|
||||||
|
exec ./GameServer "${ARGS[@]}"
|
||||||
Reference in new issue
Block a user