diff --git a/static/css/scoring_panel.css b/static/css/scoring_panel.css index e0240f91..fc71bb58 100644 --- a/static/css/scoring_panel.css +++ b/static/css/scoring_panel.css @@ -16,6 +16,7 @@ body { .container { padding-top: 1vw; width: 100%; + max-width: none; height: 100%; display: flex; flex-direction: column; @@ -38,6 +39,7 @@ body { background-color: #223; } #matchName { + margin-bottom: 0.5vw; font-size: 2vw; } .scoring-section { @@ -73,98 +75,70 @@ body { .boolean[data-value="true"] { background-color: #263; } -.endgame-status[data-value="0"] { - background-color: #333; -} -.endgame-status[data-value="1"] { - background-color: #652; -} -.endgame-status[data-value="2"] { - background-color: #263; -} -.charge-station-level[data-value="false"] { - background-color: #622; +#postMatchMessage { + height: 5vw; + display: none; + align-items: center; + font-size: 1.5vw; + color: #c90; } -.charge-station-level[data-value="true"] { - background-color: #263; +#commitMatchScore { + height: 5vw; + display: none; + align-items: center; } -#grid { - width: 100%; - margin-top: 1.5vw; - margin-bottom: 1.5vw; - display: flex; - flex-direction: column; +#commitMatchScore>button { + font-size: 1vw; } -.grid-row { - width: 100%; +#stage { + position: relative; display: flex; justify-content: center; -} -.grid-node { - width: 10vw; - display: flex; - flex-direction: column; align-items: center; - border: 1px solid #ccc; - padding: 0.5vw; - margin-top: -1px; - margin-left: -1px; } -.grid-node[data-node="2"], .grid-node[data-node="5"] { - margin-right: 1vw; +#stageGraphic { + margin-top: 9vw; + height: 30vw; + color: #999; } -.grid-node-auto { - width: 4vw; - height: 2vw; - margin-bottom: 0.5vw; +.stage-side { + position: absolute; + top: 0; + left: 0; display: flex; - justify-content: center; - align-items: center; - border-radius: 0.5vw; - background-color: #333; - color: #ccc; -} -.grid-node-auto[data-value="true"] { - background-color: #263; + width: 16vw; + height: 8vw; + border: 0.5px solid #111; } -.grid-node-states { +.stage-side-col { display: flex; - flex-wrap: wrap; - justify-content: space-around; + flex-direction: column; + flex-grow: 1; + height: 100%; } -.grid-node-button { - width: 4vw; - height: 4vw; +.stage-side-col div { display: flex; justify-content: center; align-items: center; - opacity: 0.4; -} -.grid-node-button[data-value="true"] { - border: 2px solid #aaa; - border-radius: 0.5vw; - opacity: 1; -} -.grid-node-button img { - width: 90%; + flex-grow: 1; + font-size: 1.5vw; + background-color: #333; + border: 0.5px solid #111; } -#chargeStation { - width: 70vw; - justify-content: space-between; - align-items: center; +#stageLeft { + top: 20vw; + left: -8.5vw; } -#postMatchMessage { - height: 5vw; - display: none; - align-items: center; - font-size: 1.5vw; - color: #c90; +#centerStage { + top: 0.5vw; + left: 9.3vw; } -#commitMatchScore { - height: 5vw; - display: none; - align-items: center; +#stageRight { + top: 20vw; + left: 25.9vw; } -#commitMatchScore>button { - font-size: 1vw; +#park { + top: 13vw; + left: 12.2vw; + width: 9vw; } diff --git a/static/js/scoring_panel.js b/static/js/scoring_panel.js index fc5f6065..9aa62992 100644 --- a/static/js/scoring_panel.js +++ b/static/js/scoring_panel.js @@ -10,13 +10,13 @@ let alliance; const handleMatchLoad = function(data) { $("#matchName").text(data.Match.LongName); if (alliance === "red") { - $("#team1").text(data.Match.Red1); - $("#team2").text(data.Match.Red2); - $("#team3").text(data.Match.Red3); + $(".team-1").text(data.Match.Red1); + $(".team-2").text(data.Match.Red2); + $(".team-3").text(data.Match.Red3); } else { - $("#team1").text(data.Match.Blue1); - $("#team2").text(data.Match.Blue2); - $("#team3").text(data.Match.Blue3); + $(".team-1").text(data.Match.Blue1); + $(".team-2").text(data.Match.Blue2); + $(".team-3").text(data.Match.Blue3); } }; @@ -50,33 +50,20 @@ const handleRealtimeScore = function(data) { for (let i = 0; i < 3; i++) { const i1 = i + 1; - $(`#mobilityStatus${i1}>.value`).text(score.MobilityStatuses[i] ? "Yes" : "No"); - $("#mobilityStatus" + i1).attr("data-value", score.MobilityStatuses[i]); - $("#autoDockStatus" + i1 + ">.value").text(score.AutoDockStatuses[i] ? "Yes" : "No"); - $("#autoDockStatus" + i1).attr("data-value", score.AutoDockStatuses[i]); - $("#endgameStatus" + i1 + ">.value").text(getEndgameStatusText(score.EndgameStatuses[i])); - $("#endgameStatus" + i1).attr("data-value", score.EndgameStatuses[i]); - } - - $("#autoChargeStationLevel>.value").text(score.AutoChargeStationLevel ? "Level" : "Not Level"); - $("#autoChargeStationLevel").attr("data-value", score.AutoChargeStationLevel); - $("#endgameChargeStationLevel>.value").text(score.EndgameChargeStationLevel ? "Level" : "Not Level"); - $("#endgameChargeStationLevel").attr("data-value", score.EndgameChargeStationLevel); - - for (let i = 0; i < 3; i++) { - for (let j = 0; j < 9; j++) { - $(`#gridAutoScoringRow${i}Node${j}`).attr("data-value", score.Grid.AutoScoring[i][j]); - $(`#gridNodeStatesRow${i}Node${j}`).children().each(function() { - const element = $(this); - element.attr("data-value", element.attr("data-node-state") === score.Grid.Nodes[i][j].toString()); - }); - } + $(`#leaveStatus${i1}>.value`).text(score.LeaveStatuses[i] ? "Yes" : "No"); + $(`#leaveStatus${i1}`).attr("data-value", score.LeaveStatuses[i]); + $(`#parkTeam${i1}`).attr("data-value", score.EndgameStatuses[i] === 1); + $(`#stageSide0Team${i1}`).attr("data-value", score.EndgameStatuses[i] === 2); + $(`#stageSide1Team${i1}`).attr("data-value", score.EndgameStatuses[i] === 3); + $(`#stageSide2Team${i1}`).attr("data-value", score.EndgameStatuses[i] === 4); + $(`#stageSide${i}Microphone`).attr("data-value", score.MicrophoneStatuses[i]); + $(`#stageSide${i}Trap`).attr("data-value", score.TrapStatuses[i]); } }; // Handles an element click and sends the appropriate websocket message. -const handleClick = function(command, teamPosition = 0, gridRow = 0, gridNode = 0, nodeState = 0) { - websocket.send(command, {TeamPosition: teamPosition, GridRow: gridRow, GridNode: gridNode, NodeState: nodeState}); +const handleClick = function(command, teamPosition = 0, stageIndex = 0) { + websocket.send(command, {TeamPosition: teamPosition, StageIndex: stageIndex}); }; // Sends a websocket message to indicate that the score for this alliance is ready. @@ -86,18 +73,6 @@ const commitMatchScore = function() { $("#commitMatchScore").hide(); }; -// Returns the display text corresponding to the given integer endgame status value. -const getEndgameStatusText = function(level) { - switch (level) { - case 1: - return "Park"; - case 2: - return "Dock"; - default: - return "None"; - } -}; - $(function() { alliance = window.location.href.split("/").slice(-1)[0]; $("#alliance").attr("data-alliance", alliance); diff --git a/templates/scoring_panel.html b/templates/scoring_panel.html index b6cfb429..a7d805f0 100644 --- a/templates/scoring_panel.html +++ b/templates/scoring_panel.html @@ -11,44 +11,41 @@ <div class="scoring-section"> <div class="scoring-header"> <div> </div> - <div>Mobility</div> - <div>Auto Dock</div> - <div>Endgame</div> + <div>Leave</div> </div> {{range $i := seq 3}} <div> - <div id="team{{$i}}" class="team robot-field"></div> - <div id="mobilityStatus{{$i}}" class="boolean robot-field" onclick="handleClick('mobilityStatus', {{$i}});"> - <div class="value"></div> - </div> - <div id="autoDockStatus{{$i}}" class="boolean robot-field" onclick="handleClick('autoDockStatus', {{$i}});"> - <div class="value"></div> - </div> - <div id="endgameStatus{{$i}}" class="endgame-status robot-field" - onclick="handleClick('endgameStatus', {{$i}});"> + <div class="team team-{{$i}} robot-field"></div> + <div id="leaveStatus{{$i}}" class="boolean robot-field" onclick="handleClick('leave', {{$i}});"> <div class="value"></div> </div> </div> {{end}} </div> - <div id="chargeStation" class="scoring-section"> - <div id="autoChargeStationLevel" class="charge-station-level robot-field" - onclick="handleClick('autoChargeStationLevel');"> - <div class="value"></div> - </div> - <div>Auto</div> - <div>Charge Station</div> - <div>Endgame</div> - <div id="endgameChargeStationLevel" class="charge-station-level robot-field" - onclick="handleClick('endgameChargeStationLevel');"> - <div class="value"></div> + <div id="stage"> + <svg id="stageGraphic" viewBox="0 4 100 90"> + <polygon points="5,5 95,5 50,78" fill="none" stroke="currentColor" stroke-width="0.2" /> + <text x="50" y="7.5" text-anchor="middle" font-size="2" fill="currentColor">Center</text> + <text x="50" y="9.5" text-anchor="middle" font-size="2" fill="currentColor">Stage</text> + <text x="30" y="38" text-anchor="middle" font-size="2" fill="currentColor">Stage</text> + <text x="30" y="40" text-anchor="middle" font-size="2" fill="currentColor">Left</text> + <text x="69" y="38" text-anchor="middle" font-size="2" fill="currentColor">Stage</text> + <text x="69" y="40" text-anchor="middle" font-size="2" fill="currentColor">Right</text> + <text x="50" y="15" text-anchor="middle" font-size="2" fill="currentColor">Park</text> + <line x1="5" y1="85" x2="95" y2="85" stroke="currentColor" stroke-width="0.2" /> + <text x="50" y="87.5" text-anchor="middle" font-size="2" fill="currentColor">Alliance Wall</text> + </svg> + <div id="stageLeft" class="stage-side">{{template "stageSide" dict "index" 0}}</div> + <div id="centerStage" class="stage-side">{{template "stageSide" dict "index" 1}}</div> + <div id="stageRight" class="stage-side">{{template "stageSide" dict "index" 2}}</div> + <div id="park" class="stage-side"> + <div class="stage-side-col"> + <div id="parkTeam1" class="team-1 boolean" onclick="handleClick('park', 1);"></div> + <div id="parkTeam2" class="team-2 boolean" onclick="handleClick('park', 2);"></div> + <div id="parkTeam3" class="team-3 boolean" onclick="handleClick('park', 3);"></div> + </div> </div> </div> - <div id="grid"> - {{template "gridRow" dict "rowIndex" 2 "validNodeStates" (index .ValidGridNodeStates 2)}} - {{template "gridRow" dict "rowIndex" 1 "validNodeStates" (index .ValidGridNodeStates 1)}} - {{template "gridRow" dict "rowIndex" 0 "validNodeStates" (index .ValidGridNodeStates 0)}} - </div> </div> <div id="commitMatchScore"> <button type="button" class="btn btn-primary" onclick="commitMatchScore();"> @@ -66,31 +63,14 @@ <script src="/static/js/match_timing.js"></script> <script src="/static/js/scoring_panel.js"></script> {{end}} -{{define "gridRow"}} -<div class="grid-row"> - {{range $i, $validStates := .validNodeStates}} - {{template "gridNode" dict "rowIndex" $.rowIndex "nodeIndex" $i "validStates" $validStates}} - {{end}} +{{define "stageSide"}} +<div class="stage-side-col"> + <div id="stageSide{{.index}}Team1" class="team-1 boolean" onclick="handleClick('onStage', 1, {{.index}});"></div> + <div id="stageSide{{.index}}Team2" class="team-2 boolean" onclick="handleClick('onStage', 2, {{.index}});"></div> + <div id="stageSide{{.index}}Team3" class="team-3 boolean" onclick="handleClick('onStage', 3, {{.index}});"></div> </div> -{{end}} -{{define "gridNode"}} -<div class="grid-node" data-node="{{.nodeIndex}}"> - <div id="gridAutoScoringRow{{$.rowIndex}}Node{{$.nodeIndex}}" class="grid-node-auto" - onclick="handleClick('gridAutoScoring', 0, {{$.rowIndex}}, {{$.nodeIndex}})"> - Auto - </div> - <div id="gridNodeStatesRow{{$.rowIndex}}Node{{$.nodeIndex}}" class="grid-node-states"> - {{range $i, $state := .validStates}} - {{if ne $state "Empty"}} - {{template "gridNodeButton" dict "i" $i "state" $state "rowIndex" $.rowIndex "nodeIndex" $.nodeIndex}} - {{end}} - {{end}} - </div> -</div> -{{end}} -{{define "gridNodeButton"}} -<div class="grid-node-button" data-node-state="{{nodeStateToInt .i}}" - onclick="handleClick('gridNode', 0, {{.rowIndex}}, {{.nodeIndex}}, {{nodeStateToInt .i}})"> - <img src="/static/img/node_states/{{.state}}.svg" /> +<div class="stage-side-col"> + <div id="stageSide{{.index}}Microphone" class="boolean" onclick="handleClick('microphone', 0, {{.index}});">Mic</div> + <div id="stageSide{{.index}}Trap" class="boolean" onclick="handleClick('trap', 0, {{.index}});">Trap</div> </div> {{end}} diff --git a/web/scoring_panel.go b/web/scoring_panel.go index ca8136f1..c0f9e86d 100644 --- a/web/scoring_panel.go +++ b/web/scoring_panel.go @@ -8,8 +8,10 @@ package web import ( "fmt" "github.com/Team254/cheesy-arena/field" + "github.com/Team254/cheesy-arena/game" "github.com/Team254/cheesy-arena/model" "github.com/Team254/cheesy-arena/websocket" + "github.com/mitchellh/mapstructure" "io" "log" "net/http" @@ -56,13 +58,12 @@ func (web *Web) scoringPanelWebsocketHandler(w http.ResponseWriter, r *http.Requ return } - // TODO(pat): Update for 2024. - //var realtimeScore **field.RealtimeScore - //if alliance == "red" { - // realtimeScore = &web.arena.RedRealtimeScore - //} else { - // realtimeScore = &web.arena.BlueRealtimeScore - //} + var realtimeScore **field.RealtimeScore + if alliance == "red" { + realtimeScore = &web.arena.RedRealtimeScore + } else { + realtimeScore = &web.arena.BlueRealtimeScore + } ws, err := websocket.NewWebsocket(w, r) if err != nil { @@ -81,9 +82,7 @@ func (web *Web) scoringPanelWebsocketHandler(w http.ResponseWriter, r *http.Requ // Loop, waiting for commands and responding to them, until the client closes the connection. for { - // TODO(pat): Update for 2024. - //command, data, err := ws.Read() - command, _, err := ws.Read() + command, data, err := ws.Read() if err != nil { if err == io.EOF { // Client has closed the connection; nothing to do here. @@ -92,8 +91,7 @@ func (web *Web) scoringPanelWebsocketHandler(w http.ResponseWriter, r *http.Requ log.Println(err) return } - // TODO(pat): Update for 2024. - //score := &(*realtimeScore).CurrentScore + score := &(*realtimeScore).CurrentScore scoreChanged := false if command == "commitMatch" { @@ -105,67 +103,52 @@ func (web *Web) scoringPanelWebsocketHandler(w http.ResponseWriter, r *http.Requ web.arena.ScoringPanelRegistry.SetScoreCommitted(alliance, ws) web.arena.ScoringStatusNotifier.Notify() } else { - // TODO(pat): Update for 2024. - //args := struct { - // TeamPosition int - // GridRow int - // GridNode int - // NodeState game.NodeState - //}{} - //err = mapstructure.Decode(data, &args) - //if err != nil { - // ws.WriteError(err.Error()) - // continue - //} - // - //switch command { - //case "mobilityStatus": - // if args.TeamPosition >= 1 && args.TeamPosition <= 3 { - // score.LeaveStatuses[args.TeamPosition-1] = !score.LeaveStatuses[args.TeamPosition-1] - // scoreChanged = true - // } - //case "autoDockStatus": - // if args.TeamPosition >= 1 && args.TeamPosition <= 3 { - // score.AutoDockStatuses[args.TeamPosition-1] = !score.AutoDockStatuses[args.TeamPosition-1] - // scoreChanged = true - // } - //case "endgameStatus": - // if args.TeamPosition >= 1 && args.TeamPosition <= 3 { - // score.EndgameStatuses[args.TeamPosition-1]++ - // if score.EndgameStatuses[args.TeamPosition-1] > 2 { - // score.EndgameStatuses[args.TeamPosition-1] = 0 - // } - // scoreChanged = true - // } - //case "autoChargeStationLevel": - // score.AutoChargeStationLevel = !score.AutoChargeStationLevel - // scoreChanged = true - //case "endgameChargeStationLevel": - // score.EndgameChargeStationLevel = !score.EndgameChargeStationLevel - // scoreChanged = true - //case "gridAutoScoring": - // if args.GridRow >= 0 && args.GridRow <= 2 && args.GridNode >= 0 && args.GridNode <= 8 { - // score.Grid.AutoScoring[args.GridRow][args.GridNode] = - // !score.Grid.AutoScoring[args.GridRow][args.GridNode] - // scoreChanged = true - // } - //case "gridNode": - // if args.GridRow >= 0 && args.GridRow <= 2 && args.GridNode >= 0 && args.GridNode <= 8 { - // currentState := score.Grid.Nodes[args.GridRow][args.GridNode] - // if currentState == args.NodeState { - // score.Grid.Nodes[args.GridRow][args.GridNode] = game.Empty - // if web.arena.MatchState == field.AutoPeriod || web.arena.MatchState == field.PausePeriod { - // score.Grid.AutoScoring[args.GridRow][args.GridNode] = false - // } - // } else { - // score.Grid.Nodes[args.GridRow][args.GridNode] = args.NodeState - // if web.arena.MatchState == field.AutoPeriod || web.arena.MatchState == field.PausePeriod { - // score.Grid.AutoScoring[args.GridRow][args.GridNode] = true - // } - // } - // scoreChanged = true - // } - //} + args := struct { + TeamPosition int + StageIndex int + }{} + err = mapstructure.Decode(data, &args) + if err != nil { + ws.WriteError(err.Error()) + continue + } + + switch command { + case "leave": + if args.TeamPosition >= 1 && args.TeamPosition <= 3 { + score.LeaveStatuses[args.TeamPosition-1] = !score.LeaveStatuses[args.TeamPosition-1] + scoreChanged = true + } + case "onStage": + if args.TeamPosition >= 1 && args.TeamPosition <= 3 && args.StageIndex >= 0 && args.StageIndex <= 2 { + endgameStatus := game.EndgameStatus(args.StageIndex + 2) + if score.EndgameStatuses[args.TeamPosition-1] == endgameStatus { + score.EndgameStatuses[args.TeamPosition-1] = game.EndgameNone + } else { + score.EndgameStatuses[args.TeamPosition-1] = endgameStatus + } + scoreChanged = true + } + case "park": + if args.TeamPosition >= 1 && args.TeamPosition <= 3 { + if score.EndgameStatuses[args.TeamPosition-1] == game.EndgameParked { + score.EndgameStatuses[args.TeamPosition-1] = game.EndgameNone + } else { + score.EndgameStatuses[args.TeamPosition-1] = game.EndgameParked + } + scoreChanged = true + } + case "microphone": + if args.StageIndex >= 0 && args.StageIndex <= 2 { + score.MicrophoneStatuses[args.StageIndex] = !score.MicrophoneStatuses[args.StageIndex] + scoreChanged = true + } + case "trap": + if args.StageIndex >= 0 && args.StageIndex <= 2 { + score.TrapStatuses[args.StageIndex] = !score.TrapStatuses[args.StageIndex] + scoreChanged = true + } + } if scoreChanged { web.arena.RealtimeScoreNotifier.Notify() diff --git a/web/scoring_panel_test.go b/web/scoring_panel_test.go index 83c320ae..ea4fa426 100644 --- a/web/scoring_panel_test.go +++ b/web/scoring_panel_test.go @@ -5,6 +5,7 @@ package web import ( "github.com/Team254/cheesy-arena/field" + "github.com/Team254/cheesy-arena/game" "github.com/Team254/cheesy-arena/websocket" gorillawebsocket "github.com/gorilla/websocket" "github.com/stretchr/testify/assert" @@ -18,12 +19,11 @@ func TestScoringPanel(t *testing.T) { recorder := web.getHttpResponse("/panels/scoring/invalidalliance") assert.Equal(t, 500, recorder.Code) assert.Contains(t, recorder.Body.String(), "Invalid alliance") - // TODO(pat): Update for 2024. - //recorder = web.getHttpResponse("/panels/scoring/red") - //assert.Equal(t, 200, recorder.Code) - //recorder = web.getHttpResponse("/panels/scoring/blue") - //assert.Equal(t, 200, recorder.Code) - //assert.Contains(t, recorder.Body.String(), "Scoring Panel - Untitled Event - Cheesy Arena") + recorder = web.getHttpResponse("/panels/scoring/red") + assert.Equal(t, 200, recorder.Code) + recorder = web.getHttpResponse("/panels/scoring/blue") + assert.Equal(t, 200, recorder.Code) + assert.Contains(t, recorder.Body.String(), "Scoring Panel - Untitled Event - Cheesy Arena") } func TestScoringPanelWebsocket(t *testing.T) { @@ -55,63 +55,90 @@ func TestScoringPanelWebsocket(t *testing.T) { readWebsocketType(t, blueWs, "realtimeScore") // Send some autonomous period scoring commands. - // TODO(pat): Update for 2024. - //assert.Equal(t, [3]bool{false, false, false}, web.arena.RedRealtimeScore.CurrentScore.LeaveStatuses) - //scoringData := struct { - // TeamPosition int - // GridRow int - // GridNode int - // NodeState game.NodeState - //}{} - //web.arena.MatchState = field.AutoPeriod - //scoringData.TeamPosition = 1 - //redWs.Write("mobilityStatus", scoringData) - //scoringData.TeamPosition = 3 - //redWs.Write("mobilityStatus", scoringData) - //scoringData.TeamPosition = 2 - //redWs.Write("autoDockStatus", scoringData) - //redWs.Write("autoChargeStationLevel", scoringData) - //scoringData.GridRow = 2 - //scoringData.GridNode = 7 - //scoringData.NodeState = game.ConeThenCube - //redWs.Write("gridNode", scoringData) - //for i := 0; i < 5; i++ { - // readWebsocketType(t, redWs, "realtimeScore") - // readWebsocketType(t, blueWs, "realtimeScore") - //} - //assert.Equal(t, [3]bool{true, false, true}, web.arena.RedRealtimeScore.CurrentScore.LeaveStatuses) - //assert.Equal(t, [3]bool{false, true, false}, web.arena.RedRealtimeScore.CurrentScore.AutoDockStatuses) - //assert.Equal(t, true, web.arena.RedRealtimeScore.CurrentScore.AutoChargeStationLevel) - //assert.Equal(t, true, web.arena.RedRealtimeScore.CurrentScore.Grid.AutoScoring[2][7]) - //assert.Equal(t, game.ConeThenCube, web.arena.RedRealtimeScore.CurrentScore.Grid.Nodes[2][7]) - // - //// Send some teleoperated period scoring commands. - //web.arena.MatchState = field.TeleopPeriod - //scoringData.GridRow = 0 - //scoringData.GridNode = 1 - //scoringData.NodeState = game.TwoCubes - //blueWs.Write("gridNode", scoringData) - //scoringData.GridRow = 2 - //blueWs.Write("gridAutoScoring", scoringData) - //scoringData.TeamPosition = 2 - //blueWs.Write("endgameStatus", scoringData) - //scoringData.TeamPosition = 3 - //blueWs.Write("endgameStatus", scoringData) - //blueWs.Write("endgameStatus", scoringData) - //blueWs.Write("endgameChargeStationLevel", scoringData) - //for i := 0; i < 6; i++ { - // readWebsocketType(t, redWs, "realtimeScore") - // readWebsocketType(t, blueWs, "realtimeScore") - //} - //assert.Equal(t, false, web.arena.BlueRealtimeScore.CurrentScore.Grid.AutoScoring[0][1]) - //assert.Equal(t, game.TwoCubes, web.arena.BlueRealtimeScore.CurrentScore.Grid.Nodes[0][1]) - //assert.Equal(t, true, web.arena.BlueRealtimeScore.CurrentScore.Grid.AutoScoring[2][1]) - //assert.Equal( - // t, - // [3]game.EndgameStatus{game.EndgameNone, game.EndgameParked, game.EndgameDocked}, - // web.arena.BlueRealtimeScore.CurrentScore.EndgameStatuses, - //) - //assert.Equal(t, true, web.arena.BlueRealtimeScore.CurrentScore.EndgameChargeStationLevel) + assert.Equal(t, [3]bool{false, false, false}, web.arena.RedRealtimeScore.CurrentScore.LeaveStatuses) + scoringData := struct { + TeamPosition int + StageIndex int + }{} + web.arena.MatchState = field.AutoPeriod + scoringData.TeamPosition = 1 + redWs.Write("leave", scoringData) + scoringData.TeamPosition = 3 + redWs.Write("leave", scoringData) + for i := 0; i < 2; i++ { + readWebsocketType(t, redWs, "realtimeScore") + readWebsocketType(t, blueWs, "realtimeScore") + } + assert.Equal(t, [3]bool{true, false, true}, web.arena.RedRealtimeScore.CurrentScore.LeaveStatuses) + redWs.Write("leave", scoringData) + readWebsocketType(t, redWs, "realtimeScore") + readWebsocketType(t, blueWs, "realtimeScore") + assert.Equal(t, [3]bool{true, false, false}, web.arena.RedRealtimeScore.CurrentScore.LeaveStatuses) + + // Send some teleoperated period scoring commands. + web.arena.MatchState = field.TeleopPeriod + scoringData.TeamPosition = 1 + scoringData.StageIndex = 0 + blueWs.Write("onStage", scoringData) + scoringData.TeamPosition = 2 + scoringData.StageIndex = 1 + blueWs.Write("onStage", scoringData) + scoringData.TeamPosition = 3 + scoringData.StageIndex = 2 + redWs.Write("onStage", scoringData) + redWs.Write("microphone", scoringData) + scoringData.StageIndex = 0 + redWs.Write("trap", scoringData) + for i := 0; i < 5; i++ { + readWebsocketType(t, redWs, "realtimeScore") + readWebsocketType(t, blueWs, "realtimeScore") + } + assert.Equal( + t, + [3]game.EndgameStatus{game.EndgameStageLeft, game.EndgameCenterStage, game.EndgameNone}, + web.arena.BlueRealtimeScore.CurrentScore.EndgameStatuses, + ) + assert.Equal(t, [3]bool{false, false, false}, web.arena.BlueRealtimeScore.CurrentScore.MicrophoneStatuses) + assert.Equal(t, [3]bool{false, false, false}, web.arena.BlueRealtimeScore.CurrentScore.TrapStatuses) + assert.Equal( + t, + [3]game.EndgameStatus{game.EndgameNone, game.EndgameNone, game.EndgameStageRight}, + web.arena.RedRealtimeScore.CurrentScore.EndgameStatuses, + ) + assert.Equal(t, [3]bool{false, false, true}, web.arena.RedRealtimeScore.CurrentScore.MicrophoneStatuses) + assert.Equal(t, [3]bool{true, false, false}, web.arena.RedRealtimeScore.CurrentScore.TrapStatuses) + scoringData.StageIndex = 1 + redWs.Write("trap", scoringData) + scoringData.StageIndex = 0 + redWs.Write("trap", scoringData) + scoringData.StageIndex = 2 + redWs.Write("microphone", scoringData) + scoringData.TeamPosition = 1 + blueWs.Write("park", scoringData) + scoringData.TeamPosition = 2 + scoringData.StageIndex = 1 + blueWs.Write("onStage", scoringData) + for i := 0; i < 5; i++ { + readWebsocketType(t, redWs, "realtimeScore") + readWebsocketType(t, blueWs, "realtimeScore") + } + assert.Equal( + t, + [3]game.EndgameStatus{game.EndgameParked, game.EndgameNone, game.EndgameNone}, + web.arena.BlueRealtimeScore.CurrentScore.EndgameStatuses, + ) + assert.Equal(t, [3]bool{false, false, false}, web.arena.RedRealtimeScore.CurrentScore.MicrophoneStatuses) + assert.Equal(t, [3]bool{false, true, false}, web.arena.RedRealtimeScore.CurrentScore.TrapStatuses) + + // Test that some invalid commands do nothing and don't result in score change notifications. + redWs.Write("invalid", nil) + scoringData.TeamPosition = 0 + redWs.Write("leave", scoringData) + scoringData.TeamPosition = 4 + redWs.Write("onStage", scoringData) + scoringData.TeamPosition = 1 + scoringData.StageIndex = 3 + blueWs.Write("onStage", scoringData) // Test committing logic. redWs.Write("commitMatch", nil)