λk.(k blog): Posts tagged 'games'urn:https-www-williamjbowman-com:-tags-games-html2014-06-13T19:21:00ZAn on demand Minecraft Serverurn:https-www-williamjbowman-com:-blog-2014-06-13-an-on-demand-minecraft-server2014-06-13T19:21:00Z2014-06-13T19:21:00ZWilliam J. Bowman
<p>Sometimes I play minecraft. Sometimes I play <em>a lot</em> of minecraft and sometimes I just stop playing for months. Lately when I do play, I’ve bene playing with a slightly modified version of <a href="http://www.technicpack.net/tekkit/">Tekkit</a> and running my own server. I have a VPS that I probably under use, so I decided to run the server there for when I do play with my friends.</p>
<p>My VPS is not very powerful, and running a Minecraft server when I stop playing for months is a huge waste of resources. I sought a way to automatically bring the server up when I wanted to play and shut it down when I wasn’t playing for a while.</p>
<!-- more-->
<h2 id="intro-and-credits">Intro and credits</h2>
<p>Most of this I gleemed by reading <a href="http://www.planetminecraft.com/blog/automatically-stop-a-server-when-nobodys-playing/">this article</a> at planetminecraft.com. It’s quite well written, but I made my own changes to suite my needs and expanded on some things. In particular, I wanted more abstraction, the website seems to mangle the bits of code posted there, and a couple of things were left unexplained.</p>
<p>I also heavily referenced <a href="http://wiki.vg/Server_List_Ping#Server_-.3E_Client">this wiki</a> to understand the minecraft ping protocol to get MOTD even when the server is down, letting users know the server is starting up.</p>
<p>All this code is available on <a href="https://github.com/bluephoenix47/tekkit-on-demand">github</a>.</p>
<p>Disclaimer: This code probably has at least one bug.</p>
<h2 id="assumptions">Assumptions</h2>
<p>A couple of notes before we get started. I run Arch Linux on all my machines, including my server. I use <code>cronie</code> as my crontab implementation. These scripts make use of lots of ‘standard’ tools such as a <code>screen</code>, <code>sed</code>, <code>grep</code>, and <code>tr</code>, and ‘less standard’ ones like <code>netcat</code>, <code>pgrep</code>, and <code>xinetd</code>. You don’t really need to understand them use this, but I won’t explain them here. I will assume you know how to run and install a Minecraft server. These scripts should work with any Minecraft server; I personally use Tekkit.</p>
<p>This article, and the scripts to a lesser extend, expect files to be in particular places. The only hard-coded path in the scripts should be <code>/etc/tekkit-on-demand/config.sh</code>. The article expects the binaries to be installed in <code>/usr/bin/tekkit-{start,idle}</code>, and the launch helper to be installed in <code>/etc/tekkit-on-demand/launch.sh</code></p>
<h2 id="the-server-overview">The server: overview</h2>
<p>The server runs in a <code>screen</code> session. I previously used <code>systemd</code> to manage the server, but there are a few advantages to running it in <code>screen</code>. You can easily, and programatically, send commands to the server, and more easily filter logs, which I find necessary due to the absurd number of info messages. The server is run as an unprivileged user, but requires <code>root</code> to launch it.</p>
<h3 id="configsh">config.sh</h3>
<p>The file <code>config.sh</code> contains all the configuration variables, and the functions with the core commands for starting and stopping the server, and detecting when the server is idle.</p>
<p>The file is configured by simply setting the variables at the top of the file. The variables have sensible defaults seen later in the file. We will refer to some of the variables such as <code>$SERVER_USER</code> in the rest of the guide.</p>
<p>Advanced configuration involved changing the functions <code>start</code>, <code>stop</code>, <code>idle</code>, and <code>debug</code>. The functions shouldn’t need to be changed unless your server is configured quite differently, or you want to avoid <code>screen</code>, <code>xinetd</code>, or some other vital piece explained in the rest of the guide.</p>
<div class="brush: sh">
<pre><code>#!/bin/sh
## Change these configuration variables. They should probably match server.properties
## Leave them blank if you think I'm a good guesser.
SERVER_ROOT=
SERVER_PROPERTIES=
LOCAL_PORT=
LOCAL_IP=
MINECRAFT_JAR=
MINECRAFT_LOG=
SESSION=
WAIT_TIME=
SERVER_USER=
LAUNCH=
START_LOCKFILE=
IDLE_LOCKFILE=
PLAYERS_FILE=
## NB: This default may not be sensible
JAVAOPTS=
JAVAOPTS=${JAVAOPTS:--Xmx2G -Xms1G -server -XX:+UseG1GC -XX:MaxGCPauseMillis=50 \
-XX:ParallelGCThreads=2 -XX:+DisableExplicitGC -XX:+AggressiveOpts -d64}
## TODO: Currenently not used. Need to recompute size and UTF-16BE
## encode the message, which is annoying
MESSAGE=
## Here be defaults
SERVER_ROOT=${SERVER_ROOT:-/srv/tekkit}
SERVER_PROPERTIES=${SERVER_PROPERTIES:-$SERVER_ROOT/server.properties}
LOCAL_PORT=${LOCAL_PORT:-$(sed -n 's/^server-port=\([0-9]*\)$/\1/p' ${SERVER_PROPERTIES})}
LOCAL_IP=${LOCAL_IP:-$(sed -n 's/^server-ip=\([0-9]*\)$/\1/p' ${SERVER_PROPERTIES})}
MINECRAFT_JAR=${MINECRAFT_JAR:-$SERVER_ROOT/Tekkit.jar}
MINECRAFT_LOG=${MINECRAFT_LOG:-$SERVER_ROOT/server.log}
SESSION=${SESSION:-Minecraft}
MESSAGE=${MESSAGE:-Just a moment please}
WAIT_TIME=${WAIT_TIME:-600}
SERVER_USER=${SERVER_USER:-tekkit}
LAUNCH=${LAUNCH:-/etc/tekkit-on-demand/launch.sh}
START_LOCKFILE=${START_LOCKFILE:-/tmp/startingtekkit}
IDLE_LOCKFILE=${IDLE_LOCKFILE:-/tmp/idleingtekkit}
PLAYERS_FILE=${PLAYERS_FILE:-/tmp/tekkitplayers}
...</code></pre></div>
<h2 id="starting-the-server">Starting the server</h2>
<p>Starting the server is tricky. We must ensure any user that tries to connect sees a message alerting them that the server is not up now, but will be shortly. We also need to be sure to start only one instance of the server. Finally, we have to route traffic between the server and the meta-server that is watching to start the server on-demand.</p>
<h3 id="start-on-demand">Start on-demand</h3>
<p>To automatically start the server, we use <code>xinetd</code>, a ‘super-server’ (or as I prefer, ‘meta-server’). The meta-server is a server that manages servers by binding to the server’s port, starting the server when a client attempts to connect, then forwarding all traffic to the server.</p>
<p><code>tekkit</code>:</p>
<div class="brush: xinetd">
<pre><code>service tekkit
{
type = UNLISTED
instances = 20
socket_type = stream
protocol = tcp
wait = no
user = root
group = root
server = /usr/bin/tekkit-start
port = 25565
disable = no
}</code></pre></div>
<p>We install this file in <code>/etc/xinetd.d/tekkit</code>, and have <code>xinetd</code> reread configuration files, for instance, via <code>systemctl reload xinetd</code>. This path is fixed by <code>xinetd</code>. You must change <code>port = ...</code> in this file if you change <code>$SERVER_PORT</code>.</p>
<p>Now when someone tries to connect to your server on port <code>25565</code>, the meta-server will run the file <code>/usr/bin/tekkit-start</code>. Note that since the meta-server is binding port <code>25565</code>, your server must use a different port. I use port <code>25555</code>, but you can configure this with <code>$LOCAL_PORT</code>.</p>
<h3 id="screen-and-the-server-command">Screen and the server command</h3>
<p>A typical Minecraft server is started with a command that looks something like <code>/usr/bin/java $JAVAOPTS -jar $MINECRAFT_JAR nogui</code>. We add to this command a filter to filter out the INFO messages, and to capture the number of players. All output is first piped to a <code>sed</code> script that watches for the response to a <code>list</code> command. The <code>list</code> command is a Minecraft server command that lists the number of players online. The number of players is captured to the file specified by <code>$PLAYERS_FILE</code>. The remaining output is filtered through <code>grep</code> to discard INFO messages. This is done in <code>config.sh</code> in the <code>start</code> function:</p>
<div class="brush: sh">
<pre><code>start() {
/usr/bin/java $JAVAOPTS -jar $MINECRAFT_JAR nogui 2>&1 \
| sed -n -e 's/^.*There are \([0-9]*\)\/[0-9] players.*$/\1/' -e 't M' -e 'b' -e ": M w $PLAYERS_FILE" -e 'd' \
| grep -v -e "INFO" -e "Can't keep up"
}</code></pre></div>
<p>We want to run the server in <code>screen</code> to allow issuing commands, such as <code>list</code>, to the server. Unfortunately, <code>screen</code> doesn’t appear to take a function as an argument. We use <code>launch.sh</code> as a wrapper, and have <code>screen</code> run <code>launch.sh</code> as an unprivileged user called <code>$SERVER_USER</code>.</p>
<p><code>launch.sh</code>: <code>sh
#!/bin/sh
source /etc/tekkit-on-demand/config.sh
cd $SERVER_ROOT
start</code></p>
<p>The file <code>/usr/bin/tekkit-start</code> is actually responsible for starting the server, and the <code>screen</code> command appears in there. However, much more happens before starting the server…</p>
<h3 id="server-starting-message">Server starting message</h3>
<p>When a player first connects, we do not want them scared away by a “Can’t reach server” message. We implement the minecraft server list ping response, details <a href="http://wiki.vg/Server_List_Ping#Server_-.3E_Client">here</a>, to give them a less scary message. This protocol is implemented in the function <code>sign</code> in the <code>tekkit-start</code> file.</p>
<p><code>tekkit-start</code>:</p>
<div class="brush: sh">
<pre><code>#!/bin/sh
source /etc/tekkit-on-demand/config.sh
sign(){
# Kick protocol start
echo -en "\xFF"
# Length in characters: (including protocol, MOTD, current, max players)
# 22
# |
echo -en "\x00\x22"
# UTF-16BE String: Protocol header
echo -en "\x00\xA7\x00\x31\x00\x00"
# Protocol version:
# 4 7
# | |
echo -en "\x00\x34\x00\x37\x00\x00"
# Minecraft version:
# 1 . 6 . 4
# | | |
echo -en "\x00\x31\x00\x2E\x00\x36\x00\x2E\x00\x34\x00\x00"
# MOTD: "Up in just a sec.."
echo -en "\x00\x55\x00\x70\x00\x20\x00\x69\x00\x6E\x00\x20\x00\x6A\x00\x75\x00\x73\x00\x74\x00\x20\x00\x61\x00\x20\x00\x73\x00\x65\x00\x63\x00\x2E\x00\x2E\x00\x00"
# Current Players:
# 0
# |
echo -en "\x00\x30\x00\x00"
# Max Players:
# 0
# |
echo -en "\x00\x30"
}</code></pre></div>
<p>This implementation is kind of bad, with lengths computed and strings encoded by hand. Maybe I’ll fix it later. The comment above each string explain what the string means. The first two <code>echo</code>s send binary strings representing the protocol start packet and the length of the message. The remaining <code>echo</code>s send UTF16-BE encoded information, such as the minecraft version, the MOTD (the message displayed under the server name), and the number of players.</p>
<h3 id="control-flow">Control Flow</h3>
<p>The rest of the <code>tekkit-start</code> file is dedicated to control flow. We must ensure only one instance of the server is started, so we use <code>pgrep</code> to ask if the <code>$SERVER_USER</code> user has any process using the <code>$MINECRAFT_JAR</code>. If the server is not running, we start the server, post ping response, and wait for the server to start responding. If the server is already up, we use <code>nc</code> to route traffic between the server and meta-server.</p>
<p>To ensure every user continues to see the ping response while the server is starting but not yet responding, we add a <code>$START_LOCKFILE</code> While the <code>$START_LOCKFILE</code> exists, the only thing <code>tekkit-start</code> will do is post the ping response.</p>
<div class="brush: sh">
<pre><code>...
if [ ! -f $START_LOCKFILE ]; then
touch $START_LOCKFILE
if ! pgrep -U $SERVER_USER -f "$MINECRAFT_JAR" >/dev/null; then
sudo -u $SERVER_USER -- screen -dmS $SESSION $LAUNCH
sign
while netcat -vz -w 1 localhost 25555 2>&1 | grep refused > /dev/null; do
debug "Connection refused"
sleep 1
done
debug "Deleting start lock"
/bin/rm $START_LOCKFILE
debug `[ -f $START_LOCKFILE ] && echo "Lockfile still exists"`
else
/bin/rm $START_LOCKFILE
debug `[ -f $START_LOCKFILE ] && echo "Lockfile still exists"`
exec sudo -u $SERVER_USER nc $LOCAL_IP $LOCAL_PORT
fi
else
sign
fi</code></pre></div>
<h2 id="stopping-the-server">Stopping the server</h2>
<p>Stopping the server is easier than starting it. We want to stop the server when there have been no players online for some amount of time. However, we want to make sure not to stop too frequently, since a player may stop briefly to make food, do some work, or just get away from the computers for a little bit. Once we know the server is idle, we just stop it by issuing a <code>stop</code> command to the server.</p>
<div class="brush: sh">
<pre><code>stop() {
screen -S $SESSION -p 0 -X stuff 'stop\15'
debug "Shit's going down"
}</code></pre></div>
<p>This commands tells <code>screen</code> to connect to the <code>$SESSION</code> session, on window <code>0</code>, and <code>stuff</code> the string <code>stop\15</code> into the input buffer. The command <code>stop</code> tells the server stop running. The final character <code>\15</code> is the control character for enter/return, so this simulates typing <code>stop</code> and pressing enter.</p>
<h3 id="detecting-an-idle-server">Detecting an idle server</h3>
<p>We specify how frequently to perform an idle check using <code>crontab</code>. If there is no one online during the check, the script will wait <code>$WAIT_TIME</code> seconds and check again. If both checks pass then the server will shutdown.</p>
<p>We add the following to <code>$SERVER_USER</code>’s crontab to run the idle check once an hour.</p>
<p><code>crontab -e</code>:</p>
<div class="brush: crontab">
<pre><code>@hourly /usr/bin/tekkit-idle</code></pre></div>
<p>To determine the number of users online via script, we have all logs filtered through the <code>sed</code> script seen in <code>start()</code>. The script looks for a particular server message, and dumps the number to the file <code>$PLAYERS_FILE</code>.</p>
<p>We can force the server to output this message by using the <code>list</code> command. Since the server is running in a <code>screen</code> process, we can issue this command via <code>screen -S Minecraft -p 0 -X stuff 'list\15'</code>. The command <code>list</code> asks the server to dump the current number of players.</p>
<p>Before issuing the requre, we clear the file. After issuing the request, we wait until the file is not blank, so <code>sed</code> must have found the message and dumped it to the file. This prevents race conditions. We read in and compare to 0. All this logic is implemented in the <code>config.sh</code> function <code>idle</code>. There is also a bunch of debugging information there, because I had trouble with <code>sed</code> outputing invisible characters to the <code>$PLAYERS_FILE</code>. We use <code>tr -d [:cntrl:]</code> to remove these invisible control characters.</p>
<div class="brush: sh">
<pre><code>idle() {
echo -n "" > ${PLAYERS_FILE}
debug `cat ${PLAYERS_FILE}`
screen -S $SESSION -p 0 -X stuff 'list\15'
players=`tail -n 1 ${PLAYERS_FILE} | tr -d [:cntrl:]`
while [ -z ${players} ]; do
sleep 1
players=`tail -n 1 ${PLAYERS_FILE} | tr -d [:cntrl:]`
done
debug "There are ${players} players"
if [ "0" = "${players}" ]; then
debug "Idle"
true
else
debug "Not idle"
false
fi
}</code></pre></div>
<p>Below is the idle detection script, called <code>tekkit-idle</code>. The function <code>idle</code> is implemented in <code>config.sh</code> and returns true when no players are online. The reset of the script implements the logic I explained before: if the server is idle, i.e., no one is online, then wait <code>$WAIT_TIME</code> seconds. If the server is still idle, shut it down.</p>
<p><code>tekkit-idle</code>:</p>
<div class="brush: sh">
<pre><code>#!/bin/sh
source /etc/tekkit-on-demand/config.sh
if [ ! -f $IDLE_LOCKFILE ]; then
touch $IDLE_LOCKFILE
debug "No lock file, checking!"
if idle; then
debug "Idle, waiting!..."
sleep $WAIT_TIME
if idle; then
debug "Still idle, stopping!"
stop
fi
fi
/bin/rm $IDLE_LOCKFILE
fi
debug "Idle check complete"</code></pre></div>Overclocking your ATI Card [Linux]urn:https-www-williamjbowman-com:-blog-2012-08-27-overclocking-your-ati-card-linux2012-08-28T02:26:15Z2012-08-28T02:26:15ZWilliam J. Bowman
<p>So recently I’ve been getting all my games to run under linux. As part of this process, I’m learning all about my ATI drivers, because graphics drivers are universally terrible. However, under linux, you can tinker more freely to make them (slightly) less terrible.</p>
<!-- more-->
<p>This particular hackery came as I was researching how to fix an ‘ASIC hang happened’ issue. I haven’t yet figured that out, but I did find how to over/under clock my graphics card, and stress test it, using the proprietary ATI drivers.</p>
<p>DISCLAIMER: Overclocking your machine is dangerous. Don’t do it.</p>
<p>So, to overclock your card, here are a few helpful commands, and what they do:</p>
<ul>
<li>
<p><code>aticonfig --adapter 0 --od-getclocks</code> List adapter 0’s current clock information, including peak ranges. See <code>aticonfig --list-adapters</code> to figure out which adapter you want to specify.</p></li>
<li>
<p><code>aticonfig --adapter 0 --od-setclocks=900,1150</code> Set adapter 0’s core clock to 900, and memory clock to 1150. aticonfig might warn you about how dangerous this is and request you set a flag to enable overclocking.</p></li>
<li>
<p><code>atiode -P 600 -h $DISPLAY; echo $?</code> Run the ATI stress testing tool for 600 seconds (10 minutes) on the current X display. Print out the return value after it’s done. See aticonfig —help for return value meanings.</p></li>
<li>
<p><code>while sleep 5; do aticonfig --adapter 0 --od-gettemperature --od-getclocks > atiode.log; done</code> Log temperatures and clocks to atiode.log; to make sure your GPU isn’t overheating during the stress test.</p></li>
<li>
<p><code>aticonfig --od-commitclocks</code> I’m not really sure, but the —help suggests you should do this after running the stress tests.</p></li></ul>
<p>Now you know how to over/under-clock your card, and stress test it. Have fun.</p>
<p>Purely speculatively, if you get this “ASIC hang happened” issue, you might try underclocking the card. I haven’t tested this thoroughly enough to tell if it will help, but something I read in the overclock warnings suggested it might help</p>Modding Minecrafturn:https-www-williamjbowman-com:-blog-2012-08-12-modding-minecraft2012-08-13T00:18:58Z2012-08-13T00:18:58ZWilliam J. Bowman
<p>I like minecraft, a lot, on occassion. But it needs a few tweaks for me to really get into it. I’m going to document them now:</p>
<!-- more-->
<p>First, you need mcpatcher, so we can use HD texture packs and install mods. Get it here: <a href="https://github.com/pclewis/mcpatcher/downloads">https://github.com/pclewis/mcpatcher/downloads</a></p>
<p>I’m using linux, so I need the .jar file. You can run it via</p>
<div class="brush: bash">
<pre><code>java -jar ./mcpatch-2.4.1_02.jar</code></pre></div>
<p>This should pop up a handy GUI. More on that in a minute.</p>
<p>Next, we need the appropriate mods:</p>
<ul>
<li>
<p>Auto switcher: automatically switch to the best tool for the job; the right type of pick for mining, axe for cutting, etc.
<br /> <a href="http://www.minecraftforum.net/topic/753030-131125-thebombzens-mods-now-with-autoswitch-2/">http://www.minecraftforum.net/topic/753030–131125-thebombzens-mods-now-with-autoswitch–2/</a></p></li>
<li>
<p>OptiFine: Minecraft is full of performance issues. OptiFine helps smooth them out, and supports better graphics for those with reasonable computers. <a href="http://www.minecraftforum.net/topic/249637-131-optifine-hd-b1-fps-boost-hd-textures-aa-af-and-much-more/">http://www.minecraftforum.net/topic/249637–131-optifine-hd-b1-fps-boost-hd-textures-aa-af-and-much-more/</a></p></li>
<li>
<p>ModLoader: I don’t remember why I have this installed, but presumably it’s for good reason.
<br /> <a href="http://www.minecraftforum.net/topic/75440-v131-risugamis-mods-preliminary-updates/">http://www.minecraftforum.net/topic/75440-v131-risugamis-mods-preliminary-updates/</a></p></li></ul>
<p>So now that you have all the appropriate mods downloaded, launch mcpatcher. And add a bunch of mods (Mods -> Add in the menu). Also point it at your minecraft.jar. Should be located in ~/.minecraft/bin/.</p>
<p>Now, ensure only the following mods are checked, and ensure they appear in this order. If they don’t, use the arrows at the bottom of the GUI to rearrange them:</p>
<ol>
<li>
<p>AutoSwitchMod</p></li>
<li>
<p>ModLoader</p></li>
<li>
<p>OptiFine</p></li>
<li>
<p>Custom Colors</p></li>
<li>
<p>Random Mobs</p></li>
<li>
<p>Connected Textures</p></li>
<li>
<p>Better Skies</p></li></ol>
<p>Then click patch. mcpatcher will probably complain, but just click yes.</p>
<p>Lastly, we need a good texture pack. I like this one: <a href="http://bdcraft.net/download-purebdcraft-texturepack-for-minecraft">http://bdcraft.net/download-purebdcraft-texturepack-for-minecraft</a>, 128 bit. Much higher and Minecraft doesn’t seem to handle itself very well. Download it and save the .zip to ~/.minecraft/texturepacks. You should be able to select it from the in-game menu.</p>