[GH-ISSUE #4419] [Feature]: Rustserver shutdown-warning in in-game chat #2762

Open
opened 2026-02-27 03:05:17 +03:00 by kerem · 3 comments
Owner

Originally created by @JuliusZet on GitHub (Dec 16, 2023).
Original GitHub issue: https://github.com/GameServerManagers/LinuxGSM/issues/4419

User story

As a player on a Rust server, I want to receive occasional warnings in the in-game chat before the server shuts down or restarts, so that I have a chance to prepare.

Game

Rust

Linux distro

No response

Command

command: stop

Further information

Hi there

When a Rust server is stopped, which can for example happen with the commands

  • ./rustserver stop
  • ./rustserver restart
  • ./rustserver (force-)update
  • ./rustserver backup

then it will send Ctrl+c to the tmux session. This shuts the server down immediately. I have two issues with this:

  1. Because this Ctrl+c does not explicitly execute a save, any progress of up to 300 seconds will be lost, depending on when the last save happened. (I am not 100 % sure on that, so please correct me if I am wrong.)
  2. When there are players connected to the server, they will be surprised by the shutdown and do hot have any chance to prepare.

To fix these, I would like to implement a new method to stop a Rust server, that sends the quit command via rcon to the Rust server after 15 minutes. During these 15 minutes, occasional warnings should be sent to the in-game chat, to warn any connected players, so that they can prepare. The quit command also ensures that the game is saved directly before the shutdown, so no progress is lost.

Please let me know what you think and have a great day! :)

Kind regards
JuliusZet

Originally created by @JuliusZet on GitHub (Dec 16, 2023). Original GitHub issue: https://github.com/GameServerManagers/LinuxGSM/issues/4419 ### User story As a player on a Rust server, I want to receive occasional warnings in the in-game chat before the server shuts down or restarts, so that I have a chance to prepare. ### Game Rust ### Linux distro _No response_ ### Command command: stop ### Further information Hi there When a Rust server is stopped, which can for example happen with the commands - `./rustserver stop` - `./rustserver restart` - `./rustserver (force-)update` - `./rustserver backup` then it will send `Ctrl+c` to the tmux session. This shuts the server down immediately. I have two issues with this: 1. Because this `Ctrl+c` does not explicitly execute a save, any progress of up to 300 seconds will be lost, depending on when the last save happened. (I am not 100 % sure on that, so please correct me if I am wrong.) 2. When there are players connected to the server, they will be surprised by the shutdown and do hot have any chance to prepare. To fix these, I would like to implement a new method to stop a Rust server, that sends the `quit` command via rcon to the Rust server after 15 minutes. During these 15 minutes, occasional warnings should be sent to the in-game chat, to warn any connected players, so that they can prepare. The `quit` command also ensures that the game is saved directly before the shutdown, so no progress is lost. Please let me know what you think and have a great day! :) Kind regards JuliusZet
Author
Owner

@JuliusZet commented on GitHub (Dec 16, 2023):

I have a few rough ideas on how that could work, but it would be great, if someone could implement this properly.

In modules/command_stop.sh Add a new stopmode:

fn_stop_graceful_select() {
	if [ "${stopmode}" == "1" ]; then
		fn_stop_tmux
[...]
	elif [ "${stopmode}" == "13" ]; then
		fn_stop_graceful_rust
	fi
}

Define the function fn_stop_graceful_rust() in modules/command_stop.sh:

fn_stop_graceful_rust() {
	fn_print_dots "Graceful: rcon quit: sending quit via rcon in 15 minutes"
	fn_script_log_info "Graceful: rcon quit: sending quit via rcon in 15 minutes"

	# wait 15 minutes and output occasional warnings in chat
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 15 minutes.'
	fn_print_dots "Graceful: rcon quit: 15-minute-warning sent"
	sleep "300"
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 10 minutes.'
	fn_print_dots "Graceful: rcon quit: 10-minute-warning sent"
	sleep "300"
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 5 minutes.'
	fn_print_dots "Graceful: rcon quit: 5-minute-warning sent"
	sleep "60"
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 4 minutes.'
	fn_print_dots "Graceful: rcon quit: 4-minute-warning sent"
	sleep "60"
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 3 minutes.'
	fn_print_dots "Graceful: rcon quit: 3-minute-warning sent"
	sleep "60"
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 2 minutes.'
	fn_print_dots "Graceful: rcon quit: 2-minute-warning sent"
	sleep "60"
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 1 minute.'
	fn_print_dots "Graceful: rcon quit: 1-minute-warning sent"
	sleep "30"
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 30 seconds.'
	fn_print_dots "Graceful: rcon quit: 30-second-warning sent"
	sleep "15"
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 15 seconds.'
	fn_print_dots "Graceful: rcon quit: 15-second-warning sent"
	sleep "5"
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 10 seconds.'
	fn_print_dots "Graceful: rcon quit: 10-second-warning sent"
	sleep "1"
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 9 seconds.'
	fn_print_dots "Graceful: rcon quit: 9-second-warning sent"
	sleep "1"
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 8 seconds.'
	fn_print_dots "Graceful: rcon quit: 8-second-warning sent"
	sleep "1"
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 7 seconds.'
	fn_print_dots "Graceful: rcon quit: 7-second-warning sent"
	sleep "1"
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 6 seconds.'
	fn_print_dots "Graceful: rcon quit: 6-second-warning sent"
	sleep "1"
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 5 seconds.'
	fn_print_dots "Graceful: rcon quit: 5-second-warning sent"
	sleep "1"
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 4 seconds.'
	fn_print_dots "Graceful: rcon quit: 4-second-warning sent"
	sleep "1"
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 3 seconds.'
	fn_print_dots "Graceful: rcon quit: 3-second-warning sent"
	sleep "1"
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 2 seconds.'
	fn_print_dots "Graceful: rcon quit: 2-second-warning sent"
	sleep "1"
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say :  ATTENTION! The server will restart in 1 second.'
	fn_print_dots "Graceful: rcon quit: 1-second-warning sent"
	sleep "1"

	# send "quit" via rcon
	"${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'quit'
	fn_print_dots "Graceful: rcon quit: quit command sent via rcon"

	# Waits up to 30 seconds giving the server time to shutdown gracefuly.
	for seconds in {1..30}; do
		check_status.sh
		if [ "${status}" == "0" ]; then
			fn_print_ok "Graceful: rcon quit: quit command sent via rcon - waiting for server shutdown to complete: ${seconds}: "
			fn_print_ok_eol_nl
			fn_script_log_pass "Graceful: rcon quit: OK: ${seconds} seconds"
			if [ "${statusalert}" == "on" ] && [ "${firstcommandname}" == "STOP" ]; then
				alert="stopped"
				alert.sh
			fi
			break
		fi
		fn_sleep_time_1
		fn_print_dots "Graceful: rcon quit: quit command sent via rcon - waiting for server shutdown to complete: ${seconds}"
	done
	check_status.sh
	if [ "${status}" != "0" ]; then
		fn_print_error "Graceful: rcon quit: "
		fn_print_fail_eol_nl
		fn_script_log_error "Graceful: rcon quit: FAIL"
	fi
}

