#!/usr/bin/env bash # Почасовая очистка выброшенных на земле предметов (сущность item) через RCON # с тем же графиком предупреждений, что и restart-scheduled.sh (10 / 5 / 1 мин, 30 с, 5…1). # # Требования: RCON как в restart-scheduled.sh (mcrcon или rcon), server.properties, # сервер в systemd active (по умолчанию unit minecraft). # # Расписание (cron достаточно, отдельная блокировка между скриптами не обязательна): # Перезапуск обычно: 0 */6 * * * → в :00 часов 0, 6, 12, 18. # Очистку не ставьте в те же :00 — иначе ~10 минут предупреждений пересекутся. # Рекомендуется каждый час в половине часа (после типичного перезапуска уже всё тихо): # 30 * * * * /usr/bin/bash /opt/PupaMLupa/Server/clear-ground-items-hourly.sh >>/var/log/mc-clear-items.log 2>&1 # Другой вариант — одна фиксированная минута, не кратная 6-часовому перезапуску, например: # 17 * * * * … (каждый час в :17) # # Переменные окружения (необязательно): # MINECRAFT_SERVICE — unit systemd (по умолчанию: minecraft) # RCON_HOST, RCON_PORT, RCON_PASSWORD, RCON_TIMEOUT — как в restart-scheduled.sh # CLEAR_ITEMS_RCON_CMD — команда консоли без ведущего / (по умолчанию: # kill @e[type=item] — то же, что /kill в игре) 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=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 "Готово."