Compare commits

...

2 Commits

Author SHA1 Message Date
a5bc50e921 菜园系统引入私发 2025-11-15 01:10:16 +08:00
1716985d1a 可收获多个地块 2025-11-15 00:56:26 +08:00
4 changed files with 224 additions and 50 deletions

View File

@@ -0,0 +1,99 @@
# 背景
文件名2025-11-15_1_harvest-multiple-plots.md
创建于2025-11-15_00:37:12
创建者ASUS@LIUBAI095
主分支main
任务分支main
Yolo模式Off
# 任务描述
修改收获指令,从只能收获单个地块改为可以一次收获多个地块。
当前格式:`收获 <地块序号>`
新格式:`收获 <地块序号> [地块序号...]`
# 项目概览
这是一个基于WPS Bot的菜园系统插件。当前收获功能只支持一次收获一个地块用户希望能够一次收获多个地块提高操作效率。
# 分析
## 当前实现分析
1. **garden_plugin_harvest.py**
- `callback` 方法第59-112行只解析单个地块序号
- 第64-66行只提取第一个token作为地块序号
- 第71-75行调用 `service().harvest()` 处理单个地块
- 第79-112行处理单个地块的收获结果并返回消息
2. **garden_service.py**
- `harvest` 方法第181-235行每次只处理一个地块
- 该方法会删除地块记录,返回收获结果
3. **指令格式说明**
- 第25行`identifier="收获 <地块序号>"`
- 第33行步骤说明中只提到"输入正整数地块序号"
- 第46行帮助文档中也是单个地块格式
## 需要修改的部分
1. **解析多个地块序号**:修改 `callback` 方法,支持解析空格分隔的多个地块序号
2. **循环处理多个地块**:对每个地块序号调用 `harvest` 方法
3. **汇总结果**:收集所有成功和失败的结果,统一返回给用户
4. **更新文档**:更新指令格式说明和帮助文档
## 关键逻辑考虑
- 每个地块的收获是独立的,可能触发不同的额外奖励
- 需要处理部分成功的情况(某些地块成功,某些失败)
- 需要汇总所有收获的果实和额外奖励
- 错误处理:如果某个地块失败,应该继续处理其他地块,最后汇总所有结果
# 提议的解决方案
## 方案概述
修改 `garden_plugin_harvest.py``callback` 方法,支持解析和处理多个地块序号。
## 具体实现思路
1. **解析多个地块序号**
-`payload.split()` 后的所有token都解析为地块序号
- 过滤掉非数字的token
- 去重处理,避免重复收获同一地块
2. **循环处理**
- 对每个地块序号调用 `service().harvest()`
- 使用try-except捕获每个地块的错误
- 记录成功和失败的结果
3. **结果汇总**
- 统计成功收获的地块数量
- 汇总所有基础果实(按作物类型分组)
- 汇总所有额外奖励(积分和物品)
- 列出失败的地块及原因
4. **消息格式**
- 如果全部成功:显示汇总信息
- 如果部分成功:分别显示成功和失败信息
- 如果全部失败:显示所有失败原因
5. **文档更新**
- 更新 `collect_command_entries` 中的指令格式
- 更新 `collect_guide_entries` 中的帮助说明
# 当前执行步骤:"已完成所有实施步骤"
# 任务进度
[2025-11-15_00:51:11]
- 已修改Plugins/WPSGardenSystem/garden_plugin_harvest.py
- 更改:
1. 更新 collect_command_entries 方法:修改 identifier 为 "收获 <地块序号> [地块序号...]",更新 description 和 details 说明支持多个地块
2. 更新 collect_guide_entries 方法:修改指令格式描述,说明支持多个地块序号
3. 重构 callback 方法:
- 修改解析逻辑:支持解析多个地块序号,添加去重处理
- 重构处理逻辑:循环处理每个地块,收集成功和失败结果
- 添加数据结构successful_harvests, failed_harvests, fruit_counts, extra_items, total_points_gained
- 实现果实统计和额外奖励汇总
- 统一积分结算:在所有地块处理完成后统一调用 adjust_user_points
- 重构消息生成:根据成功和失败结果生成汇总消息,包括地块列表、果实汇总、额外奖励等
- 处理边界情况:支持部分成功、全部失败等场景
- 原因:实现一次收获多个地块的功能,提高用户操作效率
- 阻碍因素:无
- 状态:未确认
# 最终审查
[待完成]

