gmod-rs/android/build.sh
Niko Marmeladkov d42b581180 fs pack: минимальный набор ассетов карты + встроенные ассеты в APK
Замер: для gm_construct реально читаются 335 файлов из VPK на 27,0 МБ
(277 материалов, 23 модели, 35 Lua-скриптов; крупнейшее — m_anm.ani 6,8 МБ)
плюс карта 35,0 МБ. Итого 62,1 МБ сырых, 31 МБ в tar.gz — против 6,7 ГБ
полной установки. Этого набора достаточно: клиент запускается с ним, карта
и пистолет полностью текстурированы (проверено кадром).

- VirtualFs: запись успешных чтений (start_recording/take_recorded);
- команда `gmod-rs fs pack <карта> --out <каталог>`: собирает мир, грузит
  модели игрока и оружия, автозагрузку Lua и копирует прочитанные файлы в
  структуру garrysmod/... плюс карту — получается самодостаточный корень
  ассетов для `--assets`;
- android/build.sh: если есть android/assets/gmod (или GMOD_RS_ANDROID_ASSETS),
  каталог кладётся в APK как assets/gmod;
- MainActivity: при первом запуске распаковывает assets/gmod в
  files/gmod_server/server, если карты там ещё нет — APK самодостаточен,
  adb push не нужен;
- .gitignore: android/assets/ (ассеты GMod не коммитим).

Все сьюты зелёные.
2026-10-23 17:03:50 +03:00

