GameServerManagers / LinuxGSM

The command-line tool for quick, simple deployment and management of Linux dedicated game servers.
https://linuxgsm.com
MIT License
4.32k stars 821 forks source link

Creating New Scripts (Which script should I base it on?) #206

Closed JmactheAttack closed 9 years ago

JmactheAttack commented 10 years ago

I am looking/attempting/failing at porting your scripts over to run a few different game servers, specifically JK3, CoD4, and CoD:WAW along with possibly a few others (and of course hopefully getting them pulled into this repo. My first attempt at it was porting the Mumble server script over to run a CoD4 server because it seemed to be the most generic script mainly because it just manages a single executable, an .ini file and some variables, without any Steam or Unreal additions. I got the CoD4 script to start the server and it runs great, but when I stop it, it seems to stop all my other scripts (a 24/7 CSGO and Mumble server). I also noticed that the Mumble server script does not seem to run perfectly either, like sometimes when I stop it, it doesn't completely kill murmur.x86 process(s). The script stops and kills the tmux session (conf, but murmur continues to run, etc, etc.

My question: is the Mumble server script out of date and incompatible with the other server scripts because of recent changes to the others? If so, should I base my new scripts off of more recent ones like the CS:GO script and just hack-off/disable the unused parts (i.e. the install bits, etc)? Also, is it okay to run everything on one user (non-root)?

BTW, I'm running everything on Ubuntu 13.10. Everything else seems to run flawlessly.

-Jmac

Scarsz commented 10 years ago

I wouldn't have a clue if the mumble script is very much used, but I would guess not. It's worth a shot to try and back up a script with another like the ts3server script though.

dgibbs64 commented 10 years ago

Its great that you want to do this. All my new scripts normally go off the Counter Strike:Source script however most scripts are steam based. It is relatively easy to not use the steam code....Simply remove/bypass it :). You can also use UT2K4 and UT99 for examples of this as they don't use steam at all and download the server files instead. Apart from that the base is pretty similar apart from specific vars for CoD:4 etc. You will need to change and remove the variables at the start of the script. as these will differ from steam based servers. This is why most the servers are steam based as its very easy for me to port them to a new steam based server.

I don't recommend using the mumble server script. As you can probably see it can be problematic and isnt as well maintained as the others. However if you want to have a go at fixing the bugs you are welcome to.

I hope you manage to get these working it would be great to get a few more servers added. Since I have limited time currently its great that other people are maintaining and adding more scripts :D

JmactheAttack commented 10 years ago

Thanks for the replies. I'm glad to see I was at least running down the correct path. Here's a rough example of where I was at with the script based on the mumble script:

#!/bin/bash
# CoD4
# Server Management Script
# Author: Daniel Gibbs
# Website: http://danielgibbs.co.uk
# Version: 250814

### Variables ####

# Notification Email
# (on|off)
emailnotification="off"
email="email@example.com"

# Start Variables
# https://developer.valvesoftware.com/wiki/Counter-Strike:_Global_Offensive_Dedicated_Servers#Starting_the_Server
maxplayers="16"
punkbuster="1"
port="28960"
ip="0.0.0.0"

# Server Details
servername="CoD4"
servicename="cod4-server"

# Directorys
rootdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
selfname="$0"
lockselfname=$(echo ".${servicename}.lock")
filesdir="${rootdir}/serverfiles/cod4"
cfg="server.cfg"
executable="./cod4_lnxded +set net_ip ${ip} +set net_port ${port} +set sv_maxclients ${maxplayers} +set sv_punkbuster ${punkbuster} +exec ${cfg} +map_rotate"
backupdir="backups"

# Logging
logdays="7"
logdir="${rootdir}/log"
scriptlogdir="${rootdir}/log/script"
consolelogdir="${rootdir}/log/console"

scriptlog="${scriptlogdir}/${servicename}-script.log"
consolelog="${consolelogdir}/${servicename}-console.log"
emaillog="${scriptlogdir}/${servicename}-email.log"

