Last active
September 17, 2015 19:04
-
-
Save dries007/47c87ee7ad332398e017 to your computer and use it in GitHub Desktop.
ARK Survival Evolved Dedigated server run script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# | |
# ARK SURVIVAL EVOLVED Dedigated server run script | |
# | |
# Assumed to be installed: | |
# - tmux, | |
# - steamcmd (in users home), | |
# - rcon (in user home, see second file on gist) | |
# | |
# MAKE SURE YOU ALWAYS RUN THIS AS THE SAME (NOT ROOT) USER! | |
# USE crontab -u <usename> -e TO MAKE SURE YOUR CRONJOB IS EXECUTED AS THAT USER TOO! | |
# | |
# Supposed to be run as a cronjob at regular (I use 5 min) intervals. | |
# Uses Tmux to assure you can take over control of the server at any point. | |
# To do so, use 'tmux attach -t Ark' be default (from the user running the cronjob!) | |
# | |
# Written by Dries007 (sept 2015), find source & updates at https://gist.github.com/dries007 | |
# Under MIT License (https://opensource.org/licenses/MIT) | |
# | |
TMUX_SESSION_NAME=Ark | |
STEAM_CMD_DIR=~ | |
SERVERDIR=~/ark | |
APPCACHE_DIR=$STEAM_CMD_DIR/Steam/appcache | |
IN_PROGRESS_MARKER=$SERVERDIR/updateinprogress | |
FILE_INSTALLED_VERSION=$SERVERDIR/installedversion.txt | |
FILE_VERSION_LOG=$SERVERDIR/versions.log | |
APP_ID="376030" | |
RCON_PASSWORD=PleaseReplaceWithRealPassword | |
RCON_IP=127.0.0.1 | |
RCON_PORT=32330 | |
RCON_FILE=~/rcon | |
RCON_CMD=$RCON_FILE' -P'$RCON_PASSWORD' -a'$RCON_IP' -p'$RCON_PORT | |
STEAM_CMD=$STEAM_CMD_DIR'/steamcmd.sh +login anonymous' | |
CMD_INFO=$STEAM_CMD' +app_info_update 1 +app_info_print '$APP_ID' +quit' | |
CMD_INSTALL=$STEAM_CMD' +force_install_dir '$SERVERDIR' +app_update '$APP_ID' +quit' | |
CMD_START_SERVER=$SERVERDIR"/ShooterGame/Binaries/Linux/ShooterGameServer \"TheIsland?RCONEnabled=True?RCONPort="$RCON_PORT"?listen\" -server -log" | |
function isOutOfDate() | |
{ | |
rm -fr $APPCACHE_DIR | |
INSTALLED=`cat $FILE_INSTALLED_VERSION` | |
LATEST=`$CMD_INFO | grep -EA 1000 '"branches"' | tr -s '[:blank:]\n' ' ' | sed -En 's/^ "branches" \{ "public" \{ "buildid" "([0-9]+)".*/\1/p'` | |
return $(( $LATEST > $INSTALLED )) | |
} | |
if [ -f $IN_PROGRESS_MARKER ] ; then | |
echo 'Already updating.' | |
exit 0 | |
fi | |
touch $IN_PROGRESS_MARKER | |
if [ ! -f $FILE_INSTALLED_VERSION ] ; then # No installed version file, assume worst case senario, set to 0 | |
echo '0' > $FILE_INSTALLED_VERSION | |
fi | |
# Check to see if the server is running | |
tmux has-session -t $TMUX_SESSION_NAME 2>/dev/null | |
if (( $? == 0 )) ; then # Server is running | |
echo 'Server is running' | |
if isOutOfDate; then | |
echo 'Server is out of date.' | |
$RCON_CMD' broadcast New update available, server is restarting in 5 minutes!' | |
sleep 4m | |
$RCON_CMD' broadcast New update available, server is restarting!' | |
$RCON_CMD' saveworld' | |
$RCON_CMD' broadcast Any changes beond this point MAY BE LOST.' | |
sleep 1m | |
$RCON_CMD' doexit' | |
if (( $? != 0 )) ; then | |
echo 'Using ^C!' | |
tmux send-key -t $TMUX_SESSION_NAME C-c | |
fi | |
sleep 25 | |
echo `date` ' ' $INSTALLED ' -> ' $LATEST >> $FILE_VERSION_LOG | |
$CMD_INSTALL | |
$CMD_INFO | grep -EA 1000 '"branches"' | tr -s '[:blank:]\n' ' ' | sed -En 's/^ "branches" \{ "public" \{ "buildid" "([0-9]+)".*/\1/p' > $FILE_INSTALLED_VERSION | |
tmux new-session -d -s Ark $CMD_START_SERVER | |
else | |
echo 'Server is running & up to date.' | |
fi | |
else # Server is not running | |
echo 'Server is NOT running' | |
if isOutOfDate; then | |
echo 'Server is out of date.' | |
echo `date` ' ' $INSTALLED ' -> ' $LATEST >> $FILE_VERSION_LOG | |
$CMD_INSTALL | |
$CMD_INFO | grep -EA 1000 '"branches"' | tr -s '[:blank:]\n' ' ' | sed -En 's/^ "branches" \{ "public" \{ "buildid" "([0-9]+)".*/\1/p' > $FILE_INSTALLED_VERSION | |
fi | |
tmux new-session -d -s Ark $CMD_START_SERVER | |
fi | |
rm $IN_PROGRESS_MARKER |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
# This is a simple linux command line utility to execute rcon commands | |
# once downloaded on your linux system, compile it with: | |
# | |
# gcc -o rcon rcon.c | |
# | |
# written by [ASY]Zyrain | |
# | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <sys/socket.h> | |
#include <sys/types.h> | |
#include <netinet/in.h> | |
#include <arpa/inet.h> | |
#include <errno.h> | |
#include <string.h> | |
#define DEBUG 0 | |
#define SERVERDATA_EXECCOMMAND 2 | |
#define SERVERDATA_AUTH 3 | |
#define SERVERDATA_RESPONSE_VALUE 0 | |
#define SERVERDATA_AUTH_RESPONSE 2 | |
int send_rcon(int sock, int id, int command, char *string1, char *string2) { | |
int size, ret; | |
size = 10+strlen(string1)+strlen(string2); | |
ret = send(sock,&size,sizeof(int),0); | |
if(ret == -1) { | |
perror("send() failed:"); | |
return -1; | |
} | |
ret = send(sock,&id,sizeof(int),0); | |
if(ret == -1) { | |
perror("send() failed:"); | |
return -1; | |
} | |
ret = send(sock,&command,sizeof(int),0); | |
if(ret == -1) { | |
perror("send() failed:"); | |
return -1; | |
} | |
ret = send(sock,string1,strlen(string1)+1,0); | |
if(ret == -1) { | |
perror("send() failed:"); | |
return -1; | |
} | |
ret = send(sock,string2,strlen(string2)+1,0); | |
if(ret == -1) { | |
perror("send() failed:"); | |
return -1; | |
} | |
if(DEBUG) printf("Sent %d bytes\n",size+4); | |
return 0; | |
} | |
int recv_rcon(int sock, int timeout, int *id, int *command, char *string1, | |
char *string2) { | |
struct timeval tv; | |
fd_set readfds; | |
int size; | |
char *ptr; | |
int ret; | |
char buf[8192]; | |
size=0xDEADBEEF; | |
*id=0xDEADBEEF; | |
*command=0xDEADBEEF; | |
string1[0]=0; | |
string2[0]=0; | |
tv.tv_sec = timeout; | |
tv.tv_usec = 0; | |
FD_ZERO(&readfds); | |
FD_SET(sock, &readfds); | |
/* don't care about writefds and exceptfds: */ | |
select(sock+1, &readfds, NULL, NULL, &tv); | |
if (!FD_ISSET(sock, &readfds)) { | |
if(DEBUG) { | |
printf("recv timeout\n"); | |
} | |
return -1; // timeout | |
} | |
if(DEBUG) printf("Got a response\n"); | |
ret = recv(sock, &size, sizeof(int), 0); | |
if(ret == -1) { | |
perror("recv() failed:"); | |
return -1; | |
} | |
if((size<10) || (size>8192)) { | |
printf("Illegal size %d\n",size); | |
exit(-1); | |
} | |
ret = recv(sock, id, sizeof(int),0); | |
if(ret == -1) { | |
perror("recv() failed:"); | |
return -1; | |
} | |
size-=ret; | |
ret = recv(sock, command, sizeof(int),0); | |
if(ret == -1) { | |
perror("recv() failed:"); | |
return -1; | |
} | |
size-=ret; | |
ptr = buf; | |
while(size) { | |
ret = recv(sock, ptr, size, 0); | |
if(ret == -1) { | |
perror("recv() failed:"); | |
return -1; | |
} | |
size -= ret; | |
ptr += ret; | |
} | |
buf[8190] = 0; | |
buf[8191] = 0; | |
strncpy(string1, buf, 4095); | |
string1[4095] = 0; | |
strncpy(string2, buf+strlen(string1)+1, 4095); | |
return 0; | |
} | |
/* This is set to 1 when we've been authorized */ | |
int auth = 0; | |
char string1[4096]; | |
char string2[4096]; | |
int process_response(int sock) { | |
int ret; | |
int id; | |
int command; | |
ret=recv_rcon(sock, 1, &id, &command, string1, string2); | |
if(DEBUG) printf("Received = %d : id=%d, command=%d, s1=%s, s2=%s\n", | |
ret, id, command, string1, string2); | |
if(ret==-1) { | |
return -1; | |
} | |
switch(command) { | |
case SERVERDATA_AUTH_RESPONSE: | |
switch(id) { | |
case 20: | |
auth = 1; | |
break; | |
case -1: | |
printf("Password Refused\n"); | |
return -1; | |
default: | |
printf("Bad Auth Response ID = %d\n",id); | |
exit(-1); | |
}; | |
break; | |
case SERVERDATA_RESPONSE_VALUE: | |
printf("%s",string1); | |
break; | |
default: | |
printf("Unexpected command: %d",command); | |
break; | |
}; | |
} | |
int main(int argc, char **argv) | |
{ | |
struct sockaddr_in a; | |
int sock; | |
int ret, i; | |
char password[512]=""; | |
short port = 27015; | |
char address[512] = "127.0.0.1"; | |
int arg; | |
auth = 0; | |
if(argc<2) | |
{ | |
printf("Syntax: rcon [-P\"rcon_password\"] [-a127.0.0.1] [-p27015] command\n"); | |
return 0; | |
} | |
for(arg = 1;arg<argc;arg++) { | |
if(argv[arg][0] != '-') | |
break; /* done with args */ | |
switch(argv[arg][1]) { | |
case 'a': | |
strncpy(address, argv[arg]+2, 512); | |
break; | |
case 'p': | |
port = atoi(argv[arg]+2); | |
break; | |
case 'P': | |
strncpy(password, argv[arg]+2, 512); | |
break; | |
default: | |
fprintf(stderr, "Unknown option -%c\n",argv[arg][1]); | |
return 0; | |
} | |
} | |
a.sin_family = AF_INET; | |
a.sin_addr.s_addr = inet_addr(address); | |
a.sin_port = htons(port); | |
sock = socket(AF_INET, SOCK_STREAM,0); // TCP socket | |
ret = 0; | |
ret = connect(sock,(struct sockaddr *)&a,sizeof(a)); | |
if(ret == -1) { | |
perror("connect() failed."); | |
return -1; | |
} else { | |
if(DEBUG) printf("Connected to Server\n"); | |
} | |
if(DEBUG) printf("Sending RCON Password\n"); | |
ret=send_rcon(sock, 20, SERVERDATA_AUTH, password, ""); | |
if(ret == -1) { | |
perror("Sending password"); | |
return -1; | |
}; | |
while(auth==0) { | |
if(process_response(sock)==-1) { | |
printf("Couldn't Authenticate\n"); | |
exit(-1); | |
} | |
} | |
if(DEBUG) printf("Password Accepted\n"); | |
/* Now we're authorized, send command */ | |
/* built command */ | |
ret = 0; | |
while(arg < argc) { | |
if(strlen(argv[arg]) + ret < 4096) { | |
strcpy(string1+ret, argv[arg]); | |
ret += strlen(argv[arg]); | |
string1[ret] = ' '; | |
ret++; | |
arg++; | |
} else { | |
fprintf(stderr, "cmd too long to send\n"); | |
return -1; | |
} | |
} | |
// string1[ret] = '\n'; | |
//ret++; | |
ret--; | |
string1[ret]=0; | |
if(DEBUG) printf("Sending Command: \"%s\"\n", string1); | |
ret=send_rcon(sock, 20, SERVERDATA_EXECCOMMAND, string1, ""); | |
if(ret == -1) { | |
perror("cmd send"); | |
return -1; | |
} | |
// process responses until a timeout | |
while(process_response(sock) != -1); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment