package app import ( "context" "errors" "strconv" "evening_detective_server/internal/services/map_service" proto "evening_detective_server/proto" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) func (s *server) GetGameMap(ctx context.Context, req *proto.GetGameMapReq) (*proto.GetGameMapRsp, error) { if !canManageScreens(ctx) { return nil, status.Error(codes.PermissionDenied, "permission denied") } if req == nil || req.GameID <= 0 { return nil, status.Error(codes.InvalidArgument, "некорректный идентификатор игры") } game, err := s.gameService.GetFullGame(ctx, int(req.GameID)) if err != nil { return nil, status.Error(codes.NotFound, "игра не найдена") } if err := s.mapService.Ensure(ctx, int(req.GameID), "organizer_desk", "1"); err != nil { return nil, status.Error(codes.Internal, "не удалось сохранить карту") } for _, team := range game.Teams { if team.ParticipationStatus == "cancelled" { continue } if err := s.mapService.Ensure(ctx, int(req.GameID), "team", team.ID); err != nil { return nil, status.Error(codes.Internal, "не удалось сохранить карту") } } screens, err := s.screenService.ListByGame(ctx, int(req.GameID)) if err != nil { return nil, status.Error(codes.Internal, "не удалось получить экраны") } for _, screen := range screens { if err := s.mapService.Ensure(ctx, int(req.GameID), "screen", strconv.Itoa(screen.ID)); err != nil { return nil, status.Error(codes.Internal, "не удалось сохранить карту") } } items, err := s.mapService.List(ctx, int(req.GameID)) if err != nil { return nil, status.Error(codes.Internal, "не удалось получить карту") } teamNames := map[string]string{} for _, team := range game.Teams { if team.ParticipationStatus == "cancelled" { continue } teamNames[team.ID] = team.Name } screenStates := map[string]*proto.ScreenState{} for _, screen := range screens { screenStates[strconv.Itoa(screen.ID)] = screenState(screen) } result := make([]*proto.MapItem, 0, len(items)) for _, item := range items { _, teamExists := teamNames[item.ItemID] if (item.Kind == "team" && !teamExists) || (item.Kind == "screen" && screenStates[item.ItemID] == nil) { if err := s.mapService.Delete(ctx, item); err != nil { return nil, status.Error(codes.Internal, "не удалось обновить карту") } continue } mapped := &proto.MapItem{Kind: item.Kind, ItemID: item.ItemID, X: int32(item.X), Y: int32(item.Y), Hidden: item.Hidden} if item.Kind == "team" { mapped.Label = teamNames[item.ItemID] } if item.Kind == "organizer_desk" { mapped.Label = "Стол организаторов" } if state := screenStates[item.ItemID]; item.Kind == "screen" && state != nil { mapped.Label = "Экран " + state.ID mapped.Status = state.Status mapped.SoundEnabled = state.SoundEnabled } result = append(result, mapped) } return &proto.GetGameMapRsp{Items: result}, nil } func (s *server) UpdateGameMapItem(ctx context.Context, req *proto.UpdateGameMapItemReq) (*proto.UpdateGameMapItemRsp, error) { if !canManageScreens(ctx) { return nil, status.Error(codes.PermissionDenied, "permission denied") } if req == nil || req.GameID <= 0 || req.ItemID == "" || (req.Kind != "team" && req.Kind != "screen" && req.Kind != "organizer_desk") { return nil, status.Error(codes.InvalidArgument, "некорректный объект карты") } if err := s.mapService.Update(ctx, &map_service.MapItem{ GameID: int(req.GameID), Kind: req.Kind, ItemID: req.ItemID, X: int(req.X), Y: int(req.Y), Hidden: req.Hidden, }); err != nil { if errors.Is(err, map_service.ErrItemNotFound) { return nil, status.Error(codes.NotFound, "объект карты не найден") } return nil, status.Error(codes.Internal, "не удалось изменить карту") } return &proto.UpdateGameMapItemRsp{}, nil }