Files
rtdd/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/InterceptData.py
T
2026-09-28 15:50:47 +08:00

400 lines
18 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""
================================================================================
右键拦截白名单数据(共享,客户端/服务端共用)—— 自动派生版
================================================================================
【作用】
统一管理"手持物品右键功能方块"时, 需要【提前取消该物品默认行为
(右键吃/放置)】的精确组合。客户端 ClientFeatureDispatcher 用它提前
cancel/ret 消除闪烁; 服务端 FeatureDispatcher 读同一份, 保持一致。
【为什么需要】
不精确拦截会造成两种问题:
1. 宽泛拦截(以前): 手持任意方块右键"任何功能方块"就取消放置 -> 正常放置失效
2. 不拦截: 手持南瓜派右键盘子时, 原版先触发"吃/放"前摇, 由服务端取消就"闪一下"
因此只对"手持的方块物品 与 被点的功能方块 存在右键转换关系"的组合拦截,
其余一律放行 (一一对应)。
【自动派生(核心)】
各功能分类的"右键转换"规则都写在各自的 *Data.py 里 (如 ChaoguoData 的
SWITCH_RULES / ITEM_USE_ON_RULES)。本模块在 import 时【直接读取这些
Data 模块的规则表】, 自动抽出所有 (手持方块物品, 被点功能方块) 的转换对。
—— 这样未来新增/修改任一菜谱, 白名单自动同步, 永不会漏、永不过时。
【集合】
ITEM_USE_ON_CANCEL : set of (手持item, 被点block) 仅这两者匹配才取消
ITEM_USE_ON_CANCEL_BY_ITEM : set of 手持item 只看手持item即可取消
SUSHI_BLOCKS : 寿司方块物品集合(用于交叉取消, 见说明)
COATING_ITEMS : 裹粉生食材集合(右键面粉块时取消)
================================================================================
"""
# ============================================================================
# 一、导入各功能分类"手持物品右键方块表面"的规则数据符号
# 只扫【ITEM_USE_ON_RULES】(surface 字段) —— 这些才走 ServerItemUseOnEvent
# -> handleItemUseOn, 是客户端 ClientItemUseOnEvent 应拦截的组合。
# 注意: 绝对不要扫 SWITCH_RULES / *_SWITCHES 等(本体现在, 走 ServerBlockUseEvent
# -> handleBlockUse), 若扫进来客户端拦截会吃掉整个右键, 导致"右键什么都不发生"。
# 注: 本项目无 __init__.py, 用与各 Service 相同的 `from ..XxxData import ...`
# 直接导入符号, 而非 import 模块对象。
# ============================================================================
# 每个条目: (规则表内容) —— 规则表 list[dict], 字段含 "item" + "surface"/"source"
_ALL_RULE_TABLES = []
def _collect_all():
"""遍历 _ALL_RULE_TABLES, 汇总全部 (手持item, 被点surface方块) 组合。
只取 "surface"(手持物品右键方块表面) 与 "source"(盘子转换的被点方块),
不取 "block"(本体现在右键, 由服务端 handleBlockUse 处理)。"""
pairs = set()
for value in _ALL_RULE_TABLES:
for rule in _as_list(value):
if not isinstance(rule, dict):
continue
item = rule.get("item")
if not item or not isinstance(item, basestring):
continue
if item.startswith("*"):
continue
for blkf in ("surface", "source"):
blk = rule.get(blkf)
if isinstance(blk, basestring) and blk:
pairs.add((item, blk))
return pairs
# ---- 面食.甜食: 手持生食/面饼/面粉 右键 烤炉/木碗/蒸笼 (itemUseOn) ----
try:
from ..mianshi.MianshiData import ITEM_USE_ON_RULES as MIANSHI_USON
_ALL_RULE_TABLES.append(MIANSHI_USON)
except Exception:
pass
# ---- 炒锅: 盖饭双向 + 蛋炒饭 (itemUseOn, surface=米饭/成品菜) ----
try:
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:
CHAOGUO_SWITCH, CHAOGUO_PLATE = None, None
# ---- 汤锅: 手持锅态汤右键 熟面条 (itemUseOn) ----
try:
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:
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
# ---- 根因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
# / STEAMER_RULES / STONEMILL_BLOCKUSE
try:
from ..chuju.ChujuData import (STOVE_RULES as CHUJU_STOVE,
MEATBALLMAKER_RULES as CHUJU_MEAT,
STEAMER_RULES as CHUJU_STEAM,
STONEMILL_BLOCKUSE as CHUJU_MILL)
_BLOCK_USE_TABLES.extend([CHUJU_STOVE, CHUJU_MEAT, CHUJU_STEAM, CHUJU_MILL])
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
# 饮料·榨汁机(手持 玻璃杯/各水果 右键榨汁机任意状态 放水果/逐级榨汁/取汁):
# YinliaoData.JUICER_BLOCKUSE。与汤锅等不同, 榨汁机取汁走 BlockUse(右击方块),
# 不标 take_out, 直接进 BlockUseRequest 通道消闪。
try:
from ..yinliao.YinliaoData import JUICER_BLOCKUSE as JUICER_BLOCKUSE
_BLOCK_USE_TABLES.append(JUICER_BLOCKUSE)
except Exception:
pass
# ---- 乡野自然(种葡萄: 手持葡萄右键支杆): NaturalData.GRAPE_PLANT ----
# 葡萄是食物(eat 动画), 右键支杆会被原版当"吃/使用"前摇, 需纳入 BLOCKUse 取消消闪,
# 机制与烧烤上杆(cod/salmon 同为食物右键支杆)完全一致。
try:
from ..ziran.NaturalData import GRAPE_PLANT as NATURAL_GRAPE_PLANT
_BLOCK_USE_TABLES.append(NATURAL_GRAPE_PLANT)
except Exception:
pass
# ---- 原版放置/盘子转换 (itemUseOn, surface=相邻放置 / source=盘子) ----
try:
from ..yuanbanfangzhi.YuanbanData import (
ITEM_USE_ON_RULES as YUANBAN_USON,
PLATE_RULES,
)
_ALL_RULE_TABLES.append(YUANBAN_USON)
_ALL_RULE_TABLES.append(PLATE_RULES)
except Exception:
pass
# ============================================================================
# 二、从规则表派生 (手持方块物品, 被点功能方块) 转换对
# ============================================================================
def _as_list(value):
"""RICE_PLANT 这类是单个 dict, 规则表是 list[dict], 统一转成 list。"""
if isinstance(value, list):
return value
if isinstance(value, dict):
return [value]
return []
# ============================================================================
# 三、自动派生 + 少量"非规则表内联转换"的手工补充
# ============================================================================
# ---- 由各 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))
# ============================================================================
# 三之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 = {
("rtdd:spatula", "rtdd:oilcan"), # 锅铲蘸油罐
("rtdd:spatula_oil", "rtdd:oilcan"), # 带油锅铲还油罐
("rtdd:spatula_oil", "rtdd:wok"), # 带油锅铲给炒锅上油
}
AUTO_CANCEL |= CHUJU_INLINE_CANCEL
# ============================================================================
# 四、寿司: 手持任何寿司方块物品 右键自家寿司方块 取消默认放置
# (寿司的堆叠/取走/转换规则在 ShousiService 内联构建, 不在 Data 表,
# 故此处手工列出寿司方块物品集合, 交叉生成 (块, 块) 组合)
# ============================================================================
SUSHI_BLOCKS = {
"rtdd:sushi_0", "rtdd:sushi_1",
"rtdd:codsushi_1", "rtdd:codsushi_2", "rtdd:codsushi_3",
"rtdd:codsushi_4", "rtdd:codsushi_5", "rtdd:codsushi_6",
"rtdd:salmonsushi_1", "rtdd:salmonsushi_2", "rtdd:salmonsushi_3",
"rtdd:salmonsushi_4", "rtdd:salmonsushi_5", "rtdd:salmonsushi_6",
"rtdd:fishsushi_1", "rtdd:fishsushi_2", "rtdd:fishsushi_3",
"rtdd:fishsushi_4", "rtdd:fishsushi_5", "rtdd:fishmonsushi_6",
"rtdd:nigirisushi",
"rtdd:sushipile_0", "rtdd:sushipile_1", "rtdd:sushipile_2",
"rtdd:sushipile_3", "rtdd:sushipile_4", "rtdd:sushipile_5",
"rtdd:nigirisushifishcod", "rtdd:nigirisushicod_2", "rtdd:nigirisushicod_3",
"rtdd:nigirisushifishsalmon_1", "rtdd:nigirisushisalnom_2", "rtdd:nigirisushisalnom_3",
"rtdd:nigirisushifish_1", "rtdd:nigirisushifish_2", "rtdd:nigirisushifish_3",
"rtdd:squid_sushi", "rtdd:squidsushi_2", "rtdd:squidsushi_3",
}
SUSHI_CANCEL = set(
(held, block) for held in SUSHI_BLOCKS for block in SUSHI_BLOCKS
)
# ============================================================================
# 五、裹粉(Shicai COATING_RULES 是 item->drop 结构, 无 floor 字段, 需手工指定被点面块)
# ============================================================================
COATING_ITEMS = {
"rtdd:sashimi", # 生鱼片
"rtdd:lobster", # 龙虾
"minecraft:porkchop", # 生猪肉
"minecraft:chicken", # 生鸡肉
"minecraft:potato", # 生土豆
}
COATING_CANCEL = set(
(item, "rtdd:farineblock_3") for item in COATING_ITEMS
)
# ============================================================================
# 六、汇总: 精确组合 ITEM_USE_ON_CANCEL = 自动派生 ∪ 寿司交叉 ∪ 裹粉
# ============================================================================
ITEM_USE_ON_CANCEL = AUTO_CANCEL | SUSHI_CANCEL | COATING_CANCEL
# ============================================================================
# 七、纯手持物品取消: 只看手持item (不做方块匹配)
# ============================================================================
# ---- 原版相邻放置(YuanbanService ITEM_USE_ON_RULES) ----
# 手持这些"非方块食品"右键任意方块表面, 都在相邻空位摆放对应切配方块。
# 他们本身不是可放置方块物品(放的是另一块), 但右键时会默认"吃/用", 需取消。
# 注: 稻谷(rtdd:rice_seeds)不在此列 —— 它已改用物品 JSON 的 minecraft:seed 组件
# 由引擎原生种植(plant_at=farmland, crop_result=riceseedlingsb), 客户端不拦截,
# 否则会吞掉引擎的原生种植行为。
PLACE_ITEMS = {
"minecraft:chicken",
"minecraft:salmon",
"minecraft:cod",
"minecraft:fish",
"minecraft:carrot",
"minecraft:potato",
"rtdd:qingcai",
"rtdd:scallions",
}
# ---- 总食用 手持直接吃 (Shiyongfood TRY_USE_RULES) ----
EAT_ITEMS = {
"rtdd:rice_balls", # 饭团
"rtdd:boiled_egg", # 水煮蛋
"rtdd:beancurd", # 豆腐
}
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