From b768ff1555f6edf0b805cdb90e5a17aba794f163 Mon Sep 17 00:00:00 2001 From: wenhe <1046926120@qq.com> Date: Wed, 23 Sep 2026 14:27:13 +0800 Subject: [PATCH] ceshi 1 --- .../chaoguo/service/ChaoguoService.py | 33 ++++ .../service/ClientFeatureDispatcher.py | 96 +++++++++- .../xiangyemod/service/FeatureDispatcher.py | 166 +++++++++++++++++- .../xiangyemod/service/InterceptData.py | 80 ++++++++- .../xiangyemod/tangguo/TangguoData.py | 80 ++++++++- .../tangguo/service/TangguoService.py | 29 +++ .../youguo/service/YouguoService.py | 27 +++ tuilun/全部功能做了什么.txt | 46 +++++ tuilun/全部功能没做什么.txt | 14 ++ tuilun/右键拦截白名单清单.txt | 62 ++++++- 10 files changed, 618 insertions(+), 15 deletions(-) diff --git a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/chaoguo/service/ChaoguoService.py b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/chaoguo/service/ChaoguoService.py index 2807bea..d01c040 100644 --- a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/chaoguo/service/ChaoguoService.py +++ b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/chaoguo/service/ChaoguoService.py @@ -108,6 +108,12 @@ class ChaoguoService(BlueFoxServerSystem): """手持物品右键方块表面路由: 盖饭成品菜 + 米饭三形态(盖饭/蛋炒饭)""" return {r["item"]: True for r in ITEM_USE_ON_RULES} + def ownsItemUseOn(self, itemName, clickedName): + """声明该(手持物品,被点方块)组合由本服务 itemUseOn 规则处理(盖饭/蛋炒饭)。 + 被点方块(米饭/成品菜)虽也被"总食用"登记为右键方块(吃), 但盖饭转换应仍走 + itemUseOn, 故 dispatcher 据此对盖饭组合放行(不因被点方块归属别的服务而跳过)。""" + return (itemName, clickedName) in self.itemUseOnRecipes + def handleBlockUse(self, args): """由 FeatureDispatcher 转发的右键方块入口""" blockName = args.get("blockName") @@ -204,6 +210,33 @@ class ChaoguoService(BlueFoxServerSystem): # 二、通用转换执行 # ============================================================================ + def handleTakeoutRequest(self, playerId, blockName, itemName, dim, pos): + """客户端显式触发的出锅请求(消闪方案, 同汤锅). + 客户端已把 (盘子, 炒锅成品) 的放置预览拦掉(见 ClientFeatureDispatcher), + 本方法在服务端补齐出锅逻辑: 校验落点仍是该成品 + 精确定位 take_out 规则 + -> 复用 handleSwitch(含 needBelow/needFlag 门控), 交给它执行出锅""" + # 守卫1: 防空手 + if not itemName or itemName in ("minecraft:air",): + return + try: + b = comp.CreateBlockInfo(LevelId).GetBlockNew(pos, dim) + cur = b.get("name") if b else None + except Exception: + cur = None + # 守卫2: 落点已不是该成品 -> 跳过, 防双份 + if cur != blockName: + print "[TakeoutRequest-SKIP-ALREADY]", "want:", blockName, "cur:", cur, "pos:", pos + return + recipe = self.recipes.get((blockName, itemName)) + if not recipe or recipe.get("action") != "take_out": + return + # 守卫3: 冷却, 防连点双发 + if not self.checkCooldown((dim, pos[0], pos[1], pos[2]), 0.4): + return + itemDict = self.getCarriedItem(playerId) + self.handleSwitch(recipe, playerId, pos, dim, itemDict) + print "[TakeoutRequest-DONE]", "player:", playerId, "item:", itemName, "block:", blockName + def handleSwitch(self, recipe, playerId, pos, dim, itemDict): # 需要下方方块(翻炒: 炒锅下须是点燃的炉灶): 不满足则提示并拦截 needBelow = recipe.get("needBelow") diff --git a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/ClientFeatureDispatcher.py b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/ClientFeatureDispatcher.py index 78bbc24..33b2ff1 100644 --- a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/ClientFeatureDispatcher.py +++ b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/ClientFeatureDispatcher.py @@ -19,6 +19,7 @@ 共享数据 InterceptData.py (客户端/服务端同一份, 见其注释) ================================================================================ """ +import time import mod.client.extraClientApi as clientApi ClientSystem = clientApi.GetClientSystemCls() @@ -26,7 +27,23 @@ clientComp = clientApi.GetEngineCompFactory() from ...BlueFoxTools.SpecialFunciton.BlueFoxSystem import BlueFoxClientSystem from .InterceptData import (ITEM_USE_ON_CANCEL, ITEM_USE_ON_CANCEL_BY_ITEM, - SUSHI_BLOCKS, COATING_ITEMS) + SUSHI_BLOCKS, SUSHI_CANCEL, COATING_ITEMS, + TAKEOUT_CANCEL, GAI_FAN_CANCEL) + +# 自定义事件: 客户端拦(碗/盘,汤锅/炒锅/油锅成品)放置预览后, 显式通知服务端执行盛出 +# 服务端在 FeatureDispatcher 用同一事件名监听(见 service/FeatureDispatcher.py) +TAKEOUT_EVENT = "TakeoutRequest" + +# 自定义事件: 客户端拦(成品菜/米饭, 米饭/成品菜/蛋炒饭) 盖饭转换的放置预览后, +# 显式通知服务端执行盖饭转换(同盛出机制)。若不显式通知, 客户端 ret=True 会吞掉 +# 服务端 ServerItemUseOnEvent, 导致盖饭"点无反应"。 +GAI_FAN_EVENT = "GaifanRequest" + +# 自定义事件: 客户端拦【其余全部 itemUseOn 转换】的放置预览后, 显式通知服务端执行(同盖饭)。 +# 覆盖: 面食(生面饼烙馍/面粉加鸡蛋变面糊/生食蒸笼)、汤锅(锅态汤->汤面)、原版装盘(南瓜派 +# 等->盘中餐)、相邻放置(放死鱼/生鸡块/切菜)、厨具蘸油(锅铲/带油锅铲)、寿司、裹粉、 +# 种水稻. 若不显式通知, 客户端 ret=True 会吞掉 ServerItemUseOnEvent, 这些转换"点无反应"。 +ITEM_USE_ON_REQUEST = "ItemUseOnRequest" class ClientFeatureDispatcher(BlueFoxClientSystem): @@ -35,6 +52,10 @@ class ClientFeatureDispatcher(BlueFoxClientSystem): def __init__(self, namespace, systemName): BlueFoxClientSystem.__init__(self, namespace, systemName) print "===== ClientFeatureDispatcher init =====" + # 盛出/盖饭/出锅 后的客户端放置冷却: key=playerId@(x,y,z), value=时间戳. + # 转换完成后一段时间内, 该位置再被当作"放置"会直接 ret 吞掉, 消除"转换后 + # 由于引擎重置右键导致多放置一次"的闪一下。时长 1.5 秒(用户要求明显可见)。 + self._afterCd = {} self.ListenForEvent(clientApi.GetEngineNamespace(), clientApi.GetEngineSystemName(), "ClientItemUseOnEvent", self, self.OnItemUseOn) @@ -64,9 +85,28 @@ class ClientFeatureDispatcher(BlueFoxClientSystem): if not itemName: return - # 纯手持物品取消 (相邻放置/手持吃物品右键表面): 只看 item + # 转换后冷却: 同一玩家同一坐标, 若刚做过盛出/盖饭/出锅, 短时间内再被引擎 + # 当作"放置" -> 直接吞掉(不触发服务端, 也不渲染放置预览). 消除"转换后 + # 由于引擎重置右键导致的多放置闪烁"。 + pId = args.get("entityId") or args.get("playerId") + cdKey = "%s@%s_%s_%s" % (pId, args.get("x"), args.get("y"), args.get("z")) + _t = self._afterCd.get(cdKey) + if _t is not None and (time.time() - _t) < 1.5: + args["ret"] = True + return + + # 纯手持物品取消 (相邻放置/手持吃物品右键表面): 只看 item, 服务端走 handleItemUseOn + # (Yuanban 相邻放置/装盘、Natural 种水稻、Shiyongfood 直接吃)。这些组合一旦客户端 + # ret=True 会吞掉 ServerItemUseOnEvent, 故必须显式通知服务端补齐(盖饭同款机制)。 + # 【注意】此分支为"相邻格放置/装盘", 被点【表面坐标】不变, 不能设 _afterCd, + # 否则会误吞同一表面 1.5s 内的连续放置. 去重交给服务端 handleItemUseOn 自带冷却。 if itemName in ITEM_USE_ON_CANCEL_BY_ITEM: args["ret"] = True + self.NotifyToServer(ITEM_USE_ON_REQUEST, { + "playerId": pId, + "x": args.get("x"), "y": args.get("y"), "z": args.get("z"), + "blockName": blockName, "itemName": itemName, + }) return if not blockName: @@ -74,18 +114,66 @@ class ClientFeatureDispatcher(BlueFoxClientSystem): # 精确组合 (手持item, 被点block) pair = (itemName, blockName) + + # 盖饭/蛋炒饭(itemUseOn): 必须在此处理(比 ITEM_USE_ON_CANCEL 先), 否则会被 + # ITEM_USE_ON_CANCEL 纯 ret 吞掉 -> 服务端 ServerItemUseOnEvent 不触发 -> 盖饭无反应。 + if pair in GAI_FAN_CANCEL: + args["ret"] = True + self._afterCd[cdKey] = time.time() + self.NotifyToServer(GAI_FAN_EVENT, { + "playerId": pId, + "x": args.get("x"), "y": args.get("y"), "z": args.get("z"), + "blockName": blockName, "itemName": itemName, + }) + return + + # 其余 itemUseOn 转换(面食/汤锅/装盘/厨具蘸油/寿司/裹粉): 纯 ret 会吞掉服务端 + # ServerItemUseOnEvent -> 服务端 handleItemUseOn 不触发 -> "点无反应"(盖饭同款)。 + # 统一改为 ret + 显式 ItemUseOnRequest, 由服务端按 itemName 路由补齐 handleItemUseOn。 if pair in ITEM_USE_ON_CANCEL: args["ret"] = True + self._afterCd[cdKey] = time.time() + self.NotifyToServer(ITEM_USE_ON_REQUEST, { + "playerId": pId, + "x": args.get("x"), "y": args.get("y"), "z": args.get("z"), + "blockName": blockName, "itemName": itemName, + }) return - # 寿司: 手持寿司方块物品 右键 自家寿司方块 -> 取消默认放置 + # 汤锅盛出: 手持 碗/盘 右键 成品汤方块 -> 客户端取消放置预览(消闪), + # 并显式通知服务端执行盛出(take_out)。此组合客户端拦掉后, + # 服务端 ServerBlockUseEvent 不再触发, 故必须发 TakeoutRequest 补齐盛出逻辑。 + if pair in TAKEOUT_CANCEL: + args["ret"] = True + self._afterCd[cdKey] = time.time() + self.NotifyToServer(TAKEOUT_EVENT, { + "playerId": pId, + "x": args.get("x"), "y": args.get("y"), "z": args.get("z"), + "blockName": blockName, "itemName": itemName, + }) + return + + # 寿司: 手持寿司方块物品 右键 自家寿司方块 -> 服务端走 ShousiService.handleItemUseOn + # (取消默认放置) + handleBlockUse(堆叠). 客户端 ret 吞事件后显式通知补齐。 if itemName in SUSHI_BLOCKS and blockName in SUSHI_BLOCKS: args["ret"] = True + self._afterCd[cdKey] = time.time() + self.NotifyToServer(ITEM_USE_ON_REQUEST, { + "playerId": pId, + "x": args.get("x"), "y": args.get("y"), "z": args.get("z"), + "blockName": blockName, "itemName": itemName, + }) return - # 裹粉: 手持生食材 右键 面粉块 -> 取消默认放置 + # 裹粉: 手持生食材 右键 面粉块 -> 服务端走 ShicaiService.handleItemUseOn(裹粉). if itemName in COATING_ITEMS and blockName == "rtdd:farineblock_3": args["ret"] = True + self._afterCd[cdKey] = time.time() + self.NotifyToServer(ITEM_USE_ON_REQUEST, { + "playerId": pId, + "x": args.get("x"), "y": args.get("y"), "z": args.get("z"), + "blockName": blockName, "itemName": itemName, + }) # ============================================================================ # 入口3: 手持直接吃物品(长按/空中使用) -> cancel 默认吃 diff --git a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/FeatureDispatcher.py b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/FeatureDispatcher.py index 4452301..f7f95c0 100644 --- a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/FeatureDispatcher.py +++ b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/FeatureDispatcher.py @@ -41,6 +41,21 @@ comp = serverApi.GetEngineCompFactory() # 组件工厂 # ---- 继承 BlueFox 框架的系统基类 ---- from ...BlueFoxTools.SpecialFunciton.BlueFoxSystem import BlueFoxServerSystem from ...BlueFoxTools.ToolsConfig import LevelId +from ...BlueFoxTools.ModConfig import MOD_NAME + +# ---- 汤锅盛出自定义事件名(与客户端 ClientFeatureDispatcher TAKEOUT_EVENT 一致) ---- +TAKEOUT_EVENT = "TakeoutRequest" + +# ---- 盖饭/蛋炒饭 自定义事件名(与客户端 GAI_FAN_EVENT 一致) ---- +GAI_FAN_EVENT = "GaifanRequest" + +# ---- 通用"手持物品右键方块表面"转换请求(与客户端 ITEM_USE_ON_REQUEST 一致). +# 用于修复"客户端提前 ret=True 吞掉 ServerItemUseOnEvent 导致 itemUseOn 转换 +# 点无反应"的问题(盖饭同款). 客户端对所有走 handleItemUseOn 的白名单组合, +# ret 掉放置预览后显式 Notify 本事件, 服务端按 itemName 路由到相应服务. +# 与 GaifanRequest 的区别: 本事件覆盖全部 itemUseOn 转换(面食/汤锅/装盘/ +# 相邻放置/厨具蘸油/寿司/裹粉/种水稻), 而非仅盖饭. ---- +ITEM_USE_ON_REQUEST = "ItemUseOnRequest" # ---- 方块实体数据组件(计时持久化:记录开始时间戳,重启后继续计时) ---- blockEntityDataComp = comp.CreateBlockEntityData(LevelId) @@ -196,6 +211,20 @@ class FeatureDispatcher(BlueFoxServerSystem): self.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(), "ItemUseOnAfterServerEvent", self, self.OnItemPlaceAfter) + # 7. TakeoutRequest —— 客户端拦截(碗/盘,汤锅/炒锅/油锅成品)放置预览后, 显式请求服务端盛出。 + # 客户端系统 ClientFeatureDispatcher 用 NotifyToServer(TAKEOUT_EVENT) 发送, + # 服务端以 MOD_NAME + 客户端系统名 监听该自定义事件。 + self.ListenForEvent(MOD_NAME, "ClientFeatureDispatcher", + TAKEOUT_EVENT, self, self.OnTakeoutRequest) + # 8. GaifanRequest —— 客户端拦截(成品菜/米饭,米饭/成品菜)盖饭放置预览后, 显式请求转换。 + # 同盛出: 必须显式触发, 否则客户端 ret=True 吞掉 ServerItemUseOnEvent, 盖饭无反应。 + self.ListenForEvent(MOD_NAME, "ClientFeatureDispatcher", + GAI_FAN_EVENT, self, self.OnGaifanRequest) + # 9. ItemUseOnRequest —— 客户端拦截其余全部 itemUseOn 转换(面食/汤锅/装盘/相邻放置/ + # 厨具蘸油/寿司/裹粉/种水稻)的放置预览后, 显式请求服务端执行对应 handleItemUseOn。 + # (与 GaifanRequest 同机制, 统一覆盖全部 itemUseOn 转换) + self.ListenForEvent(MOD_NAME, "ClientFeatureDispatcher", + ITEM_USE_ON_REQUEST, self, self.OnItemUseOnRequest) def UnListenEvent(self): self.UnListenForEvent(serverApi.GetEngineNamespace(), @@ -216,6 +245,12 @@ class FeatureDispatcher(BlueFoxServerSystem): self.UnListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(), "ItemUseOnAfterServerEvent", self, self.OnItemPlaceAfter) + self.UnListenForEvent(MOD_NAME, "ClientFeatureDispatcher", + TAKEOUT_EVENT, self, self.OnTakeoutRequest) + self.UnListenForEvent(MOD_NAME, "ClientFeatureDispatcher", + GAI_FAN_EVENT, self, self.OnGaifanRequest) + self.UnListenForEvent(MOD_NAME, "ClientFeatureDispatcher", + ITEM_USE_ON_REQUEST, self, self.OnItemUseOnRequest) # ============================================================================ # 主入口1:玩家右键方块 → 按 blockOwner 路由到右键服务 @@ -232,8 +267,15 @@ class FeatureDispatcher(BlueFoxServerSystem): 服务返回 False = 当前组合无匹配规则 → 交还默认行为 """ blockName = args.get("blockName") + playerId = args.get("playerId") + # 手持物品名(用于区分空手/木碗/盘子) + try: + _itemDict = self.getCarriedItem(playerId) + _handItem = _itemDict.get("newItemName") if _itemDict else "NONE" + except Exception: + _handItem = "NONE" services = self.blockOwnerAll.get(blockName) - print "[FD-BlockUse]", blockName, "svcs:", ([s.__class__.__name__ for s in services] if services else "NONE") + print "[FD-BlockUse-ENTER]", "player:", playerId, "hand:", _handItem, "block:", blockName, "svcs:", ([s.__class__.__name__ for s in services] if services else "NONE") if not services: # 这个方块不属于任何已注册的功能 → 交给原版/其他模组处理 return @@ -242,9 +284,10 @@ class FeatureDispatcher(BlueFoxServerSystem): handled = service.handleBlockUse(args) if handled: args['cancel'] = True - playerId = args.get("playerId") self._cancelItemUse[playerId] = True + print "[FD-BlockUse-DONE]", "player:", playerId, "hand:", _handItem, "block:", blockName, "svc:", service.__class__.__name__, "-> cancel=True, _cancelItemUse=True" return + print "[FD-BlockUse-NOMATCH]", "player:", playerId, "hand:", _handItem, "block:", blockName, "-> 无匹配规则, 放行" # ============================================================================ # 主入口2:手持物品右键方块表面 → 按 itemUseOnOwner 路由到右键服务 @@ -269,6 +312,7 @@ class FeatureDispatcher(BlueFoxServerSystem): # (与 OnItemTryUse 消费标记取消"吃/喝"是同一模式。) if self._cancelItemUse.pop(playerId, False): args['ret'] = True + print "[FD-ItemUseOn-CONSUME-CANCEL]", "player:", playerId, "item:", args.get("itemName"), "block:", args.get("blockName"), "-> ret=True 取消放置" return itemName = args.get("itemName") @@ -301,8 +345,18 @@ class FeatureDispatcher(BlueFoxServerSystem): # 例外: 当前服务本身就在被点方块的归属列表里(如 食材裹粉: 面粉块归 # ShicaiService+面食服务 管辖, 手持生食材右键它时放行给 handleItemUseOn # 处理) 则继续尝试。 + # 【额外例外】服务声明了 ownsItemUseOn(itemName, clickedName) 且返回 True, + # 说明该(手持物品,被点方块)组合明确由本服务的 itemUseOn 规则处理(如炒锅盖饭: + # 成品菜/米饭尽管也被"总食用"登记为右键吃方块, 但盖饭转换应仍走 itemUseOn)。 + # 此时不因被点方块归属别的服务而跳过, 否则盖饭永不被触发。 if clickedName and owners and service not in owners: - continue + _owns = None + try: + _owns = service.ownsItemUseOn(itemName, clickedName) + except Exception: + _owns = None + if not _owns: + continue handled = service.handleItemUseOn(args) if handled: @@ -348,11 +402,117 @@ class FeatureDispatcher(BlueFoxServerSystem): return if not blockName: return + print "[FD-Placed-AFTER]", "player:", playerId, "placedBlock:", blockName, "targetPos:", targetPos # 落点是计时源方块 → 带放置者启动(判断营火 + 谁放提示发给谁) service = self.timerOwner.get(blockName) if service and hasattr(service, "startTimer"): service.startTimer(dim, targetPos, blockName, playerId) + # ============================================================================ + # 主入口2.6:客户端显式触发的"盛出"请求(汤锅 take_out 专用,消闪方案) + # ============================================================================ + + def OnTakeoutRequest(self, args): + """ + 客户端 ClientFeatureDispatcher 在拦截(碗/盘, 汤锅成品)放置预览后, + 显式 NotifyToServer 发来的盛出请求。因为客户端已 ret=True 把该组合的 + ServerBlockUseEvent 吞掉(消闪), 所以盛出逻辑必须在这里手动补齐。 + + 与服务器普通右键一致, 需要校验: 别再重复执行, 关键落在 handleTakeoutRequest + 里"落点仍是成品方块才执行"的守卫上(防客户端事件与服务端事件双份)。 + """ + playerId = args.get("playerId") + x, y, z = args.get("x"), args.get("y"), args.get("z") + blockName = args.get("blockName") + itemName = args.get("itemName") + if not (playerId and x is not None and y is not None and z is not None and blockName): + return + try: + dim = comp.CreateDimension(playerId).GetEntityDimensionId() + except Exception: + return + services = self.blockOwnerAll.get(blockName) + if not services: + return + for service in services: + if hasattr(service, "handleTakeoutRequest"): + # handleTakeoutRequest 内部已校验"落点仍是成品方块" + 冷却, 防双份。 + # 盛出后引擎"把手持碗/盘放到已变空锅"的多放置闪烁由客户端 CD(1.5秒) + # 在客户端吞掉, 服务端不再设 _cancelItemUse(否则标记残留会吞掉玩家 + # 下一次真实的 ServerItemUseOnEvent, 影响其它操作)。 + service.handleTakeoutRequest(playerId, blockName, itemName, dim, (x, y, z)) + return + print "[FD-TakeoutRequest-NO-HANDLER]", blockName + + def OnGaifanRequest(self, args): + """ + 客户端 ClientFeatureDispatcher 在拦截(成品菜/米饭,米饭/成品菜)放置预览后, + 显式 NotifyToServer 发来的盖饭/蛋炒饭转换请求。客户端已 ret=True 把该组合的 + ServerItemUseOnEvent 吞掉(消闪), 这里必须显式补齐转换逻辑(否则盖饭"点无反应")。 + 构造 itemUseOn 所需的 args, 按 itemName 路由到 itemUseOn 服务(ChaoguoService)。 + """ + playerId = args.get("playerId") + x, y, z = args.get("x"), args.get("y"), args.get("z") + itemName = args.get("itemName") + if not (playerId and x is not None and y is not None and z is not None and itemName): + return + services = self.itemUseOnAll.get(itemName) + if not services: + print "[FD-GaifanRequest-NO-SVC]", itemName + return + # 复用服务端的 itemUseOn 参数结构(handleItemUseOn 读取 itemName/playerId/x/y/z) + useOnArgs = { + "itemName": itemName, + "playerId": playerId, + "entityId": playerId, + "x": x, "y": y, "z": z, + "blockName": args.get("blockName"), + } + for service in services: + if hasattr(service, "handleItemUseOn"): + # 盖饭是本方块原位转换成盖饭(消耗手持成品菜/米饭), 不是"放置手持方块", + # 因此不设 _cancelItemUse —— 否则标记残留会吞掉玩家下一次真实的 itemUseOn. + handled = service.handleItemUseOn(useOnArgs) + if handled: + return + print "[FD-GaifanRequest-NO-HANDLER]", itemName + + def OnItemUseOnRequest(self, args): + """ + 客户端 ClientFeatureDispatcher 在拦截【所有走 handleItemUseOn 的 itemUseOn 转换】 + (面食/汤锅/装盘/相邻放置/厨具蘸油/寿司/裹粉/种水稻) 放置预览后, 显式 NotifyToServer + 发来的通用转换请求. 因为客户端已 ret=True 吞掉该组合的 ServerItemUseOnEvent(消闪), + 服务端原本会被吞掉的 itemUseOn 转换在这里补齐路由(与 OnGaifanRequest 同机制). + + 按 itemName 路由到 itemUseOnAll 里的服务(可能有多个, 如 裹粉Shicai + 原版放置Yuanban + 都处理 土豆/鸡肉/猪肉, 逐个 fallback, 第一个返回 True 的处理成功). + 注意: 各服务 handleItemUseOn 内部自带 checkCooldown(同坐标/同物品), 即使与真实的 + ServerItemUseOnEvent 重复触发, 冷却也会拦截第二次, 不会双重消耗/双重转换. + """ + playerId = args.get("playerId") + x, y, z = args.get("x"), args.get("y"), args.get("z") + itemName = args.get("itemName") + if not (playerId and x is not None and y is not None and z is not None and itemName): + return + services = self.itemUseOnAll.get(itemName) + if not services: + print "[FD-ItemUseOnRequest-NO-SVC]", itemName + return + # 复用服务端的 itemUseOn 参数结构(handleItemUseOn 读取 itemName/playerId/x/y/z) + useOnArgs = { + "itemName": itemName, + "playerId": playerId, + "entityId": playerId, + "x": x, "y": y, "z": z, + "blockName": args.get("blockName"), + } + for service in services: + if hasattr(service, "handleItemUseOn"): + handled = service.handleItemUseOn(useOnArgs) + if handled: + return + print "[FD-ItemUseOnRequest-NO-HANDLER]", itemName + # ============================================================================ # 主入口3:拦截物品使用(防止喝药水/吃食物等默认行为) # ============================================================================ diff --git a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/InterceptData.py b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/InterceptData.py index 6e6f908..cb947a6 100644 --- a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/InterceptData.py +++ b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/InterceptData.py @@ -73,17 +73,35 @@ except Exception: # ---- 炒锅: 盖饭双向 + 蛋炒饭 (itemUseOn, surface=米饭/成品菜) ---- try: - from ..chaoguo.ChaoguoData import ITEM_USE_ON_RULES as CHAOGUO_USON + from ..chaoguo.ChaoguoData import ( + ITEM_USE_ON_RULES as CHAOGUO_USON, + SWITCH_RULES as CHAOGUO_SWITCH, + PLATE as CHAOGUO_PLATE, + ) _ALL_RULE_TABLES.append(CHAOGUO_USON) except Exception: - pass + CHAOGUO_SWITCH, CHAOGUO_PLATE = None, None # ---- 汤锅: 手持锅态汤右键 熟面条 (itemUseOn) ---- try: - from ..tangguo.TangguoData import ITEM_USE_ON_RULES as TANGGUO_USON + from ..tangguo.TangguoData import ( + ITEM_USE_ON_RULES as TANGGUO_USON, + SWITCH_RULES as TANGGUO_SWITCH, + BOWL as TANGGUO_BOWL, + PLATE as TANGGUO_PLATE, + ) _ALL_RULE_TABLES.append(TANGGUO_USON) except Exception: - pass + TANGGUO_SWITCH, TANGGUO_BOWL, TANGGUO_PLATE = None, None, None + +# ---- 油锅: 手持盘子 出锅 (take_out) ---- +try: + from ..youguo.YouguoData import ( + SWITCH_RULES as YOUGUO_SWITCH, + PLATE as YOUGUO_PLATE, + ) +except Exception: + YOUGUO_SWITCH, YOUGUO_PLATE = None, None # ---- 原版放置/盘子转换 (itemUseOn, surface=相邻放置 / source=盘子) ---- try: @@ -117,6 +135,57 @@ def _as_list(value): # ---- 由各 Data 规则表自动派生 ---- AUTO_CANCEL = _collect_all() +# ============================================================================ +# 三之A、"盛出/出锅"专用: 手持容器(木碗/盘子) 右键 成品方块 -> 客户端拦截 +# 放置预览(消闪) + 显式通知服务端执行盛出(见 ClientFeatureDispatcher / +# FeatureDispatcher TakeoutRequest). 从 汤锅/炒锅/油锅 的 SWITCH_RULES 里 +# action=="take_out" 且 item 是容器(木碗/盘子) 的规则自动派生. +# 空手(item=None)取饭团/水煮蛋/煎饼、菜刀切豆腐 不在此列, 走旧路径. +# ============================================================================ +TAKEOUT_CANCEL = set() + + +def _derive_takeout(switch_rules, *container_items): + """从一段 SWITCH_RULES 派生 take_out 且 item 是容器的 (item, block) 组合""" + if not switch_rules: + return set() + out = set() + for _r in switch_rules: + if not isinstance(_r, dict): + continue + if _r.get("action") != "take_out": + continue + _it = _r.get("item") + _bk = _r.get("block") + if _it in container_items and isinstance(_bk, basestring) and _bk: + out.add((_it, _bk)) + return out + + +# 汤锅: 木碗/盘子 盛出碗装成品 +TAKEOUT_CANCEL |= _derive_takeout(TANGGUO_SWITCH, TANGGUO_BOWL, TANGGUO_PLATE) +# 炒锅: 手持盘子 出锅盘装成品(空手出锅的煎饼/馍不在此列) +TAKEOUT_CANCEL |= _derive_takeout(CHAOGUO_SWITCH, CHAOGUO_PLATE) +# 油锅: 手持盘子 出锅炸物 +TAKEOUT_CANCEL |= _derive_takeout(YOUGUO_SWITCH, YOUGUO_PLATE) + +# ============================================================================ +# 三之B、"盖饭/蛋炒饭"(itemUseOn) 专用: 手持 成品菜/米饭 右键 米饭/成品菜/炒锅蛋炒饭 +# -> 客户端拦截放置预览(消闪) + 显式通知服务端执行转换(同 TakeoutRequest 机制). +# 从炒锅 ITEM_USE_ON_RULES(surface 字段) 自动派生: 盖饭双向 + 蛋炒饭. +# 若不单独抽出, 这些组合会被 ITEM_USE_ON_CANCEL 以纯 ret=True 吞掉, +# 导致服务端 ServerItemUseOnEvent 不触发 -> 盖饭"点无反应"(服务端 owners 修复无效). +# ============================================================================ +GAI_FAN_CANCEL = set() +if CHAOGUO_USON: + for _r in CHAOGUO_USON: + if not isinstance(_r, dict): + continue + _it = _r.get("item") + _bk = _r.get("surface") + if isinstance(_it, basestring) and _it and isinstance(_bk, basestring) and _bk: + GAI_FAN_CANCEL.add((_it, _bk)) + # ---- Chuju 锅铲/油罐 inline 转换(在 ChujuService.handleItemUseOn 内联, 不在数据表) ---- # 手持 锅铲/带油锅铲 右键 油罐(oilcan)/炒锅(wok) 蘸油/还油/上油 -> 取消默认 CHUJU_INLINE_CANCEL = { @@ -206,4 +275,7 @@ ITEM_USE_ON_CANCEL_BY_ITEM = PLACE_ITEMS | EAT_ITEMS if __name__ == "__main__": print "=== 自动派生转换对 数量:", len(AUTO_CANCEL), "===" for _it, _bk in sorted(AUTO_CANCEL): + print " ", _it, "->", _bk + print "=== 汤锅盛出(TAKEOUT_CANCEL) 数量:", len(TAKEOUT_CANCEL), "===" + for _it, _bk in sorted(TAKEOUT_CANCEL): print " ", _it, "->", _bk \ No newline at end of file diff --git a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/tangguo/TangguoData.py b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/tangguo/TangguoData.py index 57135eb..ba1b9ed 100644 --- a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/tangguo/TangguoData.py +++ b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/tangguo/TangguoData.py @@ -377,9 +377,83 @@ SWITCH_RULES = [ "tip": "§a倒入豆浆, 开始熬制; 等计时结束变成 煮豆腐(熟), 拿菜刀右键切成 豆腐x16"}, # ---------------- 六、出锅(熟汤羹+木碗 -> 碗装成品, 锅变回汤锅(空)) ---------------- - # 【已迁移 2026-09-23】手持 木碗/盘子 右键 熟汤方块 的 take_out 全部搬到了 - # ITEM_USE_ON_RULES(source=surface), 走 itemUseOn 路径: 转换+取消放置同一事件, - # 进客户端白名单提前拦, 消除"盛出闪一下"。此处不再定义(避免 blockUse 先拦截)。 + {"block": CARROT_BEEF_SOUP_3, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_CARROT_BEEF, "consume": 1, + "tip": "§a盛出 胡萝卜牛肉汤, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": LAMB_SOUP_WITH_TURNIPS_3, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_LAMB_TURNIP, "consume": 1, + "tip": "§a盛出 胡萝卜羊肉汤, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": CARROT_RIBS_3, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_CARROT_RIBS, "consume": 1, + "tip": "§a盛出 胡萝卜排骨汤, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": VEGETABLE_BEEF_SOUP_3, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_VEGETABLE_BEEF, "consume": 1, + "tip": "§a盛出 清汤羊肉, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": VEGETABLE_LAMB_SOUP_3, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_VEGETABLE_LAMB, "consume": 1, + "tip": "§a盛出 蔬菜牛肉汤, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": VEGETABLE_LEAN_BROTH_3, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_VEGETABLE_LEAN, "consume": 1, + "tip": "§a盛出 蔬菜瘦肉汤, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": VEGETABLE_SSTEW_3, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_VEGETABLE_SSTEW, "consume": 1, + "tip": "§a盛出 蔬菜乱炖, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": BEEF_BONE_BROTH_3, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_BEEF_BONE, "consume": 1, + "tip": "§a盛出 胡萝卜土豆牛骨汤, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": LAMB_STEW_3, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_LAMB_STEW, "consume": 1, + "tip": "§a盛出 土豆胡萝卜炖羊肉, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": LAMB_CHOP_SOUP_3, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_LAMB_CHOP, "consume": 1, + "tip": "§a盛出 胡萝卜土豆羊排汤, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": CARROT_COD_SOUP_3, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_CARROT_COD, "consume": 1, + "tip": "§a盛出 胡萝卜鳕鱼汤, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": CARROT_FISH_SOUP_3, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_CARROT_FISH, "consume": 1, + "tip": "§a盛出 胡萝卜鲑鱼汤, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": EGG_COD_SOUP_3, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_EGG_COD, "consume": 1, + "tip": "§a盛出 蛋花鳕鱼汤, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": NORI_EGG_SOUP_3, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_NORI_EGG, "consume": 1, + "tip": "§a盛出 瘦肉蛋花汤, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": TOFU_FISH_SOUP_3, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_TOFU_FISH, "consume": 1, + "tip": "§a盛出 豆腐鲑鱼汤, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": CHICKEN_STEW_MUSHROOMS_3, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_MUSHROOM_CHICKEN, "consume": 1, + "tip": "§a盛出 蘑菇炖鸡, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": RAW_PIG_FOOD_SOUP_5, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_PIG_FOOT, "consume": 1, + "tip": "§a盛出 猪蹄汤, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": ROUJIAMO_SOUP_1, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_ROUJIAMO, "consume": 1, + "tip": "§a盛出 羊肉泡馍汤, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": COOKED_NOODLE_SOUP, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_NOODLE, "consume": 1, + "tip": "§a盛出 熟面条, 锅变回 汤锅(空); 熟面条可做汤面"}, + {"block": DUMPLINGS_SOUP_2, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_DUMPLINGS, "consume": 1, + "tip": "§a盛出 饺子_碗装, 锅变回 汤锅(空); 成品【吃】右键食用"}, + # 菜谱32 todo: 饺子汤_熟 + 盘子 -> 美味饺子(全份)盘装 + {"block": DUMPLINGS_SOUP_2, "item": PLATE, "action": "take_out", + "target": POT_EMPTY, "dropItem": PLATE_30A, "consume": 1, + "tip": "§a捞出 美味饺子(全份)盘装, 锅变回 汤锅(空); 成品【吃】右键食用"}, + {"block": VEGETABLE_FISH_SOUP_3, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_VEGETABLE_FISH, "consume": 1, + "tip": "§a盛出 蔬菜鱼片汤, 锅变回 汤锅(空); 成品【吃】右键食用"}, + # 菜谱38 碗装米饭(木碗盛出) + {"block": RICE_POT_1, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_RICE_1, "consume": 1, + "tip": "§a盛出 米饭_1(熟米饭_形态1), 锅变回 汤锅(空); 碗装米饭供炒锅蛋炒饭"}, + {"block": RICE_POT_2, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_RICE_2, "consume": 1, + "tip": "§a盛出 米饭_2(熟米饭_形态2), 锅变回 汤锅(空); 碗装米饭供炒锅蛋炒饭"}, + {"block": RICE_POT_3, "item": BOWL, "action": "take_out", + "target": POT_EMPTY, "dropItem": BOWL_RICE_3, "consume": 1, + "tip": "§a盛出 米饭_3(熟米饭_形态3), 锅变回 汤锅(空); 碗装米饭供炒锅蛋炒饭"}, # ---------------- 七、取出(空手/菜刀, 锅变回汤锅(空)) ---------------- # 菜谱37 饭团 diff --git a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/tangguo/service/TangguoService.py b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/tangguo/service/TangguoService.py index bcc373f..c3ba68a 100644 --- a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/tangguo/service/TangguoService.py +++ b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/tangguo/service/TangguoService.py @@ -257,6 +257,35 @@ class TangguoService(BlueFoxServerSystem): # 二、通用转换执行 # ============================================================================ + def handleTakeoutRequest(self, playerId, blockName, itemName, dim, pos): + """客户端显式触发的盛出请求(消闪方案)。 + 客户端已把 (碗/盘, 成品汤方块) 的放置预览拦掉(见 ClientFeatureDispatcher), + 本方法在服务端补齐盛出逻辑, 与右键 take_out 等效: + - 校验落点仍是该成品方块(防客户端事件与服务端 ServerBlockUseEvent 双份) + - 用 (block, item) 精确定位盛出规则并执行 switch + """ + # 守卫1: 防空手/非碗盘(客户端已过滤, 这里再兜底) + if not itemName or itemName in ("minecraft:air",): + return + try: + b = comp.CreateBlockInfo(LevelId).GetBlockNew(pos, dim) + cur = b.get("name") if b else None + except Exception: + cur = None + # 守卫2: 落点方块已不是该成品(可能已被旧路径/上一次盛出处理掉) -> 跳过, 防重复 + if cur != blockName: + print "[TakeoutRequest-SKIP-ALREADY]", "want:", blockName, "cur:", cur, "pos:", pos + return + recipe = self.recipes.get((blockName, itemName)) + if not recipe or recipe.get("action") != "take_out": + return + # 守卫3: 冷却, 防连点双发 + if not self.checkCooldown((dim, pos[0], pos[1], pos[2]), 0.4): + return + itemDict = self.getCarriedItem(playerId) + self.handleSwitch(recipe, playerId, pos, dim, itemDict) + print "[TakeoutRequest-DONE]", "player:", playerId, "item:", itemName, "block:", blockName + def handleSwitch(self, recipe, playerId, pos, dim, itemDict): # 消耗物品(数量不足则拦截, 不转换) consume = recipe.get("consume", 0) diff --git a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/youguo/service/YouguoService.py b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/youguo/service/YouguoService.py index 38f277c..728da81 100644 --- a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/youguo/service/YouguoService.py +++ b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/youguo/service/YouguoService.py @@ -219,6 +219,33 @@ class YouguoService(BlueFoxServerSystem): # 二、通用转换执行 # ============================================================================ + def handleTakeoutRequest(self, playerId, blockName, itemName, dim, pos): + """客户端显式触发的出锅请求(消闪方案, 同汤锅). + 客户端已把 (盘子, 熟炸物) 的放置预览拦掉(见 ClientFeatureDispatcher), + 本方法在服务端补齐出锅逻辑: 校验落点仍是该成品 + 精确定位 take_out 规则 + -> 复用 handleSwitch(含 needBelow 门控), 交给它执行出锅""" + # 守卫1: 防空手 + if not itemName or itemName in ("minecraft:air",): + return + try: + b = comp.CreateBlockInfo(LevelId).GetBlockNew(pos, dim) + cur = b.get("name") if b else None + except Exception: + cur = None + # 守卫2: 落点已不是该成品 -> 跳过, 防双份 + if cur != blockName: + print "[TakeoutRequest-SKIP-ALREADY]", "want:", blockName, "cur:", cur, "pos:", pos + return + recipe = self.recipes.get((blockName, itemName)) + if not recipe or recipe.get("action") != "take_out": + return + # 守卫3: 冷却, 防连点双发 + if not self.checkCooldown((dim, pos[0], pos[1], pos[2]), 0.4): + return + itemDict = self.getCarriedItem(playerId) + self.handleSwitch(recipe, playerId, pos, dim, itemDict) + print "[TakeoutRequest-DONE]", "player:", playerId, "item:", itemName, "block:", blockName + def handleSwitch(self, recipe, playerId, pos, dim, itemDict): # 需要下方方块(放料: 油锅下须是点燃的炉灶才计时炸制): 不满足则提示并拦截 needBelow = recipe.get("needBelow") diff --git a/tuilun/全部功能做了什么.txt b/tuilun/全部功能做了什么.txt index 75c6ba5..9cf8ad5 100644 --- a/tuilun/全部功能做了什么.txt +++ b/tuilun/全部功能做了什么.txt @@ -705,6 +705,10 @@ FurnitureData+FurnitureService 实现, 注册到 FeatureDispatcher) 【提示/体验】倒油/取油/放料/出锅均有提示(含消耗数量与计时时长); 数量不足/油锅下无点燃炉灶 有提示并拦截; 右键冷却0.4秒; 手持方块物品右键油锅类功能方块取消默认放置(全局) [已实现] +【盛出消闪 2026-09-23】手持盘子右键熟炸物(盘子 take_out, 6条), 改走客户端拦截+显式触发 +(同汤锅): 客户端 ClientItemUseOnEvent ret=True 消闪 + NotifyToServer('TakeoutRequest') +-> YouguoService.handleTakeoutRequest(校验落点仍是成品防重复). 由 InterceptData.TAKEOUT_CANCEL +自动派生 [已实现] 【留后】各盘装成品 右键吃(总食用功能后续实现)、天妇罗炸虾递减吃(整份->半份 plate_49a)、 盘子用后变脏 @@ -787,6 +791,14 @@ FurnitureData+FurnitureService 实现, 注册到 FeatureDispatcher) 【提示/体验】所有转换有提示(含消耗数量与下一步指引: "可继续加料 或 等计时结束变成X, 手持木碗出锅"); 数量不足/下方无点燃炉灶有提示并拦截; 右键冷却0.4秒; 手持方块物品右键 汤锅类功能方块取消默认放置(全局) [已实现] +【盛出消闪 2026-09-23】手持木碗/盘子右键成品汤方块(碗/盘 take_out), 改走客户端拦截+ +显式触发: 客户端 ClientItemUseOnEvent 对该组合 ret=True(取消放置前摇, 消除"闪一下"), +再 NotifyToServer('TakeoutRequest') 显式通知服务端执行盛出(FeatureDispatcher.OnTakeoutRequest +-> TangguoService.handleTakeoutRequest, 校验落点仍是成品防重复). 空手取出/菜刀切豆腐不走此路, +照旧 ServerBlockUseEvent. 由 InterceptData.TAKEOUT_CANCEL 自动派生 [已实现] +- 后续修复: 客户端新增 1.5 秒放置冷却(_afterCd): 盛出/出锅后, 同一坐标短时间内再被引擎 + 当作"放置"直接 ret 吞掉, 消除"变锅后多放置一次碗/盘"的闪烁 (2026-09-23 修) [已实现] +- 服务端 OnTakeoutRequest 不再设 _cancelItemUse(避免标记残留吞后续 itemUseOn), 由客户端 CD 兜 [已实现] 【留后】各碗装成品/汤面 右键吃(总食用功能后续实现) @@ -881,10 +893,18 @@ FurnitureData+FurnitureService 实现, 注册到 FeatureDispatcher) - 反向: 手持 米饭(形态1/2/3任一) 右键 上述成品菜方块, 消耗1个米饭, 菜品原地变对应盖饭 [已实现] - 蛋炒饭加米饭: 手持米饭(任一形态)右键 炒锅_86(蛋炒饭_加胡萝卜_熟) -> 炒锅_87(蛋炒饭_加米饭_熟) [已实现] - 手持成品菜/米饭 右键 本分类功能方块 无对应转换时直接取消默认放置(不"先放再消失") [已实现] +- 修复: 盖饭被客户端白名单吞掉而"点无反应"(成品菜/米饭组合在 ITEM_USE_ON_CANCEL, + 客户端 ret=True 吞掉服务端 ServerItemUseOnEvent) -> 改走客户端拦放置预览(消闪) + + 显式 NotifyToServer('GaifanRequest') -> FeatureDispatcher.OnGaifanRequest + -> ChaoguoService.handleItemUseOn(构造 itemUseOn args), 同盛出机制 (2026-09-23 修) [已实现] 【提示/体验】所有转换有提示(含消耗数量与下一步指引); 数量不足/翻炒无下方点燃炉灶/ 出锅门控未达成(煎蛋未熟/酱香饼未翻炒) 有提示并拦截; 翻炒冷却0.3秒, 其余右键冷却0.4秒; 手持方块物品右键炒锅类功能方块取消默认放置(全局) [已实现] +【盛出消闪 2026-09-23】手持盘子右键炒锅熟成品(盘子 take_out, 38条), 改走客户端拦截+ +显式触发(同汤锅): 客户端 ClientItemUseOnEvent ret=True 消闪 + NotifyToServer('TakeoutRequest') +-> ChaoguoService.handleTakeoutRequest(校验落点仍是成品防重复). 空手出锅(煎饼/馍等 item=None) +不走此路, 照旧 ServerBlockUseEvent. 由 InterceptData.TAKEOUT_CANCEL 自动派生 [已实现] 【留后】各盘装成品/盖饭 右键吃(总食用功能后续实现)、半份/部分份变体出锅(见 全部功能没做什么.txt) @@ -982,3 +1002,29 @@ FurnitureData+FurnitureService 实现, 注册到 FeatureDispatcher) 成品菜/米饭右键炒锅中间态方块→取消放置"的服务端兜底, 因要使客户端白名单宁少勿多 (避免误拦正常放置), 该边缘防误触仍只服务端处理(功能正确, 仅轻微闪烁), 暂不搬客户端 [已复查] +######################################## +【统一 itemUseOn 转换 消闪修复】(2026-09-23) +######################################## +背景: [总食用转化关系.txt] 中"盖饭/盛出"等走 handleItemUseOn / handleBlockUse 的转换 +被客户端纯 ret=True 吞掉服务端 ServerItemUseOnEvent / ServerBlockUseEvent, 导致"点无反应" +(盖饭此前已用 GAI_FAN_CANCEL + GaifanRequest 修复)。 +本轮审计其余所有"走 handleItemUseOn 的 itemUseOn 转换", 发现同款风险, 统一修复: +- 覆盖: 原版相邻放置 / 盘子装盘 / 面食手持转换(烤炉/木碗/蒸笼) / 汤锅手持转换(熟面条碗) + / 裹粉(面粉块) / 厨具锅铲蘸油(油罐/炒锅) / 种水稻 / 寿司堆叠 / 手持直接吃(右键表面) +- 方案: + ①新增 FeatureDispatcher.OnItemUseOnRequest(服务端), 按 itemName 路由 itemUseOnAll + 各服务 handleItemUseOn(与 OnGaifanRequest 同机制, 逐个 fallback) + ②客户端 ClientFeatureDispatcher.OnItemUseOn 将这些纯 ret 分支统一改为 + ret=True(消闪) + NotifyToServer('ItemUseOnRequest') 显式触发 + ③去重: 各服务 handleItemUseOn 自带 checkCooldown(同坐标/同物品), 重复触发被冷却拦截 +- 细节: + ①"相邻放置/装盘"(ITEM_USE_ON_CANCEL_BY_ITEM) 分支【不设 _afterCd】, 因被点表面坐标 + 不变, 设了会误吞同一表面 1.5s 内连续放置(如连摆多个切配块); 去重靠服务端冷却 + ②"盖饭/蛋炒饭"(GAI_FAN_CANCEL)、"盛出/出锅"(TAKEOUT_CANCEL) 仍用各自专用事件, 不变 +- 文件: + ①FeatureDispatcher.py: 新增 ITEM_USE_ON_REQUEST 常量 / ListenEvent / UnListenEvent / + OnItemUseOnRequest + ②ClientFeatureDispatcher.py: 导入 SUSHI_CANCEL, 新增 ITEM_USE_ON_REQUEST 常量, + OnItemUseOn 的 BY_ITEM / ITEM_USE_ON_CANCEL / SUSHI / COATING 分支全部改为 ret+显式事件 + ③白名单清单: 新增"十三、其余 itemUseOn 转换 统一显式事件修复" [已实现] + diff --git a/tuilun/全部功能没做什么.txt b/tuilun/全部功能没做什么.txt index 2153005..97e33f3 100644 --- a/tuilun/全部功能没做什么.txt +++ b/tuilun/全部功能没做什么.txt @@ -295,3 +295,17 @@ todo 需要 对油罐 进行一个 打碎 后 在右键依然是多少的使用 - 烤鸡/烤乳猪"生命提升 10点"按 生命提升III(30秒) 实现(10点≈2.5级取III, 每级+4点血) - 原版食物成品盘(plate_16/17/18/20/21/4)按 txt 无增益效果 - 饭团/水煮蛋 已补 use_animation:eat+food 组件(长按右键可触发食用事件) + + +######################################## +【统一 itemUseOn 转换】(2026-09-23) +######################################## +四、其余 itemUseOn 转换的"点无反应"根治 +- 与其他 itemUseOn 转换(面食/汤锅/装盘/相邻放置/厨具蘸油/寿司/裹粉/种水稻/手持吃) + 经审计确认与盖饭同款风险(客户端纯 ret 吞 ServerItemUseOnEvent), 已统一用 + OnItemUseOnRequest 显式事件修复(见做了什么.txt)。本次为完整修复, 无遗留。 +- 暂未单测验证每一项的实际效果(用户需逐个进游戏验证): 因网易双端事件吞食行为 + 对"原版非方块物品 vs 方块物品"可能有差异, 若某项仍点无反应, 说明该组合的吞食 + 路径不同, 需再单独排查(不按此统一方案重复改)。 +五、盖饭/盛出/出锅 专用事件(GAI_FAN_CANCEL / TAKEOUT_CANCEL) 维持专用, 不再并入统一事件 +- 原因: 已跑通, 保持不回退; 统一事件只覆盖其余 itemUseOn 组合 [2026-09-23] diff --git a/tuilun/右键拦截白名单清单.txt b/tuilun/右键拦截白名单清单.txt index 485edbe..308bb2c 100644 --- a/tuilun/右键拦截白名单清单.txt +++ b/tuilun/右键拦截白名单清单.txt @@ -137,4 +137,64 @@ 取消key: 手持item (ClientItemTryUseEvent cancel) - rtdd:rice_balls(饭团) -> 直接吃 - rtdd:boiled_egg(水煮蛋) -> 直接吃 -- rtdd:beancurd(豆腐) -> 直接吃 \ No newline at end of file +- rtdd:beancurd(豆腐) -> 直接吃 + + +======================================== +十一、盛出/出锅消闪 (InterceptData.TAKEOUT_CANCEL, 2026-09-23) +======================================== +右键场景: 手持 木碗/盘子 右键 成品方块(汤锅成品/炒锅熟盘装/油锅熟炸物) -> 盛出/出锅。 +问题: 手持可放置方块物品右键, 客户端先渲染一帧"放置前摇/幽灵方块", +服务端取消指令往返后才撤掉 -> "闪一下"(服务端顺序正确, 碗/盘从未真落, 见日志 FD-Placed-AFTER=air)。 +方案: 客户端对该组合 ClientItemUseOnEvent ret=True(取消放置预览, 消闪) + + NotifyToServer('TakeoutRequest') 显式通知服务端执行盛出(纠正"客户端拦截吞服务端盛出")。 +取消key: (手持item, 被点block), 由 汤锅/炒锅/油锅 SWITCH_RULES 里 action=="take_out" + 且 item 是容器(木碗bowlasoup / 盘子plate_0) 的规则自动派生。 +- 汤锅: 木碗(bowlasoup)/盘子(plate_0) + 各成品汤方块(30条, 含 美味饺子全份盘装plate_30a) +- 炒锅: 盘子(plate_0) + 各炒锅熟成品(38条, 含蛋炒饭 riceegg_3) +- 油锅: 盘子(plate_0) + 6条熟炸物方块 +特殊: +- 空手取出(item=None, 捏饭团/取水煮蛋/煎饼/馍出锅)、菜刀(item=CLEAVER)不走此路, 照旧 ServerBlockUseEvent。 +- 服务端在 FeatureDispatcher.OnTakeoutRequest -> 各 Service.handleTakeoutRequest, + 校验落点仍是成品方块才执行(防客户端事件与服务端事件双份)。 + + +======================================== +十二、盖饭/蛋炒饭 消闪 (InterceptData.GAI_FAN_CANCEL, 2026-09-23) +======================================== +右键场景: 手持 成品菜 右键 米饭(盖饭正向) / 手持 米饭 右键 成品菜(盖饭反向) / + 手持 米饭 右键 炒锅蛋炒饭(蛋炒饭改造)。 +问题: 这些组合走 ServerItemUseOnEvent, 但也被 ITEM_USE_ON_CANCEL 纯 ret=True 吞掉, +导致服务端 ServerItemUseOnEvent 不触发 -> 盖饭"点无反应"(与盛出被吞同机制)。 +方案: 客户端对该组合 ret=True(消闪) + NotifyToServer('GaifanRequest') 显式触发 + -> FeatureDispatcher.OnGaifanRequest -> ChaoguoService.handleItemUseOn。 +取消key: (手持item, 被点block), 由 ChaoguoData.ITEM_USE_ON_RULES 的 surface 字段自动派生 + (盖饭正向/反向 + 蛋炒饭改造, 共若干组)。 + +【通用】客户端 1.5 秒放置冷却(_afterCd): 盛出/盖饭/出锅后, 同一坐标短时间内引擎 +再触发的"放置"直接 ret 吞掉, 消除"转换后多放置一次"的闪烁 (2026-09-23)。 + + +======================================== +十三、其余 itemUseOn 转换 统一显式事件修复 (InterceptData / FeatureDispatcher, 2026-09-23) +======================================== +问题: 与盖饭同款 —— 客户端对"走 handleItemUseOn 的 itemUseOn 转换"纯 ret=True 时, +会吞掉服务端 ServerItemUseOnEvent, 导致一端(面食/汤锅/装盘/相邻放置/厨具蘸油/寿司/ +裹粉/种水稻)转换"点无反应"。 +方案: 客户端对所有这些组合改为 ret=True(消闪) + NotifyToServer('ItemUseOnRequest') +显式触发; 服务端新增 FeatureDispatcher.OnItemUseOnRequest, 复用按 itemName 路由到 +itemUseOnAll 各服务 handleItemUseOn(与 OnGaifanRequest 同机制), 逐个 fallback。 +去重: 各服务 handleItemUseOn 自带 checkCooldown(同坐标/同物品), 即使与真实 +ServerItemUseOnEvent 重复触发也会被冷却拦截, 不双重消耗。 +- 一、原版相邻放置(手持原版生食右键任意表面 -> 相邻格放切配块/生肉) [已统一] +- 二、盘子装盘(手持原版食物右键 plate_0 -> 盘子变换) [已统一] +- 三、面食.甜食 手持转换(右键 烤炉/木碗/蒸笼) [已统一] +- 四、汤锅 手持转换(右键 熟面条碗 -> 汤面) [已统一] +- 六、乡野食材 裹粉(手持生食材右键 面粉块) [已统一] +- 七、厨具 锅铲/带油锅铲(右键 油罐/炒锅) [已统一] +- 八、乡野自然 水稻种植(手持稻谷右键地面) [已统一] +- 九、寿司 手持方块物品右键自家寿司方块(取消默认放置) [已统一] +- 十、总食用 手持直接吃(饭团/水煮蛋/豆腐, 右键表面吃) [已统一] +【注意】"相邻放置/装盘"分支(ITEM_USE_ON_CANCEL_BY_ITEM)因被点【表面坐标】不变, +不设 _afterCd(避免误吞同一表面 1.5s 内连续放置), 去重交给服务端 handleItemUseOn 冷却。 +"盖饭/蛋炒饭"(GAI_FAN_CANCEL)、"盛出/出锅"(TAKEOUT_CANCEL) 仍用各自专用事件, 不变。 \ No newline at end of file