Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions sim/core/spell.go
Original file line number Diff line number Diff line change
Expand Up @@ -743,18 +743,48 @@ func (spell *Spell) finalizeExpectedDamage(result *SpellResult) {
result.inUse = false
}
func (spell *Spell) ExpectedInitialDamage(sim *Simulation, target *Unit) float64 {
cacheIsValid, damageCache := GetCachedExpectedInitialDamage(sim, spell, target)

if cacheIsValid {
return damageCache.value
}

result := spell.expectedInitialDamageInternal(sim, target, spell, false)
spell.finalizeExpectedDamage(result)

damageCache.timestamp = sim.CurrentTime
damageCache.value = result.Damage

return result.Damage
}
func (spell *Spell) ExpectedTickDamage(sim *Simulation, target *Unit) float64 {
cacheIsValid, damageCache := GetCachedExpectedTickDamage(sim, spell, target, false)

if cacheIsValid {
return damageCache.value
}

result := spell.expectedTickDamageInternal(sim, target, spell, false)
spell.finalizeExpectedDamage(result)

damageCache.timestamp = sim.CurrentTime
damageCache.value = result.Damage

return result.Damage
}
func (spell *Spell) ExpectedTickDamageFromCurrentSnapshot(sim *Simulation, target *Unit) float64 {
cacheIsValid, damageCache := GetCachedExpectedTickDamage(sim, spell, target, true)

if cacheIsValid {
return damageCache.value
}

result := spell.expectedTickDamageInternal(sim, target, spell, true)
spell.finalizeExpectedDamage(result)

damageCache.timestamp = sim.CurrentTime
damageCache.value = result.Damage

return result.Damage
}

