#!/usr/bin/env bash # Compila o TecnoballZ do fredygames.com: o quebra-tijolos da TLK Games (codigo, graficos, sons e musica # sob a GPL-3.0-or-later; README, AUTHORS e o debian/copyright do Debian main) em WebAssembly, com o # Emscripten 6.0.10 e as portas SDL2 2.32.10, SDL2_image 2.6.0 (libpng 1.6.58, zlib 1.3.2), SDL2_mixer # 2.8.0 e libmodplug 11022021 dele, mais o TinyXML 2.6.2 (zlib) compilado aqui. Este script, o patch e # a camada de compatibilidade (tecnoballz/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-tecnoballz.sh # # Fonte: o tarball da versao 0.93.1 (tecnoballz-0.93.1.tgz, publicado pela TLK Games em linux.tlk.fr) e o # tinyxml_2_6_2.zip (SourceForge), conferidos pelo SHA-256 e guardados em artifacts/cache/tecnoballz/ (o # site hospeda os mesmos arquivos). Na pasta de fontes do site, o script acha tudo ao lado dele. # # O jogo e escrito para o SDL 1.2, que nao tem porta no Emscripten, e toca a musica pelo MikMod do # SDL_mixer 1.2 (pula para uma posicao do modulo e le a posicao tocada nas estruturas internas do # SDL_mixer). A camada de compatibilidade, escrita para este build: # - compat/SDL/SDL.h, SDL_image.h e SDL_mixer.h: o jogo inclui "SDL/SDL.h"; estes vem primeiro no # caminho de include e trazem o SDL2 mais a camada, sem mudar os includes do jogo; # - tbzsdl12.h/.c: o pedaco da API do SDL 1.2 que o jogo usa (tela de 8 bits com paleta, convertida # para uma textura a cada quadro, que tambem devolve a vez ao navegador; estado do teclado pelos # simbolos do SDL 1.2; o mouse travado pelo navegador quando o jogo "agarra" o ponteiro); # - tbzmusic.h/.c e mikmod.h: a musica tocada pela libmodplug por Mix_HookMusic, que sabe pular para # uma ordem do modulo e dizer a ordem e a linha tocadas (o que o jogo lia do MikMod). # tecnoballz-fredygames.patch (so ativo com __EMSCRIPTEN__): # - handler_audio.cc pega a posicao da musica da camada, no lugar das estruturas do SDL_mixer; # - handler_display.cc deixa de imprimir dois campos que o SDL2 nao tem (numa funcao de diagnostico); # - configfile.cc fecha o arquivo de configuracao depois de grava-lo (o original nao o fecha, e o # conteudo so chegava ao disco quando o programa terminava, o que uma aba do navegador nunca faz); # - main.cc ganha fredygames_save(), que a pagina chama quando a aba some ou fecha: o jogo so grava a # configuracao ao sair (os recordes ele grava na hora). # config.h: as definicoes que o configure geraria, escritas aqui. Os dados de src/TecnoballZ vao num # tecnoballz.data que o proprio Emscripten carrega (--preload-file) em /data; configuracao e recordes # ficam em /home/web_user/.config/tlk-games. # # Saida: artifacts/build/tecnoballz-0.93.1/tecnoballz.{js,wasm,data}, que o bundle.yaml do jogo confere # pelo SHA-256. set -euo pipefail VERSION=0.93.1 SRC_SHA256=5915bbe9efbf79713f2b0bb23a3cd33c54272b03739db22b52bcf5e1f9ef82e8 TINYXML_SHA256=ac6bb9501c6f50cc922d22f26b02fab168db47521be5e845b83d3451a3e1d512 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/tecnoballz-$VERSION" cache="$root/artifacts/cache/tecnoballz" 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 tecnoballz/ ou tecnoballz/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/tecnoballz/$1" "$here/tecnoballz/compat/$1" "$here/tecnoballz/compat/SDL/$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" } game_tar="$(fetch "tecnoballz-$VERSION.tgz" \ "https://linux.tlk.fr/games/TecnoballZ/download/tecnoballz-$VERSION.tgz" "$SRC_SHA256")" tinyxml_zip="$(fetch tinyxml_2_6_2.zip \ "https://downloads.sourceforge.net/project/tinyxml/tinyxml/2.6.2/tinyxml_2_6_2.zip" "$TINYXML_SHA256")" rm -rf "$out" mkdir -p "$out/work/compat/SDL" "$out/work/obj" tar xzf "$game_tar" -C "$out/work" unzip -q "$tinyxml_zip" -d "$out/work" G="$out/work/tecnoballz-$VERSION" X="$out/work/tinyxml" C="$out/work/compat" patch -d "$G" -p1 --no-backup-if-mismatch < "$(aux tecnoballz-fredygames.patch)" >&2 for f in tbzsdl12.h tbzsdl12.c tbzmusic.h tbzmusic.c mikmod.h; do cp "$(aux "$f")" "$C/$f"; done for f in SDL.h SDL_image.h SDL_mixer.h; do cp "$(aux "$f")" "$C/SDL/$f"; done cat > "$G/config.h" <<'EOF' #define HAVE_STDINT_H 1 #define HAVE_STDLIB_H 1 #define HAVE_STRING_H 1 #define HAVE_SYS_TIME_H 1 #define PACKAGE_STRING "TECNOBALLZ 0.93.1" #define VERSION "0.93.1" EOF PORTS=(-sUSE_SDL=2 -sUSE_SDL_IMAGE=2 -sSDL2_IMAGE_FORMATS='["png"]' -sUSE_SDL_MIXER=2 -sSDL2_MIXER_FORMATS='[]' -sUSE_MODPLUG=1) FLAGS=(-O2 -w -fexceptions -ffile-prefix-map="$out/work/=" "${PORTS[@]}" -I"$C" -I"$G" -I"$G/include" -I"$X" -DDATADIR='"/data"' -DSCOREFILE='"/home/web_user/.config/tlk-games/tecnoballz.hi"') # Arquivos: os do Makefile.am do jogo (SOURCES_MAIN), o TinyXML e a camada. srcs=() for f in $(sed -n '/^SOURCES_MAIN = /,/^$/p' "$G/src/Makefile.am" | grep -oE '[a-z_0-9]+\.cc'); do srcs+=("$G/src/$f") done for f in tinystr tinyxml tinyxmlerror tinyxmlparser; do srcs+=("$X/$f.cpp"); done srcs+=("$C/tbzsdl12.c" "$C/tbzmusic.c") objs=() jobs=0 for f in "${srcs[@]}"; do rel="${f#"$out/work/"}" o="$out/work/obj/${rel//\//_}.o" objs+=("$o") case "$f" in *.c) emcc "${FLAGS[@]}" -c "$f" -o "$o" & ;; *) em++ "${FLAGS[@]}" -c "$f" -o "$o" & ;; esac jobs=$((jobs + 1)) if [ "$jobs" -ge 8 ]; then wait; jobs=0; fi done 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 tecnoballz.data guarda o nome # que a pasta tem aqui. mkdir -p "$out/data" cp -R "$G/src/TecnoballZ/." "$out/data/" find "$out/data" -name 'Makefile*' -delete ( cd "$out" em++ -O2 -fexceptions "${objs[@]}" "${PORTS[@]}" -lidbfs.js \ -sASYNCIFY -sALLOW_MEMORY_GROWTH=1 -sINITIAL_MEMORY=64MB -sENVIRONMENT=web -sEXIT_RUNTIME=1 \ -sEXPORTED_RUNTIME_METHODS=FS,addRunDependency,removeRunDependency \ --preload-file data@/data \ -o tecnoballz.js ) rm -rf "$out/data" "$out/work" shasum -a 256 "$out/tecnoballz.js" "$out/tecnoballz.wasm" "$out/tecnoballz.data"