Skip to content
Open
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
1 change: 1 addition & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ indent_size = 1

# Credits file
[credits.txt]
charset = UTF-8
indent_style = space
indent_size = 2

Expand Down
73 changes: 73 additions & 0 deletions .github/workflows/browser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: browser

on:
push:
pull_request:
types:
- synchronize
- opened
Comment thread
cursor[bot] marked this conversation as resolved.

env:
EM_VERSION: 6.0.6
EM_CACHE_FOLDER: 'emsdk-cache'

jobs:
build:
environment: aws-deploy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: ${{ runner.os }}-${{ env.EM_VERSION }}

- name: Cache emscripten
id: cache-emscripten
uses: actions/cache@v4
env:
cache-name: cache-emscripten
with:
path: emsdk
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.EM_VERSION }}

- name: install emsdk
if: steps.cache-emscripten.outputs.cache-hit != 'true'
run: |
git clone https://github.com/emscripten-core/emsdk.git
./emsdk/emsdk install ${{ env.EM_VERSION }}
./emsdk/emsdk activate ${{ env.EM_VERSION }}

- name: Cache libjpegturbo
id: cache-libjpegturbo
uses: actions/cache@v4
env:
cache-name: cache-libjpegturbo
with:
path: |
libjpeg-turbo-2.1.0/
2.1.0.tar.gz
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.EM_VERSION }}

- name: Cache build directory
id: cache-build
uses: actions/cache@v4
env:
cache-name: cache-build
with:
path: build
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.EM_VERSION }}

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1

- name: Build
run: source emsdk/emsdk_env.sh; make output/index.html
- name: Deploy
if: ${{ github.ref == 'refs/heads/endless-web' && github.event_name == 'push' }}
run: source emsdk/emsdk_env.sh; make deploy
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,17 @@ CMakeUserPresets.json

# static code analysis
/.scannerwork

# Emscripten web build artifacts
endless-sky.js
endless-sky.js.prehash
to-be-modified-endless-sky.*
endless-sky.data
endless-sky.wasm
endless-sky.wasm.map
dataversion.js
output/
2.1.0.tar.gz
libjpeg-turbo-2.1.0/
Ubuntu-Regular.ttf
favicon.ico
153 changes: 153 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
EMSCRIPTEN_ENV := $(shell command -v emmake 2> /dev/null)
CXX := $(shell command -v ccache 2> /dev/null > /dev/null && echo ccache em++ || echo em++)

all: dev
clean:
rm -f endless-sky.js
rm -f endless-sky.data
rm -f endless-sky.wasm
rm -f dataversion.js
rm -rf output
rm -f endless-sky.wasm.map
rm -f lib/emcc/libendless-sky.a
rm -rf build/emcc
# favicon.ico and Ubuntu-Regular.ttf are downloaded, not built. Removing them in
# 'clean' means any local serve after a clean silently loses the font until
# something re-fetches them, so they are only removed by 'distclean'.
distclean: clean
rm -rf lib/emcc
rm -rf libjpeg-turbo-2.1.0
rm -f favicon.ico
rm -f Ubuntu-Regular.ttf
2.1.0.tar.gz:
wget -nv https://github.com/libjpeg-turbo/libjpeg-turbo/archive/refs/tags/2.1.0.tar.gz
libjpeg-turbo-2.1.0: 2.1.0.tar.gz
tar xzf 2.1.0.tar.gz
libjpeg-turbo-2.1.0/libturbojpeg.a: | libjpeg-turbo-2.1.0
ifndef EMSCRIPTEN_ENV
$(error "emmake is not available, activate the emscripten env first")
endif
# ENABLE_SHARED=0: without it libjpeg-turbo also builds libjpeg.so, which '-l jpeg'
# prefers over the static archive. Since emscripten 6.0.0 disabled FAKE_DYLIBS by
# default that .so is a real dynamic library, which implies -sMAIN_MODULE=2 and
# fails the link with "relocation ... cannot be used against symbol; recompile with -fPIC".
cd libjpeg-turbo-2.1.0; emcmake cmake -G"Unix Makefiles" -DENABLE_SHARED=0 -DWITH_SIMD=0 -DCMAKE_BUILD_TYPE=Release -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -Wno-dev
cd libjpeg-turbo-2.1.0; sed 's/SIZEOF_SIZE_T [0-9]*/SIZEOF_SIZE_T 4/' jconfigint.h > jconfigint.h.tmp && mv jconfigint.h.tmp jconfigint.h
cd libjpeg-turbo-2.1.0; emmake $(MAKE)
dev: endless-sky.js dataversion.js Ubuntu-Regular.ttf favicon.ico
emrun --serve_after_close --serve_after_exit --browser chrome --private_browsing endless-sky.html
Ubuntu-Regular.ttf:
curl -Ls 'https://github.com/google/fonts/blob/main/ufl/ubuntu/Ubuntu-Regular.ttf?raw=true' > Ubuntu-Regular.ttf
favicon.ico:
wget -nv https://endless-sky.github.io/favicon.ico

