*/ public const SUPPORTED_MODES = [ self::MODE_ALL, self::MODE_SINGLE, self::MODE_MULTIPLE, ]; /** * 构造房间范围服务。 */ public function __construct( private readonly ChatStateService $chatState, ) {} /** * 归一化房间模式。 */ public function normalizeRoomScopeMode(?string $mode, string $default = self::MODE_SINGLE): string { $normalizedMode = (string) $mode; if (! in_array($normalizedMode, self::SUPPORTED_MODES, true)) { return $default; } return $normalizedMode; } /** * 把原始房间数组归一化为去重后的整型数组。 * * @return array */ public function normalizeRoomIds(mixed $roomIds, array $default = [1]): array { $items = is_array($roomIds) ? $roomIds : preg_split('/[\s,,]+/u', (string) $roomIds, -1, PREG_SPLIT_NO_EMPTY); $normalizedRoomIds = collect($items) ->map(fn (mixed $roomId): int => (int) $roomId) ->filter(fn (int $roomId): bool => $roomId > 0) ->unique() ->values() ->all(); if ($normalizedRoomIds === []) { return $default; } return $normalizedRoomIds; } /** * 从 params 数组中解析房间范围配置。 * * @return array{room_scope_mode:string,room_ids:array} */ public function getScopeConfigForParams(array $params, array $defaultRoomIds = [1]): array { if ( ! array_key_exists('room_scope_mode', $params) && ! array_key_exists('room_ids', $params) && ! array_key_exists('room_id', $params) ) { return [ 'room_scope_mode' => self::MODE_ALL, 'room_ids' => $this->normalizeRoomIds($defaultRoomIds, [1]), ]; } $roomScopeMode = $this->normalizeRoomScopeMode( mode: (string) ($params['room_scope_mode'] ?? self::MODE_SINGLE), default: self::MODE_SINGLE, ); $roomIds = $this->normalizeRoomIds( roomIds: $params['room_ids'] ?? (($params['room_id'] ?? null) !== null ? [$params['room_id']] : []), default: $defaultRoomIds, ); return [ 'room_scope_mode' => $roomScopeMode, 'room_ids' => $roomIds, ]; } /** * 读取指定游戏当前配置中的房间范围。 * * @return array{room_scope_mode:string,room_ids:array} */ public function getScopeConfigForGame(string $gameKey, array $defaultRoomIds = [1]): array { $params = GameConfig::forGame($gameKey)?->params ?? []; return $this->getScopeConfigForParams($params, $defaultRoomIds); } /** * 获取指定游戏真正生效的房间 ID 列表。 * * @return array */ public function getScopedRoomIdsForGame(string $gameKey, array $defaultRoomIds = [1]): array { $scopeConfig = $this->getScopeConfigForGame($gameKey, $defaultRoomIds); if ($scopeConfig['room_scope_mode'] === self::MODE_ALL) { return $this->resolveAllAvailableRoomIds($defaultRoomIds); } return $scopeConfig['room_ids']; } /** * 获取指定游戏的首选房间。 */ public function getPrimaryRoomIdForGame(string $gameKey, int $fallback = 1): int { $roomIds = $this->getScopedRoomIdsForGame($gameKey, [$fallback]); return $roomIds[0] ?? $fallback; } /** * 判断某个房间是否在指定游戏允许范围内。 */ public function isRoomAllowedForGame(string $gameKey, int $roomId, array $defaultRoomIds = [1]): bool { return in_array($roomId, $this->getScopedRoomIdsForGame($gameKey, $defaultRoomIds), true); } /** * 从请求或在线状态解析当前操作房间。 */ public function resolveRequestRoomId(Request $request, ?User $user = null, int $fallback = 1): int { $requestedRoomId = (int) $request->integer('room_id', 0); if ($requestedRoomId > 0) { return $requestedRoomId; } return $this->resolveUserRoomId($user ?? $request->user(), $fallback); } /** * 从用户在线房间或用户资料中推断当前房间。 */ public function resolveUserRoomId(?User $user, int $fallback = 1): int { if (! $user) { return $fallback; } $activeRoomIds = $this->chatState->getUserRooms($user->username); if ($activeRoomIds !== []) { return (int) $activeRoomIds[0]; } $profileRoomId = (int) ($user->room_id ?? 0); return $profileRoomId > 0 ? $profileRoomId : $fallback; } /** * 返回通用后台复用的默认房间范围配置。 * * @return array{room_scope_mode:string,room_ids:array} */ public function defaultScopeConfig(array $defaultRoomIds = [1]): array { return [ 'room_scope_mode' => self::MODE_SINGLE, 'room_ids' => $this->normalizeRoomIds($defaultRoomIds, [1]), ]; } /** * 在“全部房间”模式下解析当前可用房间。 * * @return array */ private function resolveAllAvailableRoomIds(array $defaultRoomIds = [1]): array { $roomIds = \App\Models\Room::query() ->orderBy('id') ->pluck('id') ->map(fn (mixed $roomId): int => (int) $roomId) ->all(); return $roomIds !== [] ? $roomIds : $defaultRoomIds; } }