HASH 61373acd2b71
DATE 2025-11-13
SUBJECT simulation: WIP trinket logic for professions
FILES 6 CHANGED
HASH 61373acd2b71
DATE 2025-11-13
SUBJECT simulation: WIP trinket logic for
professions
FILES 6 CHANGED
┌─ nix/lib/default.nix ──────────────────────────────────────────────────────┐
│ diff --git a/nix/lib/default.nix b/nix/lib/default.nix │
│ index cb1fe98..7c38391 100644 │
│ --- a/nix/lib/default.nix │
│ +++ b/nix/lib/default.nix │
│ @@ -12,6 +12,6 @@ │
│ party = import ./party.nix {inherit lib;}; │
│ classes = import ./classes.nix {inherit lib;}; │
│ itemDatabase = import ./itemDatabase.nix {inherit inputs lib;}; │
│ - trinket = import ./trinket.nix {inherit lib;}; │
│ + trinket = import ./trinket.nix {inherit inputs lib;}; │
│ shellUtils = import ./shell-utils.nix {inherit lib;}; │
│ } │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ nix/lib/default.nix ────────────────┐
│ diff --git a/nix/lib/default.nix b/nix/lib/d │
│ efault.nix │
│ index cb1fe98..7c38391 100644 │
│ --- a/nix/lib/default.nix │
│ +++ b/nix/lib/default.nix │
│ @@ -12,6 +12,6 @@ │
│ party = import ./party.nix {inherit lib;} │
│ ; │
│ classes = import ./classes.nix {inherit l │
│ ib;}; │
│ itemDatabase = import ./itemDatabase.nix │
│ {inherit inputs lib;}; │
│ - trinket = import ./trinket.nix {inherit l │
│ ib;}; │
│ + trinket = import ./trinket.nix {inherit i │
│ nputs lib;}; │
│ shellUtils = import ./shell-utils.nix {in │
│ herit lib;}; │
│ } │
└──────────────────────────────────────────────┘
┌─ nix/lib/trinket.nix ──────────────────────────────────────────────────────┐
│ diff --git a/nix/lib/trinket.nix b/nix/lib/trinket.nix │
│ index d122798..59cbc9e 100644 │
│ --- a/nix/lib/trinket.nix │
│ +++ b/nix/lib/trinket.nix │
│ @@ -1,4 +1,22 @@ │
│ -{lib, ...}: let │
│ +{lib, inputs, ...}: let │
│ + wowsimsDb = lib.importJSON "${inputs.wowsims}/assets/database/db.json"; │
│ + │
│ + professionEnchantsByProfession = let │
│ + enchantsByEffectId = lib.listToAttrs (map (enchant: { │
│ + name = toString enchant.effectId; │
│ + value = enchant; │
│ + }) wowsimsDb.enchants); │
│ + in { │
│ + "Engineering" = lib.filter (e: e.requiredProfession or null == 4) wowsimsDb.e │
│ nchants; │
│ + "Tailoring" = lib.filter (e: e.requiredProfession or null == 11) wowsimsDb.en │
│ chants; │
│ + "Leatherworking" = lib.filter (e: e.requiredProfession or null == 8) wowsimsD │
│ b.enchants; │
│ + "Inscription" = lib.filter (e: e.requiredProfession or null == 6) wowsimsDb.e │
│ nchants; │
│ + "Enchanting" = lib.filter (e: e.requiredProfession or null == 3) wowsimsDb.en │
│ chants; │
│ + }; │
│ + │
│ + professionEnchantEffectIds = lib.mapAttrs (prof: enchants: │
│ + map (e: e.effectId) enchants │
│ + ) professionEnchantsByProfession; │
│ # Remove trinkets from gearset (set slots 12-13 to empty objects) │
│ removeTrinkets = gearset: │
│ if !(gearset ? items) │
│ @@ -38,6 +56,25 @@ │
│ # Returns a list of gearsets, each with one trinket in slot 13 │
│ generateTrinketGearsets = baselineGearset: trinketIds: │
│ map (trinketId: addTrinket baselineGearset trinketId) trinketIds; │
│ + │
│ + # Remove profession-specific enchants from gearset │
│ + # Note: This operates on raw equipment BEFORE enrichment, so item.enchant is ju │
│ st a number (effectId) │
│ + removeProfessionEnchants = gearset: professionName: │
│ + if !(gearset ? items) || !(professionEnchantEffectIds ? ${professionName}) │
│ + then gearset │
│ + else let │
│ + enchantIds = professionEnchantEffectIds.${professionName}; │
│ + hasProfessionEnchant = item: │
│ + (item ? enchant) && (builtins.elem item.enchant enchantIds); │
│ + in │
│ + gearset │
│ + // { │
│ + items = map (item: │
│ + if hasProfessionEnchant item │
│ + then builtins.removeAttrs item ["enchant"] │
│ + else item │
│ + ) gearset.items; │
│ + }; │
│ in { │
│ - inherit removeTrinkets addTrinket generateTrinketGearsets; │
│ + inherit removeTrinkets addTrinket generateTrinketGearsets removeProfessionEncha │
│ nts; │
│ } │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ nix/lib/trinket.nix ────────────────┐
│ diff --git a/nix/lib/trinket.nix b/nix/lib/t │
│ rinket.nix │
│ index d122798..59cbc9e 100644 │
│ --- a/nix/lib/trinket.nix │
│ +++ b/nix/lib/trinket.nix │
│ @@ -1,4 +1,22 @@ │
│ -{lib, ...}: let │
│ +{lib, inputs, ...}: let │
│ + wowsimsDb = lib.importJSON "${inputs.wows │
│ ims}/assets/database/db.json"; │
│ + │
│ + professionEnchantsByProfession = let │
│ + enchantsByEffectId = lib.listToAttrs (m │
│ ap (enchant: { │
│ + name = toString enchant.effectId; │
│ + value = enchant; │
│ + }) wowsimsDb.enchants); │
│ + in { │
│ + "Engineering" = lib.filter (e: e.requir │
│ edProfession or null == 4) wowsimsDb.enchant │
│ s; │
│ + "Tailoring" = lib.filter (e: e.required │
│ Profession or null == 11) wowsimsDb.enchants │
│ ; │
│ + "Leatherworking" = lib.filter (e: e.req │
│ uiredProfession or null == 8) wowsimsDb.ench │
│ ants; │
│ + "Inscription" = lib.filter (e: e.requir │
│ edProfession or null == 6) wowsimsDb.enchant │
│ s; │
│ + "Enchanting" = lib.filter (e: e.require │
│ dProfession or null == 3) wowsimsDb.enchants │
│ ; │
│ + }; │
│ + │
│ + professionEnchantEffectIds = lib.mapAttrs │
│ (prof: enchants: │
│ + map (e: e.effectId) enchants │
│ + ) professionEnchantsByProfession; │
│ # Remove trinkets from gearset (set slots │
│ 12-13 to empty objects) │
│ removeTrinkets = gearset: │
│ if !(gearset ? items) │
│ @@ -38,6 +56,25 @@ │
│ # Returns a list of gearsets, each with o │
│ ne trinket in slot 13 │
│ generateTrinketGearsets = baselineGearset │
│ : trinketIds: │
│ map (trinketId: addTrinket baselineGear │
│ set trinketId) trinketIds; │
│ + │
│ + # Remove profession-specific enchants fro │
│ m gearset │
│ + # Note: This operates on raw equipment BE │
│ FORE enrichment, so item.enchant is just a n │
│ umber (effectId) │
│ + removeProfessionEnchants = gearset: profe │
│ ssionName: │
│ + if !(gearset ? items) || !(professionEn │
│ chantEffectIds ? ${professionName}) │
│ + then gearset │
│ + else let │
│ + enchantIds = professionEnchantEffectI │
│ ds.${professionName}; │
│ + hasProfessionEnchant = item: │
│ + (item ? enchant) && (builtins.elem │
│ item.enchant enchantIds); │
│ + in │
│ + gearset │
│ + // { │
│ + items = map (item: │
│ + if hasProfessionEnchant item │
│ + then builtins.removeAttrs item [" │
│ enchant"] │
│ + else item │
│ + ) gearset.items; │
│ + }; │
│ in { │
│ - inherit removeTrinkets addTrinket generat │
│ eTrinketGearsets; │
│ + inherit removeTrinkets addTrinket generat │
│ eTrinketGearsets removeProfessionEnchants; │
│ } │
└──────────────────────────────────────────────┘
┌─ nix/pkgs/default.nix ─────────────────────────────────────────────────────┐
│ diff --git a/nix/pkgs/default.nix b/nix/pkgs/default.nix │
│ index 6a77513..17bf37a 100644 │
│ --- a/nix/pkgs/default.nix │
│ +++ b/nix/pkgs/default.nix │
│ @@ -39,6 +39,7 @@ │
│ // { │
│ inherit ookstats; │
│ allSimulations = simulation.generateAllSimulationsScript pkgs; │
│ + simInputs = simulation.generateSimInputs pkgs; │
│ testRaid = callPackage ./testRaid.nix { │
│ inherit lib classes encounter buffs debuffs wowsimcli; │
│ }; │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ nix/pkgs/default.nix ───────────────┐
│ diff --git a/nix/pkgs/default.nix b/nix/pkgs │
│ /default.nix │
│ index 6a77513..17bf37a 100644 │
│ --- a/nix/pkgs/default.nix │
│ +++ b/nix/pkgs/default.nix │
│ @@ -39,6 +39,7 @@ │
│ // { │
│ inherit ookstats; │
│ allSimulations = simulation.generat │
│ eAllSimulationsScript pkgs; │
│ + simInputs = simulation.generateSimI │
│ nputs pkgs; │
│ testRaid = callPackage ./testRaid.n │
│ ix { │
│ inherit lib classes encounter buf │
│ fs debuffs wowsimcli; │
│ }; │
└──────────────────────────────────────────────┘
┌─ nix/simulation/default.nix ───────────────────────────────────────────────┐
│ diff --git a/nix/simulation/default.nix b/nix/simulation/default.nix │
│ index 1c2283d..26bda0a 100644 │
│ --- a/nix/simulation/default.nix │
│ +++ b/nix/simulation/default.nix │
│ @@ -142,9 +142,15 @@ │
│ runtimeInputs = [pkgs.coreutils pkgs.findutils]; │
│ }; │
│ │
│ + # Function to generate simulation inputs with pkgs │
│ + generateSimInputs = pkgs: let │
│ + simInputsModule = import ./inputs.nix {inherit lib pkgs classes encounter buf │
│ fs debuffs inputs trinket;}; │
│ + in │
│ + simInputsModule.simInputs; │
│ + │
│ simulation = { │
│ # Generation functions that take pkgs as parameter │
│ - inherit generateMassSimulations generateRaceComparisons generateTrinketCompar │
│ isons generateAllSimulationsScript generateTestGroupSim; │
│ + inherit generateMassSimulations generateRaceComparisons generateTrinketCompar │
│ isons generateAllSimulationsScript generateTestGroupSim generateSimInputs; │
│ │
│ # Configuration and utilities │
│ inherit config generateScenarios scenarios; │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ nix/simulation/default.nix ─────────┐
│ diff --git a/nix/simulation/default.nix b/ni │
│ x/simulation/default.nix │
│ index 1c2283d..26bda0a 100644 │
│ --- a/nix/simulation/default.nix │
│ +++ b/nix/simulation/default.nix │
│ @@ -142,9 +142,15 @@ │
│ runtimeInputs = [pkgs.coreutils pkgs. │
│ findutils]; │
│ }; │
│ │
│ + # Function to generate simulation inputs │
│ with pkgs │
│ + generateSimInputs = pkgs: let │
│ + simInputsModule = import ./inputs.nix { │
│ inherit lib pkgs classes encounter buffs deb │
│ uffs inputs trinket;}; │
│ + in │
│ + simInputsModule.simInputs; │
│ + │
│ simulation = { │
│ # Generation functions that take pkgs a │
│ s parameter │
│ - inherit generateMassSimulations generat │
│ eRaceComparisons generateTrinketComparisons │
│ generateAllSimulationsScript generateTestGro │
│ upSim; │
│ + inherit generateMassSimulations generat │
│ eRaceComparisons generateTrinketComparisons │
│ generateAllSimulationsScript generateTestGro │
│ upSim generateSimInputs; │
│ │
│ # Configuration and utilities │
│ inherit config generateScenarios scenar │
│ ios; │
└──────────────────────────────────────────────┘
┌─ nix/simulation/inputs.nix ────────────────────────────────────────────────┐
│ diff --git a/nix/simulation/inputs.nix b/nix/simulation/inputs.nix │
│ new file mode 100644 │
│ index 0000000..d0a9218 │
│ --- /dev/null │
│ +++ b/nix/simulation/inputs.nix │
│ @@ -0,0 +1,252 @@ │
│ +{ │
│ + 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 b │
│ uffs 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 s │
│ cenario.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.ra │
│ id │
│ + 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 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 duratio │
│ n; │
│ + 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/simulation/inputs.nix ──────────┐
│ diff --git a/nix/simulation/inputs.nix b/nix │
│ /simulation/inputs.nix │
│ new file mode 100644 │
│ index 0000000..d0a9218 │
│ --- /dev/null │
│ +++ b/nix/simulation/inputs.nix │
│ @@ -0,0 +1,252 @@ │
│ +{ │
│ + lib, │
│ + pkgs, │
│ + classes, │
│ + encounter, │
│ + buffs, │
│ + debuffs, │
│ + inputs, │
│ + trinket, │
│ + ... │
│ +}: let │
│ + inherit (lib.sim.simulation) mkSim; │
│ + config = import ./config.nix {inherit enc │
│ ounter;}; │
│ + massSimFunctions = import ./mkMassSim.nix │
│ {inherit lib pkgs classes encounter buffs d │
│ ebuffs inputs;}; │
│ + inherit (massSimFunctions) getAllDPSSpecs │
│ getRaceConfigs getPlayableRaces; │
│ + │
│ + # Generate scenarios (target count ? dura │
│ tion combinations) │
│ + generateScenarios = targetConfigs: durati │
│ ons: │
│ + lib.flatten (lib.mapAttrsToList ( │
│ + targetCount: targetConfig: │
│ + map (duration: { │
│ + inherit targetCount duration; │
│ + inherit (targetConfig) template │
│ ; │
│ + encounter = targetConfig.encoun │
│ ters.${duration}; │
│ + }) │
│ + durations │
│ + ) │
│ + targetConfigs); │
│ + │
│ + scenarios = generateScenarios config.targ │
│ etConfigs 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 trink │
│ et}-${phase}-${targetCount}-${duration}" │
│ + else "${class}-${spec}-${phase}-${targe │
│ tCount}-${duration}"; │
│ + │
│ + # Generate all benchmark (DPS) specs acro │
│ ss scenarios │
│ + allBenchmarkSpecs = lib.flatten (map ( │
│ + phase: │
│ + lib.flatten (map (scenario: let │
│ + validSpecs = getAllDPSSpecs class │
│ es scenario.template phase; │
│ + in │
│ + map (spec: { │
│ + id = makeSimID { │
│ + class = spec.className; │
│ + spec = spec.specName; │
│ + inherit phase; │
│ + inherit (scenario) targetCoun │
│ t duration; │
│ + }; │
│ + inherit (spec) className specNa │
│ me 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 clas │
│ ses specConfig.class specConfig.spec scenari │
│ o.template "p1" "raid"; │
│ + in │
│ + map (raceConfig: { │
│ + id = makeSimID { │
│ + class = raceConfig.className; │
│ + spec = raceConfig.specName; │
│ + race = raceConfig.raceName; │
│ + phase = "p1"; │
│ + inherit (scenario) targetCoun │
│ t 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 con │
│ figuration │
│ + spec = classes.${specConfig.class │
│ }.${specConfig.spec}; │
│ + defaultRace = spec.defaultRace; │
│ + baseConfig = │
│ + if │
│ + lib.hasAttr "template" spec │
│ + && lib.hasAttr defaultRace sp │
│ ec.template │
│ + && lib.hasAttr "p1" spec.temp │
│ late.${defaultRace} │
│ + && lib.hasAttr "raid" spec.te │
│ mplate.${defaultRace}.p1 │
│ + && lib.hasAttr scenario.templ │
│ ate spec.template.${defaultRace}.p1.raid │
│ + then spec.template.${defaultRac │
│ e}.p1.raid.${scenario.template} │
│ + else throw "Template ${scenario │
│ .template} not found for ${specConfig.class} │
│ /${specConfig.spec}/${defaultRace}"; │
│ + │
│ + # Get trinket list for this categ │
│ ory 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) targetCoun │
│ t duration; │
│ + }; │
│ + className = specConfig.class; │
│ + specName = specConfig.spec; │
│ + inherit trinketID; │
│ + # Create config with trinket eq │
│ uipped │
│ + config = │
│ + baseConfig │
│ + // { │
│ + equipment = │
│ + baseConfig.equipment │
│ + // { │
│ + items = let │
│ + items = baseConfig.eq │
│ uipment.items; │
│ + # Replace trinket slo │
│ t 12 (first trinket slot) │
│ + replaceAt = index: va │
│ lue: list: │
│ + lib.imap0 (i: v: │
│ + if i == index │
│ + then value │
│ + else v) │
│ + list; │
│ + in │
│ + replaceAt 12 {id = tr │
│ inketID;} items; │
│ + }; │
│ + }; │
│ + phase = "p1"; │
│ + inherit (scenario) targetCount │
│ duration encounter; │
│ + }) │
│ + trinketList) │
│ + scenarios) │
│ + ) │
│ + config.trinketComparisonSpecs); │
│ + │
│ + wowsimsCommit = inputs.wowsims-upstream.s │
│ hortRev; │
│ + │
│ + # 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 inpu │
│ t files │
│ + simInputs = pkgs.runCommand "sim-inputs" │
│ {} '' │
│ + mkdir -p $out/inputs/{benchmark,race,tr │
│ inket} │
│ + │
│ + echo "Generating benchmark simulation i │
│ nputs..." │
│ + ${lib.concatMapStringsSep "\n" (spec: ' │
│ ' │
│ + cat > "$out/inputs/benchmark/${spec │
│ .id}.json" <<'EOF' │
│ + ${mkSim { │
│ + iterations = config.common.iterat │
│ ions; │
│ + player = spec.config; │
│ + buffs = getClassSpecificBuffs spe │
│ c.config.class; │
│ + debuffs = debuffs.full; │
│ + encounter = spec.encounter; │
│ + }} │
│ + EOF │
│ + '') │
│ + allBenchmarkSpecs} │
│ + │
│ + echo "Generating race comparison inputs │
│ ..." │
│ + ${lib.concatMapStringsSep "\n" (raceCon │
│ fig: '' │
│ + cat > "$out/inputs/race/${raceConfi │
│ g.id}.json" <<'EOF' │
│ + ${mkSim { │
│ + iterations = config.common.iterat │
│ ions; │
│ + player = raceConfig.config; │
│ + buffs = getClassSpecificBuffs rac │
│ eConfig.config.class; │
│ + debuffs = debuffs.full; │
│ + encounter = raceConfig.encounter; │
│ + }} │
│ + EOF │
│ + '') │
│ + allRaceConfigs} │
│ + │
│ + echo "Generating trinket comparison inp │
│ uts..." │
│ + ${lib.concatMapStringsSep "\n" (trinket │
│ Config: '' │
│ + cat > "$out/inputs/trinket/${trinke │
│ tConfig.id}.json" <<'EOF' │
│ + ${mkSim { │
│ + iterations = config.common.iterat │
│ ions; │
│ + player = trinketConfig.config; │
│ + buffs = getClassSpecificBuffs tri │
│ nketConfig.config.class; │
│ + debuffs = debuffs.full; │
│ + encounter = trinketConfig.encount │
│ er; │
│ + }} │
│ + EOF │
│ + '') │
│ + allTrinketConfigs} │
│ + │
│ + echo "Generating manifest..." │
│ + cat > "$out/inputs/manifest.json" <<'EO │
│ F' │
│ + ${builtins.toJSON { │
│ + version = wowsimsCommit; │
│ + simulations = { │
│ + benchmark = │
│ + map (s: { │
│ + inherit (s) id className specNa │
│ me phase targetCount duration; │
│ + file = "benchmark/${s.id}.json" │
│ ; │
│ + class = s.className; │
│ + spec = s.specName; │
│ + }) │
│ + allBenchmarkSpecs; │
│ + race = │
│ + map (r: { │
│ + inherit (r) id className specNa │
│ me 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 specNa │
│ me 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.leng │
│ th allBenchmarkSpecs)} inputs" │
│ + echo " Race: ${toString (lib.length al │
│ lRaceConfigs)} inputs" │
│ + echo " Trinket: ${toString (lib.length │
│ allTrinketConfigs)} inputs" │
│ + ''; │
│ +in { │
│ + inherit simInputs; │
│ + # Export for debugging │
│ + inherit allBenchmarkSpecs allRaceConfigs │
│ allTrinketConfigs; │
│ +} │
└──────────────────────────────────────────────┘
┌─ nix/simulation/mkTrinketComparison.nix ───────────────────────────────────┐
│ diff --git a/nix/simulation/mkTrinketComparison.nix b/nix/simulation/mkTrinketComp │
│ arison.nix │
│ index 7a670aa..0aa850f 100644 │
│ --- a/nix/simulation/mkTrinketComparison.nix │
│ +++ b/nix/simulation/mkTrinketComparison.nix │
│ @@ -75,10 +75,24 @@ │
│ # Modify profession if trinket requires it │
│ configWithProfession = │
│ if requiredProfession != null │
│ - then │
│ + then let │
│ + # Determine which profession is being replaced │
│ + droppedProfession = │
│ + if baseConfig.profession2 != requiredProfession │
│ + then baseConfig.profession2 │
│ + else if baseConfig.profession1 != requiredProfession │
│ + then baseConfig.profession1 │
│ + else null; │
│ + │
│ + # Remove enchants from the dropped profession │
│ + cleanedGearset = │
│ + if droppedProfession != null │
│ + then trinketLib.removeProfessionEnchants gearset droppedProfession │
│ + else gearset; │
│ + in │
│ baseConfig │
│ // { │
│ - equipment = gearset; │
│ + equipment = cleanedGearset; │
│ profession2 = requiredProfession; │
│ } │
│ else baseConfig // {equipment = gearset;}; │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...ation/mkTrinketComparison.nix ───┐
│ diff --git a/nix/simulation/mkTrinketCompari │
│ son.nix b/nix/simulation/mkTrinketComparison │
│ .nix │
│ index 7a670aa..0aa850f 100644 │
│ --- a/nix/simulation/mkTrinketComparison.nix │
│ +++ b/nix/simulation/mkTrinketComparison.nix │
│ @@ -75,10 +75,24 @@ │
│ # Modify profession if trinket requ │
│ ires it │
│ configWithProfession = │
│ if requiredProfession != null │
│ - then │
│ + then let │
│ + # Determine which profession is │
│ being replaced │
│ + droppedProfession = │
│ + if baseConfig.profession2 != │
│ requiredProfession │
│ + then baseConfig.profession2 │
│ + else if baseConfig.profession │
│ 1 != requiredProfession │
│ + then baseConfig.profession1 │
│ + else null; │
│ + │
│ + # Remove enchants from the drop │
│ ped profession │
│ + cleanedGearset = │
│ + if droppedProfession != null │
│ + then trinketLib.removeProfess │
│ ionEnchants gearset droppedProfession │
│ + else gearset; │
│ + in │
│ baseConfig │
│ // { │
│ - equipment = gearset; │
│ + equipment = cleanedGearset; │
│ profession2 = requiredProfess │
│ ion; │
│ } │
│ else baseConfig // {equipment = g │
│ earset;}; │
└──────────────────────────────────────────────┘
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET