Skip to content

Commit

Permalink
Merge pull request #1102 from wowsims/feature/preset-configuration
Browse files Browse the repository at this point in the history
[UI] Migrate builds to preset configurations
  • Loading branch information
kayla-glick authored Sep 27, 2024
2 parents 2d1e8f7 + faefcb2 commit d49c844
Show file tree
Hide file tree
Showing 21 changed files with 510 additions and 291 deletions.
58 changes: 29 additions & 29 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
{
"name": "sod",
"version": "0.1.0",
"private": true,
"scripts": {
"build": "bazel build //...",
"test": "bazel test //...",
"format": "npm run lint:fix && npm run prettier:fix",
"lint": "npm run lint:js && npm run lint:css",
"lint:fix": "npm run lint:js:fix && npm run lint:css:fix",
"lint:js": "npx eslint \"./ui/**/*.{js,jsx,ts,tsx}\"",
"lint:js:fix": "npm run lint:js -- --fix",
"lint:css": "stylelint \"./ui/**/*.scss\"",
"lint:css:fix": "npm run lint:css -- --fix",
"lint:json": "npx eslint \"./{ui,jsonschema}/**/*.json\"",
"lint:json:fix": "npm run lint:json -- --fix",
"prettier": "npx prettier \"./ui/**/*.{js,jsx,ts,tsx,scss,css,json}\" --check",
"prettier:fix": "npm run prettier -- --write",
"type-check": "tsc --noEmit"
},
"dependencies": {
"@popperjs/core": "^2.11.6",
"name": "sod",
"version": "0.1.0",
"private": true,
"scripts": {
"build": "bazel build //...",
"test": "bazel test //...",
"format": "npm run lint:fix && npm run prettier:fix",
"lint": "npm run lint:js && npm run lint:css",
"lint:fix": "npm run lint:js:fix && npm run lint:css:fix",
"lint:js": "npx eslint \"./ui/**/*.{js,jsx,ts,tsx}\"",
"lint:js:fix": "npm run lint:js -- --fix",
"lint:css": "stylelint \"./ui/**/*.scss\"",
"lint:css:fix": "npm run lint:css -- --fix",
"lint:json": "npx eslint \"./{ui,jsonschema}/**/*.json\"",
"lint:json:fix": "npm run lint:json -- --fix",
"prettier": "npx prettier \"./ui/**/*.{js,jsx,ts,tsx,scss,css,json}\" --check",
"prettier:fix": "npm run prettier -- --write",
"type-check": "tsc --noEmit"
},
"dependencies": {
"@popperjs/core": "^2.11.6",
"@types/golang-wasm-exec": "^1.15.2",
"@types/pako": "^2.0.0",
"bootstrap": "^5.3.0",
Expand All @@ -28,13 +28,13 @@
"tippy.js": "^6.3.7",
"tsx-vanilla": "^1.0.0",
"uuid": "^9.0.1"
},
"devDependencies": {
"@protobuf-ts/plugin": "2.9.1",
"@protobuf-ts/plugin-framework": "2.9.1",
"@protobuf-ts/protoc": "2.9.1",
"@protobuf-ts/runtime": "2.9.1",
"@types/bootstrap": "^5.2.0",
},
"devDependencies": {
"@protobuf-ts/plugin": "2.9.1",
"@protobuf-ts/plugin-framework": "2.9.1",
"@protobuf-ts/protoc": "2.9.1",
"@protobuf-ts/runtime": "2.9.1",
"@types/bootstrap": "^5.2.0",
"@types/eslint": "^8.56.10",
"@types/glob": "^8.0.3",
"@types/node": "^18.16.1",
Expand All @@ -61,5 +61,5 @@
"typescript-formatter": "^7.2.2",
"vite": "^5.0.0",
"vite-plugin-checker": "^0.6.4"
}
}
}
2 changes: 1 addition & 1 deletion ui/core/components/importers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export class IndividualLinkImporter {
return map;
})();

