From 26757e96e2e4702a191855d94baefedef3d1790e Mon Sep 17 00:00:00 2001 From: Leonid Pershin Date: Sat, 9 May 2026 22:23:54 +0300 Subject: [PATCH] Add clear-ground-items-hourly.sh script for hourly item cleanup on Minecraft server via RCON. Update .gitignore to include the new script. --- .gitignore | 1 + Server/clear-ground-items-hourly.sh | 131 ++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100755 Server/clear-ground-items-hourly.sh diff --git a/.gitignore b/.gitignore index edc7bbf..a8a78d2 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ !/Server/extract-missing-ru-translations.ps1 !/Server/install-service.sh !/Server/restart-scheduled.sh +!/Server/clear-ground-items-hourly.sh !/Server/README.md !/Server/start.sh !/Server/variables.txt diff --git a/Server/clear-ground-items-hourly.sh b/Server/clear-ground-items-hourly.sh new file mode 100755 index 0000000..c6fc3cf --- /dev/null +++ b/Server/clear-ground-items-hourly.sh @@ -0,0 +1,131 @@ +#!/usr/bin/env bash +# Почасовая очистка выброшенных на земле предметов (сущность minecraft:item) через RCON +# с тем же графиком предупреждений, что и restart-scheduled.sh (10 / 5 / 1 мин, 30 с, 5…1). +# +# Требования: RCON как в restart-scheduled.sh (mcrcon или rcon), server.properties, +# сервер в systemd active (по умолчанию unit minecraft). +# +# Расписание — каждый час, например в начале часа: +# 0 * * * * /usr/bin/bash /opt/PupaMLupa/Server/clear-ground-items-hourly.sh >>/var/log/mc-clear-items.log 2>&1 +# Чтобы не пересекаться по времени с перезапуском в 00:00 / 06:00 / 12:00 / 18:00, можно сместить: +# 30 * * * * .../clear-ground-items-hourly.sh ... +# +# Переменные окружения (необязательно): +# MINECRAFT_SERVICE — unit systemd (по умолчанию: minecraft) +# RCON_HOST, RCON_PORT, RCON_PASSWORD, RCON_TIMEOUT — как в restart-scheduled.sh +# CLEAR_ITEMS_RCON_CMD — команда консоли без ведущего / (по умолчанию: +# kill @e[type=minecraft:item]) + +set -euo pipefail +export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PATH:-}" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "${SCRIPT_DIR}" + +MINECRAFT_SERVICE="${MINECRAFT_SERVICE:-minecraft}" +RCON_HOST="${RCON_HOST:-127.0.0.1}" +RCON_TIMEOUT="${RCON_TIMEOUT:-60s}" +RCON_CLIENT="" +CLEAR_ITEMS_RCON_CMD="${CLEAR_ITEMS_RCON_CMD:-kill @e[type=minecraft:item]}" + +LOCK_FILE="${SCRIPT_DIR}/.clear-ground-items-hourly.lock" +PROPS="${SCRIPT_DIR}/server.properties" + +log() { + echo "[$(date -Iseconds)] $*" +} + +die() { + log "ОШИБКА: $*" >&2 + exit 1 +} + +read_prop() { + local key="$1" + [[ -f "${PROPS}" ]] || die "нет файла ${PROPS}" + grep -E "^[[:space:]]*${key}[[:space:]]*=" "${PROPS}" 2>/dev/null | head -n1 \ + | cut -d= -f2- | tr -d '\r' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' +} + +systemctl_wrap() { + if [[ "${EUID:-0}" -eq 0 ]]; then + systemctl "$@" + elif command -v sudo >/dev/null 2>&1 && sudo -n true 2>/dev/null; then + sudo -n systemctl "$@" + else + systemctl "$@" + fi +} + +rcon_exec() { + local cmd="$1" + if [[ "${RCON_CLIENT}" == "mcrcon" ]]; then + mcrcon -H "${RCON_HOST}" -P "${RCON_PORT}" -p "${RCON_PASSWORD}" "${cmd}" + else + set -f + # shellcheck disable=SC2086 + rcon -a "${RCON_HOST}:${RCON_PORT}" -p "${RCON_PASSWORD}" -T "${RCON_TIMEOUT}" ${cmd} + set +f + fi +} + +rcon_say() { + rcon_exec "say $1" +} + +exec 9>"${LOCK_FILE}" +if ! flock -n 9; then + log "уже идёт другой запуск (flock ${LOCK_FILE}) — выход." + exit 0 +fi + +if command -v mcrcon >/dev/null 2>&1; then + RCON_CLIENT="mcrcon" +elif command -v rcon >/dev/null 2>&1; then + RCON_CLIENT="rcon" +else + die "нужен mcrcon или rcon (см. restart-scheduled.sh в этом каталоге)." +fi +log "RCON-клиент: ${RCON_CLIENT}" + +if ! systemctl_wrap is-active --quiet "${MINECRAFT_SERVICE}"; then + log "сервис ${MINECRAFT_SERVICE} не active — очистка пропущена." + exit 0 +fi + +rc_en="$(read_prop enable-rcon)" +[[ "${rc_en,,}" == "true" ]] || die "в server.properties включите enable-rcon=true" + +_prop_port="$(read_prop rcon.port)" +_prop_pass="$(read_prop rcon.password)" +RCON_PORT="${RCON_PORT:-${_prop_port}}" +RCON_PASSWORD="${RCON_PASSWORD:-${_prop_pass}}" +[[ -n "${RCON_PORT}" ]] || die "не задан rcon.port (или RCON_PORT)" +[[ -n "${RCON_PASSWORD}" ]] || die "не задан rcon.password (или RCON_PASSWORD)" + +rcon_exec "list" >/dev/null || die "RCON не отвечает (${RCON_HOST}:${RCON_PORT})" + +log "Старт почасовой очистки предметов на земле (${MINECRAFT_SERVICE})." + +rcon_say "[Сервер] Очистка лежащих предметов через 10 минут!" +sleep 300 + +rcon_say "[Сервер] Очистка предметов через 5 минут!" +sleep 240 + +rcon_say "[Сервер] Очистка предметов через 1 минуту!" +sleep 30 + +rcon_say "[Сервер] Очистка предметов через 30 секунд!" +sleep 25 + +for n in 5 4 3 2 1; do + rcon_say "[Сервер] $n" + sleep 1 +done + +log "Выполняю: ${CLEAR_ITEMS_RCON_CMD}" +rcon_exec "${CLEAR_ITEMS_RCON_CMD}" +rcon_say "[Сервер] Лежащие предметы очищены." + +log "Готово."