117 lines
4.3 KiB
Python
117 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Regenerate server/mods.json from the Prism instance's mods directory.
|
|
|
|
For every .jar in the pack instance it:
|
|
- computes sha1
|
|
- looks up the Modrinth download URL via the version_file API
|
|
(aero-shadow-fix is CurseForge-only, pinned manually)
|
|
- drops the 19 client-only mods
|
|
and writes the server manifest to mods.json.
|
|
|
|
Usage: python3 build_mods.py regenerate server/mods.json
|
|
python3 build_mods.py --push regenerate, then update the live server
|
|
(stop -> sync mods -> start, via SSH)
|
|
"""
|
|
import argparse, hashlib, json, os, subprocess, sys, time
|
|
|
|
INSTANCE = os.path.expanduser(
|
|
"~/.local/share/PrismLauncher/instances/Reaper's Sky - dev/.minecraft/mods")
|
|
OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "mods.json")
|
|
UPDATE_SH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "update.sh")
|
|
SERVER_HOST = os.environ.get("RS_SERVER_HOST", "root@ReapersSky")
|
|
MC_VERSION = "1.21.1"
|
|
NEOFORGE_VERSION = "21.1.248"
|
|
|
|
CLIENT_ONLY = {
|
|
"iris-neoforge-1.8.14-beta.1+mc1.21.1.jar",
|
|
"EuphoriaPatcher-1.9.3-r5.8.1-neoforge.jar",
|
|
"iris-flywheel-compat-NeoForge-2.3.1.jar",
|
|
"sodium-neoforge-0.8.12+mc1.21.1.jar",
|
|
"moreculling-neoforge-1.21.1-1.0.9.jar",
|
|
"BetterF3-11.0.3-NeoForge-1.21.1.jar",
|
|
"ImmediatelyFast-NeoForge-1.6.12+1.21.1.jar",
|
|
"entityculling-neoforge-1.10.5-mc1.21.1.jar",
|
|
"dynamic-fps-3.11.4+mc1.21.0-neoforge.jar",
|
|
"MouseTweaks-neoforge-mc1.21-2.26.1.jar",
|
|
"appleskin-neoforge-mc1.21-3.0.9.jar",
|
|
"Controlling-neoforge-1.21.1-19.0.5.jar",
|
|
"Searchables-neoforge-1.21.1-1.0.2.jar",
|
|
"skinlayers3d-neoforge-1.11.2-mc1.21.1.jar",
|
|
"xaerominimap-neoforge-1.21.1-26.4.2.jar",
|
|
"xaeroworldmap-neoforge-1.21.1-1.44.2.jar",
|
|
"jade-sable-compat-1.3.0.jar",
|
|
"aero-shadow-fix.jar",
|
|
"aeronautics-propeller-blur-1.0a.jar",
|
|
}
|
|
|
|
CURSEFORGE_ONLY = {
|
|
"aero-shadow-fix.jar": "https://www.curseforge.com/api/v1/mods/1641969/files/8589529/download",
|
|
"arssophisticatedcompat-0.3.0.jar": "https://www.curseforge.com/api/v1/mods/1653477/files/8653384/download",
|
|
}
|
|
|
|
UA = "opencode-pack-builder/1.0"
|
|
|
|
|
|
def sha1(path):
|
|
h = hashlib.sha1()
|
|
with open(path, "rb") as f:
|
|
for chunk in iter(lambda: f.read(65536), b""):
|
|
h.update(chunk)
|
|
return h.hexdigest()
|
|
|
|
|
|
def resolve(jar, digest):
|
|
if jar in CURSEFORGE_ONLY:
|
|
return CURSEFORGE_ONLY[jar]
|
|
r = subprocess.run(
|
|
["curl", "-s", "--max-time", "20", "-H", f"User-Agent: {UA}",
|
|
f"https://api.modrinth.com/v2/version_file/{digest}?algorithm=sha1"],
|
|
capture_output=True, text=True)
|
|
try:
|
|
return json.loads(r.stdout)["files"][0]["url"]
|
|
except Exception:
|
|
return ""
|
|
|
|
|
|
def push():
|
|
"""Upload mods.json to the server and run update.sh there (stop/sync/start)."""
|
|
print(f"Uploading manifest to {SERVER_HOST}:/tmp/reaper-sky-mods.json ...")
|
|
with open(OUT, "rb") as f:
|
|
subprocess.run(["ssh", SERVER_HOST, "cat > /tmp/reaper-sky-mods.json"],
|
|
stdin=f, check=True)
|
|
print("Running update.sh on the server (stop -> sync -> start) ...")
|
|
with open(UPDATE_SH, "rb") as f:
|
|
subprocess.run(["ssh", SERVER_HOST, "bash -s -- /tmp/reaper-sky-mods.json"],
|
|
stdin=f, check=True)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
parser.add_argument("--push", action="store_true",
|
|
help="also update the live server: stop it, sync mods "
|
|
"(prune + download + sha1-verify), start it again")
|
|
args = parser.parse_args()
|
|
|
|
mods = []
|
|
for jar in sorted(os.listdir(INSTANCE)):
|
|
if not jar.endswith(".jar"):
|
|
continue
|
|
if jar in CLIENT_ONLY:
|
|
print(f" skip (client-only): {jar}")
|
|
continue
|
|
digest = sha1(os.path.join(INSTANCE, jar))
|
|
url = resolve(jar, digest)
|
|
if not url:
|
|
print(f" !! no URL for {jar} -- fix manually", file=sys.stderr)
|
|
mods.append({"file": jar, "url": url, "sha1": digest})
|
|
time.sleep(0.1)
|
|
manifest = {"minecraft": MC_VERSION, "neoforge": NEOFORGE_VERSION, "mods": mods}
|
|
with open(OUT, "w") as f:
|
|
json.dump(manifest, f, indent=2)
|
|
print(f"Wrote {len(mods)} server mods to {OUT}")
|
|
if args.push:
|
|
push()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |