Files
DanDingNoneBot/danding_bot/plugins/group_horse_racing/commands/race.py
Mr.Xia a952760cf8 fix: break circular import in horse racing commands
Extract shared.py from commands/__init__.py to break circular dependency:
- shared.py: shared variables/services/helper functions
- access.py: get_scope/check_access/get_event_id (canonical source)
- __init__.py: re-exports from shared.py for backward compat
- register/bet/race/help: import from .shared instead of package
2026-05-02 15:38:34 +08:00

152 lines
5.0 KiB
Python

import asyncio
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, Event, GroupMessageEvent
from .shared import (
room_store, race_engine, config, logger,
get_scope, check_access, get_event_id,
_send_to_scope, _build_race_image_message,
_get_user_name, _get_horses_in_order, _format_horse_label,
run_race_with_settlement, points_service,
)
from ..models import RoomState, HorseState
race_list_cmd = on_command("赛马列表", priority=5)
@race_list_cmd.handle()
async def handle_race_list(bot: Bot, event: Event):
"""显示当前房间所有报名马匹信息。"""
if not await check_access(bot, event):
await race_list_cmd.finish("无权限访问此功能")
return
scope = get_scope(event)
room = room_store.get_room(scope)
if not room or not room.horses:
await race_list_cmd.finish("暂无报名马匹")
return
lines = ["🏇 当前报名马匹:"]
for horse in _get_horses_in_order(room):
owner_display = await _get_user_name(bot, scope, horse.owner_id)
lines.append(f" {horse.index}. {horse.name} - 主人: {owner_display}")
lines.append(f"\n{len(room.horses)} 匹马")
await race_list_cmd.finish("\n".join(lines))
start_cmd = on_command("赛马开赛", priority=5)
@start_cmd.handle()
async def handle_start(bot: Bot, event: Event):
"""Handle race start - only participants or admins can start."""
if not await check_access(bot, event):
await start_cmd.finish("无权限访问此功能")
return
scope = get_scope(event)
user_id = get_event_id(event)
lock = room_store.get_lock(scope)
async with lock:
room = room_store.get_room(scope)
if not room:
await start_cmd.finish("房间不存在,请先报名")
return
if room.state != RoomState.WAITING:
await start_cmd.finish("比赛已经在进行中")
return
if len(room.horses) < 2:
await start_cmd.finish("至少需要2匹马才能开赛")
return
is_participant = user_id in [h.owner_id for h in room.horses.values()]
is_admin = False
if isinstance(event, GroupMessageEvent):
try:
member_info = await bot.get_group_member_info(
group_id=event.group_id,
user_id=int(user_id)
)
role = member_info.get("role", "")
is_admin = role in ("admin", "owner")
except Exception:
pass
if not is_participant and not is_admin:
await start_cmd.finish("只有参赛者或群管理员可以开赛")
return
for horse in room.horses.values():
horse.state = HorseState.RACING
await start_cmd.send("比赛开始!")
task = asyncio.create_task(run_race_with_settlement(bot, room, scope))
race_engine.register_task(scope, task)
cancel_race_cmd = on_command("赛马取消", priority=5)
@cancel_race_cmd.handle()
async def handle_cancel_race(bot: Bot, event: Event):
"""取消当前进行的比赛,退还所有下注积分。仅参赛者或管理员可操作。"""
if not await check_access(bot, event):
await cancel_race_cmd.finish("无权限访问此功能")
return
scope = get_scope(event)
user_id = get_event_id(event)
lock = room_store.get_lock(scope)
async with lock:
room = room_store.get_room(scope)
if not room:
await cancel_race_cmd.finish("房间不存在")
return
if room.state != RoomState.RACING:
await cancel_race_cmd.finish("当前没有进行中的比赛")
return
is_participant = user_id in [h.owner_id for h in room.horses.values()]
is_admin = False
if isinstance(event, GroupMessageEvent):
try:
member_info = await bot.get_group_member_info(
group_id=event.group_id,
user_id=int(user_id)
)
role = member_info.get("role", "")
is_admin = role in ("admin", "owner")
except Exception:
pass
if not is_participant and not is_admin:
await cancel_race_cmd.finish("只有参赛者或群管理员可以取消比赛")
return
race_engine.stop_race(scope)
total_refund = 0
for bet in room.bets[:]:
success, _ = await points_service.refund_bet_points(
bet.user_id, bet.amount, "比赛取消退还下注"
)
if success:
total_refund += bet.amount
room.bets.clear()
for horse in room.horses.values():
horse.state = HorseState.WAITING
room.state = RoomState.WAITING
room.tick_count = 0
await _send_to_scope(bot, scope, f"🏇 比赛已取消!共退还 {total_refund} 积分。")