155 lines
5.9 KiB
Bash
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# Сборка debug-APK клиента gmod-rs под Android (arm64-v8a).
#
# Без Gradle: SDK/NDK + cargo + aapt2/d8/apksigner. Так проще в окружении без
# скачивания Android Gradle Plugin, а результатом всё равно является обычный
# подписанный APK.
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ANDROID_DIR="$ROOT/android"
BUILD="$ANDROID_DIR/build"
OUT_DIR="$ROOT/target/android"
API=31
ABI="${ANDROID_ABI:-arm64-v8a}"
case "$ABI" in
arm64-v8a) TARGET=aarch64-linux-android; CLANG_PREFIX=aarch64-linux-android ;;
x86_64) TARGET=x86_64-linux-android; CLANG_PREFIX=x86_64-linux-android ;;
armeabi-v7a) TARGET=armv7-linux-androideabi; CLANG_PREFIX=armv7a-linux-androideabi ;;
x86) TARGET=i686-linux-android; CLANG_PREFIX=i686-linux-android ;;
*) echo "неизвестный ABI: $ABI" >&2; exit 1 ;;
esac
if [[ "$ABI" == "arm64-v8a" ]]; then
OUT="$OUT_DIR/gmod-rs-debug.apk"
else
OUT="$OUT_DIR/gmod-rs-debug-$ABI.apk"
fi
SDK="${ANDROID_HOME:-${ANDROID_SDK_ROOT:-}}"
if [[ -z "$SDK" || ! -d "$SDK" ]]; then
for candidate in "$HOME/Android/Sdk" /opt/android-sdk; do
if [[ -d "$candidate" ]]; then SDK="$candidate"; break; fi
done
fi
if [[ -z "$SDK" || ! -d "$SDK" ]]; then
echo "не найден Android SDK (задайте ANDROID_HOME)" >&2
exit 1
fi
NDK="${ANDROID_NDK_HOME:-${ANDROID_NDK:-}}"
if [[ -z "$NDK" || ! -d "$NDK" ]]; then
NDK="$(find "$SDK/ndk" -maxdepth 1 -mindepth 1 -type d 2>/dev/null | sort -V | tail -1 || true)"
fi
if [[ -z "$NDK" || ! -d "$NDK" ]]; then
NDK=/opt/android-ndk
fi
if [[ ! -f "$NDK/build/cmake/android.toolchain.cmake" ]]; then
echo "не найден Android NDK (задайте ANDROID_NDK_HOME)" >&2
exit 1
fi
BUILD_TOOLS="$(find "$SDK/build-tools" -maxdepth 1 -mindepth 1 -type d | sort -V | tail -1)"
PLATFORM_DIR="$(find "$SDK/platforms" -maxdepth 1 -mindepth 1 -type d | sort -V | tail -1)"
ANDROID_JAR="$PLATFORM_DIR/android.jar"
if [[ ! -f "$ANDROID_JAR" ]]; then
echo "не найден android.jar в $PLATFORM_DIR" >&2
exit 1
fi
TOOLCHAIN="$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin"
CC_BIN="$TOOLCHAIN/${CLANG_PREFIX}${API}-clang"
if [[ ! -x "$CC_BIN" ]]; then
CC_BIN="$TOOLCHAIN/${CLANG_PREFIX}-clang"
fi
if [[ ! -x "$CC_BIN" ]]; then
echo "не найден clang NDK для $TARGET в $TOOLCHAIN" >&2
exit 1
fi
# --- нативная часть -------------------------------------------------------
export ANDROID_NDK="$NDK"
export CMAKE_TOOLCHAIN_FILE="$NDK/build/cmake/android.toolchain.cmake"
export ANDROID_PLATFORM="android-$API"
TARGET_U="${TARGET//-/_}"
export "CC_${TARGET_U}=$CC_BIN"
export "AR_${TARGET_U}=$TOOLCHAIN/llvm-ar"
export "RANLIB_${TARGET_U}=$TOOLCHAIN/llvm-ranlib"
LINKER_VAR="CARGO_TARGET_$(echo "$TARGET_U" | tr '[:lower:]' '[:upper:]')_LINKER"
export "$LINKER_VAR=$CC_BIN"
echo "== cargo build ($TARGET / $ABI, release)"
(cd "$ROOT" && cargo build --release -p client --lib --target "$TARGET")
LIB_DIR="$ROOT/target/$TARGET/release"
SDL_SO="$LIB_DIR/libSDL3.so"
CLIENT_SO="$LIB_DIR/libclient.so"
if [[ ! -f "$SDL_SO" ]]; then
# sdl3-sys кладёт собранную SDL3 в каталог сборки, если не смог
# скопировать её наверх.
SDL_SO="$(find "$ROOT/target/$TARGET/release/build" -path '*/out/lib/libSDL3.so' | head -1)"
fi
if [[ ! -f "$SDL_SO" || ! -f "$CLIENT_SO" ]]; then
echo "не найдены собранные libSDL3.so/libclient.so" >&2
exit 1
fi
# --- Java + пакет ---------------------------------------------------------
rm -rf "$BUILD"
mkdir -p "$BUILD/classes" "$BUILD/dex" "$BUILD/lib/$ABI" "$OUT_DIR"
echo "== javac"
find "$ANDROID_DIR/app/src/main/java" -name '*.java' > "$BUILD/sources.txt"
javac --release 11 -Xlint:-options -cp "$ANDROID_JAR" -d "$BUILD/classes" @"$BUILD/sources.txt"
echo "== d8"
find "$BUILD/classes" -name '*.class' > "$BUILD/classes.txt"
"$BUILD_TOOLS/d8" --release --lib "$ANDROID_JAR" --min-api "$API" \
--output "$BUILD/dex" @"$BUILD/classes.txt"
echo "== aapt2 link"
"$BUILD_TOOLS/aapt2" link -o "$BUILD/unsigned.apk" \
--manifest "$ANDROID_DIR/AndroidManifest.xml" \
-I "$ANDROID_JAR"
cp "$SDL_SO" "$BUILD/lib/$ABI/libSDL3.so"
# SDLActivity грузит «main»: имя файла обязано быть libmain.so, а не
# libclient.so (внутри — наш cdylib с экспортом SDL_main).
cp "$CLIENT_SO" "$BUILD/lib/$ABI/libmain.so"
"$TOOLCHAIN/llvm-strip" --strip-debug "$BUILD/lib/$ABI/libSDL3.so" 2>/dev/null || true
"$TOOLCHAIN/llvm-strip" --strip-debug "$BUILD/lib/$ABI/libmain.so" 2>/dev/null || true
(cd "$BUILD/dex" && zip -q "$BUILD/unsigned.apk" classes.dex)
(cd "$BUILD" && zip -q -r "$BUILD/unsigned.apk" "lib")
# Встроенные ассеты (необязательно): `fs pack` кладёт сюда garrysmod/.
ASSETS_DIR="${GMOD_RS_ANDROID_ASSETS:-$ANDROID_DIR/assets}"
if [[ -d "$ASSETS_DIR/gmod" ]]; then
echo "== assets: $(du -sh "$ASSETS_DIR/gmod" | cut -f1)"
rm -rf "$BUILD/assets"
mkdir -p "$BUILD/assets"
cp -a "$ASSETS_DIR/gmod" "$BUILD/assets/gmod"
(cd "$BUILD" && zip -q -r "$BUILD/unsigned.apk" "assets")
fi
echo "== zipalign"
"$BUILD_TOOLS/zipalign" -f 4 "$BUILD/unsigned.apk" "$BUILD/aligned.apk"
KEYSTORE="$ANDROID_DIR/debug.keystore"
if [[ ! -f "$KEYSTORE" ]]; then
echo "== debug keystore"
keytool -genkeypair -v -keystore "$KEYSTORE" \
-storepass android -keypass android \
-alias androiddebugkey -keyalg RSA -keysize 2048 -validity 10000 \
-dname "CN=Android Debug,O=Android,C=US" >/dev/null
fi
echo "== apksigner"
"$BUILD_TOOLS/apksigner" sign \
--ks "$KEYSTORE" --ks-pass pass:android --key-pass pass:android \
--ks-key-alias androiddebugkey \
--out "$OUT" "$BUILD/aligned.apk"
"$BUILD_TOOLS/apksigner" verify --verbose "$OUT"
echo
echo "APK: $OUT"
echo "install: adb install -r \"$OUT\""