master @ 253 LINES
[ HISTORY ] [ UP ]
┌─ NIX ──────────────────────────────────────────────────────────────────────┐
│ { │
│ lib, │
│ pkgs, │
│ classes, │
│ encounter, │
│ buffs, │
│ debuffs, │
│ inputs, │
│ trinket, │
│ ... │
│ }: let │
│ inherit (lib.sim.simulation) mkSim; │
│ config = import ./config.nix {inherit encounter;}; │
│ massSimFunctions = import ./mkMassSim.nix {inherit lib pkgs classes encounter bu │
│ ffs debuffs inputs;}; │
│ inherit (massSimFunctions) getAllDPSSpecs getRaceConfigs getPlayableRaces; │
│ │
│ # Generate scenarios (target count ? duration combinations) │
│ generateScenarios = targetConfigs: durations: │
│ lib.flatten (lib.mapAttrsToList ( │
│ targetCount: targetConfig: │
│ map (duration: { │
│ inherit targetCount duration; │
│ inherit (targetConfig) template; │
│ encounter = targetConfig.encounters.${duration}; │
│ }) │
│ durations │
│ ) │
│ targetConfigs); │
│ │
│ scenarios = generateScenarios config.targetConfigs config.durations; │
│ │
│ # Helper to make simulation ID │
│ makeSimID = { │
│ class, │
│ spec, │
│ phase, │
│ targetCount, │
│ duration, │
│ race ? null, │
│ trinket ? null, │
│ }: │
│ if race != null │
│ then "${class}-${spec}-${race}-${phase}-${targetCount}-${duration}" │
│ else if trinket != null │
│ then "${class}-${spec}-${toString trinket}-${phase}-${targetCount}-${duration} │
│ " │
│ else "${class}-${spec}-${phase}-${targetCount}-${duration}"; │
│ │
│ # Generate all benchmark (DPS) specs across scenarios │
│ allBenchmarkSpecs = lib.flatten (map ( │
│ phase: │
│ lib.flatten (map (scenario: let │
│ validSpecs = getAllDPSSpecs classes scenario.template phase; │
│ in │
│ map (spec: { │
│ id = makeSimID { │
│ class = spec.className; │
│ spec = spec.specName; │
│ inherit phase; │
│ inherit (scenario) targetCount duration; │
│ }; │
│ inherit (spec) className specName config; │
│ inherit phase; │
│ inherit (scenario) targetCount duration encounter; │
│ }) │
│ validSpecs) │
│ scenarios) │
│ ) │
│ config.phases); │
│ │
│ # Generate all race comparison configs │
│ allRaceConfigs = lib.flatten (map ( │
│ specConfig: │
│ lib.flatten (map (scenario: let │
│ raceConfigs = getRaceConfigs classes specConfig.class specConfig.spec sc │
│ enario.template "p1" "raid"; │
│ in │
│ map (raceConfig: { │
│ id = makeSimID { │
│ class = raceConfig.className; │
│ spec = raceConfig.specName; │
│ race = raceConfig.raceName; │
│ phase = "p1"; │
│ inherit (scenario) targetCount duration; │
│ }; │
│ inherit (raceConfig) className specName raceName config; │
│ phase = "p1"; │
│ inherit (scenario) targetCount duration encounter; │
│ }) │
│ raceConfigs) │
│ scenarios) │
│ ) │
│ config.raceComparisonSpecs); │
│ │
│ # Generate all trinket comparison configs │
│ allTrinketConfigs = lib.flatten (map ( │
│ specConfig: │
│ lib.flatten (map (scenario: let │
│ # Get the spec's default race configuration │
│ spec = classes.${specConfig.class}.${specConfig.spec}; │
│ defaultRace = spec.defaultRace; │
│ baseConfig = │
│ if │
│ lib.hasAttr "template" spec │
│ && lib.hasAttr defaultRace spec.template │
│ && lib.hasAttr "p1" spec.template.${defaultRace} │
│ && lib.hasAttr "raid" spec.template.${defaultRace}.p1 │
│ && lib.hasAttr scenario.template spec.template.${defaultRace}.p1.rai │
│ d │
│ then spec.template.${defaultRace}.p1.raid.${scenario.template} │
│ else throw "Template ${scenario.template} not found for ${specConfig.c │
│ lass}/${specConfig.spec}/${defaultRace}"; │
│ │
│ # Get trinket list for this category from presets.p1 │
│ trinketList = trinket.presets.p1.${specConfig.trinketCategory} or []; │
│ in │
│ map (trinketID: { │
│ id = makeSimID { │
│ class = specConfig.class; │
│ spec = specConfig.spec; │
│ trinket = trinketID; │
│ phase = "p1"; │
│ inherit (scenario) targetCount duration; │
│ }; │
│ className = specConfig.class; │
│ specName = specConfig.spec; │
│ inherit trinketID; │
│ # Create config with trinket equipped │
│ config = │
│ baseConfig │
│ // { │
│ equipment = │
│ baseConfig.equipment │
│ // { │
│ items = let │
│ items = baseConfig.equipment.items; │
│ # Replace trinket slot 12 (first trinket slot) │
│ replaceAt = index: value: list: │
│ lib.imap0 (i: v: │
│ if i == index │
│ then value │
│ else v) │
│ list; │
│ in │
│ replaceAt 12 {id = trinketID;} items; │
│ }; │
│ }; │
│ phase = "p1"; │
│ inherit (scenario) targetCount duration encounter; │
│ }) │
│ trinketList) │
│ scenarios) │
│ ) │
│ config.trinketComparisonSpecs); │
│ │
│ wowsimsCommit = inputs.wowsims-upstream.shortRev; │
│ │
│ # Create class-specific buff adjustments │
│ getClassSpecificBuffs = class: │
│ if class == "ClassWarrior" │
│ then buffs.full // {skullBannerCount = 1;} │
│ else if class == "ClassShaman" │
│ then buffs.full // {stormlashTotemCount = 3;} │
│ else buffs.full; │
│ │
│ # Main derivation that generates all input files │
│ simInputs = pkgs.runCommand "sim-inputs" {} '' │
│ mkdir -p $out/inputs/{benchmark,race,trinket} │
│ │
│ echo "Generating benchmark simulation inputs..." │
│ ${lib.concatMapStringsSep "\n" (spec: '' │
│ cat > "$out/inputs/benchmark/${spec.id}.json" <<'EOF' │
│ ${mkSim { │
│ iterations = config.common.iterations; │
│ player = spec.config; │
│ buffs = getClassSpecificBuffs spec.config.class; │
│ debuffs = debuffs.full; │
│ encounter = spec.encounter; │
│ }} │
│ EOF │
│ '') │
│ allBenchmarkSpecs} │
│ │
│ echo "Generating race comparison inputs..." │
│ ${lib.concatMapStringsSep "\n" (raceConfig: '' │
│ cat > "$out/inputs/race/${raceConfig.id}.json" <<'EOF' │
│ ${mkSim { │
│ iterations = config.common.iterations; │
│ player = raceConfig.config; │
│ buffs = getClassSpecificBuffs raceConfig.config.class; │
│ debuffs = debuffs.full; │
│ encounter = raceConfig.encounter; │
│ }} │
│ EOF │
│ '') │
│ allRaceConfigs} │
│ │
│ echo "Generating trinket comparison inputs..." │
│ ${lib.concatMapStringsSep "\n" (trinketConfig: '' │
│ cat > "$out/inputs/trinket/${trinketConfig.id}.json" <<'EOF' │
│ ${mkSim { │
│ iterations = config.common.iterations; │
│ player = trinketConfig.config; │
│ buffs = getClassSpecificBuffs trinketConfig.config.class; │
│ debuffs = debuffs.full; │
│ encounter = trinketConfig.encounter; │
│ }} │
│ EOF │
│ '') │
│ allTrinketConfigs} │
│ │
│ echo "Generating manifest..." │
│ cat > "$out/inputs/manifest.json" <<'EOF' │
│ ${builtins.toJSON { │
│ version = wowsimsCommit; │
│ simulations = { │
│ benchmark = │
│ map (s: { │
│ inherit (s) id className specName phase targetCount duration; │
│ file = "benchmark/${s.id}.json"; │
│ class = s.className; │
│ spec = s.specName; │
│ }) │
│ allBenchmarkSpecs; │
│ race = │
│ map (r: { │
│ inherit (r) id className specName raceName phase targetCount duration; │
│ file = "race/${r.id}.json"; │
│ class = r.className; │
│ spec = r.specName; │
│ race = r.raceName; │
│ }) │
│ allRaceConfigs; │
│ trinket = │
│ map (t: { │
│ inherit (t) id className specName trinketID phase targetCount duration │
│ ; │
│ file = "trinket/${t.id}.json"; │
│ class = t.className; │
│ spec = t.specName; │
│ trinket = t.trinketID; │
│ }) │
│ allTrinketConfigs; │
│ }; │
│ }} │
│ EOF │
│ │
│ echo "Generated simulation inputs:" │
│ echo " Benchmark: ${toString (lib.length allBenchmarkSpecs)} inputs" │
│ echo " Race: ${toString (lib.length allRaceConfigs)} inputs" │
│ echo " Trinket: ${toString (lib.length allTrinketConfigs)} inputs" │
│ ''; │
│ in { │
│ inherit simInputs; │
│ # Export for debugging │
│ inherit allBenchmarkSpecs allRaceConfigs allTrinketConfigs; │
│ } │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ NIX ────────────────────────────────┐
│ { │
│ lib, │
│ pkgs, │
│ classes, │
│ encounter, │
│ buffs, │
│ debuffs, │
│ inputs, │
│ trinket, │
│ ... │
│ }: let │
│ inherit (lib.sim.simulation) mkSim; │
│ config = import ./config.nix {inherit enco │
│ unter;}; │
│ massSimFunctions = import ./mkMassSim.nix │
│ {inherit lib pkgs classes encounter buffs de │
│ buffs inputs;}; │
│ inherit (massSimFunctions) getAllDPSSpecs │
│ getRaceConfigs getPlayableRaces; │
│ │
│ # Generate scenarios (target count ? durat │
│ ion combinations) │
│ generateScenarios = targetConfigs: duratio │
│ ns: │
│ lib.flatten (lib.mapAttrsToList ( │
│ targetCount: targetConfig: │
│ map (duration: { │
│ inherit targetCount duration; │
│ inherit (targetConfig) template; │
│ encounter = targetConfig.encount │
│ ers.${duration}; │
│ }) │
│ durations │
│ ) │
│ targetConfigs); │
│ │
│ scenarios = generateScenarios config.targe │
│ tConfigs config.durations; │
│ │
│ # Helper to make simulation ID │
│ makeSimID = { │
│ class, │
│ spec, │
│ phase, │
│ targetCount, │
│ duration, │
│ race ? null, │
│ trinket ? null, │
│ }: │
│ if race != null │
│ then "${class}-${spec}-${race}-${phase}- │
│ ${targetCount}-${duration}" │
│ else if trinket != null │
│ then "${class}-${spec}-${toString trinke │
│ t}-${phase}-${targetCount}-${duration}" │
│ else "${class}-${spec}-${phase}-${target │
│ Count}-${duration}"; │
│ │
│ # Generate all benchmark (DPS) specs acros │
│ s scenarios │
│ allBenchmarkSpecs = lib.flatten (map ( │
│ phase: │
│ lib.flatten (map (scenario: let │
│ validSpecs = getAllDPSSpecs classe │
│ s scenario.template phase; │
│ in │
│ map (spec: { │
│ id = makeSimID { │
│ class = spec.className; │
│ spec = spec.specName; │
│ inherit phase; │
│ inherit (scenario) targetCount │
│ duration; │
│ }; │
│ inherit (spec) className specNam │
│ e config; │
│ inherit phase; │
│ inherit (scenario) targetCount d │
│ uration encounter; │
│ }) │
│ validSpecs) │
│ scenarios) │
│ ) │
│ config.phases); │
│ │
│ # Generate all race comparison configs │
│ allRaceConfigs = lib.flatten (map ( │
│ specConfig: │
│ lib.flatten (map (scenario: let │
│ raceConfigs = getRaceConfigs class │
│ es specConfig.class specConfig.spec scenario │
│ .template "p1" "raid"; │
│ in │
│ map (raceConfig: { │
│ id = makeSimID { │
│ class = raceConfig.className; │
│ spec = raceConfig.specName; │
│ race = raceConfig.raceName; │
│ phase = "p1"; │
│ inherit (scenario) targetCount │
│ duration; │
│ }; │
│ inherit (raceConfig) className s │
│ pecName raceName config; │
│ phase = "p1"; │
│ inherit (scenario) targetCount d │
│ uration encounter; │
│ }) │
│ raceConfigs) │
│ scenarios) │
│ ) │
│ config.raceComparisonSpecs); │
│ │
│ # Generate all trinket comparison configs │
│ allTrinketConfigs = lib.flatten (map ( │
│ specConfig: │
│ lib.flatten (map (scenario: let │
│ # Get the spec's default race conf │
│ iguration │
│ spec = classes.${specConfig.class} │
│ .${specConfig.spec}; │
│ defaultRace = spec.defaultRace; │
│ baseConfig = │
│ if │
│ lib.hasAttr "template" spec │
│ && lib.hasAttr defaultRace spe │
│ c.template │
│ && lib.hasAttr "p1" spec.templ │
│ ate.${defaultRace} │
│ && lib.hasAttr "raid" spec.tem │
│ plate.${defaultRace}.p1 │
│ && lib.hasAttr scenario.templa │
│ te spec.template.${defaultRace}.p1.raid │
│ then spec.template.${defaultRace │
│ }.p1.raid.${scenario.template} │
│ else throw "Template ${scenario. │
│ template} not found for ${specConfig.class}/ │
│ ${specConfig.spec}/${defaultRace}"; │
│ │
│ # Get trinket list for this catego │
│ ry from presets.p1 │
│ trinketList = trinket.presets.p1.$ │
│ {specConfig.trinketCategory} or []; │
│ in │
│ map (trinketID: { │
│ id = makeSimID { │
│ class = specConfig.class; │
│ spec = specConfig.spec; │
│ trinket = trinketID; │
│ phase = "p1"; │
│ inherit (scenario) targetCount │
│ duration; │
│ }; │
│ className = specConfig.class; │
│ specName = specConfig.spec; │
│ inherit trinketID; │
│ # Create config with trinket equ │
│ ipped │
│ config = │
│ baseConfig │
│ // { │
│ equipment = │
│ baseConfig.equipment │
│ // { │
│ items = let │
│ items = baseConfig.equ │
│ ipment.items; │
│ # Replace trinket slot │
│ 12 (first trinket slot) │
│ replaceAt = index: val │
│ ue: list: │
│ lib.imap0 (i: v: │
│ if i == index │
│ then value │
│ else v) │
│ list; │
│ in │
│ replaceAt 12 {id = tri │
│ nketID;} items; │
│ }; │
│ }; │
│ phase = "p1"; │
│ inherit (scenario) targetCount d │
│ uration encounter; │
│ }) │
│ trinketList) │
│ scenarios) │
│ ) │
│ config.trinketComparisonSpecs); │
│ │
│ wowsimsCommit = inputs.wowsims-upstream.sh │
│ ortRev; │
│ │
│ # Create class-specific buff adjustments │
│ getClassSpecificBuffs = class: │
│ if class == "ClassWarrior" │
│ then buffs.full // {skullBannerCount = 1 │
│ ;} │
│ else if class == "ClassShaman" │
│ then buffs.full // {stormlashTotemCount │
│ = 3;} │
│ else buffs.full; │
│ │
│ # Main derivation that generates all input │
│ files │
│ simInputs = pkgs.runCommand "sim-inputs" { │
│ } '' │
│ mkdir -p $out/inputs/{benchmark,race,tri │
│ nket} │
│ │
│ echo "Generating benchmark simulation in │
│ puts..." │
│ ${lib.concatMapStringsSep "\n" (spec: '' │
│ cat > "$out/inputs/benchmark/${spec. │
│ id}.json" <<'EOF' │
│ ${mkSim { │
│ iterations = config.common.iterati │
│ ons; │
│ player = spec.config; │
│ buffs = getClassSpecificBuffs spec │
│ .config.class; │
│ debuffs = debuffs.full; │
│ encounter = spec.encounter; │
│ }} │
│ EOF │
│ '') │
│ allBenchmarkSpecs} │
│ │
│ echo "Generating race comparison inputs. │
│ .." │
│ ${lib.concatMapStringsSep "\n" (raceConf │
│ ig: '' │
│ cat > "$out/inputs/race/${raceConfig │
│ .id}.json" <<'EOF' │
│ ${mkSim { │
│ iterations = config.common.iterati │
│ ons; │
│ player = raceConfig.config; │
│ buffs = getClassSpecificBuffs race │
│ Config.config.class; │
│ debuffs = debuffs.full; │
│ encounter = raceConfig.encounter; │
│ }} │
│ EOF │
│ '') │
│ allRaceConfigs} │
│ │
│ echo "Generating trinket comparison inpu │
│ ts..." │
│ ${lib.concatMapStringsSep "\n" (trinketC │
│ onfig: '' │
│ cat > "$out/inputs/trinket/${trinket │
│ Config.id}.json" <<'EOF' │
│ ${mkSim { │
│ iterations = config.common.iterati │
│ ons; │
│ player = trinketConfig.config; │
│ buffs = getClassSpecificBuffs trin │
│ ketConfig.config.class; │
│ debuffs = debuffs.full; │
│ encounter = trinketConfig.encounte │
│ r; │
│ }} │
│ EOF │
│ '') │
│ allTrinketConfigs} │
│ │
│ echo "Generating manifest..." │
│ cat > "$out/inputs/manifest.json" <<'EOF │
│ ' │
│ ${builtins.toJSON { │
│ version = wowsimsCommit; │
│ simulations = { │
│ benchmark = │
│ map (s: { │
│ inherit (s) id className specNam │
│ e phase targetCount duration; │
│ file = "benchmark/${s.id}.json"; │
│ class = s.className; │
│ spec = s.specName; │
│ }) │
│ allBenchmarkSpecs; │
│ race = │
│ map (r: { │
│ inherit (r) id className specNam │
│ e raceName phase targetCount duration; │
│ file = "race/${r.id}.json"; │
│ class = r.className; │
│ spec = r.specName; │
│ race = r.raceName; │
│ }) │
│ allRaceConfigs; │
│ trinket = │
│ map (t: { │
│ inherit (t) id className specNam │
│ e trinketID phase targetCount duration; │
│ file = "trinket/${t.id}.json"; │
│ class = t.className; │
│ spec = t.specName; │
│ trinket = t.trinketID; │
│ }) │
│ allTrinketConfigs; │
│ }; │
│ }} │
│ EOF │
│ │
│ echo "Generated simulation inputs:" │
│ echo " Benchmark: ${toString (lib.lengt │
│ h allBenchmarkSpecs)} inputs" │
│ echo " Race: ${toString (lib.length all │
│ RaceConfigs)} inputs" │
│ echo " Trinket: ${toString (lib.length │
│ allTrinketConfigs)} inputs" │
│ ''; │
│ in { │
│ inherit simInputs; │
│ # Export for debugging │
│ inherit allBenchmarkSpecs allRaceConfigs a │
│ llTrinketConfigs; │
│ } │
└──────────────────────────────────────────────┘
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET