race->fresh(); // 防止重复结算 if (! $race || $race->status !== 'running') { return; } // CAS 改状态为 settled $updated = HorseRace::query() ->where('id', $race->id) ->where('status', 'running') ->update(['status' => 'settled', 'settled_at' => now()]); if (! $updated) { return; } $race->refresh(); $config = GameConfig::forGame('horse_racing')?->params ?? []; $houseTake = (int) ($config['house_take_percent'] ?? 5); $winnerId = (int) $race->winner_horse_id; // 按马匹统计各匹下注金额 $horsePools = HorseBet::query() ->where('race_id', $race->id) ->groupBy('horse_id') ->selectRaw('horse_id, SUM(amount) as pool') ->pluck('pool', 'horse_id') ->toArray(); $totalPool = array_sum($horsePools); $winnerPool = (int) ($horsePools[$winnerId] ?? 0); $netPool = (int) ($totalPool * (1 - $houseTake / 100)); // 结算:遍历所有下注记录 $bets = HorseBet::query() ->where('race_id', $race->id) ->where('status', 'pending') ->with('user') ->get(); $totalPayout = 0; DB::transaction(function () use ($bets, $winnerId, $netPool, $winnerPool, $currency, &$totalPayout) { foreach ($bets as $bet) { if ((int) $bet->horse_id !== $winnerId) { // 未中奖(本金已在下注时扣除) $bet->update(['status' => 'lost', 'payout' => 0]); continue; } // 中奖:按注额比例分配净注池 if ($winnerPool > 0) { $payout = (int) round($netPool * ($bet->amount / $winnerPool)); } else { $payout = 0; } $bet->update(['status' => 'won', 'payout' => $payout]); if ($payout > 0 && $bet->user) { $currency->change( $bet->user, 'gold', $payout, CurrencySource::HORSE_WIN, "赛马 #{$this->race->id} 「{$bet->horse_id}号马」中奖", ); } $totalPayout += $payout; } }); // 公屏公告 $this->pushResultMessage($race, $chatState, $totalPayout); // 广播结算事件 broadcast(new HorseRaceSettled($race)); } /** * 向公屏发送赛果系统消息。 */ private function pushResultMessage(HorseRace $race, ChatStateService $chatState, int $totalPayout): void { // 找出胜利马匹名称 $horses = $race->horses ?? []; $winnerName = '未知'; foreach ($horses as $horse) { if (($horse['id'] ?? 0) === (int) $race->winner_horse_id) { $winnerName = ($horse['emoji'] ?? '').($horse['name'] ?? ''); break; } } $payoutText = $totalPayout > 0 ? '共派发 💰'.number_format($totalPayout).' 金币' : '本场无人获奖'; $content = "🏆 【赛马】第 #{$race->id} 场结束!冠军:{$winnerName}!{$payoutText}。"; $msg = [ 'id' => $chatState->nextMessageId(1), 'room_id' => 1, 'from_user' => '系统传音', 'to_user' => '大家', 'content' => $content, 'is_secret' => false, 'font_color' => '#f59e0b', 'action' => '大声宣告', 'sent_at' => now()->toDateTimeString(), ]; $chatState->pushMessage(1, $msg); broadcast(new MessageSent(1, $msg)); SaveMessageJob::dispatch($msg); } }