Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5334dfc01 | ||
|
|
72baa5d095 | ||
|
|
719494e4e5 | ||
|
|
5d3d8a4ef1 | ||
|
|
b72190cc45 | ||
|
|
4cd0302426 |
@@ -6,7 +6,7 @@
|
||||
|
||||
## 如何安装
|
||||
|
||||
方法一(推荐):在小真寻后台的插件商店下载即可。
|
||||
方法一(推荐):在小真寻后台的插件商店下载即可<br>
|
||||
方法二:下载源码放在小真寻`plugin`目录下
|
||||
|
||||
## 使用指令
|
||||
@@ -22,22 +22,32 @@
|
||||
| 收获 | 收获成熟作物 | |
|
||||
| 铲除 | 铲除荒废作物 | |
|
||||
| 我的作物 | | |
|
||||
| 出售作物 [作物名称] [数量] | 从仓库里向系统售卖作物 | 作物不填默认清空仓库 数量不填默认全部 |
|
||||
| 出售作物 [作物名称] [数量] | 从仓库里向系统售卖作物 | 不填写作物名将售卖仓库种全部作物 填作物名不填数量将指定作物全部出售 |
|
||||
| @美波理 偷菜 | 偷别人的菜 | 每人每天只能偷5次 |
|
||||
| 购买农场币 | 将真寻金币兑换成农场币 | 兑换比例默认为1:2 手续费默认20% |
|
||||
|
||||
---
|
||||
|
||||
## 更新日志[详细](./log/log.md):
|
||||
- 感谢[quanquan1014](https://github.com/quanquan1014)对农场名称中包含特殊字符的处理。
|
||||
- 更正数据库写法,但是会导致V1.0用户的作物和种子丢失
|
||||
- 完善我的农场图片资源,现在会在左上角显示经验、等级、金币等详细信息了
|
||||
- 完善出售作物逻辑,现在可以空置作物名称来一键出售全部作物了,也可以选择空置数量来一键出售仓库种指定作物
|
||||
- 完善播种逻辑,现在可以空置数量来一键播种指定作物了
|
||||
- 新增更改农场名指令
|
||||
- 改进对土地开垦条件判断
|
||||
---
|
||||
|
||||
## 待办事宜 `Todo` 列表
|
||||
|
||||
- [x] 完善我的农场图片,例如左上角显示用户数据
|
||||
- [x] 完善升级数据、作物数据、作物图片
|
||||
- [x] 签到功能
|
||||
- [x] 添加渔场功能
|
||||
- [x] 增加活动、交易行功能
|
||||
- [x] 增加交易行总行功能
|
||||
- [x] 添加其他游戏种子素材
|
||||
- [x] 想不到了,想到再说
|
||||
- [ ] 完善升级数据、作物数据、作物图片
|
||||
- [ ] 签到功能
|
||||
- [ ] 添加渔场功能
|
||||
- [ ] 增加活动、交易行功能
|
||||
- [ ] 增加交易行总行功能
|
||||
- [ ] 添加其他游戏种子素材
|
||||
- [ ] 想不到了,想到再说
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -24,18 +24,19 @@ __plugin_meta__ = PluginMetadata(
|
||||
种子商店 [页数]
|
||||
购买种子 [作物/种子名称] [数量]
|
||||
我的种子
|
||||
播种 [作物/种子名称] [数量]
|
||||
播种 [作物/种子名称] [数量] (数量不填默认将最大可能播种
|
||||
收获
|
||||
铲除
|
||||
我的作物
|
||||
出售作物 [作物/种子名称] [数量]
|
||||
偷菜 at
|
||||
出售作物 [作物/种子名称] [数量] (不填写作物名将售卖仓库种全部作物 填作物名不填数量将指定作物全部出售
|
||||
偷菜 at (每人每天只能偷5次
|
||||
开垦
|
||||
购买农场币 [数量] 数量为消耗金币的数量
|
||||
更改农场名 [新农场名]
|
||||
""".strip(),
|
||||
extra=PluginExtraData(
|
||||
author="Art_Sakura",
|
||||
version="1.0",
|
||||
version="1.1",
|
||||
commands=[Command(command="我的农场")],
|
||||
menu_type="群内小游戏",
|
||||
configs=[
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from nonebot.adapters import Event, MessageTemplate
|
||||
from nonebot.rule import to_me
|
||||
from nonebot.typing import T_State
|
||||
from nonebot_plugin_alconna import (Alconna, AlconnaQuery, Args, Arparma, At,
|
||||
Match, MultiVar, Option, Query, Subcommand,
|
||||
on_alconna, store_true)
|
||||
from nonebot_plugin_alconna import (Alconna, AlconnaMatch, AlconnaQuery, Args,
|
||||
Arparma, At, Match, MultiVar, Option,
|
||||
Query, Subcommand, on_alconna, store_true)
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
from nonebot_plugin_waiter import waiter
|
||||
|
||||
@@ -34,17 +34,89 @@ diuse_register = on_alconna(
|
||||
)
|
||||
|
||||
@diuse_register.handle()
|
||||
async def _(session: Uninfo):
|
||||
async def handle_register(session: Uninfo):
|
||||
uid = str(session.user.id)
|
||||
|
||||
user = await g_pSqlManager.getUserInfoByUid(uid)
|
||||
|
||||
if user:
|
||||
await MessageUtils.build_message("你已经有啦").send(reply_to=True)
|
||||
else:
|
||||
aaa = await g_pSqlManager.initUserInfoByUid(uid, str(session.user.name), 0, 100)
|
||||
await MessageUtils.build_message("🎉 您已经开通农场啦~").send(reply_to=True)
|
||||
return
|
||||
|
||||
await MessageUtils.build_message(str(aaa)).send(reply_to=True)
|
||||
try:
|
||||
# 获取原始用户名并安全处理
|
||||
raw_name = str(session.user.name)
|
||||
safe_name = sanitize_username(raw_name)
|
||||
|
||||
# 初始化用户信息
|
||||
success = await g_pSqlManager.initUserInfoByUid(
|
||||
uid=uid,
|
||||
name=safe_name,
|
||||
exp=0,
|
||||
point=500
|
||||
)
|
||||
|
||||
msg = (
|
||||
"✅ 农场开通成功!\n💼 初始资金:500农场币"
|
||||
if success
|
||||
else "⚠️ 开通失败,请稍后再试"
|
||||
)
|
||||
logger.info(f"用户注册 {'成功' if success else '失败'}:{uid}")
|
||||
|
||||
except Exception as e:
|
||||
msg = "⚠️ 系统繁忙,请稍后再试"
|
||||
logger.error(f"注册异常 | UID:{uid} | 错误:{str(e)}")
|
||||
|
||||
await MessageUtils.build_message(msg).send(reply_to=True)
|
||||
|
||||
def sanitize_username(username: str, max_length: int = 15) -> str:
|
||||
"""
|
||||
安全处理用户名
|
||||
功能:
|
||||
1. 移除首尾空白
|
||||
2. 过滤危险字符
|
||||
3. 转义单引号
|
||||
4. 处理空值
|
||||
5. 限制长度
|
||||
"""
|
||||
# 处理空值
|
||||
if not username:
|
||||
return "神秘农夫"
|
||||
|
||||
# 基础清洗
|
||||
cleaned = username.strip()
|
||||
|
||||
# 允许的字符白名单(可自定义扩展)
|
||||
safe_chars = {
|
||||
'_', '-', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
|
||||
'+', '=', '.', ',', '~', '·', ' ',
|
||||
'a','b','c','d','e','f','g','h','i','j','k','l','m',
|
||||
'n','o','p','q','r','s','t','u','v','w','x','y','z',
|
||||
'A','B','C','D','E','F','G','H','I','J','K','L','M',
|
||||
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
|
||||
'0','1','2','3','4','5','6','7','8','9',
|
||||
}
|
||||
# 添加常用中文字符(Unicode范围)
|
||||
safe_chars.update(chr(c) for c in range(0x4E00, 0x9FFF+1))
|
||||
|
||||
# 过滤危险字符
|
||||
filtered = [
|
||||
c if c in safe_chars or 0x4E00 <= ord(c) <= 0x9FFF
|
||||
else ''
|
||||
for c in cleaned
|
||||
]
|
||||
|
||||
# 合并处理结果
|
||||
safe_str = ''.join(filtered)
|
||||
|
||||
# 转义单引号(双重保障)
|
||||
escaped = safe_str.replace("'", "''")
|
||||
|
||||
# 处理空结果
|
||||
if not escaped:
|
||||
return "神秘农夫"
|
||||
|
||||
# 长度限制
|
||||
return escaped[:max_length]
|
||||
|
||||
diuse_farm = on_alconna(
|
||||
Alconna(
|
||||
@@ -58,24 +130,24 @@ diuse_farm = on_alconna(
|
||||
Subcommand("harvest", help_text="收获"),
|
||||
Subcommand("eradicate", help_text="铲除"),
|
||||
Subcommand("my-plant", help_text="我的作物"),
|
||||
# Subcommand("reclamation", Args["isBool?", str], help_text="开垦"),
|
||||
Subcommand("sell-plant", Args["name?", str]["num?", int], help_text="出售作物"),
|
||||
Subcommand("stealing", Args["target?", At], help_text="偷菜"),
|
||||
Subcommand("buy-point", Args["num?", int], help_text="购买农场币"),
|
||||
#Subcommand("sell-point", Args["num?", int], help_text="转换金币")
|
||||
Subcommand("change-name", Args["name?", str], help_text="更改农场名")
|
||||
),
|
||||
priority=5,
|
||||
block=True,
|
||||
)
|
||||
|
||||
@diuse_farm.assign("$main")
|
||||
async def _(session: Uninfo, nickname: str = UserName()):
|
||||
async def _(session: Uninfo):
|
||||
uid = str(session.user.id)
|
||||
|
||||
if await isRegisteredByUid(uid) == False:
|
||||
return
|
||||
|
||||
image = await g_pFarmManager.drawFarmByUid(uid, nickname)
|
||||
image = await g_pFarmManager.drawFarmByUid(uid)
|
||||
await MessageUtils.build_message(image).send(reply_to=True)
|
||||
|
||||
diuse_farm.shortcut(
|
||||
@@ -267,12 +339,7 @@ diuse_farm.shortcut(
|
||||
)
|
||||
|
||||
@diuse_farm.assign("sell-plant")
|
||||
async def _(session: Uninfo, name: Match[str], num: Query[int] = AlconnaQuery("num", 1),):
|
||||
if not name.available:
|
||||
await MessageUtils.build_message(
|
||||
"请在指令后跟需要出售的作物名称"
|
||||
).finish(reply_to=True)
|
||||
|
||||
async def _(session: Uninfo, name: Match[str], num: Query[int] = AlconnaQuery("num", -1),):
|
||||
uid = str(session.user.id)
|
||||
|
||||
if await isRegisteredByUid(uid) == False:
|
||||
@@ -329,3 +396,32 @@ async def _(session: Uninfo, num: Query[int] = AlconnaQuery("num", 0)):
|
||||
|
||||
result = await g_pFarmManager.buyPointByUid(uid, num.result)
|
||||
await MessageUtils.build_message(result).send(reply_to=True)
|
||||
|
||||
|
||||
diuse_farm.shortcut(
|
||||
"更改农场名(?P<name>)",
|
||||
command="我的农场",
|
||||
arguments=["change-name", "{name}"],
|
||||
prefix=True,
|
||||
)
|
||||
|
||||
@diuse_farm.assign("change-name")
|
||||
async def _(session: Uninfo, name: Match[str]):
|
||||
if not name.available:
|
||||
await MessageUtils.build_message(
|
||||
"请在指令后跟需要更改的用户名"
|
||||
).finish(reply_to=True)
|
||||
|
||||
uid = str(session.user.id)
|
||||
|
||||
if await isRegisteredByUid(uid) == False:
|
||||
return
|
||||
|
||||
safeName = sanitize_username(name.result)
|
||||
|
||||
result = await g_pSqlManager.updateUserNameByUid(uid, safeName)
|
||||
|
||||
if result == True:
|
||||
await MessageUtils.build_message("更新用户名成功!").send(reply_to=True)
|
||||
else:
|
||||
await MessageUtils.build_message("更新用户名失败!").send(reply_to=True)
|
||||
|
||||
@@ -38,50 +38,134 @@
|
||||
},
|
||||
"9":
|
||||
{
|
||||
"level": 15,
|
||||
"level": 11,
|
||||
"point": 19800,
|
||||
"item": []
|
||||
},
|
||||
"10":
|
||||
{
|
||||
"level":3,
|
||||
"point": 3000,
|
||||
"level": 13,
|
||||
"point": 30000,
|
||||
"item": []
|
||||
},
|
||||
"11":
|
||||
{
|
||||
"level":3,
|
||||
"point": 3000,
|
||||
"level": 15,
|
||||
"point": 50000,
|
||||
"item": []
|
||||
},
|
||||
"12":
|
||||
{
|
||||
"level":3,
|
||||
"point": 3000,
|
||||
"level": 17,
|
||||
"point": 70000,
|
||||
"item": []
|
||||
},
|
||||
"13":
|
||||
{
|
||||
"level":3,
|
||||
"point": 3000,
|
||||
"level": 19,
|
||||
"point": 90000,
|
||||
"item": []
|
||||
},
|
||||
"14":
|
||||
{
|
||||
"level":3,
|
||||
"point": 3000,
|
||||
"level": 21,
|
||||
"point": 130000,
|
||||
"item": []
|
||||
},
|
||||
"15":
|
||||
{
|
||||
"level":3,
|
||||
"point": 3000,
|
||||
"level": 23,
|
||||
"point": 150000,
|
||||
"item": []
|
||||
},
|
||||
"16":
|
||||
{
|
||||
"level":3,
|
||||
"point": 3000,
|
||||
"level": 25,
|
||||
"point": 180000,
|
||||
"item": []
|
||||
},
|
||||
"17":
|
||||
{
|
||||
"level": 27,
|
||||
"point": 230000,
|
||||
"item": []
|
||||
},
|
||||
"18":
|
||||
{
|
||||
"level": 29,
|
||||
"point": 300000,
|
||||
"item": []
|
||||
},
|
||||
"19":
|
||||
{
|
||||
"level": 31,
|
||||
"point": 500000,
|
||||
"item": []
|
||||
},
|
||||
"20":
|
||||
{
|
||||
"level": 33,
|
||||
"point": 850000,
|
||||
"item": []
|
||||
},
|
||||
"21":
|
||||
{
|
||||
"level": 36,
|
||||
"point": 1100000,
|
||||
"item": []
|
||||
},
|
||||
"22":
|
||||
{
|
||||
"level": 39,
|
||||
"point": 1300000,
|
||||
"item": []
|
||||
},
|
||||
"23":
|
||||
{
|
||||
"level": 42,
|
||||
"point": 1500000,
|
||||
"item": []
|
||||
},
|
||||
"24":
|
||||
{
|
||||
"level": 45,
|
||||
"point": 1700000,
|
||||
"item": []
|
||||
},
|
||||
"25":
|
||||
{
|
||||
"level": 48,
|
||||
"point": 2000000,
|
||||
"item": []
|
||||
},
|
||||
"26":
|
||||
{
|
||||
"level": 51,
|
||||
"point": 2200000,
|
||||
"item": []
|
||||
},
|
||||
"27":
|
||||
{
|
||||
"level": 54,
|
||||
"point": 2800000,
|
||||
"item": []
|
||||
},
|
||||
"28":
|
||||
{
|
||||
"level": 57,
|
||||
"point": 3500000,
|
||||
"item": []
|
||||
},
|
||||
"29":
|
||||
{
|
||||
"level": 60,
|
||||
"point": 4300000,
|
||||
"item": []
|
||||
},
|
||||
"30":
|
||||
{
|
||||
"level": 70,
|
||||
"point": 5200000,
|
||||
"item": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
"zhuShi":
|
||||
[
|
||||
"level: 解锁等级",
|
||||
"buy: 购买价格",
|
||||
"limit: 限制等级 0:普通土地 1:红土地 2:黄土地 3:黑土地",
|
||||
"experience: 收获经验",
|
||||
"harvest: 收获数量",
|
||||
"price: 单价",
|
||||
"price: 果实售价",
|
||||
"time: 成熟时间 小时",
|
||||
"crop: 作物可以收几次",
|
||||
"again: 再次成熟时间 单位:小时",
|
||||
@@ -19,6 +20,7 @@
|
||||
"胡萝卜":
|
||||
{
|
||||
"level": 0,
|
||||
"buy": 163,
|
||||
"limit": 0,
|
||||
"experience": 18,
|
||||
"harvest": 17,
|
||||
@@ -33,6 +35,7 @@
|
||||
"白萝卜":
|
||||
{
|
||||
"level": 0,
|
||||
"buy": 125,
|
||||
"limit": 0,
|
||||
"experience": 15,
|
||||
"harvest": 16,
|
||||
@@ -47,6 +50,7 @@
|
||||
"牧草":
|
||||
{
|
||||
"level": 0,
|
||||
"buy": 80,
|
||||
"limit": 0,
|
||||
"experience": 10,
|
||||
"harvest": 25,
|
||||
@@ -61,6 +65,7 @@
|
||||
"大白菜":
|
||||
{
|
||||
"level": 1,
|
||||
"buy": 168,
|
||||
"limit": 0,
|
||||
"experience": 19,
|
||||
"harvest": 17,
|
||||
@@ -75,6 +80,7 @@
|
||||
"大蒜":
|
||||
{
|
||||
"level": 1,
|
||||
"buy": 169,
|
||||
"limit": 0,
|
||||
"experience": 19,
|
||||
"harvest": 17,
|
||||
@@ -89,6 +95,7 @@
|
||||
"水稻":
|
||||
{
|
||||
"level": 2,
|
||||
"buy": 168,
|
||||
"limit": 0,
|
||||
"experience": 19,
|
||||
"harvest": 18,
|
||||
@@ -96,13 +103,14 @@
|
||||
"time": 14,
|
||||
"crop": 1,
|
||||
"again": 0,
|
||||
"phase": 6,
|
||||
"general": true,
|
||||
"phase": 5,
|
||||
"general": false,
|
||||
"sell": false
|
||||
},
|
||||
"小麦":
|
||||
{
|
||||
"level": 2,
|
||||
"buy": 168,
|
||||
"limit": 0,
|
||||
"experience": 19,
|
||||
"harvest": 18,
|
||||
@@ -117,6 +125,7 @@
|
||||
"玉米":
|
||||
{
|
||||
"level": 3,
|
||||
"buy": 175,
|
||||
"limit": 0,
|
||||
"experience": 19,
|
||||
"harvest": 17,
|
||||
@@ -131,6 +140,7 @@
|
||||
"油菜":
|
||||
{
|
||||
"level": 4,
|
||||
"buy": 194,
|
||||
"limit": 0,
|
||||
"experience": 29,
|
||||
"harvest": 23,
|
||||
@@ -145,6 +155,7 @@
|
||||
"生菜":
|
||||
{
|
||||
"level": 4,
|
||||
"buy": 195,
|
||||
"limit": 0,
|
||||
"experience": 25,
|
||||
"harvest": 21,
|
||||
@@ -155,6 +166,111 @@
|
||||
"phase": 6,
|
||||
"general": true,
|
||||
"sell": false
|
||||
},
|
||||
"小白菜":
|
||||
{
|
||||
"level": 4,
|
||||
"buy": 195,
|
||||
"limit": 0,
|
||||
"experience": 15,
|
||||
"harvest": 18,
|
||||
"price": 21,
|
||||
"time": 11,
|
||||
"crop": 1,
|
||||
"again": 0,
|
||||
"phase": 5,
|
||||
"general": true,
|
||||
"sell": false
|
||||
},
|
||||
"红枣":
|
||||
{
|
||||
"level": 5,
|
||||
"buy": 237,
|
||||
"limit": 0,
|
||||
"experience": 21,
|
||||
"harvest": 20,
|
||||
"price": 25,
|
||||
"time": 16,
|
||||
"crop": 1,
|
||||
"again": 0,
|
||||
"phase": 6,
|
||||
"general": true,
|
||||
"sell": false
|
||||
},
|
||||
"茄子":
|
||||
{
|
||||
"level": 5,
|
||||
"buy": 237,
|
||||
"limit": 0,
|
||||
"experience": 21,
|
||||
"harvest": 20,
|
||||
"price": 25,
|
||||
"time": 16,
|
||||
"crop": 1,
|
||||
"again": 0,
|
||||
"phase": 6,
|
||||
"general": true,
|
||||
"sell": false
|
||||
},
|
||||
"番茄":
|
||||
{
|
||||
"level": 6,
|
||||
"buy": 251,
|
||||
"limit": 0,
|
||||
"experience": 22,
|
||||
"harvest": 21,
|
||||
"price": 26,
|
||||
"time": 17,
|
||||
"crop": 1,
|
||||
"again": 0,
|
||||
"phase": 6,
|
||||
"general": true,
|
||||
"sell": false
|
||||
},
|
||||
"ATTomato":
|
||||
{
|
||||
"level": 6,
|
||||
"buy": 99999,
|
||||
"limit": 0,
|
||||
"experience": 22,
|
||||
"harvest": 21,
|
||||
"price": 7000,
|
||||
"time": 17,
|
||||
"crop": 1,
|
||||
"again": 0,
|
||||
"phase": 6,
|
||||
"general": true,
|
||||
"sell": false
|
||||
},
|
||||
"红玫瑰":
|
||||
{
|
||||
"level": 7,
|
||||
"buy": 251,
|
||||
"limit": 0,
|
||||
"experience": 23,
|
||||
"harvest": 22,
|
||||
"price": 27,
|
||||
"time": 18,
|
||||
"crop": 1,
|
||||
"again": 0,
|
||||
"phase": 6,
|
||||
"general": true,
|
||||
"sell": false
|
||||
},
|
||||
"豌豆":
|
||||
{
|
||||
"level": 7,
|
||||
"buy": 266,
|
||||
"limit": 0,
|
||||
"experience": 23,
|
||||
"harvest": 22,
|
||||
"price": 27,
|
||||
"time": 18,
|
||||
"crop": 1,
|
||||
"again": 0,
|
||||
"phase": 6,
|
||||
"general": true,
|
||||
"sell": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"date": "202505",
|
||||
""
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import math
|
||||
import os
|
||||
import re
|
||||
from contextlib import asynccontextmanager
|
||||
from datetime import date, datetime, timedelta
|
||||
from io import StringIO
|
||||
from math import e
|
||||
@@ -27,31 +28,41 @@ class CSqlManager:
|
||||
bIsExist = os.path.exists(g_sDBFilePath)
|
||||
|
||||
cls.m_pDB = await aiosqlite.connect(g_sDBFilePath)
|
||||
|
||||
#if bIsExist == False:
|
||||
#TODO 缺少判断创建失败事件
|
||||
#await cls.createDB()
|
||||
cls.m_pDB.row_factory = aiosqlite.Row
|
||||
|
||||
await cls.checkDB()
|
||||
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
async def getColumns(cls, tableName):
|
||||
""" 由AI生成
|
||||
获取表的列信息
|
||||
"""
|
||||
@asynccontextmanager
|
||||
async def _transaction(cls):
|
||||
await cls.m_pDB.execute("BEGIN;")
|
||||
try:
|
||||
cursor = await cls.m_pDB.execute(f'PRAGMA table_info("{tableName}")')
|
||||
columns = [row[1] for row in await cursor.fetchall()]
|
||||
return columns
|
||||
except aiosqlite.Error as e:
|
||||
logger.error(f"获取表结构失败: {str(e)}")
|
||||
yield
|
||||
except:
|
||||
await cls.m_pDB.execute("ROLLBACK;")
|
||||
raise
|
||||
else:
|
||||
await cls.m_pDB.execute("COMMIT;")
|
||||
|
||||
@classmethod
|
||||
async def ensure_table_exists(cls, tableName, columns) -> bool:
|
||||
"""智能创建并分析数据库表、字段是否存在 由AI生成
|
||||
async def getTableInfo(cls, tableName: str) -> list:
|
||||
if not re.match(r'^[A-Za-z_][A-Za-z0-9_]*$', tableName):
|
||||
raise ValueError(f"Illegal table name: {tableName}")
|
||||
try:
|
||||
cursor = await cls.m_pDB.execute(f'PRAGMA table_info("{tableName}")')
|
||||
rows = await cursor.fetchall()
|
||||
return [{"name": row[1], "type": row[2]} for row in rows]
|
||||
except aiosqlite.Error:
|
||||
return []
|
||||
|
||||
|
||||
@classmethod
|
||||
async def ensureTableSchema(cls, tableName: str, columns: dict) -> bool:
|
||||
"""由AI生成
|
||||
创建表或为已存在表添加缺失字段。
|
||||
返回 True 表示有变更(创建或新增列),False 则无操作
|
||||
|
||||
Args:
|
||||
tableName (_type_): 表名
|
||||
@@ -60,67 +71,50 @@ class CSqlManager:
|
||||
Returns:
|
||||
_type_: _description_
|
||||
"""
|
||||
try:
|
||||
current_columns = await cls.getColumns(tableName)
|
||||
|
||||
#检查表是否存在
|
||||
table_exists = bool(current_columns)
|
||||
info = await cls.getTableInfo(tableName)
|
||||
existing = {col['name']: col['type'].upper() for col in info}
|
||||
desired = {k: v.upper() for k, v in columns.items() if k != "PRIMARY KEY"}
|
||||
primaryKey = columns.get("PRIMARY KEY", "")
|
||||
|
||||
#如果表不存在,直接创建
|
||||
if not table_exists:
|
||||
create_sql = f'''
|
||||
CREATE TABLE "{tableName}" (
|
||||
{", ".join(f'"{k}" {v}' for k, v in columns.items())}
|
||||
);
|
||||
'''
|
||||
await cls.m_pDB.execute(create_sql)
|
||||
await cls.m_pDB.commit() #显式提交新建表操作
|
||||
if not existing:
|
||||
colsDef = ", ".join(f'"{k}" {v}' for k, v in desired.items())
|
||||
if primaryKey:
|
||||
colsDef += f", PRIMARY KEY {primaryKey}"
|
||||
await cls.m_pDB.execute(f'CREATE TABLE "{tableName}" ({colsDef});')
|
||||
return True
|
||||
|
||||
#表存在时的处理
|
||||
columns_to_add = []
|
||||
columns_to_remove = []
|
||||
toAdd = [k for k in desired if k not in existing]
|
||||
toRemove = [k for k in existing if k not in desired]
|
||||
typeMismatch = [k for k in desired if k in existing and existing[k] != desired[k]]
|
||||
|
||||
#检查需要添加的列
|
||||
for k, v in columns.items():
|
||||
if k not in current_columns:
|
||||
columns_to_add.append(f'"{k}" {v}')
|
||||
|
||||
#检查需要移除的列
|
||||
for col in current_columns:
|
||||
if col not in columns.keys():
|
||||
columns_to_remove.append(col)
|
||||
|
||||
#执行修改
|
||||
if columns_to_add or columns_to_remove:
|
||||
try:
|
||||
#开启事务(使用connection级别的事务控制)
|
||||
await cls.m_pDB.execute('BEGIN TRANSACTION')
|
||||
|
||||
#添加新列
|
||||
for col_def in columns_to_add:
|
||||
await cls.m_pDB.execute(f'ALTER TABLE "{tableName}" ADD COLUMN {col_def}')
|
||||
|
||||
#删除旧列
|
||||
for col in columns_to_remove:
|
||||
await cls.m_pDB.execute(f'ALTER TABLE "{tableName}" DROP COLUMN "{col}"')
|
||||
|
||||
#显式提交事务
|
||||
await cls.m_pDB.commit()
|
||||
if toAdd and not toRemove and not typeMismatch:
|
||||
for col in toAdd:
|
||||
await cls.m_pDB.execute(
|
||||
f'ALTER TABLE "{tableName}" ADD COLUMN "{col}" {columns[col]}'
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
#回滚事务
|
||||
await cls.m_pDB.rollback()
|
||||
logger.error(f"表结构迁移失败: {str(e)}")
|
||||
|
||||
return False
|
||||
except aiosqlite.Error as e:
|
||||
logger.error(f"表结构迁移失败: {str(e)}")
|
||||
async with cls._transaction():
|
||||
tmpTable = f"{tableName}_new"
|
||||
colsDef = ", ".join(f'"{k}" {v}' for k, v in desired.items())
|
||||
if primaryKey:
|
||||
colsDef += f", PRIMARY KEY {primaryKey}"
|
||||
await cls.m_pDB.execute(f'CREATE TABLE "{tmpTable}" ({colsDef});')
|
||||
|
||||
commonCols = [k for k in desired if k in existing]
|
||||
if commonCols:
|
||||
colsStr = ", ".join(f'"{c}"' for c in commonCols)
|
||||
await cls.m_pDB.execute(
|
||||
f'INSERT INTO "{tmpTable}" ({colsStr}) SELECT {colsStr} FROM "{tableName}";'
|
||||
)
|
||||
await cls.m_pDB.execute(f'DROP TABLE "{tableName}";')
|
||||
await cls.m_pDB.execute(f'ALTER TABLE "{tmpTable}" RENAME TO "{tableName}";')
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
async def checkDB(cls) -> bool:
|
||||
#1. 用户表
|
||||
userInfo = {
|
||||
"uid": "INTEGER PRIMARY KEY AUTOINCREMENT",
|
||||
"name": "TEXT NOT NULL",
|
||||
@@ -129,24 +123,40 @@ class CSqlManager:
|
||||
"soil": "INTEGER DEFAULT 3",
|
||||
"stealing": "TEXT DEFAULT NULL"
|
||||
}
|
||||
|
||||
userStorehouse = {
|
||||
"uid": "INTEGER PRIMARY KEY AUTOINCREMENT",
|
||||
"item": "TEXT DEFAULT ''",
|
||||
"plant": "TEXT DEFAULT ''",
|
||||
"seed": "TEXT DEFAULT ''"
|
||||
}
|
||||
|
||||
#2. 土地表
|
||||
userSoilInfo = {
|
||||
"uid": "INTEGER PRIMARY KEY AUTOINCREMENT",
|
||||
**{f"soil{i}": "TEXT DEFAULT ''" for i in range(1, 31)}
|
||||
}
|
||||
#3. 用户作物明细表
|
||||
userPlant = {
|
||||
"uid": "INTEGER NOT NULL",
|
||||
"plant": "TEXT NOT NULL",
|
||||
"count": "INTEGER NOT NULL DEFAULT 0",
|
||||
#建联合主键保证每个品种一行
|
||||
"PRIMARY KEY": "(uid, plant)"
|
||||
}
|
||||
#4. 用户种子明细表
|
||||
userSeed = {
|
||||
"uid": "INTEGER NOT NULL",
|
||||
"seed": "TEXT NOT NULL",
|
||||
"count": "INTEGER NOT NULL DEFAULT 0",
|
||||
"PRIMARY KEY": "(uid, seed)"
|
||||
}
|
||||
# 5. 用户道具明细表
|
||||
userItem = {
|
||||
"uid": "INTEGER NOT NULL",
|
||||
"item": "TEXT NOT NULL",
|
||||
"count": "INTEGER NOT NULL DEFAULT 0",
|
||||
"PRIMARY KEY": "(uid, item)"
|
||||
}
|
||||
|
||||
await cls.ensure_table_exists("user", userInfo)
|
||||
|
||||
await cls.ensure_table_exists("storehouse", userStorehouse)
|
||||
|
||||
await cls.ensure_table_exists("soil", userSoilInfo)
|
||||
#建表(或增列)
|
||||
await cls.ensureTableSchema("user", userInfo)
|
||||
await cls.ensureTableSchema("soil", userSoilInfo)
|
||||
await cls.ensureTableSchema("userPlant", userPlant)
|
||||
await cls.ensureTableSchema("userSeed", userSeed)
|
||||
await cls.ensureTableSchema("userItem", userItem)
|
||||
|
||||
return True
|
||||
|
||||
@@ -160,21 +170,20 @@ class CSqlManager:
|
||||
Returns:
|
||||
bool: 是否执行成功
|
||||
"""
|
||||
|
||||
if len(command) <= 0:
|
||||
logger.warning("数据库语句长度不能!")
|
||||
logger.warning("数据库语句长度为空!")
|
||||
return False
|
||||
|
||||
try:
|
||||
async with cls._transaction():
|
||||
await cls.m_pDB.execute(command)
|
||||
await cls.m_pDB.commit()
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning("数据库语句执行出错:" + command)
|
||||
logger.warning("数据库语句执行出错:" + command)
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def initUserInfoByUid(cls, uid: str, name: str = "", exp: int = 0, point: int = 100):
|
||||
async def initUserInfoByUid(cls, uid: str, name: str = "", exp: int = 0, point: int = 500):
|
||||
"""初始化用户信息
|
||||
|
||||
Args:
|
||||
@@ -189,11 +198,6 @@ class CSqlManager:
|
||||
INSERT INTO user (uid, name, exp, point, soil, stealing) VALUES ({uid}, '{name}', {exp}, {point}, 3, '{date.today()}|5')
|
||||
"""
|
||||
|
||||
#用户仓库
|
||||
userStorehouse = f"""
|
||||
INSERT INTO storehouse (uid) VALUES ({uid});
|
||||
"""
|
||||
|
||||
#用户土地
|
||||
userSoilInfo = f"""
|
||||
INSERT INTO soil (uid) VALUES ({uid});
|
||||
@@ -202,9 +206,6 @@ class CSqlManager:
|
||||
if not await cls.executeDB(userInfo):
|
||||
return False
|
||||
|
||||
if not await cls.executeDB(userStorehouse):
|
||||
return False
|
||||
|
||||
if not await cls.executeDB(userSoilInfo):
|
||||
return False
|
||||
|
||||
@@ -243,6 +244,55 @@ class CSqlManager:
|
||||
logger.warning(f"getUserInfoByUid查询失败: {e}")
|
||||
return {}
|
||||
|
||||
@classmethod
|
||||
async def getUserNameByUid(cls, uid: str) -> str:
|
||||
"""根据用户uid查询用户名
|
||||
|
||||
Args:
|
||||
uid (str): 用户uid
|
||||
|
||||
Returns:
|
||||
str: 用户名,如果失败返回空字符串
|
||||
"""
|
||||
if not uid:
|
||||
return ""
|
||||
|
||||
try:
|
||||
async with cls.m_pDB.execute(
|
||||
"SELECT name FROM user WHERE uid = ?",
|
||||
(uid,)
|
||||
) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
return row["name"] if row else ""
|
||||
except Exception as e:
|
||||
logger.warning(f"真寻农场getUserNameByUid查询失败: {e}")
|
||||
return ""
|
||||
|
||||
@classmethod
|
||||
async def updateUserNameByUid(cls, uid: str, name: str) -> bool:
|
||||
"""根据用户uid修改用户名
|
||||
|
||||
Args:
|
||||
uid (str): 用户uid
|
||||
name (str): 新用户名
|
||||
|
||||
Returns:
|
||||
bool: 是否更新成功
|
||||
"""
|
||||
if not uid or not name:
|
||||
return False
|
||||
|
||||
try:
|
||||
async with cls._transaction():
|
||||
await cls.m_pDB.execute(
|
||||
"UPDATE user SET name = ? WHERE uid = ?",
|
||||
(name, uid)
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning(f"真寻农场updateUserNameByUid失败: {e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def getUserPointByUid(cls, uid: str) -> int:
|
||||
"""根据用户Uid获取用户农场币
|
||||
@@ -445,205 +495,415 @@ class CSqlManager:
|
||||
|
||||
return await cls.executeDB(sql)
|
||||
|
||||
@classmethod
|
||||
async def getUserSeedByUid(cls, uid: str) -> str:
|
||||
"""获取用户仓库种子信息
|
||||
|
||||
Args:
|
||||
info (list[dict]): 用户信息
|
||||
|
||||
Returns:
|
||||
str: 仓库种子信息
|
||||
"""
|
||||
|
||||
if len(uid) <= 0:
|
||||
return ""
|
||||
|
||||
try:
|
||||
async with cls.m_pDB.execute(f"SELECT seed FROM storehouse WHERE uid = {uid}") as cursor:
|
||||
async for row in cursor:
|
||||
return row[0]
|
||||
|
||||
return ""
|
||||
except Exception as e:
|
||||
logger.warning(f"getUserSeedByUid查询失败: {e}")
|
||||
return ""
|
||||
|
||||
@classmethod
|
||||
async def getUserSeedByName(cls, uid: str, name: str) -> int:
|
||||
"""获取用户仓库种子信息
|
||||
async def addUserSeedByUid(cls, uid: str, seed: str, count: int = 1) -> bool:
|
||||
"""根据用户uid添加种子信息
|
||||
|
||||
Args:
|
||||
uid (str): 用户信息
|
||||
name (str): 种子名称
|
||||
uid (str): 用户uid
|
||||
seed (str): 种子名称
|
||||
count (int): 数量
|
||||
|
||||
Returns:
|
||||
int: 仓库种子信息
|
||||
bool: 是否添加成功
|
||||
"""
|
||||
|
||||
if len(uid) <= 0:
|
||||
return -1
|
||||
|
||||
try:
|
||||
async with cls.m_pDB.execute(f"SELECT seed FROM storehouse WHERE uid = {uid}") as cursor:
|
||||
async for row in cursor:
|
||||
if row[0] == None or len(row[0]) == 0:
|
||||
return -1
|
||||
async with cls._transaction():
|
||||
#检查是否已存在该种子
|
||||
async with cls.m_pDB.execute(
|
||||
"SELECT count FROM userSeed WHERE uid = ? AND seed = ?",
|
||||
(uid, seed)
|
||||
) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
|
||||
plantDict: Dict[str, int] = {}
|
||||
for item in row[0].split(','):
|
||||
if '|' in item:
|
||||
seedName, count = item.split('|', 1)
|
||||
plantDict[seedName] = int(count)
|
||||
|
||||
if name in plantDict:
|
||||
return plantDict[name]
|
||||
if row:
|
||||
#如果种子已存在,则更新数量
|
||||
newCount = row[0] + count
|
||||
await cls.m_pDB.execute(
|
||||
"UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?",
|
||||
(newCount, uid, seed)
|
||||
)
|
||||
else:
|
||||
return -1
|
||||
#如果种子不存在,则插入新记录
|
||||
newCount = count
|
||||
await cls.m_pDB.execute(
|
||||
"INSERT INTO userSeed (uid, seed, count) VALUES (?, ?, ?)",
|
||||
(uid, seed, count)
|
||||
)
|
||||
|
||||
return -1
|
||||
#如果种子数量为 0,删除记录
|
||||
if newCount <= 0:
|
||||
await cls.m_pDB.execute(
|
||||
"DELETE FROM userSeed WHERE uid = ? AND seed = ?",
|
||||
(uid, seed)
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning(f"getUserSeedByUid查询失败: {e}")
|
||||
return -1
|
||||
logger.warning(f"真寻农场addUserSeedByUid 失败: {e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def updateUserSeedByUid(cls, uid: str, seed: str) -> bool:
|
||||
"""更新用户种子仓库
|
||||
async def getUserSeedByName(cls, uid: str, seed: str) -> Optional[int]:
|
||||
"""根据种子名称获取种子数量
|
||||
|
||||
Args:
|
||||
uid (str): 用户Uid
|
||||
uid (str): 用户uid
|
||||
seed (str): 种子名称
|
||||
|
||||
Returns:
|
||||
bool:
|
||||
Optional[int]: 种子数量
|
||||
"""
|
||||
|
||||
if len(uid) <= 0:
|
||||
return False
|
||||
|
||||
sql = f"UPDATE storehouse SET seed = '{seed}' WHERE uid = {uid}"
|
||||
|
||||
return await cls.executeDB(sql)
|
||||
|
||||
@classmethod
|
||||
async def addUserSeedByPlant(cls, uid: str, seed: str, num: int) -> bool:
|
||||
"""添加作物信息至仓库
|
||||
|
||||
Args:
|
||||
uid (str): 用户Uid
|
||||
seed (str): 种子名称
|
||||
num(str): 种子数量
|
||||
|
||||
Returns:
|
||||
bool:
|
||||
"""
|
||||
|
||||
if len(uid) <= 0:
|
||||
return False
|
||||
|
||||
seedsDict = {}
|
||||
currentSeeds = await cls.getUserSeedByUid(uid)
|
||||
|
||||
if currentSeeds:
|
||||
for item in currentSeeds.split(','):
|
||||
if item.strip():
|
||||
name, count = item.split('|')
|
||||
seedsDict[name.strip()] = int(count.strip())
|
||||
|
||||
if seed in seedsDict:
|
||||
seedsDict[seed] += num
|
||||
if seedsDict[seed] <= 0:
|
||||
del seedsDict[seed]
|
||||
else:
|
||||
if num > 0:
|
||||
seedsDict[seed] = num
|
||||
|
||||
updatedSeeds = ','.join([f"{name}|{count}" for name, count in seedsDict.items()])
|
||||
|
||||
sql = f"UPDATE storehouse SET seed = '{updatedSeeds}' WHERE uid = {uid}"
|
||||
|
||||
return await cls.executeDB(sql)
|
||||
|
||||
@classmethod
|
||||
async def getUserPlantByUid(cls, uid: str) -> str:
|
||||
"""获取用户仓库作物信息
|
||||
|
||||
Args:
|
||||
info (list[dict]): 用户信息
|
||||
|
||||
Returns:
|
||||
str: 仓库作物信息
|
||||
"""
|
||||
|
||||
if len(uid) <= 0:
|
||||
return ""
|
||||
|
||||
try:
|
||||
async with cls.m_pDB.execute(f"SELECT plant FROM storehouse WHERE uid = {uid}") as cursor:
|
||||
async for row in cursor:
|
||||
return row[0]
|
||||
|
||||
return ""
|
||||
async with cls.m_pDB.execute(
|
||||
"SELECT count FROM userSeed WHERE uid = ? AND seed = ?",
|
||||
(uid, seed)
|
||||
) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
return row[0] if row else None
|
||||
except Exception as e:
|
||||
logger.warning(f"getUserPlantByUid查询失败: {e}")
|
||||
return ""
|
||||
logger.warning(f"真寻农场getUserSeedByName 查询失败: {e}")
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
async def updateUserPlantByUid(cls, uid: str, plant: str) -> bool:
|
||||
"""更新用户作物仓库
|
||||
async def getUserSeedByUid(cls, uid: str) -> dict:
|
||||
"""根据用户Uid获取仓库全部种子信息
|
||||
|
||||
Args:
|
||||
uid (str): 用户Uid
|
||||
plant (str): 作物名称
|
||||
uid (str): 用户uid
|
||||
|
||||
Returns:
|
||||
bool:
|
||||
dict: 种子信息
|
||||
"""
|
||||
|
||||
if len(uid) <= 0:
|
||||
return False
|
||||
|
||||
sql = f"UPDATE storehouse SET plant = '{plant}' WHERE uid = {uid}"
|
||||
|
||||
return await cls.executeDB(sql)
|
||||
cursor = await cls.m_pDB.execute(
|
||||
"SELECT seed, count FROM userSeed WHERE uid=?",
|
||||
(uid,)
|
||||
)
|
||||
rows = await cursor.fetchall()
|
||||
return {row["seed"]: row["count"] for row in rows}
|
||||
|
||||
@classmethod
|
||||
async def addUserPlantByPlant(cls, uid: str, plant: str, num: int) -> bool:
|
||||
"""添加作物信息至仓库
|
||||
async def updateUserSeedByName(cls, uid: str, seed: str, count: int) -> bool:
|
||||
"""根据种子名称更新种子数量
|
||||
|
||||
Args:
|
||||
uid (str): 用户Uid
|
||||
plant (str): 作物名称
|
||||
num(str): 作物数量
|
||||
uid (str): 用户uid
|
||||
seed (str): 种子名称
|
||||
count (int): 种子数量
|
||||
|
||||
Returns:
|
||||
bool:
|
||||
bool: 是否成功
|
||||
"""
|
||||
try:
|
||||
if count <= 0:
|
||||
return await cls.deleteUserSeedByName(uid, seed)
|
||||
|
||||
if len(uid) <= 0:
|
||||
async with cls._transaction():
|
||||
await cls.m_pDB.execute(
|
||||
"UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?",
|
||||
(count, uid, seed)
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning(f"真寻农场updateUserSeedByName失败:{e}")
|
||||
return False
|
||||
|
||||
plantsDict = {}
|
||||
currentPlants = await cls.getUserPlantByUid(uid)
|
||||
@classmethod
|
||||
async def deleteUserSeedByName(cls, uid: str, seed: str) -> bool:
|
||||
"""根据种子名称从种子仓库中删除种子
|
||||
|
||||
if currentPlants:
|
||||
for item in currentPlants.split(','):
|
||||
if item.strip():
|
||||
name, count = item.split('|')
|
||||
plantsDict[name.strip()] = int(count.strip())
|
||||
Args:
|
||||
uid (str): 用户uid
|
||||
seed (str): 种子名称
|
||||
|
||||
if plant in plantsDict:
|
||||
plantsDict[plant] += num
|
||||
if plantsDict[plant] <= 0:
|
||||
del plantsDict[plant]
|
||||
Returns:
|
||||
bool: 是否成功
|
||||
"""
|
||||
try:
|
||||
async with cls._transaction():
|
||||
await cls.m_pDB.execute(
|
||||
"DELETE FROM userSeed WHERE uid = ? AND seed = ?",
|
||||
(uid, seed)
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning(f"真寻农场deleteUserSeedByName 删除失败: {e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def addUserPlantByUid(cls, uid: str, plant: str, count: int = 1) -> bool:
|
||||
"""根据用户uid添加作物信息
|
||||
|
||||
Args:
|
||||
uid (str): 用户uid
|
||||
plant (str): 作物名称
|
||||
count (int): 数量
|
||||
|
||||
Returns:
|
||||
bool: 是否添加成功
|
||||
"""
|
||||
try:
|
||||
async with cls._transaction():
|
||||
#检查是否已存在该作物
|
||||
async with cls.m_pDB.execute(
|
||||
"SELECT count FROM userPlant WHERE uid = ? AND plant = ?",
|
||||
(uid, plant)
|
||||
) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
|
||||
if row:
|
||||
#如果作物已存在,则更新数量
|
||||
new_count = row[0] + count
|
||||
await cls.m_pDB.execute(
|
||||
"UPDATE userPlant SET count = ? WHERE uid = ? AND plant = ?",
|
||||
(new_count, uid, plant)
|
||||
)
|
||||
else:
|
||||
if num > 0:
|
||||
plantsDict[plant] = num
|
||||
#如果作物不存在,则插入新记录
|
||||
await cls.m_pDB.execute(
|
||||
"INSERT INTO userPlant (uid, plant, count) VALUES (?, ?, ?)",
|
||||
(uid, plant, count)
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning(f"真寻农场addUserPlantByUid 失败: {e}")
|
||||
return False
|
||||
|
||||
updatedPlants = ','.join([f"{name}|{count}" for name, count in plantsDict.items()])
|
||||
@classmethod
|
||||
async def getUserPlantByUid(cls, uid: str) -> Dict[str, int]:
|
||||
"""根据用户uid获取全部作物信息
|
||||
|
||||
sql = f"UPDATE storehouse SET plant = '{updatedPlants}' WHERE uid = {uid}"
|
||||
Args:
|
||||
uid (str): 用户uid
|
||||
|
||||
return await cls.executeDB(sql)
|
||||
Returns:
|
||||
Dict[str, int]: 作物名称和数量
|
||||
"""
|
||||
cursor = await cls.m_pDB.execute(
|
||||
"SELECT plant, count FROM userPlant WHERE uid=?",
|
||||
(uid,)
|
||||
)
|
||||
rows = await cursor.fetchall()
|
||||
return {row["plant"]: row["count"] for row in rows}
|
||||
|
||||
@classmethod
|
||||
async def getUserPlantByName(cls, uid: str, plant: str) -> Optional[int]:
|
||||
"""根据作物名称获取用户的作物数量
|
||||
|
||||
Args:
|
||||
uid (str): 用户uid
|
||||
plant (str): 作物名称
|
||||
|
||||
Returns:
|
||||
Optional[int]: 作物数量
|
||||
"""
|
||||
try:
|
||||
async with cls.m_pDB.execute(
|
||||
"SELECT count FROM userPlant WHERE uid = ? AND plant = ?",
|
||||
(uid, plant)
|
||||
) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
return row[0] if row else None
|
||||
except Exception as e:
|
||||
logger.warning(f"真寻农场getUserPlantByName 查询失败: {e}")
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
async def updateUserPlantByName(cls, uid: str, plant: str, count: int) -> bool:
|
||||
"""更新 userPlant 表中某个作物的数量
|
||||
|
||||
Args:
|
||||
uid (str): 用户uid
|
||||
plant (str): 作物名称
|
||||
count (int): 新的作物数量
|
||||
|
||||
Returns:
|
||||
bool: 是否更新成功
|
||||
"""
|
||||
try:
|
||||
if count <= 0:
|
||||
return await cls.deleteUserPlantByName(uid, plant)
|
||||
|
||||
async with cls._transaction():
|
||||
await cls.m_pDB.execute(
|
||||
"UPDATE userPlant SET count = ? WHERE uid = ? AND plant = ?",
|
||||
(count, uid, plant)
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning(f"真寻农场updateUserPlantByName失败:{e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def deleteUserPlantByName(cls, uid: str, plant: str) -> bool:
|
||||
"""从 userPlant 表中删除某个作物记录
|
||||
|
||||
Args:
|
||||
uid (str): 用户uid
|
||||
plant (str): 作物名称
|
||||
|
||||
Returns:
|
||||
bool: 是否删除成功
|
||||
"""
|
||||
try:
|
||||
async with cls._transaction():
|
||||
await cls.m_pDB.execute(
|
||||
"DELETE FROM userPlant WHERE uid = ? AND plant = ?",
|
||||
(uid, plant)
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning(f"真寻农场deleteUserPlantByName 失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
@classmethod
|
||||
async def getUserItemByName(cls, uid: str, item: str) -> Optional[int]:
|
||||
"""根据道具名称查询某一项数量
|
||||
|
||||
Args:
|
||||
uid (str): 用户uid
|
||||
item (str): 道具名称
|
||||
|
||||
Returns:
|
||||
Optional[int]: 数量(不存在返回None)
|
||||
"""
|
||||
if not uid or not item:
|
||||
return None
|
||||
try:
|
||||
async with cls.m_pDB.execute(
|
||||
"SELECT count FROM userItem WHERE uid = ? AND item = ?",
|
||||
(uid, item)
|
||||
) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
return row[0] if row else None
|
||||
except Exception as e:
|
||||
logger.warning(f"真寻农场getUserItemByName查询失败: {e}")
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
async def getUserItemByUid(cls, uid: str) -> dict:
|
||||
"""根据用户Uid获取全部道具信息
|
||||
|
||||
Args:
|
||||
uid (str): 用户uid
|
||||
|
||||
Returns:
|
||||
dict: {itemName: count, ...}
|
||||
"""
|
||||
if not uid:
|
||||
return {}
|
||||
try:
|
||||
cursor = await cls.m_pDB.execute(
|
||||
"SELECT item, count FROM userItem WHERE uid = ?",
|
||||
(uid,)
|
||||
)
|
||||
rows = await cursor.fetchall()
|
||||
return {row["item"]: row["count"] for row in rows}
|
||||
except Exception as e:
|
||||
logger.warning(f"真寻农场getUserItemByUid查询失败: {e}")
|
||||
return {}
|
||||
|
||||
@classmethod
|
||||
async def deleteUserItemByName(cls, uid: str, item: str) -> bool:
|
||||
"""根据道具名删除道具
|
||||
|
||||
Args:
|
||||
uid (str): 用户uid
|
||||
item (str): 道具名称
|
||||
|
||||
Returns:
|
||||
bool: 是否删除成功
|
||||
"""
|
||||
if not uid or not item:
|
||||
return False
|
||||
try:
|
||||
async with cls._transaction():
|
||||
await cls.m_pDB.execute(
|
||||
"DELETE FROM userItem WHERE uid = ? AND item = ?",
|
||||
(uid, item)
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning(f"真寻农场deleteUserItemByName失败: {e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def updateUserItemByName(cls, uid: str, item: str, count: int) -> bool:
|
||||
"""根据道具名直接更新道具数量
|
||||
|
||||
Args:
|
||||
uid (str): 用户uid
|
||||
item (str): 道具名称
|
||||
count (int): 要更新的新数量
|
||||
|
||||
Returns:
|
||||
bool: 是否更新成功
|
||||
"""
|
||||
if not uid or not item:
|
||||
return False
|
||||
try:
|
||||
async with cls._transaction():
|
||||
if count <= 0:
|
||||
await cls.m_pDB.execute(
|
||||
"DELETE FROM userItem WHERE uid = ? AND item = ?",
|
||||
(uid, item)
|
||||
)
|
||||
else:
|
||||
await cls.m_pDB.execute(
|
||||
"UPDATE userItem SET count = ? WHERE uid = ? AND item = ?",
|
||||
(count, uid, item)
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning(f"真寻农场updateUserItemByName失败: {e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def addUserItemByUid(cls, uid: str, item: str, count: int = 1) -> bool:
|
||||
"""根据用户uid添加道具信息
|
||||
|
||||
Args:
|
||||
uid (str): 用户uid
|
||||
item (str): 道具名称
|
||||
count (int, optional): 数量.Defaults to 1.
|
||||
|
||||
Returns:
|
||||
bool: 是否添加成功
|
||||
"""
|
||||
if not uid or not item:
|
||||
return False
|
||||
try:
|
||||
async with cls._transaction():
|
||||
async with cls.m_pDB.execute(
|
||||
"SELECT count FROM userItem WHERE uid = ? AND item = ?",
|
||||
(uid, item)
|
||||
) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
|
||||
if row:
|
||||
newCount = row[0] + count
|
||||
if newCount <= 0:
|
||||
await cls.m_pDB.execute(
|
||||
"DELETE FROM userItem WHERE uid = ? AND item = ?",
|
||||
(uid, item)
|
||||
)
|
||||
else:
|
||||
await cls.m_pDB.execute(
|
||||
"UPDATE userItem SET count = ? WHERE uid = ? AND item = ?",
|
||||
(newCount, uid, item)
|
||||
)
|
||||
else:
|
||||
if count > 0:
|
||||
await cls.m_pDB.execute(
|
||||
"INSERT INTO userItem (uid, item, count) VALUES (?, ?, ?)",
|
||||
(uid, item, count)
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning(f"真寻农场addUserItemByUid失败: {e}")
|
||||
return False
|
||||
|
||||
g_pSqlManager = CSqlManager()
|
||||
|
||||
@@ -51,7 +51,7 @@ class CFarmManager:
|
||||
return f"充值{point}农场币成功,手续费{tax}金币,当前农场币:{number}"
|
||||
|
||||
@classmethod
|
||||
async def drawFarmByUid(cls, uid: str, name: str) -> bytes:
|
||||
async def drawFarmByUid(cls, uid: str) -> bytes:
|
||||
"""绘制用户农场
|
||||
|
||||
Args:
|
||||
@@ -72,7 +72,9 @@ class CFarmManager:
|
||||
await grass.resize(0, soilSize[0], soilSize[1])
|
||||
|
||||
soilPos = g_pJsonManager.m_pSoil['soil']
|
||||
soilUnlock = await g_pSqlManager.getUserSoilByUid(uid)
|
||||
|
||||
userInfo = await g_pSqlManager.getUserInfoByUid(uid)
|
||||
soilUnlock = int(userInfo['soil'])
|
||||
|
||||
x = 0
|
||||
y = 0
|
||||
@@ -128,7 +130,7 @@ class CFarmManager:
|
||||
await img.paste(frame, (75, 44))
|
||||
|
||||
#用户名
|
||||
nameImg = await BuildImage.build_text_image(name, size = 24, font_color = (77, 35, 4))
|
||||
nameImg = await BuildImage.build_text_image(userInfo['name'], size = 24, font_color = (77, 35, 4))
|
||||
await img.paste(nameImg, (300, 92))
|
||||
|
||||
#经验值
|
||||
@@ -148,12 +150,10 @@ class CFarmManager:
|
||||
await img.paste(levelImg, (660, 187))
|
||||
|
||||
#金币
|
||||
point = await g_pSqlManager.getUserPointByUid(uid)
|
||||
pointImg = await BuildImage.build_text_image(str(point), size = 24, font_color = (253, 253, 253))
|
||||
pointImg = await BuildImage.build_text_image(str(userInfo['point']), size = 24, font_color = (253, 253, 253))
|
||||
await img.paste(pointImg, (330, 255))
|
||||
|
||||
#点券
|
||||
bonds = await g_pSqlManager.getUserPointByUid(uid)
|
||||
#点券 TODO
|
||||
bondsImg = await BuildImage.build_text_image("0", size = 24, font_color = (253, 253, 253))
|
||||
await img.paste(bondsImg, (570, 255))
|
||||
|
||||
@@ -213,9 +213,12 @@ class CFarmManager:
|
||||
|
||||
currentStage = int(elapsedHour / (plantInfo['time'] / (plantInfo['phase'] - 1)))
|
||||
|
||||
#TODO 缺少判断部分种子是否是通用0阶段图片
|
||||
if currentStage <= 0:
|
||||
if plantInfo['general'] == False:
|
||||
plant = BuildImage(background = g_sResourcePath / f"plant/{soilInfo[0]}/0.png")
|
||||
else:
|
||||
plant = BuildImage(background = g_sResourcePath / f"plant/basic/0.png")
|
||||
|
||||
await plant.resize(0, 35, 58)
|
||||
else:
|
||||
plant = BuildImage(background = g_sResourcePath / f"plant/{soilInfo[0]}/{currentStage}.png")
|
||||
@@ -224,17 +227,9 @@ class CFarmManager:
|
||||
|
||||
@classmethod
|
||||
async def getUserSeedByUid(cls, uid: str) -> bytes:
|
||||
"""获取用户种子仓库
|
||||
|
||||
Args:
|
||||
uid (str): 用户Uid
|
||||
|
||||
Returns:
|
||||
bytes: 返回图片
|
||||
"""
|
||||
|
||||
data_list = []
|
||||
column_name = [
|
||||
"""获取用户种子仓库"""
|
||||
dataList = []
|
||||
columnNames = [
|
||||
"-",
|
||||
"种子名称",
|
||||
"数量",
|
||||
@@ -246,37 +241,26 @@ class CFarmManager:
|
||||
"是否可以上架交易行"
|
||||
]
|
||||
|
||||
seed = await g_pSqlManager.getUserSeedByUid(uid)
|
||||
# 从数据库获取结构化数据
|
||||
seedRecords = await g_pSqlManager.getUserSeedByUid(uid) or {}
|
||||
|
||||
if seed == None:
|
||||
if not seedRecords:
|
||||
result = await ImageTemplate.table_page(
|
||||
"种子仓库",
|
||||
"播种示例:@小真寻 播种 大白菜 [数量]",
|
||||
column_name,
|
||||
data_list,
|
||||
columnNames,
|
||||
dataList,
|
||||
)
|
||||
|
||||
return result.pic2bytes()
|
||||
|
||||
sell = ""
|
||||
for item in seed.split(','):
|
||||
if '|' in item:
|
||||
seedName, count = item.split('|', 1) #分割一次,避免多竖线问题
|
||||
for seedName, count in seedRecords.items():
|
||||
try:
|
||||
plantInfo = g_pJsonManager.m_pPlant['plant'][seedName]
|
||||
iconPath = g_sResourcePath / f"plant/{seedName}/icon.png"
|
||||
icon = (iconPath, 33, 33) if iconPath.exists() else ""
|
||||
sellable = "可以" if plantInfo['again'] else "不可以"
|
||||
|
||||
icon = ""
|
||||
icon_path = g_sResourcePath / f"plant/{seedName}/icon.png"
|
||||
if icon_path.exists():
|
||||
icon = (icon_path, 33, 33)
|
||||
|
||||
if plantInfo['again'] == True:
|
||||
sell = "可以"
|
||||
else:
|
||||
sell = "不可以"
|
||||
|
||||
data_list.append(
|
||||
[
|
||||
dataList.append([
|
||||
icon,
|
||||
seedName,
|
||||
count,
|
||||
@@ -285,20 +269,17 @@ class CFarmManager:
|
||||
plantInfo['time'],
|
||||
plantInfo['crop'],
|
||||
plantInfo['again'],
|
||||
sell
|
||||
]
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
sellable
|
||||
])
|
||||
except KeyError:
|
||||
continue
|
||||
|
||||
result = await ImageTemplate.table_page(
|
||||
"种子仓库",
|
||||
"播种示例:@小真寻 播种 大白菜 [数量]",
|
||||
column_name,
|
||||
data_list,
|
||||
columnNames,
|
||||
dataList,
|
||||
)
|
||||
|
||||
return result.pic2bytes()
|
||||
|
||||
@classmethod
|
||||
@@ -311,30 +292,32 @@ class CFarmManager:
|
||||
num (int, optional): 播种数量
|
||||
|
||||
Returns:
|
||||
str:
|
||||
str: 返回结果
|
||||
"""
|
||||
|
||||
number = 0
|
||||
try:
|
||||
# 获取用户的种子数量
|
||||
count = await g_pSqlManager.getUserSeedByName(uid, name)
|
||||
if count is None:
|
||||
count = 0 # 如果返回 None,则视为没有种子
|
||||
|
||||
if count <= 0:
|
||||
return f"没有在你的仓库发现{name}种子,快去买点吧!"
|
||||
|
||||
#如果播种超过仓库种子
|
||||
isMax = False
|
||||
if count < num:
|
||||
isMax = True
|
||||
|
||||
#如果播种全部
|
||||
isAll = False
|
||||
if num == -1:
|
||||
isAll = True
|
||||
# 如果播种数量超过仓库种子数量
|
||||
if count < num and num != -1:
|
||||
return f"仓库中的{name}种子数量不足,当前剩余{count}个种子"
|
||||
|
||||
# 获取用户土地数量
|
||||
soilNumber = await g_pSqlManager.getUserSoilByUid(uid)
|
||||
|
||||
# 如果播种数量为 -1,表示播种所有可播种的土地
|
||||
if num == -1:
|
||||
num = count
|
||||
|
||||
# 记录是否成功播种
|
||||
successCount = 0
|
||||
for i in range(1, soilNumber + 1):
|
||||
if count > 0:
|
||||
if isAll or num > 0:
|
||||
if count > 0 and num > 0:
|
||||
soilName = f"soil{i}"
|
||||
success, message = await g_pSqlManager.getUserSoilStatusBySoilID(uid, soilName)
|
||||
if success:
|
||||
@@ -343,23 +326,24 @@ class CFarmManager:
|
||||
count -= 1
|
||||
|
||||
# 记录种子消耗数量
|
||||
number -= 1
|
||||
successCount += 1
|
||||
|
||||
# 更新数据库
|
||||
await g_pSqlManager.updateUserSoilStatusByPlantName(uid, soilName, name)
|
||||
|
||||
str = ""
|
||||
# 确保用户仓库数量更新
|
||||
if successCount > 0:
|
||||
await g_pSqlManager.updateUserSeedByName(uid, name, count)
|
||||
|
||||
if isMax:
|
||||
str = f"仓库数量不够那么多,已将剩余数量全部播种!"
|
||||
elif num > 0:
|
||||
str = f"播种数量超出开垦土地数量,已将可播种土地成功播种{name}!仓库还剩下{count}个种子"
|
||||
# 根据播种结果给出反馈
|
||||
if num == 0:
|
||||
return f"播种{name}成功!仓库剩余{count}个种子"
|
||||
else:
|
||||
str = f"播种{name}成功!仓库还剩下{count}个种子"
|
||||
return f"播种数量超出开垦土地数量,已将可播种土地成功播种{name}!仓库剩余{count}个种子"
|
||||
|
||||
await g_pSqlManager.addUserSeedByPlant(uid, name, number)
|
||||
|
||||
return str
|
||||
except Exception as e:
|
||||
logger.warning(f"播种操作失败: {e}")
|
||||
return "播种失败,请稍后重试!"
|
||||
|
||||
@classmethod
|
||||
async def harvest(cls, uid: str) -> str:
|
||||
@@ -414,7 +398,7 @@ class CFarmManager:
|
||||
harvestRecords.append(f"收获作物:{plantId},数量为:{number},经验为:{plantInfo['experience']}")
|
||||
|
||||
#更新数据库操作
|
||||
await g_pSqlManager.addUserPlantByPlant(uid, plantId, number)
|
||||
await g_pSqlManager.addUserPlantByUid(uid, plantId, number)
|
||||
await g_pSqlManager.updateUserSoilStatusByPlantName(uid, soil_name, "", 4)
|
||||
|
||||
if experience > 0:
|
||||
@@ -474,7 +458,6 @@ class CFarmManager:
|
||||
Returns:
|
||||
bytes: 返回图片
|
||||
"""
|
||||
|
||||
data_list = []
|
||||
column_name = [
|
||||
"-",
|
||||
@@ -487,25 +470,20 @@ class CFarmManager:
|
||||
|
||||
plant = await g_pSqlManager.getUserPlantByUid(uid)
|
||||
|
||||
if plant == None:
|
||||
if plant is None:
|
||||
result = await ImageTemplate.table_page(
|
||||
"作物仓库",
|
||||
"播种示例:@小真寻 出售作物 大白菜 [数量]",
|
||||
"出售示例:@小真寻 出售作物 大白菜 [数量]",
|
||||
column_name,
|
||||
data_list,
|
||||
)
|
||||
|
||||
return result.pic2bytes()
|
||||
|
||||
sell = ""
|
||||
for item in plant.split(','):
|
||||
if '|' in item:
|
||||
plantName, count = item.split('|', 1) #分割一次,避免多竖线问题
|
||||
try:
|
||||
plantInfo = g_pJsonManager.m_pPlant['plant'][plantName]
|
||||
|
||||
for name, count in plant.items():
|
||||
plantInfo = g_pJsonManager.m_pPlant['plant'][name]
|
||||
icon = ""
|
||||
icon_path = g_sResourcePath / f"plant/{plantName}/icon.png"
|
||||
icon_path = g_sResourcePath / f"plant/{name}/icon.png"
|
||||
if icon_path.exists():
|
||||
icon = (icon_path, 33, 33)
|
||||
|
||||
@@ -519,7 +497,7 @@ class CFarmManager:
|
||||
data_list.append(
|
||||
[
|
||||
icon,
|
||||
plantName,
|
||||
name,
|
||||
count,
|
||||
plantInfo['price'],
|
||||
number,
|
||||
@@ -527,12 +505,9 @@ class CFarmManager:
|
||||
]
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
continue
|
||||
|
||||
result = await ImageTemplate.table_page(
|
||||
"作物仓库",
|
||||
"播种示例:@小真寻 出售作物 大白菜 [数量]",
|
||||
"出售示例:@小真寻 出售作物 大白菜 [数量]",
|
||||
column_name,
|
||||
data_list,
|
||||
)
|
||||
@@ -630,7 +605,7 @@ class CFarmManager:
|
||||
logger.info(f"{randomNumber}")
|
||||
|
||||
if randomNumber > 0:
|
||||
await g_pSqlManager.addUserPlantByPlant(uid, plantId, randomNumber)
|
||||
await g_pSqlManager.addUserPlantByUid(uid, plantId, randomNumber)
|
||||
|
||||
harvestRecords.append(f"成功偷到作物:{plantId},数量为:{randomNumber}")
|
||||
stealingStatus.append(f"{uid}-{randomNumber}")
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import math
|
||||
from re import I
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.utils._build_image import BuildImage
|
||||
@@ -22,8 +23,9 @@ class CShopManager:
|
||||
column_name = [
|
||||
"-",
|
||||
"种子名称",
|
||||
"解锁等级",
|
||||
"种子单价",
|
||||
"解锁等级",
|
||||
"果实单价",
|
||||
"收获经验",
|
||||
"收获数量",
|
||||
"成熟时间(小时)",
|
||||
@@ -53,6 +55,7 @@ class CShopManager:
|
||||
[
|
||||
icon,
|
||||
key,
|
||||
plant['buy'],
|
||||
plant['level'],
|
||||
plant['price'],
|
||||
plant['experience'],
|
||||
@@ -105,7 +108,7 @@ class CShopManager:
|
||||
return "你的等级不够哦,努努力吧"
|
||||
|
||||
point = await g_pSqlManager.getUserPointByUid(uid)
|
||||
total = int(plantInfo['price']) * num
|
||||
total = int(plantInfo['buy']) * num
|
||||
|
||||
logger.debug(f"用户:{uid}购买{name},数量为{num}。用户农场币为{point},购买需要{total}")
|
||||
|
||||
@@ -114,7 +117,7 @@ class CShopManager:
|
||||
else:
|
||||
await g_pSqlManager.updateUserPointByUid(uid, point - total)
|
||||
|
||||
if await g_pSqlManager.addUserSeedByPlant(uid, name, num) == False:
|
||||
if await g_pSqlManager.addUserSeedByUid(uid, name, num) == False:
|
||||
return "购买失败,执行数据库错误!"
|
||||
|
||||
return f"成功购买{name},花费{total}农场币, 剩余{point - total}农场币"
|
||||
@@ -129,81 +132,39 @@ class CShopManager:
|
||||
Returns:
|
||||
str:
|
||||
"""
|
||||
if not isinstance(name, str) or name.strip() == "":
|
||||
name = ""
|
||||
|
||||
plant = await g_pSqlManager.getUserPlantByUid(uid)
|
||||
|
||||
if plant == None:
|
||||
if not plant:
|
||||
return "你仓库没有可以出售的作物"
|
||||
|
||||
point = 0
|
||||
totalSold = 0
|
||||
remainingItems = []
|
||||
isAll = (num == -1)
|
||||
|
||||
isAll = False
|
||||
if num == -1:
|
||||
isAll = True
|
||||
|
||||
items = plant.split(',')
|
||||
if len(name) <= 0:
|
||||
#出售全部
|
||||
for item in items:
|
||||
if '|' in item:
|
||||
plant_name, count_str = item.split('|', 1)
|
||||
try:
|
||||
count = int(count_str)
|
||||
plant_info = g_pJsonManager.m_pPlant['plant'][plant_name]
|
||||
point += plant_info['price'] * count
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
await g_pSqlManager.updateUserPlantByUid(uid, "") # 清空仓库
|
||||
if name == "":
|
||||
for plantName, count in plant.items():
|
||||
plantInfo = g_pJsonManager.m_pPlant['plant'][plantName]
|
||||
point += plantInfo['price'] * count
|
||||
await g_pSqlManager.updateUserPlantByName(uid, plantName, 0)
|
||||
else:
|
||||
for item in items:
|
||||
if '|' in item:
|
||||
plantName, countStr = item.split('|', 1)
|
||||
try:
|
||||
count = int(countStr)
|
||||
if plantName == name:
|
||||
|
||||
if isAll:
|
||||
sellAmount = count
|
||||
else:
|
||||
sellAmount = min(num, count)
|
||||
|
||||
totalSold += sellAmount
|
||||
remaining = count - sellAmount
|
||||
|
||||
if remaining > 0:
|
||||
remainingItems.append(f"{plantName}|{remaining}")
|
||||
|
||||
if isAll == False:
|
||||
num -= sellAmount
|
||||
|
||||
break
|
||||
except (ValueError, TypeError):
|
||||
continue
|
||||
|
||||
if num > 0 and isAll == False:
|
||||
if name not in plant:
|
||||
return f"出售作物{name}出错:仓库中不存在该作物"
|
||||
available = plant[name]
|
||||
sellAmount = available if isAll else min(available, num)
|
||||
if sellAmount <= 0:
|
||||
return f"出售作物{name}出错:数量不足"
|
||||
await g_pSqlManager.updateUserPlantByName(uid, name, available - sellAmount)
|
||||
totalSold = sellAmount
|
||||
|
||||
#计算收益
|
||||
try:
|
||||
plantInfo = g_pJsonManager.m_pPlant['plant'][name]
|
||||
totalPoint = plantInfo['price'] * totalSold
|
||||
except KeyError:
|
||||
return f"出售作物{name}出错:作物不存在"
|
||||
totalPoint = point if name == "" else totalSold * g_pJsonManager.m_pPlant['plant'][name]['price']
|
||||
currentPoint = await g_pSqlManager.getUserPointByUid(uid)
|
||||
await g_pSqlManager.updateUserPointByUid(uid, currentPoint + totalPoint)
|
||||
|
||||
#更新剩余作物
|
||||
remainingPlant = ','.join(remainingItems) if remainingItems else ""
|
||||
await g_pSqlManager.updateUserPlantByUid(uid, remainingPlant)
|
||||
|
||||
#更新农场币
|
||||
p = await g_pSqlManager.getUserPointByUid(uid)
|
||||
await g_pSqlManager.updateUserPointByUid(uid, p + totalPoint)
|
||||
|
||||
if name:
|
||||
return f"成功出售{name},获得农场币:{totalPoint}"
|
||||
if name == "":
|
||||
return f"成功出售所有作物,获得农场币:{totalPoint},当前农场币:{currentPoint + totalPoint}"
|
||||
else:
|
||||
return f"成功出售所有作物,获得农场币:{totalPoint}"
|
||||
return f"成功出售{name},获得农场币:{totalPoint},当前农场币:{currentPoint + totalPoint}"
|
||||
|
||||
g_pShopManager = CShopManager()
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# 真寻农场更新日志
|
||||
|
||||
## V1.1
|
||||
|
||||
- 感谢[quanquan1014](https://github.com/quanquan1014)对农场名称中包含特殊字符的处理。
|
||||
- 更正数据库写法,但是会导致V1.0用户的作物和种子丢失
|
||||
- 完善我的农场图片资源,现在会在左上角显示经验、等级、金币等详细信息了
|
||||
- 完善出售作物逻辑,现在可以空置作物名称来一键出售全部作物了,也可以选择空置数量来一键出售仓库种指定作物
|
||||
- 完善播种逻辑,现在可以空置数量来一键播种指定作物了
|
||||
- 新增更改农场名指令
|
||||
- 改进对土地开垦条件判断
|
||||
|
||||
## V1.0
|
||||
|
||||
世界的起源。
|
||||
@@ -1,31 +1,87 @@
|
||||
from unittest import result
|
||||
import os
|
||||
|
||||
import requests
|
||||
import httpx
|
||||
|
||||
from zhenxun.configs.config import Config
|
||||
from zhenxun.services.log import logger
|
||||
|
||||
|
||||
class CRequestManager:
|
||||
|
||||
@classmethod
|
||||
async def post(cls, url, json_data=None, form_data=None):
|
||||
"""发送 POST 请求(支持 JSON/Form-Data 格式)"""
|
||||
async def download(cls, url: str, savePath: str, fileName: str) -> bool:
|
||||
"""下载文件到指定路径并覆盖已存在的文件
|
||||
|
||||
Args:
|
||||
url (str): 文件的下载链接
|
||||
savePath (str): 保存文件夹路径
|
||||
fileName (str): 保存后的文件名
|
||||
|
||||
Returns:
|
||||
bool: 是否下载成功
|
||||
"""
|
||||
try:
|
||||
headers = {"Content-Type": "application/json"} if json_data else None
|
||||
response = requests.post(
|
||||
url,
|
||||
json=json_data,
|
||||
data=form_data,
|
||||
headers=headers,
|
||||
timeout=5
|
||||
)
|
||||
response.raise_for_status()
|
||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||
response = await client.get(url)
|
||||
if response.status_code == 200:
|
||||
fullPath = os.path.join(savePath, fileName)
|
||||
os.makedirs(os.path.dirname(fullPath), exist_ok=True)
|
||||
with open(fullPath, "wb") as f:
|
||||
f.write(response.content)
|
||||
return True
|
||||
else:
|
||||
logger.warning(f"文件下载失败: HTTP {response.status_code} {response.text}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.warning(f"下载文件异常: {e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def post(cls, endpoint: str, name: str = "", jsonData: dict = None, formData: dict = None) -> dict:
|
||||
"""发送POST请求到指定接口,供其他方法统一调用
|
||||
|
||||
Args:
|
||||
endpoint (str): 请求的接口路径
|
||||
name (str, optional): 操作名称用于日志记录
|
||||
jsonData (dict, optional): 以JSON格式发送的数据
|
||||
formData (dict, optional): 以表单格式发送的数据
|
||||
|
||||
Raises:
|
||||
ValueError: 当jsonData和formData都未提供时抛出
|
||||
|
||||
Returns:
|
||||
dict: 返回请求结果的JSON数据
|
||||
"""
|
||||
if jsonData is None and formData is None:
|
||||
raise ValueError("post请求必须提供jsonData或formData其中之一")
|
||||
|
||||
baseUrl = Config.get_config("zhenxun_plugin_farm", "服务地址")
|
||||
|
||||
url = f"{baseUrl.rstrip('/')}/{endpoint.lstrip('/')}"
|
||||
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=5.0) as client:
|
||||
if jsonData is not None:
|
||||
response = await client.post(url, json=jsonData)
|
||||
else:
|
||||
response = await client.post(url, data=formData)
|
||||
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"请求失败: {e}")
|
||||
else:
|
||||
logger.warning(f"真寻农场{name}请求失败: HTTP {response.status_code} {response.text}")
|
||||
return {}
|
||||
except httpx.RequestError as e:
|
||||
logger.warning(f"真寻农场{name}请求异常: {e}")
|
||||
return {}
|
||||
except Exception as e:
|
||||
logger.warning(f"真寻农场{name}处理异常: {e}")
|
||||
return {}
|
||||
|
||||
|
||||
@classmethod
|
||||
async def sign(cls, uid: str) -> str:
|
||||
a = await cls.post("http://diuse.work:9099/testPost", json_data={"level":3})
|
||||
a = await cls.post("http://diuse.work:9099/testPost", jsonData={"level":3})
|
||||
|
||||
result = ""
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |