#!/usr/bin/env bash # Compila o Holotz's Castle do fredygames.com: o jogo de plataforma de Juan Carlos Seijo Perez (codigo, # historia, graficos, animacoes e musica sob a GPL-2.0-or-later; a biblioteca JLib dele sob a # LGPL-2.0-or-later; fonte Holotz Sans derivada da Bitstream Vera) em WebAssembly, com o Emscripten 6.0.10 # e as portas SDL2 2.32.10, SDL2_image 2.6.0, SDL2_ttf 2.20.2 (FreeType 2.14.3, HarfBuzz 3.2.0), # SDL2_mixer 2.8.0 e zlib 1.3.2 dele. Este script, o patch e a camada de compatibilidade # (holotz-castle/compat) 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-holotz-castle.sh # # Fonte: o tarball da versao 1.3.14 (o site do autor, mainreactor.net, saiu do ar; o arquivo e o que o # Debian guarda como holotz-castle_1.3.14.orig.tar.gz) e os patches do pacote do Debian # (holotz-castle_1.3.14-13.debian.tar.xz: correcoes para compiladores novos, aplicadas na ordem do # debian/patches/series), conferidos pelo SHA-256 e guardados em artifacts/cache/holotz-castle/. O site # hospeda o tarball do jogo sem a pasta res/stories/milanb (fases extras de outro autor, que nao # publicou uma licenca para elas); o script aceita os dois. Na pasta de fontes do site, o script acha # tudo ao lado dele. # # O jogo e escrito para o SDL 1.2. A camada de compatibilidade, escrita para este build # (compat/hcsdl12.h e .c, e os cabecalhos SDL*.h, que incluem o do SDL2 e a camada): a tela de 640x480 # numa superficie de 16 bits (a profundidade padrao do jogo) que cada SDL_Flip envia ao canvas, o # teclado indexado pelos codigos do SDL 1.2, o caractere digitado e as funcoes de superficie do SDL 1.2 # (alfa, formato da tela). Ela tambem faz o SDL_FreeSurface ignorar a tela, como no SDL 1.2. # holotz-castle-fredygames.patch (so ativo com __EMSCRIPTEN__, salvo a ultima linha): # - JLib: a cor transparente e o alfa vem da camada (no SDL2 nao ficam no formato), sem os eventos de # janela do SDL 1.2, o laco principal cede a vez ao navegador entre os quadros, e Printf deixa de # tomar o retorno 0 do fputs da musl como erro; # - HolotzCastle.cpp: sem o menu de video (resolucao, cores e tela cheia; a pagina escala a tela e # tem o proprio botao de tela cheia); # - res/playlist.txt: so a historia do jogo, sem a "milanb". # Os dados de res/ vao num hc.data que o proprio Emscripten carrega (--preload-file) em # /usr/share/games/holotz-castle/game; opcoes e jogos salvos ficam em /home/web_user/.holotz-castle. # # Saida: artifacts/build/holotz-castle-1.3.14/hc.{js,wasm,data}, que o bundle.yaml do jogo confere pelo # SHA-256. set -euo pipefail VERSION=1.3.14 SRC_SHA256=42903559a9821b39eac6eba7730be0fcba12c9ad861ba2691f372c54371039b1 PRUNED_SHA256=7393d1c7627e55a2bfb4cf086d605912db79e00f7be2f7c9bd5a6d0049e48b34 DEBIAN_SHA256=2900579f3d7294d3ca0cca0e4953032119d1ba4768b56d33d1318ef18fdfe01d 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/holotz-castle-$VERSION" cache="$root/artifacts/cache/holotz-castle" tarball="holotz-castle_$VERSION.orig.tar.gz" pruned="holotz-castle-$VERSION-pruned.tar.gz" debian="holotz-castle_$VERSION-13.debian.tar.xz" pool="https://deb.debian.org/debian/pool/main/h/holotz-castle" 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 holotz-castle/ ou holotz-castle/compat/ (repositorio) ou ao lado do script (pasta # de fontes do site, onde tudo fica numa pasta so). aux() { local f for f in "$here/holotz-castle/$1" "$here/holotz-castle/compat/$1" "$here/$1"; do if [ -f "$f" ]; then echo "$f"; return; fi done echo "Nao achei $1." >&2 exit 1 } # Arquivo baixado: ao lado do script ou no cache, conferido pelo SHA-256. fetch() { local name="$1" url="$2" sha="$3" file if [ -f "$here/$name" ]; then file="$here/$name" else file="$cache/$name" if [ ! -f "$file" ]; then mkdir -p "$cache" curl -fsSL -o "$file.part" "$url" mv "$file.part" "$file" fi fi echo "$sha $file" | shasum -a 256 -c - >&2 echo "$file" } if [ -f "$here/$pruned" ]; then game_tar="$here/$pruned" echo "$PRUNED_SHA256 $game_tar" | shasum -a 256 -c - >&2 else game_tar="$(fetch "$tarball" "$pool/$tarball" "$SRC_SHA256")" fi debian_tar="$(fetch "$debian" "$pool/$debian" "$DEBIAN_SHA256")" rm -rf "$out" mkdir -p "$out/work/compat/SDL" "$out/work/obj" tar xzf "$game_tar" -C "$out/work" G="$out/work/holotz-castle-$VERSION-src" C="$out/work/compat" rm -rf "$G/res/stories/milanb" tar xJf "$debian_tar" -C "$out/work" while read -r name level; do [ -n "$name" ] || continue patch -d "$G" "${level:--p1}" --no-backup-if-mismatch < "$out/work/debian/patches/$name" >&2 done < "$out/work/debian/patches/series" patch -d "$G" -p1 --binary --no-backup-if-mismatch < "$(aux holotz-castle-fredygames.patch)" >&2 for f in hcsdl12.h hcsdl12.c SDL.h SDL_image.h SDL_mixer.h SDL_ttf.h SDL_endian.h SDL_thread.h; do cp "$(aux "$f")" "$C/$f" done printf '#include "../SDL.h"\n' > "$C/SDL/SDL.h" PORTS=(-sUSE_SDL=2 -sUSE_SDL_IMAGE=2 -sSDL2_IMAGE_FORMATS='["tga","bmp"]' -sUSE_SDL_TTF=2 -sUSE_SDL_MIXER=2 -sSDL2_MIXER_FORMATS='[]' -sUSE_ZLIB=1) FLAGS=(-O2 -w -fexceptions -fno-strict-aliasing -ffile-prefix-map="$out/work/=" "${PORTS[@]}" -I"$C" -I"$G/JLib" -I"$G/src" -DHC_DATA_DIR='"/usr/share/games/holotz-castle/game/"' -DHCED_DATA_DIR='"/usr/share/games/holotz-castle/editor/"') # Arquivos: a parte da JLib que o jogo usa (sem as classes de OpenGL), os do jogo (sem o editor) e a # camada. objs=() jobs=0 add() { # arquivo local f="$1" rel o rel="${f#"$out/work/"}" o="$out/work/obj/${rel//\//_}.o" objs+=("$o") case "$f" in *.c) emcc "${FLAGS[@]}" -c "$f" -o "$o" & ;; *) em++ -std=gnu++98 "${FLAGS[@]}" -c "$f" -o "$o" & ;; esac jobs=$((jobs + 1)) if [ "$jobs" -ge 8 ]; then wait; jobs=0; fi } for f in Graphics/JControl Graphics/JUI Graphics/JControlImage Graphics/JImage Graphics/JImageSprite \ Graphics/JSprite Graphics/JFont Graphics/JTextMenu Graphics/JImageMenu Util/JFile Util/JObject \ Util/JTextFile Util/JTextUtil Util/JTimer Util/JUtil Util/JApp Util/JFS Util/JThread Util/JRW \ Math/J2DPolygon; do add "$G/JLib/JLib/$f.cpp" done for f in HolotzCastle HCUtil HCTimer HCLoadSaveSlot HCPlaylist HCPreferences HCTheme HCText HCBreak HCRope \ HCContFloor HCObject HCMap HCExit HCCharacter HCEnemy HCEnemyBall HCEnemyChaser HCEnemyMaker \ HCEnemyRandom HCEnemyStatic HCScriptAction HCScriptBlock HCScript HCLevel; do add "$G/src/$f.cpp" done add "$C/hcsdl12.c" wait for o in "${objs[@]}"; do [ -f "$o" ] || { echo "Falhou: $o" >&2; exit 1; }; done # Liga de dentro da pasta de saida, com caminhos relativos: o carregador do hc.data guarda o nome que a # pasta tem aqui. mkdir -p "$out/game" cp -R "$G/res/." "$out/game/" ( cd "$out" em++ -O2 -fexceptions "${objs[@]}" "${PORTS[@]}" -lidbfs.js -sASYNCIFY -sALLOW_MEMORY_GROWTH=1 \ -sENVIRONMENT=web -sEXIT_RUNTIME=1 \ -sEXPORTED_RUNTIME_METHODS=FS,ENV,addRunDependency,removeRunDependency \ --preload-file game@/usr/share/games/holotz-castle/game \ -o hc.js ) rm -rf "$out/game" "$out/work" shasum -a 256 "$out/hc.js" "$out/hc.wasm" "$out/hc.data"