🎨 使用Python包管理和模块访问

🎨 重构数据库结构, 使用集中式服务定位器与数据库交互
🎨 更改部分代码逻辑, 减小内存消耗
This commit is contained in:
2025-11-30 16:45:13 +08:00
parent b4d3baebe6
commit a6691595e5
29 changed files with 1356 additions and 885 deletions
+15 -14
View File
@@ -7,17 +7,18 @@ from zhenxun.services.log import logger
from zhenxun.utils.message import MessageUtils from zhenxun.utils.message import MessageUtils
from .command import diuse_farm, diuse_register, reclamation from .command import diuse_farm, diuse_register, reclamation
from .core.activity.sign_in import g_pSignInManager from .core import (
from .core.database.database import g_pSqlManager CHelpManager,
CShopManager,
g_pDBlocator,
g_pSqlManager,
g_pUserPool,
getFarmManager,
getSignInManager,
)
from .core.dbService import g_pDBService from .core.dbService import g_pDBService
from .core.farm import g_pFarmManager from .event import g_pEventManager
from .core.help import g_pHelpManager from .utils import config, getJsonManager, getRequestManager
from .core.player.playerPool import g_pUserPool
from .core.shop import g_pShopManager
from .event.event import g_pEventManager
from .utils.config import g_sResourcePath, g_sTranslation
from .utils.json import g_pJsonManager
from .utils.request import g_pRequestManager
__plugin_meta__ = PluginMetadata( __plugin_meta__ = PluginMetadata(
name="真寻农场", name="真寻农场",
@@ -102,9 +103,9 @@ async def start():
await g_pDBService.init() await g_pDBService.init()
# 检查作物文件是否缺失 or 更新 # 检查作物文件是否缺失 or 更新
await g_pRequestManager.initPlantDBFile() await getRequestManager().initPlantDBFile()
await g_pHelpManager.createHelpImage() await CHelpManager.createHelpImage()
# todayRewards = [ # todayRewards = [
# { # {
@@ -141,7 +142,7 @@ async def shutdown():
@scheduler.scheduled_job(trigger="cron", hour=4, minute=30, id="signInFile") @scheduler.scheduled_job(trigger="cron", hour=4, minute=30, id="signInFile")
async def signInFile(): async def signInFile():
try: try:
await g_pJsonManager.initSignInFile() await getJsonManager().initSignInFile()
await g_pRequestManager.initPlantDBFile() await getRequestManager().initPlantDBFile()
except Exception as e: except Exception as e:
logger.error("农场定时检查出错", e=e) logger.error("农场定时检查出错", e=e)
+118 -116
View File
@@ -24,12 +24,8 @@ from zhenxun.services.log import logger
from zhenxun.utils._build_image import BuildImage from zhenxun.utils._build_image import BuildImage
from zhenxun.utils.message import MessageUtils from zhenxun.utils.message import MessageUtils
from .core.activity.sign_in import g_pSignInManager from .core import CShopManager, g_pDBlocator, getFarmManager, getSignInManager
from .core.dbService import g_pDBService from .utils import config, getDrawFarm, getToolManager
from .core.farm import g_pFarmManager
from .core.shop import g_pShopManager
from .utils.config import g_bSignStatus, g_sTranslation
from .utils.tool import g_pToolManager
diuse_register = on_alconna( diuse_register = on_alconna(
Alconna("开通农场"), Alconna("开通农场"),
@@ -43,30 +39,30 @@ diuse_register = on_alconna(
@diuse_register.handle() @diuse_register.handle()
async def handle_register(session: Uninfo): async def handle_register(session: Uninfo):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is not None and await player.isRegistered(): if player is not None and await player.isRegistered():
await MessageUtils.build_message(g_sTranslation["register"]["repeat"]).send( await MessageUtils.build_message(
reply_to=True config.g_sTranslation["register"]["repeat"]
) ).send(reply_to=True)
return return
try: try:
raw_name = str(session.user.name) raw_name = str(session.user.name)
safe_name = g_pToolManager.sanitize_username(raw_name) safe_name = getToolManager().sanitize_username(raw_name)
success = await g_pDBService.user.initUserInfo(uid, safe_name) success = await g_pDBlocator.getUserManager().initUserInfo(uid, safe_name)
logger.info(f"用户 {uid} 选择的农场名称为: {raw_name} | 过滤后为: {safe_name}") logger.info(f"用户 {uid} 选择的农场名称为: {raw_name} | 过滤后为: {safe_name}")
msg = ( msg = (
g_sTranslation["register"]["success"].format(point=500) config.g_sTranslation["register"]["success"].format(point=500)
if success if success
else g_sTranslation["register"]["error"] else config.g_sTranslation["register"]["error"]
) )
logger.info(f"用户注册 {'成功' if success else '失败'}:{uid}") logger.info(f"用户注册 {'成功' if success else '失败'}:{uid}")
except Exception as e: except Exception as e:
msg = g_sTranslation["register"]["error"] msg = config.g_sTranslation["register"]["error"]
logger.error(f"注册异常 | UID:{uid} | 错误:{e}") logger.error(f"注册异常 | UID:{uid} | 错误:{e}")
await MessageUtils.build_message(msg).send(reply_to=True) await MessageUtils.build_message(msg).send(reply_to=True)
@@ -108,12 +104,12 @@ diuse_farm = on_alconna(
@diuse_farm.assign("$main") @diuse_farm.assign("$main")
async def _(session: Uninfo): async def _(session: Uninfo):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
image = await g_pFarmManager.drawFarmByUid(uid) image = await getDrawFarm().drawFarmByUid(uid)
await MessageUtils.build_message(image).send(reply_to=True) await MessageUtils.build_message(image).send(reply_to=True)
@@ -128,12 +124,12 @@ diuse_farm.shortcut(
@diuse_farm.assign("detail") @diuse_farm.assign("detail")
async def _(session: Uninfo): async def _(session: Uninfo):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
info = await g_pFarmManager.drawDetailFarmByUid(uid) info = await getDrawFarm().drawDetailFarmByUid(uid)
await MessageUtils.alc_forward_msg( await MessageUtils.alc_forward_msg(
[info], session.self_id, BotConfig.self_nickname [info], session.self_id, BotConfig.self_nickname
@@ -151,19 +147,21 @@ diuse_farm.shortcut(
@diuse_farm.assign("my-point") @diuse_farm.assign("my-point")
async def _(session: Uninfo): async def _(session: Uninfo):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
point = player.user["point"] point = player.user["point"]
if point < 0: if point < 0:
await MessageUtils.build_message(g_sTranslation["basic"]["notFarm"]).send() await MessageUtils.build_message(
config.g_sTranslation["basic"]["notFarm"]
).send()
return False return False
await MessageUtils.build_message( await MessageUtils.build_message(
g_sTranslation["basic"]["point"].format(point=point) config.g_sTranslation["basic"]["point"].format(point=point)
).send(reply_to=True) ).send(reply_to=True)
@@ -178,10 +176,10 @@ diuse_farm.shortcut(
@diuse_farm.assign("seed-shop") @diuse_farm.assign("seed-shop")
async def _(session: Uninfo, res: Match[tuple[str, ...]]): async def _(session: Uninfo, res: Match[tuple[str, ...]]):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
if res.result is inspect._empty: if res.result is inspect._empty:
@@ -208,9 +206,9 @@ async def _(session: Uninfo, res: Match[tuple[str, ...]]):
page = int(raw[1]) page = int(raw[1])
if filterKey is None: if filterKey is None:
image = await g_pShopManager.getSeedShopImage(page, 0, 0) image = await CShopManager.getSeedShopImage(page, 0, 0)
else: else:
image = await g_pShopManager.getSeedShopImage(filterKey, page, 0) image = await CShopManager.getSeedShopImage(filterKey, page, 0)
await MessageUtils.build_message(image).send() await MessageUtils.build_message(image).send()
@@ -228,17 +226,17 @@ async def _(
session: Uninfo, name: Match[str], num: Query[int] = AlconnaQuery("num", 1) session: Uninfo, name: Match[str], num: Query[int] = AlconnaQuery("num", 1)
): ):
if not name.available: if not name.available:
await MessageUtils.build_message(g_sTranslation["buySeed"]["notSeed"]).finish( await MessageUtils.build_message(
reply_to=True config.g_sTranslation["buySeed"]["notSeed"]
) ).finish(reply_to=True)
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
result = await g_pShopManager.buySeed(uid, name.result, num.result) result = await CShopManager.buySeed(uid, name.result, num.result)
await MessageUtils.build_message(result).send(reply_to=True) await MessageUtils.build_message(result).send(reply_to=True)
@@ -253,12 +251,12 @@ diuse_farm.shortcut(
@diuse_farm.assign("my-seed") @diuse_farm.assign("my-seed")
async def _(session: Uninfo): async def _(session: Uninfo):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
result = await g_pFarmManager.getUserSeedByUid(uid) result = await getFarmManager().getUserSeedByUid(uid)
await MessageUtils.build_message(result).send(reply_to=True) await MessageUtils.build_message(result).send(reply_to=True)
@@ -275,17 +273,17 @@ async def _(
session: Uninfo, name: Match[str], num: Query[int] = AlconnaQuery("num", -1) session: Uninfo, name: Match[str], num: Query[int] = AlconnaQuery("num", -1)
): ):
if not name.available: if not name.available:
await MessageUtils.build_message(g_sTranslation["sowing"]["notSeed"]).finish( await MessageUtils.build_message(
reply_to=True config.g_sTranslation["sowing"]["notSeed"]
) ).finish(reply_to=True)
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
result = await g_pFarmManager.sowing(uid, name.result, num.result) result = await getFarmManager().sowing(uid, name.result, num.result)
await MessageUtils.build_message(result).send(reply_to=True) await MessageUtils.build_message(result).send(reply_to=True)
@@ -300,12 +298,12 @@ diuse_farm.shortcut(
@diuse_farm.assign("harvest") @diuse_farm.assign("harvest")
async def _(session: Uninfo): async def _(session: Uninfo):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
result = await g_pFarmManager.harvest(uid) result = await getFarmManager().harvest(uid)
await MessageUtils.build_message(result).send(reply_to=True) await MessageUtils.build_message(result).send(reply_to=True)
@@ -320,12 +318,12 @@ diuse_farm.shortcut(
@diuse_farm.assign("eradicate") @diuse_farm.assign("eradicate")
async def _(session: Uninfo): async def _(session: Uninfo):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
result = await g_pFarmManager.eradicate(uid) result = await getFarmManager().eradicate(uid)
await MessageUtils.build_message(result).send(reply_to=True) await MessageUtils.build_message(result).send(reply_to=True)
@@ -340,12 +338,12 @@ diuse_farm.shortcut(
@diuse_farm.assign("my-plant") @diuse_farm.assign("my-plant")
async def _(session: Uninfo): async def _(session: Uninfo):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
result = await g_pFarmManager.getUserPlantByUid(uid) result = await getFarmManager().getUserPlantByUid(uid)
await MessageUtils.build_message(result).send(reply_to=True) await MessageUtils.build_message(result).send(reply_to=True)
@@ -360,12 +358,12 @@ diuse_farm.shortcut(
@diuse_farm.assign("lock-plant") @diuse_farm.assign("lock-plant")
async def _(session: Uninfo, name: Match[str]): async def _(session: Uninfo, name: Match[str]):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
result = await g_pFarmManager.lockUserPlantByUid(uid, name.result, 1) result = await getFarmManager().lockUserPlantByUid(uid, name.result, 1)
await MessageUtils.build_message(result).send(reply_to=True) await MessageUtils.build_message(result).send(reply_to=True)
@@ -380,12 +378,12 @@ diuse_farm.shortcut(
@diuse_farm.assign("unlock-plant") @diuse_farm.assign("unlock-plant")
async def _(session: Uninfo, name: Match[str]): async def _(session: Uninfo, name: Match[str]):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
result = await g_pFarmManager.lockUserPlantByUid(uid, name.result, 0) result = await getFarmManager().lockUserPlantByUid(uid, name.result, 0)
await MessageUtils.build_message(result).send(reply_to=True) await MessageUtils.build_message(result).send(reply_to=True)
@@ -402,12 +400,12 @@ async def _(
session: Uninfo, name: Match[str], num: Query[int] = AlconnaQuery("num", -1) session: Uninfo, name: Match[str], num: Query[int] = AlconnaQuery("num", -1)
): ):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
result = await g_pShopManager.sellPlantByUid(uid, name.result, num.result) result = await CShopManager.sellPlantByUid(uid, name.result, num.result)
await MessageUtils.build_message(result).send(reply_to=True) await MessageUtils.build_message(result).send(reply_to=True)
@@ -422,13 +420,13 @@ reclamation = on_alconna(
@reclamation.handle() @reclamation.handle()
async def _(session: Uninfo): async def _(session: Uninfo):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
condition = await g_pFarmManager.reclamationCondition(uid) condition = await getFarmManager().reclamationCondition(uid)
condition += f"\n{g_sTranslation['reclamation']['confirm']}" condition += f"\n{config.g_sTranslation['reclamation']['confirm']}"
await MessageUtils.build_message(condition).send(reply_to=True) await MessageUtils.build_message(condition).send(reply_to=True)
@waiter(waits=["message"], keep_session=True) @waiter(waits=["message"], keep_session=True)
@@ -437,14 +435,14 @@ async def _(session: Uninfo):
resp = await check.wait(timeout=60) resp = await check.wait(timeout=60)
if resp is None: if resp is None:
await MessageUtils.build_message(g_sTranslation["reclamation"]["timeOut"]).send( await MessageUtils.build_message(
reply_to=True config.g_sTranslation["reclamation"]["timeOut"]
) ).send(reply_to=True)
return return
if not resp == "是": if not resp == "是":
return return
res = await g_pFarmManager.reclamation(uid) res = await getFarmManager().reclamation(uid)
await MessageUtils.build_message(res).send(reply_to=True) await MessageUtils.build_message(res).send(reply_to=True)
@@ -459,26 +457,26 @@ diuse_farm.shortcut(
@diuse_farm.assign("stealing") @diuse_farm.assign("stealing")
async def _(session: Uninfo, target: Match[At]): async def _(session: Uninfo, target: Match[At]):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
if not target.available: if not target.available:
await MessageUtils.build_message(g_sTranslation["stealing"]["noTarget"]).finish( await MessageUtils.build_message(
reply_to=True config.g_sTranslation["stealing"]["noTarget"]
) ).finish(reply_to=True)
tar = target.result tar = target.result
result = await g_pDBService.user.isRegistered(tar.target) result = await g_pDBlocator.getUserManager().isRegistered(tar.target)
if not result: if not result:
await MessageUtils.build_message( await MessageUtils.build_message(
g_sTranslation["stealing"]["targetNotFarm"] config.g_sTranslation["stealing"]["targetNotFarm"]
).send() ).send()
return None return None
result = await g_pFarmManager.stealing(uid, tar.target) result = await getFarmManager().stealing(uid, tar.target)
await MessageUtils.build_message(result).send(reply_to=True) await MessageUtils.build_message(result).send(reply_to=True)
@@ -498,12 +496,12 @@ async def _(session: Uninfo, num: Query[int] = AlconnaQuery("num", 0)):
) )
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
result = await g_pFarmManager.buyPointByUid(uid, num.result) result = await getFarmManager().buyPointByUid(uid, num.result)
await MessageUtils.build_message(result).send(reply_to=True) await MessageUtils.build_message(result).send(reply_to=True)
@@ -518,25 +516,25 @@ diuse_farm.shortcut(
@diuse_farm.assign("change-name") @diuse_farm.assign("change-name")
async def _(session: Uninfo, name: Match[str]): async def _(session: Uninfo, name: Match[str]):
if not name.available: if not name.available:
await MessageUtils.build_message(g_sTranslation["changeName"]["noName"]).finish( await MessageUtils.build_message(
reply_to=True config.g_sTranslation["changeName"]["noName"]
) ).finish(reply_to=True)
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None: if player is None:
await MessageUtils.build_message(g_sTranslation["changeName"]["error1"]).send( await MessageUtils.build_message(
reply_to=True config.g_sTranslation["changeName"]["error1"]
) ).send(reply_to=True)
return return
result = await player.updateName(name.result) result = await player.updateName(name.result)
await MessageUtils.build_message(g_sTranslation["changeName"][result]).send( await MessageUtils.build_message(config.g_sTranslation["changeName"][result]).send(
reply_to=True reply_to=True
) )
@@ -552,17 +550,19 @@ diuse_farm.shortcut(
@diuse_farm.assign("sign-in") @diuse_farm.assign("sign-in")
async def _(session: Uninfo): async def _(session: Uninfo):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
# 判断签到是否正常加载 # 判断签到是否正常加载
if not g_bSignStatus: if not config.g_bSignStatus:
await MessageUtils.build_message(g_sTranslation["signIn"]["error"]).send() await MessageUtils.build_message(
config.g_sTranslation["signIn"]["error"]
).send()
return return
message = await g_pSignInManager.signInByUid(uid) message = await getSignInManager().signInByUid(uid)
await MessageUtils.build_message(message).send() await MessageUtils.build_message(message).send()
@@ -577,12 +577,12 @@ soil_upgrade = on_alconna(
@soil_upgrade.handle() @soil_upgrade.handle()
async def _(session: Uninfo, index: Query[int] = AlconnaQuery("index", 1)): async def _(session: Uninfo, index: Query[int] = AlconnaQuery("index", 1)):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
condition = await g_pFarmManager.soilUpgradeCondition(uid, index.result) condition = await getFarmManager().soilUpgradeCondition(uid, index.result)
await MessageUtils.build_message(condition).send(reply_to=True) await MessageUtils.build_message(condition).send(reply_to=True)
@@ -595,14 +595,14 @@ async def _(session: Uninfo, index: Query[int] = AlconnaQuery("index", 1)):
resp = await check.wait(timeout=60) resp = await check.wait(timeout=60)
if resp is None: if resp is None:
await MessageUtils.build_message(g_sTranslation["soilInfo"]["timeOut"]).send( await MessageUtils.build_message(
reply_to=True config.g_sTranslation["soilInfo"]["timeOut"]
) ).send(reply_to=True)
return return
if not resp == "是": if not resp == "是":
return return
res = await g_pFarmManager.soilUpgrade(uid, index.result) res = await getFarmManager().soilUpgrade(uid, index.result)
await MessageUtils.build_message(res).send(reply_to=True) await MessageUtils.build_message(res).send(reply_to=True)
@@ -617,12 +617,12 @@ diuse_farm.shortcut(
@diuse_farm.assign("admin-up") @diuse_farm.assign("admin-up")
async def _(session: Uninfo, num: Query[int] = AlconnaQuery("num", 0)): async def _(session: Uninfo, num: Query[int] = AlconnaQuery("num", 0)):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
await g_pDBService.userSoil.nextPhase(uid, num.result) await g_pDBlocator.getUserSoilManager().nextPhase(uid, num.result)
diuse_farm.shortcut( diuse_farm.shortcut(
@@ -641,12 +641,12 @@ async def _(session: Uninfo, num: Query[int] = AlconnaQuery("num", 0)):
) )
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
result = await g_pFarmManager.pointToVipPointByUid(uid, num.result) result = await getFarmManager().pointToVipPointByUid(uid, num.result)
await MessageUtils.build_message(result).send(reply_to=True) await MessageUtils.build_message(result).send(reply_to=True)
@@ -661,13 +661,15 @@ diuse_farm.shortcut(
@diuse_farm.assign("my-vipPoint") @diuse_farm.assign("my-vipPoint")
async def _(session: Uninfo): async def _(session: Uninfo):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
await MessageUtils.build_message( await MessageUtils.build_message(
g_sTranslation["basic"]["vipPoint"].format(vipPoint=player.user["vipPoint"]) config.g_sTranslation["basic"]["vipPoint"].format(
vipPoint=player.user["vipPoint"]
)
).send(reply_to=True) ).send(reply_to=True)
@@ -699,9 +701,9 @@ diuse_farm.shortcut(
@diuse_farm.assign("vipSeed-shop") @diuse_farm.assign("vipSeed-shop")
async def _(session: Uninfo, res: Match[tuple[str, ...]]): async def _(session: Uninfo, res: Match[tuple[str, ...]]):
uid = str(session.user.id) uid = str(session.user.id)
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if player is None or not await player.isRegistered(): if player is None or not await player.isRegistered():
await g_pToolManager.repeat() await getToolManager().repeat()
return return
if res.result is inspect._empty: if res.result is inspect._empty:
@@ -728,8 +730,8 @@ async def _(session: Uninfo, res: Match[tuple[str, ...]]):
page = int(raw[1]) page = int(raw[1])
if filterKey is None: if filterKey is None:
image = await g_pShopManager.getSeedShopImage(page, 0, 1) image = await CShopManager.getSeedShopImage(page, 0, 1)
else: else:
image = await g_pShopManager.getSeedShopImage(filterKey, page, 1) image = await CShopManager.getSeedShopImage(filterKey, page, 1)
await MessageUtils.build_message(image).send() await MessageUtils.build_message(image).send()
+29
View File
@@ -0,0 +1,29 @@
from .database import g_pDBlocator, g_pSqlManager
from .help import CHelpManager
from .player.player import CPlayer
from .player.playerPool import g_pUserPool
from .shop import CShopManager
def getFarmManager():
from .farm import CFarmManager
return CFarmManager()
def getSignInManager():
from .activity.sign_in import CSignInManager
return CSignInManager()
__all__ = [
"CHelpManager",
"CPlayer",
"CShopManager",
"g_pDBlocator",
"g_pSqlManager",
"g_pUserPool",
"getFarmManager",
"getSignInManager",
]
+23 -25
View File
@@ -4,15 +4,14 @@ from typing import Any
from zhenxun.configs.config import Config from zhenxun.configs.config import Config
from zhenxun.services.log import logger from zhenxun.services.log import logger
from ...utils.config import DATA_PATH, g_sResourcePath, g_sTranslation from ...utils import config, getJsonManager, getToolManager
from ...utils.json import g_pJsonManager
from ...utils.tool import g_pToolManager
from ..dbService import g_pDBService from ..dbService import g_pDBService
class CSignInManager: class CSignInManager:
async def signInByUid(self, uid: str) -> str: @classmethod
toDay = g_pToolManager.dateTime().date().today() async def signInByUid(cls, uid: str) -> str:
toDay = getToolManager().dateTime().date().today()
message = "" message = ""
status = await g_pDBService.userSign.sign(uid, toDay.strftime("%Y-%m-%d")) status = await g_pDBService.userSign.sign(uid, toDay.strftime("%Y-%m-%d"))
@@ -26,11 +25,11 @@ class CSignInManager:
uid, toDay.strftime("%Y-%m-%d") uid, toDay.strftime("%Y-%m-%d")
) )
message += g_sTranslation["signIn"]["success"].format( message += config.g_sTranslation["signIn"]["success"].format(
day=signDay, exp=exp, num=point day=signDay, exp=exp, num=point
) )
jSign = await g_pJsonManager.getSign() jSign = await getJsonManager().getSign()
reward = jSign["continuou"].get(f"{signDay}", None) reward = jSign["continuou"].get(f"{signDay}", None)
signType = Config.get_config("zhenxun_plugin_farm", "签到图片样式") signType = Config.get_config("zhenxun_plugin_farm", "签到图片样式")
@@ -41,30 +40,31 @@ class CSignInManager:
plant = reward.get("plant", {}) plant = reward.get("plant", {})
message += g_sTranslation["signIn"]["grandTotal"].format( message += config.g_sTranslation["signIn"]["grandTotal"].format(
exp=extraExp, num=extraPoint exp=extraExp, num=extraPoint
) )
vipPoint = reward.get("vipPoint", 0) vipPoint = reward.get("vipPoint", 0)
if vipPoint > 0: if vipPoint > 0:
message += g_sTranslation["signIn"]["grandTotal1"].format( message += config.g_sTranslation["signIn"]["grandTotal1"].format(
num=vipPoint num=vipPoint
) )
if plant: if plant:
for key, value in plant.items(): for key, value in plant.items():
message += g_sTranslation["signIn"]["grandTotal2"].format( message += config.g_sTranslation["signIn"][
name=key, num=value "grandTotal2"
) ].format(name=key, num=value)
else: else:
message = g_sTranslation["signIn"]["error1"] message = config.g_sTranslation["signIn"]["error1"]
pass pass
return message return message
@classmethod
def generateSignData( def generateSignData(
self, cls,
todayRewards: list[dict[str, Any]], todayRewards: list[dict[str, Any]],
cumulativeRewards: list[dict[str, Any]], cumulativeRewards: list[dict[str, Any]],
currentProgress: int, currentProgress: int,
@@ -104,8 +104,9 @@ class CSignInManager:
"consecutiveDays": consecutiveDays, "consecutiveDays": consecutiveDays,
} }
@classmethod
async def createSignImage( async def createSignImage(
self, cls,
todayRewards: list[dict[str, Any]], todayRewards: list[dict[str, Any]],
cumulativeRewards: list[dict[str, Any]], cumulativeRewards: list[dict[str, Any]],
currentProgress: int, currentProgress: int,
@@ -122,12 +123,12 @@ class CSignInManager:
consecutiveDays (int, optional): 连续签到天数 consecutiveDays (int, optional): 连续签到天数
""" """
try: try:
templatePath = g_sResourcePath / "html/sign_in.html" templatePath = config.g_sResourcePath / "html/sign_in.html"
outputPath = g_sResourcePath / "temp_html/sign_in.html" outputPath = config.g_sResourcePath / "temp_html/sign_in.html"
savePath = DATA_PATH / "farm_res/html/sign_in.png" savePath = config.DATA_PATH / "farm_res/html/sign_in.png"
# 1. 生成渲染数据 # 1. 生成渲染数据
context = self.generateSignData( context = cls.generateSignData(
todayRewards=todayRewards, todayRewards=todayRewards,
cumulativeRewards=cumulativeRewards, cumulativeRewards=cumulativeRewards,
currentProgress=currentProgress, currentProgress=currentProgress,
@@ -136,19 +137,16 @@ class CSignInManager:
) )
# 2. 渲染HTML文件 # 2. 渲染HTML文件
g_pToolManager.renderHtmlToFile(templatePath, context, outputPath) getToolManager().renderHtmlToFile(templatePath, context, outputPath)
# 3. 生成图片字节数据 # 3. 生成图片字节数据
# imageBytes = await g_pToolManager.screenshotHtmlToBytes(outputPath) # imageBytes = await getToolManager().screenshotHtmlToBytes(outputPath)
# 4. 保存图片文件 # 4. 保存图片文件
await g_pToolManager.screenshotSave( await getToolManager().screenshotSave(
str(outputPath), str(savePath), 600, 800 str(outputPath), str(savePath), 600, 800
) )
except Exception as e: except Exception as e:
logger.error(f"❌ 生成签到图片时出错: {e}") logger.error(f"❌ 生成签到图片时出错: {e}")
raise raise
g_pSignInManager = CSignInManager()
+25
View File
@@ -0,0 +1,25 @@
from .database import g_pSqlManager
from .dbServiceLocator import g_pDBlocator
from .plant import CPlantManager
from .user import CUserDB
from .userItem import CUserItemDB
from .userPlant import CUserPlantDB
from .userPlantCount import CUserPlantCountDB
from .userSeed import CUserSeedDB
from .userSign import CUserSignDB
from .userSoil import CUserSoilDB
from .userSteal import CUserStealDB
__all__ = [
"CPlantManager",
"CUserDB",
"CUserItemDB",
"CUserPlantCountDB",
"CUserPlantDB",
"CUserSeedDB",
"CUserSignDB",
"CUserSoilDB",
"CUserStealDB",
"g_pDBlocator",
"g_pSqlManager",
]
+171 -57
View File
@@ -1,60 +1,188 @@
from abc import ABC
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
import os import os
from pathlib import Path from pathlib import Path
import re import re
from typing import Any from typing import Any, ClassVar
import aiosqlite import aiosqlite
from zhenxun.services.log import logger from zhenxun.services.log import logger
from ...utils.config import g_sDBFilePath, g_sDBPath from ...utils import config
from .dbServiceLocator import g_pDBlocator
class CSqlManager: class CSqlManager(ABC):
"""
数据库管理器基类
所有具体的数据管理器都应该继承这个类
"""
m_pDB: ClassVar[aiosqlite.Connection | None] = None
def __init__(self): def __init__(self):
dbPath = Path(g_sDBPath) self.m_sTableName: str | None = None
if dbPath and not dbPath.exists(): self.m_bInitialized: bool = False
os.makedirs(dbPath, exist_ok=True)
@classmethod self.m_pDBPath = Path(config.g_sDBPath)
async def cleanup(cls): if self.m_pDBPath and not self.m_pDBPath.exists():
if hasattr(cls, "m_pDB") and cls.m_pDB: os.makedirs(self.m_pDBPath, exist_ok=True)
await cls.m_pDB.close()
@classmethod @classmethod
async def init(cls) -> bool: async def init(cls) -> bool:
try: try:
cls.m_pDB = await aiosqlite.connect(g_sDBFilePath) if cls.m_pDB is None:
cls.m_pDB.row_factory = aiosqlite.Row cls.m_pDB = await aiosqlite.connect(config.g_sDBFilePath)
return True cls.m_pDB.row_factory = aiosqlite.Row
logger.info("真寻农场数据库连接初始化成功")
return True
else:
logger.info("真寻农场数据库连接已存在,跳过初始化")
return True
except Exception as e: except Exception as e:
logger.debug("真寻农场初始化总数据库失败", e=e) logger.error(f"真寻农场数据库连接初始化失败: {e}")
return False return False
@classmethod
async def cleanup(cls):
if cls.m_pDB:
await cls.m_pDB.close()
cls.m_pDB = None
logger.info("真寻农场数据库连接已关闭")
@classmethod
def getDB(cls) -> aiosqlite.Connection:
if cls.m_pDB is None:
raise RuntimeError("数据库连接未初始化,请先调用 init_global_db()")
return cls.m_pDB
@classmethod
def getPlantManager(cls) -> Any:
return g_pDBlocator.getPlantManager()
@classmethod
def getUserManager(cls) -> Any:
return g_pDBlocator.getUserManager()
@classmethod
def getUserSoilManager(cls) -> Any:
return g_pDBlocator.getUserSoilManager()
@classmethod
def getUserSeedManager(cls) -> Any:
return g_pDBlocator.getUserSeedManager()
@classmethod
def getUserItemManager(cls) -> Any:
return g_pDBlocator.getUserItemManager()
@classmethod
def getUserStealManager(cls) -> Any:
return g_pDBlocator.getUserStealManager()
@classmethod
def getUserSignManager(cls) -> Any:
return g_pDBlocator.getUserSignManager()
@classmethod
def getUserPlantCountManager(cls) -> Any:
return g_pDBlocator.getUserPlantCountManager()
def isInitialized(self) -> bool:
"""检查是否已初始化"""
return self.m_bInitialized
def setInitialized(self) -> None:
"""标记为已初始化"""
self.m_bInitialized = True
@classmethod @classmethod
@asynccontextmanager @asynccontextmanager
async def _transaction(cls): async def _transaction(cls):
await cls.m_pDB.execute("BEGIN;") await cls.getDB().execute("BEGIN;")
try: try:
yield yield
except: except:
await cls.m_pDB.execute("ROLLBACK;") await cls.getDB().execute("ROLLBACK;")
raise raise
else: else:
await cls.m_pDB.execute("COMMIT;") await cls.getDB().execute("COMMIT;")
@classmethod @classmethod
async def getTableInfo(cls, tableName: str) -> list: async def getTableInfo(cls, tableName: str) -> list:
if not re.match(r"^[A-Za-z_][A-Za-z0-9_]*$", tableName): if not re.match(r"^[A-Za-z_][A-Za-z0-9_]*$", tableName):
raise ValueError(f"Illegal table name: {tableName}") raise ValueError(f"Illegal table name: {tableName}")
try: try:
cursor = await cls.m_pDB.execute(f'PRAGMA table_info("{tableName}")') cursor = await cls.getDB().execute(f'PRAGMA table_info("{tableName}")')
rows = await cursor.fetchall() rows = await cursor.fetchall()
return [{"name": row[1], "type": row[2]} for row in rows] return [{"name": row[1], "type": row[2]} for row in rows]
except aiosqlite.Error: except aiosqlite.Error:
return [] return []
# @classmethod
# async def ensureTableSchema(cls, tableName: str, columns: dict) -> bool:
# """由AI生成
# 创建表或为已存在表添加缺失字段。
# 返回 True 表示有变更(创建或新增列),False 则无操作
# Args:
# tableName (str): 表名
# columns (dict): 字典
# Returns:
# bool:
# """
# 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 existing:
# colsDef = ", ".join(f'"{k}" {v}' for k, v in desired.items())
# if primaryKey:
# colsDef += f", PRIMARY KEY {primaryKey}"
# await cls.getDB().execute(f'CREATE TABLE "{tableName}" ({colsDef});')
# return True
# 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]
# ]
# if toAdd and not toRemove and not typeMismatch:
# for col in toAdd:
# await cls.getDB().execute(
# f'ALTER TABLE "{tableName}" ADD COLUMN "{col}" {columns[col]}'
# )
# return True
# 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.getDB().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)
# sql = (
# f'INSERT INTO "{tmpTable}" ({colsStr}) '
# f"SELECT {colsStr} "
# f'FROM "{tableName}";'
# )
# await cls.getDB().execute(sql)
# await cls.getDB().execute(f'DROP TABLE "{tableName}";')
# await cls.getDB().execute(
# f'ALTER TABLE "{tmpTable}" RENAME TO "{tableName}";'
# )
# return True
@classmethod @classmethod
async def ensureTableSchema(cls, tableName: str, columns: dict) -> bool: async def ensureTableSchema(cls, tableName: str, columns: dict) -> bool:
"""由AI生成 """由AI生成
@@ -62,13 +190,12 @@ class CSqlManager:
返回 True 表示有变更(创建或新增列),False 则无操作 返回 True 表示有变更(创建或新增列),False 则无操作
Args: Args:
tableName (_type_): 表名 tableName (str): 表名
columns (_type_): 字典 columns (dict): 字典
Returns: Returns:
_type_: _description_ bool:
""" """
info = await cls.getTableInfo(tableName) info = await cls.getTableInfo(tableName)
existing = {col["name"]: col["type"].upper() for col in info} existing = {col["name"]: col["type"].upper() for col in info}
desired = {k: v.upper() for k, v in columns.items() if k != "PRIMARY KEY"} desired = {k: v.upper() for k, v in columns.items() if k != "PRIMARY KEY"}
@@ -78,7 +205,7 @@ class CSqlManager:
colsDef = ", ".join(f'"{k}" {v}' for k, v in desired.items()) colsDef = ", ".join(f'"{k}" {v}' for k, v in desired.items())
if primaryKey: if primaryKey:
colsDef += f", PRIMARY KEY {primaryKey}" colsDef += f", PRIMARY KEY {primaryKey}"
await cls.m_pDB.execute(f'CREATE TABLE "{tableName}" ({colsDef});') await cls.getDB().execute(f'CREATE TABLE "{tableName}" ({colsDef});')
return True return True
toAdd = [k for k in desired if k not in existing] toAdd = [k for k in desired if k not in existing]
@@ -87,36 +214,23 @@ class CSqlManager:
k for k in desired if k in existing and existing[k] != desired[k] k for k in desired if k in existing and existing[k] != desired[k]
] ]
if toAdd and not toRemove and not typeMismatch: if toRemove or typeMismatch:
return False
if toAdd:
for col in toAdd: for col in toAdd:
await cls.m_pDB.execute( try:
f'ALTER TABLE "{tableName}" ADD COLUMN "{col}" {columns[col]}' await cls.getDB().execute(
) f'ALTER TABLE "{tableName}" ADD COLUMN "{col}" {columns[col]}'
)
except aiosqlite.OperationalError as e:
if "duplicate column name" in str(e).lower():
continue
else:
raise
return True return True
async with cls._transaction(): return False
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)
sql = (
f'INSERT INTO "{tmpTable}" ({colsStr}) '
f"SELECT {colsStr} "
f'FROM "{tableName}";'
)
await cls.m_pDB.execute(sql)
await cls.m_pDB.execute(f'DROP TABLE "{tableName}";')
await cls.m_pDB.execute(
f'ALTER TABLE "{tmpTable}" RENAME TO "{tableName}";'
)
return True
@classmethod @classmethod
async def executeDB(cls, command: str) -> bool: async def executeDB(cls, command: str) -> bool:
@@ -133,7 +247,7 @@ class CSqlManager:
try: try:
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute(command) await cls.getDB().execute(command)
return True return True
except Exception: except Exception:
return False return False
@@ -162,7 +276,7 @@ class CSqlManager:
sql = f'INSERT INTO "{tableName}" ({columns}) VALUES ({placeholders})' sql = f'INSERT INTO "{tableName}" ({columns}) VALUES ({placeholders})'
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute(sql, values) await cls.getDB().execute(sql, values)
return True return True
except Exception as e: except Exception as e:
logger.debug("真寻农场插入数据失败!", e=e) logger.debug("真寻农场插入数据失败!", e=e)
@@ -191,7 +305,7 @@ class CSqlManager:
sql = f'INSERT INTO "{tableName}" ({columns}) VALUES ({placeholders})' sql = f'INSERT INTO "{tableName}" ({columns}) VALUES ({placeholders})'
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.executemany( await cls.getDB().executemany(
sql, [list(data.values()) for data in data_list] sql, [list(data.values()) for data in data_list]
) )
return True return True
@@ -255,7 +369,7 @@ class CSqlManager:
if limit: if limit:
sql += f" LIMIT {limit}" sql += f" LIMIT {limit}"
cursor = await cls.m_pDB.execute(sql, params) cursor = await cls.getDB().execute(sql, params)
rows = await cursor.fetchall() rows = await cursor.fetchall()
# 转换为字典列表 # 转换为字典列表
@@ -304,7 +418,7 @@ class CSqlManager:
sql = f'UPDATE "{tableName}" SET {", ".join(set_conditions)} WHERE {" AND ".join(where_conditions)}' sql = f'UPDATE "{tableName}" SET {", ".join(set_conditions)} WHERE {" AND ".join(where_conditions)}'
async with cls._transaction(): async with cls._transaction():
cursor = await cls.m_pDB.execute(sql, params) cursor = await cls.getDB().execute(sql, params)
# 检查是否影响了行 # 检查是否影响了行
return cursor.rowcount > 0 return cursor.rowcount > 0
except Exception as e: except Exception as e:
@@ -337,7 +451,7 @@ class CSqlManager:
sql = f'DELETE FROM "{tableName}" WHERE {" AND ".join(where_conditions)}' sql = f'DELETE FROM "{tableName}" WHERE {" AND ".join(where_conditions)}'
async with cls._transaction(): async with cls._transaction():
cursor = await cls.m_pDB.execute(sql, params) cursor = await cls.getDB().execute(sql, params)
# 检查是否影响了行 # 检查是否影响了行
return cursor.rowcount > 0 return cursor.rowcount > 0
except Exception as e: except Exception as e:
@@ -388,7 +502,7 @@ class CSqlManager:
sql += " WHERE " + " AND ".join(where_conditions) sql += " WHERE " + " AND ".join(where_conditions)
cursor = await cls.m_pDB.execute(sql, params) cursor = await cls.getDB().execute(sql, params)
row = await cursor.fetchone() row = await cursor.fetchone()
return row["count"] if row else 0 return row["count"] if row else 0
except Exception as e: except Exception as e:
+85
View File
@@ -0,0 +1,85 @@
from typing import Any, Optional
from zhenxun.services.log import logger
class CDBServiceLocator:
"""
数据库服务定位器
负责管理所有数据库服务实例,提供统一的访问接口
"""
m_pInstance: Optional["CDBServiceLocator"] = None
def __init__(self):
self.m_pServices: dict[str, Any] = {}
self.m_bInitialized = False
@classmethod
def getInstance(cls) -> "CDBServiceLocator":
"""
获取单例实例
"""
if cls.m_pInstance is None:
cls.m_pInstance = cls()
return cls.m_pInstance
def register(self, name: str, service: Any) -> None:
"""
注册服务实例
"""
if name in self.m_pServices:
logger.error(f"真寻农场服务 {name} 已经注册")
self.m_pServices[name] = service
def get(self, name: str) -> Any:
"""
获取服务实例
"""
if name not in self.m_pServices:
raise KeyError(f"服务 {name} 未注册")
return self.m_pServices[name]
def getPlantManager(self):
return self.get("plant")
def getUserManager(self):
return self.get("user")
def getUserSoilManager(self):
return self.get("userSoil")
def getUserPlantManager(self):
return self.get("userPlant")
def getUserSeedManager(self):
return self.get("userSeed")
def getUserItemManager(self):
return self.get("userItem")
def getUserStealManager(self):
return self.get("userSteal")
def getUserSignManager(self):
return self.get("userSign")
def getUserPlantCountManager(self):
return self.get("userPlantCount")
def markInitialized(self):
"""
标记初始化完成
"""
self.m_bInitialized = True
@property
def initialized(self) -> bool:
"""
检查是否已初始化
"""
return self.m_bInitialized
# 全局服务定位器实例
g_pDBlocator = CDBServiceLocator.getInstance()
+19 -10
View File
@@ -6,14 +6,16 @@ import aiosqlite
from zhenxun.configs.config import Config from zhenxun.configs.config import Config
from zhenxun.services.log import logger from zhenxun.services.log import logger
from ...utils.config import g_bIsDebug, g_sPlantPath, g_sResourcePath from ...utils import config, getRequestManager
from ...utils.request import g_pRequestManager
class CPlantManager: class CPlantManager:
def __init__(self): def __init__(self):
self.m_sTableName = "plant"
self.m_bInitialized = False
try: try:
os.mkdir(g_sPlantPath) os.mkdir(config.g_sPlantPath)
except FileExistsError: except FileExistsError:
pass pass
@@ -23,14 +25,14 @@ class CPlantManager:
async def init(self) -> bool: async def init(self) -> bool:
try: try:
_ = os.path.exists(g_sPlantPath) _ = os.path.exists(config.g_sPlantPath)
if g_bIsDebug: if config.g_bIsDebug:
self.m_pDB = await aiosqlite.connect( self.m_pDB = await aiosqlite.connect(
str(g_sPlantPath.parent / "plant-test.db") str(config.g_sPlantPath.parent / "plant-test.db")
) )
else: else:
self.m_pDB = await aiosqlite.connect(str(g_sPlantPath)) self.m_pDB = await aiosqlite.connect(str(config.g_sPlantPath))
self.m_pDB.row_factory = aiosqlite.Row self.m_pDB.row_factory = aiosqlite.Row
return True return True
@@ -38,6 +40,9 @@ class CPlantManager:
logger.warning("初始化植物数据库失败", e=e) logger.warning("初始化植物数据库失败", e=e)
return False return False
async def initDB(self):
self.m_bInitialized = True
@asynccontextmanager @asynccontextmanager
async def _transaction(self): async def _transaction(self):
await self.m_pDB.execute("BEGIN;") await self.m_pDB.execute("BEGIN;")
@@ -254,7 +259,7 @@ class CPlantManager:
for plant in plants: for plant in plants:
name = plant["name"] name = plant["name"]
phaseCount = await self.getPlantPhaseNumberByName(name) phaseCount = await self.getPlantPhaseNumberByName(name)
saveDir = os.path.join(g_sResourcePath, "plant", name) saveDir = os.path.join(config.g_sResourcePath, "plant", name)
begin = 0 if plant["general"] == 0 else 1 begin = 0 if plant["general"] == 0 else 1
for idx in range(begin, phaseCount + 1): for idx in range(begin, phaseCount + 1):
@@ -265,14 +270,18 @@ class CPlantManager:
continue continue
url = f"{baseUrl}/{name}/{idx}.png" url = f"{baseUrl}/{name}/{idx}.png"
if not await g_pRequestManager.download(url, saveDir, f"{idx}.png"): if not await getRequestManager().download(
url, saveDir, f"{idx}.png"
):
success = False success = False
iconName = "icon.png" iconName = "icon.png"
iconPath = os.path.join(saveDir, iconName) iconPath = os.path.join(saveDir, iconName)
if not os.path.exists(iconPath): if not os.path.exists(iconPath):
iconUrl = f"{baseUrl}/{name}/{iconName}" iconUrl = f"{baseUrl}/{name}/{iconName}"
if not await g_pRequestManager.download(iconUrl, saveDir, iconName): if not await getRequestManager().download(
iconUrl, saveDir, iconName
):
success = False success = False
return success return success
+6 -3
View File
@@ -1,11 +1,13 @@
import math import math
from ...utils.tool import g_pToolManager from ...utils import getToolManager
from .database import CSqlManager from .database import CSqlManager
class CUserDB(CSqlManager): class CUserDB(CSqlManager):
def __init__(self): def __init__(self):
super().__init__()
self.m_sTableName = "user"
self.currencies: list[str] = ["point", "vipPoint"] self.currencies: list[str] = ["point", "vipPoint"]
async def initDB(self): async def initDB(self):
@@ -21,6 +23,7 @@ class CUserDB(CSqlManager):
} }
await self.ensureTableSchema("user", userInfo) await self.ensureTableSchema("user", userInfo)
self.setInitialized()
async def initUserInfo(self, uid: str, name: str) -> bool: async def initUserInfo(self, uid: str, name: str) -> bool:
"""初始化用户信息 """初始化用户信息
@@ -32,7 +35,7 @@ class CUserDB(CSqlManager):
Returns: Returns:
bool: 是否成功初始化用户信息 bool: 是否成功初始化用户信息
""" """
nowStr = g_pToolManager.dateTime().date().today().strftime("%Y-%m-%d") nowStr = getToolManager().dateTime().date().today().strftime("%Y-%m-%d")
result = await self.insert( result = await self.insert(
"user", "user",
@@ -125,7 +128,7 @@ class CUserDB(CSqlManager):
Returns: Returns:
bool: 是否成功更新农场名称 bool: 是否成功更新农场名称
""" """
safeName = g_pToolManager.sanitize_username(name) safeName = getToolManager().sanitize_username(name)
if safeName == "神秘农夫": if safeName == "神秘农夫":
return "error" return "error"
+16 -12
View File
@@ -4,8 +4,11 @@ from .database import CSqlManager
class CUserItemDB(CSqlManager): class CUserItemDB(CSqlManager):
@classmethod def __init__(self):
async def initDB(cls): super().__init__()
self.m_sTableName = "userItem"
async def initDB(self):
userItem = { userItem = {
"uid": "TEXT NOT NULL", # 用户Uid "uid": "TEXT NOT NULL", # 用户Uid
"item": "TEXT NOT NULL", # 物品名称 "item": "TEXT NOT NULL", # 物品名称
@@ -13,7 +16,8 @@ class CUserItemDB(CSqlManager):
"PRIMARY KEY": "(uid, item)", "PRIMARY KEY": "(uid, item)",
} }
await cls.ensureTableSchema("userItem", userItem) await self.ensureTableSchema("userItem", userItem)
self.setInitialized()
@classmethod @classmethod
async def getUserItemByName(cls, uid: str, item: str) -> int | None: async def getUserItemByName(cls, uid: str, item: str) -> int | None:
@@ -29,7 +33,7 @@ class CUserItemDB(CSqlManager):
if not uid or not item: if not uid or not item:
return None return None
try: try:
async with cls.m_pDB.execute( async with cls.getDB().execute(
"SELECT count FROM userItem WHERE uid = ? AND item = ?", (uid, item) "SELECT count FROM userItem WHERE uid = ? AND item = ?", (uid, item)
) as cursor: ) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
@@ -51,7 +55,7 @@ class CUserItemDB(CSqlManager):
if not uid: if not uid:
return {} return {}
try: try:
cursor = await cls.m_pDB.execute( cursor = await cls.getDB().execute(
"SELECT item, count FROM userItem WHERE uid = ?", (uid,) "SELECT item, count FROM userItem WHERE uid = ?", (uid,)
) )
rows = await cursor.fetchall() rows = await cursor.fetchall()
@@ -75,7 +79,7 @@ class CUserItemDB(CSqlManager):
return False return False
try: try:
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute( await cls.getDB().execute(
"DELETE FROM userItem WHERE uid = ? AND item = ?", (uid, item) "DELETE FROM userItem WHERE uid = ? AND item = ?", (uid, item)
) )
return True return True
@@ -100,11 +104,11 @@ class CUserItemDB(CSqlManager):
try: try:
async with cls._transaction(): async with cls._transaction():
if count <= 0: if count <= 0:
await cls.m_pDB.execute( await cls.getDB().execute(
"DELETE FROM userItem WHERE uid = ? AND item = ?", (uid, item) "DELETE FROM userItem WHERE uid = ? AND item = ?", (uid, item)
) )
else: else:
await cls.m_pDB.execute( await cls.getDB().execute(
"UPDATE userItem SET count = ? WHERE uid = ? AND item = ?", "UPDATE userItem SET count = ? WHERE uid = ? AND item = ?",
(count, uid, item), (count, uid, item),
) )
@@ -129,7 +133,7 @@ class CUserItemDB(CSqlManager):
return False return False
try: try:
async with cls._transaction(): async with cls._transaction():
async with cls.m_pDB.execute( async with cls.getDB().execute(
"SELECT count FROM userItem WHERE uid = ? AND item = ?", (uid, item) "SELECT count FROM userItem WHERE uid = ? AND item = ?", (uid, item)
) as cursor: ) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
@@ -137,18 +141,18 @@ class CUserItemDB(CSqlManager):
if row: if row:
newCount = row[0] + count newCount = row[0] + count
if newCount <= 0: if newCount <= 0:
await cls.m_pDB.execute( await cls.getDB().execute(
"DELETE FROM userItem WHERE uid = ? AND item = ?", "DELETE FROM userItem WHERE uid = ? AND item = ?",
(uid, item), (uid, item),
) )
else: else:
await cls.m_pDB.execute( await cls.getDB().execute(
"UPDATE userItem SET count = ? WHERE uid = ? AND item = ?", "UPDATE userItem SET count = ? WHERE uid = ? AND item = ?",
(newCount, uid, item), (newCount, uid, item),
) )
else: else:
if count > 0: if count > 0:
await cls.m_pDB.execute( await cls.getDB().execute(
"INSERT INTO userItem (uid, item, count) VALUES (?, ?, ?)", "INSERT INTO userItem (uid, item, count) VALUES (?, ?, ?)",
(uid, item, count), (uid, item, count),
) )
+17 -13
View File
@@ -4,8 +4,11 @@ from .database import CSqlManager
class CUserPlantDB(CSqlManager): class CUserPlantDB(CSqlManager):
@classmethod def __init__(self):
async def initDB(cls): super().__init__()
self.m_sTableName = "userPlant"
async def initDB(self):
userPlant = { userPlant = {
"uid": "TEXT NOT NULL", # 用户Uid "uid": "TEXT NOT NULL", # 用户Uid
"plant": "TEXT NOT NULL", # 作物名称 "plant": "TEXT NOT NULL", # 作物名称
@@ -14,7 +17,8 @@ class CUserPlantDB(CSqlManager):
"PRIMARY KEY": "(uid, plant)", "PRIMARY KEY": "(uid, plant)",
} }
await cls.ensureTableSchema("userPlant", userPlant) await self.ensureTableSchema("userPlant", userPlant)
self.setInitialized()
@classmethod @classmethod
async def addUserPlantByUid(cls, uid: str, plant: str, count: int = 1) -> bool: async def addUserPlantByUid(cls, uid: str, plant: str, count: int = 1) -> bool:
@@ -31,7 +35,7 @@ class CUserPlantDB(CSqlManager):
try: try:
async with cls._transaction(): async with cls._transaction():
# 检查是否已存在该作物 # 检查是否已存在该作物
async with cls.m_pDB.execute( async with cls.getDB().execute(
"SELECT count FROM userPlant WHERE uid = ? AND plant = ?", "SELECT count FROM userPlant WHERE uid = ? AND plant = ?",
(uid, plant), (uid, plant),
) as cursor: ) as cursor:
@@ -40,13 +44,13 @@ class CUserPlantDB(CSqlManager):
if row: if row:
# 如果作物已存在,则更新数量 # 如果作物已存在,则更新数量
new_count = row[0] + count new_count = row[0] + count
await cls.m_pDB.execute( await cls.getDB().execute(
"UPDATE userPlant SET count = ? WHERE uid = ? AND plant = ?", "UPDATE userPlant SET count = ? WHERE uid = ? AND plant = ?",
(new_count, uid, plant), (new_count, uid, plant),
) )
else: else:
# 如果作物不存在,则插入新记录 # 如果作物不存在,则插入新记录
await cls.m_pDB.execute( await cls.getDB().execute(
"INSERT INTO userPlant (uid, plant, count) VALUES (?, ?, ?)", "INSERT INTO userPlant (uid, plant, count) VALUES (?, ?, ?)",
(uid, plant, count), (uid, plant, count),
) )
@@ -65,7 +69,7 @@ class CUserPlantDB(CSqlManager):
Returns: Returns:
Dict[str, int]: 作物名称和数量 Dict[str, int]: 作物名称和数量
""" """
cursor = await cls.m_pDB.execute( cursor = await cls.getDB().execute(
"SELECT plant, count FROM userPlant WHERE uid=?", (uid,) "SELECT plant, count FROM userPlant WHERE uid=?", (uid,)
) )
rows = await cursor.fetchall() rows = await cursor.fetchall()
@@ -83,7 +87,7 @@ class CUserPlantDB(CSqlManager):
Optional[int]: 作物数量 Optional[int]: 作物数量
""" """
try: try:
async with cls.m_pDB.execute( async with cls.getDB().execute(
"SELECT count FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant) "SELECT count FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant)
) as cursor: ) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
@@ -104,7 +108,7 @@ class CUserPlantDB(CSqlManager):
bool: 是否存在 bool: 是否存在
""" """
try: try:
async with cls.m_pDB.execute( async with cls.getDB().execute(
"SELECT * FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant) "SELECT * FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant)
) as cursor: ) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
@@ -130,7 +134,7 @@ class CUserPlantDB(CSqlManager):
return await cls.deleteUserPlantByName(uid, plant) return await cls.deleteUserPlantByName(uid, plant)
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute( await cls.getDB().execute(
"UPDATE userPlant SET count = ? WHERE uid = ? AND plant = ?", "UPDATE userPlant SET count = ? WHERE uid = ? AND plant = ?",
(count, uid, plant), (count, uid, plant),
) )
@@ -153,7 +157,7 @@ class CUserPlantDB(CSqlManager):
""" """
try: try:
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute( await cls.getDB().execute(
"UPDATE userPlant SET isLock = ? WHERE uid = ? AND plant = ?", "UPDATE userPlant SET isLock = ? WHERE uid = ? AND plant = ?",
(lock, uid, plant), (lock, uid, plant),
) )
@@ -174,7 +178,7 @@ class CUserPlantDB(CSqlManager):
bool: 是否加锁 bool: 是否加锁
""" """
try: try:
async with cls.m_pDB.execute( async with cls.getDB().execute(
"SELECT isLock FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant) "SELECT isLock FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant)
) as cursor: ) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
@@ -196,7 +200,7 @@ class CUserPlantDB(CSqlManager):
""" """
try: try:
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute( await cls.getDB().execute(
"DELETE FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant) "DELETE FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant)
) )
return True return True
+15 -11
View File
@@ -4,8 +4,11 @@ from .database import CSqlManager
class CUserPlantCountDB(CSqlManager): class CUserPlantCountDB(CSqlManager):
@classmethod def __init__(self):
async def initDB(cls): super().__init__()
self.m_sTableName = "userPlantCount"
async def initDB(self):
userPlantCount = { userPlantCount = {
"uid": "TEXT NOT NULL", # 用户Uid "uid": "TEXT NOT NULL", # 用户Uid
"plant": "TEXT NOT NULL", # 植物名称 "plant": "TEXT NOT NULL", # 植物名称
@@ -13,7 +16,8 @@ class CUserPlantCountDB(CSqlManager):
"PRIMARY KEY": "(uid, plant)", "PRIMARY KEY": "(uid, plant)",
} }
await cls.ensureTableSchema("userPlantCount", userPlantCount) await self.ensureTableSchema("userPlantCount", userPlantCount)
self.setInitialized()
@classmethod @classmethod
async def addUserPlantCountByUid(cls, uid: str, plant: str, count: int = 1) -> bool: async def addUserPlantCountByUid(cls, uid: str, plant: str, count: int = 1) -> bool:
@@ -29,7 +33,7 @@ class CUserPlantCountDB(CSqlManager):
""" """
try: try:
async with cls._transaction(): async with cls._transaction():
async with cls.m_pDB.execute( async with cls.getDB().execute(
"SELECT count FROM userPlantCount WHERE uid = ? AND plant = ?", "SELECT count FROM userPlantCount WHERE uid = ? AND plant = ?",
(uid, plant), (uid, plant),
) as cursor: ) as cursor:
@@ -37,19 +41,19 @@ class CUserPlantCountDB(CSqlManager):
if row: if row:
newCount = row[0] + count newCount = row[0] + count
await cls.m_pDB.execute( await cls.getDB().execute(
"UPDATE userPlantCount SET count = ? WHERE uid = ? AND plant = ?", "UPDATE userPlantCount SET count = ? WHERE uid = ? AND plant = ?",
(newCount, uid, plant), (newCount, uid, plant),
) )
else: else:
newCount = count newCount = count
await cls.m_pDB.execute( await cls.getDB().execute(
"INSERT INTO userPlantCount (uid, plant, count) VALUES (?, ?, ?)", "INSERT INTO userPlantCount (uid, plant, count) VALUES (?, ?, ?)",
(uid, plant, count), (uid, plant, count),
) )
if newCount <= 0: if newCount <= 0:
await cls.m_pDB.execute( await cls.getDB().execute(
"DELETE FROM userPlantCount WHERE uid = ? AND plant = ?", "DELETE FROM userPlantCount WHERE uid = ? AND plant = ?",
(uid, plant), (uid, plant),
) )
@@ -69,7 +73,7 @@ class CUserPlantCountDB(CSqlManager):
dict: 植物信息 dict: 植物信息
""" """
cursor = await cls.m_pDB.execute( cursor = await cls.getDB().execute(
"SELECT plant, count FROM userPlantCount WHERE uid=?", (uid,) "SELECT plant, count FROM userPlantCount WHERE uid=?", (uid,)
) )
rows = await cursor.fetchall() rows = await cursor.fetchall()
@@ -86,7 +90,7 @@ class CUserPlantCountDB(CSqlManager):
Returns: Returns:
int: 收获次数 int: 收获次数
""" """
cursor = await cls.m_pDB.execute( cursor = await cls.getDB().execute(
"SELECT count FROM userPlantCount WHERE uid = ? AND plant = ?", "SELECT count FROM userPlantCount WHERE uid = ? AND plant = ?",
(uid, plant), (uid, plant),
) )
@@ -110,7 +114,7 @@ class CUserPlantCountDB(CSqlManager):
return await cls.deleteUserPlantCountByName(uid, plant) return await cls.deleteUserPlantCountByName(uid, plant)
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute( await cls.getDB().execute(
"UPDATE userPlantCount SET count = ? WHERE uid = ? AND plant = ?", "UPDATE userPlantCount SET count = ? WHERE uid = ? AND plant = ?",
(count, uid, plant), (count, uid, plant),
) )
@@ -132,7 +136,7 @@ class CUserPlantCountDB(CSqlManager):
""" """
try: try:
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute( await cls.getDB().execute(
"DELETE FROM userPlantCount WHERE uid = ? AND plant = ?", "DELETE FROM userPlantCount WHERE uid = ? AND plant = ?",
(uid, plant), (uid, plant),
) )
+18 -14
View File
@@ -4,8 +4,11 @@ from .database import CSqlManager
class CUserSeedDB(CSqlManager): class CUserSeedDB(CSqlManager):
@classmethod def __init__(self):
async def initDB(cls): super().__init__()
self.m_sTableName = "userSeed"
async def initDB(self):
userSeed = { userSeed = {
"uid": "TEXT NOT NULL", # 用户Uid "uid": "TEXT NOT NULL", # 用户Uid
"seed": "TEXT NOT NULL", # 种子名称 "seed": "TEXT NOT NULL", # 种子名称
@@ -13,7 +16,8 @@ class CUserSeedDB(CSqlManager):
"PRIMARY KEY": "(uid, seed)", "PRIMARY KEY": "(uid, seed)",
} }
await cls.ensureTableSchema("userSeed", userSeed) await self.ensureTableSchema("userSeed", userSeed)
self.setInitialized()
@classmethod @classmethod
async def addUserSeedByUid(cls, uid: str, seed: str, count: int = 1) -> bool: async def addUserSeedByUid(cls, uid: str, seed: str, count: int = 1) -> bool:
@@ -29,26 +33,26 @@ class CUserSeedDB(CSqlManager):
""" """
try: try:
async with cls._transaction(): async with cls._transaction():
async with cls.m_pDB.execute( async with cls.getDB().execute(
"SELECT count FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed) "SELECT count FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed)
) as cursor: ) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
if row: if row:
newCount = row[0] + count newCount = row[0] + count
await cls.m_pDB.execute( await cls.getDB().execute(
"UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?", "UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?",
(newCount, uid, seed), (newCount, uid, seed),
) )
else: else:
newCount = count newCount = count
await cls.m_pDB.execute( await cls.getDB().execute(
"INSERT INTO userSeed (uid, seed, count) VALUES (?, ?, ?)", "INSERT INTO userSeed (uid, seed, count) VALUES (?, ?, ?)",
(uid, seed, count), (uid, seed, count),
) )
if newCount <= 0: if newCount <= 0:
await cls.m_pDB.execute( await cls.getDB().execute(
"DELETE FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed) "DELETE FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed)
) )
return True return True
@@ -66,7 +70,7 @@ class CUserSeedDB(CSqlManager):
if existing is not None: if existing is not None:
await cls._updateUserSeedByName(uid, seed, newCount) await cls._updateUserSeedByName(uid, seed, newCount)
else: else:
await cls.m_pDB.execute( await cls.getDB().execute(
"INSERT INTO userSeed (uid, seed, count) VALUES (?, ?, ?)", "INSERT INTO userSeed (uid, seed, count) VALUES (?, ?, ?)",
(uid, seed, newCount), (uid, seed, newCount),
) )
@@ -92,7 +96,7 @@ class CUserSeedDB(CSqlManager):
""" """
try: try:
async with cls.m_pDB.execute( async with cls.getDB().execute(
"SELECT count FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed) "SELECT count FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed)
) as cursor: ) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
@@ -112,7 +116,7 @@ class CUserSeedDB(CSqlManager):
dict: 种子信息 dict: 种子信息
""" """
cursor = await cls.m_pDB.execute( cursor = await cls.getDB().execute(
"SELECT seed, count FROM userSeed WHERE uid=?", (uid,) "SELECT seed, count FROM userSeed WHERE uid=?", (uid,)
) )
rows = await cursor.fetchall() rows = await cursor.fetchall()
@@ -135,7 +139,7 @@ class CUserSeedDB(CSqlManager):
return await cls.deleteUserSeedByName(uid, seed) return await cls.deleteUserSeedByName(uid, seed)
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute( await cls.getDB().execute(
"UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?", "UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?",
(count, uid, seed), (count, uid, seed),
) )
@@ -161,7 +165,7 @@ class CUserSeedDB(CSqlManager):
return await cls.deleteUserSeedByName(uid, seed) return await cls.deleteUserSeedByName(uid, seed)
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute( await cls.getDB().execute(
"UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?", "UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?",
(count, uid, seed), (count, uid, seed),
) )
@@ -183,7 +187,7 @@ class CUserSeedDB(CSqlManager):
""" """
try: try:
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute( await cls.getDB().execute(
"DELETE FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed) "DELETE FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed)
) )
return True return True
@@ -203,7 +207,7 @@ class CUserSeedDB(CSqlManager):
bool: 是否成功 bool: 是否成功
""" """
try: try:
await cls.m_pDB.execute( await cls.getDB().execute(
"DELETE FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed) "DELETE FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed)
) )
return True return True
+26 -23
View File
@@ -5,16 +5,16 @@ import random
from zhenxun.services.log import logger from zhenxun.services.log import logger
from zhenxun.utils._build_image import BuildImage from zhenxun.utils._build_image import BuildImage
from ...utils.config import g_bIsDebug from ...utils import config, getJsonManager, getToolManager
from ...utils.json import g_pJsonManager
from ...utils.tool import g_pToolManager
from ..dbService import g_pDBService
from .database import CSqlManager from .database import CSqlManager
class CUserSignDB(CSqlManager): class CUserSignDB(CSqlManager):
@classmethod def __init__(self):
async def initDB(cls): super().__init__()
self.m_sTableName = "userSign"
async def initDB(self):
# userSignLog 表结构,每条为一次签到事件 # userSignLog 表结构,每条为一次签到事件
userSignLog = { userSignLog = {
"uid": "TEXT NOT NULL", # 用户ID "uid": "TEXT NOT NULL", # 用户ID
@@ -38,8 +38,9 @@ class CUserSignDB(CSqlManager):
"updatedAt": "DATETIME NOT NULL DEFAULT (datetime(CURRENT_TIMESTAMP, 'localtime'))", # 更新时间 # noqa: E501 "updatedAt": "DATETIME NOT NULL DEFAULT (datetime(CURRENT_TIMESTAMP, 'localtime'))", # 更新时间 # noqa: E501
} }
await cls.ensureTableSchema("userSignLog", userSignLog) await self.ensureTableSchema("userSignLog", userSignLog)
await cls.ensureTableSchema("userSignSummary", userSignSummary) await self.ensureTableSchema("userSignSummary", userSignSummary)
self.setInitialized()
@classmethod @classmethod
async def getUserSignRewardByDate(cls, uid: str, date: str) -> tuple[int, int]: async def getUserSignRewardByDate(cls, uid: str, date: str) -> tuple[int, int]:
@@ -54,7 +55,7 @@ class CUserSignDB(CSqlManager):
""" """
try: try:
async with cls._transaction(): async with cls._transaction():
async with cls.m_pDB.execute( async with cls.getDB().execute(
"SELECT exp, point FROM userSignLog WHERE uid=? AND signDate=?", "SELECT exp, point FROM userSignLog WHERE uid=? AND signDate=?",
(uid, date), (uid, date),
) as cursor: ) as cursor:
@@ -85,7 +86,7 @@ class CUserSignDB(CSqlManager):
try: try:
sql = "SELECT COUNT(*) FROM userSignLog WHERE uid=? AND signDate LIKE ?" sql = "SELECT COUNT(*) FROM userSignLog WHERE uid=? AND signDate LIKE ?"
param = f"{monthStr}-%" param = f"{monthStr}-%"
async with cls.m_pDB.execute(sql, (uid, param)) as cursor: async with cls.getDB().execute(sql, (uid, param)) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
return row[0] if row else 0 return row[0] if row else 0
except Exception as e: except Exception as e:
@@ -105,7 +106,7 @@ class CUserSignDB(CSqlManager):
""" """
try: try:
sql = "SELECT 1 FROM userSignLog WHERE uid=? AND signDate=? LIMIT 1" sql = "SELECT 1 FROM userSignLog WHERE uid=? AND signDate=? LIMIT 1"
async with cls.m_pDB.execute(sql, (uid, signDate)) as cursor: async with cls.getDB().execute(sql, (uid, signDate)) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
return row is not None return row is not None
except Exception as e: except Exception as e:
@@ -124,19 +125,21 @@ class CUserSignDB(CSqlManager):
int: 0: 签到失败 1: 签到成功 2: 重复签到 int: 0: 签到失败 1: 签到成功 2: 重复签到
""" """
try: try:
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if not player: if not player:
return 0 return 0
if not signDate: if not signDate:
signDate = g_pToolManager.dateTime().date().today().strftime("%Y-%m-%d") signDate = (
getToolManager().dateTime().date().today().strftime("%Y-%m-%d")
)
if await cls.hasSigned(uid, signDate): if await cls.hasSigned(uid, signDate):
return 2 return 2
todayStr = g_pToolManager.dateTime().date().today().strftime("%Y-%m-%d") todayStr = getToolManager().dateTime().date().today().strftime("%Y-%m-%d")
isSupplement = 0 if signDate == todayStr else 1 isSupplement = 0 if signDate == todayStr else 1
sign = await g_pJsonManager.getSign() sign = await getJsonManager().getSign()
expMax, expMin, pointMax, pointMin = [ expMax, expMin, pointMax, pointMin = [
sign.get(key, default) sign.get(key, default)
@@ -153,12 +156,12 @@ class CUserSignDB(CSqlManager):
vipPoint = 0 vipPoint = 0
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute( await cls.getDB().execute(
"INSERT INTO userSignLog (uid, signDate, isSupplement, exp, point) VALUES (?, ?, ?, ?, ?)", "INSERT INTO userSignLog (uid, signDate, isSupplement, exp, point) VALUES (?, ?, ?, ?, ?)",
(uid, signDate, isSupplement, exp, point), (uid, signDate, isSupplement, exp, point),
) )
cursor = await cls.m_pDB.execute( cursor = await cls.getDB().execute(
"SELECT * FROM userSignSummary WHERE uid=?", (uid,) "SELECT * FROM userSignSummary WHERE uid=?", (uid,)
) )
row = await cursor.fetchone() row = await cursor.fetchone()
@@ -171,7 +174,7 @@ class CUserSignDB(CSqlManager):
else 1 else 1
) )
prevDate = ( prevDate = (
g_pToolManager.dateTime().strptime(signDate, "%Y-%m-%d") getToolManager().dateTime().strptime(signDate, "%Y-%m-%d")
- timedelta(days=1) - timedelta(days=1)
).strftime("%Y-%m-%d") ).strftime("%Y-%m-%d")
continuousDays = ( continuousDays = (
@@ -184,7 +187,7 @@ class CUserSignDB(CSqlManager):
if isSupplement if isSupplement
else row["supplementCount"] else row["supplementCount"]
) )
await cls.m_pDB.execute( await cls.getDB().execute(
""" """
UPDATE userSignSummary UPDATE userSignSummary
SET totalSignDays=totalSignDays+1, SET totalSignDays=totalSignDays+1,
@@ -206,7 +209,7 @@ class CUserSignDB(CSqlManager):
) )
else: else:
monthSignDays = 1 monthSignDays = 1
await cls.m_pDB.execute( await cls.getDB().execute(
""" """
INSERT INTO userSignSummary INSERT INTO userSignSummary
(uid, totalSignDays, currentMonth, monthSignDays, lastSignDate, continuousDays, supplementCount) (uid, totalSignDays, currentMonth, monthSignDays, lastSignDate, continuousDays, supplementCount)
@@ -233,9 +236,9 @@ class CUserSignDB(CSqlManager):
plant = reward.get("plant", {}) plant = reward.get("plant", {})
if plant: if plant:
for key, value in plant.items(): for key, value in plant.items():
await g_pDBService.userSeed.addUserSeedByUid(uid, key, value) await cls.getUserSeedManager().addUserSeedByUid(uid, key, value)
if g_bIsDebug: if config.g_bIsDebug:
exp += 9999 exp += 9999
# 向数据库更新 # 向数据库更新
@@ -268,7 +271,7 @@ class CUserSignDB(CSqlManager):
monthStr = f"{year:04d}-{month:02d}" monthStr = f"{year:04d}-{month:02d}"
try: try:
sql = "SELECT signDate FROM userSignLog WHERE uid=? AND signDate LIKE ?" sql = "SELECT signDate FROM userSignLog WHERE uid=? AND signDate LIKE ?"
async with cls.m_pDB.execute(sql, (uid, f"{monthStr}-%")) as cursor: async with cls.getDB().execute(sql, (uid, f"{monthStr}-%")) as cursor:
rows = await cursor.fetchall() rows = await cursor.fetchall()
signedDays = {int(r[0][-2:]) for r in rows if r[0][-2:].isdigit()} signedDays = {int(r[0][-2:]) for r in rows if r[0][-2:].isdigit()}
except Exception as e: except Exception as e:
+33 -31
View File
@@ -3,15 +3,16 @@ import re
from zhenxun.services.log import logger from zhenxun.services.log import logger
from ...utils.config import g_bIsDebug from ...utils import config, getToolManager
from ...utils.tool import g_pToolManager
from ..dbService import g_pDBService
from .database import CSqlManager from .database import CSqlManager
class CUserSoilDB(CSqlManager): class CUserSoilDB(CSqlManager):
@classmethod def __init__(self):
async def initDB(cls): super().__init__()
self.m_sTableName = "userSoil"
async def initDB(self):
userSoil = { userSoil = {
"uid": "TEXT NOT NULL", "uid": "TEXT NOT NULL",
"soilIndex": "INTEGER NOT NULL", # 地块索引从1开始 "soilIndex": "INTEGER NOT NULL", # 地块索引从1开始
@@ -29,7 +30,8 @@ class CUserSoilDB(CSqlManager):
"PRIMARY KEY": "(uid, soilIndex)", "PRIMARY KEY": "(uid, soilIndex)",
} }
await cls.ensureTableSchema("userSoil", userSoil) await self.ensureTableSchema("userSoil", userSoil)
self.setInitialized()
@classmethod @classmethod
async def nextPhase(cls, uid: str, soilIndex: int): async def nextPhase(cls, uid: str, soilIndex: int):
@@ -38,7 +40,7 @@ class CUserSoilDB(CSqlManager):
Args: Args:
soilIndex (int): 地块索引 从1开始 soilIndex (int): 地块索引 从1开始
""" """
if not g_bIsDebug: if not config.g_bIsDebug:
return return
soilInfo = await cls.getUserSoil(uid, soilIndex) soilInfo = await cls.getUserSoil(uid, soilIndex)
@@ -46,13 +48,15 @@ class CUserSoilDB(CSqlManager):
if not soilInfo: if not soilInfo:
return return
plantInfo = await g_pDBService.plant.getPlantByName(soilInfo["plantName"]) plantInfo = await cls.getPlantManager().getPlantByName(soilInfo["plantName"])
if not plantInfo: if not plantInfo:
return return
currentTime = g_pToolManager.dateTime().now().timestamp() currentTime = getToolManager().dateTime().now().timestamp()
phaseList = await g_pDBService.plant.getPlantPhaseByName(soilInfo["plantName"]) phaseList = await cls.getPlantManager().getPlantPhaseByName(
soilInfo["plantName"]
)
if currentTime >= soilInfo["matureTime"]: if currentTime >= soilInfo["matureTime"]:
return return
@@ -88,11 +92,11 @@ class CUserSoilDB(CSqlManager):
if not plantName: if not plantName:
return return
plantInfo = await g_pDBService.plant.getPlantByName(plantName) plantInfo = await cls.getPlantManager().getPlantByName(plantName)
if not plantInfo: if not plantInfo:
return return
currentTime = int(g_pToolManager.dateTime().now().timestamp()) currentTime = int(getToolManager().dateTime().now().timestamp())
# 如果当前时间已经超过或等于成熟时间,则作物已成熟或可收获 # 如果当前时间已经超过或等于成熟时间,则作物已成熟或可收获
if currentTime >= soilInfo["matureTime"]: if currentTime >= soilInfo["matureTime"]:
return return
@@ -110,7 +114,7 @@ class CUserSoilDB(CSqlManager):
Returns: Returns:
dict: 包含字段名-值的字典; 若无数据则返回空字典 dict: 包含字段名-值的字典; 若无数据则返回空字典
""" """
cursor = await cls.m_pDB.execute("SELECT * FROM soil WHERE uid = ?", (uid,)) cursor = await cls.getDB().execute("SELECT * FROM soil WHERE uid = ?", (uid,))
row = await cursor.fetchone() row = await cursor.fetchone()
if not row: if not row:
@@ -129,7 +133,7 @@ class CUserSoilDB(CSqlManager):
None None
""" """
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute( await cls.getDB().execute(
""" """
INSERT INTO userSoil INSERT INTO userSoil
(uid, soilIndex, plantName, plantTime, matureTime, (uid, soilIndex, plantName, plantTime, matureTime,
@@ -164,7 +168,7 @@ class CUserSoilDB(CSqlManager):
Returns: Returns:
None None
""" """
await cls.m_pDB.execute( await cls.getDB().execute(
""" """
INSERT INTO userSoil INSERT INTO userSoil
(uid, soilIndex, plantName, plantTime, matureTime, (uid, soilIndex, plantName, plantTime, matureTime,
@@ -201,7 +205,7 @@ class CUserSoilDB(CSqlManager):
dict: 记录存在返回字段-值字典,否则返回 None dict: 记录存在返回字段-值字典,否则返回 None
""" """
async with cls._transaction(): async with cls._transaction():
cursor = await cls.m_pDB.execute( cursor = await cls.getDB().execute(
"SELECT * FROM userSoil WHERE uid = ? AND soilIndex = ?", "SELECT * FROM userSoil WHERE uid = ? AND soilIndex = ?",
(uid, soilIndex), (uid, soilIndex),
) )
@@ -222,7 +226,7 @@ class CUserSoilDB(CSqlManager):
Returns: Returns:
dict | None: 记录存在返回字段-值字典,否则返回 None dict | None: 记录存在返回字段-值字典,否则返回 None
""" """
cursor = await cls.m_pDB.execute( cursor = await cls.getDB().execute(
"SELECT * FROM userSoil WHERE uid = ? AND soilIndex = ?", "SELECT * FROM userSoil WHERE uid = ? AND soilIndex = ?",
(uid, soilIndex), (uid, soilIndex),
) )
@@ -244,7 +248,7 @@ class CUserSoilDB(CSqlManager):
int: 符合条件的土地数量 int: 符合条件的土地数量
""" """
async with cls._transaction(): async with cls._transaction():
cursor = await cls.m_pDB.execute( cursor = await cls.getDB().execute(
"SELECT COUNT(*) FROM userSoil WHERE uid = ? AND soilLevel = ?", "SELECT COUNT(*) FROM userSoil WHERE uid = ? AND soilLevel = ?",
(uid, soilLevel), (uid, soilLevel),
) )
@@ -265,7 +269,7 @@ class CUserSoilDB(CSqlManager):
None None
""" """
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute( await cls.getDB().execute(
f"UPDATE userSoil SET {field} = ? WHERE uid = ? AND soilIndex = ?", f"UPDATE userSoil SET {field} = ? WHERE uid = ? AND soilIndex = ?",
(value, uid, soilIndex), (value, uid, soilIndex),
) )
@@ -283,7 +287,7 @@ class CUserSoilDB(CSqlManager):
Returns: Returns:
None None
""" """
await cls.m_pDB.execute( await cls.getDB().execute(
f"UPDATE userSoil SET {field} = ? WHERE uid = ? AND soilIndex = ?", f"UPDATE userSoil SET {field} = ? WHERE uid = ? AND soilIndex = ?",
(value, uid, soilIndex), (value, uid, soilIndex),
) )
@@ -331,7 +335,7 @@ class CUserSoilDB(CSqlManager):
try: try:
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute(sql, tuple(values)) await cls.getDB().execute(sql, tuple(values))
return True return True
except Exception as e: except Exception as e:
logger.error(f"批量更新土地字段失败: {e}") logger.error(f"批量更新土地字段失败: {e}")
@@ -349,7 +353,7 @@ class CUserSoilDB(CSqlManager):
None None
""" """
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute( await cls.getDB().execute(
"DELETE FROM userSoil WHERE uid = ? AND soilIndex = ?", (uid, soilIndex) "DELETE FROM userSoil WHERE uid = ? AND soilIndex = ?", (uid, soilIndex)
) )
@@ -364,7 +368,7 @@ class CUserSoilDB(CSqlManager):
Returns: Returns:
None None
""" """
await cls.m_pDB.execute( await cls.getDB().execute(
"DELETE FROM userSoil WHERE uid = ? AND soilIndex = ?", (uid, soilIndex) "DELETE FROM userSoil WHERE uid = ? AND soilIndex = ?", (uid, soilIndex)
) )
@@ -386,12 +390,12 @@ class CUserSoilDB(CSqlManager):
return False return False
# 获取植物配置""" """ # 获取植物配置""" """
plantCfg = await g_pDBService.plant.getPlantByName(plantName) plantCfg = await cls.getPlantManager().getPlantByName(plantName)
if not plantCfg: if not plantCfg:
logger.error(f"未知植物: {plantName}") logger.error(f"未知植物: {plantName}")
return False return False
nowTs = int(g_pToolManager.dateTime().now().timestamp()) nowTs = int(getToolManager().dateTime().now().timestamp())
time = int(plantCfg.get("time", 0)) time = int(plantCfg.get("time", 0))
percent = await cls.getSoilLevelTime(soilInfo.get("soilLevel", 0)) percent = await cls.getSoilLevelTime(soilInfo.get("soilLevel", 0))
@@ -413,11 +417,9 @@ class CUserSoilDB(CSqlManager):
base_name = plantName[len(m.group(0)) :] base_name = plantName[len(m.group(0)) :]
# 只有当存在一星升级配置时才尝试按收获次数升级 # 只有当存在一星升级配置时才尝试按收获次数升级
if await g_pDBService.plant.existsPlant("一星" + base_name): if await cls.getPlantManager().existsPlant("一星" + base_name):
harvestCounts = ( harvestCounts = await cls.getUserPlantCountManager().getUserPlantCountByPlantName(
await g_pDBService.userPlantCount.getUserPlantCountByPlantName( uid, base_name
uid, base_name
)
) )
# 根据阈值设定最高星级(避免重复拼接) # 根据阈值设定最高星级(避免重复拼接)
prefix = "" prefix = ""
@@ -455,7 +457,7 @@ class CUserSoilDB(CSqlManager):
@classmethod @classmethod
async def getUserSoilStatus(cls, uid: str, soilIndex: int) -> str: async def getUserSoilStatus(cls, uid: str, soilIndex: int) -> str:
status = [] status = []
soilInfo = await g_pDBService.userSoil.getUserSoil(uid, soilIndex) soilInfo = await cls.getUserSoilManager().getUserSoil(uid, soilIndex)
if not soilInfo: if not soilInfo:
return "" return ""
+15 -11
View File
@@ -4,8 +4,11 @@ from .database import CSqlManager
class CUserStealDB(CSqlManager): class CUserStealDB(CSqlManager):
@classmethod def __init__(self):
async def initDB(cls): super().__init__()
self.m_sTableName = "userSteal"
async def initDB(self):
userSteal = { userSteal = {
"uid": "TEXT NOT NULL", # 被偷用户Uid "uid": "TEXT NOT NULL", # 被偷用户Uid
"soilIndex": "INTEGER NOT NULL", # 被偷的地块索引 从1开始 "soilIndex": "INTEGER NOT NULL", # 被偷的地块索引 从1开始
@@ -14,7 +17,8 @@ class CUserStealDB(CSqlManager):
"stealTime": "INTEGER NOT NULL", # 被偷时间 "stealTime": "INTEGER NOT NULL", # 被偷时间
"PRIMARY KEY": "(uid, soilIndex, stealerUid)", "PRIMARY KEY": "(uid, soilIndex, stealerUid)",
} }
await cls.ensureTableSchema("userSteal", userSteal) await self.ensureTableSchema("userSteal", userSteal)
self.setInitialized()
@classmethod @classmethod
async def addStealRecord( async def addStealRecord(
@@ -34,7 +38,7 @@ class CUserStealDB(CSqlManager):
""" """
try: try:
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute( await cls.getDB().execute(
'INSERT INTO "userSteal"(uid, soilIndex, stealerUid, stealCount, stealTime) VALUES(?, ?, ?, ?, ?);', 'INSERT INTO "userSteal"(uid, soilIndex, stealerUid, stealCount, stealTime) VALUES(?, ?, ?, ?, ?);',
(uid, soilIndex, stealerUid, stealCount, stealTime), (uid, soilIndex, stealerUid, stealCount, stealTime),
) )
@@ -55,7 +59,7 @@ class CUserStealDB(CSqlManager):
""" """
try: try:
async with cls._transaction(): async with cls._transaction():
cursor = await cls.m_pDB.execute( cursor = await cls.getDB().execute(
'SELECT soilIndex, stealerUid, stealCount, stealTime FROM "userSteal" WHERE uid=?;', 'SELECT soilIndex, stealerUid, stealCount, stealTime FROM "userSteal" WHERE uid=?;',
(uid,), (uid,),
) )
@@ -83,7 +87,7 @@ class CUserStealDB(CSqlManager):
""" """
try: try:
async with cls._transaction(): async with cls._transaction():
cursor = await cls.m_pDB.execute( cursor = await cls.getDB().execute(
'SELECT stealerUid, stealCount, stealTime FROM "userSteal" WHERE uid=? AND soilIndex=?;', 'SELECT stealerUid, stealCount, stealTime FROM "userSteal" WHERE uid=? AND soilIndex=?;',
(uid, soilIndex), (uid, soilIndex),
) )
@@ -115,7 +119,7 @@ class CUserStealDB(CSqlManager):
""" """
try: try:
async with cls._transaction(): async with cls._transaction():
cursor = await cls.m_pDB.execute( cursor = await cls.getDB().execute(
'SELECT SUM(stealCount) FROM "userSteal" WHERE uid=? AND soilIndex=?;', 'SELECT SUM(stealCount) FROM "userSteal" WHERE uid=? AND soilIndex=?;',
(uid, soilIndex), (uid, soilIndex),
) )
@@ -138,7 +142,7 @@ class CUserStealDB(CSqlManager):
""" """
try: try:
async with cls._transaction(): async with cls._transaction():
cursor = await cls.m_pDB.execute( cursor = await cls.getDB().execute(
'SELECT COUNT(DISTINCT stealerUid) FROM "userSteal" WHERE uid=? AND soilIndex=?;', 'SELECT COUNT(DISTINCT stealerUid) FROM "userSteal" WHERE uid=? AND soilIndex=?;',
(uid, soilIndex), (uid, soilIndex),
) )
@@ -162,7 +166,7 @@ class CUserStealDB(CSqlManager):
""" """
try: try:
async with cls._transaction(): async with cls._transaction():
cursor = await cls.m_pDB.execute( cursor = await cls.getDB().execute(
'SELECT 1 FROM "userSteal" WHERE uid=? AND soilIndex=? AND stealerUid=? LIMIT 1;', 'SELECT 1 FROM "userSteal" WHERE uid=? AND soilIndex=? AND stealerUid=? LIMIT 1;',
(uid, soilIndex, stealerUid), (uid, soilIndex, stealerUid),
) )
@@ -190,7 +194,7 @@ class CUserStealDB(CSqlManager):
""" """
try: try:
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute( await cls.getDB().execute(
'UPDATE "userSteal" SET stealCount=?, stealTime=? WHERE uid=? AND soilIndex=? AND stealerUid=?;', 'UPDATE "userSteal" SET stealCount=?, stealTime=? WHERE uid=? AND soilIndex=? AND stealerUid=?;',
(stealCount, stealTime, uid, soilIndex, stealerUid), (stealCount, stealTime, uid, soilIndex, stealerUid),
) )
@@ -212,7 +216,7 @@ class CUserStealDB(CSqlManager):
""" """
try: try:
async with cls._transaction(): async with cls._transaction():
await cls.m_pDB.execute( await cls.getDB().execute(
'DELETE FROM "userSteal" WHERE uid=? AND soilIndex=?;', 'DELETE FROM "userSteal" WHERE uid=? AND soilIndex=?;',
(uid, soilIndex), (uid, soilIndex),
) )
+102 -31
View File
@@ -1,44 +1,115 @@
import asyncio
from typing import Any
from zhenxun.services.log import logger
from .database import (
CPlantManager,
CUserDB,
CUserItemDB,
CUserPlantCountDB,
CUserPlantDB,
CUserSeedDB,
CUserSignDB,
CUserSoilDB,
CUserStealDB,
g_pDBlocator,
)
class CDBService: class CDBService:
"""
数据库服务管理器
负责初始化和协调所有数据库服务
"""
def __init__(self):
self.m_manager: dict[str, Any] = {}
self.m_bInitialized = False
async def init(self): async def init(self):
from .database.plant import CPlantManager if self.m_bInitialized:
from .database.user import CUserDB logger.warning("真寻农场数据库服务已初始化")
from .database.userItem import CUserItemDB return
from .database.userPlant import CUserPlantDB
from .database.userPlantCount import CUserPlantCountDB
from .database.userSeed import CUserSeedDB
from .database.userSign import CUserSignDB
from .database.userSoil import CUserSoilDB
from .database.userSteal import CUserStealDB
self.plant = CPlantManager() m_manager = {
await self.plant.init() "plant": CPlantManager(),
"user": CUserDB(),
"userSoil": CUserSoilDB(),
"userPlant": CUserPlantDB(),
"userSeed": CUserSeedDB(),
"userItem": CUserItemDB(),
"userSteal": CUserStealDB(),
"userSign": CUserSignDB(),
"userPlantCount": CUserPlantCountDB(),
}
self.user = CUserDB() for name, manager in m_manager.items():
await self.user.initDB() g_pDBlocator.register(name, manager)
self.m_manager[name] = manager
self.userSoil = CUserSoilDB() tasks = []
await self.userSoil.initDB() for name, manager in self.m_manager.items():
tasks.append(manager.init())
tasks.append(manager.initDB())
self.userPlant = CUserPlantDB() await asyncio.gather(*tasks)
await self.userPlant.initDB()
self.userSeed = CUserSeedDB() g_pDBlocator.markInitialized()
await self.userSeed.initDB() self.m_bInitialized = True
self.userItem = CUserItemDB() logger.debug("真寻农场数据库服务初始化完成")
await self.userItem.initDB()
self.userSteal = CUserStealDB()
await self.userSteal.initDB()
self.userSign = CUserSignDB()
await self.userSign.initDB()
self.userPlantCount = CUserPlantCountDB()
await self.userPlantCount.initDB()
async def cleanup(self): async def cleanup(self):
await self.plant.cleanup() task = []
for manager in self.m_manager.values():
if hasattr(manager, "cleanup"):
task.append(manager.cleanup())
await asyncio.gather(*task)
self.m_manager.clear()
self.m_bInitialized = False
@property
def plant(self):
return self.m_manager["plant"]
@property
def user(self):
return self.m_manager["user"]
@property
def userSoil(self):
return self.m_manager["userSoil"]
@property
def userPlant(self):
return self.m_manager["userPlant"]
@property
def userSeed(self):
return self.m_manager["userSeed"]
@property
def userItem(self):
return self.m_manager["userItem"]
@property
def userSteal(self):
return self.m_manager["userSteal"]
@property
def userSign(self):
return self.m_manager["userSign"]
@property
def userPlantCount(self):
return self.m_manager["userPlantCount"]
@property
def initialized(self) -> bool:
return self.m_bInitialized
g_pDBService = CDBService() g_pDBService = CDBService()
+85 -440
View File
@@ -5,16 +5,12 @@ import re
from zhenxun.configs.config import Config from zhenxun.configs.config import Config
from zhenxun.models.user_console import UserConsole from zhenxun.models.user_console import UserConsole
from zhenxun.services.log import logger from zhenxun.services.log import logger
from zhenxun.utils._build_image import BuildImage
from zhenxun.utils.enum import GoldHandle from zhenxun.utils.enum import GoldHandle
from zhenxun.utils.image_utils import ImageTemplate from zhenxun.utils.image_utils import ImageTemplate
from zhenxun.utils.platform import PlatformUtils
from ..core.dbService import g_pDBService from ..core.dbService import g_pDBService
from ..event.event import g_pEventManager from ..event import g_pEventManager
from ..utils.config import g_bIsDebug, g_iSoilLevelMax, g_sResourcePath, g_sTranslation from ..utils import config, getJsonManager, getToolManager
from ..utils.json import g_pJsonManager
from ..utils.tool import g_pToolManager
class CFarmManager: class CFarmManager:
@@ -50,372 +46,14 @@ class CFarmManager:
) )
point = num * pro point = num * pro
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if not player: if not player:
return g_sTranslation["basic"]["error"] return config.g_sTranslation["basic"]["error"]
await player.addPoint("point", int(point)) await player.addPoint("point", int(point))
return f"充值{point}农场币成功,手续费{tax}金币,当前农场币:{player.user.get('point', 0)}" return f"充值{point}农场币成功,手续费{tax}金币,当前农场币:{player.user.get('point', 0)}"
@classmethod
async def drawFarmByUid(cls, uid: str) -> bytes:
"""绘制用户农场
Args:
uid (str): 用户UID
Returns:
bytes: 返回绘制结果
"""
img = BuildImage(background=g_sResourcePath / "background/background.jpg")
soil = await g_pJsonManager.getSoil()
soilSize = soil["size"]
soilPos = soil["soil"]
grass = BuildImage(background=g_sResourcePath / "soil/草土地.png")
await grass.resize(0, soilSize[0], soilSize[1])
player = await g_pToolManager.getPlayerByUid(uid)
if not player:
return img.pic2bytes()
soilUnlock = int(player.user.get("soil", 3))
x = 0
y = 0
isFirstExpansion = True # 首次添加扩建图片
isFirstRipe = True
plant = None
for index in range(0, 30):
x = soilPos[str(index + 1)]["x"]
y = soilPos[str(index + 1)]["y"]
# 如果土地已经到达对应等级
if index < soilUnlock:
soilUrl = ""
# TODO 缺少判断用户土地资源状况
soilInfo = await g_pDBService.userSoil.getUserSoil(uid, index + 1)
if not soilInfo:
soilUrl = "soil/普通土地.png"
else:
soilLevel = soilInfo.get("soilLevel", 0)
if soilLevel == 1:
soilUrl = "soil/红土地.png"
elif soilLevel == 2:
soilUrl = "soil/黑土地.png"
elif soilLevel == 3:
soilUrl = "soil/金土地.png"
else:
soilUrl = "soil/普通土地.png"
soil = BuildImage(background=g_sResourcePath / soilUrl)
await soil.resize(0, soilSize[0], soilSize[1])
await img.paste(soil, (x, y))
isPlant, plant, isRipe, offsetX, offsetY = await cls.drawSoilPlant(
uid, index + 1
)
if isPlant:
await img.paste(
plant,
(
x + soilSize[0] // 2 - plant.width // 2 + offsetX,
y + soilSize[1] // 2 - plant.height // 2 + offsetY,
),
)
# 1700 275
# 首次添加可收获图片
if isRipe and isFirstRipe:
ripe = BuildImage(
background=g_sResourcePath / "background/ripe.png"
)
await img.paste(
ripe,
(x + soilSize[0] // 2 - ripe.width // 2, y - ripe.height // 2),
)
isFirstRipe = False
else:
await img.paste(grass, (x, y))
if isFirstExpansion:
isFirstExpansion = False
# 首次添加扩建图片
expansion = BuildImage(
background=g_sResourcePath / "background/expansion.png"
)
await expansion.resize(0, 69, 69)
await img.paste(
expansion,
(
x + soilSize[0] // 2 - expansion.width // 2,
y + soilSize[1] // 2 - expansion.height,
),
)
# 左上角绘制用户信息
# 头像
image = await PlatformUtils.get_user_avatar(uid, "qq")
if image:
avatar = BuildImage(background=image)
await avatar.resize(0, 140, 150)
await img.paste(avatar, (125, 85))
# 头像框
frame = BuildImage(background=g_sResourcePath / "background/frame.png")
await img.paste(frame, (75, 44))
# 用户名
nameImg = await BuildImage.build_text_image(
player.user["name"], size=24, font_color=(77, 35, 4)
)
await img.paste(nameImg, (300, 92))
# 经验值
level = await player.getUserLevel()
beginX = 309
endX = 627
# 绘制宽度计算公式为 (当前经验值 / 经验值上限) * 宽度
width = int((level[2] / level[1]) * (endX - beginX))
await img.rectangle((beginX, 188, beginX + width, 222), (171, 194, 41))
expImg = await BuildImage.build_text_image(
f"{level[2]} / {level[1]}", size=24, font_color=(102, 120, 19)
)
await img.paste(expImg, (390, 193))
# 等级
levelImg = await BuildImage.build_text_image(
str(level[0]), size=32, font_color=(214, 111, 1)
)
await img.paste(levelImg, (660, 187))
# 金币
pointImg = await BuildImage.build_text_image(
str(player.user["point"]), size=24, font_color=(253, 253, 253)
)
await img.paste(pointImg, (330, 255))
# 点券 TODO
bondsImg = await BuildImage.build_text_image(
"0", size=24, font_color=(253, 253, 253)
)
await img.paste(bondsImg, (570, 255))
# 清晰度
definition = Config.get_config("zhenxun_plugin_farm", "绘制农场清晰度")
if definition == "medium":
await img.resize(0.6)
elif definition == "hight":
await img.resize(0.8)
elif definition == "original":
pass
else:
await img.resize(0.4)
return img.pic2bytes()
@classmethod
async def drawDetailFarmByUid(cls, uid: str) -> list:
info = []
farm = await cls.drawFarmByUid(uid)
player = await g_pToolManager.getPlayerByUid(uid)
if not player:
return info
info.append(BuildImage.open(farm))
dataList = []
columnName = [
"-",
"土地ID",
"土地等级",
"作物名称",
"成熟时间",
"土地状态",
"被偷数量",
"剩余产出",
]
icon = ""
soilNumber = player.user.get("soil", 3)
for i in range(1, soilNumber + 1):
soilInfo = await g_pDBService.userSoil.getUserSoil(uid, i)
if soilInfo:
match soilInfo.get("soilLevel", 0):
case 1:
name = "红土地.png"
case 2:
name = "黑土地.png"
case 3:
name = "金土地.png"
case _:
name = "普通土地.png"
iconPath = g_sResourcePath / "soil" / name
if iconPath.exists():
icon = (iconPath, 33, 33)
plantName = soilInfo.get("plantName", "-")
if plantName == "-":
matureTime = "-"
soilStatus = "-"
totalNumber = "-"
plantNumber = "-"
else:
matureTime = (
g_pToolManager.dateTime()
.fromtimestamp(int(soilInfo.get("matureTime", 0)))
.strftime("%Y-%m-%d %H:%M:%S")
)
soilStatus = await g_pDBService.userSoil.getUserSoilStatus(uid, i)
totalNumber = await g_pDBService.userSteal.getTotalStolenCount(
uid, i
)
planInfo = await g_pDBService.plant.getPlantByName(plantName)
if not planInfo:
plantNumber = "None"
else:
plantNumber = f"{planInfo['harvest'] - totalNumber}"
dataList.append(
[
icon,
i,
await g_pDBService.userSoil.getSoilLevelText(
soilInfo["soilLevel"]
),
plantName,
matureTime,
soilStatus,
totalNumber,
plantNumber,
]
)
if len(dataList) >= 15:
result = await ImageTemplate.table_page(
"土地详细信息",
"",
columnName,
dataList,
)
info.append(result.copy())
dataList.clear()
if i >= soilNumber:
result = await ImageTemplate.table_page(
"土地详细信息",
"",
columnName,
dataList,
)
info.append(result.copy())
dataList.clear()
return info
@classmethod
async def drawSoilPlant(
cls, uid: str, soilIndex: int
) -> tuple[bool, BuildImage, bool, int, int]:
"""绘制植物资源
Args:
uid (str): 用户Uid
soilIndex (int): 土地索引 从1开始
Returns:
tuple[bool, BuildImage]: [绘制是否成功,资源图片, 是否成熟]
"""
plant = None
soilInfo = await g_pDBService.userSoil.getUserSoil(uid, soilIndex)
if not soilInfo:
return False, None, False, 0, 0 # type: ignore
# 是否枯萎
if int(soilInfo.get("wiltStatus", 0)) == 1:
plant = BuildImage(background=g_sResourcePath / "plant/basic/9.png")
await plant.resize(0, 150, 212)
return True, plant, False, 0, 0
# 获取作物详细信息
plantInfo = await g_pDBService.plant.getPlantByName(soilInfo["plantName"])
if not plantInfo:
logger.error(f"绘制植物资源失败: {soilInfo['plantName']}")
return False, None, False, 0, 0 # type: ignore
offsetX = plantInfo.get("officX", 0)
offsetY = plantInfo.get("officY", 0)
offsetW = plantInfo.get("officW", 0)
offsetH = plantInfo.get("officH", 0)
currentTime = g_pToolManager.dateTime().now().timestamp()
phaseList = await g_pDBService.plant.getPlantPhaseByName(soilInfo["plantName"])
# 如果当前时间大于成熟时间 说明作物成熟
if currentTime >= soilInfo["matureTime"]:
plant = BuildImage(
background=g_sResourcePath
/ f"plant/{soilInfo['plantName']}/{len(phaseList)}.png"
)
return True, plant, True, offsetX, offsetY
else:
# 如果是多阶段作物 且没有成熟 #早期思路 多阶段作物 直接是倒数第二阶段图片
# if soilInfo["harvestCount"] >= 1:
# plant = BuildImage(
# background=g_sResourcePath
# / f"plant/{soilInfo['plantName']}/{plantInfo['phase'] - 1}.png"
# )
# return True, plant, False, offsetX, offsetY
# 如果没有成熟 则根据当前阶段进行绘制
elapsedTime = currentTime - soilInfo["plantTime"]
currentStage = currentStage = sum(
1 for thr in phaseList if elapsedTime >= thr
)
if currentStage <= 0:
if not plantInfo["general"]:
plant = BuildImage(
background=g_sResourcePath
/ f"plant/{soilInfo['plantName']}/0.png"
)
else:
plant = BuildImage(background=g_sResourcePath / "plant/basic/0.png")
await plant.resize(0, 35 + offsetW, 58 + offsetH)
else:
plant = BuildImage(
background=g_sResourcePath
/ f"plant/{soilInfo['plantName']}/{currentStage}.png"
)
return True, plant, False, offsetX, offsetY
@classmethod @classmethod
async def getUserSeedByUid(cls, uid: str) -> bytes: async def getUserSeedByUid(cls, uid: str) -> bytes:
"""获取用户种子仓库""" """获取用户种子仓库"""
@@ -449,7 +87,7 @@ class CFarmManager:
if not plantInfo: if not plantInfo:
continue continue
iconPath = g_sResourcePath / f"plant/{seedName}/icon.png" iconPath = config.g_sResourcePath / f"plant/{seedName}/icon.png"
icon = (iconPath, 33, 33) if iconPath.exists() else "" icon = (iconPath, 33, 33) if iconPath.exists() else ""
sellable = "可以" if plantInfo["sell"] else "不可以" sellable = "可以" if plantInfo["sell"] else "不可以"
@@ -495,16 +133,18 @@ class CFarmManager:
count = 0 # 如果返回 None,则视为没有种子 count = 0 # 如果返回 None,则视为没有种子
if count <= 0: if count <= 0:
return g_sTranslation["sowing"]["noSeed"].format(name=name) return config.g_sTranslation["sowing"]["noSeed"].format(name=name)
# 如果播种数量超过仓库种子数量 # 如果播种数量超过仓库种子数量
if count < num and num != -1: if count < num and num != -1:
return g_sTranslation["sowing"]["noNum"].format(name=name, num=count) return config.g_sTranslation["sowing"]["noNum"].format(
name=name, num=count
)
# 获取用户土地数量 # 获取用户土地数量
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if not player: if not player:
return g_sTranslation["basic"]["error"] return config.g_sTranslation["basic"]["error"]
soilNumber = player.user.get("soil", 3) soilNumber = player.user.get("soil", 3)
# 如果播种数量为 -1,表示播种所有可播种的土地 # 如果播种数量为 -1,表示播种所有可播种的土地
@@ -540,13 +180,17 @@ class CFarmManager:
# 根据播种结果给出反馈 # 根据播种结果给出反馈
if num == 0: if num == 0:
return g_sTranslation["sowing"]["success"].format(name=name, num=count) return config.g_sTranslation["sowing"]["success"].format(
name=name, num=count
)
else: else:
return g_sTranslation["sowing"]["success2"].format(name=name, num=count) return config.g_sTranslation["sowing"]["success2"].format(
name=name, num=count
)
except Exception as e: except Exception as e:
logger.warning("播种操作失败!", e=e) logger.warning("播种操作失败!", e=e)
return g_sTranslation["sowing"]["error"] return config.g_sTranslation["sowing"]["error"]
@classmethod @classmethod
async def harvest(cls, uid: str) -> str: async def harvest(cls, uid: str) -> str:
@@ -561,9 +205,9 @@ class CFarmManager:
try: try:
await g_pEventManager.m_beforeHarvest.emit(uid=uid) # type: ignore await g_pEventManager.m_beforeHarvest.emit(uid=uid) # type: ignore
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if not player: if not player:
return g_sTranslation["basic"]["error"] return config.g_sTranslation["basic"]["error"]
soilNumber = player.user.get("soil", 3) soilNumber = player.user.get("soil", 3)
harvestRecords = [] # 收获日志记录 harvestRecords = [] # 收获日志记录
@@ -591,9 +235,11 @@ class CFarmManager:
if not plantInfo: if not plantInfo:
continue continue
currentTime = g_pToolManager.dateTime().now() currentTime = getToolManager().dateTime().now()
matureTime = g_pToolManager.dateTime().fromtimestamp( matureTime = (
int(soilInfo["matureTime"]) getToolManager()
.dateTime()
.fromtimestamp(int(soilInfo["matureTime"]))
) )
if currentTime >= matureTime: if currentTime >= matureTime:
@@ -620,7 +266,7 @@ class CFarmManager:
experience = math.floor(experience * (100 + percent) // 100) experience = math.floor(experience * (100 + percent) // 100)
harvestRecords.append( harvestRecords.append(
g_sTranslation["harvest"]["append"].format( config.g_sTranslation["harvest"]["append"].format(
name=soilInfo["plantName"], name=soilInfo["plantName"],
num=number, num=number,
exp=plantInfo["experience"], exp=plantInfo["experience"],
@@ -680,19 +326,19 @@ class CFarmManager:
exp = player.user.get("exp", 0) exp = player.user.get("exp", 0)
await player.addExp(exp + experience) await player.addExp(exp + experience)
harvestRecords.append( harvestRecords.append(
g_sTranslation["harvest"]["exp"].format( config.g_sTranslation["harvest"]["exp"].format(
exp=experience, exp=experience,
) )
) )
if harvestCount <= 0: if harvestCount <= 0:
return g_sTranslation["harvest"]["no"] return config.g_sTranslation["harvest"]["no"]
else: else:
return "\n".join(harvestRecords) return "\n".join(harvestRecords)
except Exception as e: except Exception as e:
logger.warning("收获操作失败!", e=e) logger.warning("收获操作失败!", e=e)
return g_sTranslation["harvest"]["error"] return config.g_sTranslation["harvest"]["error"]
@classmethod @classmethod
async def eradicate(cls, uid: str) -> str: async def eradicate(cls, uid: str) -> str:
@@ -704,9 +350,9 @@ class CFarmManager:
Returns: Returns:
str: 返回 str: 返回
""" """
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if not player: if not player:
return g_sTranslation["basic"]["error"] return config.g_sTranslation["basic"]["error"]
soilNumber = player.user.get("soil", 3) soilNumber = player.user.get("soil", 3)
await g_pEventManager.m_beforeEradicate.emit(uid=uid) # type: ignore await g_pEventManager.m_beforeEradicate.emit(uid=uid) # type: ignore
@@ -727,7 +373,7 @@ class CFarmManager:
experience += 3 experience += 3
if g_bIsDebug: if config.g_bIsDebug:
experience += 999 experience += 999
# 更新数据库操作 # 更新数据库操作
@@ -754,9 +400,9 @@ class CFarmManager:
exp = player.user.get("exp", 0) exp = player.user.get("exp", 0)
await player.addExp(exp + experience) await player.addExp(exp + experience)
return g_sTranslation["eradicate"]["success"].format(exp=experience) return config.g_sTranslation["eradicate"]["success"].format(exp=experience)
else: else:
return g_sTranslation["eradicate"]["error"] return config.g_sTranslation["eradicate"]["error"]
@classmethod @classmethod
async def getUserPlantByUid(cls, uid: str) -> bytes: async def getUserPlantByUid(cls, uid: str) -> bytes:
@@ -797,7 +443,7 @@ class CFarmManager:
continue continue
icon = "" icon = ""
icon_path = g_sResourcePath / f"plant/{name}/icon.png" icon_path = config.g_sResourcePath / f"plant/{name}/icon.png"
if icon_path.exists(): if icon_path.exists():
icon = (icon_path, 33, 33) icon = (icon_path, 33, 33)
@@ -841,16 +487,18 @@ class CFarmManager:
""" """
# 先判断该用户仓库是否有该作物 # 先判断该用户仓库是否有该作物
if not await g_pDBService.userPlant.checkUserPlantByName(uid, name): if not await g_pDBService.userPlant.checkUserPlantByName(uid, name):
return g_sTranslation["lockPlant"]["noPlant"] return config.g_sTranslation["lockPlant"]["noPlant"]
# 更改加锁状态 # 更改加锁状态
if await g_pDBService.userPlant.lockUserPlantByName(uid, name, lock): if await g_pDBService.userPlant.lockUserPlantByName(uid, name, lock):
if lock == 0: if lock == 0:
return g_sTranslation["lockPlant"]["unlockPlant"].format(name=name) return config.g_sTranslation["lockPlant"]["unlockPlant"].format(
name=name
)
else: else:
return g_sTranslation["lockPlant"]["lockPlant"].format(name=name) return config.g_sTranslation["lockPlant"]["lockPlant"].format(name=name)
else: else:
return g_sTranslation["lockPlant"]["error"] return config.g_sTranslation["lockPlant"]["error"]
@classmethod @classmethod
async def stealing(cls, uid: str, target: str) -> str: async def stealing(cls, uid: str, target: str) -> str:
@@ -864,25 +512,25 @@ class CFarmManager:
str: 返回 str: 返回
""" """
# 用户信息 # 用户信息
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if not player: if not player:
return g_sTranslation["basic"]["error"] return config.g_sTranslation["basic"]["error"]
stealTime = player.user.get("stealTime", "") stealTime = player.user.get("stealTime", "")
stealCount = int(player.user["stealCount"]) stealCount = int(player.user["stealCount"])
if stealTime == "" or not stealTime: if stealTime == "" or not stealTime:
stealTime = g_pToolManager.dateTime().date().today().strftime("%Y-%m-%d") stealTime = getToolManager().dateTime().date().today().strftime("%Y-%m-%d")
stealCount = 5 stealCount = 5
elif ( elif (
g_pToolManager.dateTime().date().fromisoformat(stealTime) getToolManager().dateTime().date().fromisoformat(stealTime)
!= g_pToolManager.dateTime().date().today() != getToolManager().dateTime().date().today()
): ):
stealTime = g_pToolManager.dateTime().date().today().strftime("%Y-%m-%d") stealTime = getToolManager().dateTime().date().today().strftime("%Y-%m-%d")
stealCount = 5 stealCount = 5
if stealCount <= 0: if stealCount <= 0:
return g_sTranslation["stealing"]["max"] return config.g_sTranslation["stealing"]["max"]
# 获取用户解锁地块数量 # 获取用户解锁地块数量
soilNumber = player.user.get("soil", 3) soilNumber = player.user.get("soil", 3)
@@ -908,9 +556,9 @@ class CFarmManager:
if not plantInfo: if not plantInfo:
continue continue
currentTime = g_pToolManager.dateTime().now() currentTime = getToolManager().dateTime().now()
matureTime = g_pToolManager.dateTime().fromtimestamp( matureTime = (
int(soilInfo["matureTime"]) getToolManager().dateTime().fromtimestamp(int(soilInfo["matureTime"]))
) )
if currentTime >= matureTime: if currentTime >= matureTime:
@@ -931,7 +579,7 @@ class CFarmManager:
) )
harvestRecords.append( harvestRecords.append(
g_sTranslation["stealing"]["info"].format( config.g_sTranslation["stealing"]["info"].format(
name=soilInfo["plantName"], num=randomNumber name=soilInfo["plantName"], num=randomNumber
) )
) )
@@ -971,7 +619,7 @@ class CFarmManager:
i, i,
uid, uid,
randomNumber, randomNumber,
int(g_pToolManager.dateTime().now().timestamp()), int(getToolManager().dateTime().now().timestamp()),
) )
else: else:
@@ -980,13 +628,13 @@ class CFarmManager:
i, i,
uid, uid,
randomNumber, randomNumber,
int(g_pToolManager.dateTime().now().timestamp()), int(getToolManager().dateTime().now().timestamp()),
) )
if isStealingPlant <= 0 and isStealingNumber <= 0: if isStealingPlant <= 0 and isStealingNumber <= 0:
return g_sTranslation["stealing"]["noPlant"] return config.g_sTranslation["stealing"]["noPlant"]
elif isStealingPlant <= 0 and isStealingNumber > 0: elif isStealingPlant <= 0 and isStealingNumber > 0:
return g_sTranslation["stealing"]["repeat"] return config.g_sTranslation["stealing"]["repeat"]
else: else:
stealCount -= 1 stealCount -= 1
@@ -1004,15 +652,15 @@ class CFarmManager:
Returns: Returns:
str: 返回条件文本信息 str: 返回条件文本信息
""" """
jLevel = await g_pJsonManager.getLevel() jLevel = await getJsonManager().getLevel()
rec = jLevel["reclamation"] rec = jLevel["reclamation"]
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if not player: if not player:
return g_sTranslation["basic"]["error"] return config.g_sTranslation["basic"]["error"]
try: try:
if player.user["soil"] >= 30: if player.user["soil"] >= 30:
return g_sTranslation["reclamation"]["perfect"] return config.g_sTranslation["reclamation"]["perfect"]
rec = rec[f"{player.user['soil'] + 1}"] rec = rec[f"{player.user['soil'] + 1}"]
@@ -1022,17 +670,17 @@ class CFarmManager:
str = "" str = ""
if len(item) == 0: if len(item) == 0:
str = g_sTranslation["reclamation"]["next"].format( str = config.g_sTranslation["reclamation"]["next"].format(
level=level, num=point level=level, num=point
) )
else: else:
str = g_sTranslation["reclamation"]["next2"].format( str = config.g_sTranslation["reclamation"]["next2"].format(
level=level, num=point, item=item level=level, num=point, item=item
) )
return str return str
except Exception: except Exception:
return g_sTranslation["reclamation"]["error"] return config.g_sTranslation["reclamation"]["error"]
@classmethod @classmethod
async def reclamation(cls, uid: str) -> str: async def reclamation(cls, uid: str) -> str:
@@ -1044,17 +692,17 @@ class CFarmManager:
Returns: Returns:
str: _description_ str: _description_
""" """
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if not player: if not player:
return g_sTranslation["basic"]["error"] return config.g_sTranslation["basic"]["error"]
level = await player.getUserLevel() level = await player.getUserLevel()
jsonLevel = await g_pJsonManager.getLevel() jsonLevel = await getJsonManager().getLevel()
rec = jsonLevel["reclamation"] rec = jsonLevel["reclamation"]
try: try:
if player.user["soil"] >= 30: if player.user["soil"] >= 30:
return g_sTranslation["reclamation"]["perfect"] return config.g_sTranslation["reclamation"]["perfect"]
rec = rec[f"{player.user['soil'] + 1}"] rec = rec[f"{player.user['soil'] + 1}"]
@@ -1063,20 +711,20 @@ class CFarmManager:
# item = rec["item"] # item = rec["item"]
if level[0] < levelFileter: if level[0] < levelFileter:
return g_sTranslation["reclamation"]["nextLevel"].format( return config.g_sTranslation["reclamation"]["nextLevel"].format(
level=level[0], next=levelFileter level=level[0], next=levelFileter
) )
if player.user["point"] < point: if player.user["point"] < point:
return g_sTranslation["reclamation"]["noNum"].format(num=point) return config.g_sTranslation["reclamation"]["noNum"].format(num=point)
# TODO 缺少判断消耗的item # TODO 缺少判断消耗的item
await player.subPoint("point", point) await player.subPoint("point", point)
await player.updateField("soil", player.user["soil"] + 1) await player.updateField("soil", player.user["soil"] + 1)
return g_sTranslation["reclamation"]["success"] return config.g_sTranslation["reclamation"]["success"]
except Exception: except Exception:
return g_sTranslation["reclamation"]["error1"] return config.g_sTranslation["reclamation"]["error1"]
@classmethod @classmethod
async def soilUpgradeCondition(cls, uid: str, soilIndex: int) -> str: async def soilUpgradeCondition(cls, uid: str, soilIndex: int) -> str:
@@ -1092,18 +740,18 @@ class CFarmManager:
soilInfo = await g_pDBService.userSoil.getUserSoil(uid, soilIndex) soilInfo = await g_pDBService.userSoil.getUserSoil(uid, soilIndex)
if not soilInfo: if not soilInfo:
return g_sTranslation["soilInfo"]["error"] return config.g_sTranslation["soilInfo"]["error"]
soilLevel = soilInfo.get("soilLevel", 0) + 1 soilLevel = soilInfo.get("soilLevel", 0) + 1
if soilLevel >= g_iSoilLevelMax: if soilLevel >= config.g_iSoilLevelMax:
return g_sTranslation["soilInfo"]["error1"] return config.g_sTranslation["soilInfo"]["error1"]
# 获取用户当前土地 的下一级土地 数量 # 获取用户当前土地 的下一级土地 数量
countSoil = await g_pDBService.userSoil.countSoilByLevel(uid, soilLevel) countSoil = await g_pDBService.userSoil.countSoilByLevel(uid, soilLevel)
# 获取升级所需 # 获取升级所需
soilLevelText = await g_pDBService.userSoil.getSoilLevel(soilLevel) soilLevelText = await g_pDBService.userSoil.getSoilLevel(soilLevel)
jSoil = await g_pJsonManager.getSoil() jSoil = await getJsonManager().getSoil()
fileter = jSoil["upgrade"][soilLevelText][countSoil] fileter = jSoil["upgrade"][soilLevelText][countSoil]
nextLevel = await g_pDBService.userSoil.getSoilLevelText(soilLevel) nextLevel = await g_pDBService.userSoil.getSoilLevelText(soilLevel)
@@ -1139,22 +787,22 @@ class CFarmManager:
Returns: Returns:
str: str:
""" """
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if not player: if not player:
return g_sTranslation["basic"]["error"] return config.g_sTranslation["basic"]["error"]
soilInfo = await g_pDBService.userSoil.getUserSoil(uid, soilIndex) soilInfo = await g_pDBService.userSoil.getUserSoil(uid, soilIndex)
if not soilInfo: if not soilInfo:
return g_sTranslation["soilInfo"]["error"] return config.g_sTranslation["soilInfo"]["error"]
soilLevel = soilInfo.get("soilLevel", 0) + 1 soilLevel = soilInfo.get("soilLevel", 0) + 1
if soilLevel >= g_iSoilLevelMax: if soilLevel >= config.g_iSoilLevelMax:
return g_sTranslation["soilInfo"]["error1"] return config.g_sTranslation["soilInfo"]["error1"]
countSoil = await g_pDBService.userSoil.countSoilByLevel(uid, soilLevel) countSoil = await g_pDBService.userSoil.countSoilByLevel(uid, soilLevel)
soilLevelText = await g_pDBService.userSoil.getSoilLevel(soilLevel) soilLevelText = await g_pDBService.userSoil.getSoilLevel(soilLevel)
soil = await g_pJsonManager.getSoil() soil = await getJsonManager().getSoil()
fileter = soil["upgrade"][soilLevelText][countSoil] fileter = soil["upgrade"][soilLevelText][countSoil]
getters = { getters = {
@@ -1188,9 +836,9 @@ class CFarmManager:
await player.subPoint("point", fileter.get("point", 0)) await player.subPoint("point", fileter.get("point", 0))
await player.subPoint("vipPoint", fileter.get("vipPoint", 0)) await player.subPoint("vipPoint", fileter.get("vipPoint", 0))
return g_sTranslation["soilInfo"]["success"].format( return config.g_sTranslation["soilInfo"]["success"].format(
name=await g_pDBService.userSoil.getSoilLevelText(soilLevel), name=await g_pDBService.userSoil.getSoilLevelText(soilLevel),
text=g_sTranslation["soilInfo"][soilLevelText], text=config.g_sTranslation["soilInfo"][soilLevelText],
) )
@classmethod @classmethod
@@ -1218,9 +866,9 @@ class CFarmManager:
pro = int(Config.get_config("zhenxun_plugin_farm", "点券兑换倍数")) pro = int(Config.get_config("zhenxun_plugin_farm", "点券兑换倍数"))
pro *= num pro *= num
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if not player: if not player:
return g_sTranslation["basic"]["error"] return config.g_sTranslation["basic"]["error"]
point = player.user.get("point", 0) point = player.user.get("point", 0)
if point < pro: if point < pro:
@@ -1241,6 +889,3 @@ class CFarmManager:
await player.subPoint("point", pro) await player.subPoint("point", pro)
return f"兑换{num}点券成功,当前点券:{number},赠送点券:{giftPoints},当前农场币:{point}" return f"兑换{num}点券成功,当前点券:{number},赠送点券:{giftPoints},当前农场币:{point}"
g_pFarmManager = CFarmManager()
+5 -9
View File
@@ -1,15 +1,14 @@
from zhenxun.configs.path_config import DATA_PATH from zhenxun.configs.path_config import DATA_PATH
from zhenxun.services.log import logger from zhenxun.services.log import logger
from ..utils.config import g_sResourcePath from ..utils import config, getToolManager
from ..utils.tool import g_pToolManager
class CHelpManager: class CHelpManager:
@classmethod @classmethod
async def createHelpImage(cls) -> bool: async def createHelpImage(cls) -> bool:
templatePath = g_sResourcePath / "html/help.html" templatePath = config.g_sResourcePath / "html/help.html"
outputPath = g_sResourcePath / "temp_html/help.html" outputPath = config.g_sResourcePath / "temp_html/help.html"
savePath = DATA_PATH / "farm_res/html/help.png" savePath = DATA_PATH / "farm_res/html/help.png"
context = { context = {
@@ -24,9 +23,9 @@ class CHelpManager:
} }
try: try:
g_pToolManager.renderHtmlToFile(templatePath, context, outputPath) getToolManager().renderHtmlToFile(templatePath, context, outputPath)
bytes = await g_pToolManager.screenshotSave( bytes = await getToolManager().screenshotSave(
str(outputPath), str(savePath), 1500, 2300 str(outputPath), str(savePath), 1500, 2300
) )
except Exception as e: except Exception as e:
@@ -34,6 +33,3 @@ class CHelpManager:
return False return False
return True return True
g_pHelpManager = CHelpManager()
+4
View File
@@ -0,0 +1,4 @@
from .player import CPlayer
from .playerPool import CPlayerPool
__all__ = ["CPlayer", "CPlayerPool"]
+15 -13
View File
@@ -1,4 +1,4 @@
from ..dbService import g_pDBService from .. import g_pDBlocator
class CPlayer: class CPlayer:
@@ -24,7 +24,7 @@ class CPlayer:
if uid == "": if uid == "":
return False return False
self.user = await g_pDBService.user.getUserInfoByUid(uid) self.user = await g_pDBlocator.getUserManager().getUserInfoByUid(uid)
return True return True
@@ -39,7 +39,7 @@ class CPlayer:
if uid == "": if uid == "":
return False return False
return await g_pDBService.user.isRegistered(uid) return await g_pDBlocator.getUserManager().isRegistered(uid)
async def addPoint(self, type: str, index: int) -> bool: async def addPoint(self, type: str, index: int) -> bool:
"""增加货币 """增加货币
@@ -53,7 +53,7 @@ class CPlayer:
""" """
uid = self.user.get("uid", "") uid = self.user.get("uid", "")
if uid == "" or type not in g_pDBService.user.currencies: if uid == "" or type not in g_pDBlocator.getUserManager().currencies:
return False return False
if index == 0: if index == 0:
@@ -64,7 +64,7 @@ class CPlayer:
if nowIndex < 0: if nowIndex < 0:
nowIndex = 0 nowIndex = 0
if await g_pDBService.user.updatePoint(uid, type, nowIndex): if await g_pDBlocator.getUserManager().updatePoint(uid, type, nowIndex):
self.user[type] = nowIndex self.user[type] = nowIndex
return True return True
@@ -82,7 +82,7 @@ class CPlayer:
""" """
uid = self.user.get("uid", "") uid = self.user.get("uid", "")
if uid == "" or type not in g_pDBService.user.currencies: if uid == "" or type not in g_pDBlocator.getUserManager().currencies:
return False return False
if index == 0: if index == 0:
@@ -93,7 +93,7 @@ class CPlayer:
if nowIndex < 0: if nowIndex < 0:
nowIndex = 0 nowIndex = 0
if await g_pDBService.user.updatePoint(uid, type, nowIndex): if await g_pDBlocator.getUserManager().updatePoint(uid, type, nowIndex):
self.user[type] = nowIndex self.user[type] = nowIndex
return True return True
@@ -121,7 +121,7 @@ class CPlayer:
if nowExp < 0: if nowExp < 0:
nowExp = 0 nowExp = 0
if await g_pDBService.user.updateExp(uid, nowExp): if await g_pDBlocator.getUserManager().updateExp(uid, nowExp):
self.user["exp"] = nowExp self.user["exp"] = nowExp
return True return True
@@ -149,7 +149,7 @@ class CPlayer:
if nowExp < 0: if nowExp < 0:
nowExp = 0 nowExp = 0
if await g_pDBService.user.updateExp(uid, nowExp): if await g_pDBlocator.getUserManager().updateExp(uid, nowExp):
self.user["exp"] = nowExp self.user["exp"] = nowExp
return True return True
@@ -169,7 +169,7 @@ class CPlayer:
if uid == "": if uid == "":
return "error" return "error"
return await g_pDBService.user.updateName(uid, name) return await g_pDBlocator.getUserManager().updateName(uid, name)
async def getUserLevel(self) -> tuple[int, int, int]: async def getUserLevel(self) -> tuple[int, int, int]:
"""获取用户等级信息 """获取用户等级信息
@@ -183,7 +183,7 @@ class CPlayer:
if uid == "": if uid == "":
return -1, -1, -1 return -1, -1, -1
return await g_pDBService.user.getUserLevelByUid(uid) return await g_pDBlocator.getUserManager().getUserLevelByUid(uid)
async def updateStealCountByUid( async def updateStealCountByUid(
self, uid: str, stealTime: str, stealCount: int self, uid: str, stealTime: str, stealCount: int
@@ -203,7 +203,9 @@ class CPlayer:
if uid == "": if uid == "":
return False return False
return await g_pDBService.user.updateStealCountByUid(uid, stealTime, stealCount) return await g_pDBlocator.getUserManager().updateStealCountByUid(
uid, stealTime, stealCount
)
async def updateField(self, field: str, value) -> bool: async def updateField(self, field: str, value) -> bool:
"""更新单字段信息 """更新单字段信息
@@ -216,4 +218,4 @@ class CPlayer:
if uid == "": if uid == "":
return False return False
return await g_pDBService.user.updateFieldByUid(uid, field, value) return await g_pDBlocator.getUserManager().updateFieldByUid(uid, field, value)
+32 -30
View File
@@ -2,9 +2,8 @@ import math
from zhenxun.utils.image_utils import ImageTemplate from zhenxun.utils.image_utils import ImageTemplate
from ..core.dbService import g_pDBService from ..utils import config, getToolManager
from ..utils.config import g_sResourcePath, g_sTranslation from . import g_pDBlocator
from ..utils.tool import g_pToolManager
class CShopManager: class CShopManager:
@@ -46,7 +45,7 @@ class CShopManager:
] ]
# 查询所有可购买作物,并根据筛选关键字过滤 # 查询所有可购买作物,并根据筛选关键字过滤
plants = await g_pDBService.plant.listPlants() plants = await g_pDBlocator.getPlantManager().listPlants()
filteredPlants = [] filteredPlants = []
# 如果是点券商店 # 如果是点券商店
@@ -87,7 +86,7 @@ class CShopManager:
for plant in pageItems: for plant in pageItems:
# 图标处理 # 图标处理
icon = "" icon = ""
iconPath = g_sResourcePath / f"plant/{plant['name']}/icon.png" iconPath = config.g_sResourcePath / f"plant/{plant['name']}/icon.png"
if iconPath.exists(): if iconPath.exists():
icon = (iconPath, 33, 33) icon = (iconPath, 33, 33)
@@ -136,17 +135,17 @@ class CShopManager:
str: str:
""" """
if num <= 0: if num <= 0:
return g_sTranslation["buySeed"]["notNum"] return config.g_sTranslation["buySeed"]["notNum"]
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
plantInfo = await g_pDBService.plant.getPlantByName(name) plantInfo = await g_pDBlocator.getPlantManager().getPlantByName(name)
if not plantInfo or not player: if not plantInfo or not player:
return g_sTranslation["buySeed"]["error"] return config.g_sTranslation["buySeed"]["error"]
level = player.user.get("level", 0) level = player.user.get("level", 0)
if level < int(plantInfo["level"]): if level < int(plantInfo["level"]):
return g_sTranslation["buySeed"]["noLevel"] return config.g_sTranslation["buySeed"]["noLevel"]
vipSeed = plantInfo.get("isVip", 0) == 1 vipSeed = plantInfo.get("isVip", 0) == 1
currencyType = "vipPoint" if vipSeed else "point" currencyType = "vipPoint" if vipSeed else "point"
@@ -155,17 +154,19 @@ class CShopManager:
currentCurrency = player.user.get(currencyType, 0) currentCurrency = player.user.get(currencyType, 0)
if currentCurrency < totalCost: if currentCurrency < totalCost:
return g_sTranslation["buySeed"][f"no{'Vip' if vipSeed else ''}Point"] return config.g_sTranslation["buySeed"][
f"no{'Vip' if vipSeed else ''}Point"
]
await player.addPoint(currencyType, currentCurrency - totalCost) await player.subPoint(currencyType, totalCost)
if not await g_pDBService.userSeed.addUserSeedByUid(uid, name, num): if not await g_pDBlocator.getUserSeedManager().addUserSeedByUid(uid, name, num):
return g_sTranslation["buySeed"]["errorSql"] return config.g_sTranslation["buySeed"]["errorSql"]
success_key = "vipSuccess" if vipSeed else "success" success_key = "vipSuccess" if vipSeed else "success"
remaining_currency = currentCurrency - totalCost remaining_currency = currentCurrency - totalCost
return g_sTranslation["buySeed"][success_key].format( return config.g_sTranslation["buySeed"][success_key].format(
name=name, total=totalCost, point=remaining_currency name=name, total=totalCost, point=remaining_currency
) )
@@ -182,9 +183,9 @@ class CShopManager:
if not isinstance(name, str) or name.strip() == "": if not isinstance(name, str) or name.strip() == "":
name = "" name = ""
plant = await g_pDBService.userPlant.getUserPlantByUid(uid) plant = await g_pDBlocator.getUserPlantManager().getUserPlantByUid(uid)
if not plant: if not plant:
return g_sTranslation["sellPlant"]["no"] return config.g_sTranslation["sellPlant"]["no"]
point = 0 point = 0
totalSold = 0 totalSold = 0
@@ -192,27 +193,31 @@ class CShopManager:
if name == "": if name == "":
for plantName, count in plant.items(): for plantName, count in plant.items():
isLock = await g_pDBService.userPlant.checkPlantLockByName( isLock = await g_pDBlocator.getUserPlantManager().checkPlantLockByName(
uid, plantName uid, plantName
) )
if isLock: if isLock:
continue continue
plantInfo = await g_pDBService.plant.getPlantByName(plantName) plantInfo = await g_pDBlocator.getUserPlantManager().getPlantByName(
plantName
)
if not plantInfo: if not plantInfo:
continue continue
point += plantInfo["price"] * count point += plantInfo["price"] * count
await g_pDBService.userPlant.updateUserPlantByName(uid, plantName, 0) await g_pDBlocator.getUserPlantManager().updateUserPlantByName(
uid, plantName, 0
)
else: else:
if name not in plant: if name not in plant:
return g_sTranslation["sellPlant"]["error"].format(name=name) return config.g_sTranslation["sellPlant"]["error"].format(name=name)
available = plant[name] available = plant[name]
sellAmount = available if isAll else min(available, num) sellAmount = available if isAll else min(available, num)
if sellAmount <= 0: if sellAmount <= 0:
return g_sTranslation["sellPlant"]["error1"].format(name=name) return config.g_sTranslation["sellPlant"]["error1"].format(name=name)
await g_pDBService.userPlant.updateUserPlantByName( await g_pDBlocator.getUserPlantManager().updateUserPlantByName(
uid, name, available - sellAmount uid, name, available - sellAmount
) )
totalSold = sellAmount totalSold = sellAmount
@@ -220,7 +225,7 @@ class CShopManager:
if name == "": if name == "":
totalPoint = point totalPoint = point
else: else:
plantInfo = await g_pDBService.plant.getPlantByName(name) plantInfo = await g_pDBlocator.getUserPlantManager().getPlantByName(name)
if not plantInfo: if not plantInfo:
price = 0 price = 0
else: else:
@@ -228,18 +233,15 @@ class CShopManager:
totalPoint = totalSold * price totalPoint = totalSold * price
player = await g_pToolManager.getPlayerByUid(uid) player = await getToolManager().getPlayerByUid(uid)
if not player: if not player:
return g_sTranslation["basic"]["error"] return config.g_sTranslation["basic"]["error"]
currentPoint = player.user.get("point", 0) currentPoint = player.user.get("point", 0)
await player.addPoint("point", currentPoint + totalPoint) await player.addPoint("point", currentPoint + totalPoint)
result = "success1" if name == "" else "success" result = "success1" if name == "" else "success"
return g_sTranslation["sellPlant"][result].format( return config.g_sTranslation["sellPlant"][result].format(
point=totalPoint, num=currentPoint + totalPoint point=totalPoint, num=currentPoint + totalPoint
) )
g_pShopManager = CShopManager()
+3
View File
@@ -0,0 +1,3 @@
from .event import g_pEventManager
__all__ = ["g_pEventManager"]
+37
View File
@@ -0,0 +1,37 @@
def getConfig():
from . import config
return config
def getDrawFarm():
from .darw.drawFarm import CDarwFarm
return CDarwFarm
def getRequestManager():
from .request import CRequestManager
return CRequestManager
def getToolManager():
from .tool import CToolManager
return CToolManager
def getJsonManager():
from .json import g_pJsonManager
return g_pJsonManager
__all__ = [
"getConfig",
"getDrawFarm",
"getJsonManager",
"getRequestManager",
"getToolManager",
]
+3
View File
@@ -0,0 +1,3 @@
from .drawFarm import CDarwFarm
__all__ = ["CDarwFarm"]
+426
View File
@@ -0,0 +1,426 @@
from zhenxun.configs.config import Config
from zhenxun.services.log import logger
from zhenxun.utils._build_image import BuildImage
from zhenxun.utils.image_utils import ImageTemplate
from zhenxun.utils.platform import PlatformUtils
from ...core.dbService import g_pDBService
from .. import config, getJsonManager, getToolManager
class CDarwFarm:
@classmethod
async def drawFarmByUid(cls, uid: str) -> bytes:
"""绘制用户农场
Args:
uid (str): 用户UID
Returns:
bytes: 返回绘制结果
"""
img, soilSize, soilPos, grass = await cls.createBaseCanvas()
player = await getToolManager().getPlayerByUid(uid)
if not player:
return img.pic2bytes()
soilUnlock = int(player.user.get("soil", 3))
isFirstExpansion = True # 首次添加扩建图片
isFirstRipe = True
for index in range(0, 30):
x = soilPos[str(index + 1)]["x"]
y = soilPos[str(index + 1)]["y"]
# 已解锁格子
if index < soilUnlock:
isRipe = await cls.drawUnlockedTile(img, uid, index + 1, x, y, soilSize)
if isRipe and isFirstRipe:
await cls.pasteRipeOnce(img, x, y, soilSize)
isFirstRipe = False
else:
addedExpansion = await cls.drawLockedTile(
img, x, y, soilSize, grass, isFirstExpansion
)
if addedExpansion:
isFirstExpansion = False
await cls.drawUserInfo(img, player, uid)
await cls.applyDefinitionResize(img)
return img.pic2bytes()
@classmethod
async def createBaseCanvas(cls) -> tuple[BuildImage, tuple, dict, BuildImage]:
"""创建基础画布并返回 (img, soilSize, soilPos, grass)
Returns:
tuple: (主画布, 土地尺寸, 土地坐标映射, 草地图)
"""
img = BuildImage(
background=config.g_sResourcePath / "background/background.jpg"
)
soil = await getJsonManager().getSoil()
soilSize = soil["size"]
soilPos = soil["soil"]
grass = BuildImage(background=config.g_sResourcePath / "soil/草土地.png")
await grass.resize(0, soilSize[0], soilSize[1])
return img, soilSize, soilPos, grass
@classmethod
async def drawUnlockedTile(
cls, img: BuildImage, uid: str, soilIndex: int, x: int, y: int, soilSize
) -> bool:
"""绘制已解锁土地格(包含土地贴图与作物),返回该格是否可收获。
Args:
img (BuildImage): 主画布。
uid (str): 用户UID。
soilIndex (int): 土地索引(从1开始)。
x (int), y (int): 贴图位置。
soilSize: 土地贴图尺寸([w,h] 或 (w,h))。
Returns:
bool: 是否有可收获作物(isRipe)。
"""
soilUrl = "soil/普通土地.png"
soilInfo = await g_pDBService.userSoil.getUserSoil(uid, soilIndex)
if soilInfo:
soilLevel = soilInfo.get("soilLevel", 0)
if soilLevel == 1:
soilUrl = "soil/红土地.png"
elif soilLevel == 2:
soilUrl = "soil/黑土地.png"
elif soilLevel == 3:
soilUrl = "soil/金土地.png"
soil = BuildImage(background=config.g_sResourcePath / soilUrl)
await soil.resize(0, soilSize[0], soilSize[1])
await img.paste(soil, (x, y))
isPlant, plant, isRipe, offsetX, offsetY = await cls.drawSoilPlant(
uid, soilIndex
)
if isPlant and plant is not None:
await img.paste(
plant,
(
x + soilSize[0] // 2 - plant.width // 2 + offsetX,
y + soilSize[1] // 2 - plant.height // 2 + offsetY,
),
)
return bool(isRipe)
@classmethod
async def drawLockedTile(
cls,
img: BuildImage,
x: int,
y: int,
soilSize,
grass: BuildImage,
isFirstExpansion: bool,
) -> bool:
"""绘制未解锁格子并在首次出现时绘制扩建图标。
Returns:
bool: 是否在此格绘制了扩建图标(仅首次返回 True)。
"""
await img.paste(grass, (x, y))
if isFirstExpansion:
expansion = BuildImage(
background=config.g_sResourcePath / "background/expansion.png"
)
await expansion.resize(0, 69, 69)
await img.paste(
expansion,
(
x + soilSize[0] // 2 - expansion.width // 2,
y + soilSize[1] // 2 - expansion.height,
),
)
return True
return False
@classmethod
async def pasteRipeOnce(cls, img: BuildImage, x: int, y: int, soilSize):
"""首次发现成熟作物时贴上成熟提示图(ripe)。"""
ripe = BuildImage(background=config.g_sResourcePath / "background/ripe.png")
await img.paste(
ripe,
(x + soilSize[0] // 2 - ripe.width // 2, y - ripe.height // 2),
)
@classmethod
async def drawUserInfo(cls, img: BuildImage, player, uid: str):
"""绘制左上角用户信息(头像、框、昵称、经验、等级、货币等)。
TODO 需要详细的绘制头像框
Args:
img (BuildImage): 主画布。
player: 用户对象(包含 user 字段)。
uid (str): 用户UID。
"""
image = await PlatformUtils.get_user_avatar(uid, "qq")
if image:
avatar = BuildImage(background=image)
await avatar.resize(0, 140, 150)
await img.paste(avatar, (125, 85))
frame = BuildImage(background=config.g_sResourcePath / "background/frame.png")
await img.paste(frame, (75, 44))
nameImg = await BuildImage.build_text_image(
player.user["name"], size=24, font_color=(77, 35, 4)
)
await img.paste(nameImg, (300, 92))
level = await player.getUserLevel()
beginX = 309
endX = 627
width = int((level[2] / level[1]) * (endX - beginX)) if level[1] else 0
await img.rectangle((beginX, 188, beginX + width, 222), (171, 194, 41))
# 经验
expImg = await BuildImage.build_text_image(
f"{level[2]} / {level[1]}", size=24, font_color=(102, 120, 19)
)
await img.paste(expImg, (390, 193))
# 等级
levelImg = await BuildImage.build_text_image(
str(level[0]), size=32, font_color=(214, 111, 1)
)
await img.paste(levelImg, (660, 187))
# 农场币
pointImg = await BuildImage.build_text_image(
str(player.user.get("point", 0)), size=24, font_color=(253, 253, 253)
)
await img.paste(pointImg, (330, 255))
# 点券
bondsImg = await BuildImage.build_text_image(
"0", size=24, font_color=(253, 253, 253)
)
await img.paste(bondsImg, (570, 255))
@classmethod
async def applyDefinitionResize(cls, img: BuildImage):
"""根据配置调整绘制清晰度(original/medium/hight/其他)。"""
definition = Config.get_config("zhenxun_plugin_farm", "绘制农场清晰度")
if definition == "medium":
await img.resize(0.6)
elif definition == "hight":
await img.resize(0.8)
elif definition == "original":
pass
else:
await img.resize(0.4)
@classmethod
async def drawDetailFarmByUid(cls, uid: str) -> list:
"""绘制用户详细信息
Args:
uid (str): 用户Uid
Returns:
list:
"""
info = []
farm = await cls.drawFarmByUid(uid)
player = await getToolManager().getPlayerByUid(uid)
if not player:
return info
info.append(BuildImage.open(farm))
dataList = []
columnName = [
"-",
"土地ID",
"土地等级",
"作物名称",
"成熟时间",
"土地状态",
"被偷数量",
"剩余产出",
]
icon = ""
soilNumber = player.user.get("soil", 3)
for i in range(1, soilNumber + 1):
soilInfo = await g_pDBService.userSoil.getUserSoil(uid, i)
if not soilInfo:
continue
match soilInfo.get("soilLevel", 0):
case 1:
name = "红土地.png"
case 2:
name = "黑土地.png"
case 3:
name = "金土地.png"
case _:
name = "普通土地.png"
iconPath = config.g_sResourcePath / "soil" / name
if iconPath.exists():
icon = (iconPath, 33, 33)
plantName = soilInfo.get("plantName", "-")
if plantName == "-":
matureTime = "-"
soilStatus = "-"
totalNumber = "-"
plantNumber = "-"
else:
matureTime = (
getToolManager()
.dateTime()
.fromtimestamp(int(soilInfo.get("matureTime", 0)))
.strftime("%Y-%m-%d %H:%M:%S")
)
soilStatus = await g_pDBService.userSoil.getUserSoilStatus(uid, i)
totalNumber = await g_pDBService.userSteal.getTotalStolenCount(uid, i)
planInfo = await g_pDBService.plant.getPlantByName(plantName)
if not planInfo:
plantNumber = "None"
else:
plantNumber = f"{planInfo['harvest'] - totalNumber}"
dataList.append(
[
icon,
i,
await g_pDBService.userSoil.getSoilLevelText(soilInfo["soilLevel"]),
plantName,
matureTime,
soilStatus,
totalNumber,
plantNumber,
]
)
if len(dataList) >= 15:
result = await ImageTemplate.table_page(
"土地详细信息",
"",
columnName,
dataList,
)
info.append(result.copy())
dataList.clear()
if i >= soilNumber:
result = await ImageTemplate.table_page(
"土地详细信息",
"",
columnName,
dataList,
)
info.append(result.copy())
dataList.clear()
return info
@classmethod
async def drawSoilPlant(
cls, uid: str, soilIndex: int
) -> tuple[bool, BuildImage, bool, int, int]:
"""绘制植物资源
Args:
uid (str): 用户Uid
soilIndex (int): 土地索引 从1开始
Returns:
tuple[bool, BuildImage]: [绘制是否成功,资源图片, 是否成熟]
"""
plant = None
soilInfo = await g_pDBService.userSoil.getUserSoil(uid, soilIndex)
if not soilInfo:
return False, None, False, 0, 0 # type: ignore
# 是否枯萎
if int(soilInfo.get("wiltStatus", 0)) == 1:
plant = BuildImage(background=config.g_sResourcePath / "plant/basic/9.png")
await plant.resize(0, 150, 212)
return True, plant, False, 0, 0
# 获取作物详细信息
plantInfo = await g_pDBService.plant.getPlantByName(soilInfo["plantName"])
if not plantInfo:
logger.error(f"绘制植物资源失败: {soilInfo['plantName']}")
return False, None, False, 0, 0 # type: ignore
offsetX = plantInfo.get("officX", 0)
offsetY = plantInfo.get("officY", 0)
offsetW = plantInfo.get("officW", 0)
offsetH = plantInfo.get("officH", 0)
currentTime = getToolManager().dateTime().now().timestamp()
phaseList = await g_pDBService.plant.getPlantPhaseByName(soilInfo["plantName"])
# 如果当前时间大于成熟时间 说明作物成熟
if currentTime >= soilInfo["matureTime"]:
plant = BuildImage(
background=config.g_sResourcePath
/ f"plant/{soilInfo['plantName']}/{len(phaseList)}.png"
)
return True, plant, True, offsetX, offsetY
else:
# 如果是多阶段作物 且没有成熟 #早期思路 多阶段作物 直接是倒数第二阶段图片
# if soilInfo["harvestCount"] >= 1:
# plant = BuildImage(
# background=g_sResourcePath
# / f"plant/{soilInfo['plantName']}/{plantInfo['phase'] - 1}.png"
# )
# return True, plant, False, offsetX, offsetY
# 如果没有成熟 则根据当前阶段进行绘制
elapsedTime = currentTime - soilInfo["plantTime"]
currentStage = currentStage = sum(
1 for thr in phaseList if elapsedTime >= thr
)
if currentStage <= 0:
if not plantInfo["general"]:
plant = BuildImage(
background=config.g_sResourcePath
/ f"plant/{soilInfo['plantName']}/0.png"
)
else:
plant = BuildImage(
background=config.g_sResourcePath / "plant/basic/0.png"
)
await plant.resize(0, 35 + offsetW, 58 + offsetH)
else:
plant = BuildImage(
background=config.g_sResourcePath
/ f"plant/{soilInfo['plantName']}/{currentStage}.png"
)
return True, plant, False, offsetX, offsetY
+2 -3
View File
@@ -2,8 +2,7 @@ import json
from zhenxun.services.log import logger from zhenxun.services.log import logger
from . import config from . import config, getRequestManager
from .request import g_pRequestManager
class CJsonManager: class CJsonManager:
@@ -117,7 +116,7 @@ class CJsonManager:
return False return False
async def initSignInFile(self) -> bool: async def initSignInFile(self) -> bool:
if not await g_pRequestManager.initSignInFile(): if not await getRequestManager().initSignInFile():
config.g_bSignStatus = False config.g_bSignStatus = False
return False return False
else: else:
+10 -14
View File
@@ -15,8 +15,7 @@ from zhenxun.configs.config import Config
from zhenxun.services.log import logger from zhenxun.services.log import logger
from ..core.dbService import g_pDBService from ..core.dbService import g_pDBService
from .config import g_sPlantPath, g_sSignInPath from . import config, getToolManager
from .tool import g_pToolManager
class CRequestManager: class CRequestManager:
@@ -162,14 +161,14 @@ class CRequestManager:
@classmethod @classmethod
async def initSignInFile(cls) -> bool: async def initSignInFile(cls) -> bool:
if os.path.exists(g_sSignInPath): if os.path.exists(config.g_sSignInPath):
try: try:
with open(g_sSignInPath, encoding="utf-8") as f: with open(config.g_sSignInPath, encoding="utf-8") as f:
content = f.read() content = f.read()
sign = json.loads(content) sign = json.loads(content)
date = sign.get("date", "") date = sign.get("date", "")
yearMonth = g_pToolManager.dateTime().now().strftime("%Y%m") yearMonth = getToolManager().dateTime().now().strftime("%Y%m")
if date == yearMonth: if date == yearMonth:
logger.debug("真寻农场签到文件检查完毕") logger.debug("真寻农场签到文件检查完毕")
@@ -193,8 +192,8 @@ class CRequestManager:
try: try:
baseUrl = Config.get_config("zhenxun_plugin_farm", "服务地址") baseUrl = Config.get_config("zhenxun_plugin_farm", "服务地址")
url = f"{baseUrl.rstrip('/')}:8998/sign_in" url = f"{baseUrl.rstrip('/')}:8998/sign_in"
path = str(g_sSignInPath.parent.resolve(strict=False)) path = str(config.g_sSignInPath.parent.resolve(strict=False))
yearMonth = g_pToolManager.dateTime().now().strftime("%Y%m") yearMonth = getToolManager().dateTime().now().strftime("%Y%m")
# 下载为 signTemp.json # 下载为 signTemp.json
success = await cls.download( success = await cls.download(
@@ -208,7 +207,7 @@ class CRequestManager:
return False return False
# 重命名为 sign_in.json # 重命名为 sign_in.json
g_pToolManager.renameFile(f"{path}/signTemp.json", "sign_in.json") getToolManager().renameFile(f"{path}/signTemp.json", "sign_in.json")
return True return True
except Exception as e: except Exception as e:
logger.error("下载签到文件失败", e=e) logger.error("下载签到文件失败", e=e)
@@ -221,7 +220,7 @@ class CRequestManager:
Returns: Returns:
bool: 是否为最新版或成功更新 bool: 是否为最新版或成功更新
""" """
versionPath = os.path.join(os.path.dirname(g_sPlantPath), "version.json") versionPath = os.path.join(os.path.dirname(config.g_sPlantPath), "version.json")
try: try:
with open(versionPath, encoding="utf-8") as f: with open(versionPath, encoding="utf-8") as f:
@@ -262,7 +261,7 @@ class CRequestManager:
""" """
baseUrl = Config.get_config("zhenxun_plugin_farm", "服务地址") baseUrl = Config.get_config("zhenxun_plugin_farm", "服务地址")
savePath = os.path.dirname(g_sPlantPath) savePath = os.path.dirname(config.g_sPlantPath)
success = await cls.download( success = await cls.download(
url=f"{baseUrl.rstrip('/')}:8998/file/plant.db", url=f"{baseUrl.rstrip('/')}:8998/file/plant.db",
savePath=savePath, savePath=savePath,
@@ -273,7 +272,7 @@ class CRequestManager:
return False return False
# 重命名为 sign_in.json # 重命名为 sign_in.json
g_pToolManager.renameFile(f"{savePath}/plantTemp.db", "plant.db") getToolManager().renameFile(f"{savePath}/plantTemp.db", "plant.db")
versionPath = os.path.join(savePath, "version.json") versionPath = os.path.join(savePath, "version.json")
try: try:
@@ -288,6 +287,3 @@ class CRequestManager:
await g_pDBService.plant.downloadPlant() await g_pDBService.plant.downloadPlant()
return True return True
g_pRequestManager = CRequestManager()
+1 -5
View File
@@ -9,8 +9,7 @@ from playwright.async_api import async_playwright
from zhenxun.services.log import logger from zhenxun.services.log import logger
from zhenxun.utils.message import MessageUtils from zhenxun.utils.message import MessageUtils
from ..core.player.player import CPlayer from ..core import CPlayer, g_pUserPool
from ..core.player.playerPool import g_pUserPool
class CToolManager: class CToolManager:
@@ -192,6 +191,3 @@ class CToolManager:
# 截图并保存到本地文件 # 截图并保存到本地文件
await page.screenshot(path=save, full_page=True) await page.screenshot(path=save, full_page=True)
await browser.close() await browser.close()
g_pToolManager = CToolManager()