feat: v4.1.0 -- workshop-ready (logo, path discovery, docs)
Players install from Steam Workshop instead of install.sh, which failed on Windows (bash) and a Manjaro box (hard-coded Mods globs). Adds Logo + logo.png the uploader ships, tools/steam_paths.py reading Steam's libraryfolders.vdf (Flatpak/Snap/second disk/Windows), and README install tiers plus in-game publishing steps. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014TkQMhvEyoFqKzeCC69N6o
This commit is contained in:
Executable
+119
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python3
|
||||
# ABOUT ME
|
||||
# Finds the installed Cosmoteer game data and the user Mods folder, wherever
|
||||
# Steam put them. Shared by install.sh and tests/test_mod.py.
|
||||
#
|
||||
# Why it exists: Steam lives in different places (native, Flatpak, Snap,
|
||||
# Debian package, Windows) and a game can sit in any library listed in
|
||||
# steamapps/libraryfolders.vdf, often on another disk. Hard-coded globs miss
|
||||
# those; this reads Steam's own library list instead.
|
||||
#
|
||||
# Environment overrides always win: COSMOTEER_DATA for the Data folder,
|
||||
# COSMOTEER_MODS_DIR for the Mods folder.
|
||||
#
|
||||
# Usage: python3 tools/steam_paths.py --data print the Data folder
|
||||
# python3 tools/steam_paths.py --mods print the Mods folder
|
||||
# Exit 1 with the roots tried on stderr when nothing is found.
|
||||
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
APP_ID = "799600"
|
||||
PROTON_PROFILE = "compatdata/" + APP_ID + "/pfx/drive_c/users/steamuser/Saved Games/Cosmoteer"
|
||||
|
||||
# Steam roots relative to HOME, in the order they are tried.
|
||||
STEAM_ROOTS_UNDER_HOME = [
|
||||
".local/share/Steam",
|
||||
".steam/steam",
|
||||
".steam/debian-installation",
|
||||
".var/app/com.valvesoftware.Steam/.local/share/Steam",
|
||||
".snap/steam/common/.local/share/Steam",
|
||||
"snap/steam/common/.local/share/Steam",
|
||||
]
|
||||
|
||||
_VDF_PATH = re.compile(r'"path"\s+"([^"]+)"')
|
||||
|
||||
|
||||
def steam_roots(env=None):
|
||||
"""Candidate Steam install roots for this environment (existing or not)."""
|
||||
env = os.environ if env is None else env
|
||||
home = env.get("HOME")
|
||||
roots = [os.path.join(home, rel) for rel in STEAM_ROOTS_UNDER_HOME] if home else []
|
||||
program_files = env.get("PROGRAMFILES(X86)") or env.get("ProgramFiles(x86)")
|
||||
if program_files:
|
||||
roots.append(os.path.join(program_files, "Steam"))
|
||||
return roots
|
||||
|
||||
|
||||
def libraries(env=None):
|
||||
"""Every Steam library folder: each root plus what its libraryfolders.vdf lists."""
|
||||
seen = []
|
||||
for root in steam_roots(env):
|
||||
for candidate in [root] + _vdf_libraries(root):
|
||||
candidate = os.path.realpath(candidate)
|
||||
if candidate not in seen and os.path.isdir(os.path.join(candidate, "steamapps")):
|
||||
seen.append(candidate)
|
||||
return seen
|
||||
|
||||
|
||||
def _vdf_libraries(root):
|
||||
vdf = os.path.join(root, "steamapps", "libraryfolders.vdf")
|
||||
if not os.path.isfile(vdf):
|
||||
return []
|
||||
with open(vdf, encoding="utf-8", errors="replace") as f:
|
||||
return [p.replace("\\\\", "\\") for p in _VDF_PATH.findall(f.read())]
|
||||
|
||||
|
||||
def find_data_dir(env=None):
|
||||
env = os.environ if env is None else env
|
||||
override = env.get("COSMOTEER_DATA")
|
||||
if override:
|
||||
return override
|
||||
for library in libraries(env):
|
||||
data = os.path.join(library, "steamapps", "common", "Cosmoteer", "Data")
|
||||
if os.path.isdir(data):
|
||||
return data
|
||||
return None
|
||||
|
||||
|
||||
def find_mods_dir(env=None):
|
||||
env = os.environ if env is None else env
|
||||
override = env.get("COSMOTEER_MODS_DIR")
|
||||
if override:
|
||||
return override
|
||||
patterns = [
|
||||
os.path.join(library, "steamapps", PROTON_PROFILE, "*", "Mods") for library in libraries(env)
|
||||
]
|
||||
profile = env.get("USERPROFILE")
|
||||
if profile:
|
||||
patterns.append(os.path.join(profile, "Saved Games", "Cosmoteer", "*", "Mods"))
|
||||
for pattern in patterns:
|
||||
for match in sorted(glob.glob(pattern)):
|
||||
if os.path.isdir(match):
|
||||
return match
|
||||
return None
|
||||
|
||||
|
||||
def main(argv):
|
||||
if argv[1:] == ["--data"]:
|
||||
found = find_data_dir()
|
||||
what = "Cosmoteer Data folder"
|
||||
elif argv[1:] == ["--mods"]:
|
||||
found = find_mods_dir()
|
||||
what = "Cosmoteer Mods folder"
|
||||
else:
|
||||
print(__doc__ or "usage: steam_paths.py --data | --mods", file=sys.stderr)
|
||||
return 2
|
||||
if found:
|
||||
print(found)
|
||||
return 0
|
||||
print(f"Could not find the {what}. Steam roots tried:", file=sys.stderr)
|
||||
for root in steam_roots():
|
||||
print(f" {root}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main(sys.argv))
|
||||
Reference in New Issue
Block a user