From 78762eceaee280ab84e80cdc13bdd9571422bc14 Mon Sep 17 00:00:00 2001 From: Shu-Ying <1754798088@qq.com> Date: Tue, 2 Dec 2025 11:06:13 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=E8=A7=A3=E5=86=B3=E9=80=80?= =?UTF-8?q?=E5=87=BA=E6=97=B6=E6=95=B0=E6=8D=AE=E5=BA=93=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E5=85=B3=E9=97=AD=E5=AF=BC=E8=87=B4=E5=8D=A1=E8=BF=9B=E7=A8=8B?= =?UTF-8?q?=E7=9A=84BUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __init__.py | 7 +++ core/database/database.py | 33 ++++++++-- requirements.txt | 0 resource/background/frame.png | Bin 18357 -> 0 bytes utils/__init__.py | 4 ++ utils/darw/drawFarm.py | 111 +++++++++++++++++++++++++++------- utils/tool.py | 43 +++++++++++++ utils/utils.py | 22 +++++++ 8 files changed, 192 insertions(+), 28 deletions(-) create mode 100644 requirements.txt delete mode 100644 resource/background/frame.png create mode 100644 utils/utils.py diff --git a/__init__.py b/__init__.py index 7d8c9a7..977f4ff 100644 --- a/__init__.py +++ b/__init__.py @@ -57,6 +57,13 @@ __plugin_meta__ = PluginMetadata( help="我的农场返回图片的清晰度, [low, medium, hight, original]", default_value="low", ), + RegisterConfig( + key="动态背景", + value=True, + help="是否开启根据季节和节日变化的动态背景", + type=bool, + default_value=True, + ), RegisterConfig( key="签到图片样式", value="text", diff --git a/core/database/database.py b/core/database/database.py index e1161a3..488bbed 100644 --- a/core/database/database.py +++ b/core/database/database.py @@ -35,10 +35,10 @@ class CSqlManager(ABC): if cls.m_pDB is None: cls.m_pDB = await aiosqlite.connect(config.g_sDBFilePath) cls.m_pDB.row_factory = aiosqlite.Row - logger.info("真寻农场数据库连接初始化成功") + logger.debug("真寻农场数据库连接初始化成功") return True else: - logger.info("真寻农场数据库连接已存在,跳过初始化") + logger.debug("真寻农场数据库连接已存在,跳过初始化") return True except Exception as e: logger.error(f"真寻农场数据库连接初始化失败: {e}") @@ -46,10 +46,33 @@ class CSqlManager(ABC): @classmethod async def cleanup(cls): - if cls.m_pDB: - await cls.m_pDB.close() + try: + if not cls.isConnectionValid(): + logger.warning("真寻农场数据库连接已关闭或无效,跳过清理") + return + + if hasattr(cls, "m_pDB") and cls.m_pDB: + await cls.m_pDB.close() + cls.m_pDB = None + cls._initialized = False + logger.debug("真寻农场数据库连接已安全关闭") + else: + logger.debug("真寻农场数据库连接已不存在,无需关闭") + + except Exception as e: + logger.error(f"真寻农场数据库清理过程中出错: {e}") cls.m_pDB = None - logger.info("真寻农场数据库连接已关闭") + cls._initialized = False + + @classmethod + def isConnectionValid(cls) -> bool: + if not hasattr(cls, "m_pDB") or cls.m_pDB is None: + return False + + try: + return hasattr(cls.m_pDB, "_conn") and cls.m_pDB._conn is not None + except: + return False @classmethod def getDB(cls) -> aiosqlite.Connection: diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/resource/background/frame.png b/resource/background/frame.png deleted file mode 100644 index a37e8bb2f804b05cb140ce60ebb50ddca70a2992..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18357 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 diff --git a/utils/__init__.py b/utils/__init__.py index 14a0990..68a2bea 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -1,3 +1,6 @@ +from . import utils + + def getConfig(): from . import config @@ -34,4 +37,5 @@ __all__ = [ "getJsonManager", "getRequestManager", "getToolManager", + "utils", ] diff --git a/utils/darw/drawFarm.py b/utils/darw/drawFarm.py index eb7f556..ff65407 100644 --- a/utils/darw/drawFarm.py +++ b/utils/darw/drawFarm.py @@ -4,8 +4,9 @@ from zhenxun.utils._build_image import BuildImage from zhenxun.utils.image_utils import ImageTemplate from zhenxun.utils.platform import PlatformUtils +from ...core import CPlayer from ...core.dbService import g_pDBService -from .. import config, getJsonManager, getToolManager +from .. import config, getJsonManager, getToolManager, utils class CDarwFarm: @@ -19,7 +20,9 @@ class CDarwFarm: Returns: bytes: 返回绘制结果 """ - img, soilSize, soilPos, grass = await cls.createBaseCanvas() + dynamic = Config.get_config("zhenxun_plugin_farm", "动态背景") + + img, soilSize, soilPos, grass = await cls.createBaseCanvas(dynamic) player = await getToolManager().getPlayerByUid(uid) if not player: @@ -48,20 +51,44 @@ class CDarwFarm: 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]: + async def createBaseCanvas( + cls, dynamic: bool + ) -> tuple[BuildImage, tuple, dict, BuildImage]: """创建基础画布并返回 (img, soilSize, soilPos, grass) Returns: tuple: (主画布, 土地尺寸, 土地坐标映射, 草地图) """ - img = BuildImage( - background=config.g_sResourcePath / "background/background.jpg" - ) + + if dynamic: + season = getToolManager().getSeason() + + backgroundPath = config.g_sResourcePath / "background/decorateIcon" + + # 节日优先级更高 + if season == utils.Season.SPRING: + bgFile = backgroundPath / "decorate_spring_1.jpg" + elif season == utils.Season.SUMMER: + bgFile = backgroundPath / "decorate_summer_1.jpg" + elif season == utils.Season.AUTUMN: + bgFile = backgroundPath / "decorate_autumn_1.jpg" + elif season == utils.Season.WINTER: + bgFile = backgroundPath / "decorate_winter_1.jpg" + else: + bgFile = backgroundPath / "decorate_default_1.jpg" + + img = BuildImage(background=bgFile) + else: + img = BuildImage( + background=config.g_sResourcePath + / "background/decorateIcon/decorate_default_1jpg" + ) soil = await getJsonManager().getSoil() soilSize = soil["size"] @@ -76,17 +103,17 @@ class CDarwFarm: 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))。 + img (BuildImage): 主画布 + uid (str): 用户UID + soilIndex (int): 土地索引(从1开始) + x (int), y (int): 贴图位置 + soilSize: 土地贴图尺寸([w,h] 或 (w,h)) Returns: - bool: 是否有可收获作物(isRipe)。 + bool: 是否有可收获作物(isRipe) """ soilUrl = "soil/普通土地.png" soilInfo = await g_pDBService.userSoil.getUserSoil(uid, soilIndex) @@ -128,10 +155,10 @@ class CDarwFarm: grass: BuildImage, isFirstExpansion: bool, ) -> bool: - """绘制未解锁格子并在首次出现时绘制扩建图标。 + """绘制未解锁格子并在首次出现时绘制扩建图标 Returns: - bool: 是否在此格绘制了扩建图标(仅首次返回 True)。 + bool: 是否在此格绘制了扩建图标(仅首次返回 True) """ await img.paste(grass, (x, y)) @@ -153,7 +180,7 @@ class CDarwFarm: @classmethod async def pasteRipeOnce(cls, img: BuildImage, x: int, y: int, soilSize): - """首次发现成熟作物时贴上成熟提示图(ripe)。""" + """首次发现成熟作物时贴上成熟提示图(ripe)""" ripe = BuildImage(background=config.g_sResourcePath / "background/ripe.png") await img.paste( ripe, @@ -161,22 +188,32 @@ class CDarwFarm: ) @classmethod - async def drawUserInfo(cls, img: BuildImage, player, uid: str): - """绘制左上角用户信息(头像、框、昵称、经验、等级、货币等)。 + async def drawUserInfo(cls, img: BuildImage, player: CPlayer, uid: str): + """绘制左上角用户信息(头像、框、昵称、经验、等级、货币等) TODO 需要详细的绘制头像框 Args: - img (BuildImage): 主画布。 - player: 用户对象(包含 user 字段)。 - uid (str): 用户UID。 + img (BuildImage): 主画布 + player(CPlayer): 用户 + uid (str): 用户Uid """ + # 背景板 + background = BuildImage( + background=config.g_sResourcePath / "background/userInfo.png" + ) + await img.paste(background, (150, 30)) + + # 头像 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") + # 头像框 + frame = BuildImage( + background=config.g_sResourcePath / "background/frame/frame.png" + ) await img.paste(frame, (75, 44)) nameImg = await BuildImage.build_text_image( @@ -214,9 +251,37 @@ class CDarwFarm: ) await img.paste(bondsImg, (570, 255)) + @classmethod + async def drawUserDecorateIcon(cls, img: BuildImage, player: CPlayer) -> bool: + """绘制用户装饰图标 + + Args: + img (BuildImage): 主画布 + player (CPlayer): 用户 + + Returns: + bool: 是否成功绘制 + """ + + decorateIconId = player.user.get("decorateIcon", 0) + if decorateIconId <= 0: + return False + + iconPath = ( + config.g_sResourcePath / f"decorateIcon/DecorateIcon{decorateIconId}.png" + ) + if not iconPath.exists(): + return False + + icon = BuildImage(background=iconPath) + await icon.resize(0, 100, 100) + await img.paste(icon, (x, y)) + + return True + @classmethod async def applyDefinitionResize(cls, img: BuildImage): - """根据配置调整绘制清晰度(original/medium/hight/其他)。""" + """根据配置调整绘制清晰度(original/medium/hight/其他)""" definition = Config.get_config("zhenxun_plugin_farm", "绘制农场清晰度") if definition == "medium": await img.resize(0.6) diff --git a/utils/tool.py b/utils/tool.py index 5976b1a..852525c 100644 --- a/utils/tool.py +++ b/utils/tool.py @@ -5,11 +5,13 @@ from zoneinfo import ZoneInfo from jinja2 import Template from playwright.async_api import async_playwright +from zhdate import ZhDate from zhenxun.services.log import logger from zhenxun.utils.message import MessageUtils from ..core import CPlayer, g_pUserPool +from . import utils class CToolManager: @@ -110,6 +112,47 @@ class CToolManager: tz = ZoneInfo("Asia/Shanghai") return datetime.now(tz) + @classmethod + def getSeason(cls) -> utils.Season: + month = cls.dateTime().month + + if month in [3, 4, 5]: + return utils.Season.SPRING + elif month in [6, 7, 8]: + return utils.Season.SUMMER + elif month in [9, 10, 11]: + return utils.Season.AUTUMN + elif month in [12, 1, 2]: + return utils.Season.WINTER + else: + return utils.Season.NO + + @classmethod + def getFestival(cls) -> utils.Festival: + now = cls.dateTime() + + lunarDate = ZhDate.from_datetime(now) + lunarMonth = lunarDate.lunar_month + lunarDay = lunarDate.lunar_day + + festivalChecks = [ + (1, lambda: lunarMonth == 8 and lunarDay == 15), # 中秋节 + (2, lambda: (now.month, now.day) == (10, 1)), # 国庆节 + (3, lambda: lunarMonth == 1 and lunarDay == 15), # 元宵节 + (4, lambda: lunarMonth == 5 and lunarDay == 5), # 端午节 + (5, lambda: lunarMonth == 1 and lunarDay == 1), # 春节 + (6, lambda: (now.month, now.day) == (10, 31)), # 万圣节 + (7, lambda: (now.month, now.day) == (12, 25)), # 圣诞节 + (8, lambda: (now.month, now.day) == (1, 1)), # 新年 + (9, lambda: (now.month, now.day) == (2, 14)), # 情人节 + ] + + for code, checkFunc in festivalChecks: + if checkFunc(): + return utils.Festival(code) + + return utils.Festival.NO + @classmethod def renderHtmlToFile( cls, path: Path | str, context: dict, output: Path | str diff --git a/utils/utils.py b/utils/utils.py new file mode 100644 index 0000000..4390413 --- /dev/null +++ b/utils/utils.py @@ -0,0 +1,22 @@ +from enum import Enum + + +class Festival(Enum): + NO = 0 # 无节日 + MIDAUTUMN = 1 # 中秋节 + NATIONALDAY = 2 # 国庆节 + LANTERNFESTIVAL = 3 # 元宵节 + DRAGONBOAT = 4 # 端午节 + SPRINGFESTIVAL = 5 # 春节 + HALLOWEEN = 6 # 万圣节 + CHRISTMAS = 7 # 圣诞节 + NEWYEAR = 8 # 新年 + VALENTINE = 9 # 情人节 + + +class Season(Enum): + NO = 0 # 无季节 + SPRING = 1 # 春季 + SUMMER = 2 # 夏季 + AUTUMN = 3 # 秋季 + WINTER = 4 # 冬季