From 463e5a195fb1bd3e20e6a62b89296c17ed9bf5fd Mon Sep 17 00:00:00 2001 From: g0shu <58014602+g0shu@users.noreply.github.com> Date: Sun, 1 Oct 2023 00:40:05 +0300 Subject: [PATCH] oopsy: add initData support (#5817) --- types/oopsy.d.ts | 25 +++++++++-- ui/oopsyraidsy/damage_tracker.ts | 33 ++++++++++++++- ui/oopsyraidsy/data/00-misc/general.ts | 41 +++++++++++-------- ui/oopsyraidsy/data/05-shb/raid/e6s.ts | 4 +- .../another_sildihn_subterrane-savage.ts | 5 +++ .../dungeon/another_sildihn_subterrane.ts | 5 +++ 6 files changed, 88 insertions(+), 25 deletions(-) diff --git a/types/oopsy.d.ts b/types/oopsy.d.ts index 9293ed67f6..2b7616dd94 100644 --- a/types/oopsy.d.ts +++ b/types/oopsy.d.ts @@ -105,7 +105,17 @@ export type OopsyTrigger = type MistakeMap = { [mistakeId: string]: string }; -type SimpleOopsyTriggerSet = { +export type DataInitializeFunc = () => Omit; + +// This helper takes all of the properties in Type and checks to see if they can be assigned to a +// blank object, and if so excludes them from the returned union. The `-?` syntax removes the +// optional modifier from the attribute which prevents `undefined` from being included in the union +// See also: https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#mapping-modifiers +type RequiredFieldsAsUnion = { + [key in keyof Type]-?: Record extends Pick ? never : key; +}[keyof Type]; + +type SimpleOopsyTriggerSet = { zoneId: ZoneIdType | ZoneIdType[]; zoneLabel?: LocaleText; damageWarn?: MistakeMap; @@ -116,12 +126,19 @@ type SimpleOopsyTriggerSet = { shareFail?: MistakeMap; soloWarn?: MistakeMap; soloFail?: MistakeMap; -}; - -export type OopsyTriggerSet = SimpleOopsyTriggerSet & { triggers?: OopsyTrigger[]; }; +// If Data contains required properties that are not on OopsyData, require initData +export type OopsyTriggerSet = + & SimpleOopsyTriggerSet + & (RequiredFieldsAsUnion extends RequiredFieldsAsUnion ? { + initData?: DataInitializeFunc; + } + : { + initData: DataInitializeFunc; + }); + export type LooseOopsyTrigger = Partial< BaseOopsyTrigger & OopsyTriggerRegex<'None'> >; diff --git a/ui/oopsyraidsy/damage_tracker.ts b/ui/oopsyraidsy/damage_tracker.ts index 92acb0333d..abc2da6fa5 100644 --- a/ui/oopsyraidsy/damage_tracker.ts +++ b/ui/oopsyraidsy/damage_tracker.ts @@ -12,6 +12,7 @@ import { Job, Role } from '../../types/job'; import { Matches, NetMatches } from '../../types/net_matches'; import { CactbotBaseRegExp } from '../../types/net_trigger'; import { + DataInitializeFunc, LooseOopsyTrigger, LooseOopsyTriggerSet, MistakeMap, @@ -117,6 +118,10 @@ export class DamageTracker { private zoneName?: string; private zoneId: ZoneIdType = ZoneId.MatchAll; private contentType = 0; + protected dataInitializers: { + file: string; + func: DataInitializeFunc; + }[] = []; constructor( private options: OopsyOptions, @@ -153,7 +158,7 @@ export class DamageTracker { } GetDataObject(): OopsyData { - return { + const data: OopsyData = { me: this.me, job: this.job, role: this.role, @@ -174,6 +179,23 @@ export class DamageTracker { // Deprecated. ParseLocaleFloat: parseFloat, }; + + let triggerData = {}; + + for (const initObj of this.dataInitializers) { + const init = initObj.func; + const initData = init(); + if (typeof initData === 'object') { + triggerData = { + ...triggerData, + ...initData, + }; + } else { + console.log(`Error in file: ${initObj.file}: these triggers may not work; + initData function returned invalid object: ${init.toString()}`); + } + } + return { ...triggerData, ...data }; } // TODO: this shouldn't clear timers and triggers @@ -673,6 +695,15 @@ export class DamageTracker { console.log('Loading user triggers for zone'); } + const setFilename = set.filename ?? 'Unknown'; + + if (set.initData) { + this.dataInitializers.push({ + file: setFilename, + func: set.initData, + }); + } + this.AddDamageTriggers('warn', set.damageWarn); this.AddDamageTriggers('fail', set.damageFail); this.AddGainsEffectTriggers('warn', set.gainsEffectWarn); diff --git a/ui/oopsyraidsy/data/00-misc/general.ts b/ui/oopsyraidsy/data/00-misc/general.ts index d7aba62044..37a7cc3c4b 100644 --- a/ui/oopsyraidsy/data/00-misc/general.ts +++ b/ui/oopsyraidsy/data/00-misc/general.ts @@ -11,14 +11,14 @@ type MitTracker = { }; export interface Data extends OopsyData { - lostFood?: { [name: string]: boolean }; - originalRaiser?: { [targetId: string]: string }; - lastRaisedLostTime?: { [targetId: string]: string }; - raiseTargetTracker?: { [sourceId: string]: string }; - targetMitTracker?: { + lostFood: { [name: string]: boolean }; + originalRaiser: { [targetId: string]: string }; + lastRaisedLostTime: { [targetId: string]: string }; + raiseTargetTracker: { [sourceId: string]: string }; + targetMitTracker: { [targetId: string]: MitTracker; }; - partyMitTracker?: MitTracker; + partyMitTracker: MitTracker; } const raiseAbilityIds = [ @@ -76,6 +76,16 @@ const shieldEffectIdToAbilityId: { [id: string]: string } = { // General mistakes; these apply everywhere. const triggerSet: OopsyTriggerSet = { zoneId: ZoneId.MatchAll, + initData: () => { + return { + lostFood: {}, + originalRaiser: {}, + lastRaisedLostTime: {}, + raiseTargetTracker: {}, + targetMitTracker: {}, + partyMitTracker: {}, + }; + }, triggers: [ { // Trigger id for internally generated early pull warning. @@ -93,7 +103,6 @@ const triggerSet: OopsyTriggerSet = { return matches.target === matches.source; }, mistake: (data, matches) => { - data.lostFood ??= {}; // Well Fed buff happens repeatedly when it falls off (WHY), // so suppress multiple occurrences. if (!data.inCombat || data.lostFood[matches.target]) @@ -119,8 +128,6 @@ const triggerSet: OopsyTriggerSet = { type: 'GainsEffect', netRegex: NetRegexes.gainsEffect({ effectId: '30' }), run: (data, matches) => { - if (!data.lostFood) - return; delete data.lostFood[matches.target]; }, }, @@ -151,7 +158,7 @@ const triggerSet: OopsyTriggerSet = { type: 'LosesEffect', netRegex: NetRegexes.losesEffect({ effectId: '94' }), run: (data, matches) => { - (data.lastRaisedLostTime ??= {})[matches.targetId] = matches.timestamp; + data.lastRaisedLostTime[matches.targetId] = matches.timestamp; }, }, { @@ -159,8 +166,6 @@ const triggerSet: OopsyTriggerSet = { type: 'GainsEffect', netRegex: NetRegexes.gainsEffect({ effectId: '94' }), mistake: (data, matches) => { - data.lastRaisedLostTime ??= {}; - data.originalRaiser ??= {}; const originalRaiser = data.originalRaiser[matches.targetId]; // 30 and 26 lines having the same timestamp means effect was overwritten and the target is still dead const overwrittenRaise = data.lastRaisedLostTime[matches.targetId] === matches.timestamp; @@ -190,7 +195,7 @@ const triggerSet: OopsyTriggerSet = { type: 'StartsUsing', netRegex: NetRegexes.startsUsing({ id: raiseAbilityIds }), run: (data, matches) => { - (data.raiseTargetTracker ??= {})[matches.sourceId] = matches.targetId; + data.raiseTargetTracker[matches.sourceId] = matches.targetId; }, }, { @@ -198,9 +203,9 @@ const triggerSet: OopsyTriggerSet = { type: 'Ability', netRegex: NetRegexes.ability({ id: raiseAbilityIds, targetId: 'E0000000' }), mistake: (data, matches) => { - const targetId = (data.raiseTargetTracker ??= {})[matches.sourceId]; + const targetId = data.raiseTargetTracker[matches.sourceId]; if (targetId !== undefined) { - const originalRaiser = (data.originalRaiser ??= {})[targetId]; + const originalRaiser = data.originalRaiser[targetId]; if (originalRaiser !== undefined) { return { type: 'warn', @@ -231,8 +236,8 @@ const triggerSet: OopsyTriggerSet = { return; const mitTracker = isTargetMit - ? ((data.targetMitTracker ??= {})[matches.targetId] ??= {}) - : (data.partyMitTracker ??= {}); + ? (data.targetMitTracker[matches.targetId] ??= {}) + : data.partyMitTracker; const newTime = new Date(matches.timestamp).getTime(); const newSource = data.ShortName(matches.source); const lastTime = mitTracker[matches.id]?.time; @@ -270,7 +275,7 @@ const triggerSet: OopsyTriggerSet = { run: (data, matches) => { const abilityId = shieldEffectIdToAbilityId[matches.effectId]; if (abilityId !== undefined) - delete (data.partyMitTracker ??= {})?.[abilityId]; + delete data.partyMitTracker[abilityId]; }, }, ], diff --git a/ui/oopsyraidsy/data/05-shb/raid/e6s.ts b/ui/oopsyraidsy/data/05-shb/raid/e6s.ts index 9cae21627c..091399e249 100644 --- a/ui/oopsyraidsy/data/05-shb/raid/e6s.ts +++ b/ui/oopsyraidsy/data/05-shb/raid/e6s.ts @@ -1,12 +1,12 @@ import ZoneId from '../../../../../resources/zone_id'; -import { SimpleOopsyTriggerSet } from '../../../../../types/oopsy'; +import { OopsyTriggerSet } from '../../../../../types/oopsy'; // TODO: check tethers being cut (when they shouldn't) // TODO: check for concussed debuff // TODO: check for taking tankbuster with lightheaded // TODO: check for one person taking multiple Storm Of Fury Tethers (4C01/4C08) -const triggerSet: SimpleOopsyTriggerSet = { +const triggerSet: OopsyTriggerSet = { zoneId: ZoneId.EdensVerseFurorSavage, damageWarn: { // It's common to just ignore futbol mechanics, so don't warn on Strike Spark. diff --git a/ui/oopsyraidsy/data/06-ew/dungeon/another_sildihn_subterrane-savage.ts b/ui/oopsyraidsy/data/06-ew/dungeon/another_sildihn_subterrane-savage.ts index 562467978b..035779ae7a 100644 --- a/ui/oopsyraidsy/data/06-ew/dungeon/another_sildihn_subterrane-savage.ts +++ b/ui/oopsyraidsy/data/06-ew/dungeon/another_sildihn_subterrane-savage.ts @@ -36,6 +36,11 @@ const stackMistake = ( const triggerSet: OopsyTriggerSet = { zoneId: ZoneId.AnotherSildihnSubterraneSavage, + initData: () => { + return { + hasRiteOfPassage: {}, + }; + }, damageWarn: { 'ASSS Aqueduct Kaluk Right Sweep': '797B', // right 200 degree cleave 'ASSS Aqueduct Kaluk Left Sweep': '797C', // left 200 degree cleave diff --git a/ui/oopsyraidsy/data/06-ew/dungeon/another_sildihn_subterrane.ts b/ui/oopsyraidsy/data/06-ew/dungeon/another_sildihn_subterrane.ts index 0918a69be3..652f9715cd 100644 --- a/ui/oopsyraidsy/data/06-ew/dungeon/another_sildihn_subterrane.ts +++ b/ui/oopsyraidsy/data/06-ew/dungeon/another_sildihn_subterrane.ts @@ -33,6 +33,11 @@ const stackMistake = ( const triggerSet: OopsyTriggerSet = { zoneId: ZoneId.AnotherSildihnSubterrane, + initData: () => { + return { + hasRiteOfPassage: {}, + }; + }, damageWarn: { 'ASS Aqueduct Kaluk Right Sweep': '7963', // right 200 degree cleave 'ASS Aqueduct Kaluk Left Sweep': '7964', // left 200 degree cleave