8
8
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/statemachine"
9
9
"github.com/google/uuid"
10
10
"github.com/pkg/errors"
11
- "google.golang.org/protobuf/types/known/timestamppb"
12
11
"io"
13
12
"log"
14
13
"net"
@@ -135,23 +134,8 @@ func (s *RemoteControlServer) SendRequest(teamName string, request *ControllerTo
135
134
return errors .Errorf ("Remote control client '%v' not connected" , teamName )
136
135
}
137
136
138
- func (c * RemoteControlClient ) replyWithState (reply * ControllerReply ) {
139
- teamState := c .gcEngine .CurrentState ().TeamState [c .team .String ()]
140
- emergencyStopDueIn := c .gcEngine .EmergencyStopDueIn (* c .team )
141
- var emergencyStopIn * float32
142
- if emergencyStopDueIn != nil {
143
- emergencyStopIn = new (float32 )
144
- * emergencyStopIn = float32 (emergencyStopDueIn .Seconds ())
145
- }
137
+ func (c * RemoteControlClient ) reply (reply * ControllerReply ) {
146
138
response := & ControllerToRemoteControl {
147
- State : & RemoteControlTeamState {
148
- KeeperId : teamState .Goalkeeper ,
149
- SubstituteBot : timeSet (teamState .RequestsBotSubstitutionSince ),
150
- EmergencyStop : timeSet (teamState .RequestsEmergencyStopSince ),
151
- EmergencyStopIn : emergencyStopIn ,
152
- Timeout : timeSet (teamState .RequestsTimeoutSince ),
153
- ChallengeFlag : gameEventPresent (c .gcEngine .CurrentState ().GameEvents , state .GameEvent_CHALLENGE_FLAG , * c .team ),
154
- },
155
139
ControllerReply : reply ,
156
140
}
157
141
@@ -160,8 +144,24 @@ func (c *RemoteControlClient) replyWithState(reply *ControllerReply) {
160
144
}
161
145
}
162
146
163
- func (c * RemoteControlClient ) reply (reply * ControllerReply ) {
147
+ func (c * RemoteControlClient ) replyWithState (reply * ControllerReply ) {
148
+ teamState := c .gcEngine .CurrentState ().TeamState [c .team .String ()]
149
+ emergencyStopIn := c .findEmergencyStopDueIn ()
150
+ yellowCardsDue := c .findYellowCardDueTimes ()
151
+ availableRequests := c .findAvailableRequestTypes ()
152
+ activeRequests := c .findActiveRequestTypes ()
153
+
164
154
response := & ControllerToRemoteControl {
155
+ State : & RemoteControlTeamState {
156
+ KeeperId : teamState .Goalkeeper ,
157
+ AvailableRequests : availableRequests ,
158
+ ActiveRequests : activeRequests ,
159
+ EmergencyStopIn : & emergencyStopIn ,
160
+ TimeoutsLeft : teamState .TimeoutsLeft ,
161
+ ChallengeFlagsLeft : teamState .ChallengeFlags ,
162
+ MaxRobots : teamState .MaxAllowedBots ,
163
+ YellowCardsDue : yellowCardsDue ,
164
+ },
165
165
ControllerReply : reply ,
166
166
}
167
167
@@ -170,62 +170,159 @@ func (c *RemoteControlClient) reply(reply *ControllerReply) {
170
170
}
171
171
}
172
172
173
- func timeSet (t * timestamppb.Timestamp ) (set * bool ) {
174
- set = new (bool )
175
- * set = t != nil
176
- return
173
+ func (c * RemoteControlClient ) findEmergencyStopDueIn () float32 {
174
+ emergencyStopDueIn := c .gcEngine .EmergencyStopDueIn (* c .team )
175
+ var emergencyStopIn float32
176
+ if emergencyStopDueIn != nil {
177
+ emergencyStopIn = float32 (emergencyStopDueIn .Seconds ())
178
+ }
179
+ return emergencyStopIn
177
180
}
178
181
179
- func gameEventPresent (events []* state.GameEvent , eventType state.GameEvent_Type , team state.Team ) (present * bool ) {
180
- present = new (bool )
181
- for _ , event := range events {
182
- if * event .Type == eventType && event .ByTeam () == team {
183
- * present = true
182
+ func (c * RemoteControlClient ) findYellowCardDueTimes () []float32 {
183
+ teamState := c .gcEngine .CurrentState ().TeamState [c .team .String ()]
184
+ var yellowCardsDue []float32
185
+ for _ , yc := range teamState .YellowCards {
186
+ if yc .TimeRemaining != nil && yc .TimeRemaining .AsDuration () > 0 {
187
+ yellowCardsDue = append (yellowCardsDue , float32 (yc .TimeRemaining .AsDuration ().Seconds ()))
184
188
}
185
189
}
186
- return
190
+ return yellowCardsDue
191
+ }
192
+
193
+ func (c * RemoteControlClient ) findActiveRequestTypes () []RemoteControlRequestType {
194
+ currentState := c .gcEngine .CurrentState ()
195
+ teamState := currentState .TeamState [c .team .String ()]
196
+
197
+ var activeRequests []RemoteControlRequestType
198
+ if teamState .RequestsBotSubstitutionSince != nil {
199
+ activeRequests = append (activeRequests , RemoteControlRequestType_ROBOT_SUBSTITUTION )
200
+ }
201
+ if teamState .RequestsTimeoutSince != nil {
202
+ activeRequests = append (activeRequests , RemoteControlRequestType_TIMEOUT )
203
+ }
204
+ if currentState .HasGameEventByTeam (state .GameEvent_CHALLENGE_FLAG , * c .team ) {
205
+ activeRequests = append (activeRequests , RemoteControlRequestType_CHALLENGE_FLAG )
206
+ }
207
+ if teamState .RequestsEmergencyStopSince != nil {
208
+ activeRequests = append (activeRequests , RemoteControlRequestType_EMERGENCY_STOP )
209
+ }
210
+ return activeRequests
211
+ }
212
+
213
+ func (c * RemoteControlClient ) findAvailableRequestTypes () []RemoteControlRequestType {
214
+ var availableRequests []RemoteControlRequestType
215
+ if c .checkRequestEmergencyStop () == nil {
216
+ availableRequests = append (availableRequests , RemoteControlRequestType_EMERGENCY_STOP )
217
+ }
218
+ if c .checkRequestTimeout () == nil {
219
+ availableRequests = append (availableRequests , RemoteControlRequestType_TIMEOUT )
220
+ }
221
+ if c .checkRequestRobotSubstitution () == nil {
222
+ availableRequests = append (availableRequests , RemoteControlRequestType_ROBOT_SUBSTITUTION )
223
+ }
224
+ if c .checkRequestChallengeFlag () == nil {
225
+ availableRequests = append (availableRequests , RemoteControlRequestType_CHALLENGE_FLAG )
226
+ }
227
+ if c .checkChangeKeeper () == nil {
228
+ availableRequests = append (availableRequests , RemoteControlRequestType_CHANGE_KEEPER_ID )
229
+ }
230
+ return availableRequests
231
+ }
232
+
233
+ func (c * RemoteControlClient ) checkRequestEmergencyStop () error {
234
+ gameStateType := * c .gcEngine .CurrentState ().GameState .Type
235
+ switch gameStateType {
236
+ case state .GameState_RUNNING ,
237
+ state .GameState_KICKOFF ,
238
+ state .GameState_PENALTY ,
239
+ state .GameState_FREE_KICK :
240
+ return nil
241
+ }
242
+ return errors .Errorf ("Game state is invalid: %s" , gameStateType )
243
+ }
244
+
245
+ func (c * RemoteControlClient ) checkRequestTimeout () error {
246
+ gameStateType := * c .gcEngine .CurrentState ().GameState .Type
247
+ if gameStateType == state .GameState_TIMEOUT {
248
+ return errors .New ("Timeout is active" )
249
+ }
250
+ return nil
251
+ }
252
+
253
+ func (c * RemoteControlClient ) checkRequestRobotSubstitution () error {
254
+ gameStateType := * c .gcEngine .CurrentState ().GameState .Type
255
+ if gameStateType == state .GameState_HALT {
256
+ return errors .New ("Game is halted" )
257
+ }
258
+ return nil
259
+ }
260
+
261
+ func (c * RemoteControlClient ) checkRequestChallengeFlag () error {
262
+ currentState := c .gcEngine .CurrentState ()
263
+ teamState := currentState .TeamState [c .team .String ()]
264
+ if currentState .HasGameEventByTeam (state .GameEvent_CHALLENGE_FLAG , * c .team ) {
265
+ return errors .New ("Challenge flag already requested" )
266
+ }
267
+ if * teamState .ChallengeFlags <= 0 {
268
+ return errors .New ("No more challenge flags left" )
269
+ } else if * teamState .TimeoutsLeft <= 0 {
270
+ return errors .New ("No more timeouts left" )
271
+ }
272
+ return nil
273
+ }
274
+
275
+ func (c * RemoteControlClient ) checkChangeKeeper () error {
276
+ currentState := c .gcEngine .CurrentState ()
277
+ teamState := currentState .TeamState [c .team .String ()]
278
+ return mayChangeKeeper (c .gcEngine .CurrentGcState (), teamState )
187
279
}
188
280
189
281
func (c * RemoteControlClient ) processRequest (request * RemoteControlToController ) error {
190
282
191
283
currentState := c .gcEngine .CurrentState ()
192
- teamState := * currentState .TeamInfo (* c .team )
284
+ teamState := currentState .TeamInfo (* c .team )
193
285
194
286
if x , ok := request .GetMsg ().(* RemoteControlToController_DesiredKeeper ); ok && * teamState .Goalkeeper != x .DesiredKeeper {
195
- if err := mayChangeKeeper (c .gcEngine .CurrentGcState (), & teamState ); err != nil {
196
- return errors .Wrap (err , "Remote control requests to change keeper, but: " )
287
+ if err := mayChangeKeeper (c .gcEngine .CurrentGcState (), teamState ); err != nil {
288
+ return errors .Wrap (err , "Can not change keeper id " )
197
289
}
198
290
c .updateTeamConfig (& statemachine.UpdateTeamState {
199
291
Goalkeeper : & x .DesiredKeeper ,
200
292
})
201
293
}
202
294
203
- if x , ok := request .GetMsg ().(* RemoteControlToController_SubstituteBot ); ok {
204
- if * timeSet (teamState .RequestsBotSubstitutionSince ) != x .SubstituteBot {
295
+ if x , ok := request .GetMsg ().(* RemoteControlToController_RequestRobotSubstitution ); ok {
296
+ robotSubstitutionRequested := teamState .RequestsBotSubstitutionSince != nil
297
+ if robotSubstitutionRequested != x .RequestRobotSubstitution {
298
+ if err := c .checkRequestRobotSubstitution (); err != nil {
299
+ return errors .Wrap (err , "Can not request robot substitution" )
300
+ }
205
301
c .updateTeamConfig (& statemachine.UpdateTeamState {
206
- RequestsBotSubstitution : & x .SubstituteBot ,
302
+ RequestsBotSubstitution : & x .RequestRobotSubstitution ,
207
303
})
208
304
}
209
305
return nil
210
306
}
211
307
212
- if x , ok := request .GetMsg ().(* RemoteControlToController_Timeout ); ok {
213
- if (* timeSet (teamState .RequestsTimeoutSince )) != x .Timeout {
308
+ if x , ok := request .GetMsg ().(* RemoteControlToController_RequestTimeout ); ok {
309
+ timeoutRequested := teamState .RequestsTimeoutSince != nil
310
+ if timeoutRequested != x .RequestTimeout {
311
+ if err := c .checkRequestTimeout (); err != nil {
312
+ return errors .Wrap (err , "Can not request timeout" )
313
+ }
214
314
c .updateTeamConfig (& statemachine.UpdateTeamState {
215
- RequestsTimeout : & x .Timeout ,
315
+ RequestsTimeout : & x .RequestTimeout ,
216
316
})
217
317
}
218
318
return nil
219
319
}
220
320
221
321
if request .GetRequest () == RemoteControlToController_CHALLENGE_FLAG {
222
- if * teamState .ChallengeFlags <= 0 {
223
- return errors .New ("No more challenge flags left" )
224
- } else if * teamState .TimeoutsLeft <= 0 {
225
- return errors .New ("No more timeouts left" )
322
+ if err := c .checkRequestChallengeFlag (); err != nil {
323
+ return errors .Wrap (err , "Can not request challenge flag" )
226
324
}
227
325
eventType := state .GameEvent_CHALLENGE_FLAG
228
- log .Println ("Request challenge flag via remote control" )
229
326
c .gcEngine .EnqueueGameEvent (& state.GameEvent {
230
327
Type : & eventType ,
231
328
Origin : []string {* origin (c .team )},
@@ -238,13 +335,14 @@ func (c *RemoteControlClient) processRequest(request *RemoteControlToController)
238
335
return nil
239
336
}
240
337
241
- if x , ok := request .GetMsg ().(* RemoteControlToController_EmergencyStop ); ok {
242
- if * currentState .GameState .Type != state .GameState_RUNNING {
243
- return errors .New ("Game is not running, can not request emergency stop" )
244
- }
245
- if * timeSet (teamState .RequestsEmergencyStopSince ) != x .EmergencyStop {
338
+ if x , ok := request .GetMsg ().(* RemoteControlToController_RequestEmergencyStop ); ok {
339
+ emergencyStopRequested := teamState .RequestsEmergencyStopSince != nil
340
+ if emergencyStopRequested != x .RequestEmergencyStop {
341
+ if err := c .checkRequestEmergencyStop (); err != nil {
342
+ return errors .Wrap (err , "Can not request emergency stop" )
343
+ }
246
344
c .updateTeamConfig (& statemachine.UpdateTeamState {
247
- RequestsEmergencyStop : & x .EmergencyStop ,
345
+ RequestsEmergencyStop : & x .RequestEmergencyStop ,
248
346
})
249
347
}
250
348
return nil
@@ -256,12 +354,15 @@ func (c *RemoteControlClient) processRequest(request *RemoteControlToController)
256
354
func (c * RemoteControlClient ) updateTeamConfig (update * statemachine.UpdateTeamState ) {
257
355
log .Println ("Update team config via remote control: " , update .String ())
258
356
update .ForTeam = c .team
259
- c .gcEngine .Enqueue (& statemachine.Change {
357
+ err := c .gcEngine .EnqueueBlocking (& statemachine.Change {
260
358
Origin : origin (c .team ),
261
359
Change : & statemachine.Change_UpdateTeamState {
262
360
UpdateTeamState : update ,
263
361
},
264
362
})
363
+ if err != nil {
364
+ log .Println ("Failed to update team state: " , err )
365
+ }
265
366
}
266
367
267
368
func origin (team * state.Team ) * string {
0 commit comments