From d7f020ccf41e50bcee44a0ca9307cf1c67e9a6b0 Mon Sep 17 00:00:00 2001
From: Will Stuckey
Date: Wed, 2 Sep 2026 23:16:12 -0400
Subject: [PATCH 01/23] initial go work
---
.gitignore | 1 +
flake.nix | 17 ++
gui/cmd/ssl-vision-processor-gui/main.go | 75 +++++++++
gui/go.mod | 11 ++
gui/go.sum | 10 ++
gui/internal/logging/logging.go | 192 +++++++++++++++++++++++
gui/internal/logging/logging_test.go | 71 +++++++++
7 files changed, 377 insertions(+)
create mode 100644 gui/cmd/ssl-vision-processor-gui/main.go
create mode 100644 gui/go.mod
create mode 100644 gui/go.sum
create mode 100644 gui/internal/logging/logging.go
create mode 100644 gui/internal/logging/logging_test.go
diff --git a/.gitignore b/.gitignore
index de4914a..add702a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,6 +12,7 @@ __pycache__
# Debug and test image directories
/img
/test-data
+*.log
#Output binaries
vision_processor
diff --git a/flake.nix b/flake.nix
index 878abcf..18a6eae 100644
--- a/flake.nix
+++ b/flake.nix
@@ -37,6 +37,13 @@
cmake
pkg-config
protobuf # provides protoc for both C++ and Python codegen
+
+ # gui/ toolchain. The Go host and its Svelte frontend are built
+ # here rather than in a second flake so that one `nix develop`
+ # covers every language in the repo.
+ go
+ buf # protobuf codegen for Go and TypeScript at once
+ nodejs_22 # frontend build; .github/workflows/ci.yml pins 22
];
buildInputs = with pkgs; [
@@ -72,12 +79,22 @@
UV_PYTHON = python.interpreter;
UV_PYTHON_DOWNLOADS = "never";
+ # The other league Go tools carry a `toolchain` line newer than the
+ # `go` directive (ssl-vision-client: go 1.25.0, toolchain go1.27.1).
+ # Left to itself Go would fetch that toolchain over the network,
+ # silently ignoring the pin above and breaking sandboxed builds.
+ # "local" turns the mismatch into an error at the point it happens.
+ GOTOOLCHAIN = "local";
+
shellHook = ''
echo "vision_processor dev shell"
echo " eigen ${pkgs.eigen.version}"
echo " opencv ${pkgs.opencv.version}"
echo " ffmpeg ${pkgs.ffmpeg_8.version}"
echo " protobuf ${pkgs.protobuf.version}"
+ echo " go ${pkgs.go.version}"
+ echo " node ${pkgs.nodejs_22.version}"
+ echo " buf ${pkgs.buf.version}"
echo
echo " cmake -B build . && make -C build -j vision_processor"
echo
diff --git a/gui/cmd/ssl-vision-processor-gui/main.go b/gui/cmd/ssl-vision-processor-gui/main.go
new file mode 100644
index 0000000..dd8aa31
--- /dev/null
+++ b/gui/cmd/ssl-vision-processor-gui/main.go
@@ -0,0 +1,75 @@
+package main
+
+import (
+ "context"
+ "flag"
+ "log/slog"
+ "os"
+ "os/signal"
+ "strings"
+ "syscall"
+
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/logging"
+)
+
+var address = flag.String("address", ":8085", "The address on which the vision processor GUI and API are served, default: :8085")
+var visionAddress = flag.String("visionAddress", "224.5.23.2:10006", "The multicast address of field vision, default: 224.5.23.2:10006")
+var skipInterfaces = flag.String("skipInterfaces", "", "Comma separated list of interface names to ignore when receiving multicast packets")
+var logLevelFlag = flag.String("logLevel", "Info", "Log Level: Debug, Info, Warn, Error. Default: Info")
+var logFile = flag.String("logFile", "logs/vision-processor-gui.log", "Rotating log file to write alongside stderr, empty to disable. Default: logs/vision-processor-gui.log")
+
+func main() {
+ flag.Parse()
+
+ // Parsed before Setup so that the level is known when the handler is built,
+ // but reported after it, so the warning goes through the same handler as
+ // everything else.
+ level, levelErr := logging.ParseLevel(*logLevelFlag)
+
+ closeLog, logErr := logging.Setup(logging.Config{
+ Level: level,
+ File: *logFile,
+ })
+ defer closeLog()
+
+ if levelErr != nil {
+ slog.Warn("falling back to info level", "err", levelErr)
+ }
+
+ if logErr != nil {
+ slog.Warn("file logging disabled", "err", logErr)
+ }
+
+ slog.Info("Init VP GUI")
+
+ // register Ctrl+C handler
+ ctx, stopSignals := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
+ defer stopSignals()
+
+ slog.Info("UI is available", "url", formattedAddress())
+
+ <-ctx.Done()
+
+ // Restore default signal handling: while shutdown is in progress a second
+ // Ctrl-C should kill the process outright rather than being swallowed.
+ stopSignals()
+
+ slog.Info("shutting down")
+
+ // Cleanup of the HTTP server, receivers and bus clients goes here, bounded
+ // by its own context so a wedged component cannot hang the process:
+ //
+ // shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ // defer cancel()
+ // httpServer.Shutdown(shutdownCtx)
+
+ slog.Info("shutdown complete")
+}
+
+func formattedAddress() string {
+ if strings.HasPrefix(*address, ":") {
+ return "http://localhost" + *address
+ }
+
+ return "http://" + *address
+}
diff --git a/gui/go.mod b/gui/go.mod
new file mode 100644
index 0000000..150696c
--- /dev/null
+++ b/gui/go.mod
@@ -0,0 +1,11 @@
+module github.com/RoboCup-SSL/ssl-vision-processor/gui
+
+go 1.26.7
+
+require (
+ github.com/RoboCup-SSL/ssl-go-tools v1.12.0 // indirect
+ github.com/gorilla/websocket v1.5.3 // indirect
+ github.com/lmittmann/tint v1.2.0 // indirect
+ google.golang.org/protobuf v1.36.12 // indirect
+ gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
+)
diff --git a/gui/go.sum b/gui/go.sum
new file mode 100644
index 0000000..7915b85
--- /dev/null
+++ b/gui/go.sum
@@ -0,0 +1,10 @@
+github.com/RoboCup-SSL/ssl-go-tools v1.12.0 h1:sXN+VSlMSOtNdLD0MPCaig3vSlj3ZTz/KIi9uJR/dy0=
+github.com/RoboCup-SSL/ssl-go-tools v1.12.0/go.mod h1:Gqrqs0LAcXmCQD3Z+IPXxrqxS9xc9sWJolYQyi3AHbw=
+github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/lmittmann/tint v1.2.0 h1:AogHRHy8HUJUnNJBHJlYa+fR4YY8mko2cnCp67xn9JY=
+github.com/lmittmann/tint v1.2.0/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
+google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
+google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
+gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
+gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
diff --git a/gui/internal/logging/logging.go b/gui/internal/logging/logging.go
new file mode 100644
index 0000000..ba5fade
--- /dev/null
+++ b/gui/internal/logging/logging.go
@@ -0,0 +1,192 @@
+// Package logging configures the process wide slog handler: a condensed,
+// coloured console for whoever is watching the terminal, and a full fidelity
+// rotating file for reading after a match.
+package logging
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "log/slog"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/lmittmann/tint"
+ "gopkg.in/natefinch/lumberjack.v2"
+)
+
+const (
+ defaultMaxSizeMB = 50
+ defaultMaxBackups = 5
+ defaultMaxAgeDays = 14
+)
+
+// logLevel is package level so that an API handler can raise the level at
+// runtime through SetLevel. LevelVar is safe for concurrent use; a plain
+// slog.Level is not.
+var logLevel slog.LevelVar
+
+// Config describes one process's logging. The zero value logs at info level to
+// stderr only.
+type Config struct {
+ Level slog.Level
+
+ // File is the rotating log file to write alongside stderr. Empty disables
+ // file logging entirely.
+ File string
+
+ MaxSizeMB int
+ MaxBackups int
+ MaxAgeDays int
+}
+
+// SetLevel changes the level of every handler installed by Setup. Safe to call
+// from any goroutine, which is what makes a runtime log level endpoint possible.
+func SetLevel(level slog.Level) {
+ logLevel.Set(level)
+}
+
+// Level reports the level currently in effect.
+func Level() slog.Level {
+ return logLevel.Level()
+}
+
+// ParseLevel maps a flag value onto a slog.Level, case insensitively. An
+// unrecognised value yields slog.LevelInfo along with an error, so a caller can
+// carry on logging and still report the typo.
+func ParseLevel(name string) (slog.Level, error) {
+ switch strings.ToLower(strings.TrimSpace(name)) {
+ case "debug":
+ return slog.LevelDebug, nil
+ case "info", "":
+ return slog.LevelInfo, nil
+ case "warn":
+ return slog.LevelWarn, nil
+ case "error":
+ return slog.LevelError, nil
+ default:
+ return slog.LevelInfo, fmt.Errorf("unknown log level %q", name)
+ }
+}
+
+// Setup installs the process wide slog handler and returns a function that
+// flushes and closes the log file.
+//
+// The handler is installed whether or not the log file could be opened, so a
+// non-nil error means "file logging is off", not "logging is unusable" -- losing
+// the file must not stop the GUI from starting at a venue. Callers should warn
+// and carry on.
+//
+// slog.SetDefault also routes the standard log package through this handler, so
+// log.Printf calls made after this point come out structured too.
+func Setup(cfg Config) (func(), error) {
+ logLevel.Set(cfg.Level)
+
+ handlers := []slog.Handler{
+ tint.NewHandler(os.Stderr, &tint.Options{
+ Level: &logLevel,
+ AddSource: true,
+ TimeFormat: "15:04:05.000",
+ NoColor: !colorSupported(os.Stderr),
+ }),
+ }
+ closeLog := func() {}
+ var setupErr error
+
+ if cfg.File != "" {
+ // lumberjack creates the file but not its parent directories.
+ if err := os.MkdirAll(filepath.Dir(cfg.File), 0o755); err != nil {
+ setupErr = fmt.Errorf("create log directory for %v: %w", cfg.File, err)
+ } else {
+ rotator := &lumberjack.Logger{
+ Filename: cfg.File,
+ MaxSize: orDefault(cfg.MaxSizeMB, defaultMaxSizeMB), // megabytes per file
+ MaxBackups: orDefault(cfg.MaxBackups, defaultMaxBackups),
+ MaxAge: orDefault(cfg.MaxAgeDays, defaultMaxAgeDays), // days
+ Compress: false,
+ }
+ handlers = append(handlers, slog.NewTextHandler(rotator, &slog.HandlerOptions{
+ Level: &logLevel,
+ AddSource: true,
+ }))
+ closeLog = func() {
+ if err := rotator.Close(); err != nil {
+ slog.Error("closing log file", "err", err)
+ }
+ }
+ }
+ }
+
+ slog.SetDefault(slog.New(multiHandler(handlers)))
+
+ return closeLog, setupErr
+}
+
+func orDefault(value, fallback int) int {
+ if value == 0 {
+ return fallback
+ }
+
+ return value
+}
+
+// colorSupported reports whether ANSI colour should be emitted to f. A pipe or
+// a redirect to a file is not a terminal, and NO_COLOR is the cross-tool
+// convention for turning colour off on one that is.
+func colorSupported(f *os.File) bool {
+ if _, set := os.LookupEnv("NO_COLOR"); set {
+ return false
+ }
+
+ stat, err := f.Stat()
+
+ return err == nil && stat.Mode()&os.ModeCharDevice != 0
+}
+
+// multiHandler fans one record out to several handlers. io.MultiWriter cannot
+// do this job because both destinations would then share one format.
+type multiHandler []slog.Handler
+
+func (m multiHandler) Enabled(ctx context.Context, level slog.Level) bool {
+ for _, h := range m {
+ if h.Enabled(ctx, level) {
+ return true
+ }
+ }
+
+ return false
+}
+
+func (m multiHandler) Handle(ctx context.Context, record slog.Record) error {
+ var errs error
+ for _, h := range m {
+ if !h.Enabled(ctx, record.Level) {
+ continue
+ }
+
+ if err := h.Handle(ctx, record.Clone()); err != nil {
+ errs = errors.Join(errs, err)
+ }
+ }
+
+ return errs
+}
+
+func (m multiHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
+ out := make(multiHandler, len(m))
+ for i, h := range m {
+ out[i] = h.WithAttrs(attrs)
+ }
+
+ return out
+}
+
+func (m multiHandler) WithGroup(name string) slog.Handler {
+ out := make(multiHandler, len(m))
+ for i, h := range m {
+ out[i] = h.WithGroup(name)
+ }
+
+ return out
+}
diff --git a/gui/internal/logging/logging_test.go b/gui/internal/logging/logging_test.go
new file mode 100644
index 0000000..e119bcb
--- /dev/null
+++ b/gui/internal/logging/logging_test.go
@@ -0,0 +1,71 @@
+package logging
+
+import (
+ "bytes"
+ "log/slog"
+ "strings"
+ "testing"
+)
+
+func TestParseLevel(t *testing.T) {
+ cases := map[string]struct {
+ want slog.Level
+ wantErr bool
+ }{
+ "debug": {want: slog.LevelDebug},
+ "Info": {want: slog.LevelInfo},
+ " WARN ": {want: slog.LevelWarn},
+ "error": {want: slog.LevelError},
+ "": {want: slog.LevelInfo},
+ "verbose": {want: slog.LevelInfo, wantErr: true},
+ }
+
+ for name, want := range cases {
+ got, err := ParseLevel(name)
+ if got != want.want {
+ t.Errorf("ParseLevel(%q) = %v, want %v", name, got, want.want)
+ }
+
+ if (err != nil) != want.wantErr {
+ t.Errorf("ParseLevel(%q) err = %v, want error: %v", name, err, want.wantErr)
+ }
+ }
+}
+
+// The point of the fan-out is that each destination keeps its own format, which
+// is exactly what a single io.MultiWriter cannot do.
+func TestMultiHandlerKeepsPerHandlerFormat(t *testing.T) {
+ var text, json bytes.Buffer
+
+ handler := multiHandler{
+ slog.NewTextHandler(&text, nil),
+ slog.NewJSONHandler(&json, nil),
+ }
+ slog.New(handler).With("instance", "cam0").Info("announce", "camId", 3)
+
+ if !strings.Contains(text.String(), `msg=announce instance=cam0 camId=3`) {
+ t.Errorf("text handler got %q", text.String())
+ }
+
+ if !strings.Contains(json.String(), `"msg":"announce","instance":"cam0","camId":3`) {
+ t.Errorf("json handler got %q", json.String())
+ }
+}
+
+func TestMultiHandlerSkipsDisabledHandlers(t *testing.T) {
+ var debug, errorsOnly bytes.Buffer
+
+ handler := multiHandler{
+ slog.NewTextHandler(&debug, &slog.HandlerOptions{Level: slog.LevelDebug}),
+ slog.NewTextHandler(&errorsOnly, &slog.HandlerOptions{Level: slog.LevelError}),
+ }
+ slog.New(handler).Info("only the debug handler wants this")
+
+ if debug.Len() == 0 {
+ t.Error("debug handler received nothing")
+ }
+
+ if errorsOnly.Len() != 0 {
+ t.Errorf("error-only handler received %q", errorsOnly.String())
+ }
+}
From f9644f33d8611958461f29a4e18e3d02cae21c37 Mon Sep 17 00:00:00 2001
From: Will Stuckey
Date: Mon, 7 Sep 2026 20:31:20 -0400
Subject: [PATCH 02/23] svelte fe migration
---
.github/workflows/ci.yml | 6 +-
.pre-commit-config.yaml | 8 +--
README.md | 2 +-
gui/cmd/ssl-vision-processor-gui/main.go | 32 +++++++++--
gui/cmd/ssl-vision-processor-gui/routes.go | 9 +++
gui/cmd/ssl-vision-processor-gui/server.go | 30 ++++++++++
.../ssl-vision-processor-gui/server_test.go | 55 +++++++++++++++++++
{wrapper-frontend => gui/frontend}/.gitignore | 0
.../frontend}/.prettierignore | 0
.../frontend}/.prettierrc.json | 0
.../frontend}/.vscode/extensions.json | 0
{wrapper-frontend => gui/frontend}/README.md | 4 +-
.../frontend}/eslint.config.js | 0
{wrapper-frontend => gui/frontend}/index.html | 0
.../frontend}/package-lock.json | 4 +-
.../frontend}/package.json | 2 +-
.../frontend}/src/App.svelte | 0
.../frontend}/src/lib/wrapper-bus.ts | 0
.../frontend}/src/main.ts | 0
.../frontend}/svelte.config.js | 0
.../frontend}/tsconfig.app.json | 0
.../frontend}/tsconfig.json | 0
.../frontend}/tsconfig.node.json | 0
.../frontend}/vite.config.ts | 0
24 files changed, 134 insertions(+), 18 deletions(-)
create mode 100644 gui/cmd/ssl-vision-processor-gui/routes.go
create mode 100644 gui/cmd/ssl-vision-processor-gui/server.go
create mode 100644 gui/cmd/ssl-vision-processor-gui/server_test.go
rename {wrapper-frontend => gui/frontend}/.gitignore (100%)
rename {wrapper-frontend => gui/frontend}/.prettierignore (100%)
rename {wrapper-frontend => gui/frontend}/.prettierrc.json (100%)
rename {wrapper-frontend => gui/frontend}/.vscode/extensions.json (100%)
rename {wrapper-frontend => gui/frontend}/README.md (98%)
rename {wrapper-frontend => gui/frontend}/eslint.config.js (100%)
rename {wrapper-frontend => gui/frontend}/index.html (100%)
rename {wrapper-frontend => gui/frontend}/package-lock.json (99%)
rename {wrapper-frontend => gui/frontend}/package.json (95%)
rename {wrapper-frontend => gui/frontend}/src/App.svelte (100%)
rename {wrapper-frontend => gui/frontend}/src/lib/wrapper-bus.ts (100%)
rename {wrapper-frontend => gui/frontend}/src/main.ts (100%)
rename {wrapper-frontend => gui/frontend}/svelte.config.js (100%)
rename {wrapper-frontend => gui/frontend}/tsconfig.app.json (100%)
rename {wrapper-frontend => gui/frontend}/tsconfig.json (100%)
rename {wrapper-frontend => gui/frontend}/tsconfig.node.json (100%)
rename {wrapper-frontend => gui/frontend}/vite.config.ts (100%)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index cf7fedf..b044784 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -59,11 +59,11 @@ jobs:
'
frontend:
- name: Frontend (wrapper-frontend)
+ name: Frontend (gui/frontend)
runs-on: ubuntu-latest
defaults:
run:
- working-directory: wrapper-frontend
+ working-directory: gui/frontend
steps:
- uses: actions/checkout@v4
@@ -71,7 +71,7 @@ jobs:
with:
node-version: 22
cache: npm
- cache-dependency-path: wrapper-frontend/package-lock.json
+ cache-dependency-path: gui/frontend/package-lock.json
- run: npm ci
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 4e67894..8a74344 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -18,13 +18,13 @@ repos:
pass_filenames: false
- id: eslint
name: eslint
- entry: npm --prefix wrapper-frontend run lint
+ entry: npm --prefix gui/frontend run lint
language: system
- files: ^wrapper-frontend/
+ files: ^gui/frontend/
pass_filenames: false
- id: prettier
name: prettier
- entry: npm --prefix wrapper-frontend run format:check
+ entry: npm --prefix gui/frontend run format:check
language: system
- files: ^wrapper-frontend/
+ files: ^gui/frontend/
pass_filenames: false
diff --git a/README.md b/README.md
index 730d4c7..d903765 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ for all vision_processors, teams and the game controller.
A modular replacement for `geom_publisher.py` plus a browser UI:
- `wrapper_backend/` — async Python (uv-managed). Owns the field geometry, absorbs incoming calibrations, exposes the bus over WebSocket. Run with `./start_wrapper.sh` (defaults to `geometry-divB.yml`). See [`wrapper_backend/README.md`](wrapper_backend/README.md).
-- `wrapper-frontend/` — Svelte 5 + TypeScript + Vite. Connects to the backend's WebSocket and renders the operator UI. Run with `cd wrapper-frontend && npm install && npm run dev`. See [`wrapper-frontend/README.md`](wrapper-frontend/README.md).
+- `gui/frontend/` — Svelte 5 + TypeScript + Vite. Connects to the backend's WebSocket and renders the operator UI. Run with `cd gui/frontend && npm install && npm run dev`. See [`gui/frontend/README.md`](gui/frontend/README.md).
## Dependency installation and compilation
diff --git a/gui/cmd/ssl-vision-processor-gui/main.go b/gui/cmd/ssl-vision-processor-gui/main.go
index dd8aa31..0b88ba5 100644
--- a/gui/cmd/ssl-vision-processor-gui/main.go
+++ b/gui/cmd/ssl-vision-processor-gui/main.go
@@ -2,12 +2,15 @@ package main
import (
"context"
+ "errors"
"flag"
"log/slog"
+ "net/http"
"os"
"os/signal"
"strings"
"syscall"
+ "time"
"github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/logging"
)
@@ -46,6 +49,23 @@ func main() {
ctx, stopSignals := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stopSignals()
+ srv := &http.Server{
+ Addr: *address,
+ Handler: NewVisionServer(),
+ ReadHeaderTimeout: 10 * time.Second,
+ }
+
+ go func() {
+ if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
+ slog.Error("http server init failed", "err", err)
+
+ // ListenAndServer always returns, but ErrServerClosed is the graceful shutdown condition
+ // if we got anything else, the system didn't start and the process should die
+ // call stopSignals() now to cancel the context otherwise we continue to block on Ctrl+C
+ stopSignals()
+ }
+ }()
+
slog.Info("UI is available", "url", formattedAddress())
<-ctx.Done()
@@ -54,14 +74,16 @@ func main() {
// Ctrl-C should kill the process outright rather than being swallowed.
stopSignals()
- slog.Info("shutting down")
+ slog.Info("initiating graceful shutdown")
// Cleanup of the HTTP server, receivers and bus clients goes here, bounded
// by its own context so a wedged component cannot hang the process:
- //
- // shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
- // defer cancel()
- // httpServer.Shutdown(shutdownCtx)
+ shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+
+ if err := srv.Shutdown(shutdownCtx); err != nil {
+ slog.Error("http server failed to close gracefully", "err", err)
+ }
slog.Info("shutdown complete")
}
diff --git a/gui/cmd/ssl-vision-processor-gui/routes.go b/gui/cmd/ssl-vision-processor-gui/routes.go
new file mode 100644
index 0000000..95b237f
--- /dev/null
+++ b/gui/cmd/ssl-vision-processor-gui/routes.go
@@ -0,0 +1,9 @@
+package main
+
+import (
+ "net/http"
+)
+
+func (s *VisionServer) addRoutes(mux *http.ServeMux) {
+ mux.Handle("GET /api/health", s.handleHealth())
+}
\ No newline at end of file
diff --git a/gui/cmd/ssl-vision-processor-gui/server.go b/gui/cmd/ssl-vision-processor-gui/server.go
new file mode 100644
index 0000000..c6e88cb
--- /dev/null
+++ b/gui/cmd/ssl-vision-processor-gui/server.go
@@ -0,0 +1,30 @@
+package main
+
+import (
+ "encoding/json"
+ "log/slog"
+ "net/http"
+)
+
+type VisionServer struct {
+
+}
+
+func NewVisionServer() http.Handler {
+ s := &VisionServer{}
+
+ mux := http.NewServeMux()
+ s.addRoutes(mux)
+
+ return mux
+}
+
+func (s *VisionServer) handleHealth() http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+
+ if err := json.NewEncoder(w).Encode(map[string]string{"status": "ok"}); err != nil {
+ slog.Error("writing health response", "err", err)
+ }
+ }
+}
\ No newline at end of file
diff --git a/gui/cmd/ssl-vision-processor-gui/server_test.go b/gui/cmd/ssl-vision-processor-gui/server_test.go
new file mode 100644
index 0000000..c41b14f
--- /dev/null
+++ b/gui/cmd/ssl-vision-processor-gui/server_test.go
@@ -0,0 +1,55 @@
+package main
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "testing"
+)
+
+func TestHealthReturnsOK(t *testing.T) {
+ req := httptest.NewRequest(http.MethodGet, "/api/health", nil)
+ rec := httptest.NewRecorder()
+
+ NewVisionServer().ServeHTTP(rec, req)
+
+ if rec.Code != http.StatusOK {
+ t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
+ }
+
+ if got := rec.Header().Get("Content-Type"); got != "application/json" {
+ t.Errorf("Content-Type = %q, want application/json", got)
+ }
+
+ // json.Encoder.Encode terminates every value with a newline.
+ if got, want := rec.Body.String(), "{\"status\":\"ok\"}\n"; got != want {
+ t.Errorf("body = %q, want %q", got, want)
+ }
+}
+
+// The method prefix in the route pattern is what produces this, so it breaks if
+// someone registers the route without one.
+func TestHealthRejectsNonGET(t *testing.T) {
+ for _, method := range []string{http.MethodPost, http.MethodPut, http.MethodDelete} {
+ req := httptest.NewRequest(method, "/api/health", nil)
+ rec := httptest.NewRecorder()
+
+ NewVisionServer().ServeHTTP(rec, req)
+
+ if rec.Code != http.StatusMethodNotAllowed {
+ t.Errorf("%s /api/health = %d, want %d", method, rec.Code, http.StatusMethodNotAllowed)
+ }
+ }
+}
+
+// Until the frontend is embedded there is no catch-all route, so an unknown
+// path must 404 rather than being swallowed by something broader.
+func TestUnknownPathReturns404(t *testing.T) {
+ req := httptest.NewRequest(http.MethodGet, "/nope", nil)
+ rec := httptest.NewRecorder()
+
+ NewVisionServer().ServeHTTP(rec, req)
+
+ if rec.Code != http.StatusNotFound {
+ t.Errorf("status = %d, want %d", rec.Code, http.StatusNotFound)
+ }
+}
diff --git a/wrapper-frontend/.gitignore b/gui/frontend/.gitignore
similarity index 100%
rename from wrapper-frontend/.gitignore
rename to gui/frontend/.gitignore
diff --git a/wrapper-frontend/.prettierignore b/gui/frontend/.prettierignore
similarity index 100%
rename from wrapper-frontend/.prettierignore
rename to gui/frontend/.prettierignore
diff --git a/wrapper-frontend/.prettierrc.json b/gui/frontend/.prettierrc.json
similarity index 100%
rename from wrapper-frontend/.prettierrc.json
rename to gui/frontend/.prettierrc.json
diff --git a/wrapper-frontend/.vscode/extensions.json b/gui/frontend/.vscode/extensions.json
similarity index 100%
rename from wrapper-frontend/.vscode/extensions.json
rename to gui/frontend/.vscode/extensions.json
diff --git a/wrapper-frontend/README.md b/gui/frontend/README.md
similarity index 98%
rename from wrapper-frontend/README.md
rename to gui/frontend/README.md
index b13513a..24efacf 100644
--- a/wrapper-frontend/README.md
+++ b/gui/frontend/README.md
@@ -1,4 +1,4 @@
-# wrapper-frontend
+# vision-processor-gui-frontend
Browser UI for the vision-processor wrapper. Svelte 5 + TypeScript + Vite.
@@ -17,7 +17,7 @@ Two terminals from the repo root:
./start_wrapper.sh
# terminal 2 (the Vite dev server, on :5173 with HMR)
-cd wrapper-frontend
+cd gui/frontend
npm install
npm run dev
```
diff --git a/wrapper-frontend/eslint.config.js b/gui/frontend/eslint.config.js
similarity index 100%
rename from wrapper-frontend/eslint.config.js
rename to gui/frontend/eslint.config.js
diff --git a/wrapper-frontend/index.html b/gui/frontend/index.html
similarity index 100%
rename from wrapper-frontend/index.html
rename to gui/frontend/index.html
diff --git a/wrapper-frontend/package-lock.json b/gui/frontend/package-lock.json
similarity index 99%
rename from wrapper-frontend/package-lock.json
rename to gui/frontend/package-lock.json
index 1d69c8b..03d6216 100644
--- a/wrapper-frontend/package-lock.json
+++ b/gui/frontend/package-lock.json
@@ -1,11 +1,11 @@
{
- "name": "wrapper-frontend",
+ "name": "vision-processor-gui-frontend",
"version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "wrapper-frontend",
+ "name": "vision-processor-gui-frontend",
"version": "0.0.0",
"devDependencies": {
"@eslint/js": "^10.0.1",
diff --git a/wrapper-frontend/package.json b/gui/frontend/package.json
similarity index 95%
rename from wrapper-frontend/package.json
rename to gui/frontend/package.json
index 34d55f5..dcd660c 100644
--- a/wrapper-frontend/package.json
+++ b/gui/frontend/package.json
@@ -1,5 +1,5 @@
{
- "name": "wrapper-frontend",
+ "name": "vision-processor-gui-frontend",
"private": true,
"version": "0.0.0",
"type": "module",
diff --git a/wrapper-frontend/src/App.svelte b/gui/frontend/src/App.svelte
similarity index 100%
rename from wrapper-frontend/src/App.svelte
rename to gui/frontend/src/App.svelte
diff --git a/wrapper-frontend/src/lib/wrapper-bus.ts b/gui/frontend/src/lib/wrapper-bus.ts
similarity index 100%
rename from wrapper-frontend/src/lib/wrapper-bus.ts
rename to gui/frontend/src/lib/wrapper-bus.ts
diff --git a/wrapper-frontend/src/main.ts b/gui/frontend/src/main.ts
similarity index 100%
rename from wrapper-frontend/src/main.ts
rename to gui/frontend/src/main.ts
diff --git a/wrapper-frontend/svelte.config.js b/gui/frontend/svelte.config.js
similarity index 100%
rename from wrapper-frontend/svelte.config.js
rename to gui/frontend/svelte.config.js
diff --git a/wrapper-frontend/tsconfig.app.json b/gui/frontend/tsconfig.app.json
similarity index 100%
rename from wrapper-frontend/tsconfig.app.json
rename to gui/frontend/tsconfig.app.json
diff --git a/wrapper-frontend/tsconfig.json b/gui/frontend/tsconfig.json
similarity index 100%
rename from wrapper-frontend/tsconfig.json
rename to gui/frontend/tsconfig.json
diff --git a/wrapper-frontend/tsconfig.node.json b/gui/frontend/tsconfig.node.json
similarity index 100%
rename from wrapper-frontend/tsconfig.node.json
rename to gui/frontend/tsconfig.node.json
diff --git a/wrapper-frontend/vite.config.ts b/gui/frontend/vite.config.ts
similarity index 100%
rename from wrapper-frontend/vite.config.ts
rename to gui/frontend/vite.config.ts
From 8f1a8797350145d07a84e00d29e322061e9a5ad3 Mon Sep 17 00:00:00 2001
From: Will Stuckey
Date: Mon, 7 Sep 2026 21:18:12 -0400
Subject: [PATCH 03/23] add SPA routes, tests, and vscode tools
---
.gitignore | 3 +
.vscode/extensions.json | 13 +++++
.vscode/settings.json | 22 +++++++
gui/Makefile | 42 ++++++++++++++
gui/cmd/ssl-vision-processor-gui/routes.go | 3 +
gui/frontend/.gitignore | 6 +-
gui/frontend/.vscode/extensions.json | 3 -
gui/frontend/embed.go | 40 +++++++++++++
gui/frontend/embed_test.go | 67 ++++++++++++++++++++++
9 files changed, 195 insertions(+), 4 deletions(-)
create mode 100644 .vscode/extensions.json
create mode 100644 .vscode/settings.json
create mode 100644 gui/Makefile
delete mode 100644 gui/frontend/.vscode/extensions.json
create mode 100644 gui/frontend/embed.go
create mode 100644 gui/frontend/embed_test.go
diff --git a/.gitignore b/.gitignore
index add702a..ec838e8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,9 @@ vision_processor
blob_benchmark
geometry_benchmark
+# Makefile sentinel for the frontend build
+/gui/.frontend
+
#CMake files
/build
.cmake
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 0000000..19a0f58
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,13 @@
+{
+ "recommendations": [
+ "golang.go",
+ "svelte.svelte-vscode",
+ "esbenp.prettier-vscode",
+ "ms-vscode.cpptools",
+ "ms-vscode.cmake-tools",
+ "ms-python.python",
+ "charliermarsh.ruff",
+ "jnoortheen.nix-ide",
+ "bufbuild.vscode-buf"
+ ]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..7c4f443
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,22 @@
+{
+ "[go]": {
+ "editor.defaultFormatter": "golang.go",
+ "editor.formatOnSave": true,
+ "editor.codeActionsOnSave": {
+ "source.organizeImports": "explicit"
+ }
+ },
+ "[svelte]": {
+ "editor.defaultFormatter": "svelte.svelte-vscode",
+ "editor.formatOnSave": true
+ },
+ "[typescript]": {
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "editor.formatOnSave": true
+ },
+ "[javascript]": {
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "editor.formatOnSave": true
+ },
+ "go.vetOnSave": "package"
+}
diff --git a/gui/Makefile b/gui/Makefile
new file mode 100644
index 0000000..72ef5a9
--- /dev/null
+++ b/gui/Makefile
@@ -0,0 +1,42 @@
+BINARY = ssl-vision-processor-gui
+
+# ./... would also descend into frontend/node_modules, where npm packages ship
+# stray Go source (flatted/golang, for one). Enumerate our own trees instead.
+GO_PACKAGES = ./cmd/... ./internal/...
+
+FRONTEND_SOURCES = $(shell find frontend -type f \
+ -not -path "frontend/node_modules/*" \
+ -not -path "frontend/dist/*")
+
+.PHONY: all frontend install test run proto clean
+
+all: install
+
+# Sentinel file, so npm reruns only when a frontend source is newer than the
+# last build. //go:embed resolves at compile time, which is why every Go target
+# below depends on this.
+.frontend: $(FRONTEND_SOURCES)
+ cd frontend && npm ci && npm run build
+ touch .frontend
+
+frontend: .frontend
+
+install: frontend
+ go install -v $(GO_PACKAGES)
+
+test: frontend
+ cd frontend && npm run check && npm run lint && npm run format:check
+ go test $(GO_PACKAGES)
+
+run: frontend
+ go run ./cmd/$(BINARY)
+
+# Regenerates Go and TypeScript protobuf bindings. Needs network access for
+# buf's remote plugins, so it never runs as part of a build.
+proto:
+ buf generate
+
+clean:
+ rm -rf frontend/dist .frontend
+ mkdir -p frontend/dist
+ touch frontend/dist/.gitkeep
diff --git a/gui/cmd/ssl-vision-processor-gui/routes.go b/gui/cmd/ssl-vision-processor-gui/routes.go
index 95b237f..650beb3 100644
--- a/gui/cmd/ssl-vision-processor-gui/routes.go
+++ b/gui/cmd/ssl-vision-processor-gui/routes.go
@@ -2,8 +2,11 @@ package main
import (
"net/http"
+
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/frontend"
)
func (s *VisionServer) addRoutes(mux *http.ServeMux) {
mux.Handle("GET /api/health", s.handleHealth())
+ mux.Handle("/", frontend.HandleFrontend())
}
\ No newline at end of file
diff --git a/gui/frontend/.gitignore b/gui/frontend/.gitignore
index a547bf3..63f51d6 100644
--- a/gui/frontend/.gitignore
+++ b/gui/frontend/.gitignore
@@ -8,7 +8,11 @@ pnpm-debug.log*
lerna-debug.log*
node_modules
-dist
+# dist is a build artefact, but the directory itself must exist: //go:embed
+# fails at compile time when it is missing, which would break `go test ./...`
+# on a fresh clone.
+dist/*
+!dist/.gitkeep
dist-ssr
*.local
diff --git a/gui/frontend/.vscode/extensions.json b/gui/frontend/.vscode/extensions.json
deleted file mode 100644
index bdef820..0000000
--- a/gui/frontend/.vscode/extensions.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "recommendations": ["svelte.svelte-vscode"]
-}
diff --git a/gui/frontend/embed.go b/gui/frontend/embed.go
new file mode 100644
index 0000000..612e39c
--- /dev/null
+++ b/gui/frontend/embed.go
@@ -0,0 +1,40 @@
+package frontend
+
+import (
+ "embed"
+ "errors"
+ "io/fs"
+ "log/slog"
+ "net/http"
+ "path"
+ "strings"
+)
+
+//go:embed all:dist
+var content embed.FS
+
+func HandleFrontend() http.Handler {
+ dist, err := fs.Sub(content, "dist")
+ if err != nil {
+ panic(err)
+ }
+
+ if _, err := fs.Stat(dist, "index.html"); err != nil {
+ slog.Warn("stat of index.html failed; frontend not built, UI will 404", "hint", "make frontend")
+ }
+
+ return serveSPA(dist, http.FileServerFS(dist))
+}
+
+func serveSPA(dist fs.FS, files http.Handler) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ name := strings.TrimPrefix(r.URL.Path, "/")
+
+ if _, err := fs.Stat(dist, name); errors.Is(err, fs.ErrNotExist) && path.Ext(name) == "" {
+ r = r.Clone(r.Context())
+ r.URL.Path = "/"
+ }
+
+ files.ServeHTTP(w, r)
+ }
+}
\ No newline at end of file
diff --git a/gui/frontend/embed_test.go b/gui/frontend/embed_test.go
new file mode 100644
index 0000000..507ef48
--- /dev/null
+++ b/gui/frontend/embed_test.go
@@ -0,0 +1,67 @@
+package frontend
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "strings"
+ "testing"
+ "testing/fstest"
+)
+
+// An in-memory stand-in for dist/, so these tests do not depend on whether
+// anyone has run `make frontend`.
+var testDist = fstest.MapFS{
+ "index.html": {Data: []byte("app")},
+ "assets/app.js": {Data: []byte("console.log(1)")},
+}
+
+func TestServeSPAStatus(t *testing.T) {
+ cases := map[string]int{
+ "/": http.StatusOK,
+ // FileServer canonicalises an explicit /index.html to ./
+ "/index.html": http.StatusMovedPermanently,
+ "/assets/app.js": http.StatusOK,
+ "/instances/cam0/calibration": http.StatusOK, // a route: falls back
+ "/assets/missing.js": http.StatusNotFound, // an asset: must 404
+ }
+
+ handler := serveSPA(testDist, http.FileServerFS(testDist))
+
+ for path, want := range cases {
+ rec := httptest.NewRecorder()
+ handler.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, path, nil))
+
+ if rec.Code != want {
+ t.Errorf("GET %s = %d, want %d", path, rec.Code, want)
+ }
+ }
+}
+
+// A 200 alone would not prove the fallback works: the body has to be the app.
+func TestServeSPAFallbackServesIndex(t *testing.T) {
+ handler := serveSPA(testDist, http.FileServerFS(testDist))
+
+ rec := httptest.NewRecorder()
+ handler.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/instances/cam0/calibration", nil))
+
+ if got := rec.Body.String(); got != "app" {
+ t.Errorf("body = %q, want the index.html contents", got)
+ }
+
+ if ct := rec.Header().Get("Content-Type"); !strings.HasPrefix(ct, "text/html") {
+ t.Errorf("Content-Type = %q, want text/html", ct)
+ }
+}
+
+// The asset guard is what keeps a stale bundle reference from being answered
+// with HTML, which surfaces in the browser as "Unexpected token '<'".
+func TestServeSPADoesNotFallBackForAssets(t *testing.T) {
+ handler := serveSPA(testDist, http.FileServerFS(testDist))
+
+ rec := httptest.NewRecorder()
+ handler.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/assets/missing.js", nil))
+
+ if strings.Contains(rec.Body.String(), "doctype") {
+ t.Errorf("missing asset answered with HTML: %q", rec.Body.String())
+ }
+}
From d409a72bd60bb4483151616143de8b05ec5aeda2 Mon Sep 17 00:00:00 2001
From: Will Stuckey
Date: Mon, 7 Sep 2026 21:34:47 -0400
Subject: [PATCH 04/23] initial proto wiring
---
gui/Makefile | 2 +-
gui/buf.gen.yaml | 36 +
gui/cmd/ssl-vision-processor-gui/routes.go | 2 +
.../ssl-vision-processor-gui/server_test.go | 37 +-
gui/frontend/.prettierignore | 4 +
gui/frontend/package-lock.json | 9 +
gui/frontend/package.json | 3 +
.../proto/gamecontroller/ssl_gc_common_pb.ts | 139 +
.../gamecontroller/ssl_gc_game_event_pb.ts | 3850 ++++++++++++++
.../gamecontroller/ssl_gc_geometry_pb.ts | 106 +
.../gamecontroller/ssl_gc_rcon_autoref_pb.ts | 157 +
.../proto/gamecontroller/ssl_gc_rcon_pb.ts | 208 +
.../ssl_gc_rcon_remotecontrol_pb.ts | 565 +++
.../gamecontroller/ssl_gc_rcon_team_pb.ts | 264 +
.../ssl_gc_referee_message_pb.ts | 1055 ++++
.../proto/vision/ssl_vision_detection_pb.ts | 403 ++
.../vision/ssl_vision_detection_tracked_pb.ts | 448 ++
.../proto/vision/ssl_vision_geometry_pb.ts | 1031 ++++
.../src/proto/vision/ssl_vision_wrapper_pb.ts | 123 +
.../vision/ssl_vision_wrapper_tracked_pb.ts | 83 +
.../src/proto/vision/ssl_vp_config_pb.ts | 951 ++++
gui/go.mod | 8 +-
gui/go.sum | 6 +-
.../gamecontroller/ssl_gc_common.pb.go | 271 +
.../gamecontroller/ssl_gc_game_event.pb.go | 4459 +++++++++++++++++
.../gamecontroller/ssl_gc_geometry.pb.go | 198 +
gui/internal/gamecontroller/ssl_gc_rcon.pb.go | 352 ++
.../gamecontroller/ssl_gc_rcon_autoref.pb.go | 283 ++
.../ssl_gc_rcon_remotecontrol.pb.go | 718 +++
.../gamecontroller/ssl_gc_rcon_team.pb.go | 442 ++
.../ssl_gc_referee_message.pb.go | 1113 ++++
.../vision/ssl_vision_detection.pb.go | 439 ++
.../vision/ssl_vision_detection_tracked.pb.go | 544 ++
gui/internal/vision/ssl_vision_geometry.pb.go | 1135 +++++
gui/internal/vision/ssl_vision_wrapper.pb.go | 238 +
.../vision/ssl_vision_wrapper_tracked.pb.go | 150 +
gui/internal/vision/ssl_vp_config.pb.go | 1230 +++++
37 files changed, 21044 insertions(+), 18 deletions(-)
create mode 100644 gui/buf.gen.yaml
create mode 100644 gui/frontend/src/proto/gamecontroller/ssl_gc_common_pb.ts
create mode 100644 gui/frontend/src/proto/gamecontroller/ssl_gc_game_event_pb.ts
create mode 100644 gui/frontend/src/proto/gamecontroller/ssl_gc_geometry_pb.ts
create mode 100644 gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_autoref_pb.ts
create mode 100644 gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_pb.ts
create mode 100644 gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_remotecontrol_pb.ts
create mode 100644 gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_team_pb.ts
create mode 100644 gui/frontend/src/proto/gamecontroller/ssl_gc_referee_message_pb.ts
create mode 100644 gui/frontend/src/proto/vision/ssl_vision_detection_pb.ts
create mode 100644 gui/frontend/src/proto/vision/ssl_vision_detection_tracked_pb.ts
create mode 100644 gui/frontend/src/proto/vision/ssl_vision_geometry_pb.ts
create mode 100644 gui/frontend/src/proto/vision/ssl_vision_wrapper_pb.ts
create mode 100644 gui/frontend/src/proto/vision/ssl_vision_wrapper_tracked_pb.ts
create mode 100644 gui/frontend/src/proto/vision/ssl_vp_config_pb.ts
create mode 100644 gui/internal/gamecontroller/ssl_gc_common.pb.go
create mode 100644 gui/internal/gamecontroller/ssl_gc_game_event.pb.go
create mode 100644 gui/internal/gamecontroller/ssl_gc_geometry.pb.go
create mode 100644 gui/internal/gamecontroller/ssl_gc_rcon.pb.go
create mode 100644 gui/internal/gamecontroller/ssl_gc_rcon_autoref.pb.go
create mode 100644 gui/internal/gamecontroller/ssl_gc_rcon_remotecontrol.pb.go
create mode 100644 gui/internal/gamecontroller/ssl_gc_rcon_team.pb.go
create mode 100644 gui/internal/gamecontroller/ssl_gc_referee_message.pb.go
create mode 100644 gui/internal/vision/ssl_vision_detection.pb.go
create mode 100644 gui/internal/vision/ssl_vision_detection_tracked.pb.go
create mode 100644 gui/internal/vision/ssl_vision_geometry.pb.go
create mode 100644 gui/internal/vision/ssl_vision_wrapper.pb.go
create mode 100644 gui/internal/vision/ssl_vision_wrapper_tracked.pb.go
create mode 100644 gui/internal/vision/ssl_vp_config.pb.go
diff --git a/gui/Makefile b/gui/Makefile
index 72ef5a9..2546dff 100644
--- a/gui/Makefile
+++ b/gui/Makefile
@@ -2,7 +2,7 @@ BINARY = ssl-vision-processor-gui
# ./... would also descend into frontend/node_modules, where npm packages ship
# stray Go source (flatted/golang, for one). Enumerate our own trees instead.
-GO_PACKAGES = ./cmd/... ./internal/...
+GO_PACKAGES = ./cmd/... ./internal/... ./frontend
FRONTEND_SOURCES = $(shell find frontend -type f \
-not -path "frontend/node_modules/*" \
diff --git a/gui/buf.gen.yaml b/gui/buf.gen.yaml
new file mode 100644
index 0000000..dac8bde
--- /dev/null
+++ b/gui/buf.gen.yaml
@@ -0,0 +1,36 @@
+version: v2
+
+# The .proto files live in the proto/ git submodule, shared with the C++ and
+# (for now) Python builds. buf reads them in place, so there is no vendored copy
+# to drift.
+inputs:
+ - directory: ../proto/proto
+ paths:
+ - ../proto/proto/vision
+ - ../proto/proto/gamecontroller
+ exclude_paths:
+ - ../proto/proto/vision/legacy
+
+# The SSL .proto files carry no go_package option, so managed mode has to supply
+# one. Combined with paths=source_relative below, proto/ generates into
+# internal/: proto/vision/*.proto -> internal/vision/*.pb.go.
+managed:
+ enabled: true
+ override:
+ - file_option: go_package_prefix
+ value: github.com/RoboCup-SSL/ssl-vision-processor/gui/internal
+
+plugins:
+ - remote: buf.build/protocolbuffers/go:v1.36.6
+ out: internal
+ opt:
+ - paths=source_relative
+
+ # json_types emits the canonical protojson shape of each message, which is
+ # what the Go side sends over the wire. 64-bit fields come out as strings
+ # there, and these types say so.
+ - remote: buf.build/bufbuild/es:v2.2.5
+ out: frontend/src/proto
+ opt:
+ - target=ts
+ - json_types=true
diff --git a/gui/cmd/ssl-vision-processor-gui/routes.go b/gui/cmd/ssl-vision-processor-gui/routes.go
index 650beb3..a393c6e 100644
--- a/gui/cmd/ssl-vision-processor-gui/routes.go
+++ b/gui/cmd/ssl-vision-processor-gui/routes.go
@@ -8,5 +8,7 @@ import (
func (s *VisionServer) addRoutes(mux *http.ServeMux) {
mux.Handle("GET /api/health", s.handleHealth())
+ mux.Handle("/api/", http.NotFoundHandler())
+
mux.Handle("/", frontend.HandleFrontend())
}
\ No newline at end of file
diff --git a/gui/cmd/ssl-vision-processor-gui/server_test.go b/gui/cmd/ssl-vision-processor-gui/server_test.go
index c41b14f..1a970c1 100644
--- a/gui/cmd/ssl-vision-processor-gui/server_test.go
+++ b/gui/cmd/ssl-vision-processor-gui/server_test.go
@@ -3,6 +3,7 @@ package main
import (
"net/http"
"net/http/httptest"
+ "strings"
"testing"
)
@@ -26,8 +27,10 @@ func TestHealthReturnsOK(t *testing.T) {
}
}
-// The method prefix in the route pattern is what produces this, so it breaks if
-// someone registers the route without one.
+// A wrong method is a 404 rather than a 405: the "/" catch-all matches every
+// method, so ServeMux never reaches its method-not-allowed path. What matters is
+// that the "/api/" subtree answers, instead of the request falling through to
+// the frontend and returning HTML with status 200.
func TestHealthRejectsNonGET(t *testing.T) {
for _, method := range []string{http.MethodPost, http.MethodPut, http.MethodDelete} {
req := httptest.NewRequest(method, "/api/health", nil)
@@ -35,16 +38,17 @@ func TestHealthRejectsNonGET(t *testing.T) {
NewVisionServer().ServeHTTP(rec, req)
- if rec.Code != http.StatusMethodNotAllowed {
- t.Errorf("%s /api/health = %d, want %d", method, rec.Code, http.StatusMethodNotAllowed)
+ if rec.Code != http.StatusNotFound {
+ t.Errorf("%s /api/health = %d, want %d", method, rec.Code, http.StatusNotFound)
}
}
}
-// Until the frontend is embedded there is no catch-all route, so an unknown
-// path must 404 rather than being swallowed by something broader.
-func TestUnknownPathReturns404(t *testing.T) {
- req := httptest.NewRequest(http.MethodGet, "/nope", nil)
+// An unrouted API path must not be answered by the SPA fallback. Returning
+// index.html here would give fetch() HTML where it expects JSON, surfacing as a
+// parse error rather than as the 404 it really is.
+func TestUnknownAPIPathReturns404(t *testing.T) {
+ req := httptest.NewRequest(http.MethodGet, "/api/does-not-exist", nil)
rec := httptest.NewRecorder()
NewVisionServer().ServeHTTP(rec, req)
@@ -52,4 +56,21 @@ func TestUnknownPathReturns404(t *testing.T) {
if rec.Code != http.StatusNotFound {
t.Errorf("status = %d, want %d", rec.Code, http.StatusNotFound)
}
+
+ if strings.Contains(rec.Body.String(), "doctype") {
+ t.Errorf("API 404 answered with HTML: %q", rec.Body.String())
+ }
+}
+
+// The counterpart: a path that looks like a client-side route does get the app,
+// so a deep link survives a reload.
+func TestUnknownPathServesApp(t *testing.T) {
+ req := httptest.NewRequest(http.MethodGet, "/instances/cam0/calibration", nil)
+ rec := httptest.NewRecorder()
+
+ NewVisionServer().ServeHTTP(rec, req)
+
+ if rec.Code != http.StatusOK {
+ t.Errorf("status = %d, want %d", rec.Code, http.StatusOK)
+ }
}
diff --git a/gui/frontend/.prettierignore b/gui/frontend/.prettierignore
index 1eae0cf..c9f9ba3 100644
--- a/gui/frontend/.prettierignore
+++ b/gui/frontend/.prettierignore
@@ -1,2 +1,6 @@
dist/
node_modules/
+
+# Generated by `buf generate` (see gui/buf.gen.yaml). Committed, never edited by
+# hand, and reformatting it would produce a diff on every regeneration.
+src/proto/
diff --git a/gui/frontend/package-lock.json b/gui/frontend/package-lock.json
index 03d6216..4d4b690 100644
--- a/gui/frontend/package-lock.json
+++ b/gui/frontend/package-lock.json
@@ -7,6 +7,9 @@
"": {
"name": "vision-processor-gui-frontend",
"version": "0.0.0",
+ "dependencies": {
+ "@bufbuild/protobuf": "^2.14.1"
+ },
"devDependencies": {
"@eslint/js": "^10.0.1",
"@sveltejs/vite-plugin-svelte": "^7.1.2",
@@ -26,6 +29,12 @@
"vite": "^8.0.12"
}
},
+ "node_modules/@bufbuild/protobuf": {
+ "version": "2.14.1",
+ "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.14.1.tgz",
+ "integrity": "sha512-agRJn3+EJDUe8AvxTx/LnHA/GErvLE62pSaSk7+MwFOtOv8eWBu/qCq2qoZjBjVZ3C2aiFJCveuSs17KMkYGOw==",
+ "license": "(Apache-2.0 AND BSD-3-Clause)"
+ },
"node_modules/@emnapi/core": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
diff --git a/gui/frontend/package.json b/gui/frontend/package.json
index dcd660c..57596b1 100644
--- a/gui/frontend/package.json
+++ b/gui/frontend/package.json
@@ -29,5 +29,8 @@
"typescript": "~6.0.2",
"typescript-eslint": "^8.59.3",
"vite": "^8.0.12"
+ },
+ "dependencies": {
+ "@bufbuild/protobuf": "^2.14.1"
}
}
diff --git a/gui/frontend/src/proto/gamecontroller/ssl_gc_common_pb.ts b/gui/frontend/src/proto/gamecontroller/ssl_gc_common_pb.ts
new file mode 100644
index 0000000..bb16105
--- /dev/null
+++ b/gui/frontend/src/proto/gamecontroller/ssl_gc_common_pb.ts
@@ -0,0 +1,139 @@
+// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
+// @generated from file gamecontroller/ssl_gc_common.proto (syntax proto2)
+/* eslint-disable */
+
+import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
+import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
+import type { Message } from "@bufbuild/protobuf";
+
+/**
+ * Describes the file gamecontroller/ssl_gc_common.proto.
+ */
+export const file_gamecontroller_ssl_gc_common: GenFile = /*@__PURE__*/
+ fileDesc("CiJnYW1lY29udHJvbGxlci9zc2xfZ2NfY29tbW9uLnByb3RvIioKB1JvYm90SWQSCgoCaWQYASABKA0SEwoEdGVhbRgCIAEoDjIFLlRlYW0qKQoEVGVhbRILCgdVTktOT1dOEAASCgoGWUVMTE9XEAESCAoEQkxVRRACKjEKCERpdmlzaW9uEg8KC0RJVl9VTktOT1dOEAASCQoFRElWX0EQARIJCgVESVZfQhACQl1CEFNzbEdjQ29tbW9uUHJvdG9QAVpHZ2l0aHViLmNvbS9Sb2JvQ3VwLVNTTC9zc2wtdmlzaW9uLXByb2Nlc3Nvci9ndWkvaW50ZXJuYWwvZ2FtZWNvbnRyb2xsZXI");
+
+/**
+ * RobotId is the combination of a team and a robot id
+ *
+ * @generated from message RobotId
+ */
+export type RobotId = Message<"RobotId"> & {
+ /**
+ * the robot number
+ *
+ * @generated from field: optional uint32 id = 1;
+ */
+ id: number;
+
+ /**
+ * the team that the robot belongs to
+ *
+ * @generated from field: optional Team team = 2;
+ */
+ team: Team;
+};
+
+/**
+ * RobotId is the combination of a team and a robot id
+ *
+ * @generated from message RobotId
+ */
+export type RobotIdJson = {
+ /**
+ * the robot number
+ *
+ * @generated from field: optional uint32 id = 1;
+ */
+ id?: number;
+
+ /**
+ * the team that the robot belongs to
+ *
+ * @generated from field: optional Team team = 2;
+ */
+ team?: TeamJson;
+};
+
+/**
+ * Describes the message RobotId.
+ * Use `create(RobotIdSchema)` to create a new message.
+ */
+export const RobotIdSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_common, 0);
+
+/**
+ * Team is either blue or yellow
+ *
+ * @generated from enum Team
+ */
+export enum Team {
+ /**
+ * team not set
+ *
+ * @generated from enum value: UNKNOWN = 0;
+ */
+ UNKNOWN = 0,
+
+ /**
+ * yellow team
+ *
+ * @generated from enum value: YELLOW = 1;
+ */
+ YELLOW = 1,
+
+ /**
+ * blue team
+ *
+ * @generated from enum value: BLUE = 2;
+ */
+ BLUE = 2,
+}
+
+/**
+ * Team is either blue or yellow
+ *
+ * @generated from enum Team
+ */
+export type TeamJson = "UNKNOWN" | "YELLOW" | "BLUE";
+
+/**
+ * Describes the enum Team.
+ */
+export const TeamSchema: GenEnum = /*@__PURE__*/
+ enumDesc(file_gamecontroller_ssl_gc_common, 0);
+
+/**
+ * Division denotes the current division, which influences some rules
+ *
+ * @generated from enum Division
+ */
+export enum Division {
+ /**
+ * @generated from enum value: DIV_UNKNOWN = 0;
+ */
+ DIV_UNKNOWN = 0,
+
+ /**
+ * @generated from enum value: DIV_A = 1;
+ */
+ DIV_A = 1,
+
+ /**
+ * @generated from enum value: DIV_B = 2;
+ */
+ DIV_B = 2,
+}
+
+/**
+ * Division denotes the current division, which influences some rules
+ *
+ * @generated from enum Division
+ */
+export type DivisionJson = "DIV_UNKNOWN" | "DIV_A" | "DIV_B";
+
+/**
+ * Describes the enum Division.
+ */
+export const DivisionSchema: GenEnum = /*@__PURE__*/
+ enumDesc(file_gamecontroller_ssl_gc_common, 1);
+
diff --git a/gui/frontend/src/proto/gamecontroller/ssl_gc_game_event_pb.ts b/gui/frontend/src/proto/gamecontroller/ssl_gc_game_event_pb.ts
new file mode 100644
index 0000000..4666b62
--- /dev/null
+++ b/gui/frontend/src/proto/gamecontroller/ssl_gc_game_event_pb.ts
@@ -0,0 +1,3850 @@
+// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
+// @generated from file gamecontroller/ssl_gc_game_event.proto (syntax proto2)
+/* eslint-disable */
+
+import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
+import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
+import type { Team, TeamJson } from "./ssl_gc_common_pb";
+import { file_gamecontroller_ssl_gc_common } from "./ssl_gc_common_pb";
+import type { Vector2, Vector2Json } from "./ssl_gc_geometry_pb";
+import { file_gamecontroller_ssl_gc_geometry } from "./ssl_gc_geometry_pb";
+import type { Message } from "@bufbuild/protobuf";
+
+/**
+ * Describes the file gamecontroller/ssl_gc_game_event.proto.
+ */
+export const file_gamecontroller_ssl_gc_game_event: GenFile = /*@__PURE__*/
+ fileDesc("CiZnYW1lY29udHJvbGxlci9zc2xfZ2NfZ2FtZV9ldmVudC5wcm90byKFQwoJR2FtZUV2ZW50EgoKAmlkGDIgASgJEh0KBHR5cGUYKCABKA4yDy5HYW1lRXZlbnQuVHlwZRIOCgZvcmlnaW4YKSADKAkSGQoRY3JlYXRlZF90aW1lc3RhbXAYMSABKAQSPgoaYmFsbF9sZWZ0X2ZpZWxkX3RvdWNoX2xpbmUYBiABKAsyGC5HYW1lRXZlbnQuQmFsbExlZnRGaWVsZEgAEj0KGWJhbGxfbGVmdF9maWVsZF9nb2FsX2xpbmUYByABKAsyGC5HYW1lRXZlbnQuQmFsbExlZnRGaWVsZEgAEi4KDGFpbWxlc3Nfa2ljaxgLIAEoCzIWLkdhbWVFdmVudC5BaW1sZXNzS2lja0gAElYKImF0dGFja2VyX3Rvb19jbG9zZV90b19kZWZlbnNlX2FyZWEYEyABKAsyKC5HYW1lRXZlbnQuQXR0YWNrZXJUb29DbG9zZVRvRGVmZW5zZUFyZWFIABJEChhkZWZlbmRlcl9pbl9kZWZlbnNlX2FyZWEYHyABKAsyIC5HYW1lRXZlbnQuRGVmZW5kZXJJbkRlZmVuc2VBcmVhSAASOAoRYm91bmRhcnlfY3Jvc3NpbmcYKyABKAsyGy5HYW1lRXZlbnQuQm91bmRhcnlDcm9zc2luZ0gAEjUKEGtlZXBlcl9oZWxkX2JhbGwYDSABKAsyGS5HYW1lRXZlbnQuS2VlcGVySGVsZEJhbGxIABJFChlib3RfZHJpYmJsZWRfYmFsbF90b29fZmFyGBEgASgLMiAuR2FtZUV2ZW50LkJvdERyaWJibGVkQmFsbFRvb0ZhckgAEjEKDmJvdF9wdXNoZWRfYm90GBggASgLMhcuR2FtZUV2ZW50LkJvdFB1c2hlZEJvdEgAEkgKGmJvdF9oZWxkX2JhbGxfZGVsaWJlcmF0ZWx5GBogASgLMiIuR2FtZUV2ZW50LkJvdEhlbGRCYWxsRGVsaWJlcmF0ZWx5SAASMwoPYm90X3RpcHBlZF9vdmVyGBsgASgLMhguR2FtZUV2ZW50LkJvdFRpcHBlZE92ZXJIABI3ChFib3RfZHJvcHBlZF9wYXJ0cxgzIAEoCzIaLkdhbWVFdmVudC5Cb3REcm9wcGVkUGFydHNIABJcCiVhdHRhY2tlcl90b3VjaGVkX2JhbGxfaW5fZGVmZW5zZV9hcmVhGA8gASgLMisuR2FtZUV2ZW50LkF0dGFja2VyVG91Y2hlZEJhbGxJbkRlZmVuc2VBcmVhSAASQwoYYm90X2tpY2tlZF9iYWxsX3Rvb19mYXN0GBIgASgLMh8uR2FtZUV2ZW50LkJvdEtpY2tlZEJhbGxUb29GYXN0SAASNQoQYm90X2NyYXNoX3VuaXF1ZRgWIAEoCzIZLkdhbWVFdmVudC5Cb3RDcmFzaFVuaXF1ZUgAEjMKD2JvdF9jcmFzaF9kcmF3bhgVIAEoCzIYLkdhbWVFdmVudC5Cb3RDcmFzaERyYXduSAASUgogZGVmZW5kZXJfdG9vX2Nsb3NlX3RvX2tpY2tfcG9pbnQYHSABKAsyJi5HYW1lRXZlbnQuRGVmZW5kZXJUb29DbG9zZVRvS2lja1BvaW50SAASOwoUYm90X3Rvb19mYXN0X2luX3N0b3AYHCABKAsyGy5HYW1lRXZlbnQuQm90VG9vRmFzdEluU3RvcEgAEkUKGGJvdF9pbnRlcmZlcmVkX3BsYWNlbWVudBgUIAEoCzIhLkdhbWVFdmVudC5Cb3RJbnRlcmZlcmVkUGxhY2VtZW50SAASKAoNcG9zc2libGVfZ29hbBgnIAEoCzIPLkdhbWVFdmVudC5Hb2FsSAASHwoEZ29hbBgIIAEoCzIPLkdhbWVFdmVudC5Hb2FsSAASJwoMaW52YWxpZF9nb2FsGCwgASgLMg8uR2FtZUV2ZW50LkdvYWxIABJMChxhdHRhY2tlcl9kb3VibGVfdG91Y2hlZF9iYWxsGA4gASgLMiQuR2FtZUV2ZW50LkF0dGFja2VyRG91YmxlVG91Y2hlZEJhbGxIABI8ChNwbGFjZW1lbnRfc3VjY2VlZGVkGAUgASgLMh0uR2FtZUV2ZW50LlBsYWNlbWVudFN1Y2NlZWRlZEgAEjsKE3BlbmFsdHlfa2lja19mYWlsZWQYLSABKAsyHC5HYW1lRXZlbnQuUGVuYWx0eUtpY2tGYWlsZWRIABI6ChNub19wcm9ncmVzc19pbl9nYW1lGAIgASgLMhsuR2FtZUV2ZW50Lk5vUHJvZ3Jlc3NJbkdhbWVIABI2ChBwbGFjZW1lbnRfZmFpbGVkGAMgASgLMhouR2FtZUV2ZW50LlBsYWNlbWVudEZhaWxlZEgAEjIKDm11bHRpcGxlX2NhcmRzGCAgASgLMhguR2FtZUV2ZW50Lk11bHRpcGxlQ2FyZHNIABIyCg5tdWx0aXBsZV9mb3VscxgiIAEoCzIYLkdhbWVFdmVudC5NdWx0aXBsZUZvdWxzSAASNgoQYm90X3N1YnN0aXR1dGlvbhglIAEoCzIaLkdhbWVFdmVudC5Cb3RTdWJzdGl0dXRpb25IABJJChpleGNlc3NpdmVfYm90X3N1YnN0aXR1dGlvbhg0IAEoCzIjLkdhbWVFdmVudC5FeGNlc3NpdmVCb3RTdWJzdGl0dXRpb25IABIzCg90b29fbWFueV9yb2JvdHMYJiABKAsyGC5HYW1lRXZlbnQuVG9vTWFueVJvYm90c0gAEjIKDmNoYWxsZW5nZV9mbGFnGC4gASgLMhguR2FtZUV2ZW50LkNoYWxsZW5nZUZsYWdIABJBChZjaGFsbGVuZ2VfZmxhZ19oYW5kbGVkGDAgASgLMh8uR2FtZUV2ZW50LkNoYWxsZW5nZUZsYWdIYW5kbGVkSAASMgoOZW1lcmdlbmN5X3N0b3AYLyABKAsyGC5HYW1lRXZlbnQuRW1lcmdlbmN5U3RvcEgAEkcKGXVuc3BvcnRpbmdfYmVoYXZpb3JfbWlub3IYIyABKAsyIi5HYW1lRXZlbnQuVW5zcG9ydGluZ0JlaGF2aW9yTWlub3JIABJHChl1bnNwb3J0aW5nX2JlaGF2aW9yX21ham9yGCQgASgLMiIuR2FtZUV2ZW50LlVuc3BvcnRpbmdCZWhhdmlvck1ham9ySAASKwoIcHJlcGFyZWQYASABKAsyEy5HYW1lRXZlbnQuUHJlcGFyZWRCAhgBSAASNAoNaW5kaXJlY3RfZ29hbBgJIAEoCzIXLkdhbWVFdmVudC5JbmRpcmVjdEdvYWxCAhgBSAASMgoMY2hpcHBlZF9nb2FsGAogASgLMhYuR2FtZUV2ZW50LkNoaXBwZWRHb2FsQgIYAUgAEjIKDGtpY2tfdGltZW91dBgMIAEoCzIWLkdhbWVFdmVudC5LaWNrVGltZW91dEICGAFIABJoCilhdHRhY2tlcl90b3VjaGVkX29wcG9uZW50X2luX2RlZmVuc2VfYXJlYRgQIAEoCzIvLkdhbWVFdmVudC5BdHRhY2tlclRvdWNoZWRPcHBvbmVudEluRGVmZW5zZUFyZWFCAhgBSAAScAoxYXR0YWNrZXJfdG91Y2hlZF9vcHBvbmVudF9pbl9kZWZlbnNlX2FyZWFfc2tpcHBlZBgqIAEoCzIvLkdhbWVFdmVudC5BdHRhY2tlclRvdWNoZWRPcHBvbmVudEluRGVmZW5zZUFyZWFCAhgBSAASQQoYYm90X2NyYXNoX3VuaXF1ZV9za2lwcGVkGBcgASgLMhkuR2FtZUV2ZW50LkJvdENyYXNoVW5pcXVlQgIYAUgAEj0KFmJvdF9wdXNoZWRfYm90X3NraXBwZWQYGSABKAsyFy5HYW1lRXZlbnQuQm90UHVzaGVkQm90QgIYAUgAElsKImRlZmVuZGVyX2luX2RlZmVuc2VfYXJlYV9wYXJ0aWFsbHkYHiABKAsyKS5HYW1lRXZlbnQuRGVmZW5kZXJJbkRlZmVuc2VBcmVhUGFydGlhbGx5QgIYAUgAEk8KG211bHRpcGxlX3BsYWNlbWVudF9mYWlsdXJlcxghIAEoCzIkLkdhbWVFdmVudC5NdWx0aXBsZVBsYWNlbWVudEZhaWx1cmVzQgIYAUgAGlMKDUJhbGxMZWZ0RmllbGQSFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhpyCgtBaW1sZXNzS2ljaxIWCgdieV90ZWFtGAEgAigOMgUuVGVhbRIOCgZieV9ib3QYAiABKA0SGgoIbG9jYXRpb24YAyABKAsyCC5WZWN0b3IyEh8KDWtpY2tfbG9jYXRpb24YBCABKAsyCC5WZWN0b3IyGu8BCgRHb2FsEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEhsKDGtpY2tpbmdfdGVhbRgGIAEoDjIFLlRlYW0SEwoLa2lja2luZ19ib3QYAiABKA0SGgoIbG9jYXRpb24YAyABKAsyCC5WZWN0b3IyEh8KDWtpY2tfbG9jYXRpb24YBCABKAsyCC5WZWN0b3IyEhcKD21heF9iYWxsX2hlaWdodBgFIAEoAhIaChJudW1fcm9ib3RzX2J5X3RlYW0YByABKA0SGgoSbGFzdF90b3VjaF9ieV90ZWFtGAggASgEEg8KB21lc3NhZ2UYCSABKAkacwoMSW5kaXJlY3RHb2FsEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEg4KBmJ5X2JvdBgCIAEoDRIaCghsb2NhdGlvbhgDIAEoCzIILlZlY3RvcjISHwoNa2lja19sb2NhdGlvbhgEIAEoCzIILlZlY3RvcjIaiwEKC0NoaXBwZWRHb2FsEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEg4KBmJ5X2JvdBgCIAEoDRIaCghsb2NhdGlvbhgDIAEoCzIILlZlY3RvcjISHwoNa2lja19sb2NhdGlvbhgEIAEoCzIILlZlY3RvcjISFwoPbWF4X2JhbGxfaGVpZ2h0GAUgASgCGmUKEEJvdFRvb0Zhc3RJblN0b3ASFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhINCgVzcGVlZBgEIAEoAhpzChtEZWZlbmRlclRvb0Nsb3NlVG9LaWNrUG9pbnQSFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhIQCghkaXN0YW5jZRgEIAEoAhqPAQoNQm90Q3Jhc2hEcmF3bhISCgpib3RfeWVsbG93GAEgASgNEhAKCGJvdF9ibHVlGAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhITCgtjcmFzaF9zcGVlZBgEIAEoAhISCgpzcGVlZF9kaWZmGAUgASgCEhMKC2NyYXNoX2FuZ2xlGAYgASgCGqQBCg5Cb3RDcmFzaFVuaXF1ZRIWCgdieV90ZWFtGAEgAigOMgUuVGVhbRIQCgh2aW9sYXRvchgCIAEoDRIOCgZ2aWN0aW0YAyABKA0SGgoIbG9jYXRpb24YBCABKAsyCC5WZWN0b3IyEhMKC2NyYXNoX3NwZWVkGAUgASgCEhIKCnNwZWVkX2RpZmYYBiABKAISEwoLY3Jhc2hfYW5nbGUYByABKAIafQoMQm90UHVzaGVkQm90EhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEhAKCHZpb2xhdG9yGAIgASgNEg4KBnZpY3RpbRgDIAEoDRIaCghsb2NhdGlvbhgEIAEoCzIILlZlY3RvcjISFwoPcHVzaGVkX2Rpc3RhbmNlGAUgASgCGnQKDUJvdFRpcHBlZE92ZXISFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhIfCg1iYWxsX2xvY2F0aW9uGAQgASgLMgguVmVjdG9yMhp2Cg9Cb3REcm9wcGVkUGFydHMSFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhIfCg1iYWxsX2xvY2F0aW9uGAQgASgLMgguVmVjdG9yMhptChVEZWZlbmRlckluRGVmZW5zZUFyZWESFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhIQCghkaXN0YW5jZRgEIAEoAhqXAQoeRGVmZW5kZXJJbkRlZmVuc2VBcmVhUGFydGlhbGx5EhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEg4KBmJ5X2JvdBgCIAEoDRIaCghsb2NhdGlvbhgDIAEoCzIILlZlY3RvcjISEAoIZGlzdGFuY2UYBCABKAISHwoNYmFsbF9sb2NhdGlvbhgFIAEoCzIILlZlY3RvcjIaeAogQXR0YWNrZXJUb3VjaGVkQmFsbEluRGVmZW5zZUFyZWESFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhIQCghkaXN0YW5jZRgEIAEoAhqHAQoUQm90S2lja2VkQmFsbFRvb0Zhc3QSFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhIaChJpbml0aWFsX2JhbGxfc3BlZWQYBCABKAISDwoHY2hpcHBlZBgFIAEoCBpvChVCb3REcmliYmxlZEJhbGxUb29GYXISFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhcKBXN0YXJ0GAMgASgLMgguVmVjdG9yMhIVCgNlbmQYBCABKAsyCC5WZWN0b3IyGnoKJEF0dGFja2VyVG91Y2hlZE9wcG9uZW50SW5EZWZlbnNlQXJlYRIWCgdieV90ZWFtGAEgAigOMgUuVGVhbRIOCgZieV9ib3QYAiABKA0SDgoGdmljdGltGAQgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhpfChlBdHRhY2tlckRvdWJsZVRvdWNoZWRCYWxsEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEg4KBmJ5X2JvdBgCIAEoDRIaCghsb2NhdGlvbhgDIAEoCzIILlZlY3RvcjIalgEKHUF0dGFja2VyVG9vQ2xvc2VUb0RlZmVuc2VBcmVhEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEg4KBmJ5X2JvdBgCIAEoDRIaCghsb2NhdGlvbhgDIAEoCzIILlZlY3RvcjISEAoIZGlzdGFuY2UYBCABKAISHwoNYmFsbF9sb2NhdGlvbhgFIAEoCzIILlZlY3RvcjIabwoXQm90SGVsZEJhbGxEZWxpYmVyYXRlbHkSFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhIQCghkdXJhdGlvbhgEIAEoAhpcChZCb3RJbnRlcmZlcmVkUGxhY2VtZW50EhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEg4KBmJ5X2JvdBgCIAEoDRIaCghsb2NhdGlvbhgDIAEoCzIILlZlY3RvcjIaJwoNTXVsdGlwbGVDYXJkcxIWCgdieV90ZWFtGAEgAigOMgUuVGVhbRpPCg1NdWx0aXBsZUZvdWxzEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEiYKEmNhdXNlZF9nYW1lX2V2ZW50cxgCIAMoCzIKLkdhbWVFdmVudBozChlNdWx0aXBsZVBsYWNlbWVudEZhaWx1cmVzEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtGk8KC0tpY2tUaW1lb3V0EhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEhoKCGxvY2F0aW9uGAIgASgLMgguVmVjdG9yMhIMCgR0aW1lGAMgASgCGjwKEE5vUHJvZ3Jlc3NJbkdhbWUSGgoIbG9jYXRpb24YASABKAsyCC5WZWN0b3IyEgwKBHRpbWUYAiABKAIaZwoPUGxhY2VtZW50RmFpbGVkEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEhoKEnJlbWFpbmluZ19kaXN0YW5jZRgCIAEoAhIgChhuZWFyZXN0X293bl9ib3RfZGlzdGFuY2UYAyABKAIaQQoXVW5zcG9ydGluZ0JlaGF2aW9yTWlub3ISFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGcmVhc29uGAIgAigJGkEKF1Vuc3BvcnRpbmdCZWhhdmlvck1ham9yEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEg4KBnJlYXNvbhgCIAIoCRpWCg5LZWVwZXJIZWxkQmFsbBIWCgdieV90ZWFtGAEgAigOMgUuVGVhbRIaCghsb2NhdGlvbhgCIAEoCzIILlZlY3RvcjISEAoIZHVyYXRpb24YAyABKAIaZQoSUGxhY2VtZW50U3VjY2VlZGVkEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEhIKCnRpbWVfdGFrZW4YAiABKAISEQoJcHJlY2lzaW9uGAMgASgCEhAKCGRpc3RhbmNlGAQgASgCGh4KCFByZXBhcmVkEhIKCnRpbWVfdGFrZW4YASABKAIaKQoPQm90U3Vic3RpdHV0aW9uEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtGjIKGEV4Y2Vzc2l2ZUJvdFN1YnN0aXR1dGlvbhIWCgdieV90ZWFtGAEgAigOMgUuVGVhbRonCg1DaGFsbGVuZ2VGbGFnEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtGkAKFENoYWxsZW5nZUZsYWdIYW5kbGVkEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEhAKCGFjY2VwdGVkGAIgAigIGicKDUVtZXJnZW5jeVN0b3ASFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0agQEKDVRvb01hbnlSb2JvdHMSFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SGgoSbnVtX3JvYm90c19hbGxvd2VkGAIgASgFEhsKE251bV9yb2JvdHNfb25fZmllbGQYAyABKAUSHwoNYmFsbF9sb2NhdGlvbhgEIAEoCzIILlZlY3RvcjIaRgoQQm91bmRhcnlDcm9zc2luZxIWCgdieV90ZWFtGAEgAigOMgUuVGVhbRIaCghsb2NhdGlvbhgCIAEoCzIILlZlY3RvcjIaVwoRUGVuYWx0eUtpY2tGYWlsZWQSFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SGgoIbG9jYXRpb24YAiABKAsyCC5WZWN0b3IyEg4KBnJlYXNvbhgDIAEoCSK1CgoEVHlwZRIbChdVTktOT1dOX0dBTUVfRVZFTlRfVFlQRRAAEh4KGkJBTExfTEVGVF9GSUVMRF9UT1VDSF9MSU5FEAYSHQoZQkFMTF9MRUZUX0ZJRUxEX0dPQUxfTElORRAHEhAKDEFJTUxFU1NfS0lDSxALEiYKIkFUVEFDS0VSX1RPT19DTE9TRV9UT19ERUZFTlNFX0FSRUEQExIcChhERUZFTkRFUl9JTl9ERUZFTlNFX0FSRUEQHxIVChFCT1VOREFSWV9DUk9TU0lORxApEhQKEEtFRVBFUl9IRUxEX0JBTEwQDRIdChlCT1RfRFJJQkJMRURfQkFMTF9UT09fRkFSEBESEgoOQk9UX1BVU0hFRF9CT1QQGBIeChpCT1RfSEVMRF9CQUxMX0RFTElCRVJBVEVMWRAaEhMKD0JPVF9USVBQRURfT1ZFUhAbEhUKEUJPVF9EUk9QUEVEX1BBUlRTEC8SKQolQVRUQUNLRVJfVE9VQ0hFRF9CQUxMX0lOX0RFRkVOU0VfQVJFQRAPEhwKGEJPVF9LSUNLRURfQkFMTF9UT09fRkFTVBASEhQKEEJPVF9DUkFTSF9VTklRVUUQFhITCg9CT1RfQ1JBU0hfRFJBV04QFRIkCiBERUZFTkRFUl9UT09fQ0xPU0VfVE9fS0lDS19QT0lOVBAdEhgKFEJPVF9UT09fRkFTVF9JTl9TVE9QEBwSHAoYQk9UX0lOVEVSRkVSRURfUExBQ0VNRU5UEBQSHgoaRVhDRVNTSVZFX0JPVF9TVUJTVElUVVRJT04QMBIRCg1QT1NTSUJMRV9HT0FMECcSCAoER09BTBAIEhAKDElOVkFMSURfR09BTBAqEiAKHEFUVEFDS0VSX0RPVUJMRV9UT1VDSEVEX0JBTEwQDhIXChNQTEFDRU1FTlRfU1VDQ0VFREVEEAUSFwoTUEVOQUxUWV9LSUNLX0ZBSUxFRBArEhcKE05PX1BST0dSRVNTX0lOX0dBTUUQAhIUChBQTEFDRU1FTlRfRkFJTEVEEAMSEgoOTVVMVElQTEVfQ0FSRFMQIBISCg5NVUxUSVBMRV9GT1VMUxAiEhQKEEJPVF9TVUJTVElUVVRJT04QJRITCg9UT09fTUFOWV9ST0JPVFMQJhISCg5DSEFMTEVOR0VfRkxBRxAsEhoKFkNIQUxMRU5HRV9GTEFHX0hBTkRMRUQQLhISCg5FTUVSR0VOQ1lfU1RPUBAtEh0KGVVOU1BPUlRJTkdfQkVIQVZJT1JfTUlOT1IQIxIdChlVTlNQT1JUSU5HX0JFSEFWSU9SX01BSk9SECQSEAoIUFJFUEFSRUQQARoCCAESFQoNSU5ESVJFQ1RfR09BTBAJGgIIARIUCgxDSElQUEVEX0dPQUwQChoCCAESFAoMS0lDS19USU1FT1VUEAwaAggBEjEKKUFUVEFDS0VSX1RPVUNIRURfT1BQT05FTlRfSU5fREVGRU5TRV9BUkVBEBAaAggBEjkKMUFUVEFDS0VSX1RPVUNIRURfT1BQT05FTlRfSU5fREVGRU5TRV9BUkVBX1NLSVBQRUQQKBoCCAESIAoYQk9UX0NSQVNIX1VOSVFVRV9TS0lQUEVEEBcaAggBEh4KFkJPVF9QVVNIRURfQk9UX1NLSVBQRUQQGRoCCAESKgoiREVGRU5ERVJfSU5fREVGRU5TRV9BUkVBX1BBUlRJQUxMWRAeGgIIARIjChtNVUxUSVBMRV9QTEFDRU1FTlRfRkFJTFVSRVMQIRoCCAFCBwoFZXZlbnRCYEITU3NsR2NHYW1lRXZlbnRQcm90b1ABWkdnaXRodWIuY29tL1JvYm9DdXAtU1NML3NzbC12aXNpb24tcHJvY2Vzc29yL2d1aS9pbnRlcm5hbC9nYW1lY29udHJvbGxlcg", [file_gamecontroller_ssl_gc_common, file_gamecontroller_ssl_gc_geometry]);
+
+/**
+ * GameEvent contains exactly one game event
+ * Each game event has optional and required fields. The required fields are mandatory to process the event.
+ * Some optional fields are only used for visualization, others are required to determine the ball placement position.
+ * If fields are missing that are required for the ball placement position, no ball placement command will be issued.
+ * Fields are marked optional to make testing and extending of the protocol easier.
+ * An autoRef should ideally set all fields, except if there are good reasons to not do so.
+ *
+ * @generated from message GameEvent
+ */
+export type GameEvent = Message<"GameEvent"> & {
+ /**
+ * A globally unique id of the game event.
+ *
+ * @generated from field: optional string id = 50;
+ */
+ id: string;
+
+ /**
+ * The type of the game event.
+ *
+ * @generated from field: optional GameEvent.Type type = 40;
+ */
+ type: GameEvent_Type;
+
+ /**
+ * The origins of this game event.
+ * Empty, if it originates from game controller.
+ * Contains autoRef name(s), if it originates from one or more autoRefs.
+ * Ignored if sent by autoRef to game controller.
+ *
+ * @generated from field: repeated string origin = 41;
+ */
+ origin: string[];
+
+ /**
+ * Unix timestamp in microseconds when the event was created.
+ *
+ * @generated from field: optional uint64 created_timestamp = 49;
+ */
+ createdTimestamp: bigint;
+
+ /**
+ * the event that occurred
+ *
+ * @generated from oneof GameEvent.event
+ */
+ event: {
+ /**
+ * @generated from field: GameEvent.BallLeftField ball_left_field_touch_line = 6;
+ */
+ value: GameEvent_BallLeftField;
+ case: "ballLeftFieldTouchLine";
+ } | {
+ /**
+ * @generated from field: GameEvent.BallLeftField ball_left_field_goal_line = 7;
+ */
+ value: GameEvent_BallLeftField;
+ case: "ballLeftFieldGoalLine";
+ } | {
+ /**
+ * @generated from field: GameEvent.AimlessKick aimless_kick = 11;
+ */
+ value: GameEvent_AimlessKick;
+ case: "aimlessKick";
+ } | {
+ /**
+ * @generated from field: GameEvent.AttackerTooCloseToDefenseArea attacker_too_close_to_defense_area = 19;
+ */
+ value: GameEvent_AttackerTooCloseToDefenseArea;
+ case: "attackerTooCloseToDefenseArea";
+ } | {
+ /**
+ * @generated from field: GameEvent.DefenderInDefenseArea defender_in_defense_area = 31;
+ */
+ value: GameEvent_DefenderInDefenseArea;
+ case: "defenderInDefenseArea";
+ } | {
+ /**
+ * @generated from field: GameEvent.BoundaryCrossing boundary_crossing = 43;
+ */
+ value: GameEvent_BoundaryCrossing;
+ case: "boundaryCrossing";
+ } | {
+ /**
+ * @generated from field: GameEvent.KeeperHeldBall keeper_held_ball = 13;
+ */
+ value: GameEvent_KeeperHeldBall;
+ case: "keeperHeldBall";
+ } | {
+ /**
+ * @generated from field: GameEvent.BotDribbledBallTooFar bot_dribbled_ball_too_far = 17;
+ */
+ value: GameEvent_BotDribbledBallTooFar;
+ case: "botDribbledBallTooFar";
+ } | {
+ /**
+ * @generated from field: GameEvent.BotPushedBot bot_pushed_bot = 24;
+ */
+ value: GameEvent_BotPushedBot;
+ case: "botPushedBot";
+ } | {
+ /**
+ * @generated from field: GameEvent.BotHeldBallDeliberately bot_held_ball_deliberately = 26;
+ */
+ value: GameEvent_BotHeldBallDeliberately;
+ case: "botHeldBallDeliberately";
+ } | {
+ /**
+ * @generated from field: GameEvent.BotTippedOver bot_tipped_over = 27;
+ */
+ value: GameEvent_BotTippedOver;
+ case: "botTippedOver";
+ } | {
+ /**
+ * @generated from field: GameEvent.BotDroppedParts bot_dropped_parts = 51;
+ */
+ value: GameEvent_BotDroppedParts;
+ case: "botDroppedParts";
+ } | {
+ /**
+ * @generated from field: GameEvent.AttackerTouchedBallInDefenseArea attacker_touched_ball_in_defense_area = 15;
+ */
+ value: GameEvent_AttackerTouchedBallInDefenseArea;
+ case: "attackerTouchedBallInDefenseArea";
+ } | {
+ /**
+ * @generated from field: GameEvent.BotKickedBallTooFast bot_kicked_ball_too_fast = 18;
+ */
+ value: GameEvent_BotKickedBallTooFast;
+ case: "botKickedBallTooFast";
+ } | {
+ /**
+ * @generated from field: GameEvent.BotCrashUnique bot_crash_unique = 22;
+ */
+ value: GameEvent_BotCrashUnique;
+ case: "botCrashUnique";
+ } | {
+ /**
+ * @generated from field: GameEvent.BotCrashDrawn bot_crash_drawn = 21;
+ */
+ value: GameEvent_BotCrashDrawn;
+ case: "botCrashDrawn";
+ } | {
+ /**
+ * @generated from field: GameEvent.DefenderTooCloseToKickPoint defender_too_close_to_kick_point = 29;
+ */
+ value: GameEvent_DefenderTooCloseToKickPoint;
+ case: "defenderTooCloseToKickPoint";
+ } | {
+ /**
+ * @generated from field: GameEvent.BotTooFastInStop bot_too_fast_in_stop = 28;
+ */
+ value: GameEvent_BotTooFastInStop;
+ case: "botTooFastInStop";
+ } | {
+ /**
+ * @generated from field: GameEvent.BotInterferedPlacement bot_interfered_placement = 20;
+ */
+ value: GameEvent_BotInterferedPlacement;
+ case: "botInterferedPlacement";
+ } | {
+ /**
+ * @generated from field: GameEvent.Goal possible_goal = 39;
+ */
+ value: GameEvent_Goal;
+ case: "possibleGoal";
+ } | {
+ /**
+ * @generated from field: GameEvent.Goal goal = 8;
+ */
+ value: GameEvent_Goal;
+ case: "goal";
+ } | {
+ /**
+ * @generated from field: GameEvent.Goal invalid_goal = 44;
+ */
+ value: GameEvent_Goal;
+ case: "invalidGoal";
+ } | {
+ /**
+ * @generated from field: GameEvent.AttackerDoubleTouchedBall attacker_double_touched_ball = 14;
+ */
+ value: GameEvent_AttackerDoubleTouchedBall;
+ case: "attackerDoubleTouchedBall";
+ } | {
+ /**
+ * @generated from field: GameEvent.PlacementSucceeded placement_succeeded = 5;
+ */
+ value: GameEvent_PlacementSucceeded;
+ case: "placementSucceeded";
+ } | {
+ /**
+ * @generated from field: GameEvent.PenaltyKickFailed penalty_kick_failed = 45;
+ */
+ value: GameEvent_PenaltyKickFailed;
+ case: "penaltyKickFailed";
+ } | {
+ /**
+ * @generated from field: GameEvent.NoProgressInGame no_progress_in_game = 2;
+ */
+ value: GameEvent_NoProgressInGame;
+ case: "noProgressInGame";
+ } | {
+ /**
+ * @generated from field: GameEvent.PlacementFailed placement_failed = 3;
+ */
+ value: GameEvent_PlacementFailed;
+ case: "placementFailed";
+ } | {
+ /**
+ * @generated from field: GameEvent.MultipleCards multiple_cards = 32;
+ */
+ value: GameEvent_MultipleCards;
+ case: "multipleCards";
+ } | {
+ /**
+ * @generated from field: GameEvent.MultipleFouls multiple_fouls = 34;
+ */
+ value: GameEvent_MultipleFouls;
+ case: "multipleFouls";
+ } | {
+ /**
+ * @generated from field: GameEvent.BotSubstitution bot_substitution = 37;
+ */
+ value: GameEvent_BotSubstitution;
+ case: "botSubstitution";
+ } | {
+ /**
+ * @generated from field: GameEvent.ExcessiveBotSubstitution excessive_bot_substitution = 52;
+ */
+ value: GameEvent_ExcessiveBotSubstitution;
+ case: "excessiveBotSubstitution";
+ } | {
+ /**
+ * @generated from field: GameEvent.TooManyRobots too_many_robots = 38;
+ */
+ value: GameEvent_TooManyRobots;
+ case: "tooManyRobots";
+ } | {
+ /**
+ * @generated from field: GameEvent.ChallengeFlag challenge_flag = 46;
+ */
+ value: GameEvent_ChallengeFlag;
+ case: "challengeFlag";
+ } | {
+ /**
+ * @generated from field: GameEvent.ChallengeFlagHandled challenge_flag_handled = 48;
+ */
+ value: GameEvent_ChallengeFlagHandled;
+ case: "challengeFlagHandled";
+ } | {
+ /**
+ * @generated from field: GameEvent.EmergencyStop emergency_stop = 47;
+ */
+ value: GameEvent_EmergencyStop;
+ case: "emergencyStop";
+ } | {
+ /**
+ * @generated from field: GameEvent.UnsportingBehaviorMinor unsporting_behavior_minor = 35;
+ */
+ value: GameEvent_UnsportingBehaviorMinor;
+ case: "unsportingBehaviorMinor";
+ } | {
+ /**
+ * @generated from field: GameEvent.UnsportingBehaviorMajor unsporting_behavior_major = 36;
+ */
+ value: GameEvent_UnsportingBehaviorMajor;
+ case: "unsportingBehaviorMajor";
+ } | {
+ /**
+ * replaced by ready_to_continue flag
+ *
+ * @generated from field: GameEvent.Prepared prepared = 1 [deprecated = true];
+ * @deprecated
+ */
+ value: GameEvent_Prepared;
+ case: "prepared";
+ } | {
+ /**
+ * obsolete
+ *
+ * @generated from field: GameEvent.IndirectGoal indirect_goal = 9 [deprecated = true];
+ * @deprecated
+ */
+ value: GameEvent_IndirectGoal;
+ case: "indirectGoal";
+ } | {
+ /**
+ * replaced by the meta-information in the possible_goal event
+ *
+ * @generated from field: GameEvent.ChippedGoal chipped_goal = 10 [deprecated = true];
+ * @deprecated
+ */
+ value: GameEvent_ChippedGoal;
+ case: "chippedGoal";
+ } | {
+ /**
+ * obsolete
+ *
+ * @generated from field: GameEvent.KickTimeout kick_timeout = 12 [deprecated = true];
+ * @deprecated
+ */
+ value: GameEvent_KickTimeout;
+ case: "kickTimeout";
+ } | {
+ /**
+ * rule removed
+ *
+ * @generated from field: GameEvent.AttackerTouchedOpponentInDefenseArea attacker_touched_opponent_in_defense_area = 16 [deprecated = true];
+ * @deprecated
+ */
+ value: GameEvent_AttackerTouchedOpponentInDefenseArea;
+ case: "attackerTouchedOpponentInDefenseArea";
+ } | {
+ /**
+ * obsolete
+ *
+ * @generated from field: GameEvent.AttackerTouchedOpponentInDefenseArea attacker_touched_opponent_in_defense_area_skipped = 42 [deprecated = true];
+ * @deprecated
+ */
+ value: GameEvent_AttackerTouchedOpponentInDefenseArea;
+ case: "attackerTouchedOpponentInDefenseAreaSkipped";
+ } | {
+ /**
+ * obsolete
+ *
+ * @generated from field: GameEvent.BotCrashUnique bot_crash_unique_skipped = 23 [deprecated = true];
+ * @deprecated
+ */
+ value: GameEvent_BotCrashUnique;
+ case: "botCrashUniqueSkipped";
+ } | {
+ /**
+ * can not be used as long as autoRefs do not judge pushing
+ *
+ * @generated from field: GameEvent.BotPushedBot bot_pushed_bot_skipped = 25 [deprecated = true];
+ * @deprecated
+ */
+ value: GameEvent_BotPushedBot;
+ case: "botPushedBotSkipped";
+ } | {
+ /**
+ * rule removed
+ *
+ * @generated from field: GameEvent.DefenderInDefenseAreaPartially defender_in_defense_area_partially = 30 [deprecated = true];
+ * @deprecated
+ */
+ value: GameEvent_DefenderInDefenseAreaPartially;
+ case: "defenderInDefenseAreaPartially";
+ } | {
+ /**
+ * the referee msg already indicates this
+ *
+ * @generated from field: GameEvent.MultiplePlacementFailures multiple_placement_failures = 33 [deprecated = true];
+ * @deprecated
+ */
+ value: GameEvent_MultiplePlacementFailures;
+ case: "multiplePlacementFailures";
+ } | { case: undefined; value?: undefined };
+};
+
+/**
+ * GameEvent contains exactly one game event
+ * Each game event has optional and required fields. The required fields are mandatory to process the event.
+ * Some optional fields are only used for visualization, others are required to determine the ball placement position.
+ * If fields are missing that are required for the ball placement position, no ball placement command will be issued.
+ * Fields are marked optional to make testing and extending of the protocol easier.
+ * An autoRef should ideally set all fields, except if there are good reasons to not do so.
+ *
+ * @generated from message GameEvent
+ */
+export type GameEventJson = {
+ /**
+ * A globally unique id of the game event.
+ *
+ * @generated from field: optional string id = 50;
+ */
+ id?: string;
+
+ /**
+ * The type of the game event.
+ *
+ * @generated from field: optional GameEvent.Type type = 40;
+ */
+ type?: GameEvent_TypeJson;
+
+ /**
+ * The origins of this game event.
+ * Empty, if it originates from game controller.
+ * Contains autoRef name(s), if it originates from one or more autoRefs.
+ * Ignored if sent by autoRef to game controller.
+ *
+ * @generated from field: repeated string origin = 41;
+ */
+ origin?: string[];
+
+ /**
+ * Unix timestamp in microseconds when the event was created.
+ *
+ * @generated from field: optional uint64 created_timestamp = 49;
+ */
+ createdTimestamp?: string;
+
+ /**
+ * @generated from field: GameEvent.BallLeftField ball_left_field_touch_line = 6;
+ */
+ ballLeftFieldTouchLine?: GameEvent_BallLeftFieldJson;
+
+ /**
+ * @generated from field: GameEvent.BallLeftField ball_left_field_goal_line = 7;
+ */
+ ballLeftFieldGoalLine?: GameEvent_BallLeftFieldJson;
+
+ /**
+ * @generated from field: GameEvent.AimlessKick aimless_kick = 11;
+ */
+ aimlessKick?: GameEvent_AimlessKickJson;
+
+ /**
+ * @generated from field: GameEvent.AttackerTooCloseToDefenseArea attacker_too_close_to_defense_area = 19;
+ */
+ attackerTooCloseToDefenseArea?: GameEvent_AttackerTooCloseToDefenseAreaJson;
+
+ /**
+ * @generated from field: GameEvent.DefenderInDefenseArea defender_in_defense_area = 31;
+ */
+ defenderInDefenseArea?: GameEvent_DefenderInDefenseAreaJson;
+
+ /**
+ * @generated from field: GameEvent.BoundaryCrossing boundary_crossing = 43;
+ */
+ boundaryCrossing?: GameEvent_BoundaryCrossingJson;
+
+ /**
+ * @generated from field: GameEvent.KeeperHeldBall keeper_held_ball = 13;
+ */
+ keeperHeldBall?: GameEvent_KeeperHeldBallJson;
+
+ /**
+ * @generated from field: GameEvent.BotDribbledBallTooFar bot_dribbled_ball_too_far = 17;
+ */
+ botDribbledBallTooFar?: GameEvent_BotDribbledBallTooFarJson;
+
+ /**
+ * @generated from field: GameEvent.BotPushedBot bot_pushed_bot = 24;
+ */
+ botPushedBot?: GameEvent_BotPushedBotJson;
+
+ /**
+ * @generated from field: GameEvent.BotHeldBallDeliberately bot_held_ball_deliberately = 26;
+ */
+ botHeldBallDeliberately?: GameEvent_BotHeldBallDeliberatelyJson;
+
+ /**
+ * @generated from field: GameEvent.BotTippedOver bot_tipped_over = 27;
+ */
+ botTippedOver?: GameEvent_BotTippedOverJson;
+
+ /**
+ * @generated from field: GameEvent.BotDroppedParts bot_dropped_parts = 51;
+ */
+ botDroppedParts?: GameEvent_BotDroppedPartsJson;
+
+ /**
+ * @generated from field: GameEvent.AttackerTouchedBallInDefenseArea attacker_touched_ball_in_defense_area = 15;
+ */
+ attackerTouchedBallInDefenseArea?: GameEvent_AttackerTouchedBallInDefenseAreaJson;
+
+ /**
+ * @generated from field: GameEvent.BotKickedBallTooFast bot_kicked_ball_too_fast = 18;
+ */
+ botKickedBallTooFast?: GameEvent_BotKickedBallTooFastJson;
+
+ /**
+ * @generated from field: GameEvent.BotCrashUnique bot_crash_unique = 22;
+ */
+ botCrashUnique?: GameEvent_BotCrashUniqueJson;
+
+ /**
+ * @generated from field: GameEvent.BotCrashDrawn bot_crash_drawn = 21;
+ */
+ botCrashDrawn?: GameEvent_BotCrashDrawnJson;
+
+ /**
+ * @generated from field: GameEvent.DefenderTooCloseToKickPoint defender_too_close_to_kick_point = 29;
+ */
+ defenderTooCloseToKickPoint?: GameEvent_DefenderTooCloseToKickPointJson;
+
+ /**
+ * @generated from field: GameEvent.BotTooFastInStop bot_too_fast_in_stop = 28;
+ */
+ botTooFastInStop?: GameEvent_BotTooFastInStopJson;
+
+ /**
+ * @generated from field: GameEvent.BotInterferedPlacement bot_interfered_placement = 20;
+ */
+ botInterferedPlacement?: GameEvent_BotInterferedPlacementJson;
+
+ /**
+ * @generated from field: GameEvent.Goal possible_goal = 39;
+ */
+ possibleGoal?: GameEvent_GoalJson;
+
+ /**
+ * @generated from field: GameEvent.Goal goal = 8;
+ */
+ goal?: GameEvent_GoalJson;
+
+ /**
+ * @generated from field: GameEvent.Goal invalid_goal = 44;
+ */
+ invalidGoal?: GameEvent_GoalJson;
+
+ /**
+ * @generated from field: GameEvent.AttackerDoubleTouchedBall attacker_double_touched_ball = 14;
+ */
+ attackerDoubleTouchedBall?: GameEvent_AttackerDoubleTouchedBallJson;
+
+ /**
+ * @generated from field: GameEvent.PlacementSucceeded placement_succeeded = 5;
+ */
+ placementSucceeded?: GameEvent_PlacementSucceededJson;
+
+ /**
+ * @generated from field: GameEvent.PenaltyKickFailed penalty_kick_failed = 45;
+ */
+ penaltyKickFailed?: GameEvent_PenaltyKickFailedJson;
+
+ /**
+ * @generated from field: GameEvent.NoProgressInGame no_progress_in_game = 2;
+ */
+ noProgressInGame?: GameEvent_NoProgressInGameJson;
+
+ /**
+ * @generated from field: GameEvent.PlacementFailed placement_failed = 3;
+ */
+ placementFailed?: GameEvent_PlacementFailedJson;
+
+ /**
+ * @generated from field: GameEvent.MultipleCards multiple_cards = 32;
+ */
+ multipleCards?: GameEvent_MultipleCardsJson;
+
+ /**
+ * @generated from field: GameEvent.MultipleFouls multiple_fouls = 34;
+ */
+ multipleFouls?: GameEvent_MultipleFoulsJson;
+
+ /**
+ * @generated from field: GameEvent.BotSubstitution bot_substitution = 37;
+ */
+ botSubstitution?: GameEvent_BotSubstitutionJson;
+
+ /**
+ * @generated from field: GameEvent.ExcessiveBotSubstitution excessive_bot_substitution = 52;
+ */
+ excessiveBotSubstitution?: GameEvent_ExcessiveBotSubstitutionJson;
+
+ /**
+ * @generated from field: GameEvent.TooManyRobots too_many_robots = 38;
+ */
+ tooManyRobots?: GameEvent_TooManyRobotsJson;
+
+ /**
+ * @generated from field: GameEvent.ChallengeFlag challenge_flag = 46;
+ */
+ challengeFlag?: GameEvent_ChallengeFlagJson;
+
+ /**
+ * @generated from field: GameEvent.ChallengeFlagHandled challenge_flag_handled = 48;
+ */
+ challengeFlagHandled?: GameEvent_ChallengeFlagHandledJson;
+
+ /**
+ * @generated from field: GameEvent.EmergencyStop emergency_stop = 47;
+ */
+ emergencyStop?: GameEvent_EmergencyStopJson;
+
+ /**
+ * @generated from field: GameEvent.UnsportingBehaviorMinor unsporting_behavior_minor = 35;
+ */
+ unsportingBehaviorMinor?: GameEvent_UnsportingBehaviorMinorJson;
+
+ /**
+ * @generated from field: GameEvent.UnsportingBehaviorMajor unsporting_behavior_major = 36;
+ */
+ unsportingBehaviorMajor?: GameEvent_UnsportingBehaviorMajorJson;
+
+ /**
+ * replaced by ready_to_continue flag
+ *
+ * @generated from field: GameEvent.Prepared prepared = 1 [deprecated = true];
+ * @deprecated
+ */
+ prepared?: GameEvent_PreparedJson;
+
+ /**
+ * obsolete
+ *
+ * @generated from field: GameEvent.IndirectGoal indirect_goal = 9 [deprecated = true];
+ * @deprecated
+ */
+ indirectGoal?: GameEvent_IndirectGoalJson;
+
+ /**
+ * replaced by the meta-information in the possible_goal event
+ *
+ * @generated from field: GameEvent.ChippedGoal chipped_goal = 10 [deprecated = true];
+ * @deprecated
+ */
+ chippedGoal?: GameEvent_ChippedGoalJson;
+
+ /**
+ * obsolete
+ *
+ * @generated from field: GameEvent.KickTimeout kick_timeout = 12 [deprecated = true];
+ * @deprecated
+ */
+ kickTimeout?: GameEvent_KickTimeoutJson;
+
+ /**
+ * rule removed
+ *
+ * @generated from field: GameEvent.AttackerTouchedOpponentInDefenseArea attacker_touched_opponent_in_defense_area = 16 [deprecated = true];
+ * @deprecated
+ */
+ attackerTouchedOpponentInDefenseArea?: GameEvent_AttackerTouchedOpponentInDefenseAreaJson;
+
+ /**
+ * obsolete
+ *
+ * @generated from field: GameEvent.AttackerTouchedOpponentInDefenseArea attacker_touched_opponent_in_defense_area_skipped = 42 [deprecated = true];
+ * @deprecated
+ */
+ attackerTouchedOpponentInDefenseAreaSkipped?: GameEvent_AttackerTouchedOpponentInDefenseAreaJson;
+
+ /**
+ * obsolete
+ *
+ * @generated from field: GameEvent.BotCrashUnique bot_crash_unique_skipped = 23 [deprecated = true];
+ * @deprecated
+ */
+ botCrashUniqueSkipped?: GameEvent_BotCrashUniqueJson;
+
+ /**
+ * can not be used as long as autoRefs do not judge pushing
+ *
+ * @generated from field: GameEvent.BotPushedBot bot_pushed_bot_skipped = 25 [deprecated = true];
+ * @deprecated
+ */
+ botPushedBotSkipped?: GameEvent_BotPushedBotJson;
+
+ /**
+ * rule removed
+ *
+ * @generated from field: GameEvent.DefenderInDefenseAreaPartially defender_in_defense_area_partially = 30 [deprecated = true];
+ * @deprecated
+ */
+ defenderInDefenseAreaPartially?: GameEvent_DefenderInDefenseAreaPartiallyJson;
+
+ /**
+ * the referee msg already indicates this
+ *
+ * @generated from field: GameEvent.MultiplePlacementFailures multiple_placement_failures = 33 [deprecated = true];
+ * @deprecated
+ */
+ multiplePlacementFailures?: GameEvent_MultiplePlacementFailuresJson;
+};
+
+/**
+ * Describes the message GameEvent.
+ * Use `create(GameEventSchema)` to create a new message.
+ */
+export const GameEventSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0);
+
+/**
+ * the ball left the field normally
+ *
+ * @generated from message GameEvent.BallLeftField
+ */
+export type GameEvent_BallLeftField = Message<"GameEvent.BallLeftField"> & {
+ /**
+ * the team that last touched the ball
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that last touched the ball
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot: number;
+
+ /**
+ * the location where the ball left the field [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+};
+
+/**
+ * the ball left the field normally
+ *
+ * @generated from message GameEvent.BallLeftField
+ */
+export type GameEvent_BallLeftFieldJson = {
+ /**
+ * the team that last touched the ball
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that last touched the ball
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot?: number;
+
+ /**
+ * the location where the ball left the field [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+};
+
+/**
+ * Describes the message GameEvent.BallLeftField.
+ * Use `create(GameEvent_BallLeftFieldSchema)` to create a new message.
+ */
+export const GameEvent_BallLeftFieldSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 0);
+
+/**
+ * the ball left the field via goal line and a team committed an aimless kick
+ *
+ * @generated from message GameEvent.AimlessKick
+ */
+export type GameEvent_AimlessKick = Message<"GameEvent.AimlessKick"> & {
+ /**
+ * the team that last touched the ball
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that last touched the ball
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot: number;
+
+ /**
+ * the location where the ball left the field [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+
+ /**
+ * the location where the ball was last touched [m]
+ *
+ * @generated from field: optional Vector2 kick_location = 4;
+ */
+ kickLocation?: Vector2;
+};
+
+/**
+ * the ball left the field via goal line and a team committed an aimless kick
+ *
+ * @generated from message GameEvent.AimlessKick
+ */
+export type GameEvent_AimlessKickJson = {
+ /**
+ * the team that last touched the ball
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that last touched the ball
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot?: number;
+
+ /**
+ * the location where the ball left the field [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the location where the ball was last touched [m]
+ *
+ * @generated from field: optional Vector2 kick_location = 4;
+ */
+ kickLocation?: Vector2Json;
+};
+
+/**
+ * Describes the message GameEvent.AimlessKick.
+ * Use `create(GameEvent_AimlessKickSchema)` to create a new message.
+ */
+export const GameEvent_AimlessKickSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 1);
+
+/**
+ * a team shot a goal
+ *
+ * @generated from message GameEvent.Goal
+ */
+export type GameEvent_Goal = Message<"GameEvent.Goal"> & {
+ /**
+ * the team that scored the goal
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the team that shot the goal (different from by_team for own goals)
+ *
+ * @generated from field: optional Team kicking_team = 6;
+ */
+ kickingTeam: Team;
+
+ /**
+ * the bot that shot the goal
+ *
+ * @generated from field: optional uint32 kicking_bot = 2;
+ */
+ kickingBot: number;
+
+ /**
+ * the location where the ball entered the goal [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+
+ /**
+ * the location where the ball was kicked (for deciding if this was a valid goal) [m]
+ *
+ * @generated from field: optional Vector2 kick_location = 4;
+ */
+ kickLocation?: Vector2;
+
+ /**
+ * the maximum height the ball reached during the goal kick (for deciding if this was a valid goal) [m]
+ *
+ * @generated from field: optional float max_ball_height = 5;
+ */
+ maxBallHeight: number;
+
+ /**
+ * number of robots of scoring team when the ball entered the goal (for deciding if this was a valid goal)
+ *
+ * @generated from field: optional uint32 num_robots_by_team = 7;
+ */
+ numRobotsByTeam: number;
+
+ /**
+ * The UNIX timestamp [μs] when the scoring team last touched the ball
+ *
+ * @generated from field: optional uint64 last_touch_by_team = 8;
+ */
+ lastTouchByTeam: bigint;
+
+ /**
+ * An additional message with e.g. a reason for invalid goals
+ *
+ * @generated from field: optional string message = 9;
+ */
+ message: string;
+};
+
+/**
+ * a team shot a goal
+ *
+ * @generated from message GameEvent.Goal
+ */
+export type GameEvent_GoalJson = {
+ /**
+ * the team that scored the goal
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the team that shot the goal (different from by_team for own goals)
+ *
+ * @generated from field: optional Team kicking_team = 6;
+ */
+ kickingTeam?: TeamJson;
+
+ /**
+ * the bot that shot the goal
+ *
+ * @generated from field: optional uint32 kicking_bot = 2;
+ */
+ kickingBot?: number;
+
+ /**
+ * the location where the ball entered the goal [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the location where the ball was kicked (for deciding if this was a valid goal) [m]
+ *
+ * @generated from field: optional Vector2 kick_location = 4;
+ */
+ kickLocation?: Vector2Json;
+
+ /**
+ * the maximum height the ball reached during the goal kick (for deciding if this was a valid goal) [m]
+ *
+ * @generated from field: optional float max_ball_height = 5;
+ */
+ maxBallHeight?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * number of robots of scoring team when the ball entered the goal (for deciding if this was a valid goal)
+ *
+ * @generated from field: optional uint32 num_robots_by_team = 7;
+ */
+ numRobotsByTeam?: number;
+
+ /**
+ * The UNIX timestamp [μs] when the scoring team last touched the ball
+ *
+ * @generated from field: optional uint64 last_touch_by_team = 8;
+ */
+ lastTouchByTeam?: string;
+
+ /**
+ * An additional message with e.g. a reason for invalid goals
+ *
+ * @generated from field: optional string message = 9;
+ */
+ message?: string;
+};
+
+/**
+ * Describes the message GameEvent.Goal.
+ * Use `create(GameEvent_GoalSchema)` to create a new message.
+ */
+export const GameEvent_GoalSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 2);
+
+/**
+ * the ball entered the goal directly during an indirect free kick
+ *
+ * @generated from message GameEvent.IndirectGoal
+ */
+export type GameEvent_IndirectGoal = Message<"GameEvent.IndirectGoal"> & {
+ /**
+ * the team that tried to shoot the goal
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that kicked the ball - at least the team must be set
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot: number;
+
+ /**
+ * the location where the ball entered the goal [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+
+ /**
+ * the location where the ball was kicked [m]
+ *
+ * @generated from field: optional Vector2 kick_location = 4;
+ */
+ kickLocation?: Vector2;
+};
+
+/**
+ * the ball entered the goal directly during an indirect free kick
+ *
+ * @generated from message GameEvent.IndirectGoal
+ */
+export type GameEvent_IndirectGoalJson = {
+ /**
+ * the team that tried to shoot the goal
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that kicked the ball - at least the team must be set
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot?: number;
+
+ /**
+ * the location where the ball entered the goal [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the location where the ball was kicked [m]
+ *
+ * @generated from field: optional Vector2 kick_location = 4;
+ */
+ kickLocation?: Vector2Json;
+};
+
+/**
+ * Describes the message GameEvent.IndirectGoal.
+ * Use `create(GameEvent_IndirectGoalSchema)` to create a new message.
+ */
+export const GameEvent_IndirectGoalSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 3);
+
+/**
+ * the ball entered the goal, but was initially chipped
+ *
+ * @generated from message GameEvent.ChippedGoal
+ */
+export type GameEvent_ChippedGoal = Message<"GameEvent.ChippedGoal"> & {
+ /**
+ * the team that tried to shoot the goal
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that kicked the ball
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot: number;
+
+ /**
+ * the location where the ball entered the goal [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+
+ /**
+ * the location where the ball was kicked [m]
+ *
+ * @generated from field: optional Vector2 kick_location = 4;
+ */
+ kickLocation?: Vector2;
+
+ /**
+ * the maximum height [m] of the ball, before it entered the goal and since the last kick [m]
+ *
+ * @generated from field: optional float max_ball_height = 5;
+ */
+ maxBallHeight: number;
+};
+
+/**
+ * the ball entered the goal, but was initially chipped
+ *
+ * @generated from message GameEvent.ChippedGoal
+ */
+export type GameEvent_ChippedGoalJson = {
+ /**
+ * the team that tried to shoot the goal
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that kicked the ball
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot?: number;
+
+ /**
+ * the location where the ball entered the goal [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the location where the ball was kicked [m]
+ *
+ * @generated from field: optional Vector2 kick_location = 4;
+ */
+ kickLocation?: Vector2Json;
+
+ /**
+ * the maximum height [m] of the ball, before it entered the goal and since the last kick [m]
+ *
+ * @generated from field: optional float max_ball_height = 5;
+ */
+ maxBallHeight?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message GameEvent.ChippedGoal.
+ * Use `create(GameEvent_ChippedGoalSchema)` to create a new message.
+ */
+export const GameEvent_ChippedGoalSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 4);
+
+/**
+ * a bot moved too fast while the game was stopped
+ *
+ * @generated from message GameEvent.BotTooFastInStop
+ */
+export type GameEvent_BotTooFastInStop = Message<"GameEvent.BotTooFastInStop"> & {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that was too fast
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot: number;
+
+ /**
+ * the location of the bot [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+
+ /**
+ * the bot speed [m/s]
+ *
+ * @generated from field: optional float speed = 4;
+ */
+ speed: number;
+};
+
+/**
+ * a bot moved too fast while the game was stopped
+ *
+ * @generated from message GameEvent.BotTooFastInStop
+ */
+export type GameEvent_BotTooFastInStopJson = {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that was too fast
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot?: number;
+
+ /**
+ * the location of the bot [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the bot speed [m/s]
+ *
+ * @generated from field: optional float speed = 4;
+ */
+ speed?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message GameEvent.BotTooFastInStop.
+ * Use `create(GameEvent_BotTooFastInStopSchema)` to create a new message.
+ */
+export const GameEvent_BotTooFastInStopSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 5);
+
+/**
+ * a bot of the defending team got too close to the kick point during a free kick
+ *
+ * @generated from message GameEvent.DefenderTooCloseToKickPoint
+ */
+export type GameEvent_DefenderTooCloseToKickPoint = Message<"GameEvent.DefenderTooCloseToKickPoint"> & {
+ /**
+ * the team that was found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that violates the distance to the kick point
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot: number;
+
+ /**
+ * the location of the bot [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+
+ /**
+ * the distance [m] from bot to the kick point (including the minimum radius)
+ *
+ * @generated from field: optional float distance = 4;
+ */
+ distance: number;
+};
+
+/**
+ * a bot of the defending team got too close to the kick point during a free kick
+ *
+ * @generated from message GameEvent.DefenderTooCloseToKickPoint
+ */
+export type GameEvent_DefenderTooCloseToKickPointJson = {
+ /**
+ * the team that was found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that violates the distance to the kick point
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot?: number;
+
+ /**
+ * the location of the bot [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the distance [m] from bot to the kick point (including the minimum radius)
+ *
+ * @generated from field: optional float distance = 4;
+ */
+ distance?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message GameEvent.DefenderTooCloseToKickPoint.
+ * Use `create(GameEvent_DefenderTooCloseToKickPointSchema)` to create a new message.
+ */
+export const GameEvent_DefenderTooCloseToKickPointSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 6);
+
+/**
+ * two robots crashed into each other with similar speeds
+ *
+ * @generated from message GameEvent.BotCrashDrawn
+ */
+export type GameEvent_BotCrashDrawn = Message<"GameEvent.BotCrashDrawn"> & {
+ /**
+ * the bot of the yellow team
+ *
+ * @generated from field: optional uint32 bot_yellow = 1;
+ */
+ botYellow: number;
+
+ /**
+ * the bot of the blue team
+ *
+ * @generated from field: optional uint32 bot_blue = 2;
+ */
+ botBlue: number;
+
+ /**
+ * the location of the crash (center between both bots) [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+
+ /**
+ * the calculated crash speed [m/s] of the two bots
+ *
+ * @generated from field: optional float crash_speed = 4;
+ */
+ crashSpeed: number;
+
+ /**
+ * the difference [m/s] of the velocity of the two bots
+ *
+ * @generated from field: optional float speed_diff = 5;
+ */
+ speedDiff: number;
+
+ /**
+ * the angle [rad] in the range [0, π] of the bot velocity vectors
+ * an angle of 0 rad ( 0°) means, the bots barely touched each other
+ * an angle of π rad (180°) means, the bots crashed frontal into each other
+ *
+ * @generated from field: optional float crash_angle = 6;
+ */
+ crashAngle: number;
+};
+
+/**
+ * two robots crashed into each other with similar speeds
+ *
+ * @generated from message GameEvent.BotCrashDrawn
+ */
+export type GameEvent_BotCrashDrawnJson = {
+ /**
+ * the bot of the yellow team
+ *
+ * @generated from field: optional uint32 bot_yellow = 1;
+ */
+ botYellow?: number;
+
+ /**
+ * the bot of the blue team
+ *
+ * @generated from field: optional uint32 bot_blue = 2;
+ */
+ botBlue?: number;
+
+ /**
+ * the location of the crash (center between both bots) [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the calculated crash speed [m/s] of the two bots
+ *
+ * @generated from field: optional float crash_speed = 4;
+ */
+ crashSpeed?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * the difference [m/s] of the velocity of the two bots
+ *
+ * @generated from field: optional float speed_diff = 5;
+ */
+ speedDiff?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * the angle [rad] in the range [0, π] of the bot velocity vectors
+ * an angle of 0 rad ( 0°) means, the bots barely touched each other
+ * an angle of π rad (180°) means, the bots crashed frontal into each other
+ *
+ * @generated from field: optional float crash_angle = 6;
+ */
+ crashAngle?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message GameEvent.BotCrashDrawn.
+ * Use `create(GameEvent_BotCrashDrawnSchema)` to create a new message.
+ */
+export const GameEvent_BotCrashDrawnSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 7);
+
+/**
+ * two robots crashed into each other and one team was found guilty to due significant speed difference
+ *
+ * @generated from message GameEvent.BotCrashUnique
+ */
+export type GameEvent_BotCrashUnique = Message<"GameEvent.BotCrashUnique"> & {
+ /**
+ * the team that caused the crash
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that caused the crash
+ *
+ * @generated from field: optional uint32 violator = 2;
+ */
+ violator: number;
+
+ /**
+ * the bot of the opposite team that was involved in the crash
+ *
+ * @generated from field: optional uint32 victim = 3;
+ */
+ victim: number;
+
+ /**
+ * the location of the crash (center between both bots) [m]
+ *
+ * @generated from field: optional Vector2 location = 4;
+ */
+ location?: Vector2;
+
+ /**
+ * the calculated crash speed vector [m/s] of the two bots
+ *
+ * @generated from field: optional float crash_speed = 5;
+ */
+ crashSpeed: number;
+
+ /**
+ * the difference [m/s] of the velocity of the two bots
+ *
+ * @generated from field: optional float speed_diff = 6;
+ */
+ speedDiff: number;
+
+ /**
+ * the angle [rad] in the range [0, π] of the bot velocity vectors
+ * an angle of 0 rad ( 0°) means, the bots barely touched each other
+ * an angle of π rad (180°) means, the bots crashed frontal into each other
+ *
+ * @generated from field: optional float crash_angle = 7;
+ */
+ crashAngle: number;
+};
+
+/**
+ * two robots crashed into each other and one team was found guilty to due significant speed difference
+ *
+ * @generated from message GameEvent.BotCrashUnique
+ */
+export type GameEvent_BotCrashUniqueJson = {
+ /**
+ * the team that caused the crash
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that caused the crash
+ *
+ * @generated from field: optional uint32 violator = 2;
+ */
+ violator?: number;
+
+ /**
+ * the bot of the opposite team that was involved in the crash
+ *
+ * @generated from field: optional uint32 victim = 3;
+ */
+ victim?: number;
+
+ /**
+ * the location of the crash (center between both bots) [m]
+ *
+ * @generated from field: optional Vector2 location = 4;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the calculated crash speed vector [m/s] of the two bots
+ *
+ * @generated from field: optional float crash_speed = 5;
+ */
+ crashSpeed?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * the difference [m/s] of the velocity of the two bots
+ *
+ * @generated from field: optional float speed_diff = 6;
+ */
+ speedDiff?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * the angle [rad] in the range [0, π] of the bot velocity vectors
+ * an angle of 0 rad ( 0°) means, the bots barely touched each other
+ * an angle of π rad (180°) means, the bots crashed frontal into each other
+ *
+ * @generated from field: optional float crash_angle = 7;
+ */
+ crashAngle?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message GameEvent.BotCrashUnique.
+ * Use `create(GameEvent_BotCrashUniqueSchema)` to create a new message.
+ */
+export const GameEvent_BotCrashUniqueSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 8);
+
+/**
+ * a bot pushed another bot over a significant distance
+ *
+ * @generated from message GameEvent.BotPushedBot
+ */
+export type GameEvent_BotPushedBot = Message<"GameEvent.BotPushedBot"> & {
+ /**
+ * the team that pushed the other team
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that pushed the other bot
+ *
+ * @generated from field: optional uint32 violator = 2;
+ */
+ violator: number;
+
+ /**
+ * the bot of the opposite team that was pushed
+ *
+ * @generated from field: optional uint32 victim = 3;
+ */
+ victim: number;
+
+ /**
+ * the location of the push (center between both bots) [m]
+ *
+ * @generated from field: optional Vector2 location = 4;
+ */
+ location?: Vector2;
+
+ /**
+ * the pushed distance [m]
+ *
+ * @generated from field: optional float pushed_distance = 5;
+ */
+ pushedDistance: number;
+};
+
+/**
+ * a bot pushed another bot over a significant distance
+ *
+ * @generated from message GameEvent.BotPushedBot
+ */
+export type GameEvent_BotPushedBotJson = {
+ /**
+ * the team that pushed the other team
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that pushed the other bot
+ *
+ * @generated from field: optional uint32 violator = 2;
+ */
+ violator?: number;
+
+ /**
+ * the bot of the opposite team that was pushed
+ *
+ * @generated from field: optional uint32 victim = 3;
+ */
+ victim?: number;
+
+ /**
+ * the location of the push (center between both bots) [m]
+ *
+ * @generated from field: optional Vector2 location = 4;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the pushed distance [m]
+ *
+ * @generated from field: optional float pushed_distance = 5;
+ */
+ pushedDistance?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message GameEvent.BotPushedBot.
+ * Use `create(GameEvent_BotPushedBotSchema)` to create a new message.
+ */
+export const GameEvent_BotPushedBotSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 9);
+
+/**
+ * a bot tipped over
+ *
+ * @generated from message GameEvent.BotTippedOver
+ */
+export type GameEvent_BotTippedOver = Message<"GameEvent.BotTippedOver"> & {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that tipped over
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot: number;
+
+ /**
+ * the location of the bot [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+
+ /**
+ * the location of the ball at the moment when this foul occurred [m]
+ *
+ * @generated from field: optional Vector2 ball_location = 4;
+ */
+ ballLocation?: Vector2;
+};
+
+/**
+ * a bot tipped over
+ *
+ * @generated from message GameEvent.BotTippedOver
+ */
+export type GameEvent_BotTippedOverJson = {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that tipped over
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot?: number;
+
+ /**
+ * the location of the bot [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the location of the ball at the moment when this foul occurred [m]
+ *
+ * @generated from field: optional Vector2 ball_location = 4;
+ */
+ ballLocation?: Vector2Json;
+};
+
+/**
+ * Describes the message GameEvent.BotTippedOver.
+ * Use `create(GameEvent_BotTippedOverSchema)` to create a new message.
+ */
+export const GameEvent_BotTippedOverSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 10);
+
+/**
+ * a bot dropped parts
+ *
+ * @generated from message GameEvent.BotDroppedParts
+ */
+export type GameEvent_BotDroppedParts = Message<"GameEvent.BotDroppedParts"> & {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that dropped the parts
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot: number;
+
+ /**
+ * the location where the parts were dropped [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+
+ /**
+ * the location of the ball at the moment when this foul occurred [m]
+ *
+ * @generated from field: optional Vector2 ball_location = 4;
+ */
+ ballLocation?: Vector2;
+};
+
+/**
+ * a bot dropped parts
+ *
+ * @generated from message GameEvent.BotDroppedParts
+ */
+export type GameEvent_BotDroppedPartsJson = {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that dropped the parts
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot?: number;
+
+ /**
+ * the location where the parts were dropped [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the location of the ball at the moment when this foul occurred [m]
+ *
+ * @generated from field: optional Vector2 ball_location = 4;
+ */
+ ballLocation?: Vector2Json;
+};
+
+/**
+ * Describes the message GameEvent.BotDroppedParts.
+ * Use `create(GameEvent_BotDroppedPartsSchema)` to create a new message.
+ */
+export const GameEvent_BotDroppedPartsSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 11);
+
+/**
+ * a defender other than the keeper was fully located inside its own defense and touched the ball
+ *
+ * @generated from message GameEvent.DefenderInDefenseArea
+ */
+export type GameEvent_DefenderInDefenseArea = Message<"GameEvent.DefenderInDefenseArea"> & {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that is inside the penalty area
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot: number;
+
+ /**
+ * the location of the bot [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+
+ /**
+ * the distance [m] from bot case to the nearest point outside the defense area
+ *
+ * @generated from field: optional float distance = 4;
+ */
+ distance: number;
+};
+
+/**
+ * a defender other than the keeper was fully located inside its own defense and touched the ball
+ *
+ * @generated from message GameEvent.DefenderInDefenseArea
+ */
+export type GameEvent_DefenderInDefenseAreaJson = {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that is inside the penalty area
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot?: number;
+
+ /**
+ * the location of the bot [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the distance [m] from bot case to the nearest point outside the defense area
+ *
+ * @generated from field: optional float distance = 4;
+ */
+ distance?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message GameEvent.DefenderInDefenseArea.
+ * Use `create(GameEvent_DefenderInDefenseAreaSchema)` to create a new message.
+ */
+export const GameEvent_DefenderInDefenseAreaSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 12);
+
+/**
+ * a defender other than the keeper was partially located inside its own defense area and touched the ball
+ *
+ * @generated from message GameEvent.DefenderInDefenseAreaPartially
+ */
+export type GameEvent_DefenderInDefenseAreaPartially = Message<"GameEvent.DefenderInDefenseAreaPartially"> & {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that is partially inside the penalty area
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot: number;
+
+ /**
+ * the location of the bot
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+
+ /**
+ * the distance [m] that the bot is inside the penalty area
+ *
+ * @generated from field: optional float distance = 4;
+ */
+ distance: number;
+
+ /**
+ * the location of the ball at the moment when this foul occurred [m]
+ *
+ * @generated from field: optional Vector2 ball_location = 5;
+ */
+ ballLocation?: Vector2;
+};
+
+/**
+ * a defender other than the keeper was partially located inside its own defense area and touched the ball
+ *
+ * @generated from message GameEvent.DefenderInDefenseAreaPartially
+ */
+export type GameEvent_DefenderInDefenseAreaPartiallyJson = {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that is partially inside the penalty area
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot?: number;
+
+ /**
+ * the location of the bot
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the distance [m] that the bot is inside the penalty area
+ *
+ * @generated from field: optional float distance = 4;
+ */
+ distance?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * the location of the ball at the moment when this foul occurred [m]
+ *
+ * @generated from field: optional Vector2 ball_location = 5;
+ */
+ ballLocation?: Vector2Json;
+};
+
+/**
+ * Describes the message GameEvent.DefenderInDefenseAreaPartially.
+ * Use `create(GameEvent_DefenderInDefenseAreaPartiallySchema)` to create a new message.
+ */
+export const GameEvent_DefenderInDefenseAreaPartiallySchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 13);
+
+/**
+ * an attacker touched the ball inside the opponent defense area
+ *
+ * @generated from message GameEvent.AttackerTouchedBallInDefenseArea
+ */
+export type GameEvent_AttackerTouchedBallInDefenseArea = Message<"GameEvent.AttackerTouchedBallInDefenseArea"> & {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that is inside the penalty area
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot: number;
+
+ /**
+ * the location of the bot [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+
+ /**
+ * the distance [m] that the bot is inside the penalty area
+ *
+ * @generated from field: optional float distance = 4;
+ */
+ distance: number;
+};
+
+/**
+ * an attacker touched the ball inside the opponent defense area
+ *
+ * @generated from message GameEvent.AttackerTouchedBallInDefenseArea
+ */
+export type GameEvent_AttackerTouchedBallInDefenseAreaJson = {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that is inside the penalty area
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot?: number;
+
+ /**
+ * the location of the bot [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the distance [m] that the bot is inside the penalty area
+ *
+ * @generated from field: optional float distance = 4;
+ */
+ distance?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message GameEvent.AttackerTouchedBallInDefenseArea.
+ * Use `create(GameEvent_AttackerTouchedBallInDefenseAreaSchema)` to create a new message.
+ */
+export const GameEvent_AttackerTouchedBallInDefenseAreaSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 14);
+
+/**
+ * a bot kicked the ball too fast
+ *
+ * @generated from message GameEvent.BotKickedBallTooFast
+ */
+export type GameEvent_BotKickedBallTooFast = Message<"GameEvent.BotKickedBallTooFast"> & {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that kicked too fast
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot: number;
+
+ /**
+ * the location of the ball at the time of the highest speed [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+
+ /**
+ * the absolute initial ball speed (kick speed) [m/s]
+ *
+ * @generated from field: optional float initial_ball_speed = 4;
+ */
+ initialBallSpeed: number;
+
+ /**
+ * was the ball chipped?
+ *
+ * @generated from field: optional bool chipped = 5;
+ */
+ chipped: boolean;
+};
+
+/**
+ * a bot kicked the ball too fast
+ *
+ * @generated from message GameEvent.BotKickedBallTooFast
+ */
+export type GameEvent_BotKickedBallTooFastJson = {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that kicked too fast
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot?: number;
+
+ /**
+ * the location of the ball at the time of the highest speed [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the absolute initial ball speed (kick speed) [m/s]
+ *
+ * @generated from field: optional float initial_ball_speed = 4;
+ */
+ initialBallSpeed?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * was the ball chipped?
+ *
+ * @generated from field: optional bool chipped = 5;
+ */
+ chipped?: boolean;
+};
+
+/**
+ * Describes the message GameEvent.BotKickedBallTooFast.
+ * Use `create(GameEvent_BotKickedBallTooFastSchema)` to create a new message.
+ */
+export const GameEvent_BotKickedBallTooFastSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 15);
+
+/**
+ * a bot dribbled to ball too far
+ *
+ * @generated from message GameEvent.BotDribbledBallTooFar
+ */
+export type GameEvent_BotDribbledBallTooFar = Message<"GameEvent.BotDribbledBallTooFar"> & {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that dribbled too far
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot: number;
+
+ /**
+ * the location where the dribbling started [m]
+ *
+ * @generated from field: optional Vector2 start = 3;
+ */
+ start?: Vector2;
+
+ /**
+ * the location where the maximum dribbling distance was reached [m]
+ *
+ * @generated from field: optional Vector2 end = 4;
+ */
+ end?: Vector2;
+};
+
+/**
+ * a bot dribbled to ball too far
+ *
+ * @generated from message GameEvent.BotDribbledBallTooFar
+ */
+export type GameEvent_BotDribbledBallTooFarJson = {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that dribbled too far
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot?: number;
+
+ /**
+ * the location where the dribbling started [m]
+ *
+ * @generated from field: optional Vector2 start = 3;
+ */
+ start?: Vector2Json;
+
+ /**
+ * the location where the maximum dribbling distance was reached [m]
+ *
+ * @generated from field: optional Vector2 end = 4;
+ */
+ end?: Vector2Json;
+};
+
+/**
+ * Describes the message GameEvent.BotDribbledBallTooFar.
+ * Use `create(GameEvent_BotDribbledBallTooFarSchema)` to create a new message.
+ */
+export const GameEvent_BotDribbledBallTooFarSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 16);
+
+/**
+ * an attacker touched the opponent robot inside defense area
+ *
+ * @generated from message GameEvent.AttackerTouchedOpponentInDefenseArea
+ */
+export type GameEvent_AttackerTouchedOpponentInDefenseArea = Message<"GameEvent.AttackerTouchedOpponentInDefenseArea"> & {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that touched the opponent robot
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot: number;
+
+ /**
+ * the bot of the opposite team that was touched
+ *
+ * @generated from field: optional uint32 victim = 4;
+ */
+ victim: number;
+
+ /**
+ * the location of the contact point between both bots [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+};
+
+/**
+ * an attacker touched the opponent robot inside defense area
+ *
+ * @generated from message GameEvent.AttackerTouchedOpponentInDefenseArea
+ */
+export type GameEvent_AttackerTouchedOpponentInDefenseAreaJson = {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that touched the opponent robot
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot?: number;
+
+ /**
+ * the bot of the opposite team that was touched
+ *
+ * @generated from field: optional uint32 victim = 4;
+ */
+ victim?: number;
+
+ /**
+ * the location of the contact point between both bots [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+};
+
+/**
+ * Describes the message GameEvent.AttackerTouchedOpponentInDefenseArea.
+ * Use `create(GameEvent_AttackerTouchedOpponentInDefenseAreaSchema)` to create a new message.
+ */
+export const GameEvent_AttackerTouchedOpponentInDefenseAreaSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 17);
+
+/**
+ * an attacker touched the ball multiple times when it was not allowed to
+ *
+ * @generated from message GameEvent.AttackerDoubleTouchedBall
+ */
+export type GameEvent_AttackerDoubleTouchedBall = Message<"GameEvent.AttackerDoubleTouchedBall"> & {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that touched the ball twice
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot: number;
+
+ /**
+ * the location of the ball when it was first touched [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+};
+
+/**
+ * an attacker touched the ball multiple times when it was not allowed to
+ *
+ * @generated from message GameEvent.AttackerDoubleTouchedBall
+ */
+export type GameEvent_AttackerDoubleTouchedBallJson = {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that touched the ball twice
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot?: number;
+
+ /**
+ * the location of the ball when it was first touched [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+};
+
+/**
+ * Describes the message GameEvent.AttackerDoubleTouchedBall.
+ * Use `create(GameEvent_AttackerDoubleTouchedBallSchema)` to create a new message.
+ */
+export const GameEvent_AttackerDoubleTouchedBallSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 18);
+
+/**
+ * an attacker was located too near to the opponent defense area during stop or free kick
+ *
+ * @generated from message GameEvent.AttackerTooCloseToDefenseArea
+ */
+export type GameEvent_AttackerTooCloseToDefenseArea = Message<"GameEvent.AttackerTooCloseToDefenseArea"> & {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that is too close to the defense area
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot: number;
+
+ /**
+ * the location of the bot [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+
+ /**
+ * the distance [m] of the bot to the penalty area
+ *
+ * @generated from field: optional float distance = 4;
+ */
+ distance: number;
+
+ /**
+ * the location of the ball at the moment when this foul occurred [m]
+ *
+ * @generated from field: optional Vector2 ball_location = 5;
+ */
+ ballLocation?: Vector2;
+};
+
+/**
+ * an attacker was located too near to the opponent defense area during stop or free kick
+ *
+ * @generated from message GameEvent.AttackerTooCloseToDefenseArea
+ */
+export type GameEvent_AttackerTooCloseToDefenseAreaJson = {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that is too close to the defense area
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot?: number;
+
+ /**
+ * the location of the bot [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the distance [m] of the bot to the penalty area
+ *
+ * @generated from field: optional float distance = 4;
+ */
+ distance?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * the location of the ball at the moment when this foul occurred [m]
+ *
+ * @generated from field: optional Vector2 ball_location = 5;
+ */
+ ballLocation?: Vector2Json;
+};
+
+/**
+ * Describes the message GameEvent.AttackerTooCloseToDefenseArea.
+ * Use `create(GameEvent_AttackerTooCloseToDefenseAreaSchema)` to create a new message.
+ */
+export const GameEvent_AttackerTooCloseToDefenseAreaSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 19);
+
+/**
+ * a bot held the ball for too long
+ *
+ * @generated from message GameEvent.BotHeldBallDeliberately
+ */
+export type GameEvent_BotHeldBallDeliberately = Message<"GameEvent.BotHeldBallDeliberately"> & {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that holds the ball
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot: number;
+
+ /**
+ * the location of the ball [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+
+ /**
+ * the duration [s] that the bot hold the ball
+ *
+ * @generated from field: optional float duration = 4;
+ */
+ duration: number;
+};
+
+/**
+ * a bot held the ball for too long
+ *
+ * @generated from message GameEvent.BotHeldBallDeliberately
+ */
+export type GameEvent_BotHeldBallDeliberatelyJson = {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that holds the ball
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot?: number;
+
+ /**
+ * the location of the ball [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the duration [s] that the bot hold the ball
+ *
+ * @generated from field: optional float duration = 4;
+ */
+ duration?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message GameEvent.BotHeldBallDeliberately.
+ * Use `create(GameEvent_BotHeldBallDeliberatelySchema)` to create a new message.
+ */
+export const GameEvent_BotHeldBallDeliberatelySchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 20);
+
+/**
+ * a bot interfered the ball placement of the other team
+ *
+ * @generated from message GameEvent.BotInterferedPlacement
+ */
+export type GameEvent_BotInterferedPlacement = Message<"GameEvent.BotInterferedPlacement"> & {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the bot that interfered the placement
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot: number;
+
+ /**
+ * the location of the bot [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2;
+};
+
+/**
+ * a bot interfered the ball placement of the other team
+ *
+ * @generated from message GameEvent.BotInterferedPlacement
+ */
+export type GameEvent_BotInterferedPlacementJson = {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the bot that interfered the placement
+ *
+ * @generated from field: optional uint32 by_bot = 2;
+ */
+ byBot?: number;
+
+ /**
+ * the location of the bot [m]
+ *
+ * @generated from field: optional Vector2 location = 3;
+ */
+ location?: Vector2Json;
+};
+
+/**
+ * Describes the message GameEvent.BotInterferedPlacement.
+ * Use `create(GameEvent_BotInterferedPlacementSchema)` to create a new message.
+ */
+export const GameEvent_BotInterferedPlacementSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 21);
+
+/**
+ * a team collected multiple yellow cards
+ *
+ * @generated from message GameEvent.MultipleCards
+ */
+export type GameEvent_MultipleCards = Message<"GameEvent.MultipleCards"> & {
+ /**
+ * the team that received multiple yellow cards
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+};
+
+/**
+ * a team collected multiple yellow cards
+ *
+ * @generated from message GameEvent.MultipleCards
+ */
+export type GameEvent_MultipleCardsJson = {
+ /**
+ * the team that received multiple yellow cards
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+};
+
+/**
+ * Describes the message GameEvent.MultipleCards.
+ * Use `create(GameEvent_MultipleCardsSchema)` to create a new message.
+ */
+export const GameEvent_MultipleCardsSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 22);
+
+/**
+ * a team collected multiple fouls, which results in a yellow card
+ *
+ * @generated from message GameEvent.MultipleFouls
+ */
+export type GameEvent_MultipleFouls = Message<"GameEvent.MultipleFouls"> & {
+ /**
+ * the team that collected multiple fouls
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the list of game events that caused the multiple fouls
+ *
+ * @generated from field: repeated GameEvent caused_game_events = 2;
+ */
+ causedGameEvents: GameEvent[];
+};
+
+/**
+ * a team collected multiple fouls, which results in a yellow card
+ *
+ * @generated from message GameEvent.MultipleFouls
+ */
+export type GameEvent_MultipleFoulsJson = {
+ /**
+ * the team that collected multiple fouls
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the list of game events that caused the multiple fouls
+ *
+ * @generated from field: repeated GameEvent caused_game_events = 2;
+ */
+ causedGameEvents?: GameEventJson[];
+};
+
+/**
+ * Describes the message GameEvent.MultipleFouls.
+ * Use `create(GameEvent_MultipleFoulsSchema)` to create a new message.
+ */
+export const GameEvent_MultipleFoulsSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 23);
+
+/**
+ * a team failed to place the ball multiple times in a row
+ *
+ * @generated from message GameEvent.MultiplePlacementFailures
+ */
+export type GameEvent_MultiplePlacementFailures = Message<"GameEvent.MultiplePlacementFailures"> & {
+ /**
+ * the team that failed multiple times
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+};
+
+/**
+ * a team failed to place the ball multiple times in a row
+ *
+ * @generated from message GameEvent.MultiplePlacementFailures
+ */
+export type GameEvent_MultiplePlacementFailuresJson = {
+ /**
+ * the team that failed multiple times
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+};
+
+/**
+ * Describes the message GameEvent.MultiplePlacementFailures.
+ * Use `create(GameEvent_MultiplePlacementFailuresSchema)` to create a new message.
+ */
+export const GameEvent_MultiplePlacementFailuresSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 24);
+
+/**
+ * timeout waiting for the attacking team to perform the free kick
+ *
+ * @generated from message GameEvent.KickTimeout
+ */
+export type GameEvent_KickTimeout = Message<"GameEvent.KickTimeout"> & {
+ /**
+ * the team that that should have kicked
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the location of the ball [m]
+ *
+ * @generated from field: optional Vector2 location = 2;
+ */
+ location?: Vector2;
+
+ /**
+ * the time [s] that was waited
+ *
+ * @generated from field: optional float time = 3;
+ */
+ time: number;
+};
+
+/**
+ * timeout waiting for the attacking team to perform the free kick
+ *
+ * @generated from message GameEvent.KickTimeout
+ */
+export type GameEvent_KickTimeoutJson = {
+ /**
+ * the team that that should have kicked
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the location of the ball [m]
+ *
+ * @generated from field: optional Vector2 location = 2;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the time [s] that was waited
+ *
+ * @generated from field: optional float time = 3;
+ */
+ time?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message GameEvent.KickTimeout.
+ * Use `create(GameEvent_KickTimeoutSchema)` to create a new message.
+ */
+export const GameEvent_KickTimeoutSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 25);
+
+/**
+ * game was stuck
+ *
+ * @generated from message GameEvent.NoProgressInGame
+ */
+export type GameEvent_NoProgressInGame = Message<"GameEvent.NoProgressInGame"> & {
+ /**
+ * the location of the ball
+ *
+ * @generated from field: optional Vector2 location = 1;
+ */
+ location?: Vector2;
+
+ /**
+ * the time [s] that was waited
+ *
+ * @generated from field: optional float time = 2;
+ */
+ time: number;
+};
+
+/**
+ * game was stuck
+ *
+ * @generated from message GameEvent.NoProgressInGame
+ */
+export type GameEvent_NoProgressInGameJson = {
+ /**
+ * the location of the ball
+ *
+ * @generated from field: optional Vector2 location = 1;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the time [s] that was waited
+ *
+ * @generated from field: optional float time = 2;
+ */
+ time?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message GameEvent.NoProgressInGame.
+ * Use `create(GameEvent_NoProgressInGameSchema)` to create a new message.
+ */
+export const GameEvent_NoProgressInGameSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 26);
+
+/**
+ * ball placement failed
+ *
+ * @generated from message GameEvent.PlacementFailed
+ */
+export type GameEvent_PlacementFailed = Message<"GameEvent.PlacementFailed"> & {
+ /**
+ * the team that failed
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the remaining distance [m] from ball to placement position
+ *
+ * @generated from field: optional float remaining_distance = 2;
+ */
+ remainingDistance: number;
+
+ /**
+ * the distance [m] of the nearest own robot to the ball
+ *
+ * @generated from field: optional float nearest_own_bot_distance = 3;
+ */
+ nearestOwnBotDistance: number;
+};
+
+/**
+ * ball placement failed
+ *
+ * @generated from message GameEvent.PlacementFailed
+ */
+export type GameEvent_PlacementFailedJson = {
+ /**
+ * the team that failed
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the remaining distance [m] from ball to placement position
+ *
+ * @generated from field: optional float remaining_distance = 2;
+ */
+ remainingDistance?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * the distance [m] of the nearest own robot to the ball
+ *
+ * @generated from field: optional float nearest_own_bot_distance = 3;
+ */
+ nearestOwnBotDistance?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message GameEvent.PlacementFailed.
+ * Use `create(GameEvent_PlacementFailedSchema)` to create a new message.
+ */
+export const GameEvent_PlacementFailedSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 27);
+
+/**
+ * a team was found guilty for minor unsporting behavior
+ *
+ * @generated from message GameEvent.UnsportingBehaviorMinor
+ */
+export type GameEvent_UnsportingBehaviorMinor = Message<"GameEvent.UnsportingBehaviorMinor"> & {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * an explanation of the situation and decision
+ *
+ * @generated from field: required string reason = 2;
+ */
+ reason: string;
+};
+
+/**
+ * a team was found guilty for minor unsporting behavior
+ *
+ * @generated from message GameEvent.UnsportingBehaviorMinor
+ */
+export type GameEvent_UnsportingBehaviorMinorJson = {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * an explanation of the situation and decision
+ *
+ * @generated from field: required string reason = 2;
+ */
+ reason?: string;
+};
+
+/**
+ * Describes the message GameEvent.UnsportingBehaviorMinor.
+ * Use `create(GameEvent_UnsportingBehaviorMinorSchema)` to create a new message.
+ */
+export const GameEvent_UnsportingBehaviorMinorSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 28);
+
+/**
+ * a team was found guilty for major unsporting behavior
+ *
+ * @generated from message GameEvent.UnsportingBehaviorMajor
+ */
+export type GameEvent_UnsportingBehaviorMajor = Message<"GameEvent.UnsportingBehaviorMajor"> & {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * an explanation of the situation and decision
+ *
+ * @generated from field: required string reason = 2;
+ */
+ reason: string;
+};
+
+/**
+ * a team was found guilty for major unsporting behavior
+ *
+ * @generated from message GameEvent.UnsportingBehaviorMajor
+ */
+export type GameEvent_UnsportingBehaviorMajorJson = {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * an explanation of the situation and decision
+ *
+ * @generated from field: required string reason = 2;
+ */
+ reason?: string;
+};
+
+/**
+ * Describes the message GameEvent.UnsportingBehaviorMajor.
+ * Use `create(GameEvent_UnsportingBehaviorMajorSchema)` to create a new message.
+ */
+export const GameEvent_UnsportingBehaviorMajorSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 29);
+
+/**
+ * a keeper held the ball in its defense area for too long
+ *
+ * @generated from message GameEvent.KeeperHeldBall
+ */
+export type GameEvent_KeeperHeldBall = Message<"GameEvent.KeeperHeldBall"> & {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the location of the ball [m]
+ *
+ * @generated from field: optional Vector2 location = 2;
+ */
+ location?: Vector2;
+
+ /**
+ * the duration [s] that the keeper hold the ball
+ *
+ * @generated from field: optional float duration = 3;
+ */
+ duration: number;
+};
+
+/**
+ * a keeper held the ball in its defense area for too long
+ *
+ * @generated from message GameEvent.KeeperHeldBall
+ */
+export type GameEvent_KeeperHeldBallJson = {
+ /**
+ * the team that found guilty
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the location of the ball [m]
+ *
+ * @generated from field: optional Vector2 location = 2;
+ */
+ location?: Vector2Json;
+
+ /**
+ * the duration [s] that the keeper hold the ball
+ *
+ * @generated from field: optional float duration = 3;
+ */
+ duration?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message GameEvent.KeeperHeldBall.
+ * Use `create(GameEvent_KeeperHeldBallSchema)` to create a new message.
+ */
+export const GameEvent_KeeperHeldBallSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 30);
+
+/**
+ * a team successfully placed the ball
+ *
+ * @generated from message GameEvent.PlacementSucceeded
+ */
+export type GameEvent_PlacementSucceeded = Message<"GameEvent.PlacementSucceeded"> & {
+ /**
+ * the team that did the placement
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the time [s] taken for placing the ball
+ *
+ * @generated from field: optional float time_taken = 2;
+ */
+ timeTaken: number;
+
+ /**
+ * the distance [m] between placement location and actual ball position
+ *
+ * @generated from field: optional float precision = 3;
+ */
+ precision: number;
+
+ /**
+ * the distance [m] between the initial ball location and the placement position
+ *
+ * @generated from field: optional float distance = 4;
+ */
+ distance: number;
+};
+
+/**
+ * a team successfully placed the ball
+ *
+ * @generated from message GameEvent.PlacementSucceeded
+ */
+export type GameEvent_PlacementSucceededJson = {
+ /**
+ * the team that did the placement
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the time [s] taken for placing the ball
+ *
+ * @generated from field: optional float time_taken = 2;
+ */
+ timeTaken?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * the distance [m] between placement location and actual ball position
+ *
+ * @generated from field: optional float precision = 3;
+ */
+ precision?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * the distance [m] between the initial ball location and the placement position
+ *
+ * @generated from field: optional float distance = 4;
+ */
+ distance?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message GameEvent.PlacementSucceeded.
+ * Use `create(GameEvent_PlacementSucceededSchema)` to create a new message.
+ */
+export const GameEvent_PlacementSucceededSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 31);
+
+/**
+ * both teams are prepared - all conditions are met to continue (with kickoff or penalty kick)
+ *
+ * @generated from message GameEvent.Prepared
+ */
+export type GameEvent_Prepared = Message<"GameEvent.Prepared"> & {
+ /**
+ * the time [s] taken for preparing
+ *
+ * @generated from field: optional float time_taken = 1;
+ */
+ timeTaken: number;
+};
+
+/**
+ * both teams are prepared - all conditions are met to continue (with kickoff or penalty kick)
+ *
+ * @generated from message GameEvent.Prepared
+ */
+export type GameEvent_PreparedJson = {
+ /**
+ * the time [s] taken for preparing
+ *
+ * @generated from field: optional float time_taken = 1;
+ */
+ timeTaken?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message GameEvent.Prepared.
+ * Use `create(GameEvent_PreparedSchema)` to create a new message.
+ */
+export const GameEvent_PreparedSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 32);
+
+/**
+ * bots are being substituted by a team
+ *
+ * @generated from message GameEvent.BotSubstitution
+ */
+export type GameEvent_BotSubstitution = Message<"GameEvent.BotSubstitution"> & {
+ /**
+ * the team that substitutes robots
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+};
+
+/**
+ * bots are being substituted by a team
+ *
+ * @generated from message GameEvent.BotSubstitution
+ */
+export type GameEvent_BotSubstitutionJson = {
+ /**
+ * the team that substitutes robots
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+};
+
+/**
+ * Describes the message GameEvent.BotSubstitution.
+ * Use `create(GameEvent_BotSubstitutionSchema)` to create a new message.
+ */
+export const GameEvent_BotSubstitutionSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 33);
+
+/**
+ * A foul for excessive bot substitutions
+ *
+ * @generated from message GameEvent.ExcessiveBotSubstitution
+ */
+export type GameEvent_ExcessiveBotSubstitution = Message<"GameEvent.ExcessiveBotSubstitution"> & {
+ /**
+ * the team that substitutes robots
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+};
+
+/**
+ * A foul for excessive bot substitutions
+ *
+ * @generated from message GameEvent.ExcessiveBotSubstitution
+ */
+export type GameEvent_ExcessiveBotSubstitutionJson = {
+ /**
+ * the team that substitutes robots
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+};
+
+/**
+ * Describes the message GameEvent.ExcessiveBotSubstitution.
+ * Use `create(GameEvent_ExcessiveBotSubstitutionSchema)` to create a new message.
+ */
+export const GameEvent_ExcessiveBotSubstitutionSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 34);
+
+/**
+ * A challenge flag, requested by a team previously, is flagged
+ *
+ * @generated from message GameEvent.ChallengeFlag
+ */
+export type GameEvent_ChallengeFlag = Message<"GameEvent.ChallengeFlag"> & {
+ /**
+ * the team that requested the challenge flag
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+};
+
+/**
+ * A challenge flag, requested by a team previously, is flagged
+ *
+ * @generated from message GameEvent.ChallengeFlag
+ */
+export type GameEvent_ChallengeFlagJson = {
+ /**
+ * the team that requested the challenge flag
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+};
+
+/**
+ * Describes the message GameEvent.ChallengeFlag.
+ * Use `create(GameEvent_ChallengeFlagSchema)` to create a new message.
+ */
+export const GameEvent_ChallengeFlagSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 35);
+
+/**
+ * A challenge, flagged recently, has been handled by the referee
+ *
+ * @generated from message GameEvent.ChallengeFlagHandled
+ */
+export type GameEvent_ChallengeFlagHandled = Message<"GameEvent.ChallengeFlagHandled"> & {
+ /**
+ * the team that requested the challenge flag
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the challenge was accepted by the referee
+ *
+ * @generated from field: required bool accepted = 2;
+ */
+ accepted: boolean;
+};
+
+/**
+ * A challenge, flagged recently, has been handled by the referee
+ *
+ * @generated from message GameEvent.ChallengeFlagHandled
+ */
+export type GameEvent_ChallengeFlagHandledJson = {
+ /**
+ * the team that requested the challenge flag
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the challenge was accepted by the referee
+ *
+ * @generated from field: required bool accepted = 2;
+ */
+ accepted?: boolean;
+};
+
+/**
+ * Describes the message GameEvent.ChallengeFlagHandled.
+ * Use `create(GameEvent_ChallengeFlagHandledSchema)` to create a new message.
+ */
+export const GameEvent_ChallengeFlagHandledSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 36);
+
+/**
+ * An emergency stop, requested by team previously, occurred
+ *
+ * @generated from message GameEvent.EmergencyStop
+ */
+export type GameEvent_EmergencyStop = Message<"GameEvent.EmergencyStop"> & {
+ /**
+ * the team that substitutes robots
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+};
+
+/**
+ * An emergency stop, requested by team previously, occurred
+ *
+ * @generated from message GameEvent.EmergencyStop
+ */
+export type GameEvent_EmergencyStopJson = {
+ /**
+ * the team that substitutes robots
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+};
+
+/**
+ * Describes the message GameEvent.EmergencyStop.
+ * Use `create(GameEvent_EmergencyStopSchema)` to create a new message.
+ */
+export const GameEvent_EmergencyStopSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 37);
+
+/**
+ * a team has too many robots on the field
+ *
+ * @generated from message GameEvent.TooManyRobots
+ */
+export type GameEvent_TooManyRobots = Message<"GameEvent.TooManyRobots"> & {
+ /**
+ * the team that has too many robots
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * number of robots allowed at the moment
+ *
+ * @generated from field: optional int32 num_robots_allowed = 2;
+ */
+ numRobotsAllowed: number;
+
+ /**
+ * number of robots currently on the field
+ *
+ * @generated from field: optional int32 num_robots_on_field = 3;
+ */
+ numRobotsOnField: number;
+
+ /**
+ * the location of the ball at the moment when this foul occurred [m]
+ *
+ * @generated from field: optional Vector2 ball_location = 4;
+ */
+ ballLocation?: Vector2;
+};
+
+/**
+ * a team has too many robots on the field
+ *
+ * @generated from message GameEvent.TooManyRobots
+ */
+export type GameEvent_TooManyRobotsJson = {
+ /**
+ * the team that has too many robots
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * number of robots allowed at the moment
+ *
+ * @generated from field: optional int32 num_robots_allowed = 2;
+ */
+ numRobotsAllowed?: number;
+
+ /**
+ * number of robots currently on the field
+ *
+ * @generated from field: optional int32 num_robots_on_field = 3;
+ */
+ numRobotsOnField?: number;
+
+ /**
+ * the location of the ball at the moment when this foul occurred [m]
+ *
+ * @generated from field: optional Vector2 ball_location = 4;
+ */
+ ballLocation?: Vector2Json;
+};
+
+/**
+ * Describes the message GameEvent.TooManyRobots.
+ * Use `create(GameEvent_TooManyRobotsSchema)` to create a new message.
+ */
+export const GameEvent_TooManyRobotsSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 38);
+
+/**
+ * a robot chipped the ball over the field boundary out of the playing surface
+ *
+ * @generated from message GameEvent.BoundaryCrossing
+ */
+export type GameEvent_BoundaryCrossing = Message<"GameEvent.BoundaryCrossing"> & {
+ /**
+ * the team that has too many robots
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the location of the ball [m]
+ *
+ * @generated from field: optional Vector2 location = 2;
+ */
+ location?: Vector2;
+};
+
+/**
+ * a robot chipped the ball over the field boundary out of the playing surface
+ *
+ * @generated from message GameEvent.BoundaryCrossing
+ */
+export type GameEvent_BoundaryCrossingJson = {
+ /**
+ * the team that has too many robots
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the location of the ball [m]
+ *
+ * @generated from field: optional Vector2 location = 2;
+ */
+ location?: Vector2Json;
+};
+
+/**
+ * Describes the message GameEvent.BoundaryCrossing.
+ * Use `create(GameEvent_BoundaryCrossingSchema)` to create a new message.
+ */
+export const GameEvent_BoundaryCrossingSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 39);
+
+/**
+ * the penalty kick failed (by time or by keeper)
+ *
+ * @generated from message GameEvent.PenaltyKickFailed
+ */
+export type GameEvent_PenaltyKickFailed = Message<"GameEvent.PenaltyKickFailed"> & {
+ /**
+ * the team that last touched the ball
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam: Team;
+
+ /**
+ * the location of the ball at the moment of this event [m]
+ *
+ * @generated from field: optional Vector2 location = 2;
+ */
+ location?: Vector2;
+
+ /**
+ * an explanation of the failure
+ *
+ * @generated from field: optional string reason = 3;
+ */
+ reason: string;
+};
+
+/**
+ * the penalty kick failed (by time or by keeper)
+ *
+ * @generated from message GameEvent.PenaltyKickFailed
+ */
+export type GameEvent_PenaltyKickFailedJson = {
+ /**
+ * the team that last touched the ball
+ *
+ * @generated from field: required Team by_team = 1;
+ */
+ byTeam?: TeamJson;
+
+ /**
+ * the location of the ball at the moment of this event [m]
+ *
+ * @generated from field: optional Vector2 location = 2;
+ */
+ location?: Vector2Json;
+
+ /**
+ * an explanation of the failure
+ *
+ * @generated from field: optional string reason = 3;
+ */
+ reason?: string;
+};
+
+/**
+ * Describes the message GameEvent.PenaltyKickFailed.
+ * Use `create(GameEvent_PenaltyKickFailedSchema)` to create a new message.
+ */
+export const GameEvent_PenaltyKickFailedSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 40);
+
+/**
+ * @generated from enum GameEvent.Type
+ */
+export enum GameEvent_Type {
+ /**
+ * @generated from enum value: UNKNOWN_GAME_EVENT_TYPE = 0;
+ */
+ UNKNOWN_GAME_EVENT_TYPE = 0,
+
+ /**
+ * triggered by autoRef
+ *
+ * @generated from enum value: BALL_LEFT_FIELD_TOUCH_LINE = 6;
+ */
+ BALL_LEFT_FIELD_TOUCH_LINE = 6,
+
+ /**
+ * triggered by autoRef
+ *
+ * @generated from enum value: BALL_LEFT_FIELD_GOAL_LINE = 7;
+ */
+ BALL_LEFT_FIELD_GOAL_LINE = 7,
+
+ /**
+ * triggered by autoRef
+ *
+ * @generated from enum value: AIMLESS_KICK = 11;
+ */
+ AIMLESS_KICK = 11,
+
+ /**
+ * triggered by autoRef
+ *
+ * @generated from enum value: ATTACKER_TOO_CLOSE_TO_DEFENSE_AREA = 19;
+ */
+ ATTACKER_TOO_CLOSE_TO_DEFENSE_AREA = 19,
+
+ /**
+ * triggered by autoRef
+ *
+ * @generated from enum value: DEFENDER_IN_DEFENSE_AREA = 31;
+ */
+ DEFENDER_IN_DEFENSE_AREA = 31,
+
+ /**
+ * triggered by autoRef
+ *
+ * @generated from enum value: BOUNDARY_CROSSING = 41;
+ */
+ BOUNDARY_CROSSING = 41,
+
+ /**
+ * triggered by GC
+ *
+ * @generated from enum value: KEEPER_HELD_BALL = 13;
+ */
+ KEEPER_HELD_BALL = 13,
+
+ /**
+ * triggered by autoRef
+ *
+ * @generated from enum value: BOT_DRIBBLED_BALL_TOO_FAR = 17;
+ */
+ BOT_DRIBBLED_BALL_TOO_FAR = 17,
+
+ /**
+ * triggered by human ref
+ *
+ * @generated from enum value: BOT_PUSHED_BOT = 24;
+ */
+ BOT_PUSHED_BOT = 24,
+
+ /**
+ * triggered by human ref
+ *
+ * @generated from enum value: BOT_HELD_BALL_DELIBERATELY = 26;
+ */
+ BOT_HELD_BALL_DELIBERATELY = 26,
+
+ /**
+ * triggered by human ref
+ *
+ * @generated from enum value: BOT_TIPPED_OVER = 27;
+ */
+ BOT_TIPPED_OVER = 27,
+
+ /**
+ * triggered by human ref
+ *
+ * @generated from enum value: BOT_DROPPED_PARTS = 47;
+ */
+ BOT_DROPPED_PARTS = 47,
+
+ /**
+ * triggered by autoRef
+ *
+ * @generated from enum value: ATTACKER_TOUCHED_BALL_IN_DEFENSE_AREA = 15;
+ */
+ ATTACKER_TOUCHED_BALL_IN_DEFENSE_AREA = 15,
+
+ /**
+ * triggered by autoRef
+ *
+ * @generated from enum value: BOT_KICKED_BALL_TOO_FAST = 18;
+ */
+ BOT_KICKED_BALL_TOO_FAST = 18,
+
+ /**
+ * triggered by autoRef
+ *
+ * @generated from enum value: BOT_CRASH_UNIQUE = 22;
+ */
+ BOT_CRASH_UNIQUE = 22,
+
+ /**
+ * triggered by autoRef
+ *
+ * @generated from enum value: BOT_CRASH_DRAWN = 21;
+ */
+ BOT_CRASH_DRAWN = 21,
+
+ /**
+ * triggered by autoRef
+ *
+ * @generated from enum value: DEFENDER_TOO_CLOSE_TO_KICK_POINT = 29;
+ */
+ DEFENDER_TOO_CLOSE_TO_KICK_POINT = 29,
+
+ /**
+ * triggered by autoRef
+ *
+ * @generated from enum value: BOT_TOO_FAST_IN_STOP = 28;
+ */
+ BOT_TOO_FAST_IN_STOP = 28,
+
+ /**
+ * triggered by autoRef
+ *
+ * @generated from enum value: BOT_INTERFERED_PLACEMENT = 20;
+ */
+ BOT_INTERFERED_PLACEMENT = 20,
+
+ /**
+ * triggered by GC
+ *
+ * @generated from enum value: EXCESSIVE_BOT_SUBSTITUTION = 48;
+ */
+ EXCESSIVE_BOT_SUBSTITUTION = 48,
+
+ /**
+ * triggered by autoRef
+ *
+ * @generated from enum value: POSSIBLE_GOAL = 39;
+ */
+ POSSIBLE_GOAL = 39,
+
+ /**
+ * triggered by GC
+ *
+ * @generated from enum value: GOAL = 8;
+ */
+ GOAL = 8,
+
+ /**
+ * triggered by GC
+ *
+ * @generated from enum value: INVALID_GOAL = 42;
+ */
+ INVALID_GOAL = 42,
+
+ /**
+ * triggered by autoRef
+ *
+ * @generated from enum value: ATTACKER_DOUBLE_TOUCHED_BALL = 14;
+ */
+ ATTACKER_DOUBLE_TOUCHED_BALL = 14,
+
+ /**
+ * triggered by autoRef
+ *
+ * @generated from enum value: PLACEMENT_SUCCEEDED = 5;
+ */
+ PLACEMENT_SUCCEEDED = 5,
+
+ /**
+ * triggered by GC and autoRef
+ *
+ * @generated from enum value: PENALTY_KICK_FAILED = 43;
+ */
+ PENALTY_KICK_FAILED = 43,
+
+ /**
+ * triggered by GC
+ *
+ * @generated from enum value: NO_PROGRESS_IN_GAME = 2;
+ */
+ NO_PROGRESS_IN_GAME = 2,
+
+ /**
+ * triggered by GC
+ *
+ * @generated from enum value: PLACEMENT_FAILED = 3;
+ */
+ PLACEMENT_FAILED = 3,
+
+ /**
+ * triggered by GC
+ *
+ * @generated from enum value: MULTIPLE_CARDS = 32;
+ */
+ MULTIPLE_CARDS = 32,
+
+ /**
+ * triggered by GC
+ *
+ * @generated from enum value: MULTIPLE_FOULS = 34;
+ */
+ MULTIPLE_FOULS = 34,
+
+ /**
+ * triggered by GC
+ *
+ * @generated from enum value: BOT_SUBSTITUTION = 37;
+ */
+ BOT_SUBSTITUTION = 37,
+
+ /**
+ * triggered by GC
+ *
+ * @generated from enum value: TOO_MANY_ROBOTS = 38;
+ */
+ TOO_MANY_ROBOTS = 38,
+
+ /**
+ * triggered by GC
+ *
+ * @generated from enum value: CHALLENGE_FLAG = 44;
+ */
+ CHALLENGE_FLAG = 44,
+
+ /**
+ * triggered by GC
+ *
+ * @generated from enum value: CHALLENGE_FLAG_HANDLED = 46;
+ */
+ CHALLENGE_FLAG_HANDLED = 46,
+
+ /**
+ * triggered by GC
+ *
+ * @generated from enum value: EMERGENCY_STOP = 45;
+ */
+ EMERGENCY_STOP = 45,
+
+ /**
+ * triggered by human ref
+ *
+ * @generated from enum value: UNSPORTING_BEHAVIOR_MINOR = 35;
+ */
+ UNSPORTING_BEHAVIOR_MINOR = 35,
+
+ /**
+ * triggered by human ref
+ *
+ * @generated from enum value: UNSPORTING_BEHAVIOR_MAJOR = 36;
+ */
+ UNSPORTING_BEHAVIOR_MAJOR = 36,
+
+ /**
+ * @generated from enum value: PREPARED = 1 [deprecated = true];
+ * @deprecated
+ */
+ PREPARED = 1,
+
+ /**
+ * @generated from enum value: INDIRECT_GOAL = 9 [deprecated = true];
+ * @deprecated
+ */
+ INDIRECT_GOAL = 9,
+
+ /**
+ * @generated from enum value: CHIPPED_GOAL = 10 [deprecated = true];
+ * @deprecated
+ */
+ CHIPPED_GOAL = 10,
+
+ /**
+ * @generated from enum value: KICK_TIMEOUT = 12 [deprecated = true];
+ * @deprecated
+ */
+ KICK_TIMEOUT = 12,
+
+ /**
+ * @generated from enum value: ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA = 16 [deprecated = true];
+ * @deprecated
+ */
+ ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA = 16,
+
+ /**
+ * @generated from enum value: ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA_SKIPPED = 40 [deprecated = true];
+ * @deprecated
+ */
+ ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA_SKIPPED = 40,
+
+ /**
+ * @generated from enum value: BOT_CRASH_UNIQUE_SKIPPED = 23 [deprecated = true];
+ * @deprecated
+ */
+ BOT_CRASH_UNIQUE_SKIPPED = 23,
+
+ /**
+ * @generated from enum value: BOT_PUSHED_BOT_SKIPPED = 25 [deprecated = true];
+ * @deprecated
+ */
+ BOT_PUSHED_BOT_SKIPPED = 25,
+
+ /**
+ * @generated from enum value: DEFENDER_IN_DEFENSE_AREA_PARTIALLY = 30 [deprecated = true];
+ * @deprecated
+ */
+ DEFENDER_IN_DEFENSE_AREA_PARTIALLY = 30,
+
+ /**
+ * @generated from enum value: MULTIPLE_PLACEMENT_FAILURES = 33 [deprecated = true];
+ * @deprecated
+ */
+ MULTIPLE_PLACEMENT_FAILURES = 33,
+}
+
+/**
+ * @generated from enum GameEvent.Type
+ */
+export type GameEvent_TypeJson = "UNKNOWN_GAME_EVENT_TYPE" | "BALL_LEFT_FIELD_TOUCH_LINE" | "BALL_LEFT_FIELD_GOAL_LINE" | "AIMLESS_KICK" | "ATTACKER_TOO_CLOSE_TO_DEFENSE_AREA" | "DEFENDER_IN_DEFENSE_AREA" | "BOUNDARY_CROSSING" | "KEEPER_HELD_BALL" | "BOT_DRIBBLED_BALL_TOO_FAR" | "BOT_PUSHED_BOT" | "BOT_HELD_BALL_DELIBERATELY" | "BOT_TIPPED_OVER" | "BOT_DROPPED_PARTS" | "ATTACKER_TOUCHED_BALL_IN_DEFENSE_AREA" | "BOT_KICKED_BALL_TOO_FAST" | "BOT_CRASH_UNIQUE" | "BOT_CRASH_DRAWN" | "DEFENDER_TOO_CLOSE_TO_KICK_POINT" | "BOT_TOO_FAST_IN_STOP" | "BOT_INTERFERED_PLACEMENT" | "EXCESSIVE_BOT_SUBSTITUTION" | "POSSIBLE_GOAL" | "GOAL" | "INVALID_GOAL" | "ATTACKER_DOUBLE_TOUCHED_BALL" | "PLACEMENT_SUCCEEDED" | "PENALTY_KICK_FAILED" | "NO_PROGRESS_IN_GAME" | "PLACEMENT_FAILED" | "MULTIPLE_CARDS" | "MULTIPLE_FOULS" | "BOT_SUBSTITUTION" | "TOO_MANY_ROBOTS" | "CHALLENGE_FLAG" | "CHALLENGE_FLAG_HANDLED" | "EMERGENCY_STOP" | "UNSPORTING_BEHAVIOR_MINOR" | "UNSPORTING_BEHAVIOR_MAJOR" | "PREPARED" | "INDIRECT_GOAL" | "CHIPPED_GOAL" | "KICK_TIMEOUT" | "ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA" | "ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA_SKIPPED" | "BOT_CRASH_UNIQUE_SKIPPED" | "BOT_PUSHED_BOT_SKIPPED" | "DEFENDER_IN_DEFENSE_AREA_PARTIALLY" | "MULTIPLE_PLACEMENT_FAILURES";
+
+/**
+ * Describes the enum GameEvent.Type.
+ */
+export const GameEvent_TypeSchema: GenEnum = /*@__PURE__*/
+ enumDesc(file_gamecontroller_ssl_gc_game_event, 0, 0);
+
diff --git a/gui/frontend/src/proto/gamecontroller/ssl_gc_geometry_pb.ts b/gui/frontend/src/proto/gamecontroller/ssl_gc_geometry_pb.ts
new file mode 100644
index 0000000..3b4c243
--- /dev/null
+++ b/gui/frontend/src/proto/gamecontroller/ssl_gc_geometry_pb.ts
@@ -0,0 +1,106 @@
+// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
+// @generated from file gamecontroller/ssl_gc_geometry.proto (syntax proto2)
+/* eslint-disable */
+
+import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
+import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
+import type { Message } from "@bufbuild/protobuf";
+
+/**
+ * Describes the file gamecontroller/ssl_gc_geometry.proto.
+ */
+export const file_gamecontroller_ssl_gc_geometry: GenFile = /*@__PURE__*/
+ fileDesc("CiRnYW1lY29udHJvbGxlci9zc2xfZ2NfZ2VvbWV0cnkucHJvdG8iHwoHVmVjdG9yMhIJCgF4GAEgAigCEgkKAXkYAiACKAIiKgoHVmVjdG9yMxIJCgF4GAEgAigCEgkKAXkYAiACKAISCQoBehgDIAIoAkJfQhJTc2xHY0dlb21ldHJ5UHJvdG9QAVpHZ2l0aHViLmNvbS9Sb2JvQ3VwLVNTTC9zc2wtdmlzaW9uLXByb2Nlc3Nvci9ndWkvaW50ZXJuYWwvZ2FtZWNvbnRyb2xsZXI");
+
+/**
+ * A vector with two dimensions
+ *
+ * @generated from message Vector2
+ */
+export type Vector2 = Message<"Vector2"> & {
+ /**
+ * @generated from field: required float x = 1;
+ */
+ x: number;
+
+ /**
+ * @generated from field: required float y = 2;
+ */
+ y: number;
+};
+
+/**
+ * A vector with two dimensions
+ *
+ * @generated from message Vector2
+ */
+export type Vector2Json = {
+ /**
+ * @generated from field: required float x = 1;
+ */
+ x?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: required float y = 2;
+ */
+ y?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message Vector2.
+ * Use `create(Vector2Schema)` to create a new message.
+ */
+export const Vector2Schema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_geometry, 0);
+
+/**
+ * A vector with three dimensions
+ *
+ * @generated from message Vector3
+ */
+export type Vector3 = Message<"Vector3"> & {
+ /**
+ * @generated from field: required float x = 1;
+ */
+ x: number;
+
+ /**
+ * @generated from field: required float y = 2;
+ */
+ y: number;
+
+ /**
+ * @generated from field: required float z = 3;
+ */
+ z: number;
+};
+
+/**
+ * A vector with three dimensions
+ *
+ * @generated from message Vector3
+ */
+export type Vector3Json = {
+ /**
+ * @generated from field: required float x = 1;
+ */
+ x?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: required float y = 2;
+ */
+ y?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: required float z = 3;
+ */
+ z?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message Vector3.
+ * Use `create(Vector3Schema)` to create a new message.
+ */
+export const Vector3Schema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_geometry, 1);
+
diff --git a/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_autoref_pb.ts b/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_autoref_pb.ts
new file mode 100644
index 0000000..b347533
--- /dev/null
+++ b/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_autoref_pb.ts
@@ -0,0 +1,157 @@
+// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
+// @generated from file gamecontroller/ssl_gc_rcon_autoref.proto (syntax proto2)
+/* eslint-disable */
+
+import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
+import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
+import type { GameEvent, GameEventJson } from "./ssl_gc_game_event_pb";
+import { file_gamecontroller_ssl_gc_game_event } from "./ssl_gc_game_event_pb";
+import type { ControllerReply, ControllerReplyJson, Signature, SignatureJson } from "./ssl_gc_rcon_pb";
+import { file_gamecontroller_ssl_gc_rcon } from "./ssl_gc_rcon_pb";
+import type { Message } from "@bufbuild/protobuf";
+
+/**
+ * Describes the file gamecontroller/ssl_gc_rcon_autoref.proto.
+ */
+export const file_gamecontroller_ssl_gc_rcon_autoref: GenFile = /*@__PURE__*/
+ fileDesc("CihnYW1lY29udHJvbGxlci9zc2xfZ2NfcmNvbl9hdXRvcmVmLnByb3RvIkgKE0F1dG9SZWZSZWdpc3RyYXRpb24SEgoKaWRlbnRpZmllchgBIAIoCRIdCglzaWduYXR1cmUYAiABKAsyCi5TaWduYXR1cmUiYAoTQXV0b1JlZlRvQ29udHJvbGxlchIdCglzaWduYXR1cmUYASABKAsyCi5TaWduYXR1cmUSHgoKZ2FtZV9ldmVudBgCIAEoCzIKLkdhbWVFdmVudEoECAMQBEoECAQQBSJKChNDb250cm9sbGVyVG9BdXRvUmVmEiwKEGNvbnRyb2xsZXJfcmVwbHkYASABKAsyEC5Db250cm9sbGVyUmVwbHlIAEIFCgNtc2dCYkIVU3NsR2NSY29uQXV0b3JlZlByb3RvUAFaR2dpdGh1Yi5jb20vUm9ib0N1cC1TU0wvc3NsLXZpc2lvbi1wcm9jZXNzb3IvZ3VpL2ludGVybmFsL2dhbWVjb250cm9sbGVy", [file_gamecontroller_ssl_gc_game_event, file_gamecontroller_ssl_gc_rcon]);
+
+/**
+ * AutoRefRegistration is the first message that a client must send to the controller to identify itself
+ *
+ * @generated from message AutoRefRegistration
+ */
+export type AutoRefRegistration = Message<"AutoRefRegistration"> & {
+ /**
+ * identifier is a unique name of the client
+ *
+ * @generated from field: required string identifier = 1;
+ */
+ identifier: string;
+
+ /**
+ * signature can optionally be specified to enable secure communication
+ *
+ * @generated from field: optional Signature signature = 2;
+ */
+ signature?: Signature;
+};
+
+/**
+ * AutoRefRegistration is the first message that a client must send to the controller to identify itself
+ *
+ * @generated from message AutoRefRegistration
+ */
+export type AutoRefRegistrationJson = {
+ /**
+ * identifier is a unique name of the client
+ *
+ * @generated from field: required string identifier = 1;
+ */
+ identifier?: string;
+
+ /**
+ * signature can optionally be specified to enable secure communication
+ *
+ * @generated from field: optional Signature signature = 2;
+ */
+ signature?: SignatureJson;
+};
+
+/**
+ * Describes the message AutoRefRegistration.
+ * Use `create(AutoRefRegistrationSchema)` to create a new message.
+ */
+export const AutoRefRegistrationSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_rcon_autoref, 0);
+
+/**
+ * AutoRefToController is the wrapper message for all subsequent messages from the autoRef to the controller
+ *
+ * @generated from message AutoRefToController
+ */
+export type AutoRefToController = Message<"AutoRefToController"> & {
+ /**
+ * signature can optionally be specified to enable secure communication
+ *
+ * @generated from field: optional Signature signature = 1;
+ */
+ signature?: Signature;
+
+ /**
+ * game_event is an optional event that the autoRef detected during the game
+ *
+ * @generated from field: optional GameEvent game_event = 2;
+ */
+ gameEvent?: GameEvent;
+};
+
+/**
+ * AutoRefToController is the wrapper message for all subsequent messages from the autoRef to the controller
+ *
+ * @generated from message AutoRefToController
+ */
+export type AutoRefToControllerJson = {
+ /**
+ * signature can optionally be specified to enable secure communication
+ *
+ * @generated from field: optional Signature signature = 1;
+ */
+ signature?: SignatureJson;
+
+ /**
+ * game_event is an optional event that the autoRef detected during the game
+ *
+ * @generated from field: optional GameEvent game_event = 2;
+ */
+ gameEvent?: GameEventJson;
+};
+
+/**
+ * Describes the message AutoRefToController.
+ * Use `create(AutoRefToControllerSchema)` to create a new message.
+ */
+export const AutoRefToControllerSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_rcon_autoref, 1);
+
+/**
+ * ControllerToAutoRef is the wrapper message for all messages from controller to autoRef
+ *
+ * @generated from message ControllerToAutoRef
+ */
+export type ControllerToAutoRef = Message<"ControllerToAutoRef"> & {
+ /**
+ * @generated from oneof ControllerToAutoRef.msg
+ */
+ msg: {
+ /**
+ * a reply from the controller
+ *
+ * @generated from field: ControllerReply controller_reply = 1;
+ */
+ value: ControllerReply;
+ case: "controllerReply";
+ } | { case: undefined; value?: undefined };
+};
+
+/**
+ * ControllerToAutoRef is the wrapper message for all messages from controller to autoRef
+ *
+ * @generated from message ControllerToAutoRef
+ */
+export type ControllerToAutoRefJson = {
+ /**
+ * a reply from the controller
+ *
+ * @generated from field: ControllerReply controller_reply = 1;
+ */
+ controllerReply?: ControllerReplyJson;
+};
+
+/**
+ * Describes the message ControllerToAutoRef.
+ * Use `create(ControllerToAutoRefSchema)` to create a new message.
+ */
+export const ControllerToAutoRefSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_rcon_autoref, 2);
+
diff --git a/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_pb.ts b/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_pb.ts
new file mode 100644
index 0000000..145c781
--- /dev/null
+++ b/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_pb.ts
@@ -0,0 +1,208 @@
+// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
+// @generated from file gamecontroller/ssl_gc_rcon.proto (syntax proto2)
+/* eslint-disable */
+
+import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
+import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
+import type { Message } from "@bufbuild/protobuf";
+
+/**
+ * Describes the file gamecontroller/ssl_gc_rcon.proto.
+ */
+export const file_gamecontroller_ssl_gc_rcon: GenFile = /*@__PURE__*/
+ fileDesc("CiBnYW1lY29udHJvbGxlci9zc2xfZ2NfcmNvbi5wcm90byKhAgoPQ29udHJvbGxlclJlcGx5EjAKC3N0YXR1c19jb2RlGAEgASgOMhsuQ29udHJvbGxlclJlcGx5LlN0YXR1c0NvZGUSDgoGcmVhc29uGAIgASgJEhIKCm5leHRfdG9rZW4YAyABKAkSMwoMdmVyaWZpY2F0aW9uGAQgASgOMh0uQ29udHJvbGxlclJlcGx5LlZlcmlmaWNhdGlvbiI7CgpTdGF0dXNDb2RlEhcKE1VOS05PV05fU1RBVFVTX0NPREUQABIGCgJPSxABEgwKCFJFSkVDVEVEEAIiRgoMVmVyaWZpY2F0aW9uEhgKFFVOS05PV05fVkVSSUZJQ0FUSU9OEAASDAoIVkVSSUZJRUQQARIOCgpVTlZFUklGSUVEEAIiLAoJU2lnbmF0dXJlEg0KBXRva2VuGAEgAigJEhAKCHBrY3MxdjE1GAIgAigMQltCDlNzbEdjUmNvblByb3RvUAFaR2dpdGh1Yi5jb20vUm9ib0N1cC1TU0wvc3NsLXZpc2lvbi1wcm9jZXNzb3IvZ3VpL2ludGVybmFsL2dhbWVjb250cm9sbGVy");
+
+/**
+ * a reply that is sent by the controller for each request from teams or autoRefs
+ *
+ * @generated from message ControllerReply
+ */
+export type ControllerReply = Message<"ControllerReply"> & {
+ /**
+ * status_code is an optional code that indicates the result of the last request
+ *
+ * @generated from field: optional ControllerReply.StatusCode status_code = 1;
+ */
+ statusCode: ControllerReply_StatusCode;
+
+ /**
+ * reason is an optional explanation of the status code
+ *
+ * @generated from field: optional string reason = 2;
+ */
+ reason: string;
+
+ /**
+ * next_token must be send with the next request, if secure communication is used
+ * the token is used to avoid replay attacks
+ * the token is always present in the very first message before the registration starts
+ * the token is not present, if secure communication is not used
+ *
+ * @generated from field: optional string next_token = 3;
+ */
+ nextToken: string;
+
+ /**
+ * verification indicates if the last request could be verified (secure communication)
+ *
+ * @generated from field: optional ControllerReply.Verification verification = 4;
+ */
+ verification: ControllerReply_Verification;
+};
+
+/**
+ * a reply that is sent by the controller for each request from teams or autoRefs
+ *
+ * @generated from message ControllerReply
+ */
+export type ControllerReplyJson = {
+ /**
+ * status_code is an optional code that indicates the result of the last request
+ *
+ * @generated from field: optional ControllerReply.StatusCode status_code = 1;
+ */
+ statusCode?: ControllerReply_StatusCodeJson;
+
+ /**
+ * reason is an optional explanation of the status code
+ *
+ * @generated from field: optional string reason = 2;
+ */
+ reason?: string;
+
+ /**
+ * next_token must be send with the next request, if secure communication is used
+ * the token is used to avoid replay attacks
+ * the token is always present in the very first message before the registration starts
+ * the token is not present, if secure communication is not used
+ *
+ * @generated from field: optional string next_token = 3;
+ */
+ nextToken?: string;
+
+ /**
+ * verification indicates if the last request could be verified (secure communication)
+ *
+ * @generated from field: optional ControllerReply.Verification verification = 4;
+ */
+ verification?: ControllerReply_VerificationJson;
+};
+
+/**
+ * Describes the message ControllerReply.
+ * Use `create(ControllerReplySchema)` to create a new message.
+ */
+export const ControllerReplySchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_rcon, 0);
+
+/**
+ * @generated from enum ControllerReply.StatusCode
+ */
+export enum ControllerReply_StatusCode {
+ /**
+ * @generated from enum value: UNKNOWN_STATUS_CODE = 0;
+ */
+ UNKNOWN_STATUS_CODE = 0,
+
+ /**
+ * @generated from enum value: OK = 1;
+ */
+ OK = 1,
+
+ /**
+ * @generated from enum value: REJECTED = 2;
+ */
+ REJECTED = 2,
+}
+
+/**
+ * @generated from enum ControllerReply.StatusCode
+ */
+export type ControllerReply_StatusCodeJson = "UNKNOWN_STATUS_CODE" | "OK" | "REJECTED";
+
+/**
+ * Describes the enum ControllerReply.StatusCode.
+ */
+export const ControllerReply_StatusCodeSchema: GenEnum = /*@__PURE__*/
+ enumDesc(file_gamecontroller_ssl_gc_rcon, 0, 0);
+
+/**
+ * @generated from enum ControllerReply.Verification
+ */
+export enum ControllerReply_Verification {
+ /**
+ * @generated from enum value: UNKNOWN_VERIFICATION = 0;
+ */
+ UNKNOWN_VERIFICATION = 0,
+
+ /**
+ * @generated from enum value: VERIFIED = 1;
+ */
+ VERIFIED = 1,
+
+ /**
+ * @generated from enum value: UNVERIFIED = 2;
+ */
+ UNVERIFIED = 2,
+}
+
+/**
+ * @generated from enum ControllerReply.Verification
+ */
+export type ControllerReply_VerificationJson = "UNKNOWN_VERIFICATION" | "VERIFIED" | "UNVERIFIED";
+
+/**
+ * Describes the enum ControllerReply.Verification.
+ */
+export const ControllerReply_VerificationSchema: GenEnum = /*@__PURE__*/
+ enumDesc(file_gamecontroller_ssl_gc_rcon, 0, 1);
+
+/**
+ * Signature can be added to a request to let it be verfied by the controller
+ *
+ * @generated from message Signature
+ */
+export type Signature = Message<"Signature"> & {
+ /**
+ * the token that was received with the last controller reply
+ *
+ * @generated from field: required string token = 1;
+ */
+ token: string;
+
+ /**
+ * the PKCS1v15 signature of this message
+ *
+ * @generated from field: required bytes pkcs1v15 = 2;
+ */
+ pkcs1v15: Uint8Array;
+};
+
+/**
+ * Signature can be added to a request to let it be verfied by the controller
+ *
+ * @generated from message Signature
+ */
+export type SignatureJson = {
+ /**
+ * the token that was received with the last controller reply
+ *
+ * @generated from field: required string token = 1;
+ */
+ token?: string;
+
+ /**
+ * the PKCS1v15 signature of this message
+ *
+ * @generated from field: required bytes pkcs1v15 = 2;
+ */
+ pkcs1v15?: string;
+};
+
+/**
+ * Describes the message Signature.
+ * Use `create(SignatureSchema)` to create a new message.
+ */
+export const SignatureSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_rcon, 1);
+
diff --git a/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_remotecontrol_pb.ts b/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_remotecontrol_pb.ts
new file mode 100644
index 0000000..b6edcf4
--- /dev/null
+++ b/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_remotecontrol_pb.ts
@@ -0,0 +1,565 @@
+// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
+// @generated from file gamecontroller/ssl_gc_rcon_remotecontrol.proto (syntax proto2)
+/* eslint-disable */
+
+import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
+import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
+import type { Team, TeamJson } from "./ssl_gc_common_pb";
+import { file_gamecontroller_ssl_gc_common } from "./ssl_gc_common_pb";
+import type { ControllerReply, ControllerReplyJson, Signature, SignatureJson } from "./ssl_gc_rcon_pb";
+import { file_gamecontroller_ssl_gc_rcon } from "./ssl_gc_rcon_pb";
+import type { Message } from "@bufbuild/protobuf";
+
+/**
+ * Describes the file gamecontroller/ssl_gc_rcon_remotecontrol.proto.
+ */
+export const file_gamecontroller_ssl_gc_rcon_remotecontrol: GenFile = /*@__PURE__*/
+ fileDesc("Ci5nYW1lY29udHJvbGxlci9zc2xfZ2NfcmNvbl9yZW1vdGVjb250cm9sLnByb3RvIk8KGVJlbW90ZUNvbnRyb2xSZWdpc3RyYXRpb24SEwoEdGVhbRgBIAIoDjIFLlRlYW0SHQoJc2lnbmF0dXJlGAIgASgLMgouU2lnbmF0dXJlItUCChlSZW1vdGVDb250cm9sVG9Db250cm9sbGVyEh0KCXNpZ25hdHVyZRgBIAEoCzIKLlNpZ25hdHVyZRI1CgdyZXF1ZXN0GAIgASgOMiIuUmVtb3RlQ29udHJvbFRvQ29udHJvbGxlci5SZXF1ZXN0SAASGAoOZGVzaXJlZF9rZWVwZXIYAyABKAVIABIkChpyZXF1ZXN0X3JvYm90X3N1YnN0aXR1dGlvbhgEIAEoCEgAEhkKD3JlcXVlc3RfdGltZW91dBgFIAEoCEgAEiAKFnJlcXVlc3RfZW1lcmdlbmN5X3N0b3AYBiABKAhIACJeCgdSZXF1ZXN0EgsKB1VOS05PV04QABIICgRQSU5HEAESEgoOQ0hBTExFTkdFX0ZMQUcQAhIQCgxTVE9QX1RJTUVPVVQQAxIWChJGQUlMX0JBTExQTEFDRU1FTlQQBEIFCgNtc2cibwoZQ29udHJvbGxlclRvUmVtb3RlQ29udHJvbBIqChBjb250cm9sbGVyX3JlcGx5GAEgASgLMhAuQ29udHJvbGxlclJlcGx5EiYKBXN0YXRlGAIgASgLMhcuUmVtb3RlQ29udHJvbFRlYW1TdGF0ZSK/AwoWUmVtb3RlQ29udHJvbFRlYW1TdGF0ZRITCgR0ZWFtGAwgASgOMgUuVGVhbRI1ChJhdmFpbGFibGVfcmVxdWVzdHMYASADKA4yGS5SZW1vdGVDb250cm9sUmVxdWVzdFR5cGUSMgoPYWN0aXZlX3JlcXVlc3RzGAIgAygOMhkuUmVtb3RlQ29udHJvbFJlcXVlc3RUeXBlEhEKCWtlZXBlcl9pZBgDIAEoBRIZChFlbWVyZ2VuY3lfc3RvcF9pbhgEIAEoAhIVCg10aW1lb3V0c19sZWZ0GAUgASgFEhkKEXRpbWVvdXRfdGltZV9sZWZ0GAogASgCEhwKFGNoYWxsZW5nZV9mbGFnc19sZWZ0GAYgASgFEhIKCm1heF9yb2JvdHMYByABKAUSFwoPcm9ib3RzX29uX2ZpZWxkGAkgASgFEhgKEHllbGxvd19jYXJkc19kdWUYCCADKAISHAoUY2FuX3N1YnN0aXR1dGVfcm9ib3QYCyABKAgSHgoWYm90X3N1YnN0aXR1dGlvbnNfbGVmdBgNIAEoDRIiChpib3Rfc3Vic3RpdHV0aW9uX3RpbWVfbGVmdBgOIAEoAirBAQoYUmVtb3RlQ29udHJvbFJlcXVlc3RUeXBlEhgKFFVOS05PV05fUkVRVUVTVF9UWVBFEAASEgoORU1FUkdFTkNZX1NUT1AQARIWChJST0JPVF9TVUJTVElUVVRJT04QAhILCgdUSU1FT1VUEAMSEgoOQ0hBTExFTkdFX0ZMQUcQBBIUChBDSEFOR0VfS0VFUEVSX0lEEAUSEAoMU1RPUF9USU1FT1VUEAYSFgoSRkFJTF9CQUxMUExBQ0VNRU5UEAdCaEIbU3NsR2NSY29uUmVtb3RlY29udHJvbFByb3RvUAFaR2dpdGh1Yi5jb20vUm9ib0N1cC1TU0wvc3NsLXZpc2lvbi1wcm9jZXNzb3IvZ3VpL2ludGVybmFsL2dhbWVjb250cm9sbGVy", [file_gamecontroller_ssl_gc_common, file_gamecontroller_ssl_gc_rcon]);
+
+/**
+ * a registration that must be send by the remote control to the controller as the very first message
+ *
+ * @generated from message RemoteControlRegistration
+ */
+export type RemoteControlRegistration = Message<"RemoteControlRegistration"> & {
+ /**
+ * the team to be controlled
+ *
+ * @generated from field: required Team team = 1;
+ */
+ team: Team;
+
+ /**
+ * signature can optionally be specified to enable secure communication
+ *
+ * @generated from field: optional Signature signature = 2;
+ */
+ signature?: Signature;
+};
+
+/**
+ * a registration that must be send by the remote control to the controller as the very first message
+ *
+ * @generated from message RemoteControlRegistration
+ */
+export type RemoteControlRegistrationJson = {
+ /**
+ * the team to be controlled
+ *
+ * @generated from field: required Team team = 1;
+ */
+ team?: TeamJson;
+
+ /**
+ * signature can optionally be specified to enable secure communication
+ *
+ * @generated from field: optional Signature signature = 2;
+ */
+ signature?: SignatureJson;
+};
+
+/**
+ * Describes the message RemoteControlRegistration.
+ * Use `create(RemoteControlRegistrationSchema)` to create a new message.
+ */
+export const RemoteControlRegistrationSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_rcon_remotecontrol, 0);
+
+/**
+ * wrapper for all messages from the remote control to the controller
+ *
+ * @generated from message RemoteControlToController
+ */
+export type RemoteControlToController = Message<"RemoteControlToController"> & {
+ /**
+ * signature can optionally be specified to enable secure communication
+ *
+ * @generated from field: optional Signature signature = 1;
+ */
+ signature?: Signature;
+
+ /**
+ * @generated from oneof RemoteControlToController.msg
+ */
+ msg: {
+ /**
+ * send a request to the GC
+ *
+ * @generated from field: RemoteControlToController.Request request = 2;
+ */
+ value: RemoteControlToController_Request;
+ case: "request";
+ } | {
+ /**
+ * request a new desired keeper id
+ *
+ * @generated from field: int32 desired_keeper = 3;
+ */
+ value: number;
+ case: "desiredKeeper";
+ } | {
+ /**
+ * true: request to substitute a robot at the next possibility
+ * false: cancel request
+ *
+ * @generated from field: bool request_robot_substitution = 4;
+ */
+ value: boolean;
+ case: "requestRobotSubstitution";
+ } | {
+ /**
+ * true: request a timeout with the next stoppage
+ * false: cancel the request
+ *
+ * @generated from field: bool request_timeout = 5;
+ */
+ value: boolean;
+ case: "requestTimeout";
+ } | {
+ /**
+ * true: initiate an emergency stop
+ * false: cancel the request
+ *
+ * @generated from field: bool request_emergency_stop = 6;
+ */
+ value: boolean;
+ case: "requestEmergencyStop";
+ } | { case: undefined; value?: undefined };
+};
+
+/**
+ * wrapper for all messages from the remote control to the controller
+ *
+ * @generated from message RemoteControlToController
+ */
+export type RemoteControlToControllerJson = {
+ /**
+ * signature can optionally be specified to enable secure communication
+ *
+ * @generated from field: optional Signature signature = 1;
+ */
+ signature?: SignatureJson;
+
+ /**
+ * send a request to the GC
+ *
+ * @generated from field: RemoteControlToController.Request request = 2;
+ */
+ request?: RemoteControlToController_RequestJson;
+
+ /**
+ * request a new desired keeper id
+ *
+ * @generated from field: int32 desired_keeper = 3;
+ */
+ desiredKeeper?: number;
+
+ /**
+ * true: request to substitute a robot at the next possibility
+ * false: cancel request
+ *
+ * @generated from field: bool request_robot_substitution = 4;
+ */
+ requestRobotSubstitution?: boolean;
+
+ /**
+ * true: request a timeout with the next stoppage
+ * false: cancel the request
+ *
+ * @generated from field: bool request_timeout = 5;
+ */
+ requestTimeout?: boolean;
+
+ /**
+ * true: initiate an emergency stop
+ * false: cancel the request
+ *
+ * @generated from field: bool request_emergency_stop = 6;
+ */
+ requestEmergencyStop?: boolean;
+};
+
+/**
+ * Describes the message RemoteControlToController.
+ * Use `create(RemoteControlToControllerSchema)` to create a new message.
+ */
+export const RemoteControlToControllerSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_rcon_remotecontrol, 1);
+
+/**
+ * @generated from enum RemoteControlToController.Request
+ */
+export enum RemoteControlToController_Request {
+ /**
+ * @generated from enum value: UNKNOWN = 0;
+ */
+ UNKNOWN = 0,
+
+ /**
+ * Ping the GC to test the connection. The GC will respond with OK and the current team state
+ *
+ * @generated from enum value: PING = 1;
+ */
+ PING = 1,
+
+ /**
+ * Raise a challenge flag (this is not revocable)
+ *
+ * @generated from enum value: CHALLENGE_FLAG = 2;
+ */
+ CHALLENGE_FLAG = 2,
+
+ /**
+ * Stop an ongoing timeout
+ *
+ * @generated from enum value: STOP_TIMEOUT = 3;
+ */
+ STOP_TIMEOUT = 3,
+
+ /**
+ * Fail a ball placement
+ *
+ * @generated from enum value: FAIL_BALLPLACEMENT = 4;
+ */
+ FAIL_BALLPLACEMENT = 4,
+}
+
+/**
+ * @generated from enum RemoteControlToController.Request
+ */
+export type RemoteControlToController_RequestJson = "UNKNOWN" | "PING" | "CHALLENGE_FLAG" | "STOP_TIMEOUT" | "FAIL_BALLPLACEMENT";
+
+/**
+ * Describes the enum RemoteControlToController.Request.
+ */
+export const RemoteControlToController_RequestSchema: GenEnum = /*@__PURE__*/
+ enumDesc(file_gamecontroller_ssl_gc_rcon_remotecontrol, 1, 0);
+
+/**
+ * wrapper for all messages from controller to a team's computer
+ *
+ * @generated from message ControllerToRemoteControl
+ */
+export type ControllerToRemoteControl = Message<"ControllerToRemoteControl"> & {
+ /**
+ * a reply from the controller
+ *
+ * @generated from field: optional ControllerReply controller_reply = 1;
+ */
+ controllerReply?: ControllerReply;
+
+ /**
+ * current team state
+ *
+ * @generated from field: optional RemoteControlTeamState state = 2;
+ */
+ state?: RemoteControlTeamState;
+};
+
+/**
+ * wrapper for all messages from controller to a team's computer
+ *
+ * @generated from message ControllerToRemoteControl
+ */
+export type ControllerToRemoteControlJson = {
+ /**
+ * a reply from the controller
+ *
+ * @generated from field: optional ControllerReply controller_reply = 1;
+ */
+ controllerReply?: ControllerReplyJson;
+
+ /**
+ * current team state
+ *
+ * @generated from field: optional RemoteControlTeamState state = 2;
+ */
+ state?: RemoteControlTeamStateJson;
+};
+
+/**
+ * Describes the message ControllerToRemoteControl.
+ * Use `create(ControllerToRemoteControlSchema)` to create a new message.
+ */
+export const ControllerToRemoteControlSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_rcon_remotecontrol, 2);
+
+/**
+ * Current team state from Controller for remote control
+ *
+ * @generated from message RemoteControlTeamState
+ */
+export type RemoteControlTeamState = Message<"RemoteControlTeamState"> & {
+ /**
+ * the team that is controlled
+ *
+ * @generated from field: optional Team team = 12;
+ */
+ team: Team;
+
+ /**
+ * list of all currently available request types that can be made
+ *
+ * @generated from field: repeated RemoteControlRequestType available_requests = 1;
+ */
+ availableRequests: RemoteControlRequestType[];
+
+ /**
+ * list of all currently active request types that are pending
+ *
+ * @generated from field: repeated RemoteControlRequestType active_requests = 2;
+ */
+ activeRequests: RemoteControlRequestType[];
+
+ /**
+ * currently set keeper id
+ *
+ * @generated from field: optional int32 keeper_id = 3;
+ */
+ keeperId: number;
+
+ /**
+ * number of seconds till emergency stop is executed
+ * zero, if no emergency stop requested
+ *
+ * @generated from field: optional float emergency_stop_in = 4;
+ */
+ emergencyStopIn: number;
+
+ /**
+ * number of timeouts left for the team
+ *
+ * @generated from field: optional int32 timeouts_left = 5;
+ */
+ timeoutsLeft: number;
+
+ /**
+ * number of seconds left for timeout for the team
+ *
+ * @generated from field: optional float timeout_time_left = 10;
+ */
+ timeoutTimeLeft: number;
+
+ /**
+ * number of challenge flags left for the team
+ *
+ * @generated from field: optional int32 challenge_flags_left = 6;
+ */
+ challengeFlagsLeft: number;
+
+ /**
+ * max number of robots currently allowed
+ *
+ * @generated from field: optional int32 max_robots = 7;
+ */
+ maxRobots: number;
+
+ /**
+ * current number of robots visible on field
+ *
+ * @generated from field: optional int32 robots_on_field = 9;
+ */
+ robotsOnField: number;
+
+ /**
+ * list of due times for each active yellow card (in seconds)
+ *
+ * @generated from field: repeated float yellow_cards_due = 8;
+ */
+ yellowCardsDue: number[];
+
+ /**
+ * if true, team is allowed to substitute robots
+ *
+ * @generated from field: optional bool can_substitute_robot = 11;
+ */
+ canSubstituteRobot: boolean;
+
+ /**
+ * number of bot substitutions left by the team in this halftime
+ *
+ * @generated from field: optional uint32 bot_substitutions_left = 13;
+ */
+ botSubstitutionsLeft: number;
+
+ /**
+ * number of seconds left for current bot substitution
+ *
+ * @generated from field: optional float bot_substitution_time_left = 14;
+ */
+ botSubstitutionTimeLeft: number;
+};
+
+/**
+ * Current team state from Controller for remote control
+ *
+ * @generated from message RemoteControlTeamState
+ */
+export type RemoteControlTeamStateJson = {
+ /**
+ * the team that is controlled
+ *
+ * @generated from field: optional Team team = 12;
+ */
+ team?: TeamJson;
+
+ /**
+ * list of all currently available request types that can be made
+ *
+ * @generated from field: repeated RemoteControlRequestType available_requests = 1;
+ */
+ availableRequests?: RemoteControlRequestTypeJson[];
+
+ /**
+ * list of all currently active request types that are pending
+ *
+ * @generated from field: repeated RemoteControlRequestType active_requests = 2;
+ */
+ activeRequests?: RemoteControlRequestTypeJson[];
+
+ /**
+ * currently set keeper id
+ *
+ * @generated from field: optional int32 keeper_id = 3;
+ */
+ keeperId?: number;
+
+ /**
+ * number of seconds till emergency stop is executed
+ * zero, if no emergency stop requested
+ *
+ * @generated from field: optional float emergency_stop_in = 4;
+ */
+ emergencyStopIn?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * number of timeouts left for the team
+ *
+ * @generated from field: optional int32 timeouts_left = 5;
+ */
+ timeoutsLeft?: number;
+
+ /**
+ * number of seconds left for timeout for the team
+ *
+ * @generated from field: optional float timeout_time_left = 10;
+ */
+ timeoutTimeLeft?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * number of challenge flags left for the team
+ *
+ * @generated from field: optional int32 challenge_flags_left = 6;
+ */
+ challengeFlagsLeft?: number;
+
+ /**
+ * max number of robots currently allowed
+ *
+ * @generated from field: optional int32 max_robots = 7;
+ */
+ maxRobots?: number;
+
+ /**
+ * current number of robots visible on field
+ *
+ * @generated from field: optional int32 robots_on_field = 9;
+ */
+ robotsOnField?: number;
+
+ /**
+ * list of due times for each active yellow card (in seconds)
+ *
+ * @generated from field: repeated float yellow_cards_due = 8;
+ */
+ yellowCardsDue?: (number | "NaN" | "Infinity" | "-Infinity")[];
+
+ /**
+ * if true, team is allowed to substitute robots
+ *
+ * @generated from field: optional bool can_substitute_robot = 11;
+ */
+ canSubstituteRobot?: boolean;
+
+ /**
+ * number of bot substitutions left by the team in this halftime
+ *
+ * @generated from field: optional uint32 bot_substitutions_left = 13;
+ */
+ botSubstitutionsLeft?: number;
+
+ /**
+ * number of seconds left for current bot substitution
+ *
+ * @generated from field: optional float bot_substitution_time_left = 14;
+ */
+ botSubstitutionTimeLeft?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message RemoteControlTeamState.
+ * Use `create(RemoteControlTeamStateSchema)` to create a new message.
+ */
+export const RemoteControlTeamStateSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_rcon_remotecontrol, 3);
+
+/**
+ * All possible request types that the remote control can make
+ *
+ * @generated from enum RemoteControlRequestType
+ */
+export enum RemoteControlRequestType {
+ /**
+ * @generated from enum value: UNKNOWN_REQUEST_TYPE = 0;
+ */
+ UNKNOWN_REQUEST_TYPE = 0,
+
+ /**
+ * @generated from enum value: EMERGENCY_STOP = 1;
+ */
+ EMERGENCY_STOP = 1,
+
+ /**
+ * @generated from enum value: ROBOT_SUBSTITUTION = 2;
+ */
+ ROBOT_SUBSTITUTION = 2,
+
+ /**
+ * @generated from enum value: TIMEOUT = 3;
+ */
+ TIMEOUT = 3,
+
+ /**
+ * @generated from enum value: CHALLENGE_FLAG = 4;
+ */
+ CHALLENGE_FLAG = 4,
+
+ /**
+ * @generated from enum value: CHANGE_KEEPER_ID = 5;
+ */
+ CHANGE_KEEPER_ID = 5,
+
+ /**
+ * @generated from enum value: STOP_TIMEOUT = 6;
+ */
+ STOP_TIMEOUT = 6,
+
+ /**
+ * @generated from enum value: FAIL_BALLPLACEMENT = 7;
+ */
+ FAIL_BALLPLACEMENT = 7,
+}
+
+/**
+ * All possible request types that the remote control can make
+ *
+ * @generated from enum RemoteControlRequestType
+ */
+export type RemoteControlRequestTypeJson = "UNKNOWN_REQUEST_TYPE" | "EMERGENCY_STOP" | "ROBOT_SUBSTITUTION" | "TIMEOUT" | "CHALLENGE_FLAG" | "CHANGE_KEEPER_ID" | "STOP_TIMEOUT" | "FAIL_BALLPLACEMENT";
+
+/**
+ * Describes the enum RemoteControlRequestType.
+ */
+export const RemoteControlRequestTypeSchema: GenEnum = /*@__PURE__*/
+ enumDesc(file_gamecontroller_ssl_gc_rcon_remotecontrol, 0);
+
diff --git a/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_team_pb.ts b/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_team_pb.ts
new file mode 100644
index 0000000..ad0578f
--- /dev/null
+++ b/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_team_pb.ts
@@ -0,0 +1,264 @@
+// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
+// @generated from file gamecontroller/ssl_gc_rcon_team.proto (syntax proto2)
+/* eslint-disable */
+
+import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
+import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
+import type { Team, TeamJson } from "./ssl_gc_common_pb";
+import { file_gamecontroller_ssl_gc_common } from "./ssl_gc_common_pb";
+import type { ControllerReply, ControllerReplyJson, Signature, SignatureJson } from "./ssl_gc_rcon_pb";
+import { file_gamecontroller_ssl_gc_rcon } from "./ssl_gc_rcon_pb";
+import type { Message } from "@bufbuild/protobuf";
+
+/**
+ * Describes the file gamecontroller/ssl_gc_rcon_team.proto.
+ */
+export const file_gamecontroller_ssl_gc_rcon_team: GenFile = /*@__PURE__*/
+ fileDesc("CiVnYW1lY29udHJvbGxlci9zc2xfZ2NfcmNvbl90ZWFtLnByb3RvIlkKEFRlYW1SZWdpc3RyYXRpb24SEQoJdGVhbV9uYW1lGAEgAigJEh0KCXNpZ25hdHVyZRgCIAEoCzIKLlNpZ25hdHVyZRITCgR0ZWFtGAMgASgOMgUuVGVhbSKqAQoQVGVhbVRvQ29udHJvbGxlchIdCglzaWduYXR1cmUYASABKAsyCi5TaWduYXR1cmUSGAoOZGVzaXJlZF9rZWVwZXIYAiABKAVIABIsChBhZHZhbnRhZ2VfY2hvaWNlGAMgASgOMhAuQWR2YW50YWdlQ2hvaWNlSAASGAoOc3Vic3RpdHV0ZV9ib3QYBCABKAhIABIOCgRwaW5nGAUgASgISABCBQoDbXNnIk0KEENvbnRyb2xsZXJUb1RlYW0SLAoQY29udHJvbGxlcl9yZXBseRgBIAEoCzIQLkNvbnRyb2xsZXJSZXBseUgAQgUKA21zZ0oECAIQAyopCg9BZHZhbnRhZ2VDaG9pY2USCAoEU1RPUBAAEgwKCENPTlRJTlVFEAFCX0ISU3NsR2NSY29uVGVhbVByb3RvUAFaR2dpdGh1Yi5jb20vUm9ib0N1cC1TU0wvc3NsLXZpc2lvbi1wcm9jZXNzb3IvZ3VpL2ludGVybmFsL2dhbWVjb250cm9sbGVy", [file_gamecontroller_ssl_gc_common, file_gamecontroller_ssl_gc_rcon]);
+
+/**
+ * a registration that must be send by teams to the controller as the very first message
+ *
+ * @generated from message TeamRegistration
+ */
+export type TeamRegistration = Message<"TeamRegistration"> & {
+ /**
+ * the exact team name as published by the game-controller
+ *
+ * @generated from field: required string team_name = 1;
+ */
+ teamName: string;
+
+ /**
+ * signature can optionally be specified to enable secure communication
+ *
+ * @generated from field: optional Signature signature = 2;
+ */
+ signature?: Signature;
+
+ /**
+ * the team (relevant only if a team plays against itself)
+ *
+ * @generated from field: optional Team team = 3;
+ */
+ team: Team;
+};
+
+/**
+ * a registration that must be send by teams to the controller as the very first message
+ *
+ * @generated from message TeamRegistration
+ */
+export type TeamRegistrationJson = {
+ /**
+ * the exact team name as published by the game-controller
+ *
+ * @generated from field: required string team_name = 1;
+ */
+ teamName?: string;
+
+ /**
+ * signature can optionally be specified to enable secure communication
+ *
+ * @generated from field: optional Signature signature = 2;
+ */
+ signature?: SignatureJson;
+
+ /**
+ * the team (relevant only if a team plays against itself)
+ *
+ * @generated from field: optional Team team = 3;
+ */
+ team?: TeamJson;
+};
+
+/**
+ * Describes the message TeamRegistration.
+ * Use `create(TeamRegistrationSchema)` to create a new message.
+ */
+export const TeamRegistrationSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_rcon_team, 0);
+
+/**
+ * wrapper for all messages from a team's computer to the controller
+ *
+ * @generated from message TeamToController
+ */
+export type TeamToController = Message<"TeamToController"> & {
+ /**
+ * signature can optionally be specified to enable secure communication
+ *
+ * @generated from field: optional Signature signature = 1;
+ */
+ signature?: Signature;
+
+ /**
+ * @generated from oneof TeamToController.msg
+ */
+ msg: {
+ /**
+ * request a new desired keeper id
+ *
+ * @generated from field: int32 desired_keeper = 2;
+ */
+ value: number;
+ case: "desiredKeeper";
+ } | {
+ /**
+ * response to an advantage choice request
+ *
+ * @generated from field: AdvantageChoice advantage_choice = 3;
+ */
+ value: AdvantageChoice;
+ case: "advantageChoice";
+ } | {
+ /**
+ * request to substitute a robot at the next possibility
+ *
+ * @generated from field: bool substitute_bot = 4;
+ */
+ value: boolean;
+ case: "substituteBot";
+ } | {
+ /**
+ * send a ping to the GC to test if the connection is still open.
+ * the value is ignored and a reply is sent back
+ *
+ * @generated from field: bool ping = 5;
+ */
+ value: boolean;
+ case: "ping";
+ } | { case: undefined; value?: undefined };
+};
+
+/**
+ * wrapper for all messages from a team's computer to the controller
+ *
+ * @generated from message TeamToController
+ */
+export type TeamToControllerJson = {
+ /**
+ * signature can optionally be specified to enable secure communication
+ *
+ * @generated from field: optional Signature signature = 1;
+ */
+ signature?: SignatureJson;
+
+ /**
+ * request a new desired keeper id
+ *
+ * @generated from field: int32 desired_keeper = 2;
+ */
+ desiredKeeper?: number;
+
+ /**
+ * response to an advantage choice request
+ *
+ * @generated from field: AdvantageChoice advantage_choice = 3;
+ */
+ advantageChoice?: AdvantageChoiceJson;
+
+ /**
+ * request to substitute a robot at the next possibility
+ *
+ * @generated from field: bool substitute_bot = 4;
+ */
+ substituteBot?: boolean;
+
+ /**
+ * send a ping to the GC to test if the connection is still open.
+ * the value is ignored and a reply is sent back
+ *
+ * @generated from field: bool ping = 5;
+ */
+ ping?: boolean;
+};
+
+/**
+ * Describes the message TeamToController.
+ * Use `create(TeamToControllerSchema)` to create a new message.
+ */
+export const TeamToControllerSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_rcon_team, 1);
+
+/**
+ * wrapper for all messages from controller to a team's computer
+ *
+ * @generated from message ControllerToTeam
+ */
+export type ControllerToTeam = Message<"ControllerToTeam"> & {
+ /**
+ * @generated from oneof ControllerToTeam.msg
+ */
+ msg: {
+ /**
+ * a reply from the controller
+ *
+ * @generated from field: ControllerReply controller_reply = 1;
+ */
+ value: ControllerReply;
+ case: "controllerReply";
+ } | { case: undefined; value?: undefined };
+};
+
+/**
+ * wrapper for all messages from controller to a team's computer
+ *
+ * @generated from message ControllerToTeam
+ */
+export type ControllerToTeamJson = {
+ /**
+ * a reply from the controller
+ *
+ * @generated from field: ControllerReply controller_reply = 1;
+ */
+ controllerReply?: ControllerReplyJson;
+};
+
+/**
+ * Describes the message ControllerToTeam.
+ * Use `create(ControllerToTeamSchema)` to create a new message.
+ */
+export const ControllerToTeamSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_rcon_team, 2);
+
+/**
+ * the current advantage choice of the team
+ * the choice is valid until another choice is received
+ * if the team disconnects, the choice is reset to its default (STOP)
+ * teams may either send their current choice continuously or only on change
+ *
+ * @generated from enum AdvantageChoice
+ */
+export enum AdvantageChoice {
+ /**
+ * stop the game
+ *
+ * @generated from enum value: STOP = 0;
+ */
+ STOP = 0,
+
+ /**
+ * keep the game running
+ *
+ * @generated from enum value: CONTINUE = 1;
+ */
+ CONTINUE = 1,
+}
+
+/**
+ * the current advantage choice of the team
+ * the choice is valid until another choice is received
+ * if the team disconnects, the choice is reset to its default (STOP)
+ * teams may either send their current choice continuously or only on change
+ *
+ * @generated from enum AdvantageChoice
+ */
+export type AdvantageChoiceJson = "STOP" | "CONTINUE";
+
+/**
+ * Describes the enum AdvantageChoice.
+ */
+export const AdvantageChoiceSchema: GenEnum = /*@__PURE__*/
+ enumDesc(file_gamecontroller_ssl_gc_rcon_team, 0);
+
diff --git a/gui/frontend/src/proto/gamecontroller/ssl_gc_referee_message_pb.ts b/gui/frontend/src/proto/gamecontroller/ssl_gc_referee_message_pb.ts
new file mode 100644
index 0000000..3c96c03
--- /dev/null
+++ b/gui/frontend/src/proto/gamecontroller/ssl_gc_referee_message_pb.ts
@@ -0,0 +1,1055 @@
+// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
+// @generated from file gamecontroller/ssl_gc_referee_message.proto (syntax proto2)
+/* eslint-disable */
+
+import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
+import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
+import type { GameEvent, GameEventJson } from "./ssl_gc_game_event_pb";
+import { file_gamecontroller_ssl_gc_game_event } from "./ssl_gc_game_event_pb";
+import type { Message } from "@bufbuild/protobuf";
+
+/**
+ * Describes the file gamecontroller/ssl_gc_referee_message.proto.
+ */
+export const file_gamecontroller_ssl_gc_referee_message: GenFile = /*@__PURE__*/
+ fileDesc("CitnYW1lY29udHJvbGxlci9zc2xfZ2NfcmVmZXJlZV9tZXNzYWdlLnByb3RvItUOCgdSZWZlcmVlEhkKEXNvdXJjZV9pZGVudGlmaWVyGBIgASgJEi0KCm1hdGNoX3R5cGUYEyABKA4yCi5NYXRjaFR5cGU6DVVOS05PV05fTUFUQ0gSGAoQcGFja2V0X3RpbWVzdGFtcBgBIAIoBBIdCgVzdGFnZRgCIAIoDjIOLlJlZmVyZWUuU3RhZ2USFwoPc3RhZ2VfdGltZV9sZWZ0GAMgASgSEiEKB2NvbW1hbmQYBCACKA4yEC5SZWZlcmVlLkNvbW1hbmQSFwoPY29tbWFuZF9jb3VudGVyGAUgAigNEhkKEWNvbW1hbmRfdGltZXN0YW1wGAYgAigEEiEKBnllbGxvdxgHIAIoCzIRLlJlZmVyZWUuVGVhbUluZm8SHwoEYmx1ZRgIIAIoCzIRLlJlZmVyZWUuVGVhbUluZm8SKwoTZGVzaWduYXRlZF9wb3NpdGlvbhgJIAEoCzIOLlJlZmVyZWUuUG9pbnQSIgoaYmx1ZV90ZWFtX29uX3Bvc2l0aXZlX2hhbGYYCiABKAgSJgoMbmV4dF9jb21tYW5kGAwgASgOMhAuUmVmZXJlZS5Db21tYW5kEh8KC2dhbWVfZXZlbnRzGBAgAygLMgouR2FtZUV2ZW50EjUKFGdhbWVfZXZlbnRfcHJvcG9zYWxzGBEgAygLMhcuR2FtZUV2ZW50UHJvcG9zYWxHcm91cBIlCh1jdXJyZW50X2FjdGlvbl90aW1lX3JlbWFpbmluZxgPIAEoAxIWCg5zdGF0dXNfbWVzc2FnZRgUIAEoCRrkAwoIVGVhbUluZm8SDAoEbmFtZRgBIAIoCRINCgVzY29yZRgCIAIoDRIRCglyZWRfY2FyZHMYAyACKA0SHQoReWVsbG93X2NhcmRfdGltZXMYBCADKA1CAhABEhQKDHllbGxvd19jYXJkcxgFIAIoDRIQCgh0aW1lb3V0cxgGIAIoDRIUCgx0aW1lb3V0X3RpbWUYByACKA0SEgoKZ29hbGtlZXBlchgIIAIoDRIUCgxmb3VsX2NvdW50ZXIYCSABKA0SHwoXYmFsbF9wbGFjZW1lbnRfZmFpbHVyZXMYCiABKA0SFgoOY2FuX3BsYWNlX2JhbGwYDCABKAgSGAoQbWF4X2FsbG93ZWRfYm90cxgNIAEoDRIfChdib3Rfc3Vic3RpdHV0aW9uX2ludGVudBgOIAEoCBInCh9iYWxsX3BsYWNlbWVudF9mYWlsdXJlc19yZWFjaGVkGA8gASgIEiAKGGJvdF9zdWJzdGl0dXRpb25fYWxsb3dlZBgQIAEoCBIeChZib3Rfc3Vic3RpdHV0aW9uc19sZWZ0GBEgASgNEiIKGmJvdF9zdWJzdGl0dXRpb25fdGltZV9sZWZ0GBIgASgNEh4KCmh1bGxfY29sb3IYEyABKA4yCi5IdWxsQ29sb3IaHQoFUG9pbnQSCQoBeBgBIAIoAhIJCgF5GAIgAigCItECCgVTdGFnZRIZChVOT1JNQUxfRklSU1RfSEFMRl9QUkUQABIVChFOT1JNQUxfRklSU1RfSEFMRhABEhQKEE5PUk1BTF9IQUxGX1RJTUUQAhIaChZOT1JNQUxfU0VDT05EX0hBTEZfUFJFEAMSFgoSTk9STUFMX1NFQ09ORF9IQUxGEAQSFAoQRVhUUkFfVElNRV9CUkVBSxAFEhgKFEVYVFJBX0ZJUlNUX0hBTEZfUFJFEAYSFAoQRVhUUkFfRklSU1RfSEFMRhAHEhMKD0VYVFJBX0hBTEZfVElNRRAIEhkKFUVYVFJBX1NFQ09ORF9IQUxGX1BSRRAJEhUKEUVYVFJBX1NFQ09ORF9IQUxGEAoSGgoWUEVOQUxUWV9TSE9PVE9VVF9CUkVBSxALEhQKEFBFTkFMVFlfU0hPT1RPVVQQDBINCglQT1NUX0dBTUUQDSKWAwoHQ29tbWFuZBIICgRIQUxUEAASCAoEU1RPUBABEhAKDE5PUk1BTF9TVEFSVBACEg8KC0ZPUkNFX1NUQVJUEAMSGgoWUFJFUEFSRV9LSUNLT0ZGX1lFTExPVxAEEhgKFFBSRVBBUkVfS0lDS09GRl9CTFVFEAUSGgoWUFJFUEFSRV9QRU5BTFRZX1lFTExPVxAGEhgKFFBSRVBBUkVfUEVOQUxUWV9CTFVFEAcSFgoSRElSRUNUX0ZSRUVfWUVMTE9XEAgSFAoQRElSRUNUX0ZSRUVfQkxVRRAJEhwKFElORElSRUNUX0ZSRUVfWUVMTE9XEAoaAggBEhoKEklORElSRUNUX0ZSRUVfQkxVRRALGgIIARISCg5USU1FT1VUX1lFTExPVxAMEhAKDFRJTUVPVVRfQkxVRRANEhMKC0dPQUxfWUVMTE9XEA4aAggBEhEKCUdPQUxfQkxVRRAPGgIIARIZChVCQUxMX1BMQUNFTUVOVF9ZRUxMT1cQEBIXChNCQUxMX1BMQUNFTUVOVF9CTFVFEBFKBAgLEAxKBAgNEA5KBAgOEA8iVwoWR2FtZUV2ZW50UHJvcG9zYWxHcm91cBIKCgJpZBgDIAEoCRIfCgtnYW1lX2V2ZW50cxgBIAMoCzIKLkdhbWVFdmVudBIQCghhY2NlcHRlZBgCIAEoCCpUCglNYXRjaFR5cGUSEQoNVU5LTk9XTl9NQVRDSBAAEg8KC0dST1VQX1BIQVNFEAESFQoRRUxJTUlOQVRJT05fUEhBU0UQAhIMCghGUklFTkRMWRADKk4KCUh1bGxDb2xvchIWChJIVUxMX0NPTE9SX1VOS05PV04QABITCg9IVUxMX0NPTE9SX0RBUksQARIUChBIVUxMX0NPTE9SX0xJR0hUEAJCZUIYU3NsR2NSZWZlcmVlTWVzc2FnZVByb3RvUAFaR2dpdGh1Yi5jb20vUm9ib0N1cC1TU0wvc3NsLXZpc2lvbi1wcm9jZXNzb3IvZ3VpL2ludGVybmFsL2dhbWVjb250cm9sbGVy", [file_gamecontroller_ssl_gc_game_event]);
+
+/**
+ * Each UDP packet contains one of these messages.
+ *
+ * @generated from message Referee
+ */
+export type Referee = Message<"Referee"> & {
+ /**
+ * A random UUID of the source that is kept constant at the source while running
+ * If multiple sources are broadcasting to the same network, this id can be used to identify individual sources
+ *
+ * @generated from field: optional string source_identifier = 18;
+ */
+ sourceIdentifier: string;
+
+ /**
+ * The match type is a meta information about the current match that helps to process the logs after a competition
+ *
+ * @generated from field: optional MatchType match_type = 19 [default = UNKNOWN_MATCH];
+ */
+ matchType: MatchType;
+
+ /**
+ * The UNIX timestamp when the packet was sent, in microseconds.
+ * Divide by 1,000,000 to get a time_t.
+ *
+ * @generated from field: required uint64 packet_timestamp = 1;
+ */
+ packetTimestamp: bigint;
+
+ /**
+ * @generated from field: required Referee.Stage stage = 2;
+ */
+ stage: Referee_Stage;
+
+ /**
+ * The number of microseconds left in the stage.
+ * The following stages have this value; the rest do not:
+ * NORMAL_FIRST_HALF
+ * NORMAL_HALF_TIME
+ * NORMAL_SECOND_HALF
+ * EXTRA_TIME_BREAK
+ * EXTRA_FIRST_HALF
+ * EXTRA_HALF_TIME
+ * EXTRA_SECOND_HALF
+ * PENALTY_SHOOTOUT_BREAK
+ *
+ * If the stage runs over its specified time, this value
+ * becomes negative.
+ *
+ * @generated from field: optional sint64 stage_time_left = 3;
+ */
+ stageTimeLeft: bigint;
+
+ /**
+ * @generated from field: required Referee.Command command = 4;
+ */
+ command: Referee_Command;
+
+ /**
+ * The number of commands issued since startup (mod 2^32).
+ *
+ * @generated from field: required uint32 command_counter = 5;
+ */
+ commandCounter: number;
+
+ /**
+ * The UNIX timestamp when the command was issued, in microseconds.
+ * This value changes only when a new command is issued, not on each packet.
+ *
+ * @generated from field: required uint64 command_timestamp = 6;
+ */
+ commandTimestamp: bigint;
+
+ /**
+ * Information about the two teams.
+ *
+ * @generated from field: required Referee.TeamInfo yellow = 7;
+ */
+ yellow?: Referee_TeamInfo;
+
+ /**
+ * @generated from field: required Referee.TeamInfo blue = 8;
+ */
+ blue?: Referee_TeamInfo;
+
+ /**
+ * @generated from field: optional Referee.Point designated_position = 9;
+ */
+ designatedPosition?: Referee_Point;
+
+ /**
+ * Information about the direction of play.
+ * True, if the blue team will have it's goal on the positive x-axis of the ssl-vision coordinate system.
+ * Obviously, the yellow team will play on the opposite half.
+ *
+ * @generated from field: optional bool blue_team_on_positive_half = 10;
+ */
+ blueTeamOnPositiveHalf: boolean;
+
+ /**
+ * The command that will be issued after the current stoppage and ball placement to continue the game.
+ *
+ * @generated from field: optional Referee.Command next_command = 12;
+ */
+ nextCommand: Referee_Command;
+
+ /**
+ * @generated from field: repeated GameEvent game_events = 16;
+ */
+ gameEvents: GameEvent[];
+
+ /**
+ * @generated from field: repeated GameEventProposalGroup game_event_proposals = 17;
+ */
+ gameEventProposals: GameEventProposalGroup[];
+
+ /**
+ * The time in microseconds that is remaining until the current action times out
+ * The time will not be reset. It can get negative.
+ * An autoRef would raise an appropriate event, if the time gets negative.
+ * Possible actions where this time is relevant:
+ * * free kicks
+ * * kickoff, penalty kick, force start
+ * * ball placement
+ *
+ * @generated from field: optional int64 current_action_time_remaining = 15;
+ */
+ currentActionTimeRemaining: bigint;
+
+ /**
+ * A message that can be displayed to the spectators, like a reason for a stoppage.
+ *
+ * @generated from field: optional string status_message = 20;
+ */
+ statusMessage: string;
+};
+
+/**
+ * Each UDP packet contains one of these messages.
+ *
+ * @generated from message Referee
+ */
+export type RefereeJson = {
+ /**
+ * A random UUID of the source that is kept constant at the source while running
+ * If multiple sources are broadcasting to the same network, this id can be used to identify individual sources
+ *
+ * @generated from field: optional string source_identifier = 18;
+ */
+ sourceIdentifier?: string;
+
+ /**
+ * The match type is a meta information about the current match that helps to process the logs after a competition
+ *
+ * @generated from field: optional MatchType match_type = 19 [default = UNKNOWN_MATCH];
+ */
+ matchType?: MatchTypeJson;
+
+ /**
+ * The UNIX timestamp when the packet was sent, in microseconds.
+ * Divide by 1,000,000 to get a time_t.
+ *
+ * @generated from field: required uint64 packet_timestamp = 1;
+ */
+ packetTimestamp?: string;
+
+ /**
+ * @generated from field: required Referee.Stage stage = 2;
+ */
+ stage?: Referee_StageJson;
+
+ /**
+ * The number of microseconds left in the stage.
+ * The following stages have this value; the rest do not:
+ * NORMAL_FIRST_HALF
+ * NORMAL_HALF_TIME
+ * NORMAL_SECOND_HALF
+ * EXTRA_TIME_BREAK
+ * EXTRA_FIRST_HALF
+ * EXTRA_HALF_TIME
+ * EXTRA_SECOND_HALF
+ * PENALTY_SHOOTOUT_BREAK
+ *
+ * If the stage runs over its specified time, this value
+ * becomes negative.
+ *
+ * @generated from field: optional sint64 stage_time_left = 3;
+ */
+ stageTimeLeft?: string;
+
+ /**
+ * @generated from field: required Referee.Command command = 4;
+ */
+ command?: Referee_CommandJson;
+
+ /**
+ * The number of commands issued since startup (mod 2^32).
+ *
+ * @generated from field: required uint32 command_counter = 5;
+ */
+ commandCounter?: number;
+
+ /**
+ * The UNIX timestamp when the command was issued, in microseconds.
+ * This value changes only when a new command is issued, not on each packet.
+ *
+ * @generated from field: required uint64 command_timestamp = 6;
+ */
+ commandTimestamp?: string;
+
+ /**
+ * Information about the two teams.
+ *
+ * @generated from field: required Referee.TeamInfo yellow = 7;
+ */
+ yellow?: Referee_TeamInfoJson;
+
+ /**
+ * @generated from field: required Referee.TeamInfo blue = 8;
+ */
+ blue?: Referee_TeamInfoJson;
+
+ /**
+ * @generated from field: optional Referee.Point designated_position = 9;
+ */
+ designatedPosition?: Referee_PointJson;
+
+ /**
+ * Information about the direction of play.
+ * True, if the blue team will have it's goal on the positive x-axis of the ssl-vision coordinate system.
+ * Obviously, the yellow team will play on the opposite half.
+ *
+ * @generated from field: optional bool blue_team_on_positive_half = 10;
+ */
+ blueTeamOnPositiveHalf?: boolean;
+
+ /**
+ * The command that will be issued after the current stoppage and ball placement to continue the game.
+ *
+ * @generated from field: optional Referee.Command next_command = 12;
+ */
+ nextCommand?: Referee_CommandJson;
+
+ /**
+ * @generated from field: repeated GameEvent game_events = 16;
+ */
+ gameEvents?: GameEventJson[];
+
+ /**
+ * @generated from field: repeated GameEventProposalGroup game_event_proposals = 17;
+ */
+ gameEventProposals?: GameEventProposalGroupJson[];
+
+ /**
+ * The time in microseconds that is remaining until the current action times out
+ * The time will not be reset. It can get negative.
+ * An autoRef would raise an appropriate event, if the time gets negative.
+ * Possible actions where this time is relevant:
+ * * free kicks
+ * * kickoff, penalty kick, force start
+ * * ball placement
+ *
+ * @generated from field: optional int64 current_action_time_remaining = 15;
+ */
+ currentActionTimeRemaining?: string;
+
+ /**
+ * A message that can be displayed to the spectators, like a reason for a stoppage.
+ *
+ * @generated from field: optional string status_message = 20;
+ */
+ statusMessage?: string;
+};
+
+/**
+ * Describes the message Referee.
+ * Use `create(RefereeSchema)` to create a new message.
+ */
+export const RefereeSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_referee_message, 0);
+
+/**
+ * Information about a single team.
+ *
+ * @generated from message Referee.TeamInfo
+ */
+export type Referee_TeamInfo = Message<"Referee.TeamInfo"> & {
+ /**
+ * The team's name (empty string if operator has not typed anything).
+ *
+ * @generated from field: required string name = 1;
+ */
+ name: string;
+
+ /**
+ * The number of goals scored by the team during normal play and overtime.
+ *
+ * @generated from field: required uint32 score = 2;
+ */
+ score: number;
+
+ /**
+ * The number of red cards issued to the team since the beginning of the game.
+ *
+ * @generated from field: required uint32 red_cards = 3;
+ */
+ redCards: number;
+
+ /**
+ * The amount of time (in microseconds) left on each yellow card issued to the team.
+ * If no yellow cards are issued, this array has no elements.
+ * Otherwise, times are ordered from smallest to largest.
+ *
+ * @generated from field: repeated uint32 yellow_card_times = 4 [packed = true];
+ */
+ yellowCardTimes: number[];
+
+ /**
+ * The total number of yellow cards ever issued to the team.
+ *
+ * @generated from field: required uint32 yellow_cards = 5;
+ */
+ yellowCards: number;
+
+ /**
+ * The number of timeouts this team can still call.
+ * If in a timeout right now, that timeout is excluded.
+ *
+ * @generated from field: required uint32 timeouts = 6;
+ */
+ timeouts: number;
+
+ /**
+ * The number of microseconds of timeout this team can use.
+ *
+ * @generated from field: required uint32 timeout_time = 7;
+ */
+ timeoutTime: number;
+
+ /**
+ * The pattern number of this team's goalkeeper.
+ *
+ * @generated from field: required uint32 goalkeeper = 8;
+ */
+ goalkeeper: number;
+
+ /**
+ * The total number of countable fouls that act towards yellow cards
+ *
+ * @generated from field: optional uint32 foul_counter = 9;
+ */
+ foulCounter: number;
+
+ /**
+ * The number of consecutive ball placement failures of this team
+ *
+ * @generated from field: optional uint32 ball_placement_failures = 10;
+ */
+ ballPlacementFailures: number;
+
+ /**
+ * Indicate if the team is able and allowed to place the ball
+ *
+ * @generated from field: optional bool can_place_ball = 12;
+ */
+ canPlaceBall: boolean;
+
+ /**
+ * The maximum number of bots allowed on the field based on division and cards
+ *
+ * @generated from field: optional uint32 max_allowed_bots = 13;
+ */
+ maxAllowedBots: number;
+
+ /**
+ * The team has submitted an intent to substitute one or more robots at the next chance
+ *
+ * @generated from field: optional bool bot_substitution_intent = 14;
+ */
+ botSubstitutionIntent: boolean;
+
+ /**
+ * Indicate if the team reached the maximum allowed ball placement failures and is thus not allowed to place the ball anymore
+ *
+ * @generated from field: optional bool ball_placement_failures_reached = 15;
+ */
+ ballPlacementFailuresReached: boolean;
+
+ /**
+ * The team is allowed to substitute one or more robots currently
+ *
+ * @generated from field: optional bool bot_substitution_allowed = 16;
+ */
+ botSubstitutionAllowed: boolean;
+
+ /**
+ * The number of bot substitutions left by the team in this halftime
+ *
+ * @generated from field: optional uint32 bot_substitutions_left = 17;
+ */
+ botSubstitutionsLeft: number;
+
+ /**
+ * The number of microseconds left for current bot substitution
+ *
+ * @generated from field: optional uint32 bot_substitution_time_left = 18;
+ */
+ botSubstitutionTimeLeft: number;
+
+ /**
+ * The color of the hull of the robots of this team
+ *
+ * @generated from field: optional HullColor hull_color = 19;
+ */
+ hullColor: HullColor;
+};
+
+/**
+ * Information about a single team.
+ *
+ * @generated from message Referee.TeamInfo
+ */
+export type Referee_TeamInfoJson = {
+ /**
+ * The team's name (empty string if operator has not typed anything).
+ *
+ * @generated from field: required string name = 1;
+ */
+ name?: string;
+
+ /**
+ * The number of goals scored by the team during normal play and overtime.
+ *
+ * @generated from field: required uint32 score = 2;
+ */
+ score?: number;
+
+ /**
+ * The number of red cards issued to the team since the beginning of the game.
+ *
+ * @generated from field: required uint32 red_cards = 3;
+ */
+ redCards?: number;
+
+ /**
+ * The amount of time (in microseconds) left on each yellow card issued to the team.
+ * If no yellow cards are issued, this array has no elements.
+ * Otherwise, times are ordered from smallest to largest.
+ *
+ * @generated from field: repeated uint32 yellow_card_times = 4 [packed = true];
+ */
+ yellowCardTimes?: number[];
+
+ /**
+ * The total number of yellow cards ever issued to the team.
+ *
+ * @generated from field: required uint32 yellow_cards = 5;
+ */
+ yellowCards?: number;
+
+ /**
+ * The number of timeouts this team can still call.
+ * If in a timeout right now, that timeout is excluded.
+ *
+ * @generated from field: required uint32 timeouts = 6;
+ */
+ timeouts?: number;
+
+ /**
+ * The number of microseconds of timeout this team can use.
+ *
+ * @generated from field: required uint32 timeout_time = 7;
+ */
+ timeoutTime?: number;
+
+ /**
+ * The pattern number of this team's goalkeeper.
+ *
+ * @generated from field: required uint32 goalkeeper = 8;
+ */
+ goalkeeper?: number;
+
+ /**
+ * The total number of countable fouls that act towards yellow cards
+ *
+ * @generated from field: optional uint32 foul_counter = 9;
+ */
+ foulCounter?: number;
+
+ /**
+ * The number of consecutive ball placement failures of this team
+ *
+ * @generated from field: optional uint32 ball_placement_failures = 10;
+ */
+ ballPlacementFailures?: number;
+
+ /**
+ * Indicate if the team is able and allowed to place the ball
+ *
+ * @generated from field: optional bool can_place_ball = 12;
+ */
+ canPlaceBall?: boolean;
+
+ /**
+ * The maximum number of bots allowed on the field based on division and cards
+ *
+ * @generated from field: optional uint32 max_allowed_bots = 13;
+ */
+ maxAllowedBots?: number;
+
+ /**
+ * The team has submitted an intent to substitute one or more robots at the next chance
+ *
+ * @generated from field: optional bool bot_substitution_intent = 14;
+ */
+ botSubstitutionIntent?: boolean;
+
+ /**
+ * Indicate if the team reached the maximum allowed ball placement failures and is thus not allowed to place the ball anymore
+ *
+ * @generated from field: optional bool ball_placement_failures_reached = 15;
+ */
+ ballPlacementFailuresReached?: boolean;
+
+ /**
+ * The team is allowed to substitute one or more robots currently
+ *
+ * @generated from field: optional bool bot_substitution_allowed = 16;
+ */
+ botSubstitutionAllowed?: boolean;
+
+ /**
+ * The number of bot substitutions left by the team in this halftime
+ *
+ * @generated from field: optional uint32 bot_substitutions_left = 17;
+ */
+ botSubstitutionsLeft?: number;
+
+ /**
+ * The number of microseconds left for current bot substitution
+ *
+ * @generated from field: optional uint32 bot_substitution_time_left = 18;
+ */
+ botSubstitutionTimeLeft?: number;
+
+ /**
+ * The color of the hull of the robots of this team
+ *
+ * @generated from field: optional HullColor hull_color = 19;
+ */
+ hullColor?: HullColorJson;
+};
+
+/**
+ * Describes the message Referee.TeamInfo.
+ * Use `create(Referee_TeamInfoSchema)` to create a new message.
+ */
+export const Referee_TeamInfoSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_referee_message, 0, 0);
+
+/**
+ * The coordinates of the Designated Position. These are measured in
+ * millimetres and correspond to SSL-Vision coordinates. These fields are
+ * always either both present (in the case of a ball placement command) or
+ * both absent (in the case of any other command).
+ *
+ * @generated from message Referee.Point
+ */
+export type Referee_Point = Message<"Referee.Point"> & {
+ /**
+ * @generated from field: required float x = 1;
+ */
+ x: number;
+
+ /**
+ * @generated from field: required float y = 2;
+ */
+ y: number;
+};
+
+/**
+ * The coordinates of the Designated Position. These are measured in
+ * millimetres and correspond to SSL-Vision coordinates. These fields are
+ * always either both present (in the case of a ball placement command) or
+ * both absent (in the case of any other command).
+ *
+ * @generated from message Referee.Point
+ */
+export type Referee_PointJson = {
+ /**
+ * @generated from field: required float x = 1;
+ */
+ x?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: required float y = 2;
+ */
+ y?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message Referee.Point.
+ * Use `create(Referee_PointSchema)` to create a new message.
+ */
+export const Referee_PointSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_referee_message, 0, 1);
+
+/**
+ * These are the "coarse" stages of the game.
+ *
+ * @generated from enum Referee.Stage
+ */
+export enum Referee_Stage {
+ /**
+ * The first half is about to start.
+ * A kickoff is called within this stage.
+ * This stage ends with the NORMAL_START.
+ *
+ * @generated from enum value: NORMAL_FIRST_HALF_PRE = 0;
+ */
+ NORMAL_FIRST_HALF_PRE = 0,
+
+ /**
+ * The first half of the normal game, before half time.
+ *
+ * @generated from enum value: NORMAL_FIRST_HALF = 1;
+ */
+ NORMAL_FIRST_HALF = 1,
+
+ /**
+ * Half time between first and second halves.
+ *
+ * @generated from enum value: NORMAL_HALF_TIME = 2;
+ */
+ NORMAL_HALF_TIME = 2,
+
+ /**
+ * The second half is about to start.
+ * A kickoff is called within this stage.
+ * This stage ends with the NORMAL_START.
+ *
+ * @generated from enum value: NORMAL_SECOND_HALF_PRE = 3;
+ */
+ NORMAL_SECOND_HALF_PRE = 3,
+
+ /**
+ * The second half of the normal game, after half time.
+ *
+ * @generated from enum value: NORMAL_SECOND_HALF = 4;
+ */
+ NORMAL_SECOND_HALF = 4,
+
+ /**
+ * The break before extra time.
+ *
+ * @generated from enum value: EXTRA_TIME_BREAK = 5;
+ */
+ EXTRA_TIME_BREAK = 5,
+
+ /**
+ * The first half of extra time is about to start.
+ * A kickoff is called within this stage.
+ * This stage ends with the NORMAL_START.
+ *
+ * @generated from enum value: EXTRA_FIRST_HALF_PRE = 6;
+ */
+ EXTRA_FIRST_HALF_PRE = 6,
+
+ /**
+ * The first half of extra time.
+ *
+ * @generated from enum value: EXTRA_FIRST_HALF = 7;
+ */
+ EXTRA_FIRST_HALF = 7,
+
+ /**
+ * Half time between first and second extra halves.
+ *
+ * @generated from enum value: EXTRA_HALF_TIME = 8;
+ */
+ EXTRA_HALF_TIME = 8,
+
+ /**
+ * The second half of extra time is about to start.
+ * A kickoff is called within this stage.
+ * This stage ends with the NORMAL_START.
+ *
+ * @generated from enum value: EXTRA_SECOND_HALF_PRE = 9;
+ */
+ EXTRA_SECOND_HALF_PRE = 9,
+
+ /**
+ * The second half of extra time.
+ *
+ * @generated from enum value: EXTRA_SECOND_HALF = 10;
+ */
+ EXTRA_SECOND_HALF = 10,
+
+ /**
+ * The break before penalty shootout.
+ *
+ * @generated from enum value: PENALTY_SHOOTOUT_BREAK = 11;
+ */
+ PENALTY_SHOOTOUT_BREAK = 11,
+
+ /**
+ * The penalty shootout.
+ *
+ * @generated from enum value: PENALTY_SHOOTOUT = 12;
+ */
+ PENALTY_SHOOTOUT = 12,
+
+ /**
+ * The game is over.
+ *
+ * @generated from enum value: POST_GAME = 13;
+ */
+ POST_GAME = 13,
+}
+
+/**
+ * These are the "coarse" stages of the game.
+ *
+ * @generated from enum Referee.Stage
+ */
+export type Referee_StageJson = "NORMAL_FIRST_HALF_PRE" | "NORMAL_FIRST_HALF" | "NORMAL_HALF_TIME" | "NORMAL_SECOND_HALF_PRE" | "NORMAL_SECOND_HALF" | "EXTRA_TIME_BREAK" | "EXTRA_FIRST_HALF_PRE" | "EXTRA_FIRST_HALF" | "EXTRA_HALF_TIME" | "EXTRA_SECOND_HALF_PRE" | "EXTRA_SECOND_HALF" | "PENALTY_SHOOTOUT_BREAK" | "PENALTY_SHOOTOUT" | "POST_GAME";
+
+/**
+ * Describes the enum Referee.Stage.
+ */
+export const Referee_StageSchema: GenEnum = /*@__PURE__*/
+ enumDesc(file_gamecontroller_ssl_gc_referee_message, 0, 0);
+
+/**
+ * These are the "fine" states of play on the field.
+ *
+ * @generated from enum Referee.Command
+ */
+export enum Referee_Command {
+ /**
+ * All robots should completely stop moving.
+ *
+ * @generated from enum value: HALT = 0;
+ */
+ HALT = 0,
+
+ /**
+ * Robots must keep 50 cm from the ball.
+ *
+ * @generated from enum value: STOP = 1;
+ */
+ STOP = 1,
+
+ /**
+ * A prepared kickoff or penalty may now be taken.
+ *
+ * @generated from enum value: NORMAL_START = 2;
+ */
+ NORMAL_START = 2,
+
+ /**
+ * The ball is dropped and free for either team.
+ *
+ * @generated from enum value: FORCE_START = 3;
+ */
+ FORCE_START = 3,
+
+ /**
+ * The yellow team may move into kickoff position.
+ *
+ * @generated from enum value: PREPARE_KICKOFF_YELLOW = 4;
+ */
+ PREPARE_KICKOFF_YELLOW = 4,
+
+ /**
+ * The blue team may move into kickoff position.
+ *
+ * @generated from enum value: PREPARE_KICKOFF_BLUE = 5;
+ */
+ PREPARE_KICKOFF_BLUE = 5,
+
+ /**
+ * The yellow team may move into penalty position.
+ *
+ * @generated from enum value: PREPARE_PENALTY_YELLOW = 6;
+ */
+ PREPARE_PENALTY_YELLOW = 6,
+
+ /**
+ * The blue team may move into penalty position.
+ *
+ * @generated from enum value: PREPARE_PENALTY_BLUE = 7;
+ */
+ PREPARE_PENALTY_BLUE = 7,
+
+ /**
+ * The yellow team may take a direct free kick.
+ *
+ * @generated from enum value: DIRECT_FREE_YELLOW = 8;
+ */
+ DIRECT_FREE_YELLOW = 8,
+
+ /**
+ * The blue team may take a direct free kick.
+ *
+ * @generated from enum value: DIRECT_FREE_BLUE = 9;
+ */
+ DIRECT_FREE_BLUE = 9,
+
+ /**
+ * The yellow team may take an indirect free kick.
+ *
+ * @generated from enum value: INDIRECT_FREE_YELLOW = 10 [deprecated = true];
+ * @deprecated
+ */
+ INDIRECT_FREE_YELLOW = 10,
+
+ /**
+ * The blue team may take an indirect free kick.
+ *
+ * @generated from enum value: INDIRECT_FREE_BLUE = 11 [deprecated = true];
+ * @deprecated
+ */
+ INDIRECT_FREE_BLUE = 11,
+
+ /**
+ * The yellow team is currently in a timeout.
+ *
+ * @generated from enum value: TIMEOUT_YELLOW = 12;
+ */
+ TIMEOUT_YELLOW = 12,
+
+ /**
+ * The blue team is currently in a timeout.
+ *
+ * @generated from enum value: TIMEOUT_BLUE = 13;
+ */
+ TIMEOUT_BLUE = 13,
+
+ /**
+ * The yellow team just scored a goal.
+ * For information only.
+ * Deprecated: Use the score field from the team infos instead. That way, you can also detect revoked goals.
+ *
+ * @generated from enum value: GOAL_YELLOW = 14 [deprecated = true];
+ * @deprecated
+ */
+ GOAL_YELLOW = 14,
+
+ /**
+ * The blue team just scored a goal. See also GOAL_YELLOW.
+ *
+ * @generated from enum value: GOAL_BLUE = 15 [deprecated = true];
+ * @deprecated
+ */
+ GOAL_BLUE = 15,
+
+ /**
+ * Equivalent to STOP, but the yellow team must pick up the ball and
+ * drop it in the Designated Position.
+ *
+ * @generated from enum value: BALL_PLACEMENT_YELLOW = 16;
+ */
+ BALL_PLACEMENT_YELLOW = 16,
+
+ /**
+ * Equivalent to STOP, but the blue team must pick up the ball and drop
+ * it in the Designated Position.
+ *
+ * @generated from enum value: BALL_PLACEMENT_BLUE = 17;
+ */
+ BALL_PLACEMENT_BLUE = 17,
+}
+
+/**
+ * These are the "fine" states of play on the field.
+ *
+ * @generated from enum Referee.Command
+ */
+export type Referee_CommandJson = "HALT" | "STOP" | "NORMAL_START" | "FORCE_START" | "PREPARE_KICKOFF_YELLOW" | "PREPARE_KICKOFF_BLUE" | "PREPARE_PENALTY_YELLOW" | "PREPARE_PENALTY_BLUE" | "DIRECT_FREE_YELLOW" | "DIRECT_FREE_BLUE" | "INDIRECT_FREE_YELLOW" | "INDIRECT_FREE_BLUE" | "TIMEOUT_YELLOW" | "TIMEOUT_BLUE" | "GOAL_YELLOW" | "GOAL_BLUE" | "BALL_PLACEMENT_YELLOW" | "BALL_PLACEMENT_BLUE";
+
+/**
+ * Describes the enum Referee.Command.
+ */
+export const Referee_CommandSchema: GenEnum = /*@__PURE__*/
+ enumDesc(file_gamecontroller_ssl_gc_referee_message, 0, 1);
+
+/**
+ * List of matching proposals
+ *
+ * @generated from message GameEventProposalGroup
+ */
+export type GameEventProposalGroup = Message<"GameEventProposalGroup"> & {
+ /**
+ * Unique ID of this group
+ *
+ * @generated from field: optional string id = 3;
+ */
+ id: string;
+
+ /**
+ * The proposed game events
+ *
+ * @generated from field: repeated GameEvent game_events = 1;
+ */
+ gameEvents: GameEvent[];
+
+ /**
+ * Whether the proposal group was accepted
+ *
+ * @generated from field: optional bool accepted = 2;
+ */
+ accepted: boolean;
+};
+
+/**
+ * List of matching proposals
+ *
+ * @generated from message GameEventProposalGroup
+ */
+export type GameEventProposalGroupJson = {
+ /**
+ * Unique ID of this group
+ *
+ * @generated from field: optional string id = 3;
+ */
+ id?: string;
+
+ /**
+ * The proposed game events
+ *
+ * @generated from field: repeated GameEvent game_events = 1;
+ */
+ gameEvents?: GameEventJson[];
+
+ /**
+ * Whether the proposal group was accepted
+ *
+ * @generated from field: optional bool accepted = 2;
+ */
+ accepted?: boolean;
+};
+
+/**
+ * Describes the message GameEventProposalGroup.
+ * Use `create(GameEventProposalGroupSchema)` to create a new message.
+ */
+export const GameEventProposalGroupSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_gamecontroller_ssl_gc_referee_message, 1);
+
+/**
+ * MatchType is a meta information about the current match for easier log processing
+ *
+ * @generated from enum MatchType
+ */
+export enum MatchType {
+ /**
+ * not set
+ *
+ * @generated from enum value: UNKNOWN_MATCH = 0;
+ */
+ UNKNOWN_MATCH = 0,
+
+ /**
+ * match is part of the group phase
+ *
+ * @generated from enum value: GROUP_PHASE = 1;
+ */
+ GROUP_PHASE = 1,
+
+ /**
+ * match is part of the elimination phase
+ *
+ * @generated from enum value: ELIMINATION_PHASE = 2;
+ */
+ ELIMINATION_PHASE = 2,
+
+ /**
+ * a friendly match, not part of a tournament
+ *
+ * @generated from enum value: FRIENDLY = 3;
+ */
+ FRIENDLY = 3,
+}
+
+/**
+ * MatchType is a meta information about the current match for easier log processing
+ *
+ * @generated from enum MatchType
+ */
+export type MatchTypeJson = "UNKNOWN_MATCH" | "GROUP_PHASE" | "ELIMINATION_PHASE" | "FRIENDLY";
+
+/**
+ * Describes the enum MatchType.
+ */
+export const MatchTypeSchema: GenEnum = /*@__PURE__*/
+ enumDesc(file_gamecontroller_ssl_gc_referee_message, 0);
+
+/**
+ * HullColor is the color of the hull of the robots of a team
+ *
+ * @generated from enum HullColor
+ */
+export enum HullColor {
+ /**
+ * not set
+ *
+ * @generated from enum value: HULL_COLOR_UNKNOWN = 0;
+ */
+ UNKNOWN = 0,
+
+ /**
+ * dark hull color
+ *
+ * @generated from enum value: HULL_COLOR_DARK = 1;
+ */
+ DARK = 1,
+
+ /**
+ * light hull color
+ *
+ * @generated from enum value: HULL_COLOR_LIGHT = 2;
+ */
+ LIGHT = 2,
+}
+
+/**
+ * HullColor is the color of the hull of the robots of a team
+ *
+ * @generated from enum HullColor
+ */
+export type HullColorJson = "HULL_COLOR_UNKNOWN" | "HULL_COLOR_DARK" | "HULL_COLOR_LIGHT";
+
+/**
+ * Describes the enum HullColor.
+ */
+export const HullColorSchema: GenEnum = /*@__PURE__*/
+ enumDesc(file_gamecontroller_ssl_gc_referee_message, 1);
+
diff --git a/gui/frontend/src/proto/vision/ssl_vision_detection_pb.ts b/gui/frontend/src/proto/vision/ssl_vision_detection_pb.ts
new file mode 100644
index 0000000..899f846
--- /dev/null
+++ b/gui/frontend/src/proto/vision/ssl_vision_detection_pb.ts
@@ -0,0 +1,403 @@
+// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
+// @generated from file vision/ssl_vision_detection.proto (syntax proto2)
+/* eslint-disable */
+
+import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
+import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
+import type { Message } from "@bufbuild/protobuf";
+
+/**
+ * Describes the file vision/ssl_vision_detection.proto.
+ */
+export const file_vision_ssl_vision_detection: GenFile = /*@__PURE__*/
+ fileDesc("CiF2aXNpb24vc3NsX3Zpc2lvbl9kZXRlY3Rpb24ucHJvdG8ieAoRU1NMX0RldGVjdGlvbkJhbGwSEgoKY29uZmlkZW5jZRgBIAIoAhIMCgRhcmVhGAIgASgNEgkKAXgYAyACKAISCQoBeRgEIAIoAhIJCgF6GAUgASgCEg8KB3BpeGVsX3gYBiACKAISDwoHcGl4ZWxfeRgHIAIoAiKXAQoSU1NMX0RldGVjdGlvblJvYm90EhIKCmNvbmZpZGVuY2UYASACKAISEAoIcm9ib3RfaWQYAiABKA0SCQoBeBgDIAIoAhIJCgF5GAQgAigCEhMKC29yaWVudGF0aW9uGAUgASgCEg8KB3BpeGVsX3gYBiACKAISDwoHcGl4ZWxfeRgHIAIoAhIOCgZoZWlnaHQYCCABKAIihgIKElNTTF9EZXRlY3Rpb25GcmFtZRIUCgxmcmFtZV9udW1iZXIYASACKA0SEQoJdF9jYXB0dXJlGAIgAigBEg4KBnRfc2VudBgDIAIoARIYChB0X2NhcHR1cmVfY2FtZXJhGAggASgBEhEKCXRfb2Zmc2V0cxgJIAMoAhIRCgljYW1lcmFfaWQYBCACKA0SIQoFYmFsbHMYBSADKAsyEi5TU0xfRGV0ZWN0aW9uQmFsbBIqCg1yb2JvdHNfeWVsbG93GAYgAygLMhMuU1NMX0RldGVjdGlvblJvYm90EigKC3JvYm90c19ibHVlGAcgAygLMhMuU1NMX0RldGVjdGlvblJvYm90QlxCF1NzbFZpc2lvbkRldGVjdGlvblByb3RvUAFaP2dpdGh1Yi5jb20vUm9ib0N1cC1TU0wvc3NsLXZpc2lvbi1wcm9jZXNzb3IvZ3VpL2ludGVybmFsL3Zpc2lvbg");
+
+/**
+ * @generated from message SSL_DetectionBall
+ */
+export type SSL_DetectionBall = Message<"SSL_DetectionBall"> & {
+ /**
+ * Confidence in [0-1] of the detection
+ *
+ * @generated from field: required float confidence = 1;
+ */
+ confidence: number;
+
+ /**
+ * @generated from field: optional uint32 area = 2;
+ */
+ area: number;
+
+ /**
+ * X-coordinate in [mm] in global ssl-vision coordinate system
+ *
+ * @generated from field: required float x = 3;
+ */
+ x: number;
+
+ /**
+ * Y-coordinate in [mm] in global ssl-vision coordinate system
+ *
+ * @generated from field: required float y = 4;
+ */
+ y: number;
+
+ /**
+ * Z-coordinate in [mm] in global ssl-vision coordinate system
+ * Not supported by ssl-vision, but might be set by simulators
+ *
+ * @generated from field: optional float z = 5;
+ */
+ z: number;
+
+ /**
+ * X-coordinate in [pixel] in the image
+ *
+ * @generated from field: required float pixel_x = 6;
+ */
+ pixelX: number;
+
+ /**
+ * Y-coordinate in [pixel] in the image
+ *
+ * @generated from field: required float pixel_y = 7;
+ */
+ pixelY: number;
+};
+
+/**
+ * @generated from message SSL_DetectionBall
+ */
+export type SSL_DetectionBallJson = {
+ /**
+ * Confidence in [0-1] of the detection
+ *
+ * @generated from field: required float confidence = 1;
+ */
+ confidence?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: optional uint32 area = 2;
+ */
+ area?: number;
+
+ /**
+ * X-coordinate in [mm] in global ssl-vision coordinate system
+ *
+ * @generated from field: required float x = 3;
+ */
+ x?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Y-coordinate in [mm] in global ssl-vision coordinate system
+ *
+ * @generated from field: required float y = 4;
+ */
+ y?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Z-coordinate in [mm] in global ssl-vision coordinate system
+ * Not supported by ssl-vision, but might be set by simulators
+ *
+ * @generated from field: optional float z = 5;
+ */
+ z?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * X-coordinate in [pixel] in the image
+ *
+ * @generated from field: required float pixel_x = 6;
+ */
+ pixelX?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Y-coordinate in [pixel] in the image
+ *
+ * @generated from field: required float pixel_y = 7;
+ */
+ pixelY?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message SSL_DetectionBall.
+ * Use `create(SSL_DetectionBallSchema)` to create a new message.
+ */
+export const SSL_DetectionBallSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vision_detection, 0);
+
+/**
+ * @generated from message SSL_DetectionRobot
+ */
+export type SSL_DetectionRobot = Message<"SSL_DetectionRobot"> & {
+ /**
+ * Confidence in [0-1] of the detection
+ *
+ * @generated from field: required float confidence = 1;
+ */
+ confidence: number;
+
+ /**
+ * Id of the robot
+ *
+ * @generated from field: optional uint32 robot_id = 2;
+ */
+ robotId: number;
+
+ /**
+ * X-coordinate in [mm] in global ssl-vision coordinate system
+ *
+ * @generated from field: required float x = 3;
+ */
+ x: number;
+
+ /**
+ * Y-coordinate in [mm] in global ssl-vision coordinate system
+ *
+ * @generated from field: required float y = 4;
+ */
+ y: number;
+
+ /**
+ * Orientation in [rad]
+ *
+ * @generated from field: optional float orientation = 5;
+ */
+ orientation: number;
+
+ /**
+ * X-coordinate in [pixel] in the image
+ *
+ * @generated from field: required float pixel_x = 6;
+ */
+ pixelX: number;
+
+ /**
+ * Y-coordinate in [pixel] in the image
+ *
+ * @generated from field: required float pixel_y = 7;
+ */
+ pixelY: number;
+
+ /**
+ * Height, as configured in ssl-vision for the respective team
+ *
+ * @generated from field: optional float height = 8;
+ */
+ height: number;
+};
+
+/**
+ * @generated from message SSL_DetectionRobot
+ */
+export type SSL_DetectionRobotJson = {
+ /**
+ * Confidence in [0-1] of the detection
+ *
+ * @generated from field: required float confidence = 1;
+ */
+ confidence?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Id of the robot
+ *
+ * @generated from field: optional uint32 robot_id = 2;
+ */
+ robotId?: number;
+
+ /**
+ * X-coordinate in [mm] in global ssl-vision coordinate system
+ *
+ * @generated from field: required float x = 3;
+ */
+ x?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Y-coordinate in [mm] in global ssl-vision coordinate system
+ *
+ * @generated from field: required float y = 4;
+ */
+ y?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Orientation in [rad]
+ *
+ * @generated from field: optional float orientation = 5;
+ */
+ orientation?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * X-coordinate in [pixel] in the image
+ *
+ * @generated from field: required float pixel_x = 6;
+ */
+ pixelX?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Y-coordinate in [pixel] in the image
+ *
+ * @generated from field: required float pixel_y = 7;
+ */
+ pixelY?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Height, as configured in ssl-vision for the respective team
+ *
+ * @generated from field: optional float height = 8;
+ */
+ height?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message SSL_DetectionRobot.
+ * Use `create(SSL_DetectionRobotSchema)` to create a new message.
+ */
+export const SSL_DetectionRobotSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vision_detection, 1);
+
+/**
+ * @generated from message SSL_DetectionFrame
+ */
+export type SSL_DetectionFrame = Message<"SSL_DetectionFrame"> & {
+ /**
+ * monotonously increasing frame number
+ *
+ * @generated from field: required uint32 frame_number = 1;
+ */
+ frameNumber: number;
+
+ /**
+ * Unix timestamp in [seconds] at which the image has been received by ssl-vision
+ *
+ * @generated from field: required double t_capture = 2;
+ */
+ tCapture: number;
+
+ /**
+ * Unix timestamp in [seconds] at which this message has been sent to the network
+ *
+ * @generated from field: required double t_sent = 3;
+ */
+ tSent: number;
+
+ /**
+ * Camera timestamp in [seconds] as reported by the camera, if supported
+ * This is not necessarily a unix timestamp
+ *
+ * @generated from field: optional double t_capture_camera = 8;
+ */
+ tCaptureCamera: number;
+
+ /**
+ * Internal VisionProcessor field for clock synchronization,
+ * containing the time offset of received packets for each cam relative to the local clock.
+ *
+ * @generated from field: repeated float t_offsets = 9;
+ */
+ tOffsets: number[];
+
+ /**
+ * Identifier of the camera
+ *
+ * @generated from field: required uint32 camera_id = 4;
+ */
+ cameraId: number;
+
+ /**
+ * Detected balls
+ *
+ * @generated from field: repeated SSL_DetectionBall balls = 5;
+ */
+ balls: SSL_DetectionBall[];
+
+ /**
+ * Detected yellow robots
+ *
+ * @generated from field: repeated SSL_DetectionRobot robots_yellow = 6;
+ */
+ robotsYellow: SSL_DetectionRobot[];
+
+ /**
+ * Detected blue robots
+ *
+ * @generated from field: repeated SSL_DetectionRobot robots_blue = 7;
+ */
+ robotsBlue: SSL_DetectionRobot[];
+};
+
+/**
+ * @generated from message SSL_DetectionFrame
+ */
+export type SSL_DetectionFrameJson = {
+ /**
+ * monotonously increasing frame number
+ *
+ * @generated from field: required uint32 frame_number = 1;
+ */
+ frameNumber?: number;
+
+ /**
+ * Unix timestamp in [seconds] at which the image has been received by ssl-vision
+ *
+ * @generated from field: required double t_capture = 2;
+ */
+ tCapture?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Unix timestamp in [seconds] at which this message has been sent to the network
+ *
+ * @generated from field: required double t_sent = 3;
+ */
+ tSent?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Camera timestamp in [seconds] as reported by the camera, if supported
+ * This is not necessarily a unix timestamp
+ *
+ * @generated from field: optional double t_capture_camera = 8;
+ */
+ tCaptureCamera?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Internal VisionProcessor field for clock synchronization,
+ * containing the time offset of received packets for each cam relative to the local clock.
+ *
+ * @generated from field: repeated float t_offsets = 9;
+ */
+ tOffsets?: (number | "NaN" | "Infinity" | "-Infinity")[];
+
+ /**
+ * Identifier of the camera
+ *
+ * @generated from field: required uint32 camera_id = 4;
+ */
+ cameraId?: number;
+
+ /**
+ * Detected balls
+ *
+ * @generated from field: repeated SSL_DetectionBall balls = 5;
+ */
+ balls?: SSL_DetectionBallJson[];
+
+ /**
+ * Detected yellow robots
+ *
+ * @generated from field: repeated SSL_DetectionRobot robots_yellow = 6;
+ */
+ robotsYellow?: SSL_DetectionRobotJson[];
+
+ /**
+ * Detected blue robots
+ *
+ * @generated from field: repeated SSL_DetectionRobot robots_blue = 7;
+ */
+ robotsBlue?: SSL_DetectionRobotJson[];
+};
+
+/**
+ * Describes the message SSL_DetectionFrame.
+ * Use `create(SSL_DetectionFrameSchema)` to create a new message.
+ */
+export const SSL_DetectionFrameSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vision_detection, 2);
+
diff --git a/gui/frontend/src/proto/vision/ssl_vision_detection_tracked_pb.ts b/gui/frontend/src/proto/vision/ssl_vision_detection_tracked_pb.ts
new file mode 100644
index 0000000..9dedf77
--- /dev/null
+++ b/gui/frontend/src/proto/vision/ssl_vision_detection_tracked_pb.ts
@@ -0,0 +1,448 @@
+// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
+// @generated from file vision/ssl_vision_detection_tracked.proto (syntax proto2)
+/* eslint-disable */
+
+import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
+import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
+import type { RobotId, RobotIdJson } from "../gamecontroller/ssl_gc_common_pb";
+import { file_gamecontroller_ssl_gc_common } from "../gamecontroller/ssl_gc_common_pb";
+import type { Vector2, Vector2Json, Vector3, Vector3Json } from "../gamecontroller/ssl_gc_geometry_pb";
+import { file_gamecontroller_ssl_gc_geometry } from "../gamecontroller/ssl_gc_geometry_pb";
+import type { Message } from "@bufbuild/protobuf";
+
+/**
+ * Describes the file vision/ssl_vision_detection_tracked.proto.
+ */
+export const file_vision_ssl_vision_detection_tracked: GenFile = /*@__PURE__*/
+ fileDesc("Cil2aXNpb24vc3NsX3Zpc2lvbl9kZXRlY3Rpb25fdHJhY2tlZC5wcm90byJPCgtUcmFja2VkQmFsbBIVCgNwb3MYASACKAsyCC5WZWN0b3IzEhUKA3ZlbBgCIAEoCzIILlZlY3RvcjMSEgoKdmlzaWJpbGl0eRgDIAEoAiKjAQoKS2lja2VkQmFsbBIVCgNwb3MYASACKAsyCC5WZWN0b3IyEhUKA3ZlbBgCIAIoCzIILlZlY3RvcjMSFwoPc3RhcnRfdGltZXN0YW1wGAMgAigBEhYKDnN0b3BfdGltZXN0YW1wGAQgASgBEhoKCHN0b3BfcG9zGAUgASgLMgguVmVjdG9yMhIaCghyb2JvdF9pZBgGIAEoCzIILlJvYm90SWQilgEKDFRyYWNrZWRSb2JvdBIaCghyb2JvdF9pZBgBIAIoCzIILlJvYm90SWQSFQoDcG9zGAIgAigLMgguVmVjdG9yMhITCgtvcmllbnRhdGlvbhgDIAIoAhIVCgN2ZWwYBCABKAsyCC5WZWN0b3IyEhMKC3ZlbF9hbmd1bGFyGAUgASgCEhIKCnZpc2liaWxpdHkYBiABKAIiuAEKDFRyYWNrZWRGcmFtZRIUCgxmcmFtZV9udW1iZXIYASACKA0SEQoJdGltZXN0YW1wGAIgAigBEhsKBWJhbGxzGAMgAygLMgwuVHJhY2tlZEJhbGwSHQoGcm9ib3RzGAQgAygLMg0uVHJhY2tlZFJvYm90EiAKC2tpY2tlZF9iYWxsGAUgASgLMgsuS2lja2VkQmFsbBIhCgxjYXBhYmlsaXRpZXMYBiADKA4yCy5DYXBhYmlsaXR5KpIBCgpDYXBhYmlsaXR5EhYKEkNBUEFCSUxJVFlfVU5LTk9XThAAEiIKHkNBUEFCSUxJVFlfREVURUNUX0ZMWUlOR19CQUxMUxABEiQKIENBUEFCSUxJVFlfREVURUNUX01VTFRJUExFX0JBTExTEAISIgoeQ0FQQUJJTElUWV9ERVRFQ1RfS0lDS0VEX0JBTExTEANCY0IeU3NsVmlzaW9uRGV0ZWN0aW9uVHJhY2tlZFByb3RvUAFaP2dpdGh1Yi5jb20vUm9ib0N1cC1TU0wvc3NsLXZpc2lvbi1wcm9jZXNzb3IvZ3VpL2ludGVybmFsL3Zpc2lvbg", [file_gamecontroller_ssl_gc_common, file_gamecontroller_ssl_gc_geometry]);
+
+/**
+ * A single tracked ball
+ *
+ * @generated from message TrackedBall
+ */
+export type TrackedBall = Message<"TrackedBall"> & {
+ /**
+ * The position (x, y, height) [m] in the ssl-vision coordinate system
+ *
+ * @generated from field: required Vector3 pos = 1;
+ */
+ pos?: Vector3;
+
+ /**
+ * The velocity [m/s] in the ssl-vision coordinate system
+ *
+ * @generated from field: optional Vector3 vel = 2;
+ */
+ vel?: Vector3;
+
+ /**
+ * The visibility of the ball
+ * A value between 0 (not visible) and 1 (visible)
+ * The exact implementation depends on the source software
+ *
+ * @generated from field: optional float visibility = 3;
+ */
+ visibility: number;
+};
+
+/**
+ * A single tracked ball
+ *
+ * @generated from message TrackedBall
+ */
+export type TrackedBallJson = {
+ /**
+ * The position (x, y, height) [m] in the ssl-vision coordinate system
+ *
+ * @generated from field: required Vector3 pos = 1;
+ */
+ pos?: Vector3Json;
+
+ /**
+ * The velocity [m/s] in the ssl-vision coordinate system
+ *
+ * @generated from field: optional Vector3 vel = 2;
+ */
+ vel?: Vector3Json;
+
+ /**
+ * The visibility of the ball
+ * A value between 0 (not visible) and 1 (visible)
+ * The exact implementation depends on the source software
+ *
+ * @generated from field: optional float visibility = 3;
+ */
+ visibility?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message TrackedBall.
+ * Use `create(TrackedBallSchema)` to create a new message.
+ */
+export const TrackedBallSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vision_detection_tracked, 0);
+
+/**
+ * A ball kicked by a robot, including predictions when the ball will come to a stop
+ *
+ * @generated from message KickedBall
+ */
+export type KickedBall = Message<"KickedBall"> & {
+ /**
+ * The initial position [m] from which the ball was kicked
+ *
+ * @generated from field: required Vector2 pos = 1;
+ */
+ pos?: Vector2;
+
+ /**
+ * The initial velocity [m/s] with which the ball was kicked
+ *
+ * @generated from field: required Vector3 vel = 2;
+ */
+ vel?: Vector3;
+
+ /**
+ * The unix timestamp [s] when the kick was performed
+ *
+ * @generated from field: required double start_timestamp = 3;
+ */
+ startTimestamp: number;
+
+ /**
+ * The predicted unix timestamp [s] when the ball comes to a stop
+ *
+ * @generated from field: optional double stop_timestamp = 4;
+ */
+ stopTimestamp: number;
+
+ /**
+ * The predicted position [m] at which the ball will come to a stop
+ *
+ * @generated from field: optional Vector2 stop_pos = 5;
+ */
+ stopPos?: Vector2;
+
+ /**
+ * The robot that kicked the ball
+ *
+ * @generated from field: optional RobotId robot_id = 6;
+ */
+ robotId?: RobotId;
+};
+
+/**
+ * A ball kicked by a robot, including predictions when the ball will come to a stop
+ *
+ * @generated from message KickedBall
+ */
+export type KickedBallJson = {
+ /**
+ * The initial position [m] from which the ball was kicked
+ *
+ * @generated from field: required Vector2 pos = 1;
+ */
+ pos?: Vector2Json;
+
+ /**
+ * The initial velocity [m/s] with which the ball was kicked
+ *
+ * @generated from field: required Vector3 vel = 2;
+ */
+ vel?: Vector3Json;
+
+ /**
+ * The unix timestamp [s] when the kick was performed
+ *
+ * @generated from field: required double start_timestamp = 3;
+ */
+ startTimestamp?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * The predicted unix timestamp [s] when the ball comes to a stop
+ *
+ * @generated from field: optional double stop_timestamp = 4;
+ */
+ stopTimestamp?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * The predicted position [m] at which the ball will come to a stop
+ *
+ * @generated from field: optional Vector2 stop_pos = 5;
+ */
+ stopPos?: Vector2Json;
+
+ /**
+ * The robot that kicked the ball
+ *
+ * @generated from field: optional RobotId robot_id = 6;
+ */
+ robotId?: RobotIdJson;
+};
+
+/**
+ * Describes the message KickedBall.
+ * Use `create(KickedBallSchema)` to create a new message.
+ */
+export const KickedBallSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vision_detection_tracked, 1);
+
+/**
+ * A single tracked robot
+ *
+ * @generated from message TrackedRobot
+ */
+export type TrackedRobot = Message<"TrackedRobot"> & {
+ /**
+ * @generated from field: required RobotId robot_id = 1;
+ */
+ robotId?: RobotId;
+
+ /**
+ * The position [m] in the ssl-vision coordinate system
+ *
+ * @generated from field: required Vector2 pos = 2;
+ */
+ pos?: Vector2;
+
+ /**
+ * The orientation [rad] in the ssl-vision coordinate system
+ *
+ * @generated from field: required float orientation = 3;
+ */
+ orientation: number;
+
+ /**
+ * The velocity [m/s] in the ssl-vision coordinate system
+ *
+ * @generated from field: optional Vector2 vel = 4;
+ */
+ vel?: Vector2;
+
+ /**
+ * The angular velocity [rad/s] in the ssl-vision coordinate system
+ *
+ * @generated from field: optional float vel_angular = 5;
+ */
+ velAngular: number;
+
+ /**
+ * The visibility of the robot
+ * A value between 0 (not visible) and 1 (visible)
+ * The exact implementation depends on the source software
+ *
+ * @generated from field: optional float visibility = 6;
+ */
+ visibility: number;
+};
+
+/**
+ * A single tracked robot
+ *
+ * @generated from message TrackedRobot
+ */
+export type TrackedRobotJson = {
+ /**
+ * @generated from field: required RobotId robot_id = 1;
+ */
+ robotId?: RobotIdJson;
+
+ /**
+ * The position [m] in the ssl-vision coordinate system
+ *
+ * @generated from field: required Vector2 pos = 2;
+ */
+ pos?: Vector2Json;
+
+ /**
+ * The orientation [rad] in the ssl-vision coordinate system
+ *
+ * @generated from field: required float orientation = 3;
+ */
+ orientation?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * The velocity [m/s] in the ssl-vision coordinate system
+ *
+ * @generated from field: optional Vector2 vel = 4;
+ */
+ vel?: Vector2Json;
+
+ /**
+ * The angular velocity [rad/s] in the ssl-vision coordinate system
+ *
+ * @generated from field: optional float vel_angular = 5;
+ */
+ velAngular?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * The visibility of the robot
+ * A value between 0 (not visible) and 1 (visible)
+ * The exact implementation depends on the source software
+ *
+ * @generated from field: optional float visibility = 6;
+ */
+ visibility?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message TrackedRobot.
+ * Use `create(TrackedRobotSchema)` to create a new message.
+ */
+export const TrackedRobotSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vision_detection_tracked, 2);
+
+/**
+ * A frame that contains all currently tracked objects on the field on all cameras
+ *
+ * @generated from message TrackedFrame
+ */
+export type TrackedFrame = Message<"TrackedFrame"> & {
+ /**
+ * A monotonous increasing frame counter
+ *
+ * @generated from field: required uint32 frame_number = 1;
+ */
+ frameNumber: number;
+
+ /**
+ * The unix timestamp in [s] of the data
+ * If timestamp is larger than timestamp_captured, the source has applied a prediction already
+ *
+ * @generated from field: required double timestamp = 2;
+ */
+ timestamp: number;
+
+ /**
+ * The list of detected balls
+ * The first ball is the primary one
+ * Sources may add additional balls based on their capabilities
+ *
+ * @generated from field: repeated TrackedBall balls = 3;
+ */
+ balls: TrackedBall[];
+
+ /**
+ * The list of detected robots of both teams
+ *
+ * @generated from field: repeated TrackedRobot robots = 4;
+ */
+ robots: TrackedRobot[];
+
+ /**
+ * Information about a kicked ball, if the ball was kicked by a robot and is still moving
+ * Note: This field is optional. Some source implementations might not set this at any time
+ *
+ * @generated from field: optional KickedBall kicked_ball = 5;
+ */
+ kickedBall?: KickedBall;
+
+ /**
+ * List of capabilities of the source implementation
+ *
+ * @generated from field: repeated Capability capabilities = 6;
+ */
+ capabilities: Capability[];
+};
+
+/**
+ * A frame that contains all currently tracked objects on the field on all cameras
+ *
+ * @generated from message TrackedFrame
+ */
+export type TrackedFrameJson = {
+ /**
+ * A monotonous increasing frame counter
+ *
+ * @generated from field: required uint32 frame_number = 1;
+ */
+ frameNumber?: number;
+
+ /**
+ * The unix timestamp in [s] of the data
+ * If timestamp is larger than timestamp_captured, the source has applied a prediction already
+ *
+ * @generated from field: required double timestamp = 2;
+ */
+ timestamp?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * The list of detected balls
+ * The first ball is the primary one
+ * Sources may add additional balls based on their capabilities
+ *
+ * @generated from field: repeated TrackedBall balls = 3;
+ */
+ balls?: TrackedBallJson[];
+
+ /**
+ * The list of detected robots of both teams
+ *
+ * @generated from field: repeated TrackedRobot robots = 4;
+ */
+ robots?: TrackedRobotJson[];
+
+ /**
+ * Information about a kicked ball, if the ball was kicked by a robot and is still moving
+ * Note: This field is optional. Some source implementations might not set this at any time
+ *
+ * @generated from field: optional KickedBall kicked_ball = 5;
+ */
+ kickedBall?: KickedBallJson;
+
+ /**
+ * List of capabilities of the source implementation
+ *
+ * @generated from field: repeated Capability capabilities = 6;
+ */
+ capabilities?: CapabilityJson[];
+};
+
+/**
+ * Describes the message TrackedFrame.
+ * Use `create(TrackedFrameSchema)` to create a new message.
+ */
+export const TrackedFrameSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vision_detection_tracked, 3);
+
+/**
+ * Capabilities that a source implementation can have
+ *
+ * @generated from enum Capability
+ */
+export enum Capability {
+ /**
+ * @generated from enum value: CAPABILITY_UNKNOWN = 0;
+ */
+ UNKNOWN = 0,
+
+ /**
+ * @generated from enum value: CAPABILITY_DETECT_FLYING_BALLS = 1;
+ */
+ DETECT_FLYING_BALLS = 1,
+
+ /**
+ * @generated from enum value: CAPABILITY_DETECT_MULTIPLE_BALLS = 2;
+ */
+ DETECT_MULTIPLE_BALLS = 2,
+
+ /**
+ * @generated from enum value: CAPABILITY_DETECT_KICKED_BALLS = 3;
+ */
+ DETECT_KICKED_BALLS = 3,
+}
+
+/**
+ * Capabilities that a source implementation can have
+ *
+ * @generated from enum Capability
+ */
+export type CapabilityJson = "CAPABILITY_UNKNOWN" | "CAPABILITY_DETECT_FLYING_BALLS" | "CAPABILITY_DETECT_MULTIPLE_BALLS" | "CAPABILITY_DETECT_KICKED_BALLS";
+
+/**
+ * Describes the enum Capability.
+ */
+export const CapabilitySchema: GenEnum = /*@__PURE__*/
+ enumDesc(file_vision_ssl_vision_detection_tracked, 0);
+
diff --git a/gui/frontend/src/proto/vision/ssl_vision_geometry_pb.ts b/gui/frontend/src/proto/vision/ssl_vision_geometry_pb.ts
new file mode 100644
index 0000000..08bc7db
--- /dev/null
+++ b/gui/frontend/src/proto/vision/ssl_vision_geometry_pb.ts
@@ -0,0 +1,1031 @@
+// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
+// @generated from file vision/ssl_vision_geometry.proto (syntax proto2)
+/* eslint-disable */
+
+import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
+import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
+import type { Message } from "@bufbuild/protobuf";
+
+/**
+ * Describes the file vision/ssl_vision_geometry.proto.
+ */
+export const file_vision_ssl_vision_geometry: GenFile = /*@__PURE__*/
+ fileDesc("CiB2aXNpb24vc3NsX3Zpc2lvbl9nZW9tZXRyeS5wcm90byIgCghWZWN0b3IyZhIJCgF4GAEgAigCEgkKAXkYAiACKAIiiAEKFFNTTF9GaWVsZExpbmVTZWdtZW50EgwKBG5hbWUYASACKAkSFQoCcDEYAiACKAsyCS5WZWN0b3IyZhIVCgJwMhgDIAIoCzIJLlZlY3RvcjJmEhEKCXRoaWNrbmVzcxgEIAIoAhIhCgR0eXBlGAUgASgOMhMuU1NMX0ZpZWxkU2hhcGVUeXBlIp0BChRTU0xfRmllbGRDaXJjdWxhckFyYxIMCgRuYW1lGAEgAigJEhkKBmNlbnRlchgCIAIoCzIJLlZlY3RvcjJmEg4KBnJhZGl1cxgDIAIoAhIKCgJhMRgEIAIoAhIKCgJhMhgFIAIoAhIRCgl0aGlja25lc3MYBiACKAISIQoEdHlwZRgHIAEoDjITLlNTTF9GaWVsZFNoYXBlVHlwZSL4AwoVU1NMX0dlb21ldHJ5RmllbGRTaXplEhQKDGZpZWxkX2xlbmd0aBgBIAIoBRITCgtmaWVsZF93aWR0aBgCIAIoBRISCgpnb2FsX3dpZHRoGAMgAigFEhIKCmdvYWxfZGVwdGgYBCACKAUSFgoOYm91bmRhcnlfd2lkdGgYBSACKAUSIAoYYm91bmRhcnlfd2lkdGhfZ29hbF9saW5lGBAgASgFEioKC2ZpZWxkX2xpbmVzGAYgAygLMhUuU1NMX0ZpZWxkTGluZVNlZ21lbnQSKQoKZmllbGRfYXJjcxgHIAMoCzIVLlNTTF9GaWVsZENpcmN1bGFyQXJjEhoKEnBlbmFsdHlfYXJlYV9kZXB0aBgIIAEoBRIaChJwZW5hbHR5X2FyZWFfd2lkdGgYCSABKAUSHAoUY2VudGVyX2NpcmNsZV9yYWRpdXMYCiABKAUSFgoObGluZV90aGlja25lc3MYCyABKAUSIwobZ29hbF9jZW50ZXJfdG9fcGVuYWx0eV9tYXJrGAwgASgFEhMKC2dvYWxfaGVpZ2h0GA0gASgFEhMKC2JhbGxfcmFkaXVzGA4gASgCEhgKEG1heF9yb2JvdF9yYWRpdXMYDyABKAISJAocZ29hbF9zdWJzdGl0dXRpb25fYXJlYV93aWR0aBgRIAEoBSKAAwodU1NMX0dlb21ldHJ5Q2FtZXJhQ2FsaWJyYXRpb24SEQoJY2FtZXJhX2lkGAEgAigNEhQKDGZvY2FsX2xlbmd0aBgCIAIoAhIZChFwcmluY2lwYWxfcG9pbnRfeBgDIAIoAhIZChFwcmluY2lwYWxfcG9pbnRfeRgEIAIoAhISCgpkaXN0b3J0aW9uGAUgAigCEgoKAnEwGAYgAigCEgoKAnExGAcgAigCEgoKAnEyGAggAigCEgoKAnEzGAkgAigCEgoKAnR4GAogAigCEgoKAnR5GAsgAigCEgoKAnR6GAwgAigCEh8KF2Rlcml2ZWRfY2FtZXJhX3dvcmxkX3R4GA0gASgCEh8KF2Rlcml2ZWRfY2FtZXJhX3dvcmxkX3R5GA4gASgCEh8KF2Rlcml2ZWRfY2FtZXJhX3dvcmxkX3R6GA8gASgCEhkKEXBpeGVsX2ltYWdlX3dpZHRoGBAgASgNEhoKEnBpeGVsX2ltYWdlX2hlaWdodBgRIAEoDSJWCh1TU0xfQmFsbE1vZGVsU3RyYWlnaHRUd29QaGFzZRIRCglhY2Nfc2xpZGUYASACKAESEAoIYWNjX3JvbGwYAiACKAESEAoIa19zd2l0Y2gYAyACKAEibAoaU1NMX0JhbGxNb2RlbENoaXBGaXhlZExvc3MSHAoUZGFtcGluZ194eV9maXJzdF9ob3AYASACKAESHQoVZGFtcGluZ194eV9vdGhlcl9ob3BzGAIgAigBEhEKCWRhbXBpbmdfehgDIAIoASKGAQoSU1NMX0dlb21ldHJ5TW9kZWxzEjoKEnN0cmFpZ2h0X3R3b19waGFzZRgBIAEoCzIeLlNTTF9CYWxsTW9kZWxTdHJhaWdodFR3b1BoYXNlEjQKD2NoaXBfZml4ZWRfbG9zcxgCIAEoCzIbLlNTTF9CYWxsTW9kZWxDaGlwRml4ZWRMb3NzIo0BChBTU0xfR2VvbWV0cnlEYXRhEiUKBWZpZWxkGAEgAigLMhYuU1NMX0dlb21ldHJ5RmllbGRTaXplEi0KBWNhbGliGAIgAygLMh4uU1NMX0dlb21ldHJ5Q2FtZXJhQ2FsaWJyYXRpb24SIwoGbW9kZWxzGAMgASgLMhMuU1NMX0dlb21ldHJ5TW9kZWxzKtsCChJTU0xfRmllbGRTaGFwZVR5cGUSDQoJVW5kZWZpbmVkEAASEAoMQ2VudGVyQ2lyY2xlEAESEAoMVG9wVG91Y2hMaW5lEAISEwoPQm90dG9tVG91Y2hMaW5lEAMSEAoMTGVmdEdvYWxMaW5lEAQSEQoNUmlnaHRHb2FsTGluZRAFEg8KC0hhbGZ3YXlMaW5lEAYSDgoKQ2VudGVyTGluZRAHEhYKEkxlZnRQZW5hbHR5U3RyZXRjaBAIEhcKE1JpZ2h0UGVuYWx0eVN0cmV0Y2gQCRIfChtMZWZ0RmllbGRMZWZ0UGVuYWx0eVN0cmV0Y2gQChIgChxMZWZ0RmllbGRSaWdodFBlbmFsdHlTdHJldGNoEAsSIAocUmlnaHRGaWVsZExlZnRQZW5hbHR5U3RyZXRjaBAMEiEKHVJpZ2h0RmllbGRSaWdodFBlbmFsdHlTdHJldGNoEA1CW0IWU3NsVmlzaW9uR2VvbWV0cnlQcm90b1ABWj9naXRodWIuY29tL1JvYm9DdXAtU1NML3NzbC12aXNpb24tcHJvY2Vzc29yL2d1aS9pbnRlcm5hbC92aXNpb24");
+
+/**
+ * A 2D float vector.
+ *
+ * @generated from message Vector2f
+ */
+export type Vector2f = Message<"Vector2f"> & {
+ /**
+ * X-coordinate in mm
+ *
+ * @generated from field: required float x = 1;
+ */
+ x: number;
+
+ /**
+ * Y-coordinate in mm
+ *
+ * @generated from field: required float y = 2;
+ */
+ y: number;
+};
+
+/**
+ * A 2D float vector.
+ *
+ * @generated from message Vector2f
+ */
+export type Vector2fJson = {
+ /**
+ * X-coordinate in mm
+ *
+ * @generated from field: required float x = 1;
+ */
+ x?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Y-coordinate in mm
+ *
+ * @generated from field: required float y = 2;
+ */
+ y?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message Vector2f.
+ * Use `create(Vector2fSchema)` to create a new message.
+ */
+export const Vector2fSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vision_geometry, 0);
+
+/**
+ * Represents a field marking as a line segment represented by a start point p1,
+ * and end point p2, and a line thickness. The start and end points are along
+ * the center of the line, so the thickness of the line extends by thickness / 2
+ * on either side of the line.
+ *
+ * @generated from message SSL_FieldLineSegment
+ */
+export type SSL_FieldLineSegment = Message<"SSL_FieldLineSegment"> & {
+ /**
+ * Name of this field marking.
+ *
+ * @generated from field: required string name = 1;
+ */
+ name: string;
+
+ /**
+ * Start point of the line segment.
+ *
+ * @generated from field: required Vector2f p1 = 2;
+ */
+ p1?: Vector2f;
+
+ /**
+ * End point of the line segment.
+ *
+ * @generated from field: required Vector2f p2 = 3;
+ */
+ p2?: Vector2f;
+
+ /**
+ * Thickness of the line segment.
+ *
+ * @generated from field: required float thickness = 4;
+ */
+ thickness: number;
+
+ /**
+ * The type of this shape
+ *
+ * @generated from field: optional SSL_FieldShapeType type = 5;
+ */
+ type: SSL_FieldShapeType;
+};
+
+/**
+ * Represents a field marking as a line segment represented by a start point p1,
+ * and end point p2, and a line thickness. The start and end points are along
+ * the center of the line, so the thickness of the line extends by thickness / 2
+ * on either side of the line.
+ *
+ * @generated from message SSL_FieldLineSegment
+ */
+export type SSL_FieldLineSegmentJson = {
+ /**
+ * Name of this field marking.
+ *
+ * @generated from field: required string name = 1;
+ */
+ name?: string;
+
+ /**
+ * Start point of the line segment.
+ *
+ * @generated from field: required Vector2f p1 = 2;
+ */
+ p1?: Vector2fJson;
+
+ /**
+ * End point of the line segment.
+ *
+ * @generated from field: required Vector2f p2 = 3;
+ */
+ p2?: Vector2fJson;
+
+ /**
+ * Thickness of the line segment.
+ *
+ * @generated from field: required float thickness = 4;
+ */
+ thickness?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * The type of this shape
+ *
+ * @generated from field: optional SSL_FieldShapeType type = 5;
+ */
+ type?: SSL_FieldShapeTypeJson;
+};
+
+/**
+ * Describes the message SSL_FieldLineSegment.
+ * Use `create(SSL_FieldLineSegmentSchema)` to create a new message.
+ */
+export const SSL_FieldLineSegmentSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vision_geometry, 1);
+
+/**
+ * Represents a field marking as a circular arc segment represented by center point, a
+ * start angle, an end angle, and an arc thickness.
+ *
+ * @generated from message SSL_FieldCircularArc
+ */
+export type SSL_FieldCircularArc = Message<"SSL_FieldCircularArc"> & {
+ /**
+ * Name of this field marking.
+ *
+ * @generated from field: required string name = 1;
+ */
+ name: string;
+
+ /**
+ * Center point of the circular arc.
+ *
+ * @generated from field: required Vector2f center = 2;
+ */
+ center?: Vector2f;
+
+ /**
+ * Radius of the arc.
+ *
+ * @generated from field: required float radius = 3;
+ */
+ radius: number;
+
+ /**
+ * Start angle in counter-clockwise order.
+ *
+ * @generated from field: required float a1 = 4;
+ */
+ a1: number;
+
+ /**
+ * End angle in counter-clockwise order.
+ *
+ * @generated from field: required float a2 = 5;
+ */
+ a2: number;
+
+ /**
+ * Thickness of the arc.
+ *
+ * @generated from field: required float thickness = 6;
+ */
+ thickness: number;
+
+ /**
+ * The type of this shape
+ *
+ * @generated from field: optional SSL_FieldShapeType type = 7;
+ */
+ type: SSL_FieldShapeType;
+};
+
+/**
+ * Represents a field marking as a circular arc segment represented by center point, a
+ * start angle, an end angle, and an arc thickness.
+ *
+ * @generated from message SSL_FieldCircularArc
+ */
+export type SSL_FieldCircularArcJson = {
+ /**
+ * Name of this field marking.
+ *
+ * @generated from field: required string name = 1;
+ */
+ name?: string;
+
+ /**
+ * Center point of the circular arc.
+ *
+ * @generated from field: required Vector2f center = 2;
+ */
+ center?: Vector2fJson;
+
+ /**
+ * Radius of the arc.
+ *
+ * @generated from field: required float radius = 3;
+ */
+ radius?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Start angle in counter-clockwise order.
+ *
+ * @generated from field: required float a1 = 4;
+ */
+ a1?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * End angle in counter-clockwise order.
+ *
+ * @generated from field: required float a2 = 5;
+ */
+ a2?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Thickness of the arc.
+ *
+ * @generated from field: required float thickness = 6;
+ */
+ thickness?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * The type of this shape
+ *
+ * @generated from field: optional SSL_FieldShapeType type = 7;
+ */
+ type?: SSL_FieldShapeTypeJson;
+};
+
+/**
+ * Describes the message SSL_FieldCircularArc.
+ * Use `create(SSL_FieldCircularArcSchema)` to create a new message.
+ */
+export const SSL_FieldCircularArcSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vision_geometry, 2);
+
+/**
+ * @generated from message SSL_GeometryFieldSize
+ */
+export type SSL_GeometryFieldSize = Message<"SSL_GeometryFieldSize"> & {
+ /**
+ * Field length (distance between goal lines) in mm
+ *
+ * @generated from field: required int32 field_length = 1;
+ */
+ fieldLength: number;
+
+ /**
+ * Field width (distance between touch lines) in mm
+ *
+ * @generated from field: required int32 field_width = 2;
+ */
+ fieldWidth: number;
+
+ /**
+ * Goal width (distance between inner edges of goal posts) in mm
+ *
+ * @generated from field: required int32 goal_width = 3;
+ */
+ goalWidth: number;
+
+ /**
+ * Goal depth (distance from outer goal line edge to inner goal back) in mm
+ *
+ * @generated from field: required int32 goal_depth = 4;
+ */
+ goalDepth: number;
+
+ /**
+ * Boundary width (distance from touch line centers to boundary walls) in mm
+ *
+ * @generated from field: required int32 boundary_width = 5;
+ */
+ boundaryWidth: number;
+
+ /**
+ * Boundary width at the goal lines (distance from goal line centers to boundary walls) in mm
+ *
+ * @generated from field: optional int32 boundary_width_goal_line = 16;
+ */
+ boundaryWidthGoalLine: number;
+
+ /**
+ * Generated line segments based on the other parameters
+ *
+ * @generated from field: repeated SSL_FieldLineSegment field_lines = 6;
+ */
+ fieldLines: SSL_FieldLineSegment[];
+
+ /**
+ * Generated circular arcs based on the other parameters
+ *
+ * @generated from field: repeated SSL_FieldCircularArc field_arcs = 7;
+ */
+ fieldArcs: SSL_FieldCircularArc[];
+
+ /**
+ * Depth of the penalty/defense area (measured between line centers) in mm
+ *
+ * @generated from field: optional int32 penalty_area_depth = 8;
+ */
+ penaltyAreaDepth: number;
+
+ /**
+ * Width of the penalty/defense area (measured between line centers) in mm
+ *
+ * @generated from field: optional int32 penalty_area_width = 9;
+ */
+ penaltyAreaWidth: number;
+
+ /**
+ * Radius of the center circle (measured between line centers) in mm
+ *
+ * @generated from field: optional int32 center_circle_radius = 10;
+ */
+ centerCircleRadius: number;
+
+ /**
+ * Thickness/width of the lines on the field in mm
+ *
+ * @generated from field: optional int32 line_thickness = 11;
+ */
+ lineThickness: number;
+
+ /**
+ * Distance between the goal center and the center of the penalty mark in mm
+ *
+ * @generated from field: optional int32 goal_center_to_penalty_mark = 12;
+ */
+ goalCenterToPenaltyMark: number;
+
+ /**
+ * Goal height in mm
+ *
+ * @generated from field: optional int32 goal_height = 13;
+ */
+ goalHeight: number;
+
+ /**
+ * Ball radius in mm (note that this is a float type to represent sub-mm precision)
+ *
+ * @generated from field: optional float ball_radius = 14;
+ */
+ ballRadius: number;
+
+ /**
+ * Max allowed robot radius in mm (note that this is a float type to represent sub-mm precision)
+ *
+ * @generated from field: optional float max_robot_radius = 15;
+ */
+ maxRobotRadius: number;
+
+ /**
+ * Width of the goal substitution area (distance from goal line center plus boundary width to boundary walls) in mm
+ *
+ * @generated from field: optional int32 goal_substitution_area_width = 17;
+ */
+ goalSubstitutionAreaWidth: number;
+};
+
+/**
+ * @generated from message SSL_GeometryFieldSize
+ */
+export type SSL_GeometryFieldSizeJson = {
+ /**
+ * Field length (distance between goal lines) in mm
+ *
+ * @generated from field: required int32 field_length = 1;
+ */
+ fieldLength?: number;
+
+ /**
+ * Field width (distance between touch lines) in mm
+ *
+ * @generated from field: required int32 field_width = 2;
+ */
+ fieldWidth?: number;
+
+ /**
+ * Goal width (distance between inner edges of goal posts) in mm
+ *
+ * @generated from field: required int32 goal_width = 3;
+ */
+ goalWidth?: number;
+
+ /**
+ * Goal depth (distance from outer goal line edge to inner goal back) in mm
+ *
+ * @generated from field: required int32 goal_depth = 4;
+ */
+ goalDepth?: number;
+
+ /**
+ * Boundary width (distance from touch line centers to boundary walls) in mm
+ *
+ * @generated from field: required int32 boundary_width = 5;
+ */
+ boundaryWidth?: number;
+
+ /**
+ * Boundary width at the goal lines (distance from goal line centers to boundary walls) in mm
+ *
+ * @generated from field: optional int32 boundary_width_goal_line = 16;
+ */
+ boundaryWidthGoalLine?: number;
+
+ /**
+ * Generated line segments based on the other parameters
+ *
+ * @generated from field: repeated SSL_FieldLineSegment field_lines = 6;
+ */
+ fieldLines?: SSL_FieldLineSegmentJson[];
+
+ /**
+ * Generated circular arcs based on the other parameters
+ *
+ * @generated from field: repeated SSL_FieldCircularArc field_arcs = 7;
+ */
+ fieldArcs?: SSL_FieldCircularArcJson[];
+
+ /**
+ * Depth of the penalty/defense area (measured between line centers) in mm
+ *
+ * @generated from field: optional int32 penalty_area_depth = 8;
+ */
+ penaltyAreaDepth?: number;
+
+ /**
+ * Width of the penalty/defense area (measured between line centers) in mm
+ *
+ * @generated from field: optional int32 penalty_area_width = 9;
+ */
+ penaltyAreaWidth?: number;
+
+ /**
+ * Radius of the center circle (measured between line centers) in mm
+ *
+ * @generated from field: optional int32 center_circle_radius = 10;
+ */
+ centerCircleRadius?: number;
+
+ /**
+ * Thickness/width of the lines on the field in mm
+ *
+ * @generated from field: optional int32 line_thickness = 11;
+ */
+ lineThickness?: number;
+
+ /**
+ * Distance between the goal center and the center of the penalty mark in mm
+ *
+ * @generated from field: optional int32 goal_center_to_penalty_mark = 12;
+ */
+ goalCenterToPenaltyMark?: number;
+
+ /**
+ * Goal height in mm
+ *
+ * @generated from field: optional int32 goal_height = 13;
+ */
+ goalHeight?: number;
+
+ /**
+ * Ball radius in mm (note that this is a float type to represent sub-mm precision)
+ *
+ * @generated from field: optional float ball_radius = 14;
+ */
+ ballRadius?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Max allowed robot radius in mm (note that this is a float type to represent sub-mm precision)
+ *
+ * @generated from field: optional float max_robot_radius = 15;
+ */
+ maxRobotRadius?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Width of the goal substitution area (distance from goal line center plus boundary width to boundary walls) in mm
+ *
+ * @generated from field: optional int32 goal_substitution_area_width = 17;
+ */
+ goalSubstitutionAreaWidth?: number;
+};
+
+/**
+ * Describes the message SSL_GeometryFieldSize.
+ * Use `create(SSL_GeometryFieldSizeSchema)` to create a new message.
+ */
+export const SSL_GeometryFieldSizeSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vision_geometry, 3);
+
+/**
+ * @generated from message SSL_GeometryCameraCalibration
+ */
+export type SSL_GeometryCameraCalibration = Message<"SSL_GeometryCameraCalibration"> & {
+ /**
+ * @generated from field: required uint32 camera_id = 1;
+ */
+ cameraId: number;
+
+ /**
+ * @generated from field: required float focal_length = 2;
+ */
+ focalLength: number;
+
+ /**
+ * @generated from field: required float principal_point_x = 3;
+ */
+ principalPointX: number;
+
+ /**
+ * @generated from field: required float principal_point_y = 4;
+ */
+ principalPointY: number;
+
+ /**
+ * @generated from field: required float distortion = 5;
+ */
+ distortion: number;
+
+ /**
+ * @generated from field: required float q0 = 6;
+ */
+ q0: number;
+
+ /**
+ * @generated from field: required float q1 = 7;
+ */
+ q1: number;
+
+ /**
+ * @generated from field: required float q2 = 8;
+ */
+ q2: number;
+
+ /**
+ * @generated from field: required float q3 = 9;
+ */
+ q3: number;
+
+ /**
+ * @generated from field: required float tx = 10;
+ */
+ tx: number;
+
+ /**
+ * @generated from field: required float ty = 11;
+ */
+ ty: number;
+
+ /**
+ * @generated from field: required float tz = 12;
+ */
+ tz: number;
+
+ /**
+ * @generated from field: optional float derived_camera_world_tx = 13;
+ */
+ derivedCameraWorldTx: number;
+
+ /**
+ * @generated from field: optional float derived_camera_world_ty = 14;
+ */
+ derivedCameraWorldTy: number;
+
+ /**
+ * @generated from field: optional float derived_camera_world_tz = 15;
+ */
+ derivedCameraWorldTz: number;
+
+ /**
+ * @generated from field: optional uint32 pixel_image_width = 16;
+ */
+ pixelImageWidth: number;
+
+ /**
+ * @generated from field: optional uint32 pixel_image_height = 17;
+ */
+ pixelImageHeight: number;
+};
+
+/**
+ * @generated from message SSL_GeometryCameraCalibration
+ */
+export type SSL_GeometryCameraCalibrationJson = {
+ /**
+ * @generated from field: required uint32 camera_id = 1;
+ */
+ cameraId?: number;
+
+ /**
+ * @generated from field: required float focal_length = 2;
+ */
+ focalLength?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: required float principal_point_x = 3;
+ */
+ principalPointX?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: required float principal_point_y = 4;
+ */
+ principalPointY?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: required float distortion = 5;
+ */
+ distortion?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: required float q0 = 6;
+ */
+ q0?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: required float q1 = 7;
+ */
+ q1?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: required float q2 = 8;
+ */
+ q2?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: required float q3 = 9;
+ */
+ q3?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: required float tx = 10;
+ */
+ tx?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: required float ty = 11;
+ */
+ ty?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: required float tz = 12;
+ */
+ tz?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: optional float derived_camera_world_tx = 13;
+ */
+ derivedCameraWorldTx?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: optional float derived_camera_world_ty = 14;
+ */
+ derivedCameraWorldTy?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: optional float derived_camera_world_tz = 15;
+ */
+ derivedCameraWorldTz?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: optional uint32 pixel_image_width = 16;
+ */
+ pixelImageWidth?: number;
+
+ /**
+ * @generated from field: optional uint32 pixel_image_height = 17;
+ */
+ pixelImageHeight?: number;
+};
+
+/**
+ * Describes the message SSL_GeometryCameraCalibration.
+ * Use `create(SSL_GeometryCameraCalibrationSchema)` to create a new message.
+ */
+export const SSL_GeometryCameraCalibrationSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vision_geometry, 4);
+
+/**
+ * Two-Phase model for straight-kicked balls.
+ * There are two phases with different accelerations during the ball kicks:
+ * 1. Sliding
+ * 2. Rolling
+ * The full model is described in the TDP of ER-Force from 2016, which can be found here:
+ * https://ssl.robocup.org/wp-content/uploads/2019/01/2016_ETDP_ER-Force.pdf
+ *
+ * @generated from message SSL_BallModelStraightTwoPhase
+ */
+export type SSL_BallModelStraightTwoPhase = Message<"SSL_BallModelStraightTwoPhase"> & {
+ /**
+ * Ball sliding acceleration [m/s^2] (should be negative)
+ *
+ * @generated from field: required double acc_slide = 1;
+ */
+ accSlide: number;
+
+ /**
+ * Ball rolling acceleration [m/s^2] (should be negative)
+ *
+ * @generated from field: required double acc_roll = 2;
+ */
+ accRoll: number;
+
+ /**
+ * Fraction of the initial velocity where the ball starts to roll
+ *
+ * @generated from field: required double k_switch = 3;
+ */
+ kSwitch: number;
+};
+
+/**
+ * Two-Phase model for straight-kicked balls.
+ * There are two phases with different accelerations during the ball kicks:
+ * 1. Sliding
+ * 2. Rolling
+ * The full model is described in the TDP of ER-Force from 2016, which can be found here:
+ * https://ssl.robocup.org/wp-content/uploads/2019/01/2016_ETDP_ER-Force.pdf
+ *
+ * @generated from message SSL_BallModelStraightTwoPhase
+ */
+export type SSL_BallModelStraightTwoPhaseJson = {
+ /**
+ * Ball sliding acceleration [m/s^2] (should be negative)
+ *
+ * @generated from field: required double acc_slide = 1;
+ */
+ accSlide?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Ball rolling acceleration [m/s^2] (should be negative)
+ *
+ * @generated from field: required double acc_roll = 2;
+ */
+ accRoll?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Fraction of the initial velocity where the ball starts to roll
+ *
+ * @generated from field: required double k_switch = 3;
+ */
+ kSwitch?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message SSL_BallModelStraightTwoPhase.
+ * Use `create(SSL_BallModelStraightTwoPhaseSchema)` to create a new message.
+ */
+export const SSL_BallModelStraightTwoPhaseSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vision_geometry, 5);
+
+/**
+ * Fixed-Loss model for chipped balls.
+ * Uses fixed damping factors for xy and z direction per hop.
+ *
+ * @generated from message SSL_BallModelChipFixedLoss
+ */
+export type SSL_BallModelChipFixedLoss = Message<"SSL_BallModelChipFixedLoss"> & {
+ /**
+ * Chip kick velocity damping factor in XY direction for the first hop
+ *
+ * @generated from field: required double damping_xy_first_hop = 1;
+ */
+ dampingXyFirstHop: number;
+
+ /**
+ * Chip kick velocity damping factor in XY direction for all following hops
+ *
+ * @generated from field: required double damping_xy_other_hops = 2;
+ */
+ dampingXyOtherHops: number;
+
+ /**
+ * Chip kick velocity damping factor in Z direction for all hops
+ *
+ * @generated from field: required double damping_z = 3;
+ */
+ dampingZ: number;
+};
+
+/**
+ * Fixed-Loss model for chipped balls.
+ * Uses fixed damping factors for xy and z direction per hop.
+ *
+ * @generated from message SSL_BallModelChipFixedLoss
+ */
+export type SSL_BallModelChipFixedLossJson = {
+ /**
+ * Chip kick velocity damping factor in XY direction for the first hop
+ *
+ * @generated from field: required double damping_xy_first_hop = 1;
+ */
+ dampingXyFirstHop?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Chip kick velocity damping factor in XY direction for all following hops
+ *
+ * @generated from field: required double damping_xy_other_hops = 2;
+ */
+ dampingXyOtherHops?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Chip kick velocity damping factor in Z direction for all hops
+ *
+ * @generated from field: required double damping_z = 3;
+ */
+ dampingZ?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message SSL_BallModelChipFixedLoss.
+ * Use `create(SSL_BallModelChipFixedLossSchema)` to create a new message.
+ */
+export const SSL_BallModelChipFixedLossSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vision_geometry, 6);
+
+/**
+ * @generated from message SSL_GeometryModels
+ */
+export type SSL_GeometryModels = Message<"SSL_GeometryModels"> & {
+ /**
+ * @generated from field: optional SSL_BallModelStraightTwoPhase straight_two_phase = 1;
+ */
+ straightTwoPhase?: SSL_BallModelStraightTwoPhase;
+
+ /**
+ * @generated from field: optional SSL_BallModelChipFixedLoss chip_fixed_loss = 2;
+ */
+ chipFixedLoss?: SSL_BallModelChipFixedLoss;
+};
+
+/**
+ * @generated from message SSL_GeometryModels
+ */
+export type SSL_GeometryModelsJson = {
+ /**
+ * @generated from field: optional SSL_BallModelStraightTwoPhase straight_two_phase = 1;
+ */
+ straightTwoPhase?: SSL_BallModelStraightTwoPhaseJson;
+
+ /**
+ * @generated from field: optional SSL_BallModelChipFixedLoss chip_fixed_loss = 2;
+ */
+ chipFixedLoss?: SSL_BallModelChipFixedLossJson;
+};
+
+/**
+ * Describes the message SSL_GeometryModels.
+ * Use `create(SSL_GeometryModelsSchema)` to create a new message.
+ */
+export const SSL_GeometryModelsSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vision_geometry, 7);
+
+/**
+ * @generated from message SSL_GeometryData
+ */
+export type SSL_GeometryData = Message<"SSL_GeometryData"> & {
+ /**
+ * @generated from field: required SSL_GeometryFieldSize field = 1;
+ */
+ field?: SSL_GeometryFieldSize;
+
+ /**
+ * @generated from field: repeated SSL_GeometryCameraCalibration calib = 2;
+ */
+ calib: SSL_GeometryCameraCalibration[];
+
+ /**
+ * @generated from field: optional SSL_GeometryModels models = 3;
+ */
+ models?: SSL_GeometryModels;
+};
+
+/**
+ * @generated from message SSL_GeometryData
+ */
+export type SSL_GeometryDataJson = {
+ /**
+ * @generated from field: required SSL_GeometryFieldSize field = 1;
+ */
+ field?: SSL_GeometryFieldSizeJson;
+
+ /**
+ * @generated from field: repeated SSL_GeometryCameraCalibration calib = 2;
+ */
+ calib?: SSL_GeometryCameraCalibrationJson[];
+
+ /**
+ * @generated from field: optional SSL_GeometryModels models = 3;
+ */
+ models?: SSL_GeometryModelsJson;
+};
+
+/**
+ * Describes the message SSL_GeometryData.
+ * Use `create(SSL_GeometryDataSchema)` to create a new message.
+ */
+export const SSL_GeometryDataSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vision_geometry, 8);
+
+/**
+ * @generated from enum SSL_FieldShapeType
+ */
+export enum SSL_FieldShapeType {
+ /**
+ * @generated from enum value: Undefined = 0;
+ */
+ Undefined = 0,
+
+ /**
+ * @generated from enum value: CenterCircle = 1;
+ */
+ CenterCircle = 1,
+
+ /**
+ * @generated from enum value: TopTouchLine = 2;
+ */
+ TopTouchLine = 2,
+
+ /**
+ * @generated from enum value: BottomTouchLine = 3;
+ */
+ BottomTouchLine = 3,
+
+ /**
+ * @generated from enum value: LeftGoalLine = 4;
+ */
+ LeftGoalLine = 4,
+
+ /**
+ * @generated from enum value: RightGoalLine = 5;
+ */
+ RightGoalLine = 5,
+
+ /**
+ * @generated from enum value: HalfwayLine = 6;
+ */
+ HalfwayLine = 6,
+
+ /**
+ * @generated from enum value: CenterLine = 7;
+ */
+ CenterLine = 7,
+
+ /**
+ * @generated from enum value: LeftPenaltyStretch = 8;
+ */
+ LeftPenaltyStretch = 8,
+
+ /**
+ * @generated from enum value: RightPenaltyStretch = 9;
+ */
+ RightPenaltyStretch = 9,
+
+ /**
+ * @generated from enum value: LeftFieldLeftPenaltyStretch = 10;
+ */
+ LeftFieldLeftPenaltyStretch = 10,
+
+ /**
+ * @generated from enum value: LeftFieldRightPenaltyStretch = 11;
+ */
+ LeftFieldRightPenaltyStretch = 11,
+
+ /**
+ * @generated from enum value: RightFieldLeftPenaltyStretch = 12;
+ */
+ RightFieldLeftPenaltyStretch = 12,
+
+ /**
+ * @generated from enum value: RightFieldRightPenaltyStretch = 13;
+ */
+ RightFieldRightPenaltyStretch = 13,
+}
+
+/**
+ * @generated from enum SSL_FieldShapeType
+ */
+export type SSL_FieldShapeTypeJson = "Undefined" | "CenterCircle" | "TopTouchLine" | "BottomTouchLine" | "LeftGoalLine" | "RightGoalLine" | "HalfwayLine" | "CenterLine" | "LeftPenaltyStretch" | "RightPenaltyStretch" | "LeftFieldLeftPenaltyStretch" | "LeftFieldRightPenaltyStretch" | "RightFieldLeftPenaltyStretch" | "RightFieldRightPenaltyStretch";
+
+/**
+ * Describes the enum SSL_FieldShapeType.
+ */
+export const SSL_FieldShapeTypeSchema: GenEnum = /*@__PURE__*/
+ enumDesc(file_vision_ssl_vision_geometry, 0);
+
diff --git a/gui/frontend/src/proto/vision/ssl_vision_wrapper_pb.ts b/gui/frontend/src/proto/vision/ssl_vision_wrapper_pb.ts
new file mode 100644
index 0000000..441bf5f
--- /dev/null
+++ b/gui/frontend/src/proto/vision/ssl_vision_wrapper_pb.ts
@@ -0,0 +1,123 @@
+// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
+// @generated from file vision/ssl_vision_wrapper.proto (syntax proto2)
+/* eslint-disable */
+
+import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
+import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
+import type { SSL_DetectionFrame, SSL_DetectionFrameJson } from "./ssl_vision_detection_pb";
+import { file_vision_ssl_vision_detection } from "./ssl_vision_detection_pb";
+import type { SSL_GeometryData, SSL_GeometryDataJson } from "./ssl_vision_geometry_pb";
+import { file_vision_ssl_vision_geometry } from "./ssl_vision_geometry_pb";
+import type { SSL_VPConfig, SSL_VPConfigJson } from "./ssl_vp_config_pb";
+import { file_vision_ssl_vp_config } from "./ssl_vp_config_pb";
+import type { Message } from "@bufbuild/protobuf";
+
+/**
+ * Describes the file vision/ssl_vision_wrapper.proto.
+ */
+export const file_vision_ssl_vision_wrapper: GenFile = /*@__PURE__*/
+ fileDesc("Ch92aXNpb24vc3NsX3Zpc2lvbl93cmFwcGVyLnByb3RvIpwBChFTU0xfV3JhcHBlclBhY2tldBImCglkZXRlY3Rpb24YASABKAsyEy5TU0xfRGV0ZWN0aW9uRnJhbWUSIwoIZ2VvbWV0cnkYAiABKAsyES5TU0xfR2VvbWV0cnlEYXRhEhsKBnNvdXJjZRgDIAEoDjILLlNTTF9Tb3VyY2USHQoGY29uZmlnGAQgASgLMg0uU1NMX1ZQQ29uZmlnKqgBCgpTU0xfU291cmNlEhYKElNTTF9TT1VSQ0VfVU5LTk9XThAAEhQKEFNTTF9TT1VSQ0VfT1RIRVIQARIZChVTU0xfU09VUkNFX1NTTF9WSVNJT04QAhIfChtTU0xfU09VUkNFX1ZJU0lPTl9QUk9DRVNTT1IQAxIUChBTU0xfU09VUkNFX0dSU0lNEAQSGgoWU1NMX1NPVVJDRV9FUkZPUkNFX1NJTRAFQlpCFVNzbFZpc2lvbldyYXBwZXJQcm90b1ABWj9naXRodWIuY29tL1JvYm9DdXAtU1NML3NzbC12aXNpb24tcHJvY2Vzc29yL2d1aS9pbnRlcm5hbC92aXNpb24", [file_vision_ssl_vision_detection, file_vision_ssl_vision_geometry, file_vision_ssl_vp_config]);
+
+/**
+ * @generated from message SSL_WrapperPacket
+ */
+export type SSL_WrapperPacket = Message<"SSL_WrapperPacket"> & {
+ /**
+ * @generated from field: optional SSL_DetectionFrame detection = 1;
+ */
+ detection?: SSL_DetectionFrame;
+
+ /**
+ * @generated from field: optional SSL_GeometryData geometry = 2;
+ */
+ geometry?: SSL_GeometryData;
+
+ /**
+ * @generated from field: optional SSL_Source source = 3;
+ */
+ source: SSL_Source;
+
+ /**
+ * @generated from field: optional SSL_VPConfig config = 4;
+ */
+ config?: SSL_VPConfig;
+};
+
+/**
+ * @generated from message SSL_WrapperPacket
+ */
+export type SSL_WrapperPacketJson = {
+ /**
+ * @generated from field: optional SSL_DetectionFrame detection = 1;
+ */
+ detection?: SSL_DetectionFrameJson;
+
+ /**
+ * @generated from field: optional SSL_GeometryData geometry = 2;
+ */
+ geometry?: SSL_GeometryDataJson;
+
+ /**
+ * @generated from field: optional SSL_Source source = 3;
+ */
+ source?: SSL_SourceJson;
+
+ /**
+ * @generated from field: optional SSL_VPConfig config = 4;
+ */
+ config?: SSL_VPConfigJson;
+};
+
+/**
+ * Describes the message SSL_WrapperPacket.
+ * Use `create(SSL_WrapperPacketSchema)` to create a new message.
+ */
+export const SSL_WrapperPacketSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vision_wrapper, 0);
+
+/**
+ * @generated from enum SSL_Source
+ */
+export enum SSL_Source {
+ /**
+ * @generated from enum value: SSL_SOURCE_UNKNOWN = 0;
+ */
+ SSL_SOURCE_UNKNOWN = 0,
+
+ /**
+ * @generated from enum value: SSL_SOURCE_OTHER = 1;
+ */
+ SSL_SOURCE_OTHER = 1,
+
+ /**
+ * @generated from enum value: SSL_SOURCE_SSL_VISION = 2;
+ */
+ SSL_SOURCE_SSL_VISION = 2,
+
+ /**
+ * @generated from enum value: SSL_SOURCE_VISION_PROCESSOR = 3;
+ */
+ SSL_SOURCE_VISION_PROCESSOR = 3,
+
+ /**
+ * @generated from enum value: SSL_SOURCE_GRSIM = 4;
+ */
+ SSL_SOURCE_GRSIM = 4,
+
+ /**
+ * @generated from enum value: SSL_SOURCE_ERFORCE_SIM = 5;
+ */
+ SSL_SOURCE_ERFORCE_SIM = 5,
+}
+
+/**
+ * @generated from enum SSL_Source
+ */
+export type SSL_SourceJson = "SSL_SOURCE_UNKNOWN" | "SSL_SOURCE_OTHER" | "SSL_SOURCE_SSL_VISION" | "SSL_SOURCE_VISION_PROCESSOR" | "SSL_SOURCE_GRSIM" | "SSL_SOURCE_ERFORCE_SIM";
+
+/**
+ * Describes the enum SSL_Source.
+ */
+export const SSL_SourceSchema: GenEnum = /*@__PURE__*/
+ enumDesc(file_vision_ssl_vision_wrapper, 0);
+
diff --git a/gui/frontend/src/proto/vision/ssl_vision_wrapper_tracked_pb.ts b/gui/frontend/src/proto/vision/ssl_vision_wrapper_tracked_pb.ts
new file mode 100644
index 0000000..3c06af7
--- /dev/null
+++ b/gui/frontend/src/proto/vision/ssl_vision_wrapper_tracked_pb.ts
@@ -0,0 +1,83 @@
+// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
+// @generated from file vision/ssl_vision_wrapper_tracked.proto (syntax proto2)
+/* eslint-disable */
+
+import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
+import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
+import type { TrackedFrame, TrackedFrameJson } from "./ssl_vision_detection_tracked_pb";
+import { file_vision_ssl_vision_detection_tracked } from "./ssl_vision_detection_tracked_pb";
+import type { Message } from "@bufbuild/protobuf";
+
+/**
+ * Describes the file vision/ssl_vision_wrapper_tracked.proto.
+ */
+export const file_vision_ssl_vision_wrapper_tracked: GenFile = /*@__PURE__*/
+ fileDesc("Cid2aXNpb24vc3NsX3Zpc2lvbl93cmFwcGVyX3RyYWNrZWQucHJvdG8iXwoUVHJhY2tlcldyYXBwZXJQYWNrZXQSDAoEdXVpZBgBIAIoCRITCgtzb3VyY2VfbmFtZRgCIAEoCRIkCg10cmFja2VkX2ZyYW1lGAMgASgLMg0uVHJhY2tlZEZyYW1lQmFCHFNzbFZpc2lvbldyYXBwZXJUcmFja2VkUHJvdG9QAVo/Z2l0aHViLmNvbS9Sb2JvQ3VwLVNTTC9zc2wtdmlzaW9uLXByb2Nlc3Nvci9ndWkvaW50ZXJuYWwvdmlzaW9u", [file_vision_ssl_vision_detection_tracked]);
+
+/**
+ * A wrapper packet containing meta data of the source
+ * Also serves for the possibility to extend the protocol later
+ *
+ * @generated from message TrackerWrapperPacket
+ */
+export type TrackerWrapperPacket = Message<"TrackerWrapperPacket"> & {
+ /**
+ * A random UUID of the source that is kept constant at the source while running
+ * If multiple sources are broadcasting to the same network, this id can be used to identify individual sources
+ *
+ * @generated from field: required string uuid = 1;
+ */
+ uuid: string;
+
+ /**
+ * The name of the source software that is producing this messages.
+ *
+ * @generated from field: optional string source_name = 2;
+ */
+ sourceName: string;
+
+ /**
+ * The tracked frame
+ *
+ * @generated from field: optional TrackedFrame tracked_frame = 3;
+ */
+ trackedFrame?: TrackedFrame;
+};
+
+/**
+ * A wrapper packet containing meta data of the source
+ * Also serves for the possibility to extend the protocol later
+ *
+ * @generated from message TrackerWrapperPacket
+ */
+export type TrackerWrapperPacketJson = {
+ /**
+ * A random UUID of the source that is kept constant at the source while running
+ * If multiple sources are broadcasting to the same network, this id can be used to identify individual sources
+ *
+ * @generated from field: required string uuid = 1;
+ */
+ uuid?: string;
+
+ /**
+ * The name of the source software that is producing this messages.
+ *
+ * @generated from field: optional string source_name = 2;
+ */
+ sourceName?: string;
+
+ /**
+ * The tracked frame
+ *
+ * @generated from field: optional TrackedFrame tracked_frame = 3;
+ */
+ trackedFrame?: TrackedFrameJson;
+};
+
+/**
+ * Describes the message TrackerWrapperPacket.
+ * Use `create(TrackerWrapperPacketSchema)` to create a new message.
+ */
+export const TrackerWrapperPacketSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vision_wrapper_tracked, 0);
+
diff --git a/gui/frontend/src/proto/vision/ssl_vp_config_pb.ts b/gui/frontend/src/proto/vision/ssl_vp_config_pb.ts
new file mode 100644
index 0000000..7762334
--- /dev/null
+++ b/gui/frontend/src/proto/vision/ssl_vp_config_pb.ts
@@ -0,0 +1,951 @@
+// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
+// @generated from file vision/ssl_vp_config.proto (syntax proto2)
+/* eslint-disable */
+
+import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
+import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
+import type { Vector2, Vector2Json } from "../gamecontroller/ssl_gc_geometry_pb";
+import { file_gamecontroller_ssl_gc_geometry } from "../gamecontroller/ssl_gc_geometry_pb";
+import type { Message } from "@bufbuild/protobuf";
+
+/**
+ * Describes the file vision/ssl_vp_config.proto.
+ */
+export const file_vision_ssl_vp_config: GenFile = /*@__PURE__*/
+ fileDesc("Chp2aXNpb24vc3NsX3ZwX2NvbmZpZy5wcm90byKXAgoSU1NMX1ZQQ29uZmlnQ2FtZXJhEikKBmRyaXZlchgBIAEoDjIZLlNTTF9WUENvbmZpZ0NhbWVyYURyaXZlchINCgJpZBgCIAEoDToBMBIOCgRwYXRoGAMgASgJOgASEAoFd2lkdGgYBCABKA06ATASEQoGaGVpZ2h0GAUgASgNOgEwEhMKCGV4cG9zdXJlGAYgASgCOgEwEg8KBGdhaW4YByABKAI6ATASEAoFZ2FtbWEYCCABKAI6ATESMwoHd2JfdHlwZRgJIAEoDjIZLlNTTF9WUENvbmZpZ0NhbWVyYVdCVHlwZToHT1VURE9PUhIRCgZ3Yl9yZWQYCiABKAI6ATESEgoHd2JfYmx1ZRgLIAEoAjoBMSKEAQoUU1NMX1ZQQ29uZmlnR2VvbWV0cnkSGAoNY2FtZXJhX2Ftb3VudBgBIAEoDToBMRIYCg1jYW1lcmFfaGVpZ2h0GAIgASgCOgEwEh4KDGxpbmVfY29ybmVycxgDIAMoCzIILlZlY3RvcjISGAoKcmVmaW5lbWVudBgEIAEoCDoEdHJ1ZSLUAQoWU1NMX1ZQQ29uZmlnVGhyZXNob2xkcxIXCgtjaXJjdWxhcml0eRgBIAEoAjoCMTUSEAoFc2NvcmUYAiABKAI6ATUSKwoObWluX2NvbmZpZGVuY2UYAyABKAI6EzAuMjAwMDAwMDAyOTgwMjMyMjQSIgoVbWluX2NhbV9lZGdlX2Rpc3RhbmNlGAQgASgCOgMxNzASHgoSY2xpcHBpbmdfdG9sZXJhbmNlGAUgASgCOgIxMBIeChJnZW9tZXRyeV90b2xlcmFuY2UYBiABKAI6AjEwIkAKBUNvbG9yEhAKA3JlZBgBIAEoDToDMTI4EhIKBWdyZWVuGAIgASgNOgMxMjgSEQoEYmx1ZRgDIAEoDToDMTI4IjoKB1ZQQ29sb3ISGQoJcmVmZXJlbmNlGAEgASgLMgYuQ29sb3ISFAoEbGl2ZRgCIAEoCzIGLkNvbG9yIoECChFTU0xfVlBDb25maWdDb2xvchIsCg9yZWZlcmVuY2VfZm9yY2UYASABKAI6EzAuMTAwMDAwMDAxNDkwMTE2MTISKAoNaGlzdG9yeV9mb3JjZRgCIAEoAjoRMC42OTk5OTk5ODgwNzkwNzESGAoGb3JhbmdlGAMgASgLMgguVlBDb2xvchIXCgVmaWVsZBgEIAEoCzIILlZQQ29sb3ISGAoGeWVsbG93GAUgASgLMgguVlBDb2xvchIWCgRibHVlGAYgASgLMgguVlBDb2xvchIXCgVncmVlbhgHIAEoCzIILlZQQ29sb3ISFgoEcGluaxgIIAEoCzIILlZQQ29sb3IiZwoTU1NMX1ZQQ29uZmlnTmV0d29yaxIZCgVnY19pcBgBIAEoCToKMjI0LjUuMjMuMRIWCgdnY19wb3J0GAIgASgNOgUxMDAwMxIdCgl2aXNpb25faXAYAyABKAk6CjIyNC41LjIzLjIikAEKElNTTF9WUENvbmZpZ1N0cmVhbRIUCgZhY3RpdmUYASABKAg6BHRydWUSKgoEdHlwZRgCIAEoDjIXLlNTTF9WUENvbmZpZ1N0cmVhbVR5cGU6A1JBVxIcCglzdHJlYW1faXAYAyABKAk6CTEyNy4wLjAuMRIaCgtzdHJlYW1fcG9ydBgEIAEoDToFMTAxMDAirwMKDFNTTF9WUENvbmZpZxIQCghpbnN0YW5jZRgBIAIoCRIUCgljYW1lcmFfaWQYAiABKA06ATASNgoNcm9ib3RfaGVpZ2h0cxgDIAMoCzIfLlNTTF9WUENvbmZpZy5Sb2JvdEhlaWdodHNFbnRyeRIjCgZjYW1lcmEYBCABKAsyEy5TU0xfVlBDb25maWdDYW1lcmESJwoIZ2VvbWV0cnkYBSABKAsyFS5TU0xfVlBDb25maWdHZW9tZXRyeRIrCgp0aHJlc2hvbGRzGAYgASgLMhcuU1NMX1ZQQ29uZmlnVGhyZXNob2xkcxIhCgVjb2xvchgHIAEoCzISLlNTTF9WUENvbmZpZ0NvbG9yEiUKB25ldHdvcmsYCCABKAsyFC5TU0xfVlBDb25maWdOZXR3b3JrEiMKBnN0cmVhbRgJIAEoCzITLlNTTF9WUENvbmZpZ1N0cmVhbRIgChF3YWl0X2Zvcl9nZW9tZXRyeRgKIAEoCDoFZmFsc2UaMwoRUm9ib3RIZWlnaHRzRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgCOgI4ASpDChhTU0xfVlBDb25maWdDYW1lcmFEcml2ZXISDQoJU1BJTk5BS0VSEAASCgoGT1BFTkNWEAESDAoITVZJTVBBQ1QQAio/ChhTU0xfVlBDb25maWdDYW1lcmFXQlR5cGUSCwoHT1VURE9PUhAAEgoKBklORE9PUhABEgoKBk1BTlVBTBACKmkKFlNTTF9WUENvbmZpZ1N0cmVhbVR5cGUSBwoDUkFXEAASFgoSUkVQUk9KX0ZBTFNFX0NPTE9SEAESFwoTUkVQUk9KX0dSQURJRU5UX0RPVBACEhUKEVJFUFJPSl9CTE9CX1NDT1JFEANCVUIQU3NsVnBDb25maWdQcm90b1ABWj9naXRodWIuY29tL1JvYm9DdXAtU1NML3NzbC12aXNpb24tcHJvY2Vzc29yL2d1aS9pbnRlcm5hbC92aXNpb24", [file_gamecontroller_ssl_gc_geometry]);
+
+/**
+ * @generated from message SSL_VPConfigCamera
+ */
+export type SSL_VPConfigCamera = Message<"SSL_VPConfigCamera"> & {
+ /**
+ * Camera driver type. Availability depending on libraries installed.
+ *
+ * @generated from field: optional SSL_VPConfigCameraDriver driver = 1;
+ */
+ driver: SSL_VPConfigCameraDriver;
+
+ /**
+ * Spinnaker, mvIMPACT or OpenCV(v4l2) camera id
+ *
+ * @generated from field: optional uint32 id = 2 [default = 0];
+ */
+ id: number;
+
+ /**
+ * OpenCV camera device, image or video file path (if unset id is used instead)
+ *
+ * @generated from field: optional string path = 3 [default = ""];
+ */
+ path: string;
+
+ /**
+ * Camera resolution as reported by the camera. VisionProcessor might use half (true color) resolution internally with SPINNAKER and MVIMPACT.
+ * 0 = Highest resolution supported by camera
+ *
+ * @generated from field: optional uint32 width = 4 [default = 0];
+ */
+ width: number;
+
+ /**
+ * @generated from field: optional uint32 height = 5 [default = 0];
+ */
+ height: number;
+
+ /**
+ * Camera exposure time in ms to adjust brightness. Higher values lead to more motion blur. Lower values lead to a darker image.
+ * Camera frame rate will drop if set equal to or higher than the frame time (1 / fps_cam).
+ * 0.0 = automatic exposure
+ *
+ * @generated from field: optional float exposure = 6 [default = 0];
+ */
+ exposure: number;
+
+ /**
+ * Camera gain to adjust brightness. Higher values lead to more noise. Lower values lead to a darker image.
+ * Frequently changing bot identities or team colors indicate an image that is too bright (all colors becoming nearly white).
+ * 0.0 = automatic gain
+ *
+ * @generated from field: optional float gain = 7 [default = 0];
+ */
+ gain: number;
+
+ /**
+ * Camera gamma as nonlinear brightness adjustment. Only supported on SPINNAKER and OPENCV.
+ * Low values reduce differences between bright and dark illuminated areas. High values increase the color contrast.
+ * 1.0 = no gamma
+ *
+ * @generated from field: optional float gamma = 8 [default = 1];
+ */
+ gamma: number;
+
+ /**
+ * Camera white balance. OUTDOOR or INDOOR for auto white balance with green or gray carpet respectively.
+ * (distinction between OUTDOOR and INDOOR currently only implemented for SPINNAKER backend)
+ *
+ * @generated from field: optional SSL_VPConfigCameraWBType wb_type = 9 [default = OUTDOOR];
+ */
+ wbType: SSL_VPConfigCameraWBType;
+
+ /**
+ * @generated from field: optional float wb_red = 10 [default = 1];
+ */
+ wbRed: number;
+
+ /**
+ * @generated from field: optional float wb_blue = 11 [default = 1];
+ */
+ wbBlue: number;
+};
+
+/**
+ * @generated from message SSL_VPConfigCamera
+ */
+export type SSL_VPConfigCameraJson = {
+ /**
+ * Camera driver type. Availability depending on libraries installed.
+ *
+ * @generated from field: optional SSL_VPConfigCameraDriver driver = 1;
+ */
+ driver?: SSL_VPConfigCameraDriverJson;
+
+ /**
+ * Spinnaker, mvIMPACT or OpenCV(v4l2) camera id
+ *
+ * @generated from field: optional uint32 id = 2 [default = 0];
+ */
+ id?: number;
+
+ /**
+ * OpenCV camera device, image or video file path (if unset id is used instead)
+ *
+ * @generated from field: optional string path = 3 [default = ""];
+ */
+ path?: string;
+
+ /**
+ * Camera resolution as reported by the camera. VisionProcessor might use half (true color) resolution internally with SPINNAKER and MVIMPACT.
+ * 0 = Highest resolution supported by camera
+ *
+ * @generated from field: optional uint32 width = 4 [default = 0];
+ */
+ width?: number;
+
+ /**
+ * @generated from field: optional uint32 height = 5 [default = 0];
+ */
+ height?: number;
+
+ /**
+ * Camera exposure time in ms to adjust brightness. Higher values lead to more motion blur. Lower values lead to a darker image.
+ * Camera frame rate will drop if set equal to or higher than the frame time (1 / fps_cam).
+ * 0.0 = automatic exposure
+ *
+ * @generated from field: optional float exposure = 6 [default = 0];
+ */
+ exposure?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Camera gain to adjust brightness. Higher values lead to more noise. Lower values lead to a darker image.
+ * Frequently changing bot identities or team colors indicate an image that is too bright (all colors becoming nearly white).
+ * 0.0 = automatic gain
+ *
+ * @generated from field: optional float gain = 7 [default = 0];
+ */
+ gain?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Camera gamma as nonlinear brightness adjustment. Only supported on SPINNAKER and OPENCV.
+ * Low values reduce differences between bright and dark illuminated areas. High values increase the color contrast.
+ * 1.0 = no gamma
+ *
+ * @generated from field: optional float gamma = 8 [default = 1];
+ */
+ gamma?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Camera white balance. OUTDOOR or INDOOR for auto white balance with green or gray carpet respectively.
+ * (distinction between OUTDOOR and INDOOR currently only implemented for SPINNAKER backend)
+ *
+ * @generated from field: optional SSL_VPConfigCameraWBType wb_type = 9 [default = OUTDOOR];
+ */
+ wbType?: SSL_VPConfigCameraWBTypeJson;
+
+ /**
+ * @generated from field: optional float wb_red = 10 [default = 1];
+ */
+ wbRed?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * @generated from field: optional float wb_blue = 11 [default = 1];
+ */
+ wbBlue?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message SSL_VPConfigCamera.
+ * Use `create(SSL_VPConfigCameraSchema)` to create a new message.
+ */
+export const SSL_VPConfigCameraSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vp_config, 0);
+
+/**
+ * @generated from message SSL_VPConfigGeometry
+ */
+export type SSL_VPConfigGeometry = Message<"SSL_VPConfigGeometry"> & {
+ /**
+ * Total camera amount over the field
+ *
+ * @generated from field: optional uint32 camera_amount = 1 [default = 1];
+ */
+ cameraAmount: number;
+
+ /**
+ * Camera height above field in mm
+ * 0.0 = automated camera height calibration, this does not work if the camera looks perpendicular to the field.
+ *
+ * @generated from field: optional float camera_height = 2 [default = 0];
+ */
+ cameraHeight: number;
+
+ /**
+ * Field line crossings at the edges of the camera extent in pixels from the top left image corner.
+ * The first coordinate must be the edge with the smallest x and y field coordinate.
+ *
+ * @generated from field: repeated Vector2 line_corners = 3;
+ */
+ lineCorners: Vector2[];
+
+ /**
+ * Enable field line pixel refinement.
+ * Disable in cluttered environments when the geometry calibration has failed multiple times in a row.
+ *
+ * @generated from field: optional bool refinement = 4 [default = true];
+ */
+ refinement: boolean;
+};
+
+/**
+ * @generated from message SSL_VPConfigGeometry
+ */
+export type SSL_VPConfigGeometryJson = {
+ /**
+ * Total camera amount over the field
+ *
+ * @generated from field: optional uint32 camera_amount = 1 [default = 1];
+ */
+ cameraAmount?: number;
+
+ /**
+ * Camera height above field in mm
+ * 0.0 = automated camera height calibration, this does not work if the camera looks perpendicular to the field.
+ *
+ * @generated from field: optional float camera_height = 2 [default = 0];
+ */
+ cameraHeight?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Field line crossings at the edges of the camera extent in pixels from the top left image corner.
+ * The first coordinate must be the edge with the smallest x and y field coordinate.
+ *
+ * @generated from field: repeated Vector2 line_corners = 3;
+ */
+ lineCorners?: Vector2Json[];
+
+ /**
+ * Enable field line pixel refinement.
+ * Disable in cluttered environments when the geometry calibration has failed multiple times in a row.
+ *
+ * @generated from field: optional bool refinement = 4 [default = true];
+ */
+ refinement?: boolean;
+};
+
+/**
+ * Describes the message SSL_VPConfigGeometry.
+ * Use `create(SSL_VPConfigGeometrySchema)` to create a new message.
+ */
+export const SSL_VPConfigGeometrySchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vp_config, 1);
+
+/**
+ * @generated from message SSL_VPConfigThresholds
+ */
+export type SSL_VPConfigThresholds = Message<"SSL_VPConfigThresholds"> & {
+ /**
+ * Minimum mean cosine similarity (not normalized) of the blob border gradient (0 - 195075.0)
+ * High value lead to undetected blobs. Low values lead to an increase in false positive blob detections.
+ *
+ * @generated from field: optional float circularity = 1 [default = 15];
+ */
+ circularity: number;
+
+ /**
+ * Minimum circularity/(3*stddev) ball blob score
+ *
+ * @generated from field: optional float score = 2 [default = 5];
+ */
+ score: number;
+
+ /**
+ * Minimum confidence (0.0 - 1.0)
+ *
+ * @generated from field: optional float min_confidence = 3 [default = 0.20000000298023224];
+ */
+ minConfidence: number;
+
+ /**
+ * Min ball camera edge distance in mm
+ *
+ * @generated from field: optional float min_cam_edge_distance = 4 [default = 170];
+ */
+ minCamEdgeDistance: number;
+
+ /**
+ * Maximum allowed clipping of two objects in mm
+ *
+ * @generated from field: optional float clipping_tolerance = 5 [default = 10];
+ */
+ clippingTolerance: number;
+
+ /**
+ * Added tolerance to geometry related operations in mm.
+ * Affects field border cutoff area and field line blob classification.
+ *
+ * @generated from field: optional float geometry_tolerance = 6 [default = 10];
+ */
+ geometryTolerance: number;
+};
+
+/**
+ * @generated from message SSL_VPConfigThresholds
+ */
+export type SSL_VPConfigThresholdsJson = {
+ /**
+ * Minimum mean cosine similarity (not normalized) of the blob border gradient (0 - 195075.0)
+ * High value lead to undetected blobs. Low values lead to an increase in false positive blob detections.
+ *
+ * @generated from field: optional float circularity = 1 [default = 15];
+ */
+ circularity?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Minimum circularity/(3*stddev) ball blob score
+ *
+ * @generated from field: optional float score = 2 [default = 5];
+ */
+ score?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Minimum confidence (0.0 - 1.0)
+ *
+ * @generated from field: optional float min_confidence = 3 [default = 0.20000000298023224];
+ */
+ minConfidence?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Min ball camera edge distance in mm
+ *
+ * @generated from field: optional float min_cam_edge_distance = 4 [default = 170];
+ */
+ minCamEdgeDistance?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Maximum allowed clipping of two objects in mm
+ *
+ * @generated from field: optional float clipping_tolerance = 5 [default = 10];
+ */
+ clippingTolerance?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Added tolerance to geometry related operations in mm.
+ * Affects field border cutoff area and field line blob classification.
+ *
+ * @generated from field: optional float geometry_tolerance = 6 [default = 10];
+ */
+ geometryTolerance?: number | "NaN" | "Infinity" | "-Infinity";
+};
+
+/**
+ * Describes the message SSL_VPConfigThresholds.
+ * Use `create(SSL_VPConfigThresholdsSchema)` to create a new message.
+ */
+export const SSL_VPConfigThresholdsSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vp_config, 2);
+
+/**
+ * @generated from message Color
+ */
+export type Color = Message<"Color"> & {
+ /**
+ * @generated from field: optional uint32 red = 1 [default = 128];
+ */
+ red: number;
+
+ /**
+ * @generated from field: optional uint32 green = 2 [default = 128];
+ */
+ green: number;
+
+ /**
+ * @generated from field: optional uint32 blue = 3 [default = 128];
+ */
+ blue: number;
+};
+
+/**
+ * @generated from message Color
+ */
+export type ColorJson = {
+ /**
+ * @generated from field: optional uint32 red = 1 [default = 128];
+ */
+ red?: number;
+
+ /**
+ * @generated from field: optional uint32 green = 2 [default = 128];
+ */
+ green?: number;
+
+ /**
+ * @generated from field: optional uint32 blue = 3 [default = 128];
+ */
+ blue?: number;
+};
+
+/**
+ * Describes the message Color.
+ * Use `create(ColorSchema)` to create a new message.
+ */
+export const ColorSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vp_config, 3);
+
+/**
+ * @generated from message VPColor
+ */
+export type VPColor = Message<"VPColor"> & {
+ /**
+ * @generated from field: optional Color reference = 1;
+ */
+ reference?: Color;
+
+ /**
+ * @generated from field: optional Color live = 2;
+ */
+ live?: Color;
+};
+
+/**
+ * @generated from message VPColor
+ */
+export type VPColorJson = {
+ /**
+ * @generated from field: optional Color reference = 1;
+ */
+ reference?: ColorJson;
+
+ /**
+ * @generated from field: optional Color live = 2;
+ */
+ live?: ColorJson;
+};
+
+/**
+ * Describes the message VPColor.
+ * Use `create(VPColorSchema)` to create a new message.
+ */
+export const VPColorSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vp_config, 4);
+
+/**
+ * @generated from message SSL_VPConfigColor
+ */
+export type SSL_VPConfigColor = Message<"SSL_VPConfigColor"> & {
+ /**
+ * Strength of the reference color during color updates (0.0 - 0.5-history_force/2)
+ *
+ * @generated from field: optional float reference_force = 1 [default = 0.10000000149011612];
+ */
+ referenceForce: number;
+
+ /**
+ * Strength of the previous color during color updates (0.0 - 1.0-reference_force)
+ *
+ * @generated from field: optional float history_force = 2 [default = 0.699999988079071];
+ */
+ historyForce: number;
+
+ /**
+ * Colors used for ball determination
+ *
+ * @generated from field: optional VPColor orange = 3;
+ */
+ orange?: VPColor;
+
+ /**
+ * @generated from field: optional VPColor field = 4;
+ */
+ field?: VPColor;
+
+ /**
+ * Colors used for center blob determination
+ *
+ * @generated from field: optional VPColor yellow = 5;
+ */
+ yellow?: VPColor;
+
+ /**
+ * @generated from field: optional VPColor blue = 6;
+ */
+ blue?: VPColor;
+
+ /**
+ * Colors used for side blob determination
+ *
+ * @generated from field: optional VPColor green = 7;
+ */
+ green?: VPColor;
+
+ /**
+ * @generated from field: optional VPColor pink = 8;
+ */
+ pink?: VPColor;
+};
+
+/**
+ * @generated from message SSL_VPConfigColor
+ */
+export type SSL_VPConfigColorJson = {
+ /**
+ * Strength of the reference color during color updates (0.0 - 0.5-history_force/2)
+ *
+ * @generated from field: optional float reference_force = 1 [default = 0.10000000149011612];
+ */
+ referenceForce?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Strength of the previous color during color updates (0.0 - 1.0-reference_force)
+ *
+ * @generated from field: optional float history_force = 2 [default = 0.699999988079071];
+ */
+ historyForce?: number | "NaN" | "Infinity" | "-Infinity";
+
+ /**
+ * Colors used for ball determination
+ *
+ * @generated from field: optional VPColor orange = 3;
+ */
+ orange?: VPColorJson;
+
+ /**
+ * @generated from field: optional VPColor field = 4;
+ */
+ field?: VPColorJson;
+
+ /**
+ * Colors used for center blob determination
+ *
+ * @generated from field: optional VPColor yellow = 5;
+ */
+ yellow?: VPColorJson;
+
+ /**
+ * @generated from field: optional VPColor blue = 6;
+ */
+ blue?: VPColorJson;
+
+ /**
+ * Colors used for side blob determination
+ *
+ * @generated from field: optional VPColor green = 7;
+ */
+ green?: VPColorJson;
+
+ /**
+ * @generated from field: optional VPColor pink = 8;
+ */
+ pink?: VPColorJson;
+};
+
+/**
+ * Describes the message SSL_VPConfigColor.
+ * Use `create(SSL_VPConfigColorSchema)` to create a new message.
+ */
+export const SSL_VPConfigColorSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vp_config, 5);
+
+/**
+ * @generated from message SSL_VPConfigNetwork
+ */
+export type SSL_VPConfigNetwork = Message<"SSL_VPConfigNetwork"> & {
+ /**
+ * Game controller ip address
+ *
+ * @generated from field: optional string gc_ip = 1 [default = "224.5.23.1"];
+ */
+ gcIp: string;
+
+ /**
+ * Game controller UDP port
+ *
+ * @generated from field: optional uint32 gc_port = 2 [default = 10003];
+ */
+ gcPort: number;
+
+ /**
+ * Vision IP address (port impossible to adjust over network)
+ *
+ * @generated from field: optional string vision_ip = 3 [default = "224.5.23.2"];
+ */
+ visionIp: string;
+};
+
+/**
+ * @generated from message SSL_VPConfigNetwork
+ */
+export type SSL_VPConfigNetworkJson = {
+ /**
+ * Game controller ip address
+ *
+ * @generated from field: optional string gc_ip = 1 [default = "224.5.23.1"];
+ */
+ gcIp?: string;
+
+ /**
+ * Game controller UDP port
+ *
+ * @generated from field: optional uint32 gc_port = 2 [default = 10003];
+ */
+ gcPort?: number;
+
+ /**
+ * Vision IP address (port impossible to adjust over network)
+ *
+ * @generated from field: optional string vision_ip = 3 [default = "224.5.23.2"];
+ */
+ visionIp?: string;
+};
+
+/**
+ * Describes the message SSL_VPConfigNetwork.
+ * Use `create(SSL_VPConfigNetworkSchema)` to create a new message.
+ */
+export const SSL_VPConfigNetworkSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vp_config, 6);
+
+/**
+ * @generated from message SSL_VPConfigStream
+ */
+export type SSL_VPConfigStream = Message<"SSL_VPConfigStream"> & {
+ /**
+ * If false no network live stream will be encoded and sent.
+ *
+ * @generated from field: optional bool active = 1 [default = true];
+ */
+ active: boolean;
+
+ /**
+ * Type of image to transmit.
+ *
+ * @generated from field: optional SSL_VPConfigStreamType type = 2 [default = RAW];
+ */
+ type: SSL_VPConfigStreamType;
+
+ /**
+ * Camera RTP stream destination IP
+ *
+ * @generated from field: optional string stream_ip = 3 [default = "127.0.0.1"];
+ */
+ streamIp: string;
+
+ /**
+ * @generated from field: optional uint32 stream_port = 4 [default = 10100];
+ */
+ streamPort: number;
+};
+
+/**
+ * @generated from message SSL_VPConfigStream
+ */
+export type SSL_VPConfigStreamJson = {
+ /**
+ * If false no network live stream will be encoded and sent.
+ *
+ * @generated from field: optional bool active = 1 [default = true];
+ */
+ active?: boolean;
+
+ /**
+ * Type of image to transmit.
+ *
+ * @generated from field: optional SSL_VPConfigStreamType type = 2 [default = RAW];
+ */
+ type?: SSL_VPConfigStreamTypeJson;
+
+ /**
+ * Camera RTP stream destination IP
+ *
+ * @generated from field: optional string stream_ip = 3 [default = "127.0.0.1"];
+ */
+ streamIp?: string;
+
+ /**
+ * @generated from field: optional uint32 stream_port = 4 [default = 10100];
+ */
+ streamPort?: number;
+};
+
+/**
+ * Describes the message SSL_VPConfigStream.
+ * Use `create(SSL_VPConfigStreamSchema)` to create a new message.
+ */
+export const SSL_VPConfigStreamSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vp_config, 7);
+
+/**
+ * @generated from message SSL_VPConfig
+ */
+export type SSL_VPConfig = Message<"SSL_VPConfig"> & {
+ /**
+ * Persistent human-readable network unique identifier (e.g. hostname or hostname:suffix if multiple VP instances on the same host).
+ *
+ * @generated from field: required string instance = 1;
+ */
+ instance: string;
+
+ /**
+ * Corresponding to the camera_id used in SSL_DetectionFrame. Unique per field and implies position on the field:
+ * Single camera field: 0 = global field
+ * Double camera field: 0 = -x side, 1 = +x side
+ * Quadruple cam field: 0 = -x and -y, 1 = -x and +y, 2 = +x and -y, 3 = +x and +y
+ * Configuration for more cams depending on field shape.
+ *
+ * @generated from field: optional uint32 camera_id = 2 [default = 0];
+ */
+ cameraId: number;
+
+ /**
+ * Database of SSL game controller team names and robot heights in mm.
+ * If the team broadcasted by the game controller has no entry, the average robot height is used.
+ *
+ * @generated from field: map robot_heights = 3;
+ */
+ robotHeights: { [key: string]: number };
+
+ /**
+ * @generated from field: optional SSL_VPConfigCamera camera = 4;
+ */
+ camera?: SSL_VPConfigCamera;
+
+ /**
+ * @generated from field: optional SSL_VPConfigGeometry geometry = 5;
+ */
+ geometry?: SSL_VPConfigGeometry;
+
+ /**
+ * @generated from field: optional SSL_VPConfigThresholds thresholds = 6;
+ */
+ thresholds?: SSL_VPConfigThresholds;
+
+ /**
+ * @generated from field: optional SSL_VPConfigColor color = 7;
+ */
+ color?: SSL_VPConfigColor;
+
+ /**
+ * @generated from field: optional SSL_VPConfigNetwork network = 8;
+ */
+ network?: SSL_VPConfigNetwork;
+
+ /**
+ * @generated from field: optional SSL_VPConfigStream stream = 9;
+ */
+ stream?: SSL_VPConfigStream;
+
+ /**
+ * Wait for geometry prior to processing frames
+ *
+ * @generated from field: optional bool wait_for_geometry = 10 [default = false];
+ */
+ waitForGeometry: boolean;
+};
+
+/**
+ * @generated from message SSL_VPConfig
+ */
+export type SSL_VPConfigJson = {
+ /**
+ * Persistent human-readable network unique identifier (e.g. hostname or hostname:suffix if multiple VP instances on the same host).
+ *
+ * @generated from field: required string instance = 1;
+ */
+ instance?: string;
+
+ /**
+ * Corresponding to the camera_id used in SSL_DetectionFrame. Unique per field and implies position on the field:
+ * Single camera field: 0 = global field
+ * Double camera field: 0 = -x side, 1 = +x side
+ * Quadruple cam field: 0 = -x and -y, 1 = -x and +y, 2 = +x and -y, 3 = +x and +y
+ * Configuration for more cams depending on field shape.
+ *
+ * @generated from field: optional uint32 camera_id = 2 [default = 0];
+ */
+ cameraId?: number;
+
+ /**
+ * Database of SSL game controller team names and robot heights in mm.
+ * If the team broadcasted by the game controller has no entry, the average robot height is used.
+ *
+ * @generated from field: map robot_heights = 3;
+ */
+ robotHeights?: { [key: string]: number | "NaN" | "Infinity" | "-Infinity" };
+
+ /**
+ * @generated from field: optional SSL_VPConfigCamera camera = 4;
+ */
+ camera?: SSL_VPConfigCameraJson;
+
+ /**
+ * @generated from field: optional SSL_VPConfigGeometry geometry = 5;
+ */
+ geometry?: SSL_VPConfigGeometryJson;
+
+ /**
+ * @generated from field: optional SSL_VPConfigThresholds thresholds = 6;
+ */
+ thresholds?: SSL_VPConfigThresholdsJson;
+
+ /**
+ * @generated from field: optional SSL_VPConfigColor color = 7;
+ */
+ color?: SSL_VPConfigColorJson;
+
+ /**
+ * @generated from field: optional SSL_VPConfigNetwork network = 8;
+ */
+ network?: SSL_VPConfigNetworkJson;
+
+ /**
+ * @generated from field: optional SSL_VPConfigStream stream = 9;
+ */
+ stream?: SSL_VPConfigStreamJson;
+
+ /**
+ * Wait for geometry prior to processing frames
+ *
+ * @generated from field: optional bool wait_for_geometry = 10 [default = false];
+ */
+ waitForGeometry?: boolean;
+};
+
+/**
+ * Describes the message SSL_VPConfig.
+ * Use `create(SSL_VPConfigSchema)` to create a new message.
+ */
+export const SSL_VPConfigSchema: GenMessage = /*@__PURE__*/
+ messageDesc(file_vision_ssl_vp_config, 8);
+
+/**
+ * @generated from enum SSL_VPConfigCameraDriver
+ */
+export enum SSL_VPConfigCameraDriver {
+ /**
+ * FLIR cameras
+ *
+ * @generated from enum value: SPINNAKER = 0;
+ */
+ SPINNAKER = 0,
+
+ /**
+ * Video and image files, video4linux2 (e.g. webcams) cameras
+ *
+ * @generated from enum value: OPENCV = 1;
+ */
+ OPENCV = 1,
+
+ /**
+ * Bluefox3 cameras
+ *
+ * @generated from enum value: MVIMPACT = 2;
+ */
+ MVIMPACT = 2,
+}
+
+/**
+ * @generated from enum SSL_VPConfigCameraDriver
+ */
+export type SSL_VPConfigCameraDriverJson = "SPINNAKER" | "OPENCV" | "MVIMPACT";
+
+/**
+ * Describes the enum SSL_VPConfigCameraDriver.
+ */
+export const SSL_VPConfigCameraDriverSchema: GenEnum = /*@__PURE__*/
+ enumDesc(file_vision_ssl_vp_config, 0);
+
+/**
+ * @generated from enum SSL_VPConfigCameraWBType
+ */
+export enum SSL_VPConfigCameraWBType {
+ /**
+ * @generated from enum value: OUTDOOR = 0;
+ */
+ OUTDOOR = 0,
+
+ /**
+ * @generated from enum value: INDOOR = 1;
+ */
+ INDOOR = 1,
+
+ /**
+ * @generated from enum value: MANUAL = 2;
+ */
+ MANUAL = 2,
+}
+
+/**
+ * @generated from enum SSL_VPConfigCameraWBType
+ */
+export type SSL_VPConfigCameraWBTypeJson = "OUTDOOR" | "INDOOR" | "MANUAL";
+
+/**
+ * Describes the enum SSL_VPConfigCameraWBType.
+ */
+export const SSL_VPConfigCameraWBTypeSchema: GenEnum = /*@__PURE__*/
+ enumDesc(file_vision_ssl_vp_config, 1);
+
+/**
+ * @generated from enum SSL_VPConfigStreamType
+ */
+export enum SSL_VPConfigStreamType {
+ /**
+ * @generated from enum value: RAW = 0;
+ */
+ RAW = 0,
+
+ /**
+ * @generated from enum value: REPROJ_FALSE_COLOR = 1;
+ */
+ REPROJ_FALSE_COLOR = 1,
+
+ /**
+ * @generated from enum value: REPROJ_GRADIENT_DOT = 2;
+ */
+ REPROJ_GRADIENT_DOT = 2,
+
+ /**
+ * @generated from enum value: REPROJ_BLOB_SCORE = 3;
+ */
+ REPROJ_BLOB_SCORE = 3,
+}
+
+/**
+ * @generated from enum SSL_VPConfigStreamType
+ */
+export type SSL_VPConfigStreamTypeJson = "RAW" | "REPROJ_FALSE_COLOR" | "REPROJ_GRADIENT_DOT" | "REPROJ_BLOB_SCORE";
+
+/**
+ * Describes the enum SSL_VPConfigStreamType.
+ */
+export const SSL_VPConfigStreamTypeSchema: GenEnum = /*@__PURE__*/
+ enumDesc(file_vision_ssl_vp_config, 2);
+
diff --git a/gui/go.mod b/gui/go.mod
index 150696c..7282a95 100644
--- a/gui/go.mod
+++ b/gui/go.mod
@@ -3,9 +3,7 @@ module github.com/RoboCup-SSL/ssl-vision-processor/gui
go 1.26.7
require (
- github.com/RoboCup-SSL/ssl-go-tools v1.12.0 // indirect
- github.com/gorilla/websocket v1.5.3 // indirect
- github.com/lmittmann/tint v1.2.0 // indirect
- google.golang.org/protobuf v1.36.12 // indirect
- gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
+ github.com/lmittmann/tint v1.2.0
+ google.golang.org/protobuf v1.36.12
+ gopkg.in/natefinch/lumberjack.v2 v2.2.1
)
diff --git a/gui/go.sum b/gui/go.sum
index 7915b85..5ad9ae0 100644
--- a/gui/go.sum
+++ b/gui/go.sum
@@ -1,7 +1,5 @@
-github.com/RoboCup-SSL/ssl-go-tools v1.12.0 h1:sXN+VSlMSOtNdLD0MPCaig3vSlj3ZTz/KIi9uJR/dy0=
-github.com/RoboCup-SSL/ssl-go-tools v1.12.0/go.mod h1:Gqrqs0LAcXmCQD3Z+IPXxrqxS9xc9sWJolYQyi3AHbw=
-github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
-github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/lmittmann/tint v1.2.0 h1:AogHRHy8HUJUnNJBHJlYa+fR4YY8mko2cnCp67xn9JY=
github.com/lmittmann/tint v1.2.0/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
diff --git a/gui/internal/gamecontroller/ssl_gc_common.pb.go b/gui/internal/gamecontroller/ssl_gc_common.pb.go
new file mode 100644
index 0000000..c9ee1ad
--- /dev/null
+++ b/gui/internal/gamecontroller/ssl_gc_common.pb.go
@@ -0,0 +1,271 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.36.6
+// protoc (unknown)
+// source: gamecontroller/ssl_gc_common.proto
+
+package gamecontroller
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+ unsafe "unsafe"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// Team is either blue or yellow
+type Team int32
+
+const (
+ // team not set
+ Team_UNKNOWN Team = 0
+ // yellow team
+ Team_YELLOW Team = 1
+ // blue team
+ Team_BLUE Team = 2
+)
+
+// Enum value maps for Team.
+var (
+ Team_name = map[int32]string{
+ 0: "UNKNOWN",
+ 1: "YELLOW",
+ 2: "BLUE",
+ }
+ Team_value = map[string]int32{
+ "UNKNOWN": 0,
+ "YELLOW": 1,
+ "BLUE": 2,
+ }
+)
+
+func (x Team) Enum() *Team {
+ p := new(Team)
+ *p = x
+ return p
+}
+
+func (x Team) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Team) Descriptor() protoreflect.EnumDescriptor {
+ return file_gamecontroller_ssl_gc_common_proto_enumTypes[0].Descriptor()
+}
+
+func (Team) Type() protoreflect.EnumType {
+ return &file_gamecontroller_ssl_gc_common_proto_enumTypes[0]
+}
+
+func (x Team) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *Team) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = Team(num)
+ return nil
+}
+
+// Deprecated: Use Team.Descriptor instead.
+func (Team) EnumDescriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_common_proto_rawDescGZIP(), []int{0}
+}
+
+// Division denotes the current division, which influences some rules
+type Division int32
+
+const (
+ Division_DIV_UNKNOWN Division = 0
+ Division_DIV_A Division = 1
+ Division_DIV_B Division = 2
+)
+
+// Enum value maps for Division.
+var (
+ Division_name = map[int32]string{
+ 0: "DIV_UNKNOWN",
+ 1: "DIV_A",
+ 2: "DIV_B",
+ }
+ Division_value = map[string]int32{
+ "DIV_UNKNOWN": 0,
+ "DIV_A": 1,
+ "DIV_B": 2,
+ }
+)
+
+func (x Division) Enum() *Division {
+ p := new(Division)
+ *p = x
+ return p
+}
+
+func (x Division) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Division) Descriptor() protoreflect.EnumDescriptor {
+ return file_gamecontroller_ssl_gc_common_proto_enumTypes[1].Descriptor()
+}
+
+func (Division) Type() protoreflect.EnumType {
+ return &file_gamecontroller_ssl_gc_common_proto_enumTypes[1]
+}
+
+func (x Division) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *Division) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = Division(num)
+ return nil
+}
+
+// Deprecated: Use Division.Descriptor instead.
+func (Division) EnumDescriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_common_proto_rawDescGZIP(), []int{1}
+}
+
+// RobotId is the combination of a team and a robot id
+type RobotId struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the robot number
+ Id *uint32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"`
+ // the team that the robot belongs to
+ Team *Team `protobuf:"varint,2,opt,name=team,enum=Team" json:"team,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RobotId) Reset() {
+ *x = RobotId{}
+ mi := &file_gamecontroller_ssl_gc_common_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RobotId) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RobotId) ProtoMessage() {}
+
+func (x *RobotId) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_common_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RobotId.ProtoReflect.Descriptor instead.
+func (*RobotId) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_common_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *RobotId) GetId() uint32 {
+ if x != nil && x.Id != nil {
+ return *x.Id
+ }
+ return 0
+}
+
+func (x *RobotId) GetTeam() Team {
+ if x != nil && x.Team != nil {
+ return *x.Team
+ }
+ return Team_UNKNOWN
+}
+
+var File_gamecontroller_ssl_gc_common_proto protoreflect.FileDescriptor
+
+const file_gamecontroller_ssl_gc_common_proto_rawDesc = "" +
+ "\n" +
+ "\"gamecontroller/ssl_gc_common.proto\"4\n" +
+ "\aRobotId\x12\x0e\n" +
+ "\x02id\x18\x01 \x01(\rR\x02id\x12\x19\n" +
+ "\x04team\x18\x02 \x01(\x0e2\x05.TeamR\x04team*)\n" +
+ "\x04Team\x12\v\n" +
+ "\aUNKNOWN\x10\x00\x12\n" +
+ "\n" +
+ "\x06YELLOW\x10\x01\x12\b\n" +
+ "\x04BLUE\x10\x02*1\n" +
+ "\bDivision\x12\x0f\n" +
+ "\vDIV_UNKNOWN\x10\x00\x12\t\n" +
+ "\x05DIV_A\x10\x01\x12\t\n" +
+ "\x05DIV_B\x10\x02B]B\x10SslGcCommonProtoP\x01ZGgithub.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
+
+var (
+ file_gamecontroller_ssl_gc_common_proto_rawDescOnce sync.Once
+ file_gamecontroller_ssl_gc_common_proto_rawDescData []byte
+)
+
+func file_gamecontroller_ssl_gc_common_proto_rawDescGZIP() []byte {
+ file_gamecontroller_ssl_gc_common_proto_rawDescOnce.Do(func() {
+ file_gamecontroller_ssl_gc_common_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_common_proto_rawDesc), len(file_gamecontroller_ssl_gc_common_proto_rawDesc)))
+ })
+ return file_gamecontroller_ssl_gc_common_proto_rawDescData
+}
+
+var file_gamecontroller_ssl_gc_common_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
+var file_gamecontroller_ssl_gc_common_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_gamecontroller_ssl_gc_common_proto_goTypes = []any{
+ (Team)(0), // 0: Team
+ (Division)(0), // 1: Division
+ (*RobotId)(nil), // 2: RobotId
+}
+var file_gamecontroller_ssl_gc_common_proto_depIdxs = []int32{
+ 0, // 0: RobotId.team:type_name -> Team
+ 1, // [1:1] is the sub-list for method output_type
+ 1, // [1:1] is the sub-list for method input_type
+ 1, // [1:1] is the sub-list for extension type_name
+ 1, // [1:1] is the sub-list for extension extendee
+ 0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_gamecontroller_ssl_gc_common_proto_init() }
+func file_gamecontroller_ssl_gc_common_proto_init() {
+ if File_gamecontroller_ssl_gc_common_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_common_proto_rawDesc), len(file_gamecontroller_ssl_gc_common_proto_rawDesc)),
+ NumEnums: 2,
+ NumMessages: 1,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_gamecontroller_ssl_gc_common_proto_goTypes,
+ DependencyIndexes: file_gamecontroller_ssl_gc_common_proto_depIdxs,
+ EnumInfos: file_gamecontroller_ssl_gc_common_proto_enumTypes,
+ MessageInfos: file_gamecontroller_ssl_gc_common_proto_msgTypes,
+ }.Build()
+ File_gamecontroller_ssl_gc_common_proto = out.File
+ file_gamecontroller_ssl_gc_common_proto_goTypes = nil
+ file_gamecontroller_ssl_gc_common_proto_depIdxs = nil
+}
diff --git a/gui/internal/gamecontroller/ssl_gc_game_event.pb.go b/gui/internal/gamecontroller/ssl_gc_game_event.pb.go
new file mode 100644
index 0000000..8c20140
--- /dev/null
+++ b/gui/internal/gamecontroller/ssl_gc_game_event.pb.go
@@ -0,0 +1,4459 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.36.6
+// protoc (unknown)
+// source: gamecontroller/ssl_gc_game_event.proto
+
+package gamecontroller
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+ unsafe "unsafe"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type GameEvent_Type int32
+
+const (
+ GameEvent_UNKNOWN_GAME_EVENT_TYPE GameEvent_Type = 0
+ GameEvent_BALL_LEFT_FIELD_TOUCH_LINE GameEvent_Type = 6 // triggered by autoRef
+ GameEvent_BALL_LEFT_FIELD_GOAL_LINE GameEvent_Type = 7 // triggered by autoRef
+ GameEvent_AIMLESS_KICK GameEvent_Type = 11 // triggered by autoRef
+ GameEvent_ATTACKER_TOO_CLOSE_TO_DEFENSE_AREA GameEvent_Type = 19 // triggered by autoRef
+ GameEvent_DEFENDER_IN_DEFENSE_AREA GameEvent_Type = 31 // triggered by autoRef
+ GameEvent_BOUNDARY_CROSSING GameEvent_Type = 41 // triggered by autoRef
+ GameEvent_KEEPER_HELD_BALL GameEvent_Type = 13 // triggered by GC
+ GameEvent_BOT_DRIBBLED_BALL_TOO_FAR GameEvent_Type = 17 // triggered by autoRef
+ GameEvent_BOT_PUSHED_BOT GameEvent_Type = 24 // triggered by human ref
+ GameEvent_BOT_HELD_BALL_DELIBERATELY GameEvent_Type = 26 // triggered by human ref
+ GameEvent_BOT_TIPPED_OVER GameEvent_Type = 27 // triggered by human ref
+ GameEvent_BOT_DROPPED_PARTS GameEvent_Type = 47 // triggered by human ref
+ GameEvent_ATTACKER_TOUCHED_BALL_IN_DEFENSE_AREA GameEvent_Type = 15 // triggered by autoRef
+ GameEvent_BOT_KICKED_BALL_TOO_FAST GameEvent_Type = 18 // triggered by autoRef
+ GameEvent_BOT_CRASH_UNIQUE GameEvent_Type = 22 // triggered by autoRef
+ GameEvent_BOT_CRASH_DRAWN GameEvent_Type = 21 // triggered by autoRef
+ GameEvent_DEFENDER_TOO_CLOSE_TO_KICK_POINT GameEvent_Type = 29 // triggered by autoRef
+ GameEvent_BOT_TOO_FAST_IN_STOP GameEvent_Type = 28 // triggered by autoRef
+ GameEvent_BOT_INTERFERED_PLACEMENT GameEvent_Type = 20 // triggered by autoRef
+ GameEvent_EXCESSIVE_BOT_SUBSTITUTION GameEvent_Type = 48 // triggered by GC
+ GameEvent_POSSIBLE_GOAL GameEvent_Type = 39 // triggered by autoRef
+ GameEvent_GOAL GameEvent_Type = 8 // triggered by GC
+ GameEvent_INVALID_GOAL GameEvent_Type = 42 // triggered by GC
+ GameEvent_ATTACKER_DOUBLE_TOUCHED_BALL GameEvent_Type = 14 // triggered by autoRef
+ GameEvent_PLACEMENT_SUCCEEDED GameEvent_Type = 5 // triggered by autoRef
+ GameEvent_PENALTY_KICK_FAILED GameEvent_Type = 43 // triggered by GC and autoRef
+ GameEvent_NO_PROGRESS_IN_GAME GameEvent_Type = 2 // triggered by GC
+ GameEvent_PLACEMENT_FAILED GameEvent_Type = 3 // triggered by GC
+ GameEvent_MULTIPLE_CARDS GameEvent_Type = 32 // triggered by GC
+ GameEvent_MULTIPLE_FOULS GameEvent_Type = 34 // triggered by GC
+ GameEvent_BOT_SUBSTITUTION GameEvent_Type = 37 // triggered by GC
+ GameEvent_TOO_MANY_ROBOTS GameEvent_Type = 38 // triggered by GC
+ GameEvent_CHALLENGE_FLAG GameEvent_Type = 44 // triggered by GC
+ GameEvent_CHALLENGE_FLAG_HANDLED GameEvent_Type = 46 // triggered by GC
+ GameEvent_EMERGENCY_STOP GameEvent_Type = 45 // triggered by GC
+ GameEvent_UNSPORTING_BEHAVIOR_MINOR GameEvent_Type = 35 // triggered by human ref
+ GameEvent_UNSPORTING_BEHAVIOR_MAJOR GameEvent_Type = 36 // triggered by human ref
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ GameEvent_PREPARED GameEvent_Type = 1
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ GameEvent_INDIRECT_GOAL GameEvent_Type = 9
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ GameEvent_CHIPPED_GOAL GameEvent_Type = 10
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ GameEvent_KICK_TIMEOUT GameEvent_Type = 12
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ GameEvent_ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA GameEvent_Type = 16
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ GameEvent_ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA_SKIPPED GameEvent_Type = 40
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ GameEvent_BOT_CRASH_UNIQUE_SKIPPED GameEvent_Type = 23
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ GameEvent_BOT_PUSHED_BOT_SKIPPED GameEvent_Type = 25
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ GameEvent_DEFENDER_IN_DEFENSE_AREA_PARTIALLY GameEvent_Type = 30
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ GameEvent_MULTIPLE_PLACEMENT_FAILURES GameEvent_Type = 33
+)
+
+// Enum value maps for GameEvent_Type.
+var (
+ GameEvent_Type_name = map[int32]string{
+ 0: "UNKNOWN_GAME_EVENT_TYPE",
+ 6: "BALL_LEFT_FIELD_TOUCH_LINE",
+ 7: "BALL_LEFT_FIELD_GOAL_LINE",
+ 11: "AIMLESS_KICK",
+ 19: "ATTACKER_TOO_CLOSE_TO_DEFENSE_AREA",
+ 31: "DEFENDER_IN_DEFENSE_AREA",
+ 41: "BOUNDARY_CROSSING",
+ 13: "KEEPER_HELD_BALL",
+ 17: "BOT_DRIBBLED_BALL_TOO_FAR",
+ 24: "BOT_PUSHED_BOT",
+ 26: "BOT_HELD_BALL_DELIBERATELY",
+ 27: "BOT_TIPPED_OVER",
+ 47: "BOT_DROPPED_PARTS",
+ 15: "ATTACKER_TOUCHED_BALL_IN_DEFENSE_AREA",
+ 18: "BOT_KICKED_BALL_TOO_FAST",
+ 22: "BOT_CRASH_UNIQUE",
+ 21: "BOT_CRASH_DRAWN",
+ 29: "DEFENDER_TOO_CLOSE_TO_KICK_POINT",
+ 28: "BOT_TOO_FAST_IN_STOP",
+ 20: "BOT_INTERFERED_PLACEMENT",
+ 48: "EXCESSIVE_BOT_SUBSTITUTION",
+ 39: "POSSIBLE_GOAL",
+ 8: "GOAL",
+ 42: "INVALID_GOAL",
+ 14: "ATTACKER_DOUBLE_TOUCHED_BALL",
+ 5: "PLACEMENT_SUCCEEDED",
+ 43: "PENALTY_KICK_FAILED",
+ 2: "NO_PROGRESS_IN_GAME",
+ 3: "PLACEMENT_FAILED",
+ 32: "MULTIPLE_CARDS",
+ 34: "MULTIPLE_FOULS",
+ 37: "BOT_SUBSTITUTION",
+ 38: "TOO_MANY_ROBOTS",
+ 44: "CHALLENGE_FLAG",
+ 46: "CHALLENGE_FLAG_HANDLED",
+ 45: "EMERGENCY_STOP",
+ 35: "UNSPORTING_BEHAVIOR_MINOR",
+ 36: "UNSPORTING_BEHAVIOR_MAJOR",
+ 1: "PREPARED",
+ 9: "INDIRECT_GOAL",
+ 10: "CHIPPED_GOAL",
+ 12: "KICK_TIMEOUT",
+ 16: "ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA",
+ 40: "ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA_SKIPPED",
+ 23: "BOT_CRASH_UNIQUE_SKIPPED",
+ 25: "BOT_PUSHED_BOT_SKIPPED",
+ 30: "DEFENDER_IN_DEFENSE_AREA_PARTIALLY",
+ 33: "MULTIPLE_PLACEMENT_FAILURES",
+ }
+ GameEvent_Type_value = map[string]int32{
+ "UNKNOWN_GAME_EVENT_TYPE": 0,
+ "BALL_LEFT_FIELD_TOUCH_LINE": 6,
+ "BALL_LEFT_FIELD_GOAL_LINE": 7,
+ "AIMLESS_KICK": 11,
+ "ATTACKER_TOO_CLOSE_TO_DEFENSE_AREA": 19,
+ "DEFENDER_IN_DEFENSE_AREA": 31,
+ "BOUNDARY_CROSSING": 41,
+ "KEEPER_HELD_BALL": 13,
+ "BOT_DRIBBLED_BALL_TOO_FAR": 17,
+ "BOT_PUSHED_BOT": 24,
+ "BOT_HELD_BALL_DELIBERATELY": 26,
+ "BOT_TIPPED_OVER": 27,
+ "BOT_DROPPED_PARTS": 47,
+ "ATTACKER_TOUCHED_BALL_IN_DEFENSE_AREA": 15,
+ "BOT_KICKED_BALL_TOO_FAST": 18,
+ "BOT_CRASH_UNIQUE": 22,
+ "BOT_CRASH_DRAWN": 21,
+ "DEFENDER_TOO_CLOSE_TO_KICK_POINT": 29,
+ "BOT_TOO_FAST_IN_STOP": 28,
+ "BOT_INTERFERED_PLACEMENT": 20,
+ "EXCESSIVE_BOT_SUBSTITUTION": 48,
+ "POSSIBLE_GOAL": 39,
+ "GOAL": 8,
+ "INVALID_GOAL": 42,
+ "ATTACKER_DOUBLE_TOUCHED_BALL": 14,
+ "PLACEMENT_SUCCEEDED": 5,
+ "PENALTY_KICK_FAILED": 43,
+ "NO_PROGRESS_IN_GAME": 2,
+ "PLACEMENT_FAILED": 3,
+ "MULTIPLE_CARDS": 32,
+ "MULTIPLE_FOULS": 34,
+ "BOT_SUBSTITUTION": 37,
+ "TOO_MANY_ROBOTS": 38,
+ "CHALLENGE_FLAG": 44,
+ "CHALLENGE_FLAG_HANDLED": 46,
+ "EMERGENCY_STOP": 45,
+ "UNSPORTING_BEHAVIOR_MINOR": 35,
+ "UNSPORTING_BEHAVIOR_MAJOR": 36,
+ "PREPARED": 1,
+ "INDIRECT_GOAL": 9,
+ "CHIPPED_GOAL": 10,
+ "KICK_TIMEOUT": 12,
+ "ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA": 16,
+ "ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA_SKIPPED": 40,
+ "BOT_CRASH_UNIQUE_SKIPPED": 23,
+ "BOT_PUSHED_BOT_SKIPPED": 25,
+ "DEFENDER_IN_DEFENSE_AREA_PARTIALLY": 30,
+ "MULTIPLE_PLACEMENT_FAILURES": 33,
+ }
+)
+
+func (x GameEvent_Type) Enum() *GameEvent_Type {
+ p := new(GameEvent_Type)
+ *p = x
+ return p
+}
+
+func (x GameEvent_Type) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (GameEvent_Type) Descriptor() protoreflect.EnumDescriptor {
+ return file_gamecontroller_ssl_gc_game_event_proto_enumTypes[0].Descriptor()
+}
+
+func (GameEvent_Type) Type() protoreflect.EnumType {
+ return &file_gamecontroller_ssl_gc_game_event_proto_enumTypes[0]
+}
+
+func (x GameEvent_Type) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *GameEvent_Type) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = GameEvent_Type(num)
+ return nil
+}
+
+// Deprecated: Use GameEvent_Type.Descriptor instead.
+func (GameEvent_Type) EnumDescriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 0}
+}
+
+// GameEvent contains exactly one game event
+// Each game event has optional and required fields. The required fields are mandatory to process the event.
+// Some optional fields are only used for visualization, others are required to determine the ball placement position.
+// If fields are missing that are required for the ball placement position, no ball placement command will be issued.
+// Fields are marked optional to make testing and extending of the protocol easier.
+// An autoRef should ideally set all fields, except if there are good reasons to not do so.
+type GameEvent struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // A globally unique id of the game event.
+ Id *string `protobuf:"bytes,50,opt,name=id" json:"id,omitempty"`
+ // The type of the game event.
+ Type *GameEvent_Type `protobuf:"varint,40,opt,name=type,enum=GameEvent_Type" json:"type,omitempty"`
+ // The origins of this game event.
+ // Empty, if it originates from game controller.
+ // Contains autoRef name(s), if it originates from one or more autoRefs.
+ // Ignored if sent by autoRef to game controller.
+ Origin []string `protobuf:"bytes,41,rep,name=origin" json:"origin,omitempty"`
+ // Unix timestamp in microseconds when the event was created.
+ CreatedTimestamp *uint64 `protobuf:"varint,49,opt,name=created_timestamp,json=createdTimestamp" json:"created_timestamp,omitempty"`
+ // the event that occurred
+ //
+ // Types that are valid to be assigned to Event:
+ //
+ // *GameEvent_BallLeftFieldTouchLine
+ // *GameEvent_BallLeftFieldGoalLine
+ // *GameEvent_AimlessKick_
+ // *GameEvent_AttackerTooCloseToDefenseArea_
+ // *GameEvent_DefenderInDefenseArea_
+ // *GameEvent_BoundaryCrossing_
+ // *GameEvent_KeeperHeldBall_
+ // *GameEvent_BotDribbledBallTooFar_
+ // *GameEvent_BotPushedBot_
+ // *GameEvent_BotHeldBallDeliberately_
+ // *GameEvent_BotTippedOver_
+ // *GameEvent_BotDroppedParts_
+ // *GameEvent_AttackerTouchedBallInDefenseArea_
+ // *GameEvent_BotKickedBallTooFast_
+ // *GameEvent_BotCrashUnique_
+ // *GameEvent_BotCrashDrawn_
+ // *GameEvent_DefenderTooCloseToKickPoint_
+ // *GameEvent_BotTooFastInStop_
+ // *GameEvent_BotInterferedPlacement_
+ // *GameEvent_PossibleGoal
+ // *GameEvent_Goal_
+ // *GameEvent_InvalidGoal
+ // *GameEvent_AttackerDoubleTouchedBall_
+ // *GameEvent_PlacementSucceeded_
+ // *GameEvent_PenaltyKickFailed_
+ // *GameEvent_NoProgressInGame_
+ // *GameEvent_PlacementFailed_
+ // *GameEvent_MultipleCards_
+ // *GameEvent_MultipleFouls_
+ // *GameEvent_BotSubstitution_
+ // *GameEvent_ExcessiveBotSubstitution_
+ // *GameEvent_TooManyRobots_
+ // *GameEvent_ChallengeFlag_
+ // *GameEvent_ChallengeFlagHandled_
+ // *GameEvent_EmergencyStop_
+ // *GameEvent_UnsportingBehaviorMinor_
+ // *GameEvent_UnsportingBehaviorMajor_
+ // *GameEvent_Prepared_
+ // *GameEvent_IndirectGoal_
+ // *GameEvent_ChippedGoal_
+ // *GameEvent_KickTimeout_
+ // *GameEvent_AttackerTouchedOpponentInDefenseArea_
+ // *GameEvent_AttackerTouchedOpponentInDefenseAreaSkipped
+ // *GameEvent_BotCrashUniqueSkipped
+ // *GameEvent_BotPushedBotSkipped
+ // *GameEvent_DefenderInDefenseAreaPartially_
+ // *GameEvent_MultiplePlacementFailures_
+ Event isGameEvent_Event `protobuf_oneof:"event"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent) Reset() {
+ *x = GameEvent{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent) ProtoMessage() {}
+
+func (x *GameEvent) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent.ProtoReflect.Descriptor instead.
+func (*GameEvent) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *GameEvent) GetId() string {
+ if x != nil && x.Id != nil {
+ return *x.Id
+ }
+ return ""
+}
+
+func (x *GameEvent) GetType() GameEvent_Type {
+ if x != nil && x.Type != nil {
+ return *x.Type
+ }
+ return GameEvent_UNKNOWN_GAME_EVENT_TYPE
+}
+
+func (x *GameEvent) GetOrigin() []string {
+ if x != nil {
+ return x.Origin
+ }
+ return nil
+}
+
+func (x *GameEvent) GetCreatedTimestamp() uint64 {
+ if x != nil && x.CreatedTimestamp != nil {
+ return *x.CreatedTimestamp
+ }
+ return 0
+}
+
+func (x *GameEvent) GetEvent() isGameEvent_Event {
+ if x != nil {
+ return x.Event
+ }
+ return nil
+}
+
+func (x *GameEvent) GetBallLeftFieldTouchLine() *GameEvent_BallLeftField {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_BallLeftFieldTouchLine); ok {
+ return x.BallLeftFieldTouchLine
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetBallLeftFieldGoalLine() *GameEvent_BallLeftField {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_BallLeftFieldGoalLine); ok {
+ return x.BallLeftFieldGoalLine
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetAimlessKick() *GameEvent_AimlessKick {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_AimlessKick_); ok {
+ return x.AimlessKick
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetAttackerTooCloseToDefenseArea() *GameEvent_AttackerTooCloseToDefenseArea {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_AttackerTooCloseToDefenseArea_); ok {
+ return x.AttackerTooCloseToDefenseArea
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetDefenderInDefenseArea() *GameEvent_DefenderInDefenseArea {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_DefenderInDefenseArea_); ok {
+ return x.DefenderInDefenseArea
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetBoundaryCrossing() *GameEvent_BoundaryCrossing {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_BoundaryCrossing_); ok {
+ return x.BoundaryCrossing
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetKeeperHeldBall() *GameEvent_KeeperHeldBall {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_KeeperHeldBall_); ok {
+ return x.KeeperHeldBall
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetBotDribbledBallTooFar() *GameEvent_BotDribbledBallTooFar {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_BotDribbledBallTooFar_); ok {
+ return x.BotDribbledBallTooFar
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetBotPushedBot() *GameEvent_BotPushedBot {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_BotPushedBot_); ok {
+ return x.BotPushedBot
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetBotHeldBallDeliberately() *GameEvent_BotHeldBallDeliberately {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_BotHeldBallDeliberately_); ok {
+ return x.BotHeldBallDeliberately
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetBotTippedOver() *GameEvent_BotTippedOver {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_BotTippedOver_); ok {
+ return x.BotTippedOver
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetBotDroppedParts() *GameEvent_BotDroppedParts {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_BotDroppedParts_); ok {
+ return x.BotDroppedParts
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetAttackerTouchedBallInDefenseArea() *GameEvent_AttackerTouchedBallInDefenseArea {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_AttackerTouchedBallInDefenseArea_); ok {
+ return x.AttackerTouchedBallInDefenseArea
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetBotKickedBallTooFast() *GameEvent_BotKickedBallTooFast {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_BotKickedBallTooFast_); ok {
+ return x.BotKickedBallTooFast
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetBotCrashUnique() *GameEvent_BotCrashUnique {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_BotCrashUnique_); ok {
+ return x.BotCrashUnique
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetBotCrashDrawn() *GameEvent_BotCrashDrawn {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_BotCrashDrawn_); ok {
+ return x.BotCrashDrawn
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetDefenderTooCloseToKickPoint() *GameEvent_DefenderTooCloseToKickPoint {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_DefenderTooCloseToKickPoint_); ok {
+ return x.DefenderTooCloseToKickPoint
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetBotTooFastInStop() *GameEvent_BotTooFastInStop {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_BotTooFastInStop_); ok {
+ return x.BotTooFastInStop
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetBotInterferedPlacement() *GameEvent_BotInterferedPlacement {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_BotInterferedPlacement_); ok {
+ return x.BotInterferedPlacement
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetPossibleGoal() *GameEvent_Goal {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_PossibleGoal); ok {
+ return x.PossibleGoal
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetGoal() *GameEvent_Goal {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_Goal_); ok {
+ return x.Goal
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetInvalidGoal() *GameEvent_Goal {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_InvalidGoal); ok {
+ return x.InvalidGoal
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetAttackerDoubleTouchedBall() *GameEvent_AttackerDoubleTouchedBall {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_AttackerDoubleTouchedBall_); ok {
+ return x.AttackerDoubleTouchedBall
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetPlacementSucceeded() *GameEvent_PlacementSucceeded {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_PlacementSucceeded_); ok {
+ return x.PlacementSucceeded
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetPenaltyKickFailed() *GameEvent_PenaltyKickFailed {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_PenaltyKickFailed_); ok {
+ return x.PenaltyKickFailed
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetNoProgressInGame() *GameEvent_NoProgressInGame {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_NoProgressInGame_); ok {
+ return x.NoProgressInGame
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetPlacementFailed() *GameEvent_PlacementFailed {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_PlacementFailed_); ok {
+ return x.PlacementFailed
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetMultipleCards() *GameEvent_MultipleCards {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_MultipleCards_); ok {
+ return x.MultipleCards
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetMultipleFouls() *GameEvent_MultipleFouls {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_MultipleFouls_); ok {
+ return x.MultipleFouls
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetBotSubstitution() *GameEvent_BotSubstitution {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_BotSubstitution_); ok {
+ return x.BotSubstitution
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetExcessiveBotSubstitution() *GameEvent_ExcessiveBotSubstitution {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_ExcessiveBotSubstitution_); ok {
+ return x.ExcessiveBotSubstitution
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetTooManyRobots() *GameEvent_TooManyRobots {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_TooManyRobots_); ok {
+ return x.TooManyRobots
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetChallengeFlag() *GameEvent_ChallengeFlag {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_ChallengeFlag_); ok {
+ return x.ChallengeFlag
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetChallengeFlagHandled() *GameEvent_ChallengeFlagHandled {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_ChallengeFlagHandled_); ok {
+ return x.ChallengeFlagHandled
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetEmergencyStop() *GameEvent_EmergencyStop {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_EmergencyStop_); ok {
+ return x.EmergencyStop
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetUnsportingBehaviorMinor() *GameEvent_UnsportingBehaviorMinor {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_UnsportingBehaviorMinor_); ok {
+ return x.UnsportingBehaviorMinor
+ }
+ }
+ return nil
+}
+
+func (x *GameEvent) GetUnsportingBehaviorMajor() *GameEvent_UnsportingBehaviorMajor {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_UnsportingBehaviorMajor_); ok {
+ return x.UnsportingBehaviorMajor
+ }
+ }
+ return nil
+}
+
+// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+func (x *GameEvent) GetPrepared() *GameEvent_Prepared {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_Prepared_); ok {
+ return x.Prepared
+ }
+ }
+ return nil
+}
+
+// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+func (x *GameEvent) GetIndirectGoal() *GameEvent_IndirectGoal {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_IndirectGoal_); ok {
+ return x.IndirectGoal
+ }
+ }
+ return nil
+}
+
+// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+func (x *GameEvent) GetChippedGoal() *GameEvent_ChippedGoal {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_ChippedGoal_); ok {
+ return x.ChippedGoal
+ }
+ }
+ return nil
+}
+
+// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+func (x *GameEvent) GetKickTimeout() *GameEvent_KickTimeout {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_KickTimeout_); ok {
+ return x.KickTimeout
+ }
+ }
+ return nil
+}
+
+// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+func (x *GameEvent) GetAttackerTouchedOpponentInDefenseArea() *GameEvent_AttackerTouchedOpponentInDefenseArea {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_AttackerTouchedOpponentInDefenseArea_); ok {
+ return x.AttackerTouchedOpponentInDefenseArea
+ }
+ }
+ return nil
+}
+
+// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+func (x *GameEvent) GetAttackerTouchedOpponentInDefenseAreaSkipped() *GameEvent_AttackerTouchedOpponentInDefenseArea {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_AttackerTouchedOpponentInDefenseAreaSkipped); ok {
+ return x.AttackerTouchedOpponentInDefenseAreaSkipped
+ }
+ }
+ return nil
+}
+
+// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+func (x *GameEvent) GetBotCrashUniqueSkipped() *GameEvent_BotCrashUnique {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_BotCrashUniqueSkipped); ok {
+ return x.BotCrashUniqueSkipped
+ }
+ }
+ return nil
+}
+
+// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+func (x *GameEvent) GetBotPushedBotSkipped() *GameEvent_BotPushedBot {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_BotPushedBotSkipped); ok {
+ return x.BotPushedBotSkipped
+ }
+ }
+ return nil
+}
+
+// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+func (x *GameEvent) GetDefenderInDefenseAreaPartially() *GameEvent_DefenderInDefenseAreaPartially {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_DefenderInDefenseAreaPartially_); ok {
+ return x.DefenderInDefenseAreaPartially
+ }
+ }
+ return nil
+}
+
+// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+func (x *GameEvent) GetMultiplePlacementFailures() *GameEvent_MultiplePlacementFailures {
+ if x != nil {
+ if x, ok := x.Event.(*GameEvent_MultiplePlacementFailures_); ok {
+ return x.MultiplePlacementFailures
+ }
+ }
+ return nil
+}
+
+type isGameEvent_Event interface {
+ isGameEvent_Event()
+}
+
+type GameEvent_BallLeftFieldTouchLine struct {
+ BallLeftFieldTouchLine *GameEvent_BallLeftField `protobuf:"bytes,6,opt,name=ball_left_field_touch_line,json=ballLeftFieldTouchLine,oneof"`
+}
+
+type GameEvent_BallLeftFieldGoalLine struct {
+ BallLeftFieldGoalLine *GameEvent_BallLeftField `protobuf:"bytes,7,opt,name=ball_left_field_goal_line,json=ballLeftFieldGoalLine,oneof"`
+}
+
+type GameEvent_AimlessKick_ struct {
+ AimlessKick *GameEvent_AimlessKick `protobuf:"bytes,11,opt,name=aimless_kick,json=aimlessKick,oneof"`
+}
+
+type GameEvent_AttackerTooCloseToDefenseArea_ struct {
+ AttackerTooCloseToDefenseArea *GameEvent_AttackerTooCloseToDefenseArea `protobuf:"bytes,19,opt,name=attacker_too_close_to_defense_area,json=attackerTooCloseToDefenseArea,oneof"`
+}
+
+type GameEvent_DefenderInDefenseArea_ struct {
+ DefenderInDefenseArea *GameEvent_DefenderInDefenseArea `protobuf:"bytes,31,opt,name=defender_in_defense_area,json=defenderInDefenseArea,oneof"`
+}
+
+type GameEvent_BoundaryCrossing_ struct {
+ BoundaryCrossing *GameEvent_BoundaryCrossing `protobuf:"bytes,43,opt,name=boundary_crossing,json=boundaryCrossing,oneof"`
+}
+
+type GameEvent_KeeperHeldBall_ struct {
+ KeeperHeldBall *GameEvent_KeeperHeldBall `protobuf:"bytes,13,opt,name=keeper_held_ball,json=keeperHeldBall,oneof"`
+}
+
+type GameEvent_BotDribbledBallTooFar_ struct {
+ BotDribbledBallTooFar *GameEvent_BotDribbledBallTooFar `protobuf:"bytes,17,opt,name=bot_dribbled_ball_too_far,json=botDribbledBallTooFar,oneof"`
+}
+
+type GameEvent_BotPushedBot_ struct {
+ BotPushedBot *GameEvent_BotPushedBot `protobuf:"bytes,24,opt,name=bot_pushed_bot,json=botPushedBot,oneof"`
+}
+
+type GameEvent_BotHeldBallDeliberately_ struct {
+ BotHeldBallDeliberately *GameEvent_BotHeldBallDeliberately `protobuf:"bytes,26,opt,name=bot_held_ball_deliberately,json=botHeldBallDeliberately,oneof"`
+}
+
+type GameEvent_BotTippedOver_ struct {
+ BotTippedOver *GameEvent_BotTippedOver `protobuf:"bytes,27,opt,name=bot_tipped_over,json=botTippedOver,oneof"`
+}
+
+type GameEvent_BotDroppedParts_ struct {
+ BotDroppedParts *GameEvent_BotDroppedParts `protobuf:"bytes,51,opt,name=bot_dropped_parts,json=botDroppedParts,oneof"`
+}
+
+type GameEvent_AttackerTouchedBallInDefenseArea_ struct {
+ AttackerTouchedBallInDefenseArea *GameEvent_AttackerTouchedBallInDefenseArea `protobuf:"bytes,15,opt,name=attacker_touched_ball_in_defense_area,json=attackerTouchedBallInDefenseArea,oneof"`
+}
+
+type GameEvent_BotKickedBallTooFast_ struct {
+ BotKickedBallTooFast *GameEvent_BotKickedBallTooFast `protobuf:"bytes,18,opt,name=bot_kicked_ball_too_fast,json=botKickedBallTooFast,oneof"`
+}
+
+type GameEvent_BotCrashUnique_ struct {
+ BotCrashUnique *GameEvent_BotCrashUnique `protobuf:"bytes,22,opt,name=bot_crash_unique,json=botCrashUnique,oneof"`
+}
+
+type GameEvent_BotCrashDrawn_ struct {
+ BotCrashDrawn *GameEvent_BotCrashDrawn `protobuf:"bytes,21,opt,name=bot_crash_drawn,json=botCrashDrawn,oneof"`
+}
+
+type GameEvent_DefenderTooCloseToKickPoint_ struct {
+ DefenderTooCloseToKickPoint *GameEvent_DefenderTooCloseToKickPoint `protobuf:"bytes,29,opt,name=defender_too_close_to_kick_point,json=defenderTooCloseToKickPoint,oneof"`
+}
+
+type GameEvent_BotTooFastInStop_ struct {
+ BotTooFastInStop *GameEvent_BotTooFastInStop `protobuf:"bytes,28,opt,name=bot_too_fast_in_stop,json=botTooFastInStop,oneof"`
+}
+
+type GameEvent_BotInterferedPlacement_ struct {
+ BotInterferedPlacement *GameEvent_BotInterferedPlacement `protobuf:"bytes,20,opt,name=bot_interfered_placement,json=botInterferedPlacement,oneof"`
+}
+
+type GameEvent_PossibleGoal struct {
+ PossibleGoal *GameEvent_Goal `protobuf:"bytes,39,opt,name=possible_goal,json=possibleGoal,oneof"`
+}
+
+type GameEvent_Goal_ struct {
+ Goal *GameEvent_Goal `protobuf:"bytes,8,opt,name=goal,oneof"`
+}
+
+type GameEvent_InvalidGoal struct {
+ InvalidGoal *GameEvent_Goal `protobuf:"bytes,44,opt,name=invalid_goal,json=invalidGoal,oneof"`
+}
+
+type GameEvent_AttackerDoubleTouchedBall_ struct {
+ AttackerDoubleTouchedBall *GameEvent_AttackerDoubleTouchedBall `protobuf:"bytes,14,opt,name=attacker_double_touched_ball,json=attackerDoubleTouchedBall,oneof"`
+}
+
+type GameEvent_PlacementSucceeded_ struct {
+ PlacementSucceeded *GameEvent_PlacementSucceeded `protobuf:"bytes,5,opt,name=placement_succeeded,json=placementSucceeded,oneof"`
+}
+
+type GameEvent_PenaltyKickFailed_ struct {
+ PenaltyKickFailed *GameEvent_PenaltyKickFailed `protobuf:"bytes,45,opt,name=penalty_kick_failed,json=penaltyKickFailed,oneof"`
+}
+
+type GameEvent_NoProgressInGame_ struct {
+ NoProgressInGame *GameEvent_NoProgressInGame `protobuf:"bytes,2,opt,name=no_progress_in_game,json=noProgressInGame,oneof"`
+}
+
+type GameEvent_PlacementFailed_ struct {
+ PlacementFailed *GameEvent_PlacementFailed `protobuf:"bytes,3,opt,name=placement_failed,json=placementFailed,oneof"`
+}
+
+type GameEvent_MultipleCards_ struct {
+ MultipleCards *GameEvent_MultipleCards `protobuf:"bytes,32,opt,name=multiple_cards,json=multipleCards,oneof"`
+}
+
+type GameEvent_MultipleFouls_ struct {
+ MultipleFouls *GameEvent_MultipleFouls `protobuf:"bytes,34,opt,name=multiple_fouls,json=multipleFouls,oneof"`
+}
+
+type GameEvent_BotSubstitution_ struct {
+ BotSubstitution *GameEvent_BotSubstitution `protobuf:"bytes,37,opt,name=bot_substitution,json=botSubstitution,oneof"`
+}
+
+type GameEvent_ExcessiveBotSubstitution_ struct {
+ ExcessiveBotSubstitution *GameEvent_ExcessiveBotSubstitution `protobuf:"bytes,52,opt,name=excessive_bot_substitution,json=excessiveBotSubstitution,oneof"`
+}
+
+type GameEvent_TooManyRobots_ struct {
+ TooManyRobots *GameEvent_TooManyRobots `protobuf:"bytes,38,opt,name=too_many_robots,json=tooManyRobots,oneof"`
+}
+
+type GameEvent_ChallengeFlag_ struct {
+ ChallengeFlag *GameEvent_ChallengeFlag `protobuf:"bytes,46,opt,name=challenge_flag,json=challengeFlag,oneof"`
+}
+
+type GameEvent_ChallengeFlagHandled_ struct {
+ ChallengeFlagHandled *GameEvent_ChallengeFlagHandled `protobuf:"bytes,48,opt,name=challenge_flag_handled,json=challengeFlagHandled,oneof"`
+}
+
+type GameEvent_EmergencyStop_ struct {
+ EmergencyStop *GameEvent_EmergencyStop `protobuf:"bytes,47,opt,name=emergency_stop,json=emergencyStop,oneof"`
+}
+
+type GameEvent_UnsportingBehaviorMinor_ struct {
+ UnsportingBehaviorMinor *GameEvent_UnsportingBehaviorMinor `protobuf:"bytes,35,opt,name=unsporting_behavior_minor,json=unsportingBehaviorMinor,oneof"`
+}
+
+type GameEvent_UnsportingBehaviorMajor_ struct {
+ UnsportingBehaviorMajor *GameEvent_UnsportingBehaviorMajor `protobuf:"bytes,36,opt,name=unsporting_behavior_major,json=unsportingBehaviorMajor,oneof"`
+}
+
+type GameEvent_Prepared_ struct {
+ // replaced by ready_to_continue flag
+ //
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ Prepared *GameEvent_Prepared `protobuf:"bytes,1,opt,name=prepared,oneof"`
+}
+
+type GameEvent_IndirectGoal_ struct {
+ // obsolete
+ //
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ IndirectGoal *GameEvent_IndirectGoal `protobuf:"bytes,9,opt,name=indirect_goal,json=indirectGoal,oneof"`
+}
+
+type GameEvent_ChippedGoal_ struct {
+ // replaced by the meta-information in the possible_goal event
+ //
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ ChippedGoal *GameEvent_ChippedGoal `protobuf:"bytes,10,opt,name=chipped_goal,json=chippedGoal,oneof"`
+}
+
+type GameEvent_KickTimeout_ struct {
+ // obsolete
+ //
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ KickTimeout *GameEvent_KickTimeout `protobuf:"bytes,12,opt,name=kick_timeout,json=kickTimeout,oneof"`
+}
+
+type GameEvent_AttackerTouchedOpponentInDefenseArea_ struct {
+ // rule removed
+ //
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ AttackerTouchedOpponentInDefenseArea *GameEvent_AttackerTouchedOpponentInDefenseArea `protobuf:"bytes,16,opt,name=attacker_touched_opponent_in_defense_area,json=attackerTouchedOpponentInDefenseArea,oneof"`
+}
+
+type GameEvent_AttackerTouchedOpponentInDefenseAreaSkipped struct {
+ // obsolete
+ //
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ AttackerTouchedOpponentInDefenseAreaSkipped *GameEvent_AttackerTouchedOpponentInDefenseArea `protobuf:"bytes,42,opt,name=attacker_touched_opponent_in_defense_area_skipped,json=attackerTouchedOpponentInDefenseAreaSkipped,oneof"`
+}
+
+type GameEvent_BotCrashUniqueSkipped struct {
+ // obsolete
+ //
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ BotCrashUniqueSkipped *GameEvent_BotCrashUnique `protobuf:"bytes,23,opt,name=bot_crash_unique_skipped,json=botCrashUniqueSkipped,oneof"`
+}
+
+type GameEvent_BotPushedBotSkipped struct {
+ // can not be used as long as autoRefs do not judge pushing
+ //
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ BotPushedBotSkipped *GameEvent_BotPushedBot `protobuf:"bytes,25,opt,name=bot_pushed_bot_skipped,json=botPushedBotSkipped,oneof"`
+}
+
+type GameEvent_DefenderInDefenseAreaPartially_ struct {
+ // rule removed
+ //
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ DefenderInDefenseAreaPartially *GameEvent_DefenderInDefenseAreaPartially `protobuf:"bytes,30,opt,name=defender_in_defense_area_partially,json=defenderInDefenseAreaPartially,oneof"`
+}
+
+type GameEvent_MultiplePlacementFailures_ struct {
+ // the referee msg already indicates this
+ //
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
+ MultiplePlacementFailures *GameEvent_MultiplePlacementFailures `protobuf:"bytes,33,opt,name=multiple_placement_failures,json=multiplePlacementFailures,oneof"`
+}
+
+func (*GameEvent_BallLeftFieldTouchLine) isGameEvent_Event() {}
+
+func (*GameEvent_BallLeftFieldGoalLine) isGameEvent_Event() {}
+
+func (*GameEvent_AimlessKick_) isGameEvent_Event() {}
+
+func (*GameEvent_AttackerTooCloseToDefenseArea_) isGameEvent_Event() {}
+
+func (*GameEvent_DefenderInDefenseArea_) isGameEvent_Event() {}
+
+func (*GameEvent_BoundaryCrossing_) isGameEvent_Event() {}
+
+func (*GameEvent_KeeperHeldBall_) isGameEvent_Event() {}
+
+func (*GameEvent_BotDribbledBallTooFar_) isGameEvent_Event() {}
+
+func (*GameEvent_BotPushedBot_) isGameEvent_Event() {}
+
+func (*GameEvent_BotHeldBallDeliberately_) isGameEvent_Event() {}
+
+func (*GameEvent_BotTippedOver_) isGameEvent_Event() {}
+
+func (*GameEvent_BotDroppedParts_) isGameEvent_Event() {}
+
+func (*GameEvent_AttackerTouchedBallInDefenseArea_) isGameEvent_Event() {}
+
+func (*GameEvent_BotKickedBallTooFast_) isGameEvent_Event() {}
+
+func (*GameEvent_BotCrashUnique_) isGameEvent_Event() {}
+
+func (*GameEvent_BotCrashDrawn_) isGameEvent_Event() {}
+
+func (*GameEvent_DefenderTooCloseToKickPoint_) isGameEvent_Event() {}
+
+func (*GameEvent_BotTooFastInStop_) isGameEvent_Event() {}
+
+func (*GameEvent_BotInterferedPlacement_) isGameEvent_Event() {}
+
+func (*GameEvent_PossibleGoal) isGameEvent_Event() {}
+
+func (*GameEvent_Goal_) isGameEvent_Event() {}
+
+func (*GameEvent_InvalidGoal) isGameEvent_Event() {}
+
+func (*GameEvent_AttackerDoubleTouchedBall_) isGameEvent_Event() {}
+
+func (*GameEvent_PlacementSucceeded_) isGameEvent_Event() {}
+
+func (*GameEvent_PenaltyKickFailed_) isGameEvent_Event() {}
+
+func (*GameEvent_NoProgressInGame_) isGameEvent_Event() {}
+
+func (*GameEvent_PlacementFailed_) isGameEvent_Event() {}
+
+func (*GameEvent_MultipleCards_) isGameEvent_Event() {}
+
+func (*GameEvent_MultipleFouls_) isGameEvent_Event() {}
+
+func (*GameEvent_BotSubstitution_) isGameEvent_Event() {}
+
+func (*GameEvent_ExcessiveBotSubstitution_) isGameEvent_Event() {}
+
+func (*GameEvent_TooManyRobots_) isGameEvent_Event() {}
+
+func (*GameEvent_ChallengeFlag_) isGameEvent_Event() {}
+
+func (*GameEvent_ChallengeFlagHandled_) isGameEvent_Event() {}
+
+func (*GameEvent_EmergencyStop_) isGameEvent_Event() {}
+
+func (*GameEvent_UnsportingBehaviorMinor_) isGameEvent_Event() {}
+
+func (*GameEvent_UnsportingBehaviorMajor_) isGameEvent_Event() {}
+
+func (*GameEvent_Prepared_) isGameEvent_Event() {}
+
+func (*GameEvent_IndirectGoal_) isGameEvent_Event() {}
+
+func (*GameEvent_ChippedGoal_) isGameEvent_Event() {}
+
+func (*GameEvent_KickTimeout_) isGameEvent_Event() {}
+
+func (*GameEvent_AttackerTouchedOpponentInDefenseArea_) isGameEvent_Event() {}
+
+func (*GameEvent_AttackerTouchedOpponentInDefenseAreaSkipped) isGameEvent_Event() {}
+
+func (*GameEvent_BotCrashUniqueSkipped) isGameEvent_Event() {}
+
+func (*GameEvent_BotPushedBotSkipped) isGameEvent_Event() {}
+
+func (*GameEvent_DefenderInDefenseAreaPartially_) isGameEvent_Event() {}
+
+func (*GameEvent_MultiplePlacementFailures_) isGameEvent_Event() {}
+
+// the ball left the field normally
+type GameEvent_BallLeftField struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that last touched the ball
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that last touched the ball
+ ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
+ // the location where the ball left the field [m]
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_BallLeftField) Reset() {
+ *x = GameEvent_BallLeftField{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_BallLeftField) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_BallLeftField) ProtoMessage() {}
+
+func (x *GameEvent_BallLeftField) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[1]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_BallLeftField.ProtoReflect.Descriptor instead.
+func (*GameEvent_BallLeftField) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 0}
+}
+
+func (x *GameEvent_BallLeftField) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_BallLeftField) GetByBot() uint32 {
+ if x != nil && x.ByBot != nil {
+ return *x.ByBot
+ }
+ return 0
+}
+
+func (x *GameEvent_BallLeftField) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+// the ball left the field via goal line and a team committed an aimless kick
+type GameEvent_AimlessKick struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that last touched the ball
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that last touched the ball
+ ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
+ // the location where the ball left the field [m]
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ // the location where the ball was last touched [m]
+ KickLocation *Vector2 `protobuf:"bytes,4,opt,name=kick_location,json=kickLocation" json:"kick_location,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_AimlessKick) Reset() {
+ *x = GameEvent_AimlessKick{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_AimlessKick) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_AimlessKick) ProtoMessage() {}
+
+func (x *GameEvent_AimlessKick) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[2]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_AimlessKick.ProtoReflect.Descriptor instead.
+func (*GameEvent_AimlessKick) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 1}
+}
+
+func (x *GameEvent_AimlessKick) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_AimlessKick) GetByBot() uint32 {
+ if x != nil && x.ByBot != nil {
+ return *x.ByBot
+ }
+ return 0
+}
+
+func (x *GameEvent_AimlessKick) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_AimlessKick) GetKickLocation() *Vector2 {
+ if x != nil {
+ return x.KickLocation
+ }
+ return nil
+}
+
+// a team shot a goal
+type GameEvent_Goal struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that scored the goal
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the team that shot the goal (different from by_team for own goals)
+ KickingTeam *Team `protobuf:"varint,6,opt,name=kicking_team,json=kickingTeam,enum=Team" json:"kicking_team,omitempty"`
+ // the bot that shot the goal
+ KickingBot *uint32 `protobuf:"varint,2,opt,name=kicking_bot,json=kickingBot" json:"kicking_bot,omitempty"`
+ // the location where the ball entered the goal [m]
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ // the location where the ball was kicked (for deciding if this was a valid goal) [m]
+ KickLocation *Vector2 `protobuf:"bytes,4,opt,name=kick_location,json=kickLocation" json:"kick_location,omitempty"`
+ // the maximum height the ball reached during the goal kick (for deciding if this was a valid goal) [m]
+ MaxBallHeight *float32 `protobuf:"fixed32,5,opt,name=max_ball_height,json=maxBallHeight" json:"max_ball_height,omitempty"`
+ // number of robots of scoring team when the ball entered the goal (for deciding if this was a valid goal)
+ NumRobotsByTeam *uint32 `protobuf:"varint,7,opt,name=num_robots_by_team,json=numRobotsByTeam" json:"num_robots_by_team,omitempty"`
+ // The UNIX timestamp [μs] when the scoring team last touched the ball
+ LastTouchByTeam *uint64 `protobuf:"varint,8,opt,name=last_touch_by_team,json=lastTouchByTeam" json:"last_touch_by_team,omitempty"`
+ // An additional message with e.g. a reason for invalid goals
+ Message *string `protobuf:"bytes,9,opt,name=message" json:"message,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_Goal) Reset() {
+ *x = GameEvent_Goal{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_Goal) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_Goal) ProtoMessage() {}
+
+func (x *GameEvent_Goal) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[3]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_Goal.ProtoReflect.Descriptor instead.
+func (*GameEvent_Goal) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 2}
+}
+
+func (x *GameEvent_Goal) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_Goal) GetKickingTeam() Team {
+ if x != nil && x.KickingTeam != nil {
+ return *x.KickingTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_Goal) GetKickingBot() uint32 {
+ if x != nil && x.KickingBot != nil {
+ return *x.KickingBot
+ }
+ return 0
+}
+
+func (x *GameEvent_Goal) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_Goal) GetKickLocation() *Vector2 {
+ if x != nil {
+ return x.KickLocation
+ }
+ return nil
+}
+
+func (x *GameEvent_Goal) GetMaxBallHeight() float32 {
+ if x != nil && x.MaxBallHeight != nil {
+ return *x.MaxBallHeight
+ }
+ return 0
+}
+
+func (x *GameEvent_Goal) GetNumRobotsByTeam() uint32 {
+ if x != nil && x.NumRobotsByTeam != nil {
+ return *x.NumRobotsByTeam
+ }
+ return 0
+}
+
+func (x *GameEvent_Goal) GetLastTouchByTeam() uint64 {
+ if x != nil && x.LastTouchByTeam != nil {
+ return *x.LastTouchByTeam
+ }
+ return 0
+}
+
+func (x *GameEvent_Goal) GetMessage() string {
+ if x != nil && x.Message != nil {
+ return *x.Message
+ }
+ return ""
+}
+
+// the ball entered the goal directly during an indirect free kick
+type GameEvent_IndirectGoal struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that tried to shoot the goal
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that kicked the ball - at least the team must be set
+ ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
+ // the location where the ball entered the goal [m]
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ // the location where the ball was kicked [m]
+ KickLocation *Vector2 `protobuf:"bytes,4,opt,name=kick_location,json=kickLocation" json:"kick_location,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_IndirectGoal) Reset() {
+ *x = GameEvent_IndirectGoal{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_IndirectGoal) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_IndirectGoal) ProtoMessage() {}
+
+func (x *GameEvent_IndirectGoal) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[4]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_IndirectGoal.ProtoReflect.Descriptor instead.
+func (*GameEvent_IndirectGoal) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 3}
+}
+
+func (x *GameEvent_IndirectGoal) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_IndirectGoal) GetByBot() uint32 {
+ if x != nil && x.ByBot != nil {
+ return *x.ByBot
+ }
+ return 0
+}
+
+func (x *GameEvent_IndirectGoal) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_IndirectGoal) GetKickLocation() *Vector2 {
+ if x != nil {
+ return x.KickLocation
+ }
+ return nil
+}
+
+// the ball entered the goal, but was initially chipped
+type GameEvent_ChippedGoal struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that tried to shoot the goal
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that kicked the ball
+ ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
+ // the location where the ball entered the goal [m]
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ // the location where the ball was kicked [m]
+ KickLocation *Vector2 `protobuf:"bytes,4,opt,name=kick_location,json=kickLocation" json:"kick_location,omitempty"`
+ // the maximum height [m] of the ball, before it entered the goal and since the last kick [m]
+ MaxBallHeight *float32 `protobuf:"fixed32,5,opt,name=max_ball_height,json=maxBallHeight" json:"max_ball_height,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_ChippedGoal) Reset() {
+ *x = GameEvent_ChippedGoal{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_ChippedGoal) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_ChippedGoal) ProtoMessage() {}
+
+func (x *GameEvent_ChippedGoal) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[5]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_ChippedGoal.ProtoReflect.Descriptor instead.
+func (*GameEvent_ChippedGoal) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 4}
+}
+
+func (x *GameEvent_ChippedGoal) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_ChippedGoal) GetByBot() uint32 {
+ if x != nil && x.ByBot != nil {
+ return *x.ByBot
+ }
+ return 0
+}
+
+func (x *GameEvent_ChippedGoal) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_ChippedGoal) GetKickLocation() *Vector2 {
+ if x != nil {
+ return x.KickLocation
+ }
+ return nil
+}
+
+func (x *GameEvent_ChippedGoal) GetMaxBallHeight() float32 {
+ if x != nil && x.MaxBallHeight != nil {
+ return *x.MaxBallHeight
+ }
+ return 0
+}
+
+// a bot moved too fast while the game was stopped
+type GameEvent_BotTooFastInStop struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that found guilty
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that was too fast
+ ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
+ // the location of the bot [m]
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ // the bot speed [m/s]
+ Speed *float32 `protobuf:"fixed32,4,opt,name=speed" json:"speed,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_BotTooFastInStop) Reset() {
+ *x = GameEvent_BotTooFastInStop{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_BotTooFastInStop) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_BotTooFastInStop) ProtoMessage() {}
+
+func (x *GameEvent_BotTooFastInStop) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[6]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_BotTooFastInStop.ProtoReflect.Descriptor instead.
+func (*GameEvent_BotTooFastInStop) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 5}
+}
+
+func (x *GameEvent_BotTooFastInStop) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_BotTooFastInStop) GetByBot() uint32 {
+ if x != nil && x.ByBot != nil {
+ return *x.ByBot
+ }
+ return 0
+}
+
+func (x *GameEvent_BotTooFastInStop) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_BotTooFastInStop) GetSpeed() float32 {
+ if x != nil && x.Speed != nil {
+ return *x.Speed
+ }
+ return 0
+}
+
+// a bot of the defending team got too close to the kick point during a free kick
+type GameEvent_DefenderTooCloseToKickPoint struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that was found guilty
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that violates the distance to the kick point
+ ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
+ // the location of the bot [m]
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ // the distance [m] from bot to the kick point (including the minimum radius)
+ Distance *float32 `protobuf:"fixed32,4,opt,name=distance" json:"distance,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_DefenderTooCloseToKickPoint) Reset() {
+ *x = GameEvent_DefenderTooCloseToKickPoint{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_DefenderTooCloseToKickPoint) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_DefenderTooCloseToKickPoint) ProtoMessage() {}
+
+func (x *GameEvent_DefenderTooCloseToKickPoint) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[7]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_DefenderTooCloseToKickPoint.ProtoReflect.Descriptor instead.
+func (*GameEvent_DefenderTooCloseToKickPoint) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 6}
+}
+
+func (x *GameEvent_DefenderTooCloseToKickPoint) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_DefenderTooCloseToKickPoint) GetByBot() uint32 {
+ if x != nil && x.ByBot != nil {
+ return *x.ByBot
+ }
+ return 0
+}
+
+func (x *GameEvent_DefenderTooCloseToKickPoint) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_DefenderTooCloseToKickPoint) GetDistance() float32 {
+ if x != nil && x.Distance != nil {
+ return *x.Distance
+ }
+ return 0
+}
+
+// two robots crashed into each other with similar speeds
+type GameEvent_BotCrashDrawn struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the bot of the yellow team
+ BotYellow *uint32 `protobuf:"varint,1,opt,name=bot_yellow,json=botYellow" json:"bot_yellow,omitempty"`
+ // the bot of the blue team
+ BotBlue *uint32 `protobuf:"varint,2,opt,name=bot_blue,json=botBlue" json:"bot_blue,omitempty"`
+ // the location of the crash (center between both bots) [m]
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ // the calculated crash speed [m/s] of the two bots
+ CrashSpeed *float32 `protobuf:"fixed32,4,opt,name=crash_speed,json=crashSpeed" json:"crash_speed,omitempty"`
+ // the difference [m/s] of the velocity of the two bots
+ SpeedDiff *float32 `protobuf:"fixed32,5,opt,name=speed_diff,json=speedDiff" json:"speed_diff,omitempty"`
+ // the angle [rad] in the range [0, π] of the bot velocity vectors
+ // an angle of 0 rad ( 0°) means, the bots barely touched each other
+ // an angle of π rad (180°) means, the bots crashed frontal into each other
+ CrashAngle *float32 `protobuf:"fixed32,6,opt,name=crash_angle,json=crashAngle" json:"crash_angle,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_BotCrashDrawn) Reset() {
+ *x = GameEvent_BotCrashDrawn{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_BotCrashDrawn) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_BotCrashDrawn) ProtoMessage() {}
+
+func (x *GameEvent_BotCrashDrawn) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[8]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_BotCrashDrawn.ProtoReflect.Descriptor instead.
+func (*GameEvent_BotCrashDrawn) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 7}
+}
+
+func (x *GameEvent_BotCrashDrawn) GetBotYellow() uint32 {
+ if x != nil && x.BotYellow != nil {
+ return *x.BotYellow
+ }
+ return 0
+}
+
+func (x *GameEvent_BotCrashDrawn) GetBotBlue() uint32 {
+ if x != nil && x.BotBlue != nil {
+ return *x.BotBlue
+ }
+ return 0
+}
+
+func (x *GameEvent_BotCrashDrawn) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_BotCrashDrawn) GetCrashSpeed() float32 {
+ if x != nil && x.CrashSpeed != nil {
+ return *x.CrashSpeed
+ }
+ return 0
+}
+
+func (x *GameEvent_BotCrashDrawn) GetSpeedDiff() float32 {
+ if x != nil && x.SpeedDiff != nil {
+ return *x.SpeedDiff
+ }
+ return 0
+}
+
+func (x *GameEvent_BotCrashDrawn) GetCrashAngle() float32 {
+ if x != nil && x.CrashAngle != nil {
+ return *x.CrashAngle
+ }
+ return 0
+}
+
+// two robots crashed into each other and one team was found guilty to due significant speed difference
+type GameEvent_BotCrashUnique struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that caused the crash
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that caused the crash
+ Violator *uint32 `protobuf:"varint,2,opt,name=violator" json:"violator,omitempty"`
+ // the bot of the opposite team that was involved in the crash
+ Victim *uint32 `protobuf:"varint,3,opt,name=victim" json:"victim,omitempty"`
+ // the location of the crash (center between both bots) [m]
+ Location *Vector2 `protobuf:"bytes,4,opt,name=location" json:"location,omitempty"`
+ // the calculated crash speed vector [m/s] of the two bots
+ CrashSpeed *float32 `protobuf:"fixed32,5,opt,name=crash_speed,json=crashSpeed" json:"crash_speed,omitempty"`
+ // the difference [m/s] of the velocity of the two bots
+ SpeedDiff *float32 `protobuf:"fixed32,6,opt,name=speed_diff,json=speedDiff" json:"speed_diff,omitempty"`
+ // the angle [rad] in the range [0, π] of the bot velocity vectors
+ // an angle of 0 rad ( 0°) means, the bots barely touched each other
+ // an angle of π rad (180°) means, the bots crashed frontal into each other
+ CrashAngle *float32 `protobuf:"fixed32,7,opt,name=crash_angle,json=crashAngle" json:"crash_angle,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_BotCrashUnique) Reset() {
+ *x = GameEvent_BotCrashUnique{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_BotCrashUnique) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_BotCrashUnique) ProtoMessage() {}
+
+func (x *GameEvent_BotCrashUnique) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[9]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_BotCrashUnique.ProtoReflect.Descriptor instead.
+func (*GameEvent_BotCrashUnique) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 8}
+}
+
+func (x *GameEvent_BotCrashUnique) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_BotCrashUnique) GetViolator() uint32 {
+ if x != nil && x.Violator != nil {
+ return *x.Violator
+ }
+ return 0
+}
+
+func (x *GameEvent_BotCrashUnique) GetVictim() uint32 {
+ if x != nil && x.Victim != nil {
+ return *x.Victim
+ }
+ return 0
+}
+
+func (x *GameEvent_BotCrashUnique) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_BotCrashUnique) GetCrashSpeed() float32 {
+ if x != nil && x.CrashSpeed != nil {
+ return *x.CrashSpeed
+ }
+ return 0
+}
+
+func (x *GameEvent_BotCrashUnique) GetSpeedDiff() float32 {
+ if x != nil && x.SpeedDiff != nil {
+ return *x.SpeedDiff
+ }
+ return 0
+}
+
+func (x *GameEvent_BotCrashUnique) GetCrashAngle() float32 {
+ if x != nil && x.CrashAngle != nil {
+ return *x.CrashAngle
+ }
+ return 0
+}
+
+// a bot pushed another bot over a significant distance
+type GameEvent_BotPushedBot struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that pushed the other team
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that pushed the other bot
+ Violator *uint32 `protobuf:"varint,2,opt,name=violator" json:"violator,omitempty"`
+ // the bot of the opposite team that was pushed
+ Victim *uint32 `protobuf:"varint,3,opt,name=victim" json:"victim,omitempty"`
+ // the location of the push (center between both bots) [m]
+ Location *Vector2 `protobuf:"bytes,4,opt,name=location" json:"location,omitempty"`
+ // the pushed distance [m]
+ PushedDistance *float32 `protobuf:"fixed32,5,opt,name=pushed_distance,json=pushedDistance" json:"pushed_distance,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_BotPushedBot) Reset() {
+ *x = GameEvent_BotPushedBot{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[10]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_BotPushedBot) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_BotPushedBot) ProtoMessage() {}
+
+func (x *GameEvent_BotPushedBot) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[10]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_BotPushedBot.ProtoReflect.Descriptor instead.
+func (*GameEvent_BotPushedBot) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 9}
+}
+
+func (x *GameEvent_BotPushedBot) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_BotPushedBot) GetViolator() uint32 {
+ if x != nil && x.Violator != nil {
+ return *x.Violator
+ }
+ return 0
+}
+
+func (x *GameEvent_BotPushedBot) GetVictim() uint32 {
+ if x != nil && x.Victim != nil {
+ return *x.Victim
+ }
+ return 0
+}
+
+func (x *GameEvent_BotPushedBot) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_BotPushedBot) GetPushedDistance() float32 {
+ if x != nil && x.PushedDistance != nil {
+ return *x.PushedDistance
+ }
+ return 0
+}
+
+// a bot tipped over
+type GameEvent_BotTippedOver struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that found guilty
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that tipped over
+ ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
+ // the location of the bot [m]
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ // the location of the ball at the moment when this foul occurred [m]
+ BallLocation *Vector2 `protobuf:"bytes,4,opt,name=ball_location,json=ballLocation" json:"ball_location,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_BotTippedOver) Reset() {
+ *x = GameEvent_BotTippedOver{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[11]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_BotTippedOver) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_BotTippedOver) ProtoMessage() {}
+
+func (x *GameEvent_BotTippedOver) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[11]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_BotTippedOver.ProtoReflect.Descriptor instead.
+func (*GameEvent_BotTippedOver) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 10}
+}
+
+func (x *GameEvent_BotTippedOver) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_BotTippedOver) GetByBot() uint32 {
+ if x != nil && x.ByBot != nil {
+ return *x.ByBot
+ }
+ return 0
+}
+
+func (x *GameEvent_BotTippedOver) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_BotTippedOver) GetBallLocation() *Vector2 {
+ if x != nil {
+ return x.BallLocation
+ }
+ return nil
+}
+
+// a bot dropped parts
+type GameEvent_BotDroppedParts struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that found guilty
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that dropped the parts
+ ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
+ // the location where the parts were dropped [m]
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ // the location of the ball at the moment when this foul occurred [m]
+ BallLocation *Vector2 `protobuf:"bytes,4,opt,name=ball_location,json=ballLocation" json:"ball_location,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_BotDroppedParts) Reset() {
+ *x = GameEvent_BotDroppedParts{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[12]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_BotDroppedParts) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_BotDroppedParts) ProtoMessage() {}
+
+func (x *GameEvent_BotDroppedParts) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[12]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_BotDroppedParts.ProtoReflect.Descriptor instead.
+func (*GameEvent_BotDroppedParts) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 11}
+}
+
+func (x *GameEvent_BotDroppedParts) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_BotDroppedParts) GetByBot() uint32 {
+ if x != nil && x.ByBot != nil {
+ return *x.ByBot
+ }
+ return 0
+}
+
+func (x *GameEvent_BotDroppedParts) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_BotDroppedParts) GetBallLocation() *Vector2 {
+ if x != nil {
+ return x.BallLocation
+ }
+ return nil
+}
+
+// a defender other than the keeper was fully located inside its own defense and touched the ball
+type GameEvent_DefenderInDefenseArea struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that found guilty
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that is inside the penalty area
+ ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
+ // the location of the bot [m]
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ // the distance [m] from bot case to the nearest point outside the defense area
+ Distance *float32 `protobuf:"fixed32,4,opt,name=distance" json:"distance,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_DefenderInDefenseArea) Reset() {
+ *x = GameEvent_DefenderInDefenseArea{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[13]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_DefenderInDefenseArea) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_DefenderInDefenseArea) ProtoMessage() {}
+
+func (x *GameEvent_DefenderInDefenseArea) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[13]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_DefenderInDefenseArea.ProtoReflect.Descriptor instead.
+func (*GameEvent_DefenderInDefenseArea) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 12}
+}
+
+func (x *GameEvent_DefenderInDefenseArea) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_DefenderInDefenseArea) GetByBot() uint32 {
+ if x != nil && x.ByBot != nil {
+ return *x.ByBot
+ }
+ return 0
+}
+
+func (x *GameEvent_DefenderInDefenseArea) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_DefenderInDefenseArea) GetDistance() float32 {
+ if x != nil && x.Distance != nil {
+ return *x.Distance
+ }
+ return 0
+}
+
+// a defender other than the keeper was partially located inside its own defense area and touched the ball
+type GameEvent_DefenderInDefenseAreaPartially struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that found guilty
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that is partially inside the penalty area
+ ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
+ // the location of the bot
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ // the distance [m] that the bot is inside the penalty area
+ Distance *float32 `protobuf:"fixed32,4,opt,name=distance" json:"distance,omitempty"`
+ // the location of the ball at the moment when this foul occurred [m]
+ BallLocation *Vector2 `protobuf:"bytes,5,opt,name=ball_location,json=ballLocation" json:"ball_location,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_DefenderInDefenseAreaPartially) Reset() {
+ *x = GameEvent_DefenderInDefenseAreaPartially{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[14]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_DefenderInDefenseAreaPartially) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_DefenderInDefenseAreaPartially) ProtoMessage() {}
+
+func (x *GameEvent_DefenderInDefenseAreaPartially) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[14]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_DefenderInDefenseAreaPartially.ProtoReflect.Descriptor instead.
+func (*GameEvent_DefenderInDefenseAreaPartially) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 13}
+}
+
+func (x *GameEvent_DefenderInDefenseAreaPartially) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_DefenderInDefenseAreaPartially) GetByBot() uint32 {
+ if x != nil && x.ByBot != nil {
+ return *x.ByBot
+ }
+ return 0
+}
+
+func (x *GameEvent_DefenderInDefenseAreaPartially) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_DefenderInDefenseAreaPartially) GetDistance() float32 {
+ if x != nil && x.Distance != nil {
+ return *x.Distance
+ }
+ return 0
+}
+
+func (x *GameEvent_DefenderInDefenseAreaPartially) GetBallLocation() *Vector2 {
+ if x != nil {
+ return x.BallLocation
+ }
+ return nil
+}
+
+// an attacker touched the ball inside the opponent defense area
+type GameEvent_AttackerTouchedBallInDefenseArea struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that found guilty
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that is inside the penalty area
+ ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
+ // the location of the bot [m]
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ // the distance [m] that the bot is inside the penalty area
+ Distance *float32 `protobuf:"fixed32,4,opt,name=distance" json:"distance,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_AttackerTouchedBallInDefenseArea) Reset() {
+ *x = GameEvent_AttackerTouchedBallInDefenseArea{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[15]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_AttackerTouchedBallInDefenseArea) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_AttackerTouchedBallInDefenseArea) ProtoMessage() {}
+
+func (x *GameEvent_AttackerTouchedBallInDefenseArea) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[15]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_AttackerTouchedBallInDefenseArea.ProtoReflect.Descriptor instead.
+func (*GameEvent_AttackerTouchedBallInDefenseArea) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 14}
+}
+
+func (x *GameEvent_AttackerTouchedBallInDefenseArea) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_AttackerTouchedBallInDefenseArea) GetByBot() uint32 {
+ if x != nil && x.ByBot != nil {
+ return *x.ByBot
+ }
+ return 0
+}
+
+func (x *GameEvent_AttackerTouchedBallInDefenseArea) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_AttackerTouchedBallInDefenseArea) GetDistance() float32 {
+ if x != nil && x.Distance != nil {
+ return *x.Distance
+ }
+ return 0
+}
+
+// a bot kicked the ball too fast
+type GameEvent_BotKickedBallTooFast struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that found guilty
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that kicked too fast
+ ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
+ // the location of the ball at the time of the highest speed [m]
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ // the absolute initial ball speed (kick speed) [m/s]
+ InitialBallSpeed *float32 `protobuf:"fixed32,4,opt,name=initial_ball_speed,json=initialBallSpeed" json:"initial_ball_speed,omitempty"`
+ // was the ball chipped?
+ Chipped *bool `protobuf:"varint,5,opt,name=chipped" json:"chipped,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_BotKickedBallTooFast) Reset() {
+ *x = GameEvent_BotKickedBallTooFast{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[16]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_BotKickedBallTooFast) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_BotKickedBallTooFast) ProtoMessage() {}
+
+func (x *GameEvent_BotKickedBallTooFast) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[16]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_BotKickedBallTooFast.ProtoReflect.Descriptor instead.
+func (*GameEvent_BotKickedBallTooFast) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 15}
+}
+
+func (x *GameEvent_BotKickedBallTooFast) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_BotKickedBallTooFast) GetByBot() uint32 {
+ if x != nil && x.ByBot != nil {
+ return *x.ByBot
+ }
+ return 0
+}
+
+func (x *GameEvent_BotKickedBallTooFast) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_BotKickedBallTooFast) GetInitialBallSpeed() float32 {
+ if x != nil && x.InitialBallSpeed != nil {
+ return *x.InitialBallSpeed
+ }
+ return 0
+}
+
+func (x *GameEvent_BotKickedBallTooFast) GetChipped() bool {
+ if x != nil && x.Chipped != nil {
+ return *x.Chipped
+ }
+ return false
+}
+
+// a bot dribbled to ball too far
+type GameEvent_BotDribbledBallTooFar struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that found guilty
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that dribbled too far
+ ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
+ // the location where the dribbling started [m]
+ Start *Vector2 `protobuf:"bytes,3,opt,name=start" json:"start,omitempty"`
+ // the location where the maximum dribbling distance was reached [m]
+ End *Vector2 `protobuf:"bytes,4,opt,name=end" json:"end,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_BotDribbledBallTooFar) Reset() {
+ *x = GameEvent_BotDribbledBallTooFar{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[17]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_BotDribbledBallTooFar) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_BotDribbledBallTooFar) ProtoMessage() {}
+
+func (x *GameEvent_BotDribbledBallTooFar) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[17]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_BotDribbledBallTooFar.ProtoReflect.Descriptor instead.
+func (*GameEvent_BotDribbledBallTooFar) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 16}
+}
+
+func (x *GameEvent_BotDribbledBallTooFar) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_BotDribbledBallTooFar) GetByBot() uint32 {
+ if x != nil && x.ByBot != nil {
+ return *x.ByBot
+ }
+ return 0
+}
+
+func (x *GameEvent_BotDribbledBallTooFar) GetStart() *Vector2 {
+ if x != nil {
+ return x.Start
+ }
+ return nil
+}
+
+func (x *GameEvent_BotDribbledBallTooFar) GetEnd() *Vector2 {
+ if x != nil {
+ return x.End
+ }
+ return nil
+}
+
+// an attacker touched the opponent robot inside defense area
+type GameEvent_AttackerTouchedOpponentInDefenseArea struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that found guilty
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that touched the opponent robot
+ ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
+ // the bot of the opposite team that was touched
+ Victim *uint32 `protobuf:"varint,4,opt,name=victim" json:"victim,omitempty"`
+ // the location of the contact point between both bots [m]
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_AttackerTouchedOpponentInDefenseArea) Reset() {
+ *x = GameEvent_AttackerTouchedOpponentInDefenseArea{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[18]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_AttackerTouchedOpponentInDefenseArea) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_AttackerTouchedOpponentInDefenseArea) ProtoMessage() {}
+
+func (x *GameEvent_AttackerTouchedOpponentInDefenseArea) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[18]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_AttackerTouchedOpponentInDefenseArea.ProtoReflect.Descriptor instead.
+func (*GameEvent_AttackerTouchedOpponentInDefenseArea) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 17}
+}
+
+func (x *GameEvent_AttackerTouchedOpponentInDefenseArea) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_AttackerTouchedOpponentInDefenseArea) GetByBot() uint32 {
+ if x != nil && x.ByBot != nil {
+ return *x.ByBot
+ }
+ return 0
+}
+
+func (x *GameEvent_AttackerTouchedOpponentInDefenseArea) GetVictim() uint32 {
+ if x != nil && x.Victim != nil {
+ return *x.Victim
+ }
+ return 0
+}
+
+func (x *GameEvent_AttackerTouchedOpponentInDefenseArea) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+// an attacker touched the ball multiple times when it was not allowed to
+type GameEvent_AttackerDoubleTouchedBall struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that found guilty
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that touched the ball twice
+ ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
+ // the location of the ball when it was first touched [m]
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_AttackerDoubleTouchedBall) Reset() {
+ *x = GameEvent_AttackerDoubleTouchedBall{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[19]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_AttackerDoubleTouchedBall) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_AttackerDoubleTouchedBall) ProtoMessage() {}
+
+func (x *GameEvent_AttackerDoubleTouchedBall) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[19]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_AttackerDoubleTouchedBall.ProtoReflect.Descriptor instead.
+func (*GameEvent_AttackerDoubleTouchedBall) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 18}
+}
+
+func (x *GameEvent_AttackerDoubleTouchedBall) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_AttackerDoubleTouchedBall) GetByBot() uint32 {
+ if x != nil && x.ByBot != nil {
+ return *x.ByBot
+ }
+ return 0
+}
+
+func (x *GameEvent_AttackerDoubleTouchedBall) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+// an attacker was located too near to the opponent defense area during stop or free kick
+type GameEvent_AttackerTooCloseToDefenseArea struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that found guilty
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that is too close to the defense area
+ ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
+ // the location of the bot [m]
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ // the distance [m] of the bot to the penalty area
+ Distance *float32 `protobuf:"fixed32,4,opt,name=distance" json:"distance,omitempty"`
+ // the location of the ball at the moment when this foul occurred [m]
+ BallLocation *Vector2 `protobuf:"bytes,5,opt,name=ball_location,json=ballLocation" json:"ball_location,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_AttackerTooCloseToDefenseArea) Reset() {
+ *x = GameEvent_AttackerTooCloseToDefenseArea{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[20]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_AttackerTooCloseToDefenseArea) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_AttackerTooCloseToDefenseArea) ProtoMessage() {}
+
+func (x *GameEvent_AttackerTooCloseToDefenseArea) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[20]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_AttackerTooCloseToDefenseArea.ProtoReflect.Descriptor instead.
+func (*GameEvent_AttackerTooCloseToDefenseArea) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 19}
+}
+
+func (x *GameEvent_AttackerTooCloseToDefenseArea) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_AttackerTooCloseToDefenseArea) GetByBot() uint32 {
+ if x != nil && x.ByBot != nil {
+ return *x.ByBot
+ }
+ return 0
+}
+
+func (x *GameEvent_AttackerTooCloseToDefenseArea) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_AttackerTooCloseToDefenseArea) GetDistance() float32 {
+ if x != nil && x.Distance != nil {
+ return *x.Distance
+ }
+ return 0
+}
+
+func (x *GameEvent_AttackerTooCloseToDefenseArea) GetBallLocation() *Vector2 {
+ if x != nil {
+ return x.BallLocation
+ }
+ return nil
+}
+
+// a bot held the ball for too long
+type GameEvent_BotHeldBallDeliberately struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that found guilty
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that holds the ball
+ ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
+ // the location of the ball [m]
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ // the duration [s] that the bot hold the ball
+ Duration *float32 `protobuf:"fixed32,4,opt,name=duration" json:"duration,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_BotHeldBallDeliberately) Reset() {
+ *x = GameEvent_BotHeldBallDeliberately{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[21]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_BotHeldBallDeliberately) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_BotHeldBallDeliberately) ProtoMessage() {}
+
+func (x *GameEvent_BotHeldBallDeliberately) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[21]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_BotHeldBallDeliberately.ProtoReflect.Descriptor instead.
+func (*GameEvent_BotHeldBallDeliberately) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 20}
+}
+
+func (x *GameEvent_BotHeldBallDeliberately) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_BotHeldBallDeliberately) GetByBot() uint32 {
+ if x != nil && x.ByBot != nil {
+ return *x.ByBot
+ }
+ return 0
+}
+
+func (x *GameEvent_BotHeldBallDeliberately) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_BotHeldBallDeliberately) GetDuration() float32 {
+ if x != nil && x.Duration != nil {
+ return *x.Duration
+ }
+ return 0
+}
+
+// a bot interfered the ball placement of the other team
+type GameEvent_BotInterferedPlacement struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that found guilty
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the bot that interfered the placement
+ ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
+ // the location of the bot [m]
+ Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_BotInterferedPlacement) Reset() {
+ *x = GameEvent_BotInterferedPlacement{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[22]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_BotInterferedPlacement) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_BotInterferedPlacement) ProtoMessage() {}
+
+func (x *GameEvent_BotInterferedPlacement) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[22]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_BotInterferedPlacement.ProtoReflect.Descriptor instead.
+func (*GameEvent_BotInterferedPlacement) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 21}
+}
+
+func (x *GameEvent_BotInterferedPlacement) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_BotInterferedPlacement) GetByBot() uint32 {
+ if x != nil && x.ByBot != nil {
+ return *x.ByBot
+ }
+ return 0
+}
+
+func (x *GameEvent_BotInterferedPlacement) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+// a team collected multiple yellow cards
+type GameEvent_MultipleCards struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that received multiple yellow cards
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_MultipleCards) Reset() {
+ *x = GameEvent_MultipleCards{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[23]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_MultipleCards) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_MultipleCards) ProtoMessage() {}
+
+func (x *GameEvent_MultipleCards) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[23]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_MultipleCards.ProtoReflect.Descriptor instead.
+func (*GameEvent_MultipleCards) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 22}
+}
+
+func (x *GameEvent_MultipleCards) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+// a team collected multiple fouls, which results in a yellow card
+type GameEvent_MultipleFouls struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that collected multiple fouls
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the list of game events that caused the multiple fouls
+ CausedGameEvents []*GameEvent `protobuf:"bytes,2,rep,name=caused_game_events,json=causedGameEvents" json:"caused_game_events,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_MultipleFouls) Reset() {
+ *x = GameEvent_MultipleFouls{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[24]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_MultipleFouls) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_MultipleFouls) ProtoMessage() {}
+
+func (x *GameEvent_MultipleFouls) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[24]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_MultipleFouls.ProtoReflect.Descriptor instead.
+func (*GameEvent_MultipleFouls) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 23}
+}
+
+func (x *GameEvent_MultipleFouls) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_MultipleFouls) GetCausedGameEvents() []*GameEvent {
+ if x != nil {
+ return x.CausedGameEvents
+ }
+ return nil
+}
+
+// a team failed to place the ball multiple times in a row
+type GameEvent_MultiplePlacementFailures struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that failed multiple times
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_MultiplePlacementFailures) Reset() {
+ *x = GameEvent_MultiplePlacementFailures{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[25]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_MultiplePlacementFailures) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_MultiplePlacementFailures) ProtoMessage() {}
+
+func (x *GameEvent_MultiplePlacementFailures) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[25]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_MultiplePlacementFailures.ProtoReflect.Descriptor instead.
+func (*GameEvent_MultiplePlacementFailures) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 24}
+}
+
+func (x *GameEvent_MultiplePlacementFailures) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+// timeout waiting for the attacking team to perform the free kick
+type GameEvent_KickTimeout struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that that should have kicked
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the location of the ball [m]
+ Location *Vector2 `protobuf:"bytes,2,opt,name=location" json:"location,omitempty"`
+ // the time [s] that was waited
+ Time *float32 `protobuf:"fixed32,3,opt,name=time" json:"time,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_KickTimeout) Reset() {
+ *x = GameEvent_KickTimeout{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[26]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_KickTimeout) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_KickTimeout) ProtoMessage() {}
+
+func (x *GameEvent_KickTimeout) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[26]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_KickTimeout.ProtoReflect.Descriptor instead.
+func (*GameEvent_KickTimeout) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 25}
+}
+
+func (x *GameEvent_KickTimeout) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_KickTimeout) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_KickTimeout) GetTime() float32 {
+ if x != nil && x.Time != nil {
+ return *x.Time
+ }
+ return 0
+}
+
+// game was stuck
+type GameEvent_NoProgressInGame struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the location of the ball
+ Location *Vector2 `protobuf:"bytes,1,opt,name=location" json:"location,omitempty"`
+ // the time [s] that was waited
+ Time *float32 `protobuf:"fixed32,2,opt,name=time" json:"time,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_NoProgressInGame) Reset() {
+ *x = GameEvent_NoProgressInGame{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[27]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_NoProgressInGame) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_NoProgressInGame) ProtoMessage() {}
+
+func (x *GameEvent_NoProgressInGame) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[27]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_NoProgressInGame.ProtoReflect.Descriptor instead.
+func (*GameEvent_NoProgressInGame) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 26}
+}
+
+func (x *GameEvent_NoProgressInGame) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_NoProgressInGame) GetTime() float32 {
+ if x != nil && x.Time != nil {
+ return *x.Time
+ }
+ return 0
+}
+
+// ball placement failed
+type GameEvent_PlacementFailed struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that failed
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the remaining distance [m] from ball to placement position
+ RemainingDistance *float32 `protobuf:"fixed32,2,opt,name=remaining_distance,json=remainingDistance" json:"remaining_distance,omitempty"`
+ // the distance [m] of the nearest own robot to the ball
+ NearestOwnBotDistance *float32 `protobuf:"fixed32,3,opt,name=nearest_own_bot_distance,json=nearestOwnBotDistance" json:"nearest_own_bot_distance,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_PlacementFailed) Reset() {
+ *x = GameEvent_PlacementFailed{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[28]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_PlacementFailed) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_PlacementFailed) ProtoMessage() {}
+
+func (x *GameEvent_PlacementFailed) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[28]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_PlacementFailed.ProtoReflect.Descriptor instead.
+func (*GameEvent_PlacementFailed) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 27}
+}
+
+func (x *GameEvent_PlacementFailed) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_PlacementFailed) GetRemainingDistance() float32 {
+ if x != nil && x.RemainingDistance != nil {
+ return *x.RemainingDistance
+ }
+ return 0
+}
+
+func (x *GameEvent_PlacementFailed) GetNearestOwnBotDistance() float32 {
+ if x != nil && x.NearestOwnBotDistance != nil {
+ return *x.NearestOwnBotDistance
+ }
+ return 0
+}
+
+// a team was found guilty for minor unsporting behavior
+type GameEvent_UnsportingBehaviorMinor struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that found guilty
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // an explanation of the situation and decision
+ Reason *string `protobuf:"bytes,2,req,name=reason" json:"reason,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_UnsportingBehaviorMinor) Reset() {
+ *x = GameEvent_UnsportingBehaviorMinor{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[29]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_UnsportingBehaviorMinor) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_UnsportingBehaviorMinor) ProtoMessage() {}
+
+func (x *GameEvent_UnsportingBehaviorMinor) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[29]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_UnsportingBehaviorMinor.ProtoReflect.Descriptor instead.
+func (*GameEvent_UnsportingBehaviorMinor) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 28}
+}
+
+func (x *GameEvent_UnsportingBehaviorMinor) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_UnsportingBehaviorMinor) GetReason() string {
+ if x != nil && x.Reason != nil {
+ return *x.Reason
+ }
+ return ""
+}
+
+// a team was found guilty for major unsporting behavior
+type GameEvent_UnsportingBehaviorMajor struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that found guilty
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // an explanation of the situation and decision
+ Reason *string `protobuf:"bytes,2,req,name=reason" json:"reason,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_UnsportingBehaviorMajor) Reset() {
+ *x = GameEvent_UnsportingBehaviorMajor{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[30]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_UnsportingBehaviorMajor) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_UnsportingBehaviorMajor) ProtoMessage() {}
+
+func (x *GameEvent_UnsportingBehaviorMajor) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[30]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_UnsportingBehaviorMajor.ProtoReflect.Descriptor instead.
+func (*GameEvent_UnsportingBehaviorMajor) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 29}
+}
+
+func (x *GameEvent_UnsportingBehaviorMajor) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_UnsportingBehaviorMajor) GetReason() string {
+ if x != nil && x.Reason != nil {
+ return *x.Reason
+ }
+ return ""
+}
+
+// a keeper held the ball in its defense area for too long
+type GameEvent_KeeperHeldBall struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that found guilty
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the location of the ball [m]
+ Location *Vector2 `protobuf:"bytes,2,opt,name=location" json:"location,omitempty"`
+ // the duration [s] that the keeper hold the ball
+ Duration *float32 `protobuf:"fixed32,3,opt,name=duration" json:"duration,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_KeeperHeldBall) Reset() {
+ *x = GameEvent_KeeperHeldBall{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[31]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_KeeperHeldBall) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_KeeperHeldBall) ProtoMessage() {}
+
+func (x *GameEvent_KeeperHeldBall) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[31]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_KeeperHeldBall.ProtoReflect.Descriptor instead.
+func (*GameEvent_KeeperHeldBall) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 30}
+}
+
+func (x *GameEvent_KeeperHeldBall) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_KeeperHeldBall) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_KeeperHeldBall) GetDuration() float32 {
+ if x != nil && x.Duration != nil {
+ return *x.Duration
+ }
+ return 0
+}
+
+// a team successfully placed the ball
+type GameEvent_PlacementSucceeded struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that did the placement
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the time [s] taken for placing the ball
+ TimeTaken *float32 `protobuf:"fixed32,2,opt,name=time_taken,json=timeTaken" json:"time_taken,omitempty"`
+ // the distance [m] between placement location and actual ball position
+ Precision *float32 `protobuf:"fixed32,3,opt,name=precision" json:"precision,omitempty"`
+ // the distance [m] between the initial ball location and the placement position
+ Distance *float32 `protobuf:"fixed32,4,opt,name=distance" json:"distance,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_PlacementSucceeded) Reset() {
+ *x = GameEvent_PlacementSucceeded{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[32]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_PlacementSucceeded) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_PlacementSucceeded) ProtoMessage() {}
+
+func (x *GameEvent_PlacementSucceeded) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[32]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_PlacementSucceeded.ProtoReflect.Descriptor instead.
+func (*GameEvent_PlacementSucceeded) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 31}
+}
+
+func (x *GameEvent_PlacementSucceeded) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_PlacementSucceeded) GetTimeTaken() float32 {
+ if x != nil && x.TimeTaken != nil {
+ return *x.TimeTaken
+ }
+ return 0
+}
+
+func (x *GameEvent_PlacementSucceeded) GetPrecision() float32 {
+ if x != nil && x.Precision != nil {
+ return *x.Precision
+ }
+ return 0
+}
+
+func (x *GameEvent_PlacementSucceeded) GetDistance() float32 {
+ if x != nil && x.Distance != nil {
+ return *x.Distance
+ }
+ return 0
+}
+
+// both teams are prepared - all conditions are met to continue (with kickoff or penalty kick)
+type GameEvent_Prepared struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the time [s] taken for preparing
+ TimeTaken *float32 `protobuf:"fixed32,1,opt,name=time_taken,json=timeTaken" json:"time_taken,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_Prepared) Reset() {
+ *x = GameEvent_Prepared{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[33]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_Prepared) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_Prepared) ProtoMessage() {}
+
+func (x *GameEvent_Prepared) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[33]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_Prepared.ProtoReflect.Descriptor instead.
+func (*GameEvent_Prepared) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 32}
+}
+
+func (x *GameEvent_Prepared) GetTimeTaken() float32 {
+ if x != nil && x.TimeTaken != nil {
+ return *x.TimeTaken
+ }
+ return 0
+}
+
+// bots are being substituted by a team
+type GameEvent_BotSubstitution struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that substitutes robots
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_BotSubstitution) Reset() {
+ *x = GameEvent_BotSubstitution{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[34]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_BotSubstitution) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_BotSubstitution) ProtoMessage() {}
+
+func (x *GameEvent_BotSubstitution) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[34]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_BotSubstitution.ProtoReflect.Descriptor instead.
+func (*GameEvent_BotSubstitution) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 33}
+}
+
+func (x *GameEvent_BotSubstitution) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+// A foul for excessive bot substitutions
+type GameEvent_ExcessiveBotSubstitution struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that substitutes robots
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_ExcessiveBotSubstitution) Reset() {
+ *x = GameEvent_ExcessiveBotSubstitution{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[35]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_ExcessiveBotSubstitution) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_ExcessiveBotSubstitution) ProtoMessage() {}
+
+func (x *GameEvent_ExcessiveBotSubstitution) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[35]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_ExcessiveBotSubstitution.ProtoReflect.Descriptor instead.
+func (*GameEvent_ExcessiveBotSubstitution) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 34}
+}
+
+func (x *GameEvent_ExcessiveBotSubstitution) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+// A challenge flag, requested by a team previously, is flagged
+type GameEvent_ChallengeFlag struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that requested the challenge flag
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_ChallengeFlag) Reset() {
+ *x = GameEvent_ChallengeFlag{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[36]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_ChallengeFlag) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_ChallengeFlag) ProtoMessage() {}
+
+func (x *GameEvent_ChallengeFlag) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[36]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_ChallengeFlag.ProtoReflect.Descriptor instead.
+func (*GameEvent_ChallengeFlag) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 35}
+}
+
+func (x *GameEvent_ChallengeFlag) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+// A challenge, flagged recently, has been handled by the referee
+type GameEvent_ChallengeFlagHandled struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that requested the challenge flag
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the challenge was accepted by the referee
+ Accepted *bool `protobuf:"varint,2,req,name=accepted" json:"accepted,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_ChallengeFlagHandled) Reset() {
+ *x = GameEvent_ChallengeFlagHandled{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[37]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_ChallengeFlagHandled) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_ChallengeFlagHandled) ProtoMessage() {}
+
+func (x *GameEvent_ChallengeFlagHandled) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[37]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_ChallengeFlagHandled.ProtoReflect.Descriptor instead.
+func (*GameEvent_ChallengeFlagHandled) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 36}
+}
+
+func (x *GameEvent_ChallengeFlagHandled) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_ChallengeFlagHandled) GetAccepted() bool {
+ if x != nil && x.Accepted != nil {
+ return *x.Accepted
+ }
+ return false
+}
+
+// An emergency stop, requested by team previously, occurred
+type GameEvent_EmergencyStop struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that substitutes robots
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_EmergencyStop) Reset() {
+ *x = GameEvent_EmergencyStop{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[38]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_EmergencyStop) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_EmergencyStop) ProtoMessage() {}
+
+func (x *GameEvent_EmergencyStop) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[38]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_EmergencyStop.ProtoReflect.Descriptor instead.
+func (*GameEvent_EmergencyStop) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 37}
+}
+
+func (x *GameEvent_EmergencyStop) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+// a team has too many robots on the field
+type GameEvent_TooManyRobots struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that has too many robots
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // number of robots allowed at the moment
+ NumRobotsAllowed *int32 `protobuf:"varint,2,opt,name=num_robots_allowed,json=numRobotsAllowed" json:"num_robots_allowed,omitempty"`
+ // number of robots currently on the field
+ NumRobotsOnField *int32 `protobuf:"varint,3,opt,name=num_robots_on_field,json=numRobotsOnField" json:"num_robots_on_field,omitempty"`
+ // the location of the ball at the moment when this foul occurred [m]
+ BallLocation *Vector2 `protobuf:"bytes,4,opt,name=ball_location,json=ballLocation" json:"ball_location,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_TooManyRobots) Reset() {
+ *x = GameEvent_TooManyRobots{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[39]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_TooManyRobots) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_TooManyRobots) ProtoMessage() {}
+
+func (x *GameEvent_TooManyRobots) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[39]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_TooManyRobots.ProtoReflect.Descriptor instead.
+func (*GameEvent_TooManyRobots) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 38}
+}
+
+func (x *GameEvent_TooManyRobots) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_TooManyRobots) GetNumRobotsAllowed() int32 {
+ if x != nil && x.NumRobotsAllowed != nil {
+ return *x.NumRobotsAllowed
+ }
+ return 0
+}
+
+func (x *GameEvent_TooManyRobots) GetNumRobotsOnField() int32 {
+ if x != nil && x.NumRobotsOnField != nil {
+ return *x.NumRobotsOnField
+ }
+ return 0
+}
+
+func (x *GameEvent_TooManyRobots) GetBallLocation() *Vector2 {
+ if x != nil {
+ return x.BallLocation
+ }
+ return nil
+}
+
+// a robot chipped the ball over the field boundary out of the playing surface
+type GameEvent_BoundaryCrossing struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that has too many robots
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the location of the ball [m]
+ Location *Vector2 `protobuf:"bytes,2,opt,name=location" json:"location,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_BoundaryCrossing) Reset() {
+ *x = GameEvent_BoundaryCrossing{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[40]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_BoundaryCrossing) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_BoundaryCrossing) ProtoMessage() {}
+
+func (x *GameEvent_BoundaryCrossing) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[40]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_BoundaryCrossing.ProtoReflect.Descriptor instead.
+func (*GameEvent_BoundaryCrossing) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 39}
+}
+
+func (x *GameEvent_BoundaryCrossing) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_BoundaryCrossing) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+// the penalty kick failed (by time or by keeper)
+type GameEvent_PenaltyKickFailed struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that last touched the ball
+ ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
+ // the location of the ball at the moment of this event [m]
+ Location *Vector2 `protobuf:"bytes,2,opt,name=location" json:"location,omitempty"`
+ // an explanation of the failure
+ Reason *string `protobuf:"bytes,3,opt,name=reason" json:"reason,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEvent_PenaltyKickFailed) Reset() {
+ *x = GameEvent_PenaltyKickFailed{}
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[41]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEvent_PenaltyKickFailed) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEvent_PenaltyKickFailed) ProtoMessage() {}
+
+func (x *GameEvent_PenaltyKickFailed) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[41]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEvent_PenaltyKickFailed.ProtoReflect.Descriptor instead.
+func (*GameEvent_PenaltyKickFailed) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 40}
+}
+
+func (x *GameEvent_PenaltyKickFailed) GetByTeam() Team {
+ if x != nil && x.ByTeam != nil {
+ return *x.ByTeam
+ }
+ return Team_UNKNOWN
+}
+
+func (x *GameEvent_PenaltyKickFailed) GetLocation() *Vector2 {
+ if x != nil {
+ return x.Location
+ }
+ return nil
+}
+
+func (x *GameEvent_PenaltyKickFailed) GetReason() string {
+ if x != nil && x.Reason != nil {
+ return *x.Reason
+ }
+ return ""
+}
+
+var File_gamecontroller_ssl_gc_game_event_proto protoreflect.FileDescriptor
+
+const file_gamecontroller_ssl_gc_game_event_proto_rawDesc = "" +
+ "\n" +
+ "&gamecontroller/ssl_gc_game_event.proto\x1a\"gamecontroller/ssl_gc_common.proto\x1a$gamecontroller/ssl_gc_geometry.proto\"\xceU\n" +
+ "\tGameEvent\x12\x0e\n" +
+ "\x02id\x182 \x01(\tR\x02id\x12#\n" +
+ "\x04type\x18( \x01(\x0e2\x0f.GameEvent.TypeR\x04type\x12\x16\n" +
+ "\x06origin\x18) \x03(\tR\x06origin\x12+\n" +
+ "\x11created_timestamp\x181 \x01(\x04R\x10createdTimestamp\x12V\n" +
+ "\x1aball_left_field_touch_line\x18\x06 \x01(\v2\x18.GameEvent.BallLeftFieldH\x00R\x16ballLeftFieldTouchLine\x12T\n" +
+ "\x19ball_left_field_goal_line\x18\a \x01(\v2\x18.GameEvent.BallLeftFieldH\x00R\x15ballLeftFieldGoalLine\x12;\n" +
+ "\faimless_kick\x18\v \x01(\v2\x16.GameEvent.AimlessKickH\x00R\vaimlessKick\x12u\n" +
+ "\"attacker_too_close_to_defense_area\x18\x13 \x01(\v2(.GameEvent.AttackerTooCloseToDefenseAreaH\x00R\x1dattackerTooCloseToDefenseArea\x12[\n" +
+ "\x18defender_in_defense_area\x18\x1f \x01(\v2 .GameEvent.DefenderInDefenseAreaH\x00R\x15defenderInDefenseArea\x12J\n" +
+ "\x11boundary_crossing\x18+ \x01(\v2\x1b.GameEvent.BoundaryCrossingH\x00R\x10boundaryCrossing\x12E\n" +
+ "\x10keeper_held_ball\x18\r \x01(\v2\x19.GameEvent.KeeperHeldBallH\x00R\x0ekeeperHeldBall\x12\\\n" +
+ "\x19bot_dribbled_ball_too_far\x18\x11 \x01(\v2 .GameEvent.BotDribbledBallTooFarH\x00R\x15botDribbledBallTooFar\x12?\n" +
+ "\x0ebot_pushed_bot\x18\x18 \x01(\v2\x17.GameEvent.BotPushedBotH\x00R\fbotPushedBot\x12a\n" +
+ "\x1abot_held_ball_deliberately\x18\x1a \x01(\v2\".GameEvent.BotHeldBallDeliberatelyH\x00R\x17botHeldBallDeliberately\x12B\n" +
+ "\x0fbot_tipped_over\x18\x1b \x01(\v2\x18.GameEvent.BotTippedOverH\x00R\rbotTippedOver\x12H\n" +
+ "\x11bot_dropped_parts\x183 \x01(\v2\x1a.GameEvent.BotDroppedPartsH\x00R\x0fbotDroppedParts\x12~\n" +
+ "%attacker_touched_ball_in_defense_area\x18\x0f \x01(\v2+.GameEvent.AttackerTouchedBallInDefenseAreaH\x00R attackerTouchedBallInDefenseArea\x12Y\n" +
+ "\x18bot_kicked_ball_too_fast\x18\x12 \x01(\v2\x1f.GameEvent.BotKickedBallTooFastH\x00R\x14botKickedBallTooFast\x12E\n" +
+ "\x10bot_crash_unique\x18\x16 \x01(\v2\x19.GameEvent.BotCrashUniqueH\x00R\x0ebotCrashUnique\x12B\n" +
+ "\x0fbot_crash_drawn\x18\x15 \x01(\v2\x18.GameEvent.BotCrashDrawnH\x00R\rbotCrashDrawn\x12o\n" +
+ " defender_too_close_to_kick_point\x18\x1d \x01(\v2&.GameEvent.DefenderTooCloseToKickPointH\x00R\x1bdefenderTooCloseToKickPoint\x12M\n" +
+ "\x14bot_too_fast_in_stop\x18\x1c \x01(\v2\x1b.GameEvent.BotTooFastInStopH\x00R\x10botTooFastInStop\x12]\n" +
+ "\x18bot_interfered_placement\x18\x14 \x01(\v2!.GameEvent.BotInterferedPlacementH\x00R\x16botInterferedPlacement\x126\n" +
+ "\rpossible_goal\x18' \x01(\v2\x0f.GameEvent.GoalH\x00R\fpossibleGoal\x12%\n" +
+ "\x04goal\x18\b \x01(\v2\x0f.GameEvent.GoalH\x00R\x04goal\x124\n" +
+ "\finvalid_goal\x18, \x01(\v2\x0f.GameEvent.GoalH\x00R\vinvalidGoal\x12g\n" +
+ "\x1cattacker_double_touched_ball\x18\x0e \x01(\v2$.GameEvent.AttackerDoubleTouchedBallH\x00R\x19attackerDoubleTouchedBall\x12P\n" +
+ "\x13placement_succeeded\x18\x05 \x01(\v2\x1d.GameEvent.PlacementSucceededH\x00R\x12placementSucceeded\x12N\n" +
+ "\x13penalty_kick_failed\x18- \x01(\v2\x1c.GameEvent.PenaltyKickFailedH\x00R\x11penaltyKickFailed\x12L\n" +
+ "\x13no_progress_in_game\x18\x02 \x01(\v2\x1b.GameEvent.NoProgressInGameH\x00R\x10noProgressInGame\x12G\n" +
+ "\x10placement_failed\x18\x03 \x01(\v2\x1a.GameEvent.PlacementFailedH\x00R\x0fplacementFailed\x12A\n" +
+ "\x0emultiple_cards\x18 \x01(\v2\x18.GameEvent.MultipleCardsH\x00R\rmultipleCards\x12A\n" +
+ "\x0emultiple_fouls\x18\" \x01(\v2\x18.GameEvent.MultipleFoulsH\x00R\rmultipleFouls\x12G\n" +
+ "\x10bot_substitution\x18% \x01(\v2\x1a.GameEvent.BotSubstitutionH\x00R\x0fbotSubstitution\x12c\n" +
+ "\x1aexcessive_bot_substitution\x184 \x01(\v2#.GameEvent.ExcessiveBotSubstitutionH\x00R\x18excessiveBotSubstitution\x12B\n" +
+ "\x0ftoo_many_robots\x18& \x01(\v2\x18.GameEvent.TooManyRobotsH\x00R\rtooManyRobots\x12A\n" +
+ "\x0echallenge_flag\x18. \x01(\v2\x18.GameEvent.ChallengeFlagH\x00R\rchallengeFlag\x12W\n" +
+ "\x16challenge_flag_handled\x180 \x01(\v2\x1f.GameEvent.ChallengeFlagHandledH\x00R\x14challengeFlagHandled\x12A\n" +
+ "\x0eemergency_stop\x18/ \x01(\v2\x18.GameEvent.EmergencyStopH\x00R\remergencyStop\x12`\n" +
+ "\x19unsporting_behavior_minor\x18# \x01(\v2\".GameEvent.UnsportingBehaviorMinorH\x00R\x17unsportingBehaviorMinor\x12`\n" +
+ "\x19unsporting_behavior_major\x18$ \x01(\v2\".GameEvent.UnsportingBehaviorMajorH\x00R\x17unsportingBehaviorMajor\x125\n" +
+ "\bprepared\x18\x01 \x01(\v2\x13.GameEvent.PreparedB\x02\x18\x01H\x00R\bprepared\x12B\n" +
+ "\rindirect_goal\x18\t \x01(\v2\x17.GameEvent.IndirectGoalB\x02\x18\x01H\x00R\findirectGoal\x12?\n" +
+ "\fchipped_goal\x18\n" +
+ " \x01(\v2\x16.GameEvent.ChippedGoalB\x02\x18\x01H\x00R\vchippedGoal\x12?\n" +
+ "\fkick_timeout\x18\f \x01(\v2\x16.GameEvent.KickTimeoutB\x02\x18\x01H\x00R\vkickTimeout\x12\x8e\x01\n" +
+ ")attacker_touched_opponent_in_defense_area\x18\x10 \x01(\v2/.GameEvent.AttackerTouchedOpponentInDefenseAreaB\x02\x18\x01H\x00R$attackerTouchedOpponentInDefenseArea\x12\x9d\x01\n" +
+ "1attacker_touched_opponent_in_defense_area_skipped\x18* \x01(\v2/.GameEvent.AttackerTouchedOpponentInDefenseAreaB\x02\x18\x01H\x00R+attackerTouchedOpponentInDefenseAreaSkipped\x12X\n" +
+ "\x18bot_crash_unique_skipped\x18\x17 \x01(\v2\x19.GameEvent.BotCrashUniqueB\x02\x18\x01H\x00R\x15botCrashUniqueSkipped\x12R\n" +
+ "\x16bot_pushed_bot_skipped\x18\x19 \x01(\v2\x17.GameEvent.BotPushedBotB\x02\x18\x01H\x00R\x13botPushedBotSkipped\x12{\n" +
+ "\"defender_in_defense_area_partially\x18\x1e \x01(\v2).GameEvent.DefenderInDefenseAreaPartiallyB\x02\x18\x01H\x00R\x1edefenderInDefenseAreaPartially\x12j\n" +
+ "\x1bmultiple_placement_failures\x18! \x01(\v2$.GameEvent.MultiplePlacementFailuresB\x02\x18\x01H\x00R\x19multiplePlacementFailures\x1al\n" +
+ "\rBallLeftField\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
+ "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x1a\x99\x01\n" +
+ "\vAimlessKick\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
+ "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12-\n" +
+ "\rkick_location\x18\x04 \x01(\v2\b.Vector2R\fkickLocation\x1a\xe2\x02\n" +
+ "\x04Goal\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12(\n" +
+ "\fkicking_team\x18\x06 \x01(\x0e2\x05.TeamR\vkickingTeam\x12\x1f\n" +
+ "\vkicking_bot\x18\x02 \x01(\rR\n" +
+ "kickingBot\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12-\n" +
+ "\rkick_location\x18\x04 \x01(\v2\b.Vector2R\fkickLocation\x12&\n" +
+ "\x0fmax_ball_height\x18\x05 \x01(\x02R\rmaxBallHeight\x12+\n" +
+ "\x12num_robots_by_team\x18\a \x01(\rR\x0fnumRobotsByTeam\x12+\n" +
+ "\x12last_touch_by_team\x18\b \x01(\x04R\x0flastTouchByTeam\x12\x18\n" +
+ "\amessage\x18\t \x01(\tR\amessage\x1a\x9a\x01\n" +
+ "\fIndirectGoal\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
+ "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12-\n" +
+ "\rkick_location\x18\x04 \x01(\v2\b.Vector2R\fkickLocation\x1a\xc1\x01\n" +
+ "\vChippedGoal\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
+ "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12-\n" +
+ "\rkick_location\x18\x04 \x01(\v2\b.Vector2R\fkickLocation\x12&\n" +
+ "\x0fmax_ball_height\x18\x05 \x01(\x02R\rmaxBallHeight\x1a\x85\x01\n" +
+ "\x10BotTooFastInStop\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
+ "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12\x14\n" +
+ "\x05speed\x18\x04 \x01(\x02R\x05speed\x1a\x96\x01\n" +
+ "\x1bDefenderTooCloseToKickPoint\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
+ "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12\x1a\n" +
+ "\bdistance\x18\x04 \x01(\x02R\bdistance\x1a\xd0\x01\n" +
+ "\rBotCrashDrawn\x12\x1d\n" +
+ "\n" +
+ "bot_yellow\x18\x01 \x01(\rR\tbotYellow\x12\x19\n" +
+ "\bbot_blue\x18\x02 \x01(\rR\abotBlue\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12\x1f\n" +
+ "\vcrash_speed\x18\x04 \x01(\x02R\n" +
+ "crashSpeed\x12\x1d\n" +
+ "\n" +
+ "speed_diff\x18\x05 \x01(\x02R\tspeedDiff\x12\x1f\n" +
+ "\vcrash_angle\x18\x06 \x01(\x02R\n" +
+ "crashAngle\x1a\xeb\x01\n" +
+ "\x0eBotCrashUnique\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x1a\n" +
+ "\bviolator\x18\x02 \x01(\rR\bviolator\x12\x16\n" +
+ "\x06victim\x18\x03 \x01(\rR\x06victim\x12$\n" +
+ "\blocation\x18\x04 \x01(\v2\b.Vector2R\blocation\x12\x1f\n" +
+ "\vcrash_speed\x18\x05 \x01(\x02R\n" +
+ "crashSpeed\x12\x1d\n" +
+ "\n" +
+ "speed_diff\x18\x06 \x01(\x02R\tspeedDiff\x12\x1f\n" +
+ "\vcrash_angle\x18\a \x01(\x02R\n" +
+ "crashAngle\x1a\xb1\x01\n" +
+ "\fBotPushedBot\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x1a\n" +
+ "\bviolator\x18\x02 \x01(\rR\bviolator\x12\x16\n" +
+ "\x06victim\x18\x03 \x01(\rR\x06victim\x12$\n" +
+ "\blocation\x18\x04 \x01(\v2\b.Vector2R\blocation\x12'\n" +
+ "\x0fpushed_distance\x18\x05 \x01(\x02R\x0epushedDistance\x1a\x9b\x01\n" +
+ "\rBotTippedOver\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
+ "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12-\n" +
+ "\rball_location\x18\x04 \x01(\v2\b.Vector2R\fballLocation\x1a\x9d\x01\n" +
+ "\x0fBotDroppedParts\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
+ "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12-\n" +
+ "\rball_location\x18\x04 \x01(\v2\b.Vector2R\fballLocation\x1a\x90\x01\n" +
+ "\x15DefenderInDefenseArea\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
+ "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12\x1a\n" +
+ "\bdistance\x18\x04 \x01(\x02R\bdistance\x1a\xc8\x01\n" +
+ "\x1eDefenderInDefenseAreaPartially\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
+ "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12\x1a\n" +
+ "\bdistance\x18\x04 \x01(\x02R\bdistance\x12-\n" +
+ "\rball_location\x18\x05 \x01(\v2\b.Vector2R\fballLocation\x1a\x9b\x01\n" +
+ " AttackerTouchedBallInDefenseArea\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
+ "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12\x1a\n" +
+ "\bdistance\x18\x04 \x01(\x02R\bdistance\x1a\xbb\x01\n" +
+ "\x14BotKickedBallTooFast\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
+ "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12,\n" +
+ "\x12initial_ball_speed\x18\x04 \x01(\x02R\x10initialBallSpeed\x12\x18\n" +
+ "\achipped\x18\x05 \x01(\bR\achipped\x1a\x8a\x01\n" +
+ "\x15BotDribbledBallTooFar\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
+ "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12\x1e\n" +
+ "\x05start\x18\x03 \x01(\v2\b.Vector2R\x05start\x12\x1a\n" +
+ "\x03end\x18\x04 \x01(\v2\b.Vector2R\x03end\x1a\x9b\x01\n" +
+ "$AttackerTouchedOpponentInDefenseArea\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
+ "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12\x16\n" +
+ "\x06victim\x18\x04 \x01(\rR\x06victim\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x1ax\n" +
+ "\x19AttackerDoubleTouchedBall\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
+ "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x1a\xc7\x01\n" +
+ "\x1dAttackerTooCloseToDefenseArea\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
+ "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12\x1a\n" +
+ "\bdistance\x18\x04 \x01(\x02R\bdistance\x12-\n" +
+ "\rball_location\x18\x05 \x01(\v2\b.Vector2R\fballLocation\x1a\x92\x01\n" +
+ "\x17BotHeldBallDeliberately\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
+ "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12\x1a\n" +
+ "\bduration\x18\x04 \x01(\x02R\bduration\x1au\n" +
+ "\x16BotInterferedPlacement\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
+ "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
+ "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x1a/\n" +
+ "\rMultipleCards\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x1ai\n" +
+ "\rMultipleFouls\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x128\n" +
+ "\x12caused_game_events\x18\x02 \x03(\v2\n" +
+ ".GameEventR\x10causedGameEvents\x1a;\n" +
+ "\x19MultiplePlacementFailures\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x1ag\n" +
+ "\vKickTimeout\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12$\n" +
+ "\blocation\x18\x02 \x01(\v2\b.Vector2R\blocation\x12\x12\n" +
+ "\x04time\x18\x03 \x01(\x02R\x04time\x1aL\n" +
+ "\x10NoProgressInGame\x12$\n" +
+ "\blocation\x18\x01 \x01(\v2\b.Vector2R\blocation\x12\x12\n" +
+ "\x04time\x18\x02 \x01(\x02R\x04time\x1a\x99\x01\n" +
+ "\x0fPlacementFailed\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12-\n" +
+ "\x12remaining_distance\x18\x02 \x01(\x02R\x11remainingDistance\x127\n" +
+ "\x18nearest_own_bot_distance\x18\x03 \x01(\x02R\x15nearestOwnBotDistance\x1aQ\n" +
+ "\x17UnsportingBehaviorMinor\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x16\n" +
+ "\x06reason\x18\x02 \x02(\tR\x06reason\x1aQ\n" +
+ "\x17UnsportingBehaviorMajor\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x16\n" +
+ "\x06reason\x18\x02 \x02(\tR\x06reason\x1ar\n" +
+ "\x0eKeeperHeldBall\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12$\n" +
+ "\blocation\x18\x02 \x01(\v2\b.Vector2R\blocation\x12\x1a\n" +
+ "\bduration\x18\x03 \x01(\x02R\bduration\x1a\x8d\x01\n" +
+ "\x12PlacementSucceeded\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x1d\n" +
+ "\n" +
+ "time_taken\x18\x02 \x01(\x02R\ttimeTaken\x12\x1c\n" +
+ "\tprecision\x18\x03 \x01(\x02R\tprecision\x12\x1a\n" +
+ "\bdistance\x18\x04 \x01(\x02R\bdistance\x1a)\n" +
+ "\bPrepared\x12\x1d\n" +
+ "\n" +
+ "time_taken\x18\x01 \x01(\x02R\ttimeTaken\x1a1\n" +
+ "\x0fBotSubstitution\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x1a:\n" +
+ "\x18ExcessiveBotSubstitution\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x1a/\n" +
+ "\rChallengeFlag\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x1aR\n" +
+ "\x14ChallengeFlagHandled\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x1a\n" +
+ "\baccepted\x18\x02 \x02(\bR\baccepted\x1a/\n" +
+ "\rEmergencyStop\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x1a\xbb\x01\n" +
+ "\rTooManyRobots\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12,\n" +
+ "\x12num_robots_allowed\x18\x02 \x01(\x05R\x10numRobotsAllowed\x12-\n" +
+ "\x13num_robots_on_field\x18\x03 \x01(\x05R\x10numRobotsOnField\x12-\n" +
+ "\rball_location\x18\x04 \x01(\v2\b.Vector2R\fballLocation\x1aX\n" +
+ "\x10BoundaryCrossing\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12$\n" +
+ "\blocation\x18\x02 \x01(\v2\b.Vector2R\blocation\x1aq\n" +
+ "\x11PenaltyKickFailed\x12\x1e\n" +
+ "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12$\n" +
+ "\blocation\x18\x02 \x01(\v2\b.Vector2R\blocation\x12\x16\n" +
+ "\x06reason\x18\x03 \x01(\tR\x06reason\"\xb5\n" +
+ "\n" +
+ "\x04Type\x12\x1b\n" +
+ "\x17UNKNOWN_GAME_EVENT_TYPE\x10\x00\x12\x1e\n" +
+ "\x1aBALL_LEFT_FIELD_TOUCH_LINE\x10\x06\x12\x1d\n" +
+ "\x19BALL_LEFT_FIELD_GOAL_LINE\x10\a\x12\x10\n" +
+ "\fAIMLESS_KICK\x10\v\x12&\n" +
+ "\"ATTACKER_TOO_CLOSE_TO_DEFENSE_AREA\x10\x13\x12\x1c\n" +
+ "\x18DEFENDER_IN_DEFENSE_AREA\x10\x1f\x12\x15\n" +
+ "\x11BOUNDARY_CROSSING\x10)\x12\x14\n" +
+ "\x10KEEPER_HELD_BALL\x10\r\x12\x1d\n" +
+ "\x19BOT_DRIBBLED_BALL_TOO_FAR\x10\x11\x12\x12\n" +
+ "\x0eBOT_PUSHED_BOT\x10\x18\x12\x1e\n" +
+ "\x1aBOT_HELD_BALL_DELIBERATELY\x10\x1a\x12\x13\n" +
+ "\x0fBOT_TIPPED_OVER\x10\x1b\x12\x15\n" +
+ "\x11BOT_DROPPED_PARTS\x10/\x12)\n" +
+ "%ATTACKER_TOUCHED_BALL_IN_DEFENSE_AREA\x10\x0f\x12\x1c\n" +
+ "\x18BOT_KICKED_BALL_TOO_FAST\x10\x12\x12\x14\n" +
+ "\x10BOT_CRASH_UNIQUE\x10\x16\x12\x13\n" +
+ "\x0fBOT_CRASH_DRAWN\x10\x15\x12$\n" +
+ " DEFENDER_TOO_CLOSE_TO_KICK_POINT\x10\x1d\x12\x18\n" +
+ "\x14BOT_TOO_FAST_IN_STOP\x10\x1c\x12\x1c\n" +
+ "\x18BOT_INTERFERED_PLACEMENT\x10\x14\x12\x1e\n" +
+ "\x1aEXCESSIVE_BOT_SUBSTITUTION\x100\x12\x11\n" +
+ "\rPOSSIBLE_GOAL\x10'\x12\b\n" +
+ "\x04GOAL\x10\b\x12\x10\n" +
+ "\fINVALID_GOAL\x10*\x12 \n" +
+ "\x1cATTACKER_DOUBLE_TOUCHED_BALL\x10\x0e\x12\x17\n" +
+ "\x13PLACEMENT_SUCCEEDED\x10\x05\x12\x17\n" +
+ "\x13PENALTY_KICK_FAILED\x10+\x12\x17\n" +
+ "\x13NO_PROGRESS_IN_GAME\x10\x02\x12\x14\n" +
+ "\x10PLACEMENT_FAILED\x10\x03\x12\x12\n" +
+ "\x0eMULTIPLE_CARDS\x10 \x12\x12\n" +
+ "\x0eMULTIPLE_FOULS\x10\"\x12\x14\n" +
+ "\x10BOT_SUBSTITUTION\x10%\x12\x13\n" +
+ "\x0fTOO_MANY_ROBOTS\x10&\x12\x12\n" +
+ "\x0eCHALLENGE_FLAG\x10,\x12\x1a\n" +
+ "\x16CHALLENGE_FLAG_HANDLED\x10.\x12\x12\n" +
+ "\x0eEMERGENCY_STOP\x10-\x12\x1d\n" +
+ "\x19UNSPORTING_BEHAVIOR_MINOR\x10#\x12\x1d\n" +
+ "\x19UNSPORTING_BEHAVIOR_MAJOR\x10$\x12\x10\n" +
+ "\bPREPARED\x10\x01\x1a\x02\b\x01\x12\x15\n" +
+ "\rINDIRECT_GOAL\x10\t\x1a\x02\b\x01\x12\x14\n" +
+ "\fCHIPPED_GOAL\x10\n" +
+ "\x1a\x02\b\x01\x12\x14\n" +
+ "\fKICK_TIMEOUT\x10\f\x1a\x02\b\x01\x121\n" +
+ ")ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA\x10\x10\x1a\x02\b\x01\x129\n" +
+ "1ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA_SKIPPED\x10(\x1a\x02\b\x01\x12 \n" +
+ "\x18BOT_CRASH_UNIQUE_SKIPPED\x10\x17\x1a\x02\b\x01\x12\x1e\n" +
+ "\x16BOT_PUSHED_BOT_SKIPPED\x10\x19\x1a\x02\b\x01\x12*\n" +
+ "\"DEFENDER_IN_DEFENSE_AREA_PARTIALLY\x10\x1e\x1a\x02\b\x01\x12#\n" +
+ "\x1bMULTIPLE_PLACEMENT_FAILURES\x10!\x1a\x02\b\x01B\a\n" +
+ "\x05eventB`B\x13SslGcGameEventProtoP\x01ZGgithub.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
+
+var (
+ file_gamecontroller_ssl_gc_game_event_proto_rawDescOnce sync.Once
+ file_gamecontroller_ssl_gc_game_event_proto_rawDescData []byte
+)
+
+func file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP() []byte {
+ file_gamecontroller_ssl_gc_game_event_proto_rawDescOnce.Do(func() {
+ file_gamecontroller_ssl_gc_game_event_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_game_event_proto_rawDesc), len(file_gamecontroller_ssl_gc_game_event_proto_rawDesc)))
+ })
+ return file_gamecontroller_ssl_gc_game_event_proto_rawDescData
+}
+
+var file_gamecontroller_ssl_gc_game_event_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_gamecontroller_ssl_gc_game_event_proto_msgTypes = make([]protoimpl.MessageInfo, 42)
+var file_gamecontroller_ssl_gc_game_event_proto_goTypes = []any{
+ (GameEvent_Type)(0), // 0: GameEvent.Type
+ (*GameEvent)(nil), // 1: GameEvent
+ (*GameEvent_BallLeftField)(nil), // 2: GameEvent.BallLeftField
+ (*GameEvent_AimlessKick)(nil), // 3: GameEvent.AimlessKick
+ (*GameEvent_Goal)(nil), // 4: GameEvent.Goal
+ (*GameEvent_IndirectGoal)(nil), // 5: GameEvent.IndirectGoal
+ (*GameEvent_ChippedGoal)(nil), // 6: GameEvent.ChippedGoal
+ (*GameEvent_BotTooFastInStop)(nil), // 7: GameEvent.BotTooFastInStop
+ (*GameEvent_DefenderTooCloseToKickPoint)(nil), // 8: GameEvent.DefenderTooCloseToKickPoint
+ (*GameEvent_BotCrashDrawn)(nil), // 9: GameEvent.BotCrashDrawn
+ (*GameEvent_BotCrashUnique)(nil), // 10: GameEvent.BotCrashUnique
+ (*GameEvent_BotPushedBot)(nil), // 11: GameEvent.BotPushedBot
+ (*GameEvent_BotTippedOver)(nil), // 12: GameEvent.BotTippedOver
+ (*GameEvent_BotDroppedParts)(nil), // 13: GameEvent.BotDroppedParts
+ (*GameEvent_DefenderInDefenseArea)(nil), // 14: GameEvent.DefenderInDefenseArea
+ (*GameEvent_DefenderInDefenseAreaPartially)(nil), // 15: GameEvent.DefenderInDefenseAreaPartially
+ (*GameEvent_AttackerTouchedBallInDefenseArea)(nil), // 16: GameEvent.AttackerTouchedBallInDefenseArea
+ (*GameEvent_BotKickedBallTooFast)(nil), // 17: GameEvent.BotKickedBallTooFast
+ (*GameEvent_BotDribbledBallTooFar)(nil), // 18: GameEvent.BotDribbledBallTooFar
+ (*GameEvent_AttackerTouchedOpponentInDefenseArea)(nil), // 19: GameEvent.AttackerTouchedOpponentInDefenseArea
+ (*GameEvent_AttackerDoubleTouchedBall)(nil), // 20: GameEvent.AttackerDoubleTouchedBall
+ (*GameEvent_AttackerTooCloseToDefenseArea)(nil), // 21: GameEvent.AttackerTooCloseToDefenseArea
+ (*GameEvent_BotHeldBallDeliberately)(nil), // 22: GameEvent.BotHeldBallDeliberately
+ (*GameEvent_BotInterferedPlacement)(nil), // 23: GameEvent.BotInterferedPlacement
+ (*GameEvent_MultipleCards)(nil), // 24: GameEvent.MultipleCards
+ (*GameEvent_MultipleFouls)(nil), // 25: GameEvent.MultipleFouls
+ (*GameEvent_MultiplePlacementFailures)(nil), // 26: GameEvent.MultiplePlacementFailures
+ (*GameEvent_KickTimeout)(nil), // 27: GameEvent.KickTimeout
+ (*GameEvent_NoProgressInGame)(nil), // 28: GameEvent.NoProgressInGame
+ (*GameEvent_PlacementFailed)(nil), // 29: GameEvent.PlacementFailed
+ (*GameEvent_UnsportingBehaviorMinor)(nil), // 30: GameEvent.UnsportingBehaviorMinor
+ (*GameEvent_UnsportingBehaviorMajor)(nil), // 31: GameEvent.UnsportingBehaviorMajor
+ (*GameEvent_KeeperHeldBall)(nil), // 32: GameEvent.KeeperHeldBall
+ (*GameEvent_PlacementSucceeded)(nil), // 33: GameEvent.PlacementSucceeded
+ (*GameEvent_Prepared)(nil), // 34: GameEvent.Prepared
+ (*GameEvent_BotSubstitution)(nil), // 35: GameEvent.BotSubstitution
+ (*GameEvent_ExcessiveBotSubstitution)(nil), // 36: GameEvent.ExcessiveBotSubstitution
+ (*GameEvent_ChallengeFlag)(nil), // 37: GameEvent.ChallengeFlag
+ (*GameEvent_ChallengeFlagHandled)(nil), // 38: GameEvent.ChallengeFlagHandled
+ (*GameEvent_EmergencyStop)(nil), // 39: GameEvent.EmergencyStop
+ (*GameEvent_TooManyRobots)(nil), // 40: GameEvent.TooManyRobots
+ (*GameEvent_BoundaryCrossing)(nil), // 41: GameEvent.BoundaryCrossing
+ (*GameEvent_PenaltyKickFailed)(nil), // 42: GameEvent.PenaltyKickFailed
+ (Team)(0), // 43: Team
+ (*Vector2)(nil), // 44: Vector2
+}
+var file_gamecontroller_ssl_gc_game_event_proto_depIdxs = []int32{
+ 0, // 0: GameEvent.type:type_name -> GameEvent.Type
+ 2, // 1: GameEvent.ball_left_field_touch_line:type_name -> GameEvent.BallLeftField
+ 2, // 2: GameEvent.ball_left_field_goal_line:type_name -> GameEvent.BallLeftField
+ 3, // 3: GameEvent.aimless_kick:type_name -> GameEvent.AimlessKick
+ 21, // 4: GameEvent.attacker_too_close_to_defense_area:type_name -> GameEvent.AttackerTooCloseToDefenseArea
+ 14, // 5: GameEvent.defender_in_defense_area:type_name -> GameEvent.DefenderInDefenseArea
+ 41, // 6: GameEvent.boundary_crossing:type_name -> GameEvent.BoundaryCrossing
+ 32, // 7: GameEvent.keeper_held_ball:type_name -> GameEvent.KeeperHeldBall
+ 18, // 8: GameEvent.bot_dribbled_ball_too_far:type_name -> GameEvent.BotDribbledBallTooFar
+ 11, // 9: GameEvent.bot_pushed_bot:type_name -> GameEvent.BotPushedBot
+ 22, // 10: GameEvent.bot_held_ball_deliberately:type_name -> GameEvent.BotHeldBallDeliberately
+ 12, // 11: GameEvent.bot_tipped_over:type_name -> GameEvent.BotTippedOver
+ 13, // 12: GameEvent.bot_dropped_parts:type_name -> GameEvent.BotDroppedParts
+ 16, // 13: GameEvent.attacker_touched_ball_in_defense_area:type_name -> GameEvent.AttackerTouchedBallInDefenseArea
+ 17, // 14: GameEvent.bot_kicked_ball_too_fast:type_name -> GameEvent.BotKickedBallTooFast
+ 10, // 15: GameEvent.bot_crash_unique:type_name -> GameEvent.BotCrashUnique
+ 9, // 16: GameEvent.bot_crash_drawn:type_name -> GameEvent.BotCrashDrawn
+ 8, // 17: GameEvent.defender_too_close_to_kick_point:type_name -> GameEvent.DefenderTooCloseToKickPoint
+ 7, // 18: GameEvent.bot_too_fast_in_stop:type_name -> GameEvent.BotTooFastInStop
+ 23, // 19: GameEvent.bot_interfered_placement:type_name -> GameEvent.BotInterferedPlacement
+ 4, // 20: GameEvent.possible_goal:type_name -> GameEvent.Goal
+ 4, // 21: GameEvent.goal:type_name -> GameEvent.Goal
+ 4, // 22: GameEvent.invalid_goal:type_name -> GameEvent.Goal
+ 20, // 23: GameEvent.attacker_double_touched_ball:type_name -> GameEvent.AttackerDoubleTouchedBall
+ 33, // 24: GameEvent.placement_succeeded:type_name -> GameEvent.PlacementSucceeded
+ 42, // 25: GameEvent.penalty_kick_failed:type_name -> GameEvent.PenaltyKickFailed
+ 28, // 26: GameEvent.no_progress_in_game:type_name -> GameEvent.NoProgressInGame
+ 29, // 27: GameEvent.placement_failed:type_name -> GameEvent.PlacementFailed
+ 24, // 28: GameEvent.multiple_cards:type_name -> GameEvent.MultipleCards
+ 25, // 29: GameEvent.multiple_fouls:type_name -> GameEvent.MultipleFouls
+ 35, // 30: GameEvent.bot_substitution:type_name -> GameEvent.BotSubstitution
+ 36, // 31: GameEvent.excessive_bot_substitution:type_name -> GameEvent.ExcessiveBotSubstitution
+ 40, // 32: GameEvent.too_many_robots:type_name -> GameEvent.TooManyRobots
+ 37, // 33: GameEvent.challenge_flag:type_name -> GameEvent.ChallengeFlag
+ 38, // 34: GameEvent.challenge_flag_handled:type_name -> GameEvent.ChallengeFlagHandled
+ 39, // 35: GameEvent.emergency_stop:type_name -> GameEvent.EmergencyStop
+ 30, // 36: GameEvent.unsporting_behavior_minor:type_name -> GameEvent.UnsportingBehaviorMinor
+ 31, // 37: GameEvent.unsporting_behavior_major:type_name -> GameEvent.UnsportingBehaviorMajor
+ 34, // 38: GameEvent.prepared:type_name -> GameEvent.Prepared
+ 5, // 39: GameEvent.indirect_goal:type_name -> GameEvent.IndirectGoal
+ 6, // 40: GameEvent.chipped_goal:type_name -> GameEvent.ChippedGoal
+ 27, // 41: GameEvent.kick_timeout:type_name -> GameEvent.KickTimeout
+ 19, // 42: GameEvent.attacker_touched_opponent_in_defense_area:type_name -> GameEvent.AttackerTouchedOpponentInDefenseArea
+ 19, // 43: GameEvent.attacker_touched_opponent_in_defense_area_skipped:type_name -> GameEvent.AttackerTouchedOpponentInDefenseArea
+ 10, // 44: GameEvent.bot_crash_unique_skipped:type_name -> GameEvent.BotCrashUnique
+ 11, // 45: GameEvent.bot_pushed_bot_skipped:type_name -> GameEvent.BotPushedBot
+ 15, // 46: GameEvent.defender_in_defense_area_partially:type_name -> GameEvent.DefenderInDefenseAreaPartially
+ 26, // 47: GameEvent.multiple_placement_failures:type_name -> GameEvent.MultiplePlacementFailures
+ 43, // 48: GameEvent.BallLeftField.by_team:type_name -> Team
+ 44, // 49: GameEvent.BallLeftField.location:type_name -> Vector2
+ 43, // 50: GameEvent.AimlessKick.by_team:type_name -> Team
+ 44, // 51: GameEvent.AimlessKick.location:type_name -> Vector2
+ 44, // 52: GameEvent.AimlessKick.kick_location:type_name -> Vector2
+ 43, // 53: GameEvent.Goal.by_team:type_name -> Team
+ 43, // 54: GameEvent.Goal.kicking_team:type_name -> Team
+ 44, // 55: GameEvent.Goal.location:type_name -> Vector2
+ 44, // 56: GameEvent.Goal.kick_location:type_name -> Vector2
+ 43, // 57: GameEvent.IndirectGoal.by_team:type_name -> Team
+ 44, // 58: GameEvent.IndirectGoal.location:type_name -> Vector2
+ 44, // 59: GameEvent.IndirectGoal.kick_location:type_name -> Vector2
+ 43, // 60: GameEvent.ChippedGoal.by_team:type_name -> Team
+ 44, // 61: GameEvent.ChippedGoal.location:type_name -> Vector2
+ 44, // 62: GameEvent.ChippedGoal.kick_location:type_name -> Vector2
+ 43, // 63: GameEvent.BotTooFastInStop.by_team:type_name -> Team
+ 44, // 64: GameEvent.BotTooFastInStop.location:type_name -> Vector2
+ 43, // 65: GameEvent.DefenderTooCloseToKickPoint.by_team:type_name -> Team
+ 44, // 66: GameEvent.DefenderTooCloseToKickPoint.location:type_name -> Vector2
+ 44, // 67: GameEvent.BotCrashDrawn.location:type_name -> Vector2
+ 43, // 68: GameEvent.BotCrashUnique.by_team:type_name -> Team
+ 44, // 69: GameEvent.BotCrashUnique.location:type_name -> Vector2
+ 43, // 70: GameEvent.BotPushedBot.by_team:type_name -> Team
+ 44, // 71: GameEvent.BotPushedBot.location:type_name -> Vector2
+ 43, // 72: GameEvent.BotTippedOver.by_team:type_name -> Team
+ 44, // 73: GameEvent.BotTippedOver.location:type_name -> Vector2
+ 44, // 74: GameEvent.BotTippedOver.ball_location:type_name -> Vector2
+ 43, // 75: GameEvent.BotDroppedParts.by_team:type_name -> Team
+ 44, // 76: GameEvent.BotDroppedParts.location:type_name -> Vector2
+ 44, // 77: GameEvent.BotDroppedParts.ball_location:type_name -> Vector2
+ 43, // 78: GameEvent.DefenderInDefenseArea.by_team:type_name -> Team
+ 44, // 79: GameEvent.DefenderInDefenseArea.location:type_name -> Vector2
+ 43, // 80: GameEvent.DefenderInDefenseAreaPartially.by_team:type_name -> Team
+ 44, // 81: GameEvent.DefenderInDefenseAreaPartially.location:type_name -> Vector2
+ 44, // 82: GameEvent.DefenderInDefenseAreaPartially.ball_location:type_name -> Vector2
+ 43, // 83: GameEvent.AttackerTouchedBallInDefenseArea.by_team:type_name -> Team
+ 44, // 84: GameEvent.AttackerTouchedBallInDefenseArea.location:type_name -> Vector2
+ 43, // 85: GameEvent.BotKickedBallTooFast.by_team:type_name -> Team
+ 44, // 86: GameEvent.BotKickedBallTooFast.location:type_name -> Vector2
+ 43, // 87: GameEvent.BotDribbledBallTooFar.by_team:type_name -> Team
+ 44, // 88: GameEvent.BotDribbledBallTooFar.start:type_name -> Vector2
+ 44, // 89: GameEvent.BotDribbledBallTooFar.end:type_name -> Vector2
+ 43, // 90: GameEvent.AttackerTouchedOpponentInDefenseArea.by_team:type_name -> Team
+ 44, // 91: GameEvent.AttackerTouchedOpponentInDefenseArea.location:type_name -> Vector2
+ 43, // 92: GameEvent.AttackerDoubleTouchedBall.by_team:type_name -> Team
+ 44, // 93: GameEvent.AttackerDoubleTouchedBall.location:type_name -> Vector2
+ 43, // 94: GameEvent.AttackerTooCloseToDefenseArea.by_team:type_name -> Team
+ 44, // 95: GameEvent.AttackerTooCloseToDefenseArea.location:type_name -> Vector2
+ 44, // 96: GameEvent.AttackerTooCloseToDefenseArea.ball_location:type_name -> Vector2
+ 43, // 97: GameEvent.BotHeldBallDeliberately.by_team:type_name -> Team
+ 44, // 98: GameEvent.BotHeldBallDeliberately.location:type_name -> Vector2
+ 43, // 99: GameEvent.BotInterferedPlacement.by_team:type_name -> Team
+ 44, // 100: GameEvent.BotInterferedPlacement.location:type_name -> Vector2
+ 43, // 101: GameEvent.MultipleCards.by_team:type_name -> Team
+ 43, // 102: GameEvent.MultipleFouls.by_team:type_name -> Team
+ 1, // 103: GameEvent.MultipleFouls.caused_game_events:type_name -> GameEvent
+ 43, // 104: GameEvent.MultiplePlacementFailures.by_team:type_name -> Team
+ 43, // 105: GameEvent.KickTimeout.by_team:type_name -> Team
+ 44, // 106: GameEvent.KickTimeout.location:type_name -> Vector2
+ 44, // 107: GameEvent.NoProgressInGame.location:type_name -> Vector2
+ 43, // 108: GameEvent.PlacementFailed.by_team:type_name -> Team
+ 43, // 109: GameEvent.UnsportingBehaviorMinor.by_team:type_name -> Team
+ 43, // 110: GameEvent.UnsportingBehaviorMajor.by_team:type_name -> Team
+ 43, // 111: GameEvent.KeeperHeldBall.by_team:type_name -> Team
+ 44, // 112: GameEvent.KeeperHeldBall.location:type_name -> Vector2
+ 43, // 113: GameEvent.PlacementSucceeded.by_team:type_name -> Team
+ 43, // 114: GameEvent.BotSubstitution.by_team:type_name -> Team
+ 43, // 115: GameEvent.ExcessiveBotSubstitution.by_team:type_name -> Team
+ 43, // 116: GameEvent.ChallengeFlag.by_team:type_name -> Team
+ 43, // 117: GameEvent.ChallengeFlagHandled.by_team:type_name -> Team
+ 43, // 118: GameEvent.EmergencyStop.by_team:type_name -> Team
+ 43, // 119: GameEvent.TooManyRobots.by_team:type_name -> Team
+ 44, // 120: GameEvent.TooManyRobots.ball_location:type_name -> Vector2
+ 43, // 121: GameEvent.BoundaryCrossing.by_team:type_name -> Team
+ 44, // 122: GameEvent.BoundaryCrossing.location:type_name -> Vector2
+ 43, // 123: GameEvent.PenaltyKickFailed.by_team:type_name -> Team
+ 44, // 124: GameEvent.PenaltyKickFailed.location:type_name -> Vector2
+ 125, // [125:125] is the sub-list for method output_type
+ 125, // [125:125] is the sub-list for method input_type
+ 125, // [125:125] is the sub-list for extension type_name
+ 125, // [125:125] is the sub-list for extension extendee
+ 0, // [0:125] is the sub-list for field type_name
+}
+
+func init() { file_gamecontroller_ssl_gc_game_event_proto_init() }
+func file_gamecontroller_ssl_gc_game_event_proto_init() {
+ if File_gamecontroller_ssl_gc_game_event_proto != nil {
+ return
+ }
+ file_gamecontroller_ssl_gc_common_proto_init()
+ file_gamecontroller_ssl_gc_geometry_proto_init()
+ file_gamecontroller_ssl_gc_game_event_proto_msgTypes[0].OneofWrappers = []any{
+ (*GameEvent_BallLeftFieldTouchLine)(nil),
+ (*GameEvent_BallLeftFieldGoalLine)(nil),
+ (*GameEvent_AimlessKick_)(nil),
+ (*GameEvent_AttackerTooCloseToDefenseArea_)(nil),
+ (*GameEvent_DefenderInDefenseArea_)(nil),
+ (*GameEvent_BoundaryCrossing_)(nil),
+ (*GameEvent_KeeperHeldBall_)(nil),
+ (*GameEvent_BotDribbledBallTooFar_)(nil),
+ (*GameEvent_BotPushedBot_)(nil),
+ (*GameEvent_BotHeldBallDeliberately_)(nil),
+ (*GameEvent_BotTippedOver_)(nil),
+ (*GameEvent_BotDroppedParts_)(nil),
+ (*GameEvent_AttackerTouchedBallInDefenseArea_)(nil),
+ (*GameEvent_BotKickedBallTooFast_)(nil),
+ (*GameEvent_BotCrashUnique_)(nil),
+ (*GameEvent_BotCrashDrawn_)(nil),
+ (*GameEvent_DefenderTooCloseToKickPoint_)(nil),
+ (*GameEvent_BotTooFastInStop_)(nil),
+ (*GameEvent_BotInterferedPlacement_)(nil),
+ (*GameEvent_PossibleGoal)(nil),
+ (*GameEvent_Goal_)(nil),
+ (*GameEvent_InvalidGoal)(nil),
+ (*GameEvent_AttackerDoubleTouchedBall_)(nil),
+ (*GameEvent_PlacementSucceeded_)(nil),
+ (*GameEvent_PenaltyKickFailed_)(nil),
+ (*GameEvent_NoProgressInGame_)(nil),
+ (*GameEvent_PlacementFailed_)(nil),
+ (*GameEvent_MultipleCards_)(nil),
+ (*GameEvent_MultipleFouls_)(nil),
+ (*GameEvent_BotSubstitution_)(nil),
+ (*GameEvent_ExcessiveBotSubstitution_)(nil),
+ (*GameEvent_TooManyRobots_)(nil),
+ (*GameEvent_ChallengeFlag_)(nil),
+ (*GameEvent_ChallengeFlagHandled_)(nil),
+ (*GameEvent_EmergencyStop_)(nil),
+ (*GameEvent_UnsportingBehaviorMinor_)(nil),
+ (*GameEvent_UnsportingBehaviorMajor_)(nil),
+ (*GameEvent_Prepared_)(nil),
+ (*GameEvent_IndirectGoal_)(nil),
+ (*GameEvent_ChippedGoal_)(nil),
+ (*GameEvent_KickTimeout_)(nil),
+ (*GameEvent_AttackerTouchedOpponentInDefenseArea_)(nil),
+ (*GameEvent_AttackerTouchedOpponentInDefenseAreaSkipped)(nil),
+ (*GameEvent_BotCrashUniqueSkipped)(nil),
+ (*GameEvent_BotPushedBotSkipped)(nil),
+ (*GameEvent_DefenderInDefenseAreaPartially_)(nil),
+ (*GameEvent_MultiplePlacementFailures_)(nil),
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_game_event_proto_rawDesc), len(file_gamecontroller_ssl_gc_game_event_proto_rawDesc)),
+ NumEnums: 1,
+ NumMessages: 42,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_gamecontroller_ssl_gc_game_event_proto_goTypes,
+ DependencyIndexes: file_gamecontroller_ssl_gc_game_event_proto_depIdxs,
+ EnumInfos: file_gamecontroller_ssl_gc_game_event_proto_enumTypes,
+ MessageInfos: file_gamecontroller_ssl_gc_game_event_proto_msgTypes,
+ }.Build()
+ File_gamecontroller_ssl_gc_game_event_proto = out.File
+ file_gamecontroller_ssl_gc_game_event_proto_goTypes = nil
+ file_gamecontroller_ssl_gc_game_event_proto_depIdxs = nil
+}
diff --git a/gui/internal/gamecontroller/ssl_gc_geometry.pb.go b/gui/internal/gamecontroller/ssl_gc_geometry.pb.go
new file mode 100644
index 0000000..b03a087
--- /dev/null
+++ b/gui/internal/gamecontroller/ssl_gc_geometry.pb.go
@@ -0,0 +1,198 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.36.6
+// protoc (unknown)
+// source: gamecontroller/ssl_gc_geometry.proto
+
+package gamecontroller
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+ unsafe "unsafe"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// A vector with two dimensions
+type Vector2 struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ X *float32 `protobuf:"fixed32,1,req,name=x" json:"x,omitempty"`
+ Y *float32 `protobuf:"fixed32,2,req,name=y" json:"y,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *Vector2) Reset() {
+ *x = Vector2{}
+ mi := &file_gamecontroller_ssl_gc_geometry_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *Vector2) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Vector2) ProtoMessage() {}
+
+func (x *Vector2) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_geometry_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Vector2.ProtoReflect.Descriptor instead.
+func (*Vector2) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_geometry_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Vector2) GetX() float32 {
+ if x != nil && x.X != nil {
+ return *x.X
+ }
+ return 0
+}
+
+func (x *Vector2) GetY() float32 {
+ if x != nil && x.Y != nil {
+ return *x.Y
+ }
+ return 0
+}
+
+// A vector with three dimensions
+type Vector3 struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ X *float32 `protobuf:"fixed32,1,req,name=x" json:"x,omitempty"`
+ Y *float32 `protobuf:"fixed32,2,req,name=y" json:"y,omitempty"`
+ Z *float32 `protobuf:"fixed32,3,req,name=z" json:"z,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *Vector3) Reset() {
+ *x = Vector3{}
+ mi := &file_gamecontroller_ssl_gc_geometry_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *Vector3) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Vector3) ProtoMessage() {}
+
+func (x *Vector3) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_geometry_proto_msgTypes[1]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Vector3.ProtoReflect.Descriptor instead.
+func (*Vector3) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_geometry_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *Vector3) GetX() float32 {
+ if x != nil && x.X != nil {
+ return *x.X
+ }
+ return 0
+}
+
+func (x *Vector3) GetY() float32 {
+ if x != nil && x.Y != nil {
+ return *x.Y
+ }
+ return 0
+}
+
+func (x *Vector3) GetZ() float32 {
+ if x != nil && x.Z != nil {
+ return *x.Z
+ }
+ return 0
+}
+
+var File_gamecontroller_ssl_gc_geometry_proto protoreflect.FileDescriptor
+
+const file_gamecontroller_ssl_gc_geometry_proto_rawDesc = "" +
+ "\n" +
+ "$gamecontroller/ssl_gc_geometry.proto\"%\n" +
+ "\aVector2\x12\f\n" +
+ "\x01x\x18\x01 \x02(\x02R\x01x\x12\f\n" +
+ "\x01y\x18\x02 \x02(\x02R\x01y\"3\n" +
+ "\aVector3\x12\f\n" +
+ "\x01x\x18\x01 \x02(\x02R\x01x\x12\f\n" +
+ "\x01y\x18\x02 \x02(\x02R\x01y\x12\f\n" +
+ "\x01z\x18\x03 \x02(\x02R\x01zB_B\x12SslGcGeometryProtoP\x01ZGgithub.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
+
+var (
+ file_gamecontroller_ssl_gc_geometry_proto_rawDescOnce sync.Once
+ file_gamecontroller_ssl_gc_geometry_proto_rawDescData []byte
+)
+
+func file_gamecontroller_ssl_gc_geometry_proto_rawDescGZIP() []byte {
+ file_gamecontroller_ssl_gc_geometry_proto_rawDescOnce.Do(func() {
+ file_gamecontroller_ssl_gc_geometry_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_geometry_proto_rawDesc), len(file_gamecontroller_ssl_gc_geometry_proto_rawDesc)))
+ })
+ return file_gamecontroller_ssl_gc_geometry_proto_rawDescData
+}
+
+var file_gamecontroller_ssl_gc_geometry_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_gamecontroller_ssl_gc_geometry_proto_goTypes = []any{
+ (*Vector2)(nil), // 0: Vector2
+ (*Vector3)(nil), // 1: Vector3
+}
+var file_gamecontroller_ssl_gc_geometry_proto_depIdxs = []int32{
+ 0, // [0:0] is the sub-list for method output_type
+ 0, // [0:0] is the sub-list for method input_type
+ 0, // [0:0] is the sub-list for extension type_name
+ 0, // [0:0] is the sub-list for extension extendee
+ 0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_gamecontroller_ssl_gc_geometry_proto_init() }
+func file_gamecontroller_ssl_gc_geometry_proto_init() {
+ if File_gamecontroller_ssl_gc_geometry_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_geometry_proto_rawDesc), len(file_gamecontroller_ssl_gc_geometry_proto_rawDesc)),
+ NumEnums: 0,
+ NumMessages: 2,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_gamecontroller_ssl_gc_geometry_proto_goTypes,
+ DependencyIndexes: file_gamecontroller_ssl_gc_geometry_proto_depIdxs,
+ MessageInfos: file_gamecontroller_ssl_gc_geometry_proto_msgTypes,
+ }.Build()
+ File_gamecontroller_ssl_gc_geometry_proto = out.File
+ file_gamecontroller_ssl_gc_geometry_proto_goTypes = nil
+ file_gamecontroller_ssl_gc_geometry_proto_depIdxs = nil
+}
diff --git a/gui/internal/gamecontroller/ssl_gc_rcon.pb.go b/gui/internal/gamecontroller/ssl_gc_rcon.pb.go
new file mode 100644
index 0000000..4db9744
--- /dev/null
+++ b/gui/internal/gamecontroller/ssl_gc_rcon.pb.go
@@ -0,0 +1,352 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.36.6
+// protoc (unknown)
+// source: gamecontroller/ssl_gc_rcon.proto
+
+package gamecontroller
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+ unsafe "unsafe"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type ControllerReply_StatusCode int32
+
+const (
+ ControllerReply_UNKNOWN_STATUS_CODE ControllerReply_StatusCode = 0
+ ControllerReply_OK ControllerReply_StatusCode = 1
+ ControllerReply_REJECTED ControllerReply_StatusCode = 2
+)
+
+// Enum value maps for ControllerReply_StatusCode.
+var (
+ ControllerReply_StatusCode_name = map[int32]string{
+ 0: "UNKNOWN_STATUS_CODE",
+ 1: "OK",
+ 2: "REJECTED",
+ }
+ ControllerReply_StatusCode_value = map[string]int32{
+ "UNKNOWN_STATUS_CODE": 0,
+ "OK": 1,
+ "REJECTED": 2,
+ }
+)
+
+func (x ControllerReply_StatusCode) Enum() *ControllerReply_StatusCode {
+ p := new(ControllerReply_StatusCode)
+ *p = x
+ return p
+}
+
+func (x ControllerReply_StatusCode) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (ControllerReply_StatusCode) Descriptor() protoreflect.EnumDescriptor {
+ return file_gamecontroller_ssl_gc_rcon_proto_enumTypes[0].Descriptor()
+}
+
+func (ControllerReply_StatusCode) Type() protoreflect.EnumType {
+ return &file_gamecontroller_ssl_gc_rcon_proto_enumTypes[0]
+}
+
+func (x ControllerReply_StatusCode) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *ControllerReply_StatusCode) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = ControllerReply_StatusCode(num)
+ return nil
+}
+
+// Deprecated: Use ControllerReply_StatusCode.Descriptor instead.
+func (ControllerReply_StatusCode) EnumDescriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_rcon_proto_rawDescGZIP(), []int{0, 0}
+}
+
+type ControllerReply_Verification int32
+
+const (
+ ControllerReply_UNKNOWN_VERIFICATION ControllerReply_Verification = 0
+ ControllerReply_VERIFIED ControllerReply_Verification = 1
+ ControllerReply_UNVERIFIED ControllerReply_Verification = 2
+)
+
+// Enum value maps for ControllerReply_Verification.
+var (
+ ControllerReply_Verification_name = map[int32]string{
+ 0: "UNKNOWN_VERIFICATION",
+ 1: "VERIFIED",
+ 2: "UNVERIFIED",
+ }
+ ControllerReply_Verification_value = map[string]int32{
+ "UNKNOWN_VERIFICATION": 0,
+ "VERIFIED": 1,
+ "UNVERIFIED": 2,
+ }
+)
+
+func (x ControllerReply_Verification) Enum() *ControllerReply_Verification {
+ p := new(ControllerReply_Verification)
+ *p = x
+ return p
+}
+
+func (x ControllerReply_Verification) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (ControllerReply_Verification) Descriptor() protoreflect.EnumDescriptor {
+ return file_gamecontroller_ssl_gc_rcon_proto_enumTypes[1].Descriptor()
+}
+
+func (ControllerReply_Verification) Type() protoreflect.EnumType {
+ return &file_gamecontroller_ssl_gc_rcon_proto_enumTypes[1]
+}
+
+func (x ControllerReply_Verification) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *ControllerReply_Verification) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = ControllerReply_Verification(num)
+ return nil
+}
+
+// Deprecated: Use ControllerReply_Verification.Descriptor instead.
+func (ControllerReply_Verification) EnumDescriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_rcon_proto_rawDescGZIP(), []int{0, 1}
+}
+
+// a reply that is sent by the controller for each request from teams or autoRefs
+type ControllerReply struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // status_code is an optional code that indicates the result of the last request
+ StatusCode *ControllerReply_StatusCode `protobuf:"varint,1,opt,name=status_code,json=statusCode,enum=ControllerReply_StatusCode" json:"status_code,omitempty"`
+ // reason is an optional explanation of the status code
+ Reason *string `protobuf:"bytes,2,opt,name=reason" json:"reason,omitempty"`
+ // next_token must be send with the next request, if secure communication is used
+ // the token is used to avoid replay attacks
+ // the token is always present in the very first message before the registration starts
+ // the token is not present, if secure communication is not used
+ NextToken *string `protobuf:"bytes,3,opt,name=next_token,json=nextToken" json:"next_token,omitempty"`
+ // verification indicates if the last request could be verified (secure communication)
+ Verification *ControllerReply_Verification `protobuf:"varint,4,opt,name=verification,enum=ControllerReply_Verification" json:"verification,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ControllerReply) Reset() {
+ *x = ControllerReply{}
+ mi := &file_gamecontroller_ssl_gc_rcon_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ControllerReply) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ControllerReply) ProtoMessage() {}
+
+func (x *ControllerReply) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_rcon_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ControllerReply.ProtoReflect.Descriptor instead.
+func (*ControllerReply) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_rcon_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *ControllerReply) GetStatusCode() ControllerReply_StatusCode {
+ if x != nil && x.StatusCode != nil {
+ return *x.StatusCode
+ }
+ return ControllerReply_UNKNOWN_STATUS_CODE
+}
+
+func (x *ControllerReply) GetReason() string {
+ if x != nil && x.Reason != nil {
+ return *x.Reason
+ }
+ return ""
+}
+
+func (x *ControllerReply) GetNextToken() string {
+ if x != nil && x.NextToken != nil {
+ return *x.NextToken
+ }
+ return ""
+}
+
+func (x *ControllerReply) GetVerification() ControllerReply_Verification {
+ if x != nil && x.Verification != nil {
+ return *x.Verification
+ }
+ return ControllerReply_UNKNOWN_VERIFICATION
+}
+
+// Signature can be added to a request to let it be verfied by the controller
+type Signature struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the token that was received with the last controller reply
+ Token *string `protobuf:"bytes,1,req,name=token" json:"token,omitempty"`
+ // the PKCS1v15 signature of this message
+ Pkcs1V15 []byte `protobuf:"bytes,2,req,name=pkcs1v15" json:"pkcs1v15,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *Signature) Reset() {
+ *x = Signature{}
+ mi := &file_gamecontroller_ssl_gc_rcon_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *Signature) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Signature) ProtoMessage() {}
+
+func (x *Signature) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_rcon_proto_msgTypes[1]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Signature.ProtoReflect.Descriptor instead.
+func (*Signature) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_rcon_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *Signature) GetToken() string {
+ if x != nil && x.Token != nil {
+ return *x.Token
+ }
+ return ""
+}
+
+func (x *Signature) GetPkcs1V15() []byte {
+ if x != nil {
+ return x.Pkcs1V15
+ }
+ return nil
+}
+
+var File_gamecontroller_ssl_gc_rcon_proto protoreflect.FileDescriptor
+
+const file_gamecontroller_ssl_gc_rcon_proto_rawDesc = "" +
+ "\n" +
+ " gamecontroller/ssl_gc_rcon.proto\"\xce\x02\n" +
+ "\x0fControllerReply\x12<\n" +
+ "\vstatus_code\x18\x01 \x01(\x0e2\x1b.ControllerReply.StatusCodeR\n" +
+ "statusCode\x12\x16\n" +
+ "\x06reason\x18\x02 \x01(\tR\x06reason\x12\x1d\n" +
+ "\n" +
+ "next_token\x18\x03 \x01(\tR\tnextToken\x12A\n" +
+ "\fverification\x18\x04 \x01(\x0e2\x1d.ControllerReply.VerificationR\fverification\";\n" +
+ "\n" +
+ "StatusCode\x12\x17\n" +
+ "\x13UNKNOWN_STATUS_CODE\x10\x00\x12\x06\n" +
+ "\x02OK\x10\x01\x12\f\n" +
+ "\bREJECTED\x10\x02\"F\n" +
+ "\fVerification\x12\x18\n" +
+ "\x14UNKNOWN_VERIFICATION\x10\x00\x12\f\n" +
+ "\bVERIFIED\x10\x01\x12\x0e\n" +
+ "\n" +
+ "UNVERIFIED\x10\x02\"=\n" +
+ "\tSignature\x12\x14\n" +
+ "\x05token\x18\x01 \x02(\tR\x05token\x12\x1a\n" +
+ "\bpkcs1v15\x18\x02 \x02(\fR\bpkcs1v15B[B\x0eSslGcRconProtoP\x01ZGgithub.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
+
+var (
+ file_gamecontroller_ssl_gc_rcon_proto_rawDescOnce sync.Once
+ file_gamecontroller_ssl_gc_rcon_proto_rawDescData []byte
+)
+
+func file_gamecontroller_ssl_gc_rcon_proto_rawDescGZIP() []byte {
+ file_gamecontroller_ssl_gc_rcon_proto_rawDescOnce.Do(func() {
+ file_gamecontroller_ssl_gc_rcon_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_rcon_proto_rawDesc), len(file_gamecontroller_ssl_gc_rcon_proto_rawDesc)))
+ })
+ return file_gamecontroller_ssl_gc_rcon_proto_rawDescData
+}
+
+var file_gamecontroller_ssl_gc_rcon_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
+var file_gamecontroller_ssl_gc_rcon_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_gamecontroller_ssl_gc_rcon_proto_goTypes = []any{
+ (ControllerReply_StatusCode)(0), // 0: ControllerReply.StatusCode
+ (ControllerReply_Verification)(0), // 1: ControllerReply.Verification
+ (*ControllerReply)(nil), // 2: ControllerReply
+ (*Signature)(nil), // 3: Signature
+}
+var file_gamecontroller_ssl_gc_rcon_proto_depIdxs = []int32{
+ 0, // 0: ControllerReply.status_code:type_name -> ControllerReply.StatusCode
+ 1, // 1: ControllerReply.verification:type_name -> ControllerReply.Verification
+ 2, // [2:2] is the sub-list for method output_type
+ 2, // [2:2] is the sub-list for method input_type
+ 2, // [2:2] is the sub-list for extension type_name
+ 2, // [2:2] is the sub-list for extension extendee
+ 0, // [0:2] is the sub-list for field type_name
+}
+
+func init() { file_gamecontroller_ssl_gc_rcon_proto_init() }
+func file_gamecontroller_ssl_gc_rcon_proto_init() {
+ if File_gamecontroller_ssl_gc_rcon_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_rcon_proto_rawDesc), len(file_gamecontroller_ssl_gc_rcon_proto_rawDesc)),
+ NumEnums: 2,
+ NumMessages: 2,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_gamecontroller_ssl_gc_rcon_proto_goTypes,
+ DependencyIndexes: file_gamecontroller_ssl_gc_rcon_proto_depIdxs,
+ EnumInfos: file_gamecontroller_ssl_gc_rcon_proto_enumTypes,
+ MessageInfos: file_gamecontroller_ssl_gc_rcon_proto_msgTypes,
+ }.Build()
+ File_gamecontroller_ssl_gc_rcon_proto = out.File
+ file_gamecontroller_ssl_gc_rcon_proto_goTypes = nil
+ file_gamecontroller_ssl_gc_rcon_proto_depIdxs = nil
+}
diff --git a/gui/internal/gamecontroller/ssl_gc_rcon_autoref.pb.go b/gui/internal/gamecontroller/ssl_gc_rcon_autoref.pb.go
new file mode 100644
index 0000000..8a0ed95
--- /dev/null
+++ b/gui/internal/gamecontroller/ssl_gc_rcon_autoref.pb.go
@@ -0,0 +1,283 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.36.6
+// protoc (unknown)
+// source: gamecontroller/ssl_gc_rcon_autoref.proto
+
+package gamecontroller
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+ unsafe "unsafe"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// AutoRefRegistration is the first message that a client must send to the controller to identify itself
+type AutoRefRegistration struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // identifier is a unique name of the client
+ Identifier *string `protobuf:"bytes,1,req,name=identifier" json:"identifier,omitempty"`
+ // signature can optionally be specified to enable secure communication
+ Signature *Signature `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *AutoRefRegistration) Reset() {
+ *x = AutoRefRegistration{}
+ mi := &file_gamecontroller_ssl_gc_rcon_autoref_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *AutoRefRegistration) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AutoRefRegistration) ProtoMessage() {}
+
+func (x *AutoRefRegistration) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_rcon_autoref_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use AutoRefRegistration.ProtoReflect.Descriptor instead.
+func (*AutoRefRegistration) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *AutoRefRegistration) GetIdentifier() string {
+ if x != nil && x.Identifier != nil {
+ return *x.Identifier
+ }
+ return ""
+}
+
+func (x *AutoRefRegistration) GetSignature() *Signature {
+ if x != nil {
+ return x.Signature
+ }
+ return nil
+}
+
+// AutoRefToController is the wrapper message for all subsequent messages from the autoRef to the controller
+type AutoRefToController struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // signature can optionally be specified to enable secure communication
+ Signature *Signature `protobuf:"bytes,1,opt,name=signature" json:"signature,omitempty"`
+ // game_event is an optional event that the autoRef detected during the game
+ GameEvent *GameEvent `protobuf:"bytes,2,opt,name=game_event,json=gameEvent" json:"game_event,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *AutoRefToController) Reset() {
+ *x = AutoRefToController{}
+ mi := &file_gamecontroller_ssl_gc_rcon_autoref_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *AutoRefToController) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AutoRefToController) ProtoMessage() {}
+
+func (x *AutoRefToController) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_rcon_autoref_proto_msgTypes[1]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use AutoRefToController.ProtoReflect.Descriptor instead.
+func (*AutoRefToController) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *AutoRefToController) GetSignature() *Signature {
+ if x != nil {
+ return x.Signature
+ }
+ return nil
+}
+
+func (x *AutoRefToController) GetGameEvent() *GameEvent {
+ if x != nil {
+ return x.GameEvent
+ }
+ return nil
+}
+
+// ControllerToAutoRef is the wrapper message for all messages from controller to autoRef
+type ControllerToAutoRef struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Types that are valid to be assigned to Msg:
+ //
+ // *ControllerToAutoRef_ControllerReply
+ Msg isControllerToAutoRef_Msg `protobuf_oneof:"msg"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ControllerToAutoRef) Reset() {
+ *x = ControllerToAutoRef{}
+ mi := &file_gamecontroller_ssl_gc_rcon_autoref_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ControllerToAutoRef) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ControllerToAutoRef) ProtoMessage() {}
+
+func (x *ControllerToAutoRef) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_rcon_autoref_proto_msgTypes[2]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ControllerToAutoRef.ProtoReflect.Descriptor instead.
+func (*ControllerToAutoRef) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ControllerToAutoRef) GetMsg() isControllerToAutoRef_Msg {
+ if x != nil {
+ return x.Msg
+ }
+ return nil
+}
+
+func (x *ControllerToAutoRef) GetControllerReply() *ControllerReply {
+ if x != nil {
+ if x, ok := x.Msg.(*ControllerToAutoRef_ControllerReply); ok {
+ return x.ControllerReply
+ }
+ }
+ return nil
+}
+
+type isControllerToAutoRef_Msg interface {
+ isControllerToAutoRef_Msg()
+}
+
+type ControllerToAutoRef_ControllerReply struct {
+ // a reply from the controller
+ ControllerReply *ControllerReply `protobuf:"bytes,1,opt,name=controller_reply,json=controllerReply,oneof"`
+}
+
+func (*ControllerToAutoRef_ControllerReply) isControllerToAutoRef_Msg() {}
+
+var File_gamecontroller_ssl_gc_rcon_autoref_proto protoreflect.FileDescriptor
+
+const file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDesc = "" +
+ "\n" +
+ "(gamecontroller/ssl_gc_rcon_autoref.proto\x1a&gamecontroller/ssl_gc_game_event.proto\x1a gamecontroller/ssl_gc_rcon.proto\"_\n" +
+ "\x13AutoRefRegistration\x12\x1e\n" +
+ "\n" +
+ "identifier\x18\x01 \x02(\tR\n" +
+ "identifier\x12(\n" +
+ "\tsignature\x18\x02 \x01(\v2\n" +
+ ".SignatureR\tsignature\"v\n" +
+ "\x13AutoRefToController\x12(\n" +
+ "\tsignature\x18\x01 \x01(\v2\n" +
+ ".SignatureR\tsignature\x12)\n" +
+ "\n" +
+ "game_event\x18\x02 \x01(\v2\n" +
+ ".GameEventR\tgameEventJ\x04\b\x03\x10\x04J\x04\b\x04\x10\x05\"[\n" +
+ "\x13ControllerToAutoRef\x12=\n" +
+ "\x10controller_reply\x18\x01 \x01(\v2\x10.ControllerReplyH\x00R\x0fcontrollerReplyB\x05\n" +
+ "\x03msgBbB\x15SslGcRconAutorefProtoP\x01ZGgithub.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
+
+var (
+ file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDescOnce sync.Once
+ file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDescData []byte
+)
+
+func file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDescGZIP() []byte {
+ file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDescOnce.Do(func() {
+ file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDesc), len(file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDesc)))
+ })
+ return file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDescData
+}
+
+var file_gamecontroller_ssl_gc_rcon_autoref_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
+var file_gamecontroller_ssl_gc_rcon_autoref_proto_goTypes = []any{
+ (*AutoRefRegistration)(nil), // 0: AutoRefRegistration
+ (*AutoRefToController)(nil), // 1: AutoRefToController
+ (*ControllerToAutoRef)(nil), // 2: ControllerToAutoRef
+ (*Signature)(nil), // 3: Signature
+ (*GameEvent)(nil), // 4: GameEvent
+ (*ControllerReply)(nil), // 5: ControllerReply
+}
+var file_gamecontroller_ssl_gc_rcon_autoref_proto_depIdxs = []int32{
+ 3, // 0: AutoRefRegistration.signature:type_name -> Signature
+ 3, // 1: AutoRefToController.signature:type_name -> Signature
+ 4, // 2: AutoRefToController.game_event:type_name -> GameEvent
+ 5, // 3: ControllerToAutoRef.controller_reply:type_name -> ControllerReply
+ 4, // [4:4] is the sub-list for method output_type
+ 4, // [4:4] is the sub-list for method input_type
+ 4, // [4:4] is the sub-list for extension type_name
+ 4, // [4:4] is the sub-list for extension extendee
+ 0, // [0:4] is the sub-list for field type_name
+}
+
+func init() { file_gamecontroller_ssl_gc_rcon_autoref_proto_init() }
+func file_gamecontroller_ssl_gc_rcon_autoref_proto_init() {
+ if File_gamecontroller_ssl_gc_rcon_autoref_proto != nil {
+ return
+ }
+ file_gamecontroller_ssl_gc_game_event_proto_init()
+ file_gamecontroller_ssl_gc_rcon_proto_init()
+ file_gamecontroller_ssl_gc_rcon_autoref_proto_msgTypes[2].OneofWrappers = []any{
+ (*ControllerToAutoRef_ControllerReply)(nil),
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDesc), len(file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDesc)),
+ NumEnums: 0,
+ NumMessages: 3,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_gamecontroller_ssl_gc_rcon_autoref_proto_goTypes,
+ DependencyIndexes: file_gamecontroller_ssl_gc_rcon_autoref_proto_depIdxs,
+ MessageInfos: file_gamecontroller_ssl_gc_rcon_autoref_proto_msgTypes,
+ }.Build()
+ File_gamecontroller_ssl_gc_rcon_autoref_proto = out.File
+ file_gamecontroller_ssl_gc_rcon_autoref_proto_goTypes = nil
+ file_gamecontroller_ssl_gc_rcon_autoref_proto_depIdxs = nil
+}
diff --git a/gui/internal/gamecontroller/ssl_gc_rcon_remotecontrol.pb.go b/gui/internal/gamecontroller/ssl_gc_rcon_remotecontrol.pb.go
new file mode 100644
index 0000000..9d7a3ff
--- /dev/null
+++ b/gui/internal/gamecontroller/ssl_gc_rcon_remotecontrol.pb.go
@@ -0,0 +1,718 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.36.6
+// protoc (unknown)
+// source: gamecontroller/ssl_gc_rcon_remotecontrol.proto
+
+package gamecontroller
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+ unsafe "unsafe"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// All possible request types that the remote control can make
+type RemoteControlRequestType int32
+
+const (
+ RemoteControlRequestType_UNKNOWN_REQUEST_TYPE RemoteControlRequestType = 0
+ RemoteControlRequestType_EMERGENCY_STOP RemoteControlRequestType = 1
+ RemoteControlRequestType_ROBOT_SUBSTITUTION RemoteControlRequestType = 2
+ RemoteControlRequestType_TIMEOUT RemoteControlRequestType = 3
+ RemoteControlRequestType_CHALLENGE_FLAG RemoteControlRequestType = 4
+ RemoteControlRequestType_CHANGE_KEEPER_ID RemoteControlRequestType = 5
+ RemoteControlRequestType_STOP_TIMEOUT RemoteControlRequestType = 6
+ RemoteControlRequestType_FAIL_BALLPLACEMENT RemoteControlRequestType = 7
+)
+
+// Enum value maps for RemoteControlRequestType.
+var (
+ RemoteControlRequestType_name = map[int32]string{
+ 0: "UNKNOWN_REQUEST_TYPE",
+ 1: "EMERGENCY_STOP",
+ 2: "ROBOT_SUBSTITUTION",
+ 3: "TIMEOUT",
+ 4: "CHALLENGE_FLAG",
+ 5: "CHANGE_KEEPER_ID",
+ 6: "STOP_TIMEOUT",
+ 7: "FAIL_BALLPLACEMENT",
+ }
+ RemoteControlRequestType_value = map[string]int32{
+ "UNKNOWN_REQUEST_TYPE": 0,
+ "EMERGENCY_STOP": 1,
+ "ROBOT_SUBSTITUTION": 2,
+ "TIMEOUT": 3,
+ "CHALLENGE_FLAG": 4,
+ "CHANGE_KEEPER_ID": 5,
+ "STOP_TIMEOUT": 6,
+ "FAIL_BALLPLACEMENT": 7,
+ }
+)
+
+func (x RemoteControlRequestType) Enum() *RemoteControlRequestType {
+ p := new(RemoteControlRequestType)
+ *p = x
+ return p
+}
+
+func (x RemoteControlRequestType) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (RemoteControlRequestType) Descriptor() protoreflect.EnumDescriptor {
+ return file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_enumTypes[0].Descriptor()
+}
+
+func (RemoteControlRequestType) Type() protoreflect.EnumType {
+ return &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_enumTypes[0]
+}
+
+func (x RemoteControlRequestType) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *RemoteControlRequestType) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = RemoteControlRequestType(num)
+ return nil
+}
+
+// Deprecated: Use RemoteControlRequestType.Descriptor instead.
+func (RemoteControlRequestType) EnumDescriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescGZIP(), []int{0}
+}
+
+type RemoteControlToController_Request int32
+
+const (
+ RemoteControlToController_UNKNOWN RemoteControlToController_Request = 0
+ // Ping the GC to test the connection. The GC will respond with OK and the current team state
+ RemoteControlToController_PING RemoteControlToController_Request = 1
+ // Raise a challenge flag (this is not revocable)
+ RemoteControlToController_CHALLENGE_FLAG RemoteControlToController_Request = 2
+ // Stop an ongoing timeout
+ RemoteControlToController_STOP_TIMEOUT RemoteControlToController_Request = 3
+ // Fail a ball placement
+ RemoteControlToController_FAIL_BALLPLACEMENT RemoteControlToController_Request = 4
+)
+
+// Enum value maps for RemoteControlToController_Request.
+var (
+ RemoteControlToController_Request_name = map[int32]string{
+ 0: "UNKNOWN",
+ 1: "PING",
+ 2: "CHALLENGE_FLAG",
+ 3: "STOP_TIMEOUT",
+ 4: "FAIL_BALLPLACEMENT",
+ }
+ RemoteControlToController_Request_value = map[string]int32{
+ "UNKNOWN": 0,
+ "PING": 1,
+ "CHALLENGE_FLAG": 2,
+ "STOP_TIMEOUT": 3,
+ "FAIL_BALLPLACEMENT": 4,
+ }
+)
+
+func (x RemoteControlToController_Request) Enum() *RemoteControlToController_Request {
+ p := new(RemoteControlToController_Request)
+ *p = x
+ return p
+}
+
+func (x RemoteControlToController_Request) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (RemoteControlToController_Request) Descriptor() protoreflect.EnumDescriptor {
+ return file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_enumTypes[1].Descriptor()
+}
+
+func (RemoteControlToController_Request) Type() protoreflect.EnumType {
+ return &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_enumTypes[1]
+}
+
+func (x RemoteControlToController_Request) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *RemoteControlToController_Request) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = RemoteControlToController_Request(num)
+ return nil
+}
+
+// Deprecated: Use RemoteControlToController_Request.Descriptor instead.
+func (RemoteControlToController_Request) EnumDescriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescGZIP(), []int{1, 0}
+}
+
+// a registration that must be send by the remote control to the controller as the very first message
+type RemoteControlRegistration struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team to be controlled
+ Team *Team `protobuf:"varint,1,req,name=team,enum=Team" json:"team,omitempty"`
+ // signature can optionally be specified to enable secure communication
+ Signature *Signature `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RemoteControlRegistration) Reset() {
+ *x = RemoteControlRegistration{}
+ mi := &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RemoteControlRegistration) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RemoteControlRegistration) ProtoMessage() {}
+
+func (x *RemoteControlRegistration) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RemoteControlRegistration.ProtoReflect.Descriptor instead.
+func (*RemoteControlRegistration) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *RemoteControlRegistration) GetTeam() Team {
+ if x != nil && x.Team != nil {
+ return *x.Team
+ }
+ return Team_UNKNOWN
+}
+
+func (x *RemoteControlRegistration) GetSignature() *Signature {
+ if x != nil {
+ return x.Signature
+ }
+ return nil
+}
+
+// wrapper for all messages from the remote control to the controller
+type RemoteControlToController struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // signature can optionally be specified to enable secure communication
+ Signature *Signature `protobuf:"bytes,1,opt,name=signature" json:"signature,omitempty"`
+ // Types that are valid to be assigned to Msg:
+ //
+ // *RemoteControlToController_Request_
+ // *RemoteControlToController_DesiredKeeper
+ // *RemoteControlToController_RequestRobotSubstitution
+ // *RemoteControlToController_RequestTimeout
+ // *RemoteControlToController_RequestEmergencyStop
+ Msg isRemoteControlToController_Msg `protobuf_oneof:"msg"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RemoteControlToController) Reset() {
+ *x = RemoteControlToController{}
+ mi := &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RemoteControlToController) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RemoteControlToController) ProtoMessage() {}
+
+func (x *RemoteControlToController) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes[1]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RemoteControlToController.ProtoReflect.Descriptor instead.
+func (*RemoteControlToController) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *RemoteControlToController) GetSignature() *Signature {
+ if x != nil {
+ return x.Signature
+ }
+ return nil
+}
+
+func (x *RemoteControlToController) GetMsg() isRemoteControlToController_Msg {
+ if x != nil {
+ return x.Msg
+ }
+ return nil
+}
+
+func (x *RemoteControlToController) GetRequest() RemoteControlToController_Request {
+ if x != nil {
+ if x, ok := x.Msg.(*RemoteControlToController_Request_); ok {
+ return x.Request
+ }
+ }
+ return RemoteControlToController_UNKNOWN
+}
+
+func (x *RemoteControlToController) GetDesiredKeeper() int32 {
+ if x != nil {
+ if x, ok := x.Msg.(*RemoteControlToController_DesiredKeeper); ok {
+ return x.DesiredKeeper
+ }
+ }
+ return 0
+}
+
+func (x *RemoteControlToController) GetRequestRobotSubstitution() bool {
+ if x != nil {
+ if x, ok := x.Msg.(*RemoteControlToController_RequestRobotSubstitution); ok {
+ return x.RequestRobotSubstitution
+ }
+ }
+ return false
+}
+
+func (x *RemoteControlToController) GetRequestTimeout() bool {
+ if x != nil {
+ if x, ok := x.Msg.(*RemoteControlToController_RequestTimeout); ok {
+ return x.RequestTimeout
+ }
+ }
+ return false
+}
+
+func (x *RemoteControlToController) GetRequestEmergencyStop() bool {
+ if x != nil {
+ if x, ok := x.Msg.(*RemoteControlToController_RequestEmergencyStop); ok {
+ return x.RequestEmergencyStop
+ }
+ }
+ return false
+}
+
+type isRemoteControlToController_Msg interface {
+ isRemoteControlToController_Msg()
+}
+
+type RemoteControlToController_Request_ struct {
+ // send a request to the GC
+ Request RemoteControlToController_Request `protobuf:"varint,2,opt,name=request,enum=RemoteControlToController_Request,oneof"`
+}
+
+type RemoteControlToController_DesiredKeeper struct {
+ // request a new desired keeper id
+ DesiredKeeper int32 `protobuf:"varint,3,opt,name=desired_keeper,json=desiredKeeper,oneof"`
+}
+
+type RemoteControlToController_RequestRobotSubstitution struct {
+ // true: request to substitute a robot at the next possibility
+ // false: cancel request
+ RequestRobotSubstitution bool `protobuf:"varint,4,opt,name=request_robot_substitution,json=requestRobotSubstitution,oneof"`
+}
+
+type RemoteControlToController_RequestTimeout struct {
+ // true: request a timeout with the next stoppage
+ // false: cancel the request
+ RequestTimeout bool `protobuf:"varint,5,opt,name=request_timeout,json=requestTimeout,oneof"`
+}
+
+type RemoteControlToController_RequestEmergencyStop struct {
+ // true: initiate an emergency stop
+ // false: cancel the request
+ RequestEmergencyStop bool `protobuf:"varint,6,opt,name=request_emergency_stop,json=requestEmergencyStop,oneof"`
+}
+
+func (*RemoteControlToController_Request_) isRemoteControlToController_Msg() {}
+
+func (*RemoteControlToController_DesiredKeeper) isRemoteControlToController_Msg() {}
+
+func (*RemoteControlToController_RequestRobotSubstitution) isRemoteControlToController_Msg() {}
+
+func (*RemoteControlToController_RequestTimeout) isRemoteControlToController_Msg() {}
+
+func (*RemoteControlToController_RequestEmergencyStop) isRemoteControlToController_Msg() {}
+
+// wrapper for all messages from controller to a team's computer
+type ControllerToRemoteControl struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // a reply from the controller
+ ControllerReply *ControllerReply `protobuf:"bytes,1,opt,name=controller_reply,json=controllerReply" json:"controller_reply,omitempty"`
+ // current team state
+ State *RemoteControlTeamState `protobuf:"bytes,2,opt,name=state" json:"state,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ControllerToRemoteControl) Reset() {
+ *x = ControllerToRemoteControl{}
+ mi := &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ControllerToRemoteControl) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ControllerToRemoteControl) ProtoMessage() {}
+
+func (x *ControllerToRemoteControl) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes[2]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ControllerToRemoteControl.ProtoReflect.Descriptor instead.
+func (*ControllerToRemoteControl) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ControllerToRemoteControl) GetControllerReply() *ControllerReply {
+ if x != nil {
+ return x.ControllerReply
+ }
+ return nil
+}
+
+func (x *ControllerToRemoteControl) GetState() *RemoteControlTeamState {
+ if x != nil {
+ return x.State
+ }
+ return nil
+}
+
+// Current team state from Controller for remote control
+type RemoteControlTeamState struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the team that is controlled
+ Team *Team `protobuf:"varint,12,opt,name=team,enum=Team" json:"team,omitempty"`
+ // list of all currently available request types that can be made
+ AvailableRequests []RemoteControlRequestType `protobuf:"varint,1,rep,name=available_requests,json=availableRequests,enum=RemoteControlRequestType" json:"available_requests,omitempty"`
+ // list of all currently active request types that are pending
+ ActiveRequests []RemoteControlRequestType `protobuf:"varint,2,rep,name=active_requests,json=activeRequests,enum=RemoteControlRequestType" json:"active_requests,omitempty"`
+ // currently set keeper id
+ KeeperId *int32 `protobuf:"varint,3,opt,name=keeper_id,json=keeperId" json:"keeper_id,omitempty"`
+ // number of seconds till emergency stop is executed
+ // zero, if no emergency stop requested
+ EmergencyStopIn *float32 `protobuf:"fixed32,4,opt,name=emergency_stop_in,json=emergencyStopIn" json:"emergency_stop_in,omitempty"`
+ // number of timeouts left for the team
+ TimeoutsLeft *int32 `protobuf:"varint,5,opt,name=timeouts_left,json=timeoutsLeft" json:"timeouts_left,omitempty"`
+ // number of seconds left for timeout for the team
+ TimeoutTimeLeft *float32 `protobuf:"fixed32,10,opt,name=timeout_time_left,json=timeoutTimeLeft" json:"timeout_time_left,omitempty"`
+ // number of challenge flags left for the team
+ ChallengeFlagsLeft *int32 `protobuf:"varint,6,opt,name=challenge_flags_left,json=challengeFlagsLeft" json:"challenge_flags_left,omitempty"`
+ // max number of robots currently allowed
+ MaxRobots *int32 `protobuf:"varint,7,opt,name=max_robots,json=maxRobots" json:"max_robots,omitempty"`
+ // current number of robots visible on field
+ RobotsOnField *int32 `protobuf:"varint,9,opt,name=robots_on_field,json=robotsOnField" json:"robots_on_field,omitempty"`
+ // list of due times for each active yellow card (in seconds)
+ YellowCardsDue []float32 `protobuf:"fixed32,8,rep,name=yellow_cards_due,json=yellowCardsDue" json:"yellow_cards_due,omitempty"`
+ // if true, team is allowed to substitute robots
+ CanSubstituteRobot *bool `protobuf:"varint,11,opt,name=can_substitute_robot,json=canSubstituteRobot" json:"can_substitute_robot,omitempty"`
+ // number of bot substitutions left by the team in this halftime
+ BotSubstitutionsLeft *uint32 `protobuf:"varint,13,opt,name=bot_substitutions_left,json=botSubstitutionsLeft" json:"bot_substitutions_left,omitempty"`
+ // number of seconds left for current bot substitution
+ BotSubstitutionTimeLeft *float32 `protobuf:"fixed32,14,opt,name=bot_substitution_time_left,json=botSubstitutionTimeLeft" json:"bot_substitution_time_left,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RemoteControlTeamState) Reset() {
+ *x = RemoteControlTeamState{}
+ mi := &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RemoteControlTeamState) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RemoteControlTeamState) ProtoMessage() {}
+
+func (x *RemoteControlTeamState) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes[3]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RemoteControlTeamState.ProtoReflect.Descriptor instead.
+func (*RemoteControlTeamState) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *RemoteControlTeamState) GetTeam() Team {
+ if x != nil && x.Team != nil {
+ return *x.Team
+ }
+ return Team_UNKNOWN
+}
+
+func (x *RemoteControlTeamState) GetAvailableRequests() []RemoteControlRequestType {
+ if x != nil {
+ return x.AvailableRequests
+ }
+ return nil
+}
+
+func (x *RemoteControlTeamState) GetActiveRequests() []RemoteControlRequestType {
+ if x != nil {
+ return x.ActiveRequests
+ }
+ return nil
+}
+
+func (x *RemoteControlTeamState) GetKeeperId() int32 {
+ if x != nil && x.KeeperId != nil {
+ return *x.KeeperId
+ }
+ return 0
+}
+
+func (x *RemoteControlTeamState) GetEmergencyStopIn() float32 {
+ if x != nil && x.EmergencyStopIn != nil {
+ return *x.EmergencyStopIn
+ }
+ return 0
+}
+
+func (x *RemoteControlTeamState) GetTimeoutsLeft() int32 {
+ if x != nil && x.TimeoutsLeft != nil {
+ return *x.TimeoutsLeft
+ }
+ return 0
+}
+
+func (x *RemoteControlTeamState) GetTimeoutTimeLeft() float32 {
+ if x != nil && x.TimeoutTimeLeft != nil {
+ return *x.TimeoutTimeLeft
+ }
+ return 0
+}
+
+func (x *RemoteControlTeamState) GetChallengeFlagsLeft() int32 {
+ if x != nil && x.ChallengeFlagsLeft != nil {
+ return *x.ChallengeFlagsLeft
+ }
+ return 0
+}
+
+func (x *RemoteControlTeamState) GetMaxRobots() int32 {
+ if x != nil && x.MaxRobots != nil {
+ return *x.MaxRobots
+ }
+ return 0
+}
+
+func (x *RemoteControlTeamState) GetRobotsOnField() int32 {
+ if x != nil && x.RobotsOnField != nil {
+ return *x.RobotsOnField
+ }
+ return 0
+}
+
+func (x *RemoteControlTeamState) GetYellowCardsDue() []float32 {
+ if x != nil {
+ return x.YellowCardsDue
+ }
+ return nil
+}
+
+func (x *RemoteControlTeamState) GetCanSubstituteRobot() bool {
+ if x != nil && x.CanSubstituteRobot != nil {
+ return *x.CanSubstituteRobot
+ }
+ return false
+}
+
+func (x *RemoteControlTeamState) GetBotSubstitutionsLeft() uint32 {
+ if x != nil && x.BotSubstitutionsLeft != nil {
+ return *x.BotSubstitutionsLeft
+ }
+ return 0
+}
+
+func (x *RemoteControlTeamState) GetBotSubstitutionTimeLeft() float32 {
+ if x != nil && x.BotSubstitutionTimeLeft != nil {
+ return *x.BotSubstitutionTimeLeft
+ }
+ return 0
+}
+
+var File_gamecontroller_ssl_gc_rcon_remotecontrol_proto protoreflect.FileDescriptor
+
+const file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDesc = "" +
+ "\n" +
+ ".gamecontroller/ssl_gc_rcon_remotecontrol.proto\x1a\"gamecontroller/ssl_gc_common.proto\x1a gamecontroller/ssl_gc_rcon.proto\"`\n" +
+ "\x19RemoteControlRegistration\x12\x19\n" +
+ "\x04team\x18\x01 \x02(\x0e2\x05.TeamR\x04team\x12(\n" +
+ "\tsignature\x18\x02 \x01(\v2\n" +
+ ".SignatureR\tsignature\"\xb8\x03\n" +
+ "\x19RemoteControlToController\x12(\n" +
+ "\tsignature\x18\x01 \x01(\v2\n" +
+ ".SignatureR\tsignature\x12>\n" +
+ "\arequest\x18\x02 \x01(\x0e2\".RemoteControlToController.RequestH\x00R\arequest\x12'\n" +
+ "\x0edesired_keeper\x18\x03 \x01(\x05H\x00R\rdesiredKeeper\x12>\n" +
+ "\x1arequest_robot_substitution\x18\x04 \x01(\bH\x00R\x18requestRobotSubstitution\x12)\n" +
+ "\x0frequest_timeout\x18\x05 \x01(\bH\x00R\x0erequestTimeout\x126\n" +
+ "\x16request_emergency_stop\x18\x06 \x01(\bH\x00R\x14requestEmergencyStop\"^\n" +
+ "\aRequest\x12\v\n" +
+ "\aUNKNOWN\x10\x00\x12\b\n" +
+ "\x04PING\x10\x01\x12\x12\n" +
+ "\x0eCHALLENGE_FLAG\x10\x02\x12\x10\n" +
+ "\fSTOP_TIMEOUT\x10\x03\x12\x16\n" +
+ "\x12FAIL_BALLPLACEMENT\x10\x04B\x05\n" +
+ "\x03msg\"\x87\x01\n" +
+ "\x19ControllerToRemoteControl\x12;\n" +
+ "\x10controller_reply\x18\x01 \x01(\v2\x10.ControllerReplyR\x0fcontrollerReply\x12-\n" +
+ "\x05state\x18\x02 \x01(\v2\x17.RemoteControlTeamStateR\x05state\"\xa3\x05\n" +
+ "\x16RemoteControlTeamState\x12\x19\n" +
+ "\x04team\x18\f \x01(\x0e2\x05.TeamR\x04team\x12H\n" +
+ "\x12available_requests\x18\x01 \x03(\x0e2\x19.RemoteControlRequestTypeR\x11availableRequests\x12B\n" +
+ "\x0factive_requests\x18\x02 \x03(\x0e2\x19.RemoteControlRequestTypeR\x0eactiveRequests\x12\x1b\n" +
+ "\tkeeper_id\x18\x03 \x01(\x05R\bkeeperId\x12*\n" +
+ "\x11emergency_stop_in\x18\x04 \x01(\x02R\x0femergencyStopIn\x12#\n" +
+ "\rtimeouts_left\x18\x05 \x01(\x05R\ftimeoutsLeft\x12*\n" +
+ "\x11timeout_time_left\x18\n" +
+ " \x01(\x02R\x0ftimeoutTimeLeft\x120\n" +
+ "\x14challenge_flags_left\x18\x06 \x01(\x05R\x12challengeFlagsLeft\x12\x1d\n" +
+ "\n" +
+ "max_robots\x18\a \x01(\x05R\tmaxRobots\x12&\n" +
+ "\x0frobots_on_field\x18\t \x01(\x05R\rrobotsOnField\x12(\n" +
+ "\x10yellow_cards_due\x18\b \x03(\x02R\x0eyellowCardsDue\x120\n" +
+ "\x14can_substitute_robot\x18\v \x01(\bR\x12canSubstituteRobot\x124\n" +
+ "\x16bot_substitutions_left\x18\r \x01(\rR\x14botSubstitutionsLeft\x12;\n" +
+ "\x1abot_substitution_time_left\x18\x0e \x01(\x02R\x17botSubstitutionTimeLeft*\xc1\x01\n" +
+ "\x18RemoteControlRequestType\x12\x18\n" +
+ "\x14UNKNOWN_REQUEST_TYPE\x10\x00\x12\x12\n" +
+ "\x0eEMERGENCY_STOP\x10\x01\x12\x16\n" +
+ "\x12ROBOT_SUBSTITUTION\x10\x02\x12\v\n" +
+ "\aTIMEOUT\x10\x03\x12\x12\n" +
+ "\x0eCHALLENGE_FLAG\x10\x04\x12\x14\n" +
+ "\x10CHANGE_KEEPER_ID\x10\x05\x12\x10\n" +
+ "\fSTOP_TIMEOUT\x10\x06\x12\x16\n" +
+ "\x12FAIL_BALLPLACEMENT\x10\aBhB\x1bSslGcRconRemotecontrolProtoP\x01ZGgithub.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
+
+var (
+ file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescOnce sync.Once
+ file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescData []byte
+)
+
+func file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescGZIP() []byte {
+ file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescOnce.Do(func() {
+ file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDesc), len(file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDesc)))
+ })
+ return file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescData
+}
+
+var file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
+var file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
+var file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_goTypes = []any{
+ (RemoteControlRequestType)(0), // 0: RemoteControlRequestType
+ (RemoteControlToController_Request)(0), // 1: RemoteControlToController.Request
+ (*RemoteControlRegistration)(nil), // 2: RemoteControlRegistration
+ (*RemoteControlToController)(nil), // 3: RemoteControlToController
+ (*ControllerToRemoteControl)(nil), // 4: ControllerToRemoteControl
+ (*RemoteControlTeamState)(nil), // 5: RemoteControlTeamState
+ (Team)(0), // 6: Team
+ (*Signature)(nil), // 7: Signature
+ (*ControllerReply)(nil), // 8: ControllerReply
+}
+var file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_depIdxs = []int32{
+ 6, // 0: RemoteControlRegistration.team:type_name -> Team
+ 7, // 1: RemoteControlRegistration.signature:type_name -> Signature
+ 7, // 2: RemoteControlToController.signature:type_name -> Signature
+ 1, // 3: RemoteControlToController.request:type_name -> RemoteControlToController.Request
+ 8, // 4: ControllerToRemoteControl.controller_reply:type_name -> ControllerReply
+ 5, // 5: ControllerToRemoteControl.state:type_name -> RemoteControlTeamState
+ 6, // 6: RemoteControlTeamState.team:type_name -> Team
+ 0, // 7: RemoteControlTeamState.available_requests:type_name -> RemoteControlRequestType
+ 0, // 8: RemoteControlTeamState.active_requests:type_name -> RemoteControlRequestType
+ 9, // [9:9] is the sub-list for method output_type
+ 9, // [9:9] is the sub-list for method input_type
+ 9, // [9:9] is the sub-list for extension type_name
+ 9, // [9:9] is the sub-list for extension extendee
+ 0, // [0:9] is the sub-list for field type_name
+}
+
+func init() { file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_init() }
+func file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_init() {
+ if File_gamecontroller_ssl_gc_rcon_remotecontrol_proto != nil {
+ return
+ }
+ file_gamecontroller_ssl_gc_common_proto_init()
+ file_gamecontroller_ssl_gc_rcon_proto_init()
+ file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes[1].OneofWrappers = []any{
+ (*RemoteControlToController_Request_)(nil),
+ (*RemoteControlToController_DesiredKeeper)(nil),
+ (*RemoteControlToController_RequestRobotSubstitution)(nil),
+ (*RemoteControlToController_RequestTimeout)(nil),
+ (*RemoteControlToController_RequestEmergencyStop)(nil),
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDesc), len(file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDesc)),
+ NumEnums: 2,
+ NumMessages: 4,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_goTypes,
+ DependencyIndexes: file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_depIdxs,
+ EnumInfos: file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_enumTypes,
+ MessageInfos: file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes,
+ }.Build()
+ File_gamecontroller_ssl_gc_rcon_remotecontrol_proto = out.File
+ file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_goTypes = nil
+ file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_depIdxs = nil
+}
diff --git a/gui/internal/gamecontroller/ssl_gc_rcon_team.pb.go b/gui/internal/gamecontroller/ssl_gc_rcon_team.pb.go
new file mode 100644
index 0000000..fc1ec5b
--- /dev/null
+++ b/gui/internal/gamecontroller/ssl_gc_rcon_team.pb.go
@@ -0,0 +1,442 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.36.6
+// protoc (unknown)
+// source: gamecontroller/ssl_gc_rcon_team.proto
+
+package gamecontroller
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+ unsafe "unsafe"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// the current advantage choice of the team
+// the choice is valid until another choice is received
+// if the team disconnects, the choice is reset to its default (STOP)
+// teams may either send their current choice continuously or only on change
+type AdvantageChoice int32
+
+const (
+ // stop the game
+ AdvantageChoice_STOP AdvantageChoice = 0
+ // keep the game running
+ AdvantageChoice_CONTINUE AdvantageChoice = 1
+)
+
+// Enum value maps for AdvantageChoice.
+var (
+ AdvantageChoice_name = map[int32]string{
+ 0: "STOP",
+ 1: "CONTINUE",
+ }
+ AdvantageChoice_value = map[string]int32{
+ "STOP": 0,
+ "CONTINUE": 1,
+ }
+)
+
+func (x AdvantageChoice) Enum() *AdvantageChoice {
+ p := new(AdvantageChoice)
+ *p = x
+ return p
+}
+
+func (x AdvantageChoice) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (AdvantageChoice) Descriptor() protoreflect.EnumDescriptor {
+ return file_gamecontroller_ssl_gc_rcon_team_proto_enumTypes[0].Descriptor()
+}
+
+func (AdvantageChoice) Type() protoreflect.EnumType {
+ return &file_gamecontroller_ssl_gc_rcon_team_proto_enumTypes[0]
+}
+
+func (x AdvantageChoice) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *AdvantageChoice) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = AdvantageChoice(num)
+ return nil
+}
+
+// Deprecated: Use AdvantageChoice.Descriptor instead.
+func (AdvantageChoice) EnumDescriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_rcon_team_proto_rawDescGZIP(), []int{0}
+}
+
+// a registration that must be send by teams to the controller as the very first message
+type TeamRegistration struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // the exact team name as published by the game-controller
+ TeamName *string `protobuf:"bytes,1,req,name=team_name,json=teamName" json:"team_name,omitempty"`
+ // signature can optionally be specified to enable secure communication
+ Signature *Signature `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"`
+ // the team (relevant only if a team plays against itself)
+ Team *Team `protobuf:"varint,3,opt,name=team,enum=Team" json:"team,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *TeamRegistration) Reset() {
+ *x = TeamRegistration{}
+ mi := &file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *TeamRegistration) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TeamRegistration) ProtoMessage() {}
+
+func (x *TeamRegistration) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TeamRegistration.ProtoReflect.Descriptor instead.
+func (*TeamRegistration) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_rcon_team_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *TeamRegistration) GetTeamName() string {
+ if x != nil && x.TeamName != nil {
+ return *x.TeamName
+ }
+ return ""
+}
+
+func (x *TeamRegistration) GetSignature() *Signature {
+ if x != nil {
+ return x.Signature
+ }
+ return nil
+}
+
+func (x *TeamRegistration) GetTeam() Team {
+ if x != nil && x.Team != nil {
+ return *x.Team
+ }
+ return Team_UNKNOWN
+}
+
+// wrapper for all messages from a team's computer to the controller
+type TeamToController struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // signature can optionally be specified to enable secure communication
+ Signature *Signature `protobuf:"bytes,1,opt,name=signature" json:"signature,omitempty"`
+ // Types that are valid to be assigned to Msg:
+ //
+ // *TeamToController_DesiredKeeper
+ // *TeamToController_AdvantageChoice
+ // *TeamToController_SubstituteBot
+ // *TeamToController_Ping
+ Msg isTeamToController_Msg `protobuf_oneof:"msg"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *TeamToController) Reset() {
+ *x = TeamToController{}
+ mi := &file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *TeamToController) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TeamToController) ProtoMessage() {}
+
+func (x *TeamToController) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes[1]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TeamToController.ProtoReflect.Descriptor instead.
+func (*TeamToController) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_rcon_team_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *TeamToController) GetSignature() *Signature {
+ if x != nil {
+ return x.Signature
+ }
+ return nil
+}
+
+func (x *TeamToController) GetMsg() isTeamToController_Msg {
+ if x != nil {
+ return x.Msg
+ }
+ return nil
+}
+
+func (x *TeamToController) GetDesiredKeeper() int32 {
+ if x != nil {
+ if x, ok := x.Msg.(*TeamToController_DesiredKeeper); ok {
+ return x.DesiredKeeper
+ }
+ }
+ return 0
+}
+
+func (x *TeamToController) GetAdvantageChoice() AdvantageChoice {
+ if x != nil {
+ if x, ok := x.Msg.(*TeamToController_AdvantageChoice); ok {
+ return x.AdvantageChoice
+ }
+ }
+ return AdvantageChoice_STOP
+}
+
+func (x *TeamToController) GetSubstituteBot() bool {
+ if x != nil {
+ if x, ok := x.Msg.(*TeamToController_SubstituteBot); ok {
+ return x.SubstituteBot
+ }
+ }
+ return false
+}
+
+func (x *TeamToController) GetPing() bool {
+ if x != nil {
+ if x, ok := x.Msg.(*TeamToController_Ping); ok {
+ return x.Ping
+ }
+ }
+ return false
+}
+
+type isTeamToController_Msg interface {
+ isTeamToController_Msg()
+}
+
+type TeamToController_DesiredKeeper struct {
+ // request a new desired keeper id
+ DesiredKeeper int32 `protobuf:"varint,2,opt,name=desired_keeper,json=desiredKeeper,oneof"`
+}
+
+type TeamToController_AdvantageChoice struct {
+ // response to an advantage choice request
+ AdvantageChoice AdvantageChoice `protobuf:"varint,3,opt,name=advantage_choice,json=advantageChoice,enum=AdvantageChoice,oneof"`
+}
+
+type TeamToController_SubstituteBot struct {
+ // request to substitute a robot at the next possibility
+ SubstituteBot bool `protobuf:"varint,4,opt,name=substitute_bot,json=substituteBot,oneof"`
+}
+
+type TeamToController_Ping struct {
+ // send a ping to the GC to test if the connection is still open.
+ // the value is ignored and a reply is sent back
+ Ping bool `protobuf:"varint,5,opt,name=ping,oneof"`
+}
+
+func (*TeamToController_DesiredKeeper) isTeamToController_Msg() {}
+
+func (*TeamToController_AdvantageChoice) isTeamToController_Msg() {}
+
+func (*TeamToController_SubstituteBot) isTeamToController_Msg() {}
+
+func (*TeamToController_Ping) isTeamToController_Msg() {}
+
+// wrapper for all messages from controller to a team's computer
+type ControllerToTeam struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Types that are valid to be assigned to Msg:
+ //
+ // *ControllerToTeam_ControllerReply
+ Msg isControllerToTeam_Msg `protobuf_oneof:"msg"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ControllerToTeam) Reset() {
+ *x = ControllerToTeam{}
+ mi := &file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ControllerToTeam) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ControllerToTeam) ProtoMessage() {}
+
+func (x *ControllerToTeam) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes[2]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ControllerToTeam.ProtoReflect.Descriptor instead.
+func (*ControllerToTeam) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_rcon_team_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ControllerToTeam) GetMsg() isControllerToTeam_Msg {
+ if x != nil {
+ return x.Msg
+ }
+ return nil
+}
+
+func (x *ControllerToTeam) GetControllerReply() *ControllerReply {
+ if x != nil {
+ if x, ok := x.Msg.(*ControllerToTeam_ControllerReply); ok {
+ return x.ControllerReply
+ }
+ }
+ return nil
+}
+
+type isControllerToTeam_Msg interface {
+ isControllerToTeam_Msg()
+}
+
+type ControllerToTeam_ControllerReply struct {
+ // a reply from the controller
+ ControllerReply *ControllerReply `protobuf:"bytes,1,opt,name=controller_reply,json=controllerReply,oneof"`
+}
+
+func (*ControllerToTeam_ControllerReply) isControllerToTeam_Msg() {}
+
+var File_gamecontroller_ssl_gc_rcon_team_proto protoreflect.FileDescriptor
+
+const file_gamecontroller_ssl_gc_rcon_team_proto_rawDesc = "" +
+ "\n" +
+ "%gamecontroller/ssl_gc_rcon_team.proto\x1a\"gamecontroller/ssl_gc_common.proto\x1a gamecontroller/ssl_gc_rcon.proto\"t\n" +
+ "\x10TeamRegistration\x12\x1b\n" +
+ "\tteam_name\x18\x01 \x02(\tR\bteamName\x12(\n" +
+ "\tsignature\x18\x02 \x01(\v2\n" +
+ ".SignatureR\tsignature\x12\x19\n" +
+ "\x04team\x18\x03 \x01(\x0e2\x05.TeamR\x04team\"\xea\x01\n" +
+ "\x10TeamToController\x12(\n" +
+ "\tsignature\x18\x01 \x01(\v2\n" +
+ ".SignatureR\tsignature\x12'\n" +
+ "\x0edesired_keeper\x18\x02 \x01(\x05H\x00R\rdesiredKeeper\x12=\n" +
+ "\x10advantage_choice\x18\x03 \x01(\x0e2\x10.AdvantageChoiceH\x00R\x0fadvantageChoice\x12'\n" +
+ "\x0esubstitute_bot\x18\x04 \x01(\bH\x00R\rsubstituteBot\x12\x14\n" +
+ "\x04ping\x18\x05 \x01(\bH\x00R\x04pingB\x05\n" +
+ "\x03msg\"^\n" +
+ "\x10ControllerToTeam\x12=\n" +
+ "\x10controller_reply\x18\x01 \x01(\v2\x10.ControllerReplyH\x00R\x0fcontrollerReplyB\x05\n" +
+ "\x03msgJ\x04\b\x02\x10\x03*)\n" +
+ "\x0fAdvantageChoice\x12\b\n" +
+ "\x04STOP\x10\x00\x12\f\n" +
+ "\bCONTINUE\x10\x01B_B\x12SslGcRconTeamProtoP\x01ZGgithub.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
+
+var (
+ file_gamecontroller_ssl_gc_rcon_team_proto_rawDescOnce sync.Once
+ file_gamecontroller_ssl_gc_rcon_team_proto_rawDescData []byte
+)
+
+func file_gamecontroller_ssl_gc_rcon_team_proto_rawDescGZIP() []byte {
+ file_gamecontroller_ssl_gc_rcon_team_proto_rawDescOnce.Do(func() {
+ file_gamecontroller_ssl_gc_rcon_team_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_rcon_team_proto_rawDesc), len(file_gamecontroller_ssl_gc_rcon_team_proto_rawDesc)))
+ })
+ return file_gamecontroller_ssl_gc_rcon_team_proto_rawDescData
+}
+
+var file_gamecontroller_ssl_gc_rcon_team_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
+var file_gamecontroller_ssl_gc_rcon_team_proto_goTypes = []any{
+ (AdvantageChoice)(0), // 0: AdvantageChoice
+ (*TeamRegistration)(nil), // 1: TeamRegistration
+ (*TeamToController)(nil), // 2: TeamToController
+ (*ControllerToTeam)(nil), // 3: ControllerToTeam
+ (*Signature)(nil), // 4: Signature
+ (Team)(0), // 5: Team
+ (*ControllerReply)(nil), // 6: ControllerReply
+}
+var file_gamecontroller_ssl_gc_rcon_team_proto_depIdxs = []int32{
+ 4, // 0: TeamRegistration.signature:type_name -> Signature
+ 5, // 1: TeamRegistration.team:type_name -> Team
+ 4, // 2: TeamToController.signature:type_name -> Signature
+ 0, // 3: TeamToController.advantage_choice:type_name -> AdvantageChoice
+ 6, // 4: ControllerToTeam.controller_reply:type_name -> ControllerReply
+ 5, // [5:5] is the sub-list for method output_type
+ 5, // [5:5] is the sub-list for method input_type
+ 5, // [5:5] is the sub-list for extension type_name
+ 5, // [5:5] is the sub-list for extension extendee
+ 0, // [0:5] is the sub-list for field type_name
+}
+
+func init() { file_gamecontroller_ssl_gc_rcon_team_proto_init() }
+func file_gamecontroller_ssl_gc_rcon_team_proto_init() {
+ if File_gamecontroller_ssl_gc_rcon_team_proto != nil {
+ return
+ }
+ file_gamecontroller_ssl_gc_common_proto_init()
+ file_gamecontroller_ssl_gc_rcon_proto_init()
+ file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes[1].OneofWrappers = []any{
+ (*TeamToController_DesiredKeeper)(nil),
+ (*TeamToController_AdvantageChoice)(nil),
+ (*TeamToController_SubstituteBot)(nil),
+ (*TeamToController_Ping)(nil),
+ }
+ file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes[2].OneofWrappers = []any{
+ (*ControllerToTeam_ControllerReply)(nil),
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_rcon_team_proto_rawDesc), len(file_gamecontroller_ssl_gc_rcon_team_proto_rawDesc)),
+ NumEnums: 1,
+ NumMessages: 3,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_gamecontroller_ssl_gc_rcon_team_proto_goTypes,
+ DependencyIndexes: file_gamecontroller_ssl_gc_rcon_team_proto_depIdxs,
+ EnumInfos: file_gamecontroller_ssl_gc_rcon_team_proto_enumTypes,
+ MessageInfos: file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes,
+ }.Build()
+ File_gamecontroller_ssl_gc_rcon_team_proto = out.File
+ file_gamecontroller_ssl_gc_rcon_team_proto_goTypes = nil
+ file_gamecontroller_ssl_gc_rcon_team_proto_depIdxs = nil
+}
diff --git a/gui/internal/gamecontroller/ssl_gc_referee_message.pb.go b/gui/internal/gamecontroller/ssl_gc_referee_message.pb.go
new file mode 100644
index 0000000..84dd959
--- /dev/null
+++ b/gui/internal/gamecontroller/ssl_gc_referee_message.pb.go
@@ -0,0 +1,1113 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.36.6
+// protoc (unknown)
+// source: gamecontroller/ssl_gc_referee_message.proto
+
+package gamecontroller
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+ unsafe "unsafe"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// MatchType is a meta information about the current match for easier log processing
+type MatchType int32
+
+const (
+ // not set
+ MatchType_UNKNOWN_MATCH MatchType = 0
+ // match is part of the group phase
+ MatchType_GROUP_PHASE MatchType = 1
+ // match is part of the elimination phase
+ MatchType_ELIMINATION_PHASE MatchType = 2
+ // a friendly match, not part of a tournament
+ MatchType_FRIENDLY MatchType = 3
+)
+
+// Enum value maps for MatchType.
+var (
+ MatchType_name = map[int32]string{
+ 0: "UNKNOWN_MATCH",
+ 1: "GROUP_PHASE",
+ 2: "ELIMINATION_PHASE",
+ 3: "FRIENDLY",
+ }
+ MatchType_value = map[string]int32{
+ "UNKNOWN_MATCH": 0,
+ "GROUP_PHASE": 1,
+ "ELIMINATION_PHASE": 2,
+ "FRIENDLY": 3,
+ }
+)
+
+func (x MatchType) Enum() *MatchType {
+ p := new(MatchType)
+ *p = x
+ return p
+}
+
+func (x MatchType) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (MatchType) Descriptor() protoreflect.EnumDescriptor {
+ return file_gamecontroller_ssl_gc_referee_message_proto_enumTypes[0].Descriptor()
+}
+
+func (MatchType) Type() protoreflect.EnumType {
+ return &file_gamecontroller_ssl_gc_referee_message_proto_enumTypes[0]
+}
+
+func (x MatchType) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *MatchType) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = MatchType(num)
+ return nil
+}
+
+// Deprecated: Use MatchType.Descriptor instead.
+func (MatchType) EnumDescriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_referee_message_proto_rawDescGZIP(), []int{0}
+}
+
+// HullColor is the color of the hull of the robots of a team
+type HullColor int32
+
+const (
+ // not set
+ HullColor_HULL_COLOR_UNKNOWN HullColor = 0
+ // dark hull color
+ HullColor_HULL_COLOR_DARK HullColor = 1
+ // light hull color
+ HullColor_HULL_COLOR_LIGHT HullColor = 2
+)
+
+// Enum value maps for HullColor.
+var (
+ HullColor_name = map[int32]string{
+ 0: "HULL_COLOR_UNKNOWN",
+ 1: "HULL_COLOR_DARK",
+ 2: "HULL_COLOR_LIGHT",
+ }
+ HullColor_value = map[string]int32{
+ "HULL_COLOR_UNKNOWN": 0,
+ "HULL_COLOR_DARK": 1,
+ "HULL_COLOR_LIGHT": 2,
+ }
+)
+
+func (x HullColor) Enum() *HullColor {
+ p := new(HullColor)
+ *p = x
+ return p
+}
+
+func (x HullColor) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (HullColor) Descriptor() protoreflect.EnumDescriptor {
+ return file_gamecontroller_ssl_gc_referee_message_proto_enumTypes[1].Descriptor()
+}
+
+func (HullColor) Type() protoreflect.EnumType {
+ return &file_gamecontroller_ssl_gc_referee_message_proto_enumTypes[1]
+}
+
+func (x HullColor) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *HullColor) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = HullColor(num)
+ return nil
+}
+
+// Deprecated: Use HullColor.Descriptor instead.
+func (HullColor) EnumDescriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_referee_message_proto_rawDescGZIP(), []int{1}
+}
+
+// These are the "coarse" stages of the game.
+type Referee_Stage int32
+
+const (
+ // The first half is about to start.
+ // A kickoff is called within this stage.
+ // This stage ends with the NORMAL_START.
+ Referee_NORMAL_FIRST_HALF_PRE Referee_Stage = 0
+ // The first half of the normal game, before half time.
+ Referee_NORMAL_FIRST_HALF Referee_Stage = 1
+ // Half time between first and second halves.
+ Referee_NORMAL_HALF_TIME Referee_Stage = 2
+ // The second half is about to start.
+ // A kickoff is called within this stage.
+ // This stage ends with the NORMAL_START.
+ Referee_NORMAL_SECOND_HALF_PRE Referee_Stage = 3
+ // The second half of the normal game, after half time.
+ Referee_NORMAL_SECOND_HALF Referee_Stage = 4
+ // The break before extra time.
+ Referee_EXTRA_TIME_BREAK Referee_Stage = 5
+ // The first half of extra time is about to start.
+ // A kickoff is called within this stage.
+ // This stage ends with the NORMAL_START.
+ Referee_EXTRA_FIRST_HALF_PRE Referee_Stage = 6
+ // The first half of extra time.
+ Referee_EXTRA_FIRST_HALF Referee_Stage = 7
+ // Half time between first and second extra halves.
+ Referee_EXTRA_HALF_TIME Referee_Stage = 8
+ // The second half of extra time is about to start.
+ // A kickoff is called within this stage.
+ // This stage ends with the NORMAL_START.
+ Referee_EXTRA_SECOND_HALF_PRE Referee_Stage = 9
+ // The second half of extra time.
+ Referee_EXTRA_SECOND_HALF Referee_Stage = 10
+ // The break before penalty shootout.
+ Referee_PENALTY_SHOOTOUT_BREAK Referee_Stage = 11
+ // The penalty shootout.
+ Referee_PENALTY_SHOOTOUT Referee_Stage = 12
+ // The game is over.
+ Referee_POST_GAME Referee_Stage = 13
+)
+
+// Enum value maps for Referee_Stage.
+var (
+ Referee_Stage_name = map[int32]string{
+ 0: "NORMAL_FIRST_HALF_PRE",
+ 1: "NORMAL_FIRST_HALF",
+ 2: "NORMAL_HALF_TIME",
+ 3: "NORMAL_SECOND_HALF_PRE",
+ 4: "NORMAL_SECOND_HALF",
+ 5: "EXTRA_TIME_BREAK",
+ 6: "EXTRA_FIRST_HALF_PRE",
+ 7: "EXTRA_FIRST_HALF",
+ 8: "EXTRA_HALF_TIME",
+ 9: "EXTRA_SECOND_HALF_PRE",
+ 10: "EXTRA_SECOND_HALF",
+ 11: "PENALTY_SHOOTOUT_BREAK",
+ 12: "PENALTY_SHOOTOUT",
+ 13: "POST_GAME",
+ }
+ Referee_Stage_value = map[string]int32{
+ "NORMAL_FIRST_HALF_PRE": 0,
+ "NORMAL_FIRST_HALF": 1,
+ "NORMAL_HALF_TIME": 2,
+ "NORMAL_SECOND_HALF_PRE": 3,
+ "NORMAL_SECOND_HALF": 4,
+ "EXTRA_TIME_BREAK": 5,
+ "EXTRA_FIRST_HALF_PRE": 6,
+ "EXTRA_FIRST_HALF": 7,
+ "EXTRA_HALF_TIME": 8,
+ "EXTRA_SECOND_HALF_PRE": 9,
+ "EXTRA_SECOND_HALF": 10,
+ "PENALTY_SHOOTOUT_BREAK": 11,
+ "PENALTY_SHOOTOUT": 12,
+ "POST_GAME": 13,
+ }
+)
+
+func (x Referee_Stage) Enum() *Referee_Stage {
+ p := new(Referee_Stage)
+ *p = x
+ return p
+}
+
+func (x Referee_Stage) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Referee_Stage) Descriptor() protoreflect.EnumDescriptor {
+ return file_gamecontroller_ssl_gc_referee_message_proto_enumTypes[2].Descriptor()
+}
+
+func (Referee_Stage) Type() protoreflect.EnumType {
+ return &file_gamecontroller_ssl_gc_referee_message_proto_enumTypes[2]
+}
+
+func (x Referee_Stage) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *Referee_Stage) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = Referee_Stage(num)
+ return nil
+}
+
+// Deprecated: Use Referee_Stage.Descriptor instead.
+func (Referee_Stage) EnumDescriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_referee_message_proto_rawDescGZIP(), []int{0, 0}
+}
+
+// These are the "fine" states of play on the field.
+type Referee_Command int32
+
+const (
+ // All robots should completely stop moving.
+ Referee_HALT Referee_Command = 0
+ // Robots must keep 50 cm from the ball.
+ Referee_STOP Referee_Command = 1
+ // A prepared kickoff or penalty may now be taken.
+ Referee_NORMAL_START Referee_Command = 2
+ // The ball is dropped and free for either team.
+ Referee_FORCE_START Referee_Command = 3
+ // The yellow team may move into kickoff position.
+ Referee_PREPARE_KICKOFF_YELLOW Referee_Command = 4
+ // The blue team may move into kickoff position.
+ Referee_PREPARE_KICKOFF_BLUE Referee_Command = 5
+ // The yellow team may move into penalty position.
+ Referee_PREPARE_PENALTY_YELLOW Referee_Command = 6
+ // The blue team may move into penalty position.
+ Referee_PREPARE_PENALTY_BLUE Referee_Command = 7
+ // The yellow team may take a direct free kick.
+ Referee_DIRECT_FREE_YELLOW Referee_Command = 8
+ // The blue team may take a direct free kick.
+ Referee_DIRECT_FREE_BLUE Referee_Command = 9
+ // The yellow team may take an indirect free kick.
+ //
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_referee_message.proto.
+ Referee_INDIRECT_FREE_YELLOW Referee_Command = 10
+ // The blue team may take an indirect free kick.
+ //
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_referee_message.proto.
+ Referee_INDIRECT_FREE_BLUE Referee_Command = 11
+ // The yellow team is currently in a timeout.
+ Referee_TIMEOUT_YELLOW Referee_Command = 12
+ // The blue team is currently in a timeout.
+ Referee_TIMEOUT_BLUE Referee_Command = 13
+ // The yellow team just scored a goal.
+ // For information only.
+ // Deprecated: Use the score field from the team infos instead. That way, you can also detect revoked goals.
+ //
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_referee_message.proto.
+ Referee_GOAL_YELLOW Referee_Command = 14
+ // The blue team just scored a goal. See also GOAL_YELLOW.
+ //
+ // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_referee_message.proto.
+ Referee_GOAL_BLUE Referee_Command = 15
+ // Equivalent to STOP, but the yellow team must pick up the ball and
+ // drop it in the Designated Position.
+ Referee_BALL_PLACEMENT_YELLOW Referee_Command = 16
+ // Equivalent to STOP, but the blue team must pick up the ball and drop
+ // it in the Designated Position.
+ Referee_BALL_PLACEMENT_BLUE Referee_Command = 17
+)
+
+// Enum value maps for Referee_Command.
+var (
+ Referee_Command_name = map[int32]string{
+ 0: "HALT",
+ 1: "STOP",
+ 2: "NORMAL_START",
+ 3: "FORCE_START",
+ 4: "PREPARE_KICKOFF_YELLOW",
+ 5: "PREPARE_KICKOFF_BLUE",
+ 6: "PREPARE_PENALTY_YELLOW",
+ 7: "PREPARE_PENALTY_BLUE",
+ 8: "DIRECT_FREE_YELLOW",
+ 9: "DIRECT_FREE_BLUE",
+ 10: "INDIRECT_FREE_YELLOW",
+ 11: "INDIRECT_FREE_BLUE",
+ 12: "TIMEOUT_YELLOW",
+ 13: "TIMEOUT_BLUE",
+ 14: "GOAL_YELLOW",
+ 15: "GOAL_BLUE",
+ 16: "BALL_PLACEMENT_YELLOW",
+ 17: "BALL_PLACEMENT_BLUE",
+ }
+ Referee_Command_value = map[string]int32{
+ "HALT": 0,
+ "STOP": 1,
+ "NORMAL_START": 2,
+ "FORCE_START": 3,
+ "PREPARE_KICKOFF_YELLOW": 4,
+ "PREPARE_KICKOFF_BLUE": 5,
+ "PREPARE_PENALTY_YELLOW": 6,
+ "PREPARE_PENALTY_BLUE": 7,
+ "DIRECT_FREE_YELLOW": 8,
+ "DIRECT_FREE_BLUE": 9,
+ "INDIRECT_FREE_YELLOW": 10,
+ "INDIRECT_FREE_BLUE": 11,
+ "TIMEOUT_YELLOW": 12,
+ "TIMEOUT_BLUE": 13,
+ "GOAL_YELLOW": 14,
+ "GOAL_BLUE": 15,
+ "BALL_PLACEMENT_YELLOW": 16,
+ "BALL_PLACEMENT_BLUE": 17,
+ }
+)
+
+func (x Referee_Command) Enum() *Referee_Command {
+ p := new(Referee_Command)
+ *p = x
+ return p
+}
+
+func (x Referee_Command) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Referee_Command) Descriptor() protoreflect.EnumDescriptor {
+ return file_gamecontroller_ssl_gc_referee_message_proto_enumTypes[3].Descriptor()
+}
+
+func (Referee_Command) Type() protoreflect.EnumType {
+ return &file_gamecontroller_ssl_gc_referee_message_proto_enumTypes[3]
+}
+
+func (x Referee_Command) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *Referee_Command) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = Referee_Command(num)
+ return nil
+}
+
+// Deprecated: Use Referee_Command.Descriptor instead.
+func (Referee_Command) EnumDescriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_referee_message_proto_rawDescGZIP(), []int{0, 1}
+}
+
+// Each UDP packet contains one of these messages.
+type Referee struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // A random UUID of the source that is kept constant at the source while running
+ // If multiple sources are broadcasting to the same network, this id can be used to identify individual sources
+ SourceIdentifier *string `protobuf:"bytes,18,opt,name=source_identifier,json=sourceIdentifier" json:"source_identifier,omitempty"`
+ // The match type is a meta information about the current match that helps to process the logs after a competition
+ MatchType *MatchType `protobuf:"varint,19,opt,name=match_type,json=matchType,enum=MatchType,def=0" json:"match_type,omitempty"`
+ // The UNIX timestamp when the packet was sent, in microseconds.
+ // Divide by 1,000,000 to get a time_t.
+ PacketTimestamp *uint64 `protobuf:"varint,1,req,name=packet_timestamp,json=packetTimestamp" json:"packet_timestamp,omitempty"`
+ Stage *Referee_Stage `protobuf:"varint,2,req,name=stage,enum=Referee_Stage" json:"stage,omitempty"`
+ // The number of microseconds left in the stage.
+ // The following stages have this value; the rest do not:
+ // NORMAL_FIRST_HALF
+ // NORMAL_HALF_TIME
+ // NORMAL_SECOND_HALF
+ // EXTRA_TIME_BREAK
+ // EXTRA_FIRST_HALF
+ // EXTRA_HALF_TIME
+ // EXTRA_SECOND_HALF
+ // PENALTY_SHOOTOUT_BREAK
+ //
+ // If the stage runs over its specified time, this value
+ // becomes negative.
+ StageTimeLeft *int64 `protobuf:"zigzag64,3,opt,name=stage_time_left,json=stageTimeLeft" json:"stage_time_left,omitempty"`
+ Command *Referee_Command `protobuf:"varint,4,req,name=command,enum=Referee_Command" json:"command,omitempty"`
+ // The number of commands issued since startup (mod 2^32).
+ CommandCounter *uint32 `protobuf:"varint,5,req,name=command_counter,json=commandCounter" json:"command_counter,omitempty"`
+ // The UNIX timestamp when the command was issued, in microseconds.
+ // This value changes only when a new command is issued, not on each packet.
+ CommandTimestamp *uint64 `protobuf:"varint,6,req,name=command_timestamp,json=commandTimestamp" json:"command_timestamp,omitempty"`
+ // Information about the two teams.
+ Yellow *Referee_TeamInfo `protobuf:"bytes,7,req,name=yellow" json:"yellow,omitempty"`
+ Blue *Referee_TeamInfo `protobuf:"bytes,8,req,name=blue" json:"blue,omitempty"`
+ DesignatedPosition *Referee_Point `protobuf:"bytes,9,opt,name=designated_position,json=designatedPosition" json:"designated_position,omitempty"`
+ // Information about the direction of play.
+ // True, if the blue team will have it's goal on the positive x-axis of the ssl-vision coordinate system.
+ // Obviously, the yellow team will play on the opposite half.
+ BlueTeamOnPositiveHalf *bool `protobuf:"varint,10,opt,name=blue_team_on_positive_half,json=blueTeamOnPositiveHalf" json:"blue_team_on_positive_half,omitempty"`
+ // The command that will be issued after the current stoppage and ball placement to continue the game.
+ NextCommand *Referee_Command `protobuf:"varint,12,opt,name=next_command,json=nextCommand,enum=Referee_Command" json:"next_command,omitempty"`
+ GameEvents []*GameEvent `protobuf:"bytes,16,rep,name=game_events,json=gameEvents" json:"game_events,omitempty"`
+ GameEventProposals []*GameEventProposalGroup `protobuf:"bytes,17,rep,name=game_event_proposals,json=gameEventProposals" json:"game_event_proposals,omitempty"`
+ // The time in microseconds that is remaining until the current action times out
+ // The time will not be reset. It can get negative.
+ // An autoRef would raise an appropriate event, if the time gets negative.
+ // Possible actions where this time is relevant:
+ // - free kicks
+ // - kickoff, penalty kick, force start
+ // - ball placement
+ CurrentActionTimeRemaining *int64 `protobuf:"varint,15,opt,name=current_action_time_remaining,json=currentActionTimeRemaining" json:"current_action_time_remaining,omitempty"`
+ // A message that can be displayed to the spectators, like a reason for a stoppage.
+ StatusMessage *string `protobuf:"bytes,20,opt,name=status_message,json=statusMessage" json:"status_message,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+// Default values for Referee fields.
+const (
+ Default_Referee_MatchType = MatchType_UNKNOWN_MATCH
+)
+
+func (x *Referee) Reset() {
+ *x = Referee{}
+ mi := &file_gamecontroller_ssl_gc_referee_message_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *Referee) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Referee) ProtoMessage() {}
+
+func (x *Referee) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_referee_message_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Referee.ProtoReflect.Descriptor instead.
+func (*Referee) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_referee_message_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Referee) GetSourceIdentifier() string {
+ if x != nil && x.SourceIdentifier != nil {
+ return *x.SourceIdentifier
+ }
+ return ""
+}
+
+func (x *Referee) GetMatchType() MatchType {
+ if x != nil && x.MatchType != nil {
+ return *x.MatchType
+ }
+ return Default_Referee_MatchType
+}
+
+func (x *Referee) GetPacketTimestamp() uint64 {
+ if x != nil && x.PacketTimestamp != nil {
+ return *x.PacketTimestamp
+ }
+ return 0
+}
+
+func (x *Referee) GetStage() Referee_Stage {
+ if x != nil && x.Stage != nil {
+ return *x.Stage
+ }
+ return Referee_NORMAL_FIRST_HALF_PRE
+}
+
+func (x *Referee) GetStageTimeLeft() int64 {
+ if x != nil && x.StageTimeLeft != nil {
+ return *x.StageTimeLeft
+ }
+ return 0
+}
+
+func (x *Referee) GetCommand() Referee_Command {
+ if x != nil && x.Command != nil {
+ return *x.Command
+ }
+ return Referee_HALT
+}
+
+func (x *Referee) GetCommandCounter() uint32 {
+ if x != nil && x.CommandCounter != nil {
+ return *x.CommandCounter
+ }
+ return 0
+}
+
+func (x *Referee) GetCommandTimestamp() uint64 {
+ if x != nil && x.CommandTimestamp != nil {
+ return *x.CommandTimestamp
+ }
+ return 0
+}
+
+func (x *Referee) GetYellow() *Referee_TeamInfo {
+ if x != nil {
+ return x.Yellow
+ }
+ return nil
+}
+
+func (x *Referee) GetBlue() *Referee_TeamInfo {
+ if x != nil {
+ return x.Blue
+ }
+ return nil
+}
+
+func (x *Referee) GetDesignatedPosition() *Referee_Point {
+ if x != nil {
+ return x.DesignatedPosition
+ }
+ return nil
+}
+
+func (x *Referee) GetBlueTeamOnPositiveHalf() bool {
+ if x != nil && x.BlueTeamOnPositiveHalf != nil {
+ return *x.BlueTeamOnPositiveHalf
+ }
+ return false
+}
+
+func (x *Referee) GetNextCommand() Referee_Command {
+ if x != nil && x.NextCommand != nil {
+ return *x.NextCommand
+ }
+ return Referee_HALT
+}
+
+func (x *Referee) GetGameEvents() []*GameEvent {
+ if x != nil {
+ return x.GameEvents
+ }
+ return nil
+}
+
+func (x *Referee) GetGameEventProposals() []*GameEventProposalGroup {
+ if x != nil {
+ return x.GameEventProposals
+ }
+ return nil
+}
+
+func (x *Referee) GetCurrentActionTimeRemaining() int64 {
+ if x != nil && x.CurrentActionTimeRemaining != nil {
+ return *x.CurrentActionTimeRemaining
+ }
+ return 0
+}
+
+func (x *Referee) GetStatusMessage() string {
+ if x != nil && x.StatusMessage != nil {
+ return *x.StatusMessage
+ }
+ return ""
+}
+
+// List of matching proposals
+type GameEventProposalGroup struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Unique ID of this group
+ Id *string `protobuf:"bytes,3,opt,name=id" json:"id,omitempty"`
+ // The proposed game events
+ GameEvents []*GameEvent `protobuf:"bytes,1,rep,name=game_events,json=gameEvents" json:"game_events,omitempty"`
+ // Whether the proposal group was accepted
+ Accepted *bool `protobuf:"varint,2,opt,name=accepted" json:"accepted,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GameEventProposalGroup) Reset() {
+ *x = GameEventProposalGroup{}
+ mi := &file_gamecontroller_ssl_gc_referee_message_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GameEventProposalGroup) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GameEventProposalGroup) ProtoMessage() {}
+
+func (x *GameEventProposalGroup) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_referee_message_proto_msgTypes[1]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GameEventProposalGroup.ProtoReflect.Descriptor instead.
+func (*GameEventProposalGroup) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_referee_message_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *GameEventProposalGroup) GetId() string {
+ if x != nil && x.Id != nil {
+ return *x.Id
+ }
+ return ""
+}
+
+func (x *GameEventProposalGroup) GetGameEvents() []*GameEvent {
+ if x != nil {
+ return x.GameEvents
+ }
+ return nil
+}
+
+func (x *GameEventProposalGroup) GetAccepted() bool {
+ if x != nil && x.Accepted != nil {
+ return *x.Accepted
+ }
+ return false
+}
+
+// Information about a single team.
+type Referee_TeamInfo struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // The team's name (empty string if operator has not typed anything).
+ Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"`
+ // The number of goals scored by the team during normal play and overtime.
+ Score *uint32 `protobuf:"varint,2,req,name=score" json:"score,omitempty"`
+ // The number of red cards issued to the team since the beginning of the game.
+ RedCards *uint32 `protobuf:"varint,3,req,name=red_cards,json=redCards" json:"red_cards,omitempty"`
+ // The amount of time (in microseconds) left on each yellow card issued to the team.
+ // If no yellow cards are issued, this array has no elements.
+ // Otherwise, times are ordered from smallest to largest.
+ YellowCardTimes []uint32 `protobuf:"varint,4,rep,packed,name=yellow_card_times,json=yellowCardTimes" json:"yellow_card_times,omitempty"`
+ // The total number of yellow cards ever issued to the team.
+ YellowCards *uint32 `protobuf:"varint,5,req,name=yellow_cards,json=yellowCards" json:"yellow_cards,omitempty"`
+ // The number of timeouts this team can still call.
+ // If in a timeout right now, that timeout is excluded.
+ Timeouts *uint32 `protobuf:"varint,6,req,name=timeouts" json:"timeouts,omitempty"`
+ // The number of microseconds of timeout this team can use.
+ TimeoutTime *uint32 `protobuf:"varint,7,req,name=timeout_time,json=timeoutTime" json:"timeout_time,omitempty"`
+ // The pattern number of this team's goalkeeper.
+ Goalkeeper *uint32 `protobuf:"varint,8,req,name=goalkeeper" json:"goalkeeper,omitempty"`
+ // The total number of countable fouls that act towards yellow cards
+ FoulCounter *uint32 `protobuf:"varint,9,opt,name=foul_counter,json=foulCounter" json:"foul_counter,omitempty"`
+ // The number of consecutive ball placement failures of this team
+ BallPlacementFailures *uint32 `protobuf:"varint,10,opt,name=ball_placement_failures,json=ballPlacementFailures" json:"ball_placement_failures,omitempty"`
+ // Indicate if the team is able and allowed to place the ball
+ CanPlaceBall *bool `protobuf:"varint,12,opt,name=can_place_ball,json=canPlaceBall" json:"can_place_ball,omitempty"`
+ // The maximum number of bots allowed on the field based on division and cards
+ MaxAllowedBots *uint32 `protobuf:"varint,13,opt,name=max_allowed_bots,json=maxAllowedBots" json:"max_allowed_bots,omitempty"`
+ // The team has submitted an intent to substitute one or more robots at the next chance
+ BotSubstitutionIntent *bool `protobuf:"varint,14,opt,name=bot_substitution_intent,json=botSubstitutionIntent" json:"bot_substitution_intent,omitempty"`
+ // Indicate if the team reached the maximum allowed ball placement failures and is thus not allowed to place the ball anymore
+ BallPlacementFailuresReached *bool `protobuf:"varint,15,opt,name=ball_placement_failures_reached,json=ballPlacementFailuresReached" json:"ball_placement_failures_reached,omitempty"`
+ // The team is allowed to substitute one or more robots currently
+ BotSubstitutionAllowed *bool `protobuf:"varint,16,opt,name=bot_substitution_allowed,json=botSubstitutionAllowed" json:"bot_substitution_allowed,omitempty"`
+ // The number of bot substitutions left by the team in this halftime
+ BotSubstitutionsLeft *uint32 `protobuf:"varint,17,opt,name=bot_substitutions_left,json=botSubstitutionsLeft" json:"bot_substitutions_left,omitempty"`
+ // The number of microseconds left for current bot substitution
+ BotSubstitutionTimeLeft *uint32 `protobuf:"varint,18,opt,name=bot_substitution_time_left,json=botSubstitutionTimeLeft" json:"bot_substitution_time_left,omitempty"`
+ // The color of the hull of the robots of this team
+ HullColor *HullColor `protobuf:"varint,19,opt,name=hull_color,json=hullColor,enum=HullColor" json:"hull_color,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *Referee_TeamInfo) Reset() {
+ *x = Referee_TeamInfo{}
+ mi := &file_gamecontroller_ssl_gc_referee_message_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *Referee_TeamInfo) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Referee_TeamInfo) ProtoMessage() {}
+
+func (x *Referee_TeamInfo) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_referee_message_proto_msgTypes[2]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Referee_TeamInfo.ProtoReflect.Descriptor instead.
+func (*Referee_TeamInfo) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_referee_message_proto_rawDescGZIP(), []int{0, 0}
+}
+
+func (x *Referee_TeamInfo) GetName() string {
+ if x != nil && x.Name != nil {
+ return *x.Name
+ }
+ return ""
+}
+
+func (x *Referee_TeamInfo) GetScore() uint32 {
+ if x != nil && x.Score != nil {
+ return *x.Score
+ }
+ return 0
+}
+
+func (x *Referee_TeamInfo) GetRedCards() uint32 {
+ if x != nil && x.RedCards != nil {
+ return *x.RedCards
+ }
+ return 0
+}
+
+func (x *Referee_TeamInfo) GetYellowCardTimes() []uint32 {
+ if x != nil {
+ return x.YellowCardTimes
+ }
+ return nil
+}
+
+func (x *Referee_TeamInfo) GetYellowCards() uint32 {
+ if x != nil && x.YellowCards != nil {
+ return *x.YellowCards
+ }
+ return 0
+}
+
+func (x *Referee_TeamInfo) GetTimeouts() uint32 {
+ if x != nil && x.Timeouts != nil {
+ return *x.Timeouts
+ }
+ return 0
+}
+
+func (x *Referee_TeamInfo) GetTimeoutTime() uint32 {
+ if x != nil && x.TimeoutTime != nil {
+ return *x.TimeoutTime
+ }
+ return 0
+}
+
+func (x *Referee_TeamInfo) GetGoalkeeper() uint32 {
+ if x != nil && x.Goalkeeper != nil {
+ return *x.Goalkeeper
+ }
+ return 0
+}
+
+func (x *Referee_TeamInfo) GetFoulCounter() uint32 {
+ if x != nil && x.FoulCounter != nil {
+ return *x.FoulCounter
+ }
+ return 0
+}
+
+func (x *Referee_TeamInfo) GetBallPlacementFailures() uint32 {
+ if x != nil && x.BallPlacementFailures != nil {
+ return *x.BallPlacementFailures
+ }
+ return 0
+}
+
+func (x *Referee_TeamInfo) GetCanPlaceBall() bool {
+ if x != nil && x.CanPlaceBall != nil {
+ return *x.CanPlaceBall
+ }
+ return false
+}
+
+func (x *Referee_TeamInfo) GetMaxAllowedBots() uint32 {
+ if x != nil && x.MaxAllowedBots != nil {
+ return *x.MaxAllowedBots
+ }
+ return 0
+}
+
+func (x *Referee_TeamInfo) GetBotSubstitutionIntent() bool {
+ if x != nil && x.BotSubstitutionIntent != nil {
+ return *x.BotSubstitutionIntent
+ }
+ return false
+}
+
+func (x *Referee_TeamInfo) GetBallPlacementFailuresReached() bool {
+ if x != nil && x.BallPlacementFailuresReached != nil {
+ return *x.BallPlacementFailuresReached
+ }
+ return false
+}
+
+func (x *Referee_TeamInfo) GetBotSubstitutionAllowed() bool {
+ if x != nil && x.BotSubstitutionAllowed != nil {
+ return *x.BotSubstitutionAllowed
+ }
+ return false
+}
+
+func (x *Referee_TeamInfo) GetBotSubstitutionsLeft() uint32 {
+ if x != nil && x.BotSubstitutionsLeft != nil {
+ return *x.BotSubstitutionsLeft
+ }
+ return 0
+}
+
+func (x *Referee_TeamInfo) GetBotSubstitutionTimeLeft() uint32 {
+ if x != nil && x.BotSubstitutionTimeLeft != nil {
+ return *x.BotSubstitutionTimeLeft
+ }
+ return 0
+}
+
+func (x *Referee_TeamInfo) GetHullColor() HullColor {
+ if x != nil && x.HullColor != nil {
+ return *x.HullColor
+ }
+ return HullColor_HULL_COLOR_UNKNOWN
+}
+
+// The coordinates of the Designated Position. These are measured in
+// millimetres and correspond to SSL-Vision coordinates. These fields are
+// always either both present (in the case of a ball placement command) or
+// both absent (in the case of any other command).
+type Referee_Point struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ X *float32 `protobuf:"fixed32,1,req,name=x" json:"x,omitempty"`
+ Y *float32 `protobuf:"fixed32,2,req,name=y" json:"y,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *Referee_Point) Reset() {
+ *x = Referee_Point{}
+ mi := &file_gamecontroller_ssl_gc_referee_message_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *Referee_Point) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Referee_Point) ProtoMessage() {}
+
+func (x *Referee_Point) ProtoReflect() protoreflect.Message {
+ mi := &file_gamecontroller_ssl_gc_referee_message_proto_msgTypes[3]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Referee_Point.ProtoReflect.Descriptor instead.
+func (*Referee_Point) Descriptor() ([]byte, []int) {
+ return file_gamecontroller_ssl_gc_referee_message_proto_rawDescGZIP(), []int{0, 1}
+}
+
+func (x *Referee_Point) GetX() float32 {
+ if x != nil && x.X != nil {
+ return *x.X
+ }
+ return 0
+}
+
+func (x *Referee_Point) GetY() float32 {
+ if x != nil && x.Y != nil {
+ return *x.Y
+ }
+ return 0
+}
+
+var File_gamecontroller_ssl_gc_referee_message_proto protoreflect.FileDescriptor
+
+const file_gamecontroller_ssl_gc_referee_message_proto_rawDesc = "" +
+ "\n" +
+ "+gamecontroller/ssl_gc_referee_message.proto\x1a&gamecontroller/ssl_gc_game_event.proto\"\xfd\x12\n" +
+ "\aReferee\x12+\n" +
+ "\x11source_identifier\x18\x12 \x01(\tR\x10sourceIdentifier\x128\n" +
+ "\n" +
+ "match_type\x18\x13 \x01(\x0e2\n" +
+ ".MatchType:\rUNKNOWN_MATCHR\tmatchType\x12)\n" +
+ "\x10packet_timestamp\x18\x01 \x02(\x04R\x0fpacketTimestamp\x12$\n" +
+ "\x05stage\x18\x02 \x02(\x0e2\x0e.Referee.StageR\x05stage\x12&\n" +
+ "\x0fstage_time_left\x18\x03 \x01(\x12R\rstageTimeLeft\x12*\n" +
+ "\acommand\x18\x04 \x02(\x0e2\x10.Referee.CommandR\acommand\x12'\n" +
+ "\x0fcommand_counter\x18\x05 \x02(\rR\x0ecommandCounter\x12+\n" +
+ "\x11command_timestamp\x18\x06 \x02(\x04R\x10commandTimestamp\x12)\n" +
+ "\x06yellow\x18\a \x02(\v2\x11.Referee.TeamInfoR\x06yellow\x12%\n" +
+ "\x04blue\x18\b \x02(\v2\x11.Referee.TeamInfoR\x04blue\x12?\n" +
+ "\x13designated_position\x18\t \x01(\v2\x0e.Referee.PointR\x12designatedPosition\x12:\n" +
+ "\x1ablue_team_on_positive_half\x18\n" +
+ " \x01(\bR\x16blueTeamOnPositiveHalf\x123\n" +
+ "\fnext_command\x18\f \x01(\x0e2\x10.Referee.CommandR\vnextCommand\x12+\n" +
+ "\vgame_events\x18\x10 \x03(\v2\n" +
+ ".GameEventR\n" +
+ "gameEvents\x12I\n" +
+ "\x14game_event_proposals\x18\x11 \x03(\v2\x17.GameEventProposalGroupR\x12gameEventProposals\x12A\n" +
+ "\x1dcurrent_action_time_remaining\x18\x0f \x01(\x03R\x1acurrentActionTimeRemaining\x12%\n" +
+ "\x0estatus_message\x18\x14 \x01(\tR\rstatusMessage\x1a\x85\x06\n" +
+ "\bTeamInfo\x12\x12\n" +
+ "\x04name\x18\x01 \x02(\tR\x04name\x12\x14\n" +
+ "\x05score\x18\x02 \x02(\rR\x05score\x12\x1b\n" +
+ "\tred_cards\x18\x03 \x02(\rR\bredCards\x12.\n" +
+ "\x11yellow_card_times\x18\x04 \x03(\rB\x02\x10\x01R\x0fyellowCardTimes\x12!\n" +
+ "\fyellow_cards\x18\x05 \x02(\rR\vyellowCards\x12\x1a\n" +
+ "\btimeouts\x18\x06 \x02(\rR\btimeouts\x12!\n" +
+ "\ftimeout_time\x18\a \x02(\rR\vtimeoutTime\x12\x1e\n" +
+ "\n" +
+ "goalkeeper\x18\b \x02(\rR\n" +
+ "goalkeeper\x12!\n" +
+ "\ffoul_counter\x18\t \x01(\rR\vfoulCounter\x126\n" +
+ "\x17ball_placement_failures\x18\n" +
+ " \x01(\rR\x15ballPlacementFailures\x12$\n" +
+ "\x0ecan_place_ball\x18\f \x01(\bR\fcanPlaceBall\x12(\n" +
+ "\x10max_allowed_bots\x18\r \x01(\rR\x0emaxAllowedBots\x126\n" +
+ "\x17bot_substitution_intent\x18\x0e \x01(\bR\x15botSubstitutionIntent\x12E\n" +
+ "\x1fball_placement_failures_reached\x18\x0f \x01(\bR\x1cballPlacementFailuresReached\x128\n" +
+ "\x18bot_substitution_allowed\x18\x10 \x01(\bR\x16botSubstitutionAllowed\x124\n" +
+ "\x16bot_substitutions_left\x18\x11 \x01(\rR\x14botSubstitutionsLeft\x12;\n" +
+ "\x1abot_substitution_time_left\x18\x12 \x01(\rR\x17botSubstitutionTimeLeft\x12)\n" +
+ "\n" +
+ "hull_color\x18\x13 \x01(\x0e2\n" +
+ ".HullColorR\thullColor\x1a#\n" +
+ "\x05Point\x12\f\n" +
+ "\x01x\x18\x01 \x02(\x02R\x01x\x12\f\n" +
+ "\x01y\x18\x02 \x02(\x02R\x01y\"\xd1\x02\n" +
+ "\x05Stage\x12\x19\n" +
+ "\x15NORMAL_FIRST_HALF_PRE\x10\x00\x12\x15\n" +
+ "\x11NORMAL_FIRST_HALF\x10\x01\x12\x14\n" +
+ "\x10NORMAL_HALF_TIME\x10\x02\x12\x1a\n" +
+ "\x16NORMAL_SECOND_HALF_PRE\x10\x03\x12\x16\n" +
+ "\x12NORMAL_SECOND_HALF\x10\x04\x12\x14\n" +
+ "\x10EXTRA_TIME_BREAK\x10\x05\x12\x18\n" +
+ "\x14EXTRA_FIRST_HALF_PRE\x10\x06\x12\x14\n" +
+ "\x10EXTRA_FIRST_HALF\x10\a\x12\x13\n" +
+ "\x0fEXTRA_HALF_TIME\x10\b\x12\x19\n" +
+ "\x15EXTRA_SECOND_HALF_PRE\x10\t\x12\x15\n" +
+ "\x11EXTRA_SECOND_HALF\x10\n" +
+ "\x12\x1a\n" +
+ "\x16PENALTY_SHOOTOUT_BREAK\x10\v\x12\x14\n" +
+ "\x10PENALTY_SHOOTOUT\x10\f\x12\r\n" +
+ "\tPOST_GAME\x10\r\"\x96\x03\n" +
+ "\aCommand\x12\b\n" +
+ "\x04HALT\x10\x00\x12\b\n" +
+ "\x04STOP\x10\x01\x12\x10\n" +
+ "\fNORMAL_START\x10\x02\x12\x0f\n" +
+ "\vFORCE_START\x10\x03\x12\x1a\n" +
+ "\x16PREPARE_KICKOFF_YELLOW\x10\x04\x12\x18\n" +
+ "\x14PREPARE_KICKOFF_BLUE\x10\x05\x12\x1a\n" +
+ "\x16PREPARE_PENALTY_YELLOW\x10\x06\x12\x18\n" +
+ "\x14PREPARE_PENALTY_BLUE\x10\a\x12\x16\n" +
+ "\x12DIRECT_FREE_YELLOW\x10\b\x12\x14\n" +
+ "\x10DIRECT_FREE_BLUE\x10\t\x12\x1c\n" +
+ "\x14INDIRECT_FREE_YELLOW\x10\n" +
+ "\x1a\x02\b\x01\x12\x1a\n" +
+ "\x12INDIRECT_FREE_BLUE\x10\v\x1a\x02\b\x01\x12\x12\n" +
+ "\x0eTIMEOUT_YELLOW\x10\f\x12\x10\n" +
+ "\fTIMEOUT_BLUE\x10\r\x12\x13\n" +
+ "\vGOAL_YELLOW\x10\x0e\x1a\x02\b\x01\x12\x11\n" +
+ "\tGOAL_BLUE\x10\x0f\x1a\x02\b\x01\x12\x19\n" +
+ "\x15BALL_PLACEMENT_YELLOW\x10\x10\x12\x17\n" +
+ "\x13BALL_PLACEMENT_BLUE\x10\x11J\x04\b\v\x10\fJ\x04\b\r\x10\x0eJ\x04\b\x0e\x10\x0f\"q\n" +
+ "\x16GameEventProposalGroup\x12\x0e\n" +
+ "\x02id\x18\x03 \x01(\tR\x02id\x12+\n" +
+ "\vgame_events\x18\x01 \x03(\v2\n" +
+ ".GameEventR\n" +
+ "gameEvents\x12\x1a\n" +
+ "\baccepted\x18\x02 \x01(\bR\baccepted*T\n" +
+ "\tMatchType\x12\x11\n" +
+ "\rUNKNOWN_MATCH\x10\x00\x12\x0f\n" +
+ "\vGROUP_PHASE\x10\x01\x12\x15\n" +
+ "\x11ELIMINATION_PHASE\x10\x02\x12\f\n" +
+ "\bFRIENDLY\x10\x03*N\n" +
+ "\tHullColor\x12\x16\n" +
+ "\x12HULL_COLOR_UNKNOWN\x10\x00\x12\x13\n" +
+ "\x0fHULL_COLOR_DARK\x10\x01\x12\x14\n" +
+ "\x10HULL_COLOR_LIGHT\x10\x02BeB\x18SslGcRefereeMessageProtoP\x01ZGgithub.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
+
+var (
+ file_gamecontroller_ssl_gc_referee_message_proto_rawDescOnce sync.Once
+ file_gamecontroller_ssl_gc_referee_message_proto_rawDescData []byte
+)
+
+func file_gamecontroller_ssl_gc_referee_message_proto_rawDescGZIP() []byte {
+ file_gamecontroller_ssl_gc_referee_message_proto_rawDescOnce.Do(func() {
+ file_gamecontroller_ssl_gc_referee_message_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_referee_message_proto_rawDesc), len(file_gamecontroller_ssl_gc_referee_message_proto_rawDesc)))
+ })
+ return file_gamecontroller_ssl_gc_referee_message_proto_rawDescData
+}
+
+var file_gamecontroller_ssl_gc_referee_message_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
+var file_gamecontroller_ssl_gc_referee_message_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
+var file_gamecontroller_ssl_gc_referee_message_proto_goTypes = []any{
+ (MatchType)(0), // 0: MatchType
+ (HullColor)(0), // 1: HullColor
+ (Referee_Stage)(0), // 2: Referee.Stage
+ (Referee_Command)(0), // 3: Referee.Command
+ (*Referee)(nil), // 4: Referee
+ (*GameEventProposalGroup)(nil), // 5: GameEventProposalGroup
+ (*Referee_TeamInfo)(nil), // 6: Referee.TeamInfo
+ (*Referee_Point)(nil), // 7: Referee.Point
+ (*GameEvent)(nil), // 8: GameEvent
+}
+var file_gamecontroller_ssl_gc_referee_message_proto_depIdxs = []int32{
+ 0, // 0: Referee.match_type:type_name -> MatchType
+ 2, // 1: Referee.stage:type_name -> Referee.Stage
+ 3, // 2: Referee.command:type_name -> Referee.Command
+ 6, // 3: Referee.yellow:type_name -> Referee.TeamInfo
+ 6, // 4: Referee.blue:type_name -> Referee.TeamInfo
+ 7, // 5: Referee.designated_position:type_name -> Referee.Point
+ 3, // 6: Referee.next_command:type_name -> Referee.Command
+ 8, // 7: Referee.game_events:type_name -> GameEvent
+ 5, // 8: Referee.game_event_proposals:type_name -> GameEventProposalGroup
+ 8, // 9: GameEventProposalGroup.game_events:type_name -> GameEvent
+ 1, // 10: Referee.TeamInfo.hull_color:type_name -> HullColor
+ 11, // [11:11] is the sub-list for method output_type
+ 11, // [11:11] is the sub-list for method input_type
+ 11, // [11:11] is the sub-list for extension type_name
+ 11, // [11:11] is the sub-list for extension extendee
+ 0, // [0:11] is the sub-list for field type_name
+}
+
+func init() { file_gamecontroller_ssl_gc_referee_message_proto_init() }
+func file_gamecontroller_ssl_gc_referee_message_proto_init() {
+ if File_gamecontroller_ssl_gc_referee_message_proto != nil {
+ return
+ }
+ file_gamecontroller_ssl_gc_game_event_proto_init()
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_referee_message_proto_rawDesc), len(file_gamecontroller_ssl_gc_referee_message_proto_rawDesc)),
+ NumEnums: 4,
+ NumMessages: 4,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_gamecontroller_ssl_gc_referee_message_proto_goTypes,
+ DependencyIndexes: file_gamecontroller_ssl_gc_referee_message_proto_depIdxs,
+ EnumInfos: file_gamecontroller_ssl_gc_referee_message_proto_enumTypes,
+ MessageInfos: file_gamecontroller_ssl_gc_referee_message_proto_msgTypes,
+ }.Build()
+ File_gamecontroller_ssl_gc_referee_message_proto = out.File
+ file_gamecontroller_ssl_gc_referee_message_proto_goTypes = nil
+ file_gamecontroller_ssl_gc_referee_message_proto_depIdxs = nil
+}
diff --git a/gui/internal/vision/ssl_vision_detection.pb.go b/gui/internal/vision/ssl_vision_detection.pb.go
new file mode 100644
index 0000000..040f87a
--- /dev/null
+++ b/gui/internal/vision/ssl_vision_detection.pb.go
@@ -0,0 +1,439 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.36.6
+// protoc (unknown)
+// source: vision/ssl_vision_detection.proto
+
+package vision
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+ unsafe "unsafe"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type SSL_DetectionBall struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Confidence in [0-1] of the detection
+ Confidence *float32 `protobuf:"fixed32,1,req,name=confidence" json:"confidence,omitempty"`
+ Area *uint32 `protobuf:"varint,2,opt,name=area" json:"area,omitempty"`
+ // X-coordinate in [mm] in global ssl-vision coordinate system
+ X *float32 `protobuf:"fixed32,3,req,name=x" json:"x,omitempty"`
+ // Y-coordinate in [mm] in global ssl-vision coordinate system
+ Y *float32 `protobuf:"fixed32,4,req,name=y" json:"y,omitempty"`
+ // Z-coordinate in [mm] in global ssl-vision coordinate system
+ // Not supported by ssl-vision, but might be set by simulators
+ Z *float32 `protobuf:"fixed32,5,opt,name=z" json:"z,omitempty"`
+ // X-coordinate in [pixel] in the image
+ PixelX *float32 `protobuf:"fixed32,6,req,name=pixel_x,json=pixelX" json:"pixel_x,omitempty"`
+ // Y-coordinate in [pixel] in the image
+ PixelY *float32 `protobuf:"fixed32,7,req,name=pixel_y,json=pixelY" json:"pixel_y,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SSL_DetectionBall) Reset() {
+ *x = SSL_DetectionBall{}
+ mi := &file_vision_ssl_vision_detection_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_DetectionBall) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_DetectionBall) ProtoMessage() {}
+
+func (x *SSL_DetectionBall) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vision_detection_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_DetectionBall.ProtoReflect.Descriptor instead.
+func (*SSL_DetectionBall) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_detection_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *SSL_DetectionBall) GetConfidence() float32 {
+ if x != nil && x.Confidence != nil {
+ return *x.Confidence
+ }
+ return 0
+}
+
+func (x *SSL_DetectionBall) GetArea() uint32 {
+ if x != nil && x.Area != nil {
+ return *x.Area
+ }
+ return 0
+}
+
+func (x *SSL_DetectionBall) GetX() float32 {
+ if x != nil && x.X != nil {
+ return *x.X
+ }
+ return 0
+}
+
+func (x *SSL_DetectionBall) GetY() float32 {
+ if x != nil && x.Y != nil {
+ return *x.Y
+ }
+ return 0
+}
+
+func (x *SSL_DetectionBall) GetZ() float32 {
+ if x != nil && x.Z != nil {
+ return *x.Z
+ }
+ return 0
+}
+
+func (x *SSL_DetectionBall) GetPixelX() float32 {
+ if x != nil && x.PixelX != nil {
+ return *x.PixelX
+ }
+ return 0
+}
+
+func (x *SSL_DetectionBall) GetPixelY() float32 {
+ if x != nil && x.PixelY != nil {
+ return *x.PixelY
+ }
+ return 0
+}
+
+type SSL_DetectionRobot struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Confidence in [0-1] of the detection
+ Confidence *float32 `protobuf:"fixed32,1,req,name=confidence" json:"confidence,omitempty"`
+ // Id of the robot
+ RobotId *uint32 `protobuf:"varint,2,opt,name=robot_id,json=robotId" json:"robot_id,omitempty"`
+ // X-coordinate in [mm] in global ssl-vision coordinate system
+ X *float32 `protobuf:"fixed32,3,req,name=x" json:"x,omitempty"`
+ // Y-coordinate in [mm] in global ssl-vision coordinate system
+ Y *float32 `protobuf:"fixed32,4,req,name=y" json:"y,omitempty"`
+ // Orientation in [rad]
+ Orientation *float32 `protobuf:"fixed32,5,opt,name=orientation" json:"orientation,omitempty"`
+ // X-coordinate in [pixel] in the image
+ PixelX *float32 `protobuf:"fixed32,6,req,name=pixel_x,json=pixelX" json:"pixel_x,omitempty"`
+ // Y-coordinate in [pixel] in the image
+ PixelY *float32 `protobuf:"fixed32,7,req,name=pixel_y,json=pixelY" json:"pixel_y,omitempty"`
+ // Height, as configured in ssl-vision for the respective team
+ Height *float32 `protobuf:"fixed32,8,opt,name=height" json:"height,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SSL_DetectionRobot) Reset() {
+ *x = SSL_DetectionRobot{}
+ mi := &file_vision_ssl_vision_detection_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_DetectionRobot) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_DetectionRobot) ProtoMessage() {}
+
+func (x *SSL_DetectionRobot) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vision_detection_proto_msgTypes[1]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_DetectionRobot.ProtoReflect.Descriptor instead.
+func (*SSL_DetectionRobot) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_detection_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *SSL_DetectionRobot) GetConfidence() float32 {
+ if x != nil && x.Confidence != nil {
+ return *x.Confidence
+ }
+ return 0
+}
+
+func (x *SSL_DetectionRobot) GetRobotId() uint32 {
+ if x != nil && x.RobotId != nil {
+ return *x.RobotId
+ }
+ return 0
+}
+
+func (x *SSL_DetectionRobot) GetX() float32 {
+ if x != nil && x.X != nil {
+ return *x.X
+ }
+ return 0
+}
+
+func (x *SSL_DetectionRobot) GetY() float32 {
+ if x != nil && x.Y != nil {
+ return *x.Y
+ }
+ return 0
+}
+
+func (x *SSL_DetectionRobot) GetOrientation() float32 {
+ if x != nil && x.Orientation != nil {
+ return *x.Orientation
+ }
+ return 0
+}
+
+func (x *SSL_DetectionRobot) GetPixelX() float32 {
+ if x != nil && x.PixelX != nil {
+ return *x.PixelX
+ }
+ return 0
+}
+
+func (x *SSL_DetectionRobot) GetPixelY() float32 {
+ if x != nil && x.PixelY != nil {
+ return *x.PixelY
+ }
+ return 0
+}
+
+func (x *SSL_DetectionRobot) GetHeight() float32 {
+ if x != nil && x.Height != nil {
+ return *x.Height
+ }
+ return 0
+}
+
+type SSL_DetectionFrame struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // monotonously increasing frame number
+ FrameNumber *uint32 `protobuf:"varint,1,req,name=frame_number,json=frameNumber" json:"frame_number,omitempty"`
+ // Unix timestamp in [seconds] at which the image has been received by ssl-vision
+ TCapture *float64 `protobuf:"fixed64,2,req,name=t_capture,json=tCapture" json:"t_capture,omitempty"`
+ // Unix timestamp in [seconds] at which this message has been sent to the network
+ TSent *float64 `protobuf:"fixed64,3,req,name=t_sent,json=tSent" json:"t_sent,omitempty"`
+ // Camera timestamp in [seconds] as reported by the camera, if supported
+ // This is not necessarily a unix timestamp
+ TCaptureCamera *float64 `protobuf:"fixed64,8,opt,name=t_capture_camera,json=tCaptureCamera" json:"t_capture_camera,omitempty"`
+ // Internal VisionProcessor field for clock synchronization,
+ // containing the time offset of received packets for each cam relative to the local clock.
+ TOffsets []float32 `protobuf:"fixed32,9,rep,name=t_offsets,json=tOffsets" json:"t_offsets,omitempty"`
+ // Identifier of the camera
+ CameraId *uint32 `protobuf:"varint,4,req,name=camera_id,json=cameraId" json:"camera_id,omitempty"`
+ // Detected balls
+ Balls []*SSL_DetectionBall `protobuf:"bytes,5,rep,name=balls" json:"balls,omitempty"`
+ // Detected yellow robots
+ RobotsYellow []*SSL_DetectionRobot `protobuf:"bytes,6,rep,name=robots_yellow,json=robotsYellow" json:"robots_yellow,omitempty"`
+ // Detected blue robots
+ RobotsBlue []*SSL_DetectionRobot `protobuf:"bytes,7,rep,name=robots_blue,json=robotsBlue" json:"robots_blue,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SSL_DetectionFrame) Reset() {
+ *x = SSL_DetectionFrame{}
+ mi := &file_vision_ssl_vision_detection_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_DetectionFrame) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_DetectionFrame) ProtoMessage() {}
+
+func (x *SSL_DetectionFrame) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vision_detection_proto_msgTypes[2]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_DetectionFrame.ProtoReflect.Descriptor instead.
+func (*SSL_DetectionFrame) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_detection_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *SSL_DetectionFrame) GetFrameNumber() uint32 {
+ if x != nil && x.FrameNumber != nil {
+ return *x.FrameNumber
+ }
+ return 0
+}
+
+func (x *SSL_DetectionFrame) GetTCapture() float64 {
+ if x != nil && x.TCapture != nil {
+ return *x.TCapture
+ }
+ return 0
+}
+
+func (x *SSL_DetectionFrame) GetTSent() float64 {
+ if x != nil && x.TSent != nil {
+ return *x.TSent
+ }
+ return 0
+}
+
+func (x *SSL_DetectionFrame) GetTCaptureCamera() float64 {
+ if x != nil && x.TCaptureCamera != nil {
+ return *x.TCaptureCamera
+ }
+ return 0
+}
+
+func (x *SSL_DetectionFrame) GetTOffsets() []float32 {
+ if x != nil {
+ return x.TOffsets
+ }
+ return nil
+}
+
+func (x *SSL_DetectionFrame) GetCameraId() uint32 {
+ if x != nil && x.CameraId != nil {
+ return *x.CameraId
+ }
+ return 0
+}
+
+func (x *SSL_DetectionFrame) GetBalls() []*SSL_DetectionBall {
+ if x != nil {
+ return x.Balls
+ }
+ return nil
+}
+
+func (x *SSL_DetectionFrame) GetRobotsYellow() []*SSL_DetectionRobot {
+ if x != nil {
+ return x.RobotsYellow
+ }
+ return nil
+}
+
+func (x *SSL_DetectionFrame) GetRobotsBlue() []*SSL_DetectionRobot {
+ if x != nil {
+ return x.RobotsBlue
+ }
+ return nil
+}
+
+var File_vision_ssl_vision_detection_proto protoreflect.FileDescriptor
+
+const file_vision_ssl_vision_detection_proto_rawDesc = "" +
+ "\n" +
+ "!vision/ssl_vision_detection.proto\"\xa3\x01\n" +
+ "\x11SSL_DetectionBall\x12\x1e\n" +
+ "\n" +
+ "confidence\x18\x01 \x02(\x02R\n" +
+ "confidence\x12\x12\n" +
+ "\x04area\x18\x02 \x01(\rR\x04area\x12\f\n" +
+ "\x01x\x18\x03 \x02(\x02R\x01x\x12\f\n" +
+ "\x01y\x18\x04 \x02(\x02R\x01y\x12\f\n" +
+ "\x01z\x18\x05 \x01(\x02R\x01z\x12\x17\n" +
+ "\apixel_x\x18\x06 \x02(\x02R\x06pixelX\x12\x17\n" +
+ "\apixel_y\x18\a \x02(\x02R\x06pixelY\"\xd7\x01\n" +
+ "\x12SSL_DetectionRobot\x12\x1e\n" +
+ "\n" +
+ "confidence\x18\x01 \x02(\x02R\n" +
+ "confidence\x12\x19\n" +
+ "\brobot_id\x18\x02 \x01(\rR\arobotId\x12\f\n" +
+ "\x01x\x18\x03 \x02(\x02R\x01x\x12\f\n" +
+ "\x01y\x18\x04 \x02(\x02R\x01y\x12 \n" +
+ "\vorientation\x18\x05 \x01(\x02R\vorientation\x12\x17\n" +
+ "\apixel_x\x18\x06 \x02(\x02R\x06pixelX\x12\x17\n" +
+ "\apixel_y\x18\a \x02(\x02R\x06pixelY\x12\x16\n" +
+ "\x06height\x18\b \x01(\x02R\x06height\"\xe9\x02\n" +
+ "\x12SSL_DetectionFrame\x12!\n" +
+ "\fframe_number\x18\x01 \x02(\rR\vframeNumber\x12\x1b\n" +
+ "\tt_capture\x18\x02 \x02(\x01R\btCapture\x12\x15\n" +
+ "\x06t_sent\x18\x03 \x02(\x01R\x05tSent\x12(\n" +
+ "\x10t_capture_camera\x18\b \x01(\x01R\x0etCaptureCamera\x12\x1b\n" +
+ "\tt_offsets\x18\t \x03(\x02R\btOffsets\x12\x1b\n" +
+ "\tcamera_id\x18\x04 \x02(\rR\bcameraId\x12(\n" +
+ "\x05balls\x18\x05 \x03(\v2\x12.SSL_DetectionBallR\x05balls\x128\n" +
+ "\rrobots_yellow\x18\x06 \x03(\v2\x13.SSL_DetectionRobotR\frobotsYellow\x124\n" +
+ "\vrobots_blue\x18\a \x03(\v2\x13.SSL_DetectionRobotR\n" +
+ "robotsBlueB\\B\x17SslVisionDetectionProtoP\x01Z?github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
+
+var (
+ file_vision_ssl_vision_detection_proto_rawDescOnce sync.Once
+ file_vision_ssl_vision_detection_proto_rawDescData []byte
+)
+
+func file_vision_ssl_vision_detection_proto_rawDescGZIP() []byte {
+ file_vision_ssl_vision_detection_proto_rawDescOnce.Do(func() {
+ file_vision_ssl_vision_detection_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_detection_proto_rawDesc), len(file_vision_ssl_vision_detection_proto_rawDesc)))
+ })
+ return file_vision_ssl_vision_detection_proto_rawDescData
+}
+
+var file_vision_ssl_vision_detection_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
+var file_vision_ssl_vision_detection_proto_goTypes = []any{
+ (*SSL_DetectionBall)(nil), // 0: SSL_DetectionBall
+ (*SSL_DetectionRobot)(nil), // 1: SSL_DetectionRobot
+ (*SSL_DetectionFrame)(nil), // 2: SSL_DetectionFrame
+}
+var file_vision_ssl_vision_detection_proto_depIdxs = []int32{
+ 0, // 0: SSL_DetectionFrame.balls:type_name -> SSL_DetectionBall
+ 1, // 1: SSL_DetectionFrame.robots_yellow:type_name -> SSL_DetectionRobot
+ 1, // 2: SSL_DetectionFrame.robots_blue:type_name -> SSL_DetectionRobot
+ 3, // [3:3] is the sub-list for method output_type
+ 3, // [3:3] is the sub-list for method input_type
+ 3, // [3:3] is the sub-list for extension type_name
+ 3, // [3:3] is the sub-list for extension extendee
+ 0, // [0:3] is the sub-list for field type_name
+}
+
+func init() { file_vision_ssl_vision_detection_proto_init() }
+func file_vision_ssl_vision_detection_proto_init() {
+ if File_vision_ssl_vision_detection_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_detection_proto_rawDesc), len(file_vision_ssl_vision_detection_proto_rawDesc)),
+ NumEnums: 0,
+ NumMessages: 3,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_vision_ssl_vision_detection_proto_goTypes,
+ DependencyIndexes: file_vision_ssl_vision_detection_proto_depIdxs,
+ MessageInfos: file_vision_ssl_vision_detection_proto_msgTypes,
+ }.Build()
+ File_vision_ssl_vision_detection_proto = out.File
+ file_vision_ssl_vision_detection_proto_goTypes = nil
+ file_vision_ssl_vision_detection_proto_depIdxs = nil
+}
diff --git a/gui/internal/vision/ssl_vision_detection_tracked.pb.go b/gui/internal/vision/ssl_vision_detection_tracked.pb.go
new file mode 100644
index 0000000..d0b462a
--- /dev/null
+++ b/gui/internal/vision/ssl_vision_detection_tracked.pb.go
@@ -0,0 +1,544 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.36.6
+// protoc (unknown)
+// source: vision/ssl_vision_detection_tracked.proto
+
+package vision
+
+import (
+ gamecontroller "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+ unsafe "unsafe"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// Capabilities that a source implementation can have
+type Capability int32
+
+const (
+ Capability_CAPABILITY_UNKNOWN Capability = 0
+ Capability_CAPABILITY_DETECT_FLYING_BALLS Capability = 1
+ Capability_CAPABILITY_DETECT_MULTIPLE_BALLS Capability = 2
+ Capability_CAPABILITY_DETECT_KICKED_BALLS Capability = 3
+)
+
+// Enum value maps for Capability.
+var (
+ Capability_name = map[int32]string{
+ 0: "CAPABILITY_UNKNOWN",
+ 1: "CAPABILITY_DETECT_FLYING_BALLS",
+ 2: "CAPABILITY_DETECT_MULTIPLE_BALLS",
+ 3: "CAPABILITY_DETECT_KICKED_BALLS",
+ }
+ Capability_value = map[string]int32{
+ "CAPABILITY_UNKNOWN": 0,
+ "CAPABILITY_DETECT_FLYING_BALLS": 1,
+ "CAPABILITY_DETECT_MULTIPLE_BALLS": 2,
+ "CAPABILITY_DETECT_KICKED_BALLS": 3,
+ }
+)
+
+func (x Capability) Enum() *Capability {
+ p := new(Capability)
+ *p = x
+ return p
+}
+
+func (x Capability) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Capability) Descriptor() protoreflect.EnumDescriptor {
+ return file_vision_ssl_vision_detection_tracked_proto_enumTypes[0].Descriptor()
+}
+
+func (Capability) Type() protoreflect.EnumType {
+ return &file_vision_ssl_vision_detection_tracked_proto_enumTypes[0]
+}
+
+func (x Capability) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *Capability) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = Capability(num)
+ return nil
+}
+
+// Deprecated: Use Capability.Descriptor instead.
+func (Capability) EnumDescriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_detection_tracked_proto_rawDescGZIP(), []int{0}
+}
+
+// A single tracked ball
+type TrackedBall struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // The position (x, y, height) [m] in the ssl-vision coordinate system
+ Pos *gamecontroller.Vector3 `protobuf:"bytes,1,req,name=pos" json:"pos,omitempty"`
+ // The velocity [m/s] in the ssl-vision coordinate system
+ Vel *gamecontroller.Vector3 `protobuf:"bytes,2,opt,name=vel" json:"vel,omitempty"`
+ // The visibility of the ball
+ // A value between 0 (not visible) and 1 (visible)
+ // The exact implementation depends on the source software
+ Visibility *float32 `protobuf:"fixed32,3,opt,name=visibility" json:"visibility,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *TrackedBall) Reset() {
+ *x = TrackedBall{}
+ mi := &file_vision_ssl_vision_detection_tracked_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *TrackedBall) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TrackedBall) ProtoMessage() {}
+
+func (x *TrackedBall) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vision_detection_tracked_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TrackedBall.ProtoReflect.Descriptor instead.
+func (*TrackedBall) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_detection_tracked_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *TrackedBall) GetPos() *gamecontroller.Vector3 {
+ if x != nil {
+ return x.Pos
+ }
+ return nil
+}
+
+func (x *TrackedBall) GetVel() *gamecontroller.Vector3 {
+ if x != nil {
+ return x.Vel
+ }
+ return nil
+}
+
+func (x *TrackedBall) GetVisibility() float32 {
+ if x != nil && x.Visibility != nil {
+ return *x.Visibility
+ }
+ return 0
+}
+
+// A ball kicked by a robot, including predictions when the ball will come to a stop
+type KickedBall struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // The initial position [m] from which the ball was kicked
+ Pos *gamecontroller.Vector2 `protobuf:"bytes,1,req,name=pos" json:"pos,omitempty"`
+ // The initial velocity [m/s] with which the ball was kicked
+ Vel *gamecontroller.Vector3 `protobuf:"bytes,2,req,name=vel" json:"vel,omitempty"`
+ // The unix timestamp [s] when the kick was performed
+ StartTimestamp *float64 `protobuf:"fixed64,3,req,name=start_timestamp,json=startTimestamp" json:"start_timestamp,omitempty"`
+ // The predicted unix timestamp [s] when the ball comes to a stop
+ StopTimestamp *float64 `protobuf:"fixed64,4,opt,name=stop_timestamp,json=stopTimestamp" json:"stop_timestamp,omitempty"`
+ // The predicted position [m] at which the ball will come to a stop
+ StopPos *gamecontroller.Vector2 `protobuf:"bytes,5,opt,name=stop_pos,json=stopPos" json:"stop_pos,omitempty"`
+ // The robot that kicked the ball
+ RobotId *gamecontroller.RobotId `protobuf:"bytes,6,opt,name=robot_id,json=robotId" json:"robot_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *KickedBall) Reset() {
+ *x = KickedBall{}
+ mi := &file_vision_ssl_vision_detection_tracked_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *KickedBall) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*KickedBall) ProtoMessage() {}
+
+func (x *KickedBall) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vision_detection_tracked_proto_msgTypes[1]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use KickedBall.ProtoReflect.Descriptor instead.
+func (*KickedBall) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_detection_tracked_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *KickedBall) GetPos() *gamecontroller.Vector2 {
+ if x != nil {
+ return x.Pos
+ }
+ return nil
+}
+
+func (x *KickedBall) GetVel() *gamecontroller.Vector3 {
+ if x != nil {
+ return x.Vel
+ }
+ return nil
+}
+
+func (x *KickedBall) GetStartTimestamp() float64 {
+ if x != nil && x.StartTimestamp != nil {
+ return *x.StartTimestamp
+ }
+ return 0
+}
+
+func (x *KickedBall) GetStopTimestamp() float64 {
+ if x != nil && x.StopTimestamp != nil {
+ return *x.StopTimestamp
+ }
+ return 0
+}
+
+func (x *KickedBall) GetStopPos() *gamecontroller.Vector2 {
+ if x != nil {
+ return x.StopPos
+ }
+ return nil
+}
+
+func (x *KickedBall) GetRobotId() *gamecontroller.RobotId {
+ if x != nil {
+ return x.RobotId
+ }
+ return nil
+}
+
+// A single tracked robot
+type TrackedRobot struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ RobotId *gamecontroller.RobotId `protobuf:"bytes,1,req,name=robot_id,json=robotId" json:"robot_id,omitempty"`
+ // The position [m] in the ssl-vision coordinate system
+ Pos *gamecontroller.Vector2 `protobuf:"bytes,2,req,name=pos" json:"pos,omitempty"`
+ // The orientation [rad] in the ssl-vision coordinate system
+ Orientation *float32 `protobuf:"fixed32,3,req,name=orientation" json:"orientation,omitempty"`
+ // The velocity [m/s] in the ssl-vision coordinate system
+ Vel *gamecontroller.Vector2 `protobuf:"bytes,4,opt,name=vel" json:"vel,omitempty"`
+ // The angular velocity [rad/s] in the ssl-vision coordinate system
+ VelAngular *float32 `protobuf:"fixed32,5,opt,name=vel_angular,json=velAngular" json:"vel_angular,omitempty"`
+ // The visibility of the robot
+ // A value between 0 (not visible) and 1 (visible)
+ // The exact implementation depends on the source software
+ Visibility *float32 `protobuf:"fixed32,6,opt,name=visibility" json:"visibility,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *TrackedRobot) Reset() {
+ *x = TrackedRobot{}
+ mi := &file_vision_ssl_vision_detection_tracked_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *TrackedRobot) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TrackedRobot) ProtoMessage() {}
+
+func (x *TrackedRobot) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vision_detection_tracked_proto_msgTypes[2]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TrackedRobot.ProtoReflect.Descriptor instead.
+func (*TrackedRobot) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_detection_tracked_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *TrackedRobot) GetRobotId() *gamecontroller.RobotId {
+ if x != nil {
+ return x.RobotId
+ }
+ return nil
+}
+
+func (x *TrackedRobot) GetPos() *gamecontroller.Vector2 {
+ if x != nil {
+ return x.Pos
+ }
+ return nil
+}
+
+func (x *TrackedRobot) GetOrientation() float32 {
+ if x != nil && x.Orientation != nil {
+ return *x.Orientation
+ }
+ return 0
+}
+
+func (x *TrackedRobot) GetVel() *gamecontroller.Vector2 {
+ if x != nil {
+ return x.Vel
+ }
+ return nil
+}
+
+func (x *TrackedRobot) GetVelAngular() float32 {
+ if x != nil && x.VelAngular != nil {
+ return *x.VelAngular
+ }
+ return 0
+}
+
+func (x *TrackedRobot) GetVisibility() float32 {
+ if x != nil && x.Visibility != nil {
+ return *x.Visibility
+ }
+ return 0
+}
+
+// A frame that contains all currently tracked objects on the field on all cameras
+type TrackedFrame struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // A monotonous increasing frame counter
+ FrameNumber *uint32 `protobuf:"varint,1,req,name=frame_number,json=frameNumber" json:"frame_number,omitempty"`
+ // The unix timestamp in [s] of the data
+ // If timestamp is larger than timestamp_captured, the source has applied a prediction already
+ Timestamp *float64 `protobuf:"fixed64,2,req,name=timestamp" json:"timestamp,omitempty"`
+ // The list of detected balls
+ // The first ball is the primary one
+ // Sources may add additional balls based on their capabilities
+ Balls []*TrackedBall `protobuf:"bytes,3,rep,name=balls" json:"balls,omitempty"`
+ // The list of detected robots of both teams
+ Robots []*TrackedRobot `protobuf:"bytes,4,rep,name=robots" json:"robots,omitempty"`
+ // Information about a kicked ball, if the ball was kicked by a robot and is still moving
+ // Note: This field is optional. Some source implementations might not set this at any time
+ KickedBall *KickedBall `protobuf:"bytes,5,opt,name=kicked_ball,json=kickedBall" json:"kicked_ball,omitempty"`
+ // List of capabilities of the source implementation
+ Capabilities []Capability `protobuf:"varint,6,rep,name=capabilities,enum=Capability" json:"capabilities,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *TrackedFrame) Reset() {
+ *x = TrackedFrame{}
+ mi := &file_vision_ssl_vision_detection_tracked_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *TrackedFrame) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TrackedFrame) ProtoMessage() {}
+
+func (x *TrackedFrame) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vision_detection_tracked_proto_msgTypes[3]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TrackedFrame.ProtoReflect.Descriptor instead.
+func (*TrackedFrame) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_detection_tracked_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *TrackedFrame) GetFrameNumber() uint32 {
+ if x != nil && x.FrameNumber != nil {
+ return *x.FrameNumber
+ }
+ return 0
+}
+
+func (x *TrackedFrame) GetTimestamp() float64 {
+ if x != nil && x.Timestamp != nil {
+ return *x.Timestamp
+ }
+ return 0
+}
+
+func (x *TrackedFrame) GetBalls() []*TrackedBall {
+ if x != nil {
+ return x.Balls
+ }
+ return nil
+}
+
+func (x *TrackedFrame) GetRobots() []*TrackedRobot {
+ if x != nil {
+ return x.Robots
+ }
+ return nil
+}
+
+func (x *TrackedFrame) GetKickedBall() *KickedBall {
+ if x != nil {
+ return x.KickedBall
+ }
+ return nil
+}
+
+func (x *TrackedFrame) GetCapabilities() []Capability {
+ if x != nil {
+ return x.Capabilities
+ }
+ return nil
+}
+
+var File_vision_ssl_vision_detection_tracked_proto protoreflect.FileDescriptor
+
+const file_vision_ssl_vision_detection_tracked_proto_rawDesc = "" +
+ "\n" +
+ ")vision/ssl_vision_detection_tracked.proto\x1a\"gamecontroller/ssl_gc_common.proto\x1a$gamecontroller/ssl_gc_geometry.proto\"e\n" +
+ "\vTrackedBall\x12\x1a\n" +
+ "\x03pos\x18\x01 \x02(\v2\b.Vector3R\x03pos\x12\x1a\n" +
+ "\x03vel\x18\x02 \x01(\v2\b.Vector3R\x03vel\x12\x1e\n" +
+ "\n" +
+ "visibility\x18\x03 \x01(\x02R\n" +
+ "visibility\"\xde\x01\n" +
+ "\n" +
+ "KickedBall\x12\x1a\n" +
+ "\x03pos\x18\x01 \x02(\v2\b.Vector2R\x03pos\x12\x1a\n" +
+ "\x03vel\x18\x02 \x02(\v2\b.Vector3R\x03vel\x12'\n" +
+ "\x0fstart_timestamp\x18\x03 \x02(\x01R\x0estartTimestamp\x12%\n" +
+ "\x0estop_timestamp\x18\x04 \x01(\x01R\rstopTimestamp\x12#\n" +
+ "\bstop_pos\x18\x05 \x01(\v2\b.Vector2R\astopPos\x12#\n" +
+ "\brobot_id\x18\x06 \x01(\v2\b.RobotIdR\arobotId\"\xce\x01\n" +
+ "\fTrackedRobot\x12#\n" +
+ "\brobot_id\x18\x01 \x02(\v2\b.RobotIdR\arobotId\x12\x1a\n" +
+ "\x03pos\x18\x02 \x02(\v2\b.Vector2R\x03pos\x12 \n" +
+ "\vorientation\x18\x03 \x02(\x02R\vorientation\x12\x1a\n" +
+ "\x03vel\x18\x04 \x01(\v2\b.Vector2R\x03vel\x12\x1f\n" +
+ "\vvel_angular\x18\x05 \x01(\x02R\n" +
+ "velAngular\x12\x1e\n" +
+ "\n" +
+ "visibility\x18\x06 \x01(\x02R\n" +
+ "visibility\"\xf9\x01\n" +
+ "\fTrackedFrame\x12!\n" +
+ "\fframe_number\x18\x01 \x02(\rR\vframeNumber\x12\x1c\n" +
+ "\ttimestamp\x18\x02 \x02(\x01R\ttimestamp\x12\"\n" +
+ "\x05balls\x18\x03 \x03(\v2\f.TrackedBallR\x05balls\x12%\n" +
+ "\x06robots\x18\x04 \x03(\v2\r.TrackedRobotR\x06robots\x12,\n" +
+ "\vkicked_ball\x18\x05 \x01(\v2\v.KickedBallR\n" +
+ "kickedBall\x12/\n" +
+ "\fcapabilities\x18\x06 \x03(\x0e2\v.CapabilityR\fcapabilities*\x92\x01\n" +
+ "\n" +
+ "Capability\x12\x16\n" +
+ "\x12CAPABILITY_UNKNOWN\x10\x00\x12\"\n" +
+ "\x1eCAPABILITY_DETECT_FLYING_BALLS\x10\x01\x12$\n" +
+ " CAPABILITY_DETECT_MULTIPLE_BALLS\x10\x02\x12\"\n" +
+ "\x1eCAPABILITY_DETECT_KICKED_BALLS\x10\x03BcB\x1eSslVisionDetectionTrackedProtoP\x01Z?github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
+
+var (
+ file_vision_ssl_vision_detection_tracked_proto_rawDescOnce sync.Once
+ file_vision_ssl_vision_detection_tracked_proto_rawDescData []byte
+)
+
+func file_vision_ssl_vision_detection_tracked_proto_rawDescGZIP() []byte {
+ file_vision_ssl_vision_detection_tracked_proto_rawDescOnce.Do(func() {
+ file_vision_ssl_vision_detection_tracked_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_detection_tracked_proto_rawDesc), len(file_vision_ssl_vision_detection_tracked_proto_rawDesc)))
+ })
+ return file_vision_ssl_vision_detection_tracked_proto_rawDescData
+}
+
+var file_vision_ssl_vision_detection_tracked_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_vision_ssl_vision_detection_tracked_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
+var file_vision_ssl_vision_detection_tracked_proto_goTypes = []any{
+ (Capability)(0), // 0: Capability
+ (*TrackedBall)(nil), // 1: TrackedBall
+ (*KickedBall)(nil), // 2: KickedBall
+ (*TrackedRobot)(nil), // 3: TrackedRobot
+ (*TrackedFrame)(nil), // 4: TrackedFrame
+ (*gamecontroller.Vector3)(nil), // 5: Vector3
+ (*gamecontroller.Vector2)(nil), // 6: Vector2
+ (*gamecontroller.RobotId)(nil), // 7: RobotId
+}
+var file_vision_ssl_vision_detection_tracked_proto_depIdxs = []int32{
+ 5, // 0: TrackedBall.pos:type_name -> Vector3
+ 5, // 1: TrackedBall.vel:type_name -> Vector3
+ 6, // 2: KickedBall.pos:type_name -> Vector2
+ 5, // 3: KickedBall.vel:type_name -> Vector3
+ 6, // 4: KickedBall.stop_pos:type_name -> Vector2
+ 7, // 5: KickedBall.robot_id:type_name -> RobotId
+ 7, // 6: TrackedRobot.robot_id:type_name -> RobotId
+ 6, // 7: TrackedRobot.pos:type_name -> Vector2
+ 6, // 8: TrackedRobot.vel:type_name -> Vector2
+ 1, // 9: TrackedFrame.balls:type_name -> TrackedBall
+ 3, // 10: TrackedFrame.robots:type_name -> TrackedRobot
+ 2, // 11: TrackedFrame.kicked_ball:type_name -> KickedBall
+ 0, // 12: TrackedFrame.capabilities:type_name -> Capability
+ 13, // [13:13] is the sub-list for method output_type
+ 13, // [13:13] is the sub-list for method input_type
+ 13, // [13:13] is the sub-list for extension type_name
+ 13, // [13:13] is the sub-list for extension extendee
+ 0, // [0:13] is the sub-list for field type_name
+}
+
+func init() { file_vision_ssl_vision_detection_tracked_proto_init() }
+func file_vision_ssl_vision_detection_tracked_proto_init() {
+ if File_vision_ssl_vision_detection_tracked_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_detection_tracked_proto_rawDesc), len(file_vision_ssl_vision_detection_tracked_proto_rawDesc)),
+ NumEnums: 1,
+ NumMessages: 4,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_vision_ssl_vision_detection_tracked_proto_goTypes,
+ DependencyIndexes: file_vision_ssl_vision_detection_tracked_proto_depIdxs,
+ EnumInfos: file_vision_ssl_vision_detection_tracked_proto_enumTypes,
+ MessageInfos: file_vision_ssl_vision_detection_tracked_proto_msgTypes,
+ }.Build()
+ File_vision_ssl_vision_detection_tracked_proto = out.File
+ file_vision_ssl_vision_detection_tracked_proto_goTypes = nil
+ file_vision_ssl_vision_detection_tracked_proto_depIdxs = nil
+}
diff --git a/gui/internal/vision/ssl_vision_geometry.pb.go b/gui/internal/vision/ssl_vision_geometry.pb.go
new file mode 100644
index 0000000..e93b604
--- /dev/null
+++ b/gui/internal/vision/ssl_vision_geometry.pb.go
@@ -0,0 +1,1135 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.36.6
+// protoc (unknown)
+// source: vision/ssl_vision_geometry.proto
+
+package vision
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+ unsafe "unsafe"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type SSL_FieldShapeType int32
+
+const (
+ SSL_FieldShapeType_Undefined SSL_FieldShapeType = 0
+ SSL_FieldShapeType_CenterCircle SSL_FieldShapeType = 1
+ SSL_FieldShapeType_TopTouchLine SSL_FieldShapeType = 2
+ SSL_FieldShapeType_BottomTouchLine SSL_FieldShapeType = 3
+ SSL_FieldShapeType_LeftGoalLine SSL_FieldShapeType = 4
+ SSL_FieldShapeType_RightGoalLine SSL_FieldShapeType = 5
+ SSL_FieldShapeType_HalfwayLine SSL_FieldShapeType = 6
+ SSL_FieldShapeType_CenterLine SSL_FieldShapeType = 7
+ SSL_FieldShapeType_LeftPenaltyStretch SSL_FieldShapeType = 8
+ SSL_FieldShapeType_RightPenaltyStretch SSL_FieldShapeType = 9
+ SSL_FieldShapeType_LeftFieldLeftPenaltyStretch SSL_FieldShapeType = 10
+ SSL_FieldShapeType_LeftFieldRightPenaltyStretch SSL_FieldShapeType = 11
+ SSL_FieldShapeType_RightFieldLeftPenaltyStretch SSL_FieldShapeType = 12
+ SSL_FieldShapeType_RightFieldRightPenaltyStretch SSL_FieldShapeType = 13
+)
+
+// Enum value maps for SSL_FieldShapeType.
+var (
+ SSL_FieldShapeType_name = map[int32]string{
+ 0: "Undefined",
+ 1: "CenterCircle",
+ 2: "TopTouchLine",
+ 3: "BottomTouchLine",
+ 4: "LeftGoalLine",
+ 5: "RightGoalLine",
+ 6: "HalfwayLine",
+ 7: "CenterLine",
+ 8: "LeftPenaltyStretch",
+ 9: "RightPenaltyStretch",
+ 10: "LeftFieldLeftPenaltyStretch",
+ 11: "LeftFieldRightPenaltyStretch",
+ 12: "RightFieldLeftPenaltyStretch",
+ 13: "RightFieldRightPenaltyStretch",
+ }
+ SSL_FieldShapeType_value = map[string]int32{
+ "Undefined": 0,
+ "CenterCircle": 1,
+ "TopTouchLine": 2,
+ "BottomTouchLine": 3,
+ "LeftGoalLine": 4,
+ "RightGoalLine": 5,
+ "HalfwayLine": 6,
+ "CenterLine": 7,
+ "LeftPenaltyStretch": 8,
+ "RightPenaltyStretch": 9,
+ "LeftFieldLeftPenaltyStretch": 10,
+ "LeftFieldRightPenaltyStretch": 11,
+ "RightFieldLeftPenaltyStretch": 12,
+ "RightFieldRightPenaltyStretch": 13,
+ }
+)
+
+func (x SSL_FieldShapeType) Enum() *SSL_FieldShapeType {
+ p := new(SSL_FieldShapeType)
+ *p = x
+ return p
+}
+
+func (x SSL_FieldShapeType) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (SSL_FieldShapeType) Descriptor() protoreflect.EnumDescriptor {
+ return file_vision_ssl_vision_geometry_proto_enumTypes[0].Descriptor()
+}
+
+func (SSL_FieldShapeType) Type() protoreflect.EnumType {
+ return &file_vision_ssl_vision_geometry_proto_enumTypes[0]
+}
+
+func (x SSL_FieldShapeType) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *SSL_FieldShapeType) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = SSL_FieldShapeType(num)
+ return nil
+}
+
+// Deprecated: Use SSL_FieldShapeType.Descriptor instead.
+func (SSL_FieldShapeType) EnumDescriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{0}
+}
+
+// A 2D float vector.
+type Vector2F struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // X-coordinate in mm
+ X *float32 `protobuf:"fixed32,1,req,name=x" json:"x,omitempty"`
+ // Y-coordinate in mm
+ Y *float32 `protobuf:"fixed32,2,req,name=y" json:"y,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *Vector2F) Reset() {
+ *x = Vector2F{}
+ mi := &file_vision_ssl_vision_geometry_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *Vector2F) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Vector2F) ProtoMessage() {}
+
+func (x *Vector2F) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vision_geometry_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Vector2F.ProtoReflect.Descriptor instead.
+func (*Vector2F) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Vector2F) GetX() float32 {
+ if x != nil && x.X != nil {
+ return *x.X
+ }
+ return 0
+}
+
+func (x *Vector2F) GetY() float32 {
+ if x != nil && x.Y != nil {
+ return *x.Y
+ }
+ return 0
+}
+
+// Represents a field marking as a line segment represented by a start point p1,
+// and end point p2, and a line thickness. The start and end points are along
+// the center of the line, so the thickness of the line extends by thickness / 2
+// on either side of the line.
+type SSL_FieldLineSegment struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Name of this field marking.
+ Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"`
+ // Start point of the line segment.
+ P1 *Vector2F `protobuf:"bytes,2,req,name=p1" json:"p1,omitempty"`
+ // End point of the line segment.
+ P2 *Vector2F `protobuf:"bytes,3,req,name=p2" json:"p2,omitempty"`
+ // Thickness of the line segment.
+ Thickness *float32 `protobuf:"fixed32,4,req,name=thickness" json:"thickness,omitempty"`
+ // The type of this shape
+ Type *SSL_FieldShapeType `protobuf:"varint,5,opt,name=type,enum=SSL_FieldShapeType" json:"type,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SSL_FieldLineSegment) Reset() {
+ *x = SSL_FieldLineSegment{}
+ mi := &file_vision_ssl_vision_geometry_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_FieldLineSegment) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_FieldLineSegment) ProtoMessage() {}
+
+func (x *SSL_FieldLineSegment) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vision_geometry_proto_msgTypes[1]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_FieldLineSegment.ProtoReflect.Descriptor instead.
+func (*SSL_FieldLineSegment) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *SSL_FieldLineSegment) GetName() string {
+ if x != nil && x.Name != nil {
+ return *x.Name
+ }
+ return ""
+}
+
+func (x *SSL_FieldLineSegment) GetP1() *Vector2F {
+ if x != nil {
+ return x.P1
+ }
+ return nil
+}
+
+func (x *SSL_FieldLineSegment) GetP2() *Vector2F {
+ if x != nil {
+ return x.P2
+ }
+ return nil
+}
+
+func (x *SSL_FieldLineSegment) GetThickness() float32 {
+ if x != nil && x.Thickness != nil {
+ return *x.Thickness
+ }
+ return 0
+}
+
+func (x *SSL_FieldLineSegment) GetType() SSL_FieldShapeType {
+ if x != nil && x.Type != nil {
+ return *x.Type
+ }
+ return SSL_FieldShapeType_Undefined
+}
+
+// Represents a field marking as a circular arc segment represented by center point, a
+// start angle, an end angle, and an arc thickness.
+type SSL_FieldCircularArc struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Name of this field marking.
+ Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"`
+ // Center point of the circular arc.
+ Center *Vector2F `protobuf:"bytes,2,req,name=center" json:"center,omitempty"`
+ // Radius of the arc.
+ Radius *float32 `protobuf:"fixed32,3,req,name=radius" json:"radius,omitempty"`
+ // Start angle in counter-clockwise order.
+ A1 *float32 `protobuf:"fixed32,4,req,name=a1" json:"a1,omitempty"`
+ // End angle in counter-clockwise order.
+ A2 *float32 `protobuf:"fixed32,5,req,name=a2" json:"a2,omitempty"`
+ // Thickness of the arc.
+ Thickness *float32 `protobuf:"fixed32,6,req,name=thickness" json:"thickness,omitempty"`
+ // The type of this shape
+ Type *SSL_FieldShapeType `protobuf:"varint,7,opt,name=type,enum=SSL_FieldShapeType" json:"type,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SSL_FieldCircularArc) Reset() {
+ *x = SSL_FieldCircularArc{}
+ mi := &file_vision_ssl_vision_geometry_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_FieldCircularArc) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_FieldCircularArc) ProtoMessage() {}
+
+func (x *SSL_FieldCircularArc) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vision_geometry_proto_msgTypes[2]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_FieldCircularArc.ProtoReflect.Descriptor instead.
+func (*SSL_FieldCircularArc) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *SSL_FieldCircularArc) GetName() string {
+ if x != nil && x.Name != nil {
+ return *x.Name
+ }
+ return ""
+}
+
+func (x *SSL_FieldCircularArc) GetCenter() *Vector2F {
+ if x != nil {
+ return x.Center
+ }
+ return nil
+}
+
+func (x *SSL_FieldCircularArc) GetRadius() float32 {
+ if x != nil && x.Radius != nil {
+ return *x.Radius
+ }
+ return 0
+}
+
+func (x *SSL_FieldCircularArc) GetA1() float32 {
+ if x != nil && x.A1 != nil {
+ return *x.A1
+ }
+ return 0
+}
+
+func (x *SSL_FieldCircularArc) GetA2() float32 {
+ if x != nil && x.A2 != nil {
+ return *x.A2
+ }
+ return 0
+}
+
+func (x *SSL_FieldCircularArc) GetThickness() float32 {
+ if x != nil && x.Thickness != nil {
+ return *x.Thickness
+ }
+ return 0
+}
+
+func (x *SSL_FieldCircularArc) GetType() SSL_FieldShapeType {
+ if x != nil && x.Type != nil {
+ return *x.Type
+ }
+ return SSL_FieldShapeType_Undefined
+}
+
+type SSL_GeometryFieldSize struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Field length (distance between goal lines) in mm
+ FieldLength *int32 `protobuf:"varint,1,req,name=field_length,json=fieldLength" json:"field_length,omitempty"`
+ // Field width (distance between touch lines) in mm
+ FieldWidth *int32 `protobuf:"varint,2,req,name=field_width,json=fieldWidth" json:"field_width,omitempty"`
+ // Goal width (distance between inner edges of goal posts) in mm
+ GoalWidth *int32 `protobuf:"varint,3,req,name=goal_width,json=goalWidth" json:"goal_width,omitempty"`
+ // Goal depth (distance from outer goal line edge to inner goal back) in mm
+ GoalDepth *int32 `protobuf:"varint,4,req,name=goal_depth,json=goalDepth" json:"goal_depth,omitempty"`
+ // Boundary width (distance from touch line centers to boundary walls) in mm
+ BoundaryWidth *int32 `protobuf:"varint,5,req,name=boundary_width,json=boundaryWidth" json:"boundary_width,omitempty"`
+ // Boundary width at the goal lines (distance from goal line centers to boundary walls) in mm
+ BoundaryWidthGoalLine *int32 `protobuf:"varint,16,opt,name=boundary_width_goal_line,json=boundaryWidthGoalLine" json:"boundary_width_goal_line,omitempty"`
+ // Generated line segments based on the other parameters
+ FieldLines []*SSL_FieldLineSegment `protobuf:"bytes,6,rep,name=field_lines,json=fieldLines" json:"field_lines,omitempty"`
+ // Generated circular arcs based on the other parameters
+ FieldArcs []*SSL_FieldCircularArc `protobuf:"bytes,7,rep,name=field_arcs,json=fieldArcs" json:"field_arcs,omitempty"`
+ // Depth of the penalty/defense area (measured between line centers) in mm
+ PenaltyAreaDepth *int32 `protobuf:"varint,8,opt,name=penalty_area_depth,json=penaltyAreaDepth" json:"penalty_area_depth,omitempty"`
+ // Width of the penalty/defense area (measured between line centers) in mm
+ PenaltyAreaWidth *int32 `protobuf:"varint,9,opt,name=penalty_area_width,json=penaltyAreaWidth" json:"penalty_area_width,omitempty"`
+ // Radius of the center circle (measured between line centers) in mm
+ CenterCircleRadius *int32 `protobuf:"varint,10,opt,name=center_circle_radius,json=centerCircleRadius" json:"center_circle_radius,omitempty"`
+ // Thickness/width of the lines on the field in mm
+ LineThickness *int32 `protobuf:"varint,11,opt,name=line_thickness,json=lineThickness" json:"line_thickness,omitempty"`
+ // Distance between the goal center and the center of the penalty mark in mm
+ GoalCenterToPenaltyMark *int32 `protobuf:"varint,12,opt,name=goal_center_to_penalty_mark,json=goalCenterToPenaltyMark" json:"goal_center_to_penalty_mark,omitempty"`
+ // Goal height in mm
+ GoalHeight *int32 `protobuf:"varint,13,opt,name=goal_height,json=goalHeight" json:"goal_height,omitempty"`
+ // Ball radius in mm (note that this is a float type to represent sub-mm precision)
+ BallRadius *float32 `protobuf:"fixed32,14,opt,name=ball_radius,json=ballRadius" json:"ball_radius,omitempty"`
+ // Max allowed robot radius in mm (note that this is a float type to represent sub-mm precision)
+ MaxRobotRadius *float32 `protobuf:"fixed32,15,opt,name=max_robot_radius,json=maxRobotRadius" json:"max_robot_radius,omitempty"`
+ // Width of the goal substitution area (distance from goal line center plus boundary width to boundary walls) in mm
+ GoalSubstitutionAreaWidth *int32 `protobuf:"varint,17,opt,name=goal_substitution_area_width,json=goalSubstitutionAreaWidth" json:"goal_substitution_area_width,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SSL_GeometryFieldSize) Reset() {
+ *x = SSL_GeometryFieldSize{}
+ mi := &file_vision_ssl_vision_geometry_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_GeometryFieldSize) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_GeometryFieldSize) ProtoMessage() {}
+
+func (x *SSL_GeometryFieldSize) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vision_geometry_proto_msgTypes[3]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_GeometryFieldSize.ProtoReflect.Descriptor instead.
+func (*SSL_GeometryFieldSize) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *SSL_GeometryFieldSize) GetFieldLength() int32 {
+ if x != nil && x.FieldLength != nil {
+ return *x.FieldLength
+ }
+ return 0
+}
+
+func (x *SSL_GeometryFieldSize) GetFieldWidth() int32 {
+ if x != nil && x.FieldWidth != nil {
+ return *x.FieldWidth
+ }
+ return 0
+}
+
+func (x *SSL_GeometryFieldSize) GetGoalWidth() int32 {
+ if x != nil && x.GoalWidth != nil {
+ return *x.GoalWidth
+ }
+ return 0
+}
+
+func (x *SSL_GeometryFieldSize) GetGoalDepth() int32 {
+ if x != nil && x.GoalDepth != nil {
+ return *x.GoalDepth
+ }
+ return 0
+}
+
+func (x *SSL_GeometryFieldSize) GetBoundaryWidth() int32 {
+ if x != nil && x.BoundaryWidth != nil {
+ return *x.BoundaryWidth
+ }
+ return 0
+}
+
+func (x *SSL_GeometryFieldSize) GetBoundaryWidthGoalLine() int32 {
+ if x != nil && x.BoundaryWidthGoalLine != nil {
+ return *x.BoundaryWidthGoalLine
+ }
+ return 0
+}
+
+func (x *SSL_GeometryFieldSize) GetFieldLines() []*SSL_FieldLineSegment {
+ if x != nil {
+ return x.FieldLines
+ }
+ return nil
+}
+
+func (x *SSL_GeometryFieldSize) GetFieldArcs() []*SSL_FieldCircularArc {
+ if x != nil {
+ return x.FieldArcs
+ }
+ return nil
+}
+
+func (x *SSL_GeometryFieldSize) GetPenaltyAreaDepth() int32 {
+ if x != nil && x.PenaltyAreaDepth != nil {
+ return *x.PenaltyAreaDepth
+ }
+ return 0
+}
+
+func (x *SSL_GeometryFieldSize) GetPenaltyAreaWidth() int32 {
+ if x != nil && x.PenaltyAreaWidth != nil {
+ return *x.PenaltyAreaWidth
+ }
+ return 0
+}
+
+func (x *SSL_GeometryFieldSize) GetCenterCircleRadius() int32 {
+ if x != nil && x.CenterCircleRadius != nil {
+ return *x.CenterCircleRadius
+ }
+ return 0
+}
+
+func (x *SSL_GeometryFieldSize) GetLineThickness() int32 {
+ if x != nil && x.LineThickness != nil {
+ return *x.LineThickness
+ }
+ return 0
+}
+
+func (x *SSL_GeometryFieldSize) GetGoalCenterToPenaltyMark() int32 {
+ if x != nil && x.GoalCenterToPenaltyMark != nil {
+ return *x.GoalCenterToPenaltyMark
+ }
+ return 0
+}
+
+func (x *SSL_GeometryFieldSize) GetGoalHeight() int32 {
+ if x != nil && x.GoalHeight != nil {
+ return *x.GoalHeight
+ }
+ return 0
+}
+
+func (x *SSL_GeometryFieldSize) GetBallRadius() float32 {
+ if x != nil && x.BallRadius != nil {
+ return *x.BallRadius
+ }
+ return 0
+}
+
+func (x *SSL_GeometryFieldSize) GetMaxRobotRadius() float32 {
+ if x != nil && x.MaxRobotRadius != nil {
+ return *x.MaxRobotRadius
+ }
+ return 0
+}
+
+func (x *SSL_GeometryFieldSize) GetGoalSubstitutionAreaWidth() int32 {
+ if x != nil && x.GoalSubstitutionAreaWidth != nil {
+ return *x.GoalSubstitutionAreaWidth
+ }
+ return 0
+}
+
+type SSL_GeometryCameraCalibration struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ CameraId *uint32 `protobuf:"varint,1,req,name=camera_id,json=cameraId" json:"camera_id,omitempty"`
+ FocalLength *float32 `protobuf:"fixed32,2,req,name=focal_length,json=focalLength" json:"focal_length,omitempty"`
+ PrincipalPointX *float32 `protobuf:"fixed32,3,req,name=principal_point_x,json=principalPointX" json:"principal_point_x,omitempty"`
+ PrincipalPointY *float32 `protobuf:"fixed32,4,req,name=principal_point_y,json=principalPointY" json:"principal_point_y,omitempty"`
+ Distortion *float32 `protobuf:"fixed32,5,req,name=distortion" json:"distortion,omitempty"`
+ Q0 *float32 `protobuf:"fixed32,6,req,name=q0" json:"q0,omitempty"`
+ Q1 *float32 `protobuf:"fixed32,7,req,name=q1" json:"q1,omitempty"`
+ Q2 *float32 `protobuf:"fixed32,8,req,name=q2" json:"q2,omitempty"`
+ Q3 *float32 `protobuf:"fixed32,9,req,name=q3" json:"q3,omitempty"`
+ Tx *float32 `protobuf:"fixed32,10,req,name=tx" json:"tx,omitempty"`
+ Ty *float32 `protobuf:"fixed32,11,req,name=ty" json:"ty,omitempty"`
+ Tz *float32 `protobuf:"fixed32,12,req,name=tz" json:"tz,omitempty"`
+ DerivedCameraWorldTx *float32 `protobuf:"fixed32,13,opt,name=derived_camera_world_tx,json=derivedCameraWorldTx" json:"derived_camera_world_tx,omitempty"`
+ DerivedCameraWorldTy *float32 `protobuf:"fixed32,14,opt,name=derived_camera_world_ty,json=derivedCameraWorldTy" json:"derived_camera_world_ty,omitempty"`
+ DerivedCameraWorldTz *float32 `protobuf:"fixed32,15,opt,name=derived_camera_world_tz,json=derivedCameraWorldTz" json:"derived_camera_world_tz,omitempty"`
+ PixelImageWidth *uint32 `protobuf:"varint,16,opt,name=pixel_image_width,json=pixelImageWidth" json:"pixel_image_width,omitempty"`
+ PixelImageHeight *uint32 `protobuf:"varint,17,opt,name=pixel_image_height,json=pixelImageHeight" json:"pixel_image_height,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SSL_GeometryCameraCalibration) Reset() {
+ *x = SSL_GeometryCameraCalibration{}
+ mi := &file_vision_ssl_vision_geometry_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_GeometryCameraCalibration) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_GeometryCameraCalibration) ProtoMessage() {}
+
+func (x *SSL_GeometryCameraCalibration) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vision_geometry_proto_msgTypes[4]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_GeometryCameraCalibration.ProtoReflect.Descriptor instead.
+func (*SSL_GeometryCameraCalibration) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *SSL_GeometryCameraCalibration) GetCameraId() uint32 {
+ if x != nil && x.CameraId != nil {
+ return *x.CameraId
+ }
+ return 0
+}
+
+func (x *SSL_GeometryCameraCalibration) GetFocalLength() float32 {
+ if x != nil && x.FocalLength != nil {
+ return *x.FocalLength
+ }
+ return 0
+}
+
+func (x *SSL_GeometryCameraCalibration) GetPrincipalPointX() float32 {
+ if x != nil && x.PrincipalPointX != nil {
+ return *x.PrincipalPointX
+ }
+ return 0
+}
+
+func (x *SSL_GeometryCameraCalibration) GetPrincipalPointY() float32 {
+ if x != nil && x.PrincipalPointY != nil {
+ return *x.PrincipalPointY
+ }
+ return 0
+}
+
+func (x *SSL_GeometryCameraCalibration) GetDistortion() float32 {
+ if x != nil && x.Distortion != nil {
+ return *x.Distortion
+ }
+ return 0
+}
+
+func (x *SSL_GeometryCameraCalibration) GetQ0() float32 {
+ if x != nil && x.Q0 != nil {
+ return *x.Q0
+ }
+ return 0
+}
+
+func (x *SSL_GeometryCameraCalibration) GetQ1() float32 {
+ if x != nil && x.Q1 != nil {
+ return *x.Q1
+ }
+ return 0
+}
+
+func (x *SSL_GeometryCameraCalibration) GetQ2() float32 {
+ if x != nil && x.Q2 != nil {
+ return *x.Q2
+ }
+ return 0
+}
+
+func (x *SSL_GeometryCameraCalibration) GetQ3() float32 {
+ if x != nil && x.Q3 != nil {
+ return *x.Q3
+ }
+ return 0
+}
+
+func (x *SSL_GeometryCameraCalibration) GetTx() float32 {
+ if x != nil && x.Tx != nil {
+ return *x.Tx
+ }
+ return 0
+}
+
+func (x *SSL_GeometryCameraCalibration) GetTy() float32 {
+ if x != nil && x.Ty != nil {
+ return *x.Ty
+ }
+ return 0
+}
+
+func (x *SSL_GeometryCameraCalibration) GetTz() float32 {
+ if x != nil && x.Tz != nil {
+ return *x.Tz
+ }
+ return 0
+}
+
+func (x *SSL_GeometryCameraCalibration) GetDerivedCameraWorldTx() float32 {
+ if x != nil && x.DerivedCameraWorldTx != nil {
+ return *x.DerivedCameraWorldTx
+ }
+ return 0
+}
+
+func (x *SSL_GeometryCameraCalibration) GetDerivedCameraWorldTy() float32 {
+ if x != nil && x.DerivedCameraWorldTy != nil {
+ return *x.DerivedCameraWorldTy
+ }
+ return 0
+}
+
+func (x *SSL_GeometryCameraCalibration) GetDerivedCameraWorldTz() float32 {
+ if x != nil && x.DerivedCameraWorldTz != nil {
+ return *x.DerivedCameraWorldTz
+ }
+ return 0
+}
+
+func (x *SSL_GeometryCameraCalibration) GetPixelImageWidth() uint32 {
+ if x != nil && x.PixelImageWidth != nil {
+ return *x.PixelImageWidth
+ }
+ return 0
+}
+
+func (x *SSL_GeometryCameraCalibration) GetPixelImageHeight() uint32 {
+ if x != nil && x.PixelImageHeight != nil {
+ return *x.PixelImageHeight
+ }
+ return 0
+}
+
+// Two-Phase model for straight-kicked balls.
+// There are two phases with different accelerations during the ball kicks:
+// 1. Sliding
+// 2. Rolling
+// The full model is described in the TDP of ER-Force from 2016, which can be found here:
+// https://ssl.robocup.org/wp-content/uploads/2019/01/2016_ETDP_ER-Force.pdf
+type SSL_BallModelStraightTwoPhase struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Ball sliding acceleration [m/s^2] (should be negative)
+ AccSlide *float64 `protobuf:"fixed64,1,req,name=acc_slide,json=accSlide" json:"acc_slide,omitempty"`
+ // Ball rolling acceleration [m/s^2] (should be negative)
+ AccRoll *float64 `protobuf:"fixed64,2,req,name=acc_roll,json=accRoll" json:"acc_roll,omitempty"`
+ // Fraction of the initial velocity where the ball starts to roll
+ KSwitch *float64 `protobuf:"fixed64,3,req,name=k_switch,json=kSwitch" json:"k_switch,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SSL_BallModelStraightTwoPhase) Reset() {
+ *x = SSL_BallModelStraightTwoPhase{}
+ mi := &file_vision_ssl_vision_geometry_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_BallModelStraightTwoPhase) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_BallModelStraightTwoPhase) ProtoMessage() {}
+
+func (x *SSL_BallModelStraightTwoPhase) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vision_geometry_proto_msgTypes[5]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_BallModelStraightTwoPhase.ProtoReflect.Descriptor instead.
+func (*SSL_BallModelStraightTwoPhase) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *SSL_BallModelStraightTwoPhase) GetAccSlide() float64 {
+ if x != nil && x.AccSlide != nil {
+ return *x.AccSlide
+ }
+ return 0
+}
+
+func (x *SSL_BallModelStraightTwoPhase) GetAccRoll() float64 {
+ if x != nil && x.AccRoll != nil {
+ return *x.AccRoll
+ }
+ return 0
+}
+
+func (x *SSL_BallModelStraightTwoPhase) GetKSwitch() float64 {
+ if x != nil && x.KSwitch != nil {
+ return *x.KSwitch
+ }
+ return 0
+}
+
+// Fixed-Loss model for chipped balls.
+// Uses fixed damping factors for xy and z direction per hop.
+type SSL_BallModelChipFixedLoss struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Chip kick velocity damping factor in XY direction for the first hop
+ DampingXyFirstHop *float64 `protobuf:"fixed64,1,req,name=damping_xy_first_hop,json=dampingXyFirstHop" json:"damping_xy_first_hop,omitempty"`
+ // Chip kick velocity damping factor in XY direction for all following hops
+ DampingXyOtherHops *float64 `protobuf:"fixed64,2,req,name=damping_xy_other_hops,json=dampingXyOtherHops" json:"damping_xy_other_hops,omitempty"`
+ // Chip kick velocity damping factor in Z direction for all hops
+ DampingZ *float64 `protobuf:"fixed64,3,req,name=damping_z,json=dampingZ" json:"damping_z,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SSL_BallModelChipFixedLoss) Reset() {
+ *x = SSL_BallModelChipFixedLoss{}
+ mi := &file_vision_ssl_vision_geometry_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_BallModelChipFixedLoss) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_BallModelChipFixedLoss) ProtoMessage() {}
+
+func (x *SSL_BallModelChipFixedLoss) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vision_geometry_proto_msgTypes[6]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_BallModelChipFixedLoss.ProtoReflect.Descriptor instead.
+func (*SSL_BallModelChipFixedLoss) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *SSL_BallModelChipFixedLoss) GetDampingXyFirstHop() float64 {
+ if x != nil && x.DampingXyFirstHop != nil {
+ return *x.DampingXyFirstHop
+ }
+ return 0
+}
+
+func (x *SSL_BallModelChipFixedLoss) GetDampingXyOtherHops() float64 {
+ if x != nil && x.DampingXyOtherHops != nil {
+ return *x.DampingXyOtherHops
+ }
+ return 0
+}
+
+func (x *SSL_BallModelChipFixedLoss) GetDampingZ() float64 {
+ if x != nil && x.DampingZ != nil {
+ return *x.DampingZ
+ }
+ return 0
+}
+
+type SSL_GeometryModels struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ StraightTwoPhase *SSL_BallModelStraightTwoPhase `protobuf:"bytes,1,opt,name=straight_two_phase,json=straightTwoPhase" json:"straight_two_phase,omitempty"`
+ ChipFixedLoss *SSL_BallModelChipFixedLoss `protobuf:"bytes,2,opt,name=chip_fixed_loss,json=chipFixedLoss" json:"chip_fixed_loss,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SSL_GeometryModels) Reset() {
+ *x = SSL_GeometryModels{}
+ mi := &file_vision_ssl_vision_geometry_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_GeometryModels) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_GeometryModels) ProtoMessage() {}
+
+func (x *SSL_GeometryModels) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vision_geometry_proto_msgTypes[7]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_GeometryModels.ProtoReflect.Descriptor instead.
+func (*SSL_GeometryModels) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *SSL_GeometryModels) GetStraightTwoPhase() *SSL_BallModelStraightTwoPhase {
+ if x != nil {
+ return x.StraightTwoPhase
+ }
+ return nil
+}
+
+func (x *SSL_GeometryModels) GetChipFixedLoss() *SSL_BallModelChipFixedLoss {
+ if x != nil {
+ return x.ChipFixedLoss
+ }
+ return nil
+}
+
+type SSL_GeometryData struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Field *SSL_GeometryFieldSize `protobuf:"bytes,1,req,name=field" json:"field,omitempty"`
+ Calib []*SSL_GeometryCameraCalibration `protobuf:"bytes,2,rep,name=calib" json:"calib,omitempty"`
+ Models *SSL_GeometryModels `protobuf:"bytes,3,opt,name=models" json:"models,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SSL_GeometryData) Reset() {
+ *x = SSL_GeometryData{}
+ mi := &file_vision_ssl_vision_geometry_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_GeometryData) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_GeometryData) ProtoMessage() {}
+
+func (x *SSL_GeometryData) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vision_geometry_proto_msgTypes[8]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_GeometryData.ProtoReflect.Descriptor instead.
+func (*SSL_GeometryData) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *SSL_GeometryData) GetField() *SSL_GeometryFieldSize {
+ if x != nil {
+ return x.Field
+ }
+ return nil
+}
+
+func (x *SSL_GeometryData) GetCalib() []*SSL_GeometryCameraCalibration {
+ if x != nil {
+ return x.Calib
+ }
+ return nil
+}
+
+func (x *SSL_GeometryData) GetModels() *SSL_GeometryModels {
+ if x != nil {
+ return x.Models
+ }
+ return nil
+}
+
+var File_vision_ssl_vision_geometry_proto protoreflect.FileDescriptor
+
+const file_vision_ssl_vision_geometry_proto_rawDesc = "" +
+ "\n" +
+ " vision/ssl_vision_geometry.proto\"&\n" +
+ "\bVector2f\x12\f\n" +
+ "\x01x\x18\x01 \x02(\x02R\x01x\x12\f\n" +
+ "\x01y\x18\x02 \x02(\x02R\x01y\"\xa7\x01\n" +
+ "\x14SSL_FieldLineSegment\x12\x12\n" +
+ "\x04name\x18\x01 \x02(\tR\x04name\x12\x19\n" +
+ "\x02p1\x18\x02 \x02(\v2\t.Vector2fR\x02p1\x12\x19\n" +
+ "\x02p2\x18\x03 \x02(\v2\t.Vector2fR\x02p2\x12\x1c\n" +
+ "\tthickness\x18\x04 \x02(\x02R\tthickness\x12'\n" +
+ "\x04type\x18\x05 \x01(\x0e2\x13.SSL_FieldShapeTypeR\x04type\"\xcc\x01\n" +
+ "\x14SSL_FieldCircularArc\x12\x12\n" +
+ "\x04name\x18\x01 \x02(\tR\x04name\x12!\n" +
+ "\x06center\x18\x02 \x02(\v2\t.Vector2fR\x06center\x12\x16\n" +
+ "\x06radius\x18\x03 \x02(\x02R\x06radius\x12\x0e\n" +
+ "\x02a1\x18\x04 \x02(\x02R\x02a1\x12\x0e\n" +
+ "\x02a2\x18\x05 \x02(\x02R\x02a2\x12\x1c\n" +
+ "\tthickness\x18\x06 \x02(\x02R\tthickness\x12'\n" +
+ "\x04type\x18\a \x01(\x0e2\x13.SSL_FieldShapeTypeR\x04type\"\x87\x06\n" +
+ "\x15SSL_GeometryFieldSize\x12!\n" +
+ "\ffield_length\x18\x01 \x02(\x05R\vfieldLength\x12\x1f\n" +
+ "\vfield_width\x18\x02 \x02(\x05R\n" +
+ "fieldWidth\x12\x1d\n" +
+ "\n" +
+ "goal_width\x18\x03 \x02(\x05R\tgoalWidth\x12\x1d\n" +
+ "\n" +
+ "goal_depth\x18\x04 \x02(\x05R\tgoalDepth\x12%\n" +
+ "\x0eboundary_width\x18\x05 \x02(\x05R\rboundaryWidth\x127\n" +
+ "\x18boundary_width_goal_line\x18\x10 \x01(\x05R\x15boundaryWidthGoalLine\x126\n" +
+ "\vfield_lines\x18\x06 \x03(\v2\x15.SSL_FieldLineSegmentR\n" +
+ "fieldLines\x124\n" +
+ "\n" +
+ "field_arcs\x18\a \x03(\v2\x15.SSL_FieldCircularArcR\tfieldArcs\x12,\n" +
+ "\x12penalty_area_depth\x18\b \x01(\x05R\x10penaltyAreaDepth\x12,\n" +
+ "\x12penalty_area_width\x18\t \x01(\x05R\x10penaltyAreaWidth\x120\n" +
+ "\x14center_circle_radius\x18\n" +
+ " \x01(\x05R\x12centerCircleRadius\x12%\n" +
+ "\x0eline_thickness\x18\v \x01(\x05R\rlineThickness\x12<\n" +
+ "\x1bgoal_center_to_penalty_mark\x18\f \x01(\x05R\x17goalCenterToPenaltyMark\x12\x1f\n" +
+ "\vgoal_height\x18\r \x01(\x05R\n" +
+ "goalHeight\x12\x1f\n" +
+ "\vball_radius\x18\x0e \x01(\x02R\n" +
+ "ballRadius\x12(\n" +
+ "\x10max_robot_radius\x18\x0f \x01(\x02R\x0emaxRobotRadius\x12?\n" +
+ "\x1cgoal_substitution_area_width\x18\x11 \x01(\x05R\x19goalSubstitutionAreaWidth\"\xc6\x04\n" +
+ "\x1dSSL_GeometryCameraCalibration\x12\x1b\n" +
+ "\tcamera_id\x18\x01 \x02(\rR\bcameraId\x12!\n" +
+ "\ffocal_length\x18\x02 \x02(\x02R\vfocalLength\x12*\n" +
+ "\x11principal_point_x\x18\x03 \x02(\x02R\x0fprincipalPointX\x12*\n" +
+ "\x11principal_point_y\x18\x04 \x02(\x02R\x0fprincipalPointY\x12\x1e\n" +
+ "\n" +
+ "distortion\x18\x05 \x02(\x02R\n" +
+ "distortion\x12\x0e\n" +
+ "\x02q0\x18\x06 \x02(\x02R\x02q0\x12\x0e\n" +
+ "\x02q1\x18\a \x02(\x02R\x02q1\x12\x0e\n" +
+ "\x02q2\x18\b \x02(\x02R\x02q2\x12\x0e\n" +
+ "\x02q3\x18\t \x02(\x02R\x02q3\x12\x0e\n" +
+ "\x02tx\x18\n" +
+ " \x02(\x02R\x02tx\x12\x0e\n" +
+ "\x02ty\x18\v \x02(\x02R\x02ty\x12\x0e\n" +
+ "\x02tz\x18\f \x02(\x02R\x02tz\x125\n" +
+ "\x17derived_camera_world_tx\x18\r \x01(\x02R\x14derivedCameraWorldTx\x125\n" +
+ "\x17derived_camera_world_ty\x18\x0e \x01(\x02R\x14derivedCameraWorldTy\x125\n" +
+ "\x17derived_camera_world_tz\x18\x0f \x01(\x02R\x14derivedCameraWorldTz\x12*\n" +
+ "\x11pixel_image_width\x18\x10 \x01(\rR\x0fpixelImageWidth\x12,\n" +
+ "\x12pixel_image_height\x18\x11 \x01(\rR\x10pixelImageHeight\"r\n" +
+ "\x1dSSL_BallModelStraightTwoPhase\x12\x1b\n" +
+ "\tacc_slide\x18\x01 \x02(\x01R\baccSlide\x12\x19\n" +
+ "\bacc_roll\x18\x02 \x02(\x01R\aaccRoll\x12\x19\n" +
+ "\bk_switch\x18\x03 \x02(\x01R\akSwitch\"\x9d\x01\n" +
+ "\x1aSSL_BallModelChipFixedLoss\x12/\n" +
+ "\x14damping_xy_first_hop\x18\x01 \x02(\x01R\x11dampingXyFirstHop\x121\n" +
+ "\x15damping_xy_other_hops\x18\x02 \x02(\x01R\x12dampingXyOtherHops\x12\x1b\n" +
+ "\tdamping_z\x18\x03 \x02(\x01R\bdampingZ\"\xa7\x01\n" +
+ "\x12SSL_GeometryModels\x12L\n" +
+ "\x12straight_two_phase\x18\x01 \x01(\v2\x1e.SSL_BallModelStraightTwoPhaseR\x10straightTwoPhase\x12C\n" +
+ "\x0fchip_fixed_loss\x18\x02 \x01(\v2\x1b.SSL_BallModelChipFixedLossR\rchipFixedLoss\"\xa3\x01\n" +
+ "\x10SSL_GeometryData\x12,\n" +
+ "\x05field\x18\x01 \x02(\v2\x16.SSL_GeometryFieldSizeR\x05field\x124\n" +
+ "\x05calib\x18\x02 \x03(\v2\x1e.SSL_GeometryCameraCalibrationR\x05calib\x12+\n" +
+ "\x06models\x18\x03 \x01(\v2\x13.SSL_GeometryModelsR\x06models*\xdb\x02\n" +
+ "\x12SSL_FieldShapeType\x12\r\n" +
+ "\tUndefined\x10\x00\x12\x10\n" +
+ "\fCenterCircle\x10\x01\x12\x10\n" +
+ "\fTopTouchLine\x10\x02\x12\x13\n" +
+ "\x0fBottomTouchLine\x10\x03\x12\x10\n" +
+ "\fLeftGoalLine\x10\x04\x12\x11\n" +
+ "\rRightGoalLine\x10\x05\x12\x0f\n" +
+ "\vHalfwayLine\x10\x06\x12\x0e\n" +
+ "\n" +
+ "CenterLine\x10\a\x12\x16\n" +
+ "\x12LeftPenaltyStretch\x10\b\x12\x17\n" +
+ "\x13RightPenaltyStretch\x10\t\x12\x1f\n" +
+ "\x1bLeftFieldLeftPenaltyStretch\x10\n" +
+ "\x12 \n" +
+ "\x1cLeftFieldRightPenaltyStretch\x10\v\x12 \n" +
+ "\x1cRightFieldLeftPenaltyStretch\x10\f\x12!\n" +
+ "\x1dRightFieldRightPenaltyStretch\x10\rB[B\x16SslVisionGeometryProtoP\x01Z?github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
+
+var (
+ file_vision_ssl_vision_geometry_proto_rawDescOnce sync.Once
+ file_vision_ssl_vision_geometry_proto_rawDescData []byte
+)
+
+func file_vision_ssl_vision_geometry_proto_rawDescGZIP() []byte {
+ file_vision_ssl_vision_geometry_proto_rawDescOnce.Do(func() {
+ file_vision_ssl_vision_geometry_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_geometry_proto_rawDesc), len(file_vision_ssl_vision_geometry_proto_rawDesc)))
+ })
+ return file_vision_ssl_vision_geometry_proto_rawDescData
+}
+
+var file_vision_ssl_vision_geometry_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_vision_ssl_vision_geometry_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
+var file_vision_ssl_vision_geometry_proto_goTypes = []any{
+ (SSL_FieldShapeType)(0), // 0: SSL_FieldShapeType
+ (*Vector2F)(nil), // 1: Vector2f
+ (*SSL_FieldLineSegment)(nil), // 2: SSL_FieldLineSegment
+ (*SSL_FieldCircularArc)(nil), // 3: SSL_FieldCircularArc
+ (*SSL_GeometryFieldSize)(nil), // 4: SSL_GeometryFieldSize
+ (*SSL_GeometryCameraCalibration)(nil), // 5: SSL_GeometryCameraCalibration
+ (*SSL_BallModelStraightTwoPhase)(nil), // 6: SSL_BallModelStraightTwoPhase
+ (*SSL_BallModelChipFixedLoss)(nil), // 7: SSL_BallModelChipFixedLoss
+ (*SSL_GeometryModels)(nil), // 8: SSL_GeometryModels
+ (*SSL_GeometryData)(nil), // 9: SSL_GeometryData
+}
+var file_vision_ssl_vision_geometry_proto_depIdxs = []int32{
+ 1, // 0: SSL_FieldLineSegment.p1:type_name -> Vector2f
+ 1, // 1: SSL_FieldLineSegment.p2:type_name -> Vector2f
+ 0, // 2: SSL_FieldLineSegment.type:type_name -> SSL_FieldShapeType
+ 1, // 3: SSL_FieldCircularArc.center:type_name -> Vector2f
+ 0, // 4: SSL_FieldCircularArc.type:type_name -> SSL_FieldShapeType
+ 2, // 5: SSL_GeometryFieldSize.field_lines:type_name -> SSL_FieldLineSegment
+ 3, // 6: SSL_GeometryFieldSize.field_arcs:type_name -> SSL_FieldCircularArc
+ 6, // 7: SSL_GeometryModels.straight_two_phase:type_name -> SSL_BallModelStraightTwoPhase
+ 7, // 8: SSL_GeometryModels.chip_fixed_loss:type_name -> SSL_BallModelChipFixedLoss
+ 4, // 9: SSL_GeometryData.field:type_name -> SSL_GeometryFieldSize
+ 5, // 10: SSL_GeometryData.calib:type_name -> SSL_GeometryCameraCalibration
+ 8, // 11: SSL_GeometryData.models:type_name -> SSL_GeometryModels
+ 12, // [12:12] is the sub-list for method output_type
+ 12, // [12:12] is the sub-list for method input_type
+ 12, // [12:12] is the sub-list for extension type_name
+ 12, // [12:12] is the sub-list for extension extendee
+ 0, // [0:12] is the sub-list for field type_name
+}
+
+func init() { file_vision_ssl_vision_geometry_proto_init() }
+func file_vision_ssl_vision_geometry_proto_init() {
+ if File_vision_ssl_vision_geometry_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_geometry_proto_rawDesc), len(file_vision_ssl_vision_geometry_proto_rawDesc)),
+ NumEnums: 1,
+ NumMessages: 9,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_vision_ssl_vision_geometry_proto_goTypes,
+ DependencyIndexes: file_vision_ssl_vision_geometry_proto_depIdxs,
+ EnumInfos: file_vision_ssl_vision_geometry_proto_enumTypes,
+ MessageInfos: file_vision_ssl_vision_geometry_proto_msgTypes,
+ }.Build()
+ File_vision_ssl_vision_geometry_proto = out.File
+ file_vision_ssl_vision_geometry_proto_goTypes = nil
+ file_vision_ssl_vision_geometry_proto_depIdxs = nil
+}
diff --git a/gui/internal/vision/ssl_vision_wrapper.pb.go b/gui/internal/vision/ssl_vision_wrapper.pb.go
new file mode 100644
index 0000000..ecbee04
--- /dev/null
+++ b/gui/internal/vision/ssl_vision_wrapper.pb.go
@@ -0,0 +1,238 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.36.6
+// protoc (unknown)
+// source: vision/ssl_vision_wrapper.proto
+
+package vision
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+ unsafe "unsafe"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type SSL_Source int32
+
+const (
+ SSL_Source_SSL_SOURCE_UNKNOWN SSL_Source = 0
+ SSL_Source_SSL_SOURCE_OTHER SSL_Source = 1
+ SSL_Source_SSL_SOURCE_SSL_VISION SSL_Source = 2
+ SSL_Source_SSL_SOURCE_VISION_PROCESSOR SSL_Source = 3
+ SSL_Source_SSL_SOURCE_GRSIM SSL_Source = 4
+ SSL_Source_SSL_SOURCE_ERFORCE_SIM SSL_Source = 5
+)
+
+// Enum value maps for SSL_Source.
+var (
+ SSL_Source_name = map[int32]string{
+ 0: "SSL_SOURCE_UNKNOWN",
+ 1: "SSL_SOURCE_OTHER",
+ 2: "SSL_SOURCE_SSL_VISION",
+ 3: "SSL_SOURCE_VISION_PROCESSOR",
+ 4: "SSL_SOURCE_GRSIM",
+ 5: "SSL_SOURCE_ERFORCE_SIM",
+ }
+ SSL_Source_value = map[string]int32{
+ "SSL_SOURCE_UNKNOWN": 0,
+ "SSL_SOURCE_OTHER": 1,
+ "SSL_SOURCE_SSL_VISION": 2,
+ "SSL_SOURCE_VISION_PROCESSOR": 3,
+ "SSL_SOURCE_GRSIM": 4,
+ "SSL_SOURCE_ERFORCE_SIM": 5,
+ }
+)
+
+func (x SSL_Source) Enum() *SSL_Source {
+ p := new(SSL_Source)
+ *p = x
+ return p
+}
+
+func (x SSL_Source) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (SSL_Source) Descriptor() protoreflect.EnumDescriptor {
+ return file_vision_ssl_vision_wrapper_proto_enumTypes[0].Descriptor()
+}
+
+func (SSL_Source) Type() protoreflect.EnumType {
+ return &file_vision_ssl_vision_wrapper_proto_enumTypes[0]
+}
+
+func (x SSL_Source) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *SSL_Source) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = SSL_Source(num)
+ return nil
+}
+
+// Deprecated: Use SSL_Source.Descriptor instead.
+func (SSL_Source) EnumDescriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_wrapper_proto_rawDescGZIP(), []int{0}
+}
+
+type SSL_WrapperPacket struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Detection *SSL_DetectionFrame `protobuf:"bytes,1,opt,name=detection" json:"detection,omitempty"`
+ Geometry *SSL_GeometryData `protobuf:"bytes,2,opt,name=geometry" json:"geometry,omitempty"`
+ Source *SSL_Source `protobuf:"varint,3,opt,name=source,enum=SSL_Source" json:"source,omitempty"`
+ Config *SSL_VPConfig `protobuf:"bytes,4,opt,name=config" json:"config,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SSL_WrapperPacket) Reset() {
+ *x = SSL_WrapperPacket{}
+ mi := &file_vision_ssl_vision_wrapper_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_WrapperPacket) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_WrapperPacket) ProtoMessage() {}
+
+func (x *SSL_WrapperPacket) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vision_wrapper_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_WrapperPacket.ProtoReflect.Descriptor instead.
+func (*SSL_WrapperPacket) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_wrapper_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *SSL_WrapperPacket) GetDetection() *SSL_DetectionFrame {
+ if x != nil {
+ return x.Detection
+ }
+ return nil
+}
+
+func (x *SSL_WrapperPacket) GetGeometry() *SSL_GeometryData {
+ if x != nil {
+ return x.Geometry
+ }
+ return nil
+}
+
+func (x *SSL_WrapperPacket) GetSource() SSL_Source {
+ if x != nil && x.Source != nil {
+ return *x.Source
+ }
+ return SSL_Source_SSL_SOURCE_UNKNOWN
+}
+
+func (x *SSL_WrapperPacket) GetConfig() *SSL_VPConfig {
+ if x != nil {
+ return x.Config
+ }
+ return nil
+}
+
+var File_vision_ssl_vision_wrapper_proto protoreflect.FileDescriptor
+
+const file_vision_ssl_vision_wrapper_proto_rawDesc = "" +
+ "\n" +
+ "\x1fvision/ssl_vision_wrapper.proto\x1a!vision/ssl_vision_detection.proto\x1a vision/ssl_vision_geometry.proto\x1a\x1avision/ssl_vp_config.proto\"\xc1\x01\n" +
+ "\x11SSL_WrapperPacket\x121\n" +
+ "\tdetection\x18\x01 \x01(\v2\x13.SSL_DetectionFrameR\tdetection\x12-\n" +
+ "\bgeometry\x18\x02 \x01(\v2\x11.SSL_GeometryDataR\bgeometry\x12#\n" +
+ "\x06source\x18\x03 \x01(\x0e2\v.SSL_SourceR\x06source\x12%\n" +
+ "\x06config\x18\x04 \x01(\v2\r.SSL_VPConfigR\x06config*\xa8\x01\n" +
+ "\n" +
+ "SSL_Source\x12\x16\n" +
+ "\x12SSL_SOURCE_UNKNOWN\x10\x00\x12\x14\n" +
+ "\x10SSL_SOURCE_OTHER\x10\x01\x12\x19\n" +
+ "\x15SSL_SOURCE_SSL_VISION\x10\x02\x12\x1f\n" +
+ "\x1bSSL_SOURCE_VISION_PROCESSOR\x10\x03\x12\x14\n" +
+ "\x10SSL_SOURCE_GRSIM\x10\x04\x12\x1a\n" +
+ "\x16SSL_SOURCE_ERFORCE_SIM\x10\x05BZB\x15SslVisionWrapperProtoP\x01Z?github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
+
+var (
+ file_vision_ssl_vision_wrapper_proto_rawDescOnce sync.Once
+ file_vision_ssl_vision_wrapper_proto_rawDescData []byte
+)
+
+func file_vision_ssl_vision_wrapper_proto_rawDescGZIP() []byte {
+ file_vision_ssl_vision_wrapper_proto_rawDescOnce.Do(func() {
+ file_vision_ssl_vision_wrapper_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_wrapper_proto_rawDesc), len(file_vision_ssl_vision_wrapper_proto_rawDesc)))
+ })
+ return file_vision_ssl_vision_wrapper_proto_rawDescData
+}
+
+var file_vision_ssl_vision_wrapper_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_vision_ssl_vision_wrapper_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_vision_ssl_vision_wrapper_proto_goTypes = []any{
+ (SSL_Source)(0), // 0: SSL_Source
+ (*SSL_WrapperPacket)(nil), // 1: SSL_WrapperPacket
+ (*SSL_DetectionFrame)(nil), // 2: SSL_DetectionFrame
+ (*SSL_GeometryData)(nil), // 3: SSL_GeometryData
+ (*SSL_VPConfig)(nil), // 4: SSL_VPConfig
+}
+var file_vision_ssl_vision_wrapper_proto_depIdxs = []int32{
+ 2, // 0: SSL_WrapperPacket.detection:type_name -> SSL_DetectionFrame
+ 3, // 1: SSL_WrapperPacket.geometry:type_name -> SSL_GeometryData
+ 0, // 2: SSL_WrapperPacket.source:type_name -> SSL_Source
+ 4, // 3: SSL_WrapperPacket.config:type_name -> SSL_VPConfig
+ 4, // [4:4] is the sub-list for method output_type
+ 4, // [4:4] is the sub-list for method input_type
+ 4, // [4:4] is the sub-list for extension type_name
+ 4, // [4:4] is the sub-list for extension extendee
+ 0, // [0:4] is the sub-list for field type_name
+}
+
+func init() { file_vision_ssl_vision_wrapper_proto_init() }
+func file_vision_ssl_vision_wrapper_proto_init() {
+ if File_vision_ssl_vision_wrapper_proto != nil {
+ return
+ }
+ file_vision_ssl_vision_detection_proto_init()
+ file_vision_ssl_vision_geometry_proto_init()
+ file_vision_ssl_vp_config_proto_init()
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_wrapper_proto_rawDesc), len(file_vision_ssl_vision_wrapper_proto_rawDesc)),
+ NumEnums: 1,
+ NumMessages: 1,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_vision_ssl_vision_wrapper_proto_goTypes,
+ DependencyIndexes: file_vision_ssl_vision_wrapper_proto_depIdxs,
+ EnumInfos: file_vision_ssl_vision_wrapper_proto_enumTypes,
+ MessageInfos: file_vision_ssl_vision_wrapper_proto_msgTypes,
+ }.Build()
+ File_vision_ssl_vision_wrapper_proto = out.File
+ file_vision_ssl_vision_wrapper_proto_goTypes = nil
+ file_vision_ssl_vision_wrapper_proto_depIdxs = nil
+}
diff --git a/gui/internal/vision/ssl_vision_wrapper_tracked.pb.go b/gui/internal/vision/ssl_vision_wrapper_tracked.pb.go
new file mode 100644
index 0000000..f993a0b
--- /dev/null
+++ b/gui/internal/vision/ssl_vision_wrapper_tracked.pb.go
@@ -0,0 +1,150 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.36.6
+// protoc (unknown)
+// source: vision/ssl_vision_wrapper_tracked.proto
+
+package vision
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+ unsafe "unsafe"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// A wrapper packet containing meta data of the source
+// Also serves for the possibility to extend the protocol later
+type TrackerWrapperPacket struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // A random UUID of the source that is kept constant at the source while running
+ // If multiple sources are broadcasting to the same network, this id can be used to identify individual sources
+ Uuid *string `protobuf:"bytes,1,req,name=uuid" json:"uuid,omitempty"`
+ // The name of the source software that is producing this messages.
+ SourceName *string `protobuf:"bytes,2,opt,name=source_name,json=sourceName" json:"source_name,omitempty"`
+ // The tracked frame
+ TrackedFrame *TrackedFrame `protobuf:"bytes,3,opt,name=tracked_frame,json=trackedFrame" json:"tracked_frame,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *TrackerWrapperPacket) Reset() {
+ *x = TrackerWrapperPacket{}
+ mi := &file_vision_ssl_vision_wrapper_tracked_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *TrackerWrapperPacket) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TrackerWrapperPacket) ProtoMessage() {}
+
+func (x *TrackerWrapperPacket) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vision_wrapper_tracked_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TrackerWrapperPacket.ProtoReflect.Descriptor instead.
+func (*TrackerWrapperPacket) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vision_wrapper_tracked_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *TrackerWrapperPacket) GetUuid() string {
+ if x != nil && x.Uuid != nil {
+ return *x.Uuid
+ }
+ return ""
+}
+
+func (x *TrackerWrapperPacket) GetSourceName() string {
+ if x != nil && x.SourceName != nil {
+ return *x.SourceName
+ }
+ return ""
+}
+
+func (x *TrackerWrapperPacket) GetTrackedFrame() *TrackedFrame {
+ if x != nil {
+ return x.TrackedFrame
+ }
+ return nil
+}
+
+var File_vision_ssl_vision_wrapper_tracked_proto protoreflect.FileDescriptor
+
+const file_vision_ssl_vision_wrapper_tracked_proto_rawDesc = "" +
+ "\n" +
+ "'vision/ssl_vision_wrapper_tracked.proto\x1a)vision/ssl_vision_detection_tracked.proto\"\x7f\n" +
+ "\x14TrackerWrapperPacket\x12\x12\n" +
+ "\x04uuid\x18\x01 \x02(\tR\x04uuid\x12\x1f\n" +
+ "\vsource_name\x18\x02 \x01(\tR\n" +
+ "sourceName\x122\n" +
+ "\rtracked_frame\x18\x03 \x01(\v2\r.TrackedFrameR\ftrackedFrameBaB\x1cSslVisionWrapperTrackedProtoP\x01Z?github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
+
+var (
+ file_vision_ssl_vision_wrapper_tracked_proto_rawDescOnce sync.Once
+ file_vision_ssl_vision_wrapper_tracked_proto_rawDescData []byte
+)
+
+func file_vision_ssl_vision_wrapper_tracked_proto_rawDescGZIP() []byte {
+ file_vision_ssl_vision_wrapper_tracked_proto_rawDescOnce.Do(func() {
+ file_vision_ssl_vision_wrapper_tracked_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_wrapper_tracked_proto_rawDesc), len(file_vision_ssl_vision_wrapper_tracked_proto_rawDesc)))
+ })
+ return file_vision_ssl_vision_wrapper_tracked_proto_rawDescData
+}
+
+var file_vision_ssl_vision_wrapper_tracked_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_vision_ssl_vision_wrapper_tracked_proto_goTypes = []any{
+ (*TrackerWrapperPacket)(nil), // 0: TrackerWrapperPacket
+ (*TrackedFrame)(nil), // 1: TrackedFrame
+}
+var file_vision_ssl_vision_wrapper_tracked_proto_depIdxs = []int32{
+ 1, // 0: TrackerWrapperPacket.tracked_frame:type_name -> TrackedFrame
+ 1, // [1:1] is the sub-list for method output_type
+ 1, // [1:1] is the sub-list for method input_type
+ 1, // [1:1] is the sub-list for extension type_name
+ 1, // [1:1] is the sub-list for extension extendee
+ 0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_vision_ssl_vision_wrapper_tracked_proto_init() }
+func file_vision_ssl_vision_wrapper_tracked_proto_init() {
+ if File_vision_ssl_vision_wrapper_tracked_proto != nil {
+ return
+ }
+ file_vision_ssl_vision_detection_tracked_proto_init()
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_wrapper_tracked_proto_rawDesc), len(file_vision_ssl_vision_wrapper_tracked_proto_rawDesc)),
+ NumEnums: 0,
+ NumMessages: 1,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_vision_ssl_vision_wrapper_tracked_proto_goTypes,
+ DependencyIndexes: file_vision_ssl_vision_wrapper_tracked_proto_depIdxs,
+ MessageInfos: file_vision_ssl_vision_wrapper_tracked_proto_msgTypes,
+ }.Build()
+ File_vision_ssl_vision_wrapper_tracked_proto = out.File
+ file_vision_ssl_vision_wrapper_tracked_proto_goTypes = nil
+ file_vision_ssl_vision_wrapper_tracked_proto_depIdxs = nil
+}
diff --git a/gui/internal/vision/ssl_vp_config.pb.go b/gui/internal/vision/ssl_vp_config.pb.go
new file mode 100644
index 0000000..9529600
--- /dev/null
+++ b/gui/internal/vision/ssl_vp_config.pb.go
@@ -0,0 +1,1230 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.36.6
+// protoc (unknown)
+// source: vision/ssl_vp_config.proto
+
+package vision
+
+import (
+ gamecontroller "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+ unsafe "unsafe"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type SSL_VPConfigCameraDriver int32
+
+const (
+ // FLIR cameras
+ SSL_VPConfigCameraDriver_SPINNAKER SSL_VPConfigCameraDriver = 0
+ // Video and image files, video4linux2 (e.g. webcams) cameras
+ SSL_VPConfigCameraDriver_OPENCV SSL_VPConfigCameraDriver = 1
+ // Bluefox3 cameras
+ SSL_VPConfigCameraDriver_MVIMPACT SSL_VPConfigCameraDriver = 2
+)
+
+// Enum value maps for SSL_VPConfigCameraDriver.
+var (
+ SSL_VPConfigCameraDriver_name = map[int32]string{
+ 0: "SPINNAKER",
+ 1: "OPENCV",
+ 2: "MVIMPACT",
+ }
+ SSL_VPConfigCameraDriver_value = map[string]int32{
+ "SPINNAKER": 0,
+ "OPENCV": 1,
+ "MVIMPACT": 2,
+ }
+)
+
+func (x SSL_VPConfigCameraDriver) Enum() *SSL_VPConfigCameraDriver {
+ p := new(SSL_VPConfigCameraDriver)
+ *p = x
+ return p
+}
+
+func (x SSL_VPConfigCameraDriver) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (SSL_VPConfigCameraDriver) Descriptor() protoreflect.EnumDescriptor {
+ return file_vision_ssl_vp_config_proto_enumTypes[0].Descriptor()
+}
+
+func (SSL_VPConfigCameraDriver) Type() protoreflect.EnumType {
+ return &file_vision_ssl_vp_config_proto_enumTypes[0]
+}
+
+func (x SSL_VPConfigCameraDriver) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *SSL_VPConfigCameraDriver) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = SSL_VPConfigCameraDriver(num)
+ return nil
+}
+
+// Deprecated: Use SSL_VPConfigCameraDriver.Descriptor instead.
+func (SSL_VPConfigCameraDriver) EnumDescriptor() ([]byte, []int) {
+ return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{0}
+}
+
+type SSL_VPConfigCameraWBType int32
+
+const (
+ SSL_VPConfigCameraWBType_OUTDOOR SSL_VPConfigCameraWBType = 0
+ SSL_VPConfigCameraWBType_INDOOR SSL_VPConfigCameraWBType = 1
+ SSL_VPConfigCameraWBType_MANUAL SSL_VPConfigCameraWBType = 2
+)
+
+// Enum value maps for SSL_VPConfigCameraWBType.
+var (
+ SSL_VPConfigCameraWBType_name = map[int32]string{
+ 0: "OUTDOOR",
+ 1: "INDOOR",
+ 2: "MANUAL",
+ }
+ SSL_VPConfigCameraWBType_value = map[string]int32{
+ "OUTDOOR": 0,
+ "INDOOR": 1,
+ "MANUAL": 2,
+ }
+)
+
+func (x SSL_VPConfigCameraWBType) Enum() *SSL_VPConfigCameraWBType {
+ p := new(SSL_VPConfigCameraWBType)
+ *p = x
+ return p
+}
+
+func (x SSL_VPConfigCameraWBType) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (SSL_VPConfigCameraWBType) Descriptor() protoreflect.EnumDescriptor {
+ return file_vision_ssl_vp_config_proto_enumTypes[1].Descriptor()
+}
+
+func (SSL_VPConfigCameraWBType) Type() protoreflect.EnumType {
+ return &file_vision_ssl_vp_config_proto_enumTypes[1]
+}
+
+func (x SSL_VPConfigCameraWBType) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *SSL_VPConfigCameraWBType) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = SSL_VPConfigCameraWBType(num)
+ return nil
+}
+
+// Deprecated: Use SSL_VPConfigCameraWBType.Descriptor instead.
+func (SSL_VPConfigCameraWBType) EnumDescriptor() ([]byte, []int) {
+ return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{1}
+}
+
+type SSL_VPConfigStreamType int32
+
+const (
+ SSL_VPConfigStreamType_RAW SSL_VPConfigStreamType = 0
+ SSL_VPConfigStreamType_REPROJ_FALSE_COLOR SSL_VPConfigStreamType = 1
+ SSL_VPConfigStreamType_REPROJ_GRADIENT_DOT SSL_VPConfigStreamType = 2
+ SSL_VPConfigStreamType_REPROJ_BLOB_SCORE SSL_VPConfigStreamType = 3
+)
+
+// Enum value maps for SSL_VPConfigStreamType.
+var (
+ SSL_VPConfigStreamType_name = map[int32]string{
+ 0: "RAW",
+ 1: "REPROJ_FALSE_COLOR",
+ 2: "REPROJ_GRADIENT_DOT",
+ 3: "REPROJ_BLOB_SCORE",
+ }
+ SSL_VPConfigStreamType_value = map[string]int32{
+ "RAW": 0,
+ "REPROJ_FALSE_COLOR": 1,
+ "REPROJ_GRADIENT_DOT": 2,
+ "REPROJ_BLOB_SCORE": 3,
+ }
+)
+
+func (x SSL_VPConfigStreamType) Enum() *SSL_VPConfigStreamType {
+ p := new(SSL_VPConfigStreamType)
+ *p = x
+ return p
+}
+
+func (x SSL_VPConfigStreamType) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (SSL_VPConfigStreamType) Descriptor() protoreflect.EnumDescriptor {
+ return file_vision_ssl_vp_config_proto_enumTypes[2].Descriptor()
+}
+
+func (SSL_VPConfigStreamType) Type() protoreflect.EnumType {
+ return &file_vision_ssl_vp_config_proto_enumTypes[2]
+}
+
+func (x SSL_VPConfigStreamType) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *SSL_VPConfigStreamType) UnmarshalJSON(b []byte) error {
+ num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+ if err != nil {
+ return err
+ }
+ *x = SSL_VPConfigStreamType(num)
+ return nil
+}
+
+// Deprecated: Use SSL_VPConfigStreamType.Descriptor instead.
+func (SSL_VPConfigStreamType) EnumDescriptor() ([]byte, []int) {
+ return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{2}
+}
+
+type SSL_VPConfigCamera struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Camera driver type. Availability depending on libraries installed.
+ Driver *SSL_VPConfigCameraDriver `protobuf:"varint,1,opt,name=driver,enum=SSL_VPConfigCameraDriver" json:"driver,omitempty"`
+ // Spinnaker, mvIMPACT or OpenCV(v4l2) camera id
+ Id *uint32 `protobuf:"varint,2,opt,name=id,def=0" json:"id,omitempty"`
+ // OpenCV camera device, image or video file path (if unset id is used instead)
+ Path *string `protobuf:"bytes,3,opt,name=path,def=" json:"path,omitempty"`
+ // Camera resolution as reported by the camera. VisionProcessor might use half (true color) resolution internally with SPINNAKER and MVIMPACT.
+ // 0 = Highest resolution supported by camera
+ Width *uint32 `protobuf:"varint,4,opt,name=width,def=0" json:"width,omitempty"`
+ Height *uint32 `protobuf:"varint,5,opt,name=height,def=0" json:"height,omitempty"`
+ // Camera exposure time in ms to adjust brightness. Higher values lead to more motion blur. Lower values lead to a darker image.
+ // Camera frame rate will drop if set equal to or higher than the frame time (1 / fps_cam).
+ // 0.0 = automatic exposure
+ Exposure *float32 `protobuf:"fixed32,6,opt,name=exposure,def=0" json:"exposure,omitempty"`
+ // Camera gain to adjust brightness. Higher values lead to more noise. Lower values lead to a darker image.
+ // Frequently changing bot identities or team colors indicate an image that is too bright (all colors becoming nearly white).
+ // 0.0 = automatic gain
+ Gain *float32 `protobuf:"fixed32,7,opt,name=gain,def=0" json:"gain,omitempty"`
+ // Camera gamma as nonlinear brightness adjustment. Only supported on SPINNAKER and OPENCV.
+ // Low values reduce differences between bright and dark illuminated areas. High values increase the color contrast.
+ // 1.0 = no gamma
+ Gamma *float32 `protobuf:"fixed32,8,opt,name=gamma,def=1" json:"gamma,omitempty"`
+ // Camera white balance. OUTDOOR or INDOOR for auto white balance with green or gray carpet respectively.
+ // (distinction between OUTDOOR and INDOOR currently only implemented for SPINNAKER backend)
+ WbType *SSL_VPConfigCameraWBType `protobuf:"varint,9,opt,name=wb_type,json=wbType,enum=SSL_VPConfigCameraWBType,def=0" json:"wb_type,omitempty"`
+ WbRed *float32 `protobuf:"fixed32,10,opt,name=wb_red,json=wbRed,def=1" json:"wb_red,omitempty"`
+ WbBlue *float32 `protobuf:"fixed32,11,opt,name=wb_blue,json=wbBlue,def=1" json:"wb_blue,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+// Default values for SSL_VPConfigCamera fields.
+const (
+ Default_SSL_VPConfigCamera_Id = uint32(0)
+ Default_SSL_VPConfigCamera_Path = string("")
+ Default_SSL_VPConfigCamera_Width = uint32(0)
+ Default_SSL_VPConfigCamera_Height = uint32(0)
+ Default_SSL_VPConfigCamera_Exposure = float32(0)
+ Default_SSL_VPConfigCamera_Gain = float32(0)
+ Default_SSL_VPConfigCamera_Gamma = float32(1)
+ Default_SSL_VPConfigCamera_WbType = SSL_VPConfigCameraWBType_OUTDOOR
+ Default_SSL_VPConfigCamera_WbRed = float32(1)
+ Default_SSL_VPConfigCamera_WbBlue = float32(1)
+)
+
+func (x *SSL_VPConfigCamera) Reset() {
+ *x = SSL_VPConfigCamera{}
+ mi := &file_vision_ssl_vp_config_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_VPConfigCamera) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_VPConfigCamera) ProtoMessage() {}
+
+func (x *SSL_VPConfigCamera) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vp_config_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_VPConfigCamera.ProtoReflect.Descriptor instead.
+func (*SSL_VPConfigCamera) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *SSL_VPConfigCamera) GetDriver() SSL_VPConfigCameraDriver {
+ if x != nil && x.Driver != nil {
+ return *x.Driver
+ }
+ return SSL_VPConfigCameraDriver_SPINNAKER
+}
+
+func (x *SSL_VPConfigCamera) GetId() uint32 {
+ if x != nil && x.Id != nil {
+ return *x.Id
+ }
+ return Default_SSL_VPConfigCamera_Id
+}
+
+func (x *SSL_VPConfigCamera) GetPath() string {
+ if x != nil && x.Path != nil {
+ return *x.Path
+ }
+ return Default_SSL_VPConfigCamera_Path
+}
+
+func (x *SSL_VPConfigCamera) GetWidth() uint32 {
+ if x != nil && x.Width != nil {
+ return *x.Width
+ }
+ return Default_SSL_VPConfigCamera_Width
+}
+
+func (x *SSL_VPConfigCamera) GetHeight() uint32 {
+ if x != nil && x.Height != nil {
+ return *x.Height
+ }
+ return Default_SSL_VPConfigCamera_Height
+}
+
+func (x *SSL_VPConfigCamera) GetExposure() float32 {
+ if x != nil && x.Exposure != nil {
+ return *x.Exposure
+ }
+ return Default_SSL_VPConfigCamera_Exposure
+}
+
+func (x *SSL_VPConfigCamera) GetGain() float32 {
+ if x != nil && x.Gain != nil {
+ return *x.Gain
+ }
+ return Default_SSL_VPConfigCamera_Gain
+}
+
+func (x *SSL_VPConfigCamera) GetGamma() float32 {
+ if x != nil && x.Gamma != nil {
+ return *x.Gamma
+ }
+ return Default_SSL_VPConfigCamera_Gamma
+}
+
+func (x *SSL_VPConfigCamera) GetWbType() SSL_VPConfigCameraWBType {
+ if x != nil && x.WbType != nil {
+ return *x.WbType
+ }
+ return Default_SSL_VPConfigCamera_WbType
+}
+
+func (x *SSL_VPConfigCamera) GetWbRed() float32 {
+ if x != nil && x.WbRed != nil {
+ return *x.WbRed
+ }
+ return Default_SSL_VPConfigCamera_WbRed
+}
+
+func (x *SSL_VPConfigCamera) GetWbBlue() float32 {
+ if x != nil && x.WbBlue != nil {
+ return *x.WbBlue
+ }
+ return Default_SSL_VPConfigCamera_WbBlue
+}
+
+type SSL_VPConfigGeometry struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Total camera amount over the field
+ CameraAmount *uint32 `protobuf:"varint,1,opt,name=camera_amount,json=cameraAmount,def=1" json:"camera_amount,omitempty"`
+ // Camera height above field in mm
+ // 0.0 = automated camera height calibration, this does not work if the camera looks perpendicular to the field.
+ CameraHeight *float32 `protobuf:"fixed32,2,opt,name=camera_height,json=cameraHeight,def=0" json:"camera_height,omitempty"`
+ // Field line crossings at the edges of the camera extent in pixels from the top left image corner.
+ // The first coordinate must be the edge with the smallest x and y field coordinate.
+ LineCorners []*gamecontroller.Vector2 `protobuf:"bytes,3,rep,name=line_corners,json=lineCorners" json:"line_corners,omitempty"`
+ // Enable field line pixel refinement.
+ // Disable in cluttered environments when the geometry calibration has failed multiple times in a row.
+ Refinement *bool `protobuf:"varint,4,opt,name=refinement,def=1" json:"refinement,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+// Default values for SSL_VPConfigGeometry fields.
+const (
+ Default_SSL_VPConfigGeometry_CameraAmount = uint32(1)
+ Default_SSL_VPConfigGeometry_CameraHeight = float32(0)
+ Default_SSL_VPConfigGeometry_Refinement = bool(true)
+)
+
+func (x *SSL_VPConfigGeometry) Reset() {
+ *x = SSL_VPConfigGeometry{}
+ mi := &file_vision_ssl_vp_config_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_VPConfigGeometry) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_VPConfigGeometry) ProtoMessage() {}
+
+func (x *SSL_VPConfigGeometry) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vp_config_proto_msgTypes[1]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_VPConfigGeometry.ProtoReflect.Descriptor instead.
+func (*SSL_VPConfigGeometry) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *SSL_VPConfigGeometry) GetCameraAmount() uint32 {
+ if x != nil && x.CameraAmount != nil {
+ return *x.CameraAmount
+ }
+ return Default_SSL_VPConfigGeometry_CameraAmount
+}
+
+func (x *SSL_VPConfigGeometry) GetCameraHeight() float32 {
+ if x != nil && x.CameraHeight != nil {
+ return *x.CameraHeight
+ }
+ return Default_SSL_VPConfigGeometry_CameraHeight
+}
+
+func (x *SSL_VPConfigGeometry) GetLineCorners() []*gamecontroller.Vector2 {
+ if x != nil {
+ return x.LineCorners
+ }
+ return nil
+}
+
+func (x *SSL_VPConfigGeometry) GetRefinement() bool {
+ if x != nil && x.Refinement != nil {
+ return *x.Refinement
+ }
+ return Default_SSL_VPConfigGeometry_Refinement
+}
+
+type SSL_VPConfigThresholds struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Minimum mean cosine similarity (not normalized) of the blob border gradient (0 - 195075.0)
+ // High value lead to undetected blobs. Low values lead to an increase in false positive blob detections.
+ Circularity *float32 `protobuf:"fixed32,1,opt,name=circularity,def=15" json:"circularity,omitempty"`
+ // Minimum circularity/(3*stddev) ball blob score
+ Score *float32 `protobuf:"fixed32,2,opt,name=score,def=5" json:"score,omitempty"`
+ // Minimum confidence (0.0 - 1.0)
+ MinConfidence *float32 `protobuf:"fixed32,3,opt,name=min_confidence,json=minConfidence,def=0.2" json:"min_confidence,omitempty"`
+ // Min ball camera edge distance in mm
+ MinCamEdgeDistance *float32 `protobuf:"fixed32,4,opt,name=min_cam_edge_distance,json=minCamEdgeDistance,def=170" json:"min_cam_edge_distance,omitempty"`
+ // Maximum allowed clipping of two objects in mm
+ ClippingTolerance *float32 `protobuf:"fixed32,5,opt,name=clipping_tolerance,json=clippingTolerance,def=10" json:"clipping_tolerance,omitempty"`
+ // Added tolerance to geometry related operations in mm.
+ // Affects field border cutoff area and field line blob classification.
+ GeometryTolerance *float32 `protobuf:"fixed32,6,opt,name=geometry_tolerance,json=geometryTolerance,def=10" json:"geometry_tolerance,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+// Default values for SSL_VPConfigThresholds fields.
+const (
+ Default_SSL_VPConfigThresholds_Circularity = float32(15)
+ Default_SSL_VPConfigThresholds_Score = float32(5)
+ Default_SSL_VPConfigThresholds_MinConfidence = float32(0.20000000298023224)
+ Default_SSL_VPConfigThresholds_MinCamEdgeDistance = float32(170)
+ Default_SSL_VPConfigThresholds_ClippingTolerance = float32(10)
+ Default_SSL_VPConfigThresholds_GeometryTolerance = float32(10)
+)
+
+func (x *SSL_VPConfigThresholds) Reset() {
+ *x = SSL_VPConfigThresholds{}
+ mi := &file_vision_ssl_vp_config_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_VPConfigThresholds) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_VPConfigThresholds) ProtoMessage() {}
+
+func (x *SSL_VPConfigThresholds) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vp_config_proto_msgTypes[2]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_VPConfigThresholds.ProtoReflect.Descriptor instead.
+func (*SSL_VPConfigThresholds) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *SSL_VPConfigThresholds) GetCircularity() float32 {
+ if x != nil && x.Circularity != nil {
+ return *x.Circularity
+ }
+ return Default_SSL_VPConfigThresholds_Circularity
+}
+
+func (x *SSL_VPConfigThresholds) GetScore() float32 {
+ if x != nil && x.Score != nil {
+ return *x.Score
+ }
+ return Default_SSL_VPConfigThresholds_Score
+}
+
+func (x *SSL_VPConfigThresholds) GetMinConfidence() float32 {
+ if x != nil && x.MinConfidence != nil {
+ return *x.MinConfidence
+ }
+ return Default_SSL_VPConfigThresholds_MinConfidence
+}
+
+func (x *SSL_VPConfigThresholds) GetMinCamEdgeDistance() float32 {
+ if x != nil && x.MinCamEdgeDistance != nil {
+ return *x.MinCamEdgeDistance
+ }
+ return Default_SSL_VPConfigThresholds_MinCamEdgeDistance
+}
+
+func (x *SSL_VPConfigThresholds) GetClippingTolerance() float32 {
+ if x != nil && x.ClippingTolerance != nil {
+ return *x.ClippingTolerance
+ }
+ return Default_SSL_VPConfigThresholds_ClippingTolerance
+}
+
+func (x *SSL_VPConfigThresholds) GetGeometryTolerance() float32 {
+ if x != nil && x.GeometryTolerance != nil {
+ return *x.GeometryTolerance
+ }
+ return Default_SSL_VPConfigThresholds_GeometryTolerance
+}
+
+type Color struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Red *uint32 `protobuf:"varint,1,opt,name=red,def=128" json:"red,omitempty"`
+ Green *uint32 `protobuf:"varint,2,opt,name=green,def=128" json:"green,omitempty"`
+ Blue *uint32 `protobuf:"varint,3,opt,name=blue,def=128" json:"blue,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+// Default values for Color fields.
+const (
+ Default_Color_Red = uint32(128)
+ Default_Color_Green = uint32(128)
+ Default_Color_Blue = uint32(128)
+)
+
+func (x *Color) Reset() {
+ *x = Color{}
+ mi := &file_vision_ssl_vp_config_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *Color) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Color) ProtoMessage() {}
+
+func (x *Color) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vp_config_proto_msgTypes[3]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Color.ProtoReflect.Descriptor instead.
+func (*Color) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *Color) GetRed() uint32 {
+ if x != nil && x.Red != nil {
+ return *x.Red
+ }
+ return Default_Color_Red
+}
+
+func (x *Color) GetGreen() uint32 {
+ if x != nil && x.Green != nil {
+ return *x.Green
+ }
+ return Default_Color_Green
+}
+
+func (x *Color) GetBlue() uint32 {
+ if x != nil && x.Blue != nil {
+ return *x.Blue
+ }
+ return Default_Color_Blue
+}
+
+type VPColor struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Reference *Color `protobuf:"bytes,1,opt,name=reference" json:"reference,omitempty"`
+ Live *Color `protobuf:"bytes,2,opt,name=live" json:"live,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *VPColor) Reset() {
+ *x = VPColor{}
+ mi := &file_vision_ssl_vp_config_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *VPColor) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*VPColor) ProtoMessage() {}
+
+func (x *VPColor) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vp_config_proto_msgTypes[4]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use VPColor.ProtoReflect.Descriptor instead.
+func (*VPColor) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *VPColor) GetReference() *Color {
+ if x != nil {
+ return x.Reference
+ }
+ return nil
+}
+
+func (x *VPColor) GetLive() *Color {
+ if x != nil {
+ return x.Live
+ }
+ return nil
+}
+
+type SSL_VPConfigColor struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Strength of the reference color during color updates (0.0 - 0.5-history_force/2)
+ ReferenceForce *float32 `protobuf:"fixed32,1,opt,name=reference_force,json=referenceForce,def=0.1" json:"reference_force,omitempty"`
+ // Strength of the previous color during color updates (0.0 - 1.0-reference_force)
+ HistoryForce *float32 `protobuf:"fixed32,2,opt,name=history_force,json=historyForce,def=0.7" json:"history_force,omitempty"`
+ // Colors used for ball determination
+ Orange *VPColor `protobuf:"bytes,3,opt,name=orange" json:"orange,omitempty"`
+ Field *VPColor `protobuf:"bytes,4,opt,name=field" json:"field,omitempty"`
+ // Colors used for center blob determination
+ Yellow *VPColor `protobuf:"bytes,5,opt,name=yellow" json:"yellow,omitempty"`
+ Blue *VPColor `protobuf:"bytes,6,opt,name=blue" json:"blue,omitempty"`
+ // Colors used for side blob determination
+ Green *VPColor `protobuf:"bytes,7,opt,name=green" json:"green,omitempty"`
+ Pink *VPColor `protobuf:"bytes,8,opt,name=pink" json:"pink,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+// Default values for SSL_VPConfigColor fields.
+const (
+ Default_SSL_VPConfigColor_ReferenceForce = float32(0.10000000149011612)
+ Default_SSL_VPConfigColor_HistoryForce = float32(0.699999988079071)
+)
+
+func (x *SSL_VPConfigColor) Reset() {
+ *x = SSL_VPConfigColor{}
+ mi := &file_vision_ssl_vp_config_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_VPConfigColor) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_VPConfigColor) ProtoMessage() {}
+
+func (x *SSL_VPConfigColor) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vp_config_proto_msgTypes[5]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_VPConfigColor.ProtoReflect.Descriptor instead.
+func (*SSL_VPConfigColor) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *SSL_VPConfigColor) GetReferenceForce() float32 {
+ if x != nil && x.ReferenceForce != nil {
+ return *x.ReferenceForce
+ }
+ return Default_SSL_VPConfigColor_ReferenceForce
+}
+
+func (x *SSL_VPConfigColor) GetHistoryForce() float32 {
+ if x != nil && x.HistoryForce != nil {
+ return *x.HistoryForce
+ }
+ return Default_SSL_VPConfigColor_HistoryForce
+}
+
+func (x *SSL_VPConfigColor) GetOrange() *VPColor {
+ if x != nil {
+ return x.Orange
+ }
+ return nil
+}
+
+func (x *SSL_VPConfigColor) GetField() *VPColor {
+ if x != nil {
+ return x.Field
+ }
+ return nil
+}
+
+func (x *SSL_VPConfigColor) GetYellow() *VPColor {
+ if x != nil {
+ return x.Yellow
+ }
+ return nil
+}
+
+func (x *SSL_VPConfigColor) GetBlue() *VPColor {
+ if x != nil {
+ return x.Blue
+ }
+ return nil
+}
+
+func (x *SSL_VPConfigColor) GetGreen() *VPColor {
+ if x != nil {
+ return x.Green
+ }
+ return nil
+}
+
+func (x *SSL_VPConfigColor) GetPink() *VPColor {
+ if x != nil {
+ return x.Pink
+ }
+ return nil
+}
+
+type SSL_VPConfigNetwork struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Game controller ip address
+ GcIp *string `protobuf:"bytes,1,opt,name=gc_ip,json=gcIp,def=224.5.23.1" json:"gc_ip,omitempty"`
+ // Game controller UDP port
+ GcPort *uint32 `protobuf:"varint,2,opt,name=gc_port,json=gcPort,def=10003" json:"gc_port,omitempty"`
+ // Vision IP address (port impossible to adjust over network)
+ VisionIp *string `protobuf:"bytes,3,opt,name=vision_ip,json=visionIp,def=224.5.23.2" json:"vision_ip,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+// Default values for SSL_VPConfigNetwork fields.
+const (
+ Default_SSL_VPConfigNetwork_GcIp = string("224.5.23.1")
+ Default_SSL_VPConfigNetwork_GcPort = uint32(10003)
+ Default_SSL_VPConfigNetwork_VisionIp = string("224.5.23.2")
+)
+
+func (x *SSL_VPConfigNetwork) Reset() {
+ *x = SSL_VPConfigNetwork{}
+ mi := &file_vision_ssl_vp_config_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_VPConfigNetwork) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_VPConfigNetwork) ProtoMessage() {}
+
+func (x *SSL_VPConfigNetwork) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vp_config_proto_msgTypes[6]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_VPConfigNetwork.ProtoReflect.Descriptor instead.
+func (*SSL_VPConfigNetwork) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *SSL_VPConfigNetwork) GetGcIp() string {
+ if x != nil && x.GcIp != nil {
+ return *x.GcIp
+ }
+ return Default_SSL_VPConfigNetwork_GcIp
+}
+
+func (x *SSL_VPConfigNetwork) GetGcPort() uint32 {
+ if x != nil && x.GcPort != nil {
+ return *x.GcPort
+ }
+ return Default_SSL_VPConfigNetwork_GcPort
+}
+
+func (x *SSL_VPConfigNetwork) GetVisionIp() string {
+ if x != nil && x.VisionIp != nil {
+ return *x.VisionIp
+ }
+ return Default_SSL_VPConfigNetwork_VisionIp
+}
+
+type SSL_VPConfigStream struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // If false no network live stream will be encoded and sent.
+ Active *bool `protobuf:"varint,1,opt,name=active,def=1" json:"active,omitempty"`
+ // Type of image to transmit.
+ Type *SSL_VPConfigStreamType `protobuf:"varint,2,opt,name=type,enum=SSL_VPConfigStreamType,def=0" json:"type,omitempty"`
+ // Camera RTP stream destination IP
+ StreamIp *string `protobuf:"bytes,3,opt,name=stream_ip,json=streamIp,def=127.0.0.1" json:"stream_ip,omitempty"`
+ StreamPort *uint32 `protobuf:"varint,4,opt,name=stream_port,json=streamPort,def=10100" json:"stream_port,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+// Default values for SSL_VPConfigStream fields.
+const (
+ Default_SSL_VPConfigStream_Active = bool(true)
+ Default_SSL_VPConfigStream_Type = SSL_VPConfigStreamType_RAW
+ Default_SSL_VPConfigStream_StreamIp = string("127.0.0.1")
+ Default_SSL_VPConfigStream_StreamPort = uint32(10100)
+)
+
+func (x *SSL_VPConfigStream) Reset() {
+ *x = SSL_VPConfigStream{}
+ mi := &file_vision_ssl_vp_config_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_VPConfigStream) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_VPConfigStream) ProtoMessage() {}
+
+func (x *SSL_VPConfigStream) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vp_config_proto_msgTypes[7]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_VPConfigStream.ProtoReflect.Descriptor instead.
+func (*SSL_VPConfigStream) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *SSL_VPConfigStream) GetActive() bool {
+ if x != nil && x.Active != nil {
+ return *x.Active
+ }
+ return Default_SSL_VPConfigStream_Active
+}
+
+func (x *SSL_VPConfigStream) GetType() SSL_VPConfigStreamType {
+ if x != nil && x.Type != nil {
+ return *x.Type
+ }
+ return Default_SSL_VPConfigStream_Type
+}
+
+func (x *SSL_VPConfigStream) GetStreamIp() string {
+ if x != nil && x.StreamIp != nil {
+ return *x.StreamIp
+ }
+ return Default_SSL_VPConfigStream_StreamIp
+}
+
+func (x *SSL_VPConfigStream) GetStreamPort() uint32 {
+ if x != nil && x.StreamPort != nil {
+ return *x.StreamPort
+ }
+ return Default_SSL_VPConfigStream_StreamPort
+}
+
+type SSL_VPConfig struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Persistent human-readable network unique identifier (e.g. hostname or hostname:suffix if multiple VP instances on the same host).
+ Instance *string `protobuf:"bytes,1,req,name=instance" json:"instance,omitempty"`
+ // Corresponding to the camera_id used in SSL_DetectionFrame. Unique per field and implies position on the field:
+ // Single camera field: 0 = global field
+ // Double camera field: 0 = -x side, 1 = +x side
+ // Quadruple cam field: 0 = -x and -y, 1 = -x and +y, 2 = +x and -y, 3 = +x and +y
+ // Configuration for more cams depending on field shape.
+ CameraId *uint32 `protobuf:"varint,2,opt,name=camera_id,json=cameraId,def=0" json:"camera_id,omitempty"`
+ // Database of SSL game controller team names and robot heights in mm.
+ // If the team broadcasted by the game controller has no entry, the average robot height is used.
+ RobotHeights map[string]float32 `protobuf:"bytes,3,rep,name=robot_heights,json=robotHeights" json:"robot_heights,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"fixed32,2,opt,name=value"`
+ Camera *SSL_VPConfigCamera `protobuf:"bytes,4,opt,name=camera" json:"camera,omitempty"`
+ Geometry *SSL_VPConfigGeometry `protobuf:"bytes,5,opt,name=geometry" json:"geometry,omitempty"`
+ Thresholds *SSL_VPConfigThresholds `protobuf:"bytes,6,opt,name=thresholds" json:"thresholds,omitempty"`
+ Color *SSL_VPConfigColor `protobuf:"bytes,7,opt,name=color" json:"color,omitempty"`
+ Network *SSL_VPConfigNetwork `protobuf:"bytes,8,opt,name=network" json:"network,omitempty"`
+ Stream *SSL_VPConfigStream `protobuf:"bytes,9,opt,name=stream" json:"stream,omitempty"`
+ // Wait for geometry prior to processing frames
+ WaitForGeometry *bool `protobuf:"varint,10,opt,name=wait_for_geometry,json=waitForGeometry,def=0" json:"wait_for_geometry,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+// Default values for SSL_VPConfig fields.
+const (
+ Default_SSL_VPConfig_CameraId = uint32(0)
+ Default_SSL_VPConfig_WaitForGeometry = bool(false)
+)
+
+func (x *SSL_VPConfig) Reset() {
+ *x = SSL_VPConfig{}
+ mi := &file_vision_ssl_vp_config_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SSL_VPConfig) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SSL_VPConfig) ProtoMessage() {}
+
+func (x *SSL_VPConfig) ProtoReflect() protoreflect.Message {
+ mi := &file_vision_ssl_vp_config_proto_msgTypes[8]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SSL_VPConfig.ProtoReflect.Descriptor instead.
+func (*SSL_VPConfig) Descriptor() ([]byte, []int) {
+ return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *SSL_VPConfig) GetInstance() string {
+ if x != nil && x.Instance != nil {
+ return *x.Instance
+ }
+ return ""
+}
+
+func (x *SSL_VPConfig) GetCameraId() uint32 {
+ if x != nil && x.CameraId != nil {
+ return *x.CameraId
+ }
+ return Default_SSL_VPConfig_CameraId
+}
+
+func (x *SSL_VPConfig) GetRobotHeights() map[string]float32 {
+ if x != nil {
+ return x.RobotHeights
+ }
+ return nil
+}
+
+func (x *SSL_VPConfig) GetCamera() *SSL_VPConfigCamera {
+ if x != nil {
+ return x.Camera
+ }
+ return nil
+}
+
+func (x *SSL_VPConfig) GetGeometry() *SSL_VPConfigGeometry {
+ if x != nil {
+ return x.Geometry
+ }
+ return nil
+}
+
+func (x *SSL_VPConfig) GetThresholds() *SSL_VPConfigThresholds {
+ if x != nil {
+ return x.Thresholds
+ }
+ return nil
+}
+
+func (x *SSL_VPConfig) GetColor() *SSL_VPConfigColor {
+ if x != nil {
+ return x.Color
+ }
+ return nil
+}
+
+func (x *SSL_VPConfig) GetNetwork() *SSL_VPConfigNetwork {
+ if x != nil {
+ return x.Network
+ }
+ return nil
+}
+
+func (x *SSL_VPConfig) GetStream() *SSL_VPConfigStream {
+ if x != nil {
+ return x.Stream
+ }
+ return nil
+}
+
+func (x *SSL_VPConfig) GetWaitForGeometry() bool {
+ if x != nil && x.WaitForGeometry != nil {
+ return *x.WaitForGeometry
+ }
+ return Default_SSL_VPConfig_WaitForGeometry
+}
+
+var File_vision_ssl_vp_config_proto protoreflect.FileDescriptor
+
+const file_vision_ssl_vp_config_proto_rawDesc = "" +
+ "\n" +
+ "\x1avision/ssl_vp_config.proto\x1a$gamecontroller/ssl_gc_geometry.proto\"\xe6\x02\n" +
+ "\x12SSL_VPConfigCamera\x121\n" +
+ "\x06driver\x18\x01 \x01(\x0e2\x19.SSL_VPConfigCameraDriverR\x06driver\x12\x11\n" +
+ "\x02id\x18\x02 \x01(\r:\x010R\x02id\x12\x14\n" +
+ "\x04path\x18\x03 \x01(\t:\x00R\x04path\x12\x17\n" +
+ "\x05width\x18\x04 \x01(\r:\x010R\x05width\x12\x19\n" +
+ "\x06height\x18\x05 \x01(\r:\x010R\x06height\x12\x1d\n" +
+ "\bexposure\x18\x06 \x01(\x02:\x010R\bexposure\x12\x15\n" +
+ "\x04gain\x18\a \x01(\x02:\x010R\x04gain\x12\x17\n" +
+ "\x05gamma\x18\b \x01(\x02:\x011R\x05gamma\x12;\n" +
+ "\awb_type\x18\t \x01(\x0e2\x19.SSL_VPConfigCameraWBType:\aOUTDOORR\x06wbType\x12\x18\n" +
+ "\x06wb_red\x18\n" +
+ " \x01(\x02:\x011R\x05wbRed\x12\x1a\n" +
+ "\awb_blue\x18\v \x01(\x02:\x011R\x06wbBlue\"\xb9\x01\n" +
+ "\x14SSL_VPConfigGeometry\x12&\n" +
+ "\rcamera_amount\x18\x01 \x01(\r:\x011R\fcameraAmount\x12&\n" +
+ "\rcamera_height\x18\x02 \x01(\x02:\x010R\fcameraHeight\x12+\n" +
+ "\fline_corners\x18\x03 \x03(\v2\b.Vector2R\vlineCorners\x12$\n" +
+ "\n" +
+ "refinement\x18\x04 \x01(\b:\x04trueR\n" +
+ "refinement\"\xb1\x02\n" +
+ "\x16SSL_VPConfigThresholds\x12$\n" +
+ "\vcircularity\x18\x01 \x01(\x02:\x0215R\vcircularity\x12\x17\n" +
+ "\x05score\x18\x02 \x01(\x02:\x015R\x05score\x12:\n" +
+ "\x0emin_confidence\x18\x03 \x01(\x02:\x130.20000000298023224R\rminConfidence\x126\n" +
+ "\x15min_cam_edge_distance\x18\x04 \x01(\x02:\x03170R\x12minCamEdgeDistance\x121\n" +
+ "\x12clipping_tolerance\x18\x05 \x01(\x02:\x0210R\x11clippingTolerance\x121\n" +
+ "\x12geometry_tolerance\x18\x06 \x01(\x02:\x0210R\x11geometryTolerance\"R\n" +
+ "\x05Color\x12\x15\n" +
+ "\x03red\x18\x01 \x01(\r:\x03128R\x03red\x12\x19\n" +
+ "\x05green\x18\x02 \x01(\r:\x03128R\x05green\x12\x17\n" +
+ "\x04blue\x18\x03 \x01(\r:\x03128R\x04blue\"K\n" +
+ "\aVPColor\x12$\n" +
+ "\treference\x18\x01 \x01(\v2\x06.ColorR\treference\x12\x1a\n" +
+ "\x04live\x18\x02 \x01(\v2\x06.ColorR\x04live\"\xc9\x02\n" +
+ "\x11SSL_VPConfigColor\x12<\n" +
+ "\x0freference_force\x18\x01 \x01(\x02:\x130.10000000149011612R\x0ereferenceForce\x126\n" +
+ "\rhistory_force\x18\x02 \x01(\x02:\x110.699999988079071R\fhistoryForce\x12 \n" +
+ "\x06orange\x18\x03 \x01(\v2\b.VPColorR\x06orange\x12\x1e\n" +
+ "\x05field\x18\x04 \x01(\v2\b.VPColorR\x05field\x12 \n" +
+ "\x06yellow\x18\x05 \x01(\v2\b.VPColorR\x06yellow\x12\x1c\n" +
+ "\x04blue\x18\x06 \x01(\v2\b.VPColorR\x04blue\x12\x1e\n" +
+ "\x05green\x18\a \x01(\v2\b.VPColorR\x05green\x12\x1c\n" +
+ "\x04pink\x18\b \x01(\v2\b.VPColorR\x04pink\"\x7f\n" +
+ "\x13SSL_VPConfigNetwork\x12\x1f\n" +
+ "\x05gc_ip\x18\x01 \x01(\t:\n" +
+ "224.5.23.1R\x04gcIp\x12\x1e\n" +
+ "\agc_port\x18\x02 \x01(\r:\x0510003R\x06gcPort\x12'\n" +
+ "\tvision_ip\x18\x03 \x01(\t:\n" +
+ "224.5.23.2R\bvisionIp\"\xb4\x01\n" +
+ "\x12SSL_VPConfigStream\x12\x1c\n" +
+ "\x06active\x18\x01 \x01(\b:\x04trueR\x06active\x120\n" +
+ "\x04type\x18\x02 \x01(\x0e2\x17.SSL_VPConfigStreamType:\x03RAWR\x04type\x12&\n" +
+ "\tstream_ip\x18\x03 \x01(\t:\t127.0.0.1R\bstreamIp\x12&\n" +
+ "\vstream_port\x18\x04 \x01(\r:\x0510100R\n" +
+ "streamPort\"\xa4\x04\n" +
+ "\fSSL_VPConfig\x12\x1a\n" +
+ "\binstance\x18\x01 \x02(\tR\binstance\x12\x1e\n" +
+ "\tcamera_id\x18\x02 \x01(\r:\x010R\bcameraId\x12D\n" +
+ "\rrobot_heights\x18\x03 \x03(\v2\x1f.SSL_VPConfig.RobotHeightsEntryR\frobotHeights\x12+\n" +
+ "\x06camera\x18\x04 \x01(\v2\x13.SSL_VPConfigCameraR\x06camera\x121\n" +
+ "\bgeometry\x18\x05 \x01(\v2\x15.SSL_VPConfigGeometryR\bgeometry\x127\n" +
+ "\n" +
+ "thresholds\x18\x06 \x01(\v2\x17.SSL_VPConfigThresholdsR\n" +
+ "thresholds\x12(\n" +
+ "\x05color\x18\a \x01(\v2\x12.SSL_VPConfigColorR\x05color\x12.\n" +
+ "\anetwork\x18\b \x01(\v2\x14.SSL_VPConfigNetworkR\anetwork\x12+\n" +
+ "\x06stream\x18\t \x01(\v2\x13.SSL_VPConfigStreamR\x06stream\x121\n" +
+ "\x11wait_for_geometry\x18\n" +
+ " \x01(\b:\x05falseR\x0fwaitForGeometry\x1a?\n" +
+ "\x11RobotHeightsEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\x02R\x05value:\x028\x01*C\n" +
+ "\x18SSL_VPConfigCameraDriver\x12\r\n" +
+ "\tSPINNAKER\x10\x00\x12\n" +
+ "\n" +
+ "\x06OPENCV\x10\x01\x12\f\n" +
+ "\bMVIMPACT\x10\x02*?\n" +
+ "\x18SSL_VPConfigCameraWBType\x12\v\n" +
+ "\aOUTDOOR\x10\x00\x12\n" +
+ "\n" +
+ "\x06INDOOR\x10\x01\x12\n" +
+ "\n" +
+ "\x06MANUAL\x10\x02*i\n" +
+ "\x16SSL_VPConfigStreamType\x12\a\n" +
+ "\x03RAW\x10\x00\x12\x16\n" +
+ "\x12REPROJ_FALSE_COLOR\x10\x01\x12\x17\n" +
+ "\x13REPROJ_GRADIENT_DOT\x10\x02\x12\x15\n" +
+ "\x11REPROJ_BLOB_SCORE\x10\x03BUB\x10SslVpConfigProtoP\x01Z?github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
+
+var (
+ file_vision_ssl_vp_config_proto_rawDescOnce sync.Once
+ file_vision_ssl_vp_config_proto_rawDescData []byte
+)
+
+func file_vision_ssl_vp_config_proto_rawDescGZIP() []byte {
+ file_vision_ssl_vp_config_proto_rawDescOnce.Do(func() {
+ file_vision_ssl_vp_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_vision_ssl_vp_config_proto_rawDesc), len(file_vision_ssl_vp_config_proto_rawDesc)))
+ })
+ return file_vision_ssl_vp_config_proto_rawDescData
+}
+
+var file_vision_ssl_vp_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
+var file_vision_ssl_vp_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
+var file_vision_ssl_vp_config_proto_goTypes = []any{
+ (SSL_VPConfigCameraDriver)(0), // 0: SSL_VPConfigCameraDriver
+ (SSL_VPConfigCameraWBType)(0), // 1: SSL_VPConfigCameraWBType
+ (SSL_VPConfigStreamType)(0), // 2: SSL_VPConfigStreamType
+ (*SSL_VPConfigCamera)(nil), // 3: SSL_VPConfigCamera
+ (*SSL_VPConfigGeometry)(nil), // 4: SSL_VPConfigGeometry
+ (*SSL_VPConfigThresholds)(nil), // 5: SSL_VPConfigThresholds
+ (*Color)(nil), // 6: Color
+ (*VPColor)(nil), // 7: VPColor
+ (*SSL_VPConfigColor)(nil), // 8: SSL_VPConfigColor
+ (*SSL_VPConfigNetwork)(nil), // 9: SSL_VPConfigNetwork
+ (*SSL_VPConfigStream)(nil), // 10: SSL_VPConfigStream
+ (*SSL_VPConfig)(nil), // 11: SSL_VPConfig
+ nil, // 12: SSL_VPConfig.RobotHeightsEntry
+ (*gamecontroller.Vector2)(nil), // 13: Vector2
+}
+var file_vision_ssl_vp_config_proto_depIdxs = []int32{
+ 0, // 0: SSL_VPConfigCamera.driver:type_name -> SSL_VPConfigCameraDriver
+ 1, // 1: SSL_VPConfigCamera.wb_type:type_name -> SSL_VPConfigCameraWBType
+ 13, // 2: SSL_VPConfigGeometry.line_corners:type_name -> Vector2
+ 6, // 3: VPColor.reference:type_name -> Color
+ 6, // 4: VPColor.live:type_name -> Color
+ 7, // 5: SSL_VPConfigColor.orange:type_name -> VPColor
+ 7, // 6: SSL_VPConfigColor.field:type_name -> VPColor
+ 7, // 7: SSL_VPConfigColor.yellow:type_name -> VPColor
+ 7, // 8: SSL_VPConfigColor.blue:type_name -> VPColor
+ 7, // 9: SSL_VPConfigColor.green:type_name -> VPColor
+ 7, // 10: SSL_VPConfigColor.pink:type_name -> VPColor
+ 2, // 11: SSL_VPConfigStream.type:type_name -> SSL_VPConfigStreamType
+ 12, // 12: SSL_VPConfig.robot_heights:type_name -> SSL_VPConfig.RobotHeightsEntry
+ 3, // 13: SSL_VPConfig.camera:type_name -> SSL_VPConfigCamera
+ 4, // 14: SSL_VPConfig.geometry:type_name -> SSL_VPConfigGeometry
+ 5, // 15: SSL_VPConfig.thresholds:type_name -> SSL_VPConfigThresholds
+ 8, // 16: SSL_VPConfig.color:type_name -> SSL_VPConfigColor
+ 9, // 17: SSL_VPConfig.network:type_name -> SSL_VPConfigNetwork
+ 10, // 18: SSL_VPConfig.stream:type_name -> SSL_VPConfigStream
+ 19, // [19:19] is the sub-list for method output_type
+ 19, // [19:19] is the sub-list for method input_type
+ 19, // [19:19] is the sub-list for extension type_name
+ 19, // [19:19] is the sub-list for extension extendee
+ 0, // [0:19] is the sub-list for field type_name
+}
+
+func init() { file_vision_ssl_vp_config_proto_init() }
+func file_vision_ssl_vp_config_proto_init() {
+ if File_vision_ssl_vp_config_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_vision_ssl_vp_config_proto_rawDesc), len(file_vision_ssl_vp_config_proto_rawDesc)),
+ NumEnums: 3,
+ NumMessages: 10,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_vision_ssl_vp_config_proto_goTypes,
+ DependencyIndexes: file_vision_ssl_vp_config_proto_depIdxs,
+ EnumInfos: file_vision_ssl_vp_config_proto_enumTypes,
+ MessageInfos: file_vision_ssl_vp_config_proto_msgTypes,
+ }.Build()
+ File_vision_ssl_vp_config_proto = out.File
+ file_vision_ssl_vp_config_proto_goTypes = nil
+ file_vision_ssl_vp_config_proto_depIdxs = nil
+}
From fd4440f2408600914f139248927761b9eaf3c341 Mon Sep 17 00:00:00 2001
From: Will Stuckey
Date: Tue, 22 Sep 2026 17:55:55 -0400
Subject: [PATCH 05/23] major UI updates
---
.github/workflows/ci.yml | 24 +-
.gitignore | 2 +-
.pre-commit-config.yaml | 15 -
README.md | 8 +-
config-camtest.yml | 159 +++
flake.nix | 9 +-
geometry-testpatch.yml | 30 +
gui/CLAUDE.md | 189 ++++
gui/Makefile | 5 +
gui/cmd/ssl-vision-processor-gui/main.go | 125 ++-
gui/cmd/ssl-vision-processor-gui/main_test.go | 52 +
gui/cmd/ssl-vision-processor-gui/routes.go | 14 +-
gui/cmd/ssl-vision-processor-gui/server.go | 133 ++-
.../ssl-vision-processor-gui/server_test.go | 143 ++-
.../testdata/geometry.yml | 23 +
gui/frontend/README.md | 57 +-
gui/frontend/dist/.gitkeep | 0
gui/frontend/embed.go | 2 +-
gui/frontend/eslint.config.js | 12 +
gui/frontend/src/App.svelte | 150 ++-
gui/frontend/src/lib/CornerPicker.svelte | 249 +++++
gui/frontend/src/lib/FieldEditor.svelte | 385 ++++++++
gui/frontend/src/lib/FieldSketch.svelte | 131 +++
.../config/ConfigCategoryPlaceholder.svelte | 94 ++
.../src/lib/config/GeometryPanel.svelte | 82 ++
gui/frontend/src/lib/fieldPresets.ts | 62 ++
gui/frontend/src/lib/fieldSplit.ts | 62 ++
gui/frontend/src/lib/geometry.svelte.ts | 152 +++
gui/frontend/src/lib/layout/ConfigNav.svelte | 105 ++
.../src/lib/layout/InstanceList.svelte | 83 ++
.../src/lib/layout/MainContent.svelte | 28 +
gui/frontend/src/lib/layout/Shell.svelte | 107 ++
gui/frontend/src/lib/layout/TabBar.svelte | 68 ++
.../src/lib/layout/configCategories.ts | 158 +++
gui/frontend/src/lib/layout/nav.svelte.ts | 50 +
gui/frontend/src/lib/wrapper-bus.ts | 4 +-
gui/frontend/vite.config.ts | 8 +
gui/go.mod | 11 +
gui/go.sum | 20 +
gui/internal/geometry/configfile.go | 116 +++
gui/internal/geometry/field.go | 87 ++
gui/internal/geometry/field_config.go | 245 +++++
gui/internal/geometry/field_config_test.go | 190 ++++
gui/internal/geometry/geometry.go | 149 +++
gui/internal/geometry/geometry_test.go | 198 ++++
gui/internal/geometry/testdata/geometry.yml | 23 +
gui/internal/hub/hub.go | 71 ++
gui/internal/hub/hub_test.go | 144 +++
gui/internal/hub/websocket.go | 163 +++
gui/internal/hub/websocket_test.go | 118 +++
gui/internal/multicast/bridge.go | 70 ++
gui/internal/multicast/bridge_test.go | 70 ++
gui/internal/snapshot/snapshot.go | 151 +++
gui/internal/snapshot/snapshot_test.go | 160 +++
pyproject.toml | 30 -
start_wrapper.sh | 4 -
uv.lock | 924 ------------------
wrapper_backend/CLAUDE.md | 42 -
wrapper_backend/README.md | 85 --
wrapper_backend/__init__.py | 39 -
wrapper_backend/__main__.py | 79 --
wrapper_backend/bus.py | 41 -
wrapper_backend/geometry.py | 175 ----
wrapper_backend/multicast.py | 107 --
wrapper_backend/snapshot.py | 42 -
wrapper_backend/websocket.py | 177 ----
66 files changed, 4790 insertions(+), 1921 deletions(-)
create mode 100644 config-camtest.yml
create mode 100644 geometry-testpatch.yml
create mode 100644 gui/CLAUDE.md
create mode 100644 gui/cmd/ssl-vision-processor-gui/main_test.go
create mode 100644 gui/cmd/ssl-vision-processor-gui/testdata/geometry.yml
create mode 100644 gui/frontend/dist/.gitkeep
create mode 100644 gui/frontend/src/lib/CornerPicker.svelte
create mode 100644 gui/frontend/src/lib/FieldEditor.svelte
create mode 100644 gui/frontend/src/lib/FieldSketch.svelte
create mode 100644 gui/frontend/src/lib/config/ConfigCategoryPlaceholder.svelte
create mode 100644 gui/frontend/src/lib/config/GeometryPanel.svelte
create mode 100644 gui/frontend/src/lib/fieldPresets.ts
create mode 100644 gui/frontend/src/lib/fieldSplit.ts
create mode 100644 gui/frontend/src/lib/geometry.svelte.ts
create mode 100644 gui/frontend/src/lib/layout/ConfigNav.svelte
create mode 100644 gui/frontend/src/lib/layout/InstanceList.svelte
create mode 100644 gui/frontend/src/lib/layout/MainContent.svelte
create mode 100644 gui/frontend/src/lib/layout/Shell.svelte
create mode 100644 gui/frontend/src/lib/layout/TabBar.svelte
create mode 100644 gui/frontend/src/lib/layout/configCategories.ts
create mode 100644 gui/frontend/src/lib/layout/nav.svelte.ts
create mode 100644 gui/internal/geometry/configfile.go
create mode 100644 gui/internal/geometry/field.go
create mode 100644 gui/internal/geometry/field_config.go
create mode 100644 gui/internal/geometry/field_config_test.go
create mode 100644 gui/internal/geometry/geometry.go
create mode 100644 gui/internal/geometry/geometry_test.go
create mode 100644 gui/internal/geometry/testdata/geometry.yml
create mode 100644 gui/internal/hub/hub.go
create mode 100644 gui/internal/hub/hub_test.go
create mode 100644 gui/internal/hub/websocket.go
create mode 100644 gui/internal/hub/websocket_test.go
create mode 100644 gui/internal/multicast/bridge.go
create mode 100644 gui/internal/multicast/bridge_test.go
create mode 100644 gui/internal/snapshot/snapshot.go
create mode 100644 gui/internal/snapshot/snapshot_test.go
delete mode 100644 pyproject.toml
delete mode 100755 start_wrapper.sh
delete mode 100644 uv.lock
delete mode 100644 wrapper_backend/CLAUDE.md
delete mode 100644 wrapper_backend/README.md
delete mode 100644 wrapper_backend/__init__.py
delete mode 100644 wrapper_backend/__main__.py
delete mode 100644 wrapper_backend/bus.py
delete mode 100644 wrapper_backend/geometry.py
delete mode 100644 wrapper_backend/multicast.py
delete mode 100644 wrapper_backend/snapshot.py
delete mode 100644 wrapper_backend/websocket.py
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b044784..18a4f43 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -34,28 +34,26 @@ jobs:
make -C build -j"$(nproc)" vision_processor geometry_benchmark blob_benchmark
'
- python:
- name: Python (wrapper_backend)
+ gui-go:
+ name: Go (gui)
runs-on: ubuntu-latest
steps:
+ # No submodule checkout: gui/internal/{vision,gamecontroller} are
+ # generated Go bindings committed to the tree (see gui/buf.gen.yaml);
+ # only `make proto` touches the proto/ submodule.
- uses: actions/checkout@v4
- with:
- submodules: recursive
- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main
- # Importing wrapper_backend runs protoc against the submodule and
- # generates wrapper_backend/proto/, which mypy needs on its path even
- # though it excludes the generated files themselves.
- - name: Lint and type check
+ - name: Format, vet, test
run: |
nix develop --command bash -c '
- uv sync --locked
- uv run python -c "import wrapper_backend"
- uv run ruff check wrapper_backend/
- uv run ruff format --check wrapper_backend/
- uv run mypy
+ cd gui
+ test -z "$(gofmt -l .)" || { gofmt -l .; exit 1; }
+ go vet ./cmd/... ./internal/... ./frontend
+ go build ./cmd/... ./internal/... ./frontend
+ go test ./cmd/... ./internal/... ./frontend -race
'
frontend:
diff --git a/.gitignore b/.gitignore
index ec838e8..ae7fe04 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,6 @@
/src/cl_kernels.S
/src/proto
/python/proto
-/wrapper_backend/proto
__pycache__
# Cam viewer
@@ -18,6 +17,7 @@ __pycache__
vision_processor
blob_benchmark
geometry_benchmark
+/gui/bin
# Makefile sentinel for the frontend build
/gui/.frontend
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 8a74344..7c5856b 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,21 +1,6 @@
repos:
- - repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.15.12
- hooks:
- - id: ruff
- args: [--fix]
- files: ^wrapper_backend/
- - id: ruff-format
- files: ^wrapper_backend/
- repo: local
hooks:
- - id: mypy
- name: mypy
- entry: uv run mypy
- language: system
- types: [python]
- files: ^wrapper_backend/
- pass_filenames: false
- id: eslint
name: eslint
entry: npm --prefix gui/frontend run lint
diff --git a/README.md b/README.md
index d903765..99f3d40 100644
--- a/README.md
+++ b/README.md
@@ -12,12 +12,12 @@ The geometry publisher `geom_publisher.py` publishes the field geometry
for all vision_processors, teams and the game controller.
`cam_viewer.py` opens the `mpv` video player with the camera streams from the vision_processor instances.
-## Wrapper
+## GUI
-A modular replacement for `geom_publisher.py` plus a browser UI:
+A Go host plus a browser UI, replacing `geom_publisher.py` for anyone running it:
-- `wrapper_backend/` — async Python (uv-managed). Owns the field geometry, absorbs incoming calibrations, exposes the bus over WebSocket. Run with `./start_wrapper.sh` (defaults to `geometry-divB.yml`). See [`wrapper_backend/README.md`](wrapper_backend/README.md).
-- `gui/frontend/` — Svelte 5 + TypeScript + Vite. Connects to the backend's WebSocket and renders the operator UI. Run with `cd gui/frontend && npm install && npm run dev`. See [`gui/frontend/README.md`](gui/frontend/README.md).
+- `gui/` — Go host (`cmd/ssl-vision-processor-gui`). Owns the field geometry, absorbs calibrations from vision processors over multicast, and serves the embedded frontend, JSON API, a WebSocket for live updates, and debug snapshot images all on one port. Run with `cd gui && make run` (defaults to `geometry-divB.yml`).
+- `gui/frontend/` — Svelte 5 + TypeScript + Vite, embedded into the Go binary. Run standalone with `cd gui/frontend && npm install && npm run dev` (proxies `/api` and `/ws` to the Go host), or serve it from the Go host directly with `make run`. See [`gui/frontend/README.md`](gui/frontend/README.md).
## Dependency installation and compilation
diff --git a/config-camtest.yml b/config-camtest.yml
new file mode 100644
index 0000000..88c8867
--- /dev/null
+++ b/config-camtest.yml
@@ -0,0 +1,159 @@
+# VisionProcessor configuration
+
+# Vision camera ID handled by this VisionProcessor instance.
+# On multi camera fields the IDs have to be ordered according to camera_ids.png.
+#cam_id: 0
+
+# Team bot heights yml file (heights in mm)
+#bot_heights_file: robot-heights.yml
+
+camera:
+ # Camera driver type. Availability depending on libraries installed.
+ # Existing: SPINNAKER (FLIR cameras), MVIMPACT (Bluefox3 cameras), OPENCV(files, v4l2 cameras)
+ driver: OPENCV
+
+ # Spinnaker, mvIMPACT or OpenCV(v4l2) camera id
+ #id: 0
+ # OpenCV camera device, image or video file path (if unset id is used instead)
+ path: /dev/video0
+
+ # Camera resolution as reported by the camera. VisionProcessor might use half (true color) resolution internally with SPINNAKER and MVIMPACT.
+ # 0 = highest resolution supported by the camera
+ #width: 0
+ #height: 0
+
+ # Camera exposure time in ms to adjust brightness. Higher values lead to more motion blur. Lower values lead to a darker image.
+ # Camera frame rate will drop if set equal to or higher than the frame time (1 / fps_cam).
+ # 0.0 = automatic exposure
+ #exposure: 0.0
+ # Camera gain to adjust brightness. Higher values lead to more noise. Lower values lead to a darker image.
+ # Frequently changing bot identities or team colors indicate an image that is too bright (all colors becoming nearly white).
+ # 0.0 = automatic gain
+ #gain: 0.0
+ # Camera gamma as nonlinear brightness adjustment. Only supported on SPINNAKER and OPENCV.
+ # Low values reduce differences between bright and dark illuminated areas. High values increase the color contrast.
+ # 1.0 = no gamma
+ #gamma: 1.0
+
+ # Camera white balance. OUTDOOR or INDOOR for auto white balance with green or gray carpet respectively.
+ # (distinction between OUTDOOR and INDOOR currently only implemented for SPINNAKER backend)
+ #white_balance: OUTDOOR
+ # If you want to set manual white balance values use this format:
+ #white_balance:
+ # red: 1.0
+ # blue: 1.0
+
+geometry:
+ # Total camera amount over the field
+ camera_amount: 2
+ # Camera height above field in mm
+ # 0.0 = automated camera height calibration, this does not work if the camera looks perpendicular to the field
+ #camera_height: 0.0
+
+ # Field line crossings at the edges of the camera extent in pixels from the top left image corner.
+ # The first coordinate must be the edge with the smallest x and y field coordinate.
+ # Only the first point's identity matters -- GeomModel.cpp brute-forces the
+ # correct clockwise order for the other three. First point = the corner
+ # picker's marker 4, which touches the goal box (confirmed against
+ # img/0.geomcalib_input.png; marker 3 is the same goal-box edge's other end
+ # and would also be a valid choice). Left/right (marker 3 vs 4 first) is an
+ # arbitrary but so-far-unverified choice: doesn't matter with one camera,
+ # would need to agree with camera 1 if a second one joins.
+ line_corners:
+ - [398, 422]
+ - [247, 135]
+ - [455, 33]
+ - [564, 327]
+
+ # Enable field line pixel refinement.
+ # Disable in cluttered environments when the geometry calibration has failed multiple times in a row.
+ #refinement: true
+
+ # Minimum brightness difference to surrounding pixels for the classification as field line pixel (0 - 255)
+ #field_line_threshold: 5
+ # Minimum length of line segments to ensure angular stability in pixels
+ #min_line_segment_length: 10.0
+ # Maximum perpendicular offset of line segments for merging in pixels
+ #max_line_segment_offset: 10.0
+ # Maximum relative angle of line segments for merging in °
+ #max_line_segment_angle: 3.0
+
+thresholds:
+ # Minimum mean cosine similarity (not normalized) of the blob border gradient (0 - 195075.0)
+ # High value lead to undetected blobs. Low values lead to an increase in false positive blob detections.
+ #circularity: 15.0
+ # Minimum circularity/(3*stddev) ball blob score
+ #score: 5.0
+
+ # Maximum amount of blobs processed per frame. Should not be necessary to adjust this value.
+ #blobs: 2000
+
+ # Minimum confidence (0.0 - 1.0)
+ #min_confidence: 0.2
+
+ # Min ball camera edge distance in mm
+ #min_cam_edge_distance: 170.0
+
+ # Maximum allowed clipping of two objects in mm
+ #clipping_tolerance: 10.0
+
+ # Added tolerance to geometry related operations in mm.
+ # Affects field border cutoff area and field line blob classification.
+ #geometry_tolerance: 10.0
+
+color:
+ # Strength of the reference color during color updates (0.0 - 0.5-history_force/2)
+ #reference_force: 0.1
+ # Strength of the previous color during color updates (0.0 - 1.0-reference_force)
+ #history_force: 0.7
+
+ # Reference colors used for ball determination
+ #orange: [192, 128, 64]
+ #field: [128, 128, 128]
+ # Reference colors used for center blob determination
+ #yellow: [255, 128, 0]
+ #blue: [0, 128, 255]
+ # Reference colors used for side blob determination
+ #green: [0, 255, 128]
+ #pink: [255, 0, 128]
+
+tracking:
+ # Min tracking radius in mm
+ #min_tracking_radius: 20.0
+
+ # Max tracked bot acceleration in m/s^2
+ #max_bot_acceleration: 6.5
+
+network:
+ # Game controller multicast ip address
+ #gc_ip: "224.5.23.1"
+ # Game controller multicast port
+ #gc_port: 10003
+
+ # Vision multicast IP address
+ #vision_ip: "224.5.23.2"
+ # Vision multicast port
+ #vision_port: 10006
+
+stream:
+ # If false no network live stream will be encoded and sent
+ #active: true
+ # Only stream raw camera footage. Useful for recordings.
+ #raw_feed: false
+
+ # Camera stream ip prefix
+ #ip_base_prefix: 224.5.23.
+ # Camera stream ip end base (cam_id is added to maintain separation)
+ #ip_base_end: 100
+ # Camera stream port
+ #port: 10100
+
+debug:
+ # Ground truth file. Only used by blob and geometry benchmark.
+ #ground_truth: gt.yml
+ # Wait for geometry prior to processing frames
+ #wait_for_geometry: false
+ # Save additional debug images in img/.
+ #debug_images: false
+ # Periodically overwrite img/.sample..png while calibration isn't accepted yet, every N milliseconds. 0 disables.
+ debug_stream_interval_ms: 3000
diff --git a/flake.nix b/flake.nix
index 18a6eae..b3243d2 100644
--- a/flake.nix
+++ b/flake.nix
@@ -18,8 +18,7 @@
let
pkgs = nixpkgs.legacyPackages.${system};
- # Only what python/*.py needs at the system level. wrapper_backend/ is
- # uv-managed (see pyproject.toml) and brings its own venv.
+ # Only what python/*.py needs at the system level.
python = pkgs.python3.withPackages (ps: [
ps.protobuf
ps.pyyaml
@@ -42,6 +41,7 @@
# here rather than in a second flake so that one `nix develop`
# covers every language in the repo.
go
+ gopls # language server; VS Code formats and vets through it
buf # protobuf codegen for Go and TypeScript at once
nodejs_22 # frontend build; .github/workflows/ci.yml pins 22
];
@@ -68,17 +68,12 @@
openclRuntime
python
- uv # wrapper_backend/
];
# The ICD loader finds runtimes through this. Without it the loader
# reports zero platforms and vision_processor exits at startup.
OCL_ICD_VENDORS = "${openclRuntime}/etc/OpenCL/vendors";
- # uv must not download its own interpreter inside the shell.
- UV_PYTHON = python.interpreter;
- UV_PYTHON_DOWNLOADS = "never";
-
# The other league Go tools carry a `toolchain` line newer than the
# `go` directive (ssl-vision-client: go 1.25.0, toolchain go1.27.1).
# Left to itself Go would fetch that toolchain over the network,
diff --git a/geometry-testpatch.yml b/geometry-testpatch.yml
new file mode 100644
index 0000000..0eba29c
--- /dev/null
+++ b/geometry-testpatch.yml
@@ -0,0 +1,30 @@
+field:
+ field_length: 2160
+ field_width: 1680
+ goal_width: 280
+ goal_depth: 50
+ goal_height: 160
+ penalty_area_depth: 290
+ penalty_area_width: 570
+ goal_center_to_penalty_mark: 1440
+ boundary_width: 100
+ boundary_width_goal_line: 100
+ center_circle_radius: 140
+ line_thickness: 10
+ ball_radius: 22
+ max_robot_radius: 90
+ goal_substitution_area_width: 0
+models:
+ chip_fixed_loss:
+ damping_xy_first_hop: 0.55
+ damping_xy_other_hops: 0.88
+ damping_z: 0.54
+ straight_two_phase:
+ acc_roll: -0.45
+ acc_slide: -3.4
+ k_switch: 0.64
+optional_field_lines:
+ centercircle: false
+ goal2goal: false
+ halfway: true
+ penalty: true
diff --git a/gui/CLAUDE.md b/gui/CLAUDE.md
new file mode 100644
index 0000000..a39eff6
--- /dev/null
+++ b/gui/CLAUDE.md
@@ -0,0 +1,189 @@
+# CLAUDE.md — gui/
+
+Single Go binary plus an embedded Svelte frontend: the browser-facing host for
+vision-processor. Owns field geometry, absorbs calibrations from vision
+processor instances over multicast, and serves the frontend, a JSON API, a
+WebSocket, and debug snapshot images all on one port.
+
+Replaces `python/geom_publisher.py` for anyone running it. Does not replace it
+in `setup.sh` or for `python/dataset.py` / `overlap_benchmark.py` / `replay.py`,
+which still import it directly — do not delete `geom_publisher.py`.
+
+## Commands
+
+All run from `gui/`.
+
+```
+make run # build frontend, run the Go host on :8085
+make test # frontend check/lint/format + go test -race, all packages
+make install # go install after a frontend build
+make proto # buf generate: needs network, never run from a sandboxed build
+make clean # wipe dist/ and the frontend-build sentinel
+```
+
+```
+cd frontend && npm run dev # Vite HMR on :5173, proxies /api and /ws to :8085
+```
+
+## Repository layout
+
+```
+cmd/ssl-vision-processor-gui/ entry point: flags, wiring, HTTP server
+internal/
+ geometry/ field config + calibration merge + 1Hz publish loop
+ multicast/ bridge to the SSL vision multicast group
+ hub/ topic pub/sub + the /ws handler
+ snapshot/ debug image listing/serving
+ logging/ slog setup: tint console + lumberjack file
+ vision/ generated Go protobuf (DO NOT EDIT, see buf.gen.yaml)
+ gamecontroller/ generated Go protobuf
+frontend/ Svelte 5 + TypeScript + Vite, embedded via //go:embed
+buf.gen.yaml generates both internal/{vision,gamecontroller} and
+ frontend/src/proto from ../proto/proto (the submodule, read
+ directly -- no vendored copy)
+```
+
+## Stack
+
+- **Go 1.22+ `net/http`**, no router library. Method-prefixed patterns
+ (`"GET /api/health"`) and `{wildcard}` path values do the routing;
+ `r.PathValue(...)` reads them.
+- **`gorilla/websocket`** for `/ws`. Not stdlib; there is no other serious
+ option (`golang.org/x/net/websocket` is legacy/incomplete).
+- **`ssl-go-tools/pkg/sslnet`** for multicast (`MulticastServer`, `UdpClient`)
+ rather than hand-rolled sockets, to match how the rest of the league already
+ handles multi-interface venue boxes.
+- **`google.golang.org/protobuf` + `protojson`**, never `encoding/json` on a
+ generated message (see Gotchas).
+- **Svelte 5 runes only**, no stores added beyond what predates this work
+ (`wrapper-bus.ts` still uses `svelte/store`'s `readable` -- not yet migrated,
+ not a blocker).
+
+## Architectural decisions
+
+**Single Go binary, not Go+Python.** The original plan was "Go host, keep the
+Python wrapper for geometry." That changed once it was clear the Python
+service (`wrapper_backend/geometry.py`, since deleted) did bookkeeping --
+merge calibrations, lay out field markings from YAML, republish at 1Hz -- and
+no calibration math. All calibration math stays in C++ (`src/calib/`). The
+bookkeeping is now `internal/geometry`, ported directly; `wrapper_backend/`
+is gone.
+
+**JSON to the browser, protojson specifically -- never raw protobuf bytes,
+never `encoding/json` on a proto message.** `encoding/json` on a generated
+struct compiles and looks like it works, then renders enums as integers,
+mishandles `oneof`, and ignores the well-known types. `protojson.Marshal` is
+what every other league tool's JSON output already agrees on. The one
+exception is the multicast wire itself (`Geometry.Encoded()`), which stays raw
+protobuf bytes because that's the SSL protocol.
+
+**`Geometry` is mutex-guarded, with a cached encoding, not a "reads don't need
+the lock" type.** `proto.Marshal` writes to the message's internal size cache,
+so even a read-only marshal is a mutation. `Absorb` re-marshals and caches the
+result; `Encoded()` and the WS hub publish just read the cached bytes.
+`Snapshot()` returns `proto.Clone` for anyone who needs the actual message.
+
+**Incoming calibrations are validated with `proto.CheckInitialized` before
+they touch stored state.** A calibration missing a required field (proto2, a
+dozen required floats) is logged and dropped, not merged -- merge-then-fail-to-
+encode would leave `Geometry`'s live message out of sync with its last-good
+`Encoded()` bytes.
+
+**The hub's `Subscribe`/`Publish` uses size-1, drop-stale channels** --
+deliberately mirroring the semantics of the retired Python `bus.py` (`Queue`
+of size 1, drain-then-put). A slow WebSocket client sees only the latest
+value, never a growing backlog.
+
+**`unsubscribe` closes the per-topic channel.** That's what lets a
+per-connection forwarding goroutine's `for data := range ch` exit cleanly when
+one topic is unsubscribed without tearing down the whole connection.
+
+**Snapshot serving assumes the Go host and the vision processor share a
+filesystem.** This is unchanged from the Python `snapshot.py` it replaces and
+is a known limitation, not an oversight -- it does not work once vision
+processors run on other hosts. See "Not yet built."
+
+**buf reads the proto submodule directly**: `inputs: [{directory:
+../proto/proto}]` in `buf.gen.yaml`. No vendored copy to drift. Generated
+output is committed (Nix builds are sandboxed/offline, so `make proto` cannot
+run inside one); `gui/frontend/dist/.gitkeep` exists for the same reason on
+the frontend side -- `//go:embed` fails to compile if `dist/` doesn't exist,
+so a fresh clone with no `npm run build` yet must still be able to `go test`.
+
+**Discovery is multicast-announce-based, config is host-owned** -- both
+still unimplemented; see below.
+
+## Gotchas
+
+- **proto2, not proto3.** Every field on the SSL messages is a pointer
+ (`*string`, `*float32`, ...) and most are `required`. Read through the
+ generated `Get*()` methods (nil-safe); write through `proto.String(...)`,
+ `proto.Float32(...)`, or a literal struct with pointer fields. A `required`
+ field left unset makes `proto.Marshal` return an error -- this is relied on
+ deliberately (see `CheckInitialized` above), not worked around.
+- **`go test ./...` from `gui/` will try to compile stray Go source inside
+ `frontend/node_modules`** (at least one npm package ships a `.go` file).
+ Use `go test ./cmd/... ./internal/... ./frontend`, which is what
+ `Makefile`'s `GO_PACKAGES` and CI already do. Don't `go test ./...` by hand.
+- **`GOTOOLCHAIN=local` is set in the root `flake.nix`.** Without it, Go
+ silently fetches whatever toolchain a dependency's `go.mod` names over the
+ network the moment it's newer than what's pinned, defeating the pin inside a
+ sandboxed build.
+- **`ReadHeaderTimeout` is set on the `http.Server`; `WriteTimeout` is not,**
+ and must not be. `WriteTimeout` is an absolute deadline on the whole
+ response and would kill every `/ws` connection (and any future video
+ stream) after N seconds.
+- **`ServeMux` route precedence is by specificity, not registration order.**
+ `/api/` is registered as a catch-all `NotFoundHandler` specifically so an
+ unrouted `/api/*` path 404s instead of falling through to the SPA handler
+ and returning HTML with status 200 -- which would otherwise break every
+ `fetch(...).json()` call against a typo'd endpoint.
+- **The WS hub pings every ~54s and sets read/write deadlines** so a client
+ that vanishes without a clean close (dead wifi, a closed laptop lid) is
+ detected and its goroutines cleaned up, rather than leaking for the life of
+ the process.
+- **`internal/snapshot` validates `camID`/`view` path segments against a
+ strict character set before they reach `filepath.Glob`.** An unvalidated
+ `view` of `*` would glob the entire snapshot directory; this is enforced and
+ tested (`TestHandleGetRejectsUnsafeSegments`), not just documented.
+- **`unsubscribe` in `internal/hub` must be called exactly once.** It closes
+ the channel; a second call panics on double-close, same as any Go channel.
+
+## Testing
+
+`go test -race` on every package, always -- this code is concurrent by
+construction (a mutex-guarded `Geometry`, a multi-goroutine WS hub) and the
+race detector has caught real bugs here before it shipped. Integration-style
+tests are preferred over mocks where the real thing is cheap to stand up:
+`internal/hub`'s WebSocket tests dial a real `httptest.Server` with a real
+`gorilla/websocket` client rather than faking the protocol; `internal/geometry`
+and `cmd/.../server_test.go` load real `testdata/*.yml` fixtures rather than
+constructing Go structs by hand.
+
+The full loop (this package's `Geometry`/`multicast.Bridge` against a real
+`vision_processor` binary and a real camera) has been manually verified once,
+end to end: the Go host published a field template, `vision_processor`
+calibrated against a real skewed webcam view, and the calibration came back
+and was absorbed with no wire-format surprises between C++ and Go protobuf.
+Not automated -- there is no CI hardware to run it on.
+
+## Not yet built
+
+- **`internal/discovery`** -- parsing `SSL_VPConfig` announces off multicast
+ into an instance table. The C++ side does not emit these yet.
+- **`internal/config`** -- the host-owned config store and the diff-based
+ reprovision loop (push desired config to an instance when its announced
+ config doesn't match, rather than trying to detect death). Blocked on
+ discovery above and on a C++-side HTTP config-apply endpoint (another
+ contributor's work, not started).
+- **Bootstrap identity.** `SSL_VPConfig.instance` is `required`, but the plan
+ drops VP-local config files entirely. Nothing yet decides what a freshly
+ started, unconfigured VP calls itself before it has ever been provisioned.
+- **Announce contents/cadence** -- whether the announce echoes the VP's full
+ current `SSL_VPConfig` (needed for diff-based reprovision to work at all) or
+ just identity, and how often.
+- **The imagery/video path for remote instances.** `internal/snapshot`'s
+ local-filesystem assumption is a known, explicitly accepted limitation, not
+ a solution. `src/rtpstreamer.cpp` already emits H.264 RTP with
+ per-instance `stream_ip`/`stream_port`; bridging that to WebRTC/WHEP in Go is
+ the likely direction but is undecided and unbuilt.
diff --git a/gui/Makefile b/gui/Makefile
index 2546dff..bbbdab8 100644
--- a/gui/Makefile
+++ b/gui/Makefile
@@ -15,8 +15,13 @@ all: install
# Sentinel file, so npm reruns only when a frontend source is newer than the
# last build. //go:embed resolves at compile time, which is why every Go target
# below depends on this.
+#
+# `npm run build` empties dist/ first (Vite's emptyOutDir), which deletes
+# dist/.gitkeep along with any stale output. Restore it every time, or a build
+# run before a commit silently drops the tracked sentinel a fresh clone needs.
.frontend: $(FRONTEND_SOURCES)
cd frontend && npm ci && npm run build
+ touch frontend/dist/.gitkeep
touch .frontend
frontend: .frontend
diff --git a/gui/cmd/ssl-vision-processor-gui/main.go b/gui/cmd/ssl-vision-processor-gui/main.go
index 0b88ba5..037c959 100644
--- a/gui/cmd/ssl-vision-processor-gui/main.go
+++ b/gui/cmd/ssl-vision-processor-gui/main.go
@@ -4,24 +4,45 @@ import (
"context"
"errors"
"flag"
+ "fmt"
"log/slog"
"net/http"
"os"
"os/signal"
"strings"
+ "sync"
"syscall"
"time"
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/geometry"
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/hub"
"github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/logging"
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/multicast"
+ "google.golang.org/protobuf/encoding/protojson"
)
var address = flag.String("address", ":8085", "The address on which the vision processor GUI and API are served, default: :8085")
var visionAddress = flag.String("visionAddress", "224.5.23.2:10006", "The multicast address of field vision, default: 224.5.23.2:10006")
var skipInterfaces = flag.String("skipInterfaces", "", "Comma separated list of interface names to ignore when receiving multicast packets")
+
+// geometry-divA.yml/geometry-divB.yml are read-only rulebook presets (see
+// geometry.ReadOnlyFiles) -- the default here must never be one of them, or
+// the first Save in the Virtual Field editor would silently overwrite a
+// tracked competition preset instead of a working copy.
+var geometryFile = flag.String("geometryFile", "geometry.yml", "Field geometry config file, default: geometry.yml")
+var geometryPreset = flag.String("geometryPreset", "geometry-divB.yml", "Preset to seed -geometryFile from if it doesn't exist yet, default: geometry-divB.yml")
+var imgDir = flag.String("imgDir", "img", "Directory the vision processor writes debug snapshot images to, default: img")
var logLevelFlag = flag.String("logLevel", "Info", "Log Level: Debug, Info, Warn, Error. Default: Info")
var logFile = flag.String("logFile", "logs/vision-processor-gui.log", "Rotating log file to write alongside stderr, empty to disable. Default: logs/vision-processor-gui.log")
func main() {
+ // Deferred cleanup (closeLog) must run even on a fatal startup error, which
+ // os.Exit would skip -- so main just reports run's exit code instead of
+ // exiting directly.
+ os.Exit(run())
+}
+
+func run() int {
flag.Parse()
// Parsed before Setup so that the level is known when the handler is built,
@@ -45,13 +66,39 @@ func main() {
slog.Info("Init VP GUI")
+ if err := bootstrapGeometryFile(*geometryFile, *geometryPreset); err != nil {
+ slog.Error("bootstrapping geometry file", "err", err)
+
+ return 1
+ }
+
+ geom, err := geometry.New(*geometryFile)
+ if err != nil {
+ slog.Error("loading geometry", "err", err)
+
+ return 1
+ }
+
// register Ctrl+C handler
ctx, stopSignals := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stopSignals()
+ bridge := multicast.New(*visionAddress, splitInterfaces(*skipInterfaces), level == slog.LevelDebug)
+ wsHub := hub.New()
+
+ var wg sync.WaitGroup
+
+ runBackground(&wg, "multicast bridge", func() error { return bridge.Run(ctx, geom.Absorb) })
+ runBackground(&wg, "geometry publish loop", func() error {
+ return geom.Run(ctx, func(encoded []byte) {
+ bridge.Send(encoded)
+ publishGeometryToHub(wsHub, geom)
+ })
+ })
+
srv := &http.Server{
- Addr: *address,
- Handler: NewVisionServer(),
+ Addr: *address,
+ Handler: NewVisionServer(geom, wsHub, *imgDir),
ReadHeaderTimeout: 10 * time.Second,
}
@@ -76,8 +123,6 @@ func main() {
slog.Info("initiating graceful shutdown")
- // Cleanup of the HTTP server, receivers and bus clients goes here, bounded
- // by its own context so a wedged component cannot hang the process:
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
@@ -85,7 +130,79 @@ func main() {
slog.Error("http server failed to close gracefully", "err", err)
}
+ wg.Wait()
+
slog.Info("shutdown complete")
+
+ return 0
+}
+
+// bootstrapGeometryFile seeds path with a copy of preset if path doesn't
+// exist yet, so a fresh checkout with no working geometry.yml starts from a
+// real, complete config instead of failing at startup. A plain byte copy,
+// not a YAML round trip, so the preset's own comments survive into the new
+// working file. Never touches path if it already exists.
+func bootstrapGeometryFile(path, preset string) error {
+ if _, err := os.Stat(path); err == nil {
+ return nil // already exists, nothing to do
+ } else if !os.IsNotExist(err) {
+ return err
+ }
+
+ data, err := os.ReadFile(preset)
+ if err != nil {
+ return fmt.Errorf("read preset %s: %w", preset, err)
+ }
+
+ if err := os.WriteFile(path, data, 0o644); err != nil {
+ return fmt.Errorf("write %s: %w", path, err)
+ }
+
+ slog.Info("seeded a fresh geometry file from preset", "path", path, "preset", preset)
+
+ return nil
+}
+
+// wrapperPacketTopic is the hub topic name the frontend already subscribes to
+// (see gui/frontend/src/App.svelte).
+const wrapperPacketTopic = "wrapper_packet.out"
+
+// publishGeometryToHub re-encodes the current geometry as protojson and
+// publishes it to the browser-facing hub. Called once per publish tick
+// alongside the raw-bytes multicast send, so both destinations stay in sync.
+func publishGeometryToHub(wsHub *hub.Hub, geom *geometry.Geometry) {
+ data, err := protojson.Marshal(geom.Snapshot())
+ if err != nil {
+ slog.Error("marshalling geometry for websocket", "err", err)
+
+ return
+ }
+
+ wsHub.Publish(wrapperPacketTopic, data)
+}
+
+// runBackground runs task in its own goroutine tracked by wg, logging its
+// error unless it is the expected result of ctx being cancelled.
+func runBackground(wg *sync.WaitGroup, name string, task func() error) {
+ wg.Add(1)
+
+ go func() {
+ defer wg.Done()
+
+ if err := task(); err != nil && !errors.Is(err, context.Canceled) {
+ slog.Error(name+" stopped", "err", err)
+ }
+ }()
+}
+
+// splitInterfaces turns the comma separated flag value into a slice, or nil
+// when the flag is unset -- an unset flag must not become []string{""}.
+func splitInterfaces(flagValue string) []string {
+ if flagValue == "" {
+ return nil
+ }
+
+ return strings.Split(flagValue, ",")
}
func formattedAddress() string {
diff --git a/gui/cmd/ssl-vision-processor-gui/main_test.go b/gui/cmd/ssl-vision-processor-gui/main_test.go
new file mode 100644
index 0000000..9083bb1
--- /dev/null
+++ b/gui/cmd/ssl-vision-processor-gui/main_test.go
@@ -0,0 +1,52 @@
+package main
+
+import (
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+func TestBootstrapGeometryFileSeedsFromPreset(t *testing.T) {
+ dir := t.TempDir()
+ path := filepath.Join(dir, "geometry.yml")
+
+ if err := bootstrapGeometryFile(path, "testdata/geometry.yml"); err != nil {
+ t.Fatalf("bootstrapGeometryFile: %v", err)
+ }
+
+ got, err := os.ReadFile(path)
+ if err != nil {
+ t.Fatalf("ReadFile: %v", err)
+ }
+
+ want, err := os.ReadFile("testdata/geometry.yml")
+ if err != nil {
+ t.Fatalf("ReadFile preset: %v", err)
+ }
+
+ if string(got) != string(want) {
+ t.Error("bootstrapped file does not match the preset byte-for-byte")
+ }
+}
+
+func TestBootstrapGeometryFileLeavesExistingFileAlone(t *testing.T) {
+ dir := t.TempDir()
+ path := filepath.Join(dir, "geometry.yml")
+
+ if err := os.WriteFile(path, []byte("already here"), 0o644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+
+ if err := bootstrapGeometryFile(path, "testdata/geometry.yml"); err != nil {
+ t.Fatalf("bootstrapGeometryFile: %v", err)
+ }
+
+ got, err := os.ReadFile(path)
+ if err != nil {
+ t.Fatalf("ReadFile: %v", err)
+ }
+
+ if string(got) != "already here" {
+ t.Errorf("existing file was overwritten: %q", got)
+ }
+}
diff --git a/gui/cmd/ssl-vision-processor-gui/routes.go b/gui/cmd/ssl-vision-processor-gui/routes.go
index a393c6e..b7472ea 100644
--- a/gui/cmd/ssl-vision-processor-gui/routes.go
+++ b/gui/cmd/ssl-vision-processor-gui/routes.go
@@ -4,11 +4,21 @@ import (
"net/http"
"github.com/RoboCup-SSL/ssl-vision-processor/gui/frontend"
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/hub"
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/snapshot"
)
func (s *VisionServer) addRoutes(mux *http.ServeMux) {
mux.Handle("GET /api/health", s.handleHealth())
+ mux.Handle("GET /api/geometry", s.handleGetGeometry())
+ mux.Handle("GET /api/geometry/field", s.handleGetFieldConfig())
+ mux.Handle("PUT /api/geometry/field", s.handlePutFieldConfig())
+ mux.Handle("GET /api/geometry/presets", s.handleGetFieldPresets())
+ mux.Handle("GET /api/snapshots", snapshot.HandleList(s.imgDir))
+ mux.Handle("GET /api/snapshot/{camID}/{view}", snapshot.HandleGet(s.imgDir))
mux.Handle("/api/", http.NotFoundHandler())
-
+
+ mux.Handle("/ws", hub.HandleWebSocket(s.hub))
+
mux.Handle("/", frontend.HandleFrontend())
-}
\ No newline at end of file
+}
diff --git a/gui/cmd/ssl-vision-processor-gui/server.go b/gui/cmd/ssl-vision-processor-gui/server.go
index c6e88cb..2ad9297 100644
--- a/gui/cmd/ssl-vision-processor-gui/server.go
+++ b/gui/cmd/ssl-vision-processor-gui/server.go
@@ -2,16 +2,23 @@ package main
import (
"encoding/json"
+ "errors"
"log/slog"
"net/http"
+
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/geometry"
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/hub"
+ "google.golang.org/protobuf/encoding/protojson"
)
type VisionServer struct {
-
+ geometry *geometry.Geometry
+ hub *hub.Hub
+ imgDir string
}
-func NewVisionServer() http.Handler {
- s := &VisionServer{}
+func NewVisionServer(geom *geometry.Geometry, wsHub *hub.Hub, imgDir string) http.Handler {
+ s := &VisionServer{geometry: geom, hub: wsHub, imgDir: imgDir}
mux := http.NewServeMux()
s.addRoutes(mux)
@@ -27,4 +34,122 @@ func (s *VisionServer) handleHealth() http.HandlerFunc {
slog.Error("writing health response", "err", err)
}
}
-}
\ No newline at end of file
+}
+
+// handleGetGeometry serves the current wrapper packet as canonical protojson,
+// matching the wire encoding the rest of the league already expects.
+func (s *VisionServer) handleGetGeometry() http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ data, err := protojson.Marshal(s.geometry.Snapshot())
+ if err != nil {
+ slog.Error("marshalling geometry", "err", err)
+ http.Error(w, "internal error", http.StatusInternalServerError)
+
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+
+ if _, err := w.Write(data); err != nil {
+ slog.Error("writing geometry response", "err", err)
+ }
+ }
+}
+
+// fieldConfigResponse is the "virtual field" shape: just the editable
+// dimensions and optional-line toggles, not the full wrapper packet (calib,
+// source, generated field_lines/arcs) that handleGetGeometry serves.
+type fieldConfigResponse struct {
+ Field geometry.FieldConfig `json:"field"`
+ OptionalFieldLines geometry.OptionalLinesConfig `json:"optionalFieldLines"`
+}
+
+func (s *VisionServer) handleGetFieldConfig() http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ field, optional := s.geometry.FieldConfig()
+
+ w.Header().Set("Content-Type", "application/json")
+
+ if err := json.NewEncoder(w).Encode(fieldConfigResponse{Field: field, OptionalFieldLines: optional}); err != nil {
+ slog.Error("writing field config response", "err", err)
+ }
+ }
+}
+
+// handlePutFieldConfig edits the virtual field: dimensions and which optional
+// markings exist. Regenerates the derived field lines/arcs and persists to
+// geometry.yml -- see geometry.Geometry.UpdateField.
+func (s *VisionServer) handlePutFieldConfig() http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ var req fieldConfigResponse
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+ http.Error(w, "malformed request body: "+err.Error(), http.StatusBadRequest)
+
+ return
+ }
+
+ if err := s.geometry.UpdateField(req.Field, req.OptionalFieldLines); err != nil {
+ var validation *geometry.ValidationError
+ var readOnly *geometry.ReadOnlyError
+
+ switch {
+ case errors.As(err, &validation), errors.As(err, &readOnly):
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ default:
+ slog.Error("updating field config", "err", err)
+ http.Error(w, "internal error", http.StatusInternalServerError)
+ }
+
+ return
+ }
+
+ w.WriteHeader(http.StatusNoContent)
+ }
+}
+
+// fieldPresets are the rulebook defaults, read live from the same files a
+// human would open (geometry-divA.yml, geometry-divB.yml at the repo root) --
+// not a copy that could drift from them. See geometry.ReadOnlyFiles: saves
+// through handlePutFieldConfig refuse to touch these paths.
+var fieldPresets = []struct {
+ Name string
+ Path string
+}{
+ {Name: "Division A", Path: "geometry-divA.yml"},
+ {Name: "Division B", Path: "geometry-divB.yml"},
+}
+
+type fieldPresetResponse struct {
+ Name string `json:"name"`
+ fieldConfigResponse
+}
+
+// handleGetFieldPresets serves the rulebook presets for the "start from a
+// preset" feature. A preset file that can't be read (wrong working
+// directory, for one) is skipped with a warning rather than failing the
+// whole request -- the other preset(s) are still useful.
+func (s *VisionServer) handleGetFieldPresets() http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ presets := make([]fieldPresetResponse, 0, len(fieldPresets))
+
+ for _, p := range fieldPresets {
+ field, optional, err := geometry.LoadPreset(p.Path)
+ if err != nil {
+ slog.Warn("skipping unreadable field preset", "name", p.Name, "path", p.Path, "err", err)
+
+ continue
+ }
+
+ presets = append(presets, fieldPresetResponse{
+ Name: p.Name,
+ fieldConfigResponse: fieldConfigResponse{Field: field, OptionalFieldLines: optional},
+ })
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+
+ if err := json.NewEncoder(w).Encode(presets); err != nil {
+ slog.Error("writing field presets response", "err", err)
+ }
+ }
+}
diff --git a/gui/cmd/ssl-vision-processor-gui/server_test.go b/gui/cmd/ssl-vision-processor-gui/server_test.go
index 1a970c1..915e812 100644
--- a/gui/cmd/ssl-vision-processor-gui/server_test.go
+++ b/gui/cmd/ssl-vision-processor-gui/server_test.go
@@ -3,15 +3,45 @@ package main
import (
"net/http"
"net/http/httptest"
+ "os"
+ "path/filepath"
"strings"
"testing"
+
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/geometry"
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/hub"
)
+// testServer loads a *copy* of the fixture, never testdata/geometry.yml
+// directly -- the /api/geometry/field PUT handler writes back to whatever
+// path Geometry was loaded from, and would otherwise rewrite a tracked file
+// on every test run.
+func testServer(t *testing.T) http.Handler {
+ t.Helper()
+
+ src, err := os.ReadFile("testdata/geometry.yml")
+ if err != nil {
+ t.Fatalf("ReadFile fixture: %v", err)
+ }
+
+ path := filepath.Join(t.TempDir(), "geometry.yml")
+ if err := os.WriteFile(path, src, 0o644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+
+ geom, err := geometry.New(path)
+ if err != nil {
+ t.Fatalf("geometry.New: %v", err)
+ }
+
+ return NewVisionServer(geom, hub.New(), t.TempDir())
+}
+
func TestHealthReturnsOK(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/api/health", nil)
rec := httptest.NewRecorder()
- NewVisionServer().ServeHTTP(rec, req)
+ testServer(t).ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
@@ -27,6 +57,111 @@ func TestHealthReturnsOK(t *testing.T) {
}
}
+func TestGeometryReturnsProtojson(t *testing.T) {
+ req := httptest.NewRequest(http.MethodGet, "/api/geometry", nil)
+ rec := httptest.NewRecorder()
+
+ testServer(t).ServeHTTP(rec, req)
+
+ if rec.Code != http.StatusOK {
+ t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
+ }
+
+ if got := rec.Header().Get("Content-Type"); got != "application/json" {
+ t.Errorf("Content-Type = %q, want application/json", got)
+ }
+
+ if !strings.Contains(rec.Body.String(), `"fieldLength"`) {
+ t.Errorf("body = %q, want it to contain fieldLength", rec.Body.String())
+ }
+}
+
+func TestGetFieldConfigReturnsCurrentValues(t *testing.T) {
+ req := httptest.NewRequest(http.MethodGet, "/api/geometry/field", nil)
+ rec := httptest.NewRecorder()
+
+ testServer(t).ServeHTTP(rec, req)
+
+ if rec.Code != http.StatusOK {
+ t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
+ }
+
+ if !strings.Contains(rec.Body.String(), `"fieldLength"`) || !strings.Contains(rec.Body.String(), `"optionalFieldLines"`) {
+ t.Errorf("body = %q, want fieldLength and optionalFieldLines", rec.Body.String())
+ }
+}
+
+func TestPutFieldConfigUpdatesAndPersists(t *testing.T) {
+ srv := testServer(t)
+
+ body := strings.NewReader(`{
+ "field": {"fieldLength": 2160, "fieldWidth": 1680, "goalWidth": 280, "goalDepth": 50, "boundaryWidth": 100, "lineThickness": 10},
+ "optionalFieldLines": {"halfway": true, "penalty": true}
+ }`)
+
+ putReq := httptest.NewRequest(http.MethodPut, "/api/geometry/field", body)
+ putRec := httptest.NewRecorder()
+ srv.ServeHTTP(putRec, putReq)
+
+ if putRec.Code != http.StatusNoContent {
+ t.Fatalf("PUT status = %d, want %d, body: %s", putRec.Code, http.StatusNoContent, putRec.Body.String())
+ }
+
+ getReq := httptest.NewRequest(http.MethodGet, "/api/geometry/field", nil)
+ getRec := httptest.NewRecorder()
+ srv.ServeHTTP(getRec, getReq)
+
+ if !strings.Contains(getRec.Body.String(), `"fieldLength":2160`) {
+ t.Errorf("after PUT, GET returned %q, want it to reflect the update", getRec.Body.String())
+ }
+}
+
+// A zero/negative dimension is the caller's mistake -- 400, not a 500, and
+// must not silently write anything to disk.
+func TestPutFieldConfigRejectsInvalidDimensions(t *testing.T) {
+ srv := testServer(t)
+
+ body := strings.NewReader(`{"field": {"fieldLength": 0}, "optionalFieldLines": {}}`)
+ req := httptest.NewRequest(http.MethodPut, "/api/geometry/field", body)
+ rec := httptest.NewRecorder()
+
+ srv.ServeHTTP(rec, req)
+
+ if rec.Code != http.StatusBadRequest {
+ t.Errorf("status = %d, want %d", rec.Code, http.StatusBadRequest)
+ }
+}
+
+func TestPutFieldConfigRejectsMalformedJSON(t *testing.T) {
+ req := httptest.NewRequest(http.MethodPut, "/api/geometry/field", strings.NewReader(`not json`))
+ rec := httptest.NewRecorder()
+
+ testServer(t).ServeHTTP(rec, req)
+
+ if rec.Code != http.StatusBadRequest {
+ t.Errorf("status = %d, want %d", rec.Code, http.StatusBadRequest)
+ }
+}
+
+// The preset endpoint reads the real repo-root files -- this test runs from
+// cmd/ssl-vision-processor-gui, so it doesn't see them and both are skipped.
+// It's still worth asserting the endpoint degrades to an empty list rather
+// than failing outright when a preset can't be read.
+func TestGetFieldPresetsDegradesGracefullyWhenFilesAreMissing(t *testing.T) {
+ req := httptest.NewRequest(http.MethodGet, "/api/geometry/presets", nil)
+ rec := httptest.NewRecorder()
+
+ testServer(t).ServeHTTP(rec, req)
+
+ if rec.Code != http.StatusOK {
+ t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
+ }
+
+ if strings.TrimSpace(rec.Body.String()) != "[]" {
+ t.Errorf("body = %q, want an empty array (no presets reachable from this cwd)", rec.Body.String())
+ }
+}
+
// A wrong method is a 404 rather than a 405: the "/" catch-all matches every
// method, so ServeMux never reaches its method-not-allowed path. What matters is
// that the "/api/" subtree answers, instead of the request falling through to
@@ -36,7 +171,7 @@ func TestHealthRejectsNonGET(t *testing.T) {
req := httptest.NewRequest(method, "/api/health", nil)
rec := httptest.NewRecorder()
- NewVisionServer().ServeHTTP(rec, req)
+ testServer(t).ServeHTTP(rec, req)
if rec.Code != http.StatusNotFound {
t.Errorf("%s /api/health = %d, want %d", method, rec.Code, http.StatusNotFound)
@@ -51,7 +186,7 @@ func TestUnknownAPIPathReturns404(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/api/does-not-exist", nil)
rec := httptest.NewRecorder()
- NewVisionServer().ServeHTTP(rec, req)
+ testServer(t).ServeHTTP(rec, req)
if rec.Code != http.StatusNotFound {
t.Errorf("status = %d, want %d", rec.Code, http.StatusNotFound)
@@ -68,7 +203,7 @@ func TestUnknownPathServesApp(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/instances/cam0/calibration", nil)
rec := httptest.NewRecorder()
- NewVisionServer().ServeHTTP(rec, req)
+ testServer(t).ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Errorf("status = %d, want %d", rec.Code, http.StatusOK)
diff --git a/gui/cmd/ssl-vision-processor-gui/testdata/geometry.yml b/gui/cmd/ssl-vision-processor-gui/testdata/geometry.yml
new file mode 100644
index 0000000..850c64a
--- /dev/null
+++ b/gui/cmd/ssl-vision-processor-gui/testdata/geometry.yml
@@ -0,0 +1,23 @@
+# Minimal fixture for geometry package tests. Not a real match config.
+optional_field_lines:
+ goal2goal: true
+ halfway: true
+ centercircle: true
+ penalty: true
+
+field:
+ field_length: 9000
+ field_width: 6000
+ goal_width: 1000
+ goal_depth: 180
+ goal_height: 160
+ penalty_area_depth: 1000
+ penalty_area_width: 2000
+ goal_center_to_penalty_mark: 6000
+ boundary_width: 300
+ boundary_width_goal_line: 300
+ center_circle_radius: 500
+ line_thickness: 10
+ ball_radius: 21.5
+ max_robot_radius: 90.0
+ goal_substitution_area_width: 0
diff --git a/gui/frontend/README.md b/gui/frontend/README.md
index 24efacf..40ca3ef 100644
--- a/gui/frontend/README.md
+++ b/gui/frontend/README.md
@@ -1,30 +1,31 @@
# vision-processor-gui-frontend
-Browser UI for the vision-processor wrapper. Svelte 5 + TypeScript + Vite.
+Browser UI for the vision-processor GUI. Svelte 5 + TypeScript + Vite.
-Currently a skeleton: connects to `wrapper_backend`'s WebSocket at
-`ws://:8765/ws`, asks the backend (via `GET /snapshots`) which
-debug images currently exist on disk, and renders an ` ` for each
-one, refreshed once per second. A separate dev panel lets you subscribe
-to `wrapper_packet.out` and see the raw JSON.
+Currently a skeleton: connects to a WebSocket at `/ws` and asks the
+backend (via `GET /api/snapshots`) which debug images currently exist
+on disk (only meaningful when the browser and the vision processor
+share a filesystem -- see the root [README.md](../../README.md)).
## Run
-Two terminals from the repo root:
+Two options:
```
-# terminal 1 (the wrapper backend, with its WebSocket on :8765)
-./start_wrapper.sh
-
-# terminal 2 (the Vite dev server, on :5173 with HMR)
+# Standalone dev server with HMR (proxies /api and /ws to the Go host on :8085)
cd gui/frontend
npm install
npm run dev
```
-Open . Whatever debug images the C++ side has
-written to `img/` will appear in the grid; click "Subscribe to
-wrapper_packet.out" to also see the raw JSON frames.
+```
+# Through the Go host itself, on its own port, no proxy involved
+cd gui
+make run
+```
+
+Either way the Go host in `gui/` must be running for the connection
+badge and snapshot grid to show anything.
## Architecture
@@ -34,13 +35,13 @@ wrapper_packet.out" to also see the raw JSON frames.
reader, unsubscribes when the last reader goes away. Reconnects on
close with exponential backoff (1s → 30s).
- `src/App.svelte` — placeholder UI: connection badge + a grid of
- ` ` tags, one per entry returned by `GET /snapshots`. The list is
+ ` ` tags, one per entry returned by `GET /api/snapshots`. The list is
refreshed every 5 s; each ` ` is refreshed once per second via a
cache-busting `?t=` query. Plus a dev panel with a subscribe
toggle + JSON dump for `wrapper_packet.out`.
- `src/main.ts` — mounts `App` into `#app`.
-The WS wire format mirrors `wrapper_backend/websocket.py`'s envelope:
+The WS wire format (`gui/internal/hub`):
```jsonc
// client -> server
@@ -48,14 +49,15 @@ The WS wire format mirrors `wrapper_backend/websocket.py`'s envelope:
{ "action": "unsubscribe", "topic": "wrapper_packet.out" }
// server -> client
{ "topic": "wrapper_packet.out", "data": { ... } }
-{ "error": "unknown topic", "topic": "..." }
```
-Snapshot endpoints are plain HTTP: `GET /snapshots` returns the list of
-available `{cam_id, view}` entries as JSON; `GET /snapshot//`
-returns the actual `image/jpeg` or `image/png` (or 404 if missing).
-` ` tags don't trigger CORS for display, so cross-origin `:5173` ->
-`:8765` works in dev without a Vite proxy.
+`wrapper_packet.out` carries the current `SSL_WrapperPacket` as
+canonical protojson, republished once per second.
+
+Snapshot endpoints are plain HTTP: `GET /api/snapshots` returns the
+list of available `{cam_id, view}` entries as JSON;
+`GET /api/snapshot//` returns the actual `image/jpeg` or
+`image/png` (or 404 if missing).
## Scripts
@@ -69,15 +71,14 @@ npm run format # prettier --write .
npm run format:check # prettier --check . (CI-style)
```
-`npm run check` is the rough analogue of `mypy` on the Python side.
-`npm run lint` + `npm run format` together cover what `ruff` does for
-Python. TypeScript is configured strict (`strict`,
+TypeScript is configured strict (`strict`,
`noUncheckedIndexedAccess`, `noImplicitOverride`,
`noPropertyAccessFromIndexSignature`, `noImplicitReturns`,
`noFallthroughCasesInSwitch`).
## Production serving
-Currently not wired. `npm run build` produces `dist/`; the wrapper
-backend does not yet serve it. For now run `npm run dev` (or
-`npm run preview`) on a separate port.
+`npm run build` produces `dist/`, which the Go host in `gui/` embeds
+directly into its binary (`gui/frontend/embed.go`) and serves on its
+own port, with a fallback to `index.html` for client-side routes. See
+`make run` in the root [README.md](../../README.md).
diff --git a/gui/frontend/dist/.gitkeep b/gui/frontend/dist/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/gui/frontend/embed.go b/gui/frontend/embed.go
index 612e39c..61e9f67 100644
--- a/gui/frontend/embed.go
+++ b/gui/frontend/embed.go
@@ -37,4 +37,4 @@ func serveSPA(dist fs.FS, files http.Handler) http.HandlerFunc {
files.ServeHTTP(w, r)
}
-}
\ No newline at end of file
+}
diff --git a/gui/frontend/eslint.config.js b/gui/frontend/eslint.config.js
index 3b66399..22fe9ed 100644
--- a/gui/frontend/eslint.config.js
+++ b/gui/frontend/eslint.config.js
@@ -31,6 +31,18 @@ export default ts.config(
parserOptions: { parser: ts.parser },
},
},
+ {
+ // eslint-plugin-svelte's own base config matches *.svelte.ts/*.svelte.js
+ // (the Svelte 5 "runes module" convention) and hands them to
+ // svelte-eslint-parser, but without delegating to the TS parser the way
+ // it does for *.svelte files above -- so a plain `import type { X }`
+ // fails to parse. Same fix as the .svelte override, for the same reason.
+ files: ["**/*.svelte.ts", "**/*.svelte.js"],
+ languageOptions: {
+ parser: svelteParser,
+ parserOptions: { parser: ts.parser },
+ },
+ },
{
ignores: [
"dist/",
diff --git a/gui/frontend/src/App.svelte b/gui/frontend/src/App.svelte
index 3b305e1..c4844f5 100644
--- a/gui/frontend/src/App.svelte
+++ b/gui/frontend/src/App.svelte
@@ -1,11 +1,12 @@
-
-
- vision-processor wrapper
-
- {$connectionState}
-
-
-
-
- Snapshots
- {#if snapshots.length === 0}
- No images in img/ yet.
- {:else}
-
- {#each snapshots as snap (`${snap.cam_id}.${snap.view}`)}
-
-
- cam {snap.cam_id} / {snap.view}
-
- {/each}
-
- {/if}
-
-
-
-
- {subscribed ? "Unsubscribe" : "Subscribe to wrapper_packet.out"}
-
-
- {#if subscribed}
- {#if $wrapperPacket}
- {JSON.stringify($wrapperPacket, null, 2)}
+
+ {#snippet below()}
+
+
+ Temporary debug utilities -- see the note in this file's source.
+
+
+
+ Snapshots
+ {#if snapshots.length === 0}
+ No images in img/ yet.
{:else}
- Waiting for first frame…
+
+ {#each snapshots as snap (`${snap.cam_id}.${snap.view}`)}
+
+
+ cam {snap.cam_id} / {snap.view}
+
+ {/each}
+
{/if}
- {/if}
-
-
- wrapper-frontend dev skeleton
-
+
+
+
+
+ {subscribed ? "Unsubscribe" : "Subscribe to wrapper_packet.out"}
+
+
+ {#if subscribed}
+ {#if $wrapperPacket}
+ {JSON.stringify($wrapperPacket, null, 2)}
+ {:else}
+ Waiting for first frame…
+ {/if}
+ {/if}
+
+ {/snippet}
+
diff --git a/gui/frontend/src/lib/CornerPicker.svelte b/gui/frontend/src/lib/CornerPicker.svelte
new file mode 100644
index 0000000..7c48fb9
--- /dev/null
+++ b/gui/frontend/src/lib/CornerPicker.svelte
@@ -0,0 +1,249 @@
+
+
+
+ Corner picker (hacky, cam 0 only)
+
+ Drag the four markers onto the real field corners in the image below, then
+ click the number on whichever one sits where the goal line meets the
+ touchline nearest this field's (0,0) corner -- that one turns green and
+ becomes first in the output. The other three can be in any order; the
+ calibration algorithm works that out itself. No camera selector yet.
+
+
+ Refresh frame
+
+
+
{
+ handleImageLoad(e.currentTarget as HTMLImageElement);
+ }}
+ />
+
+ {#if imageWidth > 0}
+
+ {#each corners as corner, index (index)}
+ {
+ startDrag(index, e);
+ }}
+ />
+ {
+ originIndex = index;
+ }}
+ onkeydown={(e) => {
+ if (e.key === "Enter" || e.key === " ") originIndex = index;
+ }}
+ >
+ {index + 1}
+
+ {/each}
+ {#if corners.length === 4}
+ `${String(c.x)},${String(c.y)}`)
+ .join(" ")}
+ />
+ {/if}
+
+ {/if}
+
+
+ {yamlSnippet}
+
+
+
diff --git a/gui/frontend/src/lib/FieldEditor.svelte b/gui/frontend/src/lib/FieldEditor.svelte
new file mode 100644
index 0000000..61a7a81
--- /dev/null
+++ b/gui/frontend/src/lib/FieldEditor.svelte
@@ -0,0 +1,385 @@
+
+
+
+ Virtual field
+
+ Measured dimensions, in mm. Saving regenerates the field markings below and
+ writes them back to geometry.yml.
+
+
+ {#if virtualField.error}
+ Error: {virtualField.error}
+ {/if}
+
+
+
+
+
+
+
+ Markings reflect the last saved dimensions; the highlighted region
+ updates live as you change camera count/id above.
+
+
+
+
+
+
diff --git a/gui/frontend/src/lib/FieldSketch.svelte b/gui/frontend/src/lib/FieldSketch.svelte
new file mode 100644
index 0000000..966d17d
--- /dev/null
+++ b/gui/frontend/src/lib/FieldSketch.svelte
@@ -0,0 +1,131 @@
+
+
+
+ {#if slice}
+
+ {/if}
+
+ {#each lines as line (line.name)}
+
+ {/each}
+
+ {#each arcs as arc (arc.name)}
+
+ {/each}
+
+
+
diff --git a/gui/frontend/src/lib/config/ConfigCategoryPlaceholder.svelte b/gui/frontend/src/lib/config/ConfigCategoryPlaceholder.svelte
new file mode 100644
index 0000000..38de4ed
--- /dev/null
+++ b/gui/frontend/src/lib/config/ConfigCategoryPlaceholder.svelte
@@ -0,0 +1,94 @@
+
+
+
+ {category.label}
+
+ {#if instance}
+
+ Editing {instance.host} / cam {instance.cameraId}'s
+ {category.yamlKey}:
+ block. Not wired to a backend yet -- there is nowhere to read or write a specific
+ instance's config.yml over the network. See
+ internal/config in gui/CLAUDE.md's "Not yet built".
+
+ {:else}
+ Select a vision processor on the left first.
+ {/if}
+
+
+ Contributing this panel? Replace this file with a real form for the fields
+ below (see config.yml at the repo root for exact defaults/ranges).
+
+
+
+ {#each category.fields as field (field.name)}
+
+
{field.name}
+ {field.comment}
+
+ {/each}
+
+
+
+
diff --git a/gui/frontend/src/lib/config/GeometryPanel.svelte b/gui/frontend/src/lib/config/GeometryPanel.svelte
new file mode 100644
index 0000000..9646c19
--- /dev/null
+++ b/gui/frontend/src/lib/config/GeometryPanel.svelte
@@ -0,0 +1,82 @@
+
+
+
+ Geometry
+
+ {#if instance}
+
+ {instance.host} / cam {instance.cameraId}. The numeric settings below
+ (config.yml's geometry: block) aren't wired to a backend yet; the
+ corner picker further down already is (writes to whichever config.yml you tell
+ it to, by hand -- see its own hint text).
+
+ {:else}
+ Select a vision processor on the left first.
+ {/if}
+
+
+ {#each category.fields as field (field.name)}
+
+
{field.name}
+ {field.comment}
+
+ {/each}
+
+
+
+
+
+
diff --git a/gui/frontend/src/lib/fieldPresets.ts b/gui/frontend/src/lib/fieldPresets.ts
new file mode 100644
index 0000000..4fc8e66
--- /dev/null
+++ b/gui/frontend/src/lib/fieldPresets.ts
@@ -0,0 +1,62 @@
+// Rulebook preset math: scaling a preset by a percentage. The presets
+// themselves are read live from /api/geometry/presets (see
+// loadFieldPresets in geometry.svelte.ts) -- straight from the same
+// geometry-divA.yml/geometry-divB.yml a human would open, rather than a copy
+// kept here that could drift from them.
+import type { FieldConfig, FieldPreset } from "./geometry.svelte";
+
+export type { FieldPreset };
+
+// Fields it makes sense to shrink along with the field itself. ballRadius and
+// maxRobotRadius are deliberately excluded by default -- they describe real
+// hardware, which is usually not scaled down just because the field is.
+export const SCALABLE_KEYS: (keyof FieldConfig)[] = [
+ "fieldLength",
+ "fieldWidth",
+ "goalWidth",
+ "goalDepth",
+ "goalHeight",
+ "penaltyAreaDepth",
+ "penaltyAreaWidth",
+ "goalCenterToPenaltyMark",
+ "boundaryWidth",
+ "boundaryWidthGoalLine",
+ "centerCircleRadius",
+ "lineThickness",
+];
+
+export const HARDWARE_KEYS: (keyof FieldConfig)[] = [
+ "ballRadius",
+ "maxRobotRadius",
+];
+
+// Applies a preset at the given percentage scale (100 = actual rule-book
+// size) to a FieldConfig, returning a new object. scaleHardware controls
+// whether ballRadius/maxRobotRadius are scaled too, or left at the preset's
+// real-hardware value.
+export function scalePreset(
+ preset: FieldPreset,
+ scalePercent: number,
+ scaleHardware: boolean,
+): FieldConfig {
+ const factor = scalePercent / 100;
+ const result: FieldConfig = { ...preset.field };
+
+ for (const key of SCALABLE_KEYS) {
+ const value = preset.field[key];
+ if (typeof value === "number") {
+ result[key] = Math.round(value * factor);
+ }
+ }
+
+ if (scaleHardware) {
+ for (const key of HARDWARE_KEYS) {
+ const value = preset.field[key];
+ if (typeof value === "number") {
+ result[key] = Math.round(value * factor * 10) / 10;
+ }
+ }
+ }
+
+ return result;
+}
diff --git a/gui/frontend/src/lib/fieldSplit.ts b/gui/frontend/src/lib/fieldSplit.ts
new file mode 100644
index 0000000..61b0f12
--- /dev/null
+++ b/gui/frontend/src/lib/fieldSplit.ts
@@ -0,0 +1,62 @@
+// Mirrors src/CameraModel.cpp's visibleFieldExtentEstimation (the boundary-
+// free variant, matching PointGeometryFit's modelCorners in GeomModel.cpp) --
+// which portion of the field one camera in a camAmount-way split is
+// responsible for. Reimplemented here rather than fetched from the Go host
+// because it's pure geometry with no state, and the UI needs it live as the
+// user changes camera count/id, not round-tripped through an API call.
+export interface FieldSlice {
+ minX: number;
+ minY: number;
+ maxX: number;
+ maxY: number;
+}
+
+export function computeFieldSlice(
+ camId: number,
+ camAmount: number,
+ fieldLength: number,
+ fieldWidth: number,
+): FieldSlice {
+ const amount = Math.max(1, camAmount);
+
+ // Always halves whichever dimension is currently longer -- for a
+ // conventional SSL field (length > width) this means camAmount=2 splits
+ // along length first, camAmount=4 then also splits width, matching
+ // "Double camera field: -x/+x side" and "Quadruple: four quadrants" in
+ // SSL_VPConfig's own comment.
+ let sizeX = 1;
+ let sizeY = 1;
+ for (let i = amount; i > 1; i = Math.floor(i / 2)) {
+ if (fieldLength / sizeX >= fieldWidth / sizeY) {
+ sizeX *= 2;
+ } else {
+ sizeY *= 2;
+ }
+ }
+
+ let posX = 0;
+ let posY = 0;
+ for (let i = camId % amount; i > 0; i--) {
+ posY++;
+ if (posY === sizeY) {
+ posY = 0;
+ posX++;
+ }
+ }
+
+ const extentX = fieldLength / sizeX;
+ const extentY = fieldWidth / sizeY;
+ const minX = extentX * posX - fieldLength / 2;
+ const minY = extentY * posY - fieldWidth / 2;
+
+ return { minX, minY, maxX: minX + extentX, maxY: minY + extentY };
+}
+
+// Whether two axis-aligned boxes overlap at all -- used to decide if a field
+// marking is at least partially within a camera's slice, not just whether
+// it's fully contained (a marking straddling the boundary is still relevant).
+export function boxesOverlap(a: FieldSlice, b: FieldSlice): boolean {
+ return (
+ a.minX <= b.maxX && a.maxX >= b.minX && a.minY <= b.maxY && a.maxY >= b.minY
+ );
+}
diff --git a/gui/frontend/src/lib/geometry.svelte.ts b/gui/frontend/src/lib/geometry.svelte.ts
new file mode 100644
index 0000000..f3a958f
--- /dev/null
+++ b/gui/frontend/src/lib/geometry.svelte.ts
@@ -0,0 +1,152 @@
+// Shared state for the virtual field editor. A module-level $state object,
+// per the project convention (this replaces a store; see CLAUDE.md).
+import type {
+ SSL_GeometryFieldSizeJson,
+ SSL_FieldLineSegmentJson,
+ SSL_FieldCircularArcJson,
+} from "../proto/vision/ssl_vision_geometry_pb";
+
+// The editable dimensions: everything the generated field size carries except
+// fieldLines/fieldArcs, which are derived server-side and never hand-edited.
+export type FieldConfig = Omit<
+ SSL_GeometryFieldSizeJson,
+ "fieldLines" | "fieldArcs"
+>;
+
+export interface OptionalFieldLines {
+ goal2Goal: boolean;
+ halfway: boolean;
+ centerCircle: boolean;
+ penalty: boolean;
+}
+
+interface FieldConfigResponse {
+ field: FieldConfig;
+ optionalFieldLines: OptionalFieldLines;
+}
+
+// A rulebook preset, as served by GET /api/geometry/presets -- read live
+// from geometry-divA.yml/geometry-divB.yml on the Go host, not duplicated
+// here. See fieldPresets.ts for what's done with one once loaded.
+export interface FieldPreset extends FieldConfigResponse {
+ name: string;
+}
+
+// Just enough of the full /api/geometry response to render the sketch -- not
+// calib, not source, nothing else this editor doesn't need.
+interface GeometryResponse {
+ geometry?: {
+ field?: {
+ fieldLines?: SSL_FieldLineSegmentJson[];
+ fieldArcs?: SSL_FieldCircularArcJson[];
+ };
+ };
+}
+
+export const virtualField = $state<{
+ field: FieldConfig;
+ optionalFieldLines: OptionalFieldLines;
+ fieldLines: SSL_FieldLineSegmentJson[];
+ fieldArcs: SSL_FieldCircularArcJson[];
+ presets: FieldPreset[];
+ loading: boolean;
+ saving: boolean;
+ error: string | null;
+ dirty: boolean;
+}>({
+ field: {},
+ optionalFieldLines: {
+ goal2Goal: false,
+ halfway: false,
+ centerCircle: false,
+ penalty: false,
+ },
+ fieldLines: [],
+ fieldArcs: [],
+ presets: [],
+ loading: false,
+ saving: false,
+ error: null,
+ dirty: false,
+});
+
+// Presets are loaded separately from loadVirtualField: a preset endpoint that
+// can't be read (see the Go handler's graceful degradation) shouldn't stop
+// the actual field config from loading, and vice versa.
+export async function loadFieldPresets(): Promise {
+ try {
+ const response = await fetch("/api/geometry/presets");
+ if (response.ok) {
+ virtualField.presets = (await response.json()) as FieldPreset[];
+ }
+ } catch {
+ // Presets are a convenience, not required for the editor to work -- an
+ // empty list just means the preset section has nothing to offer.
+ }
+}
+
+export async function loadVirtualField(): Promise {
+ virtualField.loading = true;
+ virtualField.error = null;
+
+ try {
+ const [configRes, geometryRes] = await Promise.all([
+ fetch("/api/geometry/field"),
+ fetch("/api/geometry"),
+ ]);
+
+ if (!configRes.ok) {
+ throw new Error(`GET /api/geometry/field: ${String(configRes.status)}`);
+ }
+
+ const config = (await configRes.json()) as FieldConfigResponse;
+ virtualField.field = config.field;
+ virtualField.optionalFieldLines = config.optionalFieldLines;
+ virtualField.dirty = false;
+
+ if (geometryRes.ok) {
+ const geometry = (await geometryRes.json()) as GeometryResponse;
+ virtualField.fieldLines = geometry.geometry?.field?.fieldLines ?? [];
+ virtualField.fieldArcs = geometry.geometry?.field?.fieldArcs ?? [];
+ }
+ } catch (err) {
+ virtualField.error = err instanceof Error ? err.message : String(err);
+ } finally {
+ virtualField.loading = false;
+ }
+}
+
+export async function saveVirtualField(): Promise {
+ virtualField.saving = true;
+ virtualField.error = null;
+
+ try {
+ const response = await fetch("/api/geometry/field", {
+ method: "PUT",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ field: virtualField.field,
+ optionalFieldLines: virtualField.optionalFieldLines,
+ } satisfies FieldConfigResponse),
+ });
+
+ if (!response.ok) {
+ throw new Error(await response.text());
+ }
+
+ virtualField.dirty = false;
+
+ // The saved dimensions are also the source of truth for the sketch, and
+ // the server just regenerated fieldLines/fieldArcs from them.
+ const geometryRes = await fetch("/api/geometry");
+ if (geometryRes.ok) {
+ const geometry = (await geometryRes.json()) as GeometryResponse;
+ virtualField.fieldLines = geometry.geometry?.field?.fieldLines ?? [];
+ virtualField.fieldArcs = geometry.geometry?.field?.fieldArcs ?? [];
+ }
+ } catch (err) {
+ virtualField.error = err instanceof Error ? err.message : String(err);
+ } finally {
+ virtualField.saving = false;
+ }
+}
diff --git a/gui/frontend/src/lib/layout/ConfigNav.svelte b/gui/frontend/src/lib/layout/ConfigNav.svelte
new file mode 100644
index 0000000..ea19700
--- /dev/null
+++ b/gui/frontend/src/lib/layout/ConfigNav.svelte
@@ -0,0 +1,105 @@
+
+
+
+ Shared
+
+ {#each sharedCategories as category (category.id)}
+
+ {
+ nav.selectedCategoryId = category.id;
+ }}
+ >
+ {category.label}
+
+
+ {/each}
+
+
+
+ {#if selectedInstance()}
+ {selectedInstance()?.host} / cam {selectedInstance()?.cameraId}
+ {:else}
+ Per-instance (select one above)
+ {/if}
+
+
+ {#each instanceCategories as category (category.id)}
+
+ {
+ nav.selectedCategoryId = category.id;
+ }}
+ >
+ {category.label}
+
+
+ {/each}
+
+
+
+
diff --git a/gui/frontend/src/lib/layout/InstanceList.svelte b/gui/frontend/src/lib/layout/InstanceList.svelte
new file mode 100644
index 0000000..2e4b9a8
--- /dev/null
+++ b/gui/frontend/src/lib/layout/InstanceList.svelte
@@ -0,0 +1,83 @@
+
+
+
+ Vision processors
+
+ One row per camera role, not per machine -- a host running all 4 cameras of
+ a quad setup appears here 4 times. Mock data for now; see internal/discovery
+ in gui/CLAUDE.md's "Not yet built".
+
+
+
+ {#each nav.instances as instance (instance.id)}
+
+ {
+ nav.selectedInstanceId = instance.id;
+ }}
+ >
+ {instance.host}
+ cam {instance.cameraId}
+
+
+ {/each}
+
+
+
+
diff --git a/gui/frontend/src/lib/layout/MainContent.svelte b/gui/frontend/src/lib/layout/MainContent.svelte
new file mode 100644
index 0000000..b9f15be
--- /dev/null
+++ b/gui/frontend/src/lib/layout/MainContent.svelte
@@ -0,0 +1,28 @@
+
+
+
+
+
+ {#if nav.selectedCategoryId === "field"}
+
+ {:else if nav.selectedCategoryId === "geometry"}
+
+ {:else}
+
+ {/if}
+
+
+
diff --git a/gui/frontend/src/lib/layout/Shell.svelte b/gui/frontend/src/lib/layout/Shell.svelte
new file mode 100644
index 0000000..b06ae75
--- /dev/null
+++ b/gui/frontend/src/lib/layout/Shell.svelte
@@ -0,0 +1,107 @@
+
+
+
+
+ vision-processor
+
+ {$connectionState}
+
+
+
+
+
+
+
+ {#if below}
+
+ {@render below()}
+
+ {/if}
+
+
+
+
diff --git a/gui/frontend/src/lib/layout/TabBar.svelte b/gui/frontend/src/lib/layout/TabBar.svelte
new file mode 100644
index 0000000..d59f48f
--- /dev/null
+++ b/gui/frontend/src/lib/layout/TabBar.svelte
@@ -0,0 +1,68 @@
+
+
+
+ {#each tabs as tab (tab.id)}
+ {
+ nav.selectedCategoryId = tab.id;
+ }}
+ >
+ {tab.label}
+
+ {/each}
+
+
+
diff --git a/gui/frontend/src/lib/layout/configCategories.ts b/gui/frontend/src/lib/layout/configCategories.ts
new file mode 100644
index 0000000..9afc2af
--- /dev/null
+++ b/gui/frontend/src/lib/layout/configCategories.ts
@@ -0,0 +1,158 @@
+// The left sidebar's lower nav list, one entry per config.yml top-level
+// section (see config.yml / config-camtest.yml at the repo root) plus one
+// for the shared field geometry. Field names/comments below are copied
+// straight from config.yml -- ground truth for whichever contributor builds
+// out a real form for a category, not invented.
+//
+// scope: "shared" categories are one thing for the whole deployment
+// (geometry.yml, edited by FieldEditor already). "per-instance" categories
+// are a single vision processor's own config.yml, which this host does not
+// yet read, write, or push to any instance -- see gui/CLAUDE.md's "Not yet
+// built". Their panels are placeholders until that exists.
+export type ConfigScope = "shared" | "per-instance";
+
+export interface ConfigField {
+ name: string;
+ comment: string;
+}
+
+export interface ConfigCategory {
+ id: string;
+ label: string;
+ scope: ConfigScope;
+ /** The config.yml top-level key this maps to, or null for the shared field geometry. */
+ yamlKey: string | null;
+ fields: ConfigField[];
+}
+
+export const CONFIG_CATEGORIES: ConfigCategory[] = [
+ {
+ id: "field",
+ label: "Virtual Field",
+ scope: "shared",
+ yamlKey: null, // geometry.yml's field: block, not config.yml
+ fields: [],
+ },
+ {
+ id: "camera",
+ label: "Camera",
+ scope: "per-instance",
+ yamlKey: "camera",
+ fields: [
+ { name: "driver", comment: "SPINNAKER, MVIMPACT, or OPENCV" },
+ { name: "id / path", comment: "Which camera device" },
+ { name: "width / height", comment: "0 = highest supported resolution" },
+ { name: "exposure", comment: "ms; 0.0 = automatic" },
+ { name: "gain", comment: "0.0 = automatic" },
+ { name: "gamma", comment: "1.0 = no gamma" },
+ { name: "white_balance", comment: "OUTDOOR/INDOOR, or manual red/blue" },
+ ],
+ },
+ {
+ id: "geometry",
+ label: "Geometry",
+ scope: "per-instance",
+ yamlKey: "geometry", // config.yml's geometry: block -- NOT geometry.yml's field:
+ fields: [
+ { name: "camera_amount", comment: "Total cameras over the field" },
+ {
+ name: "camera_height",
+ comment: "mm; 0.0 = automatic (fails if camera looks perpendicular)",
+ },
+ {
+ name: "line_corners",
+ comment:
+ "Pixel corners for calibration seeding -- this is what the Corner Picker below produces",
+ },
+ { name: "refinement", comment: "Field line pixel refinement toggle" },
+ { name: "field_line_threshold", comment: "0-255 brightness delta" },
+ { name: "min_line_segment_length", comment: "px" },
+ { name: "max_line_segment_offset", comment: "px" },
+ { name: "max_line_segment_angle", comment: "degrees" },
+ ],
+ },
+ {
+ id: "thresholds",
+ label: "Thresholds",
+ scope: "per-instance",
+ yamlKey: "thresholds",
+ fields: [
+ { name: "circularity", comment: "0 - 195075.0" },
+ { name: "score", comment: "min circularity/(3*stddev)" },
+ { name: "blobs", comment: "max blobs processed per frame" },
+ { name: "min_confidence", comment: "0.0 - 1.0" },
+ { name: "min_cam_edge_distance", comment: "mm" },
+ { name: "clipping_tolerance", comment: "mm" },
+ { name: "geometry_tolerance", comment: "mm" },
+ ],
+ },
+ {
+ id: "color",
+ label: "Color",
+ scope: "per-instance",
+ yamlKey: "color",
+ fields: [
+ { name: "reference_force", comment: "0.0 - 0.5-history_force/2" },
+ { name: "history_force", comment: "0.0 - 1.0-reference_force" },
+ { name: "orange / field", comment: "ball / carpet reference colors" },
+ { name: "yellow / blue", comment: "center blob reference colors" },
+ { name: "green / pink", comment: "side blob reference colors" },
+ ],
+ },
+ {
+ id: "tracking",
+ label: "Tracking",
+ scope: "per-instance",
+ yamlKey: "tracking",
+ fields: [
+ { name: "min_tracking_radius", comment: "mm" },
+ { name: "max_bot_acceleration", comment: "m/s^2" },
+ ],
+ },
+ {
+ id: "network",
+ label: "Network",
+ scope: "per-instance",
+ yamlKey: "network",
+ fields: [
+ { name: "gc_ip / gc_port", comment: "game controller multicast" },
+ { name: "vision_ip / vision_port", comment: "vision multicast" },
+ ],
+ },
+ {
+ id: "stream",
+ label: "Stream",
+ scope: "per-instance",
+ yamlKey: "stream",
+ fields: [
+ { name: "active", comment: "encode and send a live stream" },
+ { name: "raw_feed", comment: "raw camera footage only" },
+ { name: "ip_base_prefix / ip_base_end", comment: "stream destination" },
+ { name: "port", comment: "stream port" },
+ ],
+ },
+ {
+ id: "debug",
+ label: "Debug",
+ scope: "per-instance",
+ yamlKey: "debug",
+ // Not to be confused with the mockup's future "Debug Console" (a live log
+ // viewer over internal/hub) -- this is config.yml's debug: block, which
+ // controls the vision processor's own diagnostic image output.
+ fields: [
+ { name: "ground_truth", comment: "used by blob/geometry benchmarks" },
+ { name: "wait_for_geometry", comment: "hold frames until calibrated" },
+ { name: "debug_images", comment: "save additional debug images in img/" },
+ {
+ name: "debug_stream_interval_ms",
+ comment: "periodic img/.sample..png while uncalibrated",
+ },
+ ],
+ },
+];
+
+// The main column's own horizontal tab bar: quick access to the categories
+// used constantly while working on one camera, separate from the sidebar's
+// full list of all nine. Start small and add to this as more categories earn
+// a spot -- it's deliberately a subset, not a duplicate of CONFIG_CATEGORIES.
+export const TAB_CATEGORY_IDS = ["field", "geometry", "color"];
diff --git a/gui/frontend/src/lib/layout/nav.svelte.ts b/gui/frontend/src/lib/layout/nav.svelte.ts
new file mode 100644
index 0000000..024a2c8
--- /dev/null
+++ b/gui/frontend/src/lib/layout/nav.svelte.ts
@@ -0,0 +1,50 @@
+// Shared navigation state for the two-column shell: which vision-role
+// instance and which config category are selected. A module-level $state
+// object, per the project convention (see CLAUDE.md).
+import { CONFIG_CATEGORIES, type ConfigCategory } from "./configCategories";
+
+// One row in the instance list: a single camera role on a single host, not a
+// machine. A host running all 4 cameras of a quad setup appears as 4 rows
+// sharing the same host, one per camera_id -- see the note in App.svelte
+// about internal/discovery not existing yet.
+export interface VisionInstance {
+ id: string;
+ host: string;
+ cameraId: number;
+}
+
+// TODO(discovery): mock data. Replace with instances built from SSL_VPConfig
+// announces once internal/discovery exists (see gui/CLAUDE.md's "Not yet
+// built"). Kept non-empty so the panel has something to click while that's
+// unbuilt, rather than looking broken.
+const MOCK_INSTANCES: VisionInstance[] = [
+ { id: "camtest:0", host: "camtest-host", cameraId: 0 },
+ { id: "camtest:1", host: "camtest-host", cameraId: 1 },
+];
+
+export const nav = $state<{
+ instances: VisionInstance[];
+ selectedInstanceId: string | null;
+ selectedCategoryId: string;
+}>({
+ instances: MOCK_INSTANCES,
+ selectedInstanceId: MOCK_INSTANCES[0]?.id ?? null,
+ selectedCategoryId: "field",
+});
+
+export function selectedInstance(): VisionInstance | undefined {
+ return nav.instances.find((i) => i.id === nav.selectedInstanceId);
+}
+
+export function selectedCategory(): ConfigCategory {
+ const found = CONFIG_CATEGORIES.find((c) => c.id === nav.selectedCategoryId);
+ if (found) return found;
+
+ // "field" is always present in CONFIG_CATEGORIES (see configCategories.ts);
+ // a thrown error here means that constant was edited to remove it, which
+ // is a real bug worth surfacing loudly rather than typing around.
+ const fallback = CONFIG_CATEGORIES.find((c) => c.id === "field");
+ if (fallback) return fallback;
+
+ throw new Error("CONFIG_CATEGORIES is missing the 'field' category");
+}
diff --git a/gui/frontend/src/lib/wrapper-bus.ts b/gui/frontend/src/lib/wrapper-bus.ts
index e6de7eb..d69f047 100644
--- a/gui/frontend/src/lib/wrapper-bus.ts
+++ b/gui/frontend/src/lib/wrapper-bus.ts
@@ -2,7 +2,9 @@ import { readable, type Readable } from "svelte/store";
export type ConnectionState = "connecting" | "open" | "closed";
-const DEFAULT_URL = `ws://${location.hostname || "localhost"}:8765/ws`;
+// Same-origin: the Go host serves /ws itself, alongside /api and the frontend.
+// wss:// when the page itself was loaded over https.
+const DEFAULT_URL = `${location.protocol === "https:" ? "wss" : "ws"}://${location.host}/ws`;
const BACKOFF_INITIAL_MS = 1_000;
const BACKOFF_MAX_MS = 30_000;
diff --git a/gui/frontend/vite.config.ts b/gui/frontend/vite.config.ts
index 20d2272..a8c1525 100644
--- a/gui/frontend/vite.config.ts
+++ b/gui/frontend/vite.config.ts
@@ -4,4 +4,12 @@ import { svelte } from "@sveltejs/vite-plugin-svelte";
// https://vite.dev/config/
export default defineConfig({
plugins: [svelte()],
+ server: {
+ // The Go host serves /api and /ws on :8085; everything else (this dev
+ // server) is same-origin so no CORS handling is needed on either side.
+ proxy: {
+ "/api": "http://localhost:8085",
+ "/ws": { target: "ws://localhost:8085", ws: true },
+ },
+ },
});
diff --git a/gui/go.mod b/gui/go.mod
index 7282a95..619772b 100644
--- a/gui/go.mod
+++ b/gui/go.mod
@@ -7,3 +7,14 @@ require (
google.golang.org/protobuf v1.36.12
gopkg.in/natefinch/lumberjack.v2 v2.2.1
)
+
+require gopkg.in/yaml.v3 v3.0.1
+
+require github.com/gorilla/websocket v1.5.3
+
+require (
+ github.com/RoboCup-SSL/ssl-go-tools v1.12.0
+ github.com/libp2p/go-reuseport v0.4.0 // indirect
+ golang.org/x/net v0.55.0 // indirect
+ golang.org/x/sys v0.45.0 // indirect
+)
diff --git a/gui/go.sum b/gui/go.sum
index 5ad9ae0..861e898 100644
--- a/gui/go.sum
+++ b/gui/go.sum
@@ -1,8 +1,28 @@
+github.com/RoboCup-SSL/ssl-go-tools v1.12.0 h1:sXN+VSlMSOtNdLD0MPCaig3vSlj3ZTz/KIi9uJR/dy0=
+github.com/RoboCup-SSL/ssl-go-tools v1.12.0/go.mod h1:Gqrqs0LAcXmCQD3Z+IPXxrqxS9xc9sWJolYQyi3AHbw=
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
+github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s=
+github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU=
github.com/lmittmann/tint v1.2.0 h1:AogHRHy8HUJUnNJBHJlYa+fR4YY8mko2cnCp67xn9JY=
github.com/lmittmann/tint v1.2.0/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
+golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
+golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
+golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/gui/internal/geometry/configfile.go b/gui/internal/geometry/configfile.go
new file mode 100644
index 0000000..3deadd9
--- /dev/null
+++ b/gui/internal/geometry/configfile.go
@@ -0,0 +1,116 @@
+package geometry
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "os"
+
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
+ "google.golang.org/protobuf/encoding/protojson"
+ "gopkg.in/yaml.v3"
+)
+
+type optionalLines struct {
+ Goal2Goal *bool `yaml:"goal2goal"`
+ Halfway *bool `yaml:"halfway"`
+ CenterCircle *bool `yaml:"centercircle"`
+ Penalty *bool `yaml:"penalty"`
+}
+
+// Load reads path and returns the wrapper packet, the optional-line toggles
+// (not a proto field, so callers wanting to inspect or re-save them need it
+// separately), and whatever top-level YAML keys aren't "optional_field_lines"
+// or "field" (e.g. "models") so a later save can put them back unchanged.
+func Load(path string) (*vision.SSL_WrapperPacket, optionalLines, map[string]any, error) {
+ data, err := os.ReadFile(path)
+ if err != nil {
+ return nil, optionalLines{}, nil, fmt.Errorf("read %s: %w", path, err)
+ }
+
+ var raw map[string]any
+ if err := yaml.Unmarshal(data, &raw); err != nil {
+ return nil, optionalLines{}, nil, fmt.Errorf("parse %s: %w", path, err)
+ }
+
+ lines, err := popOptionalLines(raw)
+ if err != nil {
+ return nil, optionalLines{}, nil, fmt.Errorf("%s: %w", path, err)
+ }
+
+ geometry, err := decodeGeometry(raw)
+ if err != nil {
+ return nil, optionalLines{}, nil, fmt.Errorf("%s: %w", path, err)
+ }
+
+ delete(raw, "field")
+
+ wrapper := &vision.SSL_WrapperPacket{
+ Geometry: geometry,
+ Source: vision.SSL_Source_SSL_SOURCE_VISION_PROCESSOR.Enum(),
+ }
+
+ generateFieldMarkings(wrapper.GetGeometry().GetField(), lines)
+
+ return wrapper, lines, raw, nil
+}
+
+func popOptionalLines(raw map[string]any) (optionalLines, error) {
+ block, ok := raw["optional_field_lines"]
+ if !ok {
+ return optionalLines{}, errors.New("optional_field_lines: required block is missing")
+ }
+
+ delete(raw, "optional_field_lines")
+
+ return decodeOptionalLines(block)
+}
+
+func decodeOptionalLines(block any) (optionalLines, error) {
+ data, err := yaml.Marshal(block)
+ if err != nil {
+ return optionalLines{}, fmt.Errorf("optional_field_lines: %w", err)
+ }
+
+ decoder := yaml.NewDecoder(bytes.NewReader(data))
+ decoder.KnownFields(true)
+
+ var lines optionalLines
+ if err := decoder.Decode(&lines); err != nil {
+ return optionalLines{}, fmt.Errorf("optional_field_lines: %w", err)
+ }
+
+ return lines, lines.validate()
+}
+
+func (o optionalLines) validate() error {
+ var errs error
+
+ for key, value := range map[string]*bool{
+ "goal2goal": o.Goal2Goal,
+ "halfway": o.Halfway,
+ "centercircle": o.CenterCircle,
+ "penalty": o.Penalty,
+ } {
+ if value == nil {
+ errs = errors.Join(errs, fmt.Errorf("optional_field_lines.%s: required", key))
+ }
+ }
+
+ return errs
+}
+
+func decodeGeometry(raw map[string]any) (*vision.SSL_GeometryData, error) {
+ data, err := json.Marshal(raw)
+ if err != nil {
+ return nil, fmt.Errorf("geometry: %w", err)
+ }
+
+ geometry := &vision.SSL_GeometryData{}
+ if err := protojson.Unmarshal(data, geometry); err != nil {
+ return nil, fmt.Errorf("geometry: %w", err)
+ }
+
+ return geometry, nil
+}
diff --git a/gui/internal/geometry/field.go b/gui/internal/geometry/field.go
new file mode 100644
index 0000000..2af0b05
--- /dev/null
+++ b/gui/internal/geometry/field.go
@@ -0,0 +1,87 @@
+package geometry
+
+import (
+ "math"
+
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
+ "google.golang.org/protobuf/proto"
+)
+
+// generateFieldMarkings appends the standard SSL lines and arcs derived from the
+// field dimensions. Markings the physical field lacks are skipped: publishing a
+// line the camera cannot see disturbs refinement calibration.
+//
+// Coordinates are in mm, with the origin at the field centre, +x towards the
+// right goal and +y towards the top touch line.
+func generateFieldMarkings(field *vision.SSL_GeometryFieldSize, optional optionalLines) {
+ var (
+ thickness = float32(field.GetLineThickness())
+ halfLength = float32(field.GetFieldLength()) / 2
+ halfWidth = float32(field.GetFieldWidth()) / 2
+ penaltyLength = halfLength - float32(field.GetPenaltyAreaDepth())
+ halfPenalty = float32(field.GetPenaltyAreaWidth()) / 2
+ )
+
+ addLine := func(shape vision.SSL_FieldShapeType, x1, y1, x2, y2 float32) {
+ field.FieldLines = append(field.FieldLines, &vision.SSL_FieldLineSegment{
+ // The name is the enum value's own spelling, which is what the rest
+ // of the league keys off.
+ Name: proto.String(shape.String()),
+ P1: &vision.Vector2F{X: proto.Float32(x1), Y: proto.Float32(y1)},
+ P2: &vision.Vector2F{X: proto.Float32(x2), Y: proto.Float32(y2)},
+ Thickness: proto.Float32(thickness),
+ Type: shape.Enum(),
+ })
+ }
+
+ // Touchlines and goal lines are always present: every field has them, and
+ // they bound the area the detector considers in play.
+ addLine(vision.SSL_FieldShapeType_TopTouchLine, -halfLength, halfWidth, halfLength, halfWidth)
+ addLine(vision.SSL_FieldShapeType_BottomTouchLine, -halfLength, -halfWidth, halfLength, -halfWidth)
+ addLine(vision.SSL_FieldShapeType_LeftGoalLine, -halfLength, -halfWidth, -halfLength, halfWidth)
+ addLine(vision.SSL_FieldShapeType_RightGoalLine, halfLength, -halfWidth, halfLength, halfWidth)
+
+ if optional.enabled(optional.Halfway) {
+ addLine(vision.SSL_FieldShapeType_HalfwayLine, 0, -halfWidth, 0, halfWidth)
+ }
+
+ if optional.enabled(optional.Goal2Goal) {
+ addLine(vision.SSL_FieldShapeType_CenterLine, -halfLength, 0, halfLength, 0)
+ }
+
+ if optional.enabled(optional.Penalty) {
+ addLine(vision.SSL_FieldShapeType_LeftPenaltyStretch,
+ -penaltyLength, -halfPenalty, -penaltyLength, halfPenalty)
+ addLine(vision.SSL_FieldShapeType_RightPenaltyStretch,
+ penaltyLength, -halfPenalty, penaltyLength, halfPenalty)
+ addLine(vision.SSL_FieldShapeType_LeftFieldLeftPenaltyStretch,
+ -halfLength, -halfPenalty, -penaltyLength, -halfPenalty)
+ addLine(vision.SSL_FieldShapeType_LeftFieldRightPenaltyStretch,
+ -halfLength, halfPenalty, -penaltyLength, halfPenalty)
+ addLine(vision.SSL_FieldShapeType_RightFieldLeftPenaltyStretch,
+ penaltyLength, halfPenalty, halfLength, halfPenalty)
+ addLine(vision.SSL_FieldShapeType_RightFieldRightPenaltyStretch,
+ penaltyLength, -halfPenalty, halfLength, -halfPenalty)
+ }
+
+ if optional.enabled(optional.CenterCircle) {
+ shape := vision.SSL_FieldShapeType_CenterCircle
+
+ field.FieldArcs = append(field.FieldArcs, &vision.SSL_FieldCircularArc{
+ Name: proto.String(shape.String()),
+ Center: &vision.Vector2F{X: proto.Float32(0), Y: proto.Float32(0)},
+ Radius: proto.Float32(float32(field.GetCenterCircleRadius())),
+ A1: proto.Float32(0),
+ A2: proto.Float32(math.Pi * 2),
+ Thickness: proto.Float32(thickness),
+ Type: shape.Enum(),
+ })
+ }
+}
+
+// enabled reads one of the optionalLines pointers. A nil pointer cannot occur
+// after validate, but treating it as off keeps a programming error from
+// publishing a marking the field does not have.
+func (o optionalLines) enabled(flag *bool) bool {
+ return flag != nil && *flag
+}
diff --git a/gui/internal/geometry/field_config.go b/gui/internal/geometry/field_config.go
new file mode 100644
index 0000000..1811032
--- /dev/null
+++ b/gui/internal/geometry/field_config.go
@@ -0,0 +1,245 @@
+package geometry
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "path/filepath"
+
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
+ "google.golang.org/protobuf/proto"
+ "gopkg.in/yaml.v3"
+)
+
+// ReadOnlyFiles are geometry files UpdateField refuses to overwrite: the
+// rulebook presets (see gui/frontend/src/lib/fieldPresets.ts, or rather --
+// once presets are read from these directly -- the sole source of truth for
+// them). Matched by base filename, wherever -geometryFile happens to point.
+//
+// This exists because it's an easy mistake to make once, not a hypothetical:
+// the default -geometryFile briefly was "geometry-divB.yml" itself, so the
+// very first Save in the Virtual Field editor would have silently overwritten
+// the tracked competition preset.
+var ReadOnlyFiles = map[string]bool{
+ "geometry-divA.yml": true,
+ "geometry-divB.yml": true,
+}
+
+// ReadOnlyError marks a save rejected because the target file is a protected
+// preset, not the caller's working config.
+type ReadOnlyError struct{ path string }
+
+func (e *ReadOnlyError) Error() string {
+ return fmt.Sprintf("%s is a read-only rulebook preset; point -geometryFile at a working copy instead", e.path)
+}
+
+// FieldConfig is the editable subset of SSL_GeometryFieldSize -- everything
+// except FieldLines/FieldArcs (generated, never hand-edited) and the fields
+// that live elsewhere (Calib is runtime state, not static config).
+type FieldConfig struct {
+ FieldLength int32 `yaml:"field_length" json:"fieldLength"`
+ FieldWidth int32 `yaml:"field_width" json:"fieldWidth"`
+ GoalWidth int32 `yaml:"goal_width" json:"goalWidth"`
+ GoalDepth int32 `yaml:"goal_depth" json:"goalDepth"`
+ GoalHeight int32 `yaml:"goal_height" json:"goalHeight"`
+ PenaltyAreaDepth int32 `yaml:"penalty_area_depth" json:"penaltyAreaDepth"`
+ PenaltyAreaWidth int32 `yaml:"penalty_area_width" json:"penaltyAreaWidth"`
+ GoalCenterToPenaltyMark int32 `yaml:"goal_center_to_penalty_mark" json:"goalCenterToPenaltyMark"`
+ BoundaryWidth int32 `yaml:"boundary_width" json:"boundaryWidth"`
+ BoundaryWidthGoalLine int32 `yaml:"boundary_width_goal_line" json:"boundaryWidthGoalLine"`
+ CenterCircleRadius int32 `yaml:"center_circle_radius" json:"centerCircleRadius"`
+ LineThickness int32 `yaml:"line_thickness" json:"lineThickness"`
+ BallRadius float32 `yaml:"ball_radius" json:"ballRadius"`
+ MaxRobotRadius float32 `yaml:"max_robot_radius" json:"maxRobotRadius"`
+ GoalSubstitutionAreaWidth int32 `yaml:"goal_substitution_area_width" json:"goalSubstitutionAreaWidth"`
+}
+
+// OptionalLinesConfig is optionalLines with concrete bools instead of
+// pointers -- an API request/response always supplies all four, so there's no
+// "missing" case to represent here the way there is when parsing a hand-edited
+// YAML file.
+type OptionalLinesConfig struct {
+ Goal2Goal bool `json:"goal2Goal"`
+ Halfway bool `json:"halfway"`
+ CenterCircle bool `json:"centerCircle"`
+ Penalty bool `json:"penalty"`
+}
+
+// ValidationError marks a FieldConfig rejected by Validate -- the caller's
+// mistake, not ours. Callers such as the HTTP handler use errors.As to tell
+// this apart from an internal failure (e.g. a disk write error) and respond
+// 400 instead of 500.
+type ValidationError struct{ err error }
+
+func (v *ValidationError) Error() string { return v.err.Error() }
+func (v *ValidationError) Unwrap() error { return v.err }
+
+// Validate reports every dimension that can't be right, so a caller can
+// surface all of them at once rather than one failed PUT per typo.
+func (c FieldConfig) Validate() error {
+ var errs error
+
+ check := func(name string, value int32) {
+ if value <= 0 {
+ errs = errors.Join(errs, fmt.Errorf("%s: must be greater than 0, got %d", name, value))
+ }
+ }
+
+ check("field_length", c.FieldLength)
+ check("field_width", c.FieldWidth)
+ check("goal_width", c.GoalWidth)
+ check("goal_depth", c.GoalDepth)
+ check("boundary_width", c.BoundaryWidth)
+
+ if errs != nil {
+ return &ValidationError{errs}
+ }
+
+ return nil
+}
+
+// FieldConfig returns the current editable field dimensions and optional-line
+// toggles.
+func (g *Geometry) FieldConfig() (FieldConfig, OptionalLinesConfig) {
+ g.mu.Lock()
+ defer g.mu.Unlock()
+
+ return fieldConfigFrom(g.wrapper.GetGeometry().GetField(), g.optional)
+}
+
+// fieldConfigFrom reads a FieldConfig/OptionalLinesConfig pair out of a
+// decoded field size and its optional-line toggles. Shared by FieldConfig
+// (the live, held Geometry) and LoadPreset (an arbitrary file read fresh,
+// with no Geometry involved).
+func fieldConfigFrom(field *vision.SSL_GeometryFieldSize, optional optionalLines) (FieldConfig, OptionalLinesConfig) {
+ return FieldConfig{
+ FieldLength: field.GetFieldLength(),
+ FieldWidth: field.GetFieldWidth(),
+ GoalWidth: field.GetGoalWidth(),
+ GoalDepth: field.GetGoalDepth(),
+ GoalHeight: field.GetGoalHeight(),
+ PenaltyAreaDepth: field.GetPenaltyAreaDepth(),
+ PenaltyAreaWidth: field.GetPenaltyAreaWidth(),
+ GoalCenterToPenaltyMark: field.GetGoalCenterToPenaltyMark(),
+ BoundaryWidth: field.GetBoundaryWidth(),
+ BoundaryWidthGoalLine: field.GetBoundaryWidthGoalLine(),
+ CenterCircleRadius: field.GetCenterCircleRadius(),
+ LineThickness: field.GetLineThickness(),
+ BallRadius: field.GetBallRadius(),
+ MaxRobotRadius: field.GetMaxRobotRadius(),
+ GoalSubstitutionAreaWidth: field.GetGoalSubstitutionAreaWidth(),
+ }, OptionalLinesConfig{
+ Goal2Goal: optional.enabled(optional.Goal2Goal),
+ Halfway: optional.enabled(optional.Halfway),
+ CenterCircle: optional.enabled(optional.CenterCircle),
+ Penalty: optional.enabled(optional.Penalty),
+ }
+}
+
+// LoadPreset reads a geometry YAML file fresh -- no Geometry instance, no
+// mutation of anything -- and returns its field dimensions and optional-line
+// toggles. Used to serve the rulebook presets (geometry-divA.yml,
+// geometry-divB.yml) straight from the same files a human would open, rather
+// than a copy that could drift from them.
+func LoadPreset(path string) (FieldConfig, OptionalLinesConfig, error) {
+ wrapper, optional, _, err := Load(path)
+ if err != nil {
+ return FieldConfig{}, OptionalLinesConfig{}, err
+ }
+
+ field, opt := fieldConfigFrom(wrapper.GetGeometry().GetField(), optional)
+
+ return field, opt, nil
+}
+
+// UpdateField replaces the field dimensions and optional-line toggles,
+// regenerates the derived field lines/arcs, and persists the change to the
+// file Geometry was loaded from. Existing calibrations are kept.
+//
+// Persisting rewrites the whole file, so hand-added comments in it do not
+// survive a save made through this path.
+func (g *Geometry) UpdateField(cfg FieldConfig, opt OptionalLinesConfig) error {
+ if err := cfg.Validate(); err != nil {
+ return err
+ }
+
+ g.mu.Lock()
+ defer g.mu.Unlock()
+
+ // Checked before anything below mutates g.wrapper/g.optional: a rejected
+ // save must not leave the in-memory (and multicast-broadcast) state
+ // holding values that were never actually persisted.
+ if ReadOnlyFiles[filepath.Base(g.path)] {
+ return &ReadOnlyError{path: g.path}
+ }
+
+ field := &vision.SSL_GeometryFieldSize{
+ FieldLength: proto.Int32(cfg.FieldLength),
+ FieldWidth: proto.Int32(cfg.FieldWidth),
+ GoalWidth: proto.Int32(cfg.GoalWidth),
+ GoalDepth: proto.Int32(cfg.GoalDepth),
+ GoalHeight: proto.Int32(cfg.GoalHeight),
+ PenaltyAreaDepth: proto.Int32(cfg.PenaltyAreaDepth),
+ PenaltyAreaWidth: proto.Int32(cfg.PenaltyAreaWidth),
+ GoalCenterToPenaltyMark: proto.Int32(cfg.GoalCenterToPenaltyMark),
+ BoundaryWidth: proto.Int32(cfg.BoundaryWidth),
+ BoundaryWidthGoalLine: proto.Int32(cfg.BoundaryWidthGoalLine),
+ CenterCircleRadius: proto.Int32(cfg.CenterCircleRadius),
+ LineThickness: proto.Int32(cfg.LineThickness),
+ BallRadius: proto.Float32(cfg.BallRadius),
+ MaxRobotRadius: proto.Float32(cfg.MaxRobotRadius),
+ GoalSubstitutionAreaWidth: proto.Int32(cfg.GoalSubstitutionAreaWidth),
+ }
+
+ optional := optionalLines{
+ Goal2Goal: &opt.Goal2Goal,
+ Halfway: &opt.Halfway,
+ CenterCircle: &opt.CenterCircle,
+ Penalty: &opt.Penalty,
+ }
+
+ generateFieldMarkings(field, optional)
+
+ g.wrapper.Geometry.Field = field
+ g.optional = optional
+
+ if err := g.reencode(); err != nil {
+ return fmt.Errorf("encode updated geometry: %w", err)
+ }
+
+ if err := g.saveYAML(cfg, opt); err != nil {
+ return fmt.Errorf("save %s: %w", g.path, err)
+ }
+
+ return nil
+}
+
+// saveYAML writes the current field config and optional-line toggles back to
+// g.path, merged with whatever other top-level keys (e.g. "models") were
+// present when it was loaded. Callers must hold mu.
+func (g *Geometry) saveYAML(cfg FieldConfig, opt OptionalLinesConfig) error {
+ if ReadOnlyFiles[filepath.Base(g.path)] {
+ return &ReadOnlyError{path: g.path}
+ }
+
+ out := map[string]any{
+ "optional_field_lines": map[string]bool{
+ "goal2goal": opt.Goal2Goal,
+ "halfway": opt.Halfway,
+ "centercircle": opt.CenterCircle,
+ "penalty": opt.Penalty,
+ },
+ "field": cfg,
+ }
+
+ for k, v := range g.extra {
+ out[k] = v
+ }
+
+ data, err := yaml.Marshal(out)
+ if err != nil {
+ return err
+ }
+
+ return os.WriteFile(g.path, data, 0o644)
+}
diff --git a/gui/internal/geometry/field_config_test.go b/gui/internal/geometry/field_config_test.go
new file mode 100644
index 0000000..2eea80a
--- /dev/null
+++ b/gui/internal/geometry/field_config_test.go
@@ -0,0 +1,190 @@
+package geometry
+
+import (
+ "errors"
+ "os"
+ "path/filepath"
+ "testing"
+
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
+)
+
+func testConfig() FieldConfig {
+ return FieldConfig{
+ FieldLength: 2160,
+ FieldWidth: 1680,
+ GoalWidth: 280,
+ GoalDepth: 50,
+ BoundaryWidth: 100,
+ LineThickness: 10,
+ }
+}
+
+func testOptional() OptionalLinesConfig {
+ return OptionalLinesConfig{Halfway: true, Penalty: true}
+}
+
+func TestFieldConfigRoundTripsThroughGet(t *testing.T) {
+ g := testGeometry(t)
+
+ cfg := testConfig()
+ opt := testOptional()
+
+ if err := g.UpdateField(cfg, opt); err != nil {
+ t.Fatalf("UpdateField: %v", err)
+ }
+
+ gotCfg, gotOpt := g.FieldConfig()
+ if gotCfg != cfg {
+ t.Errorf("FieldConfig() = %+v, want %+v", gotCfg, cfg)
+ }
+
+ if gotOpt != opt {
+ t.Errorf("optional = %+v, want %+v", gotOpt, opt)
+ }
+}
+
+func TestUpdateFieldRegeneratesMarkings(t *testing.T) {
+ g := testGeometry(t)
+
+ if err := g.UpdateField(testConfig(), testOptional()); err != nil {
+ t.Fatalf("UpdateField: %v", err)
+ }
+
+ lines := g.Snapshot().GetGeometry().GetField().GetFieldLines()
+
+ // Halfway is on, goal2goal/centercircle are off: expect the 4 mandatory
+ // lines + HalfwayLine + the 6 penalty stretches, nothing else.
+ if len(lines) != 11 {
+ t.Fatalf("field lines = %d, want 11 (got %v)", len(lines), lines)
+ }
+}
+
+func TestUpdateFieldRejectsNonsenseDimensions(t *testing.T) {
+ g := testGeometry(t)
+
+ cfg := testConfig()
+ cfg.FieldLength = 0
+
+ if err := g.UpdateField(cfg, testOptional()); err == nil {
+ t.Fatal("UpdateField accepted a zero field_length")
+ }
+}
+
+func TestUpdateFieldKeepsExistingCalibrations(t *testing.T) {
+ g := testGeometry(t)
+ g.Absorb(&vision.SSL_GeometryData{Calib: []*vision.SSL_GeometryCameraCalibration{calib(0, 400)}})
+
+ if err := g.UpdateField(testConfig(), testOptional()); err != nil {
+ t.Fatalf("UpdateField: %v", err)
+ }
+
+ if got := g.Snapshot().GetGeometry().GetCalib(); len(got) != 1 {
+ t.Fatalf("calib = %v, want the pre-existing entry kept", got)
+ }
+}
+
+// UpdateField persists to the file Geometry was loaded from. A second Load of
+// that same file must see the new dimensions, and "models" (which UpdateField
+// never touches) must have survived the round trip unchanged.
+func TestUpdateFieldPersistsAndPreservesExtraKeys(t *testing.T) {
+ dir := t.TempDir()
+ path := filepath.Join(dir, "geometry.yml")
+
+ src, err := os.ReadFile("testdata/geometry.yml")
+ if err != nil {
+ t.Fatalf("ReadFile fixture: %v", err)
+ }
+
+ fixtureWithModels := string(src) + "\nmodels:\n straight_two_phase:\n acc_slide: -3.4\n acc_roll: -0.45\n k_switch: 0.64\n"
+ if err := os.WriteFile(path, []byte(fixtureWithModels), 0o644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+
+ g, err := New(path)
+ if err != nil {
+ t.Fatalf("New: %v", err)
+ }
+
+ cfg := testConfig()
+ if err := g.UpdateField(cfg, testOptional()); err != nil {
+ t.Fatalf("UpdateField: %v", err)
+ }
+
+ reloaded, err := New(path)
+ if err != nil {
+ t.Fatalf("New (reload): %v", err)
+ }
+
+ gotCfg, _ := reloaded.FieldConfig()
+ if gotCfg.FieldLength != cfg.FieldLength {
+ t.Errorf("reloaded field_length = %d, want %d", gotCfg.FieldLength, cfg.FieldLength)
+ }
+
+ models := reloaded.Snapshot().GetGeometry().GetModels()
+ if models.GetStraightTwoPhase().GetAccSlide() != -3.4 {
+ t.Errorf("models.straight_two_phase.acc_slide did not survive the save: %v", models)
+ }
+}
+
+// UpdateField must refuse to overwrite a file whose name matches a protected
+// rulebook preset -- and must not mutate any in-memory state on the way to
+// refusing, since a rejected save that still changed what's held in memory
+// would get broadcast over multicast despite never reaching disk.
+func TestUpdateFieldRefusesToOverwriteAPreset(t *testing.T) {
+ src, err := os.ReadFile("testdata/geometry.yml")
+ if err != nil {
+ t.Fatalf("ReadFile fixture: %v", err)
+ }
+
+ path := filepath.Join(t.TempDir(), "geometry-divB.yml")
+ if err := os.WriteFile(path, src, 0o644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+
+ g, err := New(path)
+ if err != nil {
+ t.Fatalf("New: %v", err)
+ }
+
+ before, err := os.ReadFile(path)
+ if err != nil {
+ t.Fatalf("ReadFile before: %v", err)
+ }
+
+ beforeCfg, _ := g.FieldConfig()
+
+ var readOnly *ReadOnlyError
+ if err := g.UpdateField(testConfig(), testOptional()); !errors.As(err, &readOnly) {
+ t.Fatalf("UpdateField err = %v, want a *ReadOnlyError", err)
+ }
+
+ after, err := os.ReadFile(path)
+ if err != nil {
+ t.Fatalf("ReadFile after: %v", err)
+ }
+
+ if string(before) != string(after) {
+ t.Error("file was modified despite the rejected save")
+ }
+
+ afterCfg, _ := g.FieldConfig()
+ if afterCfg != beforeCfg {
+ t.Errorf("in-memory config changed despite the rejected save: got %+v, want %+v", afterCfg, beforeCfg)
+ }
+}
+
+func TestLoadPresetReadsWithoutAGeometryInstance(t *testing.T) {
+ cfg, opt, err := LoadPreset("testdata/geometry.yml")
+ if err != nil {
+ t.Fatalf("LoadPreset: %v", err)
+ }
+
+ if cfg.FieldLength != 9000 {
+ t.Errorf("field_length = %d, want 9000", cfg.FieldLength)
+ }
+
+ if !opt.Halfway {
+ t.Error("halfway = false, want true (per the fixture)")
+ }
+}
diff --git a/gui/internal/geometry/geometry.go b/gui/internal/geometry/geometry.go
new file mode 100644
index 0000000..f639bf3
--- /dev/null
+++ b/gui/internal/geometry/geometry.go
@@ -0,0 +1,149 @@
+package geometry
+
+import (
+ "context"
+ "log/slog"
+ "sync"
+ "time"
+
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
+ "google.golang.org/protobuf/proto"
+)
+
+// PublishInterval is how often the merged wrapper packet is republished.
+const PublishInterval = time.Second
+
+// Geometry owns the field configuration and per-camera calibrations absorbed
+// from vision processors on the network.
+//
+// proto.Marshal writes to the message's size cache, so this is not a
+// read-without-locking type. mu guards every access to wrapper. encoded is the
+// last marshalled snapshot, kept so Run never has to marshal on its own.
+type Geometry struct {
+ mu sync.Mutex
+ wrapper *vision.SSL_WrapperPacket
+ encoded []byte
+ path string // source file, for UpdateField's save-back
+ optional optionalLines // retained so it can be read back and re-saved
+ extra map[string]any // top-level YAML keys besides optional_field_lines/field (e.g. models), preserved verbatim on save
+}
+
+// New loads geometry.yml at path.
+func New(path string) (*Geometry, error) {
+ wrapper, optional, extra, err := Load(path)
+ if err != nil {
+ return nil, err
+ }
+
+ g := &Geometry{wrapper: wrapper, path: path, optional: optional, extra: extra}
+ if err := g.reencode(); err != nil {
+ return nil, err
+ }
+
+ slog.Info("loaded geometry", "path", path, "calibrations", len(wrapper.GetGeometry().GetCalib()))
+
+ return g, nil
+}
+
+// reencode refreshes encoded. Callers must hold mu.
+func (g *Geometry) reencode() error {
+ data, err := proto.Marshal(g.wrapper)
+ if err != nil {
+ return err
+ }
+
+ g.encoded = data
+
+ return nil
+}
+
+// Encoded returns the last marshalled SSL_WrapperPacket.
+func (g *Geometry) Encoded() []byte {
+ g.mu.Lock()
+ defer g.mu.Unlock()
+
+ return g.encoded
+}
+
+// Snapshot returns a deep copy of the current wrapper packet.
+func (g *Geometry) Snapshot() *vision.SSL_WrapperPacket {
+ g.mu.Lock()
+ defer g.mu.Unlock()
+
+ return proto.Clone(g.wrapper).(*vision.SSL_WrapperPacket)
+}
+
+// Absorb merges one incoming SSL_GeometryData into the held wrapper packet.
+// Unknown camera IDs are appended, unchanged ones are left alone, changed ones
+// are replaced. A calibration missing required fields is rejected before it
+// can touch stored state, so a bad message never desyncs wrapper from encoded.
+func (g *Geometry) Absorb(incoming *vision.SSL_GeometryData) {
+ g.mu.Lock()
+ defer g.mu.Unlock()
+
+ changed := false
+
+ for _, camera := range incoming.GetCalib() {
+ if err := proto.CheckInitialized(camera); err != nil {
+ slog.Warn("dropping incomplete calibration", "cam", camera.GetCameraId(), "err", err)
+ continue
+ }
+
+ if g.mergeCalib(camera) {
+ changed = true
+ }
+ }
+
+ if !changed {
+ return
+ }
+
+ if err := g.reencode(); err != nil {
+ slog.Error("re-encoding wrapper packet", "err", err)
+ }
+}
+
+// mergeCalib applies one camera's calibration, reporting whether it changed
+// anything. Callers must hold mu.
+func (g *Geometry) mergeCalib(camera *vision.SSL_GeometryCameraCalibration) bool {
+ calib := g.wrapper.GetGeometry().GetCalib()
+
+ for i, existing := range calib {
+ if existing.GetCameraId() != camera.GetCameraId() {
+ continue
+ }
+
+ if proto.Equal(existing, camera) {
+ return false
+ }
+
+ calib[i] = proto.Clone(camera).(*vision.SSL_GeometryCameraCalibration)
+ slog.Info("updated camera calibration", "cam", camera.GetCameraId())
+
+ return true
+ }
+
+ g.wrapper.Geometry.Calib = append(calib, proto.Clone(camera).(*vision.SSL_GeometryCameraCalibration))
+ slog.Info("added camera calibration", "cam", camera.GetCameraId())
+
+ return true
+}
+
+// Run republishes via publish once per PublishInterval until ctx is cancelled.
+func (g *Geometry) Run(ctx context.Context, publish func([]byte)) error {
+ return g.run(ctx, PublishInterval, publish)
+}
+
+func (g *Geometry) run(ctx context.Context, interval time.Duration, publish func([]byte)) error {
+ ticker := time.NewTicker(interval)
+ defer ticker.Stop()
+
+ for {
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case <-ticker.C:
+ publish(g.Encoded())
+ }
+ }
+}
diff --git a/gui/internal/geometry/geometry_test.go b/gui/internal/geometry/geometry_test.go
new file mode 100644
index 0000000..9b8f807
--- /dev/null
+++ b/gui/internal/geometry/geometry_test.go
@@ -0,0 +1,198 @@
+package geometry
+
+import (
+ "context"
+ "os"
+ "path/filepath"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
+ "google.golang.org/protobuf/proto"
+)
+
+// testGeometry loads a *copy* of the fixture into a temp dir, never the
+// checked-in testdata/geometry.yml directly -- UpdateField writes back to
+// whatever path it was loaded from, and a test calling it against the shared
+// fixture would silently rewrite a tracked file on every run.
+func testGeometry(t *testing.T) *Geometry {
+ t.Helper()
+
+ src, err := os.ReadFile("testdata/geometry.yml")
+ if err != nil {
+ t.Fatalf("ReadFile fixture: %v", err)
+ }
+
+ path := filepath.Join(t.TempDir(), "geometry.yml")
+ if err := os.WriteFile(path, src, 0o644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+
+ g, err := New(path)
+ if err != nil {
+ t.Fatalf("New: %v", err)
+ }
+
+ return g
+}
+
+// calib builds a fully populated calibration: SSL_GeometryCameraCalibration
+// has a dozen required fields, and an incomplete one is rejected by Absorb.
+func calib(camID uint32, focalLength float32) *vision.SSL_GeometryCameraCalibration {
+ return &vision.SSL_GeometryCameraCalibration{
+ CameraId: proto.Uint32(camID),
+ FocalLength: proto.Float32(focalLength),
+ PrincipalPointX: proto.Float32(0),
+ PrincipalPointY: proto.Float32(0),
+ Distortion: proto.Float32(0),
+ Q0: proto.Float32(0),
+ Q1: proto.Float32(0),
+ Q2: proto.Float32(0),
+ Q3: proto.Float32(1),
+ Tx: proto.Float32(0),
+ Ty: proto.Float32(0),
+ Tz: proto.Float32(5000),
+ }
+}
+
+func TestAbsorbAppendsUnknownCamera(t *testing.T) {
+ g := testGeometry(t)
+
+ g.Absorb(&vision.SSL_GeometryData{Calib: []*vision.SSL_GeometryCameraCalibration{calib(0, 400)}})
+
+ got := g.Snapshot().GetGeometry().GetCalib()
+ if len(got) != 1 || got[0].GetCameraId() != 0 || got[0].GetFocalLength() != 400 {
+ t.Fatalf("calib = %v, want one entry for camera 0", got)
+ }
+}
+
+func TestAbsorbReplacesChangedCamera(t *testing.T) {
+ g := testGeometry(t)
+
+ g.Absorb(&vision.SSL_GeometryData{Calib: []*vision.SSL_GeometryCameraCalibration{calib(0, 400)}})
+ g.Absorb(&vision.SSL_GeometryData{Calib: []*vision.SSL_GeometryCameraCalibration{calib(0, 500)}})
+
+ got := g.Snapshot().GetGeometry().GetCalib()
+ if len(got) != 1 || got[0].GetFocalLength() != 500 {
+ t.Fatalf("calib = %v, want camera 0 updated to 500", got)
+ }
+}
+
+func TestAbsorbLeavesUnchangedCameraAlone(t *testing.T) {
+ g := testGeometry(t)
+
+ g.Absorb(&vision.SSL_GeometryData{Calib: []*vision.SSL_GeometryCameraCalibration{calib(0, 400)}})
+ before := g.Encoded()
+
+ g.Absorb(&vision.SSL_GeometryData{Calib: []*vision.SSL_GeometryCameraCalibration{calib(0, 400)}})
+ after := g.Encoded()
+
+ if string(before) != string(after) {
+ t.Fatalf("encoding changed on a no-op absorb")
+ }
+}
+
+func TestAbsorbHandlesMultipleCameras(t *testing.T) {
+ g := testGeometry(t)
+
+ g.Absorb(&vision.SSL_GeometryData{Calib: []*vision.SSL_GeometryCameraCalibration{calib(0, 400), calib(1, 410)}})
+
+ got := g.Snapshot().GetGeometry().GetCalib()
+ if len(got) != 2 {
+ t.Fatalf("calib = %v, want 2 cameras", got)
+ }
+}
+
+func TestAbsorbRejectsIncompleteCalibration(t *testing.T) {
+ g := testGeometry(t)
+
+ incomplete := &vision.SSL_GeometryCameraCalibration{CameraId: proto.Uint32(0)}
+ g.Absorb(&vision.SSL_GeometryData{Calib: []*vision.SSL_GeometryCameraCalibration{incomplete}})
+
+ if got := g.Snapshot().GetGeometry().GetCalib(); len(got) != 0 {
+ t.Fatalf("calib = %v, want incomplete calibration dropped", got)
+ }
+}
+
+func TestEncodedMatchesSnapshot(t *testing.T) {
+ g := testGeometry(t)
+ g.Absorb(&vision.SSL_GeometryData{Calib: []*vision.SSL_GeometryCameraCalibration{calib(0, 400)}})
+
+ var fromWire vision.SSL_WrapperPacket
+ if err := proto.Unmarshal(g.Encoded(), &fromWire); err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+
+ if !proto.Equal(&fromWire, g.Snapshot()) {
+ t.Fatalf("Encoded() does not round-trip to Snapshot()")
+ }
+}
+
+// Exercises the concurrency contract under -race: Absorb, Encoded and Snapshot
+// from many goroutines at once.
+func TestConcurrentAbsorbAndRead(t *testing.T) {
+ g := testGeometry(t)
+
+ var wg sync.WaitGroup
+
+ for camID := range uint32(8) {
+ wg.Add(1)
+
+ go func() {
+ defer wg.Done()
+
+ for i := range 20 {
+ g.Absorb(&vision.SSL_GeometryData{
+ Calib: []*vision.SSL_GeometryCameraCalibration{calib(camID, float32(400+i))},
+ })
+ }
+ }()
+ }
+
+ for range 4 {
+ wg.Add(1)
+
+ go func() {
+ defer wg.Done()
+
+ for range 50 {
+ _ = g.Encoded()
+ _ = g.Snapshot()
+ }
+ }()
+ }
+
+ wg.Wait()
+
+ if got := len(g.Snapshot().GetGeometry().GetCalib()); got != 8 {
+ t.Fatalf("calib count = %d, want 8", got)
+ }
+}
+
+func TestRunPublishesUntilCancelled(t *testing.T) {
+ g := testGeometry(t)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ published := make(chan []byte, 8)
+
+ done := make(chan error, 1)
+ go func() { done <- g.run(ctx, time.Millisecond, func(b []byte) { published <- b }) }()
+
+ select {
+ case <-published:
+ case <-time.After(time.Second):
+ t.Fatal("Run did not publish before timeout")
+ }
+
+ cancel()
+
+ select {
+ case err := <-done:
+ if err != context.Canceled {
+ t.Fatalf("Run returned %v, want context.Canceled", err)
+ }
+ case <-time.After(time.Second):
+ t.Fatal("Run did not exit after cancel")
+ }
+}
diff --git a/gui/internal/geometry/testdata/geometry.yml b/gui/internal/geometry/testdata/geometry.yml
new file mode 100644
index 0000000..850c64a
--- /dev/null
+++ b/gui/internal/geometry/testdata/geometry.yml
@@ -0,0 +1,23 @@
+# Minimal fixture for geometry package tests. Not a real match config.
+optional_field_lines:
+ goal2goal: true
+ halfway: true
+ centercircle: true
+ penalty: true
+
+field:
+ field_length: 9000
+ field_width: 6000
+ goal_width: 1000
+ goal_depth: 180
+ goal_height: 160
+ penalty_area_depth: 1000
+ penalty_area_width: 2000
+ goal_center_to_penalty_mark: 6000
+ boundary_width: 300
+ boundary_width_goal_line: 300
+ center_circle_radius: 500
+ line_thickness: 10
+ ball_radius: 21.5
+ max_robot_radius: 90.0
+ goal_substitution_area_width: 0
diff --git a/gui/internal/hub/hub.go b/gui/internal/hub/hub.go
new file mode 100644
index 0000000..f557d30
--- /dev/null
+++ b/gui/internal/hub/hub.go
@@ -0,0 +1,71 @@
+// Package hub is an in-process topic pub/sub for the browser-facing
+// WebSocket: Publish pushes JSON-encoded data onto a topic, Subscribe hands
+// back a size-1 channel of it. A slow subscriber sees only the latest value.
+package hub
+
+import "sync"
+
+// Hub fans published data out to subscribers by topic.
+type Hub struct {
+ mu sync.Mutex
+ subs map[string]map[chan []byte]struct{}
+}
+
+// New returns an empty Hub.
+func New() *Hub {
+ return &Hub{subs: make(map[string]map[chan []byte]struct{})}
+}
+
+// Subscribe returns a channel of future values published to topic, and an
+// unsubscribe function the caller must call exactly once when done.
+func (h *Hub) Subscribe(topic string) (<-chan []byte, func()) {
+ ch := make(chan []byte, 1)
+
+ h.mu.Lock()
+ if h.subs[topic] == nil {
+ h.subs[topic] = make(map[chan []byte]struct{})
+ }
+ h.subs[topic][ch] = struct{}{}
+ h.mu.Unlock()
+
+ unsubscribe := func() {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ delete(h.subs[topic], ch)
+ if len(h.subs[topic]) == 0 {
+ delete(h.subs, topic)
+ }
+
+ // Closing under the same lock that removes ch from subs means Publish
+ // can never be mid-send to a channel this is about to close.
+ close(ch)
+ }
+
+ return ch, unsubscribe
+}
+
+// Publish sends data to every current subscriber of topic. A subscriber whose
+// channel is still holding an unread value has that value replaced, not
+// queued -- matching the size-1, drop-stale semantics the rest of the host
+// uses for anything published faster than a slow reader drains it.
+func (h *Hub) Publish(topic string, data []byte) {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ for ch := range h.subs[topic] {
+ select {
+ case ch <- data:
+ default:
+ select {
+ case <-ch:
+ default:
+ }
+
+ select {
+ case ch <- data:
+ default:
+ }
+ }
+ }
+}
diff --git a/gui/internal/hub/hub_test.go b/gui/internal/hub/hub_test.go
new file mode 100644
index 0000000..2e5da76
--- /dev/null
+++ b/gui/internal/hub/hub_test.go
@@ -0,0 +1,144 @@
+package hub
+
+import (
+ "sync"
+ "testing"
+ "time"
+)
+
+func TestPublishToNoSubscribersDoesNotPanic(t *testing.T) {
+ h := New()
+ h.Publish("nobody-listening", []byte("x"))
+}
+
+func TestSubscribeReceivesPublishedValue(t *testing.T) {
+ h := New()
+ ch, unsubscribe := h.Subscribe("geometry")
+ defer unsubscribe()
+
+ h.Publish("geometry", []byte(`{"a":1}`))
+
+ select {
+ case got := <-ch:
+ if string(got) != `{"a":1}` {
+ t.Errorf("got %q", got)
+ }
+ case <-time.After(time.Second):
+ t.Fatal("did not receive published value")
+ }
+}
+
+func TestPublishReachesEverySubscriber(t *testing.T) {
+ h := New()
+ ch1, unsub1 := h.Subscribe("geometry")
+ defer unsub1()
+ ch2, unsub2 := h.Subscribe("geometry")
+ defer unsub2()
+
+ h.Publish("geometry", []byte("v"))
+
+ for _, ch := range []<-chan []byte{ch1, ch2} {
+ select {
+ case <-ch:
+ case <-time.After(time.Second):
+ t.Fatal("a subscriber did not receive the value")
+ }
+ }
+}
+
+func TestPublishIsIsolatedByTopic(t *testing.T) {
+ h := New()
+ ch, unsubscribe := h.Subscribe("a")
+ defer unsubscribe()
+
+ h.Publish("b", []byte("for b"))
+
+ select {
+ case got := <-ch:
+ t.Fatalf("subscriber to a received %q, a publish to b", got)
+ case <-time.After(50 * time.Millisecond):
+ }
+}
+
+// unsubscribe closes the channel, giving a forwarding goroutine reading it a
+// clean stop signal instead of one that just goes quiet.
+func TestUnsubscribeClosesTheChannel(t *testing.T) {
+ h := New()
+ ch, unsubscribe := h.Subscribe("geometry")
+ unsubscribe()
+
+ select {
+ case got, ok := <-ch:
+ if ok {
+ t.Fatalf("channel not closed, received %q", got)
+ }
+ case <-time.After(time.Second):
+ t.Fatal("read from closed channel should not block")
+ }
+}
+
+// A slow subscriber sees only the latest value, matching the pattern used
+// elsewhere in the host (Geometry.Encoded, the Python bus this replaces).
+func TestSlowSubscriberSeesOnlyLatestValue(t *testing.T) {
+ h := New()
+ ch, unsubscribe := h.Subscribe("geometry")
+ defer unsubscribe()
+
+ h.Publish("geometry", []byte("first"))
+ h.Publish("geometry", []byte("second"))
+
+ select {
+ case got := <-ch:
+ if string(got) != "second" {
+ t.Fatalf("got %q, want the latest value only", got)
+ }
+ case <-time.After(time.Second):
+ t.Fatal("did not receive a value")
+ }
+
+ select {
+ case got := <-ch:
+ t.Fatalf("received a second value %q, want the dropped first one gone for good", got)
+ case <-time.After(50 * time.Millisecond):
+ }
+}
+
+func TestConcurrentSubscribePublishUnsubscribe(t *testing.T) {
+ h := New()
+
+ var wg sync.WaitGroup
+
+ for range 8 {
+ wg.Add(1)
+
+ go func() {
+ defer wg.Done()
+
+ for range 50 {
+ ch, unsubscribe := h.Subscribe("geometry")
+ h.Publish("geometry", []byte("v"))
+
+ select {
+ case <-ch:
+ default:
+ }
+
+ unsubscribe()
+ }
+ }()
+ }
+
+ for range 4 {
+ wg.Add(1)
+
+ go func() {
+ defer wg.Done()
+
+ for range 50 {
+ h.Publish("geometry", []byte("v"))
+ }
+ }()
+ }
+
+ wg.Wait()
+}
diff --git a/gui/internal/hub/websocket.go b/gui/internal/hub/websocket.go
new file mode 100644
index 0000000..fd112e6
--- /dev/null
+++ b/gui/internal/hub/websocket.go
@@ -0,0 +1,163 @@
+package hub
+
+import (
+ "encoding/json"
+ "log/slog"
+ "net/http"
+ "sync"
+ "time"
+
+ "github.com/gorilla/websocket"
+)
+
+const (
+ pongWait = 60 * time.Second
+ pingPeriod = (pongWait * 9) / 10
+ writeWait = 10 * time.Second
+)
+
+var upgrader = websocket.Upgrader{}
+
+// clientMessage is what a browser sends: {"action": "subscribe"|"unsubscribe", "topic": "..."}.
+type clientMessage struct {
+ Action string `json:"action"`
+ Topic string `json:"topic"`
+}
+
+// serverMessage is what a browser receives: {"topic": "...", "data": }.
+// Data is a RawMessage so an already-JSON-encoded publish is embedded as-is,
+// not re-encoded as a string.
+type serverMessage struct {
+ Topic string `json:"topic"`
+ Data json.RawMessage `json:"data"`
+}
+
+// HandleWebSocket upgrades the request and lets the client subscribe to and
+// unsubscribe from hub topics for the life of the connection.
+func HandleWebSocket(h *Hub) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ conn, err := upgrader.Upgrade(w, r, nil)
+ if err != nil {
+ slog.Warn("websocket upgrade failed", "err", err)
+ return
+ }
+
+ serveConnection(h, conn)
+ }
+}
+
+// serveConnection owns one connection end to end: it reads client messages
+// itself, and runs exactly one other goroutine (writePump) that is the only
+// caller of conn.WriteMessage -- concurrent writers on one *websocket.Conn is
+// a data race, not just a bad idea.
+func serveConnection(h *Hub, conn *websocket.Conn) {
+ defer conn.Close()
+
+ outbound := make(chan []byte, 16)
+ unsubscribers := make(map[string]func())
+
+ var topics sync.WaitGroup
+
+ writeDone := make(chan struct{})
+ go func() {
+ writePump(conn, outbound)
+ close(writeDone)
+ }()
+
+ defer func() {
+ for _, unsubscribe := range unsubscribers {
+ unsubscribe()
+ }
+ // Every forwardTopic loop above now exits (its hub channel just
+ // closed), so nothing sends to outbound after this.
+ topics.Wait()
+ close(outbound)
+ <-writeDone
+ }()
+
+ conn.SetReadDeadline(time.Now().Add(pongWait))
+ conn.SetPongHandler(func(string) error {
+ return conn.SetReadDeadline(time.Now().Add(pongWait))
+ })
+
+ for {
+ var msg clientMessage
+ if err := conn.ReadJSON(&msg); err != nil {
+ return
+ }
+
+ switch msg.Action {
+ case "subscribe":
+ if _, already := unsubscribers[msg.Topic]; already {
+ continue
+ }
+
+ ch, unsubscribe := h.Subscribe(msg.Topic)
+ unsubscribers[msg.Topic] = unsubscribe
+
+ topics.Add(1)
+
+ go func(topic string, ch <-chan []byte) {
+ defer topics.Done()
+ forwardTopic(topic, ch, outbound)
+ }(msg.Topic, ch)
+ case "unsubscribe":
+ if unsubscribe, ok := unsubscribers[msg.Topic]; ok {
+ unsubscribe()
+ delete(unsubscribers, msg.Topic)
+ }
+ default:
+ slog.Warn("unknown websocket action", "action", msg.Action)
+ }
+ }
+}
+
+// forwardTopic relays one hub topic's values onto outbound until the topic is
+// unsubscribed (the hub channel closes).
+func forwardTopic(topic string, ch <-chan []byte, outbound chan<- []byte) {
+ for data := range ch {
+ envelope, err := json.Marshal(serverMessage{Topic: topic, Data: data})
+ if err != nil {
+ slog.Error("marshalling websocket envelope", "topic", topic, "err", err)
+ continue
+ }
+
+ select {
+ case outbound <- envelope:
+ default:
+ // This connection is behind; drop rather than block every other
+ // topic (and every other connection sharing the hub) on one slow
+ // client.
+ }
+ }
+}
+
+// writePump is the sole writer to conn: outbound messages plus a periodic
+// ping, so a client that vanished without a clean close (dead wifi, closed
+// laptop lid) is detected and this connection's goroutines get cleaned up
+// instead of leaking for the life of the process.
+func writePump(conn *websocket.Conn, outbound <-chan []byte) {
+ ticker := time.NewTicker(pingPeriod)
+ defer ticker.Stop()
+
+ for {
+ select {
+ case data, ok := <-outbound:
+ if !ok {
+ return
+ }
+
+ conn.SetWriteDeadline(time.Now().Add(writeWait))
+
+ if err := conn.WriteMessage(websocket.TextMessage, data); err != nil {
+ return
+ }
+ case <-ticker.C:
+ conn.SetWriteDeadline(time.Now().Add(writeWait))
+
+ if err := conn.WriteMessage(websocket.PingMessage, nil); err != nil {
+ return
+ }
+ }
+ }
+}
diff --git a/gui/internal/hub/websocket_test.go b/gui/internal/hub/websocket_test.go
new file mode 100644
index 0000000..96d5e4f
--- /dev/null
+++ b/gui/internal/hub/websocket_test.go
@@ -0,0 +1,118 @@
+package hub
+
+import (
+ "encoding/json"
+ "net/http/httptest"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/gorilla/websocket"
+)
+
+// dialTestServer starts an httptest server on HandleWebSocket(h) and returns a
+// connected client plus a closer.
+func dialTestServer(t *testing.T, h *Hub) *websocket.Conn {
+ t.Helper()
+
+ srv := httptest.NewServer(HandleWebSocket(h))
+ t.Cleanup(srv.Close)
+
+ wsURL := "ws" + strings.TrimPrefix(srv.URL, "http")
+
+ conn, _, err := websocket.DefaultDialer.Dial(wsURL, nil)
+ if err != nil {
+ t.Fatalf("Dial: %v", err)
+ }
+
+ t.Cleanup(func() { conn.Close() })
+
+ return conn
+}
+
+func readEnvelope(t *testing.T, conn *websocket.Conn) serverMessage {
+ t.Helper()
+
+ conn.SetReadDeadline(time.Now().Add(2 * time.Second))
+
+ var msg serverMessage
+ if err := conn.ReadJSON(&msg); err != nil {
+ t.Fatalf("ReadJSON: %v", err)
+ }
+
+ return msg
+}
+
+func TestWebSocketDeliversPublishedData(t *testing.T) {
+ h := New()
+ conn := dialTestServer(t, h)
+
+ if err := conn.WriteJSON(clientMessage{Action: "subscribe", Topic: "geometry"}); err != nil {
+ t.Fatalf("WriteJSON: %v", err)
+ }
+
+ // Subscribe is handled by the connection's read loop; give it a moment to
+ // register with the hub before publishing, or the publish can race ahead
+ // of it.
+ time.Sleep(50 * time.Millisecond)
+
+ h.Publish("geometry", []byte(`{"fieldLength":9000}`))
+
+ got := readEnvelope(t, conn)
+ if got.Topic != "geometry" {
+ t.Errorf("topic = %q, want geometry", got.Topic)
+ }
+
+ if string(got.Data) != `{"fieldLength":9000}` {
+ t.Errorf("data = %s, want the published bytes unchanged", got.Data)
+ }
+}
+
+func TestWebSocketUnsubscribeStopsDelivery(t *testing.T) {
+ h := New()
+ conn := dialTestServer(t, h)
+
+ if err := conn.WriteJSON(clientMessage{Action: "subscribe", Topic: "geometry"}); err != nil {
+ t.Fatalf("WriteJSON: %v", err)
+ }
+
+ time.Sleep(50 * time.Millisecond)
+
+ if err := conn.WriteJSON(clientMessage{Action: "unsubscribe", Topic: "geometry"}); err != nil {
+ t.Fatalf("WriteJSON: %v", err)
+ }
+
+ time.Sleep(50 * time.Millisecond)
+
+ h.Publish("geometry", []byte(`{"x":1}`))
+
+ conn.SetReadDeadline(time.Now().Add(200 * time.Millisecond))
+
+ var msg json.RawMessage
+ if err := conn.ReadJSON(&msg); err == nil {
+ t.Fatalf("received a message after unsubscribe: %s", msg)
+ }
+}
+
+func TestWebSocketTwoConnectionsOnSameTopic(t *testing.T) {
+ h := New()
+ a := dialTestServer(t, h)
+ b := dialTestServer(t, h)
+
+ for _, conn := range []*websocket.Conn{a, b} {
+ if err := conn.WriteJSON(clientMessage{Action: "subscribe", Topic: "geometry"}); err != nil {
+ t.Fatalf("WriteJSON: %v", err)
+ }
+ }
+
+ time.Sleep(50 * time.Millisecond)
+
+ h.Publish("geometry", []byte(`{"x":1}`))
+
+ for _, conn := range []*websocket.Conn{a, b} {
+ got := readEnvelope(t, conn)
+ if got.Topic != "geometry" {
+ t.Errorf("topic = %q, want geometry", got.Topic)
+ }
+ }
+}
diff --git a/gui/internal/multicast/bridge.go b/gui/internal/multicast/bridge.go
new file mode 100644
index 0000000..0c7a1da
--- /dev/null
+++ b/gui/internal/multicast/bridge.go
@@ -0,0 +1,70 @@
+// Package multicast wires the SSL vision multicast group to the geometry
+// service: inbound SSL_WrapperPacket.geometry is handed to an absorb callback,
+// and outbound bytes are sent back onto the same group.
+package multicast
+
+import (
+ "context"
+ "log/slog"
+ "net"
+
+ "github.com/RoboCup-SSL/ssl-go-tools/pkg/sslnet"
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
+ "google.golang.org/protobuf/proto"
+)
+
+// Bridge pairs a receiver and a sender on one multicast address. Our own
+// outbound packets loop back to the receiver (multicast loopback is on by
+// default); Absorb is idempotent, so this is harmless rather than special-cased.
+type Bridge struct {
+ server *sslnet.MulticastServer
+ client *sslnet.UdpClient
+}
+
+// New prepares a bridge on address (e.g. "224.5.23.2:10006"). skipInterfaces
+// excludes named network interfaces from both receive and send.
+func New(address string, skipInterfaces []string, verbose bool) *Bridge {
+ server := sslnet.NewMulticastServer(address)
+ server.SkipInterfaces = skipInterfaces
+ server.Verbose = verbose
+
+ client := sslnet.NewUdpClient(address, "")
+
+ return &Bridge{server: server, client: client}
+}
+
+// Run starts receiving until ctx is cancelled, calling absorb with the
+// geometry from every wrapper packet that carries one.
+func (b *Bridge) Run(ctx context.Context, absorb func(*vision.SSL_GeometryData)) error {
+ b.server.Consumer = func(data []byte, _ *net.UDPAddr) {
+ b.handleDatagram(data, absorb)
+ }
+
+ b.server.Start()
+ b.client.Start()
+
+ <-ctx.Done()
+
+ b.server.Stop()
+ b.client.Stop()
+
+ return ctx.Err()
+}
+
+// handleDatagram parses one datagram and, if it carries geometry, calls absorb.
+func (b *Bridge) handleDatagram(data []byte, absorb func(*vision.SSL_GeometryData)) {
+ var packet vision.SSL_WrapperPacket
+ if err := proto.Unmarshal(data, &packet); err != nil {
+ slog.Warn("dropping malformed wrapper packet", "err", err)
+ return
+ }
+
+ if geometry := packet.GetGeometry(); geometry != nil {
+ absorb(geometry)
+ }
+}
+
+// Send publishes data onto the multicast group.
+func (b *Bridge) Send(data []byte) {
+ b.client.Send(data)
+}
diff --git a/gui/internal/multicast/bridge_test.go b/gui/internal/multicast/bridge_test.go
new file mode 100644
index 0000000..8b7be4d
--- /dev/null
+++ b/gui/internal/multicast/bridge_test.go
@@ -0,0 +1,70 @@
+package multicast
+
+import (
+ "testing"
+
+ "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
+ "google.golang.org/protobuf/proto"
+)
+
+// handleDatagram is exercised directly rather than through Run/Start, so these
+// tests need no real socket -- useful in sandboxes where multicast join may be
+// blocked.
+
+func TestHandleDatagramCallsAbsorbForGeometry(t *testing.T) {
+ b := New("224.5.23.2:10006", nil, false)
+
+ // SSL_GeometryData.field is a required proto2 field, so Marshal needs a
+ // complete SSL_GeometryFieldSize even though calib is what this test cares
+ // about; calib itself has 12 required fields per entry and is left empty.
+ packet := &vision.SSL_WrapperPacket{
+ Geometry: &vision.SSL_GeometryData{
+ Field: &vision.SSL_GeometryFieldSize{
+ FieldLength: proto.Int32(9000),
+ FieldWidth: proto.Int32(6000),
+ GoalWidth: proto.Int32(1000),
+ GoalDepth: proto.Int32(180),
+ BoundaryWidth: proto.Int32(300),
+ },
+ },
+ }
+
+ data, err := proto.Marshal(packet)
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+
+ var got *vision.SSL_GeometryData
+ b.handleDatagram(data, func(g *vision.SSL_GeometryData) { got = g })
+
+ if got == nil || got.GetField().GetFieldLength() != 9000 {
+ t.Fatalf("absorb called with %v, want field_length 9000", got)
+ }
+}
+
+func TestHandleDatagramIgnoresPacketWithoutGeometry(t *testing.T) {
+ b := New("224.5.23.2:10006", nil, false)
+
+ data, err := proto.Marshal(&vision.SSL_WrapperPacket{})
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+
+ called := false
+ b.handleDatagram(data, func(*vision.SSL_GeometryData) { called = true })
+
+ if called {
+ t.Fatal("absorb called for a packet with no geometry")
+ }
+}
+
+func TestHandleDatagramDropsMalformedData(t *testing.T) {
+ b := New("224.5.23.2:10006", nil, false)
+
+ called := false
+ b.handleDatagram([]byte("not a protobuf message"), func(*vision.SSL_GeometryData) { called = true })
+
+ if called {
+ t.Fatal("absorb called for malformed data")
+ }
+}
diff --git a/gui/internal/snapshot/snapshot.go b/gui/internal/snapshot/snapshot.go
new file mode 100644
index 0000000..a770774
--- /dev/null
+++ b/gui/internal/snapshot/snapshot.go
@@ -0,0 +1,151 @@
+// Package snapshot serves the debug images the C++ vision processor writes to
+// disk as ..{jpg,png}, via tmp-then-rename so reads never see a
+// torn frame.
+//
+// This assumes the Go host and the vision processor share a filesystem, which
+// only holds for a single-host setup; it does not work for a remote instance.
+package snapshot
+
+import (
+ "encoding/json"
+ "log/slog"
+ "net/http"
+ "os"
+ "path/filepath"
+ "regexp"
+ "sort"
+)
+
+// filename matches "..", e.g. "0.raw.jpg". Both captured
+// groups are also validated against this same character set before use in a
+// filepath.Glob, since Glob treats *, ?, and [ as metacharacters and an
+// unvalidated view name could turn a lookup into a directory listing.
+var filename = regexp.MustCompile(`^(\d+)\.([a-zA-Z0-9_-]+)\.(?:jpg|jpeg|png)$`)
+
+// Entry identifies one available snapshot. Field names match what the
+// frontend already expects.
+type Entry struct {
+ CamID string `json:"cam_id"`
+ View string `json:"view"`
+}
+
+// HandleList serves the set of snapshots currently on disk in dir.
+func HandleList(dir string) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ entries, err := list(dir)
+ if err != nil {
+ slog.Error("listing snapshots", "dir", dir, "err", err)
+ http.Error(w, "internal error", http.StatusInternalServerError)
+
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+
+ if err := json.NewEncoder(w).Encode(entries); err != nil {
+ slog.Error("writing snapshot list response", "err", err)
+ }
+ }
+}
+
+func list(dir string) ([]Entry, error) {
+ files, err := os.ReadDir(dir)
+ if os.IsNotExist(err) {
+ return []Entry{}, nil
+ }
+
+ if err != nil {
+ return nil, err
+ }
+
+ seen := make(map[Entry]struct{})
+
+ for _, f := range files {
+ m := filename.FindStringSubmatch(f.Name())
+ if m == nil {
+ continue
+ }
+
+ seen[Entry{CamID: m[1], View: m[2]}] = struct{}{}
+ }
+
+ entries := make([]Entry, 0, len(seen))
+ for e := range seen {
+ entries = append(entries, e)
+ }
+
+ // os.ReadDir order is directory-entry order, not usefully sorted for a UI,
+ // and map iteration is randomised on top of that -- fix an order so the
+ // grid does not reshuffle itself every 5s poll.
+ sort.Slice(entries, func(i, j int) bool {
+ if entries[i].CamID != entries[j].CamID {
+ return entries[i].CamID < entries[j].CamID
+ }
+
+ return entries[i].View < entries[j].View
+ })
+
+ return entries, nil
+}
+
+// validSegment matches one path-value component of a snapshot request: digits
+// for a camera id, or the same character set the filename itself uses for a
+// view name.
+var validSegment = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)
+
+// HandleGet serves the most recently written {camID}.{view}.* file in dir.
+func HandleGet(dir string) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ camID := r.PathValue("camID")
+ view := r.PathValue("view")
+
+ if !validSegment.MatchString(camID) || !validSegment.MatchString(view) {
+ http.NotFound(w, r)
+
+ return
+ }
+
+ path, err := latest(dir, camID, view)
+ if err != nil {
+ slog.Error("finding snapshot", "cam", camID, "view", view, "err", err)
+ http.Error(w, "internal error", http.StatusInternalServerError)
+
+ return
+ }
+
+ if path == "" {
+ http.NotFound(w, r)
+
+ return
+ }
+
+ http.ServeFile(w, r, path)
+ }
+}
+
+// latest returns the most recently modified file matching dir/camID.view.*, or
+// "" if none exists.
+func latest(dir, camID, view string) (string, error) {
+ matches, err := filepath.Glob(filepath.Join(dir, camID+"."+view+".*"))
+ if err != nil {
+ return "", err
+ }
+
+ var (
+ newest string
+ newestTime int64
+ )
+
+ for _, path := range matches {
+ info, err := os.Stat(path)
+ if err != nil {
+ continue
+ }
+
+ if t := info.ModTime().UnixNano(); t > newestTime {
+ newest, newestTime = path, t
+ }
+ }
+
+ return newest, nil
+}
diff --git a/gui/internal/snapshot/snapshot_test.go b/gui/internal/snapshot/snapshot_test.go
new file mode 100644
index 0000000..bcb188c
--- /dev/null
+++ b/gui/internal/snapshot/snapshot_test.go
@@ -0,0 +1,160 @@
+package snapshot
+
+import (
+ "encoding/json"
+ "net/http"
+ "net/http/httptest"
+ "os"
+ "path/filepath"
+ "testing"
+ "time"
+)
+
+func writeFile(t *testing.T, dir, name string) {
+ t.Helper()
+
+ if err := os.WriteFile(filepath.Join(dir, name), []byte(name), 0o644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+}
+
+func TestListReturnsEmptyForMissingDir(t *testing.T) {
+ entries, err := list(filepath.Join(t.TempDir(), "does-not-exist"))
+ if err != nil {
+ t.Fatalf("list: %v", err)
+ }
+
+ if len(entries) != 0 {
+ t.Errorf("entries = %v, want empty", entries)
+ }
+}
+
+func TestListFindsMatchingFilesAndSkipsOthers(t *testing.T) {
+ dir := t.TempDir()
+ writeFile(t, dir, "0.raw.jpg")
+ writeFile(t, dir, "1.calib.png")
+ writeFile(t, dir, "not-a-snapshot.txt")
+ writeFile(t, dir, "0.calib.json") // legacy / non-image extension
+
+ entries, err := list(dir)
+ if err != nil {
+ t.Fatalf("list: %v", err)
+ }
+
+ want := []Entry{{CamID: "0", View: "raw"}, {CamID: "1", View: "calib"}}
+ if len(entries) != len(want) {
+ t.Fatalf("entries = %v, want %v", entries, want)
+ }
+
+ for i, e := range want {
+ if entries[i] != e {
+ t.Errorf("entries[%d] = %v, want %v", i, entries[i], e)
+ }
+ }
+}
+
+func TestListDedupesSameCameraAndView(t *testing.T) {
+ dir := t.TempDir()
+ writeFile(t, dir, "0.raw.jpg")
+ writeFile(t, dir, "0.raw.png")
+
+ entries, err := list(dir)
+ if err != nil {
+ t.Fatalf("list: %v", err)
+ }
+
+ if len(entries) != 1 {
+ t.Fatalf("entries = %v, want a single deduped entry", entries)
+ }
+}
+
+func TestHandleListServesJSON(t *testing.T) {
+ dir := t.TempDir()
+ writeFile(t, dir, "0.raw.jpg")
+
+ rec := httptest.NewRecorder()
+ HandleList(dir).ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/api/snapshots", nil))
+
+ if rec.Code != http.StatusOK {
+ t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
+ }
+
+ var got []Entry
+ if err := json.Unmarshal(rec.Body.Bytes(), &got); err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+
+ if len(got) != 1 || got[0] != (Entry{CamID: "0", View: "raw"}) {
+ t.Errorf("got %v", got)
+ }
+}
+
+func snapshotMux(dir string) http.Handler {
+ mux := http.NewServeMux()
+ mux.Handle("GET /api/snapshot/{camID}/{view}", HandleGet(dir))
+
+ return mux
+}
+
+func TestHandleGetServesTheFile(t *testing.T) {
+ dir := t.TempDir()
+ writeFile(t, dir, "0.raw.jpg")
+
+ rec := httptest.NewRecorder()
+ snapshotMux(dir).ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/api/snapshot/0/raw", nil))
+
+ if rec.Code != http.StatusOK {
+ t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
+ }
+
+ if rec.Body.String() != "0.raw.jpg" {
+ t.Errorf("body = %q, want file contents", rec.Body.String())
+ }
+}
+
+func TestHandleGetServesTheMostRecentlyModifiedMatch(t *testing.T) {
+ dir := t.TempDir()
+ writeFile(t, dir, "0.raw.jpg")
+
+ oldPath := filepath.Join(dir, "0.raw.jpg")
+ if err := os.Chtimes(oldPath, time.Now().Add(-time.Hour), time.Now().Add(-time.Hour)); err != nil {
+ t.Fatalf("Chtimes: %v", err)
+ }
+
+ writeFile(t, dir, "0.raw.png") // written just now, newer
+
+ rec := httptest.NewRecorder()
+ snapshotMux(dir).ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/api/snapshot/0/raw", nil))
+
+ if rec.Body.String() != "0.raw.png" {
+ t.Errorf("body = %q, want the newer file", rec.Body.String())
+ }
+}
+
+func TestHandleGetReturns404ForNoMatch(t *testing.T) {
+ dir := t.TempDir()
+
+ rec := httptest.NewRecorder()
+ snapshotMux(dir).ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/api/snapshot/9/raw", nil))
+
+ if rec.Code != http.StatusNotFound {
+ t.Errorf("status = %d, want %d", rec.Code, http.StatusNotFound)
+ }
+}
+
+// A view name containing glob metacharacters must not turn into a directory
+// listing, and must not escape dir via a crafted segment.
+func TestHandleGetRejectsUnsafeSegments(t *testing.T) {
+ dir := t.TempDir()
+ writeFile(t, dir, "0.raw.jpg")
+
+ for _, view := range []string{"*", "..", "raw/../../etc"} {
+ req := httptest.NewRequest(http.MethodGet, "/api/snapshot/0/"+view, nil)
+ rec := httptest.NewRecorder()
+ snapshotMux(dir).ServeHTTP(rec, req)
+
+ if rec.Code == http.StatusOK {
+ t.Errorf("view=%q: status = 200, want rejected", view)
+ }
+ }
+}
diff --git a/pyproject.toml b/pyproject.toml
deleted file mode 100644
index f52c3e2..0000000
--- a/pyproject.toml
+++ /dev/null
@@ -1,30 +0,0 @@
-[project]
-name = "vision-wrapper"
-version = "0.1.0"
-requires-python = ">=3.12"
-dependencies = [
- "aiohttp>=3.10",
- "protobuf>=7.34.1",
- "pyyaml>=6.0.3",
-]
-
-[dependency-groups]
-dev = [
- "mypy>=2.0.0",
- "pre-commit>=4.6.0",
- "ruff>=0.15.12",
- "types-protobuf>=7.34.1.20260503",
- "types-pyyaml>=6.0.12.20260408",
-]
-
-[tool.mypy]
-files = ["wrapper_backend"]
-exclude = ["wrapper_backend/proto/"]
-mypy_path = "wrapper_backend"
-
-[[tool.mypy.overrides]]
-module = "python_bindings"
-ignore_missing_imports = true
-
-[tool.ruff]
-src = ["wrapper_backend"]
diff --git a/start_wrapper.sh b/start_wrapper.sh
deleted file mode 100755
index bd5e7dc..0000000
--- a/start_wrapper.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-cd "$(dirname "$0")"
-exec uv run python -m wrapper_backend "${1:-geometry-divB.yml}" "${@:2}"
diff --git a/uv.lock b/uv.lock
deleted file mode 100644
index e936951..0000000
--- a/uv.lock
+++ /dev/null
@@ -1,924 +0,0 @@
-version = 1
-revision = 3
-requires-python = ">=3.12"
-resolution-markers = [
- "python_full_version >= '3.15'",
- "python_full_version < '3.15'",
-]
-
-[[package]]
-name = "aiohappyeyeballs"
-version = "2.6.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" },
-]
-
-[[package]]
-name = "aiohttp"
-version = "3.13.5"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "aiohappyeyeballs" },
- { name = "aiosignal" },
- { name = "attrs" },
- { name = "frozenlist" },
- { name = "multidict" },
- { name = "propcache" },
- { name = "yarl" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/77/9a/152096d4808df8e4268befa55fba462f440f14beab85e8ad9bf990516918/aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1", size = 7858271, upload-time = "2026-03-31T22:01:03.343Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/be/6f/353954c29e7dcce7cf00280a02c75f30e133c00793c7a2ed3776d7b2f426/aiohttp-3.13.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:023ecba036ddd840b0b19bf195bfae970083fd7024ce1ac22e9bba90464620e9", size = 748876, upload-time = "2026-03-31T21:57:36.319Z" },
- { url = "https://files.pythonhosted.org/packages/f5/1b/428a7c64687b3b2e9cd293186695affc0e1e54a445d0361743b231f11066/aiohttp-3.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:15c933ad7920b7d9a20de151efcd05a6e38302cbf0e10c9b2acb9a42210a2416", size = 499557, upload-time = "2026-03-31T21:57:38.236Z" },
- { url = "https://files.pythonhosted.org/packages/29/47/7be41556bfbb6917069d6a6634bb7dd5e163ba445b783a90d40f5ac7e3a7/aiohttp-3.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab2899f9fa2f9f741896ebb6fa07c4c883bfa5c7f2ddd8cf2aafa86fa981b2d2", size = 500258, upload-time = "2026-03-31T21:57:39.923Z" },
- { url = "https://files.pythonhosted.org/packages/67/84/c9ecc5828cb0b3695856c07c0a6817a99d51e2473400f705275a2b3d9239/aiohttp-3.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60eaa2d440cd4707696b52e40ed3e2b0f73f65be07fd0ef23b6b539c9c0b0b4", size = 1749199, upload-time = "2026-03-31T21:57:41.938Z" },
- { url = "https://files.pythonhosted.org/packages/f0/d3/3c6d610e66b495657622edb6ae7c7fd31b2e9086b4ec50b47897ad6042a9/aiohttp-3.13.5-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:55b3bdd3292283295774ab585160c4004f4f2f203946997f49aac032c84649e9", size = 1721013, upload-time = "2026-03-31T21:57:43.904Z" },
- { url = "https://files.pythonhosted.org/packages/49/a0/24409c12217456df0bae7babe3b014e460b0b38a8e60753d6cb339f6556d/aiohttp-3.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c2b2355dc094e5f7d45a7bb262fe7207aa0460b37a0d87027dcf21b5d890e7d5", size = 1781501, upload-time = "2026-03-31T21:57:46.285Z" },
- { url = "https://files.pythonhosted.org/packages/98/9d/b65ec649adc5bccc008b0957a9a9c691070aeac4e41cea18559fef49958b/aiohttp-3.13.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b38765950832f7d728297689ad78f5f2cf79ff82487131c4d26fe6ceecdc5f8e", size = 1878981, upload-time = "2026-03-31T21:57:48.734Z" },
- { url = "https://files.pythonhosted.org/packages/57/d8/8d44036d7eb7b6a8ec4c5494ea0c8c8b94fbc0ed3991c1a7adf230df03bf/aiohttp-3.13.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b18f31b80d5a33661e08c89e202edabf1986e9b49c42b4504371daeaa11b47c1", size = 1767934, upload-time = "2026-03-31T21:57:51.171Z" },
- { url = "https://files.pythonhosted.org/packages/31/04/d3f8211f273356f158e3464e9e45484d3fb8c4ce5eb2f6fe9405c3273983/aiohttp-3.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:33add2463dde55c4f2d9635c6ab33ce154e5ecf322bd26d09af95c5f81cfa286", size = 1566671, upload-time = "2026-03-31T21:57:53.326Z" },
- { url = "https://files.pythonhosted.org/packages/41/db/073e4ebe00b78e2dfcacff734291651729a62953b48933d765dc513bf798/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:327cc432fdf1356fb4fbc6fe833ad4e9f6aacb71a8acaa5f1855e4b25910e4a9", size = 1705219, upload-time = "2026-03-31T21:57:55.385Z" },
- { url = "https://files.pythonhosted.org/packages/48/45/7dfba71a2f9fd97b15c95c06819de7eb38113d2cdb6319669195a7d64270/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7c35b0bf0b48a70b4cb4fc5d7bed9b932532728e124874355de1a0af8ec4bc88", size = 1743049, upload-time = "2026-03-31T21:57:57.341Z" },
- { url = "https://files.pythonhosted.org/packages/18/71/901db0061e0f717d226386a7f471bb59b19566f2cae5f0d93874b017271f/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:df23d57718f24badef8656c49743e11a89fd6f5358fa8a7b96e728fda2abf7d3", size = 1749557, upload-time = "2026-03-31T21:57:59.626Z" },
- { url = "https://files.pythonhosted.org/packages/08/d5/41eebd16066e59cd43728fe74bce953d7402f2b4ddfdfef2c0e9f17ca274/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:02e048037a6501a5ec1f6fc9736135aec6eb8a004ce48838cb951c515f32c80b", size = 1558931, upload-time = "2026-03-31T21:58:01.972Z" },
- { url = "https://files.pythonhosted.org/packages/30/e6/4a799798bf05740e66c3a1161079bda7a3dd8e22ca392481d7a7f9af82a6/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31cebae8b26f8a615d2b546fee45d5ffb76852ae6450e2a03f42c9102260d6fe", size = 1774125, upload-time = "2026-03-31T21:58:04.007Z" },
- { url = "https://files.pythonhosted.org/packages/84/63/7749337c90f92bc2cb18f9560d67aa6258c7060d1397d21529b8004fcf6f/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:888e78eb5ca55a615d285c3c09a7a91b42e9dd6fc699b166ebd5dee87c9ccf14", size = 1732427, upload-time = "2026-03-31T21:58:06.337Z" },
- { url = "https://files.pythonhosted.org/packages/98/de/cf2f44ff98d307e72fb97d5f5bbae3bfcb442f0ea9790c0bf5c5c2331404/aiohttp-3.13.5-cp312-cp312-win32.whl", hash = "sha256:8bd3ec6376e68a41f9f95f5ed170e2fcf22d4eb27a1f8cb361d0508f6e0557f3", size = 433534, upload-time = "2026-03-31T21:58:08.712Z" },
- { url = "https://files.pythonhosted.org/packages/aa/ca/eadf6f9c8fa5e31d40993e3db153fb5ed0b11008ad5d9de98a95045bed84/aiohttp-3.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:110e448e02c729bcebb18c60b9214a87ba33bac4a9fa5e9a5f139938b56c6cb1", size = 460446, upload-time = "2026-03-31T21:58:10.945Z" },
- { url = "https://files.pythonhosted.org/packages/78/e9/d76bf503005709e390122d34e15256b88f7008e246c4bdbe915cd4f1adce/aiohttp-3.13.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5029cc80718bbd545123cd8fe5d15025eccaaaace5d0eeec6bd556ad6163d61", size = 742930, upload-time = "2026-03-31T21:58:13.155Z" },
- { url = "https://files.pythonhosted.org/packages/57/00/4b7b70223deaebd9bb85984d01a764b0d7bd6526fcdc73cca83bcbe7243e/aiohttp-3.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4bb6bf5811620003614076bdc807ef3b5e38244f9d25ca5fe888eaccea2a9832", size = 496927, upload-time = "2026-03-31T21:58:15.073Z" },
- { url = "https://files.pythonhosted.org/packages/9c/f5/0fb20fb49f8efdcdce6cd8127604ad2c503e754a8f139f5e02b01626523f/aiohttp-3.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a84792f8631bf5a94e52d9cc881c0b824ab42717165a5579c760b830d9392ac9", size = 497141, upload-time = "2026-03-31T21:58:17.009Z" },
- { url = "https://files.pythonhosted.org/packages/3b/86/b7c870053e36a94e8951b803cb5b909bfbc9b90ca941527f5fcafbf6b0fa/aiohttp-3.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:57653eac22c6a4c13eb22ecf4d673d64a12f266e72785ab1c8b8e5940d0e8090", size = 1732476, upload-time = "2026-03-31T21:58:18.925Z" },
- { url = "https://files.pythonhosted.org/packages/b5/e5/4e161f84f98d80c03a238671b4136e6530453d65262867d989bbe78244d0/aiohttp-3.13.5-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5e5f7debc7a57af53fdf5c5009f9391d9f4c12867049d509bf7bb164a6e295b", size = 1706507, upload-time = "2026-03-31T21:58:21.094Z" },
- { url = "https://files.pythonhosted.org/packages/d4/56/ea11a9f01518bd5a2a2fcee869d248c4b8a0cfa0bb13401574fa31adf4d4/aiohttp-3.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c719f65bebcdf6716f10e9eff80d27567f7892d8988c06de12bbbd39307c6e3a", size = 1773465, upload-time = "2026-03-31T21:58:23.159Z" },
- { url = "https://files.pythonhosted.org/packages/eb/40/333ca27fb74b0383f17c90570c748f7582501507307350a79d9f9f3c6eb1/aiohttp-3.13.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d97f93fdae594d886c5a866636397e2bcab146fd7a132fd6bb9ce182224452f8", size = 1873523, upload-time = "2026-03-31T21:58:25.59Z" },
- { url = "https://files.pythonhosted.org/packages/f0/d2/e2f77eef1acb7111405433c707dc735e63f67a56e176e72e9e7a2cd3f493/aiohttp-3.13.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3df334e39d4c2f899a914f1dba283c1aadc311790733f705182998c6f7cae665", size = 1754113, upload-time = "2026-03-31T21:58:27.624Z" },
- { url = "https://files.pythonhosted.org/packages/fb/56/3f653d7f53c89669301ec9e42c95233e2a0c0a6dd051269e6e678db4fdb0/aiohttp-3.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe6970addfea9e5e081401bcbadf865d2b6da045472f58af08427e108d618540", size = 1562351, upload-time = "2026-03-31T21:58:29.918Z" },
- { url = "https://files.pythonhosted.org/packages/ec/a6/9b3e91eb8ae791cce4ee736da02211c85c6f835f1bdfac0594a8a3b7018c/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7becdf835feff2f4f335d7477f121af787e3504b48b449ff737afb35869ba7bb", size = 1693205, upload-time = "2026-03-31T21:58:32.214Z" },
- { url = "https://files.pythonhosted.org/packages/98/fc/bfb437a99a2fcebd6b6eaec609571954de2ed424f01c352f4b5504371dd3/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:676e5651705ad5d8a70aeb8eb6936c436d8ebbd56e63436cb7dd9bb36d2a9a46", size = 1730618, upload-time = "2026-03-31T21:58:34.728Z" },
- { url = "https://files.pythonhosted.org/packages/e4/b6/c8534862126191a034f68153194c389addc285a0f1347d85096d349bbc15/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:9b16c653d38eb1a611cc898c41e76859ca27f119d25b53c12875fd0474ae31a8", size = 1745185, upload-time = "2026-03-31T21:58:36.909Z" },
- { url = "https://files.pythonhosted.org/packages/0b/93/4ca8ee2ef5236e2707e0fd5fecb10ce214aee1ff4ab307af9c558bda3b37/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:999802d5fa0389f58decd24b537c54aa63c01c3219ce17d1214cbda3c2b22d2d", size = 1557311, upload-time = "2026-03-31T21:58:39.38Z" },
- { url = "https://files.pythonhosted.org/packages/57/ae/76177b15f18c5f5d094f19901d284025db28eccc5ae374d1d254181d33f4/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ec707059ee75732b1ba130ed5f9580fe10ff75180c812bc267ded039db5128c6", size = 1773147, upload-time = "2026-03-31T21:58:41.476Z" },
- { url = "https://files.pythonhosted.org/packages/01/a4/62f05a0a98d88af59d93b7fcac564e5f18f513cb7471696ac286db970d6a/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2d6d44a5b48132053c2f6cd5c8cb14bc67e99a63594e336b0f2af81e94d5530c", size = 1730356, upload-time = "2026-03-31T21:58:44.049Z" },
- { url = "https://files.pythonhosted.org/packages/e4/85/fc8601f59dfa8c9523808281f2da571f8b4699685f9809a228adcc90838d/aiohttp-3.13.5-cp313-cp313-win32.whl", hash = "sha256:329f292ed14d38a6c4c435e465f48bebb47479fd676a0411936cc371643225cc", size = 432637, upload-time = "2026-03-31T21:58:46.167Z" },
- { url = "https://files.pythonhosted.org/packages/c0/1b/ac685a8882896acf0f6b31d689e3792199cfe7aba37969fa91da63a7fa27/aiohttp-3.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:69f571de7500e0557801c0b51f4780482c0ec5fe2ac851af5a92cfce1af1cb83", size = 458896, upload-time = "2026-03-31T21:58:48.119Z" },
- { url = "https://files.pythonhosted.org/packages/5d/ce/46572759afc859e867a5bc8ec3487315869013f59281ce61764f76d879de/aiohttp-3.13.5-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:eb4639f32fd4a9904ab8fb45bf3383ba71137f3d9d4ba25b3b3f3109977c5b8c", size = 745721, upload-time = "2026-03-31T21:58:50.229Z" },
- { url = "https://files.pythonhosted.org/packages/13/fe/8a2efd7626dbe6049b2ef8ace18ffda8a4dfcbe1bcff3ac30c0c7575c20b/aiohttp-3.13.5-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:7e5dc4311bd5ac493886c63cbf76ab579dbe4641268e7c74e48e774c74b6f2be", size = 497663, upload-time = "2026-03-31T21:58:52.232Z" },
- { url = "https://files.pythonhosted.org/packages/9b/91/cc8cc78a111826c54743d88651e1687008133c37e5ee615fee9b57990fac/aiohttp-3.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:756c3c304d394977519824449600adaf2be0ccee76d206ee339c5e76b70ded25", size = 499094, upload-time = "2026-03-31T21:58:54.566Z" },
- { url = "https://files.pythonhosted.org/packages/0a/33/a8362cb15cf16a3af7e86ed11962d5cd7d59b449202dc576cdc731310bde/aiohttp-3.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecc26751323224cf8186efcf7fbcbc30f4e1d8c7970659daf25ad995e4032a56", size = 1726701, upload-time = "2026-03-31T21:58:56.864Z" },
- { url = "https://files.pythonhosted.org/packages/45/0c/c091ac5c3a17114bd76cbf85d674650969ddf93387876cf67f754204bd77/aiohttp-3.13.5-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10a75acfcf794edf9d8db50e5a7ec5fc818b2a8d3f591ce93bc7b1210df016d2", size = 1683360, upload-time = "2026-03-31T21:58:59.072Z" },
- { url = "https://files.pythonhosted.org/packages/23/73/bcee1c2b79bc275e964d1446c55c54441a461938e70267c86afaae6fba27/aiohttp-3.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f7a18f258d124cd678c5fe072fe4432a4d5232b0657fca7c1847f599233c83a", size = 1773023, upload-time = "2026-03-31T21:59:01.776Z" },
- { url = "https://files.pythonhosted.org/packages/c7/ef/720e639df03004fee2d869f771799d8c23046dec47d5b81e396c7cda583a/aiohttp-3.13.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:df6104c009713d3a89621096f3e3e88cc323fd269dbd7c20afe18535094320be", size = 1853795, upload-time = "2026-03-31T21:59:04.568Z" },
- { url = "https://files.pythonhosted.org/packages/bd/c9/989f4034fb46841208de7aeeac2c6d8300745ab4f28c42f629ba77c2d916/aiohttp-3.13.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:241a94f7de7c0c3b616627aaad530fe2cb620084a8b144d3be7b6ecfe95bae3b", size = 1730405, upload-time = "2026-03-31T21:59:07.221Z" },
- { url = "https://files.pythonhosted.org/packages/ce/75/ee1fd286ca7dc599d824b5651dad7b3be7ff8d9a7e7b3fe9820d9180f7db/aiohttp-3.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c974fb66180e58709b6fc402846f13791240d180b74de81d23913abe48e96d94", size = 1558082, upload-time = "2026-03-31T21:59:09.484Z" },
- { url = "https://files.pythonhosted.org/packages/c3/20/1e9e6650dfc436340116b7aa89ff8cb2bbdf0abc11dfaceaad8f74273a10/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:6e27ea05d184afac78aabbac667450c75e54e35f62238d44463131bd3f96753d", size = 1692346, upload-time = "2026-03-31T21:59:12.068Z" },
- { url = "https://files.pythonhosted.org/packages/d8/40/8ebc6658d48ea630ac7903912fe0dd4e262f0e16825aa4c833c56c9f1f56/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a79a6d399cef33a11b6f004c67bb07741d91f2be01b8d712d52c75711b1e07c7", size = 1698891, upload-time = "2026-03-31T21:59:14.552Z" },
- { url = "https://files.pythonhosted.org/packages/d8/78/ea0ae5ec8ba7a5c10bdd6e318f1ba5e76fcde17db8275188772afc7917a4/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c632ce9c0b534fbe25b52c974515ed674937c5b99f549a92127c85f771a78772", size = 1742113, upload-time = "2026-03-31T21:59:17.068Z" },
- { url = "https://files.pythonhosted.org/packages/8a/66/9d308ed71e3f2491be1acb8769d96c6f0c47d92099f3bc9119cada27b357/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:fceedde51fbd67ee2bcc8c0b33d0126cc8b51ef3bbde2f86662bd6d5a6f10ec5", size = 1553088, upload-time = "2026-03-31T21:59:19.541Z" },
- { url = "https://files.pythonhosted.org/packages/da/a6/6cc25ed8dfc6e00c90f5c6d126a98e2cf28957ad06fa1036bd34b6f24a2c/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f92995dfec9420bb69ae629abf422e516923ba79ba4403bc750d94fb4a6c68c1", size = 1757976, upload-time = "2026-03-31T21:59:22.311Z" },
- { url = "https://files.pythonhosted.org/packages/c1/2b/cce5b0ffe0de99c83e5e36d8f828e4161e415660a9f3e58339d07cce3006/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20ae0ff08b1f2c8788d6fb85afcb798654ae6ba0b747575f8562de738078457b", size = 1712444, upload-time = "2026-03-31T21:59:24.635Z" },
- { url = "https://files.pythonhosted.org/packages/6c/cf/9e1795b4160c58d29421eafd1a69c6ce351e2f7c8d3c6b7e4ca44aea1a5b/aiohttp-3.13.5-cp314-cp314-win32.whl", hash = "sha256:b20df693de16f42b2472a9c485e1c948ee55524786a0a34345511afdd22246f3", size = 438128, upload-time = "2026-03-31T21:59:27.291Z" },
- { url = "https://files.pythonhosted.org/packages/22/4d/eaedff67fc805aeba4ba746aec891b4b24cebb1a7d078084b6300f79d063/aiohttp-3.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:f85c6f327bf0b8c29da7d93b1cabb6363fb5e4e160a32fa241ed2dce21b73162", size = 464029, upload-time = "2026-03-31T21:59:29.429Z" },
- { url = "https://files.pythonhosted.org/packages/79/11/c27d9332ee20d68dd164dc12a6ecdef2e2e35ecc97ed6cf0d2442844624b/aiohttp-3.13.5-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:1efb06900858bb618ff5cee184ae2de5828896c448403d51fb633f09e109be0a", size = 778758, upload-time = "2026-03-31T21:59:31.547Z" },
- { url = "https://files.pythonhosted.org/packages/04/fb/377aead2e0a3ba5f09b7624f702a964bdf4f08b5b6728a9799830c80041e/aiohttp-3.13.5-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:fee86b7c4bd29bdaf0d53d14739b08a106fdda809ca5fe032a15f52fae5fe254", size = 512883, upload-time = "2026-03-31T21:59:34.098Z" },
- { url = "https://files.pythonhosted.org/packages/bb/a6/aa109a33671f7a5d3bd78b46da9d852797c5e665bfda7d6b373f56bff2ec/aiohttp-3.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:20058e23909b9e65f9da62b396b77dfa95965cbe840f8def6e572538b1d32e36", size = 516668, upload-time = "2026-03-31T21:59:36.497Z" },
- { url = "https://files.pythonhosted.org/packages/79/b3/ca078f9f2fa9563c36fb8ef89053ea2bb146d6f792c5104574d49d8acb63/aiohttp-3.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cf20a8d6868cb15a73cab329ffc07291ba8c22b1b88176026106ae39aa6df0f", size = 1883461, upload-time = "2026-03-31T21:59:38.723Z" },
- { url = "https://files.pythonhosted.org/packages/b7/e3/a7ad633ca1ca497b852233a3cce6906a56c3225fb6d9217b5e5e60b7419d/aiohttp-3.13.5-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:330f5da04c987f1d5bdb8ae189137c77139f36bd1cb23779ca1a354a4b027800", size = 1747661, upload-time = "2026-03-31T21:59:41.187Z" },
- { url = "https://files.pythonhosted.org/packages/33/b9/cd6fe579bed34a906d3d783fe60f2fa297ef55b27bb4538438ee49d4dc41/aiohttp-3.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f1cbf0c7926d315c3c26c2da41fd2b5d2fe01ac0e157b78caefc51a782196cf", size = 1863800, upload-time = "2026-03-31T21:59:43.84Z" },
- { url = "https://files.pythonhosted.org/packages/c0/3f/2c1e2f5144cefa889c8afd5cf431994c32f3b29da9961698ff4e3811b79a/aiohttp-3.13.5-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:53fc049ed6390d05423ba33103ded7281fe897cf97878f369a527070bd95795b", size = 1958382, upload-time = "2026-03-31T21:59:46.187Z" },
- { url = "https://files.pythonhosted.org/packages/66/1d/f31ec3f1013723b3babe3609e7f119c2c2fb6ef33da90061a705ef3e1bc8/aiohttp-3.13.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:898703aa2667e3c5ca4c54ca36cd73f58b7a38ef87a5606414799ebce4d3fd3a", size = 1803724, upload-time = "2026-03-31T21:59:48.656Z" },
- { url = "https://files.pythonhosted.org/packages/0e/b4/57712dfc6f1542f067daa81eb61da282fab3e6f1966fca25db06c4fc62d5/aiohttp-3.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0494a01ca9584eea1e5fbd6d748e61ecff218c51b576ee1999c23db7066417d8", size = 1640027, upload-time = "2026-03-31T21:59:51.284Z" },
- { url = "https://files.pythonhosted.org/packages/25/3c/734c878fb43ec083d8e31bf029daae1beafeae582d1b35da234739e82ee7/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6cf81fe010b8c17b09495cbd15c1d35afbc8fb405c0c9cf4738e5ae3af1d65be", size = 1806644, upload-time = "2026-03-31T21:59:53.753Z" },
- { url = "https://files.pythonhosted.org/packages/20/a5/f671e5cbec1c21d044ff3078223f949748f3a7f86b14e34a365d74a5d21f/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:c564dd5f09ddc9d8f2c2d0a301cd30a79a2cc1b46dd1a73bef8f0038863d016b", size = 1791630, upload-time = "2026-03-31T21:59:56.239Z" },
- { url = "https://files.pythonhosted.org/packages/0b/63/fb8d0ad63a0b8a99be97deac8c04dacf0785721c158bdf23d679a87aa99e/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2994be9f6e51046c4f864598fd9abeb4fba6e88f0b2152422c9666dcd4aea9c6", size = 1809403, upload-time = "2026-03-31T21:59:59.103Z" },
- { url = "https://files.pythonhosted.org/packages/59/0c/bfed7f30662fcf12206481c2aac57dedee43fe1c49275e85b3a1e1742294/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:157826e2fa245d2ef46c83ea8a5faf77ca19355d278d425c29fda0beb3318037", size = 1634924, upload-time = "2026-03-31T22:00:02.116Z" },
- { url = "https://files.pythonhosted.org/packages/17/d6/fd518d668a09fd5a3319ae5e984d4d80b9a4b3df4e21c52f02251ef5a32e/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:a8aca50daa9493e9e13c0f566201a9006f080e7c50e5e90d0b06f53146a54500", size = 1836119, upload-time = "2026-03-31T22:00:04.756Z" },
- { url = "https://files.pythonhosted.org/packages/78/b7/15fb7a9d52e112a25b621c67b69c167805cb1f2ab8f1708a5c490d1b52fe/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3b13560160d07e047a93f23aaa30718606493036253d5430887514715b67c9d9", size = 1772072, upload-time = "2026-03-31T22:00:07.494Z" },
- { url = "https://files.pythonhosted.org/packages/7e/df/57ba7f0c4a553fc2bd8b6321df236870ec6fd64a2a473a8a13d4f733214e/aiohttp-3.13.5-cp314-cp314t-win32.whl", hash = "sha256:9a0f4474b6ea6818b41f82172d799e4b3d29e22c2c520ce4357856fced9af2f8", size = 471819, upload-time = "2026-03-31T22:00:10.277Z" },
- { url = "https://files.pythonhosted.org/packages/62/29/2f8418269e46454a26171bfdd6a055d74febf32234e474930f2f60a17145/aiohttp-3.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:18a2f6c1182c51baa1d28d68fea51513cb2a76612f038853c0ad3c145423d3d9", size = 505441, upload-time = "2026-03-31T22:00:12.791Z" },
-]
-
-[[package]]
-name = "aiosignal"
-version = "1.4.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "frozenlist" },
- { name = "typing-extensions", marker = "python_full_version < '3.13'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" },
-]
-
-[[package]]
-name = "ast-serialize"
-version = "0.3.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/a9/9d/912fefab0e30aee6a3af8a62bbea4a81b29afa4ba2c973d31170620a26de/ast_serialize-0.3.0.tar.gz", hash = "sha256:1bc3ca09a63a021376527c4e938deedd11d11d675ce850e6f9c7487f5889992b", size = 60689, upload-time = "2026-04-30T23:24:48.104Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/6f/57/a54d4de491d6cdd7a4e4b0952cc3ca9f60dcefa7b5fb48d6d492debe1649/ast_serialize-0.3.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:3a867927df59f76a18dc1d874a0b2c079b42c58972dca637905576deb0912e14", size = 1182966, upload-time = "2026-04-30T23:23:57.376Z" },
- { url = "https://files.pythonhosted.org/packages/ee/9e/a5db014bb0f91b209236b57c429389e31290c0093532b8436d577699b2fa/ast_serialize-0.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a6fb063bf040abf8321e7b8113a0554eda445ffc508aa51287f8808886a5ae22", size = 1171316, upload-time = "2026-04-30T23:23:59.63Z" },
- { url = "https://files.pythonhosted.org/packages/15/59/fd55133e478c4326f60a11df02573bf7ccb2ac685810b50f1803d0f68053/ast_serialize-0.3.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5075cd8482573d743586779e5f9b652a015e37d4e95132d7e5a9bc5c8f483d8f", size = 1232234, upload-time = "2026-04-30T23:24:01.168Z" },
- { url = "https://files.pythonhosted.org/packages/cc/79/0ca1d26357ecb4a697d74d00b73ef3137f24c140424125393a0de820eb09/ast_serialize-0.3.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:41560b27794f4553b0f77811e9fb325b77db4a2b39018d437e09932275306e66", size = 1233437, upload-time = "2026-04-30T23:24:03.151Z" },
- { url = "https://files.pythonhosted.org/packages/53/3e/7078ec94dd6e124b8e028ac77016a4f13c83fa1c145790f2e68f3816998b/ast_serialize-0.3.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b967c01ca74909c5d90e0fe4393401e2cc5da5ebd9a6262a19e45ffd3757dec8", size = 1440188, upload-time = "2026-04-30T23:24:04.717Z" },
- { url = "https://files.pythonhosted.org/packages/21/16/cca7195ef55a012f8013c3442afa91d287a0a36dcf88b480b262475135b3/ast_serialize-0.3.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:424ebb8f46cd993f7cec4009d119312d8433dd90e6b0df0499cd2c91bdcc5af9", size = 1254211, upload-time = "2026-04-30T23:24:06.18Z" },
- { url = "https://files.pythonhosted.org/packages/a0/0f/f3d4dfae67dee6580534361a6343367d34217e7d25cff858bd1d8f03b8ed/ast_serialize-0.3.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d14b1d566b56e2ee70b11fec1de7e0b94ec7cd83717ec7d189967841a361190e", size = 1255973, upload-time = "2026-04-30T23:24:07.772Z" },
- { url = "https://files.pythonhosted.org/packages/14/41/55fbfe02c42f40fbe3e74eda167d977d555ff720ce1abfa08515236efd88/ast_serialize-0.3.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7ba30b18735f047ec11103d1ab92f4789cf1fea1e0dc89b04a2f5a0632fd79de", size = 1298629, upload-time = "2026-04-30T23:24:09.4Z" },
- { url = "https://files.pythonhosted.org/packages/28/36/7d2501cacc7989fb8504aa9da2a2022a174200a59d4e6639de4367a57fdd/ast_serialize-0.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e6ea0754cb7b0f682ebb005ffb0d18f8d17993490d9c289863cd69cacc4ab8df", size = 1408435, upload-time = "2026-04-30T23:24:11.013Z" },
- { url = "https://files.pythonhosted.org/packages/03/e7/54e3b469c3fa0bf9cd532fa643d1d33b73303f8d70beac3e366b68dd64b7/ast_serialize-0.3.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:a0c5aa1073a5ba7b2abaa4b54abe8b8d75c4d1e2d54a2ff70b0ca6222fea5728", size = 1508174, upload-time = "2026-04-30T23:24:12.635Z" },
- { url = "https://files.pythonhosted.org/packages/b5/2a/9b9621865b02c60539e26d9b114a312b4fa46aa703e33e79317174bfea21/ast_serialize-0.3.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:4e52650d834c1ea7791969a361de2c54c13b2fb4c519ec79445fa8b9021a147d", size = 1502354, upload-time = "2026-04-30T23:24:14.186Z" },
- { url = "https://files.pythonhosted.org/packages/34/dd/f138bc5c43b0c414fdd12eefe15677839323078b6e75301ad7f96cd26d45/ast_serialize-0.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:15bd6af3f136c61dae27805eb6b8f3269e85a545c4c27ffe9e530ead78d2b36d", size = 1450504, upload-time = "2026-04-30T23:24:16.076Z" },
- { url = "https://files.pythonhosted.org/packages/68/cf/97ef9e1c315601db74365955c8edd3292e3055500d6317602815dbdf08ae/ast_serialize-0.3.0-cp314-cp314t-win32.whl", hash = "sha256:d188bfe37b674b49708497683051d4b571366a668799c9b8e8a94513694969d9", size = 1058662, upload-time = "2026-04-30T23:24:17.535Z" },
- { url = "https://files.pythonhosted.org/packages/f8/d6/e2c3483c31580fdb623f92ad38d2f856cde4b9205a3e6bd84760f3de7d82/ast_serialize-0.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:5832c2fdf8f8a6cf682b4cfcf677f5eaf39b4ddbc490f5480cfccdd1e7ce8fa1", size = 1100349, upload-time = "2026-04-30T23:24:18.992Z" },
- { url = "https://files.pythonhosted.org/packages/ab/89/29abcb1fe18a429cda60c6e0bbd1d6e90499339842a2f548d7567542357e/ast_serialize-0.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:670f177188d128fb7f9f15b5ad0e1b553d22c34e3f584dcb83eb8077600437f0", size = 1072895, upload-time = "2026-04-30T23:24:20.706Z" },
- { url = "https://files.pythonhosted.org/packages/bc/93/72abad83966ed6235647c9f956417dc1e17e997696388521910e3d1fa3f4/ast_serialize-0.3.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:2ec2fafa5e4313cc8feed96e436ebe19ac7bc6fa41fbc2827e826c48b9e4c3a9", size = 1190024, upload-time = "2026-04-30T23:24:22.486Z" },
- { url = "https://files.pythonhosted.org/packages/85/4f/eb88584b2f0234e581762011208ca203252bf6c98e59b4769daa571f3576/ast_serialize-0.3.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ef6d3c08b7b4cd29b48410338e134764a00e76d25841eb02c1084e868c888ecc", size = 1178633, upload-time = "2026-04-30T23:24:24.35Z" },
- { url = "https://files.pythonhosted.org/packages/56/51/cf1ec1ff3e616373d0dcbd5fad502e0029dc541f13ab642259762a7d127f/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d841424f41b886e98044abc80769c14a956e6e5ccd5fb5b0d9f5ead72be18a4", size = 1241351, upload-time = "2026-04-30T23:24:25.987Z" },
- { url = "https://files.pythonhosted.org/packages/0d/44/68fcf50478cf1093f2d423f034ae06453122c8b415d8e21a44668eca485d/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d21453734ad39367ede5d37efe4f59f830ce1c09f432fc72a90e368f77a4a3e7", size = 1239582, upload-time = "2026-04-30T23:24:27.808Z" },
- { url = "https://files.pythonhosted.org/packages/9d/c1/a6c9fa284eceb5fc6f21347e968445a051d7ca2c4d34e6a04314646dbcee/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f5e110cdce2a347e1dd987529c88ef54d26f67848dce3eba1b3b2cc2cf085c94", size = 1448853, upload-time = "2026-04-30T23:24:29.534Z" },
- { url = "https://files.pythonhosted.org/packages/23/5f/8ad3829a09e4e8c5328a53ce7d4711d660944e3e164c5f6abcc2c8f27167/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b6e23a98e57560a055f5c4b68700a0fd5ce483d2814c23140b3638c7f5d1e61", size = 1262204, upload-time = "2026-04-30T23:24:31.482Z" },
- { url = "https://files.pythonhosted.org/packages/25/13/44aa28d97f10e25247e8576b5f6b2795d4fa1a80acc88acc942c508d06f7/ast_serialize-0.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1c9e763d70293d65ce1e1ea8c943140c68d0953f0268c7ee0998f2e07f77dd0", size = 1266458, upload-time = "2026-04-30T23:24:33.088Z" },
- { url = "https://files.pythonhosted.org/packages/d8/58/b3a8be3777cd3744324fd5cec0d80d37cd96fc7cbb0fb010e03dff1e870f/ast_serialize-0.3.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4388a1796c228f1ce5c391426f7d21a0003ad3b47f677dbeded9bd1a85c7209f", size = 1308700, upload-time = "2026-04-30T23:24:34.657Z" },
- { url = "https://files.pythonhosted.org/packages/13/03/f8312d6b57f5471a9dc7946f22b8798a1fc296d38c25766223aacadec42c/ast_serialize-0.3.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5283cdcc0c64c3d8b9b688dc6aaa012d9c0cf1380a7f774a6bae6a1c01b3205a", size = 1416724, upload-time = "2026-04-30T23:24:36.562Z" },
- { url = "https://files.pythonhosted.org/packages/50/5d/13fc3789a7abac00559da2e2e9f386db4612aa1f84fc53d09bf714c37545/ast_serialize-0.3.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:f5ef88cc5842a5d7a6ac09dc0d5fc2c98f5d276c1f076f866d55047ce886785b", size = 1515441, upload-time = "2026-04-30T23:24:38.018Z" },
- { url = "https://files.pythonhosted.org/packages/eb/b9/7ab43fc7a23b1f970281093228f5f79bed6edeed7a3e672bde6d7a832a58/ast_serialize-0.3.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:cc14bf402bdc0978594ecce783793de2c7470cd4f5cd7eb286ca97ed8ff7cba9", size = 1510522, upload-time = "2026-04-30T23:24:39.798Z" },
- { url = "https://files.pythonhosted.org/packages/56/ec/d75fc2b788d319f1fad77c14156896f31afdfc68af85b505e5bdebcb9592/ast_serialize-0.3.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:11eae0cf1b7b3e0678133cc2daa974ea972caf02eb4b3aa062af6fa9acd52c57", size = 1460917, upload-time = "2026-04-30T23:24:41.305Z" },
- { url = "https://files.pythonhosted.org/packages/95/74/f99c81193a2725911e1911ae567ed27c2f2419332c7f3537366f9d238cac/ast_serialize-0.3.0-cp39-abi3-win32.whl", hash = "sha256:2db3dd99de5e6a5a11d7dda73de8750eb6e5baaf25245adf7bdcfe64b6108ae2", size = 1067804, upload-time = "2026-04-30T23:24:43.091Z" },
- { url = "https://files.pythonhosted.org/packages/16/81/76af00c47daa151e89f98ae21fbbcb2840aaa9f5766579c4da76a3c57188/ast_serialize-0.3.0-cp39-abi3-win_amd64.whl", hash = "sha256:a2cd125adccf7969470621905d302750cd25951f22ea430d9a25b7be031e5549", size = 1105561, upload-time = "2026-04-30T23:24:44.578Z" },
- { url = "https://files.pythonhosted.org/packages/bd/46/d3ec57ad500f598d1554bd14ce4df615960549ab2844961bc4e1f5fbd174/ast_serialize-0.3.0-cp39-abi3-win_arm64.whl", hash = "sha256:0dd00da29985f15f50dc35728b7e1e7c84507bccfea1d9914738530f1c72238a", size = 1077165, upload-time = "2026-04-30T23:24:46.377Z" },
-]
-
-[[package]]
-name = "attrs"
-version = "26.1.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" },
-]
-
-[[package]]
-name = "cfgv"
-version = "3.5.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" },
-]
-
-[[package]]
-name = "distlib"
-version = "0.4.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" },
-]
-
-[[package]]
-name = "filelock"
-version = "3.29.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/b5/fe/997687a931ab51049acce6fa1f23e8f01216374ea81374ddee763c493db5/filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", size = 57571, upload-time = "2026-04-19T15:39:10.068Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", size = 39812, upload-time = "2026-04-19T15:39:08.752Z" },
-]
-
-[[package]]
-name = "frozenlist"
-version = "1.8.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782, upload-time = "2025-10-06T05:36:06.649Z" },
- { url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594, upload-time = "2025-10-06T05:36:07.69Z" },
- { url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448, upload-time = "2025-10-06T05:36:08.78Z" },
- { url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411, upload-time = "2025-10-06T05:36:09.801Z" },
- { url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014, upload-time = "2025-10-06T05:36:11.394Z" },
- { url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909, upload-time = "2025-10-06T05:36:12.598Z" },
- { url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049, upload-time = "2025-10-06T05:36:14.065Z" },
- { url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485, upload-time = "2025-10-06T05:36:15.39Z" },
- { url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619, upload-time = "2025-10-06T05:36:16.558Z" },
- { url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320, upload-time = "2025-10-06T05:36:17.821Z" },
- { url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820, upload-time = "2025-10-06T05:36:19.046Z" },
- { url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518, upload-time = "2025-10-06T05:36:20.763Z" },
- { url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096, upload-time = "2025-10-06T05:36:22.129Z" },
- { url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985, upload-time = "2025-10-06T05:36:23.661Z" },
- { url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591, upload-time = "2025-10-06T05:36:24.958Z" },
- { url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102, upload-time = "2025-10-06T05:36:26.333Z" },
- { url = "https://files.pythonhosted.org/packages/2d/40/0832c31a37d60f60ed79e9dfb5a92e1e2af4f40a16a29abcc7992af9edff/frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a", size = 85717, upload-time = "2025-10-06T05:36:27.341Z" },
- { url = "https://files.pythonhosted.org/packages/30/ba/b0b3de23f40bc55a7057bd38434e25c34fa48e17f20ee273bbde5e0650f3/frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7", size = 49651, upload-time = "2025-10-06T05:36:28.855Z" },
- { url = "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40", size = 49417, upload-time = "2025-10-06T05:36:29.877Z" },
- { url = "https://files.pythonhosted.org/packages/d5/4e/e4691508f9477ce67da2015d8c00acd751e6287739123113a9fca6f1604e/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027", size = 234391, upload-time = "2025-10-06T05:36:31.301Z" },
- { url = "https://files.pythonhosted.org/packages/40/76/c202df58e3acdf12969a7895fd6f3bc016c642e6726aa63bd3025e0fc71c/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822", size = 233048, upload-time = "2025-10-06T05:36:32.531Z" },
- { url = "https://files.pythonhosted.org/packages/f9/c0/8746afb90f17b73ca5979c7a3958116e105ff796e718575175319b5bb4ce/frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121", size = 226549, upload-time = "2025-10-06T05:36:33.706Z" },
- { url = "https://files.pythonhosted.org/packages/7e/eb/4c7eefc718ff72f9b6c4893291abaae5fbc0c82226a32dcd8ef4f7a5dbef/frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5", size = 239833, upload-time = "2025-10-06T05:36:34.947Z" },
- { url = "https://files.pythonhosted.org/packages/c2/4e/e5c02187cf704224f8b21bee886f3d713ca379535f16893233b9d672ea71/frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e", size = 245363, upload-time = "2025-10-06T05:36:36.534Z" },
- { url = "https://files.pythonhosted.org/packages/1f/96/cb85ec608464472e82ad37a17f844889c36100eed57bea094518bf270692/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11", size = 229314, upload-time = "2025-10-06T05:36:38.582Z" },
- { url = "https://files.pythonhosted.org/packages/5d/6f/4ae69c550e4cee66b57887daeebe006fe985917c01d0fff9caab9883f6d0/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1", size = 243365, upload-time = "2025-10-06T05:36:40.152Z" },
- { url = "https://files.pythonhosted.org/packages/7a/58/afd56de246cf11780a40a2c28dc7cbabbf06337cc8ddb1c780a2d97e88d8/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1", size = 237763, upload-time = "2025-10-06T05:36:41.355Z" },
- { url = "https://files.pythonhosted.org/packages/cb/36/cdfaf6ed42e2644740d4a10452d8e97fa1c062e2a8006e4b09f1b5fd7d63/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8", size = 240110, upload-time = "2025-10-06T05:36:42.716Z" },
- { url = "https://files.pythonhosted.org/packages/03/a8/9ea226fbefad669f11b52e864c55f0bd57d3c8d7eb07e9f2e9a0b39502e1/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed", size = 233717, upload-time = "2025-10-06T05:36:44.251Z" },
- { url = "https://files.pythonhosted.org/packages/1e/0b/1b5531611e83ba7d13ccc9988967ea1b51186af64c42b7a7af465dcc9568/frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496", size = 39628, upload-time = "2025-10-06T05:36:45.423Z" },
- { url = "https://files.pythonhosted.org/packages/d8/cf/174c91dbc9cc49bc7b7aab74d8b734e974d1faa8f191c74af9b7e80848e6/frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231", size = 43882, upload-time = "2025-10-06T05:36:46.796Z" },
- { url = "https://files.pythonhosted.org/packages/c1/17/502cd212cbfa96eb1388614fe39a3fc9ab87dbbe042b66f97acb57474834/frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62", size = 39676, upload-time = "2025-10-06T05:36:47.8Z" },
- { url = "https://files.pythonhosted.org/packages/d2/5c/3bbfaa920dfab09e76946a5d2833a7cbdf7b9b4a91c714666ac4855b88b4/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94", size = 89235, upload-time = "2025-10-06T05:36:48.78Z" },
- { url = "https://files.pythonhosted.org/packages/d2/d6/f03961ef72166cec1687e84e8925838442b615bd0b8854b54923ce5b7b8a/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c", size = 50742, upload-time = "2025-10-06T05:36:49.837Z" },
- { url = "https://files.pythonhosted.org/packages/1e/bb/a6d12b7ba4c3337667d0e421f7181c82dda448ce4e7ad7ecd249a16fa806/frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52", size = 51725, upload-time = "2025-10-06T05:36:50.851Z" },
- { url = "https://files.pythonhosted.org/packages/bc/71/d1fed0ffe2c2ccd70b43714c6cab0f4188f09f8a67a7914a6b46ee30f274/frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51", size = 284533, upload-time = "2025-10-06T05:36:51.898Z" },
- { url = "https://files.pythonhosted.org/packages/c9/1f/fb1685a7b009d89f9bf78a42d94461bc06581f6e718c39344754a5d9bada/frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65", size = 292506, upload-time = "2025-10-06T05:36:53.101Z" },
- { url = "https://files.pythonhosted.org/packages/e6/3b/b991fe1612703f7e0d05c0cf734c1b77aaf7c7d321df4572e8d36e7048c8/frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82", size = 274161, upload-time = "2025-10-06T05:36:54.309Z" },
- { url = "https://files.pythonhosted.org/packages/ca/ec/c5c618767bcdf66e88945ec0157d7f6c4a1322f1473392319b7a2501ded7/frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714", size = 294676, upload-time = "2025-10-06T05:36:55.566Z" },
- { url = "https://files.pythonhosted.org/packages/7c/ce/3934758637d8f8a88d11f0585d6495ef54b2044ed6ec84492a91fa3b27aa/frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d", size = 300638, upload-time = "2025-10-06T05:36:56.758Z" },
- { url = "https://files.pythonhosted.org/packages/fc/4f/a7e4d0d467298f42de4b41cbc7ddaf19d3cfeabaf9ff97c20c6c7ee409f9/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506", size = 283067, upload-time = "2025-10-06T05:36:57.965Z" },
- { url = "https://files.pythonhosted.org/packages/dc/48/c7b163063d55a83772b268e6d1affb960771b0e203b632cfe09522d67ea5/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51", size = 292101, upload-time = "2025-10-06T05:36:59.237Z" },
- { url = "https://files.pythonhosted.org/packages/9f/d0/2366d3c4ecdc2fd391e0afa6e11500bfba0ea772764d631bbf82f0136c9d/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e", size = 289901, upload-time = "2025-10-06T05:37:00.811Z" },
- { url = "https://files.pythonhosted.org/packages/b8/94/daff920e82c1b70e3618a2ac39fbc01ae3e2ff6124e80739ce5d71c9b920/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0", size = 289395, upload-time = "2025-10-06T05:37:02.115Z" },
- { url = "https://files.pythonhosted.org/packages/e3/20/bba307ab4235a09fdcd3cc5508dbabd17c4634a1af4b96e0f69bfe551ebd/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41", size = 283659, upload-time = "2025-10-06T05:37:03.711Z" },
- { url = "https://files.pythonhosted.org/packages/fd/00/04ca1c3a7a124b6de4f8a9a17cc2fcad138b4608e7a3fc5877804b8715d7/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b", size = 43492, upload-time = "2025-10-06T05:37:04.915Z" },
- { url = "https://files.pythonhosted.org/packages/59/5e/c69f733a86a94ab10f68e496dc6b7e8bc078ebb415281d5698313e3af3a1/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888", size = 48034, upload-time = "2025-10-06T05:37:06.343Z" },
- { url = "https://files.pythonhosted.org/packages/16/6c/be9d79775d8abe79b05fa6d23da99ad6e7763a1d080fbae7290b286093fd/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042", size = 41749, upload-time = "2025-10-06T05:37:07.431Z" },
- { url = "https://files.pythonhosted.org/packages/f1/c8/85da824b7e7b9b6e7f7705b2ecaf9591ba6f79c1177f324c2735e41d36a2/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0", size = 86127, upload-time = "2025-10-06T05:37:08.438Z" },
- { url = "https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f", size = 49698, upload-time = "2025-10-06T05:37:09.48Z" },
- { url = "https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c", size = 49749, upload-time = "2025-10-06T05:37:10.569Z" },
- { url = "https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2", size = 231298, upload-time = "2025-10-06T05:37:11.993Z" },
- { url = "https://files.pythonhosted.org/packages/3a/3b/d9b1e0b0eed36e70477ffb8360c49c85c8ca8ef9700a4e6711f39a6e8b45/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8", size = 232015, upload-time = "2025-10-06T05:37:13.194Z" },
- { url = "https://files.pythonhosted.org/packages/dc/94/be719d2766c1138148564a3960fc2c06eb688da592bdc25adcf856101be7/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686", size = 225038, upload-time = "2025-10-06T05:37:14.577Z" },
- { url = "https://files.pythonhosted.org/packages/e4/09/6712b6c5465f083f52f50cf74167b92d4ea2f50e46a9eea0523d658454ae/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e", size = 240130, upload-time = "2025-10-06T05:37:15.781Z" },
- { url = "https://files.pythonhosted.org/packages/f8/d4/cd065cdcf21550b54f3ce6a22e143ac9e4836ca42a0de1022da8498eac89/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a", size = 242845, upload-time = "2025-10-06T05:37:17.037Z" },
- { url = "https://files.pythonhosted.org/packages/62/c3/f57a5c8c70cd1ead3d5d5f776f89d33110b1addae0ab010ad774d9a44fb9/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128", size = 229131, upload-time = "2025-10-06T05:37:18.221Z" },
- { url = "https://files.pythonhosted.org/packages/6c/52/232476fe9cb64f0742f3fde2b7d26c1dac18b6d62071c74d4ded55e0ef94/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f", size = 240542, upload-time = "2025-10-06T05:37:19.771Z" },
- { url = "https://files.pythonhosted.org/packages/5f/85/07bf3f5d0fb5414aee5f47d33c6f5c77bfe49aac680bfece33d4fdf6a246/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7", size = 237308, upload-time = "2025-10-06T05:37:20.969Z" },
- { url = "https://files.pythonhosted.org/packages/11/99/ae3a33d5befd41ac0ca2cc7fd3aa707c9c324de2e89db0e0f45db9a64c26/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30", size = 238210, upload-time = "2025-10-06T05:37:22.252Z" },
- { url = "https://files.pythonhosted.org/packages/b2/60/b1d2da22f4970e7a155f0adde9b1435712ece01b3cd45ba63702aea33938/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7", size = 231972, upload-time = "2025-10-06T05:37:23.5Z" },
- { url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536, upload-time = "2025-10-06T05:37:25.581Z" },
- { url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330, upload-time = "2025-10-06T05:37:26.928Z" },
- { url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627, upload-time = "2025-10-06T05:37:28.075Z" },
- { url = "https://files.pythonhosted.org/packages/c0/c7/43200656ecc4e02d3f8bc248df68256cd9572b3f0017f0a0c4e93440ae23/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d", size = 89238, upload-time = "2025-10-06T05:37:29.373Z" },
- { url = "https://files.pythonhosted.org/packages/d1/29/55c5f0689b9c0fb765055629f472c0de484dcaf0acee2f7707266ae3583c/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed", size = 50738, upload-time = "2025-10-06T05:37:30.792Z" },
- { url = "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930", size = 51739, upload-time = "2025-10-06T05:37:32.127Z" },
- { url = "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c", size = 284186, upload-time = "2025-10-06T05:37:33.21Z" },
- { url = "https://files.pythonhosted.org/packages/2d/14/aa36d5f85a89679a85a1d44cd7a6657e0b1c75f61e7cad987b203d2daca8/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24", size = 292196, upload-time = "2025-10-06T05:37:36.107Z" },
- { url = "https://files.pythonhosted.org/packages/05/23/6bde59eb55abd407d34f77d39a5126fb7b4f109a3f611d3929f14b700c66/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37", size = 273830, upload-time = "2025-10-06T05:37:37.663Z" },
- { url = "https://files.pythonhosted.org/packages/d2/3f/22cff331bfad7a8afa616289000ba793347fcd7bc275f3b28ecea2a27909/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a", size = 294289, upload-time = "2025-10-06T05:37:39.261Z" },
- { url = "https://files.pythonhosted.org/packages/a4/89/5b057c799de4838b6c69aa82b79705f2027615e01be996d2486a69ca99c4/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2", size = 300318, upload-time = "2025-10-06T05:37:43.213Z" },
- { url = "https://files.pythonhosted.org/packages/30/de/2c22ab3eb2a8af6d69dc799e48455813bab3690c760de58e1bf43b36da3e/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef", size = 282814, upload-time = "2025-10-06T05:37:45.337Z" },
- { url = "https://files.pythonhosted.org/packages/59/f7/970141a6a8dbd7f556d94977858cfb36fa9b66e0892c6dd780d2219d8cd8/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe", size = 291762, upload-time = "2025-10-06T05:37:46.657Z" },
- { url = "https://files.pythonhosted.org/packages/c1/15/ca1adae83a719f82df9116d66f5bb28bb95557b3951903d39135620ef157/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8", size = 289470, upload-time = "2025-10-06T05:37:47.946Z" },
- { url = "https://files.pythonhosted.org/packages/ac/83/dca6dc53bf657d371fbc88ddeb21b79891e747189c5de990b9dfff2ccba1/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a", size = 289042, upload-time = "2025-10-06T05:37:49.499Z" },
- { url = "https://files.pythonhosted.org/packages/96/52/abddd34ca99be142f354398700536c5bd315880ed0a213812bc491cff5e4/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e", size = 283148, upload-time = "2025-10-06T05:37:50.745Z" },
- { url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload-time = "2025-10-06T05:37:52.222Z" },
- { url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload-time = "2025-10-06T05:37:53.425Z" },
- { url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload-time = "2025-10-06T05:37:54.513Z" },
- { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" },
-]
-
-[[package]]
-name = "identify"
-version = "2.6.19"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/52/63/51723b5f116cc04b061cb6f5a561790abf249d25931d515cd375e063e0f4/identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842", size = 99567, upload-time = "2026-04-17T18:39:50.265Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a", size = 99397, upload-time = "2026-04-17T18:39:49.221Z" },
-]
-
-[[package]]
-name = "idna"
-version = "3.15"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/82/77/7b3966d0b9d1d31a36ddf1746926a11dface89a83409bf1483f0237aa758/idna-3.15.tar.gz", hash = "sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc", size = 199245, upload-time = "2026-05-12T22:45:57.011Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl", hash = "sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8", size = 72340, upload-time = "2026-05-12T22:45:55.733Z" },
-]
-
-[[package]]
-name = "librt"
-version = "0.10.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/39/cb/c1945e506893b5b8577fb45a60c80e3ffe4a82092a04a6f29b0b951d9a24/librt-0.10.0.tar.gz", hash = "sha256:1aba1e8aa4e3307a7be68a74149545fde7451964dc0235a8bec5704a17bdda42", size = 191799, upload-time = "2026-05-05T16:31:23.535Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/12/8e/cbb5b6f6e45e65c10a42449a69eaccc44d73e6a081ea752fbc5221c6dc1c/librt-0.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b4b58a44b407e91f633dafee008de9ddea6aa2a555ed94929c099260910bd0ba", size = 77327, upload-time = "2026-05-05T16:29:38.919Z" },
- { url = "https://files.pythonhosted.org/packages/e9/3d/8233cbee8e99e6a8992f02bfc2dec8d787509566a511d1fde2574ee7473f/librt-0.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:950b79b11762531bdf45a9df909d2f9a2a8445c70c88665c01d14c8511a27dc5", size = 79971, upload-time = "2026-05-05T16:29:40.96Z" },
- { url = "https://files.pythonhosted.org/packages/87/6f/5264b298cef2b72fc97d2dde56c66181eda35204bf5dcd1ed0c3d0a0a782/librt-0.10.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4538453f51be197633b425912c150e25b0667252d3741c53e8368176d98d9d37", size = 246559, upload-time = "2026-05-05T16:29:42.701Z" },
- { url = "https://files.pythonhosted.org/packages/07/7b/19b1b859cc60d5f99276cc2b3144d91556c6d1b1e4ebb50359696bebf7a8/librt-0.10.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:70b955f091beac93e994a0b7ec616934f63b3ea5c3d6d7af847562f935aceca7", size = 235216, upload-time = "2026-05-05T16:29:44.193Z" },
- { url = "https://files.pythonhosted.org/packages/6e/56/a2f40717142a8af46289f57874ef914353d8faccd5e4f8e594ab1e16e8c7/librt-0.10.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:483e685e06b6163728ba6c85d74315176be7190f432ec2a41226e5e14355d5f0", size = 263108, upload-time = "2026-05-05T16:29:46.365Z" },
- { url = "https://files.pythonhosted.org/packages/67/ca/15c625c3bdc0167c01e04ef8878317e9713f3bfa788438342f7a94c7b22c/librt-0.10.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7ac53d946a009d1a38c44a60812708c9458fb2a239a5f630d8e625571386650f", size = 255280, upload-time = "2026-05-05T16:29:48.087Z" },
- { url = "https://files.pythonhosted.org/packages/ed/c5/ba301d571d9e05844e2435b73aba30bee77bb75ce155c9affcfd2173dd03/librt-0.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bc8771c9fcf0ea894ca41fdc2abd83572c2fbda221f232d86e718614e57ff513", size = 268829, upload-time = "2026-05-05T16:29:49.628Z" },
- { url = "https://files.pythonhosted.org/packages/8b/60/af70e135bc1f1fe15dd3894b1e4bbefc7ecdf911749a925a39eb86ceb2a1/librt-0.10.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:70805dbc5257892ac572f86290a61e3c8d90224ecce1a8b2d1f7ed51965417f4", size = 262051, upload-time = "2026-05-05T16:29:51.244Z" },
- { url = "https://files.pythonhosted.org/packages/83/c2/c8236eb8b421bac5a172ba208f965abaa89805da2a3fa112bdf1764caf8f/librt-0.10.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d3b4f300f7bcba6e2ff73fb8bef1898479e9772bfa2682998c636391633ec826", size = 264347, upload-time = "2026-05-05T16:29:53.013Z" },
- { url = "https://files.pythonhosted.org/packages/d6/f5/15b6d32bc25dacd4a60886a683d8128d6219910c122202b995a40dd4f8d2/librt-0.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:943bc943f92f4fb3408fae62485c6a3ad68ce4f2ee205643a39641525c19a276", size = 286482, upload-time = "2026-05-05T16:29:54.675Z" },
- { url = "https://files.pythonhosted.org/packages/fb/8e/b1b959bacd323eb4360579db992513e1406d1c6ef7edb57b5511fd0666fd/librt-0.10.0-cp312-cp312-win32.whl", hash = "sha256:6065c1a758fba1010b41401013903d3d5d2750eab425ddedd584abac31d0630e", size = 62955, upload-time = "2026-05-05T16:29:56.39Z" },
- { url = "https://files.pythonhosted.org/packages/9e/4c/d4cd6e4b9fc24098e63cc85537d1b6689682aee96809c38f08072067cc2b/librt-0.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:d788ecbe208ab352dab0e105cc06057bf9a2fc7e58cabb0d751ad9e30062b9e2", size = 71191, upload-time = "2026-05-05T16:29:57.682Z" },
- { url = "https://files.pythonhosted.org/packages/2b/19/8641da1f63d24b92354a492f893c022d6b3a0df44e70c8eff49364613983/librt-0.10.0-cp312-cp312-win_arm64.whl", hash = "sha256:6003d1f295bdba02656dc81308208fc060d0a51d8c0d0a6db70f7f3c57b9ba0a", size = 61432, upload-time = "2026-05-05T16:29:58.971Z" },
- { url = "https://files.pythonhosted.org/packages/e5/29/681a75c82f4cc90d29e4b257a3299b79fe13fe927a04c57b8109d70b6957/librt-0.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f0ede79d682e73f91c1b599a76d78b7464b9b5d213754cedb13372d9df36e596", size = 77299, upload-time = "2026-05-05T16:30:00.209Z" },
- { url = "https://files.pythonhosted.org/packages/62/24/0c7ca445a55d04be79cac19819437fd094782347fa116f6681844fa6143e/librt-0.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e0ba0b131fdb336c8b9c948e397f4a7e649d0f783b529f07b647bf4961df392e", size = 79930, upload-time = "2026-05-05T16:30:01.555Z" },
- { url = "https://files.pythonhosted.org/packages/fe/1f/1e2b8f6443ef9e9a81e89486ca70e22f3684f93db003ce6eaefc3d0839b9/librt-0.10.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2728117da2afb96fb957768725ee43dc9a2d73b031e02da424b818a3cdd3a275", size = 246195, upload-time = "2026-05-05T16:30:03.261Z" },
- { url = "https://files.pythonhosted.org/packages/74/61/9dc9e03de0439ad84c1c240aac8b747f12c90cb797ea6042f7bdb8d3410f/librt-0.10.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:723ba80594c49cdf0584196fc430752262605dc9449902fc9bd3d9b79976cb77", size = 234951, upload-time = "2026-05-05T16:30:04.881Z" },
- { url = "https://files.pythonhosted.org/packages/55/f4/635223117d7590875bca441275065a3bf491203ad4208bd1cc3ffd90c5a1/librt-0.10.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7292edaaca294a61a978c53a3c7d6130d099b0dfbc8f0a65916cdc6b891b9852", size = 262768, upload-time = "2026-05-05T16:30:06.638Z" },
- { url = "https://files.pythonhosted.org/packages/e5/66/b04152d0cd8b6ca2b428a8bd3230343230c35ed304a932f35b5375f2f828/librt-0.10.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:89fe9d539f2c10a1666633eeeac507ce95dd06d9ecc58de3c6390dba156a3d3a", size = 255075, upload-time = "2026-05-05T16:30:08.216Z" },
- { url = "https://files.pythonhosted.org/packages/35/1e/25bac4c7f2ca36f0e612cade186970683cf79153d96beccc3a11a9e19b97/librt-0.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4efa7b9587503fa5b67f40593302b9c8836d211d222ff9f7cafe67be5f8f0b10", size = 268559, upload-time = "2026-05-05T16:30:10.1Z" },
- { url = "https://files.pythonhosted.org/packages/18/54/4601faab35b6632a13200faa146ca62bfd111ffbe2568be430d65c89493a/librt-0.10.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:22dc982ef59df0136df36092ccbdbb570ced8aafb33e49585739b2f1de1c13b6", size = 261753, upload-time = "2026-05-05T16:30:11.912Z" },
- { url = "https://files.pythonhosted.org/packages/1b/cf/39f4023509e94fade8b074666fa3292db9cb6b34ea5dcbe7af53df9fca1d/librt-0.10.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:6f2e5f3606253a84cea719c94a3bb1c54487b5d617d0254d46e0920d8a06be3f", size = 264055, upload-time = "2026-05-05T16:30:13.465Z" },
- { url = "https://files.pythonhosted.org/packages/8e/00/40247209fc46a8e308a91412d5206aedf8efb667ee89eb625820106a5c2f/librt-0.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:40884bfaa1e29f6b6a9be255007d8f359bfc9e61d68bdef8ed3158bfcbc95df9", size = 286190, upload-time = "2026-05-05T16:30:15.073Z" },
- { url = "https://files.pythonhosted.org/packages/d8/6e/5566beb94431a985abe1787af5ef86e087750172ff9d0bbf20f93e88132d/librt-0.10.0-cp313-cp313-win32.whl", hash = "sha256:3cd34cd8254eba756660bff6c2da91278248184301054fe3e4feb073bdd49b14", size = 62949, upload-time = "2026-05-05T16:30:16.503Z" },
- { url = "https://files.pythonhosted.org/packages/d0/c2/3ea3301d6c8dff51d39dbe8ed75db3dc92896947d4afb5eeadf821c1e67f/librt-0.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:7baac5313e2d8dce1386f97777a8d03ab28f5fe1e780b3b9ac2ee7544551fedc", size = 71152, upload-time = "2026-05-05T16:30:17.766Z" },
- { url = "https://files.pythonhosted.org/packages/3c/de/5d49cb92cadcbc77d3abc27b93fd6030ed8437487dde2eae38cab5e6704d/librt-0.10.0-cp313-cp313-win_arm64.whl", hash = "sha256:afc5b4406c8e2515698d922a5c7823a009312835ea58196671fff40e35cb8166", size = 61336, upload-time = "2026-05-05T16:30:19.021Z" },
- { url = "https://files.pythonhosted.org/packages/6a/64/7165e08108cc185a13a9c069f0685e6ef92e70e07fddf7edf5e7348c6316/librt-0.10.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:f09588a30e6a22ec624090d72a3ab1a6d4d5485c3ed739603e76aa3c16efa688", size = 76794, upload-time = "2026-05-05T16:30:20.392Z" },
- { url = "https://files.pythonhosted.org/packages/ae/ef/bf8613febf651b90c5222ee79dea5ae58d4cc2b544df69d3033424448934/librt-0.10.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:131ade118d12bd7a0adc4e655474a553f1b76cf78385868885944d21d51e45e0", size = 79662, upload-time = "2026-05-05T16:30:22.025Z" },
- { url = "https://files.pythonhosted.org/packages/b6/67/9eddd165c1d8397bdf99b38bf12b5a55b3def5035b49eedb49f2775d1430/librt-0.10.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8b9ab28e40d011c373a189eae900c916e66d6fbecf7983e9e4883089ee085ef", size = 242390, upload-time = "2026-05-05T16:30:23.51Z" },
- { url = "https://files.pythonhosted.org/packages/10/d1/d95da80334501866cd37004ab5d7483220d05862fab4b5405394f0264f0d/librt-0.10.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:67c39bb30da73bae1f293d1ed8bc2f8f6642649dd0928d3600aeff3041ac23d6", size = 232603, upload-time = "2026-05-05T16:30:25.198Z" },
- { url = "https://files.pythonhosted.org/packages/0c/fa/e6d64d28718bc1be4e1736fcb037ca1c4dfca927e7167df75a7d5215665e/librt-0.10.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8c3273c6b774614f093c8927c2bf1b077d0fefde988fe98f46a333734e5597ab", size = 259187, upload-time = "2026-05-05T16:30:26.772Z" },
- { url = "https://files.pythonhosted.org/packages/72/3f/3fdb77e7f937dad59cfd76b720be7e7643400ec76b2da35befab8d66ba30/librt-0.10.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9dd7c1b86a4baa583ab5db977484b93a2c474e69e96ef3e9538387ea54229cb9", size = 251846, upload-time = "2026-05-05T16:30:28.56Z" },
- { url = "https://files.pythonhosted.org/packages/18/ca/f4d49133dd86a6f55d79eca30bf412fa722f511a9abe67f62f57aa64e66a/librt-0.10.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a77385c5a202e831149f7ad03be9e67cf80e957e52c614e83dcb822c95222eb8", size = 264936, upload-time = "2026-05-05T16:30:30.491Z" },
- { url = "https://files.pythonhosted.org/packages/de/66/a8df2fbadc1f6c1827a096d11c40175bd526133480bd3bc88ec64a03d257/librt-0.10.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c6a5eafa74b5655bad59886138ed68426f098a6beb8cb95a71f2cc3cd8bb33fe", size = 258699, upload-time = "2026-05-05T16:30:32.002Z" },
- { url = "https://files.pythonhosted.org/packages/bb/73/1e3c83613fe05451bb969e27b68a573d177f08d5f63533cc29fec0989658/librt-0.10.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:1fc93d0439204c50ab4d1512611ce2c206f1b369b419f69c7c27c761561e3291", size = 259825, upload-time = "2026-05-05T16:30:35.077Z" },
- { url = "https://files.pythonhosted.org/packages/09/24/5e2f926ee9d3ef348d9339526d7062abb5c44d8419e3179528c01d78c102/librt-0.10.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:79e713c178bc7a744adfbee6b4619a288eecc0c914da2a9313a20255abe2f0cf", size = 282548, upload-time = "2026-05-05T16:30:36.639Z" },
- { url = "https://files.pythonhosted.org/packages/fc/7d/3e89ed6ad0162561fa8bef9df3195e24263104c955713cd0237d3711fad2/librt-0.10.0-cp314-cp314-win32.whl", hash = "sha256:2eba9d955a68c41d9f326be3da42f163ec3518b7ab20f1c826224e7bed71e0bf", size = 58970, upload-time = "2026-05-05T16:30:38.183Z" },
- { url = "https://files.pythonhosted.org/packages/76/25/579e731c94a7086a268bfa3e7a4945cd47836bebd3cbf3faeafd2e7eaef9/librt-0.10.0-cp314-cp314-win_amd64.whl", hash = "sha256:cbfaf7f5145e9917f5d18bffa298eff6a19d74e7b8b11dabdca95785befe8dbf", size = 67260, upload-time = "2026-05-05T16:30:39.804Z" },
- { url = "https://files.pythonhosted.org/packages/6e/f8/235822b7ae0b2334f12ee18bcf2476d07924077a5efeea57dbe927704be2/librt-0.10.0-cp314-cp314-win_arm64.whl", hash = "sha256:8d6d385d1969849a6b1397114df22714b6ded917bada98668e3e974dc663477e", size = 57156, upload-time = "2026-05-05T16:30:41.412Z" },
- { url = "https://files.pythonhosted.org/packages/9f/e3/9b919cbf1e8eb770bf91bb7df28125e0f1daf4587169afefd95402636e9a/librt-0.10.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:6c3a82d3bd32631ef5c79922dfc028520c9ad840255979ab4d908271818039ee", size = 79150, upload-time = "2026-05-05T16:30:42.761Z" },
- { url = "https://files.pythonhosted.org/packages/6a/f5/72a944aa3bc3498169a168087eff58ca48b58bf1b704e59d091fd30739f3/librt-0.10.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d64cc66005dc324c9bb1fa3fc2841f529002f6eb15966d55e46d430f56955a6a", size = 82304, upload-time = "2026-05-05T16:30:44.082Z" },
- { url = "https://files.pythonhosted.org/packages/9c/e3/fcc290a33e295019759472dfa794d204e43504b276ac65eab7fd9da20ea3/librt-0.10.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9bb562cd28c88cd2c6a9a6c78f99dc39348d6b16c94adc25de0e574acf1176e9", size = 272556, upload-time = "2026-05-05T16:30:45.497Z" },
- { url = "https://files.pythonhosted.org/packages/fd/54/546975e4c997573885e7f040a05012f8838e06fb12b0c3c1fbb76254e9d7/librt-0.10.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:b809aa2854d019c28773b03605df22adc675ee4f3f4402d673581313e8906119", size = 256941, upload-time = "2026-05-05T16:30:47.059Z" },
- { url = "https://files.pythonhosted.org/packages/70/8c/f1d03401571b331653acddbd4e8cd955c06d945241dd08b25192fac0d04b/librt-0.10.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cc15acabdd519bd4176fdadc2119e5e3093485d86f89138daf47e5b4cedb983a", size = 285855, upload-time = "2026-05-05T16:30:48.86Z" },
- { url = "https://files.pythonhosted.org/packages/0c/08/62cf80ff046c339faf56718b3a940244d4beb70f1c6407289b5830ec11e9/librt-0.10.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b1b2d835307d08ddadd94568e2369648ec9173bd3eea6d7f52a1abe717c81f98", size = 275321, upload-time = "2026-05-05T16:30:50.63Z" },
- { url = "https://files.pythonhosted.org/packages/d9/ea/da5918d4070362e9a4d2ee9cd34f9dc84902daad8fd4275f8504a727ff4e/librt-0.10.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d261c6a2f93335a5167887fb0223e8b98ffce20ee3fde242e8e58a37ece6d0e5", size = 293993, upload-time = "2026-05-05T16:30:52.577Z" },
- { url = "https://files.pythonhosted.org/packages/c9/8d/68b6086bed1fcdc314c640ea04e31e52d18052e08059fa595409d66a51a9/librt-0.10.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e2ffd44963f8e7f68995504d90f9881d64e94dc1d8e310039b9526108fc0c0f7", size = 284254, upload-time = "2026-05-05T16:30:55.086Z" },
- { url = "https://files.pythonhosted.org/packages/06/c8/b810f1d84ec34a5a7ed93d7b510ab04164d75fbdf23088d5c3fbe6b08357/librt-0.10.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:5f285f6455ed495791c4d8630e5af732960adea93cac4c893d15619f2eae53e8", size = 284925, upload-time = "2026-05-05T16:30:56.728Z" },
- { url = "https://files.pythonhosted.org/packages/5a/00/3c82d4158c5a2c62528b8fccce65a8c9ad700e480e86f9389387435089a5/librt-0.10.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f6034ff52e663d34c7b82ef2aa2f94ad7c1d939e2368e63b06844bc4d127d2e1", size = 307830, upload-time = "2026-05-05T16:30:58.377Z" },
- { url = "https://files.pythonhosted.org/packages/99/3a/9c635ac3e8a00383ff689161d3eac8a30b3b2ddc711b40471e6b8983ea29/librt-0.10.0-cp314-cp314t-win32.whl", hash = "sha256:657860fd877fba6a241ea088ef99f63ca819945d3c715265da670bad56c37ebe", size = 60147, upload-time = "2026-05-05T16:31:00.293Z" },
- { url = "https://files.pythonhosted.org/packages/dc/e8/6f65f3e565d4ac212cddddd552eacc8035ffdf941ca0ad6fe945a211d41f/librt-0.10.0-cp314-cp314t-win_amd64.whl", hash = "sha256:56ded2d66010203a0cb5af063b609e3f079531a0e5e576d618dece859fd2e1af", size = 68649, upload-time = "2026-05-05T16:31:01.778Z" },
- { url = "https://files.pythonhosted.org/packages/51/78/a0705a67cacd81e5fa01a5035b3adbdfbb43a7b8d4bd27e2b282ae61baf2/librt-0.10.0-cp314-cp314t-win_arm64.whl", hash = "sha256:1ee63f30abf18ed4830fdbaf87b2b6f4bba1e198d46085c314edde4045e56715", size = 58247, upload-time = "2026-05-05T16:31:03.191Z" },
-]
-
-[[package]]
-name = "multidict"
-version = "6.7.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/8d/9c/f20e0e2cf80e4b2e4b1c365bf5fe104ee633c751a724246262db8f1a0b13/multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172", size = 76893, upload-time = "2026-01-26T02:43:52.754Z" },
- { url = "https://files.pythonhosted.org/packages/fe/cf/18ef143a81610136d3da8193da9d80bfe1cb548a1e2d1c775f26b23d024a/multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd", size = 45456, upload-time = "2026-01-26T02:43:53.893Z" },
- { url = "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7", size = 43872, upload-time = "2026-01-26T02:43:55.041Z" },
- { url = "https://files.pythonhosted.org/packages/cf/3b/d6bd75dc4f3ff7c73766e04e705b00ed6dbbaccf670d9e05a12b006f5a21/multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53", size = 251018, upload-time = "2026-01-26T02:43:56.198Z" },
- { url = "https://files.pythonhosted.org/packages/fd/80/c959c5933adedb9ac15152e4067c702a808ea183a8b64cf8f31af8ad3155/multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75", size = 258883, upload-time = "2026-01-26T02:43:57.499Z" },
- { url = "https://files.pythonhosted.org/packages/86/85/7ed40adafea3d4f1c8b916e3b5cc3a8e07dfcdcb9cd72800f4ed3ca1b387/multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b", size = 242413, upload-time = "2026-01-26T02:43:58.755Z" },
- { url = "https://files.pythonhosted.org/packages/d2/57/b8565ff533e48595503c785f8361ff9a4fde4d67de25c207cd0ba3befd03/multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733", size = 268404, upload-time = "2026-01-26T02:44:00.216Z" },
- { url = "https://files.pythonhosted.org/packages/e0/50/9810c5c29350f7258180dfdcb2e52783a0632862eb334c4896ac717cebcb/multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a", size = 269456, upload-time = "2026-01-26T02:44:02.202Z" },
- { url = "https://files.pythonhosted.org/packages/f3/8d/5e5be3ced1d12966fefb5c4ea3b2a5b480afcea36406559442c6e31d4a48/multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961", size = 256322, upload-time = "2026-01-26T02:44:03.56Z" },
- { url = "https://files.pythonhosted.org/packages/31/6e/d8a26d81ac166a5592782d208dd90dfdc0a7a218adaa52b45a672b46c122/multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582", size = 253955, upload-time = "2026-01-26T02:44:04.845Z" },
- { url = "https://files.pythonhosted.org/packages/59/4c/7c672c8aad41534ba619bcd4ade7a0dc87ed6b8b5c06149b85d3dd03f0cd/multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e", size = 251254, upload-time = "2026-01-26T02:44:06.133Z" },
- { url = "https://files.pythonhosted.org/packages/7b/bd/84c24de512cbafbdbc39439f74e967f19570ce7924e3007174a29c348916/multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3", size = 252059, upload-time = "2026-01-26T02:44:07.518Z" },
- { url = "https://files.pythonhosted.org/packages/fa/ba/f5449385510825b73d01c2d4087bf6d2fccc20a2d42ac34df93191d3dd03/multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6", size = 263588, upload-time = "2026-01-26T02:44:09.382Z" },
- { url = "https://files.pythonhosted.org/packages/d7/11/afc7c677f68f75c84a69fe37184f0f82fce13ce4b92f49f3db280b7e92b3/multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a", size = 259642, upload-time = "2026-01-26T02:44:10.73Z" },
- { url = "https://files.pythonhosted.org/packages/2b/17/ebb9644da78c4ab36403739e0e6e0e30ebb135b9caf3440825001a0bddcb/multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba", size = 251377, upload-time = "2026-01-26T02:44:12.042Z" },
- { url = "https://files.pythonhosted.org/packages/ca/a4/840f5b97339e27846c46307f2530a2805d9d537d8b8bd416af031cad7fa0/multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511", size = 41887, upload-time = "2026-01-26T02:44:14.245Z" },
- { url = "https://files.pythonhosted.org/packages/80/31/0b2517913687895f5904325c2069d6a3b78f66cc641a86a2baf75a05dcbb/multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19", size = 46053, upload-time = "2026-01-26T02:44:15.371Z" },
- { url = "https://files.pythonhosted.org/packages/0c/5b/aba28e4ee4006ae4c7df8d327d31025d760ffa992ea23812a601d226e682/multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf", size = 43307, upload-time = "2026-01-26T02:44:16.852Z" },
- { url = "https://files.pythonhosted.org/packages/f2/22/929c141d6c0dba87d3e1d38fbdf1ba8baba86b7776469f2bc2d3227a1e67/multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23", size = 76174, upload-time = "2026-01-26T02:44:18.509Z" },
- { url = "https://files.pythonhosted.org/packages/c7/75/bc704ae15fee974f8fccd871305e254754167dce5f9e42d88a2def741a1d/multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2", size = 45116, upload-time = "2026-01-26T02:44:19.745Z" },
- { url = "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445", size = 43524, upload-time = "2026-01-26T02:44:21.571Z" },
- { url = "https://files.pythonhosted.org/packages/e9/3c/414842ef8d5a1628d68edee29ba0e5bcf235dbfb3ccd3ea303a7fe8c72ff/multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177", size = 249368, upload-time = "2026-01-26T02:44:22.803Z" },
- { url = "https://files.pythonhosted.org/packages/f6/32/befed7f74c458b4a525e60519fe8d87eef72bb1e99924fa2b0f9d97a221e/multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23", size = 256952, upload-time = "2026-01-26T02:44:24.306Z" },
- { url = "https://files.pythonhosted.org/packages/03/d6/c878a44ba877f366630c860fdf74bfb203c33778f12b6ac274936853c451/multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060", size = 240317, upload-time = "2026-01-26T02:44:25.772Z" },
- { url = "https://files.pythonhosted.org/packages/68/49/57421b4d7ad2e9e60e25922b08ceb37e077b90444bde6ead629095327a6f/multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d", size = 267132, upload-time = "2026-01-26T02:44:27.648Z" },
- { url = "https://files.pythonhosted.org/packages/b7/fe/ec0edd52ddbcea2a2e89e174f0206444a61440b40f39704e64dc807a70bd/multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed", size = 268140, upload-time = "2026-01-26T02:44:29.588Z" },
- { url = "https://files.pythonhosted.org/packages/b0/73/6e1b01cbeb458807aa0831742232dbdd1fa92bfa33f52a3f176b4ff3dc11/multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429", size = 254277, upload-time = "2026-01-26T02:44:30.902Z" },
- { url = "https://files.pythonhosted.org/packages/6a/b2/5fb8c124d7561a4974c342bc8c778b471ebbeb3cc17df696f034a7e9afe7/multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6", size = 252291, upload-time = "2026-01-26T02:44:32.31Z" },
- { url = "https://files.pythonhosted.org/packages/5a/96/51d4e4e06bcce92577fcd488e22600bd38e4fd59c20cb49434d054903bd2/multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9", size = 250156, upload-time = "2026-01-26T02:44:33.734Z" },
- { url = "https://files.pythonhosted.org/packages/db/6b/420e173eec5fba721a50e2a9f89eda89d9c98fded1124f8d5c675f7a0c0f/multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c", size = 249742, upload-time = "2026-01-26T02:44:35.222Z" },
- { url = "https://files.pythonhosted.org/packages/44/a3/ec5b5bd98f306bc2aa297b8c6f11a46714a56b1e6ef5ebda50a4f5d7c5fb/multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84", size = 262221, upload-time = "2026-01-26T02:44:36.604Z" },
- { url = "https://files.pythonhosted.org/packages/cd/f7/e8c0d0da0cd1e28d10e624604e1a36bcc3353aaebdfdc3a43c72bc683a12/multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d", size = 258664, upload-time = "2026-01-26T02:44:38.008Z" },
- { url = "https://files.pythonhosted.org/packages/52/da/151a44e8016dd33feed44f730bd856a66257c1ee7aed4f44b649fb7edeb3/multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33", size = 249490, upload-time = "2026-01-26T02:44:39.386Z" },
- { url = "https://files.pythonhosted.org/packages/87/af/a3b86bf9630b732897f6fc3f4c4714b90aa4361983ccbdcd6c0339b21b0c/multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3", size = 41695, upload-time = "2026-01-26T02:44:41.318Z" },
- { url = "https://files.pythonhosted.org/packages/b2/35/e994121b0e90e46134673422dd564623f93304614f5d11886b1b3e06f503/multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5", size = 45884, upload-time = "2026-01-26T02:44:42.488Z" },
- { url = "https://files.pythonhosted.org/packages/ca/61/42d3e5dbf661242a69c97ea363f2d7b46c567da8eadef8890022be6e2ab0/multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df", size = 43122, upload-time = "2026-01-26T02:44:43.664Z" },
- { url = "https://files.pythonhosted.org/packages/6d/b3/e6b21c6c4f314bb956016b0b3ef2162590a529b84cb831c257519e7fde44/multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1", size = 83175, upload-time = "2026-01-26T02:44:44.894Z" },
- { url = "https://files.pythonhosted.org/packages/fb/76/23ecd2abfe0957b234f6c960f4ade497f55f2c16aeb684d4ecdbf1c95791/multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963", size = 48460, upload-time = "2026-01-26T02:44:46.106Z" },
- { url = "https://files.pythonhosted.org/packages/c4/57/a0ed92b23f3a042c36bc4227b72b97eca803f5f1801c1ab77c8a212d455e/multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34", size = 46930, upload-time = "2026-01-26T02:44:47.278Z" },
- { url = "https://files.pythonhosted.org/packages/b5/66/02ec7ace29162e447f6382c495dc95826bf931d3818799bbef11e8f7df1a/multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65", size = 242582, upload-time = "2026-01-26T02:44:48.604Z" },
- { url = "https://files.pythonhosted.org/packages/58/18/64f5a795e7677670e872673aca234162514696274597b3708b2c0d276cce/multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292", size = 250031, upload-time = "2026-01-26T02:44:50.544Z" },
- { url = "https://files.pythonhosted.org/packages/c8/ed/e192291dbbe51a8290c5686f482084d31bcd9d09af24f63358c3d42fd284/multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43", size = 228596, upload-time = "2026-01-26T02:44:51.951Z" },
- { url = "https://files.pythonhosted.org/packages/1e/7e/3562a15a60cf747397e7f2180b0a11dc0c38d9175a650e75fa1b4d325e15/multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca", size = 257492, upload-time = "2026-01-26T02:44:53.902Z" },
- { url = "https://files.pythonhosted.org/packages/24/02/7d0f9eae92b5249bb50ac1595b295f10e263dd0078ebb55115c31e0eaccd/multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd", size = 255899, upload-time = "2026-01-26T02:44:55.316Z" },
- { url = "https://files.pythonhosted.org/packages/00/e3/9b60ed9e23e64c73a5cde95269ef1330678e9c6e34dd4eb6b431b85b5a10/multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7", size = 247970, upload-time = "2026-01-26T02:44:56.783Z" },
- { url = "https://files.pythonhosted.org/packages/3e/06/538e58a63ed5cfb0bd4517e346b91da32fde409d839720f664e9a4ae4f9d/multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3", size = 245060, upload-time = "2026-01-26T02:44:58.195Z" },
- { url = "https://files.pythonhosted.org/packages/b2/2f/d743a3045a97c895d401e9bd29aaa09b94f5cbdf1bd561609e5a6c431c70/multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4", size = 235888, upload-time = "2026-01-26T02:44:59.57Z" },
- { url = "https://files.pythonhosted.org/packages/38/83/5a325cac191ab28b63c52f14f1131f3b0a55ba3b9aa65a6d0bf2a9b921a0/multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8", size = 243554, upload-time = "2026-01-26T02:45:01.054Z" },
- { url = "https://files.pythonhosted.org/packages/20/1f/9d2327086bd15da2725ef6aae624208e2ef828ed99892b17f60c344e57ed/multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c", size = 252341, upload-time = "2026-01-26T02:45:02.484Z" },
- { url = "https://files.pythonhosted.org/packages/e8/2c/2a1aa0280cf579d0f6eed8ee5211c4f1730bd7e06c636ba2ee6aafda302e/multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52", size = 246391, upload-time = "2026-01-26T02:45:03.862Z" },
- { url = "https://files.pythonhosted.org/packages/e5/03/7ca022ffc36c5a3f6e03b179a5ceb829be9da5783e6fe395f347c0794680/multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108", size = 243422, upload-time = "2026-01-26T02:45:05.296Z" },
- { url = "https://files.pythonhosted.org/packages/dc/1d/b31650eab6c5778aceed46ba735bd97f7c7d2f54b319fa916c0f96e7805b/multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32", size = 47770, upload-time = "2026-01-26T02:45:06.754Z" },
- { url = "https://files.pythonhosted.org/packages/ac/5b/2d2d1d522e51285bd61b1e20df8f47ae1a9d80839db0b24ea783b3832832/multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8", size = 53109, upload-time = "2026-01-26T02:45:08.044Z" },
- { url = "https://files.pythonhosted.org/packages/3d/a3/cc409ba012c83ca024a308516703cf339bdc4b696195644a7215a5164a24/multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118", size = 45573, upload-time = "2026-01-26T02:45:09.349Z" },
- { url = "https://files.pythonhosted.org/packages/91/cc/db74228a8be41884a567e88a62fd589a913708fcf180d029898c17a9a371/multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee", size = 75190, upload-time = "2026-01-26T02:45:10.651Z" },
- { url = "https://files.pythonhosted.org/packages/d5/22/492f2246bb5b534abd44804292e81eeaf835388901f0c574bac4eeec73c5/multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2", size = 44486, upload-time = "2026-01-26T02:45:11.938Z" },
- { url = "https://files.pythonhosted.org/packages/f1/4f/733c48f270565d78b4544f2baddc2fb2a245e5a8640254b12c36ac7ac68e/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1", size = 43219, upload-time = "2026-01-26T02:45:14.346Z" },
- { url = "https://files.pythonhosted.org/packages/24/bb/2c0c2287963f4259c85e8bcbba9182ced8d7fca65c780c38e99e61629d11/multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d", size = 245132, upload-time = "2026-01-26T02:45:15.712Z" },
- { url = "https://files.pythonhosted.org/packages/a7/f9/44d4b3064c65079d2467888794dea218d1601898ac50222ab8a9a8094460/multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31", size = 252420, upload-time = "2026-01-26T02:45:17.293Z" },
- { url = "https://files.pythonhosted.org/packages/8b/13/78f7275e73fa17b24c9a51b0bd9d73ba64bb32d0ed51b02a746eb876abe7/multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048", size = 233510, upload-time = "2026-01-26T02:45:19.356Z" },
- { url = "https://files.pythonhosted.org/packages/4b/25/8167187f62ae3cbd52da7893f58cb036b47ea3fb67138787c76800158982/multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362", size = 264094, upload-time = "2026-01-26T02:45:20.834Z" },
- { url = "https://files.pythonhosted.org/packages/a1/e7/69a3a83b7b030cf283fb06ce074a05a02322359783424d7edf0f15fe5022/multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37", size = 260786, upload-time = "2026-01-26T02:45:22.818Z" },
- { url = "https://files.pythonhosted.org/packages/fe/3b/8ec5074bcfc450fe84273713b4b0a0dd47c0249358f5d82eb8104ffe2520/multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709", size = 248483, upload-time = "2026-01-26T02:45:24.368Z" },
- { url = "https://files.pythonhosted.org/packages/48/5a/d5a99e3acbca0e29c5d9cba8f92ceb15dce78bab963b308ae692981e3a5d/multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0", size = 248403, upload-time = "2026-01-26T02:45:25.982Z" },
- { url = "https://files.pythonhosted.org/packages/35/48/e58cd31f6c7d5102f2a4bf89f96b9cf7e00b6c6f3d04ecc44417c00a5a3c/multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb", size = 240315, upload-time = "2026-01-26T02:45:27.487Z" },
- { url = "https://files.pythonhosted.org/packages/94/33/1cd210229559cb90b6786c30676bb0c58249ff42f942765f88793b41fdce/multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd", size = 245528, upload-time = "2026-01-26T02:45:28.991Z" },
- { url = "https://files.pythonhosted.org/packages/64/f2/6e1107d226278c876c783056b7db43d800bb64c6131cec9c8dfb6903698e/multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601", size = 258784, upload-time = "2026-01-26T02:45:30.503Z" },
- { url = "https://files.pythonhosted.org/packages/4d/c1/11f664f14d525e4a1b5327a82d4de61a1db604ab34c6603bb3c2cc63ad34/multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1", size = 251980, upload-time = "2026-01-26T02:45:32.603Z" },
- { url = "https://files.pythonhosted.org/packages/e1/9f/75a9ac888121d0c5bbd4ecf4eead45668b1766f6baabfb3b7f66a410e231/multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b", size = 243602, upload-time = "2026-01-26T02:45:34.043Z" },
- { url = "https://files.pythonhosted.org/packages/9a/e7/50bf7b004cc8525d80dbbbedfdc7aed3e4c323810890be4413e589074032/multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d", size = 40930, upload-time = "2026-01-26T02:45:36.278Z" },
- { url = "https://files.pythonhosted.org/packages/e0/bf/52f25716bbe93745595800f36fb17b73711f14da59ed0bb2eba141bc9f0f/multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f", size = 45074, upload-time = "2026-01-26T02:45:37.546Z" },
- { url = "https://files.pythonhosted.org/packages/97/ab/22803b03285fa3a525f48217963da3a65ae40f6a1b6f6cf2768879e208f9/multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5", size = 42471, upload-time = "2026-01-26T02:45:38.889Z" },
- { url = "https://files.pythonhosted.org/packages/e0/6d/f9293baa6146ba9507e360ea0292b6422b016907c393e2f63fc40ab7b7b5/multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581", size = 82401, upload-time = "2026-01-26T02:45:40.254Z" },
- { url = "https://files.pythonhosted.org/packages/7a/68/53b5494738d83558d87c3c71a486504d8373421c3e0dbb6d0db48ad42ee0/multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a", size = 48143, upload-time = "2026-01-26T02:45:41.635Z" },
- { url = "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c", size = 46507, upload-time = "2026-01-26T02:45:42.99Z" },
- { url = "https://files.pythonhosted.org/packages/e4/fc/6800d0e5b3875568b4083ecf5f310dcf91d86d52573160834fb4bfcf5e4f/multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262", size = 239358, upload-time = "2026-01-26T02:45:44.376Z" },
- { url = "https://files.pythonhosted.org/packages/41/75/4ad0973179361cdf3a113905e6e088173198349131be2b390f9fa4da5fc6/multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59", size = 246884, upload-time = "2026-01-26T02:45:47.167Z" },
- { url = "https://files.pythonhosted.org/packages/c3/9c/095bb28b5da139bd41fb9a5d5caff412584f377914bd8787c2aa98717130/multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889", size = 225878, upload-time = "2026-01-26T02:45:48.698Z" },
- { url = "https://files.pythonhosted.org/packages/07/d0/c0a72000243756e8f5a277b6b514fa005f2c73d481b7d9e47cd4568aa2e4/multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4", size = 253542, upload-time = "2026-01-26T02:45:50.164Z" },
- { url = "https://files.pythonhosted.org/packages/c0/6b/f69da15289e384ecf2a68837ec8b5ad8c33e973aa18b266f50fe55f24b8c/multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d", size = 252403, upload-time = "2026-01-26T02:45:51.779Z" },
- { url = "https://files.pythonhosted.org/packages/a2/76/b9669547afa5a1a25cd93eaca91c0da1c095b06b6d2d8ec25b713588d3a1/multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609", size = 244889, upload-time = "2026-01-26T02:45:53.27Z" },
- { url = "https://files.pythonhosted.org/packages/7e/a9/a50d2669e506dad33cfc45b5d574a205587b7b8a5f426f2fbb2e90882588/multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489", size = 241982, upload-time = "2026-01-26T02:45:54.919Z" },
- { url = "https://files.pythonhosted.org/packages/c5/bb/1609558ad8b456b4827d3c5a5b775c93b87878fd3117ed3db3423dfbce1b/multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c", size = 232415, upload-time = "2026-01-26T02:45:56.981Z" },
- { url = "https://files.pythonhosted.org/packages/d8/59/6f61039d2aa9261871e03ab9dc058a550d240f25859b05b67fd70f80d4b3/multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e", size = 240337, upload-time = "2026-01-26T02:45:58.698Z" },
- { url = "https://files.pythonhosted.org/packages/a1/29/fdc6a43c203890dc2ae9249971ecd0c41deaedfe00d25cb6564b2edd99eb/multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c", size = 248788, upload-time = "2026-01-26T02:46:00.862Z" },
- { url = "https://files.pythonhosted.org/packages/a9/14/a153a06101323e4cf086ecee3faadba52ff71633d471f9685c42e3736163/multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9", size = 242842, upload-time = "2026-01-26T02:46:02.824Z" },
- { url = "https://files.pythonhosted.org/packages/41/5f/604ae839e64a4a6efc80db94465348d3b328ee955e37acb24badbcd24d83/multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2", size = 240237, upload-time = "2026-01-26T02:46:05.898Z" },
- { url = "https://files.pythonhosted.org/packages/5f/60/c3a5187bf66f6fb546ff4ab8fb5a077cbdd832d7b1908d4365c7f74a1917/multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7", size = 48008, upload-time = "2026-01-26T02:46:07.468Z" },
- { url = "https://files.pythonhosted.org/packages/0c/f7/addf1087b860ac60e6f382240f64fb99f8bfb532bb06f7c542b83c29ca61/multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5", size = 53542, upload-time = "2026-01-26T02:46:08.809Z" },
- { url = "https://files.pythonhosted.org/packages/4c/81/4629d0aa32302ef7b2ec65c75a728cc5ff4fa410c50096174c1632e70b3e/multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2", size = 44719, upload-time = "2026-01-26T02:46:11.146Z" },
- { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" },
-]
-
-[[package]]
-name = "mypy"
-version = "2.0.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "ast-serialize" },
- { name = "librt", marker = "platform_python_implementation != 'PyPy'" },
- { name = "mypy-extensions" },
- { name = "pathspec" },
- { name = "typing-extensions" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/cf/dc/7e6d49f04fca40b9dd5c752a51a432ffe67fb45200702bc9eee0cb4bbb26/mypy-2.0.0.tar.gz", hash = "sha256:1a9e3900ac5c40f1fe813506c7739da6e6f0eab2729067ebd94bfb0bbba53532", size = 3869036, upload-time = "2026-05-06T19:26:43.22Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/f6/4b/f6cd12ef1eb63be1c342da3e8ca811d2280276177f6de4ef20cb2366d79b/mypy-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:660790551c988e69d8bf7a35c8b4149edeb22f4a339165702be843532e9dcdb5", size = 14756610, upload-time = "2026-05-06T19:26:19.221Z" },
- { url = "https://files.pythonhosted.org/packages/32/73/67d09ca28bee21feaca264b2a680cf2d300bcc2071136ad064928324c843/mypy-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7a15bf92cd8781f8e72f69ffa7e30d1f434402d065ee1ecd5223ef2ef100f914", size = 13554270, upload-time = "2026-05-06T19:26:08.977Z" },
- { url = "https://files.pythonhosted.org/packages/61/b3/44718b5c6b1b5a27440ff2effe6a1be0fa2a190c0f4e2e21a83728416f95/mypy-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4ff370b43d7def05bbcd2f5267f0bcda72dd6a552ef2ea9375b02d6fe06da270", size = 13924663, upload-time = "2026-05-06T19:21:24.932Z" },
- { url = "https://files.pythonhosted.org/packages/6a/2b/bbb9cc5773f946846a7c340097e59bcf84095437dda0d56bb4f6cf1f6541/mypy-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:37bd246590a018e5a11703b7b09c39d47ede3df5ba3fa863c5b8590b465beb01", size = 14946862, upload-time = "2026-05-06T19:24:23.023Z" },
- { url = "https://files.pythonhosted.org/packages/43/25/e9318566f443a5130b4ff0ad3367ee6c4c4c49ff083fe5214a7318c18282/mypy-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cce87e92214fac8bf8feb8a680d0c1b6fb748d50e9b57fbb13e4b1d83a3ed19b", size = 15175090, upload-time = "2026-05-06T19:26:28.794Z" },
- { url = "https://files.pythonhosted.org/packages/67/65/2ec28c834f21e164c33bc296a7db538ad50c74f83e517c7a0be95ff6de86/mypy-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:e19e9cb69b66a4141009d24898259914fa2b71d026de0b46edf9fafdbf4fd46e", size = 11052899, upload-time = "2026-05-06T19:25:39.084Z" },
- { url = "https://files.pythonhosted.org/packages/9e/72/d1ec625cfc9bd101c07a6834ef1f94e820296f8fdbad2eb03f50e0983f8c/mypy-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:b021614cb08d44785b025982163ec3c39c94bff766ead071fa9e82b4ef6f62cd", size = 9972935, upload-time = "2026-05-06T19:23:24.204Z" },
- { url = "https://files.pythonhosted.org/packages/e5/c6/996a1e535e5d0d597c3b1460fc962733091f885f312e749350eb2ac10965/mypy-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ef5f581b61240d1cc629b12f8df6565ed6ffac0d82ed745eef7833222ab50b9", size = 14737259, upload-time = "2026-05-06T19:20:23.081Z" },
- { url = "https://files.pythonhosted.org/packages/94/c5/0f9460e26b77f434bd53f47d1ce32a3cd4580c92a5331fa5dfc059f9421a/mypy-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:20e3470a165dbc249bdfbe8d1c5172727ef22688cffc279f8c3aa264ab9d4d9a", size = 13538377, upload-time = "2026-05-06T19:21:08.804Z" },
- { url = "https://files.pythonhosted.org/packages/b2/3e/8ea2f8dd1e5c9c279fb3c28193bdb850adf4d3d8172880abad829eced609/mypy-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:224ba142eee8b4d65d4db657cb1fc22abec30b135ded6ab297302ba1f62e505d", size = 13914264, upload-time = "2026-05-06T19:24:12.875Z" },
- { url = "https://files.pythonhosted.org/packages/be/ce/78bd3b8520f676acee9dab48ea71473e68f6d5cf14b59fbd800bea50a92b/mypy-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e879ad8a03908ff74d15e8a9b42bf049918e6798d52c011011f1873d0b5877e", size = 14926761, upload-time = "2026-05-06T19:20:12.846Z" },
- { url = "https://files.pythonhosted.org/packages/61/ef/b52fa340522da3d22e669117c3b83155c2660f7cdc035856958fbfffb224/mypy-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:65c5c15bcbd18d6fe927cc55c459597a3517d69cc3123f067be3b020010e115e", size = 15157014, upload-time = "2026-05-06T19:25:49.78Z" },
- { url = "https://files.pythonhosted.org/packages/7a/0c/dde7614250c6d017936c7aa3bb63b9b52c7cfd298d3f1be9be45f307870b/mypy-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:d1a068acd7c9fb77e9f8923f1556f2f49d6d7895821121b8d97fa5642b9c52f5", size = 11067049, upload-time = "2026-05-06T19:21:16.116Z" },
- { url = "https://files.pythonhosted.org/packages/27/ec/1d6af4830a94a285442db19caa02f160cc1a255e4f324eec5458e6c2bafb/mypy-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:ef9d96da1ddffbc21f27d3939319b6846d12393baa17c4d2f3e81e040e73ce2c", size = 9967903, upload-time = "2026-05-06T19:22:15.52Z" },
- { url = "https://files.pythonhosted.org/packages/ce/2c/6fefe954207860aed6eeb91776795e64a257d3ce0360862288984ce121f5/mypy-2.0.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c918c64e8ce36557851b0347f84eb12f1965d3a06813c36df253eb0c0afd1d82", size = 14729633, upload-time = "2026-05-06T19:24:53.383Z" },
- { url = "https://files.pythonhosted.org/packages/23/d6/d336f5b820af189eb0390cce21de62d264c0a4e64713dfbe81bfc4fc7739/mypy-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:301f1a8ccc7d79b542ee218b28bb49443a83e194eb3d10da63ff1649e5aa5d34", size = 13559524, upload-time = "2026-05-06T19:22:24.906Z" },
- { url = "https://files.pythonhosted.org/packages/af/a6/d7bb54fde1770f0484e5fbdbdce37a41e95ed0a1cd493ec60ead111e356c/mypy-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fdf4ef489d44ce350bac3fd699907834e551d4c934e9cc862ef201215ab1558d", size = 13936018, upload-time = "2026-05-06T19:25:02.992Z" },
- { url = "https://files.pythonhosted.org/packages/7d/ba/5be51316b91e6a6bf6e3a8adb3de500e7e1fb5bf9491743b8cbc81a34a2c/mypy-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9cde2d0989f912fc850890f727d0d76495e7a6c5bdd9912a1efdb64952b4398d", size = 14910712, upload-time = "2026-05-06T19:25:21.83Z" },
- { url = "https://files.pythonhosted.org/packages/b7/37/e2c8c3b373e20ebfb66e6c83a99027fd67df4ec43b08879f74e822d2dc4c/mypy-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:cdf05693c231a14fe37dbfce192a3a1372c26a833af4a80f550547742952e719", size = 15141499, upload-time = "2026-05-06T19:20:50.924Z" },
- { url = "https://files.pythonhosted.org/packages/12/36/07756f933e00416d912e35878cfcf89a593a3350a885691c0bb85ae0226a/mypy-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:73aee2da33a2237e66cbe84a94780e53599847e86bb3aa7b93e405e8cd9905f2", size = 11240511, upload-time = "2026-05-06T19:21:32.39Z" },
- { url = "https://files.pythonhosted.org/packages/70/05/79ac1f20f2397353f3845f7b8bb5d8006cda7c8ef9092f04f9de3c6135f2/mypy-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:1f6dcd8f39971f41edab2728c877c4ac8b50ad3c387ff2770423b79a05d23910", size = 10149336, upload-time = "2026-05-06T19:22:08.383Z" },
- { url = "https://files.pythonhosted.org/packages/53/e0/0db84e0ebbad6e99e566c68e4b465784f2a2294f7719e8db9d509ef23087/mypy-2.0.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:a04e980b9275c76159da66c6e1723c7798306f9802b31bdaf9358d0c84030ce8", size = 15797362, upload-time = "2026-05-06T19:22:00.835Z" },
- { url = "https://files.pythonhosted.org/packages/0a/a4/14cc0768164dd53bec48aa41a20270b18df9bf72aa5054278bf133608315/mypy-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:33f9cf4825469b2bc73c53ba55f6d9a9b4cdb60f9e6e228745581520f29b8771", size = 14635914, upload-time = "2026-05-06T19:23:43.675Z" },
- { url = "https://files.pythonhosted.org/packages/08/48/d866a3e23b4dc5974c77d9cf65a435bf22de01a84dd4620917950e233960/mypy-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:191675c3c7dc2a5c7722a035a6909c277f14046c5e4e02aa5fbf65f8524f08ad", size = 15270866, upload-time = "2026-05-06T19:22:34.756Z" },
- { url = "https://files.pythonhosted.org/packages/71/eb/de9ef94958eb2078a6b908ceb247757dc384d3a238d3bd6ed7d81de5eaf8/mypy-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c3d26c4321a3b06fc9f04c741e0733af693f82d823f8e64e47b2e63b7f19fa84", size = 16093131, upload-time = "2026-05-06T19:23:56.541Z" },
- { url = "https://files.pythonhosted.org/packages/ad/07/0ab2c1a9d26e90942612724cbd5788f16b7810c5dd39bfcf79286c6c4524/mypy-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:bbcbc4d5917ca6ce12de70e051de7f533e3bf92d548b41a38a2232a6fe356525", size = 16330685, upload-time = "2026-05-06T19:21:42.037Z" },
- { url = "https://files.pythonhosted.org/packages/a6/8f/46f85d1371a5be642dad263828118ae1efd536d91d8bd2000c68acff3920/mypy-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:dbc6ba6d40572ae49268531565793a8f07eac7fc65ad76d482c9b4c8765b6043", size = 12752017, upload-time = "2026-05-06T19:22:44.002Z" },
- { url = "https://files.pythonhosted.org/packages/7a/e6/94ca48800cac19eb28a58188a768aaec0d16cac0f373915f073058ab0855/mypy-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:77926029dfcb7e1a3ecb0acb2ddbb24ca36be03f7d623e1759ad5376be8f6c01", size = 10527097, upload-time = "2026-05-06T19:20:58.973Z" },
- { url = "https://files.pythonhosted.org/packages/5c/14/fd0694aa594d6e9f9fd16ce821be2eff295197a273262ef56ddcc1388d68/mypy-2.0.0-py3-none-any.whl", hash = "sha256:8a92b2be3146b4fa1f062af7eb05574cbf3e6eb8e1f14704af1075423144e4e5", size = 2673434, upload-time = "2026-05-06T19:26:32.856Z" },
-]
-
-[[package]]
-name = "mypy-extensions"
-version = "1.1.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" },
-]
-
-[[package]]
-name = "nodeenv"
-version = "1.10.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" },
-]
-
-[[package]]
-name = "pathspec"
-version = "1.1.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" },
-]
-
-[[package]]
-name = "platformdirs"
-version = "4.9.6"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/9f/4a/0883b8e3802965322523f0b200ecf33d31f10991d0401162f4b23c698b42/platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a", size = 29400, upload-time = "2026-04-09T00:04:10.812Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917", size = 21348, upload-time = "2026-04-09T00:04:09.463Z" },
-]
-
-[[package]]
-name = "pre-commit"
-version = "4.6.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "cfgv" },
- { name = "identify" },
- { name = "nodeenv" },
- { name = "pyyaml" },
- { name = "virtualenv" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/8e/22/2de9408ac81acbb8a7d05d4cc064a152ccf33b3d480ebe0cd292153db239/pre_commit-4.6.0.tar.gz", hash = "sha256:718d2208cef53fdc38206e40524a6d4d9576d103eb16f0fec11c875e7716e9d9", size = 198525, upload-time = "2026-04-21T20:31:41.613Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/80/6e/4b28b62ecb6aae56769c34a8ff1d661473ec1e9519e2d5f8b2c150086b26/pre_commit-4.6.0-py2.py3-none-any.whl", hash = "sha256:e2cf246f7299edcabcf15f9b0571fdce06058527f0a06535068a86d38089f29b", size = 226472, upload-time = "2026-04-21T20:31:40.092Z" },
-]
-
-[[package]]
-name = "propcache"
-version = "0.5.2"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/ec/44/c87281c333769159c50594f22610f77398a47ccbfbbf23074e744e86f87c/propcache-0.5.2.tar.gz", hash = "sha256:01c4fc7480cd0598bb4b57022df55b9ca296da7fc5a8760bd8451a7e63a7d427", size = 50208, upload-time = "2026-05-08T21:02:12.199Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/4a/cb/e27bc2b2737a0bb49962b275efa051e8f1c35a936df7d5139b6b658b7dc9/propcache-0.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:806719138ecd720339a12410fb9614ac9b2b2d3a5fdf8235d56981c36f4039ba", size = 95887, upload-time = "2026-05-08T21:00:11.277Z" },
- { url = "https://files.pythonhosted.org/packages/e6/13/b8ae04c59392f8d11c6cd9fb4011d1dc7c86b81225c770280300e259ffe1/propcache-0.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:db2b80ea58eab4f86b2beec3cc8b39e8ff9276ac20e96b7cce43c8ae84cd6b5a", size = 54654, upload-time = "2026-05-08T21:00:12.604Z" },
- { url = "https://files.pythonhosted.org/packages/2c/7d/49777a3e20b55863d4794384a38acd460c04157b0a00f8602b0d508b8431/propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e5cbfac9f61484f7e9f3597775500cd3ebe8274e9b050c38f9525c77c97520bf", size = 55190, upload-time = "2026-05-08T21:00:13.935Z" },
- { url = "https://files.pythonhosted.org/packages/44/c7/085d0cd63062e84044e3f05797749c3f8e3938ff3aeb0eb2f69d43fafc91/propcache-0.5.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbc581d2814337da56222fab8dc5f161cd798a434e49bac27930aaef798e144", size = 59995, upload-time = "2026-05-08T21:00:15.526Z" },
- { url = "https://files.pythonhosted.org/packages/9c/42/32cf8e3009e92b2645cf1e944f701e8ea4e924dffde1ee26db860bcbf7e4/propcache-0.5.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:857187f381f88c8e2fa2fe56ab94879d011b883d5a2ee5a1b60a8cd2a06846d9", size = 63422, upload-time = "2026-05-08T21:00:16.824Z" },
- { url = "https://files.pythonhosted.org/packages/9e/1b/f112433f99fc979431b87a39ef169e3f8df070d99a72792c56d6937ac48b/propcache-0.5.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:178b4a2cdaac1818e2bf1c5a99b94383fa73ea5382e032a48dec07dc5668dc42", size = 64342, upload-time = "2026-05-08T21:00:18.362Z" },
- { url = "https://files.pythonhosted.org/packages/14/15/5574111ae50dd6e879456888c0eadd4c5a869959775854e18e18a6b345f3/propcache-0.5.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f328175a2cde1f0ff2c4ed8ce968b9dcfb55f3a7153f39e2957ed994da13476", size = 61639, upload-time = "2026-05-08T21:00:19.692Z" },
- { url = "https://files.pythonhosted.org/packages/cc/da/4d775080b1490c0ae604acda868bd71aabe3a89ed16f2aa4339eb8a283e7/propcache-0.5.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5671d09a36b06d0fd4a3da0fccbcae360e9b1570924171a15e9e0997f0249fba", size = 61588, upload-time = "2026-05-08T21:00:21.155Z" },
- { url = "https://files.pythonhosted.org/packages/04/ac/f076982cbe2195ee9cf32de5a1e46951d9fb399fc207f390562dd0fd8fb2/propcache-0.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80168e2ebe4d3ec6599d10ad8f520304ae1cad9b6c5a95372aef1b66b7bfb53a", size = 60029, upload-time = "2026-05-08T21:00:22.713Z" },
- { url = "https://files.pythonhosted.org/packages/70/60/189be62e0dd898dce3b331e1b8c7a543cd3a405ac0c81fe8ee8a9d5d77e1/propcache-0.5.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:45f11346f884bc47444f6e6647131055844134c3175b629f84952e2b5cd62b64", size = 56774, upload-time = "2026-05-08T21:00:24.001Z" },
- { url = "https://files.pythonhosted.org/packages/ea/9e/93377b9c7939c1ffae98f878dee955efadfd638078bc86dbc21f9d52f651/propcache-0.5.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8e778ebd44ef4f66ed60a0416b06b489687db264a9c0b3620362f26489492913", size = 63532, upload-time = "2026-05-08T21:00:25.545Z" },
- { url = "https://files.pythonhosted.org/packages/14/f9/590ef6cfb9b8028d516d287812ece32bb0bc5f11fbb9c8bf6b2e6313fec8/propcache-0.5.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:c0cb9ed24c8964e172768d455a38254c2dd8a552905729ce006cad3d3dda59b1", size = 61592, upload-time = "2026-05-08T21:00:27.186Z" },
- { url = "https://files.pythonhosted.org/packages/b4/5e/70958b3034c297a630bba2f17ca7abc2d5f39a803ad7e370ab79d1ecd022/propcache-0.5.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1d1ad32d9d4355e2be65574fd0bfd3677e7066b009cd5b9b2dee8aa6a6393b33", size = 64788, upload-time = "2026-05-08T21:00:28.8Z" },
- { url = "https://files.pythonhosted.org/packages/12/fd/77fe5936d8c3086ca9048f7f415f122ed82e53884a9ec193646b42deef06/propcache-0.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c80f4ba3e8f00189165999a742ee526ebeccedf6c3f7beb0c7df821e9772435a", size = 62514, upload-time = "2026-05-08T21:00:30.098Z" },
- { url = "https://files.pythonhosted.org/packages/cf/74/66bd798b5b3be70aa1b391f5cc9d6a0a5532d7fd3b19ec0b213e72e6ad9d/propcache-0.5.2-cp312-cp312-win32.whl", hash = "sha256:8c7972d8f193740d9175f0998ab38717e6cd322d5935c5b0fef8c0d323fd9031", size = 39018, upload-time = "2026-05-08T21:00:31.622Z" },
- { url = "https://files.pythonhosted.org/packages/61/7c/5c0d34aa3024694d6dcb9271cdbdd08c4e47c1c0ad95ec7e7bc74cdea145/propcache-0.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:d9ee8826a7d47863a08ac44e1a5f611a462eefc3a194b492da242128bec75b42", size = 42322, upload-time = "2026-05-08T21:00:32.918Z" },
- { url = "https://files.pythonhosted.org/packages/4d/91/875812f1a3feb20ceba818ef39fbe4d92f1081e04ac815c822496d0d038b/propcache-0.5.2-cp312-cp312-win_arm64.whl", hash = "sha256:2800a4a8ead6b28cccd1ec54b59346f0def7922ee1c7598e8499c733cfbb7c84", size = 38172, upload-time = "2026-05-08T21:00:35.124Z" },
- { url = "https://files.pythonhosted.org/packages/c5/09/f049e45385503fe67db75a6b6186a7b9f0c3930366dc960522c312a825b1/propcache-0.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:099aaf4b4d1a02265b92a977edf00b5c4f63b3b17ac6de39b0d637c9cac0188a", size = 94457, upload-time = "2026-05-08T21:00:36.355Z" },
- { url = "https://files.pythonhosted.org/packages/6b/65/83d1d05655baf63113731bd5a1008435e14f8d1e5a06cbe4ec5b23ad7a31/propcache-0.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:68ce1c44c7a813a7f71ea04315a8c7b330b63db99d059a797a4651bb6f69f117", size = 53835, upload-time = "2026-05-08T21:00:38.072Z" },
- { url = "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fc299c129490f55f254cd90be0deca4764e36e9a7c08b4aa588479a3bbed3098", size = 54545, upload-time = "2026-05-08T21:00:39.319Z" },
- { url = "https://files.pythonhosted.org/packages/a9/19/7fa086f5764c59ec8a8e157cd93aa8497acc00aba9dcdec56bfffb32602d/propcache-0.5.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a6ae2198be502c10f09b2516e7b5d019816924bc3183a43ce792a7bd6625e6f4", size = 59886, upload-time = "2026-05-08T21:00:40.621Z" },
- { url = "https://files.pythonhosted.org/packages/a1/e4/5d7663dc8235956c8f5281698a3af1d351d8820341ddd890f59d9a9127f2/propcache-0.5.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6041d31504dc1779d700e1edcfb08eea334b357620b06681a4eabb57a74e574e", size = 63261, upload-time = "2026-05-08T21:00:41.775Z" },
- { url = "https://files.pythonhosted.org/packages/4a/4a/15a03adee24d6350da4292caeac44c34c033d2afe5e87eb370f38854560f/propcache-0.5.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7eabc04151c78a9f4d5bbb5f1faf571e4defeb4b585e0fe95b60ff2dbe4d3d7", size = 64184, upload-time = "2026-05-08T21:00:43.018Z" },
- { url = "https://files.pythonhosted.org/packages/8b/c6/979176efdaa3d239e36d503d5af63a0a773b36662ed8f52e5b6a6d9fd40e/propcache-0.5.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4db0ba63d693afd40d249bd93f842b5f144f8fcbb83de05660373bcf30517b1d", size = 61534, upload-time = "2026-05-08T21:00:44.507Z" },
- { url = "https://files.pythonhosted.org/packages/c8/22/63e8cd1bae4c2d2be6493b6b7d10566ddafad88137cfbc99964a1119853c/propcache-0.5.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1dbcf7675229b35d31abb6547d8ebc8c27a830ac3f9a794edff6254873ec7c0a", size = 61500, upload-time = "2026-05-08T21:00:45.796Z" },
- { url = "https://files.pythonhosted.org/packages/60/5a/28e5d9acbac1cc9ccb67045e8c1b943aa8d79fdf39c93bd73cacd68008ea/propcache-0.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d310c013aad2c72f1c3f2f8dd3279d460a858c551f97aeb8c63e4693cca7b4d2", size = 59994, upload-time = "2026-05-08T21:00:47.093Z" },
- { url = "https://files.pythonhosted.org/packages/f3/40/db650677f554a95b9c01a7c9d93d629e93a15562f5deb4573c9ee136fed2/propcache-0.5.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:06187263ddad280d05b4d8a8b3bb7d164cbebd469236544a42e6d9b28ac6a4fa", size = 56884, upload-time = "2026-05-08T21:00:48.376Z" },
- { url = "https://files.pythonhosted.org/packages/80/45/70b39b89516ff8b96bf732fa6fded8cef20f293cb1508690101c3c07ec51/propcache-0.5.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3115559b8effafd63b142ea5ed53d63a16ea6469cbc63dce4ee194b42db5d853", size = 63464, upload-time = "2026-05-08T21:00:49.954Z" },
- { url = "https://files.pythonhosted.org/packages/f9/e2/fa59d3a89eac5534293124af4f1d0d0ada091ce4a0ab4610ce03fd2bdd8d/propcache-0.5.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c60462af8e6dc30c35407c7237ea908d777b22862bbee27bc4699c0d8bcdc45a", size = 61588, upload-time = "2026-05-08T21:00:51.281Z" },
- { url = "https://files.pythonhosted.org/packages/0b/97/efb547a55c4bc7381cfb202d6a2239ac621045277bc1ea5dfd3a7f0516c0/propcache-0.5.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40314bca9ac559716fe374094fc81c11dcc34b64fd6c585360f5775690505704", size = 64667, upload-time = "2026-05-08T21:00:52.602Z" },
- { url = "https://files.pythonhosted.org/packages/92/56/f5c7d9b4b7595d5127da38974d791b2153f3d1eae6c674af3583ace92ad3/propcache-0.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cfa21e036ce1e1db2be04ba3b85d2df1bb1702fa01932d984c5464c665228ff4", size = 62463, upload-time = "2026-05-08T21:00:54.303Z" },
- { url = "https://files.pythonhosted.org/packages/bd/3b/484a3a65fc9f9f60c41dcd17b428bace5389544e2c680994534a20755066/propcache-0.5.2-cp313-cp313-win32.whl", hash = "sha256:f156a3529f38063b6dbaf356e15602a7f95f8055b1295a438433a6386f10463d", size = 38621, upload-time = "2026-05-08T21:00:55.808Z" },
- { url = "https://files.pythonhosted.org/packages/1c/fd/3f0f10dba4dabad3bf53102be007abf55481067952bde0fdddff439e7c61/propcache-0.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:dfed59d0a5aeb01e242e66ff0300bc4a265a7c05f612d30016f0b60b1017d757", size = 41649, upload-time = "2026-05-08T21:00:57.061Z" },
- { url = "https://files.pythonhosted.org/packages/90/ec/6ce619cc32bb500a482f811f9cd509368b4e58e638d13f2c68f370d6b475/propcache-0.5.2-cp313-cp313-win_arm64.whl", hash = "sha256:ba338430e87ceb9c8f0cf754de38a9860560261e56c00376debd628698a7364f", size = 37636, upload-time = "2026-05-08T21:00:58.646Z" },
- { url = "https://files.pythonhosted.org/packages/1b/82/c1d268bbbf2ef981c5bf0fbbe746db617c66e3bcefe431a1aa8943fbe23a/propcache-0.5.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a592f5f3da71c8691c788c13cb6734b6d17663d2e1cb8caddf0673d01ef8847d", size = 98872, upload-time = "2026-05-08T21:00:59.889Z" },
- { url = "https://files.pythonhosted.org/packages/f4/d4/52c871e73e864e6b34c0e2d58ac1ec5ccd149497ddc7ad2137ae98323a35/propcache-0.5.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6a997d0489e9668a384fcfd5061b857aa5361de73191cac204d04b889cfbbafa", size = 56257, upload-time = "2026-05-08T21:01:01.195Z" },
- { url = "https://files.pythonhosted.org/packages/67/f0/9b90ca2a210b3d09bcfcd96ecd0f55545c091535abce2a45de2775cfd357/propcache-0.5.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:10734b5484ea113152ee25a91dccedf81631791805d2c9ccb054958e51842c94", size = 56696, upload-time = "2026-05-08T21:01:02.941Z" },
- { url = "https://files.pythonhosted.org/packages/9d/0e/6e9d4ba07c8e56e21ddec1e75f12148142b21ca83a51871babce095334f4/propcache-0.5.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cafca7e56c12bb02ae16d283742bef25a61122e9dab2b5b3f2ccbe589ce32164", size = 62378, upload-time = "2026-05-08T21:01:04.475Z" },
- { url = "https://files.pythonhosted.org/packages/65/19/c10badaa463dde8a27ce884f8ee2ec37e6035b7c9f5ff0c8f74f06f08dac/propcache-0.5.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f064f8d2b59177878b7615df1735cd8fe3462ed6be8c7b217d17a276489c2b7f", size = 65283, upload-time = "2026-05-08T21:01:05.959Z" },
- { url = "https://files.pythonhosted.org/packages/b0/b6/93bea99ca80e19cef6512a8580e5b7857bbe09422d9daa7fd4ef5723306c/propcache-0.5.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f78abfa8dfc32376fd1aacf597b2f2fbbe0ea751419aee718af5d4f82537ef8c", size = 66616, upload-time = "2026-05-08T21:01:07.228Z" },
- { url = "https://files.pythonhosted.org/packages/83/e4/5c7462e50625f051f37fb38b8224f7639f667184bbd34424ec83819bb1b7/propcache-0.5.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7467da8a9822bf1a55336f877340c5bcbd3c482afc43a99771169f74a26dedc", size = 63773, upload-time = "2026-05-08T21:01:08.514Z" },
- { url = "https://files.pythonhosted.org/packages/ca/b6/99238894047b13c823be25027e736626cd414a52a5e30d2c3347c2733529/propcache-0.5.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a6ddc6ac9e25de626c1f129c1b467d7ecd33ce2237d3fd0c4e429feef0a7ee1f", size = 63664, upload-time = "2026-05-08T21:01:09.874Z" },
- { url = "https://files.pythonhosted.org/packages/85/1e/a3a1a63116a2b8edb415a8bb9a6f0c34bd03830b1e18e8ce2904e1dc1cf4/propcache-0.5.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2f22cbbac9e26a8e864c0985ff1268d5d939d53d9d9411a9824279097e03a2cb", size = 62643, upload-time = "2026-05-08T21:01:11.132Z" },
- { url = "https://files.pythonhosted.org/packages/e4/03/893cf147de2fc6543c5eaa07ad833170e7e2a2385725bbebe8c0503723bb/propcache-0.5.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:fc76378c62a0f04d0cd82fbb1a2cd2d7e28fcb40d5873f28a6c44e388aaa2751", size = 59595, upload-time = "2026-05-08T21:01:12.387Z" },
- { url = "https://files.pythonhosted.org/packages/86/3b/04c1a2e12c57766568ba75ba72b3bf2042818d4c1425fab6fc07155c7cff/propcache-0.5.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:acd2c8edba48e31e58a363b8cf4e5c7db3b04b3f9e371f601df30d9b0d244836", size = 65711, upload-time = "2026-05-08T21:01:13.676Z" },
- { url = "https://files.pythonhosted.org/packages/1c/34/80f8d0099f8d6bacc4de1624c85672681c8cd1149ca2da0e38fd120b817f/propcache-0.5.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:452b5065457eb9991ec5eb38ff41d6cd4c991c9ac7c531c4d5849ae473a9a13f", size = 64247, upload-time = "2026-05-08T21:01:14.936Z" },
- { url = "https://files.pythonhosted.org/packages/f3/1a/8b08f3a5f1037e9e370c55883ceeeee0f6dd0416fb2d2d67b8bfc91f2a79/propcache-0.5.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:3430bb2bfe1331885c427745a751e774ee679fd4344f80b97bf879815fe8fa55", size = 67102, upload-time = "2026-05-08T21:01:16.281Z" },
- { url = "https://files.pythonhosted.org/packages/34/68/8bdb7bb7756d76e005490649d10e4a8369e610c74d619f71e1aedf889e9c/propcache-0.5.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cef6cea3922890dd6c9654971001fa797b526c16ab5e1e46c05fd6f877be7568", size = 64964, upload-time = "2026-05-08T21:01:17.57Z" },
- { url = "https://files.pythonhosted.org/packages/0a/aa/50fb0b5d3968b61a510926ff8b8465f1d6e976b3ab74496d7a4b9fc42515/propcache-0.5.2-cp313-cp313t-win32.whl", hash = "sha256:72d61e16dd78228b58c5d47be830ff3da7e5f139abdf0aef9d86cde1c5cf2191", size = 42546, upload-time = "2026-05-08T21:01:18.946Z" },
- { url = "https://files.pythonhosted.org/packages/ae/4c/0ddbae64321bd4a95bcbfc19307238016b5b1fee645c84626c8d539e5b74/propcache-0.5.2-cp313-cp313t-win_amd64.whl", hash = "sha256:0958834041a0166d343b8d2cedcd8bcbaeb4fdbe0cf08320c5379f143c3be6e7", size = 46330, upload-time = "2026-05-08T21:01:20.162Z" },
- { url = "https://files.pythonhosted.org/packages/00/d9/9cddc8efb78d8af264c5ec9f6d10b62f57c515feda8d321595f56010fb23/propcache-0.5.2-cp313-cp313t-win_arm64.whl", hash = "sha256:6de8bd93ddde9b992cf2b2e0d796d501a19026b5b9fd87356d7d0779531a8d96", size = 40521, upload-time = "2026-05-08T21:01:21.399Z" },
- { url = "https://files.pythonhosted.org/packages/e2/ea/23ee535d90ce8bcc465a3028eb3cc0ce3bd1005f4bb27710b30587de798d/propcache-0.5.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:46088abff4cba581dea21ae0467a480526cb25aa5f3c269e909f800328bc3999", size = 94662, upload-time = "2026-05-08T21:01:22.683Z" },
- { url = "https://files.pythonhosted.org/packages/b5/06/c5a52f419b5d8972f8d46a7577476090d8e3263ff589ce40b5ca4968d5be/propcache-0.5.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fc88b26f08d634f7bc819a7852e5214f5802641ab8d9fd5326892292eee1993e", size = 53928, upload-time = "2026-05-08T21:01:23.986Z" },
- { url = "https://files.pythonhosted.org/packages/63/b1/4260d67d6bd85e58a66b72d54ce15d5de789b6f3870cc6bedf8ff9667401/propcache-0.5.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:97797ebb098e670a2f92dd66f32897e30d7615b14e7f59711de23e30a9072539", size = 54650, upload-time = "2026-05-08T21:01:25.305Z" },
- { url = "https://files.pythonhosted.org/packages/70/06/2f46c318e3307cd7a6a7481def374ce838c0fe20084b39dd54b0879d0e99/propcache-0.5.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba57fffe4ac99c5d30076161b5866336d97600769bad35cc68f7774b15298a4e", size = 59912, upload-time = "2026-05-08T21:01:26.545Z" },
- { url = "https://files.pythonhosted.org/packages/4c/29/fe1aebec2ce57ab985a9c382bded1124431f85078113aa222c5d278430d4/propcache-0.5.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:583c19759d9eec1e5b69e2fbef36a7d9c326041be9746cb822d335c8cedc2979", size = 63300, upload-time = "2026-05-08T21:01:27.937Z" },
- { url = "https://files.pythonhosted.org/packages/b4/18/2334b26768b6c82be8c69e83671b767d5ef426aa09b0cba6c2ea47816774/propcache-0.5.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d0326e2e5e1f3163fa306c834e48e8d490e5fae607a097a40c0648109b47ba80", size = 64208, upload-time = "2026-05-08T21:01:29.484Z" },
- { url = "https://files.pythonhosted.org/packages/2b/76/7f1bfd6afff4c5e38e36a3c6d68eb5f4b7311ea80baf693db78d95b603c4/propcache-0.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e00820e192c8dbebcafb383ebbf99030895f09905e7a0eb2e0340a0bcc2bc825", size = 61633, upload-time = "2026-05-08T21:01:31.068Z" },
- { url = "https://files.pythonhosted.org/packages/c4/46/b3ff8aba2b4953a3e50de2cf72f1b5748b8eca93b15f3dc2c84339084c09/propcache-0.5.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c66afea89b1e43725731d2004732a046fe6fe955d51f952c3e95a7314a284a39", size = 61724, upload-time = "2026-05-08T21:01:32.374Z" },
- { url = "https://files.pythonhosted.org/packages/c5/01/814cfcafbcff954f94c01cf30e097ddc88a076b5440fbcf4570753437d40/propcache-0.5.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4dc37dec6c6cdad0b57881a5658fd14fbf53e333b1a86cf86559f190e1d9ec4", size = 60069, upload-time = "2026-05-08T21:01:33.67Z" },
- { url = "https://files.pythonhosted.org/packages/da/68/5c6f7622d510cc666a300687e06fd060c1a43361c0c9b20d284f06d8096a/propcache-0.5.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5570dbcc97571c15f68068e529c92715a12f8d54030e272d264b377e22bd17a5", size = 57099, upload-time = "2026-05-08T21:01:34.915Z" },
- { url = "https://files.pythonhosted.org/packages/55/27/9cb0b4c679124085327957d42521c99dba04c88c90c3e55a6f0b633ebccc/propcache-0.5.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f814362777a9f841adddb200ecdf8f5cb1e5a3c4b7a86378edbd6ccb26edd702", size = 63391, upload-time = "2026-05-08T21:01:36.231Z" },
- { url = "https://files.pythonhosted.org/packages/f0/9d/7258aaa5bdf60fc6f27591eef6fe52768cb0beda7140be477c8b12c9794a/propcache-0.5.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:196913dea116aeb5a2ba95af4ddcb7ea85559ae07d8eee8751688310d09168c3", size = 61626, upload-time = "2026-05-08T21:01:37.545Z" },
- { url = "https://files.pythonhosted.org/packages/8e/0d/41c602003e8a9b16fe1e7eadf62c7bfba9d5474370b24200bf48b315f45f/propcache-0.5.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:6e7b8719005dd1175be4ab1cd25e9b98659a5e0347331506ec6760d2773a7fb5", size = 64781, upload-time = "2026-05-08T21:01:38.83Z" },
- { url = "https://files.pythonhosted.org/packages/8b/f3/38e66b1856e9bd079deea015bc4a55f7767c0e4db2f7dcf69e7e680ba4ce/propcache-0.5.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:51f96d685ab16e88cab128cd37a52c5da540809c8b879fa047731bfcb4ad35a4", size = 62570, upload-time = "2026-05-08T21:01:40.415Z" },
- { url = "https://files.pythonhosted.org/packages/95/ca/bbfe9b910ce57dde8bb4876b4520fc02a4e89497c10de26be936758a3aaa/propcache-0.5.2-cp314-cp314-win32.whl", hash = "sha256:cc6fc3cc62e8501d3ed62894425040d2728ecddb1ed072737a5c70bd537aa9f0", size = 39436, upload-time = "2026-05-08T21:01:41.654Z" },
- { url = "https://files.pythonhosted.org/packages/61/d2/45c9defbaa1ea297035d9d4cce9e8f80daafbf19319c6007f157c6256ea9/propcache-0.5.2-cp314-cp314-win_amd64.whl", hash = "sha256:81e3a30b0bb60caa22033dd0f8a3618d1d67356212514f62c57db75cb0ef410c", size = 42373, upload-time = "2026-05-08T21:01:43.041Z" },
- { url = "https://files.pythonhosted.org/packages/44/68/9ea5103f41d5217d7d6ec24db90018e23aebec070c3f9a6e54d12b841fd8/propcache-0.5.2-cp314-cp314-win_arm64.whl", hash = "sha256:0d2c9bf8528f135dbb805ce027567e09164f7efa51a2be07458a2c0420f292d0", size = 38554, upload-time = "2026-05-08T21:01:44.336Z" },
- { url = "https://files.pythonhosted.org/packages/8a/81/fadf555f42d3b762eea8a53950b0489fdc0aa9da5f8ed9e10ce0a4e01b48/propcache-0.5.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:4bc8ff1feffc6a61c7002ffe84634c41b822e104990ae009f44a0834430070bb", size = 99395, upload-time = "2026-05-08T21:01:45.883Z" },
- { url = "https://files.pythonhosted.org/packages/f5/c9/c61e134a686949cf7971af3a390148b1156f7be81c73bc0cd12c873e2d48/propcache-0.5.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:79aa3ff0a9b566633b642fa9caf7e21ed1c13d6feca718187873f199e1514078", size = 56653, upload-time = "2026-05-08T21:01:47.307Z" },
- { url = "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1b31822f4474c4036bae62de9402710051d431a606d6a0f907fec79935a071aa", size = 56914, upload-time = "2026-05-08T21:01:48.573Z" },
- { url = "https://files.pythonhosted.org/packages/79/9f/aba959b435ea18617edd7cf0a7ad0b9c574b8fc7e3d2cd55fb59cb255d33/propcache-0.5.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13fef48778b5a2a756523fdb781326b028ca75e32858b04f2cdd19f394564917", size = 62567, upload-time = "2026-05-08T21:01:49.903Z" },
- { url = "https://files.pythonhosted.org/packages/6c/a1/859942de9a791ff42f6141736f5b37749b8f53e65edfa49638c67dd67e6a/propcache-0.5.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8b73ab70f1a3351fbc71f663b3e645af6dd0329100c353081cf69c37433fc6fe", size = 65542, upload-time = "2026-05-08T21:01:51.204Z" },
- { url = "https://files.pythonhosted.org/packages/b5/61/315bc0fd6c0fc7f80a528b8afd209e5fc4a875ea79571b91b8f50f442907/propcache-0.5.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5538d2c13d93e4698af7e092b57bc7298fd35d1d58e656ae18f23ee0d0378e03", size = 66845, upload-time = "2026-05-08T21:01:52.539Z" },
- { url = "https://files.pythonhosted.org/packages/47/f7/9f8122e3132e8e354ac41975ef8f1099be7d5a16bc7ae562734e993665c0/propcache-0.5.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd645f03898405cabe694fb8bc35241e3a9c332ec85627584fe3de201452b335", size = 63985, upload-time = "2026-05-08T21:01:53.847Z" },
- { url = "https://files.pythonhosted.org/packages/c8/54/c317819ec157cbf6f35df9df9657a6f82daf34d5faf15948b2f639c2192e/propcache-0.5.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a473b3440261e0c60706e732b2ed2f517857344fc21bf48fdfe211e2d98eb285", size = 63999, upload-time = "2026-05-08T21:01:55.179Z" },
- { url = "https://files.pythonhosted.org/packages/5a/56/387e3f7dfce0a9233df41fb888aa1c30222cb4bbbf09537c02dd9bd85fe2/propcache-0.5.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7afa37062e6650640e932e4cc9297d81f9f42d9944029cc386b8247dea4da837", size = 62779, upload-time = "2026-05-08T21:01:57.489Z" },
- { url = "https://files.pythonhosted.org/packages/a1/9c/596784cb5824ed61ee960d3f8655a3f0993e107c6e98ab6c818b7fb92ccb/propcache-0.5.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:8a90efd5777e996e42d568db9ac740b944d691e565cbfd31b2f7832f9184b2b8", size = 59796, upload-time = "2026-05-08T21:01:58.736Z" },
- { url = "https://files.pythonhosted.org/packages/c2/3d/1a6cfa1726a48542c1e8784a0761421476a5b68e09b7f36bf95eb954aaba/propcache-0.5.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:f19bb891234d72535764d703bfed1153cc34f4214d5bd7150aee1eec9e8f4366", size = 66023, upload-time = "2026-05-08T21:02:00.228Z" },
- { url = "https://files.pythonhosted.org/packages/e4/0e/05fd6990369477076e4e280bcb970de760fddf0161a46e988bc95f7940ec/propcache-0.5.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:32775082acd2d807ee3db715c7770d38767b817870acfa08c29e057f3c4d5b56", size = 64448, upload-time = "2026-05-08T21:02:01.888Z" },
- { url = "https://files.pythonhosted.org/packages/cd/86/5f8da315a4309c62c10c0b2516b17492d5d3bbe1bb862b96604db67e2a37/propcache-0.5.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9282fb1a3bccd038da9f768b927b24a0c753e466c086b7c4f3c6982851eefb2d", size = 67329, upload-time = "2026-05-08T21:02:03.484Z" },
- { url = "https://files.pythonhosted.org/packages/da/d3/3368efe79ab21f0cdf86ef49895811c9cc933131d4cde1f28a624e22e712/propcache-0.5.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc49723e2f60d6b32a0f0b08a3fd6d13203c07f1cd9566cfce0f12a917c967a2", size = 65172, upload-time = "2026-05-08T21:02:04.745Z" },
- { url = "https://files.pythonhosted.org/packages/d5/07/127e8b0bacfb325396196f9d976a22453049b89b9b2b08477cc3145faa44/propcache-0.5.2-cp314-cp314t-win32.whl", hash = "sha256:2d7aa89ebca5acc98cba9d1472d976e394782f587bad6661003602a619fd1821", size = 43813, upload-time = "2026-05-08T21:02:06.025Z" },
- { url = "https://files.pythonhosted.org/packages/88/fb/46dad6c0ae49ed230ab1b16c890c2b6314e2403e6c412976f4a72d64a527/propcache-0.5.2-cp314-cp314t-win_amd64.whl", hash = "sha256:d447bb0b3054be5818458fbb171208b1d9ff11eba14e18ca18b90cbb45767370", size = 47764, upload-time = "2026-05-08T21:02:07.353Z" },
- { url = "https://files.pythonhosted.org/packages/e7/c4/a47d0a63aa309d10d59ede6e9d4cff03a344a79d1f0f4cd0cd74997b53e0/propcache-0.5.2-cp314-cp314t-win_arm64.whl", hash = "sha256:fe67a3d11cd9b4efabfa45c3d00ffba2b26811442a73a581a94b67c2b5faccf6", size = 41140, upload-time = "2026-05-08T21:02:09.065Z" },
- { url = "https://files.pythonhosted.org/packages/3a/ed/1cdcab6ba3d6ab7feca11fc14f0eeea80755bb53ef4e892079f31b10a25f/propcache-0.5.2-py3-none-any.whl", hash = "sha256:be1ddfcbb376e3de5d2e2db1d58d6d67463e6b4f9f040c000de8e300295465fe", size = 14036, upload-time = "2026-05-08T21:02:10.673Z" },
-]
-
-[[package]]
-name = "protobuf"
-version = "7.34.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/6b/6b/a0e95cad1ad7cc3f2c6821fcab91671bd5b78bd42afb357bb4765f29bc41/protobuf-7.34.1.tar.gz", hash = "sha256:9ce42245e704cc5027be797c1db1eb93184d44d1cdd71811fb2d9b25ad541280", size = 454708, upload-time = "2026-03-20T17:34:47.036Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/ec/11/3325d41e6ee15bf1125654301211247b042563bcc898784351252549a8ad/protobuf-7.34.1-cp310-abi3-macosx_10_9_universal2.whl", hash = "sha256:d8b2cc79c4d8f62b293ad9b11ec3aebce9af481fa73e64556969f7345ebf9fc7", size = 429247, upload-time = "2026-03-20T17:34:37.024Z" },
- { url = "https://files.pythonhosted.org/packages/eb/9d/aa69df2724ff63efa6f72307b483ce0827f4347cc6d6df24b59e26659fef/protobuf-7.34.1-cp310-abi3-manylinux2014_aarch64.whl", hash = "sha256:5185e0e948d07abe94bb76ec9b8416b604cfe5da6f871d67aad30cbf24c3110b", size = 325753, upload-time = "2026-03-20T17:34:38.751Z" },
- { url = "https://files.pythonhosted.org/packages/92/e8/d174c91fd48e50101943f042b09af9029064810b734e4160bbe282fa1caa/protobuf-7.34.1-cp310-abi3-manylinux2014_s390x.whl", hash = "sha256:403b093a6e28a960372b44e5eb081775c9b056e816a8029c61231743d63f881a", size = 340198, upload-time = "2026-03-20T17:34:39.871Z" },
- { url = "https://files.pythonhosted.org/packages/53/1b/3b431694a4dc6d37b9f653f0c64b0a0d9ec074ee810710c0c3da21d67ba7/protobuf-7.34.1-cp310-abi3-manylinux2014_x86_64.whl", hash = "sha256:8ff40ce8cd688f7265326b38d5a1bed9bfdf5e6723d49961432f83e21d5713e4", size = 324267, upload-time = "2026-03-20T17:34:41.1Z" },
- { url = "https://files.pythonhosted.org/packages/85/29/64de04a0ac142fb685fd09999bc3d337943fb386f3a0ec57f92fd8203f97/protobuf-7.34.1-cp310-abi3-win32.whl", hash = "sha256:34b84ce27680df7cca9f231043ada0daa55d0c44a2ddfaa58ec1d0d89d8bf60a", size = 426628, upload-time = "2026-03-20T17:34:42.536Z" },
- { url = "https://files.pythonhosted.org/packages/4d/87/cb5e585192a22b8bd457df5a2c16a75ea0db9674c3a0a39fc9347d84e075/protobuf-7.34.1-cp310-abi3-win_amd64.whl", hash = "sha256:e97b55646e6ce5cbb0954a8c28cd39a5869b59090dfaa7df4598a7fba869468c", size = 437901, upload-time = "2026-03-20T17:34:44.112Z" },
- { url = "https://files.pythonhosted.org/packages/88/95/608f665226bca68b736b79e457fded9a2a38c4f4379a4a7614303d9db3bc/protobuf-7.34.1-py3-none-any.whl", hash = "sha256:bb3812cd53aefea2b028ef42bd780f5b96407247f20c6ef7c679807e9d188f11", size = 170715, upload-time = "2026-03-20T17:34:45.384Z" },
-]
-
-[[package]]
-name = "python-discovery"
-version = "1.3.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "filelock" },
- { name = "platformdirs" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/ae/e0/cc5a8653e9a24f6cf84768f05064aa8ed5a83dcefd5e2a043db14a1c5f44/python_discovery-1.3.0.tar.gz", hash = "sha256:d098f1e86be5d45fe4d14bf1029294aabbd332f4321179dec85e76cddce834b0", size = 63925, upload-time = "2026-05-05T14:38:39.769Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/30/d4/24d543ab8b8158b7f5a97113c831205f5c900c92c8762b1e7f44b7ea0405/python_discovery-1.3.0-py3-none-any.whl", hash = "sha256:441d9ced3dfce36e113beb35ca302c71c7ef06f3c0f9c227a0b9bb3bd49b9e9f", size = 33124, upload-time = "2026-05-05T14:38:38.539Z" },
-]
-
-[[package]]
-name = "pyyaml"
-version = "6.0.3"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" },
- { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" },
- { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" },
- { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" },
- { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" },
- { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" },
- { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" },
- { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" },
- { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" },
- { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" },
- { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" },
- { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" },
- { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" },
- { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" },
- { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" },
- { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" },
- { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" },
- { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" },
- { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" },
- { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" },
- { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" },
- { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" },
- { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" },
- { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" },
- { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" },
- { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" },
- { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" },
- { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" },
- { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" },
- { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" },
- { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" },
- { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" },
- { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" },
- { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" },
- { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" },
- { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
- { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
- { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
-]
-
-[[package]]
-name = "ruff"
-version = "0.15.12"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/99/43/3291f1cc9106f4c63bdce7a8d0df5047fe8422a75b091c16b5e9355e0b11/ruff-0.15.12.tar.gz", hash = "sha256:ecea26adb26b4232c0c2ca19ccbc0083a68344180bba2a600605538ce51a40a6", size = 4643852, upload-time = "2026-04-24T18:17:14.305Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/c3/6e/e78ffb61d4686f3d96ba3df2c801161843746dcbcbb17a1e927d4829312b/ruff-0.15.12-py3-none-linux_armv6l.whl", hash = "sha256:f86f176e188e94d6bdbc09f09bfd9dc729059ad93d0e7390b5a73efe19f8861c", size = 10640713, upload-time = "2026-04-24T18:17:22.841Z" },
- { url = "https://files.pythonhosted.org/packages/ae/08/a317bc231fb9e7b93e4ef3089501e51922ff88d6936ce5cf870c4fe55419/ruff-0.15.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e3bcd123364c3770b8e1b7baaf343cc99a35f197c5c6e8af79015c666c423a6c", size = 11069267, upload-time = "2026-04-24T18:17:30.105Z" },
- { url = "https://files.pythonhosted.org/packages/aa/a4/f828e9718d3dce1f5f11c39c4f65afd32783c8b2aebb2e3d259e492c47bd/ruff-0.15.12-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fe87510d000220aa1ed530d4448a7c696a0cae1213e5ec30e5874287b66557b5", size = 10397182, upload-time = "2026-04-24T18:17:07.177Z" },
- { url = "https://files.pythonhosted.org/packages/71/e0/3310fc6d1b5e1fdea22bf3b1b807c7e187b581021b0d7d4514cccdb5fb71/ruff-0.15.12-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84a1630093121375a3e2a95b4a6dc7b59e2b4ee76216e32d81aae550a832d002", size = 10758012, upload-time = "2026-04-24T18:16:55.759Z" },
- { url = "https://files.pythonhosted.org/packages/11/c1/a606911aee04c324ddaa883ae418f3569792fd3c4a10c50e0dd0a2311e1e/ruff-0.15.12-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fb129f40f114f089ebe0ca56c0d251cf2061b17651d464bb6478dc01e69f11f5", size = 10447479, upload-time = "2026-04-24T18:16:51.677Z" },
- { url = "https://files.pythonhosted.org/packages/9d/68/4201e8444f0894f21ab4aeeaee68aa4f10b51613514a20d80bd628d57e88/ruff-0.15.12-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0c862b172d695db7598426b8af465e7e9ac00a3ea2a3630ee67eb82e366aaa6", size = 11234040, upload-time = "2026-04-24T18:17:16.529Z" },
- { url = "https://files.pythonhosted.org/packages/34/ff/8a6d6cf4ccc23fd67060874e832c18919d1557a0611ebef03fdb01fff11e/ruff-0.15.12-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2849ea9f3484c3aca43a82f484210370319e7170df4dfe4843395ddf6c57bc33", size = 12087377, upload-time = "2026-04-24T18:17:04.944Z" },
- { url = "https://files.pythonhosted.org/packages/85/f6/c669cf73f5152f623d34e69866a46d5e6185816b19fcd5b6dd8a2d299922/ruff-0.15.12-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e77c7e51c07fe396826d5969a5b846d9cd4c402535835fb6e21ce8b28fef847", size = 11367784, upload-time = "2026-04-24T18:17:25.409Z" },
- { url = "https://files.pythonhosted.org/packages/e8/39/c61d193b8a1daaa8977f7dea9e8d8ba866e02ea7b65d32f6861693aa4c12/ruff-0.15.12-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b2f4f2f3b1026b5fb449b467d9264bf22067b600f7b6f41fc5958909f449d0", size = 11344088, upload-time = "2026-04-24T18:17:12.258Z" },
- { url = "https://files.pythonhosted.org/packages/c2/8d/49afab3645e31e12c590acb6d3b5b69d7aab5b81926dbaf7461f9441f37a/ruff-0.15.12-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9ba3b8f1afd7e2e43d8943e55f249e13f9682fde09711644a6e7290eb4f3e339", size = 11271770, upload-time = "2026-04-24T18:17:02.457Z" },
- { url = "https://files.pythonhosted.org/packages/46/06/33f41fe94403e2b755481cdfb9b7ef3e4e0ed031c4581124658d935d52b4/ruff-0.15.12-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e852ba9fdc890655e1d78f2df1499efbe0e54126bd405362154a75e2bde159c5", size = 10719355, upload-time = "2026-04-24T18:17:27.648Z" },
- { url = "https://files.pythonhosted.org/packages/0d/59/18aa4e014debbf559670e4048e39260a85c7fcee84acfd761ac01e7b8d35/ruff-0.15.12-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dd8aed930da53780d22fc70bdf84452c843cf64f8cb4eb38984319c24c5cd5fd", size = 10462758, upload-time = "2026-04-24T18:17:32.347Z" },
- { url = "https://files.pythonhosted.org/packages/25/e7/cc9f16fd0f3b5fddcbd7ec3d6ae30c8f3fde1047f32a4093a98d633c6570/ruff-0.15.12-py3-none-musllinux_1_2_i686.whl", hash = "sha256:01da3988d225628b709493d7dc67c3b9b12c0210016b08690ef9bd27970b262b", size = 10953498, upload-time = "2026-04-24T18:17:20.674Z" },
- { url = "https://files.pythonhosted.org/packages/72/7a/a9ba7f98c7a575978698f4230c5e8cc54bbc761af34f560818f933dafa0c/ruff-0.15.12-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:9cae0f92bd5700d1213188b31cd3bdd2b315361296d10b96b8e2337d3d11f53e", size = 11447765, upload-time = "2026-04-24T18:17:09.755Z" },
- { url = "https://files.pythonhosted.org/packages/ea/f9/0ae446942c846b8266059ad8a30702a35afae55f5cdc54c5adf8d7afdc27/ruff-0.15.12-py3-none-win32.whl", hash = "sha256:d0185894e038d7043ba8fd6aee7499ece6462dc0ea9f1e260c7451807c714c20", size = 10657277, upload-time = "2026-04-24T18:17:18.591Z" },
- { url = "https://files.pythonhosted.org/packages/33/f1/9614e03e1cdcbf9437570b5400ced8a720b5db22b28d8e0f1bda429f660d/ruff-0.15.12-py3-none-win_amd64.whl", hash = "sha256:c87a162d61ab3adca47c03f7f717c68672edec7d1b5499e652331780fe74950d", size = 11837758, upload-time = "2026-04-24T18:17:00.113Z" },
- { url = "https://files.pythonhosted.org/packages/c0/98/6beb4b351e472e5f4c4613f7c35a5290b8be2497e183825310c4c3a3984b/ruff-0.15.12-py3-none-win_arm64.whl", hash = "sha256:a538f7a82d061cee7be55542aca1d86d1393d55d81d4fcc314370f4340930d4f", size = 11120821, upload-time = "2026-04-24T18:16:57.979Z" },
-]
-
-[[package]]
-name = "types-protobuf"
-version = "7.34.1.20260503"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/a0/31/87969cb3e62287bde7598b78b3c098d2873d54f5fb5a7cfbcaa73b8c965e/types_protobuf-7.34.1.20260503.tar.gz", hash = "sha256:effbc819aa17e02448dde99f089c6794662d66f4b2797e922f185ffe0b24e766", size = 68830, upload-time = "2026-05-03T05:19:50.739Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/f9/67/a33fb18090a927794a5ee4b1a30730b528ace0dad6b18932540d21258184/types_protobuf-7.34.1.20260503-py3-none-any.whl", hash = "sha256:75fd66121d56785c91828b8bf7b511f39ba847f11e682573e41847f01e9cd1de", size = 86019, upload-time = "2026-05-03T05:19:49.486Z" },
-]
-
-[[package]]
-name = "types-pyyaml"
-version = "6.0.12.20260408"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/74/73/b759b1e413c31034cc01ecdfb96b38115d0ab4db55a752a3929f0cd449fd/types_pyyaml-6.0.12.20260408.tar.gz", hash = "sha256:92a73f2b8d7f39ef392a38131f76b970f8c66e4c42b3125ae872b7c93b556307", size = 17735, upload-time = "2026-04-08T04:30:50.974Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/1c/f0/c391068b86abb708882c6d75a08cd7d25b2c7227dab527b3a3685a3c635b/types_pyyaml-6.0.12.20260408-py3-none-any.whl", hash = "sha256:fbc42037d12159d9c801ebfcc79ebd28335a7c13b08a4cfbc6916df78fee9384", size = 20339, upload-time = "2026-04-08T04:30:50.113Z" },
-]
-
-[[package]]
-name = "typing-extensions"
-version = "4.15.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
-]
-
-[[package]]
-name = "virtualenv"
-version = "21.3.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "distlib" },
- { name = "filelock" },
- { name = "platformdirs" },
- { name = "python-discovery" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/ec/0d/915c02c94d207b85580eb09bffab54438a709e7288524094fe781da526c2/virtualenv-21.3.1.tar.gz", hash = "sha256:c2305bc1fddeec40699b8370d13f8d431b0701f00ce895061ce493aeded4426b", size = 7613791, upload-time = "2026-05-05T01:34:31.402Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/b1/4f/f71e641e504111a5a74e3a20bc52d01bd86788b22699dd3fee1c63253cf6/virtualenv-21.3.1-py3-none-any.whl", hash = "sha256:d1a71cf58f2f9228fff23a1f6ec15d39785c6b32e03658d104974247145edd35", size = 7594539, upload-time = "2026-05-05T01:34:28.98Z" },
-]
-
-[[package]]
-name = "vision-wrapper"
-version = "0.1.0"
-source = { virtual = "." }
-dependencies = [
- { name = "aiohttp" },
- { name = "protobuf" },
- { name = "pyyaml" },
-]
-
-[package.dev-dependencies]
-dev = [
- { name = "mypy" },
- { name = "pre-commit" },
- { name = "ruff" },
- { name = "types-protobuf" },
- { name = "types-pyyaml" },
-]
-
-[package.metadata]
-requires-dist = [
- { name = "aiohttp", specifier = ">=3.10" },
- { name = "protobuf", specifier = ">=7.34.1" },
- { name = "pyyaml", specifier = ">=6.0.3" },
-]
-
-[package.metadata.requires-dev]
-dev = [
- { name = "mypy", specifier = ">=2.0.0" },
- { name = "pre-commit", specifier = ">=4.6.0" },
- { name = "ruff", specifier = ">=0.15.12" },
- { name = "types-protobuf", specifier = ">=7.34.1.20260503" },
- { name = "types-pyyaml", specifier = ">=6.0.12.20260408" },
-]
-
-[[package]]
-name = "yarl"
-version = "1.23.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "idna" },
- { name = "multidict" },
- { name = "propcache" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/23/6e/beb1beec874a72f23815c1434518bfc4ed2175065173fb138c3705f658d4/yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5", size = 194676, upload-time = "2026-03-01T22:07:53.373Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/88/8a/94615bc31022f711add374097ad4144d569e95ff3c38d39215d07ac153a0/yarl-1.23.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1932b6b8bba8d0160a9d1078aae5838a66039e8832d41d2992daa9a3a08f7860", size = 124737, upload-time = "2026-03-01T22:05:12.897Z" },
- { url = "https://files.pythonhosted.org/packages/e3/6f/c6554045d59d64052698add01226bc867b52fe4a12373415d7991fdca95d/yarl-1.23.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:411225bae281f114067578891bc75534cfb3d92a3b4dfef7a6ca78ba354e6069", size = 87029, upload-time = "2026-03-01T22:05:14.376Z" },
- { url = "https://files.pythonhosted.org/packages/19/2a/725ecc166d53438bc88f76822ed4b1e3b10756e790bafd7b523fe97c322d/yarl-1.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13a563739ae600a631c36ce096615fe307f131344588b0bc0daec108cdb47b25", size = 86310, upload-time = "2026-03-01T22:05:15.71Z" },
- { url = "https://files.pythonhosted.org/packages/99/30/58260ed98e6ff7f90ba84442c1ddd758c9170d70327394a6227b310cd60f/yarl-1.23.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cbf44c5cb4a7633d078788e1b56387e3d3cf2b8139a3be38040b22d6c3221c8", size = 97587, upload-time = "2026-03-01T22:05:17.384Z" },
- { url = "https://files.pythonhosted.org/packages/76/0a/8b08aac08b50682e65759f7f8dde98ae8168f72487e7357a5d684c581ef9/yarl-1.23.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53ad387048f6f09a8969631e4de3f1bf70c50e93545d64af4f751b2498755072", size = 92528, upload-time = "2026-03-01T22:05:18.804Z" },
- { url = "https://files.pythonhosted.org/packages/52/07/0b7179101fe5f8385ec6c6bb5d0cb9f76bd9fb4a769591ab6fb5cdbfc69a/yarl-1.23.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4a59ba56f340334766f3a4442e0efd0af895fae9e2b204741ef885c446b3a1a8", size = 105339, upload-time = "2026-03-01T22:05:20.235Z" },
- { url = "https://files.pythonhosted.org/packages/d3/8a/36d82869ab5ec829ca8574dfcb92b51286fcfb1e9c7a73659616362dc880/yarl-1.23.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:803a3c3ce4acc62eaf01eaca1208dcf0783025ef27572c3336502b9c232005e7", size = 105061, upload-time = "2026-03-01T22:05:22.268Z" },
- { url = "https://files.pythonhosted.org/packages/66/3e/868e5c3364b6cee19ff3e1a122194fa4ce51def02c61023970442162859e/yarl-1.23.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3d2bff8f37f8d0f96c7ec554d16945050d54462d6e95414babaa18bfafc7f51", size = 100132, upload-time = "2026-03-01T22:05:23.638Z" },
- { url = "https://files.pythonhosted.org/packages/cf/26/9c89acf82f08a52cb52d6d39454f8d18af15f9d386a23795389d1d423823/yarl-1.23.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c75eb09e8d55bceb4367e83496ff8ef2bc7ea6960efb38e978e8073ea59ecb67", size = 99289, upload-time = "2026-03-01T22:05:25.749Z" },
- { url = "https://files.pythonhosted.org/packages/6f/54/5b0db00d2cb056922356104468019c0a132e89c8d3ab67d8ede9f4483d2a/yarl-1.23.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877b0738624280e34c55680d6054a307aa94f7d52fa0e3034a9cc6e790871da7", size = 96950, upload-time = "2026-03-01T22:05:27.318Z" },
- { url = "https://files.pythonhosted.org/packages/f6/40/10fa93811fd439341fad7e0718a86aca0de9548023bbb403668d6555acab/yarl-1.23.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b5405bb8f0e783a988172993cfc627e4d9d00432d6bbac65a923041edacf997d", size = 93960, upload-time = "2026-03-01T22:05:28.738Z" },
- { url = "https://files.pythonhosted.org/packages/bc/d2/8ae2e6cd77d0805f4526e30ec43b6f9a3dfc542d401ac4990d178e4bf0cf/yarl-1.23.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1c3a3598a832590c5a3ce56ab5576361b5688c12cb1d39429cf5dba30b510760", size = 104703, upload-time = "2026-03-01T22:05:30.438Z" },
- { url = "https://files.pythonhosted.org/packages/2f/0c/b3ceacf82c3fe21183ce35fa2acf5320af003d52bc1fcf5915077681142e/yarl-1.23.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:8419ebd326430d1cbb7efb5292330a2cf39114e82df5cc3d83c9a0d5ebeaf2f2", size = 98325, upload-time = "2026-03-01T22:05:31.835Z" },
- { url = "https://files.pythonhosted.org/packages/9d/e0/12900edd28bdab91a69bd2554b85ad7b151f64e8b521fe16f9ad2f56477a/yarl-1.23.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:be61f6fff406ca40e3b1d84716fde398fc08bc63dd96d15f3a14230a0973ed86", size = 105067, upload-time = "2026-03-01T22:05:33.358Z" },
- { url = "https://files.pythonhosted.org/packages/15/61/74bb1182cf79c9bbe4eb6b1f14a57a22d7a0be5e9cedf8e2d5c2086474c3/yarl-1.23.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ceb13c5c858d01321b5d9bb65e4cf37a92169ea470b70fec6f236b2c9dd7e34", size = 100285, upload-time = "2026-03-01T22:05:35.4Z" },
- { url = "https://files.pythonhosted.org/packages/69/7f/cd5ef733f2550de6241bd8bd8c3febc78158b9d75f197d9c7baa113436af/yarl-1.23.0-cp312-cp312-win32.whl", hash = "sha256:fffc45637bcd6538de8b85f51e3df3223e4ad89bccbfca0481c08c7fc8b7ed7d", size = 82359, upload-time = "2026-03-01T22:05:36.811Z" },
- { url = "https://files.pythonhosted.org/packages/f5/be/25216a49daeeb7af2bec0db22d5e7df08ed1d7c9f65d78b14f3b74fd72fc/yarl-1.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:f69f57305656a4852f2a7203efc661d8c042e6cc67f7acd97d8667fb448a426e", size = 87674, upload-time = "2026-03-01T22:05:38.171Z" },
- { url = "https://files.pythonhosted.org/packages/d2/35/aeab955d6c425b227d5b7247eafb24f2653fedc32f95373a001af5dfeb9e/yarl-1.23.0-cp312-cp312-win_arm64.whl", hash = "sha256:6e87a6e8735b44816e7db0b2fbc9686932df473c826b0d9743148432e10bb9b9", size = 81879, upload-time = "2026-03-01T22:05:40.006Z" },
- { url = "https://files.pythonhosted.org/packages/9a/4b/a0a6e5d0ee8a2f3a373ddef8a4097d74ac901ac363eea1440464ccbe0898/yarl-1.23.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:16c6994ac35c3e74fb0ae93323bf8b9c2a9088d55946109489667c510a7d010e", size = 123796, upload-time = "2026-03-01T22:05:41.412Z" },
- { url = "https://files.pythonhosted.org/packages/67/b6/8925d68af039b835ae876db5838e82e76ec87b9782ecc97e192b809c4831/yarl-1.23.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4a42e651629dafb64fd5b0286a3580613702b5809ad3f24934ea87595804f2c5", size = 86547, upload-time = "2026-03-01T22:05:42.841Z" },
- { url = "https://files.pythonhosted.org/packages/ae/50/06d511cc4b8e0360d3c94af051a768e84b755c5eb031b12adaaab6dec6e5/yarl-1.23.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7c6b9461a2a8b47c65eef63bb1c76a4f1c119618ffa99ea79bc5bb1e46c5821b", size = 85854, upload-time = "2026-03-01T22:05:44.85Z" },
- { url = "https://files.pythonhosted.org/packages/c4/f4/4e30b250927ffdab4db70da08b9b8d2194d7c7b400167b8fbeca1e4701ca/yarl-1.23.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2569b67d616eab450d262ca7cb9f9e19d2f718c70a8b88712859359d0ab17035", size = 98351, upload-time = "2026-03-01T22:05:46.836Z" },
- { url = "https://files.pythonhosted.org/packages/86/fc/4118c5671ea948208bdb1492d8b76bdf1453d3e73df051f939f563e7dcc5/yarl-1.23.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e9d9a4d06d3481eab79803beb4d9bd6f6a8e781ec078ac70d7ef2dcc29d1bea5", size = 92711, upload-time = "2026-03-01T22:05:48.316Z" },
- { url = "https://files.pythonhosted.org/packages/56/11/1ed91d42bd9e73c13dc9e7eb0dd92298d75e7ac4dd7f046ad0c472e231cd/yarl-1.23.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f514f6474e04179d3d33175ed3f3e31434d3130d42ec153540d5b157deefd735", size = 106014, upload-time = "2026-03-01T22:05:50.028Z" },
- { url = "https://files.pythonhosted.org/packages/ce/c9/74e44e056a23fbc33aca71779ef450ca648a5bc472bdad7a82339918f818/yarl-1.23.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fda207c815b253e34f7e1909840fd14299567b1c0eb4908f8c2ce01a41265401", size = 105557, upload-time = "2026-03-01T22:05:51.416Z" },
- { url = "https://files.pythonhosted.org/packages/66/fe/b1e10b08d287f518994f1e2ff9b6d26f0adeecd8dd7d533b01bab29a3eda/yarl-1.23.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34b6cf500e61c90f305094911f9acc9c86da1a05a7a3f5be9f68817043f486e4", size = 101559, upload-time = "2026-03-01T22:05:52.872Z" },
- { url = "https://files.pythonhosted.org/packages/72/59/c5b8d94b14e3d3c2a9c20cb100119fd534ab5a14b93673ab4cc4a4141ea5/yarl-1.23.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d7504f2b476d21653e4d143f44a175f7f751cd41233525312696c76aa3dbb23f", size = 100502, upload-time = "2026-03-01T22:05:54.954Z" },
- { url = "https://files.pythonhosted.org/packages/77/4f/96976cb54cbfc5c9fd73ed4c51804f92f209481d1fb190981c0f8a07a1d7/yarl-1.23.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:578110dd426f0d209d1509244e6d4a3f1a3e9077655d98c5f22583d63252a08a", size = 98027, upload-time = "2026-03-01T22:05:56.409Z" },
- { url = "https://files.pythonhosted.org/packages/63/6e/904c4f476471afdbad6b7e5b70362fb5810e35cd7466529a97322b6f5556/yarl-1.23.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:609d3614d78d74ebe35f54953c5bbd2ac647a7ddb9c30a5d877580f5e86b22f2", size = 95369, upload-time = "2026-03-01T22:05:58.141Z" },
- { url = "https://files.pythonhosted.org/packages/9d/40/acfcdb3b5f9d68ef499e39e04d25e141fe90661f9d54114556cf83be8353/yarl-1.23.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4966242ec68afc74c122f8459abd597afd7d8a60dc93d695c1334c5fd25f762f", size = 105565, upload-time = "2026-03-01T22:06:00.286Z" },
- { url = "https://files.pythonhosted.org/packages/5e/c6/31e28f3a6ba2869c43d124f37ea5260cac9c9281df803c354b31f4dd1f3c/yarl-1.23.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e0fd068364a6759bc794459f0a735ab151d11304346332489c7972bacbe9e72b", size = 99813, upload-time = "2026-03-01T22:06:01.712Z" },
- { url = "https://files.pythonhosted.org/packages/08/1f/6f65f59e72d54aa467119b63fc0b0b1762eff0232db1f4720cd89e2f4a17/yarl-1.23.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:39004f0ad156da43e86aa71f44e033de68a44e5a31fc53507b36dd253970054a", size = 105632, upload-time = "2026-03-01T22:06:03.188Z" },
- { url = "https://files.pythonhosted.org/packages/a3/c4/18b178a69935f9e7a338127d5b77d868fdc0f0e49becd286d51b3a18c61d/yarl-1.23.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e5723c01a56c5028c807c701aa66722916d2747ad737a046853f6c46f4875543", size = 101895, upload-time = "2026-03-01T22:06:04.651Z" },
- { url = "https://files.pythonhosted.org/packages/8f/54/f5b870b5505663911dba950a8e4776a0dbd51c9c54c0ae88e823e4b874a0/yarl-1.23.0-cp313-cp313-win32.whl", hash = "sha256:1b6b572edd95b4fa8df75de10b04bc81acc87c1c7d16bcdd2035b09d30acc957", size = 82356, upload-time = "2026-03-01T22:06:06.04Z" },
- { url = "https://files.pythonhosted.org/packages/7a/84/266e8da36879c6edcd37b02b547e2d9ecdfea776be49598e75696e3316e1/yarl-1.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:baaf55442359053c7d62f6f8413a62adba3205119bcb6f49594894d8be47e5e3", size = 87515, upload-time = "2026-03-01T22:06:08.107Z" },
- { url = "https://files.pythonhosted.org/packages/00/fd/7e1c66efad35e1649114fa13f17485f62881ad58edeeb7f49f8c5e748bf9/yarl-1.23.0-cp313-cp313-win_arm64.whl", hash = "sha256:fb4948814a2a98e3912505f09c9e7493b1506226afb1f881825368d6fb776ee3", size = 81785, upload-time = "2026-03-01T22:06:10.181Z" },
- { url = "https://files.pythonhosted.org/packages/9c/fc/119dd07004f17ea43bb91e3ece6587759edd7519d6b086d16bfbd3319982/yarl-1.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:aecfed0b41aa72b7881712c65cf764e39ce2ec352324f5e0837c7048d9e6daaa", size = 130719, upload-time = "2026-03-01T22:06:11.708Z" },
- { url = "https://files.pythonhosted.org/packages/e6/0d/9f2348502fbb3af409e8f47730282cd6bc80dec6630c1e06374d882d6eb2/yarl-1.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a41bcf68efd19073376eb8cf948b8d9be0af26256403e512bb18f3966f1f9120", size = 89690, upload-time = "2026-03-01T22:06:13.429Z" },
- { url = "https://files.pythonhosted.org/packages/50/93/e88f3c80971b42cfc83f50a51b9d165a1dbf154b97005f2994a79f212a07/yarl-1.23.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cde9a2ecd91668bcb7f077c4966d8ceddb60af01b52e6e3e2680e4cf00ad1a59", size = 89851, upload-time = "2026-03-01T22:06:15.53Z" },
- { url = "https://files.pythonhosted.org/packages/1c/07/61c9dd8ba8f86473263b4036f70fb594c09e99c0d9737a799dfd8bc85651/yarl-1.23.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5023346c4ee7992febc0068e7593de5fa2bf611848c08404b35ebbb76b1b0512", size = 95874, upload-time = "2026-03-01T22:06:17.553Z" },
- { url = "https://files.pythonhosted.org/packages/9e/e9/f9ff8ceefba599eac6abddcfb0b3bee9b9e636e96dbf54342a8577252379/yarl-1.23.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1009abedb49ae95b136a8904a3f71b342f849ffeced2d3747bf29caeda218c4", size = 88710, upload-time = "2026-03-01T22:06:19.004Z" },
- { url = "https://files.pythonhosted.org/packages/eb/78/0231bfcc5d4c8eec220bc2f9ef82cb4566192ea867a7c5b4148f44f6cbcd/yarl-1.23.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a8d00f29b42f534cc8aa3931cfe773b13b23e561e10d2b26f27a8d309b0e82a1", size = 101033, upload-time = "2026-03-01T22:06:21.203Z" },
- { url = "https://files.pythonhosted.org/packages/cd/9b/30ea5239a61786f18fd25797151a17fbb3be176977187a48d541b5447dd4/yarl-1.23.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:95451e6ce06c3e104556d73b559f5da6c34a069b6b62946d3ad66afcd51642ea", size = 100817, upload-time = "2026-03-01T22:06:22.738Z" },
- { url = "https://files.pythonhosted.org/packages/62/e2/a4980481071791bc83bce2b7a1a1f7adcabfa366007518b4b845e92eeee3/yarl-1.23.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:531ef597132086b6cf96faa7c6c1dcd0361dd5f1694e5cc30375907b9b7d3ea9", size = 97482, upload-time = "2026-03-01T22:06:24.21Z" },
- { url = "https://files.pythonhosted.org/packages/e5/1e/304a00cf5f6100414c4b5a01fc7ff9ee724b62158a08df2f8170dfc72a2d/yarl-1.23.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:88f9fb0116fbfcefcab70f85cf4b74a2b6ce5d199c41345296f49d974ddb4123", size = 95949, upload-time = "2026-03-01T22:06:25.697Z" },
- { url = "https://files.pythonhosted.org/packages/68/03/093f4055ed4cae649ac53bca3d180bd37102e9e11d048588e9ab0c0108d0/yarl-1.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e7b0460976dc75cb87ad9cc1f9899a4b97751e7d4e77ab840fc9b6d377b8fd24", size = 95839, upload-time = "2026-03-01T22:06:27.309Z" },
- { url = "https://files.pythonhosted.org/packages/b9/28/4c75ebb108f322aa8f917ae10a8ffa4f07cae10a8a627b64e578617df6a0/yarl-1.23.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:115136c4a426f9da976187d238e84139ff6b51a20839aa6e3720cd1026d768de", size = 90696, upload-time = "2026-03-01T22:06:29.048Z" },
- { url = "https://files.pythonhosted.org/packages/23/9c/42c2e2dd91c1a570402f51bdf066bfdb1241c2240ba001967bad778e77b7/yarl-1.23.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ead11956716a940c1abc816b7df3fa2b84d06eaed8832ca32f5c5e058c65506b", size = 100865, upload-time = "2026-03-01T22:06:30.525Z" },
- { url = "https://files.pythonhosted.org/packages/74/05/1bcd60a8a0a914d462c305137246b6f9d167628d73568505fce3f1cb2e65/yarl-1.23.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:fe8f8f5e70e6dbdfca9882cd9deaac058729bcf323cf7a58660901e55c9c94f6", size = 96234, upload-time = "2026-03-01T22:06:32.692Z" },
- { url = "https://files.pythonhosted.org/packages/90/b2/f52381aac396d6778ce516b7bc149c79e65bfc068b5de2857ab69eeea3b7/yarl-1.23.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:a0e317df055958a0c1e79e5d2aa5a5eaa4a6d05a20d4b0c9c3f48918139c9fc6", size = 100295, upload-time = "2026-03-01T22:06:34.268Z" },
- { url = "https://files.pythonhosted.org/packages/e5/e8/638bae5bbf1113a659b2435d8895474598afe38b4a837103764f603aba56/yarl-1.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f0fd84de0c957b2d280143522c4f91a73aada1923caee763e24a2b3fda9f8a5", size = 97784, upload-time = "2026-03-01T22:06:35.864Z" },
- { url = "https://files.pythonhosted.org/packages/80/25/a3892b46182c586c202629fc2159aa13975d3741d52ebd7347fd501d48d5/yarl-1.23.0-cp313-cp313t-win32.whl", hash = "sha256:93a784271881035ab4406a172edb0faecb6e7d00f4b53dc2f55919d6c9688595", size = 88313, upload-time = "2026-03-01T22:06:37.39Z" },
- { url = "https://files.pythonhosted.org/packages/43/68/8c5b36aa5178900b37387937bc2c2fe0e9505537f713495472dcf6f6fccc/yarl-1.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dd00607bffbf30250fe108065f07453ec124dbf223420f57f5e749b04295e090", size = 94932, upload-time = "2026-03-01T22:06:39.579Z" },
- { url = "https://files.pythonhosted.org/packages/c6/cc/d79ba8292f51f81f4dc533a8ccfb9fc6992cabf0998ed3245de7589dc07c/yarl-1.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ac09d42f48f80c9ee1635b2fcaa819496a44502737660d3c0f2ade7526d29144", size = 84786, upload-time = "2026-03-01T22:06:41.988Z" },
- { url = "https://files.pythonhosted.org/packages/90/98/b85a038d65d1b92c3903ab89444f48d3cee490a883477b716d7a24b1a78c/yarl-1.23.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:21d1b7305a71a15b4794b5ff22e8eef96ff4a6d7f9657155e5aa419444b28912", size = 124455, upload-time = "2026-03-01T22:06:43.615Z" },
- { url = "https://files.pythonhosted.org/packages/39/54/bc2b45559f86543d163b6e294417a107bb87557609007c007ad889afec18/yarl-1.23.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:85610b4f27f69984932a7abbe52703688de3724d9f72bceb1cca667deff27474", size = 86752, upload-time = "2026-03-01T22:06:45.425Z" },
- { url = "https://files.pythonhosted.org/packages/24/f9/e8242b68362bffe6fb536c8db5076861466fc780f0f1b479fc4ffbebb128/yarl-1.23.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23f371bd662cf44a7630d4d113101eafc0cfa7518a2760d20760b26021454719", size = 86291, upload-time = "2026-03-01T22:06:46.974Z" },
- { url = "https://files.pythonhosted.org/packages/ea/d8/d1cb2378c81dd729e98c716582b1ccb08357e8488e4c24714658cc6630e8/yarl-1.23.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4a80f77dc1acaaa61f0934176fccca7096d9b1ff08c8ba9cddf5ae034a24319", size = 99026, upload-time = "2026-03-01T22:06:48.459Z" },
- { url = "https://files.pythonhosted.org/packages/0a/ff/7196790538f31debe3341283b5b0707e7feb947620fc5e8236ef28d44f72/yarl-1.23.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:bd654fad46d8d9e823afbb4f87c79160b5a374ed1ff5bde24e542e6ba8f41434", size = 92355, upload-time = "2026-03-01T22:06:50.306Z" },
- { url = "https://files.pythonhosted.org/packages/c1/56/25d58c3eddde825890a5fe6aa1866228377354a3c39262235234ab5f616b/yarl-1.23.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:682bae25f0a0dd23a056739f23a134db9f52a63e2afd6bfb37ddc76292bbd723", size = 106417, upload-time = "2026-03-01T22:06:52.1Z" },
- { url = "https://files.pythonhosted.org/packages/51/8a/882c0e7bc8277eb895b31bce0138f51a1ba551fc2e1ec6753ffc1e7c1377/yarl-1.23.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a82836cab5f197a0514235aaf7ffccdc886ccdaa2324bc0aafdd4ae898103039", size = 106422, upload-time = "2026-03-01T22:06:54.424Z" },
- { url = "https://files.pythonhosted.org/packages/42/2b/fef67d616931055bf3d6764885990a3ac647d68734a2d6a9e1d13de437a2/yarl-1.23.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c57676bdedc94cd3bc37724cf6f8cd2779f02f6aba48de45feca073e714fe52", size = 101915, upload-time = "2026-03-01T22:06:55.895Z" },
- { url = "https://files.pythonhosted.org/packages/18/6a/530e16aebce27c5937920f3431c628a29a4b6b430fab3fd1c117b26ff3f6/yarl-1.23.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c7f8dc16c498ff06497c015642333219871effba93e4a2e8604a06264aca5c5c", size = 100690, upload-time = "2026-03-01T22:06:58.21Z" },
- { url = "https://files.pythonhosted.org/packages/88/08/93749219179a45e27b036e03260fda05190b911de8e18225c294ac95bbc9/yarl-1.23.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5ee586fb17ff8f90c91cf73c6108a434b02d69925f44f5f8e0d7f2f260607eae", size = 98750, upload-time = "2026-03-01T22:06:59.794Z" },
- { url = "https://files.pythonhosted.org/packages/d9/cf/ea424a004969f5d81a362110a6ac1496d79efdc6d50c2c4b2e3ea0fc2519/yarl-1.23.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:17235362f580149742739cc3828b80e24029d08cbb9c4bda0242c7b5bc610a8e", size = 94685, upload-time = "2026-03-01T22:07:01.375Z" },
- { url = "https://files.pythonhosted.org/packages/e2/b7/14341481fe568e2b0408bcf1484c652accafe06a0ade9387b5d3fd9df446/yarl-1.23.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:0793e2bd0cf14234983bbb371591e6bea9e876ddf6896cdcc93450996b0b5c85", size = 106009, upload-time = "2026-03-01T22:07:03.151Z" },
- { url = "https://files.pythonhosted.org/packages/0a/e6/5c744a9b54f4e8007ad35bce96fbc9218338e84812d36f3390cea616881a/yarl-1.23.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3650dc2480f94f7116c364096bc84b1d602f44224ef7d5c7208425915c0475dd", size = 100033, upload-time = "2026-03-01T22:07:04.701Z" },
- { url = "https://files.pythonhosted.org/packages/0c/23/e3bfc188d0b400f025bc49d99793d02c9abe15752138dcc27e4eaf0c4a9e/yarl-1.23.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f40e782d49630ad384db66d4d8b73ff4f1b8955dc12e26b09a3e3af064b3b9d6", size = 106483, upload-time = "2026-03-01T22:07:06.231Z" },
- { url = "https://files.pythonhosted.org/packages/72/42/f0505f949a90b3f8b7a363d6cbdf398f6e6c58946d85c6d3a3bc70595b26/yarl-1.23.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94f8575fbdf81749008d980c17796097e645574a3b8c28ee313931068dad14fe", size = 102175, upload-time = "2026-03-01T22:07:08.4Z" },
- { url = "https://files.pythonhosted.org/packages/aa/65/b39290f1d892a9dd671d1c722014ca062a9c35d60885d57e5375db0404b5/yarl-1.23.0-cp314-cp314-win32.whl", hash = "sha256:c8aa34a5c864db1087d911a0b902d60d203ea3607d91f615acd3f3108ac32169", size = 83871, upload-time = "2026-03-01T22:07:09.968Z" },
- { url = "https://files.pythonhosted.org/packages/a9/5b/9b92f54c784c26e2a422e55a8d2607ab15b7ea3349e28359282f84f01d43/yarl-1.23.0-cp314-cp314-win_amd64.whl", hash = "sha256:63e92247f383c85ab00dd0091e8c3fa331a96e865459f5ee80353c70a4a42d70", size = 89093, upload-time = "2026-03-01T22:07:11.501Z" },
- { url = "https://files.pythonhosted.org/packages/e0/7d/8a84dc9381fd4412d5e7ff04926f9865f6372b4c2fd91e10092e65d29eb8/yarl-1.23.0-cp314-cp314-win_arm64.whl", hash = "sha256:70efd20be968c76ece7baa8dafe04c5be06abc57f754d6f36f3741f7aa7a208e", size = 83384, upload-time = "2026-03-01T22:07:13.069Z" },
- { url = "https://files.pythonhosted.org/packages/dd/8d/d2fad34b1c08aa161b74394183daa7d800141aaaee207317e82c790b418d/yarl-1.23.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:9a18d6f9359e45722c064c97464ec883eb0e0366d33eda61cb19a244bf222679", size = 131019, upload-time = "2026-03-01T22:07:14.903Z" },
- { url = "https://files.pythonhosted.org/packages/19/ff/33009a39d3ccf4b94d7d7880dfe17fb5816c5a4fe0096d9b56abceea9ac7/yarl-1.23.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2803ed8b21ca47a43da80a6fd1ed3019d30061f7061daa35ac54f63933409412", size = 89894, upload-time = "2026-03-01T22:07:17.372Z" },
- { url = "https://files.pythonhosted.org/packages/0c/f1/dab7ac5e7306fb79c0190766a3c00b4cb8d09a1f390ded68c85a5934faf5/yarl-1.23.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:394906945aa8b19fc14a61cf69743a868bb8c465efe85eee687109cc540b98f4", size = 89979, upload-time = "2026-03-01T22:07:19.361Z" },
- { url = "https://files.pythonhosted.org/packages/aa/b1/08e95f3caee1fad6e65017b9f26c1d79877b502622d60e517de01e72f95d/yarl-1.23.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71d006bee8397a4a89f469b8deb22469fe7508132d3c17fa6ed871e79832691c", size = 95943, upload-time = "2026-03-01T22:07:21.266Z" },
- { url = "https://files.pythonhosted.org/packages/c0/cc/6409f9018864a6aa186c61175b977131f373f1988e198e031236916e87e4/yarl-1.23.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:62694e275c93d54f7ccedcfef57d42761b2aad5234b6be1f3e3026cae4001cd4", size = 88786, upload-time = "2026-03-01T22:07:23.129Z" },
- { url = "https://files.pythonhosted.org/packages/76/40/cc22d1d7714b717fde2006fad2ced5efe5580606cb059ae42117542122f3/yarl-1.23.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31de1613658308efdb21ada98cbc86a97c181aa050ba22a808120bb5be3ab94", size = 101307, upload-time = "2026-03-01T22:07:24.689Z" },
- { url = "https://files.pythonhosted.org/packages/8f/0d/476c38e85ddb4c6ec6b20b815bdd779aa386a013f3d8b85516feee55c8dc/yarl-1.23.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb1e8b8d66c278b21d13b0a7ca22c41dd757a7c209c6b12c313e445c31dd3b28", size = 100904, upload-time = "2026-03-01T22:07:26.287Z" },
- { url = "https://files.pythonhosted.org/packages/72/32/0abe4a76d59adf2081dcb0397168553ece4616ada1c54d1c49d8936c74f8/yarl-1.23.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50f9d8d531dfb767c565f348f33dd5139a6c43f5cbdf3f67da40d54241df93f6", size = 97728, upload-time = "2026-03-01T22:07:27.906Z" },
- { url = "https://files.pythonhosted.org/packages/b7/35/7b30f4810fba112f60f5a43237545867504e15b1c7647a785fbaf588fac2/yarl-1.23.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:575aa4405a656e61a540f4a80eaa5260f2a38fff7bfdc4b5f611840d76e9e277", size = 95964, upload-time = "2026-03-01T22:07:30.198Z" },
- { url = "https://files.pythonhosted.org/packages/2d/86/ed7a73ab85ef00e8bb70b0cb5421d8a2a625b81a333941a469a6f4022828/yarl-1.23.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:041b1a4cefacf65840b4e295c6985f334ba83c30607441ae3cf206a0eed1a2e4", size = 95882, upload-time = "2026-03-01T22:07:32.132Z" },
- { url = "https://files.pythonhosted.org/packages/19/90/d56967f61a29d8498efb7afb651e0b2b422a1e9b47b0ab5f4e40a19b699b/yarl-1.23.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:d38c1e8231722c4ce40d7593f28d92b5fc72f3e9774fe73d7e800ec32299f63a", size = 90797, upload-time = "2026-03-01T22:07:34.404Z" },
- { url = "https://files.pythonhosted.org/packages/72/00/8b8f76909259f56647adb1011d7ed8b321bcf97e464515c65016a47ecdf0/yarl-1.23.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:d53834e23c015ee83a99377db6e5e37d8484f333edb03bd15b4bc312cc7254fb", size = 101023, upload-time = "2026-03-01T22:07:35.953Z" },
- { url = "https://files.pythonhosted.org/packages/ac/e2/cab11b126fb7d440281b7df8e9ddbe4851e70a4dde47a202b6642586b8d9/yarl-1.23.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2e27c8841126e017dd2a054a95771569e6070b9ee1b133366d8b31beb5018a41", size = 96227, upload-time = "2026-03-01T22:07:37.594Z" },
- { url = "https://files.pythonhosted.org/packages/c2/9b/2c893e16bfc50e6b2edf76c1a9eb6cb0c744346197e74c65e99ad8d634d0/yarl-1.23.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:76855800ac56f878847a09ce6dba727c93ca2d89c9e9d63002d26b916810b0a2", size = 100302, upload-time = "2026-03-01T22:07:39.334Z" },
- { url = "https://files.pythonhosted.org/packages/28/ec/5498c4e3a6d5f1003beb23405671c2eb9cdbf3067d1c80f15eeafe301010/yarl-1.23.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e09fd068c2e169a7070d83d3bde728a4d48de0549f975290be3c108c02e499b4", size = 98202, upload-time = "2026-03-01T22:07:41.717Z" },
- { url = "https://files.pythonhosted.org/packages/fe/c3/cd737e2d45e70717907f83e146f6949f20cc23cd4bf7b2688727763aa458/yarl-1.23.0-cp314-cp314t-win32.whl", hash = "sha256:73309162a6a571d4cbd3b6a1dcc703c7311843ae0d1578df6f09be4e98df38d4", size = 90558, upload-time = "2026-03-01T22:07:43.433Z" },
- { url = "https://files.pythonhosted.org/packages/e1/19/3774d162f6732d1cfb0b47b4140a942a35ca82bb19b6db1f80e9e7bdc8f8/yarl-1.23.0-cp314-cp314t-win_amd64.whl", hash = "sha256:4503053d296bc6e4cbd1fad61cf3b6e33b939886c4f249ba7c78b602214fabe2", size = 97610, upload-time = "2026-03-01T22:07:45.773Z" },
- { url = "https://files.pythonhosted.org/packages/51/47/3fa2286c3cb162c71cdb34c4224d5745a1ceceb391b2bd9b19b668a8d724/yarl-1.23.0-cp314-cp314t-win_arm64.whl", hash = "sha256:44bb7bef4ea409384e3f8bc36c063d77ea1b8d4a5b2706956c0d6695f07dcc25", size = 86041, upload-time = "2026-03-01T22:07:49.026Z" },
- { url = "https://files.pythonhosted.org/packages/69/68/c8739671f5699c7dc470580a4f821ef37c32c4cb0b047ce223a7f115757f/yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f", size = 48288, upload-time = "2026-03-01T22:07:51.388Z" },
-]
diff --git a/wrapper_backend/CLAUDE.md b/wrapper_backend/CLAUDE.md
deleted file mode 100644
index cc36d53..0000000
--- a/wrapper_backend/CLAUDE.md
+++ /dev/null
@@ -1,42 +0,0 @@
-# CLAUDE.md — wrapper_backend
-
-Async Python application replacing `python/geom_publisher.py`. Owned by uv; managed via `pyproject.toml` at repo root.
-
-## Commands
-
-All run from repo root.
-
-- Run: `./start_wrapper.sh [geometry-X.yml]` (or `uv run python -m wrapper_backend geometry.yml`)
-- Type check: `uv run mypy wrapper_backend/`
-- Lint: `uv run ruff check wrapper_backend/`
-- Format: `uv run ruff format wrapper_backend/`
-- Pre-commit (manual run on wrapper files): `uv run pre-commit run --files wrapper_backend/*.py`
-
-## Architecture
-
-An `aiohttp.web.Application` owns the listener (default `:8765`). Each feature module exposes `register(http_app, ...)` which adds its routes and any cleanup hooks. `__main__.py` builds the app, calls each `register`, runs an `AppRunner` + `TCPSite`, and then drives the geometry publisher loop. Modules:
-
-- `bus.py` — every `subscribe(topic)` returns its own size-1 `asyncio.Queue`. `publish` drains-then-puts; slow subscribers see only the latest value.
-- `multicast.py` — `asyncio.DatagramProtocol` UDP. Inbound parses `SSL_WrapperPacket` and demuxes into `geometry.in` / `detection.in`. Outbound subscribes to `wrapper_packet.out` (bytes) and `sendto`s.
-- `geometry.py` — owns `geometry.yml` + in-memory `SSL_WrapperPacket`. Two tasks: `_absorb_loop` (replace-or-append calibs) and `_publish_loop` (1 Hz emit). Both share `self._wrapper`; no locks because asyncio doesn't preempt between non-`await` statements. Publisher serialises to bytes before publishing so the snapshot is locked-in before the multicast adapter awaits.
-- `websocket.py` — aiohttp WS at `/ws`. Lazy per-topic bus subscription: a channel's bus-reader task starts when the first client joins and stops when the last leaves. Each connected client owns its own size-1 outbound queue (slow clients drop intermediate frames). Read-only for now; envelope (`{"topic": ..., "data": ...}` and `{"action": ..., "topic": ...}`) is symmetric so inbound commands can be added later without breaking the wire format. Topic-to-JSON encoders live in `_TOPIC_ENCODERS`.
-- `snapshot.py` — two aiohttp routes. `GET /snapshots` walks `img/` and returns matching `..{jpg,png}` filenames as a JSON list of `{cam_id, view}` (legacy / non-matching files are filtered by a regex). `GET /snapshot/{cam_id}/{view}` globs `img/{cam_id}.{view}.*` and streams the most-recently-modified match via `web.FileResponse` (sendfile-backed, 404 when nothing matches). The C++ `SnapshotWriter` writes those files via `tmp → rename`, so reads are torn-frame-free without coordination.
-
-Topics: `geometry.in`, `detection.in` (inbound demuxed), `wrapper_packet.out` (outbound bytes).
-
-## Gotchas
-
-- `ParseDict` runs strict (no `ignore_unknown_fields`). A typo in `geometry.yml` raises at startup. Don't add forgiveness.
-- `optional_field_lines:` controls the SSL markings that may be absent on lab/exhibition carpets: `goal2goal` (CenterLine), `halfway` (HalfwayLine), `centercircle` (CenterCircle arc), `penalty` (the six penalty-area stretches). Touchlines and goal lines are always emitted. The block and all four keys are required — `load_geometry` pops the block before `ParseDict` so strict parse still rejects typos elsewhere, and missing keys raise `KeyError` rather than silently defaulting.
-- Two `# type: ignore[assignment]` on `SSL_FieldShapeType.Value(...)` calls are unavoidable: `types-protobuf` types `Value()` as `int` while proto enum fields are typed as the enum.
-- Protocol definitions live in the `proto/` git submodule (`RoboCup-SSL/ssl-protocol-defs`, `main`); the `.proto` sources are under `proto/proto/vision/`. Generated proto bindings are NOT committed. `wrapper_backend/__init__.py` calls the submodule's shared generator `proto/python/python_bindings.py` on first import if `wrapper_backend/proto/vision/ssl_vision_wrapper_pb2.py` is missing; that helper nests the bindings under `proto` and rewrites protoc's generated cross-imports (`from vision import ...` -> `from proto.vision import ...`), which is what makes them importable. It then prepends `wrapper_backend/` to `sys.path` so `from proto.vision.* import ...` resolves to `wrapper_backend/proto/vision/`. mypy uses `mypy_path = "wrapper_backend"` and excludes `wrapper_backend/proto/` to mirror this.
-- `python/` scripts (`geom_publisher.py`, `cam_viewer.py`, benchmarks) are NOT covered by the wrapper's tooling. They keep running on system Python; never modify them as part of wrapper work unless explicitly asked.
-- Pre-commit hooks are scoped to `^wrapper_backend/` for ruff. Don't widen the scope without reason — would reformat all the legacy `python/` files.
-
-## CLI flags
-
-Dash form only: `--vision-ip`, `--vision-port`, `--host`, `--port`. `geom_publisher.py`'s underscore form is dropped.
-
-## Out-of-scope (planned but not yet built)
-
-`vision_processor` subprocess supervisor, calib persistence to `geometry.yml`, production static-build serving (Svelte `dist/` mounted as `web.static('/')`). Each will be an additive module subscribing to the bus or registering routes — don't restructure existing modules to anticipate them.
diff --git a/wrapper_backend/README.md b/wrapper_backend/README.md
deleted file mode 100644
index 2fea25a..0000000
--- a/wrapper_backend/README.md
+++ /dev/null
@@ -1,85 +0,0 @@
-# wrapper_backend
-
-Python application that owns the field geometry and (eventually) the browser-based calibration UI for `vision_processor`. Replaces `python/geom_publisher.py` with a modular asyncio base that other modules — web server, WebSocket bridge, `vision_processor` supervisor — can plug into without touching existing code.
-
-## Run
-
-```
-./start_wrapper.sh # uses geometry-divB.yml
-./start_wrapper.sh geometry-divA.yml # different config
-./start_wrapper.sh geometry-divB.yml --vision-port 10100
-./start_wrapper.sh geometry-divB.yml --port 9000
-```
-
-The wrapper loads the given `geometry-*.yml`, broadcasts an `SSL_WrapperPacket` at 1 Hz on the multicast bus (default `224.5.23.2:10006`), and absorbs incoming per-camera calibrations into its in-memory state. Logs go to stderr.
-
-## Architecture
-
-The wrapper is a single asyncio process listening on `:8765`. Inside,
-modules don't call each other directly; they talk through an in-process
-pub/sub bus. From the outside, this is what it does:
-
-- Listens for SSL vision multicast traffic on UDP and parses it.
-- Folds incoming per-camera calibrations into one merged geometry state.
-- Re-broadcasts that merged state back onto the multicast group at 1 Hz.
-- Exposes the same internal topics to the browser frontend over WebSocket.
-- Serves the debug images that the C++ side writes to disk.
-
-### Files
-
-Each file is one module. In rough "outside-in" order:
-
-- **`multicast.py`** — the UDP I/O layer. Receives `SSL_WrapperPacket`s
- from the multicast group, splits them into geometry / detection topics,
- and sends our own merged packets back out.
-- **`geometry.py`** — the brains. Holds one in-memory `SSL_WrapperPacket`,
- replaces or appends per-camera calibrations as they arrive, and emits
- the current state once a second.
-- **`websocket.py`** — the WebSocket endpoint at `/ws`. Lets browser
- clients subscribe to any bus topic and receive frames as JSON. Client
- side lives in `wrapper-frontend/src/lib/wrapper-bus.ts`.
-- **`snapshot.py`** — the debug-image endpoints. `GET /snapshots`
- returns the list of `{cam_id, view}` entries currently on disk;
- `GET /snapshot//` serves the JPEG/PNG itself. Files are
- written by the C++ `SnapshotWriter` into `img/`, which is hardcoded on
- both sides (relative to each process's cwd).
-- **`bus.py`** — the pub/sub bus everything else talks through. Each
- subscriber gets its own size-1 queue, so slow readers see only the
- latest message and never block publishers.
-- **`__main__.py`** — entry point. Parses CLI args, sets up logging, and
- wires all the modules above onto one aiohttp app.
-
-### Topics on the bus
-
-| Topic | Payload | Written by | Read by |
-|---|---|---|---|
-| `geometry.in` | `SSL_GeometryData` | `multicast.py` (inbound) | `geometry.py` |
-| `detection.in` | `SSL_DetectionFrame` | `multicast.py` (inbound) | (none yet) |
-| `wrapper_packet.out` | serialised `SSL_WrapperPacket` bytes | `geometry.py` | `multicast.py` (outbound), `websocket.py` |
-
-## Development
-
-Project is managed by [uv](https://astral.sh/uv). On a fresh clone:
-
-```
-uv sync # install deps + dev deps
-uv run pre-commit install # enable git hooks
-```
-
-Day-to-day:
-
-```
-uv run mypy wrapper_backend/
-uv run ruff check wrapper_backend/
-uv run ruff format wrapper_backend/
-```
-
-The pre-commit hook runs ruff (`--fix` + format) scoped to `wrapper_backend/` and mypy on every commit. Existing `python/` scripts are not subject to the new tooling and keep running against the system Python.
-
-Type stubs for `protobuf` and `pyyaml` are dev deps. The two `# type: ignore[assignment]` on `SSL_FieldShapeType.Value(...)` calls in `geometry.py` work around an upstream `types-protobuf` stub mismatch (`Value()` is typed as returning `int` while proto enum fields are typed as the enum).
-
-## Behavioural deltas vs `python/geom_publisher.py`
-
-- **Strict YAML parsing.** `ParseDict` runs without `ignore_unknown_fields`, so a typo in `geometry.yml` raises at startup instead of being silently dropped.
-- **`default_lines:` renamed to `optional_field_lines:`** with all four toggles required. See `wrapper_backend/CLAUDE.md` for details.
-- **Dash-form CLI flags only** (`--vision-ip`, `--vision-port`, `--host`, `--port`). The underscore form is dropped.
diff --git a/wrapper_backend/__init__.py b/wrapper_backend/__init__.py
deleted file mode 100644
index b669cde..0000000
--- a/wrapper_backend/__init__.py
+++ /dev/null
@@ -1,39 +0,0 @@
-from __future__ import annotations
-
-import pathlib
-import sys
-
-_BACKEND_DIR = pathlib.Path(__file__).resolve().parent
-_REPO_ROOT = _BACKEND_DIR.parent
-_PROTO_DEFS = _REPO_ROOT / "proto"
-_PROTO_SRC = _PROTO_DEFS / "proto" / "vision"
-_PROTO_OUT = _BACKEND_DIR / "proto" / "vision"
-
-sys.path.insert(0, str(_PROTO_DEFS / "python"))
-from python_bindings import generate_python_bindings # noqa: E402
-
-
-def _bindings_are_stale() -> bool:
- outputs = list(_PROTO_OUT.glob("*_pb2.py"))
- if not outputs:
- return True
- sources = list(_PROTO_SRC.glob("*.proto"))
- if not sources:
- return True
- oldest_out = min(o.stat().st_mtime for o in outputs)
- newest_src = max(s.stat().st_mtime for s in sources)
- return newest_src > oldest_out
-
-
-if _bindings_are_stale():
- print("Compiling Protobuf files...", file=sys.stderr)
- # The generator nests everything under `proto` and rewrites the generated
- # cross-imports to match; see proto/python/python_bindings.py for why bare
- # `--python_out` is not enough.
- generate_python_bindings(
- out_dir=_BACKEND_DIR, package="proto", includes=["vision", "gamecontroller"]
- )
-
-# The generated package is `wrapper_backend/proto/`, so `wrapper_backend/` must
-# be on sys.path for `from proto.vision.* import ...` to resolve.
-sys.path.insert(0, str(_BACKEND_DIR))
diff --git a/wrapper_backend/__main__.py b/wrapper_backend/__main__.py
deleted file mode 100644
index 06e2aab..0000000
--- a/wrapper_backend/__main__.py
+++ /dev/null
@@ -1,79 +0,0 @@
-"""CLI entrypoint for the wrapper.
-
-Run with:
-
- uv run python -m wrapper_backend geometry.yml
-"""
-
-from __future__ import annotations
-
-import argparse
-import asyncio
-import logging
-from pathlib import Path
-
-from collections.abc import Awaitable, Callable
-
-from aiohttp import web
-
-from wrapper_backend import snapshot, websocket
-from wrapper_backend.bus import Bus
-from wrapper_backend.geometry import Geometry
-from wrapper_backend.multicast import Multicast
-
-log = logging.getLogger("wrapper_backend")
-
-
-@web.middleware
-async def _cors_middleware(
- request: web.Request,
- handler: Callable[[web.Request], Awaitable[web.StreamResponse]],
-) -> web.StreamResponse:
- # Dev-mode wide-open CORS so the Vite dev server on :5173 can call
- # /snapshots and /ws from a different origin. Tighten before prod.
- response = await handler(request)
- response.headers["Access-Control-Allow-Origin"] = "*"
- return response
-
-
-async def _main() -> None:
- parser = argparse.ArgumentParser(prog="wrapper")
- parser.add_argument("geometry", type=Path, help="geometry.yml path")
- parser.add_argument("--vision-ip", default="224.5.23.2")
- parser.add_argument("--vision-port", type=int, default=10006)
- parser.add_argument("--host", default="0.0.0.0")
- parser.add_argument("--port", type=int, default=8765)
- args = parser.parse_args()
-
- bus = Bus()
- multicast = Multicast(bus, args.vision_ip, args.vision_port)
- geometry = Geometry(bus, args.geometry)
-
- http_app = web.Application(middlewares=[_cors_middleware])
- websocket.register(http_app, bus)
- snapshot.register(http_app, Path("img"))
-
- http_runner = web.AppRunner(http_app)
- await http_runner.setup()
- http_site = web.TCPSite(http_runner, args.host, args.port)
- await http_site.start()
- log.info("http+ws listening on %s:%d", args.host, args.port)
-
- try:
- await multicast.start()
- await geometry.run()
- finally:
- await http_runner.cleanup()
- await multicast.close()
-
-
-def main() -> None:
- logging.basicConfig(
- level=logging.INFO,
- format="%(asctime)s %(name)s %(levelname)s %(message)s",
- )
- asyncio.run(_main())
-
-
-if __name__ == "__main__":
- main()
diff --git a/wrapper_backend/bus.py b/wrapper_backend/bus.py
deleted file mode 100644
index c79c912..0000000
--- a/wrapper_backend/bus.py
+++ /dev/null
@@ -1,41 +0,0 @@
-"""In-process async pub/sub with watch-channel semantics.
-
-Each subscriber gets its own size-1 asyncio.Queue. On publish, every
-subscriber's queue is drained-then-filled with the new message. Slow
-subscribers see only the latest value at the time they wake up;
-intermediate values are dropped.
-"""
-
-from __future__ import annotations
-
-import asyncio
-from typing import Any
-
-
-class Bus:
- def __init__(self) -> None:
- self._subs: dict[str, list[asyncio.Queue[Any]]] = {}
-
- def subscribe(self, topic: str) -> asyncio.Queue[Any]:
- queue: asyncio.Queue[Any] = asyncio.Queue(maxsize=1)
- self._subs.setdefault(topic, []).append(queue)
- return queue
-
- def publish(self, topic: str, msg: Any) -> None:
- for queue in self._subs.get(topic, ()):
- try:
- queue.get_nowait()
- except asyncio.QueueEmpty:
- pass
- queue.put_nowait(msg)
-
- def unsubscribe(self, topic: str, queue: asyncio.Queue[Any]) -> None:
- subs = self._subs.get(topic)
- if subs is None:
- return
- try:
- subs.remove(queue)
- except ValueError:
- return
- if not subs:
- del self._subs[topic]
diff --git a/wrapper_backend/geometry.py b/wrapper_backend/geometry.py
deleted file mode 100644
index ec2e023..0000000
--- a/wrapper_backend/geometry.py
+++ /dev/null
@@ -1,175 +0,0 @@
-"""Owns geometry.yml + the in-memory SSL_WrapperPacket.
-
-Two concurrent tasks:
-- _absorb_loop: subscribe to geometry.in, replace-or-append per-camera
- calibrations into the SSL_WrapperPacket.
-- _publish_loop: every second, the SSL_WrapperPacket on wrapper_packet.out.
-"""
-
-from __future__ import annotations
-
-import asyncio
-import logging
-import math
-from pathlib import Path
-
-import yaml
-from google.protobuf.json_format import ParseDict
-
-from proto.vision.ssl_vision_geometry_pb2 import (
- SSL_FieldShapeType,
- SSL_GeometryData,
-)
-from proto.vision.ssl_vision_wrapper_pb2 import (
- SSL_SOURCE_VISION_PROCESSOR,
- SSL_WrapperPacket,
-)
-from wrapper_backend.bus import Bus
-
-log = logging.getLogger("wrapper_backend.geometry")
-
-PUBLISH_INTERVAL_S = 1.0
-
-
-def _generate_field_markings(
- wrapper: SSL_WrapperPacket, field: dict, optional_lines: dict
-) -> None:
- lines = wrapper.geometry.field.field_lines
-
- thickness = field["line_thickness"]
- half_length = field["field_length"] / 2
- half_width = field["field_width"] / 2
- penalty_length = half_length - field["penalty_area_depth"]
- half_penalty = field["penalty_area_width"] / 2
-
- def add_line(name: str, x1: float, y1: float, x2: float, y2: float) -> None:
- line = lines.add()
- line.name = name
- line.p1.x = x1
- line.p1.y = y1
- line.p2.x = x2
- line.p2.y = y2
- line.thickness = thickness
- line.type = SSL_FieldShapeType.Value(name) # type: ignore[assignment]
-
- add_line("TopTouchLine", -half_length, half_width, half_length, half_width)
- add_line("BottomTouchLine", -half_length, -half_width, half_length, -half_width)
- add_line("LeftGoalLine", -half_length, -half_width, -half_length, half_width)
- add_line("RightGoalLine", half_length, -half_width, half_length, half_width)
- if optional_lines["halfway"]:
- add_line("HalfwayLine", 0, -half_width, 0, half_width)
- if optional_lines["goal2goal"]:
- add_line("CenterLine", -half_length, 0, half_length, 0)
- if optional_lines["penalty"]:
- add_line(
- "LeftPenaltyStretch",
- -penalty_length,
- -half_penalty,
- -penalty_length,
- half_penalty,
- )
- add_line(
- "RightPenaltyStretch",
- penalty_length,
- -half_penalty,
- penalty_length,
- half_penalty,
- )
- add_line(
- "LeftFieldLeftPenaltyStretch",
- -half_length,
- -half_penalty,
- -penalty_length,
- -half_penalty,
- )
- add_line(
- "LeftFieldRightPenaltyStretch",
- -half_length,
- half_penalty,
- -penalty_length,
- half_penalty,
- )
- add_line(
- "RightFieldLeftPenaltyStretch",
- penalty_length,
- half_penalty,
- half_length,
- half_penalty,
- )
- add_line(
- "RightFieldRightPenaltyStretch",
- penalty_length,
- -half_penalty,
- half_length,
- -half_penalty,
- )
-
- if optional_lines["centercircle"]:
- arc = wrapper.geometry.field.field_arcs.add()
- arc.name = "CenterCircle"
- arc.type = SSL_FieldShapeType.Value(arc.name) # type: ignore[assignment]
- arc.center.x = 0.0
- arc.center.y = 0.0
- arc.radius = field["center_circle_radius"]
- arc.a1 = 0
- arc.a2 = math.tau
- arc.thickness = thickness
-
-
-def load_geometry(path: Path) -> SSL_WrapperPacket:
- with path.open("r") as f:
- config = yaml.safe_load(f)
-
- optional_lines = config.pop("optional_field_lines")
- wrapper = SSL_WrapperPacket()
- ParseDict(config, wrapper.geometry)
- _generate_field_markings(wrapper, config["field"], optional_lines)
- wrapper.source = SSL_SOURCE_VISION_PROCESSOR
- return wrapper
-
-
-class Geometry:
- def __init__(self, bus: Bus, geometry_yml_path: Path) -> None:
- self._bus = bus
- self._wrapper = load_geometry(geometry_yml_path)
- log.info(
- "loaded %s with %d initial calib(s)",
- geometry_yml_path,
- len(self._wrapper.geometry.calib),
- )
-
- async def run(self) -> None:
- await asyncio.gather(
- self._absorb_loop(),
- self._publish_loop(),
- )
-
- async def _absorb_loop(self) -> None:
- queue = self._bus.subscribe("geometry.in")
- while True:
- incoming: SSL_GeometryData = await queue.get()
- self._merge_calibs(incoming)
-
- async def _publish_loop(self) -> None:
- while True:
- self._bus.publish("wrapper_packet.out", self._wrapper.SerializeToString())
- await asyncio.sleep(PUBLISH_INTERVAL_S)
-
- def _merge_calibs(self, incoming: SSL_GeometryData) -> None:
- calib = self._wrapper.geometry.calib
- by_id = {c.camera_id: c for c in calib}
- for camera in incoming.calib:
- existing = by_id.get(camera.camera_id)
-
- # Initial calibration received for camera. Store it
- if existing is None:
- calib.append(camera)
- log.info("Added camera %d calibration", camera.camera_id)
- continue
- incoming_bytes = camera.SerializeToString(deterministic=True)
-
- # Don't update if nothing changed
- if existing.SerializeToString(deterministic=True) == incoming_bytes:
- continue
- existing.CopyFrom(camera)
- log.info("Updated camera %d calibration", camera.camera_id)
diff --git a/wrapper_backend/multicast.py b/wrapper_backend/multicast.py
deleted file mode 100644
index 0c306d1..0000000
--- a/wrapper_backend/multicast.py
+++ /dev/null
@@ -1,107 +0,0 @@
-"""Async multicast UDP I/O.
-
-Inbound: parse SSL_WrapperPacket and demux to geometry.in / detection.in.
-Outbound: subscribe to wrapper_packet.out, sendto raw bytes.
-"""
-
-from __future__ import annotations
-
-import asyncio
-import logging
-import socket
-import struct
-
-from google.protobuf.message import DecodeError
-
-from proto.vision.ssl_vision_wrapper_pb2 import SSL_WrapperPacket
-from wrapper_backend.bus import Bus
-
-log = logging.getLogger("wrapper_backend.multicast")
-
-
-class _MulticastToBus(asyncio.DatagramProtocol):
- def __init__(self, bus: Bus) -> None:
- self._bus = bus
-
- def datagram_received(self, data: bytes, addr: tuple[str, int]) -> None:
- packet = SSL_WrapperPacket()
- try:
- packet.ParseFromString(data)
- except DecodeError as exc:
- log.warning("dropping malformed datagram from %s: %s", addr, exc)
- return
-
- if packet.HasField("geometry"):
- self._bus.publish("geometry.in", packet.geometry)
- if packet.HasField("detection"):
- self._bus.publish("detection.in", packet.detection)
-
-
-class _BusToMulticast:
- def __init__(
- self,
- bus: Bus,
- transport: asyncio.DatagramTransport,
- target: tuple[str, int],
- ) -> None:
- self._bus = bus
- self._transport = transport
- self._target = target
-
- async def run(self) -> None:
- queue = self._bus.subscribe("wrapper_packet.out")
- while True:
- payload: bytes = await queue.get()
- self._transport.sendto(payload, self._target)
-
-
-class Multicast:
- def __init__(self, bus: Bus, group: str, port: int) -> None:
- self._bus = bus
- self._group = group
- self._port = port
- self._transport: asyncio.DatagramTransport | None = None
- self._bus_to_multicast: asyncio.Task[None] | None = None
-
- async def start(self) -> None:
- # Join multicast
- sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
- sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32)
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- sock.bind((self._group, self._port))
- sock.setsockopt(
- socket.IPPROTO_IP,
- socket.IP_ADD_MEMBERSHIP,
- struct.pack("4sl", socket.inet_aton(self._group), socket.INADDR_ANY),
- )
-
- loop = asyncio.get_running_loop()
-
- # Start multicast -> bus task
- transport, _protocol = await loop.create_datagram_endpoint(
- lambda: _MulticastToBus(self._bus),
- sock=sock,
- )
- self._transport = transport
-
- # Start bus -> multicast task
- self._bus_to_multicast = asyncio.create_task(
- _BusToMulticast(self._bus, transport, (self._group, self._port)).run(),
- name="multicast-tx",
- )
-
- log.info("multicast bound to %s:%d", self._group, self._port)
-
- async def close(self) -> None:
- # Cancel bus -> multicast task
- if self._bus_to_multicast is not None:
- self._bus_to_multicast.cancel()
- try:
- await self._bus_to_multicast
- except asyncio.CancelledError:
- pass
- self._bus_to_multicast = None
- # Cancel mutlicast -> bus task
- if self._transport is not None:
- self._transport.close()
- self._transport = None
diff --git a/wrapper_backend/snapshot.py b/wrapper_backend/snapshot.py
deleted file mode 100644
index d7bd360..0000000
--- a/wrapper_backend/snapshot.py
+++ /dev/null
@@ -1,42 +0,0 @@
-"""HTTP endpoints for the debug images the C++ vision_processor writes to disk.
-
-Filenames follow ``..{jpg,png}``. ``view`` may contain dots
-(e.g. ``pixels.corner``). Non-image files and anything that doesn't match
-the scheme (legacy ``rtsp:__...`` dumps, ``.calib.json`` sidecars) are
-ignored.
-"""
-
-from __future__ import annotations
-
-import re
-from pathlib import Path
-
-from aiohttp import web
-
-_FILENAME_RE = re.compile(r"^(?P\d+)\.(?P.+)\.(?Pjpg|jpeg|png)$")
-
-
-def register(http_app: web.Application, img_dir: Path) -> None:
- async def list_handler(_: web.Request) -> web.Response:
- entries: list[dict[str, str]] = []
- if img_dir.is_dir():
- for path in img_dir.iterdir():
- if not path.is_file():
- continue
- match = _FILENAME_RE.match(path.name)
- if match is None:
- continue
- entries.append({"cam_id": match["cam_id"], "view": match["view"]})
- entries.sort(key=lambda e: (int(e["cam_id"]), e["view"]))
- return web.json_response(entries)
-
- async def file_handler(request: web.Request) -> web.FileResponse:
- cam_id = request.match_info["cam_id"]
- view = request.match_info["view"]
- matches = list(img_dir.glob(f"{cam_id}.{view}.*"))
- if not matches:
- raise web.HTTPNotFound
- return web.FileResponse(max(matches, key=lambda p: p.stat().st_mtime))
-
- http_app.router.add_get("/snapshots", list_handler)
- http_app.router.add_get("/snapshot/{cam_id}/{view}", file_handler)
diff --git a/wrapper_backend/websocket.py b/wrapper_backend/websocket.py
deleted file mode 100644
index 64e04da..0000000
--- a/wrapper_backend/websocket.py
+++ /dev/null
@@ -1,177 +0,0 @@
-"""WebSocket bridge from the bus to browser clients.
-
-Each connected client owns a size-1 outbound queue (slow clients drop
-intermediate frames, matching the bus's watch-channel semantics).
-
-A "channel" represents one bus topic. The bus is read lazily: when the
-first client joins a channel its bus-reader task starts; when the last
-client leaves it stops. Topics nobody is listening to cost nothing.
-
-Wire protocol (JSON, both directions):
-
- client -> server {"action": "subscribe", "topic": "..."}
- client -> server {"action": "unsubscribe", "topic": "..."}
- server -> client {"topic": "...", "data": {...}}
- server -> client {"error": "...", "topic": "..."}
-"""
-
-from __future__ import annotations
-
-import asyncio
-import json
-import logging
-from typing import Any, Callable
-
-from aiohttp import WSMsgType, web
-from google.protobuf.json_format import MessageToDict
-
-from proto.vision.ssl_vision_wrapper_pb2 import SSL_WrapperPacket
-from wrapper_backend.bus import Bus
-
-log = logging.getLogger("wrapper_backend.websocket")
-
-
-def _encode_wrapper_packet(payload: bytes) -> dict[str, Any]:
- packet = SSL_WrapperPacket()
- packet.ParseFromString(payload)
- return MessageToDict(packet, preserving_proto_field_name=True)
-
-
-# Encoders convert the raw bus payload for a topic into a JSON-serialisable
-# dict. Topics not present here cannot be exposed to clients.
-_TOPIC_ENCODERS: dict[str, Callable[[Any], dict[str, Any]]] = {
- "wrapper_packet.out": _encode_wrapper_packet,
-}
-
-
-class _Client:
- def __init__(self, websocket: web.WebSocketResponse) -> None:
- self._websocket = websocket
- self._outbox: asyncio.Queue[str] = asyncio.Queue(maxsize=1)
- self.topics: set[str] = set()
-
- def post(self, frame: str) -> None:
- try:
- self._outbox.get_nowait()
- except asyncio.QueueEmpty:
- pass
- self._outbox.put_nowait(frame)
-
- async def send_error(self, message: str, topic: str | None = None) -> None:
- payload: dict[str, str] = {"error": message}
- if topic is not None:
- payload["topic"] = topic
- await self._websocket.send_str(json.dumps(payload))
-
- async def deliver_forever(self) -> None:
- while True:
- frame = await self._outbox.get()
- if self._websocket.closed:
- return
- await self._websocket.send_str(frame)
-
-
-class _Channel:
- def __init__(self, task: asyncio.Task[None]) -> None:
- self.clients: set[_Client] = set()
- self.task = task
-
-
-class _TopicBridge:
- def __init__(self, bus: Bus) -> None:
- self._bus = bus
- self._channels: dict[str, _Channel] = {}
-
- async def handle(self, request: web.Request) -> web.WebSocketResponse:
- websocket = web.WebSocketResponse()
- await websocket.prepare(request)
- client = _Client(websocket)
- peer = request.remote
- log.info("client connected: %s", peer)
- delivery = asyncio.create_task(client.deliver_forever(), name="ws-deliver")
- try:
- async for message in websocket:
- if message.type == WSMsgType.TEXT:
- await self._on_client_message(client, message.data)
- finally:
- for topic in list(client.topics):
- self._leave(client, topic)
- delivery.cancel()
- try:
- await delivery
- except asyncio.CancelledError:
- pass
- log.info("client disconnected: %s", peer)
- return websocket
-
- async def shutdown(self, _: web.Application) -> None:
- for topic, channel in list(self._channels.items()):
- channel.task.cancel()
- try:
- await channel.task
- except asyncio.CancelledError:
- pass
- self._channels.pop(topic, None)
-
- async def _on_client_message(self, client: _Client, raw: str) -> None:
- try:
- request = json.loads(raw)
- action = request["action"]
- topic = request["topic"]
- except (json.JSONDecodeError, KeyError, TypeError):
- await client.send_error("malformed request")
- return
-
- if action == "subscribe":
- if topic not in _TOPIC_ENCODERS:
- await client.send_error("unknown topic", topic)
- return
- self._join(client, topic)
- elif action == "unsubscribe":
- self._leave(client, topic)
- else:
- await client.send_error("unknown action", topic)
-
- def _join(self, client: _Client, topic: str) -> None:
- channel = self._channels.get(topic)
- if channel is None:
- task = asyncio.create_task(
- self._forward_topic(topic), name=f"ws-forward-{topic}"
- )
- channel = self._channels[topic] = _Channel(task)
- log.info("opened channel %s", topic)
- channel.clients.add(client)
- client.topics.add(topic)
-
- def _leave(self, client: _Client, topic: str) -> None:
- channel = self._channels.get(topic)
- if channel is None or client not in channel.clients:
- return
- channel.clients.discard(client)
- client.topics.discard(topic)
- if not channel.clients:
- channel.task.cancel()
- del self._channels[topic]
- log.info("closed channel %s", topic)
-
- async def _forward_topic(self, topic: str) -> None:
- encode = _TOPIC_ENCODERS[topic]
- queue = self._bus.subscribe(topic)
- try:
- while True:
- payload = await queue.get()
- try:
- frame = json.dumps({"topic": topic, "data": encode(payload)})
- except Exception:
- log.exception("dropping unencodable payload on %s", topic)
- continue
- for client in self._channels[topic].clients:
- client.post(frame)
- finally:
- self._bus.unsubscribe(topic, queue)
-
-
-def register(http_app: web.Application, bus: Bus) -> None:
- bridge = _TopicBridge(bus)
- http_app.router.add_get("/ws", bridge.handle)
- http_app.on_cleanup.append(bridge.shutdown)
From b080617f8d187d30a141eb8a05b450839ff48e6a Mon Sep 17 00:00:00 2001
From: Will Stuckey
Date: Tue, 22 Sep 2026 18:15:43 -0400
Subject: [PATCH 06/23] add load/save/save-as, clean up vfield
---
.gitignore | 1 +
gui/cmd/ssl-vision-processor-gui/routes.go | 2 +
gui/cmd/ssl-vision-processor-gui/server.go | 89 +++++++++-
.../ssl-vision-processor-gui/server_test.go | 85 ++++++++++
gui/frontend/src/lib/FieldEditor.svelte | 157 +++++++++++-------
gui/frontend/src/lib/fieldPresets.ts | 20 +--
gui/frontend/src/lib/geometry.svelte.ts | 110 +++++++++---
gui/internal/geometry/field_config.go | 121 +++++++++++---
gui/internal/geometry/field_config_test.go | 74 +++++++++
9 files changed, 532 insertions(+), 127 deletions(-)
diff --git a/.gitignore b/.gitignore
index ae7fe04..35e2149 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,7 @@ vision_processor
blob_benchmark
geometry_benchmark
/gui/bin
+/gui/ssl-vision-processor-gui
# Makefile sentinel for the frontend build
/gui/.frontend
diff --git a/gui/cmd/ssl-vision-processor-gui/routes.go b/gui/cmd/ssl-vision-processor-gui/routes.go
index b7472ea..a6d3829 100644
--- a/gui/cmd/ssl-vision-processor-gui/routes.go
+++ b/gui/cmd/ssl-vision-processor-gui/routes.go
@@ -13,6 +13,8 @@ func (s *VisionServer) addRoutes(mux *http.ServeMux) {
mux.Handle("GET /api/geometry", s.handleGetGeometry())
mux.Handle("GET /api/geometry/field", s.handleGetFieldConfig())
mux.Handle("PUT /api/geometry/field", s.handlePutFieldConfig())
+ mux.Handle("POST /api/geometry/field/save-as", s.handlePostSaveAs())
+ mux.Handle("POST /api/geometry/field/load", s.handlePostLoad())
mux.Handle("GET /api/geometry/presets", s.handleGetFieldPresets())
mux.Handle("GET /api/snapshots", snapshot.HandleList(s.imgDir))
mux.Handle("GET /api/snapshot/{camID}/{view}", snapshot.HandleGet(s.imgDir))
diff --git a/gui/cmd/ssl-vision-processor-gui/server.go b/gui/cmd/ssl-vision-processor-gui/server.go
index 2ad9297..804f7a0 100644
--- a/gui/cmd/ssl-vision-processor-gui/server.go
+++ b/gui/cmd/ssl-vision-processor-gui/server.go
@@ -58,8 +58,11 @@ func (s *VisionServer) handleGetGeometry() http.HandlerFunc {
// fieldConfigResponse is the "virtual field" shape: just the editable
// dimensions and optional-line toggles, not the full wrapper packet (calib,
-// source, generated field_lines/arcs) that handleGetGeometry serves.
+// source, generated field_lines/arcs) that handleGetGeometry serves. Path is
+// which file this came from / would be saved to -- omitted on requests where
+// it doesn't apply (PUT), populated on every response.
type fieldConfigResponse struct {
+ Path string `json:"path,omitempty"`
Field geometry.FieldConfig `json:"field"`
OptionalFieldLines geometry.OptionalLinesConfig `json:"optionalFieldLines"`
}
@@ -70,7 +73,8 @@ func (s *VisionServer) handleGetFieldConfig() http.HandlerFunc {
w.Header().Set("Content-Type", "application/json")
- if err := json.NewEncoder(w).Encode(fieldConfigResponse{Field: field, OptionalFieldLines: optional}); err != nil {
+ resp := fieldConfigResponse{Path: s.geometry.Path(), Field: field, OptionalFieldLines: optional}
+ if err := json.NewEncoder(w).Encode(resp); err != nil {
slog.Error("writing field config response", "err", err)
}
}
@@ -107,6 +111,87 @@ func (s *VisionServer) handlePutFieldConfig() http.HandlerFunc {
}
}
+// saveAsRequest is fieldConfigResponse's shape with Path meaning "save here"
+// instead of "loaded from here" -- same fields, different direction, kept as
+// a distinct type so the two aren't confused at the call site.
+type saveAsRequest = fieldConfigResponse
+
+// handlePostSaveAs writes the given field config to Path and switches
+// Geometry to editing that file from now on -- see geometry.Geometry.SaveAs.
+func (s *VisionServer) handlePostSaveAs() http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ var req saveAsRequest
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+ http.Error(w, "malformed request body: "+err.Error(), http.StatusBadRequest)
+
+ return
+ }
+
+ if req.Path == "" {
+ http.Error(w, "path: required", http.StatusBadRequest)
+
+ return
+ }
+
+ if err := s.geometry.SaveAs(req.Path, req.Field, req.OptionalFieldLines); err != nil {
+ var validation *geometry.ValidationError
+ var readOnly *geometry.ReadOnlyError
+
+ switch {
+ case errors.As(err, &validation), errors.As(err, &readOnly):
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ default:
+ slog.Error("saving field config as", "path", req.Path, "err", err)
+ http.Error(w, "internal error", http.StatusInternalServerError)
+ }
+
+ return
+ }
+
+ w.WriteHeader(http.StatusNoContent)
+ }
+}
+
+type loadRequest struct {
+ Path string `json:"path"`
+}
+
+// handlePostLoad replaces the live geometry with whatever's in the given
+// path and returns it, so the frontend doesn't need a second round trip --
+// see geometry.Geometry.LoadFrom. Any failure to load is reported as 400:
+// it's about the path the caller gave, not an internal failure on our part.
+func (s *VisionServer) handlePostLoad() http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ var req loadRequest
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+ http.Error(w, "malformed request body: "+err.Error(), http.StatusBadRequest)
+
+ return
+ }
+
+ if req.Path == "" {
+ http.Error(w, "path: required", http.StatusBadRequest)
+
+ return
+ }
+
+ if err := s.geometry.LoadFrom(req.Path); err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+
+ return
+ }
+
+ field, optional := s.geometry.FieldConfig()
+
+ w.Header().Set("Content-Type", "application/json")
+
+ resp := fieldConfigResponse{Path: s.geometry.Path(), Field: field, OptionalFieldLines: optional}
+ if err := json.NewEncoder(w).Encode(resp); err != nil {
+ slog.Error("writing load response", "err", err)
+ }
+ }
+}
+
// fieldPresets are the rulebook defaults, read live from the same files a
// human would open (geometry-divA.yml, geometry-divB.yml at the repo root) --
// not a copy that could drift from them. See geometry.ReadOnlyFiles: saves
diff --git a/gui/cmd/ssl-vision-processor-gui/server_test.go b/gui/cmd/ssl-vision-processor-gui/server_test.go
index 915e812..c1c58b1 100644
--- a/gui/cmd/ssl-vision-processor-gui/server_test.go
+++ b/gui/cmd/ssl-vision-processor-gui/server_test.go
@@ -162,6 +162,91 @@ func TestGetFieldPresetsDegradesGracefullyWhenFilesAreMissing(t *testing.T) {
}
}
+func TestSaveAsWritesANewFileAndGetReflectsIt(t *testing.T) {
+ srv := testServer(t)
+
+ newPath := filepath.Join(t.TempDir(), "renamed.yml")
+ body := strings.NewReader(`{
+ "path": "` + newPath + `",
+ "field": {"fieldLength": 2160, "fieldWidth": 1680, "goalWidth": 280, "goalDepth": 50, "boundaryWidth": 100, "lineThickness": 10},
+ "optionalFieldLines": {"halfway": true, "penalty": true}
+ }`)
+
+ postReq := httptest.NewRequest(http.MethodPost, "/api/geometry/field/save-as", body)
+ postRec := httptest.NewRecorder()
+ srv.ServeHTTP(postRec, postReq)
+
+ if postRec.Code != http.StatusNoContent {
+ t.Fatalf("save-as status = %d, want %d, body: %s", postRec.Code, http.StatusNoContent, postRec.Body.String())
+ }
+
+ if _, err := os.Stat(newPath); err != nil {
+ t.Fatalf("Stat(newPath): %v", err)
+ }
+
+ getRec := httptest.NewRecorder()
+ srv.ServeHTTP(getRec, httptest.NewRequest(http.MethodGet, "/api/geometry/field", nil))
+
+ if !strings.Contains(getRec.Body.String(), `"fieldLength":2160`) {
+ t.Errorf("GET after save-as returned %q, want it to reflect the new values", getRec.Body.String())
+ }
+
+ if !strings.Contains(getRec.Body.String(), newPath) {
+ t.Errorf("GET after save-as path = %q, want it to contain %q", getRec.Body.String(), newPath)
+ }
+}
+
+func TestSaveAsRejectsAPresetTarget(t *testing.T) {
+ body := strings.NewReader(`{
+ "path": "geometry-divB.yml",
+ "field": {"fieldLength": 2160, "fieldWidth": 1680, "goalWidth": 280, "goalDepth": 50, "boundaryWidth": 100},
+ "optionalFieldLines": {}
+ }`)
+
+ req := httptest.NewRequest(http.MethodPost, "/api/geometry/field/save-as", body)
+ rec := httptest.NewRecorder()
+
+ testServer(t).ServeHTTP(rec, req)
+
+ if rec.Code != http.StatusBadRequest {
+ t.Errorf("status = %d, want %d", rec.Code, http.StatusBadRequest)
+ }
+}
+
+func TestLoadReplacesTheActiveFieldAndReturnsIt(t *testing.T) {
+ otherPath := filepath.Join(t.TempDir(), "other.yml")
+ if err := os.WriteFile(otherPath, []byte(
+ "optional_field_lines:\n goal2goal: false\n halfway: false\n centercircle: false\n penalty: false\n"+
+ "field:\n field_length: 3000\n field_width: 2000\n goal_width: 300\n goal_depth: 60\n boundary_width: 120\n",
+ ), 0o644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+
+ req := httptest.NewRequest(http.MethodPost, "/api/geometry/field/load", strings.NewReader(`{"path":"`+otherPath+`"}`))
+ rec := httptest.NewRecorder()
+
+ testServer(t).ServeHTTP(rec, req)
+
+ if rec.Code != http.StatusOK {
+ t.Fatalf("status = %d, want %d, body: %s", rec.Code, http.StatusOK, rec.Body.String())
+ }
+
+ if !strings.Contains(rec.Body.String(), `"fieldLength":3000`) {
+ t.Errorf("body = %q, want it to reflect the loaded file", rec.Body.String())
+ }
+}
+
+func TestLoadOfAMissingFileReturns400(t *testing.T) {
+ req := httptest.NewRequest(http.MethodPost, "/api/geometry/field/load", strings.NewReader(`{"path":"does-not-exist.yml"}`))
+ rec := httptest.NewRecorder()
+
+ testServer(t).ServeHTTP(rec, req)
+
+ if rec.Code != http.StatusBadRequest {
+ t.Errorf("status = %d, want %d", rec.Code, http.StatusBadRequest)
+ }
+}
+
// A wrong method is a 404 rather than a 405: the "/" catch-all matches every
// method, so ServeMux never reaches its method-not-allowed path. What matters is
// that the "/api/" subtree answers, instead of the request falling through to
diff --git a/gui/frontend/src/lib/FieldEditor.svelte b/gui/frontend/src/lib/FieldEditor.svelte
index 61a7a81..36f9da6 100644
--- a/gui/frontend/src/lib/FieldEditor.svelte
+++ b/gui/frontend/src/lib/FieldEditor.svelte
@@ -5,6 +5,8 @@
loadVirtualField,
loadFieldPresets,
saveVirtualField,
+ saveVirtualFieldAs,
+ loadVirtualFieldFrom,
} from "./geometry.svelte";
import FieldSketch from "./FieldSketch.svelte";
import { scalePreset } from "./fieldPresets";
@@ -36,6 +38,9 @@
// point past the end.
let clampedCameraId = $derived(Math.min(cameraId, cameraAmount - 1));
+ // The FieldSketch highlight: which portion of the field cameraId is
+ // responsible for out of cameraAmount, so the rest of the markings (e.g.
+ // the other goal's penalty box) render dimmed.
let fieldSlice = $derived(
computeFieldSlice(
clampedCameraId,
@@ -65,7 +70,6 @@
let selectedPresetName = $state("Division B");
let scalePercent = $state(100);
- let scaleHardware = $state(false);
function applyPreset(): void {
const preset = virtualField.presets.find(
@@ -73,10 +77,26 @@
);
if (!preset) return;
- virtualField.field = scalePreset(preset, scalePercent, scaleHardware);
+ // Ball/robot size are real hardware, not scaled with a shrunk field --
+ // scalePreset always leaves them at the preset's own value.
+ virtualField.field = scalePreset(preset, scalePercent);
markDirty();
}
+ let saveAsPath = $state("");
+ let loadPath = $state("");
+
+ function handleSaveAs(): void {
+ if (!saveAsPath) return;
+ void saveVirtualFieldAs(saveAsPath);
+ }
+
+ function handleLoad(): void {
+ if (!loadPath) return;
+ if (virtualField.dirty && !confirm("Discard unsaved changes?")) return;
+ void loadVirtualFieldFrom(loadPath);
+ }
+
// Dimension fields, paired with their FieldConfig key and a label. Order
// matches how someone would actually measure a field: outer boundary first,
// then the goal, then the penalty area, then the smaller markings.
@@ -124,11 +144,10 @@
- Virtual field
-
- Measured dimensions, in mm. Saving regenerates the field markings below and
- writes them back to geometry.yml.
-
+
+
Virtual field
+ {virtualField.path || "(unsaved)"}
+
{#if virtualField.error}
Error: {virtualField.error}
@@ -141,6 +160,41 @@
handleSave();
}}
>
+
+ File
+
+
+ {virtualField.saving ? "Saving..." : "Save"}
+
+ {#if virtualField.dirty && !virtualField.saving}
+ *new changes
+ {/if}
+
+
+
+ Save as
+
+
+ Save as
+
+
+
+
+ Load
+
+
+ Load
+
+
+
+
Field layout
@@ -154,7 +208,7 @@
setFieldLayout("full");
}}
/>
- Full field (I measured the whole thing)
+ Full field
- Half field (this camera only sees part of it)
+ Half field
{#if fieldLayout === "half"}
- Half length (goal line to split line)
+ Half length (full: {virtualField.field.fieldLength ?? 0}mm)
-
- Full field length is {virtualField.field.fieldLength ?? 0}mm (2x the
- half above). Field width below is the full, unsplit width -- a
- length-wise split still shows both touchlines.
-
{/if}
- Cameras across the {fieldLayout === "half" ? "full" : ""} field
+ Cameras (camera_amount: {cameraAmount})
{
@@ -200,14 +249,9 @@
{/each}
-
- camera_amount: {cameraAmount}. Not yet pushed anywhere -- set
- geometry.camera_amount: {cameraAmount} in each vision processor's
- own config.yml for now.
-
- Which camera is this? (camera_id)
+ This camera (camera_id)
{
@@ -219,20 +263,12 @@
{/each}
-
- Highlighted below: what this specific camera is responsible for -- the
- rest of the field's markings (e.g. the other goal's penalty box) are
- dimmed, since this camera can't calibrate against them.
-
Start from a rulebook preset
{#if virtualField.presets.length === 0}
-
- No presets available (geometry-divA.yml/geometry-divB.yml not found
- from the host's working directory).
-
+ No presets available.
{/if}
Division
@@ -249,20 +285,9 @@
%
-
-
- Also scale ball/robot size (usually real hardware -- leave off)
-
Fill in dimensions from this preset
-
- Overwrites the dimension fields below (not yet saved). Real SSL
- penalty box, goal, and boundary sizes are fixed rulebook constants,
- not derived from field size or camera count -- this is the actual
- principled way to approximate them for a scaled-down field, rather
- than guessing a ratio by hand.
-
@@ -292,16 +317,6 @@
{/each}
-
-
- {virtualField.saving ? "Saving..." : "Save"}
-
- {#if virtualField.dirty && !virtualField.saving}
- *new changes
- {/if}
@@ -312,10 +327,6 @@
arcs={virtualField.fieldArcs}
slice={fieldSlice}
/>
-
- Markings reflect the last saved dimensions; the highlighted region
- updates live as you change camera count/id above.
-
@@ -325,6 +336,23 @@
max-width: 900px;
}
+ .title-row {
+ display: flex;
+ align-items: baseline;
+ gap: 0.75rem;
+ margin-bottom: 0.5rem;
+ }
+
+ .title-row h2 {
+ margin: 0;
+ }
+
+ .path {
+ font-family: monospace;
+ font-size: 0.8rem;
+ color: #666;
+ }
+
.layout {
display: grid;
grid-template-columns: 1fr 1fr;
@@ -363,16 +391,21 @@
font-weight: normal;
}
- code {
- background: #eee;
- padding: 0.1rem 0.3rem;
- border-radius: 3px;
- }
-
input[type="number"] {
width: 6rem;
}
+ input[type="text"] {
+ width: 10rem;
+ }
+
+ .file-actions {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ margin: 0.4rem 0;
+ }
+
.error {
color: #b00020;
}
diff --git a/gui/frontend/src/lib/fieldPresets.ts b/gui/frontend/src/lib/fieldPresets.ts
index 4fc8e66..57721fd 100644
--- a/gui/frontend/src/lib/fieldPresets.ts
+++ b/gui/frontend/src/lib/fieldPresets.ts
@@ -25,19 +25,12 @@ export const SCALABLE_KEYS: (keyof FieldConfig)[] = [
"lineThickness",
];
-export const HARDWARE_KEYS: (keyof FieldConfig)[] = [
- "ballRadius",
- "maxRobotRadius",
-];
-
// Applies a preset at the given percentage scale (100 = actual rule-book
-// size) to a FieldConfig, returning a new object. scaleHardware controls
-// whether ballRadius/maxRobotRadius are scaled too, or left at the preset's
-// real-hardware value.
+// size) to a FieldConfig, returning a new object. ballRadius/maxRobotRadius
+// are real hardware and always left at the preset's value.
export function scalePreset(
preset: FieldPreset,
scalePercent: number,
- scaleHardware: boolean,
): FieldConfig {
const factor = scalePercent / 100;
const result: FieldConfig = { ...preset.field };
@@ -49,14 +42,5 @@ export function scalePreset(
}
}
- if (scaleHardware) {
- for (const key of HARDWARE_KEYS) {
- const value = preset.field[key];
- if (typeof value === "number") {
- result[key] = Math.round(value * factor * 10) / 10;
- }
- }
- }
-
return result;
}
diff --git a/gui/frontend/src/lib/geometry.svelte.ts b/gui/frontend/src/lib/geometry.svelte.ts
index f3a958f..e39eee1 100644
--- a/gui/frontend/src/lib/geometry.svelte.ts
+++ b/gui/frontend/src/lib/geometry.svelte.ts
@@ -21,6 +21,7 @@ export interface OptionalFieldLines {
}
interface FieldConfigResponse {
+ path?: string;
field: FieldConfig;
optionalFieldLines: OptionalFieldLines;
}
@@ -44,6 +45,7 @@ interface GeometryResponse {
}
export const virtualField = $state<{
+ path: string;
field: FieldConfig;
optionalFieldLines: OptionalFieldLines;
fieldLines: SSL_FieldLineSegmentJson[];
@@ -54,6 +56,7 @@ export const virtualField = $state<{
error: string | null;
dirty: boolean;
}>({
+ path: "",
field: {},
optionalFieldLines: {
goal2Goal: false,
@@ -85,30 +88,38 @@ export async function loadFieldPresets(): Promise {
}
}
+// Refreshes fieldLines/fieldArcs from /api/geometry -- the field-config
+// endpoints don't carry the generated markings themselves, and every one of
+// them (load, save, save-as) leaves the server having just regenerated these
+// from whatever field config is now active.
+async function refreshFieldMarkings(): Promise {
+ const response = await fetch("/api/geometry");
+ if (!response.ok) return;
+
+ const geometry = (await response.json()) as GeometryResponse;
+ virtualField.fieldLines = geometry.geometry?.field?.fieldLines ?? [];
+ virtualField.fieldArcs = geometry.geometry?.field?.fieldArcs ?? [];
+}
+
+function applyFieldConfigResponse(config: FieldConfigResponse): void {
+ virtualField.path = config.path ?? "";
+ virtualField.field = config.field;
+ virtualField.optionalFieldLines = config.optionalFieldLines;
+ virtualField.dirty = false;
+}
+
export async function loadVirtualField(): Promise {
virtualField.loading = true;
virtualField.error = null;
try {
- const [configRes, geometryRes] = await Promise.all([
- fetch("/api/geometry/field"),
- fetch("/api/geometry"),
- ]);
-
- if (!configRes.ok) {
- throw new Error(`GET /api/geometry/field: ${String(configRes.status)}`);
+ const response = await fetch("/api/geometry/field");
+ if (!response.ok) {
+ throw new Error(`GET /api/geometry/field: ${String(response.status)}`);
}
- const config = (await configRes.json()) as FieldConfigResponse;
- virtualField.field = config.field;
- virtualField.optionalFieldLines = config.optionalFieldLines;
- virtualField.dirty = false;
-
- if (geometryRes.ok) {
- const geometry = (await geometryRes.json()) as GeometryResponse;
- virtualField.fieldLines = geometry.geometry?.field?.fieldLines ?? [];
- virtualField.fieldArcs = geometry.geometry?.field?.fieldArcs ?? [];
- }
+ applyFieldConfigResponse((await response.json()) as FieldConfigResponse);
+ await refreshFieldMarkings();
} catch (err) {
virtualField.error = err instanceof Error ? err.message : String(err);
} finally {
@@ -135,18 +146,69 @@ export async function saveVirtualField(): Promise {
}
virtualField.dirty = false;
+ await refreshFieldMarkings();
+ } catch (err) {
+ virtualField.error = err instanceof Error ? err.message : String(err);
+ } finally {
+ virtualField.saving = false;
+ }
+}
+
+// Writes the current field config to a new path and switches to editing that
+// file (see geometry.Geometry.SaveAs) -- subsequent saveVirtualField calls go
+// there, not wherever this session started out.
+export async function saveVirtualFieldAs(path: string): Promise {
+ virtualField.saving = true;
+ virtualField.error = null;
+
+ try {
+ const response = await fetch("/api/geometry/field/save-as", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ path,
+ field: virtualField.field,
+ optionalFieldLines: virtualField.optionalFieldLines,
+ } satisfies FieldConfigResponse),
+ });
- // The saved dimensions are also the source of truth for the sketch, and
- // the server just regenerated fieldLines/fieldArcs from them.
- const geometryRes = await fetch("/api/geometry");
- if (geometryRes.ok) {
- const geometry = (await geometryRes.json()) as GeometryResponse;
- virtualField.fieldLines = geometry.geometry?.field?.fieldLines ?? [];
- virtualField.fieldArcs = geometry.geometry?.field?.fieldArcs ?? [];
+ if (!response.ok) {
+ throw new Error(await response.text());
}
+
+ virtualField.path = path;
+ virtualField.dirty = false;
+ await refreshFieldMarkings();
} catch (err) {
virtualField.error = err instanceof Error ? err.message : String(err);
} finally {
virtualField.saving = false;
}
}
+
+// Discards the current field config and replaces it with whatever's at path
+// (see geometry.Geometry.LoadFrom). Existing calibrations are dropped
+// server-side -- they belonged to the field this used to be.
+export async function loadVirtualFieldFrom(path: string): Promise {
+ virtualField.loading = true;
+ virtualField.error = null;
+
+ try {
+ const response = await fetch("/api/geometry/field/load", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ path }),
+ });
+
+ if (!response.ok) {
+ throw new Error(await response.text());
+ }
+
+ applyFieldConfigResponse((await response.json()) as FieldConfigResponse);
+ await refreshFieldMarkings();
+ } catch (err) {
+ virtualField.error = err instanceof Error ? err.message : String(err);
+ } finally {
+ virtualField.loading = false;
+ }
+}
diff --git a/gui/internal/geometry/field_config.go b/gui/internal/geometry/field_config.go
index 1811032..0e02c96 100644
--- a/gui/internal/geometry/field_config.go
+++ b/gui/internal/geometry/field_config.go
@@ -152,27 +152,12 @@ func LoadPreset(path string) (FieldConfig, OptionalLinesConfig, error) {
return field, opt, nil
}
-// UpdateField replaces the field dimensions and optional-line toggles,
-// regenerates the derived field lines/arcs, and persists the change to the
-// file Geometry was loaded from. Existing calibrations are kept.
-//
-// Persisting rewrites the whole file, so hand-added comments in it do not
-// survive a save made through this path.
-func (g *Geometry) UpdateField(cfg FieldConfig, opt OptionalLinesConfig) error {
- if err := cfg.Validate(); err != nil {
- return err
- }
-
- g.mu.Lock()
- defer g.mu.Unlock()
-
- // Checked before anything below mutates g.wrapper/g.optional: a rejected
- // save must not leave the in-memory (and multicast-broadcast) state
- // holding values that were never actually persisted.
- if ReadOnlyFiles[filepath.Base(g.path)] {
- return &ReadOnlyError{path: g.path}
- }
-
+// applyFieldConfig builds a field message from cfg, regenerates its derived
+// markings, and installs both it and opt onto g. Callers must hold mu and
+// must have already validated cfg and checked ReadOnlyFiles for whichever
+// path they're about to write to -- this never fails, so it's only safe to
+// call once nothing left can reject the operation.
+func (g *Geometry) applyFieldConfig(cfg FieldConfig, opt OptionalLinesConfig) {
field := &vision.SSL_GeometryFieldSize{
FieldLength: proto.Int32(cfg.FieldLength),
FieldWidth: proto.Int32(cfg.FieldWidth),
@@ -202,6 +187,30 @@ func (g *Geometry) UpdateField(cfg FieldConfig, opt OptionalLinesConfig) error {
g.wrapper.Geometry.Field = field
g.optional = optional
+}
+
+// UpdateField replaces the field dimensions and optional-line toggles,
+// regenerates the derived field lines/arcs, and persists the change to the
+// file Geometry was loaded from. Existing calibrations are kept.
+//
+// Persisting rewrites the whole file, so hand-added comments in it do not
+// survive a save made through this path.
+func (g *Geometry) UpdateField(cfg FieldConfig, opt OptionalLinesConfig) error {
+ if err := cfg.Validate(); err != nil {
+ return err
+ }
+
+ g.mu.Lock()
+ defer g.mu.Unlock()
+
+ // Checked before anything below mutates g.wrapper/g.optional: a rejected
+ // save must not leave the in-memory (and multicast-broadcast) state
+ // holding values that were never actually persisted.
+ if ReadOnlyFiles[filepath.Base(g.path)] {
+ return &ReadOnlyError{path: g.path}
+ }
+
+ g.applyFieldConfig(cfg, opt)
if err := g.reencode(); err != nil {
return fmt.Errorf("encode updated geometry: %w", err)
@@ -214,6 +223,76 @@ func (g *Geometry) UpdateField(cfg FieldConfig, opt OptionalLinesConfig) error {
return nil
}
+// SaveAs is UpdateField plus switching which file Geometry edits: it writes
+// cfg/opt to path rather than the current file, and -- once that write
+// succeeds -- every subsequent Save (UpdateField) goes to path too. Whatever
+// non-field content the current file carried (e.g. "models") comes along
+// unchanged; existing calibrations are kept, same as UpdateField.
+func (g *Geometry) SaveAs(path string, cfg FieldConfig, opt OptionalLinesConfig) error {
+ if err := cfg.Validate(); err != nil {
+ return err
+ }
+
+ g.mu.Lock()
+ defer g.mu.Unlock()
+
+ if ReadOnlyFiles[filepath.Base(path)] {
+ return &ReadOnlyError{path: path}
+ }
+
+ g.applyFieldConfig(cfg, opt)
+
+ if err := g.reencode(); err != nil {
+ return fmt.Errorf("encode updated geometry: %w", err)
+ }
+
+ // g.path only changes once we're past validation and encoding, so a
+ // rejected SaveAs never leaves Geometry claiming to be a file nothing was
+ // actually written to.
+ previousPath := g.path
+ g.path = path
+
+ if err := g.saveYAML(cfg, opt); err != nil {
+ g.path = previousPath
+
+ return fmt.Errorf("save %s: %w", path, err)
+ }
+
+ return nil
+}
+
+// LoadFrom replaces this Geometry's entire state -- field config, optional
+// lines, and whatever else the file carries (e.g. "models") -- with what's in
+// path, and starts editing that file: subsequent Save calls go there.
+//
+// Existing calibrations are discarded, not carried over: they were computed
+// against the field this Geometry used to hold, and are meaningless against
+// whatever was just loaded (which may not even be the same size).
+func (g *Geometry) LoadFrom(path string) error {
+ wrapper, optional, extra, err := Load(path)
+ if err != nil {
+ return err
+ }
+
+ g.mu.Lock()
+ defer g.mu.Unlock()
+
+ g.wrapper = wrapper
+ g.path = path
+ g.optional = optional
+ g.extra = extra
+
+ return g.reencode()
+}
+
+// Path reports the file Geometry currently reads from and saves to.
+func (g *Geometry) Path() string {
+ g.mu.Lock()
+ defer g.mu.Unlock()
+
+ return g.path
+}
+
// saveYAML writes the current field config and optional-line toggles back to
// g.path, merged with whatever other top-level keys (e.g. "models") were
// present when it was loaded. Callers must hold mu.
diff --git a/gui/internal/geometry/field_config_test.go b/gui/internal/geometry/field_config_test.go
index 2eea80a..b8404cc 100644
--- a/gui/internal/geometry/field_config_test.go
+++ b/gui/internal/geometry/field_config_test.go
@@ -188,3 +188,77 @@ func TestLoadPresetReadsWithoutAGeometryInstance(t *testing.T) {
t.Error("halfway = false, want true (per the fixture)")
}
}
+
+func TestSaveAsWritesToTheNewPathAndSwitchesToIt(t *testing.T) {
+ g := testGeometry(t)
+
+ newPath := filepath.Join(t.TempDir(), "new-name.yml")
+ cfg := testConfig()
+
+ if err := g.SaveAs(newPath, cfg, testOptional()); err != nil {
+ t.Fatalf("SaveAs: %v", err)
+ }
+
+ if g.Path() != newPath {
+ t.Errorf("Path() = %q, want %q", g.Path(), newPath)
+ }
+
+ if _, err := os.Stat(newPath); err != nil {
+ t.Fatalf("Stat(newPath): %v", err)
+ }
+
+ gotCfg, _ := g.FieldConfig()
+ if gotCfg != cfg {
+ t.Errorf("FieldConfig() = %+v, want %+v", gotCfg, cfg)
+ }
+
+ // A plain Save afterward must go to the new path, not the original one.
+ if err := g.UpdateField(cfg, testOptional()); err != nil {
+ t.Fatalf("UpdateField after SaveAs: %v", err)
+ }
+}
+
+func TestSaveAsRefusesAPresetTarget(t *testing.T) {
+ g := testGeometry(t)
+
+ before := g.Path()
+
+ var readOnly *ReadOnlyError
+ if err := g.SaveAs("geometry-divB.yml", testConfig(), testOptional()); !errors.As(err, &readOnly) {
+ t.Fatalf("SaveAs err = %v, want a *ReadOnlyError", err)
+ }
+
+ if g.Path() != before {
+ t.Errorf("Path() = %q, want unchanged %q", g.Path(), before)
+ }
+}
+
+func TestLoadFromReplacesStateAndDiscardsCalibrations(t *testing.T) {
+ g := testGeometry(t)
+ g.Absorb(&vision.SSL_GeometryData{Calib: []*vision.SSL_GeometryCameraCalibration{calib(0, 400)}})
+
+ otherPath := filepath.Join(t.TempDir(), "other.yml")
+ if err := os.WriteFile(otherPath, []byte(
+ "optional_field_lines:\n goal2goal: false\n halfway: false\n centercircle: false\n penalty: false\n"+
+ "field:\n field_length: 3000\n field_width: 2000\n goal_width: 300\n goal_depth: 60\n boundary_width: 120\n",
+ ), 0o644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+
+ if err := g.LoadFrom(otherPath); err != nil {
+ t.Fatalf("LoadFrom: %v", err)
+ }
+
+ if g.Path() != otherPath {
+ t.Errorf("Path() = %q, want %q", g.Path(), otherPath)
+ }
+
+ cfg, _ := g.FieldConfig()
+ if cfg.FieldLength != 3000 {
+ t.Errorf("field_length = %d, want 3000 (from the newly loaded file)", cfg.FieldLength)
+ }
+
+ if got := g.Snapshot().GetGeometry().GetCalib(); len(got) != 0 {
+ t.Errorf("calib = %v, want discarded after loading a different file", got)
+ }
+}
From 9e4070580689ec49278d2060074a1f725d0565b1 Mon Sep 17 00:00:00 2001
From: Will Stuckey
Date: Thu, 24 Sep 2026 20:52:39 -0400
Subject: [PATCH 07/23] make corner picker persistent
---
config-testpatch.yml | 159 ++++++++++
gui/CLAUDE.md | 11 +
gui/cmd/ssl-vision-processor-gui/main.go | 53 +++-
gui/cmd/ssl-vision-processor-gui/main_test.go | 30 ++
gui/cmd/ssl-vision-processor-gui/routes.go | 2 +
gui/cmd/ssl-vision-processor-gui/server.go | 82 +++++-
.../ssl-vision-processor-gui/server_test.go | 148 +++++++++-
.../testdata/config.yml | 159 ++++++++++
gui/config.yml | 157 ++++++++++
gui/frontend/src/App.svelte | 49 ++--
gui/frontend/src/lib/CornerPicker.svelte | 116 +++++++-
gui/frontend/src/lib/layout/Shell.svelte | 2 +-
gui/internal/geometry/instance_config.go | 271 ++++++++++++++++++
gui/internal/geometry/instance_config_test.go | 252 ++++++++++++++++
gui/internal/geometry/testdata/config.yml | 159 ++++++++++
15 files changed, 1614 insertions(+), 36 deletions(-)
create mode 100644 config-testpatch.yml
create mode 100644 gui/cmd/ssl-vision-processor-gui/testdata/config.yml
create mode 100644 gui/config.yml
create mode 100644 gui/internal/geometry/instance_config.go
create mode 100644 gui/internal/geometry/instance_config_test.go
create mode 100644 gui/internal/geometry/testdata/config.yml
diff --git a/config-testpatch.yml b/config-testpatch.yml
new file mode 100644
index 0000000..25a7d77
--- /dev/null
+++ b/config-testpatch.yml
@@ -0,0 +1,159 @@
+# VisionProcessor configuration
+
+# Vision camera ID handled by this VisionProcessor instance.
+# On multi camera fields the IDs have to be ordered according to camera_ids.png.
+#cam_id: 0
+
+# Team bot heights yml file (heights in mm)
+#bot_heights_file: robot-heights.yml
+
+camera:
+ # Camera driver type. Availability depending on libraries installed.
+ # Existing: SPINNAKER (FLIR cameras), MVIMPACT (Bluefox3 cameras), OPENCV(files, v4l2 cameras)
+ #driver: SPINNAKER
+
+ # Spinnaker, mvIMPACT or OpenCV(v4l2) camera id
+ #id: 0
+ # OpenCV camera device, image or video file path (if unset id is used instead)
+ #path: /dev/video0
+
+ # Camera resolution as reported by the camera. VisionProcessor might use half (true color) resolution internally with SPINNAKER and MVIMPACT.
+ # 0 = highest resolution supported by the camera
+ #width: 0
+ #height: 0
+
+ # Camera exposure time in ms to adjust brightness. Higher values lead to more motion blur. Lower values lead to a darker image.
+ # Camera frame rate will drop if set equal to or higher than the frame time (1 / fps_cam).
+ # 0.0 = automatic exposure
+ #exposure: 0.0
+ # Camera gain to adjust brightness. Higher values lead to more noise. Lower values lead to a darker image.
+ # Frequently changing bot identities or team colors indicate an image that is too bright (all colors becoming nearly white).
+ # 0.0 = automatic gain
+ #gain: 0.0
+ # Camera gamma as nonlinear brightness adjustment. Only supported on SPINNAKER and OPENCV.
+ # Low values reduce differences between bright and dark illuminated areas. High values increase the color contrast.
+ # 1.0 = no gamma
+ #gamma: 1.0
+
+ # Camera white balance. OUTDOOR or INDOOR for auto white balance with green or gray carpet respectively.
+ # (distinction between OUTDOOR and INDOOR currently only implemented for SPINNAKER backend)
+ #white_balance: OUTDOOR
+ # If you want to set manual white balance values use this format:
+ #white_balance:
+ # red: 1.0
+ # blue: 1.0
+
+geometry:
+ line_corners:
+ - [1134, 948]
+ - [1509, 729]
+ - [1266, 69]
+ - [798, 300]
+ # Total camera amount over the field
+ #camera_amount: 1
+ # Camera height above field in mm
+ # 0.0 = automated camera height calibration, this does not work if the camera looks perpendicular to the field
+ #camera_height: 0.0
+
+ # Field line crossings at the edges of the camera extent in pixels from the top left image corner.
+ # The first coordinate must be the edge with the smallest x and y field coordinate.
+ #line_corners:
+ #- [0 , 1000]
+ #- [0 , 0]
+ #- [1000, 0]
+ #- [1000, 1000]
+
+ # Enable field line pixel refinement.
+ # Disable in cluttered environments when the geometry calibration has failed multiple times in a row.
+ #refinement: true
+
+ # Minimum brightness difference to surrounding pixels for the classification as field line pixel (0 - 255)
+ #field_line_threshold: 5
+ # Minimum length of line segments to ensure angular stability in pixels
+ #min_line_segment_length: 10.0
+ # Maximum perpendicular offset of line segments for merging in pixels
+ #max_line_segment_offset: 10.0
+ # Maximum relative angle of line segments for merging in °
+ #max_line_segment_angle: 3.0
+
+ # Which corner-picker marker (1-4, its on-screen number) was chosen as the goal-side corner. Not read by vision_processor -- record only.
+ goal_side_marker: 1
+thresholds:
+ # Minimum mean cosine similarity (not normalized) of the blob border gradient (0 - 195075.0)
+ # High value lead to undetected blobs. Low values lead to an increase in false positive blob detections.
+ #circularity: 15.0
+ # Minimum circularity/(3*stddev) ball blob score
+ #score: 5.0
+
+ # Maximum amount of blobs processed per frame. Should not be necessary to adjust this value.
+ #blobs: 2000
+
+ # Minimum confidence (0.0 - 1.0)
+ #min_confidence: 0.2
+
+ # Min ball camera edge distance in mm
+ #min_cam_edge_distance: 170.0
+
+ # Maximum allowed clipping of two objects in mm
+ #clipping_tolerance: 10.0
+
+ # Added tolerance to geometry related operations in mm.
+ # Affects field border cutoff area and field line blob classification.
+ #geometry_tolerance: 10.0
+
+color:
+ # Strength of the reference color during color updates (0.0 - 0.5-history_force/2)
+ #reference_force: 0.1
+ # Strength of the previous color during color updates (0.0 - 1.0-reference_force)
+ #history_force: 0.7
+
+ # Reference colors used for ball determination
+ #orange: [192, 128, 64]
+ #field: [128, 128, 128]
+ # Reference colors used for center blob determination
+ #yellow: [255, 128, 0]
+ #blue: [0, 128, 255]
+ # Reference colors used for side blob determination
+ #green: [0, 255, 128]
+ #pink: [255, 0, 128]
+
+tracking:
+ # Min tracking radius in mm
+ #min_tracking_radius: 20.0
+
+ # Max tracked bot acceleration in m/s^2
+ #max_bot_acceleration: 6.5
+
+network:
+ # Game controller multicast ip address
+ #gc_ip: "224.5.23.1"
+ # Game controller multicast port
+ #gc_port: 10003
+
+ # Vision multicast IP address
+ #vision_ip: "224.5.23.2"
+ # Vision multicast port
+ #vision_port: 10006
+
+stream:
+ # If false no network live stream will be encoded and sent
+ #active: true
+ # Only stream raw camera footage. Useful for recordings.
+ #raw_feed: false
+
+ # Camera stream ip prefix
+ #ip_base_prefix: 224.5.23.
+ # Camera stream ip end base (cam_id is added to maintain separation)
+ #ip_base_end: 100
+ # Camera stream port
+ #port: 10100
+
+debug:
+ # Ground truth file. Only used by blob and geometry benchmark.
+ #ground_truth: gt.yml
+ # Wait for geometry prior to processing frames
+ #wait_for_geometry: false
+ # Save additional debug images in img/.
+ #debug_images: false
+ # Periodically overwrite img/.sample..png while calibration isn't accepted yet, every N milliseconds. 0 disables.
+ #debug_stream_interval_ms: 0
diff --git a/gui/CLAUDE.md b/gui/CLAUDE.md
index a39eff6..4ccc033 100644
--- a/gui/CLAUDE.md
+++ b/gui/CLAUDE.md
@@ -103,6 +103,17 @@ filesystem.** This is unchanged from the Python `snapshot.py` it replaces and
is a known limitation, not an oversight -- it does not work once vision
processors run on other hosts. See "Not yet built."
+**`internal/geometry.WriteLineCorners` edits vision_processor's per-instance
+`config.yml` as text, not as decoded/re-encoded YAML.** That file ships full
+of comments and commented-out example values meant to be hand-read; a
+decode/re-encode round trip through `gopkg.in/yaml.v3` (confirmed while
+building this) drops comments elsewhere in the document and drifts
+indentation. A line-based splice around the `line_corners:` key touches
+nothing else. This is a stand-in for the not-yet-built `internal/config`
+(single, same-host instance, matching `-imgDir`'s assumption) -- see "Not yet
+built" -- kept in `internal/geometry` for now since the corner picker needed
+it working immediately; move it if/when `internal/config` exists.
+
**buf reads the proto submodule directly**: `inputs: [{directory:
../proto/proto}]` in `buf.gen.yaml`. No vendored copy to drift. Generated
output is committed (Nix builds are sandboxed/offline, so `make proto` cannot
diff --git a/gui/cmd/ssl-vision-processor-gui/main.go b/gui/cmd/ssl-vision-processor-gui/main.go
index 037c959..fd2ce5e 100644
--- a/gui/cmd/ssl-vision-processor-gui/main.go
+++ b/gui/cmd/ssl-vision-processor-gui/main.go
@@ -6,6 +6,7 @@ import (
"flag"
"fmt"
"log/slog"
+ "net"
"net/http"
"os"
"os/signal"
@@ -32,6 +33,13 @@ var skipInterfaces = flag.String("skipInterfaces", "", "Comma separated list of
var geometryFile = flag.String("geometryFile", "geometry.yml", "Field geometry config file, default: geometry.yml")
var geometryPreset = flag.String("geometryPreset", "geometry-divB.yml", "Preset to seed -geometryFile from if it doesn't exist yet, default: geometry-divB.yml")
var imgDir = flag.String("imgDir", "img", "Directory the vision processor writes debug snapshot images to, default: img")
+
+// The vision_processor instance's own config file -- distinct from
+// -geometryFile (the shared field template). Matches vision_processor's own
+// default (argv[1] falling back to "config.yml", see src/main.cpp). Assumes
+// a single, same-host instance, same as -imgDir; see gui/CLAUDE.md's
+// "internal/discovery"/"internal/config" notes for the multi-instance plan.
+var configFile = flag.String("configFile", "config.yml", "vision_processor instance config file to write calibration values into, default: config.yml")
var logLevelFlag = flag.String("logLevel", "Info", "Log Level: Debug, Info, Warn, Error. Default: Info")
var logFile = flag.String("logFile", "logs/vision-processor-gui.log", "Rotating log file to write alongside stderr, empty to disable. Default: logs/vision-processor-gui.log")
@@ -98,7 +106,7 @@ func run() int {
srv := &http.Server{
Addr: *address,
- Handler: NewVisionServer(geom, wsHub, *imgDir),
+ Handler: NewVisionServer(geom, wsHub, *imgDir, *configFile),
ReadHeaderTimeout: 10 * time.Second,
}
@@ -113,7 +121,7 @@ func run() int {
}
}()
- slog.Info("UI is available", "url", formattedAddress())
+ slog.Info("UI is available", "url", formattedAddress(*address))
<-ctx.Done()
@@ -205,10 +213,43 @@ func splitInterfaces(flagValue string) []string {
return strings.Split(flagValue, ",")
}
-func formattedAddress() string {
- if strings.HasPrefix(*address, ":") {
- return "http://localhost" + *address
+// formattedAddress turns -address into a URL a person can actually open. A
+// bind-all host (empty, "0.0.0.0", "::") isn't itself reachable -- printing
+// the LAN-facing IP instead of "localhost" is what makes this useful to
+// someone else on the venue network, not just the machine running it.
+// localhost is only the fallback if that IP can't be determined.
+func formattedAddress(addr string) string {
+ host, port, err := net.SplitHostPort(addr)
+ if err != nil {
+ return "http://" + addr
+ }
+
+ if host != "" && host != "0.0.0.0" && host != "::" {
+ return "http://" + net.JoinHostPort(host, port)
+ }
+
+ if ip, err := outboundIP(); err == nil {
+ return "http://" + net.JoinHostPort(ip, port)
+ }
+
+ return "http://" + net.JoinHostPort("localhost", port)
+}
+
+// outboundIP reports this host's IP as seen by external routing. Dialing UDP
+// doesn't send a packet, just consults the routing table for which local
+// interface/address would be used -- so this works without real
+// connectivity, only a route to the internet.
+func outboundIP() (string, error) {
+ conn, err := net.Dial("udp", "8.8.8.8:80")
+ if err != nil {
+ return "", err
+ }
+ defer conn.Close()
+
+ addr, ok := conn.LocalAddr().(*net.UDPAddr)
+ if !ok {
+ return "", fmt.Errorf("unexpected local address type %T", conn.LocalAddr())
}
- return "http://" + *address
+ return addr.IP.String(), nil
}
diff --git a/gui/cmd/ssl-vision-processor-gui/main_test.go b/gui/cmd/ssl-vision-processor-gui/main_test.go
index 9083bb1..30062c0 100644
--- a/gui/cmd/ssl-vision-processor-gui/main_test.go
+++ b/gui/cmd/ssl-vision-processor-gui/main_test.go
@@ -3,6 +3,7 @@ package main
import (
"os"
"path/filepath"
+ "strings"
"testing"
)
@@ -50,3 +51,32 @@ func TestBootstrapGeometryFileLeavesExistingFileAlone(t *testing.T) {
t.Errorf("existing file was overwritten: %q", got)
}
}
+
+func TestFormattedAddressUsesAnExplicitHostAsIs(t *testing.T) {
+ got := formattedAddress("192.168.1.50:8085")
+ want := "http://192.168.1.50:8085"
+
+ if got != want {
+ t.Errorf("formattedAddress = %q, want %q", got, want)
+ }
+}
+
+// A bind-all host has no single deterministic answer in a test environment
+// (LAN IP if one's reachable, localhost otherwise) -- what's worth asserting
+// is that it always resolves to a well-formed URL on the right port.
+func TestFormattedAddressResolvesABindAllHostToAURL(t *testing.T) {
+ got := formattedAddress(":8085")
+
+ if !strings.HasPrefix(got, "http://") || !strings.HasSuffix(got, ":8085") {
+ t.Errorf("formattedAddress(%q) = %q, want an http://:8085 URL", ":8085", got)
+ }
+}
+
+func TestFormattedAddressFallsBackOnUnparseableInput(t *testing.T) {
+ got := formattedAddress("not-a-host-port")
+ want := "http://not-a-host-port"
+
+ if got != want {
+ t.Errorf("formattedAddress = %q, want %q", got, want)
+ }
+}
diff --git a/gui/cmd/ssl-vision-processor-gui/routes.go b/gui/cmd/ssl-vision-processor-gui/routes.go
index a6d3829..3cdd5b4 100644
--- a/gui/cmd/ssl-vision-processor-gui/routes.go
+++ b/gui/cmd/ssl-vision-processor-gui/routes.go
@@ -16,6 +16,8 @@ func (s *VisionServer) addRoutes(mux *http.ServeMux) {
mux.Handle("POST /api/geometry/field/save-as", s.handlePostSaveAs())
mux.Handle("POST /api/geometry/field/load", s.handlePostLoad())
mux.Handle("GET /api/geometry/presets", s.handleGetFieldPresets())
+ mux.Handle("GET /api/config/line-corners", s.handleGetLineCorners())
+ mux.Handle("PUT /api/config/line-corners", s.handlePutLineCorners())
mux.Handle("GET /api/snapshots", snapshot.HandleList(s.imgDir))
mux.Handle("GET /api/snapshot/{camID}/{view}", snapshot.HandleGet(s.imgDir))
mux.Handle("/api/", http.NotFoundHandler())
diff --git a/gui/cmd/ssl-vision-processor-gui/server.go b/gui/cmd/ssl-vision-processor-gui/server.go
index 804f7a0..48aa0bd 100644
--- a/gui/cmd/ssl-vision-processor-gui/server.go
+++ b/gui/cmd/ssl-vision-processor-gui/server.go
@@ -12,13 +12,14 @@ import (
)
type VisionServer struct {
- geometry *geometry.Geometry
- hub *hub.Hub
- imgDir string
+ geometry *geometry.Geometry
+ hub *hub.Hub
+ imgDir string
+ configFile string
}
-func NewVisionServer(geom *geometry.Geometry, wsHub *hub.Hub, imgDir string) http.Handler {
- s := &VisionServer{geometry: geom, hub: wsHub, imgDir: imgDir}
+func NewVisionServer(geom *geometry.Geometry, wsHub *hub.Hub, imgDir, configFile string) http.Handler {
+ s := &VisionServer{geometry: geom, hub: wsHub, imgDir: imgDir, configFile: configFile}
mux := http.NewServeMux()
s.addRoutes(mux)
@@ -192,6 +193,77 @@ func (s *VisionServer) handlePostLoad() http.HandlerFunc {
}
}
+type lineCornersRequest struct {
+ Corners []geometry.Corner `json:"corners"`
+ // GoalSideMarker is 1-based, matching the corner picker's on-screen
+ // number for whichever marker was chosen as the goal-side corner.
+ GoalSideMarker int `json:"goalSideMarker"`
+}
+
+// handleGetLineCorners reads back whatever was last written to the
+// instance's config.yml (see geometry.ReadLineCorners), so the corner picker
+// can restore its markers instead of always starting from the default inset
+// rectangle. A file with nothing saved yet -- or that can't be read at all --
+// degrades to an empty response rather than an error: not being calibrated
+// yet is the normal state, not a failure.
+func (s *VisionServer) handleGetLineCorners() http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ corners, marker, err := geometry.ReadLineCorners(s.configFile)
+ if err != nil {
+ slog.Warn("no existing line corners to load", "path", s.configFile, "err", err)
+
+ corners, marker = nil, 0
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+
+ resp := lineCornersRequest{Corners: corners, GoalSideMarker: marker}
+ if err := json.NewEncoder(w).Encode(resp); err != nil {
+ slog.Error("writing line corners response", "err", err)
+ }
+ }
+}
+
+// handlePutLineCorners writes the corner picker's calibration hint into the
+// instance's own config.yml (geometry.line_corners) -- see
+// geometry.WriteLineCorners. This isn't part of the shared field template
+// (Geometry/geometry.yml); it's a stand-in for the not-yet-built
+// internal/config (see gui/CLAUDE.md's "Not yet built"), kept in
+// internal/geometry for now since it's already of immediate use.
+func (s *VisionServer) handlePutLineCorners() http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ var req lineCornersRequest
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+ http.Error(w, "malformed request body: "+err.Error(), http.StatusBadRequest)
+
+ return
+ }
+
+ if len(req.Corners) != 4 {
+ http.Error(w, "corners: exactly 4 required", http.StatusBadRequest)
+
+ return
+ }
+
+ if req.GoalSideMarker < 1 || req.GoalSideMarker > len(req.Corners) {
+ http.Error(w, "goalSideMarker: must identify one of the given corners", http.StatusBadRequest)
+
+ return
+ }
+
+ // s.configFile is server config, not part of the request -- a
+ // failure here is our problem, not the caller's, so 500.
+ if err := geometry.WriteLineCorners(s.configFile, req.Corners, req.GoalSideMarker); err != nil {
+ slog.Error("writing line corners", "path", s.configFile, "err", err)
+ http.Error(w, "internal error", http.StatusInternalServerError)
+
+ return
+ }
+
+ w.WriteHeader(http.StatusNoContent)
+ }
+}
+
// fieldPresets are the rulebook defaults, read live from the same files a
// human would open (geometry-divA.yml, geometry-divB.yml at the repo root) --
// not a copy that could drift from them. See geometry.ReadOnlyFiles: saves
diff --git a/gui/cmd/ssl-vision-processor-gui/server_test.go b/gui/cmd/ssl-vision-processor-gui/server_test.go
index c1c58b1..8d47f62 100644
--- a/gui/cmd/ssl-vision-processor-gui/server_test.go
+++ b/gui/cmd/ssl-vision-processor-gui/server_test.go
@@ -34,7 +34,41 @@ func testServer(t *testing.T) http.Handler {
t.Fatalf("geometry.New: %v", err)
}
- return NewVisionServer(geom, hub.New(), t.TempDir())
+ return NewVisionServer(geom, hub.New(), t.TempDir(), filepath.Join(t.TempDir(), "config.yml"))
+}
+
+// testServerWithConfig is testServer plus a real, writable copy of
+// testdata/config.yml -- for the line-corners tests, which need to read back
+// what was written.
+func testServerWithConfig(t *testing.T) (http.Handler, string) {
+ t.Helper()
+
+ geomSrc, err := os.ReadFile("testdata/geometry.yml")
+ if err != nil {
+ t.Fatalf("ReadFile geometry fixture: %v", err)
+ }
+
+ geomPath := filepath.Join(t.TempDir(), "geometry.yml")
+ if err := os.WriteFile(geomPath, geomSrc, 0o644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+
+ geom, err := geometry.New(geomPath)
+ if err != nil {
+ t.Fatalf("geometry.New: %v", err)
+ }
+
+ configSrc, err := os.ReadFile("testdata/config.yml")
+ if err != nil {
+ t.Fatalf("ReadFile config fixture: %v", err)
+ }
+
+ configPath := filepath.Join(t.TempDir(), "config.yml")
+ if err := os.WriteFile(configPath, configSrc, 0o644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+
+ return NewVisionServer(geom, hub.New(), t.TempDir(), configPath), configPath
}
func TestHealthReturnsOK(t *testing.T) {
@@ -247,6 +281,118 @@ func TestLoadOfAMissingFileReturns400(t *testing.T) {
}
}
+func TestGetLineCornersReturnsWhatWasWritten(t *testing.T) {
+ srv, _ := testServerWithConfig(t)
+
+ putBody := strings.NewReader(`{"corners": [{"x":1,"y":2},{"x":3,"y":4},{"x":5,"y":6},{"x":7,"y":8}], "goalSideMarker": 2}`)
+ putReq := httptest.NewRequest(http.MethodPut, "/api/config/line-corners", putBody)
+ putRec := httptest.NewRecorder()
+ srv.ServeHTTP(putRec, putReq)
+
+ if putRec.Code != http.StatusNoContent {
+ t.Fatalf("PUT status = %d, want %d, body: %s", putRec.Code, http.StatusNoContent, putRec.Body.String())
+ }
+
+ getReq := httptest.NewRequest(http.MethodGet, "/api/config/line-corners", nil)
+ getRec := httptest.NewRecorder()
+ srv.ServeHTTP(getRec, getReq)
+
+ if getRec.Code != http.StatusOK {
+ t.Fatalf("GET status = %d, want %d, body: %s", getRec.Code, http.StatusOK, getRec.Body.String())
+ }
+
+ body := getRec.Body.String()
+ if !strings.Contains(body, `"x":1`) || !strings.Contains(body, `"goalSideMarker":2`) {
+ t.Errorf("GET body = %q, want it to reflect the PUT", body)
+ }
+}
+
+func TestGetLineCornersDegradesGracefullyWithNothingSavedYet(t *testing.T) {
+ // testServer's configFile path doesn't exist at all.
+ srv := testServer(t)
+
+ req := httptest.NewRequest(http.MethodGet, "/api/config/line-corners", nil)
+ rec := httptest.NewRecorder()
+
+ srv.ServeHTTP(rec, req)
+
+ if rec.Code != http.StatusOK {
+ t.Fatalf("status = %d, want %d, body: %s", rec.Code, http.StatusOK, rec.Body.String())
+ }
+
+ if !strings.Contains(rec.Body.String(), `"goalSideMarker":0`) {
+ t.Errorf("body = %q, want a zero-value response", rec.Body.String())
+ }
+}
+
+func TestPutLineCornersWritesToConfigFile(t *testing.T) {
+ srv, configPath := testServerWithConfig(t)
+
+ body := strings.NewReader(`{"corners": [{"x":1,"y":2},{"x":3,"y":4},{"x":5,"y":6},{"x":7,"y":8}], "goalSideMarker": 3}`)
+ req := httptest.NewRequest(http.MethodPut, "/api/config/line-corners", body)
+ rec := httptest.NewRecorder()
+
+ srv.ServeHTTP(rec, req)
+
+ if rec.Code != http.StatusNoContent {
+ t.Fatalf("status = %d, want %d, body: %s", rec.Code, http.StatusNoContent, rec.Body.String())
+ }
+
+ got, err := os.ReadFile(configPath)
+ if err != nil {
+ t.Fatalf("ReadFile: %v", err)
+ }
+
+ if !strings.Contains(string(got), "- [1, 2]") {
+ t.Errorf("config.yml was not updated: %s", got)
+ }
+
+ if !strings.Contains(string(got), "goal_side_marker: 3") {
+ t.Errorf("goal_side_marker was not recorded: %s", got)
+ }
+}
+
+func TestPutLineCornersRejectsAnOutOfRangeGoalSideMarker(t *testing.T) {
+ srv, _ := testServerWithConfig(t)
+
+ body := strings.NewReader(`{"corners": [{"x":1,"y":2},{"x":3,"y":4},{"x":5,"y":6},{"x":7,"y":8}], "goalSideMarker": 5}`)
+ req := httptest.NewRequest(http.MethodPut, "/api/config/line-corners", body)
+ rec := httptest.NewRecorder()
+
+ srv.ServeHTTP(rec, req)
+
+ if rec.Code != http.StatusBadRequest {
+ t.Errorf("status = %d, want %d", rec.Code, http.StatusBadRequest)
+ }
+}
+
+func TestPutLineCornersRejectsTheWrongCornerCount(t *testing.T) {
+ srv, _ := testServerWithConfig(t)
+
+ body := strings.NewReader(`{"corners": [{"x":1,"y":2}]}`)
+ req := httptest.NewRequest(http.MethodPut, "/api/config/line-corners", body)
+ rec := httptest.NewRecorder()
+
+ srv.ServeHTTP(rec, req)
+
+ if rec.Code != http.StatusBadRequest {
+ t.Errorf("status = %d, want %d", rec.Code, http.StatusBadRequest)
+ }
+}
+
+func TestPutLineCornersRejectsMalformedJSON(t *testing.T) {
+ srv, _ := testServerWithConfig(t)
+
+ req := httptest.NewRequest(http.MethodPut, "/api/config/line-corners", strings.NewReader(`not json`))
+ rec := httptest.NewRecorder()
+
+ srv.ServeHTTP(rec, req)
+
+ if rec.Code != http.StatusBadRequest {
+ t.Errorf("status = %d, want %d", rec.Code, http.StatusBadRequest)
+ }
+}
+
// A wrong method is a 404 rather than a 405: the "/" catch-all matches every
// method, so ServeMux never reaches its method-not-allowed path. What matters is
// that the "/api/" subtree answers, instead of the request falling through to
diff --git a/gui/cmd/ssl-vision-processor-gui/testdata/config.yml b/gui/cmd/ssl-vision-processor-gui/testdata/config.yml
new file mode 100644
index 0000000..88c8867
--- /dev/null
+++ b/gui/cmd/ssl-vision-processor-gui/testdata/config.yml
@@ -0,0 +1,159 @@
+# VisionProcessor configuration
+
+# Vision camera ID handled by this VisionProcessor instance.
+# On multi camera fields the IDs have to be ordered according to camera_ids.png.
+#cam_id: 0
+
+# Team bot heights yml file (heights in mm)
+#bot_heights_file: robot-heights.yml
+
+camera:
+ # Camera driver type. Availability depending on libraries installed.
+ # Existing: SPINNAKER (FLIR cameras), MVIMPACT (Bluefox3 cameras), OPENCV(files, v4l2 cameras)
+ driver: OPENCV
+
+ # Spinnaker, mvIMPACT or OpenCV(v4l2) camera id
+ #id: 0
+ # OpenCV camera device, image or video file path (if unset id is used instead)
+ path: /dev/video0
+
+ # Camera resolution as reported by the camera. VisionProcessor might use half (true color) resolution internally with SPINNAKER and MVIMPACT.
+ # 0 = highest resolution supported by the camera
+ #width: 0
+ #height: 0
+
+ # Camera exposure time in ms to adjust brightness. Higher values lead to more motion blur. Lower values lead to a darker image.
+ # Camera frame rate will drop if set equal to or higher than the frame time (1 / fps_cam).
+ # 0.0 = automatic exposure
+ #exposure: 0.0
+ # Camera gain to adjust brightness. Higher values lead to more noise. Lower values lead to a darker image.
+ # Frequently changing bot identities or team colors indicate an image that is too bright (all colors becoming nearly white).
+ # 0.0 = automatic gain
+ #gain: 0.0
+ # Camera gamma as nonlinear brightness adjustment. Only supported on SPINNAKER and OPENCV.
+ # Low values reduce differences between bright and dark illuminated areas. High values increase the color contrast.
+ # 1.0 = no gamma
+ #gamma: 1.0
+
+ # Camera white balance. OUTDOOR or INDOOR for auto white balance with green or gray carpet respectively.
+ # (distinction between OUTDOOR and INDOOR currently only implemented for SPINNAKER backend)
+ #white_balance: OUTDOOR
+ # If you want to set manual white balance values use this format:
+ #white_balance:
+ # red: 1.0
+ # blue: 1.0
+
+geometry:
+ # Total camera amount over the field
+ camera_amount: 2
+ # Camera height above field in mm
+ # 0.0 = automated camera height calibration, this does not work if the camera looks perpendicular to the field
+ #camera_height: 0.0
+
+ # Field line crossings at the edges of the camera extent in pixels from the top left image corner.
+ # The first coordinate must be the edge with the smallest x and y field coordinate.
+ # Only the first point's identity matters -- GeomModel.cpp brute-forces the
+ # correct clockwise order for the other three. First point = the corner
+ # picker's marker 4, which touches the goal box (confirmed against
+ # img/0.geomcalib_input.png; marker 3 is the same goal-box edge's other end
+ # and would also be a valid choice). Left/right (marker 3 vs 4 first) is an
+ # arbitrary but so-far-unverified choice: doesn't matter with one camera,
+ # would need to agree with camera 1 if a second one joins.
+ line_corners:
+ - [398, 422]
+ - [247, 135]
+ - [455, 33]
+ - [564, 327]
+
+ # Enable field line pixel refinement.
+ # Disable in cluttered environments when the geometry calibration has failed multiple times in a row.
+ #refinement: true
+
+ # Minimum brightness difference to surrounding pixels for the classification as field line pixel (0 - 255)
+ #field_line_threshold: 5
+ # Minimum length of line segments to ensure angular stability in pixels
+ #min_line_segment_length: 10.0
+ # Maximum perpendicular offset of line segments for merging in pixels
+ #max_line_segment_offset: 10.0
+ # Maximum relative angle of line segments for merging in °
+ #max_line_segment_angle: 3.0
+
+thresholds:
+ # Minimum mean cosine similarity (not normalized) of the blob border gradient (0 - 195075.0)
+ # High value lead to undetected blobs. Low values lead to an increase in false positive blob detections.
+ #circularity: 15.0
+ # Minimum circularity/(3*stddev) ball blob score
+ #score: 5.0
+
+ # Maximum amount of blobs processed per frame. Should not be necessary to adjust this value.
+ #blobs: 2000
+
+ # Minimum confidence (0.0 - 1.0)
+ #min_confidence: 0.2
+
+ # Min ball camera edge distance in mm
+ #min_cam_edge_distance: 170.0
+
+ # Maximum allowed clipping of two objects in mm
+ #clipping_tolerance: 10.0
+
+ # Added tolerance to geometry related operations in mm.
+ # Affects field border cutoff area and field line blob classification.
+ #geometry_tolerance: 10.0
+
+color:
+ # Strength of the reference color during color updates (0.0 - 0.5-history_force/2)
+ #reference_force: 0.1
+ # Strength of the previous color during color updates (0.0 - 1.0-reference_force)
+ #history_force: 0.7
+
+ # Reference colors used for ball determination
+ #orange: [192, 128, 64]
+ #field: [128, 128, 128]
+ # Reference colors used for center blob determination
+ #yellow: [255, 128, 0]
+ #blue: [0, 128, 255]
+ # Reference colors used for side blob determination
+ #green: [0, 255, 128]
+ #pink: [255, 0, 128]
+
+tracking:
+ # Min tracking radius in mm
+ #min_tracking_radius: 20.0
+
+ # Max tracked bot acceleration in m/s^2
+ #max_bot_acceleration: 6.5
+
+network:
+ # Game controller multicast ip address
+ #gc_ip: "224.5.23.1"
+ # Game controller multicast port
+ #gc_port: 10003
+
+ # Vision multicast IP address
+ #vision_ip: "224.5.23.2"
+ # Vision multicast port
+ #vision_port: 10006
+
+stream:
+ # If false no network live stream will be encoded and sent
+ #active: true
+ # Only stream raw camera footage. Useful for recordings.
+ #raw_feed: false
+
+ # Camera stream ip prefix
+ #ip_base_prefix: 224.5.23.
+ # Camera stream ip end base (cam_id is added to maintain separation)
+ #ip_base_end: 100
+ # Camera stream port
+ #port: 10100
+
+debug:
+ # Ground truth file. Only used by blob and geometry benchmark.
+ #ground_truth: gt.yml
+ # Wait for geometry prior to processing frames
+ #wait_for_geometry: false
+ # Save additional debug images in img/.
+ #debug_images: false
+ # Periodically overwrite img/.sample..png while calibration isn't accepted yet, every N milliseconds. 0 disables.
+ debug_stream_interval_ms: 3000
diff --git a/gui/config.yml b/gui/config.yml
new file mode 100644
index 0000000..7892dcc
--- /dev/null
+++ b/gui/config.yml
@@ -0,0 +1,157 @@
+# VisionProcessor configuration
+
+# Vision camera ID handled by this VisionProcessor instance.
+# On multi camera fields the IDs have to be ordered according to camera_ids.png.
+#cam_id: 0
+
+# Team bot heights yml file (heights in mm)
+#bot_heights_file: robot-heights.yml
+
+camera:
+ # Camera driver type. Availability depending on libraries installed.
+ # Existing: SPINNAKER (FLIR cameras), MVIMPACT (Bluefox3 cameras), OPENCV(files, v4l2 cameras)
+ #driver: SPINNAKER
+
+ # Spinnaker, mvIMPACT or OpenCV(v4l2) camera id
+ #id: 0
+ # OpenCV camera device, image or video file path (if unset id is used instead)
+ #path: /dev/video0
+
+ # Camera resolution as reported by the camera. VisionProcessor might use half (true color) resolution internally with SPINNAKER and MVIMPACT.
+ # 0 = highest resolution supported by the camera
+ #width: 0
+ #height: 0
+
+ # Camera exposure time in ms to adjust brightness. Higher values lead to more motion blur. Lower values lead to a darker image.
+ # Camera frame rate will drop if set equal to or higher than the frame time (1 / fps_cam).
+ # 0.0 = automatic exposure
+ #exposure: 0.0
+ # Camera gain to adjust brightness. Higher values lead to more noise. Lower values lead to a darker image.
+ # Frequently changing bot identities or team colors indicate an image that is too bright (all colors becoming nearly white).
+ # 0.0 = automatic gain
+ #gain: 0.0
+ # Camera gamma as nonlinear brightness adjustment. Only supported on SPINNAKER and OPENCV.
+ # Low values reduce differences between bright and dark illuminated areas. High values increase the color contrast.
+ # 1.0 = no gamma
+ #gamma: 1.0
+
+ # Camera white balance. OUTDOOR or INDOOR for auto white balance with green or gray carpet respectively.
+ # (distinction between OUTDOOR and INDOOR currently only implemented for SPINNAKER backend)
+ #white_balance: OUTDOOR
+ # If you want to set manual white balance values use this format:
+ #white_balance:
+ # red: 1.0
+ # blue: 1.0
+
+geometry:
+ line_corners:
+ - [1131, 945]
+ - [1263, 69]
+ - [1509, 726]
+ - [792, 300]
+ # Total camera amount over the field
+ #camera_amount: 1
+ # Camera height above field in mm
+ # 0.0 = automated camera height calibration, this does not work if the camera looks perpendicular to the field
+ #camera_height: 0.0
+
+ # Field line crossings at the edges of the camera extent in pixels from the top left image corner.
+ # The first coordinate must be the edge with the smallest x and y field coordinate.
+ #line_corners:
+ #- [0 , 1000]
+ #- [0 , 0]
+ #- [1000, 0]
+ #- [1000, 1000]
+
+ # Enable field line pixel refinement.
+ # Disable in cluttered environments when the geometry calibration has failed multiple times in a row.
+ #refinement: true
+
+ # Minimum brightness difference to surrounding pixels for the classification as field line pixel (0 - 255)
+ #field_line_threshold: 5
+ # Minimum length of line segments to ensure angular stability in pixels
+ #min_line_segment_length: 10.0
+ # Maximum perpendicular offset of line segments for merging in pixels
+ #max_line_segment_offset: 10.0
+ # Maximum relative angle of line segments for merging in °
+ #max_line_segment_angle: 3.0
+
+thresholds:
+ # Minimum mean cosine similarity (not normalized) of the blob border gradient (0 - 195075.0)
+ # High value lead to undetected blobs. Low values lead to an increase in false positive blob detections.
+ #circularity: 15.0
+ # Minimum circularity/(3*stddev) ball blob score
+ #score: 5.0
+
+ # Maximum amount of blobs processed per frame. Should not be necessary to adjust this value.
+ #blobs: 2000
+
+ # Minimum confidence (0.0 - 1.0)
+ #min_confidence: 0.2
+
+ # Min ball camera edge distance in mm
+ #min_cam_edge_distance: 170.0
+
+ # Maximum allowed clipping of two objects in mm
+ #clipping_tolerance: 10.0
+
+ # Added tolerance to geometry related operations in mm.
+ # Affects field border cutoff area and field line blob classification.
+ #geometry_tolerance: 10.0
+
+color:
+ # Strength of the reference color during color updates (0.0 - 0.5-history_force/2)
+ #reference_force: 0.1
+ # Strength of the previous color during color updates (0.0 - 1.0-reference_force)
+ #history_force: 0.7
+
+ # Reference colors used for ball determination
+ #orange: [192, 128, 64]
+ #field: [128, 128, 128]
+ # Reference colors used for center blob determination
+ #yellow: [255, 128, 0]
+ #blue: [0, 128, 255]
+ # Reference colors used for side blob determination
+ #green: [0, 255, 128]
+ #pink: [255, 0, 128]
+
+tracking:
+ # Min tracking radius in mm
+ #min_tracking_radius: 20.0
+
+ # Max tracked bot acceleration in m/s^2
+ #max_bot_acceleration: 6.5
+
+network:
+ # Game controller multicast ip address
+ #gc_ip: "224.5.23.1"
+ # Game controller multicast port
+ #gc_port: 10003
+
+ # Vision multicast IP address
+ #vision_ip: "224.5.23.2"
+ # Vision multicast port
+ #vision_port: 10006
+
+stream:
+ # If false no network live stream will be encoded and sent
+ #active: true
+ # Only stream raw camera footage. Useful for recordings.
+ #raw_feed: false
+
+ # Camera stream ip prefix
+ #ip_base_prefix: 224.5.23.
+ # Camera stream ip end base (cam_id is added to maintain separation)
+ #ip_base_end: 100
+ # Camera stream port
+ #port: 10100
+
+debug:
+ # Ground truth file. Only used by blob and geometry benchmark.
+ #ground_truth: gt.yml
+ # Wait for geometry prior to processing frames
+ #wait_for_geometry: false
+ # Save additional debug images in img/.
+ #debug_images: false
+ # Periodically overwrite img/.sample..png while calibration isn't accepted yet, every N milliseconds. 0 disables.
+ #debug_stream_interval_ms: 0
diff --git a/gui/frontend/src/App.svelte b/gui/frontend/src/App.svelte
index c4844f5..700555f 100644
--- a/gui/frontend/src/App.svelte
+++ b/gui/frontend/src/App.svelte
@@ -2,6 +2,7 @@
import { onMount } from "svelte";
import { topic } from "./lib/wrapper-bus";
import Shell from "./lib/layout/Shell.svelte";
+ import { nav } from "./lib/layout/nav.svelte";
let subscribed = $state(false);
const wrapperPacket = topic>("wrapper_packet.out");
@@ -14,6 +15,16 @@
let snapshots = $state([]);
let cacheBuster = $state(0);
+ // flat/gradient/blob are ball-detection debug views (see src/main.cpp) --
+ // color-tuning territory, not relevant to a geometry calibration.
+ const COLOR_ONLY_VIEWS = new Set(["flat", "gradient", "blob"]);
+
+ let visibleSnapshots = $derived(
+ nav.selectedCategoryId === "geometry"
+ ? snapshots.filter((s) => !COLOR_ONLY_VIEWS.has(s.view))
+ : snapshots,
+ );
+
async function refreshSnapshotList(): Promise {
try {
const response = await fetch("/api/snapshots");
@@ -54,24 +65,26 @@
Temporary debug utilities -- see the note in this file's source.
-
- Snapshots
- {#if snapshots.length === 0}
- No images in img/ yet.
- {:else}
-
- {#each snapshots as snap (`${snap.cam_id}.${snap.view}`)}
-
-
- cam {snap.cam_id} / {snap.view}
-
- {/each}
-
- {/if}
-
+ {#if nav.selectedCategoryId !== "field"}
+
+ Snapshots
+ {#if visibleSnapshots.length === 0}
+ No images in img/ yet.
+ {:else}
+
+ {#each visibleSnapshots as snap (`${snap.cam_id}.${snap.view}`)}
+
+
+ cam {snap.cam_id} / {snap.view}
+
+ {/each}
+
+ {/if}
+
+ {/if}
diff --git a/gui/frontend/src/lib/CornerPicker.svelte b/gui/frontend/src/lib/CornerPicker.svelte
index 7c48fb9..12bd77e 100644
--- a/gui/frontend/src/lib/CornerPicker.svelte
+++ b/gui/frontend/src/lib/CornerPicker.svelte
@@ -1,4 +1,6 @@
@@ -139,7 +212,8 @@
{
@@ -149,7 +223,9 @@
{
@@ -174,6 +250,22 @@
{yamlSnippet}
+
+
+
+ {saving ? "Saving..." : "Save to config.yml"}
+
+ {#if savedAt}
+ Saved.
+ {/if}
+ {#if saveError}
+ Error: {saveError}
+ {/if}
+
diff --git a/gui/frontend/src/lib/layout/Shell.svelte b/gui/frontend/src/lib/layout/Shell.svelte
index b06ae75..e63c2c4 100644
--- a/gui/frontend/src/lib/layout/Shell.svelte
+++ b/gui/frontend/src/lib/layout/Shell.svelte
@@ -21,7 +21,7 @@
vision-processor
- {$connectionState}
+ {$connectionState.toUpperCase()} ({location.host})
diff --git a/gui/internal/geometry/instance_config.go b/gui/internal/geometry/instance_config.go
new file mode 100644
index 0000000..0243dfb
--- /dev/null
+++ b/gui/internal/geometry/instance_config.go
@@ -0,0 +1,271 @@
+package geometry
+
+import (
+ "fmt"
+ "os"
+ "regexp"
+ "strings"
+
+ "gopkg.in/yaml.v3"
+)
+
+// Corner is one point in image pixel coordinates, as produced by the corner
+// picker. Only the first element of a slice passed to WriteLineCorners is
+// meaningful to src/calib/GeomModel.cpp's cornerCalibration -- it must be the
+// field's (minX, minY) corner. The other three may be in any order.
+type Corner struct {
+ X int `json:"x"`
+ Y int `json:"y"`
+}
+
+var (
+ geometryHeader = regexp.MustCompile(`^geometry:\s*$`)
+ lineCornersKey = regexp.MustCompile(`^(\s*)line_corners:\s*$`)
+ goalSideMarkerKV = regexp.MustCompile(`^(\s*)goal_side_marker:.*$`)
+)
+
+// WriteLineCorners updates geometry.line_corners in the vision_processor
+// instance config at path, in place, along with a goal_side_marker record of
+// which corner-picker marker (1-4, matching its on-screen number) was chosen
+// as the goal-side corner -- vision_processor itself never reads
+// goal_side_marker (yaml-cpp's Node["key"] lookups ignore unknown keys), it's
+// purely a record for whoever looks at this file next.
+//
+// This edits the text directly rather than decoding/re-encoding the file as
+// YAML (contrast Geometry.saveYAML for geometry.yml): config.yml ships full
+// of comments and commented-out example values meant to be hand-read, and
+// gopkg.in/yaml.v3 does not reliably preserve those across a decode/re-encode
+// round trip (confirmed while building this -- entire comment blocks
+// elsewhere in the file were dropped and indentation drifted). A line-based
+// splice touches nothing outside the two keys it's asked to set.
+func WriteLineCorners(path string, corners []Corner, goalSideMarker int) error {
+ if len(corners) == 0 {
+ return fmt.Errorf("no corners given")
+ }
+
+ if goalSideMarker < 1 || goalSideMarker > len(corners) {
+ return fmt.Errorf("goalSideMarker must identify one of the %d corners, got %d", len(corners), goalSideMarker)
+ }
+
+ data, err := os.ReadFile(path)
+ if err != nil {
+ return fmt.Errorf("read %s: %w", path, err)
+ }
+
+ updated, err := spliceLineCorners(string(data), corners)
+ if err != nil {
+ return fmt.Errorf("%s: %w", path, err)
+ }
+
+ updated, err = spliceGoalSideMarker(updated, goalSideMarker)
+ if err != nil {
+ return fmt.Errorf("%s: %w", path, err)
+ }
+
+ if err := os.WriteFile(path, []byte(updated), 0o644); err != nil {
+ return fmt.Errorf("write %s: %w", path, err)
+ }
+
+ return nil
+}
+
+// instanceConfig mirrors just the two geometry fields WriteLineCorners
+// writes. Unlike WriteLineCorners, reading doesn't need to preserve
+// anything -- nothing gets written back -- so a plain yaml.Unmarshal is fine
+// here even though it isn't for the write path.
+type instanceConfig struct {
+ Geometry struct {
+ LineCorners [][]int `yaml:"line_corners"`
+ GoalSideMarker int `yaml:"goal_side_marker"`
+ } `yaml:"geometry"`
+}
+
+// ReadLineCorners reads back whatever WriteLineCorners last saved to path.
+// Returns a nil/empty corners slice and a zero marker (not an error) if the
+// file has no line_corners yet -- that's the normal, not-yet-calibrated
+// state, not a failure.
+func ReadLineCorners(path string) ([]Corner, int, error) {
+ data, err := os.ReadFile(path)
+ if err != nil {
+ return nil, 0, fmt.Errorf("read %s: %w", path, err)
+ }
+
+ var cfg instanceConfig
+ if err := yaml.Unmarshal(data, &cfg); err != nil {
+ return nil, 0, fmt.Errorf("parse %s: %w", path, err)
+ }
+
+ corners := make([]Corner, len(cfg.Geometry.LineCorners))
+
+ for i, pair := range cfg.Geometry.LineCorners {
+ if len(pair) != 2 {
+ return nil, 0, fmt.Errorf("%s: geometry.line_corners[%d] has %d values, want 2", path, i, len(pair))
+ }
+
+ corners[i] = Corner{X: pair[0], Y: pair[1]}
+ }
+
+ return corners, cfg.Geometry.GoalSideMarker, nil
+}
+
+// geometrySectionBounds finds the 'geometry:' top-level key and the line
+// index where its section ends (the next top-level key, or len(lines)).
+func geometrySectionBounds(lines []string) (start, end int, err error) {
+ start = -1
+
+ for i, line := range lines {
+ if geometryHeader.MatchString(line) {
+ start = i
+
+ break
+ }
+ }
+
+ if start == -1 {
+ return 0, 0, fmt.Errorf("missing top-level 'geometry' section")
+ }
+
+ end = len(lines)
+
+ for i := start + 1; i < len(lines); i++ {
+ if isTopLevelKeyLine(lines[i]) {
+ end = i
+
+ break
+ }
+ }
+
+ return start, end, nil
+}
+
+// spliceLineCorners is the pure text transform behind WriteLineCorners' list
+// value, split out so it's testable without touching disk.
+func spliceLineCorners(doc string, corners []Corner) (string, error) {
+ lines, trailingNewline := splitDoc(doc)
+
+ geometryAt, sectionEnd, err := geometrySectionBounds(lines)
+ if err != nil {
+ return "", err
+ }
+
+ keyAt := -1
+ indent := ""
+
+ for i := geometryAt + 1; i < sectionEnd; i++ {
+ if m := lineCornersKey.FindStringSubmatch(lines[i]); m != nil {
+ keyAt = i
+ indent = m[1]
+
+ break
+ }
+ }
+
+ items := make([]string, len(corners))
+
+ if keyAt == -1 {
+ indent = firstChildIndent(lines[geometryAt+1 : sectionEnd])
+
+ for i, c := range corners {
+ items[i] = fmt.Sprintf("%s- [%d, %d]", indent, c.X, c.Y)
+ }
+
+ out := make([]string, 0, len(lines)+len(items)+1)
+ out = append(out, lines[:geometryAt+1]...)
+ out = append(out, indent+"line_corners:")
+ out = append(out, items...)
+ out = append(out, lines[geometryAt+1:]...)
+
+ return joinLines(out, trailingNewline), nil
+ }
+
+ // Consume any existing list items (real or commented-out placeholders)
+ // immediately following the key -- everything after that, including
+ // blank lines and the next section's comments, is left untouched.
+ itemLine := regexp.MustCompile(`^` + regexp.QuoteMeta(indent) + `#?-`)
+ end := keyAt + 1
+ for end < sectionEnd && itemLine.MatchString(lines[end]) {
+ end++
+ }
+
+ for i, c := range corners {
+ items[i] = fmt.Sprintf("%s- [%d, %d]", indent, c.X, c.Y)
+ }
+
+ out := make([]string, 0, len(lines)+len(items))
+ out = append(out, lines[:keyAt+1]...)
+ out = append(out, items...)
+ out = append(out, lines[end:]...)
+
+ return joinLines(out, trailingNewline), nil
+}
+
+// spliceGoalSideMarker is the pure text transform for the goal_side_marker
+// scalar. A one-line explanatory comment is added the first time the key is
+// created; updating an existing value leaves whatever's around it alone.
+func spliceGoalSideMarker(doc string, marker int) (string, error) {
+ lines, trailingNewline := splitDoc(doc)
+
+ geometryAt, sectionEnd, err := geometrySectionBounds(lines)
+ if err != nil {
+ return "", err
+ }
+
+ for i := geometryAt + 1; i < sectionEnd; i++ {
+ if m := goalSideMarkerKV.FindStringSubmatch(lines[i]); m != nil {
+ lines[i] = fmt.Sprintf("%sgoal_side_marker: %d", m[1], marker)
+
+ return joinLines(lines, trailingNewline), nil
+ }
+ }
+
+ indent := firstChildIndent(lines[geometryAt+1 : sectionEnd])
+ comment := indent + "# Which corner-picker marker (1-4, its on-screen number) was chosen as the goal-side corner. Not read by vision_processor -- record only."
+
+ out := make([]string, 0, len(lines)+2)
+ out = append(out, lines[:sectionEnd]...)
+ out = append(out, comment, fmt.Sprintf("%sgoal_side_marker: %d", indent, marker))
+ out = append(out, lines[sectionEnd:]...)
+
+ return joinLines(out, trailingNewline), nil
+}
+
+// isTopLevelKeyLine reports whether line starts a new root-level YAML key
+// (unindented, not blank, not a comment) -- the boundary of the 'geometry'
+// section.
+func isTopLevelKeyLine(line string) bool {
+ if line == "" {
+ return false
+ }
+
+ return line[0] != ' ' && line[0] != '\t' && line[0] != '#'
+}
+
+// firstChildIndent finds the leading whitespace of the first real (non-blank,
+// non-comment) line in a section, for a key that needs to be appended fresh.
+// Falls back to two spaces -- the indent every shipped config.yml template
+// uses -- if the section has no other real keys yet.
+func firstChildIndent(sectionLines []string) string {
+ for _, line := range sectionLines {
+ trimmed := strings.TrimSpace(line)
+ if trimmed == "" || strings.HasPrefix(trimmed, "#") {
+ continue
+ }
+
+ return line[:len(line)-len(strings.TrimLeft(line, " \t"))]
+ }
+
+ return " "
+}
+
+func splitDoc(doc string) (lines []string, trailingNewline bool) {
+ return strings.Split(strings.TrimSuffix(doc, "\n"), "\n"), strings.HasSuffix(doc, "\n")
+}
+
+func joinLines(lines []string, trailingNewline bool) string {
+ out := strings.Join(lines, "\n")
+ if trailingNewline {
+ out += "\n"
+ }
+
+ return out
+}
diff --git a/gui/internal/geometry/instance_config_test.go b/gui/internal/geometry/instance_config_test.go
new file mode 100644
index 0000000..b375362
--- /dev/null
+++ b/gui/internal/geometry/instance_config_test.go
@@ -0,0 +1,252 @@
+package geometry
+
+import (
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+// testConfigFile copies testdata/config.yml into t.TempDir() so tests can
+// freely write to it without touching the tracked fixture -- same discipline
+// as testGeometry in geometry_test.go.
+func testConfigFile(t *testing.T) string {
+ t.Helper()
+
+ src, err := os.ReadFile("testdata/config.yml")
+ if err != nil {
+ t.Fatalf("ReadFile fixture: %v", err)
+ }
+
+ path := filepath.Join(t.TempDir(), "config.yml")
+ if err := os.WriteFile(path, src, 0o644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+
+ return path
+}
+
+func TestWriteLineCornersUpdatesValuesInPlace(t *testing.T) {
+ path := testConfigFile(t)
+
+ corners := []Corner{{X: 1, Y: 2}, {X: 3, Y: 4}, {X: 5, Y: 6}, {X: 7, Y: 8}}
+ if err := WriteLineCorners(path, corners, 1); err != nil {
+ t.Fatalf("WriteLineCorners: %v", err)
+ }
+
+ got, err := os.ReadFile(path)
+ if err != nil {
+ t.Fatalf("ReadFile: %v", err)
+ }
+
+ want := "line_corners:\n - [1, 2]\n - [3, 4]\n - [5, 6]\n - [7, 8]\n"
+ if !strings.Contains(string(got), want) {
+ t.Errorf("output does not contain the new corners as a block sequence of flow tuples:\n%s", got)
+ }
+
+ if strings.Contains(string(got), "398, 422") {
+ t.Error("old corner values are still present")
+ }
+}
+
+func TestWriteLineCornersPreservesComments(t *testing.T) {
+ path := testConfigFile(t)
+
+ before, err := os.ReadFile("testdata/config.yml")
+ if err != nil {
+ t.Fatalf("ReadFile fixture: %v", err)
+ }
+
+ if err := WriteLineCorners(path, []Corner{{X: 1, Y: 2}, {X: 3, Y: 4}, {X: 5, Y: 6}, {X: 7, Y: 8}}, 1); err != nil {
+ t.Fatalf("WriteLineCorners: %v", err)
+ }
+
+ after, err := os.ReadFile(path)
+ if err != nil {
+ t.Fatalf("ReadFile: %v", err)
+ }
+
+ // Every comment line and every other section is untouched -- only the
+ // line_corners value itself should have changed.
+ for _, line := range strings.Split(string(before), "\n") {
+ trimmed := strings.TrimSpace(line)
+ if trimmed == "" || !strings.HasPrefix(trimmed, "#") {
+ continue
+ }
+
+ if !strings.Contains(string(after), line) {
+ t.Errorf("comment line lost: %q", line)
+ }
+ }
+
+ if !strings.Contains(string(after), "camera_amount: 2") {
+ t.Error("unrelated 'camera_amount' key was disturbed")
+ }
+
+ if !strings.Contains(string(after), "color:") {
+ t.Error("unrelated 'color' section was disturbed")
+ }
+}
+
+func TestWriteLineCornersAppendsTheKeyWhenAbsent(t *testing.T) {
+ path := filepath.Join(t.TempDir(), "config.yml")
+ data := "geometry:\n camera_amount: 1\n"
+ if err := os.WriteFile(path, []byte(data), 0o644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+
+ if err := WriteLineCorners(path, []Corner{{X: 1, Y: 2}, {X: 3, Y: 4}, {X: 5, Y: 6}, {X: 7, Y: 8}}, 1); err != nil {
+ t.Fatalf("WriteLineCorners: %v", err)
+ }
+
+ got, err := os.ReadFile(path)
+ if err != nil {
+ t.Fatalf("ReadFile: %v", err)
+ }
+
+ if !strings.Contains(string(got), "line_corners:") {
+ t.Errorf("line_corners key was not appended:\n%s", got)
+ }
+
+ if !strings.Contains(string(got), "camera_amount: 1") {
+ t.Error("existing key was disturbed")
+ }
+}
+
+func TestWriteLineCornersErrorsWithoutAGeometrySection(t *testing.T) {
+ path := filepath.Join(t.TempDir(), "config.yml")
+ if err := os.WriteFile(path, []byte("camera:\n driver: OPENCV\n"), 0o644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+
+ err := WriteLineCorners(path, []Corner{{X: 1, Y: 2}}, 1)
+ if err == nil {
+ t.Fatal("expected an error, got nil")
+ }
+}
+
+func TestWriteLineCornersErrorsOnAMissingFile(t *testing.T) {
+ err := WriteLineCorners(filepath.Join(t.TempDir(), "does-not-exist.yml"), []Corner{{X: 1, Y: 2}}, 1)
+ if err == nil {
+ t.Fatal("expected an error, got nil")
+ }
+}
+
+func TestWriteLineCornersErrorsWithNoCorners(t *testing.T) {
+ path := testConfigFile(t)
+
+ if err := WriteLineCorners(path, nil, 1); err == nil {
+ t.Fatal("expected an error, got nil")
+ }
+}
+
+func TestWriteLineCornersErrorsWhenGoalSideMarkerIsOutOfRange(t *testing.T) {
+ path := testConfigFile(t)
+
+ corners := []Corner{{X: 1, Y: 2}, {X: 3, Y: 4}, {X: 5, Y: 6}, {X: 7, Y: 8}}
+
+ for _, marker := range []int{0, 5, -1} {
+ if err := WriteLineCorners(path, corners, marker); err == nil {
+ t.Errorf("goalSideMarker=%d: expected an error, got nil", marker)
+ }
+ }
+}
+
+func TestWriteLineCornersRecordsTheGoalSideMarker(t *testing.T) {
+ path := testConfigFile(t)
+
+ corners := []Corner{{X: 1, Y: 2}, {X: 3, Y: 4}, {X: 5, Y: 6}, {X: 7, Y: 8}}
+ if err := WriteLineCorners(path, corners, 3); err != nil {
+ t.Fatalf("WriteLineCorners: %v", err)
+ }
+
+ got, err := os.ReadFile(path)
+ if err != nil {
+ t.Fatalf("ReadFile: %v", err)
+ }
+
+ if !strings.Contains(string(got), "goal_side_marker: 3") {
+ t.Errorf("goal_side_marker was not recorded:\n%s", got)
+ }
+}
+
+func TestReadLineCornersRoundTripsWhatWriteLineCornersSaved(t *testing.T) {
+ path := testConfigFile(t)
+
+ corners := []Corner{{X: 1, Y: 2}, {X: 3, Y: 4}, {X: 5, Y: 6}, {X: 7, Y: 8}}
+ if err := WriteLineCorners(path, corners, 3); err != nil {
+ t.Fatalf("WriteLineCorners: %v", err)
+ }
+
+ gotCorners, gotMarker, err := ReadLineCorners(path)
+ if err != nil {
+ t.Fatalf("ReadLineCorners: %v", err)
+ }
+
+ if len(gotCorners) != len(corners) {
+ t.Fatalf("got %d corners, want %d", len(gotCorners), len(corners))
+ }
+
+ for i, c := range corners {
+ if gotCorners[i] != c {
+ t.Errorf("corner %d = %+v, want %+v", i, gotCorners[i], c)
+ }
+ }
+
+ if gotMarker != 3 {
+ t.Errorf("goalSideMarker = %d, want 3", gotMarker)
+ }
+}
+
+func TestReadLineCornersReturnsEmptyWhenNothingSavedYet(t *testing.T) {
+ path := filepath.Join(t.TempDir(), "config.yml")
+ if err := os.WriteFile(path, []byte("geometry:\n camera_amount: 1\n"), 0o644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+
+ corners, marker, err := ReadLineCorners(path)
+ if err != nil {
+ t.Fatalf("ReadLineCorners: %v", err)
+ }
+
+ if len(corners) != 0 {
+ t.Errorf("corners = %+v, want none", corners)
+ }
+
+ if marker != 0 {
+ t.Errorf("goalSideMarker = %d, want 0", marker)
+ }
+}
+
+func TestReadLineCornersErrorsOnAMissingFile(t *testing.T) {
+ _, _, err := ReadLineCorners(filepath.Join(t.TempDir(), "does-not-exist.yml"))
+ if err == nil {
+ t.Fatal("expected an error, got nil")
+ }
+}
+
+func TestWriteLineCornersUpdatesAnExistingGoalSideMarkerInPlace(t *testing.T) {
+ path := testConfigFile(t)
+
+ corners := []Corner{{X: 1, Y: 2}, {X: 3, Y: 4}, {X: 5, Y: 6}, {X: 7, Y: 8}}
+ if err := WriteLineCorners(path, corners, 2); err != nil {
+ t.Fatalf("WriteLineCorners: %v", err)
+ }
+
+ if err := WriteLineCorners(path, corners, 4); err != nil {
+ t.Fatalf("WriteLineCorners: %v", err)
+ }
+
+ got, err := os.ReadFile(path)
+ if err != nil {
+ t.Fatalf("ReadFile: %v", err)
+ }
+
+ if strings.Count(string(got), "goal_side_marker:") != 1 {
+ t.Errorf("expected exactly one goal_side_marker key, got:\n%s", got)
+ }
+
+ if !strings.Contains(string(got), "goal_side_marker: 4") {
+ t.Errorf("goal_side_marker was not updated to the new value:\n%s", got)
+ }
+}
diff --git a/gui/internal/geometry/testdata/config.yml b/gui/internal/geometry/testdata/config.yml
new file mode 100644
index 0000000..88c8867
--- /dev/null
+++ b/gui/internal/geometry/testdata/config.yml
@@ -0,0 +1,159 @@
+# VisionProcessor configuration
+
+# Vision camera ID handled by this VisionProcessor instance.
+# On multi camera fields the IDs have to be ordered according to camera_ids.png.
+#cam_id: 0
+
+# Team bot heights yml file (heights in mm)
+#bot_heights_file: robot-heights.yml
+
+camera:
+ # Camera driver type. Availability depending on libraries installed.
+ # Existing: SPINNAKER (FLIR cameras), MVIMPACT (Bluefox3 cameras), OPENCV(files, v4l2 cameras)
+ driver: OPENCV
+
+ # Spinnaker, mvIMPACT or OpenCV(v4l2) camera id
+ #id: 0
+ # OpenCV camera device, image or video file path (if unset id is used instead)
+ path: /dev/video0
+
+ # Camera resolution as reported by the camera. VisionProcessor might use half (true color) resolution internally with SPINNAKER and MVIMPACT.
+ # 0 = highest resolution supported by the camera
+ #width: 0
+ #height: 0
+
+ # Camera exposure time in ms to adjust brightness. Higher values lead to more motion blur. Lower values lead to a darker image.
+ # Camera frame rate will drop if set equal to or higher than the frame time (1 / fps_cam).
+ # 0.0 = automatic exposure
+ #exposure: 0.0
+ # Camera gain to adjust brightness. Higher values lead to more noise. Lower values lead to a darker image.
+ # Frequently changing bot identities or team colors indicate an image that is too bright (all colors becoming nearly white).
+ # 0.0 = automatic gain
+ #gain: 0.0
+ # Camera gamma as nonlinear brightness adjustment. Only supported on SPINNAKER and OPENCV.
+ # Low values reduce differences between bright and dark illuminated areas. High values increase the color contrast.
+ # 1.0 = no gamma
+ #gamma: 1.0
+
+ # Camera white balance. OUTDOOR or INDOOR for auto white balance with green or gray carpet respectively.
+ # (distinction between OUTDOOR and INDOOR currently only implemented for SPINNAKER backend)
+ #white_balance: OUTDOOR
+ # If you want to set manual white balance values use this format:
+ #white_balance:
+ # red: 1.0
+ # blue: 1.0
+
+geometry:
+ # Total camera amount over the field
+ camera_amount: 2
+ # Camera height above field in mm
+ # 0.0 = automated camera height calibration, this does not work if the camera looks perpendicular to the field
+ #camera_height: 0.0
+
+ # Field line crossings at the edges of the camera extent in pixels from the top left image corner.
+ # The first coordinate must be the edge with the smallest x and y field coordinate.
+ # Only the first point's identity matters -- GeomModel.cpp brute-forces the
+ # correct clockwise order for the other three. First point = the corner
+ # picker's marker 4, which touches the goal box (confirmed against
+ # img/0.geomcalib_input.png; marker 3 is the same goal-box edge's other end
+ # and would also be a valid choice). Left/right (marker 3 vs 4 first) is an
+ # arbitrary but so-far-unverified choice: doesn't matter with one camera,
+ # would need to agree with camera 1 if a second one joins.
+ line_corners:
+ - [398, 422]
+ - [247, 135]
+ - [455, 33]
+ - [564, 327]
+
+ # Enable field line pixel refinement.
+ # Disable in cluttered environments when the geometry calibration has failed multiple times in a row.
+ #refinement: true
+
+ # Minimum brightness difference to surrounding pixels for the classification as field line pixel (0 - 255)
+ #field_line_threshold: 5
+ # Minimum length of line segments to ensure angular stability in pixels
+ #min_line_segment_length: 10.0
+ # Maximum perpendicular offset of line segments for merging in pixels
+ #max_line_segment_offset: 10.0
+ # Maximum relative angle of line segments for merging in °
+ #max_line_segment_angle: 3.0
+
+thresholds:
+ # Minimum mean cosine similarity (not normalized) of the blob border gradient (0 - 195075.0)
+ # High value lead to undetected blobs. Low values lead to an increase in false positive blob detections.
+ #circularity: 15.0
+ # Minimum circularity/(3*stddev) ball blob score
+ #score: 5.0
+
+ # Maximum amount of blobs processed per frame. Should not be necessary to adjust this value.
+ #blobs: 2000
+
+ # Minimum confidence (0.0 - 1.0)
+ #min_confidence: 0.2
+
+ # Min ball camera edge distance in mm
+ #min_cam_edge_distance: 170.0
+
+ # Maximum allowed clipping of two objects in mm
+ #clipping_tolerance: 10.0
+
+ # Added tolerance to geometry related operations in mm.
+ # Affects field border cutoff area and field line blob classification.
+ #geometry_tolerance: 10.0
+
+color:
+ # Strength of the reference color during color updates (0.0 - 0.5-history_force/2)
+ #reference_force: 0.1
+ # Strength of the previous color during color updates (0.0 - 1.0-reference_force)
+ #history_force: 0.7
+
+ # Reference colors used for ball determination
+ #orange: [192, 128, 64]
+ #field: [128, 128, 128]
+ # Reference colors used for center blob determination
+ #yellow: [255, 128, 0]
+ #blue: [0, 128, 255]
+ # Reference colors used for side blob determination
+ #green: [0, 255, 128]
+ #pink: [255, 0, 128]
+
+tracking:
+ # Min tracking radius in mm
+ #min_tracking_radius: 20.0
+
+ # Max tracked bot acceleration in m/s^2
+ #max_bot_acceleration: 6.5
+
+network:
+ # Game controller multicast ip address
+ #gc_ip: "224.5.23.1"
+ # Game controller multicast port
+ #gc_port: 10003
+
+ # Vision multicast IP address
+ #vision_ip: "224.5.23.2"
+ # Vision multicast port
+ #vision_port: 10006
+
+stream:
+ # If false no network live stream will be encoded and sent
+ #active: true
+ # Only stream raw camera footage. Useful for recordings.
+ #raw_feed: false
+
+ # Camera stream ip prefix
+ #ip_base_prefix: 224.5.23.
+ # Camera stream ip end base (cam_id is added to maintain separation)
+ #ip_base_end: 100
+ # Camera stream port
+ #port: 10100
+
+debug:
+ # Ground truth file. Only used by blob and geometry benchmark.
+ #ground_truth: gt.yml
+ # Wait for geometry prior to processing frames
+ #wait_for_geometry: false
+ # Save additional debug images in img/.
+ #debug_images: false
+ # Periodically overwrite img/.sample..png while calibration isn't accepted yet, every N milliseconds. 0 disables.
+ debug_stream_interval_ms: 3000
From 3cb7d85bef7db5df936d3bfb4ea98c65402a8c5a Mon Sep 17 00:00:00 2001
From: Will Stuckey
Date: Fri, 25 Sep 2026 10:47:28 -0400
Subject: [PATCH 08/23] make pb generated code transient
---
.github/workflows/ci.yml | 41 +-
.gitignore | 6 +-
README.md | 2 +-
gui/CLAUDE.md | 40 +-
gui/Makefile | 33 +-
gui/buf.gen.yaml | 9 +-
gui/frontend/README.md | 3 +-
gui/frontend/package-lock.json | 71 +-
gui/frontend/package.json | 1 +
.../proto/gamecontroller/ssl_gc_common_pb.ts | 139 -
.../gamecontroller/ssl_gc_game_event_pb.ts | 3850 --------------
.../gamecontroller/ssl_gc_geometry_pb.ts | 106 -
.../gamecontroller/ssl_gc_rcon_autoref_pb.ts | 157 -
.../proto/gamecontroller/ssl_gc_rcon_pb.ts | 208 -
.../ssl_gc_rcon_remotecontrol_pb.ts | 565 ---
.../gamecontroller/ssl_gc_rcon_team_pb.ts | 264 -
.../ssl_gc_referee_message_pb.ts | 1055 ----
.../proto/vision/ssl_vision_detection_pb.ts | 403 --
.../vision/ssl_vision_detection_tracked_pb.ts | 448 --
.../proto/vision/ssl_vision_geometry_pb.ts | 1031 ----
.../src/proto/vision/ssl_vision_wrapper_pb.ts | 123 -
.../vision/ssl_vision_wrapper_tracked_pb.ts | 83 -
.../src/proto/vision/ssl_vp_config_pb.ts | 951 ----
gui/go.mod | 2 +
.../gamecontroller/ssl_gc_common.pb.go | 271 -
.../gamecontroller/ssl_gc_game_event.pb.go | 4459 -----------------
.../gamecontroller/ssl_gc_geometry.pb.go | 198 -
gui/internal/gamecontroller/ssl_gc_rcon.pb.go | 352 --
.../gamecontroller/ssl_gc_rcon_autoref.pb.go | 283 --
.../ssl_gc_rcon_remotecontrol.pb.go | 718 ---
.../gamecontroller/ssl_gc_rcon_team.pb.go | 442 --
.../ssl_gc_referee_message.pb.go | 1113 ----
.../vision/ssl_vision_detection.pb.go | 439 --
.../vision/ssl_vision_detection_tracked.pb.go | 544 --
gui/internal/vision/ssl_vision_geometry.pb.go | 1135 -----
gui/internal/vision/ssl_vision_wrapper.pb.go | 238 -
.../vision/ssl_vision_wrapper_tracked.pb.go | 150 -
gui/internal/vision/ssl_vp_config.pb.go | 1230 -----
38 files changed, 162 insertions(+), 21001 deletions(-)
delete mode 100644 gui/frontend/src/proto/gamecontroller/ssl_gc_common_pb.ts
delete mode 100644 gui/frontend/src/proto/gamecontroller/ssl_gc_game_event_pb.ts
delete mode 100644 gui/frontend/src/proto/gamecontroller/ssl_gc_geometry_pb.ts
delete mode 100644 gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_autoref_pb.ts
delete mode 100644 gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_pb.ts
delete mode 100644 gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_remotecontrol_pb.ts
delete mode 100644 gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_team_pb.ts
delete mode 100644 gui/frontend/src/proto/gamecontroller/ssl_gc_referee_message_pb.ts
delete mode 100644 gui/frontend/src/proto/vision/ssl_vision_detection_pb.ts
delete mode 100644 gui/frontend/src/proto/vision/ssl_vision_detection_tracked_pb.ts
delete mode 100644 gui/frontend/src/proto/vision/ssl_vision_geometry_pb.ts
delete mode 100644 gui/frontend/src/proto/vision/ssl_vision_wrapper_pb.ts
delete mode 100644 gui/frontend/src/proto/vision/ssl_vision_wrapper_tracked_pb.ts
delete mode 100644 gui/frontend/src/proto/vision/ssl_vp_config_pb.ts
delete mode 100644 gui/internal/gamecontroller/ssl_gc_common.pb.go
delete mode 100644 gui/internal/gamecontroller/ssl_gc_game_event.pb.go
delete mode 100644 gui/internal/gamecontroller/ssl_gc_geometry.pb.go
delete mode 100644 gui/internal/gamecontroller/ssl_gc_rcon.pb.go
delete mode 100644 gui/internal/gamecontroller/ssl_gc_rcon_autoref.pb.go
delete mode 100644 gui/internal/gamecontroller/ssl_gc_rcon_remotecontrol.pb.go
delete mode 100644 gui/internal/gamecontroller/ssl_gc_rcon_team.pb.go
delete mode 100644 gui/internal/gamecontroller/ssl_gc_referee_message.pb.go
delete mode 100644 gui/internal/vision/ssl_vision_detection.pb.go
delete mode 100644 gui/internal/vision/ssl_vision_detection_tracked.pb.go
delete mode 100644 gui/internal/vision/ssl_vision_geometry.pb.go
delete mode 100644 gui/internal/vision/ssl_vision_wrapper.pb.go
delete mode 100644 gui/internal/vision/ssl_vision_wrapper_tracked.pb.go
delete mode 100644 gui/internal/vision/ssl_vp_config.pb.go
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 18a4f43..c617dde 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -38,10 +38,13 @@ jobs:
name: Go (gui)
runs-on: ubuntu-latest
steps:
- # No submodule checkout: gui/internal/{vision,gamecontroller} are
- # generated Go bindings committed to the tree (see gui/buf.gen.yaml);
- # only `make proto` touches the proto/ submodule.
+ # gui/internal/{vision,gamecontroller} are generated, not committed (see
+ # gui/buf.gen.yaml) -- the proto/ submodule and a `buf generate` (via
+ # `make .proto`, local plugins, no network needed) are needed before
+ # anything here builds.
- uses: actions/checkout@v4
+ with:
+ submodules: recursive
- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main
@@ -50,6 +53,7 @@ jobs:
run: |
nix develop --command bash -c '
cd gui
+ make .proto
test -z "$(gofmt -l .)" || { gofmt -l .; exit 1; }
go vet ./cmd/... ./internal/... ./frontend
go build ./cmd/... ./internal/... ./frontend
@@ -59,24 +63,23 @@ jobs:
frontend:
name: Frontend (gui/frontend)
runs-on: ubuntu-latest
- defaults:
- run:
- working-directory: gui/frontend
steps:
+ # frontend/src/proto is generated, not committed (see gui/buf.gen.yaml)
+ # -- this job now needs the proto/ submodule and buf/go (hence nix,
+ # same as gui-go) to produce it before npm can build against it.
- uses: actions/checkout@v4
-
- - uses: actions/setup-node@v4
with:
- node-version: 22
- cache: npm
- cache-dependency-path: gui/frontend/package-lock.json
-
- - run: npm ci
-
- - run: npm run lint
-
- - run: npm run format:check
+ submodules: recursive
- - run: npm run check
+ - uses: DeterminateSystems/nix-installer-action@main
+ - uses: DeterminateSystems/magic-nix-cache-action@main
- - run: npm run build
+ - name: Lint, check, build
+ run: |
+ nix develop --command bash -c '
+ cd gui && make .proto && cd frontend
+ npm run lint
+ npm run format:check
+ npm run check
+ npm run build
+ '
diff --git a/.gitignore b/.gitignore
index 35e2149..c1fc702 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,9 @@
/src/cl_kernels.S
/src/proto
/python/proto
+/gui/internal/vision
+/gui/internal/gamecontroller
+/gui/frontend/src/proto
__pycache__
# Cam viewer
@@ -20,8 +23,9 @@ geometry_benchmark
/gui/bin
/gui/ssl-vision-processor-gui
-# Makefile sentinel for the frontend build
+# Makefile sentinels for the frontend build and protobuf codegen
/gui/.frontend
+/gui/.proto
#CMake files
/build
diff --git a/README.md b/README.md
index 99f3d40..16aca7e 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ for all vision_processors, teams and the game controller.
A Go host plus a browser UI, replacing `geom_publisher.py` for anyone running it:
- `gui/` — Go host (`cmd/ssl-vision-processor-gui`). Owns the field geometry, absorbs calibrations from vision processors over multicast, and serves the embedded frontend, JSON API, a WebSocket for live updates, and debug snapshot images all on one port. Run with `cd gui && make run` (defaults to `geometry-divB.yml`).
-- `gui/frontend/` — Svelte 5 + TypeScript + Vite, embedded into the Go binary. Run standalone with `cd gui/frontend && npm install && npm run dev` (proxies `/api` and `/ws` to the Go host), or serve it from the Go host directly with `make run`. See [`gui/frontend/README.md`](gui/frontend/README.md).
+- `gui/frontend/` — Svelte 5 + TypeScript + Vite, embedded into the Go binary. Run standalone with `cd gui && make proto && cd frontend && npm install && npm run dev` (proxies `/api` and `/ws` to the Go host), or serve it from the Go host directly with `make run`. `make proto` regenerates the protobuf bindings the frontend imports (not committed to git; needs `buf`, or use `nix develop`, see [`gui/CLAUDE.md`](gui/CLAUDE.md)) and only needs to be rerun after the `proto/` submodule changes. See [`gui/frontend/README.md`](gui/frontend/README.md).
## Dependency installation and compilation
diff --git a/gui/CLAUDE.md b/gui/CLAUDE.md
index 4ccc033..1b225ca 100644
--- a/gui/CLAUDE.md
+++ b/gui/CLAUDE.md
@@ -14,13 +14,22 @@ which still import it directly — do not delete `geom_publisher.py`.
All run from `gui/`.
```
-make run # build frontend, run the Go host on :8085
+make run # regenerate proto, build frontend, run the Go host on :8085
make test # frontend check/lint/format + go test -race, all packages
make install # go install after a frontend build
-make proto # buf generate: needs network, never run from a sandboxed build
-make clean # wipe dist/ and the frontend-build sentinel
+make proto # regenerate internal/{vision,gamecontroller} and frontend/src/proto
+make clean # wipe dist/, internal/{vision,gamecontroller}, frontend/src/proto
```
+`proto` (and by extension `run`/`test`/`install`, which all depend on it)
+needs `git submodule update --init` to have been run at least once, but no
+network beyond that: `buf generate`'s two plugins are both local, not
+buf.build remotes. Not using `nix develop`? You need `buf` itself, plus:
+`go get -tool google.golang.org/protobuf/cmd/protoc-gen-go` (records the
+version in `go.mod`; already a direct dependency so this needs no extra
+network fetch) and `npm ci` in `frontend/` (installs `@bufbuild/protoc-gen-es`
+from `package.json`).
+
```
cd frontend && npm run dev # Vite HMR on :5173, proxies /api and /ws to :8085
```
@@ -35,9 +44,10 @@ internal/
hub/ topic pub/sub + the /ws handler
snapshot/ debug image listing/serving
logging/ slog setup: tint console + lumberjack file
- vision/ generated Go protobuf (DO NOT EDIT, see buf.gen.yaml)
- gamecontroller/ generated Go protobuf
+ vision/ generated Go protobuf, not committed -- run `make proto` (DO NOT EDIT)
+ gamecontroller/ generated Go protobuf, not committed
frontend/ Svelte 5 + TypeScript + Vite, embedded via //go:embed
+ (src/proto/ is generated, not committed)
buf.gen.yaml generates both internal/{vision,gamecontroller} and
frontend/src/proto from ../proto/proto (the submodule, read
directly -- no vendored copy)
@@ -116,10 +126,22 @@ it working immediately; move it if/when `internal/config` exists.
**buf reads the proto submodule directly**: `inputs: [{directory:
../proto/proto}]` in `buf.gen.yaml`. No vendored copy to drift. Generated
-output is committed (Nix builds are sandboxed/offline, so `make proto` cannot
-run inside one); `gui/frontend/dist/.gitkeep` exists for the same reason on
-the frontend side -- `//go:embed` fails to compile if `dist/` doesn't exist,
-so a fresh clone with no `npm run build` yet must still be able to `go test`.
+output (`internal/vision`, `internal/gamecontroller`, `frontend/src/proto`) is
+*not* committed -- `buf.gen.yaml`'s plugins are both `local:` (`go tool
+protoc-gen-go`; `frontend/node_modules/.bin/protoc-gen-es`), not buf.build
+remotes, so `make proto` needs no network beyond the already-checked-out
+`proto/` submodule and runs as an ordinary Makefile prerequisite (a `.proto`
+sentinel, same technique as `.frontend` below) rather than a separate manual
+step. This used to be committed when the plugins were remote (buf.build
+codegen calls, real network dependency); switching to local plugins removed
+the reason to.
+
+`gui/frontend/dist/.gitkeep` exists for a similar but distinct reason on the
+frontend side -- `//go:embed` fails to compile if `dist/` doesn't exist, so a
+fresh clone with no `npm run build` yet must still be able to `go test`. That
+one stays committed: `dist/` is the frontend's actual build *output*, not
+codegen from a source of truth already in the tree, so there's nothing to
+regenerate it from without first running the build it's the output of.
**Discovery is multicast-announce-based, config is host-owned** -- both
still unimplemented; see below.
diff --git a/gui/Makefile b/gui/Makefile
index bbbdab8..bbf09eb 100644
--- a/gui/Makefile
+++ b/gui/Makefile
@@ -6,21 +6,39 @@ GO_PACKAGES = ./cmd/... ./internal/... ./frontend
FRONTEND_SOURCES = $(shell find frontend -type f \
-not -path "frontend/node_modules/*" \
- -not -path "frontend/dist/*")
+ -not -path "frontend/dist/*" \
+ -not -path "frontend/src/proto/*")
+
+PROTO_SOURCES = $(shell find ../proto/proto -type f 2>/dev/null)
.PHONY: all frontend install test run proto clean
all: install
+# Sentinel file: internal/vision, internal/gamecontroller and
+# frontend/src/proto are generated, not committed (see buf.gen.yaml and
+# .gitignore), so every Go and frontend target needs this to have run first.
+# Both of buf.gen.yaml's plugins are local (go tool protoc-gen-go;
+# frontend/node_modules/.bin/protoc-gen-es), so this needs no network beyond
+# the already-checked-out proto/ submodule -- npm ci runs first only to make
+# sure the protoc-gen-es binary exists before buf calls it.
+.proto: buf.gen.yaml go.mod $(PROTO_SOURCES)
+ cd frontend && npm ci
+ buf generate
+ touch .proto
+
+proto: .proto
+
# Sentinel file, so npm reruns only when a frontend source is newer than the
# last build. //go:embed resolves at compile time, which is why every Go target
-# below depends on this.
+# below depends on this. Depends on .proto first: the build imports the
+# generated frontend/src/proto types.
#
# `npm run build` empties dist/ first (Vite's emptyOutDir), which deletes
# dist/.gitkeep along with any stale output. Restore it every time, or a build
# run before a commit silently drops the tracked sentinel a fresh clone needs.
-.frontend: $(FRONTEND_SOURCES)
- cd frontend && npm ci && npm run build
+.frontend: .proto $(FRONTEND_SOURCES)
+ cd frontend && npm run build
touch frontend/dist/.gitkeep
touch .frontend
@@ -36,12 +54,7 @@ test: frontend
run: frontend
go run ./cmd/$(BINARY)
-# Regenerates Go and TypeScript protobuf bindings. Needs network access for
-# buf's remote plugins, so it never runs as part of a build.
-proto:
- buf generate
-
clean:
- rm -rf frontend/dist .frontend
+ rm -rf frontend/dist frontend/src/proto internal/vision internal/gamecontroller .frontend .proto
mkdir -p frontend/dist
touch frontend/dist/.gitkeep
diff --git a/gui/buf.gen.yaml b/gui/buf.gen.yaml
index dac8bde..aa906a7 100644
--- a/gui/buf.gen.yaml
+++ b/gui/buf.gen.yaml
@@ -20,8 +20,13 @@ managed:
- file_option: go_package_prefix
value: github.com/RoboCup-SSL/ssl-vision-processor/gui/internal
+# Local plugins, not buf.build remotes: generation needs no network beyond the
+# already-checked-out proto/ submodule. Versions come from go.mod's `tool`
+# directive and frontend/package.json's devDependency, not a pin here, so
+# generated code never drifts from whatever protobuf runtime version the rest
+# of the code actually builds against.
plugins:
- - remote: buf.build/protocolbuffers/go:v1.36.6
+ - local: [go, tool, protoc-gen-go]
out: internal
opt:
- paths=source_relative
@@ -29,7 +34,7 @@ plugins:
# json_types emits the canonical protojson shape of each message, which is
# what the Go side sends over the wire. 64-bit fields come out as strings
# there, and these types say so.
- - remote: buf.build/bufbuild/es:v2.2.5
+ - local: ./frontend/node_modules/.bin/protoc-gen-es
out: frontend/src/proto
opt:
- target=ts
diff --git a/gui/frontend/README.md b/gui/frontend/README.md
index 40ca3ef..3071a21 100644
--- a/gui/frontend/README.md
+++ b/gui/frontend/README.md
@@ -13,7 +13,8 @@ Two options:
```
# Standalone dev server with HMR (proxies /api and /ws to the Go host on :8085)
-cd gui/frontend
+cd gui && make proto # regenerates src/proto -- not committed to git, see gui/CLAUDE.md
+cd frontend
npm install
npm run dev
```
diff --git a/gui/frontend/package-lock.json b/gui/frontend/package-lock.json
index 4d4b690..3aa8502 100644
--- a/gui/frontend/package-lock.json
+++ b/gui/frontend/package-lock.json
@@ -11,6 +11,7 @@
"@bufbuild/protobuf": "^2.14.1"
},
"devDependencies": {
+ "@bufbuild/protoc-gen-es": "^2.14.1",
"@eslint/js": "^10.0.1",
"@sveltejs/vite-plugin-svelte": "^7.1.2",
"@tsconfig/svelte": "^5.0.8",
@@ -30,11 +31,62 @@
}
},
"node_modules/@bufbuild/protobuf": {
- "version": "2.14.1",
- "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.14.1.tgz",
- "integrity": "sha512-agRJn3+EJDUe8AvxTx/LnHA/GErvLE62pSaSk7+MwFOtOv8eWBu/qCq2qoZjBjVZ3C2aiFJCveuSs17KMkYGOw==",
+ "version": "2.15.0",
+ "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.15.0.tgz",
+ "integrity": "sha512-DAheWUkVr/SJTWCc+lg9dhY0eN4SaWlf4+bG1KzHeXbnqt0AfB/NX0Z+VunGlM1ki1B4zVvye27MpKh/svySUA==",
"license": "(Apache-2.0 AND BSD-3-Clause)"
},
+ "node_modules/@bufbuild/protoc-gen-es": {
+ "version": "2.15.0",
+ "resolved": "https://registry.npmjs.org/@bufbuild/protoc-gen-es/-/protoc-gen-es-2.15.0.tgz",
+ "integrity": "sha512-FRhNTAZEXW6arWx2JxgtpuazhmewYctXugu5SfXGpXpLLCInDT1005fSKDzEM/70Es2oIn07PM4RvpwvDvR/fg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@bufbuild/protobuf": "2.15.0",
+ "@bufbuild/protoplugin": "2.15.0"
+ },
+ "bin": {
+ "protoc-gen-es": "bin/protoc-gen-es"
+ },
+ "engines": {
+ "node": ">=22"
+ },
+ "peerDependencies": {
+ "@bufbuild/protobuf": "2.15.0"
+ },
+ "peerDependenciesMeta": {
+ "@bufbuild/protobuf": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@bufbuild/protoplugin": {
+ "version": "2.15.0",
+ "resolved": "https://registry.npmjs.org/@bufbuild/protoplugin/-/protoplugin-2.15.0.tgz",
+ "integrity": "sha512-vZhRoqB/jTHATqItRvJQf1zbxdrGRRhiusGty4+lKcfEFODG0PMXky2Ezv4WHHS6oSxq+5qShITuE7K1/82SuQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@bufbuild/protobuf": "2.15.0",
+ "@typescript/vfs": "^1.6.2",
+ "typescript": "5.4.5"
+ }
+ },
+ "node_modules/@bufbuild/protoplugin/node_modules/typescript": {
+ "version": "5.4.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
+ "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
"node_modules/@emnapi/core": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
@@ -922,6 +974,19 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
+ "node_modules/@typescript/vfs": {
+ "version": "1.6.5",
+ "resolved": "https://registry.npmjs.org/@typescript/vfs/-/vfs-1.6.5.tgz",
+ "integrity": "sha512-gobLHQLmvQGJInFk31NvgMd1uYzRXsd8qgnOssyLD055R2QPnw1ubRbBQ4+T+5qC7IQVuYXdvNDE2G7tMDVHgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.3"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ }
+ },
"node_modules/acorn": {
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
diff --git a/gui/frontend/package.json b/gui/frontend/package.json
index 57596b1..59a8072 100644
--- a/gui/frontend/package.json
+++ b/gui/frontend/package.json
@@ -13,6 +13,7 @@
"format:check": "prettier --check ."
},
"devDependencies": {
+ "@bufbuild/protoc-gen-es": "^2.14.1",
"@eslint/js": "^10.0.1",
"@sveltejs/vite-plugin-svelte": "^7.1.2",
"@tsconfig/svelte": "^5.0.8",
diff --git a/gui/frontend/src/proto/gamecontroller/ssl_gc_common_pb.ts b/gui/frontend/src/proto/gamecontroller/ssl_gc_common_pb.ts
deleted file mode 100644
index bb16105..0000000
--- a/gui/frontend/src/proto/gamecontroller/ssl_gc_common_pb.ts
+++ /dev/null
@@ -1,139 +0,0 @@
-// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
-// @generated from file gamecontroller/ssl_gc_common.proto (syntax proto2)
-/* eslint-disable */
-
-import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
-import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
-import type { Message } from "@bufbuild/protobuf";
-
-/**
- * Describes the file gamecontroller/ssl_gc_common.proto.
- */
-export const file_gamecontroller_ssl_gc_common: GenFile = /*@__PURE__*/
- fileDesc("CiJnYW1lY29udHJvbGxlci9zc2xfZ2NfY29tbW9uLnByb3RvIioKB1JvYm90SWQSCgoCaWQYASABKA0SEwoEdGVhbRgCIAEoDjIFLlRlYW0qKQoEVGVhbRILCgdVTktOT1dOEAASCgoGWUVMTE9XEAESCAoEQkxVRRACKjEKCERpdmlzaW9uEg8KC0RJVl9VTktOT1dOEAASCQoFRElWX0EQARIJCgVESVZfQhACQl1CEFNzbEdjQ29tbW9uUHJvdG9QAVpHZ2l0aHViLmNvbS9Sb2JvQ3VwLVNTTC9zc2wtdmlzaW9uLXByb2Nlc3Nvci9ndWkvaW50ZXJuYWwvZ2FtZWNvbnRyb2xsZXI");
-
-/**
- * RobotId is the combination of a team and a robot id
- *
- * @generated from message RobotId
- */
-export type RobotId = Message<"RobotId"> & {
- /**
- * the robot number
- *
- * @generated from field: optional uint32 id = 1;
- */
- id: number;
-
- /**
- * the team that the robot belongs to
- *
- * @generated from field: optional Team team = 2;
- */
- team: Team;
-};
-
-/**
- * RobotId is the combination of a team and a robot id
- *
- * @generated from message RobotId
- */
-export type RobotIdJson = {
- /**
- * the robot number
- *
- * @generated from field: optional uint32 id = 1;
- */
- id?: number;
-
- /**
- * the team that the robot belongs to
- *
- * @generated from field: optional Team team = 2;
- */
- team?: TeamJson;
-};
-
-/**
- * Describes the message RobotId.
- * Use `create(RobotIdSchema)` to create a new message.
- */
-export const RobotIdSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_common, 0);
-
-/**
- * Team is either blue or yellow
- *
- * @generated from enum Team
- */
-export enum Team {
- /**
- * team not set
- *
- * @generated from enum value: UNKNOWN = 0;
- */
- UNKNOWN = 0,
-
- /**
- * yellow team
- *
- * @generated from enum value: YELLOW = 1;
- */
- YELLOW = 1,
-
- /**
- * blue team
- *
- * @generated from enum value: BLUE = 2;
- */
- BLUE = 2,
-}
-
-/**
- * Team is either blue or yellow
- *
- * @generated from enum Team
- */
-export type TeamJson = "UNKNOWN" | "YELLOW" | "BLUE";
-
-/**
- * Describes the enum Team.
- */
-export const TeamSchema: GenEnum = /*@__PURE__*/
- enumDesc(file_gamecontroller_ssl_gc_common, 0);
-
-/**
- * Division denotes the current division, which influences some rules
- *
- * @generated from enum Division
- */
-export enum Division {
- /**
- * @generated from enum value: DIV_UNKNOWN = 0;
- */
- DIV_UNKNOWN = 0,
-
- /**
- * @generated from enum value: DIV_A = 1;
- */
- DIV_A = 1,
-
- /**
- * @generated from enum value: DIV_B = 2;
- */
- DIV_B = 2,
-}
-
-/**
- * Division denotes the current division, which influences some rules
- *
- * @generated from enum Division
- */
-export type DivisionJson = "DIV_UNKNOWN" | "DIV_A" | "DIV_B";
-
-/**
- * Describes the enum Division.
- */
-export const DivisionSchema: GenEnum = /*@__PURE__*/
- enumDesc(file_gamecontroller_ssl_gc_common, 1);
-
diff --git a/gui/frontend/src/proto/gamecontroller/ssl_gc_game_event_pb.ts b/gui/frontend/src/proto/gamecontroller/ssl_gc_game_event_pb.ts
deleted file mode 100644
index 4666b62..0000000
--- a/gui/frontend/src/proto/gamecontroller/ssl_gc_game_event_pb.ts
+++ /dev/null
@@ -1,3850 +0,0 @@
-// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
-// @generated from file gamecontroller/ssl_gc_game_event.proto (syntax proto2)
-/* eslint-disable */
-
-import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
-import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
-import type { Team, TeamJson } from "./ssl_gc_common_pb";
-import { file_gamecontroller_ssl_gc_common } from "./ssl_gc_common_pb";
-import type { Vector2, Vector2Json } from "./ssl_gc_geometry_pb";
-import { file_gamecontroller_ssl_gc_geometry } from "./ssl_gc_geometry_pb";
-import type { Message } from "@bufbuild/protobuf";
-
-/**
- * Describes the file gamecontroller/ssl_gc_game_event.proto.
- */
-export const file_gamecontroller_ssl_gc_game_event: GenFile = /*@__PURE__*/
- fileDesc("CiZnYW1lY29udHJvbGxlci9zc2xfZ2NfZ2FtZV9ldmVudC5wcm90byKFQwoJR2FtZUV2ZW50EgoKAmlkGDIgASgJEh0KBHR5cGUYKCABKA4yDy5HYW1lRXZlbnQuVHlwZRIOCgZvcmlnaW4YKSADKAkSGQoRY3JlYXRlZF90aW1lc3RhbXAYMSABKAQSPgoaYmFsbF9sZWZ0X2ZpZWxkX3RvdWNoX2xpbmUYBiABKAsyGC5HYW1lRXZlbnQuQmFsbExlZnRGaWVsZEgAEj0KGWJhbGxfbGVmdF9maWVsZF9nb2FsX2xpbmUYByABKAsyGC5HYW1lRXZlbnQuQmFsbExlZnRGaWVsZEgAEi4KDGFpbWxlc3Nfa2ljaxgLIAEoCzIWLkdhbWVFdmVudC5BaW1sZXNzS2lja0gAElYKImF0dGFja2VyX3Rvb19jbG9zZV90b19kZWZlbnNlX2FyZWEYEyABKAsyKC5HYW1lRXZlbnQuQXR0YWNrZXJUb29DbG9zZVRvRGVmZW5zZUFyZWFIABJEChhkZWZlbmRlcl9pbl9kZWZlbnNlX2FyZWEYHyABKAsyIC5HYW1lRXZlbnQuRGVmZW5kZXJJbkRlZmVuc2VBcmVhSAASOAoRYm91bmRhcnlfY3Jvc3NpbmcYKyABKAsyGy5HYW1lRXZlbnQuQm91bmRhcnlDcm9zc2luZ0gAEjUKEGtlZXBlcl9oZWxkX2JhbGwYDSABKAsyGS5HYW1lRXZlbnQuS2VlcGVySGVsZEJhbGxIABJFChlib3RfZHJpYmJsZWRfYmFsbF90b29fZmFyGBEgASgLMiAuR2FtZUV2ZW50LkJvdERyaWJibGVkQmFsbFRvb0ZhckgAEjEKDmJvdF9wdXNoZWRfYm90GBggASgLMhcuR2FtZUV2ZW50LkJvdFB1c2hlZEJvdEgAEkgKGmJvdF9oZWxkX2JhbGxfZGVsaWJlcmF0ZWx5GBogASgLMiIuR2FtZUV2ZW50LkJvdEhlbGRCYWxsRGVsaWJlcmF0ZWx5SAASMwoPYm90X3RpcHBlZF9vdmVyGBsgASgLMhguR2FtZUV2ZW50LkJvdFRpcHBlZE92ZXJIABI3ChFib3RfZHJvcHBlZF9wYXJ0cxgzIAEoCzIaLkdhbWVFdmVudC5Cb3REcm9wcGVkUGFydHNIABJcCiVhdHRhY2tlcl90b3VjaGVkX2JhbGxfaW5fZGVmZW5zZV9hcmVhGA8gASgLMisuR2FtZUV2ZW50LkF0dGFja2VyVG91Y2hlZEJhbGxJbkRlZmVuc2VBcmVhSAASQwoYYm90X2tpY2tlZF9iYWxsX3Rvb19mYXN0GBIgASgLMh8uR2FtZUV2ZW50LkJvdEtpY2tlZEJhbGxUb29GYXN0SAASNQoQYm90X2NyYXNoX3VuaXF1ZRgWIAEoCzIZLkdhbWVFdmVudC5Cb3RDcmFzaFVuaXF1ZUgAEjMKD2JvdF9jcmFzaF9kcmF3bhgVIAEoCzIYLkdhbWVFdmVudC5Cb3RDcmFzaERyYXduSAASUgogZGVmZW5kZXJfdG9vX2Nsb3NlX3RvX2tpY2tfcG9pbnQYHSABKAsyJi5HYW1lRXZlbnQuRGVmZW5kZXJUb29DbG9zZVRvS2lja1BvaW50SAASOwoUYm90X3Rvb19mYXN0X2luX3N0b3AYHCABKAsyGy5HYW1lRXZlbnQuQm90VG9vRmFzdEluU3RvcEgAEkUKGGJvdF9pbnRlcmZlcmVkX3BsYWNlbWVudBgUIAEoCzIhLkdhbWVFdmVudC5Cb3RJbnRlcmZlcmVkUGxhY2VtZW50SAASKAoNcG9zc2libGVfZ29hbBgnIAEoCzIPLkdhbWVFdmVudC5Hb2FsSAASHwoEZ29hbBgIIAEoCzIPLkdhbWVFdmVudC5Hb2FsSAASJwoMaW52YWxpZF9nb2FsGCwgASgLMg8uR2FtZUV2ZW50LkdvYWxIABJMChxhdHRhY2tlcl9kb3VibGVfdG91Y2hlZF9iYWxsGA4gASgLMiQuR2FtZUV2ZW50LkF0dGFja2VyRG91YmxlVG91Y2hlZEJhbGxIABI8ChNwbGFjZW1lbnRfc3VjY2VlZGVkGAUgASgLMh0uR2FtZUV2ZW50LlBsYWNlbWVudFN1Y2NlZWRlZEgAEjsKE3BlbmFsdHlfa2lja19mYWlsZWQYLSABKAsyHC5HYW1lRXZlbnQuUGVuYWx0eUtpY2tGYWlsZWRIABI6ChNub19wcm9ncmVzc19pbl9nYW1lGAIgASgLMhsuR2FtZUV2ZW50Lk5vUHJvZ3Jlc3NJbkdhbWVIABI2ChBwbGFjZW1lbnRfZmFpbGVkGAMgASgLMhouR2FtZUV2ZW50LlBsYWNlbWVudEZhaWxlZEgAEjIKDm11bHRpcGxlX2NhcmRzGCAgASgLMhguR2FtZUV2ZW50Lk11bHRpcGxlQ2FyZHNIABIyCg5tdWx0aXBsZV9mb3VscxgiIAEoCzIYLkdhbWVFdmVudC5NdWx0aXBsZUZvdWxzSAASNgoQYm90X3N1YnN0aXR1dGlvbhglIAEoCzIaLkdhbWVFdmVudC5Cb3RTdWJzdGl0dXRpb25IABJJChpleGNlc3NpdmVfYm90X3N1YnN0aXR1dGlvbhg0IAEoCzIjLkdhbWVFdmVudC5FeGNlc3NpdmVCb3RTdWJzdGl0dXRpb25IABIzCg90b29fbWFueV9yb2JvdHMYJiABKAsyGC5HYW1lRXZlbnQuVG9vTWFueVJvYm90c0gAEjIKDmNoYWxsZW5nZV9mbGFnGC4gASgLMhguR2FtZUV2ZW50LkNoYWxsZW5nZUZsYWdIABJBChZjaGFsbGVuZ2VfZmxhZ19oYW5kbGVkGDAgASgLMh8uR2FtZUV2ZW50LkNoYWxsZW5nZUZsYWdIYW5kbGVkSAASMgoOZW1lcmdlbmN5X3N0b3AYLyABKAsyGC5HYW1lRXZlbnQuRW1lcmdlbmN5U3RvcEgAEkcKGXVuc3BvcnRpbmdfYmVoYXZpb3JfbWlub3IYIyABKAsyIi5HYW1lRXZlbnQuVW5zcG9ydGluZ0JlaGF2aW9yTWlub3JIABJHChl1bnNwb3J0aW5nX2JlaGF2aW9yX21ham9yGCQgASgLMiIuR2FtZUV2ZW50LlVuc3BvcnRpbmdCZWhhdmlvck1ham9ySAASKwoIcHJlcGFyZWQYASABKAsyEy5HYW1lRXZlbnQuUHJlcGFyZWRCAhgBSAASNAoNaW5kaXJlY3RfZ29hbBgJIAEoCzIXLkdhbWVFdmVudC5JbmRpcmVjdEdvYWxCAhgBSAASMgoMY2hpcHBlZF9nb2FsGAogASgLMhYuR2FtZUV2ZW50LkNoaXBwZWRHb2FsQgIYAUgAEjIKDGtpY2tfdGltZW91dBgMIAEoCzIWLkdhbWVFdmVudC5LaWNrVGltZW91dEICGAFIABJoCilhdHRhY2tlcl90b3VjaGVkX29wcG9uZW50X2luX2RlZmVuc2VfYXJlYRgQIAEoCzIvLkdhbWVFdmVudC5BdHRhY2tlclRvdWNoZWRPcHBvbmVudEluRGVmZW5zZUFyZWFCAhgBSAAScAoxYXR0YWNrZXJfdG91Y2hlZF9vcHBvbmVudF9pbl9kZWZlbnNlX2FyZWFfc2tpcHBlZBgqIAEoCzIvLkdhbWVFdmVudC5BdHRhY2tlclRvdWNoZWRPcHBvbmVudEluRGVmZW5zZUFyZWFCAhgBSAASQQoYYm90X2NyYXNoX3VuaXF1ZV9za2lwcGVkGBcgASgLMhkuR2FtZUV2ZW50LkJvdENyYXNoVW5pcXVlQgIYAUgAEj0KFmJvdF9wdXNoZWRfYm90X3NraXBwZWQYGSABKAsyFy5HYW1lRXZlbnQuQm90UHVzaGVkQm90QgIYAUgAElsKImRlZmVuZGVyX2luX2RlZmVuc2VfYXJlYV9wYXJ0aWFsbHkYHiABKAsyKS5HYW1lRXZlbnQuRGVmZW5kZXJJbkRlZmVuc2VBcmVhUGFydGlhbGx5QgIYAUgAEk8KG211bHRpcGxlX3BsYWNlbWVudF9mYWlsdXJlcxghIAEoCzIkLkdhbWVFdmVudC5NdWx0aXBsZVBsYWNlbWVudEZhaWx1cmVzQgIYAUgAGlMKDUJhbGxMZWZ0RmllbGQSFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhpyCgtBaW1sZXNzS2ljaxIWCgdieV90ZWFtGAEgAigOMgUuVGVhbRIOCgZieV9ib3QYAiABKA0SGgoIbG9jYXRpb24YAyABKAsyCC5WZWN0b3IyEh8KDWtpY2tfbG9jYXRpb24YBCABKAsyCC5WZWN0b3IyGu8BCgRHb2FsEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEhsKDGtpY2tpbmdfdGVhbRgGIAEoDjIFLlRlYW0SEwoLa2lja2luZ19ib3QYAiABKA0SGgoIbG9jYXRpb24YAyABKAsyCC5WZWN0b3IyEh8KDWtpY2tfbG9jYXRpb24YBCABKAsyCC5WZWN0b3IyEhcKD21heF9iYWxsX2hlaWdodBgFIAEoAhIaChJudW1fcm9ib3RzX2J5X3RlYW0YByABKA0SGgoSbGFzdF90b3VjaF9ieV90ZWFtGAggASgEEg8KB21lc3NhZ2UYCSABKAkacwoMSW5kaXJlY3RHb2FsEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEg4KBmJ5X2JvdBgCIAEoDRIaCghsb2NhdGlvbhgDIAEoCzIILlZlY3RvcjISHwoNa2lja19sb2NhdGlvbhgEIAEoCzIILlZlY3RvcjIaiwEKC0NoaXBwZWRHb2FsEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEg4KBmJ5X2JvdBgCIAEoDRIaCghsb2NhdGlvbhgDIAEoCzIILlZlY3RvcjISHwoNa2lja19sb2NhdGlvbhgEIAEoCzIILlZlY3RvcjISFwoPbWF4X2JhbGxfaGVpZ2h0GAUgASgCGmUKEEJvdFRvb0Zhc3RJblN0b3ASFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhINCgVzcGVlZBgEIAEoAhpzChtEZWZlbmRlclRvb0Nsb3NlVG9LaWNrUG9pbnQSFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhIQCghkaXN0YW5jZRgEIAEoAhqPAQoNQm90Q3Jhc2hEcmF3bhISCgpib3RfeWVsbG93GAEgASgNEhAKCGJvdF9ibHVlGAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhITCgtjcmFzaF9zcGVlZBgEIAEoAhISCgpzcGVlZF9kaWZmGAUgASgCEhMKC2NyYXNoX2FuZ2xlGAYgASgCGqQBCg5Cb3RDcmFzaFVuaXF1ZRIWCgdieV90ZWFtGAEgAigOMgUuVGVhbRIQCgh2aW9sYXRvchgCIAEoDRIOCgZ2aWN0aW0YAyABKA0SGgoIbG9jYXRpb24YBCABKAsyCC5WZWN0b3IyEhMKC2NyYXNoX3NwZWVkGAUgASgCEhIKCnNwZWVkX2RpZmYYBiABKAISEwoLY3Jhc2hfYW5nbGUYByABKAIafQoMQm90UHVzaGVkQm90EhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEhAKCHZpb2xhdG9yGAIgASgNEg4KBnZpY3RpbRgDIAEoDRIaCghsb2NhdGlvbhgEIAEoCzIILlZlY3RvcjISFwoPcHVzaGVkX2Rpc3RhbmNlGAUgASgCGnQKDUJvdFRpcHBlZE92ZXISFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhIfCg1iYWxsX2xvY2F0aW9uGAQgASgLMgguVmVjdG9yMhp2Cg9Cb3REcm9wcGVkUGFydHMSFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhIfCg1iYWxsX2xvY2F0aW9uGAQgASgLMgguVmVjdG9yMhptChVEZWZlbmRlckluRGVmZW5zZUFyZWESFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhIQCghkaXN0YW5jZRgEIAEoAhqXAQoeRGVmZW5kZXJJbkRlZmVuc2VBcmVhUGFydGlhbGx5EhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEg4KBmJ5X2JvdBgCIAEoDRIaCghsb2NhdGlvbhgDIAEoCzIILlZlY3RvcjISEAoIZGlzdGFuY2UYBCABKAISHwoNYmFsbF9sb2NhdGlvbhgFIAEoCzIILlZlY3RvcjIaeAogQXR0YWNrZXJUb3VjaGVkQmFsbEluRGVmZW5zZUFyZWESFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhIQCghkaXN0YW5jZRgEIAEoAhqHAQoUQm90S2lja2VkQmFsbFRvb0Zhc3QSFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhIaChJpbml0aWFsX2JhbGxfc3BlZWQYBCABKAISDwoHY2hpcHBlZBgFIAEoCBpvChVCb3REcmliYmxlZEJhbGxUb29GYXISFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhcKBXN0YXJ0GAMgASgLMgguVmVjdG9yMhIVCgNlbmQYBCABKAsyCC5WZWN0b3IyGnoKJEF0dGFja2VyVG91Y2hlZE9wcG9uZW50SW5EZWZlbnNlQXJlYRIWCgdieV90ZWFtGAEgAigOMgUuVGVhbRIOCgZieV9ib3QYAiABKA0SDgoGdmljdGltGAQgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhpfChlBdHRhY2tlckRvdWJsZVRvdWNoZWRCYWxsEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEg4KBmJ5X2JvdBgCIAEoDRIaCghsb2NhdGlvbhgDIAEoCzIILlZlY3RvcjIalgEKHUF0dGFja2VyVG9vQ2xvc2VUb0RlZmVuc2VBcmVhEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEg4KBmJ5X2JvdBgCIAEoDRIaCghsb2NhdGlvbhgDIAEoCzIILlZlY3RvcjISEAoIZGlzdGFuY2UYBCABKAISHwoNYmFsbF9sb2NhdGlvbhgFIAEoCzIILlZlY3RvcjIabwoXQm90SGVsZEJhbGxEZWxpYmVyYXRlbHkSFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGYnlfYm90GAIgASgNEhoKCGxvY2F0aW9uGAMgASgLMgguVmVjdG9yMhIQCghkdXJhdGlvbhgEIAEoAhpcChZCb3RJbnRlcmZlcmVkUGxhY2VtZW50EhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEg4KBmJ5X2JvdBgCIAEoDRIaCghsb2NhdGlvbhgDIAEoCzIILlZlY3RvcjIaJwoNTXVsdGlwbGVDYXJkcxIWCgdieV90ZWFtGAEgAigOMgUuVGVhbRpPCg1NdWx0aXBsZUZvdWxzEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEiYKEmNhdXNlZF9nYW1lX2V2ZW50cxgCIAMoCzIKLkdhbWVFdmVudBozChlNdWx0aXBsZVBsYWNlbWVudEZhaWx1cmVzEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtGk8KC0tpY2tUaW1lb3V0EhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEhoKCGxvY2F0aW9uGAIgASgLMgguVmVjdG9yMhIMCgR0aW1lGAMgASgCGjwKEE5vUHJvZ3Jlc3NJbkdhbWUSGgoIbG9jYXRpb24YASABKAsyCC5WZWN0b3IyEgwKBHRpbWUYAiABKAIaZwoPUGxhY2VtZW50RmFpbGVkEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEhoKEnJlbWFpbmluZ19kaXN0YW5jZRgCIAEoAhIgChhuZWFyZXN0X293bl9ib3RfZGlzdGFuY2UYAyABKAIaQQoXVW5zcG9ydGluZ0JlaGF2aW9yTWlub3ISFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SDgoGcmVhc29uGAIgAigJGkEKF1Vuc3BvcnRpbmdCZWhhdmlvck1ham9yEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEg4KBnJlYXNvbhgCIAIoCRpWCg5LZWVwZXJIZWxkQmFsbBIWCgdieV90ZWFtGAEgAigOMgUuVGVhbRIaCghsb2NhdGlvbhgCIAEoCzIILlZlY3RvcjISEAoIZHVyYXRpb24YAyABKAIaZQoSUGxhY2VtZW50U3VjY2VlZGVkEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEhIKCnRpbWVfdGFrZW4YAiABKAISEQoJcHJlY2lzaW9uGAMgASgCEhAKCGRpc3RhbmNlGAQgASgCGh4KCFByZXBhcmVkEhIKCnRpbWVfdGFrZW4YASABKAIaKQoPQm90U3Vic3RpdHV0aW9uEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtGjIKGEV4Y2Vzc2l2ZUJvdFN1YnN0aXR1dGlvbhIWCgdieV90ZWFtGAEgAigOMgUuVGVhbRonCg1DaGFsbGVuZ2VGbGFnEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtGkAKFENoYWxsZW5nZUZsYWdIYW5kbGVkEhYKB2J5X3RlYW0YASACKA4yBS5UZWFtEhAKCGFjY2VwdGVkGAIgAigIGicKDUVtZXJnZW5jeVN0b3ASFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0agQEKDVRvb01hbnlSb2JvdHMSFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SGgoSbnVtX3JvYm90c19hbGxvd2VkGAIgASgFEhsKE251bV9yb2JvdHNfb25fZmllbGQYAyABKAUSHwoNYmFsbF9sb2NhdGlvbhgEIAEoCzIILlZlY3RvcjIaRgoQQm91bmRhcnlDcm9zc2luZxIWCgdieV90ZWFtGAEgAigOMgUuVGVhbRIaCghsb2NhdGlvbhgCIAEoCzIILlZlY3RvcjIaVwoRUGVuYWx0eUtpY2tGYWlsZWQSFgoHYnlfdGVhbRgBIAIoDjIFLlRlYW0SGgoIbG9jYXRpb24YAiABKAsyCC5WZWN0b3IyEg4KBnJlYXNvbhgDIAEoCSK1CgoEVHlwZRIbChdVTktOT1dOX0dBTUVfRVZFTlRfVFlQRRAAEh4KGkJBTExfTEVGVF9GSUVMRF9UT1VDSF9MSU5FEAYSHQoZQkFMTF9MRUZUX0ZJRUxEX0dPQUxfTElORRAHEhAKDEFJTUxFU1NfS0lDSxALEiYKIkFUVEFDS0VSX1RPT19DTE9TRV9UT19ERUZFTlNFX0FSRUEQExIcChhERUZFTkRFUl9JTl9ERUZFTlNFX0FSRUEQHxIVChFCT1VOREFSWV9DUk9TU0lORxApEhQKEEtFRVBFUl9IRUxEX0JBTEwQDRIdChlCT1RfRFJJQkJMRURfQkFMTF9UT09fRkFSEBESEgoOQk9UX1BVU0hFRF9CT1QQGBIeChpCT1RfSEVMRF9CQUxMX0RFTElCRVJBVEVMWRAaEhMKD0JPVF9USVBQRURfT1ZFUhAbEhUKEUJPVF9EUk9QUEVEX1BBUlRTEC8SKQolQVRUQUNLRVJfVE9VQ0hFRF9CQUxMX0lOX0RFRkVOU0VfQVJFQRAPEhwKGEJPVF9LSUNLRURfQkFMTF9UT09fRkFTVBASEhQKEEJPVF9DUkFTSF9VTklRVUUQFhITCg9CT1RfQ1JBU0hfRFJBV04QFRIkCiBERUZFTkRFUl9UT09fQ0xPU0VfVE9fS0lDS19QT0lOVBAdEhgKFEJPVF9UT09fRkFTVF9JTl9TVE9QEBwSHAoYQk9UX0lOVEVSRkVSRURfUExBQ0VNRU5UEBQSHgoaRVhDRVNTSVZFX0JPVF9TVUJTVElUVVRJT04QMBIRCg1QT1NTSUJMRV9HT0FMECcSCAoER09BTBAIEhAKDElOVkFMSURfR09BTBAqEiAKHEFUVEFDS0VSX0RPVUJMRV9UT1VDSEVEX0JBTEwQDhIXChNQTEFDRU1FTlRfU1VDQ0VFREVEEAUSFwoTUEVOQUxUWV9LSUNLX0ZBSUxFRBArEhcKE05PX1BST0dSRVNTX0lOX0dBTUUQAhIUChBQTEFDRU1FTlRfRkFJTEVEEAMSEgoOTVVMVElQTEVfQ0FSRFMQIBISCg5NVUxUSVBMRV9GT1VMUxAiEhQKEEJPVF9TVUJTVElUVVRJT04QJRITCg9UT09fTUFOWV9ST0JPVFMQJhISCg5DSEFMTEVOR0VfRkxBRxAsEhoKFkNIQUxMRU5HRV9GTEFHX0hBTkRMRUQQLhISCg5FTUVSR0VOQ1lfU1RPUBAtEh0KGVVOU1BPUlRJTkdfQkVIQVZJT1JfTUlOT1IQIxIdChlVTlNQT1JUSU5HX0JFSEFWSU9SX01BSk9SECQSEAoIUFJFUEFSRUQQARoCCAESFQoNSU5ESVJFQ1RfR09BTBAJGgIIARIUCgxDSElQUEVEX0dPQUwQChoCCAESFAoMS0lDS19USU1FT1VUEAwaAggBEjEKKUFUVEFDS0VSX1RPVUNIRURfT1BQT05FTlRfSU5fREVGRU5TRV9BUkVBEBAaAggBEjkKMUFUVEFDS0VSX1RPVUNIRURfT1BQT05FTlRfSU5fREVGRU5TRV9BUkVBX1NLSVBQRUQQKBoCCAESIAoYQk9UX0NSQVNIX1VOSVFVRV9TS0lQUEVEEBcaAggBEh4KFkJPVF9QVVNIRURfQk9UX1NLSVBQRUQQGRoCCAESKgoiREVGRU5ERVJfSU5fREVGRU5TRV9BUkVBX1BBUlRJQUxMWRAeGgIIARIjChtNVUxUSVBMRV9QTEFDRU1FTlRfRkFJTFVSRVMQIRoCCAFCBwoFZXZlbnRCYEITU3NsR2NHYW1lRXZlbnRQcm90b1ABWkdnaXRodWIuY29tL1JvYm9DdXAtU1NML3NzbC12aXNpb24tcHJvY2Vzc29yL2d1aS9pbnRlcm5hbC9nYW1lY29udHJvbGxlcg", [file_gamecontroller_ssl_gc_common, file_gamecontroller_ssl_gc_geometry]);
-
-/**
- * GameEvent contains exactly one game event
- * Each game event has optional and required fields. The required fields are mandatory to process the event.
- * Some optional fields are only used for visualization, others are required to determine the ball placement position.
- * If fields are missing that are required for the ball placement position, no ball placement command will be issued.
- * Fields are marked optional to make testing and extending of the protocol easier.
- * An autoRef should ideally set all fields, except if there are good reasons to not do so.
- *
- * @generated from message GameEvent
- */
-export type GameEvent = Message<"GameEvent"> & {
- /**
- * A globally unique id of the game event.
- *
- * @generated from field: optional string id = 50;
- */
- id: string;
-
- /**
- * The type of the game event.
- *
- * @generated from field: optional GameEvent.Type type = 40;
- */
- type: GameEvent_Type;
-
- /**
- * The origins of this game event.
- * Empty, if it originates from game controller.
- * Contains autoRef name(s), if it originates from one or more autoRefs.
- * Ignored if sent by autoRef to game controller.
- *
- * @generated from field: repeated string origin = 41;
- */
- origin: string[];
-
- /**
- * Unix timestamp in microseconds when the event was created.
- *
- * @generated from field: optional uint64 created_timestamp = 49;
- */
- createdTimestamp: bigint;
-
- /**
- * the event that occurred
- *
- * @generated from oneof GameEvent.event
- */
- event: {
- /**
- * @generated from field: GameEvent.BallLeftField ball_left_field_touch_line = 6;
- */
- value: GameEvent_BallLeftField;
- case: "ballLeftFieldTouchLine";
- } | {
- /**
- * @generated from field: GameEvent.BallLeftField ball_left_field_goal_line = 7;
- */
- value: GameEvent_BallLeftField;
- case: "ballLeftFieldGoalLine";
- } | {
- /**
- * @generated from field: GameEvent.AimlessKick aimless_kick = 11;
- */
- value: GameEvent_AimlessKick;
- case: "aimlessKick";
- } | {
- /**
- * @generated from field: GameEvent.AttackerTooCloseToDefenseArea attacker_too_close_to_defense_area = 19;
- */
- value: GameEvent_AttackerTooCloseToDefenseArea;
- case: "attackerTooCloseToDefenseArea";
- } | {
- /**
- * @generated from field: GameEvent.DefenderInDefenseArea defender_in_defense_area = 31;
- */
- value: GameEvent_DefenderInDefenseArea;
- case: "defenderInDefenseArea";
- } | {
- /**
- * @generated from field: GameEvent.BoundaryCrossing boundary_crossing = 43;
- */
- value: GameEvent_BoundaryCrossing;
- case: "boundaryCrossing";
- } | {
- /**
- * @generated from field: GameEvent.KeeperHeldBall keeper_held_ball = 13;
- */
- value: GameEvent_KeeperHeldBall;
- case: "keeperHeldBall";
- } | {
- /**
- * @generated from field: GameEvent.BotDribbledBallTooFar bot_dribbled_ball_too_far = 17;
- */
- value: GameEvent_BotDribbledBallTooFar;
- case: "botDribbledBallTooFar";
- } | {
- /**
- * @generated from field: GameEvent.BotPushedBot bot_pushed_bot = 24;
- */
- value: GameEvent_BotPushedBot;
- case: "botPushedBot";
- } | {
- /**
- * @generated from field: GameEvent.BotHeldBallDeliberately bot_held_ball_deliberately = 26;
- */
- value: GameEvent_BotHeldBallDeliberately;
- case: "botHeldBallDeliberately";
- } | {
- /**
- * @generated from field: GameEvent.BotTippedOver bot_tipped_over = 27;
- */
- value: GameEvent_BotTippedOver;
- case: "botTippedOver";
- } | {
- /**
- * @generated from field: GameEvent.BotDroppedParts bot_dropped_parts = 51;
- */
- value: GameEvent_BotDroppedParts;
- case: "botDroppedParts";
- } | {
- /**
- * @generated from field: GameEvent.AttackerTouchedBallInDefenseArea attacker_touched_ball_in_defense_area = 15;
- */
- value: GameEvent_AttackerTouchedBallInDefenseArea;
- case: "attackerTouchedBallInDefenseArea";
- } | {
- /**
- * @generated from field: GameEvent.BotKickedBallTooFast bot_kicked_ball_too_fast = 18;
- */
- value: GameEvent_BotKickedBallTooFast;
- case: "botKickedBallTooFast";
- } | {
- /**
- * @generated from field: GameEvent.BotCrashUnique bot_crash_unique = 22;
- */
- value: GameEvent_BotCrashUnique;
- case: "botCrashUnique";
- } | {
- /**
- * @generated from field: GameEvent.BotCrashDrawn bot_crash_drawn = 21;
- */
- value: GameEvent_BotCrashDrawn;
- case: "botCrashDrawn";
- } | {
- /**
- * @generated from field: GameEvent.DefenderTooCloseToKickPoint defender_too_close_to_kick_point = 29;
- */
- value: GameEvent_DefenderTooCloseToKickPoint;
- case: "defenderTooCloseToKickPoint";
- } | {
- /**
- * @generated from field: GameEvent.BotTooFastInStop bot_too_fast_in_stop = 28;
- */
- value: GameEvent_BotTooFastInStop;
- case: "botTooFastInStop";
- } | {
- /**
- * @generated from field: GameEvent.BotInterferedPlacement bot_interfered_placement = 20;
- */
- value: GameEvent_BotInterferedPlacement;
- case: "botInterferedPlacement";
- } | {
- /**
- * @generated from field: GameEvent.Goal possible_goal = 39;
- */
- value: GameEvent_Goal;
- case: "possibleGoal";
- } | {
- /**
- * @generated from field: GameEvent.Goal goal = 8;
- */
- value: GameEvent_Goal;
- case: "goal";
- } | {
- /**
- * @generated from field: GameEvent.Goal invalid_goal = 44;
- */
- value: GameEvent_Goal;
- case: "invalidGoal";
- } | {
- /**
- * @generated from field: GameEvent.AttackerDoubleTouchedBall attacker_double_touched_ball = 14;
- */
- value: GameEvent_AttackerDoubleTouchedBall;
- case: "attackerDoubleTouchedBall";
- } | {
- /**
- * @generated from field: GameEvent.PlacementSucceeded placement_succeeded = 5;
- */
- value: GameEvent_PlacementSucceeded;
- case: "placementSucceeded";
- } | {
- /**
- * @generated from field: GameEvent.PenaltyKickFailed penalty_kick_failed = 45;
- */
- value: GameEvent_PenaltyKickFailed;
- case: "penaltyKickFailed";
- } | {
- /**
- * @generated from field: GameEvent.NoProgressInGame no_progress_in_game = 2;
- */
- value: GameEvent_NoProgressInGame;
- case: "noProgressInGame";
- } | {
- /**
- * @generated from field: GameEvent.PlacementFailed placement_failed = 3;
- */
- value: GameEvent_PlacementFailed;
- case: "placementFailed";
- } | {
- /**
- * @generated from field: GameEvent.MultipleCards multiple_cards = 32;
- */
- value: GameEvent_MultipleCards;
- case: "multipleCards";
- } | {
- /**
- * @generated from field: GameEvent.MultipleFouls multiple_fouls = 34;
- */
- value: GameEvent_MultipleFouls;
- case: "multipleFouls";
- } | {
- /**
- * @generated from field: GameEvent.BotSubstitution bot_substitution = 37;
- */
- value: GameEvent_BotSubstitution;
- case: "botSubstitution";
- } | {
- /**
- * @generated from field: GameEvent.ExcessiveBotSubstitution excessive_bot_substitution = 52;
- */
- value: GameEvent_ExcessiveBotSubstitution;
- case: "excessiveBotSubstitution";
- } | {
- /**
- * @generated from field: GameEvent.TooManyRobots too_many_robots = 38;
- */
- value: GameEvent_TooManyRobots;
- case: "tooManyRobots";
- } | {
- /**
- * @generated from field: GameEvent.ChallengeFlag challenge_flag = 46;
- */
- value: GameEvent_ChallengeFlag;
- case: "challengeFlag";
- } | {
- /**
- * @generated from field: GameEvent.ChallengeFlagHandled challenge_flag_handled = 48;
- */
- value: GameEvent_ChallengeFlagHandled;
- case: "challengeFlagHandled";
- } | {
- /**
- * @generated from field: GameEvent.EmergencyStop emergency_stop = 47;
- */
- value: GameEvent_EmergencyStop;
- case: "emergencyStop";
- } | {
- /**
- * @generated from field: GameEvent.UnsportingBehaviorMinor unsporting_behavior_minor = 35;
- */
- value: GameEvent_UnsportingBehaviorMinor;
- case: "unsportingBehaviorMinor";
- } | {
- /**
- * @generated from field: GameEvent.UnsportingBehaviorMajor unsporting_behavior_major = 36;
- */
- value: GameEvent_UnsportingBehaviorMajor;
- case: "unsportingBehaviorMajor";
- } | {
- /**
- * replaced by ready_to_continue flag
- *
- * @generated from field: GameEvent.Prepared prepared = 1 [deprecated = true];
- * @deprecated
- */
- value: GameEvent_Prepared;
- case: "prepared";
- } | {
- /**
- * obsolete
- *
- * @generated from field: GameEvent.IndirectGoal indirect_goal = 9 [deprecated = true];
- * @deprecated
- */
- value: GameEvent_IndirectGoal;
- case: "indirectGoal";
- } | {
- /**
- * replaced by the meta-information in the possible_goal event
- *
- * @generated from field: GameEvent.ChippedGoal chipped_goal = 10 [deprecated = true];
- * @deprecated
- */
- value: GameEvent_ChippedGoal;
- case: "chippedGoal";
- } | {
- /**
- * obsolete
- *
- * @generated from field: GameEvent.KickTimeout kick_timeout = 12 [deprecated = true];
- * @deprecated
- */
- value: GameEvent_KickTimeout;
- case: "kickTimeout";
- } | {
- /**
- * rule removed
- *
- * @generated from field: GameEvent.AttackerTouchedOpponentInDefenseArea attacker_touched_opponent_in_defense_area = 16 [deprecated = true];
- * @deprecated
- */
- value: GameEvent_AttackerTouchedOpponentInDefenseArea;
- case: "attackerTouchedOpponentInDefenseArea";
- } | {
- /**
- * obsolete
- *
- * @generated from field: GameEvent.AttackerTouchedOpponentInDefenseArea attacker_touched_opponent_in_defense_area_skipped = 42 [deprecated = true];
- * @deprecated
- */
- value: GameEvent_AttackerTouchedOpponentInDefenseArea;
- case: "attackerTouchedOpponentInDefenseAreaSkipped";
- } | {
- /**
- * obsolete
- *
- * @generated from field: GameEvent.BotCrashUnique bot_crash_unique_skipped = 23 [deprecated = true];
- * @deprecated
- */
- value: GameEvent_BotCrashUnique;
- case: "botCrashUniqueSkipped";
- } | {
- /**
- * can not be used as long as autoRefs do not judge pushing
- *
- * @generated from field: GameEvent.BotPushedBot bot_pushed_bot_skipped = 25 [deprecated = true];
- * @deprecated
- */
- value: GameEvent_BotPushedBot;
- case: "botPushedBotSkipped";
- } | {
- /**
- * rule removed
- *
- * @generated from field: GameEvent.DefenderInDefenseAreaPartially defender_in_defense_area_partially = 30 [deprecated = true];
- * @deprecated
- */
- value: GameEvent_DefenderInDefenseAreaPartially;
- case: "defenderInDefenseAreaPartially";
- } | {
- /**
- * the referee msg already indicates this
- *
- * @generated from field: GameEvent.MultiplePlacementFailures multiple_placement_failures = 33 [deprecated = true];
- * @deprecated
- */
- value: GameEvent_MultiplePlacementFailures;
- case: "multiplePlacementFailures";
- } | { case: undefined; value?: undefined };
-};
-
-/**
- * GameEvent contains exactly one game event
- * Each game event has optional and required fields. The required fields are mandatory to process the event.
- * Some optional fields are only used for visualization, others are required to determine the ball placement position.
- * If fields are missing that are required for the ball placement position, no ball placement command will be issued.
- * Fields are marked optional to make testing and extending of the protocol easier.
- * An autoRef should ideally set all fields, except if there are good reasons to not do so.
- *
- * @generated from message GameEvent
- */
-export type GameEventJson = {
- /**
- * A globally unique id of the game event.
- *
- * @generated from field: optional string id = 50;
- */
- id?: string;
-
- /**
- * The type of the game event.
- *
- * @generated from field: optional GameEvent.Type type = 40;
- */
- type?: GameEvent_TypeJson;
-
- /**
- * The origins of this game event.
- * Empty, if it originates from game controller.
- * Contains autoRef name(s), if it originates from one or more autoRefs.
- * Ignored if sent by autoRef to game controller.
- *
- * @generated from field: repeated string origin = 41;
- */
- origin?: string[];
-
- /**
- * Unix timestamp in microseconds when the event was created.
- *
- * @generated from field: optional uint64 created_timestamp = 49;
- */
- createdTimestamp?: string;
-
- /**
- * @generated from field: GameEvent.BallLeftField ball_left_field_touch_line = 6;
- */
- ballLeftFieldTouchLine?: GameEvent_BallLeftFieldJson;
-
- /**
- * @generated from field: GameEvent.BallLeftField ball_left_field_goal_line = 7;
- */
- ballLeftFieldGoalLine?: GameEvent_BallLeftFieldJson;
-
- /**
- * @generated from field: GameEvent.AimlessKick aimless_kick = 11;
- */
- aimlessKick?: GameEvent_AimlessKickJson;
-
- /**
- * @generated from field: GameEvent.AttackerTooCloseToDefenseArea attacker_too_close_to_defense_area = 19;
- */
- attackerTooCloseToDefenseArea?: GameEvent_AttackerTooCloseToDefenseAreaJson;
-
- /**
- * @generated from field: GameEvent.DefenderInDefenseArea defender_in_defense_area = 31;
- */
- defenderInDefenseArea?: GameEvent_DefenderInDefenseAreaJson;
-
- /**
- * @generated from field: GameEvent.BoundaryCrossing boundary_crossing = 43;
- */
- boundaryCrossing?: GameEvent_BoundaryCrossingJson;
-
- /**
- * @generated from field: GameEvent.KeeperHeldBall keeper_held_ball = 13;
- */
- keeperHeldBall?: GameEvent_KeeperHeldBallJson;
-
- /**
- * @generated from field: GameEvent.BotDribbledBallTooFar bot_dribbled_ball_too_far = 17;
- */
- botDribbledBallTooFar?: GameEvent_BotDribbledBallTooFarJson;
-
- /**
- * @generated from field: GameEvent.BotPushedBot bot_pushed_bot = 24;
- */
- botPushedBot?: GameEvent_BotPushedBotJson;
-
- /**
- * @generated from field: GameEvent.BotHeldBallDeliberately bot_held_ball_deliberately = 26;
- */
- botHeldBallDeliberately?: GameEvent_BotHeldBallDeliberatelyJson;
-
- /**
- * @generated from field: GameEvent.BotTippedOver bot_tipped_over = 27;
- */
- botTippedOver?: GameEvent_BotTippedOverJson;
-
- /**
- * @generated from field: GameEvent.BotDroppedParts bot_dropped_parts = 51;
- */
- botDroppedParts?: GameEvent_BotDroppedPartsJson;
-
- /**
- * @generated from field: GameEvent.AttackerTouchedBallInDefenseArea attacker_touched_ball_in_defense_area = 15;
- */
- attackerTouchedBallInDefenseArea?: GameEvent_AttackerTouchedBallInDefenseAreaJson;
-
- /**
- * @generated from field: GameEvent.BotKickedBallTooFast bot_kicked_ball_too_fast = 18;
- */
- botKickedBallTooFast?: GameEvent_BotKickedBallTooFastJson;
-
- /**
- * @generated from field: GameEvent.BotCrashUnique bot_crash_unique = 22;
- */
- botCrashUnique?: GameEvent_BotCrashUniqueJson;
-
- /**
- * @generated from field: GameEvent.BotCrashDrawn bot_crash_drawn = 21;
- */
- botCrashDrawn?: GameEvent_BotCrashDrawnJson;
-
- /**
- * @generated from field: GameEvent.DefenderTooCloseToKickPoint defender_too_close_to_kick_point = 29;
- */
- defenderTooCloseToKickPoint?: GameEvent_DefenderTooCloseToKickPointJson;
-
- /**
- * @generated from field: GameEvent.BotTooFastInStop bot_too_fast_in_stop = 28;
- */
- botTooFastInStop?: GameEvent_BotTooFastInStopJson;
-
- /**
- * @generated from field: GameEvent.BotInterferedPlacement bot_interfered_placement = 20;
- */
- botInterferedPlacement?: GameEvent_BotInterferedPlacementJson;
-
- /**
- * @generated from field: GameEvent.Goal possible_goal = 39;
- */
- possibleGoal?: GameEvent_GoalJson;
-
- /**
- * @generated from field: GameEvent.Goal goal = 8;
- */
- goal?: GameEvent_GoalJson;
-
- /**
- * @generated from field: GameEvent.Goal invalid_goal = 44;
- */
- invalidGoal?: GameEvent_GoalJson;
-
- /**
- * @generated from field: GameEvent.AttackerDoubleTouchedBall attacker_double_touched_ball = 14;
- */
- attackerDoubleTouchedBall?: GameEvent_AttackerDoubleTouchedBallJson;
-
- /**
- * @generated from field: GameEvent.PlacementSucceeded placement_succeeded = 5;
- */
- placementSucceeded?: GameEvent_PlacementSucceededJson;
-
- /**
- * @generated from field: GameEvent.PenaltyKickFailed penalty_kick_failed = 45;
- */
- penaltyKickFailed?: GameEvent_PenaltyKickFailedJson;
-
- /**
- * @generated from field: GameEvent.NoProgressInGame no_progress_in_game = 2;
- */
- noProgressInGame?: GameEvent_NoProgressInGameJson;
-
- /**
- * @generated from field: GameEvent.PlacementFailed placement_failed = 3;
- */
- placementFailed?: GameEvent_PlacementFailedJson;
-
- /**
- * @generated from field: GameEvent.MultipleCards multiple_cards = 32;
- */
- multipleCards?: GameEvent_MultipleCardsJson;
-
- /**
- * @generated from field: GameEvent.MultipleFouls multiple_fouls = 34;
- */
- multipleFouls?: GameEvent_MultipleFoulsJson;
-
- /**
- * @generated from field: GameEvent.BotSubstitution bot_substitution = 37;
- */
- botSubstitution?: GameEvent_BotSubstitutionJson;
-
- /**
- * @generated from field: GameEvent.ExcessiveBotSubstitution excessive_bot_substitution = 52;
- */
- excessiveBotSubstitution?: GameEvent_ExcessiveBotSubstitutionJson;
-
- /**
- * @generated from field: GameEvent.TooManyRobots too_many_robots = 38;
- */
- tooManyRobots?: GameEvent_TooManyRobotsJson;
-
- /**
- * @generated from field: GameEvent.ChallengeFlag challenge_flag = 46;
- */
- challengeFlag?: GameEvent_ChallengeFlagJson;
-
- /**
- * @generated from field: GameEvent.ChallengeFlagHandled challenge_flag_handled = 48;
- */
- challengeFlagHandled?: GameEvent_ChallengeFlagHandledJson;
-
- /**
- * @generated from field: GameEvent.EmergencyStop emergency_stop = 47;
- */
- emergencyStop?: GameEvent_EmergencyStopJson;
-
- /**
- * @generated from field: GameEvent.UnsportingBehaviorMinor unsporting_behavior_minor = 35;
- */
- unsportingBehaviorMinor?: GameEvent_UnsportingBehaviorMinorJson;
-
- /**
- * @generated from field: GameEvent.UnsportingBehaviorMajor unsporting_behavior_major = 36;
- */
- unsportingBehaviorMajor?: GameEvent_UnsportingBehaviorMajorJson;
-
- /**
- * replaced by ready_to_continue flag
- *
- * @generated from field: GameEvent.Prepared prepared = 1 [deprecated = true];
- * @deprecated
- */
- prepared?: GameEvent_PreparedJson;
-
- /**
- * obsolete
- *
- * @generated from field: GameEvent.IndirectGoal indirect_goal = 9 [deprecated = true];
- * @deprecated
- */
- indirectGoal?: GameEvent_IndirectGoalJson;
-
- /**
- * replaced by the meta-information in the possible_goal event
- *
- * @generated from field: GameEvent.ChippedGoal chipped_goal = 10 [deprecated = true];
- * @deprecated
- */
- chippedGoal?: GameEvent_ChippedGoalJson;
-
- /**
- * obsolete
- *
- * @generated from field: GameEvent.KickTimeout kick_timeout = 12 [deprecated = true];
- * @deprecated
- */
- kickTimeout?: GameEvent_KickTimeoutJson;
-
- /**
- * rule removed
- *
- * @generated from field: GameEvent.AttackerTouchedOpponentInDefenseArea attacker_touched_opponent_in_defense_area = 16 [deprecated = true];
- * @deprecated
- */
- attackerTouchedOpponentInDefenseArea?: GameEvent_AttackerTouchedOpponentInDefenseAreaJson;
-
- /**
- * obsolete
- *
- * @generated from field: GameEvent.AttackerTouchedOpponentInDefenseArea attacker_touched_opponent_in_defense_area_skipped = 42 [deprecated = true];
- * @deprecated
- */
- attackerTouchedOpponentInDefenseAreaSkipped?: GameEvent_AttackerTouchedOpponentInDefenseAreaJson;
-
- /**
- * obsolete
- *
- * @generated from field: GameEvent.BotCrashUnique bot_crash_unique_skipped = 23 [deprecated = true];
- * @deprecated
- */
- botCrashUniqueSkipped?: GameEvent_BotCrashUniqueJson;
-
- /**
- * can not be used as long as autoRefs do not judge pushing
- *
- * @generated from field: GameEvent.BotPushedBot bot_pushed_bot_skipped = 25 [deprecated = true];
- * @deprecated
- */
- botPushedBotSkipped?: GameEvent_BotPushedBotJson;
-
- /**
- * rule removed
- *
- * @generated from field: GameEvent.DefenderInDefenseAreaPartially defender_in_defense_area_partially = 30 [deprecated = true];
- * @deprecated
- */
- defenderInDefenseAreaPartially?: GameEvent_DefenderInDefenseAreaPartiallyJson;
-
- /**
- * the referee msg already indicates this
- *
- * @generated from field: GameEvent.MultiplePlacementFailures multiple_placement_failures = 33 [deprecated = true];
- * @deprecated
- */
- multiplePlacementFailures?: GameEvent_MultiplePlacementFailuresJson;
-};
-
-/**
- * Describes the message GameEvent.
- * Use `create(GameEventSchema)` to create a new message.
- */
-export const GameEventSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0);
-
-/**
- * the ball left the field normally
- *
- * @generated from message GameEvent.BallLeftField
- */
-export type GameEvent_BallLeftField = Message<"GameEvent.BallLeftField"> & {
- /**
- * the team that last touched the ball
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that last touched the ball
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot: number;
-
- /**
- * the location where the ball left the field [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-};
-
-/**
- * the ball left the field normally
- *
- * @generated from message GameEvent.BallLeftField
- */
-export type GameEvent_BallLeftFieldJson = {
- /**
- * the team that last touched the ball
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that last touched the ball
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot?: number;
-
- /**
- * the location where the ball left the field [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-};
-
-/**
- * Describes the message GameEvent.BallLeftField.
- * Use `create(GameEvent_BallLeftFieldSchema)` to create a new message.
- */
-export const GameEvent_BallLeftFieldSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 0);
-
-/**
- * the ball left the field via goal line and a team committed an aimless kick
- *
- * @generated from message GameEvent.AimlessKick
- */
-export type GameEvent_AimlessKick = Message<"GameEvent.AimlessKick"> & {
- /**
- * the team that last touched the ball
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that last touched the ball
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot: number;
-
- /**
- * the location where the ball left the field [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-
- /**
- * the location where the ball was last touched [m]
- *
- * @generated from field: optional Vector2 kick_location = 4;
- */
- kickLocation?: Vector2;
-};
-
-/**
- * the ball left the field via goal line and a team committed an aimless kick
- *
- * @generated from message GameEvent.AimlessKick
- */
-export type GameEvent_AimlessKickJson = {
- /**
- * the team that last touched the ball
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that last touched the ball
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot?: number;
-
- /**
- * the location where the ball left the field [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-
- /**
- * the location where the ball was last touched [m]
- *
- * @generated from field: optional Vector2 kick_location = 4;
- */
- kickLocation?: Vector2Json;
-};
-
-/**
- * Describes the message GameEvent.AimlessKick.
- * Use `create(GameEvent_AimlessKickSchema)` to create a new message.
- */
-export const GameEvent_AimlessKickSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 1);
-
-/**
- * a team shot a goal
- *
- * @generated from message GameEvent.Goal
- */
-export type GameEvent_Goal = Message<"GameEvent.Goal"> & {
- /**
- * the team that scored the goal
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the team that shot the goal (different from by_team for own goals)
- *
- * @generated from field: optional Team kicking_team = 6;
- */
- kickingTeam: Team;
-
- /**
- * the bot that shot the goal
- *
- * @generated from field: optional uint32 kicking_bot = 2;
- */
- kickingBot: number;
-
- /**
- * the location where the ball entered the goal [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-
- /**
- * the location where the ball was kicked (for deciding if this was a valid goal) [m]
- *
- * @generated from field: optional Vector2 kick_location = 4;
- */
- kickLocation?: Vector2;
-
- /**
- * the maximum height the ball reached during the goal kick (for deciding if this was a valid goal) [m]
- *
- * @generated from field: optional float max_ball_height = 5;
- */
- maxBallHeight: number;
-
- /**
- * number of robots of scoring team when the ball entered the goal (for deciding if this was a valid goal)
- *
- * @generated from field: optional uint32 num_robots_by_team = 7;
- */
- numRobotsByTeam: number;
-
- /**
- * The UNIX timestamp [μs] when the scoring team last touched the ball
- *
- * @generated from field: optional uint64 last_touch_by_team = 8;
- */
- lastTouchByTeam: bigint;
-
- /**
- * An additional message with e.g. a reason for invalid goals
- *
- * @generated from field: optional string message = 9;
- */
- message: string;
-};
-
-/**
- * a team shot a goal
- *
- * @generated from message GameEvent.Goal
- */
-export type GameEvent_GoalJson = {
- /**
- * the team that scored the goal
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the team that shot the goal (different from by_team for own goals)
- *
- * @generated from field: optional Team kicking_team = 6;
- */
- kickingTeam?: TeamJson;
-
- /**
- * the bot that shot the goal
- *
- * @generated from field: optional uint32 kicking_bot = 2;
- */
- kickingBot?: number;
-
- /**
- * the location where the ball entered the goal [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-
- /**
- * the location where the ball was kicked (for deciding if this was a valid goal) [m]
- *
- * @generated from field: optional Vector2 kick_location = 4;
- */
- kickLocation?: Vector2Json;
-
- /**
- * the maximum height the ball reached during the goal kick (for deciding if this was a valid goal) [m]
- *
- * @generated from field: optional float max_ball_height = 5;
- */
- maxBallHeight?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * number of robots of scoring team when the ball entered the goal (for deciding if this was a valid goal)
- *
- * @generated from field: optional uint32 num_robots_by_team = 7;
- */
- numRobotsByTeam?: number;
-
- /**
- * The UNIX timestamp [μs] when the scoring team last touched the ball
- *
- * @generated from field: optional uint64 last_touch_by_team = 8;
- */
- lastTouchByTeam?: string;
-
- /**
- * An additional message with e.g. a reason for invalid goals
- *
- * @generated from field: optional string message = 9;
- */
- message?: string;
-};
-
-/**
- * Describes the message GameEvent.Goal.
- * Use `create(GameEvent_GoalSchema)` to create a new message.
- */
-export const GameEvent_GoalSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 2);
-
-/**
- * the ball entered the goal directly during an indirect free kick
- *
- * @generated from message GameEvent.IndirectGoal
- */
-export type GameEvent_IndirectGoal = Message<"GameEvent.IndirectGoal"> & {
- /**
- * the team that tried to shoot the goal
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that kicked the ball - at least the team must be set
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot: number;
-
- /**
- * the location where the ball entered the goal [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-
- /**
- * the location where the ball was kicked [m]
- *
- * @generated from field: optional Vector2 kick_location = 4;
- */
- kickLocation?: Vector2;
-};
-
-/**
- * the ball entered the goal directly during an indirect free kick
- *
- * @generated from message GameEvent.IndirectGoal
- */
-export type GameEvent_IndirectGoalJson = {
- /**
- * the team that tried to shoot the goal
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that kicked the ball - at least the team must be set
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot?: number;
-
- /**
- * the location where the ball entered the goal [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-
- /**
- * the location where the ball was kicked [m]
- *
- * @generated from field: optional Vector2 kick_location = 4;
- */
- kickLocation?: Vector2Json;
-};
-
-/**
- * Describes the message GameEvent.IndirectGoal.
- * Use `create(GameEvent_IndirectGoalSchema)` to create a new message.
- */
-export const GameEvent_IndirectGoalSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 3);
-
-/**
- * the ball entered the goal, but was initially chipped
- *
- * @generated from message GameEvent.ChippedGoal
- */
-export type GameEvent_ChippedGoal = Message<"GameEvent.ChippedGoal"> & {
- /**
- * the team that tried to shoot the goal
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that kicked the ball
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot: number;
-
- /**
- * the location where the ball entered the goal [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-
- /**
- * the location where the ball was kicked [m]
- *
- * @generated from field: optional Vector2 kick_location = 4;
- */
- kickLocation?: Vector2;
-
- /**
- * the maximum height [m] of the ball, before it entered the goal and since the last kick [m]
- *
- * @generated from field: optional float max_ball_height = 5;
- */
- maxBallHeight: number;
-};
-
-/**
- * the ball entered the goal, but was initially chipped
- *
- * @generated from message GameEvent.ChippedGoal
- */
-export type GameEvent_ChippedGoalJson = {
- /**
- * the team that tried to shoot the goal
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that kicked the ball
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot?: number;
-
- /**
- * the location where the ball entered the goal [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-
- /**
- * the location where the ball was kicked [m]
- *
- * @generated from field: optional Vector2 kick_location = 4;
- */
- kickLocation?: Vector2Json;
-
- /**
- * the maximum height [m] of the ball, before it entered the goal and since the last kick [m]
- *
- * @generated from field: optional float max_ball_height = 5;
- */
- maxBallHeight?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message GameEvent.ChippedGoal.
- * Use `create(GameEvent_ChippedGoalSchema)` to create a new message.
- */
-export const GameEvent_ChippedGoalSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 4);
-
-/**
- * a bot moved too fast while the game was stopped
- *
- * @generated from message GameEvent.BotTooFastInStop
- */
-export type GameEvent_BotTooFastInStop = Message<"GameEvent.BotTooFastInStop"> & {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that was too fast
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot: number;
-
- /**
- * the location of the bot [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-
- /**
- * the bot speed [m/s]
- *
- * @generated from field: optional float speed = 4;
- */
- speed: number;
-};
-
-/**
- * a bot moved too fast while the game was stopped
- *
- * @generated from message GameEvent.BotTooFastInStop
- */
-export type GameEvent_BotTooFastInStopJson = {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that was too fast
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot?: number;
-
- /**
- * the location of the bot [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-
- /**
- * the bot speed [m/s]
- *
- * @generated from field: optional float speed = 4;
- */
- speed?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message GameEvent.BotTooFastInStop.
- * Use `create(GameEvent_BotTooFastInStopSchema)` to create a new message.
- */
-export const GameEvent_BotTooFastInStopSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 5);
-
-/**
- * a bot of the defending team got too close to the kick point during a free kick
- *
- * @generated from message GameEvent.DefenderTooCloseToKickPoint
- */
-export type GameEvent_DefenderTooCloseToKickPoint = Message<"GameEvent.DefenderTooCloseToKickPoint"> & {
- /**
- * the team that was found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that violates the distance to the kick point
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot: number;
-
- /**
- * the location of the bot [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-
- /**
- * the distance [m] from bot to the kick point (including the minimum radius)
- *
- * @generated from field: optional float distance = 4;
- */
- distance: number;
-};
-
-/**
- * a bot of the defending team got too close to the kick point during a free kick
- *
- * @generated from message GameEvent.DefenderTooCloseToKickPoint
- */
-export type GameEvent_DefenderTooCloseToKickPointJson = {
- /**
- * the team that was found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that violates the distance to the kick point
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot?: number;
-
- /**
- * the location of the bot [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-
- /**
- * the distance [m] from bot to the kick point (including the minimum radius)
- *
- * @generated from field: optional float distance = 4;
- */
- distance?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message GameEvent.DefenderTooCloseToKickPoint.
- * Use `create(GameEvent_DefenderTooCloseToKickPointSchema)` to create a new message.
- */
-export const GameEvent_DefenderTooCloseToKickPointSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 6);
-
-/**
- * two robots crashed into each other with similar speeds
- *
- * @generated from message GameEvent.BotCrashDrawn
- */
-export type GameEvent_BotCrashDrawn = Message<"GameEvent.BotCrashDrawn"> & {
- /**
- * the bot of the yellow team
- *
- * @generated from field: optional uint32 bot_yellow = 1;
- */
- botYellow: number;
-
- /**
- * the bot of the blue team
- *
- * @generated from field: optional uint32 bot_blue = 2;
- */
- botBlue: number;
-
- /**
- * the location of the crash (center between both bots) [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-
- /**
- * the calculated crash speed [m/s] of the two bots
- *
- * @generated from field: optional float crash_speed = 4;
- */
- crashSpeed: number;
-
- /**
- * the difference [m/s] of the velocity of the two bots
- *
- * @generated from field: optional float speed_diff = 5;
- */
- speedDiff: number;
-
- /**
- * the angle [rad] in the range [0, π] of the bot velocity vectors
- * an angle of 0 rad ( 0°) means, the bots barely touched each other
- * an angle of π rad (180°) means, the bots crashed frontal into each other
- *
- * @generated from field: optional float crash_angle = 6;
- */
- crashAngle: number;
-};
-
-/**
- * two robots crashed into each other with similar speeds
- *
- * @generated from message GameEvent.BotCrashDrawn
- */
-export type GameEvent_BotCrashDrawnJson = {
- /**
- * the bot of the yellow team
- *
- * @generated from field: optional uint32 bot_yellow = 1;
- */
- botYellow?: number;
-
- /**
- * the bot of the blue team
- *
- * @generated from field: optional uint32 bot_blue = 2;
- */
- botBlue?: number;
-
- /**
- * the location of the crash (center between both bots) [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-
- /**
- * the calculated crash speed [m/s] of the two bots
- *
- * @generated from field: optional float crash_speed = 4;
- */
- crashSpeed?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * the difference [m/s] of the velocity of the two bots
- *
- * @generated from field: optional float speed_diff = 5;
- */
- speedDiff?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * the angle [rad] in the range [0, π] of the bot velocity vectors
- * an angle of 0 rad ( 0°) means, the bots barely touched each other
- * an angle of π rad (180°) means, the bots crashed frontal into each other
- *
- * @generated from field: optional float crash_angle = 6;
- */
- crashAngle?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message GameEvent.BotCrashDrawn.
- * Use `create(GameEvent_BotCrashDrawnSchema)` to create a new message.
- */
-export const GameEvent_BotCrashDrawnSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 7);
-
-/**
- * two robots crashed into each other and one team was found guilty to due significant speed difference
- *
- * @generated from message GameEvent.BotCrashUnique
- */
-export type GameEvent_BotCrashUnique = Message<"GameEvent.BotCrashUnique"> & {
- /**
- * the team that caused the crash
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that caused the crash
- *
- * @generated from field: optional uint32 violator = 2;
- */
- violator: number;
-
- /**
- * the bot of the opposite team that was involved in the crash
- *
- * @generated from field: optional uint32 victim = 3;
- */
- victim: number;
-
- /**
- * the location of the crash (center between both bots) [m]
- *
- * @generated from field: optional Vector2 location = 4;
- */
- location?: Vector2;
-
- /**
- * the calculated crash speed vector [m/s] of the two bots
- *
- * @generated from field: optional float crash_speed = 5;
- */
- crashSpeed: number;
-
- /**
- * the difference [m/s] of the velocity of the two bots
- *
- * @generated from field: optional float speed_diff = 6;
- */
- speedDiff: number;
-
- /**
- * the angle [rad] in the range [0, π] of the bot velocity vectors
- * an angle of 0 rad ( 0°) means, the bots barely touched each other
- * an angle of π rad (180°) means, the bots crashed frontal into each other
- *
- * @generated from field: optional float crash_angle = 7;
- */
- crashAngle: number;
-};
-
-/**
- * two robots crashed into each other and one team was found guilty to due significant speed difference
- *
- * @generated from message GameEvent.BotCrashUnique
- */
-export type GameEvent_BotCrashUniqueJson = {
- /**
- * the team that caused the crash
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that caused the crash
- *
- * @generated from field: optional uint32 violator = 2;
- */
- violator?: number;
-
- /**
- * the bot of the opposite team that was involved in the crash
- *
- * @generated from field: optional uint32 victim = 3;
- */
- victim?: number;
-
- /**
- * the location of the crash (center between both bots) [m]
- *
- * @generated from field: optional Vector2 location = 4;
- */
- location?: Vector2Json;
-
- /**
- * the calculated crash speed vector [m/s] of the two bots
- *
- * @generated from field: optional float crash_speed = 5;
- */
- crashSpeed?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * the difference [m/s] of the velocity of the two bots
- *
- * @generated from field: optional float speed_diff = 6;
- */
- speedDiff?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * the angle [rad] in the range [0, π] of the bot velocity vectors
- * an angle of 0 rad ( 0°) means, the bots barely touched each other
- * an angle of π rad (180°) means, the bots crashed frontal into each other
- *
- * @generated from field: optional float crash_angle = 7;
- */
- crashAngle?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message GameEvent.BotCrashUnique.
- * Use `create(GameEvent_BotCrashUniqueSchema)` to create a new message.
- */
-export const GameEvent_BotCrashUniqueSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 8);
-
-/**
- * a bot pushed another bot over a significant distance
- *
- * @generated from message GameEvent.BotPushedBot
- */
-export type GameEvent_BotPushedBot = Message<"GameEvent.BotPushedBot"> & {
- /**
- * the team that pushed the other team
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that pushed the other bot
- *
- * @generated from field: optional uint32 violator = 2;
- */
- violator: number;
-
- /**
- * the bot of the opposite team that was pushed
- *
- * @generated from field: optional uint32 victim = 3;
- */
- victim: number;
-
- /**
- * the location of the push (center between both bots) [m]
- *
- * @generated from field: optional Vector2 location = 4;
- */
- location?: Vector2;
-
- /**
- * the pushed distance [m]
- *
- * @generated from field: optional float pushed_distance = 5;
- */
- pushedDistance: number;
-};
-
-/**
- * a bot pushed another bot over a significant distance
- *
- * @generated from message GameEvent.BotPushedBot
- */
-export type GameEvent_BotPushedBotJson = {
- /**
- * the team that pushed the other team
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that pushed the other bot
- *
- * @generated from field: optional uint32 violator = 2;
- */
- violator?: number;
-
- /**
- * the bot of the opposite team that was pushed
- *
- * @generated from field: optional uint32 victim = 3;
- */
- victim?: number;
-
- /**
- * the location of the push (center between both bots) [m]
- *
- * @generated from field: optional Vector2 location = 4;
- */
- location?: Vector2Json;
-
- /**
- * the pushed distance [m]
- *
- * @generated from field: optional float pushed_distance = 5;
- */
- pushedDistance?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message GameEvent.BotPushedBot.
- * Use `create(GameEvent_BotPushedBotSchema)` to create a new message.
- */
-export const GameEvent_BotPushedBotSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 9);
-
-/**
- * a bot tipped over
- *
- * @generated from message GameEvent.BotTippedOver
- */
-export type GameEvent_BotTippedOver = Message<"GameEvent.BotTippedOver"> & {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that tipped over
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot: number;
-
- /**
- * the location of the bot [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-
- /**
- * the location of the ball at the moment when this foul occurred [m]
- *
- * @generated from field: optional Vector2 ball_location = 4;
- */
- ballLocation?: Vector2;
-};
-
-/**
- * a bot tipped over
- *
- * @generated from message GameEvent.BotTippedOver
- */
-export type GameEvent_BotTippedOverJson = {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that tipped over
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot?: number;
-
- /**
- * the location of the bot [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-
- /**
- * the location of the ball at the moment when this foul occurred [m]
- *
- * @generated from field: optional Vector2 ball_location = 4;
- */
- ballLocation?: Vector2Json;
-};
-
-/**
- * Describes the message GameEvent.BotTippedOver.
- * Use `create(GameEvent_BotTippedOverSchema)` to create a new message.
- */
-export const GameEvent_BotTippedOverSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 10);
-
-/**
- * a bot dropped parts
- *
- * @generated from message GameEvent.BotDroppedParts
- */
-export type GameEvent_BotDroppedParts = Message<"GameEvent.BotDroppedParts"> & {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that dropped the parts
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot: number;
-
- /**
- * the location where the parts were dropped [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-
- /**
- * the location of the ball at the moment when this foul occurred [m]
- *
- * @generated from field: optional Vector2 ball_location = 4;
- */
- ballLocation?: Vector2;
-};
-
-/**
- * a bot dropped parts
- *
- * @generated from message GameEvent.BotDroppedParts
- */
-export type GameEvent_BotDroppedPartsJson = {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that dropped the parts
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot?: number;
-
- /**
- * the location where the parts were dropped [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-
- /**
- * the location of the ball at the moment when this foul occurred [m]
- *
- * @generated from field: optional Vector2 ball_location = 4;
- */
- ballLocation?: Vector2Json;
-};
-
-/**
- * Describes the message GameEvent.BotDroppedParts.
- * Use `create(GameEvent_BotDroppedPartsSchema)` to create a new message.
- */
-export const GameEvent_BotDroppedPartsSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 11);
-
-/**
- * a defender other than the keeper was fully located inside its own defense and touched the ball
- *
- * @generated from message GameEvent.DefenderInDefenseArea
- */
-export type GameEvent_DefenderInDefenseArea = Message<"GameEvent.DefenderInDefenseArea"> & {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that is inside the penalty area
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot: number;
-
- /**
- * the location of the bot [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-
- /**
- * the distance [m] from bot case to the nearest point outside the defense area
- *
- * @generated from field: optional float distance = 4;
- */
- distance: number;
-};
-
-/**
- * a defender other than the keeper was fully located inside its own defense and touched the ball
- *
- * @generated from message GameEvent.DefenderInDefenseArea
- */
-export type GameEvent_DefenderInDefenseAreaJson = {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that is inside the penalty area
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot?: number;
-
- /**
- * the location of the bot [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-
- /**
- * the distance [m] from bot case to the nearest point outside the defense area
- *
- * @generated from field: optional float distance = 4;
- */
- distance?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message GameEvent.DefenderInDefenseArea.
- * Use `create(GameEvent_DefenderInDefenseAreaSchema)` to create a new message.
- */
-export const GameEvent_DefenderInDefenseAreaSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 12);
-
-/**
- * a defender other than the keeper was partially located inside its own defense area and touched the ball
- *
- * @generated from message GameEvent.DefenderInDefenseAreaPartially
- */
-export type GameEvent_DefenderInDefenseAreaPartially = Message<"GameEvent.DefenderInDefenseAreaPartially"> & {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that is partially inside the penalty area
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot: number;
-
- /**
- * the location of the bot
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-
- /**
- * the distance [m] that the bot is inside the penalty area
- *
- * @generated from field: optional float distance = 4;
- */
- distance: number;
-
- /**
- * the location of the ball at the moment when this foul occurred [m]
- *
- * @generated from field: optional Vector2 ball_location = 5;
- */
- ballLocation?: Vector2;
-};
-
-/**
- * a defender other than the keeper was partially located inside its own defense area and touched the ball
- *
- * @generated from message GameEvent.DefenderInDefenseAreaPartially
- */
-export type GameEvent_DefenderInDefenseAreaPartiallyJson = {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that is partially inside the penalty area
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot?: number;
-
- /**
- * the location of the bot
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-
- /**
- * the distance [m] that the bot is inside the penalty area
- *
- * @generated from field: optional float distance = 4;
- */
- distance?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * the location of the ball at the moment when this foul occurred [m]
- *
- * @generated from field: optional Vector2 ball_location = 5;
- */
- ballLocation?: Vector2Json;
-};
-
-/**
- * Describes the message GameEvent.DefenderInDefenseAreaPartially.
- * Use `create(GameEvent_DefenderInDefenseAreaPartiallySchema)` to create a new message.
- */
-export const GameEvent_DefenderInDefenseAreaPartiallySchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 13);
-
-/**
- * an attacker touched the ball inside the opponent defense area
- *
- * @generated from message GameEvent.AttackerTouchedBallInDefenseArea
- */
-export type GameEvent_AttackerTouchedBallInDefenseArea = Message<"GameEvent.AttackerTouchedBallInDefenseArea"> & {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that is inside the penalty area
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot: number;
-
- /**
- * the location of the bot [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-
- /**
- * the distance [m] that the bot is inside the penalty area
- *
- * @generated from field: optional float distance = 4;
- */
- distance: number;
-};
-
-/**
- * an attacker touched the ball inside the opponent defense area
- *
- * @generated from message GameEvent.AttackerTouchedBallInDefenseArea
- */
-export type GameEvent_AttackerTouchedBallInDefenseAreaJson = {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that is inside the penalty area
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot?: number;
-
- /**
- * the location of the bot [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-
- /**
- * the distance [m] that the bot is inside the penalty area
- *
- * @generated from field: optional float distance = 4;
- */
- distance?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message GameEvent.AttackerTouchedBallInDefenseArea.
- * Use `create(GameEvent_AttackerTouchedBallInDefenseAreaSchema)` to create a new message.
- */
-export const GameEvent_AttackerTouchedBallInDefenseAreaSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 14);
-
-/**
- * a bot kicked the ball too fast
- *
- * @generated from message GameEvent.BotKickedBallTooFast
- */
-export type GameEvent_BotKickedBallTooFast = Message<"GameEvent.BotKickedBallTooFast"> & {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that kicked too fast
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot: number;
-
- /**
- * the location of the ball at the time of the highest speed [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-
- /**
- * the absolute initial ball speed (kick speed) [m/s]
- *
- * @generated from field: optional float initial_ball_speed = 4;
- */
- initialBallSpeed: number;
-
- /**
- * was the ball chipped?
- *
- * @generated from field: optional bool chipped = 5;
- */
- chipped: boolean;
-};
-
-/**
- * a bot kicked the ball too fast
- *
- * @generated from message GameEvent.BotKickedBallTooFast
- */
-export type GameEvent_BotKickedBallTooFastJson = {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that kicked too fast
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot?: number;
-
- /**
- * the location of the ball at the time of the highest speed [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-
- /**
- * the absolute initial ball speed (kick speed) [m/s]
- *
- * @generated from field: optional float initial_ball_speed = 4;
- */
- initialBallSpeed?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * was the ball chipped?
- *
- * @generated from field: optional bool chipped = 5;
- */
- chipped?: boolean;
-};
-
-/**
- * Describes the message GameEvent.BotKickedBallTooFast.
- * Use `create(GameEvent_BotKickedBallTooFastSchema)` to create a new message.
- */
-export const GameEvent_BotKickedBallTooFastSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 15);
-
-/**
- * a bot dribbled to ball too far
- *
- * @generated from message GameEvent.BotDribbledBallTooFar
- */
-export type GameEvent_BotDribbledBallTooFar = Message<"GameEvent.BotDribbledBallTooFar"> & {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that dribbled too far
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot: number;
-
- /**
- * the location where the dribbling started [m]
- *
- * @generated from field: optional Vector2 start = 3;
- */
- start?: Vector2;
-
- /**
- * the location where the maximum dribbling distance was reached [m]
- *
- * @generated from field: optional Vector2 end = 4;
- */
- end?: Vector2;
-};
-
-/**
- * a bot dribbled to ball too far
- *
- * @generated from message GameEvent.BotDribbledBallTooFar
- */
-export type GameEvent_BotDribbledBallTooFarJson = {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that dribbled too far
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot?: number;
-
- /**
- * the location where the dribbling started [m]
- *
- * @generated from field: optional Vector2 start = 3;
- */
- start?: Vector2Json;
-
- /**
- * the location where the maximum dribbling distance was reached [m]
- *
- * @generated from field: optional Vector2 end = 4;
- */
- end?: Vector2Json;
-};
-
-/**
- * Describes the message GameEvent.BotDribbledBallTooFar.
- * Use `create(GameEvent_BotDribbledBallTooFarSchema)` to create a new message.
- */
-export const GameEvent_BotDribbledBallTooFarSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 16);
-
-/**
- * an attacker touched the opponent robot inside defense area
- *
- * @generated from message GameEvent.AttackerTouchedOpponentInDefenseArea
- */
-export type GameEvent_AttackerTouchedOpponentInDefenseArea = Message<"GameEvent.AttackerTouchedOpponentInDefenseArea"> & {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that touched the opponent robot
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot: number;
-
- /**
- * the bot of the opposite team that was touched
- *
- * @generated from field: optional uint32 victim = 4;
- */
- victim: number;
-
- /**
- * the location of the contact point between both bots [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-};
-
-/**
- * an attacker touched the opponent robot inside defense area
- *
- * @generated from message GameEvent.AttackerTouchedOpponentInDefenseArea
- */
-export type GameEvent_AttackerTouchedOpponentInDefenseAreaJson = {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that touched the opponent robot
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot?: number;
-
- /**
- * the bot of the opposite team that was touched
- *
- * @generated from field: optional uint32 victim = 4;
- */
- victim?: number;
-
- /**
- * the location of the contact point between both bots [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-};
-
-/**
- * Describes the message GameEvent.AttackerTouchedOpponentInDefenseArea.
- * Use `create(GameEvent_AttackerTouchedOpponentInDefenseAreaSchema)` to create a new message.
- */
-export const GameEvent_AttackerTouchedOpponentInDefenseAreaSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 17);
-
-/**
- * an attacker touched the ball multiple times when it was not allowed to
- *
- * @generated from message GameEvent.AttackerDoubleTouchedBall
- */
-export type GameEvent_AttackerDoubleTouchedBall = Message<"GameEvent.AttackerDoubleTouchedBall"> & {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that touched the ball twice
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot: number;
-
- /**
- * the location of the ball when it was first touched [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-};
-
-/**
- * an attacker touched the ball multiple times when it was not allowed to
- *
- * @generated from message GameEvent.AttackerDoubleTouchedBall
- */
-export type GameEvent_AttackerDoubleTouchedBallJson = {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that touched the ball twice
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot?: number;
-
- /**
- * the location of the ball when it was first touched [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-};
-
-/**
- * Describes the message GameEvent.AttackerDoubleTouchedBall.
- * Use `create(GameEvent_AttackerDoubleTouchedBallSchema)` to create a new message.
- */
-export const GameEvent_AttackerDoubleTouchedBallSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 18);
-
-/**
- * an attacker was located too near to the opponent defense area during stop or free kick
- *
- * @generated from message GameEvent.AttackerTooCloseToDefenseArea
- */
-export type GameEvent_AttackerTooCloseToDefenseArea = Message<"GameEvent.AttackerTooCloseToDefenseArea"> & {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that is too close to the defense area
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot: number;
-
- /**
- * the location of the bot [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-
- /**
- * the distance [m] of the bot to the penalty area
- *
- * @generated from field: optional float distance = 4;
- */
- distance: number;
-
- /**
- * the location of the ball at the moment when this foul occurred [m]
- *
- * @generated from field: optional Vector2 ball_location = 5;
- */
- ballLocation?: Vector2;
-};
-
-/**
- * an attacker was located too near to the opponent defense area during stop or free kick
- *
- * @generated from message GameEvent.AttackerTooCloseToDefenseArea
- */
-export type GameEvent_AttackerTooCloseToDefenseAreaJson = {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that is too close to the defense area
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot?: number;
-
- /**
- * the location of the bot [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-
- /**
- * the distance [m] of the bot to the penalty area
- *
- * @generated from field: optional float distance = 4;
- */
- distance?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * the location of the ball at the moment when this foul occurred [m]
- *
- * @generated from field: optional Vector2 ball_location = 5;
- */
- ballLocation?: Vector2Json;
-};
-
-/**
- * Describes the message GameEvent.AttackerTooCloseToDefenseArea.
- * Use `create(GameEvent_AttackerTooCloseToDefenseAreaSchema)` to create a new message.
- */
-export const GameEvent_AttackerTooCloseToDefenseAreaSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 19);
-
-/**
- * a bot held the ball for too long
- *
- * @generated from message GameEvent.BotHeldBallDeliberately
- */
-export type GameEvent_BotHeldBallDeliberately = Message<"GameEvent.BotHeldBallDeliberately"> & {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that holds the ball
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot: number;
-
- /**
- * the location of the ball [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-
- /**
- * the duration [s] that the bot hold the ball
- *
- * @generated from field: optional float duration = 4;
- */
- duration: number;
-};
-
-/**
- * a bot held the ball for too long
- *
- * @generated from message GameEvent.BotHeldBallDeliberately
- */
-export type GameEvent_BotHeldBallDeliberatelyJson = {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that holds the ball
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot?: number;
-
- /**
- * the location of the ball [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-
- /**
- * the duration [s] that the bot hold the ball
- *
- * @generated from field: optional float duration = 4;
- */
- duration?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message GameEvent.BotHeldBallDeliberately.
- * Use `create(GameEvent_BotHeldBallDeliberatelySchema)` to create a new message.
- */
-export const GameEvent_BotHeldBallDeliberatelySchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 20);
-
-/**
- * a bot interfered the ball placement of the other team
- *
- * @generated from message GameEvent.BotInterferedPlacement
- */
-export type GameEvent_BotInterferedPlacement = Message<"GameEvent.BotInterferedPlacement"> & {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the bot that interfered the placement
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot: number;
-
- /**
- * the location of the bot [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2;
-};
-
-/**
- * a bot interfered the ball placement of the other team
- *
- * @generated from message GameEvent.BotInterferedPlacement
- */
-export type GameEvent_BotInterferedPlacementJson = {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the bot that interfered the placement
- *
- * @generated from field: optional uint32 by_bot = 2;
- */
- byBot?: number;
-
- /**
- * the location of the bot [m]
- *
- * @generated from field: optional Vector2 location = 3;
- */
- location?: Vector2Json;
-};
-
-/**
- * Describes the message GameEvent.BotInterferedPlacement.
- * Use `create(GameEvent_BotInterferedPlacementSchema)` to create a new message.
- */
-export const GameEvent_BotInterferedPlacementSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 21);
-
-/**
- * a team collected multiple yellow cards
- *
- * @generated from message GameEvent.MultipleCards
- */
-export type GameEvent_MultipleCards = Message<"GameEvent.MultipleCards"> & {
- /**
- * the team that received multiple yellow cards
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-};
-
-/**
- * a team collected multiple yellow cards
- *
- * @generated from message GameEvent.MultipleCards
- */
-export type GameEvent_MultipleCardsJson = {
- /**
- * the team that received multiple yellow cards
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-};
-
-/**
- * Describes the message GameEvent.MultipleCards.
- * Use `create(GameEvent_MultipleCardsSchema)` to create a new message.
- */
-export const GameEvent_MultipleCardsSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 22);
-
-/**
- * a team collected multiple fouls, which results in a yellow card
- *
- * @generated from message GameEvent.MultipleFouls
- */
-export type GameEvent_MultipleFouls = Message<"GameEvent.MultipleFouls"> & {
- /**
- * the team that collected multiple fouls
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the list of game events that caused the multiple fouls
- *
- * @generated from field: repeated GameEvent caused_game_events = 2;
- */
- causedGameEvents: GameEvent[];
-};
-
-/**
- * a team collected multiple fouls, which results in a yellow card
- *
- * @generated from message GameEvent.MultipleFouls
- */
-export type GameEvent_MultipleFoulsJson = {
- /**
- * the team that collected multiple fouls
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the list of game events that caused the multiple fouls
- *
- * @generated from field: repeated GameEvent caused_game_events = 2;
- */
- causedGameEvents?: GameEventJson[];
-};
-
-/**
- * Describes the message GameEvent.MultipleFouls.
- * Use `create(GameEvent_MultipleFoulsSchema)` to create a new message.
- */
-export const GameEvent_MultipleFoulsSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 23);
-
-/**
- * a team failed to place the ball multiple times in a row
- *
- * @generated from message GameEvent.MultiplePlacementFailures
- */
-export type GameEvent_MultiplePlacementFailures = Message<"GameEvent.MultiplePlacementFailures"> & {
- /**
- * the team that failed multiple times
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-};
-
-/**
- * a team failed to place the ball multiple times in a row
- *
- * @generated from message GameEvent.MultiplePlacementFailures
- */
-export type GameEvent_MultiplePlacementFailuresJson = {
- /**
- * the team that failed multiple times
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-};
-
-/**
- * Describes the message GameEvent.MultiplePlacementFailures.
- * Use `create(GameEvent_MultiplePlacementFailuresSchema)` to create a new message.
- */
-export const GameEvent_MultiplePlacementFailuresSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 24);
-
-/**
- * timeout waiting for the attacking team to perform the free kick
- *
- * @generated from message GameEvent.KickTimeout
- */
-export type GameEvent_KickTimeout = Message<"GameEvent.KickTimeout"> & {
- /**
- * the team that that should have kicked
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the location of the ball [m]
- *
- * @generated from field: optional Vector2 location = 2;
- */
- location?: Vector2;
-
- /**
- * the time [s] that was waited
- *
- * @generated from field: optional float time = 3;
- */
- time: number;
-};
-
-/**
- * timeout waiting for the attacking team to perform the free kick
- *
- * @generated from message GameEvent.KickTimeout
- */
-export type GameEvent_KickTimeoutJson = {
- /**
- * the team that that should have kicked
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the location of the ball [m]
- *
- * @generated from field: optional Vector2 location = 2;
- */
- location?: Vector2Json;
-
- /**
- * the time [s] that was waited
- *
- * @generated from field: optional float time = 3;
- */
- time?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message GameEvent.KickTimeout.
- * Use `create(GameEvent_KickTimeoutSchema)` to create a new message.
- */
-export const GameEvent_KickTimeoutSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 25);
-
-/**
- * game was stuck
- *
- * @generated from message GameEvent.NoProgressInGame
- */
-export type GameEvent_NoProgressInGame = Message<"GameEvent.NoProgressInGame"> & {
- /**
- * the location of the ball
- *
- * @generated from field: optional Vector2 location = 1;
- */
- location?: Vector2;
-
- /**
- * the time [s] that was waited
- *
- * @generated from field: optional float time = 2;
- */
- time: number;
-};
-
-/**
- * game was stuck
- *
- * @generated from message GameEvent.NoProgressInGame
- */
-export type GameEvent_NoProgressInGameJson = {
- /**
- * the location of the ball
- *
- * @generated from field: optional Vector2 location = 1;
- */
- location?: Vector2Json;
-
- /**
- * the time [s] that was waited
- *
- * @generated from field: optional float time = 2;
- */
- time?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message GameEvent.NoProgressInGame.
- * Use `create(GameEvent_NoProgressInGameSchema)` to create a new message.
- */
-export const GameEvent_NoProgressInGameSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 26);
-
-/**
- * ball placement failed
- *
- * @generated from message GameEvent.PlacementFailed
- */
-export type GameEvent_PlacementFailed = Message<"GameEvent.PlacementFailed"> & {
- /**
- * the team that failed
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the remaining distance [m] from ball to placement position
- *
- * @generated from field: optional float remaining_distance = 2;
- */
- remainingDistance: number;
-
- /**
- * the distance [m] of the nearest own robot to the ball
- *
- * @generated from field: optional float nearest_own_bot_distance = 3;
- */
- nearestOwnBotDistance: number;
-};
-
-/**
- * ball placement failed
- *
- * @generated from message GameEvent.PlacementFailed
- */
-export type GameEvent_PlacementFailedJson = {
- /**
- * the team that failed
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the remaining distance [m] from ball to placement position
- *
- * @generated from field: optional float remaining_distance = 2;
- */
- remainingDistance?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * the distance [m] of the nearest own robot to the ball
- *
- * @generated from field: optional float nearest_own_bot_distance = 3;
- */
- nearestOwnBotDistance?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message GameEvent.PlacementFailed.
- * Use `create(GameEvent_PlacementFailedSchema)` to create a new message.
- */
-export const GameEvent_PlacementFailedSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 27);
-
-/**
- * a team was found guilty for minor unsporting behavior
- *
- * @generated from message GameEvent.UnsportingBehaviorMinor
- */
-export type GameEvent_UnsportingBehaviorMinor = Message<"GameEvent.UnsportingBehaviorMinor"> & {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * an explanation of the situation and decision
- *
- * @generated from field: required string reason = 2;
- */
- reason: string;
-};
-
-/**
- * a team was found guilty for minor unsporting behavior
- *
- * @generated from message GameEvent.UnsportingBehaviorMinor
- */
-export type GameEvent_UnsportingBehaviorMinorJson = {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * an explanation of the situation and decision
- *
- * @generated from field: required string reason = 2;
- */
- reason?: string;
-};
-
-/**
- * Describes the message GameEvent.UnsportingBehaviorMinor.
- * Use `create(GameEvent_UnsportingBehaviorMinorSchema)` to create a new message.
- */
-export const GameEvent_UnsportingBehaviorMinorSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 28);
-
-/**
- * a team was found guilty for major unsporting behavior
- *
- * @generated from message GameEvent.UnsportingBehaviorMajor
- */
-export type GameEvent_UnsportingBehaviorMajor = Message<"GameEvent.UnsportingBehaviorMajor"> & {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * an explanation of the situation and decision
- *
- * @generated from field: required string reason = 2;
- */
- reason: string;
-};
-
-/**
- * a team was found guilty for major unsporting behavior
- *
- * @generated from message GameEvent.UnsportingBehaviorMajor
- */
-export type GameEvent_UnsportingBehaviorMajorJson = {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * an explanation of the situation and decision
- *
- * @generated from field: required string reason = 2;
- */
- reason?: string;
-};
-
-/**
- * Describes the message GameEvent.UnsportingBehaviorMajor.
- * Use `create(GameEvent_UnsportingBehaviorMajorSchema)` to create a new message.
- */
-export const GameEvent_UnsportingBehaviorMajorSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 29);
-
-/**
- * a keeper held the ball in its defense area for too long
- *
- * @generated from message GameEvent.KeeperHeldBall
- */
-export type GameEvent_KeeperHeldBall = Message<"GameEvent.KeeperHeldBall"> & {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the location of the ball [m]
- *
- * @generated from field: optional Vector2 location = 2;
- */
- location?: Vector2;
-
- /**
- * the duration [s] that the keeper hold the ball
- *
- * @generated from field: optional float duration = 3;
- */
- duration: number;
-};
-
-/**
- * a keeper held the ball in its defense area for too long
- *
- * @generated from message GameEvent.KeeperHeldBall
- */
-export type GameEvent_KeeperHeldBallJson = {
- /**
- * the team that found guilty
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the location of the ball [m]
- *
- * @generated from field: optional Vector2 location = 2;
- */
- location?: Vector2Json;
-
- /**
- * the duration [s] that the keeper hold the ball
- *
- * @generated from field: optional float duration = 3;
- */
- duration?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message GameEvent.KeeperHeldBall.
- * Use `create(GameEvent_KeeperHeldBallSchema)` to create a new message.
- */
-export const GameEvent_KeeperHeldBallSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 30);
-
-/**
- * a team successfully placed the ball
- *
- * @generated from message GameEvent.PlacementSucceeded
- */
-export type GameEvent_PlacementSucceeded = Message<"GameEvent.PlacementSucceeded"> & {
- /**
- * the team that did the placement
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the time [s] taken for placing the ball
- *
- * @generated from field: optional float time_taken = 2;
- */
- timeTaken: number;
-
- /**
- * the distance [m] between placement location and actual ball position
- *
- * @generated from field: optional float precision = 3;
- */
- precision: number;
-
- /**
- * the distance [m] between the initial ball location and the placement position
- *
- * @generated from field: optional float distance = 4;
- */
- distance: number;
-};
-
-/**
- * a team successfully placed the ball
- *
- * @generated from message GameEvent.PlacementSucceeded
- */
-export type GameEvent_PlacementSucceededJson = {
- /**
- * the team that did the placement
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the time [s] taken for placing the ball
- *
- * @generated from field: optional float time_taken = 2;
- */
- timeTaken?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * the distance [m] between placement location and actual ball position
- *
- * @generated from field: optional float precision = 3;
- */
- precision?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * the distance [m] between the initial ball location and the placement position
- *
- * @generated from field: optional float distance = 4;
- */
- distance?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message GameEvent.PlacementSucceeded.
- * Use `create(GameEvent_PlacementSucceededSchema)` to create a new message.
- */
-export const GameEvent_PlacementSucceededSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 31);
-
-/**
- * both teams are prepared - all conditions are met to continue (with kickoff or penalty kick)
- *
- * @generated from message GameEvent.Prepared
- */
-export type GameEvent_Prepared = Message<"GameEvent.Prepared"> & {
- /**
- * the time [s] taken for preparing
- *
- * @generated from field: optional float time_taken = 1;
- */
- timeTaken: number;
-};
-
-/**
- * both teams are prepared - all conditions are met to continue (with kickoff or penalty kick)
- *
- * @generated from message GameEvent.Prepared
- */
-export type GameEvent_PreparedJson = {
- /**
- * the time [s] taken for preparing
- *
- * @generated from field: optional float time_taken = 1;
- */
- timeTaken?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message GameEvent.Prepared.
- * Use `create(GameEvent_PreparedSchema)` to create a new message.
- */
-export const GameEvent_PreparedSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 32);
-
-/**
- * bots are being substituted by a team
- *
- * @generated from message GameEvent.BotSubstitution
- */
-export type GameEvent_BotSubstitution = Message<"GameEvent.BotSubstitution"> & {
- /**
- * the team that substitutes robots
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-};
-
-/**
- * bots are being substituted by a team
- *
- * @generated from message GameEvent.BotSubstitution
- */
-export type GameEvent_BotSubstitutionJson = {
- /**
- * the team that substitutes robots
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-};
-
-/**
- * Describes the message GameEvent.BotSubstitution.
- * Use `create(GameEvent_BotSubstitutionSchema)` to create a new message.
- */
-export const GameEvent_BotSubstitutionSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 33);
-
-/**
- * A foul for excessive bot substitutions
- *
- * @generated from message GameEvent.ExcessiveBotSubstitution
- */
-export type GameEvent_ExcessiveBotSubstitution = Message<"GameEvent.ExcessiveBotSubstitution"> & {
- /**
- * the team that substitutes robots
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-};
-
-/**
- * A foul for excessive bot substitutions
- *
- * @generated from message GameEvent.ExcessiveBotSubstitution
- */
-export type GameEvent_ExcessiveBotSubstitutionJson = {
- /**
- * the team that substitutes robots
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-};
-
-/**
- * Describes the message GameEvent.ExcessiveBotSubstitution.
- * Use `create(GameEvent_ExcessiveBotSubstitutionSchema)` to create a new message.
- */
-export const GameEvent_ExcessiveBotSubstitutionSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 34);
-
-/**
- * A challenge flag, requested by a team previously, is flagged
- *
- * @generated from message GameEvent.ChallengeFlag
- */
-export type GameEvent_ChallengeFlag = Message<"GameEvent.ChallengeFlag"> & {
- /**
- * the team that requested the challenge flag
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-};
-
-/**
- * A challenge flag, requested by a team previously, is flagged
- *
- * @generated from message GameEvent.ChallengeFlag
- */
-export type GameEvent_ChallengeFlagJson = {
- /**
- * the team that requested the challenge flag
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-};
-
-/**
- * Describes the message GameEvent.ChallengeFlag.
- * Use `create(GameEvent_ChallengeFlagSchema)` to create a new message.
- */
-export const GameEvent_ChallengeFlagSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 35);
-
-/**
- * A challenge, flagged recently, has been handled by the referee
- *
- * @generated from message GameEvent.ChallengeFlagHandled
- */
-export type GameEvent_ChallengeFlagHandled = Message<"GameEvent.ChallengeFlagHandled"> & {
- /**
- * the team that requested the challenge flag
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the challenge was accepted by the referee
- *
- * @generated from field: required bool accepted = 2;
- */
- accepted: boolean;
-};
-
-/**
- * A challenge, flagged recently, has been handled by the referee
- *
- * @generated from message GameEvent.ChallengeFlagHandled
- */
-export type GameEvent_ChallengeFlagHandledJson = {
- /**
- * the team that requested the challenge flag
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the challenge was accepted by the referee
- *
- * @generated from field: required bool accepted = 2;
- */
- accepted?: boolean;
-};
-
-/**
- * Describes the message GameEvent.ChallengeFlagHandled.
- * Use `create(GameEvent_ChallengeFlagHandledSchema)` to create a new message.
- */
-export const GameEvent_ChallengeFlagHandledSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 36);
-
-/**
- * An emergency stop, requested by team previously, occurred
- *
- * @generated from message GameEvent.EmergencyStop
- */
-export type GameEvent_EmergencyStop = Message<"GameEvent.EmergencyStop"> & {
- /**
- * the team that substitutes robots
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-};
-
-/**
- * An emergency stop, requested by team previously, occurred
- *
- * @generated from message GameEvent.EmergencyStop
- */
-export type GameEvent_EmergencyStopJson = {
- /**
- * the team that substitutes robots
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-};
-
-/**
- * Describes the message GameEvent.EmergencyStop.
- * Use `create(GameEvent_EmergencyStopSchema)` to create a new message.
- */
-export const GameEvent_EmergencyStopSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 37);
-
-/**
- * a team has too many robots on the field
- *
- * @generated from message GameEvent.TooManyRobots
- */
-export type GameEvent_TooManyRobots = Message<"GameEvent.TooManyRobots"> & {
- /**
- * the team that has too many robots
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * number of robots allowed at the moment
- *
- * @generated from field: optional int32 num_robots_allowed = 2;
- */
- numRobotsAllowed: number;
-
- /**
- * number of robots currently on the field
- *
- * @generated from field: optional int32 num_robots_on_field = 3;
- */
- numRobotsOnField: number;
-
- /**
- * the location of the ball at the moment when this foul occurred [m]
- *
- * @generated from field: optional Vector2 ball_location = 4;
- */
- ballLocation?: Vector2;
-};
-
-/**
- * a team has too many robots on the field
- *
- * @generated from message GameEvent.TooManyRobots
- */
-export type GameEvent_TooManyRobotsJson = {
- /**
- * the team that has too many robots
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * number of robots allowed at the moment
- *
- * @generated from field: optional int32 num_robots_allowed = 2;
- */
- numRobotsAllowed?: number;
-
- /**
- * number of robots currently on the field
- *
- * @generated from field: optional int32 num_robots_on_field = 3;
- */
- numRobotsOnField?: number;
-
- /**
- * the location of the ball at the moment when this foul occurred [m]
- *
- * @generated from field: optional Vector2 ball_location = 4;
- */
- ballLocation?: Vector2Json;
-};
-
-/**
- * Describes the message GameEvent.TooManyRobots.
- * Use `create(GameEvent_TooManyRobotsSchema)` to create a new message.
- */
-export const GameEvent_TooManyRobotsSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 38);
-
-/**
- * a robot chipped the ball over the field boundary out of the playing surface
- *
- * @generated from message GameEvent.BoundaryCrossing
- */
-export type GameEvent_BoundaryCrossing = Message<"GameEvent.BoundaryCrossing"> & {
- /**
- * the team that has too many robots
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the location of the ball [m]
- *
- * @generated from field: optional Vector2 location = 2;
- */
- location?: Vector2;
-};
-
-/**
- * a robot chipped the ball over the field boundary out of the playing surface
- *
- * @generated from message GameEvent.BoundaryCrossing
- */
-export type GameEvent_BoundaryCrossingJson = {
- /**
- * the team that has too many robots
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the location of the ball [m]
- *
- * @generated from field: optional Vector2 location = 2;
- */
- location?: Vector2Json;
-};
-
-/**
- * Describes the message GameEvent.BoundaryCrossing.
- * Use `create(GameEvent_BoundaryCrossingSchema)` to create a new message.
- */
-export const GameEvent_BoundaryCrossingSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 39);
-
-/**
- * the penalty kick failed (by time or by keeper)
- *
- * @generated from message GameEvent.PenaltyKickFailed
- */
-export type GameEvent_PenaltyKickFailed = Message<"GameEvent.PenaltyKickFailed"> & {
- /**
- * the team that last touched the ball
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam: Team;
-
- /**
- * the location of the ball at the moment of this event [m]
- *
- * @generated from field: optional Vector2 location = 2;
- */
- location?: Vector2;
-
- /**
- * an explanation of the failure
- *
- * @generated from field: optional string reason = 3;
- */
- reason: string;
-};
-
-/**
- * the penalty kick failed (by time or by keeper)
- *
- * @generated from message GameEvent.PenaltyKickFailed
- */
-export type GameEvent_PenaltyKickFailedJson = {
- /**
- * the team that last touched the ball
- *
- * @generated from field: required Team by_team = 1;
- */
- byTeam?: TeamJson;
-
- /**
- * the location of the ball at the moment of this event [m]
- *
- * @generated from field: optional Vector2 location = 2;
- */
- location?: Vector2Json;
-
- /**
- * an explanation of the failure
- *
- * @generated from field: optional string reason = 3;
- */
- reason?: string;
-};
-
-/**
- * Describes the message GameEvent.PenaltyKickFailed.
- * Use `create(GameEvent_PenaltyKickFailedSchema)` to create a new message.
- */
-export const GameEvent_PenaltyKickFailedSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_game_event, 0, 40);
-
-/**
- * @generated from enum GameEvent.Type
- */
-export enum GameEvent_Type {
- /**
- * @generated from enum value: UNKNOWN_GAME_EVENT_TYPE = 0;
- */
- UNKNOWN_GAME_EVENT_TYPE = 0,
-
- /**
- * triggered by autoRef
- *
- * @generated from enum value: BALL_LEFT_FIELD_TOUCH_LINE = 6;
- */
- BALL_LEFT_FIELD_TOUCH_LINE = 6,
-
- /**
- * triggered by autoRef
- *
- * @generated from enum value: BALL_LEFT_FIELD_GOAL_LINE = 7;
- */
- BALL_LEFT_FIELD_GOAL_LINE = 7,
-
- /**
- * triggered by autoRef
- *
- * @generated from enum value: AIMLESS_KICK = 11;
- */
- AIMLESS_KICK = 11,
-
- /**
- * triggered by autoRef
- *
- * @generated from enum value: ATTACKER_TOO_CLOSE_TO_DEFENSE_AREA = 19;
- */
- ATTACKER_TOO_CLOSE_TO_DEFENSE_AREA = 19,
-
- /**
- * triggered by autoRef
- *
- * @generated from enum value: DEFENDER_IN_DEFENSE_AREA = 31;
- */
- DEFENDER_IN_DEFENSE_AREA = 31,
-
- /**
- * triggered by autoRef
- *
- * @generated from enum value: BOUNDARY_CROSSING = 41;
- */
- BOUNDARY_CROSSING = 41,
-
- /**
- * triggered by GC
- *
- * @generated from enum value: KEEPER_HELD_BALL = 13;
- */
- KEEPER_HELD_BALL = 13,
-
- /**
- * triggered by autoRef
- *
- * @generated from enum value: BOT_DRIBBLED_BALL_TOO_FAR = 17;
- */
- BOT_DRIBBLED_BALL_TOO_FAR = 17,
-
- /**
- * triggered by human ref
- *
- * @generated from enum value: BOT_PUSHED_BOT = 24;
- */
- BOT_PUSHED_BOT = 24,
-
- /**
- * triggered by human ref
- *
- * @generated from enum value: BOT_HELD_BALL_DELIBERATELY = 26;
- */
- BOT_HELD_BALL_DELIBERATELY = 26,
-
- /**
- * triggered by human ref
- *
- * @generated from enum value: BOT_TIPPED_OVER = 27;
- */
- BOT_TIPPED_OVER = 27,
-
- /**
- * triggered by human ref
- *
- * @generated from enum value: BOT_DROPPED_PARTS = 47;
- */
- BOT_DROPPED_PARTS = 47,
-
- /**
- * triggered by autoRef
- *
- * @generated from enum value: ATTACKER_TOUCHED_BALL_IN_DEFENSE_AREA = 15;
- */
- ATTACKER_TOUCHED_BALL_IN_DEFENSE_AREA = 15,
-
- /**
- * triggered by autoRef
- *
- * @generated from enum value: BOT_KICKED_BALL_TOO_FAST = 18;
- */
- BOT_KICKED_BALL_TOO_FAST = 18,
-
- /**
- * triggered by autoRef
- *
- * @generated from enum value: BOT_CRASH_UNIQUE = 22;
- */
- BOT_CRASH_UNIQUE = 22,
-
- /**
- * triggered by autoRef
- *
- * @generated from enum value: BOT_CRASH_DRAWN = 21;
- */
- BOT_CRASH_DRAWN = 21,
-
- /**
- * triggered by autoRef
- *
- * @generated from enum value: DEFENDER_TOO_CLOSE_TO_KICK_POINT = 29;
- */
- DEFENDER_TOO_CLOSE_TO_KICK_POINT = 29,
-
- /**
- * triggered by autoRef
- *
- * @generated from enum value: BOT_TOO_FAST_IN_STOP = 28;
- */
- BOT_TOO_FAST_IN_STOP = 28,
-
- /**
- * triggered by autoRef
- *
- * @generated from enum value: BOT_INTERFERED_PLACEMENT = 20;
- */
- BOT_INTERFERED_PLACEMENT = 20,
-
- /**
- * triggered by GC
- *
- * @generated from enum value: EXCESSIVE_BOT_SUBSTITUTION = 48;
- */
- EXCESSIVE_BOT_SUBSTITUTION = 48,
-
- /**
- * triggered by autoRef
- *
- * @generated from enum value: POSSIBLE_GOAL = 39;
- */
- POSSIBLE_GOAL = 39,
-
- /**
- * triggered by GC
- *
- * @generated from enum value: GOAL = 8;
- */
- GOAL = 8,
-
- /**
- * triggered by GC
- *
- * @generated from enum value: INVALID_GOAL = 42;
- */
- INVALID_GOAL = 42,
-
- /**
- * triggered by autoRef
- *
- * @generated from enum value: ATTACKER_DOUBLE_TOUCHED_BALL = 14;
- */
- ATTACKER_DOUBLE_TOUCHED_BALL = 14,
-
- /**
- * triggered by autoRef
- *
- * @generated from enum value: PLACEMENT_SUCCEEDED = 5;
- */
- PLACEMENT_SUCCEEDED = 5,
-
- /**
- * triggered by GC and autoRef
- *
- * @generated from enum value: PENALTY_KICK_FAILED = 43;
- */
- PENALTY_KICK_FAILED = 43,
-
- /**
- * triggered by GC
- *
- * @generated from enum value: NO_PROGRESS_IN_GAME = 2;
- */
- NO_PROGRESS_IN_GAME = 2,
-
- /**
- * triggered by GC
- *
- * @generated from enum value: PLACEMENT_FAILED = 3;
- */
- PLACEMENT_FAILED = 3,
-
- /**
- * triggered by GC
- *
- * @generated from enum value: MULTIPLE_CARDS = 32;
- */
- MULTIPLE_CARDS = 32,
-
- /**
- * triggered by GC
- *
- * @generated from enum value: MULTIPLE_FOULS = 34;
- */
- MULTIPLE_FOULS = 34,
-
- /**
- * triggered by GC
- *
- * @generated from enum value: BOT_SUBSTITUTION = 37;
- */
- BOT_SUBSTITUTION = 37,
-
- /**
- * triggered by GC
- *
- * @generated from enum value: TOO_MANY_ROBOTS = 38;
- */
- TOO_MANY_ROBOTS = 38,
-
- /**
- * triggered by GC
- *
- * @generated from enum value: CHALLENGE_FLAG = 44;
- */
- CHALLENGE_FLAG = 44,
-
- /**
- * triggered by GC
- *
- * @generated from enum value: CHALLENGE_FLAG_HANDLED = 46;
- */
- CHALLENGE_FLAG_HANDLED = 46,
-
- /**
- * triggered by GC
- *
- * @generated from enum value: EMERGENCY_STOP = 45;
- */
- EMERGENCY_STOP = 45,
-
- /**
- * triggered by human ref
- *
- * @generated from enum value: UNSPORTING_BEHAVIOR_MINOR = 35;
- */
- UNSPORTING_BEHAVIOR_MINOR = 35,
-
- /**
- * triggered by human ref
- *
- * @generated from enum value: UNSPORTING_BEHAVIOR_MAJOR = 36;
- */
- UNSPORTING_BEHAVIOR_MAJOR = 36,
-
- /**
- * @generated from enum value: PREPARED = 1 [deprecated = true];
- * @deprecated
- */
- PREPARED = 1,
-
- /**
- * @generated from enum value: INDIRECT_GOAL = 9 [deprecated = true];
- * @deprecated
- */
- INDIRECT_GOAL = 9,
-
- /**
- * @generated from enum value: CHIPPED_GOAL = 10 [deprecated = true];
- * @deprecated
- */
- CHIPPED_GOAL = 10,
-
- /**
- * @generated from enum value: KICK_TIMEOUT = 12 [deprecated = true];
- * @deprecated
- */
- KICK_TIMEOUT = 12,
-
- /**
- * @generated from enum value: ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA = 16 [deprecated = true];
- * @deprecated
- */
- ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA = 16,
-
- /**
- * @generated from enum value: ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA_SKIPPED = 40 [deprecated = true];
- * @deprecated
- */
- ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA_SKIPPED = 40,
-
- /**
- * @generated from enum value: BOT_CRASH_UNIQUE_SKIPPED = 23 [deprecated = true];
- * @deprecated
- */
- BOT_CRASH_UNIQUE_SKIPPED = 23,
-
- /**
- * @generated from enum value: BOT_PUSHED_BOT_SKIPPED = 25 [deprecated = true];
- * @deprecated
- */
- BOT_PUSHED_BOT_SKIPPED = 25,
-
- /**
- * @generated from enum value: DEFENDER_IN_DEFENSE_AREA_PARTIALLY = 30 [deprecated = true];
- * @deprecated
- */
- DEFENDER_IN_DEFENSE_AREA_PARTIALLY = 30,
-
- /**
- * @generated from enum value: MULTIPLE_PLACEMENT_FAILURES = 33 [deprecated = true];
- * @deprecated
- */
- MULTIPLE_PLACEMENT_FAILURES = 33,
-}
-
-/**
- * @generated from enum GameEvent.Type
- */
-export type GameEvent_TypeJson = "UNKNOWN_GAME_EVENT_TYPE" | "BALL_LEFT_FIELD_TOUCH_LINE" | "BALL_LEFT_FIELD_GOAL_LINE" | "AIMLESS_KICK" | "ATTACKER_TOO_CLOSE_TO_DEFENSE_AREA" | "DEFENDER_IN_DEFENSE_AREA" | "BOUNDARY_CROSSING" | "KEEPER_HELD_BALL" | "BOT_DRIBBLED_BALL_TOO_FAR" | "BOT_PUSHED_BOT" | "BOT_HELD_BALL_DELIBERATELY" | "BOT_TIPPED_OVER" | "BOT_DROPPED_PARTS" | "ATTACKER_TOUCHED_BALL_IN_DEFENSE_AREA" | "BOT_KICKED_BALL_TOO_FAST" | "BOT_CRASH_UNIQUE" | "BOT_CRASH_DRAWN" | "DEFENDER_TOO_CLOSE_TO_KICK_POINT" | "BOT_TOO_FAST_IN_STOP" | "BOT_INTERFERED_PLACEMENT" | "EXCESSIVE_BOT_SUBSTITUTION" | "POSSIBLE_GOAL" | "GOAL" | "INVALID_GOAL" | "ATTACKER_DOUBLE_TOUCHED_BALL" | "PLACEMENT_SUCCEEDED" | "PENALTY_KICK_FAILED" | "NO_PROGRESS_IN_GAME" | "PLACEMENT_FAILED" | "MULTIPLE_CARDS" | "MULTIPLE_FOULS" | "BOT_SUBSTITUTION" | "TOO_MANY_ROBOTS" | "CHALLENGE_FLAG" | "CHALLENGE_FLAG_HANDLED" | "EMERGENCY_STOP" | "UNSPORTING_BEHAVIOR_MINOR" | "UNSPORTING_BEHAVIOR_MAJOR" | "PREPARED" | "INDIRECT_GOAL" | "CHIPPED_GOAL" | "KICK_TIMEOUT" | "ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA" | "ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA_SKIPPED" | "BOT_CRASH_UNIQUE_SKIPPED" | "BOT_PUSHED_BOT_SKIPPED" | "DEFENDER_IN_DEFENSE_AREA_PARTIALLY" | "MULTIPLE_PLACEMENT_FAILURES";
-
-/**
- * Describes the enum GameEvent.Type.
- */
-export const GameEvent_TypeSchema: GenEnum = /*@__PURE__*/
- enumDesc(file_gamecontroller_ssl_gc_game_event, 0, 0);
-
diff --git a/gui/frontend/src/proto/gamecontroller/ssl_gc_geometry_pb.ts b/gui/frontend/src/proto/gamecontroller/ssl_gc_geometry_pb.ts
deleted file mode 100644
index 3b4c243..0000000
--- a/gui/frontend/src/proto/gamecontroller/ssl_gc_geometry_pb.ts
+++ /dev/null
@@ -1,106 +0,0 @@
-// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
-// @generated from file gamecontroller/ssl_gc_geometry.proto (syntax proto2)
-/* eslint-disable */
-
-import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
-import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
-import type { Message } from "@bufbuild/protobuf";
-
-/**
- * Describes the file gamecontroller/ssl_gc_geometry.proto.
- */
-export const file_gamecontroller_ssl_gc_geometry: GenFile = /*@__PURE__*/
- fileDesc("CiRnYW1lY29udHJvbGxlci9zc2xfZ2NfZ2VvbWV0cnkucHJvdG8iHwoHVmVjdG9yMhIJCgF4GAEgAigCEgkKAXkYAiACKAIiKgoHVmVjdG9yMxIJCgF4GAEgAigCEgkKAXkYAiACKAISCQoBehgDIAIoAkJfQhJTc2xHY0dlb21ldHJ5UHJvdG9QAVpHZ2l0aHViLmNvbS9Sb2JvQ3VwLVNTTC9zc2wtdmlzaW9uLXByb2Nlc3Nvci9ndWkvaW50ZXJuYWwvZ2FtZWNvbnRyb2xsZXI");
-
-/**
- * A vector with two dimensions
- *
- * @generated from message Vector2
- */
-export type Vector2 = Message<"Vector2"> & {
- /**
- * @generated from field: required float x = 1;
- */
- x: number;
-
- /**
- * @generated from field: required float y = 2;
- */
- y: number;
-};
-
-/**
- * A vector with two dimensions
- *
- * @generated from message Vector2
- */
-export type Vector2Json = {
- /**
- * @generated from field: required float x = 1;
- */
- x?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: required float y = 2;
- */
- y?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message Vector2.
- * Use `create(Vector2Schema)` to create a new message.
- */
-export const Vector2Schema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_geometry, 0);
-
-/**
- * A vector with three dimensions
- *
- * @generated from message Vector3
- */
-export type Vector3 = Message<"Vector3"> & {
- /**
- * @generated from field: required float x = 1;
- */
- x: number;
-
- /**
- * @generated from field: required float y = 2;
- */
- y: number;
-
- /**
- * @generated from field: required float z = 3;
- */
- z: number;
-};
-
-/**
- * A vector with three dimensions
- *
- * @generated from message Vector3
- */
-export type Vector3Json = {
- /**
- * @generated from field: required float x = 1;
- */
- x?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: required float y = 2;
- */
- y?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: required float z = 3;
- */
- z?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message Vector3.
- * Use `create(Vector3Schema)` to create a new message.
- */
-export const Vector3Schema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_geometry, 1);
-
diff --git a/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_autoref_pb.ts b/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_autoref_pb.ts
deleted file mode 100644
index b347533..0000000
--- a/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_autoref_pb.ts
+++ /dev/null
@@ -1,157 +0,0 @@
-// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
-// @generated from file gamecontroller/ssl_gc_rcon_autoref.proto (syntax proto2)
-/* eslint-disable */
-
-import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
-import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
-import type { GameEvent, GameEventJson } from "./ssl_gc_game_event_pb";
-import { file_gamecontroller_ssl_gc_game_event } from "./ssl_gc_game_event_pb";
-import type { ControllerReply, ControllerReplyJson, Signature, SignatureJson } from "./ssl_gc_rcon_pb";
-import { file_gamecontroller_ssl_gc_rcon } from "./ssl_gc_rcon_pb";
-import type { Message } from "@bufbuild/protobuf";
-
-/**
- * Describes the file gamecontroller/ssl_gc_rcon_autoref.proto.
- */
-export const file_gamecontroller_ssl_gc_rcon_autoref: GenFile = /*@__PURE__*/
- fileDesc("CihnYW1lY29udHJvbGxlci9zc2xfZ2NfcmNvbl9hdXRvcmVmLnByb3RvIkgKE0F1dG9SZWZSZWdpc3RyYXRpb24SEgoKaWRlbnRpZmllchgBIAIoCRIdCglzaWduYXR1cmUYAiABKAsyCi5TaWduYXR1cmUiYAoTQXV0b1JlZlRvQ29udHJvbGxlchIdCglzaWduYXR1cmUYASABKAsyCi5TaWduYXR1cmUSHgoKZ2FtZV9ldmVudBgCIAEoCzIKLkdhbWVFdmVudEoECAMQBEoECAQQBSJKChNDb250cm9sbGVyVG9BdXRvUmVmEiwKEGNvbnRyb2xsZXJfcmVwbHkYASABKAsyEC5Db250cm9sbGVyUmVwbHlIAEIFCgNtc2dCYkIVU3NsR2NSY29uQXV0b3JlZlByb3RvUAFaR2dpdGh1Yi5jb20vUm9ib0N1cC1TU0wvc3NsLXZpc2lvbi1wcm9jZXNzb3IvZ3VpL2ludGVybmFsL2dhbWVjb250cm9sbGVy", [file_gamecontroller_ssl_gc_game_event, file_gamecontroller_ssl_gc_rcon]);
-
-/**
- * AutoRefRegistration is the first message that a client must send to the controller to identify itself
- *
- * @generated from message AutoRefRegistration
- */
-export type AutoRefRegistration = Message<"AutoRefRegistration"> & {
- /**
- * identifier is a unique name of the client
- *
- * @generated from field: required string identifier = 1;
- */
- identifier: string;
-
- /**
- * signature can optionally be specified to enable secure communication
- *
- * @generated from field: optional Signature signature = 2;
- */
- signature?: Signature;
-};
-
-/**
- * AutoRefRegistration is the first message that a client must send to the controller to identify itself
- *
- * @generated from message AutoRefRegistration
- */
-export type AutoRefRegistrationJson = {
- /**
- * identifier is a unique name of the client
- *
- * @generated from field: required string identifier = 1;
- */
- identifier?: string;
-
- /**
- * signature can optionally be specified to enable secure communication
- *
- * @generated from field: optional Signature signature = 2;
- */
- signature?: SignatureJson;
-};
-
-/**
- * Describes the message AutoRefRegistration.
- * Use `create(AutoRefRegistrationSchema)` to create a new message.
- */
-export const AutoRefRegistrationSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_rcon_autoref, 0);
-
-/**
- * AutoRefToController is the wrapper message for all subsequent messages from the autoRef to the controller
- *
- * @generated from message AutoRefToController
- */
-export type AutoRefToController = Message<"AutoRefToController"> & {
- /**
- * signature can optionally be specified to enable secure communication
- *
- * @generated from field: optional Signature signature = 1;
- */
- signature?: Signature;
-
- /**
- * game_event is an optional event that the autoRef detected during the game
- *
- * @generated from field: optional GameEvent game_event = 2;
- */
- gameEvent?: GameEvent;
-};
-
-/**
- * AutoRefToController is the wrapper message for all subsequent messages from the autoRef to the controller
- *
- * @generated from message AutoRefToController
- */
-export type AutoRefToControllerJson = {
- /**
- * signature can optionally be specified to enable secure communication
- *
- * @generated from field: optional Signature signature = 1;
- */
- signature?: SignatureJson;
-
- /**
- * game_event is an optional event that the autoRef detected during the game
- *
- * @generated from field: optional GameEvent game_event = 2;
- */
- gameEvent?: GameEventJson;
-};
-
-/**
- * Describes the message AutoRefToController.
- * Use `create(AutoRefToControllerSchema)` to create a new message.
- */
-export const AutoRefToControllerSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_rcon_autoref, 1);
-
-/**
- * ControllerToAutoRef is the wrapper message for all messages from controller to autoRef
- *
- * @generated from message ControllerToAutoRef
- */
-export type ControllerToAutoRef = Message<"ControllerToAutoRef"> & {
- /**
- * @generated from oneof ControllerToAutoRef.msg
- */
- msg: {
- /**
- * a reply from the controller
- *
- * @generated from field: ControllerReply controller_reply = 1;
- */
- value: ControllerReply;
- case: "controllerReply";
- } | { case: undefined; value?: undefined };
-};
-
-/**
- * ControllerToAutoRef is the wrapper message for all messages from controller to autoRef
- *
- * @generated from message ControllerToAutoRef
- */
-export type ControllerToAutoRefJson = {
- /**
- * a reply from the controller
- *
- * @generated from field: ControllerReply controller_reply = 1;
- */
- controllerReply?: ControllerReplyJson;
-};
-
-/**
- * Describes the message ControllerToAutoRef.
- * Use `create(ControllerToAutoRefSchema)` to create a new message.
- */
-export const ControllerToAutoRefSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_rcon_autoref, 2);
-
diff --git a/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_pb.ts b/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_pb.ts
deleted file mode 100644
index 145c781..0000000
--- a/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_pb.ts
+++ /dev/null
@@ -1,208 +0,0 @@
-// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
-// @generated from file gamecontroller/ssl_gc_rcon.proto (syntax proto2)
-/* eslint-disable */
-
-import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
-import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
-import type { Message } from "@bufbuild/protobuf";
-
-/**
- * Describes the file gamecontroller/ssl_gc_rcon.proto.
- */
-export const file_gamecontroller_ssl_gc_rcon: GenFile = /*@__PURE__*/
- fileDesc("CiBnYW1lY29udHJvbGxlci9zc2xfZ2NfcmNvbi5wcm90byKhAgoPQ29udHJvbGxlclJlcGx5EjAKC3N0YXR1c19jb2RlGAEgASgOMhsuQ29udHJvbGxlclJlcGx5LlN0YXR1c0NvZGUSDgoGcmVhc29uGAIgASgJEhIKCm5leHRfdG9rZW4YAyABKAkSMwoMdmVyaWZpY2F0aW9uGAQgASgOMh0uQ29udHJvbGxlclJlcGx5LlZlcmlmaWNhdGlvbiI7CgpTdGF0dXNDb2RlEhcKE1VOS05PV05fU1RBVFVTX0NPREUQABIGCgJPSxABEgwKCFJFSkVDVEVEEAIiRgoMVmVyaWZpY2F0aW9uEhgKFFVOS05PV05fVkVSSUZJQ0FUSU9OEAASDAoIVkVSSUZJRUQQARIOCgpVTlZFUklGSUVEEAIiLAoJU2lnbmF0dXJlEg0KBXRva2VuGAEgAigJEhAKCHBrY3MxdjE1GAIgAigMQltCDlNzbEdjUmNvblByb3RvUAFaR2dpdGh1Yi5jb20vUm9ib0N1cC1TU0wvc3NsLXZpc2lvbi1wcm9jZXNzb3IvZ3VpL2ludGVybmFsL2dhbWVjb250cm9sbGVy");
-
-/**
- * a reply that is sent by the controller for each request from teams or autoRefs
- *
- * @generated from message ControllerReply
- */
-export type ControllerReply = Message<"ControllerReply"> & {
- /**
- * status_code is an optional code that indicates the result of the last request
- *
- * @generated from field: optional ControllerReply.StatusCode status_code = 1;
- */
- statusCode: ControllerReply_StatusCode;
-
- /**
- * reason is an optional explanation of the status code
- *
- * @generated from field: optional string reason = 2;
- */
- reason: string;
-
- /**
- * next_token must be send with the next request, if secure communication is used
- * the token is used to avoid replay attacks
- * the token is always present in the very first message before the registration starts
- * the token is not present, if secure communication is not used
- *
- * @generated from field: optional string next_token = 3;
- */
- nextToken: string;
-
- /**
- * verification indicates if the last request could be verified (secure communication)
- *
- * @generated from field: optional ControllerReply.Verification verification = 4;
- */
- verification: ControllerReply_Verification;
-};
-
-/**
- * a reply that is sent by the controller for each request from teams or autoRefs
- *
- * @generated from message ControllerReply
- */
-export type ControllerReplyJson = {
- /**
- * status_code is an optional code that indicates the result of the last request
- *
- * @generated from field: optional ControllerReply.StatusCode status_code = 1;
- */
- statusCode?: ControllerReply_StatusCodeJson;
-
- /**
- * reason is an optional explanation of the status code
- *
- * @generated from field: optional string reason = 2;
- */
- reason?: string;
-
- /**
- * next_token must be send with the next request, if secure communication is used
- * the token is used to avoid replay attacks
- * the token is always present in the very first message before the registration starts
- * the token is not present, if secure communication is not used
- *
- * @generated from field: optional string next_token = 3;
- */
- nextToken?: string;
-
- /**
- * verification indicates if the last request could be verified (secure communication)
- *
- * @generated from field: optional ControllerReply.Verification verification = 4;
- */
- verification?: ControllerReply_VerificationJson;
-};
-
-/**
- * Describes the message ControllerReply.
- * Use `create(ControllerReplySchema)` to create a new message.
- */
-export const ControllerReplySchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_rcon, 0);
-
-/**
- * @generated from enum ControllerReply.StatusCode
- */
-export enum ControllerReply_StatusCode {
- /**
- * @generated from enum value: UNKNOWN_STATUS_CODE = 0;
- */
- UNKNOWN_STATUS_CODE = 0,
-
- /**
- * @generated from enum value: OK = 1;
- */
- OK = 1,
-
- /**
- * @generated from enum value: REJECTED = 2;
- */
- REJECTED = 2,
-}
-
-/**
- * @generated from enum ControllerReply.StatusCode
- */
-export type ControllerReply_StatusCodeJson = "UNKNOWN_STATUS_CODE" | "OK" | "REJECTED";
-
-/**
- * Describes the enum ControllerReply.StatusCode.
- */
-export const ControllerReply_StatusCodeSchema: GenEnum = /*@__PURE__*/
- enumDesc(file_gamecontroller_ssl_gc_rcon, 0, 0);
-
-/**
- * @generated from enum ControllerReply.Verification
- */
-export enum ControllerReply_Verification {
- /**
- * @generated from enum value: UNKNOWN_VERIFICATION = 0;
- */
- UNKNOWN_VERIFICATION = 0,
-
- /**
- * @generated from enum value: VERIFIED = 1;
- */
- VERIFIED = 1,
-
- /**
- * @generated from enum value: UNVERIFIED = 2;
- */
- UNVERIFIED = 2,
-}
-
-/**
- * @generated from enum ControllerReply.Verification
- */
-export type ControllerReply_VerificationJson = "UNKNOWN_VERIFICATION" | "VERIFIED" | "UNVERIFIED";
-
-/**
- * Describes the enum ControllerReply.Verification.
- */
-export const ControllerReply_VerificationSchema: GenEnum = /*@__PURE__*/
- enumDesc(file_gamecontroller_ssl_gc_rcon, 0, 1);
-
-/**
- * Signature can be added to a request to let it be verfied by the controller
- *
- * @generated from message Signature
- */
-export type Signature = Message<"Signature"> & {
- /**
- * the token that was received with the last controller reply
- *
- * @generated from field: required string token = 1;
- */
- token: string;
-
- /**
- * the PKCS1v15 signature of this message
- *
- * @generated from field: required bytes pkcs1v15 = 2;
- */
- pkcs1v15: Uint8Array;
-};
-
-/**
- * Signature can be added to a request to let it be verfied by the controller
- *
- * @generated from message Signature
- */
-export type SignatureJson = {
- /**
- * the token that was received with the last controller reply
- *
- * @generated from field: required string token = 1;
- */
- token?: string;
-
- /**
- * the PKCS1v15 signature of this message
- *
- * @generated from field: required bytes pkcs1v15 = 2;
- */
- pkcs1v15?: string;
-};
-
-/**
- * Describes the message Signature.
- * Use `create(SignatureSchema)` to create a new message.
- */
-export const SignatureSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_rcon, 1);
-
diff --git a/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_remotecontrol_pb.ts b/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_remotecontrol_pb.ts
deleted file mode 100644
index b6edcf4..0000000
--- a/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_remotecontrol_pb.ts
+++ /dev/null
@@ -1,565 +0,0 @@
-// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
-// @generated from file gamecontroller/ssl_gc_rcon_remotecontrol.proto (syntax proto2)
-/* eslint-disable */
-
-import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
-import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
-import type { Team, TeamJson } from "./ssl_gc_common_pb";
-import { file_gamecontroller_ssl_gc_common } from "./ssl_gc_common_pb";
-import type { ControllerReply, ControllerReplyJson, Signature, SignatureJson } from "./ssl_gc_rcon_pb";
-import { file_gamecontroller_ssl_gc_rcon } from "./ssl_gc_rcon_pb";
-import type { Message } from "@bufbuild/protobuf";
-
-/**
- * Describes the file gamecontroller/ssl_gc_rcon_remotecontrol.proto.
- */
-export const file_gamecontroller_ssl_gc_rcon_remotecontrol: GenFile = /*@__PURE__*/
- fileDesc("Ci5nYW1lY29udHJvbGxlci9zc2xfZ2NfcmNvbl9yZW1vdGVjb250cm9sLnByb3RvIk8KGVJlbW90ZUNvbnRyb2xSZWdpc3RyYXRpb24SEwoEdGVhbRgBIAIoDjIFLlRlYW0SHQoJc2lnbmF0dXJlGAIgASgLMgouU2lnbmF0dXJlItUCChlSZW1vdGVDb250cm9sVG9Db250cm9sbGVyEh0KCXNpZ25hdHVyZRgBIAEoCzIKLlNpZ25hdHVyZRI1CgdyZXF1ZXN0GAIgASgOMiIuUmVtb3RlQ29udHJvbFRvQ29udHJvbGxlci5SZXF1ZXN0SAASGAoOZGVzaXJlZF9rZWVwZXIYAyABKAVIABIkChpyZXF1ZXN0X3JvYm90X3N1YnN0aXR1dGlvbhgEIAEoCEgAEhkKD3JlcXVlc3RfdGltZW91dBgFIAEoCEgAEiAKFnJlcXVlc3RfZW1lcmdlbmN5X3N0b3AYBiABKAhIACJeCgdSZXF1ZXN0EgsKB1VOS05PV04QABIICgRQSU5HEAESEgoOQ0hBTExFTkdFX0ZMQUcQAhIQCgxTVE9QX1RJTUVPVVQQAxIWChJGQUlMX0JBTExQTEFDRU1FTlQQBEIFCgNtc2cibwoZQ29udHJvbGxlclRvUmVtb3RlQ29udHJvbBIqChBjb250cm9sbGVyX3JlcGx5GAEgASgLMhAuQ29udHJvbGxlclJlcGx5EiYKBXN0YXRlGAIgASgLMhcuUmVtb3RlQ29udHJvbFRlYW1TdGF0ZSK/AwoWUmVtb3RlQ29udHJvbFRlYW1TdGF0ZRITCgR0ZWFtGAwgASgOMgUuVGVhbRI1ChJhdmFpbGFibGVfcmVxdWVzdHMYASADKA4yGS5SZW1vdGVDb250cm9sUmVxdWVzdFR5cGUSMgoPYWN0aXZlX3JlcXVlc3RzGAIgAygOMhkuUmVtb3RlQ29udHJvbFJlcXVlc3RUeXBlEhEKCWtlZXBlcl9pZBgDIAEoBRIZChFlbWVyZ2VuY3lfc3RvcF9pbhgEIAEoAhIVCg10aW1lb3V0c19sZWZ0GAUgASgFEhkKEXRpbWVvdXRfdGltZV9sZWZ0GAogASgCEhwKFGNoYWxsZW5nZV9mbGFnc19sZWZ0GAYgASgFEhIKCm1heF9yb2JvdHMYByABKAUSFwoPcm9ib3RzX29uX2ZpZWxkGAkgASgFEhgKEHllbGxvd19jYXJkc19kdWUYCCADKAISHAoUY2FuX3N1YnN0aXR1dGVfcm9ib3QYCyABKAgSHgoWYm90X3N1YnN0aXR1dGlvbnNfbGVmdBgNIAEoDRIiChpib3Rfc3Vic3RpdHV0aW9uX3RpbWVfbGVmdBgOIAEoAirBAQoYUmVtb3RlQ29udHJvbFJlcXVlc3RUeXBlEhgKFFVOS05PV05fUkVRVUVTVF9UWVBFEAASEgoORU1FUkdFTkNZX1NUT1AQARIWChJST0JPVF9TVUJTVElUVVRJT04QAhILCgdUSU1FT1VUEAMSEgoOQ0hBTExFTkdFX0ZMQUcQBBIUChBDSEFOR0VfS0VFUEVSX0lEEAUSEAoMU1RPUF9USU1FT1VUEAYSFgoSRkFJTF9CQUxMUExBQ0VNRU5UEAdCaEIbU3NsR2NSY29uUmVtb3RlY29udHJvbFByb3RvUAFaR2dpdGh1Yi5jb20vUm9ib0N1cC1TU0wvc3NsLXZpc2lvbi1wcm9jZXNzb3IvZ3VpL2ludGVybmFsL2dhbWVjb250cm9sbGVy", [file_gamecontroller_ssl_gc_common, file_gamecontroller_ssl_gc_rcon]);
-
-/**
- * a registration that must be send by the remote control to the controller as the very first message
- *
- * @generated from message RemoteControlRegistration
- */
-export type RemoteControlRegistration = Message<"RemoteControlRegistration"> & {
- /**
- * the team to be controlled
- *
- * @generated from field: required Team team = 1;
- */
- team: Team;
-
- /**
- * signature can optionally be specified to enable secure communication
- *
- * @generated from field: optional Signature signature = 2;
- */
- signature?: Signature;
-};
-
-/**
- * a registration that must be send by the remote control to the controller as the very first message
- *
- * @generated from message RemoteControlRegistration
- */
-export type RemoteControlRegistrationJson = {
- /**
- * the team to be controlled
- *
- * @generated from field: required Team team = 1;
- */
- team?: TeamJson;
-
- /**
- * signature can optionally be specified to enable secure communication
- *
- * @generated from field: optional Signature signature = 2;
- */
- signature?: SignatureJson;
-};
-
-/**
- * Describes the message RemoteControlRegistration.
- * Use `create(RemoteControlRegistrationSchema)` to create a new message.
- */
-export const RemoteControlRegistrationSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_rcon_remotecontrol, 0);
-
-/**
- * wrapper for all messages from the remote control to the controller
- *
- * @generated from message RemoteControlToController
- */
-export type RemoteControlToController = Message<"RemoteControlToController"> & {
- /**
- * signature can optionally be specified to enable secure communication
- *
- * @generated from field: optional Signature signature = 1;
- */
- signature?: Signature;
-
- /**
- * @generated from oneof RemoteControlToController.msg
- */
- msg: {
- /**
- * send a request to the GC
- *
- * @generated from field: RemoteControlToController.Request request = 2;
- */
- value: RemoteControlToController_Request;
- case: "request";
- } | {
- /**
- * request a new desired keeper id
- *
- * @generated from field: int32 desired_keeper = 3;
- */
- value: number;
- case: "desiredKeeper";
- } | {
- /**
- * true: request to substitute a robot at the next possibility
- * false: cancel request
- *
- * @generated from field: bool request_robot_substitution = 4;
- */
- value: boolean;
- case: "requestRobotSubstitution";
- } | {
- /**
- * true: request a timeout with the next stoppage
- * false: cancel the request
- *
- * @generated from field: bool request_timeout = 5;
- */
- value: boolean;
- case: "requestTimeout";
- } | {
- /**
- * true: initiate an emergency stop
- * false: cancel the request
- *
- * @generated from field: bool request_emergency_stop = 6;
- */
- value: boolean;
- case: "requestEmergencyStop";
- } | { case: undefined; value?: undefined };
-};
-
-/**
- * wrapper for all messages from the remote control to the controller
- *
- * @generated from message RemoteControlToController
- */
-export type RemoteControlToControllerJson = {
- /**
- * signature can optionally be specified to enable secure communication
- *
- * @generated from field: optional Signature signature = 1;
- */
- signature?: SignatureJson;
-
- /**
- * send a request to the GC
- *
- * @generated from field: RemoteControlToController.Request request = 2;
- */
- request?: RemoteControlToController_RequestJson;
-
- /**
- * request a new desired keeper id
- *
- * @generated from field: int32 desired_keeper = 3;
- */
- desiredKeeper?: number;
-
- /**
- * true: request to substitute a robot at the next possibility
- * false: cancel request
- *
- * @generated from field: bool request_robot_substitution = 4;
- */
- requestRobotSubstitution?: boolean;
-
- /**
- * true: request a timeout with the next stoppage
- * false: cancel the request
- *
- * @generated from field: bool request_timeout = 5;
- */
- requestTimeout?: boolean;
-
- /**
- * true: initiate an emergency stop
- * false: cancel the request
- *
- * @generated from field: bool request_emergency_stop = 6;
- */
- requestEmergencyStop?: boolean;
-};
-
-/**
- * Describes the message RemoteControlToController.
- * Use `create(RemoteControlToControllerSchema)` to create a new message.
- */
-export const RemoteControlToControllerSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_rcon_remotecontrol, 1);
-
-/**
- * @generated from enum RemoteControlToController.Request
- */
-export enum RemoteControlToController_Request {
- /**
- * @generated from enum value: UNKNOWN = 0;
- */
- UNKNOWN = 0,
-
- /**
- * Ping the GC to test the connection. The GC will respond with OK and the current team state
- *
- * @generated from enum value: PING = 1;
- */
- PING = 1,
-
- /**
- * Raise a challenge flag (this is not revocable)
- *
- * @generated from enum value: CHALLENGE_FLAG = 2;
- */
- CHALLENGE_FLAG = 2,
-
- /**
- * Stop an ongoing timeout
- *
- * @generated from enum value: STOP_TIMEOUT = 3;
- */
- STOP_TIMEOUT = 3,
-
- /**
- * Fail a ball placement
- *
- * @generated from enum value: FAIL_BALLPLACEMENT = 4;
- */
- FAIL_BALLPLACEMENT = 4,
-}
-
-/**
- * @generated from enum RemoteControlToController.Request
- */
-export type RemoteControlToController_RequestJson = "UNKNOWN" | "PING" | "CHALLENGE_FLAG" | "STOP_TIMEOUT" | "FAIL_BALLPLACEMENT";
-
-/**
- * Describes the enum RemoteControlToController.Request.
- */
-export const RemoteControlToController_RequestSchema: GenEnum = /*@__PURE__*/
- enumDesc(file_gamecontroller_ssl_gc_rcon_remotecontrol, 1, 0);
-
-/**
- * wrapper for all messages from controller to a team's computer
- *
- * @generated from message ControllerToRemoteControl
- */
-export type ControllerToRemoteControl = Message<"ControllerToRemoteControl"> & {
- /**
- * a reply from the controller
- *
- * @generated from field: optional ControllerReply controller_reply = 1;
- */
- controllerReply?: ControllerReply;
-
- /**
- * current team state
- *
- * @generated from field: optional RemoteControlTeamState state = 2;
- */
- state?: RemoteControlTeamState;
-};
-
-/**
- * wrapper for all messages from controller to a team's computer
- *
- * @generated from message ControllerToRemoteControl
- */
-export type ControllerToRemoteControlJson = {
- /**
- * a reply from the controller
- *
- * @generated from field: optional ControllerReply controller_reply = 1;
- */
- controllerReply?: ControllerReplyJson;
-
- /**
- * current team state
- *
- * @generated from field: optional RemoteControlTeamState state = 2;
- */
- state?: RemoteControlTeamStateJson;
-};
-
-/**
- * Describes the message ControllerToRemoteControl.
- * Use `create(ControllerToRemoteControlSchema)` to create a new message.
- */
-export const ControllerToRemoteControlSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_rcon_remotecontrol, 2);
-
-/**
- * Current team state from Controller for remote control
- *
- * @generated from message RemoteControlTeamState
- */
-export type RemoteControlTeamState = Message<"RemoteControlTeamState"> & {
- /**
- * the team that is controlled
- *
- * @generated from field: optional Team team = 12;
- */
- team: Team;
-
- /**
- * list of all currently available request types that can be made
- *
- * @generated from field: repeated RemoteControlRequestType available_requests = 1;
- */
- availableRequests: RemoteControlRequestType[];
-
- /**
- * list of all currently active request types that are pending
- *
- * @generated from field: repeated RemoteControlRequestType active_requests = 2;
- */
- activeRequests: RemoteControlRequestType[];
-
- /**
- * currently set keeper id
- *
- * @generated from field: optional int32 keeper_id = 3;
- */
- keeperId: number;
-
- /**
- * number of seconds till emergency stop is executed
- * zero, if no emergency stop requested
- *
- * @generated from field: optional float emergency_stop_in = 4;
- */
- emergencyStopIn: number;
-
- /**
- * number of timeouts left for the team
- *
- * @generated from field: optional int32 timeouts_left = 5;
- */
- timeoutsLeft: number;
-
- /**
- * number of seconds left for timeout for the team
- *
- * @generated from field: optional float timeout_time_left = 10;
- */
- timeoutTimeLeft: number;
-
- /**
- * number of challenge flags left for the team
- *
- * @generated from field: optional int32 challenge_flags_left = 6;
- */
- challengeFlagsLeft: number;
-
- /**
- * max number of robots currently allowed
- *
- * @generated from field: optional int32 max_robots = 7;
- */
- maxRobots: number;
-
- /**
- * current number of robots visible on field
- *
- * @generated from field: optional int32 robots_on_field = 9;
- */
- robotsOnField: number;
-
- /**
- * list of due times for each active yellow card (in seconds)
- *
- * @generated from field: repeated float yellow_cards_due = 8;
- */
- yellowCardsDue: number[];
-
- /**
- * if true, team is allowed to substitute robots
- *
- * @generated from field: optional bool can_substitute_robot = 11;
- */
- canSubstituteRobot: boolean;
-
- /**
- * number of bot substitutions left by the team in this halftime
- *
- * @generated from field: optional uint32 bot_substitutions_left = 13;
- */
- botSubstitutionsLeft: number;
-
- /**
- * number of seconds left for current bot substitution
- *
- * @generated from field: optional float bot_substitution_time_left = 14;
- */
- botSubstitutionTimeLeft: number;
-};
-
-/**
- * Current team state from Controller for remote control
- *
- * @generated from message RemoteControlTeamState
- */
-export type RemoteControlTeamStateJson = {
- /**
- * the team that is controlled
- *
- * @generated from field: optional Team team = 12;
- */
- team?: TeamJson;
-
- /**
- * list of all currently available request types that can be made
- *
- * @generated from field: repeated RemoteControlRequestType available_requests = 1;
- */
- availableRequests?: RemoteControlRequestTypeJson[];
-
- /**
- * list of all currently active request types that are pending
- *
- * @generated from field: repeated RemoteControlRequestType active_requests = 2;
- */
- activeRequests?: RemoteControlRequestTypeJson[];
-
- /**
- * currently set keeper id
- *
- * @generated from field: optional int32 keeper_id = 3;
- */
- keeperId?: number;
-
- /**
- * number of seconds till emergency stop is executed
- * zero, if no emergency stop requested
- *
- * @generated from field: optional float emergency_stop_in = 4;
- */
- emergencyStopIn?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * number of timeouts left for the team
- *
- * @generated from field: optional int32 timeouts_left = 5;
- */
- timeoutsLeft?: number;
-
- /**
- * number of seconds left for timeout for the team
- *
- * @generated from field: optional float timeout_time_left = 10;
- */
- timeoutTimeLeft?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * number of challenge flags left for the team
- *
- * @generated from field: optional int32 challenge_flags_left = 6;
- */
- challengeFlagsLeft?: number;
-
- /**
- * max number of robots currently allowed
- *
- * @generated from field: optional int32 max_robots = 7;
- */
- maxRobots?: number;
-
- /**
- * current number of robots visible on field
- *
- * @generated from field: optional int32 robots_on_field = 9;
- */
- robotsOnField?: number;
-
- /**
- * list of due times for each active yellow card (in seconds)
- *
- * @generated from field: repeated float yellow_cards_due = 8;
- */
- yellowCardsDue?: (number | "NaN" | "Infinity" | "-Infinity")[];
-
- /**
- * if true, team is allowed to substitute robots
- *
- * @generated from field: optional bool can_substitute_robot = 11;
- */
- canSubstituteRobot?: boolean;
-
- /**
- * number of bot substitutions left by the team in this halftime
- *
- * @generated from field: optional uint32 bot_substitutions_left = 13;
- */
- botSubstitutionsLeft?: number;
-
- /**
- * number of seconds left for current bot substitution
- *
- * @generated from field: optional float bot_substitution_time_left = 14;
- */
- botSubstitutionTimeLeft?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message RemoteControlTeamState.
- * Use `create(RemoteControlTeamStateSchema)` to create a new message.
- */
-export const RemoteControlTeamStateSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_rcon_remotecontrol, 3);
-
-/**
- * All possible request types that the remote control can make
- *
- * @generated from enum RemoteControlRequestType
- */
-export enum RemoteControlRequestType {
- /**
- * @generated from enum value: UNKNOWN_REQUEST_TYPE = 0;
- */
- UNKNOWN_REQUEST_TYPE = 0,
-
- /**
- * @generated from enum value: EMERGENCY_STOP = 1;
- */
- EMERGENCY_STOP = 1,
-
- /**
- * @generated from enum value: ROBOT_SUBSTITUTION = 2;
- */
- ROBOT_SUBSTITUTION = 2,
-
- /**
- * @generated from enum value: TIMEOUT = 3;
- */
- TIMEOUT = 3,
-
- /**
- * @generated from enum value: CHALLENGE_FLAG = 4;
- */
- CHALLENGE_FLAG = 4,
-
- /**
- * @generated from enum value: CHANGE_KEEPER_ID = 5;
- */
- CHANGE_KEEPER_ID = 5,
-
- /**
- * @generated from enum value: STOP_TIMEOUT = 6;
- */
- STOP_TIMEOUT = 6,
-
- /**
- * @generated from enum value: FAIL_BALLPLACEMENT = 7;
- */
- FAIL_BALLPLACEMENT = 7,
-}
-
-/**
- * All possible request types that the remote control can make
- *
- * @generated from enum RemoteControlRequestType
- */
-export type RemoteControlRequestTypeJson = "UNKNOWN_REQUEST_TYPE" | "EMERGENCY_STOP" | "ROBOT_SUBSTITUTION" | "TIMEOUT" | "CHALLENGE_FLAG" | "CHANGE_KEEPER_ID" | "STOP_TIMEOUT" | "FAIL_BALLPLACEMENT";
-
-/**
- * Describes the enum RemoteControlRequestType.
- */
-export const RemoteControlRequestTypeSchema: GenEnum = /*@__PURE__*/
- enumDesc(file_gamecontroller_ssl_gc_rcon_remotecontrol, 0);
-
diff --git a/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_team_pb.ts b/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_team_pb.ts
deleted file mode 100644
index ad0578f..0000000
--- a/gui/frontend/src/proto/gamecontroller/ssl_gc_rcon_team_pb.ts
+++ /dev/null
@@ -1,264 +0,0 @@
-// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
-// @generated from file gamecontroller/ssl_gc_rcon_team.proto (syntax proto2)
-/* eslint-disable */
-
-import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
-import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
-import type { Team, TeamJson } from "./ssl_gc_common_pb";
-import { file_gamecontroller_ssl_gc_common } from "./ssl_gc_common_pb";
-import type { ControllerReply, ControllerReplyJson, Signature, SignatureJson } from "./ssl_gc_rcon_pb";
-import { file_gamecontroller_ssl_gc_rcon } from "./ssl_gc_rcon_pb";
-import type { Message } from "@bufbuild/protobuf";
-
-/**
- * Describes the file gamecontroller/ssl_gc_rcon_team.proto.
- */
-export const file_gamecontroller_ssl_gc_rcon_team: GenFile = /*@__PURE__*/
- fileDesc("CiVnYW1lY29udHJvbGxlci9zc2xfZ2NfcmNvbl90ZWFtLnByb3RvIlkKEFRlYW1SZWdpc3RyYXRpb24SEQoJdGVhbV9uYW1lGAEgAigJEh0KCXNpZ25hdHVyZRgCIAEoCzIKLlNpZ25hdHVyZRITCgR0ZWFtGAMgASgOMgUuVGVhbSKqAQoQVGVhbVRvQ29udHJvbGxlchIdCglzaWduYXR1cmUYASABKAsyCi5TaWduYXR1cmUSGAoOZGVzaXJlZF9rZWVwZXIYAiABKAVIABIsChBhZHZhbnRhZ2VfY2hvaWNlGAMgASgOMhAuQWR2YW50YWdlQ2hvaWNlSAASGAoOc3Vic3RpdHV0ZV9ib3QYBCABKAhIABIOCgRwaW5nGAUgASgISABCBQoDbXNnIk0KEENvbnRyb2xsZXJUb1RlYW0SLAoQY29udHJvbGxlcl9yZXBseRgBIAEoCzIQLkNvbnRyb2xsZXJSZXBseUgAQgUKA21zZ0oECAIQAyopCg9BZHZhbnRhZ2VDaG9pY2USCAoEU1RPUBAAEgwKCENPTlRJTlVFEAFCX0ISU3NsR2NSY29uVGVhbVByb3RvUAFaR2dpdGh1Yi5jb20vUm9ib0N1cC1TU0wvc3NsLXZpc2lvbi1wcm9jZXNzb3IvZ3VpL2ludGVybmFsL2dhbWVjb250cm9sbGVy", [file_gamecontroller_ssl_gc_common, file_gamecontroller_ssl_gc_rcon]);
-
-/**
- * a registration that must be send by teams to the controller as the very first message
- *
- * @generated from message TeamRegistration
- */
-export type TeamRegistration = Message<"TeamRegistration"> & {
- /**
- * the exact team name as published by the game-controller
- *
- * @generated from field: required string team_name = 1;
- */
- teamName: string;
-
- /**
- * signature can optionally be specified to enable secure communication
- *
- * @generated from field: optional Signature signature = 2;
- */
- signature?: Signature;
-
- /**
- * the team (relevant only if a team plays against itself)
- *
- * @generated from field: optional Team team = 3;
- */
- team: Team;
-};
-
-/**
- * a registration that must be send by teams to the controller as the very first message
- *
- * @generated from message TeamRegistration
- */
-export type TeamRegistrationJson = {
- /**
- * the exact team name as published by the game-controller
- *
- * @generated from field: required string team_name = 1;
- */
- teamName?: string;
-
- /**
- * signature can optionally be specified to enable secure communication
- *
- * @generated from field: optional Signature signature = 2;
- */
- signature?: SignatureJson;
-
- /**
- * the team (relevant only if a team plays against itself)
- *
- * @generated from field: optional Team team = 3;
- */
- team?: TeamJson;
-};
-
-/**
- * Describes the message TeamRegistration.
- * Use `create(TeamRegistrationSchema)` to create a new message.
- */
-export const TeamRegistrationSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_rcon_team, 0);
-
-/**
- * wrapper for all messages from a team's computer to the controller
- *
- * @generated from message TeamToController
- */
-export type TeamToController = Message<"TeamToController"> & {
- /**
- * signature can optionally be specified to enable secure communication
- *
- * @generated from field: optional Signature signature = 1;
- */
- signature?: Signature;
-
- /**
- * @generated from oneof TeamToController.msg
- */
- msg: {
- /**
- * request a new desired keeper id
- *
- * @generated from field: int32 desired_keeper = 2;
- */
- value: number;
- case: "desiredKeeper";
- } | {
- /**
- * response to an advantage choice request
- *
- * @generated from field: AdvantageChoice advantage_choice = 3;
- */
- value: AdvantageChoice;
- case: "advantageChoice";
- } | {
- /**
- * request to substitute a robot at the next possibility
- *
- * @generated from field: bool substitute_bot = 4;
- */
- value: boolean;
- case: "substituteBot";
- } | {
- /**
- * send a ping to the GC to test if the connection is still open.
- * the value is ignored and a reply is sent back
- *
- * @generated from field: bool ping = 5;
- */
- value: boolean;
- case: "ping";
- } | { case: undefined; value?: undefined };
-};
-
-/**
- * wrapper for all messages from a team's computer to the controller
- *
- * @generated from message TeamToController
- */
-export type TeamToControllerJson = {
- /**
- * signature can optionally be specified to enable secure communication
- *
- * @generated from field: optional Signature signature = 1;
- */
- signature?: SignatureJson;
-
- /**
- * request a new desired keeper id
- *
- * @generated from field: int32 desired_keeper = 2;
- */
- desiredKeeper?: number;
-
- /**
- * response to an advantage choice request
- *
- * @generated from field: AdvantageChoice advantage_choice = 3;
- */
- advantageChoice?: AdvantageChoiceJson;
-
- /**
- * request to substitute a robot at the next possibility
- *
- * @generated from field: bool substitute_bot = 4;
- */
- substituteBot?: boolean;
-
- /**
- * send a ping to the GC to test if the connection is still open.
- * the value is ignored and a reply is sent back
- *
- * @generated from field: bool ping = 5;
- */
- ping?: boolean;
-};
-
-/**
- * Describes the message TeamToController.
- * Use `create(TeamToControllerSchema)` to create a new message.
- */
-export const TeamToControllerSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_rcon_team, 1);
-
-/**
- * wrapper for all messages from controller to a team's computer
- *
- * @generated from message ControllerToTeam
- */
-export type ControllerToTeam = Message<"ControllerToTeam"> & {
- /**
- * @generated from oneof ControllerToTeam.msg
- */
- msg: {
- /**
- * a reply from the controller
- *
- * @generated from field: ControllerReply controller_reply = 1;
- */
- value: ControllerReply;
- case: "controllerReply";
- } | { case: undefined; value?: undefined };
-};
-
-/**
- * wrapper for all messages from controller to a team's computer
- *
- * @generated from message ControllerToTeam
- */
-export type ControllerToTeamJson = {
- /**
- * a reply from the controller
- *
- * @generated from field: ControllerReply controller_reply = 1;
- */
- controllerReply?: ControllerReplyJson;
-};
-
-/**
- * Describes the message ControllerToTeam.
- * Use `create(ControllerToTeamSchema)` to create a new message.
- */
-export const ControllerToTeamSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_rcon_team, 2);
-
-/**
- * the current advantage choice of the team
- * the choice is valid until another choice is received
- * if the team disconnects, the choice is reset to its default (STOP)
- * teams may either send their current choice continuously or only on change
- *
- * @generated from enum AdvantageChoice
- */
-export enum AdvantageChoice {
- /**
- * stop the game
- *
- * @generated from enum value: STOP = 0;
- */
- STOP = 0,
-
- /**
- * keep the game running
- *
- * @generated from enum value: CONTINUE = 1;
- */
- CONTINUE = 1,
-}
-
-/**
- * the current advantage choice of the team
- * the choice is valid until another choice is received
- * if the team disconnects, the choice is reset to its default (STOP)
- * teams may either send their current choice continuously or only on change
- *
- * @generated from enum AdvantageChoice
- */
-export type AdvantageChoiceJson = "STOP" | "CONTINUE";
-
-/**
- * Describes the enum AdvantageChoice.
- */
-export const AdvantageChoiceSchema: GenEnum = /*@__PURE__*/
- enumDesc(file_gamecontroller_ssl_gc_rcon_team, 0);
-
diff --git a/gui/frontend/src/proto/gamecontroller/ssl_gc_referee_message_pb.ts b/gui/frontend/src/proto/gamecontroller/ssl_gc_referee_message_pb.ts
deleted file mode 100644
index 3c96c03..0000000
--- a/gui/frontend/src/proto/gamecontroller/ssl_gc_referee_message_pb.ts
+++ /dev/null
@@ -1,1055 +0,0 @@
-// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
-// @generated from file gamecontroller/ssl_gc_referee_message.proto (syntax proto2)
-/* eslint-disable */
-
-import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
-import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
-import type { GameEvent, GameEventJson } from "./ssl_gc_game_event_pb";
-import { file_gamecontroller_ssl_gc_game_event } from "./ssl_gc_game_event_pb";
-import type { Message } from "@bufbuild/protobuf";
-
-/**
- * Describes the file gamecontroller/ssl_gc_referee_message.proto.
- */
-export const file_gamecontroller_ssl_gc_referee_message: GenFile = /*@__PURE__*/
- fileDesc("CitnYW1lY29udHJvbGxlci9zc2xfZ2NfcmVmZXJlZV9tZXNzYWdlLnByb3RvItUOCgdSZWZlcmVlEhkKEXNvdXJjZV9pZGVudGlmaWVyGBIgASgJEi0KCm1hdGNoX3R5cGUYEyABKA4yCi5NYXRjaFR5cGU6DVVOS05PV05fTUFUQ0gSGAoQcGFja2V0X3RpbWVzdGFtcBgBIAIoBBIdCgVzdGFnZRgCIAIoDjIOLlJlZmVyZWUuU3RhZ2USFwoPc3RhZ2VfdGltZV9sZWZ0GAMgASgSEiEKB2NvbW1hbmQYBCACKA4yEC5SZWZlcmVlLkNvbW1hbmQSFwoPY29tbWFuZF9jb3VudGVyGAUgAigNEhkKEWNvbW1hbmRfdGltZXN0YW1wGAYgAigEEiEKBnllbGxvdxgHIAIoCzIRLlJlZmVyZWUuVGVhbUluZm8SHwoEYmx1ZRgIIAIoCzIRLlJlZmVyZWUuVGVhbUluZm8SKwoTZGVzaWduYXRlZF9wb3NpdGlvbhgJIAEoCzIOLlJlZmVyZWUuUG9pbnQSIgoaYmx1ZV90ZWFtX29uX3Bvc2l0aXZlX2hhbGYYCiABKAgSJgoMbmV4dF9jb21tYW5kGAwgASgOMhAuUmVmZXJlZS5Db21tYW5kEh8KC2dhbWVfZXZlbnRzGBAgAygLMgouR2FtZUV2ZW50EjUKFGdhbWVfZXZlbnRfcHJvcG9zYWxzGBEgAygLMhcuR2FtZUV2ZW50UHJvcG9zYWxHcm91cBIlCh1jdXJyZW50X2FjdGlvbl90aW1lX3JlbWFpbmluZxgPIAEoAxIWCg5zdGF0dXNfbWVzc2FnZRgUIAEoCRrkAwoIVGVhbUluZm8SDAoEbmFtZRgBIAIoCRINCgVzY29yZRgCIAIoDRIRCglyZWRfY2FyZHMYAyACKA0SHQoReWVsbG93X2NhcmRfdGltZXMYBCADKA1CAhABEhQKDHllbGxvd19jYXJkcxgFIAIoDRIQCgh0aW1lb3V0cxgGIAIoDRIUCgx0aW1lb3V0X3RpbWUYByACKA0SEgoKZ29hbGtlZXBlchgIIAIoDRIUCgxmb3VsX2NvdW50ZXIYCSABKA0SHwoXYmFsbF9wbGFjZW1lbnRfZmFpbHVyZXMYCiABKA0SFgoOY2FuX3BsYWNlX2JhbGwYDCABKAgSGAoQbWF4X2FsbG93ZWRfYm90cxgNIAEoDRIfChdib3Rfc3Vic3RpdHV0aW9uX2ludGVudBgOIAEoCBInCh9iYWxsX3BsYWNlbWVudF9mYWlsdXJlc19yZWFjaGVkGA8gASgIEiAKGGJvdF9zdWJzdGl0dXRpb25fYWxsb3dlZBgQIAEoCBIeChZib3Rfc3Vic3RpdHV0aW9uc19sZWZ0GBEgASgNEiIKGmJvdF9zdWJzdGl0dXRpb25fdGltZV9sZWZ0GBIgASgNEh4KCmh1bGxfY29sb3IYEyABKA4yCi5IdWxsQ29sb3IaHQoFUG9pbnQSCQoBeBgBIAIoAhIJCgF5GAIgAigCItECCgVTdGFnZRIZChVOT1JNQUxfRklSU1RfSEFMRl9QUkUQABIVChFOT1JNQUxfRklSU1RfSEFMRhABEhQKEE5PUk1BTF9IQUxGX1RJTUUQAhIaChZOT1JNQUxfU0VDT05EX0hBTEZfUFJFEAMSFgoSTk9STUFMX1NFQ09ORF9IQUxGEAQSFAoQRVhUUkFfVElNRV9CUkVBSxAFEhgKFEVYVFJBX0ZJUlNUX0hBTEZfUFJFEAYSFAoQRVhUUkFfRklSU1RfSEFMRhAHEhMKD0VYVFJBX0hBTEZfVElNRRAIEhkKFUVYVFJBX1NFQ09ORF9IQUxGX1BSRRAJEhUKEUVYVFJBX1NFQ09ORF9IQUxGEAoSGgoWUEVOQUxUWV9TSE9PVE9VVF9CUkVBSxALEhQKEFBFTkFMVFlfU0hPT1RPVVQQDBINCglQT1NUX0dBTUUQDSKWAwoHQ29tbWFuZBIICgRIQUxUEAASCAoEU1RPUBABEhAKDE5PUk1BTF9TVEFSVBACEg8KC0ZPUkNFX1NUQVJUEAMSGgoWUFJFUEFSRV9LSUNLT0ZGX1lFTExPVxAEEhgKFFBSRVBBUkVfS0lDS09GRl9CTFVFEAUSGgoWUFJFUEFSRV9QRU5BTFRZX1lFTExPVxAGEhgKFFBSRVBBUkVfUEVOQUxUWV9CTFVFEAcSFgoSRElSRUNUX0ZSRUVfWUVMTE9XEAgSFAoQRElSRUNUX0ZSRUVfQkxVRRAJEhwKFElORElSRUNUX0ZSRUVfWUVMTE9XEAoaAggBEhoKEklORElSRUNUX0ZSRUVfQkxVRRALGgIIARISCg5USU1FT1VUX1lFTExPVxAMEhAKDFRJTUVPVVRfQkxVRRANEhMKC0dPQUxfWUVMTE9XEA4aAggBEhEKCUdPQUxfQkxVRRAPGgIIARIZChVCQUxMX1BMQUNFTUVOVF9ZRUxMT1cQEBIXChNCQUxMX1BMQUNFTUVOVF9CTFVFEBFKBAgLEAxKBAgNEA5KBAgOEA8iVwoWR2FtZUV2ZW50UHJvcG9zYWxHcm91cBIKCgJpZBgDIAEoCRIfCgtnYW1lX2V2ZW50cxgBIAMoCzIKLkdhbWVFdmVudBIQCghhY2NlcHRlZBgCIAEoCCpUCglNYXRjaFR5cGUSEQoNVU5LTk9XTl9NQVRDSBAAEg8KC0dST1VQX1BIQVNFEAESFQoRRUxJTUlOQVRJT05fUEhBU0UQAhIMCghGUklFTkRMWRADKk4KCUh1bGxDb2xvchIWChJIVUxMX0NPTE9SX1VOS05PV04QABITCg9IVUxMX0NPTE9SX0RBUksQARIUChBIVUxMX0NPTE9SX0xJR0hUEAJCZUIYU3NsR2NSZWZlcmVlTWVzc2FnZVByb3RvUAFaR2dpdGh1Yi5jb20vUm9ib0N1cC1TU0wvc3NsLXZpc2lvbi1wcm9jZXNzb3IvZ3VpL2ludGVybmFsL2dhbWVjb250cm9sbGVy", [file_gamecontroller_ssl_gc_game_event]);
-
-/**
- * Each UDP packet contains one of these messages.
- *
- * @generated from message Referee
- */
-export type Referee = Message<"Referee"> & {
- /**
- * A random UUID of the source that is kept constant at the source while running
- * If multiple sources are broadcasting to the same network, this id can be used to identify individual sources
- *
- * @generated from field: optional string source_identifier = 18;
- */
- sourceIdentifier: string;
-
- /**
- * The match type is a meta information about the current match that helps to process the logs after a competition
- *
- * @generated from field: optional MatchType match_type = 19 [default = UNKNOWN_MATCH];
- */
- matchType: MatchType;
-
- /**
- * The UNIX timestamp when the packet was sent, in microseconds.
- * Divide by 1,000,000 to get a time_t.
- *
- * @generated from field: required uint64 packet_timestamp = 1;
- */
- packetTimestamp: bigint;
-
- /**
- * @generated from field: required Referee.Stage stage = 2;
- */
- stage: Referee_Stage;
-
- /**
- * The number of microseconds left in the stage.
- * The following stages have this value; the rest do not:
- * NORMAL_FIRST_HALF
- * NORMAL_HALF_TIME
- * NORMAL_SECOND_HALF
- * EXTRA_TIME_BREAK
- * EXTRA_FIRST_HALF
- * EXTRA_HALF_TIME
- * EXTRA_SECOND_HALF
- * PENALTY_SHOOTOUT_BREAK
- *
- * If the stage runs over its specified time, this value
- * becomes negative.
- *
- * @generated from field: optional sint64 stage_time_left = 3;
- */
- stageTimeLeft: bigint;
-
- /**
- * @generated from field: required Referee.Command command = 4;
- */
- command: Referee_Command;
-
- /**
- * The number of commands issued since startup (mod 2^32).
- *
- * @generated from field: required uint32 command_counter = 5;
- */
- commandCounter: number;
-
- /**
- * The UNIX timestamp when the command was issued, in microseconds.
- * This value changes only when a new command is issued, not on each packet.
- *
- * @generated from field: required uint64 command_timestamp = 6;
- */
- commandTimestamp: bigint;
-
- /**
- * Information about the two teams.
- *
- * @generated from field: required Referee.TeamInfo yellow = 7;
- */
- yellow?: Referee_TeamInfo;
-
- /**
- * @generated from field: required Referee.TeamInfo blue = 8;
- */
- blue?: Referee_TeamInfo;
-
- /**
- * @generated from field: optional Referee.Point designated_position = 9;
- */
- designatedPosition?: Referee_Point;
-
- /**
- * Information about the direction of play.
- * True, if the blue team will have it's goal on the positive x-axis of the ssl-vision coordinate system.
- * Obviously, the yellow team will play on the opposite half.
- *
- * @generated from field: optional bool blue_team_on_positive_half = 10;
- */
- blueTeamOnPositiveHalf: boolean;
-
- /**
- * The command that will be issued after the current stoppage and ball placement to continue the game.
- *
- * @generated from field: optional Referee.Command next_command = 12;
- */
- nextCommand: Referee_Command;
-
- /**
- * @generated from field: repeated GameEvent game_events = 16;
- */
- gameEvents: GameEvent[];
-
- /**
- * @generated from field: repeated GameEventProposalGroup game_event_proposals = 17;
- */
- gameEventProposals: GameEventProposalGroup[];
-
- /**
- * The time in microseconds that is remaining until the current action times out
- * The time will not be reset. It can get negative.
- * An autoRef would raise an appropriate event, if the time gets negative.
- * Possible actions where this time is relevant:
- * * free kicks
- * * kickoff, penalty kick, force start
- * * ball placement
- *
- * @generated from field: optional int64 current_action_time_remaining = 15;
- */
- currentActionTimeRemaining: bigint;
-
- /**
- * A message that can be displayed to the spectators, like a reason for a stoppage.
- *
- * @generated from field: optional string status_message = 20;
- */
- statusMessage: string;
-};
-
-/**
- * Each UDP packet contains one of these messages.
- *
- * @generated from message Referee
- */
-export type RefereeJson = {
- /**
- * A random UUID of the source that is kept constant at the source while running
- * If multiple sources are broadcasting to the same network, this id can be used to identify individual sources
- *
- * @generated from field: optional string source_identifier = 18;
- */
- sourceIdentifier?: string;
-
- /**
- * The match type is a meta information about the current match that helps to process the logs after a competition
- *
- * @generated from field: optional MatchType match_type = 19 [default = UNKNOWN_MATCH];
- */
- matchType?: MatchTypeJson;
-
- /**
- * The UNIX timestamp when the packet was sent, in microseconds.
- * Divide by 1,000,000 to get a time_t.
- *
- * @generated from field: required uint64 packet_timestamp = 1;
- */
- packetTimestamp?: string;
-
- /**
- * @generated from field: required Referee.Stage stage = 2;
- */
- stage?: Referee_StageJson;
-
- /**
- * The number of microseconds left in the stage.
- * The following stages have this value; the rest do not:
- * NORMAL_FIRST_HALF
- * NORMAL_HALF_TIME
- * NORMAL_SECOND_HALF
- * EXTRA_TIME_BREAK
- * EXTRA_FIRST_HALF
- * EXTRA_HALF_TIME
- * EXTRA_SECOND_HALF
- * PENALTY_SHOOTOUT_BREAK
- *
- * If the stage runs over its specified time, this value
- * becomes negative.
- *
- * @generated from field: optional sint64 stage_time_left = 3;
- */
- stageTimeLeft?: string;
-
- /**
- * @generated from field: required Referee.Command command = 4;
- */
- command?: Referee_CommandJson;
-
- /**
- * The number of commands issued since startup (mod 2^32).
- *
- * @generated from field: required uint32 command_counter = 5;
- */
- commandCounter?: number;
-
- /**
- * The UNIX timestamp when the command was issued, in microseconds.
- * This value changes only when a new command is issued, not on each packet.
- *
- * @generated from field: required uint64 command_timestamp = 6;
- */
- commandTimestamp?: string;
-
- /**
- * Information about the two teams.
- *
- * @generated from field: required Referee.TeamInfo yellow = 7;
- */
- yellow?: Referee_TeamInfoJson;
-
- /**
- * @generated from field: required Referee.TeamInfo blue = 8;
- */
- blue?: Referee_TeamInfoJson;
-
- /**
- * @generated from field: optional Referee.Point designated_position = 9;
- */
- designatedPosition?: Referee_PointJson;
-
- /**
- * Information about the direction of play.
- * True, if the blue team will have it's goal on the positive x-axis of the ssl-vision coordinate system.
- * Obviously, the yellow team will play on the opposite half.
- *
- * @generated from field: optional bool blue_team_on_positive_half = 10;
- */
- blueTeamOnPositiveHalf?: boolean;
-
- /**
- * The command that will be issued after the current stoppage and ball placement to continue the game.
- *
- * @generated from field: optional Referee.Command next_command = 12;
- */
- nextCommand?: Referee_CommandJson;
-
- /**
- * @generated from field: repeated GameEvent game_events = 16;
- */
- gameEvents?: GameEventJson[];
-
- /**
- * @generated from field: repeated GameEventProposalGroup game_event_proposals = 17;
- */
- gameEventProposals?: GameEventProposalGroupJson[];
-
- /**
- * The time in microseconds that is remaining until the current action times out
- * The time will not be reset. It can get negative.
- * An autoRef would raise an appropriate event, if the time gets negative.
- * Possible actions where this time is relevant:
- * * free kicks
- * * kickoff, penalty kick, force start
- * * ball placement
- *
- * @generated from field: optional int64 current_action_time_remaining = 15;
- */
- currentActionTimeRemaining?: string;
-
- /**
- * A message that can be displayed to the spectators, like a reason for a stoppage.
- *
- * @generated from field: optional string status_message = 20;
- */
- statusMessage?: string;
-};
-
-/**
- * Describes the message Referee.
- * Use `create(RefereeSchema)` to create a new message.
- */
-export const RefereeSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_referee_message, 0);
-
-/**
- * Information about a single team.
- *
- * @generated from message Referee.TeamInfo
- */
-export type Referee_TeamInfo = Message<"Referee.TeamInfo"> & {
- /**
- * The team's name (empty string if operator has not typed anything).
- *
- * @generated from field: required string name = 1;
- */
- name: string;
-
- /**
- * The number of goals scored by the team during normal play and overtime.
- *
- * @generated from field: required uint32 score = 2;
- */
- score: number;
-
- /**
- * The number of red cards issued to the team since the beginning of the game.
- *
- * @generated from field: required uint32 red_cards = 3;
- */
- redCards: number;
-
- /**
- * The amount of time (in microseconds) left on each yellow card issued to the team.
- * If no yellow cards are issued, this array has no elements.
- * Otherwise, times are ordered from smallest to largest.
- *
- * @generated from field: repeated uint32 yellow_card_times = 4 [packed = true];
- */
- yellowCardTimes: number[];
-
- /**
- * The total number of yellow cards ever issued to the team.
- *
- * @generated from field: required uint32 yellow_cards = 5;
- */
- yellowCards: number;
-
- /**
- * The number of timeouts this team can still call.
- * If in a timeout right now, that timeout is excluded.
- *
- * @generated from field: required uint32 timeouts = 6;
- */
- timeouts: number;
-
- /**
- * The number of microseconds of timeout this team can use.
- *
- * @generated from field: required uint32 timeout_time = 7;
- */
- timeoutTime: number;
-
- /**
- * The pattern number of this team's goalkeeper.
- *
- * @generated from field: required uint32 goalkeeper = 8;
- */
- goalkeeper: number;
-
- /**
- * The total number of countable fouls that act towards yellow cards
- *
- * @generated from field: optional uint32 foul_counter = 9;
- */
- foulCounter: number;
-
- /**
- * The number of consecutive ball placement failures of this team
- *
- * @generated from field: optional uint32 ball_placement_failures = 10;
- */
- ballPlacementFailures: number;
-
- /**
- * Indicate if the team is able and allowed to place the ball
- *
- * @generated from field: optional bool can_place_ball = 12;
- */
- canPlaceBall: boolean;
-
- /**
- * The maximum number of bots allowed on the field based on division and cards
- *
- * @generated from field: optional uint32 max_allowed_bots = 13;
- */
- maxAllowedBots: number;
-
- /**
- * The team has submitted an intent to substitute one or more robots at the next chance
- *
- * @generated from field: optional bool bot_substitution_intent = 14;
- */
- botSubstitutionIntent: boolean;
-
- /**
- * Indicate if the team reached the maximum allowed ball placement failures and is thus not allowed to place the ball anymore
- *
- * @generated from field: optional bool ball_placement_failures_reached = 15;
- */
- ballPlacementFailuresReached: boolean;
-
- /**
- * The team is allowed to substitute one or more robots currently
- *
- * @generated from field: optional bool bot_substitution_allowed = 16;
- */
- botSubstitutionAllowed: boolean;
-
- /**
- * The number of bot substitutions left by the team in this halftime
- *
- * @generated from field: optional uint32 bot_substitutions_left = 17;
- */
- botSubstitutionsLeft: number;
-
- /**
- * The number of microseconds left for current bot substitution
- *
- * @generated from field: optional uint32 bot_substitution_time_left = 18;
- */
- botSubstitutionTimeLeft: number;
-
- /**
- * The color of the hull of the robots of this team
- *
- * @generated from field: optional HullColor hull_color = 19;
- */
- hullColor: HullColor;
-};
-
-/**
- * Information about a single team.
- *
- * @generated from message Referee.TeamInfo
- */
-export type Referee_TeamInfoJson = {
- /**
- * The team's name (empty string if operator has not typed anything).
- *
- * @generated from field: required string name = 1;
- */
- name?: string;
-
- /**
- * The number of goals scored by the team during normal play and overtime.
- *
- * @generated from field: required uint32 score = 2;
- */
- score?: number;
-
- /**
- * The number of red cards issued to the team since the beginning of the game.
- *
- * @generated from field: required uint32 red_cards = 3;
- */
- redCards?: number;
-
- /**
- * The amount of time (in microseconds) left on each yellow card issued to the team.
- * If no yellow cards are issued, this array has no elements.
- * Otherwise, times are ordered from smallest to largest.
- *
- * @generated from field: repeated uint32 yellow_card_times = 4 [packed = true];
- */
- yellowCardTimes?: number[];
-
- /**
- * The total number of yellow cards ever issued to the team.
- *
- * @generated from field: required uint32 yellow_cards = 5;
- */
- yellowCards?: number;
-
- /**
- * The number of timeouts this team can still call.
- * If in a timeout right now, that timeout is excluded.
- *
- * @generated from field: required uint32 timeouts = 6;
- */
- timeouts?: number;
-
- /**
- * The number of microseconds of timeout this team can use.
- *
- * @generated from field: required uint32 timeout_time = 7;
- */
- timeoutTime?: number;
-
- /**
- * The pattern number of this team's goalkeeper.
- *
- * @generated from field: required uint32 goalkeeper = 8;
- */
- goalkeeper?: number;
-
- /**
- * The total number of countable fouls that act towards yellow cards
- *
- * @generated from field: optional uint32 foul_counter = 9;
- */
- foulCounter?: number;
-
- /**
- * The number of consecutive ball placement failures of this team
- *
- * @generated from field: optional uint32 ball_placement_failures = 10;
- */
- ballPlacementFailures?: number;
-
- /**
- * Indicate if the team is able and allowed to place the ball
- *
- * @generated from field: optional bool can_place_ball = 12;
- */
- canPlaceBall?: boolean;
-
- /**
- * The maximum number of bots allowed on the field based on division and cards
- *
- * @generated from field: optional uint32 max_allowed_bots = 13;
- */
- maxAllowedBots?: number;
-
- /**
- * The team has submitted an intent to substitute one or more robots at the next chance
- *
- * @generated from field: optional bool bot_substitution_intent = 14;
- */
- botSubstitutionIntent?: boolean;
-
- /**
- * Indicate if the team reached the maximum allowed ball placement failures and is thus not allowed to place the ball anymore
- *
- * @generated from field: optional bool ball_placement_failures_reached = 15;
- */
- ballPlacementFailuresReached?: boolean;
-
- /**
- * The team is allowed to substitute one or more robots currently
- *
- * @generated from field: optional bool bot_substitution_allowed = 16;
- */
- botSubstitutionAllowed?: boolean;
-
- /**
- * The number of bot substitutions left by the team in this halftime
- *
- * @generated from field: optional uint32 bot_substitutions_left = 17;
- */
- botSubstitutionsLeft?: number;
-
- /**
- * The number of microseconds left for current bot substitution
- *
- * @generated from field: optional uint32 bot_substitution_time_left = 18;
- */
- botSubstitutionTimeLeft?: number;
-
- /**
- * The color of the hull of the robots of this team
- *
- * @generated from field: optional HullColor hull_color = 19;
- */
- hullColor?: HullColorJson;
-};
-
-/**
- * Describes the message Referee.TeamInfo.
- * Use `create(Referee_TeamInfoSchema)` to create a new message.
- */
-export const Referee_TeamInfoSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_referee_message, 0, 0);
-
-/**
- * The coordinates of the Designated Position. These are measured in
- * millimetres and correspond to SSL-Vision coordinates. These fields are
- * always either both present (in the case of a ball placement command) or
- * both absent (in the case of any other command).
- *
- * @generated from message Referee.Point
- */
-export type Referee_Point = Message<"Referee.Point"> & {
- /**
- * @generated from field: required float x = 1;
- */
- x: number;
-
- /**
- * @generated from field: required float y = 2;
- */
- y: number;
-};
-
-/**
- * The coordinates of the Designated Position. These are measured in
- * millimetres and correspond to SSL-Vision coordinates. These fields are
- * always either both present (in the case of a ball placement command) or
- * both absent (in the case of any other command).
- *
- * @generated from message Referee.Point
- */
-export type Referee_PointJson = {
- /**
- * @generated from field: required float x = 1;
- */
- x?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: required float y = 2;
- */
- y?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message Referee.Point.
- * Use `create(Referee_PointSchema)` to create a new message.
- */
-export const Referee_PointSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_referee_message, 0, 1);
-
-/**
- * These are the "coarse" stages of the game.
- *
- * @generated from enum Referee.Stage
- */
-export enum Referee_Stage {
- /**
- * The first half is about to start.
- * A kickoff is called within this stage.
- * This stage ends with the NORMAL_START.
- *
- * @generated from enum value: NORMAL_FIRST_HALF_PRE = 0;
- */
- NORMAL_FIRST_HALF_PRE = 0,
-
- /**
- * The first half of the normal game, before half time.
- *
- * @generated from enum value: NORMAL_FIRST_HALF = 1;
- */
- NORMAL_FIRST_HALF = 1,
-
- /**
- * Half time between first and second halves.
- *
- * @generated from enum value: NORMAL_HALF_TIME = 2;
- */
- NORMAL_HALF_TIME = 2,
-
- /**
- * The second half is about to start.
- * A kickoff is called within this stage.
- * This stage ends with the NORMAL_START.
- *
- * @generated from enum value: NORMAL_SECOND_HALF_PRE = 3;
- */
- NORMAL_SECOND_HALF_PRE = 3,
-
- /**
- * The second half of the normal game, after half time.
- *
- * @generated from enum value: NORMAL_SECOND_HALF = 4;
- */
- NORMAL_SECOND_HALF = 4,
-
- /**
- * The break before extra time.
- *
- * @generated from enum value: EXTRA_TIME_BREAK = 5;
- */
- EXTRA_TIME_BREAK = 5,
-
- /**
- * The first half of extra time is about to start.
- * A kickoff is called within this stage.
- * This stage ends with the NORMAL_START.
- *
- * @generated from enum value: EXTRA_FIRST_HALF_PRE = 6;
- */
- EXTRA_FIRST_HALF_PRE = 6,
-
- /**
- * The first half of extra time.
- *
- * @generated from enum value: EXTRA_FIRST_HALF = 7;
- */
- EXTRA_FIRST_HALF = 7,
-
- /**
- * Half time between first and second extra halves.
- *
- * @generated from enum value: EXTRA_HALF_TIME = 8;
- */
- EXTRA_HALF_TIME = 8,
-
- /**
- * The second half of extra time is about to start.
- * A kickoff is called within this stage.
- * This stage ends with the NORMAL_START.
- *
- * @generated from enum value: EXTRA_SECOND_HALF_PRE = 9;
- */
- EXTRA_SECOND_HALF_PRE = 9,
-
- /**
- * The second half of extra time.
- *
- * @generated from enum value: EXTRA_SECOND_HALF = 10;
- */
- EXTRA_SECOND_HALF = 10,
-
- /**
- * The break before penalty shootout.
- *
- * @generated from enum value: PENALTY_SHOOTOUT_BREAK = 11;
- */
- PENALTY_SHOOTOUT_BREAK = 11,
-
- /**
- * The penalty shootout.
- *
- * @generated from enum value: PENALTY_SHOOTOUT = 12;
- */
- PENALTY_SHOOTOUT = 12,
-
- /**
- * The game is over.
- *
- * @generated from enum value: POST_GAME = 13;
- */
- POST_GAME = 13,
-}
-
-/**
- * These are the "coarse" stages of the game.
- *
- * @generated from enum Referee.Stage
- */
-export type Referee_StageJson = "NORMAL_FIRST_HALF_PRE" | "NORMAL_FIRST_HALF" | "NORMAL_HALF_TIME" | "NORMAL_SECOND_HALF_PRE" | "NORMAL_SECOND_HALF" | "EXTRA_TIME_BREAK" | "EXTRA_FIRST_HALF_PRE" | "EXTRA_FIRST_HALF" | "EXTRA_HALF_TIME" | "EXTRA_SECOND_HALF_PRE" | "EXTRA_SECOND_HALF" | "PENALTY_SHOOTOUT_BREAK" | "PENALTY_SHOOTOUT" | "POST_GAME";
-
-/**
- * Describes the enum Referee.Stage.
- */
-export const Referee_StageSchema: GenEnum = /*@__PURE__*/
- enumDesc(file_gamecontroller_ssl_gc_referee_message, 0, 0);
-
-/**
- * These are the "fine" states of play on the field.
- *
- * @generated from enum Referee.Command
- */
-export enum Referee_Command {
- /**
- * All robots should completely stop moving.
- *
- * @generated from enum value: HALT = 0;
- */
- HALT = 0,
-
- /**
- * Robots must keep 50 cm from the ball.
- *
- * @generated from enum value: STOP = 1;
- */
- STOP = 1,
-
- /**
- * A prepared kickoff or penalty may now be taken.
- *
- * @generated from enum value: NORMAL_START = 2;
- */
- NORMAL_START = 2,
-
- /**
- * The ball is dropped and free for either team.
- *
- * @generated from enum value: FORCE_START = 3;
- */
- FORCE_START = 3,
-
- /**
- * The yellow team may move into kickoff position.
- *
- * @generated from enum value: PREPARE_KICKOFF_YELLOW = 4;
- */
- PREPARE_KICKOFF_YELLOW = 4,
-
- /**
- * The blue team may move into kickoff position.
- *
- * @generated from enum value: PREPARE_KICKOFF_BLUE = 5;
- */
- PREPARE_KICKOFF_BLUE = 5,
-
- /**
- * The yellow team may move into penalty position.
- *
- * @generated from enum value: PREPARE_PENALTY_YELLOW = 6;
- */
- PREPARE_PENALTY_YELLOW = 6,
-
- /**
- * The blue team may move into penalty position.
- *
- * @generated from enum value: PREPARE_PENALTY_BLUE = 7;
- */
- PREPARE_PENALTY_BLUE = 7,
-
- /**
- * The yellow team may take a direct free kick.
- *
- * @generated from enum value: DIRECT_FREE_YELLOW = 8;
- */
- DIRECT_FREE_YELLOW = 8,
-
- /**
- * The blue team may take a direct free kick.
- *
- * @generated from enum value: DIRECT_FREE_BLUE = 9;
- */
- DIRECT_FREE_BLUE = 9,
-
- /**
- * The yellow team may take an indirect free kick.
- *
- * @generated from enum value: INDIRECT_FREE_YELLOW = 10 [deprecated = true];
- * @deprecated
- */
- INDIRECT_FREE_YELLOW = 10,
-
- /**
- * The blue team may take an indirect free kick.
- *
- * @generated from enum value: INDIRECT_FREE_BLUE = 11 [deprecated = true];
- * @deprecated
- */
- INDIRECT_FREE_BLUE = 11,
-
- /**
- * The yellow team is currently in a timeout.
- *
- * @generated from enum value: TIMEOUT_YELLOW = 12;
- */
- TIMEOUT_YELLOW = 12,
-
- /**
- * The blue team is currently in a timeout.
- *
- * @generated from enum value: TIMEOUT_BLUE = 13;
- */
- TIMEOUT_BLUE = 13,
-
- /**
- * The yellow team just scored a goal.
- * For information only.
- * Deprecated: Use the score field from the team infos instead. That way, you can also detect revoked goals.
- *
- * @generated from enum value: GOAL_YELLOW = 14 [deprecated = true];
- * @deprecated
- */
- GOAL_YELLOW = 14,
-
- /**
- * The blue team just scored a goal. See also GOAL_YELLOW.
- *
- * @generated from enum value: GOAL_BLUE = 15 [deprecated = true];
- * @deprecated
- */
- GOAL_BLUE = 15,
-
- /**
- * Equivalent to STOP, but the yellow team must pick up the ball and
- * drop it in the Designated Position.
- *
- * @generated from enum value: BALL_PLACEMENT_YELLOW = 16;
- */
- BALL_PLACEMENT_YELLOW = 16,
-
- /**
- * Equivalent to STOP, but the blue team must pick up the ball and drop
- * it in the Designated Position.
- *
- * @generated from enum value: BALL_PLACEMENT_BLUE = 17;
- */
- BALL_PLACEMENT_BLUE = 17,
-}
-
-/**
- * These are the "fine" states of play on the field.
- *
- * @generated from enum Referee.Command
- */
-export type Referee_CommandJson = "HALT" | "STOP" | "NORMAL_START" | "FORCE_START" | "PREPARE_KICKOFF_YELLOW" | "PREPARE_KICKOFF_BLUE" | "PREPARE_PENALTY_YELLOW" | "PREPARE_PENALTY_BLUE" | "DIRECT_FREE_YELLOW" | "DIRECT_FREE_BLUE" | "INDIRECT_FREE_YELLOW" | "INDIRECT_FREE_BLUE" | "TIMEOUT_YELLOW" | "TIMEOUT_BLUE" | "GOAL_YELLOW" | "GOAL_BLUE" | "BALL_PLACEMENT_YELLOW" | "BALL_PLACEMENT_BLUE";
-
-/**
- * Describes the enum Referee.Command.
- */
-export const Referee_CommandSchema: GenEnum = /*@__PURE__*/
- enumDesc(file_gamecontroller_ssl_gc_referee_message, 0, 1);
-
-/**
- * List of matching proposals
- *
- * @generated from message GameEventProposalGroup
- */
-export type GameEventProposalGroup = Message<"GameEventProposalGroup"> & {
- /**
- * Unique ID of this group
- *
- * @generated from field: optional string id = 3;
- */
- id: string;
-
- /**
- * The proposed game events
- *
- * @generated from field: repeated GameEvent game_events = 1;
- */
- gameEvents: GameEvent[];
-
- /**
- * Whether the proposal group was accepted
- *
- * @generated from field: optional bool accepted = 2;
- */
- accepted: boolean;
-};
-
-/**
- * List of matching proposals
- *
- * @generated from message GameEventProposalGroup
- */
-export type GameEventProposalGroupJson = {
- /**
- * Unique ID of this group
- *
- * @generated from field: optional string id = 3;
- */
- id?: string;
-
- /**
- * The proposed game events
- *
- * @generated from field: repeated GameEvent game_events = 1;
- */
- gameEvents?: GameEventJson[];
-
- /**
- * Whether the proposal group was accepted
- *
- * @generated from field: optional bool accepted = 2;
- */
- accepted?: boolean;
-};
-
-/**
- * Describes the message GameEventProposalGroup.
- * Use `create(GameEventProposalGroupSchema)` to create a new message.
- */
-export const GameEventProposalGroupSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_gamecontroller_ssl_gc_referee_message, 1);
-
-/**
- * MatchType is a meta information about the current match for easier log processing
- *
- * @generated from enum MatchType
- */
-export enum MatchType {
- /**
- * not set
- *
- * @generated from enum value: UNKNOWN_MATCH = 0;
- */
- UNKNOWN_MATCH = 0,
-
- /**
- * match is part of the group phase
- *
- * @generated from enum value: GROUP_PHASE = 1;
- */
- GROUP_PHASE = 1,
-
- /**
- * match is part of the elimination phase
- *
- * @generated from enum value: ELIMINATION_PHASE = 2;
- */
- ELIMINATION_PHASE = 2,
-
- /**
- * a friendly match, not part of a tournament
- *
- * @generated from enum value: FRIENDLY = 3;
- */
- FRIENDLY = 3,
-}
-
-/**
- * MatchType is a meta information about the current match for easier log processing
- *
- * @generated from enum MatchType
- */
-export type MatchTypeJson = "UNKNOWN_MATCH" | "GROUP_PHASE" | "ELIMINATION_PHASE" | "FRIENDLY";
-
-/**
- * Describes the enum MatchType.
- */
-export const MatchTypeSchema: GenEnum = /*@__PURE__*/
- enumDesc(file_gamecontroller_ssl_gc_referee_message, 0);
-
-/**
- * HullColor is the color of the hull of the robots of a team
- *
- * @generated from enum HullColor
- */
-export enum HullColor {
- /**
- * not set
- *
- * @generated from enum value: HULL_COLOR_UNKNOWN = 0;
- */
- UNKNOWN = 0,
-
- /**
- * dark hull color
- *
- * @generated from enum value: HULL_COLOR_DARK = 1;
- */
- DARK = 1,
-
- /**
- * light hull color
- *
- * @generated from enum value: HULL_COLOR_LIGHT = 2;
- */
- LIGHT = 2,
-}
-
-/**
- * HullColor is the color of the hull of the robots of a team
- *
- * @generated from enum HullColor
- */
-export type HullColorJson = "HULL_COLOR_UNKNOWN" | "HULL_COLOR_DARK" | "HULL_COLOR_LIGHT";
-
-/**
- * Describes the enum HullColor.
- */
-export const HullColorSchema: GenEnum = /*@__PURE__*/
- enumDesc(file_gamecontroller_ssl_gc_referee_message, 1);
-
diff --git a/gui/frontend/src/proto/vision/ssl_vision_detection_pb.ts b/gui/frontend/src/proto/vision/ssl_vision_detection_pb.ts
deleted file mode 100644
index 899f846..0000000
--- a/gui/frontend/src/proto/vision/ssl_vision_detection_pb.ts
+++ /dev/null
@@ -1,403 +0,0 @@
-// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
-// @generated from file vision/ssl_vision_detection.proto (syntax proto2)
-/* eslint-disable */
-
-import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
-import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
-import type { Message } from "@bufbuild/protobuf";
-
-/**
- * Describes the file vision/ssl_vision_detection.proto.
- */
-export const file_vision_ssl_vision_detection: GenFile = /*@__PURE__*/
- fileDesc("CiF2aXNpb24vc3NsX3Zpc2lvbl9kZXRlY3Rpb24ucHJvdG8ieAoRU1NMX0RldGVjdGlvbkJhbGwSEgoKY29uZmlkZW5jZRgBIAIoAhIMCgRhcmVhGAIgASgNEgkKAXgYAyACKAISCQoBeRgEIAIoAhIJCgF6GAUgASgCEg8KB3BpeGVsX3gYBiACKAISDwoHcGl4ZWxfeRgHIAIoAiKXAQoSU1NMX0RldGVjdGlvblJvYm90EhIKCmNvbmZpZGVuY2UYASACKAISEAoIcm9ib3RfaWQYAiABKA0SCQoBeBgDIAIoAhIJCgF5GAQgAigCEhMKC29yaWVudGF0aW9uGAUgASgCEg8KB3BpeGVsX3gYBiACKAISDwoHcGl4ZWxfeRgHIAIoAhIOCgZoZWlnaHQYCCABKAIihgIKElNTTF9EZXRlY3Rpb25GcmFtZRIUCgxmcmFtZV9udW1iZXIYASACKA0SEQoJdF9jYXB0dXJlGAIgAigBEg4KBnRfc2VudBgDIAIoARIYChB0X2NhcHR1cmVfY2FtZXJhGAggASgBEhEKCXRfb2Zmc2V0cxgJIAMoAhIRCgljYW1lcmFfaWQYBCACKA0SIQoFYmFsbHMYBSADKAsyEi5TU0xfRGV0ZWN0aW9uQmFsbBIqCg1yb2JvdHNfeWVsbG93GAYgAygLMhMuU1NMX0RldGVjdGlvblJvYm90EigKC3JvYm90c19ibHVlGAcgAygLMhMuU1NMX0RldGVjdGlvblJvYm90QlxCF1NzbFZpc2lvbkRldGVjdGlvblByb3RvUAFaP2dpdGh1Yi5jb20vUm9ib0N1cC1TU0wvc3NsLXZpc2lvbi1wcm9jZXNzb3IvZ3VpL2ludGVybmFsL3Zpc2lvbg");
-
-/**
- * @generated from message SSL_DetectionBall
- */
-export type SSL_DetectionBall = Message<"SSL_DetectionBall"> & {
- /**
- * Confidence in [0-1] of the detection
- *
- * @generated from field: required float confidence = 1;
- */
- confidence: number;
-
- /**
- * @generated from field: optional uint32 area = 2;
- */
- area: number;
-
- /**
- * X-coordinate in [mm] in global ssl-vision coordinate system
- *
- * @generated from field: required float x = 3;
- */
- x: number;
-
- /**
- * Y-coordinate in [mm] in global ssl-vision coordinate system
- *
- * @generated from field: required float y = 4;
- */
- y: number;
-
- /**
- * Z-coordinate in [mm] in global ssl-vision coordinate system
- * Not supported by ssl-vision, but might be set by simulators
- *
- * @generated from field: optional float z = 5;
- */
- z: number;
-
- /**
- * X-coordinate in [pixel] in the image
- *
- * @generated from field: required float pixel_x = 6;
- */
- pixelX: number;
-
- /**
- * Y-coordinate in [pixel] in the image
- *
- * @generated from field: required float pixel_y = 7;
- */
- pixelY: number;
-};
-
-/**
- * @generated from message SSL_DetectionBall
- */
-export type SSL_DetectionBallJson = {
- /**
- * Confidence in [0-1] of the detection
- *
- * @generated from field: required float confidence = 1;
- */
- confidence?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: optional uint32 area = 2;
- */
- area?: number;
-
- /**
- * X-coordinate in [mm] in global ssl-vision coordinate system
- *
- * @generated from field: required float x = 3;
- */
- x?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Y-coordinate in [mm] in global ssl-vision coordinate system
- *
- * @generated from field: required float y = 4;
- */
- y?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Z-coordinate in [mm] in global ssl-vision coordinate system
- * Not supported by ssl-vision, but might be set by simulators
- *
- * @generated from field: optional float z = 5;
- */
- z?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * X-coordinate in [pixel] in the image
- *
- * @generated from field: required float pixel_x = 6;
- */
- pixelX?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Y-coordinate in [pixel] in the image
- *
- * @generated from field: required float pixel_y = 7;
- */
- pixelY?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message SSL_DetectionBall.
- * Use `create(SSL_DetectionBallSchema)` to create a new message.
- */
-export const SSL_DetectionBallSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vision_detection, 0);
-
-/**
- * @generated from message SSL_DetectionRobot
- */
-export type SSL_DetectionRobot = Message<"SSL_DetectionRobot"> & {
- /**
- * Confidence in [0-1] of the detection
- *
- * @generated from field: required float confidence = 1;
- */
- confidence: number;
-
- /**
- * Id of the robot
- *
- * @generated from field: optional uint32 robot_id = 2;
- */
- robotId: number;
-
- /**
- * X-coordinate in [mm] in global ssl-vision coordinate system
- *
- * @generated from field: required float x = 3;
- */
- x: number;
-
- /**
- * Y-coordinate in [mm] in global ssl-vision coordinate system
- *
- * @generated from field: required float y = 4;
- */
- y: number;
-
- /**
- * Orientation in [rad]
- *
- * @generated from field: optional float orientation = 5;
- */
- orientation: number;
-
- /**
- * X-coordinate in [pixel] in the image
- *
- * @generated from field: required float pixel_x = 6;
- */
- pixelX: number;
-
- /**
- * Y-coordinate in [pixel] in the image
- *
- * @generated from field: required float pixel_y = 7;
- */
- pixelY: number;
-
- /**
- * Height, as configured in ssl-vision for the respective team
- *
- * @generated from field: optional float height = 8;
- */
- height: number;
-};
-
-/**
- * @generated from message SSL_DetectionRobot
- */
-export type SSL_DetectionRobotJson = {
- /**
- * Confidence in [0-1] of the detection
- *
- * @generated from field: required float confidence = 1;
- */
- confidence?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Id of the robot
- *
- * @generated from field: optional uint32 robot_id = 2;
- */
- robotId?: number;
-
- /**
- * X-coordinate in [mm] in global ssl-vision coordinate system
- *
- * @generated from field: required float x = 3;
- */
- x?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Y-coordinate in [mm] in global ssl-vision coordinate system
- *
- * @generated from field: required float y = 4;
- */
- y?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Orientation in [rad]
- *
- * @generated from field: optional float orientation = 5;
- */
- orientation?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * X-coordinate in [pixel] in the image
- *
- * @generated from field: required float pixel_x = 6;
- */
- pixelX?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Y-coordinate in [pixel] in the image
- *
- * @generated from field: required float pixel_y = 7;
- */
- pixelY?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Height, as configured in ssl-vision for the respective team
- *
- * @generated from field: optional float height = 8;
- */
- height?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message SSL_DetectionRobot.
- * Use `create(SSL_DetectionRobotSchema)` to create a new message.
- */
-export const SSL_DetectionRobotSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vision_detection, 1);
-
-/**
- * @generated from message SSL_DetectionFrame
- */
-export type SSL_DetectionFrame = Message<"SSL_DetectionFrame"> & {
- /**
- * monotonously increasing frame number
- *
- * @generated from field: required uint32 frame_number = 1;
- */
- frameNumber: number;
-
- /**
- * Unix timestamp in [seconds] at which the image has been received by ssl-vision
- *
- * @generated from field: required double t_capture = 2;
- */
- tCapture: number;
-
- /**
- * Unix timestamp in [seconds] at which this message has been sent to the network
- *
- * @generated from field: required double t_sent = 3;
- */
- tSent: number;
-
- /**
- * Camera timestamp in [seconds] as reported by the camera, if supported
- * This is not necessarily a unix timestamp
- *
- * @generated from field: optional double t_capture_camera = 8;
- */
- tCaptureCamera: number;
-
- /**
- * Internal VisionProcessor field for clock synchronization,
- * containing the time offset of received packets for each cam relative to the local clock.
- *
- * @generated from field: repeated float t_offsets = 9;
- */
- tOffsets: number[];
-
- /**
- * Identifier of the camera
- *
- * @generated from field: required uint32 camera_id = 4;
- */
- cameraId: number;
-
- /**
- * Detected balls
- *
- * @generated from field: repeated SSL_DetectionBall balls = 5;
- */
- balls: SSL_DetectionBall[];
-
- /**
- * Detected yellow robots
- *
- * @generated from field: repeated SSL_DetectionRobot robots_yellow = 6;
- */
- robotsYellow: SSL_DetectionRobot[];
-
- /**
- * Detected blue robots
- *
- * @generated from field: repeated SSL_DetectionRobot robots_blue = 7;
- */
- robotsBlue: SSL_DetectionRobot[];
-};
-
-/**
- * @generated from message SSL_DetectionFrame
- */
-export type SSL_DetectionFrameJson = {
- /**
- * monotonously increasing frame number
- *
- * @generated from field: required uint32 frame_number = 1;
- */
- frameNumber?: number;
-
- /**
- * Unix timestamp in [seconds] at which the image has been received by ssl-vision
- *
- * @generated from field: required double t_capture = 2;
- */
- tCapture?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Unix timestamp in [seconds] at which this message has been sent to the network
- *
- * @generated from field: required double t_sent = 3;
- */
- tSent?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Camera timestamp in [seconds] as reported by the camera, if supported
- * This is not necessarily a unix timestamp
- *
- * @generated from field: optional double t_capture_camera = 8;
- */
- tCaptureCamera?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Internal VisionProcessor field for clock synchronization,
- * containing the time offset of received packets for each cam relative to the local clock.
- *
- * @generated from field: repeated float t_offsets = 9;
- */
- tOffsets?: (number | "NaN" | "Infinity" | "-Infinity")[];
-
- /**
- * Identifier of the camera
- *
- * @generated from field: required uint32 camera_id = 4;
- */
- cameraId?: number;
-
- /**
- * Detected balls
- *
- * @generated from field: repeated SSL_DetectionBall balls = 5;
- */
- balls?: SSL_DetectionBallJson[];
-
- /**
- * Detected yellow robots
- *
- * @generated from field: repeated SSL_DetectionRobot robots_yellow = 6;
- */
- robotsYellow?: SSL_DetectionRobotJson[];
-
- /**
- * Detected blue robots
- *
- * @generated from field: repeated SSL_DetectionRobot robots_blue = 7;
- */
- robotsBlue?: SSL_DetectionRobotJson[];
-};
-
-/**
- * Describes the message SSL_DetectionFrame.
- * Use `create(SSL_DetectionFrameSchema)` to create a new message.
- */
-export const SSL_DetectionFrameSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vision_detection, 2);
-
diff --git a/gui/frontend/src/proto/vision/ssl_vision_detection_tracked_pb.ts b/gui/frontend/src/proto/vision/ssl_vision_detection_tracked_pb.ts
deleted file mode 100644
index 9dedf77..0000000
--- a/gui/frontend/src/proto/vision/ssl_vision_detection_tracked_pb.ts
+++ /dev/null
@@ -1,448 +0,0 @@
-// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
-// @generated from file vision/ssl_vision_detection_tracked.proto (syntax proto2)
-/* eslint-disable */
-
-import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
-import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
-import type { RobotId, RobotIdJson } from "../gamecontroller/ssl_gc_common_pb";
-import { file_gamecontroller_ssl_gc_common } from "../gamecontroller/ssl_gc_common_pb";
-import type { Vector2, Vector2Json, Vector3, Vector3Json } from "../gamecontroller/ssl_gc_geometry_pb";
-import { file_gamecontroller_ssl_gc_geometry } from "../gamecontroller/ssl_gc_geometry_pb";
-import type { Message } from "@bufbuild/protobuf";
-
-/**
- * Describes the file vision/ssl_vision_detection_tracked.proto.
- */
-export const file_vision_ssl_vision_detection_tracked: GenFile = /*@__PURE__*/
- fileDesc("Cil2aXNpb24vc3NsX3Zpc2lvbl9kZXRlY3Rpb25fdHJhY2tlZC5wcm90byJPCgtUcmFja2VkQmFsbBIVCgNwb3MYASACKAsyCC5WZWN0b3IzEhUKA3ZlbBgCIAEoCzIILlZlY3RvcjMSEgoKdmlzaWJpbGl0eRgDIAEoAiKjAQoKS2lja2VkQmFsbBIVCgNwb3MYASACKAsyCC5WZWN0b3IyEhUKA3ZlbBgCIAIoCzIILlZlY3RvcjMSFwoPc3RhcnRfdGltZXN0YW1wGAMgAigBEhYKDnN0b3BfdGltZXN0YW1wGAQgASgBEhoKCHN0b3BfcG9zGAUgASgLMgguVmVjdG9yMhIaCghyb2JvdF9pZBgGIAEoCzIILlJvYm90SWQilgEKDFRyYWNrZWRSb2JvdBIaCghyb2JvdF9pZBgBIAIoCzIILlJvYm90SWQSFQoDcG9zGAIgAigLMgguVmVjdG9yMhITCgtvcmllbnRhdGlvbhgDIAIoAhIVCgN2ZWwYBCABKAsyCC5WZWN0b3IyEhMKC3ZlbF9hbmd1bGFyGAUgASgCEhIKCnZpc2liaWxpdHkYBiABKAIiuAEKDFRyYWNrZWRGcmFtZRIUCgxmcmFtZV9udW1iZXIYASACKA0SEQoJdGltZXN0YW1wGAIgAigBEhsKBWJhbGxzGAMgAygLMgwuVHJhY2tlZEJhbGwSHQoGcm9ib3RzGAQgAygLMg0uVHJhY2tlZFJvYm90EiAKC2tpY2tlZF9iYWxsGAUgASgLMgsuS2lja2VkQmFsbBIhCgxjYXBhYmlsaXRpZXMYBiADKA4yCy5DYXBhYmlsaXR5KpIBCgpDYXBhYmlsaXR5EhYKEkNBUEFCSUxJVFlfVU5LTk9XThAAEiIKHkNBUEFCSUxJVFlfREVURUNUX0ZMWUlOR19CQUxMUxABEiQKIENBUEFCSUxJVFlfREVURUNUX01VTFRJUExFX0JBTExTEAISIgoeQ0FQQUJJTElUWV9ERVRFQ1RfS0lDS0VEX0JBTExTEANCY0IeU3NsVmlzaW9uRGV0ZWN0aW9uVHJhY2tlZFByb3RvUAFaP2dpdGh1Yi5jb20vUm9ib0N1cC1TU0wvc3NsLXZpc2lvbi1wcm9jZXNzb3IvZ3VpL2ludGVybmFsL3Zpc2lvbg", [file_gamecontroller_ssl_gc_common, file_gamecontroller_ssl_gc_geometry]);
-
-/**
- * A single tracked ball
- *
- * @generated from message TrackedBall
- */
-export type TrackedBall = Message<"TrackedBall"> & {
- /**
- * The position (x, y, height) [m] in the ssl-vision coordinate system
- *
- * @generated from field: required Vector3 pos = 1;
- */
- pos?: Vector3;
-
- /**
- * The velocity [m/s] in the ssl-vision coordinate system
- *
- * @generated from field: optional Vector3 vel = 2;
- */
- vel?: Vector3;
-
- /**
- * The visibility of the ball
- * A value between 0 (not visible) and 1 (visible)
- * The exact implementation depends on the source software
- *
- * @generated from field: optional float visibility = 3;
- */
- visibility: number;
-};
-
-/**
- * A single tracked ball
- *
- * @generated from message TrackedBall
- */
-export type TrackedBallJson = {
- /**
- * The position (x, y, height) [m] in the ssl-vision coordinate system
- *
- * @generated from field: required Vector3 pos = 1;
- */
- pos?: Vector3Json;
-
- /**
- * The velocity [m/s] in the ssl-vision coordinate system
- *
- * @generated from field: optional Vector3 vel = 2;
- */
- vel?: Vector3Json;
-
- /**
- * The visibility of the ball
- * A value between 0 (not visible) and 1 (visible)
- * The exact implementation depends on the source software
- *
- * @generated from field: optional float visibility = 3;
- */
- visibility?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message TrackedBall.
- * Use `create(TrackedBallSchema)` to create a new message.
- */
-export const TrackedBallSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vision_detection_tracked, 0);
-
-/**
- * A ball kicked by a robot, including predictions when the ball will come to a stop
- *
- * @generated from message KickedBall
- */
-export type KickedBall = Message<"KickedBall"> & {
- /**
- * The initial position [m] from which the ball was kicked
- *
- * @generated from field: required Vector2 pos = 1;
- */
- pos?: Vector2;
-
- /**
- * The initial velocity [m/s] with which the ball was kicked
- *
- * @generated from field: required Vector3 vel = 2;
- */
- vel?: Vector3;
-
- /**
- * The unix timestamp [s] when the kick was performed
- *
- * @generated from field: required double start_timestamp = 3;
- */
- startTimestamp: number;
-
- /**
- * The predicted unix timestamp [s] when the ball comes to a stop
- *
- * @generated from field: optional double stop_timestamp = 4;
- */
- stopTimestamp: number;
-
- /**
- * The predicted position [m] at which the ball will come to a stop
- *
- * @generated from field: optional Vector2 stop_pos = 5;
- */
- stopPos?: Vector2;
-
- /**
- * The robot that kicked the ball
- *
- * @generated from field: optional RobotId robot_id = 6;
- */
- robotId?: RobotId;
-};
-
-/**
- * A ball kicked by a robot, including predictions when the ball will come to a stop
- *
- * @generated from message KickedBall
- */
-export type KickedBallJson = {
- /**
- * The initial position [m] from which the ball was kicked
- *
- * @generated from field: required Vector2 pos = 1;
- */
- pos?: Vector2Json;
-
- /**
- * The initial velocity [m/s] with which the ball was kicked
- *
- * @generated from field: required Vector3 vel = 2;
- */
- vel?: Vector3Json;
-
- /**
- * The unix timestamp [s] when the kick was performed
- *
- * @generated from field: required double start_timestamp = 3;
- */
- startTimestamp?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * The predicted unix timestamp [s] when the ball comes to a stop
- *
- * @generated from field: optional double stop_timestamp = 4;
- */
- stopTimestamp?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * The predicted position [m] at which the ball will come to a stop
- *
- * @generated from field: optional Vector2 stop_pos = 5;
- */
- stopPos?: Vector2Json;
-
- /**
- * The robot that kicked the ball
- *
- * @generated from field: optional RobotId robot_id = 6;
- */
- robotId?: RobotIdJson;
-};
-
-/**
- * Describes the message KickedBall.
- * Use `create(KickedBallSchema)` to create a new message.
- */
-export const KickedBallSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vision_detection_tracked, 1);
-
-/**
- * A single tracked robot
- *
- * @generated from message TrackedRobot
- */
-export type TrackedRobot = Message<"TrackedRobot"> & {
- /**
- * @generated from field: required RobotId robot_id = 1;
- */
- robotId?: RobotId;
-
- /**
- * The position [m] in the ssl-vision coordinate system
- *
- * @generated from field: required Vector2 pos = 2;
- */
- pos?: Vector2;
-
- /**
- * The orientation [rad] in the ssl-vision coordinate system
- *
- * @generated from field: required float orientation = 3;
- */
- orientation: number;
-
- /**
- * The velocity [m/s] in the ssl-vision coordinate system
- *
- * @generated from field: optional Vector2 vel = 4;
- */
- vel?: Vector2;
-
- /**
- * The angular velocity [rad/s] in the ssl-vision coordinate system
- *
- * @generated from field: optional float vel_angular = 5;
- */
- velAngular: number;
-
- /**
- * The visibility of the robot
- * A value between 0 (not visible) and 1 (visible)
- * The exact implementation depends on the source software
- *
- * @generated from field: optional float visibility = 6;
- */
- visibility: number;
-};
-
-/**
- * A single tracked robot
- *
- * @generated from message TrackedRobot
- */
-export type TrackedRobotJson = {
- /**
- * @generated from field: required RobotId robot_id = 1;
- */
- robotId?: RobotIdJson;
-
- /**
- * The position [m] in the ssl-vision coordinate system
- *
- * @generated from field: required Vector2 pos = 2;
- */
- pos?: Vector2Json;
-
- /**
- * The orientation [rad] in the ssl-vision coordinate system
- *
- * @generated from field: required float orientation = 3;
- */
- orientation?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * The velocity [m/s] in the ssl-vision coordinate system
- *
- * @generated from field: optional Vector2 vel = 4;
- */
- vel?: Vector2Json;
-
- /**
- * The angular velocity [rad/s] in the ssl-vision coordinate system
- *
- * @generated from field: optional float vel_angular = 5;
- */
- velAngular?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * The visibility of the robot
- * A value between 0 (not visible) and 1 (visible)
- * The exact implementation depends on the source software
- *
- * @generated from field: optional float visibility = 6;
- */
- visibility?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message TrackedRobot.
- * Use `create(TrackedRobotSchema)` to create a new message.
- */
-export const TrackedRobotSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vision_detection_tracked, 2);
-
-/**
- * A frame that contains all currently tracked objects on the field on all cameras
- *
- * @generated from message TrackedFrame
- */
-export type TrackedFrame = Message<"TrackedFrame"> & {
- /**
- * A monotonous increasing frame counter
- *
- * @generated from field: required uint32 frame_number = 1;
- */
- frameNumber: number;
-
- /**
- * The unix timestamp in [s] of the data
- * If timestamp is larger than timestamp_captured, the source has applied a prediction already
- *
- * @generated from field: required double timestamp = 2;
- */
- timestamp: number;
-
- /**
- * The list of detected balls
- * The first ball is the primary one
- * Sources may add additional balls based on their capabilities
- *
- * @generated from field: repeated TrackedBall balls = 3;
- */
- balls: TrackedBall[];
-
- /**
- * The list of detected robots of both teams
- *
- * @generated from field: repeated TrackedRobot robots = 4;
- */
- robots: TrackedRobot[];
-
- /**
- * Information about a kicked ball, if the ball was kicked by a robot and is still moving
- * Note: This field is optional. Some source implementations might not set this at any time
- *
- * @generated from field: optional KickedBall kicked_ball = 5;
- */
- kickedBall?: KickedBall;
-
- /**
- * List of capabilities of the source implementation
- *
- * @generated from field: repeated Capability capabilities = 6;
- */
- capabilities: Capability[];
-};
-
-/**
- * A frame that contains all currently tracked objects on the field on all cameras
- *
- * @generated from message TrackedFrame
- */
-export type TrackedFrameJson = {
- /**
- * A monotonous increasing frame counter
- *
- * @generated from field: required uint32 frame_number = 1;
- */
- frameNumber?: number;
-
- /**
- * The unix timestamp in [s] of the data
- * If timestamp is larger than timestamp_captured, the source has applied a prediction already
- *
- * @generated from field: required double timestamp = 2;
- */
- timestamp?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * The list of detected balls
- * The first ball is the primary one
- * Sources may add additional balls based on their capabilities
- *
- * @generated from field: repeated TrackedBall balls = 3;
- */
- balls?: TrackedBallJson[];
-
- /**
- * The list of detected robots of both teams
- *
- * @generated from field: repeated TrackedRobot robots = 4;
- */
- robots?: TrackedRobotJson[];
-
- /**
- * Information about a kicked ball, if the ball was kicked by a robot and is still moving
- * Note: This field is optional. Some source implementations might not set this at any time
- *
- * @generated from field: optional KickedBall kicked_ball = 5;
- */
- kickedBall?: KickedBallJson;
-
- /**
- * List of capabilities of the source implementation
- *
- * @generated from field: repeated Capability capabilities = 6;
- */
- capabilities?: CapabilityJson[];
-};
-
-/**
- * Describes the message TrackedFrame.
- * Use `create(TrackedFrameSchema)` to create a new message.
- */
-export const TrackedFrameSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vision_detection_tracked, 3);
-
-/**
- * Capabilities that a source implementation can have
- *
- * @generated from enum Capability
- */
-export enum Capability {
- /**
- * @generated from enum value: CAPABILITY_UNKNOWN = 0;
- */
- UNKNOWN = 0,
-
- /**
- * @generated from enum value: CAPABILITY_DETECT_FLYING_BALLS = 1;
- */
- DETECT_FLYING_BALLS = 1,
-
- /**
- * @generated from enum value: CAPABILITY_DETECT_MULTIPLE_BALLS = 2;
- */
- DETECT_MULTIPLE_BALLS = 2,
-
- /**
- * @generated from enum value: CAPABILITY_DETECT_KICKED_BALLS = 3;
- */
- DETECT_KICKED_BALLS = 3,
-}
-
-/**
- * Capabilities that a source implementation can have
- *
- * @generated from enum Capability
- */
-export type CapabilityJson = "CAPABILITY_UNKNOWN" | "CAPABILITY_DETECT_FLYING_BALLS" | "CAPABILITY_DETECT_MULTIPLE_BALLS" | "CAPABILITY_DETECT_KICKED_BALLS";
-
-/**
- * Describes the enum Capability.
- */
-export const CapabilitySchema: GenEnum = /*@__PURE__*/
- enumDesc(file_vision_ssl_vision_detection_tracked, 0);
-
diff --git a/gui/frontend/src/proto/vision/ssl_vision_geometry_pb.ts b/gui/frontend/src/proto/vision/ssl_vision_geometry_pb.ts
deleted file mode 100644
index 08bc7db..0000000
--- a/gui/frontend/src/proto/vision/ssl_vision_geometry_pb.ts
+++ /dev/null
@@ -1,1031 +0,0 @@
-// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
-// @generated from file vision/ssl_vision_geometry.proto (syntax proto2)
-/* eslint-disable */
-
-import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
-import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
-import type { Message } from "@bufbuild/protobuf";
-
-/**
- * Describes the file vision/ssl_vision_geometry.proto.
- */
-export const file_vision_ssl_vision_geometry: GenFile = /*@__PURE__*/
- fileDesc("CiB2aXNpb24vc3NsX3Zpc2lvbl9nZW9tZXRyeS5wcm90byIgCghWZWN0b3IyZhIJCgF4GAEgAigCEgkKAXkYAiACKAIiiAEKFFNTTF9GaWVsZExpbmVTZWdtZW50EgwKBG5hbWUYASACKAkSFQoCcDEYAiACKAsyCS5WZWN0b3IyZhIVCgJwMhgDIAIoCzIJLlZlY3RvcjJmEhEKCXRoaWNrbmVzcxgEIAIoAhIhCgR0eXBlGAUgASgOMhMuU1NMX0ZpZWxkU2hhcGVUeXBlIp0BChRTU0xfRmllbGRDaXJjdWxhckFyYxIMCgRuYW1lGAEgAigJEhkKBmNlbnRlchgCIAIoCzIJLlZlY3RvcjJmEg4KBnJhZGl1cxgDIAIoAhIKCgJhMRgEIAIoAhIKCgJhMhgFIAIoAhIRCgl0aGlja25lc3MYBiACKAISIQoEdHlwZRgHIAEoDjITLlNTTF9GaWVsZFNoYXBlVHlwZSL4AwoVU1NMX0dlb21ldHJ5RmllbGRTaXplEhQKDGZpZWxkX2xlbmd0aBgBIAIoBRITCgtmaWVsZF93aWR0aBgCIAIoBRISCgpnb2FsX3dpZHRoGAMgAigFEhIKCmdvYWxfZGVwdGgYBCACKAUSFgoOYm91bmRhcnlfd2lkdGgYBSACKAUSIAoYYm91bmRhcnlfd2lkdGhfZ29hbF9saW5lGBAgASgFEioKC2ZpZWxkX2xpbmVzGAYgAygLMhUuU1NMX0ZpZWxkTGluZVNlZ21lbnQSKQoKZmllbGRfYXJjcxgHIAMoCzIVLlNTTF9GaWVsZENpcmN1bGFyQXJjEhoKEnBlbmFsdHlfYXJlYV9kZXB0aBgIIAEoBRIaChJwZW5hbHR5X2FyZWFfd2lkdGgYCSABKAUSHAoUY2VudGVyX2NpcmNsZV9yYWRpdXMYCiABKAUSFgoObGluZV90aGlja25lc3MYCyABKAUSIwobZ29hbF9jZW50ZXJfdG9fcGVuYWx0eV9tYXJrGAwgASgFEhMKC2dvYWxfaGVpZ2h0GA0gASgFEhMKC2JhbGxfcmFkaXVzGA4gASgCEhgKEG1heF9yb2JvdF9yYWRpdXMYDyABKAISJAocZ29hbF9zdWJzdGl0dXRpb25fYXJlYV93aWR0aBgRIAEoBSKAAwodU1NMX0dlb21ldHJ5Q2FtZXJhQ2FsaWJyYXRpb24SEQoJY2FtZXJhX2lkGAEgAigNEhQKDGZvY2FsX2xlbmd0aBgCIAIoAhIZChFwcmluY2lwYWxfcG9pbnRfeBgDIAIoAhIZChFwcmluY2lwYWxfcG9pbnRfeRgEIAIoAhISCgpkaXN0b3J0aW9uGAUgAigCEgoKAnEwGAYgAigCEgoKAnExGAcgAigCEgoKAnEyGAggAigCEgoKAnEzGAkgAigCEgoKAnR4GAogAigCEgoKAnR5GAsgAigCEgoKAnR6GAwgAigCEh8KF2Rlcml2ZWRfY2FtZXJhX3dvcmxkX3R4GA0gASgCEh8KF2Rlcml2ZWRfY2FtZXJhX3dvcmxkX3R5GA4gASgCEh8KF2Rlcml2ZWRfY2FtZXJhX3dvcmxkX3R6GA8gASgCEhkKEXBpeGVsX2ltYWdlX3dpZHRoGBAgASgNEhoKEnBpeGVsX2ltYWdlX2hlaWdodBgRIAEoDSJWCh1TU0xfQmFsbE1vZGVsU3RyYWlnaHRUd29QaGFzZRIRCglhY2Nfc2xpZGUYASACKAESEAoIYWNjX3JvbGwYAiACKAESEAoIa19zd2l0Y2gYAyACKAEibAoaU1NMX0JhbGxNb2RlbENoaXBGaXhlZExvc3MSHAoUZGFtcGluZ194eV9maXJzdF9ob3AYASACKAESHQoVZGFtcGluZ194eV9vdGhlcl9ob3BzGAIgAigBEhEKCWRhbXBpbmdfehgDIAIoASKGAQoSU1NMX0dlb21ldHJ5TW9kZWxzEjoKEnN0cmFpZ2h0X3R3b19waGFzZRgBIAEoCzIeLlNTTF9CYWxsTW9kZWxTdHJhaWdodFR3b1BoYXNlEjQKD2NoaXBfZml4ZWRfbG9zcxgCIAEoCzIbLlNTTF9CYWxsTW9kZWxDaGlwRml4ZWRMb3NzIo0BChBTU0xfR2VvbWV0cnlEYXRhEiUKBWZpZWxkGAEgAigLMhYuU1NMX0dlb21ldHJ5RmllbGRTaXplEi0KBWNhbGliGAIgAygLMh4uU1NMX0dlb21ldHJ5Q2FtZXJhQ2FsaWJyYXRpb24SIwoGbW9kZWxzGAMgASgLMhMuU1NMX0dlb21ldHJ5TW9kZWxzKtsCChJTU0xfRmllbGRTaGFwZVR5cGUSDQoJVW5kZWZpbmVkEAASEAoMQ2VudGVyQ2lyY2xlEAESEAoMVG9wVG91Y2hMaW5lEAISEwoPQm90dG9tVG91Y2hMaW5lEAMSEAoMTGVmdEdvYWxMaW5lEAQSEQoNUmlnaHRHb2FsTGluZRAFEg8KC0hhbGZ3YXlMaW5lEAYSDgoKQ2VudGVyTGluZRAHEhYKEkxlZnRQZW5hbHR5U3RyZXRjaBAIEhcKE1JpZ2h0UGVuYWx0eVN0cmV0Y2gQCRIfChtMZWZ0RmllbGRMZWZ0UGVuYWx0eVN0cmV0Y2gQChIgChxMZWZ0RmllbGRSaWdodFBlbmFsdHlTdHJldGNoEAsSIAocUmlnaHRGaWVsZExlZnRQZW5hbHR5U3RyZXRjaBAMEiEKHVJpZ2h0RmllbGRSaWdodFBlbmFsdHlTdHJldGNoEA1CW0IWU3NsVmlzaW9uR2VvbWV0cnlQcm90b1ABWj9naXRodWIuY29tL1JvYm9DdXAtU1NML3NzbC12aXNpb24tcHJvY2Vzc29yL2d1aS9pbnRlcm5hbC92aXNpb24");
-
-/**
- * A 2D float vector.
- *
- * @generated from message Vector2f
- */
-export type Vector2f = Message<"Vector2f"> & {
- /**
- * X-coordinate in mm
- *
- * @generated from field: required float x = 1;
- */
- x: number;
-
- /**
- * Y-coordinate in mm
- *
- * @generated from field: required float y = 2;
- */
- y: number;
-};
-
-/**
- * A 2D float vector.
- *
- * @generated from message Vector2f
- */
-export type Vector2fJson = {
- /**
- * X-coordinate in mm
- *
- * @generated from field: required float x = 1;
- */
- x?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Y-coordinate in mm
- *
- * @generated from field: required float y = 2;
- */
- y?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message Vector2f.
- * Use `create(Vector2fSchema)` to create a new message.
- */
-export const Vector2fSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vision_geometry, 0);
-
-/**
- * Represents a field marking as a line segment represented by a start point p1,
- * and end point p2, and a line thickness. The start and end points are along
- * the center of the line, so the thickness of the line extends by thickness / 2
- * on either side of the line.
- *
- * @generated from message SSL_FieldLineSegment
- */
-export type SSL_FieldLineSegment = Message<"SSL_FieldLineSegment"> & {
- /**
- * Name of this field marking.
- *
- * @generated from field: required string name = 1;
- */
- name: string;
-
- /**
- * Start point of the line segment.
- *
- * @generated from field: required Vector2f p1 = 2;
- */
- p1?: Vector2f;
-
- /**
- * End point of the line segment.
- *
- * @generated from field: required Vector2f p2 = 3;
- */
- p2?: Vector2f;
-
- /**
- * Thickness of the line segment.
- *
- * @generated from field: required float thickness = 4;
- */
- thickness: number;
-
- /**
- * The type of this shape
- *
- * @generated from field: optional SSL_FieldShapeType type = 5;
- */
- type: SSL_FieldShapeType;
-};
-
-/**
- * Represents a field marking as a line segment represented by a start point p1,
- * and end point p2, and a line thickness. The start and end points are along
- * the center of the line, so the thickness of the line extends by thickness / 2
- * on either side of the line.
- *
- * @generated from message SSL_FieldLineSegment
- */
-export type SSL_FieldLineSegmentJson = {
- /**
- * Name of this field marking.
- *
- * @generated from field: required string name = 1;
- */
- name?: string;
-
- /**
- * Start point of the line segment.
- *
- * @generated from field: required Vector2f p1 = 2;
- */
- p1?: Vector2fJson;
-
- /**
- * End point of the line segment.
- *
- * @generated from field: required Vector2f p2 = 3;
- */
- p2?: Vector2fJson;
-
- /**
- * Thickness of the line segment.
- *
- * @generated from field: required float thickness = 4;
- */
- thickness?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * The type of this shape
- *
- * @generated from field: optional SSL_FieldShapeType type = 5;
- */
- type?: SSL_FieldShapeTypeJson;
-};
-
-/**
- * Describes the message SSL_FieldLineSegment.
- * Use `create(SSL_FieldLineSegmentSchema)` to create a new message.
- */
-export const SSL_FieldLineSegmentSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vision_geometry, 1);
-
-/**
- * Represents a field marking as a circular arc segment represented by center point, a
- * start angle, an end angle, and an arc thickness.
- *
- * @generated from message SSL_FieldCircularArc
- */
-export type SSL_FieldCircularArc = Message<"SSL_FieldCircularArc"> & {
- /**
- * Name of this field marking.
- *
- * @generated from field: required string name = 1;
- */
- name: string;
-
- /**
- * Center point of the circular arc.
- *
- * @generated from field: required Vector2f center = 2;
- */
- center?: Vector2f;
-
- /**
- * Radius of the arc.
- *
- * @generated from field: required float radius = 3;
- */
- radius: number;
-
- /**
- * Start angle in counter-clockwise order.
- *
- * @generated from field: required float a1 = 4;
- */
- a1: number;
-
- /**
- * End angle in counter-clockwise order.
- *
- * @generated from field: required float a2 = 5;
- */
- a2: number;
-
- /**
- * Thickness of the arc.
- *
- * @generated from field: required float thickness = 6;
- */
- thickness: number;
-
- /**
- * The type of this shape
- *
- * @generated from field: optional SSL_FieldShapeType type = 7;
- */
- type: SSL_FieldShapeType;
-};
-
-/**
- * Represents a field marking as a circular arc segment represented by center point, a
- * start angle, an end angle, and an arc thickness.
- *
- * @generated from message SSL_FieldCircularArc
- */
-export type SSL_FieldCircularArcJson = {
- /**
- * Name of this field marking.
- *
- * @generated from field: required string name = 1;
- */
- name?: string;
-
- /**
- * Center point of the circular arc.
- *
- * @generated from field: required Vector2f center = 2;
- */
- center?: Vector2fJson;
-
- /**
- * Radius of the arc.
- *
- * @generated from field: required float radius = 3;
- */
- radius?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Start angle in counter-clockwise order.
- *
- * @generated from field: required float a1 = 4;
- */
- a1?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * End angle in counter-clockwise order.
- *
- * @generated from field: required float a2 = 5;
- */
- a2?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Thickness of the arc.
- *
- * @generated from field: required float thickness = 6;
- */
- thickness?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * The type of this shape
- *
- * @generated from field: optional SSL_FieldShapeType type = 7;
- */
- type?: SSL_FieldShapeTypeJson;
-};
-
-/**
- * Describes the message SSL_FieldCircularArc.
- * Use `create(SSL_FieldCircularArcSchema)` to create a new message.
- */
-export const SSL_FieldCircularArcSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vision_geometry, 2);
-
-/**
- * @generated from message SSL_GeometryFieldSize
- */
-export type SSL_GeometryFieldSize = Message<"SSL_GeometryFieldSize"> & {
- /**
- * Field length (distance between goal lines) in mm
- *
- * @generated from field: required int32 field_length = 1;
- */
- fieldLength: number;
-
- /**
- * Field width (distance between touch lines) in mm
- *
- * @generated from field: required int32 field_width = 2;
- */
- fieldWidth: number;
-
- /**
- * Goal width (distance between inner edges of goal posts) in mm
- *
- * @generated from field: required int32 goal_width = 3;
- */
- goalWidth: number;
-
- /**
- * Goal depth (distance from outer goal line edge to inner goal back) in mm
- *
- * @generated from field: required int32 goal_depth = 4;
- */
- goalDepth: number;
-
- /**
- * Boundary width (distance from touch line centers to boundary walls) in mm
- *
- * @generated from field: required int32 boundary_width = 5;
- */
- boundaryWidth: number;
-
- /**
- * Boundary width at the goal lines (distance from goal line centers to boundary walls) in mm
- *
- * @generated from field: optional int32 boundary_width_goal_line = 16;
- */
- boundaryWidthGoalLine: number;
-
- /**
- * Generated line segments based on the other parameters
- *
- * @generated from field: repeated SSL_FieldLineSegment field_lines = 6;
- */
- fieldLines: SSL_FieldLineSegment[];
-
- /**
- * Generated circular arcs based on the other parameters
- *
- * @generated from field: repeated SSL_FieldCircularArc field_arcs = 7;
- */
- fieldArcs: SSL_FieldCircularArc[];
-
- /**
- * Depth of the penalty/defense area (measured between line centers) in mm
- *
- * @generated from field: optional int32 penalty_area_depth = 8;
- */
- penaltyAreaDepth: number;
-
- /**
- * Width of the penalty/defense area (measured between line centers) in mm
- *
- * @generated from field: optional int32 penalty_area_width = 9;
- */
- penaltyAreaWidth: number;
-
- /**
- * Radius of the center circle (measured between line centers) in mm
- *
- * @generated from field: optional int32 center_circle_radius = 10;
- */
- centerCircleRadius: number;
-
- /**
- * Thickness/width of the lines on the field in mm
- *
- * @generated from field: optional int32 line_thickness = 11;
- */
- lineThickness: number;
-
- /**
- * Distance between the goal center and the center of the penalty mark in mm
- *
- * @generated from field: optional int32 goal_center_to_penalty_mark = 12;
- */
- goalCenterToPenaltyMark: number;
-
- /**
- * Goal height in mm
- *
- * @generated from field: optional int32 goal_height = 13;
- */
- goalHeight: number;
-
- /**
- * Ball radius in mm (note that this is a float type to represent sub-mm precision)
- *
- * @generated from field: optional float ball_radius = 14;
- */
- ballRadius: number;
-
- /**
- * Max allowed robot radius in mm (note that this is a float type to represent sub-mm precision)
- *
- * @generated from field: optional float max_robot_radius = 15;
- */
- maxRobotRadius: number;
-
- /**
- * Width of the goal substitution area (distance from goal line center plus boundary width to boundary walls) in mm
- *
- * @generated from field: optional int32 goal_substitution_area_width = 17;
- */
- goalSubstitutionAreaWidth: number;
-};
-
-/**
- * @generated from message SSL_GeometryFieldSize
- */
-export type SSL_GeometryFieldSizeJson = {
- /**
- * Field length (distance between goal lines) in mm
- *
- * @generated from field: required int32 field_length = 1;
- */
- fieldLength?: number;
-
- /**
- * Field width (distance between touch lines) in mm
- *
- * @generated from field: required int32 field_width = 2;
- */
- fieldWidth?: number;
-
- /**
- * Goal width (distance between inner edges of goal posts) in mm
- *
- * @generated from field: required int32 goal_width = 3;
- */
- goalWidth?: number;
-
- /**
- * Goal depth (distance from outer goal line edge to inner goal back) in mm
- *
- * @generated from field: required int32 goal_depth = 4;
- */
- goalDepth?: number;
-
- /**
- * Boundary width (distance from touch line centers to boundary walls) in mm
- *
- * @generated from field: required int32 boundary_width = 5;
- */
- boundaryWidth?: number;
-
- /**
- * Boundary width at the goal lines (distance from goal line centers to boundary walls) in mm
- *
- * @generated from field: optional int32 boundary_width_goal_line = 16;
- */
- boundaryWidthGoalLine?: number;
-
- /**
- * Generated line segments based on the other parameters
- *
- * @generated from field: repeated SSL_FieldLineSegment field_lines = 6;
- */
- fieldLines?: SSL_FieldLineSegmentJson[];
-
- /**
- * Generated circular arcs based on the other parameters
- *
- * @generated from field: repeated SSL_FieldCircularArc field_arcs = 7;
- */
- fieldArcs?: SSL_FieldCircularArcJson[];
-
- /**
- * Depth of the penalty/defense area (measured between line centers) in mm
- *
- * @generated from field: optional int32 penalty_area_depth = 8;
- */
- penaltyAreaDepth?: number;
-
- /**
- * Width of the penalty/defense area (measured between line centers) in mm
- *
- * @generated from field: optional int32 penalty_area_width = 9;
- */
- penaltyAreaWidth?: number;
-
- /**
- * Radius of the center circle (measured between line centers) in mm
- *
- * @generated from field: optional int32 center_circle_radius = 10;
- */
- centerCircleRadius?: number;
-
- /**
- * Thickness/width of the lines on the field in mm
- *
- * @generated from field: optional int32 line_thickness = 11;
- */
- lineThickness?: number;
-
- /**
- * Distance between the goal center and the center of the penalty mark in mm
- *
- * @generated from field: optional int32 goal_center_to_penalty_mark = 12;
- */
- goalCenterToPenaltyMark?: number;
-
- /**
- * Goal height in mm
- *
- * @generated from field: optional int32 goal_height = 13;
- */
- goalHeight?: number;
-
- /**
- * Ball radius in mm (note that this is a float type to represent sub-mm precision)
- *
- * @generated from field: optional float ball_radius = 14;
- */
- ballRadius?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Max allowed robot radius in mm (note that this is a float type to represent sub-mm precision)
- *
- * @generated from field: optional float max_robot_radius = 15;
- */
- maxRobotRadius?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Width of the goal substitution area (distance from goal line center plus boundary width to boundary walls) in mm
- *
- * @generated from field: optional int32 goal_substitution_area_width = 17;
- */
- goalSubstitutionAreaWidth?: number;
-};
-
-/**
- * Describes the message SSL_GeometryFieldSize.
- * Use `create(SSL_GeometryFieldSizeSchema)` to create a new message.
- */
-export const SSL_GeometryFieldSizeSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vision_geometry, 3);
-
-/**
- * @generated from message SSL_GeometryCameraCalibration
- */
-export type SSL_GeometryCameraCalibration = Message<"SSL_GeometryCameraCalibration"> & {
- /**
- * @generated from field: required uint32 camera_id = 1;
- */
- cameraId: number;
-
- /**
- * @generated from field: required float focal_length = 2;
- */
- focalLength: number;
-
- /**
- * @generated from field: required float principal_point_x = 3;
- */
- principalPointX: number;
-
- /**
- * @generated from field: required float principal_point_y = 4;
- */
- principalPointY: number;
-
- /**
- * @generated from field: required float distortion = 5;
- */
- distortion: number;
-
- /**
- * @generated from field: required float q0 = 6;
- */
- q0: number;
-
- /**
- * @generated from field: required float q1 = 7;
- */
- q1: number;
-
- /**
- * @generated from field: required float q2 = 8;
- */
- q2: number;
-
- /**
- * @generated from field: required float q3 = 9;
- */
- q3: number;
-
- /**
- * @generated from field: required float tx = 10;
- */
- tx: number;
-
- /**
- * @generated from field: required float ty = 11;
- */
- ty: number;
-
- /**
- * @generated from field: required float tz = 12;
- */
- tz: number;
-
- /**
- * @generated from field: optional float derived_camera_world_tx = 13;
- */
- derivedCameraWorldTx: number;
-
- /**
- * @generated from field: optional float derived_camera_world_ty = 14;
- */
- derivedCameraWorldTy: number;
-
- /**
- * @generated from field: optional float derived_camera_world_tz = 15;
- */
- derivedCameraWorldTz: number;
-
- /**
- * @generated from field: optional uint32 pixel_image_width = 16;
- */
- pixelImageWidth: number;
-
- /**
- * @generated from field: optional uint32 pixel_image_height = 17;
- */
- pixelImageHeight: number;
-};
-
-/**
- * @generated from message SSL_GeometryCameraCalibration
- */
-export type SSL_GeometryCameraCalibrationJson = {
- /**
- * @generated from field: required uint32 camera_id = 1;
- */
- cameraId?: number;
-
- /**
- * @generated from field: required float focal_length = 2;
- */
- focalLength?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: required float principal_point_x = 3;
- */
- principalPointX?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: required float principal_point_y = 4;
- */
- principalPointY?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: required float distortion = 5;
- */
- distortion?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: required float q0 = 6;
- */
- q0?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: required float q1 = 7;
- */
- q1?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: required float q2 = 8;
- */
- q2?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: required float q3 = 9;
- */
- q3?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: required float tx = 10;
- */
- tx?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: required float ty = 11;
- */
- ty?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: required float tz = 12;
- */
- tz?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: optional float derived_camera_world_tx = 13;
- */
- derivedCameraWorldTx?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: optional float derived_camera_world_ty = 14;
- */
- derivedCameraWorldTy?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: optional float derived_camera_world_tz = 15;
- */
- derivedCameraWorldTz?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: optional uint32 pixel_image_width = 16;
- */
- pixelImageWidth?: number;
-
- /**
- * @generated from field: optional uint32 pixel_image_height = 17;
- */
- pixelImageHeight?: number;
-};
-
-/**
- * Describes the message SSL_GeometryCameraCalibration.
- * Use `create(SSL_GeometryCameraCalibrationSchema)` to create a new message.
- */
-export const SSL_GeometryCameraCalibrationSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vision_geometry, 4);
-
-/**
- * Two-Phase model for straight-kicked balls.
- * There are two phases with different accelerations during the ball kicks:
- * 1. Sliding
- * 2. Rolling
- * The full model is described in the TDP of ER-Force from 2016, which can be found here:
- * https://ssl.robocup.org/wp-content/uploads/2019/01/2016_ETDP_ER-Force.pdf
- *
- * @generated from message SSL_BallModelStraightTwoPhase
- */
-export type SSL_BallModelStraightTwoPhase = Message<"SSL_BallModelStraightTwoPhase"> & {
- /**
- * Ball sliding acceleration [m/s^2] (should be negative)
- *
- * @generated from field: required double acc_slide = 1;
- */
- accSlide: number;
-
- /**
- * Ball rolling acceleration [m/s^2] (should be negative)
- *
- * @generated from field: required double acc_roll = 2;
- */
- accRoll: number;
-
- /**
- * Fraction of the initial velocity where the ball starts to roll
- *
- * @generated from field: required double k_switch = 3;
- */
- kSwitch: number;
-};
-
-/**
- * Two-Phase model for straight-kicked balls.
- * There are two phases with different accelerations during the ball kicks:
- * 1. Sliding
- * 2. Rolling
- * The full model is described in the TDP of ER-Force from 2016, which can be found here:
- * https://ssl.robocup.org/wp-content/uploads/2019/01/2016_ETDP_ER-Force.pdf
- *
- * @generated from message SSL_BallModelStraightTwoPhase
- */
-export type SSL_BallModelStraightTwoPhaseJson = {
- /**
- * Ball sliding acceleration [m/s^2] (should be negative)
- *
- * @generated from field: required double acc_slide = 1;
- */
- accSlide?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Ball rolling acceleration [m/s^2] (should be negative)
- *
- * @generated from field: required double acc_roll = 2;
- */
- accRoll?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Fraction of the initial velocity where the ball starts to roll
- *
- * @generated from field: required double k_switch = 3;
- */
- kSwitch?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message SSL_BallModelStraightTwoPhase.
- * Use `create(SSL_BallModelStraightTwoPhaseSchema)` to create a new message.
- */
-export const SSL_BallModelStraightTwoPhaseSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vision_geometry, 5);
-
-/**
- * Fixed-Loss model for chipped balls.
- * Uses fixed damping factors for xy and z direction per hop.
- *
- * @generated from message SSL_BallModelChipFixedLoss
- */
-export type SSL_BallModelChipFixedLoss = Message<"SSL_BallModelChipFixedLoss"> & {
- /**
- * Chip kick velocity damping factor in XY direction for the first hop
- *
- * @generated from field: required double damping_xy_first_hop = 1;
- */
- dampingXyFirstHop: number;
-
- /**
- * Chip kick velocity damping factor in XY direction for all following hops
- *
- * @generated from field: required double damping_xy_other_hops = 2;
- */
- dampingXyOtherHops: number;
-
- /**
- * Chip kick velocity damping factor in Z direction for all hops
- *
- * @generated from field: required double damping_z = 3;
- */
- dampingZ: number;
-};
-
-/**
- * Fixed-Loss model for chipped balls.
- * Uses fixed damping factors for xy and z direction per hop.
- *
- * @generated from message SSL_BallModelChipFixedLoss
- */
-export type SSL_BallModelChipFixedLossJson = {
- /**
- * Chip kick velocity damping factor in XY direction for the first hop
- *
- * @generated from field: required double damping_xy_first_hop = 1;
- */
- dampingXyFirstHop?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Chip kick velocity damping factor in XY direction for all following hops
- *
- * @generated from field: required double damping_xy_other_hops = 2;
- */
- dampingXyOtherHops?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Chip kick velocity damping factor in Z direction for all hops
- *
- * @generated from field: required double damping_z = 3;
- */
- dampingZ?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message SSL_BallModelChipFixedLoss.
- * Use `create(SSL_BallModelChipFixedLossSchema)` to create a new message.
- */
-export const SSL_BallModelChipFixedLossSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vision_geometry, 6);
-
-/**
- * @generated from message SSL_GeometryModels
- */
-export type SSL_GeometryModels = Message<"SSL_GeometryModels"> & {
- /**
- * @generated from field: optional SSL_BallModelStraightTwoPhase straight_two_phase = 1;
- */
- straightTwoPhase?: SSL_BallModelStraightTwoPhase;
-
- /**
- * @generated from field: optional SSL_BallModelChipFixedLoss chip_fixed_loss = 2;
- */
- chipFixedLoss?: SSL_BallModelChipFixedLoss;
-};
-
-/**
- * @generated from message SSL_GeometryModels
- */
-export type SSL_GeometryModelsJson = {
- /**
- * @generated from field: optional SSL_BallModelStraightTwoPhase straight_two_phase = 1;
- */
- straightTwoPhase?: SSL_BallModelStraightTwoPhaseJson;
-
- /**
- * @generated from field: optional SSL_BallModelChipFixedLoss chip_fixed_loss = 2;
- */
- chipFixedLoss?: SSL_BallModelChipFixedLossJson;
-};
-
-/**
- * Describes the message SSL_GeometryModels.
- * Use `create(SSL_GeometryModelsSchema)` to create a new message.
- */
-export const SSL_GeometryModelsSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vision_geometry, 7);
-
-/**
- * @generated from message SSL_GeometryData
- */
-export type SSL_GeometryData = Message<"SSL_GeometryData"> & {
- /**
- * @generated from field: required SSL_GeometryFieldSize field = 1;
- */
- field?: SSL_GeometryFieldSize;
-
- /**
- * @generated from field: repeated SSL_GeometryCameraCalibration calib = 2;
- */
- calib: SSL_GeometryCameraCalibration[];
-
- /**
- * @generated from field: optional SSL_GeometryModels models = 3;
- */
- models?: SSL_GeometryModels;
-};
-
-/**
- * @generated from message SSL_GeometryData
- */
-export type SSL_GeometryDataJson = {
- /**
- * @generated from field: required SSL_GeometryFieldSize field = 1;
- */
- field?: SSL_GeometryFieldSizeJson;
-
- /**
- * @generated from field: repeated SSL_GeometryCameraCalibration calib = 2;
- */
- calib?: SSL_GeometryCameraCalibrationJson[];
-
- /**
- * @generated from field: optional SSL_GeometryModels models = 3;
- */
- models?: SSL_GeometryModelsJson;
-};
-
-/**
- * Describes the message SSL_GeometryData.
- * Use `create(SSL_GeometryDataSchema)` to create a new message.
- */
-export const SSL_GeometryDataSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vision_geometry, 8);
-
-/**
- * @generated from enum SSL_FieldShapeType
- */
-export enum SSL_FieldShapeType {
- /**
- * @generated from enum value: Undefined = 0;
- */
- Undefined = 0,
-
- /**
- * @generated from enum value: CenterCircle = 1;
- */
- CenterCircle = 1,
-
- /**
- * @generated from enum value: TopTouchLine = 2;
- */
- TopTouchLine = 2,
-
- /**
- * @generated from enum value: BottomTouchLine = 3;
- */
- BottomTouchLine = 3,
-
- /**
- * @generated from enum value: LeftGoalLine = 4;
- */
- LeftGoalLine = 4,
-
- /**
- * @generated from enum value: RightGoalLine = 5;
- */
- RightGoalLine = 5,
-
- /**
- * @generated from enum value: HalfwayLine = 6;
- */
- HalfwayLine = 6,
-
- /**
- * @generated from enum value: CenterLine = 7;
- */
- CenterLine = 7,
-
- /**
- * @generated from enum value: LeftPenaltyStretch = 8;
- */
- LeftPenaltyStretch = 8,
-
- /**
- * @generated from enum value: RightPenaltyStretch = 9;
- */
- RightPenaltyStretch = 9,
-
- /**
- * @generated from enum value: LeftFieldLeftPenaltyStretch = 10;
- */
- LeftFieldLeftPenaltyStretch = 10,
-
- /**
- * @generated from enum value: LeftFieldRightPenaltyStretch = 11;
- */
- LeftFieldRightPenaltyStretch = 11,
-
- /**
- * @generated from enum value: RightFieldLeftPenaltyStretch = 12;
- */
- RightFieldLeftPenaltyStretch = 12,
-
- /**
- * @generated from enum value: RightFieldRightPenaltyStretch = 13;
- */
- RightFieldRightPenaltyStretch = 13,
-}
-
-/**
- * @generated from enum SSL_FieldShapeType
- */
-export type SSL_FieldShapeTypeJson = "Undefined" | "CenterCircle" | "TopTouchLine" | "BottomTouchLine" | "LeftGoalLine" | "RightGoalLine" | "HalfwayLine" | "CenterLine" | "LeftPenaltyStretch" | "RightPenaltyStretch" | "LeftFieldLeftPenaltyStretch" | "LeftFieldRightPenaltyStretch" | "RightFieldLeftPenaltyStretch" | "RightFieldRightPenaltyStretch";
-
-/**
- * Describes the enum SSL_FieldShapeType.
- */
-export const SSL_FieldShapeTypeSchema: GenEnum = /*@__PURE__*/
- enumDesc(file_vision_ssl_vision_geometry, 0);
-
diff --git a/gui/frontend/src/proto/vision/ssl_vision_wrapper_pb.ts b/gui/frontend/src/proto/vision/ssl_vision_wrapper_pb.ts
deleted file mode 100644
index 441bf5f..0000000
--- a/gui/frontend/src/proto/vision/ssl_vision_wrapper_pb.ts
+++ /dev/null
@@ -1,123 +0,0 @@
-// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
-// @generated from file vision/ssl_vision_wrapper.proto (syntax proto2)
-/* eslint-disable */
-
-import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
-import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
-import type { SSL_DetectionFrame, SSL_DetectionFrameJson } from "./ssl_vision_detection_pb";
-import { file_vision_ssl_vision_detection } from "./ssl_vision_detection_pb";
-import type { SSL_GeometryData, SSL_GeometryDataJson } from "./ssl_vision_geometry_pb";
-import { file_vision_ssl_vision_geometry } from "./ssl_vision_geometry_pb";
-import type { SSL_VPConfig, SSL_VPConfigJson } from "./ssl_vp_config_pb";
-import { file_vision_ssl_vp_config } from "./ssl_vp_config_pb";
-import type { Message } from "@bufbuild/protobuf";
-
-/**
- * Describes the file vision/ssl_vision_wrapper.proto.
- */
-export const file_vision_ssl_vision_wrapper: GenFile = /*@__PURE__*/
- fileDesc("Ch92aXNpb24vc3NsX3Zpc2lvbl93cmFwcGVyLnByb3RvIpwBChFTU0xfV3JhcHBlclBhY2tldBImCglkZXRlY3Rpb24YASABKAsyEy5TU0xfRGV0ZWN0aW9uRnJhbWUSIwoIZ2VvbWV0cnkYAiABKAsyES5TU0xfR2VvbWV0cnlEYXRhEhsKBnNvdXJjZRgDIAEoDjILLlNTTF9Tb3VyY2USHQoGY29uZmlnGAQgASgLMg0uU1NMX1ZQQ29uZmlnKqgBCgpTU0xfU291cmNlEhYKElNTTF9TT1VSQ0VfVU5LTk9XThAAEhQKEFNTTF9TT1VSQ0VfT1RIRVIQARIZChVTU0xfU09VUkNFX1NTTF9WSVNJT04QAhIfChtTU0xfU09VUkNFX1ZJU0lPTl9QUk9DRVNTT1IQAxIUChBTU0xfU09VUkNFX0dSU0lNEAQSGgoWU1NMX1NPVVJDRV9FUkZPUkNFX1NJTRAFQlpCFVNzbFZpc2lvbldyYXBwZXJQcm90b1ABWj9naXRodWIuY29tL1JvYm9DdXAtU1NML3NzbC12aXNpb24tcHJvY2Vzc29yL2d1aS9pbnRlcm5hbC92aXNpb24", [file_vision_ssl_vision_detection, file_vision_ssl_vision_geometry, file_vision_ssl_vp_config]);
-
-/**
- * @generated from message SSL_WrapperPacket
- */
-export type SSL_WrapperPacket = Message<"SSL_WrapperPacket"> & {
- /**
- * @generated from field: optional SSL_DetectionFrame detection = 1;
- */
- detection?: SSL_DetectionFrame;
-
- /**
- * @generated from field: optional SSL_GeometryData geometry = 2;
- */
- geometry?: SSL_GeometryData;
-
- /**
- * @generated from field: optional SSL_Source source = 3;
- */
- source: SSL_Source;
-
- /**
- * @generated from field: optional SSL_VPConfig config = 4;
- */
- config?: SSL_VPConfig;
-};
-
-/**
- * @generated from message SSL_WrapperPacket
- */
-export type SSL_WrapperPacketJson = {
- /**
- * @generated from field: optional SSL_DetectionFrame detection = 1;
- */
- detection?: SSL_DetectionFrameJson;
-
- /**
- * @generated from field: optional SSL_GeometryData geometry = 2;
- */
- geometry?: SSL_GeometryDataJson;
-
- /**
- * @generated from field: optional SSL_Source source = 3;
- */
- source?: SSL_SourceJson;
-
- /**
- * @generated from field: optional SSL_VPConfig config = 4;
- */
- config?: SSL_VPConfigJson;
-};
-
-/**
- * Describes the message SSL_WrapperPacket.
- * Use `create(SSL_WrapperPacketSchema)` to create a new message.
- */
-export const SSL_WrapperPacketSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vision_wrapper, 0);
-
-/**
- * @generated from enum SSL_Source
- */
-export enum SSL_Source {
- /**
- * @generated from enum value: SSL_SOURCE_UNKNOWN = 0;
- */
- SSL_SOURCE_UNKNOWN = 0,
-
- /**
- * @generated from enum value: SSL_SOURCE_OTHER = 1;
- */
- SSL_SOURCE_OTHER = 1,
-
- /**
- * @generated from enum value: SSL_SOURCE_SSL_VISION = 2;
- */
- SSL_SOURCE_SSL_VISION = 2,
-
- /**
- * @generated from enum value: SSL_SOURCE_VISION_PROCESSOR = 3;
- */
- SSL_SOURCE_VISION_PROCESSOR = 3,
-
- /**
- * @generated from enum value: SSL_SOURCE_GRSIM = 4;
- */
- SSL_SOURCE_GRSIM = 4,
-
- /**
- * @generated from enum value: SSL_SOURCE_ERFORCE_SIM = 5;
- */
- SSL_SOURCE_ERFORCE_SIM = 5,
-}
-
-/**
- * @generated from enum SSL_Source
- */
-export type SSL_SourceJson = "SSL_SOURCE_UNKNOWN" | "SSL_SOURCE_OTHER" | "SSL_SOURCE_SSL_VISION" | "SSL_SOURCE_VISION_PROCESSOR" | "SSL_SOURCE_GRSIM" | "SSL_SOURCE_ERFORCE_SIM";
-
-/**
- * Describes the enum SSL_Source.
- */
-export const SSL_SourceSchema: GenEnum = /*@__PURE__*/
- enumDesc(file_vision_ssl_vision_wrapper, 0);
-
diff --git a/gui/frontend/src/proto/vision/ssl_vision_wrapper_tracked_pb.ts b/gui/frontend/src/proto/vision/ssl_vision_wrapper_tracked_pb.ts
deleted file mode 100644
index 3c06af7..0000000
--- a/gui/frontend/src/proto/vision/ssl_vision_wrapper_tracked_pb.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
-// @generated from file vision/ssl_vision_wrapper_tracked.proto (syntax proto2)
-/* eslint-disable */
-
-import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
-import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
-import type { TrackedFrame, TrackedFrameJson } from "./ssl_vision_detection_tracked_pb";
-import { file_vision_ssl_vision_detection_tracked } from "./ssl_vision_detection_tracked_pb";
-import type { Message } from "@bufbuild/protobuf";
-
-/**
- * Describes the file vision/ssl_vision_wrapper_tracked.proto.
- */
-export const file_vision_ssl_vision_wrapper_tracked: GenFile = /*@__PURE__*/
- fileDesc("Cid2aXNpb24vc3NsX3Zpc2lvbl93cmFwcGVyX3RyYWNrZWQucHJvdG8iXwoUVHJhY2tlcldyYXBwZXJQYWNrZXQSDAoEdXVpZBgBIAIoCRITCgtzb3VyY2VfbmFtZRgCIAEoCRIkCg10cmFja2VkX2ZyYW1lGAMgASgLMg0uVHJhY2tlZEZyYW1lQmFCHFNzbFZpc2lvbldyYXBwZXJUcmFja2VkUHJvdG9QAVo/Z2l0aHViLmNvbS9Sb2JvQ3VwLVNTTC9zc2wtdmlzaW9uLXByb2Nlc3Nvci9ndWkvaW50ZXJuYWwvdmlzaW9u", [file_vision_ssl_vision_detection_tracked]);
-
-/**
- * A wrapper packet containing meta data of the source
- * Also serves for the possibility to extend the protocol later
- *
- * @generated from message TrackerWrapperPacket
- */
-export type TrackerWrapperPacket = Message<"TrackerWrapperPacket"> & {
- /**
- * A random UUID of the source that is kept constant at the source while running
- * If multiple sources are broadcasting to the same network, this id can be used to identify individual sources
- *
- * @generated from field: required string uuid = 1;
- */
- uuid: string;
-
- /**
- * The name of the source software that is producing this messages.
- *
- * @generated from field: optional string source_name = 2;
- */
- sourceName: string;
-
- /**
- * The tracked frame
- *
- * @generated from field: optional TrackedFrame tracked_frame = 3;
- */
- trackedFrame?: TrackedFrame;
-};
-
-/**
- * A wrapper packet containing meta data of the source
- * Also serves for the possibility to extend the protocol later
- *
- * @generated from message TrackerWrapperPacket
- */
-export type TrackerWrapperPacketJson = {
- /**
- * A random UUID of the source that is kept constant at the source while running
- * If multiple sources are broadcasting to the same network, this id can be used to identify individual sources
- *
- * @generated from field: required string uuid = 1;
- */
- uuid?: string;
-
- /**
- * The name of the source software that is producing this messages.
- *
- * @generated from field: optional string source_name = 2;
- */
- sourceName?: string;
-
- /**
- * The tracked frame
- *
- * @generated from field: optional TrackedFrame tracked_frame = 3;
- */
- trackedFrame?: TrackedFrameJson;
-};
-
-/**
- * Describes the message TrackerWrapperPacket.
- * Use `create(TrackerWrapperPacketSchema)` to create a new message.
- */
-export const TrackerWrapperPacketSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vision_wrapper_tracked, 0);
-
diff --git a/gui/frontend/src/proto/vision/ssl_vp_config_pb.ts b/gui/frontend/src/proto/vision/ssl_vp_config_pb.ts
deleted file mode 100644
index 7762334..0000000
--- a/gui/frontend/src/proto/vision/ssl_vp_config_pb.ts
+++ /dev/null
@@ -1,951 +0,0 @@
-// @generated by protoc-gen-es v2.2.5 with parameter "target=ts,json_types=true"
-// @generated from file vision/ssl_vp_config.proto (syntax proto2)
-/* eslint-disable */
-
-import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1";
-import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1";
-import type { Vector2, Vector2Json } from "../gamecontroller/ssl_gc_geometry_pb";
-import { file_gamecontroller_ssl_gc_geometry } from "../gamecontroller/ssl_gc_geometry_pb";
-import type { Message } from "@bufbuild/protobuf";
-
-/**
- * Describes the file vision/ssl_vp_config.proto.
- */
-export const file_vision_ssl_vp_config: GenFile = /*@__PURE__*/
- fileDesc("Chp2aXNpb24vc3NsX3ZwX2NvbmZpZy5wcm90byKXAgoSU1NMX1ZQQ29uZmlnQ2FtZXJhEikKBmRyaXZlchgBIAEoDjIZLlNTTF9WUENvbmZpZ0NhbWVyYURyaXZlchINCgJpZBgCIAEoDToBMBIOCgRwYXRoGAMgASgJOgASEAoFd2lkdGgYBCABKA06ATASEQoGaGVpZ2h0GAUgASgNOgEwEhMKCGV4cG9zdXJlGAYgASgCOgEwEg8KBGdhaW4YByABKAI6ATASEAoFZ2FtbWEYCCABKAI6ATESMwoHd2JfdHlwZRgJIAEoDjIZLlNTTF9WUENvbmZpZ0NhbWVyYVdCVHlwZToHT1VURE9PUhIRCgZ3Yl9yZWQYCiABKAI6ATESEgoHd2JfYmx1ZRgLIAEoAjoBMSKEAQoUU1NMX1ZQQ29uZmlnR2VvbWV0cnkSGAoNY2FtZXJhX2Ftb3VudBgBIAEoDToBMRIYCg1jYW1lcmFfaGVpZ2h0GAIgASgCOgEwEh4KDGxpbmVfY29ybmVycxgDIAMoCzIILlZlY3RvcjISGAoKcmVmaW5lbWVudBgEIAEoCDoEdHJ1ZSLUAQoWU1NMX1ZQQ29uZmlnVGhyZXNob2xkcxIXCgtjaXJjdWxhcml0eRgBIAEoAjoCMTUSEAoFc2NvcmUYAiABKAI6ATUSKwoObWluX2NvbmZpZGVuY2UYAyABKAI6EzAuMjAwMDAwMDAyOTgwMjMyMjQSIgoVbWluX2NhbV9lZGdlX2Rpc3RhbmNlGAQgASgCOgMxNzASHgoSY2xpcHBpbmdfdG9sZXJhbmNlGAUgASgCOgIxMBIeChJnZW9tZXRyeV90b2xlcmFuY2UYBiABKAI6AjEwIkAKBUNvbG9yEhAKA3JlZBgBIAEoDToDMTI4EhIKBWdyZWVuGAIgASgNOgMxMjgSEQoEYmx1ZRgDIAEoDToDMTI4IjoKB1ZQQ29sb3ISGQoJcmVmZXJlbmNlGAEgASgLMgYuQ29sb3ISFAoEbGl2ZRgCIAEoCzIGLkNvbG9yIoECChFTU0xfVlBDb25maWdDb2xvchIsCg9yZWZlcmVuY2VfZm9yY2UYASABKAI6EzAuMTAwMDAwMDAxNDkwMTE2MTISKAoNaGlzdG9yeV9mb3JjZRgCIAEoAjoRMC42OTk5OTk5ODgwNzkwNzESGAoGb3JhbmdlGAMgASgLMgguVlBDb2xvchIXCgVmaWVsZBgEIAEoCzIILlZQQ29sb3ISGAoGeWVsbG93GAUgASgLMgguVlBDb2xvchIWCgRibHVlGAYgASgLMgguVlBDb2xvchIXCgVncmVlbhgHIAEoCzIILlZQQ29sb3ISFgoEcGluaxgIIAEoCzIILlZQQ29sb3IiZwoTU1NMX1ZQQ29uZmlnTmV0d29yaxIZCgVnY19pcBgBIAEoCToKMjI0LjUuMjMuMRIWCgdnY19wb3J0GAIgASgNOgUxMDAwMxIdCgl2aXNpb25faXAYAyABKAk6CjIyNC41LjIzLjIikAEKElNTTF9WUENvbmZpZ1N0cmVhbRIUCgZhY3RpdmUYASABKAg6BHRydWUSKgoEdHlwZRgCIAEoDjIXLlNTTF9WUENvbmZpZ1N0cmVhbVR5cGU6A1JBVxIcCglzdHJlYW1faXAYAyABKAk6CTEyNy4wLjAuMRIaCgtzdHJlYW1fcG9ydBgEIAEoDToFMTAxMDAirwMKDFNTTF9WUENvbmZpZxIQCghpbnN0YW5jZRgBIAIoCRIUCgljYW1lcmFfaWQYAiABKA06ATASNgoNcm9ib3RfaGVpZ2h0cxgDIAMoCzIfLlNTTF9WUENvbmZpZy5Sb2JvdEhlaWdodHNFbnRyeRIjCgZjYW1lcmEYBCABKAsyEy5TU0xfVlBDb25maWdDYW1lcmESJwoIZ2VvbWV0cnkYBSABKAsyFS5TU0xfVlBDb25maWdHZW9tZXRyeRIrCgp0aHJlc2hvbGRzGAYgASgLMhcuU1NMX1ZQQ29uZmlnVGhyZXNob2xkcxIhCgVjb2xvchgHIAEoCzISLlNTTF9WUENvbmZpZ0NvbG9yEiUKB25ldHdvcmsYCCABKAsyFC5TU0xfVlBDb25maWdOZXR3b3JrEiMKBnN0cmVhbRgJIAEoCzITLlNTTF9WUENvbmZpZ1N0cmVhbRIgChF3YWl0X2Zvcl9nZW9tZXRyeRgKIAEoCDoFZmFsc2UaMwoRUm9ib3RIZWlnaHRzRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgCOgI4ASpDChhTU0xfVlBDb25maWdDYW1lcmFEcml2ZXISDQoJU1BJTk5BS0VSEAASCgoGT1BFTkNWEAESDAoITVZJTVBBQ1QQAio/ChhTU0xfVlBDb25maWdDYW1lcmFXQlR5cGUSCwoHT1VURE9PUhAAEgoKBklORE9PUhABEgoKBk1BTlVBTBACKmkKFlNTTF9WUENvbmZpZ1N0cmVhbVR5cGUSBwoDUkFXEAASFgoSUkVQUk9KX0ZBTFNFX0NPTE9SEAESFwoTUkVQUk9KX0dSQURJRU5UX0RPVBACEhUKEVJFUFJPSl9CTE9CX1NDT1JFEANCVUIQU3NsVnBDb25maWdQcm90b1ABWj9naXRodWIuY29tL1JvYm9DdXAtU1NML3NzbC12aXNpb24tcHJvY2Vzc29yL2d1aS9pbnRlcm5hbC92aXNpb24", [file_gamecontroller_ssl_gc_geometry]);
-
-/**
- * @generated from message SSL_VPConfigCamera
- */
-export type SSL_VPConfigCamera = Message<"SSL_VPConfigCamera"> & {
- /**
- * Camera driver type. Availability depending on libraries installed.
- *
- * @generated from field: optional SSL_VPConfigCameraDriver driver = 1;
- */
- driver: SSL_VPConfigCameraDriver;
-
- /**
- * Spinnaker, mvIMPACT or OpenCV(v4l2) camera id
- *
- * @generated from field: optional uint32 id = 2 [default = 0];
- */
- id: number;
-
- /**
- * OpenCV camera device, image or video file path (if unset id is used instead)
- *
- * @generated from field: optional string path = 3 [default = ""];
- */
- path: string;
-
- /**
- * Camera resolution as reported by the camera. VisionProcessor might use half (true color) resolution internally with SPINNAKER and MVIMPACT.
- * 0 = Highest resolution supported by camera
- *
- * @generated from field: optional uint32 width = 4 [default = 0];
- */
- width: number;
-
- /**
- * @generated from field: optional uint32 height = 5 [default = 0];
- */
- height: number;
-
- /**
- * Camera exposure time in ms to adjust brightness. Higher values lead to more motion blur. Lower values lead to a darker image.
- * Camera frame rate will drop if set equal to or higher than the frame time (1 / fps_cam).
- * 0.0 = automatic exposure
- *
- * @generated from field: optional float exposure = 6 [default = 0];
- */
- exposure: number;
-
- /**
- * Camera gain to adjust brightness. Higher values lead to more noise. Lower values lead to a darker image.
- * Frequently changing bot identities or team colors indicate an image that is too bright (all colors becoming nearly white).
- * 0.0 = automatic gain
- *
- * @generated from field: optional float gain = 7 [default = 0];
- */
- gain: number;
-
- /**
- * Camera gamma as nonlinear brightness adjustment. Only supported on SPINNAKER and OPENCV.
- * Low values reduce differences between bright and dark illuminated areas. High values increase the color contrast.
- * 1.0 = no gamma
- *
- * @generated from field: optional float gamma = 8 [default = 1];
- */
- gamma: number;
-
- /**
- * Camera white balance. OUTDOOR or INDOOR for auto white balance with green or gray carpet respectively.
- * (distinction between OUTDOOR and INDOOR currently only implemented for SPINNAKER backend)
- *
- * @generated from field: optional SSL_VPConfigCameraWBType wb_type = 9 [default = OUTDOOR];
- */
- wbType: SSL_VPConfigCameraWBType;
-
- /**
- * @generated from field: optional float wb_red = 10 [default = 1];
- */
- wbRed: number;
-
- /**
- * @generated from field: optional float wb_blue = 11 [default = 1];
- */
- wbBlue: number;
-};
-
-/**
- * @generated from message SSL_VPConfigCamera
- */
-export type SSL_VPConfigCameraJson = {
- /**
- * Camera driver type. Availability depending on libraries installed.
- *
- * @generated from field: optional SSL_VPConfigCameraDriver driver = 1;
- */
- driver?: SSL_VPConfigCameraDriverJson;
-
- /**
- * Spinnaker, mvIMPACT or OpenCV(v4l2) camera id
- *
- * @generated from field: optional uint32 id = 2 [default = 0];
- */
- id?: number;
-
- /**
- * OpenCV camera device, image or video file path (if unset id is used instead)
- *
- * @generated from field: optional string path = 3 [default = ""];
- */
- path?: string;
-
- /**
- * Camera resolution as reported by the camera. VisionProcessor might use half (true color) resolution internally with SPINNAKER and MVIMPACT.
- * 0 = Highest resolution supported by camera
- *
- * @generated from field: optional uint32 width = 4 [default = 0];
- */
- width?: number;
-
- /**
- * @generated from field: optional uint32 height = 5 [default = 0];
- */
- height?: number;
-
- /**
- * Camera exposure time in ms to adjust brightness. Higher values lead to more motion blur. Lower values lead to a darker image.
- * Camera frame rate will drop if set equal to or higher than the frame time (1 / fps_cam).
- * 0.0 = automatic exposure
- *
- * @generated from field: optional float exposure = 6 [default = 0];
- */
- exposure?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Camera gain to adjust brightness. Higher values lead to more noise. Lower values lead to a darker image.
- * Frequently changing bot identities or team colors indicate an image that is too bright (all colors becoming nearly white).
- * 0.0 = automatic gain
- *
- * @generated from field: optional float gain = 7 [default = 0];
- */
- gain?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Camera gamma as nonlinear brightness adjustment. Only supported on SPINNAKER and OPENCV.
- * Low values reduce differences between bright and dark illuminated areas. High values increase the color contrast.
- * 1.0 = no gamma
- *
- * @generated from field: optional float gamma = 8 [default = 1];
- */
- gamma?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Camera white balance. OUTDOOR or INDOOR for auto white balance with green or gray carpet respectively.
- * (distinction between OUTDOOR and INDOOR currently only implemented for SPINNAKER backend)
- *
- * @generated from field: optional SSL_VPConfigCameraWBType wb_type = 9 [default = OUTDOOR];
- */
- wbType?: SSL_VPConfigCameraWBTypeJson;
-
- /**
- * @generated from field: optional float wb_red = 10 [default = 1];
- */
- wbRed?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * @generated from field: optional float wb_blue = 11 [default = 1];
- */
- wbBlue?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message SSL_VPConfigCamera.
- * Use `create(SSL_VPConfigCameraSchema)` to create a new message.
- */
-export const SSL_VPConfigCameraSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vp_config, 0);
-
-/**
- * @generated from message SSL_VPConfigGeometry
- */
-export type SSL_VPConfigGeometry = Message<"SSL_VPConfigGeometry"> & {
- /**
- * Total camera amount over the field
- *
- * @generated from field: optional uint32 camera_amount = 1 [default = 1];
- */
- cameraAmount: number;
-
- /**
- * Camera height above field in mm
- * 0.0 = automated camera height calibration, this does not work if the camera looks perpendicular to the field.
- *
- * @generated from field: optional float camera_height = 2 [default = 0];
- */
- cameraHeight: number;
-
- /**
- * Field line crossings at the edges of the camera extent in pixels from the top left image corner.
- * The first coordinate must be the edge with the smallest x and y field coordinate.
- *
- * @generated from field: repeated Vector2 line_corners = 3;
- */
- lineCorners: Vector2[];
-
- /**
- * Enable field line pixel refinement.
- * Disable in cluttered environments when the geometry calibration has failed multiple times in a row.
- *
- * @generated from field: optional bool refinement = 4 [default = true];
- */
- refinement: boolean;
-};
-
-/**
- * @generated from message SSL_VPConfigGeometry
- */
-export type SSL_VPConfigGeometryJson = {
- /**
- * Total camera amount over the field
- *
- * @generated from field: optional uint32 camera_amount = 1 [default = 1];
- */
- cameraAmount?: number;
-
- /**
- * Camera height above field in mm
- * 0.0 = automated camera height calibration, this does not work if the camera looks perpendicular to the field.
- *
- * @generated from field: optional float camera_height = 2 [default = 0];
- */
- cameraHeight?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Field line crossings at the edges of the camera extent in pixels from the top left image corner.
- * The first coordinate must be the edge with the smallest x and y field coordinate.
- *
- * @generated from field: repeated Vector2 line_corners = 3;
- */
- lineCorners?: Vector2Json[];
-
- /**
- * Enable field line pixel refinement.
- * Disable in cluttered environments when the geometry calibration has failed multiple times in a row.
- *
- * @generated from field: optional bool refinement = 4 [default = true];
- */
- refinement?: boolean;
-};
-
-/**
- * Describes the message SSL_VPConfigGeometry.
- * Use `create(SSL_VPConfigGeometrySchema)` to create a new message.
- */
-export const SSL_VPConfigGeometrySchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vp_config, 1);
-
-/**
- * @generated from message SSL_VPConfigThresholds
- */
-export type SSL_VPConfigThresholds = Message<"SSL_VPConfigThresholds"> & {
- /**
- * Minimum mean cosine similarity (not normalized) of the blob border gradient (0 - 195075.0)
- * High value lead to undetected blobs. Low values lead to an increase in false positive blob detections.
- *
- * @generated from field: optional float circularity = 1 [default = 15];
- */
- circularity: number;
-
- /**
- * Minimum circularity/(3*stddev) ball blob score
- *
- * @generated from field: optional float score = 2 [default = 5];
- */
- score: number;
-
- /**
- * Minimum confidence (0.0 - 1.0)
- *
- * @generated from field: optional float min_confidence = 3 [default = 0.20000000298023224];
- */
- minConfidence: number;
-
- /**
- * Min ball camera edge distance in mm
- *
- * @generated from field: optional float min_cam_edge_distance = 4 [default = 170];
- */
- minCamEdgeDistance: number;
-
- /**
- * Maximum allowed clipping of two objects in mm
- *
- * @generated from field: optional float clipping_tolerance = 5 [default = 10];
- */
- clippingTolerance: number;
-
- /**
- * Added tolerance to geometry related operations in mm.
- * Affects field border cutoff area and field line blob classification.
- *
- * @generated from field: optional float geometry_tolerance = 6 [default = 10];
- */
- geometryTolerance: number;
-};
-
-/**
- * @generated from message SSL_VPConfigThresholds
- */
-export type SSL_VPConfigThresholdsJson = {
- /**
- * Minimum mean cosine similarity (not normalized) of the blob border gradient (0 - 195075.0)
- * High value lead to undetected blobs. Low values lead to an increase in false positive blob detections.
- *
- * @generated from field: optional float circularity = 1 [default = 15];
- */
- circularity?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Minimum circularity/(3*stddev) ball blob score
- *
- * @generated from field: optional float score = 2 [default = 5];
- */
- score?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Minimum confidence (0.0 - 1.0)
- *
- * @generated from field: optional float min_confidence = 3 [default = 0.20000000298023224];
- */
- minConfidence?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Min ball camera edge distance in mm
- *
- * @generated from field: optional float min_cam_edge_distance = 4 [default = 170];
- */
- minCamEdgeDistance?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Maximum allowed clipping of two objects in mm
- *
- * @generated from field: optional float clipping_tolerance = 5 [default = 10];
- */
- clippingTolerance?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Added tolerance to geometry related operations in mm.
- * Affects field border cutoff area and field line blob classification.
- *
- * @generated from field: optional float geometry_tolerance = 6 [default = 10];
- */
- geometryTolerance?: number | "NaN" | "Infinity" | "-Infinity";
-};
-
-/**
- * Describes the message SSL_VPConfigThresholds.
- * Use `create(SSL_VPConfigThresholdsSchema)` to create a new message.
- */
-export const SSL_VPConfigThresholdsSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vp_config, 2);
-
-/**
- * @generated from message Color
- */
-export type Color = Message<"Color"> & {
- /**
- * @generated from field: optional uint32 red = 1 [default = 128];
- */
- red: number;
-
- /**
- * @generated from field: optional uint32 green = 2 [default = 128];
- */
- green: number;
-
- /**
- * @generated from field: optional uint32 blue = 3 [default = 128];
- */
- blue: number;
-};
-
-/**
- * @generated from message Color
- */
-export type ColorJson = {
- /**
- * @generated from field: optional uint32 red = 1 [default = 128];
- */
- red?: number;
-
- /**
- * @generated from field: optional uint32 green = 2 [default = 128];
- */
- green?: number;
-
- /**
- * @generated from field: optional uint32 blue = 3 [default = 128];
- */
- blue?: number;
-};
-
-/**
- * Describes the message Color.
- * Use `create(ColorSchema)` to create a new message.
- */
-export const ColorSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vp_config, 3);
-
-/**
- * @generated from message VPColor
- */
-export type VPColor = Message<"VPColor"> & {
- /**
- * @generated from field: optional Color reference = 1;
- */
- reference?: Color;
-
- /**
- * @generated from field: optional Color live = 2;
- */
- live?: Color;
-};
-
-/**
- * @generated from message VPColor
- */
-export type VPColorJson = {
- /**
- * @generated from field: optional Color reference = 1;
- */
- reference?: ColorJson;
-
- /**
- * @generated from field: optional Color live = 2;
- */
- live?: ColorJson;
-};
-
-/**
- * Describes the message VPColor.
- * Use `create(VPColorSchema)` to create a new message.
- */
-export const VPColorSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vp_config, 4);
-
-/**
- * @generated from message SSL_VPConfigColor
- */
-export type SSL_VPConfigColor = Message<"SSL_VPConfigColor"> & {
- /**
- * Strength of the reference color during color updates (0.0 - 0.5-history_force/2)
- *
- * @generated from field: optional float reference_force = 1 [default = 0.10000000149011612];
- */
- referenceForce: number;
-
- /**
- * Strength of the previous color during color updates (0.0 - 1.0-reference_force)
- *
- * @generated from field: optional float history_force = 2 [default = 0.699999988079071];
- */
- historyForce: number;
-
- /**
- * Colors used for ball determination
- *
- * @generated from field: optional VPColor orange = 3;
- */
- orange?: VPColor;
-
- /**
- * @generated from field: optional VPColor field = 4;
- */
- field?: VPColor;
-
- /**
- * Colors used for center blob determination
- *
- * @generated from field: optional VPColor yellow = 5;
- */
- yellow?: VPColor;
-
- /**
- * @generated from field: optional VPColor blue = 6;
- */
- blue?: VPColor;
-
- /**
- * Colors used for side blob determination
- *
- * @generated from field: optional VPColor green = 7;
- */
- green?: VPColor;
-
- /**
- * @generated from field: optional VPColor pink = 8;
- */
- pink?: VPColor;
-};
-
-/**
- * @generated from message SSL_VPConfigColor
- */
-export type SSL_VPConfigColorJson = {
- /**
- * Strength of the reference color during color updates (0.0 - 0.5-history_force/2)
- *
- * @generated from field: optional float reference_force = 1 [default = 0.10000000149011612];
- */
- referenceForce?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Strength of the previous color during color updates (0.0 - 1.0-reference_force)
- *
- * @generated from field: optional float history_force = 2 [default = 0.699999988079071];
- */
- historyForce?: number | "NaN" | "Infinity" | "-Infinity";
-
- /**
- * Colors used for ball determination
- *
- * @generated from field: optional VPColor orange = 3;
- */
- orange?: VPColorJson;
-
- /**
- * @generated from field: optional VPColor field = 4;
- */
- field?: VPColorJson;
-
- /**
- * Colors used for center blob determination
- *
- * @generated from field: optional VPColor yellow = 5;
- */
- yellow?: VPColorJson;
-
- /**
- * @generated from field: optional VPColor blue = 6;
- */
- blue?: VPColorJson;
-
- /**
- * Colors used for side blob determination
- *
- * @generated from field: optional VPColor green = 7;
- */
- green?: VPColorJson;
-
- /**
- * @generated from field: optional VPColor pink = 8;
- */
- pink?: VPColorJson;
-};
-
-/**
- * Describes the message SSL_VPConfigColor.
- * Use `create(SSL_VPConfigColorSchema)` to create a new message.
- */
-export const SSL_VPConfigColorSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vp_config, 5);
-
-/**
- * @generated from message SSL_VPConfigNetwork
- */
-export type SSL_VPConfigNetwork = Message<"SSL_VPConfigNetwork"> & {
- /**
- * Game controller ip address
- *
- * @generated from field: optional string gc_ip = 1 [default = "224.5.23.1"];
- */
- gcIp: string;
-
- /**
- * Game controller UDP port
- *
- * @generated from field: optional uint32 gc_port = 2 [default = 10003];
- */
- gcPort: number;
-
- /**
- * Vision IP address (port impossible to adjust over network)
- *
- * @generated from field: optional string vision_ip = 3 [default = "224.5.23.2"];
- */
- visionIp: string;
-};
-
-/**
- * @generated from message SSL_VPConfigNetwork
- */
-export type SSL_VPConfigNetworkJson = {
- /**
- * Game controller ip address
- *
- * @generated from field: optional string gc_ip = 1 [default = "224.5.23.1"];
- */
- gcIp?: string;
-
- /**
- * Game controller UDP port
- *
- * @generated from field: optional uint32 gc_port = 2 [default = 10003];
- */
- gcPort?: number;
-
- /**
- * Vision IP address (port impossible to adjust over network)
- *
- * @generated from field: optional string vision_ip = 3 [default = "224.5.23.2"];
- */
- visionIp?: string;
-};
-
-/**
- * Describes the message SSL_VPConfigNetwork.
- * Use `create(SSL_VPConfigNetworkSchema)` to create a new message.
- */
-export const SSL_VPConfigNetworkSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vp_config, 6);
-
-/**
- * @generated from message SSL_VPConfigStream
- */
-export type SSL_VPConfigStream = Message<"SSL_VPConfigStream"> & {
- /**
- * If false no network live stream will be encoded and sent.
- *
- * @generated from field: optional bool active = 1 [default = true];
- */
- active: boolean;
-
- /**
- * Type of image to transmit.
- *
- * @generated from field: optional SSL_VPConfigStreamType type = 2 [default = RAW];
- */
- type: SSL_VPConfigStreamType;
-
- /**
- * Camera RTP stream destination IP
- *
- * @generated from field: optional string stream_ip = 3 [default = "127.0.0.1"];
- */
- streamIp: string;
-
- /**
- * @generated from field: optional uint32 stream_port = 4 [default = 10100];
- */
- streamPort: number;
-};
-
-/**
- * @generated from message SSL_VPConfigStream
- */
-export type SSL_VPConfigStreamJson = {
- /**
- * If false no network live stream will be encoded and sent.
- *
- * @generated from field: optional bool active = 1 [default = true];
- */
- active?: boolean;
-
- /**
- * Type of image to transmit.
- *
- * @generated from field: optional SSL_VPConfigStreamType type = 2 [default = RAW];
- */
- type?: SSL_VPConfigStreamTypeJson;
-
- /**
- * Camera RTP stream destination IP
- *
- * @generated from field: optional string stream_ip = 3 [default = "127.0.0.1"];
- */
- streamIp?: string;
-
- /**
- * @generated from field: optional uint32 stream_port = 4 [default = 10100];
- */
- streamPort?: number;
-};
-
-/**
- * Describes the message SSL_VPConfigStream.
- * Use `create(SSL_VPConfigStreamSchema)` to create a new message.
- */
-export const SSL_VPConfigStreamSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vp_config, 7);
-
-/**
- * @generated from message SSL_VPConfig
- */
-export type SSL_VPConfig = Message<"SSL_VPConfig"> & {
- /**
- * Persistent human-readable network unique identifier (e.g. hostname or hostname:suffix if multiple VP instances on the same host).
- *
- * @generated from field: required string instance = 1;
- */
- instance: string;
-
- /**
- * Corresponding to the camera_id used in SSL_DetectionFrame. Unique per field and implies position on the field:
- * Single camera field: 0 = global field
- * Double camera field: 0 = -x side, 1 = +x side
- * Quadruple cam field: 0 = -x and -y, 1 = -x and +y, 2 = +x and -y, 3 = +x and +y
- * Configuration for more cams depending on field shape.
- *
- * @generated from field: optional uint32 camera_id = 2 [default = 0];
- */
- cameraId: number;
-
- /**
- * Database of SSL game controller team names and robot heights in mm.
- * If the team broadcasted by the game controller has no entry, the average robot height is used.
- *
- * @generated from field: map robot_heights = 3;
- */
- robotHeights: { [key: string]: number };
-
- /**
- * @generated from field: optional SSL_VPConfigCamera camera = 4;
- */
- camera?: SSL_VPConfigCamera;
-
- /**
- * @generated from field: optional SSL_VPConfigGeometry geometry = 5;
- */
- geometry?: SSL_VPConfigGeometry;
-
- /**
- * @generated from field: optional SSL_VPConfigThresholds thresholds = 6;
- */
- thresholds?: SSL_VPConfigThresholds;
-
- /**
- * @generated from field: optional SSL_VPConfigColor color = 7;
- */
- color?: SSL_VPConfigColor;
-
- /**
- * @generated from field: optional SSL_VPConfigNetwork network = 8;
- */
- network?: SSL_VPConfigNetwork;
-
- /**
- * @generated from field: optional SSL_VPConfigStream stream = 9;
- */
- stream?: SSL_VPConfigStream;
-
- /**
- * Wait for geometry prior to processing frames
- *
- * @generated from field: optional bool wait_for_geometry = 10 [default = false];
- */
- waitForGeometry: boolean;
-};
-
-/**
- * @generated from message SSL_VPConfig
- */
-export type SSL_VPConfigJson = {
- /**
- * Persistent human-readable network unique identifier (e.g. hostname or hostname:suffix if multiple VP instances on the same host).
- *
- * @generated from field: required string instance = 1;
- */
- instance?: string;
-
- /**
- * Corresponding to the camera_id used in SSL_DetectionFrame. Unique per field and implies position on the field:
- * Single camera field: 0 = global field
- * Double camera field: 0 = -x side, 1 = +x side
- * Quadruple cam field: 0 = -x and -y, 1 = -x and +y, 2 = +x and -y, 3 = +x and +y
- * Configuration for more cams depending on field shape.
- *
- * @generated from field: optional uint32 camera_id = 2 [default = 0];
- */
- cameraId?: number;
-
- /**
- * Database of SSL game controller team names and robot heights in mm.
- * If the team broadcasted by the game controller has no entry, the average robot height is used.
- *
- * @generated from field: map robot_heights = 3;
- */
- robotHeights?: { [key: string]: number | "NaN" | "Infinity" | "-Infinity" };
-
- /**
- * @generated from field: optional SSL_VPConfigCamera camera = 4;
- */
- camera?: SSL_VPConfigCameraJson;
-
- /**
- * @generated from field: optional SSL_VPConfigGeometry geometry = 5;
- */
- geometry?: SSL_VPConfigGeometryJson;
-
- /**
- * @generated from field: optional SSL_VPConfigThresholds thresholds = 6;
- */
- thresholds?: SSL_VPConfigThresholdsJson;
-
- /**
- * @generated from field: optional SSL_VPConfigColor color = 7;
- */
- color?: SSL_VPConfigColorJson;
-
- /**
- * @generated from field: optional SSL_VPConfigNetwork network = 8;
- */
- network?: SSL_VPConfigNetworkJson;
-
- /**
- * @generated from field: optional SSL_VPConfigStream stream = 9;
- */
- stream?: SSL_VPConfigStreamJson;
-
- /**
- * Wait for geometry prior to processing frames
- *
- * @generated from field: optional bool wait_for_geometry = 10 [default = false];
- */
- waitForGeometry?: boolean;
-};
-
-/**
- * Describes the message SSL_VPConfig.
- * Use `create(SSL_VPConfigSchema)` to create a new message.
- */
-export const SSL_VPConfigSchema: GenMessage = /*@__PURE__*/
- messageDesc(file_vision_ssl_vp_config, 8);
-
-/**
- * @generated from enum SSL_VPConfigCameraDriver
- */
-export enum SSL_VPConfigCameraDriver {
- /**
- * FLIR cameras
- *
- * @generated from enum value: SPINNAKER = 0;
- */
- SPINNAKER = 0,
-
- /**
- * Video and image files, video4linux2 (e.g. webcams) cameras
- *
- * @generated from enum value: OPENCV = 1;
- */
- OPENCV = 1,
-
- /**
- * Bluefox3 cameras
- *
- * @generated from enum value: MVIMPACT = 2;
- */
- MVIMPACT = 2,
-}
-
-/**
- * @generated from enum SSL_VPConfigCameraDriver
- */
-export type SSL_VPConfigCameraDriverJson = "SPINNAKER" | "OPENCV" | "MVIMPACT";
-
-/**
- * Describes the enum SSL_VPConfigCameraDriver.
- */
-export const SSL_VPConfigCameraDriverSchema: GenEnum = /*@__PURE__*/
- enumDesc(file_vision_ssl_vp_config, 0);
-
-/**
- * @generated from enum SSL_VPConfigCameraWBType
- */
-export enum SSL_VPConfigCameraWBType {
- /**
- * @generated from enum value: OUTDOOR = 0;
- */
- OUTDOOR = 0,
-
- /**
- * @generated from enum value: INDOOR = 1;
- */
- INDOOR = 1,
-
- /**
- * @generated from enum value: MANUAL = 2;
- */
- MANUAL = 2,
-}
-
-/**
- * @generated from enum SSL_VPConfigCameraWBType
- */
-export type SSL_VPConfigCameraWBTypeJson = "OUTDOOR" | "INDOOR" | "MANUAL";
-
-/**
- * Describes the enum SSL_VPConfigCameraWBType.
- */
-export const SSL_VPConfigCameraWBTypeSchema: GenEnum = /*@__PURE__*/
- enumDesc(file_vision_ssl_vp_config, 1);
-
-/**
- * @generated from enum SSL_VPConfigStreamType
- */
-export enum SSL_VPConfigStreamType {
- /**
- * @generated from enum value: RAW = 0;
- */
- RAW = 0,
-
- /**
- * @generated from enum value: REPROJ_FALSE_COLOR = 1;
- */
- REPROJ_FALSE_COLOR = 1,
-
- /**
- * @generated from enum value: REPROJ_GRADIENT_DOT = 2;
- */
- REPROJ_GRADIENT_DOT = 2,
-
- /**
- * @generated from enum value: REPROJ_BLOB_SCORE = 3;
- */
- REPROJ_BLOB_SCORE = 3,
-}
-
-/**
- * @generated from enum SSL_VPConfigStreamType
- */
-export type SSL_VPConfigStreamTypeJson = "RAW" | "REPROJ_FALSE_COLOR" | "REPROJ_GRADIENT_DOT" | "REPROJ_BLOB_SCORE";
-
-/**
- * Describes the enum SSL_VPConfigStreamType.
- */
-export const SSL_VPConfigStreamTypeSchema: GenEnum = /*@__PURE__*/
- enumDesc(file_vision_ssl_vp_config, 2);
-
diff --git a/gui/go.mod b/gui/go.mod
index 619772b..3b78cb2 100644
--- a/gui/go.mod
+++ b/gui/go.mod
@@ -18,3 +18,5 @@ require (
golang.org/x/net v0.55.0 // indirect
golang.org/x/sys v0.45.0 // indirect
)
+
+tool google.golang.org/protobuf/cmd/protoc-gen-go
diff --git a/gui/internal/gamecontroller/ssl_gc_common.pb.go b/gui/internal/gamecontroller/ssl_gc_common.pb.go
deleted file mode 100644
index c9ee1ad..0000000
--- a/gui/internal/gamecontroller/ssl_gc_common.pb.go
+++ /dev/null
@@ -1,271 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.36.6
-// protoc (unknown)
-// source: gamecontroller/ssl_gc_common.proto
-
-package gamecontroller
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
- unsafe "unsafe"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-// Team is either blue or yellow
-type Team int32
-
-const (
- // team not set
- Team_UNKNOWN Team = 0
- // yellow team
- Team_YELLOW Team = 1
- // blue team
- Team_BLUE Team = 2
-)
-
-// Enum value maps for Team.
-var (
- Team_name = map[int32]string{
- 0: "UNKNOWN",
- 1: "YELLOW",
- 2: "BLUE",
- }
- Team_value = map[string]int32{
- "UNKNOWN": 0,
- "YELLOW": 1,
- "BLUE": 2,
- }
-)
-
-func (x Team) Enum() *Team {
- p := new(Team)
- *p = x
- return p
-}
-
-func (x Team) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (Team) Descriptor() protoreflect.EnumDescriptor {
- return file_gamecontroller_ssl_gc_common_proto_enumTypes[0].Descriptor()
-}
-
-func (Team) Type() protoreflect.EnumType {
- return &file_gamecontroller_ssl_gc_common_proto_enumTypes[0]
-}
-
-func (x Team) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Do not use.
-func (x *Team) UnmarshalJSON(b []byte) error {
- num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
- if err != nil {
- return err
- }
- *x = Team(num)
- return nil
-}
-
-// Deprecated: Use Team.Descriptor instead.
-func (Team) EnumDescriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_common_proto_rawDescGZIP(), []int{0}
-}
-
-// Division denotes the current division, which influences some rules
-type Division int32
-
-const (
- Division_DIV_UNKNOWN Division = 0
- Division_DIV_A Division = 1
- Division_DIV_B Division = 2
-)
-
-// Enum value maps for Division.
-var (
- Division_name = map[int32]string{
- 0: "DIV_UNKNOWN",
- 1: "DIV_A",
- 2: "DIV_B",
- }
- Division_value = map[string]int32{
- "DIV_UNKNOWN": 0,
- "DIV_A": 1,
- "DIV_B": 2,
- }
-)
-
-func (x Division) Enum() *Division {
- p := new(Division)
- *p = x
- return p
-}
-
-func (x Division) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (Division) Descriptor() protoreflect.EnumDescriptor {
- return file_gamecontroller_ssl_gc_common_proto_enumTypes[1].Descriptor()
-}
-
-func (Division) Type() protoreflect.EnumType {
- return &file_gamecontroller_ssl_gc_common_proto_enumTypes[1]
-}
-
-func (x Division) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Do not use.
-func (x *Division) UnmarshalJSON(b []byte) error {
- num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
- if err != nil {
- return err
- }
- *x = Division(num)
- return nil
-}
-
-// Deprecated: Use Division.Descriptor instead.
-func (Division) EnumDescriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_common_proto_rawDescGZIP(), []int{1}
-}
-
-// RobotId is the combination of a team and a robot id
-type RobotId struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the robot number
- Id *uint32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"`
- // the team that the robot belongs to
- Team *Team `protobuf:"varint,2,opt,name=team,enum=Team" json:"team,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *RobotId) Reset() {
- *x = RobotId{}
- mi := &file_gamecontroller_ssl_gc_common_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *RobotId) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*RobotId) ProtoMessage() {}
-
-func (x *RobotId) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_common_proto_msgTypes[0]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use RobotId.ProtoReflect.Descriptor instead.
-func (*RobotId) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_common_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *RobotId) GetId() uint32 {
- if x != nil && x.Id != nil {
- return *x.Id
- }
- return 0
-}
-
-func (x *RobotId) GetTeam() Team {
- if x != nil && x.Team != nil {
- return *x.Team
- }
- return Team_UNKNOWN
-}
-
-var File_gamecontroller_ssl_gc_common_proto protoreflect.FileDescriptor
-
-const file_gamecontroller_ssl_gc_common_proto_rawDesc = "" +
- "\n" +
- "\"gamecontroller/ssl_gc_common.proto\"4\n" +
- "\aRobotId\x12\x0e\n" +
- "\x02id\x18\x01 \x01(\rR\x02id\x12\x19\n" +
- "\x04team\x18\x02 \x01(\x0e2\x05.TeamR\x04team*)\n" +
- "\x04Team\x12\v\n" +
- "\aUNKNOWN\x10\x00\x12\n" +
- "\n" +
- "\x06YELLOW\x10\x01\x12\b\n" +
- "\x04BLUE\x10\x02*1\n" +
- "\bDivision\x12\x0f\n" +
- "\vDIV_UNKNOWN\x10\x00\x12\t\n" +
- "\x05DIV_A\x10\x01\x12\t\n" +
- "\x05DIV_B\x10\x02B]B\x10SslGcCommonProtoP\x01ZGgithub.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
-
-var (
- file_gamecontroller_ssl_gc_common_proto_rawDescOnce sync.Once
- file_gamecontroller_ssl_gc_common_proto_rawDescData []byte
-)
-
-func file_gamecontroller_ssl_gc_common_proto_rawDescGZIP() []byte {
- file_gamecontroller_ssl_gc_common_proto_rawDescOnce.Do(func() {
- file_gamecontroller_ssl_gc_common_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_common_proto_rawDesc), len(file_gamecontroller_ssl_gc_common_proto_rawDesc)))
- })
- return file_gamecontroller_ssl_gc_common_proto_rawDescData
-}
-
-var file_gamecontroller_ssl_gc_common_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
-var file_gamecontroller_ssl_gc_common_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
-var file_gamecontroller_ssl_gc_common_proto_goTypes = []any{
- (Team)(0), // 0: Team
- (Division)(0), // 1: Division
- (*RobotId)(nil), // 2: RobotId
-}
-var file_gamecontroller_ssl_gc_common_proto_depIdxs = []int32{
- 0, // 0: RobotId.team:type_name -> Team
- 1, // [1:1] is the sub-list for method output_type
- 1, // [1:1] is the sub-list for method input_type
- 1, // [1:1] is the sub-list for extension type_name
- 1, // [1:1] is the sub-list for extension extendee
- 0, // [0:1] is the sub-list for field type_name
-}
-
-func init() { file_gamecontroller_ssl_gc_common_proto_init() }
-func file_gamecontroller_ssl_gc_common_proto_init() {
- if File_gamecontroller_ssl_gc_common_proto != nil {
- return
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_common_proto_rawDesc), len(file_gamecontroller_ssl_gc_common_proto_rawDesc)),
- NumEnums: 2,
- NumMessages: 1,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_gamecontroller_ssl_gc_common_proto_goTypes,
- DependencyIndexes: file_gamecontroller_ssl_gc_common_proto_depIdxs,
- EnumInfos: file_gamecontroller_ssl_gc_common_proto_enumTypes,
- MessageInfos: file_gamecontroller_ssl_gc_common_proto_msgTypes,
- }.Build()
- File_gamecontroller_ssl_gc_common_proto = out.File
- file_gamecontroller_ssl_gc_common_proto_goTypes = nil
- file_gamecontroller_ssl_gc_common_proto_depIdxs = nil
-}
diff --git a/gui/internal/gamecontroller/ssl_gc_game_event.pb.go b/gui/internal/gamecontroller/ssl_gc_game_event.pb.go
deleted file mode 100644
index 8c20140..0000000
--- a/gui/internal/gamecontroller/ssl_gc_game_event.pb.go
+++ /dev/null
@@ -1,4459 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.36.6
-// protoc (unknown)
-// source: gamecontroller/ssl_gc_game_event.proto
-
-package gamecontroller
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
- unsafe "unsafe"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-type GameEvent_Type int32
-
-const (
- GameEvent_UNKNOWN_GAME_EVENT_TYPE GameEvent_Type = 0
- GameEvent_BALL_LEFT_FIELD_TOUCH_LINE GameEvent_Type = 6 // triggered by autoRef
- GameEvent_BALL_LEFT_FIELD_GOAL_LINE GameEvent_Type = 7 // triggered by autoRef
- GameEvent_AIMLESS_KICK GameEvent_Type = 11 // triggered by autoRef
- GameEvent_ATTACKER_TOO_CLOSE_TO_DEFENSE_AREA GameEvent_Type = 19 // triggered by autoRef
- GameEvent_DEFENDER_IN_DEFENSE_AREA GameEvent_Type = 31 // triggered by autoRef
- GameEvent_BOUNDARY_CROSSING GameEvent_Type = 41 // triggered by autoRef
- GameEvent_KEEPER_HELD_BALL GameEvent_Type = 13 // triggered by GC
- GameEvent_BOT_DRIBBLED_BALL_TOO_FAR GameEvent_Type = 17 // triggered by autoRef
- GameEvent_BOT_PUSHED_BOT GameEvent_Type = 24 // triggered by human ref
- GameEvent_BOT_HELD_BALL_DELIBERATELY GameEvent_Type = 26 // triggered by human ref
- GameEvent_BOT_TIPPED_OVER GameEvent_Type = 27 // triggered by human ref
- GameEvent_BOT_DROPPED_PARTS GameEvent_Type = 47 // triggered by human ref
- GameEvent_ATTACKER_TOUCHED_BALL_IN_DEFENSE_AREA GameEvent_Type = 15 // triggered by autoRef
- GameEvent_BOT_KICKED_BALL_TOO_FAST GameEvent_Type = 18 // triggered by autoRef
- GameEvent_BOT_CRASH_UNIQUE GameEvent_Type = 22 // triggered by autoRef
- GameEvent_BOT_CRASH_DRAWN GameEvent_Type = 21 // triggered by autoRef
- GameEvent_DEFENDER_TOO_CLOSE_TO_KICK_POINT GameEvent_Type = 29 // triggered by autoRef
- GameEvent_BOT_TOO_FAST_IN_STOP GameEvent_Type = 28 // triggered by autoRef
- GameEvent_BOT_INTERFERED_PLACEMENT GameEvent_Type = 20 // triggered by autoRef
- GameEvent_EXCESSIVE_BOT_SUBSTITUTION GameEvent_Type = 48 // triggered by GC
- GameEvent_POSSIBLE_GOAL GameEvent_Type = 39 // triggered by autoRef
- GameEvent_GOAL GameEvent_Type = 8 // triggered by GC
- GameEvent_INVALID_GOAL GameEvent_Type = 42 // triggered by GC
- GameEvent_ATTACKER_DOUBLE_TOUCHED_BALL GameEvent_Type = 14 // triggered by autoRef
- GameEvent_PLACEMENT_SUCCEEDED GameEvent_Type = 5 // triggered by autoRef
- GameEvent_PENALTY_KICK_FAILED GameEvent_Type = 43 // triggered by GC and autoRef
- GameEvent_NO_PROGRESS_IN_GAME GameEvent_Type = 2 // triggered by GC
- GameEvent_PLACEMENT_FAILED GameEvent_Type = 3 // triggered by GC
- GameEvent_MULTIPLE_CARDS GameEvent_Type = 32 // triggered by GC
- GameEvent_MULTIPLE_FOULS GameEvent_Type = 34 // triggered by GC
- GameEvent_BOT_SUBSTITUTION GameEvent_Type = 37 // triggered by GC
- GameEvent_TOO_MANY_ROBOTS GameEvent_Type = 38 // triggered by GC
- GameEvent_CHALLENGE_FLAG GameEvent_Type = 44 // triggered by GC
- GameEvent_CHALLENGE_FLAG_HANDLED GameEvent_Type = 46 // triggered by GC
- GameEvent_EMERGENCY_STOP GameEvent_Type = 45 // triggered by GC
- GameEvent_UNSPORTING_BEHAVIOR_MINOR GameEvent_Type = 35 // triggered by human ref
- GameEvent_UNSPORTING_BEHAVIOR_MAJOR GameEvent_Type = 36 // triggered by human ref
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- GameEvent_PREPARED GameEvent_Type = 1
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- GameEvent_INDIRECT_GOAL GameEvent_Type = 9
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- GameEvent_CHIPPED_GOAL GameEvent_Type = 10
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- GameEvent_KICK_TIMEOUT GameEvent_Type = 12
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- GameEvent_ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA GameEvent_Type = 16
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- GameEvent_ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA_SKIPPED GameEvent_Type = 40
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- GameEvent_BOT_CRASH_UNIQUE_SKIPPED GameEvent_Type = 23
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- GameEvent_BOT_PUSHED_BOT_SKIPPED GameEvent_Type = 25
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- GameEvent_DEFENDER_IN_DEFENSE_AREA_PARTIALLY GameEvent_Type = 30
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- GameEvent_MULTIPLE_PLACEMENT_FAILURES GameEvent_Type = 33
-)
-
-// Enum value maps for GameEvent_Type.
-var (
- GameEvent_Type_name = map[int32]string{
- 0: "UNKNOWN_GAME_EVENT_TYPE",
- 6: "BALL_LEFT_FIELD_TOUCH_LINE",
- 7: "BALL_LEFT_FIELD_GOAL_LINE",
- 11: "AIMLESS_KICK",
- 19: "ATTACKER_TOO_CLOSE_TO_DEFENSE_AREA",
- 31: "DEFENDER_IN_DEFENSE_AREA",
- 41: "BOUNDARY_CROSSING",
- 13: "KEEPER_HELD_BALL",
- 17: "BOT_DRIBBLED_BALL_TOO_FAR",
- 24: "BOT_PUSHED_BOT",
- 26: "BOT_HELD_BALL_DELIBERATELY",
- 27: "BOT_TIPPED_OVER",
- 47: "BOT_DROPPED_PARTS",
- 15: "ATTACKER_TOUCHED_BALL_IN_DEFENSE_AREA",
- 18: "BOT_KICKED_BALL_TOO_FAST",
- 22: "BOT_CRASH_UNIQUE",
- 21: "BOT_CRASH_DRAWN",
- 29: "DEFENDER_TOO_CLOSE_TO_KICK_POINT",
- 28: "BOT_TOO_FAST_IN_STOP",
- 20: "BOT_INTERFERED_PLACEMENT",
- 48: "EXCESSIVE_BOT_SUBSTITUTION",
- 39: "POSSIBLE_GOAL",
- 8: "GOAL",
- 42: "INVALID_GOAL",
- 14: "ATTACKER_DOUBLE_TOUCHED_BALL",
- 5: "PLACEMENT_SUCCEEDED",
- 43: "PENALTY_KICK_FAILED",
- 2: "NO_PROGRESS_IN_GAME",
- 3: "PLACEMENT_FAILED",
- 32: "MULTIPLE_CARDS",
- 34: "MULTIPLE_FOULS",
- 37: "BOT_SUBSTITUTION",
- 38: "TOO_MANY_ROBOTS",
- 44: "CHALLENGE_FLAG",
- 46: "CHALLENGE_FLAG_HANDLED",
- 45: "EMERGENCY_STOP",
- 35: "UNSPORTING_BEHAVIOR_MINOR",
- 36: "UNSPORTING_BEHAVIOR_MAJOR",
- 1: "PREPARED",
- 9: "INDIRECT_GOAL",
- 10: "CHIPPED_GOAL",
- 12: "KICK_TIMEOUT",
- 16: "ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA",
- 40: "ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA_SKIPPED",
- 23: "BOT_CRASH_UNIQUE_SKIPPED",
- 25: "BOT_PUSHED_BOT_SKIPPED",
- 30: "DEFENDER_IN_DEFENSE_AREA_PARTIALLY",
- 33: "MULTIPLE_PLACEMENT_FAILURES",
- }
- GameEvent_Type_value = map[string]int32{
- "UNKNOWN_GAME_EVENT_TYPE": 0,
- "BALL_LEFT_FIELD_TOUCH_LINE": 6,
- "BALL_LEFT_FIELD_GOAL_LINE": 7,
- "AIMLESS_KICK": 11,
- "ATTACKER_TOO_CLOSE_TO_DEFENSE_AREA": 19,
- "DEFENDER_IN_DEFENSE_AREA": 31,
- "BOUNDARY_CROSSING": 41,
- "KEEPER_HELD_BALL": 13,
- "BOT_DRIBBLED_BALL_TOO_FAR": 17,
- "BOT_PUSHED_BOT": 24,
- "BOT_HELD_BALL_DELIBERATELY": 26,
- "BOT_TIPPED_OVER": 27,
- "BOT_DROPPED_PARTS": 47,
- "ATTACKER_TOUCHED_BALL_IN_DEFENSE_AREA": 15,
- "BOT_KICKED_BALL_TOO_FAST": 18,
- "BOT_CRASH_UNIQUE": 22,
- "BOT_CRASH_DRAWN": 21,
- "DEFENDER_TOO_CLOSE_TO_KICK_POINT": 29,
- "BOT_TOO_FAST_IN_STOP": 28,
- "BOT_INTERFERED_PLACEMENT": 20,
- "EXCESSIVE_BOT_SUBSTITUTION": 48,
- "POSSIBLE_GOAL": 39,
- "GOAL": 8,
- "INVALID_GOAL": 42,
- "ATTACKER_DOUBLE_TOUCHED_BALL": 14,
- "PLACEMENT_SUCCEEDED": 5,
- "PENALTY_KICK_FAILED": 43,
- "NO_PROGRESS_IN_GAME": 2,
- "PLACEMENT_FAILED": 3,
- "MULTIPLE_CARDS": 32,
- "MULTIPLE_FOULS": 34,
- "BOT_SUBSTITUTION": 37,
- "TOO_MANY_ROBOTS": 38,
- "CHALLENGE_FLAG": 44,
- "CHALLENGE_FLAG_HANDLED": 46,
- "EMERGENCY_STOP": 45,
- "UNSPORTING_BEHAVIOR_MINOR": 35,
- "UNSPORTING_BEHAVIOR_MAJOR": 36,
- "PREPARED": 1,
- "INDIRECT_GOAL": 9,
- "CHIPPED_GOAL": 10,
- "KICK_TIMEOUT": 12,
- "ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA": 16,
- "ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA_SKIPPED": 40,
- "BOT_CRASH_UNIQUE_SKIPPED": 23,
- "BOT_PUSHED_BOT_SKIPPED": 25,
- "DEFENDER_IN_DEFENSE_AREA_PARTIALLY": 30,
- "MULTIPLE_PLACEMENT_FAILURES": 33,
- }
-)
-
-func (x GameEvent_Type) Enum() *GameEvent_Type {
- p := new(GameEvent_Type)
- *p = x
- return p
-}
-
-func (x GameEvent_Type) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (GameEvent_Type) Descriptor() protoreflect.EnumDescriptor {
- return file_gamecontroller_ssl_gc_game_event_proto_enumTypes[0].Descriptor()
-}
-
-func (GameEvent_Type) Type() protoreflect.EnumType {
- return &file_gamecontroller_ssl_gc_game_event_proto_enumTypes[0]
-}
-
-func (x GameEvent_Type) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Do not use.
-func (x *GameEvent_Type) UnmarshalJSON(b []byte) error {
- num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
- if err != nil {
- return err
- }
- *x = GameEvent_Type(num)
- return nil
-}
-
-// Deprecated: Use GameEvent_Type.Descriptor instead.
-func (GameEvent_Type) EnumDescriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 0}
-}
-
-// GameEvent contains exactly one game event
-// Each game event has optional and required fields. The required fields are mandatory to process the event.
-// Some optional fields are only used for visualization, others are required to determine the ball placement position.
-// If fields are missing that are required for the ball placement position, no ball placement command will be issued.
-// Fields are marked optional to make testing and extending of the protocol easier.
-// An autoRef should ideally set all fields, except if there are good reasons to not do so.
-type GameEvent struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // A globally unique id of the game event.
- Id *string `protobuf:"bytes,50,opt,name=id" json:"id,omitempty"`
- // The type of the game event.
- Type *GameEvent_Type `protobuf:"varint,40,opt,name=type,enum=GameEvent_Type" json:"type,omitempty"`
- // The origins of this game event.
- // Empty, if it originates from game controller.
- // Contains autoRef name(s), if it originates from one or more autoRefs.
- // Ignored if sent by autoRef to game controller.
- Origin []string `protobuf:"bytes,41,rep,name=origin" json:"origin,omitempty"`
- // Unix timestamp in microseconds when the event was created.
- CreatedTimestamp *uint64 `protobuf:"varint,49,opt,name=created_timestamp,json=createdTimestamp" json:"created_timestamp,omitempty"`
- // the event that occurred
- //
- // Types that are valid to be assigned to Event:
- //
- // *GameEvent_BallLeftFieldTouchLine
- // *GameEvent_BallLeftFieldGoalLine
- // *GameEvent_AimlessKick_
- // *GameEvent_AttackerTooCloseToDefenseArea_
- // *GameEvent_DefenderInDefenseArea_
- // *GameEvent_BoundaryCrossing_
- // *GameEvent_KeeperHeldBall_
- // *GameEvent_BotDribbledBallTooFar_
- // *GameEvent_BotPushedBot_
- // *GameEvent_BotHeldBallDeliberately_
- // *GameEvent_BotTippedOver_
- // *GameEvent_BotDroppedParts_
- // *GameEvent_AttackerTouchedBallInDefenseArea_
- // *GameEvent_BotKickedBallTooFast_
- // *GameEvent_BotCrashUnique_
- // *GameEvent_BotCrashDrawn_
- // *GameEvent_DefenderTooCloseToKickPoint_
- // *GameEvent_BotTooFastInStop_
- // *GameEvent_BotInterferedPlacement_
- // *GameEvent_PossibleGoal
- // *GameEvent_Goal_
- // *GameEvent_InvalidGoal
- // *GameEvent_AttackerDoubleTouchedBall_
- // *GameEvent_PlacementSucceeded_
- // *GameEvent_PenaltyKickFailed_
- // *GameEvent_NoProgressInGame_
- // *GameEvent_PlacementFailed_
- // *GameEvent_MultipleCards_
- // *GameEvent_MultipleFouls_
- // *GameEvent_BotSubstitution_
- // *GameEvent_ExcessiveBotSubstitution_
- // *GameEvent_TooManyRobots_
- // *GameEvent_ChallengeFlag_
- // *GameEvent_ChallengeFlagHandled_
- // *GameEvent_EmergencyStop_
- // *GameEvent_UnsportingBehaviorMinor_
- // *GameEvent_UnsportingBehaviorMajor_
- // *GameEvent_Prepared_
- // *GameEvent_IndirectGoal_
- // *GameEvent_ChippedGoal_
- // *GameEvent_KickTimeout_
- // *GameEvent_AttackerTouchedOpponentInDefenseArea_
- // *GameEvent_AttackerTouchedOpponentInDefenseAreaSkipped
- // *GameEvent_BotCrashUniqueSkipped
- // *GameEvent_BotPushedBotSkipped
- // *GameEvent_DefenderInDefenseAreaPartially_
- // *GameEvent_MultiplePlacementFailures_
- Event isGameEvent_Event `protobuf_oneof:"event"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent) Reset() {
- *x = GameEvent{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent) ProtoMessage() {}
-
-func (x *GameEvent) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[0]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent.ProtoReflect.Descriptor instead.
-func (*GameEvent) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *GameEvent) GetId() string {
- if x != nil && x.Id != nil {
- return *x.Id
- }
- return ""
-}
-
-func (x *GameEvent) GetType() GameEvent_Type {
- if x != nil && x.Type != nil {
- return *x.Type
- }
- return GameEvent_UNKNOWN_GAME_EVENT_TYPE
-}
-
-func (x *GameEvent) GetOrigin() []string {
- if x != nil {
- return x.Origin
- }
- return nil
-}
-
-func (x *GameEvent) GetCreatedTimestamp() uint64 {
- if x != nil && x.CreatedTimestamp != nil {
- return *x.CreatedTimestamp
- }
- return 0
-}
-
-func (x *GameEvent) GetEvent() isGameEvent_Event {
- if x != nil {
- return x.Event
- }
- return nil
-}
-
-func (x *GameEvent) GetBallLeftFieldTouchLine() *GameEvent_BallLeftField {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_BallLeftFieldTouchLine); ok {
- return x.BallLeftFieldTouchLine
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetBallLeftFieldGoalLine() *GameEvent_BallLeftField {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_BallLeftFieldGoalLine); ok {
- return x.BallLeftFieldGoalLine
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetAimlessKick() *GameEvent_AimlessKick {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_AimlessKick_); ok {
- return x.AimlessKick
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetAttackerTooCloseToDefenseArea() *GameEvent_AttackerTooCloseToDefenseArea {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_AttackerTooCloseToDefenseArea_); ok {
- return x.AttackerTooCloseToDefenseArea
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetDefenderInDefenseArea() *GameEvent_DefenderInDefenseArea {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_DefenderInDefenseArea_); ok {
- return x.DefenderInDefenseArea
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetBoundaryCrossing() *GameEvent_BoundaryCrossing {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_BoundaryCrossing_); ok {
- return x.BoundaryCrossing
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetKeeperHeldBall() *GameEvent_KeeperHeldBall {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_KeeperHeldBall_); ok {
- return x.KeeperHeldBall
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetBotDribbledBallTooFar() *GameEvent_BotDribbledBallTooFar {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_BotDribbledBallTooFar_); ok {
- return x.BotDribbledBallTooFar
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetBotPushedBot() *GameEvent_BotPushedBot {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_BotPushedBot_); ok {
- return x.BotPushedBot
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetBotHeldBallDeliberately() *GameEvent_BotHeldBallDeliberately {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_BotHeldBallDeliberately_); ok {
- return x.BotHeldBallDeliberately
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetBotTippedOver() *GameEvent_BotTippedOver {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_BotTippedOver_); ok {
- return x.BotTippedOver
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetBotDroppedParts() *GameEvent_BotDroppedParts {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_BotDroppedParts_); ok {
- return x.BotDroppedParts
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetAttackerTouchedBallInDefenseArea() *GameEvent_AttackerTouchedBallInDefenseArea {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_AttackerTouchedBallInDefenseArea_); ok {
- return x.AttackerTouchedBallInDefenseArea
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetBotKickedBallTooFast() *GameEvent_BotKickedBallTooFast {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_BotKickedBallTooFast_); ok {
- return x.BotKickedBallTooFast
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetBotCrashUnique() *GameEvent_BotCrashUnique {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_BotCrashUnique_); ok {
- return x.BotCrashUnique
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetBotCrashDrawn() *GameEvent_BotCrashDrawn {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_BotCrashDrawn_); ok {
- return x.BotCrashDrawn
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetDefenderTooCloseToKickPoint() *GameEvent_DefenderTooCloseToKickPoint {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_DefenderTooCloseToKickPoint_); ok {
- return x.DefenderTooCloseToKickPoint
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetBotTooFastInStop() *GameEvent_BotTooFastInStop {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_BotTooFastInStop_); ok {
- return x.BotTooFastInStop
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetBotInterferedPlacement() *GameEvent_BotInterferedPlacement {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_BotInterferedPlacement_); ok {
- return x.BotInterferedPlacement
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetPossibleGoal() *GameEvent_Goal {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_PossibleGoal); ok {
- return x.PossibleGoal
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetGoal() *GameEvent_Goal {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_Goal_); ok {
- return x.Goal
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetInvalidGoal() *GameEvent_Goal {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_InvalidGoal); ok {
- return x.InvalidGoal
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetAttackerDoubleTouchedBall() *GameEvent_AttackerDoubleTouchedBall {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_AttackerDoubleTouchedBall_); ok {
- return x.AttackerDoubleTouchedBall
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetPlacementSucceeded() *GameEvent_PlacementSucceeded {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_PlacementSucceeded_); ok {
- return x.PlacementSucceeded
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetPenaltyKickFailed() *GameEvent_PenaltyKickFailed {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_PenaltyKickFailed_); ok {
- return x.PenaltyKickFailed
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetNoProgressInGame() *GameEvent_NoProgressInGame {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_NoProgressInGame_); ok {
- return x.NoProgressInGame
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetPlacementFailed() *GameEvent_PlacementFailed {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_PlacementFailed_); ok {
- return x.PlacementFailed
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetMultipleCards() *GameEvent_MultipleCards {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_MultipleCards_); ok {
- return x.MultipleCards
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetMultipleFouls() *GameEvent_MultipleFouls {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_MultipleFouls_); ok {
- return x.MultipleFouls
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetBotSubstitution() *GameEvent_BotSubstitution {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_BotSubstitution_); ok {
- return x.BotSubstitution
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetExcessiveBotSubstitution() *GameEvent_ExcessiveBotSubstitution {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_ExcessiveBotSubstitution_); ok {
- return x.ExcessiveBotSubstitution
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetTooManyRobots() *GameEvent_TooManyRobots {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_TooManyRobots_); ok {
- return x.TooManyRobots
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetChallengeFlag() *GameEvent_ChallengeFlag {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_ChallengeFlag_); ok {
- return x.ChallengeFlag
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetChallengeFlagHandled() *GameEvent_ChallengeFlagHandled {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_ChallengeFlagHandled_); ok {
- return x.ChallengeFlagHandled
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetEmergencyStop() *GameEvent_EmergencyStop {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_EmergencyStop_); ok {
- return x.EmergencyStop
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetUnsportingBehaviorMinor() *GameEvent_UnsportingBehaviorMinor {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_UnsportingBehaviorMinor_); ok {
- return x.UnsportingBehaviorMinor
- }
- }
- return nil
-}
-
-func (x *GameEvent) GetUnsportingBehaviorMajor() *GameEvent_UnsportingBehaviorMajor {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_UnsportingBehaviorMajor_); ok {
- return x.UnsportingBehaviorMajor
- }
- }
- return nil
-}
-
-// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
-func (x *GameEvent) GetPrepared() *GameEvent_Prepared {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_Prepared_); ok {
- return x.Prepared
- }
- }
- return nil
-}
-
-// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
-func (x *GameEvent) GetIndirectGoal() *GameEvent_IndirectGoal {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_IndirectGoal_); ok {
- return x.IndirectGoal
- }
- }
- return nil
-}
-
-// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
-func (x *GameEvent) GetChippedGoal() *GameEvent_ChippedGoal {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_ChippedGoal_); ok {
- return x.ChippedGoal
- }
- }
- return nil
-}
-
-// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
-func (x *GameEvent) GetKickTimeout() *GameEvent_KickTimeout {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_KickTimeout_); ok {
- return x.KickTimeout
- }
- }
- return nil
-}
-
-// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
-func (x *GameEvent) GetAttackerTouchedOpponentInDefenseArea() *GameEvent_AttackerTouchedOpponentInDefenseArea {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_AttackerTouchedOpponentInDefenseArea_); ok {
- return x.AttackerTouchedOpponentInDefenseArea
- }
- }
- return nil
-}
-
-// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
-func (x *GameEvent) GetAttackerTouchedOpponentInDefenseAreaSkipped() *GameEvent_AttackerTouchedOpponentInDefenseArea {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_AttackerTouchedOpponentInDefenseAreaSkipped); ok {
- return x.AttackerTouchedOpponentInDefenseAreaSkipped
- }
- }
- return nil
-}
-
-// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
-func (x *GameEvent) GetBotCrashUniqueSkipped() *GameEvent_BotCrashUnique {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_BotCrashUniqueSkipped); ok {
- return x.BotCrashUniqueSkipped
- }
- }
- return nil
-}
-
-// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
-func (x *GameEvent) GetBotPushedBotSkipped() *GameEvent_BotPushedBot {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_BotPushedBotSkipped); ok {
- return x.BotPushedBotSkipped
- }
- }
- return nil
-}
-
-// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
-func (x *GameEvent) GetDefenderInDefenseAreaPartially() *GameEvent_DefenderInDefenseAreaPartially {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_DefenderInDefenseAreaPartially_); ok {
- return x.DefenderInDefenseAreaPartially
- }
- }
- return nil
-}
-
-// Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
-func (x *GameEvent) GetMultiplePlacementFailures() *GameEvent_MultiplePlacementFailures {
- if x != nil {
- if x, ok := x.Event.(*GameEvent_MultiplePlacementFailures_); ok {
- return x.MultiplePlacementFailures
- }
- }
- return nil
-}
-
-type isGameEvent_Event interface {
- isGameEvent_Event()
-}
-
-type GameEvent_BallLeftFieldTouchLine struct {
- BallLeftFieldTouchLine *GameEvent_BallLeftField `protobuf:"bytes,6,opt,name=ball_left_field_touch_line,json=ballLeftFieldTouchLine,oneof"`
-}
-
-type GameEvent_BallLeftFieldGoalLine struct {
- BallLeftFieldGoalLine *GameEvent_BallLeftField `protobuf:"bytes,7,opt,name=ball_left_field_goal_line,json=ballLeftFieldGoalLine,oneof"`
-}
-
-type GameEvent_AimlessKick_ struct {
- AimlessKick *GameEvent_AimlessKick `protobuf:"bytes,11,opt,name=aimless_kick,json=aimlessKick,oneof"`
-}
-
-type GameEvent_AttackerTooCloseToDefenseArea_ struct {
- AttackerTooCloseToDefenseArea *GameEvent_AttackerTooCloseToDefenseArea `protobuf:"bytes,19,opt,name=attacker_too_close_to_defense_area,json=attackerTooCloseToDefenseArea,oneof"`
-}
-
-type GameEvent_DefenderInDefenseArea_ struct {
- DefenderInDefenseArea *GameEvent_DefenderInDefenseArea `protobuf:"bytes,31,opt,name=defender_in_defense_area,json=defenderInDefenseArea,oneof"`
-}
-
-type GameEvent_BoundaryCrossing_ struct {
- BoundaryCrossing *GameEvent_BoundaryCrossing `protobuf:"bytes,43,opt,name=boundary_crossing,json=boundaryCrossing,oneof"`
-}
-
-type GameEvent_KeeperHeldBall_ struct {
- KeeperHeldBall *GameEvent_KeeperHeldBall `protobuf:"bytes,13,opt,name=keeper_held_ball,json=keeperHeldBall,oneof"`
-}
-
-type GameEvent_BotDribbledBallTooFar_ struct {
- BotDribbledBallTooFar *GameEvent_BotDribbledBallTooFar `protobuf:"bytes,17,opt,name=bot_dribbled_ball_too_far,json=botDribbledBallTooFar,oneof"`
-}
-
-type GameEvent_BotPushedBot_ struct {
- BotPushedBot *GameEvent_BotPushedBot `protobuf:"bytes,24,opt,name=bot_pushed_bot,json=botPushedBot,oneof"`
-}
-
-type GameEvent_BotHeldBallDeliberately_ struct {
- BotHeldBallDeliberately *GameEvent_BotHeldBallDeliberately `protobuf:"bytes,26,opt,name=bot_held_ball_deliberately,json=botHeldBallDeliberately,oneof"`
-}
-
-type GameEvent_BotTippedOver_ struct {
- BotTippedOver *GameEvent_BotTippedOver `protobuf:"bytes,27,opt,name=bot_tipped_over,json=botTippedOver,oneof"`
-}
-
-type GameEvent_BotDroppedParts_ struct {
- BotDroppedParts *GameEvent_BotDroppedParts `protobuf:"bytes,51,opt,name=bot_dropped_parts,json=botDroppedParts,oneof"`
-}
-
-type GameEvent_AttackerTouchedBallInDefenseArea_ struct {
- AttackerTouchedBallInDefenseArea *GameEvent_AttackerTouchedBallInDefenseArea `protobuf:"bytes,15,opt,name=attacker_touched_ball_in_defense_area,json=attackerTouchedBallInDefenseArea,oneof"`
-}
-
-type GameEvent_BotKickedBallTooFast_ struct {
- BotKickedBallTooFast *GameEvent_BotKickedBallTooFast `protobuf:"bytes,18,opt,name=bot_kicked_ball_too_fast,json=botKickedBallTooFast,oneof"`
-}
-
-type GameEvent_BotCrashUnique_ struct {
- BotCrashUnique *GameEvent_BotCrashUnique `protobuf:"bytes,22,opt,name=bot_crash_unique,json=botCrashUnique,oneof"`
-}
-
-type GameEvent_BotCrashDrawn_ struct {
- BotCrashDrawn *GameEvent_BotCrashDrawn `protobuf:"bytes,21,opt,name=bot_crash_drawn,json=botCrashDrawn,oneof"`
-}
-
-type GameEvent_DefenderTooCloseToKickPoint_ struct {
- DefenderTooCloseToKickPoint *GameEvent_DefenderTooCloseToKickPoint `protobuf:"bytes,29,opt,name=defender_too_close_to_kick_point,json=defenderTooCloseToKickPoint,oneof"`
-}
-
-type GameEvent_BotTooFastInStop_ struct {
- BotTooFastInStop *GameEvent_BotTooFastInStop `protobuf:"bytes,28,opt,name=bot_too_fast_in_stop,json=botTooFastInStop,oneof"`
-}
-
-type GameEvent_BotInterferedPlacement_ struct {
- BotInterferedPlacement *GameEvent_BotInterferedPlacement `protobuf:"bytes,20,opt,name=bot_interfered_placement,json=botInterferedPlacement,oneof"`
-}
-
-type GameEvent_PossibleGoal struct {
- PossibleGoal *GameEvent_Goal `protobuf:"bytes,39,opt,name=possible_goal,json=possibleGoal,oneof"`
-}
-
-type GameEvent_Goal_ struct {
- Goal *GameEvent_Goal `protobuf:"bytes,8,opt,name=goal,oneof"`
-}
-
-type GameEvent_InvalidGoal struct {
- InvalidGoal *GameEvent_Goal `protobuf:"bytes,44,opt,name=invalid_goal,json=invalidGoal,oneof"`
-}
-
-type GameEvent_AttackerDoubleTouchedBall_ struct {
- AttackerDoubleTouchedBall *GameEvent_AttackerDoubleTouchedBall `protobuf:"bytes,14,opt,name=attacker_double_touched_ball,json=attackerDoubleTouchedBall,oneof"`
-}
-
-type GameEvent_PlacementSucceeded_ struct {
- PlacementSucceeded *GameEvent_PlacementSucceeded `protobuf:"bytes,5,opt,name=placement_succeeded,json=placementSucceeded,oneof"`
-}
-
-type GameEvent_PenaltyKickFailed_ struct {
- PenaltyKickFailed *GameEvent_PenaltyKickFailed `protobuf:"bytes,45,opt,name=penalty_kick_failed,json=penaltyKickFailed,oneof"`
-}
-
-type GameEvent_NoProgressInGame_ struct {
- NoProgressInGame *GameEvent_NoProgressInGame `protobuf:"bytes,2,opt,name=no_progress_in_game,json=noProgressInGame,oneof"`
-}
-
-type GameEvent_PlacementFailed_ struct {
- PlacementFailed *GameEvent_PlacementFailed `protobuf:"bytes,3,opt,name=placement_failed,json=placementFailed,oneof"`
-}
-
-type GameEvent_MultipleCards_ struct {
- MultipleCards *GameEvent_MultipleCards `protobuf:"bytes,32,opt,name=multiple_cards,json=multipleCards,oneof"`
-}
-
-type GameEvent_MultipleFouls_ struct {
- MultipleFouls *GameEvent_MultipleFouls `protobuf:"bytes,34,opt,name=multiple_fouls,json=multipleFouls,oneof"`
-}
-
-type GameEvent_BotSubstitution_ struct {
- BotSubstitution *GameEvent_BotSubstitution `protobuf:"bytes,37,opt,name=bot_substitution,json=botSubstitution,oneof"`
-}
-
-type GameEvent_ExcessiveBotSubstitution_ struct {
- ExcessiveBotSubstitution *GameEvent_ExcessiveBotSubstitution `protobuf:"bytes,52,opt,name=excessive_bot_substitution,json=excessiveBotSubstitution,oneof"`
-}
-
-type GameEvent_TooManyRobots_ struct {
- TooManyRobots *GameEvent_TooManyRobots `protobuf:"bytes,38,opt,name=too_many_robots,json=tooManyRobots,oneof"`
-}
-
-type GameEvent_ChallengeFlag_ struct {
- ChallengeFlag *GameEvent_ChallengeFlag `protobuf:"bytes,46,opt,name=challenge_flag,json=challengeFlag,oneof"`
-}
-
-type GameEvent_ChallengeFlagHandled_ struct {
- ChallengeFlagHandled *GameEvent_ChallengeFlagHandled `protobuf:"bytes,48,opt,name=challenge_flag_handled,json=challengeFlagHandled,oneof"`
-}
-
-type GameEvent_EmergencyStop_ struct {
- EmergencyStop *GameEvent_EmergencyStop `protobuf:"bytes,47,opt,name=emergency_stop,json=emergencyStop,oneof"`
-}
-
-type GameEvent_UnsportingBehaviorMinor_ struct {
- UnsportingBehaviorMinor *GameEvent_UnsportingBehaviorMinor `protobuf:"bytes,35,opt,name=unsporting_behavior_minor,json=unsportingBehaviorMinor,oneof"`
-}
-
-type GameEvent_UnsportingBehaviorMajor_ struct {
- UnsportingBehaviorMajor *GameEvent_UnsportingBehaviorMajor `protobuf:"bytes,36,opt,name=unsporting_behavior_major,json=unsportingBehaviorMajor,oneof"`
-}
-
-type GameEvent_Prepared_ struct {
- // replaced by ready_to_continue flag
- //
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- Prepared *GameEvent_Prepared `protobuf:"bytes,1,opt,name=prepared,oneof"`
-}
-
-type GameEvent_IndirectGoal_ struct {
- // obsolete
- //
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- IndirectGoal *GameEvent_IndirectGoal `protobuf:"bytes,9,opt,name=indirect_goal,json=indirectGoal,oneof"`
-}
-
-type GameEvent_ChippedGoal_ struct {
- // replaced by the meta-information in the possible_goal event
- //
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- ChippedGoal *GameEvent_ChippedGoal `protobuf:"bytes,10,opt,name=chipped_goal,json=chippedGoal,oneof"`
-}
-
-type GameEvent_KickTimeout_ struct {
- // obsolete
- //
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- KickTimeout *GameEvent_KickTimeout `protobuf:"bytes,12,opt,name=kick_timeout,json=kickTimeout,oneof"`
-}
-
-type GameEvent_AttackerTouchedOpponentInDefenseArea_ struct {
- // rule removed
- //
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- AttackerTouchedOpponentInDefenseArea *GameEvent_AttackerTouchedOpponentInDefenseArea `protobuf:"bytes,16,opt,name=attacker_touched_opponent_in_defense_area,json=attackerTouchedOpponentInDefenseArea,oneof"`
-}
-
-type GameEvent_AttackerTouchedOpponentInDefenseAreaSkipped struct {
- // obsolete
- //
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- AttackerTouchedOpponentInDefenseAreaSkipped *GameEvent_AttackerTouchedOpponentInDefenseArea `protobuf:"bytes,42,opt,name=attacker_touched_opponent_in_defense_area_skipped,json=attackerTouchedOpponentInDefenseAreaSkipped,oneof"`
-}
-
-type GameEvent_BotCrashUniqueSkipped struct {
- // obsolete
- //
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- BotCrashUniqueSkipped *GameEvent_BotCrashUnique `protobuf:"bytes,23,opt,name=bot_crash_unique_skipped,json=botCrashUniqueSkipped,oneof"`
-}
-
-type GameEvent_BotPushedBotSkipped struct {
- // can not be used as long as autoRefs do not judge pushing
- //
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- BotPushedBotSkipped *GameEvent_BotPushedBot `protobuf:"bytes,25,opt,name=bot_pushed_bot_skipped,json=botPushedBotSkipped,oneof"`
-}
-
-type GameEvent_DefenderInDefenseAreaPartially_ struct {
- // rule removed
- //
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- DefenderInDefenseAreaPartially *GameEvent_DefenderInDefenseAreaPartially `protobuf:"bytes,30,opt,name=defender_in_defense_area_partially,json=defenderInDefenseAreaPartially,oneof"`
-}
-
-type GameEvent_MultiplePlacementFailures_ struct {
- // the referee msg already indicates this
- //
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_game_event.proto.
- MultiplePlacementFailures *GameEvent_MultiplePlacementFailures `protobuf:"bytes,33,opt,name=multiple_placement_failures,json=multiplePlacementFailures,oneof"`
-}
-
-func (*GameEvent_BallLeftFieldTouchLine) isGameEvent_Event() {}
-
-func (*GameEvent_BallLeftFieldGoalLine) isGameEvent_Event() {}
-
-func (*GameEvent_AimlessKick_) isGameEvent_Event() {}
-
-func (*GameEvent_AttackerTooCloseToDefenseArea_) isGameEvent_Event() {}
-
-func (*GameEvent_DefenderInDefenseArea_) isGameEvent_Event() {}
-
-func (*GameEvent_BoundaryCrossing_) isGameEvent_Event() {}
-
-func (*GameEvent_KeeperHeldBall_) isGameEvent_Event() {}
-
-func (*GameEvent_BotDribbledBallTooFar_) isGameEvent_Event() {}
-
-func (*GameEvent_BotPushedBot_) isGameEvent_Event() {}
-
-func (*GameEvent_BotHeldBallDeliberately_) isGameEvent_Event() {}
-
-func (*GameEvent_BotTippedOver_) isGameEvent_Event() {}
-
-func (*GameEvent_BotDroppedParts_) isGameEvent_Event() {}
-
-func (*GameEvent_AttackerTouchedBallInDefenseArea_) isGameEvent_Event() {}
-
-func (*GameEvent_BotKickedBallTooFast_) isGameEvent_Event() {}
-
-func (*GameEvent_BotCrashUnique_) isGameEvent_Event() {}
-
-func (*GameEvent_BotCrashDrawn_) isGameEvent_Event() {}
-
-func (*GameEvent_DefenderTooCloseToKickPoint_) isGameEvent_Event() {}
-
-func (*GameEvent_BotTooFastInStop_) isGameEvent_Event() {}
-
-func (*GameEvent_BotInterferedPlacement_) isGameEvent_Event() {}
-
-func (*GameEvent_PossibleGoal) isGameEvent_Event() {}
-
-func (*GameEvent_Goal_) isGameEvent_Event() {}
-
-func (*GameEvent_InvalidGoal) isGameEvent_Event() {}
-
-func (*GameEvent_AttackerDoubleTouchedBall_) isGameEvent_Event() {}
-
-func (*GameEvent_PlacementSucceeded_) isGameEvent_Event() {}
-
-func (*GameEvent_PenaltyKickFailed_) isGameEvent_Event() {}
-
-func (*GameEvent_NoProgressInGame_) isGameEvent_Event() {}
-
-func (*GameEvent_PlacementFailed_) isGameEvent_Event() {}
-
-func (*GameEvent_MultipleCards_) isGameEvent_Event() {}
-
-func (*GameEvent_MultipleFouls_) isGameEvent_Event() {}
-
-func (*GameEvent_BotSubstitution_) isGameEvent_Event() {}
-
-func (*GameEvent_ExcessiveBotSubstitution_) isGameEvent_Event() {}
-
-func (*GameEvent_TooManyRobots_) isGameEvent_Event() {}
-
-func (*GameEvent_ChallengeFlag_) isGameEvent_Event() {}
-
-func (*GameEvent_ChallengeFlagHandled_) isGameEvent_Event() {}
-
-func (*GameEvent_EmergencyStop_) isGameEvent_Event() {}
-
-func (*GameEvent_UnsportingBehaviorMinor_) isGameEvent_Event() {}
-
-func (*GameEvent_UnsportingBehaviorMajor_) isGameEvent_Event() {}
-
-func (*GameEvent_Prepared_) isGameEvent_Event() {}
-
-func (*GameEvent_IndirectGoal_) isGameEvent_Event() {}
-
-func (*GameEvent_ChippedGoal_) isGameEvent_Event() {}
-
-func (*GameEvent_KickTimeout_) isGameEvent_Event() {}
-
-func (*GameEvent_AttackerTouchedOpponentInDefenseArea_) isGameEvent_Event() {}
-
-func (*GameEvent_AttackerTouchedOpponentInDefenseAreaSkipped) isGameEvent_Event() {}
-
-func (*GameEvent_BotCrashUniqueSkipped) isGameEvent_Event() {}
-
-func (*GameEvent_BotPushedBotSkipped) isGameEvent_Event() {}
-
-func (*GameEvent_DefenderInDefenseAreaPartially_) isGameEvent_Event() {}
-
-func (*GameEvent_MultiplePlacementFailures_) isGameEvent_Event() {}
-
-// the ball left the field normally
-type GameEvent_BallLeftField struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that last touched the ball
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that last touched the ball
- ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
- // the location where the ball left the field [m]
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_BallLeftField) Reset() {
- *x = GameEvent_BallLeftField{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_BallLeftField) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_BallLeftField) ProtoMessage() {}
-
-func (x *GameEvent_BallLeftField) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[1]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_BallLeftField.ProtoReflect.Descriptor instead.
-func (*GameEvent_BallLeftField) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 0}
-}
-
-func (x *GameEvent_BallLeftField) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_BallLeftField) GetByBot() uint32 {
- if x != nil && x.ByBot != nil {
- return *x.ByBot
- }
- return 0
-}
-
-func (x *GameEvent_BallLeftField) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-// the ball left the field via goal line and a team committed an aimless kick
-type GameEvent_AimlessKick struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that last touched the ball
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that last touched the ball
- ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
- // the location where the ball left the field [m]
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- // the location where the ball was last touched [m]
- KickLocation *Vector2 `protobuf:"bytes,4,opt,name=kick_location,json=kickLocation" json:"kick_location,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_AimlessKick) Reset() {
- *x = GameEvent_AimlessKick{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[2]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_AimlessKick) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_AimlessKick) ProtoMessage() {}
-
-func (x *GameEvent_AimlessKick) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[2]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_AimlessKick.ProtoReflect.Descriptor instead.
-func (*GameEvent_AimlessKick) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 1}
-}
-
-func (x *GameEvent_AimlessKick) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_AimlessKick) GetByBot() uint32 {
- if x != nil && x.ByBot != nil {
- return *x.ByBot
- }
- return 0
-}
-
-func (x *GameEvent_AimlessKick) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_AimlessKick) GetKickLocation() *Vector2 {
- if x != nil {
- return x.KickLocation
- }
- return nil
-}
-
-// a team shot a goal
-type GameEvent_Goal struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that scored the goal
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the team that shot the goal (different from by_team for own goals)
- KickingTeam *Team `protobuf:"varint,6,opt,name=kicking_team,json=kickingTeam,enum=Team" json:"kicking_team,omitempty"`
- // the bot that shot the goal
- KickingBot *uint32 `protobuf:"varint,2,opt,name=kicking_bot,json=kickingBot" json:"kicking_bot,omitempty"`
- // the location where the ball entered the goal [m]
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- // the location where the ball was kicked (for deciding if this was a valid goal) [m]
- KickLocation *Vector2 `protobuf:"bytes,4,opt,name=kick_location,json=kickLocation" json:"kick_location,omitempty"`
- // the maximum height the ball reached during the goal kick (for deciding if this was a valid goal) [m]
- MaxBallHeight *float32 `protobuf:"fixed32,5,opt,name=max_ball_height,json=maxBallHeight" json:"max_ball_height,omitempty"`
- // number of robots of scoring team when the ball entered the goal (for deciding if this was a valid goal)
- NumRobotsByTeam *uint32 `protobuf:"varint,7,opt,name=num_robots_by_team,json=numRobotsByTeam" json:"num_robots_by_team,omitempty"`
- // The UNIX timestamp [μs] when the scoring team last touched the ball
- LastTouchByTeam *uint64 `protobuf:"varint,8,opt,name=last_touch_by_team,json=lastTouchByTeam" json:"last_touch_by_team,omitempty"`
- // An additional message with e.g. a reason for invalid goals
- Message *string `protobuf:"bytes,9,opt,name=message" json:"message,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_Goal) Reset() {
- *x = GameEvent_Goal{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[3]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_Goal) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_Goal) ProtoMessage() {}
-
-func (x *GameEvent_Goal) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[3]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_Goal.ProtoReflect.Descriptor instead.
-func (*GameEvent_Goal) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 2}
-}
-
-func (x *GameEvent_Goal) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_Goal) GetKickingTeam() Team {
- if x != nil && x.KickingTeam != nil {
- return *x.KickingTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_Goal) GetKickingBot() uint32 {
- if x != nil && x.KickingBot != nil {
- return *x.KickingBot
- }
- return 0
-}
-
-func (x *GameEvent_Goal) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_Goal) GetKickLocation() *Vector2 {
- if x != nil {
- return x.KickLocation
- }
- return nil
-}
-
-func (x *GameEvent_Goal) GetMaxBallHeight() float32 {
- if x != nil && x.MaxBallHeight != nil {
- return *x.MaxBallHeight
- }
- return 0
-}
-
-func (x *GameEvent_Goal) GetNumRobotsByTeam() uint32 {
- if x != nil && x.NumRobotsByTeam != nil {
- return *x.NumRobotsByTeam
- }
- return 0
-}
-
-func (x *GameEvent_Goal) GetLastTouchByTeam() uint64 {
- if x != nil && x.LastTouchByTeam != nil {
- return *x.LastTouchByTeam
- }
- return 0
-}
-
-func (x *GameEvent_Goal) GetMessage() string {
- if x != nil && x.Message != nil {
- return *x.Message
- }
- return ""
-}
-
-// the ball entered the goal directly during an indirect free kick
-type GameEvent_IndirectGoal struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that tried to shoot the goal
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that kicked the ball - at least the team must be set
- ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
- // the location where the ball entered the goal [m]
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- // the location where the ball was kicked [m]
- KickLocation *Vector2 `protobuf:"bytes,4,opt,name=kick_location,json=kickLocation" json:"kick_location,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_IndirectGoal) Reset() {
- *x = GameEvent_IndirectGoal{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[4]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_IndirectGoal) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_IndirectGoal) ProtoMessage() {}
-
-func (x *GameEvent_IndirectGoal) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[4]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_IndirectGoal.ProtoReflect.Descriptor instead.
-func (*GameEvent_IndirectGoal) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 3}
-}
-
-func (x *GameEvent_IndirectGoal) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_IndirectGoal) GetByBot() uint32 {
- if x != nil && x.ByBot != nil {
- return *x.ByBot
- }
- return 0
-}
-
-func (x *GameEvent_IndirectGoal) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_IndirectGoal) GetKickLocation() *Vector2 {
- if x != nil {
- return x.KickLocation
- }
- return nil
-}
-
-// the ball entered the goal, but was initially chipped
-type GameEvent_ChippedGoal struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that tried to shoot the goal
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that kicked the ball
- ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
- // the location where the ball entered the goal [m]
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- // the location where the ball was kicked [m]
- KickLocation *Vector2 `protobuf:"bytes,4,opt,name=kick_location,json=kickLocation" json:"kick_location,omitempty"`
- // the maximum height [m] of the ball, before it entered the goal and since the last kick [m]
- MaxBallHeight *float32 `protobuf:"fixed32,5,opt,name=max_ball_height,json=maxBallHeight" json:"max_ball_height,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_ChippedGoal) Reset() {
- *x = GameEvent_ChippedGoal{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[5]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_ChippedGoal) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_ChippedGoal) ProtoMessage() {}
-
-func (x *GameEvent_ChippedGoal) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[5]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_ChippedGoal.ProtoReflect.Descriptor instead.
-func (*GameEvent_ChippedGoal) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 4}
-}
-
-func (x *GameEvent_ChippedGoal) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_ChippedGoal) GetByBot() uint32 {
- if x != nil && x.ByBot != nil {
- return *x.ByBot
- }
- return 0
-}
-
-func (x *GameEvent_ChippedGoal) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_ChippedGoal) GetKickLocation() *Vector2 {
- if x != nil {
- return x.KickLocation
- }
- return nil
-}
-
-func (x *GameEvent_ChippedGoal) GetMaxBallHeight() float32 {
- if x != nil && x.MaxBallHeight != nil {
- return *x.MaxBallHeight
- }
- return 0
-}
-
-// a bot moved too fast while the game was stopped
-type GameEvent_BotTooFastInStop struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that found guilty
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that was too fast
- ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
- // the location of the bot [m]
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- // the bot speed [m/s]
- Speed *float32 `protobuf:"fixed32,4,opt,name=speed" json:"speed,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_BotTooFastInStop) Reset() {
- *x = GameEvent_BotTooFastInStop{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[6]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_BotTooFastInStop) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_BotTooFastInStop) ProtoMessage() {}
-
-func (x *GameEvent_BotTooFastInStop) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[6]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_BotTooFastInStop.ProtoReflect.Descriptor instead.
-func (*GameEvent_BotTooFastInStop) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 5}
-}
-
-func (x *GameEvent_BotTooFastInStop) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_BotTooFastInStop) GetByBot() uint32 {
- if x != nil && x.ByBot != nil {
- return *x.ByBot
- }
- return 0
-}
-
-func (x *GameEvent_BotTooFastInStop) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_BotTooFastInStop) GetSpeed() float32 {
- if x != nil && x.Speed != nil {
- return *x.Speed
- }
- return 0
-}
-
-// a bot of the defending team got too close to the kick point during a free kick
-type GameEvent_DefenderTooCloseToKickPoint struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that was found guilty
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that violates the distance to the kick point
- ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
- // the location of the bot [m]
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- // the distance [m] from bot to the kick point (including the minimum radius)
- Distance *float32 `protobuf:"fixed32,4,opt,name=distance" json:"distance,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_DefenderTooCloseToKickPoint) Reset() {
- *x = GameEvent_DefenderTooCloseToKickPoint{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[7]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_DefenderTooCloseToKickPoint) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_DefenderTooCloseToKickPoint) ProtoMessage() {}
-
-func (x *GameEvent_DefenderTooCloseToKickPoint) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[7]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_DefenderTooCloseToKickPoint.ProtoReflect.Descriptor instead.
-func (*GameEvent_DefenderTooCloseToKickPoint) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 6}
-}
-
-func (x *GameEvent_DefenderTooCloseToKickPoint) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_DefenderTooCloseToKickPoint) GetByBot() uint32 {
- if x != nil && x.ByBot != nil {
- return *x.ByBot
- }
- return 0
-}
-
-func (x *GameEvent_DefenderTooCloseToKickPoint) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_DefenderTooCloseToKickPoint) GetDistance() float32 {
- if x != nil && x.Distance != nil {
- return *x.Distance
- }
- return 0
-}
-
-// two robots crashed into each other with similar speeds
-type GameEvent_BotCrashDrawn struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the bot of the yellow team
- BotYellow *uint32 `protobuf:"varint,1,opt,name=bot_yellow,json=botYellow" json:"bot_yellow,omitempty"`
- // the bot of the blue team
- BotBlue *uint32 `protobuf:"varint,2,opt,name=bot_blue,json=botBlue" json:"bot_blue,omitempty"`
- // the location of the crash (center between both bots) [m]
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- // the calculated crash speed [m/s] of the two bots
- CrashSpeed *float32 `protobuf:"fixed32,4,opt,name=crash_speed,json=crashSpeed" json:"crash_speed,omitempty"`
- // the difference [m/s] of the velocity of the two bots
- SpeedDiff *float32 `protobuf:"fixed32,5,opt,name=speed_diff,json=speedDiff" json:"speed_diff,omitempty"`
- // the angle [rad] in the range [0, π] of the bot velocity vectors
- // an angle of 0 rad ( 0°) means, the bots barely touched each other
- // an angle of π rad (180°) means, the bots crashed frontal into each other
- CrashAngle *float32 `protobuf:"fixed32,6,opt,name=crash_angle,json=crashAngle" json:"crash_angle,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_BotCrashDrawn) Reset() {
- *x = GameEvent_BotCrashDrawn{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[8]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_BotCrashDrawn) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_BotCrashDrawn) ProtoMessage() {}
-
-func (x *GameEvent_BotCrashDrawn) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[8]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_BotCrashDrawn.ProtoReflect.Descriptor instead.
-func (*GameEvent_BotCrashDrawn) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 7}
-}
-
-func (x *GameEvent_BotCrashDrawn) GetBotYellow() uint32 {
- if x != nil && x.BotYellow != nil {
- return *x.BotYellow
- }
- return 0
-}
-
-func (x *GameEvent_BotCrashDrawn) GetBotBlue() uint32 {
- if x != nil && x.BotBlue != nil {
- return *x.BotBlue
- }
- return 0
-}
-
-func (x *GameEvent_BotCrashDrawn) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_BotCrashDrawn) GetCrashSpeed() float32 {
- if x != nil && x.CrashSpeed != nil {
- return *x.CrashSpeed
- }
- return 0
-}
-
-func (x *GameEvent_BotCrashDrawn) GetSpeedDiff() float32 {
- if x != nil && x.SpeedDiff != nil {
- return *x.SpeedDiff
- }
- return 0
-}
-
-func (x *GameEvent_BotCrashDrawn) GetCrashAngle() float32 {
- if x != nil && x.CrashAngle != nil {
- return *x.CrashAngle
- }
- return 0
-}
-
-// two robots crashed into each other and one team was found guilty to due significant speed difference
-type GameEvent_BotCrashUnique struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that caused the crash
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that caused the crash
- Violator *uint32 `protobuf:"varint,2,opt,name=violator" json:"violator,omitempty"`
- // the bot of the opposite team that was involved in the crash
- Victim *uint32 `protobuf:"varint,3,opt,name=victim" json:"victim,omitempty"`
- // the location of the crash (center between both bots) [m]
- Location *Vector2 `protobuf:"bytes,4,opt,name=location" json:"location,omitempty"`
- // the calculated crash speed vector [m/s] of the two bots
- CrashSpeed *float32 `protobuf:"fixed32,5,opt,name=crash_speed,json=crashSpeed" json:"crash_speed,omitempty"`
- // the difference [m/s] of the velocity of the two bots
- SpeedDiff *float32 `protobuf:"fixed32,6,opt,name=speed_diff,json=speedDiff" json:"speed_diff,omitempty"`
- // the angle [rad] in the range [0, π] of the bot velocity vectors
- // an angle of 0 rad ( 0°) means, the bots barely touched each other
- // an angle of π rad (180°) means, the bots crashed frontal into each other
- CrashAngle *float32 `protobuf:"fixed32,7,opt,name=crash_angle,json=crashAngle" json:"crash_angle,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_BotCrashUnique) Reset() {
- *x = GameEvent_BotCrashUnique{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[9]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_BotCrashUnique) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_BotCrashUnique) ProtoMessage() {}
-
-func (x *GameEvent_BotCrashUnique) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[9]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_BotCrashUnique.ProtoReflect.Descriptor instead.
-func (*GameEvent_BotCrashUnique) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 8}
-}
-
-func (x *GameEvent_BotCrashUnique) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_BotCrashUnique) GetViolator() uint32 {
- if x != nil && x.Violator != nil {
- return *x.Violator
- }
- return 0
-}
-
-func (x *GameEvent_BotCrashUnique) GetVictim() uint32 {
- if x != nil && x.Victim != nil {
- return *x.Victim
- }
- return 0
-}
-
-func (x *GameEvent_BotCrashUnique) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_BotCrashUnique) GetCrashSpeed() float32 {
- if x != nil && x.CrashSpeed != nil {
- return *x.CrashSpeed
- }
- return 0
-}
-
-func (x *GameEvent_BotCrashUnique) GetSpeedDiff() float32 {
- if x != nil && x.SpeedDiff != nil {
- return *x.SpeedDiff
- }
- return 0
-}
-
-func (x *GameEvent_BotCrashUnique) GetCrashAngle() float32 {
- if x != nil && x.CrashAngle != nil {
- return *x.CrashAngle
- }
- return 0
-}
-
-// a bot pushed another bot over a significant distance
-type GameEvent_BotPushedBot struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that pushed the other team
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that pushed the other bot
- Violator *uint32 `protobuf:"varint,2,opt,name=violator" json:"violator,omitempty"`
- // the bot of the opposite team that was pushed
- Victim *uint32 `protobuf:"varint,3,opt,name=victim" json:"victim,omitempty"`
- // the location of the push (center between both bots) [m]
- Location *Vector2 `protobuf:"bytes,4,opt,name=location" json:"location,omitempty"`
- // the pushed distance [m]
- PushedDistance *float32 `protobuf:"fixed32,5,opt,name=pushed_distance,json=pushedDistance" json:"pushed_distance,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_BotPushedBot) Reset() {
- *x = GameEvent_BotPushedBot{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[10]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_BotPushedBot) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_BotPushedBot) ProtoMessage() {}
-
-func (x *GameEvent_BotPushedBot) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[10]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_BotPushedBot.ProtoReflect.Descriptor instead.
-func (*GameEvent_BotPushedBot) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 9}
-}
-
-func (x *GameEvent_BotPushedBot) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_BotPushedBot) GetViolator() uint32 {
- if x != nil && x.Violator != nil {
- return *x.Violator
- }
- return 0
-}
-
-func (x *GameEvent_BotPushedBot) GetVictim() uint32 {
- if x != nil && x.Victim != nil {
- return *x.Victim
- }
- return 0
-}
-
-func (x *GameEvent_BotPushedBot) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_BotPushedBot) GetPushedDistance() float32 {
- if x != nil && x.PushedDistance != nil {
- return *x.PushedDistance
- }
- return 0
-}
-
-// a bot tipped over
-type GameEvent_BotTippedOver struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that found guilty
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that tipped over
- ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
- // the location of the bot [m]
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- // the location of the ball at the moment when this foul occurred [m]
- BallLocation *Vector2 `protobuf:"bytes,4,opt,name=ball_location,json=ballLocation" json:"ball_location,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_BotTippedOver) Reset() {
- *x = GameEvent_BotTippedOver{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[11]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_BotTippedOver) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_BotTippedOver) ProtoMessage() {}
-
-func (x *GameEvent_BotTippedOver) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[11]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_BotTippedOver.ProtoReflect.Descriptor instead.
-func (*GameEvent_BotTippedOver) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 10}
-}
-
-func (x *GameEvent_BotTippedOver) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_BotTippedOver) GetByBot() uint32 {
- if x != nil && x.ByBot != nil {
- return *x.ByBot
- }
- return 0
-}
-
-func (x *GameEvent_BotTippedOver) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_BotTippedOver) GetBallLocation() *Vector2 {
- if x != nil {
- return x.BallLocation
- }
- return nil
-}
-
-// a bot dropped parts
-type GameEvent_BotDroppedParts struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that found guilty
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that dropped the parts
- ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
- // the location where the parts were dropped [m]
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- // the location of the ball at the moment when this foul occurred [m]
- BallLocation *Vector2 `protobuf:"bytes,4,opt,name=ball_location,json=ballLocation" json:"ball_location,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_BotDroppedParts) Reset() {
- *x = GameEvent_BotDroppedParts{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[12]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_BotDroppedParts) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_BotDroppedParts) ProtoMessage() {}
-
-func (x *GameEvent_BotDroppedParts) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[12]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_BotDroppedParts.ProtoReflect.Descriptor instead.
-func (*GameEvent_BotDroppedParts) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 11}
-}
-
-func (x *GameEvent_BotDroppedParts) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_BotDroppedParts) GetByBot() uint32 {
- if x != nil && x.ByBot != nil {
- return *x.ByBot
- }
- return 0
-}
-
-func (x *GameEvent_BotDroppedParts) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_BotDroppedParts) GetBallLocation() *Vector2 {
- if x != nil {
- return x.BallLocation
- }
- return nil
-}
-
-// a defender other than the keeper was fully located inside its own defense and touched the ball
-type GameEvent_DefenderInDefenseArea struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that found guilty
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that is inside the penalty area
- ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
- // the location of the bot [m]
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- // the distance [m] from bot case to the nearest point outside the defense area
- Distance *float32 `protobuf:"fixed32,4,opt,name=distance" json:"distance,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_DefenderInDefenseArea) Reset() {
- *x = GameEvent_DefenderInDefenseArea{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[13]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_DefenderInDefenseArea) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_DefenderInDefenseArea) ProtoMessage() {}
-
-func (x *GameEvent_DefenderInDefenseArea) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[13]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_DefenderInDefenseArea.ProtoReflect.Descriptor instead.
-func (*GameEvent_DefenderInDefenseArea) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 12}
-}
-
-func (x *GameEvent_DefenderInDefenseArea) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_DefenderInDefenseArea) GetByBot() uint32 {
- if x != nil && x.ByBot != nil {
- return *x.ByBot
- }
- return 0
-}
-
-func (x *GameEvent_DefenderInDefenseArea) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_DefenderInDefenseArea) GetDistance() float32 {
- if x != nil && x.Distance != nil {
- return *x.Distance
- }
- return 0
-}
-
-// a defender other than the keeper was partially located inside its own defense area and touched the ball
-type GameEvent_DefenderInDefenseAreaPartially struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that found guilty
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that is partially inside the penalty area
- ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
- // the location of the bot
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- // the distance [m] that the bot is inside the penalty area
- Distance *float32 `protobuf:"fixed32,4,opt,name=distance" json:"distance,omitempty"`
- // the location of the ball at the moment when this foul occurred [m]
- BallLocation *Vector2 `protobuf:"bytes,5,opt,name=ball_location,json=ballLocation" json:"ball_location,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_DefenderInDefenseAreaPartially) Reset() {
- *x = GameEvent_DefenderInDefenseAreaPartially{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[14]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_DefenderInDefenseAreaPartially) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_DefenderInDefenseAreaPartially) ProtoMessage() {}
-
-func (x *GameEvent_DefenderInDefenseAreaPartially) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[14]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_DefenderInDefenseAreaPartially.ProtoReflect.Descriptor instead.
-func (*GameEvent_DefenderInDefenseAreaPartially) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 13}
-}
-
-func (x *GameEvent_DefenderInDefenseAreaPartially) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_DefenderInDefenseAreaPartially) GetByBot() uint32 {
- if x != nil && x.ByBot != nil {
- return *x.ByBot
- }
- return 0
-}
-
-func (x *GameEvent_DefenderInDefenseAreaPartially) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_DefenderInDefenseAreaPartially) GetDistance() float32 {
- if x != nil && x.Distance != nil {
- return *x.Distance
- }
- return 0
-}
-
-func (x *GameEvent_DefenderInDefenseAreaPartially) GetBallLocation() *Vector2 {
- if x != nil {
- return x.BallLocation
- }
- return nil
-}
-
-// an attacker touched the ball inside the opponent defense area
-type GameEvent_AttackerTouchedBallInDefenseArea struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that found guilty
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that is inside the penalty area
- ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
- // the location of the bot [m]
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- // the distance [m] that the bot is inside the penalty area
- Distance *float32 `protobuf:"fixed32,4,opt,name=distance" json:"distance,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_AttackerTouchedBallInDefenseArea) Reset() {
- *x = GameEvent_AttackerTouchedBallInDefenseArea{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[15]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_AttackerTouchedBallInDefenseArea) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_AttackerTouchedBallInDefenseArea) ProtoMessage() {}
-
-func (x *GameEvent_AttackerTouchedBallInDefenseArea) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[15]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_AttackerTouchedBallInDefenseArea.ProtoReflect.Descriptor instead.
-func (*GameEvent_AttackerTouchedBallInDefenseArea) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 14}
-}
-
-func (x *GameEvent_AttackerTouchedBallInDefenseArea) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_AttackerTouchedBallInDefenseArea) GetByBot() uint32 {
- if x != nil && x.ByBot != nil {
- return *x.ByBot
- }
- return 0
-}
-
-func (x *GameEvent_AttackerTouchedBallInDefenseArea) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_AttackerTouchedBallInDefenseArea) GetDistance() float32 {
- if x != nil && x.Distance != nil {
- return *x.Distance
- }
- return 0
-}
-
-// a bot kicked the ball too fast
-type GameEvent_BotKickedBallTooFast struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that found guilty
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that kicked too fast
- ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
- // the location of the ball at the time of the highest speed [m]
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- // the absolute initial ball speed (kick speed) [m/s]
- InitialBallSpeed *float32 `protobuf:"fixed32,4,opt,name=initial_ball_speed,json=initialBallSpeed" json:"initial_ball_speed,omitempty"`
- // was the ball chipped?
- Chipped *bool `protobuf:"varint,5,opt,name=chipped" json:"chipped,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_BotKickedBallTooFast) Reset() {
- *x = GameEvent_BotKickedBallTooFast{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[16]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_BotKickedBallTooFast) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_BotKickedBallTooFast) ProtoMessage() {}
-
-func (x *GameEvent_BotKickedBallTooFast) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[16]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_BotKickedBallTooFast.ProtoReflect.Descriptor instead.
-func (*GameEvent_BotKickedBallTooFast) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 15}
-}
-
-func (x *GameEvent_BotKickedBallTooFast) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_BotKickedBallTooFast) GetByBot() uint32 {
- if x != nil && x.ByBot != nil {
- return *x.ByBot
- }
- return 0
-}
-
-func (x *GameEvent_BotKickedBallTooFast) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_BotKickedBallTooFast) GetInitialBallSpeed() float32 {
- if x != nil && x.InitialBallSpeed != nil {
- return *x.InitialBallSpeed
- }
- return 0
-}
-
-func (x *GameEvent_BotKickedBallTooFast) GetChipped() bool {
- if x != nil && x.Chipped != nil {
- return *x.Chipped
- }
- return false
-}
-
-// a bot dribbled to ball too far
-type GameEvent_BotDribbledBallTooFar struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that found guilty
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that dribbled too far
- ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
- // the location where the dribbling started [m]
- Start *Vector2 `protobuf:"bytes,3,opt,name=start" json:"start,omitempty"`
- // the location where the maximum dribbling distance was reached [m]
- End *Vector2 `protobuf:"bytes,4,opt,name=end" json:"end,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_BotDribbledBallTooFar) Reset() {
- *x = GameEvent_BotDribbledBallTooFar{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[17]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_BotDribbledBallTooFar) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_BotDribbledBallTooFar) ProtoMessage() {}
-
-func (x *GameEvent_BotDribbledBallTooFar) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[17]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_BotDribbledBallTooFar.ProtoReflect.Descriptor instead.
-func (*GameEvent_BotDribbledBallTooFar) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 16}
-}
-
-func (x *GameEvent_BotDribbledBallTooFar) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_BotDribbledBallTooFar) GetByBot() uint32 {
- if x != nil && x.ByBot != nil {
- return *x.ByBot
- }
- return 0
-}
-
-func (x *GameEvent_BotDribbledBallTooFar) GetStart() *Vector2 {
- if x != nil {
- return x.Start
- }
- return nil
-}
-
-func (x *GameEvent_BotDribbledBallTooFar) GetEnd() *Vector2 {
- if x != nil {
- return x.End
- }
- return nil
-}
-
-// an attacker touched the opponent robot inside defense area
-type GameEvent_AttackerTouchedOpponentInDefenseArea struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that found guilty
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that touched the opponent robot
- ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
- // the bot of the opposite team that was touched
- Victim *uint32 `protobuf:"varint,4,opt,name=victim" json:"victim,omitempty"`
- // the location of the contact point between both bots [m]
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_AttackerTouchedOpponentInDefenseArea) Reset() {
- *x = GameEvent_AttackerTouchedOpponentInDefenseArea{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[18]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_AttackerTouchedOpponentInDefenseArea) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_AttackerTouchedOpponentInDefenseArea) ProtoMessage() {}
-
-func (x *GameEvent_AttackerTouchedOpponentInDefenseArea) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[18]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_AttackerTouchedOpponentInDefenseArea.ProtoReflect.Descriptor instead.
-func (*GameEvent_AttackerTouchedOpponentInDefenseArea) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 17}
-}
-
-func (x *GameEvent_AttackerTouchedOpponentInDefenseArea) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_AttackerTouchedOpponentInDefenseArea) GetByBot() uint32 {
- if x != nil && x.ByBot != nil {
- return *x.ByBot
- }
- return 0
-}
-
-func (x *GameEvent_AttackerTouchedOpponentInDefenseArea) GetVictim() uint32 {
- if x != nil && x.Victim != nil {
- return *x.Victim
- }
- return 0
-}
-
-func (x *GameEvent_AttackerTouchedOpponentInDefenseArea) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-// an attacker touched the ball multiple times when it was not allowed to
-type GameEvent_AttackerDoubleTouchedBall struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that found guilty
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that touched the ball twice
- ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
- // the location of the ball when it was first touched [m]
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_AttackerDoubleTouchedBall) Reset() {
- *x = GameEvent_AttackerDoubleTouchedBall{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[19]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_AttackerDoubleTouchedBall) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_AttackerDoubleTouchedBall) ProtoMessage() {}
-
-func (x *GameEvent_AttackerDoubleTouchedBall) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[19]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_AttackerDoubleTouchedBall.ProtoReflect.Descriptor instead.
-func (*GameEvent_AttackerDoubleTouchedBall) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 18}
-}
-
-func (x *GameEvent_AttackerDoubleTouchedBall) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_AttackerDoubleTouchedBall) GetByBot() uint32 {
- if x != nil && x.ByBot != nil {
- return *x.ByBot
- }
- return 0
-}
-
-func (x *GameEvent_AttackerDoubleTouchedBall) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-// an attacker was located too near to the opponent defense area during stop or free kick
-type GameEvent_AttackerTooCloseToDefenseArea struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that found guilty
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that is too close to the defense area
- ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
- // the location of the bot [m]
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- // the distance [m] of the bot to the penalty area
- Distance *float32 `protobuf:"fixed32,4,opt,name=distance" json:"distance,omitempty"`
- // the location of the ball at the moment when this foul occurred [m]
- BallLocation *Vector2 `protobuf:"bytes,5,opt,name=ball_location,json=ballLocation" json:"ball_location,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_AttackerTooCloseToDefenseArea) Reset() {
- *x = GameEvent_AttackerTooCloseToDefenseArea{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[20]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_AttackerTooCloseToDefenseArea) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_AttackerTooCloseToDefenseArea) ProtoMessage() {}
-
-func (x *GameEvent_AttackerTooCloseToDefenseArea) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[20]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_AttackerTooCloseToDefenseArea.ProtoReflect.Descriptor instead.
-func (*GameEvent_AttackerTooCloseToDefenseArea) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 19}
-}
-
-func (x *GameEvent_AttackerTooCloseToDefenseArea) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_AttackerTooCloseToDefenseArea) GetByBot() uint32 {
- if x != nil && x.ByBot != nil {
- return *x.ByBot
- }
- return 0
-}
-
-func (x *GameEvent_AttackerTooCloseToDefenseArea) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_AttackerTooCloseToDefenseArea) GetDistance() float32 {
- if x != nil && x.Distance != nil {
- return *x.Distance
- }
- return 0
-}
-
-func (x *GameEvent_AttackerTooCloseToDefenseArea) GetBallLocation() *Vector2 {
- if x != nil {
- return x.BallLocation
- }
- return nil
-}
-
-// a bot held the ball for too long
-type GameEvent_BotHeldBallDeliberately struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that found guilty
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that holds the ball
- ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
- // the location of the ball [m]
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- // the duration [s] that the bot hold the ball
- Duration *float32 `protobuf:"fixed32,4,opt,name=duration" json:"duration,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_BotHeldBallDeliberately) Reset() {
- *x = GameEvent_BotHeldBallDeliberately{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[21]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_BotHeldBallDeliberately) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_BotHeldBallDeliberately) ProtoMessage() {}
-
-func (x *GameEvent_BotHeldBallDeliberately) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[21]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_BotHeldBallDeliberately.ProtoReflect.Descriptor instead.
-func (*GameEvent_BotHeldBallDeliberately) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 20}
-}
-
-func (x *GameEvent_BotHeldBallDeliberately) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_BotHeldBallDeliberately) GetByBot() uint32 {
- if x != nil && x.ByBot != nil {
- return *x.ByBot
- }
- return 0
-}
-
-func (x *GameEvent_BotHeldBallDeliberately) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_BotHeldBallDeliberately) GetDuration() float32 {
- if x != nil && x.Duration != nil {
- return *x.Duration
- }
- return 0
-}
-
-// a bot interfered the ball placement of the other team
-type GameEvent_BotInterferedPlacement struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that found guilty
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the bot that interfered the placement
- ByBot *uint32 `protobuf:"varint,2,opt,name=by_bot,json=byBot" json:"by_bot,omitempty"`
- // the location of the bot [m]
- Location *Vector2 `protobuf:"bytes,3,opt,name=location" json:"location,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_BotInterferedPlacement) Reset() {
- *x = GameEvent_BotInterferedPlacement{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[22]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_BotInterferedPlacement) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_BotInterferedPlacement) ProtoMessage() {}
-
-func (x *GameEvent_BotInterferedPlacement) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[22]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_BotInterferedPlacement.ProtoReflect.Descriptor instead.
-func (*GameEvent_BotInterferedPlacement) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 21}
-}
-
-func (x *GameEvent_BotInterferedPlacement) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_BotInterferedPlacement) GetByBot() uint32 {
- if x != nil && x.ByBot != nil {
- return *x.ByBot
- }
- return 0
-}
-
-func (x *GameEvent_BotInterferedPlacement) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-// a team collected multiple yellow cards
-type GameEvent_MultipleCards struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that received multiple yellow cards
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_MultipleCards) Reset() {
- *x = GameEvent_MultipleCards{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[23]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_MultipleCards) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_MultipleCards) ProtoMessage() {}
-
-func (x *GameEvent_MultipleCards) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[23]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_MultipleCards.ProtoReflect.Descriptor instead.
-func (*GameEvent_MultipleCards) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 22}
-}
-
-func (x *GameEvent_MultipleCards) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-// a team collected multiple fouls, which results in a yellow card
-type GameEvent_MultipleFouls struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that collected multiple fouls
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the list of game events that caused the multiple fouls
- CausedGameEvents []*GameEvent `protobuf:"bytes,2,rep,name=caused_game_events,json=causedGameEvents" json:"caused_game_events,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_MultipleFouls) Reset() {
- *x = GameEvent_MultipleFouls{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[24]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_MultipleFouls) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_MultipleFouls) ProtoMessage() {}
-
-func (x *GameEvent_MultipleFouls) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[24]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_MultipleFouls.ProtoReflect.Descriptor instead.
-func (*GameEvent_MultipleFouls) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 23}
-}
-
-func (x *GameEvent_MultipleFouls) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_MultipleFouls) GetCausedGameEvents() []*GameEvent {
- if x != nil {
- return x.CausedGameEvents
- }
- return nil
-}
-
-// a team failed to place the ball multiple times in a row
-type GameEvent_MultiplePlacementFailures struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that failed multiple times
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_MultiplePlacementFailures) Reset() {
- *x = GameEvent_MultiplePlacementFailures{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[25]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_MultiplePlacementFailures) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_MultiplePlacementFailures) ProtoMessage() {}
-
-func (x *GameEvent_MultiplePlacementFailures) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[25]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_MultiplePlacementFailures.ProtoReflect.Descriptor instead.
-func (*GameEvent_MultiplePlacementFailures) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 24}
-}
-
-func (x *GameEvent_MultiplePlacementFailures) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-// timeout waiting for the attacking team to perform the free kick
-type GameEvent_KickTimeout struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that that should have kicked
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the location of the ball [m]
- Location *Vector2 `protobuf:"bytes,2,opt,name=location" json:"location,omitempty"`
- // the time [s] that was waited
- Time *float32 `protobuf:"fixed32,3,opt,name=time" json:"time,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_KickTimeout) Reset() {
- *x = GameEvent_KickTimeout{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[26]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_KickTimeout) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_KickTimeout) ProtoMessage() {}
-
-func (x *GameEvent_KickTimeout) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[26]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_KickTimeout.ProtoReflect.Descriptor instead.
-func (*GameEvent_KickTimeout) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 25}
-}
-
-func (x *GameEvent_KickTimeout) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_KickTimeout) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_KickTimeout) GetTime() float32 {
- if x != nil && x.Time != nil {
- return *x.Time
- }
- return 0
-}
-
-// game was stuck
-type GameEvent_NoProgressInGame struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the location of the ball
- Location *Vector2 `protobuf:"bytes,1,opt,name=location" json:"location,omitempty"`
- // the time [s] that was waited
- Time *float32 `protobuf:"fixed32,2,opt,name=time" json:"time,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_NoProgressInGame) Reset() {
- *x = GameEvent_NoProgressInGame{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[27]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_NoProgressInGame) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_NoProgressInGame) ProtoMessage() {}
-
-func (x *GameEvent_NoProgressInGame) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[27]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_NoProgressInGame.ProtoReflect.Descriptor instead.
-func (*GameEvent_NoProgressInGame) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 26}
-}
-
-func (x *GameEvent_NoProgressInGame) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_NoProgressInGame) GetTime() float32 {
- if x != nil && x.Time != nil {
- return *x.Time
- }
- return 0
-}
-
-// ball placement failed
-type GameEvent_PlacementFailed struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that failed
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the remaining distance [m] from ball to placement position
- RemainingDistance *float32 `protobuf:"fixed32,2,opt,name=remaining_distance,json=remainingDistance" json:"remaining_distance,omitempty"`
- // the distance [m] of the nearest own robot to the ball
- NearestOwnBotDistance *float32 `protobuf:"fixed32,3,opt,name=nearest_own_bot_distance,json=nearestOwnBotDistance" json:"nearest_own_bot_distance,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_PlacementFailed) Reset() {
- *x = GameEvent_PlacementFailed{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[28]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_PlacementFailed) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_PlacementFailed) ProtoMessage() {}
-
-func (x *GameEvent_PlacementFailed) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[28]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_PlacementFailed.ProtoReflect.Descriptor instead.
-func (*GameEvent_PlacementFailed) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 27}
-}
-
-func (x *GameEvent_PlacementFailed) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_PlacementFailed) GetRemainingDistance() float32 {
- if x != nil && x.RemainingDistance != nil {
- return *x.RemainingDistance
- }
- return 0
-}
-
-func (x *GameEvent_PlacementFailed) GetNearestOwnBotDistance() float32 {
- if x != nil && x.NearestOwnBotDistance != nil {
- return *x.NearestOwnBotDistance
- }
- return 0
-}
-
-// a team was found guilty for minor unsporting behavior
-type GameEvent_UnsportingBehaviorMinor struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that found guilty
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // an explanation of the situation and decision
- Reason *string `protobuf:"bytes,2,req,name=reason" json:"reason,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_UnsportingBehaviorMinor) Reset() {
- *x = GameEvent_UnsportingBehaviorMinor{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[29]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_UnsportingBehaviorMinor) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_UnsportingBehaviorMinor) ProtoMessage() {}
-
-func (x *GameEvent_UnsportingBehaviorMinor) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[29]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_UnsportingBehaviorMinor.ProtoReflect.Descriptor instead.
-func (*GameEvent_UnsportingBehaviorMinor) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 28}
-}
-
-func (x *GameEvent_UnsportingBehaviorMinor) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_UnsportingBehaviorMinor) GetReason() string {
- if x != nil && x.Reason != nil {
- return *x.Reason
- }
- return ""
-}
-
-// a team was found guilty for major unsporting behavior
-type GameEvent_UnsportingBehaviorMajor struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that found guilty
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // an explanation of the situation and decision
- Reason *string `protobuf:"bytes,2,req,name=reason" json:"reason,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_UnsportingBehaviorMajor) Reset() {
- *x = GameEvent_UnsportingBehaviorMajor{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[30]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_UnsportingBehaviorMajor) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_UnsportingBehaviorMajor) ProtoMessage() {}
-
-func (x *GameEvent_UnsportingBehaviorMajor) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[30]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_UnsportingBehaviorMajor.ProtoReflect.Descriptor instead.
-func (*GameEvent_UnsportingBehaviorMajor) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 29}
-}
-
-func (x *GameEvent_UnsportingBehaviorMajor) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_UnsportingBehaviorMajor) GetReason() string {
- if x != nil && x.Reason != nil {
- return *x.Reason
- }
- return ""
-}
-
-// a keeper held the ball in its defense area for too long
-type GameEvent_KeeperHeldBall struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that found guilty
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the location of the ball [m]
- Location *Vector2 `protobuf:"bytes,2,opt,name=location" json:"location,omitempty"`
- // the duration [s] that the keeper hold the ball
- Duration *float32 `protobuf:"fixed32,3,opt,name=duration" json:"duration,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_KeeperHeldBall) Reset() {
- *x = GameEvent_KeeperHeldBall{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[31]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_KeeperHeldBall) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_KeeperHeldBall) ProtoMessage() {}
-
-func (x *GameEvent_KeeperHeldBall) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[31]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_KeeperHeldBall.ProtoReflect.Descriptor instead.
-func (*GameEvent_KeeperHeldBall) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 30}
-}
-
-func (x *GameEvent_KeeperHeldBall) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_KeeperHeldBall) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_KeeperHeldBall) GetDuration() float32 {
- if x != nil && x.Duration != nil {
- return *x.Duration
- }
- return 0
-}
-
-// a team successfully placed the ball
-type GameEvent_PlacementSucceeded struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that did the placement
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the time [s] taken for placing the ball
- TimeTaken *float32 `protobuf:"fixed32,2,opt,name=time_taken,json=timeTaken" json:"time_taken,omitempty"`
- // the distance [m] between placement location and actual ball position
- Precision *float32 `protobuf:"fixed32,3,opt,name=precision" json:"precision,omitempty"`
- // the distance [m] between the initial ball location and the placement position
- Distance *float32 `protobuf:"fixed32,4,opt,name=distance" json:"distance,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_PlacementSucceeded) Reset() {
- *x = GameEvent_PlacementSucceeded{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[32]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_PlacementSucceeded) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_PlacementSucceeded) ProtoMessage() {}
-
-func (x *GameEvent_PlacementSucceeded) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[32]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_PlacementSucceeded.ProtoReflect.Descriptor instead.
-func (*GameEvent_PlacementSucceeded) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 31}
-}
-
-func (x *GameEvent_PlacementSucceeded) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_PlacementSucceeded) GetTimeTaken() float32 {
- if x != nil && x.TimeTaken != nil {
- return *x.TimeTaken
- }
- return 0
-}
-
-func (x *GameEvent_PlacementSucceeded) GetPrecision() float32 {
- if x != nil && x.Precision != nil {
- return *x.Precision
- }
- return 0
-}
-
-func (x *GameEvent_PlacementSucceeded) GetDistance() float32 {
- if x != nil && x.Distance != nil {
- return *x.Distance
- }
- return 0
-}
-
-// both teams are prepared - all conditions are met to continue (with kickoff or penalty kick)
-type GameEvent_Prepared struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the time [s] taken for preparing
- TimeTaken *float32 `protobuf:"fixed32,1,opt,name=time_taken,json=timeTaken" json:"time_taken,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_Prepared) Reset() {
- *x = GameEvent_Prepared{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[33]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_Prepared) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_Prepared) ProtoMessage() {}
-
-func (x *GameEvent_Prepared) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[33]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_Prepared.ProtoReflect.Descriptor instead.
-func (*GameEvent_Prepared) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 32}
-}
-
-func (x *GameEvent_Prepared) GetTimeTaken() float32 {
- if x != nil && x.TimeTaken != nil {
- return *x.TimeTaken
- }
- return 0
-}
-
-// bots are being substituted by a team
-type GameEvent_BotSubstitution struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that substitutes robots
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_BotSubstitution) Reset() {
- *x = GameEvent_BotSubstitution{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[34]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_BotSubstitution) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_BotSubstitution) ProtoMessage() {}
-
-func (x *GameEvent_BotSubstitution) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[34]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_BotSubstitution.ProtoReflect.Descriptor instead.
-func (*GameEvent_BotSubstitution) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 33}
-}
-
-func (x *GameEvent_BotSubstitution) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-// A foul for excessive bot substitutions
-type GameEvent_ExcessiveBotSubstitution struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that substitutes robots
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_ExcessiveBotSubstitution) Reset() {
- *x = GameEvent_ExcessiveBotSubstitution{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[35]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_ExcessiveBotSubstitution) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_ExcessiveBotSubstitution) ProtoMessage() {}
-
-func (x *GameEvent_ExcessiveBotSubstitution) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[35]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_ExcessiveBotSubstitution.ProtoReflect.Descriptor instead.
-func (*GameEvent_ExcessiveBotSubstitution) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 34}
-}
-
-func (x *GameEvent_ExcessiveBotSubstitution) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-// A challenge flag, requested by a team previously, is flagged
-type GameEvent_ChallengeFlag struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that requested the challenge flag
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_ChallengeFlag) Reset() {
- *x = GameEvent_ChallengeFlag{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[36]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_ChallengeFlag) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_ChallengeFlag) ProtoMessage() {}
-
-func (x *GameEvent_ChallengeFlag) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[36]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_ChallengeFlag.ProtoReflect.Descriptor instead.
-func (*GameEvent_ChallengeFlag) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 35}
-}
-
-func (x *GameEvent_ChallengeFlag) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-// A challenge, flagged recently, has been handled by the referee
-type GameEvent_ChallengeFlagHandled struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that requested the challenge flag
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the challenge was accepted by the referee
- Accepted *bool `protobuf:"varint,2,req,name=accepted" json:"accepted,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_ChallengeFlagHandled) Reset() {
- *x = GameEvent_ChallengeFlagHandled{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[37]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_ChallengeFlagHandled) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_ChallengeFlagHandled) ProtoMessage() {}
-
-func (x *GameEvent_ChallengeFlagHandled) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[37]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_ChallengeFlagHandled.ProtoReflect.Descriptor instead.
-func (*GameEvent_ChallengeFlagHandled) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 36}
-}
-
-func (x *GameEvent_ChallengeFlagHandled) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_ChallengeFlagHandled) GetAccepted() bool {
- if x != nil && x.Accepted != nil {
- return *x.Accepted
- }
- return false
-}
-
-// An emergency stop, requested by team previously, occurred
-type GameEvent_EmergencyStop struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that substitutes robots
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_EmergencyStop) Reset() {
- *x = GameEvent_EmergencyStop{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[38]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_EmergencyStop) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_EmergencyStop) ProtoMessage() {}
-
-func (x *GameEvent_EmergencyStop) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[38]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_EmergencyStop.ProtoReflect.Descriptor instead.
-func (*GameEvent_EmergencyStop) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 37}
-}
-
-func (x *GameEvent_EmergencyStop) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-// a team has too many robots on the field
-type GameEvent_TooManyRobots struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that has too many robots
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // number of robots allowed at the moment
- NumRobotsAllowed *int32 `protobuf:"varint,2,opt,name=num_robots_allowed,json=numRobotsAllowed" json:"num_robots_allowed,omitempty"`
- // number of robots currently on the field
- NumRobotsOnField *int32 `protobuf:"varint,3,opt,name=num_robots_on_field,json=numRobotsOnField" json:"num_robots_on_field,omitempty"`
- // the location of the ball at the moment when this foul occurred [m]
- BallLocation *Vector2 `protobuf:"bytes,4,opt,name=ball_location,json=ballLocation" json:"ball_location,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_TooManyRobots) Reset() {
- *x = GameEvent_TooManyRobots{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[39]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_TooManyRobots) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_TooManyRobots) ProtoMessage() {}
-
-func (x *GameEvent_TooManyRobots) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[39]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_TooManyRobots.ProtoReflect.Descriptor instead.
-func (*GameEvent_TooManyRobots) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 38}
-}
-
-func (x *GameEvent_TooManyRobots) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_TooManyRobots) GetNumRobotsAllowed() int32 {
- if x != nil && x.NumRobotsAllowed != nil {
- return *x.NumRobotsAllowed
- }
- return 0
-}
-
-func (x *GameEvent_TooManyRobots) GetNumRobotsOnField() int32 {
- if x != nil && x.NumRobotsOnField != nil {
- return *x.NumRobotsOnField
- }
- return 0
-}
-
-func (x *GameEvent_TooManyRobots) GetBallLocation() *Vector2 {
- if x != nil {
- return x.BallLocation
- }
- return nil
-}
-
-// a robot chipped the ball over the field boundary out of the playing surface
-type GameEvent_BoundaryCrossing struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that has too many robots
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the location of the ball [m]
- Location *Vector2 `protobuf:"bytes,2,opt,name=location" json:"location,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_BoundaryCrossing) Reset() {
- *x = GameEvent_BoundaryCrossing{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[40]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_BoundaryCrossing) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_BoundaryCrossing) ProtoMessage() {}
-
-func (x *GameEvent_BoundaryCrossing) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[40]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_BoundaryCrossing.ProtoReflect.Descriptor instead.
-func (*GameEvent_BoundaryCrossing) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 39}
-}
-
-func (x *GameEvent_BoundaryCrossing) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_BoundaryCrossing) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-// the penalty kick failed (by time or by keeper)
-type GameEvent_PenaltyKickFailed struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that last touched the ball
- ByTeam *Team `protobuf:"varint,1,req,name=by_team,json=byTeam,enum=Team" json:"by_team,omitempty"`
- // the location of the ball at the moment of this event [m]
- Location *Vector2 `protobuf:"bytes,2,opt,name=location" json:"location,omitempty"`
- // an explanation of the failure
- Reason *string `protobuf:"bytes,3,opt,name=reason" json:"reason,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEvent_PenaltyKickFailed) Reset() {
- *x = GameEvent_PenaltyKickFailed{}
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[41]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEvent_PenaltyKickFailed) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEvent_PenaltyKickFailed) ProtoMessage() {}
-
-func (x *GameEvent_PenaltyKickFailed) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_game_event_proto_msgTypes[41]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEvent_PenaltyKickFailed.ProtoReflect.Descriptor instead.
-func (*GameEvent_PenaltyKickFailed) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP(), []int{0, 40}
-}
-
-func (x *GameEvent_PenaltyKickFailed) GetByTeam() Team {
- if x != nil && x.ByTeam != nil {
- return *x.ByTeam
- }
- return Team_UNKNOWN
-}
-
-func (x *GameEvent_PenaltyKickFailed) GetLocation() *Vector2 {
- if x != nil {
- return x.Location
- }
- return nil
-}
-
-func (x *GameEvent_PenaltyKickFailed) GetReason() string {
- if x != nil && x.Reason != nil {
- return *x.Reason
- }
- return ""
-}
-
-var File_gamecontroller_ssl_gc_game_event_proto protoreflect.FileDescriptor
-
-const file_gamecontroller_ssl_gc_game_event_proto_rawDesc = "" +
- "\n" +
- "&gamecontroller/ssl_gc_game_event.proto\x1a\"gamecontroller/ssl_gc_common.proto\x1a$gamecontroller/ssl_gc_geometry.proto\"\xceU\n" +
- "\tGameEvent\x12\x0e\n" +
- "\x02id\x182 \x01(\tR\x02id\x12#\n" +
- "\x04type\x18( \x01(\x0e2\x0f.GameEvent.TypeR\x04type\x12\x16\n" +
- "\x06origin\x18) \x03(\tR\x06origin\x12+\n" +
- "\x11created_timestamp\x181 \x01(\x04R\x10createdTimestamp\x12V\n" +
- "\x1aball_left_field_touch_line\x18\x06 \x01(\v2\x18.GameEvent.BallLeftFieldH\x00R\x16ballLeftFieldTouchLine\x12T\n" +
- "\x19ball_left_field_goal_line\x18\a \x01(\v2\x18.GameEvent.BallLeftFieldH\x00R\x15ballLeftFieldGoalLine\x12;\n" +
- "\faimless_kick\x18\v \x01(\v2\x16.GameEvent.AimlessKickH\x00R\vaimlessKick\x12u\n" +
- "\"attacker_too_close_to_defense_area\x18\x13 \x01(\v2(.GameEvent.AttackerTooCloseToDefenseAreaH\x00R\x1dattackerTooCloseToDefenseArea\x12[\n" +
- "\x18defender_in_defense_area\x18\x1f \x01(\v2 .GameEvent.DefenderInDefenseAreaH\x00R\x15defenderInDefenseArea\x12J\n" +
- "\x11boundary_crossing\x18+ \x01(\v2\x1b.GameEvent.BoundaryCrossingH\x00R\x10boundaryCrossing\x12E\n" +
- "\x10keeper_held_ball\x18\r \x01(\v2\x19.GameEvent.KeeperHeldBallH\x00R\x0ekeeperHeldBall\x12\\\n" +
- "\x19bot_dribbled_ball_too_far\x18\x11 \x01(\v2 .GameEvent.BotDribbledBallTooFarH\x00R\x15botDribbledBallTooFar\x12?\n" +
- "\x0ebot_pushed_bot\x18\x18 \x01(\v2\x17.GameEvent.BotPushedBotH\x00R\fbotPushedBot\x12a\n" +
- "\x1abot_held_ball_deliberately\x18\x1a \x01(\v2\".GameEvent.BotHeldBallDeliberatelyH\x00R\x17botHeldBallDeliberately\x12B\n" +
- "\x0fbot_tipped_over\x18\x1b \x01(\v2\x18.GameEvent.BotTippedOverH\x00R\rbotTippedOver\x12H\n" +
- "\x11bot_dropped_parts\x183 \x01(\v2\x1a.GameEvent.BotDroppedPartsH\x00R\x0fbotDroppedParts\x12~\n" +
- "%attacker_touched_ball_in_defense_area\x18\x0f \x01(\v2+.GameEvent.AttackerTouchedBallInDefenseAreaH\x00R attackerTouchedBallInDefenseArea\x12Y\n" +
- "\x18bot_kicked_ball_too_fast\x18\x12 \x01(\v2\x1f.GameEvent.BotKickedBallTooFastH\x00R\x14botKickedBallTooFast\x12E\n" +
- "\x10bot_crash_unique\x18\x16 \x01(\v2\x19.GameEvent.BotCrashUniqueH\x00R\x0ebotCrashUnique\x12B\n" +
- "\x0fbot_crash_drawn\x18\x15 \x01(\v2\x18.GameEvent.BotCrashDrawnH\x00R\rbotCrashDrawn\x12o\n" +
- " defender_too_close_to_kick_point\x18\x1d \x01(\v2&.GameEvent.DefenderTooCloseToKickPointH\x00R\x1bdefenderTooCloseToKickPoint\x12M\n" +
- "\x14bot_too_fast_in_stop\x18\x1c \x01(\v2\x1b.GameEvent.BotTooFastInStopH\x00R\x10botTooFastInStop\x12]\n" +
- "\x18bot_interfered_placement\x18\x14 \x01(\v2!.GameEvent.BotInterferedPlacementH\x00R\x16botInterferedPlacement\x126\n" +
- "\rpossible_goal\x18' \x01(\v2\x0f.GameEvent.GoalH\x00R\fpossibleGoal\x12%\n" +
- "\x04goal\x18\b \x01(\v2\x0f.GameEvent.GoalH\x00R\x04goal\x124\n" +
- "\finvalid_goal\x18, \x01(\v2\x0f.GameEvent.GoalH\x00R\vinvalidGoal\x12g\n" +
- "\x1cattacker_double_touched_ball\x18\x0e \x01(\v2$.GameEvent.AttackerDoubleTouchedBallH\x00R\x19attackerDoubleTouchedBall\x12P\n" +
- "\x13placement_succeeded\x18\x05 \x01(\v2\x1d.GameEvent.PlacementSucceededH\x00R\x12placementSucceeded\x12N\n" +
- "\x13penalty_kick_failed\x18- \x01(\v2\x1c.GameEvent.PenaltyKickFailedH\x00R\x11penaltyKickFailed\x12L\n" +
- "\x13no_progress_in_game\x18\x02 \x01(\v2\x1b.GameEvent.NoProgressInGameH\x00R\x10noProgressInGame\x12G\n" +
- "\x10placement_failed\x18\x03 \x01(\v2\x1a.GameEvent.PlacementFailedH\x00R\x0fplacementFailed\x12A\n" +
- "\x0emultiple_cards\x18 \x01(\v2\x18.GameEvent.MultipleCardsH\x00R\rmultipleCards\x12A\n" +
- "\x0emultiple_fouls\x18\" \x01(\v2\x18.GameEvent.MultipleFoulsH\x00R\rmultipleFouls\x12G\n" +
- "\x10bot_substitution\x18% \x01(\v2\x1a.GameEvent.BotSubstitutionH\x00R\x0fbotSubstitution\x12c\n" +
- "\x1aexcessive_bot_substitution\x184 \x01(\v2#.GameEvent.ExcessiveBotSubstitutionH\x00R\x18excessiveBotSubstitution\x12B\n" +
- "\x0ftoo_many_robots\x18& \x01(\v2\x18.GameEvent.TooManyRobotsH\x00R\rtooManyRobots\x12A\n" +
- "\x0echallenge_flag\x18. \x01(\v2\x18.GameEvent.ChallengeFlagH\x00R\rchallengeFlag\x12W\n" +
- "\x16challenge_flag_handled\x180 \x01(\v2\x1f.GameEvent.ChallengeFlagHandledH\x00R\x14challengeFlagHandled\x12A\n" +
- "\x0eemergency_stop\x18/ \x01(\v2\x18.GameEvent.EmergencyStopH\x00R\remergencyStop\x12`\n" +
- "\x19unsporting_behavior_minor\x18# \x01(\v2\".GameEvent.UnsportingBehaviorMinorH\x00R\x17unsportingBehaviorMinor\x12`\n" +
- "\x19unsporting_behavior_major\x18$ \x01(\v2\".GameEvent.UnsportingBehaviorMajorH\x00R\x17unsportingBehaviorMajor\x125\n" +
- "\bprepared\x18\x01 \x01(\v2\x13.GameEvent.PreparedB\x02\x18\x01H\x00R\bprepared\x12B\n" +
- "\rindirect_goal\x18\t \x01(\v2\x17.GameEvent.IndirectGoalB\x02\x18\x01H\x00R\findirectGoal\x12?\n" +
- "\fchipped_goal\x18\n" +
- " \x01(\v2\x16.GameEvent.ChippedGoalB\x02\x18\x01H\x00R\vchippedGoal\x12?\n" +
- "\fkick_timeout\x18\f \x01(\v2\x16.GameEvent.KickTimeoutB\x02\x18\x01H\x00R\vkickTimeout\x12\x8e\x01\n" +
- ")attacker_touched_opponent_in_defense_area\x18\x10 \x01(\v2/.GameEvent.AttackerTouchedOpponentInDefenseAreaB\x02\x18\x01H\x00R$attackerTouchedOpponentInDefenseArea\x12\x9d\x01\n" +
- "1attacker_touched_opponent_in_defense_area_skipped\x18* \x01(\v2/.GameEvent.AttackerTouchedOpponentInDefenseAreaB\x02\x18\x01H\x00R+attackerTouchedOpponentInDefenseAreaSkipped\x12X\n" +
- "\x18bot_crash_unique_skipped\x18\x17 \x01(\v2\x19.GameEvent.BotCrashUniqueB\x02\x18\x01H\x00R\x15botCrashUniqueSkipped\x12R\n" +
- "\x16bot_pushed_bot_skipped\x18\x19 \x01(\v2\x17.GameEvent.BotPushedBotB\x02\x18\x01H\x00R\x13botPushedBotSkipped\x12{\n" +
- "\"defender_in_defense_area_partially\x18\x1e \x01(\v2).GameEvent.DefenderInDefenseAreaPartiallyB\x02\x18\x01H\x00R\x1edefenderInDefenseAreaPartially\x12j\n" +
- "\x1bmultiple_placement_failures\x18! \x01(\v2$.GameEvent.MultiplePlacementFailuresB\x02\x18\x01H\x00R\x19multiplePlacementFailures\x1al\n" +
- "\rBallLeftField\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
- "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x1a\x99\x01\n" +
- "\vAimlessKick\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
- "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12-\n" +
- "\rkick_location\x18\x04 \x01(\v2\b.Vector2R\fkickLocation\x1a\xe2\x02\n" +
- "\x04Goal\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12(\n" +
- "\fkicking_team\x18\x06 \x01(\x0e2\x05.TeamR\vkickingTeam\x12\x1f\n" +
- "\vkicking_bot\x18\x02 \x01(\rR\n" +
- "kickingBot\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12-\n" +
- "\rkick_location\x18\x04 \x01(\v2\b.Vector2R\fkickLocation\x12&\n" +
- "\x0fmax_ball_height\x18\x05 \x01(\x02R\rmaxBallHeight\x12+\n" +
- "\x12num_robots_by_team\x18\a \x01(\rR\x0fnumRobotsByTeam\x12+\n" +
- "\x12last_touch_by_team\x18\b \x01(\x04R\x0flastTouchByTeam\x12\x18\n" +
- "\amessage\x18\t \x01(\tR\amessage\x1a\x9a\x01\n" +
- "\fIndirectGoal\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
- "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12-\n" +
- "\rkick_location\x18\x04 \x01(\v2\b.Vector2R\fkickLocation\x1a\xc1\x01\n" +
- "\vChippedGoal\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
- "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12-\n" +
- "\rkick_location\x18\x04 \x01(\v2\b.Vector2R\fkickLocation\x12&\n" +
- "\x0fmax_ball_height\x18\x05 \x01(\x02R\rmaxBallHeight\x1a\x85\x01\n" +
- "\x10BotTooFastInStop\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
- "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12\x14\n" +
- "\x05speed\x18\x04 \x01(\x02R\x05speed\x1a\x96\x01\n" +
- "\x1bDefenderTooCloseToKickPoint\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
- "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12\x1a\n" +
- "\bdistance\x18\x04 \x01(\x02R\bdistance\x1a\xd0\x01\n" +
- "\rBotCrashDrawn\x12\x1d\n" +
- "\n" +
- "bot_yellow\x18\x01 \x01(\rR\tbotYellow\x12\x19\n" +
- "\bbot_blue\x18\x02 \x01(\rR\abotBlue\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12\x1f\n" +
- "\vcrash_speed\x18\x04 \x01(\x02R\n" +
- "crashSpeed\x12\x1d\n" +
- "\n" +
- "speed_diff\x18\x05 \x01(\x02R\tspeedDiff\x12\x1f\n" +
- "\vcrash_angle\x18\x06 \x01(\x02R\n" +
- "crashAngle\x1a\xeb\x01\n" +
- "\x0eBotCrashUnique\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x1a\n" +
- "\bviolator\x18\x02 \x01(\rR\bviolator\x12\x16\n" +
- "\x06victim\x18\x03 \x01(\rR\x06victim\x12$\n" +
- "\blocation\x18\x04 \x01(\v2\b.Vector2R\blocation\x12\x1f\n" +
- "\vcrash_speed\x18\x05 \x01(\x02R\n" +
- "crashSpeed\x12\x1d\n" +
- "\n" +
- "speed_diff\x18\x06 \x01(\x02R\tspeedDiff\x12\x1f\n" +
- "\vcrash_angle\x18\a \x01(\x02R\n" +
- "crashAngle\x1a\xb1\x01\n" +
- "\fBotPushedBot\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x1a\n" +
- "\bviolator\x18\x02 \x01(\rR\bviolator\x12\x16\n" +
- "\x06victim\x18\x03 \x01(\rR\x06victim\x12$\n" +
- "\blocation\x18\x04 \x01(\v2\b.Vector2R\blocation\x12'\n" +
- "\x0fpushed_distance\x18\x05 \x01(\x02R\x0epushedDistance\x1a\x9b\x01\n" +
- "\rBotTippedOver\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
- "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12-\n" +
- "\rball_location\x18\x04 \x01(\v2\b.Vector2R\fballLocation\x1a\x9d\x01\n" +
- "\x0fBotDroppedParts\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
- "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12-\n" +
- "\rball_location\x18\x04 \x01(\v2\b.Vector2R\fballLocation\x1a\x90\x01\n" +
- "\x15DefenderInDefenseArea\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
- "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12\x1a\n" +
- "\bdistance\x18\x04 \x01(\x02R\bdistance\x1a\xc8\x01\n" +
- "\x1eDefenderInDefenseAreaPartially\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
- "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12\x1a\n" +
- "\bdistance\x18\x04 \x01(\x02R\bdistance\x12-\n" +
- "\rball_location\x18\x05 \x01(\v2\b.Vector2R\fballLocation\x1a\x9b\x01\n" +
- " AttackerTouchedBallInDefenseArea\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
- "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12\x1a\n" +
- "\bdistance\x18\x04 \x01(\x02R\bdistance\x1a\xbb\x01\n" +
- "\x14BotKickedBallTooFast\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
- "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12,\n" +
- "\x12initial_ball_speed\x18\x04 \x01(\x02R\x10initialBallSpeed\x12\x18\n" +
- "\achipped\x18\x05 \x01(\bR\achipped\x1a\x8a\x01\n" +
- "\x15BotDribbledBallTooFar\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
- "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12\x1e\n" +
- "\x05start\x18\x03 \x01(\v2\b.Vector2R\x05start\x12\x1a\n" +
- "\x03end\x18\x04 \x01(\v2\b.Vector2R\x03end\x1a\x9b\x01\n" +
- "$AttackerTouchedOpponentInDefenseArea\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
- "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12\x16\n" +
- "\x06victim\x18\x04 \x01(\rR\x06victim\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x1ax\n" +
- "\x19AttackerDoubleTouchedBall\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
- "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x1a\xc7\x01\n" +
- "\x1dAttackerTooCloseToDefenseArea\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
- "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12\x1a\n" +
- "\bdistance\x18\x04 \x01(\x02R\bdistance\x12-\n" +
- "\rball_location\x18\x05 \x01(\v2\b.Vector2R\fballLocation\x1a\x92\x01\n" +
- "\x17BotHeldBallDeliberately\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
- "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x12\x1a\n" +
- "\bduration\x18\x04 \x01(\x02R\bduration\x1au\n" +
- "\x16BotInterferedPlacement\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x15\n" +
- "\x06by_bot\x18\x02 \x01(\rR\x05byBot\x12$\n" +
- "\blocation\x18\x03 \x01(\v2\b.Vector2R\blocation\x1a/\n" +
- "\rMultipleCards\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x1ai\n" +
- "\rMultipleFouls\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x128\n" +
- "\x12caused_game_events\x18\x02 \x03(\v2\n" +
- ".GameEventR\x10causedGameEvents\x1a;\n" +
- "\x19MultiplePlacementFailures\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x1ag\n" +
- "\vKickTimeout\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12$\n" +
- "\blocation\x18\x02 \x01(\v2\b.Vector2R\blocation\x12\x12\n" +
- "\x04time\x18\x03 \x01(\x02R\x04time\x1aL\n" +
- "\x10NoProgressInGame\x12$\n" +
- "\blocation\x18\x01 \x01(\v2\b.Vector2R\blocation\x12\x12\n" +
- "\x04time\x18\x02 \x01(\x02R\x04time\x1a\x99\x01\n" +
- "\x0fPlacementFailed\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12-\n" +
- "\x12remaining_distance\x18\x02 \x01(\x02R\x11remainingDistance\x127\n" +
- "\x18nearest_own_bot_distance\x18\x03 \x01(\x02R\x15nearestOwnBotDistance\x1aQ\n" +
- "\x17UnsportingBehaviorMinor\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x16\n" +
- "\x06reason\x18\x02 \x02(\tR\x06reason\x1aQ\n" +
- "\x17UnsportingBehaviorMajor\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x16\n" +
- "\x06reason\x18\x02 \x02(\tR\x06reason\x1ar\n" +
- "\x0eKeeperHeldBall\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12$\n" +
- "\blocation\x18\x02 \x01(\v2\b.Vector2R\blocation\x12\x1a\n" +
- "\bduration\x18\x03 \x01(\x02R\bduration\x1a\x8d\x01\n" +
- "\x12PlacementSucceeded\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x1d\n" +
- "\n" +
- "time_taken\x18\x02 \x01(\x02R\ttimeTaken\x12\x1c\n" +
- "\tprecision\x18\x03 \x01(\x02R\tprecision\x12\x1a\n" +
- "\bdistance\x18\x04 \x01(\x02R\bdistance\x1a)\n" +
- "\bPrepared\x12\x1d\n" +
- "\n" +
- "time_taken\x18\x01 \x01(\x02R\ttimeTaken\x1a1\n" +
- "\x0fBotSubstitution\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x1a:\n" +
- "\x18ExcessiveBotSubstitution\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x1a/\n" +
- "\rChallengeFlag\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x1aR\n" +
- "\x14ChallengeFlagHandled\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12\x1a\n" +
- "\baccepted\x18\x02 \x02(\bR\baccepted\x1a/\n" +
- "\rEmergencyStop\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x1a\xbb\x01\n" +
- "\rTooManyRobots\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12,\n" +
- "\x12num_robots_allowed\x18\x02 \x01(\x05R\x10numRobotsAllowed\x12-\n" +
- "\x13num_robots_on_field\x18\x03 \x01(\x05R\x10numRobotsOnField\x12-\n" +
- "\rball_location\x18\x04 \x01(\v2\b.Vector2R\fballLocation\x1aX\n" +
- "\x10BoundaryCrossing\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12$\n" +
- "\blocation\x18\x02 \x01(\v2\b.Vector2R\blocation\x1aq\n" +
- "\x11PenaltyKickFailed\x12\x1e\n" +
- "\aby_team\x18\x01 \x02(\x0e2\x05.TeamR\x06byTeam\x12$\n" +
- "\blocation\x18\x02 \x01(\v2\b.Vector2R\blocation\x12\x16\n" +
- "\x06reason\x18\x03 \x01(\tR\x06reason\"\xb5\n" +
- "\n" +
- "\x04Type\x12\x1b\n" +
- "\x17UNKNOWN_GAME_EVENT_TYPE\x10\x00\x12\x1e\n" +
- "\x1aBALL_LEFT_FIELD_TOUCH_LINE\x10\x06\x12\x1d\n" +
- "\x19BALL_LEFT_FIELD_GOAL_LINE\x10\a\x12\x10\n" +
- "\fAIMLESS_KICK\x10\v\x12&\n" +
- "\"ATTACKER_TOO_CLOSE_TO_DEFENSE_AREA\x10\x13\x12\x1c\n" +
- "\x18DEFENDER_IN_DEFENSE_AREA\x10\x1f\x12\x15\n" +
- "\x11BOUNDARY_CROSSING\x10)\x12\x14\n" +
- "\x10KEEPER_HELD_BALL\x10\r\x12\x1d\n" +
- "\x19BOT_DRIBBLED_BALL_TOO_FAR\x10\x11\x12\x12\n" +
- "\x0eBOT_PUSHED_BOT\x10\x18\x12\x1e\n" +
- "\x1aBOT_HELD_BALL_DELIBERATELY\x10\x1a\x12\x13\n" +
- "\x0fBOT_TIPPED_OVER\x10\x1b\x12\x15\n" +
- "\x11BOT_DROPPED_PARTS\x10/\x12)\n" +
- "%ATTACKER_TOUCHED_BALL_IN_DEFENSE_AREA\x10\x0f\x12\x1c\n" +
- "\x18BOT_KICKED_BALL_TOO_FAST\x10\x12\x12\x14\n" +
- "\x10BOT_CRASH_UNIQUE\x10\x16\x12\x13\n" +
- "\x0fBOT_CRASH_DRAWN\x10\x15\x12$\n" +
- " DEFENDER_TOO_CLOSE_TO_KICK_POINT\x10\x1d\x12\x18\n" +
- "\x14BOT_TOO_FAST_IN_STOP\x10\x1c\x12\x1c\n" +
- "\x18BOT_INTERFERED_PLACEMENT\x10\x14\x12\x1e\n" +
- "\x1aEXCESSIVE_BOT_SUBSTITUTION\x100\x12\x11\n" +
- "\rPOSSIBLE_GOAL\x10'\x12\b\n" +
- "\x04GOAL\x10\b\x12\x10\n" +
- "\fINVALID_GOAL\x10*\x12 \n" +
- "\x1cATTACKER_DOUBLE_TOUCHED_BALL\x10\x0e\x12\x17\n" +
- "\x13PLACEMENT_SUCCEEDED\x10\x05\x12\x17\n" +
- "\x13PENALTY_KICK_FAILED\x10+\x12\x17\n" +
- "\x13NO_PROGRESS_IN_GAME\x10\x02\x12\x14\n" +
- "\x10PLACEMENT_FAILED\x10\x03\x12\x12\n" +
- "\x0eMULTIPLE_CARDS\x10 \x12\x12\n" +
- "\x0eMULTIPLE_FOULS\x10\"\x12\x14\n" +
- "\x10BOT_SUBSTITUTION\x10%\x12\x13\n" +
- "\x0fTOO_MANY_ROBOTS\x10&\x12\x12\n" +
- "\x0eCHALLENGE_FLAG\x10,\x12\x1a\n" +
- "\x16CHALLENGE_FLAG_HANDLED\x10.\x12\x12\n" +
- "\x0eEMERGENCY_STOP\x10-\x12\x1d\n" +
- "\x19UNSPORTING_BEHAVIOR_MINOR\x10#\x12\x1d\n" +
- "\x19UNSPORTING_BEHAVIOR_MAJOR\x10$\x12\x10\n" +
- "\bPREPARED\x10\x01\x1a\x02\b\x01\x12\x15\n" +
- "\rINDIRECT_GOAL\x10\t\x1a\x02\b\x01\x12\x14\n" +
- "\fCHIPPED_GOAL\x10\n" +
- "\x1a\x02\b\x01\x12\x14\n" +
- "\fKICK_TIMEOUT\x10\f\x1a\x02\b\x01\x121\n" +
- ")ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA\x10\x10\x1a\x02\b\x01\x129\n" +
- "1ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA_SKIPPED\x10(\x1a\x02\b\x01\x12 \n" +
- "\x18BOT_CRASH_UNIQUE_SKIPPED\x10\x17\x1a\x02\b\x01\x12\x1e\n" +
- "\x16BOT_PUSHED_BOT_SKIPPED\x10\x19\x1a\x02\b\x01\x12*\n" +
- "\"DEFENDER_IN_DEFENSE_AREA_PARTIALLY\x10\x1e\x1a\x02\b\x01\x12#\n" +
- "\x1bMULTIPLE_PLACEMENT_FAILURES\x10!\x1a\x02\b\x01B\a\n" +
- "\x05eventB`B\x13SslGcGameEventProtoP\x01ZGgithub.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
-
-var (
- file_gamecontroller_ssl_gc_game_event_proto_rawDescOnce sync.Once
- file_gamecontroller_ssl_gc_game_event_proto_rawDescData []byte
-)
-
-func file_gamecontroller_ssl_gc_game_event_proto_rawDescGZIP() []byte {
- file_gamecontroller_ssl_gc_game_event_proto_rawDescOnce.Do(func() {
- file_gamecontroller_ssl_gc_game_event_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_game_event_proto_rawDesc), len(file_gamecontroller_ssl_gc_game_event_proto_rawDesc)))
- })
- return file_gamecontroller_ssl_gc_game_event_proto_rawDescData
-}
-
-var file_gamecontroller_ssl_gc_game_event_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
-var file_gamecontroller_ssl_gc_game_event_proto_msgTypes = make([]protoimpl.MessageInfo, 42)
-var file_gamecontroller_ssl_gc_game_event_proto_goTypes = []any{
- (GameEvent_Type)(0), // 0: GameEvent.Type
- (*GameEvent)(nil), // 1: GameEvent
- (*GameEvent_BallLeftField)(nil), // 2: GameEvent.BallLeftField
- (*GameEvent_AimlessKick)(nil), // 3: GameEvent.AimlessKick
- (*GameEvent_Goal)(nil), // 4: GameEvent.Goal
- (*GameEvent_IndirectGoal)(nil), // 5: GameEvent.IndirectGoal
- (*GameEvent_ChippedGoal)(nil), // 6: GameEvent.ChippedGoal
- (*GameEvent_BotTooFastInStop)(nil), // 7: GameEvent.BotTooFastInStop
- (*GameEvent_DefenderTooCloseToKickPoint)(nil), // 8: GameEvent.DefenderTooCloseToKickPoint
- (*GameEvent_BotCrashDrawn)(nil), // 9: GameEvent.BotCrashDrawn
- (*GameEvent_BotCrashUnique)(nil), // 10: GameEvent.BotCrashUnique
- (*GameEvent_BotPushedBot)(nil), // 11: GameEvent.BotPushedBot
- (*GameEvent_BotTippedOver)(nil), // 12: GameEvent.BotTippedOver
- (*GameEvent_BotDroppedParts)(nil), // 13: GameEvent.BotDroppedParts
- (*GameEvent_DefenderInDefenseArea)(nil), // 14: GameEvent.DefenderInDefenseArea
- (*GameEvent_DefenderInDefenseAreaPartially)(nil), // 15: GameEvent.DefenderInDefenseAreaPartially
- (*GameEvent_AttackerTouchedBallInDefenseArea)(nil), // 16: GameEvent.AttackerTouchedBallInDefenseArea
- (*GameEvent_BotKickedBallTooFast)(nil), // 17: GameEvent.BotKickedBallTooFast
- (*GameEvent_BotDribbledBallTooFar)(nil), // 18: GameEvent.BotDribbledBallTooFar
- (*GameEvent_AttackerTouchedOpponentInDefenseArea)(nil), // 19: GameEvent.AttackerTouchedOpponentInDefenseArea
- (*GameEvent_AttackerDoubleTouchedBall)(nil), // 20: GameEvent.AttackerDoubleTouchedBall
- (*GameEvent_AttackerTooCloseToDefenseArea)(nil), // 21: GameEvent.AttackerTooCloseToDefenseArea
- (*GameEvent_BotHeldBallDeliberately)(nil), // 22: GameEvent.BotHeldBallDeliberately
- (*GameEvent_BotInterferedPlacement)(nil), // 23: GameEvent.BotInterferedPlacement
- (*GameEvent_MultipleCards)(nil), // 24: GameEvent.MultipleCards
- (*GameEvent_MultipleFouls)(nil), // 25: GameEvent.MultipleFouls
- (*GameEvent_MultiplePlacementFailures)(nil), // 26: GameEvent.MultiplePlacementFailures
- (*GameEvent_KickTimeout)(nil), // 27: GameEvent.KickTimeout
- (*GameEvent_NoProgressInGame)(nil), // 28: GameEvent.NoProgressInGame
- (*GameEvent_PlacementFailed)(nil), // 29: GameEvent.PlacementFailed
- (*GameEvent_UnsportingBehaviorMinor)(nil), // 30: GameEvent.UnsportingBehaviorMinor
- (*GameEvent_UnsportingBehaviorMajor)(nil), // 31: GameEvent.UnsportingBehaviorMajor
- (*GameEvent_KeeperHeldBall)(nil), // 32: GameEvent.KeeperHeldBall
- (*GameEvent_PlacementSucceeded)(nil), // 33: GameEvent.PlacementSucceeded
- (*GameEvent_Prepared)(nil), // 34: GameEvent.Prepared
- (*GameEvent_BotSubstitution)(nil), // 35: GameEvent.BotSubstitution
- (*GameEvent_ExcessiveBotSubstitution)(nil), // 36: GameEvent.ExcessiveBotSubstitution
- (*GameEvent_ChallengeFlag)(nil), // 37: GameEvent.ChallengeFlag
- (*GameEvent_ChallengeFlagHandled)(nil), // 38: GameEvent.ChallengeFlagHandled
- (*GameEvent_EmergencyStop)(nil), // 39: GameEvent.EmergencyStop
- (*GameEvent_TooManyRobots)(nil), // 40: GameEvent.TooManyRobots
- (*GameEvent_BoundaryCrossing)(nil), // 41: GameEvent.BoundaryCrossing
- (*GameEvent_PenaltyKickFailed)(nil), // 42: GameEvent.PenaltyKickFailed
- (Team)(0), // 43: Team
- (*Vector2)(nil), // 44: Vector2
-}
-var file_gamecontroller_ssl_gc_game_event_proto_depIdxs = []int32{
- 0, // 0: GameEvent.type:type_name -> GameEvent.Type
- 2, // 1: GameEvent.ball_left_field_touch_line:type_name -> GameEvent.BallLeftField
- 2, // 2: GameEvent.ball_left_field_goal_line:type_name -> GameEvent.BallLeftField
- 3, // 3: GameEvent.aimless_kick:type_name -> GameEvent.AimlessKick
- 21, // 4: GameEvent.attacker_too_close_to_defense_area:type_name -> GameEvent.AttackerTooCloseToDefenseArea
- 14, // 5: GameEvent.defender_in_defense_area:type_name -> GameEvent.DefenderInDefenseArea
- 41, // 6: GameEvent.boundary_crossing:type_name -> GameEvent.BoundaryCrossing
- 32, // 7: GameEvent.keeper_held_ball:type_name -> GameEvent.KeeperHeldBall
- 18, // 8: GameEvent.bot_dribbled_ball_too_far:type_name -> GameEvent.BotDribbledBallTooFar
- 11, // 9: GameEvent.bot_pushed_bot:type_name -> GameEvent.BotPushedBot
- 22, // 10: GameEvent.bot_held_ball_deliberately:type_name -> GameEvent.BotHeldBallDeliberately
- 12, // 11: GameEvent.bot_tipped_over:type_name -> GameEvent.BotTippedOver
- 13, // 12: GameEvent.bot_dropped_parts:type_name -> GameEvent.BotDroppedParts
- 16, // 13: GameEvent.attacker_touched_ball_in_defense_area:type_name -> GameEvent.AttackerTouchedBallInDefenseArea
- 17, // 14: GameEvent.bot_kicked_ball_too_fast:type_name -> GameEvent.BotKickedBallTooFast
- 10, // 15: GameEvent.bot_crash_unique:type_name -> GameEvent.BotCrashUnique
- 9, // 16: GameEvent.bot_crash_drawn:type_name -> GameEvent.BotCrashDrawn
- 8, // 17: GameEvent.defender_too_close_to_kick_point:type_name -> GameEvent.DefenderTooCloseToKickPoint
- 7, // 18: GameEvent.bot_too_fast_in_stop:type_name -> GameEvent.BotTooFastInStop
- 23, // 19: GameEvent.bot_interfered_placement:type_name -> GameEvent.BotInterferedPlacement
- 4, // 20: GameEvent.possible_goal:type_name -> GameEvent.Goal
- 4, // 21: GameEvent.goal:type_name -> GameEvent.Goal
- 4, // 22: GameEvent.invalid_goal:type_name -> GameEvent.Goal
- 20, // 23: GameEvent.attacker_double_touched_ball:type_name -> GameEvent.AttackerDoubleTouchedBall
- 33, // 24: GameEvent.placement_succeeded:type_name -> GameEvent.PlacementSucceeded
- 42, // 25: GameEvent.penalty_kick_failed:type_name -> GameEvent.PenaltyKickFailed
- 28, // 26: GameEvent.no_progress_in_game:type_name -> GameEvent.NoProgressInGame
- 29, // 27: GameEvent.placement_failed:type_name -> GameEvent.PlacementFailed
- 24, // 28: GameEvent.multiple_cards:type_name -> GameEvent.MultipleCards
- 25, // 29: GameEvent.multiple_fouls:type_name -> GameEvent.MultipleFouls
- 35, // 30: GameEvent.bot_substitution:type_name -> GameEvent.BotSubstitution
- 36, // 31: GameEvent.excessive_bot_substitution:type_name -> GameEvent.ExcessiveBotSubstitution
- 40, // 32: GameEvent.too_many_robots:type_name -> GameEvent.TooManyRobots
- 37, // 33: GameEvent.challenge_flag:type_name -> GameEvent.ChallengeFlag
- 38, // 34: GameEvent.challenge_flag_handled:type_name -> GameEvent.ChallengeFlagHandled
- 39, // 35: GameEvent.emergency_stop:type_name -> GameEvent.EmergencyStop
- 30, // 36: GameEvent.unsporting_behavior_minor:type_name -> GameEvent.UnsportingBehaviorMinor
- 31, // 37: GameEvent.unsporting_behavior_major:type_name -> GameEvent.UnsportingBehaviorMajor
- 34, // 38: GameEvent.prepared:type_name -> GameEvent.Prepared
- 5, // 39: GameEvent.indirect_goal:type_name -> GameEvent.IndirectGoal
- 6, // 40: GameEvent.chipped_goal:type_name -> GameEvent.ChippedGoal
- 27, // 41: GameEvent.kick_timeout:type_name -> GameEvent.KickTimeout
- 19, // 42: GameEvent.attacker_touched_opponent_in_defense_area:type_name -> GameEvent.AttackerTouchedOpponentInDefenseArea
- 19, // 43: GameEvent.attacker_touched_opponent_in_defense_area_skipped:type_name -> GameEvent.AttackerTouchedOpponentInDefenseArea
- 10, // 44: GameEvent.bot_crash_unique_skipped:type_name -> GameEvent.BotCrashUnique
- 11, // 45: GameEvent.bot_pushed_bot_skipped:type_name -> GameEvent.BotPushedBot
- 15, // 46: GameEvent.defender_in_defense_area_partially:type_name -> GameEvent.DefenderInDefenseAreaPartially
- 26, // 47: GameEvent.multiple_placement_failures:type_name -> GameEvent.MultiplePlacementFailures
- 43, // 48: GameEvent.BallLeftField.by_team:type_name -> Team
- 44, // 49: GameEvent.BallLeftField.location:type_name -> Vector2
- 43, // 50: GameEvent.AimlessKick.by_team:type_name -> Team
- 44, // 51: GameEvent.AimlessKick.location:type_name -> Vector2
- 44, // 52: GameEvent.AimlessKick.kick_location:type_name -> Vector2
- 43, // 53: GameEvent.Goal.by_team:type_name -> Team
- 43, // 54: GameEvent.Goal.kicking_team:type_name -> Team
- 44, // 55: GameEvent.Goal.location:type_name -> Vector2
- 44, // 56: GameEvent.Goal.kick_location:type_name -> Vector2
- 43, // 57: GameEvent.IndirectGoal.by_team:type_name -> Team
- 44, // 58: GameEvent.IndirectGoal.location:type_name -> Vector2
- 44, // 59: GameEvent.IndirectGoal.kick_location:type_name -> Vector2
- 43, // 60: GameEvent.ChippedGoal.by_team:type_name -> Team
- 44, // 61: GameEvent.ChippedGoal.location:type_name -> Vector2
- 44, // 62: GameEvent.ChippedGoal.kick_location:type_name -> Vector2
- 43, // 63: GameEvent.BotTooFastInStop.by_team:type_name -> Team
- 44, // 64: GameEvent.BotTooFastInStop.location:type_name -> Vector2
- 43, // 65: GameEvent.DefenderTooCloseToKickPoint.by_team:type_name -> Team
- 44, // 66: GameEvent.DefenderTooCloseToKickPoint.location:type_name -> Vector2
- 44, // 67: GameEvent.BotCrashDrawn.location:type_name -> Vector2
- 43, // 68: GameEvent.BotCrashUnique.by_team:type_name -> Team
- 44, // 69: GameEvent.BotCrashUnique.location:type_name -> Vector2
- 43, // 70: GameEvent.BotPushedBot.by_team:type_name -> Team
- 44, // 71: GameEvent.BotPushedBot.location:type_name -> Vector2
- 43, // 72: GameEvent.BotTippedOver.by_team:type_name -> Team
- 44, // 73: GameEvent.BotTippedOver.location:type_name -> Vector2
- 44, // 74: GameEvent.BotTippedOver.ball_location:type_name -> Vector2
- 43, // 75: GameEvent.BotDroppedParts.by_team:type_name -> Team
- 44, // 76: GameEvent.BotDroppedParts.location:type_name -> Vector2
- 44, // 77: GameEvent.BotDroppedParts.ball_location:type_name -> Vector2
- 43, // 78: GameEvent.DefenderInDefenseArea.by_team:type_name -> Team
- 44, // 79: GameEvent.DefenderInDefenseArea.location:type_name -> Vector2
- 43, // 80: GameEvent.DefenderInDefenseAreaPartially.by_team:type_name -> Team
- 44, // 81: GameEvent.DefenderInDefenseAreaPartially.location:type_name -> Vector2
- 44, // 82: GameEvent.DefenderInDefenseAreaPartially.ball_location:type_name -> Vector2
- 43, // 83: GameEvent.AttackerTouchedBallInDefenseArea.by_team:type_name -> Team
- 44, // 84: GameEvent.AttackerTouchedBallInDefenseArea.location:type_name -> Vector2
- 43, // 85: GameEvent.BotKickedBallTooFast.by_team:type_name -> Team
- 44, // 86: GameEvent.BotKickedBallTooFast.location:type_name -> Vector2
- 43, // 87: GameEvent.BotDribbledBallTooFar.by_team:type_name -> Team
- 44, // 88: GameEvent.BotDribbledBallTooFar.start:type_name -> Vector2
- 44, // 89: GameEvent.BotDribbledBallTooFar.end:type_name -> Vector2
- 43, // 90: GameEvent.AttackerTouchedOpponentInDefenseArea.by_team:type_name -> Team
- 44, // 91: GameEvent.AttackerTouchedOpponentInDefenseArea.location:type_name -> Vector2
- 43, // 92: GameEvent.AttackerDoubleTouchedBall.by_team:type_name -> Team
- 44, // 93: GameEvent.AttackerDoubleTouchedBall.location:type_name -> Vector2
- 43, // 94: GameEvent.AttackerTooCloseToDefenseArea.by_team:type_name -> Team
- 44, // 95: GameEvent.AttackerTooCloseToDefenseArea.location:type_name -> Vector2
- 44, // 96: GameEvent.AttackerTooCloseToDefenseArea.ball_location:type_name -> Vector2
- 43, // 97: GameEvent.BotHeldBallDeliberately.by_team:type_name -> Team
- 44, // 98: GameEvent.BotHeldBallDeliberately.location:type_name -> Vector2
- 43, // 99: GameEvent.BotInterferedPlacement.by_team:type_name -> Team
- 44, // 100: GameEvent.BotInterferedPlacement.location:type_name -> Vector2
- 43, // 101: GameEvent.MultipleCards.by_team:type_name -> Team
- 43, // 102: GameEvent.MultipleFouls.by_team:type_name -> Team
- 1, // 103: GameEvent.MultipleFouls.caused_game_events:type_name -> GameEvent
- 43, // 104: GameEvent.MultiplePlacementFailures.by_team:type_name -> Team
- 43, // 105: GameEvent.KickTimeout.by_team:type_name -> Team
- 44, // 106: GameEvent.KickTimeout.location:type_name -> Vector2
- 44, // 107: GameEvent.NoProgressInGame.location:type_name -> Vector2
- 43, // 108: GameEvent.PlacementFailed.by_team:type_name -> Team
- 43, // 109: GameEvent.UnsportingBehaviorMinor.by_team:type_name -> Team
- 43, // 110: GameEvent.UnsportingBehaviorMajor.by_team:type_name -> Team
- 43, // 111: GameEvent.KeeperHeldBall.by_team:type_name -> Team
- 44, // 112: GameEvent.KeeperHeldBall.location:type_name -> Vector2
- 43, // 113: GameEvent.PlacementSucceeded.by_team:type_name -> Team
- 43, // 114: GameEvent.BotSubstitution.by_team:type_name -> Team
- 43, // 115: GameEvent.ExcessiveBotSubstitution.by_team:type_name -> Team
- 43, // 116: GameEvent.ChallengeFlag.by_team:type_name -> Team
- 43, // 117: GameEvent.ChallengeFlagHandled.by_team:type_name -> Team
- 43, // 118: GameEvent.EmergencyStop.by_team:type_name -> Team
- 43, // 119: GameEvent.TooManyRobots.by_team:type_name -> Team
- 44, // 120: GameEvent.TooManyRobots.ball_location:type_name -> Vector2
- 43, // 121: GameEvent.BoundaryCrossing.by_team:type_name -> Team
- 44, // 122: GameEvent.BoundaryCrossing.location:type_name -> Vector2
- 43, // 123: GameEvent.PenaltyKickFailed.by_team:type_name -> Team
- 44, // 124: GameEvent.PenaltyKickFailed.location:type_name -> Vector2
- 125, // [125:125] is the sub-list for method output_type
- 125, // [125:125] is the sub-list for method input_type
- 125, // [125:125] is the sub-list for extension type_name
- 125, // [125:125] is the sub-list for extension extendee
- 0, // [0:125] is the sub-list for field type_name
-}
-
-func init() { file_gamecontroller_ssl_gc_game_event_proto_init() }
-func file_gamecontroller_ssl_gc_game_event_proto_init() {
- if File_gamecontroller_ssl_gc_game_event_proto != nil {
- return
- }
- file_gamecontroller_ssl_gc_common_proto_init()
- file_gamecontroller_ssl_gc_geometry_proto_init()
- file_gamecontroller_ssl_gc_game_event_proto_msgTypes[0].OneofWrappers = []any{
- (*GameEvent_BallLeftFieldTouchLine)(nil),
- (*GameEvent_BallLeftFieldGoalLine)(nil),
- (*GameEvent_AimlessKick_)(nil),
- (*GameEvent_AttackerTooCloseToDefenseArea_)(nil),
- (*GameEvent_DefenderInDefenseArea_)(nil),
- (*GameEvent_BoundaryCrossing_)(nil),
- (*GameEvent_KeeperHeldBall_)(nil),
- (*GameEvent_BotDribbledBallTooFar_)(nil),
- (*GameEvent_BotPushedBot_)(nil),
- (*GameEvent_BotHeldBallDeliberately_)(nil),
- (*GameEvent_BotTippedOver_)(nil),
- (*GameEvent_BotDroppedParts_)(nil),
- (*GameEvent_AttackerTouchedBallInDefenseArea_)(nil),
- (*GameEvent_BotKickedBallTooFast_)(nil),
- (*GameEvent_BotCrashUnique_)(nil),
- (*GameEvent_BotCrashDrawn_)(nil),
- (*GameEvent_DefenderTooCloseToKickPoint_)(nil),
- (*GameEvent_BotTooFastInStop_)(nil),
- (*GameEvent_BotInterferedPlacement_)(nil),
- (*GameEvent_PossibleGoal)(nil),
- (*GameEvent_Goal_)(nil),
- (*GameEvent_InvalidGoal)(nil),
- (*GameEvent_AttackerDoubleTouchedBall_)(nil),
- (*GameEvent_PlacementSucceeded_)(nil),
- (*GameEvent_PenaltyKickFailed_)(nil),
- (*GameEvent_NoProgressInGame_)(nil),
- (*GameEvent_PlacementFailed_)(nil),
- (*GameEvent_MultipleCards_)(nil),
- (*GameEvent_MultipleFouls_)(nil),
- (*GameEvent_BotSubstitution_)(nil),
- (*GameEvent_ExcessiveBotSubstitution_)(nil),
- (*GameEvent_TooManyRobots_)(nil),
- (*GameEvent_ChallengeFlag_)(nil),
- (*GameEvent_ChallengeFlagHandled_)(nil),
- (*GameEvent_EmergencyStop_)(nil),
- (*GameEvent_UnsportingBehaviorMinor_)(nil),
- (*GameEvent_UnsportingBehaviorMajor_)(nil),
- (*GameEvent_Prepared_)(nil),
- (*GameEvent_IndirectGoal_)(nil),
- (*GameEvent_ChippedGoal_)(nil),
- (*GameEvent_KickTimeout_)(nil),
- (*GameEvent_AttackerTouchedOpponentInDefenseArea_)(nil),
- (*GameEvent_AttackerTouchedOpponentInDefenseAreaSkipped)(nil),
- (*GameEvent_BotCrashUniqueSkipped)(nil),
- (*GameEvent_BotPushedBotSkipped)(nil),
- (*GameEvent_DefenderInDefenseAreaPartially_)(nil),
- (*GameEvent_MultiplePlacementFailures_)(nil),
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_game_event_proto_rawDesc), len(file_gamecontroller_ssl_gc_game_event_proto_rawDesc)),
- NumEnums: 1,
- NumMessages: 42,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_gamecontroller_ssl_gc_game_event_proto_goTypes,
- DependencyIndexes: file_gamecontroller_ssl_gc_game_event_proto_depIdxs,
- EnumInfos: file_gamecontroller_ssl_gc_game_event_proto_enumTypes,
- MessageInfos: file_gamecontroller_ssl_gc_game_event_proto_msgTypes,
- }.Build()
- File_gamecontroller_ssl_gc_game_event_proto = out.File
- file_gamecontroller_ssl_gc_game_event_proto_goTypes = nil
- file_gamecontroller_ssl_gc_game_event_proto_depIdxs = nil
-}
diff --git a/gui/internal/gamecontroller/ssl_gc_geometry.pb.go b/gui/internal/gamecontroller/ssl_gc_geometry.pb.go
deleted file mode 100644
index b03a087..0000000
--- a/gui/internal/gamecontroller/ssl_gc_geometry.pb.go
+++ /dev/null
@@ -1,198 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.36.6
-// protoc (unknown)
-// source: gamecontroller/ssl_gc_geometry.proto
-
-package gamecontroller
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
- unsafe "unsafe"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-// A vector with two dimensions
-type Vector2 struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- X *float32 `protobuf:"fixed32,1,req,name=x" json:"x,omitempty"`
- Y *float32 `protobuf:"fixed32,2,req,name=y" json:"y,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *Vector2) Reset() {
- *x = Vector2{}
- mi := &file_gamecontroller_ssl_gc_geometry_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *Vector2) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*Vector2) ProtoMessage() {}
-
-func (x *Vector2) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_geometry_proto_msgTypes[0]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use Vector2.ProtoReflect.Descriptor instead.
-func (*Vector2) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_geometry_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *Vector2) GetX() float32 {
- if x != nil && x.X != nil {
- return *x.X
- }
- return 0
-}
-
-func (x *Vector2) GetY() float32 {
- if x != nil && x.Y != nil {
- return *x.Y
- }
- return 0
-}
-
-// A vector with three dimensions
-type Vector3 struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- X *float32 `protobuf:"fixed32,1,req,name=x" json:"x,omitempty"`
- Y *float32 `protobuf:"fixed32,2,req,name=y" json:"y,omitempty"`
- Z *float32 `protobuf:"fixed32,3,req,name=z" json:"z,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *Vector3) Reset() {
- *x = Vector3{}
- mi := &file_gamecontroller_ssl_gc_geometry_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *Vector3) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*Vector3) ProtoMessage() {}
-
-func (x *Vector3) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_geometry_proto_msgTypes[1]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use Vector3.ProtoReflect.Descriptor instead.
-func (*Vector3) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_geometry_proto_rawDescGZIP(), []int{1}
-}
-
-func (x *Vector3) GetX() float32 {
- if x != nil && x.X != nil {
- return *x.X
- }
- return 0
-}
-
-func (x *Vector3) GetY() float32 {
- if x != nil && x.Y != nil {
- return *x.Y
- }
- return 0
-}
-
-func (x *Vector3) GetZ() float32 {
- if x != nil && x.Z != nil {
- return *x.Z
- }
- return 0
-}
-
-var File_gamecontroller_ssl_gc_geometry_proto protoreflect.FileDescriptor
-
-const file_gamecontroller_ssl_gc_geometry_proto_rawDesc = "" +
- "\n" +
- "$gamecontroller/ssl_gc_geometry.proto\"%\n" +
- "\aVector2\x12\f\n" +
- "\x01x\x18\x01 \x02(\x02R\x01x\x12\f\n" +
- "\x01y\x18\x02 \x02(\x02R\x01y\"3\n" +
- "\aVector3\x12\f\n" +
- "\x01x\x18\x01 \x02(\x02R\x01x\x12\f\n" +
- "\x01y\x18\x02 \x02(\x02R\x01y\x12\f\n" +
- "\x01z\x18\x03 \x02(\x02R\x01zB_B\x12SslGcGeometryProtoP\x01ZGgithub.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
-
-var (
- file_gamecontroller_ssl_gc_geometry_proto_rawDescOnce sync.Once
- file_gamecontroller_ssl_gc_geometry_proto_rawDescData []byte
-)
-
-func file_gamecontroller_ssl_gc_geometry_proto_rawDescGZIP() []byte {
- file_gamecontroller_ssl_gc_geometry_proto_rawDescOnce.Do(func() {
- file_gamecontroller_ssl_gc_geometry_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_geometry_proto_rawDesc), len(file_gamecontroller_ssl_gc_geometry_proto_rawDesc)))
- })
- return file_gamecontroller_ssl_gc_geometry_proto_rawDescData
-}
-
-var file_gamecontroller_ssl_gc_geometry_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
-var file_gamecontroller_ssl_gc_geometry_proto_goTypes = []any{
- (*Vector2)(nil), // 0: Vector2
- (*Vector3)(nil), // 1: Vector3
-}
-var file_gamecontroller_ssl_gc_geometry_proto_depIdxs = []int32{
- 0, // [0:0] is the sub-list for method output_type
- 0, // [0:0] is the sub-list for method input_type
- 0, // [0:0] is the sub-list for extension type_name
- 0, // [0:0] is the sub-list for extension extendee
- 0, // [0:0] is the sub-list for field type_name
-}
-
-func init() { file_gamecontroller_ssl_gc_geometry_proto_init() }
-func file_gamecontroller_ssl_gc_geometry_proto_init() {
- if File_gamecontroller_ssl_gc_geometry_proto != nil {
- return
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_geometry_proto_rawDesc), len(file_gamecontroller_ssl_gc_geometry_proto_rawDesc)),
- NumEnums: 0,
- NumMessages: 2,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_gamecontroller_ssl_gc_geometry_proto_goTypes,
- DependencyIndexes: file_gamecontroller_ssl_gc_geometry_proto_depIdxs,
- MessageInfos: file_gamecontroller_ssl_gc_geometry_proto_msgTypes,
- }.Build()
- File_gamecontroller_ssl_gc_geometry_proto = out.File
- file_gamecontroller_ssl_gc_geometry_proto_goTypes = nil
- file_gamecontroller_ssl_gc_geometry_proto_depIdxs = nil
-}
diff --git a/gui/internal/gamecontroller/ssl_gc_rcon.pb.go b/gui/internal/gamecontroller/ssl_gc_rcon.pb.go
deleted file mode 100644
index 4db9744..0000000
--- a/gui/internal/gamecontroller/ssl_gc_rcon.pb.go
+++ /dev/null
@@ -1,352 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.36.6
-// protoc (unknown)
-// source: gamecontroller/ssl_gc_rcon.proto
-
-package gamecontroller
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
- unsafe "unsafe"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-type ControllerReply_StatusCode int32
-
-const (
- ControllerReply_UNKNOWN_STATUS_CODE ControllerReply_StatusCode = 0
- ControllerReply_OK ControllerReply_StatusCode = 1
- ControllerReply_REJECTED ControllerReply_StatusCode = 2
-)
-
-// Enum value maps for ControllerReply_StatusCode.
-var (
- ControllerReply_StatusCode_name = map[int32]string{
- 0: "UNKNOWN_STATUS_CODE",
- 1: "OK",
- 2: "REJECTED",
- }
- ControllerReply_StatusCode_value = map[string]int32{
- "UNKNOWN_STATUS_CODE": 0,
- "OK": 1,
- "REJECTED": 2,
- }
-)
-
-func (x ControllerReply_StatusCode) Enum() *ControllerReply_StatusCode {
- p := new(ControllerReply_StatusCode)
- *p = x
- return p
-}
-
-func (x ControllerReply_StatusCode) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (ControllerReply_StatusCode) Descriptor() protoreflect.EnumDescriptor {
- return file_gamecontroller_ssl_gc_rcon_proto_enumTypes[0].Descriptor()
-}
-
-func (ControllerReply_StatusCode) Type() protoreflect.EnumType {
- return &file_gamecontroller_ssl_gc_rcon_proto_enumTypes[0]
-}
-
-func (x ControllerReply_StatusCode) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Do not use.
-func (x *ControllerReply_StatusCode) UnmarshalJSON(b []byte) error {
- num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
- if err != nil {
- return err
- }
- *x = ControllerReply_StatusCode(num)
- return nil
-}
-
-// Deprecated: Use ControllerReply_StatusCode.Descriptor instead.
-func (ControllerReply_StatusCode) EnumDescriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_rcon_proto_rawDescGZIP(), []int{0, 0}
-}
-
-type ControllerReply_Verification int32
-
-const (
- ControllerReply_UNKNOWN_VERIFICATION ControllerReply_Verification = 0
- ControllerReply_VERIFIED ControllerReply_Verification = 1
- ControllerReply_UNVERIFIED ControllerReply_Verification = 2
-)
-
-// Enum value maps for ControllerReply_Verification.
-var (
- ControllerReply_Verification_name = map[int32]string{
- 0: "UNKNOWN_VERIFICATION",
- 1: "VERIFIED",
- 2: "UNVERIFIED",
- }
- ControllerReply_Verification_value = map[string]int32{
- "UNKNOWN_VERIFICATION": 0,
- "VERIFIED": 1,
- "UNVERIFIED": 2,
- }
-)
-
-func (x ControllerReply_Verification) Enum() *ControllerReply_Verification {
- p := new(ControllerReply_Verification)
- *p = x
- return p
-}
-
-func (x ControllerReply_Verification) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (ControllerReply_Verification) Descriptor() protoreflect.EnumDescriptor {
- return file_gamecontroller_ssl_gc_rcon_proto_enumTypes[1].Descriptor()
-}
-
-func (ControllerReply_Verification) Type() protoreflect.EnumType {
- return &file_gamecontroller_ssl_gc_rcon_proto_enumTypes[1]
-}
-
-func (x ControllerReply_Verification) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Do not use.
-func (x *ControllerReply_Verification) UnmarshalJSON(b []byte) error {
- num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
- if err != nil {
- return err
- }
- *x = ControllerReply_Verification(num)
- return nil
-}
-
-// Deprecated: Use ControllerReply_Verification.Descriptor instead.
-func (ControllerReply_Verification) EnumDescriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_rcon_proto_rawDescGZIP(), []int{0, 1}
-}
-
-// a reply that is sent by the controller for each request from teams or autoRefs
-type ControllerReply struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // status_code is an optional code that indicates the result of the last request
- StatusCode *ControllerReply_StatusCode `protobuf:"varint,1,opt,name=status_code,json=statusCode,enum=ControllerReply_StatusCode" json:"status_code,omitempty"`
- // reason is an optional explanation of the status code
- Reason *string `protobuf:"bytes,2,opt,name=reason" json:"reason,omitempty"`
- // next_token must be send with the next request, if secure communication is used
- // the token is used to avoid replay attacks
- // the token is always present in the very first message before the registration starts
- // the token is not present, if secure communication is not used
- NextToken *string `protobuf:"bytes,3,opt,name=next_token,json=nextToken" json:"next_token,omitempty"`
- // verification indicates if the last request could be verified (secure communication)
- Verification *ControllerReply_Verification `protobuf:"varint,4,opt,name=verification,enum=ControllerReply_Verification" json:"verification,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *ControllerReply) Reset() {
- *x = ControllerReply{}
- mi := &file_gamecontroller_ssl_gc_rcon_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *ControllerReply) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*ControllerReply) ProtoMessage() {}
-
-func (x *ControllerReply) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_rcon_proto_msgTypes[0]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use ControllerReply.ProtoReflect.Descriptor instead.
-func (*ControllerReply) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_rcon_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *ControllerReply) GetStatusCode() ControllerReply_StatusCode {
- if x != nil && x.StatusCode != nil {
- return *x.StatusCode
- }
- return ControllerReply_UNKNOWN_STATUS_CODE
-}
-
-func (x *ControllerReply) GetReason() string {
- if x != nil && x.Reason != nil {
- return *x.Reason
- }
- return ""
-}
-
-func (x *ControllerReply) GetNextToken() string {
- if x != nil && x.NextToken != nil {
- return *x.NextToken
- }
- return ""
-}
-
-func (x *ControllerReply) GetVerification() ControllerReply_Verification {
- if x != nil && x.Verification != nil {
- return *x.Verification
- }
- return ControllerReply_UNKNOWN_VERIFICATION
-}
-
-// Signature can be added to a request to let it be verfied by the controller
-type Signature struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the token that was received with the last controller reply
- Token *string `protobuf:"bytes,1,req,name=token" json:"token,omitempty"`
- // the PKCS1v15 signature of this message
- Pkcs1V15 []byte `protobuf:"bytes,2,req,name=pkcs1v15" json:"pkcs1v15,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *Signature) Reset() {
- *x = Signature{}
- mi := &file_gamecontroller_ssl_gc_rcon_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *Signature) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*Signature) ProtoMessage() {}
-
-func (x *Signature) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_rcon_proto_msgTypes[1]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use Signature.ProtoReflect.Descriptor instead.
-func (*Signature) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_rcon_proto_rawDescGZIP(), []int{1}
-}
-
-func (x *Signature) GetToken() string {
- if x != nil && x.Token != nil {
- return *x.Token
- }
- return ""
-}
-
-func (x *Signature) GetPkcs1V15() []byte {
- if x != nil {
- return x.Pkcs1V15
- }
- return nil
-}
-
-var File_gamecontroller_ssl_gc_rcon_proto protoreflect.FileDescriptor
-
-const file_gamecontroller_ssl_gc_rcon_proto_rawDesc = "" +
- "\n" +
- " gamecontroller/ssl_gc_rcon.proto\"\xce\x02\n" +
- "\x0fControllerReply\x12<\n" +
- "\vstatus_code\x18\x01 \x01(\x0e2\x1b.ControllerReply.StatusCodeR\n" +
- "statusCode\x12\x16\n" +
- "\x06reason\x18\x02 \x01(\tR\x06reason\x12\x1d\n" +
- "\n" +
- "next_token\x18\x03 \x01(\tR\tnextToken\x12A\n" +
- "\fverification\x18\x04 \x01(\x0e2\x1d.ControllerReply.VerificationR\fverification\";\n" +
- "\n" +
- "StatusCode\x12\x17\n" +
- "\x13UNKNOWN_STATUS_CODE\x10\x00\x12\x06\n" +
- "\x02OK\x10\x01\x12\f\n" +
- "\bREJECTED\x10\x02\"F\n" +
- "\fVerification\x12\x18\n" +
- "\x14UNKNOWN_VERIFICATION\x10\x00\x12\f\n" +
- "\bVERIFIED\x10\x01\x12\x0e\n" +
- "\n" +
- "UNVERIFIED\x10\x02\"=\n" +
- "\tSignature\x12\x14\n" +
- "\x05token\x18\x01 \x02(\tR\x05token\x12\x1a\n" +
- "\bpkcs1v15\x18\x02 \x02(\fR\bpkcs1v15B[B\x0eSslGcRconProtoP\x01ZGgithub.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
-
-var (
- file_gamecontroller_ssl_gc_rcon_proto_rawDescOnce sync.Once
- file_gamecontroller_ssl_gc_rcon_proto_rawDescData []byte
-)
-
-func file_gamecontroller_ssl_gc_rcon_proto_rawDescGZIP() []byte {
- file_gamecontroller_ssl_gc_rcon_proto_rawDescOnce.Do(func() {
- file_gamecontroller_ssl_gc_rcon_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_rcon_proto_rawDesc), len(file_gamecontroller_ssl_gc_rcon_proto_rawDesc)))
- })
- return file_gamecontroller_ssl_gc_rcon_proto_rawDescData
-}
-
-var file_gamecontroller_ssl_gc_rcon_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
-var file_gamecontroller_ssl_gc_rcon_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
-var file_gamecontroller_ssl_gc_rcon_proto_goTypes = []any{
- (ControllerReply_StatusCode)(0), // 0: ControllerReply.StatusCode
- (ControllerReply_Verification)(0), // 1: ControllerReply.Verification
- (*ControllerReply)(nil), // 2: ControllerReply
- (*Signature)(nil), // 3: Signature
-}
-var file_gamecontroller_ssl_gc_rcon_proto_depIdxs = []int32{
- 0, // 0: ControllerReply.status_code:type_name -> ControllerReply.StatusCode
- 1, // 1: ControllerReply.verification:type_name -> ControllerReply.Verification
- 2, // [2:2] is the sub-list for method output_type
- 2, // [2:2] is the sub-list for method input_type
- 2, // [2:2] is the sub-list for extension type_name
- 2, // [2:2] is the sub-list for extension extendee
- 0, // [0:2] is the sub-list for field type_name
-}
-
-func init() { file_gamecontroller_ssl_gc_rcon_proto_init() }
-func file_gamecontroller_ssl_gc_rcon_proto_init() {
- if File_gamecontroller_ssl_gc_rcon_proto != nil {
- return
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_rcon_proto_rawDesc), len(file_gamecontroller_ssl_gc_rcon_proto_rawDesc)),
- NumEnums: 2,
- NumMessages: 2,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_gamecontroller_ssl_gc_rcon_proto_goTypes,
- DependencyIndexes: file_gamecontroller_ssl_gc_rcon_proto_depIdxs,
- EnumInfos: file_gamecontroller_ssl_gc_rcon_proto_enumTypes,
- MessageInfos: file_gamecontroller_ssl_gc_rcon_proto_msgTypes,
- }.Build()
- File_gamecontroller_ssl_gc_rcon_proto = out.File
- file_gamecontroller_ssl_gc_rcon_proto_goTypes = nil
- file_gamecontroller_ssl_gc_rcon_proto_depIdxs = nil
-}
diff --git a/gui/internal/gamecontroller/ssl_gc_rcon_autoref.pb.go b/gui/internal/gamecontroller/ssl_gc_rcon_autoref.pb.go
deleted file mode 100644
index 8a0ed95..0000000
--- a/gui/internal/gamecontroller/ssl_gc_rcon_autoref.pb.go
+++ /dev/null
@@ -1,283 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.36.6
-// protoc (unknown)
-// source: gamecontroller/ssl_gc_rcon_autoref.proto
-
-package gamecontroller
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
- unsafe "unsafe"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-// AutoRefRegistration is the first message that a client must send to the controller to identify itself
-type AutoRefRegistration struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // identifier is a unique name of the client
- Identifier *string `protobuf:"bytes,1,req,name=identifier" json:"identifier,omitempty"`
- // signature can optionally be specified to enable secure communication
- Signature *Signature `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *AutoRefRegistration) Reset() {
- *x = AutoRefRegistration{}
- mi := &file_gamecontroller_ssl_gc_rcon_autoref_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *AutoRefRegistration) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*AutoRefRegistration) ProtoMessage() {}
-
-func (x *AutoRefRegistration) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_rcon_autoref_proto_msgTypes[0]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use AutoRefRegistration.ProtoReflect.Descriptor instead.
-func (*AutoRefRegistration) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *AutoRefRegistration) GetIdentifier() string {
- if x != nil && x.Identifier != nil {
- return *x.Identifier
- }
- return ""
-}
-
-func (x *AutoRefRegistration) GetSignature() *Signature {
- if x != nil {
- return x.Signature
- }
- return nil
-}
-
-// AutoRefToController is the wrapper message for all subsequent messages from the autoRef to the controller
-type AutoRefToController struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // signature can optionally be specified to enable secure communication
- Signature *Signature `protobuf:"bytes,1,opt,name=signature" json:"signature,omitempty"`
- // game_event is an optional event that the autoRef detected during the game
- GameEvent *GameEvent `protobuf:"bytes,2,opt,name=game_event,json=gameEvent" json:"game_event,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *AutoRefToController) Reset() {
- *x = AutoRefToController{}
- mi := &file_gamecontroller_ssl_gc_rcon_autoref_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *AutoRefToController) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*AutoRefToController) ProtoMessage() {}
-
-func (x *AutoRefToController) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_rcon_autoref_proto_msgTypes[1]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use AutoRefToController.ProtoReflect.Descriptor instead.
-func (*AutoRefToController) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDescGZIP(), []int{1}
-}
-
-func (x *AutoRefToController) GetSignature() *Signature {
- if x != nil {
- return x.Signature
- }
- return nil
-}
-
-func (x *AutoRefToController) GetGameEvent() *GameEvent {
- if x != nil {
- return x.GameEvent
- }
- return nil
-}
-
-// ControllerToAutoRef is the wrapper message for all messages from controller to autoRef
-type ControllerToAutoRef struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // Types that are valid to be assigned to Msg:
- //
- // *ControllerToAutoRef_ControllerReply
- Msg isControllerToAutoRef_Msg `protobuf_oneof:"msg"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *ControllerToAutoRef) Reset() {
- *x = ControllerToAutoRef{}
- mi := &file_gamecontroller_ssl_gc_rcon_autoref_proto_msgTypes[2]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *ControllerToAutoRef) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*ControllerToAutoRef) ProtoMessage() {}
-
-func (x *ControllerToAutoRef) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_rcon_autoref_proto_msgTypes[2]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use ControllerToAutoRef.ProtoReflect.Descriptor instead.
-func (*ControllerToAutoRef) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDescGZIP(), []int{2}
-}
-
-func (x *ControllerToAutoRef) GetMsg() isControllerToAutoRef_Msg {
- if x != nil {
- return x.Msg
- }
- return nil
-}
-
-func (x *ControllerToAutoRef) GetControllerReply() *ControllerReply {
- if x != nil {
- if x, ok := x.Msg.(*ControllerToAutoRef_ControllerReply); ok {
- return x.ControllerReply
- }
- }
- return nil
-}
-
-type isControllerToAutoRef_Msg interface {
- isControllerToAutoRef_Msg()
-}
-
-type ControllerToAutoRef_ControllerReply struct {
- // a reply from the controller
- ControllerReply *ControllerReply `protobuf:"bytes,1,opt,name=controller_reply,json=controllerReply,oneof"`
-}
-
-func (*ControllerToAutoRef_ControllerReply) isControllerToAutoRef_Msg() {}
-
-var File_gamecontroller_ssl_gc_rcon_autoref_proto protoreflect.FileDescriptor
-
-const file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDesc = "" +
- "\n" +
- "(gamecontroller/ssl_gc_rcon_autoref.proto\x1a&gamecontroller/ssl_gc_game_event.proto\x1a gamecontroller/ssl_gc_rcon.proto\"_\n" +
- "\x13AutoRefRegistration\x12\x1e\n" +
- "\n" +
- "identifier\x18\x01 \x02(\tR\n" +
- "identifier\x12(\n" +
- "\tsignature\x18\x02 \x01(\v2\n" +
- ".SignatureR\tsignature\"v\n" +
- "\x13AutoRefToController\x12(\n" +
- "\tsignature\x18\x01 \x01(\v2\n" +
- ".SignatureR\tsignature\x12)\n" +
- "\n" +
- "game_event\x18\x02 \x01(\v2\n" +
- ".GameEventR\tgameEventJ\x04\b\x03\x10\x04J\x04\b\x04\x10\x05\"[\n" +
- "\x13ControllerToAutoRef\x12=\n" +
- "\x10controller_reply\x18\x01 \x01(\v2\x10.ControllerReplyH\x00R\x0fcontrollerReplyB\x05\n" +
- "\x03msgBbB\x15SslGcRconAutorefProtoP\x01ZGgithub.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
-
-var (
- file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDescOnce sync.Once
- file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDescData []byte
-)
-
-func file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDescGZIP() []byte {
- file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDescOnce.Do(func() {
- file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDesc), len(file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDesc)))
- })
- return file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDescData
-}
-
-var file_gamecontroller_ssl_gc_rcon_autoref_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
-var file_gamecontroller_ssl_gc_rcon_autoref_proto_goTypes = []any{
- (*AutoRefRegistration)(nil), // 0: AutoRefRegistration
- (*AutoRefToController)(nil), // 1: AutoRefToController
- (*ControllerToAutoRef)(nil), // 2: ControllerToAutoRef
- (*Signature)(nil), // 3: Signature
- (*GameEvent)(nil), // 4: GameEvent
- (*ControllerReply)(nil), // 5: ControllerReply
-}
-var file_gamecontroller_ssl_gc_rcon_autoref_proto_depIdxs = []int32{
- 3, // 0: AutoRefRegistration.signature:type_name -> Signature
- 3, // 1: AutoRefToController.signature:type_name -> Signature
- 4, // 2: AutoRefToController.game_event:type_name -> GameEvent
- 5, // 3: ControllerToAutoRef.controller_reply:type_name -> ControllerReply
- 4, // [4:4] is the sub-list for method output_type
- 4, // [4:4] is the sub-list for method input_type
- 4, // [4:4] is the sub-list for extension type_name
- 4, // [4:4] is the sub-list for extension extendee
- 0, // [0:4] is the sub-list for field type_name
-}
-
-func init() { file_gamecontroller_ssl_gc_rcon_autoref_proto_init() }
-func file_gamecontroller_ssl_gc_rcon_autoref_proto_init() {
- if File_gamecontroller_ssl_gc_rcon_autoref_proto != nil {
- return
- }
- file_gamecontroller_ssl_gc_game_event_proto_init()
- file_gamecontroller_ssl_gc_rcon_proto_init()
- file_gamecontroller_ssl_gc_rcon_autoref_proto_msgTypes[2].OneofWrappers = []any{
- (*ControllerToAutoRef_ControllerReply)(nil),
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDesc), len(file_gamecontroller_ssl_gc_rcon_autoref_proto_rawDesc)),
- NumEnums: 0,
- NumMessages: 3,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_gamecontroller_ssl_gc_rcon_autoref_proto_goTypes,
- DependencyIndexes: file_gamecontroller_ssl_gc_rcon_autoref_proto_depIdxs,
- MessageInfos: file_gamecontroller_ssl_gc_rcon_autoref_proto_msgTypes,
- }.Build()
- File_gamecontroller_ssl_gc_rcon_autoref_proto = out.File
- file_gamecontroller_ssl_gc_rcon_autoref_proto_goTypes = nil
- file_gamecontroller_ssl_gc_rcon_autoref_proto_depIdxs = nil
-}
diff --git a/gui/internal/gamecontroller/ssl_gc_rcon_remotecontrol.pb.go b/gui/internal/gamecontroller/ssl_gc_rcon_remotecontrol.pb.go
deleted file mode 100644
index 9d7a3ff..0000000
--- a/gui/internal/gamecontroller/ssl_gc_rcon_remotecontrol.pb.go
+++ /dev/null
@@ -1,718 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.36.6
-// protoc (unknown)
-// source: gamecontroller/ssl_gc_rcon_remotecontrol.proto
-
-package gamecontroller
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
- unsafe "unsafe"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-// All possible request types that the remote control can make
-type RemoteControlRequestType int32
-
-const (
- RemoteControlRequestType_UNKNOWN_REQUEST_TYPE RemoteControlRequestType = 0
- RemoteControlRequestType_EMERGENCY_STOP RemoteControlRequestType = 1
- RemoteControlRequestType_ROBOT_SUBSTITUTION RemoteControlRequestType = 2
- RemoteControlRequestType_TIMEOUT RemoteControlRequestType = 3
- RemoteControlRequestType_CHALLENGE_FLAG RemoteControlRequestType = 4
- RemoteControlRequestType_CHANGE_KEEPER_ID RemoteControlRequestType = 5
- RemoteControlRequestType_STOP_TIMEOUT RemoteControlRequestType = 6
- RemoteControlRequestType_FAIL_BALLPLACEMENT RemoteControlRequestType = 7
-)
-
-// Enum value maps for RemoteControlRequestType.
-var (
- RemoteControlRequestType_name = map[int32]string{
- 0: "UNKNOWN_REQUEST_TYPE",
- 1: "EMERGENCY_STOP",
- 2: "ROBOT_SUBSTITUTION",
- 3: "TIMEOUT",
- 4: "CHALLENGE_FLAG",
- 5: "CHANGE_KEEPER_ID",
- 6: "STOP_TIMEOUT",
- 7: "FAIL_BALLPLACEMENT",
- }
- RemoteControlRequestType_value = map[string]int32{
- "UNKNOWN_REQUEST_TYPE": 0,
- "EMERGENCY_STOP": 1,
- "ROBOT_SUBSTITUTION": 2,
- "TIMEOUT": 3,
- "CHALLENGE_FLAG": 4,
- "CHANGE_KEEPER_ID": 5,
- "STOP_TIMEOUT": 6,
- "FAIL_BALLPLACEMENT": 7,
- }
-)
-
-func (x RemoteControlRequestType) Enum() *RemoteControlRequestType {
- p := new(RemoteControlRequestType)
- *p = x
- return p
-}
-
-func (x RemoteControlRequestType) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (RemoteControlRequestType) Descriptor() protoreflect.EnumDescriptor {
- return file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_enumTypes[0].Descriptor()
-}
-
-func (RemoteControlRequestType) Type() protoreflect.EnumType {
- return &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_enumTypes[0]
-}
-
-func (x RemoteControlRequestType) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Do not use.
-func (x *RemoteControlRequestType) UnmarshalJSON(b []byte) error {
- num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
- if err != nil {
- return err
- }
- *x = RemoteControlRequestType(num)
- return nil
-}
-
-// Deprecated: Use RemoteControlRequestType.Descriptor instead.
-func (RemoteControlRequestType) EnumDescriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescGZIP(), []int{0}
-}
-
-type RemoteControlToController_Request int32
-
-const (
- RemoteControlToController_UNKNOWN RemoteControlToController_Request = 0
- // Ping the GC to test the connection. The GC will respond with OK and the current team state
- RemoteControlToController_PING RemoteControlToController_Request = 1
- // Raise a challenge flag (this is not revocable)
- RemoteControlToController_CHALLENGE_FLAG RemoteControlToController_Request = 2
- // Stop an ongoing timeout
- RemoteControlToController_STOP_TIMEOUT RemoteControlToController_Request = 3
- // Fail a ball placement
- RemoteControlToController_FAIL_BALLPLACEMENT RemoteControlToController_Request = 4
-)
-
-// Enum value maps for RemoteControlToController_Request.
-var (
- RemoteControlToController_Request_name = map[int32]string{
- 0: "UNKNOWN",
- 1: "PING",
- 2: "CHALLENGE_FLAG",
- 3: "STOP_TIMEOUT",
- 4: "FAIL_BALLPLACEMENT",
- }
- RemoteControlToController_Request_value = map[string]int32{
- "UNKNOWN": 0,
- "PING": 1,
- "CHALLENGE_FLAG": 2,
- "STOP_TIMEOUT": 3,
- "FAIL_BALLPLACEMENT": 4,
- }
-)
-
-func (x RemoteControlToController_Request) Enum() *RemoteControlToController_Request {
- p := new(RemoteControlToController_Request)
- *p = x
- return p
-}
-
-func (x RemoteControlToController_Request) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (RemoteControlToController_Request) Descriptor() protoreflect.EnumDescriptor {
- return file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_enumTypes[1].Descriptor()
-}
-
-func (RemoteControlToController_Request) Type() protoreflect.EnumType {
- return &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_enumTypes[1]
-}
-
-func (x RemoteControlToController_Request) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Do not use.
-func (x *RemoteControlToController_Request) UnmarshalJSON(b []byte) error {
- num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
- if err != nil {
- return err
- }
- *x = RemoteControlToController_Request(num)
- return nil
-}
-
-// Deprecated: Use RemoteControlToController_Request.Descriptor instead.
-func (RemoteControlToController_Request) EnumDescriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescGZIP(), []int{1, 0}
-}
-
-// a registration that must be send by the remote control to the controller as the very first message
-type RemoteControlRegistration struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team to be controlled
- Team *Team `protobuf:"varint,1,req,name=team,enum=Team" json:"team,omitempty"`
- // signature can optionally be specified to enable secure communication
- Signature *Signature `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *RemoteControlRegistration) Reset() {
- *x = RemoteControlRegistration{}
- mi := &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *RemoteControlRegistration) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*RemoteControlRegistration) ProtoMessage() {}
-
-func (x *RemoteControlRegistration) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes[0]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use RemoteControlRegistration.ProtoReflect.Descriptor instead.
-func (*RemoteControlRegistration) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *RemoteControlRegistration) GetTeam() Team {
- if x != nil && x.Team != nil {
- return *x.Team
- }
- return Team_UNKNOWN
-}
-
-func (x *RemoteControlRegistration) GetSignature() *Signature {
- if x != nil {
- return x.Signature
- }
- return nil
-}
-
-// wrapper for all messages from the remote control to the controller
-type RemoteControlToController struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // signature can optionally be specified to enable secure communication
- Signature *Signature `protobuf:"bytes,1,opt,name=signature" json:"signature,omitempty"`
- // Types that are valid to be assigned to Msg:
- //
- // *RemoteControlToController_Request_
- // *RemoteControlToController_DesiredKeeper
- // *RemoteControlToController_RequestRobotSubstitution
- // *RemoteControlToController_RequestTimeout
- // *RemoteControlToController_RequestEmergencyStop
- Msg isRemoteControlToController_Msg `protobuf_oneof:"msg"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *RemoteControlToController) Reset() {
- *x = RemoteControlToController{}
- mi := &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *RemoteControlToController) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*RemoteControlToController) ProtoMessage() {}
-
-func (x *RemoteControlToController) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes[1]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use RemoteControlToController.ProtoReflect.Descriptor instead.
-func (*RemoteControlToController) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescGZIP(), []int{1}
-}
-
-func (x *RemoteControlToController) GetSignature() *Signature {
- if x != nil {
- return x.Signature
- }
- return nil
-}
-
-func (x *RemoteControlToController) GetMsg() isRemoteControlToController_Msg {
- if x != nil {
- return x.Msg
- }
- return nil
-}
-
-func (x *RemoteControlToController) GetRequest() RemoteControlToController_Request {
- if x != nil {
- if x, ok := x.Msg.(*RemoteControlToController_Request_); ok {
- return x.Request
- }
- }
- return RemoteControlToController_UNKNOWN
-}
-
-func (x *RemoteControlToController) GetDesiredKeeper() int32 {
- if x != nil {
- if x, ok := x.Msg.(*RemoteControlToController_DesiredKeeper); ok {
- return x.DesiredKeeper
- }
- }
- return 0
-}
-
-func (x *RemoteControlToController) GetRequestRobotSubstitution() bool {
- if x != nil {
- if x, ok := x.Msg.(*RemoteControlToController_RequestRobotSubstitution); ok {
- return x.RequestRobotSubstitution
- }
- }
- return false
-}
-
-func (x *RemoteControlToController) GetRequestTimeout() bool {
- if x != nil {
- if x, ok := x.Msg.(*RemoteControlToController_RequestTimeout); ok {
- return x.RequestTimeout
- }
- }
- return false
-}
-
-func (x *RemoteControlToController) GetRequestEmergencyStop() bool {
- if x != nil {
- if x, ok := x.Msg.(*RemoteControlToController_RequestEmergencyStop); ok {
- return x.RequestEmergencyStop
- }
- }
- return false
-}
-
-type isRemoteControlToController_Msg interface {
- isRemoteControlToController_Msg()
-}
-
-type RemoteControlToController_Request_ struct {
- // send a request to the GC
- Request RemoteControlToController_Request `protobuf:"varint,2,opt,name=request,enum=RemoteControlToController_Request,oneof"`
-}
-
-type RemoteControlToController_DesiredKeeper struct {
- // request a new desired keeper id
- DesiredKeeper int32 `protobuf:"varint,3,opt,name=desired_keeper,json=desiredKeeper,oneof"`
-}
-
-type RemoteControlToController_RequestRobotSubstitution struct {
- // true: request to substitute a robot at the next possibility
- // false: cancel request
- RequestRobotSubstitution bool `protobuf:"varint,4,opt,name=request_robot_substitution,json=requestRobotSubstitution,oneof"`
-}
-
-type RemoteControlToController_RequestTimeout struct {
- // true: request a timeout with the next stoppage
- // false: cancel the request
- RequestTimeout bool `protobuf:"varint,5,opt,name=request_timeout,json=requestTimeout,oneof"`
-}
-
-type RemoteControlToController_RequestEmergencyStop struct {
- // true: initiate an emergency stop
- // false: cancel the request
- RequestEmergencyStop bool `protobuf:"varint,6,opt,name=request_emergency_stop,json=requestEmergencyStop,oneof"`
-}
-
-func (*RemoteControlToController_Request_) isRemoteControlToController_Msg() {}
-
-func (*RemoteControlToController_DesiredKeeper) isRemoteControlToController_Msg() {}
-
-func (*RemoteControlToController_RequestRobotSubstitution) isRemoteControlToController_Msg() {}
-
-func (*RemoteControlToController_RequestTimeout) isRemoteControlToController_Msg() {}
-
-func (*RemoteControlToController_RequestEmergencyStop) isRemoteControlToController_Msg() {}
-
-// wrapper for all messages from controller to a team's computer
-type ControllerToRemoteControl struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // a reply from the controller
- ControllerReply *ControllerReply `protobuf:"bytes,1,opt,name=controller_reply,json=controllerReply" json:"controller_reply,omitempty"`
- // current team state
- State *RemoteControlTeamState `protobuf:"bytes,2,opt,name=state" json:"state,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *ControllerToRemoteControl) Reset() {
- *x = ControllerToRemoteControl{}
- mi := &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes[2]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *ControllerToRemoteControl) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*ControllerToRemoteControl) ProtoMessage() {}
-
-func (x *ControllerToRemoteControl) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes[2]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use ControllerToRemoteControl.ProtoReflect.Descriptor instead.
-func (*ControllerToRemoteControl) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescGZIP(), []int{2}
-}
-
-func (x *ControllerToRemoteControl) GetControllerReply() *ControllerReply {
- if x != nil {
- return x.ControllerReply
- }
- return nil
-}
-
-func (x *ControllerToRemoteControl) GetState() *RemoteControlTeamState {
- if x != nil {
- return x.State
- }
- return nil
-}
-
-// Current team state from Controller for remote control
-type RemoteControlTeamState struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the team that is controlled
- Team *Team `protobuf:"varint,12,opt,name=team,enum=Team" json:"team,omitempty"`
- // list of all currently available request types that can be made
- AvailableRequests []RemoteControlRequestType `protobuf:"varint,1,rep,name=available_requests,json=availableRequests,enum=RemoteControlRequestType" json:"available_requests,omitempty"`
- // list of all currently active request types that are pending
- ActiveRequests []RemoteControlRequestType `protobuf:"varint,2,rep,name=active_requests,json=activeRequests,enum=RemoteControlRequestType" json:"active_requests,omitempty"`
- // currently set keeper id
- KeeperId *int32 `protobuf:"varint,3,opt,name=keeper_id,json=keeperId" json:"keeper_id,omitempty"`
- // number of seconds till emergency stop is executed
- // zero, if no emergency stop requested
- EmergencyStopIn *float32 `protobuf:"fixed32,4,opt,name=emergency_stop_in,json=emergencyStopIn" json:"emergency_stop_in,omitempty"`
- // number of timeouts left for the team
- TimeoutsLeft *int32 `protobuf:"varint,5,opt,name=timeouts_left,json=timeoutsLeft" json:"timeouts_left,omitempty"`
- // number of seconds left for timeout for the team
- TimeoutTimeLeft *float32 `protobuf:"fixed32,10,opt,name=timeout_time_left,json=timeoutTimeLeft" json:"timeout_time_left,omitempty"`
- // number of challenge flags left for the team
- ChallengeFlagsLeft *int32 `protobuf:"varint,6,opt,name=challenge_flags_left,json=challengeFlagsLeft" json:"challenge_flags_left,omitempty"`
- // max number of robots currently allowed
- MaxRobots *int32 `protobuf:"varint,7,opt,name=max_robots,json=maxRobots" json:"max_robots,omitempty"`
- // current number of robots visible on field
- RobotsOnField *int32 `protobuf:"varint,9,opt,name=robots_on_field,json=robotsOnField" json:"robots_on_field,omitempty"`
- // list of due times for each active yellow card (in seconds)
- YellowCardsDue []float32 `protobuf:"fixed32,8,rep,name=yellow_cards_due,json=yellowCardsDue" json:"yellow_cards_due,omitempty"`
- // if true, team is allowed to substitute robots
- CanSubstituteRobot *bool `protobuf:"varint,11,opt,name=can_substitute_robot,json=canSubstituteRobot" json:"can_substitute_robot,omitempty"`
- // number of bot substitutions left by the team in this halftime
- BotSubstitutionsLeft *uint32 `protobuf:"varint,13,opt,name=bot_substitutions_left,json=botSubstitutionsLeft" json:"bot_substitutions_left,omitempty"`
- // number of seconds left for current bot substitution
- BotSubstitutionTimeLeft *float32 `protobuf:"fixed32,14,opt,name=bot_substitution_time_left,json=botSubstitutionTimeLeft" json:"bot_substitution_time_left,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *RemoteControlTeamState) Reset() {
- *x = RemoteControlTeamState{}
- mi := &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes[3]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *RemoteControlTeamState) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*RemoteControlTeamState) ProtoMessage() {}
-
-func (x *RemoteControlTeamState) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes[3]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use RemoteControlTeamState.ProtoReflect.Descriptor instead.
-func (*RemoteControlTeamState) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescGZIP(), []int{3}
-}
-
-func (x *RemoteControlTeamState) GetTeam() Team {
- if x != nil && x.Team != nil {
- return *x.Team
- }
- return Team_UNKNOWN
-}
-
-func (x *RemoteControlTeamState) GetAvailableRequests() []RemoteControlRequestType {
- if x != nil {
- return x.AvailableRequests
- }
- return nil
-}
-
-func (x *RemoteControlTeamState) GetActiveRequests() []RemoteControlRequestType {
- if x != nil {
- return x.ActiveRequests
- }
- return nil
-}
-
-func (x *RemoteControlTeamState) GetKeeperId() int32 {
- if x != nil && x.KeeperId != nil {
- return *x.KeeperId
- }
- return 0
-}
-
-func (x *RemoteControlTeamState) GetEmergencyStopIn() float32 {
- if x != nil && x.EmergencyStopIn != nil {
- return *x.EmergencyStopIn
- }
- return 0
-}
-
-func (x *RemoteControlTeamState) GetTimeoutsLeft() int32 {
- if x != nil && x.TimeoutsLeft != nil {
- return *x.TimeoutsLeft
- }
- return 0
-}
-
-func (x *RemoteControlTeamState) GetTimeoutTimeLeft() float32 {
- if x != nil && x.TimeoutTimeLeft != nil {
- return *x.TimeoutTimeLeft
- }
- return 0
-}
-
-func (x *RemoteControlTeamState) GetChallengeFlagsLeft() int32 {
- if x != nil && x.ChallengeFlagsLeft != nil {
- return *x.ChallengeFlagsLeft
- }
- return 0
-}
-
-func (x *RemoteControlTeamState) GetMaxRobots() int32 {
- if x != nil && x.MaxRobots != nil {
- return *x.MaxRobots
- }
- return 0
-}
-
-func (x *RemoteControlTeamState) GetRobotsOnField() int32 {
- if x != nil && x.RobotsOnField != nil {
- return *x.RobotsOnField
- }
- return 0
-}
-
-func (x *RemoteControlTeamState) GetYellowCardsDue() []float32 {
- if x != nil {
- return x.YellowCardsDue
- }
- return nil
-}
-
-func (x *RemoteControlTeamState) GetCanSubstituteRobot() bool {
- if x != nil && x.CanSubstituteRobot != nil {
- return *x.CanSubstituteRobot
- }
- return false
-}
-
-func (x *RemoteControlTeamState) GetBotSubstitutionsLeft() uint32 {
- if x != nil && x.BotSubstitutionsLeft != nil {
- return *x.BotSubstitutionsLeft
- }
- return 0
-}
-
-func (x *RemoteControlTeamState) GetBotSubstitutionTimeLeft() float32 {
- if x != nil && x.BotSubstitutionTimeLeft != nil {
- return *x.BotSubstitutionTimeLeft
- }
- return 0
-}
-
-var File_gamecontroller_ssl_gc_rcon_remotecontrol_proto protoreflect.FileDescriptor
-
-const file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDesc = "" +
- "\n" +
- ".gamecontroller/ssl_gc_rcon_remotecontrol.proto\x1a\"gamecontroller/ssl_gc_common.proto\x1a gamecontroller/ssl_gc_rcon.proto\"`\n" +
- "\x19RemoteControlRegistration\x12\x19\n" +
- "\x04team\x18\x01 \x02(\x0e2\x05.TeamR\x04team\x12(\n" +
- "\tsignature\x18\x02 \x01(\v2\n" +
- ".SignatureR\tsignature\"\xb8\x03\n" +
- "\x19RemoteControlToController\x12(\n" +
- "\tsignature\x18\x01 \x01(\v2\n" +
- ".SignatureR\tsignature\x12>\n" +
- "\arequest\x18\x02 \x01(\x0e2\".RemoteControlToController.RequestH\x00R\arequest\x12'\n" +
- "\x0edesired_keeper\x18\x03 \x01(\x05H\x00R\rdesiredKeeper\x12>\n" +
- "\x1arequest_robot_substitution\x18\x04 \x01(\bH\x00R\x18requestRobotSubstitution\x12)\n" +
- "\x0frequest_timeout\x18\x05 \x01(\bH\x00R\x0erequestTimeout\x126\n" +
- "\x16request_emergency_stop\x18\x06 \x01(\bH\x00R\x14requestEmergencyStop\"^\n" +
- "\aRequest\x12\v\n" +
- "\aUNKNOWN\x10\x00\x12\b\n" +
- "\x04PING\x10\x01\x12\x12\n" +
- "\x0eCHALLENGE_FLAG\x10\x02\x12\x10\n" +
- "\fSTOP_TIMEOUT\x10\x03\x12\x16\n" +
- "\x12FAIL_BALLPLACEMENT\x10\x04B\x05\n" +
- "\x03msg\"\x87\x01\n" +
- "\x19ControllerToRemoteControl\x12;\n" +
- "\x10controller_reply\x18\x01 \x01(\v2\x10.ControllerReplyR\x0fcontrollerReply\x12-\n" +
- "\x05state\x18\x02 \x01(\v2\x17.RemoteControlTeamStateR\x05state\"\xa3\x05\n" +
- "\x16RemoteControlTeamState\x12\x19\n" +
- "\x04team\x18\f \x01(\x0e2\x05.TeamR\x04team\x12H\n" +
- "\x12available_requests\x18\x01 \x03(\x0e2\x19.RemoteControlRequestTypeR\x11availableRequests\x12B\n" +
- "\x0factive_requests\x18\x02 \x03(\x0e2\x19.RemoteControlRequestTypeR\x0eactiveRequests\x12\x1b\n" +
- "\tkeeper_id\x18\x03 \x01(\x05R\bkeeperId\x12*\n" +
- "\x11emergency_stop_in\x18\x04 \x01(\x02R\x0femergencyStopIn\x12#\n" +
- "\rtimeouts_left\x18\x05 \x01(\x05R\ftimeoutsLeft\x12*\n" +
- "\x11timeout_time_left\x18\n" +
- " \x01(\x02R\x0ftimeoutTimeLeft\x120\n" +
- "\x14challenge_flags_left\x18\x06 \x01(\x05R\x12challengeFlagsLeft\x12\x1d\n" +
- "\n" +
- "max_robots\x18\a \x01(\x05R\tmaxRobots\x12&\n" +
- "\x0frobots_on_field\x18\t \x01(\x05R\rrobotsOnField\x12(\n" +
- "\x10yellow_cards_due\x18\b \x03(\x02R\x0eyellowCardsDue\x120\n" +
- "\x14can_substitute_robot\x18\v \x01(\bR\x12canSubstituteRobot\x124\n" +
- "\x16bot_substitutions_left\x18\r \x01(\rR\x14botSubstitutionsLeft\x12;\n" +
- "\x1abot_substitution_time_left\x18\x0e \x01(\x02R\x17botSubstitutionTimeLeft*\xc1\x01\n" +
- "\x18RemoteControlRequestType\x12\x18\n" +
- "\x14UNKNOWN_REQUEST_TYPE\x10\x00\x12\x12\n" +
- "\x0eEMERGENCY_STOP\x10\x01\x12\x16\n" +
- "\x12ROBOT_SUBSTITUTION\x10\x02\x12\v\n" +
- "\aTIMEOUT\x10\x03\x12\x12\n" +
- "\x0eCHALLENGE_FLAG\x10\x04\x12\x14\n" +
- "\x10CHANGE_KEEPER_ID\x10\x05\x12\x10\n" +
- "\fSTOP_TIMEOUT\x10\x06\x12\x16\n" +
- "\x12FAIL_BALLPLACEMENT\x10\aBhB\x1bSslGcRconRemotecontrolProtoP\x01ZGgithub.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
-
-var (
- file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescOnce sync.Once
- file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescData []byte
-)
-
-func file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescGZIP() []byte {
- file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescOnce.Do(func() {
- file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDesc), len(file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDesc)))
- })
- return file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDescData
-}
-
-var file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
-var file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
-var file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_goTypes = []any{
- (RemoteControlRequestType)(0), // 0: RemoteControlRequestType
- (RemoteControlToController_Request)(0), // 1: RemoteControlToController.Request
- (*RemoteControlRegistration)(nil), // 2: RemoteControlRegistration
- (*RemoteControlToController)(nil), // 3: RemoteControlToController
- (*ControllerToRemoteControl)(nil), // 4: ControllerToRemoteControl
- (*RemoteControlTeamState)(nil), // 5: RemoteControlTeamState
- (Team)(0), // 6: Team
- (*Signature)(nil), // 7: Signature
- (*ControllerReply)(nil), // 8: ControllerReply
-}
-var file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_depIdxs = []int32{
- 6, // 0: RemoteControlRegistration.team:type_name -> Team
- 7, // 1: RemoteControlRegistration.signature:type_name -> Signature
- 7, // 2: RemoteControlToController.signature:type_name -> Signature
- 1, // 3: RemoteControlToController.request:type_name -> RemoteControlToController.Request
- 8, // 4: ControllerToRemoteControl.controller_reply:type_name -> ControllerReply
- 5, // 5: ControllerToRemoteControl.state:type_name -> RemoteControlTeamState
- 6, // 6: RemoteControlTeamState.team:type_name -> Team
- 0, // 7: RemoteControlTeamState.available_requests:type_name -> RemoteControlRequestType
- 0, // 8: RemoteControlTeamState.active_requests:type_name -> RemoteControlRequestType
- 9, // [9:9] is the sub-list for method output_type
- 9, // [9:9] is the sub-list for method input_type
- 9, // [9:9] is the sub-list for extension type_name
- 9, // [9:9] is the sub-list for extension extendee
- 0, // [0:9] is the sub-list for field type_name
-}
-
-func init() { file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_init() }
-func file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_init() {
- if File_gamecontroller_ssl_gc_rcon_remotecontrol_proto != nil {
- return
- }
- file_gamecontroller_ssl_gc_common_proto_init()
- file_gamecontroller_ssl_gc_rcon_proto_init()
- file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes[1].OneofWrappers = []any{
- (*RemoteControlToController_Request_)(nil),
- (*RemoteControlToController_DesiredKeeper)(nil),
- (*RemoteControlToController_RequestRobotSubstitution)(nil),
- (*RemoteControlToController_RequestTimeout)(nil),
- (*RemoteControlToController_RequestEmergencyStop)(nil),
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDesc), len(file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_rawDesc)),
- NumEnums: 2,
- NumMessages: 4,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_goTypes,
- DependencyIndexes: file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_depIdxs,
- EnumInfos: file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_enumTypes,
- MessageInfos: file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_msgTypes,
- }.Build()
- File_gamecontroller_ssl_gc_rcon_remotecontrol_proto = out.File
- file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_goTypes = nil
- file_gamecontroller_ssl_gc_rcon_remotecontrol_proto_depIdxs = nil
-}
diff --git a/gui/internal/gamecontroller/ssl_gc_rcon_team.pb.go b/gui/internal/gamecontroller/ssl_gc_rcon_team.pb.go
deleted file mode 100644
index fc1ec5b..0000000
--- a/gui/internal/gamecontroller/ssl_gc_rcon_team.pb.go
+++ /dev/null
@@ -1,442 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.36.6
-// protoc (unknown)
-// source: gamecontroller/ssl_gc_rcon_team.proto
-
-package gamecontroller
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
- unsafe "unsafe"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-// the current advantage choice of the team
-// the choice is valid until another choice is received
-// if the team disconnects, the choice is reset to its default (STOP)
-// teams may either send their current choice continuously or only on change
-type AdvantageChoice int32
-
-const (
- // stop the game
- AdvantageChoice_STOP AdvantageChoice = 0
- // keep the game running
- AdvantageChoice_CONTINUE AdvantageChoice = 1
-)
-
-// Enum value maps for AdvantageChoice.
-var (
- AdvantageChoice_name = map[int32]string{
- 0: "STOP",
- 1: "CONTINUE",
- }
- AdvantageChoice_value = map[string]int32{
- "STOP": 0,
- "CONTINUE": 1,
- }
-)
-
-func (x AdvantageChoice) Enum() *AdvantageChoice {
- p := new(AdvantageChoice)
- *p = x
- return p
-}
-
-func (x AdvantageChoice) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (AdvantageChoice) Descriptor() protoreflect.EnumDescriptor {
- return file_gamecontroller_ssl_gc_rcon_team_proto_enumTypes[0].Descriptor()
-}
-
-func (AdvantageChoice) Type() protoreflect.EnumType {
- return &file_gamecontroller_ssl_gc_rcon_team_proto_enumTypes[0]
-}
-
-func (x AdvantageChoice) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Do not use.
-func (x *AdvantageChoice) UnmarshalJSON(b []byte) error {
- num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
- if err != nil {
- return err
- }
- *x = AdvantageChoice(num)
- return nil
-}
-
-// Deprecated: Use AdvantageChoice.Descriptor instead.
-func (AdvantageChoice) EnumDescriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_rcon_team_proto_rawDescGZIP(), []int{0}
-}
-
-// a registration that must be send by teams to the controller as the very first message
-type TeamRegistration struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // the exact team name as published by the game-controller
- TeamName *string `protobuf:"bytes,1,req,name=team_name,json=teamName" json:"team_name,omitempty"`
- // signature can optionally be specified to enable secure communication
- Signature *Signature `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"`
- // the team (relevant only if a team plays against itself)
- Team *Team `protobuf:"varint,3,opt,name=team,enum=Team" json:"team,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *TeamRegistration) Reset() {
- *x = TeamRegistration{}
- mi := &file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *TeamRegistration) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*TeamRegistration) ProtoMessage() {}
-
-func (x *TeamRegistration) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes[0]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use TeamRegistration.ProtoReflect.Descriptor instead.
-func (*TeamRegistration) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_rcon_team_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *TeamRegistration) GetTeamName() string {
- if x != nil && x.TeamName != nil {
- return *x.TeamName
- }
- return ""
-}
-
-func (x *TeamRegistration) GetSignature() *Signature {
- if x != nil {
- return x.Signature
- }
- return nil
-}
-
-func (x *TeamRegistration) GetTeam() Team {
- if x != nil && x.Team != nil {
- return *x.Team
- }
- return Team_UNKNOWN
-}
-
-// wrapper for all messages from a team's computer to the controller
-type TeamToController struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // signature can optionally be specified to enable secure communication
- Signature *Signature `protobuf:"bytes,1,opt,name=signature" json:"signature,omitempty"`
- // Types that are valid to be assigned to Msg:
- //
- // *TeamToController_DesiredKeeper
- // *TeamToController_AdvantageChoice
- // *TeamToController_SubstituteBot
- // *TeamToController_Ping
- Msg isTeamToController_Msg `protobuf_oneof:"msg"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *TeamToController) Reset() {
- *x = TeamToController{}
- mi := &file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *TeamToController) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*TeamToController) ProtoMessage() {}
-
-func (x *TeamToController) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes[1]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use TeamToController.ProtoReflect.Descriptor instead.
-func (*TeamToController) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_rcon_team_proto_rawDescGZIP(), []int{1}
-}
-
-func (x *TeamToController) GetSignature() *Signature {
- if x != nil {
- return x.Signature
- }
- return nil
-}
-
-func (x *TeamToController) GetMsg() isTeamToController_Msg {
- if x != nil {
- return x.Msg
- }
- return nil
-}
-
-func (x *TeamToController) GetDesiredKeeper() int32 {
- if x != nil {
- if x, ok := x.Msg.(*TeamToController_DesiredKeeper); ok {
- return x.DesiredKeeper
- }
- }
- return 0
-}
-
-func (x *TeamToController) GetAdvantageChoice() AdvantageChoice {
- if x != nil {
- if x, ok := x.Msg.(*TeamToController_AdvantageChoice); ok {
- return x.AdvantageChoice
- }
- }
- return AdvantageChoice_STOP
-}
-
-func (x *TeamToController) GetSubstituteBot() bool {
- if x != nil {
- if x, ok := x.Msg.(*TeamToController_SubstituteBot); ok {
- return x.SubstituteBot
- }
- }
- return false
-}
-
-func (x *TeamToController) GetPing() bool {
- if x != nil {
- if x, ok := x.Msg.(*TeamToController_Ping); ok {
- return x.Ping
- }
- }
- return false
-}
-
-type isTeamToController_Msg interface {
- isTeamToController_Msg()
-}
-
-type TeamToController_DesiredKeeper struct {
- // request a new desired keeper id
- DesiredKeeper int32 `protobuf:"varint,2,opt,name=desired_keeper,json=desiredKeeper,oneof"`
-}
-
-type TeamToController_AdvantageChoice struct {
- // response to an advantage choice request
- AdvantageChoice AdvantageChoice `protobuf:"varint,3,opt,name=advantage_choice,json=advantageChoice,enum=AdvantageChoice,oneof"`
-}
-
-type TeamToController_SubstituteBot struct {
- // request to substitute a robot at the next possibility
- SubstituteBot bool `protobuf:"varint,4,opt,name=substitute_bot,json=substituteBot,oneof"`
-}
-
-type TeamToController_Ping struct {
- // send a ping to the GC to test if the connection is still open.
- // the value is ignored and a reply is sent back
- Ping bool `protobuf:"varint,5,opt,name=ping,oneof"`
-}
-
-func (*TeamToController_DesiredKeeper) isTeamToController_Msg() {}
-
-func (*TeamToController_AdvantageChoice) isTeamToController_Msg() {}
-
-func (*TeamToController_SubstituteBot) isTeamToController_Msg() {}
-
-func (*TeamToController_Ping) isTeamToController_Msg() {}
-
-// wrapper for all messages from controller to a team's computer
-type ControllerToTeam struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // Types that are valid to be assigned to Msg:
- //
- // *ControllerToTeam_ControllerReply
- Msg isControllerToTeam_Msg `protobuf_oneof:"msg"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *ControllerToTeam) Reset() {
- *x = ControllerToTeam{}
- mi := &file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes[2]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *ControllerToTeam) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*ControllerToTeam) ProtoMessage() {}
-
-func (x *ControllerToTeam) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes[2]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use ControllerToTeam.ProtoReflect.Descriptor instead.
-func (*ControllerToTeam) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_rcon_team_proto_rawDescGZIP(), []int{2}
-}
-
-func (x *ControllerToTeam) GetMsg() isControllerToTeam_Msg {
- if x != nil {
- return x.Msg
- }
- return nil
-}
-
-func (x *ControllerToTeam) GetControllerReply() *ControllerReply {
- if x != nil {
- if x, ok := x.Msg.(*ControllerToTeam_ControllerReply); ok {
- return x.ControllerReply
- }
- }
- return nil
-}
-
-type isControllerToTeam_Msg interface {
- isControllerToTeam_Msg()
-}
-
-type ControllerToTeam_ControllerReply struct {
- // a reply from the controller
- ControllerReply *ControllerReply `protobuf:"bytes,1,opt,name=controller_reply,json=controllerReply,oneof"`
-}
-
-func (*ControllerToTeam_ControllerReply) isControllerToTeam_Msg() {}
-
-var File_gamecontroller_ssl_gc_rcon_team_proto protoreflect.FileDescriptor
-
-const file_gamecontroller_ssl_gc_rcon_team_proto_rawDesc = "" +
- "\n" +
- "%gamecontroller/ssl_gc_rcon_team.proto\x1a\"gamecontroller/ssl_gc_common.proto\x1a gamecontroller/ssl_gc_rcon.proto\"t\n" +
- "\x10TeamRegistration\x12\x1b\n" +
- "\tteam_name\x18\x01 \x02(\tR\bteamName\x12(\n" +
- "\tsignature\x18\x02 \x01(\v2\n" +
- ".SignatureR\tsignature\x12\x19\n" +
- "\x04team\x18\x03 \x01(\x0e2\x05.TeamR\x04team\"\xea\x01\n" +
- "\x10TeamToController\x12(\n" +
- "\tsignature\x18\x01 \x01(\v2\n" +
- ".SignatureR\tsignature\x12'\n" +
- "\x0edesired_keeper\x18\x02 \x01(\x05H\x00R\rdesiredKeeper\x12=\n" +
- "\x10advantage_choice\x18\x03 \x01(\x0e2\x10.AdvantageChoiceH\x00R\x0fadvantageChoice\x12'\n" +
- "\x0esubstitute_bot\x18\x04 \x01(\bH\x00R\rsubstituteBot\x12\x14\n" +
- "\x04ping\x18\x05 \x01(\bH\x00R\x04pingB\x05\n" +
- "\x03msg\"^\n" +
- "\x10ControllerToTeam\x12=\n" +
- "\x10controller_reply\x18\x01 \x01(\v2\x10.ControllerReplyH\x00R\x0fcontrollerReplyB\x05\n" +
- "\x03msgJ\x04\b\x02\x10\x03*)\n" +
- "\x0fAdvantageChoice\x12\b\n" +
- "\x04STOP\x10\x00\x12\f\n" +
- "\bCONTINUE\x10\x01B_B\x12SslGcRconTeamProtoP\x01ZGgithub.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
-
-var (
- file_gamecontroller_ssl_gc_rcon_team_proto_rawDescOnce sync.Once
- file_gamecontroller_ssl_gc_rcon_team_proto_rawDescData []byte
-)
-
-func file_gamecontroller_ssl_gc_rcon_team_proto_rawDescGZIP() []byte {
- file_gamecontroller_ssl_gc_rcon_team_proto_rawDescOnce.Do(func() {
- file_gamecontroller_ssl_gc_rcon_team_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_rcon_team_proto_rawDesc), len(file_gamecontroller_ssl_gc_rcon_team_proto_rawDesc)))
- })
- return file_gamecontroller_ssl_gc_rcon_team_proto_rawDescData
-}
-
-var file_gamecontroller_ssl_gc_rcon_team_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
-var file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
-var file_gamecontroller_ssl_gc_rcon_team_proto_goTypes = []any{
- (AdvantageChoice)(0), // 0: AdvantageChoice
- (*TeamRegistration)(nil), // 1: TeamRegistration
- (*TeamToController)(nil), // 2: TeamToController
- (*ControllerToTeam)(nil), // 3: ControllerToTeam
- (*Signature)(nil), // 4: Signature
- (Team)(0), // 5: Team
- (*ControllerReply)(nil), // 6: ControllerReply
-}
-var file_gamecontroller_ssl_gc_rcon_team_proto_depIdxs = []int32{
- 4, // 0: TeamRegistration.signature:type_name -> Signature
- 5, // 1: TeamRegistration.team:type_name -> Team
- 4, // 2: TeamToController.signature:type_name -> Signature
- 0, // 3: TeamToController.advantage_choice:type_name -> AdvantageChoice
- 6, // 4: ControllerToTeam.controller_reply:type_name -> ControllerReply
- 5, // [5:5] is the sub-list for method output_type
- 5, // [5:5] is the sub-list for method input_type
- 5, // [5:5] is the sub-list for extension type_name
- 5, // [5:5] is the sub-list for extension extendee
- 0, // [0:5] is the sub-list for field type_name
-}
-
-func init() { file_gamecontroller_ssl_gc_rcon_team_proto_init() }
-func file_gamecontroller_ssl_gc_rcon_team_proto_init() {
- if File_gamecontroller_ssl_gc_rcon_team_proto != nil {
- return
- }
- file_gamecontroller_ssl_gc_common_proto_init()
- file_gamecontroller_ssl_gc_rcon_proto_init()
- file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes[1].OneofWrappers = []any{
- (*TeamToController_DesiredKeeper)(nil),
- (*TeamToController_AdvantageChoice)(nil),
- (*TeamToController_SubstituteBot)(nil),
- (*TeamToController_Ping)(nil),
- }
- file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes[2].OneofWrappers = []any{
- (*ControllerToTeam_ControllerReply)(nil),
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_rcon_team_proto_rawDesc), len(file_gamecontroller_ssl_gc_rcon_team_proto_rawDesc)),
- NumEnums: 1,
- NumMessages: 3,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_gamecontroller_ssl_gc_rcon_team_proto_goTypes,
- DependencyIndexes: file_gamecontroller_ssl_gc_rcon_team_proto_depIdxs,
- EnumInfos: file_gamecontroller_ssl_gc_rcon_team_proto_enumTypes,
- MessageInfos: file_gamecontroller_ssl_gc_rcon_team_proto_msgTypes,
- }.Build()
- File_gamecontroller_ssl_gc_rcon_team_proto = out.File
- file_gamecontroller_ssl_gc_rcon_team_proto_goTypes = nil
- file_gamecontroller_ssl_gc_rcon_team_proto_depIdxs = nil
-}
diff --git a/gui/internal/gamecontroller/ssl_gc_referee_message.pb.go b/gui/internal/gamecontroller/ssl_gc_referee_message.pb.go
deleted file mode 100644
index 84dd959..0000000
--- a/gui/internal/gamecontroller/ssl_gc_referee_message.pb.go
+++ /dev/null
@@ -1,1113 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.36.6
-// protoc (unknown)
-// source: gamecontroller/ssl_gc_referee_message.proto
-
-package gamecontroller
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
- unsafe "unsafe"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-// MatchType is a meta information about the current match for easier log processing
-type MatchType int32
-
-const (
- // not set
- MatchType_UNKNOWN_MATCH MatchType = 0
- // match is part of the group phase
- MatchType_GROUP_PHASE MatchType = 1
- // match is part of the elimination phase
- MatchType_ELIMINATION_PHASE MatchType = 2
- // a friendly match, not part of a tournament
- MatchType_FRIENDLY MatchType = 3
-)
-
-// Enum value maps for MatchType.
-var (
- MatchType_name = map[int32]string{
- 0: "UNKNOWN_MATCH",
- 1: "GROUP_PHASE",
- 2: "ELIMINATION_PHASE",
- 3: "FRIENDLY",
- }
- MatchType_value = map[string]int32{
- "UNKNOWN_MATCH": 0,
- "GROUP_PHASE": 1,
- "ELIMINATION_PHASE": 2,
- "FRIENDLY": 3,
- }
-)
-
-func (x MatchType) Enum() *MatchType {
- p := new(MatchType)
- *p = x
- return p
-}
-
-func (x MatchType) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (MatchType) Descriptor() protoreflect.EnumDescriptor {
- return file_gamecontroller_ssl_gc_referee_message_proto_enumTypes[0].Descriptor()
-}
-
-func (MatchType) Type() protoreflect.EnumType {
- return &file_gamecontroller_ssl_gc_referee_message_proto_enumTypes[0]
-}
-
-func (x MatchType) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Do not use.
-func (x *MatchType) UnmarshalJSON(b []byte) error {
- num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
- if err != nil {
- return err
- }
- *x = MatchType(num)
- return nil
-}
-
-// Deprecated: Use MatchType.Descriptor instead.
-func (MatchType) EnumDescriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_referee_message_proto_rawDescGZIP(), []int{0}
-}
-
-// HullColor is the color of the hull of the robots of a team
-type HullColor int32
-
-const (
- // not set
- HullColor_HULL_COLOR_UNKNOWN HullColor = 0
- // dark hull color
- HullColor_HULL_COLOR_DARK HullColor = 1
- // light hull color
- HullColor_HULL_COLOR_LIGHT HullColor = 2
-)
-
-// Enum value maps for HullColor.
-var (
- HullColor_name = map[int32]string{
- 0: "HULL_COLOR_UNKNOWN",
- 1: "HULL_COLOR_DARK",
- 2: "HULL_COLOR_LIGHT",
- }
- HullColor_value = map[string]int32{
- "HULL_COLOR_UNKNOWN": 0,
- "HULL_COLOR_DARK": 1,
- "HULL_COLOR_LIGHT": 2,
- }
-)
-
-func (x HullColor) Enum() *HullColor {
- p := new(HullColor)
- *p = x
- return p
-}
-
-func (x HullColor) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (HullColor) Descriptor() protoreflect.EnumDescriptor {
- return file_gamecontroller_ssl_gc_referee_message_proto_enumTypes[1].Descriptor()
-}
-
-func (HullColor) Type() protoreflect.EnumType {
- return &file_gamecontroller_ssl_gc_referee_message_proto_enumTypes[1]
-}
-
-func (x HullColor) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Do not use.
-func (x *HullColor) UnmarshalJSON(b []byte) error {
- num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
- if err != nil {
- return err
- }
- *x = HullColor(num)
- return nil
-}
-
-// Deprecated: Use HullColor.Descriptor instead.
-func (HullColor) EnumDescriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_referee_message_proto_rawDescGZIP(), []int{1}
-}
-
-// These are the "coarse" stages of the game.
-type Referee_Stage int32
-
-const (
- // The first half is about to start.
- // A kickoff is called within this stage.
- // This stage ends with the NORMAL_START.
- Referee_NORMAL_FIRST_HALF_PRE Referee_Stage = 0
- // The first half of the normal game, before half time.
- Referee_NORMAL_FIRST_HALF Referee_Stage = 1
- // Half time between first and second halves.
- Referee_NORMAL_HALF_TIME Referee_Stage = 2
- // The second half is about to start.
- // A kickoff is called within this stage.
- // This stage ends with the NORMAL_START.
- Referee_NORMAL_SECOND_HALF_PRE Referee_Stage = 3
- // The second half of the normal game, after half time.
- Referee_NORMAL_SECOND_HALF Referee_Stage = 4
- // The break before extra time.
- Referee_EXTRA_TIME_BREAK Referee_Stage = 5
- // The first half of extra time is about to start.
- // A kickoff is called within this stage.
- // This stage ends with the NORMAL_START.
- Referee_EXTRA_FIRST_HALF_PRE Referee_Stage = 6
- // The first half of extra time.
- Referee_EXTRA_FIRST_HALF Referee_Stage = 7
- // Half time between first and second extra halves.
- Referee_EXTRA_HALF_TIME Referee_Stage = 8
- // The second half of extra time is about to start.
- // A kickoff is called within this stage.
- // This stage ends with the NORMAL_START.
- Referee_EXTRA_SECOND_HALF_PRE Referee_Stage = 9
- // The second half of extra time.
- Referee_EXTRA_SECOND_HALF Referee_Stage = 10
- // The break before penalty shootout.
- Referee_PENALTY_SHOOTOUT_BREAK Referee_Stage = 11
- // The penalty shootout.
- Referee_PENALTY_SHOOTOUT Referee_Stage = 12
- // The game is over.
- Referee_POST_GAME Referee_Stage = 13
-)
-
-// Enum value maps for Referee_Stage.
-var (
- Referee_Stage_name = map[int32]string{
- 0: "NORMAL_FIRST_HALF_PRE",
- 1: "NORMAL_FIRST_HALF",
- 2: "NORMAL_HALF_TIME",
- 3: "NORMAL_SECOND_HALF_PRE",
- 4: "NORMAL_SECOND_HALF",
- 5: "EXTRA_TIME_BREAK",
- 6: "EXTRA_FIRST_HALF_PRE",
- 7: "EXTRA_FIRST_HALF",
- 8: "EXTRA_HALF_TIME",
- 9: "EXTRA_SECOND_HALF_PRE",
- 10: "EXTRA_SECOND_HALF",
- 11: "PENALTY_SHOOTOUT_BREAK",
- 12: "PENALTY_SHOOTOUT",
- 13: "POST_GAME",
- }
- Referee_Stage_value = map[string]int32{
- "NORMAL_FIRST_HALF_PRE": 0,
- "NORMAL_FIRST_HALF": 1,
- "NORMAL_HALF_TIME": 2,
- "NORMAL_SECOND_HALF_PRE": 3,
- "NORMAL_SECOND_HALF": 4,
- "EXTRA_TIME_BREAK": 5,
- "EXTRA_FIRST_HALF_PRE": 6,
- "EXTRA_FIRST_HALF": 7,
- "EXTRA_HALF_TIME": 8,
- "EXTRA_SECOND_HALF_PRE": 9,
- "EXTRA_SECOND_HALF": 10,
- "PENALTY_SHOOTOUT_BREAK": 11,
- "PENALTY_SHOOTOUT": 12,
- "POST_GAME": 13,
- }
-)
-
-func (x Referee_Stage) Enum() *Referee_Stage {
- p := new(Referee_Stage)
- *p = x
- return p
-}
-
-func (x Referee_Stage) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (Referee_Stage) Descriptor() protoreflect.EnumDescriptor {
- return file_gamecontroller_ssl_gc_referee_message_proto_enumTypes[2].Descriptor()
-}
-
-func (Referee_Stage) Type() protoreflect.EnumType {
- return &file_gamecontroller_ssl_gc_referee_message_proto_enumTypes[2]
-}
-
-func (x Referee_Stage) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Do not use.
-func (x *Referee_Stage) UnmarshalJSON(b []byte) error {
- num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
- if err != nil {
- return err
- }
- *x = Referee_Stage(num)
- return nil
-}
-
-// Deprecated: Use Referee_Stage.Descriptor instead.
-func (Referee_Stage) EnumDescriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_referee_message_proto_rawDescGZIP(), []int{0, 0}
-}
-
-// These are the "fine" states of play on the field.
-type Referee_Command int32
-
-const (
- // All robots should completely stop moving.
- Referee_HALT Referee_Command = 0
- // Robots must keep 50 cm from the ball.
- Referee_STOP Referee_Command = 1
- // A prepared kickoff or penalty may now be taken.
- Referee_NORMAL_START Referee_Command = 2
- // The ball is dropped and free for either team.
- Referee_FORCE_START Referee_Command = 3
- // The yellow team may move into kickoff position.
- Referee_PREPARE_KICKOFF_YELLOW Referee_Command = 4
- // The blue team may move into kickoff position.
- Referee_PREPARE_KICKOFF_BLUE Referee_Command = 5
- // The yellow team may move into penalty position.
- Referee_PREPARE_PENALTY_YELLOW Referee_Command = 6
- // The blue team may move into penalty position.
- Referee_PREPARE_PENALTY_BLUE Referee_Command = 7
- // The yellow team may take a direct free kick.
- Referee_DIRECT_FREE_YELLOW Referee_Command = 8
- // The blue team may take a direct free kick.
- Referee_DIRECT_FREE_BLUE Referee_Command = 9
- // The yellow team may take an indirect free kick.
- //
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_referee_message.proto.
- Referee_INDIRECT_FREE_YELLOW Referee_Command = 10
- // The blue team may take an indirect free kick.
- //
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_referee_message.proto.
- Referee_INDIRECT_FREE_BLUE Referee_Command = 11
- // The yellow team is currently in a timeout.
- Referee_TIMEOUT_YELLOW Referee_Command = 12
- // The blue team is currently in a timeout.
- Referee_TIMEOUT_BLUE Referee_Command = 13
- // The yellow team just scored a goal.
- // For information only.
- // Deprecated: Use the score field from the team infos instead. That way, you can also detect revoked goals.
- //
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_referee_message.proto.
- Referee_GOAL_YELLOW Referee_Command = 14
- // The blue team just scored a goal. See also GOAL_YELLOW.
- //
- // Deprecated: Marked as deprecated in gamecontroller/ssl_gc_referee_message.proto.
- Referee_GOAL_BLUE Referee_Command = 15
- // Equivalent to STOP, but the yellow team must pick up the ball and
- // drop it in the Designated Position.
- Referee_BALL_PLACEMENT_YELLOW Referee_Command = 16
- // Equivalent to STOP, but the blue team must pick up the ball and drop
- // it in the Designated Position.
- Referee_BALL_PLACEMENT_BLUE Referee_Command = 17
-)
-
-// Enum value maps for Referee_Command.
-var (
- Referee_Command_name = map[int32]string{
- 0: "HALT",
- 1: "STOP",
- 2: "NORMAL_START",
- 3: "FORCE_START",
- 4: "PREPARE_KICKOFF_YELLOW",
- 5: "PREPARE_KICKOFF_BLUE",
- 6: "PREPARE_PENALTY_YELLOW",
- 7: "PREPARE_PENALTY_BLUE",
- 8: "DIRECT_FREE_YELLOW",
- 9: "DIRECT_FREE_BLUE",
- 10: "INDIRECT_FREE_YELLOW",
- 11: "INDIRECT_FREE_BLUE",
- 12: "TIMEOUT_YELLOW",
- 13: "TIMEOUT_BLUE",
- 14: "GOAL_YELLOW",
- 15: "GOAL_BLUE",
- 16: "BALL_PLACEMENT_YELLOW",
- 17: "BALL_PLACEMENT_BLUE",
- }
- Referee_Command_value = map[string]int32{
- "HALT": 0,
- "STOP": 1,
- "NORMAL_START": 2,
- "FORCE_START": 3,
- "PREPARE_KICKOFF_YELLOW": 4,
- "PREPARE_KICKOFF_BLUE": 5,
- "PREPARE_PENALTY_YELLOW": 6,
- "PREPARE_PENALTY_BLUE": 7,
- "DIRECT_FREE_YELLOW": 8,
- "DIRECT_FREE_BLUE": 9,
- "INDIRECT_FREE_YELLOW": 10,
- "INDIRECT_FREE_BLUE": 11,
- "TIMEOUT_YELLOW": 12,
- "TIMEOUT_BLUE": 13,
- "GOAL_YELLOW": 14,
- "GOAL_BLUE": 15,
- "BALL_PLACEMENT_YELLOW": 16,
- "BALL_PLACEMENT_BLUE": 17,
- }
-)
-
-func (x Referee_Command) Enum() *Referee_Command {
- p := new(Referee_Command)
- *p = x
- return p
-}
-
-func (x Referee_Command) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (Referee_Command) Descriptor() protoreflect.EnumDescriptor {
- return file_gamecontroller_ssl_gc_referee_message_proto_enumTypes[3].Descriptor()
-}
-
-func (Referee_Command) Type() protoreflect.EnumType {
- return &file_gamecontroller_ssl_gc_referee_message_proto_enumTypes[3]
-}
-
-func (x Referee_Command) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Do not use.
-func (x *Referee_Command) UnmarshalJSON(b []byte) error {
- num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
- if err != nil {
- return err
- }
- *x = Referee_Command(num)
- return nil
-}
-
-// Deprecated: Use Referee_Command.Descriptor instead.
-func (Referee_Command) EnumDescriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_referee_message_proto_rawDescGZIP(), []int{0, 1}
-}
-
-// Each UDP packet contains one of these messages.
-type Referee struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // A random UUID of the source that is kept constant at the source while running
- // If multiple sources are broadcasting to the same network, this id can be used to identify individual sources
- SourceIdentifier *string `protobuf:"bytes,18,opt,name=source_identifier,json=sourceIdentifier" json:"source_identifier,omitempty"`
- // The match type is a meta information about the current match that helps to process the logs after a competition
- MatchType *MatchType `protobuf:"varint,19,opt,name=match_type,json=matchType,enum=MatchType,def=0" json:"match_type,omitempty"`
- // The UNIX timestamp when the packet was sent, in microseconds.
- // Divide by 1,000,000 to get a time_t.
- PacketTimestamp *uint64 `protobuf:"varint,1,req,name=packet_timestamp,json=packetTimestamp" json:"packet_timestamp,omitempty"`
- Stage *Referee_Stage `protobuf:"varint,2,req,name=stage,enum=Referee_Stage" json:"stage,omitempty"`
- // The number of microseconds left in the stage.
- // The following stages have this value; the rest do not:
- // NORMAL_FIRST_HALF
- // NORMAL_HALF_TIME
- // NORMAL_SECOND_HALF
- // EXTRA_TIME_BREAK
- // EXTRA_FIRST_HALF
- // EXTRA_HALF_TIME
- // EXTRA_SECOND_HALF
- // PENALTY_SHOOTOUT_BREAK
- //
- // If the stage runs over its specified time, this value
- // becomes negative.
- StageTimeLeft *int64 `protobuf:"zigzag64,3,opt,name=stage_time_left,json=stageTimeLeft" json:"stage_time_left,omitempty"`
- Command *Referee_Command `protobuf:"varint,4,req,name=command,enum=Referee_Command" json:"command,omitempty"`
- // The number of commands issued since startup (mod 2^32).
- CommandCounter *uint32 `protobuf:"varint,5,req,name=command_counter,json=commandCounter" json:"command_counter,omitempty"`
- // The UNIX timestamp when the command was issued, in microseconds.
- // This value changes only when a new command is issued, not on each packet.
- CommandTimestamp *uint64 `protobuf:"varint,6,req,name=command_timestamp,json=commandTimestamp" json:"command_timestamp,omitempty"`
- // Information about the two teams.
- Yellow *Referee_TeamInfo `protobuf:"bytes,7,req,name=yellow" json:"yellow,omitempty"`
- Blue *Referee_TeamInfo `protobuf:"bytes,8,req,name=blue" json:"blue,omitempty"`
- DesignatedPosition *Referee_Point `protobuf:"bytes,9,opt,name=designated_position,json=designatedPosition" json:"designated_position,omitempty"`
- // Information about the direction of play.
- // True, if the blue team will have it's goal on the positive x-axis of the ssl-vision coordinate system.
- // Obviously, the yellow team will play on the opposite half.
- BlueTeamOnPositiveHalf *bool `protobuf:"varint,10,opt,name=blue_team_on_positive_half,json=blueTeamOnPositiveHalf" json:"blue_team_on_positive_half,omitempty"`
- // The command that will be issued after the current stoppage and ball placement to continue the game.
- NextCommand *Referee_Command `protobuf:"varint,12,opt,name=next_command,json=nextCommand,enum=Referee_Command" json:"next_command,omitempty"`
- GameEvents []*GameEvent `protobuf:"bytes,16,rep,name=game_events,json=gameEvents" json:"game_events,omitempty"`
- GameEventProposals []*GameEventProposalGroup `protobuf:"bytes,17,rep,name=game_event_proposals,json=gameEventProposals" json:"game_event_proposals,omitempty"`
- // The time in microseconds that is remaining until the current action times out
- // The time will not be reset. It can get negative.
- // An autoRef would raise an appropriate event, if the time gets negative.
- // Possible actions where this time is relevant:
- // - free kicks
- // - kickoff, penalty kick, force start
- // - ball placement
- CurrentActionTimeRemaining *int64 `protobuf:"varint,15,opt,name=current_action_time_remaining,json=currentActionTimeRemaining" json:"current_action_time_remaining,omitempty"`
- // A message that can be displayed to the spectators, like a reason for a stoppage.
- StatusMessage *string `protobuf:"bytes,20,opt,name=status_message,json=statusMessage" json:"status_message,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-// Default values for Referee fields.
-const (
- Default_Referee_MatchType = MatchType_UNKNOWN_MATCH
-)
-
-func (x *Referee) Reset() {
- *x = Referee{}
- mi := &file_gamecontroller_ssl_gc_referee_message_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *Referee) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*Referee) ProtoMessage() {}
-
-func (x *Referee) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_referee_message_proto_msgTypes[0]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use Referee.ProtoReflect.Descriptor instead.
-func (*Referee) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_referee_message_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *Referee) GetSourceIdentifier() string {
- if x != nil && x.SourceIdentifier != nil {
- return *x.SourceIdentifier
- }
- return ""
-}
-
-func (x *Referee) GetMatchType() MatchType {
- if x != nil && x.MatchType != nil {
- return *x.MatchType
- }
- return Default_Referee_MatchType
-}
-
-func (x *Referee) GetPacketTimestamp() uint64 {
- if x != nil && x.PacketTimestamp != nil {
- return *x.PacketTimestamp
- }
- return 0
-}
-
-func (x *Referee) GetStage() Referee_Stage {
- if x != nil && x.Stage != nil {
- return *x.Stage
- }
- return Referee_NORMAL_FIRST_HALF_PRE
-}
-
-func (x *Referee) GetStageTimeLeft() int64 {
- if x != nil && x.StageTimeLeft != nil {
- return *x.StageTimeLeft
- }
- return 0
-}
-
-func (x *Referee) GetCommand() Referee_Command {
- if x != nil && x.Command != nil {
- return *x.Command
- }
- return Referee_HALT
-}
-
-func (x *Referee) GetCommandCounter() uint32 {
- if x != nil && x.CommandCounter != nil {
- return *x.CommandCounter
- }
- return 0
-}
-
-func (x *Referee) GetCommandTimestamp() uint64 {
- if x != nil && x.CommandTimestamp != nil {
- return *x.CommandTimestamp
- }
- return 0
-}
-
-func (x *Referee) GetYellow() *Referee_TeamInfo {
- if x != nil {
- return x.Yellow
- }
- return nil
-}
-
-func (x *Referee) GetBlue() *Referee_TeamInfo {
- if x != nil {
- return x.Blue
- }
- return nil
-}
-
-func (x *Referee) GetDesignatedPosition() *Referee_Point {
- if x != nil {
- return x.DesignatedPosition
- }
- return nil
-}
-
-func (x *Referee) GetBlueTeamOnPositiveHalf() bool {
- if x != nil && x.BlueTeamOnPositiveHalf != nil {
- return *x.BlueTeamOnPositiveHalf
- }
- return false
-}
-
-func (x *Referee) GetNextCommand() Referee_Command {
- if x != nil && x.NextCommand != nil {
- return *x.NextCommand
- }
- return Referee_HALT
-}
-
-func (x *Referee) GetGameEvents() []*GameEvent {
- if x != nil {
- return x.GameEvents
- }
- return nil
-}
-
-func (x *Referee) GetGameEventProposals() []*GameEventProposalGroup {
- if x != nil {
- return x.GameEventProposals
- }
- return nil
-}
-
-func (x *Referee) GetCurrentActionTimeRemaining() int64 {
- if x != nil && x.CurrentActionTimeRemaining != nil {
- return *x.CurrentActionTimeRemaining
- }
- return 0
-}
-
-func (x *Referee) GetStatusMessage() string {
- if x != nil && x.StatusMessage != nil {
- return *x.StatusMessage
- }
- return ""
-}
-
-// List of matching proposals
-type GameEventProposalGroup struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // Unique ID of this group
- Id *string `protobuf:"bytes,3,opt,name=id" json:"id,omitempty"`
- // The proposed game events
- GameEvents []*GameEvent `protobuf:"bytes,1,rep,name=game_events,json=gameEvents" json:"game_events,omitempty"`
- // Whether the proposal group was accepted
- Accepted *bool `protobuf:"varint,2,opt,name=accepted" json:"accepted,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GameEventProposalGroup) Reset() {
- *x = GameEventProposalGroup{}
- mi := &file_gamecontroller_ssl_gc_referee_message_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GameEventProposalGroup) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GameEventProposalGroup) ProtoMessage() {}
-
-func (x *GameEventProposalGroup) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_referee_message_proto_msgTypes[1]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GameEventProposalGroup.ProtoReflect.Descriptor instead.
-func (*GameEventProposalGroup) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_referee_message_proto_rawDescGZIP(), []int{1}
-}
-
-func (x *GameEventProposalGroup) GetId() string {
- if x != nil && x.Id != nil {
- return *x.Id
- }
- return ""
-}
-
-func (x *GameEventProposalGroup) GetGameEvents() []*GameEvent {
- if x != nil {
- return x.GameEvents
- }
- return nil
-}
-
-func (x *GameEventProposalGroup) GetAccepted() bool {
- if x != nil && x.Accepted != nil {
- return *x.Accepted
- }
- return false
-}
-
-// Information about a single team.
-type Referee_TeamInfo struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // The team's name (empty string if operator has not typed anything).
- Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"`
- // The number of goals scored by the team during normal play and overtime.
- Score *uint32 `protobuf:"varint,2,req,name=score" json:"score,omitempty"`
- // The number of red cards issued to the team since the beginning of the game.
- RedCards *uint32 `protobuf:"varint,3,req,name=red_cards,json=redCards" json:"red_cards,omitempty"`
- // The amount of time (in microseconds) left on each yellow card issued to the team.
- // If no yellow cards are issued, this array has no elements.
- // Otherwise, times are ordered from smallest to largest.
- YellowCardTimes []uint32 `protobuf:"varint,4,rep,packed,name=yellow_card_times,json=yellowCardTimes" json:"yellow_card_times,omitempty"`
- // The total number of yellow cards ever issued to the team.
- YellowCards *uint32 `protobuf:"varint,5,req,name=yellow_cards,json=yellowCards" json:"yellow_cards,omitempty"`
- // The number of timeouts this team can still call.
- // If in a timeout right now, that timeout is excluded.
- Timeouts *uint32 `protobuf:"varint,6,req,name=timeouts" json:"timeouts,omitempty"`
- // The number of microseconds of timeout this team can use.
- TimeoutTime *uint32 `protobuf:"varint,7,req,name=timeout_time,json=timeoutTime" json:"timeout_time,omitempty"`
- // The pattern number of this team's goalkeeper.
- Goalkeeper *uint32 `protobuf:"varint,8,req,name=goalkeeper" json:"goalkeeper,omitempty"`
- // The total number of countable fouls that act towards yellow cards
- FoulCounter *uint32 `protobuf:"varint,9,opt,name=foul_counter,json=foulCounter" json:"foul_counter,omitempty"`
- // The number of consecutive ball placement failures of this team
- BallPlacementFailures *uint32 `protobuf:"varint,10,opt,name=ball_placement_failures,json=ballPlacementFailures" json:"ball_placement_failures,omitempty"`
- // Indicate if the team is able and allowed to place the ball
- CanPlaceBall *bool `protobuf:"varint,12,opt,name=can_place_ball,json=canPlaceBall" json:"can_place_ball,omitempty"`
- // The maximum number of bots allowed on the field based on division and cards
- MaxAllowedBots *uint32 `protobuf:"varint,13,opt,name=max_allowed_bots,json=maxAllowedBots" json:"max_allowed_bots,omitempty"`
- // The team has submitted an intent to substitute one or more robots at the next chance
- BotSubstitutionIntent *bool `protobuf:"varint,14,opt,name=bot_substitution_intent,json=botSubstitutionIntent" json:"bot_substitution_intent,omitempty"`
- // Indicate if the team reached the maximum allowed ball placement failures and is thus not allowed to place the ball anymore
- BallPlacementFailuresReached *bool `protobuf:"varint,15,opt,name=ball_placement_failures_reached,json=ballPlacementFailuresReached" json:"ball_placement_failures_reached,omitempty"`
- // The team is allowed to substitute one or more robots currently
- BotSubstitutionAllowed *bool `protobuf:"varint,16,opt,name=bot_substitution_allowed,json=botSubstitutionAllowed" json:"bot_substitution_allowed,omitempty"`
- // The number of bot substitutions left by the team in this halftime
- BotSubstitutionsLeft *uint32 `protobuf:"varint,17,opt,name=bot_substitutions_left,json=botSubstitutionsLeft" json:"bot_substitutions_left,omitempty"`
- // The number of microseconds left for current bot substitution
- BotSubstitutionTimeLeft *uint32 `protobuf:"varint,18,opt,name=bot_substitution_time_left,json=botSubstitutionTimeLeft" json:"bot_substitution_time_left,omitempty"`
- // The color of the hull of the robots of this team
- HullColor *HullColor `protobuf:"varint,19,opt,name=hull_color,json=hullColor,enum=HullColor" json:"hull_color,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *Referee_TeamInfo) Reset() {
- *x = Referee_TeamInfo{}
- mi := &file_gamecontroller_ssl_gc_referee_message_proto_msgTypes[2]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *Referee_TeamInfo) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*Referee_TeamInfo) ProtoMessage() {}
-
-func (x *Referee_TeamInfo) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_referee_message_proto_msgTypes[2]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use Referee_TeamInfo.ProtoReflect.Descriptor instead.
-func (*Referee_TeamInfo) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_referee_message_proto_rawDescGZIP(), []int{0, 0}
-}
-
-func (x *Referee_TeamInfo) GetName() string {
- if x != nil && x.Name != nil {
- return *x.Name
- }
- return ""
-}
-
-func (x *Referee_TeamInfo) GetScore() uint32 {
- if x != nil && x.Score != nil {
- return *x.Score
- }
- return 0
-}
-
-func (x *Referee_TeamInfo) GetRedCards() uint32 {
- if x != nil && x.RedCards != nil {
- return *x.RedCards
- }
- return 0
-}
-
-func (x *Referee_TeamInfo) GetYellowCardTimes() []uint32 {
- if x != nil {
- return x.YellowCardTimes
- }
- return nil
-}
-
-func (x *Referee_TeamInfo) GetYellowCards() uint32 {
- if x != nil && x.YellowCards != nil {
- return *x.YellowCards
- }
- return 0
-}
-
-func (x *Referee_TeamInfo) GetTimeouts() uint32 {
- if x != nil && x.Timeouts != nil {
- return *x.Timeouts
- }
- return 0
-}
-
-func (x *Referee_TeamInfo) GetTimeoutTime() uint32 {
- if x != nil && x.TimeoutTime != nil {
- return *x.TimeoutTime
- }
- return 0
-}
-
-func (x *Referee_TeamInfo) GetGoalkeeper() uint32 {
- if x != nil && x.Goalkeeper != nil {
- return *x.Goalkeeper
- }
- return 0
-}
-
-func (x *Referee_TeamInfo) GetFoulCounter() uint32 {
- if x != nil && x.FoulCounter != nil {
- return *x.FoulCounter
- }
- return 0
-}
-
-func (x *Referee_TeamInfo) GetBallPlacementFailures() uint32 {
- if x != nil && x.BallPlacementFailures != nil {
- return *x.BallPlacementFailures
- }
- return 0
-}
-
-func (x *Referee_TeamInfo) GetCanPlaceBall() bool {
- if x != nil && x.CanPlaceBall != nil {
- return *x.CanPlaceBall
- }
- return false
-}
-
-func (x *Referee_TeamInfo) GetMaxAllowedBots() uint32 {
- if x != nil && x.MaxAllowedBots != nil {
- return *x.MaxAllowedBots
- }
- return 0
-}
-
-func (x *Referee_TeamInfo) GetBotSubstitutionIntent() bool {
- if x != nil && x.BotSubstitutionIntent != nil {
- return *x.BotSubstitutionIntent
- }
- return false
-}
-
-func (x *Referee_TeamInfo) GetBallPlacementFailuresReached() bool {
- if x != nil && x.BallPlacementFailuresReached != nil {
- return *x.BallPlacementFailuresReached
- }
- return false
-}
-
-func (x *Referee_TeamInfo) GetBotSubstitutionAllowed() bool {
- if x != nil && x.BotSubstitutionAllowed != nil {
- return *x.BotSubstitutionAllowed
- }
- return false
-}
-
-func (x *Referee_TeamInfo) GetBotSubstitutionsLeft() uint32 {
- if x != nil && x.BotSubstitutionsLeft != nil {
- return *x.BotSubstitutionsLeft
- }
- return 0
-}
-
-func (x *Referee_TeamInfo) GetBotSubstitutionTimeLeft() uint32 {
- if x != nil && x.BotSubstitutionTimeLeft != nil {
- return *x.BotSubstitutionTimeLeft
- }
- return 0
-}
-
-func (x *Referee_TeamInfo) GetHullColor() HullColor {
- if x != nil && x.HullColor != nil {
- return *x.HullColor
- }
- return HullColor_HULL_COLOR_UNKNOWN
-}
-
-// The coordinates of the Designated Position. These are measured in
-// millimetres and correspond to SSL-Vision coordinates. These fields are
-// always either both present (in the case of a ball placement command) or
-// both absent (in the case of any other command).
-type Referee_Point struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- X *float32 `protobuf:"fixed32,1,req,name=x" json:"x,omitempty"`
- Y *float32 `protobuf:"fixed32,2,req,name=y" json:"y,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *Referee_Point) Reset() {
- *x = Referee_Point{}
- mi := &file_gamecontroller_ssl_gc_referee_message_proto_msgTypes[3]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *Referee_Point) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*Referee_Point) ProtoMessage() {}
-
-func (x *Referee_Point) ProtoReflect() protoreflect.Message {
- mi := &file_gamecontroller_ssl_gc_referee_message_proto_msgTypes[3]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use Referee_Point.ProtoReflect.Descriptor instead.
-func (*Referee_Point) Descriptor() ([]byte, []int) {
- return file_gamecontroller_ssl_gc_referee_message_proto_rawDescGZIP(), []int{0, 1}
-}
-
-func (x *Referee_Point) GetX() float32 {
- if x != nil && x.X != nil {
- return *x.X
- }
- return 0
-}
-
-func (x *Referee_Point) GetY() float32 {
- if x != nil && x.Y != nil {
- return *x.Y
- }
- return 0
-}
-
-var File_gamecontroller_ssl_gc_referee_message_proto protoreflect.FileDescriptor
-
-const file_gamecontroller_ssl_gc_referee_message_proto_rawDesc = "" +
- "\n" +
- "+gamecontroller/ssl_gc_referee_message.proto\x1a&gamecontroller/ssl_gc_game_event.proto\"\xfd\x12\n" +
- "\aReferee\x12+\n" +
- "\x11source_identifier\x18\x12 \x01(\tR\x10sourceIdentifier\x128\n" +
- "\n" +
- "match_type\x18\x13 \x01(\x0e2\n" +
- ".MatchType:\rUNKNOWN_MATCHR\tmatchType\x12)\n" +
- "\x10packet_timestamp\x18\x01 \x02(\x04R\x0fpacketTimestamp\x12$\n" +
- "\x05stage\x18\x02 \x02(\x0e2\x0e.Referee.StageR\x05stage\x12&\n" +
- "\x0fstage_time_left\x18\x03 \x01(\x12R\rstageTimeLeft\x12*\n" +
- "\acommand\x18\x04 \x02(\x0e2\x10.Referee.CommandR\acommand\x12'\n" +
- "\x0fcommand_counter\x18\x05 \x02(\rR\x0ecommandCounter\x12+\n" +
- "\x11command_timestamp\x18\x06 \x02(\x04R\x10commandTimestamp\x12)\n" +
- "\x06yellow\x18\a \x02(\v2\x11.Referee.TeamInfoR\x06yellow\x12%\n" +
- "\x04blue\x18\b \x02(\v2\x11.Referee.TeamInfoR\x04blue\x12?\n" +
- "\x13designated_position\x18\t \x01(\v2\x0e.Referee.PointR\x12designatedPosition\x12:\n" +
- "\x1ablue_team_on_positive_half\x18\n" +
- " \x01(\bR\x16blueTeamOnPositiveHalf\x123\n" +
- "\fnext_command\x18\f \x01(\x0e2\x10.Referee.CommandR\vnextCommand\x12+\n" +
- "\vgame_events\x18\x10 \x03(\v2\n" +
- ".GameEventR\n" +
- "gameEvents\x12I\n" +
- "\x14game_event_proposals\x18\x11 \x03(\v2\x17.GameEventProposalGroupR\x12gameEventProposals\x12A\n" +
- "\x1dcurrent_action_time_remaining\x18\x0f \x01(\x03R\x1acurrentActionTimeRemaining\x12%\n" +
- "\x0estatus_message\x18\x14 \x01(\tR\rstatusMessage\x1a\x85\x06\n" +
- "\bTeamInfo\x12\x12\n" +
- "\x04name\x18\x01 \x02(\tR\x04name\x12\x14\n" +
- "\x05score\x18\x02 \x02(\rR\x05score\x12\x1b\n" +
- "\tred_cards\x18\x03 \x02(\rR\bredCards\x12.\n" +
- "\x11yellow_card_times\x18\x04 \x03(\rB\x02\x10\x01R\x0fyellowCardTimes\x12!\n" +
- "\fyellow_cards\x18\x05 \x02(\rR\vyellowCards\x12\x1a\n" +
- "\btimeouts\x18\x06 \x02(\rR\btimeouts\x12!\n" +
- "\ftimeout_time\x18\a \x02(\rR\vtimeoutTime\x12\x1e\n" +
- "\n" +
- "goalkeeper\x18\b \x02(\rR\n" +
- "goalkeeper\x12!\n" +
- "\ffoul_counter\x18\t \x01(\rR\vfoulCounter\x126\n" +
- "\x17ball_placement_failures\x18\n" +
- " \x01(\rR\x15ballPlacementFailures\x12$\n" +
- "\x0ecan_place_ball\x18\f \x01(\bR\fcanPlaceBall\x12(\n" +
- "\x10max_allowed_bots\x18\r \x01(\rR\x0emaxAllowedBots\x126\n" +
- "\x17bot_substitution_intent\x18\x0e \x01(\bR\x15botSubstitutionIntent\x12E\n" +
- "\x1fball_placement_failures_reached\x18\x0f \x01(\bR\x1cballPlacementFailuresReached\x128\n" +
- "\x18bot_substitution_allowed\x18\x10 \x01(\bR\x16botSubstitutionAllowed\x124\n" +
- "\x16bot_substitutions_left\x18\x11 \x01(\rR\x14botSubstitutionsLeft\x12;\n" +
- "\x1abot_substitution_time_left\x18\x12 \x01(\rR\x17botSubstitutionTimeLeft\x12)\n" +
- "\n" +
- "hull_color\x18\x13 \x01(\x0e2\n" +
- ".HullColorR\thullColor\x1a#\n" +
- "\x05Point\x12\f\n" +
- "\x01x\x18\x01 \x02(\x02R\x01x\x12\f\n" +
- "\x01y\x18\x02 \x02(\x02R\x01y\"\xd1\x02\n" +
- "\x05Stage\x12\x19\n" +
- "\x15NORMAL_FIRST_HALF_PRE\x10\x00\x12\x15\n" +
- "\x11NORMAL_FIRST_HALF\x10\x01\x12\x14\n" +
- "\x10NORMAL_HALF_TIME\x10\x02\x12\x1a\n" +
- "\x16NORMAL_SECOND_HALF_PRE\x10\x03\x12\x16\n" +
- "\x12NORMAL_SECOND_HALF\x10\x04\x12\x14\n" +
- "\x10EXTRA_TIME_BREAK\x10\x05\x12\x18\n" +
- "\x14EXTRA_FIRST_HALF_PRE\x10\x06\x12\x14\n" +
- "\x10EXTRA_FIRST_HALF\x10\a\x12\x13\n" +
- "\x0fEXTRA_HALF_TIME\x10\b\x12\x19\n" +
- "\x15EXTRA_SECOND_HALF_PRE\x10\t\x12\x15\n" +
- "\x11EXTRA_SECOND_HALF\x10\n" +
- "\x12\x1a\n" +
- "\x16PENALTY_SHOOTOUT_BREAK\x10\v\x12\x14\n" +
- "\x10PENALTY_SHOOTOUT\x10\f\x12\r\n" +
- "\tPOST_GAME\x10\r\"\x96\x03\n" +
- "\aCommand\x12\b\n" +
- "\x04HALT\x10\x00\x12\b\n" +
- "\x04STOP\x10\x01\x12\x10\n" +
- "\fNORMAL_START\x10\x02\x12\x0f\n" +
- "\vFORCE_START\x10\x03\x12\x1a\n" +
- "\x16PREPARE_KICKOFF_YELLOW\x10\x04\x12\x18\n" +
- "\x14PREPARE_KICKOFF_BLUE\x10\x05\x12\x1a\n" +
- "\x16PREPARE_PENALTY_YELLOW\x10\x06\x12\x18\n" +
- "\x14PREPARE_PENALTY_BLUE\x10\a\x12\x16\n" +
- "\x12DIRECT_FREE_YELLOW\x10\b\x12\x14\n" +
- "\x10DIRECT_FREE_BLUE\x10\t\x12\x1c\n" +
- "\x14INDIRECT_FREE_YELLOW\x10\n" +
- "\x1a\x02\b\x01\x12\x1a\n" +
- "\x12INDIRECT_FREE_BLUE\x10\v\x1a\x02\b\x01\x12\x12\n" +
- "\x0eTIMEOUT_YELLOW\x10\f\x12\x10\n" +
- "\fTIMEOUT_BLUE\x10\r\x12\x13\n" +
- "\vGOAL_YELLOW\x10\x0e\x1a\x02\b\x01\x12\x11\n" +
- "\tGOAL_BLUE\x10\x0f\x1a\x02\b\x01\x12\x19\n" +
- "\x15BALL_PLACEMENT_YELLOW\x10\x10\x12\x17\n" +
- "\x13BALL_PLACEMENT_BLUE\x10\x11J\x04\b\v\x10\fJ\x04\b\r\x10\x0eJ\x04\b\x0e\x10\x0f\"q\n" +
- "\x16GameEventProposalGroup\x12\x0e\n" +
- "\x02id\x18\x03 \x01(\tR\x02id\x12+\n" +
- "\vgame_events\x18\x01 \x03(\v2\n" +
- ".GameEventR\n" +
- "gameEvents\x12\x1a\n" +
- "\baccepted\x18\x02 \x01(\bR\baccepted*T\n" +
- "\tMatchType\x12\x11\n" +
- "\rUNKNOWN_MATCH\x10\x00\x12\x0f\n" +
- "\vGROUP_PHASE\x10\x01\x12\x15\n" +
- "\x11ELIMINATION_PHASE\x10\x02\x12\f\n" +
- "\bFRIENDLY\x10\x03*N\n" +
- "\tHullColor\x12\x16\n" +
- "\x12HULL_COLOR_UNKNOWN\x10\x00\x12\x13\n" +
- "\x0fHULL_COLOR_DARK\x10\x01\x12\x14\n" +
- "\x10HULL_COLOR_LIGHT\x10\x02BeB\x18SslGcRefereeMessageProtoP\x01ZGgithub.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
-
-var (
- file_gamecontroller_ssl_gc_referee_message_proto_rawDescOnce sync.Once
- file_gamecontroller_ssl_gc_referee_message_proto_rawDescData []byte
-)
-
-func file_gamecontroller_ssl_gc_referee_message_proto_rawDescGZIP() []byte {
- file_gamecontroller_ssl_gc_referee_message_proto_rawDescOnce.Do(func() {
- file_gamecontroller_ssl_gc_referee_message_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_referee_message_proto_rawDesc), len(file_gamecontroller_ssl_gc_referee_message_proto_rawDesc)))
- })
- return file_gamecontroller_ssl_gc_referee_message_proto_rawDescData
-}
-
-var file_gamecontroller_ssl_gc_referee_message_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
-var file_gamecontroller_ssl_gc_referee_message_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
-var file_gamecontroller_ssl_gc_referee_message_proto_goTypes = []any{
- (MatchType)(0), // 0: MatchType
- (HullColor)(0), // 1: HullColor
- (Referee_Stage)(0), // 2: Referee.Stage
- (Referee_Command)(0), // 3: Referee.Command
- (*Referee)(nil), // 4: Referee
- (*GameEventProposalGroup)(nil), // 5: GameEventProposalGroup
- (*Referee_TeamInfo)(nil), // 6: Referee.TeamInfo
- (*Referee_Point)(nil), // 7: Referee.Point
- (*GameEvent)(nil), // 8: GameEvent
-}
-var file_gamecontroller_ssl_gc_referee_message_proto_depIdxs = []int32{
- 0, // 0: Referee.match_type:type_name -> MatchType
- 2, // 1: Referee.stage:type_name -> Referee.Stage
- 3, // 2: Referee.command:type_name -> Referee.Command
- 6, // 3: Referee.yellow:type_name -> Referee.TeamInfo
- 6, // 4: Referee.blue:type_name -> Referee.TeamInfo
- 7, // 5: Referee.designated_position:type_name -> Referee.Point
- 3, // 6: Referee.next_command:type_name -> Referee.Command
- 8, // 7: Referee.game_events:type_name -> GameEvent
- 5, // 8: Referee.game_event_proposals:type_name -> GameEventProposalGroup
- 8, // 9: GameEventProposalGroup.game_events:type_name -> GameEvent
- 1, // 10: Referee.TeamInfo.hull_color:type_name -> HullColor
- 11, // [11:11] is the sub-list for method output_type
- 11, // [11:11] is the sub-list for method input_type
- 11, // [11:11] is the sub-list for extension type_name
- 11, // [11:11] is the sub-list for extension extendee
- 0, // [0:11] is the sub-list for field type_name
-}
-
-func init() { file_gamecontroller_ssl_gc_referee_message_proto_init() }
-func file_gamecontroller_ssl_gc_referee_message_proto_init() {
- if File_gamecontroller_ssl_gc_referee_message_proto != nil {
- return
- }
- file_gamecontroller_ssl_gc_game_event_proto_init()
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: unsafe.Slice(unsafe.StringData(file_gamecontroller_ssl_gc_referee_message_proto_rawDesc), len(file_gamecontroller_ssl_gc_referee_message_proto_rawDesc)),
- NumEnums: 4,
- NumMessages: 4,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_gamecontroller_ssl_gc_referee_message_proto_goTypes,
- DependencyIndexes: file_gamecontroller_ssl_gc_referee_message_proto_depIdxs,
- EnumInfos: file_gamecontroller_ssl_gc_referee_message_proto_enumTypes,
- MessageInfos: file_gamecontroller_ssl_gc_referee_message_proto_msgTypes,
- }.Build()
- File_gamecontroller_ssl_gc_referee_message_proto = out.File
- file_gamecontroller_ssl_gc_referee_message_proto_goTypes = nil
- file_gamecontroller_ssl_gc_referee_message_proto_depIdxs = nil
-}
diff --git a/gui/internal/vision/ssl_vision_detection.pb.go b/gui/internal/vision/ssl_vision_detection.pb.go
deleted file mode 100644
index 040f87a..0000000
--- a/gui/internal/vision/ssl_vision_detection.pb.go
+++ /dev/null
@@ -1,439 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.36.6
-// protoc (unknown)
-// source: vision/ssl_vision_detection.proto
-
-package vision
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
- unsafe "unsafe"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-type SSL_DetectionBall struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // Confidence in [0-1] of the detection
- Confidence *float32 `protobuf:"fixed32,1,req,name=confidence" json:"confidence,omitempty"`
- Area *uint32 `protobuf:"varint,2,opt,name=area" json:"area,omitempty"`
- // X-coordinate in [mm] in global ssl-vision coordinate system
- X *float32 `protobuf:"fixed32,3,req,name=x" json:"x,omitempty"`
- // Y-coordinate in [mm] in global ssl-vision coordinate system
- Y *float32 `protobuf:"fixed32,4,req,name=y" json:"y,omitempty"`
- // Z-coordinate in [mm] in global ssl-vision coordinate system
- // Not supported by ssl-vision, but might be set by simulators
- Z *float32 `protobuf:"fixed32,5,opt,name=z" json:"z,omitempty"`
- // X-coordinate in [pixel] in the image
- PixelX *float32 `protobuf:"fixed32,6,req,name=pixel_x,json=pixelX" json:"pixel_x,omitempty"`
- // Y-coordinate in [pixel] in the image
- PixelY *float32 `protobuf:"fixed32,7,req,name=pixel_y,json=pixelY" json:"pixel_y,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *SSL_DetectionBall) Reset() {
- *x = SSL_DetectionBall{}
- mi := &file_vision_ssl_vision_detection_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_DetectionBall) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_DetectionBall) ProtoMessage() {}
-
-func (x *SSL_DetectionBall) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vision_detection_proto_msgTypes[0]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_DetectionBall.ProtoReflect.Descriptor instead.
-func (*SSL_DetectionBall) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vision_detection_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *SSL_DetectionBall) GetConfidence() float32 {
- if x != nil && x.Confidence != nil {
- return *x.Confidence
- }
- return 0
-}
-
-func (x *SSL_DetectionBall) GetArea() uint32 {
- if x != nil && x.Area != nil {
- return *x.Area
- }
- return 0
-}
-
-func (x *SSL_DetectionBall) GetX() float32 {
- if x != nil && x.X != nil {
- return *x.X
- }
- return 0
-}
-
-func (x *SSL_DetectionBall) GetY() float32 {
- if x != nil && x.Y != nil {
- return *x.Y
- }
- return 0
-}
-
-func (x *SSL_DetectionBall) GetZ() float32 {
- if x != nil && x.Z != nil {
- return *x.Z
- }
- return 0
-}
-
-func (x *SSL_DetectionBall) GetPixelX() float32 {
- if x != nil && x.PixelX != nil {
- return *x.PixelX
- }
- return 0
-}
-
-func (x *SSL_DetectionBall) GetPixelY() float32 {
- if x != nil && x.PixelY != nil {
- return *x.PixelY
- }
- return 0
-}
-
-type SSL_DetectionRobot struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // Confidence in [0-1] of the detection
- Confidence *float32 `protobuf:"fixed32,1,req,name=confidence" json:"confidence,omitempty"`
- // Id of the robot
- RobotId *uint32 `protobuf:"varint,2,opt,name=robot_id,json=robotId" json:"robot_id,omitempty"`
- // X-coordinate in [mm] in global ssl-vision coordinate system
- X *float32 `protobuf:"fixed32,3,req,name=x" json:"x,omitempty"`
- // Y-coordinate in [mm] in global ssl-vision coordinate system
- Y *float32 `protobuf:"fixed32,4,req,name=y" json:"y,omitempty"`
- // Orientation in [rad]
- Orientation *float32 `protobuf:"fixed32,5,opt,name=orientation" json:"orientation,omitempty"`
- // X-coordinate in [pixel] in the image
- PixelX *float32 `protobuf:"fixed32,6,req,name=pixel_x,json=pixelX" json:"pixel_x,omitempty"`
- // Y-coordinate in [pixel] in the image
- PixelY *float32 `protobuf:"fixed32,7,req,name=pixel_y,json=pixelY" json:"pixel_y,omitempty"`
- // Height, as configured in ssl-vision for the respective team
- Height *float32 `protobuf:"fixed32,8,opt,name=height" json:"height,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *SSL_DetectionRobot) Reset() {
- *x = SSL_DetectionRobot{}
- mi := &file_vision_ssl_vision_detection_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_DetectionRobot) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_DetectionRobot) ProtoMessage() {}
-
-func (x *SSL_DetectionRobot) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vision_detection_proto_msgTypes[1]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_DetectionRobot.ProtoReflect.Descriptor instead.
-func (*SSL_DetectionRobot) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vision_detection_proto_rawDescGZIP(), []int{1}
-}
-
-func (x *SSL_DetectionRobot) GetConfidence() float32 {
- if x != nil && x.Confidence != nil {
- return *x.Confidence
- }
- return 0
-}
-
-func (x *SSL_DetectionRobot) GetRobotId() uint32 {
- if x != nil && x.RobotId != nil {
- return *x.RobotId
- }
- return 0
-}
-
-func (x *SSL_DetectionRobot) GetX() float32 {
- if x != nil && x.X != nil {
- return *x.X
- }
- return 0
-}
-
-func (x *SSL_DetectionRobot) GetY() float32 {
- if x != nil && x.Y != nil {
- return *x.Y
- }
- return 0
-}
-
-func (x *SSL_DetectionRobot) GetOrientation() float32 {
- if x != nil && x.Orientation != nil {
- return *x.Orientation
- }
- return 0
-}
-
-func (x *SSL_DetectionRobot) GetPixelX() float32 {
- if x != nil && x.PixelX != nil {
- return *x.PixelX
- }
- return 0
-}
-
-func (x *SSL_DetectionRobot) GetPixelY() float32 {
- if x != nil && x.PixelY != nil {
- return *x.PixelY
- }
- return 0
-}
-
-func (x *SSL_DetectionRobot) GetHeight() float32 {
- if x != nil && x.Height != nil {
- return *x.Height
- }
- return 0
-}
-
-type SSL_DetectionFrame struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // monotonously increasing frame number
- FrameNumber *uint32 `protobuf:"varint,1,req,name=frame_number,json=frameNumber" json:"frame_number,omitempty"`
- // Unix timestamp in [seconds] at which the image has been received by ssl-vision
- TCapture *float64 `protobuf:"fixed64,2,req,name=t_capture,json=tCapture" json:"t_capture,omitempty"`
- // Unix timestamp in [seconds] at which this message has been sent to the network
- TSent *float64 `protobuf:"fixed64,3,req,name=t_sent,json=tSent" json:"t_sent,omitempty"`
- // Camera timestamp in [seconds] as reported by the camera, if supported
- // This is not necessarily a unix timestamp
- TCaptureCamera *float64 `protobuf:"fixed64,8,opt,name=t_capture_camera,json=tCaptureCamera" json:"t_capture_camera,omitempty"`
- // Internal VisionProcessor field for clock synchronization,
- // containing the time offset of received packets for each cam relative to the local clock.
- TOffsets []float32 `protobuf:"fixed32,9,rep,name=t_offsets,json=tOffsets" json:"t_offsets,omitempty"`
- // Identifier of the camera
- CameraId *uint32 `protobuf:"varint,4,req,name=camera_id,json=cameraId" json:"camera_id,omitempty"`
- // Detected balls
- Balls []*SSL_DetectionBall `protobuf:"bytes,5,rep,name=balls" json:"balls,omitempty"`
- // Detected yellow robots
- RobotsYellow []*SSL_DetectionRobot `protobuf:"bytes,6,rep,name=robots_yellow,json=robotsYellow" json:"robots_yellow,omitempty"`
- // Detected blue robots
- RobotsBlue []*SSL_DetectionRobot `protobuf:"bytes,7,rep,name=robots_blue,json=robotsBlue" json:"robots_blue,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *SSL_DetectionFrame) Reset() {
- *x = SSL_DetectionFrame{}
- mi := &file_vision_ssl_vision_detection_proto_msgTypes[2]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_DetectionFrame) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_DetectionFrame) ProtoMessage() {}
-
-func (x *SSL_DetectionFrame) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vision_detection_proto_msgTypes[2]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_DetectionFrame.ProtoReflect.Descriptor instead.
-func (*SSL_DetectionFrame) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vision_detection_proto_rawDescGZIP(), []int{2}
-}
-
-func (x *SSL_DetectionFrame) GetFrameNumber() uint32 {
- if x != nil && x.FrameNumber != nil {
- return *x.FrameNumber
- }
- return 0
-}
-
-func (x *SSL_DetectionFrame) GetTCapture() float64 {
- if x != nil && x.TCapture != nil {
- return *x.TCapture
- }
- return 0
-}
-
-func (x *SSL_DetectionFrame) GetTSent() float64 {
- if x != nil && x.TSent != nil {
- return *x.TSent
- }
- return 0
-}
-
-func (x *SSL_DetectionFrame) GetTCaptureCamera() float64 {
- if x != nil && x.TCaptureCamera != nil {
- return *x.TCaptureCamera
- }
- return 0
-}
-
-func (x *SSL_DetectionFrame) GetTOffsets() []float32 {
- if x != nil {
- return x.TOffsets
- }
- return nil
-}
-
-func (x *SSL_DetectionFrame) GetCameraId() uint32 {
- if x != nil && x.CameraId != nil {
- return *x.CameraId
- }
- return 0
-}
-
-func (x *SSL_DetectionFrame) GetBalls() []*SSL_DetectionBall {
- if x != nil {
- return x.Balls
- }
- return nil
-}
-
-func (x *SSL_DetectionFrame) GetRobotsYellow() []*SSL_DetectionRobot {
- if x != nil {
- return x.RobotsYellow
- }
- return nil
-}
-
-func (x *SSL_DetectionFrame) GetRobotsBlue() []*SSL_DetectionRobot {
- if x != nil {
- return x.RobotsBlue
- }
- return nil
-}
-
-var File_vision_ssl_vision_detection_proto protoreflect.FileDescriptor
-
-const file_vision_ssl_vision_detection_proto_rawDesc = "" +
- "\n" +
- "!vision/ssl_vision_detection.proto\"\xa3\x01\n" +
- "\x11SSL_DetectionBall\x12\x1e\n" +
- "\n" +
- "confidence\x18\x01 \x02(\x02R\n" +
- "confidence\x12\x12\n" +
- "\x04area\x18\x02 \x01(\rR\x04area\x12\f\n" +
- "\x01x\x18\x03 \x02(\x02R\x01x\x12\f\n" +
- "\x01y\x18\x04 \x02(\x02R\x01y\x12\f\n" +
- "\x01z\x18\x05 \x01(\x02R\x01z\x12\x17\n" +
- "\apixel_x\x18\x06 \x02(\x02R\x06pixelX\x12\x17\n" +
- "\apixel_y\x18\a \x02(\x02R\x06pixelY\"\xd7\x01\n" +
- "\x12SSL_DetectionRobot\x12\x1e\n" +
- "\n" +
- "confidence\x18\x01 \x02(\x02R\n" +
- "confidence\x12\x19\n" +
- "\brobot_id\x18\x02 \x01(\rR\arobotId\x12\f\n" +
- "\x01x\x18\x03 \x02(\x02R\x01x\x12\f\n" +
- "\x01y\x18\x04 \x02(\x02R\x01y\x12 \n" +
- "\vorientation\x18\x05 \x01(\x02R\vorientation\x12\x17\n" +
- "\apixel_x\x18\x06 \x02(\x02R\x06pixelX\x12\x17\n" +
- "\apixel_y\x18\a \x02(\x02R\x06pixelY\x12\x16\n" +
- "\x06height\x18\b \x01(\x02R\x06height\"\xe9\x02\n" +
- "\x12SSL_DetectionFrame\x12!\n" +
- "\fframe_number\x18\x01 \x02(\rR\vframeNumber\x12\x1b\n" +
- "\tt_capture\x18\x02 \x02(\x01R\btCapture\x12\x15\n" +
- "\x06t_sent\x18\x03 \x02(\x01R\x05tSent\x12(\n" +
- "\x10t_capture_camera\x18\b \x01(\x01R\x0etCaptureCamera\x12\x1b\n" +
- "\tt_offsets\x18\t \x03(\x02R\btOffsets\x12\x1b\n" +
- "\tcamera_id\x18\x04 \x02(\rR\bcameraId\x12(\n" +
- "\x05balls\x18\x05 \x03(\v2\x12.SSL_DetectionBallR\x05balls\x128\n" +
- "\rrobots_yellow\x18\x06 \x03(\v2\x13.SSL_DetectionRobotR\frobotsYellow\x124\n" +
- "\vrobots_blue\x18\a \x03(\v2\x13.SSL_DetectionRobotR\n" +
- "robotsBlueB\\B\x17SslVisionDetectionProtoP\x01Z?github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
-
-var (
- file_vision_ssl_vision_detection_proto_rawDescOnce sync.Once
- file_vision_ssl_vision_detection_proto_rawDescData []byte
-)
-
-func file_vision_ssl_vision_detection_proto_rawDescGZIP() []byte {
- file_vision_ssl_vision_detection_proto_rawDescOnce.Do(func() {
- file_vision_ssl_vision_detection_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_detection_proto_rawDesc), len(file_vision_ssl_vision_detection_proto_rawDesc)))
- })
- return file_vision_ssl_vision_detection_proto_rawDescData
-}
-
-var file_vision_ssl_vision_detection_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
-var file_vision_ssl_vision_detection_proto_goTypes = []any{
- (*SSL_DetectionBall)(nil), // 0: SSL_DetectionBall
- (*SSL_DetectionRobot)(nil), // 1: SSL_DetectionRobot
- (*SSL_DetectionFrame)(nil), // 2: SSL_DetectionFrame
-}
-var file_vision_ssl_vision_detection_proto_depIdxs = []int32{
- 0, // 0: SSL_DetectionFrame.balls:type_name -> SSL_DetectionBall
- 1, // 1: SSL_DetectionFrame.robots_yellow:type_name -> SSL_DetectionRobot
- 1, // 2: SSL_DetectionFrame.robots_blue:type_name -> SSL_DetectionRobot
- 3, // [3:3] is the sub-list for method output_type
- 3, // [3:3] is the sub-list for method input_type
- 3, // [3:3] is the sub-list for extension type_name
- 3, // [3:3] is the sub-list for extension extendee
- 0, // [0:3] is the sub-list for field type_name
-}
-
-func init() { file_vision_ssl_vision_detection_proto_init() }
-func file_vision_ssl_vision_detection_proto_init() {
- if File_vision_ssl_vision_detection_proto != nil {
- return
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_detection_proto_rawDesc), len(file_vision_ssl_vision_detection_proto_rawDesc)),
- NumEnums: 0,
- NumMessages: 3,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_vision_ssl_vision_detection_proto_goTypes,
- DependencyIndexes: file_vision_ssl_vision_detection_proto_depIdxs,
- MessageInfos: file_vision_ssl_vision_detection_proto_msgTypes,
- }.Build()
- File_vision_ssl_vision_detection_proto = out.File
- file_vision_ssl_vision_detection_proto_goTypes = nil
- file_vision_ssl_vision_detection_proto_depIdxs = nil
-}
diff --git a/gui/internal/vision/ssl_vision_detection_tracked.pb.go b/gui/internal/vision/ssl_vision_detection_tracked.pb.go
deleted file mode 100644
index d0b462a..0000000
--- a/gui/internal/vision/ssl_vision_detection_tracked.pb.go
+++ /dev/null
@@ -1,544 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.36.6
-// protoc (unknown)
-// source: vision/ssl_vision_detection_tracked.proto
-
-package vision
-
-import (
- gamecontroller "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
- unsafe "unsafe"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-// Capabilities that a source implementation can have
-type Capability int32
-
-const (
- Capability_CAPABILITY_UNKNOWN Capability = 0
- Capability_CAPABILITY_DETECT_FLYING_BALLS Capability = 1
- Capability_CAPABILITY_DETECT_MULTIPLE_BALLS Capability = 2
- Capability_CAPABILITY_DETECT_KICKED_BALLS Capability = 3
-)
-
-// Enum value maps for Capability.
-var (
- Capability_name = map[int32]string{
- 0: "CAPABILITY_UNKNOWN",
- 1: "CAPABILITY_DETECT_FLYING_BALLS",
- 2: "CAPABILITY_DETECT_MULTIPLE_BALLS",
- 3: "CAPABILITY_DETECT_KICKED_BALLS",
- }
- Capability_value = map[string]int32{
- "CAPABILITY_UNKNOWN": 0,
- "CAPABILITY_DETECT_FLYING_BALLS": 1,
- "CAPABILITY_DETECT_MULTIPLE_BALLS": 2,
- "CAPABILITY_DETECT_KICKED_BALLS": 3,
- }
-)
-
-func (x Capability) Enum() *Capability {
- p := new(Capability)
- *p = x
- return p
-}
-
-func (x Capability) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (Capability) Descriptor() protoreflect.EnumDescriptor {
- return file_vision_ssl_vision_detection_tracked_proto_enumTypes[0].Descriptor()
-}
-
-func (Capability) Type() protoreflect.EnumType {
- return &file_vision_ssl_vision_detection_tracked_proto_enumTypes[0]
-}
-
-func (x Capability) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Do not use.
-func (x *Capability) UnmarshalJSON(b []byte) error {
- num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
- if err != nil {
- return err
- }
- *x = Capability(num)
- return nil
-}
-
-// Deprecated: Use Capability.Descriptor instead.
-func (Capability) EnumDescriptor() ([]byte, []int) {
- return file_vision_ssl_vision_detection_tracked_proto_rawDescGZIP(), []int{0}
-}
-
-// A single tracked ball
-type TrackedBall struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // The position (x, y, height) [m] in the ssl-vision coordinate system
- Pos *gamecontroller.Vector3 `protobuf:"bytes,1,req,name=pos" json:"pos,omitempty"`
- // The velocity [m/s] in the ssl-vision coordinate system
- Vel *gamecontroller.Vector3 `protobuf:"bytes,2,opt,name=vel" json:"vel,omitempty"`
- // The visibility of the ball
- // A value between 0 (not visible) and 1 (visible)
- // The exact implementation depends on the source software
- Visibility *float32 `protobuf:"fixed32,3,opt,name=visibility" json:"visibility,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *TrackedBall) Reset() {
- *x = TrackedBall{}
- mi := &file_vision_ssl_vision_detection_tracked_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *TrackedBall) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*TrackedBall) ProtoMessage() {}
-
-func (x *TrackedBall) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vision_detection_tracked_proto_msgTypes[0]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use TrackedBall.ProtoReflect.Descriptor instead.
-func (*TrackedBall) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vision_detection_tracked_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *TrackedBall) GetPos() *gamecontroller.Vector3 {
- if x != nil {
- return x.Pos
- }
- return nil
-}
-
-func (x *TrackedBall) GetVel() *gamecontroller.Vector3 {
- if x != nil {
- return x.Vel
- }
- return nil
-}
-
-func (x *TrackedBall) GetVisibility() float32 {
- if x != nil && x.Visibility != nil {
- return *x.Visibility
- }
- return 0
-}
-
-// A ball kicked by a robot, including predictions when the ball will come to a stop
-type KickedBall struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // The initial position [m] from which the ball was kicked
- Pos *gamecontroller.Vector2 `protobuf:"bytes,1,req,name=pos" json:"pos,omitempty"`
- // The initial velocity [m/s] with which the ball was kicked
- Vel *gamecontroller.Vector3 `protobuf:"bytes,2,req,name=vel" json:"vel,omitempty"`
- // The unix timestamp [s] when the kick was performed
- StartTimestamp *float64 `protobuf:"fixed64,3,req,name=start_timestamp,json=startTimestamp" json:"start_timestamp,omitempty"`
- // The predicted unix timestamp [s] when the ball comes to a stop
- StopTimestamp *float64 `protobuf:"fixed64,4,opt,name=stop_timestamp,json=stopTimestamp" json:"stop_timestamp,omitempty"`
- // The predicted position [m] at which the ball will come to a stop
- StopPos *gamecontroller.Vector2 `protobuf:"bytes,5,opt,name=stop_pos,json=stopPos" json:"stop_pos,omitempty"`
- // The robot that kicked the ball
- RobotId *gamecontroller.RobotId `protobuf:"bytes,6,opt,name=robot_id,json=robotId" json:"robot_id,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *KickedBall) Reset() {
- *x = KickedBall{}
- mi := &file_vision_ssl_vision_detection_tracked_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *KickedBall) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*KickedBall) ProtoMessage() {}
-
-func (x *KickedBall) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vision_detection_tracked_proto_msgTypes[1]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use KickedBall.ProtoReflect.Descriptor instead.
-func (*KickedBall) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vision_detection_tracked_proto_rawDescGZIP(), []int{1}
-}
-
-func (x *KickedBall) GetPos() *gamecontroller.Vector2 {
- if x != nil {
- return x.Pos
- }
- return nil
-}
-
-func (x *KickedBall) GetVel() *gamecontroller.Vector3 {
- if x != nil {
- return x.Vel
- }
- return nil
-}
-
-func (x *KickedBall) GetStartTimestamp() float64 {
- if x != nil && x.StartTimestamp != nil {
- return *x.StartTimestamp
- }
- return 0
-}
-
-func (x *KickedBall) GetStopTimestamp() float64 {
- if x != nil && x.StopTimestamp != nil {
- return *x.StopTimestamp
- }
- return 0
-}
-
-func (x *KickedBall) GetStopPos() *gamecontroller.Vector2 {
- if x != nil {
- return x.StopPos
- }
- return nil
-}
-
-func (x *KickedBall) GetRobotId() *gamecontroller.RobotId {
- if x != nil {
- return x.RobotId
- }
- return nil
-}
-
-// A single tracked robot
-type TrackedRobot struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- RobotId *gamecontroller.RobotId `protobuf:"bytes,1,req,name=robot_id,json=robotId" json:"robot_id,omitempty"`
- // The position [m] in the ssl-vision coordinate system
- Pos *gamecontroller.Vector2 `protobuf:"bytes,2,req,name=pos" json:"pos,omitempty"`
- // The orientation [rad] in the ssl-vision coordinate system
- Orientation *float32 `protobuf:"fixed32,3,req,name=orientation" json:"orientation,omitempty"`
- // The velocity [m/s] in the ssl-vision coordinate system
- Vel *gamecontroller.Vector2 `protobuf:"bytes,4,opt,name=vel" json:"vel,omitempty"`
- // The angular velocity [rad/s] in the ssl-vision coordinate system
- VelAngular *float32 `protobuf:"fixed32,5,opt,name=vel_angular,json=velAngular" json:"vel_angular,omitempty"`
- // The visibility of the robot
- // A value between 0 (not visible) and 1 (visible)
- // The exact implementation depends on the source software
- Visibility *float32 `protobuf:"fixed32,6,opt,name=visibility" json:"visibility,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *TrackedRobot) Reset() {
- *x = TrackedRobot{}
- mi := &file_vision_ssl_vision_detection_tracked_proto_msgTypes[2]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *TrackedRobot) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*TrackedRobot) ProtoMessage() {}
-
-func (x *TrackedRobot) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vision_detection_tracked_proto_msgTypes[2]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use TrackedRobot.ProtoReflect.Descriptor instead.
-func (*TrackedRobot) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vision_detection_tracked_proto_rawDescGZIP(), []int{2}
-}
-
-func (x *TrackedRobot) GetRobotId() *gamecontroller.RobotId {
- if x != nil {
- return x.RobotId
- }
- return nil
-}
-
-func (x *TrackedRobot) GetPos() *gamecontroller.Vector2 {
- if x != nil {
- return x.Pos
- }
- return nil
-}
-
-func (x *TrackedRobot) GetOrientation() float32 {
- if x != nil && x.Orientation != nil {
- return *x.Orientation
- }
- return 0
-}
-
-func (x *TrackedRobot) GetVel() *gamecontroller.Vector2 {
- if x != nil {
- return x.Vel
- }
- return nil
-}
-
-func (x *TrackedRobot) GetVelAngular() float32 {
- if x != nil && x.VelAngular != nil {
- return *x.VelAngular
- }
- return 0
-}
-
-func (x *TrackedRobot) GetVisibility() float32 {
- if x != nil && x.Visibility != nil {
- return *x.Visibility
- }
- return 0
-}
-
-// A frame that contains all currently tracked objects on the field on all cameras
-type TrackedFrame struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // A monotonous increasing frame counter
- FrameNumber *uint32 `protobuf:"varint,1,req,name=frame_number,json=frameNumber" json:"frame_number,omitempty"`
- // The unix timestamp in [s] of the data
- // If timestamp is larger than timestamp_captured, the source has applied a prediction already
- Timestamp *float64 `protobuf:"fixed64,2,req,name=timestamp" json:"timestamp,omitempty"`
- // The list of detected balls
- // The first ball is the primary one
- // Sources may add additional balls based on their capabilities
- Balls []*TrackedBall `protobuf:"bytes,3,rep,name=balls" json:"balls,omitempty"`
- // The list of detected robots of both teams
- Robots []*TrackedRobot `protobuf:"bytes,4,rep,name=robots" json:"robots,omitempty"`
- // Information about a kicked ball, if the ball was kicked by a robot and is still moving
- // Note: This field is optional. Some source implementations might not set this at any time
- KickedBall *KickedBall `protobuf:"bytes,5,opt,name=kicked_ball,json=kickedBall" json:"kicked_ball,omitempty"`
- // List of capabilities of the source implementation
- Capabilities []Capability `protobuf:"varint,6,rep,name=capabilities,enum=Capability" json:"capabilities,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *TrackedFrame) Reset() {
- *x = TrackedFrame{}
- mi := &file_vision_ssl_vision_detection_tracked_proto_msgTypes[3]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *TrackedFrame) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*TrackedFrame) ProtoMessage() {}
-
-func (x *TrackedFrame) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vision_detection_tracked_proto_msgTypes[3]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use TrackedFrame.ProtoReflect.Descriptor instead.
-func (*TrackedFrame) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vision_detection_tracked_proto_rawDescGZIP(), []int{3}
-}
-
-func (x *TrackedFrame) GetFrameNumber() uint32 {
- if x != nil && x.FrameNumber != nil {
- return *x.FrameNumber
- }
- return 0
-}
-
-func (x *TrackedFrame) GetTimestamp() float64 {
- if x != nil && x.Timestamp != nil {
- return *x.Timestamp
- }
- return 0
-}
-
-func (x *TrackedFrame) GetBalls() []*TrackedBall {
- if x != nil {
- return x.Balls
- }
- return nil
-}
-
-func (x *TrackedFrame) GetRobots() []*TrackedRobot {
- if x != nil {
- return x.Robots
- }
- return nil
-}
-
-func (x *TrackedFrame) GetKickedBall() *KickedBall {
- if x != nil {
- return x.KickedBall
- }
- return nil
-}
-
-func (x *TrackedFrame) GetCapabilities() []Capability {
- if x != nil {
- return x.Capabilities
- }
- return nil
-}
-
-var File_vision_ssl_vision_detection_tracked_proto protoreflect.FileDescriptor
-
-const file_vision_ssl_vision_detection_tracked_proto_rawDesc = "" +
- "\n" +
- ")vision/ssl_vision_detection_tracked.proto\x1a\"gamecontroller/ssl_gc_common.proto\x1a$gamecontroller/ssl_gc_geometry.proto\"e\n" +
- "\vTrackedBall\x12\x1a\n" +
- "\x03pos\x18\x01 \x02(\v2\b.Vector3R\x03pos\x12\x1a\n" +
- "\x03vel\x18\x02 \x01(\v2\b.Vector3R\x03vel\x12\x1e\n" +
- "\n" +
- "visibility\x18\x03 \x01(\x02R\n" +
- "visibility\"\xde\x01\n" +
- "\n" +
- "KickedBall\x12\x1a\n" +
- "\x03pos\x18\x01 \x02(\v2\b.Vector2R\x03pos\x12\x1a\n" +
- "\x03vel\x18\x02 \x02(\v2\b.Vector3R\x03vel\x12'\n" +
- "\x0fstart_timestamp\x18\x03 \x02(\x01R\x0estartTimestamp\x12%\n" +
- "\x0estop_timestamp\x18\x04 \x01(\x01R\rstopTimestamp\x12#\n" +
- "\bstop_pos\x18\x05 \x01(\v2\b.Vector2R\astopPos\x12#\n" +
- "\brobot_id\x18\x06 \x01(\v2\b.RobotIdR\arobotId\"\xce\x01\n" +
- "\fTrackedRobot\x12#\n" +
- "\brobot_id\x18\x01 \x02(\v2\b.RobotIdR\arobotId\x12\x1a\n" +
- "\x03pos\x18\x02 \x02(\v2\b.Vector2R\x03pos\x12 \n" +
- "\vorientation\x18\x03 \x02(\x02R\vorientation\x12\x1a\n" +
- "\x03vel\x18\x04 \x01(\v2\b.Vector2R\x03vel\x12\x1f\n" +
- "\vvel_angular\x18\x05 \x01(\x02R\n" +
- "velAngular\x12\x1e\n" +
- "\n" +
- "visibility\x18\x06 \x01(\x02R\n" +
- "visibility\"\xf9\x01\n" +
- "\fTrackedFrame\x12!\n" +
- "\fframe_number\x18\x01 \x02(\rR\vframeNumber\x12\x1c\n" +
- "\ttimestamp\x18\x02 \x02(\x01R\ttimestamp\x12\"\n" +
- "\x05balls\x18\x03 \x03(\v2\f.TrackedBallR\x05balls\x12%\n" +
- "\x06robots\x18\x04 \x03(\v2\r.TrackedRobotR\x06robots\x12,\n" +
- "\vkicked_ball\x18\x05 \x01(\v2\v.KickedBallR\n" +
- "kickedBall\x12/\n" +
- "\fcapabilities\x18\x06 \x03(\x0e2\v.CapabilityR\fcapabilities*\x92\x01\n" +
- "\n" +
- "Capability\x12\x16\n" +
- "\x12CAPABILITY_UNKNOWN\x10\x00\x12\"\n" +
- "\x1eCAPABILITY_DETECT_FLYING_BALLS\x10\x01\x12$\n" +
- " CAPABILITY_DETECT_MULTIPLE_BALLS\x10\x02\x12\"\n" +
- "\x1eCAPABILITY_DETECT_KICKED_BALLS\x10\x03BcB\x1eSslVisionDetectionTrackedProtoP\x01Z?github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
-
-var (
- file_vision_ssl_vision_detection_tracked_proto_rawDescOnce sync.Once
- file_vision_ssl_vision_detection_tracked_proto_rawDescData []byte
-)
-
-func file_vision_ssl_vision_detection_tracked_proto_rawDescGZIP() []byte {
- file_vision_ssl_vision_detection_tracked_proto_rawDescOnce.Do(func() {
- file_vision_ssl_vision_detection_tracked_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_detection_tracked_proto_rawDesc), len(file_vision_ssl_vision_detection_tracked_proto_rawDesc)))
- })
- return file_vision_ssl_vision_detection_tracked_proto_rawDescData
-}
-
-var file_vision_ssl_vision_detection_tracked_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
-var file_vision_ssl_vision_detection_tracked_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
-var file_vision_ssl_vision_detection_tracked_proto_goTypes = []any{
- (Capability)(0), // 0: Capability
- (*TrackedBall)(nil), // 1: TrackedBall
- (*KickedBall)(nil), // 2: KickedBall
- (*TrackedRobot)(nil), // 3: TrackedRobot
- (*TrackedFrame)(nil), // 4: TrackedFrame
- (*gamecontroller.Vector3)(nil), // 5: Vector3
- (*gamecontroller.Vector2)(nil), // 6: Vector2
- (*gamecontroller.RobotId)(nil), // 7: RobotId
-}
-var file_vision_ssl_vision_detection_tracked_proto_depIdxs = []int32{
- 5, // 0: TrackedBall.pos:type_name -> Vector3
- 5, // 1: TrackedBall.vel:type_name -> Vector3
- 6, // 2: KickedBall.pos:type_name -> Vector2
- 5, // 3: KickedBall.vel:type_name -> Vector3
- 6, // 4: KickedBall.stop_pos:type_name -> Vector2
- 7, // 5: KickedBall.robot_id:type_name -> RobotId
- 7, // 6: TrackedRobot.robot_id:type_name -> RobotId
- 6, // 7: TrackedRobot.pos:type_name -> Vector2
- 6, // 8: TrackedRobot.vel:type_name -> Vector2
- 1, // 9: TrackedFrame.balls:type_name -> TrackedBall
- 3, // 10: TrackedFrame.robots:type_name -> TrackedRobot
- 2, // 11: TrackedFrame.kicked_ball:type_name -> KickedBall
- 0, // 12: TrackedFrame.capabilities:type_name -> Capability
- 13, // [13:13] is the sub-list for method output_type
- 13, // [13:13] is the sub-list for method input_type
- 13, // [13:13] is the sub-list for extension type_name
- 13, // [13:13] is the sub-list for extension extendee
- 0, // [0:13] is the sub-list for field type_name
-}
-
-func init() { file_vision_ssl_vision_detection_tracked_proto_init() }
-func file_vision_ssl_vision_detection_tracked_proto_init() {
- if File_vision_ssl_vision_detection_tracked_proto != nil {
- return
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_detection_tracked_proto_rawDesc), len(file_vision_ssl_vision_detection_tracked_proto_rawDesc)),
- NumEnums: 1,
- NumMessages: 4,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_vision_ssl_vision_detection_tracked_proto_goTypes,
- DependencyIndexes: file_vision_ssl_vision_detection_tracked_proto_depIdxs,
- EnumInfos: file_vision_ssl_vision_detection_tracked_proto_enumTypes,
- MessageInfos: file_vision_ssl_vision_detection_tracked_proto_msgTypes,
- }.Build()
- File_vision_ssl_vision_detection_tracked_proto = out.File
- file_vision_ssl_vision_detection_tracked_proto_goTypes = nil
- file_vision_ssl_vision_detection_tracked_proto_depIdxs = nil
-}
diff --git a/gui/internal/vision/ssl_vision_geometry.pb.go b/gui/internal/vision/ssl_vision_geometry.pb.go
deleted file mode 100644
index e93b604..0000000
--- a/gui/internal/vision/ssl_vision_geometry.pb.go
+++ /dev/null
@@ -1,1135 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.36.6
-// protoc (unknown)
-// source: vision/ssl_vision_geometry.proto
-
-package vision
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
- unsafe "unsafe"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-type SSL_FieldShapeType int32
-
-const (
- SSL_FieldShapeType_Undefined SSL_FieldShapeType = 0
- SSL_FieldShapeType_CenterCircle SSL_FieldShapeType = 1
- SSL_FieldShapeType_TopTouchLine SSL_FieldShapeType = 2
- SSL_FieldShapeType_BottomTouchLine SSL_FieldShapeType = 3
- SSL_FieldShapeType_LeftGoalLine SSL_FieldShapeType = 4
- SSL_FieldShapeType_RightGoalLine SSL_FieldShapeType = 5
- SSL_FieldShapeType_HalfwayLine SSL_FieldShapeType = 6
- SSL_FieldShapeType_CenterLine SSL_FieldShapeType = 7
- SSL_FieldShapeType_LeftPenaltyStretch SSL_FieldShapeType = 8
- SSL_FieldShapeType_RightPenaltyStretch SSL_FieldShapeType = 9
- SSL_FieldShapeType_LeftFieldLeftPenaltyStretch SSL_FieldShapeType = 10
- SSL_FieldShapeType_LeftFieldRightPenaltyStretch SSL_FieldShapeType = 11
- SSL_FieldShapeType_RightFieldLeftPenaltyStretch SSL_FieldShapeType = 12
- SSL_FieldShapeType_RightFieldRightPenaltyStretch SSL_FieldShapeType = 13
-)
-
-// Enum value maps for SSL_FieldShapeType.
-var (
- SSL_FieldShapeType_name = map[int32]string{
- 0: "Undefined",
- 1: "CenterCircle",
- 2: "TopTouchLine",
- 3: "BottomTouchLine",
- 4: "LeftGoalLine",
- 5: "RightGoalLine",
- 6: "HalfwayLine",
- 7: "CenterLine",
- 8: "LeftPenaltyStretch",
- 9: "RightPenaltyStretch",
- 10: "LeftFieldLeftPenaltyStretch",
- 11: "LeftFieldRightPenaltyStretch",
- 12: "RightFieldLeftPenaltyStretch",
- 13: "RightFieldRightPenaltyStretch",
- }
- SSL_FieldShapeType_value = map[string]int32{
- "Undefined": 0,
- "CenterCircle": 1,
- "TopTouchLine": 2,
- "BottomTouchLine": 3,
- "LeftGoalLine": 4,
- "RightGoalLine": 5,
- "HalfwayLine": 6,
- "CenterLine": 7,
- "LeftPenaltyStretch": 8,
- "RightPenaltyStretch": 9,
- "LeftFieldLeftPenaltyStretch": 10,
- "LeftFieldRightPenaltyStretch": 11,
- "RightFieldLeftPenaltyStretch": 12,
- "RightFieldRightPenaltyStretch": 13,
- }
-)
-
-func (x SSL_FieldShapeType) Enum() *SSL_FieldShapeType {
- p := new(SSL_FieldShapeType)
- *p = x
- return p
-}
-
-func (x SSL_FieldShapeType) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (SSL_FieldShapeType) Descriptor() protoreflect.EnumDescriptor {
- return file_vision_ssl_vision_geometry_proto_enumTypes[0].Descriptor()
-}
-
-func (SSL_FieldShapeType) Type() protoreflect.EnumType {
- return &file_vision_ssl_vision_geometry_proto_enumTypes[0]
-}
-
-func (x SSL_FieldShapeType) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Do not use.
-func (x *SSL_FieldShapeType) UnmarshalJSON(b []byte) error {
- num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
- if err != nil {
- return err
- }
- *x = SSL_FieldShapeType(num)
- return nil
-}
-
-// Deprecated: Use SSL_FieldShapeType.Descriptor instead.
-func (SSL_FieldShapeType) EnumDescriptor() ([]byte, []int) {
- return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{0}
-}
-
-// A 2D float vector.
-type Vector2F struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // X-coordinate in mm
- X *float32 `protobuf:"fixed32,1,req,name=x" json:"x,omitempty"`
- // Y-coordinate in mm
- Y *float32 `protobuf:"fixed32,2,req,name=y" json:"y,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *Vector2F) Reset() {
- *x = Vector2F{}
- mi := &file_vision_ssl_vision_geometry_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *Vector2F) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*Vector2F) ProtoMessage() {}
-
-func (x *Vector2F) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vision_geometry_proto_msgTypes[0]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use Vector2F.ProtoReflect.Descriptor instead.
-func (*Vector2F) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *Vector2F) GetX() float32 {
- if x != nil && x.X != nil {
- return *x.X
- }
- return 0
-}
-
-func (x *Vector2F) GetY() float32 {
- if x != nil && x.Y != nil {
- return *x.Y
- }
- return 0
-}
-
-// Represents a field marking as a line segment represented by a start point p1,
-// and end point p2, and a line thickness. The start and end points are along
-// the center of the line, so the thickness of the line extends by thickness / 2
-// on either side of the line.
-type SSL_FieldLineSegment struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // Name of this field marking.
- Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"`
- // Start point of the line segment.
- P1 *Vector2F `protobuf:"bytes,2,req,name=p1" json:"p1,omitempty"`
- // End point of the line segment.
- P2 *Vector2F `protobuf:"bytes,3,req,name=p2" json:"p2,omitempty"`
- // Thickness of the line segment.
- Thickness *float32 `protobuf:"fixed32,4,req,name=thickness" json:"thickness,omitempty"`
- // The type of this shape
- Type *SSL_FieldShapeType `protobuf:"varint,5,opt,name=type,enum=SSL_FieldShapeType" json:"type,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *SSL_FieldLineSegment) Reset() {
- *x = SSL_FieldLineSegment{}
- mi := &file_vision_ssl_vision_geometry_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_FieldLineSegment) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_FieldLineSegment) ProtoMessage() {}
-
-func (x *SSL_FieldLineSegment) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vision_geometry_proto_msgTypes[1]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_FieldLineSegment.ProtoReflect.Descriptor instead.
-func (*SSL_FieldLineSegment) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{1}
-}
-
-func (x *SSL_FieldLineSegment) GetName() string {
- if x != nil && x.Name != nil {
- return *x.Name
- }
- return ""
-}
-
-func (x *SSL_FieldLineSegment) GetP1() *Vector2F {
- if x != nil {
- return x.P1
- }
- return nil
-}
-
-func (x *SSL_FieldLineSegment) GetP2() *Vector2F {
- if x != nil {
- return x.P2
- }
- return nil
-}
-
-func (x *SSL_FieldLineSegment) GetThickness() float32 {
- if x != nil && x.Thickness != nil {
- return *x.Thickness
- }
- return 0
-}
-
-func (x *SSL_FieldLineSegment) GetType() SSL_FieldShapeType {
- if x != nil && x.Type != nil {
- return *x.Type
- }
- return SSL_FieldShapeType_Undefined
-}
-
-// Represents a field marking as a circular arc segment represented by center point, a
-// start angle, an end angle, and an arc thickness.
-type SSL_FieldCircularArc struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // Name of this field marking.
- Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"`
- // Center point of the circular arc.
- Center *Vector2F `protobuf:"bytes,2,req,name=center" json:"center,omitempty"`
- // Radius of the arc.
- Radius *float32 `protobuf:"fixed32,3,req,name=radius" json:"radius,omitempty"`
- // Start angle in counter-clockwise order.
- A1 *float32 `protobuf:"fixed32,4,req,name=a1" json:"a1,omitempty"`
- // End angle in counter-clockwise order.
- A2 *float32 `protobuf:"fixed32,5,req,name=a2" json:"a2,omitempty"`
- // Thickness of the arc.
- Thickness *float32 `protobuf:"fixed32,6,req,name=thickness" json:"thickness,omitempty"`
- // The type of this shape
- Type *SSL_FieldShapeType `protobuf:"varint,7,opt,name=type,enum=SSL_FieldShapeType" json:"type,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *SSL_FieldCircularArc) Reset() {
- *x = SSL_FieldCircularArc{}
- mi := &file_vision_ssl_vision_geometry_proto_msgTypes[2]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_FieldCircularArc) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_FieldCircularArc) ProtoMessage() {}
-
-func (x *SSL_FieldCircularArc) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vision_geometry_proto_msgTypes[2]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_FieldCircularArc.ProtoReflect.Descriptor instead.
-func (*SSL_FieldCircularArc) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{2}
-}
-
-func (x *SSL_FieldCircularArc) GetName() string {
- if x != nil && x.Name != nil {
- return *x.Name
- }
- return ""
-}
-
-func (x *SSL_FieldCircularArc) GetCenter() *Vector2F {
- if x != nil {
- return x.Center
- }
- return nil
-}
-
-func (x *SSL_FieldCircularArc) GetRadius() float32 {
- if x != nil && x.Radius != nil {
- return *x.Radius
- }
- return 0
-}
-
-func (x *SSL_FieldCircularArc) GetA1() float32 {
- if x != nil && x.A1 != nil {
- return *x.A1
- }
- return 0
-}
-
-func (x *SSL_FieldCircularArc) GetA2() float32 {
- if x != nil && x.A2 != nil {
- return *x.A2
- }
- return 0
-}
-
-func (x *SSL_FieldCircularArc) GetThickness() float32 {
- if x != nil && x.Thickness != nil {
- return *x.Thickness
- }
- return 0
-}
-
-func (x *SSL_FieldCircularArc) GetType() SSL_FieldShapeType {
- if x != nil && x.Type != nil {
- return *x.Type
- }
- return SSL_FieldShapeType_Undefined
-}
-
-type SSL_GeometryFieldSize struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // Field length (distance between goal lines) in mm
- FieldLength *int32 `protobuf:"varint,1,req,name=field_length,json=fieldLength" json:"field_length,omitempty"`
- // Field width (distance between touch lines) in mm
- FieldWidth *int32 `protobuf:"varint,2,req,name=field_width,json=fieldWidth" json:"field_width,omitempty"`
- // Goal width (distance between inner edges of goal posts) in mm
- GoalWidth *int32 `protobuf:"varint,3,req,name=goal_width,json=goalWidth" json:"goal_width,omitempty"`
- // Goal depth (distance from outer goal line edge to inner goal back) in mm
- GoalDepth *int32 `protobuf:"varint,4,req,name=goal_depth,json=goalDepth" json:"goal_depth,omitempty"`
- // Boundary width (distance from touch line centers to boundary walls) in mm
- BoundaryWidth *int32 `protobuf:"varint,5,req,name=boundary_width,json=boundaryWidth" json:"boundary_width,omitempty"`
- // Boundary width at the goal lines (distance from goal line centers to boundary walls) in mm
- BoundaryWidthGoalLine *int32 `protobuf:"varint,16,opt,name=boundary_width_goal_line,json=boundaryWidthGoalLine" json:"boundary_width_goal_line,omitempty"`
- // Generated line segments based on the other parameters
- FieldLines []*SSL_FieldLineSegment `protobuf:"bytes,6,rep,name=field_lines,json=fieldLines" json:"field_lines,omitempty"`
- // Generated circular arcs based on the other parameters
- FieldArcs []*SSL_FieldCircularArc `protobuf:"bytes,7,rep,name=field_arcs,json=fieldArcs" json:"field_arcs,omitempty"`
- // Depth of the penalty/defense area (measured between line centers) in mm
- PenaltyAreaDepth *int32 `protobuf:"varint,8,opt,name=penalty_area_depth,json=penaltyAreaDepth" json:"penalty_area_depth,omitempty"`
- // Width of the penalty/defense area (measured between line centers) in mm
- PenaltyAreaWidth *int32 `protobuf:"varint,9,opt,name=penalty_area_width,json=penaltyAreaWidth" json:"penalty_area_width,omitempty"`
- // Radius of the center circle (measured between line centers) in mm
- CenterCircleRadius *int32 `protobuf:"varint,10,opt,name=center_circle_radius,json=centerCircleRadius" json:"center_circle_radius,omitempty"`
- // Thickness/width of the lines on the field in mm
- LineThickness *int32 `protobuf:"varint,11,opt,name=line_thickness,json=lineThickness" json:"line_thickness,omitempty"`
- // Distance between the goal center and the center of the penalty mark in mm
- GoalCenterToPenaltyMark *int32 `protobuf:"varint,12,opt,name=goal_center_to_penalty_mark,json=goalCenterToPenaltyMark" json:"goal_center_to_penalty_mark,omitempty"`
- // Goal height in mm
- GoalHeight *int32 `protobuf:"varint,13,opt,name=goal_height,json=goalHeight" json:"goal_height,omitempty"`
- // Ball radius in mm (note that this is a float type to represent sub-mm precision)
- BallRadius *float32 `protobuf:"fixed32,14,opt,name=ball_radius,json=ballRadius" json:"ball_radius,omitempty"`
- // Max allowed robot radius in mm (note that this is a float type to represent sub-mm precision)
- MaxRobotRadius *float32 `protobuf:"fixed32,15,opt,name=max_robot_radius,json=maxRobotRadius" json:"max_robot_radius,omitempty"`
- // Width of the goal substitution area (distance from goal line center plus boundary width to boundary walls) in mm
- GoalSubstitutionAreaWidth *int32 `protobuf:"varint,17,opt,name=goal_substitution_area_width,json=goalSubstitutionAreaWidth" json:"goal_substitution_area_width,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *SSL_GeometryFieldSize) Reset() {
- *x = SSL_GeometryFieldSize{}
- mi := &file_vision_ssl_vision_geometry_proto_msgTypes[3]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_GeometryFieldSize) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_GeometryFieldSize) ProtoMessage() {}
-
-func (x *SSL_GeometryFieldSize) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vision_geometry_proto_msgTypes[3]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_GeometryFieldSize.ProtoReflect.Descriptor instead.
-func (*SSL_GeometryFieldSize) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{3}
-}
-
-func (x *SSL_GeometryFieldSize) GetFieldLength() int32 {
- if x != nil && x.FieldLength != nil {
- return *x.FieldLength
- }
- return 0
-}
-
-func (x *SSL_GeometryFieldSize) GetFieldWidth() int32 {
- if x != nil && x.FieldWidth != nil {
- return *x.FieldWidth
- }
- return 0
-}
-
-func (x *SSL_GeometryFieldSize) GetGoalWidth() int32 {
- if x != nil && x.GoalWidth != nil {
- return *x.GoalWidth
- }
- return 0
-}
-
-func (x *SSL_GeometryFieldSize) GetGoalDepth() int32 {
- if x != nil && x.GoalDepth != nil {
- return *x.GoalDepth
- }
- return 0
-}
-
-func (x *SSL_GeometryFieldSize) GetBoundaryWidth() int32 {
- if x != nil && x.BoundaryWidth != nil {
- return *x.BoundaryWidth
- }
- return 0
-}
-
-func (x *SSL_GeometryFieldSize) GetBoundaryWidthGoalLine() int32 {
- if x != nil && x.BoundaryWidthGoalLine != nil {
- return *x.BoundaryWidthGoalLine
- }
- return 0
-}
-
-func (x *SSL_GeometryFieldSize) GetFieldLines() []*SSL_FieldLineSegment {
- if x != nil {
- return x.FieldLines
- }
- return nil
-}
-
-func (x *SSL_GeometryFieldSize) GetFieldArcs() []*SSL_FieldCircularArc {
- if x != nil {
- return x.FieldArcs
- }
- return nil
-}
-
-func (x *SSL_GeometryFieldSize) GetPenaltyAreaDepth() int32 {
- if x != nil && x.PenaltyAreaDepth != nil {
- return *x.PenaltyAreaDepth
- }
- return 0
-}
-
-func (x *SSL_GeometryFieldSize) GetPenaltyAreaWidth() int32 {
- if x != nil && x.PenaltyAreaWidth != nil {
- return *x.PenaltyAreaWidth
- }
- return 0
-}
-
-func (x *SSL_GeometryFieldSize) GetCenterCircleRadius() int32 {
- if x != nil && x.CenterCircleRadius != nil {
- return *x.CenterCircleRadius
- }
- return 0
-}
-
-func (x *SSL_GeometryFieldSize) GetLineThickness() int32 {
- if x != nil && x.LineThickness != nil {
- return *x.LineThickness
- }
- return 0
-}
-
-func (x *SSL_GeometryFieldSize) GetGoalCenterToPenaltyMark() int32 {
- if x != nil && x.GoalCenterToPenaltyMark != nil {
- return *x.GoalCenterToPenaltyMark
- }
- return 0
-}
-
-func (x *SSL_GeometryFieldSize) GetGoalHeight() int32 {
- if x != nil && x.GoalHeight != nil {
- return *x.GoalHeight
- }
- return 0
-}
-
-func (x *SSL_GeometryFieldSize) GetBallRadius() float32 {
- if x != nil && x.BallRadius != nil {
- return *x.BallRadius
- }
- return 0
-}
-
-func (x *SSL_GeometryFieldSize) GetMaxRobotRadius() float32 {
- if x != nil && x.MaxRobotRadius != nil {
- return *x.MaxRobotRadius
- }
- return 0
-}
-
-func (x *SSL_GeometryFieldSize) GetGoalSubstitutionAreaWidth() int32 {
- if x != nil && x.GoalSubstitutionAreaWidth != nil {
- return *x.GoalSubstitutionAreaWidth
- }
- return 0
-}
-
-type SSL_GeometryCameraCalibration struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- CameraId *uint32 `protobuf:"varint,1,req,name=camera_id,json=cameraId" json:"camera_id,omitempty"`
- FocalLength *float32 `protobuf:"fixed32,2,req,name=focal_length,json=focalLength" json:"focal_length,omitempty"`
- PrincipalPointX *float32 `protobuf:"fixed32,3,req,name=principal_point_x,json=principalPointX" json:"principal_point_x,omitempty"`
- PrincipalPointY *float32 `protobuf:"fixed32,4,req,name=principal_point_y,json=principalPointY" json:"principal_point_y,omitempty"`
- Distortion *float32 `protobuf:"fixed32,5,req,name=distortion" json:"distortion,omitempty"`
- Q0 *float32 `protobuf:"fixed32,6,req,name=q0" json:"q0,omitempty"`
- Q1 *float32 `protobuf:"fixed32,7,req,name=q1" json:"q1,omitempty"`
- Q2 *float32 `protobuf:"fixed32,8,req,name=q2" json:"q2,omitempty"`
- Q3 *float32 `protobuf:"fixed32,9,req,name=q3" json:"q3,omitempty"`
- Tx *float32 `protobuf:"fixed32,10,req,name=tx" json:"tx,omitempty"`
- Ty *float32 `protobuf:"fixed32,11,req,name=ty" json:"ty,omitempty"`
- Tz *float32 `protobuf:"fixed32,12,req,name=tz" json:"tz,omitempty"`
- DerivedCameraWorldTx *float32 `protobuf:"fixed32,13,opt,name=derived_camera_world_tx,json=derivedCameraWorldTx" json:"derived_camera_world_tx,omitempty"`
- DerivedCameraWorldTy *float32 `protobuf:"fixed32,14,opt,name=derived_camera_world_ty,json=derivedCameraWorldTy" json:"derived_camera_world_ty,omitempty"`
- DerivedCameraWorldTz *float32 `protobuf:"fixed32,15,opt,name=derived_camera_world_tz,json=derivedCameraWorldTz" json:"derived_camera_world_tz,omitempty"`
- PixelImageWidth *uint32 `protobuf:"varint,16,opt,name=pixel_image_width,json=pixelImageWidth" json:"pixel_image_width,omitempty"`
- PixelImageHeight *uint32 `protobuf:"varint,17,opt,name=pixel_image_height,json=pixelImageHeight" json:"pixel_image_height,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *SSL_GeometryCameraCalibration) Reset() {
- *x = SSL_GeometryCameraCalibration{}
- mi := &file_vision_ssl_vision_geometry_proto_msgTypes[4]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_GeometryCameraCalibration) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_GeometryCameraCalibration) ProtoMessage() {}
-
-func (x *SSL_GeometryCameraCalibration) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vision_geometry_proto_msgTypes[4]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_GeometryCameraCalibration.ProtoReflect.Descriptor instead.
-func (*SSL_GeometryCameraCalibration) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{4}
-}
-
-func (x *SSL_GeometryCameraCalibration) GetCameraId() uint32 {
- if x != nil && x.CameraId != nil {
- return *x.CameraId
- }
- return 0
-}
-
-func (x *SSL_GeometryCameraCalibration) GetFocalLength() float32 {
- if x != nil && x.FocalLength != nil {
- return *x.FocalLength
- }
- return 0
-}
-
-func (x *SSL_GeometryCameraCalibration) GetPrincipalPointX() float32 {
- if x != nil && x.PrincipalPointX != nil {
- return *x.PrincipalPointX
- }
- return 0
-}
-
-func (x *SSL_GeometryCameraCalibration) GetPrincipalPointY() float32 {
- if x != nil && x.PrincipalPointY != nil {
- return *x.PrincipalPointY
- }
- return 0
-}
-
-func (x *SSL_GeometryCameraCalibration) GetDistortion() float32 {
- if x != nil && x.Distortion != nil {
- return *x.Distortion
- }
- return 0
-}
-
-func (x *SSL_GeometryCameraCalibration) GetQ0() float32 {
- if x != nil && x.Q0 != nil {
- return *x.Q0
- }
- return 0
-}
-
-func (x *SSL_GeometryCameraCalibration) GetQ1() float32 {
- if x != nil && x.Q1 != nil {
- return *x.Q1
- }
- return 0
-}
-
-func (x *SSL_GeometryCameraCalibration) GetQ2() float32 {
- if x != nil && x.Q2 != nil {
- return *x.Q2
- }
- return 0
-}
-
-func (x *SSL_GeometryCameraCalibration) GetQ3() float32 {
- if x != nil && x.Q3 != nil {
- return *x.Q3
- }
- return 0
-}
-
-func (x *SSL_GeometryCameraCalibration) GetTx() float32 {
- if x != nil && x.Tx != nil {
- return *x.Tx
- }
- return 0
-}
-
-func (x *SSL_GeometryCameraCalibration) GetTy() float32 {
- if x != nil && x.Ty != nil {
- return *x.Ty
- }
- return 0
-}
-
-func (x *SSL_GeometryCameraCalibration) GetTz() float32 {
- if x != nil && x.Tz != nil {
- return *x.Tz
- }
- return 0
-}
-
-func (x *SSL_GeometryCameraCalibration) GetDerivedCameraWorldTx() float32 {
- if x != nil && x.DerivedCameraWorldTx != nil {
- return *x.DerivedCameraWorldTx
- }
- return 0
-}
-
-func (x *SSL_GeometryCameraCalibration) GetDerivedCameraWorldTy() float32 {
- if x != nil && x.DerivedCameraWorldTy != nil {
- return *x.DerivedCameraWorldTy
- }
- return 0
-}
-
-func (x *SSL_GeometryCameraCalibration) GetDerivedCameraWorldTz() float32 {
- if x != nil && x.DerivedCameraWorldTz != nil {
- return *x.DerivedCameraWorldTz
- }
- return 0
-}
-
-func (x *SSL_GeometryCameraCalibration) GetPixelImageWidth() uint32 {
- if x != nil && x.PixelImageWidth != nil {
- return *x.PixelImageWidth
- }
- return 0
-}
-
-func (x *SSL_GeometryCameraCalibration) GetPixelImageHeight() uint32 {
- if x != nil && x.PixelImageHeight != nil {
- return *x.PixelImageHeight
- }
- return 0
-}
-
-// Two-Phase model for straight-kicked balls.
-// There are two phases with different accelerations during the ball kicks:
-// 1. Sliding
-// 2. Rolling
-// The full model is described in the TDP of ER-Force from 2016, which can be found here:
-// https://ssl.robocup.org/wp-content/uploads/2019/01/2016_ETDP_ER-Force.pdf
-type SSL_BallModelStraightTwoPhase struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // Ball sliding acceleration [m/s^2] (should be negative)
- AccSlide *float64 `protobuf:"fixed64,1,req,name=acc_slide,json=accSlide" json:"acc_slide,omitempty"`
- // Ball rolling acceleration [m/s^2] (should be negative)
- AccRoll *float64 `protobuf:"fixed64,2,req,name=acc_roll,json=accRoll" json:"acc_roll,omitempty"`
- // Fraction of the initial velocity where the ball starts to roll
- KSwitch *float64 `protobuf:"fixed64,3,req,name=k_switch,json=kSwitch" json:"k_switch,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *SSL_BallModelStraightTwoPhase) Reset() {
- *x = SSL_BallModelStraightTwoPhase{}
- mi := &file_vision_ssl_vision_geometry_proto_msgTypes[5]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_BallModelStraightTwoPhase) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_BallModelStraightTwoPhase) ProtoMessage() {}
-
-func (x *SSL_BallModelStraightTwoPhase) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vision_geometry_proto_msgTypes[5]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_BallModelStraightTwoPhase.ProtoReflect.Descriptor instead.
-func (*SSL_BallModelStraightTwoPhase) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{5}
-}
-
-func (x *SSL_BallModelStraightTwoPhase) GetAccSlide() float64 {
- if x != nil && x.AccSlide != nil {
- return *x.AccSlide
- }
- return 0
-}
-
-func (x *SSL_BallModelStraightTwoPhase) GetAccRoll() float64 {
- if x != nil && x.AccRoll != nil {
- return *x.AccRoll
- }
- return 0
-}
-
-func (x *SSL_BallModelStraightTwoPhase) GetKSwitch() float64 {
- if x != nil && x.KSwitch != nil {
- return *x.KSwitch
- }
- return 0
-}
-
-// Fixed-Loss model for chipped balls.
-// Uses fixed damping factors for xy and z direction per hop.
-type SSL_BallModelChipFixedLoss struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // Chip kick velocity damping factor in XY direction for the first hop
- DampingXyFirstHop *float64 `protobuf:"fixed64,1,req,name=damping_xy_first_hop,json=dampingXyFirstHop" json:"damping_xy_first_hop,omitempty"`
- // Chip kick velocity damping factor in XY direction for all following hops
- DampingXyOtherHops *float64 `protobuf:"fixed64,2,req,name=damping_xy_other_hops,json=dampingXyOtherHops" json:"damping_xy_other_hops,omitempty"`
- // Chip kick velocity damping factor in Z direction for all hops
- DampingZ *float64 `protobuf:"fixed64,3,req,name=damping_z,json=dampingZ" json:"damping_z,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *SSL_BallModelChipFixedLoss) Reset() {
- *x = SSL_BallModelChipFixedLoss{}
- mi := &file_vision_ssl_vision_geometry_proto_msgTypes[6]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_BallModelChipFixedLoss) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_BallModelChipFixedLoss) ProtoMessage() {}
-
-func (x *SSL_BallModelChipFixedLoss) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vision_geometry_proto_msgTypes[6]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_BallModelChipFixedLoss.ProtoReflect.Descriptor instead.
-func (*SSL_BallModelChipFixedLoss) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{6}
-}
-
-func (x *SSL_BallModelChipFixedLoss) GetDampingXyFirstHop() float64 {
- if x != nil && x.DampingXyFirstHop != nil {
- return *x.DampingXyFirstHop
- }
- return 0
-}
-
-func (x *SSL_BallModelChipFixedLoss) GetDampingXyOtherHops() float64 {
- if x != nil && x.DampingXyOtherHops != nil {
- return *x.DampingXyOtherHops
- }
- return 0
-}
-
-func (x *SSL_BallModelChipFixedLoss) GetDampingZ() float64 {
- if x != nil && x.DampingZ != nil {
- return *x.DampingZ
- }
- return 0
-}
-
-type SSL_GeometryModels struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- StraightTwoPhase *SSL_BallModelStraightTwoPhase `protobuf:"bytes,1,opt,name=straight_two_phase,json=straightTwoPhase" json:"straight_two_phase,omitempty"`
- ChipFixedLoss *SSL_BallModelChipFixedLoss `protobuf:"bytes,2,opt,name=chip_fixed_loss,json=chipFixedLoss" json:"chip_fixed_loss,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *SSL_GeometryModels) Reset() {
- *x = SSL_GeometryModels{}
- mi := &file_vision_ssl_vision_geometry_proto_msgTypes[7]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_GeometryModels) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_GeometryModels) ProtoMessage() {}
-
-func (x *SSL_GeometryModels) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vision_geometry_proto_msgTypes[7]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_GeometryModels.ProtoReflect.Descriptor instead.
-func (*SSL_GeometryModels) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{7}
-}
-
-func (x *SSL_GeometryModels) GetStraightTwoPhase() *SSL_BallModelStraightTwoPhase {
- if x != nil {
- return x.StraightTwoPhase
- }
- return nil
-}
-
-func (x *SSL_GeometryModels) GetChipFixedLoss() *SSL_BallModelChipFixedLoss {
- if x != nil {
- return x.ChipFixedLoss
- }
- return nil
-}
-
-type SSL_GeometryData struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- Field *SSL_GeometryFieldSize `protobuf:"bytes,1,req,name=field" json:"field,omitempty"`
- Calib []*SSL_GeometryCameraCalibration `protobuf:"bytes,2,rep,name=calib" json:"calib,omitempty"`
- Models *SSL_GeometryModels `protobuf:"bytes,3,opt,name=models" json:"models,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *SSL_GeometryData) Reset() {
- *x = SSL_GeometryData{}
- mi := &file_vision_ssl_vision_geometry_proto_msgTypes[8]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_GeometryData) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_GeometryData) ProtoMessage() {}
-
-func (x *SSL_GeometryData) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vision_geometry_proto_msgTypes[8]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_GeometryData.ProtoReflect.Descriptor instead.
-func (*SSL_GeometryData) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vision_geometry_proto_rawDescGZIP(), []int{8}
-}
-
-func (x *SSL_GeometryData) GetField() *SSL_GeometryFieldSize {
- if x != nil {
- return x.Field
- }
- return nil
-}
-
-func (x *SSL_GeometryData) GetCalib() []*SSL_GeometryCameraCalibration {
- if x != nil {
- return x.Calib
- }
- return nil
-}
-
-func (x *SSL_GeometryData) GetModels() *SSL_GeometryModels {
- if x != nil {
- return x.Models
- }
- return nil
-}
-
-var File_vision_ssl_vision_geometry_proto protoreflect.FileDescriptor
-
-const file_vision_ssl_vision_geometry_proto_rawDesc = "" +
- "\n" +
- " vision/ssl_vision_geometry.proto\"&\n" +
- "\bVector2f\x12\f\n" +
- "\x01x\x18\x01 \x02(\x02R\x01x\x12\f\n" +
- "\x01y\x18\x02 \x02(\x02R\x01y\"\xa7\x01\n" +
- "\x14SSL_FieldLineSegment\x12\x12\n" +
- "\x04name\x18\x01 \x02(\tR\x04name\x12\x19\n" +
- "\x02p1\x18\x02 \x02(\v2\t.Vector2fR\x02p1\x12\x19\n" +
- "\x02p2\x18\x03 \x02(\v2\t.Vector2fR\x02p2\x12\x1c\n" +
- "\tthickness\x18\x04 \x02(\x02R\tthickness\x12'\n" +
- "\x04type\x18\x05 \x01(\x0e2\x13.SSL_FieldShapeTypeR\x04type\"\xcc\x01\n" +
- "\x14SSL_FieldCircularArc\x12\x12\n" +
- "\x04name\x18\x01 \x02(\tR\x04name\x12!\n" +
- "\x06center\x18\x02 \x02(\v2\t.Vector2fR\x06center\x12\x16\n" +
- "\x06radius\x18\x03 \x02(\x02R\x06radius\x12\x0e\n" +
- "\x02a1\x18\x04 \x02(\x02R\x02a1\x12\x0e\n" +
- "\x02a2\x18\x05 \x02(\x02R\x02a2\x12\x1c\n" +
- "\tthickness\x18\x06 \x02(\x02R\tthickness\x12'\n" +
- "\x04type\x18\a \x01(\x0e2\x13.SSL_FieldShapeTypeR\x04type\"\x87\x06\n" +
- "\x15SSL_GeometryFieldSize\x12!\n" +
- "\ffield_length\x18\x01 \x02(\x05R\vfieldLength\x12\x1f\n" +
- "\vfield_width\x18\x02 \x02(\x05R\n" +
- "fieldWidth\x12\x1d\n" +
- "\n" +
- "goal_width\x18\x03 \x02(\x05R\tgoalWidth\x12\x1d\n" +
- "\n" +
- "goal_depth\x18\x04 \x02(\x05R\tgoalDepth\x12%\n" +
- "\x0eboundary_width\x18\x05 \x02(\x05R\rboundaryWidth\x127\n" +
- "\x18boundary_width_goal_line\x18\x10 \x01(\x05R\x15boundaryWidthGoalLine\x126\n" +
- "\vfield_lines\x18\x06 \x03(\v2\x15.SSL_FieldLineSegmentR\n" +
- "fieldLines\x124\n" +
- "\n" +
- "field_arcs\x18\a \x03(\v2\x15.SSL_FieldCircularArcR\tfieldArcs\x12,\n" +
- "\x12penalty_area_depth\x18\b \x01(\x05R\x10penaltyAreaDepth\x12,\n" +
- "\x12penalty_area_width\x18\t \x01(\x05R\x10penaltyAreaWidth\x120\n" +
- "\x14center_circle_radius\x18\n" +
- " \x01(\x05R\x12centerCircleRadius\x12%\n" +
- "\x0eline_thickness\x18\v \x01(\x05R\rlineThickness\x12<\n" +
- "\x1bgoal_center_to_penalty_mark\x18\f \x01(\x05R\x17goalCenterToPenaltyMark\x12\x1f\n" +
- "\vgoal_height\x18\r \x01(\x05R\n" +
- "goalHeight\x12\x1f\n" +
- "\vball_radius\x18\x0e \x01(\x02R\n" +
- "ballRadius\x12(\n" +
- "\x10max_robot_radius\x18\x0f \x01(\x02R\x0emaxRobotRadius\x12?\n" +
- "\x1cgoal_substitution_area_width\x18\x11 \x01(\x05R\x19goalSubstitutionAreaWidth\"\xc6\x04\n" +
- "\x1dSSL_GeometryCameraCalibration\x12\x1b\n" +
- "\tcamera_id\x18\x01 \x02(\rR\bcameraId\x12!\n" +
- "\ffocal_length\x18\x02 \x02(\x02R\vfocalLength\x12*\n" +
- "\x11principal_point_x\x18\x03 \x02(\x02R\x0fprincipalPointX\x12*\n" +
- "\x11principal_point_y\x18\x04 \x02(\x02R\x0fprincipalPointY\x12\x1e\n" +
- "\n" +
- "distortion\x18\x05 \x02(\x02R\n" +
- "distortion\x12\x0e\n" +
- "\x02q0\x18\x06 \x02(\x02R\x02q0\x12\x0e\n" +
- "\x02q1\x18\a \x02(\x02R\x02q1\x12\x0e\n" +
- "\x02q2\x18\b \x02(\x02R\x02q2\x12\x0e\n" +
- "\x02q3\x18\t \x02(\x02R\x02q3\x12\x0e\n" +
- "\x02tx\x18\n" +
- " \x02(\x02R\x02tx\x12\x0e\n" +
- "\x02ty\x18\v \x02(\x02R\x02ty\x12\x0e\n" +
- "\x02tz\x18\f \x02(\x02R\x02tz\x125\n" +
- "\x17derived_camera_world_tx\x18\r \x01(\x02R\x14derivedCameraWorldTx\x125\n" +
- "\x17derived_camera_world_ty\x18\x0e \x01(\x02R\x14derivedCameraWorldTy\x125\n" +
- "\x17derived_camera_world_tz\x18\x0f \x01(\x02R\x14derivedCameraWorldTz\x12*\n" +
- "\x11pixel_image_width\x18\x10 \x01(\rR\x0fpixelImageWidth\x12,\n" +
- "\x12pixel_image_height\x18\x11 \x01(\rR\x10pixelImageHeight\"r\n" +
- "\x1dSSL_BallModelStraightTwoPhase\x12\x1b\n" +
- "\tacc_slide\x18\x01 \x02(\x01R\baccSlide\x12\x19\n" +
- "\bacc_roll\x18\x02 \x02(\x01R\aaccRoll\x12\x19\n" +
- "\bk_switch\x18\x03 \x02(\x01R\akSwitch\"\x9d\x01\n" +
- "\x1aSSL_BallModelChipFixedLoss\x12/\n" +
- "\x14damping_xy_first_hop\x18\x01 \x02(\x01R\x11dampingXyFirstHop\x121\n" +
- "\x15damping_xy_other_hops\x18\x02 \x02(\x01R\x12dampingXyOtherHops\x12\x1b\n" +
- "\tdamping_z\x18\x03 \x02(\x01R\bdampingZ\"\xa7\x01\n" +
- "\x12SSL_GeometryModels\x12L\n" +
- "\x12straight_two_phase\x18\x01 \x01(\v2\x1e.SSL_BallModelStraightTwoPhaseR\x10straightTwoPhase\x12C\n" +
- "\x0fchip_fixed_loss\x18\x02 \x01(\v2\x1b.SSL_BallModelChipFixedLossR\rchipFixedLoss\"\xa3\x01\n" +
- "\x10SSL_GeometryData\x12,\n" +
- "\x05field\x18\x01 \x02(\v2\x16.SSL_GeometryFieldSizeR\x05field\x124\n" +
- "\x05calib\x18\x02 \x03(\v2\x1e.SSL_GeometryCameraCalibrationR\x05calib\x12+\n" +
- "\x06models\x18\x03 \x01(\v2\x13.SSL_GeometryModelsR\x06models*\xdb\x02\n" +
- "\x12SSL_FieldShapeType\x12\r\n" +
- "\tUndefined\x10\x00\x12\x10\n" +
- "\fCenterCircle\x10\x01\x12\x10\n" +
- "\fTopTouchLine\x10\x02\x12\x13\n" +
- "\x0fBottomTouchLine\x10\x03\x12\x10\n" +
- "\fLeftGoalLine\x10\x04\x12\x11\n" +
- "\rRightGoalLine\x10\x05\x12\x0f\n" +
- "\vHalfwayLine\x10\x06\x12\x0e\n" +
- "\n" +
- "CenterLine\x10\a\x12\x16\n" +
- "\x12LeftPenaltyStretch\x10\b\x12\x17\n" +
- "\x13RightPenaltyStretch\x10\t\x12\x1f\n" +
- "\x1bLeftFieldLeftPenaltyStretch\x10\n" +
- "\x12 \n" +
- "\x1cLeftFieldRightPenaltyStretch\x10\v\x12 \n" +
- "\x1cRightFieldLeftPenaltyStretch\x10\f\x12!\n" +
- "\x1dRightFieldRightPenaltyStretch\x10\rB[B\x16SslVisionGeometryProtoP\x01Z?github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
-
-var (
- file_vision_ssl_vision_geometry_proto_rawDescOnce sync.Once
- file_vision_ssl_vision_geometry_proto_rawDescData []byte
-)
-
-func file_vision_ssl_vision_geometry_proto_rawDescGZIP() []byte {
- file_vision_ssl_vision_geometry_proto_rawDescOnce.Do(func() {
- file_vision_ssl_vision_geometry_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_geometry_proto_rawDesc), len(file_vision_ssl_vision_geometry_proto_rawDesc)))
- })
- return file_vision_ssl_vision_geometry_proto_rawDescData
-}
-
-var file_vision_ssl_vision_geometry_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
-var file_vision_ssl_vision_geometry_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
-var file_vision_ssl_vision_geometry_proto_goTypes = []any{
- (SSL_FieldShapeType)(0), // 0: SSL_FieldShapeType
- (*Vector2F)(nil), // 1: Vector2f
- (*SSL_FieldLineSegment)(nil), // 2: SSL_FieldLineSegment
- (*SSL_FieldCircularArc)(nil), // 3: SSL_FieldCircularArc
- (*SSL_GeometryFieldSize)(nil), // 4: SSL_GeometryFieldSize
- (*SSL_GeometryCameraCalibration)(nil), // 5: SSL_GeometryCameraCalibration
- (*SSL_BallModelStraightTwoPhase)(nil), // 6: SSL_BallModelStraightTwoPhase
- (*SSL_BallModelChipFixedLoss)(nil), // 7: SSL_BallModelChipFixedLoss
- (*SSL_GeometryModels)(nil), // 8: SSL_GeometryModels
- (*SSL_GeometryData)(nil), // 9: SSL_GeometryData
-}
-var file_vision_ssl_vision_geometry_proto_depIdxs = []int32{
- 1, // 0: SSL_FieldLineSegment.p1:type_name -> Vector2f
- 1, // 1: SSL_FieldLineSegment.p2:type_name -> Vector2f
- 0, // 2: SSL_FieldLineSegment.type:type_name -> SSL_FieldShapeType
- 1, // 3: SSL_FieldCircularArc.center:type_name -> Vector2f
- 0, // 4: SSL_FieldCircularArc.type:type_name -> SSL_FieldShapeType
- 2, // 5: SSL_GeometryFieldSize.field_lines:type_name -> SSL_FieldLineSegment
- 3, // 6: SSL_GeometryFieldSize.field_arcs:type_name -> SSL_FieldCircularArc
- 6, // 7: SSL_GeometryModels.straight_two_phase:type_name -> SSL_BallModelStraightTwoPhase
- 7, // 8: SSL_GeometryModels.chip_fixed_loss:type_name -> SSL_BallModelChipFixedLoss
- 4, // 9: SSL_GeometryData.field:type_name -> SSL_GeometryFieldSize
- 5, // 10: SSL_GeometryData.calib:type_name -> SSL_GeometryCameraCalibration
- 8, // 11: SSL_GeometryData.models:type_name -> SSL_GeometryModels
- 12, // [12:12] is the sub-list for method output_type
- 12, // [12:12] is the sub-list for method input_type
- 12, // [12:12] is the sub-list for extension type_name
- 12, // [12:12] is the sub-list for extension extendee
- 0, // [0:12] is the sub-list for field type_name
-}
-
-func init() { file_vision_ssl_vision_geometry_proto_init() }
-func file_vision_ssl_vision_geometry_proto_init() {
- if File_vision_ssl_vision_geometry_proto != nil {
- return
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_geometry_proto_rawDesc), len(file_vision_ssl_vision_geometry_proto_rawDesc)),
- NumEnums: 1,
- NumMessages: 9,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_vision_ssl_vision_geometry_proto_goTypes,
- DependencyIndexes: file_vision_ssl_vision_geometry_proto_depIdxs,
- EnumInfos: file_vision_ssl_vision_geometry_proto_enumTypes,
- MessageInfos: file_vision_ssl_vision_geometry_proto_msgTypes,
- }.Build()
- File_vision_ssl_vision_geometry_proto = out.File
- file_vision_ssl_vision_geometry_proto_goTypes = nil
- file_vision_ssl_vision_geometry_proto_depIdxs = nil
-}
diff --git a/gui/internal/vision/ssl_vision_wrapper.pb.go b/gui/internal/vision/ssl_vision_wrapper.pb.go
deleted file mode 100644
index ecbee04..0000000
--- a/gui/internal/vision/ssl_vision_wrapper.pb.go
+++ /dev/null
@@ -1,238 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.36.6
-// protoc (unknown)
-// source: vision/ssl_vision_wrapper.proto
-
-package vision
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
- unsafe "unsafe"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-type SSL_Source int32
-
-const (
- SSL_Source_SSL_SOURCE_UNKNOWN SSL_Source = 0
- SSL_Source_SSL_SOURCE_OTHER SSL_Source = 1
- SSL_Source_SSL_SOURCE_SSL_VISION SSL_Source = 2
- SSL_Source_SSL_SOURCE_VISION_PROCESSOR SSL_Source = 3
- SSL_Source_SSL_SOURCE_GRSIM SSL_Source = 4
- SSL_Source_SSL_SOURCE_ERFORCE_SIM SSL_Source = 5
-)
-
-// Enum value maps for SSL_Source.
-var (
- SSL_Source_name = map[int32]string{
- 0: "SSL_SOURCE_UNKNOWN",
- 1: "SSL_SOURCE_OTHER",
- 2: "SSL_SOURCE_SSL_VISION",
- 3: "SSL_SOURCE_VISION_PROCESSOR",
- 4: "SSL_SOURCE_GRSIM",
- 5: "SSL_SOURCE_ERFORCE_SIM",
- }
- SSL_Source_value = map[string]int32{
- "SSL_SOURCE_UNKNOWN": 0,
- "SSL_SOURCE_OTHER": 1,
- "SSL_SOURCE_SSL_VISION": 2,
- "SSL_SOURCE_VISION_PROCESSOR": 3,
- "SSL_SOURCE_GRSIM": 4,
- "SSL_SOURCE_ERFORCE_SIM": 5,
- }
-)
-
-func (x SSL_Source) Enum() *SSL_Source {
- p := new(SSL_Source)
- *p = x
- return p
-}
-
-func (x SSL_Source) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (SSL_Source) Descriptor() protoreflect.EnumDescriptor {
- return file_vision_ssl_vision_wrapper_proto_enumTypes[0].Descriptor()
-}
-
-func (SSL_Source) Type() protoreflect.EnumType {
- return &file_vision_ssl_vision_wrapper_proto_enumTypes[0]
-}
-
-func (x SSL_Source) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Do not use.
-func (x *SSL_Source) UnmarshalJSON(b []byte) error {
- num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
- if err != nil {
- return err
- }
- *x = SSL_Source(num)
- return nil
-}
-
-// Deprecated: Use SSL_Source.Descriptor instead.
-func (SSL_Source) EnumDescriptor() ([]byte, []int) {
- return file_vision_ssl_vision_wrapper_proto_rawDescGZIP(), []int{0}
-}
-
-type SSL_WrapperPacket struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- Detection *SSL_DetectionFrame `protobuf:"bytes,1,opt,name=detection" json:"detection,omitempty"`
- Geometry *SSL_GeometryData `protobuf:"bytes,2,opt,name=geometry" json:"geometry,omitempty"`
- Source *SSL_Source `protobuf:"varint,3,opt,name=source,enum=SSL_Source" json:"source,omitempty"`
- Config *SSL_VPConfig `protobuf:"bytes,4,opt,name=config" json:"config,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *SSL_WrapperPacket) Reset() {
- *x = SSL_WrapperPacket{}
- mi := &file_vision_ssl_vision_wrapper_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_WrapperPacket) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_WrapperPacket) ProtoMessage() {}
-
-func (x *SSL_WrapperPacket) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vision_wrapper_proto_msgTypes[0]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_WrapperPacket.ProtoReflect.Descriptor instead.
-func (*SSL_WrapperPacket) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vision_wrapper_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *SSL_WrapperPacket) GetDetection() *SSL_DetectionFrame {
- if x != nil {
- return x.Detection
- }
- return nil
-}
-
-func (x *SSL_WrapperPacket) GetGeometry() *SSL_GeometryData {
- if x != nil {
- return x.Geometry
- }
- return nil
-}
-
-func (x *SSL_WrapperPacket) GetSource() SSL_Source {
- if x != nil && x.Source != nil {
- return *x.Source
- }
- return SSL_Source_SSL_SOURCE_UNKNOWN
-}
-
-func (x *SSL_WrapperPacket) GetConfig() *SSL_VPConfig {
- if x != nil {
- return x.Config
- }
- return nil
-}
-
-var File_vision_ssl_vision_wrapper_proto protoreflect.FileDescriptor
-
-const file_vision_ssl_vision_wrapper_proto_rawDesc = "" +
- "\n" +
- "\x1fvision/ssl_vision_wrapper.proto\x1a!vision/ssl_vision_detection.proto\x1a vision/ssl_vision_geometry.proto\x1a\x1avision/ssl_vp_config.proto\"\xc1\x01\n" +
- "\x11SSL_WrapperPacket\x121\n" +
- "\tdetection\x18\x01 \x01(\v2\x13.SSL_DetectionFrameR\tdetection\x12-\n" +
- "\bgeometry\x18\x02 \x01(\v2\x11.SSL_GeometryDataR\bgeometry\x12#\n" +
- "\x06source\x18\x03 \x01(\x0e2\v.SSL_SourceR\x06source\x12%\n" +
- "\x06config\x18\x04 \x01(\v2\r.SSL_VPConfigR\x06config*\xa8\x01\n" +
- "\n" +
- "SSL_Source\x12\x16\n" +
- "\x12SSL_SOURCE_UNKNOWN\x10\x00\x12\x14\n" +
- "\x10SSL_SOURCE_OTHER\x10\x01\x12\x19\n" +
- "\x15SSL_SOURCE_SSL_VISION\x10\x02\x12\x1f\n" +
- "\x1bSSL_SOURCE_VISION_PROCESSOR\x10\x03\x12\x14\n" +
- "\x10SSL_SOURCE_GRSIM\x10\x04\x12\x1a\n" +
- "\x16SSL_SOURCE_ERFORCE_SIM\x10\x05BZB\x15SslVisionWrapperProtoP\x01Z?github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
-
-var (
- file_vision_ssl_vision_wrapper_proto_rawDescOnce sync.Once
- file_vision_ssl_vision_wrapper_proto_rawDescData []byte
-)
-
-func file_vision_ssl_vision_wrapper_proto_rawDescGZIP() []byte {
- file_vision_ssl_vision_wrapper_proto_rawDescOnce.Do(func() {
- file_vision_ssl_vision_wrapper_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_wrapper_proto_rawDesc), len(file_vision_ssl_vision_wrapper_proto_rawDesc)))
- })
- return file_vision_ssl_vision_wrapper_proto_rawDescData
-}
-
-var file_vision_ssl_vision_wrapper_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
-var file_vision_ssl_vision_wrapper_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
-var file_vision_ssl_vision_wrapper_proto_goTypes = []any{
- (SSL_Source)(0), // 0: SSL_Source
- (*SSL_WrapperPacket)(nil), // 1: SSL_WrapperPacket
- (*SSL_DetectionFrame)(nil), // 2: SSL_DetectionFrame
- (*SSL_GeometryData)(nil), // 3: SSL_GeometryData
- (*SSL_VPConfig)(nil), // 4: SSL_VPConfig
-}
-var file_vision_ssl_vision_wrapper_proto_depIdxs = []int32{
- 2, // 0: SSL_WrapperPacket.detection:type_name -> SSL_DetectionFrame
- 3, // 1: SSL_WrapperPacket.geometry:type_name -> SSL_GeometryData
- 0, // 2: SSL_WrapperPacket.source:type_name -> SSL_Source
- 4, // 3: SSL_WrapperPacket.config:type_name -> SSL_VPConfig
- 4, // [4:4] is the sub-list for method output_type
- 4, // [4:4] is the sub-list for method input_type
- 4, // [4:4] is the sub-list for extension type_name
- 4, // [4:4] is the sub-list for extension extendee
- 0, // [0:4] is the sub-list for field type_name
-}
-
-func init() { file_vision_ssl_vision_wrapper_proto_init() }
-func file_vision_ssl_vision_wrapper_proto_init() {
- if File_vision_ssl_vision_wrapper_proto != nil {
- return
- }
- file_vision_ssl_vision_detection_proto_init()
- file_vision_ssl_vision_geometry_proto_init()
- file_vision_ssl_vp_config_proto_init()
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_wrapper_proto_rawDesc), len(file_vision_ssl_vision_wrapper_proto_rawDesc)),
- NumEnums: 1,
- NumMessages: 1,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_vision_ssl_vision_wrapper_proto_goTypes,
- DependencyIndexes: file_vision_ssl_vision_wrapper_proto_depIdxs,
- EnumInfos: file_vision_ssl_vision_wrapper_proto_enumTypes,
- MessageInfos: file_vision_ssl_vision_wrapper_proto_msgTypes,
- }.Build()
- File_vision_ssl_vision_wrapper_proto = out.File
- file_vision_ssl_vision_wrapper_proto_goTypes = nil
- file_vision_ssl_vision_wrapper_proto_depIdxs = nil
-}
diff --git a/gui/internal/vision/ssl_vision_wrapper_tracked.pb.go b/gui/internal/vision/ssl_vision_wrapper_tracked.pb.go
deleted file mode 100644
index f993a0b..0000000
--- a/gui/internal/vision/ssl_vision_wrapper_tracked.pb.go
+++ /dev/null
@@ -1,150 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.36.6
-// protoc (unknown)
-// source: vision/ssl_vision_wrapper_tracked.proto
-
-package vision
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
- unsafe "unsafe"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-// A wrapper packet containing meta data of the source
-// Also serves for the possibility to extend the protocol later
-type TrackerWrapperPacket struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // A random UUID of the source that is kept constant at the source while running
- // If multiple sources are broadcasting to the same network, this id can be used to identify individual sources
- Uuid *string `protobuf:"bytes,1,req,name=uuid" json:"uuid,omitempty"`
- // The name of the source software that is producing this messages.
- SourceName *string `protobuf:"bytes,2,opt,name=source_name,json=sourceName" json:"source_name,omitempty"`
- // The tracked frame
- TrackedFrame *TrackedFrame `protobuf:"bytes,3,opt,name=tracked_frame,json=trackedFrame" json:"tracked_frame,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *TrackerWrapperPacket) Reset() {
- *x = TrackerWrapperPacket{}
- mi := &file_vision_ssl_vision_wrapper_tracked_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *TrackerWrapperPacket) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*TrackerWrapperPacket) ProtoMessage() {}
-
-func (x *TrackerWrapperPacket) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vision_wrapper_tracked_proto_msgTypes[0]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use TrackerWrapperPacket.ProtoReflect.Descriptor instead.
-func (*TrackerWrapperPacket) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vision_wrapper_tracked_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *TrackerWrapperPacket) GetUuid() string {
- if x != nil && x.Uuid != nil {
- return *x.Uuid
- }
- return ""
-}
-
-func (x *TrackerWrapperPacket) GetSourceName() string {
- if x != nil && x.SourceName != nil {
- return *x.SourceName
- }
- return ""
-}
-
-func (x *TrackerWrapperPacket) GetTrackedFrame() *TrackedFrame {
- if x != nil {
- return x.TrackedFrame
- }
- return nil
-}
-
-var File_vision_ssl_vision_wrapper_tracked_proto protoreflect.FileDescriptor
-
-const file_vision_ssl_vision_wrapper_tracked_proto_rawDesc = "" +
- "\n" +
- "'vision/ssl_vision_wrapper_tracked.proto\x1a)vision/ssl_vision_detection_tracked.proto\"\x7f\n" +
- "\x14TrackerWrapperPacket\x12\x12\n" +
- "\x04uuid\x18\x01 \x02(\tR\x04uuid\x12\x1f\n" +
- "\vsource_name\x18\x02 \x01(\tR\n" +
- "sourceName\x122\n" +
- "\rtracked_frame\x18\x03 \x01(\v2\r.TrackedFrameR\ftrackedFrameBaB\x1cSslVisionWrapperTrackedProtoP\x01Z?github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
-
-var (
- file_vision_ssl_vision_wrapper_tracked_proto_rawDescOnce sync.Once
- file_vision_ssl_vision_wrapper_tracked_proto_rawDescData []byte
-)
-
-func file_vision_ssl_vision_wrapper_tracked_proto_rawDescGZIP() []byte {
- file_vision_ssl_vision_wrapper_tracked_proto_rawDescOnce.Do(func() {
- file_vision_ssl_vision_wrapper_tracked_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_wrapper_tracked_proto_rawDesc), len(file_vision_ssl_vision_wrapper_tracked_proto_rawDesc)))
- })
- return file_vision_ssl_vision_wrapper_tracked_proto_rawDescData
-}
-
-var file_vision_ssl_vision_wrapper_tracked_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
-var file_vision_ssl_vision_wrapper_tracked_proto_goTypes = []any{
- (*TrackerWrapperPacket)(nil), // 0: TrackerWrapperPacket
- (*TrackedFrame)(nil), // 1: TrackedFrame
-}
-var file_vision_ssl_vision_wrapper_tracked_proto_depIdxs = []int32{
- 1, // 0: TrackerWrapperPacket.tracked_frame:type_name -> TrackedFrame
- 1, // [1:1] is the sub-list for method output_type
- 1, // [1:1] is the sub-list for method input_type
- 1, // [1:1] is the sub-list for extension type_name
- 1, // [1:1] is the sub-list for extension extendee
- 0, // [0:1] is the sub-list for field type_name
-}
-
-func init() { file_vision_ssl_vision_wrapper_tracked_proto_init() }
-func file_vision_ssl_vision_wrapper_tracked_proto_init() {
- if File_vision_ssl_vision_wrapper_tracked_proto != nil {
- return
- }
- file_vision_ssl_vision_detection_tracked_proto_init()
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: unsafe.Slice(unsafe.StringData(file_vision_ssl_vision_wrapper_tracked_proto_rawDesc), len(file_vision_ssl_vision_wrapper_tracked_proto_rawDesc)),
- NumEnums: 0,
- NumMessages: 1,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_vision_ssl_vision_wrapper_tracked_proto_goTypes,
- DependencyIndexes: file_vision_ssl_vision_wrapper_tracked_proto_depIdxs,
- MessageInfos: file_vision_ssl_vision_wrapper_tracked_proto_msgTypes,
- }.Build()
- File_vision_ssl_vision_wrapper_tracked_proto = out.File
- file_vision_ssl_vision_wrapper_tracked_proto_goTypes = nil
- file_vision_ssl_vision_wrapper_tracked_proto_depIdxs = nil
-}
diff --git a/gui/internal/vision/ssl_vp_config.pb.go b/gui/internal/vision/ssl_vp_config.pb.go
deleted file mode 100644
index 9529600..0000000
--- a/gui/internal/vision/ssl_vp_config.pb.go
+++ /dev/null
@@ -1,1230 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.36.6
-// protoc (unknown)
-// source: vision/ssl_vp_config.proto
-
-package vision
-
-import (
- gamecontroller "github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/gamecontroller"
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
- unsafe "unsafe"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-type SSL_VPConfigCameraDriver int32
-
-const (
- // FLIR cameras
- SSL_VPConfigCameraDriver_SPINNAKER SSL_VPConfigCameraDriver = 0
- // Video and image files, video4linux2 (e.g. webcams) cameras
- SSL_VPConfigCameraDriver_OPENCV SSL_VPConfigCameraDriver = 1
- // Bluefox3 cameras
- SSL_VPConfigCameraDriver_MVIMPACT SSL_VPConfigCameraDriver = 2
-)
-
-// Enum value maps for SSL_VPConfigCameraDriver.
-var (
- SSL_VPConfigCameraDriver_name = map[int32]string{
- 0: "SPINNAKER",
- 1: "OPENCV",
- 2: "MVIMPACT",
- }
- SSL_VPConfigCameraDriver_value = map[string]int32{
- "SPINNAKER": 0,
- "OPENCV": 1,
- "MVIMPACT": 2,
- }
-)
-
-func (x SSL_VPConfigCameraDriver) Enum() *SSL_VPConfigCameraDriver {
- p := new(SSL_VPConfigCameraDriver)
- *p = x
- return p
-}
-
-func (x SSL_VPConfigCameraDriver) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (SSL_VPConfigCameraDriver) Descriptor() protoreflect.EnumDescriptor {
- return file_vision_ssl_vp_config_proto_enumTypes[0].Descriptor()
-}
-
-func (SSL_VPConfigCameraDriver) Type() protoreflect.EnumType {
- return &file_vision_ssl_vp_config_proto_enumTypes[0]
-}
-
-func (x SSL_VPConfigCameraDriver) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Do not use.
-func (x *SSL_VPConfigCameraDriver) UnmarshalJSON(b []byte) error {
- num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
- if err != nil {
- return err
- }
- *x = SSL_VPConfigCameraDriver(num)
- return nil
-}
-
-// Deprecated: Use SSL_VPConfigCameraDriver.Descriptor instead.
-func (SSL_VPConfigCameraDriver) EnumDescriptor() ([]byte, []int) {
- return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{0}
-}
-
-type SSL_VPConfigCameraWBType int32
-
-const (
- SSL_VPConfigCameraWBType_OUTDOOR SSL_VPConfigCameraWBType = 0
- SSL_VPConfigCameraWBType_INDOOR SSL_VPConfigCameraWBType = 1
- SSL_VPConfigCameraWBType_MANUAL SSL_VPConfigCameraWBType = 2
-)
-
-// Enum value maps for SSL_VPConfigCameraWBType.
-var (
- SSL_VPConfigCameraWBType_name = map[int32]string{
- 0: "OUTDOOR",
- 1: "INDOOR",
- 2: "MANUAL",
- }
- SSL_VPConfigCameraWBType_value = map[string]int32{
- "OUTDOOR": 0,
- "INDOOR": 1,
- "MANUAL": 2,
- }
-)
-
-func (x SSL_VPConfigCameraWBType) Enum() *SSL_VPConfigCameraWBType {
- p := new(SSL_VPConfigCameraWBType)
- *p = x
- return p
-}
-
-func (x SSL_VPConfigCameraWBType) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (SSL_VPConfigCameraWBType) Descriptor() protoreflect.EnumDescriptor {
- return file_vision_ssl_vp_config_proto_enumTypes[1].Descriptor()
-}
-
-func (SSL_VPConfigCameraWBType) Type() protoreflect.EnumType {
- return &file_vision_ssl_vp_config_proto_enumTypes[1]
-}
-
-func (x SSL_VPConfigCameraWBType) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Do not use.
-func (x *SSL_VPConfigCameraWBType) UnmarshalJSON(b []byte) error {
- num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
- if err != nil {
- return err
- }
- *x = SSL_VPConfigCameraWBType(num)
- return nil
-}
-
-// Deprecated: Use SSL_VPConfigCameraWBType.Descriptor instead.
-func (SSL_VPConfigCameraWBType) EnumDescriptor() ([]byte, []int) {
- return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{1}
-}
-
-type SSL_VPConfigStreamType int32
-
-const (
- SSL_VPConfigStreamType_RAW SSL_VPConfigStreamType = 0
- SSL_VPConfigStreamType_REPROJ_FALSE_COLOR SSL_VPConfigStreamType = 1
- SSL_VPConfigStreamType_REPROJ_GRADIENT_DOT SSL_VPConfigStreamType = 2
- SSL_VPConfigStreamType_REPROJ_BLOB_SCORE SSL_VPConfigStreamType = 3
-)
-
-// Enum value maps for SSL_VPConfigStreamType.
-var (
- SSL_VPConfigStreamType_name = map[int32]string{
- 0: "RAW",
- 1: "REPROJ_FALSE_COLOR",
- 2: "REPROJ_GRADIENT_DOT",
- 3: "REPROJ_BLOB_SCORE",
- }
- SSL_VPConfigStreamType_value = map[string]int32{
- "RAW": 0,
- "REPROJ_FALSE_COLOR": 1,
- "REPROJ_GRADIENT_DOT": 2,
- "REPROJ_BLOB_SCORE": 3,
- }
-)
-
-func (x SSL_VPConfigStreamType) Enum() *SSL_VPConfigStreamType {
- p := new(SSL_VPConfigStreamType)
- *p = x
- return p
-}
-
-func (x SSL_VPConfigStreamType) String() string {
- return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
-}
-
-func (SSL_VPConfigStreamType) Descriptor() protoreflect.EnumDescriptor {
- return file_vision_ssl_vp_config_proto_enumTypes[2].Descriptor()
-}
-
-func (SSL_VPConfigStreamType) Type() protoreflect.EnumType {
- return &file_vision_ssl_vp_config_proto_enumTypes[2]
-}
-
-func (x SSL_VPConfigStreamType) Number() protoreflect.EnumNumber {
- return protoreflect.EnumNumber(x)
-}
-
-// Deprecated: Do not use.
-func (x *SSL_VPConfigStreamType) UnmarshalJSON(b []byte) error {
- num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
- if err != nil {
- return err
- }
- *x = SSL_VPConfigStreamType(num)
- return nil
-}
-
-// Deprecated: Use SSL_VPConfigStreamType.Descriptor instead.
-func (SSL_VPConfigStreamType) EnumDescriptor() ([]byte, []int) {
- return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{2}
-}
-
-type SSL_VPConfigCamera struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // Camera driver type. Availability depending on libraries installed.
- Driver *SSL_VPConfigCameraDriver `protobuf:"varint,1,opt,name=driver,enum=SSL_VPConfigCameraDriver" json:"driver,omitempty"`
- // Spinnaker, mvIMPACT or OpenCV(v4l2) camera id
- Id *uint32 `protobuf:"varint,2,opt,name=id,def=0" json:"id,omitempty"`
- // OpenCV camera device, image or video file path (if unset id is used instead)
- Path *string `protobuf:"bytes,3,opt,name=path,def=" json:"path,omitempty"`
- // Camera resolution as reported by the camera. VisionProcessor might use half (true color) resolution internally with SPINNAKER and MVIMPACT.
- // 0 = Highest resolution supported by camera
- Width *uint32 `protobuf:"varint,4,opt,name=width,def=0" json:"width,omitempty"`
- Height *uint32 `protobuf:"varint,5,opt,name=height,def=0" json:"height,omitempty"`
- // Camera exposure time in ms to adjust brightness. Higher values lead to more motion blur. Lower values lead to a darker image.
- // Camera frame rate will drop if set equal to or higher than the frame time (1 / fps_cam).
- // 0.0 = automatic exposure
- Exposure *float32 `protobuf:"fixed32,6,opt,name=exposure,def=0" json:"exposure,omitempty"`
- // Camera gain to adjust brightness. Higher values lead to more noise. Lower values lead to a darker image.
- // Frequently changing bot identities or team colors indicate an image that is too bright (all colors becoming nearly white).
- // 0.0 = automatic gain
- Gain *float32 `protobuf:"fixed32,7,opt,name=gain,def=0" json:"gain,omitempty"`
- // Camera gamma as nonlinear brightness adjustment. Only supported on SPINNAKER and OPENCV.
- // Low values reduce differences between bright and dark illuminated areas. High values increase the color contrast.
- // 1.0 = no gamma
- Gamma *float32 `protobuf:"fixed32,8,opt,name=gamma,def=1" json:"gamma,omitempty"`
- // Camera white balance. OUTDOOR or INDOOR for auto white balance with green or gray carpet respectively.
- // (distinction between OUTDOOR and INDOOR currently only implemented for SPINNAKER backend)
- WbType *SSL_VPConfigCameraWBType `protobuf:"varint,9,opt,name=wb_type,json=wbType,enum=SSL_VPConfigCameraWBType,def=0" json:"wb_type,omitempty"`
- WbRed *float32 `protobuf:"fixed32,10,opt,name=wb_red,json=wbRed,def=1" json:"wb_red,omitempty"`
- WbBlue *float32 `protobuf:"fixed32,11,opt,name=wb_blue,json=wbBlue,def=1" json:"wb_blue,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-// Default values for SSL_VPConfigCamera fields.
-const (
- Default_SSL_VPConfigCamera_Id = uint32(0)
- Default_SSL_VPConfigCamera_Path = string("")
- Default_SSL_VPConfigCamera_Width = uint32(0)
- Default_SSL_VPConfigCamera_Height = uint32(0)
- Default_SSL_VPConfigCamera_Exposure = float32(0)
- Default_SSL_VPConfigCamera_Gain = float32(0)
- Default_SSL_VPConfigCamera_Gamma = float32(1)
- Default_SSL_VPConfigCamera_WbType = SSL_VPConfigCameraWBType_OUTDOOR
- Default_SSL_VPConfigCamera_WbRed = float32(1)
- Default_SSL_VPConfigCamera_WbBlue = float32(1)
-)
-
-func (x *SSL_VPConfigCamera) Reset() {
- *x = SSL_VPConfigCamera{}
- mi := &file_vision_ssl_vp_config_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_VPConfigCamera) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_VPConfigCamera) ProtoMessage() {}
-
-func (x *SSL_VPConfigCamera) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vp_config_proto_msgTypes[0]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_VPConfigCamera.ProtoReflect.Descriptor instead.
-func (*SSL_VPConfigCamera) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *SSL_VPConfigCamera) GetDriver() SSL_VPConfigCameraDriver {
- if x != nil && x.Driver != nil {
- return *x.Driver
- }
- return SSL_VPConfigCameraDriver_SPINNAKER
-}
-
-func (x *SSL_VPConfigCamera) GetId() uint32 {
- if x != nil && x.Id != nil {
- return *x.Id
- }
- return Default_SSL_VPConfigCamera_Id
-}
-
-func (x *SSL_VPConfigCamera) GetPath() string {
- if x != nil && x.Path != nil {
- return *x.Path
- }
- return Default_SSL_VPConfigCamera_Path
-}
-
-func (x *SSL_VPConfigCamera) GetWidth() uint32 {
- if x != nil && x.Width != nil {
- return *x.Width
- }
- return Default_SSL_VPConfigCamera_Width
-}
-
-func (x *SSL_VPConfigCamera) GetHeight() uint32 {
- if x != nil && x.Height != nil {
- return *x.Height
- }
- return Default_SSL_VPConfigCamera_Height
-}
-
-func (x *SSL_VPConfigCamera) GetExposure() float32 {
- if x != nil && x.Exposure != nil {
- return *x.Exposure
- }
- return Default_SSL_VPConfigCamera_Exposure
-}
-
-func (x *SSL_VPConfigCamera) GetGain() float32 {
- if x != nil && x.Gain != nil {
- return *x.Gain
- }
- return Default_SSL_VPConfigCamera_Gain
-}
-
-func (x *SSL_VPConfigCamera) GetGamma() float32 {
- if x != nil && x.Gamma != nil {
- return *x.Gamma
- }
- return Default_SSL_VPConfigCamera_Gamma
-}
-
-func (x *SSL_VPConfigCamera) GetWbType() SSL_VPConfigCameraWBType {
- if x != nil && x.WbType != nil {
- return *x.WbType
- }
- return Default_SSL_VPConfigCamera_WbType
-}
-
-func (x *SSL_VPConfigCamera) GetWbRed() float32 {
- if x != nil && x.WbRed != nil {
- return *x.WbRed
- }
- return Default_SSL_VPConfigCamera_WbRed
-}
-
-func (x *SSL_VPConfigCamera) GetWbBlue() float32 {
- if x != nil && x.WbBlue != nil {
- return *x.WbBlue
- }
- return Default_SSL_VPConfigCamera_WbBlue
-}
-
-type SSL_VPConfigGeometry struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // Total camera amount over the field
- CameraAmount *uint32 `protobuf:"varint,1,opt,name=camera_amount,json=cameraAmount,def=1" json:"camera_amount,omitempty"`
- // Camera height above field in mm
- // 0.0 = automated camera height calibration, this does not work if the camera looks perpendicular to the field.
- CameraHeight *float32 `protobuf:"fixed32,2,opt,name=camera_height,json=cameraHeight,def=0" json:"camera_height,omitempty"`
- // Field line crossings at the edges of the camera extent in pixels from the top left image corner.
- // The first coordinate must be the edge with the smallest x and y field coordinate.
- LineCorners []*gamecontroller.Vector2 `protobuf:"bytes,3,rep,name=line_corners,json=lineCorners" json:"line_corners,omitempty"`
- // Enable field line pixel refinement.
- // Disable in cluttered environments when the geometry calibration has failed multiple times in a row.
- Refinement *bool `protobuf:"varint,4,opt,name=refinement,def=1" json:"refinement,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-// Default values for SSL_VPConfigGeometry fields.
-const (
- Default_SSL_VPConfigGeometry_CameraAmount = uint32(1)
- Default_SSL_VPConfigGeometry_CameraHeight = float32(0)
- Default_SSL_VPConfigGeometry_Refinement = bool(true)
-)
-
-func (x *SSL_VPConfigGeometry) Reset() {
- *x = SSL_VPConfigGeometry{}
- mi := &file_vision_ssl_vp_config_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_VPConfigGeometry) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_VPConfigGeometry) ProtoMessage() {}
-
-func (x *SSL_VPConfigGeometry) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vp_config_proto_msgTypes[1]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_VPConfigGeometry.ProtoReflect.Descriptor instead.
-func (*SSL_VPConfigGeometry) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{1}
-}
-
-func (x *SSL_VPConfigGeometry) GetCameraAmount() uint32 {
- if x != nil && x.CameraAmount != nil {
- return *x.CameraAmount
- }
- return Default_SSL_VPConfigGeometry_CameraAmount
-}
-
-func (x *SSL_VPConfigGeometry) GetCameraHeight() float32 {
- if x != nil && x.CameraHeight != nil {
- return *x.CameraHeight
- }
- return Default_SSL_VPConfigGeometry_CameraHeight
-}
-
-func (x *SSL_VPConfigGeometry) GetLineCorners() []*gamecontroller.Vector2 {
- if x != nil {
- return x.LineCorners
- }
- return nil
-}
-
-func (x *SSL_VPConfigGeometry) GetRefinement() bool {
- if x != nil && x.Refinement != nil {
- return *x.Refinement
- }
- return Default_SSL_VPConfigGeometry_Refinement
-}
-
-type SSL_VPConfigThresholds struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // Minimum mean cosine similarity (not normalized) of the blob border gradient (0 - 195075.0)
- // High value lead to undetected blobs. Low values lead to an increase in false positive blob detections.
- Circularity *float32 `protobuf:"fixed32,1,opt,name=circularity,def=15" json:"circularity,omitempty"`
- // Minimum circularity/(3*stddev) ball blob score
- Score *float32 `protobuf:"fixed32,2,opt,name=score,def=5" json:"score,omitempty"`
- // Minimum confidence (0.0 - 1.0)
- MinConfidence *float32 `protobuf:"fixed32,3,opt,name=min_confidence,json=minConfidence,def=0.2" json:"min_confidence,omitempty"`
- // Min ball camera edge distance in mm
- MinCamEdgeDistance *float32 `protobuf:"fixed32,4,opt,name=min_cam_edge_distance,json=minCamEdgeDistance,def=170" json:"min_cam_edge_distance,omitempty"`
- // Maximum allowed clipping of two objects in mm
- ClippingTolerance *float32 `protobuf:"fixed32,5,opt,name=clipping_tolerance,json=clippingTolerance,def=10" json:"clipping_tolerance,omitempty"`
- // Added tolerance to geometry related operations in mm.
- // Affects field border cutoff area and field line blob classification.
- GeometryTolerance *float32 `protobuf:"fixed32,6,opt,name=geometry_tolerance,json=geometryTolerance,def=10" json:"geometry_tolerance,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-// Default values for SSL_VPConfigThresholds fields.
-const (
- Default_SSL_VPConfigThresholds_Circularity = float32(15)
- Default_SSL_VPConfigThresholds_Score = float32(5)
- Default_SSL_VPConfigThresholds_MinConfidence = float32(0.20000000298023224)
- Default_SSL_VPConfigThresholds_MinCamEdgeDistance = float32(170)
- Default_SSL_VPConfigThresholds_ClippingTolerance = float32(10)
- Default_SSL_VPConfigThresholds_GeometryTolerance = float32(10)
-)
-
-func (x *SSL_VPConfigThresholds) Reset() {
- *x = SSL_VPConfigThresholds{}
- mi := &file_vision_ssl_vp_config_proto_msgTypes[2]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_VPConfigThresholds) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_VPConfigThresholds) ProtoMessage() {}
-
-func (x *SSL_VPConfigThresholds) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vp_config_proto_msgTypes[2]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_VPConfigThresholds.ProtoReflect.Descriptor instead.
-func (*SSL_VPConfigThresholds) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{2}
-}
-
-func (x *SSL_VPConfigThresholds) GetCircularity() float32 {
- if x != nil && x.Circularity != nil {
- return *x.Circularity
- }
- return Default_SSL_VPConfigThresholds_Circularity
-}
-
-func (x *SSL_VPConfigThresholds) GetScore() float32 {
- if x != nil && x.Score != nil {
- return *x.Score
- }
- return Default_SSL_VPConfigThresholds_Score
-}
-
-func (x *SSL_VPConfigThresholds) GetMinConfidence() float32 {
- if x != nil && x.MinConfidence != nil {
- return *x.MinConfidence
- }
- return Default_SSL_VPConfigThresholds_MinConfidence
-}
-
-func (x *SSL_VPConfigThresholds) GetMinCamEdgeDistance() float32 {
- if x != nil && x.MinCamEdgeDistance != nil {
- return *x.MinCamEdgeDistance
- }
- return Default_SSL_VPConfigThresholds_MinCamEdgeDistance
-}
-
-func (x *SSL_VPConfigThresholds) GetClippingTolerance() float32 {
- if x != nil && x.ClippingTolerance != nil {
- return *x.ClippingTolerance
- }
- return Default_SSL_VPConfigThresholds_ClippingTolerance
-}
-
-func (x *SSL_VPConfigThresholds) GetGeometryTolerance() float32 {
- if x != nil && x.GeometryTolerance != nil {
- return *x.GeometryTolerance
- }
- return Default_SSL_VPConfigThresholds_GeometryTolerance
-}
-
-type Color struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- Red *uint32 `protobuf:"varint,1,opt,name=red,def=128" json:"red,omitempty"`
- Green *uint32 `protobuf:"varint,2,opt,name=green,def=128" json:"green,omitempty"`
- Blue *uint32 `protobuf:"varint,3,opt,name=blue,def=128" json:"blue,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-// Default values for Color fields.
-const (
- Default_Color_Red = uint32(128)
- Default_Color_Green = uint32(128)
- Default_Color_Blue = uint32(128)
-)
-
-func (x *Color) Reset() {
- *x = Color{}
- mi := &file_vision_ssl_vp_config_proto_msgTypes[3]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *Color) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*Color) ProtoMessage() {}
-
-func (x *Color) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vp_config_proto_msgTypes[3]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use Color.ProtoReflect.Descriptor instead.
-func (*Color) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{3}
-}
-
-func (x *Color) GetRed() uint32 {
- if x != nil && x.Red != nil {
- return *x.Red
- }
- return Default_Color_Red
-}
-
-func (x *Color) GetGreen() uint32 {
- if x != nil && x.Green != nil {
- return *x.Green
- }
- return Default_Color_Green
-}
-
-func (x *Color) GetBlue() uint32 {
- if x != nil && x.Blue != nil {
- return *x.Blue
- }
- return Default_Color_Blue
-}
-
-type VPColor struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- Reference *Color `protobuf:"bytes,1,opt,name=reference" json:"reference,omitempty"`
- Live *Color `protobuf:"bytes,2,opt,name=live" json:"live,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *VPColor) Reset() {
- *x = VPColor{}
- mi := &file_vision_ssl_vp_config_proto_msgTypes[4]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *VPColor) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*VPColor) ProtoMessage() {}
-
-func (x *VPColor) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vp_config_proto_msgTypes[4]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use VPColor.ProtoReflect.Descriptor instead.
-func (*VPColor) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{4}
-}
-
-func (x *VPColor) GetReference() *Color {
- if x != nil {
- return x.Reference
- }
- return nil
-}
-
-func (x *VPColor) GetLive() *Color {
- if x != nil {
- return x.Live
- }
- return nil
-}
-
-type SSL_VPConfigColor struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // Strength of the reference color during color updates (0.0 - 0.5-history_force/2)
- ReferenceForce *float32 `protobuf:"fixed32,1,opt,name=reference_force,json=referenceForce,def=0.1" json:"reference_force,omitempty"`
- // Strength of the previous color during color updates (0.0 - 1.0-reference_force)
- HistoryForce *float32 `protobuf:"fixed32,2,opt,name=history_force,json=historyForce,def=0.7" json:"history_force,omitempty"`
- // Colors used for ball determination
- Orange *VPColor `protobuf:"bytes,3,opt,name=orange" json:"orange,omitempty"`
- Field *VPColor `protobuf:"bytes,4,opt,name=field" json:"field,omitempty"`
- // Colors used for center blob determination
- Yellow *VPColor `protobuf:"bytes,5,opt,name=yellow" json:"yellow,omitempty"`
- Blue *VPColor `protobuf:"bytes,6,opt,name=blue" json:"blue,omitempty"`
- // Colors used for side blob determination
- Green *VPColor `protobuf:"bytes,7,opt,name=green" json:"green,omitempty"`
- Pink *VPColor `protobuf:"bytes,8,opt,name=pink" json:"pink,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-// Default values for SSL_VPConfigColor fields.
-const (
- Default_SSL_VPConfigColor_ReferenceForce = float32(0.10000000149011612)
- Default_SSL_VPConfigColor_HistoryForce = float32(0.699999988079071)
-)
-
-func (x *SSL_VPConfigColor) Reset() {
- *x = SSL_VPConfigColor{}
- mi := &file_vision_ssl_vp_config_proto_msgTypes[5]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_VPConfigColor) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_VPConfigColor) ProtoMessage() {}
-
-func (x *SSL_VPConfigColor) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vp_config_proto_msgTypes[5]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_VPConfigColor.ProtoReflect.Descriptor instead.
-func (*SSL_VPConfigColor) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{5}
-}
-
-func (x *SSL_VPConfigColor) GetReferenceForce() float32 {
- if x != nil && x.ReferenceForce != nil {
- return *x.ReferenceForce
- }
- return Default_SSL_VPConfigColor_ReferenceForce
-}
-
-func (x *SSL_VPConfigColor) GetHistoryForce() float32 {
- if x != nil && x.HistoryForce != nil {
- return *x.HistoryForce
- }
- return Default_SSL_VPConfigColor_HistoryForce
-}
-
-func (x *SSL_VPConfigColor) GetOrange() *VPColor {
- if x != nil {
- return x.Orange
- }
- return nil
-}
-
-func (x *SSL_VPConfigColor) GetField() *VPColor {
- if x != nil {
- return x.Field
- }
- return nil
-}
-
-func (x *SSL_VPConfigColor) GetYellow() *VPColor {
- if x != nil {
- return x.Yellow
- }
- return nil
-}
-
-func (x *SSL_VPConfigColor) GetBlue() *VPColor {
- if x != nil {
- return x.Blue
- }
- return nil
-}
-
-func (x *SSL_VPConfigColor) GetGreen() *VPColor {
- if x != nil {
- return x.Green
- }
- return nil
-}
-
-func (x *SSL_VPConfigColor) GetPink() *VPColor {
- if x != nil {
- return x.Pink
- }
- return nil
-}
-
-type SSL_VPConfigNetwork struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // Game controller ip address
- GcIp *string `protobuf:"bytes,1,opt,name=gc_ip,json=gcIp,def=224.5.23.1" json:"gc_ip,omitempty"`
- // Game controller UDP port
- GcPort *uint32 `protobuf:"varint,2,opt,name=gc_port,json=gcPort,def=10003" json:"gc_port,omitempty"`
- // Vision IP address (port impossible to adjust over network)
- VisionIp *string `protobuf:"bytes,3,opt,name=vision_ip,json=visionIp,def=224.5.23.2" json:"vision_ip,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-// Default values for SSL_VPConfigNetwork fields.
-const (
- Default_SSL_VPConfigNetwork_GcIp = string("224.5.23.1")
- Default_SSL_VPConfigNetwork_GcPort = uint32(10003)
- Default_SSL_VPConfigNetwork_VisionIp = string("224.5.23.2")
-)
-
-func (x *SSL_VPConfigNetwork) Reset() {
- *x = SSL_VPConfigNetwork{}
- mi := &file_vision_ssl_vp_config_proto_msgTypes[6]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_VPConfigNetwork) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_VPConfigNetwork) ProtoMessage() {}
-
-func (x *SSL_VPConfigNetwork) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vp_config_proto_msgTypes[6]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_VPConfigNetwork.ProtoReflect.Descriptor instead.
-func (*SSL_VPConfigNetwork) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{6}
-}
-
-func (x *SSL_VPConfigNetwork) GetGcIp() string {
- if x != nil && x.GcIp != nil {
- return *x.GcIp
- }
- return Default_SSL_VPConfigNetwork_GcIp
-}
-
-func (x *SSL_VPConfigNetwork) GetGcPort() uint32 {
- if x != nil && x.GcPort != nil {
- return *x.GcPort
- }
- return Default_SSL_VPConfigNetwork_GcPort
-}
-
-func (x *SSL_VPConfigNetwork) GetVisionIp() string {
- if x != nil && x.VisionIp != nil {
- return *x.VisionIp
- }
- return Default_SSL_VPConfigNetwork_VisionIp
-}
-
-type SSL_VPConfigStream struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // If false no network live stream will be encoded and sent.
- Active *bool `protobuf:"varint,1,opt,name=active,def=1" json:"active,omitempty"`
- // Type of image to transmit.
- Type *SSL_VPConfigStreamType `protobuf:"varint,2,opt,name=type,enum=SSL_VPConfigStreamType,def=0" json:"type,omitempty"`
- // Camera RTP stream destination IP
- StreamIp *string `protobuf:"bytes,3,opt,name=stream_ip,json=streamIp,def=127.0.0.1" json:"stream_ip,omitempty"`
- StreamPort *uint32 `protobuf:"varint,4,opt,name=stream_port,json=streamPort,def=10100" json:"stream_port,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-// Default values for SSL_VPConfigStream fields.
-const (
- Default_SSL_VPConfigStream_Active = bool(true)
- Default_SSL_VPConfigStream_Type = SSL_VPConfigStreamType_RAW
- Default_SSL_VPConfigStream_StreamIp = string("127.0.0.1")
- Default_SSL_VPConfigStream_StreamPort = uint32(10100)
-)
-
-func (x *SSL_VPConfigStream) Reset() {
- *x = SSL_VPConfigStream{}
- mi := &file_vision_ssl_vp_config_proto_msgTypes[7]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_VPConfigStream) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_VPConfigStream) ProtoMessage() {}
-
-func (x *SSL_VPConfigStream) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vp_config_proto_msgTypes[7]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_VPConfigStream.ProtoReflect.Descriptor instead.
-func (*SSL_VPConfigStream) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{7}
-}
-
-func (x *SSL_VPConfigStream) GetActive() bool {
- if x != nil && x.Active != nil {
- return *x.Active
- }
- return Default_SSL_VPConfigStream_Active
-}
-
-func (x *SSL_VPConfigStream) GetType() SSL_VPConfigStreamType {
- if x != nil && x.Type != nil {
- return *x.Type
- }
- return Default_SSL_VPConfigStream_Type
-}
-
-func (x *SSL_VPConfigStream) GetStreamIp() string {
- if x != nil && x.StreamIp != nil {
- return *x.StreamIp
- }
- return Default_SSL_VPConfigStream_StreamIp
-}
-
-func (x *SSL_VPConfigStream) GetStreamPort() uint32 {
- if x != nil && x.StreamPort != nil {
- return *x.StreamPort
- }
- return Default_SSL_VPConfigStream_StreamPort
-}
-
-type SSL_VPConfig struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- // Persistent human-readable network unique identifier (e.g. hostname or hostname:suffix if multiple VP instances on the same host).
- Instance *string `protobuf:"bytes,1,req,name=instance" json:"instance,omitempty"`
- // Corresponding to the camera_id used in SSL_DetectionFrame. Unique per field and implies position on the field:
- // Single camera field: 0 = global field
- // Double camera field: 0 = -x side, 1 = +x side
- // Quadruple cam field: 0 = -x and -y, 1 = -x and +y, 2 = +x and -y, 3 = +x and +y
- // Configuration for more cams depending on field shape.
- CameraId *uint32 `protobuf:"varint,2,opt,name=camera_id,json=cameraId,def=0" json:"camera_id,omitempty"`
- // Database of SSL game controller team names and robot heights in mm.
- // If the team broadcasted by the game controller has no entry, the average robot height is used.
- RobotHeights map[string]float32 `protobuf:"bytes,3,rep,name=robot_heights,json=robotHeights" json:"robot_heights,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"fixed32,2,opt,name=value"`
- Camera *SSL_VPConfigCamera `protobuf:"bytes,4,opt,name=camera" json:"camera,omitempty"`
- Geometry *SSL_VPConfigGeometry `protobuf:"bytes,5,opt,name=geometry" json:"geometry,omitempty"`
- Thresholds *SSL_VPConfigThresholds `protobuf:"bytes,6,opt,name=thresholds" json:"thresholds,omitempty"`
- Color *SSL_VPConfigColor `protobuf:"bytes,7,opt,name=color" json:"color,omitempty"`
- Network *SSL_VPConfigNetwork `protobuf:"bytes,8,opt,name=network" json:"network,omitempty"`
- Stream *SSL_VPConfigStream `protobuf:"bytes,9,opt,name=stream" json:"stream,omitempty"`
- // Wait for geometry prior to processing frames
- WaitForGeometry *bool `protobuf:"varint,10,opt,name=wait_for_geometry,json=waitForGeometry,def=0" json:"wait_for_geometry,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-// Default values for SSL_VPConfig fields.
-const (
- Default_SSL_VPConfig_CameraId = uint32(0)
- Default_SSL_VPConfig_WaitForGeometry = bool(false)
-)
-
-func (x *SSL_VPConfig) Reset() {
- *x = SSL_VPConfig{}
- mi := &file_vision_ssl_vp_config_proto_msgTypes[8]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *SSL_VPConfig) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*SSL_VPConfig) ProtoMessage() {}
-
-func (x *SSL_VPConfig) ProtoReflect() protoreflect.Message {
- mi := &file_vision_ssl_vp_config_proto_msgTypes[8]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use SSL_VPConfig.ProtoReflect.Descriptor instead.
-func (*SSL_VPConfig) Descriptor() ([]byte, []int) {
- return file_vision_ssl_vp_config_proto_rawDescGZIP(), []int{8}
-}
-
-func (x *SSL_VPConfig) GetInstance() string {
- if x != nil && x.Instance != nil {
- return *x.Instance
- }
- return ""
-}
-
-func (x *SSL_VPConfig) GetCameraId() uint32 {
- if x != nil && x.CameraId != nil {
- return *x.CameraId
- }
- return Default_SSL_VPConfig_CameraId
-}
-
-func (x *SSL_VPConfig) GetRobotHeights() map[string]float32 {
- if x != nil {
- return x.RobotHeights
- }
- return nil
-}
-
-func (x *SSL_VPConfig) GetCamera() *SSL_VPConfigCamera {
- if x != nil {
- return x.Camera
- }
- return nil
-}
-
-func (x *SSL_VPConfig) GetGeometry() *SSL_VPConfigGeometry {
- if x != nil {
- return x.Geometry
- }
- return nil
-}
-
-func (x *SSL_VPConfig) GetThresholds() *SSL_VPConfigThresholds {
- if x != nil {
- return x.Thresholds
- }
- return nil
-}
-
-func (x *SSL_VPConfig) GetColor() *SSL_VPConfigColor {
- if x != nil {
- return x.Color
- }
- return nil
-}
-
-func (x *SSL_VPConfig) GetNetwork() *SSL_VPConfigNetwork {
- if x != nil {
- return x.Network
- }
- return nil
-}
-
-func (x *SSL_VPConfig) GetStream() *SSL_VPConfigStream {
- if x != nil {
- return x.Stream
- }
- return nil
-}
-
-func (x *SSL_VPConfig) GetWaitForGeometry() bool {
- if x != nil && x.WaitForGeometry != nil {
- return *x.WaitForGeometry
- }
- return Default_SSL_VPConfig_WaitForGeometry
-}
-
-var File_vision_ssl_vp_config_proto protoreflect.FileDescriptor
-
-const file_vision_ssl_vp_config_proto_rawDesc = "" +
- "\n" +
- "\x1avision/ssl_vp_config.proto\x1a$gamecontroller/ssl_gc_geometry.proto\"\xe6\x02\n" +
- "\x12SSL_VPConfigCamera\x121\n" +
- "\x06driver\x18\x01 \x01(\x0e2\x19.SSL_VPConfigCameraDriverR\x06driver\x12\x11\n" +
- "\x02id\x18\x02 \x01(\r:\x010R\x02id\x12\x14\n" +
- "\x04path\x18\x03 \x01(\t:\x00R\x04path\x12\x17\n" +
- "\x05width\x18\x04 \x01(\r:\x010R\x05width\x12\x19\n" +
- "\x06height\x18\x05 \x01(\r:\x010R\x06height\x12\x1d\n" +
- "\bexposure\x18\x06 \x01(\x02:\x010R\bexposure\x12\x15\n" +
- "\x04gain\x18\a \x01(\x02:\x010R\x04gain\x12\x17\n" +
- "\x05gamma\x18\b \x01(\x02:\x011R\x05gamma\x12;\n" +
- "\awb_type\x18\t \x01(\x0e2\x19.SSL_VPConfigCameraWBType:\aOUTDOORR\x06wbType\x12\x18\n" +
- "\x06wb_red\x18\n" +
- " \x01(\x02:\x011R\x05wbRed\x12\x1a\n" +
- "\awb_blue\x18\v \x01(\x02:\x011R\x06wbBlue\"\xb9\x01\n" +
- "\x14SSL_VPConfigGeometry\x12&\n" +
- "\rcamera_amount\x18\x01 \x01(\r:\x011R\fcameraAmount\x12&\n" +
- "\rcamera_height\x18\x02 \x01(\x02:\x010R\fcameraHeight\x12+\n" +
- "\fline_corners\x18\x03 \x03(\v2\b.Vector2R\vlineCorners\x12$\n" +
- "\n" +
- "refinement\x18\x04 \x01(\b:\x04trueR\n" +
- "refinement\"\xb1\x02\n" +
- "\x16SSL_VPConfigThresholds\x12$\n" +
- "\vcircularity\x18\x01 \x01(\x02:\x0215R\vcircularity\x12\x17\n" +
- "\x05score\x18\x02 \x01(\x02:\x015R\x05score\x12:\n" +
- "\x0emin_confidence\x18\x03 \x01(\x02:\x130.20000000298023224R\rminConfidence\x126\n" +
- "\x15min_cam_edge_distance\x18\x04 \x01(\x02:\x03170R\x12minCamEdgeDistance\x121\n" +
- "\x12clipping_tolerance\x18\x05 \x01(\x02:\x0210R\x11clippingTolerance\x121\n" +
- "\x12geometry_tolerance\x18\x06 \x01(\x02:\x0210R\x11geometryTolerance\"R\n" +
- "\x05Color\x12\x15\n" +
- "\x03red\x18\x01 \x01(\r:\x03128R\x03red\x12\x19\n" +
- "\x05green\x18\x02 \x01(\r:\x03128R\x05green\x12\x17\n" +
- "\x04blue\x18\x03 \x01(\r:\x03128R\x04blue\"K\n" +
- "\aVPColor\x12$\n" +
- "\treference\x18\x01 \x01(\v2\x06.ColorR\treference\x12\x1a\n" +
- "\x04live\x18\x02 \x01(\v2\x06.ColorR\x04live\"\xc9\x02\n" +
- "\x11SSL_VPConfigColor\x12<\n" +
- "\x0freference_force\x18\x01 \x01(\x02:\x130.10000000149011612R\x0ereferenceForce\x126\n" +
- "\rhistory_force\x18\x02 \x01(\x02:\x110.699999988079071R\fhistoryForce\x12 \n" +
- "\x06orange\x18\x03 \x01(\v2\b.VPColorR\x06orange\x12\x1e\n" +
- "\x05field\x18\x04 \x01(\v2\b.VPColorR\x05field\x12 \n" +
- "\x06yellow\x18\x05 \x01(\v2\b.VPColorR\x06yellow\x12\x1c\n" +
- "\x04blue\x18\x06 \x01(\v2\b.VPColorR\x04blue\x12\x1e\n" +
- "\x05green\x18\a \x01(\v2\b.VPColorR\x05green\x12\x1c\n" +
- "\x04pink\x18\b \x01(\v2\b.VPColorR\x04pink\"\x7f\n" +
- "\x13SSL_VPConfigNetwork\x12\x1f\n" +
- "\x05gc_ip\x18\x01 \x01(\t:\n" +
- "224.5.23.1R\x04gcIp\x12\x1e\n" +
- "\agc_port\x18\x02 \x01(\r:\x0510003R\x06gcPort\x12'\n" +
- "\tvision_ip\x18\x03 \x01(\t:\n" +
- "224.5.23.2R\bvisionIp\"\xb4\x01\n" +
- "\x12SSL_VPConfigStream\x12\x1c\n" +
- "\x06active\x18\x01 \x01(\b:\x04trueR\x06active\x120\n" +
- "\x04type\x18\x02 \x01(\x0e2\x17.SSL_VPConfigStreamType:\x03RAWR\x04type\x12&\n" +
- "\tstream_ip\x18\x03 \x01(\t:\t127.0.0.1R\bstreamIp\x12&\n" +
- "\vstream_port\x18\x04 \x01(\r:\x0510100R\n" +
- "streamPort\"\xa4\x04\n" +
- "\fSSL_VPConfig\x12\x1a\n" +
- "\binstance\x18\x01 \x02(\tR\binstance\x12\x1e\n" +
- "\tcamera_id\x18\x02 \x01(\r:\x010R\bcameraId\x12D\n" +
- "\rrobot_heights\x18\x03 \x03(\v2\x1f.SSL_VPConfig.RobotHeightsEntryR\frobotHeights\x12+\n" +
- "\x06camera\x18\x04 \x01(\v2\x13.SSL_VPConfigCameraR\x06camera\x121\n" +
- "\bgeometry\x18\x05 \x01(\v2\x15.SSL_VPConfigGeometryR\bgeometry\x127\n" +
- "\n" +
- "thresholds\x18\x06 \x01(\v2\x17.SSL_VPConfigThresholdsR\n" +
- "thresholds\x12(\n" +
- "\x05color\x18\a \x01(\v2\x12.SSL_VPConfigColorR\x05color\x12.\n" +
- "\anetwork\x18\b \x01(\v2\x14.SSL_VPConfigNetworkR\anetwork\x12+\n" +
- "\x06stream\x18\t \x01(\v2\x13.SSL_VPConfigStreamR\x06stream\x121\n" +
- "\x11wait_for_geometry\x18\n" +
- " \x01(\b:\x05falseR\x0fwaitForGeometry\x1a?\n" +
- "\x11RobotHeightsEntry\x12\x10\n" +
- "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
- "\x05value\x18\x02 \x01(\x02R\x05value:\x028\x01*C\n" +
- "\x18SSL_VPConfigCameraDriver\x12\r\n" +
- "\tSPINNAKER\x10\x00\x12\n" +
- "\n" +
- "\x06OPENCV\x10\x01\x12\f\n" +
- "\bMVIMPACT\x10\x02*?\n" +
- "\x18SSL_VPConfigCameraWBType\x12\v\n" +
- "\aOUTDOOR\x10\x00\x12\n" +
- "\n" +
- "\x06INDOOR\x10\x01\x12\n" +
- "\n" +
- "\x06MANUAL\x10\x02*i\n" +
- "\x16SSL_VPConfigStreamType\x12\a\n" +
- "\x03RAW\x10\x00\x12\x16\n" +
- "\x12REPROJ_FALSE_COLOR\x10\x01\x12\x17\n" +
- "\x13REPROJ_GRADIENT_DOT\x10\x02\x12\x15\n" +
- "\x11REPROJ_BLOB_SCORE\x10\x03BUB\x10SslVpConfigProtoP\x01Z?github.com/RoboCup-SSL/ssl-vision-processor/gui/internal/vision"
-
-var (
- file_vision_ssl_vp_config_proto_rawDescOnce sync.Once
- file_vision_ssl_vp_config_proto_rawDescData []byte
-)
-
-func file_vision_ssl_vp_config_proto_rawDescGZIP() []byte {
- file_vision_ssl_vp_config_proto_rawDescOnce.Do(func() {
- file_vision_ssl_vp_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_vision_ssl_vp_config_proto_rawDesc), len(file_vision_ssl_vp_config_proto_rawDesc)))
- })
- return file_vision_ssl_vp_config_proto_rawDescData
-}
-
-var file_vision_ssl_vp_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
-var file_vision_ssl_vp_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
-var file_vision_ssl_vp_config_proto_goTypes = []any{
- (SSL_VPConfigCameraDriver)(0), // 0: SSL_VPConfigCameraDriver
- (SSL_VPConfigCameraWBType)(0), // 1: SSL_VPConfigCameraWBType
- (SSL_VPConfigStreamType)(0), // 2: SSL_VPConfigStreamType
- (*SSL_VPConfigCamera)(nil), // 3: SSL_VPConfigCamera
- (*SSL_VPConfigGeometry)(nil), // 4: SSL_VPConfigGeometry
- (*SSL_VPConfigThresholds)(nil), // 5: SSL_VPConfigThresholds
- (*Color)(nil), // 6: Color
- (*VPColor)(nil), // 7: VPColor
- (*SSL_VPConfigColor)(nil), // 8: SSL_VPConfigColor
- (*SSL_VPConfigNetwork)(nil), // 9: SSL_VPConfigNetwork
- (*SSL_VPConfigStream)(nil), // 10: SSL_VPConfigStream
- (*SSL_VPConfig)(nil), // 11: SSL_VPConfig
- nil, // 12: SSL_VPConfig.RobotHeightsEntry
- (*gamecontroller.Vector2)(nil), // 13: Vector2
-}
-var file_vision_ssl_vp_config_proto_depIdxs = []int32{
- 0, // 0: SSL_VPConfigCamera.driver:type_name -> SSL_VPConfigCameraDriver
- 1, // 1: SSL_VPConfigCamera.wb_type:type_name -> SSL_VPConfigCameraWBType
- 13, // 2: SSL_VPConfigGeometry.line_corners:type_name -> Vector2
- 6, // 3: VPColor.reference:type_name -> Color
- 6, // 4: VPColor.live:type_name -> Color
- 7, // 5: SSL_VPConfigColor.orange:type_name -> VPColor
- 7, // 6: SSL_VPConfigColor.field:type_name -> VPColor
- 7, // 7: SSL_VPConfigColor.yellow:type_name -> VPColor
- 7, // 8: SSL_VPConfigColor.blue:type_name -> VPColor
- 7, // 9: SSL_VPConfigColor.green:type_name -> VPColor
- 7, // 10: SSL_VPConfigColor.pink:type_name -> VPColor
- 2, // 11: SSL_VPConfigStream.type:type_name -> SSL_VPConfigStreamType
- 12, // 12: SSL_VPConfig.robot_heights:type_name -> SSL_VPConfig.RobotHeightsEntry
- 3, // 13: SSL_VPConfig.camera:type_name -> SSL_VPConfigCamera
- 4, // 14: SSL_VPConfig.geometry:type_name -> SSL_VPConfigGeometry
- 5, // 15: SSL_VPConfig.thresholds:type_name -> SSL_VPConfigThresholds
- 8, // 16: SSL_VPConfig.color:type_name -> SSL_VPConfigColor
- 9, // 17: SSL_VPConfig.network:type_name -> SSL_VPConfigNetwork
- 10, // 18: SSL_VPConfig.stream:type_name -> SSL_VPConfigStream
- 19, // [19:19] is the sub-list for method output_type
- 19, // [19:19] is the sub-list for method input_type
- 19, // [19:19] is the sub-list for extension type_name
- 19, // [19:19] is the sub-list for extension extendee
- 0, // [0:19] is the sub-list for field type_name
-}
-
-func init() { file_vision_ssl_vp_config_proto_init() }
-func file_vision_ssl_vp_config_proto_init() {
- if File_vision_ssl_vp_config_proto != nil {
- return
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: unsafe.Slice(unsafe.StringData(file_vision_ssl_vp_config_proto_rawDesc), len(file_vision_ssl_vp_config_proto_rawDesc)),
- NumEnums: 3,
- NumMessages: 10,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_vision_ssl_vp_config_proto_goTypes,
- DependencyIndexes: file_vision_ssl_vp_config_proto_depIdxs,
- EnumInfos: file_vision_ssl_vp_config_proto_enumTypes,
- MessageInfos: file_vision_ssl_vp_config_proto_msgTypes,
- }.Build()
- File_vision_ssl_vp_config_proto = out.File
- file_vision_ssl_vp_config_proto_goTypes = nil
- file_vision_ssl_vp_config_proto_depIdxs = nil
-}
From 7a38b0a9d308fc39a7579b5c7e673949bb59e06b Mon Sep 17 00:00:00 2001
From: Will Stuckey
Date: Fri, 25 Sep 2026 15:11:40 -0400
Subject: [PATCH 09/23] cleanup after code review
---
.github/workflows/ci.yml | 16 +-
.gitignore | 17 ++
README.md | 6 +
config-camtest.yml | 159 -----------------
config-testpatch.yml | 159 -----------------
geometry-testpatch.yml | 30 ----
gui/Makefile | 20 ++-
gui/cmd/ssl-vision-processor-gui/server.go | 59 ++++---
gui/config.yml | 157 -----------------
gui/frontend/src/App.svelte | 42 ++++-
gui/frontend/src/lib/CornerPicker.svelte | 129 ++++++--------
gui/frontend/src/lib/FieldEditor.svelte | 11 +-
gui/frontend/src/lib/api.ts | 40 +++++
.../config/ConfigCategoryPlaceholder.svelte | 33 +---
.../src/lib/config/ConfigFieldList.svelte | 43 +++++
.../src/lib/config/GeometryPanel.svelte | 37 +---
gui/frontend/src/lib/geometry.svelte.ts | 163 +++++++-----------
gui/frontend/src/lib/layout/ConfigNav.svelte | 11 +-
gui/frontend/src/lib/lineCorners.svelte.ts | 73 ++++++++
gui/internal/geometry/field_config.go | 65 ++++---
gui/internal/geometry/geometry.go | 13 +-
gui/internal/geometry/geometry_test.go | 44 +++++
gui/internal/geometry/instance_config.go | 29 +++-
gui/internal/geometry/instance_config_test.go | 40 +++++
gui/internal/hub/hub.go | 27 ++-
gui/internal/hub/hub_test.go | 23 +++
gui/internal/hub/websocket.go | 20 ++-
gui/internal/logging/logging.go | 24 +--
gui/internal/snapshot/snapshot.go | 21 ++-
gui/internal/snapshot/snapshot_test.go | 33 ++++
30 files changed, 681 insertions(+), 863 deletions(-)
delete mode 100644 config-camtest.yml
delete mode 100644 config-testpatch.yml
delete mode 100644 geometry-testpatch.yml
delete mode 100644 gui/config.yml
create mode 100644 gui/frontend/src/lib/api.ts
create mode 100644 gui/frontend/src/lib/config/ConfigFieldList.svelte
create mode 100644 gui/frontend/src/lib/lineCorners.svelte.ts
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c617dde..4f2abbb 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -49,15 +49,15 @@ jobs:
- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main
- - name: Format, vet, test
+ - name: Format, vet, build, test
run: |
nix develop --command bash -c '
cd gui
make .proto
test -z "$(gofmt -l .)" || { gofmt -l .; exit 1; }
- go vet ./cmd/... ./internal/... ./frontend
- go build ./cmd/... ./internal/... ./frontend
- go test ./cmd/... ./internal/... ./frontend -race
+ make vet
+ make build
+ make go-test
'
frontend:
@@ -77,9 +77,7 @@ jobs:
- name: Lint, check, build
run: |
nix develop --command bash -c '
- cd gui && make .proto && cd frontend
- npm run lint
- npm run format:check
- npm run check
- npm run build
+ cd gui
+ make frontend-test
+ make frontend
'
diff --git a/.gitignore b/.gitignore
index c1fc702..28f9a35 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,23 @@ __pycache__
/test-data
*.log
+# Device/venue-specific configs -- only the reference templates below are
+# tracked. Anything else matching config*.yml/geometry*.yml at the repo root
+# (config-camtest.yml, a real venue's calibration, ...) is a personal/local
+# working file per the README's config[X].yml/geometry[X].yml convention, not
+# shipped source -- `git add -A` has swept these in by accident before.
+/config*.yml
+/geometry*.yml
+!/config.yml
+!/config-minimal.yml
+!/geometry-divA.yml
+!/geometry-divB.yml
+
+# gui/'s own working copies of the above, bootstrapped from geometry-divB.yml
+# / vision_processor's own config.yml default -- same reasoning.
+/gui/config.yml
+/gui/geometry.yml
+
#Output binaries
vision_processor
blob_benchmark
diff --git a/README.md b/README.md
index 16aca7e..c69fac1 100644
--- a/README.md
+++ b/README.md
@@ -85,6 +85,12 @@ Installation with PIP: `pip install protobuf pyyaml`
If the calibration is unsuccessful, restart the geom_publisher for a new geometry calibration.
For setups with multiple cameras it is recommended to tune the calibration by hand.
+Your own `config[X].yml`/`geometry[X].yml` files (camera or venue specific) are gitignored by
+default and won't be committed. Only the reference templates -- `config.yml`, `config-minimal.yml`,
+`geometry-divA.yml`, `geometry-divB.yml` -- are tracked; `gui/config.yml` and `gui/geometry.yml`
+(the GUI's own working copies, bootstrapped from these) are gitignored the same way. If you need to
+track a variant anyway, `git add -f` it.
+
## Troubleshooting
diff --git a/config-camtest.yml b/config-camtest.yml
deleted file mode 100644
index 88c8867..0000000
--- a/config-camtest.yml
+++ /dev/null
@@ -1,159 +0,0 @@
-# VisionProcessor configuration
-
-# Vision camera ID handled by this VisionProcessor instance.
-# On multi camera fields the IDs have to be ordered according to camera_ids.png.
-#cam_id: 0
-
-# Team bot heights yml file (heights in mm)
-#bot_heights_file: robot-heights.yml
-
-camera:
- # Camera driver type. Availability depending on libraries installed.
- # Existing: SPINNAKER (FLIR cameras), MVIMPACT (Bluefox3 cameras), OPENCV(files, v4l2 cameras)
- driver: OPENCV
-
- # Spinnaker, mvIMPACT or OpenCV(v4l2) camera id
- #id: 0
- # OpenCV camera device, image or video file path (if unset id is used instead)
- path: /dev/video0
-
- # Camera resolution as reported by the camera. VisionProcessor might use half (true color) resolution internally with SPINNAKER and MVIMPACT.
- # 0 = highest resolution supported by the camera
- #width: 0
- #height: 0
-
- # Camera exposure time in ms to adjust brightness. Higher values lead to more motion blur. Lower values lead to a darker image.
- # Camera frame rate will drop if set equal to or higher than the frame time (1 / fps_cam).
- # 0.0 = automatic exposure
- #exposure: 0.0
- # Camera gain to adjust brightness. Higher values lead to more noise. Lower values lead to a darker image.
- # Frequently changing bot identities or team colors indicate an image that is too bright (all colors becoming nearly white).
- # 0.0 = automatic gain
- #gain: 0.0
- # Camera gamma as nonlinear brightness adjustment. Only supported on SPINNAKER and OPENCV.
- # Low values reduce differences between bright and dark illuminated areas. High values increase the color contrast.
- # 1.0 = no gamma
- #gamma: 1.0
-
- # Camera white balance. OUTDOOR or INDOOR for auto white balance with green or gray carpet respectively.
- # (distinction between OUTDOOR and INDOOR currently only implemented for SPINNAKER backend)
- #white_balance: OUTDOOR
- # If you want to set manual white balance values use this format:
- #white_balance:
- # red: 1.0
- # blue: 1.0
-
-geometry:
- # Total camera amount over the field
- camera_amount: 2
- # Camera height above field in mm
- # 0.0 = automated camera height calibration, this does not work if the camera looks perpendicular to the field
- #camera_height: 0.0
-
- # Field line crossings at the edges of the camera extent in pixels from the top left image corner.
- # The first coordinate must be the edge with the smallest x and y field coordinate.
- # Only the first point's identity matters -- GeomModel.cpp brute-forces the
- # correct clockwise order for the other three. First point = the corner
- # picker's marker 4, which touches the goal box (confirmed against
- # img/0.geomcalib_input.png; marker 3 is the same goal-box edge's other end
- # and would also be a valid choice). Left/right (marker 3 vs 4 first) is an
- # arbitrary but so-far-unverified choice: doesn't matter with one camera,
- # would need to agree with camera 1 if a second one joins.
- line_corners:
- - [398, 422]
- - [247, 135]
- - [455, 33]
- - [564, 327]
-
- # Enable field line pixel refinement.
- # Disable in cluttered environments when the geometry calibration has failed multiple times in a row.
- #refinement: true
-
- # Minimum brightness difference to surrounding pixels for the classification as field line pixel (0 - 255)
- #field_line_threshold: 5
- # Minimum length of line segments to ensure angular stability in pixels
- #min_line_segment_length: 10.0
- # Maximum perpendicular offset of line segments for merging in pixels
- #max_line_segment_offset: 10.0
- # Maximum relative angle of line segments for merging in °
- #max_line_segment_angle: 3.0
-
-thresholds:
- # Minimum mean cosine similarity (not normalized) of the blob border gradient (0 - 195075.0)
- # High value lead to undetected blobs. Low values lead to an increase in false positive blob detections.
- #circularity: 15.0
- # Minimum circularity/(3*stddev) ball blob score
- #score: 5.0
-
- # Maximum amount of blobs processed per frame. Should not be necessary to adjust this value.
- #blobs: 2000
-
- # Minimum confidence (0.0 - 1.0)
- #min_confidence: 0.2
-
- # Min ball camera edge distance in mm
- #min_cam_edge_distance: 170.0
-
- # Maximum allowed clipping of two objects in mm
- #clipping_tolerance: 10.0
-
- # Added tolerance to geometry related operations in mm.
- # Affects field border cutoff area and field line blob classification.
- #geometry_tolerance: 10.0
-
-color:
- # Strength of the reference color during color updates (0.0 - 0.5-history_force/2)
- #reference_force: 0.1
- # Strength of the previous color during color updates (0.0 - 1.0-reference_force)
- #history_force: 0.7
-
- # Reference colors used for ball determination
- #orange: [192, 128, 64]
- #field: [128, 128, 128]
- # Reference colors used for center blob determination
- #yellow: [255, 128, 0]
- #blue: [0, 128, 255]
- # Reference colors used for side blob determination
- #green: [0, 255, 128]
- #pink: [255, 0, 128]
-
-tracking:
- # Min tracking radius in mm
- #min_tracking_radius: 20.0
-
- # Max tracked bot acceleration in m/s^2
- #max_bot_acceleration: 6.5
-
-network:
- # Game controller multicast ip address
- #gc_ip: "224.5.23.1"
- # Game controller multicast port
- #gc_port: 10003
-
- # Vision multicast IP address
- #vision_ip: "224.5.23.2"
- # Vision multicast port
- #vision_port: 10006
-
-stream:
- # If false no network live stream will be encoded and sent
- #active: true
- # Only stream raw camera footage. Useful for recordings.
- #raw_feed: false
-
- # Camera stream ip prefix
- #ip_base_prefix: 224.5.23.
- # Camera stream ip end base (cam_id is added to maintain separation)
- #ip_base_end: 100
- # Camera stream port
- #port: 10100
-
-debug:
- # Ground truth file. Only used by blob and geometry benchmark.
- #ground_truth: gt.yml
- # Wait for geometry prior to processing frames
- #wait_for_geometry: false
- # Save additional debug images in img/.
- #debug_images: false
- # Periodically overwrite img/.sample..png while calibration isn't accepted yet, every N milliseconds. 0 disables.
- debug_stream_interval_ms: 3000
diff --git a/config-testpatch.yml b/config-testpatch.yml
deleted file mode 100644
index 25a7d77..0000000
--- a/config-testpatch.yml
+++ /dev/null
@@ -1,159 +0,0 @@
-# VisionProcessor configuration
-
-# Vision camera ID handled by this VisionProcessor instance.
-# On multi camera fields the IDs have to be ordered according to camera_ids.png.
-#cam_id: 0
-
-# Team bot heights yml file (heights in mm)
-#bot_heights_file: robot-heights.yml
-
-camera:
- # Camera driver type. Availability depending on libraries installed.
- # Existing: SPINNAKER (FLIR cameras), MVIMPACT (Bluefox3 cameras), OPENCV(files, v4l2 cameras)
- #driver: SPINNAKER
-
- # Spinnaker, mvIMPACT or OpenCV(v4l2) camera id
- #id: 0
- # OpenCV camera device, image or video file path (if unset id is used instead)
- #path: /dev/video0
-
- # Camera resolution as reported by the camera. VisionProcessor might use half (true color) resolution internally with SPINNAKER and MVIMPACT.
- # 0 = highest resolution supported by the camera
- #width: 0
- #height: 0
-
- # Camera exposure time in ms to adjust brightness. Higher values lead to more motion blur. Lower values lead to a darker image.
- # Camera frame rate will drop if set equal to or higher than the frame time (1 / fps_cam).
- # 0.0 = automatic exposure
- #exposure: 0.0
- # Camera gain to adjust brightness. Higher values lead to more noise. Lower values lead to a darker image.
- # Frequently changing bot identities or team colors indicate an image that is too bright (all colors becoming nearly white).
- # 0.0 = automatic gain
- #gain: 0.0
- # Camera gamma as nonlinear brightness adjustment. Only supported on SPINNAKER and OPENCV.
- # Low values reduce differences between bright and dark illuminated areas. High values increase the color contrast.
- # 1.0 = no gamma
- #gamma: 1.0
-
- # Camera white balance. OUTDOOR or INDOOR for auto white balance with green or gray carpet respectively.
- # (distinction between OUTDOOR and INDOOR currently only implemented for SPINNAKER backend)
- #white_balance: OUTDOOR
- # If you want to set manual white balance values use this format:
- #white_balance:
- # red: 1.0
- # blue: 1.0
-
-geometry:
- line_corners:
- - [1134, 948]
- - [1509, 729]
- - [1266, 69]
- - [798, 300]
- # Total camera amount over the field
- #camera_amount: 1
- # Camera height above field in mm
- # 0.0 = automated camera height calibration, this does not work if the camera looks perpendicular to the field
- #camera_height: 0.0
-
- # Field line crossings at the edges of the camera extent in pixels from the top left image corner.
- # The first coordinate must be the edge with the smallest x and y field coordinate.
- #line_corners:
- #- [0 , 1000]
- #- [0 , 0]
- #- [1000, 0]
- #- [1000, 1000]
-
- # Enable field line pixel refinement.
- # Disable in cluttered environments when the geometry calibration has failed multiple times in a row.
- #refinement: true
-
- # Minimum brightness difference to surrounding pixels for the classification as field line pixel (0 - 255)
- #field_line_threshold: 5
- # Minimum length of line segments to ensure angular stability in pixels
- #min_line_segment_length: 10.0
- # Maximum perpendicular offset of line segments for merging in pixels
- #max_line_segment_offset: 10.0
- # Maximum relative angle of line segments for merging in °
- #max_line_segment_angle: 3.0
-
- # Which corner-picker marker (1-4, its on-screen number) was chosen as the goal-side corner. Not read by vision_processor -- record only.
- goal_side_marker: 1
-thresholds:
- # Minimum mean cosine similarity (not normalized) of the blob border gradient (0 - 195075.0)
- # High value lead to undetected blobs. Low values lead to an increase in false positive blob detections.
- #circularity: 15.0
- # Minimum circularity/(3*stddev) ball blob score
- #score: 5.0
-
- # Maximum amount of blobs processed per frame. Should not be necessary to adjust this value.
- #blobs: 2000
-
- # Minimum confidence (0.0 - 1.0)
- #min_confidence: 0.2
-
- # Min ball camera edge distance in mm
- #min_cam_edge_distance: 170.0
-
- # Maximum allowed clipping of two objects in mm
- #clipping_tolerance: 10.0
-
- # Added tolerance to geometry related operations in mm.
- # Affects field border cutoff area and field line blob classification.
- #geometry_tolerance: 10.0
-
-color:
- # Strength of the reference color during color updates (0.0 - 0.5-history_force/2)
- #reference_force: 0.1
- # Strength of the previous color during color updates (0.0 - 1.0-reference_force)
- #history_force: 0.7
-
- # Reference colors used for ball determination
- #orange: [192, 128, 64]
- #field: [128, 128, 128]
- # Reference colors used for center blob determination
- #yellow: [255, 128, 0]
- #blue: [0, 128, 255]
- # Reference colors used for side blob determination
- #green: [0, 255, 128]
- #pink: [255, 0, 128]
-
-tracking:
- # Min tracking radius in mm
- #min_tracking_radius: 20.0
-
- # Max tracked bot acceleration in m/s^2
- #max_bot_acceleration: 6.5
-
-network:
- # Game controller multicast ip address
- #gc_ip: "224.5.23.1"
- # Game controller multicast port
- #gc_port: 10003
-
- # Vision multicast IP address
- #vision_ip: "224.5.23.2"
- # Vision multicast port
- #vision_port: 10006
-
-stream:
- # If false no network live stream will be encoded and sent
- #active: true
- # Only stream raw camera footage. Useful for recordings.
- #raw_feed: false
-
- # Camera stream ip prefix
- #ip_base_prefix: 224.5.23.
- # Camera stream ip end base (cam_id is added to maintain separation)
- #ip_base_end: 100
- # Camera stream port
- #port: 10100
-
-debug:
- # Ground truth file. Only used by blob and geometry benchmark.
- #ground_truth: gt.yml
- # Wait for geometry prior to processing frames
- #wait_for_geometry: false
- # Save additional debug images in img/.
- #debug_images: false
- # Periodically overwrite img/.sample..png while calibration isn't accepted yet, every N milliseconds. 0 disables.
- #debug_stream_interval_ms: 0
diff --git a/geometry-testpatch.yml b/geometry-testpatch.yml
deleted file mode 100644
index 0eba29c..0000000
--- a/geometry-testpatch.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-field:
- field_length: 2160
- field_width: 1680
- goal_width: 280
- goal_depth: 50
- goal_height: 160
- penalty_area_depth: 290
- penalty_area_width: 570
- goal_center_to_penalty_mark: 1440
- boundary_width: 100
- boundary_width_goal_line: 100
- center_circle_radius: 140
- line_thickness: 10
- ball_radius: 22
- max_robot_radius: 90
- goal_substitution_area_width: 0
-models:
- chip_fixed_loss:
- damping_xy_first_hop: 0.55
- damping_xy_other_hops: 0.88
- damping_z: 0.54
- straight_two_phase:
- acc_roll: -0.45
- acc_slide: -3.4
- k_switch: 0.64
-optional_field_lines:
- centercircle: false
- goal2goal: false
- halfway: true
- penalty: true
diff --git a/gui/Makefile b/gui/Makefile
index bbf09eb..fb97694 100644
--- a/gui/Makefile
+++ b/gui/Makefile
@@ -11,7 +11,7 @@ FRONTEND_SOURCES = $(shell find frontend -type f \
PROTO_SOURCES = $(shell find ../proto/proto -type f 2>/dev/null)
-.PHONY: all frontend install test run proto clean
+.PHONY: all frontend install test go-test frontend-test vet build run proto clean
all: install
@@ -47,9 +47,23 @@ frontend: .frontend
install: frontend
go install -v $(GO_PACKAGES)
-test: frontend
+vet: frontend
+ go vet $(GO_PACKAGES)
+
+build: frontend
+ go build $(GO_PACKAGES)
+
+go-test: frontend
+ go test $(GO_PACKAGES) -race
+
+frontend-test: frontend
cd frontend && npm run check && npm run lint && npm run format:check
- go test $(GO_PACKAGES)
+
+# CI runs go-test and frontend-test as separate parallel jobs (see
+# .github/workflows/ci.yml) -- this is the single "everything before you
+# push" target for local use, composed of exactly those same two so the
+# package/command lists live in one place either way.
+test: go-test frontend-test
run: frontend
go run ./cmd/$(BINARY)
diff --git a/gui/cmd/ssl-vision-processor-gui/server.go b/gui/cmd/ssl-vision-processor-gui/server.go
index 48aa0bd..f0bc2bf 100644
--- a/gui/cmd/ssl-vision-processor-gui/server.go
+++ b/gui/cmd/ssl-vision-processor-gui/server.go
@@ -81,6 +81,29 @@ func (s *VisionServer) handleGetFieldConfig() http.HandlerFunc {
}
}
+// respondGeometryErr classifies an error from a geometry package call and
+// writes the matching HTTP response: a caller-fixable *ValidationError or
+// *ReadOnlyError becomes 400 (the error's own message is safe to return --
+// both types exist specifically to describe the caller's mistake back to
+// them), anything else is logged and reported as a generic 500. Shared by
+// every handler whose geometry call can fail either way.
+//
+// handlePostLoad deliberately does not use this: every LoadFrom failure is
+// about the path the caller gave, not an internal failure on our part, so
+// it's unconditionally 400 regardless of error type -- see its own comment.
+func respondGeometryErr(w http.ResponseWriter, err error, logMsg string, logArgs ...any) {
+ var validation *geometry.ValidationError
+ var readOnly *geometry.ReadOnlyError
+
+ switch {
+ case errors.As(err, &validation), errors.As(err, &readOnly):
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ default:
+ slog.Error(logMsg, append(logArgs, "err", err)...)
+ http.Error(w, "internal error", http.StatusInternalServerError)
+ }
+}
+
// handlePutFieldConfig edits the virtual field: dimensions and which optional
// markings exist. Regenerates the derived field lines/arcs and persists to
// geometry.yml -- see geometry.Geometry.UpdateField.
@@ -94,16 +117,7 @@ func (s *VisionServer) handlePutFieldConfig() http.HandlerFunc {
}
if err := s.geometry.UpdateField(req.Field, req.OptionalFieldLines); err != nil {
- var validation *geometry.ValidationError
- var readOnly *geometry.ReadOnlyError
-
- switch {
- case errors.As(err, &validation), errors.As(err, &readOnly):
- http.Error(w, err.Error(), http.StatusBadRequest)
- default:
- slog.Error("updating field config", "err", err)
- http.Error(w, "internal error", http.StatusInternalServerError)
- }
+ respondGeometryErr(w, err, "updating field config")
return
}
@@ -135,16 +149,7 @@ func (s *VisionServer) handlePostSaveAs() http.HandlerFunc {
}
if err := s.geometry.SaveAs(req.Path, req.Field, req.OptionalFieldLines); err != nil {
- var validation *geometry.ValidationError
- var readOnly *geometry.ReadOnlyError
-
- switch {
- case errors.As(err, &validation), errors.As(err, &readOnly):
- http.Error(w, err.Error(), http.StatusBadRequest)
- default:
- slog.Error("saving field config as", "path", req.Path, "err", err)
- http.Error(w, "internal error", http.StatusInternalServerError)
- }
+ respondGeometryErr(w, err, "saving field config as", "path", req.Path)
return
}
@@ -245,17 +250,11 @@ func (s *VisionServer) handlePutLineCorners() http.HandlerFunc {
return
}
- if req.GoalSideMarker < 1 || req.GoalSideMarker > len(req.Corners) {
- http.Error(w, "goalSideMarker: must identify one of the given corners", http.StatusBadRequest)
-
- return
- }
-
- // s.configFile is server config, not part of the request -- a
- // failure here is our problem, not the caller's, so 500.
+ // goalSideMarker's own range check lives in WriteLineCorners, not
+ // duplicated here -- it returns a *ValidationError for exactly this
+ // case, which respondGeometryErr turns back into a 400.
if err := geometry.WriteLineCorners(s.configFile, req.Corners, req.GoalSideMarker); err != nil {
- slog.Error("writing line corners", "path", s.configFile, "err", err)
- http.Error(w, "internal error", http.StatusInternalServerError)
+ respondGeometryErr(w, err, "writing line corners", "path", s.configFile)
return
}
diff --git a/gui/config.yml b/gui/config.yml
deleted file mode 100644
index 7892dcc..0000000
--- a/gui/config.yml
+++ /dev/null
@@ -1,157 +0,0 @@
-# VisionProcessor configuration
-
-# Vision camera ID handled by this VisionProcessor instance.
-# On multi camera fields the IDs have to be ordered according to camera_ids.png.
-#cam_id: 0
-
-# Team bot heights yml file (heights in mm)
-#bot_heights_file: robot-heights.yml
-
-camera:
- # Camera driver type. Availability depending on libraries installed.
- # Existing: SPINNAKER (FLIR cameras), MVIMPACT (Bluefox3 cameras), OPENCV(files, v4l2 cameras)
- #driver: SPINNAKER
-
- # Spinnaker, mvIMPACT or OpenCV(v4l2) camera id
- #id: 0
- # OpenCV camera device, image or video file path (if unset id is used instead)
- #path: /dev/video0
-
- # Camera resolution as reported by the camera. VisionProcessor might use half (true color) resolution internally with SPINNAKER and MVIMPACT.
- # 0 = highest resolution supported by the camera
- #width: 0
- #height: 0
-
- # Camera exposure time in ms to adjust brightness. Higher values lead to more motion blur. Lower values lead to a darker image.
- # Camera frame rate will drop if set equal to or higher than the frame time (1 / fps_cam).
- # 0.0 = automatic exposure
- #exposure: 0.0
- # Camera gain to adjust brightness. Higher values lead to more noise. Lower values lead to a darker image.
- # Frequently changing bot identities or team colors indicate an image that is too bright (all colors becoming nearly white).
- # 0.0 = automatic gain
- #gain: 0.0
- # Camera gamma as nonlinear brightness adjustment. Only supported on SPINNAKER and OPENCV.
- # Low values reduce differences between bright and dark illuminated areas. High values increase the color contrast.
- # 1.0 = no gamma
- #gamma: 1.0
-
- # Camera white balance. OUTDOOR or INDOOR for auto white balance with green or gray carpet respectively.
- # (distinction between OUTDOOR and INDOOR currently only implemented for SPINNAKER backend)
- #white_balance: OUTDOOR
- # If you want to set manual white balance values use this format:
- #white_balance:
- # red: 1.0
- # blue: 1.0
-
-geometry:
- line_corners:
- - [1131, 945]
- - [1263, 69]
- - [1509, 726]
- - [792, 300]
- # Total camera amount over the field
- #camera_amount: 1
- # Camera height above field in mm
- # 0.0 = automated camera height calibration, this does not work if the camera looks perpendicular to the field
- #camera_height: 0.0
-
- # Field line crossings at the edges of the camera extent in pixels from the top left image corner.
- # The first coordinate must be the edge with the smallest x and y field coordinate.
- #line_corners:
- #- [0 , 1000]
- #- [0 , 0]
- #- [1000, 0]
- #- [1000, 1000]
-
- # Enable field line pixel refinement.
- # Disable in cluttered environments when the geometry calibration has failed multiple times in a row.
- #refinement: true
-
- # Minimum brightness difference to surrounding pixels for the classification as field line pixel (0 - 255)
- #field_line_threshold: 5
- # Minimum length of line segments to ensure angular stability in pixels
- #min_line_segment_length: 10.0
- # Maximum perpendicular offset of line segments for merging in pixels
- #max_line_segment_offset: 10.0
- # Maximum relative angle of line segments for merging in °
- #max_line_segment_angle: 3.0
-
-thresholds:
- # Minimum mean cosine similarity (not normalized) of the blob border gradient (0 - 195075.0)
- # High value lead to undetected blobs. Low values lead to an increase in false positive blob detections.
- #circularity: 15.0
- # Minimum circularity/(3*stddev) ball blob score
- #score: 5.0
-
- # Maximum amount of blobs processed per frame. Should not be necessary to adjust this value.
- #blobs: 2000
-
- # Minimum confidence (0.0 - 1.0)
- #min_confidence: 0.2
-
- # Min ball camera edge distance in mm
- #min_cam_edge_distance: 170.0
-
- # Maximum allowed clipping of two objects in mm
- #clipping_tolerance: 10.0
-
- # Added tolerance to geometry related operations in mm.
- # Affects field border cutoff area and field line blob classification.
- #geometry_tolerance: 10.0
-
-color:
- # Strength of the reference color during color updates (0.0 - 0.5-history_force/2)
- #reference_force: 0.1
- # Strength of the previous color during color updates (0.0 - 1.0-reference_force)
- #history_force: 0.7
-
- # Reference colors used for ball determination
- #orange: [192, 128, 64]
- #field: [128, 128, 128]
- # Reference colors used for center blob determination
- #yellow: [255, 128, 0]
- #blue: [0, 128, 255]
- # Reference colors used for side blob determination
- #green: [0, 255, 128]
- #pink: [255, 0, 128]
-
-tracking:
- # Min tracking radius in mm
- #min_tracking_radius: 20.0
-
- # Max tracked bot acceleration in m/s^2
- #max_bot_acceleration: 6.5
-
-network:
- # Game controller multicast ip address
- #gc_ip: "224.5.23.1"
- # Game controller multicast port
- #gc_port: 10003
-
- # Vision multicast IP address
- #vision_ip: "224.5.23.2"
- # Vision multicast port
- #vision_port: 10006
-
-stream:
- # If false no network live stream will be encoded and sent
- #active: true
- # Only stream raw camera footage. Useful for recordings.
- #raw_feed: false
-
- # Camera stream ip prefix
- #ip_base_prefix: 224.5.23.
- # Camera stream ip end base (cam_id is added to maintain separation)
- #ip_base_end: 100
- # Camera stream port
- #port: 10100
-
-debug:
- # Ground truth file. Only used by blob and geometry benchmark.
- #ground_truth: gt.yml
- # Wait for geometry prior to processing frames
- #wait_for_geometry: false
- # Save additional debug images in img/.
- #debug_images: false
- # Periodically overwrite img/.sample..png while calibration isn't accepted yet, every N milliseconds. 0 disables.
- #debug_stream_interval_ms: 0
diff --git a/gui/frontend/src/App.svelte b/gui/frontend/src/App.svelte
index 700555f..7ec0626 100644
--- a/gui/frontend/src/App.svelte
+++ b/gui/frontend/src/App.svelte
@@ -2,10 +2,38 @@
import { onMount } from "svelte";
import { topic } from "./lib/wrapper-bus";
import Shell from "./lib/layout/Shell.svelte";
- import { nav } from "./lib/layout/nav.svelte";
+ import { nav, selectedCategory } from "./lib/layout/nav.svelte";
+ import { requestJSON } from "./lib/api";
let subscribed = $state(false);
- const wrapperPacket = topic>("wrapper_packet.out");
+ let wrapperPacket = $state | null>(null);
+
+ // topic()'s store only subscribes to the bus (sending the WS "subscribe"
+ // message) once something calls .subscribe() on it -- gating that call on
+ // `subscribed` here, instead of an auto-subscribing `$wrapperPacket`
+ // reference in the template, is what makes the toggle below actually
+ // control the traffic. A `$store` reference anywhere in a component
+ // auto-subscribes at init regardless of which template branch it's in, so
+ // referencing it only inside `{#if subscribed}` would NOT have gated
+ // anything -- the WS subscribe message would still fire on mount.
+ $effect(() => {
+ if (!subscribed) {
+ wrapperPacket = null;
+
+ return;
+ }
+
+ const unsubscribe = topic>(
+ "wrapper_packet.out",
+ ).subscribe((value) => {
+ wrapperPacket = value;
+ });
+
+ return () => {
+ unsubscribe();
+ wrapperPacket = null;
+ };
+ });
// Same-origin: the Go host serves /api itself, alongside /ws and the frontend.
interface Snapshot {
@@ -27,8 +55,8 @@
async function refreshSnapshotList(): Promise {
try {
- const response = await fetch("/api/snapshots");
- if (response.ok) snapshots = (await response.json()) as Snapshot[];
+ const response = await requestJSON("/api/snapshots");
+ snapshots = (await response.json()) as Snapshot[];
} catch {
// ignore: next tick will retry
}
@@ -65,7 +93,7 @@
Temporary debug utilities -- see the note in this file's source.
- {#if nav.selectedCategoryId !== "field"}
+ {#if selectedCategory().scope === "per-instance"}
Snapshots
{#if visibleSnapshots.length === 0}
@@ -92,8 +120,8 @@
{#if subscribed}
- {#if $wrapperPacket}
- {JSON.stringify($wrapperPacket, null, 2)}
+ {#if wrapperPacket}
+ {JSON.stringify(wrapperPacket, null, 2)}
{:else}
Waiting for first frame…
{/if}
diff --git a/gui/frontend/src/lib/CornerPicker.svelte b/gui/frontend/src/lib/CornerPicker.svelte
index 12bd77e..2f3fa73 100644
--- a/gui/frontend/src/lib/CornerPicker.svelte
+++ b/gui/frontend/src/lib/CornerPicker.svelte
@@ -1,5 +1,10 @@
@@ -254,16 +233,16 @@
- {saving ? "Saving..." : "Save to config.yml"}
+ {lineCorners.saving ? "Saving..." : "Save to config.yml"}
- {#if savedAt}
+ {#if lineCorners.savedAt}
Saved.
{/if}
- {#if saveError}
- Error: {saveError}
+ {#if lineCorners.error}
+ Error: {lineCorners.error}
{/if}
diff --git a/gui/frontend/src/lib/FieldEditor.svelte b/gui/frontend/src/lib/FieldEditor.svelte
index 36f9da6..e743fd1 100644
--- a/gui/frontend/src/lib/FieldEditor.svelte
+++ b/gui/frontend/src/lib/FieldEditor.svelte
@@ -129,8 +129,17 @@
{ key: "penalty", label: "Penalty area" },
];
+ // virtualField is a module-level singleton, not component-local state --
+ // switching tabs away and back destroys and recreates this component
+ // (MainContent's {#if}/{:else if}), re-running onMount, but virtualField
+ // itself survives that unmount with whatever dirty edits were in progress.
+ // Reloading unconditionally would silently discard them; guard it exactly
+ // like handleLoad below does for the same class of data loss.
onMount(() => {
- void loadVirtualField();
+ if (!virtualField.dirty || confirm("Discard unsaved changes?")) {
+ void loadVirtualField();
+ }
+
void loadFieldPresets();
});
diff --git a/gui/frontend/src/lib/api.ts b/gui/frontend/src/lib/api.ts
new file mode 100644
index 0000000..0c34f26
--- /dev/null
+++ b/gui/frontend/src/lib/api.ts
@@ -0,0 +1,40 @@
+// Shared fetch helpers, used by every module that owns request state
+// (geometry.svelte.ts, lineCorners.svelte.ts, App.svelte's snapshot poll):
+// the same "set a loading/saving flag, clear the error, run the request,
+// catch and format any failure, always clear the flag" and "throw the
+// backend's own error text on a non-2xx response" shapes were previously
+// hand-repeated at every call site.
+
+// Runs fn with setLoading(true) for its duration. Clears the error first;
+// sets it (formatted the same way everywhere) if fn throws.
+export async function withLoadingState(
+ setLoading: (loading: boolean) => void,
+ setError: (message: string | null) => void,
+ fn: () => Promise,
+): Promise {
+ setLoading(true);
+ setError(null);
+
+ try {
+ await fn();
+ } catch (err) {
+ setError(err instanceof Error ? err.message : String(err));
+ } finally {
+ setLoading(false);
+ }
+}
+
+// fetch that throws the backend's own response body as the Error message on
+// a non-2xx status, instead of every caller re-deriving that (or, worse,
+// just the numeric status code) from scratch.
+export async function requestJSON(
+ url: string,
+ init?: RequestInit,
+): Promise {
+ const response = await fetch(url, init);
+ if (!response.ok) {
+ throw new Error(await response.text());
+ }
+
+ return response;
+}
diff --git a/gui/frontend/src/lib/config/ConfigCategoryPlaceholder.svelte b/gui/frontend/src/lib/config/ConfigCategoryPlaceholder.svelte
index 38de4ed..91541f6 100644
--- a/gui/frontend/src/lib/config/ConfigCategoryPlaceholder.svelte
+++ b/gui/frontend/src/lib/config/ConfigCategoryPlaceholder.svelte
@@ -1,6 +1,7 @@
+
+
+ {#each fields as field (field.name)}
+
+
{field.name}
+ {field.comment}
+
+ {/each}
+
+
+
diff --git a/gui/frontend/src/lib/config/GeometryPanel.svelte b/gui/frontend/src/lib/config/GeometryPanel.svelte
index 9646c19..567943a 100644
--- a/gui/frontend/src/lib/config/GeometryPanel.svelte
+++ b/gui/frontend/src/lib/config/GeometryPanel.svelte
@@ -2,6 +2,7 @@
import type { ConfigCategory } from "../layout/configCategories";
import type { VisionInstance } from "../layout/nav.svelte";
import CornerPicker from "../CornerPicker.svelte";
+ import ConfigFieldList from "./ConfigFieldList.svelte";
interface Props {
category: ConfigCategory;
@@ -18,21 +19,14 @@
{instance.host} / cam {instance.cameraId}. The numeric settings below
(config.yml's geometry: block) aren't wired to a backend yet; the
- corner picker further down already is (writes to whichever config.yml you tell
- it to, by hand -- see its own hint text).
+ corner picker further down already is (writes to this host's configured config.yml
+ automatically).
{:else}
Select a vision processor on the left first.
{/if}
-
- {#each category.fields as field (field.name)}
-
-
{field.name}
- {field.comment}
-
- {/each}
-
+
@@ -51,29 +45,6 @@
font-size: 0.85rem;
}
- dl {
- margin: 1rem 0;
- }
-
- .field {
- display: flex;
- gap: 1rem;
- padding: 0.35rem 0;
- border-bottom: 1px solid #eee;
- font-size: 0.85rem;
- }
-
- dt {
- flex: 0 0 12rem;
- font-family: monospace;
- font-weight: 600;
- }
-
- dd {
- margin: 0;
- color: #555;
- }
-
code {
background: #eee;
padding: 0.1rem 0.3rem;
diff --git a/gui/frontend/src/lib/geometry.svelte.ts b/gui/frontend/src/lib/geometry.svelte.ts
index e39eee1..6392b50 100644
--- a/gui/frontend/src/lib/geometry.svelte.ts
+++ b/gui/frontend/src/lib/geometry.svelte.ts
@@ -5,6 +5,7 @@ import type {
SSL_FieldLineSegmentJson,
SSL_FieldCircularArcJson,
} from "../proto/vision/ssl_vision_geometry_pb";
+import { requestJSON, withLoadingState } from "./api";
// The editable dimensions: everything the generated field size carries except
// fieldLines/fieldArcs, which are derived server-side and never hand-edited.
@@ -75,16 +76,14 @@ export const virtualField = $state<{
// Presets are loaded separately from loadVirtualField: a preset endpoint that
// can't be read (see the Go handler's graceful degradation) shouldn't stop
-// the actual field config from loading, and vice versa.
+// the actual field config from loading, and vice versa -- a convenience, not
+// required, so a failure here is silently ignored rather than surfaced.
export async function loadFieldPresets(): Promise {
try {
- const response = await fetch("/api/geometry/presets");
- if (response.ok) {
- virtualField.presets = (await response.json()) as FieldPreset[];
- }
+ const response = await requestJSON("/api/geometry/presets");
+ virtualField.presets = (await response.json()) as FieldPreset[];
} catch {
- // Presets are a convenience, not required for the editor to work -- an
- // empty list just means the preset section has nothing to offer.
+ // An empty list just means the preset section has nothing to offer.
}
}
@@ -93,9 +92,7 @@ export async function loadFieldPresets(): Promise {
// them (load, save, save-as) leaves the server having just regenerated these
// from whatever field config is now active.
async function refreshFieldMarkings(): Promise {
- const response = await fetch("/api/geometry");
- if (!response.ok) return;
-
+ const response = await requestJSON("/api/geometry");
const geometry = (await response.json()) as GeometryResponse;
virtualField.fieldLines = geometry.geometry?.field?.fieldLines ?? [];
virtualField.fieldArcs = geometry.geometry?.field?.fieldArcs ?? [];
@@ -109,106 +106,78 @@ function applyFieldConfigResponse(config: FieldConfigResponse): void {
}
export async function loadVirtualField(): Promise {
- virtualField.loading = true;
- virtualField.error = null;
-
- try {
- const response = await fetch("/api/geometry/field");
- if (!response.ok) {
- throw new Error(`GET /api/geometry/field: ${String(response.status)}`);
- }
-
- applyFieldConfigResponse((await response.json()) as FieldConfigResponse);
- await refreshFieldMarkings();
- } catch (err) {
- virtualField.error = err instanceof Error ? err.message : String(err);
- } finally {
- virtualField.loading = false;
- }
+ await withLoadingState(
+ (v) => (virtualField.loading = v),
+ (v) => (virtualField.error = v),
+ async () => {
+ const response = await requestJSON("/api/geometry/field");
+ applyFieldConfigResponse((await response.json()) as FieldConfigResponse);
+ await refreshFieldMarkings();
+ },
+ );
}
export async function saveVirtualField(): Promise {
- virtualField.saving = true;
- virtualField.error = null;
-
- try {
- const response = await fetch("/api/geometry/field", {
- method: "PUT",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({
- field: virtualField.field,
- optionalFieldLines: virtualField.optionalFieldLines,
- } satisfies FieldConfigResponse),
- });
-
- if (!response.ok) {
- throw new Error(await response.text());
- }
-
- virtualField.dirty = false;
- await refreshFieldMarkings();
- } catch (err) {
- virtualField.error = err instanceof Error ? err.message : String(err);
- } finally {
- virtualField.saving = false;
- }
+ await withLoadingState(
+ (v) => (virtualField.saving = v),
+ (v) => (virtualField.error = v),
+ async () => {
+ await requestJSON("/api/geometry/field", {
+ method: "PUT",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ field: virtualField.field,
+ optionalFieldLines: virtualField.optionalFieldLines,
+ } satisfies FieldConfigResponse),
+ });
+
+ virtualField.dirty = false;
+ await refreshFieldMarkings();
+ },
+ );
}
// Writes the current field config to a new path and switches to editing that
// file (see geometry.Geometry.SaveAs) -- subsequent saveVirtualField calls go
// there, not wherever this session started out.
export async function saveVirtualFieldAs(path: string): Promise {
- virtualField.saving = true;
- virtualField.error = null;
-
- try {
- const response = await fetch("/api/geometry/field/save-as", {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({
- path,
- field: virtualField.field,
- optionalFieldLines: virtualField.optionalFieldLines,
- } satisfies FieldConfigResponse),
- });
-
- if (!response.ok) {
- throw new Error(await response.text());
- }
-
- virtualField.path = path;
- virtualField.dirty = false;
- await refreshFieldMarkings();
- } catch (err) {
- virtualField.error = err instanceof Error ? err.message : String(err);
- } finally {
- virtualField.saving = false;
- }
+ await withLoadingState(
+ (v) => (virtualField.saving = v),
+ (v) => (virtualField.error = v),
+ async () => {
+ await requestJSON("/api/geometry/field/save-as", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ path,
+ field: virtualField.field,
+ optionalFieldLines: virtualField.optionalFieldLines,
+ } satisfies FieldConfigResponse),
+ });
+
+ virtualField.path = path;
+ virtualField.dirty = false;
+ await refreshFieldMarkings();
+ },
+ );
}
// Discards the current field config and replaces it with whatever's at path
// (see geometry.Geometry.LoadFrom). Existing calibrations are dropped
// server-side -- they belonged to the field this used to be.
export async function loadVirtualFieldFrom(path: string): Promise {
- virtualField.loading = true;
- virtualField.error = null;
-
- try {
- const response = await fetch("/api/geometry/field/load", {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({ path }),
- });
-
- if (!response.ok) {
- throw new Error(await response.text());
- }
-
- applyFieldConfigResponse((await response.json()) as FieldConfigResponse);
- await refreshFieldMarkings();
- } catch (err) {
- virtualField.error = err instanceof Error ? err.message : String(err);
- } finally {
- virtualField.loading = false;
- }
+ await withLoadingState(
+ (v) => (virtualField.loading = v),
+ (v) => (virtualField.error = v),
+ async () => {
+ const response = await requestJSON("/api/geometry/field/load", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ path }),
+ });
+
+ applyFieldConfigResponse((await response.json()) as FieldConfigResponse);
+ await refreshFieldMarkings();
+ },
+ );
}
diff --git a/gui/frontend/src/lib/layout/ConfigNav.svelte b/gui/frontend/src/lib/layout/ConfigNav.svelte
index ea19700..96b2dea 100644
--- a/gui/frontend/src/lib/layout/ConfigNav.svelte
+++ b/gui/frontend/src/lib/layout/ConfigNav.svelte
@@ -8,6 +8,11 @@
let instanceCategories = $derived(
CONFIG_CATEGORIES.filter((c) => c.scope === "per-instance"),
);
+
+ // Computed once, matching MainContent.svelte's own pattern for the same
+ // function, rather than calling selectedInstance() again at each of the
+ // template sites below.
+ let instance = $derived(selectedInstance());
@@ -29,8 +34,8 @@
- {#if selectedInstance()}
- {selectedInstance()?.host} / cam {selectedInstance()?.cameraId}
+ {#if instance}
+ {instance.host} / cam {instance.cameraId}
{:else}
Per-instance (select one above)
{/if}
@@ -41,7 +46,7 @@
{
nav.selectedCategoryId = category.id;
}}
diff --git a/gui/frontend/src/lib/lineCorners.svelte.ts b/gui/frontend/src/lib/lineCorners.svelte.ts
new file mode 100644
index 0000000..e267e67
--- /dev/null
+++ b/gui/frontend/src/lib/lineCorners.svelte.ts
@@ -0,0 +1,73 @@
+// Shared state for the corner picker, mirroring geometry.svelte.ts's pattern
+// for the virtual field editor: a module-level $state object plus load/save
+// functions built on the shared api.ts helpers, instead of the corner picker
+// hand-rolling its own one-off fetch/loading/error shape.
+import { requestJSON, withLoadingState } from "./api";
+
+export interface Corner {
+ x: number;
+ y: number;
+}
+
+interface LineCornersResponse {
+ corners?: Corner[];
+ goalSideMarker?: number;
+}
+
+export const lineCorners = $state<{
+ corners: Corner[];
+ goalSideMarker: number | null;
+ loading: boolean;
+ saving: boolean;
+ error: string | null;
+ savedAt: number | null;
+}>({
+ corners: [],
+ goalSideMarker: null,
+ loading: false,
+ saving: false,
+ error: null,
+ savedAt: null,
+});
+
+// Loads whatever was last saved to the instance's config.yml (see
+// geometry.ReadLineCorners). lineCorners.corners stays empty if nothing's
+// been saved yet, or if what's there isn't a complete set of 4 -- that's the
+// normal, not-yet-calibrated state, not a failure.
+export async function loadLineCorners(): Promise {
+ await withLoadingState(
+ (v) => (lineCorners.loading = v),
+ (v) => (lineCorners.error = v),
+ async () => {
+ const response = await requestJSON("/api/config/line-corners");
+ const data = (await response.json()) as LineCornersResponse;
+ lineCorners.corners = data.corners?.length === 4 ? data.corners : [];
+ lineCorners.goalSideMarker = data.goalSideMarker ?? null;
+ },
+ );
+}
+
+// Saves corners (already reordered so the goal-side corner is first -- see
+// orderedCorners in CornerPicker.svelte) and which original on-screen marker
+// number (1-4) was chosen, to the instance's config.yml (see
+// geometry.WriteLineCorners).
+export async function saveLineCorners(
+ corners: Corner[],
+ goalSideMarker: number,
+): Promise {
+ lineCorners.savedAt = null;
+
+ await withLoadingState(
+ (v) => (lineCorners.saving = v),
+ (v) => (lineCorners.error = v),
+ async () => {
+ await requestJSON("/api/config/line-corners", {
+ method: "PUT",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ corners, goalSideMarker }),
+ });
+
+ lineCorners.savedAt = Date.now();
+ },
+ );
+}
diff --git a/gui/internal/geometry/field_config.go b/gui/internal/geometry/field_config.go
index 0e02c96..98d927d 100644
--- a/gui/internal/geometry/field_config.go
+++ b/gui/internal/geometry/field_config.go
@@ -189,6 +189,41 @@ func (g *Geometry) applyFieldConfig(cfg FieldConfig, opt OptionalLinesConfig) {
g.optional = optional
}
+// applyAndPersist mutates g to reflect cfg/opt, re-encodes, and calls persist
+// to write the change to disk -- rolling the in-memory mutation back if
+// either step fails, so a rejected save never leaves g holding (and
+// broadcasting, over multicast and the WS hub) field data that was never
+// actually written anywhere. Callers must hold mu, must have already
+// validated cfg, and must have already checked ReadOnlyFiles for whichever
+// path persist is about to write to.
+func (g *Geometry) applyAndPersist(cfg FieldConfig, opt OptionalLinesConfig, persist func() error) error {
+ previousField := g.wrapper.Geometry.Field
+ previousOptional := g.optional
+ previousEncoded := g.encoded
+
+ rollback := func() {
+ g.wrapper.Geometry.Field = previousField
+ g.optional = previousOptional
+ g.encoded = previousEncoded
+ }
+
+ g.applyFieldConfig(cfg, opt)
+
+ if err := g.reencode(); err != nil {
+ rollback()
+
+ return fmt.Errorf("encode updated geometry: %w", err)
+ }
+
+ if err := persist(); err != nil {
+ rollback()
+
+ return fmt.Errorf("save %s: %w", g.path, err)
+ }
+
+ return nil
+}
+
// UpdateField replaces the field dimensions and optional-line toggles,
// regenerates the derived field lines/arcs, and persists the change to the
// file Geometry was loaded from. Existing calibrations are kept.
@@ -210,17 +245,7 @@ func (g *Geometry) UpdateField(cfg FieldConfig, opt OptionalLinesConfig) error {
return &ReadOnlyError{path: g.path}
}
- g.applyFieldConfig(cfg, opt)
-
- if err := g.reencode(); err != nil {
- return fmt.Errorf("encode updated geometry: %w", err)
- }
-
- if err := g.saveYAML(cfg, opt); err != nil {
- return fmt.Errorf("save %s: %w", g.path, err)
- }
-
- return nil
+ return g.applyAndPersist(cfg, opt, func() error { return g.saveYAML(cfg, opt) })
}
// SaveAs is UpdateField plus switching which file Geometry edits: it writes
@@ -240,22 +265,18 @@ func (g *Geometry) SaveAs(path string, cfg FieldConfig, opt OptionalLinesConfig)
return &ReadOnlyError{path: path}
}
- g.applyFieldConfig(cfg, opt)
-
- if err := g.reencode(); err != nil {
- return fmt.Errorf("encode updated geometry: %w", err)
- }
-
- // g.path only changes once we're past validation and encoding, so a
- // rejected SaveAs never leaves Geometry claiming to be a file nothing was
- // actually written to.
+ // g.path changes before persisting so applyAndPersist's error message (and
+ // saveYAML's ReadOnlyFiles recheck) refer to the new path -- rolled back
+ // on any failure, same as the field/optional/encoded state, so a rejected
+ // SaveAs never leaves Geometry claiming to be a file nothing was actually
+ // written to.
previousPath := g.path
g.path = path
- if err := g.saveYAML(cfg, opt); err != nil {
+ if err := g.applyAndPersist(cfg, opt, func() error { return g.saveYAML(cfg, opt) }); err != nil {
g.path = previousPath
- return fmt.Errorf("save %s: %w", path, err)
+ return err
}
return nil
diff --git a/gui/internal/geometry/geometry.go b/gui/internal/geometry/geometry.go
index f639bf3..4452dd6 100644
--- a/gui/internal/geometry/geometry.go
+++ b/gui/internal/geometry/geometry.go
@@ -129,12 +129,23 @@ func (g *Geometry) mergeCalib(camera *vision.SSL_GeometryCameraCalibration) bool
return true
}
-// Run republishes via publish once per PublishInterval until ctx is cancelled.
+// Run publishes immediately, then republishes via publish once per
+// PublishInterval until ctx is cancelled. Publishing before the first wait
+// (not after) matters here: real vision_processor instances on the network
+// wait to receive the field-geometry template before they can calibrate, so
+// a restart of this host should hand it to them right away, not after an
+// extra idle PublishInterval.
func (g *Geometry) Run(ctx context.Context, publish func([]byte)) error {
return g.run(ctx, PublishInterval, publish)
}
func (g *Geometry) run(ctx context.Context, interval time.Duration, publish func([]byte)) error {
+ // Skipped if ctx is already cancelled -- Run should do nothing and return
+ // immediately in that case, same as before this published up front.
+ if ctx.Err() == nil {
+ publish(g.Encoded())
+ }
+
ticker := time.NewTicker(interval)
defer ticker.Stop()
diff --git a/gui/internal/geometry/geometry_test.go b/gui/internal/geometry/geometry_test.go
index 9b8f807..53924a2 100644
--- a/gui/internal/geometry/geometry_test.go
+++ b/gui/internal/geometry/geometry_test.go
@@ -170,6 +170,50 @@ func TestConcurrentAbsorbAndRead(t *testing.T) {
}
}
+// Real vision_processor instances wait for the field-geometry template
+// before they can calibrate -- Run must hand it to them immediately on
+// startup, not only after the first interval elapses.
+func TestRunPublishesImmediatelyBeforeTheFirstInterval(t *testing.T) {
+ g := testGeometry(t)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ published := make(chan []byte, 1)
+
+ // An interval far longer than the test's own timeout: if a publish
+ // arrives at all, it can only be the immediate one, not a ticked one.
+ go func() { _ = g.run(ctx, time.Hour, func(b []byte) { published <- b }) }()
+
+ select {
+ case <-published:
+ case <-time.After(time.Second):
+ t.Fatal("Run did not publish immediately")
+ }
+}
+
+// A Run started with an already-cancelled context does nothing at all --
+// confirms the immediate publish above doesn't fire unconditionally.
+func TestRunSkipsTheImmediatePublishIfAlreadyCancelled(t *testing.T) {
+ g := testGeometry(t)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel()
+
+ published := make(chan []byte, 1)
+
+ err := g.run(ctx, time.Hour, func(b []byte) { published <- b })
+ if err != context.Canceled { //nolint:errorlint // exact sentinel, not a wrapped error
+ t.Fatalf("run returned %v, want context.Canceled", err)
+ }
+
+ select {
+ case <-published:
+ t.Fatal("run published despite an already-cancelled context")
+ default:
+ }
+}
+
func TestRunPublishesUntilCancelled(t *testing.T) {
g := testGeometry(t)
diff --git a/gui/internal/geometry/instance_config.go b/gui/internal/geometry/instance_config.go
index 0243dfb..52443db 100644
--- a/gui/internal/geometry/instance_config.go
+++ b/gui/internal/geometry/instance_config.go
@@ -5,10 +5,23 @@ import (
"os"
"regexp"
"strings"
+ "sync"
"gopkg.in/yaml.v3"
)
+// instanceConfigMu serializes every WriteLineCorners/ReadLineCorners call.
+// Unlike Geometry, there's no per-instance object to hang a mutex off of --
+// this is a bare read-modify-write of a file on disk -- so a single
+// package-level lock is what keeps two concurrent PUT /api/config/line-corners
+// requests (two browser tabs, a double-click before the Save button disables)
+// from each doing their own unsynchronized os.ReadFile/os.WriteFile and
+// silently clobbering one another, and keeps a concurrent read from ever
+// seeing a half-written file. Matches this package's existing single,
+// same-host-instance assumption (see gui/CLAUDE.md) -- one config.yml, one
+// lock.
+var instanceConfigMu sync.Mutex
+
// Corner is one point in image pixel coordinates, as produced by the corner
// picker. Only the first element of a slice passed to WriteLineCorners is
// meaningful to src/calib/GeomModel.cpp's cornerCalibration -- it must be the
@@ -31,6 +44,12 @@ var (
// goal_side_marker (yaml-cpp's Node["key"] lookups ignore unknown keys), it's
// purely a record for whoever looks at this file next.
//
+// A bad corners/goalSideMarker argument is reported as a *ValidationError
+// (the caller's mistake), same type UpdateField/SaveAs use for the same
+// purpose -- callers use errors.As to give it a 400 instead of a 500, so this
+// bounds check only has to live here, not also at whatever HTTP handler
+// calls in.
+//
// This edits the text directly rather than decoding/re-encoding the file as
// YAML (contrast Geometry.saveYAML for geometry.yml): config.yml ships full
// of comments and commented-out example values meant to be hand-read, and
@@ -40,13 +59,16 @@ var (
// splice touches nothing outside the two keys it's asked to set.
func WriteLineCorners(path string, corners []Corner, goalSideMarker int) error {
if len(corners) == 0 {
- return fmt.Errorf("no corners given")
+ return &ValidationError{fmt.Errorf("no corners given")}
}
if goalSideMarker < 1 || goalSideMarker > len(corners) {
- return fmt.Errorf("goalSideMarker must identify one of the %d corners, got %d", len(corners), goalSideMarker)
+ return &ValidationError{fmt.Errorf("goalSideMarker must identify one of the %d corners, got %d", len(corners), goalSideMarker)}
}
+ instanceConfigMu.Lock()
+ defer instanceConfigMu.Unlock()
+
data, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("read %s: %w", path, err)
@@ -85,6 +107,9 @@ type instanceConfig struct {
// file has no line_corners yet -- that's the normal, not-yet-calibrated
// state, not a failure.
func ReadLineCorners(path string) ([]Corner, int, error) {
+ instanceConfigMu.Lock()
+ defer instanceConfigMu.Unlock()
+
data, err := os.ReadFile(path)
if err != nil {
return nil, 0, fmt.Errorf("read %s: %w", path, err)
diff --git a/gui/internal/geometry/instance_config_test.go b/gui/internal/geometry/instance_config_test.go
index b375362..4bb225f 100644
--- a/gui/internal/geometry/instance_config_test.go
+++ b/gui/internal/geometry/instance_config_test.go
@@ -4,6 +4,7 @@ import (
"os"
"path/filepath"
"strings"
+ "sync"
"testing"
)
@@ -250,3 +251,42 @@ func TestWriteLineCornersUpdatesAnExistingGoalSideMarkerInPlace(t *testing.T) {
t.Errorf("goal_side_marker was not updated to the new value:\n%s", got)
}
}
+
+// Two browser tabs (or a double-click racing the Save button's disabled
+// state) can call this concurrently on the same file. instanceConfigMu must
+// serialize them -- run under -race, and check the result is one complete
+// write, not a torn mix of two.
+func TestWriteLineCornersIsSafeForConcurrentCallers(t *testing.T) {
+ path := testConfigFile(t)
+
+ var wg sync.WaitGroup
+
+ for i := 1; i <= 8; i++ {
+ wg.Add(1)
+
+ go func(marker int) {
+ defer wg.Done()
+
+ corners := []Corner{
+ {X: marker, Y: marker},
+ {X: marker + 1, Y: marker + 1},
+ {X: marker + 2, Y: marker + 2},
+ {X: marker + 3, Y: marker + 3},
+ }
+ if err := WriteLineCorners(path, corners, 1); err != nil {
+ t.Errorf("WriteLineCorners: %v", err)
+ }
+ }(i)
+ }
+
+ wg.Wait()
+
+ corners, marker, err := ReadLineCorners(path)
+ if err != nil {
+ t.Fatalf("ReadLineCorners: %v", err)
+ }
+
+ if len(corners) != 4 || marker != 1 {
+ t.Errorf("got corners=%v marker=%d, want exactly one complete write's worth of data", corners, marker)
+ }
+}
diff --git a/gui/internal/hub/hub.go b/gui/internal/hub/hub.go
index f557d30..8fe58e0 100644
--- a/gui/internal/hub/hub.go
+++ b/gui/internal/hub/hub.go
@@ -54,18 +54,27 @@ func (h *Hub) Publish(topic string, data []byte) {
defer h.mu.Unlock()
for ch := range h.subs[topic] {
+ sendLatest(ch, data)
+ }
+}
+
+// sendLatest sends data on ch, dropping whatever unread value is already
+// queued rather than blocking or letting a backlog grow -- the drop-stale,
+// keep-latest guarantee this package makes wherever it multiplexes onto a
+// size-limited channel: a topic's own per-subscriber channel here, and (see
+// websocket.go's forwardTopic) a connection's shared outbound channel.
+func sendLatest(ch chan []byte, data []byte) {
+ select {
+ case ch <- data:
+ default:
select {
- case ch <- data:
+ case <-ch:
default:
- select {
- case <-ch:
- default:
- }
+ }
- select {
- case ch <- data:
- default:
- }
+ select {
+ case ch <- data:
+ default:
}
}
}
diff --git a/gui/internal/hub/hub_test.go b/gui/internal/hub/hub_test.go
index 2e5da76..145844b 100644
--- a/gui/internal/hub/hub_test.go
+++ b/gui/internal/hub/hub_test.go
@@ -103,6 +103,29 @@ func TestSlowSubscriberSeesOnlyLatestValue(t *testing.T) {
}
}
+// forwardTopic (websocket.go) shares one connection-wide channel across every
+// topic a client subscribes to, unlike Publish's per-subscriber channel --
+// sendLatest is what both rely on for the same drop-stale, keep-latest
+// guarantee, so it's worth testing directly against a channel with room for
+// more than one queued value, not just the size-1 case Publish/Subscribe use.
+func TestSendLatestDropsTheOldestQueuedValueWhenFull(t *testing.T) {
+ ch := make(chan []byte, 2)
+
+ sendLatest(ch, []byte("a"))
+ sendLatest(ch, []byte("b"))
+ sendLatest(ch, []byte("c")) // full (a, b): must drop "a", never silently drop "c" itself
+
+ var got []string
+ for len(ch) > 0 {
+ got = append(got, string(<-ch))
+ }
+
+ want := []string{"b", "c"}
+ if len(got) != len(want) || got[0] != want[0] || got[1] != want[1] {
+ t.Errorf("queue ended up %v, want %v -- the newest value must never be the one dropped", got, want)
+ }
+}
+
func TestConcurrentSubscribePublishUnsubscribe(t *testing.T) {
h := New()
diff --git a/gui/internal/hub/websocket.go b/gui/internal/hub/websocket.go
index fd112e6..6dc7b29 100644
--- a/gui/internal/hub/websocket.go
+++ b/gui/internal/hub/websocket.go
@@ -113,8 +113,16 @@ func serveConnection(h *Hub, conn *websocket.Conn) {
}
// forwardTopic relays one hub topic's values onto outbound until the topic is
-// unsubscribed (the hub channel closes).
-func forwardTopic(topic string, ch <-chan []byte, outbound chan<- []byte) {
+// unsubscribed (the hub channel closes). outbound is shared across every
+// topic this connection subscribes to, so uses the same drop-stale,
+// keep-latest sendLatest as a topic's own per-subscriber channel -- a slow
+// connection sees the latest value across its subscriptions, never a growing
+// backlog of stale ones queued ahead of it. (Concurrent forwardTopic
+// goroutines for different topics may occasionally race on which one's stale
+// entry gets dropped when both find outbound full at once; sendLatest's
+// channel ops are safe for that, and the guarantee that matters -- no
+// unbounded backlog -- still holds either way.)
+func forwardTopic(topic string, ch <-chan []byte, outbound chan []byte) {
for data := range ch {
envelope, err := json.Marshal(serverMessage{Topic: topic, Data: data})
if err != nil {
@@ -122,13 +130,7 @@ func forwardTopic(topic string, ch <-chan []byte, outbound chan<- []byte) {
continue
}
- select {
- case outbound <- envelope:
- default:
- // This connection is behind; drop rather than block every other
- // topic (and every other connection sharing the hub) on one slow
- // client.
- }
+ sendLatest(outbound, envelope)
}
}
diff --git a/gui/internal/logging/logging.go b/gui/internal/logging/logging.go
index ba5fade..df91e1b 100644
--- a/gui/internal/logging/logging.go
+++ b/gui/internal/logging/logging.go
@@ -17,9 +17,9 @@ import (
)
const (
- defaultMaxSizeMB = 50
- defaultMaxBackups = 5
- defaultMaxAgeDays = 14
+ rotateMaxSizeMB = 50
+ rotateMaxBackups = 5
+ rotateMaxAgeDays = 14
)
// logLevel is package level so that an API handler can raise the level at
@@ -35,10 +35,6 @@ type Config struct {
// File is the rotating log file to write alongside stderr. Empty disables
// file logging entirely.
File string
-
- MaxSizeMB int
- MaxBackups int
- MaxAgeDays int
}
// SetLevel changes the level of every handler installed by Setup. Safe to call
@@ -101,9 +97,9 @@ func Setup(cfg Config) (func(), error) {
} else {
rotator := &lumberjack.Logger{
Filename: cfg.File,
- MaxSize: orDefault(cfg.MaxSizeMB, defaultMaxSizeMB), // megabytes per file
- MaxBackups: orDefault(cfg.MaxBackups, defaultMaxBackups),
- MaxAge: orDefault(cfg.MaxAgeDays, defaultMaxAgeDays), // days
+ MaxSize: rotateMaxSizeMB, // megabytes per file
+ MaxBackups: rotateMaxBackups,
+ MaxAge: rotateMaxAgeDays, // days
Compress: false,
}
handlers = append(handlers, slog.NewTextHandler(rotator, &slog.HandlerOptions{
@@ -123,14 +119,6 @@ func Setup(cfg Config) (func(), error) {
return closeLog, setupErr
}
-func orDefault(value, fallback int) int {
- if value == 0 {
- return fallback
- }
-
- return value
-}
-
// colorSupported reports whether ANSI colour should be emitted to f. A pipe or
// a redirect to a file is not a terminal, and NO_COLOR is the cross-tool
// convention for turning colour off on one that is.
diff --git a/gui/internal/snapshot/snapshot.go b/gui/internal/snapshot/snapshot.go
index a770774..dffd120 100644
--- a/gui/internal/snapshot/snapshot.go
+++ b/gui/internal/snapshot/snapshot.go
@@ -16,11 +16,13 @@ import (
"sort"
)
-// filename matches "..", e.g. "0.raw.jpg". Both captured
-// groups are also validated against this same character set before use in a
-// filepath.Glob, since Glob treats *, ?, and [ as metacharacters and an
-// unvalidated view name could turn a lookup into a directory listing.
-var filename = regexp.MustCompile(`^(\d+)\.([a-zA-Z0-9_-]+)\.(?:jpg|jpeg|png)$`)
+// filename matches "..", e.g. "0.raw.jpg" or
+// "0.pixels.corner.png" -- view itself may contain dots (GeomModel.cpp writes
+// "pixels.corner"/"pixels.refined"), so it's `.+`, not a restricted character
+// class. This only ever runs against real names returned by os.ReadDir, never
+// untrusted input, so there's no injection risk in being permissive here; see
+// validSegment below for the regex that actually guards a filepath.Glob call.
+var filename = regexp.MustCompile(`^(\d+)\.(.+)\.(?:jpg|jpeg|png)$`)
// Entry identifies one available snapshot. Field names match what the
// frontend already expects.
@@ -89,9 +91,12 @@ func list(dir string) ([]Entry, error) {
}
// validSegment matches one path-value component of a snapshot request: digits
-// for a camera id, or the same character set the filename itself uses for a
-// view name.
-var validSegment = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)
+// for a camera id, or a view name (which may contain dots, e.g.
+// "pixels.corner"). This guards untrusted URL input right before it reaches
+// filepath.Glob in latest() -- it excludes '/' (no escaping the single path
+// segment camID+"."+view+".*" is joined into) and Glob's own metacharacters
+// (*, ?, [, ]), which is what actually matters; dots are harmless here.
+var validSegment = regexp.MustCompile(`^[a-zA-Z0-9_.-]+$`)
// HandleGet serves the most recently written {camID}.{view}.* file in dir.
func HandleGet(dir string) http.HandlerFunc {
diff --git a/gui/internal/snapshot/snapshot_test.go b/gui/internal/snapshot/snapshot_test.go
index bcb188c..b0328ea 100644
--- a/gui/internal/snapshot/snapshot_test.go
+++ b/gui/internal/snapshot/snapshot_test.go
@@ -53,6 +53,23 @@ func TestListFindsMatchingFilesAndSkipsOthers(t *testing.T) {
}
}
+// GeomModel.cpp writes debug overlays as ".pixels.corner.png" and
+// ".pixels.refined.png" -- view itself contains a dot.
+func TestListHandlesADottedViewName(t *testing.T) {
+ dir := t.TempDir()
+ writeFile(t, dir, "0.pixels.corner.png")
+
+ entries, err := list(dir)
+ if err != nil {
+ t.Fatalf("list: %v", err)
+ }
+
+ want := Entry{CamID: "0", View: "pixels.corner"}
+ if len(entries) != 1 || entries[0] != want {
+ t.Fatalf("entries = %v, want [%v]", entries, want)
+ }
+}
+
func TestListDedupesSameCameraAndView(t *testing.T) {
dir := t.TempDir()
writeFile(t, dir, "0.raw.jpg")
@@ -131,6 +148,22 @@ func TestHandleGetServesTheMostRecentlyModifiedMatch(t *testing.T) {
}
}
+func TestHandleGetServesADottedViewName(t *testing.T) {
+ dir := t.TempDir()
+ writeFile(t, dir, "0.pixels.corner.png")
+
+ rec := httptest.NewRecorder()
+ snapshotMux(dir).ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/api/snapshot/0/pixels.corner", nil))
+
+ if rec.Code != http.StatusOK {
+ t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
+ }
+
+ if rec.Body.String() != "0.pixels.corner.png" {
+ t.Errorf("body = %q, want file contents", rec.Body.String())
+ }
+}
+
func TestHandleGetReturns404ForNoMatch(t *testing.T) {
dir := t.TempDir()
From 166706cf54347884789f896b9956a33cd1ea22b9 Mon Sep 17 00:00:00 2001
From: Will Stuckey
Date: Fri, 25 Sep 2026 15:30:05 -0400
Subject: [PATCH 10/23] update docs
---
README.md | 2 +-
gui/ARCHITECTURE.md | 183 +++++++++++++++++++++++++++++++++++++++++
gui/README.md | 72 ++++++++++++++++
gui/frontend/README.md | 57 ++++++++-----
4 files changed, 294 insertions(+), 20 deletions(-)
create mode 100644 gui/ARCHITECTURE.md
create mode 100644 gui/README.md
diff --git a/README.md b/README.md
index c69fac1..fe70465 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ for all vision_processors, teams and the game controller.
A Go host plus a browser UI, replacing `geom_publisher.py` for anyone running it:
-- `gui/` — Go host (`cmd/ssl-vision-processor-gui`). Owns the field geometry, absorbs calibrations from vision processors over multicast, and serves the embedded frontend, JSON API, a WebSocket for live updates, and debug snapshot images all on one port. Run with `cd gui && make run` (defaults to `geometry-divB.yml`).
+- `gui/` — Go host (`cmd/ssl-vision-processor-gui`). Owns the field geometry, absorbs calibrations from vision processors over multicast, and serves the embedded frontend, JSON API, a WebSocket for live updates, and debug snapshot images all on one port. Run with `cd gui && make run` (defaults to `geometry-divB.yml`). See [`gui/README.md`](gui/README.md) for development and [`gui/ARCHITECTURE.md`](gui/ARCHITECTURE.md) for its design.
- `gui/frontend/` — Svelte 5 + TypeScript + Vite, embedded into the Go binary. Run standalone with `cd gui && make proto && cd frontend && npm install && npm run dev` (proxies `/api` and `/ws` to the Go host), or serve it from the Go host directly with `make run`. `make proto` regenerates the protobuf bindings the frontend imports (not committed to git; needs `buf`, or use `nix develop`, see [`gui/CLAUDE.md`](gui/CLAUDE.md)) and only needs to be rerun after the `proto/` submodule changes. See [`gui/frontend/README.md`](gui/frontend/README.md).
## Dependency installation and compilation
diff --git a/gui/ARCHITECTURE.md b/gui/ARCHITECTURE.md
new file mode 100644
index 0000000..c8b2436
--- /dev/null
+++ b/gui/ARCHITECTURE.md
@@ -0,0 +1,183 @@
+# gui Architecture
+
+This document describes the design of `gui`, the Go host and browser UI for vision_processor. It covers the
+subsystem in this directory only. The C++ vision_processor and the Python scripts in `python/` are described in
+the root README and are not modified by this subsystem.
+
+`gui` replaces `python/geom_publisher.py` for anyone running it. It is a single Go binary with an embedded
+Svelte frontend. It owns the shared field geometry, absorbs camera calibrations from vision_processor instances
+over multicast, and serves the frontend, a JSON API, and a WebSocket for live updates, all on one port.
+
+## System overview
+
+A venue runs one or more vision_processor instances, one per camera. Each instance shares a filesystem with the
+gui host (debug images in `img/`, the instance's own `config.yml`) and exchanges SSL vision protocol messages
+with it over the same multicast group the rest of the league uses.
+
+```mermaid
+graph LR
+ subgraph Venue Host
+ VP0["vision_processor cam 0"]
+ VP1["vision_processor cam 1"]
+ FS[("shared filesystem\nimg/, config.yml")]
+ end
+
+ GUI["gui host\nssl-vision-processor-gui"]
+ MC(("multicast\n224.5.23.2:10006"))
+ Browser["Browser UI"]
+
+ VP0 -->|"detections"| MC
+ VP1 -->|"detections"| MC
+ MC -->|"calibration"| GUI
+ GUI -->|"field template,\nmerged wrapper packet"| MC
+ MC -->|"field template"| VP0
+ MC -->|"field template"| VP1
+ VP0 -.-> FS
+ GUI -.-> FS
+ Browser --> GUI
+ GUI --> Browser
+```
+
+The gui host does not talk to a vision_processor instance directly. Both sides only ever speak to the multicast
+group, the same way any other league consumer would. This keeps the host interchangeable with the legacy
+`geom_publisher.py` service from the vision_processor's point of view. The browser talks to the gui host over
+HTTP and a WebSocket instead, covered under HTTP API and WebSocket protocol below.
+
+## Process layout
+
+`ssl-vision-processor-gui` is one process with three concurrent responsibilities, wired together in
+`cmd/ssl-vision-processor-gui/main.go`.
+
+```mermaid
+graph TD
+ main["main() / run()"]
+ http["HTTP server\ngoroutine"]
+ bridge["multicast bridge\ngoroutine"]
+ publish["geometry publish loop\ngoroutine, 1Hz"]
+
+ main --> http
+ main --> bridge
+ main --> publish
+ bridge -- "Absorb(calib)" --> Geometry
+ publish -- "Encoded()" --> Geometry
+ http -- "reads/writes" --> Geometry
+```
+
+All three goroutines share one `*geometry.Geometry` instance, guarded by its own mutex. Shutdown is graceful: an
+`os.Interrupt`/`SIGTERM` cancels a shared context, the HTTP server drains in-flight requests, and `main` waits for
+both other goroutines to exit before returning.
+
+## Package responsibilities
+
+| Package | Responsibility |
+| ---------------------- | -------------------------------------------------------------------------------|
+| `cmd/ssl-vision-processor-gui` | Flags, wiring, HTTP handlers and routes. |
+| `internal/geometry` | Field configuration, calibration merge, the 1Hz publish loop, and the corner picker's config.yml writeback. |
+| `internal/multicast` | Bridge to the SSL vision multicast group. |
+| `internal/hub` | In-process topic pub/sub and the `/ws` WebSocket handler. |
+| `internal/snapshot` | Debug image listing and serving. |
+| `internal/logging` | slog setup: a coloured console handler and a rotating file handler. |
+| `internal/vision`, `internal/gamecontroller` | Generated protobuf bindings. Not committed, see Build-time codegen below. |
+| `frontend` | Svelte 5 and TypeScript, embedded into the binary via `//go:embed`. |
+
+## Data flow: geometry state
+
+`Geometry` holds one `SSL_WrapperPacket`: the field template plus every camera's absorbed calibration. It keeps a
+cached protobuf encoding alongside the live message, since `proto.Marshal` writes to the message's own size cache
+and is not safe to call from multiple goroutines without a lock.
+
+```mermaid
+graph LR
+ Absorb["Absorb(calib)\nfrom multicast"] -->|"validated,\nmerged"| State[("Geometry\n(wrapper + encoded)")]
+ UpdateField["UpdateField / SaveAs / LoadFrom\nfrom HTTP"] -->|"validated,\npersisted to disk"| State
+ State -->|"Encoded()"| Multicast["multicast bridge"]
+ State -->|"Snapshot() -> protojson"| API["GET /api/geometry"]
+```
+
+A calibration missing a required proto2 field is rejected with `proto.CheckInitialized` before it can touch
+`State`, so a malformed message from one instance never desyncs the held message from its cached encoding. A
+field edit that fails to persist to disk (`UpdateField`, `SaveAs`) is rolled back the same way, so the live,
+broadcast state never claims a change that was never actually saved.
+
+## Data flow: corner picker calibration hint
+
+The corner picker lets an operator mark the field's first calibration corner directly on a debug snapshot in the
+browser, instead of estimating pixel coordinates by eye. It writes into the target instance's own `config.yml`,
+not into the shared `geometry.yml`.
+
+```mermaid
+sequenceDiagram
+ participant Browser
+ participant GUI as gui host
+ participant Config as config.yml
+ participant VP as vision_processor
+
+ Browser->>GUI: PUT /api/config/line-corners
+ GUI->>Config: splice geometry.line_corners, goal_side_marker
+ Note over VP: reloadConfigIfChanged() picks up the edit on its next frame
+ VP->>VP: geometryCalibration()
+ VP-->>GUI: SSL_GeometryData (multicast)
+ GUI->>GUI: Absorb(calib)
+ GUI-->>Browser: wrapper_packet.out (WebSocket)
+```
+
+`internal/geometry.WriteLineCorners` edits `config.yml` as text, not as decoded and re-encoded YAML. The file
+ships full of comments and commented out example values meant for a human to read, and a decode and re-encode
+round trip through the YAML library does not reliably preserve those. A line based splice touches only the two
+keys it is asked to set.
+
+## HTTP API
+
+All routes are registered in `cmd/ssl-vision-processor-gui/routes.go`.
+
+| Method | Path | Purpose |
+| ------ | ----------------------------- | -------------------------------------------------------------------|
+| GET | `/api/health` | Liveness check. |
+| GET | `/api/geometry` | The full wrapper packet, as canonical protojson. |
+| GET | `/api/geometry/field` | The editable field dimensions and optional line toggles. |
+| PUT | `/api/geometry/field` | Update the field dimensions, persisted to the current geometry file. |
+| POST | `/api/geometry/field/save-as` | Save the field config to a new file and switch to editing it. |
+| POST | `/api/geometry/field/load` | Discard the current field config and load another file. |
+| GET | `/api/geometry/presets` | The rulebook presets, read live from `geometry-divA.yml`/`geometry-divB.yml`. |
+| GET | `/api/config/line-corners` | The corner picker's last saved corners and goal side marker. |
+| PUT | `/api/config/line-corners` | Save the corner picker's calibration hint to `config.yml`. |
+| GET | `/api/snapshots` | List of debug images currently on disk. |
+| GET | `/api/snapshot/{camID}/{view}` | One debug image. |
+| GET | `/ws` | WebSocket, see below. |
+
+An unrouted `/api/*` path returns 404 rather than falling through to the frontend, so a typo'd endpoint fails
+with a clear status instead of returning HTML to a caller expecting JSON. Every other path serves the embedded
+frontend, with a fallback to `index.html` for client side routes.
+
+## WebSocket protocol
+
+`/ws` is a single connection carrying a topic based publish/subscribe protocol, implemented in `internal/hub`.
+
+```json
+// client -> server
+{ "action": "subscribe", "topic": "wrapper_packet.out" }
+{ "action": "unsubscribe", "topic": "wrapper_packet.out" }
+// server -> client
+{ "topic": "wrapper_packet.out", "data": { /* protojson */ } }
+```
+
+`wrapper_packet.out` carries the current `SSL_WrapperPacket` as canonical protojson, published once per second.
+Every channel in this path, from a topic's own subscriber channel to a connection's shared outbound channel, is
+size limited and drops the oldest queued value in favor of the newest one. A slow client sees only the latest
+value once it catches up, never a growing backlog of stale ones.
+
+## Build-time codegen
+
+`internal/vision`, `internal/gamecontroller`, and `frontend/src/proto` are `buf generate` output and are not
+committed. `buf.gen.yaml` uses local plugins (`go tool protoc-gen-go`, `protoc-gen-es` from the frontend's own
+`node_modules`), so generation needs no network beyond the already checked out `proto/` submodule. `gui/Makefile`
+regenerates them as an ordinary build prerequisite. See `gui/README.md` for the exact commands.
+
+## Not yet built
+
+- **Discovery.** Parsing `SSL_VPConfig` announces off multicast into an instance table. The C++ side does not
+ emit these yet.
+- **Host owned config push.** Diffing an instance's announced config against a desired one and pushing the
+ difference, rather than editing its `config.yml` by hand as the corner picker does today.
+- **Remote video.** `internal/snapshot` assumes the gui host and the vision_processor instance share a
+ filesystem. This does not hold once instances run on other hosts.
diff --git a/gui/README.md b/gui/README.md
new file mode 100644
index 0000000..5acb6bc
--- /dev/null
+++ b/gui/README.md
@@ -0,0 +1,72 @@
+# gui
+
+Go host and browser UI for vision_processor. Owns the shared field geometry, absorbs camera calibrations from
+vision_processor instances over multicast, and serves the frontend, a JSON API, and a WebSocket for live updates,
+all on one port. See [ARCHITECTURE.md](ARCHITECTURE.md) for how it fits together and why it is built this way.
+
+This document covers development on `gui` itself. For running vision_processor at a venue, see the root
+[README.md](../README.md). For the frontend's own layout and scripts, see
+[frontend/README.md](frontend/README.md).
+
+## Requirements
+
+The root `flake.nix` provides everything needed: `go`, `buf`, `nodejs_22`, and the C++ toolchain for the rest of
+the repo. Run `nix develop` from the repo root before any command below.
+
+Without nix, you need `buf` on your `PATH`, a Go toolchain matching the `go` directive in `gui/go.mod`, and
+Node 22. `protoc-gen-go` and `protoc-gen-es` do not need to be installed separately: `go tool protoc-gen-go` is
+resolved from `gui/go.mod`'s `tool` directive, and `protoc-gen-es` is a `frontend/package.json` devDependency
+installed by `npm ci`.
+
+## Commands
+
+Run these from `gui/`.
+
+| Command | Effect |
+| -------------- | -------------------------------------------------------------------------------|
+| `make run` | Regenerate protobuf bindings, build the frontend, and run the Go host on `:8085`. |
+| `make test` | Frontend check, lint, and format, plus `go test -race` for every package. |
+| `make install` | `go install` after a frontend build. |
+| `make proto` | Regenerate `internal/vision`, `internal/gamecontroller`, and `frontend/src/proto`. |
+| `make vet` | `go vet` for every package. |
+| `make build` | `go build` for every package, without installing. |
+| `make clean` | Remove the frontend build, generated protobuf code, and build sentinels. |
+
+`make proto` needs `git submodule update --init` to have been run once, but no network beyond that: both of
+`buf.gen.yaml`'s plugins are local, not buf.build remotes. `make run`, `make test`, and `make install` all depend
+on it, so a fresh checkout builds correctly without a separate manual step.
+
+For frontend only work with hot reload:
+
+```
+cd frontend
+npm run dev
+```
+
+This proxies `/api` and `/ws` to the Go host, so `gui`'s own server still needs to be running (`make run` in a
+second terminal) for the page to show anything.
+
+## Repository layout
+
+```
+cmd/ssl-vision-processor-gui/ entry point: flags, wiring, HTTP server
+internal/
+ geometry/ field config, calibration merge, the 1Hz publish loop, corner picker writeback
+ multicast/ bridge to the SSL vision multicast group
+ hub/ topic pub/sub and the /ws handler
+ snapshot/ debug image listing and serving
+ logging/ slog setup
+ vision/ generated protobuf bindings, not committed
+ gamecontroller/ generated protobuf bindings, not committed
+frontend/ Svelte 5, TypeScript, and Vite, embedded via //go:embed
+buf.gen.yaml buf configuration for the two packages above
+```
+
+## Testing
+
+`go test -race` runs on every package. This code is concurrent by construction: a mutex guarded `Geometry` and a
+multi goroutine WebSocket hub. Tests that exercise a file write (`internal/geometry`, `cmd/.../server_test.go`)
+copy their fixture into `t.TempDir()` first and never operate on the checked in `testdata/` files directly.
+
+`go test ./...` from `gui/` will try to compile stray Go source inside `frontend/node_modules`. Use
+`go test ./cmd/... ./internal/... ./frontend`, which is what `Makefile` and CI both do.
diff --git a/gui/frontend/README.md b/gui/frontend/README.md
index 3071a21..3c13fe1 100644
--- a/gui/frontend/README.md
+++ b/gui/frontend/README.md
@@ -1,11 +1,19 @@
# vision-processor-gui-frontend
-Browser UI for the vision-processor GUI. Svelte 5 + TypeScript + Vite.
-
-Currently a skeleton: connects to a WebSocket at `/ws` and asks the
-backend (via `GET /api/snapshots`) which debug images currently exist
-on disk (only meaningful when the browser and the vision processor
-share a filesystem -- see the root [README.md](../../README.md)).
+Browser UI for the vision-processor GUI. Svelte 5, TypeScript, and Vite. See
+[`gui/README.md`](../README.md) for building it as part of the Go host, and
+[`gui/ARCHITECTURE.md`](../ARCHITECTURE.md) for how the whole system fits
+together. This document covers the frontend's own layout and scripts.
+
+The UI is organized as a two column shell: an instance list and config
+category nav on the left, the selected category's panel on the right. A tab
+bar above the panel gives quick access to the categories used most, Virtual
+Field, Geometry, and Color. Virtual Field edits the shared `geometry.yml`
+field template. Geometry embeds the corner picker, which lets an operator
+mark a calibration corner on a debug snapshot and save it into that
+instance's `config.yml`. Debug snapshots (via `GET /api/snapshots`) are only
+meaningful when the browser and the vision processor share a filesystem, see
+the root [README.md](../../README.md).
## Run
@@ -28,19 +36,30 @@ make run
Either way the Go host in `gui/` must be running for the connection
badge and snapshot grid to show anything.
-## Architecture
-
-- `src/lib/wrapper-bus.ts` — single `WebSocket` client. Exposes
- `connectionState` (Svelte store) and `topic(name)` (returns a
- store of the latest message). Subscribes to a topic lazily on first
- reader, unsubscribes when the last reader goes away. Reconnects on
- close with exponential backoff (1s → 30s).
-- `src/App.svelte` — placeholder UI: connection badge + a grid of
- ` ` tags, one per entry returned by `GET /api/snapshots`. The list is
- refreshed every 5 s; each ` ` is refreshed once per second via a
- cache-busting `?t=` query. Plus a dev panel with a subscribe
- toggle + JSON dump for `wrapper_packet.out`.
-- `src/main.ts` — mounts `App` into `#app`.
+## Layout
+
+- `src/lib/layout/` holds the shell: `Shell.svelte` (the two column grid and
+ connection badge), `InstanceList.svelte`, `ConfigNav.svelte`, `TabBar.svelte`,
+ and `MainContent.svelte`, which switches panels on `nav.selectedCategoryId`.
+ `nav.svelte.ts` and `configCategories.ts` hold the shared navigation state
+ and the category list itself.
+- `src/lib/FieldEditor.svelte` is the Virtual Field editor, backed by
+ `src/lib/geometry.svelte.ts`, a module level `$state` object shared with
+ anything else that needs the field config.
+- `src/lib/config/GeometryPanel.svelte` is the Geometry category's panel. It
+ embeds `src/lib/CornerPicker.svelte`, backed by
+ `src/lib/lineCorners.svelte.ts` in the same way.
+- `src/lib/api.ts` holds the fetch helpers (`requestJSON`, `withLoadingState`)
+ every panel's load and save functions are built on.
+- `src/lib/wrapper-bus.ts` is a single `WebSocket` client. It exposes
+ `connectionState` (a Svelte store) and `topic(name)` (a store of the
+ latest message on that topic). A topic subscribes lazily on first reader
+ and unsubscribes when the last reader goes away. It reconnects on close
+ with exponential backoff, from 1 second up to 30.
+- `src/App.svelte` mounts the shell and still carries a couple of temporary
+ debug utilities predating it (a snapshot grid and a raw `wrapper_packet.out`
+ dump), kept until the mockup's real Video and Debug Console panels exist.
+- `src/main.ts` mounts `App` into `#app`.
The WS wire format (`gui/internal/hub`):
From 7749c3c2578f975d7e8b3a90d7f0e97d508fbd3e Mon Sep 17 00:00:00 2001
From: Will Stuckey
Date: Fri, 25 Sep 2026 15:46:43 -0400
Subject: [PATCH 11/23] minor docs correction
---
gui/ARCHITECTURE.md | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/gui/ARCHITECTURE.md b/gui/ARCHITECTURE.md
index c8b2436..24302ea 100644
--- a/gui/ARCHITECTURE.md
+++ b/gui/ARCHITECTURE.md
@@ -114,7 +114,7 @@ sequenceDiagram
Browser->>GUI: PUT /api/config/line-corners
GUI->>Config: splice geometry.line_corners, goal_side_marker
- Note over VP: reloadConfigIfChanged() picks up the edit on its next frame
+ Note over VP: geometry: is only read at startup, not by reloadConfigIfChanged() -- restart required
VP->>VP: geometryCalibration()
VP-->>GUI: SSL_GeometryData (multicast)
GUI->>GUI: Absorb(calib)
@@ -126,6 +126,11 @@ ships full of comments and commented out example values meant for a human to rea
round trip through the YAML library does not reliably preserve those. A line based splice touches only the two
keys it is asked to set.
+The `geometry:` section is only read once, when `Resources` is constructed at process startup
+(`src/Resources.cpp`). `reloadConfigIfChanged()` hot reloads `thresholds`, `tracking`, `color`, and `debug` every
+half second, but never `geometry`, `camera`, `network`, or `stream`. A corner saved through this endpoint has no
+effect until the target vision_processor instance is restarted.
+
## HTTP API
All routes are registered in `cmd/ssl-vision-processor-gui/routes.go`.
From d963b4e04871b76a97cffa2bf4e4ffabea2b2877 Mon Sep 17 00:00:00 2001
From: Will Stuckey
Date: Fri, 25 Sep 2026 21:29:52 -0400
Subject: [PATCH 12/23] dimension view layout updates
---
gui/frontend/package-lock.json | 714 ++++++++++++++++--
gui/frontend/package.json | 6 +-
gui/frontend/src/App.svelte | 3 +
gui/frontend/src/app.css | 54 ++
gui/frontend/src/lib/FieldEditor.svelte | 63 +-
gui/frontend/src/lib/fieldConfigFields.ts | 51 ++
gui/frontend/src/lib/fieldSplit.ts | 8 +
.../src/lib/wizard/SetupWizard.svelte | 84 +++
.../wizard/steps/WizardDimensionLine.svelte | 198 +++++
.../lib/wizard/steps/WizardDimensions.svelte | 86 +++
.../steps/WizardDimensionsPreview.svelte | 235 ++++++
.../wizard/steps/WizardFieldPreview.svelte | 137 ++++
.../src/lib/wizard/steps/WizardFinish.svelte | 33 +
.../src/lib/wizard/steps/WizardLayout.svelte | 61 ++
.../wizard/steps/WizardOptionalLines.svelte | 25 +
.../wizard/steps/WizardRadiusDimension.svelte | 139 ++++
.../src/lib/wizard/steps/WizardStart.svelte | 46 ++
gui/frontend/src/lib/wizard/wizard.svelte.ts | 111 +++
gui/frontend/src/main.ts | 1 +
gui/frontend/vite.config.ts | 5 +-
20 files changed, 1965 insertions(+), 95 deletions(-)
create mode 100644 gui/frontend/src/app.css
create mode 100644 gui/frontend/src/lib/fieldConfigFields.ts
create mode 100644 gui/frontend/src/lib/wizard/SetupWizard.svelte
create mode 100644 gui/frontend/src/lib/wizard/steps/WizardDimensionLine.svelte
create mode 100644 gui/frontend/src/lib/wizard/steps/WizardDimensions.svelte
create mode 100644 gui/frontend/src/lib/wizard/steps/WizardDimensionsPreview.svelte
create mode 100644 gui/frontend/src/lib/wizard/steps/WizardFieldPreview.svelte
create mode 100644 gui/frontend/src/lib/wizard/steps/WizardFinish.svelte
create mode 100644 gui/frontend/src/lib/wizard/steps/WizardLayout.svelte
create mode 100644 gui/frontend/src/lib/wizard/steps/WizardOptionalLines.svelte
create mode 100644 gui/frontend/src/lib/wizard/steps/WizardRadiusDimension.svelte
create mode 100644 gui/frontend/src/lib/wizard/steps/WizardStart.svelte
create mode 100644 gui/frontend/src/lib/wizard/wizard.svelte.ts
diff --git a/gui/frontend/package-lock.json b/gui/frontend/package-lock.json
index 3aa8502..1f6875a 100644
--- a/gui/frontend/package-lock.json
+++ b/gui/frontend/package-lock.json
@@ -8,12 +8,15 @@
"name": "vision-processor-gui-frontend",
"version": "0.0.0",
"dependencies": {
- "@bufbuild/protobuf": "^2.14.1"
+ "@bufbuild/protobuf": "^2.14.1",
+ "flowbite": "^4.0.2",
+ "flowbite-svelte": "^1.33.1"
},
"devDependencies": {
"@bufbuild/protoc-gen-es": "^2.14.1",
"@eslint/js": "^10.0.1",
"@sveltejs/vite-plugin-svelte": "^7.1.2",
+ "@tailwindcss/vite": "^4.3.3",
"@tsconfig/svelte": "^5.0.8",
"@types/node": "^24.12.3",
"eslint": "^10.3.0",
@@ -25,11 +28,24 @@
"svelte": "^5.55.5",
"svelte-check": "^4.4.8",
"svelte-eslint-parser": "^1.6.1",
+ "tailwindcss": "^4.3.3",
"typescript": "~6.0.2",
"typescript-eslint": "^8.59.3",
"vite": "^8.0.12"
}
},
+ "node_modules/@alloc/quick-lru": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.3.0.tgz",
+ "integrity": "sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/@bufbuild/protobuf": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.15.0.tgz",
@@ -91,7 +107,6 @@
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
- "dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -103,7 +118,6 @@
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
- "dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -114,7 +128,6 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
"integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
- "dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -249,6 +262,31 @@
"node": "^20.19.0 || ^22.13.0 || >=24"
}
},
+ "node_modules/@floating-ui/core": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz",
+ "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/utils": "^0.2.12"
+ }
+ },
+ "node_modules/@floating-ui/dom": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz",
+ "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/core": "^1.8.0",
+ "@floating-ui/utils": "^0.2.12"
+ }
+ },
+ "node_modules/@floating-ui/utils": {
+ "version": "0.2.12",
+ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz",
+ "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==",
+ "license": "MIT"
+ },
"node_modules/@humanfs/core": {
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
@@ -319,7 +357,6 @@
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0",
@@ -330,7 +367,6 @@
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
@@ -341,7 +377,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
@@ -351,14 +386,12 @@
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
- "dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.31",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
@@ -369,7 +402,6 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
"integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==",
- "dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -394,6 +426,16 @@
"url": "https://github.com/sponsors/Boshen"
}
},
+ "node_modules/@popperjs/core": {
+ "version": "2.11.8",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
+ "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/popperjs"
+ }
+ },
"node_modules/@rolldown/binding-android-arm64": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0.tgz",
@@ -658,11 +700,56 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@rollup/plugin-node-resolve": {
+ "version": "15.3.1",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz",
+ "integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==",
+ "license": "MIT",
+ "dependencies": {
+ "@rollup/pluginutils": "^5.0.1",
+ "@types/resolve": "1.20.2",
+ "deepmerge": "^4.2.2",
+ "is-module": "^1.0.0",
+ "resolve": "^1.22.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^2.78.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/pluginutils": {
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz",
+ "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "estree-walker": "^2.0.2",
+ "picomatch": "^4.0.2"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@sveltejs/acorn-typescript": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.9.tgz",
"integrity": "sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==",
- "dev": true,
"license": "MIT",
"peerDependencies": {
"acorn": "^8.9.0"
@@ -688,6 +775,277 @@
"vite": "^8.0.0-beta.7 || ^8.0.0"
}
},
+ "node_modules/@tailwindcss/node": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz",
+ "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/remapping": "^2.3.5",
+ "enhanced-resolve": "^5.24.1",
+ "jiti": "^2.7.0",
+ "lightningcss": "1.32.0",
+ "magic-string": "^0.30.21",
+ "source-map-js": "^1.2.1",
+ "tailwindcss": "4.3.3"
+ }
+ },
+ "node_modules/@tailwindcss/oxide": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz",
+ "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20"
+ },
+ "optionalDependencies": {
+ "@tailwindcss/oxide-android-arm64": "4.3.3",
+ "@tailwindcss/oxide-darwin-arm64": "4.3.3",
+ "@tailwindcss/oxide-darwin-x64": "4.3.3",
+ "@tailwindcss/oxide-freebsd-x64": "4.3.3",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.3.3",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.3.3",
+ "@tailwindcss/oxide-linux-x64-musl": "4.3.3",
+ "@tailwindcss/oxide-wasm32-wasi": "4.3.3",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.3.3"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-android-arm64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz",
+ "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-arm64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz",
+ "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-x64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz",
+ "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-freebsd-x64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz",
+ "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz",
+ "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz",
+ "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz",
+ "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz",
+ "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-musl": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz",
+ "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz",
+ "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==",
+ "bundleDependencies": [
+ "@napi-rs/wasm-runtime",
+ "@emnapi/core",
+ "@emnapi/runtime",
+ "@tybys/wasm-util",
+ "@emnapi/wasi-threads",
+ "tslib"
+ ],
+ "cpu": [
+ "wasm32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.11.1",
+ "@emnapi/runtime": "^1.11.1",
+ "@emnapi/wasi-threads": "^1.2.2",
+ "@napi-rs/wasm-runtime": "^1.1.4",
+ "@tybys/wasm-util": "^0.10.2",
+ "tslib": "^2.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz",
+ "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz",
+ "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/postcss": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.3.tgz",
+ "integrity": "sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg==",
+ "license": "MIT",
+ "dependencies": {
+ "@alloc/quick-lru": "^5.2.0",
+ "@tailwindcss/node": "4.3.3",
+ "@tailwindcss/oxide": "4.3.3",
+ "postcss": "^8.5.16",
+ "tailwindcss": "4.3.3"
+ }
+ },
+ "node_modules/@tailwindcss/vite": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.3.tgz",
+ "integrity": "sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@tailwindcss/node": "4.3.3",
+ "@tailwindcss/oxide": "4.3.3",
+ "tailwindcss": "4.3.3"
+ },
+ "peerDependencies": {
+ "vite": "^5.2.0 || ^6 || ^7 || ^8"
+ }
+ },
"node_modules/@tsconfig/svelte": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-5.0.8.tgz",
@@ -699,7 +1057,6 @@
"version": "0.10.2",
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
"integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
- "dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -717,7 +1074,6 @@
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
"integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
- "dev": true,
"license": "MIT"
},
"node_modules/@types/json-schema": {
@@ -737,11 +1093,16 @@
"undici-types": "~7.16.0"
}
},
+ "node_modules/@types/resolve": {
+ "version": "1.20.2",
+ "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
+ "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
+ "license": "MIT"
+ },
"node_modules/@types/trusted-types": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
- "dev": true,
"license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
@@ -894,7 +1255,7 @@
"version": "8.59.3",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.3.tgz",
"integrity": "sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -991,7 +1352,6 @@
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
- "dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
@@ -1027,11 +1387,16 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
+ "node_modules/apexcharts": {
+ "version": "5.16.0",
+ "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-5.16.0.tgz",
+ "integrity": "sha512-ULO3Gqrm0/26uwBcYz49u181uIp8Fy6BQQgg9QUDajs+JAs/EbXxiAmdc6BLy1JY29/JXroM7P0j0t2JPDApdg==",
+ "license": "SEE LICENSE IN LICENSE"
+ },
"node_modules/aria-query": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.1.tgz",
"integrity": "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==",
- "dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">= 0.4"
@@ -1041,7 +1406,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
"integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
- "dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">= 0.4"
@@ -1090,7 +1454,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -1124,6 +1487,16 @@
"node": ">=4"
}
},
+ "node_modules/date-fns": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.4.0.tgz",
+ "integrity": "sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/kossnocorp"
+ }
+ },
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
@@ -1153,7 +1526,6 @@
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -1163,7 +1535,6 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
- "dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=8"
@@ -1173,9 +1544,30 @@
"version": "5.8.0",
"resolved": "https://registry.npmjs.org/devalue/-/devalue-5.8.0.tgz",
"integrity": "sha512-2zA9pFEsnp7vWBZbXF5JAgAq0fsUIt/1XPbRiAmRV3lp/2C3upzH+sADiyy66aFCihoLEsrQHxNM5w1gIDfsBg==",
- "dev": true,
"license": "MIT"
},
+ "node_modules/enhanced-resolve": {
+ "version": "5.25.1",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.25.1.tgz",
+ "integrity": "sha512-nGXts5znJzmWPu+mIE9izCOzdg63oJca2mDzGWWTth7sr4aCToKcoyFVBQwN75Ij5Pf6p510EwkTqViTRzDV+w==",
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.3.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@@ -1344,7 +1736,6 @@
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
"integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==",
- "dev": true,
"license": "MIT"
},
"node_modules/espree": {
@@ -1382,7 +1773,6 @@
"version": "2.2.8",
"resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.8.tgz",
"integrity": "sha512-MPweq2EvEGj8jwOI7Hgycw/QIHzqA1EbAM8lG7p+FBfZbZq/hQ6h3AMsqnu/djzisH1KVWNzbb7LSgIVtMlPSg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15"
@@ -1419,6 +1809,12 @@
"node": ">=4.0"
}
},
+ "node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "license": "MIT"
+ },
"node_modules/esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
@@ -1519,6 +1915,83 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/flowbite": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/flowbite/-/flowbite-4.0.2.tgz",
+ "integrity": "sha512-TxBdfZpd3HktHH4ashiYjirrSZeVPtG1OCRZMKTeXUa9FOlMxSF98zgjMB/AxE49KZ+rlfgWynAlaNpWxrqZmA==",
+ "license": "MIT",
+ "dependencies": {
+ "@popperjs/core": "^2.9.3",
+ "flowbite-datepicker": "^2.0.0",
+ "mini-svg-data-uri": "^1.4.3",
+ "postcss": "^8.5.1",
+ "tailwindcss": "^4.1.12"
+ }
+ },
+ "node_modules/flowbite-datepicker": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/flowbite-datepicker/-/flowbite-datepicker-2.0.0.tgz",
+ "integrity": "sha512-m81hl0Bimq45MUg4maJLOnXrX+C9lZ0AkjMb9uotuVUSr729k/YiymWDfVAm63AYDH7g7y3rI3ke3XaBzWWqLw==",
+ "license": "MIT",
+ "dependencies": {
+ "@rollup/plugin-node-resolve": "^15.2.3",
+ "@tailwindcss/postcss": "^4.1.17"
+ }
+ },
+ "node_modules/flowbite-svelte": {
+ "version": "1.33.1",
+ "resolved": "https://registry.npmjs.org/flowbite-svelte/-/flowbite-svelte-1.33.1.tgz",
+ "integrity": "sha512-HIG61H/YvWbfk0JTfirbPFb1F/YRPiJWYlUE7KTlmZ1X/ZTG6NZA9CgRuraO358cdpt0kv1gPYldrAKM1Apx2w==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/dom": "^1.7.6",
+ "@floating-ui/utils": "^0.2.11",
+ "apexcharts": "^5.10.4",
+ "clsx": "^2.1.1",
+ "date-fns": "^4.1.0",
+ "esm-env": "^1.2.2",
+ "flowbite": "^3.1.2",
+ "tailwind-merge": "^3.5.0",
+ "tailwind-variants": "^3.2.2"
+ },
+ "peerDependencies": {
+ "svelte": "^5.40.0",
+ "tailwindcss": "^4.1.4"
+ }
+ },
+ "node_modules/flowbite-svelte/node_modules/flowbite": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/flowbite/-/flowbite-3.1.2.tgz",
+ "integrity": "sha512-MkwSgbbybCYgMC+go6Da5idEKUFfMqc/AmSjm/2ZbdmvoKf5frLPq/eIhXc9P+rC8t9boZtUXzHDgt5whZ6A/Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@popperjs/core": "^2.9.3",
+ "flowbite-datepicker": "^1.3.1",
+ "mini-svg-data-uri": "^1.4.3",
+ "postcss": "^8.5.1"
+ }
+ },
+ "node_modules/flowbite-svelte/node_modules/flowbite-datepicker": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/flowbite-datepicker/-/flowbite-datepicker-1.3.2.tgz",
+ "integrity": "sha512-6Nfm0MCVX3mpaR7YSCjmEO2GO8CDt6CX8ZpQnGdeu03WUCWtEPQ/uy0PUiNtIJjJZWnX0Cm3H55MOhbD1g+E/g==",
+ "license": "MIT",
+ "dependencies": {
+ "@rollup/plugin-node-resolve": "^15.2.3",
+ "flowbite": "^2.0.0"
+ }
+ },
+ "node_modules/flowbite-svelte/node_modules/flowbite-datepicker/node_modules/flowbite": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/flowbite/-/flowbite-2.5.2.tgz",
+ "integrity": "sha512-kwFD3n8/YW4EG8GlY3Od9IoKND97kitO+/ejISHSqpn3vw2i5K/+ZI8Jm2V+KC4fGdnfi0XZ+TzYqQb4Q1LshA==",
+ "license": "MIT",
+ "dependencies": {
+ "@popperjs/core": "^2.9.3",
+ "flowbite-datepicker": "^1.3.0",
+ "mini-svg-data-uri": "^1.4.3"
+ }
+ },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -1534,6 +2007,15 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
@@ -1560,6 +2042,24 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "license": "ISC"
+ },
+ "node_modules/hasown": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
+ "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -1580,6 +2080,21 @@
"node": ">=0.8.19"
}
},
+ "node_modules/is-core-module": {
+ "version": "2.17.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.17.0.tgz",
+ "integrity": "sha512-J/vG0zBCbIKOQFfufSwyXdMrsohyJIUNkrnmo6WZGzoM7tr/lsbfW5b2BvisL6zsyMzK9UxV9L6c7AoFbyXHOA==",
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -1603,11 +2118,16 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-module": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
+ "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
+ "license": "MIT"
+ },
"node_modules/is-reference": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz",
"integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.6"
@@ -1620,6 +2140,15 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/jiti": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz",
+ "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==",
+ "license": "MIT",
+ "bin": {
+ "jiti": "lib/jiti-cli.mjs"
+ }
+ },
"node_modules/json-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
@@ -1676,7 +2205,6 @@
"version": "1.32.0",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
"integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
- "dev": true,
"license": "MPL-2.0",
"dependencies": {
"detect-libc": "^2.0.3"
@@ -1709,7 +2237,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -1730,7 +2257,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -1751,7 +2277,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -1772,7 +2297,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -1793,7 +2317,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -1814,7 +2337,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -1835,7 +2357,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -1856,7 +2377,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -1877,7 +2397,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -1898,7 +2417,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -1919,7 +2437,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -1947,7 +2464,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
- "dev": true,
"license": "MIT"
},
"node_modules/locate-path": {
@@ -1970,12 +2486,20 @@
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
+ "node_modules/mini-svg-data-uri": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz",
+ "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==",
+ "license": "MIT",
+ "bin": {
+ "mini-svg-data-uri": "cli.js"
+ }
+ },
"node_modules/minimatch": {
"version": "10.2.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
@@ -2010,10 +2534,9 @@
"license": "MIT"
},
"node_modules/nanoid": {
- "version": "3.3.12",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
- "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
- "dev": true,
+ "version": "3.3.19",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz",
+ "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==",
"funding": [
{
"type": "github",
@@ -2116,18 +2639,22 @@
"node": ">=8"
}
},
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "license": "MIT"
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
- "dev": true,
"license": "ISC"
},
"node_modules/picomatch": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
@@ -2137,10 +2664,9 @@
}
},
"node_modules/postcss": {
- "version": "8.5.14",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz",
- "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==",
- "dev": true,
+ "version": "8.5.28",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz",
+ "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==",
"funding": [
{
"type": "opencollective",
@@ -2157,7 +2683,7 @@
],
"license": "MIT",
"dependencies": {
- "nanoid": "^3.3.11",
+ "nanoid": "^3.3.18",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
@@ -2334,6 +2860,27 @@
"url": "https://paulmillr.com/funding/"
}
},
+ "node_modules/resolve": {
+ "version": "1.22.12",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz",
+ "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "is-core-module": "^2.16.1",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/rolldown": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0.tgz",
@@ -2421,17 +2968,27 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
- "dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/svelte": {
"version": "5.55.5",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.55.5.tgz",
"integrity": "sha512-2uCs/LZ9us+AktdzYJM8OcxQ8qnPS1kpaO7syGT/MgO+6Qr1Ybl+TqPq+97u7PHqmmMlye5ZkoyXONy5mjjAbw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/remapping": "^2.3.4",
@@ -2558,6 +3115,57 @@
"url": "https://opencollective.com/eslint"
}
},
+ "node_modules/tailwind-merge": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.7.0.tgz",
+ "integrity": "sha512-XPPUyAc+cvspz3lHTcR/QgPfW2A0lv/xQNIjX3HGhLR+Nq2lHaLq5MtTesHn8GUr3W3DguT2KT5x3NVgRtYwmA==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/dcastil"
+ }
+ },
+ "node_modules/tailwind-variants": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/tailwind-variants/-/tailwind-variants-3.3.1.tgz",
+ "integrity": "sha512-4pAvwUtM4HKBiRZftncAbpn6V9Hhwoa5Fl7O2u5zbp7Z5Cvu+/o/6+176WY3WCEES209543quG8zFIcXCsc5Jw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=16.9.x",
+ "pnpm": ">=7.x"
+ },
+ "peerDependencies": {
+ "tailwind-merge": ">=3.0.0",
+ "tailwindcss": "*"
+ },
+ "peerDependenciesMeta": {
+ "tailwind-merge": {
+ "optional": true
+ },
+ "tailwindcss": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz",
+ "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==",
+ "license": "MIT"
+ },
+ "node_modules/tapable": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
+ "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
"node_modules/tinyglobby": {
"version": "0.2.16",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
@@ -2592,7 +3200,6 @@
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
- "dev": true,
"license": "0BSD",
"optional": true
},
@@ -2830,7 +3437,6 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz",
"integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==",
- "dev": true,
"license": "MIT"
}
}
diff --git a/gui/frontend/package.json b/gui/frontend/package.json
index 59a8072..6b82939 100644
--- a/gui/frontend/package.json
+++ b/gui/frontend/package.json
@@ -16,6 +16,7 @@
"@bufbuild/protoc-gen-es": "^2.14.1",
"@eslint/js": "^10.0.1",
"@sveltejs/vite-plugin-svelte": "^7.1.2",
+ "@tailwindcss/vite": "^4.3.3",
"@tsconfig/svelte": "^5.0.8",
"@types/node": "^24.12.3",
"eslint": "^10.3.0",
@@ -27,11 +28,14 @@
"svelte": "^5.55.5",
"svelte-check": "^4.4.8",
"svelte-eslint-parser": "^1.6.1",
+ "tailwindcss": "^4.3.3",
"typescript": "~6.0.2",
"typescript-eslint": "^8.59.3",
"vite": "^8.0.12"
},
"dependencies": {
- "@bufbuild/protobuf": "^2.14.1"
+ "@bufbuild/protobuf": "^2.14.1",
+ "flowbite": "^4.0.2",
+ "flowbite-svelte": "^1.33.1"
}
}
diff --git a/gui/frontend/src/App.svelte b/gui/frontend/src/App.svelte
index 7ec0626..bfb5dce 100644
--- a/gui/frontend/src/App.svelte
+++ b/gui/frontend/src/App.svelte
@@ -4,6 +4,7 @@
import Shell from "./lib/layout/Shell.svelte";
import { nav, selectedCategory } from "./lib/layout/nav.svelte";
import { requestJSON } from "./lib/api";
+ import SetupWizard from "./lib/wizard/SetupWizard.svelte";
let subscribed = $state(false);
let wrapperPacket = $state | null>(null);
@@ -130,6 +131,8 @@
{/snippet}
+
+
diff --git a/gui/frontend/src/lib/wizard/steps/WizardDimensions.svelte b/gui/frontend/src/lib/wizard/steps/WizardDimensions.svelte
new file mode 100644
index 0000000..b398bd3
--- /dev/null
+++ b/gui/frontend/src/lib/wizard/steps/WizardDimensions.svelte
@@ -0,0 +1,86 @@
+
+
+
diff --git a/gui/frontend/src/lib/wizard/steps/WizardDimensionsPreview.svelte b/gui/frontend/src/lib/wizard/steps/WizardDimensionsPreview.svelte
new file mode 100644
index 0000000..b0797f6
--- /dev/null
+++ b/gui/frontend/src/lib/wizard/steps/WizardDimensionsPreview.svelte
@@ -0,0 +1,235 @@
+
+
+
+
+
+ {#if wizard.draft.optionalFieldLines.goal2Goal}
+
+ {/if}
+ {#if wizard.draft.optionalFieldLines.halfway}
+
+ {/if}
+ {#if wizard.draft.optionalFieldLines.centerCircle}
+
+ {/if}
+ {#if wizard.draft.optionalFieldLines.penalty}
+ {#each [-1, 1] as side (side)}
+ 0 ? length / 2 - penaltyDepth : -length / 2}
+ y={-penaltyWidth / 2}
+ width={penaltyDepth}
+ height={penaltyWidth}
+ fill="none"
+ class="marking"
+ />
+ {/each}
+ {/if}
+
+
+
+
+
+
+
+
+
+
+ {#if wizard.draft.optionalFieldLines.penalty}
+
+
+
+ {/if}
+
+ {#if wizard.draft.optionalFieldLines.centerCircle}
+
+ {/if}
+
+
+
diff --git a/gui/frontend/src/lib/wizard/steps/WizardFieldPreview.svelte b/gui/frontend/src/lib/wizard/steps/WizardFieldPreview.svelte
new file mode 100644
index 0000000..9080f2c
--- /dev/null
+++ b/gui/frontend/src/lib/wizard/steps/WizardFieldPreview.svelte
@@ -0,0 +1,137 @@
+
+
+
+
+
+
+
+
+
+
+
+ {#each [-1, 1] as side (side)}
+ 0 ? length / 2 - penaltyDepth : -length / 2}
+ y={-penaltyWidth / 2}
+ width={penaltyDepth}
+ height={penaltyWidth}
+ fill="none"
+ class="marking"
+ opacity={opacity(wizard.draft.optionalFieldLines.penalty)}
+ />
+ {/each}
+
+ {#if wizard.fieldLayout === "half"}
+
+ {/if}
+
+
+
diff --git a/gui/frontend/src/lib/wizard/steps/WizardFinish.svelte b/gui/frontend/src/lib/wizard/steps/WizardFinish.svelte
new file mode 100644
index 0000000..38dfba1
--- /dev/null
+++ b/gui/frontend/src/lib/wizard/steps/WizardFinish.svelte
@@ -0,0 +1,33 @@
+
+
+
+
+ Review, then apply to load these values into the editor.
+
+
+
+
+ Field: {wizard.draft.field.fieldLength ?? 0}mm x {wizard.draft.field
+ .fieldWidth ?? 0}mm
+
+
+ Markings:
+ {markings.length > 0 ? markings.map((f) => f.label).join(", ") : "none"}
+
+
+
+
+ Applying loads these values into the Virtual Field editor but doesn't save
+ them -- use its own Save button to write {virtualField.path || "geometry.yml"}, then calibrate each camera on its own Geometry tab.
+
+
diff --git a/gui/frontend/src/lib/wizard/steps/WizardLayout.svelte b/gui/frontend/src/lib/wizard/steps/WizardLayout.svelte
new file mode 100644
index 0000000..4bfc917
--- /dev/null
+++ b/gui/frontend/src/lib/wizard/steps/WizardLayout.svelte
@@ -0,0 +1,61 @@
+
+
+
diff --git a/gui/frontend/src/lib/wizard/steps/WizardOptionalLines.svelte b/gui/frontend/src/lib/wizard/steps/WizardOptionalLines.svelte
new file mode 100644
index 0000000..0ec5651
--- /dev/null
+++ b/gui/frontend/src/lib/wizard/steps/WizardOptionalLines.svelte
@@ -0,0 +1,25 @@
+
+
+
+
+
Which markings does this field have?
+
+ {#each OPTIONAL_LINE_FIELDS as { key, label } (key)}
+
+
+ {label}
+
+ {/each}
+
+
+
+
+
+
diff --git a/gui/frontend/src/lib/wizard/steps/WizardRadiusDimension.svelte b/gui/frontend/src/lib/wizard/steps/WizardRadiusDimension.svelte
new file mode 100644
index 0000000..4bcd498
--- /dev/null
+++ b/gui/frontend/src/lib/wizard/steps/WizardRadiusDimension.svelte
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+ {text}
+
+
+
+
diff --git a/gui/frontend/src/lib/wizard/steps/WizardStart.svelte b/gui/frontend/src/lib/wizard/steps/WizardStart.svelte
new file mode 100644
index 0000000..8d39e03
--- /dev/null
+++ b/gui/frontend/src/lib/wizard/steps/WizardStart.svelte
@@ -0,0 +1,46 @@
+
+
+
+
+ Start from a regulation field, or configure a custom one.
+
+
+ {#if virtualField.presets.length === 0}
+
+ Loading presets...
+
+ {:else}
+ {#each virtualField.presets as preset (preset.name)}
+
{
+ chooseDivision(preset.name);
+ }}
+ >
+ Regulation {preset.name}
+
+ {/each}
+ {/if}
+
+
+ Custom field
+
+
diff --git a/gui/frontend/src/lib/wizard/wizard.svelte.ts b/gui/frontend/src/lib/wizard/wizard.svelte.ts
new file mode 100644
index 0000000..965f3b7
--- /dev/null
+++ b/gui/frontend/src/lib/wizard/wizard.svelte.ts
@@ -0,0 +1,111 @@
+// Shared state for the setup wizard drawer. A module-level $state object,
+// per the project convention (see geometry.svelte.ts, nav.svelte.ts).
+// optionalLines comes before dimensions: which markings exist decides which
+// dimension fields are even worth asking about (a field with no penalty box
+// has no penalty box depth/width to enter). See WizardDimensions.svelte.
+// There's no dedicated save step: finish is a summary/confirm gate, and
+// confirming there is what copies `draft` into the live virtualField state
+// (see finishWizard below) -- persisting that to disk stays the normal
+// Save/Save As action in the main Virtual Field panel.
+import {
+ virtualField,
+ type FieldConfig,
+ type OptionalFieldLines,
+ type FieldPreset,
+} from "../geometry.svelte";
+
+export const WIZARD_STEPS = [
+ "start",
+ "layout",
+ "optionalLines",
+ "dimensions",
+ "finish",
+] as const;
+
+export type WizardStep = (typeof WIZARD_STEPS)[number];
+
+export const wizard = $state<{
+ open: boolean;
+ step: WizardStep;
+ // Advisory only, for the Layout step and Finish's summary -- camera_amount
+ // isn't wired to any instance's config.yml yet (see gui/CLAUDE.md's "Not
+ // yet built"), so this never gets written anywhere, just relayed back to
+ // the operator as a reminder of what to set by hand.
+ fieldLayout: "full" | "half";
+ cameraCount: number;
+ // A working copy the wizard's own steps read and write, kept separate from
+ // virtualField so an abandoned wizard (closed without reaching Finish)
+ // never leaves a half-entered field applied to the live editor/webpage.
+ // Only finishWizard() below copies this into virtualField.
+ draft: { field: FieldConfig; optionalFieldLines: OptionalFieldLines };
+}>({
+ open: false,
+ step: "start",
+ fieldLayout: "full",
+ cameraCount: 1,
+ draft: {
+ field: {},
+ optionalFieldLines: {
+ goal2Goal: false,
+ halfway: false,
+ centerCircle: false,
+ penalty: false,
+ },
+ },
+});
+
+export function openWizard(): void {
+ wizard.step = "start";
+ wizard.fieldLayout = "full";
+ wizard.cameraCount = 1;
+ // Seed from the current live field, not blank -- reopening the wizard to
+ // adjust an already-configured field should start from what's there.
+ // $state.snapshot, not structuredClone: virtualField.field is itself a
+ // $state proxy, and structuredClone throws ("Proxy object could not be
+ // cloned") on one directly -- snapshot first to get a plain object.
+ wizard.draft.field = $state.snapshot(virtualField.field);
+ wizard.draft.optionalFieldLines = $state.snapshot(
+ virtualField.optionalFieldLines,
+ );
+ wizard.open = true;
+}
+
+export function goToStep(step: WizardStep): void {
+ wizard.step = step;
+}
+
+// The Division A/B short-circuit: loads the preset into the draft (not
+// virtualField directly) and skips straight past layout/optional lines/
+// dimensions, since a preset already supplies all three.
+export function applyPresetToDraft(preset: FieldPreset): void {
+ wizard.draft.field = $state.snapshot(preset.field);
+ wizard.draft.optionalFieldLines = $state.snapshot(preset.optionalFieldLines);
+}
+
+export function skipToFinish(): void {
+ wizard.step = "finish";
+}
+
+// Only place the draft ever reaches virtualField: called from Finish's
+// confirm action. Marks dirty so the main panel's own Save/Save As (unchanged)
+// is what actually persists it.
+export function finishWizard(): void {
+ virtualField.field = $state.snapshot(wizard.draft.field);
+ virtualField.optionalFieldLines = $state.snapshot(
+ wizard.draft.optionalFieldLines,
+ );
+ virtualField.dirty = true;
+ wizard.open = false;
+}
+
+export function nextStep(): void {
+ const index = WIZARD_STEPS.indexOf(wizard.step);
+ const next = WIZARD_STEPS[index + 1];
+ if (next) wizard.step = next;
+}
+
+export function previousStep(): void {
+ const index = WIZARD_STEPS.indexOf(wizard.step);
+ const prev = WIZARD_STEPS[index - 1];
+ if (prev) wizard.step = prev;
+}
diff --git a/gui/frontend/src/main.ts b/gui/frontend/src/main.ts
index cfd630e..bafc656 100644
--- a/gui/frontend/src/main.ts
+++ b/gui/frontend/src/main.ts
@@ -1,3 +1,4 @@
+import "./app.css";
import { mount } from "svelte";
import App from "./App.svelte";
diff --git a/gui/frontend/vite.config.ts b/gui/frontend/vite.config.ts
index a8c1525..25d2a2f 100644
--- a/gui/frontend/vite.config.ts
+++ b/gui/frontend/vite.config.ts
@@ -1,9 +1,12 @@
import { defineConfig } from "vite";
import { svelte } from "@sveltejs/vite-plugin-svelte";
+import tailwindcss from "@tailwindcss/vite";
// https://vite.dev/config/
export default defineConfig({
- plugins: [svelte()],
+ // tailwindcss() must come before svelte() so Tailwind's own PostCSS-less
+ // Vite transform sees .svelte files before vite-plugin-svelte compiles them.
+ plugins: [tailwindcss(), svelte()],
server: {
// The Go host serves /api and /ws on :8085; everything else (this dev
// server) is same-origin so no CORS handling is needed on either side.
From 6d9df0649d4dadb589749d21bcbc80d073ab40b3 Mon Sep 17 00:00:00 2001
From: Will Stuckey
Date: Fri, 25 Sep 2026 21:59:11 -0400
Subject: [PATCH 13/23] clean default pane
---
gui/frontend/src/app.css | 42 ++++++++++++++++++++++
gui/frontend/src/lib/FieldEditor.svelte | 45 ------------------------
gui/frontend/src/lib/fieldPresets.ts | 46 -------------------------
gui/frontend/src/lib/geometry.svelte.ts | 3 +-
4 files changed, 44 insertions(+), 92 deletions(-)
delete mode 100644 gui/frontend/src/lib/fieldPresets.ts
diff --git a/gui/frontend/src/app.css b/gui/frontend/src/app.css
index 81b9634..dc52a50 100644
--- a/gui/frontend/src/app.css
+++ b/gui/frontend/src/app.css
@@ -52,3 +52,45 @@ part.
}
@source "../node_modules/flowbite-svelte/dist";
+
+/*
+Tailwind's preflight (pulled in by @import "tailwindcss" above) zeroes every
+element's margin/padding/border and strips native button/select chrome
+(background, border) globally -- normal for a project that styles everything
+with utility classes, but this one predates Tailwind: FieldEditor.svelte and
+friends are still plain hand-written
diff --git a/gui/frontend/src/lib/config/ColorUpdateEquation.svelte b/gui/frontend/src/lib/config/ColorUpdateEquation.svelte
new file mode 100644
index 0000000..80c7eaf
--- /dev/null
+++ b/gui/frontend/src/lib/config/ColorUpdateEquation.svelte
@@ -0,0 +1,97 @@
+
+
+
+ new {referenceLabel} =
+
+
+ {pct(referenceForce)} · reference
+
+ +
+
+
+ {pct(historyForce)} · history
+
+ +
+
+
+ {pct(updateForce)} · current frame
+
+
+
+
diff --git a/gui/frontend/src/lib/config/WeightTriangle.svelte b/gui/frontend/src/lib/config/WeightTriangle.svelte
new file mode 100644
index 0000000..3a861a4
--- /dev/null
+++ b/gui/frontend/src/lib/config/WeightTriangle.svelte
@@ -0,0 +1,602 @@
+
+
+
+
+
+
+
+
+
+ Reference
+ History
+ Current frame
+
+ min {pct(minReferenceForce)}
+
+
+
+
+
+
+
+ Reference
+ {pct(referenceForce)}
+ History
+ {pct(historyForce)}
+ Current frame
+ {pct(updateForce)}
+
+
+
+ Restore default weights
+
+
+
+
+ Minimum reference weight
+
+
+
+ {#if !minForceUnlocked}
+
+
+ Unlock
+
+ {#if showUnlockConfirm}
+
+ {/if}
+
+ {/if}
+
+
+
+
+
+
diff --git a/gui/frontend/src/lib/config/YuvPositionPane.svelte b/gui/frontend/src/lib/config/YuvPositionPane.svelte
new file mode 100644
index 0000000..78d0a81
--- /dev/null
+++ b/gui/frontend/src/lib/config/YuvPositionPane.svelte
@@ -0,0 +1,552 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {#each COLOR_CLASSES as cls (cls)}
+ (selectedClass = cls)}
+ >
+
+ {CLASS_LABELS[cls]}
+
+ {/each}
+
+
+
+ Y (brightness)
+ {sliceY}{previewing ? " (previewing)" : ""}
+ U
+ {actualYuv.u}
+ V
+ {actualYuv.v}
+ Reachable
+ {Math.round(gamutFraction * 100)}%
+
+
+
+
+ {#if preferences.tooltipsEnabled && gamutFraction < 0.3}
+
+ Only {Math.round(gamutFraction * 100)}% of the square is a real color at
+ this brightness -- the outlined shape, not a full square, is expected
+ here: brightness this close to {sliceY < 128 ? "black" : "white"} genuinely
+ has few reachable colors. Not a rendering glitch.
+
+ {/if}
+
+
+ Drag or click inside the square to set {label || "the reference color"}'s
+ color at the brightness shown. Dragging the slider (or scrolling over either
+ control) only previews a different brightness -- the marker stays exactly
+ where the saved color actually is, even inside the shaded region if that
+ color isn't reachable at the previewed brightness; nothing is saved until
+ you click or drag inside the square again. The currently-autoadapted
+ position and per-frame blob samples aren't shown yet: both need the other
+ contributor's protobuf work to reach this host.
+
+
+
+
diff --git a/gui/frontend/src/lib/layout/MainContent.svelte b/gui/frontend/src/lib/layout/MainContent.svelte
index b9f15be..8c5dfdc 100644
--- a/gui/frontend/src/lib/layout/MainContent.svelte
+++ b/gui/frontend/src/lib/layout/MainContent.svelte
@@ -3,6 +3,7 @@
import TabBar from "./TabBar.svelte";
import FieldEditor from "../FieldEditor.svelte";
import GeometryPanel from "../config/GeometryPanel.svelte";
+ import ColorPanel from "../config/ColorPanel.svelte";
import ConfigCategoryPlaceholder from "../config/ConfigCategoryPlaceholder.svelte";
let category = $derived(selectedCategory());
@@ -16,6 +17,8 @@
{:else if nav.selectedCategoryId === "geometry"}
+ {:else if nav.selectedCategoryId === "color"}
+
{:else}
{/if}
diff --git a/gui/frontend/src/lib/layout/Shell.svelte b/gui/frontend/src/lib/layout/Shell.svelte
index e63c2c4..f38eb6f 100644
--- a/gui/frontend/src/lib/layout/Shell.svelte
+++ b/gui/frontend/src/lib/layout/Shell.svelte
@@ -1,5 +1,6 @@
+
+