Files
pt-minecraft-modpack/start.sh

273 lines
7.3 KiB
Bash
Executable File
Raw 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
set -Eeuo pipefail
ROOT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
PACK_DIR="${PT_PACK_DIR:-$ROOT_DIR/server-01-random-block}"
RUNTIME_DIR="${PT_RUNTIME_DIR:-$ROOT_DIR/.pt-panel-runtime}"
MODS_DIR="${PT_MODS_DIR:-$ROOT_DIR/mods}"
DOWNLOAD_DIR="$RUNTIME_DIR/downloads"
STAMP_FILE="$RUNTIME_DIR/fabric-install.stamp"
JAVA_BIN="${JAVA_BIN:-java}"
JAVA_ARGS="${PT_JAVA_ARGS:--Xms1G -Xmx2G}"
SERVER_JAR_OVERRIDE="${PT_SERVER_JAR:-}"
FORCE_UPDATE="${PT_FORCE_UPDATE:-0}"
DRY_RUN="${PT_DRY_RUN:-0}"
SKIP_HASH_CHECK="${PT_SKIP_HASH_CHECK:-0}"
AUTO_EULA="${PT_AUTO_EULA:-TRUE}"
log() {
printf '[pt-panel] %s\n' "$*"
}
fail() {
printf '[pt-panel] ERROR: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "缺少命令: $1"
}
fetch() {
local url="$1"
local dest="$2"
if command -v curl >/dev/null 2>&1; then
curl -fL --retry 3 --retry-delay 2 -o "$dest" "$url"
elif command -v wget >/dev/null 2>&1; then
wget -O "$dest" "$url"
else
fail "缺少 curl 或 wget无法下载文件"
fi
}
fetch_to_stdout() {
local url="$1"
if command -v curl >/dev/null 2>&1; then
curl -fL --retry 3 --retry-delay 2 "$url"
elif command -v wget >/dev/null 2>&1; then
wget -O - "$url"
else
fail "缺少 curl 或 wget无法下载文件"
fi
}
trim_quotes() {
local value="$1"
value="${value#\"}"
value="${value%\"}"
printf '%s' "$value"
}
toml_value() {
local key="$1"
local file="$2"
local line
line="$(grep -E "^${key}[[:space:]]*=" "$file" | head -n 1 || true)"
[ -n "$line" ] || return 1
line="${line#*=}"
line="${line#${line%%[![:space:]]*}}"
trim_quotes "$line"
}
hash_cmd_for() {
case "$1" in
sha512) echo sha512sum ;;
sha256) echo sha256sum ;;
sha1) echo sha1sum ;;
md5) echo md5sum ;;
*) return 1 ;;
esac
}
verify_hash() {
local file="$1"
local expected="$2"
local format="$3"
local cmd actual
[ "$SKIP_HASH_CHECK" = "1" ] && return 0
cmd="$(hash_cmd_for "$format" || true)"
[ -n "$cmd" ] || return 0
command -v "$cmd" >/dev/null 2>&1 || return 0
actual="$($cmd "$file" | awk '{print $1}')"
[ "$actual" = "$expected" ]
}
ensure_dirs() {
mkdir -p "$RUNTIME_DIR" "$DOWNLOAD_DIR" "$MODS_DIR"
}
load_pack_versions() {
[ -f "$PACK_DIR/pack.toml" ] || fail "找不到 $PACK_DIR/pack.toml请确认已上传服务端 pack 文件"
MINECRAFT_VERSION="$(toml_value 'minecraft' "$PACK_DIR/pack.toml")"
FABRIC_LOADER_VERSION="$(toml_value 'fabric' "$PACK_DIR/pack.toml")"
[ -n "$MINECRAFT_VERSION" ] || fail "无法从 $PACK_DIR/pack.toml 读取 minecraft 版本"
[ -n "$FABRIC_LOADER_VERSION" ] || fail "无法从 $PACK_DIR/pack.toml 读取 fabric 版本"
}
load_latest_fabric_installer_version() {
local meta version
meta="$(fetch_to_stdout 'https://meta.fabricmc.net/v2/versions/installer')"
version="$(printf '%s\n' "$meta" | grep '"version"' | head -n 1 | sed 's/.*"version": *"\([^"]*\)".*/\1/')"
[ -n "$version" ] || fail "无法获取最新 Fabric installer 版本"
printf '%s' "$version"
}
install_fabric_server() {
local installer_version installer_jar wanted_stamp current_stamp
installer_version="$(load_latest_fabric_installer_version)"
installer_jar="$DOWNLOAD_DIR/fabric-installer-${installer_version}.jar"
wanted_stamp="mc=$MINECRAFT_VERSION loader=$FABRIC_LOADER_VERSION installer=$installer_version"
current_stamp="$(cat "$STAMP_FILE" 2>/dev/null || true)"
if [ "$FORCE_UPDATE" != "1" ] && [ -f "$ROOT_DIR/fabric-server-launch.jar" ] && [ "$wanted_stamp" = "$current_stamp" ]; then
log "Fabric 服务端已就绪,跳过重复安装"
return 0
fi
log "准备安装 Fabric 服务端 (Minecraft $MINECRAFT_VERSION / Loader $FABRIC_LOADER_VERSION)"
fetch "https://maven.fabricmc.net/net/fabricmc/fabric-installer/${installer_version}/fabric-installer-${installer_version}.jar" "$installer_jar"
if [ "$DRY_RUN" = "1" ]; then
log "DRY RUN: 跳过执行 Fabric installer"
return 0
fi
"$JAVA_BIN" -jar "$installer_jar" server -mcversion "$MINECRAFT_VERSION" -loader "$FABRIC_LOADER_VERSION" -downloadMinecraft
printf '%s\n' "$wanted_stamp" > "$STAMP_FILE"
}
sync_mods() {
local meta file_name url hash_format hash dest tmp
shopt -s nullglob
local files=("$PACK_DIR"/mods/*.pw.toml)
shopt -u nullglob
[ "${#files[@]}" -gt 0 ] || fail "$PACK_DIR/mods 下没有找到任何 .pw.toml 模组定义"
for meta in "${files[@]}"; do
file_name="$(toml_value 'filename' "$meta")"
url="$(toml_value 'url' "$meta")"
hash_format="$(toml_value 'hash-format' "$meta" || true)"
hash="$(toml_value 'hash' "$meta" || true)"
[ -n "$file_name" ] || fail "无法读取 $meta 中的 filename"
[ -n "$url" ] || fail "无法读取 $meta 中的 download.url"
dest="$MODS_DIR/$file_name"
if [ "$FORCE_UPDATE" != "1" ] && [ -f "$dest" ]; then
if [ -n "$hash_format" ] && [ -n "$hash" ]; then
if verify_hash "$dest" "$hash" "$hash_format"; then
log "模组已存在且校验通过: $file_name"
continue
fi
log "模组校验失败,重新下载: $file_name"
else
log "模组已存在,跳过下载: $file_name"
continue
fi
else
log "下载模组: $file_name"
fi
if [ "$DRY_RUN" = "1" ]; then
log "DRY RUN: 跳过下载 $url"
continue
fi
tmp="$dest.part"
fetch "$url" "$tmp"
if [ -n "$hash_format" ] && [ -n "$hash" ] && ! verify_hash "$tmp" "$hash" "$hash_format"; then
rm -f "$tmp"
fail "模组校验失败: $file_name"
fi
mv "$tmp" "$dest"
done
}
write_eula() {
if [ "$AUTO_EULA" = "TRUE" ] || [ "$AUTO_EULA" = "true" ] || [ "$AUTO_EULA" = "1" ]; then
printf 'eula=true\n' > "$ROOT_DIR/eula.txt"
log "已写入 eula.txt"
else
log "已跳过自动写入 EULAPT_AUTO_EULA=$AUTO_EULA"
fi
}
find_server_jar() {
if [ -n "$SERVER_JAR_OVERRIDE" ]; then
printf '%s' "$SERVER_JAR_OVERRIDE"
return 0
fi
if [ -f "$ROOT_DIR/fabric-server-launch.jar" ]; then
printf '%s' "$ROOT_DIR/fabric-server-launch.jar"
return 0
fi
local candidate
candidate="$(find "$ROOT_DIR" -maxdepth 1 -type f \( -name 'fabric-server-launch.jar' -o -name 'fabric-server-*.jar' -o -name 'server.jar' \) | sort | head -n 1 || true)"
[ -n "$candidate" ] || return 1
printf '%s' "$candidate"
}
start_server() {
local server_jar
server_jar="$(find_server_jar || true)"
if [ "$DRY_RUN" = "1" ]; then
if [ -n "$server_jar" ]; then
log "使用服务端文件: $server_jar"
else
log "DRY RUN: 当前尚未生成服务端 jar正式运行时会先执行 Fabric installer"
fi
log "启动参数: $JAVA_ARGS"
log "DRY RUN: 跳过实际启动"
return 0
fi
[ -n "$server_jar" ] || fail "找不到可启动的服务端 jar请检查 Fabric 安装是否成功"
log "使用服务端文件: $server_jar"
log "启动参数: $JAVA_ARGS"
cd "$ROOT_DIR"
exec "$JAVA_BIN" $JAVA_ARGS -jar "$server_jar" nogui
}
main() {
need_cmd "$JAVA_BIN"
need_cmd grep
need_cmd sed
need_cmd awk
need_cmd find
ensure_dirs
load_pack_versions
log "根目录: $ROOT_DIR"
log "Pack 目录: $PACK_DIR"
log "Minecraft 版本: $MINECRAFT_VERSION"
log "Fabric Loader 版本: $FABRIC_LOADER_VERSION"
install_fabric_server
sync_mods
write_eula
start_server
}
main "$@"