From 6eed4bf3a2bcf1fa9cf6788a6e14cc5b9fb71c55 Mon Sep 17 00:00:00 2001 From: "Mr.Xia" <1424473282@qq.com> Date: Fri, 3 Apr 2026 22:27:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=EF=BC=9A=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=20Pydantic=20v2=20=E5=85=BC=E5=AE=B9=E6=80=A7=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=8F=92=E4=BB=B6=E5=8A=A0=E8=BD=BD=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 更新 danding_points 配置使用 pydantic_settings.BaseSettings 和 SettingsConfigDict - 更新 onmyoji_gacha 配置使用 pydantic_settings.BaseSettings - 修复 danding_qqpush 配置加载使用 model_validate 替代 parse_obj - 添加 group_horse_racing 插件的详细 README 文档 这些修复解决了 Pydantic v2 迁移中的导入错误和 API 变更问题。 Co-Authored-By: Claude Opus 4.6 --- danding_bot/plugins/danding_points/config.py | 19 +- .../plugins/danding_qqpush/__init__.py | 2 +- .../plugins/group_horse_racing/README.md | 212 ++++++++++++++++++ danding_bot/plugins/onmyoji_gacha/config.py | 27 ++- 4 files changed, 238 insertions(+), 22 deletions(-) create mode 100644 danding_bot/plugins/group_horse_racing/README.md diff --git a/danding_bot/plugins/danding_points/config.py b/danding_bot/plugins/danding_points/config.py index 33025b2..ef82285 100644 --- a/danding_bot/plugins/danding_points/config.py +++ b/danding_bot/plugins/danding_points/config.py @@ -1,26 +1,31 @@ -from pydantic import BaseSettings, validator +from pydantic import field_validator +from pydantic_settings import BaseSettings, SettingsConfigDict from pathlib import Path class Config(BaseSettings): """Points system configuration.""" + model_config = SettingsConfigDict( + env_prefix="DANDING_", + case_sensitive=True, + extra="ignore", + ) + POINTS_DB_FILE: str = "data/danding_points/points.db" POINTS_MAX_BALANCE: int = 0 # 0 = unlimited POINTS_MAX_PER_OPERATION: int = 0 # 0 = unlimited POINTS_LOG_RETENTION_DAYS: int = 365 - class Config: - env_prefix = "DANDING_" - case_sensitive = True - - @validator("POINTS_MAX_BALANCE", "POINTS_MAX_PER_OPERATION", "POINTS_LOG_RETENTION_DAYS") + @field_validator("POINTS_MAX_BALANCE", "POINTS_MAX_PER_OPERATION", "POINTS_LOG_RETENTION_DAYS") + @classmethod def validate_non_negative(cls, v): if v < 0: raise ValueError("Value must be non-negative") return v - @validator("POINTS_DB_FILE") + @field_validator("POINTS_DB_FILE") + @classmethod def validate_db_path(cls, v): if not v: raise ValueError("Database file path cannot be empty") diff --git a/danding_bot/plugins/danding_qqpush/__init__.py b/danding_bot/plugins/danding_qqpush/__init__.py index 7b7d7d2..de65b05 100644 --- a/danding_bot/plugins/danding_qqpush/__init__.py +++ b/danding_bot/plugins/danding_qqpush/__init__.py @@ -31,7 +31,7 @@ __plugin_meta__ = PluginMetadata( # 加载配置 -plugin_config = Config.parse_obj(get_driver().config) +plugin_config = Config.model_validate(get_driver().config.dict()) def register_routes(): diff --git a/danding_bot/plugins/group_horse_racing/README.md b/danding_bot/plugins/group_horse_racing/README.md new file mode 100644 index 0000000..6baaaef --- /dev/null +++ b/danding_bot/plugins/group_horse_racing/README.md @@ -0,0 +1,212 @@ +# Group Horse Racing 插件 + +群赛马插件 - 一个支持群组内多人参与的赛马游戏,集成积分系统和下注功能。 + +## 功能概述 + +这是一个完整的群组赛马游戏系统,支持以下核心功能: + +- **马匹报名**:用户可以报名参加赛马比赛 +- **下注系统**:支持用户对参赛马匹进行下注 +- **自动比赛**:基于随机算法的赛马进程模拟 +- **积分集成**:与 danding_points 积分系统无缝集成 +- **自动撤回**:支持配置消息自动撤回时间 +- **多房间支持**:支持群组和私聊两种模式 + +## 命令列表 + +### 基础命令 + +| 命令 | 说明 | 示例 | +|------|------|------| +| `/赛马报名` | 报名参加赛马比赛 | `/赛马报名` | +| `/赛马开赛` | 开始比赛(需要至少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` 用于测试各项功能。 + +## 扩展建议 + +- 支持更多赛马属性(速度、耐力等) +- 实现赔率动态计算 +- 添加排行榜功能 +- 支持马匹升级系统 +- 实现更复杂的下注规则 diff --git a/danding_bot/plugins/onmyoji_gacha/config.py b/danding_bot/plugins/onmyoji_gacha/config.py index 2eef27f..bf9f01a 100644 --- a/danding_bot/plugins/onmyoji_gacha/config.py +++ b/danding_bot/plugins/onmyoji_gacha/config.py @@ -1,7 +1,9 @@ -from pydantic import BaseSettings +from pydantic_settings import BaseSettings, SettingsConfigDict import os class Config(BaseSettings): + model_config = SettingsConfigDict(extra="ignore") + # 抽卡概率配置 RARITY_PROBABILITY: dict = { "R": 78.75, @@ -9,18 +11,18 @@ class Config(BaseSettings): "SSR": 1.0, "SP": 0.25 } - + # 每日抽卡限制 DAILY_LIMIT: int = 3 - + # 数据文件路径 DB_FILE: str = "data/onmyoji_gacha/gacha.db" DAILY_DRAWS_FILE: str = "data/onmyoji_gacha/daily_draws.json" # 保留用于迁移 USER_STATS_FILE: str = "data/onmyoji_gacha/user_stats.json" # 保留用于迁移 - + # 式神图片目录 SHIKIGAMI_IMG_DIR: str = "data/chouka/" - + # 触发指令 GACHA_COMMANDS: list = ["抽卡","抽奖", "召唤"] STATS_COMMANDS: list = ["我的抽卡","我的抽奖", "我的图鉴"] @@ -28,7 +30,7 @@ class Config(BaseSettings): TRIPLE_GACHA_COMMANDS: list = ["三连", "三连抽"] ACHIEVEMENT_COMMANDS: list = ["查询成就", "抽卡成就"] INTRO_COMMANDS: list = ["抽卡介绍", "抽卡说明", "抽卡帮助"] - + # 成就系统配置 ACHIEVEMENTS: dict = { "consecutive_days_30_1": { @@ -99,20 +101,17 @@ class Config(BaseSettings): "type": "no_ssr_streak" } } - + # 权限配置 ALLOWED_GROUP_ID: int = 621016172 ALLOWED_USER_ID: int = 1424473282 - + # 特殊概率用户配置 SPECIAL_PROBABILITY_USERS: list = ["1424473282"] # 100%抽到SSR或SP的用户列表 - + # Web后台管理配置 WEB_ADMIN_TOKEN: str = os.getenv("WEB_ADMIN_TOKEN", "onmyoji_admin_token_2024") WEB_ADMIN_PORT: int = int(os.getenv("WEB_ADMIN_PORT", "8080")) - + # 时区 - TIMEZONE: str = "Asia/Shanghai" - - class Config: - extra = "ignore" \ No newline at end of file + TIMEZONE: str = "Asia/Shanghai" \ No newline at end of file