#!/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_ShowAllPlayersOnMap_QueryName() { echo "Show all players on map" } serverconfig_ShowAllPlayersOnMap_Type() { echo "boolean" } serverconfig_ShowAllPlayersOnMap_Default() { echo "true" } serverconfig_ShowAllPlayersOnMap_ErrorMessage() { echo "Not a valid boolean given (true/false or yes/no or y/n)." } 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_TelnetPassword_Validate() { if [ -z $1 ]; then echo "0" else echo "1" fi } serverconfig_TelnetPassword_ErrorMessage() { echo "Telnet must have a password set to function." } 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!" 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 \ ShowAllPlayersOnMap 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 }