diff --git a/CentOS/Arma/Arma-Connect-Server.bash b/CentOS/Arma/Arma-Connect-Server.bash new file mode 100755 index 0000000..b89322d --- /dev/null +++ b/CentOS/Arma/Arma-Connect-Server.bash @@ -0,0 +1,12 @@ +#!/bin/bash --posix + +set -e + +[[ -z "${1}" ]] && \ +echo \ +"Error - Invalid Server ID Passed + Usage: $(basename ${0}) " && exit 1 + +tmux attach-session -t "Arma-Server-${1}" + +exit ${?} \ No newline at end of file diff --git a/CentOS/Arma/Arma-Open-Ports.bash b/CentOS/Arma/Arma-Open-Ports.bash new file mode 100755 index 0000000..bf5ccec --- /dev/null +++ b/CentOS/Arma/Arma-Open-Ports.bash @@ -0,0 +1,9 @@ +#!/bin/bash --posix + +# To add additional ports for Arma you need to have 5 ports open as a range +# Arma offsets from the first port and increments upwards until 5 ports are open +# E.g. game is set to run on port 100, then ports 100-104 need to be opened +# By default Arma 3 runs from port 2302 +firewall-cmd --zone=public --add-port=2300-2309/udp --permanent +firewall-cmd --reload + diff --git a/CentOS/Arma/Arma-Start-Server.bash b/CentOS/Arma/Arma-Start-Server.bash new file mode 100755 index 0000000..513f297 --- /dev/null +++ b/CentOS/Arma/Arma-Start-Server.bash @@ -0,0 +1,107 @@ +#!/bin/bash --posix + +set -e + +usage() { + printf "%s\n" "Usage: Autodelete-Files -u -p + --user | -u + Example: + --user Sbinalla + --server | -s + Example: + --server 0" +} + +error() { + printf "\n%s\n" "$1" >&2 + exit 1 +} + +confirmation() { + while true; do + read -p "${1}" -n 1 -r choice + case "$choice" in + y | Y) return 1 ;; + n | N) return 0 ;; + *) echo -e "\nInput must be either y, Y, n, or N" ;; + esac + done +} + +SERVERNUM="" +STEAMUSER="" + +while :; do + case $1 in + -h | -\? | --help) + usage # Display a usage synopsis. + exit + ;; + --) # End of all options. + shift + break + ;; + -s | --server) + shift + SERVERNUM="${1}" + ;; + -u | --user) + shift + STEAMUSER="${1}" + ;; + -?*) + printf 'Unknown option: %s\n' "$1" >&2 + usage + error + ;; + *) # Default case: No more options, so break out of the loop. + break ;; + esac + shift +done + + +[[ "${SERVERNUM}" == "" ]] && error "Error: A server number must be provided" +[[ "${SERVERNUM}" =~ [^0-9]+. ]] && error "Error: The argument for server must be a number" + +[[ "${STEAMUSER}" == "" ]] && error "Error: A steam user must be provided" + + +[[ -d ~/Arma/ ]] || \ + mkdir -p ~/Arma/ && echo "Created the Arma directory..." + +steamcmd +quit +steamcmd +login "${STEAMUSER}" +force_install_dir ~/Arma/Server-"${SERVERNUM}" +app_update 233780 validate +quit + +[[ -d ~/Arma/Server-"${SERVERNUM}"/mods ]] || \ + mkdir ~/Arma/Server-"${SERVERNUM}"/mods && echo "Creating new mods directory" + +# These directories are necessary for Arma servers on linux +[[ -d ~/".local/share/Arma 3" ]] || \ + mkdir -p ~/".local/share/Arma 3" && echo "Created the Arma 3 share" +[[ -d ~/".local/share/Arma 3 - Other Profiles" ]] || \ + mkdir -p ~/".local/share/Arma 3 - Other Profiles" && echo "Created the Arma 3 Other Profiles" + + +MODS="" +for mod in $(ls ~/Arma/Server-"${SERVERNUM}"/mods/) +do + echo "Adding mod ${mod}" + MODPATH=~/Arma/Server-"${SERVERNUM}"/mods + MODS="${MODS}${MODPATH}/${mod}\;" +done + +echo "Mods added to startup: ${MODS}" + +SERVERPORT=$(("2300" + "${SERVERNUM}")) + +tmux kill-session -t "Arma-Server-${SERVERNUM}" &>/dev/null + +tmux new-session -d -s \ + "Arma-Server-${SERVERNUM}" \ + ~/Arma/Server-"${SERVERNUM}"/arma3server \ + -name=Arma-Server-"${SERVERNUM}" \ + -mod="${MODS}" \ + -config=~/Arma/Server-"${SERVERNUM}"/server.cfg \ + -noSound \ + -port="${SERVERPORT}" diff --git a/CentOS/Arma/Mods/Arma-Install-Mod.bash b/CentOS/Arma/Mods/Arma-Install-Mod.bash new file mode 100755 index 0000000..8f6a619 --- /dev/null +++ b/CentOS/Arma/Mods/Arma-Install-Mod.bash @@ -0,0 +1,124 @@ +#!/bin/bash --posix + +usage() { + printf "%s\n" \ + "Usage: $(basename "${0}") -u -s -w -m + --user | -u + Example: + --user Sbinalla + --server | -s + Example: + --server 0 + --workshop-id | -w + Example: + --workshop-id 450814997 + --mod-name | -m + Example: + --mod-name @cba3 + Note: + All mod names are converted to lowercase, Arma 3 requires lowercase mod names for linux." +} + +error() { + printf "\n%s\n" "$1" >&2 + exit 1 +} + +confirmation() { + local choice + while true; do + read -p "${1}" -n 1 -r choice + case "${choice}" in + y | Y) + echo "" + return 1 + ;; + n | N) + echo "" + return 0 + ;; + *) echo -e "\nInput must be either y, Y, n, or N" ;; + esac + done +} + +## Variable setup +SERVERNUM="" +STEAMUSER="" +WORKSHOPID="" +MODNAME="" + +# Arg parsing is done here +while :; do + case $1 in + -h | -\? | --help) + usage # Display a usage synopsis. + exit + ;; + --) # End of all options. + shift + break + ;; + -s | --server) + shift + SERVERNUM="${1}" + ;; + -u | --user) + shift + STEAMUSER="${1}" + ;; + -w | --workshop-id) + shift + WORKSHOPID="${1}" + ;; + -m | --mod-name) + shift + MODNAME="${1}" + ;; + -?*) + printf 'Unknown option: %s\n' "$1" >&2 + usage + error + ;; + *) # Default case: No more options, so break out of the loop. + break ;; + esac + shift +done + +## Next chunk is checks to see that variables are passed and match correct arguments etc. +[[ "${SERVERNUM}" == "" ]] && error "Error: A server number must be provided" +[[ "${SERVERNUM}" =~ [^0-9]+. ]] && error "Error: The argument for server must be a number" + +[[ "${STEAMUSER}" == "" ]] && error "Error: A steam user must be provided" + +[[ "${WORKSHOPID}" == "" ]] && error "Error: An argument for workshop-id must be provided" +[[ "${WORKSHOPID}" =~ [^0-9]+. ]] && error "Error: The argument for workshop-id must be a number" + +[[ "${MODNAME}" == "" ]] && error "Error: An argument for mod-name must be provided" + +[[ -d ~/Arma/Server-"${SERVERNUM}" ]] || error "Error: Arma Server ${SERVERNUM} does not exist!" + +# Converts the modname to lowercase as Arma 3 on linux requires lowercase mod directory names +MODNAME=$(echo "${MODNAME}" | tr '[:upper:]' '[:lower:]') + +# Checks if the modname has an @ symbol as the first character, if not we add it +[[ "${MODNAME}" =~ ^@ ]] || MODNAME="@${MODNAME}" + +# Create the mods directory if it doesn't exist +[[ -d ~/Arma/Server-"${SERVERNUM}"/mods ]] \ + || "$(mkdir ~/Arma/Server-"${SERVERNUM}"/mods && echo "Info: Created mods directory as it did not exist")" + +echo "Info: Downloading mod ${WORKSHOPID} as ${MODNAME}" +# Download the mod +steamcmd +login "${STEAMUSER}" +force_install_dir ~/Arma/Server-"${SERVERNUM}" +workshop_download_item 107410 "${WORKSHOPID}" +quit \ + && echo && echo "Info: Finished Downloading mod" + +# Finally install the mod into the mods directory +echo "Info: Installing the mod ${MODNAME}" +[[ -d "${HOME}/Arma/Server-${SERVERNUM}/mods/${MODNAME}" ]] && rm -rf "${HOME}/Arma/Server-${SERVERNUM}/mods/${MODNAME}" +[[ -d ~/Arma/Server-"${SERVERNUM}"/mods/"${MODNAME}" ]] \ + || mkdir -p ~/Arma/Server-"${SERVERNUM}"/mods/"${MODNAME}" \ + && echo "Info: Created the ${MODNAME} directory within mods" +mv "${HOME}/Arma/Server-${SERVERNUM}/steamapps/workshop/content/107410/${WORKSHOPID}"/* "${HOME}/Arma/Server-${SERVERNUM}/mods/${MODNAME}" +echo "Info: Successfully installed the mod ${MODNAME} (${WORKSHOPID}) to Server-${SERVERNUM}" diff --git a/CentOS/Arma/Mods/Parse-Arma-Modlist.py b/CentOS/Arma/Mods/Parse-Arma-Modlist.py new file mode 100644 index 0000000..420d511 --- /dev/null +++ b/CentOS/Arma/Mods/Parse-Arma-Modlist.py @@ -0,0 +1,89 @@ +import sys +import re +import subprocess + +from pathlib import Path +from bs4 import BeautifulSoup + +current_script = Path(__file__) + + +def show_help(): + print( + f"Usage:\n" + f" python[3] {current_script.parts[-1]} " + ) + + +def parse_html(html: str) -> list[list[str, int]]: + html = BeautifulSoup(html, "html.parser") + modlist = html.find("div", {"class": "mod-list"}) + table = modlist.find("table") + + mods = [] + for mod in table.findAll("tr"): + mod: BeautifulSoup + + mod_link = mod.find("a").get("href") + if not mod_link: + continue + mod_workshop_id = int(mod_link.split("id=")[-1]) + + mod_name: str = mod.find("td").contents[-1].casefold().strip() + mod_name = re.sub(r"[^a-zA-Z0-9]", "_", mod_name) + mods.append([mod_name, mod_workshop_id]) + return mods + + +def main(args: list[str]): + if args[1].casefold() == "--help" or args[1].casefold() == "-h": + show_help() + exit(0) + if len(args) != 4: + print( + f"Invalid number of arguments found, refer to help:\n" + f" python[3] {current_script.parts[-1]} --help" + ) + exit(1) + else: + path = Path(args[1]) + user = args[2].strip() + try: + server = int(args[3]) + except ValueError: + print("Server must be a number!") + exit(1) + + if not path.exists(): + print("Invalid path received:\n" + f" Received: \"{path.__str__()}\"") + exit(1) + elif not path.is_file(): + print("Expected a file, please use a path to a file") + exit(1) + else: + print(f"Installing all mods located in {path.parts[-1]} ({path.absolute()})") + with open(path) as f: + html = f.read() + mods = parse_html(html) + + for mod in mods: + command = f"Arma-Install-Mod -s {server} -w {mod[-1]} -m {mod[0]} -u {user}" + print(f"Executing: \"{command}\"") + result = subprocess.run( + command.split(" ") + ) + if result.returncode == 0: + continue + else: + print(f"The following command failed: \"{command}\"") + exit(result.returncode) + + print(f"Finished installing mods from: {path.parts[-1]} ({path.absolute()})") + + +if __name__ == "__main__": + try: + main(sys.argv) + except KeyboardInterrupt: + exit(0)