diff --git a/README.md b/README.md index da7dca7..3a4c2fd 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,22 @@ make test Видео сначала загружается через `POST /api/files/upload` (MP4/WebM, до 64 МБ); в `video` передаётся возвращённое имя файла. Текст и видео можно задавать отдельно. `{"conclusion":null}` удаляет закрывашку. Она возвращается в `story.conclusion` полного сценария, но не передаётся в историю игроков, включая MCP. Закрывашка переносится вместе с ZIP-архивом; действуют общие лимиты импорта архива (32 МБ на архив и отдельный файл). +## Экспорт игры на автономную площадку + +Администратор, разработчик или организатор запускает подготовку через +`POST /api/games/{ID}/export`, получает состояние через `GET /api/games/{ID}/export` +и скачивает готовый ZIP через `GET /api/games/{ID}/export/download` с JWT. +Экспорт доступен для игры в черновике без дат проведения и прогресса. Он сохраняет +снимок для пакета и показывает в интерфейсе подготовку или офлайн-режим, сохраняя +возможность изменений. Изменения после запуска не синхронизируются с готовым +пакетом. Ошибка подготовки переводит попытку в `failed`; обрыв скачивания не +меняет статус. Повторный запуск готовой попытки возвращает прежний пакет. + +Используйте только тестовые игры до завершения возврата результатов. UI передачи +и импорт реализуются следующими этапами. Контракт, закрытое хранение RustFS, +восстановление worker и команды проверки описаны в +[`docs/GAME_PACKAGE.md`](docs/GAME_PACKAGE.md#экспорт-со-статусом-офлайн-режима-этап-5). + ## Документация и юридические документы - [`docs/TERMS.md`](docs/TERMS.md) — Пользовательское соглашение (оферта); раздаётся сервером по постоянному URL `/api/terms`; diff --git a/api/main.proto b/api/main.proto index 3639752..ad8d019 100644 --- a/api/main.proto +++ b/api/main.proto @@ -626,6 +626,17 @@ service EveningDetectiveServer { }; } + rpc StartGameExport(StartGameExportReq) returns (GameExportRsp) { + option (google.api.http) = { + post: "/api/games/{ID}/export" + body: "*" + }; + } + + rpc GetGameExport(GetGameExportReq) returns (GameExportRsp) { + option (google.api.http) = {get: "/api/games/{ID}/export"}; + } + rpc IssueGameTickets(IssueGameTicketsReq) returns (IssueGameTicketsRsp) { option (google.api.http) = { post: "/api/games/{gameID}/tickets" @@ -1628,8 +1639,26 @@ message Game { optional google.protobuf.Timestamp ended_at = 9; string format = 10; string location = 11; + GameExport export = 12; } +// Download ready ZIP through the authenticated streaming HTTP route: +// GET /api/games/{ID}/export/download (not an HttpBody RPC). +message GameExport { + string ID = 1; + string state = 2; // preparing, ready or failed; preparing/ready lock game writes. + string packageID = 3; + int64 size = 4; + string sha256 = 5; + string failure = 6; +} + +message StartGameExportReq { int32 ID = 1; } + +message GetGameExportReq { int32 ID = 1; } + +message GameExportRsp { GameExport export = 1; } + enum ScreenMode { SCREEN_MODE_UNSPECIFIED = 0; SCREEN_MODE_COVER = 1; diff --git a/cmd/evening_detective_server/main.go b/cmd/evening_detective_server/main.go index 82624be..49cc365 100644 --- a/cmd/evening_detective_server/main.go +++ b/cmd/evening_detective_server/main.go @@ -16,6 +16,7 @@ import ( "evening_detective_server/internal/modules/storytelling" "evening_detective_server/internal/repos/actions_repo" "evening_detective_server/internal/repos/applications_repo" + "evening_detective_server/internal/repos/game_exports_repo" "evening_detective_server/internal/repos/game_map_repo" "evening_detective_server/internal/repos/game_reviews_repo" "evening_detective_server/internal/repos/game_screen_plans_repo" @@ -32,6 +33,8 @@ import ( "evening_detective_server/internal/repos/users_repo" "evening_detective_server/internal/services/answer_service" "evening_detective_server/internal/services/file_service" + "evening_detective_server/internal/services/game_export_service" + "evening_detective_server/internal/services/game_package_service" "evening_detective_server/internal/services/game_review_service" "evening_detective_server/internal/services/game_service" "evening_detective_server/internal/services/gameplay_service" @@ -127,6 +130,30 @@ func main() { log.Fatalf("Unable to create connection rustfs: %v\n", err) } fileService := file_service.NewFileService(fileStorage, maxFileSize) + var exportStorage file_storage.IStreamStorage + if !venueMode { + exportStorage, err = file_storage.NewPrivateRustFSStorage( + context.Background(), + os.Getenv("S3_HOST"), + os.Getenv("S3_USER"), + os.Getenv("S3_PASSWORD"), + os.Getenv("S3_BUCKET")+"-game-exports", + ) + if err != nil { + log.Fatalf("Unable to initialize private export storage: %v", err) + } + } + gameExportService := game_export_service.NewGameExportService( + game_exports_repo.NewGameExportsRepo(dbpool), + game_package_service.NewGamePackageService(os.Getenv("FILE_PREFIX_DOMAIN")), + exportStorage, + fileStorage.(file_storage.IStreamStorage).Open, + os.Getenv("APP_BASE_URL"), + venueMode, + ) + if !venueMode { + go gameExportService.Run(context.Background()) + } scenariosRepo := scenarios_repo.NewScenariosRepo(dbpool) cleaner := cleaner.NewCleaner() scenarioService := scenarios_service.NewScenarioService( @@ -236,6 +263,7 @@ func main() { screenPlanService, mapService, taskService, + gameExportService, ), ) @@ -295,6 +323,7 @@ func main() { } mainMux := http.NewServeMux() + mainMux.Handle("GET /api/games/{id}/export/download", app.GameExportDownloadHandler(processorJWT, gameExportService)) if !venueMode { mainMux.Handle("POST /api/games/{id}/registrations", app.TeamRegistrationHandler(os.Getenv("YANDEX_FORMS_TOKEN"), teamService.RegisterTeam)) } diff --git a/cmd/evening_detective_server/main.swagger.json b/cmd/evening_detective_server/main.swagger.json index c65c385..37b6fab 100644 --- a/cmd/evening_detective_server/main.swagger.json +++ b/cmd/evening_detective_server/main.swagger.json @@ -551,6 +551,74 @@ ] } }, + "/api/games/{ID}/export": { + "get": { + "operationId": "EveningDetectiveServer_GetGameExport", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/evening_detective_serverGameExportRsp" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "ID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + } + ], + "tags": [ + "EveningDetectiveServer" + ] + }, + "post": { + "operationId": "EveningDetectiveServer_StartGameExport", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/evening_detective_serverGameExportRsp" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "ID", + "in": "path", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/EveningDetectiveServerStartGameExportBody" + } + } + ], + "tags": [ + "EveningDetectiveServer" + ] + } + }, "/api/games/{ID}/finish": { "put": { "summary": "Закончить игру", @@ -3979,6 +4047,9 @@ "EveningDetectiveServerStartGameBody": { "type": "object" }, + "EveningDetectiveServerStartGameExportBody": { + "type": "object" + }, "EveningDetectiveServerSubmitTeamAnswersBody": { "type": "object", "properties": { @@ -4588,6 +4659,43 @@ }, "location": { "type": "string" + }, + "export": { + "$ref": "#/definitions/evening_detective_serverGameExport" + } + } + }, + "evening_detective_serverGameExport": { + "type": "object", + "properties": { + "ID": { + "type": "string" + }, + "state": { + "type": "string", + "description": "preparing, ready or failed; preparing/ready lock game writes." + }, + "packageID": { + "type": "string" + }, + "size": { + "type": "string", + "format": "int64" + }, + "sha256": { + "type": "string" + }, + "failure": { + "type": "string" + } + }, + "description": "Download ready ZIP through the authenticated streaming HTTP route:\nGET /api/games/{ID}/export/download (not an HttpBody RPC)." + }, + "evening_detective_serverGameExportRsp": { + "type": "object", + "properties": { + "export": { + "$ref": "#/definitions/evening_detective_serverGameExport" } } }, diff --git a/docs/GAME_PACKAGE.md b/docs/GAME_PACKAGE.md index 461d98f..0234457 100644 --- a/docs/GAME_PACKAGE.md +++ b/docs/GAME_PACKAGE.md @@ -105,7 +105,7 @@ defer os.RemoveAll(bundle.Dir) `Snapshot.SourceServer` содержит исходный адрес онлайн-сервера. `Snapshot.HasProgress` заполняется экспортёром по наличию действий, полученных улик и ответов. Кодек не читает БД, поэтому достоверность снимка и этого признака -обеспечивает этап 5. `Data` не имеет полей для игрового прогресса. +обеспечивает экспортёр этапа 5. `Data` не имеет полей для игрового прогресса. `Pack` сначала собирает ZIP в приватном временном каталоге, затем копирует его в `destination`. Ошибка получения файлов не выдаёт частичный пакет. Ошибка @@ -141,13 +141,108 @@ MIME и SHA-256, некорректные связи данных и состо Ошибки проверяются через `errors.Is`: `ErrInvalidPackage`, `ErrUnsupportedVersion`, `ErrLimitExceeded`, `ErrMediaUnavailable`, `ErrUnsafeURL`; отмена сохраняет `context.Canceled`/`context.DeadlineExceeded`. -Транспортных handlers на этапе 4 нет; внутренние причины ошибок нельзя напрямую -выдавать в будущем API. +Кодек не содержит транспортных handlers; экспортёр переводит ошибки в безопасные +сообщения API. SHA-256 защищает от повреждения, но не подтверждает автора пакета. Подпись и шифрование не реализованы. Кодек не блокирует игру и не делает импорт; повторные -импорты, сохранность QR на площадке и полный перенос проверяются на этапах 5–6. +импорты, сохранность QR на площадке и полный перенос проверяются на этапе 6. Проверка: `go test ./internal/services/game_package_service -count=1` и полный `go test ./...`. Тесты покрывают сохранение данных, автономное чтение, загрузку медиа, дедупликацию, потоковую обработку, отмену, очистку, лимиты и повреждённые пакеты. + +## Экспорт со статусом офлайн-режима: этап 5 + +Только для тестовых игр до реализации возврата результатов. Импорт, интерфейс +передачи, отмена и возврат результатов реализуются следующими этапами. + +### API + +Все три маршрута требуют `Authorization: Bearer ` и одну из ролей `admin`, +`developer`, `organizer`. `author` и `user` не имеют доступа. В `APP_MODE=venue` +экспорт запрещён, worker не запускается и закрытый bucket не инициализируется. + +| Метод и маршрут | Результат | +| --- | --- | +| `POST /api/games/{ID}/export` | Запуск фоновой подготовки; повторный запрос в `preparing`/`ready` возвращает ту же попытку. Тело: `{}`. | +| `GET /api/games/{ID}/export` | Последняя попытка: состояние, ID, готовый пакет либо безопасная причина ошибки. | +| `GET /api/games/{ID}/export/download` | Потоковый ZIP готовой попытки; `Content-Length`, `Content-Disposition`, `Cache-Control: no-store`, `X-Content-Type-Options: nosniff`. | + +Первые два маршрута возвращают `{"export":{"ID":"...","state":"preparing"}}`. +В `ready` добавляются `packageID` из фактического манифеста, `size` (int64 в +protobuf JSON представлен строкой), `sha256`. В `failed` — безопасный `failure`. +Снимок, инициатор, владелец worker и ключ RustFS наружу не передаются. +`Game.export` в обычных ответах игры содержит те же сведения для будущего UI. + +Ошибки доступа: HTTP 401/403; отсутствие попытки — 404; начатая игра, прогресс, +режим `venue` и ещё не готовый ZIP — HTTP 400 +(`FailedPrecondition`). Неизвестные ошибки дают безопасный HTTP 500. +Скачивание реализовано отдельным HTTP-handler с штатной JWT-проверкой; ZIP не +проходит через gRPC `HttpBody` или публичный `/api/files`. + +### Снимок и статус офлайн-режима + +Начало экспорта блокирует строку игры в короткой транзакции. Проверяются `draft`, +отсутствие `started_at`, `ended_at`, действий, улик и ответов команд. Запланированное +`start_at` переносится. Одним SQL-снимком сохраняются игра, общий сценарий, все +команды и билеты, карта, план экранов, выбранный плейлист игры и default сценария. +`game_music_states.playlist_id` имеет приоритет над `games.playlist_id`. + +Частичный уникальный индекс допускает одну попытку `preparing`/`ready` на игру. +Экспорт не запрещает изменения игры и связанных данных: команды, регистрация, +билеты, прогресс, оценки, музыка, экраны и карта продолжают работать штатно. +Почтовые workers продолжают обработку. Функций и триггеров БД нет. + +В списке игр и на странице управления `preparing` отображается как подготовка +офлайн-пакета, `ready` — как «Игра в офлайн-режиме». Это информационный статус, +а не подтверждение импорта пакета на площадке. Поля `status` и `format` игры +не меняются. При `failed` отметка офлайн-режима исчезает. + +ZIP собирается из сохранённого снимка. Изменения после начала экспорта не +попадают в этот пакет, повторное скачивание отдаёт прежнюю версию. Общие сценарии +и плейлисты остаются редактируемыми; недоступное или удалённое медиа приводит +к ошибке сборки. Отдельный интерфейс запуска/скачивания остаётся этапом 7. + +### Worker и хранение + +Очередь и снимки находятся в PostgreSQL (`game_exports`), отдельного брокера нет. +Worker проверяет задания каждые 5 секунд. После захвата попытки аренда длится +2 минуты, heartbeat обновляет её каждые 30 секунд. Общая подготовка, включая +ожидание в очереди, ограничена 30 минутами с момента запуска. Потеря владения +отменяет подготовку; `ready` публикуется только после полной загрузки ZIP и +повторной проверки ID попытки, владельца, аренды и срока подготовки в БД. + +ZIP собирается во временном каталоге `0700` с файлами `0600` и потоково +загружается в отдельный закрытый bucket `-game-exports` в текущем +RustFS с текущими учётными данными. Новые переменные окружения и изменения +production-конфигурации не нужны. Временные файлы удаляются после работы; +maintenance очищает оставшиеся каталоги терминальных попыток и неполные объекты +после перезапуска. Данные для очистки сохраняются даже после удаления игры, +независимо от её текущего наличия. + +Ошибка сборки или истёкшая аренда переводит попытку в `failed`. Повторный POST создаёт новую попытку и новый снимок. Worker старой +попытки не может опубликовать результат или изменить новую попытку. Неоднозначный +ответ БД после публикации не приводит к удалению готового ZIP: удаление допустимо +только после подтверждённого `failed`. Очистка повторяется до окончания возможной +работы старого worker. + +Готовый пакет хранится до реализации возврата результатов. Повторное скачивание +отдаёт те же байты; закрытие соединения не меняет `ready`. + +### Проверка + +`TEST_DATABASE_URL` включает PostgreSQL-проверки в изолированных схемах через +реальные миграции и публичные методы репозиториев/сервисов. `go test ./...` +проверяет снимок, конкурентный запуск, возможность изменений после экспорта, истечение +аренды/timeout, запрет устаревшей публикации, ошибку/повторный запуск, очистку, +права и режим `venue`. + +Для отдельного тестового RustFS дополнительно задаются `TEST_S3_ENDPOINT`, +`TEST_S3_USER`, `TEST_S3_PASSWORD` и запускается +`go test ./internal/services/game_export_service -run TestExportRustFS -count=1 -v`. +Тест создаёт отдельный bucket, проверяет кодек, SHA-256, анонимный отказ, потоковую +выдачу/обрыв и повторное создание клиента, затем удаляет свои объекты и bucket. +Необязательный `TEST_S3_RESTART_MARKER` позволяет внешнему тестовому harness +перезапустить изолированный RustFS: после появления marker нужно дождаться health +и создать `.continue` в течение трёх минут. Это не production-проверка. diff --git a/internal/app/game_export.go b/internal/app/game_export.go new file mode 100644 index 0000000..9f4e1f2 --- /dev/null +++ b/internal/app/game_export.go @@ -0,0 +1,97 @@ +package app + +import ( + "context" + "io" + "log" + "net/http" + "strconv" + "strings" + + "evening_detective_server/internal/modules/processor_jwt" + "evening_detective_server/internal/modules/roles" + "evening_detective_server/internal/services/game_export_service" + "evening_detective_server/proto" + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func canExportGame(claims *processor_jwt.JWTClaims) bool { + return claims != nil && (roles.HasRole(claims, roles.Organizer) || claims.HasRole(roles.Developer)) +} + +func (s *server) StartGameExport(ctx context.Context, req *proto.StartGameExportReq) (*proto.GameExportRsp, error) { + claims, err := claimsFromContext(ctx) + if err != nil { + return nil, err + } + if !canExportGame(claims) { + return nil, status.Error(codes.PermissionDenied, "permission denied") + } + result, err := s.gameExportService.Start(ctx, int(req.GetID()), claims.UserID) + if err != nil { + return nil, gameExportErrorStatus(err) + } + return &proto.GameExportRsp{Export: mapGameExport(result)}, nil +} + +func (s *server) GetGameExport(ctx context.Context, req *proto.GetGameExportReq) (*proto.GameExportRsp, error) { + claims, err := claimsFromContext(ctx) + if err != nil { + return nil, err + } + if !canExportGame(claims) { + return nil, status.Error(codes.PermissionDenied, "permission denied") + } + result, err := s.gameExportService.Get(ctx, int(req.GetID())) + if err != nil { + return nil, gameExportErrorStatus(err) + } + return &proto.GameExportRsp{Export: mapGameExport(result)}, nil +} + +// GameExportDownloadHandler authenticates with the existing JWT processor and streams private ZIPs. +func GameExportDownloadHandler(jwt processor_jwt.IProcessorJWT, exports *game_export_service.GameExportService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Cache-Control", "no-store") + fail := func(err error) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(runtime.HTTPStatusFromCode(status.Code(err))) + // The message has already been reduced to a safe transport error. + _, _ = w.Write([]byte(`{"error":` + strconv.Quote(status.Convert(err).Message()) + `}`)) + } + token := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ") + if token == "" { + fail(status.Error(codes.Unauthenticated, "Требуется авторизация")) + return + } + claims, err := jwt.GetClaims(token) + if err != nil { + fail(status.Error(codes.Unauthenticated, "Недействительный токен")) + return + } + if !canExportGame(claims) { + fail(status.Error(codes.PermissionDenied, "permission denied")) + return + } + gameID, err := strconv.ParseInt(r.PathValue("id"), 10, 32) + if err != nil || gameID <= 0 { + fail(status.Error(codes.InvalidArgument, "Некорректный идентификатор игры")) + return + } + result, body, err := exports.OpenDownload(r.Context(), int(gameID)) + if err != nil { + fail(gameExportErrorStatus(err)) + return + } + defer func() { _ = body.Close() }() + w.Header().Set("Content-Type", "application/zip") + w.Header().Set("Content-Disposition", `attachment; filename="game-`+result.PackageID+`.zip"`) + w.Header().Set("Content-Length", strconv.FormatInt(result.Size, 10)) + w.Header().Set("X-Content-Type-Options", "nosniff") + if _, err := io.CopyBuffer(w, body, make([]byte, 32<<10)); err != nil && r.Context().Err() == nil { + log.Printf("game export download: %v", err) + } + }) +} diff --git a/internal/app/game_export_errors.go b/internal/app/game_export_errors.go new file mode 100644 index 0000000..12be667 --- /dev/null +++ b/internal/app/game_export_errors.go @@ -0,0 +1,30 @@ +package app + +import ( + "errors" + "log" + + "evening_detective_server/internal/services/game_export_service" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func gameExportErrorStatus(err error) error { + switch { + case errors.Is(err, game_export_service.ErrGameNotFound): + return status.Error(codes.NotFound, game_export_service.ErrGameNotFound.Error()) + case errors.Is(err, game_export_service.ErrExportNotFound): + return status.Error(codes.NotFound, game_export_service.ErrExportNotFound.Error()) + case errors.Is(err, game_export_service.ErrVenueMode): + return status.Error(codes.FailedPrecondition, game_export_service.ErrVenueMode.Error()) + case errors.Is(err, game_export_service.ErrNotReady): + return status.Error(codes.FailedPrecondition, game_export_service.ErrNotReady.Error()) + case errors.Is(err, game_export_service.ErrNotExportable): + return status.Error(codes.FailedPrecondition, game_export_service.ErrNotExportable.Error()) + case errors.Is(err, game_export_service.ErrInvalidGameID): + return status.Error(codes.InvalidArgument, game_export_service.ErrInvalidGameID.Error()) + default: + log.Printf("game export API: %v", err) + return status.Error(codes.Internal, "Не удалось выполнить операцию экспорта игры") + } +} diff --git a/internal/app/game_export_mapper.go b/internal/app/game_export_mapper.go new file mode 100644 index 0000000..3c9af40 --- /dev/null +++ b/internal/app/game_export_mapper.go @@ -0,0 +1,20 @@ +package app + +import ( + "evening_detective_server/internal/services/game_export_service" + "evening_detective_server/proto" +) + +func mapGameExport(value *game_export_service.GameExport) *proto.GameExport { + if value == nil { + return nil + } + return &proto.GameExport{ + ID: value.ID, + State: value.State, + PackageID: value.PackageID, + Size: value.Size, + Sha256: value.SHA256, + Failure: value.Failure, + } +} diff --git a/internal/app/game_export_test.go b/internal/app/game_export_test.go new file mode 100644 index 0000000..ff05dc8 --- /dev/null +++ b/internal/app/game_export_test.go @@ -0,0 +1,87 @@ +package app + +import ( + "context" + "errors" + "fmt" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "evening_detective_server/internal/modules/processor_jwt" + "evening_detective_server/internal/services/game_export_service" + "evening_detective_server/proto" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func TestExportRolesAndVenueMode(t *testing.T) { + exports := game_export_service.NewGameExportService(nil, nil, nil, nil, "", true) + server := &server{gameExportService: exports} + jwt := processor_jwt.NewProcessor("export-test-secret") + for _, tc := range []struct { + role string + code codes.Code + httpCode int + }{ + {"admin", codes.FailedPrecondition, http.StatusBadRequest}, + {"developer", codes.FailedPrecondition, http.StatusBadRequest}, + {"organizer", codes.FailedPrecondition, http.StatusBadRequest}, + {"author", codes.PermissionDenied, http.StatusForbidden}, + {"user", codes.PermissionDenied, http.StatusForbidden}, + {"", codes.Unauthenticated, http.StatusUnauthorized}, + } { + t.Run(tc.role, func(t *testing.T) { + ctx := context.Background() + if tc.role != "" { + ctx = processor_jwt.ContextWithClaims(ctx, &processor_jwt.JWTClaims{UserID: 1, Roles: []string{tc.role}}) + } + _, err := server.StartGameExport(ctx, &proto.StartGameExportReq{ID: 1}) + if status.Code(err) != tc.code { + t.Fatalf("start access: %v", err) + } + _, err = server.GetGameExport(ctx, &proto.GetGameExportReq{ID: 1}) + if status.Code(err) != tc.code { + t.Fatalf("status access: %v", err) + } + request := httptest.NewRequest(http.MethodGet, "/api/games/1/export/download", nil) + request.SetPathValue("id", "1") + if tc.role != "" { + token, err := jwt.GenerateAccessToken(1, "export@test.invalid", []string{tc.role}) + if err != nil { + t.Fatal(err) + } + request.Header.Set("Authorization", "Bearer "+token) + } + response := httptest.NewRecorder() + GameExportDownloadHandler(jwt, exports).ServeHTTP(response, request) + if response.Code != tc.httpCode { + t.Fatalf("download access: %d, %s", response.Code, response.Body.String()) + } + }) + } +} + +func TestExportErrorsAreSafe(t *testing.T) { + for _, tc := range []struct { + name string + err error + code codes.Code + }{ + {"game missing", game_export_service.ErrGameNotFound, codes.NotFound}, + {"export missing", game_export_service.ErrExportNotFound, codes.NotFound}, + {"progress", game_export_service.ErrNotExportable, codes.FailedPrecondition}, + {"not ready", game_export_service.ErrNotReady, codes.FailedPrecondition}, + {"venue", game_export_service.ErrVenueMode, codes.FailedPrecondition}, + {"invalid game", game_export_service.ErrInvalidGameID, codes.InvalidArgument}, + {"internal", errors.New("private SQL and object key"), codes.Internal}, + } { + t.Run(tc.name, func(t *testing.T) { + mapped := gameExportErrorStatus(fmt.Errorf("private detail: %w", tc.err)) + if status.Code(mapped) != tc.code || strings.Contains(mapped.Error(), "private") { + t.Fatalf("unexpected export status: %v", mapped) + } + }) + } +} diff --git a/internal/app/game_mapper.go b/internal/app/game_mapper.go index ae8157d..1d59b6b 100644 --- a/internal/app/game_mapper.go +++ b/internal/app/game_mapper.go @@ -29,6 +29,7 @@ func mapGame( } return &proto.Game{ ID: int32(o.ID), + Export: mapGameExport(o.Export), Name: o.Name, Description: o.Description, Location: location, diff --git a/internal/app/server.go b/internal/app/server.go index bedec3e..6a3ef46 100644 --- a/internal/app/server.go +++ b/internal/app/server.go @@ -3,6 +3,7 @@ package app import ( "evening_detective_server/internal/services/answer_service" "evening_detective_server/internal/services/file_service" + "evening_detective_server/internal/services/game_export_service" "evening_detective_server/internal/services/game_review_service" "evening_detective_server/internal/services/game_service" "evening_detective_server/internal/services/gameplay_service" @@ -28,6 +29,7 @@ type server struct { taskService *task_service.TaskService fileService *file_service.FileService scenarioService *scenarios_service.ScenarioService + gameExportService *game_export_service.GameExportService gameService *game_service.GameService gameplayService *gameplay_service.GameplayService answerService *answer_service.AnswerService @@ -59,9 +61,11 @@ func NewServer( screenPlanService *screen_plan_service.ScreenPlanService, mapService *map_service.MapService, taskService *task_service.TaskService, + gameExportService *game_export_service.GameExportService, ) proto.EveningDetectiveServerServer { return &server{ taskService: taskService, + gameExportService: gameExportService, usersService: usersService, uiService: uiService, fileService: fileService, diff --git a/internal/modules/file_storage/storage.go b/internal/modules/file_storage/storage.go index d275728..4e9a51d 100644 --- a/internal/modules/file_storage/storage.go +++ b/internal/modules/file_storage/storage.go @@ -38,13 +38,19 @@ func NewRustFSStorage( ctx, cancel := context.WithTimeout(ctx, 3*time.Second) defer cancel() - err = client.CreateBucket( - ctx, - bucket, - ) + exists, err := client.BucketExists(ctx, bucket) if err != nil { return nil, err } + if !exists { + err = client.CreateBucket(ctx, bucket) + if err != nil { + var apiErr smithy.APIError + if !errors.As(err, &apiErr) || apiErr.ErrorCode() != "BucketAlreadyOwnedByYou" { + return nil, err + } + } + } return &storage{ client: client, diff --git a/internal/modules/file_storage/stream.go b/internal/modules/file_storage/stream.go new file mode 100644 index 0000000..fcc6c16 --- /dev/null +++ b/internal/modules/file_storage/stream.go @@ -0,0 +1,30 @@ +package file_storage + +import ( + "context" + "io" +) + +// IStreamStorage supports large private objects without loading them into memory. +type IStreamStorage interface { + PutStream(context.Context, string, io.Reader, string) error + Open(context.Context, string) (io.ReadCloser, error) + Delete(context.Context, string) error +} + +// NewPrivateRustFSStorage uses an independent bucket with no public file route or policy. +func NewPrivateRustFSStorage(ctx context.Context, endpoint, user, password, bucket string) (IStreamStorage, error) { + files, err := NewRustFSStorage(ctx, endpoint, user, password, bucket) + if err != nil { + return nil, err + } + return files.(*storage), nil +} + +func (s *storage) PutStream(ctx context.Context, key string, body io.Reader, mime string) error { + return s.client.PutObject(ctx, s.bucket, key, body, mime) +} + +func (s *storage) Open(ctx context.Context, key string) (io.ReadCloser, error) { + return s.client.GetObject(ctx, s.bucket, key) +} diff --git a/internal/repos/game.go b/internal/repos/game.go index a675ace..f00bd07 100644 --- a/internal/repos/game.go +++ b/internal/repos/game.go @@ -6,6 +6,7 @@ import ( // Game describes a game and its scenario and teams. type Game struct { + Export *GameExport Format string ID int Name string diff --git a/internal/repos/game_export.go b/internal/repos/game_export.go new file mode 100644 index 0000000..d7a363d --- /dev/null +++ b/internal/repos/game_export.go @@ -0,0 +1,11 @@ +package repos + +// GameExport contains public status, never the snapshot or storage key. +type GameExport struct { + ID string `json:"id"` + State string `json:"state"` + PackageID string `json:"package_id"` + Size int64 `json:"size"` + SHA256 string `json:"sha256"` + Failure string `json:"failure"` +} diff --git a/internal/repos/game_exports_repo/fixture_test.go b/internal/repos/game_exports_repo/fixture_test.go new file mode 100644 index 0000000..f93e054 --- /dev/null +++ b/internal/repos/game_exports_repo/fixture_test.go @@ -0,0 +1,106 @@ +package game_exports_repo + +import ( + "context" + "fmt" + "os" + "path/filepath" + "strings" + "testing" + "time" + + "evening_detective_server/internal/repos/games_repo" + "evening_detective_server/internal/repos/scenarios_repo" + "evening_detective_server/internal/repos/teams_repo" + "evening_detective_server/internal/repos/user_agreements_repo" + "evening_detective_server/internal/repos/users_repo" + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgxpool" +) + +type exportFixture struct { + pool *pgxpool.Pool + exports *GameExportsRepo + games *games_repo.GamesRepo + teams *teams_repo.TeamsRepo + scenarios *scenarios_repo.ScenariosRepo + users *users_repo.UsersRepo + userID int + scenarioID int + gameID int + teamID int +} + +// newExportFixture uses real migrations in an isolated test schema; all game data uses repositories. +func newExportFixture(t *testing.T) exportFixture { + t.Helper() + dsn := os.Getenv("TEST_DATABASE_URL") + if dsn == "" { + t.Skip("set TEST_DATABASE_URL for PostgreSQL export checks") + } + ctx := context.Background() + admin, err := pgxpool.New(ctx, dsn) + requireNoError(t, err) + schema := fmt.Sprintf("exports_test_%d", time.Now().UnixNano()) + quoted := pgx.Identifier{schema}.Sanitize() + _, err = admin.Exec(ctx, "CREATE SCHEMA "+quoted) + requireNoError(t, err) + t.Cleanup(func() { + _, err := admin.Exec(ctx, "DROP SCHEMA "+quoted+" CASCADE") + if err != nil { + t.Error(err) + } + admin.Close() + }) + config, err := pgxpool.ParseConfig(dsn) + requireNoError(t, err) + config.ConnConfig.RuntimeParams["search_path"] = schema + config.ConnConfig.RuntimeParams["timezone"] = "UTC" + pool, err := pgxpool.NewWithConfig(ctx, config) + requireNoError(t, err) + t.Cleanup(pool.Close) + files, err := filepath.Glob("../../../migrations/*.sql") + requireNoError(t, err) + for _, name := range files { + raw, err := os.ReadFile(name) + requireNoError(t, err) + _, err = pool.Exec(ctx, strings.Split(string(raw), "-- +goose Down")[0]) + if err != nil { + t.Fatalf("migration %s: %v", name, err) + } + } + f := exportFixture{ + pool: pool, + exports: NewGameExportsRepo(pool), + games: games_repo.NewGamesRepo(pool), + teams: teams_repo.NewTeamsRepo(pool), + scenarios: scenarios_repo.NewScenariosRepo(pool), + users: users_repo.NewUserRepo(pool), + } + f.userID, err = f.users.AddUserWithAgreements(ctx, "organizer", "export@test.invalid", "hash", []string{"organizer"}, + []user_agreements_repo.Agreement{{AgreementType: "terms", Version: "test"}}) + requireNoError(t, err) + f.scenarioID, err = f.scenarios.AddScenario(ctx, "Original story", f.userID) + requireNoError(t, err) + requireNoError(t, f.scenarios.UpdateStoryByScenarioID(ctx, f.scenarioID, + `{"introduction":{"text":"Intro"},"questions":[{"code":"q","text":"Who?","answer":"Butler"}]}`)) + f.gameID, err = f.games.AddGame(ctx, "Test export", "Original description", nil, time.Now().Add(12*time.Hour), int32(f.scenarioID), "offline") + requireNoError(t, err) + f.teamID, err = f.teams.AddTeamWithParticipation(ctx, f.userID, f.gameID, "Team", "original-qr", "captain@test.invalid", 3, false) + requireNoError(t, err) + return f +} + +func requireNoError(t *testing.T, err error) { + t.Helper() + if err != nil { + t.Fatal(err) + } +} + +func (f exportFixture) start(t *testing.T, id string) *Attempt { + t.Helper() + attempt, err := f.exports.Start(context.Background(), f.gameID, f.userID, id, "https://game.example") + requireNoError(t, err) + return attempt +} diff --git a/internal/repos/game_exports_repo/repo.go b/internal/repos/game_exports_repo/repo.go new file mode 100644 index 0000000..5a700c5 --- /dev/null +++ b/internal/repos/game_exports_repo/repo.go @@ -0,0 +1,366 @@ +// Package game_exports_repo persists export attempts and their immutable snapshots. +package game_exports_repo + +import ( + "context" + "errors" + "time" + + "evening_detective_server/internal/repos" + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgxpool" +) + +var ( + ErrGameNotFound = errors.New("игра не найдена") + ErrNotExportable = errors.New("экспорт доступен только для игры в черновике без дат проведения и прогресса") + ErrExportNotFound = errors.New("экспорт игры ещё не запущен") + ErrOwnershipLost = errors.New("владение экспортом потеряно") +) + +const Lease = 2 * time.Minute +const PrepareTimeout = 30 * time.Minute + +// Attempt includes private worker data; only GameExport may be exposed to clients. +type Attempt struct { + repos.GameExport + GameID int + Snapshot []byte + SourceServer string + ObjectKey string + CreatedAt time.Time +} + +type GameExportsRepo struct { + pool *pgxpool.Pool + lease time.Duration + prepareTimeout time.Duration +} + +func NewGameExportsRepo(pool *pgxpool.Pool) *GameExportsRepo { + return &GameExportsRepo{ + pool: pool, + lease: Lease, + prepareTimeout: PrepareTimeout, + } +} + +// Start locks the game before inspecting progress, then saves all package data in one SQL snapshot. +func (r *GameExportsRepo) Start(ctx context.Context, gameID, userID int, id, source string) (*Attempt, error) { + tx, err := r.pool.Begin(ctx) + if err != nil { + return nil, err + } + defer func() { _ = tx.Rollback(ctx) }() + var status string + var started, ended *time.Time + err = tx.QueryRow( + ctx, + `SELECT + status, + started_at, + ended_at + FROM games + WHERE id = $1 + FOR UPDATE`, + gameID, + ).Scan(&status, &started, &ended) + if errors.Is(err, pgx.ErrNoRows) { + return nil, ErrGameNotFound + } + if err != nil { + return nil, err + } + existing, err := readAttempt(ctx, tx, gameID, true, true) + if err == nil { + return existing, tx.Commit(ctx) + } + if !errors.Is(err, ErrExportNotFound) { + return nil, err + } + if status != "draft" || started != nil || ended != nil { + return nil, ErrNotExportable + } + var progress bool + err = tx.QueryRow( + ctx, + `SELECT + EXISTS ( + SELECT + 1 + FROM teams t + WHERE t.game_id = $1 AND ( + EXISTS ( + SELECT + 1 + FROM actions a + WHERE a.team_id = t.id + ) + OR EXISTS ( + SELECT + 1 + FROM applications a + WHERE a.team_id = t.id + ) + OR EXISTS ( + SELECT + 1 + FROM team_answers a + WHERE a.team_id = t.id + ) + ) + )`, + gameID, + ).Scan(&progress) + if err != nil { + return nil, err + } + if progress { + return nil, ErrNotExportable + } + snapshot, err := captureSnapshot(ctx, tx, gameID) + if err != nil { + return nil, err + } + _, err = tx.Exec( + ctx, + `INSERT INTO game_exports (id, game_id, initiator_id, snapshot, source_server, object_key) + VALUES ($1, $2, $3, $4, $5, $6)`, + id, + gameID, + userID, + snapshot, + source, + id+".zip", + ) + if err != nil { + return nil, err + } + result, err := readAttempt(ctx, tx, gameID, true, true) + if err != nil { + return nil, err + } + return result, tx.Commit(ctx) +} + +func (r *GameExportsRepo) Get(ctx context.Context, gameID int) (*Attempt, error) { + return readAttempt(ctx, r.pool, gameID, false, false) +} + +// IRowReader is implemented by both the pool and a transaction. +type IRowReader interface { + QueryRow(context.Context, string, ...any) pgx.Row +} + +func readAttempt(ctx context.Context, reader IRowReader, gameID int, active, withSnapshot bool) (*Attempt, error) { + attempt := &Attempt{} + err := reader.QueryRow( + ctx, + `SELECT + id, + COALESCE(game_id, 0), + state, + package_id, + size, + sha256, + failure, + CASE WHEN $3 THEN snapshot ELSE NULL END, + source_server, + object_key, + created_at + FROM game_exports + WHERE game_id = $1 AND (NOT $2 OR state IN ('preparing', 'ready')) + ORDER BY created_at DESC, id + LIMIT 1`, + gameID, + active, + withSnapshot, + ).Scan(&attempt.ID, &attempt.GameID, &attempt.State, &attempt.PackageID, &attempt.Size, + &attempt.SHA256, &attempt.Failure, &attempt.Snapshot, &attempt.SourceServer, &attempt.ObjectKey, &attempt.CreatedAt) + if errors.Is(err, pgx.ErrNoRows) { + return nil, ErrExportNotFound + } + return attempt, err +} + +// Claim only assigns unowned live attempts. Expired ownership is failed, never reassigned. +func (r *GameExportsRepo) Claim(ctx context.Context, owner string) (*Attempt, error) { + attempt := &Attempt{} + err := r.pool.QueryRow( + ctx, + `WITH candidate AS ( + SELECT + id + FROM game_exports + WHERE state = 'preparing' AND owner_id IS NULL + AND created_at + $3::interval > clock_timestamp() + ORDER BY created_at + FOR UPDATE SKIP LOCKED + LIMIT 1 + ) + UPDATE game_exports e + SET owner_id = $1, lease_until = clock_timestamp() + $2::interval + FROM candidate c + WHERE e.id = c.id + RETURNING + e.id, + COALESCE(e.game_id, 0), + e.state, + e.package_id, + e.size, + e.sha256, + e.failure, + e.snapshot, + e.source_server, + e.object_key, + e.created_at`, + owner, + r.lease.String(), + r.prepareTimeout.String(), + ).Scan(&attempt.ID, &attempt.GameID, &attempt.State, &attempt.PackageID, &attempt.Size, + &attempt.SHA256, &attempt.Failure, &attempt.Snapshot, &attempt.SourceServer, &attempt.ObjectKey, &attempt.CreatedAt) + if err != nil { + return nil, err + } + return attempt, nil +} + +func (r *GameExportsRepo) Heartbeat(ctx context.Context, id, owner string) error { + tag, err := r.pool.Exec( + ctx, + `UPDATE game_exports + SET lease_until = clock_timestamp() + $3::interval + WHERE id = $1 AND owner_id = $2 AND state = 'preparing' + AND lease_until > clock_timestamp() + AND created_at + $4::interval > clock_timestamp()`, + id, + owner, + r.lease.String(), + r.prepareTimeout.String(), + ) + if err != nil { + return err + } + if tag.RowsAffected() == 0 { + return ErrOwnershipLost + } + return nil +} + +// Complete fences publication by attempt, owner, lease and total preparation deadline. +func (r *GameExportsRepo) Complete(ctx context.Context, id, owner, packageID, digest string, size int64) error { + tag, err := r.pool.Exec( + ctx, + `UPDATE game_exports + SET state = 'ready', package_id = $3, sha256 = $4, size = $5, + owner_id = NULL, lease_until = NULL + WHERE id = $1 AND owner_id = $2 AND state = 'preparing' + AND lease_until > clock_timestamp() + AND created_at + $6::interval > clock_timestamp()`, + id, + owner, + packageID, + digest, + size, + r.prepareTimeout.String(), + ) + if err != nil { + return err + } + if tag.RowsAffected() == 0 { + return ErrOwnershipLost + } + return nil +} + +// Fail refuses stale workers without changing game data. +func (r *GameExportsRepo) Fail(ctx context.Context, id, owner, reason string) error { + tag, err := r.pool.Exec( + ctx, + `UPDATE game_exports + SET state = 'failed', failure = $3, owner_id = NULL, lease_until = NULL + WHERE id = $1 AND owner_id = $2 + AND state = 'preparing' AND lease_until > clock_timestamp()`, + id, + owner, + reason, + ) + if err != nil { + return err + } + if tag.RowsAffected() == 0 { + return ErrOwnershipLost + } + return nil +} + +func (r *GameExportsRepo) Expire(ctx context.Context) error { + _, err := r.pool.Exec( + ctx, + `UPDATE game_exports + SET state = 'failed', failure = 'Подготовка прервана. Запустите экспорт повторно.', + owner_id = NULL, lease_until = NULL + WHERE state = 'preparing' AND ( + lease_until <= clock_timestamp() OR created_at + $1::interval <= clock_timestamp() + )`, + r.prepareTimeout.String(), + ) + return err +} + +// CleanupKeys retries deletions until all old workers' preparation deadlines have elapsed. +func (r *GameExportsRepo) CleanupKeys(ctx context.Context) ([]string, error) { + rows, err := r.pool.Query( + ctx, + `SELECT + object_key + FROM game_exports + WHERE state = 'failed' AND (cleaned_at IS NULL OR ( + cleaned_at < created_at + $1::interval AND cleaned_at < clock_timestamp() - INTERVAL '2 minutes' + )) + ORDER BY created_at + LIMIT 100`, + (r.prepareTimeout + r.lease).String(), + ) + if err != nil { + return nil, err + } + defer rows.Close() + keys := []string{} + for rows.Next() { + var key string + if err := rows.Scan(&key); err != nil { + return nil, err + } + keys = append(keys, key) + } + return keys, rows.Err() +} + +func (r *GameExportsRepo) MarkCleaned(ctx context.Context, key string) error { + _, err := r.pool.Exec( + ctx, + `UPDATE game_exports + SET cleaned_at = clock_timestamp() + WHERE object_key = $1 AND state = 'failed'`, + key, + ) + return err +} + +// IsInactive only identifies known terminal attempts, including leftovers after successful publication. +func (r *GameExportsRepo) IsInactive(ctx context.Context, id string) (bool, error) { + var inactive bool + err := r.pool.QueryRow( + ctx, + `SELECT + EXISTS ( + SELECT + 1 + FROM game_exports + WHERE id = $1 AND state IN ('ready', 'failed') + )`, + id, + ).Scan(&inactive) + return inactive, err +} diff --git a/internal/repos/game_exports_repo/repo_test.go b/internal/repos/game_exports_repo/repo_test.go new file mode 100644 index 0000000..fab7142 --- /dev/null +++ b/internal/repos/game_exports_repo/repo_test.go @@ -0,0 +1,340 @@ +package game_exports_repo + +import ( + "bytes" + "context" + "crypto/sha256" + "encoding/json" + "errors" + "fmt" + "sync" + "testing" + "time" + + "evening_detective_server/internal/repos" + "evening_detective_server/internal/repos/actions_repo" + "evening_detective_server/internal/repos/applications_repo" + "evening_detective_server/internal/repos/game_map_repo" + "evening_detective_server/internal/repos/game_reviews_repo" + "evening_detective_server/internal/repos/game_screen_plans_repo" + "evening_detective_server/internal/repos/playlists_repo" + "evening_detective_server/internal/repos/screen_sessions_repo" + "evening_detective_server/internal/repos/team_answers_repo" + "evening_detective_server/internal/repos/tickets_repo" + "github.com/jackc/pgx/v5" +) + +func TestExportSnapshotAndEditableGame(t *testing.T) { + for _, state := range []string{"preparing", "ready"} { + t.Run(state, func(t *testing.T) { + f := newExportFixture(t) + ctx := context.Background() + music := playlists_repo.New(f.pool) + base, err := music.Create(ctx, "Scenario default") + requireNoError(t, err) + assigned, err := music.Create(ctx, "Game assigned") + requireNoError(t, err) + selected, err := music.Create(ctx, "Selected by screen") + requireNoError(t, err) + requireNoError(t, music.SetScenario(ctx, f.scenarioID, base.ID)) + requireNoError(t, music.SetGame(ctx, f.gameID, assigned.ID)) + _, err = music.SetMusic(ctx, f.gameID, selected.ID, 0, 0, 100, false, 1) + requireNoError(t, err) + ticketRepo := tickets_repo.New(f.pool) + activeHash := sha256.Sum256([]byte("active-ticket")) + usedHash := sha256.Sum256([]byte("used-ticket")) + _, err = ticketRepo.CreateBatch(ctx, f.gameID, [][]byte{activeHash[:], usedHash[:]}) + requireNoError(t, err) + _, err = ticketRepo.Accept(ctx, usedHash[:], f.userID) + requireNoError(t, err) + token := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + requireNoError(t, f.teams.SetParticipationToken(ctx, f.teamID, token)) + mapRepo := game_map_repo.NewGameMapRepo(f.pool) + requireNoError(t, mapRepo.Ensure(ctx, f.gameID, "team", f.teamID)) + plans := game_screen_plans_repo.NewGameScreenPlansRepo(f.pool) + _, err = plans.Save(ctx, f.gameID, []game_screen_plans_repo.Step{{Mode: 1}}, 0) + requireNoError(t, err) + screens := screen_sessions_repo.NewScreenSessionsRepo(f.pool) + screenID, err := screens.Create(ctx, "screen-token-hash") + requireNoError(t, err) + requireNoError(t, screens.Bind(ctx, screenID, f.gameID, "screen-token-hash")) + reviews := game_reviews_repo.NewGameReviewsRepo(f.pool) + review, err := reviews.Create(ctx, f.gameID, f.teamID, 5, 2, "Review") + requireNoError(t, err) + attempt := f.start(t, "attempt-original") + if state == "ready" { + _, err := f.exports.Claim(ctx, "worker") + requireNoError(t, err) + requireNoError(t, f.exports.Complete(ctx, attempt.ID, "worker", "package-id", "digest", 123)) + } + var snapshot struct { + Game struct { + PlaylistID int `json:"playlist_id"` + } + Scenario struct { + Name string `json:"name"` + } + Teams []struct { + Password string `json:"password"` + } + Tickets []struct { + TokenHash []byte `json:"token_hash"` + Status string `json:"status"` + } + Playlists []struct { + ID int `json:"id"` + } + } + requireNoError(t, json.Unmarshal(attempt.Snapshot, &snapshot)) + if snapshot.Game.PlaylistID != selected.ID || len(snapshot.Playlists) != 2 || len(snapshot.Tickets) != 2 || + !bytes.Equal(snapshot.Tickets[0].TokenHash, activeHash[:]) || snapshot.Teams[0].Password != "original-qr" { + t.Fatalf("snapshot lost effective music, ticket or QR: %+v", snapshot) + } + requireNoError(t, f.teams.UpdateTeam(ctx, f.teamID, "Online edit")) + _, err = f.teams.RegisterTeam(ctx, f.gameID, "delivery", "New", "new@test.invalid", 2, "password") + requireNoError(t, err) + _, err = f.teams.AnswerParticipation(ctx, token, "confirmed") + requireNoError(t, err) + _, err = actions_repo.NewActionsRepo(f.pool).AddAction(ctx, f.teamID, "code", false) + requireNoError(t, err) + _, err = ticketRepo.Accept(ctx, activeHash[:], f.userID) + requireNoError(t, err) + _, err = music.SetMusic(ctx, f.gameID, base.ID, 0, 0, 100, false, 1) + requireNoError(t, err) + _, err = plans.Save(ctx, f.gameID, []game_screen_plans_repo.Step{{Mode: 2}}, 0) + requireNoError(t, err) + requireNoError(t, screens.SetMode(ctx, f.gameID, 2)) + requireNoError(t, screens.Unbind(ctx, screenID)) + requireNoError(t, mapRepo.Update(ctx, game_map_repo.Item{GameID: f.gameID, Kind: "team", ItemID: f.teamID, X: 10})) + _, err = reviews.Moderate(ctx, review.ID, "approved") + requireNoError(t, err) + same, err := f.exports.Start(ctx, f.gameID, f.userID, "not-a-new-attempt", "test") + requireNoError(t, err) + if same.ID != attempt.ID || !bytes.Equal(same.Snapshot, attempt.Snapshot) { + t.Fatal("online edits changed an existing export snapshot") + } + requireNoError(t, f.scenarios.UpdateScenarioByID(ctx, f.scenarioID, "Edited shared story", "", "")) + _, err = music.Update(ctx, selected.ID, "Edited shared playlist") + requireNoError(t, err) + requireNoError(t, f.users.DeleteUser(ctx, f.userID)) + team, err := f.teams.GetTeamByID(ctx, f.teamID) + requireNoError(t, err) + if team.Password != "original-qr" { + t.Fatal("account deletion changed exported team") + } + ticket, err := ticketRepo.GetByHash(ctx, usedHash[:]) + requireNoError(t, err) + if ticket.UsedBy != nil || ticket.Status != "used" { + t.Fatal("account deletion changed exported ticket") + } + }) + } +} + +func TestExportConcurrentStartAndTeamWrites(t *testing.T) { + for _, tc := range []struct{ name string }{{"one active attempt and consistent team snapshot"}} { + t.Run(tc.name, func(t *testing.T) { + f := newExportFixture(t) + ctx := context.Background() + var wg sync.WaitGroup + attempts := make(chan *Attempt, 8) + errs := make(chan error, 9) + for n := range 8 { + wg.Add(1) + go func() { + defer wg.Done() + attempt, err := f.exports.Start(ctx, f.gameID, f.userID, fmt.Sprintf("attempt-%d", n), "https://game.example") + if err != nil { + errs <- err + } else { + attempts <- attempt + } + }() + } + wg.Add(1) + var changeErr error + go func() { defer wg.Done(); changeErr = f.teams.UpdateTeam(ctx, f.teamID, "Concurrent name") }() + wg.Wait() + close(errs) + close(attempts) + for err := range errs { + t.Error(err) + } + if changeErr != nil { + t.Fatal(changeErr) + } + var id string + for attempt := range attempts { + if id != "" && id != attempt.ID { + t.Fatal("more than one active export") + } + id = attempt.ID + var snapshot struct { + Teams []struct { + Name string `json:"name"` + } + } + requireNoError(t, json.Unmarshal(attempt.Snapshot, &snapshot)) + if snapshot.Teams[0].Name != "Concurrent name" && snapshot.Teams[0].Name != "Team" { + t.Fatalf("unexpected team snapshot: %s", snapshot.Teams[0].Name) + } + } + }) + } +} + +func TestExportRejectsProgressAndRunningGames(t *testing.T) { + for _, tc := range []struct { + name string + mutate func(exportFixture) error + }{ + {"started", func(f exportFixture) error { return f.games.StartGame(context.Background(), f.gameID) }}, + {"actions", func(f exportFixture) error { + _, e := actions_repo.NewActionsRepo(f.pool).AddAction(context.Background(), f.teamID, "p", false) + return e + }}, + {"applications", func(f exportFixture) error { + _, e := applications_repo.NewApplicationsRepo(f.pool).AddApplication(context.Background(), f.teamID, "Clue", "clue.pdf", "pdf") + return e + }}, + {"answers", func(f exportFixture) error { + return team_answers_repo.NewTeamAnswersRepo(f.pool).UpsertAnswers(context.Background(), f.teamID, []repos.TeamAnswer{{QuestionCode: "q"}}) + }}, + } { + t.Run(tc.name, func(t *testing.T) { + f := newExportFixture(t) + requireNoError(t, tc.mutate(f)) + _, err := f.exports.Start(context.Background(), f.gameID, f.userID, "attempt", "https://game.example") + if !errors.Is(err, ErrNotExportable) { + t.Fatalf("export allowed: %v", err) + } + requireNoError(t, f.teams.UpdateTeam(context.Background(), f.teamID, "Still writable")) + }) + } +} + +func TestExpiredExportCannotPublishAndRetryTakesNewSnapshot(t *testing.T) { + for _, tc := range []struct { + name string + lease, timeout time.Duration + }{ + {"lease", 100 * time.Millisecond, time.Minute}, + {"total deadline", time.Minute, 100 * time.Millisecond}, + } { + t.Run(tc.name, func(t *testing.T) { + f := newExportFixture(t) + f.exports.lease, f.exports.prepareTimeout = tc.lease, tc.timeout + ctx := context.Background() + attempt := f.start(t, "old-attempt") + claimed, err := f.exports.Claim(ctx, "old-worker") + requireNoError(t, err) + if claimed.ID != attempt.ID { + t.Fatal("wrong claimed attempt") + } + _, err = NewGameExportsRepo(f.pool).Claim(ctx, "other-worker") + if !errors.Is(err, pgx.ErrNoRows) { + t.Fatalf("ownership stolen: %v", err) + } + if err := f.exports.Complete(ctx, attempt.ID, "other-worker", "id", "digest", 10); !errors.Is(err, ErrOwnershipLost) { + t.Fatal(err) + } + time.Sleep(150 * time.Millisecond) + if err := f.exports.Heartbeat(ctx, attempt.ID, "old-worker"); !errors.Is(err, ErrOwnershipLost) { + t.Fatalf("expired heartbeat accepted: %v", err) + } + requireNoError(t, f.exports.Expire(ctx)) + failed, err := f.exports.Get(ctx, f.gameID) + requireNoError(t, err) + if failed.State != "failed" { + t.Fatalf("not recovered: %+v", failed) + } + requireNoError(t, f.teams.UpdateTeam(ctx, f.teamID, "New snapshot name")) + f.exports.lease, f.exports.prepareTimeout = Lease, PrepareTimeout + retry := f.start(t, "new-attempt") + if retry.ID == attempt.ID || bytes.Equal(retry.Snapshot, attempt.Snapshot) { + t.Fatal("retry reused old snapshot") + } + if err := f.exports.Fail(ctx, attempt.ID, "old-worker", "stale failure"); !errors.Is(err, ErrOwnershipLost) { + t.Fatalf("stale failure accepted: %v", err) + } + current, err := f.exports.Get(ctx, f.gameID) + requireNoError(t, err) + if current.ID != retry.ID || current.State != "preparing" { + t.Fatal("stale failure changed retry") + } + + if err := f.exports.Complete(ctx, attempt.ID, "old-worker", "id", "digest", 10); !errors.Is(err, ErrOwnershipLost) { + t.Fatalf("stale publication accepted: %v", err) + } + _, err = NewGameExportsRepo(f.pool).Claim(ctx, "new-worker") + requireNoError(t, err) + requireNoError(t, f.exports.Heartbeat(ctx, retry.ID, "new-worker")) + requireNoError(t, f.exports.Complete(ctx, retry.ID, "new-worker", "package-id", "digest", 10)) + ready, err := NewGameExportsRepo(f.pool).Get(ctx, f.gameID) + requireNoError(t, err) + if ready.State != "ready" { + t.Fatal("ready package lost after repository restart") + } + }) + } +} + +func TestFailedExportCleanupSurvivesGameDeletion(t *testing.T) { + for _, tc := range []struct{ name string }{{"cleanup remains durable after game removal"}} { + t.Run(tc.name, func(t *testing.T) { + f := newExportFixture(t) + ctx := context.Background() + attempt := f.start(t, "failed-attempt") + _, err := f.exports.Claim(ctx, "worker") + requireNoError(t, err) + requireNoError(t, f.exports.Fail(ctx, attempt.ID, "worker", "Safe failure")) + requireNoError(t, f.teams.DeleteTeam(ctx, f.teamID)) + requireNoError(t, f.games.DeleteGameByID(ctx, f.gameID)) + keys, err := f.exports.CleanupKeys(ctx) + requireNoError(t, err) + if len(keys) != 1 || keys[0] != attempt.ObjectKey { + t.Fatal("deleted game lost pending object cleanup") + } + }) + } +} + +func TestPreparingExportSurvivesGameDeletion(t *testing.T) { + for _, result := range []string{"ready", "failed", "expired"} { + t.Run(result, func(t *testing.T) { + f := newExportFixture(t) + ctx := context.Background() + attempt := f.start(t, "deleted-game-attempt") + requireNoError(t, f.teams.DeleteTeam(ctx, f.teamID)) + requireNoError(t, f.games.DeleteGameByID(ctx, f.gameID)) + claimed, err := f.exports.Claim(ctx, "worker") + requireNoError(t, err) + if claimed.ID != attempt.ID || claimed.GameID != 0 || !bytes.Equal(claimed.Snapshot, attempt.Snapshot) { + t.Fatal("deleting the game damaged queued snapshot") + } + switch result { + case "ready": + requireNoError(t, f.exports.Complete(ctx, attempt.ID, "worker", "package-id", "digest", 123)) + case "failed": + requireNoError(t, f.exports.Fail(ctx, attempt.ID, "worker", "Safe failure")) + case "expired": + f.exports.prepareTimeout = 0 + requireNoError(t, f.exports.Expire(ctx)) + } + inactive, err := f.exports.IsInactive(ctx, attempt.ID) + requireNoError(t, err) + if !inactive { + t.Fatal("deleted game left an unfinishable export") + } + keys, err := f.exports.CleanupKeys(ctx) + requireNoError(t, err) + expected := 1 + if result == "ready" { + expected = 0 + } + if len(keys) != expected { + t.Fatalf("wrong object cleanup state: %v", keys) + } + }) + } +} diff --git a/internal/repos/game_exports_repo/snapshot.go b/internal/repos/game_exports_repo/snapshot.go new file mode 100644 index 0000000..95c35c6 --- /dev/null +++ b/internal/repos/game_exports_repo/snapshot.go @@ -0,0 +1,82 @@ +package game_exports_repo + +import ( + "context" + + "github.com/jackc/pgx/v5" +) + +// captureSnapshot uses one statement so editable shared scenarios and playlists are consistent. +func captureSnapshot(ctx context.Context, tx pgx.Tx, gameID int) ([]byte, error) { + var raw []byte + err := tx.QueryRow( + ctx, + `SELECT jsonb_build_object( + 'game', jsonb_build_object( + 'id', g.id, 'name', g.name, 'description', COALESCE(g.description, ''), + 'location', g.location, 'start_at', g.start_at AT TIME ZONE 'UTC', + 'status', g.status, 'format', g.format, 'scenario_id', g.scenario_id, + 'playlist_id', COALESCE(m.playlist_id, g.playlist_id), + 'started_at', g.started_at AT TIME ZONE 'UTC', 'ended_at', g.ended_at AT TIME ZONE 'UTC' + ), + 'scenario', jsonb_build_object( + 'id', s.id, 'name', s.name, 'description', s.description, + 'image', COALESCE(s.image, ''), 'story', s.scenario, 'author_id', s.author_id, + 'status', s.status, 'created_at', s.created_at AT TIME ZONE 'UTC', + 'updated_at', s.updated_at AT TIME ZONE 'UTC', + 'published_at', s.published_at AT TIME ZONE 'UTC', 'playlist_id', s.playlist_id + ), + 'teams', COALESCE(( + SELECT jsonb_agg(jsonb_build_object( + 'id', t.id, 'game_id', t.game_id, 'name', t.name, 'status', t.status, + 'password', t.password, 'creator_id', t.creator_id, 'captain_email', t.captain_email, + 'participants_count', t.participants_count, 'participation_status', t.participation_status, + 'participation_source', t.participation_source, 'participation_answered_at', t.participation_answered_at, + 'registration_delivery_id', t.registration_delivery_id, 'created_at', t.created_at AT TIME ZONE 'UTC' + ) ORDER BY t.id) + FROM teams t + WHERE t.game_id = g.id + ), '[]'::jsonb), + 'tickets', COALESCE(( + SELECT jsonb_agg(jsonb_build_object( + 'id', t.id, 'game_id', t.game_id, 'token_hash', encode(t.token_hash, 'base64'), + 'status', t.status, 'used_at', t.used_at, 'used_by', t.used_by, 'created_at', t.created_at + ) ORDER BY t.id) + FROM tickets t + WHERE t.game_id = g.id + ), '[]'::jsonb), + 'playlists', COALESCE(( + SELECT jsonb_agg(jsonb_build_object( + 'id', p.id, 'name', p.name, 'tracks', COALESCE(( + SELECT jsonb_agg(jsonb_build_object( + 'id', tr.id, 'name', tr.name, 'filename', tr.filename, 'position', tr.position + ) ORDER BY tr.position, tr.id) + FROM playlist_tracks tr + WHERE tr.playlist_id = p.id + ), '[]'::jsonb) + ) ORDER BY p.id) + FROM playlists p + WHERE p.id IN (COALESCE(m.playlist_id, g.playlist_id), s.playlist_id) + ), '[]'::jsonb), + 'screen_plan', ( + SELECT jsonb_build_object('game_id', sp.game_id, 'steps', sp.steps, 'current_step', sp.current_step) + FROM game_screen_plans sp + WHERE sp.game_id = g.id + ), + 'map', COALESCE(( + SELECT jsonb_agg(jsonb_build_object( + 'game_id', mi.game_id, 'kind', mi.kind, 'item_id', mi.item_id, + 'x', mi.x, 'y', mi.y, 'hidden', mi.hidden + ) ORDER BY mi.kind, mi.item_id) + FROM game_map_items mi + WHERE mi.game_id = g.id + ), '[]'::jsonb) + ) + FROM games g + JOIN scenarios s ON s.id = g.scenario_id + LEFT JOIN game_music_states m ON m.game_id = g.id + WHERE g.id = $1`, + gameID, + ).Scan(&raw) + return raw, err +} diff --git a/internal/repos/game_reviews_repo/repo.go b/internal/repos/game_reviews_repo/repo.go index 33bfe36..f94d50e 100644 --- a/internal/repos/game_reviews_repo/repo.go +++ b/internal/repos/game_reviews_repo/repo.go @@ -52,7 +52,7 @@ func (r *Repo) Create(ctx context.Context, gameID, teamID int, rating, difficult FROM teams t WHERE t.id = $2 AND t.game_id = $1 ON CONFLICT (game_id, team_id) DO NOTHING - RETURNING id, game_id, team_id, rating, text, status, created_at`, + RETURNING id, game_id, team_id, rating, difficulty, text, status, created_at`, gameID, teamID, rating, diff --git a/internal/repos/games_repo/repo.go b/internal/repos/games_repo/repo.go index 9d56a3f..62c4f6b 100644 --- a/internal/repos/games_repo/repo.go +++ b/internal/repos/games_repo/repo.go @@ -76,7 +76,16 @@ func (r *GamesRepo) GetGameByID( games.status, games.scenario_id, games.started_at, - games.ended_at + games.ended_at, + (SELECT + jsonb_build_object( + 'id', e.id, 'state', e.state, 'package_id', e.package_id, + 'size', e.size, 'sha256', e.sha256, 'failure', e.failure + ) + FROM game_exports e + WHERE e.game_id = games.id + ORDER BY e.created_at DESC, e.id + LIMIT 1) FROM games WHERE id = $1`, id, @@ -92,6 +101,7 @@ func (r *GamesRepo) GetGameByID( &game.ScenarioID, &game.StartedAt, &game.EndedAt, + &game.Export, ) if err != nil { if errors.Is(err, pgx.ErrNoRows) { @@ -136,7 +146,16 @@ func (r *GamesRepo) GetGames( games.location, games.start_at, games.format, - games.status + games.status, + (SELECT + jsonb_build_object( + 'id', e.id, 'state', e.state, 'package_id', e.package_id, + 'size', e.size, 'sha256', e.sha256, 'failure', e.failure + ) + FROM game_exports e + WHERE e.game_id = games.id + ORDER BY e.created_at DESC, e.id + LIMIT 1) FROM games ORDER BY created_at DESC`, ) @@ -156,6 +175,7 @@ func (r *GamesRepo) GetGames( &game.StartAt, &game.Format, &game.Status, + &game.Export, ) if err != nil { return nil, err diff --git a/internal/services/answer_service/service_test.go b/internal/services/answer_service/service_test.go index d68ed9e..928a446 100644 --- a/internal/services/answer_service/service_test.go +++ b/internal/services/answer_service/service_test.go @@ -28,6 +28,7 @@ func TestAnswerAccessPostgres(t *testing.T) { } defer pool.Close() _, err = pool.Exec(ctx, ` + CREATE TEMP TABLE game_exports(id TEXT, game_id INT, state TEXT, package_id TEXT, size BIGINT, sha256 TEXT, failure TEXT, created_at TIMESTAMPTZ); CREATE TEMP TABLE games (id INT, name TEXT, description TEXT, location TEXT, start_at TIMESTAMP, format TEXT, status TEXT, scenario_id INT, started_at TIMESTAMP, ended_at TIMESTAMP); CREATE TEMP TABLE teams (id INT, name TEXT, captain_email TEXT, participants_count INT, @@ -71,10 +72,10 @@ func TestAnswerAccessPostgres(t *testing.T) { if _, err := pool.Exec(ctx, "UPDATE teams SET participation_status=$1", tc.participation); err != nil { t.Fatal(err) } - if _, err := service.GetTeamAnswers(ctx, 1, tc.password); !errors.Is(err, teams_repo.ErrTeamNotFound) { + if _, err := service.GetTeamAnswers(ctx, 1, tc.password); !errors.Is(err, ErrTeamNotFound) { t.Fatalf("read access: %v", err) } - if err := service.SubmitTeamAnswers(ctx, 1, tc.password, nil); !errors.Is(err, teams_repo.ErrTeamNotFound) { + if err := service.SubmitTeamAnswers(ctx, 1, tc.password, nil); !errors.Is(err, ErrTeamNotFound) { t.Fatalf("write access: %v", err) } } diff --git a/internal/services/game_export_service/export_mapper.go b/internal/services/game_export_service/export_mapper.go new file mode 100644 index 0000000..7f565a0 --- /dev/null +++ b/internal/services/game_export_service/export_mapper.go @@ -0,0 +1,19 @@ +package game_export_service + +import ( + "encoding/json" + + "evening_detective_server/internal/repos/game_exports_repo" + "evening_detective_server/internal/services/game_package_service" +) + +func mapSnapshot(attempt *game_exports_repo.Attempt) (*game_package_service.Snapshot, error) { + var data game_package_service.Data + if err := json.Unmarshal(attempt.Snapshot, &data); err != nil { + return nil, err + } + return &game_package_service.Snapshot{ + SourceServer: attempt.SourceServer, + Data: data, + }, nil +} diff --git a/internal/services/game_export_service/export_test.go b/internal/services/game_export_service/export_test.go new file mode 100644 index 0000000..0def0d6 --- /dev/null +++ b/internal/services/game_export_service/export_test.go @@ -0,0 +1,394 @@ +package game_export_service_test + +import ( + "bytes" + "context" + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + "io" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "strings" + "sync" + "testing" + "time" + + "evening_detective_server/internal/app" + "evening_detective_server/internal/modules/file_storage" + "evening_detective_server/internal/modules/processor_jwt" + "evening_detective_server/internal/repos/actions_repo" + "evening_detective_server/internal/repos/applications_repo" + "evening_detective_server/internal/repos/game_exports_repo" + "evening_detective_server/internal/repos/game_map_repo" + "evening_detective_server/internal/repos/games_repo" + "evening_detective_server/internal/repos/scenarios_repo" + "evening_detective_server/internal/repos/screen_sessions_repo" + "evening_detective_server/internal/repos/teams_repo" + "evening_detective_server/internal/repos/tickets_repo" + "evening_detective_server/internal/repos/user_agreements_repo" + "evening_detective_server/internal/repos/users_repo" + "evening_detective_server/internal/services/game_export_service" + "evening_detective_server/internal/services/game_package_service" + "evening_detective_server/internal/services/game_service" + "evening_detective_server/internal/services/map_service" + "evening_detective_server/internal/services/screen_service" + "evening_detective_server/proto" + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgxpool" +) + +type memoryStorage struct { + mu sync.Mutex + objects map[string][]byte + uploadErr error + deletes int +} + +func (s *memoryStorage) PutStream(ctx context.Context, key string, body io.Reader, mime string) error { + data, err := io.ReadAll(body) + if err != nil { + return err + } + s.mu.Lock() + defer s.mu.Unlock() + s.objects[key] = data + return s.uploadErr +} + +func (s *memoryStorage) Open(ctx context.Context, key string) (io.ReadCloser, error) { + s.mu.Lock() + defer s.mu.Unlock() + data, ok := s.objects[key] + if !ok { + return nil, file_storage.ErrFileNotFound + } + return io.NopCloser(bytes.NewReader(data)), nil +} + +func (s *memoryStorage) Delete(ctx context.Context, key string) error { + s.mu.Lock() + defer s.mu.Unlock() + delete(s.objects, key) + s.deletes++ + return nil +} + +type serviceFixture struct { + pool *pgxpool.Pool + repo *game_exports_repo.GameExportsRepo + codec *game_package_service.GamePackageService + games *games_repo.GamesRepo + teams *teams_repo.TeamsRepo + scenarios *scenarios_repo.ScenariosRepo + gameID, teamID, scenarioID, userID int + media []byte +} + +// newServiceFixture is schema infrastructure only; all fixture data uses public repositories. +func newServiceFixture(t *testing.T) serviceFixture { + t.Helper() + dsn := os.Getenv("TEST_DATABASE_URL") + if dsn == "" { + t.Skip("set TEST_DATABASE_URL for export lifecycle checks") + } + ctx := context.Background() + admin, err := pgxpool.New(ctx, dsn) + check(t, err) + schema := fmt.Sprintf("export_service_test_%d", time.Now().UnixNano()) + quoted := pgx.Identifier{schema}.Sanitize() + _, err = admin.Exec(ctx, "CREATE SCHEMA "+quoted) + check(t, err) + t.Cleanup(func() { + _, err := admin.Exec(ctx, "DROP SCHEMA "+quoted+" CASCADE") + if err != nil { + t.Error(err) + } + admin.Close() + }) + config, err := pgxpool.ParseConfig(dsn) + check(t, err) + config.ConnConfig.RuntimeParams["search_path"] = schema + config.ConnConfig.RuntimeParams["timezone"] = "UTC" + pool, err := pgxpool.NewWithConfig(ctx, config) + check(t, err) + t.Cleanup(pool.Close) + migrations, err := filepath.Glob("../../../migrations/*.sql") + check(t, err) + for _, name := range migrations { + raw, err := os.ReadFile(name) + check(t, err) + _, err = pool.Exec(ctx, strings.Split(string(raw), "-- +goose Down")[0]) + if err != nil { + t.Fatalf("migration %s: %v", name, err) + } + } + f := serviceFixture{ + pool: pool, + repo: game_exports_repo.NewGameExportsRepo(pool), + codec: game_package_service.NewGamePackageService("https://files.example/api/files/"), + games: games_repo.NewGamesRepo(pool), + teams: teams_repo.NewTeamsRepo(pool), + scenarios: scenarios_repo.NewScenariosRepo(pool), + media: []byte("\x89PNG\r\n\x1a\noriginal-image"), + } + f.userID, err = users_repo.NewUserRepo(pool).AddUserWithAgreements(ctx, "organizer", "export@test.invalid", "hash", []string{"organizer"}, + []user_agreements_repo.Agreement{{AgreementType: "terms", Version: "test"}}) + check(t, err) + f.scenarioID, err = f.scenarios.AddScenario(ctx, "Saved story", f.userID) + check(t, err) + check(t, f.scenarios.UpdateStoryByScenarioID(ctx, f.scenarioID, + `{"background":"original.png","introduction":{"text":"Saved intro"},"questions":[{"code":"q","text":"Who?","answer":"Butler"}]}`)) + f.gameID, err = f.games.AddGame(ctx, "Test game", "Description", nil, time.Now().Add(48*time.Hour), int32(f.scenarioID), "offline") + check(t, err) + f.teamID, err = f.teams.AddTeam(ctx, f.userID, f.gameID, "Original team", "original-qr") + check(t, err) + hash := sha256.Sum256([]byte("ticket")) + _, err = tickets_repo.New(pool).CreateBatch(ctx, f.gameID, [][]byte{hash[:]}) + check(t, err) + return f +} + +func check(t *testing.T, err error) { + t.Helper() + if err != nil { + t.Fatal(err) + } +} + +func (f serviceFixture) service(storage file_storage.IStreamStorage) *game_export_service.GameExportService { + return game_export_service.NewGameExportService(f.repo, f.codec, storage, func(ctx context.Context, key string) (io.ReadCloser, error) { + if key != "original.png" { + return nil, file_storage.ErrFileNotFound + } + return io.NopCloser(bytes.NewReader(f.media)), nil + }, "https://game.example", false) +} + +func download(t *testing.T, service *game_export_service.GameExportService, gameID int) (*game_export_service.GameExport, []byte) { + t.Helper() + info, body, err := service.OpenDownload(context.Background(), gameID) + check(t, err) + defer func() { _ = body.Close() }() + data, err := io.ReadAll(body) + check(t, err) + return info, data +} + +func verifyPackage(t *testing.T, f serviceFixture, service *game_export_service.GameExportService) []byte { + t.Helper() + info, data := download(t, service, f.gameID) + digest := sha256.Sum256(data) + if info.Size != int64(len(data)) || info.SHA256 != hex.EncodeToString(digest[:]) { + t.Fatal("incorrect archive size or digest") + } + bundle, err := f.codec.Unpack(context.Background(), bytes.NewReader(data), int64(len(data)), t.TempDir()) + check(t, err) + defer func() { _ = os.RemoveAll(bundle.Dir) }() + if bundle.Manifest.PackageID != info.PackageID || bundle.Data.Teams[0].Password != "original-qr" || + len(bundle.Data.Tickets) != 1 || bundle.Data.Scenario.Story.Introduction.Text != "Saved intro" { + t.Fatal("package lost saved snapshot or actual manifest ID") + } + return data +} + +func TestExportBuildsSavedSnapshotAcrossWorkerRestart(t *testing.T) { + for _, tc := range []struct{ name string }{{"snapshot, durable bytes and abort"}} { + t.Run(tc.name, func(t *testing.T) { + f := newServiceFixture(t) + storage := &memoryStorage{objects: map[string][]byte{}} + firstWorker := f.service(storage) + original, err := firstWorker.Start(context.Background(), f.gameID, f.userID) + check(t, err) + _, _, err = firstWorker.OpenDownload(context.Background(), f.gameID) + if !errors.Is(err, game_export_service.ErrNotReady) { + t.Fatal("preparing archive downloadable") + } + check(t, f.scenarios.UpdateStoryByScenarioID(context.Background(), f.scenarioID, + `{"introduction":{"text":"Changed after snapshot"}}`)) + restartedWorker := f.service(storage) + worked, err := restartedWorker.ProcessNext(context.Background()) + check(t, err) + if !worked { + t.Fatal("pending export lost on restart") + } + first := verifyPackage(t, f, restartedWorker) + verifyExportedGameReads(t, f, restartedWorker, original.ID) + repeated, err := restartedWorker.Start(context.Background(), f.gameID, f.userID) + check(t, err) + if repeated.ID != original.ID || repeated.State != "ready" { + t.Fatal("ready export not idempotent") + } + _, second := download(t, f.service(storage), f.gameID) + if !bytes.Equal(first, second) { + t.Fatal("download changed after restart") + } + assertAbortedDownload(t, f, restartedWorker, first) + }) + } +} + +func assertAbortedDownload(t *testing.T, f serviceFixture, service *game_export_service.GameExportService, original []byte) { + t.Helper() + jwt := processor_jwt.NewProcessor("export-test-secret") + token, err := jwt.GenerateAccessToken(f.userID, "organizer@test.invalid", []string{"organizer"}) + check(t, err) + mux := http.NewServeMux() + mux.Handle("GET /api/games/{id}/export/download", app.GameExportDownloadHandler(jwt, service)) + server := httptest.NewServer(mux) + defer server.Close() + request := func() *http.Request { + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/api/games/%d/export/download", server.URL, f.gameID), nil) + check(t, err) + req.Header.Set("Authorization", "Bearer "+token) + return req + } + interrupted, err := server.Client().Do(request()) + check(t, err) + var prefix [16]byte + _, err = io.ReadFull(interrupted.Body, prefix[:]) + check(t, err) + check(t, interrupted.Body.Close()) + info, err := service.Get(context.Background(), f.gameID) + check(t, err) + if info.State != "ready" { + t.Fatal("download abort changed export state") + } + check(t, f.teams.UpdateTeam(context.Background(), f.teamID, "Online edit after download abort")) + response, err := server.Client().Do(request()) + check(t, err) + defer func() { _ = response.Body.Close() }() + data, err := io.ReadAll(response.Body) + check(t, err) + if response.StatusCode != http.StatusOK || !bytes.Equal(data, original) || response.Header.Get("Content-Type") != "application/zip" || + response.Header.Get("Content-Length") != fmt.Sprint(len(original)) { + t.Fatal("streamed repeat download differs") + } +} + +func TestExportFailureUnlocksAndRetriesWithNewSnapshot(t *testing.T) { + for _, tc := range []struct { + name string + missingMedia, failedUpload bool + }{ + {"unavailable media", true, false}, + {"partial upload", false, true}, + } { + t.Run(tc.name, func(t *testing.T) { + f := newServiceFixture(t) + storage := &memoryStorage{objects: map[string][]byte{}} + if tc.failedUpload { + storage.uploadErr = errors.New("private S3 endpoint secret detail") + } + worker := f.service(storage) + if tc.missingMedia { + worker = game_export_service.NewGameExportService(f.repo, f.codec, storage, + func(context.Context, string) (io.ReadCloser, error) { return nil, errors.New("private media path") }, "https://game.example", false) + } + attempt, err := worker.Start(context.Background(), f.gameID, f.userID) + check(t, err) + worked, err := worker.ProcessNext(context.Background()) + if !worked || err == nil { + t.Fatal("build failure ignored") + } + failed, err := worker.Get(context.Background(), f.gameID) + check(t, err) + if failed.State != "failed" || strings.Contains(failed.Failure, "private") || len(storage.objects) != 0 { + t.Fatalf("unsafe or incomplete failure: %+v", failed) + } + + orphanDir, err := os.MkdirTemp("", "game-export-"+attempt.ID+"-") + check(t, err) + defer func() { _ = os.RemoveAll(orphanDir) }() + check(t, os.WriteFile(filepath.Join(orphanDir, "partial.zip"), []byte("partial"), 0600)) + storage.objects[attempt.ID+".zip"] = []byte("leftover upload") + check(t, worker.Maintain(context.Background())) + if _, err := os.Stat(orphanDir); !errors.Is(err, os.ErrNotExist) || len(storage.objects) != 0 { + t.Fatal("restart cleanup left temporary files or incomplete objects") + } + check(t, f.teams.UpdateTeam(context.Background(), f.teamID, "Changed for retry")) + storage.uploadErr = nil + worker = f.service(storage) + retry, err := worker.Start(context.Background(), f.gameID, f.userID) + check(t, err) + if retry.ID == attempt.ID { + t.Fatal("failed attempt reused") + } + worked, err = worker.ProcessNext(context.Background()) + check(t, err) + if !worked { + t.Fatal("retry not claimed") + } + _, data := download(t, worker, f.gameID) + bundle, err := f.codec.Unpack(context.Background(), bytes.NewReader(data), int64(len(data)), t.TempDir()) + check(t, err) + defer func() { _ = os.RemoveAll(bundle.Dir) }() + if bundle.Data.Teams[0].Name != "Changed for retry" { + t.Fatal("retry reused original snapshot") + } + }) + } +} + +type ambiguousCommitRepo struct { + *game_exports_repo.GameExportsRepo +} + +func (r ambiguousCommitRepo) Complete(ctx context.Context, id, owner, packageID, digest string, size int64) error { + if err := r.GameExportsRepo.Complete(ctx, id, owner, packageID, digest, size); err != nil { + return err + } + return errors.New("connection lost after commit") +} + +func TestAmbiguousPublicationPreservesReadyObject(t *testing.T) { + for _, tc := range []struct{ name string }{{"commit succeeds but connection fails"}} { + t.Run(tc.name, func(t *testing.T) { + f := newServiceFixture(t) + storage := &memoryStorage{objects: map[string][]byte{}} + worker := game_export_service.NewGameExportService(ambiguousCommitRepo{f.repo}, f.codec, storage, + func(context.Context, string) (io.ReadCloser, error) { + return io.NopCloser(bytes.NewReader(f.media)), nil + }, "https://game.example", false) + _, err := worker.Start(context.Background(), f.gameID, f.userID) + check(t, err) + _, err = worker.ProcessNext(context.Background()) + if err == nil { + t.Fatal("ambiguous commit ignored") + } + info, data := download(t, worker, f.gameID) + if info.State != "ready" || len(data) == 0 || storage.deletes != 0 { + t.Fatal("worker deleted published object") + } + check(t, worker.Maintain(context.Background())) + _, repeated := download(t, worker, f.gameID) + if !bytes.Equal(data, repeated) { + t.Fatal("cleanup deleted ready object") + } + }) + } +} + +func verifyExportedGameReads(t *testing.T, f serviceFixture, worker *game_export_service.GameExportService, attemptID string) { + t.Helper() + games := game_service.NewGameService(f.games, f.teams, f.scenarios, nil, "", actions_repo.NewActionsRepo(f.pool), applications_repo.NewApplicationsRepo(f.pool)) + mapRepo := game_map_repo.NewGameMapRepo(f.pool) + server := app.NewServer(nil, nil, nil, nil, games, nil, nil, nil, nil, nil, nil, + screen_service.NewScreenService(screen_sessions_repo.NewScreenSessionsRepo(f.pool)), nil, nil, map_service.NewMapService(mapRepo), nil, worker) + ctx := processor_jwt.ContextWithClaims(context.Background(), &processor_jwt.JWTClaims{UserID: f.userID, Roles: []string{"organizer"}}) + game, err := server.GetGame(ctx, &proto.GetGameReq{ID: int32(f.gameID)}) + check(t, err) + if game.Game.Export == nil || game.Game.Export.ID != attemptID || game.Game.Export.State != "ready" { + t.Fatal("game state lost export status") + } + items, err := server.GetGameMap(ctx, &proto.GetGameMapReq{GameID: int32(f.gameID)}) + check(t, err) + stored, err := mapRepo.List(ctx, f.gameID) + check(t, err) + if len(stored) != 2 || len(items.Items) != 2 { + t.Fatal("export status prevented normal map housekeeping") + } +} diff --git a/internal/services/game_export_service/model.go b/internal/services/game_export_service/model.go new file mode 100644 index 0000000..b7859a1 --- /dev/null +++ b/internal/services/game_export_service/model.go @@ -0,0 +1,30 @@ +package game_export_service + +import ( + "context" + "evening_detective_server/internal/repos" + "evening_detective_server/internal/repos/game_exports_repo" +) + +// GameExport is the public status shared with game reads. +type GameExport = repos.GameExport + +var ( + ErrGameNotFound = game_exports_repo.ErrGameNotFound + ErrExportNotFound = game_exports_repo.ErrExportNotFound + ErrNotExportable = game_exports_repo.ErrNotExportable +) + +// IGameExportsRepo is the worker's persistence boundary, including publication fencing. +type IGameExportsRepo interface { + Start(context.Context, int, int, string, string) (*game_exports_repo.Attempt, error) + Get(context.Context, int) (*game_exports_repo.Attempt, error) + Claim(context.Context, string) (*game_exports_repo.Attempt, error) + Heartbeat(context.Context, string, string) error + Complete(context.Context, string, string, string, string, int64) error + Fail(context.Context, string, string, string) error + Expire(context.Context) error + CleanupKeys(context.Context) ([]string, error) + MarkCleaned(context.Context, string) error + IsInactive(context.Context, string) (bool, error) +} diff --git a/internal/services/game_export_service/rustfs_test.go b/internal/services/game_export_service/rustfs_test.go new file mode 100644 index 0000000..324627b --- /dev/null +++ b/internal/services/game_export_service/rustfs_test.go @@ -0,0 +1,100 @@ +package game_export_service_test + +import ( + "bytes" + "context" + "crypto/rand" + "fmt" + "net/http" + "os" + "testing" + "time" + + "evening_detective_server/internal/modules/file_storage" + "github.com/kzzan/s3kit" +) + +func TestExportRustFSPrivateStreamingAndRestart(t *testing.T) { + for _, tc := range []struct{ name string }{{"private ZIP survives storage and worker restart"}} { + t.Run(tc.name, func(t *testing.T) { + endpoint := os.Getenv("TEST_S3_ENDPOINT") + if endpoint == "" { + t.Skip("set TEST_S3_ENDPOINT, TEST_S3_USER and TEST_S3_PASSWORD for isolated RustFS checks") + } + user, password := os.Getenv("TEST_S3_USER"), os.Getenv("TEST_S3_PASSWORD") + f := newServiceFixture(t) + // An incompressible image makes the real HTTP abort happen during streaming. + f.media = make([]byte, 2<<20) + _, err := rand.Read(f.media) + check(t, err) + copy(f.media, []byte("\x89PNG\r\n\x1a\n")) + bucket := fmt.Sprintf("ed029-export-test-%d", time.Now().UnixNano()) + ctx := context.Background() + storage, err := file_storage.NewPrivateRustFSStorage(ctx, endpoint, user, password, bucket) + check(t, err) + client, err := s3kit.New(s3kit.Config{Endpoint: endpoint, AccessKeyID: user, SecretAccessKey: password, Region: "ru-1"}) + check(t, err) + var key string + t.Cleanup(func() { + if key != "" { + if err := storage.Delete(ctx, key); err != nil { + t.Error(err) + } + } + if err := client.DeleteBucket(ctx, bucket); err != nil { + t.Error(err) + } + }) + worker := f.service(storage) + attempt, err := worker.Start(ctx, f.gameID, f.userID) + check(t, err) + key = attempt.ID + ".zip" + worked, err := worker.ProcessNext(ctx) + check(t, err) + if !worked { + t.Fatal("RustFS build not processed") + } + original := verifyPackage(t, f, worker) + assertAbortedDownload(t, f, worker, original) + anonymous, err := http.Get(endpoint + "/" + bucket + "/" + key) + check(t, err) + check(t, anonymous.Body.Close()) + if anonymous.StatusCode != http.StatusForbidden && anonymous.StatusCode != http.StatusNotFound { + t.Fatalf("private package anonymously readable: %d", anonymous.StatusCode) + } + waitForStorageRestart(t) + restartedStorage, err := file_storage.NewPrivateRustFSStorage(ctx, endpoint, user, password, bucket) + check(t, err) + restartedWorker := f.service(restartedStorage) + _, repeated := download(t, restartedWorker, f.gameID) + if !bytes.Equal(original, repeated) { + t.Fatal("RustFS restart changed or lost package") + } + ready, err := restartedWorker.Start(ctx, f.gameID, f.userID) + check(t, err) + if ready.ID != attempt.ID || ready.State != "ready" { + t.Fatal("restart rebuilt ready package") + } + }) + } +} + +// The external test harness may restart only the isolated RustFS container while this schema stays alive. +func waitForStorageRestart(t *testing.T) { + t.Helper() + marker := os.Getenv("TEST_S3_RESTART_MARKER") + if marker == "" { + return + } + _ = os.Remove(marker + ".continue") + check(t, os.WriteFile(marker, []byte("ready"), 0600)) + defer func() { _ = os.Remove(marker); _ = os.Remove(marker + ".continue") }() + deadline := time.Now().Add(3 * time.Minute) + for time.Now().Before(deadline) { + if _, err := os.Stat(marker + ".continue"); err == nil { + return + } + time.Sleep(100 * time.Millisecond) + } + t.Fatal("isolated storage restart was not completed within three minutes") +} diff --git a/internal/services/game_export_service/service.go b/internal/services/game_export_service/service.go new file mode 100644 index 0000000..90ffe50 --- /dev/null +++ b/internal/services/game_export_service/service.go @@ -0,0 +1,333 @@ +// Package game_export_service prepares durable, private game packages in online mode. +package game_export_service + +import ( + "archive/zip" + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io" + "log" + "os" + "path/filepath" + "strings" + "time" + + "evening_detective_server/internal/modules/file_storage" + "evening_detective_server/internal/repos" + "evening_detective_server/internal/repos/game_exports_repo" + "evening_detective_server/internal/services/game_package_service" + "github.com/jackc/pgx/v5" +) + +var ( + ErrVenueMode = errors.New("экспорт игры доступен только на онлайн-сервере") + ErrNotReady = errors.New("пакет игры ещё не готов") + ErrInvalidGameID = errors.New("некорректный идентификатор игры") +) + +type GameExportService struct { + repo IGameExportsRepo + codec *game_package_service.GamePackageService + storage file_storage.IStreamStorage + openMedia game_package_service.OpenLocalFile + source string + venue bool +} + +func NewGameExportService(repo IGameExportsRepo, codec *game_package_service.GamePackageService, + storage file_storage.IStreamStorage, openMedia game_package_service.OpenLocalFile, source string, venue bool) *GameExportService { + return &GameExportService{ + repo: repo, + codec: codec, + storage: storage, + openMedia: openMedia, + source: source, + venue: venue, + } +} + +func (s *GameExportService) Start(ctx context.Context, gameID, userID int) (*repos.GameExport, error) { + if s.venue { + return nil, ErrVenueMode + } + if gameID <= 0 { + return nil, ErrInvalidGameID + } + id, err := file_storage.NewName() + if err != nil { + return nil, err + } + attempt, err := s.repo.Start(ctx, gameID, userID, id, s.source) + if err != nil { + return nil, err + } + return &attempt.GameExport, nil +} + +func (s *GameExportService) Get(ctx context.Context, gameID int) (*repos.GameExport, error) { + if s.venue { + return nil, ErrVenueMode + } + if gameID <= 0 { + return nil, ErrInvalidGameID + } + attempt, err := s.repo.Get(ctx, gameID) + if err != nil { + return nil, err + } + return &attempt.GameExport, nil +} + +// OpenDownload always opens the same stored bytes and never changes game or export state. +func (s *GameExportService) OpenDownload(ctx context.Context, gameID int) (*repos.GameExport, io.ReadCloser, error) { + if s.venue { + return nil, nil, ErrVenueMode + } + if gameID <= 0 { + return nil, nil, ErrInvalidGameID + } + attempt, err := s.repo.Get(ctx, gameID) + if err != nil { + return nil, nil, err + } + if attempt.State != "ready" { + return nil, nil, ErrNotReady + } + body, err := s.storage.Open(ctx, attempt.ObjectKey) + if err != nil { + return nil, nil, err + } + return &attempt.GameExport, body, nil +} + +// Run owns no in-memory queue. Restart recovery and cleanup are driven by PostgreSQL. +func (s *GameExportService) Run(ctx context.Context) { + if s.venue { + return + } + maintenanceCtx, stop := context.WithCancel(ctx) + defer stop() + go func() { + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + for { + if err := s.Maintain(maintenanceCtx); err != nil && maintenanceCtx.Err() == nil { + log.Printf("game export recovery: %v", err) + } + select { + case <-maintenanceCtx.Done(): + return + case <-ticker.C: + } + } + }() + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + for ctx.Err() == nil { + worked, err := s.ProcessNext(ctx) + if err != nil && ctx.Err() == nil { + log.Printf("game export worker: %v", err) + } + if worked { + continue + } + select { + case <-ctx.Done(): + return + case <-ticker.C: + } + } +} + +// Maintain fails expired attempts before cleaning their private objects. +func (s *GameExportService) Maintain(ctx context.Context) error { + if s.venue { + return ErrVenueMode + } + if err := s.repo.Expire(ctx); err != nil { + return err + } + keys, err := s.repo.CleanupKeys(ctx) + if err != nil { + return err + } + for _, key := range keys { + if err := s.storage.Delete(ctx, key); err != nil { + return err + } + if err := s.repo.MarkCleaned(ctx, key); err != nil { + return err + } + } + return s.cleanTemporaryFiles(ctx) +} + +// ProcessNext processes at most one attempt; publication is fenced even after an upload succeeds. +func (s *GameExportService) ProcessNext(ctx context.Context) (bool, error) { + if s.venue { + return false, ErrVenueMode + } + owner, err := file_storage.NewName() + if err != nil { + return false, err + } + attempt, err := s.repo.Claim(ctx, owner) + if errors.Is(err, pgx.ErrNoRows) { + return false, nil + } + if err != nil { + return false, err + } + buildCtx, cancel := context.WithDeadline(ctx, attempt.CreatedAt.Add(game_exports_repo.PrepareTimeout)) + done := make(chan struct{}) + go func() { + defer close(done) + ticker := time.NewTicker(30 * time.Second) + defer ticker.Stop() + for { + select { + case <-buildCtx.Done(): + return + case <-ticker.C: + if err := s.repo.Heartbeat(buildCtx, attempt.ID, owner); err != nil { + cancel() + return + } + } + } + }() + err = s.prepare(buildCtx, attempt, owner) + cancel() + <-done + if err == nil { + return true, nil + } + // Cleanup uses a fresh bounded context even when preparation was cancelled. + cleanupCtx, cleanupCancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cleanupCancel() + failErr := s.repo.Fail(cleanupCtx, attempt.ID, owner, safeFailure(err)) + var deleteErr error + if failErr == nil { + deleteErr = s.storage.Delete(cleanupCtx, attempt.ObjectKey) + } + if errors.Is(failErr, game_exports_repo.ErrOwnershipLost) { + failErr = nil + } + return true, errors.Join(err, failErr, deleteErr) +} + +func (s *GameExportService) prepare(ctx context.Context, attempt *game_exports_repo.Attempt, owner string) error { + snapshot, err := mapSnapshot(attempt) + if err != nil { + return err + } + dir, err := os.MkdirTemp("", "game-export-"+attempt.ID+"-") + if err != nil { + return err + } + defer func() { _ = os.RemoveAll(dir) }() + file, err := os.CreateTemp(dir, "archive-*.zip") + if err != nil { + return err + } + defer func() { _ = file.Close(); _ = os.Remove(file.Name()) }() + digest := sha256.New() + if err := s.codec.PackInDirectory(ctx, snapshot, s.openMedia, io.MultiWriter(file, digest), dir); err != nil { + return err + } + info, err := file.Stat() + if err != nil { + return err + } + packageID, err := readPackageID(file, info.Size()) + if err != nil { + return err + } + if err := s.repo.Heartbeat(ctx, attempt.ID, owner); err != nil { + return err + } + if _, err := file.Seek(0, io.SeekStart); err != nil { + return err + } + if err := s.storage.PutStream(ctx, attempt.ObjectKey, file, "application/zip"); err != nil { + return err + } + if err := ctx.Err(); err != nil { + return err + } + return s.repo.Complete(ctx, attempt.ID, owner, packageID, hex.EncodeToString(digest.Sum(nil)), info.Size()) +} + +func readPackageID(file *os.File, size int64) (string, error) { + archive, err := zip.NewReader(file, size) + if err != nil { + return "", err + } + for _, entry := range archive.File { + if entry.Name != "manifest.json" { + continue + } + reader, err := entry.Open() + if err != nil { + return "", err + } + defer func() { _ = reader.Close() }() + var manifest game_package_service.Manifest + if err := json.NewDecoder(io.LimitReader(reader, game_package_service.MaxJSONSize)).Decode(&manifest); err != nil { + return "", err + } + if manifest.PackageID == "" { + return "", fmt.Errorf("empty package ID") + } + return manifest.PackageID, nil + } + return "", fmt.Errorf("package manifest missing") +} + +func safeFailure(err error) string { + switch { + case errors.Is(err, game_package_service.ErrMediaUnavailable), errors.Is(err, game_package_service.ErrUnsafeURL): + return "Не удалось получить медиафайлы игры. Проверьте их доступность и повторите экспорт." + case errors.Is(err, game_package_service.ErrLimitExceeded): + return "Пакет игры превышает допустимый размер." + case errors.Is(err, game_package_service.ErrInvalidPackage): + return "Данные игры не подходят для автономного пакета." + default: + return "Не удалось подготовить пакет. Запустите экспорт повторно." + } +} + +func (s *GameExportService) cleanTemporaryFiles(ctx context.Context) error { + entries, err := os.ReadDir(os.TempDir()) + if err != nil { + return err + } + for _, entry := range entries { + name := entry.Name() + if !entry.IsDir() || !strings.HasPrefix(name, "game-export-") { + continue + } + suffix := strings.TrimPrefix(name, "game-export-") + if len(suffix) < 34 || suffix[32] != '-' { + continue + } + id := suffix[:32] + if raw, err := hex.DecodeString(id); err != nil || len(raw) != 16 { + continue + } + inactive, err := s.repo.IsInactive(ctx, id) + if err != nil { + return err + } + if inactive { + if err := os.RemoveAll(filepath.Join(os.TempDir(), name)); err != nil { + return err + } + } + } + return ctx.Err() +} diff --git a/internal/services/game_model/game.go b/internal/services/game_model/game.go index 483f23e..3991ec0 100644 --- a/internal/services/game_model/game.go +++ b/internal/services/game_model/game.go @@ -2,12 +2,14 @@ package game_model import ( + "evening_detective_server/internal/repos" "evening_detective_server/internal/services/scenarios_service" "time" ) // Game describes a game exposed by the service layer. type Game struct { + Export *repos.GameExport Format string ID int Name string diff --git a/internal/services/game_model/game_mapper.go b/internal/services/game_model/game_mapper.go index 5c2101f..ad9a77f 100644 --- a/internal/services/game_model/game_mapper.go +++ b/internal/services/game_model/game_mapper.go @@ -12,6 +12,7 @@ func MapGame( ) *Game { return &Game{ ID: o.ID, + Export: o.Export, Name: o.Name, Description: o.Description, Location: o.Location, diff --git a/internal/services/game_package_service/service.go b/internal/services/game_package_service/service.go index 1e95696..26d4059 100644 --- a/internal/services/game_package_service/service.go +++ b/internal/services/game_package_service/service.go @@ -51,6 +51,11 @@ func NewGamePackageService(fileDomain string) *GamePackageService { // Pack stages the complete archive before writing it. The caller discards output on error. // Snapshot IDs and secrets are preserved; the input snapshot is never mutated. func (s *GamePackageService) Pack(ctx context.Context, snapshot *Snapshot, openLocal OpenLocalFile, output io.Writer) error { + return s.PackInDirectory(ctx, snapshot, openLocal, output, "") +} + +// PackInDirectory puts staging files under the export's owned temporary directory. +func (s *GamePackageService) PackInDirectory(ctx context.Context, snapshot *Snapshot, openLocal OpenLocalFile, output io.Writer, tempRoot string) error { if err := ctx.Err(); err != nil { return err } @@ -68,7 +73,7 @@ func (s *GamePackageService) Pack(ctx context.Context, snapshot *Snapshot, openL if err := validateData(data); err != nil { return err } - dir, err := os.MkdirTemp("", "game-package-pack-") + dir, err := os.MkdirTemp(tempRoot, "game-package-pack-") if err != nil { return err } diff --git a/internal/services/game_service/lifecycle_test.go b/internal/services/game_service/lifecycle_test.go index e4c8e3a..d9890ad 100644 --- a/internal/services/game_service/lifecycle_test.go +++ b/internal/services/game_service/lifecycle_test.go @@ -46,7 +46,8 @@ func TestServicesLifecyclePostgres(t *testing.T) { defer pool.Close() _, err = pool.Exec(ctx, ` CREATE TEMP TABLE users(id INT, username TEXT); - CREATE TEMP TABLE scenarios(id INT PRIMARY KEY, name TEXT, description TEXT, image TEXT, scenario TEXT, + CREATE TEMP TABLE game_exports(id TEXT, game_id INT, state TEXT, package_id TEXT, size BIGINT, sha256 TEXT, failure TEXT, created_at TIMESTAMPTZ); + CREATE TEMP TABLE scenarios(id INT PRIMARY KEY, playlist_id INT, name TEXT, description TEXT, image TEXT, scenario TEXT, author_id INT, status TEXT DEFAULT 'draft', updated_at TIMESTAMP DEFAULT NOW(), created_at TIMESTAMP DEFAULT NOW(), published_at TIMESTAMP, is_deleted BOOLEAN DEFAULT FALSE); CREATE TEMP TABLE games(id SERIAL PRIMARY KEY, name TEXT, description TEXT, location TEXT, start_at TIMESTAMP, scenario_id INT, format TEXT, status TEXT DEFAULT 'draft', started_at TIMESTAMP, ended_at TIMESTAMP, updated_at TIMESTAMP DEFAULT NOW(), created_at TIMESTAMP DEFAULT NOW()); diff --git a/internal/services/gameplay_service/finished_story_test.go b/internal/services/gameplay_service/finished_story_test.go index 7dc7c41..141cdd9 100644 --- a/internal/services/gameplay_service/finished_story_test.go +++ b/internal/services/gameplay_service/finished_story_test.go @@ -30,6 +30,7 @@ func TestFinishedTeamStoryPostgres(t *testing.T) { } defer pool.Close() _, err = pool.Exec(ctx, ` + CREATE TEMP TABLE game_exports(id TEXT, game_id INT, state TEXT, package_id TEXT, size BIGINT, sha256 TEXT, failure TEXT, created_at TIMESTAMPTZ); CREATE TEMP TABLE games (id INT, name TEXT, description TEXT, location TEXT, start_at TIMESTAMP, format TEXT, status TEXT, scenario_id INT, started_at TIMESTAMP, ended_at TIMESTAMP); CREATE TEMP TABLE teams (id INT, name TEXT, captain_email TEXT, participants_count INT, @@ -55,7 +56,7 @@ func TestFinishedTeamStoryPostgres(t *testing.T) { t.Fatalf("finished game exposed content or lost status: story=%+v game=%+v actions=%+v", story, game, actions) } } - if _, _, _, err := s.GetTeamActions(ctx, 1, "wrong"); !errors.Is(err, teams_repo.ErrTeamNotFound) { + if _, _, _, err := s.GetTeamActions(ctx, 1, "wrong"); !errors.Is(err, ErrTeamNotFound) { t.Fatalf("password check bypassed: %v", err) } } diff --git a/internal/services/participation_service/participation_test.go b/internal/services/participation_service/participation_test.go index 0087eaa..1c76161 100644 --- a/internal/services/participation_service/participation_test.go +++ b/internal/services/participation_service/participation_test.go @@ -78,7 +78,8 @@ func TestParticipationPostgres(t *testing.T) { t.Fatal(err) } } - exec(`CREATE TABLE games(id SERIAL PRIMARY KEY,name TEXT DEFAULT 'Game',start_at TIMESTAMP NOT NULL,status TEXT DEFAULT 'draft'); + exec(`CREATE TABLE game_exports(game_id INT, state TEXT); + CREATE TABLE games(id SERIAL PRIMARY KEY,name TEXT DEFAULT 'Game',start_at TIMESTAMP NOT NULL,status TEXT DEFAULT 'draft'); CREATE TABLE teams(id SERIAL PRIMARY KEY,name TEXT DEFAULT 'Team',creator_id INTEGER,game_id INTEGER REFERENCES games(id),password TEXT DEFAULT 'secret',status TEXT DEFAULT 'register',created_at TIMESTAMP DEFAULT (NOW() AT TIME ZONE 'UTC')); INSERT INTO games(start_at) VALUES((NOW() AT TIME ZONE 'UTC')+INTERVAL '12 hours'),((NOW() AT TIME ZONE 'UTC')+INTERVAL '2 days'); INSERT INTO teams(game_id,created_at) VALUES(1,(NOW() AT TIME ZONE 'UTC')-INTERVAL '2 days'),(1,(NOW() AT TIME ZONE 'UTC')-INTERVAL '1 hour');`) @@ -221,14 +222,14 @@ func TestParticipationPostgres(t *testing.T) { } } gameplayService := gameplay_service.NewGameplayService(nil, repo, nil, nil, nil, nil, nil, "") - if _, _, _, err := gameplayService.GetTeamActions(ctx, 3, "secret"); !errors.Is(err, teams_repo.ErrTeamNotFound) { + if _, _, _, err := gameplayService.GetTeamActions(ctx, 3, "secret"); !errors.Is(err, gameplay_service.ErrTeamNotFound) { t.Fatalf("cancelled team got story: %v", err) } - if err := gameplayService.AddTeamAction(ctx, 3, "secret", "anything", false); !errors.Is(err, teams_repo.ErrTeamNotFound) { + if err := gameplayService.AddTeamAction(ctx, 3, "secret", "anything", false); !errors.Is(err, gameplay_service.ErrTeamNotFound) { t.Fatalf("cancelled team added action: %v", err) } answerService := answer_service.NewAnswerService(nil, repo, nil, nil, nil) - if _, err := answerService.GetTeamAnswers(ctx, 3, "secret"); !errors.Is(err, teams_repo.ErrTeamNotFound) { + if _, err := answerService.GetTeamAnswers(ctx, 3, "secret"); !errors.Is(err, answer_service.ErrTeamNotFound) { t.Fatalf("cancelled team got answers: %v", err) } token6 := participationToken("secret", 6) diff --git a/migrations/20261010180000_create_game_exports.sql b/migrations/20261010180000_create_game_exports.sql new file mode 100644 index 0000000..8805012 --- /dev/null +++ b/migrations/20261010180000_create_game_exports.sql @@ -0,0 +1,25 @@ +-- +goose Up +CREATE TABLE game_exports ( + id TEXT PRIMARY KEY, + game_id INTEGER REFERENCES games(id) ON DELETE SET NULL, + initiator_id INTEGER REFERENCES users(id) ON DELETE SET NULL, + state TEXT NOT NULL DEFAULT 'preparing' CHECK (state IN ('preparing', 'ready', 'failed')), + snapshot JSONB NOT NULL, + source_server TEXT NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(), + owner_id TEXT, + lease_until TIMESTAMPTZ, + package_id TEXT NOT NULL DEFAULT '', + size BIGINT NOT NULL DEFAULT 0, + sha256 TEXT NOT NULL DEFAULT '', + object_key TEXT NOT NULL UNIQUE, + failure TEXT NOT NULL DEFAULT '', + cleaned_at TIMESTAMPTZ, + CHECK (state <> 'ready' OR (package_id <> '' AND size > 0 AND sha256 <> '')) +); +CREATE UNIQUE INDEX game_exports_active ON game_exports(game_id) WHERE state IN ('preparing', 'ready'); +CREATE INDEX game_exports_game ON game_exports(game_id, created_at DESC); +CREATE INDEX game_exports_pending ON game_exports(created_at) WHERE state = 'preparing'; + +-- +goose Down +DROP TABLE game_exports; diff --git a/proto/main.pb.go b/proto/main.pb.go index 2faa8ea..a7548f6 100644 --- a/proto/main.pb.go +++ b/proto/main.pb.go @@ -5278,6 +5278,7 @@ type Game struct { EndedAt *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=ended_at,json=endedAt,proto3,oneof" json:"ended_at,omitempty"` Format string `protobuf:"bytes,10,opt,name=format,proto3" json:"format,omitempty"` Location string `protobuf:"bytes,11,opt,name=location,proto3" json:"location,omitempty"` + Export *GameExport `protobuf:"bytes,12,opt,name=export,proto3" json:"export,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -5389,6 +5390,231 @@ func (x *Game) GetLocation() string { return "" } +func (x *Game) GetExport() *GameExport { + if x != nil { + return x.Export + } + return nil +} + +// Download ready ZIP through the authenticated streaming HTTP route: +// GET /api/games/{ID}/export/download (not an HttpBody RPC). +type GameExport struct { + state protoimpl.MessageState `protogen:"open.v1"` + ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` + State string `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"` // preparing, ready or failed; preparing/ready lock game writes. + PackageID string `protobuf:"bytes,3,opt,name=packageID,proto3" json:"packageID,omitempty"` + Size int64 `protobuf:"varint,4,opt,name=size,proto3" json:"size,omitempty"` + Sha256 string `protobuf:"bytes,5,opt,name=sha256,proto3" json:"sha256,omitempty"` + Failure string `protobuf:"bytes,6,opt,name=failure,proto3" json:"failure,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GameExport) Reset() { + *x = GameExport{} + mi := &file_main_proto_msgTypes[105] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GameExport) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GameExport) ProtoMessage() {} + +func (x *GameExport) ProtoReflect() protoreflect.Message { + mi := &file_main_proto_msgTypes[105] + 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 GameExport.ProtoReflect.Descriptor instead. +func (*GameExport) Descriptor() ([]byte, []int) { + return file_main_proto_rawDescGZIP(), []int{105} +} + +func (x *GameExport) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *GameExport) GetState() string { + if x != nil { + return x.State + } + return "" +} + +func (x *GameExport) GetPackageID() string { + if x != nil { + return x.PackageID + } + return "" +} + +func (x *GameExport) GetSize() int64 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *GameExport) GetSha256() string { + if x != nil { + return x.Sha256 + } + return "" +} + +func (x *GameExport) GetFailure() string { + if x != nil { + return x.Failure + } + return "" +} + +type StartGameExportReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + ID int32 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StartGameExportReq) Reset() { + *x = StartGameExportReq{} + mi := &file_main_proto_msgTypes[106] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StartGameExportReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StartGameExportReq) ProtoMessage() {} + +func (x *StartGameExportReq) ProtoReflect() protoreflect.Message { + mi := &file_main_proto_msgTypes[106] + 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 StartGameExportReq.ProtoReflect.Descriptor instead. +func (*StartGameExportReq) Descriptor() ([]byte, []int) { + return file_main_proto_rawDescGZIP(), []int{106} +} + +func (x *StartGameExportReq) GetID() int32 { + if x != nil { + return x.ID + } + return 0 +} + +type GetGameExportReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + ID int32 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetGameExportReq) Reset() { + *x = GetGameExportReq{} + mi := &file_main_proto_msgTypes[107] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetGameExportReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetGameExportReq) ProtoMessage() {} + +func (x *GetGameExportReq) ProtoReflect() protoreflect.Message { + mi := &file_main_proto_msgTypes[107] + 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 GetGameExportReq.ProtoReflect.Descriptor instead. +func (*GetGameExportReq) Descriptor() ([]byte, []int) { + return file_main_proto_rawDescGZIP(), []int{107} +} + +func (x *GetGameExportReq) GetID() int32 { + if x != nil { + return x.ID + } + return 0 +} + +type GameExportRsp struct { + state protoimpl.MessageState `protogen:"open.v1"` + Export *GameExport `protobuf:"bytes,1,opt,name=export,proto3" json:"export,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GameExportRsp) Reset() { + *x = GameExportRsp{} + mi := &file_main_proto_msgTypes[108] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GameExportRsp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GameExportRsp) ProtoMessage() {} + +func (x *GameExportRsp) ProtoReflect() protoreflect.Message { + mi := &file_main_proto_msgTypes[108] + 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 GameExportRsp.ProtoReflect.Descriptor instead. +func (*GameExportRsp) Descriptor() ([]byte, []int) { + return file_main_proto_rawDescGZIP(), []int{108} +} + +func (x *GameExportRsp) GetExport() *GameExport { + if x != nil { + return x.Export + } + return nil +} + type ScreenState struct { state protoimpl.MessageState `protogen:"open.v1"` ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` @@ -5418,7 +5644,7 @@ type ScreenState struct { func (x *ScreenState) Reset() { *x = ScreenState{} - mi := &file_main_proto_msgTypes[105] + mi := &file_main_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5430,7 +5656,7 @@ func (x *ScreenState) String() string { func (*ScreenState) ProtoMessage() {} func (x *ScreenState) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[105] + mi := &file_main_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5443,7 +5669,7 @@ func (x *ScreenState) ProtoReflect() protoreflect.Message { // Deprecated: Use ScreenState.ProtoReflect.Descriptor instead. func (*ScreenState) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{105} + return file_main_proto_rawDescGZIP(), []int{109} } func (x *ScreenState) GetID() string { @@ -5601,7 +5827,7 @@ type CreateScreenSessionReq struct { func (x *CreateScreenSessionReq) Reset() { *x = CreateScreenSessionReq{} - mi := &file_main_proto_msgTypes[106] + mi := &file_main_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5613,7 +5839,7 @@ func (x *CreateScreenSessionReq) String() string { func (*CreateScreenSessionReq) ProtoMessage() {} func (x *CreateScreenSessionReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[106] + mi := &file_main_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5626,7 +5852,7 @@ func (x *CreateScreenSessionReq) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateScreenSessionReq.ProtoReflect.Descriptor instead. func (*CreateScreenSessionReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{106} + return file_main_proto_rawDescGZIP(), []int{110} } type CreateScreenSessionRsp struct { @@ -5639,7 +5865,7 @@ type CreateScreenSessionRsp struct { func (x *CreateScreenSessionRsp) Reset() { *x = CreateScreenSessionRsp{} - mi := &file_main_proto_msgTypes[107] + mi := &file_main_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5651,7 +5877,7 @@ func (x *CreateScreenSessionRsp) String() string { func (*CreateScreenSessionRsp) ProtoMessage() {} func (x *CreateScreenSessionRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[107] + mi := &file_main_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5664,7 +5890,7 @@ func (x *CreateScreenSessionRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateScreenSessionRsp.ProtoReflect.Descriptor instead. func (*CreateScreenSessionRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{107} + return file_main_proto_rawDescGZIP(), []int{111} } func (x *CreateScreenSessionRsp) GetScreenID() string { @@ -5691,7 +5917,7 @@ type GetScreenStateReq struct { func (x *GetScreenStateReq) Reset() { *x = GetScreenStateReq{} - mi := &file_main_proto_msgTypes[108] + mi := &file_main_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5703,7 +5929,7 @@ func (x *GetScreenStateReq) String() string { func (*GetScreenStateReq) ProtoMessage() {} func (x *GetScreenStateReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[108] + mi := &file_main_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5716,7 +5942,7 @@ func (x *GetScreenStateReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetScreenStateReq.ProtoReflect.Descriptor instead. func (*GetScreenStateReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{108} + return file_main_proto_rawDescGZIP(), []int{112} } func (x *GetScreenStateReq) GetScreenID() string { @@ -5742,7 +5968,7 @@ type GetScreenStateRsp struct { func (x *GetScreenStateRsp) Reset() { *x = GetScreenStateRsp{} - mi := &file_main_proto_msgTypes[109] + mi := &file_main_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5754,7 +5980,7 @@ func (x *GetScreenStateRsp) String() string { func (*GetScreenStateRsp) ProtoMessage() {} func (x *GetScreenStateRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[109] + mi := &file_main_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5767,7 +5993,7 @@ func (x *GetScreenStateRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use GetScreenStateRsp.ProtoReflect.Descriptor instead. func (*GetScreenStateRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{109} + return file_main_proto_rawDescGZIP(), []int{113} } func (x *GetScreenStateRsp) GetState() *ScreenState { @@ -5786,7 +6012,7 @@ type GetGameScreensReq struct { func (x *GetGameScreensReq) Reset() { *x = GetGameScreensReq{} - mi := &file_main_proto_msgTypes[110] + mi := &file_main_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5798,7 +6024,7 @@ func (x *GetGameScreensReq) String() string { func (*GetGameScreensReq) ProtoMessage() {} func (x *GetGameScreensReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[110] + mi := &file_main_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5811,7 +6037,7 @@ func (x *GetGameScreensReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGameScreensReq.ProtoReflect.Descriptor instead. func (*GetGameScreensReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{110} + return file_main_proto_rawDescGZIP(), []int{114} } func (x *GetGameScreensReq) GetGameID() int32 { @@ -5830,7 +6056,7 @@ type GetGameScreensRsp struct { func (x *GetGameScreensRsp) Reset() { *x = GetGameScreensRsp{} - mi := &file_main_proto_msgTypes[111] + mi := &file_main_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5842,7 +6068,7 @@ func (x *GetGameScreensRsp) String() string { func (*GetGameScreensRsp) ProtoMessage() {} func (x *GetGameScreensRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[111] + mi := &file_main_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5855,7 +6081,7 @@ func (x *GetGameScreensRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGameScreensRsp.ProtoReflect.Descriptor instead. func (*GetGameScreensRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{111} + return file_main_proto_rawDescGZIP(), []int{115} } func (x *GetGameScreensRsp) GetScreens() []*ScreenState { @@ -5880,7 +6106,7 @@ type MusicState struct { func (x *MusicState) Reset() { *x = MusicState{} - mi := &file_main_proto_msgTypes[112] + mi := &file_main_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5892,7 +6118,7 @@ func (x *MusicState) String() string { func (*MusicState) ProtoMessage() {} func (x *MusicState) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[112] + mi := &file_main_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5905,7 +6131,7 @@ func (x *MusicState) ProtoReflect() protoreflect.Message { // Deprecated: Use MusicState.ProtoReflect.Descriptor instead. func (*MusicState) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{112} + return file_main_proto_rawDescGZIP(), []int{116} } func (x *MusicState) GetPlaylist() *Playlist { @@ -5966,7 +6192,7 @@ type GetGameMusicReq struct { func (x *GetGameMusicReq) Reset() { *x = GetGameMusicReq{} - mi := &file_main_proto_msgTypes[113] + mi := &file_main_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5978,7 +6204,7 @@ func (x *GetGameMusicReq) String() string { func (*GetGameMusicReq) ProtoMessage() {} func (x *GetGameMusicReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[113] + mi := &file_main_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5991,7 +6217,7 @@ func (x *GetGameMusicReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGameMusicReq.ProtoReflect.Descriptor instead. func (*GetGameMusicReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{113} + return file_main_proto_rawDescGZIP(), []int{117} } func (x *GetGameMusicReq) GetGameID() int32 { @@ -6013,7 +6239,7 @@ type GetGameMusicRsp struct { func (x *GetGameMusicRsp) Reset() { *x = GetGameMusicRsp{} - mi := &file_main_proto_msgTypes[114] + mi := &file_main_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6025,7 +6251,7 @@ func (x *GetGameMusicRsp) String() string { func (*GetGameMusicRsp) ProtoMessage() {} func (x *GetGameMusicRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[114] + mi := &file_main_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6038,7 +6264,7 @@ func (x *GetGameMusicRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGameMusicRsp.ProtoReflect.Descriptor instead. func (*GetGameMusicRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{114} + return file_main_proto_rawDescGZIP(), []int{118} } func (x *GetGameMusicRsp) GetPlaylists() []*Playlist { @@ -6084,7 +6310,7 @@ type SetGameMusicReq struct { func (x *SetGameMusicReq) Reset() { *x = SetGameMusicReq{} - mi := &file_main_proto_msgTypes[115] + mi := &file_main_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6096,7 +6322,7 @@ func (x *SetGameMusicReq) String() string { func (*SetGameMusicReq) ProtoMessage() {} func (x *SetGameMusicReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[115] + mi := &file_main_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6109,7 +6335,7 @@ func (x *SetGameMusicReq) ProtoReflect() protoreflect.Message { // Deprecated: Use SetGameMusicReq.ProtoReflect.Descriptor instead. func (*SetGameMusicReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{115} + return file_main_proto_rawDescGZIP(), []int{119} } func (x *SetGameMusicReq) GetGameID() int32 { @@ -6170,7 +6396,7 @@ type SetGameMusicRsp struct { func (x *SetGameMusicRsp) Reset() { *x = SetGameMusicRsp{} - mi := &file_main_proto_msgTypes[116] + mi := &file_main_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6182,7 +6408,7 @@ func (x *SetGameMusicRsp) String() string { func (*SetGameMusicRsp) ProtoMessage() {} func (x *SetGameMusicRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[116] + mi := &file_main_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6195,7 +6421,7 @@ func (x *SetGameMusicRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use SetGameMusicRsp.ProtoReflect.Descriptor instead. func (*SetGameMusicRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{116} + return file_main_proto_rawDescGZIP(), []int{120} } func (x *SetGameMusicRsp) GetState() *MusicState { @@ -6215,7 +6441,7 @@ type AdvanceScreenMusicReq struct { func (x *AdvanceScreenMusicReq) Reset() { *x = AdvanceScreenMusicReq{} - mi := &file_main_proto_msgTypes[117] + mi := &file_main_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6227,7 +6453,7 @@ func (x *AdvanceScreenMusicReq) String() string { func (*AdvanceScreenMusicReq) ProtoMessage() {} func (x *AdvanceScreenMusicReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[117] + mi := &file_main_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6240,7 +6466,7 @@ func (x *AdvanceScreenMusicReq) ProtoReflect() protoreflect.Message { // Deprecated: Use AdvanceScreenMusicReq.ProtoReflect.Descriptor instead. func (*AdvanceScreenMusicReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{117} + return file_main_proto_rawDescGZIP(), []int{121} } func (x *AdvanceScreenMusicReq) GetScreenID() string { @@ -6266,7 +6492,7 @@ type AdvanceScreenMusicRsp struct { func (x *AdvanceScreenMusicRsp) Reset() { *x = AdvanceScreenMusicRsp{} - mi := &file_main_proto_msgTypes[118] + mi := &file_main_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6278,7 +6504,7 @@ func (x *AdvanceScreenMusicRsp) String() string { func (*AdvanceScreenMusicRsp) ProtoMessage() {} func (x *AdvanceScreenMusicRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[118] + mi := &file_main_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6291,7 +6517,7 @@ func (x *AdvanceScreenMusicRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use AdvanceScreenMusicRsp.ProtoReflect.Descriptor instead. func (*AdvanceScreenMusicRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{118} + return file_main_proto_rawDescGZIP(), []int{122} } func (x *AdvanceScreenMusicRsp) GetState() *MusicState { @@ -6312,7 +6538,7 @@ type BindScreenReq struct { func (x *BindScreenReq) Reset() { *x = BindScreenReq{} - mi := &file_main_proto_msgTypes[119] + mi := &file_main_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6324,7 +6550,7 @@ func (x *BindScreenReq) String() string { func (*BindScreenReq) ProtoMessage() {} func (x *BindScreenReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[119] + mi := &file_main_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6337,7 +6563,7 @@ func (x *BindScreenReq) ProtoReflect() protoreflect.Message { // Deprecated: Use BindScreenReq.ProtoReflect.Descriptor instead. func (*BindScreenReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{119} + return file_main_proto_rawDescGZIP(), []int{123} } func (x *BindScreenReq) GetScreenID() string { @@ -6370,7 +6596,7 @@ type BindScreenRsp struct { func (x *BindScreenRsp) Reset() { *x = BindScreenRsp{} - mi := &file_main_proto_msgTypes[120] + mi := &file_main_proto_msgTypes[124] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6382,7 +6608,7 @@ func (x *BindScreenRsp) String() string { func (*BindScreenRsp) ProtoMessage() {} func (x *BindScreenRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[120] + mi := &file_main_proto_msgTypes[124] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6395,7 +6621,7 @@ func (x *BindScreenRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use BindScreenRsp.ProtoReflect.Descriptor instead. func (*BindScreenRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{120} + return file_main_proto_rawDescGZIP(), []int{124} } func (x *BindScreenRsp) GetState() *ScreenState { @@ -6414,7 +6640,7 @@ type UnbindScreenReq struct { func (x *UnbindScreenReq) Reset() { *x = UnbindScreenReq{} - mi := &file_main_proto_msgTypes[121] + mi := &file_main_proto_msgTypes[125] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6426,7 +6652,7 @@ func (x *UnbindScreenReq) String() string { func (*UnbindScreenReq) ProtoMessage() {} func (x *UnbindScreenReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[121] + mi := &file_main_proto_msgTypes[125] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6439,7 +6665,7 @@ func (x *UnbindScreenReq) ProtoReflect() protoreflect.Message { // Deprecated: Use UnbindScreenReq.ProtoReflect.Descriptor instead. func (*UnbindScreenReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{121} + return file_main_proto_rawDescGZIP(), []int{125} } func (x *UnbindScreenReq) GetScreenID() string { @@ -6457,7 +6683,7 @@ type UnbindScreenRsp struct { func (x *UnbindScreenRsp) Reset() { *x = UnbindScreenRsp{} - mi := &file_main_proto_msgTypes[122] + mi := &file_main_proto_msgTypes[126] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6469,7 +6695,7 @@ func (x *UnbindScreenRsp) String() string { func (*UnbindScreenRsp) ProtoMessage() {} func (x *UnbindScreenRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[122] + mi := &file_main_proto_msgTypes[126] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6482,7 +6708,7 @@ func (x *UnbindScreenRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use UnbindScreenRsp.ProtoReflect.Descriptor instead. func (*UnbindScreenRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{122} + return file_main_proto_rawDescGZIP(), []int{126} } type SetScreenSoundReq struct { @@ -6495,7 +6721,7 @@ type SetScreenSoundReq struct { func (x *SetScreenSoundReq) Reset() { *x = SetScreenSoundReq{} - mi := &file_main_proto_msgTypes[123] + mi := &file_main_proto_msgTypes[127] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6507,7 +6733,7 @@ func (x *SetScreenSoundReq) String() string { func (*SetScreenSoundReq) ProtoMessage() {} func (x *SetScreenSoundReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[123] + mi := &file_main_proto_msgTypes[127] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6520,7 +6746,7 @@ func (x *SetScreenSoundReq) ProtoReflect() protoreflect.Message { // Deprecated: Use SetScreenSoundReq.ProtoReflect.Descriptor instead. func (*SetScreenSoundReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{123} + return file_main_proto_rawDescGZIP(), []int{127} } func (x *SetScreenSoundReq) GetScreenID() string { @@ -6545,7 +6771,7 @@ type SetScreenSoundRsp struct { func (x *SetScreenSoundRsp) Reset() { *x = SetScreenSoundRsp{} - mi := &file_main_proto_msgTypes[124] + mi := &file_main_proto_msgTypes[128] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6557,7 +6783,7 @@ func (x *SetScreenSoundRsp) String() string { func (*SetScreenSoundRsp) ProtoMessage() {} func (x *SetScreenSoundRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[124] + mi := &file_main_proto_msgTypes[128] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6570,7 +6796,7 @@ func (x *SetScreenSoundRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use SetScreenSoundRsp.ProtoReflect.Descriptor instead. func (*SetScreenSoundRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{124} + return file_main_proto_rawDescGZIP(), []int{128} } type MapItem struct { @@ -6589,7 +6815,7 @@ type MapItem struct { func (x *MapItem) Reset() { *x = MapItem{} - mi := &file_main_proto_msgTypes[125] + mi := &file_main_proto_msgTypes[129] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6601,7 +6827,7 @@ func (x *MapItem) String() string { func (*MapItem) ProtoMessage() {} func (x *MapItem) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[125] + mi := &file_main_proto_msgTypes[129] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6614,7 +6840,7 @@ func (x *MapItem) ProtoReflect() protoreflect.Message { // Deprecated: Use MapItem.ProtoReflect.Descriptor instead. func (*MapItem) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{125} + return file_main_proto_rawDescGZIP(), []int{129} } func (x *MapItem) GetKind() string { @@ -6682,7 +6908,7 @@ type GetGameMapReq struct { func (x *GetGameMapReq) Reset() { *x = GetGameMapReq{} - mi := &file_main_proto_msgTypes[126] + mi := &file_main_proto_msgTypes[130] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6694,7 +6920,7 @@ func (x *GetGameMapReq) String() string { func (*GetGameMapReq) ProtoMessage() {} func (x *GetGameMapReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[126] + mi := &file_main_proto_msgTypes[130] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6707,7 +6933,7 @@ func (x *GetGameMapReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGameMapReq.ProtoReflect.Descriptor instead. func (*GetGameMapReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{126} + return file_main_proto_rawDescGZIP(), []int{130} } func (x *GetGameMapReq) GetGameID() int32 { @@ -6726,7 +6952,7 @@ type GetGameMapRsp struct { func (x *GetGameMapRsp) Reset() { *x = GetGameMapRsp{} - mi := &file_main_proto_msgTypes[127] + mi := &file_main_proto_msgTypes[131] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6738,7 +6964,7 @@ func (x *GetGameMapRsp) String() string { func (*GetGameMapRsp) ProtoMessage() {} func (x *GetGameMapRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[127] + mi := &file_main_proto_msgTypes[131] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6751,7 +6977,7 @@ func (x *GetGameMapRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGameMapRsp.ProtoReflect.Descriptor instead. func (*GetGameMapRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{127} + return file_main_proto_rawDescGZIP(), []int{131} } func (x *GetGameMapRsp) GetItems() []*MapItem { @@ -6775,7 +7001,7 @@ type UpdateGameMapItemReq struct { func (x *UpdateGameMapItemReq) Reset() { *x = UpdateGameMapItemReq{} - mi := &file_main_proto_msgTypes[128] + mi := &file_main_proto_msgTypes[132] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6787,7 +7013,7 @@ func (x *UpdateGameMapItemReq) String() string { func (*UpdateGameMapItemReq) ProtoMessage() {} func (x *UpdateGameMapItemReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[128] + mi := &file_main_proto_msgTypes[132] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6800,7 +7026,7 @@ func (x *UpdateGameMapItemReq) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateGameMapItemReq.ProtoReflect.Descriptor instead. func (*UpdateGameMapItemReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{128} + return file_main_proto_rawDescGZIP(), []int{132} } func (x *UpdateGameMapItemReq) GetGameID() int32 { @@ -6853,7 +7079,7 @@ type UpdateGameMapItemRsp struct { func (x *UpdateGameMapItemRsp) Reset() { *x = UpdateGameMapItemRsp{} - mi := &file_main_proto_msgTypes[129] + mi := &file_main_proto_msgTypes[133] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6865,7 +7091,7 @@ func (x *UpdateGameMapItemRsp) String() string { func (*UpdateGameMapItemRsp) ProtoMessage() {} func (x *UpdateGameMapItemRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[129] + mi := &file_main_proto_msgTypes[133] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6878,7 +7104,7 @@ func (x *UpdateGameMapItemRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateGameMapItemRsp.ProtoReflect.Descriptor instead. func (*UpdateGameMapItemRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{129} + return file_main_proto_rawDescGZIP(), []int{133} } type SetScreenModeReq struct { @@ -6891,7 +7117,7 @@ type SetScreenModeReq struct { func (x *SetScreenModeReq) Reset() { *x = SetScreenModeReq{} - mi := &file_main_proto_msgTypes[130] + mi := &file_main_proto_msgTypes[134] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6903,7 +7129,7 @@ func (x *SetScreenModeReq) String() string { func (*SetScreenModeReq) ProtoMessage() {} func (x *SetScreenModeReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[130] + mi := &file_main_proto_msgTypes[134] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6916,7 +7142,7 @@ func (x *SetScreenModeReq) ProtoReflect() protoreflect.Message { // Deprecated: Use SetScreenModeReq.ProtoReflect.Descriptor instead. func (*SetScreenModeReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{130} + return file_main_proto_rawDescGZIP(), []int{134} } func (x *SetScreenModeReq) GetGameID() int32 { @@ -6941,7 +7167,7 @@ type SetScreenModeRsp struct { func (x *SetScreenModeRsp) Reset() { *x = SetScreenModeRsp{} - mi := &file_main_proto_msgTypes[131] + mi := &file_main_proto_msgTypes[135] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6953,7 +7179,7 @@ func (x *SetScreenModeRsp) String() string { func (*SetScreenModeRsp) ProtoMessage() {} func (x *SetScreenModeRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[131] + mi := &file_main_proto_msgTypes[135] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6966,7 +7192,7 @@ func (x *SetScreenModeRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use SetScreenModeRsp.ProtoReflect.Descriptor instead. func (*SetScreenModeRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{131} + return file_main_proto_rawDescGZIP(), []int{135} } type SetScreenTimerReq struct { @@ -6980,7 +7206,7 @@ type SetScreenTimerReq struct { func (x *SetScreenTimerReq) Reset() { *x = SetScreenTimerReq{} - mi := &file_main_proto_msgTypes[132] + mi := &file_main_proto_msgTypes[136] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6992,7 +7218,7 @@ func (x *SetScreenTimerReq) String() string { func (*SetScreenTimerReq) ProtoMessage() {} func (x *SetScreenTimerReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[132] + mi := &file_main_proto_msgTypes[136] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7005,7 +7231,7 @@ func (x *SetScreenTimerReq) ProtoReflect() protoreflect.Message { // Deprecated: Use SetScreenTimerReq.ProtoReflect.Descriptor instead. func (*SetScreenTimerReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{132} + return file_main_proto_rawDescGZIP(), []int{136} } func (x *SetScreenTimerReq) GetGameID() int32 { @@ -7037,7 +7263,7 @@ type SetScreenTimerRsp struct { func (x *SetScreenTimerRsp) Reset() { *x = SetScreenTimerRsp{} - mi := &file_main_proto_msgTypes[133] + mi := &file_main_proto_msgTypes[137] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7049,7 +7275,7 @@ func (x *SetScreenTimerRsp) String() string { func (*SetScreenTimerRsp) ProtoMessage() {} func (x *SetScreenTimerRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[133] + mi := &file_main_proto_msgTypes[137] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7062,7 +7288,7 @@ func (x *SetScreenTimerRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use SetScreenTimerRsp.ProtoReflect.Descriptor instead. func (*SetScreenTimerRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{133} + return file_main_proto_rawDescGZIP(), []int{137} } type SendScreenCommandReq struct { @@ -7077,7 +7303,7 @@ type SendScreenCommandReq struct { func (x *SendScreenCommandReq) Reset() { *x = SendScreenCommandReq{} - mi := &file_main_proto_msgTypes[134] + mi := &file_main_proto_msgTypes[138] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7089,7 +7315,7 @@ func (x *SendScreenCommandReq) String() string { func (*SendScreenCommandReq) ProtoMessage() {} func (x *SendScreenCommandReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[134] + mi := &file_main_proto_msgTypes[138] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7102,7 +7328,7 @@ func (x *SendScreenCommandReq) ProtoReflect() protoreflect.Message { // Deprecated: Use SendScreenCommandReq.ProtoReflect.Descriptor instead. func (*SendScreenCommandReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{134} + return file_main_proto_rawDescGZIP(), []int{138} } func (x *SendScreenCommandReq) GetGameID() int32 { @@ -7141,7 +7367,7 @@ type SendScreenCommandRsp struct { func (x *SendScreenCommandRsp) Reset() { *x = SendScreenCommandRsp{} - mi := &file_main_proto_msgTypes[135] + mi := &file_main_proto_msgTypes[139] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7153,7 +7379,7 @@ func (x *SendScreenCommandRsp) String() string { func (*SendScreenCommandRsp) ProtoMessage() {} func (x *SendScreenCommandRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[135] + mi := &file_main_proto_msgTypes[139] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7166,7 +7392,7 @@ func (x *SendScreenCommandRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use SendScreenCommandRsp.ProtoReflect.Descriptor instead. func (*SendScreenCommandRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{135} + return file_main_proto_rawDescGZIP(), []int{139} } type ScreenPlanStep struct { @@ -7181,7 +7407,7 @@ type ScreenPlanStep struct { func (x *ScreenPlanStep) Reset() { *x = ScreenPlanStep{} - mi := &file_main_proto_msgTypes[136] + mi := &file_main_proto_msgTypes[140] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7193,7 +7419,7 @@ func (x *ScreenPlanStep) String() string { func (*ScreenPlanStep) ProtoMessage() {} func (x *ScreenPlanStep) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[136] + mi := &file_main_proto_msgTypes[140] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7206,7 +7432,7 @@ func (x *ScreenPlanStep) ProtoReflect() protoreflect.Message { // Deprecated: Use ScreenPlanStep.ProtoReflect.Descriptor instead. func (*ScreenPlanStep) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{136} + return file_main_proto_rawDescGZIP(), []int{140} } func (x *ScreenPlanStep) GetMode() ScreenMode { @@ -7247,7 +7473,7 @@ type ScreenPlan struct { func (x *ScreenPlan) Reset() { *x = ScreenPlan{} - mi := &file_main_proto_msgTypes[137] + mi := &file_main_proto_msgTypes[141] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7259,7 +7485,7 @@ func (x *ScreenPlan) String() string { func (*ScreenPlan) ProtoMessage() {} func (x *ScreenPlan) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[137] + mi := &file_main_proto_msgTypes[141] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7272,7 +7498,7 @@ func (x *ScreenPlan) ProtoReflect() protoreflect.Message { // Deprecated: Use ScreenPlan.ProtoReflect.Descriptor instead. func (*ScreenPlan) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{137} + return file_main_proto_rawDescGZIP(), []int{141} } func (x *ScreenPlan) GetSteps() []*ScreenPlanStep { @@ -7298,7 +7524,7 @@ type GetScreenPlanReq struct { func (x *GetScreenPlanReq) Reset() { *x = GetScreenPlanReq{} - mi := &file_main_proto_msgTypes[138] + mi := &file_main_proto_msgTypes[142] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7310,7 +7536,7 @@ func (x *GetScreenPlanReq) String() string { func (*GetScreenPlanReq) ProtoMessage() {} func (x *GetScreenPlanReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[138] + mi := &file_main_proto_msgTypes[142] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7323,7 +7549,7 @@ func (x *GetScreenPlanReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetScreenPlanReq.ProtoReflect.Descriptor instead. func (*GetScreenPlanReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{138} + return file_main_proto_rawDescGZIP(), []int{142} } func (x *GetScreenPlanReq) GetGameID() int32 { @@ -7342,7 +7568,7 @@ type GetScreenPlanRsp struct { func (x *GetScreenPlanRsp) Reset() { *x = GetScreenPlanRsp{} - mi := &file_main_proto_msgTypes[139] + mi := &file_main_proto_msgTypes[143] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7354,7 +7580,7 @@ func (x *GetScreenPlanRsp) String() string { func (*GetScreenPlanRsp) ProtoMessage() {} func (x *GetScreenPlanRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[139] + mi := &file_main_proto_msgTypes[143] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7367,7 +7593,7 @@ func (x *GetScreenPlanRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use GetScreenPlanRsp.ProtoReflect.Descriptor instead. func (*GetScreenPlanRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{139} + return file_main_proto_rawDescGZIP(), []int{143} } func (x *GetScreenPlanRsp) GetPlan() *ScreenPlan { @@ -7388,7 +7614,7 @@ type SaveScreenPlanReq struct { func (x *SaveScreenPlanReq) Reset() { *x = SaveScreenPlanReq{} - mi := &file_main_proto_msgTypes[140] + mi := &file_main_proto_msgTypes[144] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7400,7 +7626,7 @@ func (x *SaveScreenPlanReq) String() string { func (*SaveScreenPlanReq) ProtoMessage() {} func (x *SaveScreenPlanReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[140] + mi := &file_main_proto_msgTypes[144] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7413,7 +7639,7 @@ func (x *SaveScreenPlanReq) ProtoReflect() protoreflect.Message { // Deprecated: Use SaveScreenPlanReq.ProtoReflect.Descriptor instead. func (*SaveScreenPlanReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{140} + return file_main_proto_rawDescGZIP(), []int{144} } func (x *SaveScreenPlanReq) GetGameID() int32 { @@ -7446,7 +7672,7 @@ type SaveScreenPlanRsp struct { func (x *SaveScreenPlanRsp) Reset() { *x = SaveScreenPlanRsp{} - mi := &file_main_proto_msgTypes[141] + mi := &file_main_proto_msgTypes[145] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7458,7 +7684,7 @@ func (x *SaveScreenPlanRsp) String() string { func (*SaveScreenPlanRsp) ProtoMessage() {} func (x *SaveScreenPlanRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[141] + mi := &file_main_proto_msgTypes[145] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7471,7 +7697,7 @@ func (x *SaveScreenPlanRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use SaveScreenPlanRsp.ProtoReflect.Descriptor instead. func (*SaveScreenPlanRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{141} + return file_main_proto_rawDescGZIP(), []int{145} } func (x *SaveScreenPlanRsp) GetPlan() *ScreenPlan { @@ -7491,7 +7717,7 @@ type SetScreenPlanStepReq struct { func (x *SetScreenPlanStepReq) Reset() { *x = SetScreenPlanStepReq{} - mi := &file_main_proto_msgTypes[142] + mi := &file_main_proto_msgTypes[146] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7503,7 +7729,7 @@ func (x *SetScreenPlanStepReq) String() string { func (*SetScreenPlanStepReq) ProtoMessage() {} func (x *SetScreenPlanStepReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[142] + mi := &file_main_proto_msgTypes[146] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7516,7 +7742,7 @@ func (x *SetScreenPlanStepReq) ProtoReflect() protoreflect.Message { // Deprecated: Use SetScreenPlanStepReq.ProtoReflect.Descriptor instead. func (*SetScreenPlanStepReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{142} + return file_main_proto_rawDescGZIP(), []int{146} } func (x *SetScreenPlanStepReq) GetGameID() int32 { @@ -7542,7 +7768,7 @@ type SetScreenPlanStepRsp struct { func (x *SetScreenPlanStepRsp) Reset() { *x = SetScreenPlanStepRsp{} - mi := &file_main_proto_msgTypes[143] + mi := &file_main_proto_msgTypes[147] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7554,7 +7780,7 @@ func (x *SetScreenPlanStepRsp) String() string { func (*SetScreenPlanStepRsp) ProtoMessage() {} func (x *SetScreenPlanStepRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[143] + mi := &file_main_proto_msgTypes[147] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7567,7 +7793,7 @@ func (x *SetScreenPlanStepRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use SetScreenPlanStepRsp.ProtoReflect.Descriptor instead. func (*SetScreenPlanStepRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{143} + return file_main_proto_rawDescGZIP(), []int{147} } func (x *SetScreenPlanStepRsp) GetPlan() *ScreenPlan { @@ -7587,7 +7813,7 @@ type GetScreenResultsReq struct { func (x *GetScreenResultsReq) Reset() { *x = GetScreenResultsReq{} - mi := &file_main_proto_msgTypes[144] + mi := &file_main_proto_msgTypes[148] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7599,7 +7825,7 @@ func (x *GetScreenResultsReq) String() string { func (*GetScreenResultsReq) ProtoMessage() {} func (x *GetScreenResultsReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[144] + mi := &file_main_proto_msgTypes[148] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7612,7 +7838,7 @@ func (x *GetScreenResultsReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetScreenResultsReq.ProtoReflect.Descriptor instead. func (*GetScreenResultsReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{144} + return file_main_proto_rawDescGZIP(), []int{148} } func (x *GetScreenResultsReq) GetScreenID() string { @@ -7639,7 +7865,7 @@ type GetScreenResultsRsp struct { func (x *GetScreenResultsRsp) Reset() { *x = GetScreenResultsRsp{} - mi := &file_main_proto_msgTypes[145] + mi := &file_main_proto_msgTypes[149] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7651,7 +7877,7 @@ func (x *GetScreenResultsRsp) String() string { func (*GetScreenResultsRsp) ProtoMessage() {} func (x *GetScreenResultsRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[145] + mi := &file_main_proto_msgTypes[149] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7664,7 +7890,7 @@ func (x *GetScreenResultsRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use GetScreenResultsRsp.ProtoReflect.Descriptor instead. func (*GetScreenResultsRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{145} + return file_main_proto_rawDescGZIP(), []int{149} } func (x *GetScreenResultsRsp) GetQuestions() []*ResultsQuestion { @@ -7691,7 +7917,7 @@ type GetParticipationReq struct { func (x *GetParticipationReq) Reset() { *x = GetParticipationReq{} - mi := &file_main_proto_msgTypes[146] + mi := &file_main_proto_msgTypes[150] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7703,7 +7929,7 @@ func (x *GetParticipationReq) String() string { func (*GetParticipationReq) ProtoMessage() {} func (x *GetParticipationReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[146] + mi := &file_main_proto_msgTypes[150] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7716,7 +7942,7 @@ func (x *GetParticipationReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetParticipationReq.ProtoReflect.Descriptor instead. func (*GetParticipationReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{146} + return file_main_proto_rawDescGZIP(), []int{150} } func (x *GetParticipationReq) GetToken() string { @@ -7738,7 +7964,7 @@ type AnswerParticipationReq struct { func (x *AnswerParticipationReq) Reset() { *x = AnswerParticipationReq{} - mi := &file_main_proto_msgTypes[147] + mi := &file_main_proto_msgTypes[151] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7750,7 +7976,7 @@ func (x *AnswerParticipationReq) String() string { func (*AnswerParticipationReq) ProtoMessage() {} func (x *AnswerParticipationReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[147] + mi := &file_main_proto_msgTypes[151] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7763,7 +7989,7 @@ func (x *AnswerParticipationReq) ProtoReflect() protoreflect.Message { // Deprecated: Use AnswerParticipationReq.ProtoReflect.Descriptor instead. func (*AnswerParticipationReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{147} + return file_main_proto_rawDescGZIP(), []int{151} } func (x *AnswerParticipationReq) GetToken() string { @@ -7801,7 +8027,7 @@ type ParticipationRsp struct { func (x *ParticipationRsp) Reset() { *x = ParticipationRsp{} - mi := &file_main_proto_msgTypes[148] + mi := &file_main_proto_msgTypes[152] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7813,7 +8039,7 @@ func (x *ParticipationRsp) String() string { func (*ParticipationRsp) ProtoMessage() {} func (x *ParticipationRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[148] + mi := &file_main_proto_msgTypes[152] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7826,7 +8052,7 @@ func (x *ParticipationRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use ParticipationRsp.ProtoReflect.Descriptor instead. func (*ParticipationRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{148} + return file_main_proto_rawDescGZIP(), []int{152} } func (x *ParticipationRsp) GetTeamName() string { @@ -7895,7 +8121,7 @@ type Team struct { func (x *Team) Reset() { *x = Team{} - mi := &file_main_proto_msgTypes[149] + mi := &file_main_proto_msgTypes[153] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7907,7 +8133,7 @@ func (x *Team) String() string { func (*Team) ProtoMessage() {} func (x *Team) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[149] + mi := &file_main_proto_msgTypes[153] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7920,7 +8146,7 @@ func (x *Team) ProtoReflect() protoreflect.Message { // Deprecated: Use Team.ProtoReflect.Descriptor instead. func (*Team) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{149} + return file_main_proto_rawDescGZIP(), []int{153} } func (x *Team) GetID() int32 { @@ -8016,7 +8242,7 @@ type GetGameReq struct { func (x *GetGameReq) Reset() { *x = GetGameReq{} - mi := &file_main_proto_msgTypes[150] + mi := &file_main_proto_msgTypes[154] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8028,7 +8254,7 @@ func (x *GetGameReq) String() string { func (*GetGameReq) ProtoMessage() {} func (x *GetGameReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[150] + mi := &file_main_proto_msgTypes[154] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8041,7 +8267,7 @@ func (x *GetGameReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGameReq.ProtoReflect.Descriptor instead. func (*GetGameReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{150} + return file_main_proto_rawDescGZIP(), []int{154} } func (x *GetGameReq) GetID() int32 { @@ -8060,7 +8286,7 @@ type GetGameRsp struct { func (x *GetGameRsp) Reset() { *x = GetGameRsp{} - mi := &file_main_proto_msgTypes[151] + mi := &file_main_proto_msgTypes[155] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8072,7 +8298,7 @@ func (x *GetGameRsp) String() string { func (*GetGameRsp) ProtoMessage() {} func (x *GetGameRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[151] + mi := &file_main_proto_msgTypes[155] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8085,7 +8311,7 @@ func (x *GetGameRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGameRsp.ProtoReflect.Descriptor instead. func (*GetGameRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{151} + return file_main_proto_rawDescGZIP(), []int{155} } func (x *GetGameRsp) GetGame() *Game { @@ -8104,7 +8330,7 @@ type GetGameAnswersReq struct { func (x *GetGameAnswersReq) Reset() { *x = GetGameAnswersReq{} - mi := &file_main_proto_msgTypes[152] + mi := &file_main_proto_msgTypes[156] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8116,7 +8342,7 @@ func (x *GetGameAnswersReq) String() string { func (*GetGameAnswersReq) ProtoMessage() {} func (x *GetGameAnswersReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[152] + mi := &file_main_proto_msgTypes[156] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8129,7 +8355,7 @@ func (x *GetGameAnswersReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGameAnswersReq.ProtoReflect.Descriptor instead. func (*GetGameAnswersReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{152} + return file_main_proto_rawDescGZIP(), []int{156} } func (x *GetGameAnswersReq) GetGameID() int32 { @@ -8149,7 +8375,7 @@ type GetGameAnswersRsp struct { func (x *GetGameAnswersRsp) Reset() { *x = GetGameAnswersRsp{} - mi := &file_main_proto_msgTypes[153] + mi := &file_main_proto_msgTypes[157] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8161,7 +8387,7 @@ func (x *GetGameAnswersRsp) String() string { func (*GetGameAnswersRsp) ProtoMessage() {} func (x *GetGameAnswersRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[153] + mi := &file_main_proto_msgTypes[157] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8174,7 +8400,7 @@ func (x *GetGameAnswersRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGameAnswersRsp.ProtoReflect.Descriptor instead. func (*GetGameAnswersRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{153} + return file_main_proto_rawDescGZIP(), []int{157} } func (x *GetGameAnswersRsp) GetQuestions() []*Question { @@ -8200,7 +8426,7 @@ type GetGameResultsReq struct { func (x *GetGameResultsReq) Reset() { *x = GetGameResultsReq{} - mi := &file_main_proto_msgTypes[154] + mi := &file_main_proto_msgTypes[158] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8212,7 +8438,7 @@ func (x *GetGameResultsReq) String() string { func (*GetGameResultsReq) ProtoMessage() {} func (x *GetGameResultsReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[154] + mi := &file_main_proto_msgTypes[158] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8225,7 +8451,7 @@ func (x *GetGameResultsReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGameResultsReq.ProtoReflect.Descriptor instead. func (*GetGameResultsReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{154} + return file_main_proto_rawDescGZIP(), []int{158} } func (x *GetGameResultsReq) GetGameID() int32 { @@ -8247,7 +8473,7 @@ type ResultsQuestion struct { func (x *ResultsQuestion) Reset() { *x = ResultsQuestion{} - mi := &file_main_proto_msgTypes[155] + mi := &file_main_proto_msgTypes[159] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8259,7 +8485,7 @@ func (x *ResultsQuestion) String() string { func (*ResultsQuestion) ProtoMessage() {} func (x *ResultsQuestion) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[155] + mi := &file_main_proto_msgTypes[159] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8272,7 +8498,7 @@ func (x *ResultsQuestion) ProtoReflect() protoreflect.Message { // Deprecated: Use ResultsQuestion.ProtoReflect.Descriptor instead. func (*ResultsQuestion) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{155} + return file_main_proto_rawDescGZIP(), []int{159} } func (x *ResultsQuestion) GetCode() string { @@ -8308,7 +8534,7 @@ type TeamResult struct { func (x *TeamResult) Reset() { *x = TeamResult{} - mi := &file_main_proto_msgTypes[156] + mi := &file_main_proto_msgTypes[160] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8320,7 +8546,7 @@ func (x *TeamResult) String() string { func (*TeamResult) ProtoMessage() {} func (x *TeamResult) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[156] + mi := &file_main_proto_msgTypes[160] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8333,7 +8559,7 @@ func (x *TeamResult) ProtoReflect() protoreflect.Message { // Deprecated: Use TeamResult.ProtoReflect.Descriptor instead. func (*TeamResult) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{156} + return file_main_proto_rawDescGZIP(), []int{160} } func (x *TeamResult) GetTeam() *Team { @@ -8381,7 +8607,7 @@ type GetGameResultsRsp struct { func (x *GetGameResultsRsp) Reset() { *x = GetGameResultsRsp{} - mi := &file_main_proto_msgTypes[157] + mi := &file_main_proto_msgTypes[161] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8393,7 +8619,7 @@ func (x *GetGameResultsRsp) String() string { func (*GetGameResultsRsp) ProtoMessage() {} func (x *GetGameResultsRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[157] + mi := &file_main_proto_msgTypes[161] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8406,7 +8632,7 @@ func (x *GetGameResultsRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGameResultsRsp.ProtoReflect.Descriptor instead. func (*GetGameResultsRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{157} + return file_main_proto_rawDescGZIP(), []int{161} } func (x *GetGameResultsRsp) GetQuestions() []*ResultsQuestion { @@ -8441,7 +8667,7 @@ type GameReview struct { func (x *GameReview) Reset() { *x = GameReview{} - mi := &file_main_proto_msgTypes[158] + mi := &file_main_proto_msgTypes[162] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8453,7 +8679,7 @@ func (x *GameReview) String() string { func (*GameReview) ProtoMessage() {} func (x *GameReview) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[158] + mi := &file_main_proto_msgTypes[162] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8466,7 +8692,7 @@ func (x *GameReview) ProtoReflect() protoreflect.Message { // Deprecated: Use GameReview.ProtoReflect.Descriptor instead. func (*GameReview) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{158} + return file_main_proto_rawDescGZIP(), []int{162} } func (x *GameReview) GetID() int32 { @@ -8553,7 +8779,7 @@ type CreateGameReviewReq struct { func (x *CreateGameReviewReq) Reset() { *x = CreateGameReviewReq{} - mi := &file_main_proto_msgTypes[159] + mi := &file_main_proto_msgTypes[163] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8565,7 +8791,7 @@ func (x *CreateGameReviewReq) String() string { func (*CreateGameReviewReq) ProtoMessage() {} func (x *CreateGameReviewReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[159] + mi := &file_main_proto_msgTypes[163] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8578,7 +8804,7 @@ func (x *CreateGameReviewReq) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateGameReviewReq.ProtoReflect.Descriptor instead. func (*CreateGameReviewReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{159} + return file_main_proto_rawDescGZIP(), []int{163} } func (x *CreateGameReviewReq) GetGameID() int32 { @@ -8632,7 +8858,7 @@ type CreateGameReviewRsp struct { func (x *CreateGameReviewRsp) Reset() { *x = CreateGameReviewRsp{} - mi := &file_main_proto_msgTypes[160] + mi := &file_main_proto_msgTypes[164] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8644,7 +8870,7 @@ func (x *CreateGameReviewRsp) String() string { func (*CreateGameReviewRsp) ProtoMessage() {} func (x *CreateGameReviewRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[160] + mi := &file_main_proto_msgTypes[164] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8657,7 +8883,7 @@ func (x *CreateGameReviewRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateGameReviewRsp.ProtoReflect.Descriptor instead. func (*CreateGameReviewRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{160} + return file_main_proto_rawDescGZIP(), []int{164} } func (x *CreateGameReviewRsp) GetReview() *GameReview { @@ -8676,7 +8902,7 @@ type GetGameReviewsReq struct { func (x *GetGameReviewsReq) Reset() { *x = GetGameReviewsReq{} - mi := &file_main_proto_msgTypes[161] + mi := &file_main_proto_msgTypes[165] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8688,7 +8914,7 @@ func (x *GetGameReviewsReq) String() string { func (*GetGameReviewsReq) ProtoMessage() {} func (x *GetGameReviewsReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[161] + mi := &file_main_proto_msgTypes[165] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8701,7 +8927,7 @@ func (x *GetGameReviewsReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGameReviewsReq.ProtoReflect.Descriptor instead. func (*GetGameReviewsReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{161} + return file_main_proto_rawDescGZIP(), []int{165} } func (x *GetGameReviewsReq) GetGameID() int32 { @@ -8720,7 +8946,7 @@ type GetScenarioReviewsReq struct { func (x *GetScenarioReviewsReq) Reset() { *x = GetScenarioReviewsReq{} - mi := &file_main_proto_msgTypes[162] + mi := &file_main_proto_msgTypes[166] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8732,7 +8958,7 @@ func (x *GetScenarioReviewsReq) String() string { func (*GetScenarioReviewsReq) ProtoMessage() {} func (x *GetScenarioReviewsReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[162] + mi := &file_main_proto_msgTypes[166] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8745,7 +8971,7 @@ func (x *GetScenarioReviewsReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetScenarioReviewsReq.ProtoReflect.Descriptor instead. func (*GetScenarioReviewsReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{162} + return file_main_proto_rawDescGZIP(), []int{166} } func (x *GetScenarioReviewsReq) GetScenarioID() int32 { @@ -8763,7 +8989,7 @@ type GetReviewsForModerationReq struct { func (x *GetReviewsForModerationReq) Reset() { *x = GetReviewsForModerationReq{} - mi := &file_main_proto_msgTypes[163] + mi := &file_main_proto_msgTypes[167] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8775,7 +9001,7 @@ func (x *GetReviewsForModerationReq) String() string { func (*GetReviewsForModerationReq) ProtoMessage() {} func (x *GetReviewsForModerationReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[163] + mi := &file_main_proto_msgTypes[167] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8788,7 +9014,7 @@ func (x *GetReviewsForModerationReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetReviewsForModerationReq.ProtoReflect.Descriptor instead. func (*GetReviewsForModerationReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{163} + return file_main_proto_rawDescGZIP(), []int{167} } type GetGameReviewsRsp struct { @@ -8802,7 +9028,7 @@ type GetGameReviewsRsp struct { func (x *GetGameReviewsRsp) Reset() { *x = GetGameReviewsRsp{} - mi := &file_main_proto_msgTypes[164] + mi := &file_main_proto_msgTypes[168] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8814,7 +9040,7 @@ func (x *GetGameReviewsRsp) String() string { func (*GetGameReviewsRsp) ProtoMessage() {} func (x *GetGameReviewsRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[164] + mi := &file_main_proto_msgTypes[168] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8827,7 +9053,7 @@ func (x *GetGameReviewsRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGameReviewsRsp.ProtoReflect.Descriptor instead. func (*GetGameReviewsRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{164} + return file_main_proto_rawDescGZIP(), []int{168} } func (x *GetGameReviewsRsp) GetAverageRating() float64 { @@ -8861,7 +9087,7 @@ type ModerateGameReviewReq struct { func (x *ModerateGameReviewReq) Reset() { *x = ModerateGameReviewReq{} - mi := &file_main_proto_msgTypes[165] + mi := &file_main_proto_msgTypes[169] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8873,7 +9099,7 @@ func (x *ModerateGameReviewReq) String() string { func (*ModerateGameReviewReq) ProtoMessage() {} func (x *ModerateGameReviewReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[165] + mi := &file_main_proto_msgTypes[169] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8886,7 +9112,7 @@ func (x *ModerateGameReviewReq) ProtoReflect() protoreflect.Message { // Deprecated: Use ModerateGameReviewReq.ProtoReflect.Descriptor instead. func (*ModerateGameReviewReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{165} + return file_main_proto_rawDescGZIP(), []int{169} } func (x *ModerateGameReviewReq) GetID() int32 { @@ -8912,7 +9138,7 @@ type ModerateGameReviewRsp struct { func (x *ModerateGameReviewRsp) Reset() { *x = ModerateGameReviewRsp{} - mi := &file_main_proto_msgTypes[166] + mi := &file_main_proto_msgTypes[170] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8924,7 +9150,7 @@ func (x *ModerateGameReviewRsp) String() string { func (*ModerateGameReviewRsp) ProtoMessage() {} func (x *ModerateGameReviewRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[166] + mi := &file_main_proto_msgTypes[170] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8937,7 +9163,7 @@ func (x *ModerateGameReviewRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use ModerateGameReviewRsp.ProtoReflect.Descriptor instead. func (*ModerateGameReviewRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{166} + return file_main_proto_rawDescGZIP(), []int{170} } func (x *ModerateGameReviewRsp) GetReview() *GameReview { @@ -8962,7 +9188,7 @@ type UpdateGameReq struct { func (x *UpdateGameReq) Reset() { *x = UpdateGameReq{} - mi := &file_main_proto_msgTypes[167] + mi := &file_main_proto_msgTypes[171] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8974,7 +9200,7 @@ func (x *UpdateGameReq) String() string { func (*UpdateGameReq) ProtoMessage() {} func (x *UpdateGameReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[167] + mi := &file_main_proto_msgTypes[171] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8987,7 +9213,7 @@ func (x *UpdateGameReq) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateGameReq.ProtoReflect.Descriptor instead. func (*UpdateGameReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{167} + return file_main_proto_rawDescGZIP(), []int{171} } func (x *UpdateGameReq) GetID() int32 { @@ -9047,7 +9273,7 @@ type UpdateGameRsp struct { func (x *UpdateGameRsp) Reset() { *x = UpdateGameRsp{} - mi := &file_main_proto_msgTypes[168] + mi := &file_main_proto_msgTypes[172] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9059,7 +9285,7 @@ func (x *UpdateGameRsp) String() string { func (*UpdateGameRsp) ProtoMessage() {} func (x *UpdateGameRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[168] + mi := &file_main_proto_msgTypes[172] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9072,7 +9298,7 @@ func (x *UpdateGameRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateGameRsp.ProtoReflect.Descriptor instead. func (*UpdateGameRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{168} + return file_main_proto_rawDescGZIP(), []int{172} } type StartGameReq struct { @@ -9084,7 +9310,7 @@ type StartGameReq struct { func (x *StartGameReq) Reset() { *x = StartGameReq{} - mi := &file_main_proto_msgTypes[169] + mi := &file_main_proto_msgTypes[173] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9096,7 +9322,7 @@ func (x *StartGameReq) String() string { func (*StartGameReq) ProtoMessage() {} func (x *StartGameReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[169] + mi := &file_main_proto_msgTypes[173] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9109,7 +9335,7 @@ func (x *StartGameReq) ProtoReflect() protoreflect.Message { // Deprecated: Use StartGameReq.ProtoReflect.Descriptor instead. func (*StartGameReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{169} + return file_main_proto_rawDescGZIP(), []int{173} } func (x *StartGameReq) GetID() int32 { @@ -9127,7 +9353,7 @@ type StartGameRsp struct { func (x *StartGameRsp) Reset() { *x = StartGameRsp{} - mi := &file_main_proto_msgTypes[170] + mi := &file_main_proto_msgTypes[174] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9139,7 +9365,7 @@ func (x *StartGameRsp) String() string { func (*StartGameRsp) ProtoMessage() {} func (x *StartGameRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[170] + mi := &file_main_proto_msgTypes[174] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9152,7 +9378,7 @@ func (x *StartGameRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use StartGameRsp.ProtoReflect.Descriptor instead. func (*StartGameRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{170} + return file_main_proto_rawDescGZIP(), []int{174} } type PauseGameReq struct { @@ -9164,7 +9390,7 @@ type PauseGameReq struct { func (x *PauseGameReq) Reset() { *x = PauseGameReq{} - mi := &file_main_proto_msgTypes[171] + mi := &file_main_proto_msgTypes[175] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9176,7 +9402,7 @@ func (x *PauseGameReq) String() string { func (*PauseGameReq) ProtoMessage() {} func (x *PauseGameReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[171] + mi := &file_main_proto_msgTypes[175] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9189,7 +9415,7 @@ func (x *PauseGameReq) ProtoReflect() protoreflect.Message { // Deprecated: Use PauseGameReq.ProtoReflect.Descriptor instead. func (*PauseGameReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{171} + return file_main_proto_rawDescGZIP(), []int{175} } func (x *PauseGameReq) GetID() int32 { @@ -9207,7 +9433,7 @@ type PauseGameRsp struct { func (x *PauseGameRsp) Reset() { *x = PauseGameRsp{} - mi := &file_main_proto_msgTypes[172] + mi := &file_main_proto_msgTypes[176] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9219,7 +9445,7 @@ func (x *PauseGameRsp) String() string { func (*PauseGameRsp) ProtoMessage() {} func (x *PauseGameRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[172] + mi := &file_main_proto_msgTypes[176] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9232,7 +9458,7 @@ func (x *PauseGameRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use PauseGameRsp.ProtoReflect.Descriptor instead. func (*PauseGameRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{172} + return file_main_proto_rawDescGZIP(), []int{176} } type PlayGameReq struct { @@ -9244,7 +9470,7 @@ type PlayGameReq struct { func (x *PlayGameReq) Reset() { *x = PlayGameReq{} - mi := &file_main_proto_msgTypes[173] + mi := &file_main_proto_msgTypes[177] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9256,7 +9482,7 @@ func (x *PlayGameReq) String() string { func (*PlayGameReq) ProtoMessage() {} func (x *PlayGameReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[173] + mi := &file_main_proto_msgTypes[177] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9269,7 +9495,7 @@ func (x *PlayGameReq) ProtoReflect() protoreflect.Message { // Deprecated: Use PlayGameReq.ProtoReflect.Descriptor instead. func (*PlayGameReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{173} + return file_main_proto_rawDescGZIP(), []int{177} } func (x *PlayGameReq) GetID() int32 { @@ -9287,7 +9513,7 @@ type PlayGameRsp struct { func (x *PlayGameRsp) Reset() { *x = PlayGameRsp{} - mi := &file_main_proto_msgTypes[174] + mi := &file_main_proto_msgTypes[178] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9299,7 +9525,7 @@ func (x *PlayGameRsp) String() string { func (*PlayGameRsp) ProtoMessage() {} func (x *PlayGameRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[174] + mi := &file_main_proto_msgTypes[178] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9312,7 +9538,7 @@ func (x *PlayGameRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use PlayGameRsp.ProtoReflect.Descriptor instead. func (*PlayGameRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{174} + return file_main_proto_rawDescGZIP(), []int{178} } type FinishGameReq struct { @@ -9324,7 +9550,7 @@ type FinishGameReq struct { func (x *FinishGameReq) Reset() { *x = FinishGameReq{} - mi := &file_main_proto_msgTypes[175] + mi := &file_main_proto_msgTypes[179] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9336,7 +9562,7 @@ func (x *FinishGameReq) String() string { func (*FinishGameReq) ProtoMessage() {} func (x *FinishGameReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[175] + mi := &file_main_proto_msgTypes[179] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9349,7 +9575,7 @@ func (x *FinishGameReq) ProtoReflect() protoreflect.Message { // Deprecated: Use FinishGameReq.ProtoReflect.Descriptor instead. func (*FinishGameReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{175} + return file_main_proto_rawDescGZIP(), []int{179} } func (x *FinishGameReq) GetID() int32 { @@ -9367,7 +9593,7 @@ type FinishGameRsp struct { func (x *FinishGameRsp) Reset() { *x = FinishGameRsp{} - mi := &file_main_proto_msgTypes[176] + mi := &file_main_proto_msgTypes[180] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9379,7 +9605,7 @@ func (x *FinishGameRsp) String() string { func (*FinishGameRsp) ProtoMessage() {} func (x *FinishGameRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[176] + mi := &file_main_proto_msgTypes[180] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9392,7 +9618,7 @@ func (x *FinishGameRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use FinishGameRsp.ProtoReflect.Descriptor instead. func (*FinishGameRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{176} + return file_main_proto_rawDescGZIP(), []int{180} } type ResetGameReq struct { @@ -9404,7 +9630,7 @@ type ResetGameReq struct { func (x *ResetGameReq) Reset() { *x = ResetGameReq{} - mi := &file_main_proto_msgTypes[177] + mi := &file_main_proto_msgTypes[181] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9416,7 +9642,7 @@ func (x *ResetGameReq) String() string { func (*ResetGameReq) ProtoMessage() {} func (x *ResetGameReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[177] + mi := &file_main_proto_msgTypes[181] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9429,7 +9655,7 @@ func (x *ResetGameReq) ProtoReflect() protoreflect.Message { // Deprecated: Use ResetGameReq.ProtoReflect.Descriptor instead. func (*ResetGameReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{177} + return file_main_proto_rawDescGZIP(), []int{181} } func (x *ResetGameReq) GetID() int32 { @@ -9447,7 +9673,7 @@ type ResetGameRsp struct { func (x *ResetGameRsp) Reset() { *x = ResetGameRsp{} - mi := &file_main_proto_msgTypes[178] + mi := &file_main_proto_msgTypes[182] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9459,7 +9685,7 @@ func (x *ResetGameRsp) String() string { func (*ResetGameRsp) ProtoMessage() {} func (x *ResetGameRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[178] + mi := &file_main_proto_msgTypes[182] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9472,7 +9698,7 @@ func (x *ResetGameRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use ResetGameRsp.ProtoReflect.Descriptor instead. func (*ResetGameRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{178} + return file_main_proto_rawDescGZIP(), []int{182} } type DeleteGameReq struct { @@ -9484,7 +9710,7 @@ type DeleteGameReq struct { func (x *DeleteGameReq) Reset() { *x = DeleteGameReq{} - mi := &file_main_proto_msgTypes[179] + mi := &file_main_proto_msgTypes[183] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9496,7 +9722,7 @@ func (x *DeleteGameReq) String() string { func (*DeleteGameReq) ProtoMessage() {} func (x *DeleteGameReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[179] + mi := &file_main_proto_msgTypes[183] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9509,7 +9735,7 @@ func (x *DeleteGameReq) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteGameReq.ProtoReflect.Descriptor instead. func (*DeleteGameReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{179} + return file_main_proto_rawDescGZIP(), []int{183} } func (x *DeleteGameReq) GetID() int32 { @@ -9527,7 +9753,7 @@ type DeleteGameRsp struct { func (x *DeleteGameRsp) Reset() { *x = DeleteGameRsp{} - mi := &file_main_proto_msgTypes[180] + mi := &file_main_proto_msgTypes[184] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9539,7 +9765,7 @@ func (x *DeleteGameRsp) String() string { func (*DeleteGameRsp) ProtoMessage() {} func (x *DeleteGameRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[180] + mi := &file_main_proto_msgTypes[184] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9552,7 +9778,7 @@ func (x *DeleteGameRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteGameRsp.ProtoReflect.Descriptor instead. func (*DeleteGameRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{180} + return file_main_proto_rawDescGZIP(), []int{184} } type AddTeamReq struct { @@ -9567,7 +9793,7 @@ type AddTeamReq struct { func (x *AddTeamReq) Reset() { *x = AddTeamReq{} - mi := &file_main_proto_msgTypes[181] + mi := &file_main_proto_msgTypes[185] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9579,7 +9805,7 @@ func (x *AddTeamReq) String() string { func (*AddTeamReq) ProtoMessage() {} func (x *AddTeamReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[181] + mi := &file_main_proto_msgTypes[185] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9592,7 +9818,7 @@ func (x *AddTeamReq) ProtoReflect() protoreflect.Message { // Deprecated: Use AddTeamReq.ProtoReflect.Descriptor instead. func (*AddTeamReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{181} + return file_main_proto_rawDescGZIP(), []int{185} } func (x *AddTeamReq) GetGameID() int32 { @@ -9633,7 +9859,7 @@ type AddTeamRsp struct { func (x *AddTeamRsp) Reset() { *x = AddTeamRsp{} - mi := &file_main_proto_msgTypes[182] + mi := &file_main_proto_msgTypes[186] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9645,7 +9871,7 @@ func (x *AddTeamRsp) String() string { func (*AddTeamRsp) ProtoMessage() {} func (x *AddTeamRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[182] + mi := &file_main_proto_msgTypes[186] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9658,7 +9884,7 @@ func (x *AddTeamRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use AddTeamRsp.ProtoReflect.Descriptor instead. func (*AddTeamRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{182} + return file_main_proto_rawDescGZIP(), []int{186} } func (x *AddTeamRsp) GetID() int32 { @@ -9685,7 +9911,7 @@ type UpdateTeamReq struct { func (x *UpdateTeamReq) Reset() { *x = UpdateTeamReq{} - mi := &file_main_proto_msgTypes[183] + mi := &file_main_proto_msgTypes[187] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9697,7 +9923,7 @@ func (x *UpdateTeamReq) String() string { func (*UpdateTeamReq) ProtoMessage() {} func (x *UpdateTeamReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[183] + mi := &file_main_proto_msgTypes[187] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9710,7 +9936,7 @@ func (x *UpdateTeamReq) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateTeamReq.ProtoReflect.Descriptor instead. func (*UpdateTeamReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{183} + return file_main_proto_rawDescGZIP(), []int{187} } func (x *UpdateTeamReq) GetID() int32 { @@ -9735,7 +9961,7 @@ type UpdateTeamRsp struct { func (x *UpdateTeamRsp) Reset() { *x = UpdateTeamRsp{} - mi := &file_main_proto_msgTypes[184] + mi := &file_main_proto_msgTypes[188] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9747,7 +9973,7 @@ func (x *UpdateTeamRsp) String() string { func (*UpdateTeamRsp) ProtoMessage() {} func (x *UpdateTeamRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[184] + mi := &file_main_proto_msgTypes[188] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9760,7 +9986,7 @@ func (x *UpdateTeamRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateTeamRsp.ProtoReflect.Descriptor instead. func (*UpdateTeamRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{184} + return file_main_proto_rawDescGZIP(), []int{188} } type DeleteTeamReq struct { @@ -9772,7 +9998,7 @@ type DeleteTeamReq struct { func (x *DeleteTeamReq) Reset() { *x = DeleteTeamReq{} - mi := &file_main_proto_msgTypes[185] + mi := &file_main_proto_msgTypes[189] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9784,7 +10010,7 @@ func (x *DeleteTeamReq) String() string { func (*DeleteTeamReq) ProtoMessage() {} func (x *DeleteTeamReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[185] + mi := &file_main_proto_msgTypes[189] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9797,7 +10023,7 @@ func (x *DeleteTeamReq) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteTeamReq.ProtoReflect.Descriptor instead. func (*DeleteTeamReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{185} + return file_main_proto_rawDescGZIP(), []int{189} } func (x *DeleteTeamReq) GetID() int64 { @@ -9815,7 +10041,7 @@ type DeleteTeamRsp struct { func (x *DeleteTeamRsp) Reset() { *x = DeleteTeamRsp{} - mi := &file_main_proto_msgTypes[186] + mi := &file_main_proto_msgTypes[190] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9827,7 +10053,7 @@ func (x *DeleteTeamRsp) String() string { func (*DeleteTeamRsp) ProtoMessage() {} func (x *DeleteTeamRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[186] + mi := &file_main_proto_msgTypes[190] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9840,7 +10066,7 @@ func (x *DeleteTeamRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteTeamRsp.ProtoReflect.Descriptor instead. func (*DeleteTeamRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{186} + return file_main_proto_rawDescGZIP(), []int{190} } type GiveTeamApplicationsReq struct { @@ -9853,7 +10079,7 @@ type GiveTeamApplicationsReq struct { func (x *GiveTeamApplicationsReq) Reset() { *x = GiveTeamApplicationsReq{} - mi := &file_main_proto_msgTypes[187] + mi := &file_main_proto_msgTypes[191] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9865,7 +10091,7 @@ func (x *GiveTeamApplicationsReq) String() string { func (*GiveTeamApplicationsReq) ProtoMessage() {} func (x *GiveTeamApplicationsReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[187] + mi := &file_main_proto_msgTypes[191] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9878,7 +10104,7 @@ func (x *GiveTeamApplicationsReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GiveTeamApplicationsReq.ProtoReflect.Descriptor instead. func (*GiveTeamApplicationsReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{187} + return file_main_proto_rawDescGZIP(), []int{191} } func (x *GiveTeamApplicationsReq) GetID() int64 { @@ -9903,7 +10129,7 @@ type GiveTeamApplicationsRsp struct { func (x *GiveTeamApplicationsRsp) Reset() { *x = GiveTeamApplicationsRsp{} - mi := &file_main_proto_msgTypes[188] + mi := &file_main_proto_msgTypes[192] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9915,7 +10141,7 @@ func (x *GiveTeamApplicationsRsp) String() string { func (*GiveTeamApplicationsRsp) ProtoMessage() {} func (x *GiveTeamApplicationsRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[188] + mi := &file_main_proto_msgTypes[192] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9928,7 +10154,7 @@ func (x *GiveTeamApplicationsRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use GiveTeamApplicationsRsp.ProtoReflect.Descriptor instead. func (*GiveTeamApplicationsRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{188} + return file_main_proto_rawDescGZIP(), []int{192} } type GetTeamStoryReq struct { @@ -9941,7 +10167,7 @@ type GetTeamStoryReq struct { func (x *GetTeamStoryReq) Reset() { *x = GetTeamStoryReq{} - mi := &file_main_proto_msgTypes[189] + mi := &file_main_proto_msgTypes[193] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9953,7 +10179,7 @@ func (x *GetTeamStoryReq) String() string { func (*GetTeamStoryReq) ProtoMessage() {} func (x *GetTeamStoryReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[189] + mi := &file_main_proto_msgTypes[193] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9966,7 +10192,7 @@ func (x *GetTeamStoryReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTeamStoryReq.ProtoReflect.Descriptor instead. func (*GetTeamStoryReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{189} + return file_main_proto_rawDescGZIP(), []int{193} } func (x *GetTeamStoryReq) GetID() int64 { @@ -9994,7 +10220,7 @@ type GetTeamStoryRsp struct { func (x *GetTeamStoryRsp) Reset() { *x = GetTeamStoryRsp{} - mi := &file_main_proto_msgTypes[190] + mi := &file_main_proto_msgTypes[194] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10006,7 +10232,7 @@ func (x *GetTeamStoryRsp) String() string { func (*GetTeamStoryRsp) ProtoMessage() {} func (x *GetTeamStoryRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[190] + mi := &file_main_proto_msgTypes[194] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10019,7 +10245,7 @@ func (x *GetTeamStoryRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTeamStoryRsp.ProtoReflect.Descriptor instead. func (*GetTeamStoryRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{190} + return file_main_proto_rawDescGZIP(), []int{194} } func (x *GetTeamStoryRsp) GetStory() *Story { @@ -10053,7 +10279,7 @@ type TeamAction struct { func (x *TeamAction) Reset() { *x = TeamAction{} - mi := &file_main_proto_msgTypes[191] + mi := &file_main_proto_msgTypes[195] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10065,7 +10291,7 @@ func (x *TeamAction) String() string { func (*TeamAction) ProtoMessage() {} func (x *TeamAction) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[191] + mi := &file_main_proto_msgTypes[195] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10078,7 +10304,7 @@ func (x *TeamAction) ProtoReflect() protoreflect.Message { // Deprecated: Use TeamAction.ProtoReflect.Descriptor instead. func (*TeamAction) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{191} + return file_main_proto_rawDescGZIP(), []int{195} } func (x *TeamAction) GetCode() string { @@ -10106,7 +10332,7 @@ type AddTeamActionReq struct { func (x *AddTeamActionReq) Reset() { *x = AddTeamActionReq{} - mi := &file_main_proto_msgTypes[192] + mi := &file_main_proto_msgTypes[196] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10118,7 +10344,7 @@ func (x *AddTeamActionReq) String() string { func (*AddTeamActionReq) ProtoMessage() {} func (x *AddTeamActionReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[192] + mi := &file_main_proto_msgTypes[196] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10131,7 +10357,7 @@ func (x *AddTeamActionReq) ProtoReflect() protoreflect.Message { // Deprecated: Use AddTeamActionReq.ProtoReflect.Descriptor instead. func (*AddTeamActionReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{192} + return file_main_proto_rawDescGZIP(), []int{196} } func (x *AddTeamActionReq) GetID() int64 { @@ -10163,7 +10389,7 @@ type AddTeamActionRsp struct { func (x *AddTeamActionRsp) Reset() { *x = AddTeamActionRsp{} - mi := &file_main_proto_msgTypes[193] + mi := &file_main_proto_msgTypes[197] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10175,7 +10401,7 @@ func (x *AddTeamActionRsp) String() string { func (*AddTeamActionRsp) ProtoMessage() {} func (x *AddTeamActionRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[193] + mi := &file_main_proto_msgTypes[197] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10188,7 +10414,7 @@ func (x *AddTeamActionRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use AddTeamActionRsp.ProtoReflect.Descriptor instead. func (*AddTeamActionRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{193} + return file_main_proto_rawDescGZIP(), []int{197} } type DeleteLastTeamActionReq struct { @@ -10200,7 +10426,7 @@ type DeleteLastTeamActionReq struct { func (x *DeleteLastTeamActionReq) Reset() { *x = DeleteLastTeamActionReq{} - mi := &file_main_proto_msgTypes[194] + mi := &file_main_proto_msgTypes[198] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10212,7 +10438,7 @@ func (x *DeleteLastTeamActionReq) String() string { func (*DeleteLastTeamActionReq) ProtoMessage() {} func (x *DeleteLastTeamActionReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[194] + mi := &file_main_proto_msgTypes[198] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10225,7 +10451,7 @@ func (x *DeleteLastTeamActionReq) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteLastTeamActionReq.ProtoReflect.Descriptor instead. func (*DeleteLastTeamActionReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{194} + return file_main_proto_rawDescGZIP(), []int{198} } func (x *DeleteLastTeamActionReq) GetID() int64 { @@ -10243,7 +10469,7 @@ type DeleteLastTeamActionRsp struct { func (x *DeleteLastTeamActionRsp) Reset() { *x = DeleteLastTeamActionRsp{} - mi := &file_main_proto_msgTypes[195] + mi := &file_main_proto_msgTypes[199] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10255,7 +10481,7 @@ func (x *DeleteLastTeamActionRsp) String() string { func (*DeleteLastTeamActionRsp) ProtoMessage() {} func (x *DeleteLastTeamActionRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[195] + mi := &file_main_proto_msgTypes[199] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10268,7 +10494,7 @@ func (x *DeleteLastTeamActionRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteLastTeamActionRsp.ProtoReflect.Descriptor instead. func (*DeleteLastTeamActionRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{195} + return file_main_proto_rawDescGZIP(), []int{199} } type GetTeamAnswersReq struct { @@ -10281,7 +10507,7 @@ type GetTeamAnswersReq struct { func (x *GetTeamAnswersReq) Reset() { *x = GetTeamAnswersReq{} - mi := &file_main_proto_msgTypes[196] + mi := &file_main_proto_msgTypes[200] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10293,7 +10519,7 @@ func (x *GetTeamAnswersReq) String() string { func (*GetTeamAnswersReq) ProtoMessage() {} func (x *GetTeamAnswersReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[196] + mi := &file_main_proto_msgTypes[200] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10306,7 +10532,7 @@ func (x *GetTeamAnswersReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTeamAnswersReq.ProtoReflect.Descriptor instead. func (*GetTeamAnswersReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{196} + return file_main_proto_rawDescGZIP(), []int{200} } func (x *GetTeamAnswersReq) GetID() int64 { @@ -10332,7 +10558,7 @@ type GetTeamAnswersRsp struct { func (x *GetTeamAnswersRsp) Reset() { *x = GetTeamAnswersRsp{} - mi := &file_main_proto_msgTypes[197] + mi := &file_main_proto_msgTypes[201] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10344,7 +10570,7 @@ func (x *GetTeamAnswersRsp) String() string { func (*GetTeamAnswersRsp) ProtoMessage() {} func (x *GetTeamAnswersRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[197] + mi := &file_main_proto_msgTypes[201] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10357,7 +10583,7 @@ func (x *GetTeamAnswersRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTeamAnswersRsp.ProtoReflect.Descriptor instead. func (*GetTeamAnswersRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{197} + return file_main_proto_rawDescGZIP(), []int{201} } func (x *GetTeamAnswersRsp) GetAnswers() []*Answer { @@ -10378,7 +10604,7 @@ type SubmitTeamAnswersReq struct { func (x *SubmitTeamAnswersReq) Reset() { *x = SubmitTeamAnswersReq{} - mi := &file_main_proto_msgTypes[198] + mi := &file_main_proto_msgTypes[202] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10390,7 +10616,7 @@ func (x *SubmitTeamAnswersReq) String() string { func (*SubmitTeamAnswersReq) ProtoMessage() {} func (x *SubmitTeamAnswersReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[198] + mi := &file_main_proto_msgTypes[202] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10403,7 +10629,7 @@ func (x *SubmitTeamAnswersReq) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitTeamAnswersReq.ProtoReflect.Descriptor instead. func (*SubmitTeamAnswersReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{198} + return file_main_proto_rawDescGZIP(), []int{202} } func (x *SubmitTeamAnswersReq) GetID() int64 { @@ -10435,7 +10661,7 @@ type SubmitTeamAnswersRsp struct { func (x *SubmitTeamAnswersRsp) Reset() { *x = SubmitTeamAnswersRsp{} - mi := &file_main_proto_msgTypes[199] + mi := &file_main_proto_msgTypes[203] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10447,7 +10673,7 @@ func (x *SubmitTeamAnswersRsp) String() string { func (*SubmitTeamAnswersRsp) ProtoMessage() {} func (x *SubmitTeamAnswersRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[199] + mi := &file_main_proto_msgTypes[203] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10460,7 +10686,7 @@ func (x *SubmitTeamAnswersRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitTeamAnswersRsp.ProtoReflect.Descriptor instead. func (*SubmitTeamAnswersRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{199} + return file_main_proto_rawDescGZIP(), []int{203} } type SetTeamAnswerScoreReq struct { @@ -10475,7 +10701,7 @@ type SetTeamAnswerScoreReq struct { func (x *SetTeamAnswerScoreReq) Reset() { *x = SetTeamAnswerScoreReq{} - mi := &file_main_proto_msgTypes[200] + mi := &file_main_proto_msgTypes[204] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10487,7 +10713,7 @@ func (x *SetTeamAnswerScoreReq) String() string { func (*SetTeamAnswerScoreReq) ProtoMessage() {} func (x *SetTeamAnswerScoreReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[200] + mi := &file_main_proto_msgTypes[204] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10500,7 +10726,7 @@ func (x *SetTeamAnswerScoreReq) ProtoReflect() protoreflect.Message { // Deprecated: Use SetTeamAnswerScoreReq.ProtoReflect.Descriptor instead. func (*SetTeamAnswerScoreReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{200} + return file_main_proto_rawDescGZIP(), []int{204} } func (x *SetTeamAnswerScoreReq) GetID() int64 { @@ -10532,7 +10758,7 @@ type SetTeamAnswerScoreRsp struct { func (x *SetTeamAnswerScoreRsp) Reset() { *x = SetTeamAnswerScoreRsp{} - mi := &file_main_proto_msgTypes[201] + mi := &file_main_proto_msgTypes[205] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10544,7 +10770,7 @@ func (x *SetTeamAnswerScoreRsp) String() string { func (*SetTeamAnswerScoreRsp) ProtoMessage() {} func (x *SetTeamAnswerScoreRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[201] + mi := &file_main_proto_msgTypes[205] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10557,7 +10783,7 @@ func (x *SetTeamAnswerScoreRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use SetTeamAnswerScoreRsp.ProtoReflect.Descriptor instead. func (*SetTeamAnswerScoreRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{201} + return file_main_proto_rawDescGZIP(), []int{205} } type UpdateScenarioBackgroundReq struct { @@ -10570,7 +10796,7 @@ type UpdateScenarioBackgroundReq struct { func (x *UpdateScenarioBackgroundReq) Reset() { *x = UpdateScenarioBackgroundReq{} - mi := &file_main_proto_msgTypes[202] + mi := &file_main_proto_msgTypes[206] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10582,7 +10808,7 @@ func (x *UpdateScenarioBackgroundReq) String() string { func (*UpdateScenarioBackgroundReq) ProtoMessage() {} func (x *UpdateScenarioBackgroundReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[202] + mi := &file_main_proto_msgTypes[206] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10595,7 +10821,7 @@ func (x *UpdateScenarioBackgroundReq) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateScenarioBackgroundReq.ProtoReflect.Descriptor instead. func (*UpdateScenarioBackgroundReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{202} + return file_main_proto_rawDescGZIP(), []int{206} } func (x *UpdateScenarioBackgroundReq) GetID() int32 { @@ -10620,7 +10846,7 @@ type UpdateScenarioBackgroundRsp struct { func (x *UpdateScenarioBackgroundRsp) Reset() { *x = UpdateScenarioBackgroundRsp{} - mi := &file_main_proto_msgTypes[203] + mi := &file_main_proto_msgTypes[207] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10632,7 +10858,7 @@ func (x *UpdateScenarioBackgroundRsp) String() string { func (*UpdateScenarioBackgroundRsp) ProtoMessage() {} func (x *UpdateScenarioBackgroundRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[203] + mi := &file_main_proto_msgTypes[207] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10645,7 +10871,7 @@ func (x *UpdateScenarioBackgroundRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateScenarioBackgroundRsp.ProtoReflect.Descriptor instead. func (*UpdateScenarioBackgroundRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{203} + return file_main_proto_rawDescGZIP(), []int{207} } type IssueGameTicketsReq struct { @@ -10658,7 +10884,7 @@ type IssueGameTicketsReq struct { func (x *IssueGameTicketsReq) Reset() { *x = IssueGameTicketsReq{} - mi := &file_main_proto_msgTypes[204] + mi := &file_main_proto_msgTypes[208] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10670,7 +10896,7 @@ func (x *IssueGameTicketsReq) String() string { func (*IssueGameTicketsReq) ProtoMessage() {} func (x *IssueGameTicketsReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[204] + mi := &file_main_proto_msgTypes[208] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10683,7 +10909,7 @@ func (x *IssueGameTicketsReq) ProtoReflect() protoreflect.Message { // Deprecated: Use IssueGameTicketsReq.ProtoReflect.Descriptor instead. func (*IssueGameTicketsReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{204} + return file_main_proto_rawDescGZIP(), []int{208} } func (x *IssueGameTicketsReq) GetGameID() int32 { @@ -10709,7 +10935,7 @@ type IssueGameTicketsRsp struct { func (x *IssueGameTicketsRsp) Reset() { *x = IssueGameTicketsRsp{} - mi := &file_main_proto_msgTypes[205] + mi := &file_main_proto_msgTypes[209] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10721,7 +10947,7 @@ func (x *IssueGameTicketsRsp) String() string { func (*IssueGameTicketsRsp) ProtoMessage() {} func (x *IssueGameTicketsRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[205] + mi := &file_main_proto_msgTypes[209] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10734,7 +10960,7 @@ func (x *IssueGameTicketsRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use IssueGameTicketsRsp.ProtoReflect.Descriptor instead. func (*IssueGameTicketsRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{205} + return file_main_proto_rawDescGZIP(), []int{209} } func (x *IssueGameTicketsRsp) GetTickets() []*Ticket { @@ -10754,7 +10980,7 @@ type Ticket struct { func (x *Ticket) Reset() { *x = Ticket{} - mi := &file_main_proto_msgTypes[206] + mi := &file_main_proto_msgTypes[210] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10766,7 +10992,7 @@ func (x *Ticket) String() string { func (*Ticket) ProtoMessage() {} func (x *Ticket) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[206] + mi := &file_main_proto_msgTypes[210] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10779,7 +11005,7 @@ func (x *Ticket) ProtoReflect() protoreflect.Message { // Deprecated: Use Ticket.ProtoReflect.Descriptor instead. func (*Ticket) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{206} + return file_main_proto_rawDescGZIP(), []int{210} } func (x *Ticket) GetID() int32 { @@ -10805,7 +11031,7 @@ type GetTicketReq struct { func (x *GetTicketReq) Reset() { *x = GetTicketReq{} - mi := &file_main_proto_msgTypes[207] + mi := &file_main_proto_msgTypes[211] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10817,7 +11043,7 @@ func (x *GetTicketReq) String() string { func (*GetTicketReq) ProtoMessage() {} func (x *GetTicketReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[207] + mi := &file_main_proto_msgTypes[211] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10830,7 +11056,7 @@ func (x *GetTicketReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTicketReq.ProtoReflect.Descriptor instead. func (*GetTicketReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{207} + return file_main_proto_rawDescGZIP(), []int{211} } func (x *GetTicketReq) GetToken() string { @@ -10849,7 +11075,7 @@ type GetTicketRsp struct { func (x *GetTicketRsp) Reset() { *x = GetTicketRsp{} - mi := &file_main_proto_msgTypes[208] + mi := &file_main_proto_msgTypes[212] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10861,7 +11087,7 @@ func (x *GetTicketRsp) String() string { func (*GetTicketRsp) ProtoMessage() {} func (x *GetTicketRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[208] + mi := &file_main_proto_msgTypes[212] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10874,7 +11100,7 @@ func (x *GetTicketRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTicketRsp.ProtoReflect.Descriptor instead. func (*GetTicketRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{208} + return file_main_proto_rawDescGZIP(), []int{212} } func (x *GetTicketRsp) GetTicket() *TicketPage { @@ -10893,7 +11119,7 @@ type AcceptTicketReq struct { func (x *AcceptTicketReq) Reset() { *x = AcceptTicketReq{} - mi := &file_main_proto_msgTypes[209] + mi := &file_main_proto_msgTypes[213] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10905,7 +11131,7 @@ func (x *AcceptTicketReq) String() string { func (*AcceptTicketReq) ProtoMessage() {} func (x *AcceptTicketReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[209] + mi := &file_main_proto_msgTypes[213] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10918,7 +11144,7 @@ func (x *AcceptTicketReq) ProtoReflect() protoreflect.Message { // Deprecated: Use AcceptTicketReq.ProtoReflect.Descriptor instead. func (*AcceptTicketReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{209} + return file_main_proto_rawDescGZIP(), []int{213} } func (x *AcceptTicketReq) GetToken() string { @@ -10937,7 +11163,7 @@ type AcceptTicketRsp struct { func (x *AcceptTicketRsp) Reset() { *x = AcceptTicketRsp{} - mi := &file_main_proto_msgTypes[210] + mi := &file_main_proto_msgTypes[214] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10949,7 +11175,7 @@ func (x *AcceptTicketRsp) String() string { func (*AcceptTicketRsp) ProtoMessage() {} func (x *AcceptTicketRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[210] + mi := &file_main_proto_msgTypes[214] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10962,7 +11188,7 @@ func (x *AcceptTicketRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use AcceptTicketRsp.ProtoReflect.Descriptor instead. func (*AcceptTicketRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{210} + return file_main_proto_rawDescGZIP(), []int{214} } func (x *AcceptTicketRsp) GetTicket() *TicketPage { @@ -10988,7 +11214,7 @@ type TicketPage struct { func (x *TicketPage) Reset() { *x = TicketPage{} - mi := &file_main_proto_msgTypes[211] + mi := &file_main_proto_msgTypes[215] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11000,7 +11226,7 @@ func (x *TicketPage) String() string { func (*TicketPage) ProtoMessage() {} func (x *TicketPage) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[211] + mi := &file_main_proto_msgTypes[215] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11013,7 +11239,7 @@ func (x *TicketPage) ProtoReflect() protoreflect.Message { // Deprecated: Use TicketPage.ProtoReflect.Descriptor instead. func (*TicketPage) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{211} + return file_main_proto_rawDescGZIP(), []int{215} } func (x *TicketPage) GetID() int32 { @@ -11095,7 +11321,7 @@ type DeveloperTask struct { func (x *DeveloperTask) Reset() { *x = DeveloperTask{} - mi := &file_main_proto_msgTypes[212] + mi := &file_main_proto_msgTypes[216] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11107,7 +11333,7 @@ func (x *DeveloperTask) String() string { func (*DeveloperTask) ProtoMessage() {} func (x *DeveloperTask) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[212] + mi := &file_main_proto_msgTypes[216] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11120,7 +11346,7 @@ func (x *DeveloperTask) ProtoReflect() protoreflect.Message { // Deprecated: Use DeveloperTask.ProtoReflect.Descriptor instead. func (*DeveloperTask) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{212} + return file_main_proto_rawDescGZIP(), []int{216} } func (x *DeveloperTask) GetID() int32 { @@ -11210,7 +11436,7 @@ type TaskAssignee struct { func (x *TaskAssignee) Reset() { *x = TaskAssignee{} - mi := &file_main_proto_msgTypes[213] + mi := &file_main_proto_msgTypes[217] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11222,7 +11448,7 @@ func (x *TaskAssignee) String() string { func (*TaskAssignee) ProtoMessage() {} func (x *TaskAssignee) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[213] + mi := &file_main_proto_msgTypes[217] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11235,7 +11461,7 @@ func (x *TaskAssignee) ProtoReflect() protoreflect.Message { // Deprecated: Use TaskAssignee.ProtoReflect.Descriptor instead. func (*TaskAssignee) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{213} + return file_main_proto_rawDescGZIP(), []int{217} } func (x *TaskAssignee) GetID() int32 { @@ -11260,7 +11486,7 @@ type GetTasksReq struct { func (x *GetTasksReq) Reset() { *x = GetTasksReq{} - mi := &file_main_proto_msgTypes[214] + mi := &file_main_proto_msgTypes[218] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11272,7 +11498,7 @@ func (x *GetTasksReq) String() string { func (*GetTasksReq) ProtoMessage() {} func (x *GetTasksReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[214] + mi := &file_main_proto_msgTypes[218] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11285,7 +11511,7 @@ func (x *GetTasksReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTasksReq.ProtoReflect.Descriptor instead. func (*GetTasksReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{214} + return file_main_proto_rawDescGZIP(), []int{218} } type GetTasksRsp struct { @@ -11297,7 +11523,7 @@ type GetTasksRsp struct { func (x *GetTasksRsp) Reset() { *x = GetTasksRsp{} - mi := &file_main_proto_msgTypes[215] + mi := &file_main_proto_msgTypes[219] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11309,7 +11535,7 @@ func (x *GetTasksRsp) String() string { func (*GetTasksRsp) ProtoMessage() {} func (x *GetTasksRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[215] + mi := &file_main_proto_msgTypes[219] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11322,7 +11548,7 @@ func (x *GetTasksRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTasksRsp.ProtoReflect.Descriptor instead. func (*GetTasksRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{215} + return file_main_proto_rawDescGZIP(), []int{219} } func (x *GetTasksRsp) GetTasks() []*DeveloperTask { @@ -11340,7 +11566,7 @@ type GetTaskAssigneesReq struct { func (x *GetTaskAssigneesReq) Reset() { *x = GetTaskAssigneesReq{} - mi := &file_main_proto_msgTypes[216] + mi := &file_main_proto_msgTypes[220] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11352,7 +11578,7 @@ func (x *GetTaskAssigneesReq) String() string { func (*GetTaskAssigneesReq) ProtoMessage() {} func (x *GetTaskAssigneesReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[216] + mi := &file_main_proto_msgTypes[220] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11365,7 +11591,7 @@ func (x *GetTaskAssigneesReq) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTaskAssigneesReq.ProtoReflect.Descriptor instead. func (*GetTaskAssigneesReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{216} + return file_main_proto_rawDescGZIP(), []int{220} } type GetTaskAssigneesRsp struct { @@ -11377,7 +11603,7 @@ type GetTaskAssigneesRsp struct { func (x *GetTaskAssigneesRsp) Reset() { *x = GetTaskAssigneesRsp{} - mi := &file_main_proto_msgTypes[217] + mi := &file_main_proto_msgTypes[221] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11389,7 +11615,7 @@ func (x *GetTaskAssigneesRsp) String() string { func (*GetTaskAssigneesRsp) ProtoMessage() {} func (x *GetTaskAssigneesRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[217] + mi := &file_main_proto_msgTypes[221] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11402,7 +11628,7 @@ func (x *GetTaskAssigneesRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTaskAssigneesRsp.ProtoReflect.Descriptor instead. func (*GetTaskAssigneesRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{217} + return file_main_proto_rawDescGZIP(), []int{221} } func (x *GetTaskAssigneesRsp) GetAssignees() []*TaskAssignee { @@ -11425,7 +11651,7 @@ type CreateTaskReq struct { func (x *CreateTaskReq) Reset() { *x = CreateTaskReq{} - mi := &file_main_proto_msgTypes[218] + mi := &file_main_proto_msgTypes[222] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11437,7 +11663,7 @@ func (x *CreateTaskReq) String() string { func (*CreateTaskReq) ProtoMessage() {} func (x *CreateTaskReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[218] + mi := &file_main_proto_msgTypes[222] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11450,7 +11676,7 @@ func (x *CreateTaskReq) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateTaskReq.ProtoReflect.Descriptor instead. func (*CreateTaskReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{218} + return file_main_proto_rawDescGZIP(), []int{222} } func (x *CreateTaskReq) GetTitle() string { @@ -11503,7 +11729,7 @@ type UpdateTaskReq struct { func (x *UpdateTaskReq) Reset() { *x = UpdateTaskReq{} - mi := &file_main_proto_msgTypes[219] + mi := &file_main_proto_msgTypes[223] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11515,7 +11741,7 @@ func (x *UpdateTaskReq) String() string { func (*UpdateTaskReq) ProtoMessage() {} func (x *UpdateTaskReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[219] + mi := &file_main_proto_msgTypes[223] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11528,7 +11754,7 @@ func (x *UpdateTaskReq) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateTaskReq.ProtoReflect.Descriptor instead. func (*UpdateTaskReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{219} + return file_main_proto_rawDescGZIP(), []int{223} } func (x *UpdateTaskReq) GetID() int32 { @@ -11591,7 +11817,7 @@ type SetTaskStatusReq struct { func (x *SetTaskStatusReq) Reset() { *x = SetTaskStatusReq{} - mi := &file_main_proto_msgTypes[220] + mi := &file_main_proto_msgTypes[224] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11603,7 +11829,7 @@ func (x *SetTaskStatusReq) String() string { func (*SetTaskStatusReq) ProtoMessage() {} func (x *SetTaskStatusReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[220] + mi := &file_main_proto_msgTypes[224] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11616,7 +11842,7 @@ func (x *SetTaskStatusReq) ProtoReflect() protoreflect.Message { // Deprecated: Use SetTaskStatusReq.ProtoReflect.Descriptor instead. func (*SetTaskStatusReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{220} + return file_main_proto_rawDescGZIP(), []int{224} } func (x *SetTaskStatusReq) GetID() int32 { @@ -11650,7 +11876,7 @@ type DeleteTaskReq struct { func (x *DeleteTaskReq) Reset() { *x = DeleteTaskReq{} - mi := &file_main_proto_msgTypes[221] + mi := &file_main_proto_msgTypes[225] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11662,7 +11888,7 @@ func (x *DeleteTaskReq) String() string { func (*DeleteTaskReq) ProtoMessage() {} func (x *DeleteTaskReq) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[221] + mi := &file_main_proto_msgTypes[225] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11675,7 +11901,7 @@ func (x *DeleteTaskReq) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteTaskReq.ProtoReflect.Descriptor instead. func (*DeleteTaskReq) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{221} + return file_main_proto_rawDescGZIP(), []int{225} } func (x *DeleteTaskReq) GetID() int32 { @@ -11701,7 +11927,7 @@ type TaskRsp struct { func (x *TaskRsp) Reset() { *x = TaskRsp{} - mi := &file_main_proto_msgTypes[222] + mi := &file_main_proto_msgTypes[226] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11713,7 +11939,7 @@ func (x *TaskRsp) String() string { func (*TaskRsp) ProtoMessage() {} func (x *TaskRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[222] + mi := &file_main_proto_msgTypes[226] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11726,7 +11952,7 @@ func (x *TaskRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use TaskRsp.ProtoReflect.Descriptor instead. func (*TaskRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{222} + return file_main_proto_rawDescGZIP(), []int{226} } func (x *TaskRsp) GetTask() *DeveloperTask { @@ -11744,7 +11970,7 @@ type DeleteTaskRsp struct { func (x *DeleteTaskRsp) Reset() { *x = DeleteTaskRsp{} - mi := &file_main_proto_msgTypes[223] + mi := &file_main_proto_msgTypes[227] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11756,7 +11982,7 @@ func (x *DeleteTaskRsp) String() string { func (*DeleteTaskRsp) ProtoMessage() {} func (x *DeleteTaskRsp) ProtoReflect() protoreflect.Message { - mi := &file_main_proto_msgTypes[223] + mi := &file_main_proto_msgTypes[227] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11769,7 +11995,7 @@ func (x *DeleteTaskRsp) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteTaskRsp.ProtoReflect.Descriptor instead. func (*DeleteTaskRsp) Descriptor() ([]byte, []int) { - return file_main_proto_rawDescGZIP(), []int{223} + return file_main_proto_rawDescGZIP(), []int{227} } var File_main_proto protoreflect.FileDescriptor @@ -12063,7 +12289,7 @@ const file_main_proto_rawDesc = "" + "\x02ID\x18\x01 \x01(\x05R\x02ID\"\r\n" + "\vGetGamesReq\"I\n" + "\vGetGamesRsp\x12:\n" + - "\x05games\x18\x01 \x03(\v2$.crabs.evening_detective_server.GameR\x05games\"\xe9\x03\n" + + "\x05games\x18\x01 \x03(\v2$.crabs.evening_detective_server.GameR\x05games\"\xad\x04\n" + "\x04Game\x12\x0e\n" + "\x02ID\x18\x01 \x01(\x05R\x02ID\x12\x12\n" + "\x04name\x18\x02 \x01(\tR\x04name\x12 \n" + @@ -12077,9 +12303,24 @@ const file_main_proto_rawDesc = "" + "\bended_at\x18\t \x01(\v2\x1a.google.protobuf.TimestampH\x01R\aendedAt\x88\x01\x01\x12\x16\n" + "\x06format\x18\n" + " \x01(\tR\x06format\x12\x1a\n" + - "\blocation\x18\v \x01(\tR\blocationB\r\n" + + "\blocation\x18\v \x01(\tR\blocation\x12B\n" + + "\x06export\x18\f \x01(\v2*.crabs.evening_detective_server.GameExportR\x06exportB\r\n" + "\v_started_atB\v\n" + - "\t_ended_at\"\xec\x06\n" + + "\t_ended_at\"\x96\x01\n" + + "\n" + + "GameExport\x12\x0e\n" + + "\x02ID\x18\x01 \x01(\tR\x02ID\x12\x14\n" + + "\x05state\x18\x02 \x01(\tR\x05state\x12\x1c\n" + + "\tpackageID\x18\x03 \x01(\tR\tpackageID\x12\x12\n" + + "\x04size\x18\x04 \x01(\x03R\x04size\x12\x16\n" + + "\x06sha256\x18\x05 \x01(\tR\x06sha256\x12\x18\n" + + "\afailure\x18\x06 \x01(\tR\afailure\"$\n" + + "\x12StartGameExportReq\x12\x0e\n" + + "\x02ID\x18\x01 \x01(\x05R\x02ID\"\"\n" + + "\x10GetGameExportReq\x12\x0e\n" + + "\x02ID\x18\x01 \x01(\x05R\x02ID\"S\n" + + "\rGameExportRsp\x12B\n" + + "\x06export\x18\x01 \x01(\v2*.crabs.evening_detective_server.GameExportR\x06export\"\xec\x06\n" + "\vScreenState\x12\x0e\n" + "\x02ID\x18\x01 \x01(\tR\x02ID\x12\x16\n" + "\x06status\x18\x02 \x01(\tR\x06status\x12\x1b\n" + @@ -12547,7 +12788,7 @@ const file_main_proto_rawDesc = "" + "\x1aMUSIC_PLAYBACK_UNSPECIFIED\x10\x00\x12\x1a\n" + "\x16MUSIC_PLAYBACK_STOPPED\x10\x01\x12\x1a\n" + "\x16MUSIC_PLAYBACK_PLAYING\x10\x02\x12\x19\n" + - "\x15MUSIC_PLAYBACK_PAUSED\x10\x032\xfe\xc9\x01\n" + + "\x15MUSIC_PLAYBACK_PAUSED\x10\x032\xab\xcc\x01\n" + "\x16EveningDetectiveServer\x12\x8c\x02\n" + "\bGetTasks\x12+.crabs.evening_detective_server.GetTasksReq\x1a+.crabs.evening_detective_server.GetTasksRsp\"\xa5\x01\x92A\x8f\x01\n" + "\fЗадачи\x121Получить общую доску задач\x1aLДоступно разработчикам и администратору.\x82\xd3\xe4\x93\x02\f\x12\n" + @@ -12686,7 +12927,9 @@ const file_main_proto_rawDesc = "" + "\bИгры\x12\x19Получить игры\x82\xd3\xe4\x93\x02\f\x12\n" + "/api/games\x12\xa2\x01\n" + "\aGetGame\x12*.crabs.evening_detective_server.GetGameReq\x1a*.crabs.evening_detective_server.GetGameRsp\"?\x92A%\n" + - "\bИгры\x12\x19Получить игру\x82\xd3\xe4\x93\x02\x11\x12\x0f/api/games/{ID}\x12\xec\x01\n" + + "\bИгры\x12\x19Получить игру\x82\xd3\xe4\x93\x02\x11\x12\x0f/api/games/{ID}\x12\x97\x01\n" + + "\x0fStartGameExport\x122.crabs.evening_detective_server.StartGameExportReq\x1a-.crabs.evening_detective_server.GameExportRsp\"!\x82\xd3\xe4\x93\x02\x1b:\x01*\"\x16/api/games/{ID}/export\x12\x90\x01\n" + + "\rGetGameExport\x120.crabs.evening_detective_server.GetGameExportReq\x1a-.crabs.evening_detective_server.GameExportRsp\"\x1e\x82\xd3\xe4\x93\x02\x18\x12\x16/api/games/{ID}/export\x12\xec\x01\n" + "\x10IssueGameTickets\x123.crabs.evening_detective_server.IssueGameTicketsReq\x1a3.crabs.evening_detective_server.IssueGameTicketsRsp\"n\x92AE\n" + "\fБилеты\x12-Выпустить билеты на игруb\x06\n" + "\x04\n" + @@ -12834,7 +13077,7 @@ func file_main_proto_rawDescGZIP() []byte { } var file_main_proto_enumTypes = make([]protoimpl.EnumInfo, 4) -var file_main_proto_msgTypes = make([]protoimpl.MessageInfo, 224) +var file_main_proto_msgTypes = make([]protoimpl.MessageInfo, 228) var file_main_proto_goTypes = []any{ (ScreenMode)(0), // 0: crabs.evening_detective_server.ScreenMode (ScreenTimerState)(0), // 1: crabs.evening_detective_server.ScreenTimerState @@ -12945,131 +13188,135 @@ var file_main_proto_goTypes = []any{ (*GetGamesReq)(nil), // 106: crabs.evening_detective_server.GetGamesReq (*GetGamesRsp)(nil), // 107: crabs.evening_detective_server.GetGamesRsp (*Game)(nil), // 108: crabs.evening_detective_server.Game - (*ScreenState)(nil), // 109: crabs.evening_detective_server.ScreenState - (*CreateScreenSessionReq)(nil), // 110: crabs.evening_detective_server.CreateScreenSessionReq - (*CreateScreenSessionRsp)(nil), // 111: crabs.evening_detective_server.CreateScreenSessionRsp - (*GetScreenStateReq)(nil), // 112: crabs.evening_detective_server.GetScreenStateReq - (*GetScreenStateRsp)(nil), // 113: crabs.evening_detective_server.GetScreenStateRsp - (*GetGameScreensReq)(nil), // 114: crabs.evening_detective_server.GetGameScreensReq - (*GetGameScreensRsp)(nil), // 115: crabs.evening_detective_server.GetGameScreensRsp - (*MusicState)(nil), // 116: crabs.evening_detective_server.MusicState - (*GetGameMusicReq)(nil), // 117: crabs.evening_detective_server.GetGameMusicReq - (*GetGameMusicRsp)(nil), // 118: crabs.evening_detective_server.GetGameMusicRsp - (*SetGameMusicReq)(nil), // 119: crabs.evening_detective_server.SetGameMusicReq - (*SetGameMusicRsp)(nil), // 120: crabs.evening_detective_server.SetGameMusicRsp - (*AdvanceScreenMusicReq)(nil), // 121: crabs.evening_detective_server.AdvanceScreenMusicReq - (*AdvanceScreenMusicRsp)(nil), // 122: crabs.evening_detective_server.AdvanceScreenMusicRsp - (*BindScreenReq)(nil), // 123: crabs.evening_detective_server.BindScreenReq - (*BindScreenRsp)(nil), // 124: crabs.evening_detective_server.BindScreenRsp - (*UnbindScreenReq)(nil), // 125: crabs.evening_detective_server.UnbindScreenReq - (*UnbindScreenRsp)(nil), // 126: crabs.evening_detective_server.UnbindScreenRsp - (*SetScreenSoundReq)(nil), // 127: crabs.evening_detective_server.SetScreenSoundReq - (*SetScreenSoundRsp)(nil), // 128: crabs.evening_detective_server.SetScreenSoundRsp - (*MapItem)(nil), // 129: crabs.evening_detective_server.MapItem - (*GetGameMapReq)(nil), // 130: crabs.evening_detective_server.GetGameMapReq - (*GetGameMapRsp)(nil), // 131: crabs.evening_detective_server.GetGameMapRsp - (*UpdateGameMapItemReq)(nil), // 132: crabs.evening_detective_server.UpdateGameMapItemReq - (*UpdateGameMapItemRsp)(nil), // 133: crabs.evening_detective_server.UpdateGameMapItemRsp - (*SetScreenModeReq)(nil), // 134: crabs.evening_detective_server.SetScreenModeReq - (*SetScreenModeRsp)(nil), // 135: crabs.evening_detective_server.SetScreenModeRsp - (*SetScreenTimerReq)(nil), // 136: crabs.evening_detective_server.SetScreenTimerReq - (*SetScreenTimerRsp)(nil), // 137: crabs.evening_detective_server.SetScreenTimerRsp - (*SendScreenCommandReq)(nil), // 138: crabs.evening_detective_server.SendScreenCommandReq - (*SendScreenCommandRsp)(nil), // 139: crabs.evening_detective_server.SendScreenCommandRsp - (*ScreenPlanStep)(nil), // 140: crabs.evening_detective_server.ScreenPlanStep - (*ScreenPlan)(nil), // 141: crabs.evening_detective_server.ScreenPlan - (*GetScreenPlanReq)(nil), // 142: crabs.evening_detective_server.GetScreenPlanReq - (*GetScreenPlanRsp)(nil), // 143: crabs.evening_detective_server.GetScreenPlanRsp - (*SaveScreenPlanReq)(nil), // 144: crabs.evening_detective_server.SaveScreenPlanReq - (*SaveScreenPlanRsp)(nil), // 145: crabs.evening_detective_server.SaveScreenPlanRsp - (*SetScreenPlanStepReq)(nil), // 146: crabs.evening_detective_server.SetScreenPlanStepReq - (*SetScreenPlanStepRsp)(nil), // 147: crabs.evening_detective_server.SetScreenPlanStepRsp - (*GetScreenResultsReq)(nil), // 148: crabs.evening_detective_server.GetScreenResultsReq - (*GetScreenResultsRsp)(nil), // 149: crabs.evening_detective_server.GetScreenResultsRsp - (*GetParticipationReq)(nil), // 150: crabs.evening_detective_server.GetParticipationReq - (*AnswerParticipationReq)(nil), // 151: crabs.evening_detective_server.AnswerParticipationReq - (*ParticipationRsp)(nil), // 152: crabs.evening_detective_server.ParticipationRsp - (*Team)(nil), // 153: crabs.evening_detective_server.Team - (*GetGameReq)(nil), // 154: crabs.evening_detective_server.GetGameReq - (*GetGameRsp)(nil), // 155: crabs.evening_detective_server.GetGameRsp - (*GetGameAnswersReq)(nil), // 156: crabs.evening_detective_server.GetGameAnswersReq - (*GetGameAnswersRsp)(nil), // 157: crabs.evening_detective_server.GetGameAnswersRsp - (*GetGameResultsReq)(nil), // 158: crabs.evening_detective_server.GetGameResultsReq - (*ResultsQuestion)(nil), // 159: crabs.evening_detective_server.ResultsQuestion - (*TeamResult)(nil), // 160: crabs.evening_detective_server.TeamResult - (*GetGameResultsRsp)(nil), // 161: crabs.evening_detective_server.GetGameResultsRsp - (*GameReview)(nil), // 162: crabs.evening_detective_server.GameReview - (*CreateGameReviewReq)(nil), // 163: crabs.evening_detective_server.CreateGameReviewReq - (*CreateGameReviewRsp)(nil), // 164: crabs.evening_detective_server.CreateGameReviewRsp - (*GetGameReviewsReq)(nil), // 165: crabs.evening_detective_server.GetGameReviewsReq - (*GetScenarioReviewsReq)(nil), // 166: crabs.evening_detective_server.GetScenarioReviewsReq - (*GetReviewsForModerationReq)(nil), // 167: crabs.evening_detective_server.GetReviewsForModerationReq - (*GetGameReviewsRsp)(nil), // 168: crabs.evening_detective_server.GetGameReviewsRsp - (*ModerateGameReviewReq)(nil), // 169: crabs.evening_detective_server.ModerateGameReviewReq - (*ModerateGameReviewRsp)(nil), // 170: crabs.evening_detective_server.ModerateGameReviewRsp - (*UpdateGameReq)(nil), // 171: crabs.evening_detective_server.UpdateGameReq - (*UpdateGameRsp)(nil), // 172: crabs.evening_detective_server.UpdateGameRsp - (*StartGameReq)(nil), // 173: crabs.evening_detective_server.StartGameReq - (*StartGameRsp)(nil), // 174: crabs.evening_detective_server.StartGameRsp - (*PauseGameReq)(nil), // 175: crabs.evening_detective_server.PauseGameReq - (*PauseGameRsp)(nil), // 176: crabs.evening_detective_server.PauseGameRsp - (*PlayGameReq)(nil), // 177: crabs.evening_detective_server.PlayGameReq - (*PlayGameRsp)(nil), // 178: crabs.evening_detective_server.PlayGameRsp - (*FinishGameReq)(nil), // 179: crabs.evening_detective_server.FinishGameReq - (*FinishGameRsp)(nil), // 180: crabs.evening_detective_server.FinishGameRsp - (*ResetGameReq)(nil), // 181: crabs.evening_detective_server.ResetGameReq - (*ResetGameRsp)(nil), // 182: crabs.evening_detective_server.ResetGameRsp - (*DeleteGameReq)(nil), // 183: crabs.evening_detective_server.DeleteGameReq - (*DeleteGameRsp)(nil), // 184: crabs.evening_detective_server.DeleteGameRsp - (*AddTeamReq)(nil), // 185: crabs.evening_detective_server.AddTeamReq - (*AddTeamRsp)(nil), // 186: crabs.evening_detective_server.AddTeamRsp - (*UpdateTeamReq)(nil), // 187: crabs.evening_detective_server.UpdateTeamReq - (*UpdateTeamRsp)(nil), // 188: crabs.evening_detective_server.UpdateTeamRsp - (*DeleteTeamReq)(nil), // 189: crabs.evening_detective_server.DeleteTeamReq - (*DeleteTeamRsp)(nil), // 190: crabs.evening_detective_server.DeleteTeamRsp - (*GiveTeamApplicationsReq)(nil), // 191: crabs.evening_detective_server.GiveTeamApplicationsReq - (*GiveTeamApplicationsRsp)(nil), // 192: crabs.evening_detective_server.GiveTeamApplicationsRsp - (*GetTeamStoryReq)(nil), // 193: crabs.evening_detective_server.GetTeamStoryReq - (*GetTeamStoryRsp)(nil), // 194: crabs.evening_detective_server.GetTeamStoryRsp - (*TeamAction)(nil), // 195: crabs.evening_detective_server.TeamAction - (*AddTeamActionReq)(nil), // 196: crabs.evening_detective_server.AddTeamActionReq - (*AddTeamActionRsp)(nil), // 197: crabs.evening_detective_server.AddTeamActionRsp - (*DeleteLastTeamActionReq)(nil), // 198: crabs.evening_detective_server.DeleteLastTeamActionReq - (*DeleteLastTeamActionRsp)(nil), // 199: crabs.evening_detective_server.DeleteLastTeamActionRsp - (*GetTeamAnswersReq)(nil), // 200: crabs.evening_detective_server.GetTeamAnswersReq - (*GetTeamAnswersRsp)(nil), // 201: crabs.evening_detective_server.GetTeamAnswersRsp - (*SubmitTeamAnswersReq)(nil), // 202: crabs.evening_detective_server.SubmitTeamAnswersReq - (*SubmitTeamAnswersRsp)(nil), // 203: crabs.evening_detective_server.SubmitTeamAnswersRsp - (*SetTeamAnswerScoreReq)(nil), // 204: crabs.evening_detective_server.SetTeamAnswerScoreReq - (*SetTeamAnswerScoreRsp)(nil), // 205: crabs.evening_detective_server.SetTeamAnswerScoreRsp - (*UpdateScenarioBackgroundReq)(nil), // 206: crabs.evening_detective_server.UpdateScenarioBackgroundReq - (*UpdateScenarioBackgroundRsp)(nil), // 207: crabs.evening_detective_server.UpdateScenarioBackgroundRsp - (*IssueGameTicketsReq)(nil), // 208: crabs.evening_detective_server.IssueGameTicketsReq - (*IssueGameTicketsRsp)(nil), // 209: crabs.evening_detective_server.IssueGameTicketsRsp - (*Ticket)(nil), // 210: crabs.evening_detective_server.Ticket - (*GetTicketReq)(nil), // 211: crabs.evening_detective_server.GetTicketReq - (*GetTicketRsp)(nil), // 212: crabs.evening_detective_server.GetTicketRsp - (*AcceptTicketReq)(nil), // 213: crabs.evening_detective_server.AcceptTicketReq - (*AcceptTicketRsp)(nil), // 214: crabs.evening_detective_server.AcceptTicketRsp - (*TicketPage)(nil), // 215: crabs.evening_detective_server.TicketPage - (*DeveloperTask)(nil), // 216: crabs.evening_detective_server.DeveloperTask - (*TaskAssignee)(nil), // 217: crabs.evening_detective_server.TaskAssignee - (*GetTasksReq)(nil), // 218: crabs.evening_detective_server.GetTasksReq - (*GetTasksRsp)(nil), // 219: crabs.evening_detective_server.GetTasksRsp - (*GetTaskAssigneesReq)(nil), // 220: crabs.evening_detective_server.GetTaskAssigneesReq - (*GetTaskAssigneesRsp)(nil), // 221: crabs.evening_detective_server.GetTaskAssigneesRsp - (*CreateTaskReq)(nil), // 222: crabs.evening_detective_server.CreateTaskReq - (*UpdateTaskReq)(nil), // 223: crabs.evening_detective_server.UpdateTaskReq - (*SetTaskStatusReq)(nil), // 224: crabs.evening_detective_server.SetTaskStatusReq - (*DeleteTaskReq)(nil), // 225: crabs.evening_detective_server.DeleteTaskReq - (*TaskRsp)(nil), // 226: crabs.evening_detective_server.TaskRsp - (*DeleteTaskRsp)(nil), // 227: crabs.evening_detective_server.DeleteTaskRsp - (*timestamppb.Timestamp)(nil), // 228: google.protobuf.Timestamp - (*httpbody.HttpBody)(nil), // 229: google.api.HttpBody + (*GameExport)(nil), // 109: crabs.evening_detective_server.GameExport + (*StartGameExportReq)(nil), // 110: crabs.evening_detective_server.StartGameExportReq + (*GetGameExportReq)(nil), // 111: crabs.evening_detective_server.GetGameExportReq + (*GameExportRsp)(nil), // 112: crabs.evening_detective_server.GameExportRsp + (*ScreenState)(nil), // 113: crabs.evening_detective_server.ScreenState + (*CreateScreenSessionReq)(nil), // 114: crabs.evening_detective_server.CreateScreenSessionReq + (*CreateScreenSessionRsp)(nil), // 115: crabs.evening_detective_server.CreateScreenSessionRsp + (*GetScreenStateReq)(nil), // 116: crabs.evening_detective_server.GetScreenStateReq + (*GetScreenStateRsp)(nil), // 117: crabs.evening_detective_server.GetScreenStateRsp + (*GetGameScreensReq)(nil), // 118: crabs.evening_detective_server.GetGameScreensReq + (*GetGameScreensRsp)(nil), // 119: crabs.evening_detective_server.GetGameScreensRsp + (*MusicState)(nil), // 120: crabs.evening_detective_server.MusicState + (*GetGameMusicReq)(nil), // 121: crabs.evening_detective_server.GetGameMusicReq + (*GetGameMusicRsp)(nil), // 122: crabs.evening_detective_server.GetGameMusicRsp + (*SetGameMusicReq)(nil), // 123: crabs.evening_detective_server.SetGameMusicReq + (*SetGameMusicRsp)(nil), // 124: crabs.evening_detective_server.SetGameMusicRsp + (*AdvanceScreenMusicReq)(nil), // 125: crabs.evening_detective_server.AdvanceScreenMusicReq + (*AdvanceScreenMusicRsp)(nil), // 126: crabs.evening_detective_server.AdvanceScreenMusicRsp + (*BindScreenReq)(nil), // 127: crabs.evening_detective_server.BindScreenReq + (*BindScreenRsp)(nil), // 128: crabs.evening_detective_server.BindScreenRsp + (*UnbindScreenReq)(nil), // 129: crabs.evening_detective_server.UnbindScreenReq + (*UnbindScreenRsp)(nil), // 130: crabs.evening_detective_server.UnbindScreenRsp + (*SetScreenSoundReq)(nil), // 131: crabs.evening_detective_server.SetScreenSoundReq + (*SetScreenSoundRsp)(nil), // 132: crabs.evening_detective_server.SetScreenSoundRsp + (*MapItem)(nil), // 133: crabs.evening_detective_server.MapItem + (*GetGameMapReq)(nil), // 134: crabs.evening_detective_server.GetGameMapReq + (*GetGameMapRsp)(nil), // 135: crabs.evening_detective_server.GetGameMapRsp + (*UpdateGameMapItemReq)(nil), // 136: crabs.evening_detective_server.UpdateGameMapItemReq + (*UpdateGameMapItemRsp)(nil), // 137: crabs.evening_detective_server.UpdateGameMapItemRsp + (*SetScreenModeReq)(nil), // 138: crabs.evening_detective_server.SetScreenModeReq + (*SetScreenModeRsp)(nil), // 139: crabs.evening_detective_server.SetScreenModeRsp + (*SetScreenTimerReq)(nil), // 140: crabs.evening_detective_server.SetScreenTimerReq + (*SetScreenTimerRsp)(nil), // 141: crabs.evening_detective_server.SetScreenTimerRsp + (*SendScreenCommandReq)(nil), // 142: crabs.evening_detective_server.SendScreenCommandReq + (*SendScreenCommandRsp)(nil), // 143: crabs.evening_detective_server.SendScreenCommandRsp + (*ScreenPlanStep)(nil), // 144: crabs.evening_detective_server.ScreenPlanStep + (*ScreenPlan)(nil), // 145: crabs.evening_detective_server.ScreenPlan + (*GetScreenPlanReq)(nil), // 146: crabs.evening_detective_server.GetScreenPlanReq + (*GetScreenPlanRsp)(nil), // 147: crabs.evening_detective_server.GetScreenPlanRsp + (*SaveScreenPlanReq)(nil), // 148: crabs.evening_detective_server.SaveScreenPlanReq + (*SaveScreenPlanRsp)(nil), // 149: crabs.evening_detective_server.SaveScreenPlanRsp + (*SetScreenPlanStepReq)(nil), // 150: crabs.evening_detective_server.SetScreenPlanStepReq + (*SetScreenPlanStepRsp)(nil), // 151: crabs.evening_detective_server.SetScreenPlanStepRsp + (*GetScreenResultsReq)(nil), // 152: crabs.evening_detective_server.GetScreenResultsReq + (*GetScreenResultsRsp)(nil), // 153: crabs.evening_detective_server.GetScreenResultsRsp + (*GetParticipationReq)(nil), // 154: crabs.evening_detective_server.GetParticipationReq + (*AnswerParticipationReq)(nil), // 155: crabs.evening_detective_server.AnswerParticipationReq + (*ParticipationRsp)(nil), // 156: crabs.evening_detective_server.ParticipationRsp + (*Team)(nil), // 157: crabs.evening_detective_server.Team + (*GetGameReq)(nil), // 158: crabs.evening_detective_server.GetGameReq + (*GetGameRsp)(nil), // 159: crabs.evening_detective_server.GetGameRsp + (*GetGameAnswersReq)(nil), // 160: crabs.evening_detective_server.GetGameAnswersReq + (*GetGameAnswersRsp)(nil), // 161: crabs.evening_detective_server.GetGameAnswersRsp + (*GetGameResultsReq)(nil), // 162: crabs.evening_detective_server.GetGameResultsReq + (*ResultsQuestion)(nil), // 163: crabs.evening_detective_server.ResultsQuestion + (*TeamResult)(nil), // 164: crabs.evening_detective_server.TeamResult + (*GetGameResultsRsp)(nil), // 165: crabs.evening_detective_server.GetGameResultsRsp + (*GameReview)(nil), // 166: crabs.evening_detective_server.GameReview + (*CreateGameReviewReq)(nil), // 167: crabs.evening_detective_server.CreateGameReviewReq + (*CreateGameReviewRsp)(nil), // 168: crabs.evening_detective_server.CreateGameReviewRsp + (*GetGameReviewsReq)(nil), // 169: crabs.evening_detective_server.GetGameReviewsReq + (*GetScenarioReviewsReq)(nil), // 170: crabs.evening_detective_server.GetScenarioReviewsReq + (*GetReviewsForModerationReq)(nil), // 171: crabs.evening_detective_server.GetReviewsForModerationReq + (*GetGameReviewsRsp)(nil), // 172: crabs.evening_detective_server.GetGameReviewsRsp + (*ModerateGameReviewReq)(nil), // 173: crabs.evening_detective_server.ModerateGameReviewReq + (*ModerateGameReviewRsp)(nil), // 174: crabs.evening_detective_server.ModerateGameReviewRsp + (*UpdateGameReq)(nil), // 175: crabs.evening_detective_server.UpdateGameReq + (*UpdateGameRsp)(nil), // 176: crabs.evening_detective_server.UpdateGameRsp + (*StartGameReq)(nil), // 177: crabs.evening_detective_server.StartGameReq + (*StartGameRsp)(nil), // 178: crabs.evening_detective_server.StartGameRsp + (*PauseGameReq)(nil), // 179: crabs.evening_detective_server.PauseGameReq + (*PauseGameRsp)(nil), // 180: crabs.evening_detective_server.PauseGameRsp + (*PlayGameReq)(nil), // 181: crabs.evening_detective_server.PlayGameReq + (*PlayGameRsp)(nil), // 182: crabs.evening_detective_server.PlayGameRsp + (*FinishGameReq)(nil), // 183: crabs.evening_detective_server.FinishGameReq + (*FinishGameRsp)(nil), // 184: crabs.evening_detective_server.FinishGameRsp + (*ResetGameReq)(nil), // 185: crabs.evening_detective_server.ResetGameReq + (*ResetGameRsp)(nil), // 186: crabs.evening_detective_server.ResetGameRsp + (*DeleteGameReq)(nil), // 187: crabs.evening_detective_server.DeleteGameReq + (*DeleteGameRsp)(nil), // 188: crabs.evening_detective_server.DeleteGameRsp + (*AddTeamReq)(nil), // 189: crabs.evening_detective_server.AddTeamReq + (*AddTeamRsp)(nil), // 190: crabs.evening_detective_server.AddTeamRsp + (*UpdateTeamReq)(nil), // 191: crabs.evening_detective_server.UpdateTeamReq + (*UpdateTeamRsp)(nil), // 192: crabs.evening_detective_server.UpdateTeamRsp + (*DeleteTeamReq)(nil), // 193: crabs.evening_detective_server.DeleteTeamReq + (*DeleteTeamRsp)(nil), // 194: crabs.evening_detective_server.DeleteTeamRsp + (*GiveTeamApplicationsReq)(nil), // 195: crabs.evening_detective_server.GiveTeamApplicationsReq + (*GiveTeamApplicationsRsp)(nil), // 196: crabs.evening_detective_server.GiveTeamApplicationsRsp + (*GetTeamStoryReq)(nil), // 197: crabs.evening_detective_server.GetTeamStoryReq + (*GetTeamStoryRsp)(nil), // 198: crabs.evening_detective_server.GetTeamStoryRsp + (*TeamAction)(nil), // 199: crabs.evening_detective_server.TeamAction + (*AddTeamActionReq)(nil), // 200: crabs.evening_detective_server.AddTeamActionReq + (*AddTeamActionRsp)(nil), // 201: crabs.evening_detective_server.AddTeamActionRsp + (*DeleteLastTeamActionReq)(nil), // 202: crabs.evening_detective_server.DeleteLastTeamActionReq + (*DeleteLastTeamActionRsp)(nil), // 203: crabs.evening_detective_server.DeleteLastTeamActionRsp + (*GetTeamAnswersReq)(nil), // 204: crabs.evening_detective_server.GetTeamAnswersReq + (*GetTeamAnswersRsp)(nil), // 205: crabs.evening_detective_server.GetTeamAnswersRsp + (*SubmitTeamAnswersReq)(nil), // 206: crabs.evening_detective_server.SubmitTeamAnswersReq + (*SubmitTeamAnswersRsp)(nil), // 207: crabs.evening_detective_server.SubmitTeamAnswersRsp + (*SetTeamAnswerScoreReq)(nil), // 208: crabs.evening_detective_server.SetTeamAnswerScoreReq + (*SetTeamAnswerScoreRsp)(nil), // 209: crabs.evening_detective_server.SetTeamAnswerScoreRsp + (*UpdateScenarioBackgroundReq)(nil), // 210: crabs.evening_detective_server.UpdateScenarioBackgroundReq + (*UpdateScenarioBackgroundRsp)(nil), // 211: crabs.evening_detective_server.UpdateScenarioBackgroundRsp + (*IssueGameTicketsReq)(nil), // 212: crabs.evening_detective_server.IssueGameTicketsReq + (*IssueGameTicketsRsp)(nil), // 213: crabs.evening_detective_server.IssueGameTicketsRsp + (*Ticket)(nil), // 214: crabs.evening_detective_server.Ticket + (*GetTicketReq)(nil), // 215: crabs.evening_detective_server.GetTicketReq + (*GetTicketRsp)(nil), // 216: crabs.evening_detective_server.GetTicketRsp + (*AcceptTicketReq)(nil), // 217: crabs.evening_detective_server.AcceptTicketReq + (*AcceptTicketRsp)(nil), // 218: crabs.evening_detective_server.AcceptTicketRsp + (*TicketPage)(nil), // 219: crabs.evening_detective_server.TicketPage + (*DeveloperTask)(nil), // 220: crabs.evening_detective_server.DeveloperTask + (*TaskAssignee)(nil), // 221: crabs.evening_detective_server.TaskAssignee + (*GetTasksReq)(nil), // 222: crabs.evening_detective_server.GetTasksReq + (*GetTasksRsp)(nil), // 223: crabs.evening_detective_server.GetTasksRsp + (*GetTaskAssigneesReq)(nil), // 224: crabs.evening_detective_server.GetTaskAssigneesReq + (*GetTaskAssigneesRsp)(nil), // 225: crabs.evening_detective_server.GetTaskAssigneesRsp + (*CreateTaskReq)(nil), // 226: crabs.evening_detective_server.CreateTaskReq + (*UpdateTaskReq)(nil), // 227: crabs.evening_detective_server.UpdateTaskReq + (*SetTaskStatusReq)(nil), // 228: crabs.evening_detective_server.SetTaskStatusReq + (*DeleteTaskReq)(nil), // 229: crabs.evening_detective_server.DeleteTaskReq + (*TaskRsp)(nil), // 230: crabs.evening_detective_server.TaskRsp + (*DeleteTaskRsp)(nil), // 231: crabs.evening_detective_server.DeleteTaskRsp + (*timestamppb.Timestamp)(nil), // 232: google.protobuf.Timestamp + (*httpbody.HttpBody)(nil), // 233: google.api.HttpBody } var file_main_proto_depIdxs = []int32{ 26, // 0: crabs.evening_detective_server.GetUsersRsp.users:type_name -> crabs.evening_detective_server.User - 228, // 1: crabs.evening_detective_server.User.created_at:type_name -> google.protobuf.Timestamp + 232, // 1: crabs.evening_detective_server.User.created_at:type_name -> google.protobuf.Timestamp 26, // 2: crabs.evening_detective_server.GetUserByIDRsp.user:type_name -> crabs.evening_detective_server.User 26, // 3: crabs.evening_detective_server.GetMeRsp.user:type_name -> crabs.evening_detective_server.User 42, // 4: crabs.evening_detective_server.Playlist.tracks:type_name -> crabs.evening_detective_server.PlaylistTrack @@ -13082,9 +13329,9 @@ var file_main_proto_depIdxs = []int32{ 66, // 11: crabs.evening_detective_server.GetScenarioRsp.scenario:type_name -> crabs.evening_detective_server.Scenario 67, // 12: crabs.evening_detective_server.Scenario.story:type_name -> crabs.evening_detective_server.Story 26, // 13: crabs.evening_detective_server.Scenario.author:type_name -> crabs.evening_detective_server.User - 228, // 14: crabs.evening_detective_server.Scenario.updated_at:type_name -> google.protobuf.Timestamp - 228, // 15: crabs.evening_detective_server.Scenario.created_at:type_name -> google.protobuf.Timestamp - 228, // 16: crabs.evening_detective_server.Scenario.published_at:type_name -> google.protobuf.Timestamp + 232, // 14: crabs.evening_detective_server.Scenario.updated_at:type_name -> google.protobuf.Timestamp + 232, // 15: crabs.evening_detective_server.Scenario.created_at:type_name -> google.protobuf.Timestamp + 232, // 16: crabs.evening_detective_server.Scenario.published_at:type_name -> google.protobuf.Timestamp 70, // 17: crabs.evening_detective_server.Story.places:type_name -> crabs.evening_detective_server.Place 69, // 18: crabs.evening_detective_server.Story.introduction:type_name -> crabs.evening_detective_server.Introduction 74, // 19: crabs.evening_detective_server.Story.questions:type_name -> crabs.evening_detective_server.Question @@ -13093,7 +13340,7 @@ var file_main_proto_depIdxs = []int32{ 72, // 22: crabs.evening_detective_server.Place.doors:type_name -> crabs.evening_detective_server.Door 73, // 23: crabs.evening_detective_server.Place.keys:type_name -> crabs.evening_detective_server.Key 73, // 24: crabs.evening_detective_server.Door.keys:type_name -> crabs.evening_detective_server.Key - 153, // 25: crabs.evening_detective_server.TeamAnswers.team:type_name -> crabs.evening_detective_server.Team + 157, // 25: crabs.evening_detective_server.TeamAnswers.team:type_name -> crabs.evening_detective_server.Team 76, // 26: crabs.evening_detective_server.TeamAnswers.answers:type_name -> crabs.evening_detective_server.AnswerScore 70, // 27: crabs.evening_detective_server.AddScenarioPlaceReq.place:type_name -> crabs.evening_detective_server.Place 70, // 28: crabs.evening_detective_server.UpdateScenarioPlaceReq.place:type_name -> crabs.evening_detective_server.Place @@ -13101,280 +13348,286 @@ var file_main_proto_depIdxs = []int32{ 69, // 30: crabs.evening_detective_server.UpdateScenarioIntroReq.introduction:type_name -> crabs.evening_detective_server.Introduction 74, // 31: crabs.evening_detective_server.AddScenarioQuestionReq.question:type_name -> crabs.evening_detective_server.Question 74, // 32: crabs.evening_detective_server.UpdateScenarioQuestionReq.question:type_name -> crabs.evening_detective_server.Question - 228, // 33: crabs.evening_detective_server.AddGameReq.start_at:type_name -> google.protobuf.Timestamp + 232, // 33: crabs.evening_detective_server.AddGameReq.start_at:type_name -> google.protobuf.Timestamp 108, // 34: crabs.evening_detective_server.GetGamesRsp.games:type_name -> crabs.evening_detective_server.Game - 228, // 35: crabs.evening_detective_server.Game.start_at:type_name -> google.protobuf.Timestamp + 232, // 35: crabs.evening_detective_server.Game.start_at:type_name -> google.protobuf.Timestamp 66, // 36: crabs.evening_detective_server.Game.scenario:type_name -> crabs.evening_detective_server.Scenario - 153, // 37: crabs.evening_detective_server.Game.teams:type_name -> crabs.evening_detective_server.Team - 228, // 38: crabs.evening_detective_server.Game.started_at:type_name -> google.protobuf.Timestamp - 228, // 39: crabs.evening_detective_server.Game.ended_at:type_name -> google.protobuf.Timestamp - 0, // 40: crabs.evening_detective_server.ScreenState.mode:type_name -> crabs.evening_detective_server.ScreenMode - 2, // 41: crabs.evening_detective_server.ScreenState.command:type_name -> crabs.evening_detective_server.ScreenCommand - 1, // 42: crabs.evening_detective_server.ScreenState.timer_state:type_name -> crabs.evening_detective_server.ScreenTimerState - 116, // 43: crabs.evening_detective_server.ScreenState.music:type_name -> crabs.evening_detective_server.MusicState - 109, // 44: crabs.evening_detective_server.GetScreenStateRsp.state:type_name -> crabs.evening_detective_server.ScreenState - 109, // 45: crabs.evening_detective_server.GetGameScreensRsp.screens:type_name -> crabs.evening_detective_server.ScreenState - 43, // 46: crabs.evening_detective_server.MusicState.playlist:type_name -> crabs.evening_detective_server.Playlist - 3, // 47: crabs.evening_detective_server.MusicState.playback:type_name -> crabs.evening_detective_server.MusicPlaybackState - 43, // 48: crabs.evening_detective_server.GetGameMusicRsp.playlists:type_name -> crabs.evening_detective_server.Playlist - 116, // 49: crabs.evening_detective_server.GetGameMusicRsp.state:type_name -> crabs.evening_detective_server.MusicState - 3, // 50: crabs.evening_detective_server.SetGameMusicReq.playback:type_name -> crabs.evening_detective_server.MusicPlaybackState - 116, // 51: crabs.evening_detective_server.SetGameMusicRsp.state:type_name -> crabs.evening_detective_server.MusicState - 116, // 52: crabs.evening_detective_server.AdvanceScreenMusicRsp.state:type_name -> crabs.evening_detective_server.MusicState - 109, // 53: crabs.evening_detective_server.BindScreenRsp.state:type_name -> crabs.evening_detective_server.ScreenState - 129, // 54: crabs.evening_detective_server.GetGameMapRsp.items:type_name -> crabs.evening_detective_server.MapItem - 0, // 55: crabs.evening_detective_server.SetScreenModeReq.mode:type_name -> crabs.evening_detective_server.ScreenMode - 2, // 56: crabs.evening_detective_server.SendScreenCommandReq.command:type_name -> crabs.evening_detective_server.ScreenCommand - 0, // 57: crabs.evening_detective_server.ScreenPlanStep.mode:type_name -> crabs.evening_detective_server.ScreenMode - 140, // 58: crabs.evening_detective_server.ScreenPlan.steps:type_name -> crabs.evening_detective_server.ScreenPlanStep - 141, // 59: crabs.evening_detective_server.GetScreenPlanRsp.plan:type_name -> crabs.evening_detective_server.ScreenPlan - 140, // 60: crabs.evening_detective_server.SaveScreenPlanReq.steps:type_name -> crabs.evening_detective_server.ScreenPlanStep - 141, // 61: crabs.evening_detective_server.SaveScreenPlanRsp.plan:type_name -> crabs.evening_detective_server.ScreenPlan - 141, // 62: crabs.evening_detective_server.SetScreenPlanStepRsp.plan:type_name -> crabs.evening_detective_server.ScreenPlan - 159, // 63: crabs.evening_detective_server.GetScreenResultsRsp.questions:type_name -> crabs.evening_detective_server.ResultsQuestion - 160, // 64: crabs.evening_detective_server.GetScreenResultsRsp.teams:type_name -> crabs.evening_detective_server.TeamResult - 228, // 65: crabs.evening_detective_server.ParticipationRsp.start_at:type_name -> google.protobuf.Timestamp - 71, // 66: crabs.evening_detective_server.Team.applications:type_name -> crabs.evening_detective_server.Application - 108, // 67: crabs.evening_detective_server.GetGameRsp.game:type_name -> crabs.evening_detective_server.Game - 74, // 68: crabs.evening_detective_server.GetGameAnswersRsp.questions:type_name -> crabs.evening_detective_server.Question - 77, // 69: crabs.evening_detective_server.GetGameAnswersRsp.teams:type_name -> crabs.evening_detective_server.TeamAnswers - 153, // 70: crabs.evening_detective_server.TeamResult.team:type_name -> crabs.evening_detective_server.Team - 76, // 71: crabs.evening_detective_server.TeamResult.answers:type_name -> crabs.evening_detective_server.AnswerScore - 159, // 72: crabs.evening_detective_server.GetGameResultsRsp.questions:type_name -> crabs.evening_detective_server.ResultsQuestion - 160, // 73: crabs.evening_detective_server.GetGameResultsRsp.teams:type_name -> crabs.evening_detective_server.TeamResult - 228, // 74: crabs.evening_detective_server.GameReview.created_at:type_name -> google.protobuf.Timestamp - 162, // 75: crabs.evening_detective_server.CreateGameReviewRsp.review:type_name -> crabs.evening_detective_server.GameReview - 162, // 76: crabs.evening_detective_server.GetGameReviewsRsp.reviews:type_name -> crabs.evening_detective_server.GameReview - 162, // 77: crabs.evening_detective_server.ModerateGameReviewRsp.review:type_name -> crabs.evening_detective_server.GameReview - 228, // 78: crabs.evening_detective_server.UpdateGameReq.start_at:type_name -> google.protobuf.Timestamp - 67, // 79: crabs.evening_detective_server.GetTeamStoryRsp.story:type_name -> crabs.evening_detective_server.Story - 108, // 80: crabs.evening_detective_server.GetTeamStoryRsp.game:type_name -> crabs.evening_detective_server.Game - 195, // 81: crabs.evening_detective_server.GetTeamStoryRsp.actions:type_name -> crabs.evening_detective_server.TeamAction - 75, // 82: crabs.evening_detective_server.GetTeamAnswersRsp.answers:type_name -> crabs.evening_detective_server.Answer - 75, // 83: crabs.evening_detective_server.SubmitTeamAnswersReq.answers:type_name -> crabs.evening_detective_server.Answer - 210, // 84: crabs.evening_detective_server.IssueGameTicketsRsp.tickets:type_name -> crabs.evening_detective_server.Ticket - 215, // 85: crabs.evening_detective_server.GetTicketRsp.ticket:type_name -> crabs.evening_detective_server.TicketPage - 215, // 86: crabs.evening_detective_server.AcceptTicketRsp.ticket:type_name -> crabs.evening_detective_server.TicketPage - 228, // 87: crabs.evening_detective_server.TicketPage.start_at:type_name -> google.protobuf.Timestamp - 228, // 88: crabs.evening_detective_server.TicketPage.used_at:type_name -> google.protobuf.Timestamp - 228, // 89: crabs.evening_detective_server.DeveloperTask.createdAt:type_name -> google.protobuf.Timestamp - 228, // 90: crabs.evening_detective_server.DeveloperTask.updatedAt:type_name -> google.protobuf.Timestamp - 216, // 91: crabs.evening_detective_server.GetTasksRsp.tasks:type_name -> crabs.evening_detective_server.DeveloperTask - 217, // 92: crabs.evening_detective_server.GetTaskAssigneesRsp.assignees:type_name -> crabs.evening_detective_server.TaskAssignee - 216, // 93: crabs.evening_detective_server.TaskRsp.task:type_name -> crabs.evening_detective_server.DeveloperTask - 218, // 94: crabs.evening_detective_server.EveningDetectiveServer.GetTasks:input_type -> crabs.evening_detective_server.GetTasksReq - 220, // 95: crabs.evening_detective_server.EveningDetectiveServer.GetTaskAssignees:input_type -> crabs.evening_detective_server.GetTaskAssigneesReq - 222, // 96: crabs.evening_detective_server.EveningDetectiveServer.CreateTask:input_type -> crabs.evening_detective_server.CreateTaskReq - 223, // 97: crabs.evening_detective_server.EveningDetectiveServer.UpdateTask:input_type -> crabs.evening_detective_server.UpdateTaskReq - 224, // 98: crabs.evening_detective_server.EveningDetectiveServer.SetTaskStatus:input_type -> crabs.evening_detective_server.SetTaskStatusReq - 225, // 99: crabs.evening_detective_server.EveningDetectiveServer.DeleteTask:input_type -> crabs.evening_detective_server.DeleteTaskReq - 150, // 100: crabs.evening_detective_server.EveningDetectiveServer.GetParticipation:input_type -> crabs.evening_detective_server.GetParticipationReq - 151, // 101: crabs.evening_detective_server.EveningDetectiveServer.AnswerParticipation:input_type -> crabs.evening_detective_server.AnswerParticipationReq - 4, // 102: crabs.evening_detective_server.EveningDetectiveServer.Ping:input_type -> crabs.evening_detective_server.PingReq - 6, // 103: crabs.evening_detective_server.EveningDetectiveServer.Echo:input_type -> crabs.evening_detective_server.EchoReq - 8, // 104: crabs.evening_detective_server.EveningDetectiveServer.Signup:input_type -> crabs.evening_detective_server.SignupReq - 10, // 105: crabs.evening_detective_server.EveningDetectiveServer.RefreshPassword:input_type -> crabs.evening_detective_server.RefreshPasswordReq - 12, // 106: crabs.evening_detective_server.EveningDetectiveServer.Login:input_type -> crabs.evening_detective_server.LoginReq - 14, // 107: crabs.evening_detective_server.EveningDetectiveServer.Refresh:input_type -> crabs.evening_detective_server.RefreshReq - 16, // 108: crabs.evening_detective_server.EveningDetectiveServer.DeleteAccount:input_type -> crabs.evening_detective_server.DeleteAccountReq - 18, // 109: crabs.evening_detective_server.EveningDetectiveServer.GetTerms:input_type -> crabs.evening_detective_server.GetTermsReq - 20, // 110: crabs.evening_detective_server.EveningDetectiveServer.GetPrivacy:input_type -> crabs.evening_detective_server.GetPrivacyReq - 22, // 111: crabs.evening_detective_server.EveningDetectiveServer.GetConsent:input_type -> crabs.evening_detective_server.GetConsentReq - 24, // 112: crabs.evening_detective_server.EveningDetectiveServer.GetUsers:input_type -> crabs.evening_detective_server.GetUsersReq - 27, // 113: crabs.evening_detective_server.EveningDetectiveServer.GetUserByID:input_type -> crabs.evening_detective_server.GetUserByIDReq - 29, // 114: crabs.evening_detective_server.EveningDetectiveServer.GetMe:input_type -> crabs.evening_detective_server.GetMeReq - 31, // 115: crabs.evening_detective_server.EveningDetectiveServer.ChangeUserPassword:input_type -> crabs.evening_detective_server.ChangeUserPasswordReq - 33, // 116: crabs.evening_detective_server.EveningDetectiveServer.AddUserRole:input_type -> crabs.evening_detective_server.AddUserRoleReq - 35, // 117: crabs.evening_detective_server.EveningDetectiveServer.DeleteUserRole:input_type -> crabs.evening_detective_server.DeleteUserRoleReq - 37, // 118: crabs.evening_detective_server.EveningDetectiveServer.GetPermissions:input_type -> crabs.evening_detective_server.GetPermissionsReq - 39, // 119: crabs.evening_detective_server.EveningDetectiveServer.UploadFile:input_type -> crabs.evening_detective_server.UploadFileReq - 41, // 120: crabs.evening_detective_server.EveningDetectiveServer.DownloadFile:input_type -> crabs.evening_detective_server.DownloadFileReq - 44, // 121: crabs.evening_detective_server.EveningDetectiveServer.GetPlaylists:input_type -> crabs.evening_detective_server.GetPlaylistsReq - 46, // 122: crabs.evening_detective_server.EveningDetectiveServer.CreatePlaylist:input_type -> crabs.evening_detective_server.CreatePlaylistReq - 48, // 123: crabs.evening_detective_server.EveningDetectiveServer.UpdatePlaylist:input_type -> crabs.evening_detective_server.UpdatePlaylistReq - 50, // 124: crabs.evening_detective_server.EveningDetectiveServer.DeletePlaylist:input_type -> crabs.evening_detective_server.DeletePlaylistReq - 52, // 125: crabs.evening_detective_server.EveningDetectiveServer.UploadPlaylistTrack:input_type -> crabs.evening_detective_server.UploadPlaylistTrackReq - 54, // 126: crabs.evening_detective_server.EveningDetectiveServer.DeletePlaylistTrack:input_type -> crabs.evening_detective_server.DeletePlaylistTrackReq - 56, // 127: crabs.evening_detective_server.EveningDetectiveServer.SetScenarioPlaylist:input_type -> crabs.evening_detective_server.SetScenarioPlaylistReq - 58, // 128: crabs.evening_detective_server.EveningDetectiveServer.AddScenario:input_type -> crabs.evening_detective_server.AddScenarioReq - 60, // 129: crabs.evening_detective_server.EveningDetectiveServer.GetMyScenarios:input_type -> crabs.evening_detective_server.GetMyScenariosReq - 62, // 130: crabs.evening_detective_server.EveningDetectiveServer.GetScenariosCatalog:input_type -> crabs.evening_detective_server.GetScenariosCatalogReq - 64, // 131: crabs.evening_detective_server.EveningDetectiveServer.GetFullScenario:input_type -> crabs.evening_detective_server.GetScenarioReq - 64, // 132: crabs.evening_detective_server.EveningDetectiveServer.GetScenario:input_type -> crabs.evening_detective_server.GetScenarioReq - 78, // 133: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenario:input_type -> crabs.evening_detective_server.UpdateScenarioReq - 80, // 134: crabs.evening_detective_server.EveningDetectiveServer.PublicScenario:input_type -> crabs.evening_detective_server.PublicScenarioReq - 82, // 135: crabs.evening_detective_server.EveningDetectiveServer.DraftScenario:input_type -> crabs.evening_detective_server.DraftScenarioReq - 84, // 136: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenario:input_type -> crabs.evening_detective_server.DeleteScenarioReq - 86, // 137: crabs.evening_detective_server.EveningDetectiveServer.AddScenarioPlace:input_type -> crabs.evening_detective_server.AddScenarioPlaceReq - 88, // 138: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioPlace:input_type -> crabs.evening_detective_server.UpdateScenarioPlaceReq - 90, // 139: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenarioPlace:input_type -> crabs.evening_detective_server.DeleteScenarioPlaceReq - 96, // 140: crabs.evening_detective_server.EveningDetectiveServer.AddScenarioQuestion:input_type -> crabs.evening_detective_server.AddScenarioQuestionReq - 98, // 141: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioQuestion:input_type -> crabs.evening_detective_server.UpdateScenarioQuestionReq - 100, // 142: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenarioQuestion:input_type -> crabs.evening_detective_server.DeleteScenarioQuestionReq - 206, // 143: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioBackground:input_type -> crabs.evening_detective_server.UpdateScenarioBackgroundReq - 94, // 144: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioIntro:input_type -> crabs.evening_detective_server.UpdateScenarioIntroReq - 92, // 145: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioConclusion:input_type -> crabs.evening_detective_server.UpdateScenarioConclusionReq - 102, // 146: crabs.evening_detective_server.EveningDetectiveServer.DownloadScenarioArchive:input_type -> crabs.evening_detective_server.DownloadScenarioArchiveReq - 229, // 147: crabs.evening_detective_server.EveningDetectiveServer.UploadScenarioArchive:input_type -> google.api.HttpBody - 104, // 148: crabs.evening_detective_server.EveningDetectiveServer.AddGame:input_type -> crabs.evening_detective_server.AddGameReq - 106, // 149: crabs.evening_detective_server.EveningDetectiveServer.GetGames:input_type -> crabs.evening_detective_server.GetGamesReq - 154, // 150: crabs.evening_detective_server.EveningDetectiveServer.GetGame:input_type -> crabs.evening_detective_server.GetGameReq - 208, // 151: crabs.evening_detective_server.EveningDetectiveServer.IssueGameTickets:input_type -> crabs.evening_detective_server.IssueGameTicketsReq - 211, // 152: crabs.evening_detective_server.EveningDetectiveServer.GetTicket:input_type -> crabs.evening_detective_server.GetTicketReq - 213, // 153: crabs.evening_detective_server.EveningDetectiveServer.AcceptTicket:input_type -> crabs.evening_detective_server.AcceptTicketReq - 110, // 154: crabs.evening_detective_server.EveningDetectiveServer.CreateScreenSession:input_type -> crabs.evening_detective_server.CreateScreenSessionReq - 112, // 155: crabs.evening_detective_server.EveningDetectiveServer.GetScreenState:input_type -> crabs.evening_detective_server.GetScreenStateReq - 114, // 156: crabs.evening_detective_server.EveningDetectiveServer.GetGameScreens:input_type -> crabs.evening_detective_server.GetGameScreensReq - 117, // 157: crabs.evening_detective_server.EveningDetectiveServer.GetGameMusic:input_type -> crabs.evening_detective_server.GetGameMusicReq - 119, // 158: crabs.evening_detective_server.EveningDetectiveServer.SetGameMusic:input_type -> crabs.evening_detective_server.SetGameMusicReq - 121, // 159: crabs.evening_detective_server.EveningDetectiveServer.AdvanceScreenMusic:input_type -> crabs.evening_detective_server.AdvanceScreenMusicReq - 123, // 160: crabs.evening_detective_server.EveningDetectiveServer.BindScreen:input_type -> crabs.evening_detective_server.BindScreenReq - 125, // 161: crabs.evening_detective_server.EveningDetectiveServer.UnbindScreen:input_type -> crabs.evening_detective_server.UnbindScreenReq - 127, // 162: crabs.evening_detective_server.EveningDetectiveServer.SetScreenSound:input_type -> crabs.evening_detective_server.SetScreenSoundReq - 130, // 163: crabs.evening_detective_server.EveningDetectiveServer.GetGameMap:input_type -> crabs.evening_detective_server.GetGameMapReq - 132, // 164: crabs.evening_detective_server.EveningDetectiveServer.UpdateGameMapItem:input_type -> crabs.evening_detective_server.UpdateGameMapItemReq - 134, // 165: crabs.evening_detective_server.EveningDetectiveServer.SetScreenMode:input_type -> crabs.evening_detective_server.SetScreenModeReq - 136, // 166: crabs.evening_detective_server.EveningDetectiveServer.SetScreenTimer:input_type -> crabs.evening_detective_server.SetScreenTimerReq - 138, // 167: crabs.evening_detective_server.EveningDetectiveServer.SendScreenCommand:input_type -> crabs.evening_detective_server.SendScreenCommandReq - 142, // 168: crabs.evening_detective_server.EveningDetectiveServer.GetScreenPlan:input_type -> crabs.evening_detective_server.GetScreenPlanReq - 144, // 169: crabs.evening_detective_server.EveningDetectiveServer.SaveScreenPlan:input_type -> crabs.evening_detective_server.SaveScreenPlanReq - 146, // 170: crabs.evening_detective_server.EveningDetectiveServer.SetScreenPlanStep:input_type -> crabs.evening_detective_server.SetScreenPlanStepReq - 148, // 171: crabs.evening_detective_server.EveningDetectiveServer.GetScreenResults:input_type -> crabs.evening_detective_server.GetScreenResultsReq - 154, // 172: crabs.evening_detective_server.EveningDetectiveServer.DownloadTeamQR:input_type -> crabs.evening_detective_server.GetGameReq - 156, // 173: crabs.evening_detective_server.EveningDetectiveServer.GetGameAnswers:input_type -> crabs.evening_detective_server.GetGameAnswersReq - 158, // 174: crabs.evening_detective_server.EveningDetectiveServer.GetGameResults:input_type -> crabs.evening_detective_server.GetGameResultsReq - 163, // 175: crabs.evening_detective_server.EveningDetectiveServer.CreateGameReview:input_type -> crabs.evening_detective_server.CreateGameReviewReq - 165, // 176: crabs.evening_detective_server.EveningDetectiveServer.GetGameReviews:input_type -> crabs.evening_detective_server.GetGameReviewsReq - 166, // 177: crabs.evening_detective_server.EveningDetectiveServer.GetScenarioReviews:input_type -> crabs.evening_detective_server.GetScenarioReviewsReq - 165, // 178: crabs.evening_detective_server.EveningDetectiveServer.GetGameReviewsForModeration:input_type -> crabs.evening_detective_server.GetGameReviewsReq - 167, // 179: crabs.evening_detective_server.EveningDetectiveServer.GetReviewsForModeration:input_type -> crabs.evening_detective_server.GetReviewsForModerationReq - 169, // 180: crabs.evening_detective_server.EveningDetectiveServer.ModerateGameReview:input_type -> crabs.evening_detective_server.ModerateGameReviewReq - 171, // 181: crabs.evening_detective_server.EveningDetectiveServer.UpdateGame:input_type -> crabs.evening_detective_server.UpdateGameReq - 173, // 182: crabs.evening_detective_server.EveningDetectiveServer.StartGame:input_type -> crabs.evening_detective_server.StartGameReq - 175, // 183: crabs.evening_detective_server.EveningDetectiveServer.PauseGame:input_type -> crabs.evening_detective_server.PauseGameReq - 177, // 184: crabs.evening_detective_server.EveningDetectiveServer.PlayGame:input_type -> crabs.evening_detective_server.PlayGameReq - 179, // 185: crabs.evening_detective_server.EveningDetectiveServer.FinishGame:input_type -> crabs.evening_detective_server.FinishGameReq - 181, // 186: crabs.evening_detective_server.EveningDetectiveServer.ResetGame:input_type -> crabs.evening_detective_server.ResetGameReq - 183, // 187: crabs.evening_detective_server.EveningDetectiveServer.DeleteGame:input_type -> crabs.evening_detective_server.DeleteGameReq - 185, // 188: crabs.evening_detective_server.EveningDetectiveServer.AddTeam:input_type -> crabs.evening_detective_server.AddTeamReq - 187, // 189: crabs.evening_detective_server.EveningDetectiveServer.UpdateTeam:input_type -> crabs.evening_detective_server.UpdateTeamReq - 189, // 190: crabs.evening_detective_server.EveningDetectiveServer.DeleteTeam:input_type -> crabs.evening_detective_server.DeleteTeamReq - 191, // 191: crabs.evening_detective_server.EveningDetectiveServer.GiveTeamApplications:input_type -> crabs.evening_detective_server.GiveTeamApplicationsReq - 193, // 192: crabs.evening_detective_server.EveningDetectiveServer.GetTeamStory:input_type -> crabs.evening_detective_server.GetTeamStoryReq - 196, // 193: crabs.evening_detective_server.EveningDetectiveServer.AddTeamAction:input_type -> crabs.evening_detective_server.AddTeamActionReq - 198, // 194: crabs.evening_detective_server.EveningDetectiveServer.DeleteLastTeamAction:input_type -> crabs.evening_detective_server.DeleteLastTeamActionReq - 200, // 195: crabs.evening_detective_server.EveningDetectiveServer.GetTeamAnswers:input_type -> crabs.evening_detective_server.GetTeamAnswersReq - 202, // 196: crabs.evening_detective_server.EveningDetectiveServer.SubmitTeamAnswers:input_type -> crabs.evening_detective_server.SubmitTeamAnswersReq - 204, // 197: crabs.evening_detective_server.EveningDetectiveServer.SetTeamAnswerScore:input_type -> crabs.evening_detective_server.SetTeamAnswerScoreReq - 219, // 198: crabs.evening_detective_server.EveningDetectiveServer.GetTasks:output_type -> crabs.evening_detective_server.GetTasksRsp - 221, // 199: crabs.evening_detective_server.EveningDetectiveServer.GetTaskAssignees:output_type -> crabs.evening_detective_server.GetTaskAssigneesRsp - 226, // 200: crabs.evening_detective_server.EveningDetectiveServer.CreateTask:output_type -> crabs.evening_detective_server.TaskRsp - 226, // 201: crabs.evening_detective_server.EveningDetectiveServer.UpdateTask:output_type -> crabs.evening_detective_server.TaskRsp - 226, // 202: crabs.evening_detective_server.EveningDetectiveServer.SetTaskStatus:output_type -> crabs.evening_detective_server.TaskRsp - 227, // 203: crabs.evening_detective_server.EveningDetectiveServer.DeleteTask:output_type -> crabs.evening_detective_server.DeleteTaskRsp - 152, // 204: crabs.evening_detective_server.EveningDetectiveServer.GetParticipation:output_type -> crabs.evening_detective_server.ParticipationRsp - 152, // 205: crabs.evening_detective_server.EveningDetectiveServer.AnswerParticipation:output_type -> crabs.evening_detective_server.ParticipationRsp - 5, // 206: crabs.evening_detective_server.EveningDetectiveServer.Ping:output_type -> crabs.evening_detective_server.PingRsp - 7, // 207: crabs.evening_detective_server.EveningDetectiveServer.Echo:output_type -> crabs.evening_detective_server.EchoRsp - 9, // 208: crabs.evening_detective_server.EveningDetectiveServer.Signup:output_type -> crabs.evening_detective_server.SignupRsp - 11, // 209: crabs.evening_detective_server.EveningDetectiveServer.RefreshPassword:output_type -> crabs.evening_detective_server.RefreshPasswordRsp - 13, // 210: crabs.evening_detective_server.EveningDetectiveServer.Login:output_type -> crabs.evening_detective_server.LoginRsp - 15, // 211: crabs.evening_detective_server.EveningDetectiveServer.Refresh:output_type -> crabs.evening_detective_server.RefreshRsp - 17, // 212: crabs.evening_detective_server.EveningDetectiveServer.DeleteAccount:output_type -> crabs.evening_detective_server.DeleteAccountRsp - 19, // 213: crabs.evening_detective_server.EveningDetectiveServer.GetTerms:output_type -> crabs.evening_detective_server.GetTermsRsp - 21, // 214: crabs.evening_detective_server.EveningDetectiveServer.GetPrivacy:output_type -> crabs.evening_detective_server.GetPrivacyRsp - 23, // 215: crabs.evening_detective_server.EveningDetectiveServer.GetConsent:output_type -> crabs.evening_detective_server.GetConsentRsp - 25, // 216: crabs.evening_detective_server.EveningDetectiveServer.GetUsers:output_type -> crabs.evening_detective_server.GetUsersRsp - 28, // 217: crabs.evening_detective_server.EveningDetectiveServer.GetUserByID:output_type -> crabs.evening_detective_server.GetUserByIDRsp - 30, // 218: crabs.evening_detective_server.EveningDetectiveServer.GetMe:output_type -> crabs.evening_detective_server.GetMeRsp - 32, // 219: crabs.evening_detective_server.EveningDetectiveServer.ChangeUserPassword:output_type -> crabs.evening_detective_server.ChangeUserPasswordRsp - 34, // 220: crabs.evening_detective_server.EveningDetectiveServer.AddUserRole:output_type -> crabs.evening_detective_server.AddUserRoleRsp - 36, // 221: crabs.evening_detective_server.EveningDetectiveServer.DeleteUserRole:output_type -> crabs.evening_detective_server.DeleteUserRoleRsp - 38, // 222: crabs.evening_detective_server.EveningDetectiveServer.GetPermissions:output_type -> crabs.evening_detective_server.GetPermissionsRsp - 40, // 223: crabs.evening_detective_server.EveningDetectiveServer.UploadFile:output_type -> crabs.evening_detective_server.UploadFileRsp - 229, // 224: crabs.evening_detective_server.EveningDetectiveServer.DownloadFile:output_type -> google.api.HttpBody - 45, // 225: crabs.evening_detective_server.EveningDetectiveServer.GetPlaylists:output_type -> crabs.evening_detective_server.GetPlaylistsRsp - 47, // 226: crabs.evening_detective_server.EveningDetectiveServer.CreatePlaylist:output_type -> crabs.evening_detective_server.CreatePlaylistRsp - 49, // 227: crabs.evening_detective_server.EveningDetectiveServer.UpdatePlaylist:output_type -> crabs.evening_detective_server.UpdatePlaylistRsp - 51, // 228: crabs.evening_detective_server.EveningDetectiveServer.DeletePlaylist:output_type -> crabs.evening_detective_server.DeletePlaylistRsp - 53, // 229: crabs.evening_detective_server.EveningDetectiveServer.UploadPlaylistTrack:output_type -> crabs.evening_detective_server.UploadPlaylistTrackRsp - 55, // 230: crabs.evening_detective_server.EveningDetectiveServer.DeletePlaylistTrack:output_type -> crabs.evening_detective_server.DeletePlaylistTrackRsp - 57, // 231: crabs.evening_detective_server.EveningDetectiveServer.SetScenarioPlaylist:output_type -> crabs.evening_detective_server.SetScenarioPlaylistRsp - 59, // 232: crabs.evening_detective_server.EveningDetectiveServer.AddScenario:output_type -> crabs.evening_detective_server.AddScenarioRsp - 61, // 233: crabs.evening_detective_server.EveningDetectiveServer.GetMyScenarios:output_type -> crabs.evening_detective_server.GetMyScenariosRsp - 63, // 234: crabs.evening_detective_server.EveningDetectiveServer.GetScenariosCatalog:output_type -> crabs.evening_detective_server.GetScenariosCatalogRsp - 65, // 235: crabs.evening_detective_server.EveningDetectiveServer.GetFullScenario:output_type -> crabs.evening_detective_server.GetScenarioRsp - 65, // 236: crabs.evening_detective_server.EveningDetectiveServer.GetScenario:output_type -> crabs.evening_detective_server.GetScenarioRsp - 79, // 237: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenario:output_type -> crabs.evening_detective_server.UpdateScenarioRsp - 81, // 238: crabs.evening_detective_server.EveningDetectiveServer.PublicScenario:output_type -> crabs.evening_detective_server.PublicScenarioRsp - 83, // 239: crabs.evening_detective_server.EveningDetectiveServer.DraftScenario:output_type -> crabs.evening_detective_server.DraftScenarioRsp - 85, // 240: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenario:output_type -> crabs.evening_detective_server.DeleteScenarioRsp - 87, // 241: crabs.evening_detective_server.EveningDetectiveServer.AddScenarioPlace:output_type -> crabs.evening_detective_server.AddScenarioPlaceRsp - 89, // 242: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioPlace:output_type -> crabs.evening_detective_server.UpdateScenarioPlaceRsp - 91, // 243: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenarioPlace:output_type -> crabs.evening_detective_server.DeleteScenarioPlaceRsp - 97, // 244: crabs.evening_detective_server.EveningDetectiveServer.AddScenarioQuestion:output_type -> crabs.evening_detective_server.AddScenarioQuestionRsp - 99, // 245: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioQuestion:output_type -> crabs.evening_detective_server.UpdateScenarioQuestionRsp - 101, // 246: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenarioQuestion:output_type -> crabs.evening_detective_server.DeleteScenarioQuestionRsp - 207, // 247: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioBackground:output_type -> crabs.evening_detective_server.UpdateScenarioBackgroundRsp - 95, // 248: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioIntro:output_type -> crabs.evening_detective_server.UpdateScenarioIntroRsp - 93, // 249: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioConclusion:output_type -> crabs.evening_detective_server.UpdateScenarioConclusionRsp - 229, // 250: crabs.evening_detective_server.EveningDetectiveServer.DownloadScenarioArchive:output_type -> google.api.HttpBody - 103, // 251: crabs.evening_detective_server.EveningDetectiveServer.UploadScenarioArchive:output_type -> crabs.evening_detective_server.UploadScenarioArchiveRsp - 105, // 252: crabs.evening_detective_server.EveningDetectiveServer.AddGame:output_type -> crabs.evening_detective_server.AddGameRsp - 107, // 253: crabs.evening_detective_server.EveningDetectiveServer.GetGames:output_type -> crabs.evening_detective_server.GetGamesRsp - 155, // 254: crabs.evening_detective_server.EveningDetectiveServer.GetGame:output_type -> crabs.evening_detective_server.GetGameRsp - 209, // 255: crabs.evening_detective_server.EveningDetectiveServer.IssueGameTickets:output_type -> crabs.evening_detective_server.IssueGameTicketsRsp - 212, // 256: crabs.evening_detective_server.EveningDetectiveServer.GetTicket:output_type -> crabs.evening_detective_server.GetTicketRsp - 214, // 257: crabs.evening_detective_server.EveningDetectiveServer.AcceptTicket:output_type -> crabs.evening_detective_server.AcceptTicketRsp - 111, // 258: crabs.evening_detective_server.EveningDetectiveServer.CreateScreenSession:output_type -> crabs.evening_detective_server.CreateScreenSessionRsp - 113, // 259: crabs.evening_detective_server.EveningDetectiveServer.GetScreenState:output_type -> crabs.evening_detective_server.GetScreenStateRsp - 115, // 260: crabs.evening_detective_server.EveningDetectiveServer.GetGameScreens:output_type -> crabs.evening_detective_server.GetGameScreensRsp - 118, // 261: crabs.evening_detective_server.EveningDetectiveServer.GetGameMusic:output_type -> crabs.evening_detective_server.GetGameMusicRsp - 120, // 262: crabs.evening_detective_server.EveningDetectiveServer.SetGameMusic:output_type -> crabs.evening_detective_server.SetGameMusicRsp - 122, // 263: crabs.evening_detective_server.EveningDetectiveServer.AdvanceScreenMusic:output_type -> crabs.evening_detective_server.AdvanceScreenMusicRsp - 124, // 264: crabs.evening_detective_server.EveningDetectiveServer.BindScreen:output_type -> crabs.evening_detective_server.BindScreenRsp - 126, // 265: crabs.evening_detective_server.EveningDetectiveServer.UnbindScreen:output_type -> crabs.evening_detective_server.UnbindScreenRsp - 128, // 266: crabs.evening_detective_server.EveningDetectiveServer.SetScreenSound:output_type -> crabs.evening_detective_server.SetScreenSoundRsp - 131, // 267: crabs.evening_detective_server.EveningDetectiveServer.GetGameMap:output_type -> crabs.evening_detective_server.GetGameMapRsp - 133, // 268: crabs.evening_detective_server.EveningDetectiveServer.UpdateGameMapItem:output_type -> crabs.evening_detective_server.UpdateGameMapItemRsp - 135, // 269: crabs.evening_detective_server.EveningDetectiveServer.SetScreenMode:output_type -> crabs.evening_detective_server.SetScreenModeRsp - 137, // 270: crabs.evening_detective_server.EveningDetectiveServer.SetScreenTimer:output_type -> crabs.evening_detective_server.SetScreenTimerRsp - 139, // 271: crabs.evening_detective_server.EveningDetectiveServer.SendScreenCommand:output_type -> crabs.evening_detective_server.SendScreenCommandRsp - 143, // 272: crabs.evening_detective_server.EveningDetectiveServer.GetScreenPlan:output_type -> crabs.evening_detective_server.GetScreenPlanRsp - 145, // 273: crabs.evening_detective_server.EveningDetectiveServer.SaveScreenPlan:output_type -> crabs.evening_detective_server.SaveScreenPlanRsp - 147, // 274: crabs.evening_detective_server.EveningDetectiveServer.SetScreenPlanStep:output_type -> crabs.evening_detective_server.SetScreenPlanStepRsp - 149, // 275: crabs.evening_detective_server.EveningDetectiveServer.GetScreenResults:output_type -> crabs.evening_detective_server.GetScreenResultsRsp - 229, // 276: crabs.evening_detective_server.EveningDetectiveServer.DownloadTeamQR:output_type -> google.api.HttpBody - 157, // 277: crabs.evening_detective_server.EveningDetectiveServer.GetGameAnswers:output_type -> crabs.evening_detective_server.GetGameAnswersRsp - 161, // 278: crabs.evening_detective_server.EveningDetectiveServer.GetGameResults:output_type -> crabs.evening_detective_server.GetGameResultsRsp - 164, // 279: crabs.evening_detective_server.EveningDetectiveServer.CreateGameReview:output_type -> crabs.evening_detective_server.CreateGameReviewRsp - 168, // 280: crabs.evening_detective_server.EveningDetectiveServer.GetGameReviews:output_type -> crabs.evening_detective_server.GetGameReviewsRsp - 168, // 281: crabs.evening_detective_server.EveningDetectiveServer.GetScenarioReviews:output_type -> crabs.evening_detective_server.GetGameReviewsRsp - 168, // 282: crabs.evening_detective_server.EveningDetectiveServer.GetGameReviewsForModeration:output_type -> crabs.evening_detective_server.GetGameReviewsRsp - 168, // 283: crabs.evening_detective_server.EveningDetectiveServer.GetReviewsForModeration:output_type -> crabs.evening_detective_server.GetGameReviewsRsp - 170, // 284: crabs.evening_detective_server.EveningDetectiveServer.ModerateGameReview:output_type -> crabs.evening_detective_server.ModerateGameReviewRsp - 172, // 285: crabs.evening_detective_server.EveningDetectiveServer.UpdateGame:output_type -> crabs.evening_detective_server.UpdateGameRsp - 174, // 286: crabs.evening_detective_server.EveningDetectiveServer.StartGame:output_type -> crabs.evening_detective_server.StartGameRsp - 176, // 287: crabs.evening_detective_server.EveningDetectiveServer.PauseGame:output_type -> crabs.evening_detective_server.PauseGameRsp - 178, // 288: crabs.evening_detective_server.EveningDetectiveServer.PlayGame:output_type -> crabs.evening_detective_server.PlayGameRsp - 180, // 289: crabs.evening_detective_server.EveningDetectiveServer.FinishGame:output_type -> crabs.evening_detective_server.FinishGameRsp - 182, // 290: crabs.evening_detective_server.EveningDetectiveServer.ResetGame:output_type -> crabs.evening_detective_server.ResetGameRsp - 184, // 291: crabs.evening_detective_server.EveningDetectiveServer.DeleteGame:output_type -> crabs.evening_detective_server.DeleteGameRsp - 186, // 292: crabs.evening_detective_server.EveningDetectiveServer.AddTeam:output_type -> crabs.evening_detective_server.AddTeamRsp - 188, // 293: crabs.evening_detective_server.EveningDetectiveServer.UpdateTeam:output_type -> crabs.evening_detective_server.UpdateTeamRsp - 190, // 294: crabs.evening_detective_server.EveningDetectiveServer.DeleteTeam:output_type -> crabs.evening_detective_server.DeleteTeamRsp - 192, // 295: crabs.evening_detective_server.EveningDetectiveServer.GiveTeamApplications:output_type -> crabs.evening_detective_server.GiveTeamApplicationsRsp - 194, // 296: crabs.evening_detective_server.EveningDetectiveServer.GetTeamStory:output_type -> crabs.evening_detective_server.GetTeamStoryRsp - 197, // 297: crabs.evening_detective_server.EveningDetectiveServer.AddTeamAction:output_type -> crabs.evening_detective_server.AddTeamActionRsp - 199, // 298: crabs.evening_detective_server.EveningDetectiveServer.DeleteLastTeamAction:output_type -> crabs.evening_detective_server.DeleteLastTeamActionRsp - 201, // 299: crabs.evening_detective_server.EveningDetectiveServer.GetTeamAnswers:output_type -> crabs.evening_detective_server.GetTeamAnswersRsp - 203, // 300: crabs.evening_detective_server.EveningDetectiveServer.SubmitTeamAnswers:output_type -> crabs.evening_detective_server.SubmitTeamAnswersRsp - 205, // 301: crabs.evening_detective_server.EveningDetectiveServer.SetTeamAnswerScore:output_type -> crabs.evening_detective_server.SetTeamAnswerScoreRsp - 198, // [198:302] is the sub-list for method output_type - 94, // [94:198] is the sub-list for method input_type - 94, // [94:94] is the sub-list for extension type_name - 94, // [94:94] is the sub-list for extension extendee - 0, // [0:94] is the sub-list for field type_name + 157, // 37: crabs.evening_detective_server.Game.teams:type_name -> crabs.evening_detective_server.Team + 232, // 38: crabs.evening_detective_server.Game.started_at:type_name -> google.protobuf.Timestamp + 232, // 39: crabs.evening_detective_server.Game.ended_at:type_name -> google.protobuf.Timestamp + 109, // 40: crabs.evening_detective_server.Game.export:type_name -> crabs.evening_detective_server.GameExport + 109, // 41: crabs.evening_detective_server.GameExportRsp.export:type_name -> crabs.evening_detective_server.GameExport + 0, // 42: crabs.evening_detective_server.ScreenState.mode:type_name -> crabs.evening_detective_server.ScreenMode + 2, // 43: crabs.evening_detective_server.ScreenState.command:type_name -> crabs.evening_detective_server.ScreenCommand + 1, // 44: crabs.evening_detective_server.ScreenState.timer_state:type_name -> crabs.evening_detective_server.ScreenTimerState + 120, // 45: crabs.evening_detective_server.ScreenState.music:type_name -> crabs.evening_detective_server.MusicState + 113, // 46: crabs.evening_detective_server.GetScreenStateRsp.state:type_name -> crabs.evening_detective_server.ScreenState + 113, // 47: crabs.evening_detective_server.GetGameScreensRsp.screens:type_name -> crabs.evening_detective_server.ScreenState + 43, // 48: crabs.evening_detective_server.MusicState.playlist:type_name -> crabs.evening_detective_server.Playlist + 3, // 49: crabs.evening_detective_server.MusicState.playback:type_name -> crabs.evening_detective_server.MusicPlaybackState + 43, // 50: crabs.evening_detective_server.GetGameMusicRsp.playlists:type_name -> crabs.evening_detective_server.Playlist + 120, // 51: crabs.evening_detective_server.GetGameMusicRsp.state:type_name -> crabs.evening_detective_server.MusicState + 3, // 52: crabs.evening_detective_server.SetGameMusicReq.playback:type_name -> crabs.evening_detective_server.MusicPlaybackState + 120, // 53: crabs.evening_detective_server.SetGameMusicRsp.state:type_name -> crabs.evening_detective_server.MusicState + 120, // 54: crabs.evening_detective_server.AdvanceScreenMusicRsp.state:type_name -> crabs.evening_detective_server.MusicState + 113, // 55: crabs.evening_detective_server.BindScreenRsp.state:type_name -> crabs.evening_detective_server.ScreenState + 133, // 56: crabs.evening_detective_server.GetGameMapRsp.items:type_name -> crabs.evening_detective_server.MapItem + 0, // 57: crabs.evening_detective_server.SetScreenModeReq.mode:type_name -> crabs.evening_detective_server.ScreenMode + 2, // 58: crabs.evening_detective_server.SendScreenCommandReq.command:type_name -> crabs.evening_detective_server.ScreenCommand + 0, // 59: crabs.evening_detective_server.ScreenPlanStep.mode:type_name -> crabs.evening_detective_server.ScreenMode + 144, // 60: crabs.evening_detective_server.ScreenPlan.steps:type_name -> crabs.evening_detective_server.ScreenPlanStep + 145, // 61: crabs.evening_detective_server.GetScreenPlanRsp.plan:type_name -> crabs.evening_detective_server.ScreenPlan + 144, // 62: crabs.evening_detective_server.SaveScreenPlanReq.steps:type_name -> crabs.evening_detective_server.ScreenPlanStep + 145, // 63: crabs.evening_detective_server.SaveScreenPlanRsp.plan:type_name -> crabs.evening_detective_server.ScreenPlan + 145, // 64: crabs.evening_detective_server.SetScreenPlanStepRsp.plan:type_name -> crabs.evening_detective_server.ScreenPlan + 163, // 65: crabs.evening_detective_server.GetScreenResultsRsp.questions:type_name -> crabs.evening_detective_server.ResultsQuestion + 164, // 66: crabs.evening_detective_server.GetScreenResultsRsp.teams:type_name -> crabs.evening_detective_server.TeamResult + 232, // 67: crabs.evening_detective_server.ParticipationRsp.start_at:type_name -> google.protobuf.Timestamp + 71, // 68: crabs.evening_detective_server.Team.applications:type_name -> crabs.evening_detective_server.Application + 108, // 69: crabs.evening_detective_server.GetGameRsp.game:type_name -> crabs.evening_detective_server.Game + 74, // 70: crabs.evening_detective_server.GetGameAnswersRsp.questions:type_name -> crabs.evening_detective_server.Question + 77, // 71: crabs.evening_detective_server.GetGameAnswersRsp.teams:type_name -> crabs.evening_detective_server.TeamAnswers + 157, // 72: crabs.evening_detective_server.TeamResult.team:type_name -> crabs.evening_detective_server.Team + 76, // 73: crabs.evening_detective_server.TeamResult.answers:type_name -> crabs.evening_detective_server.AnswerScore + 163, // 74: crabs.evening_detective_server.GetGameResultsRsp.questions:type_name -> crabs.evening_detective_server.ResultsQuestion + 164, // 75: crabs.evening_detective_server.GetGameResultsRsp.teams:type_name -> crabs.evening_detective_server.TeamResult + 232, // 76: crabs.evening_detective_server.GameReview.created_at:type_name -> google.protobuf.Timestamp + 166, // 77: crabs.evening_detective_server.CreateGameReviewRsp.review:type_name -> crabs.evening_detective_server.GameReview + 166, // 78: crabs.evening_detective_server.GetGameReviewsRsp.reviews:type_name -> crabs.evening_detective_server.GameReview + 166, // 79: crabs.evening_detective_server.ModerateGameReviewRsp.review:type_name -> crabs.evening_detective_server.GameReview + 232, // 80: crabs.evening_detective_server.UpdateGameReq.start_at:type_name -> google.protobuf.Timestamp + 67, // 81: crabs.evening_detective_server.GetTeamStoryRsp.story:type_name -> crabs.evening_detective_server.Story + 108, // 82: crabs.evening_detective_server.GetTeamStoryRsp.game:type_name -> crabs.evening_detective_server.Game + 199, // 83: crabs.evening_detective_server.GetTeamStoryRsp.actions:type_name -> crabs.evening_detective_server.TeamAction + 75, // 84: crabs.evening_detective_server.GetTeamAnswersRsp.answers:type_name -> crabs.evening_detective_server.Answer + 75, // 85: crabs.evening_detective_server.SubmitTeamAnswersReq.answers:type_name -> crabs.evening_detective_server.Answer + 214, // 86: crabs.evening_detective_server.IssueGameTicketsRsp.tickets:type_name -> crabs.evening_detective_server.Ticket + 219, // 87: crabs.evening_detective_server.GetTicketRsp.ticket:type_name -> crabs.evening_detective_server.TicketPage + 219, // 88: crabs.evening_detective_server.AcceptTicketRsp.ticket:type_name -> crabs.evening_detective_server.TicketPage + 232, // 89: crabs.evening_detective_server.TicketPage.start_at:type_name -> google.protobuf.Timestamp + 232, // 90: crabs.evening_detective_server.TicketPage.used_at:type_name -> google.protobuf.Timestamp + 232, // 91: crabs.evening_detective_server.DeveloperTask.createdAt:type_name -> google.protobuf.Timestamp + 232, // 92: crabs.evening_detective_server.DeveloperTask.updatedAt:type_name -> google.protobuf.Timestamp + 220, // 93: crabs.evening_detective_server.GetTasksRsp.tasks:type_name -> crabs.evening_detective_server.DeveloperTask + 221, // 94: crabs.evening_detective_server.GetTaskAssigneesRsp.assignees:type_name -> crabs.evening_detective_server.TaskAssignee + 220, // 95: crabs.evening_detective_server.TaskRsp.task:type_name -> crabs.evening_detective_server.DeveloperTask + 222, // 96: crabs.evening_detective_server.EveningDetectiveServer.GetTasks:input_type -> crabs.evening_detective_server.GetTasksReq + 224, // 97: crabs.evening_detective_server.EveningDetectiveServer.GetTaskAssignees:input_type -> crabs.evening_detective_server.GetTaskAssigneesReq + 226, // 98: crabs.evening_detective_server.EveningDetectiveServer.CreateTask:input_type -> crabs.evening_detective_server.CreateTaskReq + 227, // 99: crabs.evening_detective_server.EveningDetectiveServer.UpdateTask:input_type -> crabs.evening_detective_server.UpdateTaskReq + 228, // 100: crabs.evening_detective_server.EveningDetectiveServer.SetTaskStatus:input_type -> crabs.evening_detective_server.SetTaskStatusReq + 229, // 101: crabs.evening_detective_server.EveningDetectiveServer.DeleteTask:input_type -> crabs.evening_detective_server.DeleteTaskReq + 154, // 102: crabs.evening_detective_server.EveningDetectiveServer.GetParticipation:input_type -> crabs.evening_detective_server.GetParticipationReq + 155, // 103: crabs.evening_detective_server.EveningDetectiveServer.AnswerParticipation:input_type -> crabs.evening_detective_server.AnswerParticipationReq + 4, // 104: crabs.evening_detective_server.EveningDetectiveServer.Ping:input_type -> crabs.evening_detective_server.PingReq + 6, // 105: crabs.evening_detective_server.EveningDetectiveServer.Echo:input_type -> crabs.evening_detective_server.EchoReq + 8, // 106: crabs.evening_detective_server.EveningDetectiveServer.Signup:input_type -> crabs.evening_detective_server.SignupReq + 10, // 107: crabs.evening_detective_server.EveningDetectiveServer.RefreshPassword:input_type -> crabs.evening_detective_server.RefreshPasswordReq + 12, // 108: crabs.evening_detective_server.EveningDetectiveServer.Login:input_type -> crabs.evening_detective_server.LoginReq + 14, // 109: crabs.evening_detective_server.EveningDetectiveServer.Refresh:input_type -> crabs.evening_detective_server.RefreshReq + 16, // 110: crabs.evening_detective_server.EveningDetectiveServer.DeleteAccount:input_type -> crabs.evening_detective_server.DeleteAccountReq + 18, // 111: crabs.evening_detective_server.EveningDetectiveServer.GetTerms:input_type -> crabs.evening_detective_server.GetTermsReq + 20, // 112: crabs.evening_detective_server.EveningDetectiveServer.GetPrivacy:input_type -> crabs.evening_detective_server.GetPrivacyReq + 22, // 113: crabs.evening_detective_server.EveningDetectiveServer.GetConsent:input_type -> crabs.evening_detective_server.GetConsentReq + 24, // 114: crabs.evening_detective_server.EveningDetectiveServer.GetUsers:input_type -> crabs.evening_detective_server.GetUsersReq + 27, // 115: crabs.evening_detective_server.EveningDetectiveServer.GetUserByID:input_type -> crabs.evening_detective_server.GetUserByIDReq + 29, // 116: crabs.evening_detective_server.EveningDetectiveServer.GetMe:input_type -> crabs.evening_detective_server.GetMeReq + 31, // 117: crabs.evening_detective_server.EveningDetectiveServer.ChangeUserPassword:input_type -> crabs.evening_detective_server.ChangeUserPasswordReq + 33, // 118: crabs.evening_detective_server.EveningDetectiveServer.AddUserRole:input_type -> crabs.evening_detective_server.AddUserRoleReq + 35, // 119: crabs.evening_detective_server.EveningDetectiveServer.DeleteUserRole:input_type -> crabs.evening_detective_server.DeleteUserRoleReq + 37, // 120: crabs.evening_detective_server.EveningDetectiveServer.GetPermissions:input_type -> crabs.evening_detective_server.GetPermissionsReq + 39, // 121: crabs.evening_detective_server.EveningDetectiveServer.UploadFile:input_type -> crabs.evening_detective_server.UploadFileReq + 41, // 122: crabs.evening_detective_server.EveningDetectiveServer.DownloadFile:input_type -> crabs.evening_detective_server.DownloadFileReq + 44, // 123: crabs.evening_detective_server.EveningDetectiveServer.GetPlaylists:input_type -> crabs.evening_detective_server.GetPlaylistsReq + 46, // 124: crabs.evening_detective_server.EveningDetectiveServer.CreatePlaylist:input_type -> crabs.evening_detective_server.CreatePlaylistReq + 48, // 125: crabs.evening_detective_server.EveningDetectiveServer.UpdatePlaylist:input_type -> crabs.evening_detective_server.UpdatePlaylistReq + 50, // 126: crabs.evening_detective_server.EveningDetectiveServer.DeletePlaylist:input_type -> crabs.evening_detective_server.DeletePlaylistReq + 52, // 127: crabs.evening_detective_server.EveningDetectiveServer.UploadPlaylistTrack:input_type -> crabs.evening_detective_server.UploadPlaylistTrackReq + 54, // 128: crabs.evening_detective_server.EveningDetectiveServer.DeletePlaylistTrack:input_type -> crabs.evening_detective_server.DeletePlaylistTrackReq + 56, // 129: crabs.evening_detective_server.EveningDetectiveServer.SetScenarioPlaylist:input_type -> crabs.evening_detective_server.SetScenarioPlaylistReq + 58, // 130: crabs.evening_detective_server.EveningDetectiveServer.AddScenario:input_type -> crabs.evening_detective_server.AddScenarioReq + 60, // 131: crabs.evening_detective_server.EveningDetectiveServer.GetMyScenarios:input_type -> crabs.evening_detective_server.GetMyScenariosReq + 62, // 132: crabs.evening_detective_server.EveningDetectiveServer.GetScenariosCatalog:input_type -> crabs.evening_detective_server.GetScenariosCatalogReq + 64, // 133: crabs.evening_detective_server.EveningDetectiveServer.GetFullScenario:input_type -> crabs.evening_detective_server.GetScenarioReq + 64, // 134: crabs.evening_detective_server.EveningDetectiveServer.GetScenario:input_type -> crabs.evening_detective_server.GetScenarioReq + 78, // 135: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenario:input_type -> crabs.evening_detective_server.UpdateScenarioReq + 80, // 136: crabs.evening_detective_server.EveningDetectiveServer.PublicScenario:input_type -> crabs.evening_detective_server.PublicScenarioReq + 82, // 137: crabs.evening_detective_server.EveningDetectiveServer.DraftScenario:input_type -> crabs.evening_detective_server.DraftScenarioReq + 84, // 138: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenario:input_type -> crabs.evening_detective_server.DeleteScenarioReq + 86, // 139: crabs.evening_detective_server.EveningDetectiveServer.AddScenarioPlace:input_type -> crabs.evening_detective_server.AddScenarioPlaceReq + 88, // 140: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioPlace:input_type -> crabs.evening_detective_server.UpdateScenarioPlaceReq + 90, // 141: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenarioPlace:input_type -> crabs.evening_detective_server.DeleteScenarioPlaceReq + 96, // 142: crabs.evening_detective_server.EveningDetectiveServer.AddScenarioQuestion:input_type -> crabs.evening_detective_server.AddScenarioQuestionReq + 98, // 143: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioQuestion:input_type -> crabs.evening_detective_server.UpdateScenarioQuestionReq + 100, // 144: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenarioQuestion:input_type -> crabs.evening_detective_server.DeleteScenarioQuestionReq + 210, // 145: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioBackground:input_type -> crabs.evening_detective_server.UpdateScenarioBackgroundReq + 94, // 146: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioIntro:input_type -> crabs.evening_detective_server.UpdateScenarioIntroReq + 92, // 147: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioConclusion:input_type -> crabs.evening_detective_server.UpdateScenarioConclusionReq + 102, // 148: crabs.evening_detective_server.EveningDetectiveServer.DownloadScenarioArchive:input_type -> crabs.evening_detective_server.DownloadScenarioArchiveReq + 233, // 149: crabs.evening_detective_server.EveningDetectiveServer.UploadScenarioArchive:input_type -> google.api.HttpBody + 104, // 150: crabs.evening_detective_server.EveningDetectiveServer.AddGame:input_type -> crabs.evening_detective_server.AddGameReq + 106, // 151: crabs.evening_detective_server.EveningDetectiveServer.GetGames:input_type -> crabs.evening_detective_server.GetGamesReq + 158, // 152: crabs.evening_detective_server.EveningDetectiveServer.GetGame:input_type -> crabs.evening_detective_server.GetGameReq + 110, // 153: crabs.evening_detective_server.EveningDetectiveServer.StartGameExport:input_type -> crabs.evening_detective_server.StartGameExportReq + 111, // 154: crabs.evening_detective_server.EveningDetectiveServer.GetGameExport:input_type -> crabs.evening_detective_server.GetGameExportReq + 212, // 155: crabs.evening_detective_server.EveningDetectiveServer.IssueGameTickets:input_type -> crabs.evening_detective_server.IssueGameTicketsReq + 215, // 156: crabs.evening_detective_server.EveningDetectiveServer.GetTicket:input_type -> crabs.evening_detective_server.GetTicketReq + 217, // 157: crabs.evening_detective_server.EveningDetectiveServer.AcceptTicket:input_type -> crabs.evening_detective_server.AcceptTicketReq + 114, // 158: crabs.evening_detective_server.EveningDetectiveServer.CreateScreenSession:input_type -> crabs.evening_detective_server.CreateScreenSessionReq + 116, // 159: crabs.evening_detective_server.EveningDetectiveServer.GetScreenState:input_type -> crabs.evening_detective_server.GetScreenStateReq + 118, // 160: crabs.evening_detective_server.EveningDetectiveServer.GetGameScreens:input_type -> crabs.evening_detective_server.GetGameScreensReq + 121, // 161: crabs.evening_detective_server.EveningDetectiveServer.GetGameMusic:input_type -> crabs.evening_detective_server.GetGameMusicReq + 123, // 162: crabs.evening_detective_server.EveningDetectiveServer.SetGameMusic:input_type -> crabs.evening_detective_server.SetGameMusicReq + 125, // 163: crabs.evening_detective_server.EveningDetectiveServer.AdvanceScreenMusic:input_type -> crabs.evening_detective_server.AdvanceScreenMusicReq + 127, // 164: crabs.evening_detective_server.EveningDetectiveServer.BindScreen:input_type -> crabs.evening_detective_server.BindScreenReq + 129, // 165: crabs.evening_detective_server.EveningDetectiveServer.UnbindScreen:input_type -> crabs.evening_detective_server.UnbindScreenReq + 131, // 166: crabs.evening_detective_server.EveningDetectiveServer.SetScreenSound:input_type -> crabs.evening_detective_server.SetScreenSoundReq + 134, // 167: crabs.evening_detective_server.EveningDetectiveServer.GetGameMap:input_type -> crabs.evening_detective_server.GetGameMapReq + 136, // 168: crabs.evening_detective_server.EveningDetectiveServer.UpdateGameMapItem:input_type -> crabs.evening_detective_server.UpdateGameMapItemReq + 138, // 169: crabs.evening_detective_server.EveningDetectiveServer.SetScreenMode:input_type -> crabs.evening_detective_server.SetScreenModeReq + 140, // 170: crabs.evening_detective_server.EveningDetectiveServer.SetScreenTimer:input_type -> crabs.evening_detective_server.SetScreenTimerReq + 142, // 171: crabs.evening_detective_server.EveningDetectiveServer.SendScreenCommand:input_type -> crabs.evening_detective_server.SendScreenCommandReq + 146, // 172: crabs.evening_detective_server.EveningDetectiveServer.GetScreenPlan:input_type -> crabs.evening_detective_server.GetScreenPlanReq + 148, // 173: crabs.evening_detective_server.EveningDetectiveServer.SaveScreenPlan:input_type -> crabs.evening_detective_server.SaveScreenPlanReq + 150, // 174: crabs.evening_detective_server.EveningDetectiveServer.SetScreenPlanStep:input_type -> crabs.evening_detective_server.SetScreenPlanStepReq + 152, // 175: crabs.evening_detective_server.EveningDetectiveServer.GetScreenResults:input_type -> crabs.evening_detective_server.GetScreenResultsReq + 158, // 176: crabs.evening_detective_server.EveningDetectiveServer.DownloadTeamQR:input_type -> crabs.evening_detective_server.GetGameReq + 160, // 177: crabs.evening_detective_server.EveningDetectiveServer.GetGameAnswers:input_type -> crabs.evening_detective_server.GetGameAnswersReq + 162, // 178: crabs.evening_detective_server.EveningDetectiveServer.GetGameResults:input_type -> crabs.evening_detective_server.GetGameResultsReq + 167, // 179: crabs.evening_detective_server.EveningDetectiveServer.CreateGameReview:input_type -> crabs.evening_detective_server.CreateGameReviewReq + 169, // 180: crabs.evening_detective_server.EveningDetectiveServer.GetGameReviews:input_type -> crabs.evening_detective_server.GetGameReviewsReq + 170, // 181: crabs.evening_detective_server.EveningDetectiveServer.GetScenarioReviews:input_type -> crabs.evening_detective_server.GetScenarioReviewsReq + 169, // 182: crabs.evening_detective_server.EveningDetectiveServer.GetGameReviewsForModeration:input_type -> crabs.evening_detective_server.GetGameReviewsReq + 171, // 183: crabs.evening_detective_server.EveningDetectiveServer.GetReviewsForModeration:input_type -> crabs.evening_detective_server.GetReviewsForModerationReq + 173, // 184: crabs.evening_detective_server.EveningDetectiveServer.ModerateGameReview:input_type -> crabs.evening_detective_server.ModerateGameReviewReq + 175, // 185: crabs.evening_detective_server.EveningDetectiveServer.UpdateGame:input_type -> crabs.evening_detective_server.UpdateGameReq + 177, // 186: crabs.evening_detective_server.EveningDetectiveServer.StartGame:input_type -> crabs.evening_detective_server.StartGameReq + 179, // 187: crabs.evening_detective_server.EveningDetectiveServer.PauseGame:input_type -> crabs.evening_detective_server.PauseGameReq + 181, // 188: crabs.evening_detective_server.EveningDetectiveServer.PlayGame:input_type -> crabs.evening_detective_server.PlayGameReq + 183, // 189: crabs.evening_detective_server.EveningDetectiveServer.FinishGame:input_type -> crabs.evening_detective_server.FinishGameReq + 185, // 190: crabs.evening_detective_server.EveningDetectiveServer.ResetGame:input_type -> crabs.evening_detective_server.ResetGameReq + 187, // 191: crabs.evening_detective_server.EveningDetectiveServer.DeleteGame:input_type -> crabs.evening_detective_server.DeleteGameReq + 189, // 192: crabs.evening_detective_server.EveningDetectiveServer.AddTeam:input_type -> crabs.evening_detective_server.AddTeamReq + 191, // 193: crabs.evening_detective_server.EveningDetectiveServer.UpdateTeam:input_type -> crabs.evening_detective_server.UpdateTeamReq + 193, // 194: crabs.evening_detective_server.EveningDetectiveServer.DeleteTeam:input_type -> crabs.evening_detective_server.DeleteTeamReq + 195, // 195: crabs.evening_detective_server.EveningDetectiveServer.GiveTeamApplications:input_type -> crabs.evening_detective_server.GiveTeamApplicationsReq + 197, // 196: crabs.evening_detective_server.EveningDetectiveServer.GetTeamStory:input_type -> crabs.evening_detective_server.GetTeamStoryReq + 200, // 197: crabs.evening_detective_server.EveningDetectiveServer.AddTeamAction:input_type -> crabs.evening_detective_server.AddTeamActionReq + 202, // 198: crabs.evening_detective_server.EveningDetectiveServer.DeleteLastTeamAction:input_type -> crabs.evening_detective_server.DeleteLastTeamActionReq + 204, // 199: crabs.evening_detective_server.EveningDetectiveServer.GetTeamAnswers:input_type -> crabs.evening_detective_server.GetTeamAnswersReq + 206, // 200: crabs.evening_detective_server.EveningDetectiveServer.SubmitTeamAnswers:input_type -> crabs.evening_detective_server.SubmitTeamAnswersReq + 208, // 201: crabs.evening_detective_server.EveningDetectiveServer.SetTeamAnswerScore:input_type -> crabs.evening_detective_server.SetTeamAnswerScoreReq + 223, // 202: crabs.evening_detective_server.EveningDetectiveServer.GetTasks:output_type -> crabs.evening_detective_server.GetTasksRsp + 225, // 203: crabs.evening_detective_server.EveningDetectiveServer.GetTaskAssignees:output_type -> crabs.evening_detective_server.GetTaskAssigneesRsp + 230, // 204: crabs.evening_detective_server.EveningDetectiveServer.CreateTask:output_type -> crabs.evening_detective_server.TaskRsp + 230, // 205: crabs.evening_detective_server.EveningDetectiveServer.UpdateTask:output_type -> crabs.evening_detective_server.TaskRsp + 230, // 206: crabs.evening_detective_server.EveningDetectiveServer.SetTaskStatus:output_type -> crabs.evening_detective_server.TaskRsp + 231, // 207: crabs.evening_detective_server.EveningDetectiveServer.DeleteTask:output_type -> crabs.evening_detective_server.DeleteTaskRsp + 156, // 208: crabs.evening_detective_server.EveningDetectiveServer.GetParticipation:output_type -> crabs.evening_detective_server.ParticipationRsp + 156, // 209: crabs.evening_detective_server.EveningDetectiveServer.AnswerParticipation:output_type -> crabs.evening_detective_server.ParticipationRsp + 5, // 210: crabs.evening_detective_server.EveningDetectiveServer.Ping:output_type -> crabs.evening_detective_server.PingRsp + 7, // 211: crabs.evening_detective_server.EveningDetectiveServer.Echo:output_type -> crabs.evening_detective_server.EchoRsp + 9, // 212: crabs.evening_detective_server.EveningDetectiveServer.Signup:output_type -> crabs.evening_detective_server.SignupRsp + 11, // 213: crabs.evening_detective_server.EveningDetectiveServer.RefreshPassword:output_type -> crabs.evening_detective_server.RefreshPasswordRsp + 13, // 214: crabs.evening_detective_server.EveningDetectiveServer.Login:output_type -> crabs.evening_detective_server.LoginRsp + 15, // 215: crabs.evening_detective_server.EveningDetectiveServer.Refresh:output_type -> crabs.evening_detective_server.RefreshRsp + 17, // 216: crabs.evening_detective_server.EveningDetectiveServer.DeleteAccount:output_type -> crabs.evening_detective_server.DeleteAccountRsp + 19, // 217: crabs.evening_detective_server.EveningDetectiveServer.GetTerms:output_type -> crabs.evening_detective_server.GetTermsRsp + 21, // 218: crabs.evening_detective_server.EveningDetectiveServer.GetPrivacy:output_type -> crabs.evening_detective_server.GetPrivacyRsp + 23, // 219: crabs.evening_detective_server.EveningDetectiveServer.GetConsent:output_type -> crabs.evening_detective_server.GetConsentRsp + 25, // 220: crabs.evening_detective_server.EveningDetectiveServer.GetUsers:output_type -> crabs.evening_detective_server.GetUsersRsp + 28, // 221: crabs.evening_detective_server.EveningDetectiveServer.GetUserByID:output_type -> crabs.evening_detective_server.GetUserByIDRsp + 30, // 222: crabs.evening_detective_server.EveningDetectiveServer.GetMe:output_type -> crabs.evening_detective_server.GetMeRsp + 32, // 223: crabs.evening_detective_server.EveningDetectiveServer.ChangeUserPassword:output_type -> crabs.evening_detective_server.ChangeUserPasswordRsp + 34, // 224: crabs.evening_detective_server.EveningDetectiveServer.AddUserRole:output_type -> crabs.evening_detective_server.AddUserRoleRsp + 36, // 225: crabs.evening_detective_server.EveningDetectiveServer.DeleteUserRole:output_type -> crabs.evening_detective_server.DeleteUserRoleRsp + 38, // 226: crabs.evening_detective_server.EveningDetectiveServer.GetPermissions:output_type -> crabs.evening_detective_server.GetPermissionsRsp + 40, // 227: crabs.evening_detective_server.EveningDetectiveServer.UploadFile:output_type -> crabs.evening_detective_server.UploadFileRsp + 233, // 228: crabs.evening_detective_server.EveningDetectiveServer.DownloadFile:output_type -> google.api.HttpBody + 45, // 229: crabs.evening_detective_server.EveningDetectiveServer.GetPlaylists:output_type -> crabs.evening_detective_server.GetPlaylistsRsp + 47, // 230: crabs.evening_detective_server.EveningDetectiveServer.CreatePlaylist:output_type -> crabs.evening_detective_server.CreatePlaylistRsp + 49, // 231: crabs.evening_detective_server.EveningDetectiveServer.UpdatePlaylist:output_type -> crabs.evening_detective_server.UpdatePlaylistRsp + 51, // 232: crabs.evening_detective_server.EveningDetectiveServer.DeletePlaylist:output_type -> crabs.evening_detective_server.DeletePlaylistRsp + 53, // 233: crabs.evening_detective_server.EveningDetectiveServer.UploadPlaylistTrack:output_type -> crabs.evening_detective_server.UploadPlaylistTrackRsp + 55, // 234: crabs.evening_detective_server.EveningDetectiveServer.DeletePlaylistTrack:output_type -> crabs.evening_detective_server.DeletePlaylistTrackRsp + 57, // 235: crabs.evening_detective_server.EveningDetectiveServer.SetScenarioPlaylist:output_type -> crabs.evening_detective_server.SetScenarioPlaylistRsp + 59, // 236: crabs.evening_detective_server.EveningDetectiveServer.AddScenario:output_type -> crabs.evening_detective_server.AddScenarioRsp + 61, // 237: crabs.evening_detective_server.EveningDetectiveServer.GetMyScenarios:output_type -> crabs.evening_detective_server.GetMyScenariosRsp + 63, // 238: crabs.evening_detective_server.EveningDetectiveServer.GetScenariosCatalog:output_type -> crabs.evening_detective_server.GetScenariosCatalogRsp + 65, // 239: crabs.evening_detective_server.EveningDetectiveServer.GetFullScenario:output_type -> crabs.evening_detective_server.GetScenarioRsp + 65, // 240: crabs.evening_detective_server.EveningDetectiveServer.GetScenario:output_type -> crabs.evening_detective_server.GetScenarioRsp + 79, // 241: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenario:output_type -> crabs.evening_detective_server.UpdateScenarioRsp + 81, // 242: crabs.evening_detective_server.EveningDetectiveServer.PublicScenario:output_type -> crabs.evening_detective_server.PublicScenarioRsp + 83, // 243: crabs.evening_detective_server.EveningDetectiveServer.DraftScenario:output_type -> crabs.evening_detective_server.DraftScenarioRsp + 85, // 244: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenario:output_type -> crabs.evening_detective_server.DeleteScenarioRsp + 87, // 245: crabs.evening_detective_server.EveningDetectiveServer.AddScenarioPlace:output_type -> crabs.evening_detective_server.AddScenarioPlaceRsp + 89, // 246: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioPlace:output_type -> crabs.evening_detective_server.UpdateScenarioPlaceRsp + 91, // 247: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenarioPlace:output_type -> crabs.evening_detective_server.DeleteScenarioPlaceRsp + 97, // 248: crabs.evening_detective_server.EveningDetectiveServer.AddScenarioQuestion:output_type -> crabs.evening_detective_server.AddScenarioQuestionRsp + 99, // 249: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioQuestion:output_type -> crabs.evening_detective_server.UpdateScenarioQuestionRsp + 101, // 250: crabs.evening_detective_server.EveningDetectiveServer.DeleteScenarioQuestion:output_type -> crabs.evening_detective_server.DeleteScenarioQuestionRsp + 211, // 251: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioBackground:output_type -> crabs.evening_detective_server.UpdateScenarioBackgroundRsp + 95, // 252: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioIntro:output_type -> crabs.evening_detective_server.UpdateScenarioIntroRsp + 93, // 253: crabs.evening_detective_server.EveningDetectiveServer.UpdateScenarioConclusion:output_type -> crabs.evening_detective_server.UpdateScenarioConclusionRsp + 233, // 254: crabs.evening_detective_server.EveningDetectiveServer.DownloadScenarioArchive:output_type -> google.api.HttpBody + 103, // 255: crabs.evening_detective_server.EveningDetectiveServer.UploadScenarioArchive:output_type -> crabs.evening_detective_server.UploadScenarioArchiveRsp + 105, // 256: crabs.evening_detective_server.EveningDetectiveServer.AddGame:output_type -> crabs.evening_detective_server.AddGameRsp + 107, // 257: crabs.evening_detective_server.EveningDetectiveServer.GetGames:output_type -> crabs.evening_detective_server.GetGamesRsp + 159, // 258: crabs.evening_detective_server.EveningDetectiveServer.GetGame:output_type -> crabs.evening_detective_server.GetGameRsp + 112, // 259: crabs.evening_detective_server.EveningDetectiveServer.StartGameExport:output_type -> crabs.evening_detective_server.GameExportRsp + 112, // 260: crabs.evening_detective_server.EveningDetectiveServer.GetGameExport:output_type -> crabs.evening_detective_server.GameExportRsp + 213, // 261: crabs.evening_detective_server.EveningDetectiveServer.IssueGameTickets:output_type -> crabs.evening_detective_server.IssueGameTicketsRsp + 216, // 262: crabs.evening_detective_server.EveningDetectiveServer.GetTicket:output_type -> crabs.evening_detective_server.GetTicketRsp + 218, // 263: crabs.evening_detective_server.EveningDetectiveServer.AcceptTicket:output_type -> crabs.evening_detective_server.AcceptTicketRsp + 115, // 264: crabs.evening_detective_server.EveningDetectiveServer.CreateScreenSession:output_type -> crabs.evening_detective_server.CreateScreenSessionRsp + 117, // 265: crabs.evening_detective_server.EveningDetectiveServer.GetScreenState:output_type -> crabs.evening_detective_server.GetScreenStateRsp + 119, // 266: crabs.evening_detective_server.EveningDetectiveServer.GetGameScreens:output_type -> crabs.evening_detective_server.GetGameScreensRsp + 122, // 267: crabs.evening_detective_server.EveningDetectiveServer.GetGameMusic:output_type -> crabs.evening_detective_server.GetGameMusicRsp + 124, // 268: crabs.evening_detective_server.EveningDetectiveServer.SetGameMusic:output_type -> crabs.evening_detective_server.SetGameMusicRsp + 126, // 269: crabs.evening_detective_server.EveningDetectiveServer.AdvanceScreenMusic:output_type -> crabs.evening_detective_server.AdvanceScreenMusicRsp + 128, // 270: crabs.evening_detective_server.EveningDetectiveServer.BindScreen:output_type -> crabs.evening_detective_server.BindScreenRsp + 130, // 271: crabs.evening_detective_server.EveningDetectiveServer.UnbindScreen:output_type -> crabs.evening_detective_server.UnbindScreenRsp + 132, // 272: crabs.evening_detective_server.EveningDetectiveServer.SetScreenSound:output_type -> crabs.evening_detective_server.SetScreenSoundRsp + 135, // 273: crabs.evening_detective_server.EveningDetectiveServer.GetGameMap:output_type -> crabs.evening_detective_server.GetGameMapRsp + 137, // 274: crabs.evening_detective_server.EveningDetectiveServer.UpdateGameMapItem:output_type -> crabs.evening_detective_server.UpdateGameMapItemRsp + 139, // 275: crabs.evening_detective_server.EveningDetectiveServer.SetScreenMode:output_type -> crabs.evening_detective_server.SetScreenModeRsp + 141, // 276: crabs.evening_detective_server.EveningDetectiveServer.SetScreenTimer:output_type -> crabs.evening_detective_server.SetScreenTimerRsp + 143, // 277: crabs.evening_detective_server.EveningDetectiveServer.SendScreenCommand:output_type -> crabs.evening_detective_server.SendScreenCommandRsp + 147, // 278: crabs.evening_detective_server.EveningDetectiveServer.GetScreenPlan:output_type -> crabs.evening_detective_server.GetScreenPlanRsp + 149, // 279: crabs.evening_detective_server.EveningDetectiveServer.SaveScreenPlan:output_type -> crabs.evening_detective_server.SaveScreenPlanRsp + 151, // 280: crabs.evening_detective_server.EveningDetectiveServer.SetScreenPlanStep:output_type -> crabs.evening_detective_server.SetScreenPlanStepRsp + 153, // 281: crabs.evening_detective_server.EveningDetectiveServer.GetScreenResults:output_type -> crabs.evening_detective_server.GetScreenResultsRsp + 233, // 282: crabs.evening_detective_server.EveningDetectiveServer.DownloadTeamQR:output_type -> google.api.HttpBody + 161, // 283: crabs.evening_detective_server.EveningDetectiveServer.GetGameAnswers:output_type -> crabs.evening_detective_server.GetGameAnswersRsp + 165, // 284: crabs.evening_detective_server.EveningDetectiveServer.GetGameResults:output_type -> crabs.evening_detective_server.GetGameResultsRsp + 168, // 285: crabs.evening_detective_server.EveningDetectiveServer.CreateGameReview:output_type -> crabs.evening_detective_server.CreateGameReviewRsp + 172, // 286: crabs.evening_detective_server.EveningDetectiveServer.GetGameReviews:output_type -> crabs.evening_detective_server.GetGameReviewsRsp + 172, // 287: crabs.evening_detective_server.EveningDetectiveServer.GetScenarioReviews:output_type -> crabs.evening_detective_server.GetGameReviewsRsp + 172, // 288: crabs.evening_detective_server.EveningDetectiveServer.GetGameReviewsForModeration:output_type -> crabs.evening_detective_server.GetGameReviewsRsp + 172, // 289: crabs.evening_detective_server.EveningDetectiveServer.GetReviewsForModeration:output_type -> crabs.evening_detective_server.GetGameReviewsRsp + 174, // 290: crabs.evening_detective_server.EveningDetectiveServer.ModerateGameReview:output_type -> crabs.evening_detective_server.ModerateGameReviewRsp + 176, // 291: crabs.evening_detective_server.EveningDetectiveServer.UpdateGame:output_type -> crabs.evening_detective_server.UpdateGameRsp + 178, // 292: crabs.evening_detective_server.EveningDetectiveServer.StartGame:output_type -> crabs.evening_detective_server.StartGameRsp + 180, // 293: crabs.evening_detective_server.EveningDetectiveServer.PauseGame:output_type -> crabs.evening_detective_server.PauseGameRsp + 182, // 294: crabs.evening_detective_server.EveningDetectiveServer.PlayGame:output_type -> crabs.evening_detective_server.PlayGameRsp + 184, // 295: crabs.evening_detective_server.EveningDetectiveServer.FinishGame:output_type -> crabs.evening_detective_server.FinishGameRsp + 186, // 296: crabs.evening_detective_server.EveningDetectiveServer.ResetGame:output_type -> crabs.evening_detective_server.ResetGameRsp + 188, // 297: crabs.evening_detective_server.EveningDetectiveServer.DeleteGame:output_type -> crabs.evening_detective_server.DeleteGameRsp + 190, // 298: crabs.evening_detective_server.EveningDetectiveServer.AddTeam:output_type -> crabs.evening_detective_server.AddTeamRsp + 192, // 299: crabs.evening_detective_server.EveningDetectiveServer.UpdateTeam:output_type -> crabs.evening_detective_server.UpdateTeamRsp + 194, // 300: crabs.evening_detective_server.EveningDetectiveServer.DeleteTeam:output_type -> crabs.evening_detective_server.DeleteTeamRsp + 196, // 301: crabs.evening_detective_server.EveningDetectiveServer.GiveTeamApplications:output_type -> crabs.evening_detective_server.GiveTeamApplicationsRsp + 198, // 302: crabs.evening_detective_server.EveningDetectiveServer.GetTeamStory:output_type -> crabs.evening_detective_server.GetTeamStoryRsp + 201, // 303: crabs.evening_detective_server.EveningDetectiveServer.AddTeamAction:output_type -> crabs.evening_detective_server.AddTeamActionRsp + 203, // 304: crabs.evening_detective_server.EveningDetectiveServer.DeleteLastTeamAction:output_type -> crabs.evening_detective_server.DeleteLastTeamActionRsp + 205, // 305: crabs.evening_detective_server.EveningDetectiveServer.GetTeamAnswers:output_type -> crabs.evening_detective_server.GetTeamAnswersRsp + 207, // 306: crabs.evening_detective_server.EveningDetectiveServer.SubmitTeamAnswers:output_type -> crabs.evening_detective_server.SubmitTeamAnswersRsp + 209, // 307: crabs.evening_detective_server.EveningDetectiveServer.SetTeamAnswerScore:output_type -> crabs.evening_detective_server.SetTeamAnswerScoreRsp + 202, // [202:308] is the sub-list for method output_type + 96, // [96:202] is the sub-list for method input_type + 96, // [96:96] is the sub-list for extension type_name + 96, // [96:96] is the sub-list for extension extendee + 0, // [0:96] is the sub-list for field type_name } func init() { file_main_proto_init() } @@ -13385,19 +13638,19 @@ func file_main_proto_init() { file_main_proto_msgTypes[62].OneofWrappers = []any{} file_main_proto_msgTypes[72].OneofWrappers = []any{} file_main_proto_msgTypes[104].OneofWrappers = []any{} - file_main_proto_msgTypes[105].OneofWrappers = []any{} - file_main_proto_msgTypes[200].OneofWrappers = []any{} - file_main_proto_msgTypes[211].OneofWrappers = []any{} - file_main_proto_msgTypes[212].OneofWrappers = []any{} - file_main_proto_msgTypes[218].OneofWrappers = []any{} - file_main_proto_msgTypes[219].OneofWrappers = []any{} + file_main_proto_msgTypes[109].OneofWrappers = []any{} + file_main_proto_msgTypes[204].OneofWrappers = []any{} + file_main_proto_msgTypes[215].OneofWrappers = []any{} + file_main_proto_msgTypes[216].OneofWrappers = []any{} + file_main_proto_msgTypes[222].OneofWrappers = []any{} + file_main_proto_msgTypes[223].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_main_proto_rawDesc), len(file_main_proto_rawDesc)), NumEnums: 4, - NumMessages: 224, + NumMessages: 228, NumExtensions: 0, NumServices: 1, }, diff --git a/proto/main.pb.gw.go b/proto/main.pb.gw.go index d9755fe..016f881 100644 --- a/proto/main.pb.gw.go +++ b/proto/main.pb.gw.go @@ -2053,6 +2053,90 @@ func local_request_EveningDetectiveServer_GetGame_0(ctx context.Context, marshal return msg, metadata, err } +func request_EveningDetectiveServer_StartGameExport_0(ctx context.Context, marshaler runtime.Marshaler, client EveningDetectiveServerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq StartGameExportReq + metadata runtime.ServerMetadata + err error + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + val, ok := pathParams["ID"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "ID") + } + protoReq.ID, err = runtime.Int32(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "ID", err) + } + msg, err := client.StartGameExport(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_EveningDetectiveServer_StartGameExport_0(ctx context.Context, marshaler runtime.Marshaler, server EveningDetectiveServerServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq StartGameExportReq + metadata runtime.ServerMetadata + err error + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + val, ok := pathParams["ID"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "ID") + } + protoReq.ID, err = runtime.Int32(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "ID", err) + } + msg, err := server.StartGameExport(ctx, &protoReq) + return msg, metadata, err +} + +func request_EveningDetectiveServer_GetGameExport_0(ctx context.Context, marshaler runtime.Marshaler, client EveningDetectiveServerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetGameExportReq + metadata runtime.ServerMetadata + err error + ) + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + val, ok := pathParams["ID"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "ID") + } + protoReq.ID, err = runtime.Int32(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "ID", err) + } + msg, err := client.GetGameExport(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_EveningDetectiveServer_GetGameExport_0(ctx context.Context, marshaler runtime.Marshaler, server EveningDetectiveServerServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetGameExportReq + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["ID"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "ID") + } + protoReq.ID, err = runtime.Int32(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "ID", err) + } + msg, err := server.GetGameExport(ctx, &protoReq) + return msg, metadata, err +} + func request_EveningDetectiveServer_IssueGameTickets_0(ctx context.Context, marshaler runtime.Marshaler, client EveningDetectiveServerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( protoReq IssueGameTicketsReq @@ -5180,6 +5264,46 @@ func RegisterEveningDetectiveServerHandlerServer(ctx context.Context, mux *runti } forward_EveningDetectiveServer_GetGame_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodPost, pattern_EveningDetectiveServer_StartGameExport_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/crabs.evening_detective_server.EveningDetectiveServer/StartGameExport", runtime.WithHTTPPathPattern("/api/games/{ID}/export")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_EveningDetectiveServer_StartGameExport_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_EveningDetectiveServer_StartGameExport_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_EveningDetectiveServer_GetGameExport_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/crabs.evening_detective_server.EveningDetectiveServer/GetGameExport", runtime.WithHTTPPathPattern("/api/games/{ID}/export")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_EveningDetectiveServer_GetGameExport_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_EveningDetectiveServer_GetGameExport_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodPost, pattern_EveningDetectiveServer_IssueGameTickets_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -7129,6 +7253,40 @@ func RegisterEveningDetectiveServerHandlerClient(ctx context.Context, mux *runti } forward_EveningDetectiveServer_GetGame_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodPost, pattern_EveningDetectiveServer_StartGameExport_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/crabs.evening_detective_server.EveningDetectiveServer/StartGameExport", runtime.WithHTTPPathPattern("/api/games/{ID}/export")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_EveningDetectiveServer_StartGameExport_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_EveningDetectiveServer_StartGameExport_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_EveningDetectiveServer_GetGameExport_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/crabs.evening_detective_server.EveningDetectiveServer/GetGameExport", runtime.WithHTTPPathPattern("/api/games/{ID}/export")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_EveningDetectiveServer_GetGameExport_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_EveningDetectiveServer_GetGameExport_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodPost, pattern_EveningDetectiveServer_IssueGameTickets_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -7989,6 +8147,8 @@ var ( pattern_EveningDetectiveServer_AddGame_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"api", "games"}, "")) pattern_EveningDetectiveServer_GetGames_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"api", "games"}, "")) pattern_EveningDetectiveServer_GetGame_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"api", "games", "ID"}, "")) + pattern_EveningDetectiveServer_StartGameExport_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"api", "games", "ID", "export"}, "")) + pattern_EveningDetectiveServer_GetGameExport_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"api", "games", "ID", "export"}, "")) pattern_EveningDetectiveServer_IssueGameTickets_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"api", "games", "gameID", "tickets"}, "")) pattern_EveningDetectiveServer_GetTicket_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"api", "tickets", "token"}, "")) pattern_EveningDetectiveServer_AcceptTicket_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"api", "tickets", "token", "accept"}, "")) @@ -8096,6 +8256,8 @@ var ( forward_EveningDetectiveServer_AddGame_0 = runtime.ForwardResponseMessage forward_EveningDetectiveServer_GetGames_0 = runtime.ForwardResponseMessage forward_EveningDetectiveServer_GetGame_0 = runtime.ForwardResponseMessage + forward_EveningDetectiveServer_StartGameExport_0 = runtime.ForwardResponseMessage + forward_EveningDetectiveServer_GetGameExport_0 = runtime.ForwardResponseMessage forward_EveningDetectiveServer_IssueGameTickets_0 = runtime.ForwardResponseMessage forward_EveningDetectiveServer_GetTicket_0 = runtime.ForwardResponseMessage forward_EveningDetectiveServer_AcceptTicket_0 = runtime.ForwardResponseMessage diff --git a/proto/main_grpc.pb.go b/proto/main_grpc.pb.go index c811ab2..89b0689 100644 --- a/proto/main_grpc.pb.go +++ b/proto/main_grpc.pb.go @@ -83,6 +83,8 @@ const ( EveningDetectiveServer_AddGame_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/AddGame" EveningDetectiveServer_GetGames_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/GetGames" EveningDetectiveServer_GetGame_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/GetGame" + EveningDetectiveServer_StartGameExport_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/StartGameExport" + EveningDetectiveServer_GetGameExport_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/GetGameExport" EveningDetectiveServer_IssueGameTickets_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/IssueGameTickets" EveningDetectiveServer_GetTicket_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/GetTicket" EveningDetectiveServer_AcceptTicket_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/AcceptTicket" @@ -197,6 +199,8 @@ type EveningDetectiveServerClient interface { AddGame(ctx context.Context, in *AddGameReq, opts ...grpc.CallOption) (*AddGameRsp, error) GetGames(ctx context.Context, in *GetGamesReq, opts ...grpc.CallOption) (*GetGamesRsp, error) GetGame(ctx context.Context, in *GetGameReq, opts ...grpc.CallOption) (*GetGameRsp, error) + StartGameExport(ctx context.Context, in *StartGameExportReq, opts ...grpc.CallOption) (*GameExportRsp, error) + GetGameExport(ctx context.Context, in *GetGameExportReq, opts ...grpc.CallOption) (*GameExportRsp, error) IssueGameTickets(ctx context.Context, in *IssueGameTicketsReq, opts ...grpc.CallOption) (*IssueGameTicketsRsp, error) GetTicket(ctx context.Context, in *GetTicketReq, opts ...grpc.CallOption) (*GetTicketRsp, error) AcceptTicket(ctx context.Context, in *AcceptTicketReq, opts ...grpc.CallOption) (*AcceptTicketRsp, error) @@ -830,6 +834,26 @@ func (c *eveningDetectiveServerClient) GetGame(ctx context.Context, in *GetGameR return out, nil } +func (c *eveningDetectiveServerClient) StartGameExport(ctx context.Context, in *StartGameExportReq, opts ...grpc.CallOption) (*GameExportRsp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GameExportRsp) + err := c.cc.Invoke(ctx, EveningDetectiveServer_StartGameExport_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *eveningDetectiveServerClient) GetGameExport(ctx context.Context, in *GetGameExportReq, opts ...grpc.CallOption) (*GameExportRsp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GameExportRsp) + err := c.cc.Invoke(ctx, EveningDetectiveServer_GetGameExport_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *eveningDetectiveServerClient) IssueGameTickets(ctx context.Context, in *IssueGameTicketsReq, opts ...grpc.CallOption) (*IssueGameTicketsRsp, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(IssueGameTicketsRsp) @@ -1365,6 +1389,8 @@ type EveningDetectiveServerServer interface { AddGame(context.Context, *AddGameReq) (*AddGameRsp, error) GetGames(context.Context, *GetGamesReq) (*GetGamesRsp, error) GetGame(context.Context, *GetGameReq) (*GetGameRsp, error) + StartGameExport(context.Context, *StartGameExportReq) (*GameExportRsp, error) + GetGameExport(context.Context, *GetGameExportReq) (*GameExportRsp, error) IssueGameTickets(context.Context, *IssueGameTicketsReq) (*IssueGameTicketsRsp, error) GetTicket(context.Context, *GetTicketReq) (*GetTicketRsp, error) AcceptTicket(context.Context, *AcceptTicketReq) (*AcceptTicketRsp, error) @@ -1599,6 +1625,12 @@ func (UnimplementedEveningDetectiveServerServer) GetGames(context.Context, *GetG func (UnimplementedEveningDetectiveServerServer) GetGame(context.Context, *GetGameReq) (*GetGameRsp, error) { return nil, status.Error(codes.Unimplemented, "method GetGame not implemented") } +func (UnimplementedEveningDetectiveServerServer) StartGameExport(context.Context, *StartGameExportReq) (*GameExportRsp, error) { + return nil, status.Error(codes.Unimplemented, "method StartGameExport not implemented") +} +func (UnimplementedEveningDetectiveServerServer) GetGameExport(context.Context, *GetGameExportReq) (*GameExportRsp, error) { + return nil, status.Error(codes.Unimplemented, "method GetGameExport not implemented") +} func (UnimplementedEveningDetectiveServerServer) IssueGameTickets(context.Context, *IssueGameTicketsReq) (*IssueGameTicketsRsp, error) { return nil, status.Error(codes.Unimplemented, "method IssueGameTickets not implemented") } @@ -2788,6 +2820,42 @@ func _EveningDetectiveServer_GetGame_Handler(srv interface{}, ctx context.Contex return interceptor(ctx, in, info, handler) } +func _EveningDetectiveServer_StartGameExport_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StartGameExportReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EveningDetectiveServerServer).StartGameExport(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: EveningDetectiveServer_StartGameExport_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EveningDetectiveServerServer).StartGameExport(ctx, req.(*StartGameExportReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _EveningDetectiveServer_GetGameExport_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetGameExportReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EveningDetectiveServerServer).GetGameExport(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: EveningDetectiveServer_GetGameExport_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EveningDetectiveServerServer).GetGameExport(ctx, req.(*GetGameExportReq)) + } + return interceptor(ctx, in, info, handler) +} + func _EveningDetectiveServer_IssueGameTickets_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(IssueGameTicketsReq) if err := dec(in); err != nil { @@ -3869,6 +3937,14 @@ var EveningDetectiveServer_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetGame", Handler: _EveningDetectiveServer_GetGame_Handler, }, + { + MethodName: "StartGameExport", + Handler: _EveningDetectiveServer_StartGameExport_Handler, + }, + { + MethodName: "GetGameExport", + Handler: _EveningDetectiveServer_GetGameExport_Handler, + }, { MethodName: "IssueGameTickets", Handler: _EveningDetectiveServer_IssueGameTickets_Handler,