HASH ab16f19ff4fd
DATE 2025-07-20
SUBJECT nix: refactor apps
FILES 12 CHANGED
HASH ab16f19ff4fd
DATE 2025-07-20
SUBJECT nix: refactor apps
FILES 12 CHANGED
┌─ CLAUDE.md ────────────────────────────────────────────────────────────────┐
│ diff --git a/CLAUDE.md b/CLAUDE.md │
│ new file mode 100644 │
│ index 0000000..5a2a5e5 │
│ --- /dev/null │
│ +++ b/CLAUDE.md │
│ @@ -0,0 +1,179 @@ │
│ +# CLAUDE.md │
│ + │
│ +This file provides guidance to Claude Code (claude.ai/code) when working with cod │
│ e in this repository. │
│ + │
│ +## Project Overview │
│ + │
│ +This is a Nix-based data pipeline for generating World of Warcraft simulation lea │
│ derboards and statistics. The project uses the wowsims CLI engine to create a theo │
│ rycrafting website similar to bloodmallet, showing spec performance rankings and t │
│ rinket data for WoW Mists of Pandaria. │
│ + │
│ +### Project Vision │
│ +- Generate spec simulation leaderboards across different encounter types │
│ +- Provide trinket performance data and rankings │
│ +- Serve results via static website with JSON data files │
│ +- Automate updates via GitHub Actions when upstream wowsims changes │
│ +- Use Nix for reproducible builds and server configuration │
│ + │
│ +## Development Environment │
│ + │
│ +### Setup │
│ +- Use `nix develop` to enter the development shell which provides `wowsimcli` │
│ +- The project uses a Nix flake with inputs from the wowsims MoP fork │
│ + │
│ +### Key Commands │
│ +- `nix develop` - Enter development environment with wowsimcli available │
│ +- `wowsimcli sim --infile input.json` - Run simulation with input file │
│ +- `wowsimcli sim --infile input.json --outfile results.json` - Save results to fi │
│ le │
│ +- `nix flake show` - Show available flake outputs │
│ +- `nix build` - Build packages (future: website and data generation) │
│ + │
│ +## Architecture │
│ + │
│ +### Core Structure │
│ +- `nix/lib/` - Core simulation library functions │
│ +- `nix/lib/default.nix` - Main library exports (target, encounter, player, raid) │
│ +- `nix/lib/extend.nix` - Extends nixpkgs lib with sim functions │
│ +- `docs/` - Example JSON configurations for CLI input │
│ + │
│ +### Key Components │
│ + │
│ +#### Player Configuration (`nix/lib/player.nix`) │
│ +- `mkPlayer` function creates player configurations from: │
│ + - Race, class, spec selection │
│ + - Gearsets loaded from wowsims JSON files │
│ + - APL (Action Priority List) rotations │
│ + - Consumables, talents, glyphs, professions │
│ + - Challenge mode support │
│ + │
│ +#### Target/Encounter System (`nix/lib/target.nix`) │
│ +- Predefined target types: `defaultRaidBoss`, `smallTrash`, `largeTrash` │
│ +- Configurable mob stats, damage, and mechanics │
│ + │
│ +#### Simulation (`nix/lib/simulation.nix`) │
│ +- `mkSim` function creates full simulation configurations │
│ +- Supports iterations, random seeds, different sim types │
│ + │
│ +### Data Sources │
│ +- Gearsets: `${wowsims}/ui/${class}/${spec}/gear_sets/${gearset}.gear.json` │
│ +- APLs: `${wowsims}/ui/${class}/${spec}/apls/${apl}.apl.json` │
│ +- References external wowsims repository for game data │
│ + │
│ +## File Organization │
│ +- Configuration examples in `docs/example_cli_input_windwalker.json` │
│ +- Nix library functions organized by domain (player, target, encounter, simulatio │
│ n) │
│ +- No traditional package.json or test files - this is a pure Nix project │
│ + │
│ +## Input JSON Schema │
│ + │
│ +The wowsimcli expects complex JSON input files with this hierarchy: │
│ + │
│ +### Top-Level Structure │
│ +```json │
│ +{ │
│ + "requestId": "string", │
│ + "type": "SimTypeIndividual", │
│ + "raid": RaidConfig, │
│ + "encounter": EncounterConfig, │
│ + "simOptions": SimulationOptions │
│ +} │
│ +``` │
│ + │
│ +### Key Schema Components │
│ +- **Raid**: Contains 5 parties (25-person raid), each with 5 player slots, plus r │
│ aid-wide buffs/debuffs │
│ +- **Player**: Complex nested structure with equipment (16 slots), consumables, ta │
│ lents, spec-specific options, and APL rotations │
│ +- **Equipment**: Items with IDs, gems, enchants, reforging, tinkers │
│ +- **APL (Action Priority Lists)**: Deep conditional logic trees for spell rotatio │
│ n decisions │
│ +- **Encounter**: Target configuration, fight duration, execute phases, enemy stat │
│ s │
│ +- **Enumeration Patterns**: Prefixed types like "RaceBloodElf", "ClassMonk", "Mob │
│ TypeMechanical" │
│ + │
│ +### Critical Details │
│ +- Equipment items use game database IDs for items/gems/enchants │
│ +- APL system uses complex nested conditions (and/or/cmp operators) │
│ +- Stats arrays are fixed-length (22 elements for target stats) │
│ +- Empty `{}` objects serve as placeholders for unused slots │
│ +- Spec-specific config uses dynamic keys like `"windwalkerMonk": {...}` │
│ + │
│ +## Data Pipeline │
│ + │
│ +### Planned Workflow │
│ +1. **Input Generation**: Nix functions create JSON input files matching wowsims s │
│ chema │
│ +2. **Simulation**: wowsimcli processes inputs and generates result data │
│ +3. **Aggregation**: Results are collected into static JSON files for website cons │
│ umption │
│ +4. **Website**: Static site serves leaderboards and trinket data │
│ +5. **Automation**: GitHub Actions trigger updates when upstream wowsims changes │
│ + │
│ +### Target Simulations │
│ +- **Encounter Types**: Single Target, Multi-Target, Short Single Target │
│ +- **Scope**: All specs initially, trinket comparisons later │
│ +- **Output**: JSON files for web frontend consumption │
│ + │
│ +## Composable Component Design │
│ + │
│ +### Class Component Pattern │
│ +The project uses a layered composition approach for building reusable class confi │
│ gurations: │
│ + │
│ +```nix │
│ +{ │
│ + lib, │
│ + components, │
│ + ... │
│ +}: let │
│ + inherit (lib.sim.player) mkPlayer; │
│ + inherit (components.consumables) agilityDps; │
│ + │
│ + # Spec-specific builder function │
│ + mkWindwalker = { │
│ + race, │
│ + apl, │
│ + gearset, │
│ + talents, │
│ + }: mkPlayer { │
│ + class = "monk"; │
│ + spec = "windwalker"; │
│ + inherit race gearset talents apl; │
│ + consumables = agilityDps; # Shared consumable set │
│ + }; │
│ + │
│ + # Organized configurations by tier and scenario │
│ + windwalker = { │
│ + talents = { │
│ + xuen = "213322"; # Single target build │
│ + rjw = "233321"; # AoE build │
│ + }; │
│ + p1 = { │
│ + singleTarget = mkWindwalker { │
│ + race = "orc"; │
│ + apl = "default"; │
│ + gearset = "dw_p1_bis"; │
│ + talents = windwalker.talents.xuen; │
│ + }; │
│ + aoeOrc = mkWindwalker { │
│ + race = "orc"; │
│ + apl = "default"; │
│ + gearset = "dw_p1_bis"; │
│ + talents = windwalker.talents.rjw; │
│ + }; │
│ + }; │
│ + }; │
│ +in windwalker │
│ +``` │
│ + │
│ +### Design Benefits │
│ +- **Shared Defaults**: Common consumables, base configurations │
│ +- **Scenario Organization**: Grouped by content tier (p1, p2) and encounter type │
│ +- **Talent Variants**: Named talent configurations for different playstyles │
│ +- **Race Flexibility**: Easy to create variants for different races │
│ +- **Inheritance Chain**: `mkWindwalker` ? `mkPlayer` ? JSON output │
│ + │
│ +## Working with the Code │
│ +- Build reusable Nix components following the layered composition pattern │
│ +- Create spec builders that inherit from `mkPlayer` with sensible defaults │
│ +- Organize configurations by content tier and encounter scenario │
│ +- Keep individual functions small and focused for maintainability │
│ +- Test changes by entering `nix develop` and running `wowsimcli` with generated c │
│ onfigs │
│ +- All simulation data comes from the referenced wowsims fork │
│ +- Challenge mode can be enabled on equipment for different stat scaling │
│ + │
│ +## Future Development │
│ +- GitHub Actions integration for automated simulation updates │
│ +- Website packaging and server configuration via Nix │
│ +- Trinket simulation expansion beyond basic spec rankings │
│ \ No newline at end of file │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ CLAUDE.md ──────────────────────────┐
│ diff --git a/CLAUDE.md b/CLAUDE.md │
│ new file mode 100644 │
│ index 0000000..5a2a5e5 │
│ --- /dev/null │
│ +++ b/CLAUDE.md │
│ @@ -0,0 +1,179 @@ │
│ +# CLAUDE.md │
│ + │
│ +This file provides guidance to Claude Code │
│ (claude.ai/code) when working with code in t │
│ his repository. │
│ + │
│ +## Project Overview │
│ + │
│ +This is a Nix-based data pipeline for gener │
│ ating World of Warcraft simulation leaderboa │
│ rds and statistics. The project uses the wow │
│ sims CLI engine to create a theorycrafting w │
│ ebsite similar to bloodmallet, showing spec │
│ performance rankings and trinket data for Wo │
│ W Mists of Pandaria. │
│ + │
│ +### Project Vision │
│ +- Generate spec simulation leaderboards acr │
│ oss different encounter types │
│ +- Provide trinket performance data and rank │
│ ings │
│ +- Serve results via static website with JSO │
│ N data files │
│ +- Automate updates via GitHub Actions when │
│ upstream wowsims changes │
│ +- Use Nix for reproducible builds and serve │
│ r configuration │
│ + │
│ +## Development Environment │
│ + │
│ +### Setup │
│ +- Use `nix develop` to enter the developmen │
│ t shell which provides `wowsimcli` │
│ +- The project uses a Nix flake with inputs │
│ from the wowsims MoP fork │
│ + │
│ +### Key Commands │
│ +- `nix develop` - Enter development environ │
│ ment with wowsimcli available │
│ +- `wowsimcli sim --infile input.json` - Run │
│ simulation with input file │
│ +- `wowsimcli sim --infile input.json --outf │
│ ile results.json` - Save results to file │
│ +- `nix flake show` - Show available flake o │
│ utputs │
│ +- `nix build` - Build packages (future: web │
│ site and data generation) │
│ + │
│ +## Architecture │
│ + │
│ +### Core Structure │
│ +- `nix/lib/` - Core simulation library func │
│ tions │
│ +- `nix/lib/default.nix` - Main library expo │
│ rts (target, encounter, player, raid) │
│ +- `nix/lib/extend.nix` - Extends nixpkgs li │
│ b with sim functions │
│ +- `docs/` - Example JSON configurations for │
│ CLI input │
│ + │
│ +### Key Components │
│ + │
│ +#### Player Configuration (`nix/lib/player. │
│ nix`) │
│ +- `mkPlayer` function creates player config │
│ urations from: │
│ + - Race, class, spec selection │
│ + - Gearsets loaded from wowsims JSON files │
│ + - APL (Action Priority List) rotations │
│ + - Consumables, talents, glyphs, professio │
│ ns │
│ + - Challenge mode support │
│ + │
│ +#### Target/Encounter System (`nix/lib/targ │
│ et.nix`) │
│ +- Predefined target types: `defaultRaidBoss │
│ `, `smallTrash`, `largeTrash` │
│ +- Configurable mob stats, damage, and mecha │
│ nics │
│ + │
│ +#### Simulation (`nix/lib/simulation.nix`) │
│ +- `mkSim` function creates full simulation │
│ configurations │
│ +- Supports iterations, random seeds, differ │
│ ent sim types │
│ + │
│ +### Data Sources │
│ +- Gearsets: `${wowsims}/ui/${class}/${spec} │
│ /gear_sets/${gearset}.gear.json` │
│ +- APLs: `${wowsims}/ui/${class}/${spec}/apl │
│ s/${apl}.apl.json` │
│ +- References external wowsims repository fo │
│ r game data │
│ + │
│ +## File Organization │
│ +- Configuration examples in `docs/example_c │
│ li_input_windwalker.json` │
│ +- Nix library functions organized by domain │
│ (player, target, encounter, simulation) │
│ +- No traditional package.json or test files │
│ - this is a pure Nix project │
│ + │
│ +## Input JSON Schema │
│ + │
│ +The wowsimcli expects complex JSON input fi │
│ les with this hierarchy: │
│ + │
│ +### Top-Level Structure │
│ +```json │
│ +{ │
│ + "requestId": "string", │
│ + "type": "SimTypeIndividual", │
│ + "raid": RaidConfig, │
│ + "encounter": EncounterConfig, │
│ + "simOptions": SimulationOptions │
│ +} │
│ +``` │
│ + │
│ +### Key Schema Components │
│ +- **Raid**: Contains 5 parties (25-person r │
│ aid), each with 5 player slots, plus raid-wi │
│ de buffs/debuffs │
│ +- **Player**: Complex nested structure with │
│ equipment (16 slots), consumables, talents, │
│ spec-specific options, and APL rotations │
│ +- **Equipment**: Items with IDs, gems, ench │
│ ants, reforging, tinkers │
│ +- **APL (Action Priority Lists)**: Deep con │
│ ditional logic trees for spell rotation deci │
│ sions │
│ +- **Encounter**: Target configuration, figh │
│ t duration, execute phases, enemy stats │
│ +- **Enumeration Patterns**: Prefixed types │
│ like "RaceBloodElf", "ClassMonk", "MobTypeMe │
│ chanical" │
│ + │
│ +### Critical Details │
│ +- Equipment items use game database IDs for │
│ items/gems/enchants │
│ +- APL system uses complex nested conditions │
│ (and/or/cmp operators) │
│ +- Stats arrays are fixed-length (22 element │
│ s for target stats) │
│ +- Empty `{}` objects serve as placeholders │
│ for unused slots │
│ +- Spec-specific config uses dynamic keys li │
│ ke `"windwalkerMonk": {...}` │
│ + │
│ +## Data Pipeline │
│ + │
│ +### Planned Workflow │
│ +1. **Input Generation**: Nix functions crea │
│ te JSON input files matching wowsims schema │
│ +2. **Simulation**: wowsimcli processes inpu │
│ ts and generates result data │
│ +3. **Aggregation**: Results are collected i │
│ nto static JSON files for website consumptio │
│ n │
│ +4. **Website**: Static site serves leaderbo │
│ ards and trinket data │
│ +5. **Automation**: GitHub Actions trigger u │
│ pdates when upstream wowsims changes │
│ + │
│ +### Target Simulations │
│ +- **Encounter Types**: Single Target, Multi │
│ -Target, Short Single Target │
│ +- **Scope**: All specs initially, trinket c │
│ omparisons later │
│ +- **Output**: JSON files for web frontend c │
│ onsumption │
│ + │
│ +## Composable Component Design │
│ + │
│ +### Class Component Pattern │
│ +The project uses a layered composition appr │
│ oach for building reusable class configurati │
│ ons: │
│ + │
│ +```nix │
│ +{ │
│ + lib, │
│ + components, │
│ + ... │
│ +}: let │
│ + inherit (lib.sim.player) mkPlayer; │
│ + inherit (components.consumables) agilityD │
│ ps; │
│ + │
│ + # Spec-specific builder function │
│ + mkWindwalker = { │
│ + race, │
│ + apl, │
│ + gearset, │
│ + talents, │
│ + }: mkPlayer { │
│ + class = "monk"; │
│ + spec = "windwalker"; │
│ + inherit race gearset talents apl; │
│ + consumables = agilityDps; # Shared con │
│ sumable set │
│ + }; │
│ + │
│ + # Organized configurations by tier and sc │
│ enario │
│ + windwalker = { │
│ + talents = { │
│ + xuen = "213322"; # Single target bui │
│ ld │
│ + rjw = "233321"; # AoE build │
│ + }; │
│ + p1 = { │
│ + singleTarget = mkWindwalker { │
│ + race = "orc"; │
│ + apl = "default"; │
│ + gearset = "dw_p1_bis"; │
│ + talents = windwalker.talents.xuen; │
│ + }; │
│ + aoeOrc = mkWindwalker { │
│ + race = "orc"; │
│ + apl = "default"; │
│ + gearset = "dw_p1_bis"; │
│ + talents = windwalker.talents.rjw; │
│ + }; │
│ + }; │
│ + }; │
│ +in windwalker │
│ +``` │
│ + │
│ +### Design Benefits │
│ +- **Shared Defaults**: Common consumables, │
│ base configurations │
│ +- **Scenario Organization**: Grouped by con │
│ tent tier (p1, p2) and encounter type │
│ +- **Talent Variants**: Named talent configu │
│ rations for different playstyles │
│ +- **Race Flexibility**: Easy to create vari │
│ ants for different races │
│ +- **Inheritance Chain**: `mkWindwalker` ? ` │
│ mkPlayer` ? JSON output │
│ + │
│ +## Working with the Code │
│ +- Build reusable Nix components following t │
│ he layered composition pattern │
│ +- Create spec builders that inherit from `m │
│ kPlayer` with sensible defaults │
│ +- Organize configurations by content tier a │
│ nd encounter scenario │
│ +- Keep individual functions small and focus │
│ ed for maintainability │
│ +- Test changes by entering `nix develop` an │
│ d running `wowsimcli` with generated configs │
│ +- All simulation data comes from the refere │
│ nced wowsims fork │
│ +- Challenge mode can be enabled on equipmen │
│ t for different stat scaling │
│ + │
│ +## Future Development │
│ +- GitHub Actions integration for automated │
│ simulation updates │
│ +- Website packaging and server configuratio │
│ n via Nix │
│ +- Trinket simulation expansion beyond basic │
│ spec rankings │
│ \ No newline at end of file │
└──────────────────────────────────────────────┘
┌─ README.md ────────────────────────────────────────────────────────────────┐
│ diff --git a/README.md b/README.md │
│ index 5abd3d0..5157023 100644 │
│ --- a/README.md │
│ +++ b/README.md │
│ @@ -1 +1,37 @@ │
│ -WIP. This tool uses [wowsims](https://github.com/wowsims/mop) │
│ +WIP. This tool uses [wowsims](https://github.com/wowsims/mop). │
│ + │
│ +Planned Features │
│ + │
│ +- Leaderboard for multiple encounters │
│ + - Long/Short Raid/Challenge mode │
│ + - Single target │
│ + - Multi target │
│ + - Cleave │
│ + - Mass AOE │
│ +- Trinket Comparison per spec │
│ +- 10/25 raid benchmarks │
│ + │
│ +# Developing │
│ + │
│ +- Install nix │
│ +- run `nix develop` │
│ + │
│ +# Running simulations │
│ + │
│ +- `nix run .#<simulation>` │
│ + │
│ +Available simulations from [nix/apps.nix](./nix/apps.nix): │
│ + │
│ +- `singleTargetRaidLong` │
│ +- `multiTargetRaidLong` │
│ +- `cleaveRaidLong` │
│ +- `massMultiTargetRaid` │
│ + │
│ +Example: `nix run .#singleTargetRaidLong` │
│ + │
│ +This will output a json file inside `web/public/data` that is consumed by the │
│ +web frontend. │
│ + │
│ +# How it works │
│ + │
│ +We use nix to generate the json schema that the wowsimcli uses as input. │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ README.md ──────────────────────────┐
│ diff --git a/README.md b/README.md │
│ index 5abd3d0..5157023 100644 │
│ --- a/README.md │
│ +++ b/README.md │
│ @@ -1 +1,37 @@ │
│ -WIP. This tool uses [wowsims](https://githu │
│ b.com/wowsims/mop) │
│ +WIP. This tool uses [wowsims](https://githu │
│ b.com/wowsims/mop). │
│ + │
│ +Planned Features │
│ + │
│ +- Leaderboard for multiple encounters │
│ + - Long/Short Raid/Challenge mode │
│ + - Single target │
│ + - Multi target │
│ + - Cleave │
│ + - Mass AOE │
│ +- Trinket Comparison per spec │
│ +- 10/25 raid benchmarks │
│ + │
│ +# Developing │
│ + │
│ +- Install nix │
│ +- run `nix develop` │
│ + │
│ +# Running simulations │
│ + │
│ +- `nix run .#<simulation>` │
│ + │
│ +Available simulations from [nix/apps.nix](. │
│ /nix/apps.nix): │
│ + │
│ +- `singleTargetRaidLong` │
│ +- `multiTargetRaidLong` │
│ +- `cleaveRaidLong` │
│ +- `massMultiTargetRaid` │
│ + │
│ +Example: `nix run .#singleTargetRaidLong` │
│ + │
│ +This will output a json file inside `web/pu │
│ blic/data` that is consumed by the │
│ +web frontend. │
│ + │
│ +# How it works │
│ + │
│ +We use nix to generate the json schema that │
│ the wowsimcli uses as input. │
└──────────────────────────────────────────────┘
┌─ nix/apps.nix ─────────────────────────────────────────────────────────────┐
│ diff --git a/nix/apps.nix b/nix/apps.nix │
│ deleted file mode 100644 │
│ index 1c7bd8b..0000000 │
│ --- a/nix/apps.nix │
│ +++ /dev/null │
│ @@ -1,120 +0,0 @@ │
│ -{ │
│ - lib, │
│ - classes, │
│ - encounter, │
│ - buffs, │
│ - debuffs, │
│ - inputs, │
│ - ... │
│ -}: { │
│ - perSystem = {pkgs, ...}: let │
│ - # Test composition script │
│ - inherit (lib.sim.simulation) mkSim; │
│ - │
│ - class = "druid"; │
│ - spec = "balance"; │
│ - │
│ - testRaid = mkSim { │
│ - requestId = "raidSimAsync-f2cf5e22118a43c7"; │
│ - iterations = 1000; │
│ - player = classes.${class}.${spec}.template.p1.raid.singleTarget; │
│ - buffs = buffs.full; │
│ - debuffs = debuffs.full; │
│ - encounter = encounter.raid.long.singleTarget; │
│ - }; │
│ - testComposition = pkgs.writeShellApplication { │
│ - name = "test-composition"; │
│ - text = '' │
│ - # Generate test elemental simulation │
│ - cat > ${spec}_input.json << 'EOF' │
│ - ${testRaid} │
│ - EOF │
│ - │
│ - echo "Generated ${spec}_input.json" │
│ - echo "File size: $(wc -c < ${spec}_input.json) bytes" │
│ - echo "Player name: $(jq -r '.raid.parties[0].players[0].name // "missing" │
│ ' ${spec}_input.json)" │
│ - echo "" │
│ - │
│ - echo "Running wowsimcli simulation..." │
│ - wowsimcli sim --infile ${spec}_input.json --outfile ${spec}_output.json │
│ - │
│ - if [ -f ${spec}_output.json ]; then │
│ - echo "Simulation completed successfully!" │
│ - avgDps=$(jq -r '.raidMetrics.dps.avg' ${spec}_output.json) │
│ - echo "Average DPS: $avgDps" │
│ - else │
│ - echo "Error: wowsimcli failed to generate output" │
│ - exit 1 │
│ - fi │
│ - ''; │
│ - runtimeInputs = [pkgs.jq inputs.wowsims.packages.${pkgs.system}.wowsimcli]; │
│ - }; │
│ - │
│ - # Import mass simulation │
│ - massSimulation = import ./mass-simulation.nix { │
│ - inherit lib pkgs classes encounter buffs debuffs inputs; │
│ - }; │
│ - │
│ - # Mass simulations using mkMassSim │
│ - mkMassSim = (import ./lib/mkMassSim.nix {inherit lib pkgs classes encounter b │
│ uffs debuffs inputs;}).mkMassSim; │
│ - │
│ - massSimulations = { │
│ - singleTargetRaidLong = mkMassSim { │
│ - specs = "dps"; # shortcut to all DPS classes templates │
│ - encounter = encounter.raid.long.singleTarget; │
│ - iterations = 10000; │
│ - phase = "p1"; │
│ - encounterType = "raid"; │
│ - targetCount = "single"; │
│ - duration = "long"; │
│ - }; │
│ - │
│ - multiTargetRaidLong = mkMassSim { │
│ - specs = "dps"; │
│ - encounter = encounter.raid.long.threeTarget; │
│ - iterations = 10000; │
│ - phase = "p1"; │
│ - encounterType = "raid"; │
│ - targetCount = "three"; │
│ - duration = "long"; │
│ - }; │
│ - │
│ - cleaveRaidLong = mkMassSim { │
│ - specs = "dps"; │
│ - encounter = encounter.raid.long.cleave; │
│ - iterations = 10000; │
│ - phase = "p1"; │
│ - encounterType = "raid"; │
│ - targetCount = "cleave"; │
│ - duration = "long"; │
│ - }; │
│ - │
│ - massMultiTargetRaidLong = mkMassSim { │
│ - specs = "dps"; │
│ - encounter = encounter.raid.long.tenTarget; │
│ - iterations = 10000; │
│ - phase = "p1"; │
│ - encounterType = "raid"; │
│ - targetCount = "ten"; │
│ - duration = "long"; │
│ - }; │
│ - }; │
│ - in { │
│ - apps = │
│ - { │
│ - test-composition = { │
│ - type = "app"; │
│ - program = "${testComposition}/bin/test-composition"; │
│ - }; │
│ - mass-sim = { │
│ - type = "app"; │
│ - program = "${massSimulation.massSimulationScript}/bin/mass-simulation"; │
│ - }; │
│ - } │
│ - // (lib.mapAttrs (name: massSim: { │
│ - type = "app"; │
│ - program = "${massSim.script}/bin/${massSim.metadata.output}-aggregator" │
│ ; │
│ - }) │
│ - massSimulations); │
│ - }; │
│ -} │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ nix/apps.nix ───────────────────────┐
│ diff --git a/nix/apps.nix b/nix/apps.nix │
│ deleted file mode 100644 │
│ index 1c7bd8b..0000000 │
│ --- a/nix/apps.nix │
│ +++ /dev/null │
│ @@ -1,120 +0,0 @@ │
│ -{ │
│ - lib, │
│ - classes, │
│ - encounter, │
│ - buffs, │
│ - debuffs, │
│ - inputs, │
│ - ... │
│ -}: { │
│ - perSystem = {pkgs, ...}: let │
│ - # Test composition script │
│ - inherit (lib.sim.simulation) mkSim; │
│ - │
│ - class = "druid"; │
│ - spec = "balance"; │
│ - │
│ - testRaid = mkSim { │
│ - requestId = "raidSimAsync-f2cf5e22118 │
│ a43c7"; │
│ - iterations = 1000; │
│ - player = classes.${class}.${spec}.tem │
│ plate.p1.raid.singleTarget; │
│ - buffs = buffs.full; │
│ - debuffs = debuffs.full; │
│ - encounter = encounter.raid.long.singl │
│ eTarget; │
│ - }; │
│ - testComposition = pkgs.writeShellApplic │
│ ation { │
│ - name = "test-composition"; │
│ - text = '' │
│ - # Generate test elemental simulatio │
│ n │
│ - cat > ${spec}_input.json << 'EOF' │
│ - ${testRaid} │
│ - EOF │
│ - │
│ - echo "Generated ${spec}_input.json" │
│ - echo "File size: $(wc -c < ${spec}_ │
│ input.json) bytes" │
│ - echo "Player name: $(jq -r '.raid.p │
│ arties[0].players[0].name // "missing"' ${sp │
│ ec}_input.json)" │
│ - echo "" │
│ - │
│ - echo "Running wowsimcli simulation. │
│ .." │
│ - wowsimcli sim --infile ${spec}_inpu │
│ t.json --outfile ${spec}_output.json │
│ - │
│ - if [ -f ${spec}_output.json ]; then │
│ - echo "Simulation completed succes │
│ sfully!" │
│ - avgDps=$(jq -r '.raidMetrics.dps. │
│ avg' ${spec}_output.json) │
│ - echo "Average DPS: $avgDps" │
│ - else │
│ - echo "Error: wowsimcli failed to │
│ generate output" │
│ - exit 1 │
│ - fi │
│ - ''; │
│ - runtimeInputs = [pkgs.jq inputs.wowsi │
│ ms.packages.${pkgs.system}.wowsimcli]; │
│ - }; │
│ - │
│ - # Import mass simulation │
│ - massSimulation = import ./mass-simulati │
│ on.nix { │
│ - inherit lib pkgs classes encounter bu │
│ ffs debuffs inputs; │
│ - }; │
│ - │
│ - # Mass simulations using mkMassSim │
│ - mkMassSim = (import ./lib/mkMassSim.nix │
│ {inherit lib pkgs classes encounter buffs d │
│ ebuffs inputs;}).mkMassSim; │
│ - │
│ - massSimulations = { │
│ - singleTargetRaidLong = mkMassSim { │
│ - specs = "dps"; # shortcut to all DP │
│ S classes templates │
│ - encounter = encounter.raid.long.sin │
│ gleTarget; │
│ - iterations = 10000; │
│ - phase = "p1"; │
│ - encounterType = "raid"; │
│ - targetCount = "single"; │
│ - duration = "long"; │
│ - }; │
│ - │
│ - multiTargetRaidLong = mkMassSim { │
│ - specs = "dps"; │
│ - encounter = encounter.raid.long.thr │
│ eeTarget; │
│ - iterations = 10000; │
│ - phase = "p1"; │
│ - encounterType = "raid"; │
│ - targetCount = "three"; │
│ - duration = "long"; │
│ - }; │
│ - │
│ - cleaveRaidLong = mkMassSim { │
│ - specs = "dps"; │
│ - encounter = encounter.raid.long.cle │
│ ave; │
│ - iterations = 10000; │
│ - phase = "p1"; │
│ - encounterType = "raid"; │
│ - targetCount = "cleave"; │
│ - duration = "long"; │
│ - }; │
│ - │
│ - massMultiTargetRaidLong = mkMassSim { │
│ - specs = "dps"; │
│ - encounter = encounter.raid.long.ten │
│ Target; │
│ - iterations = 10000; │
│ - phase = "p1"; │
│ - encounterType = "raid"; │
│ - targetCount = "ten"; │
│ - duration = "long"; │
│ - }; │
│ - }; │
│ - in { │
│ - apps = │
│ - { │
│ - test-composition = { │
│ - type = "app"; │
│ - program = "${testComposition}/bin │
│ /test-composition"; │
│ - }; │
│ - mass-sim = { │
│ - type = "app"; │
│ - program = "${massSimulation.massS │
│ imulationScript}/bin/mass-simulation"; │
│ - }; │
│ - } │
│ - // (lib.mapAttrs (name: massSim: { │
│ - type = "app"; │
│ - program = "${massSim.script}/bin/ │
│ ${massSim.metadata.output}-aggregator"; │
│ - }) │
│ - massSimulations); │
│ - }; │
│ -} │
└──────────────────────────────────────────────┘
┌─ nix/apps/default.nix ─────────────────────────────────────────────────────┐
│ diff --git a/nix/apps/default.nix b/nix/apps/default.nix │
│ new file mode 100644 │
│ index 0000000..65bf09e │
│ --- /dev/null │
│ +++ b/nix/apps/default.nix │
│ @@ -0,0 +1,15 @@ │
│ +{ │
│ + lib, │
│ + classes, │
│ + encounter, │
│ + buffs, │
│ + debuffs, │
│ + inputs, │
│ + ... │
│ +}: { │
│ + perSystem = {pkgs, ...}: let │
│ + simulation = import ./simulation {inherit lib classes encounter buffs debuffs │
│ inputs pkgs;}; │
│ + in { │
│ + apps = simulation; │
│ + }; │
│ +} │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ nix/apps/default.nix ───────────────┐
│ diff --git a/nix/apps/default.nix b/nix/apps │
│ /default.nix │
│ new file mode 100644 │
│ index 0000000..65bf09e │
│ --- /dev/null │
│ +++ b/nix/apps/default.nix │
│ @@ -0,0 +1,15 @@ │
│ +{ │
│ + lib, │
│ + classes, │
│ + encounter, │
│ + buffs, │
│ + debuffs, │
│ + inputs, │
│ + ... │
│ +}: { │
│ + perSystem = {pkgs, ...}: let │
│ + simulation = import ./simulation {inher │
│ it lib classes encounter buffs debuffs input │
│ s pkgs;}; │
│ + in { │
│ + apps = simulation; │
│ + }; │
│ +} │
└──────────────────────────────────────────────┘
┌─ nix/apps/simulation/default.nix ──────────────────────────────────────────┐
│ diff --git a/nix/apps/simulation/default.nix b/nix/apps/simulation/default.nix │
│ new file mode 100644 │
│ index 0000000..3195272 │
│ --- /dev/null │
│ +++ b/nix/apps/simulation/default.nix │
│ @@ -0,0 +1,90 @@ │
│ +{ │
│ + lib, │
│ + pkgs, │
│ + classes, │
│ + encounter, │
│ + buffs, │
│ + debuffs, │
│ + inputs, │
│ + ... │
│ +}: let │
│ + # Mass simulations using mkMassSim │
│ + mkMassSim = (import ./mkMassSim.nix {inherit lib pkgs classes encounter buffs d │
│ ebuffs inputs;}).mkMassSim; │
│ + │
│ + massSimulations = { │
│ + dps-p1-raid-single-long = mkMassSim { │
│ + specs = "dps"; # shortcut to all DPS classes templates │
│ + encounter = encounter.raid.long.singleTarget; │
│ + iterations = 10000; │
│ + phase = "p1"; │
│ + encounterType = "raid"; │
│ + targetCount = "single"; │
│ + duration = "long"; │
│ + }; │
│ + │
│ + dps-p1-raid-three-long = mkMassSim { │
│ + specs = "dps"; │
│ + encounter = encounter.raid.long.threeTarget; │
│ + iterations = 10000; │
│ + phase = "p1"; │
│ + encounterType = "raid"; │
│ + targetCount = "three"; │
│ + duration = "long"; │
│ + }; │
│ + │
│ + dps-p1-raid-cleave-long = mkMassSim { │
│ + specs = "dps"; │
│ + encounter = encounter.raid.long.cleave; │
│ + iterations = 10000; │
│ + phase = "p1"; │
│ + encounterType = "raid"; │
│ + targetCount = "cleave"; │
│ + duration = "long"; │
│ + }; │
│ + │
│ + dps-p1-raid-ten-long = mkMassSim { │
│ + specs = "dps"; │
│ + encounter = encounter.raid.long.tenTarget; │
│ + iterations = 10000; │
│ + phase = "p1"; │
│ + encounterType = "raid"; │
│ + targetCount = "ten"; │
│ + duration = "long"; │
│ + }; │
│ + }; │
│ + │
│ + # Script that runs all simulations │
│ + allSimulationsScript = pkgs.writeShellApplication { │
│ + name = "all-simulations"; │
│ + text = '' │
│ + echo "Running all WoW simulations..." │
│ + │
│ + ${lib.concatMapStringsSep "\n" (name: '' │
│ + echo "" │
│ + echo "Running ${name}..." │
│ + ${massSimulations.${name}.script}/bin/${massSimulations.${name}.metadata. │
│ output}-aggregator │
│ + '') (lib.attrNames massSimulations)} │
│ + │
│ + echo "" │
│ + echo "All simulations completed successfully!" │
│ + echo "Generated files:" │
│ + ls -la web/public/data/*.json 2>/dev/null || echo "No JSON files found" │
│ + ''; │
│ + runtimeInputs = [pkgs.coreutils]; │
│ + }; │
│ + │
│ + # Convert mass simulations to apps and add the all-simulations app │
│ + simulationApps = │
│ + lib.mapAttrs (name: massSim: { │
│ + type = "app"; │
│ + program = "${massSim.script}/bin/${massSim.metadata.output}-aggregator"; │
│ + }) │
│ + massSimulations; │
│ +in │
│ + simulationApps │
│ + // { │
│ + allSimulations = { │
│ + type = "app"; │
│ + program = "${allSimulationsScript}/bin/all-simulations"; │
│ + }; │
│ + } │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ nix/apps/simulation/default.nix ────┐
│ diff --git a/nix/apps/simulation/default.nix │
│ b/nix/apps/simulation/default.nix │
│ new file mode 100644 │
│ index 0000000..3195272 │
│ --- /dev/null │
│ +++ b/nix/apps/simulation/default.nix │
│ @@ -0,0 +1,90 @@ │
│ +{ │
│ + lib, │
│ + pkgs, │
│ + classes, │
│ + encounter, │
│ + buffs, │
│ + debuffs, │
│ + inputs, │
│ + ... │
│ +}: let │
│ + # Mass simulations using mkMassSim │
│ + mkMassSim = (import ./mkMassSim.nix {inhe │
│ rit lib pkgs classes encounter buffs debuffs │
│ inputs;}).mkMassSim; │
│ + │
│ + massSimulations = { │
│ + dps-p1-raid-single-long = mkMassSim { │
│ + specs = "dps"; # shortcut to all DPS │
│ classes templates │
│ + encounter = encounter.raid.long.singl │
│ eTarget; │
│ + iterations = 10000; │
│ + phase = "p1"; │
│ + encounterType = "raid"; │
│ + targetCount = "single"; │
│ + duration = "long"; │
│ + }; │
│ + │
│ + dps-p1-raid-three-long = mkMassSim { │
│ + specs = "dps"; │
│ + encounter = encounter.raid.long.three │
│ Target; │
│ + iterations = 10000; │
│ + phase = "p1"; │
│ + encounterType = "raid"; │
│ + targetCount = "three"; │
│ + duration = "long"; │
│ + }; │
│ + │
│ + dps-p1-raid-cleave-long = mkMassSim { │
│ + specs = "dps"; │
│ + encounter = encounter.raid.long.cleav │
│ e; │
│ + iterations = 10000; │
│ + phase = "p1"; │
│ + encounterType = "raid"; │
│ + targetCount = "cleave"; │
│ + duration = "long"; │
│ + }; │
│ + │
│ + dps-p1-raid-ten-long = mkMassSim { │
│ + specs = "dps"; │
│ + encounter = encounter.raid.long.tenTa │
│ rget; │
│ + iterations = 10000; │
│ + phase = "p1"; │
│ + encounterType = "raid"; │
│ + targetCount = "ten"; │
│ + duration = "long"; │
│ + }; │
│ + }; │
│ + │
│ + # Script that runs all simulations │
│ + allSimulationsScript = pkgs.writeShellApp │
│ lication { │
│ + name = "all-simulations"; │
│ + text = '' │
│ + echo "Running all WoW simulations..." │
│ + │
│ + ${lib.concatMapStringsSep "\n" (name: │
│ '' │
│ + echo "" │
│ + echo "Running ${name}..." │
│ + ${massSimulations.${name}.script}/b │
│ in/${massSimulations.${name}.metadata.output │
│ }-aggregator │
│ + '') (lib.attrNames massSimulations)} │
│ + │
│ + echo "" │
│ + echo "All simulations completed succe │
│ ssfully!" │
│ + echo "Generated files:" │
│ + ls -la web/public/data/*.json 2>/dev/ │
│ null || echo "No JSON files found" │
│ + ''; │
│ + runtimeInputs = [pkgs.coreutils]; │
│ + }; │
│ + │
│ + # Convert mass simulations to apps and ad │
│ d the all-simulations app │
│ + simulationApps = │
│ + lib.mapAttrs (name: massSim: { │
│ + type = "app"; │
│ + program = "${massSim.script}/bin/${ma │
│ ssSim.metadata.output}-aggregator"; │
│ + }) │
│ + massSimulations; │
│ +in │
│ + simulationApps │
│ + // { │
│ + allSimulations = { │
│ + type = "app"; │
│ + program = "${allSimulationsScript}/bi │
│ n/all-simulations"; │
│ + }; │
│ + } │
└──────────────────────────────────────────────┘
┌─ nix/apps/simulation/mkMassSim.nix ────────────────────────────────────────┐
│ diff --git a/nix/lib/mkMassSim.nix b/nix/apps/simulation/mkMassSim.nix │
│ similarity index 100% │
│ rename from nix/lib/mkMassSim.nix │
│ rename to nix/apps/simulation/mkMassSim.nix │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...apps/simulation/mkMassSim.nix ───┐
│ diff --git a/nix/lib/mkMassSim.nix b/nix/app │
│ s/simulation/mkMassSim.nix │
│ similarity index 100% │
│ rename from nix/lib/mkMassSim.nix │
│ rename to nix/apps/simulation/mkMassSim.nix │
└──────────────────────────────────────────────┘
┌─ nix/default.nix ──────────────────────────────────────────────────────────┐
│ diff --git a/nix/default.nix b/nix/default.nix │
│ index 44d9a28..d353f15 100644 │
│ --- a/nix/default.nix │
│ +++ b/nix/default.nix │
│ @@ -1,8 +1,9 @@ │
│ { │
│ imports = [ │
│ ./shell.nix │
│ - ./apps.nix │
│ + ./apps │
│ ./checks.nix │
│ + ./pkgs │
│ │
│ # components │
│ ./classes │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ nix/default.nix ────────────────────┐
│ diff --git a/nix/default.nix b/nix/default.n │
│ ix │
│ index 44d9a28..d353f15 100644 │
│ --- a/nix/default.nix │
│ +++ b/nix/default.nix │
│ @@ -1,8 +1,9 @@ │
│ { │
│ imports = [ │
│ ./shell.nix │
│ - ./apps.nix │
│ + ./apps │
│ ./checks.nix │
│ + ./pkgs │
│ │
│ # components │
│ ./classes │
└──────────────────────────────────────────────┘
┌─ nix/lib/mass-sim.nix ─────────────────────────────────────────────────────┐
│ diff --git a/nix/lib/mass-sim.nix b/nix/lib/mass-sim.nix │
│ deleted file mode 100644 │
│ index 5b00bba..0000000 │
│ --- a/nix/lib/mass-sim.nix │
│ +++ /dev/null │
│ @@ -1,165 +0,0 @@ │
│ -{ │
│ - lib, │
│ - pkgs, │
│ - classes, │
│ - encounter, │
│ - buffs, │
│ - debuffs, │
│ - ... │
│ -}: let │
│ - inherit (lib.sim.simulation) mkSim; │
│ - │
│ - # Helper to get all available class/spec combinations for a given encounter typ │
│ e │
│ - getAllSpecConfigs = encounterCategory: targetType: duration: classes: │
│ - lib.flatten (lib.mapAttrsToList ( │
│ - className: classSpecs: │
│ - lib.mapAttrsToList ( │
│ - specName: specConfigs: │
│ - if │
│ - lib.hasAttr "template" specConfigs │
│ - && lib.hasAttr "p1" specConfigs.template │
│ - && lib.hasAttr encounterCategory specConfigs.template.p1 │
│ - && lib.hasAttr targetType specConfigs.template.p1.${encounterCate │
│ gory} │
│ - then { │
│ - inherit className specName; │
│ - config = specConfigs.template.p1.${encounterCategory}.${targetTyp │
│ e}; │
│ - } │
│ - else null │
│ - ) │
│ - classSpecs │
│ - ) │
│ - classes); │
│ - │
│ - # Filter out null values │
│ - filterValidConfigs = configs: lib.filter (x: x != null) configs; │
│ - │
│ - # Create simulation input for a specific spec │
│ - createSimInput = { │
│ - className, │
│ - specName, │
│ - config, │
│ - encounterType, │
│ - encounterCategory, │
│ - targetType, │
│ - duration, │
│ - }: │
│ - mkSim { │
│ - requestId = "mass-sim-${className}-${specName}-${encounterCategory}-${targe │
│ tType}-${duration}"; │
│ - iterations = 1000; │
│ - player = config; │
│ - buffs = buffs.full; │
│ - debuffs = debuffs.full; │
│ - encounter = encounter.${encounterCategory}.${duration}.${targetType}; │
│ - }; │
│ - │
│ - # Mass simulation function │
│ - mkMassSimulation = { │
│ - encounterCategory ? "raid", │
│ - targetType ? "singleTarget", │
│ - duration ? "long", │
│ - }: let │
│ - # Get all valid spec configurations │
│ - allSpecs = filterValidConfigs (getAllSpecConfigs encounterCategory targetType │
│ duration classes); │
│ - │
│ - # Create individual simulation derivations │
│ - simDerivations = lib.listToAttrs (map (spec: { │
│ - name = "${spec.className}-${spec.specName}"; │
│ - value = let │
│ - simInput = createSimInput { │
│ - inherit (spec) className specName config; │
│ - encounterType = encounterCategory; │
│ - inherit encounterCategory targetType duration; │
│ - }; │
│ - in │
│ - pkgs.runCommand "sim-${spec.className}-${spec.specName}" { │
│ - buildInputs = [pkgs.jq]; │
│ - nativeBuildInputs = [pkgs.wowsimcli]; │
│ - } '' │
│ - # Create input file │
│ - cat > input.json << 'EOF' │
│ - ${simInput} │
│ - EOF │
│ - │
│ - # Run simulation │
│ - wowsimcli sim --infile input.json --outfile output.json │
│ - │
│ - # Extract DPS and create result JSON │
│ - avgDps=$(jq -r '.raidMetrics.dps.avg // 0' output.json) │
│ - │
│ - # Create output with DPS and loadout info │
│ - jq -n --arg dps "$avgDps" --arg className "${spec.className}" --arg s │
│ pecName "${spec.specName}" \ │
│ - --argjson loadout '${builtins.toJSON spec.config}' \ │
│ - '{ │
│ - dps: ($dps | tonumber), │
│ - className: $className, │
│ - specName: $specName, │
│ - loadout: $loadout │
│ - }' > $out │
│ - ''; │
│ - }) │
│ - allSpecs); │
│ - │
│ - # Aggregate all results into final JSON structure │
│ - aggregatedResults = │
│ - pkgs.runCommand "mass-sim-${encounterCategory}-${targetType}-${duration}" { │
│ - buildInputs = [pkgs.jq]; │
│ - } '' │
│ - # Create the nested JSON structure │
│ - jq -n --argjson specs '{}' \ │
│ - '{ "${encounterCategory}": { "${targetType}": { "${duration}": $specs } │
│ } }' > result.json │
│ - │
│ - ${lib.concatMapStringsSep "\n" (spec: '' │
│ - # Read result for ${spec.className}/${spec.specName} │
│ - specResult=$(cat ${simDerivations."${spec.className}-${spec.specName} │
│ "}) │
│ - │
│ - # Add to the nested structure │
│ - jq --argjson spec "$specResult" \ │
│ - '.${encounterCategory}.${targetType}.${duration}."${spec.className │
│ }"."${spec.specName}" = { │
│ - dps: $spec.dps, │
│ - loadout: $spec.loadout │
│ - }' result.json > temp.json && mv temp.json result.json │
│ - '') │
│ - allSpecs} │
│ - │
│ - # Final output │
│ - cp result.json $out │
│ - ''; │
│ - in { │
│ - # Individual simulation results │
│ - simulations = simDerivations; │
│ - │
│ - # Aggregated JSON output │
│ - result = aggregatedResults; │
│ - │
│ - # Metadata │
│ - metadata = { │
│ - inherit encounterCategory targetType duration; │
│ - specCount = lib.length allSpecs; │
│ - specs = map (s: "${s.className}/${s.specName}") allSpecs; │
│ - }; │
│ - }; │
│ -in { │
│ - inherit mkMassSimulation; │
│ - │
│ - # Pre-defined common simulation sets │
│ - presets = { │
│ - raidSingleTargetLong = mkMassSimulation { │
│ - encounterCategory = "raid"; │
│ - targetType = "singleTarget"; │
│ - duration = "long"; │
│ - }; │
│ - │
│ - raidMultiTargetLong = mkMassSimulation { │
│ - encounterCategory = "raid"; │
│ - targetType = "multiTarget"; │
│ - duration = "long"; │
│ - }; │
│ - │
│ - raidCleaveLong = mkMassSimulation { │
│ - encounterCategory = "raid"; │
│ - targetType = "cleave"; │
│ - duration = "long"; │
│ - }; │
│ - }; │
│ -} │
│ - │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ nix/lib/mass-sim.nix ───────────────┐
│ diff --git a/nix/lib/mass-sim.nix b/nix/lib/ │
│ mass-sim.nix │
│ deleted file mode 100644 │
│ index 5b00bba..0000000 │
│ --- a/nix/lib/mass-sim.nix │
│ +++ /dev/null │
│ @@ -1,165 +0,0 @@ │
│ -{ │
│ - lib, │
│ - pkgs, │
│ - classes, │
│ - encounter, │
│ - buffs, │
│ - debuffs, │
│ - ... │
│ -}: let │
│ - inherit (lib.sim.simulation) mkSim; │
│ - │
│ - # Helper to get all available class/spec │
│ combinations for a given encounter type │
│ - getAllSpecConfigs = encounterCategory: ta │
│ rgetType: duration: classes: │
│ - lib.flatten (lib.mapAttrsToList ( │
│ - className: classSpecs: │
│ - lib.mapAttrsToList ( │
│ - specName: specConfigs: │
│ - if │
│ - lib.hasAttr "template" spec │
│ Configs │
│ - && lib.hasAttr "p1" specCon │
│ figs.template │
│ - && lib.hasAttr encounterCat │
│ egory specConfigs.template.p1 │
│ - && lib.hasAttr targetType s │
│ pecConfigs.template.p1.${encounterCategory} │
│ - then { │
│ - inherit className specName; │
│ - config = specConfigs.templa │
│ te.p1.${encounterCategory}.${targetType}; │
│ - } │
│ - else null │
│ - ) │
│ - classSpecs │
│ - ) │
│ - classes); │
│ - │
│ - # Filter out null values │
│ - filterValidConfigs = configs: lib.filter │
│ (x: x != null) configs; │
│ - │
│ - # Create simulation input for a specific │
│ spec │
│ - createSimInput = { │
│ - className, │
│ - specName, │
│ - config, │
│ - encounterType, │
│ - encounterCategory, │
│ - targetType, │
│ - duration, │
│ - }: │
│ - mkSim { │
│ - requestId = "mass-sim-${className}-${ │
│ specName}-${encounterCategory}-${targetType} │
│ -${duration}"; │
│ - iterations = 1000; │
│ - player = config; │
│ - buffs = buffs.full; │
│ - debuffs = debuffs.full; │
│ - encounter = encounter.${encounterCate │
│ gory}.${duration}.${targetType}; │
│ - }; │
│ - │
│ - # Mass simulation function │
│ - mkMassSimulation = { │
│ - encounterCategory ? "raid", │
│ - targetType ? "singleTarget", │
│ - duration ? "long", │
│ - }: let │
│ - # Get all valid spec configurations │
│ - allSpecs = filterValidConfigs (getAllSp │
│ ecConfigs encounterCategory targetType durat │
│ ion classes); │
│ - │
│ - # Create individual simulation derivati │
│ ons │
│ - simDerivations = lib.listToAttrs (map ( │
│ spec: { │
│ - name = "${spec.className}-${spec.sp │
│ ecName}"; │
│ - value = let │
│ - simInput = createSimInput { │
│ - inherit (spec) className specNa │
│ me config; │
│ - encounterType = encounterCatego │
│ ry; │
│ - inherit encounterCategory targe │
│ tType duration; │
│ - }; │
│ - in │
│ - pkgs.runCommand "sim-${spec.class │
│ Name}-${spec.specName}" { │
│ - buildInputs = [pkgs.jq]; │
│ - nativeBuildInputs = [pkgs.wowsi │
│ mcli]; │
│ - } '' │
│ - # Create input file │
│ - cat > input.json << 'EOF' │
│ - ${simInput} │
│ - EOF │
│ - │
│ - # Run simulation │
│ - wowsimcli sim --infile input.js │
│ on --outfile output.json │
│ - │
│ - # Extract DPS and create result │
│ JSON │
│ - avgDps=$(jq -r '.raidMetrics.dp │
│ s.avg // 0' output.json) │
│ - │
│ - # Create output with DPS and lo │
│ adout info │
│ - jq -n --arg dps "$avgDps" --arg │
│ className "${spec.className}" --arg specNam │
│ e "${spec.specName}" \ │
│ - --argjson loadout '${builtin │
│ s.toJSON spec.config}' \ │
│ - '{ │
│ - dps: ($dps | tonumber), │
│ - className: $className, │
│ - specName: $specName, │
│ - loadout: $loadout │
│ - }' > $out │
│ - ''; │
│ - }) │
│ - allSpecs); │
│ - │
│ - # Aggregate all results into final JSON │
│ structure │
│ - aggregatedResults = │
│ - pkgs.runCommand "mass-sim-${encounter │
│ Category}-${targetType}-${duration}" { │
│ - buildInputs = [pkgs.jq]; │
│ - } '' │
│ - # Create the nested JSON structure │
│ - jq -n --argjson specs '{}' \ │
│ - '{ "${encounterCategory}": { "${t │
│ argetType}": { "${duration}": $specs } } }' │
│ > result.json │
│ - │
│ - ${lib.concatMapStringsSep "\n" (spe │
│ c: '' │
│ - # Read result for ${spec.classN │
│ ame}/${spec.specName} │
│ - specResult=$(cat ${simDerivatio │
│ ns."${spec.className}-${spec.specName}"}) │
│ - │
│ - # Add to the nested structure │
│ - jq --argjson spec "$specResult" │
│ \ │
│ - '.${encounterCategory}.${tar │
│ getType}.${duration}."${spec.className}"."${ │
│ spec.specName}" = { │
│ - dps: $spec.dps, │
│ - loadout: $spec.loadout │
│ - }' result.json > temp.json & │
│ & mv temp.json result.json │
│ - '') │
│ - allSpecs} │
│ - │
│ - # Final output │
│ - cp result.json $out │
│ - ''; │
│ - in { │
│ - # Individual simulation results │
│ - simulations = simDerivations; │
│ - │
│ - # Aggregated JSON output │
│ - result = aggregatedResults; │
│ - │
│ - # Metadata │
│ - metadata = { │
│ - inherit encounterCategory targetType │
│ duration; │
│ - specCount = lib.length allSpecs; │
│ - specs = map (s: "${s.className}/${s.s │
│ pecName}") allSpecs; │
│ - }; │
│ - }; │
│ -in { │
│ - inherit mkMassSimulation; │
│ - │
│ - # Pre-defined common simulation sets │
│ - presets = { │
│ - raidSingleTargetLong = mkMassSimulation │
│ { │
│ - encounterCategory = "raid"; │
│ - targetType = "singleTarget"; │
│ - duration = "long"; │
│ - }; │
│ - │
│ - raidMultiTargetLong = mkMassSimulation │
│ { │
│ - encounterCategory = "raid"; │
│ - targetType = "multiTarget"; │
│ - duration = "long"; │
│ - }; │
│ - │
│ - raidCleaveLong = mkMassSimulation { │
│ - encounterCategory = "raid"; │
│ - targetType = "cleave"; │
│ - duration = "long"; │
│ - }; │
│ - }; │
│ -} │
│ - │
└──────────────────────────────────────────────┘
┌─ nix/pkgs/default.nix ─────────────────────────────────────────────────────┐
│ diff --git a/nix/pkgs/default.nix b/nix/pkgs/default.nix │
│ new file mode 100644 │
│ index 0000000..a706234 │
│ --- /dev/null │
│ +++ b/nix/pkgs/default.nix │
│ @@ -0,0 +1,23 @@ │
│ +{ │
│ + lib, │
│ + classes, │
│ + encounter, │
│ + buffs, │
│ + debuffs, │
│ + ... │
│ +}: { │
│ + perSystem = { │
│ + pkgs, │
│ + inputs', │
│ + ... │
│ + }: let │
│ + inherit (pkgs) callPackage; │
│ + inherit (inputs'.wowsims.packages) wowsimcli; │
│ + in { │
│ + packages = { │
│ + 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 │
│ new file mode 100644 │
│ index 0000000..a706234 │
│ --- /dev/null │
│ +++ b/nix/pkgs/default.nix │
│ @@ -0,0 +1,23 @@ │
│ +{ │
│ + lib, │
│ + classes, │
│ + encounter, │
│ + buffs, │
│ + debuffs, │
│ + ... │
│ +}: { │
│ + perSystem = { │
│ + pkgs, │
│ + inputs', │
│ + ... │
│ + }: let │
│ + inherit (pkgs) callPackage; │
│ + inherit (inputs'.wowsims.packages) wows │
│ imcli; │
│ + in { │
│ + packages = { │
│ + testRaid = callPackage ./testRaid.nix │
│ { │
│ + inherit lib classes encounter buffs │
│ debuffs wowsimcli; │
│ + }; │
│ + }; │
│ + }; │
│ +} │
└──────────────────────────────────────────────┘
┌─ nix/pkgs/pkgs.nix ────────────────────────────────────────────────────────┐
│ diff --git a/nix/pkgs/pkgs.nix b/nix/pkgs/pkgs.nix │
│ deleted file mode 100644 │
│ index 7300efe..0000000 │
│ --- a/nix/pkgs/pkgs.nix │
│ +++ /dev/null │
│ @@ -1,24 +0,0 @@ │
│ -{self, ...}: { │
│ - perSystem = { │
│ - pkgs, │
│ - self', │
│ - lib, │
│ - ... │
│ - }: let │
│ - inherit (lib) getExe; │
│ - in { │
│ - packages.default = pkgs.stdenvNoCC.mkDerivation { │
│ - pname = "my package"; │
│ - version = "0.1.0"; │
│ - src = "${self}/src"; │
│ - nativeBuildInputs = []; │
│ - │
│ - buildPhase = ""; │
│ - dontInstall = true; │
│ - }; │
│ - apps.default = { │
│ - type = "app"; │
│ - program = "${getExe self'.packages.default}"; │
│ - }; │
│ - }; │
│ -} │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ nix/pkgs/pkgs.nix ──────────────────┐
│ diff --git a/nix/pkgs/pkgs.nix b/nix/pkgs/pk │
│ gs.nix │
│ deleted file mode 100644 │
│ index 7300efe..0000000 │
│ --- a/nix/pkgs/pkgs.nix │
│ +++ /dev/null │
│ @@ -1,24 +0,0 @@ │
│ -{self, ...}: { │
│ - perSystem = { │
│ - pkgs, │
│ - self', │
│ - lib, │
│ - ... │
│ - }: let │
│ - inherit (lib) getExe; │
│ - in { │
│ - packages.default = pkgs.stdenvNoCC.mkDe │
│ rivation { │
│ - pname = "my package"; │
│ - version = "0.1.0"; │
│ - src = "${self}/src"; │
│ - nativeBuildInputs = []; │
│ - │
│ - buildPhase = ""; │
│ - dontInstall = true; │
│ - }; │
│ - apps.default = { │
│ - type = "app"; │
│ - program = "${getExe self'.packages.de │
│ fault}"; │
│ - }; │
│ - }; │
│ -} │
└──────────────────────────────────────────────┘
┌─ nix/pkgs/rankings.nix ────────────────────────────────────────────────────┐
│ diff --git a/nix/pkgs/rankings.nix b/nix/pkgs/rankings.nix │
│ deleted file mode 100644 │
│ index 48a557f..0000000 │
│ --- a/nix/pkgs/rankings.nix │
│ +++ /dev/null │
│ @@ -1,106 +0,0 @@ │
│ -{ │
│ - writeShellApplication, │
│ - wowsimcli, │
│ - jq, │
│ - self, │
│ - lib, │
│ - ... │
│ -}: let │
│ - classConfigs = import ./utils/classConfigs.nix {inherit lib self;}; │
│ - │
│ - # Test the new generateSimulation function │
│ - testInfile = classConfigs.generateSimulation │
│ - classConfigs.monk.windwalker.singleTarget │
│ - classConfigs.encounters.long.singleTarget; │
│ - │
│ - # Test challenge mode │
│ - testChallengeModeInfile = classConfigs.generateSimulation │
│ - classConfigs.monk.windwalker.challengeMode │
│ - classConfigs.encounters.long.singleTarget; │
│ -in │
│ - writeShellApplication { │
│ - name = "generate-rankings"; │
│ - runtimeInputs = [ │
│ - wowsimcli │
│ - jq │
│ - ]; │
│ - text = '' │
│ - set -euo pipefail │
│ - │
│ - echo "Testing class configuration system..." │
│ - │
│ - # Generate different configurations │
│ - echo "1. Monk Windwalker Single Target (Long):" │
│ - cat > "./monk_windwalker_st_long.json" << 'EOF' │
│ - ${testInfile} │
│ - EOF │
│ - │
│ - echo "? Generated: monk_windwalker_st_long.json" │
│ - echo "File size: $(du -h "./monk_windwalker_st_long.json" | cut -f1)" │
│ - │
│ - echo "" │
│ - echo "2. Monk Windwalker Challenge Mode:" │
│ - cat > "./monk_windwalker_challenge_mode.json" << 'EOF' │
│ - ${testChallengeModeInfile} │
│ - EOF │
│ - │
│ - echo "? Generated: monk_windwalker_challenge_mode.json" │
│ - echo "File size: $(du -h "./monk_windwalker_challenge_mode.json" | cut -f1) │
│ " │
│ - │
│ - # Test JSON validation │
│ - echo "" │
│ - echo "JSON validation:" │
│ - if jq empty "./monk_windwalker_st_long.json" 2>/dev/null && jq empty "./mon │
│ k_windwalker_challenge_mode.json" 2>/dev/null; then │
│ - echo "? Both files have valid JSON" │
│ - else │
│ - echo "? Invalid JSON found" │
│ - echo "Standard mode errors:" │
│ - jq empty "./monk_windwalker_st_long.json" │
│ - echo "Challenge mode errors:" │
│ - jq empty "./monk_windwalker_challenge_mode.json" │
│ - fi │
│ - │
│ - echo "" │
│ - echo "Configuration demonstrates:" │
│ - echo "Standard Mode:" │
│ - echo "- Class: $(jq -r '.raid.parties[0].players[0].class' "./monk_windwalk │
│ er_st_long.json")" │
│ - echo "- Spec field: $(jq -r '. | keys | .[] | select(. == "windwalkerMonk") │
│ ' "./monk_windwalker_st_long.json" || echo "windwalkerMonk")" │
│ - echo "- Encounter duration: $(jq -r '.encounter.duration' "./monk_windwalke │
│ r_st_long.json")s" │
│ - echo "- Target count: $(jq -r '.encounter.targets | length' "./monk_windwal │
│ ker_st_long.json")" │
│ - echo "- Raid buffs enabled: $(jq -r '.raid.buffs | [to_entries[] | select(. │
│ value == true) | .key] | length' "./monk_windwalker_st_long.json")" │
│ - echo "- Challenge mode items: $(jq -r '.raid.parties[0].players[0].equipmen │
│ t.items | map(select(.challengeMode == true)) | length' "./monk_windwalker_st_long │
│ .json")" │
│ - echo "" │
│ - echo "Challenge Mode:" │
│ - echo "- Challenge mode items: $(jq -r '.raid.parties[0].players[0].equipmen │
│ t.items | map(select(.challengeMode == true)) | length' "./monk_windwalker_challen │
│ ge_mode.json")" │
│ - echo "- Total equipment items: $(jq -r '.raid.parties[0].players[0].equipme │
│ nt.items | length' "./monk_windwalker_challenge_mode.json")" │
│ - │
│ - echo "" │
│ - echo "Usage examples:" │
│ - echo " classConfigs.generateSimulation classConfigs.monk.windwalker.single │
│ Target classConfigs.encounters.long.singleTarget" │
│ - echo " classConfigs.generateSimulation classConfigs.monk.windwalker.multiT │
│ arget classConfigs.encounters.short.multiTarget8" │
│ - echo " classConfigs.generateSimulation classConfigs.monk.windwalker.challe │
│ ngeMode classConfigs.encounters.long.singleTarget" │
│ - echo " classConfigs.generateSimulation classConfigs.monk.windwalker.challe │
│ ngeModeMultiTarget classConfigs.encounters.short.multiTarget8" │
│ - echo "" │
│ - echo "Available encounters:" │
│ - echo " - encounters.long.singleTarget" │
│ - echo " - encounters.long.multiTarget2" │
│ - echo " - encounters.long.multiTarget8" │
│ - echo " - encounters.short.singleTarget" │
│ - echo " - encounters.short.multiTarget2" │
│ - echo " - encounters.short.multiTarget8" │
│ - echo " - encounters.patchwerk.long" │
│ - echo " - encounters.cleave.short" │
│ - echo " - encounters.aoe.long" │
│ - echo "" │
│ - echo "Available raid buff presets:" │
│ - echo " - raidBuffs.fullBuffs (all buffs including bloodlust)" │
│ - echo " - raidBuffs.fullBuffsNoLust (all buffs except bloodlust)" │
│ - echo " - raidBuffs.noBuffs (no buffs)" │
│ - echo " - raidBuffs.mergeRaidBuffs {bloodlust = false; trueshotAura = false │
│ ;} (custom)" │
│ - echo "" │
│ - echo "Available raid debuff presets:" │
│ - echo " - raidDebuffs.fullDebuffs (all debuffs)" │
│ - echo " - raidDebuffs.noDebuffs (no debuffs)" │
│ - echo " - raidDebuffs.mergeRaidDebuffs {physicalVulnerability = false;} (cu │
│ stom)" │
│ - ''; │
│ - } │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ nix/pkgs/rankings.nix ──────────────┐
│ diff --git a/nix/pkgs/rankings.nix b/nix/pkg │
│ s/rankings.nix │
│ deleted file mode 100644 │
│ index 48a557f..0000000 │
│ --- a/nix/pkgs/rankings.nix │
│ +++ /dev/null │
│ @@ -1,106 +0,0 @@ │
│ -{ │
│ - writeShellApplication, │
│ - wowsimcli, │
│ - jq, │
│ - self, │
│ - lib, │
│ - ... │
│ -}: let │
│ - classConfigs = import ./utils/classConfig │
│ s.nix {inherit lib self;}; │
│ - │
│ - # Test the new generateSimulation functio │
│ n │
│ - testInfile = classConfigs.generateSimulat │
│ ion │
│ - classConfigs.monk.windwalker.singleTarg │
│ et │
│ - classConfigs.encounters.long.singleTarg │
│ et; │
│ - │
│ - # Test challenge mode │
│ - testChallengeModeInfile = classConfigs.ge │
│ nerateSimulation │
│ - classConfigs.monk.windwalker.challengeM │
│ ode │
│ - classConfigs.encounters.long.singleTarg │
│ et; │
│ -in │
│ - writeShellApplication { │
│ - name = "generate-rankings"; │
│ - runtimeInputs = [ │
│ - wowsimcli │
│ - jq │
│ - ]; │
│ - text = '' │
│ - set -euo pipefail │
│ - │
│ - echo "Testing class configuration sys │
│ tem..." │
│ - │
│ - # Generate different configurations │
│ - echo "1. Monk Windwalker Single Targe │
│ t (Long):" │
│ - cat > "./monk_windwalker_st_long.json │
│ " << 'EOF' │
│ - ${testInfile} │
│ - EOF │
│ - │
│ - echo "? Generated: monk_windwalker_st │
│ _long.json" │
│ - echo "File size: $(du -h "./monk_wind │
│ walker_st_long.json" | cut -f1)" │
│ - │
│ - echo "" │
│ - echo "2. Monk Windwalker Challenge Mo │
│ de:" │
│ - cat > "./monk_windwalker_challenge_mo │
│ de.json" << 'EOF' │
│ - ${testChallengeModeInfile} │
│ - EOF │
│ - │
│ - echo "? Generated: monk_windwalker_ch │
│ allenge_mode.json" │
│ - echo "File size: $(du -h "./monk_wind │
│ walker_challenge_mode.json" | cut -f1)" │
│ - │
│ - # Test JSON validation │
│ - echo "" │
│ - echo "JSON validation:" │
│ - if jq empty "./monk_windwalker_st_lon │
│ g.json" 2>/dev/null && jq empty "./monk_wind │
│ walker_challenge_mode.json" 2>/dev/null; the │
│ n │
│ - echo "? Both files have valid JSON" │
│ - else │
│ - echo "? Invalid JSON found" │
│ - echo "Standard mode errors:" │
│ - jq empty "./monk_windwalker_st_long │
│ .json" │
│ - echo "Challenge mode errors:" │
│ - jq empty "./monk_windwalker_challen │
│ ge_mode.json" │
│ - fi │
│ - │
│ - echo "" │
│ - echo "Configuration demonstrates:" │
│ - echo "Standard Mode:" │
│ - echo "- Class: $(jq -r '.raid.parties │
│ [0].players[0].class' "./monk_windwalker_st_ │
│ long.json")" │
│ - echo "- Spec field: $(jq -r '. | keys │
│ | .[] | select(. == "windwalkerMonk")' "./m │
│ onk_windwalker_st_long.json" || echo "windwa │
│ lkerMonk")" │
│ - echo "- Encounter duration: $(jq -r ' │
│ .encounter.duration' "./monk_windwalker_st_l │
│ ong.json")s" │
│ - echo "- Target count: $(jq -r '.encou │
│ nter.targets | length' "./monk_windwalker_st │
│ _long.json")" │
│ - echo "- Raid buffs enabled: $(jq -r ' │
│ .raid.buffs | [to_entries[] | select(.value │
│ == true) | .key] | length' "./monk_windwalke │
│ r_st_long.json")" │
│ - echo "- Challenge mode items: $(jq -r │
│ '.raid.parties[0].players[0].equipment.item │
│ s | map(select(.challengeMode == true)) | le │
│ ngth' "./monk_windwalker_st_long.json")" │
│ - echo "" │
│ - echo "Challenge Mode:" │
│ - echo "- Challenge mode items: $(jq -r │
│ '.raid.parties[0].players[0].equipment.item │
│ s | map(select(.challengeMode == true)) | le │
│ ngth' "./monk_windwalker_challenge_mode.json │
│ ")" │
│ - echo "- Total equipment items: $(jq - │
│ r '.raid.parties[0].players[0].equipment.ite │
│ ms | length' "./monk_windwalker_challenge_mo │
│ de.json")" │
│ - │
│ - echo "" │
│ - echo "Usage examples:" │
│ - echo " classConfigs.generateSimulati │
│ on classConfigs.monk.windwalker.singleTarget │
│ classConfigs.encounters.long.singleTarget" │
│ - echo " classConfigs.generateSimulati │
│ on classConfigs.monk.windwalker.multiTarget │
│ classConfigs.encounters.short.multiTarget8" │
│ - echo " classConfigs.generateSimulati │
│ on classConfigs.monk.windwalker.challengeMod │
│ e classConfigs.encounters.long.singleTarget" │
│ - echo " classConfigs.generateSimulati │
│ on classConfigs.monk.windwalker.challengeMod │
│ eMultiTarget classConfigs.encounters.short.m │
│ ultiTarget8" │
│ - echo "" │
│ - echo "Available encounters:" │
│ - echo " - encounters.long.singleTarge │
│ t" │
│ - echo " - encounters.long.multiTarget │
│ 2" │
│ - echo " - encounters.long.multiTarget │
│ 8" │
│ - echo " - encounters.short.singleTarg │
│ et" │
│ - echo " - encounters.short.multiTarge │
│ t2" │
│ - echo " - encounters.short.multiTarge │
│ t8" │
│ - echo " - encounters.patchwerk.long" │
│ - echo " - encounters.cleave.short" │
│ - echo " - encounters.aoe.long" │
│ - echo "" │
│ - echo "Available raid buff presets:" │
│ - echo " - raidBuffs.fullBuffs (all bu │
│ ffs including bloodlust)" │
│ - echo " - raidBuffs.fullBuffsNoLust ( │
│ all buffs except bloodlust)" │
│ - echo " - raidBuffs.noBuffs (no buffs │
│ )" │
│ - echo " - raidBuffs.mergeRaidBuffs {b │
│ loodlust = false; trueshotAura = false;} (cu │
│ stom)" │
│ - echo "" │
│ - echo "Available raid debuff presets:" │
│ - echo " - raidDebuffs.fullDebuffs (al │
│ l debuffs)" │
│ - echo " - raidDebuffs.noDebuffs (no d │
│ ebuffs)" │
│ - echo " - raidDebuffs.mergeRaidDebuff │
│ s {physicalVulnerability = false;} (custom)" │
│ - ''; │
│ - } │
└──────────────────────────────────────────────┘
┌─ nix/pkgs/testRaid.nix ────────────────────────────────────────────────────┐
│ diff --git a/nix/pkgs/testRaid.nix b/nix/pkgs/testRaid.nix │
│ new file mode 100644 │
│ index 0000000..6ab0f7a │
│ --- /dev/null │
│ +++ b/nix/pkgs/testRaid.nix │
│ @@ -0,0 +1,53 @@ │
│ +{ │
│ + wowsimcli, │
│ + jq, │
│ + writeShellApplication, │
│ + lib, │
│ + classes, │
│ + encounter, │
│ + buffs, │
│ + debuffs, │
│ + ... │
│ +}: let │
│ + # quickly sim a single spec for testing purposes │
│ + inherit (lib.sim.simulation) mkSim; │
│ + │
│ + class = "druid"; │
│ + spec = "balance"; │
│ + │
│ + raid = mkSim { │
│ + requestId = "raidSimAsync-f2cf5e22118a43c7"; │
│ + iterations = 1000; │
│ + player = classes.${class}.${spec}.template.p1.raid.singleTarget; │
│ + buffs = buffs.full; │
│ + debuffs = debuffs.full; │
│ + encounter = encounter.raid.long.singleTarget; │
│ + }; │
│ + testRaid = writeShellApplication { │
│ + name = "testRaid"; │
│ + text = '' │
│ + cat > ${spec}_input.json << 'EOF' │
│ + ${raid} │
│ + EOF │
│ + │
│ + echo "Generated ${spec}_input.json" │
│ + echo "File size: $(wc -c < ${spec}_input.json) bytes" │
│ + echo "Player name: $(jq -r '.raid.parties[0].players[0].name // "missing"' │
│ ${spec}_input.json)" │
│ + echo "" │
│ + │
│ + echo "Running wowsimcli simulation..." │
│ + wowsimcli sim --infile ${spec}_input.json --outfile ${spec}_output.json │
│ + │
│ + if [ -f ${spec}_output.json ]; then │
│ + echo "Simulation completed successfully!" │
│ + avgDps=$(jq -r '.raidMetrics.dps.avg' ${spec}_output.json) │
│ + echo "Average DPS: $avgDps" │
│ + else │
│ + echo "Error: wowsimcli failed to generate output" │
│ + exit 1 │
│ + fi │
│ + ''; │
│ + runtimeInputs = [jq wowsimcli]; │
│ + }; │
│ +in │
│ + testRaid │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ nix/pkgs/testRaid.nix ──────────────┐
│ diff --git a/nix/pkgs/testRaid.nix b/nix/pkg │
│ s/testRaid.nix │
│ new file mode 100644 │
│ index 0000000..6ab0f7a │
│ --- /dev/null │
│ +++ b/nix/pkgs/testRaid.nix │
│ @@ -0,0 +1,53 @@ │
│ +{ │
│ + wowsimcli, │
│ + jq, │
│ + writeShellApplication, │
│ + lib, │
│ + classes, │
│ + encounter, │
│ + buffs, │
│ + debuffs, │
│ + ... │
│ +}: let │
│ + # quickly sim a single spec for testing p │
│ urposes │
│ + inherit (lib.sim.simulation) mkSim; │
│ + │
│ + class = "druid"; │
│ + spec = "balance"; │
│ + │
│ + raid = mkSim { │
│ + requestId = "raidSimAsync-f2cf5e22118a4 │
│ 3c7"; │
│ + iterations = 1000; │
│ + player = classes.${class}.${spec}.templ │
│ ate.p1.raid.singleTarget; │
│ + buffs = buffs.full; │
│ + debuffs = debuffs.full; │
│ + encounter = encounter.raid.long.singleT │
│ arget; │
│ + }; │
│ + testRaid = writeShellApplication { │
│ + name = "testRaid"; │
│ + text = '' │
│ + cat > ${spec}_input.json << 'EOF' │
│ + ${raid} │
│ + EOF │
│ + │
│ + echo "Generated ${spec}_input.json" │
│ + echo "File size: $(wc -c < ${spec}_in │
│ put.json) bytes" │
│ + echo "Player name: $(jq -r '.raid.par │
│ ties[0].players[0].name // "missing"' ${spec │
│ }_input.json)" │
│ + echo "" │
│ + │
│ + echo "Running wowsimcli simulation... │
│ " │
│ + wowsimcli sim --infile ${spec}_input. │
│ json --outfile ${spec}_output.json │
│ + │
│ + if [ -f ${spec}_output.json ]; then │
│ + echo "Simulation completed successf │
│ ully!" │
│ + avgDps=$(jq -r '.raidMetrics.dps.av │
│ g' ${spec}_output.json) │
│ + echo "Average DPS: $avgDps" │
│ + else │
│ + echo "Error: wowsimcli failed to ge │
│ nerate output" │
│ + exit 1 │
│ + fi │
│ + ''; │
│ + runtimeInputs = [jq wowsimcli]; │
│ + }; │
│ +in │
│ + testRaid │
└──────────────────────────────────────────────┘
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET