From 842befe7ddb05e7c3e55d9e3f97e15e44a3de607 Mon Sep 17 00:00:00 2001 From: wenhe <1046926120@qq.com> Date: Thu, 30 Jul 2026 12:25:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=B5=8B=E8=AF=95=202026?= =?UTF-8?q?=E5=B9=B47=E6=9C=8830=E6=97=A5=201?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ceshi/service/CookingService.py | 208 +++++++++++++----- 代办设计 | 2 +- 2 files changed, 155 insertions(+), 55 deletions(-) diff --git a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/ceshi/service/CookingService.py b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/ceshi/service/CookingService.py index 240add8..fb33f6b 100644 --- a/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/ceshi/service/CookingService.py +++ b/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/ceshi/service/CookingService.py @@ -41,10 +41,11 @@ from ...BlueFoxTools.SpecialFunciton.BlueFoxSystem import BlueFoxServerSystem from ...BlueFoxTools.ToolsConfig import LevelId # ---- 方块实体数据组件 ---- -# 每个方块都可以存一点自定义数据(比如"翻炒了几次"), -# 这个组件就是读写这些数据的。LevelId 是全局唯一的标识符, -# 所有方块数据统一存在这个 LevelId 下,和之前的 Function.py 用同一个 -blockEntityDataComp = comp.CreateBlockEntityData(LevelId) +# 每个方块都可以存一点自定义数据(比如"翻炒了几次")。 +# GetBlockEntityData / SetBlockEntityData 都在 BlockInfo 组件上。 +# 注意:CreateBlockEntityData 返回的组件只有 GetBlockEntityData(只读), +# 没有 SetBlockEntityData,所以必须用 CreateBlockInfo。 +blockEntityDataComp = comp.CreateBlockInfo(LevelId) # ---- 导入所有配方 ---- # RECIPES 是一个列表,每条配方是一个 dict,格式见 RecipeData.py 顶部注释 @@ -225,19 +226,18 @@ class CookingService(BlueFoxServerSystem): # type="switch" 或 "timer" → 工具方块切换(箭桶、挂肉钩、水槽等) # 没有 type 或 type="cook" → 做菜配方(炒锅、煎锅等) + # ---- 统一加载:把方块里的历史数据恢复到内存 ---- + # 不管是做菜还是工具切换,先把方块数据加载到内存,后面直接用 + self._loadBlockDataToMemory(key, playerId, pos, dim, recipe) + if recipeType == "switch" or recipeType == "timer": self.handleSwitch(recipe, playerId, pos, dim, itemDict, key, blockName) return # ---- 第五步:以下为做菜配方逻辑 ---- - # ---- 加载翻炒进度(如果这个方块之前翻过的话) ---- - # 先从内存取,内存没有就从方块实体数据加载(服务器重启后恢复) + # 内存中已有数据(_loadBlockDataToMemory 已加载),直接用 stirInfo = self.stirData.get(key, {}) - if not stirInfo: - stirInfo = self.loadStirData(playerId, pos, dim, recipe) - if stirInfo: - self.stirData[key] = stirInfo # 加载成功后写入内存缓存 # ---- 根据配方类型判断 ---- # needFinished=True 的配方 → 需要先翻炒熟了才能操作(比如出锅) @@ -321,12 +321,13 @@ class CookingService(BlueFoxServerSystem): return # ---- 切换型 ---- - # 获取当前方块的记录数据 + # 内存中已有数据(_loadBlockDataToMemory 已加载),直接用 record = self.switchRecord.get(key) # ---- 正向操作:往方块里放东西(source == 被右键的方块) ---- if recipe["source"] == blockName and recipe.get("item") is not None: # 玩家手里有物品,往方块里放 + needSave = False # 标记是否需要保存记录到方块 if recipe.get("record"): if recipe.get("recordType") == "count": # 数量记录型:只记录一种物品的总数 @@ -335,20 +336,18 @@ class CookingService(BlueFoxServerSystem): "count": 0, "itemName": itemDict["newItemName"], } - self.switchRecord[key] = record # 检查是否满了 maxCount = recipe.get("maxCount", 999) if record["count"] >= maxCount: return # 满了,不能再放 # 记录物品+1 record["count"] += 1 - self.switchRecord[key] = record + needSave = True elif recipe.get("recordType") == "stack": # 堆栈记录型:后进先出,记录每种物品的完整信息 if not record: record = {"stack": []} - self.switchRecord[key] = record maxCount = recipe.get("maxCount", 999) if len(record["stack"]) >= maxCount: return # 满了 @@ -359,16 +358,20 @@ class CookingService(BlueFoxServerSystem): "auxValue": itemDict.get("newAuxValue", 0), "userData": itemDict.get("userData", {}), }) - self.switchRecord[key] = record + needSave = True # 消耗物品 if recipe.get("consume", 1) > 0: self.consumeItem(playerId, itemDict, recipe.get("consume", 1)) - # 替换方块 + # 替换方块(旧方块销毁,新方块出现) if recipe.get("target"): self.replaceBlock(pos, dim, recipe["target"], playerId) + # ★ 关键:替换完方块后再保存记录到新方块上,否则数据随旧方块一起销毁 + if needSave: + self._saveRecord(key, playerId, pos, dim, record) + # 如果配方指定了给物品(如烧烤架浇水给桶) if recipe.get("giveItem"): self.giveItem(playerId, recipe["giveItem"]) @@ -377,6 +380,9 @@ class CookingService(BlueFoxServerSystem): # ---- 逆向操作:从方块里取东西(空手右键或取回物品) ---- if recipe["source"] == blockName and recipe.get("item") is None: + needSaveRecord = False # 是否需要保存记录 + needClearRecord = False # 是否需要清除记录 + if recipe.get("record") and record: if recipe.get("recordType") == "count": # 数量记录型取回:给玩家对应的物品,数量-1 @@ -384,9 +390,9 @@ class CookingService(BlueFoxServerSystem): self.giveItem(playerId, record["itemName"]) record["count"] -= 1 if record["count"] <= 0: - self.switchRecord.pop(key, None) + needClearRecord = True else: - self.switchRecord[key] = record + needSaveRecord = True elif recipe.get("recordType") == "stack": # 堆栈记录型取回:后进先出,取最后一个放的物品 @@ -399,18 +405,24 @@ class CookingService(BlueFoxServerSystem): "userData": topItem.get("userData", {})}, playerId) if not record["stack"]: - self.switchRecord.pop(key, None) + needClearRecord = True else: - self.switchRecord[key] = record + needSaveRecord = True # 如果配方直接指定了给什么物品(水槽、盘子架取回、挂肉钩退回等) if recipe.get("giveItem"): self.giveItem(playerId, recipe["giveItem"]) - # 替换方块 + # 替换方块(旧方块销毁,新方块出现) if recipe.get("target"): self.replaceBlock(pos, dim, recipe["target"], playerId) + # ★ 关键:替换完方块后再保存/清除记录,否则数据随旧方块一起销毁 + if needClearRecord: + self.clearSwitchRecord(key, playerId, pos, dim) + elif needSaveRecord: + self._saveRecord(key, playerId, pos, dim, record) + return # ============================================================================ @@ -475,7 +487,7 @@ class CookingService(BlueFoxServerSystem): - 熟了之后可以继续右键"出锅"(变成成品菜) 流程: - 1. 从内存或方块数据加载当前翻炒进度 + 1. 从内存取翻炒进度(_loadBlockDataToMemory 已提前加载) 2. 检查冷却时间,没冷却好就忽略 3. 翻炒次数+1,更新进度 4. 给玩家发进度提示("翻炒中... 3/10") @@ -483,17 +495,22 @@ class CookingService(BlueFoxServerSystem): """ now = time.time() - # ---- 第一步:加载或初始化翻炒数据 ---- - data = self.stirData.get(key) or self.loadStirData(playerId, pos, dim, recipe) + # ---- 第一步:从内存取翻炒数据(入口已通过 _loadBlockDataToMemory 加载) ---- + data = self.stirData.get(key) if not data: # 全新的翻炒,初始化数据 data = { - "count": 0, # 从0次开始 - "lastTime": 0.0, # 上次翻的时间(初始为0,第一次翻不受冷却限制) - "finished": False, # 还没熟 - "dropIfDone": recipe.get("dropIfDone", []), # 熟了拆掉掉什么 - "dropIfNot": recipe.get("dropIfNot", []), # 没熟拆掉掉什么 + "count": 0, + "lastTime": 0.0, + "finished": False, + "dropIfDone": recipe.get("dropIfDone", []), + "dropIfNot": recipe.get("dropIfNot", []), } + else: + # 兜底防止 None 值(方块数据可能不完整) + for field, default in [("lastTime", 0.0), ("count", 0), ("finished", False)]: + if data.get(field) is None: + data[field] = default self.stirData[key] = data # ---- 第二步:冷却检查 ---- @@ -705,6 +722,61 @@ class CookingService(BlueFoxServerSystem): except: pass + # ============================================================================ + # 通用持久化帮手(避免重复的 try/except/Get/Set 写法) + # ============================================================================ + + def _writeBlockData(self, dim, pos, **kwargs): + """ + 通用方块实体数据写入:读 → 改 → 写。 + + 把 saveStirData / clearStirData / saveSwitchRecord / clearSwitchRecord + 四个方法里重复的 try/except/GetBlockEntityData/SetBlockEntityData 抽出来, + 一行搞定,不用每次写一样的 try/except。 + """ + try: + blockData = blockEntityDataComp.GetBlockEntityData(dim, pos) + if blockData is None: + blockData = {} + for key, value in kwargs.items(): + blockData[key] = value + blockEntityDataComp.SetBlockEntityData(dim, pos, blockData) + except Exception as e: + print "[CookingService] _writeBlockData 写入失败: pos=%s dim=%s err=%s" % (pos, dim, str(e)) + + def _saveRecord(self, key, playerId, pos, dim, record): + """ + 同时更新内存和方块实体数据中的工具方块记录。 + + 替代原本重复出现的: + self.switchRecord[key] = record + self.saveSwitchRecord(playerId, pos, dim, record) + """ + self.switchRecord[key] = record + self.saveSwitchRecord(playerId, pos, dim, record) + + # ============================================================================ + # 统一数据加载入口(玩家右键方块时先把方块数据恢复到内存) + # ============================================================================ + + def _loadBlockDataToMemory(self, key, playerId, pos, dim, recipe): + """ + 在确定玩家右键命中了一个配方后,立刻把方块里存的历史数据加载到内存。 + + 这样 handleStir / handleSwitch 里就不用各自加载了, + 直接从 self.stirData / self.switchRecord 取就行。 + + 两个数据源互不干扰:翻炒数据用 stirData,工具切换记录用 switchRecord。 + """ + if key not in self.stirData: + stirInfo = self.loadStirData(playerId, pos, dim, recipe) + if stirInfo: + self.stirData[key] = stirInfo + if key not in self.switchRecord: + switchInfo = self.loadSwitchRecord(playerId, pos, dim) + if switchInfo: + self.switchRecord[key] = switchInfo + # ============================================================================ # 翻炒数据持久化(存方块里,不存JSON文件) # ============================================================================ @@ -742,40 +814,68 @@ class CookingService(BlueFoxServerSystem): def saveStirData(self, playerId, pos, dim, data): """ - 把翻炒进度写入方块的实体数据。 - - 每次翻炒后都调用一次,保证数据实时同步。 - 用方括号 [] 直接赋值,网易API会自动保存到方块中。 + 把翻炒进度写入方块实体数据。 """ - try: - blockData = blockEntityDataComp.GetBlockEntityData(dim, pos) - blockData["rtdd_sc"] = data["count"] # 保存翻炒次数 - blockData["rtdd_slt"] = data["lastTime"] # 保存最后翻炒时间 - blockData["rtdd_sf"] = data["finished"] # 保存是否熟了 - except: - # 如果方块没有实体数据对象,忽略(下次加载会重新初始化) - pass + self._writeBlockData(dim, pos, + rtdd_sc=data["count"], + rtdd_slt=data["lastTime"], + rtdd_sf=data["finished"]) def clearStirData(self, key, playerId, pos, dim): """ - 清除方块上的翻炒数据。 - - 调用时机: - - 方块被替换(比如炒锅变成了成品菜) - - 方块被拆掉(玩家把锅拆了) - - 同时清除内存和方块实体数据。 + 清除方块上的翻炒数据(内存+方块实体数据)。 """ - # 清除内存中的数据 self.stirData.pop(key, None) - # 清除方块实体数据(重置为初始值) + self._writeBlockData(dim, pos, rtdd_sc=0, rtdd_slt=0.0, rtdd_sf=False) + + # ============================================================================ + # 工具方块记录持久化(药水架、书柜、箭桶等) + # ============================================================================ + + def saveSwitchRecord(self, playerId, pos, dim, record): + """ + 把工具方块的记录数据写入方块实体数据。 + 记录类型:count型(箭桶)→ rtdd_swt/swc/swi,stack型(书柜/药水架)→ rtdd_swt/sws + """ + if "count" in record: + self._writeBlockData(dim, pos, + rtdd_swt="count", + rtdd_swc=record["count"], + rtdd_swi=record.get("itemName", "")) + elif "stack" in record: + self._writeBlockData(dim, pos, + rtdd_swt="stack", + rtdd_sws=record["stack"]) + + def loadSwitchRecord(self, playerId, pos, dim): + """ + 从方块实体数据里读取工具方块的记录数据。 + + 返回: + 有数据 → {"count": N, "itemName": "xxx"} 或 {"stack": [...]} + 没有 → None + """ try: blockData = blockEntityDataComp.GetBlockEntityData(dim, pos) - blockData["rtdd_sc"] = 0 - blockData["rtdd_slt"] = 0.0 - blockData["rtdd_sf"] = False + swt = blockData["rtdd_swt"] # 记录类型:"count" 或 "stack" + if swt == "count": + return { + "count": blockData["rtdd_swc"], + "itemName": blockData["rtdd_swi"], + } + elif swt == "stack": + return { + "stack": blockData["rtdd_sws"], + } except: - pass + return None + + def clearSwitchRecord(self, key, playerId, pos, dim): + """ + 清除工具方块的记录数据(内存+方块实体数据)。 + """ + self.switchRecord.pop(key, None) + self._writeBlockData(dim, pos, rtdd_swt="", rtdd_swc=0, rtdd_swi="", rtdd_sws=[]) # ============================================================================ # 拆方块处理 diff --git a/代办设计 b/代办设计 index 82e5282..68e859f 100644 --- a/代办设计 +++ b/代办设计 @@ -3,7 +3,7 @@ 底座方块分析(锅下面是灶) 菜品做出后方块化 盘子 清洗/盛饭/放置 -附魔书柜 放置/取回 +附魔书柜 放置/取回 (1) 切菜 鳕鱼没有鲑鱼的晾干流程模型 水槽只有四个脏盘子和满水状态,没有满水放脏盘子的模型