#!/usr/bin/env bash # Compila o TerraTactician Expandoria (jogo de colocar hexagonos, do coletivo terratactician-expandoria, codigo AGPL-3.0-or-later, # arte propria CC BY-SA 4.0; Rust + Bevy 0.17) para WebAssembly a partir do commit 604b667 de # codeberg.org/terratactician_expandoria/game, no mesmo molde do build-bevy-games.sh (Rust 1.92.0, "cargo build --locked", wasm-bindgen # 0.2.106 = o do Cargo.lock, paginas e licencas dos crates compartilhadas em bevy/ e gridbugs/): # # src/FredGames.Bundler/Builds/build-terratactician.sh # # Mudancas no jogo (terratactician/terratactician-fredygames.patch): sem os botoes e links que levam ao site do projeto (ajuda, # "mais informacoes" dos pisos) e o quit() do JS so recarrega a pagina em vez de navegar ate la. Mudancas nos assets (neste script): # - a musica (8 faixas de Alexander Nakarada, CC BY 4.0) e recodificada em Ogg Vorbis qualidade 0,1 (de 39 MB para ~18 MB): # oggdec.c (vorbisfile) + wav2ogg.c (../pygame-music), ambos compilados em artifacts/tools/pygame-music; a licenca CC BY exige # dizer que houve mudanca, e o LICENSE.txt diz; # - os 4 sons ambientes (ocean_waves, wind_chime, wind, birds), que o autor diz ser "mostly CC0" baixados do chosic.com (nao # foi possivel conferir a licenca de cada um: o site bloqueia leitura automatica) sao trocados por silencio gerado aqui # (mesmos nomes de arquivo; o jogo os carrega e nao toca nada audivel); # - sem assets/android-res (so do app para Android). # A pagina (bevy/index.html.in, bevy/start.js.in) e nossa: o jogo so inicia depois de um clique, window.open nao abre nada e a # politica de seguranca bloqueia qualquer conexao fora da origem. # # Saida: artifacts/build/terratactician/{terratactician_bg.wasm, terratactician-604b667-dist.tar.gz, terratactician-licenses.txt}. # O .wasm do cargo sai igual em builds seguidos (o script grava o sha256 em cargo-wasm.sha256: 7c601783...), mas o wasm-bindgen 0.2.106 # NAO e deterministico: o mesmo .wasm de entrada da, a cada execucao, um terratactician.js e um _bg.wasm diferentes (so a ordem das # funcoes e os nomes __wbindgen_cast_/__wasm_bindgen_func_elem_; CHECK_WB=1 mostra isso). Por isso o bundle.yaml pina os # sha256 do build que foi testado e publicado, e outro build vai exigir atualizar os hashes (o comportamento do jogo e o mesmo). set -euo pipefail COMMIT=604b6678144e289280974d7bee0c3417bedc3887 SHA256=2423643a5c5ffe0a4564f1562d5dda8389eccc5fda32fa54d70a30ba54e3dd23 TOOLCHAIN=1.92.0 WB=0.2.106 WB_ARCH=aarch64-apple-darwin WB_SHA=f26611811a06c4fe48f8105f241eabfc4800a4ea1ce6a6084b86420a3b9711eb MUSIC_Q=0.1 # Crates que a conferencia de licencas aceita: option-ext (MPL-2.0, fonte em sources) e self_cell (Apache-2.0 OR GPL-2.0-only: usamos a Apache-2.0). ALLOW="${ALLOW:-option-ext,self_cell}" here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" root="$(git -C "$here" rev-parse --show-toplevel 2>/dev/null || pwd)" cache="$root/artifacts/build/cache" tools="$root/artifacts/tools" out="$root/artifacts/build/${OUT_NAME:-terratactician}" tree="$out/tree" short="${COMMIT:0:7}" mkdir -p "$cache" export RUSTUP_HOME="$tools/rustup" CARGO_HOME="$tools/cargo" export PATH="$CARGO_HOME/bin:$PATH" fetch() { # url arquivo sha256 if [ ! -f "$cache/$2" ]; then curl -fsSL --retry 4 "$1" -o "$cache/$2.partial" && mv "$cache/$2.partial" "$cache/$2" fi echo "$3 $cache/$2" | shasum -a 256 -c - >/dev/null } fetch "https://codeberg.org/terratactician_expandoria/game/archive/$COMMIT.tar.gz" "terratactician-$short.tar.gz" "$SHA256" fetch "https://github.com/rustwasm/wasm-bindgen/releases/download/$WB/wasm-bindgen-$WB-$WB_ARCH.tar.gz" "wasm-bindgen-$WB-$WB_ARCH.tar.gz" "$WB_SHA" if [ ! -x "$tools/wasm-bindgen-$WB/wasm-bindgen" ]; then rm -rf "$tools/wasm-bindgen-$WB.tmp"; mkdir -p "$tools/wasm-bindgen-$WB.tmp" tar -xzf "$cache/wasm-bindgen-$WB-$WB_ARCH.tar.gz" -C "$tools/wasm-bindgen-$WB.tmp" --strip-components 1 mv "$tools/wasm-bindgen-$WB.tmp" "$tools/wasm-bindgen-$WB" fi rustup toolchain install "$TOOLCHAIN" --profile minimal --target wasm32-unknown-unknown >/dev/null 2>&1 export RUSTUP_TOOLCHAIN="$TOOLCHAIN" # Ferramentas de audio (libvorbis 1.3.7 em artifacts/tools/vorbis-1.3.7; ver Builds/pygame-music/README). V="$tools/vorbis-1.3.7" if [ ! -x "$tools/pygame-music/oggdec" ]; then cc -O2 "$here/terratactician/oggdec.c" "$tools/vorbis-src/libvorbis-1.3.7/lib/vorbisfile.c" -I"$V/include" \ -I"$tools/vorbis-src/libvorbis-1.3.7/include" -L"$V/lib" -lvorbis -logg -lm -o "$tools/pygame-music/oggdec" fi [ -x "$tools/pygame-music/wav2ogg" ] || cc -O2 "$here/pygame-music/wav2ogg.c" -I"$V/include" -L"$V/lib" -lvorbisenc -lvorbis -logg -lm -o "$tools/pygame-music/wav2ogg" rm -rf "$out"; mkdir -p "$tree" "$out/dist" tar -xzf "$cache/terratactician-$short.tar.gz" -C "$tree" --strip-components 1 ( cd "$tree" && patch -p1 --no-backup-if-mismatch < "$here/terratactician/terratactician-fredygames.patch" >/dev/null ) # Assets: musica recodificada, ambientes trocados por silencio, sem os recursos do Android. rm -rf "$tree/assets/android-res" tmp="$out/audio-tmp"; mkdir -p "$tmp" for f in "$tree"/assets/music/*.ogg; do "$tools/pygame-music/oggdec" "$f" "$tmp/in.wav" "$tools/pygame-music/wav2ogg" "$tmp/in.wav" "$tmp/out.ogg" "$MUSIC_Q" mv "$tmp/out.ogg" "$f" done python3 -I - "$tmp/silence.wav" <<'PY' import struct, sys n = 44100 # 1 s de silencio, 44,1 kHz, 16 bits, estereo hdr = b'RIFF' + struct.pack(' "$tree/assets/ambient/LICENSE" <<'TXT' FredyGames: the four ambient sound files (ocean_waves, wind_chime, wind, birds) of the original repository, sourced from chosic.com with the statement "Most ambient sound effects are cc0", could not be checked against their source pages and are not distributed. These files are one second of generated silence (public domain, made for this site). TXT # Licencas dos crates primeiro (falha cedo): cargo metadata baixa os crates e o script confere cada licenca. ( cd "$tree" cargo metadata --locked --format-version 1 --filter-platform wasm32-unknown-unknown 2>/dev/null \ | RUST_LICENSES_ALLOW="$ALLOW" python3 -I "$here/gridbugs/rust-licenses.py" terratactician-expandoria "$out/crates.txt" ) echo "crates com copyleft de arquivo (MPL-2.0; o fonte vai em sources do bundle.yaml):"; cat "$out/crates.txt.copyleft" 2>/dev/null || true # Os caminhos do codigo vao para dentro do .wasm (mensagens de panico): o do jogo vira /src e o do CARGO_HOME vira /cargo. target="$tree/target/wasm32-unknown-unknown" ( cd "$tree" CARGO_INCREMENTAL=0 RUSTFLAGS="--remap-path-prefix=$tree=/src --remap-path-prefix=$CARGO_HOME=/cargo --cfg getrandom_backend=\"wasm_js\"" \ cargo build --locked --release --target wasm32-unknown-unknown 2> "$out/cargo.log" || { tail -40 "$out/cargo.log"; exit 1; } shasum -a 256 "$target/release/terratactician-expandoria.wasm" > "$out/cargo-wasm.sha256" "$tools/wasm-bindgen-$WB/wasm-bindgen" --target web --no-typescript --remove-name-section --remove-producers-section \ --out-name terratactician --out-dir "$out/dist" "$target/release/terratactician-expandoria.wasm" if [ -n "${CHECK_WB:-}" ]; then # diagnostico: o mesmo .wasm do cargo passado duas vezes pelo wasm-bindgen for n in 1 2; do "$tools/wasm-bindgen-$WB/wasm-bindgen" --target web --no-typescript --remove-name-section --remove-producers-section \ --out-name terratactician --out-dir "$out/wb$n" "$target/release/terratactician-expandoria.wasm" find "$out/wb$n" -type f | sort | xargs shasum -a 256 done fi ) mkdir -p "$out/dist/assets" cp -R "$tree/assets/." "$out/dist/assets/" find "$out/dist/assets" -name ".DS_Store" -delete # Pagina e script de partida (modelos compartilhados em bevy/). canvas=' ' python3 -I - "$here/bevy/index.html.in" "$out/dist/index.html" "TerraTactician Expandoria" '#f5e0dc' "$canvas" 'width: 100% !important; height: 100% !important;' <<'PY' import sys src, dst, title, bg, canvas, css = sys.argv[1:7] s = open(src, encoding='utf-8').read() for k, v in (('@TITLE@', title), ('@BG@', bg), ('@CANVAS@', canvas), ('@CANVASCSS@', css)): s = s.replace(k, v) open(dst, 'w', encoding='utf-8').write(s) PY python3 -I - "$here/bevy/start.js.in" "$out/dist/start.js" terratactician '{ module_or_path: wasm }' <<'PY' import sys src, dst, name, init = sys.argv[1:5] s = open(src, encoding='utf-8').read().replace('@NAME@', name).replace('@INIT@', init) s = s.replace('@FIXED@', 'false').replace('@W@', '0').replace('@H@', '0') # Os links do jogo (creditos, tabelas) abrem o endereco com window.open: aqui nao abrem nada. s += "\n// O jogo tem links para fora do site (creditos); nada abre.\nwindow.open = () => null;\n" open(dst, 'w', encoding='utf-8').write(s) PY # O .wasm sai a parte (o Bundler comprime); o resto vira um tar.gz deterministico (datas fixas, ordem fixa, sem dono). mv "$out/dist/terratactician_bg.wasm" "$out/terratactician_bg.wasm" { cat "$here/terratactician/licenses-header.txt" for f in LICENSE assets/music/License.txt assets/models/License.txt assets/models/Textures/License.txt assets/models/holiday/License.txt \ assets/sounds/License.txt assets/icons/License.txt assets/icons/buttons/LICENSE.txt assets/icons/resources/License.txt \ assets/icons/gamemodes/LICENSE.txt assets/previews/License.txt assets/fonts/Fira/LICENSE.txt assets/fonts/Inter/LICENSE.txt \ assets/fonts/PermanentMarker/LICENSE.txt; do echo; echo "------------------------------------------------------------------------"; echo "$f" echo "------------------------------------------------------------------------" cat "$tree/$f"; echo done echo "------------------------------------------------------------------------"; echo "Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)" echo "------------------------------------------------------------------------" cat "$here/bevy/CC-BY-SA-4.0.txt"; echo echo "------------------------------------------------------------------------"; echo "Apache License, Version 2.0 (Permanent Marker font, and Rust crates under it)" echo "------------------------------------------------------------------------" cat "$here/bevy/Apache-2.0.txt"; echo echo "------------------------------------------------------------------------"; echo "SIL Open Font License 1.1 (Fira, Inter)" echo "------------------------------------------------------------------------" cat "$here/bevy/OFL-1.1.txt"; echo echo; cat "$out/crates.txt" } > "$out/terratactician-licenses.txt" find "$out/dist" -exec touch -t 202511010000 {} + ( cd "$out" && find dist -type f | LC_ALL=C sort > files.txt \ && COPYFILE_DISABLE=1 tar --format=ustar --uid 0 --gid 0 --uname root --gname root -n -cf - -T files.txt \ | gzip -n -9 > "terratactician-$short-dist.tar.gz" && rm files.txt ) rm -rf "$tree" cat "$out/cargo-wasm.sha256" ls -l "$out/terratactician_bg.wasm" "$out/terratactician-$short-dist.tar.gz" shasum -a 256 "$out/terratactician_bg.wasm" "$out/terratactician-$short-dist.tar.gz" "$out/terratactician-licenses.txt"