乡野自然实现 2
This commit is contained in:
1 parent
1fb4e24c78
commit
97da44ab18
6 files changed
+578
No files matched your search
@@ -0,0 +1,106 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
================================================================================
|
||||
乡野自然(xy_natural)转化规则数据
|
||||
================================================================================
|
||||
统一管理"乡野自然"(xy_natural) 分类下的转化规则常量。只被
|
||||
NaturalService / NaturalTimerService 读取,FeatureDispatcher 通过方块名/物品名
|
||||
集合路由到对应服务。
|
||||
|
||||
【本次实现的功能】
|
||||
1) 果树结果 (计时): 苹果/桃/橘 树叶 -> 果实形态 逐级结果
|
||||
2) 葡萄藤生长 (计时): grapebushes_1 -> grapebushes_2
|
||||
3) 葡萄藤取葡萄 (右键): 成熟葡萄藤 -> 取3葡萄, 变回葡萄藤_1
|
||||
4) 柴火堆叠/取用 (右键): firewood <-> firewood_2
|
||||
5) 柴火分解 (工作台配方): firewood -> 9个木条
|
||||
6) 水稻种植 (手持稻谷右键耕地): farmland -> 水稻刚种下
|
||||
7) 水稻生长 (计时): riceseedlingsb -> c -> d
|
||||
8) 水稻收获 (右键): 成熟水稻 -> 取16大米, 变回刚种下
|
||||
|
||||
【不实现(后续实现)】
|
||||
- 果树"树苗成长"机制(树叶对应树苗, 像原版一样长成树): 后续实现, 本次跳过。
|
||||
|
||||
【计时说明】
|
||||
果树结果/藤蔓生长/水稻生长均 autoStart=True(放置/种下后自动开始),
|
||||
用绝对时间戳写方块实体数据, 退出重进继续计时。
|
||||
================================================================================
|
||||
"""
|
||||
|
||||
# ============================================================================
|
||||
# 一、柴火堆叠/取用(右键)
|
||||
# firewood(柴火_1) + 手持柴火 -> firewood_2(柴火_2 堆放)
|
||||
# firewood_2 空手右键 -> firewood + 给1个柴火
|
||||
# ============================================================================
|
||||
FIREWOOD_RULES = [
|
||||
{"source": "rtdd:firewood", "item": "rtdd:firewood",
|
||||
"target": "rtdd:firewood_2", "consume": 1, "tip": "§a堆放柴火"},
|
||||
{"source": "rtdd:firewood_2", "item": None,
|
||||
"target": "rtdd:firewood", "giveItem": "rtdd:firewood", "tip": "§a取走柴火"},
|
||||
]
|
||||
|
||||
# ============================================================================
|
||||
# 二、葡萄藤取葡萄(右键)
|
||||
# grapebushes_2(成熟) 空手右键 -> grapebushes_1 + 掉落3个葡萄
|
||||
# ============================================================================
|
||||
GRAPE_HARVEST = {
|
||||
"source": "rtdd:grapebushes_2", "item": None,
|
||||
"target": "rtdd:grapebushes_1",
|
||||
"dropItem": [{"name": "rtdd:grape", "count": 3}],
|
||||
"tip": "§a取出了3个葡萄",
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 三、水稻收获(右键)
|
||||
# riceseedlingsd(成熟) 空手右键 -> riceseedlingsb + 掉落16个大米
|
||||
# ============================================================================
|
||||
RICE_HARVEST = {
|
||||
"source": "rtdd:riceseedlingsd", "item": None,
|
||||
"target": "rtdd:riceseedlingsb",
|
||||
"dropItem": [{"name": "rtdd:brownrice", "count": 16}],
|
||||
"tip": "§a收获了16个大米",
|
||||
}
|
||||
|
||||
# 汇总: 乡野自然右键切换规则
|
||||
NATURAL_SWITCHES = FIREWOOD_RULES + [GRAPE_HARVEST, RICE_HARVEST]
|
||||
|
||||
# ============================================================================
|
||||
# 四、计时转换 (果树结果 / 葡萄藤生长 / 水稻生长, 均 autoStart 自动生长)
|
||||
# ============================================================================
|
||||
NATURAL_TIMERS = [
|
||||
# 苹果树: 树叶 -> 苹果形态1 -> 苹果形态2
|
||||
{"source": "rtdd:apple_leaves", "target": "rtdd:apple_fruit_1",
|
||||
"time": 60, "autoStart": True, "doneTip": "§e苹果树结果了"},
|
||||
{"source": "rtdd:apple_fruit_1", "target": "rtdd:apple_fruit_3",
|
||||
"time": 60, "autoStart": True, "doneTip": "§e苹果熟了"},
|
||||
# 桃树: 树叶 -> 桃子一个 -> 桃子两个
|
||||
{"source": "rtdd:peach_leaves", "target": "rtdd:b_173",
|
||||
"time": 60, "autoStart": True, "doneTip": "§e桃树结果了"},
|
||||
{"source": "rtdd:b_173", "target": "rtdd:b_176",
|
||||
"time": 60, "autoStart": True, "doneTip": "§e桃子熟了"},
|
||||
# 橘树: 树叶 -> 橘子形态一 -> 形态二 -> 形态三
|
||||
{"source": "rtdd:orange_leaves", "target": "rtdd:tangerine_0",
|
||||
"time": 60, "autoStart": True, "doneTip": "§e橘树结果了"},
|
||||
{"source": "rtdd:tangerine_0", "target": "rtdd:tangerine_1",
|
||||
"time": 60, "autoStart": True},
|
||||
{"source": "rtdd:tangerine_1", "target": "rtdd:tangerine_2",
|
||||
"time": 60, "autoStart": True, "doneTip": "§e橘子熟了"},
|
||||
# 葡萄藤: 藤_1 -> 藤_2
|
||||
{"source": "rtdd:grapebushes_1", "target": "rtdd:grapebushes_2",
|
||||
"time": 180, "autoStart": True, "doneTip": "§e葡萄熟了"},
|
||||
# 水稻: 刚种下 -> 生长中 -> 成熟
|
||||
{"source": "rtdd:riceseedlingsb", "target": "rtdd:riceseedlingsc",
|
||||
"time": 120, "autoStart": True},
|
||||
{"source": "rtdd:riceseedlingsc", "target": "rtdd:riceseedlingsd",
|
||||
"time": 120, "autoStart": True, "doneTip": "§e水稻成熟了"},
|
||||
]
|
||||
|
||||
# ============================================================================
|
||||
# 五、水稻种植(手持稻谷右键耕地, 在耕地上方放置水稻刚种下)
|
||||
# ============================================================================
|
||||
RICE_PLANT = {
|
||||
"item": "rtdd:rice_seeds", # 稻谷(手持)
|
||||
"surface": "minecraft:farmland", # 必须右键原版耕地
|
||||
"target": "rtdd:riceseedlingsb", # 放置水稻刚种下
|
||||
"consume": 1,
|
||||
"tip": "§a种下水稻",
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
+253
@@ -0,0 +1,253 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
================================================================================
|
||||
乡野自然·右键转换引擎(服务端)
|
||||
================================================================================
|
||||
处理"乡野自然"(xy_natural) 分类下的右键转换 + 水稻种植:
|
||||
柴火堆叠/取用、葡萄藤取葡萄、水稻收获(右键);稻谷右键耕地种植水稻(ItemUseOn)。
|
||||
|
||||
【与计时转换解耦】
|
||||
果树结果/葡萄藤生长/水稻生长的计时拆到 NaturalTimerService(本模块不碰计时)。
|
||||
|
||||
【事件监听在哪?】
|
||||
本类【不】监听任何事件!
|
||||
所有事件由 FeatureDispatcher 统一监听, 按 blockOwner/itemUseOnOwner 路由到本类。
|
||||
|
||||
【本类怎么做】
|
||||
handleBlockUse ← 入口:分发器转发右键方块事件(柴火/葡萄收获/水稻收获)
|
||||
handleItemUseOn ← 入口:分发器转发"手持稻谷右键方块表面"(种植水稻)
|
||||
(通用工具) getCarriedItem / consumeItem / giveItem / replaceBlock /
|
||||
dropItems / checkCooldown
|
||||
================================================================================
|
||||
"""
|
||||
import time
|
||||
import mod.server.extraServerApi as serverApi
|
||||
|
||||
# ---- 网易API基础对象 ----
|
||||
ServerSystem = serverApi.GetServerSystemCls() # 服务端系统基类
|
||||
comp = serverApi.GetEngineCompFactory() # 组件工厂
|
||||
|
||||
# ---- 继承 BlueFox 框架的系统基类(提供 CreateEngineItemEntity 等方法) ----
|
||||
from ....BlueFoxTools.SpecialFunciton.BlueFoxSystem import BlueFoxServerSystem
|
||||
from ....BlueFoxTools.ToolsConfig import LevelId
|
||||
|
||||
# ---- 只导入乡野自然自己的数据库 ----
|
||||
from ..NaturalData import NATURAL_SWITCHES, RICE_PLANT
|
||||
|
||||
# ---- 统一分发器 ----
|
||||
from ...service.FeatureDispatcher import FeatureDispatcher
|
||||
|
||||
|
||||
class NaturalService(BlueFoxServerSystem):
|
||||
"""
|
||||
乡野自然·右键转换引擎
|
||||
"""
|
||||
|
||||
def __init__(self, namespace, systemName):
|
||||
super(NaturalService, self).__init__(namespace, systemName)
|
||||
print "===== NaturalService init ====="
|
||||
|
||||
# ---- 构建右键规则字典 (方块, 物品) -> 规则 ----
|
||||
self.switchRecipes = {}
|
||||
self.featureBlocks = set()
|
||||
for r in NATURAL_SWITCHES:
|
||||
self.switchRecipes[(r["source"], r.get("item"))] = r
|
||||
self.featureBlocks.add(r["source"])
|
||||
|
||||
# ---- 右键冷却表 ----
|
||||
self.cooldown = {}
|
||||
|
||||
# ---- 注册到统一分发器 ----
|
||||
FeatureDispatcher.register(self)
|
||||
|
||||
# ============================================================================
|
||||
# 一、给 FeatureDispatcher 的接口
|
||||
# ============================================================================
|
||||
|
||||
def getFeatureBlocks(self):
|
||||
"""返回本功能管辖的所有右键方块名集合(右键路由用)"""
|
||||
return self.featureBlocks
|
||||
|
||||
def getItemUseOnRules(self):
|
||||
"""返回"手持物品右键方块表面"的规则: 稻谷(rice_seeds) → 种植水稻"""
|
||||
return {RICE_PLANT["item"]: True}
|
||||
|
||||
def handleBlockUse(self, args):
|
||||
"""由 FeatureDispatcher 转发的右键方块入口(柴火/葡萄收获/水稻收获)"""
|
||||
blockName = args.get("blockName")
|
||||
playerId = args.get("playerId")
|
||||
x, y, z = args.get("x"), args.get("y"), args.get("z")
|
||||
pos = (x, y, z)
|
||||
dim = comp.CreateDimension(playerId).GetEntityDimensionId()
|
||||
key = (dim, x, y, z)
|
||||
|
||||
itemDict = self.getCarriedItem(playerId)
|
||||
itemName = itemDict.get("newItemName") if itemDict else None
|
||||
|
||||
recipe = self.findRecipe(blockName, itemDict)
|
||||
if not recipe:
|
||||
return False
|
||||
if not self.checkCooldown(key, 0.5):
|
||||
return True
|
||||
self.handleSwitch(recipe, playerId, pos, dim, itemDict, key)
|
||||
return True
|
||||
|
||||
def handleItemUseOn(self, args):
|
||||
"""由 FeatureDispatcher 转发的"手持物品右键方块表面"入口(稻谷种水稻)"""
|
||||
itemName = args.get("itemName")
|
||||
playerId = args.get("playerId") or args.get("entityId")
|
||||
x, y, z = args.get("x"), args.get("y"), args.get("z")
|
||||
dim = comp.CreateDimension(playerId).GetEntityDimensionId()
|
||||
|
||||
if itemName != RICE_PLANT["item"]:
|
||||
return False
|
||||
|
||||
# 被点方块必须是原版耕地
|
||||
try:
|
||||
cur = comp.CreateBlockInfo(LevelId).GetBlockNew((x, y, z), dim)
|
||||
if not cur or cur.get("name") != RICE_PLANT["surface"]:
|
||||
return False
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
# 目标格 = 耕地上方一格
|
||||
targetPos = (x, y + 1, z)
|
||||
try:
|
||||
cur = comp.CreateBlockInfo(LevelId).GetBlockNew(targetPos, dim)
|
||||
if cur and cur.get("name") != "minecraft:air":
|
||||
return False
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
# 连点冷却
|
||||
key = (dim, targetPos[0], targetPos[1], targetPos[2])
|
||||
if not self.checkCooldown(key, 0.5):
|
||||
return True
|
||||
|
||||
# 消耗稻谷
|
||||
itemDict = self.getCarriedItem(playerId)
|
||||
if not itemDict:
|
||||
return False
|
||||
self.consumeItem(playerId, itemDict, RICE_PLANT.get("consume", 1))
|
||||
|
||||
# 放置水稻刚种下
|
||||
self.replaceBlock(targetPos, dim, RICE_PLANT["target"], playerId)
|
||||
if RICE_PLANT.get("tip"):
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(playerId, RICE_PLANT["tip"])
|
||||
return True
|
||||
|
||||
# ============================================================================
|
||||
# 二、规则匹配(精确 + 空手 fallback)
|
||||
# ============================================================================
|
||||
|
||||
def findRecipe(self, blockName, itemDict):
|
||||
itemName = itemDict.get("newItemName") if itemDict else None
|
||||
recipe = self.switchRecipes.get((blockName, itemName))
|
||||
if recipe:
|
||||
return recipe
|
||||
if not itemName or itemName == "minecraft:air":
|
||||
return self.switchRecipes.get((blockName, None))
|
||||
return None
|
||||
|
||||
# ============================================================================
|
||||
# 三、右键规则执行
|
||||
# ============================================================================
|
||||
|
||||
def handleSwitch(self, recipe, playerId, pos, dim, itemDict, key):
|
||||
# 消耗物品
|
||||
if recipe.get("item") is not None and recipe.get("consume", 0) > 0:
|
||||
self.consumeItem(playerId, itemDict, recipe.get("consume", 1))
|
||||
# 替换方块
|
||||
if recipe.get("target"):
|
||||
self.replaceBlock(pos, dim, recipe["target"], playerId)
|
||||
# 掉落物
|
||||
if recipe.get("dropItem"):
|
||||
self.dropItems(dim, pos, recipe["dropItem"])
|
||||
# 给背包物品
|
||||
if recipe.get("giveItem"):
|
||||
self.giveItem(playerId, recipe["giveItem"])
|
||||
# 提示
|
||||
if recipe.get("tip"):
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(playerId, recipe["tip"])
|
||||
|
||||
# ============================================================================
|
||||
# 四、工具方法:获取玩家主手物品
|
||||
# ============================================================================
|
||||
|
||||
def getCarriedItem(self, playerId):
|
||||
itemComp = comp.CreateItem(playerId)
|
||||
return itemComp.GetPlayerItem(
|
||||
serverApi.GetMinecraftEnum().ItemPosType.CARRIED, 0, True)
|
||||
|
||||
# ============================================================================
|
||||
# 五、工具方法:给玩家物品
|
||||
# ============================================================================
|
||||
|
||||
def giveItem(self, playerId, itemName, count=1, aux=0):
|
||||
try:
|
||||
itemDict = {"itemName": itemName, "count": count, "auxValue": aux}
|
||||
comp.CreateItem(playerId).SpawnItemToPlayerInv(itemDict, playerId)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ============================================================================
|
||||
# 六、工具方法:消耗物品
|
||||
# ============================================================================
|
||||
|
||||
def consumeItem(self, playerId, itemDict, amount=1):
|
||||
if itemDict is None:
|
||||
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:
|
||||
itemDict["count"] = count - amount
|
||||
comp.CreateItem(playerId).SetEntityItem(
|
||||
serverApi.GetMinecraftEnum().ItemPosType.CARRIED,
|
||||
{"itemName": itemDict["newItemName"],
|
||||
"count": itemDict["count"],
|
||||
"auxValue": itemDict.get("newAuxValue", 0),
|
||||
"userData": itemDict.get("userData", {})})
|
||||
|
||||
# ============================================================================
|
||||
# 七、工具方法:替换方块
|
||||
# ============================================================================
|
||||
|
||||
def replaceBlock(self, pos, dim, newBlockName, playerId=None):
|
||||
creator = playerId if playerId is not None else LevelId
|
||||
aux = 0
|
||||
try:
|
||||
oldBlock = comp.CreateBlockInfo(creator).GetBlockNew(pos, dim)
|
||||
aux = oldBlock.get("aux", 0)
|
||||
except Exception:
|
||||
aux = 0
|
||||
comp.CreateBlockInfo(creator).SetBlockNew(
|
||||
pos, blockDict={"name": newBlockName, "aux": aux},
|
||||
oldBlockHandling=0, dimensionId=dim)
|
||||
|
||||
# ============================================================================
|
||||
# 八、工具方法:以掉落物形式生成物品
|
||||
# ============================================================================
|
||||
|
||||
def dropItems(self, dim, pos, dropList):
|
||||
for d in dropList:
|
||||
itemDict = {
|
||||
"itemName": d["name"],
|
||||
"count": d.get("count", 1),
|
||||
"auxValue": d.get("aux", 0),
|
||||
}
|
||||
self.CreateEngineItemEntity(itemDict, dim, (pos[0], pos[1] + 0.5, pos[2]))
|
||||
|
||||
# ============================================================================
|
||||
# 九、工具方法:冷却检查
|
||||
# ============================================================================
|
||||
|
||||
def checkCooldown(self, key, cd=0.5):
|
||||
now = time.time()
|
||||
last = self.cooldown.get(key, 0)
|
||||
if now - last < cd:
|
||||
return False
|
||||
self.cooldown[key] = now
|
||||
return True
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
================================================================================
|
||||
乡野自然·计时转换引擎(服务端)
|
||||
================================================================================
|
||||
只处理"乡野自然"(xy_natural) 分类下的【计时自动转换】:
|
||||
果树结果(苹果/桃/橘 树叶->果实)、葡萄藤生长、水稻生长。
|
||||
全部 autoStart=True:方块放置/种下后自动开始计时(自动生长)。
|
||||
|
||||
【与右键转换解耦】
|
||||
柴火堆叠/取用、葡萄收获、水稻收获、种植 在 NaturalService。
|
||||
本类只负责计时,由 FeatureDispatcher 按 timerOwner 路由。
|
||||
|
||||
【计时怎么做到"退出游戏继续计时"】
|
||||
不做倒计时,只记"开始时刻":
|
||||
- 启动时把 开始时间戳(rtdd_tstart)+总时长(rtdd_tdur) 写进方块实体数据
|
||||
- 每帧 tick 判断 当前时间-开始时刻 >= 总时长 -> 到点转换
|
||||
- 时间戳是绝对时间(time.time()), 重启/离线真实时间仍在流逝, 剩余时间自然准确
|
||||
|
||||
【事件监听在哪?】
|
||||
本类【不】监听任何事件!
|
||||
ServerBlockEntityTickEvent 由 FeatureDispatcher 统一监听, 再按 timerOwner 路由。
|
||||
================================================================================
|
||||
"""
|
||||
import time
|
||||
import mod.server.extraServerApi as serverApi
|
||||
|
||||
# ---- 网易API基础对象 ----
|
||||
ServerSystem = serverApi.GetServerSystemCls() # 服务端系统基类
|
||||
comp = serverApi.GetEngineCompFactory() # 组件工厂
|
||||
|
||||
# ---- 继承 BlueFox 框架的系统基类 ----
|
||||
from ....BlueFoxTools.SpecialFunciton.BlueFoxSystem import BlueFoxServerSystem
|
||||
from ....BlueFoxTools.ToolsConfig import LevelId
|
||||
|
||||
# ---- 方块实体数据组件(计时持久化) ----
|
||||
blockEntityDataComp = comp.CreateBlockEntityData(LevelId)
|
||||
|
||||
# ---- 只导入乡野自然自己的数据库 ----
|
||||
from ..NaturalData import NATURAL_TIMERS
|
||||
|
||||
# ---- 统一分发器 ----
|
||||
from ...service.FeatureDispatcher import FeatureDispatcher
|
||||
|
||||
|
||||
class NaturalTimerService(BlueFoxServerSystem):
|
||||
"""
|
||||
乡野自然·计时转换引擎
|
||||
"""
|
||||
|
||||
def __init__(self, namespace, systemName):
|
||||
super(NaturalTimerService, self).__init__(namespace, systemName)
|
||||
print "===== NaturalTimerService init ====="
|
||||
|
||||
# ---- 收集计时型规则(source -> 规则) ----
|
||||
self.naturalTimers = {t["source"]: t for t in NATURAL_TIMERS}
|
||||
|
||||
# ---- 注册到分发器的计时路由表 ----
|
||||
FeatureDispatcher.registerTimer(self)
|
||||
|
||||
# ============================================================================
|
||||
# 一、给 FeatureDispatcher 的接口
|
||||
# ============================================================================
|
||||
|
||||
def getTimerBlocks(self):
|
||||
"""返回本功能的所有"计时源方块"集合(tick 路由用)"""
|
||||
return set(self.naturalTimers.keys())
|
||||
|
||||
def handleBlockEntityTick(self, args):
|
||||
"""由 FeatureDispatcher 转发的计时方块 tick 入口"""
|
||||
dim = args.get("dimension")
|
||||
pos = (args.get("posX"), args.get("posY"), args.get("posZ"))
|
||||
blockName = args.get("blockName", "")
|
||||
self._tickProcess(dim, pos, blockName)
|
||||
|
||||
# ============================================================================
|
||||
# 二、启动计时(果树/藤蔓/水稻 autoStart, 保留接口)
|
||||
# ============================================================================
|
||||
|
||||
def startTimer(self, dim, pos, blockName, playerId=None):
|
||||
recipe = self.naturalTimers.get(blockName)
|
||||
if not recipe:
|
||||
return False
|
||||
try:
|
||||
data = blockEntityDataComp.GetBlockEntityData(dim, pos)
|
||||
if data and data["rtdd_tid"] == blockName:
|
||||
return False
|
||||
except Exception:
|
||||
pass
|
||||
self._writeTimerData(dim, pos, recipe, playerId)
|
||||
return True
|
||||
|
||||
# ============================================================================
|
||||
# 三、tick 检查与到点转换
|
||||
# ============================================================================
|
||||
|
||||
def _tickProcess(self, dim, pos, blockName):
|
||||
try:
|
||||
recipe = self.naturalTimers.get(blockName)
|
||||
if not recipe:
|
||||
return
|
||||
|
||||
blockData = blockEntityDataComp.GetBlockEntityData(dim, pos)
|
||||
if blockData is None:
|
||||
return
|
||||
|
||||
try:
|
||||
tid = blockData["rtdd_tid"]
|
||||
except Exception:
|
||||
tid = ""
|
||||
if tid != blockName:
|
||||
# autoStart=True: 计时源方块无计时数据时自动启动(自动生长)
|
||||
if recipe.get("autoStart", True):
|
||||
self._writeTimerData(dim, pos, recipe, None)
|
||||
return
|
||||
|
||||
tstart = blockData["rtdd_tstart"]
|
||||
tdur = blockData["rtdd_tdur"]
|
||||
|
||||
if time.time() - tstart >= tdur:
|
||||
self._finishTimer(dim, pos, recipe, blockData)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _finishTimer(self, dim, pos, recipe, data):
|
||||
try:
|
||||
cur = comp.CreateBlockInfo(LevelId).GetBlockNew(pos, dim)
|
||||
if cur and cur.get("name") != recipe["source"]:
|
||||
self._clearTimerData(dim, pos)
|
||||
return
|
||||
self.replaceBlock(pos, dim, recipe["target"], None)
|
||||
self._clearTimerData(dim, pos)
|
||||
if recipe.get("doneTip"):
|
||||
self._notifyIfOnline(data["rtdd_tp"], recipe["doneTip"])
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ============================================================================
|
||||
# 四、计时数据读写(存在方块实体数据里,重启不丢)
|
||||
# ============================================================================
|
||||
|
||||
def _writeTimerData(self, dim, pos, recipe, playerId=None):
|
||||
try:
|
||||
blockData = blockEntityDataComp.GetBlockEntityData(dim, pos)
|
||||
if blockData is None:
|
||||
return
|
||||
now = time.time()
|
||||
blockData["rtdd_tid"] = recipe["source"]
|
||||
blockData["rtdd_tstart"] = now
|
||||
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
|
||||
|
||||
# ============================================================================
|
||||
# 六、工具方法:替换方块
|
||||
# ============================================================================
|
||||
|
||||
def replaceBlock(self, pos, dim, newBlockName, playerId=None):
|
||||
creator = playerId if playerId is not None else LevelId
|
||||
aux = 0
|
||||
try:
|
||||
oldBlock = comp.CreateBlockInfo(creator).GetBlockNew(pos, dim)
|
||||
aux = oldBlock.get("aux", 0)
|
||||
except Exception:
|
||||
aux = 0
|
||||
comp.CreateBlockInfo(creator).SetBlockNew(
|
||||
pos, blockDict={"name": newBlockName, "aux": aux},
|
||||
oldBlockHandling=0, dimensionId=dim)
|
||||
@@ -0,0 +1 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"format_version": "1.12",
|
||||
"minecraft:recipe_shapeless": {
|
||||
"ingredients": [
|
||||
{
|
||||
"item": "rtdd:firewood",
|
||||
"data": 0
|
||||
}
|
||||
],
|
||||
"description": {
|
||||
"identifier": "rtdd:xy_firewood_plank"
|
||||
},
|
||||
"result": {
|
||||
"data": 0,
|
||||
"item": "rtdd:b_15",
|
||||
"count": 9
|
||||
},
|
||||
"tags": [
|
||||
"crafting_table"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user