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.shicai.service.ShicaiService import ShicaiService
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():
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 = {}
blockSet = set()
blockOwnerAll = {} # 方块名 -> [服务...]: 同一方块可被多个服务注册(按注册顺序), 逐个 fallback
itemUseOnOwner = {}
itemUseOnSet = set()
itemUseOnAll = {} # 物品名 -> [服务...]: 同一物品可被多个服务注册(按注册顺序), 逐个 fallback
@@ -81,12 +82,14 @@ class FeatureDispatcher(BlueFoxServerSystem):
def register(cls, service):
"""
右键服务初始化时调用:把管辖的"右键方块"和"手持物品右键方块表面"注册进路由表。
同一方块/物品只会归属最后一个注册的服务(一般不会冲突)。
同一方块/物品可被多个服务注册(如 面粉块: 食材裹粉去重 + 面食和面),
按注册顺序追加, OnBlockUse/OnItemUseOn 逐个 fallback(第一个返回 True 的处理)。
"""
# 右键方块路由:方块名 → 服务
# 右键方块路由:方块名 → 服务列表
for block in service.getFeatureBlocks():
cls.blockOwner[block] = service
cls.blockSet.add(block)
cls.blockOwnerAll.setdefault(block, []).append(service)
# 手持物品右键方块表面路由:物品名 → 服务
for itemName in service.getItemUseOnRules():
@@ -189,23 +192,27 @@ class FeatureDispatcher(BlueFoxServerSystem):
def OnBlockUse(self, args):
"""
玩家右键方块时触发。
用被右键的方块名 O(1) 定位到唯一的功能服务,转发给它的 handleBlockUse。
用被右键的方块名 O(1) 定位到注册它的所有功能服务(blockOwnerAll, 按注册顺序),
逐个尝试 handleBlockUse, 第一个返回 True 的服务处理成功(多服务 fallback,
如 面粉块: 食材服务先试(裹粉去重, 空手无规则返回False) -> 面食服务和面)。
服务返回 True = 处理成功 → 取消默认行为,并标记拦截下一次物品使用
服务返回 False = 当前组合无匹配规则 → 交还默认行为
"""
blockName = args.get("blockName")
service = self.blockOwner.get(blockName)
print "[FD-BlockUse]", blockName, "svc:", (service.__class__.__name__ if service else "NONE")
if not service:
services = self.blockOwnerAll.get(blockName)
print "[FD-BlockUse]", blockName, "svcs:", ([s.__class__.__name__ for s in services] if services else "NONE")
if not services:
# 这个方块不属于任何已注册的功能 → 交给原版/其他模组处理
return
handled = service.handleBlockUse(args)
if handled:
args['cancel'] = True
playerId = args.get("playerId")
self._cancelItemUse[playerId] = True
for service in services:
handled = service.handleBlockUse(args)
if handled:
args['cancel'] = True
playerId = args.get("playerId")
self._cancelItemUse[playerId] = True
return
# ============================================================================
# 主入口2:手持物品右键方块表面 → 按 itemUseOnOwner 路由到右键服务
@@ -229,7 +236,7 @@ class FeatureDispatcher(BlueFoxServerSystem):
print "[FD-ItemUseOn]", itemName, "svcs:", [s.__class__.__name__ for s in services]
playerId = args.get("playerId") or args.get("entityId")
# 被点方块(用于去重: 该方块归哪个右键服务管辖)
# 被点方块(用于去重: 该方块归哪些右键服务管辖)
clickedName = None
try:
dim = comp.CreateDimension(playerId).GetEntityDimensionId()
@@ -239,15 +246,16 @@ class FeatureDispatcher(BlueFoxServerSystem):
except Exception:
pass
owners = self.blockOwnerAll.get(clickedName) if clickedName else None
for service in services:
# 被点方块属于某个"右键方块"服务的管辖(条箱/挂肉钩/锅具等) → 该方块右键由
# 被点方块属于某些"右键方块"服务的管辖(条箱/挂肉钩/锅具等) → 该方块右键由
# ServerBlockUseEvent 处理(放入/挂鱼/做菜), 跳过本服务的 itemUseOn,
# 避免与方块右键逻辑重复(如手持鲑鱼右键条箱应放入而非放置死鲑鱼)。
# 例外: 被点方块的 owner 就是当前服务自己(如 食材裹粉: 面粉块归 ShicaiService
# 管辖, 手持生食材右键它时放行给 handleItemUseOn 处理) 则继续尝试。
if clickedName and clickedName in self.blockOwner:
if self.blockOwner[clickedName] is not service:
continue
# 例外: 当前服务本身就在被点方块的归属列表里(如 食材裹粉: 面粉块归
# ShicaiService+面食服务 管辖, 手持生食材右键它时放行给 handleItemUseOn
# 处理) 则继续尝试。
if clickedName and owners and service not in owners:
continue
handled = service.handleItemUseOn(args)
if handled:
@@ -314,11 +322,13 @@ class FeatureDispatcher(BlueFoxServerSystem):
blockName = args.get("fullName") or args.get("blockName")
args["blockName"] = blockName # 统一成 blockName 字段, 服务内部直接用
# 1. 优先: 归属的右键服务实现了 handleDestroy → 交给服务处理
service = self.blockOwner.get(blockName)
if service and hasattr(service, "handleDestroy"):
if service.handleDestroy(args):
return
# 1. 优先: 归属的右键服务实现了 handleDestroy → 交给服务处理(逐个 fallback)
services = self.blockOwnerAll.get(blockName)
if services:
for service in services:
if hasattr(service, "handleDestroy"):
if service.handleDestroy(args):
return
# 2. 静态映射: 放置的死鱼/生鸡肉 → 原版生食材
itemName = self.DESTROY_DROP.get(blockName)
@@ -48,7 +48,7 @@
"netease:block_entity": {
"client_tick": false,
"movable": false,
"tick": false
"tick": true
}
}
}
@@ -48,7 +48,7 @@
"netease:block_entity": {
"client_tick": false,
"movable": false,
"tick": false
"tick": true
}
}
}
@@ -48,7 +48,7 @@
"netease:block_entity": {
"client_tick": false,
"movable": false,
"tick": false
"tick": true
}
}
}
@@ -48,7 +48,7 @@
"netease:block_entity": {
"client_tick": false,
"movable": false,
"tick": false
"tick": true
}
}
}
@@ -48,7 +48,7 @@
"netease:block_entity": {
"client_tick": false,
"movable": false,
"tick": false
"tick": true
}
}
}
@@ -48,7 +48,7 @@
"netease:block_entity": {
"client_tick": false,
"movable": false,
"tick": false
"tick": true
}
}
}
@@ -48,7 +48,7 @@
"netease:block_entity": {
"client_tick": false,
"movable": false,
"tick": false
"tick": true
}
}
}
@@ -48,7 +48,7 @@
"netease:block_entity": {
"client_tick": false,
"movable": false,
"tick": false
"tick": true
}
}
}
@@ -48,7 +48,7 @@
"netease:block_entity": {
"client_tick": false,
"movable": false,
"tick": false
"tick": true
}
}
}
@@ -48,7 +48,7 @@
"netease:block_entity": {
"client_tick": false,
"movable": false,
"tick": false
"tick": true
}
}
}
@@ -48,7 +48,7 @@
"netease:block_entity": {
"client_tick": false,
"movable": false,
"tick": false
"tick": true
}
}
}
@@ -48,7 +48,7 @@
"netease:block_entity": {
"client_tick": false,
"movable": false,
"tick": false
"tick": true
}
}
}
@@ -48,7 +48,7 @@
"netease:block_entity": {
"client_tick": false,
"movable": false,
"tick": false
"tick": true
}
}
}
@@ -48,7 +48,7 @@
"netease:block_entity": {
"client_tick": false,
"movable": false,
"tick": false
"tick": true
}
}
}
@@ -48,7 +48,7 @@
"netease:block_entity": {
"client_tick": false,
"movable": false,
"tick": false
"tick": true
}
}
}
@@ -48,7 +48,7 @@
"netease:block_entity": {
"client_tick": 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) 分组移除,
面食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个, 锅恢复空汤锅
- 未做原因: 属汤锅分类, 汤锅代码整体尚未开发, 本次只做分类整理与转化文档
########################################
【面食.甜食】(xy_mianshi)
########################################
(主要转换已实现于 xiangyemod/mianshi, 见 全部功能做了什么.txt)
一、吃 (熟食 右键食用)
- 熟肉包子/馍/煎饼卷(牛肉/鳕鱼成品)/熟竹筒饭/蛋糕小块 均可 空手右键吃
- 未做原因: 食用部分由统一的"总食用功能"汇总实现, 本次不实现 (转化文档已用 todo 标注)
二、巧克力蛋糕系列 (蛋糕胚 + 巧克力)
-- 未做原因: 转化文档标注"巧克力暂不实现"
+3 -2
View File
@@ -232,12 +232,13 @@ todo 熟竹筒饭 右键吃 (吃的操作后续实现)
转换条件:[右键脱模, 掉落 1个蛋糕胚 + 1个木碗]
60. 蛋糕胚 + 奶油(食材) -> 奶油蛋糕
转换条件:[手持 奶油 右键]
61. 蛋糕胚 + 蜂蜜 -> 蜂蜜蛋糕系列; 蛋糕胚 + 浆果 -> 浆果蛋糕系列; 蛋糕胚 + 巧克力 -> 巧克力蛋糕系列
61. 蛋糕胚 + 蜂蜜 -> 蜂蜜蛋糕系列; 奶油蛋糕 + 浆果 -> 浆果蛋糕系列; 蛋糕胚 + 巧克力 -> 巧克力蛋糕系列
转换条件:[手持 蜂蜜/浆果/巧克力 右键]
todo 巧克力暂不实现
62. 各蛋糕整块 -> 3/4块 -> 半块
转换条件:[手持 菜刀 右键切分, 每次掉落 1个 对应小块蛋糕]
todo 半块 菜刀 拆分 直接 掉落两个小块蛋糕
半块 -> 消失, 掉落两个对应小块蛋糕
转换条件:[手持 菜刀 右键拆分, 半块消失 + 掉落 2个 小块]
todo 各小块 空手右键 吃 (吃的操作后续实现)
63. 蛋液半成品 -> 布丁半成品
转换条件:[下方方块是 烤炉, 计时60秒]