搬运了原版食材 原版锅铲贴图 去掉了旧版锅铲锅勺
This commit is contained in:
1 parent
991239bc26
commit
f00601f7ad
93 files changed
+1779
-1164
No files matched your search
+266
@@ -0,0 +1,266 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
================================================================================
|
||||
动物养殖·计时转换引擎(服务端)
|
||||
================================================================================
|
||||
只处理"动物养殖"(xy_animal) 分类下的【计时自动转换】:
|
||||
饲料盆/饲料槽装满后,随时间逐级变空(如 满→半量→空)。
|
||||
|
||||
【与右键转换解耦】
|
||||
同分类的"右键切换"(放蛋/取蛋/填充饲料/清理粪便)在 AnimalService。
|
||||
本类只负责计时,两者通过 FeatureDispatcher 协作:
|
||||
- AnimalService 填充完饲料发现计时源方块 → 调 FeatureDispatcher.startTimerFor
|
||||
转发到本类的 startTimer 启动计时
|
||||
- 服务器 tick(ServerBlockEntityTickEvent)由 FeatureDispatcher 按 timerOwner
|
||||
路由到本类的 handleBlockEntityTick,到点即转换
|
||||
|
||||
【计时怎么做到"退出游戏继续计时"】
|
||||
不做倒计时,只记"开始时刻":
|
||||
- 启动时把 开始时间戳(rtdd_tstart)+总时长(rtdd_tdur) 写进方块实体数据
|
||||
- 每帧 tick 判断 当前时间-开始时刻 >= 总时长 → 到点转换
|
||||
- 时间戳是绝对时间(time.time()),服务器重启/玩家离线,真实时间仍在流逝,
|
||||
回来后 tick 直接算差值,剩余时间自然准确(如烤了40秒退出,回来只剩20秒)
|
||||
|
||||
【事件监听在哪?】
|
||||
本类【不】监听任何事件!
|
||||
ServerBlockEntityTickEvent 由 FeatureDispatcher 统一监听,再按 timerOwner
|
||||
路由到本类的 handleBlockEntityTick。
|
||||
|
||||
【本类怎么做(自上而下的方法系列)】
|
||||
handleBlockEntityTick ← 入口:分发器转发 tick 事件
|
||||
└─ _tickProcess ← 判断是否到点 / 放置自动补写计时(autoStart)
|
||||
└─ _finishTimer ← 到点执行转换,链式续计时或结束提示
|
||||
└─ _notifyIfOnline ← 完成提示(启动者在线才发)
|
||||
startTimer ← 入口:AnimalService 转发过来启动计时
|
||||
└─ _writeTimerData ← 写 开始时刻+时长+启动者 到方块实体
|
||||
_clearTimerData ← 清理方块上的计时数据
|
||||
================================================================================
|
||||
"""
|
||||
import time
|
||||
import mod.server.extraServerApi as serverApi
|
||||
|
||||
# ---- 网易API基础对象 ----
|
||||
ServerSystem = serverApi.GetServerSystemCls() # 服务端系统基类
|
||||
comp = serverApi.GetEngineCompFactory() # 组件工厂
|
||||
|
||||
# ---- 继承 BlueFox 框架的系统基类 ----
|
||||
from ....BlueFoxTools.SpecialFunciton.BlueFoxSystem import BlueFoxServerSystem
|
||||
from ....BlueFoxTools.ToolsConfig import LevelId
|
||||
|
||||
# ---- 方块实体数据组件(计时持久化:把开始时间戳+时长写进方块,重启后继续计时) ----
|
||||
blockEntityDataComp = comp.CreateBlockEntityData(LevelId)
|
||||
|
||||
# ---- 只导入动物养殖自己的数据库 ----
|
||||
from ..AnimalData import ANIMAL_SWITCHES
|
||||
|
||||
# ---- 统一分发器(本类把自己注册进计时路由表,让分发器把 tick 事件转发过来) ----
|
||||
from ...service.FeatureDispatcher import FeatureDispatcher
|
||||
|
||||
|
||||
class AnimalTimerService(BlueFoxServerSystem):
|
||||
"""
|
||||
动物养殖·计时转换引擎
|
||||
|
||||
【核心数据结构】
|
||||
animalTimers = {计时源方块名: 规则dict} # 只收 type=="timer" 的规则
|
||||
"""
|
||||
|
||||
def __init__(self, namespace, systemName):
|
||||
"""
|
||||
初始化:收集计时型规则,并注册到统一分发器的计时路由表。
|
||||
"""
|
||||
super(AnimalTimerService, self).__init__(namespace, systemName)
|
||||
print "===== AnimalTimerService init ====="
|
||||
|
||||
# ---- 只收集计时型规则(source → 规则) ----
|
||||
self.animalTimers = {}
|
||||
for sw in ANIMAL_SWITCHES:
|
||||
if sw.get("type") == "timer":
|
||||
self.animalTimers[sw["source"]] = sw
|
||||
|
||||
# ---- 注册到分发器的计时路由表(tick 事件按方块名路由到这里) ----
|
||||
FeatureDispatcher.registerTimer(self)
|
||||
|
||||
# ============================================================================
|
||||
# 一、给 FeatureDispatcher 的接口
|
||||
# ============================================================================
|
||||
|
||||
def getTimerBlocks(self):
|
||||
"""
|
||||
返回本功能的所有"计时源方块"集合。
|
||||
FeatureDispatcher 靠它构建 方块名→本实例 的计时路由表(timerOwner)。
|
||||
"""
|
||||
return set(self.animalTimers.keys())
|
||||
|
||||
def handleBlockEntityTick(self, args):
|
||||
"""
|
||||
由 FeatureDispatcher 转发的计时方块 tick 入口。
|
||||
只有 blockName 在计时路由表里才会被调用。
|
||||
"""
|
||||
dim = args.get("dimension")
|
||||
pos = (args.get("posX"), args.get("posY"), args.get("posZ"))
|
||||
blockName = args.get("blockName", "")
|
||||
self._tickProcess(dim, pos, blockName)
|
||||
|
||||
# ============================================================================
|
||||
# 二、计时启动(AnimalService 填充完饲料后转发调用 / 右键计时源方块)
|
||||
# ============================================================================
|
||||
|
||||
def startTimer(self, dim, pos, blockName, playerId=None):
|
||||
"""
|
||||
启动计时:把 计时标识+开始时间戳+时长 写入方块实体数据。
|
||||
- 已处于本规则计时中的方块不会重复重置时间(保持原剩余时间)
|
||||
- 动物计时 autoStart 默认 True:放置/填充后自动开始(tick 也会自动补写)
|
||||
"""
|
||||
recipe = self.animalTimers.get(blockName)
|
||||
if not recipe:
|
||||
return
|
||||
# 去重:如果该方块已经在本规则计时中,不重置(保持原剩余时间)
|
||||
try:
|
||||
data = blockEntityDataComp.GetBlockEntityData(dim, pos)
|
||||
if data and data["rtdd_tid"] == blockName:
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
self._writeTimerData(dim, pos, recipe, playerId)
|
||||
# 计时开始提示
|
||||
if playerId and recipe.get("startTip"):
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(playerId, recipe["startTip"])
|
||||
|
||||
# ============================================================================
|
||||
# 三、tick 检查与到点转换
|
||||
# ============================================================================
|
||||
|
||||
def _tickProcess(self, dim, pos, blockName):
|
||||
"""
|
||||
tick 主逻辑:
|
||||
1) 按事件自带的当前方块名判断是否计时源(创造直接放置也会进来)
|
||||
2) 是计时源但没有计时数据 → 自动补写计时(放置即开始计时)
|
||||
3) 有计时数据 → 到点执行转换(重启后时间戳照常生效)
|
||||
方块被拆掉后 tick 停止、数据随方块消失,不会在原位置继续计时转换。
|
||||
注意:GetBlockEntityData 返回的对象不支持 .get(),这里统一用 [] 读取。
|
||||
"""
|
||||
try:
|
||||
recipe = self.animalTimers.get(blockName)
|
||||
if not recipe:
|
||||
return # 当前方块不是计时源(tick 只对计时源方块开启)
|
||||
|
||||
blockData = blockEntityDataComp.GetBlockEntityData(dim, pos)
|
||||
if blockData is None:
|
||||
return
|
||||
|
||||
# 读取计时标识;没有或与当前方块不符
|
||||
try:
|
||||
tid = blockData["rtdd_tid"]
|
||||
except Exception:
|
||||
tid = ""
|
||||
if tid != blockName:
|
||||
# 放置即自动计时:默认开启(动物饲料盆/饲料槽)
|
||||
# 若某条规则 autoStart=False 则必须右键激活,这里不补写
|
||||
if recipe.get("autoStart", True):
|
||||
self._writeTimerData(dim, pos, recipe, None)
|
||||
return
|
||||
|
||||
tstart = blockData["rtdd_tstart"]
|
||||
tdur = blockData["rtdd_tdur"]
|
||||
|
||||
if time.time() - tstart >= tdur:
|
||||
self._finishTimer(dim, pos, recipe, blockData)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _finishTimer(self, dim, pos, recipe, data):
|
||||
"""
|
||||
计时到点:确认方块仍是计时源后替换方块。
|
||||
- 若新方块是下一级计时源 → 写入新计时数据继续(如 满→半量→空)
|
||||
- 若整条链结束 → 清除计时数据,并给启动者发送完成提示
|
||||
"""
|
||||
try:
|
||||
cur = comp.CreateBlockInfo(LevelId).GetBlockNew(pos, dim)
|
||||
if cur and cur.get("name") != recipe["source"]:
|
||||
# 方块已被玩家改变 → 清掉过期计时
|
||||
self._clearTimerData(dim, pos)
|
||||
return
|
||||
# 替换方块
|
||||
self.replaceBlock(pos, dim, recipe["target"], None)
|
||||
nextRecipe = self.animalTimers.get(recipe["target"])
|
||||
if nextRecipe:
|
||||
# 下一级计时(换新的开始时间戳)
|
||||
self._writeTimerData(dim, pos, nextRecipe, data["rtdd_tp"])
|
||||
else:
|
||||
# 整条链结束:清数据 + 完成提示
|
||||
self._clearTimerData(dim, pos)
|
||||
doneTip = recipe.get("doneTip")
|
||||
if doneTip:
|
||||
self._notifyIfOnline(data["rtdd_tp"], doneTip)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ============================================================================
|
||||
# 四、计时数据读写(存在方块实体数据里,重启不丢)
|
||||
# ============================================================================
|
||||
|
||||
def _writeTimerData(self, dim, pos, recipe, playerId=None):
|
||||
"""把 计时标识+开始时刻+时长+启动者 写进方块实体数据"""
|
||||
try:
|
||||
blockData = blockEntityDataComp.GetBlockEntityData(dim, pos)
|
||||
if blockData is None:
|
||||
return
|
||||
now = time.time()
|
||||
blockData["rtdd_tid"] = recipe["source"]
|
||||
blockData["rtdd_tstart"] = now
|
||||
blockData["rtdd_tdur"] = recipe.get("time", 60)
|
||||
blockData["rtdd_tp"] = playerId if playerId else ""
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _clearTimerData(self, dim, pos):
|
||||
"""清除方块上的计时数据"""
|
||||
try:
|
||||
blockData = blockEntityDataComp.GetBlockEntityData(dim, pos)
|
||||
if blockData is None:
|
||||
return
|
||||
blockData["rtdd_tid"] = ""
|
||||
blockData["rtdd_tstart"] = 0
|
||||
blockData["rtdd_tdur"] = 0
|
||||
blockData["rtdd_tp"] = ""
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ============================================================================
|
||||
# 五、工具方法:完成提示
|
||||
# ============================================================================
|
||||
|
||||
def _notifyIfOnline(self, playerId, tip):
|
||||
"""若启动者在线,发送完成提示(离线则跳过)"""
|
||||
if not tip or not playerId:
|
||||
return
|
||||
try:
|
||||
ids = comp.CreateGame(LevelId).GetAllPlayerIds()
|
||||
if playerId in ids:
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(playerId, tip)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ============================================================================
|
||||
# 六、工具方法:替换方块
|
||||
# ============================================================================
|
||||
|
||||
def replaceBlock(self, pos, dim, newBlockName, playerId, aux=None):
|
||||
"""
|
||||
替换指定位置的方块。
|
||||
newBlockName="minecraft:air" 表示清除该方块。
|
||||
playerId 可为 None(计时回调时没有玩家),用 LevelId 创建组件。
|
||||
"""
|
||||
creator = playerId if playerId is not None else LevelId
|
||||
if aux is None:
|
||||
try:
|
||||
oldBlock = comp.CreateBlockInfo(creator).GetBlockNew(pos, dim)
|
||||
aux = oldBlock.get("aux", 0)
|
||||
except Exception:
|
||||
aux = 0
|
||||
comp.CreateBlockInfo(creator).SetBlockNew(
|
||||
pos,
|
||||
blockDict={"name": newBlockName, "aux": aux},
|
||||
oldBlockHandling=0,
|
||||
dimensionId=dim)
|
||||
+301
@@ -0,0 +1,301 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
================================================================================
|
||||
烧烤·计时转换引擎(服务端)
|
||||
================================================================================
|
||||
只处理"烧烤"(xy_barbecue) 分类下的【计时自动转换】:
|
||||
烤鸡/烤乳猪/烤鳕鱼/烤鲑鱼 上杆后,下方放篝火,计时自动烤熟。
|
||||
|
||||
【与右键转换解耦】
|
||||
同分类的"右键切换"(烧烤架点火/灭火、烤串翻烤、上杆、取下)在 BarbecueService。
|
||||
本类只负责计时,两者通过 FeatureDispatcher 协作:
|
||||
- BarbecueService 右键"计时源方块"(如烤鸡(生))→ 调 FeatureDispatcher.startTimerFor
|
||||
转发到本类的 startTimer 启动烤制(下方篝火检查也在这里做)
|
||||
- 服务器 tick(ServerBlockEntityTickEvent)由 FeatureDispatcher 按 timerOwner
|
||||
路由到本类的 handleBlockEntityTick,到点即烤熟
|
||||
|
||||
【烤制规则】
|
||||
- autoStart=False:上杆/放置后【不会】自动开始烤制,必须右键激活(startTimer)
|
||||
- 启动前检查下方是否为篝火(minecraft:campfire),不是则拒绝并提示
|
||||
- 烤制中若下方篝火被拿走 → 暂停(到点时不转换);篝火放回后继续
|
||||
- 完成后清除计时数据,并给"启动烤制的玩家"发送"烤熟了"提示
|
||||
|
||||
【计时怎么做到"退出游戏继续计时"】
|
||||
不做倒计时,只记"开始时刻":
|
||||
- 启动时把 开始时间戳(rtdd_tstart)+总时长(rtdd_tdur) 写进方块实体数据
|
||||
- 每帧 tick 判断 当前时间-开始时刻 >= 总时长 → 到点转换
|
||||
- 时间戳是绝对时间(time.time()),服务器重启/玩家离线,真实时间仍在流逝,
|
||||
回来后 tick 直接算差值,剩余时间自然准确(如烤了40秒退出,回来只剩20秒)
|
||||
|
||||
【事件监听在哪?】
|
||||
本类【不】监听任何事件!
|
||||
ServerBlockEntityTickEvent 由 FeatureDispatcher 统一监听,再按 timerOwner
|
||||
路由到本类的 handleBlockEntityTick。
|
||||
|
||||
【本类怎么做(自上而下的方法系列)】
|
||||
handleBlockEntityTick ← 入口:分发器转发 tick 事件
|
||||
└─ _tickProcess ← 判断是否到点 / autoStart=False 不自动补写
|
||||
└─ _finishTimer ← 到点执行转换(重新检查篝火,否则暂停)
|
||||
└─ _notifyIfOnline ← 完成提示(启动者在线才发)
|
||||
startTimer ← 入口:BarbecueService 转发过来启动烤制
|
||||
├─ checkBelow ← 下方篝火检查(失败拒绝并提示)
|
||||
└─ _writeTimerData ← 写 开始时刻+时长+启动者 到方块实体
|
||||
_clearTimerData ← 清理方块上的计时数据
|
||||
================================================================================
|
||||
"""
|
||||
import time
|
||||
import mod.server.extraServerApi as serverApi
|
||||
|
||||
# ---- 网易API基础对象 ----
|
||||
ServerSystem = serverApi.GetServerSystemCls() # 服务端系统基类
|
||||
comp = serverApi.GetEngineCompFactory() # 组件工厂
|
||||
|
||||
# ---- 继承 BlueFox 框架的系统基类 ----
|
||||
from ....BlueFoxTools.SpecialFunciton.BlueFoxSystem import BlueFoxServerSystem
|
||||
from ....BlueFoxTools.ToolsConfig import LevelId
|
||||
|
||||
# ---- 方块实体数据组件(计时持久化:把开始时间戳+时长写进方块,重启后继续计时) ----
|
||||
blockEntityDataComp = comp.CreateBlockEntityData(LevelId)
|
||||
|
||||
# ---- 只导入烧烤自己的数据库 ----
|
||||
from ..BarbecueData import BARBECUE_SWITCHES
|
||||
|
||||
# ---- 统一分发器(本类把自己注册进计时路由表,让分发器把 tick 事件转发过来) ----
|
||||
from ...service.FeatureDispatcher import FeatureDispatcher
|
||||
|
||||
|
||||
class BarbecueTimerService(BlueFoxServerSystem):
|
||||
"""
|
||||
烧烤·计时转换引擎
|
||||
|
||||
【核心数据结构】
|
||||
barbecueTimers = {计时源方块名: 规则dict} # 只收 type=="timer" 的规则
|
||||
"""
|
||||
|
||||
def __init__(self, namespace, systemName):
|
||||
"""
|
||||
初始化:收集计时型规则,并注册到统一分发器的计时路由表。
|
||||
"""
|
||||
super(BarbecueTimerService, self).__init__(namespace, systemName)
|
||||
print "===== BarbecueTimerService init ====="
|
||||
|
||||
# ---- 只收集计时型规则(source → 规则) ----
|
||||
self.barbecueTimers = {}
|
||||
for sw in BARBECUE_SWITCHES:
|
||||
if sw.get("type") == "timer":
|
||||
self.barbecueTimers[sw["source"]] = sw
|
||||
|
||||
# ---- 注册到分发器的计时路由表(tick 事件按方块名路由到这里) ----
|
||||
FeatureDispatcher.registerTimer(self)
|
||||
|
||||
# ============================================================================
|
||||
# 一、给 FeatureDispatcher 的接口
|
||||
# ============================================================================
|
||||
|
||||
def getTimerBlocks(self):
|
||||
"""
|
||||
返回本功能的所有"计时源方块"集合。
|
||||
FeatureDispatcher 靠它构建 方块名→本实例 的计时路由表(timerOwner)。
|
||||
"""
|
||||
return set(self.barbecueTimers.keys())
|
||||
|
||||
def handleBlockEntityTick(self, args):
|
||||
"""
|
||||
由 FeatureDispatcher 转发的计时方块 tick 入口。
|
||||
只有 blockName 在计时路由表里才会被调用。
|
||||
"""
|
||||
dim = args.get("dimension")
|
||||
pos = (args.get("posX"), args.get("posY"), args.get("posZ"))
|
||||
blockName = args.get("blockName", "")
|
||||
self._tickProcess(dim, pos, blockName)
|
||||
|
||||
# ============================================================================
|
||||
# 二、烤制启动(BarbecueService 右键"计时源方块"后转发调用)
|
||||
# ============================================================================
|
||||
|
||||
def startTimer(self, dim, pos, blockName, playerId=None):
|
||||
"""
|
||||
启动烤制计时:先检查下方篝火,通过后写 开始时间戳+时长 到方块实体数据。
|
||||
- 启动前检查:下方不是篝火 → 拒绝并提示(烧烤必须右键激活,不会自动烤)
|
||||
- 已在本规则计时中的方块不会重复重置时间(保持原剩余时间)
|
||||
"""
|
||||
recipe = self.barbecueTimers.get(blockName)
|
||||
if not recipe:
|
||||
return
|
||||
|
||||
# 启动前检查下方篝火(烧烤必须下方是篝火才能开始烤制)
|
||||
if not self.checkBelow(recipe, dim, pos):
|
||||
if playerId:
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(playerId, "§c支杆下方需要放一个篝火(营火)才能烤制!")
|
||||
return
|
||||
|
||||
# 去重:如果该方块已经在本规则计时中,不重置(保持原剩余时间)
|
||||
try:
|
||||
data = blockEntityDataComp.GetBlockEntityData(dim, pos)
|
||||
if data and data["rtdd_tid"] == blockName:
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
self._writeTimerData(dim, pos, recipe, playerId)
|
||||
# 烤制开始提示
|
||||
if playerId and recipe.get("startTip"):
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(playerId, recipe["startTip"])
|
||||
|
||||
# ============================================================================
|
||||
# 三、tick 检查与到点转换
|
||||
# ============================================================================
|
||||
|
||||
def _tickProcess(self, dim, pos, blockName):
|
||||
"""
|
||||
tick 主逻辑:
|
||||
1) 按事件自带的当前方块名判断是否计时源(创造直接放置也会进来)
|
||||
2) 是计时源但没有计时数据 → 只有 autoStart=True 才自动补写。
|
||||
烧烤 autoStart=False:上杆后不会自动烤,必须右键激活,这里不补写
|
||||
3) 有计时数据 → 到点执行转换(重启后时间戳照常生效)
|
||||
方块被拆掉后 tick 停止、数据随方块消失,不会在原位置继续计时转换。
|
||||
注意:GetBlockEntityData 返回的对象不支持 .get(),这里统一用 [] 读取。
|
||||
"""
|
||||
try:
|
||||
recipe = self.barbecueTimers.get(blockName)
|
||||
if not recipe:
|
||||
return # 当前方块不是计时源(tick 只对计时源方块开启)
|
||||
|
||||
blockData = blockEntityDataComp.GetBlockEntityData(dim, pos)
|
||||
if blockData is None:
|
||||
return
|
||||
|
||||
# 读取计时标识;没有或与当前方块不符
|
||||
try:
|
||||
tid = blockData["rtdd_tid"]
|
||||
except Exception:
|
||||
tid = ""
|
||||
if tid != blockName:
|
||||
# 烧烤必须右键激活烤制:autoStart=False 时不自动补写计时
|
||||
if recipe.get("autoStart", True):
|
||||
self._writeTimerData(dim, pos, recipe, None)
|
||||
return
|
||||
|
||||
tstart = blockData["rtdd_tstart"]
|
||||
tdur = blockData["rtdd_tdur"]
|
||||
|
||||
if time.time() - tstart >= tdur:
|
||||
self._finishTimer(dim, pos, recipe, blockData)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _finishTimer(self, dim, pos, recipe, data):
|
||||
"""
|
||||
计时到点:确认方块仍是计时源、下方仍有篝火,才执行转换。
|
||||
- 篝火被拿走 → 暂停烤制(不转换),等篝火回来继续
|
||||
- 烤熟后清除计时数据,并给启动者发送"烤熟了"提示
|
||||
"""
|
||||
try:
|
||||
cur = comp.CreateBlockInfo(LevelId).GetBlockNew(pos, dim)
|
||||
if cur and cur.get("name") != recipe["source"]:
|
||||
# 方块已被玩家改变 → 清掉过期计时
|
||||
self._clearTimerData(dim, pos)
|
||||
return
|
||||
if not self.checkBelow(recipe, dim, pos):
|
||||
return # 篝火被拿走了,暂停烤制,等篝火回来继续
|
||||
# 替换方块
|
||||
self.replaceBlock(pos, dim, recipe["target"], None)
|
||||
nextRecipe = self.barbecueTimers.get(recipe["target"])
|
||||
if nextRecipe:
|
||||
# 下一级计时(换新的开始时间戳)
|
||||
self._writeTimerData(dim, pos, nextRecipe, data["rtdd_tp"])
|
||||
else:
|
||||
# 整条链结束:清数据 + 完成提示
|
||||
self._clearTimerData(dim, pos)
|
||||
doneTip = recipe.get("doneTip")
|
||||
if doneTip:
|
||||
self._notifyIfOnline(data["rtdd_tp"], doneTip)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ============================================================================
|
||||
# 四、下方方块检查(计时烤制专用:下方必须是篝火)
|
||||
# ============================================================================
|
||||
|
||||
def checkBelow(self, recipe, dim, pos):
|
||||
"""
|
||||
检查方块下方是否为 recipe["below"] 中指定的方块(如 minecraft:campfire)。
|
||||
没写 below 字段 → 视为满足。
|
||||
"""
|
||||
below = recipe.get("below")
|
||||
if not below:
|
||||
return True
|
||||
belowPos = (pos[0], pos[1] - 1, pos[2])
|
||||
try:
|
||||
b = comp.CreateBlockInfo(LevelId).GetBlockNew(belowPos, dim)
|
||||
return b.get("name") in below
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
# ============================================================================
|
||||
# 五、计时数据读写(存在方块实体数据里,重启不丢)
|
||||
# ============================================================================
|
||||
|
||||
def _writeTimerData(self, dim, pos, recipe, playerId=None):
|
||||
"""把 计时标识+开始时刻+时长+启动者 写进方块实体数据"""
|
||||
try:
|
||||
blockData = blockEntityDataComp.GetBlockEntityData(dim, pos)
|
||||
if blockData is None:
|
||||
return
|
||||
now = time.time()
|
||||
blockData["rtdd_tid"] = recipe["source"]
|
||||
blockData["rtdd_tstart"] = now
|
||||
blockData["rtdd_tdur"] = recipe.get("time", 60)
|
||||
blockData["rtdd_tp"] = playerId if playerId else ""
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _clearTimerData(self, dim, pos):
|
||||
"""清除方块上的计时数据"""
|
||||
try:
|
||||
blockData = blockEntityDataComp.GetBlockEntityData(dim, pos)
|
||||
if blockData is None:
|
||||
return
|
||||
blockData["rtdd_tid"] = ""
|
||||
blockData["rtdd_tstart"] = 0
|
||||
blockData["rtdd_tdur"] = 0
|
||||
blockData["rtdd_tp"] = ""
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ============================================================================
|
||||
# 六、工具方法:完成提示
|
||||
# ============================================================================
|
||||
|
||||
def _notifyIfOnline(self, playerId, tip):
|
||||
"""若启动者在线,发送完成提示(离线则跳过)"""
|
||||
if not tip or not playerId:
|
||||
return
|
||||
try:
|
||||
ids = comp.CreateGame(LevelId).GetAllPlayerIds()
|
||||
if playerId in ids:
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(playerId, tip)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ============================================================================
|
||||
# 七、工具方法:替换方块
|
||||
# ============================================================================
|
||||
|
||||
def replaceBlock(self, pos, dim, newBlockName, playerId, aux=None):
|
||||
"""
|
||||
替换指定位置的方块。
|
||||
newBlockName="minecraft:air" 表示清除该方块。
|
||||
playerId 可为 None(计时回调时没有玩家),用 LevelId 创建组件。
|
||||
"""
|
||||
creator = playerId if playerId is not None else LevelId
|
||||
if aux is None:
|
||||
try:
|
||||
oldBlock = comp.CreateBlockInfo(creator).GetBlockNew(pos, dim)
|
||||
aux = oldBlock.get("aux", 0)
|
||||
except Exception:
|
||||
aux = 0
|
||||
comp.CreateBlockInfo(creator).SetBlockNew(
|
||||
pos,
|
||||
blockDict={"name": newBlockName, "aux": aux},
|
||||
oldBlockHandling=0,
|
||||
dimensionId=dim)
|
||||
Reference in new issue
Block a user