COMMON_FLAGS = -O3\
-s USE_SDL=2\
-s USE_LIBPNG=1\
-s DISABLE_EXCEPTION_CATCHING=0

CFLAGS = $(COMMON_FLAGS)\
-s USE_ZLIB=1\
-Duuid_generate_random=uuid_generate\
-std=c++20\
-Wall\
-Werror\
-Wold-style-cast\
-DES_GLES\
-gsource-map\
-I libjpeg-turbo-2.1.0\

LINK_FLAGS = $(COMMON_FLAGS)\
-s USE_ZLIB=1\
-L libjpeg-turbo-2.1.0\
-l jpeg\
-lopenal\
-lidbfs.js\
--source-map-base http://localhost:6931/\
-s USE_WEBGL2=1\
-s ASSERTIONS=2\
-s GL_ASSERTIONS=1\
-s ASYNCIFY\
-s MIN_WEBGL_VERSION=2\
-s MAX_WEBGL_VERSION=2\
-s MAXIMUM_MEMORY=2147483648\
-s INITIAL_MEMORY=1347289088\
-s ALLOW_MEMORY_GROWTH=1\
--preload-file data\
--preload-file images\
--preload-file sounds\
--preload-file shaders\
--preload-file credits.txt\
--preload-file keys.txt\
-s EXPORTED_RUNTIME_METHODS=['callMain']\
--emrun

# Source files: all .cpp in source subdirs except test/, windows/, and excluded audio suppliers
# Also exclude ZipFile.cpp (no minizip in emscripten)
CPPS := $(filter-out source/ZipFile.cpp,$(shell ls source/*.cpp)) \
$(shell ls source/text/*.cpp) \
$(shell ls source/ship/*.cpp) \
$(shell ls source/audio/*.cpp) \
$(shell ls source/audio/player/*.cpp) \
$(shell ls source/audio/supplier/AudioSupplier.cpp source/audio/supplier/WavSupplier.cpp source/audio/supplier/effect/Fade.cpp) \
$(shell ls source/image/*.cpp) \
$(shell ls source/shader/*.cpp) \
$(shell ls source/comparators/*.cpp 2>/dev/null) \
$(shell ls source/orders/*.cpp 2>/dev/null) \
$(shell ls source/test/*.cpp 2>/dev/null)
CPPS_EXCEPT_MAIN := $(filter-out source/main.cpp,$(CPPS))
TEMP := $(subst source/,build/emcc/,$(CPPS))
OBJS := $(subst .cpp,.o,$(TEMP))
TEMP := $(subst source/,build/emcc/,$(CPPS_EXCEPT_MAIN))
OBJS_EXCEPT_MAIN := $(subst .cpp,.o,$(TEMP))
HEADERS := $(shell find source -name '*.h' -o -name '*.hpp' | grep -v windows/)

BUILD_DIRS := build/emcc build/emcc/text build/emcc/ship build/emcc/audio \
build/emcc/audio/player build/emcc/audio/supplier build/emcc/audio/supplier/effect \
build/emcc/image build/emcc/shader build/emcc/comparators build/emcc/orders build/emcc/test

build/emcc/%.o: source/%.cpp $(HEADERS) libjpeg-turbo-2.1.0/libturbojpeg.a
@mkdir -p $(BUILD_DIRS)
$(CXX) $(CFLAGS) -c $< -o $@

lib/emcc/libendless-sky.a: $(OBJS_EXCEPT_MAIN)
@mkdir -p lib/emcc
emar rcs lib/emcc/libendless-sky.a $(OBJS_EXCEPT_MAIN)

endless-sky.js: Makefile libjpeg-turbo-2.1.0/libturbojpeg.a lib/emcc/libendless-sky.a build/emcc/main.o
ifndef EMSCRIPTEN_ENV
$(error "em++ is not available, activate the emscripten env first")
endif
em++ -o endless-sky.js $(LINK_FLAGS) build/emcc/main.o lib/emcc/libendless-sky.a

dataversion.js: endless-sky.js
./hash-data.py endless-sky.data dataversion.js
output/index.html: endless-sky.js endless-sky.html favicon.ico Ubuntu-Regular.ttf dataversion.js js/cached-resource.js js/plugins.js js/save-games.js
rm -rf output
mkdir -p output
cp endless-sky.html to-be-modified-endless-sky.html
cp endless-sky.js to-be-modified-endless-sky.js
./copy-to-hashed-location.py endless-sky.wasm endless-sky.data output/
mkdir output/js
./copy-to-hashed-location.py js/* output/
./copy-to-hashed-location.py dataversion.js output/
./copy-to-hashed-location.py loading.mp3 output/
./copy-to-hashed-location.py Ubuntu-Regular.ttf output/
cp favicon.ico output/
# Hash endless-sky.js only after its .wasm and .data references have been
# rewritten, so the filename reflects the bytes that actually ship. Hashing it
# beforehand meant two builds differing only in C++ produced an identical
# filename of identical length, so 'aws s3 sync --size-only' silently skipped
# uploading the newer one and the site kept loading the previous wasm.
mv endless-sky.js endless-sky.js.prehash
mv to-be-modified-endless-sky.js endless-sky.js
./copy-to-hashed-location.py endless-sky.js output/
mv endless-sky.js.prehash endless-sky.js
mv to-be-modified-endless-sky.html output/index.html
test: output/index.html
cd output; emrun --serve_after_close --serve_after_exit --browser chrome --private_browsing index.html
deploy: output/index.html
aws s3 sync --size-only --exclude index.html output s3://play-endless-sky.com/live --cache-control 'public, max-age=604800, immutable'
aws s3 sync --exclude '*' --include index.html output s3://play-endless-sky.com/live --cache-control 'max-age=0'
aws cloudfront create-invalidation --distribution-id E2TZUW922XPLEF --paths / /index.html
aws cloudfront create-invalidation --distribution-id E3D0Y4DMGSVPWC --paths / /index.html
64 changes: 64 additions & 0 deletions copy-to-hashed-location.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env python

import shutil
import os
from pathlib import Path


def copy_and_add_hash(target_directory, source, files_to_modify):
import hashlib
hash_md5 = hashlib.md5()
length = 0
with open(source, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
length += len(chunk)
hash_md5.update(chunk)
hash = hash_md5.hexdigest()
if '.' in os.path.basename(source):
base, extensions = os.path.basename(source).split('.', 1)
extensions = '.' + extensions
else:
base = source
extensions = ''
dest = base + '-' + hash + extensions
copy_dest = os.path.join(target, dest)
print(source, '->', dest)

total_count = 0
for to_modify in files_to_modify:
with open(to_modify, "r+") as f:
data = f.read()
f.seek(0)
count = data.count(source)
if count:
print("replacing", count, "occurrence" + ('' if count == 1 else 's'), "of", source, 'in', to_modify)
output = data.replace(source, dest)
f.write(output)
f.truncate()
total_count += count
if total_count == 0:
raise ValueError(repr(files_to_modify) + " do not contain source '"+source+"' to modify!")

shutil.copy(source, copy_dest)

if __name__ == '__main__':
FILES_TO_MODIFY = [
"to-be-modified-endless-sky.html",
"to-be-modified-endless-sky.js"
]

import sys
target = sys.argv[-1]
if target[-1] == '/':
target = target[:-1]
sources = sys.argv[1:-1]
if not os.path.isdir(target):
raise ValueError("dest must be a directory")
# endless-sky.js is hashed last, after it has itself been rewritten and moved
# into place, so by then it is no longer available to be modified. Skip any
# file that has already been consumed, but require at least one to remain.
FILES_TO_MODIFY = [f for f in FILES_TO_MODIFY if os.path.exists(f)]
if not FILES_TO_MODIFY:
raise ValueError("none of the files to modify exist")
for source in sources:
copy_and_add_hash(target, source, FILES_TO_MODIFY)
4 changes: 4 additions & 0 deletions credits.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ Developers
W1zrad
Zitchas

WebAssembly Port
Michał Janiszewski (janisozaur)
Thomas Ballinger

Major Programming
AdamKauffman
Amazinite
Expand Down
22 changes: 22 additions & 0 deletions docs/readme-developer.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,25 @@ $ cmake -G Xcode --preset macos # macos-arm for Apple Silicon
```

The XCode project is located in the `build/` directory.

## Building for the web

Mac and Linux (Windows not supported):

Install Emscripten following the instructions at https://emscripten.org/docs/getting_started/downloads.html
Use the latest version and source the emsdk_env.sh file so you can run commands like emcc, em++ and emmake.
The last time I checked, this looked like:

```
$ git clone https://github.com/emscripten-core/emsdk.git
$ cd emsdk
$ ./emsdk install 6.0.6
$ ./emsdk activate 6.0.6
$ source ./emsdk_env.sh # you'll need to run this one each time you open a new terminal
```

Now back in the endless-sky repo directory run: (maybe you need to install make, wget, and tar first? I figure those should be everywhere already)

```
$ make dev
```
Loading
Loading