#!/usr/bin/env bash
# Dựng Rapfi (GPL-3, https://github.com/dhbloo/rapfi – bản sao lưu https://github.com/marseraf7/rapfi) thành WebAssembly
# cho BOAT – tái tạo đúng các file trong caro/rapfi/:
# rapfi-single-simd128.{js,wasm} Rapfi nguyên bản (luật tự do / tiêu chuẩn / Renju)
# rapfi-caro-simd128.{js,wasm} Rapfi-CARO: cùng mã + bản vá rapfi-caro.patch cùng thư mục (luật Việt Nam)
# bash caro/rapfi/build/build.sh [thư mục ra, mặc định caro/rapfi]
# Cần emsdk đã kích hoạt (emcmake / emcc trong PATH; bản đã dùng: 6.0.12) và cmake.
# Nguồn (theo thứ tự ưu tiên):
# RAPFI_SRC=
bản clone có sẵn (phải ở commit ghim dưới đây)
# RAPFI_CLONE=1 clone từ bản sao lưu marseraf7/rapfi, lỗi thì từ kho gốc dhbloo/rapfi
# (mặc định) gói nguồn kèm theo rapfi-src-3c94c2a.tar.gz cùng thư mục – không cần mạng
# Bản nguyên bản dùng mã nguồn nguyên vẹn; chỉ thêm expose-fs.js (--pre-js) và không gói sẵn mạng nào
# (wasm_preloads.txt rỗng) – trang tự tải đúng mạng của luật khi cần. RAPFI_ONLY=single | caro: chỉ dựng một bản.
# Mỗi bản dựng hai kiểu: 1 luồng (rapfi-*-simd128) và đa luồng (rapfi-*-multi-simd128 – pthread, cần trang được cô lập
# cross-origin: máy chủ gửi Document-Isolation-Policy, xem server/src/web.js). RAPFI_MT=0: chỉ dựng bản 1 luồng.
set -euo pipefail
RAPFI_COMMIT=3c94c2a976f24a0dd1c5517623e9ab6fffe66bd7
HERE="$(cd "$(dirname "$0")" && pwd)"
ROOT="$(cd "$HERE/../../.." && pwd)"
OUT="$(mkdir -p "${1:-$ROOT/caro/rapfi}" && cd "${1:-$ROOT/caro/rapfi}" && pwd)"
WORK="$(mktemp -d)"
trap 'rm -rf "$WORK"' EXIT
if [ -n "${RAPFI_SRC:-}" ]; then
cp -r "$RAPFI_SRC/Rapfi" "$WORK/Rapfi"
if [ -d "$RAPFI_SRC/.git" ] && [ "$(git -C "$RAPFI_SRC" rev-parse HEAD)" != "$RAPFI_COMMIT" ]; then
echo "Cảnh báo: RAPFI_SRC không ở commit $RAPFI_COMMIT – bản dựng sẽ khác bản trong app" >&2
fi
elif [ "${RAPFI_CLONE:-}" = "1" ]; then
# Bản sao lưu (fork) trước, kho gốc của tác giả sau – cùng commit ghim nên cùng mã nguồn
git clone https://github.com/marseraf7/rapfi.git "$WORK/src" || git clone https://github.com/dhbloo/rapfi.git "$WORK/src"
git -C "$WORK/src" checkout -q "$RAPFI_COMMIT"
mv "$WORK/src/Rapfi" "$WORK/Rapfi"
else
mkdir "$WORK/src"
tar xzf "$HERE/rapfi-src-3c94c2a.tar.gz" -C "$WORK/src" --strip-components=1
mv "$WORK/src/Rapfi" "$WORK/Rapfi"
fi
mkdir -p "$WORK/Networks" && : > "$WORK/Networks/wasm_preloads.txt"
build() { # $1 = thư mục mã (trong $WORK), $2 = tên bản ra, $3 = ON (1 luồng) | OFF (đa luồng), $4.. = tuỳ chọn cmake
local src="$WORK/$1" name="$2" dir="$WORK/build-$2" single="$3"; shift 3
local proj=rapfi-single-simd128; [ "$single" = OFF ] && proj=rapfi-multi-simd128
if [ "$single" = OFF ]; then
# Bản đa luồng: thêm bản vá rapfi-mt.patch (GPL-3) – tắt cờ "đang nghĩ" trước khi in nước đi, để lệnh gửi ngay sau
# nước đi không bị bỏ qua (runProtocol bỏ mọi lệnh trừ STOP khi cờ còn bật)
mkdir -p "$WORK/mt-$name/Networks" && : > "$WORK/mt-$name/Networks/wasm_preloads.txt"
cp -r "$src" "$WORK/mt-$name/Rapfi"
(cd "$WORK/mt-$name" && patch -s -p1 < "$HERE/rapfi-mt.patch")
src="$WORK/mt-$name/Rapfi"
fi
# Lỗi thì in phần cuối nhật ký (thư mục tạm bị xoá khi thoát)
if ! { emcmake cmake -S "$src" -B "$dir" -DCMAKE_BUILD_TYPE=Release -DNO_MULTI_THREADING="$single" -DNO_COMMAND_MODULES=ON \
-DUSE_SSE=OFF -DUSE_AVX2=OFF -DUSE_AVX512=OFF -DUSE_BMI2=OFF -DUSE_VNNI=OFF -DUSE_WASM_SIMD_RELAXED=OFF \
-DCMAKE_EXE_LINKER_FLAGS="--pre-js $HERE/expose-fs.js" "$@" && cmake --build "$dir" -j"$(nproc)"; } > "$dir.log" 2>&1; then
echo "✗ Dựng $name thất bại – 40 dòng cuối nhật ký:" >&2
tail -40 "$dir.log" >&2
exit 1
fi
# Glue JS vẫn gọi tên dự án (rapfi-single / multi-simd128.wasm); worker.js (wasmName) đổi sang đúng file khi nạp
cp "$dir/$proj.js" "$OUT/$name.js"
cp "$dir/$proj.wasm" "$OUT/$name.wasm"
if [ "$single" = OFF ]; then
# Glue đa luồng tạo pthread bằng new Worker(_scriptName); trong Worker, _scriptName = self.location.href – tức
# rapfi/worker.js (nạp glue bằng importScripts), sai file: cho worker.js đặt đúng đường dẫn glue qua RAPFI_SCRIPT_URL
local a='_scriptName=self.location.href'
[ "$(grep -oF "$a" "$OUT/$name.js" | wc -l)" = 1 ] || { echo "✗ $name.js: không thấy đúng một chỗ $a" >&2; exit 1; }
sed -i 's#_scriptName=self\.location\.href#_scriptName=globalThis.RAPFI_SCRIPT_URL||self.location.href#' "$OUT/$name.js"
fi
}
# Mạng NNUE của Rapfi bắt buộc có SIMD (không có bản vô hướng): trình duyệt không hỗ trợ WebAssembly SIMD
# (rất cũ, vd. Safari < 16.4) thì BOAT tự dùng engine của game.
if [ "${RAPFI_ONLY:-}" != "caro" ]; then
build Rapfi rapfi-single-simd128 ON -DUSE_WASM_SIMD=ON
[ "${RAPFI_MT:-1}" = 0 ] || build Rapfi rapfi-multi-simd128 OFF -DUSE_WASM_SIMD=ON
fi
if [ "${RAPFI_ONLY:-}" != "single" ]; then
# Rapfi-CARO: thêm luật Việt Nam (chặn hai đầu) – bản vá GPL-3 kèm trong repo
mkdir -p "$WORK/caro/Networks" && : > "$WORK/caro/Networks/wasm_preloads.txt" && cp -r "$WORK/Rapfi" "$WORK/caro/Rapfi"
(cd "$WORK/caro" && patch -s -p1 < "$HERE/rapfi-caro.patch")
build caro/Rapfi rapfi-caro-simd128 ON -DUSE_WASM_SIMD=ON
[ "${RAPFI_MT:-1}" = 0 ] || build caro/Rapfi rapfi-caro-multi-simd128 OFF -DUSE_WASM_SIMD=ON
fi
ls -la "$OUT"/rapfi-*simd128.*
sha256sum "$OUT"/rapfi-*simd128.* 2>/dev/null || shasum -a 256 "$OUT"/rapfi-*simd128.*
|