#!/usr/bin/env bash # Compila o AstroMenace do fredygames.com: o shooter 3D da Viewizard (codigo GPL-3.0-or-later; dados # GPL-3 e CC BY-SA 4.0, ver LICENSE.md do jogo) em WebAssembly, com o Emscripten 6.0.10 e as portas # SDL2 2.32.10, libogg 1.3.5, libvorbis 1.3.7 e FreeType 2.14.3 dele, o OpenAL do proprio Emscripten # e o gl4es (MIT), que emula o OpenGL 1.x/2.x do jogo sobre o WebGL. Este script e o patch fazem parte # do codigo-fonte publicado junto do jogo. # # source /emsdk_env.sh # emsdk install 6.0.10 && emsdk activate 6.0.10 # src/FredGames.Bundler/Builds/build-astromenace.sh # # Fontes: os tarballs do GitHub dos commits fixos abaixo (o ultimo do jogo e o do gl4es usado), # conferidos pelo SHA-256 e guardados em artifacts/cache/astromenace/ (o site hospeda os mesmos # arquivos). Na pasta de fontes do site, o script acha os tarballs e o patch ao lado dele. # # astromenace-fredygames.patch (so ativo com __EMSCRIPTEN__): # - gl4es: initialize_gl4es() logo depois de criar o contexto, e as extensoes do OpenGL pedidas ao # gl4es (gl4es_GetProcAddress) em vez do navegador; sem gluBuild2DMipmaps (nao ha GLU, e o gl4es # sempre tem glGenerateMipmap); glu_web.cpp com as outras duas funcoes da GLU que o jogo usa # (gluPerspective e gluLookAt); # - alut_web.h no lugar do freealut (LGPL, ausente no Emscripten): as cinco chamadas que o jogo usa, # com um leitor de WAV PCM; # - emscripten_sleep(0) a cada quadro (o jogo tem lacos proprios; o build usa Asyncify); # - na primeira vez o jogo abre em janela, nao em tela cheia (a pagina estica o canvas ate o player); # - fredygames_save(), que a pagina chama quando a aba some ou fecha: o jogo so grava os perfis ao # trocar entre menu e missao e ao sair. # # gamedata.vfs: o pacote de dados que o proprio jogo gera ("astromenace --pack"), aqui com as mesmas # duas fontes do jogo (vfs.cpp e fs2vfs.cpp) compiladas para o Node.js, que le gamedata/ do tarball. # # Saida: artifacts/build/astromenace-/astromenace.{js,wasm} e gamedata.vfs, que o bundle.yaml # do jogo confere pelo SHA-256. set -euo pipefail COMMIT=bbdb3ac5af2774c92b85c4d9b2a238f606911e66 GAME_SHA256=9c9b5ba756f7a826e5a0d04cac43c5407e8b29727a739f3404f12a9803d99cac GL4ES_COMMIT=a025615bc79ac43ec911dced8fe5b8eb45a0b72d GL4ES_SHA256=b4e68ee01c45c114d89d0df290618ea7aa6f4078db11c276a893af39b9ad9b76 GL4ES_DATE=1791993939 # data do commit do gl4es (2026-10-14 16:05:39 UTC) EMSCRIPTEN=6.0.10 here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" root="$(git -C "$here" rev-parse --show-toplevel 2>/dev/null || pwd)" out="$root/artifacts/build/astromenace-${COMMIT:0:10}" cache="$root/artifacts/cache/astromenace" 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 # Arquivo auxiliar: em astromenace/ (repositorio) ou ao lado do script (pasta de fontes do site). aux() { if [ -f "$here/astromenace/$1" ]; then echo "$here/astromenace/$1"; else echo "$here/$1"; fi } # Tarball conferido: ao lado do script, no cache ou baixado do GitHub. fetch() { # local file if [ -f "$here/$1" ]; then file="$here/$1" else file="$cache/$1" if [ ! -f "$file" ]; then mkdir -p "$cache" curl -fsSL -o "$file.part" "$2" mv "$file.part" "$file" fi fi echo "$3 $file" | shasum -a 256 -c - >&2 echo "$file" } game_tar="$(fetch "astromenace-${COMMIT:0:10}.tar.gz" \ "https://github.com/viewizard/astromenace/archive/$COMMIT.tar.gz" "$GAME_SHA256")" gl4es_tar="$(fetch "gl4es-${GL4ES_COMMIT:0:10}.tar.gz" \ "https://github.com/ptitSeb/gl4es/archive/$GL4ES_COMMIT.tar.gz" "$GL4ES_SHA256")" rm -rf "$out" mkdir -p "$out/obj" tar xzf "$game_tar" -C "$out" tar xzf "$gl4es_tar" -C "$out" src="$out/astromenace-$COMMIT" gl4es="$out/gl4es-$GL4ES_COMMIT" patch -d "$src" -p1 --no-backup-if-mismatch < "$(aux astromenace-fredygames.patch)" # O gl4es grava a data do build (__DATE__ e __TIME__); com SOURCE_DATE_EPOCH o Clang usa a do commit. # Os caminhos dos fontes (__FILE__) saem relativos a pasta de saida (-ffile-prefix-map), para o # resultado nao depender de onde o repositorio esta. export SOURCE_DATE_EPOCH=$GL4ES_DATE # gl4es como biblioteca estatica (receita do COMPILE.md dele para Emscripten). ( cd "$gl4es" emcmake cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DNOX11=ON -DNOEGL=ON -DSTATICLIB=ON \ -DCMAKE_C_FLAGS="-ffile-prefix-map=$out/=" >/dev/null cmake --build build -j 8 >/dev/null ) # Jogo: as opcoes do CMakeLists.txt dele (C++11, sem excecoes, sem RTTI), em Release. flags=(-O2 -DNDEBUG -ffile-prefix-map="$out/=" -std=c++11 -fno-exceptions -fno-rtti -w -I"$gl4es/include" -sUSE_SDL=2 -sUSE_OGG=1 -sUSE_VORBIS=1 -sUSE_FREETYPE=1) ( cd "$src" find src -name '*.cpp' | LC_ALL=C sort > "$out/sources.txt" # Compila em paralelo; cada objeto leva o caminho do fonte no nome, para a ordem do link ser fixa. OBJ="$out/obj" xargs -P 8 -n 1 bash -c \ 'f="${!#}"; em++ "${@:1:$#-1}" -c "$f" -o "$OBJ/$(echo "$f" | tr / _).o"' bash "${flags[@]}" \ < "$out/sources.txt" objs=() while read -r f; do objs+=("$out/obj/$(echo "$f" | tr / _).o"); done < "$out/sources.txt" em++ "${flags[@]}" "${objs[@]}" "$gl4es/lib/libGL.a" -lopenal -lidbfs.js \ -sFULL_ES2=1 -sASYNCIFY -sALLOW_MEMORY_GROWTH -sINITIAL_MEMORY=256MB -sSTACK_SIZE=1MB \ -sENVIRONMENT=web -sEXIT_RUNTIME=1 \ -sEXPORTED_RUNTIME_METHODS=FS,addRunDependency,removeRunDependency \ -o "$out/astromenace.js" ) # gamedata.vfs com o empacotador do proprio jogo, rodando no Node.js. ( cd "$src" cat > "$out/pack.cpp" <<'EOF' #include "utils/fs2vfs.h" int main(int argc, char **argv) { return argc == 3 ? viewizard::astromenace::ConvertFS2VFS(argv[1], argv[2]) : 2; } EOF em++ -O2 -std=c++11 -fno-exceptions -fno-rtti -w -Isrc -sNODERAWFS=1 -sENVIRONMENT=node \ -sALLOW_MEMORY_GROWTH "$out/pack.cpp" src/utils/fs2vfs.cpp src/core/vfs/vfs.cpp -o "$out/pack.js" node "$out/pack.js" "$src/gamedata/" "$out/gamedata.vfs" >/dev/null ) shasum -a 256 "$out/astromenace.js" "$out/astromenace.wasm" "$out/gamedata.vfs"