This commit is contained in:
wenhe committed 2026-09-11 11:17:45 +08:00
1 parent 4e7b9abee5
commit 052e4844b2
26 files changed
+1053 -41

No files matched your search

@@ -18,6 +18,8 @@ from xiangyemod.ziran.service.NaturalService import NaturalService
from xiangyemod.ziran.service.NaturalTimerService import NaturalTimerService from xiangyemod.ziran.service.NaturalTimerService import NaturalTimerService
from xiangyemod.shicai.service.ShicaiService import ShicaiService from xiangyemod.shicai.service.ShicaiService import ShicaiService
from xiangyemod.shousi.service.ShousiService import ShousiService from xiangyemod.shousi.service.ShousiService import ShousiService
from xiangyemod.mianshi.service.MianshiService import MianshiService
from xiangyemod.mianshi.service.MianshiTimerService import MianshiTimerService
if not serverApi.IsInServer(): if not serverApi.IsInServer():
pass pass
@@ -0,0 +1,326 @@
# -*- coding: utf-8 -*-
"""
================================================================================
面食.甜食(xy_mianshi)转化规则数据
================================================================================
统一管理"面食.甜食"分类下的转化规则常量。只被
MianshiService / MianshiTimerService 读取, FeatureDispatcher 通过
方块名/物品名集合路由到对应服务。
【实现范围(对应 面食.甜食转化关系.txt 一~九组)】
面粉·面团: 加鸡蛋/加水/揉面/和面/擀面(擀面杖消耗返还)/切面/压饺子皮
饺子 : 加猪肉馅/青菜碎(双向组合)/捏合 -> 蒸笼蒸熟 -> 盘子取盘装水饺
包子 : 饺子皮转包子皮/加肉/塑形 -> 蒸笼蒸熟 -> 取出熟肉包子 -> 切/堆叠/递减
馍 : 生面饼烙制/菜刀切开/夹熟肉
煎饼卷 : 加菜/加熟牛肉/熟鳕鱼/土豆/卷制
竹筒饭 : 竹筒切开/装米(32)/加肉 -> 蒸笼蒸熟 -> 取出熟竹筒饭
面包 : 法棍/吐司/可颂/甜甜圈 堆叠份数 + 递减取走
面团胚料: 四种胚料右键循环转换 + 发酵 + 烤炉烘焙
甜点蛋糕: 木碗+面粉(加鸡蛋)面糊/烤熟/脱模/加奶油/蜂蜜/浆果/切分/布丁/舒芙蕾/蒸蛋奶
【计时(见 MianshiTimerService)】
发酵60秒 / 烤炉烘焙60秒(下方判定烤炉, 烤炉被打碎 -> 方块掉落+提示) / 蒸笼蒸熟60秒
【不实现(txt 已标 todo)】: 吃(熟肉包子/馍/煎饼卷/熟竹筒饭/蛋糕小块 右键吃)、
巧克力蛋糕系列、蛋糕半块拆两块
================================================================================
"""
# ============================================================================
# 一、物品(手持原料/工具)
# ============================================================================
EGG = "minecraft:egg" # 鸡蛋
WATER_BUCKET = "minecraft:water_bucket" # 水桶
EMPTY_BUCKET = "minecraft:bucket" # 空桶
CLEAVER = "rtdd:cleaver" # 菜刀
ROLLINGPIN = "rtdd:rollingpin" # 厨具擀面杖
PORK_FILLING = "rtdd:rawmeatball_0" # 生猪肉馅
BEEF_FILLING = "rtdd:rawmeatball_1" # 生牛肉馅
VEGGIE = "rtdd:vegetable" # 青菜碎
COOKED_BEEF = "minecraft:cooked_beef" # 熟牛肉(原版)
COOKED_PORK = "minecraft:cooked_porkchop" # 熟猪肉(原版)
COOKED_COD = "minecraft:cooked_cod" # 熟鳕鱼(原版)
POTATO = "minecraft:potato" # 土豆(原版)
BROWN_RICE = "rtdd:brownrice" # 大米(生米)
CREAM = "rtdd:cream_0" # 奶油
HONEY = "minecraft:honey_bottle" # 蜂蜜
BERRIES = "minecraft:sweet_berries" # 浆果
SUGAR = "minecraft:sugar" # 糖
PLATE = "rtdd:plate_0" # 盘子
BOWL = "rtdd:bowlasoup" # 木碗
STEAMER = "rtdd:steamer" # 蒸笼
OVEN = "rtdd:oven" # 烤炉
# 竹筒饭加肉: 接受原版常见生熟肉类(【待确认】具体肉类未定, 先放开常见肉)
MEAT_ITEMS = [
"minecraft:porkchop", "minecraft:cooked_porkchop",
"minecraft:chicken", "minecraft:cooked_chicken",
"minecraft:beef", "minecraft:cooked_beef",
"minecraft:mutton", "minecraft:cooked_mutton",
"minecraft:rabbit", "minecraft:cooked_rabbit",
]
# 包子加肉: 猪/牛肉馅
FILLING_ITEMS = [PORK_FILLING, BEEF_FILLING]
# 肉夹馍: 熟牛肉/熟猪肉
RICH_MEAT_ITEMS = [COOKED_BEEF, COOKED_PORK]
# ============================================================================
# 二、右键开关规则 (方块, 手持物品) -> 规则
# item=None 表示空手; target=替换方块; consume=消耗手持; give=给背包;
# dropItem=掉落物; action=特殊动作(take_steamer 蒸笼取出 / chop_smalldough
# 切小面团 / chop_noodles 切生面 / unmold_cake 蛋糕脱模)
# ============================================================================
SWITCH_RULES = [
# ---- 一、面粉·面团组 ----
{"block": "rtdd:farineblcok", "item": EGG,
"target": "rtdd:farineblock_1", "consume": 3, "tip": "§a面粉加了鸡蛋"},
{"block": "rtdd:farineblock_1", "item": WATER_BUCKET,
"target": "rtdd:farineblock_2", "consume": 1, "give": EMPTY_BUCKET,
"tip": "§a面粉加水, 水桶变空桶"},
{"block": "rtdd:rawdough_0", "item": None, "target": "rtdd:rawdough_1", "tip": "§a和面中…"},
{"block": "rtdd:rawdough_1", "item": None, "target": "rtdd:rawdough_2", "tip": "§a和面中…"},
{"block": "rtdd:rawdough_2", "item": None, "target": "rtdd:rawdough_3", "tip": "§a和面中…"},
{"block": "rtdd:rawdough_3", "item": None, "target": "rtdd:rawdough_4", "tip": "§a和面完成"},
{"block": "rtdd:rawdough_4", "item": CLEAVER, "action": "chop_smalldough",
"tip": "§a切出了8个小面团"},
{"block": "rtdd:dough_0", "item": ROLLINGPIN, "target": "rtdd:dough_1",
"consume": 1, "tip": "§a开始擀面(消耗1根擀面杖)"},
{"block": "rtdd:dough_1", "item": None, "target": "rtdd:dought_2", "tip": "§a擀面中…"},
{"block": "rtdd:dought_2", "item": None, "target": "rtdd:dought_3", "tip": "§a擀面中…"},
{"block": "rtdd:dought_3", "item": None, "target": "rtdd:dought_4", "tip": "§a擀面中…"},
{"block": "rtdd:dought_4", "item": None, "target": "rtdd:dought_5", "tip": "§a擀面中…"},
{"block": "rtdd:dought_5", "item": None, "target": "rtdd:dought_6", "tip": "§a擀面中…"},
{"block": "rtdd:dought_6", "item": None, "target": "rtdd:dought_7",
"give": ROLLINGPIN, "tip": "§a擀好了, 擀面杖返还"},
{"block": "rtdd:dought_7", "item": CLEAVER, "target": "rtdd:dought_8", "tip": "§a面饼切开"},
{"block": "rtdd:dought_8", "item": None, "target": "rtdd:dought_9", "tip": "§a转成可颂面胚"},
{"block": "rtdd:dought_8", "item": CLEAVER, "action": "chop_noodles",
"tip": "§a切出了生面"},
{"block": "rtdd:smalldough_0", "item": ROLLINGPIN, "target": "rtdd:smalldough_1",
"consume": 1, "tip": "§a开始擀小面团(消耗1根擀面杖)"},
{"block": "rtdd:smalldough_1", "item": None, "target": "rtdd:smalldough_2", "tip": "§a擀小面团中…"},
{"block": "rtdd:smalldough_2", "item": None, "target": "rtdd:smalldough_3", "tip": "§a擀小面团中…"},
{"block": "rtdd:smalldough_3", "item": None, "target": "rtdd:dumplings_0",
"give": ROLLINGPIN, "tip": "§a压成饺子皮, 擀面杖返还"},
# ---- 二、饺子组 ----
{"block": "rtdd:dumplings_0", "item": PORK_FILLING, "target": "rtdd:dumplings_1",
"tip": "§a饺子皮加了猪肉馅"},
{"block": "rtdd:dumplings_0", "item": VEGGIE, "target": "rtdd:dumplings_2",
"tip": "§a饺子皮加了青菜碎"},
{"block": "rtdd:dumplings_1", "item": VEGGIE, "target": "rtdd:dumplings_3",
"tip": "§a加了青菜碎"},
{"block": "rtdd:dumplings_2", "item": PORK_FILLING, "target": "rtdd:dumplings_3",
"tip": "§a加了猪肉馅"},
{"block": "rtdd:dumplings_3", "item": None, "target": "rtdd:dumplings_4",
"tip": "§a捏合成了生饺子"},
{"block": "rtdd:steamerdumplings_1", "item": PLATE, "action": "take_steamer",
"dropItem": "rtdd:plate_30", "consume": 1, "tip": "§a取出盘装水饺, 蒸笼归位"},
# ---- 三、包子组 ----
{"block": "rtdd:dumplings_0", "item": None, "target": "rtdd:baozipi",
"tip": "§a变成包子皮"},
{"block": "rtdd:baozipi", "item": PORK_FILLING, "target": "rtdd:roubao_1",
"tip": "§a包子皮加了肉馅"},
{"block": "rtdd:baozipi", "item": BEEF_FILLING, "target": "rtdd:roubao_1",
"tip": "§a包子皮加了肉馅"},
{"block": "rtdd:roubao_1", "item": None, "target": "rtdd:roubao_2", "tip": "§a塑形中…"},
{"block": "rtdd:roubao_2", "item": None, "target": "rtdd:roubaozi_3",
"tip": "§a塑形成生肉包子"},
{"block": "rtdd:baozilong_2", "item": None, "action": "take_steamer",
"dropItem": "rtdd:shouroubao", "tip": "§a取出熟肉包子, 蒸笼归位"},
{"block": "rtdd:shouroubao", "item": CLEAVER, "target": "rtdd:shoubaozi_2",
"tip": "§a切出半个"},
{"block": "rtdd:shoubaozi_2", "item": CLEAVER, "target": "rtdd:shoubaozi_3",
"tip": "§a切成1/4个"},
{"block": "rtdd:shoubaozi_2", "item": "rtdd:shouroubao", "target": "rtdd:shoubaozidui_2",
"consume": 1, "tip": "§a堆叠成两个"},
{"block": "rtdd:shoubaozidui_2", "item": "rtdd:shouroubao", "target": "rtdd:shoubaozidui_3",
"consume": 1, "tip": "§a堆叠成三个"},
{"block": "rtdd:shoubaozidui_3", "item": None, "target": "rtdd:shoubaozidui_2",
"dropItem": "rtdd:shouroubao", "tip": "§a取走一个"},
{"block": "rtdd:shoubaozidui_2", "item": None, "target": "rtdd:shoubaozi_2",
"dropItem": "rtdd:shouroubao", "tip": "§a取走一个"},
# ---- 四、馍·肉夹馍组 ----
{"block": "rtdd:roujiamo_0", "item": CLEAVER, "target": "rtdd:roujiamo_1",
"tip": "§a馍切开"},
{"block": "rtdd:roujiamo_1", "item": COOKED_BEEF, "target": "rtdd:roujiamo_2",
"tip": "§a夹入熟牛肉"},
{"block": "rtdd:roujiamo_1", "item": COOKED_PORK, "target": "rtdd:roujiamo_2",
"tip": "§a夹入熟猪肉"},
# ---- 五、煎饼卷组 ----
{"block": "rtdd:cooked_dought", "item": VEGGIE, "target": "rtdd:cookeddought_1",
"tip": "§a煎饼加了青菜碎"},
{"block": "rtdd:cookeddought_1", "item": COOKED_BEEF, "target": "rtdd:cookeddought_2",
"tip": "§a加入熟牛肉"},
{"block": "rtdd:cookeddought_2", "item": POTATO, "target": "rtdd:cookeddought_3",
"tip": "§a加入土豆"},
{"block": "rtdd:cookeddought_3", "item": None, "target": "rtdd:cookeddought_4",
"tip": "§a卷制中…"},
{"block": "rtdd:cookeddought_4", "item": None, "target": "rtdd:cookeddought_5",
"tip": "§a卷制中…"},
{"block": "rtdd:cookeddought_5", "item": None, "target": "rtdd:cookeddought_6",
"tip": "§a煎饼卷牛肉完成"},
{"block": "rtdd:cookeddought_1", "item": COOKED_COD, "target": "rtdd:cookedcoddought_2",
"tip": "§a加入熟鳕鱼"},
{"block": "rtdd:cookedcoddought_2", "item": POTATO, "target": "rtdd:cookedcoddought_3",
"tip": "§a加入土豆"},
{"block": "rtdd:cookedcoddought_3", "item": None, "target": "rtdd:cookedcoddought_4",
"tip": "§a卷制中…"},
{"block": "rtdd:cookedcoddought_4", "item": None, "target": "rtdd:cookedcoddought_5",
"tip": "§a卷制中…"},
{"block": "rtdd:cookedcoddought_5", "item": None, "target": "rtdd:cookedcoddought_6",
"tip": "§a煎饼卷鳕鱼完成"},
# ---- 六、竹筒饭组 ----
{"block": "rtdd:bamboo_0", "item": CLEAVER, "target": "rtdd:bamboo_1",
"tip": "§a竹筒切开"},
{"block": "rtdd:bamboo_1", "item": BROWN_RICE, "target": "rtdd:bamboo_2",
"consume": 32, "tip": "§a竹筒填满生大米"},
{"block": "rtdd:bamboo_7", "item": None, "action": "take_steamer",
"dropItem": "rtdd:bamboo_5", "tip": "§a取出熟竹筒饭, 蒸笼归位"},
# ---- 七、面包·烘焙组(堆叠/递减) ----
{"block": "rtdd:bread_1", "item": "rtdd:bread_1", "target": "rtdd:bread_1a",
"consume": 1, "tip": "§a堆叠成2份"},
{"block": "rtdd:bread_1a", "item": "rtdd:bread_1", "target": "rtdd:bread_1b",
"consume": 1, "tip": "§a堆叠成3份"},
{"block": "rtdd:bread_1b", "item": None, "target": "rtdd:bread_1a",
"dropItem": "rtdd:bread_1", "tip": "§a取走一个"},
{"block": "rtdd:bread_1a", "item": None, "target": "rtdd:bread_1",
"dropItem": "rtdd:bread_1", "tip": "§a取走一个"},
{"block": "rtdd:bread_2", "item": "rtdd:bread_2", "target": "rtdd:bread_2a",
"consume": 1, "tip": "§a堆叠成2份"},
{"block": "rtdd:bread_2a", "item": "rtdd:bread_2", "target": "rtdd:bread_2b",
"consume": 1, "tip": "§a堆叠成3份"},
{"block": "rtdd:bread_2b", "item": None, "target": "rtdd:bread_2a",
"dropItem": "rtdd:bread_2", "tip": "§a取走一个"},
{"block": "rtdd:bread_2a", "item": None, "target": "rtdd:bread_2",
"dropItem": "rtdd:bread_2", "tip": "§a取走一个"},
{"block": "rtdd:bread_3", "item": "rtdd:bread_3", "target": "rtdd:bread_3a",
"consume": 1, "tip": "§a堆叠成2份"},
{"block": "rtdd:bread_3a", "item": "rtdd:bread_3", "target": "rtdd:bread_3b",
"consume": 1, "tip": "§a堆叠成3份"},
{"block": "rtdd:bread_3b", "item": None, "target": "rtdd:bread_3a",
"dropItem": "rtdd:bread_3", "tip": "§a取走一个"},
{"block": "rtdd:bread_3a", "item": None, "target": "rtdd:bread_3",
"dropItem": "rtdd:bread_3", "tip": "§a取走一个"},
{"block": "rtdd:bread_4", "item": "rtdd:bread_4", "target": "rtdd:bread_4a",
"consume": 1, "tip": "§a堆叠成2个"},
{"block": "rtdd:bread_4a", "item": "rtdd:bread_4", "target": "rtdd:bread_4b",
"consume": 1, "tip": "§a堆叠成3个"},
{"block": "rtdd:bread_4b", "item": None, "target": "rtdd:bread_4a",
"dropItem": "rtdd:bread_4", "tip": "§a取走一个甜甜圈"},
{"block": "rtdd:bread_4a", "item": None, "target": "rtdd:bread_4",
"dropItem": "rtdd:bread_4", "tip": "§a取走一个甜甜圈"},
{"block": "rtdd:bread_4c", "item": CREAM, "target": "rtdd:bread_4",
"consume": 1, "tip": "§a甜甜圈涂了奶油"},
# ---- 八、面团·胚料组(右键循环转换) ----
{"block": "rtdd:dough_0", "item": None, "target": "rtdd:breaddough_1",
"tip": "§a转成法棍面胚"},
{"block": "rtdd:breaddough_1", "item": None, "target": "rtdd:breaddough_2",
"tip": "§a转成吐司面胚"},
{"block": "rtdd:breaddough_2", "item": None, "target": "rtdd:breaddough_4d",
"tip": "§a转成甜甜圈胚"},
{"block": "rtdd:breaddough_4d", "item": None, "target": "rtdd:dough_0",
"tip": "§a转回发酵面团"},
# ---- 九、甜点·蛋糕组 ----
{"block": "rtdd:cakebatterblock", "item": None, "action": "unmold_cake",
"tip": "§a脱模出蛋糕胚 + 木碗"},
{"block": "rtdd:cakebase", "item": CREAM, "target": "rtdd:cake_0",
"consume": 1, "tip": "§a做了奶油蛋糕"},
{"block": "rtdd:cakebase", "item": HONEY, "target": "rtdd:cake_1",
"consume": 1, "tip": "§a做了蜂蜜蛋糕"},
{"block": "rtdd:cakebase", "item": BERRIES, "target": "rtdd:cake_2",
"consume": 1, "tip": "§a做了浆果蛋糕"},
{"block": "rtdd:cake_1", "item": CLEAVER, "target": "rtdd:cake_1a",
"dropItem": "rtdd:cake_1d", "tip": "§a切下小块"},
{"block": "rtdd:cake_1a", "item": CLEAVER, "target": "rtdd:cake_1b",
"dropItem": "rtdd:cake_1d", "tip": "§a切下小块"},
{"block": "rtdd:cake_2", "item": CLEAVER, "target": "rtdd:cake_2a",
"dropItem": "rtdd:cake_2d", "tip": "§a切下小块"},
{"block": "rtdd:cake_2a", "item": CLEAVER, "target": "rtdd:cake_2b",
"dropItem": "rtdd:cake_2d", "tip": "§a切下小块"},
{"block": "rtdd:cake_1b", "item": CLEAVER, "action": "split_cake",
"dropItem": "rtdd:cake_1d", "tip": "§a半块切成两块小块"},
{"block": "rtdd:cake_2b", "item": CLEAVER, "action": "split_cake",
"dropItem": "rtdd:cake_2d", "tip": "§a半块切成两块小块"},
{"block": "rtdd:plate_35", "item": SUGAR, "target": "rtdd:cream_caramel",
"consume": 16, "tip": "§a做成焦糖布丁"},
{"block": "rtdd:plate_34", "item": CREAM, "target": "rtdd:creampastry_0",
"consume": 1, "tip": "§a做成舒芙蕾半成品"},
]
# ============================================================================
# 三、揉面/和面 连点计数(空手右键, 次数达标转换)
# ============================================================================
KNEAD_COUNTERS = {
"rtdd:farineblock_2": {"times": 2, "target": "rtdd:farineblock_3",
"tip": "§a揉面中…(%d/2)", "doneTip": "§a揉好了, 变成面粉块"},
"rtdd:farineblock_3": {"times": 3, "target": "rtdd:rawdough_0",
"tip": "§a和面中…(%d/3)", "doneTip": "§a和好面了, 变成生面团"},
}
# ============================================================================
# 四、手持物品右键方块表面规则 (itemUseOn)
# 生面饼右键烤炉 -> 烤炉上方放置 馍; 面粉(加鸡蛋)右键木碗 -> 木碗变蛋糕面糊
# ============================================================================
ITEM_USE_ON_RULES = [
{"item": "rtdd:dought_7", "surface": OVEN, "above": "rtdd:roujiamo_0",
"consume": 1, "tip": "§a烙制成了馍"},
{"item": "rtdd:farineblock_1", "surface": BOWL, "replace": "rtdd:cakebatterblock_0",
"consume": 1, "tip": "§a木碗变成了蛋糕面糊(生)"},
]
# ============================================================================
# 五、计时规则(供 MianshiTimerService)
# below: 下方方块判定列表(烤炉/蒸笼); dropOnBreak: 下方方块被打碎时该方块掉落+提示
# ============================================================================
TIMER_RULES = [
# 发酵(60秒, autoStart)
{"source": "rtdd:rawdough_4", "target": "rtdd:dough_0", "time": 60,
"autoStart": True, "doneTip": "§e面团发酵好了"},
{"source": "rtdd:breaddough_1", "target": "rtdd:breaddough_1a", "time": 60,
"autoStart": True, "doneTip": "§e法棍面胚发好了"},
# 蒸笼: 食物放蒸笼上 -> 蒸食物块(1秒) / 蒸熟(60秒)
{"source": "rtdd:dumplings_4", "target": "rtdd:steamerdumplings_0", "time": 1,
"below": [STEAMER], "autoStart": True},
{"source": "rtdd:roubaozi_3", "target": "rtdd:baozilong_1", "time": 1,
"below": [STEAMER], "autoStart": True},
{"source": "rtdd:bamboo_4", "target": "rtdd:bamboo_6", "time": 1,
"below": [STEAMER], "autoStart": True},
{"source": "rtdd:plate_34", "target": "rtdd:steamermilkandegg", "time": 1,
"below": [STEAMER], "autoStart": True},
{"source": "rtdd:steamerdumplings_0", "target": "rtdd:steamerdumplings_1", "time": 60,
"below": [STEAMER], "autoStart": True, "doneTip": "§e饺子蒸好了"},
{"source": "rtdd:baozilong_1", "target": "rtdd:baozilong_2", "time": 60,
"below": [STEAMER], "autoStart": True, "doneTip": "§e包子蒸好了"},
{"source": "rtdd:bamboo_6", "target": "rtdd:bamboo_7", "time": 60,
"below": [STEAMER], "autoStart": True, "doneTip": "§e竹筒饭蒸好了"},
{"source": "rtdd:steamermilkandegg", "target": "rtdd:steamermilkandegg_1", "time": 60,
"below": [STEAMER], "autoStart": True, "doneTip": "§e蒸牛奶鸡蛋好了"},
# 烤炉烘焙(60秒, 下方判定烤炉; 烤炉被打碎 -> 该方块掉落+提示)
{"source": "rtdd:breaddough_1a", "target": "rtdd:bread_1", "time": 60,
"below": [OVEN], "autoStart": True, "dropOnBreak": True, "doneTip": "§e法棍烤好了"},
{"source": "rtdd:breaddough_2", "target": "rtdd:bread_2", "time": 60,
"below": [OVEN], "autoStart": True, "dropOnBreak": True, "doneTip": "§e吐司烤好了"},
{"source": "rtdd:breaddough_4d", "target": "rtdd:bread_4c", "time": 60,
"below": [OVEN], "autoStart": True, "dropOnBreak": True, "doneTip": "§e甜甜圈胚烤好了"},
{"source": "rtdd:dought_9", "target": "rtdd:bread_3", "time": 60,
"below": [OVEN], "autoStart": True, "dropOnBreak": True, "doneTip": "§e可颂烤好了"},
{"source": "rtdd:cakebatterblock_0", "target": "rtdd:cakebatterblock", "time": 60,
"below": [OVEN], "autoStart": True, "dropOnBreak": True, "doneTip": "§e蛋糕面糊烤好了"},
{"source": "rtdd:plate_34", "target": "rtdd:plate_35", "time": 60,
"below": [OVEN], "autoStart": True, "dropOnBreak": True, "doneTip": "§e布丁半成品好了"},
{"source": "rtdd:creampastry_0", "target": "rtdd:souffle_0", "time": 60,
"below": [OVEN], "autoStart": True, "dropOnBreak": True, "doneTip": "§e舒芙蕾烤好了"},
]
# 烤炉烘焙掉落的提示语
BREAK_TIP = "§c烤炉被移走了, 烤制的方块掉落了!"
@@ -0,0 +1 @@
# -*- coding: utf-8 -*-
@@ -0,0 +1,337 @@
# -*- coding: utf-8 -*-
"""
================================================================================
面食.甜食·右键转换引擎(服务端)
================================================================================
处理"面食.甜食"(xy_mianshi) 分类下的右键转换:
面粉·面团(和面/擀面/切分)、饺子、包子、馍、煎饼卷、竹筒饭、
面包堆叠/递减、面团胚料循环、甜点蛋糕(脱模/加料/切分)。
【事件监听在哪?】
本类【不】监听任何事件!
所有事件由 FeatureDispatcher 统一监听, 按 blockOwner/itemUseOnOwner
(多服务 fallback) 路由到本类 handleBlockUse / handleItemUseOn。
【本类怎么做】
handleBlockUse ← 入口:分发器转发右键方块事件
├─ _handleKnead ← 揉面/和面 连点计数(空手)
├─ _handleAction ← 特殊动作(蒸笼取出/切小面团/切生面/蛋糕脱模)
└─ handleSwitch ← 通用转换(加料/擀面/卷制/堆叠/递减/切分)
handleItemUseOn ← 入口:生面饼右键烤炉烙制 / 面粉(加鸡蛋)右键木碗做面糊
(通用工具) getCarriedItem / consumeItem / giveItem / dropItem / replaceBlock /
clearBlock / checkCooldown
================================================================================
"""
import time
import mod.server.extraServerApi as serverApi
# ---- 网易API基础对象 ----
ServerSystem = serverApi.GetServerSystemCls() # 服务端系统基类
comp = serverApi.GetEngineCompFactory() # 组件工厂
# ---- 继承 BlueFox 框架的系统基类(提供 CreateEngineItemEntity 等方法) ----
from ....BlueFoxTools.SpecialFunciton.BlueFoxSystem import BlueFoxServerSystem
from ....BlueFoxTools.ToolsConfig import LevelId
# ---- 只导入面食自己的数据库 ----
from ..MianshiData import (
CLEAVER, ROLLINGPIN, BOWL, OVEN,
MEAT_ITEMS, FILLING_ITEMS, RICH_MEAT_ITEMS,
SWITCH_RULES, KNEAD_COUNTERS, ITEM_USE_ON_RULES,
)
# ---- 统一分发器 ----
from ...service.FeatureDispatcher import FeatureDispatcher
class MianshiService(BlueFoxServerSystem):
"""
面食.甜食·右键转换引擎
"""
def __init__(self, namespace, systemName):
super(MianshiService, self).__init__(namespace, systemName)
print "===== MianshiService init ====="
# ---- (方块, 手持物品) -> 规则: O(1) 查找 ----
self.recipes = {}
self.featureBlocks = set()
def add(rule):
block = rule["block"]
item = rule.get("item")
self.recipes[(block, item)] = rule
self.featureBlocks.add(block)
for r in SWITCH_RULES:
add(r)
# 竹筒饭加肉: (bamboo_2 + 任一肉类) -> bamboo_4
for meat in MEAT_ITEMS:
add({"block": "rtdd:bamboo_2", "item": meat,
"target": "rtdd:bamboo_4", "consume": 1, "tip": "§a竹筒加了肉"})
# 揉面/和面连点方块也要注册(空手右键路由)
for b in KNEAD_COUNTERS:
self.featureBlocks.add(b)
# ---- itemUseOn 映射: 手持物品 -> 规则 ----
self.itemUseOnMap = {}
for r in ITEM_USE_ON_RULES:
self.itemUseOnMap[r["item"]] = r
# ---- 揉面/和面计数 {(dim,x,y,z): n} ----
self.kneadCount = {}
# ---- 右键冷却表 ----
self.cooldown = {}
# ---- 注册到统一分发器 ----
FeatureDispatcher.register(self)
# ============================================================================
# 一、给 FeatureDispatcher 的接口
# ============================================================================
def getFeatureBlocks(self):
"""返回本功能管辖的所有右键方块名集合"""
return self.featureBlocks
def getItemUseOnRules(self):
"""手持物品右键方块表面路由: 生面饼(烙制) / 面粉(加鸡蛋)(做面糊)"""
return {r["item"]: True for r in ITEM_USE_ON_RULES}
def handleBlockUse(self, args):
"""由 FeatureDispatcher 转发的右键方块入口"""
blockName = args.get("blockName")
playerId = args.get("playerId")
x, y, z = args.get("x"), args.get("y"), args.get("z")
pos = (x, y, z)
dim = comp.CreateDimension(playerId).GetEntityDimensionId()
key = (dim, x, y, z)
itemDict = self.getCarriedItem(playerId)
itemName = itemDict.get("newItemName") if itemDict else None
# ---- 揉面/和面: 空手右键连点 ----
if blockName in KNEAD_COUNTERS and (not itemName or itemName == "minecraft:air"):
return self._handleKnead(blockName, playerId, pos, dim, key)
# ---- 常规转换 ----
recipe = self.findRecipe(blockName, itemDict)
if not recipe:
return False
if not self.checkCooldown(key, 0.4):
return True
self.handleSwitch(recipe, playerId, pos, dim, itemDict)
return True
def handleItemUseOn(self, args):
"""由 FeatureDispatcher 转发的"手持物品右键方块表面"入口:
1) 手持 生面饼 右键 烤炉 -> 烤炉上方放置 馍(烙制), 消耗1个生面饼
2) 手持 面粉(加鸡蛋) 右键 木碗 -> 木碗变 蛋糕面糊(生), 消耗1个
返回 True=处理了; False=不属本功能管(交还默认行为)。"""
itemName = args.get("itemName")
playerId = args.get("playerId") or args.get("entityId")
x, y, z = args.get("x"), args.get("y"), args.get("z")
dim = comp.CreateDimension(playerId).GetEntityDimensionId()
rule = self.itemUseOnMap.get(itemName)
if not rule:
return False
# 被点方块必须是规则要求的表面方块
try:
cur = comp.CreateBlockInfo(LevelId).GetBlockNew((x, y, z), dim)
if not cur or cur.get("name") != rule["surface"]:
return False
except Exception:
return False
if not self.checkCooldown((dim, x, y, z), 0.4):
return True
itemDict = self.getCarriedItem(playerId)
if not itemDict:
return False
self.consumeItem(playerId, itemDict, rule.get("consume", 1))
if rule.get("above"):
# 在表面方块上方放置结果(烙制)
targetPos = (x, y + 1, z)
try:
cur = comp.CreateBlockInfo(LevelId).GetBlockNew(targetPos, dim)
if cur and cur.get("name") != "minecraft:air":
comp.CreateMsg(playerId).NotifyOneMessage(playerId, "§c上方被占, 无法烙制")
return True
except Exception:
pass
self.replaceBlock(targetPos, dim, rule["above"], playerId)
elif rule.get("replace"):
# 表面方块本身被替换(木碗变蛋糕面糊)
self.replaceBlock((x, y, z), dim, rule["replace"], playerId)
if rule.get("tip"):
comp.CreateMsg(playerId).NotifyOneMessage(playerId, rule["tip"])
return True
# ============================================================================
# 二、规则匹配(精确 + 空手 fallback)
# ============================================================================
def findRecipe(self, blockName, itemDict):
itemName = itemDict.get("newItemName") if itemDict else None
recipe = self.recipes.get((blockName, itemName))
if recipe:
return recipe
if not itemName or itemName == "minecraft:air":
return self.recipes.get((blockName, None))
return None
# ============================================================================
# 三、揉面/和面(空手右键连点)
# ============================================================================
def _handleKnead(self, blockName, playerId, pos, dim, key):
if not self.checkCooldown(key, 0.4):
return True
cfg = KNEAD_COUNTERS[blockName]
n = self.kneadCount.get(key, 0) + 1
if n >= cfg["times"]:
self.kneadCount.pop(key, None)
self.replaceBlock(pos, dim, cfg["target"], playerId)
comp.CreateMsg(playerId).NotifyOneMessage(playerId, cfg.get("doneTip", "§a完成"))
else:
self.kneadCount[key] = n
comp.CreateMsg(playerId).NotifyOneMessage(playerId, cfg["tip"] % n)
return True
# ============================================================================
# 四、通用转换执行
# ============================================================================
def handleSwitch(self, recipe, playerId, pos, dim, itemDict):
# 消耗物品
if recipe.get("consume", 0) > 0:
self.consumeItem(playerId, itemDict, recipe["consume"])
# 替换方块
if recipe.get("target"):
self.replaceBlock(pos, dim, recipe["target"], playerId)
# 特殊动作(自行管理掉落, 避免与通用掉落重复)
action = recipe.get("action")
# 掉落物(切分/递减/取出) —— 无特殊动作时才走通用掉落
if recipe.get("dropItem") and not action:
self.dropItem(dim, pos, recipe["dropItem"])
# 给背包物品(水桶变空桶/擀面杖返还)
if recipe.get("give"):
self.giveItem(playerId, recipe["give"])
# 特殊动作
if action == "chop_smalldough":
self.clearBlock(pos, dim)
for _ in range(8):
self.dropItem(dim, pos, "rtdd:smalldough_0")
elif action == "chop_noodles":
self.clearBlock(pos, dim)
self.dropItem(dim, pos, "rtdd:noodles")
elif action == "unmold_cake":
# 蛋糕面糊(烤熟) 脱模 -> 蛋糕胚(方块) + 掉落 1 木碗
self.replaceBlock(pos, dim, "rtdd:cakebase", playerId)
self.dropItem(dim, pos, BOWL)
elif action == "split_cake":
# 半块蛋糕 菜刀拆分: 半块消失 -> 掉落两个对应小块
self.clearBlock(pos, dim)
for _ in range(2):
self.dropItem(dim, pos, recipe["dropItem"])
elif action == "take_steamer":
# 蒸笼取出: 蒸食物块 -> 变回空蒸笼 + 掉落成品
self.replaceBlock(pos, dim, "rtdd:steamer", playerId)
if recipe.get("dropItem"):
self.dropItem(dim, pos, recipe["dropItem"])
# 提示
if recipe.get("tip"):
comp.CreateMsg(playerId).NotifyOneMessage(playerId, recipe["tip"])
# ============================================================================
# 五、工具方法:获取玩家主手物品
# ============================================================================
def getCarriedItem(self, playerId):
itemComp = comp.CreateItem(playerId)
return itemComp.GetPlayerItem(
serverApi.GetMinecraftEnum().ItemPosType.CARRIED, 0, True)
# ============================================================================
# 六、工具方法:给玩家物品
# ============================================================================
def giveItem(self, playerId, itemName, count=1, aux=0):
try:
itemDict = {"itemName": itemName, "count": count, "auxValue": aux}
comp.CreateItem(playerId).SpawnItemToPlayerInv(itemDict, playerId)
except Exception:
pass
# ============================================================================
# 七、工具方法:消耗物品
# ============================================================================
def consumeItem(self, playerId, itemDict, amount=1):
if itemDict is None:
return
count = itemDict.get("count", 0)
if count <= amount:
comp.CreateItem(playerId).SetEntityItem(
serverApi.GetMinecraftEnum().ItemPosType.CARRIED,
{"itemName": "minecraft:air", "count": 0, "auxValue": 0})
else:
itemDict["count"] = count - amount
comp.CreateItem(playerId).SetEntityItem(
serverApi.GetMinecraftEnum().ItemPosType.CARRIED,
{"itemName": itemDict["newItemName"],
"count": itemDict["count"],
"auxValue": itemDict.get("newAuxValue", 0),
"userData": itemDict.get("userData", {})})
# ============================================================================
# 八、工具方法:以掉落物形式生成物品
# ============================================================================
def dropItem(self, dim, pos, itemName, count=1, aux=0):
try:
itemDict = {"itemName": itemName, "count": count, "auxValue": aux}
self.CreateEngineItemEntity(itemDict, dim, (pos[0], pos[1] + 0.5, pos[2]))
except Exception:
pass
# ============================================================================
# 九、工具方法:替换方块 / 清空方块(保留 aux, 兼容定向变体)
# ============================================================================
def replaceBlock(self, pos, dim, newBlockName, playerId=None):
creator = playerId if playerId is not None else LevelId
aux = 0
try:
oldBlock = comp.CreateBlockInfo(creator).GetBlockNew(pos, dim)
aux = oldBlock.get("aux", 0)
except Exception:
aux = 0
comp.CreateBlockInfo(creator).SetBlockNew(
pos, blockDict={"name": newBlockName, "aux": aux},
oldBlockHandling=0, dimensionId=dim)
def clearBlock(self, pos, dim):
comp.CreateBlockInfo(LevelId).SetBlockNew(
pos, blockDict={"name": "minecraft:air", "aux": 0},
oldBlockHandling=0, dimensionId=dim)
# ============================================================================
# 十、工具方法:冷却检查
# ============================================================================
def checkCooldown(self, key, cd=0.4):
now = time.time()
last = self.cooldown.get(key, 0)
if now - last < cd:
return False
self.cooldown[key] = now
return True
@@ -0,0 +1,259 @@
# -*- coding: utf-8 -*-
"""
================================================================================
面食.甜食·计时转换引擎(服务端)
================================================================================
只处理"面食.甜食"(xy_mianshi) 分类下的【计时自动转换】:
发酵60秒(和面_4 -> 发酵后 / 法棍面胚_1 -> 发面)
蒸笼蒸熟60秒(食物放蒸笼上 1秒入蒸笼, 再60秒蒸熟)
烤炉烘焙60秒(下方判定烤炉: 胚料/面糊/蛋液 放烤炉上计时)
【与右键转换解耦】
右键转换(和面/擀面/加料/蒸笼取出等)在 MianshiService, 本类只负责计时。
【烤炉机制(用户指定)】
- 下方方块判定为 烤炉(oven) 才对该方块计时, 烤炉只做判断用
- 计时期间 烤炉被打碎 -> 终止计时, 烤炉上方方块 变成掉落物, 并给出提示
【下方判定】
below: 该方块的"正下方一格"必须是指定方块(烤炉/蒸笼)才计时
dropOnBreak: 下方判定失败且计时中 -> 方块掉落+提示(烤炉); 否则暂停(蒸笼)
【事件监听在哪?】
本类【不】监听任何事件!
ServerBlockEntityTickEvent 由 FeatureDispatcher 统一监听, 再按 timerOwner
路由到本类的 handleBlockEntityTick。计时用绝对时间戳写方块实体数据,
退出重进继续计时。
================================================================================
"""
import time
import mod.server.extraServerApi as serverApi
# ---- 网易API基础对象 ----
ServerSystem = serverApi.GetServerSystemCls() # 服务端系统基类
comp = serverApi.GetEngineCompFactory() # 组件工厂
# ---- 继承 BlueFox 框架的系统基类 ----
from ....BlueFoxTools.SpecialFunciton.BlueFoxSystem import BlueFoxServerSystem
from ....BlueFoxTools.ToolsConfig import LevelId
# ---- 方块实体数据组件(计时持久化: 开始时间戳+时长写进方块) ----
blockEntityDataComp = comp.CreateBlockEntityData(LevelId)
# ---- 只导入面食自己的数据库 ----
from ..MianshiData import TIMER_RULES, BREAK_TIP
# ---- 统一分发器 ----
from ...service.FeatureDispatcher import FeatureDispatcher
class MianshiTimerService(BlueFoxServerSystem):
"""
面食.甜食·计时转换引擎
"""
def __init__(self, namespace, systemName):
super(MianshiTimerService, self).__init__(namespace, systemName)
print "===== MianshiTimerService init ====="
# ---- 计时规则: source -> [规则...] (同一source可对应蒸笼/烤炉等不同下方) ----
self.timerMap = {}
for t in TIMER_RULES:
self.timerMap.setdefault(t["source"], []).append(t)
# ---- 注册到分发器的计时路由表 ----
FeatureDispatcher.registerTimer(self)
# ============================================================================
# 一、给 FeatureDispatcher 的接口
# ============================================================================
def getTimerBlocks(self):
"""返回本功能的所有"计时源方块"集合(tick 路由用)"""
return set(self.timerMap.keys())
def handleBlockEntityTick(self, args):
"""由 FeatureDispatcher 转发的计时方块 tick 入口"""
dim = args.get("dimension")
pos = (args.get("posX"), args.get("posY"), args.get("posZ"))
blockName = args.get("blockName", "")
self._tickProcess(dim, pos, blockName)
# ============================================================================
# 二、启动计时(本模块 autoStart, 保留接口以便需要时外部触发)
# ============================================================================
def startTimer(self, dim, pos, blockName, playerId=None):
rules = self.timerMap.get(blockName)
if not rules:
return False
rule = self._pickRule(rules, dim, pos)
if not rule:
return False
try:
data = blockEntityDataComp.GetBlockEntityData(dim, pos)
if data and data["rtdd_tid"] == blockName:
return False
except Exception:
pass
self._writeTimerData(dim, pos, rule, playerId)
return True
# ============================================================================
# 三、tick 检查与到点转换
# ============================================================================
def _pickRule(self, rules, dim, pos):
"""按"下方方块"匹配规则(蒸笼/烤炉等), 返回命中的规则; 无命中返回 None"""
belowPos = (pos[0], pos[1] - 1, pos[2])
try:
b = comp.CreateBlockInfo(LevelId).GetBlockNew(belowPos, dim)
belowName = b.get("name") if b else ""
except Exception:
belowName = ""
for rule in rules:
if belowName in rule.get("below", [belowName]):
return rule
return None
def _tickProcess(self, dim, pos, blockName):
try:
rules = self.timerMap.get(blockName)
if not rules:
return
blockData = blockEntityDataComp.GetBlockEntityData(dim, pos)
if blockData is None:
return
try:
tid = blockData["rtdd_tid"]
except Exception:
tid = ""
if tid != blockName:
# autoStart: 计时源方块无计时数据且下方方块匹配时自动启动
if any(r.get("autoStart", True) for r in rules):
rule = self._pickRule(rules, dim, pos)
if rule:
self._writeTimerData(dim, pos, rule, None)
return
# 计时中: 按下方判定规则处理(烤炉被打碎 -> 掉落; 蒸笼移走 -> 暂停)
rule = self._pickRule(rules, dim, pos)
if rule is None:
self._handleBelowBroken(dim, pos, blockName, blockData, rules)
return
tstart = blockData["rtdd_tstart"]
tdur = blockData["rtdd_tdur"]
if time.time() - tstart >= tdur:
self._finishTimer(dim, pos, rule, blockData)
except Exception:
pass
def _handleBelowBroken(self, dim, pos, blockName, data, rules):
"""下方判定方块被打碎/移走:
- 烤炉(dropOnBreak): 终止计时 + 方块掉落 + 提示
- 蒸笼: 暂停计时(数据保留, 蒸笼回来继续)"""
rule = None
for r in rules:
if r.get("dropOnBreak"):
rule = r
break
if rule is None:
return # 蒸笼等: 暂停
# 烤炉被打碎: 方块掉落 + 变空气 + 终止计时 + 提示
self._clearTimerData(dim, pos)
self._dropBlockItem(dim, pos, blockName)
self._setAir(dim, pos)
self._notifyIfOnline(data.get("rtdd_tp"), BREAK_TIP)
def _finishTimer(self, dim, pos, rule, data):
try:
cur = comp.CreateBlockInfo(LevelId).GetBlockNew(pos, dim)
if cur and cur.get("name") != rule["source"]:
self._clearTimerData(dim, pos)
return
# 到点转换
self.replaceBlock(pos, dim, rule["target"], None)
self._clearTimerData(dim, pos)
if rule.get("doneTip"):
self._notifyIfOnline(data.get("rtdd_tp"), rule["doneTip"])
except Exception:
pass
# ============================================================================
# 四、计时数据读写(存在方块实体数据里,重启不丢)
# ============================================================================
def _writeTimerData(self, dim, pos, recipe, playerId=None):
try:
blockData = blockEntityDataComp.GetBlockEntityData(dim, pos)
if blockData is None:
return
now = time.time()
blockData["rtdd_tid"] = recipe["source"]
blockData["rtdd_tstart"] = now
blockData["rtdd_tdur"] = recipe.get("time", 60)
blockData["rtdd_tp"] = playerId if playerId else ""
except Exception:
pass
def _clearTimerData(self, dim, pos):
try:
blockData = blockEntityDataComp.GetBlockEntityData(dim, pos)
if blockData is None:
return
blockData["rtdd_tid"] = ""
blockData["rtdd_tstart"] = 0
blockData["rtdd_tdur"] = 0
blockData["rtdd_tp"] = ""
except Exception:
pass
# ============================================================================
# 五、工具方法:完成/掉落提示
# ============================================================================
def _notifyIfOnline(self, playerId, tip):
if not tip or not playerId:
return
try:
ids = comp.CreateGame(LevelId).GetAllPlayerIds()
if playerId in ids:
comp.CreateMsg(playerId).NotifyOneMessage(playerId, tip)
except Exception:
pass
def _dropBlockItem(self, dim, pos, blockName):
"""把当前方块以物品实体形式掉落(烤炉被打碎时)"""
try:
itemDict = {"itemName": blockName, "count": 1, "auxValue": 0}
self.CreateEngineItemEntity(itemDict, dim, (pos[0], pos[1] + 0.5, pos[2]))
except Exception:
pass
def _setAir(self, dim, pos):
try:
comp.CreateBlockInfo(LevelId).SetBlockNew(
pos, blockDict={"name": "minecraft:air", "aux": 0},
oldBlockHandling=0, dimensionId=dim)
except Exception:
pass
# ============================================================================
# 六、工具方法:替换方块
# ============================================================================
def replaceBlock(self, pos, dim, newBlockName, playerId=None):
creator = playerId if playerId is not None else LevelId
aux = 0
try:
oldBlock = comp.CreateBlockInfo(creator).GetBlockNew(pos, dim)
aux = oldBlock.get("aux", 0)
except Exception:
aux = 0
comp.CreateBlockInfo(creator).SetBlockNew(
pos, blockDict={"name": newBlockName, "aux": aux},
oldBlockHandling=0, dimensionId=dim)
@@ -0,0 +1 @@
# -*- coding: utf-8 -*-
@@ -59,6 +59,7 @@ class FeatureDispatcher(BlueFoxServerSystem):
# ---- 类级共享路由表(用类变量,任何实例都能读写) ---- # ---- 类级共享路由表(用类变量,任何实例都能读写) ----
blockOwner = {} blockOwner = {}
blockSet = set() blockSet = set()
blockOwnerAll = {} # 方块名 -> [服务...]: 同一方块可被多个服务注册(按注册顺序), 逐个 fallback
itemUseOnOwner = {} itemUseOnOwner = {}
itemUseOnSet = set() itemUseOnSet = set()
itemUseOnAll = {} # 物品名 -> [服务...]: 同一物品可被多个服务注册(按注册顺序), 逐个 fallback itemUseOnAll = {} # 物品名 -> [服务...]: 同一物品可被多个服务注册(按注册顺序), 逐个 fallback
@@ -81,12 +82,14 @@ class FeatureDispatcher(BlueFoxServerSystem):
def register(cls, service): def register(cls, service):
""" """
右键服务初始化时调用:把管辖的"右键方块"和"手持物品右键方块表面"注册进路由表。 右键服务初始化时调用:把管辖的"右键方块"和"手持物品右键方块表面"注册进路由表。
同一方块/物品只会归属最后一个注册的服务(一般不会冲突)。 同一方块/物品可被多个服务注册(如 面粉块: 食材裹粉去重 + 面食和面),
按注册顺序追加, OnBlockUse/OnItemUseOn 逐个 fallback(第一个返回 True 的处理)。
""" """
# 右键方块路由:方块名 → 服务 # 右键方块路由:方块名 → 服务列表
for block in service.getFeatureBlocks(): for block in service.getFeatureBlocks():
cls.blockOwner[block] = service cls.blockOwner[block] = service
cls.blockSet.add(block) cls.blockSet.add(block)
cls.blockOwnerAll.setdefault(block, []).append(service)
# 手持物品右键方块表面路由:物品名 → 服务 # 手持物品右键方块表面路由:物品名 → 服务
for itemName in service.getItemUseOnRules(): for itemName in service.getItemUseOnRules():
@@ -189,23 +192,27 @@ class FeatureDispatcher(BlueFoxServerSystem):
def OnBlockUse(self, args): def OnBlockUse(self, args):
""" """
玩家右键方块时触发。 玩家右键方块时触发。
用被右键的方块名 O(1) 定位到唯一的功能服务,转发给它的 handleBlockUse。 用被右键的方块名 O(1) 定位到注册它的所有功能服务(blockOwnerAll, 按注册顺序),
逐个尝试 handleBlockUse, 第一个返回 True 的服务处理成功(多服务 fallback,
如 面粉块: 食材服务先试(裹粉去重, 空手无规则返回False) -> 面食服务和面)。
服务返回 True = 处理成功 → 取消默认行为,并标记拦截下一次物品使用 服务返回 True = 处理成功 → 取消默认行为,并标记拦截下一次物品使用
服务返回 False = 当前组合无匹配规则 → 交还默认行为 服务返回 False = 当前组合无匹配规则 → 交还默认行为
""" """
blockName = args.get("blockName") blockName = args.get("blockName")
service = self.blockOwner.get(blockName) services = self.blockOwnerAll.get(blockName)
print "[FD-BlockUse]", blockName, "svc:", (service.__class__.__name__ if service else "NONE") print "[FD-BlockUse]", blockName, "svcs:", ([s.__class__.__name__ for s in services] if services else "NONE")
if not service: if not services:
# 这个方块不属于任何已注册的功能 → 交给原版/其他模组处理 # 这个方块不属于任何已注册的功能 → 交给原版/其他模组处理
return return
handled = service.handleBlockUse(args) for service in services:
if handled: handled = service.handleBlockUse(args)
args['cancel'] = True if handled:
playerId = args.get("playerId") args['cancel'] = True
self._cancelItemUse[playerId] = True playerId = args.get("playerId")
self._cancelItemUse[playerId] = True
return
# ============================================================================ # ============================================================================
# 主入口2:手持物品右键方块表面 → 按 itemUseOnOwner 路由到右键服务 # 主入口2:手持物品右键方块表面 → 按 itemUseOnOwner 路由到右键服务
@@ -229,7 +236,7 @@ class FeatureDispatcher(BlueFoxServerSystem):
print "[FD-ItemUseOn]", itemName, "svcs:", [s.__class__.__name__ for s in services] print "[FD-ItemUseOn]", itemName, "svcs:", [s.__class__.__name__ for s in services]
playerId = args.get("playerId") or args.get("entityId") playerId = args.get("playerId") or args.get("entityId")
# 被点方块(用于去重: 该方块归哪个右键服务管辖) # 被点方块(用于去重: 该方块归哪些右键服务管辖)
clickedName = None clickedName = None
try: try:
dim = comp.CreateDimension(playerId).GetEntityDimensionId() dim = comp.CreateDimension(playerId).GetEntityDimensionId()
@@ -239,15 +246,16 @@ class FeatureDispatcher(BlueFoxServerSystem):
except Exception: except Exception:
pass pass
owners = self.blockOwnerAll.get(clickedName) if clickedName else None
for service in services: for service in services:
# 被点方块属于某个"右键方块"服务的管辖(条箱/挂肉钩/锅具等) → 该方块右键由 # 被点方块属于某些"右键方块"服务的管辖(条箱/挂肉钩/锅具等) → 该方块右键由
# ServerBlockUseEvent 处理(放入/挂鱼/做菜), 跳过本服务的 itemUseOn, # ServerBlockUseEvent 处理(放入/挂鱼/做菜), 跳过本服务的 itemUseOn,
# 避免与方块右键逻辑重复(如手持鲑鱼右键条箱应放入而非放置死鲑鱼)。 # 避免与方块右键逻辑重复(如手持鲑鱼右键条箱应放入而非放置死鲑鱼)。
# 例外: 被点方块的 owner 就是当前服务自己(如 食材裹粉: 面粉块归 ShicaiService # 例外: 当前服务本身就在被点方块的归属列表里(如 食材裹粉: 面粉块归
# 管辖, 手持生食材右键它时放行给 handleItemUseOn 处理) 则继续尝试。 # ShicaiService+面食服务 管辖, 手持生食材右键它时放行给 handleItemUseOn
if clickedName and clickedName in self.blockOwner: # 处理) 则继续尝试。
if self.blockOwner[clickedName] is not service: if clickedName and owners and service not in owners:
continue continue
handled = service.handleItemUseOn(args) handled = service.handleItemUseOn(args)
if handled: if handled:
@@ -314,11 +322,13 @@ class FeatureDispatcher(BlueFoxServerSystem):
blockName = args.get("fullName") or args.get("blockName") blockName = args.get("fullName") or args.get("blockName")
args["blockName"] = blockName # 统一成 blockName 字段, 服务内部直接用 args["blockName"] = blockName # 统一成 blockName 字段, 服务内部直接用
# 1. 优先: 归属的右键服务实现了 handleDestroy → 交给服务处理 # 1. 优先: 归属的右键服务实现了 handleDestroy → 交给服务处理(逐个 fallback)
service = self.blockOwner.get(blockName) services = self.blockOwnerAll.get(blockName)
if service and hasattr(service, "handleDestroy"): if services:
if service.handleDestroy(args): for service in services:
return if hasattr(service, "handleDestroy"):
if service.handleDestroy(args):
return
# 2. 静态映射: 放置的死鱼/生鸡肉 → 原版生食材 # 2. 静态映射: 放置的死鱼/生鸡肉 → 原版生食材
itemName = self.DESTROY_DROP.get(blockName) itemName = self.DESTROY_DROP.get(blockName)
@@ -48,7 +48,7 @@
"netease:block_entity": { "netease:block_entity": {
"client_tick": false, "client_tick": false,
"movable": false, "movable": false,
"tick": false "tick": true
} }
} }
} }
@@ -48,7 +48,7 @@
"netease:block_entity": { "netease:block_entity": {
"client_tick": false, "client_tick": false,
"movable": false, "movable": false,
"tick": false "tick": true
} }
} }
} }
@@ -48,7 +48,7 @@
"netease:block_entity": { "netease:block_entity": {
"client_tick": false, "client_tick": false,
"movable": false, "movable": false,
"tick": false "tick": true
} }
} }
} }
@@ -48,7 +48,7 @@
"netease:block_entity": { "netease:block_entity": {
"client_tick": false, "client_tick": false,
"movable": false, "movable": false,
"tick": false "tick": true
} }
} }
} }
@@ -48,7 +48,7 @@
"netease:block_entity": { "netease:block_entity": {
"client_tick": false, "client_tick": false,
"movable": false, "movable": false,
"tick": false "tick": true
} }
} }
} }
@@ -48,7 +48,7 @@
"netease:block_entity": { "netease:block_entity": {
"client_tick": false, "client_tick": false,
"movable": false, "movable": false,
"tick": false "tick": true
} }
} }
} }
@@ -48,7 +48,7 @@
"netease:block_entity": { "netease:block_entity": {
"client_tick": false, "client_tick": false,
"movable": false, "movable": false,
"tick": false "tick": true
} }
} }
} }
@@ -48,7 +48,7 @@
"netease:block_entity": { "netease:block_entity": {
"client_tick": false, "client_tick": false,
"movable": false, "movable": false,
"tick": false "tick": true
} }
} }
} }
@@ -48,7 +48,7 @@
"netease:block_entity": { "netease:block_entity": {
"client_tick": false, "client_tick": false,
"movable": false, "movable": false,
"tick": false "tick": true
} }
} }
} }
@@ -48,7 +48,7 @@
"netease:block_entity": { "netease:block_entity": {
"client_tick": false, "client_tick": false,
"movable": false, "movable": false,
"tick": false "tick": true
} }
} }
} }
@@ -48,7 +48,7 @@
"netease:block_entity": { "netease:block_entity": {
"client_tick": false, "client_tick": false,
"movable": false, "movable": false,
"tick": false "tick": true
} }
} }
} }
@@ -48,7 +48,7 @@
"netease:block_entity": { "netease:block_entity": {
"client_tick": false, "client_tick": false,
"movable": false, "movable": false,
"tick": false "tick": true
} }
} }
} }
@@ -48,7 +48,7 @@
"netease:block_entity": { "netease:block_entity": {
"client_tick": false, "client_tick": false,
"movable": false, "movable": false,
"tick": false "tick": true
} }
} }
} }
@@ -48,7 +48,7 @@
"netease:block_entity": { "netease:block_entity": {
"client_tick": false, "client_tick": false,
"movable": false, "movable": false,
"tick": false "tick": true
} }
} }
} }
@@ -48,7 +48,7 @@
"netease:block_entity": { "netease:block_entity": {
"client_tick": false, "client_tick": false,
"movable": false, "movable": false,
"tick": false "tick": true
} }
} }
} }
@@ -48,7 +48,7 @@
"netease:block_entity": { "netease:block_entity": {
"client_tick": false, "client_tick": false,
"movable": false, "movable": false,
"tick": false "tick": true
} }
} }
} }
+62
View File
@@ -564,3 +564,65 @@ FurnitureData+FurnitureService 实现, 注册到 FeatureDispatcher)
category 由 xy_mianshi 改为 xy_jinyong, 从 面团·胚料(food_04_dough) 分组移除, category 由 xy_mianshi 改为 xy_jinyong, 从 面团·胚料(food_04_dough) 分组移除,
面食txt 已归入禁用清单补记 (吐司面胚现仅 breaddough_2) [已调整] 面食txt 已归入禁用清单补记 (吐司面胚现仅 breaddough_2) [已调整]
########################################
【面食.甜食】(xy_mianshi) 2026-09-10 实现
########################################
实现于 xiangyemod/mianshi (MianshiData + MianshiService + MianshiTimerService, 注册到 FeatureDispatcher)
+ FeatureDispatcher 升级: 方块路由 blockOwner 改为多服务 fallback(blockOwnerAll),
与物品路由 itemUseOnAll 一致 (面粉块: 食材裹粉去重 + 面食和面 共管) [已实现]
+ 16个计时源方块 netease:block_entity tick 改为 true (发酵/蒸/烤炉)
一、面粉·面团组
- 面粉+鸡蛋x3 -> 面粉(加鸡蛋); +水桶(水桶变空桶) -> 面粉(加水) [已实现]
- 揉面(空手x2) -> 面粉块; 和面(空手x3) -> 生面团; 空手和面四级(和面_1~4) [已实现]
- 和面_4 计时60秒 -> 发酵后; 和面_4 + 菜刀 -> 掉落8个小面团 [已实现]
- 擀面链: 发酵后 手持擀面杖(消耗1根) -> 擀面_1, 空手逐级 -> 擀面_6 -> 生面饼(返还擀面杖) [已实现]
- 生面饼+菜刀 -> 面饼切开; 面饼切开 空手 -> 可颂胚 / +菜刀 -> 掉落生面 [已实现]
- 小面团链: 手持擀面杖(消耗1根) -> 擀面_1, 空手 -> 擀面_3 -> 饺子皮(返还擀面杖) [已实现]
二、饺子组
- 饺子皮 + 猪肉馅/青菜碎 双向组合 -> 饺子皮(猪肉馅加蔬菜) -> 生饺子(捏合) [已实现]
- 生饺子 放蒸笼上(下方蒸笼) 1秒入笼 -> 蒸笼(蒸饺子_生), 60秒 -> 熟 [已实现]
- 手持盘子(plate_0)右键熟 -> 掉落盘装水饺(plate_30) + 蒸笼归位 [已实现]
三、包子组
- 饺子皮 空手 -> 包子皮; +猪/牛肉馅 -> 包子皮(加肉); 捏合/塑形 -> 生肉包子 [已实现]
- 生肉包子 放蒸笼上 -> 蒸笼(包子_生), 60秒 -> 熟; 空手取出 熟肉包子 + 蒸笼归位 [已实现]
- 熟肉包子+菜刀 -> 半个 -> 1/4个; 手持熟肉包子堆叠(两个/三个); 空手递减取走(掉落1个) [已实现]
四、馍·肉夹馍组
- 生面饼 右键 烤炉(表面) -> 烤炉上方放置 馍 [已实现]
- 馍+菜刀 -> 馍(切开); +熟牛肉/熟猪肉 -> 肉夹馍 [已实现]
五、煎饼卷组
- 煎饼+青菜碎 -> 煎饼(加蔬菜); +熟牛肉/土豆 -> 煎饼卷牛肉(卷制3级); +熟鳕鱼/土豆 -> 煎饼卷鳕鱼 [已实现]
六、竹筒饭组
- 竹筒+菜刀 -> 竹筒(切开); +大米x32 -> 竹筒(加入米); +肉类 -> 竹筒(加入肉) [已实现]
- 竹筒(加入肉) 放蒸笼上 -> 蒸笼(竹筒饭_生), 60秒 -> 熟; 空手取出 熟竹筒饭 + 蒸笼归位 [已实现]
七、面包·烘焙组
- 法棍/吐司/可颂/甜甜圈: 手持整份右键堆叠(2份/3份); 空手递减取走(掉落1个) [已实现]
- 甜甜圈胚(烤熟)+奶油 -> 甜甜圈(成品1个) [已实现]
八、面团·胚料组
- 发酵后/法棍面胚_1/吐司面胚/甜甜圈胚(生) 空手右键循环转换 [已实现]
- 法棍面胚_1 60秒发酵 -> 发面; 发面/吐司面胚/甜甜圈胚(生)/可颂面胚 放烤炉上 60秒烘焙 -> 成品 [已实现]
九、甜点·蛋糕组
- 面粉(加鸡蛋) 右键 木碗 -> 蛋糕面糊(生); 放烤炉 60秒 -> 烤熟; 脱模 -> 蛋糕胚 + 掉落木碗 [已实现]
- 蛋糕胚+奶油/蜂蜜/浆果 -> 奶油/蜂蜜/浆果蛋糕; 菜刀切分(整块->3/4块->半块, 每次掉落小块) [已实现]
- 半块 菜刀拆分: 半块消失 + 掉落 2个 对应小块蛋糕 (蜂蜜cake_1b->2个cake_1d, 浆果cake_2b->2个cake_2d) [已实现]
- 蛋液半成品: 放烤炉 60秒 -> 布丁半成品; +糖x16 -> 焦糖布丁; +奶油 -> 舒芙蕾半成品;
舒芙蕾半成品 放烤炉 60秒 -> 舒芙蕾 [已实现]
- 蛋液半成品 放蒸笼上 -> 蒸笼(蒸牛奶鸡蛋_生), 60秒 -> 熟 [已实现]
【烤炉机制】下方判定为烤炉才对该方块计时(烤炉只做判断); 计时中烤炉被打碎 ->
终止计时 + 烤炉上方方块变掉落物 + 提示 [已实现]
【蒸笼机制】食物方块放在蒸笼(steamer)正上方(下方判定), 1秒入笼 -> 计时60秒 -> 熟;
取出时蒸笼归位 [已实现]
【留后】吃(熟肉包子/馍/煎饼卷/熟竹筒饭/蛋糕小块 右键吃)、巧克力蛋糕系列
见 全部功能没做什么.txt 面食节
+13
View File
@@ -216,3 +216,16 @@
- 煮豆腐_熟 + 手持刀(cleaver)右键 -> 获得 豆腐(beancurd) 16个, 锅恢复空汤锅 - 煮豆腐_熟 + 手持刀(cleaver)右键 -> 获得 豆腐(beancurd) 16个, 锅恢复空汤锅
- 未做原因: 属汤锅分类, 汤锅代码整体尚未开发, 本次只做分类整理与转化文档 - 未做原因: 属汤锅分类, 汤锅代码整体尚未开发, 本次只做分类整理与转化文档
########################################
【面食.甜食】(xy_mianshi)
########################################
(主要转换已实现于 xiangyemod/mianshi, 见 全部功能做了什么.txt)
一、吃 (熟食 右键食用)
- 熟肉包子/馍/煎饼卷(牛肉/鳕鱼成品)/熟竹筒饭/蛋糕小块 均可 空手右键吃
- 未做原因: 食用部分由统一的"总食用功能"汇总实现, 本次不实现 (转化文档已用 todo 标注)
二、巧克力蛋糕系列 (蛋糕胚 + 巧克力)
-- 未做原因: 转化文档标注"巧克力暂不实现"
+3 -2
View File
@@ -232,12 +232,13 @@ todo 熟竹筒饭 右键吃 (吃的操作后续实现)
转换条件:[右键脱模, 掉落 1个蛋糕胚 + 1个木碗] 转换条件:[右键脱模, 掉落 1个蛋糕胚 + 1个木碗]
60. 蛋糕胚 + 奶油(食材) -> 奶油蛋糕 60. 蛋糕胚 + 奶油(食材) -> 奶油蛋糕
转换条件:[手持 奶油 右键] 转换条件:[手持 奶油 右键]
61. 蛋糕胚 + 蜂蜜 -> 蜂蜜蛋糕系列; 蛋糕胚 + 浆果 -> 浆果蛋糕系列; 蛋糕胚 + 巧克力 -> 巧克力蛋糕系列 61. 蛋糕胚 + 蜂蜜 -> 蜂蜜蛋糕系列; 奶油蛋糕 + 浆果 -> 浆果蛋糕系列; 蛋糕胚 + 巧克力 -> 巧克力蛋糕系列
转换条件:[手持 蜂蜜/浆果/巧克力 右键] 转换条件:[手持 蜂蜜/浆果/巧克力 右键]
todo 巧克力暂不实现 todo 巧克力暂不实现
62. 各蛋糕整块 -> 3/4块 -> 半块 62. 各蛋糕整块 -> 3/4块 -> 半块
转换条件:[手持 菜刀 右键切分, 每次掉落 1个 对应小块蛋糕] 转换条件:[手持 菜刀 右键切分, 每次掉落 1个 对应小块蛋糕]
todo 半块 菜刀 拆分 直接 掉落两个小块蛋糕 半块 -> 消失, 掉落两个对应小块蛋糕
转换条件:[手持 菜刀 右键拆分, 半块消失 + 掉落 2个 小块]
todo 各小块 空手右键 吃 (吃的操作后续实现) todo 各小块 空手右键 吃 (吃的操作后续实现)
63. 蛋液半成品 -> 布丁半成品 63. 蛋液半成品 -> 布丁半成品
转换条件:[下方方块是 烤炉, 计时60秒] 转换条件:[下方方块是 烤炉, 计时60秒]