#!/bin/bash # Provides functions to query and validate values for serverconfig.xml ################################# ## Definition of options serverconfig_ServerPort_QueryName() { echo "Base Port" } serverconfig_ServerPort_Type() { echo "number" } serverconfig_ServerPort_Default() { echo "25000" } serverconfig_ServerPort_Range() { echo "1024-65533" } serverconfig_ServerPort_Validate() { local I=${INSTANCE:-!} if [ $(checkGamePortUsed "$1" "$I") -eq 0 ]; then echo "1" else echo "0" fi } serverconfig_ServerPort_ErrorMessage() { echo "Illegal port number or port already in use by another instance." } serverconfig_ServerIsPublic_QueryName() { echo "Public server" } serverconfig_ServerIsPublic_Type() { echo "boolean" } serverconfig_ServerIsPublic_Default() { echo "true" } serverconfig_ServerIsPublic_ErrorMessage() { echo "Not a valid boolean given (true/false or yes/no or y/n)." } serverconfig_ServerName_QueryName() { echo "Server name" } serverconfig_ServerName_Type() { echo "string" } serverconfig_ServerName_Validate() { if [ ! -z "$1" ]; then echo "1" else echo "0" fi } serverconfig_ServerName_ErrorMessage() { echo "Server name cannot be empty." } serverconfig_ServerPassword_QueryName() { echo "Server password" } serverconfig_ServerPassword_Type() { echo "string" } serverconfig_ServerMaxPlayerCount_QueryName() { echo "Max players" } serverconfig_ServerMaxPlayerCount_Type() { echo "number" } serverconfig_ServerMaxPlayerCount_Default() { echo "4" } serverconfig_ServerMaxPlayerCount_Range() { echo "1-64" } serverconfig_GameWorld_QueryName() { echo "World name" } serverconfig_GameWorld_Type() { echo "enum" } serverconfig_GameWorld_Default() { echo "1" } serverconfig_GameWorld_Values() { config_allowed_values=("Navezgane" "MP Wasteland Horde" "MP Wasteland Skirmish" "MP Wasteland War") } serverconfig_GameName_QueryName() { echo "Game name" } serverconfig_GameName_Type() { echo "string" } serverconfig_GameName_Validate() { if [ ! -z "$1" ]; then echo "1" else echo "0" fi } serverconfig_GameName_ErrorMessage() { echo "Game name cannot be empty." } serverconfig_GameDifficulty_QueryName() { echo "Difficulty" } serverconfig_GameDifficulty_Type() { echo "number" } serverconfig_GameDifficulty_Default() { echo "2" } serverconfig_GameDifficulty_Range() { echo "0-4" } serverconfig_GameDifficulty_Values() { config_allowed_values=("Very easy" "Easy" "Medium" "Hard" "Very hard") } serverconfig_GameMode_QueryName() { echo "Game mode" } serverconfig_GameMode_Type() { echo "enum" } serverconfig_GameMode_Default() { echo "1" } serverconfig_GameMode_Values() { config_allowed_values=("GameModeSurvivalMP" "GameModeSurvivalSP") } serverconfig_ZombiesRun_QueryName() { echo "Zombies run" } serverconfig_ZombiesRun_Type() { echo "number" } serverconfig_ZombiesRun_Default() { echo "0" } serverconfig_ZombiesRun_Range() { echo "0-2" } serverconfig_ZombiesRun_Values() { config_allowed_values=("Default day/night walk/run" "Never run" "Always run") } serverconfig_BuildCreate_QueryName() { echo "Item spawn menu" } serverconfig_BuildCreate_Type() { echo "boolean" } serverconfig_BuildCreate_Default() { echo "true" } serverconfig_BuildCreate_ErrorMessage() { echo "Not a valid boolean given (true/false or yes/no or y/n)." } serverconfig_DayNightLength_QueryName() { echo "Length of one day" } serverconfig_DayNightLength_Type() { echo "number" } serverconfig_DayNightLength_Default() { echo "45" } serverconfig_FriendlyFire_QueryName() { echo "Friendly fire" } serverconfig_FriendlyFire_Type() { echo "boolean" } serverconfig_FriendlyFire_Default() { echo "false" } serverconfig_FriendlyFire_ErrorMessage() { echo "Not a valid boolean given (true/false or yes/no or y/n)." } serverconfig_DayCount_QueryName() { echo "Day Count (Horde)" } serverconfig_DayCount_Type() { echo "number" } serverconfig_DayCount_Default() { echo "3" } serverconfig_FragLimit_QueryName() { echo "Frag limit (DM)" } serverconfig_FragLimit_Type() { echo "number" } serverconfig_FragLimit_Default() { echo "5" } serverconfig_MatchLength_QueryName() { echo "Match length (DM)" } serverconfig_MatchLength_Type() { echo "number" } serverconfig_MatchLength_Default() { echo "15" } serverconfig_RebuildMap_QueryName() { echo "Rebuild map on round restart" } serverconfig_RebuildMap_Type() { echo "boolean" } serverconfig_RebuildMap_Default() { echo "false" } serverconfig_RebuildMap_ErrorMessage() { echo "Not a valid boolean given (true/false or yes/no or y/n)." } serverconfig_ControlPanelEnabled_QueryName() { echo "Enable control panel" } serverconfig_ControlPanelEnabled_Type() { echo "boolean" } serverconfig_ControlPanelEnabled_Default() { echo "false" } serverconfig_ControlPanelEnabled_ErrorMessage() { echo "Not a valid boolean given (true/false or yes/no or y/n)." } serverconfig_ControlPanelPort_QueryName() { echo "Control panel port" } serverconfig_ControlPanelPort_Type() { echo "number" } serverconfig_ControlPanelPort_Default() { echo "8080" } serverconfig_ControlPanelPort_Range() { echo "1024-65535" } serverconfig_ControlPanelPort_Validate() { local I=${INSTANCE:-!} if [ $(checkTCPPortUsed "$1" "$I") -eq 0 ]; then echo "1" else echo "0" fi } serverconfig_ControlPanelPort_ErrorMessage() { echo "Illegal port number or port already in use by another instance." } serverconfig_ControlPanelPassword_QueryName() { echo "Control panel password" } serverconfig_ControlPanelPassword_Type() { echo "string" } serverconfig_TelnetPort_QueryName() { echo "Telnet port" } serverconfig_TelnetPort_Type() { echo "number" } serverconfig_TelnetPort_Default() { echo "8081" } serverconfig_TelnetPort_Range() { echo "1024-65535" } serverconfig_TelnetPort_Validate() { local I=${INSTANCE:-!} if [ $(checkTCPPortUsed "$1" "$I") -eq 0 ]; then echo "1" else echo "0" fi } serverconfig_TelnetPort_ErrorMessage() { echo "Illegal port number or port already in use by another instance." } serverconfig_TelnetPassword_QueryName() { echo "Telnet password" } serverconfig_TelnetPassword_Type() { echo "string" } serverconfig_DisableNAT_QueryName() { echo "Disable NAT" } serverconfig_DisableNAT_Type() { echo "boolean" } serverconfig_DisableNAT_Default() { echo "true" } serverconfig_DisableNAT_ErrorMessage() { echo "Not a valid boolean given (true/false or yes/no or y/n)." } serverconfig_DropOnDeath_QueryName() { echo "Drop on Death" } serverconfig_DropOnDeath_Type() { echo "number" } serverconfig_DropOnDeath_Default() { echo "0" } serverconfig_DropOnDeath_Range() { echo "0-3" } serverconfig_DropOnDeath_Values() { config_allowed_values=("Everything" "Toolbelt only" "Backpack only" "Delete all") } serverconfig_DropOnQuit_QueryName() { echo "Drop on Quit" } serverconfig_DropOnQuit_Type() { echo "number" } serverconfig_DropOnQuit_Default() { echo "0" } serverconfig_DropOnQuit_Range() { echo "0-3" } serverconfig_DropOnQuit_Values() { config_allowed_values=("Nothing" "Everything" "Toolbelt only" "Backpack only") } serverconfig_CraftTimer_QueryName() { echo "Craft speed" } serverconfig_CraftTimer_Type() { echo "number" } serverconfig_CraftTimer_Default() { echo "1" } serverconfig_CraftTimer_Range() { echo "0-2" } serverconfig_CraftTimer_Values() { config_allowed_values=("Instant" "Normal" "Double") } serverconfig_LootTimer_QueryName() { echo "Loot open speed" } serverconfig_LootTimer_Type() { echo "number" } serverconfig_LootTimer_Default() { echo "1" } serverconfig_LootTimer_Range() { echo "0-2" } serverconfig_LootTimer_Values() { config_allowed_values=("Instant" "Normal" "Double") } serverconfig_PlayerDamageGiven_QueryName() { echo "Damage Player->Zombies" } serverconfig_PlayerDamageGiven_Type() { echo "number" } serverconfig_PlayerDamageGiven_Default() { echo "2" } serverconfig_PlayerDamageGiven_Range() { echo "0-4" } serverconfig_PlayerDamageGiven_Values() { config_allowed_values=("50%" "75%" "100%" "150%" "200%") } serverconfig_PlayerDamageRecieved_QueryName() { echo "Damage Zombies->Player" } serverconfig_PlayerDamageRecieved_Type() { echo "number" } serverconfig_PlayerDamageRecieved_Default() { echo "2" } serverconfig_PlayerDamageRecieved_Range() { echo "0-4" } serverconfig_PlayerDamageRecieved_Values() { config_allowed_values=("50%" "75%" "100%" "150%" "200%") } serverconfig_EnemySenseMemory_QueryName() { echo "Sense memory (seconds)" } serverconfig_EnemySenseMemory_Type() { echo "number" } serverconfig_EnemySenseMemory_Default() { echo "60" } serverconfig_EnemySpawnMode_QueryName() { echo "Spawn mode" } serverconfig_EnemySpawnMode_Type() { echo "number" } serverconfig_EnemySpawnMode_Default() { echo "3" } serverconfig_EnemySpawnMode_Range() { echo "0-5" } serverconfig_EnemySpawnMode_Values() { config_allowed_values=("Disabled" "50%" "75%" "100%" "125%" "150%") } serverconfig_EnemyDifficulty_QueryName() { echo "Enemy difficulty" } serverconfig_EnemyDifficulty_Type() { echo "number" } serverconfig_EnemyDifficulty_Default() { echo "0" } serverconfig_EnemyDifficulty_Range() { echo "0-1" } serverconfig_EnemyDifficulty_Values() { config_allowed_values=("Normal" "Feral") } serverconfig_NightPercentage_QueryName() { echo "Night percentage" } serverconfig_NightPercentage_Type() { echo "number" } serverconfig_NightPercentage_Default() { echo "35" } serverconfig_NightPercentage_Range() { echo "10-90" } serverconfig_BlockDurabilityModifier_QueryName() { echo "Block durability (%)" } serverconfig_BlockDurabilityModifier_Type() { echo "number" } serverconfig_BlockDurabilityModifier_Default() { echo "100" } serverconfig_LootAbundance_QueryName() { echo "Loot abundance (%)" } serverconfig_LootAbundance_Type() { echo "number" } serverconfig_LootAbundance_Default() { echo "100" } serverconfig_LootRespawnDays_QueryName() { echo "Loot respawn delay (days)" } serverconfig_LootRespawnDays_Type() { echo "number" } serverconfig_LootRespawnDays_Default() { echo "7" } serverconfig_LandClaimSize_QueryName() { echo "Land claim size" } serverconfig_LandClaimSize_Type() { echo "number" } serverconfig_LandClaimSize_Default() { echo "7" } serverconfig_LandClaimDeadZone_QueryName() { echo "Minimum keystone distance" } serverconfig_LandClaimDeadZone_Type() { echo "number" } serverconfig_LandClaimDeadZone_Default() { echo "30" } serverconfig_LandClaimExpiryTime_QueryName() { echo "Claim expiry time (days)" } serverconfig_LandClaimExpiryTime_Type() { echo "number" } serverconfig_LandClaimExpiryTime_Default() { echo "3" } serverconfig_LandClaimDecayMode_QueryName() { echo "Claim decay mode" } serverconfig_LandClaimDecayMode_Type() { echo "number" } serverconfig_LandClaimDecayMode_Default() { echo "0" } serverconfig_LandClaimDecayMode_Range() { echo "0-2" } serverconfig_LandClaimDecayMode_Values() { config_allowed_values=("Linear" "Exponential" "Full protection") } serverconfig_LandClaimOnlineDurabilityModifier_QueryName() { echo "Claim durability modifier - online" } serverconfig_LandClaimOnlineDurabilityModifier_Type() { echo "number" } serverconfig_LandClaimOnlineDurabilityModifier_Default() { echo "4" } serverconfig_LandClaimOfflineDurabilityModifier_QueryName() { echo "Claim durability modifier - offline" } serverconfig_LandClaimOfflineDurabilityModifier_Type() { echo "number" } serverconfig_LandClaimOfflineDurabilityModifier_Default() { echo "4" } serverconfig_AirDropFrequency_QueryName() { echo "Airdrop delay (hours)" } serverconfig_AirDropFrequency_Type() { echo "number" } serverconfig_AirDropFrequency_Default() { echo "24" } serverconfig_MaxSpawnedZombies_QueryName() { echo "Maximum number of concurrent zombies" } serverconfig_MaxSpawnedZombies_Type() { echo "number" } serverconfig_MaxSpawnedZombies_Default() { echo "60" } serverconfig_VACEnabled_QueryName() { echo "Enable Valve Anti Cheat" } serverconfig_VACEnabled_Type() { echo "boolean" } serverconfig_VACEnabled_Default() { echo "true" } serverconfig_VACEnabled_ErrorMessage() { echo "Not a valid boolean given (true/false or yes/no or y/n)." } ################################# ## Edit option functions configEditServer() { local CV echo "Server" echo "--------------------------------" for CV in \ ServerName ServerPassword ServerIsPublic ServerPort ServerMaxPlayerCount \ DisableNAT VACEnabled MaxSpawnedZombies \ ; do $1 $CV done echo } configEditRemoteControl() { local CV echo "Remote control" echo "--------------------------------" for CV in \ ControlPanelEnabled ControlPanelPort ControlPanelPassword \ TelnetPort TelnetPassword \ ; do if [ "$CV" = "TelnetPort" ]; then echo echo "NOTE: Telnet will always be enabled for management purposes!" echo "Make sure you block external access to this port or set no password" echo "so the server will only listen on the loopback interface!" echo fi $1 $CV done echo } configEditGameType() { local CV echo "Game type" echo "--------------------------------" for CV in \ GameName GameWorld GameMode \ ; do $1 $CV done echo } configEditGameTypeSpecific() { local CV echo "Options for specific game types" echo "--------------------------------" for CV in \ DayCount FragLimit MatchLength RebuildMap \ ; do $1 $CV done echo } configEditGeneric() { local CV echo "Generic options" echo "--------------------------------" for CV in \ FriendlyFire BuildCreate \ BlockDurabilityModifier \ ; do $1 $CV done echo } configEditDropLoot() { local CV echo "Drop and Loot" echo "--------------------------------" for CV in \ DropOnDeath DropOnQuit \ LootAbundance LootRespawnDays AirDropFrequency \ ; do $1 $CV done echo } configEditTimes() { local CV echo "Times / Durations" echo "--------------------------------" for CV in \ CraftTimer LootTimer \ DayNightLength NightPercentage \ ; do $1 $CV done echo } configEditDifficulty() { local CV echo "Difficulty" echo "--------------------------------" for CV in \ GameDifficulty ZombiesRun \ PlayerDamageGiven PlayerDamageRecieved EnemySenseMemory EnemySpawnMode EnemyDifficulty \ ; do $1 $CV done echo } configEditLandClaim() { local CV echo "Land claim options" echo "--------------------------------" for CV in \ LandClaimSize LandClaimDeadZone LandClaimExpiryTime LandClaimDecayMode \ LandClaimOnlineDurabilityModifier LandClaimOfflineDurabilityModifier \ ; do $1 $CV done echo } configEditAll() { configEditServer "$1" configEditRemoteControl "$1" configEditGameType "$1" configEditGameTypeSpecific "$1" configEditGeneric "$1" configEditDropLoot "$1" configEditTimes "$1" configEditDifficulty "$1" configEditLandClaim "$1" } ################################# ## Generic worker functions # List all defined config editing parts # Returns: # List of config funcs listConfigEditFuncs() { local CV for CV in $(declare -F | cut -d\ -f3 | grep "^configEdit.*$"); do CV=${CV#configEdit} printf "%s " "$CV" done } # List all defined config options # Returns: # List of defined config options listConfigValues() { local CV for CV in $(declare -F | cut -d\ -f3 | grep "^serverconfig_.*_Type$"); do CV=${CV#serverconfig_} CV=${CV%_Type} printf "%s " "$CV" done } # Validate the given value for the given option # Params: # 1: Option name # 2: Value # Returns: # 0/1: invalid/valid isValidOptionValue() { local TYPE=$(serverconfig_$1_Type) local RANGE="" if [ "$TYPE" = "enum" ]; then TYPE="number" serverconfig_$1_Values RANGE=1-${#config_allowed_values[@]} else if [ "$(type -t serverconfig_$1_Range)" = "function" ]; then RANGE=$(serverconfig_$1_Range) fi fi case "$TYPE" in number) if [ $(isANumber "$2") -eq 0 ]; then echo "0" return fi if [ ! -z "$RANGE" ]; then local MIN=$(cut -d- -f1 <<< "$RANGE") local MAX=$(cut -d- -f2 <<< "$RANGE") if [ $2 -lt $MIN -o $2 -gt $MAX ]; then echo "0" return fi fi ;; boolean) if [ $(isABool "$2") -eq 0 ]; then echo "0" return fi ;; string) ;; esac if [ "$(type -t serverconfig_$1_Validate)" = "function" ]; then if [ $(serverconfig_$1_Validate "$2") -eq 0 ]; then echo "0" return fi fi echo "1" } # Query for the value of a single config option # Will be stored in $configCurrent_$1 # Params: # 1: Option name configQueryValue() { local TYPE=$(serverconfig_$1_Type) local NAME="" local RANGE="" local DEFAULT="" local currentValName=configCurrent_$1 if [ "$(type -t serverconfig_$1_Values)" = "function" ]; then echo "$(serverconfig_$1_QueryName), options:" serverconfig_$1_Values NAME="Select option" if [ "$TYPE" = "enum" ]; then local OPTOFFSET=1 else local OPTOFFSET=0 fi for (( i=$OPTOFFSET; i < ${#config_allowed_values[@]}+$OPTOFFSET; i++ )); do printf " %2d: %s\n" $i "${config_allowed_values[$i-$OPTOFFSET]}" done else NAME=$(serverconfig_$1_QueryName) fi if [ "$TYPE" = "enum" ]; then RANGE=1-${#config_allowed_values[@]} if [ ! -z "${!currentValName}" ]; then for (( i=1; i < ${#config_allowed_values[@]}+1; i++ )); do if [ "${!currentValName}" = "${config_allowed_values[$i-1]}" ]; then DEFAULT=$i fi done export $currentValName= fi else if [ "$(type -t serverconfig_$1_Range)" = "function" ]; then RANGE=$(serverconfig_$1_Range) fi fi if [ -z "$DEFAULT" ]; then if [ ! -z "${!currentValName}" ]; then DEFAULT=${!currentValName} else if [ "$(type -t serverconfig_$1_Default)" = "function" ]; then DEFAULT=$(serverconfig_$1_Default) fi fi fi local prompt=$(printf "%s" "$NAME") if [ ! -z "$RANGE" ]; then prompt=$(printf "%s (%s)" "$prompt" "$RANGE") fi if [ ! -z "$DEFAULT" ]; then prompt=$(printf "%s [%s]" "$prompt" "$DEFAULT") fi prompt=$(printf "%s:" "$prompt") prompt=$(printf "%-*s " 40 "$prompt") while : ; do read -p "$prompt" $currentValName export $currentValName="${!currentValName:-$DEFAULT}" if [ $(isValidOptionValue "$1" "${!currentValName}") -eq 0 ]; then if [ "$(type -t serverconfig_$1_ErrorMessage)" = "function" ]; then serverconfig_$1_ErrorMessage "${!currentValName}" fi fi [ $(isValidOptionValue "$1" "${!currentValName}") -eq 1 ] && break done if [ "$TYPE" = "boolean" ]; then if [ $(getBool ${!currentValName}) -eq 1 ]; then export $currentValName="true" else export $currentValName="false" fi fi if [ "$TYPE" = "enum" ]; then export $currentValName="${config_allowed_values[$currentValName-1]}" fi echo } # Set parameters for current instance that have forced values: # - TelnetEnabled must be set so that management scripts can work # - AdminFileName is made to point to the local instance admins.xml # - SaveGameFolder is made to point to the instance folder # Params: # 1: Instance name configSetAutoParameters() { configCurrent_TelnetEnabled=true configCurrent_AdminFileName=admins.xml configCurrent_SaveGameFolder="$(getInstancePath "$1")" } # Print defined config value # Params: # 1: Config option printConfigValue() { local currentValName=configCurrent_$1 printf "%-25s = %s\n" "$(serverconfig_$1_QueryName)" "${!currentValName}" } # Query for an instance name (will be saved in $INSTANCE) readInstanceName() { until [ $(isValidInstanceName "$INSTANCE") -eq 1 ]; do read -p "Instance name: " INSTANCE if [ $(isValidInstanceName "$INSTANCE") -eq 0 ]; then echo "Invalid instance name, may only contain:" echo " - letters (A-Z / a-z)" echo " - digits (0-9)" echo " - underscores (_)" echo " - hyphens (-)" fi done } # Undefine the current config values unsetAllConfigValues() { local CV for CV in $(listConfigValues); do local currentValName=configCurrent_$CV export $currentValName= done } # Load all config values from the config.xml of the given instance # Params: # 1: Instance name loadCurrentConfigValues() { local CV for CV in $(listConfigValues); do local currentValName=configCurrent_$CV local cfile=$(getInstancePath "$1")/config.xml local XPATH="/ServerSettings/property[@name='$CV']/@value" local VAL=$($XMLSTARLET sel -t -v "$XPATH" $cfile) if [ ! -z "$VAL" ]; then export $currentValName="$VAL" fi done } # Save all config values to the config.xml of the given instance # Params: # 1: Instance name saveCurrentConfigValues() { local CV for CV in $(listConfigValues) TelnetEnabled AdminFileName SaveGameFolder; do local currentValName=configCurrent_$CV local val="${!currentValName}" local cfile=$(getInstancePath "$1")/config.xml XPATHBASE="/ServerSettings/property[@name='$CV']" if [ -z $($XMLSTARLET sel -t -v "$XPATHBASE/@name" $cfile) ]; then $XMLSTARLET ed -L \ -s "/ServerSettings" -t elem -n "property" -v "" \ -i "/ServerSettings/property[not(@name)]" -t attr -n "name" -v "$CV" \ -i "$XPATHBASE" -t attr -n "value" -v "$val" \ $cfile else $XMLSTARLET ed -L \ -u "$XPATHBASE/@value" -v "$val" \ $cfile fi done } # Check if the config template exists # Returns: # 0/1: no/yes configTemplateExists() { if [ -f $SDTD_BASE/templates/config.xml ]; then echo 1 else echo 0 fi } # Get a single value from a serverconfig # Params: # 1: Instance name # 2: Property name # Returns: # Property value getConfigValue() { local CONF=$(getInstancePath $1)/config.xml $XMLSTARLET sel -t -v "/ServerSettings/property[@name='$2']/@value" $CONF } # Update a single value in a serverconfig # Params: # 1: Instance name # 2: Property name # 3: New value setConfigValue() { local CONF=$(getInstancePath $1)/config.xml $XMLSTARLET ed -L -u "/ServerSettings/property[@name='$2']/@value" -v "$3" $CONF }