feat(bot): use runtime api for bot data

This commit is contained in:
2026-06-20 18:20:40 +08:00
parent f67f3ca1d6
commit 8d26c46323
16 changed files with 1803 additions and 1491 deletions

View File

@@ -1,5 +1,7 @@
import logging
import asyncio
import logging
import asyncio
from datetime import datetime
from uuid import uuid4
from nonebot.adapters.onebot.v11 import Bot, Event, GroupMessageEvent, Message, MessageSegment, PrivateMessageEvent
@@ -27,8 +29,8 @@ async def _get_user_name(bot: Bot, scope: str, user_id: str) -> str:
group_id = int(scope.split("_", 1)[1])
info = await bot.get_group_member_info(group_id=group_id, user_id=int(user_id))
return info.get("card") or info.get("nickname") or user_id
except Exception:
pass
except Exception as exc:
logger.debug("获取赛马用户昵称失败 scope=%s user_id=%s error=%s", scope, user_id, exc)
return user_id
@@ -142,13 +144,14 @@ async def _is_admin_or_owner(bot: Bot, event: Event) -> bool:
user_id=int(event.get_user_id()),
)
return member_info.get("role", "") in ("admin", "owner")
except Exception:
return False
except Exception as exc:
logger.debug("检查赛马管理员权限失败 user_id=%s error=%s", getattr(event, "user_id", ""), exc)
return False
def _build_point_changes(room: Room, odds: dict[str, float]) -> tuple[dict[str, int], dict[str, str]]:
point_changes: dict[str, int] = {}
def _build_point_changes(room: Room, odds: dict[str, float]) -> tuple[dict[str, int], dict[str, str]]:
point_changes: dict[str, int] = {}
for horse in room.horses.values():
point_changes[horse.owner_id] = point_changes.get(horse.owner_id, 0) + config.PARTICIPANT_REWARD
@@ -168,8 +171,23 @@ def _build_point_changes(room: Room, odds: dict[str, float]) -> tuple[dict[str,
point_summaries = {
user_id: _describe_points_delta(delta)
for user_id, delta in point_changes.items()
}
return point_changes, point_summaries
}
return point_changes, point_summaries
def _build_participants_snapshot(room: Room) -> list[str]:
"""生成赛果归档所需的参赛马名快照。"""
return [horse.name for horse in _get_horses_in_order(room)]
def _build_bet_distribution(room: Room) -> dict[str, int]:
"""按马名汇总下注分布,供 xapi 原样归档。"""
distribution = {horse.name: 0 for horse in _get_horses_in_order(room)}
for bet in room.bets:
distribution[bet.horse_name] = distribution.get(bet.horse_name, 0) + bet.amount
return distribution
async def _send_to_scope(bot: Bot, scope: str, message: str, message_type: str = "race_update", critical: bool = False):
@@ -243,10 +261,10 @@ async def settle_race(room: Room) -> tuple[RaceResult, dict[str, float]] | None:
for bet in room.bets:
user_ids.add(bet.user_id)
# Record pre-balances
pre_balances: dict[str, int] = {}
for uid in user_ids:
pre_balances[uid] = points_service.get_balance(uid)
# Record pre-balances
pre_balances: dict[str, int] = {}
for uid in user_ids:
pre_balances[uid] = await points_service.get_balance(uid)
# 1. Reward all participants
for horse in room.horses.values():
@@ -271,10 +289,10 @@ async def settle_race(room: Room) -> tuple[RaceResult, dict[str, float]] | None:
except Exception as e:
logger.warning(f"payout_winnings failed for {bet.user_id}: {e}")
# Record post-balances and compute deltas
post_balances: dict[str, int] = {}
for uid in user_ids:
post_balances[uid] = points_service.get_balance(uid)
# Record post-balances and compute deltas
post_balances: dict[str, int] = {}
for uid in user_ids:
post_balances[uid] = await points_service.get_balance(uid)
point_changes: dict[str, int] = {}
for uid in user_ids:
@@ -285,13 +303,20 @@ async def settle_race(room: Room) -> tuple[RaceResult, dict[str, float]] | None:
# Build human-readable summaries
_, point_change_summaries = _build_point_changes(room, odds)
result = RaceResult(
champion_name=room.champion_name,
champion_owner=champion.owner_id,
point_changes=point_changes,
point_change_summaries=point_change_summaries,
)
return result, odds
result = RaceResult(
race_id=str(uuid4()),
scope=room.scope,
champion_name=room.champion_name,
champion_owner=champion.owner_id,
participants=_build_participants_snapshot(room),
bet_distribution=_build_bet_distribution(room),
duration_ticks=room.tick_count,
completed_at=datetime.now(),
point_changes=point_changes,
point_change_summaries=point_change_summaries,
odds_snapshot=odds,
)
return result, odds
async def run_race_with_settlement(bot: Bot, room: Room, scope: str):
@@ -343,12 +368,15 @@ async def run_race_with_settlement(bot: Bot, room: Room, scope: str):
if result:
result_lines.extend(await _format_point_change_lines(room, result.point_changes, result.point_change_summaries, name_map))
await message_service.recall_previous_of_type(bot, scope, "race_update")
await _send_to_scope(bot, scope, "\n".join(result_lines), "race_result")
race_engine.stop_race(scope)
room_store.delete_room(scope)
message_service.clear_pending_recalls(scope)
await message_service.recall_previous_of_type(bot, scope, "race_update")
await _send_to_scope(bot, scope, "\n".join(result_lines), "race_result")
if result:
await room_store.save_race_result(result)
race_engine.stop_race(scope)
room_store.delete_room(scope)
message_service.clear_pending_recalls(scope)
# Import and re-export access functions from access.py (canonical source)