Add prepare_local script, gitignore LocalMods

This commit is contained in:
2026-06-08 18:49:15 +03:00
parent 32204f4cf9
commit 143f2fed7c
21 changed files with 162 additions and 720 deletions

161
prepare_local Executable file
View File

@@ -0,0 +1,161 @@
#!/usr/bin/env python3
"""Copy workshop mods from ACTUAL_SERVER.xml into LocalMods/ with readable names."""
import shutil
import sys
import os
import xml.etree.ElementTree as ET
WORKSHOP_DIR = "/mnt/nvme/B/SteamLibrary/steamapps/workshop/content/602960"
MODLIST_PATH = "/mnt/nvme/B/SteamLibrary/steamapps/common/Barotrauma/ModLists/ACTUAL_SERVER.xml"
LOCALMODS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "LocalMods")
def log_ok(msg: str, indent: int = 0):
prefix = " " * indent + "✓"
print(f"\033[92m{prefix}\033[0m {msg}")
def log_info(msg: str, indent: int = 0):
prefix = " " * indent + "•"
print(f"{prefix} {msg}")
def log_warn(msg: str, indent: int = 0):
prefix = " " * indent + "⚠"
print(f"\033[93m{prefix}\033[0m {msg}")
def log_err(msg: str, indent: int = 0):
prefix = " " * indent + "✗"
print(f"\033[91m{prefix}\033[0m {msg}", file=sys.stderr)
def sanitize_folder_name(name: str) -> str:
forbidden = '/\\:*?"<>|'
for ch in forbidden:
name = name.replace(ch, "_")
return name.strip()
def get_mod_name_from_filelist(folder_path: str) -> str | None:
fl_path = os.path.join(folder_path, "filelist.xml")
if not os.path.isfile(fl_path):
return None
try:
root = ET.parse(fl_path).getroot()
return root.get("name")
except Exception as e:
log_warn(f"Failed to parse filelist.xml: {e}", indent=2)
return None
def copy_mod(src: str, dst: str) -> bool:
if os.path.exists(dst):
log_info(f"Removing existing folder: {dst}", indent=2)
shutil.rmtree(dst)
log_info(f"Copying: {src} → {dst}", indent=2)
shutil.copytree(src, dst, symlinks=True)
return True
def main():
print()
print("╔══════════════════════════════════════════╗")
print("║ Prepare Local Mods from ACTUAL_SERVER ║")
print("╚══════════════════════════════════════════╝")
print()
if not os.path.isfile(MODLIST_PATH):
log_err(f"Mod list not found: {MODLIST_PATH}")
sys.exit(1)
log_info(f"Reading mod list: {MODLIST_PATH}")
try:
tree = ET.parse(MODLIST_PATH)
root = tree.getroot()
except Exception as e:
log_err(f"Failed to parse mod list: {e}")
sys.exit(1)
mods = root.findall("Workshop")
if not mods:
log_warn("No <Workshop> entries found in mod list")
sys.exit(0)
log_info(f"Found {len(mods)} workshop mod(s)")
print()
copied = 0
skipped = 0
errors = 0
for mod in mods:
mod_id = mod.get("id", "").strip()
mod_name = mod.get("name", "").strip()
if not mod_id:
log_warn(f"Skipping entry with no id: name='{mod_name}'", indent=1)
skipped += 1
continue
print(f"[{mod_id}] {mod_name}")
log_info(f"Processing mod: {mod_name}", indent=1)
src_dir = os.path.join(WORKSHOP_DIR, mod_id)
if not os.path.isdir(src_dir):
log_err(f"Workshop folder not found: {src_dir}", indent=2)
errors += 1
continue
display_name = get_mod_name_from_filelist(src_dir)
if not display_name:
log_warn("No name found in filelist.xml, using Steam name", indent=2)
display_name = mod_name
safe_name = sanitize_folder_name(display_name)
if not safe_name:
log_warn("Sanitized name is empty, using mod ID as fallback", indent=2)
safe_name = mod_id
dst_dir = os.path.join(LOCALMODS_DIR, safe_name)
try:
copy_mod(src_dir, dst_dir)
log_ok(f"Copied as: {safe_name}", indent=2)
copied += 1
except Exception as e:
log_err(f"Copy failed: {e}", indent=2)
errors += 1
print()
print("─" * 50)
log_ok(f"Copied: {copied}")
log_info(f"Skipped: {skipped}")
if errors:
log_err(f"Errors: {errors}")
local_mods = root.findall("Local")
if local_mods:
print()
log_info(f"Checking {len(local_mods)} local mod reference(s)…")
for lm in local_mods:
lm_name = lm.get("name", "").strip()
if not lm_name:
continue
lm_path = os.path.join(LOCALMODS_DIR, sanitize_folder_name(lm_name))
if os.path.isdir(lm_path):
log_ok(f"Local mod present: {lm_name}", indent=1)
else:
log_warn(f"Local mod NOT found: {lm_name}", indent=1)
print()
if not errors and skipped == 0:
print()
log_ok("All mods prepared successfully!")
print()
if __name__ == "__main__":
main()