Skip to content

Commit e81434e

Browse files
committed
Allow robot substitution during halt
1 parent 5c6a832 commit e81434e

15 files changed

+216
-147
lines changed

frontend/src/proto/ssl_gc_referee_message.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,8 @@ export interface Referee_TeamInfo {
461461
botSubstitutionIntent?: boolean;
462462
/** Indicate if the team reached the maximum allowed ball placement failures and is thus not allowed to place the ball anymore */
463463
ballPlacementFailuresReached?: boolean;
464+
/** The team is allowed to substitute one or more robots currently */
465+
botSubstitutionAllowed?: boolean;
464466
}
465467

466468
/**
@@ -564,6 +566,7 @@ export const Referee_TeamInfo = {
564566
ballPlacementFailuresReached: isSet(object.ballPlacementFailuresReached)
565567
? Boolean(object.ballPlacementFailuresReached)
566568
: false,
569+
botSubstitutionAllowed: isSet(object.botSubstitutionAllowed) ? Boolean(object.botSubstitutionAllowed) : false,
567570
};
568571
},
569572

@@ -589,6 +592,7 @@ export const Referee_TeamInfo = {
589592
message.botSubstitutionIntent !== undefined && (obj.botSubstitutionIntent = message.botSubstitutionIntent);
590593
message.ballPlacementFailuresReached !== undefined &&
591594
(obj.ballPlacementFailuresReached = message.ballPlacementFailuresReached);
595+
message.botSubstitutionAllowed !== undefined && (obj.botSubstitutionAllowed = message.botSubstitutionAllowed);
592596
return obj;
593597
},
594598
};

frontend/src/proto/ssl_gc_state.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ export interface TeamInfo {
228228
requestsTimeoutSince?: Date;
229229
requestsEmergencyStopSince?: Date;
230230
challengeFlags?: number;
231+
botSubstitutionAllowed?: boolean;
231232
}
232233

233234
export interface State {
@@ -409,6 +410,7 @@ export const TeamInfo = {
409410
? fromJsonTimestamp(object.requestsEmergencyStopSince)
410411
: undefined,
411412
challengeFlags: isSet(object.challengeFlags) ? Number(object.challengeFlags) : 0,
413+
botSubstitutionAllowed: isSet(object.botSubstitutionAllowed) ? Boolean(object.botSubstitutionAllowed) : false,
412414
};
413415
},
414416

@@ -449,6 +451,7 @@ export const TeamInfo = {
449451
message.requestsEmergencyStopSince !== undefined &&
450452
(obj.requestsEmergencyStopSince = message.requestsEmergencyStopSince.toISOString());
451453
message.challengeFlags !== undefined && (obj.challengeFlags = Math.round(message.challengeFlags));
454+
message.botSubstitutionAllowed !== undefined && (obj.botSubstitutionAllowed = message.botSubstitutionAllowed);
452455
return obj;
453456
},
454457
};

internal/app/engine/engine.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,12 +213,22 @@ func (e *Engine) Start() error {
213213
return errors.Wrap(err, "Could not load state store")
214214
}
215215
e.currentState = e.initialStateFromStore()
216+
217+
initializeAddedTeamInfoFields(e.currentState.TeamInfo(state.Team_BLUE))
218+
initializeAddedTeamInfoFields(e.currentState.TeamInfo(state.Team_YELLOW))
219+
216220
e.stateMachine.Geometry = e.gameConfig.DefaultGeometry[e.currentState.Division.Div()]
217221
log.Printf("Loaded default geometry for DivA: %+v", e.stateMachine.Geometry)
218222
go e.processChanges()
219223
return nil
220224
}
221225

226+
func initializeAddedTeamInfoFields(teamInfo *state.TeamInfo) {
227+
if teamInfo.BotSubstitutionAllowed == nil {
228+
teamInfo.BotSubstitutionAllowed = new(bool)
229+
}
230+
}
231+
222232
// Stop stops the go routine that processes the change queue
223233
func (e *Engine) Stop() {
224234
e.mutex.Lock()

internal/app/engine/process_continue_next_action.go

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ func (e *Engine) nextActions() (actions []*ContinueAction) {
9191
}
9292
}
9393

94-
if *e.currentState.Command.Type == state.Command_STOP {
94+
if *e.currentState.Command.Type == state.Command_STOP ||
95+
*e.currentState.Command.Type == state.Command_HALT {
9596
if e.currentState.StageTimeLeft.AsDuration() < 0 {
9697
actions = append(actions, createContinueAction(
9798
ContinueAction_NEXT_STAGE,
@@ -121,7 +122,11 @@ func (e *Engine) nextActions() (actions []*ContinueAction) {
121122
*teamRequestingTimeout,
122123
ContinueAction_READY_MANUAL,
123124
))
124-
} else if e.ballPlacementRequired() {
125+
}
126+
}
127+
128+
if *e.currentState.Command.Type == state.Command_STOP {
129+
if e.ballPlacementRequired() {
125130
placingTeam := e.ballPlacementTeam()
126131
if placingTeam.Known() {
127132
actions = append(actions, createContinueAction(
@@ -146,11 +151,16 @@ func (e *Engine) nextActions() (actions []*ContinueAction) {
146151
}
147152

148153
if *e.currentState.Command.Type == state.Command_HALT {
149-
actions = append(actions, createContinueAction(
154+
continueFromHalt := createContinueAction(
150155
ContinueAction_RESUME_FROM_HALT,
151156
state.Team_UNKNOWN,
152157
ContinueAction_READY_MANUAL,
153-
))
158+
)
159+
if e.teamDoingBotSubstitution() {
160+
continueFromHalt.ContinuationIssues = append(continueFromHalt.ContinuationIssues,
161+
"Robot substitution in progress")
162+
}
163+
actions = append(actions, continueFromHalt)
154164
}
155165

156166
if *e.currentState.Command.Type != state.Command_HALT &&
@@ -168,7 +178,8 @@ func (e *Engine) nextActions() (actions []*ContinueAction) {
168178
func (e *Engine) teamRequestingBotSubstitution() *state.Team {
169179
var teams []state.Team
170180
for _, team := range state.BothTeams() {
171-
if e.currentState.TeamInfo(team).RequestsBotSubstitutionSince != nil {
181+
if e.currentState.TeamInfo(team).RequestsBotSubstitutionSince != nil &&
182+
!*e.currentState.TeamInfo(team).BotSubstitutionAllowed {
172183
teams = append(teams, team)
173184
}
174185
}
@@ -181,6 +192,15 @@ func (e *Engine) teamRequestingBotSubstitution() *state.Team {
181192
return nil
182193
}
183194

195+
func (e *Engine) teamDoingBotSubstitution() bool {
196+
for _, team := range state.BothTeams() {
197+
if *e.currentState.TeamInfo(team).BotSubstitutionAllowed {
198+
return true
199+
}
200+
}
201+
return false
202+
}
203+
184204
func (e *Engine) teamRequestingTimeout() *state.Team {
185205
requestBlue := e.currentState.TeamInfo(state.Team_BLUE).RequestsTimeoutSince
186206
requestYellow := e.currentState.TeamInfo(state.Team_YELLOW).RequestsTimeoutSince

internal/app/publish/messagegenerator.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ func updateTeam(teamInfo *state.Referee_TeamInfo, teamState *state.TeamInfo) {
135135
*teamInfo.CanPlaceBall = *teamState.CanPlaceBall
136136
*teamInfo.MaxAllowedBots = unsigned32(*teamState.MaxAllowedBots)
137137
*teamInfo.BotSubstitutionIntent = teamState.RequestsBotSubstitutionSince != nil
138+
*teamInfo.BotSubstitutionAllowed = *teamState.BotSubstitutionAllowed
138139
timeoutTime := teamState.TimeoutTimeLeft.AsDuration()
139140
*teamInfo.TimeoutTime = mapTime(timeoutTime)
140141
}
@@ -171,6 +172,7 @@ func newTeamInfo() (t *state.Referee_TeamInfo) {
171172
t.CanPlaceBall = new(bool)
172173
t.MaxAllowedBots = new(uint32)
173174
t.BotSubstitutionIntent = new(bool)
175+
t.BotSubstitutionAllowed = new(bool)
174176
return
175177
}
176178

internal/app/rcon/server_remotecontrol.go

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,7 @@ func (c *RemoteControlClient) findYellowCardDueTimes() []float32 {
199199

200200
func (c *RemoteControlClient) canSubstituteRobot() bool {
201201
teamState := c.gcEngine.CurrentState().TeamState[c.team.String()]
202-
substitutionEvents := c.gcEngine.CurrentState().FindGameEventsByTeam(state.GameEvent_BOT_SUBSTITUTION, *c.team)
203-
return len(substitutionEvents) > 0 &&
204-
teamState.RequestsBotSubstitutionSince != nil &&
205-
c.gcEngine.CurrentState().GameState.IsHalted()
202+
return *teamState.BotSubstitutionAllowed
206203
}
207204

208205
func (c *RemoteControlClient) findActiveRequestTypes() []RemoteControlRequestType {
@@ -280,11 +277,6 @@ func (c *RemoteControlClient) checkStopTimeout() error {
280277
}
281278

282279
func (c *RemoteControlClient) checkRequestRobotSubstitution() error {
283-
gameStateType := *c.gcEngine.CurrentState().GameState.Type
284-
teamState := c.gcEngine.CurrentState().TeamState[c.team.String()]
285-
if gameStateType == state.GameState_HALT && teamState.RequestsBotSubstitutionSince == nil {
286-
return errors.New("Game is halted")
287-
}
288280
return nil
289281
}
290282

0 commit comments

Comments
 (0)