1.签到系统错误修复2.商店系统修复bug并更新购买逻辑3.将炉灰加入商店并添加炉渣配方4.修改一些炼金系统的逻辑
This commit is contained in:
@@ -30,7 +30,7 @@ Yolo模式: Off
|
|||||||
- 暴露 get_user_name/url/points 与 adjust_user_points 接口供其他插件调用。
|
- 暴露 get_user_name/url/points 与 adjust_user_points 接口供其他插件调用。
|
||||||
- 通过 asyncio.Lock 确保写入串行, 保存失败会记录错误日志。
|
- 通过 asyncio.Lock 确保写入串行, 保存失败会记录错误日志。
|
||||||
|
|
||||||
# 当前执行步骤:"3. 实施配置插件"
|
# 当前执行步骤:"4. 修复签到唯一约束"
|
||||||
|
|
||||||
# 任务进度
|
# 任务进度
|
||||||
|
|
||||||
@@ -67,4 +67,13 @@ Yolo模式: Off
|
|||||||
|
|
||||||
[2025-11-07_22:33:00]
|
[2025-11-07_22:33:00]
|
||||||
- 已修改: Plugins/WPSPointSystem->Plugins/WPSConfigSystem
|
- 已修改: Plugins/WPSPointSystem->Plugins/WPSConfigSystem
|
||||||
- 原因: user_id相关的最优先表被注册在此处
|
- 原因: user_id相关的最优先表被注册在此处
|
||||||
|
- 阻碍因素: 无
|
||||||
|
- 状态: 成功
|
||||||
|
|
||||||
|
[2025-11-09_19:35:08]
|
||||||
|
- 已修改: `Plugins/WPSConfigSystem.py`
|
||||||
|
- 更改: 在记录每日签到时使用 INSERT ... ON CONFLICT(user_id) DO UPDATE,避免跨日签到触发唯一约束错误
|
||||||
|
- 原因: 保障每日签到功能在重复执行时保持幂等性
|
||||||
|
- 阻碍因素: 无
|
||||||
|
- 状态: 成功
|
||||||
@@ -45,7 +45,7 @@ WPS Bot 插件体系,现有 `WPSConfigAPI` 提供积分管理与签到积分
|
|||||||
- 重新整理依赖关系与命令注册,确保未注册商品或物品未找到时返回明确错误提示(如“未找到商店商品”“背包未注册物品”)。
|
- 重新整理依赖关系与命令注册,确保未注册商品或物品未找到时返回明确错误提示(如“未找到商店商品”“背包未注册物品”)。
|
||||||
- 暴露额外接口:`list_registered_modes()`、`get_store_snapshot()` 等辅助方法供其他插件调试或扩展使用。
|
- 暴露额外接口:`list_registered_modes()`、`get_store_snapshot()` 等辅助方法供其他插件调试或扩展使用。
|
||||||
|
|
||||||
# 当前执行步骤:"5. 重新规划命令拆分"
|
# 当前执行步骤:"10. 购买排序优化"
|
||||||
|
|
||||||
实施清单:
|
实施清单:
|
||||||
1. 重构 `WPSStoreSystem`:新增 `purchase_item`/`sell_item` 公共方法,并将 `callback` 限制为 `商店` 指令。
|
1. 重构 `WPSStoreSystem`:新增 `purchase_item`/`sell_item` 公共方法,并将 `callback` 限制为 `商店` 指令。
|
||||||
@@ -109,6 +109,36 @@ WPS Bot 插件体系,现有 `WPSConfigAPI` 提供积分管理与签到积分
|
|||||||
- 原因:满足命令拆分要求,避免未注册商品时误返回帮助信息
|
- 原因:满足命令拆分要求,避免未注册商品时误返回帮助信息
|
||||||
- 阻碍因素:无
|
- 阻碍因素:无
|
||||||
- 状态:未确认
|
- 状态:未确认
|
||||||
|
2025-11-09_19:18:39
|
||||||
|
- 已修改:`Plugins/WPSStoreSystem.py`
|
||||||
|
- 更改:玩家出售与系统商品展示统一使用物品名称,扩展 `PlayerListing` 并在加载时补充物品名
|
||||||
|
- 原因:确保商店界面不再暴露物品ID,提升可读性
|
||||||
|
- 阻碍因素:无
|
||||||
|
- 状态:未确认
|
||||||
|
2025-11-09_19:35:08
|
||||||
|
- 已修改:`Plugins/WPSStoreSystem.py` `PWF/CoreModules/plugin_interface.py`
|
||||||
|
- 更改:出售指令支持 `<数量> <单价>` 参数,调整逻辑使用玩家自定 single price,并在表注册时自动补齐缺失列
|
||||||
|
- 原因:允许运营自定售价并避免旧表缺列导致的运行错误
|
||||||
|
- 阻碍因素:无
|
||||||
|
- 状态:成功
|
||||||
|
2025-11-09_19:45:00
|
||||||
|
- 已修改:`Plugins/WPSStoreSystem.py`
|
||||||
|
- 更改:购买流程统一收集匹配来源,按价格升序排序;同价时优先玩家,再按系统、常驻顺序处理
|
||||||
|
- 原因:满足按价格优先购买的需求,确保同价时玩家商品优先售出
|
||||||
|
- 阻碍因素:无
|
||||||
|
- 状态:进行中
|
||||||
|
2025-11-09_19:50:00
|
||||||
|
- 已修改:`Plugins/WPSAlchemyGame.py`
|
||||||
|
- 更改:炼金插件依赖商店系统,在注册炉灰物品后同步为整点刷新候选,单价 8 分、限购 999
|
||||||
|
- 原因:补充基础货源,便于验证按价格排序的购买流程
|
||||||
|
- 阻碍因素:无
|
||||||
|
- 状态:成功
|
||||||
|
2025-11-09_21:22:44
|
||||||
|
- 已修改:`Plugins/WPSStoreSystem.py`
|
||||||
|
- 更改:玩家出售展示改为调用配置接口获取昵称,避免暴露纯数字ID
|
||||||
|
- 原因:提升商店玩家出售区的可读性与一致性
|
||||||
|
- 阻碍因素:无
|
||||||
|
- 状态:未确认
|
||||||
|
|
||||||
# 最终审查
|
# 最终审查
|
||||||
(待补充)
|
(待补充)
|
||||||
|
|||||||
2
PWF
2
PWF
Submodule PWF updated: 4d3d841dda...7deef9092a
@@ -15,6 +15,7 @@ from .WPSBackpackSystem import (
|
|||||||
WPSBackpackSystem,
|
WPSBackpackSystem,
|
||||||
)
|
)
|
||||||
from .WPSConfigSystem import WPSConfigAPI
|
from .WPSConfigSystem import WPSConfigAPI
|
||||||
|
from .WPSStoreSystem import WPSStoreSystem
|
||||||
from .WPSFortuneSystem import WPSFortuneSystem
|
from .WPSFortuneSystem import WPSFortuneSystem
|
||||||
|
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@ class WPSAlchemyGame(WPSAPI):
|
|||||||
ASH_ITEM_NAME = "炉灰"
|
ASH_ITEM_NAME = "炉灰"
|
||||||
SLAG_ITEM_ID = "alchemy_slag"
|
SLAG_ITEM_ID = "alchemy_slag"
|
||||||
SLAG_ITEM_NAME = "炉渣"
|
SLAG_ITEM_NAME = "炉渣"
|
||||||
MAX_BATCH_TIMES = 9999
|
MAX_BATCH_TIMES = 99
|
||||||
|
|
||||||
_PHASE_TABLE: List[Tuple[float, float, str, str]] = [
|
_PHASE_TABLE: List[Tuple[float, float, str, str]] = [
|
||||||
(0.1481481481, 0.0, "爆炸", "💥 炼金反噬,积分化为飞灰……"),
|
(0.1481481481, 0.0, "爆炸", "💥 炼金反噬,积分化为飞灰……"),
|
||||||
@@ -58,7 +59,7 @@ class WPSAlchemyGame(WPSAPI):
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
def dependencies(self) -> List[type]:
|
def dependencies(self) -> List[type]:
|
||||||
return [WPSAPI, WPSBackpackSystem, WPSConfigAPI, WPSFortuneSystem]
|
return [WPSAPI, WPSBackpackSystem, WPSConfigAPI, WPSFortuneSystem, WPSStoreSystem]
|
||||||
|
|
||||||
@override
|
@override
|
||||||
def wake_up(self) -> None:
|
def wake_up(self) -> None:
|
||||||
@@ -83,6 +84,19 @@ class WPSAlchemyGame(WPSAPI):
|
|||||||
"Warning",
|
"Warning",
|
||||||
f"{ConsoleFrontColor.YELLOW}注册炉灰物品时出现问题: {exc}{ConsoleFrontColor.RESET}",
|
f"{ConsoleFrontColor.YELLOW}注册炉灰物品时出现问题: {exc}{ConsoleFrontColor.RESET}",
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
store_system = Architecture.Get(WPSStoreSystem)
|
||||||
|
store_system.register_mode(
|
||||||
|
item_id=self.ASH_ITEM_ID,
|
||||||
|
price=8,
|
||||||
|
limit_amount=999,
|
||||||
|
)
|
||||||
|
except Exception as exc:
|
||||||
|
logger.Log(
|
||||||
|
"Warning",
|
||||||
|
f"{ConsoleFrontColor.YELLOW}注册炉灰商店模式时出现问题: {exc}{ConsoleFrontColor.RESET}",
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
backpack.register_item(
|
backpack.register_item(
|
||||||
self.SLAG_ITEM_ID,
|
self.SLAG_ITEM_ID,
|
||||||
@@ -180,7 +194,7 @@ class WPSAlchemyGame(WPSAPI):
|
|||||||
if points <= 0:
|
if points <= 0:
|
||||||
return "❌ 投入积分必须大于 0"
|
return "❌ 投入积分必须大于 0"
|
||||||
config_api: WPSConfigAPI = Architecture.Get(WPSConfigAPI)
|
config_api: WPSConfigAPI = Architecture.Get(WPSConfigAPI)
|
||||||
current_points = config_api.get_user_points(chat_id, user_id)
|
current_points = config_api.get_user_points(user_id)
|
||||||
if current_points < points:
|
if current_points < points:
|
||||||
return f"❌ 积分不足,需要 {points} 分,当前仅有 {current_points} 分"
|
return f"❌ 积分不足,需要 {points} 分,当前仅有 {current_points} 分"
|
||||||
|
|
||||||
@@ -205,7 +219,7 @@ class WPSAlchemyGame(WPSAPI):
|
|||||||
backpack: WPSBackpackSystem = Architecture.Get(WPSBackpackSystem)
|
backpack: WPSBackpackSystem = Architecture.Get(WPSBackpackSystem)
|
||||||
backpack.add_item(user_id, self.ASH_ITEM_ID, ash_reward)
|
backpack.add_item(user_id, self.ASH_ITEM_ID, ash_reward)
|
||||||
|
|
||||||
final_points = config_api.get_user_points(chat_id, user_id)
|
final_points = config_api.get_user_points(user_id)
|
||||||
extra_line = ""
|
extra_line = ""
|
||||||
if ash_reward > 0:
|
if ash_reward > 0:
|
||||||
extra_line = (
|
extra_line = (
|
||||||
|
|||||||
@@ -160,21 +160,21 @@ class WPSConfigAPI(WPSAPI):
|
|||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def get_user_name(self, chat_id: int, user_id: int) -> Optional[str]:
|
def get_user_name(self, user_id: int) -> Optional[str]:
|
||||||
record = self._get_user_record(user_id)
|
record = self._get_user_record(user_id)
|
||||||
if not record:
|
if not record:
|
||||||
return f"user_{user_id}"
|
return f"user_{user_id}"
|
||||||
value = record.get("username")
|
value = record.get("username")
|
||||||
return str(value) if value else f"user_{user_id}"
|
return str(value) if value else f"user_{user_id}"
|
||||||
|
|
||||||
def get_user_url(self, chat_id: int, user_id: int) -> Optional[str]:
|
def get_user_url(self, user_id: int) -> Optional[str]:
|
||||||
record = self._get_user_record(user_id)
|
record = self._get_user_record(user_id)
|
||||||
if not record:
|
if not record:
|
||||||
return None
|
return None
|
||||||
value = record.get("userurl")
|
value = record.get("userurl")
|
||||||
return str(value) if value else None
|
return str(value) if value else None
|
||||||
|
|
||||||
def get_user_points(self, chat_id: int, user_id: int) -> int:
|
def get_user_points(self, user_id: int) -> int:
|
||||||
record = self._get_user_record(user_id)
|
record = self._get_user_record(user_id)
|
||||||
if not record:
|
if not record:
|
||||||
return 0
|
return 0
|
||||||
@@ -224,7 +224,15 @@ class WPSCheckinAPI(WPSAPI):
|
|||||||
|
|
||||||
def _set_today_checkin_status(self, user_id: int) -> None:
|
def _set_today_checkin_status(self, user_id: int) -> None:
|
||||||
cursor = get_db().conn.cursor()
|
cursor = get_db().conn.cursor()
|
||||||
cursor.execute("INSERT INTO daily_checkin (user_id, checkin_date) VALUES (?, ?)", (user_id, datetime.now().strftime("%Y-%m-%d")))
|
cursor.execute(
|
||||||
|
"""
|
||||||
|
INSERT INTO daily_checkin (user_id, checkin_date)
|
||||||
|
VALUES (?, ?)
|
||||||
|
ON CONFLICT(user_id) DO UPDATE SET
|
||||||
|
checkin_date = excluded.checkin_date
|
||||||
|
""",
|
||||||
|
(user_id, datetime.now().strftime("%Y-%m-%d")),
|
||||||
|
)
|
||||||
get_db().conn.commit()
|
get_db().conn.commit()
|
||||||
|
|
||||||
async def do_callback(self, message: str, chat_id: int, user_id: int) -> Optional[str]:
|
async def do_callback(self, message: str, chat_id: int, user_id: int) -> Optional[str]:
|
||||||
@@ -259,7 +267,7 @@ class WPSCheckinAPI(WPSAPI):
|
|||||||
return f'''# 📅 Daily 命令帮助
|
return f'''# 📅 Daily 命令帮助
|
||||||
- checkin: 签到
|
- checkin: 签到
|
||||||
---
|
---
|
||||||
- 当前分数: {wps_config_api.get_user_points(chat_id, user_id)}
|
- 当前分数: {wps_config_api.get_user_points(user_id)}
|
||||||
- 今日签到状态: {"已签到" if self._get_today_checkin_status(user_id) else "未签到"}
|
- 今日签到状态: {"已签到" if self._get_today_checkin_status(user_id) else "未签到"}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ class StoreEntry(BaseModel):
|
|||||||
class PlayerListing(BaseModel):
|
class PlayerListing(BaseModel):
|
||||||
user_id: int
|
user_id: int
|
||||||
item_id: str
|
item_id: str
|
||||||
|
item_name: str
|
||||||
price: int
|
price: int
|
||||||
quantity: int
|
quantity: int
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
@@ -390,6 +391,7 @@ class WPSStoreSystem(WPSAPI):
|
|||||||
system_entries, permanent_entries = self._fetch_system_entries()
|
system_entries, permanent_entries = self._fetch_system_entries()
|
||||||
player_listings = self._fetch_player_listings()
|
player_listings = self._fetch_player_listings()
|
||||||
return self._format_store_markdown(
|
return self._format_store_markdown(
|
||||||
|
chat_id=chat_id,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
system_entries=system_entries,
|
system_entries=system_entries,
|
||||||
permanent_entries=permanent_entries,
|
permanent_entries=permanent_entries,
|
||||||
@@ -413,25 +415,63 @@ class WPSStoreSystem(WPSAPI):
|
|||||||
system_entries, permanent_entries = self._fetch_system_entries()
|
system_entries, permanent_entries = self._fetch_system_entries()
|
||||||
player_listings = self._fetch_player_listings()
|
player_listings = self._fetch_player_listings()
|
||||||
|
|
||||||
target = self._resolve_system_entry(identifier, system_entries, permanent_entries)
|
matched_system_entries = self._resolve_system_entries(
|
||||||
if target:
|
identifier=identifier,
|
||||||
return await self._purchase_system_entry(
|
system_entries=system_entries,
|
||||||
entry=target,
|
permanent_entries=permanent_entries,
|
||||||
|
)
|
||||||
|
matched_player_listings = await self._resolve_player_listings(
|
||||||
|
identifier=identifier,
|
||||||
|
listings=player_listings,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not matched_system_entries and not matched_player_listings:
|
||||||
|
return "❌ 未找到匹配的商品,请确认名称或物品ID是否正确"
|
||||||
|
|
||||||
|
candidates: list[tuple[int, int, str, StoreEntry | PlayerListing]] = []
|
||||||
|
|
||||||
|
for idx, listing in enumerate(matched_player_listings):
|
||||||
|
candidates.append((listing.price, 0, f"player-{idx}", listing))
|
||||||
|
for idx, entry in enumerate(system_entries):
|
||||||
|
if entry in matched_system_entries["system"]:
|
||||||
|
candidates.append((entry.price, 1, f"system-{idx}", entry))
|
||||||
|
for idx, entry in enumerate(permanent_entries):
|
||||||
|
if entry in matched_system_entries["permanent"]:
|
||||||
|
candidates.append((entry.price, 2, f"permanent-{idx}", entry))
|
||||||
|
|
||||||
|
if not candidates:
|
||||||
|
return "❌ 未找到匹配的商品,请确认名称或物品ID是否正确"
|
||||||
|
|
||||||
|
candidates.sort(key=lambda item: (item[0], item[1], item[2]))
|
||||||
|
|
||||||
|
for price, source_priority, _, payload in candidates:
|
||||||
|
if source_priority == 0:
|
||||||
|
listing = payload # type: ignore[assignment]
|
||||||
|
response = await self._purchase_player_listing(
|
||||||
|
listing=listing,
|
||||||
|
quantity=quantity,
|
||||||
|
chat_id=chat_id,
|
||||||
|
user_id=user_id,
|
||||||
|
)
|
||||||
|
if not response.startswith("❌"):
|
||||||
|
return response
|
||||||
|
if "库存不足" in response:
|
||||||
|
continue
|
||||||
|
return response
|
||||||
|
entry = payload # type: ignore[assignment]
|
||||||
|
response = await self._purchase_system_entry(
|
||||||
|
entry=entry,
|
||||||
quantity=quantity,
|
quantity=quantity,
|
||||||
chat_id=chat_id,
|
chat_id=chat_id,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
)
|
)
|
||||||
|
if not response.startswith("❌"):
|
||||||
|
return response
|
||||||
|
if "库存不足" in response:
|
||||||
|
continue
|
||||||
|
return response
|
||||||
|
|
||||||
listing = await self._resolve_player_listing(identifier, player_listings)
|
return "❌ 所有匹配的商品已售罄或库存不足"
|
||||||
if listing:
|
|
||||||
return await self._purchase_player_listing(
|
|
||||||
listing=listing,
|
|
||||||
quantity=quantity,
|
|
||||||
chat_id=chat_id,
|
|
||||||
user_id=user_id,
|
|
||||||
)
|
|
||||||
|
|
||||||
return "❌ 未找到匹配的商品,请确认名称或物品ID是否正确"
|
|
||||||
|
|
||||||
async def sell_item(
|
async def sell_item(
|
||||||
self,
|
self,
|
||||||
@@ -440,12 +480,15 @@ class WPSStoreSystem(WPSAPI):
|
|||||||
user_id: int,
|
user_id: int,
|
||||||
identifier: str,
|
identifier: str,
|
||||||
quantity: int,
|
quantity: int,
|
||||||
|
price: int,
|
||||||
) -> str:
|
) -> str:
|
||||||
identifier = identifier.strip()
|
identifier = identifier.strip()
|
||||||
if not identifier:
|
if not identifier:
|
||||||
return "❌ 出售指令格式错误,请提供物品名称或ID"
|
return "❌ 出售指令格式错误,请提供物品名称或ID"
|
||||||
if quantity < 0:
|
if quantity < 0:
|
||||||
return "❌ 出售数量必须大于或等于0"
|
return "❌ 出售数量必须大于或等于0"
|
||||||
|
if price < 0:
|
||||||
|
return "❌ 出售单价必须是非负整数"
|
||||||
backpack = Architecture.Get(WPSBackpackSystem)
|
backpack = Architecture.Get(WPSBackpackSystem)
|
||||||
item_id, definition = self._resolve_item(identifier)
|
item_id, definition = self._resolve_item(identifier)
|
||||||
if item_id is None:
|
if item_id is None:
|
||||||
@@ -482,10 +525,6 @@ class WPSStoreSystem(WPSAPI):
|
|||||||
elif diff < 0:
|
elif diff < 0:
|
||||||
backpack.add_item(user_id, item_id, -diff)
|
backpack.add_item(user_id, item_id, -diff)
|
||||||
|
|
||||||
try:
|
|
||||||
price = self._derive_player_price(item_id)
|
|
||||||
except ValueError as exc:
|
|
||||||
return f"❌ 当前物品 {definition.name} 未设置售价,无法出售({exc})"
|
|
||||||
cursor = get_db().conn.cursor()
|
cursor = get_db().conn.cursor()
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
f"""
|
f"""
|
||||||
@@ -505,10 +544,6 @@ class WPSStoreSystem(WPSAPI):
|
|||||||
if available_qty < quantity:
|
if available_qty < quantity:
|
||||||
return f"❌ 背包数量不足,当前拥有 {available_qty} 个 {definition.name}"
|
return f"❌ 背包数量不足,当前拥有 {available_qty} 个 {definition.name}"
|
||||||
|
|
||||||
try:
|
|
||||||
price = self._derive_player_price(item_id)
|
|
||||||
except ValueError as exc:
|
|
||||||
return f"❌ 当前物品 {definition.name} 未设置售价,无法出售({exc})"
|
|
||||||
backpack.set_item_quantity(user_id, item_id, available_qty - quantity)
|
backpack.set_item_quantity(user_id, item_id, available_qty - quantity)
|
||||||
|
|
||||||
cursor = get_db().conn.cursor()
|
cursor = get_db().conn.cursor()
|
||||||
@@ -532,7 +567,7 @@ class WPSStoreSystem(WPSAPI):
|
|||||||
return """# 🛒 商店指令帮助
|
return """# 🛒 商店指令帮助
|
||||||
- `商店`:查看当前系统商品与玩家出售列表
|
- `商店`:查看当前系统商品与玩家出售列表
|
||||||
- `购买 <物品名称或ID> <数量>`:购买指定商品
|
- `购买 <物品名称或ID> <数量>`:购买指定商品
|
||||||
- `出售 <物品名称或ID> <数量>`:上架自己的出售物品(限一种)
|
- `出售 <物品名称或ID> <数量> <单价>`:上架或更新自己的出售物品(限一种)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _fetch_system_entries(self) -> Tuple[List[StoreEntry], List[StoreEntry]]:
|
def _fetch_system_entries(self) -> Tuple[List[StoreEntry], List[StoreEntry]]:
|
||||||
@@ -582,11 +617,19 @@ class WPSStoreSystem(WPSAPI):
|
|||||||
)
|
)
|
||||||
rows = cursor.fetchall()
|
rows = cursor.fetchall()
|
||||||
listings: List[PlayerListing] = []
|
listings: List[PlayerListing] = []
|
||||||
|
backpack: WPSBackpackSystem = Architecture.Get(WPSBackpackSystem)
|
||||||
for row in rows:
|
for row in rows:
|
||||||
|
item_id = row["item_id"]
|
||||||
|
try:
|
||||||
|
definition = backpack._get_definition(item_id) # type: ignore[attr-defined]
|
||||||
|
item_name = definition.name
|
||||||
|
except Exception:
|
||||||
|
item_name = item_id
|
||||||
listings.append(
|
listings.append(
|
||||||
PlayerListing(
|
PlayerListing(
|
||||||
user_id=row["user_id"],
|
user_id=row["user_id"],
|
||||||
item_id=row["item_id"],
|
item_id=item_id,
|
||||||
|
item_name=item_name,
|
||||||
price=row["price"],
|
price=row["price"],
|
||||||
quantity=row["quantity"],
|
quantity=row["quantity"],
|
||||||
created_at=self._parse_datetime(row["created_at"]),
|
created_at=self._parse_datetime(row["created_at"]),
|
||||||
@@ -598,12 +641,14 @@ class WPSStoreSystem(WPSAPI):
|
|||||||
def _format_store_markdown(
|
def _format_store_markdown(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
|
chat_id: int,
|
||||||
user_id: int,
|
user_id: int,
|
||||||
system_entries: List[StoreEntry],
|
system_entries: List[StoreEntry],
|
||||||
permanent_entries: List[StoreEntry],
|
permanent_entries: List[StoreEntry],
|
||||||
player_listings: List[PlayerListing],
|
player_listings: List[PlayerListing],
|
||||||
) -> str:
|
) -> str:
|
||||||
lines: List[str] = ["# 🏬 每小时商店"]
|
lines: List[str] = ["# 🏬 每小时商店"]
|
||||||
|
config_api: WPSConfigAPI = Architecture.Get(WPSConfigAPI)
|
||||||
if permanent_entries:
|
if permanent_entries:
|
||||||
lines.append("## ♾️ 常驻商品")
|
lines.append("## ♾️ 常驻商品")
|
||||||
for entry in permanent_entries:
|
for entry in permanent_entries:
|
||||||
@@ -613,7 +658,7 @@ class WPSStoreSystem(WPSAPI):
|
|||||||
else f"限购 {entry.limit_amount}"
|
else f"限购 {entry.limit_amount}"
|
||||||
)
|
)
|
||||||
lines.append(
|
lines.append(
|
||||||
f"- `{entry.item_id}` · {entry.display_name}|价格 {entry.price} 分|{limit_text}"
|
f"- {entry.display_name}|价格 {entry.price} 分|{limit_text}"
|
||||||
)
|
)
|
||||||
if system_entries:
|
if system_entries:
|
||||||
lines.append("## ⏱️ 本时段商品")
|
lines.append("## ⏱️ 本时段商品")
|
||||||
@@ -623,7 +668,7 @@ class WPSStoreSystem(WPSAPI):
|
|||||||
else:
|
else:
|
||||||
stock_text = f"剩余:{entry.remaining_amount}"
|
stock_text = f"剩余:{entry.remaining_amount}"
|
||||||
lines.append(
|
lines.append(
|
||||||
f"- `{entry.item_id}` · {entry.display_name}|价格 {entry.price} 分|{stock_text}"
|
f"- {entry.display_name}|价格 {entry.price} 分|{stock_text}"
|
||||||
)
|
)
|
||||||
if not permanent_entries and not system_entries:
|
if not permanent_entries and not system_entries:
|
||||||
lines.append("> ⚠️ 当前没有可售的系统商品")
|
lines.append("> ⚠️ 当前没有可售的系统商品")
|
||||||
@@ -631,9 +676,11 @@ class WPSStoreSystem(WPSAPI):
|
|||||||
lines.append("## 👥 玩家出售")
|
lines.append("## 👥 玩家出售")
|
||||||
if player_listings:
|
if player_listings:
|
||||||
for listing in player_listings:
|
for listing in player_listings:
|
||||||
owner = "你" if listing.user_id == user_id else f"玩家 {listing.user_id}"
|
owner = "你"
|
||||||
|
if listing.user_id != user_id:
|
||||||
|
owner = config_api.get_user_name(listing.user_id)
|
||||||
lines.append(
|
lines.append(
|
||||||
f"- {owner}|`{listing.item_id}`|数量 {listing.quantity}|价格 {listing.price} 分"
|
f"- {owner}|{listing.item_name}|数量 {listing.quantity}|价格 {listing.price} 分"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
lines.append("> 当前暂无玩家出售信息")
|
lines.append("> 当前暂无玩家出售信息")
|
||||||
@@ -689,27 +736,32 @@ class WPSStoreSystem(WPSAPI):
|
|||||||
f"当前剩余积分:{new_points}"
|
f"当前剩余积分:{new_points}"
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _resolve_player_listing(
|
async def _resolve_player_listings(
|
||||||
self,
|
self,
|
||||||
identifier: str,
|
identifier: str,
|
||||||
listings: List[PlayerListing],
|
listings: List[PlayerListing],
|
||||||
) -> Optional[PlayerListing]:
|
) -> List[PlayerListing]:
|
||||||
if not listings:
|
if not listings:
|
||||||
return None
|
return []
|
||||||
backpack = Architecture.Get(WPSBackpackSystem)
|
backpack: WPSBackpackSystem = Architecture.Get(WPSBackpackSystem)
|
||||||
identifier_lower = identifier.lower()
|
identifier_lower = identifier.lower()
|
||||||
|
matches: List[PlayerListing] = []
|
||||||
for listing in listings:
|
for listing in listings:
|
||||||
if listing.quantity <= 0:
|
if listing.quantity <= 0:
|
||||||
continue
|
continue
|
||||||
if listing.item_id.lower() == identifier_lower:
|
if listing.item_id.lower() == identifier_lower:
|
||||||
return listing
|
matches.append(listing)
|
||||||
|
continue
|
||||||
|
if listing.item_name.lower() == identifier_lower:
|
||||||
|
matches.append(listing)
|
||||||
|
continue
|
||||||
try:
|
try:
|
||||||
definition = backpack._get_definition(listing.item_id) # type: ignore[attr-defined]
|
definition = backpack._get_definition(listing.item_id) # type: ignore[attr-defined]
|
||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
if definition.name.lower() == identifier_lower:
|
if definition.name.lower() == identifier_lower:
|
||||||
return listing
|
matches.append(listing)
|
||||||
return None
|
return matches
|
||||||
|
|
||||||
async def _purchase_player_listing(
|
async def _purchase_player_listing(
|
||||||
self,
|
self,
|
||||||
@@ -772,19 +824,22 @@ class WPSStoreSystem(WPSAPI):
|
|||||||
f"当前剩余积分:{buyer_new_points}"
|
f"当前剩余积分:{buyer_new_points}"
|
||||||
)
|
)
|
||||||
|
|
||||||
def _resolve_system_entry(
|
def _resolve_system_entries(
|
||||||
self,
|
self,
|
||||||
identifier: str,
|
identifier: str,
|
||||||
system_entries: List[StoreEntry],
|
system_entries: List[StoreEntry],
|
||||||
permanent_entries: List[StoreEntry],
|
permanent_entries: List[StoreEntry],
|
||||||
) -> Optional[StoreEntry]:
|
) -> Dict[str, List[StoreEntry]]:
|
||||||
identifier_lower = identifier.lower()
|
identifier_lower = identifier.lower()
|
||||||
for entry in permanent_entries + system_entries:
|
matched_system: List[StoreEntry] = []
|
||||||
if entry.item_id.lower() == identifier_lower:
|
matched_permanent: List[StoreEntry] = []
|
||||||
return entry
|
for entry in permanent_entries:
|
||||||
if entry.display_name.lower() == identifier_lower:
|
if entry.item_id.lower() == identifier_lower or entry.display_name.lower() == identifier_lower:
|
||||||
return entry
|
matched_permanent.append(entry)
|
||||||
return None
|
for entry in system_entries:
|
||||||
|
if entry.item_id.lower() == identifier_lower or entry.display_name.lower() == identifier_lower:
|
||||||
|
matched_system.append(entry)
|
||||||
|
return {"system": matched_system, "permanent": matched_permanent}
|
||||||
|
|
||||||
def _get_user_listing(self, user_id: int) -> Optional[PlayerListing]:
|
def _get_user_listing(self, user_id: int) -> Optional[PlayerListing]:
|
||||||
cursor = get_db().conn.cursor()
|
cursor = get_db().conn.cursor()
|
||||||
@@ -799,9 +854,17 @@ class WPSStoreSystem(WPSAPI):
|
|||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
if not row:
|
if not row:
|
||||||
return None
|
return None
|
||||||
|
item_id = row["item_id"]
|
||||||
|
backpack: WPSBackpackSystem = Architecture.Get(WPSBackpackSystem)
|
||||||
|
try:
|
||||||
|
definition = backpack._get_definition(item_id) # type: ignore[attr-defined]
|
||||||
|
item_name = definition.name
|
||||||
|
except Exception:
|
||||||
|
item_name = item_id
|
||||||
return PlayerListing(
|
return PlayerListing(
|
||||||
user_id=row["user_id"],
|
user_id=row["user_id"],
|
||||||
item_id=row["item_id"],
|
item_id=item_id,
|
||||||
|
item_name=item_name,
|
||||||
price=row["price"],
|
price=row["price"],
|
||||||
quantity=row["quantity"],
|
quantity=row["quantity"],
|
||||||
created_at=self._parse_datetime(row["created_at"]),
|
created_at=self._parse_datetime(row["created_at"]),
|
||||||
@@ -975,25 +1038,38 @@ class WPSStoreSellCommand(WPSAPI):
|
|||||||
message = self.parse_message_after_at(message).strip()
|
message = self.parse_message_after_at(message).strip()
|
||||||
if not message:
|
if not message:
|
||||||
return await self._send_error(
|
return await self._send_error(
|
||||||
"❌ 出售指令格式错误,请使用:`出售 <物品名称或ID> <数量>`",
|
"❌ 出售指令格式错误,请使用:`出售 <物品名称或ID> <数量> <单价>`",
|
||||||
chat_id,
|
chat_id,
|
||||||
user_id,
|
user_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
tokens = [token.strip() for token in message.split() if token.strip()]
|
tokens = [token.strip() for token in message.split() if token.strip()]
|
||||||
if len(tokens) < 2:
|
if len(tokens) < 3:
|
||||||
return await self._send_error(
|
return await self._send_error(
|
||||||
"❌ 出售指令格式错误,请使用:`出售 <物品名称或ID> <数量>`",
|
"❌ 出售指令格式错误,请使用:`出售 <物品名称或ID> <数量> <单价>`",
|
||||||
chat_id,
|
chat_id,
|
||||||
user_id,
|
user_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
identifier = " ".join(tokens[:-1]).strip()
|
identifier = " ".join(tokens[:-2]).strip()
|
||||||
quantity_token = tokens[-1]
|
quantity_token = tokens[-2]
|
||||||
|
price_token = tokens[-1]
|
||||||
|
if not identifier:
|
||||||
|
return await self._send_error(
|
||||||
|
"❌ 出售指令格式错误,请提供物品名称或ID",
|
||||||
|
chat_id,
|
||||||
|
user_id,
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
quantity = int(quantity_token)
|
quantity = int(quantity_token)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return await self._send_error("❌ 出售数量必须是整数", chat_id, user_id)
|
return await self._send_error("❌ 出售数量必须是整数", chat_id, user_id)
|
||||||
|
try:
|
||||||
|
price = int(price_token)
|
||||||
|
except ValueError:
|
||||||
|
return await self._send_error("❌ 出售单价必须是整数", chat_id, user_id)
|
||||||
|
if price < 0:
|
||||||
|
return await self._send_error("❌ 出售单价必须是非负整数", chat_id, user_id)
|
||||||
|
|
||||||
store_api = Architecture.Get(WPSStoreSystem)
|
store_api = Architecture.Get(WPSStoreSystem)
|
||||||
response = await store_api.sell_item(
|
response = await store_api.sell_item(
|
||||||
@@ -1001,6 +1077,7 @@ class WPSStoreSellCommand(WPSAPI):
|
|||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
identifier=identifier,
|
identifier=identifier,
|
||||||
quantity=quantity,
|
quantity=quantity,
|
||||||
|
price=price,
|
||||||
)
|
)
|
||||||
return await self.send_markdown_message(response, chat_id, user_id)
|
return await self.send_markdown_message(response, chat_id, user_id)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user