Compare commits

..

15 Commits
v00 ... master

Author SHA1 Message Date
e153607c0b Merge pull request 'v1.1' (#6) from dev into master
Reviewed-on: #6
2026-05-07 06:36:10 +08:00
8247addf40 v1.1
- 自动化安装脚本
- 自动化启停脚本
2026-05-07 06:34:54 +08:00
6d753b85c7 Merge pull request 'v1.0.6' (#5) from dev into master
Reviewed-on: #5
2026-05-07 05:15:40 +08:00
3591532954 v1.0.6
- 修改启停脚本拉取命令
- debug 中
2026-05-07 05:15:23 +08:00
4c936245cd Merge pull request 'dev' (#4) from dev into master
Reviewed-on: #4
2026-05-07 05:06:08 +08:00
f351a37403 v1.0.5
- 修改启停脚本拉取命令
2026-05-07 05:05:45 +08:00
4cceb7717c v1.0.5
- 修改启停脚本拉取命令
2026-05-07 05:04:47 +08:00
6ad1ba513d Merge pull request 'v1.0.4' (#3) from dev into master
Reviewed-on: #3
2026-05-07 04:44:19 +08:00
d8579cf0d7 v1.0.4
- 新增stop后断后还占用
- 新增debug功能
- 制作时间更新
- debug版本
2026-05-07 04:44:02 +08:00
7520d1712e Merge pull request 'v1.0.3' (#2) from dev into master
Reviewed-on: #2
2026-05-07 04:41:29 +08:00
4bf1a0522d v1.0.3
- 新增stop后断后还占用
- 新增debug功能
- 制作时间更新
- debug版本
2026-05-07 04:41:09 +08:00
73b6c4fe26 Merge pull request 'v1.0.2' (#1) from dev into master
Reviewed-on: #1
2026-05-07 04:40:20 +08:00
34c2107e53 v1.0.3
- 新增stop后断后还占用
- 新增debug功能
- 制作时间更新
- debug版本
2026-05-07 04:38:43 +08:00
5aa36a3706 v1.0.2
- 新增stop后断后还占用
- 新增debug功能
- 制作时间更新
- debug版本
2026-05-07 04:27:20 +08:00
070faeaf29 v1.0.1
- 新增stop后断后还占用
- 新增debug功能
2026-05-07 03:35:14 +08:00
3 changed files with 1220 additions and 1 deletions

144
README.md Normal file
View File

@ -0,0 +1,144 @@
# 一个基于 Ubuntu2204 制作的 欧卡自动化安装脚本
## 一、快速部署
- 安装时会创建一个名字为 steam 的用户以便管理和维护
---
一键安装脚本-推荐:
```bash
curl -fsSL "https://git.a-hxin.cn/ahxin/ets2-server/raw/branch/master/install_server/install_server.sh" | sudo bash
```
单条执行:
```bash
sudo chown ubuntu:ubuntu install_server.sh
chmod +x install_server.sh
sudo bash install_server.sh
```
## 二、切换用户
给 steam 用户设置密码 以便后续访问
```bash
sudo passwd steam
```
切换 steam 用户
```bash
sudo su steam
```
## 三、启动服务
注意:一定要再 steam 用户下才能启停成功
操作指引:
```JS
steam@myserver:/home/ubuntu$ ets2_sv
ETS2 服务器管理命令
用法: ets2_sv {start|stop|restart|status|update|debug|log|listlog|cleanlog|check|ports|portstatus|kill}
start - 后台启动 ETS2 服务器
stop - 停止 ETS2 服务器,并释放端口
restart - 重启 ETS2 服务器
status - 查看 ETS2 服务器状态
update - 更新 ETS2 专用服务器
debug - 前台调试启动,不后台运行,实时输出
log - 实时查看最新日志
listlog - 查看最近日志文件
cleanlog - 清理旧日志
check - 检查配置文件和端口
ports - 检查端口是否可用
portstatus - 查看端口占用详情
kill - 强制清理残留 ETS2 进程
```
## 四、配置文件
- 这里一定要配置否则用不了
- 也无法启动成功
### 1、生成卡车文件
进游戏在终端执行,
成功会提示:[MP]Server packages exported successfully
```bash
export_server_packages
```
- 此时在电脑文档目录下Documents\Euro Truck Simulator 2
- 会得到以下三个文件
- **server_packages.dat****server_packages.sii**、**server_config.sii**
- 地图和数据文件:**server_packages.dat**、 **server_packages.sii**
- 房间数据文件:**server_config.sii**
### 2、准备房间文件
把刚才生成出来的 **server_config.sii** 进行修改 根据需求修改:
- 接下来修改房间文件
- steam tokey获取地址https://steamcommunity.com/dev/managegameservers
```js
SiiNunit
{
server_config : _nameless.24a.9a1f.bd00 {
lobby_name: "Euro Truck Simulator 2 server" //会话名称,限制为 63 个字符。
description: "" // 房间描述,限制为 63 个字符。
welcome_message: "" // 房间欢迎消息,限制为 127 个字符。
password: "" // 房间密码,限制为 63 个字符
max_players: 128 // 会话中的最大玩家数量,限制为 8 名玩家。
max_vehicles_total: 100 // 最大车辆总数
max_ai_vehicles_player: 50 // 最大人工智能车辆玩家数量
max_ai_vehicles_player_spawn: 50 // 最大AI车辆数量
connection_virtual_port: 100 // 连接虚拟端口
query_virtual_port: 101 // 查询虚拟端口
connection_dedicated_port: 27015 // 连接专用端口
query_dedicated_port: 27016 // 查询专用端口
server_logon_token: "" // Steam游戏服务器登录令牌永久账户
player_damage: true // 玩家之间的碰撞,建议开
traffic: true // 路上有没有AI车辆
hide_in_company: false // 标记远程玩家是否隐藏在公司区域
hide_colliding: true // 标志用于在传送后隐藏碰撞的车辆
force_speed_limiter: false // 卡车限速器限速90
mods_optioning: false // 可选MOD开启后需要高级筛选才可以显示房间开启后支持使用【可选的MOD】的玩家进入房间
timezones: 0 // 时区值0-2
service_no_collision: false // 服务器禁止碰撞建议关true
in_menu_ghosting: false // 游戏暂停时禁用碰撞
name_tags: true // 是否显示玩家名字,建议开
friends_only: false //
show_server: true // 是否显示房间
moderator_list: 0 // 主持人人数
moderator_list[0]: 123456789 //用户 steam id
}
}
```
## 五、上推文件
一般来说房间数据在构建服务器时上传 或者房间作调整 其他时间都不怎么用改
而 地图和数据文件就需要频繁修改只是在房间mod 修改的时候重新上传重启欧卡服务器即可
---
- 地图和数据文件:**server_packages.dat**、 **server_packages.sii**
- 房间数据文件:**server_config.sii**
### 1、上传文件
- 登陆 steam 用户
把刚才得到的 三个文件都上传至
```js
~/ets2_doc/Euro\ Truck\ Simulator\ 2/
```
### 2、如果服务器开机128
修改服务器上的 **config_ds.cfg** 文件
```bash
vim ~/ets2_doc/Euro\ Truck\ Simulator\ 2/config_ds.cfg
```
找到这个改为 128
```js
uset g_max_convoy_size "128"
```
然后可以先用 ets2_sv debug 启动 后面再正常使用 ets2_start

View File

@ -0,0 +1,320 @@
#!/usr/bin/env bash
# 2026年5月7日
# 项目地址: https://git.a-hxin.cn/ahxin/ets2-server.git
set -Eeuo pipefail
export DEBIAN_FRONTEND=noninteractive
export NEEDRESTART_MODE=l
REPO_HOST="https://git.a-hxin.cn/ahxin/ets2-server"
BRANCH="master"
RAW_BASE="${REPO_HOST}/raw/branch/${BRANCH}"
STEAM_USER="steam"
STEAM_HOME="/home/steam"
STEAMCMD_DIR="${STEAM_HOME}/steamcmd"
ETS2_DIR="${STEAM_HOME}/ets2_sv"
ETS2_DOC_DIR="${STEAM_HOME}/ets2_doc"
ETS2_BIN_DIR="${ETS2_DIR}/bin/linux_x64"
SERVER_SCRIPT_URL="${RAW_BASE}/server/server.sh"
SERVER_SCRIPT_PATH="${ETS2_BIN_DIR}/server.sh"
ETS2_CMD="/usr/local/bin/ets2_sv"
APP_ID="1948160"
while [ $# -gt 0 ]; do
case "$1" in
--branch)
BRANCH="$2"
RAW_BASE="${REPO_HOST}/raw/branch/${BRANCH}"
SERVER_SCRIPT_URL="${RAW_BASE}/server/server.sh"
shift 2
;;
*)
echo "[ERROR] 未知参数: $1"
exit 1
;;
esac
done
echo "========================================"
echo " ETS2 Dedicated Server 一键部署脚本"
echo " System: Ubuntu / Debian"
echo " Branch: ${BRANCH}"
echo "========================================"
if [ "$(id -u)" -ne 0 ]; then
echo "[ERROR] 请使用 root 权限执行:"
echo "curl -fsSL \"${RAW_BASE}/install_server/install_server.sh\" | sudo bash"
exit 1
fi
echo
echo "一、检查系统环境"
if [ -f /etc/os-release ]; then
. /etc/os-release
echo "[INFO] 当前系统: ${PRETTY_NAME:-unknown}"
fi
if ! command -v apt-get >/dev/null 2>&1; then
echo "[ERROR] 当前脚本主要适配 Ubuntu / Debian未检测到 apt-get"
exit 1
fi
echo
echo "二、创建 steam 用户"
if id "${STEAM_USER}" >/dev/null 2>&1; then
echo "[OK] 用户 ${STEAM_USER} 已存在,跳过创建"
else
adduser \
--system \
--shell /bin/bash \
--gecos 'Steam Service User' \
--group \
--disabled-password \
--home "${STEAM_HOME}" \
"${STEAM_USER}"
echo "[OK] 用户 ${STEAM_USER} 创建完成"
fi
echo
echo "三、创建工作目录"
mkdir -p "${STEAMCMD_DIR}" "${ETS2_DIR}" "${ETS2_DOC_DIR}" "${ETS2_BIN_DIR}"
chown -R "${STEAM_USER}:${STEAM_USER}" "${STEAM_HOME}"
echo "[OK] 目录创建完成:"
echo "${STEAMCMD_DIR}"
echo "${ETS2_DIR}"
echo "${ETS2_DOC_DIR}"
echo
echo "四、安装运行库"
dpkg --add-architecture i386 || true
apt-get update
apt-get install -y \
sudo \
curl \
ca-certificates \
tar \
gzip \
git \
util-linux \
coreutils \
procps \
iproute2 \
libatomic1 \
libatomic1:i386 \
libc6:i386 \
libstdc++6:i386 \
libgcc-s1:i386 \
libx11-6:i386 \
libxext6:i386 \
libxau6:i386 \
libxdmcp6:i386 \
libncurses5:i386 \
libncursesw5:i386 \
libcurl4:i386 \
zlib1g:i386 \
libbz2-1.0:i386 \
libtinfo6:i386
echo "[OK] 运行库安装完成"
echo
echo "五、下载 / 更新 SteamCMD"
sudo -u "${STEAM_USER}" bash -lc "
mkdir -p '${STEAMCMD_DIR}'
cd '${STEAMCMD_DIR}'
curl -sqL 'https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz' | tar zxvf -
chmod +x '${STEAMCMD_DIR}/steamcmd.sh'
"
echo "[OK] SteamCMD 准备完成"
echo
echo "六、安装 / 更新 ETS2 Dedicated Server"
chown -R "${STEAM_USER}:${STEAM_USER}" "${STEAMCMD_DIR}" "${ETS2_DIR}"
set +e
sudo -u "${STEAM_USER}" bash -lc "
cd '${STEAMCMD_DIR}' &&
./steamcmd.sh \
+@sSteamCmdForcePlatformType linux \
+login anonymous \
+app_info_update 1 \
+force_install_dir '${ETS2_DIR}' \
+app_update '${APP_ID}' validate \
+quit
"
INSTALL_RESULT=$?
if [ "${INSTALL_RESULT}" -ne 0 ]; then
echo "[WARN] 第一次安装失败,尝试清理 SteamCMD 缓存后重试..."
sudo -u "${STEAM_USER}" rm -rf "${STEAMCMD_DIR}/appcache" || true
sudo -u "${STEAM_USER}" rm -rf "${STEAM_HOME}/Steam/appcache" || true
sudo -u "${STEAM_USER}" rm -rf "${STEAM_HOME}/.steam/appcache" || true
sudo -u "${STEAM_USER}" bash -lc "
cd '${STEAMCMD_DIR}' &&
./steamcmd.sh \
+@sSteamCmdForcePlatformType linux \
+login anonymous \
+app_info_update 1 \
+force_install_dir '${ETS2_DIR}' \
+app_update '${APP_ID}' validate \
+quit
"
INSTALL_RESULT=$?
fi
set -e
if [ "${INSTALL_RESULT}" -ne 0 ]; then
echo "[ERROR] ETS2 Dedicated Server 安装失败"
echo
echo "可手动测试:"
echo "sudo -u steam bash -lc 'cd ${STEAMCMD_DIR} && ./steamcmd.sh +login anonymous +app_info_print ${APP_ID} +quit'"
exit 1
fi
echo "[OK] ETS2 Dedicated Server 安装完成"
echo
echo "七、安装 server.sh 管理脚本"
mkdir -p "${ETS2_BIN_DIR}"
echo "[INFO] 下载地址:${SERVER_SCRIPT_URL}"
curl -fsSL "${SERVER_SCRIPT_URL}" -o "${SERVER_SCRIPT_PATH}"
chmod +x "${SERVER_SCRIPT_PATH}"
chown "${STEAM_USER}:${STEAM_USER}" "${SERVER_SCRIPT_PATH}"
echo "[OK] server.sh 安装完成:${SERVER_SCRIPT_PATH}"
echo
echo "八、修复 steamclient.so 链接"
if [ -f "${ETS2_DIR}/linux64/steamclient.so" ]; then
sudo -u "${STEAM_USER}" mkdir -p "${STEAM_HOME}/.steam/sdk64"
sudo -u "${STEAM_USER}" ln -sfn \
"${ETS2_DIR}/linux64/steamclient.so" \
"${STEAM_HOME}/.steam/sdk64/steamclient.so"
echo "[OK] steamclient.so 链接完成"
else
echo "[WARN] 未找到 ${ETS2_DIR}/linux64/steamclient.so跳过"
fi
echo
echo "九、创建必要目录并设置权限"
mkdir -p "${ETS2_BIN_DIR}/logs"
mkdir -p "${ETS2_DOC_DIR}/Euro Truck Simulator 2"
chown -R "${STEAM_USER}:${STEAM_USER}" "${STEAM_HOME}"
find "${ETS2_BIN_DIR}" -type d -exec chmod 775 {} \; 2>/dev/null || true
find "${ETS2_BIN_DIR}" -type f -exec chmod 664 {} \; 2>/dev/null || true
chmod +x "${SERVER_SCRIPT_PATH}" || true
chmod +x "${ETS2_BIN_DIR}/server_launch.sh" 2>/dev/null || true
chmod +x "${ETS2_BIN_DIR}/eurotrucks2_server" 2>/dev/null || true
find "${ETS2_DOC_DIR}" -type d -exec chmod 775 {} \; 2>/dev/null || true
find "${ETS2_DOC_DIR}" -type f -exec chmod 664 {} \; 2>/dev/null || true
echo "[OK] 权限设置完成"
echo
echo "十、创建快捷命令 ets2_sv"
rm -f "${ETS2_CMD}"
cat > "${ETS2_CMD}" <<EOF
#!/usr/bin/env bash
SERVER_SCRIPT="${SERVER_SCRIPT_PATH}"
if [ ! -f "\$SERVER_SCRIPT" ]; then
echo "[ERROR] 找不到服务脚本: \$SERVER_SCRIPT"
exit 1
fi
if [ "\$(id -un)" = "${STEAM_USER}" ]; then
exec "\$SERVER_SCRIPT" "\$@"
else
exec sudo -u ${STEAM_USER} "\$SERVER_SCRIPT" "\$@"
fi
EOF
chmod +x "${ETS2_CMD}"
echo "[OK] 快捷命令创建完成:${ETS2_CMD}"
echo
echo "十一、基础检查"
if [ -f "${ETS2_BIN_DIR}/eurotrucks2_server" ]; then
echo "[INFO] 检查 eurotrucks2_server 依赖:"
ldd "${ETS2_BIN_DIR}/eurotrucks2_server" | grep -i "not found" || echo "[OK] 未发现缺失动态库"
else
echo "[WARN] 未找到 ${ETS2_BIN_DIR}/eurotrucks2_server"
fi
echo
echo "========================================"
echo "部署完成"
echo "========================================"
echo
echo "仓库地址:"
echo "${REPO_HOST}.git"
echo
echo "当前分支:"
echo "${BRANCH}"
echo
echo "服务器目录:"
echo "${ETS2_DIR}"
echo
echo "配置目录:"
echo "${ETS2_DOC_DIR}/Euro Truck Simulator 2"
echo
echo "管理脚本:"
echo "${SERVER_SCRIPT_PATH}"
echo
echo "快捷命令:"
echo "ets2_sv"
echo
echo "下一步:"
echo "1. 上传 server_config.sii、server_packages.sii、server_packages.dat 到:"
echo " ${ETS2_DOC_DIR}/Euro Truck Simulator 2"
echo
echo "2. 检查配置:"
echo " ets2_sv check"
echo
echo "3. 前台调试启动:"
echo " ets2_sv debug"
echo
echo "4. 后台启动:"
echo " ets2_sv start"
echo
echo "========================================"

View File

@ -1 +1,756 @@
~~~~~111
#!/bin/sh
# 2026年5月7日04点25分
# 项目地址: https://git.a-hxin.cn/ahxin/ets2-server/raw/branch/master/server/server.sh
# ==============================
# ETS2 Dedicated Server 管理脚本
# ==============================
# 服务器目录
SERVER_HOME="/home/steam/ets2_sv/bin/linux_x64"
# 官方启动脚本
SERVER_LAUNCH="$SERVER_HOME/server_launch.sh"
# Steam 运行库目录
STEAM_PATH="/home/steam/ets2_sv/linux64"
# SteamCMD 目录
STEAMCMD_HOME="/home/steam/steamcmd"
# ETS2 服务端安装目录
ETS2_INSTALL_DIR="/home/steam/ets2_sv"
# ETS2 Dedicated Server AppID
ETS2_APP_ID="1948160"
# 欧卡文档目录
# 实际读取目录:
# /home/steam/ets2_doc/Euro Truck Simulator 2
export XDG_DATA_HOME="/home/steam/ets2_doc"
# 设置 LD_LIBRARY_PATH
export LD_LIBRARY_PATH="$STEAM_PATH:$SERVER_HOME:${LD_LIBRARY_PATH:-}"
# 启动参数
SERVER_OPTIONS="-nosingle -server server_packages.sii -server_cfg server_config.sii"
# 实际配置目录
ETS2_DOC_HOME="$XDG_DATA_HOME/Euro Truck Simulator 2"
# 日志根目录
LOG_ROOT="$SERVER_HOME/logs"
# PID 文件
PID_FILE="$LOG_ROOT/server.pid"
# 后台启动器 PID 文件
RUNNER_PID_FILE="$LOG_ROOT/runner.pid"
# 进程组 ID 文件
PGID_FILE="$LOG_ROOT/server.pgid"
# 最新日志软链接
LATEST_LOG_LINK="$LOG_ROOT/latest.log"
# 当前日志路径记录
CURRENT_LOG_PATH_FILE="$LOG_ROOT/current_log.path"
# 日志保留天数
LOG_KEEP_DAYS=15
# 当前运行日志文件
SERVER_LOG=""
show_info() {
echo "[INFO] $1"
}
show_ok() {
echo "[OK] $1"
}
show_warn() {
echo "[WARN] $1"
}
show_error() {
echo "[ERROR] $1"
}
prepare_dirs() {
mkdir -p "$LOG_ROOT"
mkdir -p "$ETS2_DOC_HOME"
}
create_log_file() {
LOG_DAY=$(date +"%Y-%m-%d")
LOG_TIME=$(date +"%Y%m%d_%H%M%S")
LOG_DIR="$LOG_ROOT/$LOG_DAY"
mkdir -p "$LOG_DIR"
SERVER_LOG="$LOG_DIR/server_$LOG_TIME.log"
touch "$SERVER_LOG"
ln -sfn "$SERVER_LOG" "$LATEST_LOG_LINK"
echo "$SERVER_LOG" > "$CURRENT_LOG_PATH_FILE"
show_info "本次日志文件: $SERVER_LOG"
}
cleanup_old_logs() {
if [ -d "$LOG_ROOT" ]; then
find "$LOG_ROOT" -mindepth 1 -maxdepth 1 -type d -mtime +"$LOG_KEEP_DAYS" -exec rm -rf {} \; 2>/dev/null
fi
}
check_required_files() {
echo "========== ETS2 配置文件检查 =========="
echo "当前用户: $(whoami)"
echo "SERVER_HOME: $SERVER_HOME"
echo "SERVER_LAUNCH: $SERVER_LAUNCH"
echo "STEAM_PATH: $STEAM_PATH"
echo "XDG_DATA_HOME: $XDG_DATA_HOME"
echo "ETS2_DOC_HOME: $ETS2_DOC_HOME"
echo "LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
echo "SERVER_OPTIONS: $SERVER_OPTIONS"
echo ""
if [ -x "$SERVER_LAUNCH" ]; then
echo "[OK] server_launch.sh 存在并可执行"
else
echo "[ERROR] server_launch.sh 不存在或不可执行"
fi
if [ -f "$ETS2_DOC_HOME/server_config.sii" ]; then
echo "[OK] server_config.sii 存在"
else
echo "[WARN] 缺少 server_config.sii"
fi
if [ -f "$ETS2_DOC_HOME/server_packages.sii" ]; then
echo "[OK] server_packages.sii 存在"
else
echo "[ERROR] 缺少 server_packages.sii"
fi
if [ -f "$ETS2_DOC_HOME/server_packages.dat" ]; then
echo "[OK] server_packages.dat 存在"
else
echo "[ERROR] 缺少 server_packages.dat"
fi
echo ""
echo "当前配置目录文件:"
ls -lah "$ETS2_DOC_HOME" 2>/dev/null
echo "======================================="
}
get_server_pid() {
pgrep -f "eurotrucks2_server" | head -n 1
}
get_launch_pid() {
pgrep -f "server_launch.sh" | head -n 1
}
get_config_port() {
KEY="$1"
CONFIG_FILE="$ETS2_DOC_HOME/server_config.sii"
if [ ! -f "$CONFIG_FILE" ]; then
return
fi
grep -E "^[[:space:]]*$KEY[[:space:]]*:" "$CONFIG_FILE" | \
head -n 1 | \
sed -E 's/.*:[[:space:]]*([0-9]+).*/\1/'
}
get_connection_port() {
PORT=$(get_config_port "connection_dedicated_port")
if [ -z "$PORT" ]; then
PORT="27015"
fi
echo "$PORT"
}
get_query_port() {
PORT=$(get_config_port "query_dedicated_port")
if [ -z "$PORT" ]; then
PORT="27016"
fi
echo "$PORT"
}
port_in_use() {
PORT="$1"
if [ -z "$PORT" ]; then
return 1
fi
ss -H -lntup 2>/dev/null | awk -v port=":$PORT" '
$5 ~ port"$" {
found=1
}
END {
exit !found
}
'
}
show_port_owner() {
PORT="$1"
ss -lntup 2>/dev/null | grep -E ":$PORT[[:space:]]|:$PORT$" || true
}
get_port_owner_pids() {
PORT="$1"
ss -H -lntup 2>/dev/null | awk -v port=":$PORT" '
$0 ~ port {
line=$0
while (match(line, /pid=[0-9]+/)) {
pid=substr(line, RSTART + 4, RLENGTH - 4)
print pid
line=substr(line, RSTART + RLENGTH)
}
}
' | sort -u
}
get_ets2_pid_from_ports() {
CONN_PORT=$(get_connection_port)
QUERY_PORT=$(get_query_port)
for PORT in "$CONN_PORT" "$QUERY_PORT"; do
for P in $(get_port_owner_pids "$PORT"); do
CMD=$(ps -p "$P" -o command= 2>/dev/null)
case "$CMD" in
*eurotrucks2_server*)
echo "$P"
return 0
;;
esac
done
done
return 1
}
check_ports_available() {
CONN_PORT=$(get_connection_port)
QUERY_PORT=$(get_query_port)
echo "========== ETS2 端口检查 =========="
echo "connection_dedicated_port: $CONN_PORT"
echo "query_dedicated_port: $QUERY_PORT"
echo ""
HAS_ERROR=0
if port_in_use "$CONN_PORT"; then
show_error "端口 $CONN_PORT 已被占用"
show_port_owner "$CONN_PORT"
HAS_ERROR=1
else
show_ok "端口 $CONN_PORT 可用"
fi
if port_in_use "$QUERY_PORT"; then
show_error "端口 $QUERY_PORT 已被占用"
show_port_owner "$QUERY_PORT"
HAS_ERROR=1
else
show_ok "端口 $QUERY_PORT 可用"
fi
echo "=================================="
if [ "$HAS_ERROR" -ne 0 ]; then
echo ""
show_error "端口被占用,请先执行:"
echo "$0 stop"
echo ""
echo "如果 stop 后仍占用,执行:"
echo "$0 kill"
return 1
fi
return 0
}
show_ports_status() {
CONN_PORT=$(get_connection_port)
QUERY_PORT=$(get_query_port)
echo "========== ETS2 端口状态 =========="
echo "connection_dedicated_port: $CONN_PORT"
show_port_owner "$CONN_PORT"
echo ""
echo "query_dedicated_port: $QUERY_PORT"
show_port_owner "$QUERY_PORT"
echo "=================================="
}
pgid_has_ets2() {
TARGET_PGID="$1"
if [ -z "$TARGET_PGID" ]; then
return 1
fi
ps -eo pgid=,cmd= | awk -v pgid="$TARGET_PGID" '
$1 == pgid && ($0 ~ /eurotrucks2_server/ || $0 ~ /server_launch.sh/ || $0 ~ /script .*server_launch.sh/) {
found=1
}
END {
exit !found
}
'
}
kill_ets2_port_owners() {
CONN_PORT=$(get_connection_port)
QUERY_PORT=$(get_query_port)
for PORT in "$CONN_PORT" "$QUERY_PORT"; do
for P in $(get_port_owner_pids "$PORT"); do
CMD=$(ps -p "$P" -o command= 2>/dev/null)
case "$CMD" in
*eurotrucks2_server*|*server_launch.sh*)
show_warn "端口 $PORT 仍被 ETS2 进程占用,强制清理 PID: $P"
kill -TERM "$P" 2>/dev/null || true
sleep 1
kill -KILL "$P" 2>/dev/null || true
;;
*)
show_warn "端口 $PORT 被非 ETS2 进程占用PID: $P"
echo "$CMD"
;;
esac
done
done
}
wait_ports_release() {
CONN_PORT=$(get_connection_port)
QUERY_PORT=$(get_query_port)
COUNT=0
while [ "$COUNT" -lt 10 ]; do
if ! port_in_use "$CONN_PORT" && ! port_in_use "$QUERY_PORT"; then
show_ok "端口 $CONN_PORT / $QUERY_PORT 已释放。"
return 0
fi
sleep 1
COUNT=$((COUNT + 1))
done
show_warn "端口仍未完全释放,尝试按端口兜底清理..."
kill_ets2_port_owners
sleep 2
if ! port_in_use "$CONN_PORT" && ! port_in_use "$QUERY_PORT"; then
show_ok "端口 $CONN_PORT / $QUERY_PORT 已释放。"
return 0
fi
show_error "端口仍被占用:"
show_port_owner "$CONN_PORT"
show_port_owner "$QUERY_PORT"
return 1
}
force_cleanup_server() {
prepare_dirs
show_warn "正在清理残留 ETS2 进程..."
RUNNER_PID=""
PGID=""
if [ -f "$RUNNER_PID_FILE" ]; then
RUNNER_PID=$(cat "$RUNNER_PID_FILE")
fi
if [ -f "$PGID_FILE" ]; then
PGID=$(cat "$PGID_FILE")
fi
if [ -n "$PGID" ]; then
if pgid_has_ets2 "$PGID"; then
show_warn "正在停止 ETS2 进程组 PGID: $PGID"
kill -TERM "-$PGID" 2>/dev/null || true
else
show_warn "PGID $PGID 不存在或不属于 ETS2跳过进程组终止"
fi
fi
if [ -n "$RUNNER_PID" ]; then
show_warn "正在停止启动器 PID: $RUNNER_PID"
kill -TERM "$RUNNER_PID" 2>/dev/null || true
fi
pkill -TERM -f "eurotrucks2_server" 2>/dev/null || true
pkill -TERM -f "server_launch.sh" 2>/dev/null || true
pkill -TERM -f "script .*server_launch.sh" 2>/dev/null || true
sleep 3
if [ -n "$PGID" ]; then
if pgid_has_ets2 "$PGID"; then
kill -KILL "-$PGID" 2>/dev/null || true
fi
fi
if [ -n "$RUNNER_PID" ]; then
kill -KILL "$RUNNER_PID" 2>/dev/null || true
fi
pkill -KILL -f "eurotrucks2_server" 2>/dev/null || true
pkill -KILL -f "server_launch.sh" 2>/dev/null || true
pkill -KILL -f "script .*server_launch.sh" 2>/dev/null || true
kill_ets2_port_owners
rm -f "$PID_FILE"
rm -f "$RUNNER_PID_FILE"
rm -f "$PGID_FILE"
wait_ports_release || true
show_ok "残留进程清理完成。"
}
run_server_realtime() {
cd "$SERVER_HOME" || exit 1
if command -v script >/dev/null 2>&1; then
script -qefc "$SERVER_LAUNCH $SERVER_OPTIONS" /dev/null
elif command -v stdbuf >/dev/null 2>&1; then
stdbuf -oL -eL "$SERVER_LAUNCH" $SERVER_OPTIONS
else
"$SERVER_LAUNCH" $SERVER_OPTIONS
fi
}
case "$1" in
start)
show_info "正在启动 ETS2 服务器..."
prepare_dirs
cleanup_old_logs
SERVER_PID=$(get_server_pid)
if [ -z "$SERVER_PID" ]; then
SERVER_PID=$(get_ets2_pid_from_ports)
fi
if [ -n "$SERVER_PID" ]; then
show_warn "ETS2 服务器似乎已经在运行PID: $SERVER_PID"
echo "$SERVER_PID" > "$PID_FILE"
if [ -f "$CURRENT_LOG_PATH_FILE" ]; then
show_info "本次日志: $(cat "$CURRENT_LOG_PATH_FILE")"
fi
exit 0
fi
check_ports_available || exit 1
create_log_file
cd "$SERVER_HOME" || exit 1
setsid sh -c '
SERVER_HOME="$1"
SERVER_LAUNCH="$2"
SERVER_OPTIONS="$3"
SERVER_LOG="$4"
cd "$SERVER_HOME" || exit 1
if command -v script >/dev/null 2>&1; then
script -qefc "$SERVER_LAUNCH $SERVER_OPTIONS" /dev/null
elif command -v stdbuf >/dev/null 2>&1; then
stdbuf -oL -eL "$SERVER_LAUNCH" $SERVER_OPTIONS
else
"$SERVER_LAUNCH" $SERVER_OPTIONS
fi 2>&1 | awk '"'"'{print strftime("%Y-%m-%d %H:%M:%S"), "-", $0; fflush();}'"'"' >> "$SERVER_LOG"
' sh "$SERVER_HOME" "$SERVER_LAUNCH" "$SERVER_OPTIONS" "$SERVER_LOG" >/dev/null 2>&1 &
RUNNER_PID=$!
echo "$RUNNER_PID" > "$RUNNER_PID_FILE"
echo "$RUNNER_PID" > "$PGID_FILE"
show_info "启动器 PID: $RUNNER_PID"
show_info "进程组 PGID: $RUNNER_PID"
show_info "等待 ETS2 服务端启动,最多等待 60 秒..."
WAIT_COUNT=0
SERVER_PID=""
LAUNCH_PID=""
while [ "$WAIT_COUNT" -lt 60 ]; do
SERVER_PID=$(get_server_pid)
if [ -z "$SERVER_PID" ]; then
SERVER_PID=$(get_ets2_pid_from_ports)
fi
LAUNCH_PID=$(get_launch_pid)
if [ -n "$SERVER_PID" ]; then
echo "$SERVER_PID" > "$PID_FILE"
show_ok "ETS2 服务器已启动PID: $SERVER_PID"
show_info "最新日志: $LATEST_LOG_LINK"
show_info "本次日志: $SERVER_LOG"
exit 0
fi
if [ -n "$LAUNCH_PID" ]; then
show_info "启动脚本仍在运行PID: $LAUNCH_PID,继续等待..."
fi
if grep -qiE "Failed to init|Server was terminated|couldn't find an open port|Server packages file not found|SteamAPI_Init.*failed|\*\*\* ERROR \*\*\*" "$SERVER_LOG" 2>/dev/null; then
show_error "检测到启动错误,准备清理残留进程..."
tail -n 100 "$SERVER_LOG"
force_cleanup_server
exit 1
fi
WAIT_COUNT=$((WAIT_COUNT + 1))
sleep 1
done
SERVER_PID=$(get_server_pid)
if [ -z "$SERVER_PID" ]; then
SERVER_PID=$(get_ets2_pid_from_ports)
fi
if [ -n "$SERVER_PID" ]; then
echo "$SERVER_PID" > "$PID_FILE"
show_ok "ETS2 服务器已启动PID: $SERVER_PID"
show_info "最新日志: $LATEST_LOG_LINK"
show_info "本次日志: $SERVER_LOG"
exit 0
fi
show_error "等待 60 秒后仍未检测到 ETS2 主进程,准备清理残留进程..."
tail -n 120 "$SERVER_LOG"
force_cleanup_server
exit 1
;;
debug)
show_info "正在以前台调试模式启动 ETS2 服务器..."
show_warn "当前不会后台运行,按 Ctrl+C 可停止服务器。"
prepare_dirs
cleanup_old_logs
create_log_file
check_required_files
OLD_PID=$(get_server_pid)
if [ -z "$OLD_PID" ]; then
OLD_PID=$(get_ets2_pid_from_ports)
fi
if [ -n "$OLD_PID" ]; then
show_error "检测到已有 ETS2 服务端进程正在运行PID: $OLD_PID"
echo ""
echo "请先执行:"
echo "$0 stop"
echo ""
echo "如果仍然无法释放端口,执行:"
echo "$0 kill"
exit 1
fi
check_ports_available || exit 1
trap '
echo ""
echo "[WARN] 收到中断信号,正在退出 debug 模式..."
force_cleanup_server
echo "[OK] debug 残留进程已清理。"
exit 130
' INT TERM HUP
echo ""
echo "========== 开始前台调试 =========="
echo "执行命令:"
echo "$SERVER_LAUNCH $SERVER_OPTIONS"
echo "本次日志:"
echo "$SERVER_LOG"
echo "=================================="
echo ""
run_server_realtime 2>&1 | \
awk '{print strftime("%Y-%m-%d %H:%M:%S"), "-", $0; fflush();}' | \
tee -a "$SERVER_LOG"
trap - INT TERM HUP
show_warn "debug 模式已退出,正在清理可能残留的 ETS2 进程..."
force_cleanup_server
;;
stop)
show_info "正在停止 ETS2 服务器..."
force_cleanup_server
;;
kill)
force_cleanup_server
;;
restart)
show_info "正在重启 ETS2 服务器..."
"$0" stop
sleep 3
"$0" start
;;
update)
show_info "正在更新 ETS2 专用服务器..."
SERVER_PID=$(get_server_pid)
if [ -n "$SERVER_PID" ]; then
show_warn "检测到服务器正在运行,先停止服务器..."
"$0" stop
sleep 3
fi
mkdir -p "$STEAMCMD_HOME" "$ETS2_INSTALL_DIR"
cd "$STEAMCMD_HOME" || exit 1
show_info "检查 SteamCMD..."
curl -sqL "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz" | tar zxvf -
chmod +x "$STEAMCMD_HOME/steamcmd.sh"
show_info "开始更新 ETS2 Dedicated Server..."
"$STEAMCMD_HOME/steamcmd.sh" \
+force_install_dir "$ETS2_INSTALL_DIR" \
+login anonymous \
+app_update "$ETS2_APP_ID" validate \
+quit
show_ok "ETS2 专用服务器更新完成。"
;;
status)
prepare_dirs
SERVER_PID=$(get_server_pid)
if [ -z "$SERVER_PID" ]; then
SERVER_PID=$(get_ets2_pid_from_ports)
fi
LAUNCH_PID=$(get_launch_pid)
if [ -n "$SERVER_PID" ]; then
show_ok "ETS2 服务器正在运行PID: $SERVER_PID"
if [ -n "$LAUNCH_PID" ]; then
show_info "启动脚本进程 PID: $LAUNCH_PID"
fi
if [ -f "$CURRENT_LOG_PATH_FILE" ]; then
show_info "本次日志: $(cat "$CURRENT_LOG_PATH_FILE")"
fi
show_info "最新日志: $LATEST_LOG_LINK"
echo ""
show_ports_status
else
show_warn "ETS2 服务器未运行。"
rm -f "$PID_FILE"
fi
;;
log)
prepare_dirs
if [ -L "$LATEST_LOG_LINK" ] || [ -f "$LATEST_LOG_LINK" ]; then
tail -n 100 -F "$LATEST_LOG_LINK"
else
show_warn "暂无最新日志文件。"
show_info "请先执行:$0 start 或 $0 debug"
fi
;;
listlog)
prepare_dirs
echo "最近日志文件:"
find "$LOG_ROOT" -type f -name "*.log" 2>/dev/null | sort | tail -n 30
;;
cleanlog)
prepare_dirs
cleanup_old_logs
show_ok "已清理超过 $LOG_KEEP_DAYS 天的日志目录。"
;;
check)
prepare_dirs
check_required_files
echo ""
check_ports_available || true
;;
ports)
prepare_dirs
check_ports_available || true
;;
portstatus)
prepare_dirs
show_ports_status
;;
*)
echo "ETS2 服务器管理命令"
echo "用法: ets2_sv {start|stop|restart|status|update|debug|log|listlog|cleanlog|check|ports|portstatus|kill}"
echo ""
echo " start - 后台启动 ETS2 服务器"
echo " stop - 停止 ETS2 服务器,并释放端口"
echo " restart - 重启 ETS2 服务器"
echo " status - 查看 ETS2 服务器状态"
echo " update - 更新 ETS2 专用服务器"
echo " debug - 前台调试启动,不后台运行,实时输出"
echo " log - 实时查看最新日志"
echo " listlog - 查看最近日志文件"
echo " cleanlog - 清理旧日志"
echo " check - 检查配置文件和端口"
echo " ports - 检查端口是否可用"
echo " portstatus - 查看端口占用详情"
echo " kill - 强制清理残留 ETS2 进程"
exit 1
;;
esac