This commit is contained in:
wenhe committed 2026-09-22 16:03:30 +08:00
1 parent fadb5db6ec
commit 379a1c87e9
4 files changed
+170 -50

No files matched your search

@@ -36,7 +36,8 @@
tip: 转换成功时给玩家的提示(绿色§a开头)
startTip: 计时型规则启动计时时给玩家的提示(仅玩家主动触发时发)
doneTip: 计时到点完成时给启动者的提示(如"烤鸡烤熟了!")
autoStart: 放置时是否自动开始计时,默认True(自动);烧烤烤制设为False=必须右键激活
autoStart: 放置/上杆后是否自动开始计时,默认True(自动);烧烤设为True=下方
出现营火即自动开始烤制,无需右键启动
================================================================================
"""
@@ -179,13 +180,14 @@ BARBECUE_SWITCHES = [
# 三、上杆(手持生食材右键 支杆b_34)
# ============================================================
# 【上烤鸡】支杆 + 生鸡肉(放置后方块物品) → 烤鸡(上烤架_生)
# 提示不说"开始烤制"——下方是不是营火由运行时判断(aotoStartRoast)。
{
"source": "rtdd:b_34",
"item": "rtdd:roastchickenplace_0",
"target": "rtdd:roastchicken_0",
"consume": 1,
"type": "switch",
"tip": "§a烤鸡已上杆,右键开始烤制",
"tip": "§a烤鸡已上杆",
"giveItem": None,
},
# 【上烤乳猪】支杆 + 死猪 → 烤乳猪(生)
@@ -195,7 +197,7 @@ BARBECUE_SWITCHES = [
"target": "rtdd:roastpig_0",
"consume": 1,
"type": "switch",
"tip": "§a烤乳猪已上杆,右键开始烤制",
"tip": "§a烤乳猪已上杆",
"giveItem": None,
},
# 【上烤鳕鱼】支杆 + 鳕鱼 → 烤鳕鱼(生)
@@ -205,7 +207,7 @@ BARBECUE_SWITCHES = [
"target": "rtdd:grilledcod_0",
"consume": 1,
"type": "switch",
"tip": "§a烤鳕鱼已上杆,右键开始烤制",
"tip": "§a烤鳕鱼已上杆",
"giveItem": None,
},
# 【上烤鲑鱼】支杆 + 鲑鱼 → 烤鲑鱼(生)
@@ -215,15 +217,16 @@ BARBECUE_SWITCHES = [
"target": "rtdd:grilled_fish",
"consume": 1,
"type": "switch",
"tip": "§a烤鲑鱼已上杆,右键开始烤制",
"tip": "§a烤鲑鱼已上杆",
"giveItem": None,
},
# ============================================================
# 四、计时烤制(上杆后,支杆下方篝火,计时自动转换)
# ============================================================
# 【烤熟】烤鸡(上烤架_生) → 烤鸡(上烤架_熟),下方需篝火,约60秒
# autoStart=False:放置/上杆后必须右键一下才开始烤制
# 【烤熟】烤鸡(上烤架_生) → 烤鸡(上烤架_熟),下方需篝火
# autoStart=True:下方出现营火即自动开始烤制,无需右键
# startTip=下方已是营火时的提示(aotoStartRoast 动态判断下发)
{
"source": "rtdd:roastchicken_0",
"item": None,
@@ -232,12 +235,12 @@ BARBECUE_SWITCHES = [
"type": "timer",
"time": 60,
"below": ["minecraft:campfire"],
"autoStart": False,
"startTip": "§e开始烤制烤鸡,约60秒…",
"autoStart": True,
"startTip": "§a下方是营火,烤鸡开始烤制",
"doneTip": "§e烤鸡烤熟了!",
"giveItem": None,
},
# 【烤熟】烤乳猪(生) → 烤乳猪(熟),下方需篝火,约60秒
# 【烤熟】烤乳猪(生) → 烤乳猪(熟),下方需篝火
{
"source": "rtdd:roastpig_0",
"item": None,
@@ -246,12 +249,12 @@ BARBECUE_SWITCHES = [
"type": "timer",
"time": 60,
"below": ["minecraft:campfire"],
"autoStart": False,
"startTip": "§e开始烤制烤乳猪,约60秒…",
"autoStart": True,
"startTip": "§a下方是营火,烤乳猪开始烤制",
"doneTip": "§e烤乳猪烤熟了!",
"giveItem": None,
},
# 【烤熟】烤鳕鱼(生) → 烤鳕鱼(熟),下方需篝火,约60秒
# 【烤熟】烤鳕鱼(生) → 烤鳕鱼(熟),下方需篝火
{
"source": "rtdd:grilledcod_0",
"item": None,
@@ -260,12 +263,12 @@ BARBECUE_SWITCHES = [
"type": "timer",
"time": 60,
"below": ["minecraft:campfire"],
"autoStart": False,
"startTip": "§e开始烤制烤鳕鱼,约60秒…",
"autoStart": True,
"startTip": "§a下方是营火,烤鳕鱼开始烤制",
"doneTip": "§e烤鳕鱼烤熟了!",
"giveItem": None,
},
# 【烤熟】烤鲑鱼(生) → 烤鲑鱼(熟),下方需篝火,约60秒
# 【烤熟】烤鲑鱼(生) → 烤鲑鱼(熟),下方需篝火
{
"source": "rtdd:grilled_fish",
"item": None,
@@ -274,8 +277,8 @@ BARBECUE_SWITCHES = [
"type": "timer",
"time": 60,
"below": ["minecraft:campfire"],
"autoStart": False,
"startTip": "§e开始烤制烤鲑鱼,约60秒…",
"autoStart": True,
"startTip": "§a下方是营火,烤鲑鱼开始烤制",
"doneTip": "§e烤鲑鱼烤熟了!",
"giveItem": None,
},
@@ -10,8 +10,10 @@
同分类的"计时自动转换"(烤鸡/烤乳猪/烤鱼 上杆后下方篝火烤熟)已拆到独立类:
BarbecueTimerService —— 处理 ServerBlockEntityTickEvent 转发的计时逻辑
本类只负责右键事件,两者通过 FeatureDispatcher 协作:
- 本类右键碰到"计时源方块"(如烤鸡(生))→ 调 FeatureDispatcher.startTimerFor
转发给 BarbecueTimerService 启动烤制(篝火检查也在计时服务里做)
- 本类上杆/放置成"计时源方块"(烤鸡/烤乳猪/烤鱼 生态)→ 调 autoStartRoast
→ FeatureDispatcher.startTimerFor 转发给 BarbecueTimerService 自动启动烤制
(下方营火判定 + 提示都在计时服务里做)
- 计时源方块的 tick 也会自动检测下方营火并补写计时(即使玩家先放生态再放营火)
- 计时到点转换完全由 BarbecueTimerService 负责,本类不碰任何计时数据
【事件监听在哪?】
@@ -26,13 +28,13 @@
handleBlockUse ← 入口:分发器转发右键方块事件
├─ findRecipe ← 匹配 (方块名, 物品名) 规则
├─ checkCooldown ← 连点冷却(防刷提示)
├─ forwardStartTimer ← 计时源方块 → 转发给计时服务启动烤制
├─ checkBelow ← 切换型规则的下方方块检查(烤串需点燃的烧烤炉)
└─ handleSwitch ← 切换型规则具体执行(点火/烤串/上杆/取下)
├─ consumeItem ← 消耗物品
├─ replaceBlock ← 替换方块
├─ giveItem ← 直接给物品(塞背包)
└─ dropItems ← 掉落物形式给物品(取下整只成品)
├─ handleSwitch ← 切换型规则具体执行(点火/烤串/上杆/取下)
│ └─ autoStartRoast← 上杆/放置计时源方块后自动判定下方营火并启动烤制
│ └─ checkBelow ← 切换型规则的下方方块检查(烤串需点燃的烧烤炉)
│ └─ consumeItem ← 消耗物品
│ └─ replaceBlock ← 替换方块
│ └─ giveItem ← 直接给物品(塞背包)
└─ dropItems ← 掉落物形式给物品(取下整只成品)
================================================================================
"""
import time
@@ -78,10 +80,14 @@ class BarbecueService(BlueFoxServerSystem):
# switch 和 timer 规则都收进来:右键"计时源方块"时才能识别并转发给计时服务
self.barbecueRecipes = {}
self.barbecueBlockSet = set()
# 计时源方块集合(上杆/放置后需要自动判定下方营火并启动烤制)
self.timerSourceSet = set()
for sw in BARBECUE_SWITCHES:
key = (sw["source"], sw.get("item"))
self.barbecueRecipes[key] = sw
self.barbecueBlockSet.add(sw["source"])
if sw.get("type") == "timer":
self.timerSourceSet.add(sw["source"])
# ---- 右键冷却表 ----
self.cooldown = {}
@@ -122,15 +128,17 @@ class BarbecueService(BlueFoxServerSystem):
if not recipe:
return False
# 计时型规则【不再通过右键启动】。烤制改为"放置/上杆后自动判定下方营火"
# (见 handleSwitch 正向; 营火放上去也会由 tick 自动检测启动)。
# 因此右键计时源方块(烤乳猪生态等)一律放行,不拦截 —— 否则玩家想在上面
# 放方块时会被一直拦截并弹"需要营火",造成互斥。
if recipe.get("type") == "timer":
return False
# 冷却检查(烤串"右键2次"用 switchCd 调小冷却以便快速连点)
if not self.checkCooldown(key, recipe.get("switchCd", 0.5)):
return True
# 计时型规则:右键"计时源方块"(如烤鸡(生))→ 转发给计时服务启动烤制。
# 下方篝火检查在 BarbecueTimerService.startTimer 里做(失败会提示玩家)
if recipe.get("type") == "timer":
return self.forwardStartTimer(blockName, dim, pos, playerId)
# 切换型规则:先检查下方方块(烤串要求下方是点燃的烧烤炉)
if not self.checkBelow(recipe, dim, pos):
comp.CreateMsg(playerId).NotifyOneMessage(playerId, "§c下方不是点燃的烧烤炉,无法翻烤!")
@@ -157,15 +165,18 @@ class BarbecueService(BlueFoxServerSystem):
return self.barbecueRecipes.get((blockName, None))
# ============================================================================
# 三、计时转发(把"计时源方块"的烤制启动任务交给 BarbecueTimerService)
# 三、计时自动启动(上杆/放置计时源方块后,判定下方营火并启动烤制)
# ============================================================================
def forwardStartTimer(self, blockName, dim, pos, playerId):
def autoStartRoast(self, blockName, dim, pos, playerId):
"""
右键碰到"计时源方块"(如烤鸡(生))时,把启动烤制转交给计时服务。
通过 FeatureDispatcher.startTimerFor 按方块名 O(1) 路由到 BarbecueTimerService。
上杆/放置成"计时源方块"(烤乳猪生态等)后自动判定并启动烤制:
- 下方是营火 → 启动计时,提示开始烤制
- 下方不是营火 → 提示需要营火
通过 FeatureDispatcher.startTimerFor 按方块名 O(1) 路由到 BarbecueTimerService,
由它的 startTimer 统一做营火判定 + 提示 + 写计时数据。
"""
return FeatureDispatcher.startTimerFor(blockName, dim, pos, playerId)
FeatureDispatcher.startTimerFor(blockName, dim, pos, playerId)
# ============================================================================
# 四、切换型规则处理
@@ -178,9 +189,8 @@ class BarbecueService(BlueFoxServerSystem):
正向(item 不为 None):点火/上杆 → 消耗 → 替换 → 给奖励
逆向(item 为 None) :烤串2次/取下 → 掉落 → 替换
注意:上杆/点火后【不自动启动烤制】。
烧烤计时规则 autoStart=False,必须玩家右键"计时源方块"才激活烤制
(见 handleBlockUse → forwardStartTimer)。
注意:上杆/放置成"计时源方块"(烤鸡/烤乳猪/烤鱼 生态)后会自动调用
autoStartRoast 检测下方营火并启动烤制(无需右键,见下方正向分支)。
"""
# ---- 正向操作 ----
if recipe.get("item") is not None:
@@ -200,6 +210,13 @@ class BarbecueService(BlueFoxServerSystem):
if recipe.get("tip"):
comp.CreateMsg(playerId).NotifyOneMessage(playerId, recipe["tip"])
# 【自动烤制】:若上杆/放置成的方块是计时源(烤乳猪生态/烤鸡/烤鱼),
# 立即判定下方是否营火:是→开始计时;否→提示需要营火。
# (不再需要玩家右键启动,避免与"放方块"互斥。)
target = recipe.get("target")
if target and target in self.timerSourceSet:
self.autoStartRoast(target, dim, pos, playerId)
return
# ---- 逆向操作 ----
@@ -9,14 +9,17 @@
【与右键转换解耦】
同分类的"右键切换"(烧烤架点火/灭火、烤串翻烤、上杆、取下)在 BarbecueService。
本类只负责计时,两者通过 FeatureDispatcher 协作:
- BarbecueService 右键"计时源方块"(如烤鸡(生))→ 调 FeatureDispatcher.startTimerFor
转发到本类的 startTimer 启动烤制(下方篝火检查也在这里做)
- BarbecueService 上杆/放置成"计时源方块"→ 调 autoStartRoast →
FeatureDispatcher.startTimerFor 转发到本类的 startTimer 启动烤制
(下方篝火检查 + 提示也在这里做)
- 计时源方块的 tick 也会自动检测下方营火并补写计时(先放生态再放营火也成立)
- 服务器 tick(ServerBlockEntityTickEvent)由 FeatureDispatcher 按 timerOwner
路由到本类的 handleBlockEntityTick,到点即烤熟
【烤制规则】
- autoStart=False:上杆/放置后【不会】自动开始烤制,必须右键激活(startTimer)
- autoStart=True:放置/上杆后,只要下方是营火就【自动】开始烤制(无需右键启动)
- 启动前检查下方是否为篝火(minecraft:campfire),不是则拒绝并提示
- tick 也会自动检测:即使玩家先放"生态"再放营火,下方出现营火后下一 tick 自动补写计时
- 烤制中若下方篝火被拿走 → 暂停(到点时不转换);篝火放回后继续
- 完成后清除计时数据,并给"启动烤制的玩家"发送"烤熟了"提示
@@ -63,6 +66,8 @@ from ..BarbecueData import BARBECUE_SWITCHES
# ---- 统一分发器(本类把自己注册进计时路由表,让分发器把 tick 事件转发过来) ----
from ...service.FeatureDispatcher import FeatureDispatcher
gameComp = comp.CreateGame(LevelId) # 便捷取游戏组件(延时写 owner 用)
class BarbecueTimerService(BlueFoxServerSystem):
"""
@@ -116,7 +121,9 @@ class BarbecueTimerService(BlueFoxServerSystem):
def startTimer(self, dim, pos, blockName, playerId=None):
"""
启动烤制计时:先检查下方篝火,通过后写 开始时间戳+时长 到方块实体数据。
- 启动前检查:下方不是篝火 → 拒绝并提示(烧烤必须右键激活,不会自动烤)
- 由 BarbecueService 上杆/放置计时源方块时调用(autoStartRoast),
也用于其他计时源主动启动。
- 启动前检查:下方不是篝火 → 拒绝并提示"支杆下方需要放一个篝火(营火)"
- 已在本规则计时中的方块不会重复重置时间(保持原剩余时间)
返回 True=找到规则并处理(含已计时中/篝火检查失败);False=不属于本计时功能
"""
@@ -124,6 +131,11 @@ class BarbecueTimerService(BlueFoxServerSystem):
if not recipe:
return False
# 先记录"放置者"(rtdd_tp),即使下方还没营火也记 —— 这样等营火放上去后
# tick 自动补写开始计时时,能拿到这位玩家并发"开始烤制"提示。
if playerId:
self._recordOwner(dim, pos, playerId)
# 启动前检查下方篝火(烧烤必须下方是篝火才能开始烤制)
if not self.checkBelow(recipe, dim, pos):
if playerId:
@@ -151,8 +163,8 @@ class BarbecueTimerService(BlueFoxServerSystem):
"""
tick 主逻辑:
1) 按事件自带的当前方块名判断是否计时源(创造直接放置也会进来)
2) 是计时源但没有计时数据 → 只有 autoStart=True 才自动补写。
烧烤 autoStart=False:上杆后不会自动烤,必须右键激活,这里不补写
2) 是计时源但没有计时数据 → autoStart=True 时自动补写开始计时,
前提是下方是营火(玩家先放生态再放营火,下方出现营火后下一 tick 自动开始烤制)
3) 有计时数据 → 到点执行转换(重启后时间戳照常生效)
方块被拆掉后 tick 停止、数据随方块消失,不会在原位置继续计时转换。
注意:GetBlockEntityData 返回的对象不支持 .get(),这里统一用 [] 读取。
@@ -172,9 +184,20 @@ class BarbecueTimerService(BlueFoxServerSystem):
except Exception:
tid = ""
if tid != blockName:
# 烧烤必须右键激活烤制:autoStart=False 时不自动补写计时
if recipe.get("autoStart", True):
self._writeTimerData(dim, pos, recipe, None)
# 无计时数据(刚上杆/刚放置生态/刚被清过计时)。
# 烧烤自动烤制:只要下方是营火就自动补写开始计时 —— 这样玩家无论
# 先放烤乳猪还是先放营火,只要下方出现营火就会自动开始烤制,
# 彻底免去手动右键启动。
if recipe.get("autoStart", True) and self.checkBelow(recipe, dim, pos):
owner = ""
try:
owner = blockData["rtdd_tp"] or ""
except Exception:
owner = ""
self._writeTimerData(dim, pos, recipe, owner if owner else None)
# 只发序号给记录到的放置者(rtdd_tp),绝不群发
if owner and recipe.get("startTip"):
self._notifyIfOnline(owner, recipe["startTip"])
return
tstart = blockData["rtdd_tstart"]
@@ -264,6 +287,20 @@ class BarbecueTimerService(BlueFoxServerSystem):
except Exception:
pass
def _recordOwner(self, dim, pos, playerId):
"""记录"放置者"到方块实体数据 rtdd_tp。
放置时方块实体数据可能刚建好,延时 0.1 秒再写入(足够比 tick 首批补写快),
这样之后 tick 自动补写开始计时时能取到 owner 并发提示。"""
gameComp.AddTimer(0.1, self._recordOwnerDelayed, dim, pos, playerId)
def _recordOwnerDelayed(self, dim, pos, playerId):
try:
blockData = blockEntityDataComp.GetBlockEntityData(dim, pos)
if blockData is not None:
blockData["rtdd_tp"] = playerId
except Exception:
pass
# ============================================================================
# 六、工具方法:完成提示
# ============================================================================