feat(horse-racing): 新增赛马列表/取消下注/开赛权限限制 + 修复退还异常保护 + 文档同步

This commit is contained in:
2026-05-02 11:50:34 +08:00
parent 9566920866
commit 5869618a9c
2 changed files with 324 additions and 217 deletions

View File

@@ -1,215 +1,223 @@
# Group Horse Racing 插件
群赛马插件 - 一个支持群组内多人参与的赛马游戏,集成积分系统和下注功能。
## 功能概述
这是一个完整的群组赛马游戏系统,支持以下核心功能:
- **马匹报名**:用户可以报名参加赛马比赛
- **下注系统**:支持用户对任意参赛马匹进行下注(含自己的马)
- **自动比赛**:基于随机算法的赛马进程模拟
- **积分集成**:与 danding_points 积分系统无缝集成
- **自动撤回**:支持配置消息自动撤回时间
- **多房间支持**:支持群组和私聊两种模式
## 命令列表
### 基础命令
| 命令 | 说明 | 示例 |
|------|------|------|
| `/赛马报名 <马匹名>` | 报名参加赛马比赛。若不输入则复用上次马名或使用昵称 | `/赛马报名 绝地赤兔` |
| `/赛马取消报名` | 取消报名并退还下注(限开始前) | `/赛马取消报名` |
| `/赛马下注 <序号|马名> <金额>` | 为马匹下注 | `/赛马下注 01 100` |
| `/赛马开赛` | 开始比赛需要至少2匹马 | `/赛马开赛` |
| `/赛马帮助` | 显示帮助信息 | `/赛马帮助` |
## 配置说明
### 环境变量
所有配置项都可通过环境变量设置,前缀为 `GROUP_HORSE_RACING_`
```python
# 测试模式
GROUP_HORSE_RACING_TEST_MODE=false
# 测试用户ID集合
GROUP_HORSE_RACING_TESTERS=[]
# 测试群组ID集合
GROUP_HORSE_RACING_TEST_GROUPS=[]
# 允许的群组ID集合
GROUP_HORSE_RACING_ALLOWED_GROUPS=[]
```
### 游戏配置
| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| `PARTICIPANT_REWARD` | 50 | 参赛者奖励积分 |
| `CHAMPION_REWARD` | 200 | 冠军奖励积分 |
| `MIN_BET` | 10 | 最小下注积分 |
| `MIN_ODDS` | 1.2 | 最小赔率 |
| `RACE_DISTANCE` | 100 | 比赛距离 |
| `RACE_TICK_INTERVAL` | 5 | 比赛更新间隔(秒) |
### 消息撤回配置
可配置不同类型消息的自动撤回时间0表示不撤回
```python
MESSAGE_RECALL = {
"race_update": 30, # 比赛更新消息
"registration": 180, # 报名确认消息
"bet_confirm": 180, # 下注确认消息
"cancel_confirm": 60, # 取消确认消息
"error": 60, # 错误消息
"race_result": 0, # 比赛结果(不撤回)
"leaderboard": 0, # 排行榜(不撤回)
"help": 0, # 帮助信息(不撤回)
"odds_display": 0, # 赔率显示(不撤回)
}
```
### 数据库配置
```python
RACE_DB_FILE = "data/group_horse_racing/race.db"
```
## 核心模块
### models.py
定义了游戏中的数据模型:
- **RoomState**房间状态枚举WAITING、RUNNING、FINISHED、INTERRUPTED
- **HorseState**马匹状态枚举READY、RACING、FINISHED
- **Horse**马匹数据类包含所有者ID、名称、位置、状态
- **Bet**下注数据类包含用户ID、马匹名称、下注金额
- **Room**:房间数据类,管理马匹、下注、比赛状态
- **RaceResult**:比赛结果数据类,记录比赛统计信息
### race_engine.py
比赛引擎,负责比赛逻辑:
- **start_race()**:启动比赛循环
- **_race_loop()**主比赛循环每个tick更新马匹位置
- **_determine_champion()**:确定冠军(处理平局情况)
比赛采用高斯分布随机算法每个tick马匹随机前进一定距离。
### points_service.py
积分服务,与 danding_points 插件集成:
- **spend_bet_points()**:扣除下注积分(支持重试)
- **refund_bet_points()**:退还下注积分
- **payout_winnings()**:支付中奖积分
- **reward_participant()**奖励参赛者
- **reward_champion()**:奖励冠军
- **get_balance()**:获取用户余额
### message_service.py
消息服务,处理消息发送和自动撤回:
- **send_with_recall()**:发送消息并根据配置自动撤回
- **_schedule_recall()**:异步调度消息撤回
- **clear_pending_recalls()**:清除待撤回消息任务
### room_store.py
房间存储,管理比赛房间的生命周期:
- 支持并发访问控制使用asyncio.Lock
- 房间持久化存储
- 房间清理和过期处理
### commands.py
命令处理器,实现所有用户命令:
- **handle_register()**:处理报名命令
- **handle_start()**:处理开赛命令
- **handle_help()**:处理帮助命令
## 使用流程
### 基本游戏流程
1. **报名阶段**
- 用户执行 `/赛马报名` 命令
- 系统检查权限和房间容量最多8匹马
- 成功报名
2. **下注阶段**
- 用户可对参赛马匹进行下注
- 下注金额需满足最小下注要求
- 下注积分从用户账户扣除
- 可以给自己的马下注
3. **比赛阶段**
- 房主执行 `/赛马开赛` 命令
- 系统启动比赛引擎
- 每个tick更新马匹位置
- 首先到达终点的马匹为冠军
4. **结算阶段**
- 冠军获得冠军奖励
- 中奖用户获得下注奖金(下注金额 × 赔率)
- 比赛结果保存到数据库
## 权限控制
插件支持两种权限模式:
### 测试模式TEST_MODE=true
- 仅允许 `TEST_GROUPS` 中的群组使用
- 仅允许 `TESTERS` 中的用户在私聊中使用
### 正常模式TEST_MODE=false
- 仅允许 `ALLOWED_GROUPS` 中的群组使用
- 私聊中禁用
## 依赖关系
- **必需**`danding_bot.plugins.danding_points` - 积分系统插件
## 数据存储
比赛数据存储在SQLite数据库中
- 位置:`data/group_horse_racing/race.db`
- 存储内容:比赛历史、结果统计、用户数据
## 并发控制
- 使用 `asyncio.Lock` 保证房间操作的线程安全
- 支持多个房间同时进行比赛
- 每个房间有独立的锁和异步任务
## 错误处理
- 权限检查:无权限时返回错误提示
- 房间检查:房间不存在或已满时返回错误
- 参赛人数检查少于2匹马时无法开赛
- 积分检查:积分不足时下注失败
## 测试
项目包含 `test_commands.py` 用于测试各项功能。
## 扩展建议
- 支持更多赛马属性(速度、耐力等)
- 实现赔率动态计算
- 添加排行榜功能
- 支持马匹升级系统
- 实现更复杂的下注规则
# Group Horse Racing 插件
群赛马插件 - 一个支持群组内多人参与的赛马游戏,集成积分系统和下注功能。
## 功能概述
这是一个完整的群组赛马游戏系统,支持以下核心功能:
- **马匹报名**:用户可以报名参加赛马比赛
- **下注系统**:支持用户对任意参赛马匹进行下注(含自己的马)
- **自动比赛**:基于随机算法的赛马进程模拟
- **积分集成**:与 danding_points 积分系统无缝集成
- **自动撤回**:支持配置消息自动撤回时间
- **多房间支持**:支持群组和私聊两种模式
## 命令列表
### 基础命令
| 命令 | 说明 | 示例 |
|------|------|------|
| `/赛马报名 <马匹名>` | 报名参加赛马比赛。若不输入则复用上次马名或使用昵称 | `/赛马报名 绝地赤兔` |
| `/赛马取消报名` | 取消报名并退还下注(限开始前) | `/赛马取消报名` |
| `/赛马下注 <序号|马名> <金额>` | 为马匹下注 | `/赛马下注 01 100` |
| `/赛马取消下注` | 取消本人所有下注并退还积分(限开始前 | `/赛马取消下注` |
| `/赛马赔率` | 查看当前赔率和下注池 | `/赛马赔率` |
| `/赛马列表` | 查看当前报名马匹列表 | `/赛马列表` |
| `/赛马开赛` | 开始比赛需参赛者或管理员至少2匹马 | `/赛马开赛` |
| `/赛马帮助` | 显示帮助信息 | `/赛马帮助` |
## 配置说明
### 环境变量
所有配置项都可通过环境变量设置,前缀为 `GROUP_HORSE_RACING_`
```python
# 测试模式
GROUP_HORSE_RACING_TEST_MODE=false
# 测试用户ID集合
GROUP_HORSE_RACING_TESTERS=[]
# 测试群组ID集合
GROUP_HORSE_RACING_TEST_GROUPS=[]
# 允许的群组ID集合
GROUP_HORSE_RACING_ALLOWED_GROUPS=[]
```
### 游戏配置
| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| `PARTICIPANT_REWARD` | 20 | 参赛者奖励积分 |
| `CHAMPION_REWARD` | 150 | 冠军奖励积分 |
| `MIN_BET` | 10 | 最小下注积分 |
| `MIN_ODDS` | 1.2 | 最小赔率 |
| `RACE_DISTANCE` | 100 | 比赛距离 |
| `RACE_TICK_INTERVAL` | 5 | 比赛更新间隔(秒) |
### 消息撤回配置
可配置不同类型消息的自动撤回时间0表示不撤回
```python
MESSAGE_RECALL = {
"race_update": 30, # 比赛更新消息
"registration": 180, # 报名确认消息
"bet_confirm": 180, # 下注确认消息
"cancel_confirm": 60, # 取消确认消息
"error": 60, # 错误消息
"race_result": 0, # 比赛结果(不撤回)
"leaderboard": 0, # 排行榜(不撤回)
"help": 0, # 帮助信息(不撤回)
"odds_display": 0, # 赔率显示(不撤回)
}
```
### 数据库配置
```python
RACE_DB_FILE = "data/group_horse_racing/race.db"
```
## 核心模块
### models.py
定义了游戏中的数据模型:
- **RoomState**房间状态枚举WAITING、RUNNING、FINISHED、INTERRUPTED
- **HorseState**马匹状态枚举READY、RACING、FINISHED
- **Horse**马匹数据类包含所有者ID、名称、位置、状态
- **Bet**下注数据类包含用户ID、马匹名称、下注金额
- **Room**:房间数据类,管理马匹、下注、比赛状态
- **RaceResult**:比赛结果数据类,记录比赛统计信息
### race_engine.py
比赛引擎,负责比赛逻辑:
- **start_race()**:启动比赛循环
- **_race_loop()**主比赛循环每个tick更新马匹位置
- **_determine_champion()**:确定冠军(处理平局情况)
比赛采用高斯分布随机算法每个tick马匹随机前进一定距离。
### points_service.py
积分服务,与 danding_points 插件集成:
- **spend_bet_points()**扣除下注积分(支持重试)
- **refund_bet_points()**:退还下注积分
- **payout_winnings()**:支付中奖积分
- **reward_participant()**:奖励参赛者
- **reward_champion()**:奖励冠军
- **get_balance()**:获取用户余额
### message_service.py
消息服务,处理消息发送和自动撤回
- **send_with_recall()**:发送消息并根据配置自动撤回
- **_schedule_recall()**:异步调度消息撤回
- **clear_pending_recalls()**:清除待撤回消息任务
### room_store.py
房间存储,管理比赛房间的生命周期:
- 支持并发访问控制使用asyncio.Lock
- 房间持久化存储
- 房间清理和过期处理
### commands.py
命令处理器,实现所有用户命令
- **handle_register()**:处理报名命令
- **handle_cancel()**:处理取消报名命令
- **handle_bet()**:处理下注命令
- **handle_cancel_bet()**:处理取消下注命令
- **handle_odds()**:处理赔率显示命令
- **handle_race_list()**:处理马匹列表命令
- **handle_start()**:处理开赛命令(仅参赛者或管理员可操作)
- **handle_help()**:处理帮助命令
## 使用流程
### 基本游戏流程
1. **报名阶段**
- 用户执行 `/赛马报名` 命令
- 系统检查权限和房间容量最多8匹马
- 成功报名
2. **下注阶段**
- 用户可对参赛马匹进行下注
- 下注金额需满足最小下注要求
- 下注积分从用户账户扣除
- 可以给自己的马下注
3. **比赛阶段**
- 房主执行 `/赛马开赛` 命令
- 系统启动比赛引擎
- 每个tick更新马匹位置
- 首先到达终点的马匹为冠军
4. **结算阶段**
- 冠军获得冠军奖励
- 中奖用户获得下注奖金(下注金额 × 赔率)
- 比赛结果保存到数据库
## 权限控制
插件支持两种权限模式:
### 测试模式TEST_MODE=true
- 仅允许 `TEST_GROUPS` 中的群组使用
- 仅允许 `TESTERS` 中的用户在私聊中使用
### 正常模式TEST_MODE=false
- 仅允许 `ALLOWED_GROUPS` 中的群组使用
- 私聊中禁用
## 依赖关系
- **必需**`danding_bot.plugins.danding_points` - 积分系统插件
## 数据存储
比赛数据存储在SQLite数据库中
- 位置:`data/group_horse_racing/race.db`
- 存储内容:比赛历史、结果统计、用户数据
## 并发控制
- 使用 `asyncio.Lock` 保证房间操作的线程安全
- 支持多个房间同时进行比赛
- 每个房间有独立的锁和异步任务
## 错误处理
- 权限检查:无权限时返回错误提示
- 房间检查:房间不存在或已满时返回错误
- 参赛人数检查少于2匹马时无法开赛
- 积分检查:积分不足时下注失败
## 测试
项目包含 `test_commands.py` 用于测试各项功能。
## 扩展建议
- 支持更多赛马属性(速度、耐力等)
- 实现赔率动态计算
- 添加排行榜功能
- 支持马匹升级系统
- 实现更复杂的下注规则