Skip to content

Commit ff66372

Browse files
committed
[feature] Implement more referee events
1 parent bf47770 commit ff66372

File tree

6 files changed

+117
-46
lines changed

6 files changed

+117
-46
lines changed

internal/app/controller/apiServer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func (a *ApiServer) PublishState(state State) {
7979
a.PublishWrapper(wrapper)
8080
}
8181

82-
func (a *ApiServer) PublishGameEvents(events []RefereeEvent) {
82+
func (a *ApiServer) PublishRefereeEvents(events []RefereeEvent) {
8383
a.latestRefereeEvents = events
8484
wrapper := MessageWrapper{RefereeEvents: &events}
8585
a.PublishWrapper(wrapper)

internal/app/controller/controller.go

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ const configFileName = "config/ssl-game-controller.yaml"
99

1010
// GameController controls a game
1111
type GameController struct {
12-
Config Config
13-
Publisher Publisher
14-
ApiServer ApiServer
15-
Engine Engine
16-
timer timer.Timer
17-
historyPreserver HistoryPreserver
12+
Config Config
13+
Publisher Publisher
14+
ApiServer ApiServer
15+
Engine Engine
16+
timer timer.Timer
17+
historyPreserver HistoryPreserver
18+
numRefereeEventsLastPublish int
1819
}
1920

2021
// NewGameController creates a new RefBox
@@ -33,44 +34,43 @@ func NewGameController() (r *GameController) {
3334
}
3435

3536
// Run the GameController by starting an endless loop in the background
36-
func (r *GameController) Run() (err error) {
37+
func (c *GameController) Run() (err error) {
3738

38-
if err := r.historyPreserver.Open(); err != nil {
39+
if err := c.historyPreserver.Open(); err != nil {
3940
log.Print("Could not open history", err)
4041
} else {
41-
history, err := r.historyPreserver.Load()
42+
history, err := c.historyPreserver.Load()
4243
if err != nil {
4344
log.Print("Could not load history", err)
4445
} else if len(*history) > 0 {
45-
r.Engine.History = *history
46-
*r.Engine.State = r.Engine.History[len(r.Engine.History)-1].State
47-
r.Engine.RefereeEvents = r.Engine.History[len(r.Engine.History)-1].RefereeEvents
46+
c.Engine.History = *history
47+
*c.Engine.State = c.Engine.History[len(c.Engine.History)-1].State
48+
c.Engine.RefereeEvents = c.Engine.History[len(c.Engine.History)-1].RefereeEvents
4849
}
4950
}
5051

51-
r.ApiServer.PublishState(*r.Engine.State)
52-
r.ApiServer.PublishGameEvents(r.Engine.RefereeEvents)
52+
c.ApiServer.PublishState(*c.Engine.State)
53+
c.ApiServer.PublishRefereeEvents(c.Engine.RefereeEvents)
5354

5455
go func() {
55-
defer r.historyPreserver.Close()
56+
defer c.historyPreserver.Close()
5657
for {
57-
r.timer.WaitTillNextFullSecond()
58-
r.Engine.Tick(r.timer.Delta())
59-
r.historyPreserver.Save(r.Engine.History)
60-
r.publish()
58+
c.timer.WaitTillNextFullSecond()
59+
c.Engine.Tick(c.timer.Delta())
60+
c.historyPreserver.Save(c.Engine.History)
61+
c.publish()
6162
}
6263
}()
6364
return nil
6465
}
6566

66-
func (r *GameController) OnNewEvent(event Event) {
67-
err := r.Engine.Process(event)
67+
func (c *GameController) OnNewEvent(event Event) {
68+
err := c.Engine.Process(event)
6869
if err != nil {
6970
log.Println("Could not process event:", event, err)
7071
} else {
71-
r.historyPreserver.Save(r.Engine.History)
72-
r.publish()
73-
r.publishGameEvents()
72+
c.historyPreserver.Save(c.Engine.History)
73+
c.publish()
7474
}
7575
}
7676

@@ -91,12 +91,12 @@ func loadConfig() Config {
9191
}
9292

9393
// publish publishes the state to the UI and the teams
94-
func (r *GameController) publish() {
95-
r.ApiServer.PublishState(*r.Engine.State)
96-
r.Publisher.Publish(r.Engine.State)
97-
}
94+
func (c *GameController) publish() {
95+
if len(c.Engine.RefereeEvents) != c.numRefereeEventsLastPublish {
96+
c.ApiServer.PublishRefereeEvents(c.Engine.RefereeEvents)
97+
c.numRefereeEventsLastPublish = len(c.Engine.RefereeEvents)
98+
}
9899

99-
// publishGameEvents publishes the current list of game events
100-
func (r *GameController) publishGameEvents() {
101-
r.ApiServer.PublishGameEvents(r.Engine.RefereeEvents)
100+
c.ApiServer.PublishState(*c.Engine.State)
101+
c.Publisher.Publish(c.Engine.State)
102102
}

internal/app/controller/engine.go

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package controller
22

33
import (
4+
"fmt"
45
"github.com/pkg/errors"
56
"log"
67
"strconv"
@@ -122,6 +123,38 @@ func (e *Engine) LogCommand() {
122123
e.RefereeEvents = append(e.RefereeEvents, refereeEvent)
123124
}
124125

126+
func (e *Engine) LogCard(card *EventCard) {
127+
refereeEvent := RefereeEvent{
128+
Timestamp: e.TimeProvider(),
129+
StageTime: e.State.StageTimeElapsed,
130+
Type: RefereeEventCard,
131+
Name: fmt.Sprintf("%v %v card", card.Operation, card.Type),
132+
Team: card.ForTeam,
133+
}
134+
e.RefereeEvents = append(e.RefereeEvents, refereeEvent)
135+
}
136+
137+
func (e *Engine) LogTime(description string, forTeam Team) {
138+
refereeEvent := RefereeEvent{
139+
Timestamp: e.TimeProvider(),
140+
StageTime: e.State.StageTimeElapsed,
141+
Type: RefereeEventTime,
142+
Name: description,
143+
Team: forTeam,
144+
}
145+
e.RefereeEvents = append(e.RefereeEvents, refereeEvent)
146+
}
147+
148+
func (e *Engine) LogStage(stage Stage) {
149+
refereeEvent := RefereeEvent{
150+
Timestamp: e.TimeProvider(),
151+
StageTime: e.State.StageTimeElapsed,
152+
Type: RefereeEventStage,
153+
Name: string(stage),
154+
}
155+
e.RefereeEvents = append(e.RefereeEvents, refereeEvent)
156+
}
157+
125158
func (e *Engine) loadStages() {
126159
e.StageTimes = map[Stage]time.Duration{}
127160
for _, stage := range Stages {
@@ -142,14 +175,23 @@ func (e *Engine) updateTimes(delta time.Duration) {
142175
e.State.StageTimeElapsed += delta
143176
e.State.StageTimeLeft -= delta
144177

145-
for _, teamState := range e.State.TeamState {
178+
if e.State.StageTimeLeft+delta > 0 && e.State.StageTimeLeft <= 0 {
179+
e.LogTime("Stage time elapsed", "")
180+
}
181+
182+
for team, teamState := range e.State.TeamState {
146183
reduceYellowCardTimes(teamState, delta)
147-
removeElapsedYellowCards(teamState)
184+
e.removeElapsedYellowCards(team, teamState)
148185
}
149186
}
150187

151188
if e.State.GameState() == GameStateTimeout && e.State.CommandFor.Known() {
152189
e.State.TeamState[e.State.CommandFor].TimeoutTimeLeft -= delta
190+
191+
timeLeft := e.State.TeamState[e.State.CommandFor].TimeoutTimeLeft
192+
if timeLeft+delta > 0 && timeLeft <= 0 {
193+
e.LogTime("Timeout time elapsed", e.State.CommandFor)
194+
}
153195
}
154196
}
155197

@@ -259,6 +301,7 @@ func (e *Engine) processStage(s *EventStage) error {
259301
}
260302

261303
func (e *Engine) updateStage(stage Stage) {
304+
e.LogStage(stage)
262305

263306
e.State.StageTimeLeft = e.StageTimes[stage]
264307
e.State.StageTimeElapsed = 0
@@ -296,7 +339,7 @@ func (e *Engine) updatePreStages() {
296339
}
297340
}
298341

299-
func (e *Engine) processCard(card *EventCard) error {
342+
func (e *Engine) processCard(card *EventCard) (err error) {
300343
if card.ForTeam != TeamYellow && card.ForTeam != TeamBlue {
301344
return errors.Errorf("Unknown team: %v", card.ForTeam)
302345
}
@@ -305,13 +348,19 @@ func (e *Engine) processCard(card *EventCard) error {
305348
}
306349
teamState := e.State.TeamState[card.ForTeam]
307350
if card.Operation == CardOperationAdd {
308-
return addCard(card, teamState, e.config.YellowCardDuration)
351+
err = addCard(card, teamState, e.config.YellowCardDuration)
309352
} else if card.Operation == CardOperationRevoke {
310-
return revokeCard(card, teamState)
353+
err = revokeCard(card, teamState)
311354
} else if card.Operation == CardOperationModify {
312355
return modifyCard(card, teamState)
356+
} else {
357+
return errors.Errorf("Unknown operation: %v", card.Operation)
313358
}
314-
return errors.Errorf("Unknown operation: %v", card.Operation)
359+
360+
if err == nil {
361+
e.LogCard(card)
362+
}
363+
return
315364
}
316365

317366
func modifyCard(card *EventCard, teamState *TeamInfo) error {
@@ -436,11 +485,13 @@ func reduceYellowCardTimes(teamState *TeamInfo, delta time.Duration) {
436485
}
437486
}
438487

439-
func removeElapsedYellowCards(teamState *TeamInfo) {
488+
func (e *Engine) removeElapsedYellowCards(team Team, teamState *TeamInfo) {
440489
b := teamState.YellowCardTimes[:0]
441490
for _, x := range teamState.YellowCardTimes {
442491
if x > 0 {
443492
b = append(b, x)
493+
} else {
494+
e.LogTime("Yellow card time elapsed", team)
444495
}
445496
}
446497
teamState.YellowCardTimes = b

internal/app/controller/gameEvents.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const (
1616
RefereeEventCommand RefereeEventType = "command"
1717
RefereeEventStage RefereeEventType = "stage"
1818
RefereeEventCard RefereeEventType = "card"
19+
RefereeEventTime RefereeEventType = "time"
1920
RefereeEventGameEvent RefereeEventType = "gameEvent"
2021
)
2122

src/components/common/TeamSelection.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<template>
22
<b-form-group :label="label" horizontal>
33
<b-form-radio-group id="select-team" v-model="newEvent.team" buttons>
4-
<b-form-radio value="yellow">Yellow</b-form-radio>
5-
<b-form-radio value="blue">Blue</b-form-radio>
4+
<b-form-radio value="Yellow">Yellow</b-form-radio>
5+
<b-form-radio value="Blue">Blue</b-form-radio>
66
<b-form-radio value="unknown" :disable="showUnknown">No team</b-form-radio>
77
</b-form-radio-group>
88
</b-form-group>

src/components/control/ControlMatch.vue

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,32 @@
11
<template>
22
<div>
33
<b-button v-b-tooltip.hover title="Start a new match by resetting everything"
4-
v-on:click="resetMatch">
4+
v-on:click="resetMatch"
5+
:disabled="forbidMatchControls">
56
Reset Match
67
</b-button>
78
<b-button v-b-tooltip.hover title="Undo the last state change"
89
v-on:click="undo">
910
Undo
1011
</b-button>
1112
<b-button v-b-tooltip.hover title="Switch the colors of the teams, keep everything else"
12-
v-on:click="switchColor">
13+
v-on:click="switchColor"
14+
:disabled="forbidMatchControls">
1315
Switch colors
1416
</b-button>
1517
<b-button v-b-tooltip.hover title="Switch the playing half (the goal) of the teams"
16-
v-on:click="switchSides">
18+
v-on:click="switchSides"
19+
:disabled="forbidMatchControls">
1720
Switch sides
1821
</b-button>
1922
<b-button v-b-tooltip.hover title="Change back to the previous stage (if something went wrong)"
20-
v-on:click="previousStage">
23+
v-on:click="previousStage"
24+
:disabled="forbidMatchControls">
2125
Previous Stage
2226
</b-button>
2327
<b-button v-b-tooltip.hover title="Proceed to the next stage"
24-
v-on:click="nextStage">
28+
v-on:click="nextStage"
29+
:disabled="forbidMatchControls">
2530
Next Stage
2631
</b-button>
2732
</div>
@@ -61,6 +66,20 @@
6166
'stage': {'stageOperation': 'next'}
6267
})
6368
},
69+
},
70+
computed: {
71+
state() {
72+
return this.$store.state.refBoxState
73+
},
74+
halted() {
75+
return this.state.command === 'halt';
76+
},
77+
stopped() {
78+
return this.state.command === 'stop';
79+
},
80+
forbidMatchControls() {
81+
return !this.stopped && !this.halted;
82+
}
6483
}
6584
}
6685
</script>

0 commit comments

Comments
 (0)