173 lines
5.8 KiB
PHP
173 lines
5.8 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace app\common\library;
|
||
|
||
use support\think\Db;
|
||
use Throwable;
|
||
|
||
/**
|
||
* 根据档位奖励 JSON 生成 game_reward_weight 对照(先删后插)
|
||
*/
|
||
final class GameRewardWeightSeeder
|
||
{
|
||
private const LEOPARD = [5, 10, 15, 20, 25, 30];
|
||
|
||
/**
|
||
* @throws Throwable
|
||
*/
|
||
public static function syncFromTierRewardForm(int $gameChannelId, string $tierRewardFormJson): void
|
||
{
|
||
$decoded = json_decode($tierRewardFormJson, true);
|
||
if (!is_array($decoded) || count($decoded) !== 26) {
|
||
throw new \RuntimeException('档位奖励表单必须为 26 条且为合法 JSON');
|
||
}
|
||
|
||
$byGrid = [];
|
||
foreach ($decoded as $idx => $row) {
|
||
if (!is_array($row)) {
|
||
throw new \RuntimeException('档位奖励表单第' . strval($idx + 1) . '条格式错误');
|
||
}
|
||
$g = $row['grid_number'] ?? null;
|
||
if (!is_numeric($g)) {
|
||
throw new \RuntimeException('档位奖励表单第' . strval($idx + 1) . '条点数无效');
|
||
}
|
||
$gi = intval(strval($g));
|
||
if ($gi < 5 || $gi > 30) {
|
||
throw new \RuntimeException('档位奖励表单点数须在 5~30');
|
||
}
|
||
$byGrid[$gi] = $row;
|
||
}
|
||
|
||
$cells = [];
|
||
for ($i = 0; $i < 26; $i++) {
|
||
$g = 5 + $i;
|
||
if (!isset($byGrid[$g])) {
|
||
throw new \RuntimeException('档位奖励表单缺少点数 ' . strval($g));
|
||
}
|
||
$cells[$i] = self::normalizeCell($byGrid[$g], $i + 1);
|
||
}
|
||
|
||
self::assertLeopardOk($cells);
|
||
|
||
$batch = [];
|
||
for ($d = 5; $d <= 30; $d++) {
|
||
$start = $d - 5;
|
||
$endCw = ($start + $d) % 26;
|
||
$x = $start - $d;
|
||
$endCcw = $x >= 0 ? $x : 26 + $start - $d;
|
||
$batch[] = self::buildInsertRow($gameChannelId, 0, $d, $start, $endCw, $cells[$endCw]);
|
||
$batch[] = self::buildInsertRow($gameChannelId, 1, $d, $start, $endCcw, $cells[$endCcw]);
|
||
}
|
||
|
||
$now = time();
|
||
foreach ($batch as $k => $_) {
|
||
$batch[$k]['create_time'] = $now;
|
||
$batch[$k]['update_time'] = $now;
|
||
}
|
||
|
||
Db::startTrans();
|
||
try {
|
||
Db::name('game_reward_weight')->where('game_channel_id', $gameChannelId)->delete();
|
||
Db::name('game_reward_weight')->insertAll($batch);
|
||
Db::commit();
|
||
} catch (Throwable $e) {
|
||
Db::rollback();
|
||
$msg = $e->getMessage();
|
||
if (str_contains($msg, 'game_reward_weight') || str_contains($msg, "doesn't exist")) {
|
||
throw new \RuntimeException('写入失败:请确认已创建数据表 game_reward_weight 并已执行迁移。' . $msg);
|
||
}
|
||
throw $e;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @param list<array{ui_text: string, real_ev: float, tier: string, remark: string}> $cells
|
||
*/
|
||
private static function assertLeopardOk(array $cells): void
|
||
{
|
||
foreach (self::LEOPARD as $d) {
|
||
$start = $d - 5;
|
||
$endCw = ($start + $d) % 26;
|
||
$x = $start - $d;
|
||
$endCcw = $x >= 0 ? $x : 26 + $start - $d;
|
||
foreach ([$endCw, $endCcw] as $idx) {
|
||
$t = $cells[$idx]['tier'];
|
||
if ($t === 'T4' || $t === 'T5') {
|
||
throw new \RuntimeException(
|
||
'豹子点数 ' . strval($d) . ' 的落点不能为 T4/T5,请先在档位表中调整后再生成权重对照'
|
||
);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @param array<string, mixed> $row
|
||
* @return array{ui_text: string, real_ev: float, tier: string, remark: string}
|
||
*/
|
||
private static function normalizeCell(array $row, int $rowNo): array
|
||
{
|
||
$ui = $row['ui_text'] ?? null;
|
||
$ev = $row['real_ev'] ?? null;
|
||
$tier = $row['tier'] ?? null;
|
||
if (!is_string($ui) || trim($ui) === '') {
|
||
throw new \RuntimeException('档位奖励表单第' . strval($rowNo) . '条显示文本不能为空');
|
||
}
|
||
if ($ev === null || $ev === '' || !is_numeric($ev)) {
|
||
throw new \RuntimeException('档位奖励表单第' . strval($rowNo) . '条实际中奖无效');
|
||
}
|
||
if (!is_string($tier) || !in_array($tier, ['T1', 'T2', 'T3', 'T4', 'T5'], true)) {
|
||
throw new \RuntimeException('档位奖励表单第' . strval($rowNo) . '条档位无效');
|
||
}
|
||
$remark = $row['remark'] ?? '';
|
||
$remarkStr = is_string($remark) ? $remark : '';
|
||
|
||
return [
|
||
'ui_text' => $ui,
|
||
'real_ev' => floatval(strval($ev)),
|
||
'tier' => $tier,
|
||
'remark' => $remarkStr,
|
||
];
|
||
}
|
||
|
||
/**
|
||
* @param array{ui_text: string, real_ev: float, tier: string, remark: string} $cell
|
||
* @return array<string, int|float|string>
|
||
*/
|
||
private static function buildInsertRow(
|
||
int $gameChannelId,
|
||
int $direction,
|
||
int $gridNumber,
|
||
int $startIndex,
|
||
int $endIndex,
|
||
array $cell
|
||
): array {
|
||
return [
|
||
'game_channel_id' => $gameChannelId,
|
||
'direction' => $direction,
|
||
'grid_number' => $gridNumber,
|
||
'start_index' => $startIndex,
|
||
'end_index' => $endIndex,
|
||
'ui_text' => $cell['ui_text'],
|
||
'real_ev' => $cell['real_ev'],
|
||
'tier' => $cell['tier'],
|
||
'type' => self::tierToType($cell['tier']),
|
||
'remark' => $cell['remark'],
|
||
'weight' => 1,
|
||
];
|
||
}
|
||
|
||
private static function tierToType(string $tier): int
|
||
{
|
||
return match ($tier) {
|
||
'T1' => 3,
|
||
'T2' => 2,
|
||
'T3' => -1,
|
||
'T4' => -2,
|
||
'T5' => 1,
|
||
};
|
||
}
|
||
}
|