scriptlogdate="${scriptlogdir}/${servicename}-script-$(date '+%d-%m-%Y-%H-%M-%S').log"
consolelogdate="${consolelogdir}/${servicename}-console-$(date '+%d-%m-%Y-%H-%M-%S').log"

##### Script #####
# Do not edit
# unless you know
# what you are doing

fn_scriptlog(){
    echo -e "$(date '+%b %d %H:%M:%S') ${servicename}: '$1'" >> ${scriptlog}
}

# [ FAIL ]
fn_printfail(){
    echo -en "\r\033[K[\e[0;31m FAIL \e[0;39m] $@"
}

fn_printfailnl(){
    echo -e "\r\033[K[\e[0;31m FAIL \e[0;39m] $@"
}

fn_printok(){
    echo -en "\r\033[K[\e[0;32m  OK  \e[0;39m] $@"
}

# [  OK  ]
fn_printoknl(){
    echo -e "\r\033[K[\e[0;32m  OK  \e[0;39m] $@"
}

fn_printinfo(){
    echo -en "\r\033[K[\e[0;36m INFO \e[0;39m] $@"
}

fn_printinfonl(){
    echo -e "\r\033[K[\e[0;36m INFO \e[0;39m] $@"
}

# [ INFO ]
fn_printokinfonl(){
    echo -e "\r\033[K[\e[0;36m INFO \e[0;39m] $@"
}

fn_printwarn(){
    echo -en "\r\033[K[\e[1;33m WARN \e[0;39m] $@"
}

fn_printwarnnl(){
    echo -e "\r\033[K[\e[1;33m WARN \e[0;39m] $@"
}

# [ .... ]
fn_printdots(){
    echo -en "\r\033[K[ .... ] $@"
}

fn_rootcheck(){
if [ `whoami` = "root" ]; then
    fn_printfailnl "Script will not run as root!"
    exit
fi
}

fn_syscheck(){
if [ ! -e "${filesdir}" ]; then
    fn_printfailnl "Cannot access ${systemdir}: No such directory"
    exit
fi
}

fn_inicheck(){
if [ ! -e ${filesdir}/${ini} ]; then
    fn_printwarnnl "${servicename}: ${filesdir}/${ini} is missing"
    fn_scriptlog "${servername} ${filesdir}/${ini} is missing" >> ${scriptlog}
fi
}

fn_backupserver(){
fn_rootcheck
fn_syscheck
backupname="${servicename}-$(date '+%Y-%m-%d-%H%M%S')"
echo ""
echo "${gamename} Backup"
echo "============================"
echo ""
echo "The following backup will be created."
echo ""
echo "${backupdir}/${backupname}.tar.gz"
echo ""
while true; do
    read -p "Continue? [y/N]" yn
    case $yn in
    [Yy]* ) break;;
    [Nn]* ) echo Exiting; return 1;;
    * ) echo "Please answer yes or no.";;
esac
done
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l)
if [ ${tmuxwc} -eq 1 ]; then
    echo -e "\e[0;31mWARNING!\e[0;39m ${servicename} is currently running"
    while true; do
        read -p "Would you like to stop ${servicename} while running the backup? [y/N]" yn
        case $yn in
        [Yy]* ) fn_stopserver; break;;
        [Nn]* ) break;;
        * ) echo "Please answer yes or no.";;
    esac
    done
fi
fn_printdots "Starting backup ${servicename}: ${servername}"
sleep 1
fn_printok "Starting backup ${servicename}: ${servername}"
sleep 1
fn_scriptlog "Backup started"
echo -en "\n"
cd "${rootdir}"
mkdir -pv "${backupdir}" > /dev/null 2>&1
tar -cvzf "${backupdir}/${backupname}.tar.gz" --exclude "${backupdir}" *
echo -en "\r\033[K${servicename} Backup complete"
fn_scriptlog "Backup complete"
}

