箭桶修复
This commit is contained in:
1 parent
e38c2b4b38
commit
2a8c7e8328
1 file changed
+190
-116
+190
-116
@@ -46,6 +46,10 @@ from ...BlueFoxTools.ToolsConfig import LevelId
|
||||
# GetBlockEntityData 返回的 BlockEntityData 对象支持 [] 操作,直接赋值即可持久化。
|
||||
blockEntityDataComp = comp.CreateBlockEntityData(LevelId)
|
||||
|
||||
# ---- 游戏组件(用于 AddTimer 延迟写入 block entity) ----#
|
||||
gameComp = comp.CreateGame(LevelId)
|
||||
|
||||
|
||||
# ---- 导入工具方块切换规则 ----
|
||||
# BLOCK_SWITCHES 是一个列表,每条规则是一个 dict,格式见 BlockSwitchData.py 顶部注释
|
||||
from ..BlockSwitchData import BLOCK_SWITCHES
|
||||
@@ -157,7 +161,7 @@ class BlockSwitchService(BlueFoxServerSystem):
|
||||
|
||||
# ============================================================================
|
||||
# 主入口:玩家右键方块
|
||||
# ============================================================================
|
||||
# ============================================================================
|
||||
|
||||
def OnBlockUse(self, args):
|
||||
"""
|
||||
@@ -307,7 +311,7 @@ class BlockSwitchService(BlueFoxServerSystem):
|
||||
return
|
||||
|
||||
# ---- 切换型 ----
|
||||
# 内存中已有数据(_loadBlockDataToMemory 已加载),直接用
|
||||
# 内存中已有数据(_loaBlockDataToMemory 已加载),直接用
|
||||
record = self.switchRecord.get(key)
|
||||
|
||||
# ---- 正向操作:往方块里放东西(source == 被右键的方块) ----
|
||||
@@ -425,13 +429,27 @@ class BlockSwitchService(BlueFoxServerSystem):
|
||||
"""
|
||||
try:
|
||||
blockData = blockEntityDataComp.GetBlockEntityData(dim, pos)
|
||||
print "[BlockSwitchService] _writeBlockData GetBlockEntityData returned: %s (pos=%s dim=%s)" % (type(blockData).__name__ if blockData is not None else "None", pos, dim)
|
||||
if blockData is None:
|
||||
print "[BlockSwitchService] _writeBlockData blockData is None: pos=%s dim=%s" % (pos, dim)
|
||||
return
|
||||
for key, value in kwargs.items():
|
||||
print "[BlockSwitchService] _writeBlockData setting: [%s]=%s (type=%s)" % (key, value, type(value).__name__)
|
||||
blockData[key] = value
|
||||
# 写入后立即读取验证
|
||||
verifyData = blockEntityDataComp.GetBlockEntityData(dim, pos)
|
||||
if verifyData:
|
||||
for key in kwargs:
|
||||
try:
|
||||
val = verifyData[key]
|
||||
print "[BlockSwitchService] _writeBlockData verify: [%s]=%s" % (key, val)
|
||||
except:
|
||||
print "[BlockSwitchService] _writeBlockData verify: [%s]=<KEY_ERROR>" % key
|
||||
else:
|
||||
print "[BlockSwitchService] _writeBlockData verify FAILED: blockData is None after write!"
|
||||
except Exception as e:
|
||||
print "[BlockSwitchService] _writeBlockData 写入失败: pos=%s dim=%s err=%s" % (pos, dim, str(e))
|
||||
import traceback
|
||||
print "[BlockSwitchService] _writeBlockData 写入失败: pos=%s dim=%s err=%s trace=%s" % (pos, dim, str(e), traceback.format_exc())
|
||||
|
||||
def _saveRecord(self, key, playerId, pos, dim, record):
|
||||
"""
|
||||
@@ -471,6 +489,7 @@ class BlockSwitchService(BlueFoxServerSystem):
|
||||
记录存在方块实体数据里,所以玩家退出游戏再重进,
|
||||
loadSwitchRecord 还能从方块里把物品读回来。
|
||||
"""
|
||||
print "[BlockSwitchService] saveSwitchRecord pos=%s dim=%s record=%s" % (pos, dim, record)
|
||||
if "count" in record:
|
||||
self._writeBlockData(dim, pos,
|
||||
rtdd_swt="count",
|
||||
@@ -492,18 +511,39 @@ class BlockSwitchService(BlueFoxServerSystem):
|
||||
"""
|
||||
try:
|
||||
blockData = blockEntityDataComp.GetBlockEntityData(dim, pos)
|
||||
print "[BlockSwitchService] loadSwitchRecord GetBlockEntityData returned: %s (pos=%s dim=%s)" % (type(blockData).__name__ if blockData is not None else "None", pos, dim)
|
||||
if blockData is None:
|
||||
print "[BlockSwitchService] loadSwitchRecord blockData is None!"
|
||||
return None
|
||||
# 注意:BlockEntityData 对象不支持 .keys() 和 .get() 方法
|
||||
# 只支持 [] 操作符(__getitem__),key 不存在会抛 KeyError
|
||||
swt = blockData["rtdd_swt"] # 记录类型:"count" 或 "stack"
|
||||
print "[BlockSwitchService] loadSwitchRecord rtdd_swt=%s" % swt
|
||||
if swt == "count":
|
||||
count = blockData["rtdd_swc"]
|
||||
itemName = blockData["rtdd_swi"]
|
||||
try:
|
||||
auxValue = blockData["rtdd_swa"]
|
||||
except (KeyError, Exception):
|
||||
auxValue = 0
|
||||
print "[BlockSwitchService] loadSwitchRecord count data: count=%s itemName=%s auxValue=%s" % (count, itemName, auxValue)
|
||||
return {
|
||||
"count": blockData["rtdd_swc"],
|
||||
"itemName": blockData["rtdd_swi"],
|
||||
"auxValue": blockData.get("rtdd_swa", 0),
|
||||
"count": count,
|
||||
"itemName": itemName,
|
||||
"auxValue": auxValue,
|
||||
}
|
||||
elif swt == "stack":
|
||||
stack = blockData["rtdd_sws"]
|
||||
print "[BlockSwitchService] loadSwitchRecord stack data: len=%s" % len(stack)
|
||||
return {
|
||||
"stack": blockData["rtdd_sws"],
|
||||
"stack": stack,
|
||||
}
|
||||
except:
|
||||
else:
|
||||
print "[BlockSwitchService] loadSwitchRecord unknown swt: %s" % swt
|
||||
return None
|
||||
except Exception as e:
|
||||
import traceback
|
||||
print "[BlockSwitchService] loadSwitchRecord exception: %s trace=%s" % (str(e), traceback.format_exc())
|
||||
return None
|
||||
|
||||
def clearSwitchRecord(self, key, playerId, pos, dim):
|
||||
@@ -513,6 +553,147 @@ class BlockSwitchService(BlueFoxServerSystem):
|
||||
self.switchRecord.pop(key, None)
|
||||
self._writeBlockData(dim, pos, rtdd_swt="", rtdd_swc=0, rtdd_swi="", rtdd_swa=0, rtdd_sws=[])
|
||||
|
||||
# ============================================================================
|
||||
# 箭桶模式(arrowMode):存箭 / 取箭
|
||||
# ============================================================================
|
||||
|
||||
def _handleArrowMode(self, arrowMode, recipe, playerId, pos, dim, itemDict, key, blockName):
|
||||
"""
|
||||
处理箭桶的存箭/取箭逻辑。
|
||||
|
||||
【存箭流程】
|
||||
1. 检查手中是否为箭(_isArrow 已在 findRecipe 验证过)
|
||||
2. 检查方块是否有记录且类型匹配:
|
||||
a. 已有记录 → 检查手中箭类型(itemName+auxValue)是否匹配 → 不匹配则 return
|
||||
b. 无记录 → 新建记录
|
||||
3. 计算实际可存数量 = min(手中数量, maxCount - 已有数量)
|
||||
4. 如果可存数量 <= 0 → return
|
||||
5. 从手中扣减,更新记录,替换方块
|
||||
|
||||
【取箭流程】
|
||||
1. 检查方块是否有记录且 count > 0
|
||||
2. 给玩家手中/背包添加 count 只箭(itemName + auxValue 按记录)
|
||||
3. 清空记录,替换方块
|
||||
"""
|
||||
record = self.switchRecord.get(key)
|
||||
|
||||
if arrowMode == "store":
|
||||
# ---- 存箭 ----
|
||||
handCount = itemDict.get("count", 0)
|
||||
if handCount <= 0:
|
||||
return
|
||||
|
||||
handItemName = itemDict.get("newItemName", "")
|
||||
handAuxValue = itemDict.get("newAuxValue", 0)
|
||||
|
||||
# 检查方块是否有记录且类型匹配
|
||||
if record and record["count"] > 0:
|
||||
# 已有记录 → 检查箭类型是否一致
|
||||
if record.get("itemName") != handItemName or record.get("auxValue", 0) != handAuxValue:
|
||||
return # 类型不匹配,不能混存
|
||||
else:
|
||||
# 无记录 → 新建
|
||||
record = {
|
||||
"count": 0,
|
||||
"itemName": handItemName,
|
||||
"auxValue": handAuxValue,
|
||||
}
|
||||
|
||||
# 计算实际可存数量
|
||||
maxCount = recipe.get("maxCount", 32)
|
||||
if record["count"] >= maxCount:
|
||||
return # 已满
|
||||
storeCount = min(handCount, maxCount - record["count"])
|
||||
|
||||
# 从玩家手中扣减
|
||||
self._consumeItemCount(playerId, itemDict, storeCount)
|
||||
|
||||
# 更新记录
|
||||
record["count"] += storeCount
|
||||
|
||||
# 替换方块
|
||||
if recipe.get("target"):
|
||||
self.replaceBlock(pos, dim, recipe["target"], playerId)
|
||||
|
||||
# ★ 保存记录到新方块
|
||||
# 注意:这里不用延迟写入。虽然 SetBlockNew 替换方块后 block entity
|
||||
# 可能尚未完全初始化,但 GetBlockEntityData 仍然能获取到对象并写入。
|
||||
# 延迟写入反而可能导致退出游戏后数据不持久化。
|
||||
self._saveRecord(key, playerId, pos, dim, record)
|
||||
|
||||
elif arrowMode == "retrieve":
|
||||
# ---- 取箭 ----
|
||||
if not record or record["count"] <= 0:
|
||||
return
|
||||
|
||||
retCount = record["count"]
|
||||
retItemName = record["itemName"]
|
||||
retAuxValue = record.get("auxValue", 0)
|
||||
|
||||
# 给玩家箭
|
||||
self.giveItem(playerId, retItemName, retCount, retAuxValue)
|
||||
|
||||
# 替换方块
|
||||
if recipe.get("target"):
|
||||
self.replaceBlock(pos, dim, recipe["target"], playerId)
|
||||
|
||||
# ★ 清空记录
|
||||
self.clearSwitchRecord(key, playerId, pos, dim)
|
||||
|
||||
def _consumeItemCount(self, playerId, itemDict, amount):
|
||||
"""
|
||||
从玩家主手批量扣减指定数量的物品。
|
||||
如果手中数量刚好等于 amount → 清空主手。
|
||||
如果手中数量大于 amount → 减少 amount。
|
||||
"""
|
||||
if not itemDict or amount <= 0:
|
||||
return
|
||||
count = itemDict.get("count", 0)
|
||||
if count <= amount:
|
||||
# 数量不够或刚好用完 → 清空主手
|
||||
comp.CreateItem(playerId).SetEntityItem(
|
||||
serverApi.GetMinecraftEnum().ItemPosType.CARRIED,
|
||||
{"itemName": "minecraft:air", "count": 0, "auxValue": 0})
|
||||
else:
|
||||
# 数量够 → 减少 amount 个
|
||||
itemDict["count"] = count - amount
|
||||
comp.CreateItem(playerId).SetEntityItem(
|
||||
serverApi.GetMinecraftEnum().ItemPosType.CARRIED,
|
||||
{"itemName": itemDict["newItemName"],
|
||||
"count": itemDict["count"],
|
||||
"auxValue": itemDict.get("newAuxValue", 0)})
|
||||
|
||||
# ============================================================================
|
||||
# 延迟写入帮手(解决 SetBlockNew 替换方块后 block entity 未初始化的问题)
|
||||
# ============================================================================
|
||||
|
||||
def _saveRecordDelayed(self, key, playerId, pos, dim, record):
|
||||
"""
|
||||
延迟一帧保存记录到方块实体数据。
|
||||
|
||||
SetBlockNew 替换方块后,新方块的 block entity 需要引擎内部初始化时间,
|
||||
立即 GetBlockEntityData 可能返回 None 导致写入静默失败。
|
||||
|
||||
先更新内存,再延迟写入方块实体。
|
||||
"""
|
||||
print "[BlockSwitchService] _saveRecordDelayed key=%s record=%s" % (key, record)
|
||||
self.switchRecord[key] = record
|
||||
gameComp.AddTimer(0.1, self.saveSwitchRecord, playerId, pos, dim, record)
|
||||
|
||||
def _clearRecordDelayed(self, key, playerId, pos, dim):
|
||||
"""
|
||||
延迟一帧清除方块实体数据。
|
||||
"""
|
||||
print "[BlockSwitchService] _clearRecordDelayed key=%s" % (key,)
|
||||
self.switchRecord.pop(key, None)
|
||||
gameComp.AddTimer(0.1, self._clearRecordWrite, playerId, pos, dim)
|
||||
|
||||
def _clearRecordWrite(self, playerId, pos, dim):
|
||||
"""
|
||||
实际执行清除写入(被 AddTimer 调用)。
|
||||
"""
|
||||
self._writeBlockData(dim, pos, rtdd_swt="", rtdd_swc=0, rtdd_swi="", rtdd_swa=0, rtdd_sws=[])
|
||||
|
||||
# ============================================================================
|
||||
# 工具方法:获取玩家手中物品
|
||||
# ============================================================================
|
||||
@@ -587,111 +768,4 @@ class BlockSwitchService(BlueFoxServerSystem):
|
||||
如果背包满了,物品会掉在地上。
|
||||
"""
|
||||
comp.CreateItem(playerId).SpawnItemToPlayerInv(
|
||||
{"itemName": itemName, "count": count, "auxValue": auxValue}, playerId)
|
||||
|
||||
# ============================================================================
|
||||
# 箭桶模式(arrowMode):存箭 / 取箭
|
||||
# ============================================================================
|
||||
|
||||
def _handleArrowMode(self, arrowMode, recipe, playerId, pos, dim, itemDict, key, blockName):
|
||||
"""
|
||||
处理箭桶的存箭/取箭逻辑。
|
||||
|
||||
【存箭流程】
|
||||
1. 检查手中是否为箭(_isArrow 已在 findRecipe 验证过)
|
||||
2. 检查方块是否有记录且类型匹配:
|
||||
a. 已有记录 → 检查手中箭类型(itemName+auxValue)是否匹配 → 不匹配则 return
|
||||
b. 无记录 → 新建记录
|
||||
3. 计算实际可存数量 = min(手中数量, maxCount - 已有数量)
|
||||
4. 如果可存数量 <= 0 → return
|
||||
5. 从手中扣减,更新记录,替换方块
|
||||
|
||||
【取箭流程】
|
||||
1. 检查方块是否有记录且 count > 0
|
||||
2. 给玩家手中/背包添加 count 只箭(itemName + auxValue 按记录)
|
||||
3. 清空记录,替换方块
|
||||
"""
|
||||
record = self.switchRecord.get(key)
|
||||
|
||||
if arrowMode == "store":
|
||||
# ---- 存箭 ----
|
||||
handCount = itemDict.get("count", 0)
|
||||
if handCount <= 0:
|
||||
return
|
||||
|
||||
handItemName = itemDict.get("newItemName", "")
|
||||
handAuxValue = itemDict.get("newAuxValue", 0)
|
||||
|
||||
# 检查方块是否有记录且类型匹配
|
||||
if record and record["count"] > 0:
|
||||
# 已有记录 → 检查箭类型是否一致
|
||||
if record.get("itemName") != handItemName or record.get("auxValue", 0) != handAuxValue:
|
||||
return # 类型不匹配,不能混存
|
||||
else:
|
||||
# 无记录 → 新建
|
||||
record = {
|
||||
"count": 0,
|
||||
"itemName": handItemName,
|
||||
"auxValue": handAuxValue,
|
||||
}
|
||||
|
||||
# 计算实际可存数量
|
||||
maxCount = recipe.get("maxCount", 32)
|
||||
if record["count"] >= maxCount:
|
||||
return # 已满
|
||||
storeCount = min(handCount, maxCount - record["count"])
|
||||
|
||||
# 从玩家手中扣减
|
||||
self._consumeItemCount(playerId, itemDict, storeCount)
|
||||
|
||||
# 更新记录
|
||||
record["count"] += storeCount
|
||||
|
||||
# 替换方块
|
||||
if recipe.get("target"):
|
||||
self.replaceBlock(pos, dim, recipe["target"], playerId)
|
||||
|
||||
# 保存记录到新方块
|
||||
self._saveRecord(key, playerId, pos, dim, record)
|
||||
|
||||
elif arrowMode == "retrieve":
|
||||
# ---- 取箭 ----
|
||||
if not record or record["count"] <= 0:
|
||||
return
|
||||
|
||||
retCount = record["count"]
|
||||
retItemName = record["itemName"]
|
||||
retAuxValue = record.get("auxValue", 0)
|
||||
|
||||
# 给玩家箭
|
||||
self.giveItem(playerId, retItemName, retCount, retAuxValue)
|
||||
|
||||
# 替换方块
|
||||
if recipe.get("target"):
|
||||
self.replaceBlock(pos, dim, recipe["target"], playerId)
|
||||
|
||||
# 清空记录
|
||||
self.clearSwitchRecord(key, playerId, pos, dim)
|
||||
|
||||
def _consumeItemCount(self, playerId, itemDict, amount):
|
||||
"""
|
||||
从玩家主手批量扣减指定数量的物品。
|
||||
如果手中数量刚好等于 amount → 清空主手。
|
||||
如果手中数量大于 amount → 减少 amount。
|
||||
"""
|
||||
if not itemDict or amount <= 0:
|
||||
return
|
||||
count = itemDict.get("count", 0)
|
||||
if count <= amount:
|
||||
# 数量不够或刚好用完 → 清空主手
|
||||
comp.CreateItem(playerId).SetEntityItem(
|
||||
serverApi.GetMinecraftEnum().ItemPosType.CARRIED,
|
||||
{"itemName": "minecraft:air", "count": 0, "auxValue": 0})
|
||||
else:
|
||||
# 数量够 → 减少 amount 个
|
||||
itemDict["count"] = count - amount
|
||||
comp.CreateItem(playerId).SetEntityItem(
|
||||
serverApi.GetMinecraftEnum().ItemPosType.CARRIED,
|
||||
{"itemName": itemDict["newItemName"],
|
||||
"count": itemDict["count"],
|
||||
"auxValue": itemDict.get("newAuxValue", 0)})
|
||||
{"itemName": itemName, "count": count, "auxValue": auxValue}, playerId)
|
||||
Reference in new issue
Block a user