从 dota2-draft-vision 迁出并定名,作为天梯选将识别项目起点。 Co-authored-by: Cursor <cursoragent@cursor.com>
143 lines
4.0 KiB
Python
143 lines
4.0 KiB
Python
"""Install the Game State Integration config that lets Dota 2 talk to gsi_watch.py.
|
|
|
|
Usage:
|
|
python gsi_setup.py # auto-detect Dota 2 and write the cfg
|
|
python gsi_setup.py --path "D:\\Steam\\steamapps\\common\\dota 2 beta"
|
|
python gsi_setup.py --remove # uninstall the cfg
|
|
python gsi_setup.py --check # only report where things are
|
|
|
|
After installing, add -gamestateintegration to Dota 2's launch options
|
|
(Steam library -> right-click Dota 2 -> Properties) and restart the game.
|
|
"""
|
|
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from common import load_config
|
|
|
|
CFG_NAME = "gamestate_integration_climperor.cfg"
|
|
|
|
CFG_TEMPLATE = """"Climperor"
|
|
{{
|
|
"uri" "http://127.0.0.1:{port}/"
|
|
"timeout" "5.0"
|
|
"buffer" "0.1"
|
|
"throttle" "0.5"
|
|
"heartbeat" "30.0"
|
|
"data"
|
|
{{
|
|
"provider" "1"
|
|
"map" "1"
|
|
"player" "1"
|
|
"hero" "1"
|
|
}}
|
|
}}
|
|
"""
|
|
|
|
FALLBACK_ROOTS = [
|
|
r"C:\Program Files (x86)\Steam",
|
|
r"C:\Steam",
|
|
r"D:\Steam",
|
|
r"D:\SteamLibrary",
|
|
r"E:\SteamLibrary",
|
|
]
|
|
|
|
|
|
def steam_roots() -> list[Path]:
|
|
"""Candidate Steam library roots, from the registry plus libraryfolders.vdf."""
|
|
roots: list[Path] = []
|
|
|
|
try:
|
|
import winreg
|
|
|
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\Valve\Steam") as key:
|
|
roots.append(Path(winreg.QueryValueEx(key, "SteamPath")[0]))
|
|
except Exception: # noqa: BLE001 - registry is best-effort
|
|
pass
|
|
|
|
roots += [Path(p) for p in FALLBACK_ROOTS]
|
|
|
|
# libraryfolders.vdf lists every additional install drive
|
|
for root in list(roots):
|
|
vdf = root / "steamapps" / "libraryfolders.vdf"
|
|
if not vdf.is_file():
|
|
continue
|
|
try:
|
|
text = vdf.read_text(encoding="utf-8", errors="ignore")
|
|
except OSError:
|
|
continue
|
|
for match in re.finditer(r'"path"\s+"([^"]+)"', text):
|
|
roots.append(Path(match.group(1).replace("\\\\", "\\")))
|
|
|
|
seen: set[str] = set()
|
|
unique: list[Path] = []
|
|
for r in roots:
|
|
k = str(r).lower()
|
|
if k not in seen:
|
|
seen.add(k)
|
|
unique.append(r)
|
|
return unique
|
|
|
|
|
|
def find_dota() -> Path | None:
|
|
"""Locate the 'dota 2 beta' install directory."""
|
|
for root in steam_roots():
|
|
candidate = root / "steamapps" / "common" / "dota 2 beta"
|
|
if (candidate / "game" / "dota").is_dir():
|
|
return candidate
|
|
return None
|
|
|
|
|
|
def gsi_dir(dota: Path) -> Path:
|
|
return dota / "game" / "dota" / "cfg" / "gamestate_integration"
|
|
|
|
|
|
def main() -> None:
|
|
args = sys.argv[1:]
|
|
|
|
if "--path" in args:
|
|
dota = Path(args[args.index("--path") + 1])
|
|
if not (dota / "game" / "dota").is_dir():
|
|
sys.exit(f"not a Dota 2 install directory: {dota}")
|
|
else:
|
|
dota = find_dota()
|
|
if dota is None:
|
|
sys.exit(
|
|
"could not find Dota 2 automatically.\n"
|
|
"Pass it explicitly, e.g.:\n"
|
|
' python gsi_setup.py --path "D:\\Steam\\steamapps\\common\\dota 2 beta"'
|
|
)
|
|
|
|
target = gsi_dir(dota) / CFG_NAME
|
|
print(f"dota 2 : {dota}")
|
|
print(f"gsi cfg : {target}")
|
|
|
|
if "--check" in args:
|
|
print(f"installed: {target.is_file()}")
|
|
return
|
|
|
|
if "--remove" in args:
|
|
if target.is_file():
|
|
target.unlink()
|
|
print("removed.")
|
|
else:
|
|
print("nothing to remove.")
|
|
return
|
|
|
|
port = load_config().get("gsi", {}).get("port", 3223)
|
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
target.write_text(CFG_TEMPLATE.format(port=port), encoding="utf-8")
|
|
|
|
print(f"installed, endpoint http://127.0.0.1:{port}/")
|
|
print()
|
|
print("Next steps:")
|
|
print(" 1. Steam library -> Dota 2 -> Properties -> Launch Options:")
|
|
print(" add -gamestateintegration")
|
|
print(" 2. Restart Dota 2.")
|
|
print(" 3. Run python gsi_watch.py")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|