-
Notifications
You must be signed in to change notification settings - Fork 36
/
presim.go
122 lines (103 loc) · 3.69 KB
/
presim.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package core
import (
"time"
"github.com/wowsims/cata/sim/core/proto"
googleProto "google.golang.org/protobuf/proto"
)
// A presim is a full simulation run with multiple iterations, as a preparation
// step for testing out settings before starting the recorded iterations.
//
// To use this, just implement this interface on your Agent.
//
// If you don't know what this is, you probably don't need it.
type Presimmer interface {
GetPresimOptions(*proto.Player) *PresimOptions
}
// Controls the presim behavior for 1 Agent.
type PresimOptions struct {
// Called once before each presim round.
//
// Modify the player parameter to use whatever player options are desired
// for the presim.
SetPresimPlayerOptions func(player *proto.Player)
// Called once after each presim round to provide the results.
//
// Should return true if this Agent is done running presims, and false otherwise.
OnPresimResult func(presimResult *proto.UnitMetrics, iterations int32, duration time.Duration) bool
}
func (sim *Simulation) runPresims(request *proto.RaidSimRequest) *proto.RaidSimResult {
const numPresimIterations = 100
// Run presims if requested.
raidPresimOptions := make([]*PresimOptions, 25)
remainingAgents := 0
for _, party := range sim.Raid.Parties {
for _, player := range party.Players {
presimmer, ok := player.(Presimmer)
if !ok {
continue
}
partyConfig := request.Raid.Parties[player.GetCharacter().Party.Index]
if player.GetCharacter().PartyIndex >= len(partyConfig.Players) {
// This happens for target dummies.
continue
}
playerConfig := partyConfig.Players[player.GetCharacter().PartyIndex]
presimOptions := presimmer.GetPresimOptions(playerConfig)
if presimOptions == nil {
continue
}
raidPresimOptions[player.GetCharacter().Index] = presimOptions
remainingAgents++
}
}
// Base presim request.
// Define this outside the loop so that, as Agents iteratively update their
// settings, we keep the most recent settings even after that Agent is
// done with presims.
presimRequest := googleProto.Clone(request).(*proto.RaidSimRequest)
presimRequest.SimOptions.RandomSeed = 1
presimRequest.SimOptions.Debug = false
presimRequest.SimOptions.DebugFirstIteration = false
presimRequest.SimOptions.Iterations = numPresimIterations
duration := DurationFromSeconds(presimRequest.Encounter.Duration)
var lastResult *proto.RaidSimResult
doOne := sim.Encounter.EndFightAtHealth > 0
for doOne || remainingAgents > 0 {
// ** Run a presim round. **
// Let each Agent modify their own settings.
for partyIdx, party := range sim.Raid.Parties {
partyConfig := presimRequest.Raid.Parties[partyIdx]
for _, player := range party.Players {
playerConfig := partyConfig.Players[player.GetCharacter().PartyIndex]
presimOptions := raidPresimOptions[player.GetCharacter().Index]
if presimOptions == nil {
continue
}
presimOptions.SetPresimPlayerOptions(playerConfig)
}
}
// Run the presim.
presimResult := runSim(presimRequest, nil, true, nil)
lastResult = presimResult
if presimResult.ErrorResult != "" {
break
}
// Provide each Agent with their own results.
for partyIdx, party := range sim.Raid.Parties {
partyMetrics := presimResult.RaidMetrics.Parties[partyIdx]
for _, player := range party.Players {
playerMetrics := partyMetrics.Players[player.GetCharacter().PartyIndex]
presimOptions := raidPresimOptions[player.GetCharacter().Index]
if presimOptions != nil {
done := presimOptions.OnPresimResult(playerMetrics, numPresimIterations, duration)
if done {
raidPresimOptions[player.GetCharacter().Index] = nil
remainingAgents--
}
}
}
}
doOne = false
}
return lastResult
}