Files
chatroom/routes/console.php
lkddi b30be5c053 修复:赛马开局延迟 30 秒,避免与百家乐同时广播公屏
两个游戏都由每分钟调度器触发,条件同时满足时会在同一秒发公屏,
互相干扰且用户体验混乱。

解决方案:OpenHorseRaceJob::dispatch()->delay(30s)
- 百家乐:整分钟触发(:00)
- 赛马:整分钟 +30 秒触发(:30)
两个游戏公屏广播自然错开半分钟
2026-03-04 15:06:06 +08:00

130 lines
5.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schedule;
Artisan::command('inspire', function () {
$this->comment(Inspiring::quote());
})->purpose('Display an inspiring quote');
// 每天凌晨 3 点清理超过 30 天的聊天记录
Schedule::command('messages:purge')->dailyAt('03:00');
// 每 5 分钟为所有在线用户自动存点(经验/金币/等级)
Schedule::command('chatroom:auto-save-exp')->everyFiveMinutes();
// ──────────── 婚姻系统定时任务 ────────────────────────────────────
// 每 5 分钟扫描超时求婚48h后失效 + 戒指消失 + 广播通知)
Schedule::job(new \App\Jobs\ExpireMarriageProposals)->everyFiveMinutes();
// 每 5 分钟:触发到时的定时婚礼(红包分发 + 广播庆典)
Schedule::job(new \App\Jobs\TriggerScheduledWeddings)->everyFiveMinutes();
// 每小时协议离婚超时自动升级为强制72h无响应
Schedule::job(new \App\Jobs\AutoExpireDivorces)->hourly();
// 每小时清理过期婚礼红包expired_at 过后标记 completed
Schedule::job(new \App\Jobs\ExpireWeddingEnvelopes)->hourly();
// 每天 00:05全量处理婚姻亲密度时间奖励每日加分
Schedule::job(new \App\Jobs\ProcessMarriageIntimacy)->dailyAt('00:05');
// ──────────── 节日福利定时任务 ────────────────────────────────────
// 每分钟:扫描并触发到期的节日福利活动
Schedule::call(function () {
\App\Models\HolidayEvent::pendingToTrigger()
->each(fn ($e) => \App\Jobs\TriggerHolidayEventJob::dispatch($e));
})->everyMinute()->name('holiday-events:trigger')->withoutOverlapping();
// ──────────── 百家乐定时任务 ─────────────────────────────────────
// 每分钟:检查是否应开新一局(游戏开启 + 无正在进行的局)
Schedule::call(function () {
if (! \App\Models\GameConfig::isEnabled('baccarat')) {
return;
}
$config = \App\Models\GameConfig::forGame('baccarat')?->params ?? [];
$interval = (int) ($config['interval_minutes'] ?? 2);
// 检查距上一局触发时间是否已达到间隔
$lastRound = \App\Models\BaccaratRound::latest()->first();
if ($lastRound && $lastRound->created_at->diffInMinutes(now()) < $interval) {
return; // 还没到开局时间
}
// 无当前进行中的局才开新局
if (! \App\Models\BaccaratRound::currentRound()) {
\App\Jobs\OpenBaccaratRoundJob::dispatch();
}
})->everyMinute()->name('baccarat:open-round')->withoutOverlapping();
// ──────────── 神秘箱子定时投放 ─────────────────────────────────
// 每分钟:检查是否应自动投放一个新箱子
Schedule::call(function () {
if (! \App\Models\GameConfig::isEnabled('mystery_box')) {
return;
}
$config = \App\Models\GameConfig::forGame('mystery_box')?->params ?? [];
// 自动投放开关
if (! ($config['auto_drop_enabled'] ?? false)) {
return;
}
// 当前已有可领取的箱子时跳过(一次只投放一个)
if (\App\Models\MysteryBox::currentOpenBox()) {
return;
}
$intervalHours = (float) ($config['auto_interval_hours'] ?? 2);
// 检查距上次投放时间
$lastBox = \App\Models\MysteryBox::latest()->first();
if ($lastBox && $lastBox->created_at->diffInHours(now()) < $intervalHours) {
return;
}
// 按配置的陷阱概率决定箱子类型
$trapChance = (int) ($config['trap_chance_percent'] ?? 10);
$rand = random_int(1, 100);
$boxType = match (true) {
$rand <= $trapChance => 'trap',
$rand <= $trapChance + 15 => 'rare',
default => 'normal',
};
\App\Jobs\DropMysteryBoxJob::dispatch($boxType);
})->everyMinute()->name('mystery-box:auto-drop')->withoutOverlapping();
// ──────────── 赛马竞猜定时任务 ─────────────────────────────────
// 每分钟:检查是否应开启新一场赛马
Schedule::call(function () {
if (! \App\Models\GameConfig::isEnabled('horse_racing')) {
return;
}
// 当前已有进行中的场次(押注中/跑马中),跳过
if (\App\Models\HorseRace::currentRace()) {
return;
}
$config = \App\Models\GameConfig::forGame('horse_racing')?->params ?? [];
$interval = (int) ($config['interval_minutes'] ?? 30);
// 检查距上一场触发时间是否已达到间隔
$lastRace = \App\Models\HorseRace::latest()->first();
if ($lastRace && $lastRace->created_at->diffInMinutes(now()) < $interval) {
return;
}
\App\Jobs\OpenHorseRaceJob::dispatch()->delay(now()->addSeconds(30));
})->everyMinute()->name('horse-race:open-race')->withoutOverlapping();