fn_distro(){
arch=$(uname -m)
kernel=$(uname -r)
if [ -f /etc/lsb-release ]; then
    os=$(lsb_release -s -d)
elif [ -f /etc/debian_version ]; then
    os="Debian $(cat /etc/debian_version)"
elif [ -f /etc/redhat-release ]; then
    os=$(cat /etc/redhat-release)
else
    os="$(uname -s) $(uname -r)"
fi
}

fn_uptime(){
uptime=$(</proc/uptime)
uptime=${uptime%%.*}
minutes=$(( uptime/60%60 ))
hours=$(( uptime/60/60%24 ))
days=$(( uptime/60/60/24 ))
}

fn_load(){
load=$(uptime|awk -F 'load average' '{ print $2 }')
}

fn_emailnotification(){
fn_distro
fn_uptime
fn_load
{
    echo -e "========================================\n${servicename} details\n========================================\n"
    echo -e "Service: ${servicename}"
    echo -e "Server: ${servername}"
    echo -e "Failure reason: ${failurereason}"
    echo -e "Action Taken: ${actiontaken}\n"
    echo -e "========================================\nServer details\n========================================\n"
    echo -e "Date: $(date)"
    echo -e "Distro: ${os}"
    echo -e "Arch: ${arch}"
    echo -e "Kernel: ${kernel}"
    echo -e "Hostname: $HOSTNAME"
    echo -e "Uptime: ${days}d, ${hours}h, ${minutes}m"
    echo -e "Avg Load${load}\n"
    echo -e "========================================\nLogs\n========================================\n"
    echo -e "Script log\n===================\n"
}|tee "${scriptlogdir}/${servicename}-email.log" > /dev/null 2>&1
tail -25 "${scriptlog}" >> "${emaillog}"
if [ ! -z "${consolelog}" ]; then
    echo -e "\n\nConsole log\n====================\n" >> "${emaillog}"
    tail -25 "${consolelog}" >> "${emaillog}"
fi
if [ ! -z "${gamelogdir}" ]; then
    echo -e "\n\nServer log\n====================\n" >> "${emaillog}"
    tail "${gamelogdir}"/*|grep -v "==>"|sed '/^$/d'|tail -25 >> "${emaillog}"
fi
mail -s "${subject}" ${email} < "${emaillog}"
fn_printinfo "Sent email notification to ${email}"
sleep 1
echo -en "\n"
fn_scriptlog "Sent email notification to ${email}"
}

fn_emailtest(){
fn_rootcheck
fn_syscheck
fn_scriptlog "Emailing test notification"
if [ "${emailnotification}" = "on" ]; then
    subject="${servicename} Email Test Notification - Testing ${servername}"
    failurereason="Testing ${servicename} email notification"
    actiontaken="Sent test email...hello is this thing on?"
    fn_emailnotification
else
    fn_printfailnl "Email notification not enabled"
    fn_scriptlog "Email notification not enabled"
fi
sleep 1
echo -en "\n"
}

fn_monitorserver(){
fn_rootcheck
fn_syscheck
if [ ! -f ${lockselfname} ]; then 
    fn_printinfo "Monitoring ${servicename}: No lock file found: Monitor disabled"
    sleep 1
    echo -en "\n"
    exit
fi
fn_printdots "Monitoring ${servicename}: ${servername}"
sleep 1
fn_scriptlog "Monitoring ${servername}"
fn_printdots "Monitoring ${servicename}: Checking session: CHECKING"
sleep 1 
fn_scriptlog "Checking session: CHECKING"
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l)
if [ ${tmuxwc} -eq 1 ]; then
    fn_printok "Monitoring ${servicename}: Checking session: OK"
    sleep 1     
    echo -en "\n"
    fn_scriptlog "Checking session: OK"
    exit
else
    fn_printfail "Monitoring ${servicename}: Checking session: FAIL"
    fn_scriptlog "Checking session: FAIL"
    sleep 1
    echo -en "\n"
    if [ "${emailnotification}" = "on" ]; then
        subject="${servicename} Monitor - Starting ${servername}"
        failurereason="${servicename} process not running"
        actiontaken="${servicename} has been restarted"
        fn_emailnotification
    fi
    fn_scriptlog "Monitor is starting ${servername}"
    fn_startserver
fi
}

fn_logmanager(){
if [ ! -e "${consolelog}" ]; then
    touch "${consolelog}"
fi
# log manager will active if finds logs older than ${logdays}
if [ `find "${scriptlogdir}"/* -mtime +${logdays}|wc -l` -ne "0" ]; then
    fn_printdots "Starting log cleaner"
    sleep 1 
    fn_printok "Starting log cleaner"
    sleep 1 
    fn_scriptlog "Starting log cleaner"
    sleep 1
    echo -en "\n"
    fn_printinfo "Removing logs older than ${logdays} days"
    sleep 1
    echo -en "\n"
    fn_scriptlog "Removing logs older than ${logdays} days"
    sleep 1
    find "${scriptlogdir}"/* -mtime +${logdays}|tee >> "${scriptlog}"
    find "${consolelogdir}"/* -mtime +${logdays}|tee >> "${scriptlog}"
    scriptcount=$(find "${scriptlogdir}"/* -mtime +${logdays}|wc -l)
    consolecount=$(find "${consolelogdir}"/* -mtime +${logdays}|wc -l)
    count=$((${scriptcount} + ${consolecount}))
    find "${scriptlogdir}"/* -mtime +${logdays} -exec rm {} \;
    find "${consolelogdir}"/* -mtime +${logdays} -exec rm {} \;
    fn_printok "Log cleaner removed ${count} log files"
    sleep 1
    echo -en "\n"
    fn_scriptlog "Log cleaner removed ${count} log files"
fi
}

fn_restartserver(){
fn_scriptlog "Restarting ${servername}"
fn_stopserver
fn_startserver
}

fn_stopserver(){
fn_rootcheck
fn_syscheck
pid=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -E "^${servicename}:"|wc -l)
pidwc=$(screen -ls |grep -E "^${servicename}:" |awk -F . '{print $1}'|awk '{print $1}'|wc -l)

fn_printdots "Stopping ${servicename}: ${servername}"
sleep 1
fn_scriptlog "Stopping ${servername}"
if [ "${pid}" == "0" ]; then
    fn_printfail "Stopping ${servicename}: ${servername} is already stopped"
    fn_scriptlog "${servername} is already stopped"
else
    #Kill CoD4 process that spawns separate to tmux process
    for s in `tmux list-sessions -F '#{session_name}'` ; do
        for pid in `tmux list-panes -s -F '#{pane_pid}' -t "$s"` ; do
        kill $pid
    done
    tmux kill-session -t ${servicename}
    fn_printok "Stopping ${servicename}: ${servername}"
    fn_scriptlog "Stopped ${servername}"
done    
fi
# Remove lock file
rm -f ${lockselfname}
sleep 1
echo -en "\n"
}

fn_startserver(){
if [ ! -d ${logdir} ];then
    mkdir ${logdir}
    mkdir ${scriptlogdir}
    mkdir ${consolelogdir}
    echo -e "[\e[0;36m INFO \e[0;39m] ${servicename}: ${servername} Creating log directory ${logdir}"
    fn_scriptlog " Creating log directory ${logdir}" >> ${scriptlog}
fi
fn_rootcheck
fn_syscheck
fn_logmanager
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l)
if [ ${tmuxwc} -eq 0 ]; then
    mv "${scriptlog}" "${scriptlogdate}"
    mv "${consolelog}" "${consolelogdate}"
fi
fn_printdots "Starting ${servicename}: ${servername}"
sleep 1
fn_scriptlog "Starting ${servername}"
if [ ${tmuxwc} -eq 1 ]; then
    fn_printinfo "Starting ${servicename}: ${servername} is already running"
    sleep 1
    echo -en "\n"
    fn_scriptlog "${servername} is already running"
    exit
fi
# Create lock file
date > ${lockselfname}
cd ${filesdir}
tmux new-session -d -s ${servicename} "${executable}"
tmux pipe-pane -o -t ${servicename} "exec cat >> '${consolelog}'"
sleep 1
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -E "^${servicename}:"|wc -l)
if [ ${tmuxwc} -eq 0 ]; then
    fn_printfail "Starting ${servicename}: Failed to start ${servername}"
    fn_scriptlog "failed to start ${servername}"
else
    fn_printok "Starting ${servicename}: ${servername}"
    fn_scriptlog "Started ${servername}"
fi
sleep 1
echo -en "\n"
}

fn_debugserver(){
fn_rootcheck
fn_syscheck
echo ""
echo "${gamename} Debug"
echo "============================"
echo ""
echo -e "Use for identifying server issues only!"
echo -e "Press CTRL+c to drop out of debug mode"
echo -e "\e[0;31mWARNING!\e[0;39m If ${servicename} is already running it will be stopped"
echo ""
echo "Start parameters:"
echo ${executable}
echo ""
while true; do
    read -p "Continue? [y/N]" yn
    case $yn in
    [Yy]* ) break;;
    [Nn]* ) echo Exiting; return 1;;
    * ) echo "Please answer yes or no.";;
esac
done
fn_stopserver
fn_printdots "Starting debug mode ${servicename}: ${servername}"
sleep 1
fn_printok "Starting debug mode ${servicename}: ${servername}"
sleep 1
fn_scriptlog "Started debug mode ${servername}"
echo -en "\n"
cd ${filesdir}
./cod4_lnxded +set net_ip ${ip} +set net_port ${port} +set sv_maxclients ${maxplayers} +set sv_punkbuster ${punkbuster} +exec ${cfg} +map_rotate
}

fn_console(){
fn_rootcheck
fn_syscheck
echo ""
echo "${gamename} Console"
echo "============================"
echo ""
echo "Press \"CTRL+b d\" to exit console"
echo -e "\e[0;31mWARNING!\e[0;39m Do NOT press CTRL+c to exit"
echo ""
while true; do
    read -p "Continue? [y/N]" yn
    case $yn in
    [Yy]* ) break;;
    [Nn]* ) echo Exiting; return 1;;
    * ) echo "Please answer yes or no.";;
esac
done
fn_printdots "Starting ${servicename} console"
sleep 1
tmuxwc=$(tmux list-sessions 2>&1|awk '{print $1}'|grep -v failed|grep -E "^${servicename}:"|wc -l)
if [ ${tmuxwc} -eq 1 ]; then
    fn_printoknl "Starting ${servicename} console"
    sleep 1
    fn_scriptlog "Console accessed"
    tmux attach-session -t ${servicename}
else
    fn_printfailnl "Starting ${servicename} console: ${servername} not running"
    sleep 1
    while true; do
        read -p "Do you want to start the server? [y/N]" yn
        case $yn in
        [Yy]* ) fn_startserver; break;;
        [Nn]* ) break;;
        * ) echo "Please answer yes or no.";;
    esac
    done
fi
}

case "$1" in
    start)
        fn_startserver;;
    stop)
        fn_stopserver;;
    restart)
        fn_restartserver;;
    monitor)
        fn_monitorserver;;
    email-test)
        fn_emailtest;;
    backup)
        fn_backupserver;;
    console)
        fn_console;;
    debug)
        fn_debugserver;;
    *)
        echo "Usage: $0 {start|stop|restart|monitor|debug|backup|email-test}"
        exit 1;;
esac
exit

As it is, I don't think I'll ever be able to create a real way of installing it beyond a README.md because CoD servers require assets that come from your game install and punkbuster no longer actually supports the game which makes installing it all through the script very complicated. Same for JK3, and CoD:World at War. Once I get it a little more settled I'll start committing this. I was also looking at using this to run a Minecraft(bukkit) server with this. This could present some interesting challenges with updating the server and working with plugins.

lock[bot] commented 6 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.