From bad483b2d3f97cbbd757feb4c9340adb8a2e3f9a Mon Sep 17 00:00:00 2001 From: Adrian Klingen Date: Tue, 20 Aug 2024 10:33:28 +0200 Subject: [PATCH 1/5] Fix default encounter target --- proto/common.proto | 2 +- ui/core/encounter.ts | 55 +++++++++++++++++++++++++++++++------------- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/proto/common.proto b/proto/common.proto index b9c4d7385a..4d7593e57a 100644 --- a/proto/common.proto +++ b/proto/common.proto @@ -25,7 +25,7 @@ message ProtoVersion { // protos need to define an api_version field so that the UI code knows // to up-convert these protos to the new format whenever api_version is // missing (0) or lower than current_version_number. - option (current_version_number) = 2; + option (current_version_number) = 3; // The actual field value is only used within unit tests. int32 saved_version_number = 1; diff --git a/ui/core/encounter.ts b/ui/core/encounter.ts index e6fd6fca97..13d90e3a67 100644 --- a/ui/core/encounter.ts +++ b/ui/core/encounter.ts @@ -1,10 +1,11 @@ -import * as Mechanics from './constants/mechanics.js'; -import { CURRENT_API_VERSION } from './constants/other.js'; -import { UnitMetadataList } from './player.js'; -import { Encounter as EncounterProto, MobType, PresetEncounter, PresetTarget, SpellSchool, Stat, Target as TargetProto, TargetInput } from './proto/common.js'; -import { Stats } from './proto_utils/stats.js'; -import { Sim } from './sim.js'; -import { EventID, TypedEvent } from './typed_event.js'; +import Toast from './components/toast'; +import * as Mechanics from './constants/mechanics'; +import { CURRENT_API_VERSION } from './constants/other'; +import { UnitMetadataList } from './player'; +import { Encounter as EncounterProto, MobType, PresetEncounter, PresetTarget, SpellSchool, Stat, Target as TargetProto, TargetInput } from './proto/common'; +import { Stats } from './proto_utils/stats'; +import { Sim } from './sim'; +import { EventID, TypedEvent } from './typed_event'; // Manages all the settings for an Encounter. export class Encounter { @@ -172,28 +173,43 @@ export class Encounter { } static defaultTargetProto(): TargetProto { + // Copy default raid target used as fallback for missing DB. + // https://github.com/wowsims/cata/blob/3570c4fcf1a4e2cd81926019d4a1b3182f613de1/sim/encounters/register_all.go#L24 return TargetProto.create({ + id: 31146, + name: 'Raid Target', level: Mechanics.BOSS_LEVEL, mobType: MobType.MobTypeGiant, - tankIndex: 0, - swingSpeed: 1.5, - minBaseDamage: 65000, - dualWield: false, - dualWieldPenalty: false, - suppressDodge: false, - parryHaste: true, - spellSchool: SpellSchool.SpellSchoolPhysical, stats: Stats.fromMap({ [Stat.StatArmor]: 11977, [Stat.StatAttackPower]: 805, + [Stat.StatHealth]: 120016403, }).asProtoArray(), + minBaseDamage: 210000, + damageSpread: 0.4, + tankIndex: 0, + swingSpeed: 2.5, + suppressDodge: false, + parryHaste: false, + dualWield: false, + dualWieldPenalty: false, + spellSchool: SpellSchool.SpellSchoolPhysical, targetInputs: new Array(0), }); } static updateProtoVersion(proto: EncounterProto) { - // First migrate the stats arrays embedded in each target. + let showOutOfDateEncounterTargetWarning = false; proto.targets.forEach(target => { + // If the old target is detected return the + // new default target without needing to migrate the stats + if (target.minBaseDamage === 65000) { + target = Encounter.defaultTargetProto(); + showOutOfDateEncounterTargetWarning = true; + return; + } + + // Migrate the stats arrays embedded in each target target.stats = Stats.migrateStatsArray(target.stats, proto.apiVersion, this.defaultTargetProto().stats); }); @@ -201,5 +217,12 @@ export class Encounter { // Flag the version as up-to-date once all migrations are done. proto.apiVersion = CURRENT_API_VERSION; + + if (showOutOfDateEncounterTargetWarning) + new Toast({ + delay: 5000, + variant: 'info', + body: 'We detected an out-of-date encounter target with WOTLK settings. It has been updated it to the latest version.', + }); } } From ac9cb0de5b8609d77777b7bdd4adb455edab021f Mon Sep 17 00:00:00 2001 From: Adrian Klingen Date: Tue, 20 Aug 2024 11:25:16 +0200 Subject: [PATCH 2/5] Fix minBaseDamage input and healingmodel --- proto/common.proto | 6 ++++++ ui/core/components/encounter_picker.ts | 16 ++++++++-------- ui/core/encounter.ts | 8 ++++---- ui/core/player.ts | 15 +++++++++++++++ 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/proto/common.proto b/proto/common.proto index 4d7593e57a..31a08a4da4 100644 --- a/proto/common.proto +++ b/proto/common.proto @@ -998,6 +998,12 @@ message Cooldowns { } message HealingModel { + // Proto version at the time these healing settings were saved. If you + // make any changes to this proto that will break saved browser data or + // old sim links, then make sure to increment the current_version_number + // option within the ProtoVersion message at the top of this file, and + // also modify the updateHealingModelProtoVersion() method of ui/core/player.ts. + int32 api_version = 6; // Healing per second to apply. double hps = 1; // How often healing is applied. diff --git a/ui/core/components/encounter_picker.ts b/ui/core/components/encounter_picker.ts index b65c8294c3..f82201183c 100644 --- a/ui/core/components/encounter_picker.ts +++ b/ui/core/components/encounter_picker.ts @@ -384,7 +384,7 @@ class TargetPicker extends Input { this.statPickers = ALL_TARGET_STATS.map(statData => { const stat = statData.stat; return new NumberPicker(section2, null, { - id: `target-picker-stats-${statData.stat}`, + id: `target-${this.targetIndex}-picker-stats-${statData.stat}`, inline: true, extraCssClasses: statData.extraCssClasses, label: getStatName(stat), @@ -399,7 +399,7 @@ class TargetPicker extends Input { }); this.swingSpeedPicker = new NumberPicker(section3, null, { - id: 'target-picker-swing-speed', + id: `target-${this.targetIndex}-picker-swing-speed`, label: 'Swing Speed', labelTooltip: 'Time in seconds between auto attacks. Set to 0 to disable auto attacks.', float: true, @@ -411,7 +411,7 @@ class TargetPicker extends Input { }, }); this.minBaseDamagePicker = new NumberPicker(section3, null, { - id: 'target-picker-min-base-damage', + id: `target-${this.targetIndex}-picker-min-base-damage`, label: 'Min Base Damage', labelTooltip: 'Base damage for auto attacks, i.e. lowest roll with 0 AP against a 0-armor Player.', changedEvent: () => encounter.targetsChangeEmitter, @@ -422,7 +422,7 @@ class TargetPicker extends Input { }, }); this.damageSpreadPicker = new NumberPicker(section3, null, { - id: 'target-picker-damage-spread', + id: `target-${this.targetIndex}-picker-damage-spread`, label: 'Damage Spread', labelTooltip: 'Fractional spread between the minimum and maximum auto-attack damage from this enemy at 0 Attack Power.', float: true, @@ -434,7 +434,7 @@ class TargetPicker extends Input { }, }); this.dualWieldPicker = new BooleanPicker(section3, null, { - id: 'target-picker-dual-wield', + id: `target-${this.targetIndex}-picker-dual-wield`, label: 'Dual Wield', labelTooltip: 'Uses 2 separate weapons to attack.', inline: true, @@ -447,7 +447,7 @@ class TargetPicker extends Input { }, }); this.dwMissPenaltyPicker = new BooleanPicker(section3, null, { - id: 'target-picker-dw-miss-penalty', + id: `target-${this.targetIndex}-picker-dw-miss-penalty`, label: 'DW Miss Penalty', labelTooltip: 'Enables the Dual Wield Miss Penalty (+19% chance to miss) if dual wielding. Bosses in Hyjal/BT/SWP usually have this disabled to stop tanks from avoidance stacking.', @@ -462,7 +462,7 @@ class TargetPicker extends Input { enableWhen: () => this.getTarget().dualWield, }); this.parryHastePicker = new BooleanPicker(section3, null, { - id: 'target-picker-parry-haste', + id: `target-${this.targetIndex}-picker-parry-haste`, label: 'Parry Haste', labelTooltip: 'Whether this enemy will gain parry haste when parrying attacks.', inline: true, @@ -475,7 +475,7 @@ class TargetPicker extends Input { }, }); this.spellSchoolPicker = new EnumPicker(section3, null, { - id: 'target-picker-spell-school', + id: `target-${this.targetIndex}-picker-spell-school`, label: 'Spell School', labelTooltip: 'Type of damage caused by auto attacks. This is usually Physical, but some enemies have elemental attacks.', values: [ diff --git a/ui/core/encounter.ts b/ui/core/encounter.ts index 13d90e3a67..37fc8a57fe 100644 --- a/ui/core/encounter.ts +++ b/ui/core/encounter.ts @@ -39,7 +39,7 @@ export class Encounter { } get primaryTarget(): TargetProto { - return TargetProto.clone(this.targets[0]); + return this.targets[0]; } getDurationVariation(): number { @@ -200,11 +200,11 @@ export class Encounter { static updateProtoVersion(proto: EncounterProto) { let showOutOfDateEncounterTargetWarning = false; - proto.targets.forEach(target => { + proto.targets.forEach((target, index) => { // If the old target is detected return the // new default target without needing to migrate the stats if (target.minBaseDamage === 65000) { - target = Encounter.defaultTargetProto(); + proto.targets[index] = Encounter.defaultTargetProto(); showOutOfDateEncounterTargetWarning = true; return; } @@ -222,7 +222,7 @@ export class Encounter { new Toast({ delay: 5000, variant: 'info', - body: 'We detected an out-of-date encounter target with WOTLK settings. It has been updated it to the latest version.', + body: 'We detected an out-of-date encounter target with WOTLK settings. Encounter settings have been updated the latest defaults.', }); } } diff --git a/ui/core/player.ts b/ui/core/player.ts index 7d137f4538..378e80f647 100644 --- a/ui/core/player.ts +++ b/ui/core/player.ts @@ -1,5 +1,6 @@ import Toast from './components/toast'; import * as Mechanics from './constants/mechanics'; +import { CURRENT_API_VERSION } from './constants/other'; import { MAX_PARTY_SIZE, Party } from './party'; import { PlayerClass } from './player_class'; import { PlayerSpec } from './player_spec'; @@ -1505,6 +1506,11 @@ export class Player { fromProto(eventID: EventID, proto: PlayerProto, includeCategories?: Array) { const loadCategory = (cat: SimSettingCategories) => !includeCategories || includeCategories.length == 0 || includeCategories.includes(cat); + // Fix out-of-date protos before importing + if (proto.healingModel && proto.healingModel.apiVersion < CURRENT_API_VERSION) { + Player.updateHealingModelProtoVersion(proto); + } + TypedEvent.freezeAllAndDo(() => { if (loadCategory(SimSettingCategories.Gear)) { this.setGear(eventID, proto.equipment ? this.sim.db.lookupEquipmentSpec(proto.equipment) : new Gear({})); @@ -1548,6 +1554,15 @@ export class Player { }); } + static updateHealingModelProtoVersion(proto: PlayerProto) { + // API version null -> 3: Added new encounter target defaults + // This means we should reset the healing model to prevent incorrect behavior + // due to automatic defaults being calculated based on encounter target stats. + if (proto.healingModel && proto.healingModel.apiVersion < 3) { + proto.healingModel = HealingModel.create(); + } + } + clone(eventID: EventID): Player { const newPlayer = new Player(this.playerSpec, this.sim); newPlayer.fromProto(eventID, this.toProto()); From fdf01993adfb1c0f810491c57c4e1b28a3e2df15 Mon Sep 17 00:00:00 2001 From: Adrian Klingen Date: Tue, 20 Aug 2024 11:40:02 +0200 Subject: [PATCH 3/5] Update API version --- sim/core/TestProtoVersioning.results | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sim/core/TestProtoVersioning.results b/sim/core/TestProtoVersioning.results index 8bade4ddf3..e7ee4a6935 100644 --- a/sim/core/TestProtoVersioning.results +++ b/sim/core/TestProtoVersioning.results @@ -1 +1 @@ -saved_version_number: 2 +saved_version_number: 3 From 71ac277a1d6085e2d9ecb3b0dc9ad45da075a191 Mon Sep 17 00:00:00 2001 From: Adrian Klingen Date: Tue, 20 Aug 2024 20:25:14 +0200 Subject: [PATCH 4/5] Undo encounter migration --- proto/common.proto | 6 ------ ui/core/encounter.ts | 18 +----------------- ui/core/player.ts | 14 -------------- 3 files changed, 1 insertion(+), 37 deletions(-) diff --git a/proto/common.proto b/proto/common.proto index 31a08a4da4..4d7593e57a 100644 --- a/proto/common.proto +++ b/proto/common.proto @@ -998,12 +998,6 @@ message Cooldowns { } message HealingModel { - // Proto version at the time these healing settings were saved. If you - // make any changes to this proto that will break saved browser data or - // old sim links, then make sure to increment the current_version_number - // option within the ProtoVersion message at the top of this file, and - // also modify the updateHealingModelProtoVersion() method of ui/core/player.ts. - int32 api_version = 6; // Healing per second to apply. double hps = 1; // How often healing is applied. diff --git a/ui/core/encounter.ts b/ui/core/encounter.ts index 37fc8a57fe..543ce1c2be 100644 --- a/ui/core/encounter.ts +++ b/ui/core/encounter.ts @@ -199,17 +199,8 @@ export class Encounter { } static updateProtoVersion(proto: EncounterProto) { - let showOutOfDateEncounterTargetWarning = false; + // First migrate the stats arrays embedded in each target. proto.targets.forEach((target, index) => { - // If the old target is detected return the - // new default target without needing to migrate the stats - if (target.minBaseDamage === 65000) { - proto.targets[index] = Encounter.defaultTargetProto(); - showOutOfDateEncounterTargetWarning = true; - return; - } - - // Migrate the stats arrays embedded in each target target.stats = Stats.migrateStatsArray(target.stats, proto.apiVersion, this.defaultTargetProto().stats); }); @@ -217,12 +208,5 @@ export class Encounter { // Flag the version as up-to-date once all migrations are done. proto.apiVersion = CURRENT_API_VERSION; - - if (showOutOfDateEncounterTargetWarning) - new Toast({ - delay: 5000, - variant: 'info', - body: 'We detected an out-of-date encounter target with WOTLK settings. Encounter settings have been updated the latest defaults.', - }); } } diff --git a/ui/core/player.ts b/ui/core/player.ts index 378e80f647..179267931e 100644 --- a/ui/core/player.ts +++ b/ui/core/player.ts @@ -1506,11 +1506,6 @@ export class Player { fromProto(eventID: EventID, proto: PlayerProto, includeCategories?: Array) { const loadCategory = (cat: SimSettingCategories) => !includeCategories || includeCategories.length == 0 || includeCategories.includes(cat); - // Fix out-of-date protos before importing - if (proto.healingModel && proto.healingModel.apiVersion < CURRENT_API_VERSION) { - Player.updateHealingModelProtoVersion(proto); - } - TypedEvent.freezeAllAndDo(() => { if (loadCategory(SimSettingCategories.Gear)) { this.setGear(eventID, proto.equipment ? this.sim.db.lookupEquipmentSpec(proto.equipment) : new Gear({})); @@ -1554,15 +1549,6 @@ export class Player { }); } - static updateHealingModelProtoVersion(proto: PlayerProto) { - // API version null -> 3: Added new encounter target defaults - // This means we should reset the healing model to prevent incorrect behavior - // due to automatic defaults being calculated based on encounter target stats. - if (proto.healingModel && proto.healingModel.apiVersion < 3) { - proto.healingModel = HealingModel.create(); - } - } - clone(eventID: EventID): Player { const newPlayer = new Player(this.playerSpec, this.sim); newPlayer.fromProto(eventID, this.toProto()); From 580e64de9e7d142383cd8f4e32945e55fad5a552 Mon Sep 17 00:00:00 2001 From: Adrian Klingen Date: Tue, 20 Aug 2024 20:39:34 +0200 Subject: [PATCH 5/5] Lint fixes --- ui/core/encounter.ts | 3 +-- ui/core/player.ts | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/ui/core/encounter.ts b/ui/core/encounter.ts index 543ce1c2be..49077f335d 100644 --- a/ui/core/encounter.ts +++ b/ui/core/encounter.ts @@ -1,4 +1,3 @@ -import Toast from './components/toast'; import * as Mechanics from './constants/mechanics'; import { CURRENT_API_VERSION } from './constants/other'; import { UnitMetadataList } from './player'; @@ -200,7 +199,7 @@ export class Encounter { static updateProtoVersion(proto: EncounterProto) { // First migrate the stats arrays embedded in each target. - proto.targets.forEach((target, index) => { + proto.targets.forEach(target => { target.stats = Stats.migrateStatsArray(target.stats, proto.apiVersion, this.defaultTargetProto().stats); }); diff --git a/ui/core/player.ts b/ui/core/player.ts index 179267931e..7d137f4538 100644 --- a/ui/core/player.ts +++ b/ui/core/player.ts @@ -1,6 +1,5 @@ import Toast from './components/toast'; import * as Mechanics from './constants/mechanics'; -import { CURRENT_API_VERSION } from './constants/other'; import { MAX_PARTY_SIZE, Party } from './party'; import { PlayerClass } from './player_class'; import { PlayerSpec } from './player_spec';