db33224009
Storage: Sophisticated Core/Storage/Backpacks + Create integration addons, Tom's Simple Storage, Pipez. Automation: Create Slice & Dice (bundles atmosphere/sable-companion jarjar), Create: Easy Stone Generators. Create x Ars: Create: Ars Nouveau Compat + Create: Compat Core. Ars x Backpacks: Sophisticated Backpacks: Ars Compat (LuminaCherry, CF-pinned). Building: Macaw's set (Doors, Fences&Walls, Windows, Bridges, Stairs, Trapdoors, Furniture, Lights&Lamps, Paths&Pavings, Paintings) — no roofs. Server manifest regenerated to 82 mods; mrpack rebuilt as ReapersSky-1.1.0. Validated: server boots to Done on 21.1.248 with all new mods loaded.
93 lines
3.1 KiB
Python
93 lines
3.1 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
|
|
"""
|
|
import 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")
|
|
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",
|
|
"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-1.21.1-NeoForge-15.10.6.jar",
|
|
"jade-sable-compat-1.3.0.jar",
|
|
"aero-shadow-fix.jar",
|
|
"aeronautics-propeller-blur-1.0a.jar",
|
|
"jei-1.21.1-neoforge-19.44.0.403.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 main():
|
|
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 __name__ == "__main__":
|
|
main() |