代码测试 2026年7月30日 减少bug 处理

This commit is contained in:
wenhe committed 2026-07-30 16:32:45 +08:00
1 parent 9c6bb1aacc
commit 2ab9aa7585
1 file changed
+38 -59
@@ -41,14 +41,9 @@ from ...BlueFoxTools.SpecialFunciton.BlueFoxSystem import BlueFoxServerSystem
from ...BlueFoxTools.ToolsConfig import LevelId
# ---- 方块实体数据组件 ----
# 根据网易文档:
# GetBlockEntityData 在 blockEntityExDataCompServer 组件上(CreateBlockEntityData)
# SetBlockEntityData 在 blockInfoCompServer 组件上(CreateBlockInfo)
# 两个 API 在不同组件上,所以要创建两个组件:
# blockEntityDataComp → 读数据(GetBlockEntityData)
# blockInfoComp → 写数据(SetBlockEntityData)
# GetBlockEntityData 返回的 BlockEntityData 对象支持 [] 操作,直接赋值即可持久化。
# 参考官方文档:方块实体数据组件只有 GetBlockEntityData,没有 SetBlockEntityData。
blockEntityDataComp = comp.CreateBlockEntityData(LevelId)
blockInfoComp = comp.CreateBlockInfo(LevelId)
# ---- 导入所有配方 ----
# RECIPES 是一个列表,每条配方是一个 dict,格式见 RecipeData.py 顶部注释
@@ -135,6 +130,7 @@ class CookingService(BlueFoxServerSystem):
self.stirData = {} # 内存中的翻炒数据字典
self.switchRecord = {} # 工具方块的记录数据(箭桶数量、药水架顺序等)
self.switchCooldown = {} # 工具方块切换冷却时间(防止连点)
self._cancelItemUse = {} # 将要取消下一次物品使用的玩家ID集合(防止喝药水等)
self.ListenEvent() # 注册游戏事件监听
# ---- 构建统一配方字典(O(1) 查找) ----
@@ -162,9 +158,10 @@ class CookingService(BlueFoxServerSystem):
def ListenEvent(self):
"""
注册两个游戏事件:
注册三个游戏事件:
1. ServerBlockUseEvent —— 玩家右键方块(做菜、翻炒、加油等)
2. ServerPlayerTryDestroyBlockEvent —— 玩家拆方块(拆锅时掉落食材)
2. ServerPlayerTryDestroyBlockEvent —— 玩家拆方块(掉落食材)
3. ServerItemTryUseEvent —— 玩家尝试使用物品(拦截喝药水等默认行为)
"""
# 事件1:玩家右键方块
self.ListenForEvent(serverApi.GetEngineNamespace(),
@@ -174,6 +171,10 @@ class CookingService(BlueFoxServerSystem):
self.ListenForEvent(serverApi.GetEngineNamespace(),
serverApi.GetEngineSystemName(),
"ServerPlayerTryDestroyBlockEvent", self, self.OnDestroy)
# 事件3:玩家尝试使用物品(拦截喝药水)
self.ListenForEvent(serverApi.GetEngineNamespace(),
serverApi.GetEngineSystemName(),
"ServerItemTryUseEvent", self, self.OnItemTryUse)
def UnListenEvent(self):
"""
@@ -185,6 +186,9 @@ class CookingService(BlueFoxServerSystem):
self.UnListenForEvent(serverApi.GetEngineNamespace(),
serverApi.GetEngineSystemName(),
"ServerPlayerTryDestroyBlockEvent", self, self.OnDestroy)
self.UnListenForEvent(serverApi.GetEngineNamespace(),
serverApi.GetEngineSystemName(),
"ServerItemTryUseEvent", self, self.OnItemTryUse)
# ============================================================================
# 主入口:玩家右键方块
@@ -227,6 +231,8 @@ class CookingService(BlueFoxServerSystem):
# 找到配方后,取消默认行为(如喝药水、吃食物等),由本 Mod 全权接管
args['cancel'] = True
# 同时标记该玩家下一次物品使用事件也要取消,防止喝药水等默认行为
self._cancelItemUse[playerId] = True
# ---- 第四步:判断是不是工具切换类型 ----
recipeType = recipe.get("type", "cook")
@@ -265,6 +271,15 @@ class CookingService(BlueFoxServerSystem):
# 没有 stirCount → 普通替换流程(比如加油、加水、盖盖)
self.executeRecipe(recipe, playerId, pos, dim, itemDict, key)
# ============================================================================
# 拦截物品使用事件(防止喝药水等默认行为)
# ============================================================================
def OnItemTryUse(self, args):
playerId = args.get("playerId")
if self._cancelItemUse.pop(playerId, False):
args['cancel'] = True
# ============================================================================
# 配方匹配(O(1) 字典查找)
# ============================================================================
@@ -354,19 +369,6 @@ class CookingService(BlueFoxServerSystem):
# 检查是否满了
maxCount = recipe.get("maxCount", 999)
if record["count"] >= maxCount:
# 满了,自动转向取回操作
takeRecipe = self.allRecipes.get((blockName, None))
if takeRecipe and record["count"] > 0:
self.giveItem(playerId, record["itemName"])
record["count"] -= 1
if takeRecipe.get("giveItem"):
self.giveItem(playerId, takeRecipe["giveItem"])
if takeRecipe.get("target"):
self.replaceBlock(pos, dim, takeRecipe["target"], playerId)
if record["count"] <= 0:
self.clearSwitchRecord(key, playerId, pos, dim)
else:
self._saveRecord(key, playerId, pos, dim, record)
return
# 记录物品+1
record["count"] += 1
@@ -378,31 +380,6 @@ class CookingService(BlueFoxServerSystem):
record = {"stack": []}
maxCount = recipe.get("maxCount", 999)
if len(record["stack"]) >= maxCount:
# 满了,自动转向取回操作
takeRecipe = self.allRecipes.get((blockName, None))
if takeRecipe:
needSave = False
needClear = False
if record["stack"]:
topItem = record["stack"].pop()
comp.CreateItem(playerId).SpawnItemToPlayerInv(
{"itemName": topItem["itemName"],
"count": topItem["count"],
"auxValue": topItem["auxValue"],
"userData": topItem.get("userData", {})},
playerId)
if not record["stack"]:
needClear = True
else:
needSave = True
if takeRecipe.get("giveItem"):
self.giveItem(playerId, takeRecipe["giveItem"])
if takeRecipe.get("target"):
self.replaceBlock(pos, dim, takeRecipe["target"], playerId)
if needClear:
self.clearSwitchRecord(key, playerId, pos, dim)
elif needSave:
self._saveRecord(key, playerId, pos, dim, record)
return
# 把物品信息压入堆栈
record["stack"].append({
@@ -664,26 +641,26 @@ class CookingService(BlueFoxServerSystem):
def consumeItem(self, playerId, itemDict, amount=1):
"""
消耗玩家手里物品的指定数量。
消耗玩家主手物品的指定数量。
如果数量不够 → 直接清空这个格子
如果数量不够 → 清空主手(SetEntityItem 传 None)
如果数量够 → 减少对应数量
重要:网易API里 GetPlayerItem 返回的 key 是 newItemName/newAuxValue,
但 SetEntityItem 接收的 key 是 itemName/auxValue,
所以这里需要做字段名转换。
重要:SetInvItemNum 的参数是背包槽位索引(int),不是 ItemPosType 枚举。
清空主手必须用 SetEntityItem(CARRIED, None),不能用 SetInvItemNum。
"""
count = itemDict.get("count", 0)
if count <= amount:
# 数量不够或刚好用完 → 清空这个格子
comp.CreateItem(playerId).SetInvItemNum(
serverApi.GetMinecraftEnum().ItemPosType.CARRIED, 0)
# 数量不够或刚好用完 → 清空主手
comp.CreateItem(playerId).SetEntityItem(
serverApi.GetMinecraftEnum().ItemPosType.CARRIED,
None)
else:
# 数量够 → 减少 amount 个
itemDict["count"] = count - amount
comp.CreateItem(playerId).SetEntityItem(
serverApi.GetMinecraftEnum().ItemPosType.CARRIED,
{"itemName": itemDict["newItemName"], # 注意:这里是 itemName 不是 newItemName
{"itemName": itemDict["newItemName"],
"count": itemDict["count"],
"auxValue": itemDict.get("newAuxValue", 0)})
@@ -783,14 +760,16 @@ class CookingService(BlueFoxServerSystem):
"""
通用方块实体数据写入。
读用 blockEntityDataComp(GetBlockEntityData),写用 blockInfoComp(SetBlockEntityData)。
两个 API 在不同组件上,所以要分开调用。
GetBlockEntityData 返回的 BlockEntityData 对象支持 [] 操作,
直接赋值即可持久化。官方没有 SetBlockEntityData 方法。
"""
try:
blockData = blockEntityDataComp.GetBlockEntityData(dim, pos)
if blockData is None:
print "[CookingService] _writeBlockData blockData is None: pos=%s dim=%s" % (pos, dim)
return
for key, value in kwargs.items():
blockData[key] = value
blockInfoComp.SetBlockEntityData(dim, pos, blockData)
except Exception as e:
print "[CookingService] _writeBlockData 写入失败: pos=%s dim=%s err=%s" % (pos, dim, str(e))