This requires, that the user manually downloads the rcon executable (from https://github.com/gorcon/rcon-cli) to ~/.local/bin/. This should ideally happen automatically with the execution of ./rustserver install. Maybe there is a better place for it than ~/.local/bin/, for example in the lgsm/modules/ directory?

<!-- gh-comment-id:1858827968 --> @JuliusZet commented on GitHub (Dec 16, 2023): I have a few rough ideas on how that could work, but it would be great, if someone could implement this properly. In `modules/command_stop.sh` Add a new stopmode: ``` fn_stop_graceful_select() { if [ "${stopmode}" == "1" ]; then fn_stop_tmux [...] elif [ "${stopmode}" == "13" ]; then fn_stop_graceful_rust fi } ``` Define the function `fn_stop_graceful_rust()` in `modules/command_stop.sh`: ``` fn_stop_graceful_rust() { fn_print_dots "Graceful: rcon quit: sending quit via rcon in 15 minutes" fn_script_log_info "Graceful: rcon quit: sending quit via rcon in 15 minutes" # wait 15 minutes and output occasional warnings in chat "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 15 minutes.' fn_print_dots "Graceful: rcon quit: 15-minute-warning sent" sleep "300" "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 10 minutes.' fn_print_dots "Graceful: rcon quit: 10-minute-warning sent" sleep "300" "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 5 minutes.' fn_print_dots "Graceful: rcon quit: 5-minute-warning sent" sleep "60" "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 4 minutes.' fn_print_dots "Graceful: rcon quit: 4-minute-warning sent" sleep "60" "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 3 minutes.' fn_print_dots "Graceful: rcon quit: 3-minute-warning sent" sleep "60" "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 2 minutes.' fn_print_dots "Graceful: rcon quit: 2-minute-warning sent" sleep "60" "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 1 minute.' fn_print_dots "Graceful: rcon quit: 1-minute-warning sent" sleep "30" "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 30 seconds.' fn_print_dots "Graceful: rcon quit: 30-second-warning sent" sleep "15" "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 15 seconds.' fn_print_dots "Graceful: rcon quit: 15-second-warning sent" sleep "5" "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 10 seconds.' fn_print_dots "Graceful: rcon quit: 10-second-warning sent" sleep "1" "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 9 seconds.' fn_print_dots "Graceful: rcon quit: 9-second-warning sent" sleep "1" "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 8 seconds.' fn_print_dots "Graceful: rcon quit: 8-second-warning sent" sleep "1" "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 7 seconds.' fn_print_dots "Graceful: rcon quit: 7-second-warning sent" sleep "1" "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 6 seconds.' fn_print_dots "Graceful: rcon quit: 6-second-warning sent" sleep "1" "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 5 seconds.' fn_print_dots "Graceful: rcon quit: 5-second-warning sent" sleep "1" "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 4 seconds.' fn_print_dots "Graceful: rcon quit: 4-second-warning sent" sleep "1" "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 3 seconds.' fn_print_dots "Graceful: rcon quit: 3-second-warning sent" sleep "1" "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 2 seconds.' fn_print_dots "Graceful: rcon quit: 2-second-warning sent" sleep "1" "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'say : ATTENTION! The server will restart in 1 second.' fn_print_dots "Graceful: rcon quit: 1-second-warning sent" sleep "1" # send "quit" via rcon "${HOME}/.local/bin/rcon" -a 127.0.0.1:${rconport} -p ${rconpassword} -t web 'quit' fn_print_dots "Graceful: rcon quit: quit command sent via rcon" # Waits up to 30 seconds giving the server time to shutdown gracefuly. for seconds in {1..30}; do check_status.sh if [ "${status}" == "0" ]; then fn_print_ok "Graceful: rcon quit: quit command sent via rcon - waiting for server shutdown to complete: ${seconds}: " fn_print_ok_eol_nl fn_script_log_pass "Graceful: rcon quit: OK: ${seconds} seconds" if [ "${statusalert}" == "on" ] && [ "${firstcommandname}" == "STOP" ]; then alert="stopped" alert.sh fi break fi fn_sleep_time_1 fn_print_dots "Graceful: rcon quit: quit command sent via rcon - waiting for server shutdown to complete: ${seconds}" done check_status.sh if [ "${status}" != "0" ]; then fn_print_error "Graceful: rcon quit: " fn_print_fail_eol_nl fn_script_log_error "Graceful: rcon quit: FAIL" fi } ``` This requires, that the user manually downloads the `rcon` executable (from https://github.com/gorcon/rcon-cli) to `~/.local/bin/`. This should ideally happen automatically with the execution of `./rustserver install`. Maybe there is a better place for it than `~/.local/bin/`, for example in the `lgsm/modules/` directory?
Author
Owner

@JimTR commented on GitHub (Dec 17, 2023):

Just a thought why not just send the required commands to the tmux instance ?
something like tmux send "Server shutting down in x mins" ENTER rather than going for recon ?

<!-- gh-comment-id:1859068048 --> @JimTR commented on GitHub (Dec 17, 2023): Just a thought why not just send the required commands to the tmux instance ? something like ```tmux send "Server shutting down in x mins" ENTER``` rather than going for recon ?
Author
Owner

@JuliusZet commented on GitHub (Dec 17, 2023):

Just a thought why not just send the required commands to the tmux instance ? something like tmux send "Server shutting down in x mins" ENTER rather than going for recon ?

That is because the Rust server console in tmux is non-interactive. You can not enter any commands through it. :/

<!-- gh-comment-id:1859103088 --> @JuliusZet commented on GitHub (Dec 17, 2023): > Just a thought why not just send the required commands to the tmux instance ? something like `tmux send "Server shutting down in x mins" ENTER` rather than going for recon ? That is because the Rust server console in tmux is non-interactive. You can not enter any commands through it. :/
Sign in to join this conversation.
No labels
Atomic
Epic
cannot reproduce
command: backup
command: console
command: debug
command: details
command: fast-dl
command: install
command: mods
command: monitor
command: post-details
command: restart
command: send
command: start
command: stop
command: update
command: update-lgsm
command: validate
command: wipe
distro: AlmaLinux
distro: Arch Linux
distro: CentOS
distro: Debian
distro: Fedora
distro: RedHat
distro: Rocky Linux
distro: Ubuntu
distro: openSUSE
engine: goldsrc
engine: source
game: 7 Days to Die
game: ARMA 3
game: Ark: Survival Evolved
game: Assetto Corsa
game: Avorion
game: BATTALION: Legacy
game: Barotrauma
game: Battalion 1944
game: Battlefield 1942
game: Black Mesa: Deathmatch
game: Blade Symphony
game: Call of Duty 2
game: Call of Duty 4
game: Call of Duty: United Offensive
game: Counter-Strike 1.6
game: Counter-Strike 2
game: Counter-Strike: Global Offensive
game: Counter-Strike: Source
game: Day of Infamy
game: Dayz
game: Death Match Classic
game: Don't Starve Together
game: ET: Legacy
game: Eco
game: Factorio
game: Factorio
game: Garry's Mod
game: Half-Life
game: Hurtword
game: Insurgecy
game: Insurgecy
game: Insurgency: Sandstorm
game: Just Cause 3
game: Killing Floor
game: Killing Floor 2
game: Left 4 Dead 2
game: Minecraft
game: Minecraft Bedrock
game: Mordhau
game: Multi Theft Auto
game: Mumble
game: Natural Selection 2
game: No More Room in Hell
game: Pavlov VR
game: Post Scriptum
game: Project Zomboid
game: Quake 3
game: QuakeWorld
game: Red Orchestra: Ostfront 41-45
game: Return to Castle Wolfenstein
game: Rising World
game: Rust
game: San Andreas Multiplayer
game: Satisfactory
game: Soldat
game: Soldier of Fortune 2
game: Squad
game: Squad 44
game: Starbound
game: Stationeers
game: Sven Co-op
game: Team Fortress 2
game: Teamspeak 3
game: Teeworlds
game: Terraria
game: The Front
game: Unreal Tournament 2004
game: Unreal Tournament 3
game: Unreal Tournament 99
game: Unturned
game: Valheim
game: Wurm Unlimited
game: Zombie Master Reborn
game: label missing
good first issue
help wanted
info: alerts
info: dependency
info: docker
info: docs
info: email
info: query
info: steamcmd
info: systemd
info: tmux
info: website
info: website
needs more info
outcome: duplicate
outcome: issue resolved
outcome: issue resolved
outcome: issue unresolved
outcome: pr accepted
outcome: pr rejected
outcome: unconfirmed
outcome: wontfix
outcome: wrong forum
potential-duplicate
priority
pull-request
type: bug
type: feature
type: feature
type: feature request
type: game server request
type: refactor
waiting response
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/LinuxGSM#2762
No description provided.