#!/usr/bin/env python3 """Generate the staged client-perf configs (tiers + Phase 2 bench variants). Every override is applied to a *base* file and must hit a key that already exists in that base, otherwise the build fails. Bases are either the observed defaults generated by the exact pinned jar (DH 3.3.2, Sodium 0.8.13, EMF 3.3.9, Flywheel 1.0.6, Sable 2.0.5, SPR 1.5.1 - versions verified against the 2026-09-24 launch log) or hand-authored templates whose keys were read from the pinned jar's source (see README.md, "Key provenance"). Output: out//, plus out/MANIFEST.md. python3 build.py # from this directory; stdlib only python3 build.py --ship # also copy T-default into the repo (see SHIP), then # run `packwiz refresh` from the repo root """ import json import re import shutil import sys from pathlib import Path HERE = Path(__file__).resolve().parent OBSERVED = HERE.parent / "data" / "observed-default-configs" TEMPLATES = HERE / "templates" OUT = HERE / "out" REPO = HERE.parents[2] # What `--ship` copies from out/T-default into the repo, and where. # Default Options seeds these client-side only, and only if the file is absent # (see README ยง1). Not shipped: sable-client.toml and sodium-options.json (no change # from upstream). modernfix-mixins.properties is held back until bench block B6 # passes; when it does, add it here with destination "config/modernfix-mixins.properties" # (enforced packwiz file, because ModernFix reads it before Default Options runs) and # re-include it in .packwizignore. DO = "config/defaultoptions" SHIP = { "options.txt": f"{DO}/options.txt", "config/DistantHorizons.toml": f"{DO}/extra/config/DistantHorizons.toml", "config/entity_model_features.json": f"{DO}/extra/config/entity_model_features.json", "config/flywheel-client.toml": f"{DO}/extra/config/flywheel-client.toml", "config/lambdynlights.toml": f"{DO}/extra/config/lambdynlights.toml", "config/ssrd-common.toml": f"{DO}/extra/config/ssrd-common.toml", "config/sound_physics_remastered/soundphysics.properties": f"{DO}/extra/config/sound_physics_remastered/soundphysics.properties", "config/sound_physics_remastered/sound_rates.properties": f"{DO}/extra/config/sound_physics_remastered/sound_rates.properties", } # game-dir path -> (base file, format, may_append_new_keys) FILES = { "options.txt": (TEMPLATES / "options.txt", "options", False), "config/DistantHorizons.toml": (OBSERVED / "DistantHorizons.toml", "toml", False), "config/sodium-options.json": (OBSERVED / "sodium-options.json", "json", False), "config/entity_model_features.json": (OBSERVED / "entity_model_features.json", "json", False), "config/flywheel-client.toml": (OBSERVED / "flywheel-client.toml", "toml", False), "config/sable-client.toml": (OBSERVED / "sable-client.toml", "toml", False), "config/ssrd-common.toml": (TEMPLATES / "config/ssrd-common.toml", "toml", False), "config/lambdynlights.toml": (TEMPLATES / "config/lambdynlights.toml", "toml", False), "config/modernfix-mixins.properties": (TEMPLATES / "config/modernfix-mixins.properties", "properties", False), "config/sound_physics_remastered/soundphysics.properties": ( OBSERVED / "sound_physics_remastered/soundphysics.properties", "properties", False), # SPR merges partial files over its generated defaults (SoundRateConfig.load) "config/sound_physics_remastered/sound_rates.properties": ( TEMPLATES / "config/sound_physics_remastered/sound_rates.properties", "properties", True), } DH_Q = "client.advanced.graphics.quality" DH_G = "client.advanced.graphics" DH_T = "common.multiThreading" DH_W = "common.worldGenerator" # Create 6.0.10 sound IDs (from the observed sound_rates.properties, same Create version). # Over the cap, SPR plays the sound dry (SoundPhysics.java: setDefaultEnvironment), it is not dropped. CREATE_NOISY = [ "create:cogs", "create:mixing", "create:mixing_compounded_1", "create:mechanical_press_activation", "create:mechanical_press_activation_compounded_1", "create:mechanical_press_activation_belt", "create:mechanical_press_activation_belt_compounded_1", "create:crushing_1", "create:crushing_2", "create:crushing_3", "create:saw_activate_stone", "create:saw_activate_wood", "create:funnel_flap", "create:funnel_flap_compounded_1", "create:depot_slide", "create:depot_plop", "create:steam", "create:sanding_short", "create:sanding_long", ] def sound_caps(n): return {s.replace(":", "\\:"): n for s in CREATE_NOISY} # Observed DH values were computed on a 4-thread box; DH's real default is # ceil(nproc * 0.5) (ThreadPresetConfigEventHandler) = 4 on every 8-thread fleet # machine. Applied first to every variant so C0 is the fleet's true default. UPSTREAM = {"config/DistantHorizons.toml": {(DH_T, "numberOfThreads"): 4}} # Per-install values that must not ship: DH regenerates missing keys with their # default (ConfigFileHandler.loadEntry -> saveEntry); serverId is new Random().nextInt(). STRIP = {"config/DistantHorizons.toml": [("server", "serverId")]} # -------------------------------------------------------------------------- # Tiers. "default" is the pack-wide conservative default; deck/high are deltas # on top of it; mid == default. # -------------------------------------------------------------------------- DEFAULT = { "options.txt": { "renderDistance": 8, # server view-distance is 8; more loads nothing in MP "simulationDistance": 8, # singleplayer only "biomeBlendRadius": 1, # 3x3; chunk-build cost (Sodium tooltip) "mipmapLevels": 2, # block atlas is >=4096^2 "entityDistanceScaling": 0.75, # slider steps are 0.25 }, "config/DistantHorizons.toml": { (DH_Q, "lodChunkRenderDistanceRadius"): 128, # default 256 (DH_G, "enableSsao"): False, # default true (DH_T, "numberOfThreads"): 2, # default ceil(nproc*0.5) = 4 on the fleet }, "config/entity_model_features.json": { "animationLODDistance": 12, # default 20; lower = more frame skipping "modelUpdateFrequency": "Slow", # default Average; model refresh, not animation }, "config/flywheel-client.toml": { ("flw_backends", "lightSmoothness"): "TRI_LINEAR", # default SMOOTH }, "config/ssrd-common.toml": { ("", "physicsRenderDistance"): 16, # default 128; slider floor is minPhysicsRenderDistance=16 }, "config/lambdynlights.toml": { ("", "mode"): "fast", # default fancy; fast = TickMode.SLOW }, "config/modernfix-mixins.properties": { "mixin.perf.dynamic_resources": "true", # GATED on bench block B6 }, "config/sound_physics_remastered/soundphysics.properties": { "environment_evaluation_ray_count": 16, # default 32 "environment_evaluation_ray_bounces": 2, # default 4 }, "config/sound_physics_remastered/sound_rates.properties": sound_caps(4), } DECK = { "options.txt": {"biomeBlendRadius": 0, "particles": 1, "entityShadows": "false"}, # = DH's own LOW quality preset (RenderQualityPresetConfigEventHandler) + radius 64 "config/DistantHorizons.toml": { (DH_Q, "lodChunkRenderDistanceRadius"): 64, (DH_Q, "horizontalQuality"): "LOW", (DH_Q, "verticalQuality"): "LOW", (DH_Q, "transparency"): "DISABLED", (DH_Q, "vanillaFadeMode"): "SINGLE_PASS", (DH_Q, "lodBiomeBlending"): 1, }, "config/sodium-options.json": { "quality.weather_quality": "FAST", "quality.leaves_quality": "FAST", }, "config/entity_model_features.json": { "animationLODDistance": 8, "retainDetailOnLowFps": False, }, "config/flywheel-client.toml": {("flw_backends", "lightSmoothness"): "FLAT"}, "config/lambdynlights.toml": { ("", "mode"): "fastest", ("light_sources", "entities"): False, }, "config/sound_physics_remastered/soundphysics.properties": {"strict_occlusion": "true"}, } HIGH = { # strong GPU, but still a 4C/8T CPU (true of every fleet machine) "options.txt": {"mipmapLevels": 4, "biomeBlendRadius": 2, "entityDistanceScaling": 1.0}, "config/DistantHorizons.toml": {(DH_G, "enableSsao"): True}, "config/flywheel-client.toml": {("flw_backends", "lightSmoothness"): "SMOOTH"}, "config/ssrd-common.toml": {("", "physicsRenderDistance"): 32}, "config/lambdynlights.toml": {("light_sources", "entities"): False}, "config/sound_physics_remastered/soundphysics.properties": {"strict_occlusion": "true"}, } # -------------------------------------------------------------------------- # Phase 2 bench variants. C0 = every file at upstream default (explicit, so stale # instance edits can't leak in). Everything else is C1 (= T-mid) plus ONE change. # BENCH is layered on every bench variant: uncapped, vsync off, phase0 pins, # no DH world generation during runs (world is pre-generated). # -------------------------------------------------------------------------- BENCH = { "options.txt": {"maxFps": 260, "enableVsync": "false", "renderDistance": 8, "simulationDistance": 8}, "config/DistantHorizons.toml": { (DH_W, "generatorPlan"): "DISABLED", # Harness: suppress DH's "new update available" modal on every launch. ("client.advanced.autoUpdater", "enableAutoUpdater"): False, }, } def c1(extra): return [DEFAULT, extra] VARIANTS = { # player tiers (no BENCH layer) "T-default": ([DEFAULT], False), "T-deck": ([DEFAULT, DECK], False), "T-mid": ([DEFAULT], False), "T-high": ([DEFAULT, HIGH], False), # bench: composites "C0": ([], True), "C1": ([DEFAULT], True), "C1-deck": ([DEFAULT, DECK], True), "C1-high": ([DEFAULT, HIGH], True), # bench: Distant Horizons "dh-r256": (c1({"config/DistantHorizons.toml": {(DH_Q, "lodChunkRenderDistanceRadius"): 256}}), True), "dh-r192": (c1({"config/DistantHorizons.toml": {(DH_Q, "lodChunkRenderDistanceRadius"): 192}}), True), "dh-r64": (c1({"config/DistantHorizons.toml": {(DH_Q, "lodChunkRenderDistanceRadius"): 64}}), True), "dh-ssao": (c1({"config/DistantHorizons.toml": {(DH_G, "enableSsao"): True}}), True), "dh-thr4": (c1({"config/DistantHorizons.toml": {(DH_T, "numberOfThreads"): 4}}), True), "dh-qlow": (c1({"config/DistantHorizons.toml": DECK["config/DistantHorizons.toml"] | {(DH_Q, "lodChunkRenderDistanceRadius"): 128}}), True), # bench: Flywheel / ModernFix / Sable / SSRD "fw-flat": (c1({"config/flywheel-client.toml": {("flw_backends", "lightSmoothness"): "FLAT"}}), True), "fw-smooth": (c1({"config/flywheel-client.toml": {("flw_backends", "lightSmoothness"): "SMOOTH"}}), True), "mf-dynres-off": (c1({"config/modernfix-mixins.properties": {"mixin.perf.dynamic_resources": "false"}}), True), "ssrd-32": (c1({"config/ssrd-common.toml": {("", "physicsRenderDistance"): 32}}), True), "ssrd-64": (c1({"config/ssrd-common.toml": {("", "physicsRenderDistance"): 64}}), True), "ssrd-128": (c1({"config/ssrd-common.toml": {("", "physicsRenderDistance"): 128}}), True), "sable-noshade": (c1({"config/sable-client.toml": {("", "sub_level_dynamic_shading"): False}}), True), # bench: entities / lights / sound "emf-lod20": (c1({"config/entity_model_features.json": {"animationLODDistance": 20, "modelUpdateFrequency": "Average"}}), True), "emf-lod8": (c1({"config/entity_model_features.json": {"animationLODDistance": 8, "retainDetailOnLowFps": False}}), True), "ldl-fancy": (c1({"config/lambdynlights.toml": {("", "mode"): "fancy"}}), True), "ldl-fastest": (c1({"config/lambdynlights.toml": {("", "mode"): "fastest", ("light_sources", "entities"): False}}), True), "spr-up": (c1({"config/sound_physics_remastered/soundphysics.properties": { "environment_evaluation_ray_count": 32, "environment_evaluation_ray_bounces": 4}}), True), "spr-strict": (c1({"config/sound_physics_remastered/soundphysics.properties": {"strict_occlusion": "true"}}), True), "spr-nocap": (c1({"config/sound_physics_remastered/sound_rates.properties": sound_caps(-1)}), True), # bench: vanilla / Sodium "sod-thr3": (c1({"config/sodium-options.json": {"performance.chunk_builder_threads": 3}}), True), "opt-blend2": (c1({"options.txt": {"biomeBlendRadius": 2}}), True), "opt-blend0": (c1({"options.txt": {"biomeBlendRadius": 0}}), True), "opt-mip4": (c1({"options.txt": {"mipmapLevels": 4}}), True), } # -------------------------------------------------------------------------- def toml_val(v): if isinstance(v, bool): return "true" if v else "false" if isinstance(v, (int, float)): return str(v) return json.dumps(v) def apply_toml(text, ov, name): lines = text.split("\n") hdr = re.compile(r"^\s*\[([^\]]+)\]\s*$") for (section, key), val in ov.items(): cur, hits = "", [] for i, ln in enumerate(lines): m = hdr.match(ln) if m: cur = m.group(1).strip() continue if cur == section and re.match(rf"^\s*{re.escape(key)}\s*=", ln): hits.append(i) if len(hits) != 1: raise SystemExit(f"{name}: [{section}] {key}: {len(hits)} matches in base") i = hits[0] indent = re.match(r"^(\s*)", lines[i]).group(1) lines[i] = f"{indent}{key} = {toml_val(val)}" return "\n".join(lines) def apply_json(text, ov, name): data = json.loads(text) for path, val in ov.items(): node, parts = data, path.split(".") for p in parts[:-1]: node = node[p] if parts[-1] not in node: raise SystemExit(f"{name}: {path} not in base") if type(node[parts[-1]]) is not type(val): raise SystemExit(f"{name}: {path} type {type(node[parts[-1]]).__name__} != {type(val).__name__}") node[parts[-1]] = val return json.dumps(data, indent=2) + "\n" def apply_kv(text, ov, name, sep, append): lines = text.rstrip("\n").split("\n") for key, val in ov.items(): sval = toml_val(val) if isinstance(val, bool) else str(val) rx = re.compile(rf"^{re.escape(key)}{re.escape(sep)}") hits = [i for i, ln in enumerate(lines) if rx.match(ln)] if len(hits) > 1 or (not hits and not append): raise SystemExit(f"{name}: {key}: {len(hits)} matches in base") if hits: lines[hits[0]] = f"{key}{sep}{sval}" else: lines.append(f"{key}{sep}{sval}") return "\n".join(lines) + "\n" def strip(text, keys, name): lines = text.split("\n") hdr = re.compile(r"^\s*\[([^\]]+)\]\s*$") for section, key in keys: cur, hits = "", [] for i, ln in enumerate(lines): m = hdr.match(ln) if m: cur = m.group(1).strip() elif cur == section and re.match(rf"^\s*{re.escape(key)}\s*=", ln): hits.append(i) if len(hits) != 1: raise SystemExit(f"{name}: strip [{section}] {key}: {len(hits)} matches") del lines[hits[0]] return "\n".join(lines) def render(layers, name): base, fmt, append = FILES[name] text = strip(base.read_text(), STRIP.get(name, []), name) merged = {} for layer in [UPSTREAM] + layers: merged.update(layer.get(name, {})) if fmt == "toml": return apply_toml(text, merged, name), merged if fmt == "json": return apply_json(text, merged, name), merged sep = ":" if fmt == "options" else "=" return apply_kv(text, merged, name, sep, append), merged def main(): if OUT.exists(): shutil.rmtree(OUT) manifest = ["# Generated by build.py - do not edit\n", "Changed keys per variant, relative to the upstream default of each file.\n"] for vid, (layers, bench) in VARIANTS.items(): layers = list(layers) + ([BENCH] if bench else []) manifest.append(f"\n## {vid}\n") for name in FILES: text, merged = render(layers, name) dest = OUT / vid / name dest.parent.mkdir(parents=True, exist_ok=True) dest.write_text(text) for k, v in merged.items(): k = f"[{k[0]}] {k[1]}" if isinstance(k, tuple) else k manifest.append(f"- `{name}`: `{k}` = `{v}`\n") (OUT / "MANIFEST.md").write_text("".join(manifest)) print(f"wrote {len(VARIANTS)} variants x {len(FILES)} files to {OUT}") if "--ship" in sys.argv: shutil.rmtree(REPO / DO, ignore_errors=True) for src, dst in SHIP.items(): (REPO / dst).parent.mkdir(parents=True, exist_ok=True) shutil.copyfile(OUT / "T-default" / src, REPO / dst) print(f"shipped {len(SHIP)} files to {REPO / DO}; now run `packwiz refresh`") main()