-
Notifications
You must be signed in to change notification settings - Fork 0
/
mcserver
executable file
·398 lines (355 loc) · 11.3 KB
/
mcserver
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
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
#!/bin/sh
# Author: Phidica Veia
# Create: 2015-07-10
# v0.1: 2015-07-10
# v1.0: 2015-07-14
serversDir=/opt/phidica/.minecraft-server
backupsDir=/home/phidica/.minecraft-server/backups
declare -a templateFiles=("run.sh" "eula.txt" "ops.json") # Files to copy from existing server when making new server
itsNotTomorrowUntilIWakeUp=true # If true - Up until 06:00, the date will be considered the previous day
reminder="Pause your torrents!" # An optional short reminder printed at startup; set to "" to ignore
debug=false # If true - run.sh will not actually be executed, everything else works as normal
_requestServer() # _resultVar
{
local _requestServer_resultVar=${1}
local serversArr=()
# Ensure serversDir exists
if [[ ! -e "${serversDir}" ]]; then
printf "%s\n" "mcserver error: ${serversDir} does not exist. Make it and put some servers in there!"
exit 1
fi
# Get alphabetical array of directories in the serversDir, that aren't backupsDir
for file in ${serversDir}/*; do
if [[ -d "${file}" && "$(basename ${file})" != "$(basename ${backupsDir})" ]]; then
serversArr+=("$(basename ${file})")
fi
done
# Check that serversArr contains at least one element
if [[ ${#serversArr[@]} -eq 0 ]]; then
printf "%s\n" "mcserver error: No servers found in ${serversDir}"
exit 1
fi
# Create an array of the indices of elements in serversArr, but they are in reverse chronological order of server modification times
local serversArrTimeIdcs=(
$(
for index in ${!serversArr[*]}; do # Gets an array of the array indices
modtimeStr="$(find ${serversDir}/${serversArr[${index}]}/ -exec stat "{}" --printf="%y\n" \; | sort -n -r | head -n 1)" # Most recent modtime of any contained file
printf "%s %s\n" "${modtimeStr}" "${index}"
done | sort -n -r | awk '{print $4}'
)
)
# Print server list
printf "%s\n" "Select a server by ID"
for index in ${!serversArrTimeIdcs[*]}; do # Gets an array of the array indices
printf "%s\n" " (${index}) ${serversArr[${serversArrTimeIdcs[${index}]}]}" # I'm sure this is very confusing to read; sorry
done
# Request user input and set _resultVar to the chosen server
while true; do
read -p "[0]: " usrOpt
if [[ ${usrOpt} -ge 0 && ${usrOpt} -lt ${#serversArr[*]} ]]; then # Checks against total number of entries in array
# Set the variable which was passed to this function to the chosen server
eval ${_requestServer_resultVar}="${serversArr[${serversArrTimeIdcs[${usrOpt}]}]}"
break
else
printf "%s\n" " Invalid selection"
fi
done
}
_launch() # serverBasename (optional)
{
serverBasenameOpt=${1}
# Put the server choice into a variable
local serverBasename
if [[ ${serverBasenameOpt} == "" ]]; then
_requestServer serverBasename
else
serverBasename=${serverBasenameOpt}
fi
# Check we'll be able to start the server
if [[ ! -e "${serversDir}/${serverBasename}/run.sh" ]]; then
printf "%s\n" "mcserver error: No run.sh file found for ${serverBasename}, server cannot be started"
exit 1
fi
# Offer the user to change the server MotD
_changeMotd serverBasename
# Run server
if [[ ${debug} == true ]]; then
printf "Debug: pretending to start server in ${serverBasename} \n"
else
printf "%s\n\n" "(Entering java)"
cd "${serversDir}/${serverBasename}"; sh run.sh
printf "\n%s\n" "(Exiting java)"
fi
# Prompt for backups
printf "%s\n" "Back up this server now?"
while true; do
read -p "[y]: " usrOpt
case ${usrOpt} in
y|Y|"")
_backUp "${serverBasename}"; break
;;
n|N)
break
;;
*)
printf "%s\n" " Invalid selection"
;;
esac
done
}
_new()
{
# Get target
while true; do
read -p "Name of new server (A-z_0-9): " targetServer
if [[ "${targetServer}" == "" ]]; then
printf "%s\n" " Invalid selection - No name entered"
elif [[ -e "${serversDir}/${targetServer}" ]]; then
printf "%s\n" " Invalid selection - A server with that name already exists"
else
break
fi
done
# Get source
local sourceServer
printf "%s\n" "Choose the existing server which will provide the configuration files (but not the world files) for ${targetServer}"
_requestServer sourceServer
# Attempt to make target
printf "%s" "Making directory for ${targetServer}... "
mkdir "${serversDir}/${targetServer}" >/dev/null 2>&1
if [[ ${?} == 0 ]]; then
printf "%s\n" "Done!"
else
printf "%s\n" "Failed with mkdir error ${?}. Aborting server creation"
exit 1
fi
# Attempt to copy source files
for file in "${templateFiles[@]}"; do
printf "%s" "Copying ${file} from ${sourceServer}... "
cp "${serversDir}/${sourceServer}/${file}" "${serversDir}/${targetServer}" >/dev/null 2>&1
if [[ ${?} == 0 ]]; then
printf "%s\n" "Done!"
else
printf "%s\n" "Failed with cp error ${?}. File may not exist"
fi
done
# Bring in world data
while true; do
# Dir prompt
local worldDir=""
local worldDirDefault="${serversDir}/${sourceServer}/world"
printf "%s\n" "Select a world directory containing level data to import"
printf "%s\n" " (0) Skip this step"
while true; do
read -e -p "[${worldDirDefault}]: " usrOpt
case ${usrOpt} in
0)
worldDir=""
break # end dir prompt
;;
"")
worldDir=${worldDirDefault}
break # end dir prompt
;;
*)
worldDir=${usrOpt} # Don't quote or you might kill a ~
break # end dir prompt
;;
esac
done
if [[ "${worldDir}" == "" ]]; then # User selected to skip this step
break # End bring in world data
fi
printf "%s\n" "Should player data be imported too?"
local playerImport=""
local playerImportDefault="n"
while true; do
read -e -p "[${playerImportDefault}]: " usrOpt
case ${usrOpt} in
y|Y)
playerImport=true
break
;;
n|N|"")
playerImport=false
break
;;
*)
printf "%s\n" " Invalid selection"
;;
esac
done
# Attempt the copy
printf "%s" "Copying level data from ${worldDir}... "
cp -r "${worldDir}" "${serversDir}/${targetServer}" >/dev/null 2>&1
if [[ ${?} == 0 ]]; then
printf "%s\n" "Done!"
printf "%s" "Cleansing imported player data... "
rm -rf "${serversDir}/${targetServer}/$(basename ${worldDir})"/{playerdata,stats,data/scoreboard.dat} >/dev/null 2>&1
if [[ ${?} == 0 ]]; then
printf "%s\n" "Done!"
else
printf "%s\n" "Failed with rm error ${?}. Player data may have not existed"
fi
break # End bring in world data
else
printf "%s\n" "Failed with cp error ${?}. Directory may have not existed"
rm -r "${serversDir}/${targetServer}/$(basename ${worldDir})" # Clear partial progress
continue # Retry bring in world data
fi
# Delete some files
done
# Prompt for whether to start server or let script execution finish
printf "%s\n" "Launch this server now?"
while true; do
read -p "[y]: " usrOpt
case ${usrOpt} in
y|Y|"")
_launch "${targetServer}"; break
;;
n|N)
break
;;
*)
printf "%s\n" " Invalid selection"
;;
esac
done
}
_changeMotd() # serverBasename
{
# Get location of the script itself
local mcserverDir="$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)"
# If we don't have access to the Python script, don't try and use it
if [[ ! -e "${mcserverDir}/mcserver-motd" ]]; then
printf "%s\n" "mcserver warning: mcserver-motd not found. Could not retrieve or change MotD"
return 1
fi
local infile="${serversDir}/${serverBasename}/server.properties"
# If the server.properties file doesn't exist, we can't change it
if [[ ! -e ${infile} ]]; then
printf "%s\n" "mcserver warning: ${infile} does not exist. It may have not been created yet"
return 1
fi
local motd="$(python "${mcserverDir}/mcserver-motd" ${infile} -g)"
printf "%s\n" "Set message of the day"
while true; do
read -p "[${motd}]: " usrOpt
case "${usrOpt}" in
"")
break
;;
*)
python "${mcserverDir}/mcserver-motd" "${infile}" -s "${usrOpt}"
break
;;
esac
done
}
_backUp() # serverBasename
{
local serverBasename=${1}
if [[ ${serverBasename} == "" ]]; then
_requestServer serverBasename
fi
local serverDir="${serversDir}/${serverBasename}"
# Get current date in the local timezone
local date="$(date "+%Y-%m-%d")"
# Personal preference: I consider it to be the previous day if it's still not sunrise (06:00)
if [[ ${itsNotTomorrowUntilIWakeUp} == true && $(date "+%H") -lt 6 ]]; then
# Get the date 6 hours ago
date="$(date --date="6 hours ago" "+%Y-%m-%d")"
fi
local bkDir="${backupsDir}/${date}"
# Create or use backup directory, or abort on error
printf "%s" "Making backup directory for ${date}... "
mkdir "${bkDir}" >/dev/null 2>&1
if [[ ${?} == 0 ]]; then
printf "%s\n" "Done!"
elif [[ ${?} == 1 ]]; then
printf "%s\n" "Found existing directory; using it"
else
printf "%s\n" "Failed with mkdir error ${?}. Aborting backup"
exit 1
fi
# Check for existing backups and either delete them or prepare to skip the copying step
local doCopy=true
if [[ -e "${bkDir}/${serverBasename}" ]]; then
printf "%s\n" "A backup of ${serverBasename} for ${date} already exists. Delete and replace it?"
while true; do
read -p "[y]: " usrOpt
case ${usrOpt} in
y|Y|"")
rm -rf "${bkDir}/${serverBasename}" >/dev/null 2>&1
break
;;
n|N)
doCopy=false
break
;;
*)
printf "%s\n" " Invalid selection"
;;
esac
done
fi
# Copy the server data, or abort on error
if [[ ${doCopy} == true ]]; then
printf "%s" "Copying server files for ${serverBasename}... "
cp -r "${serverDir}" "${bkDir}" >/dev/null 2>&1
if [[ ${?} == 0 ]]; then
printf "%s\n" "Done!"
else
printf "%s\n" "Failed with cp error ${?}. Aborting backup"
exit 1
fi
fi
# If necessary, recursively call the function to back up another server
printf "%s\n" "Back up another server for this same date?"
while true; do
read -p "[n]: " usrOpt
case ${usrOpt} in
n|N|"")
break
;;
y|Y)
local newServerBasename=${serverBasename}
while [[ ${newServerBasename} == ${serverBasename} ]]; do
printf "%s\n" "Choose a server that isn't this one"
_requestServer newServerBasename
done
_backUp "${newServerBasename}"
break
;;
*)
printf "%s\n" " Invalid selection"
;;
esac
done
}
# program
if [[ ${reminder} != "" ]]; then
printf "%s\n" "(Reminder: ${reminder})"
fi
printf "%s\n" "Select mode"
printf "%s\n" " (0) Launch a new or existing server"
printf "%s\n" " (1) Make new server from existing server"
printf "%s\n" " (2) Back up existing server"
while true; do
read -p "[0]: " usrOpt
case ${usrOpt} in
0|launch|l|"")
_launch; break
;;
1|new|n)
_new; break
;;
2|backup|b)
_backUp; break
;;
*)
printf "%s\n" " Invalid selection"
;;
esac
done
# end program