diff --git a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/shaokao/BarbecueData.py b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/shaokao/BarbecueData.py index 31cad0a..9a2d2b7 100644 --- a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/shaokao/BarbecueData.py +++ b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/shaokao/BarbecueData.py @@ -32,7 +32,10 @@ 格式: [{"name": "xxx", "count": N}, ...] type: "switch"=右键切换, "timer"=计时自动转换 time: 计时型转换需要多少秒(到时间自动替换方块) - below: 计时型转换要求下方方块(如 ["minecraft:campfire"]) + below: 计时型/烤串转换要求下方方块(如 ["minecraft:campfire"]) + tip: 转换成功时给玩家的提示(绿色§a开头) + startTip: 计时型规则启动计时时给玩家的提示(仅玩家主动触发时发) + doneTip: 计时到点完成时给启动者的提示(如"烤鸡烤熟了!") ================================================================================ """ @@ -48,6 +51,7 @@ BARBECUE_SWITCHES = [ "target": "rtdd:barbecuegrill_1", "consume": 0, "type": "switch", + "tip": "§a烧烤炉已点燃!", "giveItem": None, }, # 【点火-烈焰弹】烧烤架_1(无火) → 烧烤架_2(点燃),烈焰弹消耗1个 @@ -57,6 +61,7 @@ BARBECUE_SWITCHES = [ "target": "rtdd:barbecuegrill_1", "consume": 1, "type": "switch", + "tip": "§a烧烤炉已点燃!", "giveItem": None, }, # 【灭火】烧烤架_2(点燃) → 烧烤架_1(无火),消耗水桶,获得空桶 @@ -68,6 +73,7 @@ BARBECUE_SWITCHES = [ "type": "switch", "giveItem": "minecraft:bucket", "giveCount": 1, + "tip": "§a已用水扑灭烧烤炉", }, # ============================================================ @@ -84,6 +90,7 @@ BARBECUE_SWITCHES = [ "type": "switch", "switchCd": 0.15, "below": ["rtdd:barbecuegrill_1"], + "tip": "§a牛肉串正在翻烤…", "giveItem": None, }, { @@ -94,6 +101,7 @@ BARBECUE_SWITCHES = [ "type": "switch", "switchCd": 0.15, "below": ["rtdd:barbecuegrill_1"], + "tip": "§e牛肉串烤熟了!", "giveItem": None, }, # 羊肉串: 生(_1) → 半熟(_0) → 熟(_3) @@ -105,6 +113,7 @@ BARBECUE_SWITCHES = [ "type": "switch", "switchCd": 0.15, "below": ["rtdd:barbecuegrill_1"], + "tip": "§a羊肉串正在翻烤…", "giveItem": None, }, { @@ -115,6 +124,7 @@ BARBECUE_SWITCHES = [ "type": "switch", "switchCd": 0.15, "below": ["rtdd:barbecuegrill_1"], + "tip": "§e羊肉串烤熟了!", "giveItem": None, }, # 烤蔬菜串: 生(_0) → 半熟(_1) → 熟(_3) @@ -126,6 +136,7 @@ BARBECUE_SWITCHES = [ "type": "switch", "switchCd": 0.15, "below": ["rtdd:barbecuegrill_1"], + "tip": "§a烤蔬菜串正在翻烤…", "giveItem": None, }, { @@ -136,6 +147,7 @@ BARBECUE_SWITCHES = [ "type": "switch", "switchCd": 0.15, "below": ["rtdd:barbecuegrill_1"], + "tip": "§e烤蔬菜串烤熟了!", "giveItem": None, }, # 烤香菇串: 生(_0) → 半熟(_1) → 熟(_3) @@ -147,6 +159,7 @@ BARBECUE_SWITCHES = [ "type": "switch", "switchCd": 0.15, "below": ["rtdd:barbecuegrill_1"], + "tip": "§a烤香菇串正在翻烤…", "giveItem": None, }, { @@ -157,6 +170,7 @@ BARBECUE_SWITCHES = [ "type": "switch", "switchCd": 0.15, "below": ["rtdd:barbecuegrill_1"], + "tip": "§e烤香菇串烤熟了!", "giveItem": None, }, @@ -170,6 +184,7 @@ BARBECUE_SWITCHES = [ "target": "rtdd:roastchicken_0", "consume": 1, "type": "switch", + "tip": "§a烤鸡已上杆,等待篝火烤制…", "giveItem": None, }, # 【上烤乳猪】支杆 + 死猪 → 烤乳猪(生) @@ -179,6 +194,7 @@ BARBECUE_SWITCHES = [ "target": "rtdd:roastpig_0", "consume": 1, "type": "switch", + "tip": "§a烤乳猪已上杆,等待篝火烤制…", "giveItem": None, }, # 【上烤鳕鱼】支杆 + 鳕鱼 → 烤鳕鱼(生) @@ -188,6 +204,7 @@ BARBECUE_SWITCHES = [ "target": "rtdd:grilledcod_0", "consume": 1, "type": "switch", + "tip": "§a烤鳕鱼已上杆,等待篝火烤制…", "giveItem": None, }, # 【上烤鲑鱼】支杆 + 鲑鱼 → 烤鲑鱼(生) @@ -197,6 +214,7 @@ BARBECUE_SWITCHES = [ "target": "rtdd:grilled_fish", "consume": 1, "type": "switch", + "tip": "§a烤鲑鱼已上杆,等待篝火烤制…", "giveItem": None, }, @@ -212,6 +230,8 @@ BARBECUE_SWITCHES = [ "type": "timer", "time": 60, "below": ["minecraft:campfire"], + "startTip": "§e开始烤制烤鸡,约60秒…", + "doneTip": "§e烤鸡烤熟了!", "giveItem": None, }, # 【烤熟】烤乳猪(生) → 烤乳猪(熟),下方需篝火,约60秒 @@ -223,6 +243,8 @@ BARBECUE_SWITCHES = [ "type": "timer", "time": 60, "below": ["minecraft:campfire"], + "startTip": "§e开始烤制烤乳猪,约60秒…", + "doneTip": "§e烤乳猪烤熟了!", "giveItem": None, }, # 【烤熟】烤鳕鱼(生) → 烤鳕鱼(熟),下方需篝火,约60秒 @@ -234,6 +256,8 @@ BARBECUE_SWITCHES = [ "type": "timer", "time": 60, "below": ["minecraft:campfire"], + "startTip": "§e开始烤制烤鳕鱼,约60秒…", + "doneTip": "§e烤鳕鱼烤熟了!", "giveItem": None, }, # 【烤熟】烤鲑鱼(生) → 烤鲑鱼(熟),下方需篝火,约60秒 @@ -245,6 +269,8 @@ BARBECUE_SWITCHES = [ "type": "timer", "time": 60, "below": ["minecraft:campfire"], + "startTip": "§e开始烤制烤鲑鱼,约60秒…", + "doneTip": "§e烤鲑鱼烤熟了!", "giveItem": None, }, @@ -259,6 +285,7 @@ BARBECUE_SWITCHES = [ "consume": 0, "type": "switch", "dropItem": [{"name": "rtdd:roast_chickenplace_1", "count": 1}], + "tip": "§a取下了烤鸡(整只)", "giveItem": None, }, # 【取下烤乳猪】烤乳猪(熟) → 支杆 + 掉落 烤乳猪(整只) @@ -269,6 +296,7 @@ BARBECUE_SWITCHES = [ "consume": 0, "type": "switch", "dropItem": [{"name": "rtdd:roastpignew_1", "count": 1}], + "tip": "§a取下了烤乳猪(整只)", "giveItem": None, }, ] @@ -285,5 +313,6 @@ ITEM_USE_ON_RULES = [ "item": "minecraft:chicken", # 手持的原版生鸡肉 "target": "rtdd:roastchickenplace_0", # 生成的目标方块 "consume": 1, # 消耗1个生鸡肉 + "tip": "§a已放置生鸡肉,可右键支杆上杆烤制", }, ] diff --git a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/shaokao/service/BarbecueService.py b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/shaokao/service/BarbecueService.py index edfb97d..aa1f9cd 100644 --- a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/shaokao/service/BarbecueService.py +++ b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/shaokao/service/BarbecueService.py @@ -33,6 +33,9 @@ comp = serverApi.GetEngineCompFactory() # 组件工厂 from ....BlueFoxTools.SpecialFunciton.BlueFoxSystem import BlueFoxServerSystem from ....BlueFoxTools.ToolsConfig import LevelId +# ---- 方块实体数据组件(计时持久化:把开始时间戳+时长写进方块,重启后继续计时) ---- +blockEntityDataComp = comp.CreateBlockEntityData(LevelId) + # ---- 只导入烧烤自己的数据库 ---- from ..BarbecueData import BARBECUE_SWITCHES, ITEM_USE_ON_RULES @@ -83,8 +86,7 @@ class BarbecueService(BlueFoxServerSystem): for rule in ITEM_USE_ON_RULES: self.itemUseOnRecipes[rule["item"]] = rule - # ---- 计时去重表 + 右键冷却表 ---- - self._timerSchedule = {} + # ---- 右键冷却表 ---- self.cooldown = {} # ---- 注册到统一分发器 ---- @@ -125,19 +127,19 @@ class BarbecueService(BlueFoxServerSystem): if not self.checkCooldown(key, recipe.get("switchCd", 0.5)): return True - # ---- 下方方块检查(timer 需篝火,烤串需点燃的烧烤架) ---- + # ---- 下方方块检查(timer 需篝火,烤串需点燃的烧烤炉) ---- if not self.checkBelow(recipe, dim, pos): - # 下方不是要求的方法 → 提示玩家,不执行(但也算处理,取消默认行为) + # 下方不是要求的方块 → 失败提示,不执行(但也算处理,取消默认行为) if recipe.get("type") == "timer": tip = "§c支杆下方需要放一个篝火(营火)才能烤制!" else: - tip = "§c烤串需要放在点燃的烧烤架上才能烤制!" + tip = "§c下方不是点燃的烧烤炉,无法翻烤!" comp.CreateMsg(playerId).NotifyOneMessage(playerId, tip) return True # 计时型:启动计时 if recipe.get("type") == "timer": - self.startTimer(key, recipe, dim) + self.startTimer(key, recipe, dim, playerId) return True # 切换型 @@ -180,6 +182,9 @@ class BarbecueService(BlueFoxServerSystem): # 生成生鸡肉(放置后)方块 self.replaceBlock(targetPos, dim, rule["target"], playerId) + # 放置成功提示 + if rule.get("tip"): + comp.CreateMsg(playerId).NotifyOneMessage(playerId, rule["tip"]) return True # ============================================================================ @@ -220,7 +225,11 @@ class BarbecueService(BlueFoxServerSystem): if recipe.get("target") in self.barbecueTimers: nextTimer = self.barbecueTimers[recipe["target"]] if self.checkBelow(nextTimer, dim, pos): - self.startTimer(key, nextTimer, dim) + self.startTimer(key, nextTimer, dim, playerId) + + # 转换成功提示(点火/上杆等) + if recipe.get("tip"): + comp.CreateMsg(playerId).NotifyOneMessage(playerId, recipe["tip"]) return @@ -233,8 +242,12 @@ class BarbecueService(BlueFoxServerSystem): if recipe.get("target"): self.replaceBlock(pos, dim, recipe["target"], playerId) + # 转换成功提示(烤串翻烤/取下等) + if recipe.get("tip"): + comp.CreateMsg(playerId).NotifyOneMessage(playerId, recipe["tip"]) + # ============================================================================ - # 计时型规则处理(AddTimer 一次性定时,启动前检查下方篝火) + # 计时型规则处理(方块实体 tick 持久化计时,启动前检查下方篝火) # ============================================================================ def checkBelow(self, recipe, dim, pos): @@ -252,29 +265,116 @@ class BarbecueService(BlueFoxServerSystem): except Exception: return False - def startTimer(self, key, recipe, dim): - """启动一次性定时器,1秒内去重,到点由 _timerDone 执行转换""" - now = time.time() - last = self._timerSchedule.get(key, 0) - if now - last < 1.0: - return - self._timerSchedule[key] = now - self.AddTimer(recipe.get("time", 60), self._timerDone, key, recipe, dim) - - def _timerDone(self, key, recipe, dim): - """计时到点:确认方块仍是计时源,且下方仍有篝火,才执行转换""" + def startTimer(self, key, recipe, dim, playerId=None): + """ + 启动烤制计时:把 计时标识+开始时间戳+时长 写入方块实体数据。 + - 已处于本规则计时中的方块不会重复重置时间 + - 到点判断由 FeatureDispatcher 转发的 ServerBlockEntityTickEvent 完成 + - 时间戳存在方块上 → 服务器重启/玩家重进后继续计时 + (例如烤了40秒退出,回来只剩20秒) + """ pos = (key[1], key[2], key[3]) + # 去重:已在本规则计时中的方块不重置 + try: + data = blockEntityDataComp.GetBlockEntityData(dim, pos) + if data and data.get("rtdd_tid") == recipe["source"]: + return + except Exception: + pass + self._writeTimerData(dim, pos, recipe, playerId) + # 计时开始提示 + if playerId and recipe.get("startTip"): + comp.CreateMsg(playerId).NotifyOneMessage(playerId, recipe["startTip"]) + + def handleBlockEntityTick(self, args): + """FeatureDispatcher 转发:烤制方块每 tick 检查是否到点""" + posDim = args.get("posDim") + if not posDim: + return + dim = posDim[3] + pos = (posDim[0], posDim[1], posDim[2]) + self._tickProcess(dim, pos) + + def _tickProcess(self, dim, pos): + """tick 主逻辑:读计时数据,到点执行转换(重启后照样生效)""" + try: + data = blockEntityDataComp.GetBlockEntityData(dim, pos) + if not data: + return + tid = data.get("rtdd_tid") + if not tid: + return + recipe = self.barbecueTimers.get(tid) + if not recipe: + return + tstart = data.get("rtdd_tstart", 0) + tdur = data.get("rtdd_tdur", 0) + if time.time() - tstart >= tdur: + self._finishTimer(dim, pos, recipe, data) + except Exception: + pass + + def _finishTimer(self, dim, pos, recipe, data): + """ + 计时到点:确认方块仍是计时源、下方仍有篝火,才执行转换。 + - 篝火被拿走 → 暂停烤制,等篝火回来继续 + - 烤熟后清除计时数据,并给启动者发送"烤熟了"提示 + """ try: cur = comp.CreateBlockInfo(LevelId).GetBlockNew(pos, dim) - if not cur or cur.get("name") != recipe["source"]: + 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.startTimer(key, nextRecipe, dim) + self._writeTimerData(dim, pos, nextRecipe, data.get("rtdd_tp")) + else: + self._clearTimerData(dim, pos) + doneTip = recipe.get("doneTip") + if doneTip: + self._notifyIfOnline(data.get("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 + blockData["rtdd_tid"] = recipe["source"] + blockData["rtdd_tstart"] = time.time() + 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