Skip to content

Commit 3036f34

Browse files
committed
[feature] Implement ball placement correctly for both divisions
* Replace primary/secondary game events by a list * send timestamp as number in ns to avoid wrong sorting in UI
1 parent 92a4372 commit 3036f34

17 files changed

+254
-251
lines changed

internal/app/controller/engine.go

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -52,23 +52,13 @@ func (e *Engine) SendCommand(command RefCommand, forTeam Team) {
5252
e.State.CommandFor = forTeam
5353
e.LogCommand()
5454

55-
if command.RunningState() {
56-
if e.State.GameEvent.Type != GameEventNone {
57-
e.State.GameEvent = GameEvent{Type: GameEventNone}
58-
}
59-
if e.State.GameEventSecondary.Type != GameEventNone {
60-
e.State.GameEventSecondary = GameEvent{Type: GameEventNone}
61-
}
55+
if command.RunningState() && len(e.State.GameEvents) > 0 {
56+
e.State.GameEvents = []*GameEvent{}
6257
}
6358
}
6459

65-
func (e *Engine) SendGameEventPrimary(gameEvent GameEvent) {
66-
e.State.GameEvent = gameEvent
67-
e.LogGameEvent(gameEvent)
68-
}
69-
70-
func (e *Engine) SendGameEventSecondary(gameEvent GameEvent) {
71-
e.State.GameEventSecondary = gameEvent
60+
func (e *Engine) AddGameEvent(gameEvent GameEvent) {
61+
e.State.GameEvents = append(e.State.GameEvents, &gameEvent)
7262
e.LogGameEvent(gameEvent)
7363
}
7464

@@ -83,7 +73,31 @@ func (e *Engine) UndoLastAction() {
8373
}
8474

8575
func (e *Engine) Continue() error {
86-
switch e.State.GameEvent.Type {
76+
if len(e.State.GameEvents) == 0 {
77+
return errors.New("No game events available to determine next action")
78+
}
79+
primaryEvent := e.State.GameEvents[0]
80+
teamInFavor := primaryEvent.ByTeam().Opposite()
81+
82+
if e.State.Division == DivA {
83+
for _, event := range e.State.GameEvents {
84+
if event.Type == GameEventPlacementFailedByTeamInFavor {
85+
switch primaryEvent.Type {
86+
case
87+
GameEventGoal,
88+
GameEventDefenderInDefenseArea,
89+
GameEventMultipleYellowCards:
90+
default:
91+
// the placement failed by team in favor
92+
// the game is continued by the other team
93+
e.SendCommand(CommandIndirect, teamInFavor.Opposite())
94+
}
95+
return nil
96+
}
97+
}
98+
}
99+
100+
switch primaryEvent.Type {
87101
case
88102
GameEventBallLeftFieldTouchLine,
89103
GameEventIcing,
@@ -96,7 +110,7 @@ func (e *Engine) Continue() error {
96110
GameEventDefenderInDefenseAreaPartially,
97111
GameEventKickTimeout,
98112
GameEventKeeperHeldBall:
99-
e.SendCommand(CommandIndirect, e.State.GameEvent.ByTeam().Opposite())
113+
e.SendCommand(CommandIndirect, teamInFavor)
100114
case
101115
GameEventBallLeftFieldGoalLine,
102116
GameEventIndirectGoal,
@@ -105,30 +119,25 @@ func (e *Engine) Continue() error {
105119
GameEventBotCrashUnique,
106120
GameEventBotPushedBot,
107121
GameEventBotHeldBallDeliberately:
108-
e.SendCommand(CommandDirect, e.State.GameEvent.ByTeam().Opposite())
122+
e.SendCommand(CommandDirect, teamInFavor)
109123
case
110124
GameEventGoal:
111-
e.SendCommand(CommandKickoff, e.State.GameEvent.ByTeam().Opposite())
125+
e.SendCommand(CommandKickoff, teamInFavor)
112126
case
113127
GameEventBotCrashDrawn,
114128
GameEventNoProgressInGame:
115129
e.SendCommand(CommandForceStart, TeamUnknown)
116130
case
117131
GameEventDefenderInDefenseArea,
118132
GameEventMultipleYellowCards:
119-
e.SendCommand(CommandPenalty, e.State.GameEvent.ByTeam().Opposite())
133+
e.SendCommand(CommandPenalty, teamInFavor)
120134
case
121135
GameEventBotInterferedPlacement,
122136
GameEventDefenderTooCloseToKickPoint:
123137
if cmd, err := e.LastGameStartCommand(); err != nil {
124138
log.Print("Warn: ", err)
125139
} else {
126-
e.SendCommand(cmd, e.State.GameEvent.ByTeam().Opposite())
127-
}
128-
case
129-
GameEventPlacementFailedByTeamInFavor:
130-
if e.State.PlacementPos != nil {
131-
e.SendCommand(CommandBallPlacement, e.State.GameEvent.ByTeam().Opposite())
140+
e.SendCommand(cmd, teamInFavor)
132141
}
133142
case
134143
GameEventBotTooFastInStop,
@@ -137,10 +146,11 @@ func (e *Engine) Continue() error {
137146
GameEventBotCrashUniqueContinue,
138147
GameEventBotPushedBotContinue,
139148
GameEventMultipleFouls,
149+
GameEventPlacementFailedByTeamInFavor,
140150
GameEventPlacementFailedByOpponent:
141151
// no command
142152
default:
143-
return errors.Errorf("Unknown game event: %v", e.State.GameEvent)
153+
return errors.Errorf("Unknown game event: %v", e.State.GameEvents)
144154
}
145155
return nil
146156
}
@@ -177,7 +187,7 @@ func (e *Engine) appendHistory() {
177187

178188
func (e *Engine) LogGameEvent(event GameEvent) {
179189
gameEvent := RefereeEvent{
180-
Timestamp: e.TimeProvider(),
190+
Timestamp: e.TimeProvider().UnixNano(),
181191
StageTime: e.State.StageTimeElapsed,
182192
Type: RefereeEventGameEvent,
183193
Name: string(event.Type),
@@ -189,7 +199,7 @@ func (e *Engine) LogGameEvent(event GameEvent) {
189199

190200
func (e *Engine) LogCommand() {
191201
refereeEvent := RefereeEvent{
192-
Timestamp: e.TimeProvider(),
202+
Timestamp: e.TimeProvider().UnixNano(),
193203
StageTime: e.State.StageTimeElapsed,
194204
Type: RefereeEventCommand,
195205
Name: string(e.State.Command),
@@ -200,7 +210,7 @@ func (e *Engine) LogCommand() {
200210

201211
func (e *Engine) LogCard(card *EventCard) {
202212
refereeEvent := RefereeEvent{
203-
Timestamp: e.TimeProvider(),
213+
Timestamp: e.TimeProvider().UnixNano(),
204214
StageTime: e.State.StageTimeElapsed,
205215
Type: RefereeEventCard,
206216
Name: fmt.Sprintf("%v %v card", card.Operation, card.Type),
@@ -211,7 +221,7 @@ func (e *Engine) LogCard(card *EventCard) {
211221

212222
func (e *Engine) LogTime(description string, forTeam Team) {
213223
refereeEvent := RefereeEvent{
214-
Timestamp: e.TimeProvider(),
224+
Timestamp: e.TimeProvider().UnixNano(),
215225
StageTime: e.State.StageTimeElapsed,
216226
Type: RefereeEventTime,
217227
Name: description,
@@ -222,7 +232,7 @@ func (e *Engine) LogTime(description string, forTeam Team) {
222232

223233
func (e *Engine) LogStage(stage Stage) {
224234
refereeEvent := RefereeEvent{
225-
Timestamp: e.TimeProvider(),
235+
Timestamp: e.TimeProvider().UnixNano(),
226236
StageTime: e.State.StageTimeElapsed,
227237
Type: RefereeEventStage,
228238
Name: string(stage),
@@ -532,15 +542,11 @@ func (e *Engine) processGameEvent(event *GameEvent) error {
532542
addCard(&EventCard{Type: CardTypeRed, ForTeam: team, Operation: CardOperationAdd}, e.State.TeamState[team], 0)
533543
}
534544

535-
if event.IsSecondary() {
536-
e.SendGameEventSecondary(*event)
537-
} else {
538-
e.SendGameEventPrimary(*event)
539-
e.State.PlacementPos = e.BallPlacementPos()
540-
}
545+
e.AddGameEvent(*event)
546+
e.State.PlacementPos = e.BallPlacementPos()
541547

542548
if e.State.GameState() != GameStateHalted && !event.IsContinued() {
543-
teamInFavor := e.State.GameEvent.ByTeam().Opposite()
549+
teamInFavor := event.ByTeam().Opposite()
544550
if e.State.PlacementPos == nil {
545551
e.SendCommand(CommandStop, "")
546552
} else if e.State.TeamState[teamInFavor].CanPlaceBall {

internal/app/controller/gameEvent.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ func (e GameEvent) IsSecondary() bool {
113113
GameEventMultipleFouls,
114114
GameEventBotCrashUniqueContinue,
115115
GameEventBotPushedBotContinue,
116+
GameEventPlacementFailedByTeamInFavor,
116117
GameEventPlacementFailedByOpponent:
117118
return true
118119
}

internal/app/controller/placementPos.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ import (
77

88
// BallPlacementPos determines the ball placement position based on the game event
99
func (e *Engine) BallPlacementPos() *Location {
10-
event := e.State.GameEvent
11-
12-
if event.Type == GameEventNone || event.IsSecondary() || event.IsContinued() {
10+
if len(e.State.GameEvents) == 0 {
11+
return nil
12+
}
13+
event := e.State.GameEvents[0]
14+
if event.IsSecondary() || event.IsContinued() {
1315
return nil
1416
}
1517

internal/app/controller/publisher.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,16 +104,15 @@ func updateMessage(r *refproto.Referee, state *State) (republish bool) {
104104
} else if state.TeamState[TeamBlue].Goals > int(*r.Blue.Score) {
105105
updateCommand(r, refproto.Referee_GOAL_BLUE)
106106
republish = true
107-
} else if state.Command == CommandBallPlacement && *r.Command != refproto.Referee_STOP {
107+
} else if state.Command == CommandBallPlacement && *r.Command != refproto.Referee_STOP && *r.Command != refproto.Referee_BALL_PLACEMENT_BLUE && *r.Command != refproto.Referee_BALL_PLACEMENT_YELLOW {
108108
// send a STOP before the ball placement command to be compatible with earlier behavior
109109
updateCommand(r, refproto.Referee_STOP)
110110
republish = true
111111
} else if *r.Command != newCommand {
112112
updateCommand(r, newCommand)
113113
}
114114

115-
r.CurrentGameEvent = state.GameEvent.ToProto()
116-
r.CurrentGameEventSecondary = state.GameEventSecondary.ToProto()
115+
r.GameEvents = mapGameEvents(state.GameEvents)
117116
r.DesignatedPosition = mapLocation(state.PlacementPos)
118117

119118
*r.PacketTimestamp = uint64(time.Now().UnixNano() / 1000)
@@ -124,6 +123,13 @@ func updateMessage(r *refproto.Referee, state *State) (republish bool) {
124123
updateTeam(r.Blue, state.TeamState[TeamBlue])
125124
return
126125
}
126+
func mapGameEvents(events []*GameEvent) []*refproto.GameEvent {
127+
mappedEvents := make([]*refproto.GameEvent, len(events))
128+
for i, e := range events {
129+
mappedEvents[i] = e.ToProto()
130+
}
131+
return mappedEvents
132+
}
127133

128134
func updateCommand(r *refproto.Referee, newCommand refproto.Referee_Command) {
129135
*r.Command = newCommand

internal/app/controller/refereeEvents.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const (
1515
)
1616

1717
type RefereeEvent struct {
18-
Timestamp time.Time `json:"timestamp"`
18+
Timestamp int64 `json:"timestamp"`
1919
StageTime time.Duration `json:"stageTime"`
2020
Type RefereeEventType `json:"type"`
2121
Name string `json:"name"`

internal/app/controller/state.go

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -231,27 +231,25 @@ type TeamInfo struct {
231231

232232
// State of the game
233233
type State struct {
234-
Stage Stage `json:"stage"`
235-
Command RefCommand `json:"command"`
236-
CommandFor Team `json:"commandForTeam"`
237-
GameEvent GameEvent `json:"gameEvent"`
238-
GameEventSecondary GameEvent `json:"gameEventSecondary"`
239-
StageTimeElapsed time.Duration `json:"stageTimeElapsed"`
240-
StageTimeLeft time.Duration `json:"stageTimeLeft"`
241-
MatchTimeStart time.Time `json:"matchTimeStart"`
242-
MatchDuration time.Duration `json:"matchDuration"`
243-
TeamState map[Team]*TeamInfo `json:"teamState"`
244-
Division Division `json:"division"`
245-
PlacementPos *Location `json:"placementPos"`
234+
Stage Stage `json:"stage"`
235+
Command RefCommand `json:"command"`
236+
CommandFor Team `json:"commandForTeam"`
237+
GameEvents []*GameEvent `json:"gameEvents"`
238+
StageTimeElapsed time.Duration `json:"stageTimeElapsed"`
239+
StageTimeLeft time.Duration `json:"stageTimeLeft"`
240+
MatchTimeStart time.Time `json:"matchTimeStart"`
241+
MatchDuration time.Duration `json:"matchDuration"`
242+
TeamState map[Team]*TeamInfo `json:"teamState"`
243+
Division Division `json:"division"`
244+
PlacementPos *Location `json:"placementPos"`
246245
}
247246

248247
// NewState creates a new state, initialized for the start of a new game
249248
func NewState() (s *State) {
250249
s = new(State)
251250
s.Stage = StagePreGame
252251
s.Command = CommandHalt
253-
s.GameEvent.Type = GameEventNone
254-
s.GameEventSecondary.Type = GameEventNone
252+
s.GameEvents = []*GameEvent{}
255253

256254
s.StageTimeLeft = 0
257255
s.StageTimeElapsed = 0
@@ -302,6 +300,7 @@ func newTeamInfo() (t TeamInfo) {
302300
t.OnPositiveHalf = true
303301
t.FoulCounter = 0
304302
t.BallPlacementFailures = 0
303+
t.CanPlaceBall = true
305304
return
306305
}
307306

pkg/refproto/ssl_game_controller_auto_ref.pb.go

Lines changed: 12 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)