-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstop-server.sh
More file actions
executable file
·348 lines (292 loc) · 10.7 KB
/
Copy pathstop-server.sh
File metadata and controls
executable file
·348 lines (292 loc) · 10.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
#!/bin/bash
# Minecraft Bedrock Server Stop Script
# This script gracefully stops the Minecraft Bedrock server
set -euo pipefail
# Source configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/config.sh"
# Color codes for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging function
log() {
local level="$1"
shift
local message="$*"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
case "$level" in
INFO) echo -e "${GREEN}[INFO]${NC} $message" ;;
WARN) echo -e "${YELLOW}[WARN]${NC} $message" ;;
ERROR) echo -e "${RED}[ERROR]${NC} $message" ;;
DEBUG) echo -e "${BLUE}[DEBUG]${NC} $message" ;;
esac
# Also log to file if log directory exists
if [[ -d "$LOG_DIR" ]]; then
echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
fi
}
# Check if server is running
is_server_running() {
local screen_running=false
local process_running=false
# First check if screen session exists
if sudo -u "$SERVER_USER" screen -list | grep -q "$SCREEN_SESSION_NAME" 2>/dev/null; then
screen_running=true
fi
# Then check if the bedrock_server process is actually running
# Use multiple methods to be more reliable
if sudo -u "$SERVER_USER" pgrep -x "$SERVER_EXECUTABLE" >/dev/null 2>&1; then
process_running=true
elif sudo -u "$SERVER_USER" pgrep -f "\./$SERVER_EXECUTABLE" >/dev/null 2>&1; then
process_running=true
elif sudo -u "$SERVER_USER" ps aux | grep -v grep | grep -q "$SERVER_EXECUTABLE"; then
process_running=true
fi
# Debug output (uncomment for troubleshooting)
log DEBUG "Screen session running: $screen_running, Process running: $process_running"
# Server is considered running if BOTH screen session exists AND process is running
if [[ "$screen_running" == true && "$process_running" == true ]]; then
return 0
else
return 1
fi
}
# Send a message to all players before shutdown
send_shutdown_warning() {
local countdown="$1"
log INFO "Sending shutdown warning to players ($countdown seconds)..."
local message="Server will shut down in $countdown seconds. Please save your progress!"
# Send the message to the server console
sudo -u "$SERVER_USER" screen -S "$SCREEN_SESSION_NAME" -X stuff "say $message\n" || {
log WARN "Failed to send shutdown warning"
return 1
}
}
# Send a command to the server console
send_server_command() {
local command="$1"
if is_server_running; then
sudo -u "$SERVER_USER" screen -S "$SCREEN_SESSION_NAME" -X stuff "$command\n" || {
log ERROR "Failed to send command: $command"
return 1
}
return 0
else
log ERROR "Server is not running"
return 1
fi
}
# Gracefully stop the server
graceful_stop() {
local force="$1"
if ! is_server_running; then
log INFO "Server is not running"
return 0
fi
log INFO "Stopping Minecraft Bedrock Server gracefully..."
# If not forcing, send warnings to players
if [[ "$force" != "force" ]]; then
# Send warnings at 60, 30, 15, 5 seconds
send_shutdown_warning 60 || log WARN "Failed to send first shutdown warning"
sleep 45
if is_server_running; then
send_shutdown_warning 15 || log WARN "Failed to send second shutdown warning"
sleep 10
if is_server_running; then
send_shutdown_warning 5 || log WARN "Failed to send final shutdown warning"
sleep 5
fi
fi
fi
if is_server_running; then
# Save the world before stopping
log INFO "Saving world data..."
send_server_command "save hold" || log WARN "Failed to send 'save hold' command"
sleep 2
send_server_command "save query" || log WARN "Failed to send 'save query' command"
sleep 3
send_server_command "save resume" || log WARN "Failed to send 'save resume' command"
sleep 2
# Send stop command
log INFO "Sending stop command to server..."
send_server_command "stop" || log WARN "Failed to send 'stop' command"
# Give the server a moment to process the stop command
sleep 5
# Do an immediate check to see if server stopped quickly
if ! is_server_running; then
log INFO "Server stopped quickly after stop command"
else
log INFO "Server still running, continuing to wait..."
fi
# Wait for server to stop (max 60 seconds)
local count=0
local max_wait=60
log INFO "Waiting for server to stop (max $max_wait seconds)..."
while [[ $count -lt $max_wait ]]; do
# Check if server is still running
if ! is_server_running; then
log INFO "Server stopped after $count seconds"
break
fi
sleep 1
((count++))
# Show progress every 10 seconds
if [[ $((count % 10)) -eq 0 ]]; then
log INFO "Still waiting... ($count/$max_wait seconds)"
# Additional debug info every 20 seconds
if [[ $((count % 20)) -eq 0 ]]; then
local screen_status="not found"
local process_status="not found"
if sudo -u "$SERVER_USER" screen -list | grep -q "$SCREEN_SESSION_NAME" 2>/dev/null; then
screen_status="running"
fi
if sudo -u "$SERVER_USER" pgrep -x "$SERVER_EXECUTABLE" >/dev/null 2>&1 || \
sudo -u "$SERVER_USER" pgrep -f "\./$SERVER_EXECUTABLE" >/dev/null 2>&1; then
process_status="running"
fi
log DEBUG "Status check - Screen: $screen_status, Process: $process_status"
fi
fi
done
if is_server_running; then
log WARN "Server didn't stop gracefully within $max_wait seconds"
log WARN "Killing screen session..."
sudo -u "$SERVER_USER" screen -S "$SCREEN_SESSION_NAME" -X quit || {
log WARN "Failed to kill screen session gracefully"
}
sleep 2
# Also kill any remaining bedrock_server processes
if sudo -u "$SERVER_USER" pgrep -f "$SERVER_EXECUTABLE" >/dev/null 2>&1; then
log WARN "Killing remaining bedrock_server processes..."
sudo -u "$SERVER_USER" pkill -f "$SERVER_EXECUTABLE" || {
log ERROR "Failed to kill bedrock_server processes"
return 1
}
sleep 2
fi
if is_server_running; then
log ERROR "Failed to stop server"
return 1
else
log WARN "Server stopped forcefully"
fi
else
log INFO "Server stopped gracefully"
# Clean up any lingering screen session
if sudo -u "$SERVER_USER" screen -list | grep -q "$SCREEN_SESSION_NAME" 2>/dev/null; then
log INFO "Cleaning up screen session..."
sudo -u "$SERVER_USER" screen -S "$SCREEN_SESSION_NAME" -X quit || true
fi
fi
fi
return 0
}
# Force stop the server (immediate)
force_stop() {
if ! is_server_running; then
log INFO "Server is not running"
return 0
fi
log WARN "Force stopping Minecraft Bedrock Server..."
# First try to kill the bedrock_server process
if sudo -u "$SERVER_USER" pgrep -f "$SERVER_EXECUTABLE" >/dev/null 2>&1; then
log INFO "Killing bedrock_server processes..."
sudo -u "$SERVER_USER" pkill -f "$SERVER_EXECUTABLE" || {
log WARN "Failed to kill bedrock_server processes gracefully, trying with SIGKILL..."
sudo -u "$SERVER_USER" pkill -9 -f "$SERVER_EXECUTABLE" || {
log ERROR "Failed to kill bedrock_server processes"
}
}
sleep 2
fi
# Then kill the screen session
if sudo -u "$SERVER_USER" screen -list | grep -q "$SCREEN_SESSION_NAME" 2>/dev/null; then
log INFO "Killing screen session..."
sudo -u "$SERVER_USER" screen -S "$SCREEN_SESSION_NAME" -X quit || {
log WARN "Failed to kill screen session gracefully"
}
sleep 2
fi
if is_server_running; then
log ERROR "Failed to force stop server"
return 1
else
log INFO "Server stopped forcefully"
fi
return 0
}
# Show server status
show_status() {
echo ""
log INFO "Server Status:"
if is_server_running; then
log INFO "✓ Server is running"
# Show screen sessions
echo ""
log INFO "Active screen sessions:"
sudo -u "$SERVER_USER" screen -list | grep "$SCREEN_SESSION_NAME" || true
else
log INFO "✗ Server is not running"
fi
echo ""
}
# Show usage information
show_usage() {
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " -f, --force Force stop the server immediately (no warnings)"
echo " -s, --status Show server status only"
echo " -h, --help Show this help message"
echo ""
echo "Examples:"
echo " $0 Stop server gracefully with player warnings"
echo " $0 --force Stop server immediately"
echo " $0 --status Check if server is running"
}
# Main function
main() {
local action="stop"
local force_mode="normal"
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-f|--force)
force_mode="force"
shift
;;
-s|--status)
action="status"
shift
;;
-h|--help)
show_usage
exit 0
;;
*)
log ERROR "Unknown option: $1"
show_usage
exit 1
;;
esac
done
log INFO "Minecraft Bedrock Server Stop Script"
case "$action" in
"status")
show_status
;;
"stop")
if [[ "$force_mode" == "force" ]]; then
force_stop
else
graceful_stop "$force_mode"
fi
show_status
;;
esac
}
# Run main function
main "$@"