Skip to content

Commit

Permalink
Merge branch 'master' into feature/results-refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
1337LutZ committed Aug 19, 2024
2 parents 0fee7ef + a02ad7f commit fadaaa8
Show file tree
Hide file tree
Showing 285 changed files with 40,791 additions and 41,037 deletions.
2 changes: 1 addition & 1 deletion .deployedprotoversion
Original file line number Diff line number Diff line change
@@ -1 +1 @@
saved_version_number: 1
saved_version_number: 2
Binary file modified assets/database/db.bin
Binary file not shown.
14,314 changes: 7,157 additions & 7,157 deletions assets/database/db.json

Large diffs are not rendered by default.

Binary file modified assets/database/leftover_db.bin
Binary file not shown.
58,764 changes: 29,382 additions & 29,382 deletions assets/database/leftover_db.json

Large diffs are not rendered by default.

137 changes: 96 additions & 41 deletions proto/common.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -128,8 +128,46 @@ enum Profession {
Archeology = 12;
}

// Keep in sync with sim/core/stats/stats.go.
// NextIndex: 31;
// General rules for Stats vs. PseudoStats at the proto level:
// - Define a property as a Stat if and only if it needs to be present in
// one or more stats arrays embedded in the database files, local storage
// data, or sim links. This generally means that the property is a BASIC
// attribute that is directly found on items or enchants and parsed from
// tooltips during database generation. Alternatively, if the stat is
// required for reconstructing a target NPC from saved Encounter
// settings, then it also belongs in the Stat enum.
//
// - If the above criterion is not satisfied, then the best practice is to
// define the property as a PseudoStat rather than a Stat. For example,
// the various school-specific versions of Hit, Crit, and Haste are all
// defined as PseudoStats from Cataclysm onwards, since only the generic
// Ratings need to be parsed from item data and stored in the sim
// database.
//
// - Note that the above rules apply only for the proto messages used for
// saving and loading data in the browser. It is perfectly okay to define
// additional Stats in the back-end code for convenience or performance
// reasons, such as for automatically propagating linear stat
// dependencies when dynamic stat changes occur in a sim iteration. For
// example, the SpellHit PseudoStat mentioned above is actually modeled
// as a proper Stat in the back-end code so that it can benefit from the
// StatDependency tooling, but is converted to a PseudoStat when writing
// UnitStats protos for character stats and stat weights requests. This
// keeps the item database compact while still giving the UI access to
// calculated tertiary stats like SpellHit, MeleeCrit, RangedHaste, etc.
//
// - When adding new Stats or PseudoStats, make the units for each property
// explicit in the name to avoid confusion. For example, append "Rating"
// to the end of the field name for properties that are represented in
// Rating units (regardless of how they are stored in-game), and append
// "Chance" to the end of the field name for properties that represent
// probabilities (between 0 and 1).
//
// Keep in sync with sim/core/stats/stats.go. As mentioned above, it is okay for
// the Go Stats array to be larger than the size of the Stat enum proto, but the
// shared indices between the two must exactly match.
//
// NextIndex: 27;
enum Stat {
// Primary attributes ("main stat")
StatStrength = 0;
Expand All @@ -139,36 +177,34 @@ enum Stat {

// Reforge-able secondary stats
StatSpirit = 4;
StatMeleeHit = 5;
StatSpellHit = 6;
StatMeleeCrit = 7;
StatSpellCrit = 8;
StatMeleeHaste = 9;
StatSpellHaste = 10;
StatExpertise = 11;
StatDodge = 12;
StatParry = 13;
StatMastery = 14;
StatHitRating = 5;
StatCritRating = 6;
StatHasteRating = 7;
StatExpertiseRating = 8;
StatDodgeRating = 9;
StatParryRating = 10;
StatMasteryRating = 11;

// Non-reforge-able secondary stats found on gear
StatAttackPower = 15;
StatRangedAttackPower = 16;
StatSpellPower = 17;
StatMP5 = 18;
StatSpellPenetration = 19;
StatResilience = 20;
StatArcaneResistance = 21;
StatFireResistance = 22;
StatFrostResistance = 23;
StatNatureResistance = 24;
StatShadowResistance = 25;
StatArmor = 26; // "white armor" that fully scales with all multipliers
StatBonusArmor = 27; // "green armor" that does not scale

// Composite stats that are built up from the above gear stats + buffs
StatHealth = 28;
StatMana = 29;
StatBlock = 30;
StatAttackPower = 12;
StatRangedAttackPower = 13;
StatSpellPower = 14;
StatSpellPenetration = 15;
StatResilienceRating = 16;
StatArcaneResistance = 17;
StatFireResistance = 18;
StatFrostResistance = 19;
StatNatureResistance = 20;
StatShadowResistance = 21;
StatArmor = 22; // "white armor" that fully scales with all multipliers
StatBonusArmor = 23; // "green armor" that does not scale

// Composite stats that are built up from the above gear stats + buffs.
// These still belong in the Stat enum because they can be present on
// some enchants and because the base values need to be stored for NPCs.
StatHealth = 24;
StatMana = 25;
StatMP5 = 26;

// DO NOT add new stats here without discussing it first; new stats come
// with a performance penalty.
Expand Down Expand Up @@ -197,19 +233,38 @@ enum Stat {
}

// Not all pseudostats are included here; just the ones we want to pass
// between the UI and backend.
// between the UI and backend. It's also OK to include things here which aren't
// in the PseudoStats struct.
//
// It's also OK to include things here which aren't in the PseudoStats struct.
// NextIndex: 16;
enum PseudoStat {
PseudoStatMainHandDps = 0;
PseudoStatOffHandDps = 1;
PseudoStatRangedDps = 2;
PseudoStatBlockDamageReduction = 3;
PseudoStatDodge = 4;
PseudoStatParry = 5;
PseudoStatRangedSpeedMultiplier = 6;
PseudoStatMeleeSpeedMultiplier = 7;

// Final buffed values including DR, represented as percentages (0-100)
PseudoStatDodgePercent = 3;
PseudoStatParryPercent = 4;
PseudoStatBlockPercent = 5;

// Net impact of all multiplicative Haste buffs (Bloodlust etc.)
PseudoStatMeleeSpeedMultiplier = 6;
PseudoStatRangedSpeedMultiplier = 7;
PseudoStatCastSpeedMultiplier = 8;

// Final buffed Haste values after combining the above multipliers with
// Haste Rating from gear. Expressed in percentage units (0-100).
PseudoStatMeleeHastePercent = 9;
PseudoStatRangedHastePercent = 10;
PseudoStatSpellHastePercent = 11;

// School-specific fully buffed Hit/Crit stats, also in percentage
// units. These are modeled as proper Stats in the back-end due to stat
// dependencies, but do not need to be stored in any database files.
PseudoStatPhysicalHitPercent = 12;
PseudoStatSpellHitPercent = 13;
PseudoStatPhysicalCritPercent = 14;
PseudoStatSpellCritPercent = 15;
}

message UnitStats {
Expand All @@ -230,9 +285,9 @@ message UnitStats {
}

message ReforgeStat {
int32 id = 1;
repeated Stat fromStat = 2;
repeated Stat toStat = 3;
int32 id = 1;
Stat fromStat = 2;
Stat toStat = 3;
double multiplier = 4;
}

Expand Down
15 changes: 13 additions & 2 deletions proto/ui.proto
Original file line number Diff line number Diff line change
Expand Up @@ -318,11 +318,10 @@ message IndividualSimSettings {
Stat heal_ref_stat = 13;
Stat tank_ref_stat = 14;
UnitStats stat_caps = 15;
repeated StatCapConfig soft_cap_breakpoints = 16;
}

message StatCapConfig {
Stat stat = 1;
UIStat unit_stat = 1;

// Breakpoint values in ascending order
repeated double breakpoints = 2;
Expand All @@ -336,6 +335,18 @@ message StatCapConfig {
repeated double post_cap_EPs = 4;
}

// Represents a single attribute that is either a Stat or a PseudoStat.
// Currently used only within the StatCapConfig UI message for configuring Haste
// caps, and is therefore not versioned, since this message is not imported or
// exported from local storage or links.
message UIStat {
// Uniquely identifies the attribute
oneof unit_stat {
Stat stat = 1;
PseudoStat pseudo_stat = 2;
}
}

enum StatCapType {
TypeUnknown = 0;

Expand Down
8 changes: 4 additions & 4 deletions sim/common/cata/enchant_effects.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func init() {
return character.NewTemporaryStatsAura(
name,
core.ActionID{SpellID: 74221, Tag: tag},
stats.Stats{stats.MeleeHaste: 450, stats.SpellHaste: 450},
stats.Stats{stats.HasteRating: 450},
time.Second*12,
)
}
Expand Down Expand Up @@ -298,7 +298,7 @@ func init() {
statAura := character.NewTemporaryStatsAura(
"Windwalk Proc",
core.ActionID{SpellID: 74243},
stats.Stats{stats.Dodge: 600},
stats.Stats{stats.DodgeRating: 600},
time.Second*10,
)

Expand Down Expand Up @@ -456,15 +456,15 @@ func init() {

// Enchant: 4176, Item: 59595 - R19 Threatfinder
core.NewEnchantEffect(4176, func(agent core.Agent) {
agent.GetCharacter().AddBonusRangedHitRating(88)
agent.GetCharacter().AddBonusRangedHitPercent(88 / core.PhysicalHitRatingPerHitPercent)
})

// Enchant: 4177, Item: 59596 - Safety Catch Removal Kit
core.NewEnchantEffect(4177, func(agent core.Agent) {
character := agent.GetCharacter()
// TODO: This should be ranged-only haste. For now just make it hunter-only.
if character.Class == proto.Class_ClassHunter {
character.AddStats(stats.Stats{stats.MeleeHaste: 88, stats.SpellHaste: 88})
character.AddStat(stats.HasteRating, 88)
}
})

Expand Down
64 changes: 32 additions & 32 deletions sim/common/cata/other_effects.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,8 @@ func init() {
Duration: time.Second * 20,
MaxStacks: 5,
OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks, newStacks int32) {
deltaHaste := float64(321) * float64(newStacks-oldStacks)
character.AddStatsDynamic(sim, stats.Stats{stats.MeleeHaste: deltaHaste, stats.SpellHaste: deltaHaste})
deltaHasteRating := float64(321) * float64(newStacks-oldStacks)
character.AddStatDynamic(sim, stats.HasteRating, deltaHasteRating)
},
})

Expand Down Expand Up @@ -366,8 +366,8 @@ func init() {
Duration: time.Second * 20,
MaxStacks: 5,
OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks, newStacks int32) {
deltaHaste := float64(363) * float64(newStacks-oldStacks)
character.AddStatsDynamic(sim, stats.Stats{stats.MeleeHaste: deltaHaste, stats.SpellHaste: deltaHaste})
deltaHasteRating := float64(363) * float64(newStacks-oldStacks)
character.AddStatDynamic(sim, stats.HasteRating, deltaHasteRating)
},
})

Expand Down Expand Up @@ -549,9 +549,9 @@ func init() {
}))

statBonus := float64(508 * dummyAura.MaxStacks)
buffAuraCrit := character.NewTemporaryStatsAura("Blessing of the Shaper Crit", core.ActionID{SpellID: 96928}, stats.Stats{stats.MeleeCrit: statBonus, stats.SpellCrit: statBonus}, time.Second*15)
buffAuraHaste := character.NewTemporaryStatsAura("Blessing of the Shaper Haste", core.ActionID{SpellID: 96927}, stats.Stats{stats.MeleeHaste: statBonus, stats.SpellHaste: statBonus}, time.Second*15)
buffAuraMastery := character.NewTemporaryStatsAura("Blessing of the Shaper Mastery", core.ActionID{SpellID: 96929}, stats.Stats{stats.Mastery: statBonus}, time.Second*15)
buffAuraCrit := character.NewTemporaryStatsAura("Blessing of the Shaper Crit", core.ActionID{SpellID: 96928}, stats.Stats{stats.CritRating: statBonus}, time.Second*15)
buffAuraHaste := character.NewTemporaryStatsAura("Blessing of the Shaper Haste", core.ActionID{SpellID: 96927}, stats.Stats{stats.HasteRating: statBonus}, time.Second*15)
buffAuraMastery := character.NewTemporaryStatsAura("Blessing of the Shaper Mastery", core.ActionID{SpellID: 96929}, stats.Stats{stats.MasteryRating: statBonus}, time.Second*15)

sharedCD := character.GetOffensiveTrinketCD()
trinketSpell := character.RegisterSpell(core.SpellConfig{
Expand All @@ -571,13 +571,13 @@ func init() {
},

ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) {
statType := character.GetHighestStat([]stats.Stat{stats.MeleeCrit, stats.SpellCrit, stats.MeleeHaste, stats.SpellHaste, stats.Mastery})
statType := character.GetHighestStatType([]stats.Stat{stats.CritRating, stats.HasteRating, stats.MasteryRating})
switch statType {
case stats.MeleeCrit, stats.SpellCrit:
case stats.CritRating:
buffAuraCrit.Activate(sim)
case stats.MeleeHaste, stats.SpellHaste:
case stats.HasteRating:
buffAuraHaste.Activate(sim)
case stats.Mastery:
case stats.MasteryRating:
buffAuraMastery.Activate(sim)
default:
panic("unexpected statType")
Expand Down Expand Up @@ -626,9 +626,9 @@ func init() {
// the trinket should allow to activate at any number of stacks, should we allow this behaviour at all to the users?
// would also mean that we need the temporary aura to be created on the fly after an environment is finalized
statBonus := float64(575 * dummyAura.MaxStacks)
buffAuraCrit := character.NewTemporaryStatsAura("Blessing of the Shaper Crit (Heroic)", core.ActionID{SpellID: 96928}, stats.Stats{stats.MeleeCrit: statBonus, stats.SpellCrit: statBonus}, time.Second*15)
buffAuraHaste := character.NewTemporaryStatsAura("Blessing of the Shaper Haste (Heroic)", core.ActionID{SpellID: 96927}, stats.Stats{stats.MeleeHaste: statBonus, stats.SpellHaste: statBonus}, time.Second*15)
buffAuraMastery := character.NewTemporaryStatsAura("Blessing of the Shaper Mastery (Heroic)", core.ActionID{SpellID: 96929}, stats.Stats{stats.Mastery: statBonus}, time.Second*15)
buffAuraCrit := character.NewTemporaryStatsAura("Blessing of the Shaper Crit (Heroic)", core.ActionID{SpellID: 96928}, stats.Stats{stats.CritRating: statBonus}, time.Second*15)
buffAuraHaste := character.NewTemporaryStatsAura("Blessing of the Shaper Haste (Heroic)", core.ActionID{SpellID: 96927}, stats.Stats{stats.HasteRating: statBonus}, time.Second*15)
buffAuraMastery := character.NewTemporaryStatsAura("Blessing of the Shaper Mastery (Heroic)", core.ActionID{SpellID: 96929}, stats.Stats{stats.MasteryRating: statBonus}, time.Second*15)

sharedCD := character.GetOffensiveTrinketCD()
trinketSpell := character.RegisterSpell(core.SpellConfig{
Expand All @@ -647,13 +647,13 @@ func init() {
},
},
ApplyEffects: func(sim *core.Simulation, target *core.Unit, spell *core.Spell) {
statType := character.GetHighestStat([]stats.Stat{stats.MeleeCrit, stats.SpellCrit, stats.MeleeHaste, stats.SpellHaste, stats.Mastery})
statType := character.GetHighestStatType([]stats.Stat{stats.CritRating, stats.HasteRating, stats.MasteryRating})
switch statType {
case stats.MeleeCrit, stats.SpellCrit:
case stats.CritRating:
buffAuraCrit.Activate(sim)
case stats.MeleeHaste, stats.SpellHaste:
case stats.HasteRating:
buffAuraHaste.Activate(sim)
case stats.Mastery:
case stats.MasteryRating:
buffAuraMastery.Activate(sim)
default:
panic("unexpected statType")
Expand All @@ -679,9 +679,9 @@ func init() {
character := agent.GetCharacter()

bonusStats := 1624.0
procAuraCrit := character.NewTemporaryStatsAura("Matrix Restabilizer Crit Proc", core.ActionID{SpellID: 96978}, stats.Stats{stats.MeleeCrit: bonusStats, stats.SpellCrit: bonusStats}, time.Second*30)
procAuraHaste := character.NewTemporaryStatsAura("Matrix Restabilizer Haste Proc", core.ActionID{SpellID: 96977}, stats.Stats{stats.MeleeHaste: bonusStats, stats.SpellHaste: bonusStats}, time.Second*30)
procAuraMastery := character.NewTemporaryStatsAura("Matrix Restabilizer Mastery Proc", core.ActionID{SpellID: 96979}, stats.Stats{stats.Mastery: bonusStats}, time.Second*30)
procAuraCrit := character.NewTemporaryStatsAura("Matrix Restabilizer Crit Proc", core.ActionID{SpellID: 96978}, stats.Stats{stats.CritRating: bonusStats}, time.Second*30)
procAuraHaste := character.NewTemporaryStatsAura("Matrix Restabilizer Haste Proc", core.ActionID{SpellID: 96977}, stats.Stats{stats.HasteRating: bonusStats}, time.Second*30)
procAuraMastery := character.NewTemporaryStatsAura("Matrix Restabilizer Mastery Proc", core.ActionID{SpellID: 96979}, stats.Stats{stats.MasteryRating: bonusStats}, time.Second*30)

icd := core.Cooldown{
Timer: character.NewTimer(),
Expand All @@ -701,13 +701,13 @@ func init() {
Harmful: true,
Handler: func(sim *core.Simulation, _ *core.Spell, _ *core.SpellResult) {
if icd.IsReady(sim) {
statType := character.GetHighestStat([]stats.Stat{stats.MeleeCrit, stats.SpellCrit, stats.MeleeHaste, stats.SpellHaste, stats.Mastery})
statType := character.GetHighestStatType([]stats.Stat{stats.CritRating, stats.HasteRating, stats.MasteryRating})
switch statType {
case stats.MeleeCrit, stats.SpellCrit:
case stats.CritRating:
procAuraCrit.Activate(sim)
case stats.MeleeHaste, stats.SpellHaste:
case stats.HasteRating:
procAuraHaste.Activate(sim)
case stats.Mastery:
case stats.MasteryRating:
procAuraMastery.Activate(sim)
default:
panic("unexpected statType")
Expand All @@ -722,9 +722,9 @@ func init() {
character := agent.GetCharacter()

bonusStats := 1834.0
procAuraCrit := character.NewTemporaryStatsAura("Matrix Restabilizer Crit Proc (Heroic)", core.ActionID{SpellID: 97140}, stats.Stats{stats.MeleeCrit: bonusStats, stats.SpellCrit: bonusStats}, time.Second*30)
procAuraHaste := character.NewTemporaryStatsAura("Matrix Restabilizer Haste Proc (Heroic)", core.ActionID{SpellID: 97139}, stats.Stats{stats.MeleeHaste: bonusStats, stats.SpellHaste: bonusStats}, time.Second*30)
procAuraMastery := character.NewTemporaryStatsAura("Matrix Restabilizer Mastery Proc (Heroic)", core.ActionID{SpellID: 97141}, stats.Stats{stats.Mastery: bonusStats}, time.Second*30)
procAuraCrit := character.NewTemporaryStatsAura("Matrix Restabilizer Crit Proc (Heroic)", core.ActionID{SpellID: 97140}, stats.Stats{stats.CritRating: bonusStats}, time.Second*30)
procAuraHaste := character.NewTemporaryStatsAura("Matrix Restabilizer Haste Proc (Heroic)", core.ActionID{SpellID: 97139}, stats.Stats{stats.HasteRating: bonusStats}, time.Second*30)
procAuraMastery := character.NewTemporaryStatsAura("Matrix Restabilizer Mastery Proc (Heroic)", core.ActionID{SpellID: 97141}, stats.Stats{stats.MasteryRating: bonusStats}, time.Second*30)

icd := core.Cooldown{
Timer: character.NewTimer(),
Expand All @@ -744,13 +744,13 @@ func init() {
Harmful: true,
Handler: func(sim *core.Simulation, _ *core.Spell, _ *core.SpellResult) {
if icd.IsReady(sim) {
statType := character.GetHighestStat([]stats.Stat{stats.MeleeCrit, stats.SpellCrit, stats.MeleeHaste, stats.SpellHaste, stats.Mastery})
statType := character.GetHighestStatType([]stats.Stat{stats.CritRating, stats.HasteRating, stats.MasteryRating})
switch statType {
case stats.MeleeCrit, stats.SpellCrit:
case stats.CritRating:
procAuraCrit.Activate(sim)
case stats.MeleeHaste, stats.SpellHaste:
case stats.HasteRating:
procAuraHaste.Activate(sim)
case stats.Mastery:
case stats.MasteryRating:
procAuraMastery.Activate(sim)
default:
panic("unexpected statType")
Expand Down
Loading

0 comments on commit fadaaa8

Please sign in to comment.