static tryParseUrlLocation(location: Location): UrlParseData | null {
static tryParseUrlLocation(location: Location | URL): UrlParseData | null {
let hash = location.hash;
if (hash.length <= 1) {
return null;
Expand Down
7 changes: 6 additions & 1 deletion ui/core/components/individual_sim_ui/gear_tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { EventID, TypedEvent } from '../../typed_event';
import GearPicker from '../gear_picker/gear_picker';
import { SavedDataManager } from '../saved_data_manager';
import { SimTab } from '../sim_tab';
import { PresetConfigurationPicker } from './preset_configuration_picker';

export class GearTab extends SimTab {
protected simUI: IndividualSimUI<Spec>;
Expand All @@ -32,14 +33,18 @@ export class GearTab extends SimTab {

protected buildTabContent() {
this.buildGearPickers();

this.buildPresetConfigurationPicker();
this.buildSavedGearsetPicker();
}

private buildGearPickers() {
new GearPicker(this.leftPanel, this.simUI, this.simUI.player);
}

private buildPresetConfigurationPicker() {
new PresetConfigurationPicker(this.rightPanel, this.simUI, 'gear');
}

private buildSavedGearsetPicker() {
const savedGearManager = new SavedDataManager<Player<any>, SavedGearSet>(this.rightPanel, this.simUI.player, {
header: { title: 'Gear Sets' },
Expand Down
87 changes: 0 additions & 87 deletions ui/core/components/individual_sim_ui/preset_builds_picker.tsx

This file was deleted.

122 changes: 122 additions & 0 deletions ui/core/components/individual_sim_ui/preset_configuration_picker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import tippy from 'tippy.js';
import { ref } from 'tsx-vanilla';

import { IndividualSimUI } from '../../individual_sim_ui';
import { PresetBuild } from '../../preset_utils';
import { APLRotation, APLRotation_Type } from '../../proto/apl';
import { Encounter, EquipmentSpec, HealingModel, Spec } from '../../proto/common';
import { TypedEvent } from '../../typed_event';
import { Component } from '../component';
import { ContentBlock } from '../content_block';

type PresetConfigurationCategory = 'gear' | 'talents' | 'rotation' | 'encounter';

export class PresetConfigurationPicker extends Component {
readonly simUI: IndividualSimUI<Spec>;
readonly builds: Array<PresetBuild>;

constructor(parentElem: HTMLElement, simUI: IndividualSimUI<Spec>, type?: PresetConfigurationCategory) {
super(parentElem, 'preset-configuration-picker-root');
this.rootElem.classList.add('saved-data-manager-root');

this.simUI = simUI;
this.builds = (this.simUI.individualConfig.presets.builds ?? []).filter(build =>
Object.keys(build).some(category => category === type && !!build[category]),
);

if (!this.builds.length) {
this.rootElem.classList.add('hide');
return;
}

const contentBlock = new ContentBlock(this.rootElem, 'saved-data', {
header: {
title: 'Preset Configurations',
tooltip: 'Preset configurations can apply an optimal combination of gear, talents, rotation and encounter settings.',
},
});

const buildsContainerRef = ref<HTMLDivElement>();

const container = (
<div className="saved-data-container">
<div className="saved-data-presets" ref={buildsContainerRef}></div>
</div>
);

this.simUI.sim.waitForInit().then(() => {
this.builds.forEach(build => {
const dataElemRef = ref<HTMLButtonElement>();
buildsContainerRef.value!.appendChild(
<button className="saved-data-set-chip badge rounded-pill" ref={dataElemRef}>
<span className="saved-data-set-name" attributes={{ role: 'button' }} onclick={() => this.applyBuild(build)}>
{build.name}
</span>
</button>,
);

tippy(dataElemRef.value!, {
content: (
<>
<p className="mb-1">This preset affects the following settings:</p>
<ul className="mb-0 text-capitalize">
{Object.keys(build)
.filter(c => c !== 'name')
.map(category => (build[category as PresetConfigurationCategory] ? <li>{category}</li> : undefined))}
</ul>
</>
),
});

const checkActive = () => dataElemRef.value!.classList[this.isBuildActive(build) ? 'add' : 'remove']('active');

checkActive();
TypedEvent.onAny([
this.simUI.player.changeEmitter,
this.simUI.sim.settingsChangeEmitter,
this.simUI.sim.raid.changeEmitter,
this.simUI.sim.encounter.changeEmitter,
]).on(checkActive);
});
contentBlock.bodyElement.replaceChildren(container);
});
}

private applyBuild({ gear, rotation, talents, epWeights, encounter }: PresetBuild) {
const eventID = TypedEvent.nextEventID();
TypedEvent.freezeAllAndDo(() => {
if (gear) this.simUI.player.setGear(eventID, this.simUI.sim.db.lookupEquipmentSpec(gear.gear));
if (talents) this.simUI.player.setTalentsString(eventID, talents.data.talentsString);
if (rotation?.rotation.rotation) {
this.simUI.player.setAplRotation(eventID, rotation.rotation.rotation);
}
if (epWeights) this.simUI.player.setEpWeights(eventID, epWeights.epWeights);
if (encounter) {
if (encounter.encounter) this.simUI.sim.encounter.fromProto(eventID, encounter.encounter);
if (encounter.healingModel) this.simUI.player.setHealingModel(eventID, encounter.healingModel);
if (encounter.tanks) this.simUI.sim.raid.setTanks(eventID, encounter.tanks);
if (encounter.buffs) this.simUI.player.setBuffs(eventID, encounter.buffs);
if (encounter.debuffs) this.simUI.sim.raid.setDebuffs(eventID, encounter.debuffs);
if (encounter.raidBuffs) this.simUI.sim.raid.setBuffs(eventID, encounter.raidBuffs);
if (encounter.consumes) this.simUI.player.setConsumes(eventID, encounter.consumes);
}
});
}

private isBuildActive({ gear, rotation, talents, epWeights, encounter }: PresetBuild): boolean {
const hasGear = gear ? EquipmentSpec.equals(gear.gear, this.simUI.player.getGear().asSpec()) : true;
const hasTalents = talents ? talents.data.talentsString == this.simUI.player.getTalentsString() : true;
let hasRotation = true;
if (rotation) {
const activeRotation = this.simUI.player.getResolvedAplRotation();
// Ensure that the auto rotation can be matched with a preset
if (activeRotation.type === APLRotation_Type.TypeAuto) activeRotation.type = APLRotation_Type.TypeAPL;
hasRotation = APLRotation.equals(rotation.rotation.rotation, activeRotation);
}
const hasEpWeights = epWeights ? this.simUI.player.getEpWeights().equals(epWeights.epWeights) : true;
const hasEncounter = encounter?.encounter ? Encounter.equals(encounter.encounter, this.simUI.sim.encounter.toProto()) : true;
const hasHealingModel = encounter?.healingModel ? HealingModel.equals(encounter.healingModel, this.simUI.player.getHealingModel()) : true;

return hasGear && hasTalents && hasRotation && hasEpWeights && hasEncounter && hasHealingModel;
}
}
6 changes: 6 additions & 0 deletions ui/core/components/individual_sim_ui/rotation_tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { SavedDataManager } from '../saved_data_manager';
import { SimTab } from '../sim_tab';
import { APLRotationPicker } from './apl_rotation_picker';
import { CooldownsPicker } from './cooldowns_picker';
import { PresetConfigurationPicker } from './preset_configuration_picker';

export class RotationTab extends SimTab {
protected simUI: IndividualSimUI<Spec>;
Expand Down Expand Up @@ -48,6 +49,7 @@ export class RotationTab extends SimTab {
this.buildAplContent();
this.buildSimpleContent();

this.buildPresetConfigurationPicker();
this.buildSavedDataPickers();
}

Expand Down Expand Up @@ -173,6 +175,10 @@ export class RotationTab extends SimTab {
}
}

private buildPresetConfigurationPicker() {
new PresetConfigurationPicker(this.rightPanel, this.simUI, 'rotation');
}

private buildSavedDataPickers() {
const savedRotationsManager = new SavedDataManager<Player<any>, SavedRotation>(this.rightPanel, this.simUI.player, {
label: 'Rotation',
Expand Down
9 changes: 6 additions & 3 deletions ui/core/components/individual_sim_ui/settings_tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { SimTab } from '../sim_tab';
import { IsbConfig } from './../other_inputs';
import { ConsumesPicker } from './consumes_picker';
import { ItemSwapPicker } from './item_swap_picker';
import { PresetBuildsPicker } from './preset_builds_picker';
import { PresetConfigurationPicker } from './preset_configuration_picker';

export class SettingsTab extends SimTab {
protected simUI: IndividualSimUI<Spec>;
Expand Down Expand Up @@ -80,6 +80,7 @@ export class SettingsTab extends SimTab {
this.buildBuffsSettings();
this.buildWorldBuffsSettings();
this.buildDebuffsSettings();
this.buildPresetConfigurationPicker();
this.buildSavedDataPickers();
}
});
Expand Down Expand Up @@ -108,8 +109,6 @@ export class SettingsTab extends SimTab {
true,
);

new PresetBuildsPicker(contentBlock.bodyElement, this.simUI);

new EnumPicker(contentBlock.bodyElement, this.simUI.player, {
id: 'player-level',
label: 'Level',
Expand Down Expand Up @@ -313,6 +312,10 @@ export class SettingsTab extends SimTab {
this.simUI.player.getRaid()?.debuffsChangeEmitter.emit(TypedEvent.nextEventID());
}

private buildPresetConfigurationPicker() {
new PresetConfigurationPicker(this.rightPanel, this.simUI, 'encounter');
}

private buildSavedDataPickers() {
const savedEncounterManager = new SavedDataManager<Encounter, SavedEncounter>(this.rightPanel, this.simUI.sim.encounter, {
label: 'Encounter',
Expand Down
Loading

0 comments on commit d49c844

Please sign in to comment.