commit 689edbdb1b14c52258557715642545583b3f626e
parent 039cf19830aa3932b57084b6eefd19309ff16ea3
Author: giygas <giygas@boymiasma.net>
Date: Tue, 28 Oct 2025 00:31:33 +0100
Default configuration fix, apply steam library fix, interface changes, add READMEREADME
Diffstat:
| M | README.md | | | 176 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
| M | scrake.ini | | | 23 | ++++++++++++----------- |
| M | scrake.sh | | | 89 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------- |
3 files changed, 257 insertions(+), 31 deletions(-)
diff --git a/README.md b/README.md
@@ -1,2 +1,174 @@
-under construction
-docs soon
+# This software is experimental!
+As is currently, scraketools suffers from several limitations that require manual intervention.
+Numerous helper scripts and helpful behaviours have yet to be added before the software reaches
+a usable Beta state. Nevertheless, the scraketools is programmed as a user-facing application,
+and contains safeguards against accidental data deletion. Still; never run scraketools
+as root, and consider creating a backup of your server installation before migrating it to a
+scrake instance.
+
+As of 2025-10-27, boymiasma.net's Killing Floor 1 servers are administrated through scrake.sh
+
+# Intro
+scraketools is a growing suite of bourne-again shell scripts designed to ease the burden of administrating multiple
+Killing Floor 1 dedicated servers in tandem.
+
+Amongst its features are
+- Creation and management of individual server instances derived from a single server base install
+- Per-instance map/mutator installation
+- Global and per-instance base game and mutator configuration through a single file, `scrake.ini`
+- Automatic installation of the base server software through `steamcmd`
+- Automatic application of the linux server discoverablity prefix
+
+# Installation
+```
+git clone git://git.boymiasma.net/scraketools
+chmod +x scraketools/scrake.sh
+```
+
+Furthermore, scraketools requires `steamcmd` to exist within your path.
+
+# Quickstart (fresh server installation)
+Never copy-paste commands. This is but a reference. Keep reading.
+```
+# install the base server software. You will be prompted to log in by steamcmd.
+# NOTE: if you plan to migrate an existing server, skip this step and consult the "Existing server migration" header below
+scraketools/scrake.sh init <steam_username>
+
+# NOTE: because of a limitation in Killing Floor's default config generation, the rest of this
+# quickstart guide will leave you without map or kick-voting. If you need these functionalities,
+# enable the web server for the base server installation (~/.steam/SteamApps/common/Killing Floor Dedicated Server - Linux/System/KillingFloor.ini by default on ArchLinux)
+# and set an admin password, and enable WebAdmin. Run the server as `./ucc-bin server KF-Wyre.rom?game=KFmod.KFGameType -nohomedir`, and enable Map Voting through the interface.
+# You might also want to define your maplist here, as there is no way to accomplish this through standard scraketools configuration (yet).
+# Save the configuration, shut down the server, proceed as normal, and heed the warning under 'Configuration' down below.
+
+# create three server instances; which can then be found in ~/Scrake/Servers
+scraketools/scrake.sh create Normal Hard Suicidal
+
+# (Optionally) Install maps/mutators (see below)
+for INSTANCE in Normal Hard Suicidal; do
+ scraketools/scrake.sh mod $INSTANCE mutator add <mut1> <mut2> ...
+ scraketools/scrake.sh mod $INSTANCE map add <mut1> <mut2> ...
+done
+
+# Edit the default configuration in Scrake/scrake.ini (see below)
+cp scraketools/scrake.ini Scrake/scrake.ini
+
+# Apply scraketools/scrake.ini to each instance
+scraketools/scrake.sh sync Normal Hard Suicidal
+
+# Run servers
+for INSTANCE in Normal Hard Suicidal; do
+ scraketools/scrake.sh run $INSTANCE KF-Wyre.rom &
+done
+```
+From here, you may make changes to Scrake/scrake.ini and re-sync them to each instance.
+Note that the server must not be running while you run the `sync` command; it has been known
+to overwrite the active configuration file while up, undoing the changes applied by `sync`.
+
+# Configuration
+What follows is an incomplete copy of the example configuration file bundled with scraketools
+```
+[Scrake]
+Engine.AccessControl/AdminPassword=Admin123
++Engine.GameInfo/bVACSecured=True
+-Engine.GameEngine/ServerActors=IpDrv.MasterServerUplink
+
+[Scrake.Normal]
+URL/Port=7707
+IpDrv.UdpGamespyQuery/OldQueryPortNumber=7717
+Engine.GameInfo/GameDifficulty=2
+
+[Scrake.Hard]
+URL/Port=7807
+IpDrv.UdpGamespyQuery/OldQueryPortNumber=7817
+Engine.GameInfo/GameDifficulty=4
+
+[Scrake.Suicidal]
+URL/Port=7907
+IpDrv.UdpGamespyQuery/OldQueryPortNumber=7917
+Engine.GameInfo/GameDifficulty=5
+```
+scrake.ini defines overrides applied to an individual instance's System/*.ini files.
+Each override takes the form:
+[modifier]Section/Key=Value
+Where modifier may be one of '+', '-', or unspecified.
+scrake.sh alters the value of any matching configuration key in the specified section to
+the new value specified in scrake.ini. The overrides are applied to each System/*.ini file.
+If the override specifies a section/key that does not appear in the configuration file, it is silently ignored.
+
+The '+' modifier instructs scrake.sh to add a new key-value pair to the specified section
+The '-' modifier makes scrake.sh remove a key-value pair from the specified action if the given value matches exactly.
+
+Overrides from the [Scrake] section are applied to any and all instances supplied to the `sync` command.
+Overrides from any section that takes the form [Scrake.<instance>] are only applied to the corresponding instance.
+
+LIMITATION: the order of the sections in scrake.ini matters; the last encountered override will be applied last.
+LIMITATION: there MUST be a blank line between the any given final key-value pair and next section.
+
+CONFIGURATION NOTE (if you followed the extra steps in the Quickstart):
+ By default, some values like Engine.GameInfo/bVACSecured and Engine.GameInfo/GameDifficulty do not appear in the default
+ configuration, and so they must possess the '+' modifier in scrake.ini in order to be added.
+ However, if you ran the webadmin console on the base installation and pressed 'Save', Killing Floor will have
+ added these values to KillingFloor.ini itself, which leads to the '+' modifier creating duplicate values,
+ most likely ignoring your overrides. You must instead override these values with no modifier, so that
+ scrake.sh alters the default, instead of adding a duplicate. I am working on fixing this.
+
+# Migrating from an existing setup (Untested)
+scrake.sh's behaviour may be modified by changing various configuration variables. Amongst these is SCRAKE_BASE, which
+points to the default server installation path out of the box (~/.steam/SteamApps/common/Killing Floor Dedicated Server - Linux)
+
+After changing SCRAKE_BASE to the root directory of your existing server installation, scrake.sh will create new instances
+using the specified installation as the base.
+
+In testing, scrake.sh has never corrupted or altered the base server installation (besides alterations made by `init`, which,
+if you're consulting this section, you wouldn't execute). Regardless, consider making a copy of your server installation while
+testing out this experimental software.
+
+# Adding or removing maps and mutators
+Add mutators or maps to Scrake/Mutators/<Mutname> or Scrake/Maps/<Mapname>. The contents of <Mutname> and <Mapname> should correspond
+to the directory structure of the base installation. For example:
+ Scrake/Maps/
+ Affairs/
+ Maps/
+ KF-Affairs.rom
+ Arcade-Hardcore/
+ Maps/
+ KF-Arcade-Hardcore.rom
+or:
+ Scrake/Mutators/
+ CustomServerDetails/
+ System/
+ CustomServerDetails.ini
+ CustomServerDetails.u
+etc.
+
+TODO: write a script to 'install' maps and mutators to the corresponding directories with the correct directory structure.
+
+Now the maps and mutators can be installed by executing:
+scraketools/scrake.sh mod Normal mutator add CustomServerDetails
+scraketools/scrake.sh mod Normal map add Affairs Arcade-Hardcore
+
+# Finally... how does it work?
+scrake.sh creates instances by re-creating the directory structure of the base server software, and then symbolically linking
+every single file over. The links to configuration files in System are renamed from *.ini to *.ini.defaults. The `sync` command
+then applies the configuration overrides from scrake.ini to each *.ini.defaults file, writing them to the 'real' configuration file,
+KillingFloor.ini . This allows for several server instances to run in tandem from only a single base server installation.
+
+One might imagine that, through the help of a tool such as `sshfs`, one could run an arbitrary number of Killing Floor servers
+spread across a variety of machines on a DMZ, all from one installation.
+
+# Next on the chopping block
+- There needs to be a more robust solution for applying overrides from scrake.ini to the individual server configurations. Currently,
+ defining map lists or custom sections is just straight up out of the question.
+- I'm currently tearing my hair out about whether to ship a sane default KillingFloor.ini with scraketools, or whether to continue
+ trying to programmatically wrangle the server binary to just cough up the "full" configuration during setup. I'm not quite
+ decided on that yet.
+- It should not be difficult at all to write a script to install maps/mutators to Scrake and 'guess' the correct directory structure
+ from the contents of the zip/rar/7z/whatever.
+
+# Features beyond the horizon
+- Automatic synchronisation of banlists
+- systemd unit file generation
+- FastDL manager
+- Status watchdog & log analyser
+
diff --git a/scrake.ini b/scrake.ini
@@ -1,40 +1,41 @@
[Scrake]
-Engine.AccessControl/AdminPassword=AdminPassword
+Engine.AccessControl/AdminPassword=
Engine.AccessControl/GamePassword=
-Engine.GameInfo/bVACSecured=True
-Engine.GameReplicationInfo/ServerName=My Server
++Engine.GameInfo/bVACSecured=True
Engine.GameReplicationInfo/ShortName=
Engine.GameReplicationInfo/AdminName=
Engine.GameReplicationInfo/AdminEmail=
Engine.GameReplicationInfo/MessageOfTheDay=
IpDrv.MasterServerUplink/DoUplink=True
-IpDrv.MasterServerUplink/UplinkToGamespy=False
+IpDrv.MasterServerUplink/UplinkToGamespy=True
IpDrv.MasterServerUplink/SendStats=True
IpDrv.MasterServerUplink/ServerBehindNAT=False
IpDrv.MasterServerUplink/DoLANBroadcast=False
IpDrv.HTTPDownload/RedirectToURL=
--Engine.GameEngine/ServerActors=IpDrv.MasterServerUplink
-+Engine.GameEngine/ServerActors=CustomServerDetails.CSDMasterServerUplink
-+Engine.GameEngine/ServerActors=MutKillMessage.MutKillMessage
-+Engine.GameEngine/ServerActors=ReloadOptionsMut.ReloadOptionsMut
[Scrake.Normal]
URL/Port=7707
IpDrv.UdpGamespyQuery/OldQueryPortNumber=7717
UWeb.WebServer/bEnabled=True
UWeb.WebServer/ListenPort=8075
-Engine.GameInfo/GameDifficulty=2
++Engine.GameInfo/GameDifficulty=2
+Engine.GameReplicationInfo/ServerName=My Killing Floor Server (Normal)
+KFmod.KFGameType/KFGameLength=2
[Scrake.Hard]
URL/Port=7807
IpDrv.UdpGamespyQuery/OldQueryPortNumber=7817
UWeb.WebServer/bEnabled=True
UWeb.WebServer/ListenPort=8175
-Engine.GameInfo/GameDifficulty=4
++Engine.GameInfo/GameDifficulty=4
+Engine.GameReplicationInfo/ServerName=My Killing Floor Server (Hard)
+KFmod.KFGameType/KFGameLength=2
[Scrake.Suicidal]
URL/Port=7907
IpDrv.UdpGamespyQuery/OldQueryPortNumber=7917
UWeb.WebServer/bEnabled=True
UWeb.WebServer/ListenPort=8275
-Engine.GameInfo/GameDifficulty=5
++Engine.GameInfo/GameDifficulty=5
+Engine.GameReplicationInfo/ServerName=My Killing Floor Server (Suicidal)
+KFmod.KFGameType/KFGameLength=2
diff --git a/scrake.sh b/scrake.sh
@@ -77,13 +77,14 @@ init_base() {
done
rm "$FIRSTRUN_FIFO"
notify "init_base: first run successful"
+
+ tr -d '\r' <"$SCRAKE_BASE/System/Default.ini" | sed -n '/^\[KFmod.KFGameType\]$/,/^ *$/p' >> "$SCRAKE_BASE/System/KillingFloor.ini"
}
-# Usage: skeleton_link -i src dst
+# Usage: skeleton_link src dst
skeleton_link()
{
- typeset SRC DST INI_REPLACE DIR DIRNAME
- if [ "$1" == "-i" ]; then INI_REPLACE=1; shift; fi
+ typeset SRC DST DIR DIRNAME
if [ $# -ne 2 ]; then fatal "usage: skeleton_link source destination"; fi
SRC="$(realpath "$1")"
if [ ! -d "$SRC" ]; then fatal "skeleton_link: no such directory '$SRC'"; fi
@@ -95,9 +96,6 @@ skeleton_link()
[ -d "$DST/$DIRNAME" ] || mkdir $VERBOSE "$DST/$DIRNAME"
find "$DIR" -type f -exec ln $VERBOSE -s {} "$DST/$DIRNAME" \;
done
- if [ ! -z "$INI_REPLACE" ]; then
- find "$DST" -type l -name '*.ini' -exec mv $VERBOSE {} {}.defaults \;
- fi
}
# Usage: skeleton_unlink src dst
@@ -115,20 +113,72 @@ skeleton_unlink()
done
}
+# Usage: fix_steam dst
+fix_steam() {
+ typeset SRC DST FILE
+ if [ $# -ne 1 ]; then fatal "usage: fix_steam dst"; fi
+ SRC="$(realpath "$STEAM_ROOT/steamcmd/linux32")"
+ if [ ! -d "$SRC" ]; then warn "fix_steam: could not find '$SRC'. Fix will fail."; fi
+ DST="$(realpath "$1")"
+ if [ ! -d "$DST" ]; then fatal "fix_steam: no such directory '$DST'"; exit 1; fi
+
+ notify "applying steam library fix to restore master server list discoverability."
+ for FILE in steamclient.so libtier0_s.so libvstdlib_s.so; do
+ if [ ! -f "$SRC/$FILE" ]; then warn "library not found: '$SRC/FILE'. Skipping."; continue; fi
+ ln $VERBOSE -fs "$SRC/$FILE" "$DST/$FILE"
+ done
+}
+
+# Usage: ini_rename dst
+ini_rename() {
+ typeset DST
+ if [ $# -ne 1 ]; then fatal "usage: ini_rename dst"; exit 1; fi
+ DST="$(realpath "$1")"
+ if [ ! -d "$DST" ]; then fatal "ini_rename: no such directory '$DST'"; exit 1; fi
+
+ notify "changing the .ini extension on instance symlinks to .ini.defaults"
+ find "$DST" -type l -name '*.ini' -exec mv $VERBOSE {} {}.defaults \;
+}
+
+# Usage: meta_remove dst
+meta_remove() {
+ typeset DST FILE
+ if [ $# -ne 1 ]; then fatal "usage: meta_remove dst"; exit 1; fi
+ DST="$(realpath "$1")"
+ if [ ! -d "$DST" ]; then fatal "meta_remove: no such directory '$DST'"; exit 1; fi
-# Usage: new_instance name [name [...]]
+ notify "removing meta maps"
+ for FILE in KFintro.rom KF-Menu.rom Entry.rom; do
+ rm $VERBOSE "$DST/$FILE"
+ done
+}
+
+usage_new_instance() { echo "new_instance [-DLM] name [name [...]]"; }
new_instance() {
- typeset SRC DST
- if [ $# -lt 1 ]; then fatal "usage: new_instance name [name [...]]" >&2; fi
+ typeset SRC DST FILE OPT OPTIND STEAMFIX INIRENAME METAREMOVE
+ if [ $# -lt 1 ]; then fatal "$(usage_new_instance)" >&2; exit 1; fi
+
+ STEAMFIX=1; INIRENAME=1; METAREMOVE=1;
+ while getopts "DLM" OPT; do
+ case "$OPT" in
+ D) INIRENAME=0;;
+ L) STEAMFIX=0;;
+ M) METAREMOVE=0;;
+ *) fatal "$(usage_new_instance)"; exit 1;;
+ esac
+ done
+ shift $((OPTIND-1))
while [ $# -ge 1 ]; do
notify "creating instance '$1'"
SRC="$(realpath "$SCRAKE_BASE")"
DST="$(realpath "$SCRAKE_ROOT/Servers/$1")"
- if [ -d "$DST" ]; then notify "new_instance: instance '$1' already exists. Skipping..."; fi
-
- mkdir $VERBOSE "$DST" && skeleton_link -i "$SRC" "$DST"
+ if [ -d "$DST" ]; then notify "new_instance: instance '$1' already exists.";
+ else mkdir $VERBOSE "$DST" && skeleton_link "$SRC" "$DST"; fi
+ if [ $STEAMFIX -eq 1 ]; then fix_steam "$DST/System"; fi
+ if [ $INIRENAME -eq 1 ]; then ini_rename "$DST/System"; fi
+ if [ $METAREMOVE -eq 1 ]; then meta_remove "$DST/Maps"; fi
shift
done
}
@@ -159,7 +209,8 @@ mod_instance() {
continue;
fi
notify "mod_mutator: installing $WHAT '$1' to $TARGET"
- skeleton_link -i "$SRC/$1" "$DST"
+ skeleton_link "$SRC/$1" "$DST"
+ ini_rename "$DST/System"
shift
done;;
remove)
@@ -224,11 +275,10 @@ usage_scrake() {
cat <<EOF
usage:
$PROGNAME [global-options] init [-N] steam_username [alt_install_dir]
- $PROGNAME [global-options] create instance_name ...
+ $PROGNAME [global-options] create [-DLM] instance_name ...
$PROGNAME [global-options] mod instance_name mutator add|remove mutname ...
$PROGNAME [global-options] mod instance_name map add|remove mapname ...
- $PROGNAME [global-options] sync cfg instance_name ...
- $PROGNAME [global-options] sync bans instance_name ...
+ $PROGNAME [global-options] sync instance_name ...
$PROGNAME [global-options] run instance_name map_name
global options:
-h show this help message
@@ -238,7 +288,11 @@ global options:
-i alternative configuration override file (overrides SCRAKE_CFG)
-v verbose flag
init options:
- -N do not perform the automatic server first-run
+ -N do not perform the automatic server first-run (not recommended)
+create options:
+ -D do not rename .ini symlinks to .defaults (not recommended)
+ -L do not apply master server list discoverability fix
+ -M do not remove meta-maps (KFintro.rom, Entry.rom, KF-Menu.rom)
EOF
}
while getopts "b:i:Nhr:s:v" OPT; do
@@ -246,7 +300,6 @@ while getopts "b:i:Nhr:s:v" OPT; do
b) SCRAKE_BASE="${OPTARG}";;
h) usage_scrake; exit;;
i) SCRAKE_CFG="${OPTARG}";;
- N) NO_FIRSTRUN=1;;
r) SCRAKE_ROOT="${OPTARG}";;
s) STEAM_ROOT="${OPTARG}";;
v) VERBOSE="-v";;