Expand Down
38 changes: 38 additions & 0 deletions sim/core/target.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,10 @@ func (target *Target) GetMetricsProto() *proto.UnitMetrics {

type DynamicDamageDoneByCaster func(sim *Simulation, spell *Spell, attackTable *AttackTable) float64
type DynamicThreatDoneByCaster DynamicDamageDoneByCaster
type ExpectedDamageCalculatorCache struct {
timestamp time.Duration
value float64
}

// Holds cached values for outcome/damage calculations, for a specific attacker+defender pair.
// These are updated dynamically when attacker or defender stats change.
Expand Down Expand Up @@ -358,6 +362,11 @@ type AttackTable struct {
DamageDoneByCasterExtraMultiplier []DynamicDamageDoneByCaster

ThreatDoneByCasterExtraMultiplier []DynamicThreatDoneByCaster

// Store Expected Initial/DoT Tick values to speed up DoT damage calculations
expectedInitialDamageCache map[*Spell]*ExpectedDamageCalculatorCache
expectedTickDamageCache map[*Spell]*ExpectedDamageCalculatorCache
expectedTickSnapshotDamageCache map[*Spell]*ExpectedDamageCalculatorCache
}

func NewAttackTable(attacker *Unit, defender *Unit) *AttackTable {
Expand All @@ -369,6 +378,10 @@ func NewAttackTable(attacker *Unit, defender *Unit) *AttackTable {
DamageTakenMultiplier: 1,
RangedDamageTakenMultiplier: 1,
HealingDealtMultiplier: 1,

expectedInitialDamageCache: make(map[*Spell]*ExpectedDamageCalculatorCache),
expectedTickDamageCache: make(map[*Spell]*ExpectedDamageCalculatorCache),
expectedTickSnapshotDamageCache: make(map[*Spell]*ExpectedDamageCalculatorCache),
}

if defender.Type == EnemyUnit {
Expand Down Expand Up @@ -414,3 +427,28 @@ func EnableThreatDoneByCaster(index int, maxIndex int, attackTable *AttackTable,
func DisableThreatDoneByCaster(index int, attackTable *AttackTable) {
attackTable.ThreatDoneByCasterExtraMultiplier[index] = nil
}

func GetCachedExpectedInitialDamage(sim *Simulation, spell *Spell, target *Unit) (bool, *ExpectedDamageCalculatorCache) {
return getCachedExpectedDamageInternal(sim, spell, spell.Unit.AttackTables[target.Index].expectedInitialDamageCache)
}

func GetCachedExpectedTickDamage(sim *Simulation, spell *Spell, target *Unit, useSnapshot bool) (bool, *ExpectedDamageCalculatorCache) {
if useSnapshot {
return getCachedExpectedDamageInternal(sim, spell, spell.Unit.AttackTables[target.Index].expectedTickSnapshotDamageCache)
}

return getCachedExpectedDamageInternal(sim, spell, spell.Unit.AttackTables[target.Index].expectedTickDamageCache)
}

func getCachedExpectedDamageInternal(sim *Simulation, spell *Spell, store map[*Spell]*ExpectedDamageCalculatorCache) (bool, *ExpectedDamageCalculatorCache) {
if store[spell] == nil {
emptyCache := ExpectedDamageCalculatorCache{}
store[spell] = &emptyCache
}

if (store[spell].timestamp - sim.CurrentTime).Abs() <= spell.Unit.ReactionTime {
return true, store[spell]
}

return false, store[spell]
}
6 changes: 6 additions & 0 deletions sim/core/unit.go
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,12 @@ func (unit *Unit) reset(sim *Simulation, _ Agent) {
spell.reset(sim)
}

for _, attackTable := range unit.AttackTables {
attackTable.expectedInitialDamageCache = make(map[*Spell]*ExpectedDamageCalculatorCache)
attackTable.expectedTickDamageCache = make(map[*Spell]*ExpectedDamageCalculatorCache)
attackTable.expectedTickSnapshotDamageCache = make(map[*Spell]*ExpectedDamageCalculatorCache)
}

unit.manaBar.reset()
unit.focusBar.reset(sim)
unit.healthBar.reset(sim)
Expand Down
46 changes: 23 additions & 23 deletions sim/death_knight/blood/TestBlood.results
Original file line number Diff line number Diff line change
Expand Up @@ -861,10 +861,10 @@ dps_results: {
dps_results: {
key: "TestBlood-AllItems-EssenceofTerror-87175"
value: {
dps: 221342.77751
tps: 1.1115278575e+06
dps: 220959.31479
tps: 1.10884900975e+06
dtps: 65497.31347
hps: 75148.77989
hps: 75244.01626
}
}
dps_results: {
Expand Down Expand Up @@ -1968,10 +1968,10 @@ dps_results: {
dps_results: {
key: "TestBlood-AllItems-PhaseFingers-4697"
value: {
dps: 216530.41154
tps: 1.09592384667e+06
dps: 216448.52098
tps: 1.09472396979e+06
dtps: 65340.55983
hps: 77887.83765
hps: 77820.25412
}
}
dps_results: {
Expand All @@ -1995,10 +1995,10 @@ dps_results: {
dps_results: {
key: "TestBlood-AllItems-PlateoftheLostCatacomb"
value: {
dps: 206194.37904
tps: 1.04391607776e+06
dps: 206289.32716
tps: 1.0444848343e+06
dtps: 69733.3762
hps: 83403.5959
hps: 83317.35933
}
}
dps_results: {
Expand Down Expand Up @@ -2175,10 +2175,10 @@ dps_results: {
dps_results: {
key: "TestBlood-AllItems-PurifiedBindingsofImmerseus-105422"
value: {
dps: 221038.23925
tps: 1.12998075584e+06
dps: 221114.6103
tps: 1.13011827705e+06
dtps: 65350.88916
hps: 75774.17892
hps: 75810.63691
}
}
dps_results: {
Expand Down Expand Up @@ -2355,19 +2355,19 @@ dps_results: {
dps_results: {
key: "TestBlood-AllItems-RuneofSwordbreaking-3594"
value: {
dps: 209839.64377
tps: 1.06720357127e+06
dps: 209864.15746
tps: 1.0683475303e+06
dtps: 64984.70313
hps: 72815.24325
hps: 72868.7662
}
}
dps_results: {
key: "TestBlood-AllItems-RuneofSwordshattering-3365"
value: {
dps: 211785.36739
tps: 1.07785498228e+06
dps: 211809.88108
tps: 1.07899894131e+06
dtps: 63437.01107
hps: 72839.21702
hps: 72892.73996
}
}
dps_results: {
Expand Down Expand Up @@ -2751,10 +2751,10 @@ dps_results: {
dps_results: {
key: "TestBlood-AllItems-SynapseSprings(MarkII)-4898"
value: {
dps: 218352.09357
tps: 1.10863598216e+06
dps: 218465.80933
tps: 1.10947025407e+06
dtps: 64965.54903
hps: 78006.7543
hps: 77980.68281
}
}
dps_results: {
Expand Down Expand Up @@ -3210,8 +3210,8 @@ dps_results: {
dps_results: {
key: "TestBlood-Average-Default"
value: {
dps: 204690.13412
tps: 1.05432628739e+06
dps: 204690.33734
tps: 1.05432770987e+06
dtps: 61071.88955
hps: 75863.07654
}
Expand Down
Loading