2
PWF

Submodule PWF updated: 9cb259f2c7...89de330e2d

View File

@@ -3,7 +3,7 @@
from __future__ import annotations
import json
from typing import Any, Dict, List, Optional, Sequence, Type, Union
from typing import Any, Dict, List, Optional, Sequence, Type, Union, override
from PWF.Convention.Runtime.Architecture import Architecture
from PWF.Convention.Runtime.GlobalConfig import ConsoleFrontColor, ProjectConfig
@@ -200,6 +200,15 @@ class WPSGardenBase(WPSAPI):
cls._service.recover_overdue_plots()
return cls._service
@override
def get_webhook_url(self, message: str, user_id: int) -> str:
config : WPSConfigAPI = Architecture.Get(WPSConfigAPI)
url = config.get_user_url(user_id)
if url:
return url
else:
return super().get_webhook_url(message, user_id)
def dependencies(self) -> List[Type]:
return [
WPSConfigAPI,
@@ -398,7 +407,7 @@ class WPSGardenBase(WPSAPI):
return
message = (
"# 🌾 作物成熟提醒\n"
f"- 地块 {plot_index}{crop.display_name} 已成熟,记得收获!"
f"- 地块 {plot_index}{crop.display_name} 已成熟,记得收获!"
)
await self.send_markdown_message(message, chat_id, user_id)

View File

@@ -22,15 +22,15 @@ class WPSGardenHarvest(WPSGardenBase):
return (
GuideEntry(
title="收获",
identifier="收获 <地块序号>",
description="从成熟地块采摘果实并发放额外奖励。",
identifier="收获 <地块序号> [地块序号...]",
description="从成熟地块采摘果实并发放额外奖励。支持一次收获多个地块。",
metadata={"别名": "harvest"},
icon="🧺",
details=[
{
"type": "steps",
"items": [
"输入正整数地块序号。",
"输入一个或多个正整数地块序号,用空格分隔",
"系统校验成熟状态,计算基础果实数量。",
"发放额外奖励:积分或额外物品会自动结算。",
],
@@ -43,7 +43,7 @@ class WPSGardenHarvest(WPSGardenBase):
return (
{
"title": "指令格式",
"description": "`收获 <地块序号>`,序号需为正整数。",
"description": "`收获 <地块序号> [地块序号...]`,支持一次收获多个地块,序号用空格分隔,序号需为正整数。",
},
{
"title": "收益构成",
@@ -59,56 +59,122 @@ class WPSGardenHarvest(WPSGardenBase):
async def callback(self, message: str, chat_id: int, user_id: int) -> Optional[str]:
payload = self.parse_message_after_at(message).strip()
if not payload:
return await self.send_markdown_message("❌ 指令格式:`收获 <地块序号>`", chat_id, user_id)
return await self.send_markdown_message("❌ 指令格式:`收获 <地块序号> [地块序号...]`", chat_id, user_id)
tokens = [token.strip() for token in payload.split() if token.strip()]
if not tokens or not tokens[0].isdigit():
return await self.send_markdown_message("❌ 指令格式:`收获 <地块序号>`", chat_id, user_id)
plot_index = int(tokens[0])
# 解析多个地块序号
plot_indices = []
for token in tokens:
if token.isdigit():
plot_index = int(token)
if plot_index > 0: # 确保是正整数
plot_indices.append(plot_index)
# 去重
plot_indices = list(set(plot_indices))
if not plot_indices:
return await self.send_markdown_message("❌ 指令格式:`收获 <地块序号> [地块序号...]`", chat_id, user_id)
fortune: WPSFortuneSystem = Architecture.Get(WPSFortuneSystem)
fortune_value = fortune.get_fortune_value(user_id)
try:
result = self.service().harvest(
user_id=user_id,
plot_index=plot_index,
fortune_value=fortune_value,
)
except ValueError as exc:
return await self.send_markdown_message(f"{exc}", chat_id, user_id)
crop = result["crop"]
base_qty = result["base_yield"]
backpack: WPSBackpackSystem = Architecture.Get(WPSBackpackSystem)
backpack.add_item(user_id, crop.fruit_id, base_qty)
config_api: WPSConfigAPI = Architecture.Get(WPSConfigAPI)
extra_lines = []
if result["extra"]:
extra = result["extra"]
if extra["type"] == "points":
gained = int(extra["amount"])
if gained > 0:
new_points = await config_api.adjust_user_points(
chat_id,
user_id,
gained,
reason=f"收获 {crop.display_name} 的额外积分",
# 收集结果
successful_harvests = []
failed_harvests = []
total_points_gained = 0
extra_items = {} # {item_id: quantity}
fruit_counts = {} # {fruit_id: quantity}
# 循环处理每个地块
for plot_index in plot_indices:
try:
result = self.service().harvest(
user_id=user_id,
plot_index=plot_index,
fortune_value=fortune_value,
)
crop = result["crop"]
base_qty = result["base_yield"]
# 添加到背包
backpack.add_item(user_id, crop.fruit_id, base_qty)
# 统计果实
fruit_counts[crop.fruit_id] = fruit_counts.get(crop.fruit_id, 0) + base_qty
# 处理额外奖励
if result["extra"]:
extra = result["extra"]
if extra["type"] == "points":
gained = int(extra["amount"])
if gained > 0:
total_points_gained += gained
elif extra["type"] == "item":
item_id = extra["item_id"]
qty = int(extra["quantity"])
if qty > 0:
extra_items[item_id] = extra_items.get(item_id, 0) + qty
backpack.add_item(user_id, item_id, qty)
successful_harvests.append((plot_index, crop, result))
except ValueError as exc:
failed_harvests.append((plot_index, str(exc)))
# 统一处理积分奖励
new_points = None
if total_points_gained > 0:
new_points = await config_api.adjust_user_points(
chat_id,
user_id,
total_points_gained,
reason=f"收获 {len(successful_harvests)} 个地块的额外积分",
)
# 生成汇总消息
message_lines = []
if successful_harvests:
message_lines.append("# ✅ 收获成功")
message_lines.append(f"- 成功收获:{len(successful_harvests)} 个地块")
# 列出成功的地块
for plot_index, crop, result in successful_harvests:
message_lines.append(f" - 地块 {plot_index}{crop.display_name} × {result['base_yield']}")
# 汇总果实
if fruit_counts:
message_lines.append("\n- 获得果实:")
for fruit_id, qty in fruit_counts.items():
# 从成功收获中查找对应的作物显示名称
crop_for_fruit = next(
(c for _, c, _ in successful_harvests if c.fruit_id == fruit_id),
None
)
extra_lines.append(f"- 额外积分:+{gained}(当前积分 {new_points}")
elif extra["type"] == "item":
item_id = extra["item_id"]
qty = int(extra["quantity"])
if qty > 0:
backpack.add_item(user_id, item_id, qty)
extra_lines.append(f"- 额外物品:{item_id} × {qty}")
message_lines = [
"# ✅ 收获成功",
f"- 地块:{plot_index}",
f"- 作物:{crop.display_name}",
f"- 基础果实:{crop.display_name}的果实 × {base_qty}",
]
message_lines.extend(extra_lines)
fruit_name = crop_for_fruit.display_name if crop_for_fruit else fruit_id
message_lines.append(f" - {fruit_name}的果实 × {qty}")
# 额外奖励
if total_points_gained > 0:
message_lines.append(f"\n- 额外积分:+{total_points_gained}(当前积分 {new_points}")
if extra_items:
message_lines.append("\n- 额外物品:")
for item_id, qty in extra_items.items():
message_lines.append(f" - {item_id} × {qty}")
if failed_harvests:
if message_lines:
message_lines.append("\n---\n")
message_lines.append("# ❌ 收获失败")
for plot_index, error_msg in failed_harvests:
message_lines.append(f"- 地块 {plot_index}{error_msg}")
if not message_lines:
return await self.send_markdown_message("❌ 没有可收获的地块", chat_id, user_id)
return await self.send_markdown_message("\n".join(message_lines), chat_id, user_id)