Skip to content

Commit

Permalink
Merge pull request #3234 from wowsims/apl
Browse files Browse the repository at this point in the history
APL UI work, all values now implemented
  • Loading branch information
jimmyt857 authored Jul 2, 2023
2 parents 8a228d9 + 09fd924 commit b0b0d1a
Show file tree
Hide file tree
Showing 11 changed files with 815 additions and 291 deletions.
200 changes: 127 additions & 73 deletions ui/core/components/individual_sim_ui/apl_actions.ts
Original file line number Diff line number Diff line change
@@ -1,119 +1,173 @@
import {
APLListItem,
APLAction,
APLActionCastSpell,
APLActionSequence,
APLActionWait,
APLValue,
} from '../../proto/apl.js';

import { ActionID, Spec } from '../../proto/common.js';
import { EventID } from '../../typed_event.js';
import { Input, InputConfig } from '../input.js';
import { ActionId } from '../../proto_utils/action_id.js';
import { Player } from '../../player.js';
import { stringComparator } from '../../utils.js';
import { TextDropdownPicker } from '../dropdown_picker.js';

import * as AplHelpers from './apl_helpers.js';
import * as AplValues from './apl_values.js';

export class APLActionCastSpellPicker extends Input<Player<any>, APLActionCastSpell> {
private readonly spellIdPicker: AplHelpers.APLActionIDPicker;
export interface APLActionPickerConfig extends InputConfig<Player<any>, APLAction> {
}

constructor(parent: HTMLElement, player: Player<any>, config: InputConfig<Player<any>, APLActionCastSpell>) {
super(parent, 'apl-action-cast-spell-picker-root', player, config);
export type APLActionType = APLAction['action']['oneofKind'];

this.spellIdPicker = new AplHelpers.APLActionIDPicker(this.rootElem, player, {
defaultLabel: 'Spell',
values: [],
changedEvent: (player: Player<any>) => player.rotationChangeEmitter,
getValue: () => ActionId.fromProto(this.getSourceValue().spellId || ActionID.create()),
setValue: (eventID: EventID, player: Player<any>, newValue: ActionId) => {
this.getSourceValue().spellId = newValue.toProto();
player.rotationChangeEmitter.emit(eventID);
},
});
export class APLActionPicker extends Input<Player<any>, APLAction> {

this.init();
private typePicker: TextDropdownPicker<Player<any>, APLActionType>;

const updateValues = async () => {
const playerStats = player.getCurrentStats();
const spellPromises = Promise.all(playerStats.spells.map(spell => ActionId.fromProto(spell).fill()));
const cooldownPromises = Promise.all(playerStats.cooldowns.map(cd => ActionId.fromProto(cd).fill()));
private readonly actionDiv: HTMLElement;
private currentType: APLActionType;
private actionPicker: Input<Player<any>, any>|null;

let [spells, cooldowns] = await Promise.all([spellPromises, cooldownPromises]);
spells = spells.sort((a, b) => stringComparator(a.name, b.name))
cooldowns = cooldowns.sort((a, b) => stringComparator(a.name, b.name))
private readonly conditionPicker: AplValues.APLValuePicker;

constructor(parent: HTMLElement, player: Player<any>, config: APLActionPickerConfig) {
super(parent, 'apl-action-picker-root', player, config);

this.conditionPicker = new AplValues.APLValuePicker(this.rootElem, this.modObject, {
changedEvent: (player: Player<any>) => player.rotationChangeEmitter,
getValue: (player: Player<any>) => this.getSourceValue().condition,
setValue: (eventID: EventID, player: Player<any>, newValue: APLValue|undefined) => {
this.getSourceValue().condition = newValue;
player.rotationChangeEmitter.emit(eventID);
},
});

const values = [...spells, ...cooldowns].map(actionId => {
this.actionDiv = document.createElement('div');
this.actionDiv.classList.add('apl-action-picker-action');
this.rootElem.appendChild(this.actionDiv);

const allActionTypes = Object.keys(actionTypeFactories) as Array<NonNullable<APLActionType>>;
this.typePicker = new TextDropdownPicker(this.actionDiv, player, {
defaultLabel: 'Action',
values: allActionTypes.map(actionType => {
return {
value: actionId,
value: actionType,
label: actionTypeFactories[actionType].label,
};
});
this.spellIdPicker.setOptions(values);
};
updateValues();
player.currentStatsEmitter.on(updateValues);
}),
equals: (a, b) => a == b,
changedEvent: (player: Player<any>) => player.rotationChangeEmitter,
getValue: (player: Player<any>) => this.getSourceValue().action.oneofKind,
setValue: (eventID: EventID, player: Player<any>, newValue: APLActionType) => {
const action = this.getSourceValue();
if (action.action.oneofKind == newValue) {
return;
}
if (newValue) {
const factory = actionTypeFactories[newValue];
const obj: any = { oneofKind: newValue };
obj[newValue] = factory.newValue();
action.action = obj;
} else {
action.action = {
oneofKind: newValue,
};
}
player.rotationChangeEmitter.emit(eventID);
},
});

this.currentType = undefined;
this.actionPicker = null;

this.init();
}

getInputElem(): HTMLElement | null {
return this.rootElem;
}

getInputValue(): APLActionCastSpell {
return APLActionCastSpell.create({
spellId: this.spellIdPicker.getInputValue(),
getInputValue(): APLAction {
const actionType = this.typePicker.getInputValue();
return APLAction.create({
condition: this.conditionPicker.getInputValue(),
action: {
oneofKind: actionType,
...((() => {
const val: any = {};
if (actionType && this.actionPicker) {
val[actionType] = this.actionPicker.getInputValue();
}
return val;
})()),
},
})
}

setInputValue(newValue: APLActionCastSpell) {
setInputValue(newValue: APLAction) {
if (!newValue) {
return;
}
this.spellIdPicker.setInputValue(ActionId.fromProto(newValue.spellId || ActionID.create()));
}
}

export class APLActionSequencePicker extends Input<Player<any>, APLActionSequence> {
this.conditionPicker.setInputValue(newValue.condition || APLValue.create());

constructor(parent: HTMLElement, player: Player<any>, config: InputConfig<Player<any>, APLActionSequence>) {
super(parent, 'apl-action-sequence-picker-root', player, config);
this.init();
}
const newActionType = newValue.action.oneofKind;
this.updateActionPicker(newActionType);

getInputElem(): HTMLElement | null {
return this.rootElem;
if (newActionType) {
this.actionPicker!.setInputValue((newValue.action as any)[newActionType]);
}
}

getInputValue(): APLActionSequence {
return APLActionSequence.create({
})
}

setInputValue(newValue: APLActionSequence) {
if (!newValue) {
private updateActionPicker(newActionType: APLActionType) {
const actionType = this.currentType;
if (newActionType == actionType) {
return;
}
}
}
this.currentType = newActionType;

export class APLActionWaitPicker extends Input<Player<any>, APLActionWait> {
if (this.actionPicker) {
this.actionPicker.rootElem.remove();
this.actionPicker = null;
}

constructor(parent: HTMLElement, player: Player<any>, config: InputConfig<Player<any>, APLActionWait>) {
super(parent, 'apl-action-wait-picker-root', player, config);
this.init();
}
if (!newActionType) {
return;
}

getInputElem(): HTMLElement | null {
return this.rootElem;
this.typePicker.setInputValue(newActionType);

const factory = actionTypeFactories[newActionType];
this.actionPicker = factory.factory(this.actionDiv, this.modObject, {
changedEvent: (player: Player<any>) => player.rotationChangeEmitter,
getValue: () => (this.getSourceValue().action as any)[newActionType] || factory.newValue(),
setValue: (eventID: EventID, player: Player<any>, newValue: any) => {
(this.getSourceValue().action as any)[newActionType] = newValue;
player.rotationChangeEmitter.emit(eventID);
},
});
}
}

getInputValue(): APLActionWait {
return APLActionWait.create({
})
}
type ActionTypeConfig = {
label: string,
newValue: () => object,
factory: (parent: HTMLElement, player: Player<any>, config: InputConfig<Player<any>, any>) => Input<Player<any>, any>,
};

function inputBuilder<T extends object>(label: string, newValue: () => T, fields: Array<AplHelpers.APLPickerBuilderFieldConfig<T, any>>): ActionTypeConfig {
return {
label: label,
newValue: newValue,
factory: AplHelpers.aplInputBuilder(newValue, fields),
};
}

setInputValue(newValue: APLActionWait) {
if (!newValue) {
return;
}
}
}
export const actionTypeFactories: Record<NonNullable<APLActionType>, ActionTypeConfig> = {
['castSpell']: inputBuilder('Cast', APLActionCastSpell.create, [
AplHelpers.actionIdFieldConfig('spellId', 'all_spells'),
]),
['sequence']: inputBuilder('Sequence', APLActionSequence.create, [
]),
['wait']: inputBuilder('Wait', APLActionWait.create, [
]),
};
Loading

0 comments on commit b0b0d1a

Please sign in to comment.