✨ 新增每天00:30检查签到文件
10
__init__.py
@ -1,5 +1,6 @@
|
||||
from nonebot import get_driver
|
||||
from nonebot.plugin import PluginMetadata
|
||||
from nonebot_plugin_apscheduler import scheduler
|
||||
|
||||
from zhenxun.configs.utils import Command, PluginExtraData, RegisterConfig
|
||||
from zhenxun.services.log import logger
|
||||
@ -89,3 +90,12 @@ async def shutdown():
|
||||
await g_pSqlManager.cleanup()
|
||||
|
||||
await g_pDBService.cleanup()
|
||||
|
||||
|
||||
@scheduler.add_job(
|
||||
trigger="cron",
|
||||
hour=0,
|
||||
minute=30,
|
||||
)
|
||||
async def _():
|
||||
await g_pJsonManager.initSignInFile()
|
||||
|
||||
22
command.py
@ -140,6 +140,7 @@ diuse_farm = on_alconna(
|
||||
#Subcommand("sell-point", Args["num?", int], help_text="转换金币")
|
||||
Subcommand("change-name", Args["name?", str], help_text="更改农场名"),
|
||||
Subcommand("sign-in", help_text="农场签到"),
|
||||
Subcommand("admin-up", Args["num?", int], help_text="农场下阶段"),
|
||||
),
|
||||
priority=5,
|
||||
block=True,
|
||||
@ -513,6 +514,11 @@ async def _(session: Uninfo):
|
||||
|
||||
message += f"\n\n成功领取累计签到奖励:\n额外获得经验{extraExp},额外获得金币{extraPoint}"
|
||||
|
||||
vipPoint = reward.get('vipPoint', 0)
|
||||
|
||||
if vipPoint > 0:
|
||||
message += f",额外获得点券{vipPoint}"
|
||||
|
||||
if plant:
|
||||
for key, value in plant.items():
|
||||
message += f"\n获得{key}种子 * {value}"
|
||||
@ -522,3 +528,19 @@ async def _(session: Uninfo):
|
||||
await MessageUtils.build_message(message).send()
|
||||
|
||||
# await MessageUtils.alc_forward_msg([info], session.self_id, BotConfig.self_nickname).send(reply_to=True)
|
||||
|
||||
diuse_farm.shortcut(
|
||||
"农场下阶段(.*?)",
|
||||
command="我的农场",
|
||||
arguments=["admin-up"],
|
||||
prefix=True,
|
||||
)
|
||||
|
||||
@diuse_farm.assign("admin-up")
|
||||
async def _(session: Uninfo, num: Query[int] = AlconnaQuery("num", 0)):
|
||||
uid = str(session.user.id)
|
||||
|
||||
if not await isRegisteredByUid(uid):
|
||||
return
|
||||
|
||||
await g_pDBService.userSoil.nextPhase(uid, num.result)
|
||||
|
||||
@ -2,6 +2,8 @@ from pathlib import Path
|
||||
|
||||
from zhenxun.configs.path_config import DATA_PATH
|
||||
|
||||
g_bIsDebug = True
|
||||
|
||||
g_sDBPath = DATA_PATH / "farm_db"
|
||||
g_sDBFilePath = DATA_PATH / "farm_db/farm.db"
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ import aiosqlite
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
|
||||
from ..config import g_sPlantPath
|
||||
from ..config import g_bIsDebug, g_sPlantPath
|
||||
|
||||
|
||||
class CPlantManager:
|
||||
@ -27,7 +27,12 @@ class CPlantManager:
|
||||
async def init(cls) -> bool:
|
||||
try:
|
||||
_ = os.path.exists(g_sPlantPath)
|
||||
|
||||
if g_bIsDebug:
|
||||
cls.m_pDB = await aiosqlite.connect(str(g_sPlantPath.parent / "plant-test.db"))
|
||||
else:
|
||||
cls.m_pDB = await aiosqlite.connect(str(g_sPlantPath))
|
||||
|
||||
cls.m_pDB.row_factory = aiosqlite.Row
|
||||
return True
|
||||
except Exception as e:
|
||||
|
||||
@ -3,8 +3,8 @@ from typing import List, Union
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
|
||||
from .database import CSqlManager
|
||||
from ..tool import g_pToolManager
|
||||
from .database import CSqlManager
|
||||
|
||||
|
||||
class CUserDB(CSqlManager):
|
||||
@ -16,6 +16,7 @@ class CUserDB(CSqlManager):
|
||||
"name": "TEXT NOT NULL", #农场名称
|
||||
"exp": "INTEGER DEFAULT 0", #经验值
|
||||
"point": "INTEGER DEFAULT 0", #金币
|
||||
"vipPoint": "INTEGER DEFAULT 0", #点券
|
||||
"soil": "INTEGER DEFAULT 3", #解锁土地数量
|
||||
"stealTime": "TEXT DEFAULT NULL", #偷菜时间字符串
|
||||
"stealCount": "INTEGER DEFAULT 0" #剩余偷菜次数
|
||||
@ -203,6 +204,52 @@ class CUserDB(CSqlManager):
|
||||
logger.error("updateUserPointByUid 事务执行失败!", e=e)
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def getUserVipPointByUid(cls, uid: str) -> int:
|
||||
"""获取指定用户点券
|
||||
|
||||
Args:
|
||||
uid (str): 用户Uid
|
||||
|
||||
Returns:
|
||||
int: 点券数量,失败返回 -1
|
||||
"""
|
||||
if not uid:
|
||||
return -1
|
||||
try:
|
||||
async with cls.m_pDB.execute(
|
||||
"SELECT vipPoint FROM user WHERE uid = ?", (uid,)
|
||||
) as cursor:
|
||||
row = await cursor.fetchone()
|
||||
return int(row[0]) if row and row[0] is not None else -1
|
||||
except Exception as e:
|
||||
logger.warning("getUservipPointByUid 查询失败!", e=e)
|
||||
return -1
|
||||
|
||||
@classmethod
|
||||
async def updateUserVipPointByUid(cls, uid: str, vipPoint: int) -> bool:
|
||||
"""根据用户Uid更新农场币数量
|
||||
|
||||
Args:
|
||||
uid (str): 用户Uid
|
||||
vipPoint (int): 新农场币数量
|
||||
|
||||
Returns:
|
||||
bool: 是否更新成功
|
||||
"""
|
||||
if not uid or vipPoint < 0:
|
||||
logger.warning("updateUservipPointByUid 参数校验失败!")
|
||||
return False
|
||||
try:
|
||||
async with cls._transaction():
|
||||
await cls.m_pDB.execute(
|
||||
"UPDATE user SET vipPoint = ? WHERE uid = ?", (vipPoint, uid)
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error("updateUservipPointByUid 事务执行失败!", e=e)
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def getUserExpByUid(cls, uid: str) -> int:
|
||||
"""获取指定用户经验值
|
||||
|
||||
@ -6,6 +6,7 @@ from typing import Optional
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.utils._build_image import BuildImage
|
||||
|
||||
from ..config import g_bIsDebug
|
||||
from ..dbService import g_pDBService
|
||||
from ..json import g_pJsonManager
|
||||
from ..tool import g_pToolManager
|
||||
@ -145,6 +146,7 @@ class CUserSignDB(CSqlManager):
|
||||
|
||||
exp = random.randint(expMin, expMax)
|
||||
point = random.randint(pointMin, pointMax)
|
||||
vipPoint = 0
|
||||
|
||||
async with cls._transaction():
|
||||
await cls.m_pDB.execute(
|
||||
@ -193,6 +195,7 @@ class CUserSignDB(CSqlManager):
|
||||
if reward:
|
||||
point += reward.get('point', 0)
|
||||
exp += reward.get('exp', 0)
|
||||
vipPoint = reward.get('vipPoint', 0)
|
||||
|
||||
plant = reward.get('plant', {})
|
||||
|
||||
@ -200,6 +203,9 @@ class CUserSignDB(CSqlManager):
|
||||
for key, value in plant.items():
|
||||
await g_pDBService.userSeed.addUserSeedByUid(uid, key, value)
|
||||
|
||||
if g_bIsDebug:
|
||||
exp += 9999
|
||||
|
||||
#向数据库更新
|
||||
currentExp = await g_pDBService.user.getUserExpByUid(uid)
|
||||
await g_pDBService.user.updateUserExpByUid(uid, currentExp + exp)
|
||||
@ -207,6 +213,10 @@ class CUserSignDB(CSqlManager):
|
||||
currentPoint = await g_pDBService.user.getUserPointByUid(uid)
|
||||
await g_pDBService.user.updateUserPointByUid(uid, currentPoint + point)
|
||||
|
||||
if vipPoint > 0:
|
||||
currentVipPoint = await g_pDBService.user.getUserVipPointByUid(uid)
|
||||
await g_pDBService.user.updateUserVipPointByUid(uid, currentVipPoint + vipPoint)
|
||||
|
||||
return 1
|
||||
except Exception as e:
|
||||
logger.warning("执行签到失败", e=e)
|
||||
|
||||
@ -2,6 +2,7 @@ from typing import Optional
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
|
||||
from ..config import g_bIsDebug
|
||||
from ..dbService import g_pDBService
|
||||
from ..json import g_pJsonManager
|
||||
from ..tool import g_pToolManager
|
||||
@ -29,6 +30,46 @@ class CUserSoilDB(CSqlManager):
|
||||
|
||||
await cls.ensureTableSchema("userSoil", userSoil)
|
||||
|
||||
@classmethod
|
||||
async def nextPhase(cls, uid: str, soilIndex: int):
|
||||
"""将指定地块的作物进入下个阶段
|
||||
|
||||
Args:
|
||||
soilIndex (int): 地块索引 从1开始
|
||||
"""
|
||||
if not g_bIsDebug:
|
||||
return
|
||||
|
||||
soilInfo = await cls.getUserSoil(uid, soilIndex)
|
||||
|
||||
if not soilInfo:
|
||||
return
|
||||
|
||||
plantInfo = await g_pDBService.plant.getPlantByName(soilInfo['plantName'])
|
||||
|
||||
if not plantInfo:
|
||||
return
|
||||
|
||||
currentTime = g_pToolManager.dateTime().now()
|
||||
matureTime = g_pToolManager.dateTime().fromtimestamp(int(soilInfo['matureTime']))
|
||||
|
||||
phase = await g_pDBService.plant.getPlantPhaseNumberByName(soilInfo['plantName'])
|
||||
phaseList = await g_pDBService.plant.getPlantPhaseByName(soilInfo['plantName'])
|
||||
|
||||
if currentTime >= matureTime:
|
||||
return
|
||||
|
||||
plantedTime = g_pToolManager.dateTime().fromtimestamp(int(soilInfo['plantTime']))
|
||||
|
||||
elapsedTime = currentTime - plantedTime
|
||||
elapsedHour = elapsedTime.total_seconds() / 3600
|
||||
|
||||
currentStage = int(elapsedHour / (plantInfo['time'] / phase))
|
||||
|
||||
t = int(soilInfo['plantTime']) - phaseList[currentStage]
|
||||
|
||||
await cls.updateUserSoil(uid, soilIndex, "plantTime", t)
|
||||
|
||||
@classmethod
|
||||
async def getUserFarmByUid(cls, uid: str) -> dict:
|
||||
"""获取指定用户的旧农场数据
|
||||
|
||||
36
farm/farm.py
@ -11,7 +11,7 @@ from zhenxun.utils.enum import GoldHandle
|
||||
from zhenxun.utils.image_utils import ImageTemplate
|
||||
from zhenxun.utils.platform import PlatformUtils
|
||||
|
||||
from ..config import g_sResourcePath
|
||||
from ..config import g_bIsDebug, g_sResourcePath
|
||||
from ..dbService import g_pDBService
|
||||
from ..event.event import g_pEventManager
|
||||
from ..json import g_pJsonManager
|
||||
@ -88,11 +88,11 @@ class CFarmManager:
|
||||
if index < soilUnlock:
|
||||
await img.paste(soil, (x, y))
|
||||
|
||||
isPlant, plant, isRipe= await cls.drawSoilPlant(uid, index + 1)
|
||||
isPlant, plant, isRipe, offsetX, offsetY = await cls.drawSoilPlant(uid, index + 1)
|
||||
|
||||
if isPlant:
|
||||
await img.paste(plant, (x + soilSize[0] // 2 - plant.width // 2,
|
||||
y + soilSize[1] // 2 - plant.height // 2))
|
||||
await img.paste(plant, (x + soilSize[0] // 2 - plant.width // 2 + offsetX,
|
||||
y + soilSize[1] // 2 - plant.height // 2 + offsetY))
|
||||
|
||||
#1700 275
|
||||
#首次添加可收获图片
|
||||
@ -258,7 +258,7 @@ class CFarmManager:
|
||||
return info
|
||||
|
||||
@classmethod
|
||||
async def drawSoilPlant(cls, uid: str, soilIndex: int) -> tuple[bool, BuildImage, bool]:
|
||||
async def drawSoilPlant(cls, uid: str, soilIndex: int) -> tuple[bool, BuildImage, bool, int, int]:
|
||||
"""绘制植物资源
|
||||
|
||||
Args:
|
||||
@ -279,13 +279,18 @@ class CFarmManager:
|
||||
if int(soilInfo.get("wiltStatus", 0)) == 1:
|
||||
plant = BuildImage(background = g_sResourcePath / f"plant/basic/9.png")
|
||||
await plant.resize(0, 150, 212)
|
||||
return True, plant, False
|
||||
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 #type: ignore
|
||||
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()
|
||||
matureTime = g_pToolManager.dateTime().fromtimestamp(int(soilInfo['matureTime']))
|
||||
@ -296,13 +301,13 @@ class CFarmManager:
|
||||
if currentTime >= matureTime:
|
||||
plant = BuildImage(background = g_sResourcePath / f"plant/{soilInfo['plantName']}/{phase}.png")
|
||||
|
||||
return True, plant, True
|
||||
return True, plant, True, offsetX, offsetY
|
||||
else:
|
||||
#如果是多阶段作物 且没有成熟 #早期思路 多阶段作物 直接是倒数第二阶段图片
|
||||
# if soilInfo['harvestCount'] >= 1:
|
||||
# plant = BuildImage(background = g_sResourcePath / f"plant/{soilInfo['plantName']}/{plantInfo['phase'] - 1s}.png")
|
||||
|
||||
# return True, plant, False
|
||||
# return True, plant, False, offsetX, offsetY
|
||||
|
||||
#如果没有成熟 则根据当前阶段进行绘制
|
||||
plantedTime = g_pToolManager.dateTime().fromtimestamp(int(soilInfo['plantTime']))
|
||||
@ -318,11 +323,11 @@ class CFarmManager:
|
||||
else:
|
||||
plant = BuildImage(background = g_sResourcePath / f"plant/basic/0.png")
|
||||
|
||||
await plant.resize(0, 35, 58)
|
||||
await plant.resize(0, 35 + offsetW, 58 + offsetH)
|
||||
else:
|
||||
plant = BuildImage(background = g_sResourcePath / f"plant/{soilInfo['plantName']}/{currentStage}.png")
|
||||
|
||||
return True, plant, False
|
||||
return True, plant, False, offsetX, offsetY
|
||||
|
||||
@classmethod
|
||||
async def getUserSeedByUid(cls, uid: str) -> bytes:
|
||||
@ -568,6 +573,9 @@ class CFarmManager:
|
||||
|
||||
experience += 3
|
||||
|
||||
if g_bIsDebug:
|
||||
experience += 999
|
||||
|
||||
#批量更新数据库操作
|
||||
await g_pDBService.userSoil.deleteUserSoil(uid, i)
|
||||
|
||||
@ -775,13 +783,13 @@ class CFarmManager:
|
||||
|
||||
str = ""
|
||||
if len(item) == 0:
|
||||
str = f"下次升级所需条件:等级:{level},农场币:{point}"
|
||||
str = f"下次开垦所需条件:等级:{level},农场币:{point}"
|
||||
else:
|
||||
str = f"下次升级所需条件:等级:{level},农场币:{point},物品:{item}"
|
||||
str = f"下次开垦所需条件:等级:{level},农场币:{point},物品:{item}"
|
||||
|
||||
return str
|
||||
except Exception as e:
|
||||
return "获取升级土地条件失败!"
|
||||
return "获取开垦土地条件失败!"
|
||||
|
||||
@classmethod
|
||||
async def reclamation(cls, uid: str) -> str:
|
||||
|
||||
15
json.py
@ -24,12 +24,7 @@ class CJsonManager:
|
||||
if not await self.initSoil():
|
||||
return False
|
||||
|
||||
if not await g_pRequestManager.initSignInFile():
|
||||
config.g_bSignStatus = False
|
||||
|
||||
return False
|
||||
else:
|
||||
return await self.initSign()
|
||||
return await self.initSignInFile()
|
||||
|
||||
async def initItem(self) -> bool:
|
||||
try:
|
||||
@ -79,6 +74,14 @@ class CJsonManager:
|
||||
logger.warning(f"soil.json JSON格式错误: {e}")
|
||||
return False
|
||||
|
||||
async def initSignInFile(self) -> bool:
|
||||
if not await g_pRequestManager.initSignInFile():
|
||||
config.g_bSignStatus = False
|
||||
|
||||
return False
|
||||
else:
|
||||
return await self.initSign()
|
||||
|
||||
async def initSign(self) -> bool:
|
||||
try:
|
||||
with open(
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
---
|
||||
- 修正了多阶段作物成长素材计算逻辑
|
||||
- 修正了作物数据库字段错乱的问题
|
||||
- 作物新增offset字段,用于以后偏移坐标(尚未加入代码 TODO
|
||||
- 作物新增offset字段,用于以后偏移坐标
|
||||
|
||||
## V1.3
|
||||
用户方面
|
||||
|
||||
BIN
resource/db/plant-test.db
Normal file
BIN
resource/plant/园艺世/1.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
resource/plant/园艺世/2.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
resource/plant/园艺世/3.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
resource/plant/园艺世/4.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
resource/plant/园艺世/5.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
resource/plant/园艺世/icon.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
resource/plant/蜜思桃/1.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
resource/plant/蜜思桃/2.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
resource/plant/蜜思桃/3.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
resource/plant/蜜思桃/4.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
resource/plant/蜜思桃/5.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
resource/plant/蜜思桃/icon.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
resource/plant/香粽龙舟/0.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 34 KiB |
BIN
resource/plant/香粽龙舟/icon.png
Normal file
|
After Width: | Height: | Size: 27 KiB |