烧烤 动物养殖 分类 功能实现3

This commit is contained in:
wenhe committed 2026-09-01 23:02:02 +08:00
1 parent 9c99295db6
commit 6686e80d22
2 files changed
+152 -23

No files matched your search

@@ -33,6 +33,9 @@ comp = serverApi.GetEngineCompFactory() # 组件工厂
from ....BlueFoxTools.SpecialFunciton.BlueFoxSystem import BlueFoxServerSystem
from ....BlueFoxTools.ToolsConfig import LevelId
# ---- 方块实体数据组件(计时持久化:把开始时间戳+时长写进方块,重启后继续计时) ----
blockEntityDataComp = comp.CreateBlockEntityData(LevelId)
# ---- 只导入烧烤自己的数据库 ----
from ..BarbecueData import BARBECUE_SWITCHES, ITEM_USE_ON_RULES
@@ -83,8 +86,7 @@ class BarbecueService(BlueFoxServerSystem):
for rule in ITEM_USE_ON_RULES:
self.itemUseOnRecipes[rule["item"]] = rule
# ---- 计时去重表 + 右键冷却表 ----
self._timerSchedule = {}
# ---- 右键冷却表 ----
self.cooldown = {}
# ---- 注册到统一分发器 ----
@@ -125,19 +127,19 @@ class BarbecueService(BlueFoxServerSystem):
if not self.checkCooldown(key, recipe.get("switchCd", 0.5)):
return True
# ---- 下方方块检查(timer 需篝火,烤串需点燃的烧烤架) ----
# ---- 下方方块检查(timer 需篝火,烤串需点燃的烧烤炉) ----
if not self.checkBelow(recipe, dim, pos):
# 下方不是要求的方法 → 提示玩家,不执行(但也算处理,取消默认行为)
# 下方不是要求的方块 → 失败提示,不执行(但也算处理,取消默认行为)
if recipe.get("type") == "timer":
tip = "§c支杆下方需要放一个篝火(营火)才能烤制!"
else:
tip = "§c烤串需要放在点燃的烧烤架上才能烤制!"
tip = "§c下方不是点燃的烧烤炉,无法翻烤!"
comp.CreateMsg(playerId).NotifyOneMessage(playerId, tip)
return True
# 计时型:启动计时
if recipe.get("type") == "timer":
self.startTimer(key, recipe, dim)
self.startTimer(key, recipe, dim, playerId)
return True
# 切换型
@@ -180,6 +182,9 @@ class BarbecueService(BlueFoxServerSystem):
# 生成生鸡肉(放置后)方块
self.replaceBlock(targetPos, dim, rule["target"], playerId)
# 放置成功提示
if rule.get("tip"):
comp.CreateMsg(playerId).NotifyOneMessage(playerId, rule["tip"])
return True
# ============================================================================
@@ -220,7 +225,11 @@ class BarbecueService(BlueFoxServerSystem):
if recipe.get("target") in self.barbecueTimers:
nextTimer = self.barbecueTimers[recipe["target"]]
if self.checkBelow(nextTimer, dim, pos):
self.startTimer(key, nextTimer, dim)
self.startTimer(key, nextTimer, dim, playerId)
# 转换成功提示(点火/上杆等)
if recipe.get("tip"):
comp.CreateMsg(playerId).NotifyOneMessage(playerId, recipe["tip"])
return
@@ -233,8 +242,12 @@ class BarbecueService(BlueFoxServerSystem):
if recipe.get("target"):
self.replaceBlock(pos, dim, recipe["target"], playerId)
# 转换成功提示(烤串翻烤/取下等)
if recipe.get("tip"):
comp.CreateMsg(playerId).NotifyOneMessage(playerId, recipe["tip"])
# ============================================================================
# 计时型规则处理(AddTimer 一次性定时,启动前检查下方篝火)
# 计时型规则处理(方块实体 tick 持久化计时,启动前检查下方篝火)
# ============================================================================
def checkBelow(self, recipe, dim, pos):
@@ -252,29 +265,116 @@ class BarbecueService(BlueFoxServerSystem):
except Exception:
return False
def startTimer(self, key, recipe, dim):
"""启动一次性定时器,1秒内去重,到点由 _timerDone 执行转换"""
now = time.time()
last = self._timerSchedule.get(key, 0)
if now - last < 1.0:
return
self._timerSchedule[key] = now
self.AddTimer(recipe.get("time", 60), self._timerDone, key, recipe, dim)
def _timerDone(self, key, recipe, dim):
"""计时到点:确认方块仍是计时源,且下方仍有篝火,才执行转换"""
def startTimer(self, key, recipe, dim, playerId=None):
"""
启动烤制计时:把 计时标识+开始时间戳+时长 写入方块实体数据。
- 已处于本规则计时中的方块不会重复重置时间
- 到点判断由 FeatureDispatcher 转发的 ServerBlockEntityTickEvent 完成
- 时间戳存在方块上 → 服务器重启/玩家重进后继续计时
(例如烤了40秒退出,回来只剩20秒)
"""
pos = (key[1], key[2], key[3])
# 去重:已在本规则计时中的方块不重置
try:
data = blockEntityDataComp.GetBlockEntityData(dim, pos)
if data and data.get("rtdd_tid") == recipe["source"]:
return
except Exception:
pass
self._writeTimerData(dim, pos, recipe, playerId)
# 计时开始提示
if playerId and recipe.get("startTip"):
comp.CreateMsg(playerId).NotifyOneMessage(playerId, recipe["startTip"])
def handleBlockEntityTick(self, args):
"""FeatureDispatcher 转发:烤制方块每 tick 检查是否到点"""
posDim = args.get("posDim")
if not posDim:
return
dim = posDim[3]
pos = (posDim[0], posDim[1], posDim[2])
self._tickProcess(dim, pos)
def _tickProcess(self, dim, pos):
"""tick 主逻辑:读计时数据,到点执行转换(重启后照样生效)"""
try:
data = blockEntityDataComp.GetBlockEntityData(dim, pos)
if not data:
return
tid = data.get("rtdd_tid")
if not tid:
return
recipe = self.barbecueTimers.get(tid)
if not recipe:
return
tstart = data.get("rtdd_tstart", 0)
tdur = data.get("rtdd_tdur", 0)
if time.time() - tstart >= tdur:
self._finishTimer(dim, pos, recipe, data)
except Exception:
pass
def _finishTimer(self, dim, pos, recipe, data):
"""
计时到点:确认方块仍是计时源、下方仍有篝火,才执行转换。
- 篝火被拿走 → 暂停烤制,等篝火回来继续
- 烤熟后清除计时数据,并给启动者发送"烤熟了"提示
"""
try:
cur = comp.CreateBlockInfo(LevelId).GetBlockNew(pos, dim)
if not cur or cur.get("name") != recipe["source"]:
if cur and cur.get("name") != recipe["source"]:
self._clearTimerData(dim, pos)
return
if not self.checkBelow(recipe, dim, pos):
return # 篝火被拿走了,暂停烤制
self.replaceBlock(pos, dim, recipe["target"], None)
# 若新方块仍是计时源 → 继续下一级(当前烧烤无多级计时,预留)
nextRecipe = self.barbecueTimers.get(recipe["target"])
if nextRecipe:
self.startTimer(key, nextRecipe, dim)
self._writeTimerData(dim, pos, nextRecipe, data.get("rtdd_tp"))
else:
self._clearTimerData(dim, pos)
doneTip = recipe.get("doneTip")
if doneTip:
self._notifyIfOnline(data.get("rtdd_tp"), doneTip)
except Exception:
pass
# ---- 计时数据读写(存在方块实体数据里,重启不丢) ----
def _writeTimerData(self, dim, pos, recipe, playerId=None):
"""把计时信息写进方块实体数据"""
try:
blockData = blockEntityDataComp.GetBlockEntityData(dim, pos)
if blockData is None:
return
blockData["rtdd_tid"] = recipe["source"]
blockData["rtdd_tstart"] = time.time()
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