方块转换数据库 ceshi
This commit is contained in:
1 parent
962513e699
commit
a9099b6044
2 files changed
+1466
-22
No files matched your search
File diff suppressed because it is too large.
Load diff
+175
-22
@@ -50,6 +50,10 @@ blockEntityDataComp = comp.CreateBlockEntityData(LevelId)
|
||||
# RECIPES 是一个列表,每条配方是一个 dict,格式见 RecipeData.py 顶部注释
|
||||
from ..RecipeData import RECIPES
|
||||
|
||||
# ---- 导入工具方块切换规则 ----
|
||||
# BLOCK_SWITCHES 是一个列表,每条规则是一个 dict,格式见 BlockSwitchData.py 顶部注释
|
||||
from ..BlockSwitchData import BLOCK_SWITCHES
|
||||
|
||||
|
||||
# ================================================================================
|
||||
# 工具函数:读取物品 userData 里的嵌套字段
|
||||
@@ -107,17 +111,39 @@ class CookingService(BlueFoxServerSystem):
|
||||
1. 内存(self.stirData)—— 快,关服就没了
|
||||
2. 方块实体数据(blockEntityData)—— 慢一点,但关服重启后还在
|
||||
每次操作都会同步更新两处,保证重启不丢进度
|
||||
|
||||
【工具方块记录数据】
|
||||
switchRecord = {
|
||||
(维度ID, x, y, z): {
|
||||
"count": 整数, # recordType="count" 时记录数量(如箭桶里有多少箭)
|
||||
"itemName": 字符串, # recordType="count" 时记录物品名(如"minecraft:arrow")
|
||||
"stack": [物品信息列表], # recordType="stack" 时记录后进先出的物品堆
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(self, namespace, systemName):
|
||||
"""
|
||||
初始化:清空翻炒数据、注册事件监听
|
||||
初始化:清空翻炒数据、注册事件监听、构建统一配方字典
|
||||
"""
|
||||
super(CookingService, self).__init__(namespace, systemName)
|
||||
print "===== CookingService init ====="
|
||||
self.stirData = {} # 内存中的翻炒数据字典
|
||||
self.switchRecord = {} # 工具方块的记录数据(箭桶数量、药水架顺序等)
|
||||
self.ListenEvent() # 注册游戏事件监听
|
||||
|
||||
# ---- 构建统一配方字典(O(1) 查找) ----
|
||||
# 把 RECIPES(做菜配方)和 BLOCK_SWITCHES(工具切换规则)合并成一份字典
|
||||
# key = (方块名, 物品名),value = 配方dict
|
||||
# 这样查找时不用遍历整个列表,直接 dict[key] 就能拿到,速度飞快
|
||||
self.allRecipes = {}
|
||||
for recipe in RECIPES:
|
||||
key = (recipe["source"], recipe.get("item"))
|
||||
self.allRecipes[key] = recipe
|
||||
for switch in BLOCK_SWITCHES:
|
||||
key = (switch["source"], switch.get("item"))
|
||||
self.allRecipes[key] = switch
|
||||
|
||||
def Destroy(self):
|
||||
"""
|
||||
系统销毁时取消所有事件监听,防止内存泄漏
|
||||
@@ -166,9 +192,9 @@ class CookingService(BlueFoxServerSystem):
|
||||
流程:
|
||||
1. 拿到被右键的方块名、玩家ID、方块坐标
|
||||
2. 看玩家手里拿了什么物品
|
||||
3. 拿着"方块名+手里物品名"去 RecipeData 里找匹配的配方
|
||||
4. 找到配方后,判断是"需要翻炒"还是"直接替换"两种类型
|
||||
5. 执行对应的做菜逻辑
|
||||
3. 拿着"方块名+手里物品名"去统一字典里 O(1) 查找
|
||||
4. 找到规则后,判断是"做菜配方"还是"工具切换"类型
|
||||
5. 执行对应的逻辑
|
||||
|
||||
args 是网易API传过来的事件参数,包含:
|
||||
- blockName: 被右键的方块名字(如 "rtdd:wok")
|
||||
@@ -188,13 +214,24 @@ class CookingService(BlueFoxServerSystem):
|
||||
# itemDict 可能是 None(空手),也可能是 dict(手里有东西)
|
||||
# dict 格式:{"newItemName": "rtdd:spatula", "count": 1, "userData": {...}}
|
||||
|
||||
# ---- 第三步:查配方 ----
|
||||
# ---- 第三步:查配方(O(1) 字典查找) ----
|
||||
recipe = self.findRecipe(blockName, itemDict)
|
||||
if not recipe:
|
||||
# 没找到匹配的配方 → 不是做菜操作,不拦截,让游戏正常处理
|
||||
return
|
||||
|
||||
# ---- 第四步:加载翻炒进度(如果这个方块之前翻过的话) ----
|
||||
# ---- 第四步:判断是不是工具切换类型 ----
|
||||
recipeType = recipe.get("type", "cook")
|
||||
# type="switch" 或 "timer" → 工具方块切换(箭桶、挂肉钩、水槽等)
|
||||
# 没有 type 或 type="cook" → 做菜配方(炒锅、煎锅等)
|
||||
|
||||
if recipeType == "switch" or recipeType == "timer":
|
||||
self.handleSwitch(recipe, playerId, pos, dim, itemDict, key, blockName)
|
||||
return
|
||||
|
||||
# ---- 第五步:以下为做菜配方逻辑 ----
|
||||
|
||||
# ---- 加载翻炒进度(如果这个方块之前翻过的话) ----
|
||||
# 先从内存取,内存没有就从方块实体数据加载(服务器重启后恢复)
|
||||
stirInfo = self.stirData.get(key, {})
|
||||
if not stirInfo:
|
||||
@@ -202,7 +239,7 @@ class CookingService(BlueFoxServerSystem):
|
||||
if stirInfo:
|
||||
self.stirData[key] = stirInfo # 加载成功后写入内存缓存
|
||||
|
||||
# ---- 第五步:根据配方类型判断 ----
|
||||
# ---- 根据配方类型判断 ----
|
||||
# needFinished=True 的配方 → 需要先翻炒熟了才能操作(比如出锅)
|
||||
# needFinished=False 的配方 → 只能对没熟的进行操作(比如继续加油)
|
||||
if recipe.get("needFinished") is True and not stirInfo.get("finished"):
|
||||
@@ -212,7 +249,7 @@ class CookingService(BlueFoxServerSystem):
|
||||
# 配方要求"没熟",但当前状态是"已熟" → 不执行
|
||||
return
|
||||
|
||||
# ---- 第六步:分发到不同的处理逻辑 ----
|
||||
# ---- 分发到不同的处理逻辑 ----
|
||||
if recipe.get("stirCount"):
|
||||
# 这个配方有 stirCount 字段 → 需要翻炒,走翻炒流程
|
||||
self.handleStir(key, recipe, playerId, pos, dim, itemDict)
|
||||
@@ -222,36 +259,152 @@ class CookingService(BlueFoxServerSystem):
|
||||
self.executeRecipe(recipe, playerId, pos, dim, itemDict, key)
|
||||
|
||||
# ============================================================================
|
||||
# 配方匹配
|
||||
# 配方匹配(O(1) 字典查找)
|
||||
# ============================================================================
|
||||
|
||||
def findRecipe(self, blockName, itemDict):
|
||||
"""
|
||||
遍历 RECIPES 列表,找到第一个匹配的配方。
|
||||
在统一字典中 O(1) 查找匹配的配方。
|
||||
|
||||
匹配条件:
|
||||
1. 配方的 source 字段 == 被右键的方块名(比如 "rtdd:wok")
|
||||
2. 如果配方指定了 item 字段,则玩家手里物品必须匹配
|
||||
3. 如果配方 item 是 None,表示空手也能触发(比如点锅盖)
|
||||
1. 先精确匹配 (方块名, 物品名)
|
||||
2. 如果没找到,尝试匹配 (方块名, None) —— 空手也能触发的规则
|
||||
|
||||
返回:匹配到的配方 dict,找不到返回 None
|
||||
"""
|
||||
# 提取玩家手里物品的名字(空手时 itemName 为 None)
|
||||
itemName = itemDict.get("newItemName") if itemDict else None
|
||||
|
||||
for recipe in RECIPES:
|
||||
# 条件1:方块名必须匹配
|
||||
if recipe["source"] != blockName:
|
||||
continue
|
||||
# 条件2:物品名必须匹配(None 表示不需要特定物品)
|
||||
if recipe["item"] is not None and recipe["item"] != itemName:
|
||||
continue
|
||||
# 两个条件都满足 → 找到了
|
||||
# 精确匹配:(方块名, 物品名)
|
||||
recipe = self.allRecipes.get((blockName, itemName))
|
||||
if recipe:
|
||||
return recipe
|
||||
|
||||
# 空手匹配:(方块名, None)
|
||||
recipe = self.allRecipes.get((blockName, None))
|
||||
if recipe:
|
||||
return recipe
|
||||
|
||||
# 遍历完所有配方都没找到
|
||||
return None
|
||||
|
||||
# ============================================================================
|
||||
# 工具方块切换处理
|
||||
# ============================================================================
|
||||
|
||||
def handleSwitch(self, recipe, playerId, pos, dim, itemDict, key, blockName):
|
||||
"""
|
||||
处理工具方块的切换逻辑(箭桶、挂肉钩、水槽、盘子架、药水架、书柜等)。
|
||||
|
||||
支持三种模式:
|
||||
1. recordType="count" → 记录一种物品+数量(如箭桶存箭)
|
||||
2. recordType="stack" → 后进先出堆栈(如药水架、书柜)
|
||||
3. 无 record → 纯切换,不记录(如挂肉钩直接换状态)
|
||||
|
||||
流程:
|
||||
1. 如果是计时型(type="timer"),直接替换方块,不消耗物品
|
||||
2. 如果是切换型(type="switch"),根据 recordType 决定记录方式
|
||||
3. 消耗物品、替换方块、更新记录
|
||||
"""
|
||||
# ---- 如果规则指定了 tool,检查玩家手里是不是拿着指定工具 ----
|
||||
if recipe.get("tool"):
|
||||
if not itemDict:
|
||||
return
|
||||
carriedItem = itemDict.get("newItemName", "")
|
||||
# 简单判断:物品名是否包含工具名
|
||||
if recipe["tool"] not in carriedItem:
|
||||
return
|
||||
|
||||
# ---- 计时型:直接替换方块,不消耗物品,不记录 ----
|
||||
if recipe.get("type") == "timer":
|
||||
if recipe.get("target"):
|
||||
self.replaceBlock(pos, dim, recipe["target"], playerId)
|
||||
return
|
||||
|
||||
# ---- 切换型 ----
|
||||
# 获取当前方块的记录数据
|
||||
record = self.switchRecord.get(key)
|
||||
|
||||
# ---- 正向操作:往方块里放东西(source == 被右键的方块) ----
|
||||
if recipe["source"] == blockName and recipe.get("item") is not None:
|
||||
# 玩家手里有物品,往方块里放
|
||||
if recipe.get("record"):
|
||||
if recipe.get("recordType") == "count":
|
||||
# 数量记录型:只记录一种物品的总数
|
||||
if not record:
|
||||
record = {
|
||||
"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
|
||||
|
||||
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 # 满了
|
||||
# 把物品信息压入堆栈
|
||||
record["stack"].append({
|
||||
"itemName": itemDict["newItemName"],
|
||||
"count": itemDict.get("count", 1),
|
||||
"auxValue": itemDict.get("newAuxValue", 0),
|
||||
"userData": itemDict.get("userData", {}),
|
||||
})
|
||||
self.switchRecord[key] = record
|
||||
|
||||
# 消耗物品
|
||||
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)
|
||||
|
||||
return
|
||||
|
||||
# ---- 逆向操作:从方块里取东西(空手右键或取回物品) ----
|
||||
if recipe["source"] == blockName and recipe.get("item") is None:
|
||||
if recipe.get("record") and record:
|
||||
if recipe.get("recordType") == "count":
|
||||
# 数量记录型取回:给玩家对应的物品,数量-1
|
||||
if record["count"] > 0:
|
||||
self.giveItem(playerId, record["itemName"])
|
||||
record["count"] -= 1
|
||||
if record["count"] <= 0:
|
||||
self.switchRecord.pop(key, None)
|
||||
else:
|
||||
self.switchRecord[key] = record
|
||||
|
||||
elif recipe.get("recordType") == "stack":
|
||||
# 堆栈记录型取回:后进先出,取最后一个放的物品
|
||||
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"]:
|
||||
self.switchRecord.pop(key, None)
|
||||
else:
|
||||
self.switchRecord[key] = record
|
||||
|
||||
# 替换方块
|
||||
if recipe.get("target"):
|
||||
self.replaceBlock(pos, dim, recipe["target"], playerId)
|
||||
|
||||
return
|
||||
|
||||
# ============================================================================
|
||||
# 配方执行(普通替换类型)
|
||||
# ============================================================================
|
||||
|
||||
Reference in new issue
Block a user