barotrauma-sunken-tapes/main.py

343 lines
11 KiB
Python
Raw Normal View History

2021-09-24 12:00:38 +02:00
import os
import tkinter as tk
from tkinter import filedialog as fd
from tkinter.messagebox import showinfo, askyesno, askokcancel
from tkinter import ttk
2021-10-10 23:48:38 +02:00
from tooltip import Hovertip
2021-09-24 12:00:38 +02:00
from pathlib import Path
from deploy import download_ffmpeg, download_git, deploy, get_ffmpeg_version, update
import logging
import sys
import re
import unicodedata
def slugify(value, allow_unicode=False):
"""
Taken from https://github.com/django/django/blob/master/django/utils/text.py
Convert to ASCII if 'allow_unicode' is False. Convert spaces or repeated
dashes to single dashes. Remove characters that aren't alphanumerics,
underscores, or hyphens. Convert to lowercase. Also strip leading and
trailing whitespace, dashes, and underscores.
"""
value = str(value)
if allow_unicode:
value = unicodedata.normalize('NFKC', value)
else:
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii')
value = re.sub(r'[^\w\s-]', '', value.lower())
return re.sub(r'[-\s]+', '-', value).strip('-_')
2021-09-24 12:00:38 +02:00
def get_curr_screen_geometry():
"""
Workaround to get the size of the current screen in a multi-screen setup.
Returns:
geometry (str): The standard Tk geometry string.
[width]x[height]+[left]+[top]
"""
root = tk.Tk()
root.update_idletasks()
root.attributes('-fullscreen', True)
root.state('iconic')
geometry = root.winfo_geometry()
root.destroy()
return geometry
def create_name_frame(container):
frame = ttk.LabelFrame(container, text='Mod Name')
# Override Workshop checkbox
override_workshop = tk.StringVar()
override_workshop.set("0")
override_workshop_check = ttk.Checkbutton(
frame,
variable=override_workshop,
text='Override Workshop',
command=lambda: override_action())
override_workshop_check.pack(side="left", padx=3, pady=3)
name = tk.StringVar()
name.set("Sunken Tapez")
name_entry = ttk.Entry(frame, width=30, textvariable=name)
name_entry.pack(side="left", padx=3, pady=3, expand=True, fill="x")
slug = tk.StringVar()
slug.set(slugify("Sunken Tapez"))
slug_entry = ttk.Entry(frame, width=30, textvariable=slug)
slug_entry["state"] = "disable"
slug_entry.pack(side="left", padx=3, pady=3, expand=True, fill="x")
Hovertip(override_workshop_check,
'Keep this unchecked to prevent Steam Workshop'
'\noverriding your custom installation.'
'\n\nIt exists only for the author\'s convenience.')
Hovertip(name_entry,
'Name of the deploy mod. You can customise this'
'\nif you want to create your own version.')
Hovertip(slug_entry,
'Slug of the deployed mod name that is'
'\nused for file paths and references.')
def update_slug(*args):
slug.set(slugify(name.get()))
name.trace("w", update_slug)
def override_action():
if override_workshop.get() == "1":
name.set("Sunken Tapes")
name_entry["state"] = "disable"
2021-10-28 12:03:58 +02:00
slug.set("sunken_tapes")
elif override_workshop.get() == "0":
name.set("Sunken Tapez")
name_entry["state"] = "normal"
return frame, name, slug
2021-09-24 12:00:38 +02:00
def create_install_frame(container):
def find_barotrauma_directory():
first_guess = Path("C:/Program Files (x86)/Steam/steamapps/common/Barotrauma")
second_guess = Path("D:/Steam/steamapps/common/Barotrauma")
if first_guess.is_dir():
return first_guess.as_posix()
elif second_guess.is_dir():
return second_guess.as_posix()
else:
return False
def select_barotrauma_directory():
return_dir = fd.askdirectory(initialdir="C:/")
install_dir.set(return_dir)
frame = ttk.LabelFrame(container, text='Barotrauma installation directory')
find_button = ttk.Button(frame, text='Guess',
command=lambda: install_dir.set(find_barotrauma_directory()))
find_button.pack(side="left", padx=3, pady=3)
install_dir = tk.StringVar()
install_dir.set(find_barotrauma_directory())
directory_entry = ttk.Entry(frame, width=60, textvariable=install_dir)
directory_entry.pack(side="left", padx=3, pady=3, expand=True, fill="x")
browse_button = ttk.Button(frame, text='Browse', command=select_barotrauma_directory)
browse_button.pack(side="left", padx=3, pady=3)
return frame, install_dir
def create_options_frame(container):
frame = ttk.LabelFrame(container, text='Options')
# Use ITA checkbox
use_ita = tk.StringVar()
2021-10-10 23:48:38 +02:00
use_ita.set("0")
2021-09-24 12:00:38 +02:00
use_ita_check = ttk.Checkbutton(
frame,
variable=use_ita,
text='Use ITA mod',
command=lambda: print(use_ita.get()))
# Buffs checkbox
buffs = tk.StringVar()
buffs.set("1")
buffs_check = ttk.Checkbutton(
frame,
variable=buffs,
text='Buffs',
command=lambda: print(buffs.get()))
2021-10-10 23:48:38 +02:00
Hovertip(use_ita_check,
'Check this box if you use Into The Abyss mod.'
'\nITA and Sunken Tapes override the same style file.')
Hovertip(buffs_check,
'Check this box to enable some songs causing strange effects'
'\nThis is the intended default behaviour.')
2021-09-24 12:00:38 +02:00
for widget in frame.winfo_children():
widget.pack(side="top", padx=3, pady=3, fill="x")
return frame, use_ita, buffs
2021-09-24 12:00:38 +02:00
def create_resolution_frame(container):
frame = ttk.LabelFrame(container, text='Resolution')
def detect_screen_resolution():
w, h = get_curr_screen_geometry().split("+")[0].split("x")
width.set(w)
height.set(h)
width = tk.StringVar()
width.set("1920")
width_label = ttk.Label(frame, text='Width:')
width_frame = ttk.Entry(frame, width=12, textvariable=width)
height = tk.StringVar()
height.set("1080")
height_label = ttk.Label(frame, text='Height:')
height_frame = ttk.Entry(frame, width=12, textvariable=height)
detect_button = ttk.Button(frame, text='Detect', command=detect_screen_resolution)
for widget in frame.winfo_children():
widget.pack(side="left", padx=3, pady=3)
return frame, width, height
def create_deploy_frame(container, config):
def deploy_action():
config_values = {"installdir": config["installdir"].get(),
"use_ita": config["use_ita"].get() == "1",
"buffs": config["buffs"].get() == "1",
"name": config["name"].get(),
"slug": config["slug"].get(),
2021-09-24 12:00:38 +02:00
"resolution_x": int(config["resolution_x"].get()),
"resolution_y": int(config["resolution_y"].get())}
2021-09-24 12:00:38 +02:00
logging.info(f"deploying with config: {config_values}")
deploy(config_values)
if config_values["name"] != "Sunken Tapes":
note = f'\n\nThis is a custom version and is named {config_values["name"]} to differentiate it from ' \
+ 'the Steam Workshop version that would overwrite it otherwise.' \
+ '\n\nPlease include a link to the original mod if you publish it to Steam Workshop.'
else:
note = ""
2021-09-24 12:00:38 +02:00
showinfo(title='Success!',
message=f'{config_values["name"]} was successfully installed to:'
f'\n\n{config_values["installdir"]}/Mods/{config_values["slug"]}'
f'\n\nThis installer will now close.'
f'{note}')
2021-09-24 12:00:38 +02:00
container.destroy()
def download_ffmpeg_action():
def finish():
does_ffmpeg_exists()
showinfo(title='Success!',
message=f'ffmpeg downloaded. You can now deploy Sunken Tapes:')
if not Path("./utils/ffmpeg-" + get_ffmpeg_version() + "-full_build/bin/ffmpeg.exe").exists():
download_ffmpeg()
finish()
return
else:
answer = askyesno(title='ffmpeg already downloaded',
message='ffmpeg is already in utils directory!'
'\n\nDelete the existing one and download again?')
if answer:
download_ffmpeg(clean=True)
finish()
else:
return
def update_action():
if not Path("./utils/git").exists():
answer = askokcancel(
title='Confirmation',
message='Portable version of git will be downloaded.'
'\nThis is needed to check for updates in the repository')
if answer:
download_git()
else:
return
else:
logging.info(f"git already in utils")
update()
def does_ffmpeg_exists():
if Path("./utils/ffmpeg-" + get_ffmpeg_version() + "-full_build/bin/ffmpeg.exe").exists():
deploy_button["state"] = "normal"
2021-11-14 21:27:38 +01:00
download_tools_button["state"] = "disable"
2021-09-24 12:00:38 +02:00
else:
deploy_button["state"] = "disable"
2021-11-14 21:27:38 +01:00
download_tools_button["state"] = "normal"
2021-09-24 12:00:38 +02:00
frame = ttk.LabelFrame(container, text='Install')
frame_1 = ttk.Frame(frame)
download_tools_label = ttk.Label(frame_1, text='Download and unpack ffmpeg:')
download_tools_label.pack(side="left", padx=3, pady=3)
download_tools_button = ttk.Button(frame_1, text='Download', command=download_ffmpeg_action)
download_tools_button.pack(side="right", padx=3, pady=3)
frame_1.pack(side="top", fill="x")
frame_2 = ttk.Frame(frame)
update_label = ttk.Label(frame_2, text='Download update from git.kompot.si/jaka/barotrauma-sunken-tapes:')
update_label.pack(side="left", padx=3, pady=3)
update_button = ttk.Button(frame_2, text='Update', command=update_action)
update_button.pack(side="right", padx=3, pady=3)
frame_2.pack(side="top", fill="x")
frame_3 = ttk.Frame(frame)
deploy_label = ttk.Label(frame_3, text='Download songs and deploy mod to Barotrauma Mods directory:')
deploy_label.pack(side="left", padx=3, pady=3)
deploy_button = ttk.Button(frame_3, text='Deploy', command=deploy_action)
deploy_button.pack(side="right", padx=3, pady=3)
frame_3.pack(side="top", fill="x")
does_ffmpeg_exists()
return frame
def create_main_window():
# root window
root = tk.Tk()
root.title('Sunken Tapes')
middle_frame = ttk.Frame(root)
name_frame, name, slug = create_name_frame(root)
2021-09-24 12:00:38 +02:00
install_frame, install_dir = create_install_frame(root)
options_frame, use_ita, buffs = create_options_frame(middle_frame)
2021-09-24 12:00:38 +02:00
resolution_frame, width, height = create_resolution_frame(middle_frame)
config = {"installdir": install_dir,
"use_ita": use_ita,
"buffs": buffs,
"name": name,
"slug": slug,
2021-09-24 12:00:38 +02:00
"resolution_x": width,
"resolution_y": height}
2021-09-24 12:00:38 +02:00
deploy_frame = create_deploy_frame(root, config)
name_frame.pack(side="top", fill="x", pady=3, padx=3)
2021-09-24 12:00:38 +02:00
install_frame.pack(side="top", fill="x", pady=3, padx=3)
options_frame.pack(side="left", fill="y", pady=3, padx=3)
resolution_frame.pack(side="left", fill="both", pady=3, padx=3, expand=True)
middle_frame.pack(side="top", fill="x")
deploy_frame.pack(side="top", fill="x", pady=3, padx=3)
root.mainloop()
if __name__ == "__main__":
os.chdir(Path(__file__).parents[0])
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
create_main_window()