389 lines
17 KiB
Python
389 lines
17 KiB
Python
# -*- 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
|
||
|
||
# ---- 原版放置/盘子转换 (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) + 水稻种植(Natural RICE_PLANT) ----
|
||
# 手持这些"非方块食品/种子"右键任意方块表面, 都在相邻空位摆放对应切配方块。
|
||
# 它们本身不是可放置方块物品(放的是另一块), 但右键时会默认"吃/用", 需取消。
|
||
PLACE_ITEMS = {
|
||
"minecraft:chicken",
|
||
"minecraft:salmon",
|
||
"minecraft:cod",
|
||
"minecraft:fish",
|
||
"minecraft:carrot",
|
||
"minecraft:potato",
|
||
"rtdd:qingcai",
|
||
"rtdd:scallions",
|
||
"rtdd:rice_seeds", # 稻谷: 右键耕地相邻放置水稻苗(RICE_PLANT)
|
||
}
|
||
|
||
# ---- 总食用 手持直接吃 (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 |