Now displays which mod can be run server side only.
This commit is contained in:
parent
33d1502a1b
commit
ebda851611
3 changed files with 59 additions and 17 deletions
|
@ -37,9 +37,10 @@ The main source file for the CLI version is `seven_mods.py`. General usage is:
|
||||||
The available commands are:
|
The available commands are:
|
||||||
|
|
||||||
- `list`: show a listing of all installed mods. Disabled mods appear in red.
|
- `list`: show a listing of all installed mods. Disabled mods appear in red.
|
||||||
Enabled ones appear in green, and are followed by an asterisk (`*`). `list`
|
Enabled ones appear in green, and are followed by an asterisk (`*`). Mods that
|
||||||
also accepts an optional argument, `profiles`, which tells it to list all saved
|
are expected to be able to work server-side only (i.e. "modlets") are followed
|
||||||
profiles instead of mods.
|
by a dollar sign (`$`). `list` also accepts an optional argument, `profiles`,
|
||||||
|
which tells it to list all saved profiles instead of mods.
|
||||||
- `enable`: enable mods. A list of mod names can be given, separated by spaces.
|
- `enable`: enable mods. A list of mod names can be given, separated by spaces.
|
||||||
The mod names are the names of their respective folders, *not* the names listed
|
The mod names are the names of their respective folders, *not* the names listed
|
||||||
in their respective `ModInfo.xml` files. Alternatively, to enable all mods,
|
in their respective `ModInfo.xml` files. Alternatively, to enable all mods,
|
||||||
|
|
|
@ -35,6 +35,9 @@ MODS_DIR = os.getcwd()
|
||||||
STEAM_LIBRARIES_DIR = os.path.join(HOME, ".local/share/Steam/config/libraryfolders.vdf")
|
STEAM_LIBRARIES_DIR = os.path.join(HOME, ".local/share/Steam/config/libraryfolders.vdf")
|
||||||
SEVEN_DIR = os.path.join(HOME, "/.steam/steam/steamapps/common/7 Days To Die")
|
SEVEN_DIR = os.path.join(HOME, "/.steam/steam/steamapps/common/7 Days To Die")
|
||||||
CONFIG_FILE = "seven-mods.cfg"
|
CONFIG_FILE = "seven-mods.cfg"
|
||||||
|
SERVER_ONLY_FILE_TYPES = ("md", "txt", "xml")
|
||||||
|
ALL_MODS = ("-a", "-A", "*", "--all")
|
||||||
|
ALL_SERVER_ONLY_MODS = ("-s", "-S", "--server-only")
|
||||||
|
|
||||||
HELP_TEXT="""Usage: seven-mods.py <command> <args ...>
|
HELP_TEXT="""Usage: seven-mods.py <command> <args ...>
|
||||||
Valid commands are:
|
Valid commands are:
|
||||||
|
@ -264,6 +267,20 @@ def get_available_mods(cfg: Config) -> list:
|
||||||
ret.append(entry.name)
|
ret.append(entry.name)
|
||||||
return sorted(ret, key = lambda x: x.casefold())
|
return sorted(ret, key = lambda x: x.casefold())
|
||||||
|
|
||||||
|
def mod_is_server_only(mod_dir: str) -> bool:
|
||||||
|
"""Checks if a mod can work when only deployed on a server."""
|
||||||
|
with os.scandir(mod_dir) as it:
|
||||||
|
for entry in it:
|
||||||
|
if entry.is_dir():
|
||||||
|
if not mod_is_server_only(entry.path):
|
||||||
|
#print(f"Mod {mod_dir} found not server only at {entry.name}")
|
||||||
|
return False
|
||||||
|
elif entry.is_file():
|
||||||
|
if not entry.name.endswith(SERVER_ONLY_FILE_TYPES):
|
||||||
|
#print(f"Mod {mod_dir} found not server only at {entry.name}")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def enable_mod(cfg: Config, mod_name: str):
|
def enable_mod(cfg: Config, mod_name: str):
|
||||||
link_source = os.path.join(cfg.mods_dir, mod_name)
|
link_source = os.path.join(cfg.mods_dir, mod_name)
|
||||||
link_dest = os.path.join(get_internal_mods_path(cfg), mod_name)
|
link_dest = os.path.join(get_internal_mods_path(cfg), mod_name)
|
||||||
|
@ -290,7 +307,8 @@ def toggle_mod(cfg: Config, mod_name: str):
|
||||||
os.symlink(link_source, link_dest)
|
os.symlink(link_source, link_dest)
|
||||||
|
|
||||||
def get_mod_data(mod: str, cfg: Config) -> tuple:
|
def get_mod_data(mod: str, cfg: Config) -> tuple:
|
||||||
mod_info_path = os.path.join(cfg.mods_dir, mod, "ModInfo.xml")
|
mod_path = os.path.join(cfg.mods_dir, mod)
|
||||||
|
mod_info_path = os.path.join(mod_path, "ModInfo.xml")
|
||||||
try:
|
try:
|
||||||
tree = et.parse(mod_info_path)
|
tree = et.parse(mod_info_path)
|
||||||
except:
|
except:
|
||||||
|
@ -299,6 +317,7 @@ def get_mod_data(mod: str, cfg: Config) -> tuple:
|
||||||
name = ""
|
name = ""
|
||||||
author = ""
|
author = ""
|
||||||
version = ""
|
version = ""
|
||||||
|
serverside = str(mod_is_server_only(mod_path))
|
||||||
for node in root[0]:
|
for node in root[0]:
|
||||||
if node.tag == "Name":
|
if node.tag == "Name":
|
||||||
name = node.attrib["value"]
|
name = node.attrib["value"]
|
||||||
|
@ -306,7 +325,7 @@ def get_mod_data(mod: str, cfg: Config) -> tuple:
|
||||||
author = node.attrib["value"]
|
author = node.attrib["value"]
|
||||||
elif node.tag == "Version":
|
elif node.tag == "Version":
|
||||||
version = node.attrib["value"]
|
version = node.attrib["value"]
|
||||||
return name, version, author
|
return name, version, author, serverside
|
||||||
|
|
||||||
def command_list(args: list, cfg: Config, profiles: ModProfiles):
|
def command_list(args: list, cfg: Config, profiles: ModProfiles):
|
||||||
if len(args) == 3 and args[2] == "profiles":
|
if len(args) == 3 and args[2] == "profiles":
|
||||||
|
@ -327,41 +346,57 @@ def command_list(args: list, cfg: Config, profiles: ModProfiles):
|
||||||
print("".join(["mod".ljust(ts1), "name".ljust(ts2), "version".ljust(ts3), "author".ljust(ts4)]))
|
print("".join(["mod".ljust(ts1), "name".ljust(ts2), "version".ljust(ts3), "author".ljust(ts4)]))
|
||||||
for mod, name, version, author in zip(available_mods, pretty_names, versions, authors):
|
for mod, name, version, author in zip(available_mods, pretty_names, versions, authors):
|
||||||
if mod in loaded_mods:
|
if mod in loaded_mods:
|
||||||
print(f"\x1b[32m{mod.ljust(ts1)}{name.ljust(ts2)}{version.ljust(ts3)}{author.ljust(ts4)}\x1b[0m *")
|
print(f"\x1b[32m{mod.ljust(ts1)}{name.ljust(ts2)}{version.ljust(ts3)}{author.ljust(ts4)}\x1b[0m{suffix} *")
|
||||||
else:
|
else:
|
||||||
print(f"\x1b[31m{mod.ljust(ts1)}{name.ljust(ts2)}{version.ljust(ts3)}{author.ljust(ts4)}\x1b[0m")
|
print(f"\x1b[31m{mod.ljust(ts1)}{name.ljust(ts2)}{version.ljust(ts3)}{author.ljust(ts4)}\x1b[0m{suffix}")
|
||||||
else:
|
else:
|
||||||
for mod in available_mods:
|
for mod in available_mods:
|
||||||
|
suffix = ""
|
||||||
|
if mod_is_server_only(os.path.join(cfg.mods_dir, mod)):
|
||||||
|
suffix += " $"
|
||||||
if mod in loaded_mods:
|
if mod in loaded_mods:
|
||||||
print(f"\x1b[32m{mod}\x1b[0m *")
|
print(f"\x1b[32m{mod}\x1b[0m{suffix} *")
|
||||||
else:
|
else:
|
||||||
print(f"\x1b[31m{mod}\x1b[0m")
|
print(f"\x1b[31m{mod}\x1b[0m{suffix}")
|
||||||
else:
|
else:
|
||||||
print(f"Usage: {args[0]} {args[1]} [profiles]")
|
print(f"Usage: {args[0]} {args[1]} [profiles]")
|
||||||
|
|
||||||
def command_enable(args: list, cfg: Config, profiles: ModProfiles):
|
def command_enable(args: list, cfg: Config, profiles: ModProfiles):
|
||||||
args = [a.rstrip("/") for a in args]
|
args = [a.rstrip("/") for a in args]
|
||||||
for mod in args[2:]:
|
for mod in args[2:]:
|
||||||
if not mod in ("-a", "-A", "*"):
|
if not mod in ALL_MODS + ALL_SERVER_ONLY_MODS:
|
||||||
enable_mod(cfg, mod)
|
enable_mod(cfg, mod)
|
||||||
else:
|
elif mod in ALL_MODS:
|
||||||
available_mods = get_available_mods(cfg)
|
available_mods = get_available_mods(cfg)
|
||||||
loaded_mods = get_loaded_mods(cfg)
|
loaded_mods = get_loaded_mods(cfg)
|
||||||
for mod in available_mods:
|
for mod in available_mods:
|
||||||
if mod not in loaded_mods:
|
if mod not in loaded_mods:
|
||||||
enable_mod(cfg, mod)
|
enable_mod(cfg, mod)
|
||||||
break
|
break
|
||||||
|
elif mod in ALL_SERVER_ONLY_MODS:
|
||||||
|
available_mods = get_available_mods(cfg)
|
||||||
|
loaded_mods = get_loaded_mods(cfg)
|
||||||
|
for mod in available_mods:
|
||||||
|
if mod not in loaded_mods and mod_is_server_only(os.path.join(cfg.mods_dir, mod)):
|
||||||
|
enable_mod(cfg, mod)
|
||||||
|
break
|
||||||
|
|
||||||
def command_disable(args: list, cfg: Config, profiles: ModProfiles):
|
def command_disable(args: list, cfg: Config, profiles: ModProfiles):
|
||||||
args = [a.rstrip("/") for a in args]
|
args = [a.rstrip("/") for a in args]
|
||||||
for mod in args[2:]:
|
for mod in args[2:]:
|
||||||
if not mod in ("-a", "-A", "*"):
|
if not mod in ALL_MODS + ALL_SERVER_ONLY_MODS:
|
||||||
disable_mod(cfg, mod)
|
disable_mod(cfg, mod)
|
||||||
else:
|
elif mod in ALL_MODS:
|
||||||
loaded_mods = get_loaded_mods(cfg)
|
loaded_mods = get_loaded_mods(cfg)
|
||||||
for mod in loaded_mods:
|
for mod in loaded_mods:
|
||||||
disable_mod(cfg, mod)
|
disable_mod(cfg, mod)
|
||||||
break
|
break
|
||||||
|
elif mod in ALL_SERVER_ONLY_MODS:
|
||||||
|
loaded_mods = get_loaded_mods(cfg)
|
||||||
|
for mod in loaded_mods:
|
||||||
|
if mod_is_server_only(os.path.join(cfg.mods_dir, mod)):
|
||||||
|
disable_mod(cfg, mod)
|
||||||
|
break
|
||||||
|
|
||||||
def command_toggle(args: list, cfg: Config, profiles: ModProfiles):
|
def command_toggle(args: list, cfg: Config, profiles: ModProfiles):
|
||||||
args = [a.rstrip("/") for a in args]
|
args = [a.rstrip("/") for a in args]
|
||||||
|
|
|
@ -82,13 +82,17 @@ class AppFrame(ttk.Frame):
|
||||||
|
|
||||||
# Mod list
|
# Mod list
|
||||||
self.mod_list = ttk.Treeview(self,
|
self.mod_list = ttk.Treeview(self,
|
||||||
columns = ("name", "version", "author", "enabled"),
|
columns = ("name", "version", "author", "serverside", "enabled"),
|
||||||
height = 20,
|
height = 20,
|
||||||
selectmode = "browse")
|
selectmode = "browse")
|
||||||
self.mod_list.heading("name", text = "Name")
|
self.mod_list.heading("name", text = "Name")
|
||||||
self.mod_list.heading("version", text = "Version")
|
self.mod_list.heading("version", text = "Version")
|
||||||
|
self.mod_list.column("version", width = 100)
|
||||||
self.mod_list.heading("author", text = "Author")
|
self.mod_list.heading("author", text = "Author")
|
||||||
|
self.mod_list.heading("serverside", text = "Serverside")
|
||||||
|
self.mod_list.column("serverside", width = 100)
|
||||||
self.mod_list.heading("enabled", text = "Enabled")
|
self.mod_list.heading("enabled", text = "Enabled")
|
||||||
|
self.mod_list.column("enabled", width = 100)
|
||||||
self.mod_list.tag_configure("DISABLED", foreground = "red")
|
self.mod_list.tag_configure("DISABLED", foreground = "red")
|
||||||
self.mod_list.tag_configure("ENABLED", foreground = "green")
|
self.mod_list.tag_configure("ENABLED", foreground = "green")
|
||||||
self.mod_list.tag_bind("DISABLED", '<Double-1>', lambda e: self.command_enable(self.mod_list.selection()[0]))
|
self.mod_list.tag_bind("DISABLED", '<Double-1>', lambda e: self.command_enable(self.mod_list.selection()[0]))
|
||||||
|
@ -177,7 +181,8 @@ class AppFrame(ttk.Frame):
|
||||||
self.refresh_mod_list()
|
self.refresh_mod_list()
|
||||||
|
|
||||||
def get_mod_data(self, mod: str) -> tuple:
|
def get_mod_data(self, mod: str) -> tuple:
|
||||||
mod_info_path = os.path.join(self.cfg.mods_dir, mod, "ModInfo.xml")
|
mod_path = os.path.join(self.cfg.mods_dir, mod)
|
||||||
|
mod_info_path = os.path.join(mod_path, "ModInfo.xml")
|
||||||
try:
|
try:
|
||||||
tree = et.parse(mod_info_path)
|
tree = et.parse(mod_info_path)
|
||||||
except:
|
except:
|
||||||
|
@ -186,6 +191,7 @@ class AppFrame(ttk.Frame):
|
||||||
name = ""
|
name = ""
|
||||||
author = ""
|
author = ""
|
||||||
version = ""
|
version = ""
|
||||||
|
serverside = str(seven_mods.mod_is_server_only(mod_path))
|
||||||
for node in root[0]:
|
for node in root[0]:
|
||||||
if node.tag == "Name":
|
if node.tag == "Name":
|
||||||
name = node.attrib["value"]
|
name = node.attrib["value"]
|
||||||
|
@ -193,7 +199,7 @@ class AppFrame(ttk.Frame):
|
||||||
author = node.attrib["value"]
|
author = node.attrib["value"]
|
||||||
elif node.tag == "Version":
|
elif node.tag == "Version":
|
||||||
version = node.attrib["value"]
|
version = node.attrib["value"]
|
||||||
return name, version, author
|
return name, version, author, serverside
|
||||||
|
|
||||||
def refresh_mod_list(self):
|
def refresh_mod_list(self):
|
||||||
if self.cfg == None:
|
if self.cfg == None:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue