支持所有游戏按房间范围配置和运行
This commit is contained in:
@@ -14,14 +14,20 @@
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\UpdateGameConfigParamsRequest;
|
||||
use App\Models\GameConfig;
|
||||
use App\Models\LotteryIssue;
|
||||
use App\Models\Room;
|
||||
use App\Services\GameRoomScopeService;
|
||||
use App\Services\LotteryService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
/**
|
||||
* 类功能:统一处理后台游戏开关、参数保存与手动操作入口。
|
||||
*/
|
||||
class GameConfigController extends Controller
|
||||
{
|
||||
/**
|
||||
@@ -30,8 +36,9 @@ class GameConfigController extends Controller
|
||||
public function index(): View
|
||||
{
|
||||
$games = GameConfig::orderBy('id')->get();
|
||||
$availableRooms = Room::query()->orderBy('id')->get();
|
||||
|
||||
return view('admin.game-configs.index', compact('games'));
|
||||
return view('admin.game-configs.index', compact('games', 'availableRooms'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,15 +63,16 @@ class GameConfigController extends Controller
|
||||
*
|
||||
* 接收前端提交的 params JSON 对象并合并至现有配置。
|
||||
*/
|
||||
public function updateParams(Request $request, GameConfig $gameConfig): RedirectResponse
|
||||
public function updateParams(UpdateGameConfigParamsRequest $request, GameConfig $gameConfig, GameRoomScopeService $roomScopeService): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'params' => 'required|array',
|
||||
]);
|
||||
|
||||
// 合并参数,保留已有键,只更新传入的键
|
||||
$current = $gameConfig->params ?? [];
|
||||
$updated = array_merge($current, $request->input('params'));
|
||||
$validatedParams = $request->validated('params');
|
||||
$updated = array_merge($current, $validatedParams);
|
||||
|
||||
$scopeConfig = $roomScopeService->getScopeConfigForParams($validatedParams);
|
||||
$updated['room_scope_mode'] = $scopeConfig['room_scope_mode'];
|
||||
$updated['room_ids'] = $scopeConfig['room_ids'];
|
||||
|
||||
if ($gameConfig->game_key === 'mystery_box') {
|
||||
$legacyMap = [
|
||||
@@ -107,17 +115,19 @@ class GameConfigController extends Controller
|
||||
}
|
||||
|
||||
// 检查是否有正在开放的箱子(避免同时多个)
|
||||
if (\App\Models\MysteryBox::currentOpenBox()) {
|
||||
$targetRoomId = app(GameRoomScopeService::class)->getPrimaryRoomIdForGame('mystery_box');
|
||||
|
||||
if (\App\Models\MysteryBox::currentOpenBox($targetRoomId)) {
|
||||
return response()->json(['ok' => false, 'message' => '当前已有一个神秘箱子正在等待领取,请等它结束后再投放。']);
|
||||
}
|
||||
|
||||
\App\Jobs\DropMysteryBoxJob::dispatch($boxType, 1, null, (int) auth()->id());
|
||||
\App\Jobs\DropMysteryBoxJob::dispatch($boxType, $targetRoomId, null, (int) auth()->id());
|
||||
|
||||
$typeNames = ['normal' => '普通箱', 'rare' => '稀有箱', 'trap' => '黑化箱'];
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'message' => "✅ 已投放「{$typeNames[$boxType]}」到 #1 房间,暗号将实时发送到公屏!",
|
||||
'message' => "✅ 已投放「{$typeNames[$boxType]}」到 #{$targetRoomId} 房间,暗号将实时发送到公屏!",
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -126,19 +136,31 @@ class GameConfigController extends Controller
|
||||
*
|
||||
* 仅在当前无进行中期次时生效,防止重复开期。
|
||||
*/
|
||||
public function openLotteryIssue(): JsonResponse
|
||||
public function openLotteryIssue(GameRoomScopeService $roomScopeService): JsonResponse
|
||||
{
|
||||
if (! GameConfig::isEnabled('lottery')) {
|
||||
return response()->json(['ok' => false, 'message' => '双色球彩票未开启,请先开启游戏。']);
|
||||
}
|
||||
|
||||
if (LotteryIssue::currentIssue()) {
|
||||
return response()->json(['ok' => false, 'message' => '当前已有进行中的期次,无需重复开期。']);
|
||||
$openedRoomIds = [];
|
||||
|
||||
foreach ($roomScopeService->getScopedRoomIdsForGame('lottery') as $roomId) {
|
||||
if (LotteryIssue::currentIssue($roomId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
\App\Jobs\OpenLotteryIssueJob::dispatch($roomId);
|
||||
$openedRoomIds[] = $roomId;
|
||||
}
|
||||
|
||||
\App\Jobs\OpenLotteryIssueJob::dispatch();
|
||||
if ($openedRoomIds === []) {
|
||||
return response()->json(['ok' => false, 'message' => '目标房间当前已有进行中的期次,无需重复开期。']);
|
||||
}
|
||||
|
||||
return response()->json(['ok' => true, 'message' => '✅ 已排队开期任务,新期次将就绪建立!']);
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'message' => '✅ 已排队开期任务,目标房间:#'.implode('、#', $openedRoomIds),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,16 +20,21 @@ use App\Models\BaccaratBet;
|
||||
use App\Models\BaccaratRound;
|
||||
use App\Models\GameConfig;
|
||||
use App\Services\BaccaratLossCoverService;
|
||||
use App\Services\GameRoomScopeService;
|
||||
use App\Services\UserCurrencyService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* 类功能:提供百家乐当前局查询、下注与历史接口。
|
||||
*/
|
||||
class BaccaratController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserCurrencyService $currency,
|
||||
private readonly BaccaratLossCoverService $lossCoverService,
|
||||
private readonly GameRoomScopeService $roomScopeService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -38,7 +43,13 @@ class BaccaratController extends Controller
|
||||
public function currentRound(Request $request): JsonResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
$round = BaccaratRound::currentRound();
|
||||
$roomId = $this->roomScopeService->resolveRequestRoomId($request, $user);
|
||||
|
||||
if (! $this->roomScopeService->isRoomAllowedForGame('baccarat', $roomId)) {
|
||||
return response()->json(['round' => null, 'jjb' => (int) ($user->jjb ?? 0)]);
|
||||
}
|
||||
|
||||
$round = BaccaratRound::currentRound($roomId);
|
||||
|
||||
if (! $round) {
|
||||
return response()->json([
|
||||
@@ -98,6 +109,11 @@ class BaccaratController extends Controller
|
||||
'bet_type' => 'required|in:big,small,triple',
|
||||
'amount' => 'required|integer|min:1',
|
||||
]);
|
||||
$roomId = $this->roomScopeService->resolveRequestRoomId($request, $request->user());
|
||||
|
||||
if (! $this->roomScopeService->isRoomAllowedForGame('baccarat', $roomId)) {
|
||||
return response()->json(['ok' => false, 'message' => '当前房间未开启百家乐。'], 403);
|
||||
}
|
||||
|
||||
$config = GameConfig::forGame('baccarat')?->params ?? [];
|
||||
$minBet = (int) ($config['min_bet'] ?? 100);
|
||||
@@ -109,7 +125,7 @@ class BaccaratController extends Controller
|
||||
|
||||
$round = BaccaratRound::find($data['round_id']);
|
||||
|
||||
if (! $round || ! $round->isBettingOpen()) {
|
||||
if (! $round || (int) $round->room_id !== $roomId || ! $round->isBettingOpen()) {
|
||||
return response()->json(['ok' => false, 'message' => '当前不在下注时间内。']);
|
||||
}
|
||||
|
||||
@@ -212,7 +228,9 @@ class BaccaratController extends Controller
|
||||
*/
|
||||
public function history(): JsonResponse
|
||||
{
|
||||
$roomId = $this->roomScopeService->resolveUserRoomId(auth()->user());
|
||||
$rounds = BaccaratRound::query()
|
||||
->where('room_id', $roomId)
|
||||
->where('status', 'settled')
|
||||
->orderByDesc('id')
|
||||
->limit(10)
|
||||
|
||||
@@ -21,6 +21,7 @@ use App\Models\GameConfig;
|
||||
use App\Models\Sysparam;
|
||||
use App\Services\ChatStateService;
|
||||
use App\Services\FishingService;
|
||||
use App\Services\GameRoomScopeService;
|
||||
use App\Services\ShopService;
|
||||
use App\Services\UserCurrencyService;
|
||||
use App\Services\VipService;
|
||||
@@ -30,6 +31,9 @@ use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* 类功能:处理钓鱼小游戏的抛竿与收竿流程。
|
||||
*/
|
||||
class FishingController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
@@ -38,6 +42,7 @@ class FishingController extends Controller
|
||||
private readonly UserCurrencyService $currencyService,
|
||||
private readonly ShopService $shopService,
|
||||
private readonly FishingService $fishingService,
|
||||
private readonly GameRoomScopeService $roomScopeService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -63,6 +68,10 @@ class FishingController extends Controller
|
||||
return response()->json(['status' => 'error', 'message' => '钓鱼功能暂未开放。'], 403);
|
||||
}
|
||||
|
||||
if (! $this->roomScopeService->isRoomAllowedForGame('fishing', $id)) {
|
||||
return response()->json(['status' => 'error', 'message' => '当前房间未开启钓鱼小游戏。'], 403);
|
||||
}
|
||||
|
||||
// 1. 检查冷却时间(Redis TTL)
|
||||
$cooldownKey = "fishing:cd:{$user->id}";
|
||||
if (Redis::exists($cooldownKey)) {
|
||||
@@ -142,6 +151,10 @@ class FishingController extends Controller
|
||||
return response()->json(['status' => 'error', 'message' => '请先登录'], 401);
|
||||
}
|
||||
|
||||
if (! $this->roomScopeService->isRoomAllowedForGame('fishing', $id)) {
|
||||
return response()->json(['status' => 'error', 'message' => '当前房间未开启钓鱼小游戏。'], 403);
|
||||
}
|
||||
|
||||
// 1. 验证 token + 服务端时间校验(防止前端篡改 wait_time 跳过等待)
|
||||
$tokenKey = "fishing:token:{$user->id}";
|
||||
$storedJson = Redis::get($tokenKey);
|
||||
|
||||
@@ -18,14 +18,19 @@ namespace App\Http\Controllers;
|
||||
use App\Enums\CurrencySource;
|
||||
use App\Models\FortuneLog;
|
||||
use App\Models\GameConfig;
|
||||
use App\Services\GameRoomScopeService;
|
||||
use App\Services\UserCurrencyService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* 类功能:提供神秘占卜状态、抽签和历史接口。
|
||||
*/
|
||||
class FortuneTellingController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserCurrencyService $currency,
|
||||
private readonly GameRoomScopeService $roomScopeService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -37,6 +42,11 @@ class FortuneTellingController extends Controller
|
||||
return response()->json(['enabled' => false]);
|
||||
}
|
||||
|
||||
$roomId = $this->roomScopeService->resolveRequestRoomId($request, $request->user());
|
||||
if (! $this->roomScopeService->isRoomAllowedForGame('fortune_telling', $roomId)) {
|
||||
return response()->json(['enabled' => false]);
|
||||
}
|
||||
|
||||
$user = $request->user();
|
||||
$config = GameConfig::forGame('fortune_telling')?->params ?? [];
|
||||
|
||||
@@ -81,6 +91,11 @@ class FortuneTellingController extends Controller
|
||||
return response()->json(['ok' => false, 'message' => '神秘占卜当前未开启。']);
|
||||
}
|
||||
|
||||
$roomId = $this->roomScopeService->resolveRequestRoomId($request, $request->user());
|
||||
if (! $this->roomScopeService->isRoomAllowedForGame('fortune_telling', $roomId)) {
|
||||
return response()->json(['ok' => false, 'message' => '当前房间未开启神秘占卜。'], 403);
|
||||
}
|
||||
|
||||
$user = $request->user();
|
||||
$config = GameConfig::forGame('fortune_telling')?->params ?? [];
|
||||
|
||||
@@ -145,6 +160,11 @@ class FortuneTellingController extends Controller
|
||||
*/
|
||||
public function history(Request $request): JsonResponse
|
||||
{
|
||||
$roomId = $this->roomScopeService->resolveRequestRoomId($request, $request->user());
|
||||
if (! $this->roomScopeService->isRoomAllowedForGame('fortune_telling', $roomId)) {
|
||||
return response()->json(['history' => []]);
|
||||
}
|
||||
|
||||
$logs = FortuneLog::query()
|
||||
->where('user_id', $request->user()->id)
|
||||
->orderByDesc('id')
|
||||
|
||||
@@ -24,17 +24,22 @@ use App\Events\GomokuInviteEvent;
|
||||
use App\Events\GomokuMovedEvent;
|
||||
use App\Models\GameConfig;
|
||||
use App\Models\GomokuGame;
|
||||
use App\Services\GameRoomScopeService;
|
||||
use App\Services\GomokuAiService;
|
||||
use App\Services\UserCurrencyService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* 类功能:处理五子棋创建、加入与对局过程接口。
|
||||
*/
|
||||
class GomokuController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly GomokuAiService $ai,
|
||||
private readonly UserCurrencyService $currency,
|
||||
private readonly GameRoomScopeService $roomScopeService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -58,6 +63,10 @@ class GomokuController extends Controller
|
||||
|
||||
$user = $request->user();
|
||||
|
||||
if (! $this->roomScopeService->isRoomAllowedForGame('gomoku', (int) $data['room_id'])) {
|
||||
return response()->json(['ok' => false, 'message' => '当前房间未开启五子棋。'], 403);
|
||||
}
|
||||
|
||||
// PvP:检查是否已在等待/对局中(一次只能参与一场)
|
||||
$activeGame = GomokuGame::query()
|
||||
->where(function ($q) use ($user) {
|
||||
|
||||
@@ -23,6 +23,7 @@ use App\Models\GameConfig;
|
||||
use App\Models\HorseBet;
|
||||
use App\Models\HorseRace;
|
||||
use App\Services\ChatStateService;
|
||||
use App\Services\GameRoomScopeService;
|
||||
use App\Services\UserCurrencyService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -38,6 +39,7 @@ class HorseRaceController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserCurrencyService $currency,
|
||||
private readonly GameRoomScopeService $roomScopeService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -50,7 +52,12 @@ class HorseRaceController extends Controller
|
||||
return response()->json(['message' => '未登录', 'status' => 'error'], 401);
|
||||
}
|
||||
|
||||
$race = $this->resolveCurrentRaceState(HorseRace::currentRace());
|
||||
$roomId = $this->roomScopeService->resolveRequestRoomId($request, $user);
|
||||
if (! $this->roomScopeService->isRoomAllowedForGame('horse_racing', $roomId)) {
|
||||
return response()->json(['race' => null, 'jjb' => (int) ($user->jjb ?? 0)]);
|
||||
}
|
||||
|
||||
$race = $this->resolveCurrentRaceState(HorseRace::currentRace($roomId));
|
||||
|
||||
if (! $race) {
|
||||
return response()->json([
|
||||
@@ -145,6 +152,11 @@ class HorseRaceController extends Controller
|
||||
'horse_id' => 'required|integer|min:1',
|
||||
'amount' => 'required|integer|min:1',
|
||||
]);
|
||||
$roomId = $this->roomScopeService->resolveRequestRoomId($request, $request->user());
|
||||
|
||||
if (! $this->roomScopeService->isRoomAllowedForGame('horse_racing', $roomId)) {
|
||||
return response()->json(['ok' => false, 'message' => '当前房间未开启赛马竞猜。'], 403);
|
||||
}
|
||||
|
||||
$config = GameConfig::forGame('horse_racing')?->params ?? [];
|
||||
$minBet = (int) ($config['min_bet'] ?? 100);
|
||||
@@ -156,7 +168,7 @@ class HorseRaceController extends Controller
|
||||
|
||||
$race = HorseRace::find($data['race_id']);
|
||||
|
||||
if (! $race || ! $race->isBettingOpen()) {
|
||||
if (! $race || (int) $race->room_id !== $roomId || ! $race->isBettingOpen()) {
|
||||
return response()->json(['ok' => false, 'message' => '当前不在下注时间内。']);
|
||||
}
|
||||
|
||||
@@ -213,8 +225,8 @@ class HorseRaceController extends Controller
|
||||
$formattedAmount = number_format($data['amount']);
|
||||
$content = "🐎 <b>【赛马】【{$user->username}】</b> 押注了 <b>{$formattedAmount}</b> 金币({$horseName})!✨";
|
||||
$msg = [
|
||||
'id' => $chatState->nextMessageId(1),
|
||||
'room_id' => 1,
|
||||
'id' => $chatState->nextMessageId((int) $race->room_id),
|
||||
'room_id' => (int) $race->room_id,
|
||||
'from_user' => '系统传音',
|
||||
'to_user' => '大家',
|
||||
'content' => $content,
|
||||
@@ -223,8 +235,8 @@ class HorseRaceController extends Controller
|
||||
'action' => '',
|
||||
'sent_at' => now()->toDateTimeString(),
|
||||
];
|
||||
$chatState->pushMessage(1, $msg);
|
||||
event(new MessageSent(1, $msg));
|
||||
$chatState->pushMessage((int) $race->room_id, $msg);
|
||||
event(new MessageSent((int) $race->room_id, $msg));
|
||||
SaveMessageJob::dispatch($msg);
|
||||
|
||||
return response()->json([
|
||||
@@ -241,7 +253,9 @@ class HorseRaceController extends Controller
|
||||
*/
|
||||
public function history(): JsonResponse
|
||||
{
|
||||
$roomId = $this->roomScopeService->resolveUserRoomId(auth()->user());
|
||||
$races = HorseRace::query()
|
||||
->where('room_id', $roomId)
|
||||
->where('status', 'settled')
|
||||
->orderByDesc('id')
|
||||
->limit(10)
|
||||
@@ -291,7 +305,7 @@ class HorseRaceController extends Controller
|
||||
// 线上若漏消费 CloseHorseRaceJob,这里同步补做一次结算,避免界面一直显示“跑马中”。
|
||||
app()->call([new \App\Jobs\CloseHorseRaceJob($race), 'handle']);
|
||||
|
||||
return HorseRace::currentRace();
|
||||
return HorseRace::currentRace((int) $race->room_id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,27 +19,38 @@ namespace App\Http\Controllers;
|
||||
use App\Models\GameConfig;
|
||||
use App\Models\LotteryIssue;
|
||||
use App\Models\LotteryTicket;
|
||||
use App\Services\GameRoomScopeService;
|
||||
use App\Services\LotteryService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
/**
|
||||
* 类功能:提供双色球当前期、购票和历史记录接口。
|
||||
*/
|
||||
class LotteryController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly LotteryService $lottery,
|
||||
private readonly GameRoomScopeService $roomScopeService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 返回当期状态:期号、奖池、剩余时间、我本期购票列表。
|
||||
*/
|
||||
public function current(): JsonResponse
|
||||
public function current(Request $request): JsonResponse
|
||||
{
|
||||
if (! GameConfig::isEnabled('lottery')) {
|
||||
return response()->json(['enabled' => false]);
|
||||
}
|
||||
|
||||
$issue = LotteryIssue::currentIssue() ?? LotteryIssue::latestIssue();
|
||||
$roomId = $this->roomScopeService->resolveRequestRoomId($request);
|
||||
|
||||
if (! $this->roomScopeService->isRoomAllowedForGame('lottery', $roomId)) {
|
||||
return response()->json(['enabled' => false, 'message' => '当前房间未开启双色球彩票。'], 403);
|
||||
}
|
||||
|
||||
$issue = LotteryIssue::currentIssue($roomId) ?? LotteryIssue::latestIssue($roomId);
|
||||
|
||||
if (! $issue) {
|
||||
return response()->json(['enabled' => true, 'issue' => null]);
|
||||
@@ -90,6 +101,11 @@ class LotteryController extends Controller
|
||||
*/
|
||||
public function buy(Request $request): JsonResponse
|
||||
{
|
||||
$roomId = $this->roomScopeService->resolveRequestRoomId($request);
|
||||
if (! $this->roomScopeService->isRoomAllowedForGame('lottery', $roomId)) {
|
||||
return response()->json(['status' => 'error', 'message' => '当前房间未开启双色球彩票。'], 403);
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'numbers' => 'required|array|min:1',
|
||||
'numbers.*.reds' => 'required|array|size:3',
|
||||
@@ -132,7 +148,9 @@ class LotteryController extends Controller
|
||||
*/
|
||||
public function history(): JsonResponse
|
||||
{
|
||||
$roomId = $this->roomScopeService->resolveUserRoomId(Auth::user());
|
||||
$issues = LotteryIssue::query()
|
||||
->where('room_id', $roomId)
|
||||
->where('status', 'settled')
|
||||
->latest()
|
||||
->limit(20)
|
||||
|
||||
@@ -28,28 +28,38 @@ use App\Models\GameConfig;
|
||||
use App\Models\MysteryBox;
|
||||
use App\Models\MysteryBoxClaim;
|
||||
use App\Services\ChatStateService;
|
||||
use App\Services\GameRoomScopeService;
|
||||
use App\Services\UserCurrencyService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* 类功能:提供神秘箱子状态查询与暗号开箱接口。
|
||||
*/
|
||||
class MysteryBoxController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserCurrencyService $currency,
|
||||
private readonly ChatStateService $chatState,
|
||||
private readonly GameRoomScopeService $roomScopeService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 查询当前可领取的箱子状态(给前端轮询/显示用)。
|
||||
*/
|
||||
public function status(): JsonResponse
|
||||
public function status(Request $request): JsonResponse
|
||||
{
|
||||
if (! GameConfig::isEnabled('mystery_box')) {
|
||||
return response()->json(['active' => false]);
|
||||
}
|
||||
|
||||
$box = MysteryBox::currentOpenBox();
|
||||
$roomId = $this->roomScopeService->resolveRequestRoomId($request);
|
||||
if (! $this->roomScopeService->isRoomAllowedForGame('mystery_box', $roomId)) {
|
||||
return response()->json(['active' => false]);
|
||||
}
|
||||
|
||||
$box = MysteryBox::currentOpenBox($roomId);
|
||||
|
||||
if (! $box) {
|
||||
return response()->json(['active' => false]);
|
||||
@@ -85,10 +95,16 @@ class MysteryBoxController extends Controller
|
||||
}
|
||||
|
||||
$user = $request->user();
|
||||
$roomId = $this->roomScopeService->resolveRequestRoomId($request, $user);
|
||||
|
||||
return DB::transaction(function () use ($user, $passcode): JsonResponse {
|
||||
if (! $this->roomScopeService->isRoomAllowedForGame('mystery_box', $roomId)) {
|
||||
return response()->json(['ok' => false, 'message' => '当前房间未开启神秘箱子。'], 403);
|
||||
}
|
||||
|
||||
return DB::transaction(function () use ($user, $passcode, $roomId): JsonResponse {
|
||||
// 查找匹配暗号的可领取箱子(加锁防并发)
|
||||
$box = MysteryBox::query()
|
||||
->where('room_id', $roomId)
|
||||
->where('passcode', $passcode)
|
||||
->where('status', 'open')
|
||||
->where(fn ($q) => $q->whereNull('expires_at')->orWhere('expires_at', '>', now()))
|
||||
@@ -147,18 +163,16 @@ class MysteryBoxController extends Controller
|
||||
$typeName = $box->typeName();
|
||||
|
||||
if ($reward >= 0) {
|
||||
$content = "{$emoji}【神秘箱子】开箱播报:恭喜 【{$username}】 抢到了神秘{$typeName}!"
|
||||
.'获得 💰'.number_format($reward).' 金币!';
|
||||
$content = "{$emoji} 【{$username}】抢到{$typeName},获得 💰".number_format($reward).' 金币!';
|
||||
$color = $box->box_type === 'rare' ? '#c4b5fd' : '#34d399';
|
||||
} else {
|
||||
$content = "☠️【神秘箱子】《黑化陷阱》haha!【{$username}】 中了神秘黑化箱的陷阱!"
|
||||
.'被扣除 💰'.number_format(abs($reward)).' 金币!点背~';
|
||||
$content = "☠️ 【{$username}】踩中黑化陷阱,扣除 💰".number_format(abs($reward)).' 金币!';
|
||||
$color = '#f87171';
|
||||
}
|
||||
|
||||
$msg = [
|
||||
'id' => $this->chatState->nextMessageId(1),
|
||||
'room_id' => 1,
|
||||
'id' => $this->chatState->nextMessageId((int) $box->room_id),
|
||||
'room_id' => (int) $box->room_id,
|
||||
'from_user' => '系统传音',
|
||||
'to_user' => '大家',
|
||||
'content' => $content,
|
||||
@@ -168,8 +182,8 @@ class MysteryBoxController extends Controller
|
||||
'sent_at' => now()->toDateTimeString(),
|
||||
];
|
||||
|
||||
$this->chatState->pushMessage(1, $msg);
|
||||
broadcast(new MessageSent(1, $msg));
|
||||
$this->chatState->pushMessage((int) $box->room_id, $msg);
|
||||
broadcast(new MessageSent((int) $box->room_id, $msg));
|
||||
SaveMessageJob::dispatch($msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,16 +23,21 @@ use App\Jobs\SaveMessageJob;
|
||||
use App\Models\GameConfig;
|
||||
use App\Models\SlotMachineLog;
|
||||
use App\Services\ChatStateService;
|
||||
use App\Services\GameRoomScopeService;
|
||||
use App\Services\UserCurrencyService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* 类功能:提供老虎机信息查询、转动和个人记录接口。
|
||||
*/
|
||||
class SlotMachineController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserCurrencyService $currency,
|
||||
private readonly ChatStateService $chatState,
|
||||
private readonly GameRoomScopeService $roomScopeService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -44,6 +49,11 @@ class SlotMachineController extends Controller
|
||||
return response()->json(['enabled' => false]);
|
||||
}
|
||||
|
||||
$roomId = $this->roomScopeService->resolveRequestRoomId($request, $request->user());
|
||||
if (! $this->roomScopeService->isRoomAllowedForGame('slot_machine', $roomId)) {
|
||||
return response()->json(['enabled' => false]);
|
||||
}
|
||||
|
||||
$config = GameConfig::forGame('slot_machine')?->params ?? [];
|
||||
$user = $request->user();
|
||||
$dailyLimit = (int) ($config['daily_limit'] ?? 0);
|
||||
@@ -77,6 +87,11 @@ class SlotMachineController extends Controller
|
||||
return response()->json(['ok' => false, 'message' => '老虎机未开放。']);
|
||||
}
|
||||
|
||||
$roomId = $this->roomScopeService->resolveRequestRoomId($request, $request->user());
|
||||
if (! $this->roomScopeService->isRoomAllowedForGame('slot_machine', $roomId)) {
|
||||
return response()->json(['ok' => false, 'message' => '当前房间未开启老虎机。'], 403);
|
||||
}
|
||||
|
||||
$config = GameConfig::forGame('slot_machine')?->params ?? [];
|
||||
$cost = (int) ($config['cost_per_spin'] ?? 100);
|
||||
$dailyLimit = (int) ($config['daily_limit'] ?? 0);
|
||||
@@ -100,7 +115,7 @@ class SlotMachineController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
return DB::transaction(function () use ($user, $cost, $config): JsonResponse {
|
||||
return DB::transaction(function () use ($user, $cost, $config, $roomId): JsonResponse {
|
||||
// ① 扣费
|
||||
$this->currency->change(
|
||||
$user,
|
||||
@@ -164,16 +179,16 @@ class SlotMachineController extends Controller
|
||||
|
||||
if ($resultType === 'jackpot') {
|
||||
// 三个7:全服公屏广播
|
||||
$this->broadcastJackpot($user->username, $payout, $cost);
|
||||
$this->broadcastJackpot($user->username, $payout, $cost, $roomId);
|
||||
} elseif (in_array($resultType, ['triple_gem', 'triple', 'pair'], true)) {
|
||||
// 普通中奖:仅向本人发送聊天室系统通知
|
||||
$net = $payout - $cost;
|
||||
$content = "🎰 {$resultLabel}!{$e1}{$e2}{$e3} 赢得 +💰".number_format($net).' 金币';
|
||||
$this->broadcastPersonal($user->username, $content);
|
||||
$this->broadcastPersonal($user->username, $content, $roomId);
|
||||
} elseif ($resultType === 'curse') {
|
||||
// 诅咒:通知本人
|
||||
$content = "☠️ 三骷髅诅咒!{$e1}{$e2}{$e3} 额外扣除 💰".number_format($cost).' 金币!';
|
||||
$this->broadcastPersonal($user->username, $content);
|
||||
$this->broadcastPersonal($user->username, $content, $roomId);
|
||||
}
|
||||
|
||||
$user->refresh();
|
||||
@@ -200,6 +215,11 @@ class SlotMachineController extends Controller
|
||||
*/
|
||||
public function history(Request $request): JsonResponse
|
||||
{
|
||||
$roomId = $this->roomScopeService->resolveRequestRoomId($request, $request->user());
|
||||
if (! $this->roomScopeService->isRoomAllowedForGame('slot_machine', $roomId)) {
|
||||
return response()->json(['history' => []]);
|
||||
}
|
||||
|
||||
$logs = SlotMachineLog::query()
|
||||
->where('user_id', $request->user()->id)
|
||||
->orderByDesc('id')
|
||||
@@ -239,15 +259,15 @@ class SlotMachineController extends Controller
|
||||
/**
|
||||
* 三个7全服公屏广播。
|
||||
*/
|
||||
private function broadcastJackpot(string $username, int $payout, int $cost): void
|
||||
private function broadcastJackpot(string $username, int $payout, int $cost, int $roomId): void
|
||||
{
|
||||
$net = $payout - $cost;
|
||||
$content = "🎰🎉【老虎机大奖】恭喜 【{$username}】 转出三个7️⃣!"
|
||||
.'狂揽 💰'.number_format($net).' 金币!全服见证奇迹!';
|
||||
|
||||
$msg = [
|
||||
'id' => $this->chatState->nextMessageId(1),
|
||||
'room_id' => 1,
|
||||
'id' => $this->chatState->nextMessageId($roomId),
|
||||
'room_id' => $roomId,
|
||||
'from_user' => '系统传音',
|
||||
'to_user' => '大家',
|
||||
'content' => $content,
|
||||
@@ -257,8 +277,8 @@ class SlotMachineController extends Controller
|
||||
'sent_at' => now()->toDateTimeString(),
|
||||
];
|
||||
|
||||
$this->chatState->pushMessage(1, $msg);
|
||||
broadcast(new MessageSent(1, $msg));
|
||||
$this->chatState->pushMessage($roomId, $msg);
|
||||
broadcast(new MessageSent($roomId, $msg));
|
||||
SaveMessageJob::dispatch($msg);
|
||||
}
|
||||
|
||||
@@ -268,11 +288,11 @@ class SlotMachineController extends Controller
|
||||
* @param string $toUsername 接收用户名
|
||||
* @param string $content 消息内容
|
||||
*/
|
||||
private function broadcastPersonal(string $toUsername, string $content): void
|
||||
private function broadcastPersonal(string $toUsername, string $content, int $roomId): void
|
||||
{
|
||||
$msg = [
|
||||
'id' => $this->chatState->nextMessageId(1),
|
||||
'room_id' => 1,
|
||||
'id' => $this->chatState->nextMessageId($roomId),
|
||||
'room_id' => $roomId,
|
||||
'from_user' => '系统传音',
|
||||
'to_user' => $toUsername,
|
||||
'content' => $content,
|
||||
@@ -282,7 +302,7 @@ class SlotMachineController extends Controller
|
||||
'sent_at' => now()->toDateTimeString(),
|
||||
];
|
||||
|
||||
broadcast(new MessageSent(1, $msg));
|
||||
broadcast(new MessageSent($roomId, $msg));
|
||||
SaveMessageJob::dispatch($msg);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user