Skip to content

Commit f0ac0db

Browse files
committed
Fix: Correctly implement KEEPER_HELD_BALL foul
1 parent f1969bd commit f0ac0db

File tree

7 files changed

+66
-24
lines changed

7 files changed

+66
-24
lines changed

internal/app/config/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type Game struct {
5151
PrepareTimeout time.Duration `yaml:"prepare-timeout"`
5252
FreeKickTimeout map[Division]time.Duration `yaml:"free-kick-timeout"`
5353
NoProgressTimeout map[Division]time.Duration `yaml:"no-progress-timeout"`
54+
KeeperHeldBallTimeout map[Division]time.Duration `yaml:"keeper-held-ball-timeout"`
5455
BallPlacementTime time.Duration `yaml:"ball-placement-time"`
5556
BallPlacementTimeTopUp time.Duration `yaml:"ball-placement-time-top-up"`
5657
StateStoreFile string `yaml:"state-store-file"`
@@ -184,6 +185,7 @@ func DefaultControllerConfig() (c Controller) {
184185
c.Game.PrepareTimeout = time.Second * 10
185186
c.Game.FreeKickTimeout = map[Division]time.Duration{DivA: time.Second * 5, DivB: time.Second * 10}
186187
c.Game.NoProgressTimeout = map[Division]time.Duration{DivA: time.Second * 5, DivB: time.Second * 10}
188+
c.Game.KeeperHeldBallTimeout = map[Division]time.Duration{DivA: time.Second * 5, DivB: time.Second * 10}
187189
c.Game.BallPlacementTime = time.Second * 30
188190
c.Game.BallPlacementTimeTopUp = time.Second * 10
189191
c.Game.BallPlacementRequiredDistance = 1.0

internal/app/config/testdata/config.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ game:
3535
no-progress-timeout:
3636
DIV_A: 5s
3737
DIV_B: 10s
38+
keeper-held-ball-timeout:
39+
DIV_A: 5s
40+
DIV_B: 10s
3841
ball-placement-time: 30s
3942
ball-placement-time-top-up: 10s
4043
ball-placement-required-distance: 1.0

internal/app/engine/common.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,13 @@ func (x *GcStateTracker) NumTeamRobots(team state.Team) (count int32) {
130130
}
131131
return
132132
}
133+
134+
func (e *Engine) isBallInAnyDefenseArea() (bool, state.Team) {
135+
for _, team := range state.BothTeams() {
136+
defenseArea := geom.NewDefenseArea(e.getGeometry(), *e.currentState.TeamState[team.String()].OnPositiveHalf)
137+
if defenseArea.IsPointInside(e.trackerStateGc.Ball.Pos.ToVector2()) {
138+
return true, team
139+
}
140+
}
141+
return false, state.Team_UNKNOWN
142+
}

internal/app/engine/engine.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ type Engine struct {
4040
mutex sync.Mutex
4141
mutexEnqueueBlocking sync.Mutex
4242
noProgressDetector NoProgressDetector
43+
keeperHeldBallDetector KeeperHeldBallDetector
4344
ballPlacementCoordinator BallPlacementCoordinator
4445
botNumberProcessor BotNumberProcessor
4546
tickChanProvider func() <-chan time.Time
@@ -70,6 +71,7 @@ func NewEngine(gameConfig config.Game, engineConfig config.Engine) (e *Engine) {
7071
e.trackerStateGc = &GcStateTracker{}
7172
e.trackerLastUpdate = map[string]time.Time{}
7273
e.noProgressDetector = NoProgressDetector{gcEngine: e}
74+
e.keeperHeldBallDetector = KeeperHeldBallDetector{gcEngine: e}
7375
e.ballPlacementCoordinator = BallPlacementCoordinator{gcEngine: e}
7476
e.botNumberProcessor = BotNumberProcessor{gcEngine: e}
7577
e.tickChanProvider = func() <-chan time.Time {
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package engine
2+
3+
import (
4+
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/state"
5+
"time"
6+
)
7+
8+
type KeeperHeldBallDetector struct {
9+
gcEngine *Engine
10+
lastTime *time.Time
11+
}
12+
13+
func (d *KeeperHeldBallDetector) process() {
14+
15+
if !d.gcEngine.currentState.Command.IsRunning() ||
16+
d.gcEngine.trackerStateGc.Ball == nil {
17+
d.lastTime = nil
18+
return
19+
}
20+
21+
if ok, team := d.gcEngine.isBallInAnyDefenseArea(); ok {
22+
if d.lastTime == nil {
23+
d.lastTime = new(time.Time)
24+
*d.lastTime = d.gcEngine.timeProvider()
25+
return
26+
}
27+
28+
timeSinceLastProgress := d.gcEngine.timeProvider().Sub(*d.lastTime)
29+
if timeSinceLastProgress > d.gcEngine.gameConfig.KeeperHeldBallTimeout[d.gcEngine.currentState.Division.Div()] {
30+
duration := float32(timeSinceLastProgress.Seconds())
31+
location := d.gcEngine.trackerStateGc.Ball.Pos.ToVector2()
32+
if d.gcEngine.IsGameEventEnabled(state.GameEvent_KEEPER_HELD_BALL) {
33+
d.gcEngine.Enqueue(createGameEventChange(state.GameEvent_KEEPER_HELD_BALL, &state.GameEvent{
34+
Event: &state.GameEvent_KeeperHeldBall_{
35+
KeeperHeldBall: &state.GameEvent_KeeperHeldBall{
36+
ByTeam: &team,
37+
Location: location,
38+
Duration: &duration,
39+
},
40+
},
41+
}))
42+
return
43+
}
44+
}
45+
} else {
46+
d.lastTime = nil
47+
}
48+
}

internal/app/engine/process_noprogress.go

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,6 @@ func (d *NoProgressDetector) process() {
4545
if timeSinceLastProgress > d.gcEngine.gameConfig.NoProgressTimeout[d.gcEngine.currentState.Division.Div()] {
4646
duration := float32(timeSinceLastProgress.Seconds())
4747
location := d.gcEngine.trackerStateGc.Ball.Pos.ToVector2()
48-
if d.gcEngine.IsGameEventEnabled(state.GameEvent_KEEPER_HELD_BALL) {
49-
if ok, team := d.isBallInAnyDefenseArea(); ok {
50-
d.gcEngine.Enqueue(createGameEventChange(state.GameEvent_KEEPER_HELD_BALL, &state.GameEvent{
51-
Event: &state.GameEvent_KeeperHeldBall_{
52-
KeeperHeldBall: &state.GameEvent_KeeperHeldBall{
53-
ByTeam: &team,
54-
Location: location,
55-
Duration: &duration,
56-
},
57-
},
58-
}))
59-
return
60-
}
61-
}
6248
if d.gcEngine.IsGameEventEnabled(state.GameEvent_NO_PROGRESS_IN_GAME) {
6349
d.gcEngine.Enqueue(createGameEventChange(state.GameEvent_NO_PROGRESS_IN_GAME, &state.GameEvent{
6450
Event: &state.GameEvent_NoProgressInGame_{
@@ -71,13 +57,3 @@ func (d *NoProgressDetector) process() {
7157
}
7258
}
7359
}
74-
75-
func (d *NoProgressDetector) isBallInAnyDefenseArea() (bool, state.Team) {
76-
for _, team := range state.BothTeams() {
77-
defenseArea := geom.NewDefenseArea(d.gcEngine.getGeometry(), *d.gcEngine.currentState.TeamState[team.String()].OnPositiveHalf)
78-
if defenseArea.IsPointInside(d.gcEngine.trackerStateGc.Ball.Pos.ToVector2()) {
79-
return true, team
80-
}
81-
}
82-
return false, state.Team_UNKNOWN
83-
}

internal/app/engine/process_tick.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ func (e *Engine) processTick() {
5757
}
5858
}
5959

60+
e.keeperHeldBallDetector.process()
6061
e.noProgressDetector.process()
6162
e.ballPlacementCoordinator.process()
6263
e.processContinue()

0 commit comments

Comments
 (0)