diff --git a/__init__.py b/__init__.py index 2065b6c..7d8c9a7 100644 --- a/__init__.py +++ b/__init__.py @@ -7,17 +7,18 @@ from zhenxun.services.log import logger from zhenxun.utils.message import MessageUtils from .command import diuse_farm, diuse_register, reclamation -from .core.activity.sign_in import g_pSignInManager -from .core.database.database import g_pSqlManager +from .core import ( + CHelpManager, + CShopManager, + g_pDBlocator, + g_pSqlManager, + g_pUserPool, + getFarmManager, + getSignInManager, +) from .core.dbService import g_pDBService -from .core.farm import g_pFarmManager -from .core.help import g_pHelpManager -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 +from .event import g_pEventManager +from .utils import config, getJsonManager, getRequestManager __plugin_meta__ = PluginMetadata( name="真寻农场", @@ -102,9 +103,9 @@ async def start(): await g_pDBService.init() # 检查作物文件是否缺失 or 更新 - await g_pRequestManager.initPlantDBFile() + await getRequestManager().initPlantDBFile() - await g_pHelpManager.createHelpImage() + await CHelpManager.createHelpImage() # todayRewards = [ # { @@ -141,7 +142,7 @@ async def shutdown(): @scheduler.scheduled_job(trigger="cron", hour=4, minute=30, id="signInFile") async def signInFile(): try: - await g_pJsonManager.initSignInFile() - await g_pRequestManager.initPlantDBFile() + await getJsonManager().initSignInFile() + await getRequestManager().initPlantDBFile() except Exception as e: logger.error("农场定时检查出错", e=e) diff --git a/command.py b/command.py index b6c03d2..4e9b523 100644 --- a/command.py +++ b/command.py @@ -24,12 +24,8 @@ from zhenxun.services.log import logger from zhenxun.utils._build_image import BuildImage from zhenxun.utils.message import MessageUtils -from .core.activity.sign_in import g_pSignInManager -from .core.dbService import g_pDBService -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 +from .core import CShopManager, g_pDBlocator, getFarmManager, getSignInManager +from .utils import config, getDrawFarm, getToolManager diuse_register = on_alconna( Alconna("开通农场"), @@ -43,30 +39,30 @@ diuse_register = on_alconna( @diuse_register.handle() async def handle_register(session: Uninfo): 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(): - await MessageUtils.build_message(g_sTranslation["register"]["repeat"]).send( - reply_to=True - ) + await MessageUtils.build_message( + config.g_sTranslation["register"]["repeat"] + ).send(reply_to=True) return try: 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}") msg = ( - g_sTranslation["register"]["success"].format(point=500) + config.g_sTranslation["register"]["success"].format(point=500) if success - else g_sTranslation["register"]["error"] + else config.g_sTranslation["register"]["error"] ) logger.info(f"用户注册 {'成功' if success else '失败'}:{uid}") except Exception as e: - msg = g_sTranslation["register"]["error"] + msg = config.g_sTranslation["register"]["error"] logger.error(f"注册异常 | UID:{uid} | 错误:{e}") await MessageUtils.build_message(msg).send(reply_to=True) @@ -108,12 +104,12 @@ diuse_farm = on_alconna( @diuse_farm.assign("$main") async def _(session: Uninfo): 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() return - image = await g_pFarmManager.drawFarmByUid(uid) + image = await getDrawFarm().drawFarmByUid(uid) await MessageUtils.build_message(image).send(reply_to=True) @@ -128,12 +124,12 @@ diuse_farm.shortcut( @diuse_farm.assign("detail") async def _(session: Uninfo): 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() return - info = await g_pFarmManager.drawDetailFarmByUid(uid) + info = await getDrawFarm().drawDetailFarmByUid(uid) await MessageUtils.alc_forward_msg( [info], session.self_id, BotConfig.self_nickname @@ -151,19 +147,21 @@ diuse_farm.shortcut( @diuse_farm.assign("my-point") async def _(session: Uninfo): 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() return point = player.user["point"] if point < 0: - await MessageUtils.build_message(g_sTranslation["basic"]["notFarm"]).send() + await MessageUtils.build_message( + config.g_sTranslation["basic"]["notFarm"] + ).send() return False await MessageUtils.build_message( - g_sTranslation["basic"]["point"].format(point=point) + config.g_sTranslation["basic"]["point"].format(point=point) ).send(reply_to=True) @@ -178,10 +176,10 @@ diuse_farm.shortcut( @diuse_farm.assign("seed-shop") async def _(session: Uninfo, res: Match[tuple[str, ...]]): 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() return if res.result is inspect._empty: @@ -208,9 +206,9 @@ async def _(session: Uninfo, res: Match[tuple[str, ...]]): page = int(raw[1]) if filterKey is None: - image = await g_pShopManager.getSeedShopImage(page, 0, 0) + image = await CShopManager.getSeedShopImage(page, 0, 0) else: - image = await g_pShopManager.getSeedShopImage(filterKey, page, 0) + image = await CShopManager.getSeedShopImage(filterKey, page, 0) await MessageUtils.build_message(image).send() @@ -228,17 +226,17 @@ async def _( session: Uninfo, name: Match[str], num: Query[int] = AlconnaQuery("num", 1) ): if not name.available: - await MessageUtils.build_message(g_sTranslation["buySeed"]["notSeed"]).finish( - reply_to=True - ) + await MessageUtils.build_message( + config.g_sTranslation["buySeed"]["notSeed"] + ).finish(reply_to=True) 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() 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) @@ -253,12 +251,12 @@ diuse_farm.shortcut( @diuse_farm.assign("my-seed") async def _(session: Uninfo): 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() return - result = await g_pFarmManager.getUserSeedByUid(uid) + result = await getFarmManager().getUserSeedByUid(uid) 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) ): if not name.available: - await MessageUtils.build_message(g_sTranslation["sowing"]["notSeed"]).finish( - reply_to=True - ) + await MessageUtils.build_message( + config.g_sTranslation["sowing"]["notSeed"] + ).finish(reply_to=True) 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() 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) @@ -300,12 +298,12 @@ diuse_farm.shortcut( @diuse_farm.assign("harvest") async def _(session: Uninfo): 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() return - result = await g_pFarmManager.harvest(uid) + result = await getFarmManager().harvest(uid) await MessageUtils.build_message(result).send(reply_to=True) @@ -320,12 +318,12 @@ diuse_farm.shortcut( @diuse_farm.assign("eradicate") async def _(session: Uninfo): 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() return - result = await g_pFarmManager.eradicate(uid) + result = await getFarmManager().eradicate(uid) await MessageUtils.build_message(result).send(reply_to=True) @@ -340,12 +338,12 @@ diuse_farm.shortcut( @diuse_farm.assign("my-plant") async def _(session: Uninfo): 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() return - result = await g_pFarmManager.getUserPlantByUid(uid) + result = await getFarmManager().getUserPlantByUid(uid) await MessageUtils.build_message(result).send(reply_to=True) @@ -360,12 +358,12 @@ diuse_farm.shortcut( @diuse_farm.assign("lock-plant") async def _(session: Uninfo, name: Match[str]): 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() 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) @@ -380,12 +378,12 @@ diuse_farm.shortcut( @diuse_farm.assign("unlock-plant") async def _(session: Uninfo, name: Match[str]): 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() 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) @@ -402,12 +400,12 @@ async def _( session: Uninfo, name: Match[str], num: Query[int] = AlconnaQuery("num", -1) ): 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() 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) @@ -422,13 +420,13 @@ reclamation = on_alconna( @reclamation.handle() async def _(session: Uninfo): 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() return - condition = await g_pFarmManager.reclamationCondition(uid) - condition += f"\n{g_sTranslation['reclamation']['confirm']}" + condition = await getFarmManager().reclamationCondition(uid) + condition += f"\n{config.g_sTranslation['reclamation']['confirm']}" await MessageUtils.build_message(condition).send(reply_to=True) @waiter(waits=["message"], keep_session=True) @@ -437,14 +435,14 @@ async def _(session: Uninfo): resp = await check.wait(timeout=60) if resp is None: - await MessageUtils.build_message(g_sTranslation["reclamation"]["timeOut"]).send( - reply_to=True - ) + await MessageUtils.build_message( + config.g_sTranslation["reclamation"]["timeOut"] + ).send(reply_to=True) return if not resp == "是": return - res = await g_pFarmManager.reclamation(uid) + res = await getFarmManager().reclamation(uid) await MessageUtils.build_message(res).send(reply_to=True) @@ -459,26 +457,26 @@ diuse_farm.shortcut( @diuse_farm.assign("stealing") async def _(session: Uninfo, target: Match[At]): 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() return if not target.available: - await MessageUtils.build_message(g_sTranslation["stealing"]["noTarget"]).finish( - reply_to=True - ) + await MessageUtils.build_message( + config.g_sTranslation["stealing"]["noTarget"] + ).finish(reply_to=True) tar = target.result - result = await g_pDBService.user.isRegistered(tar.target) + result = await g_pDBlocator.getUserManager().isRegistered(tar.target) if not result: await MessageUtils.build_message( - g_sTranslation["stealing"]["targetNotFarm"] + config.g_sTranslation["stealing"]["targetNotFarm"] ).send() 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) @@ -498,12 +496,12 @@ async def _(session: Uninfo, num: Query[int] = AlconnaQuery("num", 0)): ) 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() 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) @@ -518,25 +516,25 @@ diuse_farm.shortcut( @diuse_farm.assign("change-name") async def _(session: Uninfo, name: Match[str]): if not name.available: - await MessageUtils.build_message(g_sTranslation["changeName"]["noName"]).finish( - reply_to=True - ) + await MessageUtils.build_message( + config.g_sTranslation["changeName"]["noName"] + ).finish(reply_to=True) 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() return - player = await g_pToolManager.getPlayerByUid(uid) + player = await getToolManager().getPlayerByUid(uid) if player is None: - await MessageUtils.build_message(g_sTranslation["changeName"]["error1"]).send( - reply_to=True - ) + await MessageUtils.build_message( + config.g_sTranslation["changeName"]["error1"] + ).send(reply_to=True) return 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 ) @@ -552,17 +550,19 @@ diuse_farm.shortcut( @diuse_farm.assign("sign-in") async def _(session: Uninfo): 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() return # 判断签到是否正常加载 - if not g_bSignStatus: - await MessageUtils.build_message(g_sTranslation["signIn"]["error"]).send() + if not config.g_bSignStatus: + await MessageUtils.build_message( + config.g_sTranslation["signIn"]["error"] + ).send() return - message = await g_pSignInManager.signInByUid(uid) + message = await getSignInManager().signInByUid(uid) await MessageUtils.build_message(message).send() @@ -577,12 +577,12 @@ soil_upgrade = on_alconna( @soil_upgrade.handle() async def _(session: Uninfo, index: Query[int] = AlconnaQuery("index", 1)): 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() 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) @@ -595,14 +595,14 @@ async def _(session: Uninfo, index: Query[int] = AlconnaQuery("index", 1)): resp = await check.wait(timeout=60) if resp is None: - await MessageUtils.build_message(g_sTranslation["soilInfo"]["timeOut"]).send( - reply_to=True - ) + await MessageUtils.build_message( + config.g_sTranslation["soilInfo"]["timeOut"] + ).send(reply_to=True) return if not resp == "是": 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) @@ -617,12 +617,12 @@ diuse_farm.shortcut( @diuse_farm.assign("admin-up") async def _(session: Uninfo, num: Query[int] = AlconnaQuery("num", 0)): 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() return - await g_pDBService.userSoil.nextPhase(uid, num.result) + await g_pDBlocator.getUserSoilManager().nextPhase(uid, num.result) diuse_farm.shortcut( @@ -641,12 +641,12 @@ async def _(session: Uninfo, num: Query[int] = AlconnaQuery("num", 0)): ) 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() 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) @@ -661,13 +661,15 @@ diuse_farm.shortcut( @diuse_farm.assign("my-vipPoint") async def _(session: Uninfo): 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() return 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) @@ -699,9 +701,9 @@ diuse_farm.shortcut( @diuse_farm.assign("vipSeed-shop") async def _(session: Uninfo, res: Match[tuple[str, ...]]): 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(): - await g_pToolManager.repeat() + await getToolManager().repeat() return if res.result is inspect._empty: @@ -728,8 +730,8 @@ async def _(session: Uninfo, res: Match[tuple[str, ...]]): page = int(raw[1]) if filterKey is None: - image = await g_pShopManager.getSeedShopImage(page, 0, 1) + image = await CShopManager.getSeedShopImage(page, 0, 1) else: - image = await g_pShopManager.getSeedShopImage(filterKey, page, 1) + image = await CShopManager.getSeedShopImage(filterKey, page, 1) await MessageUtils.build_message(image).send() diff --git a/core/__init__.py b/core/__init__.py new file mode 100644 index 0000000..c728de0 --- /dev/null +++ b/core/__init__.py @@ -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", +] diff --git a/core/activity/sign_in.py b/core/activity/sign_in.py index 073970a..c986efe 100644 --- a/core/activity/sign_in.py +++ b/core/activity/sign_in.py @@ -4,15 +4,14 @@ from typing import Any from zhenxun.configs.config import Config from zhenxun.services.log import logger -from ...utils.config import DATA_PATH, g_sResourcePath, g_sTranslation -from ...utils.json import g_pJsonManager -from ...utils.tool import g_pToolManager +from ...utils import config, getJsonManager, getToolManager from ..dbService import g_pDBService class CSignInManager: - async def signInByUid(self, uid: str) -> str: - toDay = g_pToolManager.dateTime().date().today() + @classmethod + async def signInByUid(cls, uid: str) -> str: + toDay = getToolManager().dateTime().date().today() message = "" status = await g_pDBService.userSign.sign(uid, toDay.strftime("%Y-%m-%d")) @@ -26,11 +25,11 @@ class CSignInManager: 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 ) - jSign = await g_pJsonManager.getSign() + jSign = await getJsonManager().getSign() reward = jSign["continuou"].get(f"{signDay}", None) signType = Config.get_config("zhenxun_plugin_farm", "签到图片样式") @@ -41,30 +40,31 @@ class CSignInManager: plant = reward.get("plant", {}) - message += g_sTranslation["signIn"]["grandTotal"].format( + message += config.g_sTranslation["signIn"]["grandTotal"].format( exp=extraExp, num=extraPoint ) vipPoint = reward.get("vipPoint", 0) if vipPoint > 0: - message += g_sTranslation["signIn"]["grandTotal1"].format( + message += config.g_sTranslation["signIn"]["grandTotal1"].format( num=vipPoint ) if plant: for key, value in plant.items(): - message += g_sTranslation["signIn"]["grandTotal2"].format( - name=key, num=value - ) + message += config.g_sTranslation["signIn"][ + "grandTotal2" + ].format(name=key, num=value) else: - message = g_sTranslation["signIn"]["error1"] + message = config.g_sTranslation["signIn"]["error1"] pass return message + @classmethod def generateSignData( - self, + cls, todayRewards: list[dict[str, Any]], cumulativeRewards: list[dict[str, Any]], currentProgress: int, @@ -104,8 +104,9 @@ class CSignInManager: "consecutiveDays": consecutiveDays, } + @classmethod async def createSignImage( - self, + cls, todayRewards: list[dict[str, Any]], cumulativeRewards: list[dict[str, Any]], currentProgress: int, @@ -122,12 +123,12 @@ class CSignInManager: consecutiveDays (int, optional): 连续签到天数 """ try: - templatePath = g_sResourcePath / "html/sign_in.html" - outputPath = g_sResourcePath / "temp_html/sign_in.html" - savePath = DATA_PATH / "farm_res/html/sign_in.png" + templatePath = config.g_sResourcePath / "html/sign_in.html" + outputPath = config.g_sResourcePath / "temp_html/sign_in.html" + savePath = config.DATA_PATH / "farm_res/html/sign_in.png" # 1. 生成渲染数据 - context = self.generateSignData( + context = cls.generateSignData( todayRewards=todayRewards, cumulativeRewards=cumulativeRewards, currentProgress=currentProgress, @@ -136,19 +137,16 @@ class CSignInManager: ) # 2. 渲染HTML文件 - g_pToolManager.renderHtmlToFile(templatePath, context, outputPath) + getToolManager().renderHtmlToFile(templatePath, context, outputPath) # 3. 生成图片字节数据 - # imageBytes = await g_pToolManager.screenshotHtmlToBytes(outputPath) + # imageBytes = await getToolManager().screenshotHtmlToBytes(outputPath) # 4. 保存图片文件 - await g_pToolManager.screenshotSave( + await getToolManager().screenshotSave( str(outputPath), str(savePath), 600, 800 ) except Exception as e: logger.error(f"❌ 生成签到图片时出错: {e}") raise - - -g_pSignInManager = CSignInManager() diff --git a/core/database/__init__.py b/core/database/__init__.py new file mode 100644 index 0000000..975ca9b --- /dev/null +++ b/core/database/__init__.py @@ -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", +] diff --git a/core/database/database.py b/core/database/database.py index d0b9934..e1161a3 100644 --- a/core/database/database.py +++ b/core/database/database.py @@ -1,60 +1,188 @@ +from abc import ABC from contextlib import asynccontextmanager import os from pathlib import Path import re -from typing import Any +from typing import Any, ClassVar import aiosqlite 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): - dbPath = Path(g_sDBPath) - if dbPath and not dbPath.exists(): - os.makedirs(dbPath, exist_ok=True) + self.m_sTableName: str | None = None + self.m_bInitialized: bool = False - @classmethod - async def cleanup(cls): - if hasattr(cls, "m_pDB") and cls.m_pDB: - await cls.m_pDB.close() + self.m_pDBPath = Path(config.g_sDBPath) + if self.m_pDBPath and not self.m_pDBPath.exists(): + os.makedirs(self.m_pDBPath, exist_ok=True) @classmethod async def init(cls) -> bool: try: - cls.m_pDB = await aiosqlite.connect(g_sDBFilePath) - cls.m_pDB.row_factory = aiosqlite.Row - return True + if cls.m_pDB is None: + cls.m_pDB = await aiosqlite.connect(config.g_sDBFilePath) + cls.m_pDB.row_factory = aiosqlite.Row + logger.info("真寻农场数据库连接初始化成功") + return True + else: + logger.info("真寻农场数据库连接已存在,跳过初始化") + return True except Exception as e: - logger.debug("真寻农场初始化总数据库失败", e=e) + logger.error(f"真寻农场数据库连接初始化失败: {e}") 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 @asynccontextmanager async def _transaction(cls): - await cls.m_pDB.execute("BEGIN;") + await cls.getDB().execute("BEGIN;") try: yield except: - await cls.m_pDB.execute("ROLLBACK;") + await cls.getDB().execute("ROLLBACK;") raise else: - await cls.m_pDB.execute("COMMIT;") + await cls.getDB().execute("COMMIT;") @classmethod async def getTableInfo(cls, tableName: str) -> list: if not re.match(r"^[A-Za-z_][A-Za-z0-9_]*$", tableName): raise ValueError(f"Illegal table name: {tableName}") try: - cursor = await cls.m_pDB.execute(f'PRAGMA table_info("{tableName}")') + cursor = await cls.getDB().execute(f'PRAGMA table_info("{tableName}")') rows = await cursor.fetchall() return [{"name": row[1], "type": row[2]} for row in rows] except aiosqlite.Error: return [] + # @classmethod + # async def ensureTableSchema(cls, tableName: str, columns: dict) -> bool: + # """由AI生成 + # 创建表或为已存在表添加缺失字段。 + # 返回 True 表示有变更(创建或新增列),False 则无操作 + + # Args: + # tableName (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 async def ensureTableSchema(cls, tableName: str, columns: dict) -> bool: """由AI生成 @@ -62,13 +190,12 @@ class CSqlManager: 返回 True 表示有变更(创建或新增列),False 则无操作 Args: - tableName (_type_): 表名 - columns (_type_): 字典 + tableName (str): 表名 + columns (dict): 字典 Returns: - _type_: _description_ + 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"} @@ -78,7 +205,7 @@ class CSqlManager: colsDef = ", ".join(f'"{k}" {v}' for k, v in desired.items()) if primaryKey: colsDef += f", PRIMARY KEY {primaryKey}" - await cls.m_pDB.execute(f'CREATE TABLE "{tableName}" ({colsDef});') + await cls.getDB().execute(f'CREATE TABLE "{tableName}" ({colsDef});') return True 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] ] - if toAdd and not toRemove and not typeMismatch: + if toRemove or typeMismatch: + return False + + if toAdd: for col in toAdd: - await cls.m_pDB.execute( - f'ALTER TABLE "{tableName}" ADD COLUMN "{col}" {columns[col]}' - ) + try: + 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 - async with cls._transaction(): - tmpTable = f"{tableName}_new" - colsDef = ", ".join(f'"{k}" {v}' for k, v in desired.items()) - if primaryKey: - colsDef += f", PRIMARY KEY {primaryKey}" - await cls.m_pDB.execute(f'CREATE TABLE "{tmpTable}" ({colsDef});') - - commonCols = [k for k in desired if k in existing] - if commonCols: - colsStr = ", ".join(f'"{c}"' for c in commonCols) - - 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 + return False @classmethod async def executeDB(cls, command: str) -> bool: @@ -133,7 +247,7 @@ class CSqlManager: try: async with cls._transaction(): - await cls.m_pDB.execute(command) + await cls.getDB().execute(command) return True except Exception: return False @@ -162,7 +276,7 @@ class CSqlManager: sql = f'INSERT INTO "{tableName}" ({columns}) VALUES ({placeholders})' async with cls._transaction(): - await cls.m_pDB.execute(sql, values) + await cls.getDB().execute(sql, values) return True except Exception as e: logger.debug("真寻农场插入数据失败!", e=e) @@ -191,7 +305,7 @@ class CSqlManager: sql = f'INSERT INTO "{tableName}" ({columns}) VALUES ({placeholders})' async with cls._transaction(): - await cls.m_pDB.executemany( + await cls.getDB().executemany( sql, [list(data.values()) for data in data_list] ) return True @@ -255,7 +369,7 @@ class CSqlManager: if limit: sql += f" LIMIT {limit}" - cursor = await cls.m_pDB.execute(sql, params) + cursor = await cls.getDB().execute(sql, params) rows = await cursor.fetchall() # 转换为字典列表 @@ -304,7 +418,7 @@ class CSqlManager: sql = f'UPDATE "{tableName}" SET {", ".join(set_conditions)} WHERE {" AND ".join(where_conditions)}' async with cls._transaction(): - cursor = await cls.m_pDB.execute(sql, params) + cursor = await cls.getDB().execute(sql, params) # 检查是否影响了行 return cursor.rowcount > 0 except Exception as e: @@ -337,7 +451,7 @@ class CSqlManager: sql = f'DELETE FROM "{tableName}" WHERE {" AND ".join(where_conditions)}' async with cls._transaction(): - cursor = await cls.m_pDB.execute(sql, params) + cursor = await cls.getDB().execute(sql, params) # 检查是否影响了行 return cursor.rowcount > 0 except Exception as e: @@ -388,7 +502,7 @@ class CSqlManager: 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() return row["count"] if row else 0 except Exception as e: diff --git a/core/database/dbServiceLocator.py b/core/database/dbServiceLocator.py new file mode 100644 index 0000000..d3a6a90 --- /dev/null +++ b/core/database/dbServiceLocator.py @@ -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() diff --git a/core/database/plant.py b/core/database/plant.py index a2ef3f4..94312bf 100644 --- a/core/database/plant.py +++ b/core/database/plant.py @@ -6,14 +6,16 @@ import aiosqlite from zhenxun.configs.config import Config from zhenxun.services.log import logger -from ...utils.config import g_bIsDebug, g_sPlantPath, g_sResourcePath -from ...utils.request import g_pRequestManager +from ...utils import config, getRequestManager class CPlantManager: def __init__(self): + self.m_sTableName = "plant" + self.m_bInitialized = False + try: - os.mkdir(g_sPlantPath) + os.mkdir(config.g_sPlantPath) except FileExistsError: pass @@ -23,14 +25,14 @@ class CPlantManager: async def init(self) -> bool: 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( - str(g_sPlantPath.parent / "plant-test.db") + str(config.g_sPlantPath.parent / "plant-test.db") ) 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 return True @@ -38,6 +40,9 @@ class CPlantManager: logger.warning("初始化植物数据库失败", e=e) return False + async def initDB(self): + self.m_bInitialized = True + @asynccontextmanager async def _transaction(self): await self.m_pDB.execute("BEGIN;") @@ -254,7 +259,7 @@ class CPlantManager: for plant in plants: name = plant["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 for idx in range(begin, phaseCount + 1): @@ -265,14 +270,18 @@ class CPlantManager: continue 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 iconName = "icon.png" iconPath = os.path.join(saveDir, iconName) if not os.path.exists(iconPath): iconUrl = f"{baseUrl}/{name}/{iconName}" - if not await g_pRequestManager.download(iconUrl, saveDir, iconName): + if not await getRequestManager().download( + iconUrl, saveDir, iconName + ): success = False return success diff --git a/core/database/user.py b/core/database/user.py index 015717a..741d78b 100644 --- a/core/database/user.py +++ b/core/database/user.py @@ -1,11 +1,13 @@ import math -from ...utils.tool import g_pToolManager +from ...utils import getToolManager from .database import CSqlManager class CUserDB(CSqlManager): def __init__(self): + super().__init__() + self.m_sTableName = "user" self.currencies: list[str] = ["point", "vipPoint"] async def initDB(self): @@ -21,6 +23,7 @@ class CUserDB(CSqlManager): } await self.ensureTableSchema("user", userInfo) + self.setInitialized() async def initUserInfo(self, uid: str, name: str) -> bool: """初始化用户信息 @@ -32,7 +35,7 @@ class CUserDB(CSqlManager): Returns: bool: 是否成功初始化用户信息 """ - nowStr = g_pToolManager.dateTime().date().today().strftime("%Y-%m-%d") + nowStr = getToolManager().dateTime().date().today().strftime("%Y-%m-%d") result = await self.insert( "user", @@ -125,7 +128,7 @@ class CUserDB(CSqlManager): Returns: bool: 是否成功更新农场名称 """ - safeName = g_pToolManager.sanitize_username(name) + safeName = getToolManager().sanitize_username(name) if safeName == "神秘农夫": return "error" diff --git a/core/database/userItem.py b/core/database/userItem.py index b75cd58..dd4b021 100644 --- a/core/database/userItem.py +++ b/core/database/userItem.py @@ -4,8 +4,11 @@ from .database import CSqlManager class CUserItemDB(CSqlManager): - @classmethod - async def initDB(cls): + def __init__(self): + super().__init__() + self.m_sTableName = "userItem" + + async def initDB(self): userItem = { "uid": "TEXT NOT NULL", # 用户Uid "item": "TEXT NOT NULL", # 物品名称 @@ -13,7 +16,8 @@ class CUserItemDB(CSqlManager): "PRIMARY KEY": "(uid, item)", } - await cls.ensureTableSchema("userItem", userItem) + await self.ensureTableSchema("userItem", userItem) + self.setInitialized() @classmethod async def getUserItemByName(cls, uid: str, item: str) -> int | None: @@ -29,7 +33,7 @@ class CUserItemDB(CSqlManager): if not uid or not item: return None try: - async with cls.m_pDB.execute( + async with cls.getDB().execute( "SELECT count FROM userItem WHERE uid = ? AND item = ?", (uid, item) ) as cursor: row = await cursor.fetchone() @@ -51,7 +55,7 @@ class CUserItemDB(CSqlManager): if not uid: return {} try: - cursor = await cls.m_pDB.execute( + cursor = await cls.getDB().execute( "SELECT item, count FROM userItem WHERE uid = ?", (uid,) ) rows = await cursor.fetchall() @@ -75,7 +79,7 @@ class CUserItemDB(CSqlManager): return False try: async with cls._transaction(): - await cls.m_pDB.execute( + await cls.getDB().execute( "DELETE FROM userItem WHERE uid = ? AND item = ?", (uid, item) ) return True @@ -100,11 +104,11 @@ class CUserItemDB(CSqlManager): try: async with cls._transaction(): if count <= 0: - await cls.m_pDB.execute( + await cls.getDB().execute( "DELETE FROM userItem WHERE uid = ? AND item = ?", (uid, item) ) else: - await cls.m_pDB.execute( + await cls.getDB().execute( "UPDATE userItem SET count = ? WHERE uid = ? AND item = ?", (count, uid, item), ) @@ -129,7 +133,7 @@ class CUserItemDB(CSqlManager): return False try: 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) ) as cursor: row = await cursor.fetchone() @@ -137,18 +141,18 @@ class CUserItemDB(CSqlManager): if row: newCount = row[0] + count if newCount <= 0: - await cls.m_pDB.execute( + await cls.getDB().execute( "DELETE FROM userItem WHERE uid = ? AND item = ?", (uid, item), ) else: - await cls.m_pDB.execute( + await cls.getDB().execute( "UPDATE userItem SET count = ? WHERE uid = ? AND item = ?", (newCount, uid, item), ) else: if count > 0: - await cls.m_pDB.execute( + await cls.getDB().execute( "INSERT INTO userItem (uid, item, count) VALUES (?, ?, ?)", (uid, item, count), ) diff --git a/core/database/userPlant.py b/core/database/userPlant.py index 7f8492e..504b267 100644 --- a/core/database/userPlant.py +++ b/core/database/userPlant.py @@ -4,8 +4,11 @@ from .database import CSqlManager class CUserPlantDB(CSqlManager): - @classmethod - async def initDB(cls): + def __init__(self): + super().__init__() + self.m_sTableName = "userPlant" + + async def initDB(self): userPlant = { "uid": "TEXT NOT NULL", # 用户Uid "plant": "TEXT NOT NULL", # 作物名称 @@ -14,7 +17,8 @@ class CUserPlantDB(CSqlManager): "PRIMARY KEY": "(uid, plant)", } - await cls.ensureTableSchema("userPlant", userPlant) + await self.ensureTableSchema("userPlant", userPlant) + self.setInitialized() @classmethod async def addUserPlantByUid(cls, uid: str, plant: str, count: int = 1) -> bool: @@ -31,7 +35,7 @@ class CUserPlantDB(CSqlManager): try: async with cls._transaction(): # 检查是否已存在该作物 - async with cls.m_pDB.execute( + async with cls.getDB().execute( "SELECT count FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant), ) as cursor: @@ -40,13 +44,13 @@ class CUserPlantDB(CSqlManager): if row: # 如果作物已存在,则更新数量 new_count = row[0] + count - await cls.m_pDB.execute( + await cls.getDB().execute( "UPDATE userPlant SET count = ? WHERE uid = ? AND plant = ?", (new_count, uid, plant), ) else: # 如果作物不存在,则插入新记录 - await cls.m_pDB.execute( + await cls.getDB().execute( "INSERT INTO userPlant (uid, plant, count) VALUES (?, ?, ?)", (uid, plant, count), ) @@ -65,7 +69,7 @@ class CUserPlantDB(CSqlManager): Returns: Dict[str, int]: 作物名称和数量 """ - cursor = await cls.m_pDB.execute( + cursor = await cls.getDB().execute( "SELECT plant, count FROM userPlant WHERE uid=?", (uid,) ) rows = await cursor.fetchall() @@ -83,7 +87,7 @@ class CUserPlantDB(CSqlManager): Optional[int]: 作物数量 """ try: - async with cls.m_pDB.execute( + async with cls.getDB().execute( "SELECT count FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant) ) as cursor: row = await cursor.fetchone() @@ -104,7 +108,7 @@ class CUserPlantDB(CSqlManager): bool: 是否存在 """ try: - async with cls.m_pDB.execute( + async with cls.getDB().execute( "SELECT * FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant) ) as cursor: row = await cursor.fetchone() @@ -130,7 +134,7 @@ class CUserPlantDB(CSqlManager): return await cls.deleteUserPlantByName(uid, plant) async with cls._transaction(): - await cls.m_pDB.execute( + await cls.getDB().execute( "UPDATE userPlant SET count = ? WHERE uid = ? AND plant = ?", (count, uid, plant), ) @@ -153,7 +157,7 @@ class CUserPlantDB(CSqlManager): """ try: async with cls._transaction(): - await cls.m_pDB.execute( + await cls.getDB().execute( "UPDATE userPlant SET isLock = ? WHERE uid = ? AND plant = ?", (lock, uid, plant), ) @@ -174,7 +178,7 @@ class CUserPlantDB(CSqlManager): bool: 是否加锁 """ try: - async with cls.m_pDB.execute( + async with cls.getDB().execute( "SELECT isLock FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant) ) as cursor: row = await cursor.fetchone() @@ -196,7 +200,7 @@ class CUserPlantDB(CSqlManager): """ try: async with cls._transaction(): - await cls.m_pDB.execute( + await cls.getDB().execute( "DELETE FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant) ) return True diff --git a/core/database/userPlantCount.py b/core/database/userPlantCount.py index 726d699..1bd8367 100644 --- a/core/database/userPlantCount.py +++ b/core/database/userPlantCount.py @@ -4,8 +4,11 @@ from .database import CSqlManager class CUserPlantCountDB(CSqlManager): - @classmethod - async def initDB(cls): + def __init__(self): + super().__init__() + self.m_sTableName = "userPlantCount" + + async def initDB(self): userPlantCount = { "uid": "TEXT NOT NULL", # 用户Uid "plant": "TEXT NOT NULL", # 植物名称 @@ -13,7 +16,8 @@ class CUserPlantCountDB(CSqlManager): "PRIMARY KEY": "(uid, plant)", } - await cls.ensureTableSchema("userPlantCount", userPlantCount) + await self.ensureTableSchema("userPlantCount", userPlantCount) + self.setInitialized() @classmethod async def addUserPlantCountByUid(cls, uid: str, plant: str, count: int = 1) -> bool: @@ -29,7 +33,7 @@ class CUserPlantCountDB(CSqlManager): """ try: async with cls._transaction(): - async with cls.m_pDB.execute( + async with cls.getDB().execute( "SELECT count FROM userPlantCount WHERE uid = ? AND plant = ?", (uid, plant), ) as cursor: @@ -37,19 +41,19 @@ class CUserPlantCountDB(CSqlManager): if row: newCount = row[0] + count - await cls.m_pDB.execute( + await cls.getDB().execute( "UPDATE userPlantCount SET count = ? WHERE uid = ? AND plant = ?", (newCount, uid, plant), ) else: newCount = count - await cls.m_pDB.execute( + await cls.getDB().execute( "INSERT INTO userPlantCount (uid, plant, count) VALUES (?, ?, ?)", (uid, plant, count), ) if newCount <= 0: - await cls.m_pDB.execute( + await cls.getDB().execute( "DELETE FROM userPlantCount WHERE uid = ? AND plant = ?", (uid, plant), ) @@ -69,7 +73,7 @@ class CUserPlantCountDB(CSqlManager): dict: 植物信息 """ - cursor = await cls.m_pDB.execute( + cursor = await cls.getDB().execute( "SELECT plant, count FROM userPlantCount WHERE uid=?", (uid,) ) rows = await cursor.fetchall() @@ -86,7 +90,7 @@ class CUserPlantCountDB(CSqlManager): Returns: int: 收获次数 """ - cursor = await cls.m_pDB.execute( + cursor = await cls.getDB().execute( "SELECT count FROM userPlantCount WHERE uid = ? AND plant = ?", (uid, plant), ) @@ -110,7 +114,7 @@ class CUserPlantCountDB(CSqlManager): return await cls.deleteUserPlantCountByName(uid, plant) async with cls._transaction(): - await cls.m_pDB.execute( + await cls.getDB().execute( "UPDATE userPlantCount SET count = ? WHERE uid = ? AND plant = ?", (count, uid, plant), ) @@ -132,7 +136,7 @@ class CUserPlantCountDB(CSqlManager): """ try: async with cls._transaction(): - await cls.m_pDB.execute( + await cls.getDB().execute( "DELETE FROM userPlantCount WHERE uid = ? AND plant = ?", (uid, plant), ) diff --git a/core/database/userSeed.py b/core/database/userSeed.py index 2ef7682..8207247 100644 --- a/core/database/userSeed.py +++ b/core/database/userSeed.py @@ -4,8 +4,11 @@ from .database import CSqlManager class CUserSeedDB(CSqlManager): - @classmethod - async def initDB(cls): + def __init__(self): + super().__init__() + self.m_sTableName = "userSeed" + + async def initDB(self): userSeed = { "uid": "TEXT NOT NULL", # 用户Uid "seed": "TEXT NOT NULL", # 种子名称 @@ -13,7 +16,8 @@ class CUserSeedDB(CSqlManager): "PRIMARY KEY": "(uid, seed)", } - await cls.ensureTableSchema("userSeed", userSeed) + await self.ensureTableSchema("userSeed", userSeed) + self.setInitialized() @classmethod async def addUserSeedByUid(cls, uid: str, seed: str, count: int = 1) -> bool: @@ -29,26 +33,26 @@ class CUserSeedDB(CSqlManager): """ try: 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) ) as cursor: row = await cursor.fetchone() if row: newCount = row[0] + count - await cls.m_pDB.execute( + await cls.getDB().execute( "UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?", (newCount, uid, seed), ) else: newCount = count - await cls.m_pDB.execute( + await cls.getDB().execute( "INSERT INTO userSeed (uid, seed, count) VALUES (?, ?, ?)", (uid, seed, count), ) if newCount <= 0: - await cls.m_pDB.execute( + await cls.getDB().execute( "DELETE FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed) ) return True @@ -66,7 +70,7 @@ class CUserSeedDB(CSqlManager): if existing is not None: await cls._updateUserSeedByName(uid, seed, newCount) else: - await cls.m_pDB.execute( + await cls.getDB().execute( "INSERT INTO userSeed (uid, seed, count) VALUES (?, ?, ?)", (uid, seed, newCount), ) @@ -92,7 +96,7 @@ class CUserSeedDB(CSqlManager): """ try: - async with cls.m_pDB.execute( + async with cls.getDB().execute( "SELECT count FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed) ) as cursor: row = await cursor.fetchone() @@ -112,7 +116,7 @@ class CUserSeedDB(CSqlManager): dict: 种子信息 """ - cursor = await cls.m_pDB.execute( + cursor = await cls.getDB().execute( "SELECT seed, count FROM userSeed WHERE uid=?", (uid,) ) rows = await cursor.fetchall() @@ -135,7 +139,7 @@ class CUserSeedDB(CSqlManager): return await cls.deleteUserSeedByName(uid, seed) async with cls._transaction(): - await cls.m_pDB.execute( + await cls.getDB().execute( "UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?", (count, uid, seed), ) @@ -161,7 +165,7 @@ class CUserSeedDB(CSqlManager): return await cls.deleteUserSeedByName(uid, seed) async with cls._transaction(): - await cls.m_pDB.execute( + await cls.getDB().execute( "UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?", (count, uid, seed), ) @@ -183,7 +187,7 @@ class CUserSeedDB(CSqlManager): """ try: async with cls._transaction(): - await cls.m_pDB.execute( + await cls.getDB().execute( "DELETE FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed) ) return True @@ -203,7 +207,7 @@ class CUserSeedDB(CSqlManager): bool: 是否成功 """ try: - await cls.m_pDB.execute( + await cls.getDB().execute( "DELETE FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed) ) return True diff --git a/core/database/userSign.py b/core/database/userSign.py index c64abaf..712df93 100644 --- a/core/database/userSign.py +++ b/core/database/userSign.py @@ -5,16 +5,16 @@ import random from zhenxun.services.log import logger from zhenxun.utils._build_image import BuildImage -from ...utils.config import g_bIsDebug -from ...utils.json import g_pJsonManager -from ...utils.tool import g_pToolManager -from ..dbService import g_pDBService +from ...utils import config, getJsonManager, getToolManager from .database import CSqlManager class CUserSignDB(CSqlManager): - @classmethod - async def initDB(cls): + def __init__(self): + super().__init__() + self.m_sTableName = "userSign" + + async def initDB(self): # userSignLog 表结构,每条为一次签到事件 userSignLog = { "uid": "TEXT NOT NULL", # 用户ID @@ -38,8 +38,9 @@ class CUserSignDB(CSqlManager): "updatedAt": "DATETIME NOT NULL DEFAULT (datetime(CURRENT_TIMESTAMP, 'localtime'))", # 更新时间 # noqa: E501 } - await cls.ensureTableSchema("userSignLog", userSignLog) - await cls.ensureTableSchema("userSignSummary", userSignSummary) + await self.ensureTableSchema("userSignLog", userSignLog) + await self.ensureTableSchema("userSignSummary", userSignSummary) + self.setInitialized() @classmethod async def getUserSignRewardByDate(cls, uid: str, date: str) -> tuple[int, int]: @@ -54,7 +55,7 @@ class CUserSignDB(CSqlManager): """ try: async with cls._transaction(): - async with cls.m_pDB.execute( + async with cls.getDB().execute( "SELECT exp, point FROM userSignLog WHERE uid=? AND signDate=?", (uid, date), ) as cursor: @@ -85,7 +86,7 @@ class CUserSignDB(CSqlManager): try: sql = "SELECT COUNT(*) FROM userSignLog WHERE uid=? AND signDate LIKE ?" 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() return row[0] if row else 0 except Exception as e: @@ -105,7 +106,7 @@ class CUserSignDB(CSqlManager): """ try: 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() return row is not None except Exception as e: @@ -124,19 +125,21 @@ class CUserSignDB(CSqlManager): int: 0: 签到失败 1: 签到成功 2: 重复签到 """ try: - player = await g_pToolManager.getPlayerByUid(uid) + player = await getToolManager().getPlayerByUid(uid) if not player: return 0 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): 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 - sign = await g_pJsonManager.getSign() + sign = await getJsonManager().getSign() expMax, expMin, pointMax, pointMin = [ sign.get(key, default) @@ -153,12 +156,12 @@ class CUserSignDB(CSqlManager): vipPoint = 0 async with cls._transaction(): - await cls.m_pDB.execute( + await cls.getDB().execute( "INSERT INTO userSignLog (uid, signDate, isSupplement, exp, point) VALUES (?, ?, ?, ?, ?)", (uid, signDate, isSupplement, exp, point), ) - cursor = await cls.m_pDB.execute( + cursor = await cls.getDB().execute( "SELECT * FROM userSignSummary WHERE uid=?", (uid,) ) row = await cursor.fetchone() @@ -171,7 +174,7 @@ class CUserSignDB(CSqlManager): else 1 ) prevDate = ( - g_pToolManager.dateTime().strptime(signDate, "%Y-%m-%d") + getToolManager().dateTime().strptime(signDate, "%Y-%m-%d") - timedelta(days=1) ).strftime("%Y-%m-%d") continuousDays = ( @@ -184,7 +187,7 @@ class CUserSignDB(CSqlManager): if isSupplement else row["supplementCount"] ) - await cls.m_pDB.execute( + await cls.getDB().execute( """ UPDATE userSignSummary SET totalSignDays=totalSignDays+1, @@ -206,7 +209,7 @@ class CUserSignDB(CSqlManager): ) else: monthSignDays = 1 - await cls.m_pDB.execute( + await cls.getDB().execute( """ INSERT INTO userSignSummary (uid, totalSignDays, currentMonth, monthSignDays, lastSignDate, continuousDays, supplementCount) @@ -233,9 +236,9 @@ class CUserSignDB(CSqlManager): plant = reward.get("plant", {}) if plant: 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 # 向数据库更新 @@ -268,7 +271,7 @@ class CUserSignDB(CSqlManager): monthStr = f"{year:04d}-{month:02d}" try: 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() signedDays = {int(r[0][-2:]) for r in rows if r[0][-2:].isdigit()} except Exception as e: diff --git a/core/database/userSoil.py b/core/database/userSoil.py index 34f8d8a..ca76c9b 100644 --- a/core/database/userSoil.py +++ b/core/database/userSoil.py @@ -3,15 +3,16 @@ import re from zhenxun.services.log import logger -from ...utils.config import g_bIsDebug -from ...utils.tool import g_pToolManager -from ..dbService import g_pDBService +from ...utils import config, getToolManager from .database import CSqlManager class CUserSoilDB(CSqlManager): - @classmethod - async def initDB(cls): + def __init__(self): + super().__init__() + self.m_sTableName = "userSoil" + + async def initDB(self): userSoil = { "uid": "TEXT NOT NULL", "soilIndex": "INTEGER NOT NULL", # 地块索引从1开始 @@ -29,7 +30,8 @@ class CUserSoilDB(CSqlManager): "PRIMARY KEY": "(uid, soilIndex)", } - await cls.ensureTableSchema("userSoil", userSoil) + await self.ensureTableSchema("userSoil", userSoil) + self.setInitialized() @classmethod async def nextPhase(cls, uid: str, soilIndex: int): @@ -38,7 +40,7 @@ class CUserSoilDB(CSqlManager): Args: soilIndex (int): 地块索引 从1开始 """ - if not g_bIsDebug: + if not config.g_bIsDebug: return soilInfo = await cls.getUserSoil(uid, soilIndex) @@ -46,13 +48,15 @@ class CUserSoilDB(CSqlManager): if not soilInfo: return - plantInfo = await g_pDBService.plant.getPlantByName(soilInfo["plantName"]) + plantInfo = await cls.getPlantManager().getPlantByName(soilInfo["plantName"]) if not plantInfo: return - currentTime = g_pToolManager.dateTime().now().timestamp() - phaseList = await g_pDBService.plant.getPlantPhaseByName(soilInfo["plantName"]) + currentTime = getToolManager().dateTime().now().timestamp() + phaseList = await cls.getPlantManager().getPlantPhaseByName( + soilInfo["plantName"] + ) if currentTime >= soilInfo["matureTime"]: return @@ -88,11 +92,11 @@ class CUserSoilDB(CSqlManager): if not plantName: return - plantInfo = await g_pDBService.plant.getPlantByName(plantName) + plantInfo = await cls.getPlantManager().getPlantByName(plantName) if not plantInfo: return - currentTime = int(g_pToolManager.dateTime().now().timestamp()) + currentTime = int(getToolManager().dateTime().now().timestamp()) # 如果当前时间已经超过或等于成熟时间,则作物已成熟或可收获 if currentTime >= soilInfo["matureTime"]: return @@ -110,7 +114,7 @@ class CUserSoilDB(CSqlManager): Returns: 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() if not row: @@ -129,7 +133,7 @@ class CUserSoilDB(CSqlManager): None """ async with cls._transaction(): - await cls.m_pDB.execute( + await cls.getDB().execute( """ INSERT INTO userSoil (uid, soilIndex, plantName, plantTime, matureTime, @@ -164,7 +168,7 @@ class CUserSoilDB(CSqlManager): Returns: None """ - await cls.m_pDB.execute( + await cls.getDB().execute( """ INSERT INTO userSoil (uid, soilIndex, plantName, plantTime, matureTime, @@ -201,7 +205,7 @@ class CUserSoilDB(CSqlManager): dict: 记录存在返回字段-值字典,否则返回 None """ async with cls._transaction(): - cursor = await cls.m_pDB.execute( + cursor = await cls.getDB().execute( "SELECT * FROM userSoil WHERE uid = ? AND soilIndex = ?", (uid, soilIndex), ) @@ -222,7 +226,7 @@ class CUserSoilDB(CSqlManager): Returns: dict | None: 记录存在返回字段-值字典,否则返回 None """ - cursor = await cls.m_pDB.execute( + cursor = await cls.getDB().execute( "SELECT * FROM userSoil WHERE uid = ? AND soilIndex = ?", (uid, soilIndex), ) @@ -244,7 +248,7 @@ class CUserSoilDB(CSqlManager): int: 符合条件的土地数量 """ async with cls._transaction(): - cursor = await cls.m_pDB.execute( + cursor = await cls.getDB().execute( "SELECT COUNT(*) FROM userSoil WHERE uid = ? AND soilLevel = ?", (uid, soilLevel), ) @@ -265,7 +269,7 @@ class CUserSoilDB(CSqlManager): None """ async with cls._transaction(): - await cls.m_pDB.execute( + await cls.getDB().execute( f"UPDATE userSoil SET {field} = ? WHERE uid = ? AND soilIndex = ?", (value, uid, soilIndex), ) @@ -283,7 +287,7 @@ class CUserSoilDB(CSqlManager): Returns: None """ - await cls.m_pDB.execute( + await cls.getDB().execute( f"UPDATE userSoil SET {field} = ? WHERE uid = ? AND soilIndex = ?", (value, uid, soilIndex), ) @@ -331,7 +335,7 @@ class CUserSoilDB(CSqlManager): try: async with cls._transaction(): - await cls.m_pDB.execute(sql, tuple(values)) + await cls.getDB().execute(sql, tuple(values)) return True except Exception as e: logger.error(f"批量更新土地字段失败: {e}") @@ -349,7 +353,7 @@ class CUserSoilDB(CSqlManager): None """ async with cls._transaction(): - await cls.m_pDB.execute( + await cls.getDB().execute( "DELETE FROM userSoil WHERE uid = ? AND soilIndex = ?", (uid, soilIndex) ) @@ -364,7 +368,7 @@ class CUserSoilDB(CSqlManager): Returns: None """ - await cls.m_pDB.execute( + await cls.getDB().execute( "DELETE FROM userSoil WHERE uid = ? AND soilIndex = ?", (uid, soilIndex) ) @@ -386,12 +390,12 @@ class CUserSoilDB(CSqlManager): return False # 获取植物配置""" """ - plantCfg = await g_pDBService.plant.getPlantByName(plantName) + plantCfg = await cls.getPlantManager().getPlantByName(plantName) if not plantCfg: logger.error(f"未知植物: {plantName}") return False - nowTs = int(g_pToolManager.dateTime().now().timestamp()) + nowTs = int(getToolManager().dateTime().now().timestamp()) time = int(plantCfg.get("time", 0)) percent = await cls.getSoilLevelTime(soilInfo.get("soilLevel", 0)) @@ -413,11 +417,9 @@ class CUserSoilDB(CSqlManager): base_name = plantName[len(m.group(0)) :] # 只有当存在一星升级配置时才尝试按收获次数升级 - if await g_pDBService.plant.existsPlant("一星" + base_name): - harvestCounts = ( - await g_pDBService.userPlantCount.getUserPlantCountByPlantName( - uid, base_name - ) + if await cls.getPlantManager().existsPlant("一星" + base_name): + harvestCounts = await cls.getUserPlantCountManager().getUserPlantCountByPlantName( + uid, base_name ) # 根据阈值设定最高星级(避免重复拼接) prefix = "" @@ -455,7 +457,7 @@ class CUserSoilDB(CSqlManager): @classmethod async def getUserSoilStatus(cls, uid: str, soilIndex: int) -> str: status = [] - soilInfo = await g_pDBService.userSoil.getUserSoil(uid, soilIndex) + soilInfo = await cls.getUserSoilManager().getUserSoil(uid, soilIndex) if not soilInfo: return "" diff --git a/core/database/userSteal.py b/core/database/userSteal.py index 474054d..002f984 100644 --- a/core/database/userSteal.py +++ b/core/database/userSteal.py @@ -4,8 +4,11 @@ from .database import CSqlManager class CUserStealDB(CSqlManager): - @classmethod - async def initDB(cls): + def __init__(self): + super().__init__() + self.m_sTableName = "userSteal" + + async def initDB(self): userSteal = { "uid": "TEXT NOT NULL", # 被偷用户Uid "soilIndex": "INTEGER NOT NULL", # 被偷的地块索引 从1开始 @@ -14,7 +17,8 @@ class CUserStealDB(CSqlManager): "stealTime": "INTEGER NOT NULL", # 被偷时间 "PRIMARY KEY": "(uid, soilIndex, stealerUid)", } - await cls.ensureTableSchema("userSteal", userSteal) + await self.ensureTableSchema("userSteal", userSteal) + self.setInitialized() @classmethod async def addStealRecord( @@ -34,7 +38,7 @@ class CUserStealDB(CSqlManager): """ try: async with cls._transaction(): - await cls.m_pDB.execute( + await cls.getDB().execute( 'INSERT INTO "userSteal"(uid, soilIndex, stealerUid, stealCount, stealTime) VALUES(?, ?, ?, ?, ?);', (uid, soilIndex, stealerUid, stealCount, stealTime), ) @@ -55,7 +59,7 @@ class CUserStealDB(CSqlManager): """ try: async with cls._transaction(): - cursor = await cls.m_pDB.execute( + cursor = await cls.getDB().execute( 'SELECT soilIndex, stealerUid, stealCount, stealTime FROM "userSteal" WHERE uid=?;', (uid,), ) @@ -83,7 +87,7 @@ class CUserStealDB(CSqlManager): """ try: 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=?;', (uid, soilIndex), ) @@ -115,7 +119,7 @@ class CUserStealDB(CSqlManager): """ try: async with cls._transaction(): - cursor = await cls.m_pDB.execute( + cursor = await cls.getDB().execute( 'SELECT SUM(stealCount) FROM "userSteal" WHERE uid=? AND soilIndex=?;', (uid, soilIndex), ) @@ -138,7 +142,7 @@ class CUserStealDB(CSqlManager): """ try: 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=?;', (uid, soilIndex), ) @@ -162,7 +166,7 @@ class CUserStealDB(CSqlManager): """ try: 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;', (uid, soilIndex, stealerUid), ) @@ -190,7 +194,7 @@ class CUserStealDB(CSqlManager): """ try: async with cls._transaction(): - await cls.m_pDB.execute( + await cls.getDB().execute( 'UPDATE "userSteal" SET stealCount=?, stealTime=? WHERE uid=? AND soilIndex=? AND stealerUid=?;', (stealCount, stealTime, uid, soilIndex, stealerUid), ) @@ -212,7 +216,7 @@ class CUserStealDB(CSqlManager): """ try: async with cls._transaction(): - await cls.m_pDB.execute( + await cls.getDB().execute( 'DELETE FROM "userSteal" WHERE uid=? AND soilIndex=?;', (uid, soilIndex), ) diff --git a/core/dbService.py b/core/dbService.py index a0928f4..0379eab 100644 --- a/core/dbService.py +++ b/core/dbService.py @@ -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: + """ + 数据库服务管理器 + 负责初始化和协调所有数据库服务 + """ + + def __init__(self): + self.m_manager: dict[str, Any] = {} + self.m_bInitialized = False + async def init(self): - from .database.plant import CPlantManager - from .database.user import CUserDB - from .database.userItem import CUserItemDB - 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 + if self.m_bInitialized: + logger.warning("真寻农场数据库服务已初始化") + return - self.plant = CPlantManager() - await self.plant.init() + m_manager = { + "plant": CPlantManager(), + "user": CUserDB(), + "userSoil": CUserSoilDB(), + "userPlant": CUserPlantDB(), + "userSeed": CUserSeedDB(), + "userItem": CUserItemDB(), + "userSteal": CUserStealDB(), + "userSign": CUserSignDB(), + "userPlantCount": CUserPlantCountDB(), + } - self.user = CUserDB() - await self.user.initDB() + for name, manager in m_manager.items(): + g_pDBlocator.register(name, manager) + self.m_manager[name] = manager - self.userSoil = CUserSoilDB() - await self.userSoil.initDB() + tasks = [] + for name, manager in self.m_manager.items(): + tasks.append(manager.init()) + tasks.append(manager.initDB()) - self.userPlant = CUserPlantDB() - await self.userPlant.initDB() + await asyncio.gather(*tasks) - self.userSeed = CUserSeedDB() - await self.userSeed.initDB() + g_pDBlocator.markInitialized() + self.m_bInitialized = True - self.userItem = CUserItemDB() - 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() + logger.debug("真寻农场数据库服务初始化完成") 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() diff --git a/core/farm.py b/core/farm.py index 55b7f32..2dce43c 100644 --- a/core/farm.py +++ b/core/farm.py @@ -5,16 +5,12 @@ import re from zhenxun.configs.config import Config from zhenxun.models.user_console import UserConsole from zhenxun.services.log import logger -from zhenxun.utils._build_image import BuildImage from zhenxun.utils.enum import GoldHandle from zhenxun.utils.image_utils import ImageTemplate -from zhenxun.utils.platform import PlatformUtils from ..core.dbService import g_pDBService -from ..event.event import g_pEventManager -from ..utils.config import g_bIsDebug, g_iSoilLevelMax, g_sResourcePath, g_sTranslation -from ..utils.json import g_pJsonManager -from ..utils.tool import g_pToolManager +from ..event import g_pEventManager +from ..utils import config, getJsonManager, getToolManager class CFarmManager: @@ -50,372 +46,14 @@ class CFarmManager: ) point = num * pro - player = await g_pToolManager.getPlayerByUid(uid) + player = await getToolManager().getPlayerByUid(uid) if not player: - return g_sTranslation["basic"]["error"] + return config.g_sTranslation["basic"]["error"] await player.addPoint("point", int(point)) 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 async def getUserSeedByUid(cls, uid: str) -> bytes: """获取用户种子仓库""" @@ -449,7 +87,7 @@ class CFarmManager: if not plantInfo: 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 "" sellable = "可以" if plantInfo["sell"] else "不可以" @@ -495,16 +133,18 @@ class CFarmManager: count = 0 # 如果返回 None,则视为没有种子 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: - 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: - return g_sTranslation["basic"]["error"] + return config.g_sTranslation["basic"]["error"] soilNumber = player.user.get("soil", 3) # 如果播种数量为 -1,表示播种所有可播种的土地 @@ -540,13 +180,17 @@ class CFarmManager: # 根据播种结果给出反馈 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: - 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: logger.warning("播种操作失败!", e=e) - return g_sTranslation["sowing"]["error"] + return config.g_sTranslation["sowing"]["error"] @classmethod async def harvest(cls, uid: str) -> str: @@ -561,9 +205,9 @@ class CFarmManager: try: await g_pEventManager.m_beforeHarvest.emit(uid=uid) # type: ignore - player = await g_pToolManager.getPlayerByUid(uid) + player = await getToolManager().getPlayerByUid(uid) if not player: - return g_sTranslation["basic"]["error"] + return config.g_sTranslation["basic"]["error"] soilNumber = player.user.get("soil", 3) harvestRecords = [] # 收获日志记录 @@ -591,9 +235,11 @@ class CFarmManager: if not plantInfo: continue - currentTime = g_pToolManager.dateTime().now() - matureTime = g_pToolManager.dateTime().fromtimestamp( - int(soilInfo["matureTime"]) + currentTime = getToolManager().dateTime().now() + matureTime = ( + getToolManager() + .dateTime() + .fromtimestamp(int(soilInfo["matureTime"])) ) if currentTime >= matureTime: @@ -620,7 +266,7 @@ class CFarmManager: experience = math.floor(experience * (100 + percent) // 100) harvestRecords.append( - g_sTranslation["harvest"]["append"].format( + config.g_sTranslation["harvest"]["append"].format( name=soilInfo["plantName"], num=number, exp=plantInfo["experience"], @@ -680,19 +326,19 @@ class CFarmManager: exp = player.user.get("exp", 0) await player.addExp(exp + experience) harvestRecords.append( - g_sTranslation["harvest"]["exp"].format( + config.g_sTranslation["harvest"]["exp"].format( exp=experience, ) ) if harvestCount <= 0: - return g_sTranslation["harvest"]["no"] + return config.g_sTranslation["harvest"]["no"] else: return "\n".join(harvestRecords) except Exception as e: logger.warning("收获操作失败!", e=e) - return g_sTranslation["harvest"]["error"] + return config.g_sTranslation["harvest"]["error"] @classmethod async def eradicate(cls, uid: str) -> str: @@ -704,9 +350,9 @@ class CFarmManager: Returns: str: 返回 """ - player = await g_pToolManager.getPlayerByUid(uid) + player = await getToolManager().getPlayerByUid(uid) if not player: - return g_sTranslation["basic"]["error"] + return config.g_sTranslation["basic"]["error"] soilNumber = player.user.get("soil", 3) await g_pEventManager.m_beforeEradicate.emit(uid=uid) # type: ignore @@ -727,7 +373,7 @@ class CFarmManager: experience += 3 - if g_bIsDebug: + if config.g_bIsDebug: experience += 999 # 更新数据库操作 @@ -754,9 +400,9 @@ class CFarmManager: exp = player.user.get("exp", 0) await player.addExp(exp + experience) - return g_sTranslation["eradicate"]["success"].format(exp=experience) + return config.g_sTranslation["eradicate"]["success"].format(exp=experience) else: - return g_sTranslation["eradicate"]["error"] + return config.g_sTranslation["eradicate"]["error"] @classmethod async def getUserPlantByUid(cls, uid: str) -> bytes: @@ -797,7 +443,7 @@ class CFarmManager: continue icon = "" - icon_path = g_sResourcePath / f"plant/{name}/icon.png" + icon_path = config.g_sResourcePath / f"plant/{name}/icon.png" if icon_path.exists(): icon = (icon_path, 33, 33) @@ -841,16 +487,18 @@ class CFarmManager: """ # 先判断该用户仓库是否有该作物 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 lock == 0: - return g_sTranslation["lockPlant"]["unlockPlant"].format(name=name) + return config.g_sTranslation["lockPlant"]["unlockPlant"].format( + name=name + ) else: - return g_sTranslation["lockPlant"]["lockPlant"].format(name=name) + return config.g_sTranslation["lockPlant"]["lockPlant"].format(name=name) else: - return g_sTranslation["lockPlant"]["error"] + return config.g_sTranslation["lockPlant"]["error"] @classmethod async def stealing(cls, uid: str, target: str) -> str: @@ -864,25 +512,25 @@ class CFarmManager: str: 返回 """ # 用户信息 - player = await g_pToolManager.getPlayerByUid(uid) + player = await getToolManager().getPlayerByUid(uid) if not player: - return g_sTranslation["basic"]["error"] + return config.g_sTranslation["basic"]["error"] stealTime = player.user.get("stealTime", "") stealCount = int(player.user["stealCount"]) 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 elif ( - g_pToolManager.dateTime().date().fromisoformat(stealTime) - != g_pToolManager.dateTime().date().today() + getToolManager().dateTime().date().fromisoformat(stealTime) + != 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 if stealCount <= 0: - return g_sTranslation["stealing"]["max"] + return config.g_sTranslation["stealing"]["max"] # 获取用户解锁地块数量 soilNumber = player.user.get("soil", 3) @@ -908,9 +556,9 @@ class CFarmManager: if not plantInfo: continue - currentTime = g_pToolManager.dateTime().now() - matureTime = g_pToolManager.dateTime().fromtimestamp( - int(soilInfo["matureTime"]) + currentTime = getToolManager().dateTime().now() + matureTime = ( + getToolManager().dateTime().fromtimestamp(int(soilInfo["matureTime"])) ) if currentTime >= matureTime: @@ -931,7 +579,7 @@ class CFarmManager: ) harvestRecords.append( - g_sTranslation["stealing"]["info"].format( + config.g_sTranslation["stealing"]["info"].format( name=soilInfo["plantName"], num=randomNumber ) ) @@ -971,7 +619,7 @@ class CFarmManager: i, uid, randomNumber, - int(g_pToolManager.dateTime().now().timestamp()), + int(getToolManager().dateTime().now().timestamp()), ) else: @@ -980,13 +628,13 @@ class CFarmManager: i, uid, randomNumber, - int(g_pToolManager.dateTime().now().timestamp()), + int(getToolManager().dateTime().now().timestamp()), ) if isStealingPlant <= 0 and isStealingNumber <= 0: - return g_sTranslation["stealing"]["noPlant"] + return config.g_sTranslation["stealing"]["noPlant"] elif isStealingPlant <= 0 and isStealingNumber > 0: - return g_sTranslation["stealing"]["repeat"] + return config.g_sTranslation["stealing"]["repeat"] else: stealCount -= 1 @@ -1004,15 +652,15 @@ class CFarmManager: Returns: str: 返回条件文本信息 """ - jLevel = await g_pJsonManager.getLevel() + jLevel = await getJsonManager().getLevel() rec = jLevel["reclamation"] - player = await g_pToolManager.getPlayerByUid(uid) + player = await getToolManager().getPlayerByUid(uid) if not player: - return g_sTranslation["basic"]["error"] + return config.g_sTranslation["basic"]["error"] try: if player.user["soil"] >= 30: - return g_sTranslation["reclamation"]["perfect"] + return config.g_sTranslation["reclamation"]["perfect"] rec = rec[f"{player.user['soil'] + 1}"] @@ -1022,17 +670,17 @@ class CFarmManager: str = "" if len(item) == 0: - str = g_sTranslation["reclamation"]["next"].format( + str = config.g_sTranslation["reclamation"]["next"].format( level=level, num=point ) else: - str = g_sTranslation["reclamation"]["next2"].format( + str = config.g_sTranslation["reclamation"]["next2"].format( level=level, num=point, item=item ) return str except Exception: - return g_sTranslation["reclamation"]["error"] + return config.g_sTranslation["reclamation"]["error"] @classmethod async def reclamation(cls, uid: str) -> str: @@ -1044,17 +692,17 @@ class CFarmManager: Returns: str: _description_ """ - player = await g_pToolManager.getPlayerByUid(uid) + player = await getToolManager().getPlayerByUid(uid) if not player: - return g_sTranslation["basic"]["error"] + return config.g_sTranslation["basic"]["error"] level = await player.getUserLevel() - jsonLevel = await g_pJsonManager.getLevel() + jsonLevel = await getJsonManager().getLevel() rec = jsonLevel["reclamation"] try: if player.user["soil"] >= 30: - return g_sTranslation["reclamation"]["perfect"] + return config.g_sTranslation["reclamation"]["perfect"] rec = rec[f"{player.user['soil'] + 1}"] @@ -1063,20 +711,20 @@ class CFarmManager: # item = rec["item"] if level[0] < levelFileter: - return g_sTranslation["reclamation"]["nextLevel"].format( + return config.g_sTranslation["reclamation"]["nextLevel"].format( level=level[0], next=levelFileter ) if player.user["point"] < point: - return g_sTranslation["reclamation"]["noNum"].format(num=point) + return config.g_sTranslation["reclamation"]["noNum"].format(num=point) # TODO 缺少判断消耗的item await player.subPoint("point", point) await player.updateField("soil", player.user["soil"] + 1) - return g_sTranslation["reclamation"]["success"] + return config.g_sTranslation["reclamation"]["success"] except Exception: - return g_sTranslation["reclamation"]["error1"] + return config.g_sTranslation["reclamation"]["error1"] @classmethod async def soilUpgradeCondition(cls, uid: str, soilIndex: int) -> str: @@ -1092,18 +740,18 @@ class CFarmManager: soilInfo = await g_pDBService.userSoil.getUserSoil(uid, soilIndex) if not soilInfo: - return g_sTranslation["soilInfo"]["error"] + return config.g_sTranslation["soilInfo"]["error"] soilLevel = soilInfo.get("soilLevel", 0) + 1 - if soilLevel >= g_iSoilLevelMax: - return g_sTranslation["soilInfo"]["error1"] + if soilLevel >= config.g_iSoilLevelMax: + return config.g_sTranslation["soilInfo"]["error1"] # 获取用户当前土地 的下一级土地 数量 countSoil = await g_pDBService.userSoil.countSoilByLevel(uid, soilLevel) # 获取升级所需 soilLevelText = await g_pDBService.userSoil.getSoilLevel(soilLevel) - jSoil = await g_pJsonManager.getSoil() + jSoil = await getJsonManager().getSoil() fileter = jSoil["upgrade"][soilLevelText][countSoil] nextLevel = await g_pDBService.userSoil.getSoilLevelText(soilLevel) @@ -1139,22 +787,22 @@ class CFarmManager: Returns: str: """ - player = await g_pToolManager.getPlayerByUid(uid) + player = await getToolManager().getPlayerByUid(uid) if not player: - return g_sTranslation["basic"]["error"] + return config.g_sTranslation["basic"]["error"] soilInfo = await g_pDBService.userSoil.getUserSoil(uid, soilIndex) if not soilInfo: - return g_sTranslation["soilInfo"]["error"] + return config.g_sTranslation["soilInfo"]["error"] soilLevel = soilInfo.get("soilLevel", 0) + 1 - if soilLevel >= g_iSoilLevelMax: - return g_sTranslation["soilInfo"]["error1"] + if soilLevel >= config.g_iSoilLevelMax: + return config.g_sTranslation["soilInfo"]["error1"] countSoil = await g_pDBService.userSoil.countSoilByLevel(uid, soilLevel) soilLevelText = await g_pDBService.userSoil.getSoilLevel(soilLevel) - soil = await g_pJsonManager.getSoil() + soil = await getJsonManager().getSoil() fileter = soil["upgrade"][soilLevelText][countSoil] getters = { @@ -1188,9 +836,9 @@ class CFarmManager: await player.subPoint("point", fileter.get("point", 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), - text=g_sTranslation["soilInfo"][soilLevelText], + text=config.g_sTranslation["soilInfo"][soilLevelText], ) @classmethod @@ -1218,9 +866,9 @@ class CFarmManager: pro = int(Config.get_config("zhenxun_plugin_farm", "点券兑换倍数")) pro *= num - player = await g_pToolManager.getPlayerByUid(uid) + player = await getToolManager().getPlayerByUid(uid) if not player: - return g_sTranslation["basic"]["error"] + return config.g_sTranslation["basic"]["error"] point = player.user.get("point", 0) if point < pro: @@ -1241,6 +889,3 @@ class CFarmManager: await player.subPoint("point", pro) return f"兑换{num}点券成功,当前点券:{number},赠送点券:{giftPoints},当前农场币:{point}" - - -g_pFarmManager = CFarmManager() diff --git a/core/help.py b/core/help.py index c2efced..18eabe1 100644 --- a/core/help.py +++ b/core/help.py @@ -1,15 +1,14 @@ from zhenxun.configs.path_config import DATA_PATH from zhenxun.services.log import logger -from ..utils.config import g_sResourcePath -from ..utils.tool import g_pToolManager +from ..utils import config, getToolManager class CHelpManager: @classmethod async def createHelpImage(cls) -> bool: - templatePath = g_sResourcePath / "html/help.html" - outputPath = g_sResourcePath / "temp_html/help.html" + templatePath = config.g_sResourcePath / "html/help.html" + outputPath = config.g_sResourcePath / "temp_html/help.html" savePath = DATA_PATH / "farm_res/html/help.png" context = { @@ -24,9 +23,9 @@ class CHelpManager: } 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 ) except Exception as e: @@ -34,6 +33,3 @@ class CHelpManager: return False return True - - -g_pHelpManager = CHelpManager() diff --git a/core/player/__init__.py b/core/player/__init__.py new file mode 100644 index 0000000..e34da51 --- /dev/null +++ b/core/player/__init__.py @@ -0,0 +1,4 @@ +from .player import CPlayer +from .playerPool import CPlayerPool + +__all__ = ["CPlayer", "CPlayerPool"] diff --git a/core/player/player.py b/core/player/player.py index a565605..0e0bdca 100644 --- a/core/player/player.py +++ b/core/player/player.py @@ -1,4 +1,4 @@ -from ..dbService import g_pDBService +from .. import g_pDBlocator class CPlayer: @@ -24,7 +24,7 @@ class CPlayer: if uid == "": return False - self.user = await g_pDBService.user.getUserInfoByUid(uid) + self.user = await g_pDBlocator.getUserManager().getUserInfoByUid(uid) return True @@ -39,7 +39,7 @@ class CPlayer: if uid == "": 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: """增加货币 @@ -53,7 +53,7 @@ class CPlayer: """ 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 if index == 0: @@ -64,7 +64,7 @@ class CPlayer: if 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 return True @@ -82,7 +82,7 @@ class CPlayer: """ 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 if index == 0: @@ -93,7 +93,7 @@ class CPlayer: if 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 return True @@ -121,7 +121,7 @@ class CPlayer: if nowExp < 0: nowExp = 0 - if await g_pDBService.user.updateExp(uid, nowExp): + if await g_pDBlocator.getUserManager().updateExp(uid, nowExp): self.user["exp"] = nowExp return True @@ -149,7 +149,7 @@ class CPlayer: if nowExp < 0: nowExp = 0 - if await g_pDBService.user.updateExp(uid, nowExp): + if await g_pDBlocator.getUserManager().updateExp(uid, nowExp): self.user["exp"] = nowExp return True @@ -169,7 +169,7 @@ class CPlayer: if uid == "": 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]: """获取用户等级信息 @@ -183,7 +183,7 @@ class CPlayer: if uid == "": return -1, -1, -1 - return await g_pDBService.user.getUserLevelByUid(uid) + return await g_pDBlocator.getUserManager().getUserLevelByUid(uid) async def updateStealCountByUid( self, uid: str, stealTime: str, stealCount: int @@ -203,7 +203,9 @@ class CPlayer: if uid == "": 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: """更新单字段信息 @@ -216,4 +218,4 @@ class CPlayer: if uid == "": return False - return await g_pDBService.user.updateFieldByUid(uid, field, value) + return await g_pDBlocator.getUserManager().updateFieldByUid(uid, field, value) diff --git a/core/shop.py b/core/shop.py index aff4302..53e020e 100644 --- a/core/shop.py +++ b/core/shop.py @@ -2,9 +2,8 @@ import math from zhenxun.utils.image_utils import ImageTemplate -from ..core.dbService import g_pDBService -from ..utils.config import g_sResourcePath, g_sTranslation -from ..utils.tool import g_pToolManager +from ..utils import config, getToolManager +from . import g_pDBlocator class CShopManager: @@ -46,7 +45,7 @@ class CShopManager: ] # 查询所有可购买作物,并根据筛选关键字过滤 - plants = await g_pDBService.plant.listPlants() + plants = await g_pDBlocator.getPlantManager().listPlants() filteredPlants = [] # 如果是点券商店 @@ -87,7 +86,7 @@ class CShopManager: for plant in pageItems: # 图标处理 icon = "" - iconPath = g_sResourcePath / f"plant/{plant['name']}/icon.png" + iconPath = config.g_sResourcePath / f"plant/{plant['name']}/icon.png" if iconPath.exists(): icon = (iconPath, 33, 33) @@ -136,17 +135,17 @@ class CShopManager: str: """ if num <= 0: - return g_sTranslation["buySeed"]["notNum"] + return config.g_sTranslation["buySeed"]["notNum"] - player = await g_pToolManager.getPlayerByUid(uid) - plantInfo = await g_pDBService.plant.getPlantByName(name) + player = await getToolManager().getPlayerByUid(uid) + plantInfo = await g_pDBlocator.getPlantManager().getPlantByName(name) if not plantInfo or not player: - return g_sTranslation["buySeed"]["error"] + return config.g_sTranslation["buySeed"]["error"] level = player.user.get("level", 0) if level < int(plantInfo["level"]): - return g_sTranslation["buySeed"]["noLevel"] + return config.g_sTranslation["buySeed"]["noLevel"] vipSeed = plantInfo.get("isVip", 0) == 1 currencyType = "vipPoint" if vipSeed else "point" @@ -155,17 +154,19 @@ class CShopManager: currentCurrency = player.user.get(currencyType, 0) 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): - return g_sTranslation["buySeed"]["errorSql"] + if not await g_pDBlocator.getUserSeedManager().addUserSeedByUid(uid, name, num): + return config.g_sTranslation["buySeed"]["errorSql"] success_key = "vipSuccess" if vipSeed else "success" 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 ) @@ -182,9 +183,9 @@ class CShopManager: if not isinstance(name, str) or name.strip() == "": name = "" - plant = await g_pDBService.userPlant.getUserPlantByUid(uid) + plant = await g_pDBlocator.getUserPlantManager().getUserPlantByUid(uid) if not plant: - return g_sTranslation["sellPlant"]["no"] + return config.g_sTranslation["sellPlant"]["no"] point = 0 totalSold = 0 @@ -192,27 +193,31 @@ class CShopManager: if name == "": for plantName, count in plant.items(): - isLock = await g_pDBService.userPlant.checkPlantLockByName( + isLock = await g_pDBlocator.getUserPlantManager().checkPlantLockByName( uid, plantName ) if isLock: continue - plantInfo = await g_pDBService.plant.getPlantByName(plantName) + plantInfo = await g_pDBlocator.getUserPlantManager().getPlantByName( + plantName + ) if not plantInfo: continue point += plantInfo["price"] * count - await g_pDBService.userPlant.updateUserPlantByName(uid, plantName, 0) + await g_pDBlocator.getUserPlantManager().updateUserPlantByName( + uid, plantName, 0 + ) else: 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] sellAmount = available if isAll else min(available, num) if sellAmount <= 0: - return g_sTranslation["sellPlant"]["error1"].format(name=name) - await g_pDBService.userPlant.updateUserPlantByName( + return config.g_sTranslation["sellPlant"]["error1"].format(name=name) + await g_pDBlocator.getUserPlantManager().updateUserPlantByName( uid, name, available - sellAmount ) totalSold = sellAmount @@ -220,7 +225,7 @@ class CShopManager: if name == "": totalPoint = point else: - plantInfo = await g_pDBService.plant.getPlantByName(name) + plantInfo = await g_pDBlocator.getUserPlantManager().getPlantByName(name) if not plantInfo: price = 0 else: @@ -228,18 +233,15 @@ class CShopManager: totalPoint = totalSold * price - player = await g_pToolManager.getPlayerByUid(uid) + player = await getToolManager().getPlayerByUid(uid) if not player: - return g_sTranslation["basic"]["error"] + return config.g_sTranslation["basic"]["error"] currentPoint = player.user.get("point", 0) await player.addPoint("point", currentPoint + totalPoint) result = "success1" if name == "" else "success" - return g_sTranslation["sellPlant"][result].format( + return config.g_sTranslation["sellPlant"][result].format( point=totalPoint, num=currentPoint + totalPoint ) - - -g_pShopManager = CShopManager() diff --git a/event/__init__.py b/event/__init__.py new file mode 100644 index 0000000..c734322 --- /dev/null +++ b/event/__init__.py @@ -0,0 +1,3 @@ +from .event import g_pEventManager + +__all__ = ["g_pEventManager"] diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..14a0990 --- /dev/null +++ b/utils/__init__.py @@ -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", +] diff --git a/utils/darw/__init__.py b/utils/darw/__init__.py new file mode 100644 index 0000000..4237bd5 --- /dev/null +++ b/utils/darw/__init__.py @@ -0,0 +1,3 @@ +from .drawFarm import CDarwFarm + +__all__ = ["CDarwFarm"] diff --git a/utils/darw/drawFarm.py b/utils/darw/drawFarm.py new file mode 100644 index 0000000..eb7f556 --- /dev/null +++ b/utils/darw/drawFarm.py @@ -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 diff --git a/utils/json.py b/utils/json.py index e16ec47..9de4d56 100644 --- a/utils/json.py +++ b/utils/json.py @@ -2,8 +2,7 @@ import json from zhenxun.services.log import logger -from . import config -from .request import g_pRequestManager +from . import config, getRequestManager class CJsonManager: @@ -117,7 +116,7 @@ class CJsonManager: return False async def initSignInFile(self) -> bool: - if not await g_pRequestManager.initSignInFile(): + if not await getRequestManager().initSignInFile(): config.g_bSignStatus = False return False else: diff --git a/utils/request.py b/utils/request.py index 3b468cf..f8e0c82 100644 --- a/utils/request.py +++ b/utils/request.py @@ -15,8 +15,7 @@ from zhenxun.configs.config import Config from zhenxun.services.log import logger from ..core.dbService import g_pDBService -from .config import g_sPlantPath, g_sSignInPath -from .tool import g_pToolManager +from . import config, getToolManager class CRequestManager: @@ -162,14 +161,14 @@ class CRequestManager: @classmethod async def initSignInFile(cls) -> bool: - if os.path.exists(g_sSignInPath): + if os.path.exists(config.g_sSignInPath): try: - with open(g_sSignInPath, encoding="utf-8") as f: + with open(config.g_sSignInPath, encoding="utf-8") as f: content = f.read() sign = json.loads(content) date = sign.get("date", "") - yearMonth = g_pToolManager.dateTime().now().strftime("%Y%m") + yearMonth = getToolManager().dateTime().now().strftime("%Y%m") if date == yearMonth: logger.debug("真寻农场签到文件检查完毕") @@ -193,8 +192,8 @@ class CRequestManager: try: baseUrl = Config.get_config("zhenxun_plugin_farm", "服务地址") url = f"{baseUrl.rstrip('/')}:8998/sign_in" - path = str(g_sSignInPath.parent.resolve(strict=False)) - yearMonth = g_pToolManager.dateTime().now().strftime("%Y%m") + path = str(config.g_sSignInPath.parent.resolve(strict=False)) + yearMonth = getToolManager().dateTime().now().strftime("%Y%m") # 下载为 signTemp.json success = await cls.download( @@ -208,7 +207,7 @@ class CRequestManager: return False # 重命名为 sign_in.json - g_pToolManager.renameFile(f"{path}/signTemp.json", "sign_in.json") + getToolManager().renameFile(f"{path}/signTemp.json", "sign_in.json") return True except Exception as e: logger.error("下载签到文件失败", e=e) @@ -221,7 +220,7 @@ class CRequestManager: Returns: 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: with open(versionPath, encoding="utf-8") as f: @@ -262,7 +261,7 @@ class CRequestManager: """ baseUrl = Config.get_config("zhenxun_plugin_farm", "服务地址") - savePath = os.path.dirname(g_sPlantPath) + savePath = os.path.dirname(config.g_sPlantPath) success = await cls.download( url=f"{baseUrl.rstrip('/')}:8998/file/plant.db", savePath=savePath, @@ -273,7 +272,7 @@ class CRequestManager: return False # 重命名为 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") try: @@ -288,6 +287,3 @@ class CRequestManager: await g_pDBService.plant.downloadPlant() return True - - -g_pRequestManager = CRequestManager() diff --git a/utils/tool.py b/utils/tool.py index 39c6e23..5976b1a 100644 --- a/utils/tool.py +++ b/utils/tool.py @@ -9,8 +9,7 @@ from playwright.async_api import async_playwright from zhenxun.services.log import logger from zhenxun.utils.message import MessageUtils -from ..core.player.player import CPlayer -from ..core.player.playerPool import g_pUserPool +from ..core import CPlayer, g_pUserPool class CToolManager: @@ -192,6 +191,3 @@ class CToolManager: # 截图并保存到本地文件 await page.screenshot(path=save, full_page=True) await browser.close() - - -g_pToolManager = CToolManager()