#!/usr/bin/env bash # Compila o Endless Sky do fredygames.com: Endless Sky 0.11.3 (GPL-3.0-or-later) em WebAssembly, com # o Emscripten 6.0.10, as portas SDL2 2.32.10, libpng 1.6.58 e zlib 1.3.2 dele, a libwebp 1.6.0 # (BSD-3-Clause, so o decodificador) e o OpenAL do proprio Emscripten (library_openal.js). Este # script, os arquivos em endless-sky/ e o patch sao parte do codigo-fonte publicado junto do jogo # ("the scripts used to control compilation" da GPL). # # source /emsdk_env.sh # emsdk install 6.0.10 && emsdk activate 6.0.10 # src/FredGames.Bundler/Builds/build-endless-sky.sh [--source ] # # Fonte do jogo: o tarball original da tag v0.11.3 (baixado do GitHub se --source nao for dado) ou o # endless-sky-0.11.3-pruned.tar.gz que o fredygames.com hospeda (o mesmo, sem os 137 arquivos de # imagem que este build deixa de fora; lista em removed-images.txt). Os dois geram os mesmos bytes. # Na pasta de fontes do site os arquivos ficam todos lado a lado: o script acha o patch, os scripts # Python, a lista e os tarballs ao lado dele (ou em endless-sky/, no repositorio) e, sem --source, usa # o pruned que estiver ao lado dele. # # Saida: artifacts/build/endless-sky-0.11.3/endless-sky.{js,wasm,data}, que o bundle.yaml do jogo # confere pelo SHA-256. Tambem precisa do cmake (libwebp) e do Python de artifacts/tools/venv # (Pillow 12.3.0, com FreeType 2.14.3 e libwebp 1.6.0) para preparar as imagens. # # Base: o port "endless-web" de Thomas Ballinger (github.com/thomasballinger/endless-web, GPL-3.0, # commits 0d8dea4 e 8678fa5, de fevereiro de 2026). O endless-sky-fredygames.patch traz as mudancas # de C++ desse port que este build usa e as nossas: # - TaskQueue sem threads: as tarefas rodam na hora, na thread principal (endless-web); o # carregamento de sons tambem (endless-web); sem musica nem som ambiente (endless-web: o MP3/FLAC # tocaria numa thread propria), por isso sounds/ambient fica de fora; # - sem zip (minizip): plugins nao existem no navegador (endless-web); # - imagens em WebP no lugar de PNG/JPG (libwebp; sem libjpeg nem libavif) (nosso); # - a janela comeca do tamanho da pagina e nunca em tela cheia (nosso; endless-web: sem o aviso de # resolucao minima); se o quadro do player for menor do que a interface precisa a 100% (cerca de # 1000 x 500), o zoom desce abaixo de 100% para os menus caberem (nosso); o FrameTimer devolve o resto do quadro ao navegador com emscripten_sleep # (nosso); as preferencias sao gravadas ao sair da tela de preferencias, porque a aba costuma ser # fechada sem sair pelo menu (nosso); "abrir pasta" nao faz nada (nosso). # Os saves e as preferencias ficam em /home/web_user/endless-sky, que a pagina monta no IndexedDB # (IDBFS com autoPersist); os dados do jogo ficam em /es, no endless-sky.data. # # Arquivos do jogo (prepare-assets.py), na regra "na duvida, fica de fora": saem as 37 # imagens sob a "Unsplash License", as 90 que o copyright do jogo atribui ao morgueFile (as estrofes # genericas de images/land/* e images/scene/*) e as 10 capturas de cenarios feitos com assets # comprados na Unity Asset Store (land/sivael*), com as linhas de dados que apontam para elas # (paisagens, cenas de conversas, miniaturas de cenarios); as duas fontes em bitmap (desenhos da # fonte Ubuntu) sao redesenhadas com a DejaVu Sans 2.37 (endless-sky/make-font.py); o resto das # imagens vira WebP (qualidade 80, alfa sem # perda; interface e mascaras sem perda); sons em WAV como estao. # # Opcoes: -sASYNCIFY (o laco principal do jogo nao retorna; o SDL_GL_SwapWindow e o FrameTimer cedem # a vez ao navegador), excecoes de C++ pelo JavaScript (o jogo usa excecoes), WebGL 2 (o jogo usa # OpenGL ES 3.0, -DES_GLES), sem threads (sem SharedArrayBuffer, sem COOP/COEP), -lidbfs.js. set -euo pipefail VERSION=0.11.3 EMSCRIPTEN=6.0.10 ES_SHA256=2c3b887ca0c4d856566ce5be3d529ad1a28540ba254cee1a540dae4e8d638c07 # endless-sky-0.11.3-pruned.tar.gz (gerado pelo FredGames.Bundler a partir do original, deterministico). PRUNED_SHA256=a69c0a39027f11fab072f12f67591626a7d22ba634a7cc88214f7df3f295d25b WEBP_VERSION=1.6.0 WEBP_SHA256=e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 DEJAVU_SHA256=fa9ca4d13871dd122f61258a80d01751d603b4d3ee14095d65453b4e846e17d7 # Resultado de make-font.py (outra Pillow/FreeType rasteriza diferente). FONT14_SHA256=9f957c2e4bf057829a6378cdfbf09dd080dbd5fe904926ca65607e191f80d7c7 FONT18_SHA256=44f1d2c34cba0f66aaa4a8bea4fafd03015e1ae1238dbde494ad8f8f3725663a here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source_tarball="" while [ $# -gt 0 ]; do case "$1" in --source) source_tarball="$(cd "$(dirname "$2")" && pwd)/$(basename "$2")"; shift 2 ;; *) echo "Uso: $0 [--source ]" >&2; exit 2 ;; esac done # Arquivos auxiliares: em endless-sky/ (repositorio) ou ao lado do script (pasta de fontes do site). aux() { if [ -f "$here/endless-sky/$1" ]; then echo "$here/endless-sky/$1" elif [ -f "$here/$1" ]; then echo "$here/$1" else echo "Falta $1 (em $here/endless-sky/ ou $here/)." >&2; exit 1; fi } patch_file="$(aux endless-sky-fredygames.patch)" make_font="$(aux make-font.py)" prepare_assets="$(aux prepare-assets.py)" aux removed-images.txt > /dev/null if [ -z "$source_tarball" ] && [ -f "$here/endless-sky-0.11.3-pruned.tar.gz" ]; then source_tarball="$here/endless-sky-0.11.3-pruned.tar.gz" fi root="$(git -C "$here" rev-parse --show-toplevel 2>/dev/null || pwd)" out="$root/artifacts/build/endless-sky-$VERSION" dl="$out/dl" python="${PYTHON:-$root/artifacts/tools/venv/bin/python}" jobs="$(sysctl -n hw.ncpu 2>/dev/null || nproc)" if ! emcc --version 2>/dev/null | head -1 | grep -q " $EMSCRIPTEN "; then echo "Precisa do Emscripten $EMSCRIPTEN no PATH (source /emsdk_env.sh)." >&2 exit 1 fi mkdir -p "$dl" fetch() { # url arquivo sha256 (usa a copia ao lado do script, se houver) [ -f "$dl/$2" ] || { [ -f "$here/$2" ] && cp "$here/$2" "$dl/$2"; } || curl -fsSL "$1" -o "$dl/$2" echo "$3 $dl/$2" | shasum -a 256 -c - } if [ -n "$source_tarball" ]; then es_sha="$(shasum -a 256 "$source_tarball" | cut -d' ' -f1)" if [ "$es_sha" != "$ES_SHA256" ] && [ "$es_sha" != "$PRUNED_SHA256" ]; then echo "$source_tarball nao e o tarball original nem o pruned do Endless Sky $VERSION ($es_sha)." >&2 exit 1 fi es_tarball="$source_tarball" else fetch "https://github.com/endless-sky/endless-sky/archive/refs/tags/v$VERSION.tar.gz" \ "endless-sky-$VERSION.tar.gz" "$ES_SHA256" es_tarball="$dl/endless-sky-$VERSION.tar.gz" fi echo "Fonte do jogo: $es_tarball" fetch "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$WEBP_VERSION.tar.gz" \ "libwebp-$WEBP_VERSION.tar.gz" "$WEBP_SHA256" fetch https://github.com/dejavu-fonts/dejavu-fonts/releases/download/version_2_37/dejavu-fonts-ttf-2.37.tar.bz2 \ dejavu-fonts-ttf-2.37.tar.bz2 "$DEJAVU_SHA256" rm -rf "$out/source" "$out/libwebp" "$out/dejavu" "$out/font" "$out/assets" "$out/obj" mkdir -p "$out/source" "$out/libwebp" "$out/dejavu" "$out/obj" tar -xzf "$es_tarball" -C "$out/source" --strip-components 1 tar -xzf "$dl/libwebp-$WEBP_VERSION.tar.gz" -C "$out/libwebp" --strip-components 1 tar -xjf "$dl/dejavu-fonts-ttf-2.37.tar.bz2" -C "$out/dejavu" --strip-components 1 patch -d "$out/source" -p1 --no-backup-if-mismatch < "$patch_file" # Fontes redesenhadas e arquivos do jogo. "$python" "$make_font" "$out/source/images/font" "$out/dejavu/ttf/DejaVuSans.ttf" "$out/font" echo "$FONT14_SHA256 $out/font/ubuntu14r.png" | shasum -a 256 -c - echo "$FONT18_SHA256 $out/font/ubuntu18r.png" | shasum -a 256 -c - "$python" "$prepare_assets" "$out/source" "$out/font" "$out/assets" # libwebp: so o decodificador (libwebpdecoder.a), sem SIMD (o WebAssembly SIMD ficaria de fora em # navegadores antigos). ( cd "$out/libwebp" emcmake cmake -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DWEBP_ENABLE_SIMD=OFF \ -DWEBP_BUILD_ANIM_UTILS=OFF -DWEBP_BUILD_CWEBP=OFF -DWEBP_BUILD_DWEBP=OFF -DWEBP_BUILD_GIF2WEBP=OFF \ -DWEBP_BUILD_IMG2WEBP=OFF -DWEBP_BUILD_VWEBP=OFF -DWEBP_BUILD_WEBPINFO=OFF -DWEBP_BUILD_LIBWEBPMUX=OFF \ -DWEBP_BUILD_WEBPMUX=OFF -DWEBP_BUILD_EXTRAS=OFF -DWEBP_USE_THREAD=OFF > cmake.log emmake make -C build -j"$jobs" webpdecoder > make.log ) # Os cabecalhos da zlib, da libpng e do SDL2 so entram no sysroot quando as portas sao compiladas. embuilder build zlib libpng sdl2 > /dev/null # O jogo: todos os .cpp de source/, menos Windows, zip e os decodificadores de musica (MP3/FLAC). # Caminhos relativos e ordem fixa: o resultado e o mesmo a cada build. cd "$out/source" cflags=(-O2 -std=c++20 -fexceptions -DES_GLES -DNDEBUG -Duuid_generate_random=uuid_generate -sUSE_SDL=2 -sUSE_LIBPNG=1 -sUSE_ZLIB=1 -I../libwebp/src -Wno-deprecated-declarations) LC_ALL=C find source -name '*.cpp' ! -path 'source/windows/*' ! -name ZipFile.cpp \ ! -name FlacSupplier.cpp ! -name Mp3Supplier.cpp | LC_ALL=C sort > ../sources.txt while read -r src; do obj="../obj/${src%.cpp}.o" mkdir -p "$(dirname "$obj")" printf '%s\0%s\0' "$src" "$obj" done < ../sources.txt | CFLAGS="${cflags[*]}" xargs -0 -n 2 -P "$jobs" sh -c 'em++ $CFLAGS -c "$1" -o "$2"' sh objs=() while read -r src; do objs+=("../obj/${src%.cpp}.o"); done < ../sources.txt # Os arquivos do jogo vao para /es no endless-sky.data (--preload-file). cd "$out" em++ -O2 -fexceptions "${objs[@]/#..\//}" libwebp/build/libwebpdecoder.a \ -sUSE_SDL=2 -sUSE_LIBPNG=1 -sUSE_ZLIB=1 -lopenal -lidbfs.js \ -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 \ -sASYNCIFY -sASYNCIFY_STACK_SIZE=1048576 -sSTACK_SIZE=8388608 \ -sINITIAL_MEMORY=268435456 -sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=2147483648 \ -sEXIT_RUNTIME=1 -sENVIRONMENT=web \ -sEXPORTED_RUNTIME_METHODS=FS,addRunDependency,removeRunDependency \ --preload-file assets@/es \ -o endless-sky.js shasum -a 256 endless-sky.js endless-sky.wasm endless-sky.data