mirror of
https://github.com/greenseeker/t2server.git
synced 2026-01-19 19:24:46 +00:00
First Commit
This commit is contained in:
commit
8ffa4dacbd
10
etc/systemd/system/t2bouncer.service
Normal file
10
etc/systemd/system/t2bouncer.service
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[Unit]
|
||||
Description=t2bouncer (restarts t2server at configured time)
|
||||
Wants=t2bouncer.timer
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/bin/t2bouncer
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
10
etc/systemd/system/t2bouncer.timer
Normal file
10
etc/systemd/system/t2bouncer.timer
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[Unit]
|
||||
Description=t2bouncer timer
|
||||
BindsTo=t2server.service
|
||||
|
||||
[Timer]
|
||||
Unit=t2bouncer.service
|
||||
OnCalendar=*:00:00
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
36
etc/systemd/system/t2server.service
Normal file
36
etc/systemd/system/t2server.service
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
[Unit]
|
||||
Description=Tribes 2 Dedicated Server
|
||||
Requires=network.target
|
||||
After=network.target
|
||||
Wants=t2bouncer.timer
|
||||
Before=t2bouncer.timer
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Environment=TERM=xterm-256color
|
||||
Environment=PYTHONUNBUFFERED=1
|
||||
User=t2server
|
||||
CPUAffinity=0
|
||||
ExecStart=/usr/local/bin/t2server
|
||||
ExecStop=/usr/bin/wineserver -k
|
||||
Restart=on-failure
|
||||
RestartSec=15s
|
||||
TimeoutStopSec=60s
|
||||
WorkingDirectory=/opt/t2server/GameData
|
||||
LogsDirectory=t2server
|
||||
|
||||
# Below settings help lock down the service for security
|
||||
ProtectSystem=full
|
||||
ProtectHome=true
|
||||
SystemCallFilter=@system-service
|
||||
NoNewPrivileges=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectKernelModules=true
|
||||
ProtectKernelLogs=true
|
||||
ProtectControlGroups=true
|
||||
ProtectClock=true
|
||||
ProtectHostname=true
|
||||
PrivateTmp=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
44
etc/t2server/config.yaml
Normal file
44
etc/t2server/config.yaml
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
---
|
||||
## ServerPrefs indicates the server config file in /etc/t2server/serverprefs
|
||||
## to use. This is case-sensitive and must match the filename exactly.
|
||||
ServerPrefs: Classic_CTF.cs
|
||||
|
||||
## Tribes 2 servers tend to get unstable after a couple weeks of being online.
|
||||
## Here you can specify a day and hour to automatically bounce the server.
|
||||
## Set RestartTime to the hour of the day, 0-23, to cycle the server
|
||||
## (eg. 4=4:00am, 16=4:00pm) or False to disable. Set RestartDay to the
|
||||
## three-letter abbreviation of the day on which the server should be restarted
|
||||
## (Sun, Mon, Tue, Wed, Thu, Fri, or Sat). This will be ignored if
|
||||
## RestartTime = False.
|
||||
RestartTime: False
|
||||
RestartDay: Mon
|
||||
|
||||
## Set Mod to the directory name of the mod to be loaded, or 'base' for
|
||||
## vanilla (but why?). This is case-sensitive and must match the subdirectory
|
||||
## name exactly.
|
||||
Mod: Classic
|
||||
|
||||
## Set Public to False to host a LAN-only game, or to True to host a public
|
||||
## game which will be registered with the TribesNext master.
|
||||
Public: False
|
||||
|
||||
## Tribes 2 servers try to detect descrepencies between their own IP and the IP
|
||||
## that the client believes it's connecting to as possible man-in-the-middle
|
||||
## attacks, however this often interfers with connections when the server is
|
||||
## NATed or multi-homed. Enable OverrideMITM to effectively disable this
|
||||
## detection. This setting has no effect if Public = False.
|
||||
OverrideMITM: True
|
||||
|
||||
## Configure a custom map rotation list. The standard Mission Types are
|
||||
## "Bounty", "CnH" (Capture and Hold), "CTF" (Capture the Flag), "DM"
|
||||
## (Deathmatch), "DnD" (Defend and Destroy), "Hunters", "Rabbit", "Siege",
|
||||
## "TeamHunters", and "TeamRabbit". Your server will always launch with the
|
||||
## MissionType and Map specified in your serverprefs file ($Host::MissionType
|
||||
## and $Host::Map), so make sure MissionType matches $Host::MissionType and
|
||||
## the first map in MapList matches $Host::Map. If you're running a mod that
|
||||
## handles map rotation, set these to 'False'.
|
||||
## Example:
|
||||
## MissionType: CTF
|
||||
## MapList: ["Katabatic", "Minotaur", "Tombstone"]
|
||||
MissionType: False
|
||||
MapList: False
|
||||
52
etc/t2server/serverprefs/Classic_CTF.cs
Normal file
52
etc/t2server/serverprefs/Classic_CTF.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
$Host::AdminPassword = "changethis";
|
||||
$Host::allowAdminPlayerVotes = "0";
|
||||
$Host::AllowMapScript = 1;
|
||||
$Host::BanTime = 1800;
|
||||
$Host::BotCount = 7;
|
||||
$Host::BotsEnabled = "0";
|
||||
$Host::ClassicSuperAdminPassword = "changethis";
|
||||
$Host::CRCTextures = 0;
|
||||
$Host::FloodProtectionEnabled = 1;
|
||||
$Host::GameName = "Tribes 2 Classic CTF Server";
|
||||
$Host::HiVisibility = "1";
|
||||
$Host::holoName1 = "Storm";
|
||||
$Host::holoName2 = "Inferno";
|
||||
$Host::holoName3 = "Starwolf";
|
||||
$Host::holoName4 = "DSword";
|
||||
$Host::holoName5 = "BloodEagle";
|
||||
$Host::holoName6 = "Harbinger";
|
||||
$Host::Info = "This is a Tribes 2 Classic Server.";
|
||||
$Host::KickBanTime = 300;
|
||||
$Host::Map = "Minotaur";
|
||||
$Host::MarkDnDObjectives = 1;
|
||||
$Host::MaxMessageLen = 120;
|
||||
$Host::MaxPlayers = "64";
|
||||
$Host::MissionType = "CTF";
|
||||
$Host::NoSmurfs = 0;
|
||||
$Host::PlayerRespawnTimeout = "60";
|
||||
$Host::Port = "28000";
|
||||
$Host::PureServer = 0;
|
||||
$Host::TeamDamageOn = "1";
|
||||
$Host::TeamName0 = "Unassigned";
|
||||
$Host::TeamName1 = "Storm";
|
||||
$Host::TeamName2 = "Inferno";
|
||||
$Host::TeamName3 = "Starwolf";
|
||||
$Host::TeamName4 = "Diamond Sword";
|
||||
$Host::TeamName5 = "Blood Eagle";
|
||||
$Host::TeamName6 = "Phoenix";
|
||||
$Host::TeamSkin0 = "blank";
|
||||
$Host::TeamSkin1 = "base";
|
||||
$Host::TeamSkin2 = "baseb";
|
||||
$Host::TeamSkin3 = "swolf";
|
||||
$Host::TeamSkin4 = "dsword";
|
||||
$Host::TeamSkin5 = "beagle";
|
||||
$Host::TeamSkin6 = "cotp";
|
||||
$Host::TimeLimit = "200";
|
||||
$Host::TN::beat = 3;
|
||||
$Host::TN::echo = 1;
|
||||
$Host::TournamentMode = "0";
|
||||
$Host::UseHighPerformanceCounter = 0;
|
||||
$Host::VotePassPercent = "60";
|
||||
$Host::VoteSpread = 20;
|
||||
$Host::VoteTime = "30";
|
||||
$Host::warmupTime = "20";
|
||||
304
setup
Executable file
304
setup
Executable file
|
|
@ -0,0 +1,304 @@
|
|||
#!/usr/bin/env -S python3 -B
|
||||
from os import system, unlink, symlink, makedirs, geteuid, getcwd, chmod, rename
|
||||
from os.path import isfile, isdir
|
||||
from time import time
|
||||
from shutil import copyfile, rmtree
|
||||
from glob import iglob
|
||||
from pwd import getpwnam as getuser
|
||||
from t2support import *
|
||||
|
||||
if geteuid() != 0:
|
||||
bail(f"This script must be run with sudo or as root.\n")
|
||||
|
||||
pwd = getcwd()
|
||||
|
||||
installer_mirror_list = [
|
||||
"https://www.the-construct.net/downloads/tribes2/tribes2gsi.exe",
|
||||
"http://spinfusor.ch/tribes2/setup/tribes2_gsi.exe",
|
||||
"https://adamantis.keybase.pub/Abandonware/Tribes2/tribes2gsi.exe?dl=1",
|
||||
"http://xfer1.the-construct.net/tribes2/tribes2gsi.exe",
|
||||
"http://dl.rawr32.net/tribes2gsi.exe",
|
||||
"https://files.playt2.com/Install/tribes2gsi.exe",
|
||||
"https://gamestand.net/dl/tribes-2/?ind=1527034109041&filename=tribes2_gsi.exe&wpdmdl=165&refresh=5fb884009d78b1605927936",
|
||||
"http://www.tribes2stats.com/files/tribes2_gsi.exe"
|
||||
]
|
||||
|
||||
tnpatch_mirror_list = [
|
||||
"http://www.tribesnext.com/files/TribesNext_rc2a.exe",
|
||||
"https://keybase.pub/adamantis/Abandonware/Tribes2/TribesNext_rc2a.exe",
|
||||
"https://files.playt2.com/Install/TribesNext_rc2a.exe",
|
||||
"https://gamestand.net/dl/tribes-2/?ind=1527034087554&filename=TribesNext_rc2a.exe&wpdmdl=165&refresh=5fb884009d73d1605927936",
|
||||
"http://www.tribes2stats.com/files/patches/TribesNext_rc2a.exe",
|
||||
"http://files.nastyhobbit.org/t2-installer/TribesNext_rc2a.exe",
|
||||
"http://www.the-flet.com/dynamix/t2/TribesNext_rc2a.exe",
|
||||
"http://cdn.net-load.com/TribesNext_rc2a.exe",
|
||||
"https://starsiege.pw/_tribes2/TribesNext_rc2a.exe"
|
||||
]
|
||||
|
||||
installer_checksum = "93460541ddd3bdff9b30829ba04f2186"
|
||||
tnpatch_checksum = "3bec757215cd29b37d85b567edf8d693"
|
||||
|
||||
def md5sum(filename):
|
||||
""" Return the md5 checksum of the given file """
|
||||
with open(filename, "rb") as file:
|
||||
file_hash = md5()
|
||||
chunk = file.read(8192)
|
||||
while chunk:
|
||||
file_hash.update(chunk)
|
||||
chunk = file.read(8192)
|
||||
return file_hash.hexdigest()
|
||||
|
||||
def download_file(url, filename):
|
||||
""" Download url with progress meter and save to filename """
|
||||
req = get(url, stream=True)
|
||||
with open(filename, 'wb') as outfile:
|
||||
pbar = tqdm(total=int(req.headers['Content-Length']), unit="B", unit_scale=True, unit_divisor=1024, position=0, desc=filename.split("/")[-1])
|
||||
for chunk in req.iter_content(chunk_size=1024*1024):
|
||||
if chunk:
|
||||
pbar.update(len(chunk))
|
||||
outfile.write(chunk)
|
||||
pbar.close()
|
||||
return filename
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
action=menu(["~~[C]ontinue","[Q]uit"],header="This script will install Tribes 2 for use as a dedicated server.")
|
||||
if action == "Q": bail()
|
||||
|
||||
# Check if user exists
|
||||
try:
|
||||
user_info = getuser(user)
|
||||
except KeyError:
|
||||
user_info = False
|
||||
|
||||
# Create or repurpose user
|
||||
if user_info:
|
||||
if user_info.pw_dir == install_dir:
|
||||
pwarn(f"User '{user}' exists and will be reused.")
|
||||
else:
|
||||
bail(f"ERROR: User '{user}' already exists and may belong to another person or process.")
|
||||
else:
|
||||
pinfo(f"Creating {user} user and {install_dir}.")
|
||||
system(f"useradd -md {install_dir} {user}")
|
||||
|
||||
if not user_info: user_info = getuser(user)
|
||||
|
||||
# Create log_dir
|
||||
pinfo(f"Creating {log_dir}.")
|
||||
makedirs(log_dir, mode=0o777, exist_ok=True)
|
||||
chmod(log_dir, 0o777)
|
||||
|
||||
# Create .wine dir
|
||||
pinfo(f"Creating {install_dir}/.wine defaults.")
|
||||
system(f"su - {user} -c'wineboot -i > /dev/null 2>&1'")
|
||||
|
||||
# Map wine I: drive to pwd T: drive to install_dir and L: to log_dir
|
||||
pinfo(f"Mapping I: in wine for {user}.")
|
||||
try:
|
||||
symlink(f"{pwd}/winbin", f"{install_dir}/.wine/dosdevices/i:")
|
||||
except FileExistsError:
|
||||
pass
|
||||
|
||||
pinfo(f"Mapping L: in wine for {user}.")
|
||||
try:
|
||||
symlink(log_dir, f"{install_dir}/.wine/dosdevices/l:")
|
||||
except FileExistsError:
|
||||
pass
|
||||
|
||||
pinfo(f"Mapping T: in wine for {user}.")
|
||||
try:
|
||||
symlink(install_parent, f"{install_dir}/.wine/dosdevices/t:")
|
||||
except FileExistsError:
|
||||
pass
|
||||
|
||||
|
||||
# Check for needed exe/zip/dll files in winbin dir
|
||||
needed_files=[]
|
||||
if isfile(f"{pwd}/winbin/tribes2gsi.exe"):
|
||||
pinfo("tribes2gsi.exe found.")
|
||||
installer_exe = f"{pwd}/winbin/tribes2gsi.exe"
|
||||
elif isfile(f"{pwd}/winbin/tribes2_gsi.exe"):
|
||||
pinfo("tribes2_gsi.exe found.")
|
||||
installer_exe = f"{pwd}/winbin/tribes2_gsi.exe"
|
||||
else:
|
||||
pwarn("Tribes 2 installer not found.")
|
||||
needed_files.append("tribes2_gsi.exe")
|
||||
installer_exe = False
|
||||
|
||||
if isfile(f"{pwd}/winbin/TribesNext_rc2a.exe"):
|
||||
pinfo("TribesNext_rc2a.exe found.")
|
||||
tnpatch_exe = f"{pwd}/winbin/TribesNext_rc2a.exe"
|
||||
else:
|
||||
pwarn("Tribes Next patch not found.")
|
||||
needed_files.append("TribesNext_rc2a.exe")
|
||||
tnpatch_exe = False
|
||||
|
||||
ruby_dll = f"{pwd}/winbin/msvcrt-ruby191.dll"
|
||||
instwrap_exe = f"{pwd}/winbin/install_wrapper.exe"
|
||||
|
||||
# Download files if needed
|
||||
if not installer_exe or not tnpatch_exe:
|
||||
action=menu(["~~[D]ownload automatically","[Q]uit"],header="One or more needed files were not found. Download automatically or quit so they can be manually placed in the 'winbin' subdirectory?")
|
||||
if needed_files == 2:
|
||||
needed_files=f"{needed_files[0]} and {needed_files[1]}"
|
||||
if action=="Q": bail(f"Manually place {needed_files} in the 'winbin' subdirectory then rerun setup.")
|
||||
|
||||
if not installer_exe:
|
||||
for url in installer_mirror_list:
|
||||
try:
|
||||
pinfo(f"\nDownloading from {url.split('/')[2]}...")
|
||||
installer_exe = download_file(url, f"{pwd}/winbin/tribes2_gsi.exe")
|
||||
if md5sum(installer_exe) == installer_checksum:
|
||||
pinfo("Checksum validation passed.")
|
||||
break
|
||||
else:
|
||||
perror("Checksum validation failed. Trying next mirror.")
|
||||
except KeyError:
|
||||
perror("Download error. Trying next mirror.")
|
||||
continue
|
||||
|
||||
if not installer_exe:
|
||||
bail("ERROR: Tribes 2 installer could not be downloaded.")
|
||||
|
||||
if not tnpatch_exe:
|
||||
for url in tnpatch_mirror_list:
|
||||
try:
|
||||
pinfo(f"\nDownloading from {url.split('/')[2]}...")
|
||||
tnpatch_exe = download_file(url, f"{pwd}/winbin/TribesNext_rc2a.exe")
|
||||
if md5sum(tnpatch_exe) == tnpatch_checksum:
|
||||
pinfo("Checksum validation passed.")
|
||||
break
|
||||
else:
|
||||
perror("Checksum validation failed. Trying next mirror." )
|
||||
except KeyError:
|
||||
perror("Download error. Trying next mirror.")
|
||||
continue
|
||||
|
||||
if not tnpatch_exe:
|
||||
bail("ERROR: Tribes Next patch could not be downloaded.")
|
||||
|
||||
# Present SLAs before beginning install
|
||||
sla = None
|
||||
while not sla:
|
||||
sla=menu(["[V]iew Tribes 2 and TribesNext License Agreements", "[A]ccept License Agreements", "[Q]uit"], header="Please take a moment to review and accept the Tribes 2 and TribeNext License Agreements before beginning automated install.")
|
||||
if sla == "V":
|
||||
print(color.DY)
|
||||
system(f"/usr/bin/less {pwd}/sla/tribes2.txt")
|
||||
print(color.DP)
|
||||
system(f"/usr/bin/less {pwd}/sla/tribesnext.txt")
|
||||
sla = None
|
||||
elif sla == "A":
|
||||
break
|
||||
elif sla == "Q":
|
||||
bail("You must accept the License Agreements to install.")
|
||||
|
||||
# Ensure sufficient permissions on winbin and its contents
|
||||
chmod(f"{pwd}/winbin", 0o777)
|
||||
chmod(installer_exe, 0o777)
|
||||
chmod(tnpatch_exe, 0o777)
|
||||
chmod(instwrap_exe, 0o777)
|
||||
chmod(ruby_dll, 0o777)
|
||||
|
||||
# Execute install wrapper
|
||||
pinfo(f"\nInstalling Tribes 2 and the TribesNext patch in wine. Please wait...")
|
||||
chowner(install_dir, user)
|
||||
system(f"su - {user} -c'xvfb-run -as " + '"-fbdir /var/tmp"' + " wine I:/install_wrapper.exe > /dev/null 2>&1'")
|
||||
|
||||
# Rudamentary check to see if T2 install succeeded
|
||||
if not isfile(f"{install_dir}/Tribes 2 Solo & LAN.lnk"): bail(f"ERROR: Tribes 2 installation appears to have failed. Check {log_dir}/install_wrapper.log")
|
||||
|
||||
# Rudamentary check to see if TN install succeeded
|
||||
if not isfile(f"{install_dir}/GameData/TN_Uninstall.exe"): bail(f"ERROR: Tribes Next installation appears to have failed. Check {log_dir}/install_wrapper.log")
|
||||
|
||||
# Replace msvcrt-ruby190.dll with msvcrt-ruby191.dll
|
||||
pinfo("Updating msvcrt-ruby190.dll to msvcrt-ruby191.dll.\n")
|
||||
copyfile(ruby_dll,f"{install_dir}/GameData/msvcrt-ruby191.dll")
|
||||
unlink(f"{install_dir}/GameData/msvcrt-ruby190.dll")
|
||||
symlink(f"{install_dir}/GameData/msvcrt-ruby191.dll", f"{install_dir}/GameData/msvcrt-ruby190.dll")
|
||||
|
||||
# Install addons
|
||||
for addon in iglob(f"{pwd}/addons/*"):
|
||||
if addon.endswith(".zip"):
|
||||
pinfo(f"Unpacking {addon} into {install_dir}/GameData.")
|
||||
system(f"unzip -qqd {install_dir}/GameData {addon}")
|
||||
elif addon.endswith((".tar",".tgz",".tar.gz",".txz",".tar.xz",".tbz",".tar.bz")):
|
||||
pinfo(f"Unpacking {addon} into {install_dir}/GameData.")
|
||||
system(f"tar -C {install_dir}/GameData -xf {addon}")
|
||||
elif addon.endswith(".vl2"):
|
||||
pinfo(f"Copying {addon} to {install_dir}/GameData/base.")
|
||||
copyfile(addon,f"{install_dir}/GameData/base/{addon.split('/')[-1]}")
|
||||
elif addon.endswith("readme.txt"):
|
||||
pass
|
||||
else:
|
||||
pwarn(f"Ignoring {addon}.")
|
||||
|
||||
# Copy t2server and t2bouncer to /usr/local/bin/
|
||||
pinfo("Installing t2server script.")
|
||||
copyfile(f"{pwd}/usr/local/bin/t2server",f"{bin_dir}/t2server")
|
||||
pinfo("Installing t2bouncer script.")
|
||||
copyfile(f"{pwd}/usr/local/bin/t2bouncer",f"{bin_dir}/t2bouncer")
|
||||
|
||||
# Set owner/group on install_dir
|
||||
chowner(install_dir, user)
|
||||
|
||||
# Clean up temp dir and some unneeded files
|
||||
pinfo("A little housekeeping...")
|
||||
if isfile(f"{install_dir}/Tribes 2 Online.lnk"): unlink(f"{install_dir}/Tribes 2 Online.lnk")
|
||||
if isfile(f"{install_dir}/Tribes 2 Solo & LAN.lnk"): unlink(f"{install_dir}/Tribes 2 Solo & LAN.lnk")
|
||||
if isfile(f"{install_dir}/UNWISE.EXE"): unlink(f"{install_dir}/UNWISE.EXE")
|
||||
if isfile(f"{install_dir}/Readme.txt"): unlink(f"{install_dir}/Readme.txt")
|
||||
if isfile(f"{install_dir}/GameData/Classic_LAN.bat"): unlink(f"{install_dir}/GameData/Classic_LAN.bat")
|
||||
if isfile(f"{install_dir}/GameData/Classic_dedicated_server.bat"): unlink(f"{install_dir}/GameData/Classic_dedicated_server.bat")
|
||||
if isfile(f"{install_dir}/GameData/Classic_online.bat"): unlink(f"{install_dir}/GameData/Classic_online.bat")
|
||||
if isfile(f"{install_dir}/GameData/base/EULA.txt"): unlink(f"{install_dir}/GameData/base/EULA.txt")
|
||||
if isfile(f"{install_dir}/GameData/base/UKEULA.txt"): unlink(f"{install_dir}/GameData/base/UKEULA.txt")
|
||||
if isdir(f"{install_dir}/Manual"): rmtree(f"{install_dir}/Manual")
|
||||
if isdir(f"{install_dir}/.wine/drive_c/users/t2server/Temp"): rmtree(f"{install_dir}/.wine/drive_c/users/t2server/Temp")
|
||||
if isfile(f"{install_dir}/t2csri_eula.txt"): unlink(f"{install_dir}/t2csri_eula.txt")
|
||||
if isfile(f"{install_dir}/Inside\ Team\ Rabbit\ 2.txt"): unlink(f"{install_dir}/Inside\ Team\ Rabbit\ 2.txt")
|
||||
if isfile(f"{install_dir}/UpdatePatch.txt"): unlink(f"{install_dir}/UpdatePatch.txt")
|
||||
if isfile(f"{install_dir}/Classic/Classic_readme.txt"): unlink(f"{install_dir}/Classic/Classic_readme.txt")
|
||||
if isfile(f"{install_dir}/Classic_technical.txt"): unlink(f"{install_dir}/Classic_technical.txt")
|
||||
|
||||
# Create config directory and files
|
||||
pinfo(f"\nCreating {etc_dir}, default config, and installing prefs files.")
|
||||
makedirs(f"{etc_dir}/serverprefs", mode=0o775, exist_ok=True)
|
||||
if isfile(f"{etc_dir}/config.yaml"):
|
||||
timestamp = int(time())
|
||||
rename(f"{etc_dir}/config.yaml",f"{etc_dir}/config.yaml.{timestamp}")
|
||||
pwarn(f"Existing {etc_dir}/config.yaml renamed to {etc_dir}/config.yaml.{timestamp}. Be sure to compare with and update the new config.yaml file.")
|
||||
pinfo(f"Writing default {etc_dir}/config.yaml.")
|
||||
copyfile(f"{pwd}/etc/t2server/config.yaml", f"{etc_dir}/config.yaml")
|
||||
for pfile in iglob(f"{pwd}/etc/t2server/serverprefs/*"):
|
||||
pinfo(f"Copying {pfile} to {etc_dir}/serverprefs.")
|
||||
copyfile(pfile,f"{etc_dir}/serverprefs/{pfile.split('/')[-1]}")
|
||||
|
||||
# Create systemd units
|
||||
pinfo("\nCreating systemd units:")
|
||||
pinfo("- t2server service")
|
||||
copyfile(f"{pwd}/etc/systemd/system/t2server.service",f"{unit_dir}/t2server.service")
|
||||
pinfo("- t2bouncer service")
|
||||
copyfile(f"{pwd}/etc/systemd/system/t2bouncer.service",f"{unit_dir}/t2bouncer.service")
|
||||
pinfo("- t2bouncer timer")
|
||||
copyfile(f"{pwd}/etc/systemd/system/t2bouncer.timer",f"{unit_dir}/t2bouncer.timer")
|
||||
system("systemctl daemon-reload")
|
||||
|
||||
# Install utility scripts
|
||||
pinfo("\nInstalling utilities:")
|
||||
pinfo("- t2bouncer")
|
||||
copyfile(f"{pwd}/usr/local/bin/t2fixer",f"{bin_dir}/t2fixer")
|
||||
pinfo("- t2remove")
|
||||
copyfile(f"{pwd}/usr/local/bin/t2remove",f"{bin_dir}/t2remove")
|
||||
pinfo("- t2help")
|
||||
copyfile(f"{pwd}/usr/local/bin/t2help",f"{bin_dir}/t2help")
|
||||
|
||||
# Install python module
|
||||
copyfile(f"{pwd}/usr/local/bin/t2support.py",f"{bin_dir}/t2support.py")
|
||||
chmod(f"{bin_dir}/t2fixer",0o777)
|
||||
system(f"{bin_dir}/t2fixer")
|
||||
|
||||
# Show help
|
||||
system(f"{bin_dir}/t2help")
|
||||
menu(['~~[E]xit'],header="You can run 't2help' at any time to view the info above again.")
|
||||
|
||||
print(f"{color.X}\n")
|
||||
196
sla/tribes2.txt
Normal file
196
sla/tribes2.txt
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
_______ __ __ _______
|
||||
| |.----.|__|| |--..-----..-----. | |
|
||||
|.| | || _|| || _ || -__||__ --| |___| |
|
||||
`-|. |-'|__| |__||_____||_____||_____| / ___/
|
||||
|: | |: 1 \
|
||||
--------------- |::.| ------- License Agreement -------- |::.. . | -------------
|
||||
`---' `-------'
|
||||
|
||||
YOU SHOULD CAREFULLY READ THE FOLLOWING END USER LICENSE AGREEMENT BEFORE
|
||||
INSTALLING THIS SOFTWARE PROGRAM. BY INSTALLING OR OTHERWISE USING THE SOFTWARE
|
||||
PROGRAM, YOU AGREE TO BE BOUND BY THE TERMS OF THIS AGREEMENT. IF YOU DO NOT
|
||||
AGREE TO THE TERMS OF THIS AGREEMENT, PROMPTLY RETURN THE UNUSED SOFTWARE
|
||||
PROGRAM TO THE PLACE OF PURCHASE OR CONTACT SIERRA ON-LINE, INC. CUSTOMER
|
||||
SERVICE AT (425) 746-5771 FOR A FULL REFUND OF THE PURCHASE PRICE WITHIN 30 DAYS
|
||||
OF THE ORIGINAL PURCHASE.
|
||||
|
||||
This software program (the "Program"), any printed materials, any on-line or
|
||||
electronic documentation, and any and all copies and derivative works of such
|
||||
software program (including materials created with a so called level editor, if
|
||||
included) and materials are the copyrighted work of Sierra On-Line, Inc., a
|
||||
division of Havas Interactive, Inc. and/or its wholly owned subsidiaries, or its
|
||||
suppliers. All rights reserved, except as expressly stated herein. All use of
|
||||
the Program is governed by the terms of this End User License Agreement provided
|
||||
below ("License Agreement"). The Program is solely for use by end users
|
||||
according to the terms of the License Agreement. Any use, reproduction or
|
||||
redistribution of the Program not in accordance with the terms of the License
|
||||
Agreement is expressly prohibited.
|
||||
|
||||
END USER LICENSE AGREEMENT
|
||||
|
||||
1. Limited Use License. Sierra On-Line, Inc. ("Sierra ") hereby grants, and by
|
||||
installing the Program you thereby accept, a limited, non-exclusive license and
|
||||
right to install and use one (1) copy of the Program for your use on either a
|
||||
home, business or portable computer. In addition, the Program has a multi-player
|
||||
capability that allows users to utilize the Program over the Internet via
|
||||
Sierra's online game network Sierra.com. Use of the Program over Sierra.com is
|
||||
subject to your acceptance of Sierra.com's Terms of Use Agreement. Sierra
|
||||
On-Line, Inc. reserves the right to update, modify or change the Sierra.com
|
||||
Terms of Use Agreement at any time. The Program may also contain a Level Editor
|
||||
(the "Editor") that allows you to create custom levels or other materials for
|
||||
your personal use in connection with the Program ("New Materials"). All use of
|
||||
the Editor or any New Materials is subject to this License Agreement. The
|
||||
Program is licensed, not sold. Your license confers no title or ownership in the
|
||||
Program.
|
||||
|
||||
2. Ownership. All title, ownership rights and intellectual property rights in
|
||||
and to the Program and any and all copies thereof (including but not limited to
|
||||
any titles, computer code, themes, objects, characters, character names,
|
||||
stories, dialog, catch phrases, locations, concepts, artwork, animations,
|
||||
sounds, musical compositions, audio-visual effects, methods of operation, moral
|
||||
rights, any related documentation, and "applets" incorporated into the Program)
|
||||
are owned by Sierra On-Line, Inc. or its licensors. The Program is protected by
|
||||
the copyright laws of the United States, international copyright treaties and
|
||||
conventions and other laws. All rights are reserved. The Program contains
|
||||
certain licensed materials and Sierra 's licensors may protect their rights in
|
||||
the event of any violation of this Agreement.
|
||||
|
||||
3. Responsibilities of End User.
|
||||
A. Subject to the Grant of License hereinabove, you may not, in whole or in
|
||||
part, copy, photocopy, reproduce, translate, reverse engineer, derive source
|
||||
code, modify, disassemble, decompile, create derivative works based on the
|
||||
Program, or remove any proprietary notices or labels on the Program without
|
||||
the prior consent, in writing, of Sierra.
|
||||
B. The Program is licensed to you as a single product. Its component parts
|
||||
may not be separated for use on more than one computer.
|
||||
C. You are entitled to use the Program for your own use, but you are not
|
||||
entitled to:
|
||||
(i) sell, grant a security interest in or transfer reproductions of the
|
||||
Program to other parties in any way, nor to rent, lease or license the
|
||||
Program to others without the prior written consent of Sierra.
|
||||
(ii) exploit the Program or any of its parts for any commercial purpose
|
||||
including, but not limited to, use at a cyber café, computer gaming center
|
||||
or any other location-based site. Sierra may offer a separate Site License
|
||||
Agreement to permit you to make the Program available for commercial use;
|
||||
contact Sierra for details;
|
||||
(iii) host or provide matchmaking services for the Program or emulate or
|
||||
redirect the communication protocols used by Sierra in the network feature
|
||||
of the Program, through protocol emulation, tunneling, modifying or adding
|
||||
components to the Program, use of a utility program or any other
|
||||
techniques now known or hereafter developed, for any purpose including,
|
||||
but not limited to network play over the Internet, network play utilizing
|
||||
commercial or non-commercial gaming networks or as part of content
|
||||
aggregation networks without the prior written consent of Sierra ;
|
||||
(iv) create or maintain, under any circumstance, more than one
|
||||
simultaneous connection to Sierra.com. All such connections to Sierra.com,
|
||||
whether created by the Program or by other tools and utilities, may only
|
||||
be made through methods and means expressly approved by Sierra On-Line,
|
||||
Inc. Under no circumstances may you connect, or create tools that allow
|
||||
you to connect to Sierra.com's private binary interface or interfaces
|
||||
other than those explicitly provided by Sierra On-Line, Inc. for public
|
||||
use.
|
||||
|
||||
4. Program Transfer. You may permanently transfer all of your rights under this
|
||||
License Agreement, provided the recipient agrees to the terms of this License
|
||||
Agreement and you agree to remove the Program from your home or portable
|
||||
computer.
|
||||
|
||||
5. Termination. This License Agreement is effective until terminated. You may
|
||||
terminate the License Agreement at any time by destroying the Program. Sierra
|
||||
may, at its discretion, terminate this License Agreement in the event that you
|
||||
fail to comply with the terms and conditions contained herein. In such event,
|
||||
you must immediately destroy the Program.
|
||||
|
||||
6. Export Controls. The Program may not be re-exported, downloaded or otherwise
|
||||
exported into (or to a national or resident of) any country to which the U.S.
|
||||
has embargoed goods, or to anyone on the U.S. Treasury Department's list of
|
||||
Specially Designated Nationals or the U.S. Commerce Department's Table of Denial
|
||||
Orders. By installing the Program, you are agreeing to the foregoing and you are
|
||||
representing and warranting that you are not located in, under the control of,
|
||||
or a national or resident of any such country or on any such list.
|
||||
|
||||
7. Limited Warranty. Sierra expressly disclaims any warranty for the Program,
|
||||
Editor and Manual(s). The Program, Editor and Manual(s) are provided "as is"
|
||||
without warranty of any kind, either express or implied, including, without
|
||||
limitation, the implied warranties of merchantability, fitness for a particular
|
||||
purpose, or noninfringement. The entire risk arising out of use or performance
|
||||
of the Program and Manual(s) remains with the User, however Sierra warrants up
|
||||
to and including 90 days from the date of your purchase of the Program that the
|
||||
media containing the Program shall be free from defects in material and
|
||||
workmanship. In the event that the media proves to be defective during that time
|
||||
period, and upon presentation to Sierra of proof of purchase of the defective
|
||||
Program, Sierra will at its option 1) correct any defect, 2) provide you with a
|
||||
product of equal or lesser value, or 3) refund your money. Some states do not
|
||||
allow the exclusion or limitation of implied warranties or liability for
|
||||
incidental damages, so the above limitations may not apply to you.
|
||||
|
||||
8. Limitation of Liability. NEITHER SIERRA, HAVAS INTERACTIVE, INC., ITS PARENT,
|
||||
SUBSIDIARIES OR AFFILIATES SHALL BE LIABLE IN ANY WAY FOR LOSS OR DAMAGE OF ANY
|
||||
KIND RESULTING FROM THE USE OF THE PROGRAM OR USE OF SIERRA ON-LINE, INC.'S
|
||||
ONLINE GAME NETWORK, SIERRA.COM INCLUDING, BUT NOT LIMITED TO, LOSS OF
|
||||
GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
|
||||
COMMERCIAL DAMAGES OR LOSSES. SIERRA FURTHER DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO YEAR 2000 COMPLIANCE OF THE SOFTWARE. SPECIFICALLY, SIERRA MAKES NO
|
||||
WARRANTIES THAT THE PERFORMANCE OR FUNCTIONALITY OF THE PROGRAM WILL NOT BE
|
||||
AFFECTED BY DATES PRIOR TO, DURING OR AFTER THE YEAR 2000, OR THAT THE PROGRAM
|
||||
WILL BE CAPABLE OF CORRECTLY PROCESSING, PROVIDING, AND/OR RECEIVING DATE
|
||||
INFORMATION WITHIN AND BETWEEN CENTURIES, INCLUDING THE PROPER EXCHANGE OF DATE
|
||||
INFORMATION BETWEEN PRODUCTS OR APPLICATIONS. ANY WARRANTY AGAINST INFRINGEMENT
|
||||
THAT MAY BE PROVIDED IN SECTION 2-312(3) OF THE UNIFORM COMMERCIAL CODE AND/OR
|
||||
IN ANY OTHER COMPARABLE STATE STATUTE IS EXPRESSLY DISCLAIMED. FURTHER, Sierra
|
||||
On-Line, Inc. SHALL NOT BE LIABLE IN ANY WAY FOR THE LOSS OR DAMAGE TO PLAYER
|
||||
CHARACTERS, ACCOUNTS, STATISTICS OR USER PROFILE INFORMATION STORED ON
|
||||
SIERRA.COM. I UNDERSTAND AND ACKNOWLEDGE THAT SIERRA ON-LINE, INC. CANNOT AND
|
||||
WILL NOT BE RESPONSIBLE FOR ANY INTURUPTIONS OF SERVICE ON SIERRA.COM INCLUDING,
|
||||
BUT NOT LIMITED TO ISP DISRUPTIONS, SOFTWARE OR HARDWARE FAILURES OR ANY OTHER
|
||||
EVENT WHICH MAY RESULT IN A LOSS OF DATA OR DISRUPTION OF SERVICE. Some states
|
||||
do not allow the exclusion or limitation of incidental or consequential damages,
|
||||
or allow limitations on how long an implied warranty lasts, so the above
|
||||
limitations may not apply.
|
||||
|
||||
9. Equitable Remedies. You hereby agree that Sierra would be irreparably damaged
|
||||
if the terms of this License Agreement were not specifically enforced, and
|
||||
therefore you agree that Sierra shall be entitled, without bond, other security,
|
||||
or proof of damages, to appropriate equitable remedies with respect to breaches
|
||||
of this License Agreement, in addition to such other remedies as Sierra may
|
||||
otherwise have available to it under applicable laws. In the event any
|
||||
litigation is brought by either party in connection with this License Agreement,
|
||||
the prevailing party in such litigation shall be entitled to recover from the
|
||||
other party all the costs, attorneys' fees and other expenses incurred by such
|
||||
prevailing party in the litigation.
|
||||
|
||||
10. Limitations on License. Nothing in this License Agreement shall preclude
|
||||
you from making or authorizing the making of another copy or adaptation of the
|
||||
Program provided, however, that (1) such new copy or adaptation is created as an
|
||||
essential step in your utilization of the Program in accordance with the terms
|
||||
of this License Agreement and for NO OTHER PURPOSE; or (2) such new copy or
|
||||
adaptation is for archival purposes ONLY and all archival copies are destroyed
|
||||
in the event of your Transfer of the Program, the Termination of this Agreement
|
||||
or other circumstances under which your continued use of the Program ceases to
|
||||
be rightful.
|
||||
|
||||
11. Miscellaneous. This License Agreement shall be deemed to have been made and
|
||||
executed in the State of California and any dispute arising hereunder shall be
|
||||
resolved in accordance with the law of California. You agree that any claim
|
||||
asserted in any legal proceeding by one of the parties against the other shall
|
||||
be commenced and maintained in any state or federal court located in the State
|
||||
of California, County of Los Angeles, having subject matter jurisdiction with
|
||||
respect to the dispute between the parties. This License Agreement may be
|
||||
amended, altered or modified only by an instrument in writing, specifying such
|
||||
amendment, alteration or modification, executed by both parties. In the event
|
||||
that any provision of this License Agreement shall be held by a court or other
|
||||
tribunal of competent jurisdiction to be unenforceable, such provision will be
|
||||
enforced to the maximum extent permissible and the remaining portions of this
|
||||
License Agreement shall remain in full force and effect. This License Agreement
|
||||
constitutes and contains the entire agreement between the parties with respect
|
||||
to the subject matter hereof and supersedes any prior oral or written
|
||||
agreements.
|
||||
|
||||
I hereby acknowledge that I have read and understand the foregoing License
|
||||
Agreement and agree that the action of installing the Program is an
|
||||
acknowledgment of my agreement to be bound by the terms and conditions of the
|
||||
License Agreement contained herein. I also acknowledge and agree that this
|
||||
License Agreement is the complete and exclusive statement of the agreement
|
||||
between Sierra and I and that the License Agreement supersedes any prior or
|
||||
contemporaneous agreement, either oral or written, and any other communications
|
||||
between Sierra and myself.
|
||||
104
sla/tribesnext.txt
Normal file
104
sla/tribesnext.txt
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
_______ __ __ _______ _______ ___ ___ _______
|
||||
|_ _|.----.|__|| |--..-----..-----.| | || ___|| | ||_ _|
|
||||
| | | _|| || _ || -__||__ --|| || ___||- -| | |
|
||||
|___| |__| |__||_____||_____||_____||__|____||_______||___|___| |___|
|
||||
|
||||
----------------------------- License Agreement --------------------------------
|
||||
|
||||
YOU SHOULD CAREFULLY READ THE FOLLOWING LICENSE AGREEMENT BEFORE INSTALLING THIS
|
||||
SOFTWARE PROGRAM. BY INSTALLING OR OTHERWISE USING THE SOFTWARE PROGRAM, YOU
|
||||
AGREE TO BE BOUND BY THE TERMS OF THIS AGREEMENT. IF YOU DO NOT AGREE TO THE
|
||||
TERMS OF THIS AGREEMENT, PROMPTLY DELETE THE UNUSED SOFTWARE PROGRAM.
|
||||
|
||||
Definitions:
|
||||
1. "This software program" is defined as the integrated, machine readable,
|
||||
executable code, and application tools included as part of the TribesNext
|
||||
match making service.
|
||||
2. "Associated intepreted script code" is defined as the human readable,
|
||||
executable code, and all intermediate representations included as part of or
|
||||
generated during utilization of the TribesNext match making service.
|
||||
|
||||
This software program (the “Program”), associated interpreted script code, any
|
||||
on-line or electronic documentation, and any and all copies and derivative works
|
||||
of such software program are the copyrighted work of the TribesNext team, All
|
||||
rights reserved, except as expressly stated herein. All use of the Program is
|
||||
governed by the terms of this License Agreement provided below. The Program is
|
||||
solely for use by end users according to the terms of the License Agreement. Any
|
||||
use, reproduction or redistribution of the Program not in accordance with the
|
||||
terms of the License Agreement is expressly prohibited.
|
||||
|
||||
1. Ownership. All title, ownership rights and intellectual property rights in
|
||||
and to the Program and any and all copies thereof (including but not limited
|
||||
to any titles, computer code, objects, concepts, artwork, methods of
|
||||
operation, moral rights, any related documentation, and “applets”
|
||||
incorporated into the Program) are owned by the TribesNext team or its
|
||||
licensors. The Program is protected by the copyright laws of the United
|
||||
States, international copyright treaties and conventions and other laws. All
|
||||
rights are reserved. The Program contains certain licensed materials and
|
||||
TribesNext's licensors may protect their rights in the event of any violation
|
||||
of this Agreement.
|
||||
2. Termination. This License Agreement is effective until terminated. You may
|
||||
terminate the License Agreement at any time by destroying the Program.
|
||||
TribesNext may, at its discretion, terminate this License Agreement in the
|
||||
event that you fail to comply with the terms and conditions contained herein.
|
||||
In such event, you must immediately destroy the Program.
|
||||
3. Export Controls. The Program contains strong cryptography, thus the
|
||||
Program may not be re-exported, downloaded or otherwise exported into (or to
|
||||
a national or resident of) any country to which the U.S. has embargoed goods,
|
||||
or to anyone on the U.S. Treasury Department’s list of Specially Designated
|
||||
Nationals or the U.S. Commerce Department’s Table of Denial Orders. By
|
||||
installing the Program, you are agreeing to the foregoing and you are
|
||||
representing and warranting that you are not located in, under the control
|
||||
of, or a national or resident of any such country or on any such list.
|
||||
4. Limited Warranty. TribesNext expressly disclaims any warranty for the
|
||||
Program, components and any assorted documentation. The Program, components
|
||||
and any assorted documentation are provided "as is" without warranty of any
|
||||
kind, either express or implied, including, without limitation, the implied
|
||||
warranties of merchantability, fitness for a particular purpose, or
|
||||
noninfringement. The entire risk arising out of use or performance of the
|
||||
Program, components and any assorted documentation remains with the User.
|
||||
Some states do not allow the exclusion or limitation of implied warranties or
|
||||
liability for incidental damages, so the above limitations may not apply to
|
||||
you.
|
||||
5. Limitation of Liability. NEITHER TRIBESNEXT, SUBSIDIARIES OR AFFILIATES
|
||||
SHALL BE LIABLE IN ANY WAY FOR LOSS OR DAMAGE OF ANY KIND RESULTING FROM THE
|
||||
USE OF THE PROGRAM OR USE OF ASSOCIATED ONLINE SERVICES INCLUDING, BUT NOT
|
||||
LIMITED TO, LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION,
|
||||
OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES. TRIBESNEXT FURTHER
|
||||
DISCLAIMS ALL WARRANTIES WITH REGARD TO YEAR 2000 COMPLIANCE OF THE SOFTWARE.
|
||||
SPECIFICALLY, TRIBESNEXT MAKES NO WARRANTIES THAT THE PERFORMANCE OR
|
||||
FUNCTIONALITY OF THE PROGRAM WILL NOT BE AFFECTED BY DATES PRIOR TO, DURING
|
||||
OR AFTER THE YEAR 2000, OR THAT THE PROGRAM WILL BE CAPABLE OF CORRECTLY
|
||||
PROCESSING, PROVIDING, AND/OR RECEIVING DATE INFORMATION WITHIN AND BETWEEN
|
||||
CENTURIES, INCLUDING THE PROPER EXCHANGE OF DATE INFORMATION BETWEEN PRODUCTS
|
||||
OR APPLICATIONS. ANY WARRANTY AGAINST INFRINGEMENT THAT MAY BE PROVIDED IN
|
||||
SECTION 2-312(3) OF THE UNIFORM COMMERCIAL CODE AND/OR IN ANY OTHER
|
||||
COMPARABLE STATE STATUTE IS EXPRESSLY DISCLAIMED. FURTHER, TRIBESNEXT SHALL
|
||||
NOT BE LIABLE IN ANY WAY FOR THE LOSS OR DAMAGE TO PLAYER CHARACTERS,
|
||||
ACCOUNTS, STATISTICS OR USER PROFILE INFORMATION STORED ON TribesNext.com. I
|
||||
UNDERSTAND AND ACKNOWLEDGE THAT TRIBESNEXT. CANNOT AND WILL NOT BE
|
||||
RESPONSIBLE FOR ANY INTURUPTIONS OF SERVICE ON TRIBESNEXT.COM INCLUDING, BUT
|
||||
NOT LIMITED TO ISP DISRUPTIONS, SOFTWARE OR HARDWARE FAILURES OR ANY OTHER
|
||||
EVENT WHICH MAY RESULT IN A LOSS OF DATA OR DISRUPTION OF SERVICE. Some
|
||||
states do not allow the exclusion or limitation of incidental or
|
||||
consequential damages, or allow limitations on how long an implied warranty
|
||||
lasts, so the above limitations may not apply.
|
||||
6. Equitable Remedies. You hereby agree that TribesNext would be irreparably
|
||||
damaged if the terms of this License Agreement were not specifically
|
||||
enforced, and therefore you agree that TribesNext shall be entitled, without
|
||||
bond, other security, or proof of damages, to appropriate equitable remedies
|
||||
with respect to breaches of this License Agreement, in addition to such other
|
||||
remedies as TribesNext may otherwise have available to it under applicable
|
||||
laws. In the event any litigation is brought by either party in connection
|
||||
with this License Agreement, the prevailing party in such litigation shall be
|
||||
entitled to recover from the other party all the costs, attorneys’ fees and
|
||||
other expenses incurred by such prevailing party in the litigation.
|
||||
|
||||
I hereby acknowledge that I have read and understand the foregoing License
|
||||
Agreement and agree that the action of installing the Program is an
|
||||
acknowledgment of my agreement to be bound by the terms and conditions of the
|
||||
License Agreement contained herein. I also acknowledge and agree that this
|
||||
License Agreement is the complete and exclusive statement of the agreement
|
||||
between TribesNext and I and that the License Agreement supersedes any prior or
|
||||
contemporaneous agreement, either oral or written, and any other communications
|
||||
between TribesNext and myself
|
||||
1
t2support.py
Symbolic link
1
t2support.py
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
usr/local/bin/t2support.py
|
||||
31
usr/local/bin/t2bouncer
Executable file
31
usr/local/bin/t2bouncer
Executable file
|
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/env -S python3 -B
|
||||
import yaml
|
||||
from datetime import datetime
|
||||
from os import system
|
||||
from t2support import *
|
||||
|
||||
# Set default configuration
|
||||
config_defaults = {
|
||||
'RestartTime' : False,
|
||||
'RestartDay' : 'Mon',
|
||||
}
|
||||
|
||||
# Read configuration from config.yaml
|
||||
with open(f'{etc_dir}/config.yaml', 'r') as f:
|
||||
loaded_config = yaml.full_load(f)
|
||||
|
||||
# Merge config_defaults and loaded_config, with loaded_config taking precedence where there are conflicts.
|
||||
# This ensures there are no undefined values in the case of a user removing one from config.yaml.
|
||||
config = {**config_defaults, **loaded_config}
|
||||
|
||||
now=datetime.now()
|
||||
|
||||
if not config['RestartTime']:
|
||||
print("RestartTime is disabled.")
|
||||
|
||||
elif config['RestartTime'] > 0 and config['RestartTime'] < 25:
|
||||
if config['RestartTime'] == int(now.strftime('%H')) and config['RestartDay'][:3].upper() == now.strftime('%a').upper():
|
||||
print("RestartTime and RestartDay match current time and day. Restarting t2server.service.")
|
||||
system("/usr/bin/systemctl try-restart t2server.service")
|
||||
else:
|
||||
print("RestartTime and RestartDay do not match current time and day.")
|
||||
103
usr/local/bin/t2fixer
Executable file
103
usr/local/bin/t2fixer
Executable file
|
|
@ -0,0 +1,103 @@
|
|||
#!/usr/bin/env -S python3 -B
|
||||
from os import geteuid, chmod, walk
|
||||
from os.path import isdir, islink, join
|
||||
from shutil import chown
|
||||
from sys import exit as bail
|
||||
from t2support import *
|
||||
|
||||
if geteuid() != 0:
|
||||
bail("This script must be run with sudo or as root.\n")
|
||||
|
||||
def setperm(file):
|
||||
if islink(file):
|
||||
pass
|
||||
elif isdir(file):
|
||||
log.write(f"Setting mode 775 on directory {file}")
|
||||
try:
|
||||
chmod(file,0o775)
|
||||
log.write(f"\n")
|
||||
except:
|
||||
pwarn(f"Failed to set permissions on {file}")
|
||||
log.write(f"... FAILED!\n")
|
||||
pass
|
||||
elif file.endswith("t2support.py"):
|
||||
log.write(f"Setting mode 664 on file {file}")
|
||||
try:
|
||||
chmod(file,0o664)
|
||||
log.write(f"\n")
|
||||
except:
|
||||
pwarn(f"Failed to set permissions on {file}")
|
||||
log.write(f"... FAILED!\n")
|
||||
pass
|
||||
elif file.startswith(bin_dir):
|
||||
log.write(f"Setting mode 775 on script {file}")
|
||||
try:
|
||||
chmod(file,0o775)
|
||||
log.write(f"\n")
|
||||
except:
|
||||
pwarn(f"Failed to set permissions on {file}")
|
||||
log.write(f"... FAILED!\n")
|
||||
pass
|
||||
elif file.endswith(".exe"):
|
||||
log.write(f"Setting mode 775 on exe {file}")
|
||||
try:
|
||||
chmod(file,0o775)
|
||||
log.write(f"\n")
|
||||
except:
|
||||
pwarn(f"Failed to set permissions on {file}")
|
||||
log.write(f"... FAILED!\n")
|
||||
pass
|
||||
else:
|
||||
log.write(f"Setting mode 664 on file {file}")
|
||||
try:
|
||||
chmod(file,0o664)
|
||||
log.write(f"\n")
|
||||
except:
|
||||
pwarn(f"Failed to set permissions on {file}")
|
||||
log.write(f"... FAILED!\n")
|
||||
pass
|
||||
|
||||
if islink(file):
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
log.write(f"Setting owner/group on {file}")
|
||||
chown(file, "t2server", "t2server")
|
||||
log.write(f"\n")
|
||||
except:
|
||||
pwarn(f"Failed to set owner/group on {file}")
|
||||
log.write(f"... FAILED!\n")
|
||||
pass
|
||||
|
||||
|
||||
with open(f'{log_dir}/t2fixer.log', 'w') as log:
|
||||
setperm(install_dir)
|
||||
setperm(etc_dir)
|
||||
|
||||
for r, d, f in walk(f"{install_dir}/GameData"):
|
||||
for file in d:
|
||||
setperm(join(r, file))
|
||||
for file in f:
|
||||
setperm(join(r, file))
|
||||
|
||||
for r, d, f in walk(etc_dir):
|
||||
for file in d:
|
||||
setperm(join(r, file))
|
||||
for file in f:
|
||||
setperm(join(r, file))
|
||||
|
||||
for r, d, f in walk(log_dir):
|
||||
for file in d:
|
||||
setperm(join(r, file))
|
||||
for file in f:
|
||||
setperm(join(r, file))
|
||||
|
||||
setperm(f"{unit_dir}/t2server.service")
|
||||
setperm(f"{unit_dir}/t2bouncer.service")
|
||||
setperm(f"{unit_dir}/t2bouncer.timer")
|
||||
setperm(f"{bin_dir}/t2server")
|
||||
setperm(f"{bin_dir}/t2bouncer")
|
||||
setperm(f"{bin_dir}/t2remove")
|
||||
setperm(f"{bin_dir}/t2fixer")
|
||||
setperm(f"{bin_dir}/t2help")
|
||||
setperm(f"{bin_dir}/t2support.py")
|
||||
22
usr/local/bin/t2help
Executable file
22
usr/local/bin/t2help
Executable file
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env -S python3 -B
|
||||
from t2support import color
|
||||
|
||||
print(f"\n{color.DC}The follow commands can be used to manage your Tribes 2 server:")
|
||||
|
||||
print(f"""\n{color.BW}systemctl <action> t2server{color.DC}: The t2server service can be managed with the
|
||||
standard Linux systemctl command.""")
|
||||
|
||||
print(f"""\n{color.BW}t2fixer{color.DC}: This command resets the owner and permissions on all files associated
|
||||
with t2server. It's recommended to run this command any time you make changes
|
||||
or add files (such as mods or map packs) to your server to ensure they can be
|
||||
properly read and accessed. In the future, this command may also resolve other
|
||||
common issues.""")
|
||||
|
||||
print(f"""\n{color.BW}t2remove{color.DC}: This command uninstalls t2server and removes most associated files.
|
||||
Configuration and serverprefs files will be left alone.""")
|
||||
|
||||
print(f"\n{color.DC}Tribes 2 is installed in {color.BW}/opt/t2server{color.DC}.")
|
||||
print(f"{color.DC}The {color.BW}/etc/t2server/config.yaml{color.DC} file holds basic service configuration values.")
|
||||
print(f"{color.DC}The {color.BW}/etc/t2server/serverprefs{color.DC} directory holds your T2 serverprefs .cs files.")
|
||||
|
||||
print(color.X)
|
||||
64
usr/local/bin/t2remove
Executable file
64
usr/local/bin/t2remove
Executable file
|
|
@ -0,0 +1,64 @@
|
|||
#!/usr/bin/env -S python3 -B
|
||||
from os import system, unlink, geteuid
|
||||
from sys import argv
|
||||
from t2support import *
|
||||
|
||||
if geteuid() != 0:
|
||||
bail(f"This script must be run with sudo or as root.\n")
|
||||
|
||||
if menu(["[Y]es, remove Tribes 2", "~~[N]o, exit t2remove"],header=f"This script will remove Tribes 2, service files, and utilities. {etc_dir} will be left as it is.") == "N": bail()
|
||||
|
||||
system("/usr/bin/systemctl stop t2server.service")
|
||||
system("/usr/sbin/userdel -fr t2server > /dev/null 2>&1")
|
||||
system("/usr/sbin/groupdel t2server > /dev/null 2>&1")
|
||||
|
||||
systemd_delete_failed=0
|
||||
|
||||
try:
|
||||
unlink(f"{unit_dir}/t2bouncer.service")
|
||||
except:
|
||||
pwarn(f"Failed to delete {unit_dir}/t2bouncer.service")
|
||||
systemd_delete_failed+=1
|
||||
|
||||
try:
|
||||
unlink(f"{unit_dir}/t2bouncer.timer")
|
||||
except:
|
||||
pwarn(f"Failed to delete {unit_dir}/t2bouncer.timer")
|
||||
systemd_delete_failed+=1
|
||||
|
||||
try:
|
||||
unlink(f"{unit_dir}/t2server.service")
|
||||
except:
|
||||
pwarn(f"Failed to delete {unit_dir}/t2server.service")
|
||||
systemd_delete_failed+=1
|
||||
|
||||
|
||||
if systemd_delete_failed > 0:
|
||||
pinfo("After manually removing the files above, run 'systemctl daemon-reload' to refresh systemd.")
|
||||
else:
|
||||
system("/usr/bin/systemctl daemon-reload")
|
||||
|
||||
try:
|
||||
unlink(f"{bin_dir}/t2bouncer")
|
||||
except:
|
||||
pwarn(f"Failed to delete {bin_dir}/t2bouncer")
|
||||
|
||||
try:
|
||||
unlink(f"{bin_dir}/t2fixer")
|
||||
except:
|
||||
pwarn(f"Failed to delete {bin_dir}/t2fixer")
|
||||
|
||||
try:
|
||||
unlink(f"{bin_dir}/t2server")
|
||||
except:
|
||||
pwarn(f"Failed to delete {bin_dir}/t2server")
|
||||
|
||||
try:
|
||||
unlink(f"{bin_dir}/t2support.py")
|
||||
except:
|
||||
pwarn(f"Failed to delete {bin_dir}/t2support.py")
|
||||
|
||||
try:
|
||||
if argv[0].startswith(bin_dir): unlink(argv[0])
|
||||
except:
|
||||
pwarn(f"Failed to delete {argv[0]}")
|
||||
192
usr/local/bin/t2server
Executable file
192
usr/local/bin/t2server
Executable file
|
|
@ -0,0 +1,192 @@
|
|||
#!/usr/bin/env -S python3 -B
|
||||
import yaml
|
||||
from os import unlink, symlink, chdir, getppid, makedirs
|
||||
from os.path import isfile, islink, isdir, getmtime
|
||||
from re import match
|
||||
from glob import iglob
|
||||
from subprocess import run, PIPE
|
||||
from time import sleep
|
||||
from requests import get
|
||||
from threading import Thread
|
||||
from t2support import *
|
||||
|
||||
winecmd=["/usr/bin/wineconsole", "--backend=curses"]
|
||||
argbase=["Tribes2.exe","-dedicated"]
|
||||
basecmd=winecmd+argbase
|
||||
parent=getppid()
|
||||
|
||||
def dso_cleanup():
|
||||
"""
|
||||
This function finds all .dso files (compiled .cs scripts) and deletes them
|
||||
if they are older than their associated .cs script so that Tribes 2 will
|
||||
recompile them at startup.
|
||||
"""
|
||||
for dso_file in iglob(f"{install_dir}/**/*.dso", recursive=True):
|
||||
cs_file=dso_file[:-4]
|
||||
if isfile(cs_file):
|
||||
cs_mtime=getmtime(cs_file)
|
||||
dso_mtime=getmtime(dso_file)
|
||||
if cs_mtime > dso_mtime:
|
||||
print(f"Deleting {dso_file} so it can be rebuilt.")
|
||||
unlink(dso_file)
|
||||
|
||||
def build_args(basecmd,config):
|
||||
"""
|
||||
This function assembles the command line to launch the server based on the
|
||||
config.yaml file.
|
||||
"""
|
||||
server_command=basecmd
|
||||
if config['Public']:
|
||||
server_command.append("-online")
|
||||
else:
|
||||
server_command.append("-nologin")
|
||||
|
||||
if config['Mod'] != "base":
|
||||
server_command.extend(["-mod", config['Mod']])
|
||||
|
||||
if config['ServerPrefs']:
|
||||
server_command.extend(["-serverprefs","prefs\\ServerPrefs.cs"])
|
||||
|
||||
return server_command
|
||||
|
||||
def server_files(config):
|
||||
"""
|
||||
This function creates a symlink to the specified /etc/t2server/serverprefs
|
||||
file in the GameData/<mod>/prefs directory where Tribes 2 expects to find it.
|
||||
If MapList and MissionType are also configured, this funtion writes
|
||||
GameData/base/prefs/missions.txt with the appropriate values for the
|
||||
GameData/base/scripts/autoexec/missioncycle.cs script. If either MapList or
|
||||
MissionType is False, an empty missions.txt is written.
|
||||
"""
|
||||
if config['ServerPrefs']:
|
||||
if isfile(f"{install_dir}/GameData/{config['Mod']}/prefs/ServerPrefs.cs") or islink(f"{install_dir}/GameData/{config['Mod']}/prefs/ServerPrefs.cs"):
|
||||
print(f"Deleting {install_dir}/GameData/{config['Mod']}/prefs/ServerPrefs.cs")
|
||||
unlink(f"{install_dir}/GameData/{config['Mod']}/prefs/ServerPrefs.cs")
|
||||
print(f"Linking {install_dir}/GameData/{config['Mod']}/prefs/ServerPrefs.cs -> {etc_dir}/serverprefs/{config['ServerPrefs']}")
|
||||
makedirs(f"{install_dir}/GameData/{config['Mod']}/prefs", mode=0o755, exist_ok=True)
|
||||
symlink(f"{etc_dir}/serverprefs/{config['ServerPrefs']}", f"{install_dir}/GameData/{config['Mod']}/prefs/ServerPrefs.cs")
|
||||
|
||||
if config["MapList"] and config["MissionType"]:
|
||||
print(f"Writing {install_dir}/GameData/base/prefs/missions.txt")
|
||||
makedirs(f"{install_dir}/GameData/base/prefs", mode=0o755, exist_ok=True)
|
||||
with open(f"{install_dir}/GameData/base/prefs/missions.txt", 'w') as mlist:
|
||||
for mission in config["MapList"]:
|
||||
mlist.write(f"{config['MissionType']} {mission}\n")
|
||||
else:
|
||||
if isfile(f"{install_dir}/GameData/base/prefs/missions.txt"):
|
||||
print(f"Purging {install_dir}/GameData/base/prefs/missions.txt")
|
||||
# missions.txt needs to exist or the missioncycle.cs script will hang, so overwrite with an empty file
|
||||
open(f"{install_dir}/GameData/base/prefs/missions.txt", 'w').close()
|
||||
|
||||
|
||||
def runaway_control():
|
||||
"""
|
||||
When run in the background, wine will spawn a 'wineconsole --use-event=52'
|
||||
process that will consume all available CPU. This function finds that
|
||||
process and uses cpulimit to keep it under control.
|
||||
"""
|
||||
for x in range(20):
|
||||
sleep(15)
|
||||
print("Checking for runaway wineconsole process...")
|
||||
runaway_pid=run(["/usr/bin/pgrep","-f","wineconsole --use-event=52"],stdout=PIPE).stdout
|
||||
if runaway_pid:
|
||||
runaway_pid=str(int(runaway_pid))
|
||||
print(f"Limiting runaway wineconsole process: {runaway_pid}")
|
||||
run(["/usr/bin/cpulimit","-bp",runaway_pid,"-l2"])
|
||||
break
|
||||
|
||||
def master_heartbeat():
|
||||
"""
|
||||
A public Tribes 2 server should send a regular heartbeat to the TribexNext
|
||||
master server so that it appears in the list, however this seems
|
||||
inconsistent, so this function takes over that responsibility.
|
||||
"""
|
||||
print("Starting TribesNext heartbeat thread...")
|
||||
while True:
|
||||
get('http://master.tribesnext.com/add/28000')
|
||||
sleep(240)
|
||||
|
||||
def is_valid_ip(ip):
|
||||
"""Check if an ip looks like a valid IP address."""
|
||||
return bool(match(r"^(\d{1,3}\.){3}\d{1,3}$", ip))
|
||||
|
||||
def override_mitm():
|
||||
"""
|
||||
Tribes 2 servers try to detect descrepencies between their own IP and the IP
|
||||
that the client believes it's connecting to as possible man-in-the-middle
|
||||
attacks, however this often interfers with connections when the server is
|
||||
NATed or multi-homed. This function gets the public-facing IP of the host
|
||||
and writes an autoexec script to effectively disable this detection.
|
||||
"""
|
||||
for ip_service in ["http://api.ipify.org","http://ifconfig.me","http://ipinfo.io/ip"]:
|
||||
r=get(ip_service)
|
||||
if r.status_code == 200 and is_valid_ip(r.text):
|
||||
print(f"Got public IP address {r.text}")
|
||||
break
|
||||
if r.status_code != 200: bail("Could not get this server's public IP address.")
|
||||
print(f"Overriding Man-in-the-Middle attack detection.")
|
||||
with open(f'{install_dir}/GameData/base/scripts/autoexec/noMITM.cs', 'w') as nomitm_script:
|
||||
nomitm_script.write(f'$IPv4::InetAddress = "{r.text}";\n')
|
||||
|
||||
if __name__ == "__main__":
|
||||
# If run interactively, warn user that they probably don't want to do this unless troubleshooting.
|
||||
if parent == 1:
|
||||
print(f"Started by init")
|
||||
else:
|
||||
interactive_run=menu(['[Y]es, run t2server interactively.',"~~[N]o, abort."],header="Running t2server directly can be helpful for troubleshooting but generally it's best to manage your server with 'systemctl'. Do you still want to run t2server?",footer="Choose [N] and run 't2help' if you're unsure of what to do.")
|
||||
if interactive_run == 'N': bail()
|
||||
chdir(f"{install_dir}/GameData")
|
||||
|
||||
# Set default configuration
|
||||
config_defaults = {
|
||||
'ServerPrefs' : 'Classic_CTF.cs',
|
||||
'Mod' : 'Classic',
|
||||
'Public' : False,
|
||||
'OverrideMITM': True,
|
||||
'MissionType' : 'CTF',
|
||||
'MapList' : False
|
||||
}
|
||||
|
||||
# Read configuration from config.yaml
|
||||
with open(f'{etc_dir}/config.yaml', 'r') as f:
|
||||
loaded_config = yaml.full_load(f)
|
||||
|
||||
# Merge config_defaults and loaded_config, with loaded_config taking precedence where there are conflicts.
|
||||
# This ensures there are no undefined values in the case of a user removing one from config.yaml.
|
||||
config = {**config_defaults, **loaded_config}
|
||||
print(config)
|
||||
|
||||
# Validate the mod directory and serverprefs file
|
||||
if not isdir(f"{install_dir}/GameData/{config['Mod']}"):
|
||||
bail(f"Invalid Mod directory: {config['Mod']}")
|
||||
if not isfile(f"{etc_dir}/serverprefs/{config['ServerPrefs']}"):
|
||||
bail(f"Invalid ServerPrefs file: {config['ServerPrefs']}")
|
||||
|
||||
# Delete any pre-existing noMITM script/dso. It will be recreated below, if needed.
|
||||
if isfile(f"{install_dir}/GameData/base/scripts/autoexec/noMITM.cs"): unlink(f"{install_dir}/GameData/base/scripts/autoexec/noMITM.cs")
|
||||
if isfile(f"{install_dir}/GameData/base/scripts/autoexec/noMITM.cs.dso"): unlink(f"{install_dir}/GameData/base/scripts/autoexec/noMITM.cs.dso")
|
||||
|
||||
# Create serverprefs symlink and missions.txt (if appropriate), clean out stale dso files, then assemble the command line arguments to launch the server
|
||||
server_files(config)
|
||||
dso_cleanup()
|
||||
server_command=build_args(basecmd,config)
|
||||
|
||||
# If this is a public server, start a hearbeat thread. Also write the MITM override file if configured.
|
||||
if config['Public']:
|
||||
print("Starting heartbeat...")
|
||||
if config['OverrideMITM']: override_mitm()
|
||||
heartbeat=Thread(target=master_heartbeat)
|
||||
heartbeat.daemon=True
|
||||
heartbeat.start()
|
||||
|
||||
# Cap the CPU of the runaway wineconsole process
|
||||
wcpid_limit=Thread(target=runaway_control)
|
||||
wcpid_limit.start()
|
||||
|
||||
# Open the console log file if running as service and start the Tribes 2 server
|
||||
print(f"Starting Tribes 2 server: " + " ".join(server_command))
|
||||
if parent == 1:
|
||||
with open(f"{log_dir}/console.log", 'w') as consolelog:
|
||||
run(server_command,stdout=consolelog)
|
||||
else:
|
||||
run(server_command)
|
||||
132
usr/local/bin/t2support.py
Normal file
132
usr/local/bin/t2support.py
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
from tqdm import tqdm
|
||||
from re import search
|
||||
from requests import get
|
||||
from hashlib import md5
|
||||
from os import walk
|
||||
from os.path import join, islink
|
||||
from shutil import chown
|
||||
from sys import exit
|
||||
from textwrap import wrap
|
||||
from itertools import chain
|
||||
|
||||
user = "t2server"
|
||||
install_parent = "/opt"
|
||||
install_dir = f"{install_parent}/t2server"
|
||||
etc_dir = "/etc/t2server"
|
||||
log_dir = "/var/log/t2server"
|
||||
unit_dir = "/etc/systemd/system"
|
||||
bin_dir = "/usr/local/bin"
|
||||
|
||||
class color:
|
||||
X = '\033[m' # Reset
|
||||
DR = '\033[31m' # Dark Red
|
||||
DG = '\033[32m' # Dark Green
|
||||
DY = '\033[33m' # Dark Yellow (Brown)
|
||||
DU = '\033[34m' # Dark Blue
|
||||
DP = '\033[35m' # Dark Purple
|
||||
DC = '\033[36m' # Dark Cyan
|
||||
DW = '\033[37m' # Dark White (light grey)
|
||||
BK = '\033[90m' # Bright Black (dark grey)
|
||||
BR = '\033[91m' # Bright Red
|
||||
BG = '\033[92m' # Bright Green
|
||||
BY = '\033[93m' # Bright Yellow
|
||||
BU = '\033[94m' # Bright Blue
|
||||
BP = '\033[95m' # Bright Purple
|
||||
BC = '\033[96m' # Bright Cyan
|
||||
BW = '\033[97m' # Bright White
|
||||
|
||||
class box:
|
||||
TR = u'\u2510'
|
||||
TL = u'\u250c'
|
||||
BR = u'\u2518'
|
||||
BL = u'\u2514'
|
||||
H = u'\u2500'
|
||||
V = u'\u2502'
|
||||
|
||||
def menu(option_list,header="",footer=""):
|
||||
"""
|
||||
This function takes a list of options and make a BBS-style menu out of them.
|
||||
Each item should have a unique alphanum in square brackets (eg. "[Q]uit" or "[1] Quit")
|
||||
that represents the letter the user will type to select that option. Additionally, one
|
||||
option may start with ~~ to indicate that it is the default option. This option will be
|
||||
selected if the user presses Enter without typing a letter. ~~ will not be displayed on
|
||||
screen. The function returns the selected letter in uppercase.
|
||||
"""
|
||||
default=None
|
||||
keys=[]
|
||||
line_list=list(option_list)
|
||||
|
||||
if header:
|
||||
header_list = wrap(header,width=76)
|
||||
line_list.extend(header_list)
|
||||
else:
|
||||
header_list = None
|
||||
|
||||
if footer:
|
||||
footer_list = wrap(footer,width=76)
|
||||
line_list.extend(footer_list)
|
||||
else:
|
||||
footer_list = None
|
||||
|
||||
longest = max(list(chain((len(ele) for ele in line_list),[40])))
|
||||
|
||||
print(f"{color.BG}{box.TL}{box.H}{''.ljust(longest,box.H)}{box.H}{box.TR}{color.X}")
|
||||
print(f"{color.BG}{box.V} {''.ljust(longest)} {color.DG}{box.V}{color.X}")
|
||||
if header_list:
|
||||
for line in header_list:
|
||||
print(f"{color.BG}{box.V} {color.DG}{line.ljust(longest)} {box.V}{color.X}")
|
||||
print(f"{color.BG}{box.V} {''.ljust(longest)} {color.DG}{box.V}{color.X}")
|
||||
for option in option_list:
|
||||
try:
|
||||
key=search(r'\[([0-9a-zA-Z])\]', option).group(1)
|
||||
except AttributeError:
|
||||
pass
|
||||
if option.startswith("~~"):
|
||||
default = str(key)
|
||||
keys.append(key.upper())
|
||||
option=option[2:]
|
||||
else:
|
||||
keys.append(str(key).lower())
|
||||
option=option.ljust(longest)
|
||||
option=option.replace("[", color.BG + "[" + color.BW)
|
||||
option=option.replace("]", color.BG + "]" + color.DG)
|
||||
option=color.DG + option + color.X
|
||||
print(f"{color.BG}{box.V} {option.ljust(longest)} {color.DG}{box.V}{color.X}")
|
||||
if footer_list:
|
||||
print(f"{color.BG}{box.V} {''.ljust(longest)} {color.DG}{box.V}{color.X}")
|
||||
for line in footer_list:
|
||||
print(f"{color.BG}{box.V} {color.DG}{line.ljust(longest)} {box.V}{color.X}")
|
||||
print(f"{color.BG}{box.V} {''.ljust(longest)} {color.DG}{box.V}{color.X}")
|
||||
print(f"{color.BG}{box.BL}{color.DG}{box.H}{''.ljust(longest,box.H)}{box.H}{box.BR}{color.X}")
|
||||
menu_choice=" "
|
||||
if default:
|
||||
prompt=f"{color.DG}Choice {color.BK}({color.BG}{default}{color.BK}){color.DG}: {color.X}"
|
||||
else:
|
||||
prompt=f"{color.DG}Choice: {color.X}"
|
||||
while menu_choice.upper() not in [x.upper() for x in keys]:
|
||||
menu_choice = str(input(prompt))
|
||||
if default and menu_choice == "": menu_choice = default
|
||||
return menu_choice.upper()
|
||||
|
||||
def chowner(path, owner):
|
||||
""" Recursively chown path with owner as both user and group """
|
||||
for dirpath, ignore, filenames in walk(path):
|
||||
chown(dirpath, owner, owner)
|
||||
for filename in filenames:
|
||||
if not islink(join(dirpath, filename)):
|
||||
chown(join(dirpath, filename), owner, owner)
|
||||
|
||||
def pinfo(message):
|
||||
print(color.BU + message + color.X)
|
||||
|
||||
def pwarn(message):
|
||||
print(color.BY + message + color.X)
|
||||
|
||||
def perror(message):
|
||||
print(color.BR + message + color.X)
|
||||
|
||||
def bail(message=""):
|
||||
exit(color.BR + message + color.X)
|
||||
|
||||
if __name__ == "__main__":
|
||||
bail("This file contains only shared functions and variables for the other scripts and is not meant to be run interactively.")
|
||||
82
winbin/install_wrapper.au3
Normal file
82
winbin/install_wrapper.au3
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
; Define a logging function
|
||||
Func WriteLog($ErrorMessage)
|
||||
FileWriteLine("L:\install_wrapper.log", @MON & "/" & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC & " " & $ErrorMessage)
|
||||
EndFunc
|
||||
|
||||
WriteLog("--- Starting script ---")
|
||||
|
||||
; Run the Tribes 2 installer
|
||||
WriteLog("Launching tribes2_gsi.exe: " & Run("I:\tribes2_gsi.exe"))
|
||||
|
||||
; SLA
|
||||
WriteLog("Wait for SLA window: " & WinWait("Software License Agreement", "Please read through the entire license agreement", 60))
|
||||
WriteLog("Click [I Agree]: " & ControlClick("Software License Agreement", "Please read through the entire license agreement", 4)) ; click I Agree
|
||||
|
||||
; Welcome window
|
||||
WriteLog("Wait for Welcome window: " & WinWait("Tribes 2", "Welcome to the Tribes 2 Installation!", 60))
|
||||
WriteLog("Click [Skip]: " & ControlClick("Tribes 2", "Welcome to the Tribes 2 Installation!", 4)) ; click "Skip >"
|
||||
|
||||
; Tribes Vengeance preorder
|
||||
WriteLog("Wait for Tribes Vengeance Preorder window: " & WinWait("Tribes: Vengeance", "Click here to Pre-order Tribes: Vengeance Now!", 60))
|
||||
WriteLog("Click [Next]: " & ControlClick("Tribes: Vengeance", "Click here to Pre-order Tribes: Vengeance Now!", 5)) ; click "Next >"
|
||||
|
||||
; Welcome 2
|
||||
WriteLog("Wait for Welcome: " & WinWait("Welcome", "Welcome to the Tribes 2 Setup program", 60))
|
||||
WriteLog("Click [Next]: " & ControlClick("Welcome", "Welcome to the Tribes 2 Setup program", 3)) ; click "Next >"
|
||||
|
||||
; Credits
|
||||
WriteLog("Wait for Credits window: " & WinWait("Credits", "It's not often that the community of a game", 60))
|
||||
WriteLog("Click [Next]: " & ControlClick("Credits", "It's not often that the community of a game", 3)) ; click "Next >"
|
||||
|
||||
; Choose Destination Location
|
||||
WriteLog("Wait for Choose Destination window: " & WinWait("Choose Destination Location", "Setup will install Tribes 2 in the following folder.", 60))
|
||||
WriteLog("Click [Browse]: " & ControlClick("Choose Destination Location", "Setup will install Tribes 2 in the following folder.", 9)) ; click "Browse"
|
||||
WriteLog("Wait for Browse window: " & WinWait("Select Destination Directory", "", 60))
|
||||
WriteLog("Type 'T:\t2server': " & ControlSend("Select Destination Directory", "", 3, "T:\t2server")) ; update the destination path
|
||||
WriteLog("Click [OK]: " & ControlClick("Select Destination Directory", "", 7)) ; click OK
|
||||
WriteLog("Click [Yes] to use existing directory: " & ControlClick("Install", "The directory T:\t2server already exists", 1)) ; T:\t2server already exists, install anyway
|
||||
WriteLog("Click [Next]: " & ControlClick("Choose Destination Location", "Setup will install Tribes 2 in the following folder.", 3)) ; click "Next >"
|
||||
|
||||
; Select Program Manager Group
|
||||
WriteLog("Wait for Start Menu Group window: " & WinWait("Select Program Manager Group", "Enter the name of the Program Manager group to add Tribes 2 icons to:", 60))
|
||||
WriteLog("Click [Next]: " & ControlClick("Select Program Manager Group", "Enter the name of the Program Manager group to add Tribes 2 icons to:", 3)) ; click "Next >"
|
||||
|
||||
; Start Installation
|
||||
WriteLog("Wait for Start Installation window: " & WinWait("Start Installation", "You are now ready to install Tribes 2.", 60))
|
||||
WriteLog("Click [Next]: " & ControlClick("Start Installation", "You are now ready to install Tribes 2.", 3)) ; click "Next >"
|
||||
|
||||
; Register
|
||||
WriteLog("Wait for Register window: " & WinWait("Register", "You can register Tribes 2 on the World Wide Web.", 60))
|
||||
WriteLog("Uncheck 'Register Tribes 2 Now': " & ControlClick("Register", "You can register Tribes 2 on the World Wide Web.", 9)) ; uncheck "Register Tribes 2 Now"
|
||||
WriteLog("Click [Next]: " & ControlClick("Register", "You can register Tribes 2 on the World Wide Web.", 3)) ; click "Next >"
|
||||
|
||||
; DirectX 8a
|
||||
WriteLog("Wait for DX8 Install window: " & WinWait("DirectX 8a", "DirectX 8a Install", 60))
|
||||
WriteLog("Uncheck 'Install DirectX 8a': " & ControlClick("DirectX 8a", "DirectX 8a Install", 9)) ; uncheck "Install DirectX 8a"
|
||||
WriteLog("Click [Next]: " & ControlClick("DirectX 8a", "DirectX 8a Install", 3)) ; click "Next >"
|
||||
|
||||
; Installation Complete
|
||||
WriteLog("Wait for Installation Complete window: " & WinWait("Installation Complete", "Tribes 2 has been successfully installed.", 60))
|
||||
WriteLog("Uncheck 'Open the Tribes 2 Readme': " & ControlClick("Installation Complete", "Tribes 2 has been successfully installed.", 9)) ; uncheck "Open the Tribes 2 Readme"
|
||||
WriteLog("Uncheck 'Launch Tribes 2': " & ControlClick("Installation Complete", "Tribes 2 has been successfully installed.", 10)) ; uncheck "Launch Tribes 2"
|
||||
WriteLog("Click [Next]: " & ControlClick("Installation Complete", "Tribes 2 has been successfully installed.", 3)) ; click "Next >"
|
||||
|
||||
; Wait up to a minute for the installer to complete and exit
|
||||
WriteLog("Wait for tribes2_gsi.exe to exit: " & ProcessWaitClose("tribes2_gsi.exe", 60))
|
||||
|
||||
; Run the TribesNext Patch
|
||||
WriteLog("Launching TribesNExt_rc2a.exe: " & Run("I:\TribesNext_rc2a.exe"))
|
||||
|
||||
; SLA
|
||||
WriteLog("Wait for License Agreement window: " & WinWait("TribesNext Patcher: License Agreement", "Please review the license agreement before installing", 60))
|
||||
WriteLog("Click [I Agree]: " & ControlClick("TribesNext Patcher: License Agreement", "Please review the license agreement before installing", 1)) ; click "I Agree"
|
||||
|
||||
; Installation Folder
|
||||
WriteLog("Wait for Completed window: " & WinWait("TribesNext Patcher: Installation Folder", "Setup will apply the TribesNext multiplayer patch", 60))
|
||||
WriteLog("Click [Apply Patch]: " & ControlClick("TribesNext Patcher: Installation Folder", "Setup will apply the TribesNext multiplayer patch", 1)) ; click "Apply Patch"
|
||||
|
||||
; Completed
|
||||
WriteLog("Wait for SLA window: " & WinWait("TribesNext Patcher: Completed", "Completed", 60))
|
||||
WriteLog("Click [Close]: " & ControlClick("TribesNext Patcher: Completed", "Completed", 1)) ; click "Close"
|
||||
|
||||
WriteLog("--- Script Complete ---")
|
||||
Loading…
Reference in a new issue