From faa3a22631130d8fd7d781e675ca72d91cabae9b Mon Sep 17 00:00:00 2001 From: wenhe <1046926120@qq.com> Date: Wed, 23 Sep 2026 16:58:44 +0800 Subject: [PATCH] =?UTF-8?q?ceshi=202=20bug=E5=A4=84=E7=90=86ok?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jiaju/service/FurnitureService.py | 19 ++-- .../xiangyemod/mianshi/MianshiData.py | 34 +++---- .../mianshi/service/MianshiService.py | 29 +++--- .../service/ClientFeatureDispatcher.py | 52 +++++++++- .../xiangyemod/service/FeatureDispatcher.py | 82 ++++++++++++++-- .../xiangyemod/service/InterceptData.py | 97 +++++++++++++++++++ .../xiangyemod/yuanbanfangzhi/YuanbanData.py | 2 +- tuilun/全部功能做了什么.txt | 51 ++++++++++ 8 files changed, 314 insertions(+), 52 deletions(-) diff --git a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/jiaju/service/FurnitureService.py b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/jiaju/service/FurnitureService.py index af897d6..221e1e1 100644 --- a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/jiaju/service/FurnitureService.py +++ b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/jiaju/service/FurnitureService.py @@ -331,8 +331,8 @@ class FurnitureService(BlueFoxServerSystem): retItemName = record["itemName"] retAux = record.get("aux", 0) - # 给玩家箭 - self.giveItem(playerId, retItemName, retCount, retAux) + # 掉落物形式返回箭(根因C) + self._dropItemDict(dim, pos, {"itemName": retItemName, "count": retCount, "auxValue": retAux}) # 替换方块 if recipe.get("target"): @@ -371,9 +371,10 @@ class FurnitureService(BlueFoxServerSystem): poppedName = stackNames.pop() # 后放先取, 弹最后一件 if stack: topItem = stack.pop() - self.giveItemObj(playerId, topItem) + self._dropItemObj(dim, pos, topItem) # 掉落物返还(根因C) else: - self.giveItem(playerId, poppedName) + self._dropItemDict(dim, pos, + {"itemName": poppedName, "count": 1, "auxValue": 0}) # 计算剩余 -> 目标方块, 并保存剩余记录(保证后续取回一致) target = self._rackTarget(stackNames) self.replaceBlock(pos, dim, target, playerId) @@ -477,9 +478,15 @@ class FurnitureService(BlueFoxServerSystem): if recipe.get("dropItem"): self.dropItems(dim, pos, recipe["dropItem"]) - # ---- 给玩家背包物品(水槽取水/取脏盘子/盘子架取回) ---- + # ---- 掉落物形式(水槽取水/取脏盘子/盘子架取回等) ---- + # 【根因C】获得物品一律改掉落物形式, 不再直接塞进背包 if recipe.get("giveItem"): - self.giveItem(playerId, recipe["giveItem"]) + _gItem = recipe["giveItem"] + if isinstance(_gItem, dict): + self._dropItemDict(dim, pos, _gItem) + else: + self._dropItemDict(dim, pos, + {"itemName": _gItem, "count": recipe.get("giveCount", 1), "auxValue": 0}) # ---- 转换成功提示 ---- if recipe.get("tip"): diff --git a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/mianshi/MianshiData.py b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/mianshi/MianshiData.py index 4e17a9b..60759f9 100644 --- a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/mianshi/MianshiData.py +++ b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/mianshi/MianshiData.py @@ -348,22 +348,22 @@ ITEM_USE_ON_RULES = [ "replace": "rtdd:steamerdumplings_0", "consume": 4, "startTimer": "rtdd:steamerdumplings_0", "needBelow": LIT_STOVE, "belowTip": "§c蒸笼需要放在点燃的炉灶上", - "tip": "§a四个生饺子放进蒸笼, 开始蒸制(共60秒); 计时结束变成 熟饺子"}, + "tip": "§a四个生饺子放进蒸笼, 开始蒸制; 计时结束变成 熟饺子"}, {"item": "rtdd:roubaozi_3", "surface": STEAMER, "replace": "rtdd:baozilong_1", "consume": 3, "startTimer": "rtdd:baozilong_1", "needBelow": LIT_STOVE, "belowTip": "§c蒸笼需要放在点燃的炉灶上", - "tip": "§a三个生肉包子放进蒸笼, 开始蒸制(共60秒); 计时结束变成 熟包子"}, + "tip": "§a三个生肉包子放进蒸笼, 开始蒸制; 计时结束变成 熟包子"}, {"item": "rtdd:bamboo_4", "surface": STEAMER, "replace": "rtdd:bamboo_6", "consume": 1, "startTimer": "rtdd:bamboo_6", "needBelow": LIT_STOVE, "belowTip": "§c蒸笼需要放在点燃的炉灶上", - "tip": "§a竹筒饭放进蒸笼, 开始蒸制(共60秒); 计时结束变成 熟竹筒饭"}, + "tip": "§a竹筒饭放进蒸笼, 开始蒸制; 计时结束变成 熟竹筒饭"}, {"item": "rtdd:plate_34", "surface": STEAMER, "replace": "rtdd:steamermilkandegg", "consume": 1, "startTimer": "rtdd:steamermilkandegg", "needBelow": LIT_STOVE, "belowTip": "§c蒸笼需要放在点燃的炉灶上", - "tip": "§a蛋液半成品放进蒸笼, 开始蒸制(共60秒); 计时结束变成 蒸牛奶鸡蛋"}, + "tip": "§a蛋液半成品放进蒸笼, 开始蒸制; 计时结束变成 蒸牛奶鸡蛋"}, ] # ============================================================================ @@ -372,34 +372,34 @@ ITEM_USE_ON_RULES = [ # ============================================================================ TIMER_RULES = [ # 发酵(60秒, autoStart) - {"source": "rtdd:rawdough_4", "target": "rtdd:dough_0", "time": 60, + {"source": "rtdd:rawdough_4", "target": "rtdd:dough_0", "time": 2, "autoStart": True, "doneTip": "§e面团发酵好了"}, - {"source": "rtdd:breaddough_1", "target": "rtdd:breaddough_1a", "time": 60, + {"source": "rtdd:breaddough_1", "target": "rtdd:breaddough_1a", "time": 2, "autoStart": True, "doneTip": "§e法棍面胚发好了"}, # 蒸笼: 手持生食右键蒸笼 -> 蒸X_生(见 ITEM_USE_ON_RULES); 蒸X_生下方是 # 点燃的炉灶(stove_2)才计时, 60秒蒸熟 - {"source": "rtdd:steamerdumplings_0", "target": "rtdd:steamerdumplings_1", "time": 60, + {"source": "rtdd:steamerdumplings_0", "target": "rtdd:steamerdumplings_1", "time": 2, "below": [LIT_STOVE], "autoStart": True, "doneTip": "§e饺子蒸好了"}, - {"source": "rtdd:baozilong_1", "target": "rtdd:baozilong_2", "time": 60, + {"source": "rtdd:baozilong_1", "target": "rtdd:baozilong_2", "time": 2, "below": [LIT_STOVE], "autoStart": True, "doneTip": "§e包子蒸好了"}, - {"source": "rtdd:bamboo_6", "target": "rtdd:bamboo_7", "time": 60, + {"source": "rtdd:bamboo_6", "target": "rtdd:bamboo_7", "time": 2, "below": [LIT_STOVE], "autoStart": True, "doneTip": "§e竹筒饭蒸好了"}, - {"source": "rtdd:steamermilkandegg", "target": "rtdd:steamermilkandegg_1", "time": 60, + {"source": "rtdd:steamermilkandegg", "target": "rtdd:steamermilkandegg_1", "time": 2, "below": [LIT_STOVE], "autoStart": True, "doneTip": "§e蒸牛奶鸡蛋好了"}, # 烤炉烘焙(60秒, 下方判定烤炉; 烤炉被打碎 -> 该方块掉落+提示) - {"source": "rtdd:breaddough_1a", "target": "rtdd:bread_1", "time": 60, + {"source": "rtdd:breaddough_1a", "target": "rtdd:bread_1", "time": 2, "below": [OVEN], "autoStart": True, "dropOnBreak": True, "doneTip": "§e法棍烤好了"}, - {"source": "rtdd:breaddough_2", "target": "rtdd:bread_2", "time": 60, + {"source": "rtdd:breaddough_2", "target": "rtdd:bread_2", "time": 2, "below": [OVEN], "autoStart": True, "dropOnBreak": True, "doneTip": "§e吐司烤好了"}, - {"source": "rtdd:breaddough_4d", "target": "rtdd:bread_4c", "time": 60, + {"source": "rtdd:breaddough_4d", "target": "rtdd:bread_4c", "time": 2, "below": [OVEN], "autoStart": True, "dropOnBreak": True, "doneTip": "§e甜甜圈胚烤好了"}, - {"source": "rtdd:dought_9", "target": "rtdd:bread_3", "time": 60, + {"source": "rtdd:dought_9", "target": "rtdd:bread_3", "time": 2, "below": [OVEN], "autoStart": True, "dropOnBreak": True, "doneTip": "§e可颂烤好了"}, - {"source": "rtdd:cakebatterblock_0", "target": "rtdd:cakebatterblock", "time": 60, + {"source": "rtdd:cakebatterblock_0", "target": "rtdd:cakebatterblock", "time": 2, "below": [OVEN], "autoStart": True, "dropOnBreak": True, "doneTip": "§e蛋糕面糊烤好了"}, - {"source": "rtdd:plate_34", "target": "rtdd:plate_35", "time": 60, + {"source": "rtdd:plate_34", "target": "rtdd:plate_35", "time": 2, "below": [OVEN], "autoStart": True, "dropOnBreak": True, "doneTip": "§e布丁半成品好了"}, - {"source": "rtdd:creampastry_0", "target": "rtdd:souffle_0", "time": 60, + {"source": "rtdd:creampastry_0", "target": "rtdd:souffle_0", "time": 2, "below": [OVEN], "autoStart": True, "dropOnBreak": True, "doneTip": "§e舒芙蕾烤好了"}, ] diff --git a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/mianshi/service/MianshiService.py b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/mianshi/service/MianshiService.py index c226ed8..ac14f29 100644 --- a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/mianshi/service/MianshiService.py +++ b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/mianshi/service/MianshiService.py @@ -105,10 +105,9 @@ class MianshiService(BlueFoxServerSystem): self.timerSources.add(src) self.featureBlocks.add(src) if src not in self.startTimerTips: - sec = r.get("time", 60) tgt = NAME_MAP.get(r["target"], r["target"]) - self.startTimerTips[src] = "§a开始蒸制: 还需%d秒, 计时结束变成 %s" % (sec, tgt) - self.timingTips[src] = "§e正在蒸制中: 还需%d秒, 计时结束变成 %s" % (sec, tgt) + self.startTimerTips[src] = "§a开始蒸制, 计时结束变成 %s" % tgt + self.timingTips[src] = "§e正在蒸制中, 计时结束变成 %s" % tgt # ---- 结果方块/物品 -> "下一步"可读提示(供转换/入笼提示追加) ---- # 例子: 饺子皮 -> "加入 猪肉馅、青菜碎"; 可颂面胚 -> "放在烤炉上等计时(60秒)结束变成 可颂" @@ -140,9 +139,9 @@ class MianshiService(BlueFoxServerSystem): sec = r.get("time", 60) tgt = NAME_MAP.get(r["target"], r["target"]) if r.get("below") == [OVEN]: - _addTip(src, "放在烤炉上等计时(%d秒)结束变成 %s" % (sec, tgt)) + _addTip(src, "放在烤炉上等计时结束变成 %s" % tgt) else: - _addTip(src, "等计时(%d秒)结束变成 %s" % (sec, tgt)) + _addTip(src, "等计时结束变成 %s" % tgt) # ---- 计时源方块 -> 计时结束后的成品名(烤炉固定开始烤制提示用) ---- self.timerTargetName = {} @@ -191,13 +190,11 @@ class MianshiService(BlueFoxServerSystem): if blockName in KNEAD_COUNTERS and (not itemName or itemName == "minecraft:air"): return self._handleKnead(blockName, playerId, pos, dim, key) - # ---- 烤炉固定: 胚/面糊/蛋液等放在烤炉上 -> 禁止右键转换, 固定开始烤制 ---- - if blockName in OVEN_FIX_BLOCKS and self._belowIs(dim, pos, OVEN): - FeatureDispatcher.startTimerFor(blockName, dim, pos, playerId) - if self.checkCooldown(key, 0.4): - comp.CreateMsg(playerId).NotifyOneMessage( - playerId, "§a已启动计时(共60秒)") - return True + # ---- 烤炉固定: 胚/面糊/蛋液等放在烤炉上 → 不再通过右键启动计时。 + # 【根因D】计时改自动开始: MianshiTimerService 的 tick 会按下方是否为烤炉 + # 自动启动计时(OVEN_FIX_BLOCKS 的 autoStart, 参照烤乳猪机制)。这里不再拦截 + # 右键启动, 也不挡玩家正常放置。空手右键成品取走逻辑保留在下方。 + # (移除了原"startTimerFor + 提示已启动计时"分支) # ---- 烤制成品取走: 空手右键成品(下方是烤炉) -> 成品掉落物, 烤炉不动 ---- if blockName in OVEN_RESULT_BLOCKS and self._belowIs(dim, pos, OVEN) \ @@ -210,12 +207,8 @@ class MianshiService(BlueFoxServerSystem): playerId, "§a取走" + self._nameOf(blockName)) return True - # ---- 空手右键"蒸笼计时源"(蒸X_生): 下方是点燃炉灶 -> 开始/继续计时 ---- - if (not itemName or itemName == "minecraft:air") and blockName in self.timerSources: - if not self.checkCooldown(key, 0.4): - return True - self._handleStartTimer(blockName, playerId, pos, dim) - return True + # ---- 空手右键"蒸笼计时源"(蒸X_生): 计时已改自动(tick 判定下方点燃炉灶), + # 不再通过空手右键启动; 此处不再拦截, 避免空手右键被吞影响后续操作。---- # ---- 常规转换 ---- recipe = self.findRecipe(blockName, itemDict) diff --git a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/ClientFeatureDispatcher.py b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/ClientFeatureDispatcher.py index 33b2ff1..20a2443 100644 --- a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/ClientFeatureDispatcher.py +++ b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/ClientFeatureDispatcher.py @@ -28,7 +28,8 @@ clientComp = clientApi.GetEngineCompFactory() from ...BlueFoxTools.SpecialFunciton.BlueFoxSystem import BlueFoxClientSystem from .InterceptData import (ITEM_USE_ON_CANCEL, ITEM_USE_ON_CANCEL_BY_ITEM, SUSHI_BLOCKS, SUSHI_CANCEL, COATING_ITEMS, - TAKEOUT_CANCEL, GAI_FAN_CANCEL) + TAKEOUT_CANCEL, GAI_FAN_CANCEL, BLOCKUSE_CANCEL, + BLOCKUSE_CANCEL_ITEMS) # 自定义事件: 客户端拦(碗/盘,汤锅/炒锅/油锅成品)放置预览后, 显式通知服务端执行盛出 # 服务端在 FeatureDispatcher 用同一事件名监听(见 service/FeatureDispatcher.py) @@ -45,6 +46,13 @@ GAI_FAN_EVENT = "GaifanRequest" # 种水稻. 若不显式通知, 客户端 ret=True 会吞掉 ServerItemUseOnEvent, 这些转换"点无反应"。 ITEM_USE_ON_REQUEST = "ItemUseOnRequest" +# 自定义事件: 客户端拦(手持可放置/可投掷物品, 功能方块)放置预览后, 显式通知服务端执行 +# BlockUse 转换(根因B). 例如手持 生鸡肉/鳕鱼/鲑鱼 右键 支杆 -> 上杆; 死鱼右键挂肉钩 -> +# 挂放; 鸡蛋右键鸡窝 -> 放蛋; 胡萝卜右键饲料槽 -> 加料; 盘子右键丸子机/石磨 -> 盛取; +# 木条右键炉灶 -> 点火. 客户端 ret 掉放置/投掷预览后 NotifyToServer, 服务端按被点方块 +# blockOwnerAll 路由到 handleBlockUse(与 TakeoutRequest 同机制). +BLOCK_USE_REQUEST = "BlockUseRequest" + class ClientFeatureDispatcher(BlueFoxClientSystem): """客户端右键拦截: 白名单提前 cancel/ret, 消除闪烁""" @@ -56,6 +64,14 @@ class ClientFeatureDispatcher(BlueFoxClientSystem): # 转换完成后一段时间内, 该位置再被当作"放置"会直接 ret 吞掉, 消除"转换后 # 由于引擎重置右键导致多放置一次"的闪一下。时长 1.5 秒(用户要求明显可见)。 self._afterCd = {} + # BlockUse 转换(手持食材/鸡蛋右键功能方块)的独立短冷却: 回调方块后的 0.2s 内 + # 该坐标再被当作右键会直接 ret 吞掉, 防止"放蛋后连点被误当投掷扔出去"。 + # 时长 0.2 秒(用户指定"稍微停一下0.1~0.2秒"); 翻炒(0.3s 间隔)不受影响。 + self._blockCd = {} + # 玩家级"刚做过 BlockUse 转换(放蛋/放料)"短标记: key=playerId, value=时间戳. + # 用于 OnItemTryUse(投掷/使用轨道)在 0.2s 内取消该玩家的投掷动画(如鸡蛋右键鸡窝 + # 放蛋后引擎重置右键立即触发投掷 -> 扔蛋)。cd 到即放行, 对地扔蛋正常。 + self._blockCdPlayer = {} self.ListenForEvent(clientApi.GetEngineNamespace(), clientApi.GetEngineSystemName(), "ClientItemUseOnEvent", self, self.OnItemUseOn) @@ -95,6 +111,31 @@ class ClientFeatureDispatcher(BlueFoxClientSystem): args["ret"] = True return + # BlockUse 转换短冷却: 放蛋/放料后 0.2s 内同一坐标再被当作右键(引擎重置导致的 + # 二次使用/投掷)直接吞掉, 防止"连点鸡窝被误当扔蛋"。时长 0.2s(用户指定, 不卡翻炒)。 + _bcd = self._blockCd.get(cdKey) + if _bcd is not None and (time.time() - _bcd) < 0.2: + args["ret"] = True + return + + # 【根因B】手持可放置/可投掷物品 右键功能方块(支杆/挂肉钩/鸡窝/饲料槽/丸子机/石磨/ + # 炉灶/寿司/炒锅放料 等) -> 此组合是 BlockUse 转换(服务端 handleBlockUse), 不能走下面 + # ITEM_USE_ON_CANCEL_BY_ITEM 的"相邻放置"(那会绕开 owners 检查把死鱼/死鸡放到地面)。 + # 此处 ret 掉放置/投掷预览 + 显式 BlockUseRequest, 由服务端按被点方块 handleBlockUse。 + # 【注意】这里设 _blockCd(0.2s 短冷却): 放蛋/放料转换后引擎重置右键会再触发一次 + # "使用/投掷", 若这次也被当正常右键会扔蛋/放着。0.2s 内同坐标直接吞掉, 既消扔蛋又 + # 不卡翻炒(翻炒 0.3s 间隔 > 0.2s)。去重同时靠服务端 handleBlockUse 自带 checkCooldown。 + if blockName and (itemName, blockName) in BLOCKUSE_CANCEL: + args["ret"] = True + self._blockCd[cdKey] = time.time() + self._blockCdPlayer[pId] = time.time() # 玩家级短标记, 取消随后 0.2s 内投掷动画 + self.NotifyToServer(BLOCK_USE_REQUEST, { + "playerId": pId, + "x": args.get("x"), "y": args.get("y"), "z": args.get("z"), + "blockName": blockName, "itemName": itemName, + }) + return + # 纯手持物品取消 (相邻放置/手持吃物品右键表面): 只看 item, 服务端走 handleItemUseOn # (Yuanban 相邻放置/装盘、Natural 种水稻、Shiyongfood 直接吃)。这些组合一旦客户端 # ret=True 会吞掉 ServerItemUseOnEvent, 故必须显式通知服务端补齐(盖饭同款机制)。 @@ -187,6 +228,15 @@ class ClientFeatureDispatcher(BlueFoxClientSystem): # 饭团/水煮蛋/豆腐 在 ITEM_USE_ON_CANCEL_BY_ITEM 里(EAT_ITEMS) if itemName in ITEM_USE_ON_CANCEL_BY_ITEM: args["cancel"] = True + # 投掷/使用抑制: 玩家刚做过 BlockUse 转换(0.2s 内, 如放蛋/放料), 引擎重置右键会立即 + # 再触发一次"投掷/使用"动画(鸡蛋右键鸡窝放蛋 -> 扔蛋)。此窗口内若手持 BlockUse 可投掷/ + # 可用物品, 直接 cancel 掉投掷; 窗口过后放行(对地扔蛋正常)。 + # 注意: 玩家级标记(pId)而非坐标——投掷事件无目标方块坐标, 只有玩家。0.2s 极短且仅在 + # 刚做完方块转换后生效, 不会影响玩家正常对地面/空中扔蛋。 + _pId = args.get("playerId") or args.get("entityId") + _pc = self._blockCdPlayer.get(_pId, 0) + if _pc and (time.time() - _pc) < 0.2 and itemName in BLOCKUSE_CANCEL_ITEMS: + args["cancel"] = True # 注: 客户端系统需在客户端进程被实例化。modMain 只能在服务端 import 服务端 diff --git a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/FeatureDispatcher.py b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/FeatureDispatcher.py index f7f95c0..9273ae5 100644 --- a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/FeatureDispatcher.py +++ b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/FeatureDispatcher.py @@ -32,6 +32,7 @@ 4. 在 modMain.py import 这些服务类即可(框架会自动实例化) ================================================================================ """ +import time import mod.server.extraServerApi as serverApi # ---- 网易API基础对象 ---- @@ -57,6 +58,15 @@ GAI_FAN_EVENT = "GaifanRequest" # 相邻放置/厨具蘸油/寿司/裹粉/种水稻), 而非仅盖饭. ---- ITEM_USE_ON_REQUEST = "ItemUseOnRequest" +# ---- 通用"手持物品右键功能方块"的 BlockUse 转换请求(与客户端 BLOCK_USE_REQUEST 一致). +# 用于修复根因B: 手持可放置/可投掷物品(生肉/鱼/鸡蛋/胡萝卜/盘子/木条/寿司等)右键 +# 功能方块(支杆/挂肉钩/鸡窝/饲料槽/丸子机/石磨/炉灶/寿司方块)时, 原版先播放"放置/ +# 投掷"预览, 服务端 handleBlockUse 转换靠 ServerBlockUseEvent 触发, 但顺序不可保证, +# 导致"想转换却放置/投掷了"。客户端对该(物品,功能方块)组合 ret 消闪后显式 Notify +# 本事件, 服务端按被点方块 blockOwnerAll 路由到相应 handleBlockUse (与 TakeoutRequest +# 同机制). ---- +BLOCK_USE_REQUEST = "BlockUseRequest" + # ---- 方块实体数据组件(计时持久化:记录开始时间戳,重启后继续计时) ---- blockEntityDataComp = comp.CreateBlockEntityData(LevelId) @@ -71,6 +81,15 @@ FACE_OFFSET = { 5: (1, 0, 0), } +# ---- 右键转换成功后"取消同一右键配套的放置/吃"的时间窗口(秒) ---- +# 同一右键动作会同时触发 ServerBlockUseEvent(转换) 和 ServerItemUseOnEvent / +# ServerItemTryUseEvent(手持方块物品的放置前摇 / 喝药吃食)。OnBlockUse 转换成功后 +# 会记录该玩家在此窗口内的后续 ItemUseOn/TryUse 应被取消(否则"转出了成品却又把 +# 手持方块放出来")。超过窗口即视为过期残留, pop 后直接放行, 避免"做完一个操作 +# 后任意位置放置都被吞"(统计: 空手右键只触发 BlockUse, 无配套 ItemUseOn 消费, +# 若标记无时限会永久残留吞掉玩家下一次真实放置)。 +CANCEL_WINDOW = 0.5 + class FeatureDispatcher(BlueFoxServerSystem): """ @@ -225,6 +244,10 @@ class FeatureDispatcher(BlueFoxServerSystem): # (与 GaifanRequest 同机制, 统一覆盖全部 itemUseOn 转换) self.ListenForEvent(MOD_NAME, "ClientFeatureDispatcher", ITEM_USE_ON_REQUEST, self, self.OnItemUseOnRequest) + # 10. BlockUseRequest —— 客户端拦截(手持可放置/可投掷物品, 功能方块)放置预览后, + # 显式请求服务端执行对应 handleBlockUse(根因B: 防止"想转换却放置/投掷"了)。 + self.ListenForEvent(MOD_NAME, "ClientFeatureDispatcher", + BLOCK_USE_REQUEST, self, self.OnBlockUseRequest) def UnListenEvent(self): self.UnListenForEvent(serverApi.GetEngineNamespace(), @@ -251,6 +274,8 @@ class FeatureDispatcher(BlueFoxServerSystem): GAI_FAN_EVENT, self, self.OnGaifanRequest) self.UnListenForEvent(MOD_NAME, "ClientFeatureDispatcher", ITEM_USE_ON_REQUEST, self, self.OnItemUseOnRequest) + self.UnListenForEvent(MOD_NAME, "ClientFeatureDispatcher", + BLOCK_USE_REQUEST, self, self.OnBlockUseRequest) # ============================================================================ # 主入口1:玩家右键方块 → 按 blockOwner 路由到右键服务 @@ -284,8 +309,9 @@ class FeatureDispatcher(BlueFoxServerSystem): handled = service.handleBlockUse(args) if handled: args['cancel'] = True - self._cancelItemUse[playerId] = True - print "[FD-BlockUse-DONE]", "player:", playerId, "hand:", _handItem, "block:", blockName, "svc:", service.__class__.__name__, "-> cancel=True, _cancelItemUse=True" + # 记录时间戳(带窗口), 只取消同一右键配套的放置/吃; 过期残留自动放行 + self._cancelItemUse[playerId] = time.time() + print "[FD-BlockUse-DONE]", "player:", playerId, "hand:", _handItem, "block:", blockName, "svc:", service.__class__.__name__, "-> cancel=True, _cancelItemUse=ts" return print "[FD-BlockUse-NOMATCH]", "player:", playerId, "hand:", _handItem, "block:", blockName, "-> 无匹配规则, 放行" @@ -306,11 +332,12 @@ class FeatureDispatcher(BlueFoxServerSystem): """ playerId = args.get("playerId") or args.get("entityId") # 【关键】同一右键动作会同时触发 ServerBlockUseEvent(盛出/转换, 已由 OnBlockUse - # 处理并设置 _cancelItemUse) 和 ServerItemUseOnEvent(手持方块物品的放置前摇)。 - # 若前一帧 OnBlockUse 已成功处理(盛出掉落/方块转换), 这里必须消费标记并 - # ret=True 取消放置, 否则"盛出了成品"却又"把手持的木碗/盘子放了出来"。 - # (与 OnItemTryUse 消费标记取消"吃/喝"是同一模式。) - if self._cancelItemUse.pop(playerId, False): + # 处理并设置 _cancelItemUse 时间戳) 和 ServerItemUseOnEvent(手持方块物品的放置前摇)。 + # 若在 CANCEL_WINDOW 窗口内, 这里必须消费标记并 ret=True 取消放置, 否则"盛出了成品" + # 却又"把手持的木碗/盘子放了出来"。超窗口则视为过期残留, pop 后直接放行——绝不吞 + # 玩家之后的真实放置(日志: 空手右键完成后残留标记吞掉任意位置放置, 已修复)。 + _ts = self._cancelItemUse.pop(playerId, 0) + if _ts and (time.time() - _ts) < CANCEL_WINDOW: args['ret'] = True print "[FD-ItemUseOn-CONSUME-CANCEL]", "player:", playerId, "item:", args.get("itemName"), "block:", args.get("blockName"), "-> ret=True 取消放置" return @@ -361,7 +388,8 @@ class FeatureDispatcher(BlueFoxServerSystem): handled = service.handleItemUseOn(args) if handled: args['ret'] = True - self._cancelItemUse[playerId] = True + # 时间戳(带窗口): itemUseOn 转换成功后, 同右手的后续 TryUse/放置也取消 + self._cancelItemUse[playerId] = time.time() return # ============================================================================ @@ -513,6 +541,39 @@ class FeatureDispatcher(BlueFoxServerSystem): return print "[FD-ItemUseOnRequest-NO-HANDLER]", itemName + def OnBlockUseRequest(self, args): + """ + 客户端 ClientFeatureDispatcher 在拦截(手持可放置/可投掷物品, 功能方块)放置预览后, + 显式 NotifyToServer 发来的 BlockUse 转换请求(根因B). 因为客户端已 ret=True 把该 + 组合的 ServerBlockUseEvent 吞掉(消闪), 服务端原本的 handleBlockUse 转换在这里补齐. + + 按被点方块名路由到 blockOwnerAll 里的服务(可能多个, 逐个 fallback, 第一个返回 True + 的处理成功, 与 OnBlockUse 相同). 各服务 handleBlockUse 内部自带 checkCooldown(同坐标/ + 同物品), 即使与真实 ServerBlockUseEvent 重复触发, 冷却也会拦截第二次, 不双重消耗. + """ + playerId = args.get("playerId") + x, y, z = args.get("x"), args.get("y"), args.get("z") + blockName = args.get("blockName") + if not (playerId and x is not None and y is not None and z is not None and blockName): + return + services = self.blockOwnerAll.get(blockName) + if not services: + print "[FD-BlockUseRequest-NO-SVC]", blockName + return + useArgs = { + "blockName": blockName, + "playerId": playerId, + "entityId": playerId, + "x": x, "y": y, "z": z, + "face": args.get("face", 1), + } + for service in services: + if hasattr(service, "handleBlockUse"): + handled = service.handleBlockUse(useArgs) + if handled: + return + print "[FD-BlockUseRequest-NO-HANDLER]", blockName + # ============================================================================ # 主入口3:拦截物品使用(防止喝药水/吃食物等默认行为) # ============================================================================ @@ -526,7 +587,10 @@ class FeatureDispatcher(BlueFoxServerSystem): """ playerId = args.get("playerId") print "[FD-ItemTryUse]", args.get("itemName"), "player", playerId - if self._cancelItemUse.pop(playerId, False): + # 仅在 CANCEL_WINDOW 窗口内消费(同一右键配套的吃/喝); 过期残留 pop 后放行, + # 不吞玩家之后再吃/喝物品(根因A: 无时限标记残留会吞掉后续任意物品使用)。 + _ts = self._cancelItemUse.pop(playerId, 0) + if _ts and (time.time() - _ts) < CANCEL_WINDOW: args['cancel'] = True return itemName = args.get("itemName") diff --git a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/InterceptData.py b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/InterceptData.py index cb947a6..0ba8696 100644 --- a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/InterceptData.py +++ b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/InterceptData.py @@ -103,6 +103,72 @@ try: except Exception: YOUGUO_SWITCH, YOUGUO_PLATE = None, None +# ---- 根因B: 各"手持可放置/可投掷物品右键功能方块"走 ServerBlockUseEvent 的转换规则表. +# 字段用 source/block + item(块字段统一为 source; 不同服务可能用 source 或 block, 取兼容). ---- +_BLOCK_USE_TABLES = [] + +# 动物养殖(鸡窝放蛋/饲料槽/水槽 等): AnimalData.ANIMAL_SWITCHES +try: + from ..dongwuyangzhi.AnimalData import ANIMAL_SWITCHES as ANIMAL_RS + _BLOCK_USE_TABLES.append(ANIMAL_RS) +except Exception: + pass + +# 烧烤(上杆: 支杆+生肉/鱼): BarbecueData.BARBECUE_SWITCHES +try: + from ..shaokao.BarbecueData import BARBECUE_SWITCHES as BBQ_RS + _BLOCK_USE_TABLES.append(BBQ_RS) +except Exception: + pass + +# 死亡生物(挂肉钩: 死鱼+钩/尸体挂放): DeadmobData.DEADMOB_SWITCHES +try: + from ..siwangshengwu.DeadmobData import DEADMOB_SWITCHES as DEADMOB_RS + _BLOCK_USE_TABLES.append(DEADMOB_RS) +except Exception: + pass + +# 厨具(炉灶/丸子机/石磨: 木条+炉灶 等): ChujuData.STOVE_RULES / MEATBALLMAKER_RULES +try: + from ..chuju.ChujuData import (STOVE_RULES as CHUJU_STOVE, + MEATBALLMAKER_RULES as CHUJU_MEAT, + STEAMER_RULES as CHUJU_STEAM) + _BLOCK_USE_TABLES.extend([CHUJU_STOVE, CHUJU_MEAT, CHUJU_STEAM]) +except Exception: + pass + +# 面食(面粉加水/揉面 等): MianshiData.SWITCH_RULES +try: + from ..mianshi.MianshiData import SWITCH_RULES as MIANSHI_SWITCH + _BLOCK_USE_TABLES.append(MIANSHI_SWITCH) +except Exception: + pass + +# 炒锅(放料: 手持食材右键炒锅等): ChaoguoData.SWITCH_RULES +# (放料/翻炒走 handleBlockUse; 其中 action==take_out 的"盘子出锅"已由 TAKEOUT_CANCEL +# 专用通道处理, 派生时过滤掉, 避免与盛出走 TakeoutRequest 冲突) +try: + from ..chaoguo.ChaoguoData import SWITCH_RULES as CHAOGUO_BLOCKUSE + _BLOCK_USE_TABLES.append(CHAOGUO_BLOCKUSE) +except Exception: + pass + +# 汤锅(放料: 手持食材/锅态汤右键汤锅等): TangguoData.SWITCH_RULES +# 同样过滤 action==take_out(盛出走 TakeoutRequest) +try: + from ..tangguo.TangguoData import SWITCH_RULES as TANGGUO_BLOCKUSE + _BLOCK_USE_TABLES.append(TANGGUO_BLOCKUSE) +except Exception: + pass + +# 油锅(放料: 手持食材右键油锅等): YouguoData.SWITCH_RULES +# 同样过滤 action==take_out(出锅走 TakeoutRequest) +try: + from ..youguo.YouguoData import SWITCH_RULES as YOUGUO_BLOCKUSE + _BLOCK_USE_TABLES.append(YOUGUO_BLOCKUSE) +except Exception: + pass + # ---- 原版放置/盘子转换 (itemUseOn, surface=相邻放置 / source=盘子) ---- try: from ..yuanbanfangzhi.YuanbanData import ( @@ -186,6 +252,37 @@ if CHAOGUO_USON: if isinstance(_it, basestring) and _it and isinstance(_bk, basestring) and _bk: GAI_FAN_CANCEL.add((_it, _bk)) +# ============================================================================ +# 三之C、根因B "手持可放置/可投掷物品右键功能方块" -> BlockUse 显式事件拦截 +# 客户端拦(手持物品, 功能方块)的放置/投掷预览后, NotifyToServer(BLOCK_USE_REQUEST), +# 服务端 OnBlockUseRequest 按被点方块路由到对应服务的 handleBlockUse。 +# 仅取"手持物品非空"(item != None 且非 * 通配) 的转换对 —— 空手右键(item=None) +# 不涉及放置预览, 不需要拦截, 仍走正常 ServerBlockUseEvent。 +# ============================================================================ +BLOCKUSE_CANCEL = set() +for _tbl in _BLOCK_USE_TABLES: + for _r in _as_list(_tbl): + if not isinstance(_r, dict): + continue + _it = _r.get("item") + if not _it or not isinstance(_it, basestring) or _it.startswith("*"): + continue # 只看"手持具体物品"的转换; 空手/通配不拦 + # 炒锅 SWITCH_RULES 的 action==take_out(盘子出锅) 已由 TAKEOUT_CANCEL 专用通道处理, + # 这里跳过, 避免与盛出走 TakeoutRequest 冲突; 其余(放料/翻炒)走 BlockUse。 + if _r.get("action") == "take_out": + continue + # 被点方块: 兼容 source(主流) 与 block(个别) + _bk = _r.get("source") or _r.get("block") + if isinstance(_bk, basestring) and _bk: + BLOCKUSE_CANCEL.add((_it, _bk)) + +# BlockUse 转换涉及的全部手持物品集合(客户端 OnItemTryUse 也需取消默认"使用/投掷/倒水", +# 否则手持鸡蛋右键鸡窝会被当成投掷扔出去; 水桶倒水同理)。 +# 只取原版/可"使用"的物品(minecraft: 前缀)进入 TryUse 取消; rtdd 方块物品不触发 TryUse。 +BLOCKUSE_CANCEL_ITEMS = set( + _it for (_it, _bk) in BLOCKUSE_CANCEL if _it.startswith("minecraft:") +) + # ---- Chuju 锅铲/油罐 inline 转换(在 ChujuService.handleItemUseOn 内联, 不在数据表) ---- # 手持 锅铲/带油锅铲 右键 油罐(oilcan)/炒锅(wok) 蘸油/还油/上油 -> 取消默认 CHUJU_INLINE_CANCEL = { diff --git a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/yuanbanfangzhi/YuanbanData.py b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/yuanbanfangzhi/YuanbanData.py index 4fc1637..fc32e78 100644 --- a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/yuanbanfangzhi/YuanbanData.py +++ b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/yuanbanfangzhi/YuanbanData.py @@ -31,7 +31,7 @@ ITEM_USE_ON_RULES = [ "item": "minecraft:chicken", # 原版生鸡肉 "target": "rtdd:roastchickenplace_0", # 生鸡肉(放置后) "consume": 1, - "tip": "§a已放置生鸡肉,可右键支杆上杆烤制", + "tip": "§a已放置生鸡肉", }, { "item": "minecraft:salmon", # 原版生鲑鱼 diff --git a/tuilun/全部功能做了什么.txt b/tuilun/全部功能做了什么.txt index 9cf8ad5..521d3d1 100644 --- a/tuilun/全部功能做了什么.txt +++ b/tuilun/全部功能做了什么.txt @@ -1028,3 +1028,54 @@ FurnitureData+FurnitureService 实现, 注册到 FeatureDispatcher) OnItemUseOn 的 BY_ITEM / ITEM_USE_ON_CANCEL / SUSHI / COATING 分支全部改为 ret+显式事件 ③白名单清单: 新增"十三、其余 itemUseOn 转换 统一显式事件修复" [已实现] +######################################## +【统一消闪修复·第二轮】(2026-09-23) +######################################## +用户批量反馈后的统一修复, 分根因A/B/C/D四块: +【根因A】操作后任意位置放置被吞(全模组, 最严重) +- 症状: 日志 [FD-BlockUse-DONE]hand:NONE吃roastedmushrooms_3 设 _cancelItemUse=True 后, + 玩家之后在任意位置放方块都被 [FD-ItemUseOn-CONSUME-CANCEL] 吞掉。 +- 根因: _cancelItemUse 是无时限的玩家级布尔标记, OnBlockUse 设 True 后残留; + 空手右键(吃/取)只触发 BlockUse 不触发 ItemUseOn, 标记无人消费残留到下一次真实放置。 +- 修复: FeatureDispatcher.py 加 CANCEL_WINDOW=0.5, _cancelItemUse 改存时间戳, + OnBlockUse/OnItemUseOn(itemUseOn成功)/OnItemTryUse 三处消费处均判断 time.time()-ts<0.5, + 过期残留 pop 后直接放行, 不再吞后续放置/吃。 [已实现] +【根因D】面食计时改2秒+去秒提示+移除右键启动(参照烤乳猪自动判定) +- MianshiData.TIMER_RULES 全部 time:60->2 (发酵/蒸笼/烤炉烘焙 共13条) +- MianshiService: 移除"烤炉固定 OVEN_FIX_BLOCKS 右键 startTimerFor+提示"、"空手右键蒸笼计时源 + timerSources 启动"两段; 改由 MianshiTimerService autoStart tick 按下方烤炉/点燃炉灶自动启动 +- 提示去秒数: startTimerTips/timingTips 去掉"还需%d秒", 蒸笼入笼 tip 去掉"(共60秒)", 只报开始蒸制 +【根因C】家具家私获得物品改掉落物形式 +- FurnitureService: 箭盒取箭 giveItem->_dropItemDict; 厨具架取回 giveItemObj/giveItem->_dropItemObj/ + _dropItemDict; 通用 recipe giveItem(水槽取水/取脏盘子/盘子架取回)->_dropItemDict。 [已实现] +【根因B】手持可放置/可投掷物品右键功能方块"想转换却被放置/投掷" +- 症状: 持鸡蛋右键鸡窝扔蛋/放不进; 持胡萝卜右键饲料槽摆切萝卜; 烧烤上杆/死亡生物挂肉钩/ + 厨具丸子机/石磨/炉灶/面食加水/寿司 等闪一下或真放出去。 +- 根因: 这些转换走 ServerBlockUseEvent(handleBlockUse), 但手持物是真块/可投掷, 客户端 + ClientItemUseOnEvent 未拦(手持物,功能方块), 原版先播放放置/投掷预览; 且部分物品(鸡/鳕/ + 鲑/胡萝卜/稻谷)在 PLACE_ITEMS 里, 客户端拦截后走 ItemUseOnRequest 相邻放置, 绕开 owners 检查。 +- 修复: 新增 BlockUseRequest 统一显式事件通道(与盛出同架构): + ①InterceptData: 新增 BLOCKUSE_CANCEL, 扫描 ANIMAL_SWITCHES/BARBECUE_SWITCHES/DEADMOB_SWITCHES/ + STOVE_RULES/MEATBALLMAKER_RULES/STEAMER_RULES/Mianshi SWITCH_RULES 中 item非空且非* 的 + (手持物品,source/block) 对 + ②FeatureDispatcher: 新增 BLOCK_USE_REQUEST 常量/监听/路由 OnBlockUseRequest(按 blockOwnerAll + handleBlockUse) + ③ClientFeatureDispatcher: 新增 BLOCK_USE_REQUEST 常量, OnItemUseOn 中 BLOCKUSE_CANCEL 分支 + 优先于 ITEM_USE_ON_CANCEL_BY_ITEM(避免相邻放置抢走), ret+Notify 显式触发 [已实现] +【注意事项】 +- 烧烤上杆烤鸡规则 item=rtdd:roastchickenplace_0(放置后的块), 不是 minecraft:chicken; + 若玩家想"手持生鸡肉右键支杆", 该组合不属于转换(需先放出生鸡肉块), 待用户确认是否要改数据。 +- 面食/汤锅/装盘(ITEM_USE_ON_CANCEL_BY_ITEM) 仍走 ItemUseOnRequest; 他们不属于 blockUse 转换。 +- 炒锅放料补充: 用户反馈"炒锅放胡萝卜"同款问题。已把 ChaoguoData.SWITCH_RULES 纳入 BLOCKUSE_CANCEL + 派生(InterceptData), 且派生时跳过 action==take_out(避免与 TAKEOUT_CANCEL 抢盘子出锅)。这样手持 + 胡萝卜/葱花/蒜末等食材右键炒锅(油锅/添油) 会走 BlockUseRequest, 不再被相邻放置抢走。 [已补] +- 汤锅/油锅放料补充: 用户要求把炒锅/汤锅/油锅"手持食材放置"全部处理, 不只是胡萝卜。 + 已将 TangguoData.SWITCH_RULES、YouguoData.SWITCH_RULES 一并纳入 BLOCKUSE_CANCEL 派生 + (同样过滤 action==take_out)。汤锅/油锅/炒锅放料(手持食材/锅态汤右键锅身) 现在都走 + BlockUseRequest, 不再被相邻放置/放置物品抢走。 [已补] +- 投掷物(鸡蛋等)扔蛋修复: 扔蛋是独立投掷事件 ClientItemTryUseEvent 触发(非 ItemUseOn放置)。 + 方案(用户指定): 右键鸡窝放蛋时客户端记玩家级 _blockCdPlayer[pId]=now(0.2s 短标记); + OnItemTryUse 中该玩家 0.2s 内手持 BlockUse 可投掷/可用物品(BLOCKUSE_CANCEL_ITEMS)直接 + cancel 掉投掷动画; 窗口过后放行, 对地扔蛋正常。不设全局取消(会破坏对地投掷, 已弃)。 + 时长 0.2s, 不卡翻炒(0.3s 间隔)。 [已修] +