市场贸易实现 bug修复
This commit is contained in:
1 parent
1f329f8b4c
commit
cae9bcb19e
25 files changed
+1300
-187
No files matched your search
@@ -9,6 +9,8 @@ from xiangyemod.shaokao.service.BarbecueTimerService import BarbecueTimerService
|
||||
from xiangyemod.siwangshengwu.service.DeadmobService import DeadmobService
|
||||
from xiangyemod.siwangshengwu.service.DeadmobTimerService import DeadmobTimerService
|
||||
from xiangyemod.shouban.service.ShoubanService import ShoubanService
|
||||
from xiangyemod.shichangmaoyi.service.MarketService import MarketService
|
||||
from xiangyemod.yuanbanfangzhi.service.YuanbanService import YuanbanService
|
||||
|
||||
if not serverApi.IsInServer():
|
||||
pass
|
||||
|
||||
@@ -75,35 +75,10 @@ BLOCK_SWITCHES = [
|
||||
},
|
||||
|
||||
|
||||
# 三、售卖箱 ↔ 鲑鱼箱
|
||||
# 三、售卖盒(鲑鱼)
|
||||
# ============================================================
|
||||
# 【放鲑鱼】售卖箱_1 → 鲑鱼箱
|
||||
{
|
||||
"source": "rtdd:clothbox_1",
|
||||
"item": "minecraft:salmon",
|
||||
"target": "rtdd:b_30",
|
||||
"consume": 1,
|
||||
"type": "switch",
|
||||
"giveItem": None,
|
||||
},
|
||||
# 【放鲑鱼】售卖箱_2 → 鲑鱼箱
|
||||
{
|
||||
"source": "rtdd:clothbox_2",
|
||||
"item": "minecraft:salmon",
|
||||
"target": "rtdd:b_30",
|
||||
"consume": 1,
|
||||
"type": "switch",
|
||||
"giveItem": None,
|
||||
},
|
||||
# 【取回鲑鱼】鲑鱼箱 → 售卖箱_2
|
||||
{
|
||||
"source": "rtdd:b_30",
|
||||
"item": None,
|
||||
"target": "rtdd:clothbox_2",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"giveItem": "minecraft:salmon",
|
||||
},
|
||||
# 旧"售卖箱↔鲑鱼箱"规则已移除: clothbox_1/2 已禁用, b_30(售卖盒(鲑鱼))
|
||||
# 归 市场贸易 MarketService 处理(空售卖盒+32条鲑鱼放入 / 空手右键取出)。
|
||||
|
||||
|
||||
# 四、烧烤架
|
||||
|
||||
+65
-3
@@ -64,6 +64,14 @@ class FeatureDispatcher(BlueFoxServerSystem):
|
||||
timerOwner = {}
|
||||
timerSet = set()
|
||||
|
||||
# ---- 拆方块掉落映射: 方块名 → 掉落对应的原版生食材 ----
|
||||
# 玩家左键破坏这些"放置的半成品/死鱼"方块时, 取消默认掉落, 改为掉对应的原版生食材
|
||||
DESTROY_DROP = {
|
||||
"rtdd:killfish_0": "minecraft:salmon", # 死鲑鱼 → 原版生鲑鱼
|
||||
"rtdd:killcod_0": "minecraft:cod", # 死鳕鱼 → 原版生鳕鱼
|
||||
"rtdd:roastchickenplace_0": "minecraft:chicken", # 生鸡肉(放置后) → 原版生鸡肉
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# 注册接口(功能服务在 __init__ 里调用)
|
||||
# ============================================================================
|
||||
@@ -128,11 +136,12 @@ class FeatureDispatcher(BlueFoxServerSystem):
|
||||
|
||||
def ListenEvent(self):
|
||||
"""
|
||||
注册四个事件:
|
||||
注册五个事件:
|
||||
1. ServerBlockUseEvent —— 玩家右键方块(所有功能的右键转换入口)
|
||||
2. ServerItemUseOnEvent —— 手持物品右键方块表面(如放置生鸡肉)
|
||||
3. ServerItemTryUseEvent —— 玩家尝试使用物品(拦截喝药水/吃食物等默认行为)
|
||||
4. ServerBlockEntityTickEvent —— 计时方块每tick触发(烤制/饲料变空等,持久化计时)
|
||||
5. ServerPlayerTryDestroyBlockEvent —— 玩家拆方块(放置的死鱼/生鸡肉掉回原版生食材)
|
||||
"""
|
||||
self.ListenForEvent(serverApi.GetEngineNamespace(),
|
||||
serverApi.GetEngineSystemName(),
|
||||
@@ -146,6 +155,9 @@ class FeatureDispatcher(BlueFoxServerSystem):
|
||||
self.ListenForEvent(serverApi.GetEngineNamespace(),
|
||||
serverApi.GetEngineSystemName(),
|
||||
"ServerBlockEntityTickEvent", self, self.OnBlockEntityTick)
|
||||
self.ListenForEvent(serverApi.GetEngineNamespace(),
|
||||
serverApi.GetEngineSystemName(),
|
||||
"ServerPlayerTryDestroyBlockEvent", self, self.OnDestroy)
|
||||
|
||||
def UnListenEvent(self):
|
||||
self.UnListenForEvent(serverApi.GetEngineNamespace(),
|
||||
@@ -160,6 +172,9 @@ class FeatureDispatcher(BlueFoxServerSystem):
|
||||
self.UnListenForEvent(serverApi.GetEngineNamespace(),
|
||||
serverApi.GetEngineSystemName(),
|
||||
"ServerBlockEntityTickEvent", self, self.OnBlockEntityTick)
|
||||
self.UnListenForEvent(serverApi.GetEngineNamespace(),
|
||||
serverApi.GetEngineSystemName(),
|
||||
"ServerPlayerTryDestroyBlockEvent", self, self.OnDestroy)
|
||||
|
||||
# ============================================================================
|
||||
# 主入口1:玩家右键方块 → 按 blockOwner 路由到右键服务
|
||||
@@ -204,11 +219,22 @@ class FeatureDispatcher(BlueFoxServerSystem):
|
||||
if not service:
|
||||
return
|
||||
|
||||
# 被点方块属于某个"右键方块"服务的管辖(条箱/挂肉钩/锅具等) → 该方块右键由
|
||||
# ServerBlockUseEvent 处理(放入/挂鱼/做菜), 不执行"手持物品右键表面放置",
|
||||
# 避免与方块右键逻辑重复(如手持鲑鱼右键条箱应放入而非放置死鲑鱼)。
|
||||
playerId = args.get("playerId") or args.get("entityId")
|
||||
try:
|
||||
dim = comp.CreateDimension(playerId).GetEntityDimensionId()
|
||||
b = comp.CreateBlockInfo(LevelId).GetBlockNew(
|
||||
(args.get("x"), args.get("y"), args.get("z")), dim)
|
||||
if b and b.get("name") in self.blockOwner:
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
handled = service.handleItemUseOn(args)
|
||||
if handled:
|
||||
args['ret'] = True
|
||||
# ServerItemUseOnEvent 的玩家键是 entityId,不是 playerId
|
||||
playerId = args.get("playerId") or args.get("entityId")
|
||||
self._cancelItemUse[playerId] = True
|
||||
|
||||
# ============================================================================
|
||||
@@ -253,3 +279,39 @@ class FeatureDispatcher(BlueFoxServerSystem):
|
||||
if not service:
|
||||
return
|
||||
service.handleBlockEntityTick(args)
|
||||
|
||||
# ============================================================================
|
||||
# 主入口5:玩家拆方块 → 放置的死鱼/生鸡肉掉回原版生食材
|
||||
# ============================================================================
|
||||
|
||||
def OnDestroy(self, args):
|
||||
"""
|
||||
玩家拆方块时触发。
|
||||
部分"放置的半成品/死鱼"方块被拆掉时, 取消默认掉落(不把方块本身掉出来),
|
||||
手动清空方块并掉落对应的原版生食材:
|
||||
- killfish_0(死鲑鱼) → 原版生鲑鱼
|
||||
- killcod_0(死鳕鱼) → 原版生鳕鱼
|
||||
- roastchickenplace_0(生鸡肉放置后) → 原版生鸡肉
|
||||
"""
|
||||
blockName = args.get("blockName")
|
||||
itemName = self.DESTROY_DROP.get(blockName)
|
||||
if not itemName:
|
||||
return
|
||||
playerId = args.get("playerId")
|
||||
x, y, z = args.get("x"), args.get("y"), args.get("z")
|
||||
dim = comp.CreateDimension(playerId).GetEntityDimensionId()
|
||||
# 取消默认破坏(不让方块本身作为掉落物掉出来)
|
||||
args['cancel'] = True
|
||||
# 手动清空方块
|
||||
try:
|
||||
comp.CreateBlockInfo(LevelId).SetBlockNew(
|
||||
(x, y, z), blockDict={"name": "minecraft:air", "aux": 0},
|
||||
oldBlockHandling=0, dimensionId=dim)
|
||||
except Exception:
|
||||
pass
|
||||
# 掉落对应的原版生食材
|
||||
try:
|
||||
itemDict = {"itemName": itemName, "count": 1, "auxValue": 0}
|
||||
self.CreateEngineItemEntity(itemDict, dim, (x, y + 0.5, z))
|
||||
except Exception:
|
||||
pass
|
||||
+3
-11
@@ -311,14 +311,6 @@ BARBECUE_SWITCHES = [
|
||||
# ============================================================
|
||||
# 六、手持物品右键"方块表面"生成规则(ServerItemUseOnEvent)
|
||||
# ============================================================
|
||||
# 目前只有一条:手持"原版生鸡肉"右键任意方块表面 → 在其表面生成
|
||||
# "生鸡肉(原版生鸡肉右键放置后)"(roastchickenplace_0) 方块,消耗1个。
|
||||
# 该规则由 FeatureDispatcher 转发 ServerItemUseOnEvent 到 BarbecueService。
|
||||
ITEM_USE_ON_RULES = [
|
||||
{
|
||||
"item": "minecraft:chicken", # 手持的原版生鸡肉
|
||||
"target": "rtdd:roastchickenplace_0", # 生成的目标方块
|
||||
"consume": 1, # 消耗1个生鸡肉
|
||||
"tip": "§a已放置生鸡肉,可右键支杆上杆烤制",
|
||||
},
|
||||
]
|
||||
# 原版生鸡肉右键放置"生鸡肉(放置后)"的规则已拆到
|
||||
# xiangyemod/yuanbanfangzhi/YuanbanData.py(原版放置统一管理)。
|
||||
# 本分类不再定义 ItemUseOn 规则。
|
||||
+10
-65
@@ -17,14 +17,13 @@
|
||||
【事件监听在哪?】
|
||||
本类【不】监听任何事件!
|
||||
所有事件由 FeatureDispatcher(xiangyemod/service/FeatureDispatcher.py)统一监听:
|
||||
- ServerBlockUseEvent → OnBlockUse → 按 blockOwner 路由到本类 handleBlockUse
|
||||
- ServerItemUseOnEvent → OnItemUseOn → 按 itemUseOnOwner 路由到本类 handleItemUseOn
|
||||
- ServerBlockUseEvent → OnBlockUse → 按 blockOwner 路由到本类 handleBlockUse
|
||||
- ServerBlockEntityTickEvent → OnBlockEntityTick → 按 timerOwner 路由到 BarbecueTimerService
|
||||
本类只实现被分发器调用的接口方法,不关心事件来源。
|
||||
注: 原版生鸡肉右键放置"生鸡肉(放置后)"已拆到 yuanbanfangzhi/YuanbanService。
|
||||
|
||||
【本类怎么做(自上而下的方法系列)】
|
||||
handleBlockUse ← 入口1:分发器转发右键方块事件
|
||||
handleItemUseOn ← 入口2:分发器转发"手持物品右键方块表面"事件(放置生鸡肉)
|
||||
handleBlockUse ← 入口:分发器转发右键方块事件
|
||||
├─ findRecipe ← 匹配 (方块名, 物品名) 规则
|
||||
├─ checkCooldown ← 连点冷却(防刷提示)
|
||||
├─ forwardStartTimer ← 计时源方块 → 转发给计时服务启动烤制
|
||||
@@ -48,21 +47,11 @@ from ....BlueFoxTools.SpecialFunciton.BlueFoxSystem import BlueFoxServerSystem
|
||||
from ....BlueFoxTools.ToolsConfig import LevelId
|
||||
|
||||
# ---- 只导入烧烤自己的数据库 ----
|
||||
from ..BarbecueData import BARBECUE_SWITCHES, ITEM_USE_ON_RULES
|
||||
from ..BarbecueData import BARBECUE_SWITCHES
|
||||
|
||||
# ---- 统一分发器 ----
|
||||
from ...service.FeatureDispatcher import FeatureDispatcher
|
||||
|
||||
# ---- 方块表面方向 → 相邻坐标偏移(0下 1上 2北 3南 4西 5东) ----
|
||||
FACE_OFFSET = {
|
||||
0: (0, -1, 0),
|
||||
1: (0, 1, 0),
|
||||
2: (0, 0, -1),
|
||||
3: (0, 0, 1),
|
||||
4: (-1, 0, 0),
|
||||
5: (1, 0, 0),
|
||||
}
|
||||
|
||||
|
||||
class BarbecueService(BlueFoxServerSystem):
|
||||
"""
|
||||
@@ -71,8 +60,11 @@ class BarbecueService(BlueFoxServerSystem):
|
||||
【核心数据结构】
|
||||
barbecueRecipes = {(方块名, 物品名): 规则dict} # O(1) 查找,含 switch+timer 规则
|
||||
barbecueBlockSet = {方块名, ...} # O(1) 拦截/注册用(所有源方块)
|
||||
itemUseOnRecipes = {物品名: 规则dict} # 手持物品右键方块表面 → 生成规则
|
||||
cooldown = {key: 时间戳} # 连点冷却表
|
||||
|
||||
【原版放置已拆出】
|
||||
手持原版生鸡肉右键方块表面放置"生鸡肉(放置后)"的 ItemUseOn 逻辑
|
||||
已拆到 xiangyemod/yuanbanfangzhi/YuanbanService。
|
||||
"""
|
||||
|
||||
def __init__(self, namespace, systemName):
|
||||
@@ -91,11 +83,6 @@ class BarbecueService(BlueFoxServerSystem):
|
||||
self.barbecueRecipes[key] = sw
|
||||
self.barbecueBlockSet.add(sw["source"])
|
||||
|
||||
# ---- 手持物品右键方块表面规则:物品名 → 规则 ----
|
||||
self.itemUseOnRecipes = {}
|
||||
for rule in ITEM_USE_ON_RULES:
|
||||
self.itemUseOnRecipes[rule["item"]] = rule
|
||||
|
||||
# ---- 右键冷却表 ----
|
||||
self.cooldown = {}
|
||||
|
||||
@@ -111,8 +98,8 @@ class BarbecueService(BlueFoxServerSystem):
|
||||
return self.barbecueBlockSet
|
||||
|
||||
def getItemUseOnRules(self):
|
||||
"""返回手持物品右键方块表面的规则:{物品名: 规则dict}(供分发器路由)"""
|
||||
return self.itemUseOnRecipes
|
||||
"""返回"手持物品右键方块表面"的规则(原版放置已拆到 yuanbanfangzhi, 返回空)"""
|
||||
return {}
|
||||
|
||||
def handleBlockUse(self, args):
|
||||
"""
|
||||
@@ -153,48 +140,6 @@ class BarbecueService(BlueFoxServerSystem):
|
||||
self.handleSwitch(recipe, playerId, pos, dim, itemDict, key)
|
||||
return True
|
||||
|
||||
def handleItemUseOn(self, args):
|
||||
"""
|
||||
由 FeatureDispatcher 转发的"手持物品右键方块表面"事件。
|
||||
当前用于:手持原版生鸡肉右键任意方块表面 → 在其表面生成生鸡肉(放置后)方块。
|
||||
返回 True=已处理,False=当前组合无匹配规则。
|
||||
"""
|
||||
itemName = args.get("itemName")
|
||||
# ServerItemUseOnEvent 的玩家键是 entityId,不是 playerId
|
||||
playerId = args.get("playerId") or args.get("entityId")
|
||||
rule = self.itemUseOnRecipes.get(itemName)
|
||||
if not rule:
|
||||
return False
|
||||
|
||||
x, y, z = args.get("x"), args.get("y"), args.get("z")
|
||||
face = args.get("face", 1)
|
||||
dim = comp.CreateDimension(playerId).GetEntityDimensionId()
|
||||
|
||||
# 计算被点方块表面相邻的目标格
|
||||
off = FACE_OFFSET.get(face, (0, 1, 0))
|
||||
targetPos = (x + off[0], y + off[1], z + off[2])
|
||||
|
||||
# 目标格必须为空(可放置)
|
||||
try:
|
||||
cur = comp.CreateBlockInfo(LevelId).GetBlockNew(targetPos, dim)
|
||||
if cur and cur.get("name") != "minecraft:air":
|
||||
return False
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
# 消耗 1 个生鸡肉
|
||||
itemDict = self.getCarriedItem(playerId)
|
||||
if not itemDict:
|
||||
return False
|
||||
self.consumeItem(playerId, itemDict, rule.get("consume", 1))
|
||||
|
||||
# 生成生鸡肉(放置后)方块
|
||||
self.replaceBlock(targetPos, dim, rule["target"], playerId)
|
||||
# 放置成功提示
|
||||
if rule.get("tip"):
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(playerId, rule["tip"])
|
||||
return True
|
||||
|
||||
# ============================================================================
|
||||
# 二、规则匹配(O(1) 字典查找)
|
||||
# ============================================================================
|
||||
|
||||
+534
@@ -0,0 +1,534 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
================================================================================
|
||||
市场贸易分类转换规则数据
|
||||
================================================================================
|
||||
只处理"市场贸易"(xy_market) 分类下的右键转换:
|
||||
1) 条箱/货桶/售卖盒 放入: 手持对应物品右键 空容器 → 消耗物品 → 变为对应容器
|
||||
2) 条箱/货桶/售卖盒 取出: 空手右键 装满容器 → 变回空容器 + 以掉落物形式取回物品
|
||||
3) 悬赏纸循环: 空手右键逐级切换 bountypaper → _1 → _2 → bountypaper
|
||||
其余摊位设施(b_4/menus/vending_desk)为静态, 无转换。
|
||||
布料(clothbox_1/2)已按标注禁用, 不参与本分类转换。
|
||||
|
||||
【消耗数量】
|
||||
除 南瓜/西瓜 消耗1个原版方块(minecraft:pumpkin / minecraft:melon_block)外,
|
||||
其余均消耗32个对应物品; 取出时按放入数量取回(南瓜/西瓜取回1个方块)。
|
||||
|
||||
字段说明(与 AnimalData/DeadmobData 一致):
|
||||
source: 被右键的方块ID(必填)
|
||||
item: 玩家手里必须拿的物品, None=空手
|
||||
target: 替换成什么方块
|
||||
consume: 消耗物品数量, 0=不消耗
|
||||
dropItem: 转换时以掉落物形式生成的物品列表(取出用)
|
||||
tip: 转换成功提示
|
||||
================================================================================
|
||||
"""
|
||||
|
||||
MARKET_SWITCHES = [
|
||||
|
||||
# ============================================================
|
||||
# 一、条箱 (woodenbox_0空 → woodenbox_1~7 各装一种)
|
||||
# ============================================================
|
||||
# ---- 放入 (手持物品右键 空条箱) ----
|
||||
{
|
||||
"source": "rtdd:woodenbox_0",
|
||||
"item": "minecraft:apple",
|
||||
"target": "rtdd:woodenbox_1",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32个苹果",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:woodenbox_0",
|
||||
"item": "minecraft:carrot",
|
||||
"target": "rtdd:woodenbox_2",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32个胡萝卜",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:woodenbox_0",
|
||||
"item": "minecraft:potato",
|
||||
"target": "rtdd:woodenbox_3",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32个土豆",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:woodenbox_0",
|
||||
"item": "rtdd:peach",
|
||||
"target": "rtdd:woodenbox_4",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32个桃子",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:woodenbox_0",
|
||||
"item": "rtdd:orange",
|
||||
"target": "rtdd:woodenbox_5",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32个橘子",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:woodenbox_0",
|
||||
"item": "minecraft:cod",
|
||||
"target": "rtdd:woodenbox_6",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32条鳕鱼",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:woodenbox_0",
|
||||
"item": "minecraft:salmon",
|
||||
"target": "rtdd:woodenbox_7",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32条鲑鱼",
|
||||
"giveItem": None,
|
||||
},
|
||||
# ---- 取出 (空手右键 装满的条箱) ----
|
||||
{
|
||||
"source": "rtdd:woodenbox_1",
|
||||
"item": None,
|
||||
"target": "rtdd:woodenbox_0",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "minecraft:apple", "count": 32}],
|
||||
"tip": "§a取出了32个苹果",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:woodenbox_2",
|
||||
"item": None,
|
||||
"target": "rtdd:woodenbox_0",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "minecraft:carrot", "count": 32}],
|
||||
"tip": "§a取出了32个胡萝卜",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:woodenbox_3",
|
||||
"item": None,
|
||||
"target": "rtdd:woodenbox_0",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "minecraft:potato", "count": 32}],
|
||||
"tip": "§a取出了32个土豆",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:woodenbox_4",
|
||||
"item": None,
|
||||
"target": "rtdd:woodenbox_0",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "rtdd:peach", "count": 32}],
|
||||
"tip": "§a取出了32个桃子",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:woodenbox_5",
|
||||
"item": None,
|
||||
"target": "rtdd:woodenbox_0",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "rtdd:orange", "count": 32}],
|
||||
"tip": "§a取出了32个橘子",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:woodenbox_6",
|
||||
"item": None,
|
||||
"target": "rtdd:woodenbox_0",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "minecraft:cod", "count": 32}],
|
||||
"tip": "§a取出了32条鳕鱼",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:woodenbox_7",
|
||||
"item": None,
|
||||
"target": "rtdd:woodenbox_0",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "minecraft:salmon", "count": 32}],
|
||||
"tip": "§a取出了32条鲑鱼",
|
||||
"giveItem": None,
|
||||
},
|
||||
|
||||
# ============================================================
|
||||
# 二、货桶 (fishbucket_0空 → 各装一种)
|
||||
# ============================================================
|
||||
# ---- 放入 ----
|
||||
{
|
||||
"source": "rtdd:fishbucket_0",
|
||||
"item": "minecraft:cod",
|
||||
"target": "rtdd:fishbucket_1",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32条鳕鱼",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:fishbucket_0",
|
||||
"item": "minecraft:salmon",
|
||||
"target": "rtdd:fishbucket_2",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32条鲑鱼",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:fishbucket_0",
|
||||
"item": "minecraft:carrot",
|
||||
"target": "rtdd:carrotbarrel",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32个胡萝卜",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:fishbucket_0",
|
||||
"item": "minecraft:potato",
|
||||
"target": "rtdd:potatobarrel",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32个土豆",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:fishbucket_0",
|
||||
"item": "rtdd:peach",
|
||||
"target": "rtdd:peachbarrel",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32个桃子",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:fishbucket_0",
|
||||
"item": "rtdd:orange",
|
||||
"target": "rtdd:orangebarrel",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32个橘子",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:fishbucket_0",
|
||||
"item": "minecraft:apple",
|
||||
"target": "rtdd:applebox",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32个苹果",
|
||||
"giveItem": None,
|
||||
},
|
||||
# ---- 取出 ----
|
||||
{
|
||||
"source": "rtdd:fishbucket_1",
|
||||
"item": None,
|
||||
"target": "rtdd:fishbucket_0",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "minecraft:cod", "count": 32}],
|
||||
"tip": "§a取出了32条鳕鱼",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:fishbucket_2",
|
||||
"item": None,
|
||||
"target": "rtdd:fishbucket_0",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "minecraft:salmon", "count": 32}],
|
||||
"tip": "§a取出了32条鲑鱼",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:carrotbarrel",
|
||||
"item": None,
|
||||
"target": "rtdd:fishbucket_0",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "minecraft:carrot", "count": 32}],
|
||||
"tip": "§a取出了32个胡萝卜",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:potatobarrel",
|
||||
"item": None,
|
||||
"target": "rtdd:fishbucket_0",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "minecraft:potato", "count": 32}],
|
||||
"tip": "§a取出了32个土豆",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:peachbarrel",
|
||||
"item": None,
|
||||
"target": "rtdd:fishbucket_0",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "rtdd:peach", "count": 32}],
|
||||
"tip": "§a取出了32个桃子",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:orangebarrel",
|
||||
"item": None,
|
||||
"target": "rtdd:fishbucket_0",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "rtdd:orange", "count": 32}],
|
||||
"tip": "§a取出了32个橘子",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:applebox",
|
||||
"item": None,
|
||||
"target": "rtdd:fishbucket_0",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "minecraft:apple", "count": 32}],
|
||||
"tip": "§a取出了32个苹果",
|
||||
"giveItem": None,
|
||||
},
|
||||
|
||||
# ============================================================
|
||||
# 三、售卖盒 (sellingboxes空 → 各装一种)
|
||||
# 南瓜/西瓜消耗1个原版方块, 其余32个
|
||||
# ============================================================
|
||||
# ---- 放入 ----
|
||||
{
|
||||
"source": "rtdd:sellingboxes",
|
||||
"item": "rtdd:orange",
|
||||
"target": "rtdd:orangebox",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32个橘子",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:sellingboxes",
|
||||
"item": "rtdd:peach",
|
||||
"target": "rtdd:peachbox",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32个桃子",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:sellingboxes",
|
||||
"item": "minecraft:cod",
|
||||
"target": "rtdd:sales_box_cod",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32条鳕鱼",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:sellingboxes",
|
||||
"item": "minecraft:salmon",
|
||||
"target": "rtdd:b_30",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32条鲑鱼",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:sellingboxes",
|
||||
"item": "minecraft:carrot",
|
||||
"target": "rtdd:sales_box_carrot",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32个胡萝卜",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:sellingboxes",
|
||||
"item": "minecraft:bread",
|
||||
"target": "rtdd:sales_box_bread",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32个面包",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:sellingboxes",
|
||||
"item": "minecraft:apple",
|
||||
"target": "rtdd:sales_box_apple",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32个苹果",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:sellingboxes",
|
||||
"item": "minecraft:pumpkin",
|
||||
"target": "rtdd:sales_box_pumpkin",
|
||||
"consume": 1,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入1个原版南瓜",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:sellingboxes",
|
||||
"item": "minecraft:melon_block",
|
||||
"target": "rtdd:sales_box_watermelon",
|
||||
"consume": 1,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入1个原版西瓜",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:sellingboxes",
|
||||
"item": "minecraft:potato",
|
||||
"target": "rtdd:sales_box_potato",
|
||||
"consume": 32,
|
||||
"type": "switch",
|
||||
"tip": "§a已放入32个土豆",
|
||||
"giveItem": None,
|
||||
},
|
||||
# ---- 取出 ----
|
||||
{
|
||||
"source": "rtdd:orangebox",
|
||||
"item": None,
|
||||
"target": "rtdd:sellingboxes",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "rtdd:orange", "count": 32}],
|
||||
"tip": "§a取出了32个橘子",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:peachbox",
|
||||
"item": None,
|
||||
"target": "rtdd:sellingboxes",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "rtdd:peach", "count": 32}],
|
||||
"tip": "§a取出了32个桃子",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:sales_box_cod",
|
||||
"item": None,
|
||||
"target": "rtdd:sellingboxes",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "minecraft:cod", "count": 32}],
|
||||
"tip": "§a取出了32条鳕鱼",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:b_30",
|
||||
"item": None,
|
||||
"target": "rtdd:sellingboxes",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "minecraft:salmon", "count": 32}],
|
||||
"tip": "§a取出了32条鲑鱼",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:sales_box_carrot",
|
||||
"item": None,
|
||||
"target": "rtdd:sellingboxes",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "minecraft:carrot", "count": 32}],
|
||||
"tip": "§a取出了32个胡萝卜",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:sales_box_bread",
|
||||
"item": None,
|
||||
"target": "rtdd:sellingboxes",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "minecraft:bread", "count": 32}],
|
||||
"tip": "§a取出了32个面包",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:sales_box_apple",
|
||||
"item": None,
|
||||
"target": "rtdd:sellingboxes",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "minecraft:apple", "count": 32}],
|
||||
"tip": "§a取出了32个苹果",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:sales_box_pumpkin",
|
||||
"item": None,
|
||||
"target": "rtdd:sellingboxes",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "minecraft:pumpkin", "count": 1}],
|
||||
"tip": "§a取出了1个原版南瓜",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:sales_box_watermelon",
|
||||
"item": None,
|
||||
"target": "rtdd:sellingboxes",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "minecraft:melon_block", "count": 1}],
|
||||
"tip": "§a取出了1个原版西瓜",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:sales_box_potato",
|
||||
"item": None,
|
||||
"target": "rtdd:sellingboxes",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"dropItem": [{"name": "minecraft:potato", "count": 32}],
|
||||
"tip": "§a取出了32个土豆",
|
||||
"giveItem": None,
|
||||
},
|
||||
|
||||
# ============================================================
|
||||
# 四、悬赏纸循环 (空手右键逐级切换)
|
||||
# ============================================================
|
||||
{
|
||||
"source": "rtdd:bountypaper",
|
||||
"item": None,
|
||||
"target": "rtdd:bountypaper_1",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"tip": "§a切换到悬赏纸_1",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:bountypaper_1",
|
||||
"item": None,
|
||||
"target": "rtdd:bountypaper_2",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"tip": "§a切换到悬赏纸_2",
|
||||
"giveItem": None,
|
||||
},
|
||||
{
|
||||
"source": "rtdd:bountypaper_2",
|
||||
"item": None,
|
||||
"target": "rtdd:bountypaper",
|
||||
"consume": 0,
|
||||
"type": "switch",
|
||||
"tip": "§a切回农贸清单",
|
||||
"giveItem": None,
|
||||
},
|
||||
]
|
||||
Whitespace-only changes.
+265
@@ -0,0 +1,265 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
================================================================================
|
||||
市场贸易·右键转换引擎(服务端)
|
||||
================================================================================
|
||||
只处理"市场贸易"(xy_market) 分类下的【右键切换型】转换:
|
||||
条箱/货桶/售卖盒 放入与取出、悬赏纸循环切换。
|
||||
全部为即时右键转换, 无计时, 因此只有一个服务类, 不需要拆分 TimerService。
|
||||
|
||||
【事件监听在哪?】
|
||||
本类【不】监听任何事件!
|
||||
所有事件由 FeatureDispatcher(xiangyemod/service/FeatureDispatcher.py)统一监听:
|
||||
- ServerBlockUseEvent → OnBlockUse → 按 blockOwner 路由到本类 handleBlockUse
|
||||
本类只实现被分发器调用的接口方法, 不关心事件来源。
|
||||
|
||||
【本类怎么做(自上而下的方法系列)】
|
||||
handleBlockUse ← 入口:分发器转发右键方块事件
|
||||
├─ findRecipe ← 匹配 (方块名, 物品名);空手规则需确认真正空手
|
||||
├─ checkCooldown← 连点冷却
|
||||
└─ handleSwitch ← 放入(消耗+替换) / 取出(掉落+替换) / 悬赏纸循环(替换)
|
||||
├─ checkCount ← 放入前检查物品数量足够(不足给红字提示)
|
||||
├─ consumeItem ← 消耗物品
|
||||
├─ replaceBlock ← 替换方块
|
||||
└─ dropItems ← 取出时以掉落物形式生成物品
|
||||
================================================================================
|
||||
"""
|
||||
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 ..MarketData import MARKET_SWITCHES
|
||||
|
||||
# ---- 统一分发器 ----
|
||||
from ...service.FeatureDispatcher import FeatureDispatcher
|
||||
|
||||
|
||||
class MarketService(BlueFoxServerSystem):
|
||||
"""
|
||||
市场贸易·右键转换引擎
|
||||
|
||||
【核心数据结构】
|
||||
marketRecipes = {(方块名, 物品名): 规则dict} # O(1) 查找
|
||||
marketBlockSet = {方块名, ...} # O(1) 注册用
|
||||
cooldown = {key: 时间戳} # 连点冷却表
|
||||
"""
|
||||
|
||||
def __init__(self, namespace, systemName):
|
||||
"""
|
||||
初始化:构建规则字典,并注册到统一分发器。
|
||||
"""
|
||||
super(MarketService, self).__init__(namespace, systemName)
|
||||
print "===== MarketService init ====="
|
||||
|
||||
# ---- 构建规则字典(O(1) 查找) ----
|
||||
self.marketRecipes = {}
|
||||
self.marketBlockSet = set()
|
||||
for sw in MARKET_SWITCHES:
|
||||
key = (sw["source"], sw.get("item"))
|
||||
self.marketRecipes[key] = sw
|
||||
self.marketBlockSet.add(sw["source"])
|
||||
|
||||
# ---- 右键冷却表 ----
|
||||
self.cooldown = {}
|
||||
|
||||
# ---- 注册到统一分发器 ----
|
||||
FeatureDispatcher.register(self)
|
||||
|
||||
# ============================================================================
|
||||
# 一、给 FeatureDispatcher 的接口
|
||||
# ============================================================================
|
||||
|
||||
def getFeatureBlocks(self):
|
||||
"""返回本功能管辖的所有方块名集合(右键路由用)"""
|
||||
return self.marketBlockSet
|
||||
|
||||
def getItemUseOnRules(self):
|
||||
"""返回"手持物品右键方块表面"的规则(市场贸易没有, 返回空)"""
|
||||
return {}
|
||||
|
||||
def handleBlockUse(self, args):
|
||||
"""
|
||||
由 FeatureDispatcher 转发的右键方块入口。
|
||||
只有 blockName 在本功能的方块集合里才会被调用。
|
||||
|
||||
返回 True = 本功能处理了这个右键(分发器取消默认行为)
|
||||
返回 False = 当前组合没有匹配规则(分发器不拦截)
|
||||
"""
|
||||
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)
|
||||
|
||||
recipe = self.findRecipe(blockName, itemDict)
|
||||
if not recipe:
|
||||
return False
|
||||
|
||||
# 连点冷却
|
||||
if not self.checkCooldown(key, recipe.get("switchCd", 0.5)):
|
||||
return True
|
||||
|
||||
# 放入前检查物品数量是否足够
|
||||
if recipe.get("item") is not None:
|
||||
need = recipe.get("consume", 1)
|
||||
if not self.checkCount(playerId, itemDict, need):
|
||||
return True
|
||||
|
||||
# 切换型规则:就地执行
|
||||
self.handleSwitch(recipe, playerId, pos, dim, itemDict)
|
||||
return True
|
||||
|
||||
# ============================================================================
|
||||
# 二、规则匹配(O(1) 字典查找)
|
||||
# ============================================================================
|
||||
|
||||
def findRecipe(self, blockName, itemDict):
|
||||
"""
|
||||
在市场中查找匹配规则:
|
||||
1. 先精确匹配 (方块名, 物品名) —— 放入(手持物品) / 悬赏纸循环
|
||||
2. 没找到再匹配 (方块名, None) —— 空手触发的规则(取出)
|
||||
注意:只有确认玩家真正空手时才 fallback 到空手规则, 避免手持物品误触发取出。
|
||||
"""
|
||||
itemName = itemDict.get("newItemName") if itemDict else None
|
||||
recipe = self.marketRecipes.get((blockName, itemName))
|
||||
if recipe:
|
||||
return recipe
|
||||
# 空手规则:只有确认空手(无物品或手持空气)才 fallback
|
||||
if not itemName or itemName == "minecraft:air":
|
||||
return self.marketRecipes.get((blockName, None))
|
||||
return None
|
||||
|
||||
# ============================================================================
|
||||
# 三、切换型规则处理
|
||||
# ============================================================================
|
||||
|
||||
def handleSwitch(self, recipe, playerId, pos, dim, itemDict):
|
||||
"""
|
||||
处理"右键直接转换"类规则。
|
||||
- 放入(item 不为 None): 消耗物品 + 替换方块 + 提示
|
||||
- 取出(item 为 None): 掉落物 + 替换方块 + 提示(悬赏纸循环只替换+提示)
|
||||
"""
|
||||
# ---- 放入:消耗物品 ----
|
||||
if recipe.get("item") is not None and recipe.get("consume", 1) > 0:
|
||||
self.consumeItem(playerId, itemDict, recipe.get("consume", 1))
|
||||
|
||||
# ---- 取出:掉落物 ----
|
||||
if recipe.get("dropItem"):
|
||||
self.dropItems(dim, pos, recipe["dropItem"])
|
||||
|
||||
# ---- 替换方块 ----
|
||||
if recipe.get("target"):
|
||||
self.replaceBlock(pos, dim, recipe["target"], playerId)
|
||||
|
||||
# ---- 转换成功提示 ----
|
||||
if recipe.get("tip"):
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(playerId, recipe["tip"])
|
||||
|
||||
# ============================================================================
|
||||
# 四、工具方法:放入数量检查
|
||||
# ============================================================================
|
||||
|
||||
def checkCount(self, playerId, itemDict, need):
|
||||
"""放入前检查手中物品数量是否足够 need 个, 不足给红字提示并返回 False"""
|
||||
if itemDict is None:
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(playerId, "§c需要至少%d个对应物品!" % need)
|
||||
return False
|
||||
count = itemDict.get("count", 0)
|
||||
if count < need:
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(playerId, "§c数量不足,需要至少%d个对应物品!" % need)
|
||||
return False
|
||||
return True
|
||||
|
||||
# ============================================================================
|
||||
# 五、工具方法:获取玩家主手物品
|
||||
# ============================================================================
|
||||
|
||||
def getCarriedItem(self, playerId):
|
||||
itemComp = comp.CreateItem(playerId)
|
||||
return itemComp.GetPlayerItem(
|
||||
serverApi.GetMinecraftEnum().ItemPosType.CARRIED, 0)
|
||||
|
||||
# ============================================================================
|
||||
# 六、工具方法:消耗物品
|
||||
# ============================================================================
|
||||
|
||||
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)})
|
||||
|
||||
# ============================================================================
|
||||
# 七、工具方法:替换方块
|
||||
# ============================================================================
|
||||
|
||||
def replaceBlock(self, pos, dim, newBlockName, playerId=None):
|
||||
"""
|
||||
替换指定位置的方块。
|
||||
playerId 可为 None, 用 LevelId 创建组件。
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
dropList 格式:[{"name": "xxx", "count": N}, ...]
|
||||
在方块上方生成掉落物实体, 让它自然掉到地上。
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
右键冷却:同一方块 cd 秒内只响应一次, 防止连点刷物品/刷提示。
|
||||
"""
|
||||
now = time.time()
|
||||
last = self.cooldown.get(key, 0)
|
||||
if now - last < cd:
|
||||
return False
|
||||
self.cooldown[key] = now
|
||||
return True
|
||||
Whitespace-only changes.
+7
-4
@@ -12,10 +12,10 @@
|
||||
→ 挂上对应尸体(消耗1个)。鱼可挂两条。
|
||||
2) 取下退回: 切肉开始前, 空手右键 整只/整头 → 空钩 + 掉落回尸体(不可逆前可退)
|
||||
3) 挂肉钩切肉: 手持 菜刀(cleaver) 右键 逐级切割(不可逆), 以掉落物形式获得对应部位肉
|
||||
- 切肉每刀掉落数量: 常规肉 2~3 个; 四肢固定 4 个; 牛头骨固定 1 个
|
||||
- 牛: 去头去皮掉牛头骨1+原版牛肉4~5 → 去四肢掉牛腿肉4 → 去肉掉牛肋2~3+牛里脊2~3+原版牛肉4~5 → 空钩掉碎肉2~3+原版牛肉4~5
|
||||
- 猪: 去皮掉五花肉2~3+原版生猪排4~5 → 去四肢掉猪蹄4 → 去肉掉猪肋排2~3+原版生猪排4~5 → 空钩掉碎肉2~3+原版生猪排4~5
|
||||
- 羊: 去皮掉羊小排2~3+原版生羊肉4~5 → 去四肢掉羊腿4 → 去肉掉羊里脊2~3+原版生羊肉4~5 → 空钩掉碎肉2~3+原版生羊肉4~5
|
||||
- 切肉每刀掉落数量: 常规肉 2~3 个; 四肢固定 4 个; 牛头骨固定 1 个; 去皮额外掉原版皮革4~6
|
||||
- 牛: 去头去皮掉牛头骨1+原版牛肉4~5+皮革4~6 → 去四肢掉牛腿肉4 → 去肉掉牛肋2~3+牛里脊2~3+原版牛肉4~5 → 空钩掉碎肉2~3+原版牛肉4~5
|
||||
- 猪: 去皮掉五花肉2~3+原版生猪排4~5+皮革4~6 → 去四肢掉猪蹄4 → 去肉掉猪肋排2~3+原版生猪排4~5 → 空钩掉碎肉2~3+原版生猪排4~5
|
||||
- 羊: 去皮掉羊小排2~3+原版生羊肉4~5+皮革4~6 → 去四肢掉羊腿4 → 去肉掉羊里脊2~3+原版生羊肉4~5 → 空钩掉碎肉2~3+原版生羊肉4~5
|
||||
4) 鱼晾干(计时): 鲑鱼/鳕鱼挂上后自动计时约300秒晾干(挂肉钩自动开始, autoStart=True)
|
||||
- 鲑鱼: 挂一条→干一条; 挂两条→干两条
|
||||
- 鳕鱼: 挂两条→干两条
|
||||
@@ -161,6 +161,7 @@ DEADMOB_SWITCHES = [
|
||||
"dropItem": [
|
||||
{"name": "rtdd:cow_skull", "count": 1},
|
||||
{"name": "minecraft:beef", "count": (4, 5)},
|
||||
{"name": "minecraft:leather", "count": (4, 6)},
|
||||
],
|
||||
"tip": "§a砍下了牛头",
|
||||
"giveItem": None,
|
||||
@@ -212,6 +213,7 @@ DEADMOB_SWITCHES = [
|
||||
"dropItem": [
|
||||
{"name": "rtdd:porkloins", "count": (2, 3)},
|
||||
{"name": "minecraft:porkchop", "count": (4, 5)},
|
||||
{"name": "minecraft:leather", "count": (4, 6)},
|
||||
],
|
||||
"tip": "§a已给猪去皮",
|
||||
"giveItem": None,
|
||||
@@ -262,6 +264,7 @@ DEADMOB_SWITCHES = [
|
||||
"dropItem": [
|
||||
{"name": "rtdd:sheepracks", "count": (2, 3)},
|
||||
{"name": "minecraft:mutton", "count": (4, 5)},
|
||||
{"name": "minecraft:leather", "count": (4, 6)},
|
||||
],
|
||||
"tip": "§a已给羊去皮",
|
||||
"giveItem": None,
|
||||
|
||||
+2
-5
@@ -95,11 +95,8 @@ class DeadmobService(BlueFoxServerSystem):
|
||||
|
||||
def getItemUseOnRules(self):
|
||||
"""
|
||||
返回"手持物品右键方块表面"的规则(当前返回空)。
|
||||
挂鱼走 ServerBlockUseEvent(右键方块本身)即可,不需要 ItemUseOn:
|
||||
日志验证手持原版鲑鱼/鳕鱼右键肉钩会正常触发 ServerBlockUseEvent 并转换,
|
||||
若同时注册 ItemUseOn 会重复转换(多消耗一条鱼)且 ServerItemUseOnEvent 的
|
||||
玩家键是 entityId 不是 playerId,易出错,故不再使用该路径。
|
||||
返回"手持物品右键方块表面"的规则(原版放置已拆到 yuanbanfangzhi, 返回空)。
|
||||
手持原版鲑鱼/鳕鱼右键方块表面放置 死鲑鱼/死鳕鱼 的逻辑由 YuanbanService 处理。
|
||||
"""
|
||||
return {}
|
||||
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
================================================================================
|
||||
原版放置分类转换规则数据
|
||||
================================================================================
|
||||
统一管理"手持原版物品右键方块表面 → 放置对应方块"的规则(ServerItemUseOnEvent)。
|
||||
从各功能分类中剔除出来单独成目录, 避免散落在各处。
|
||||
|
||||
当前规则:
|
||||
1) 原版生鸡肉(minecraft:chicken) → 生鸡肉(放置后) roastchickenplace_0 [烧烤用]
|
||||
2) 原版生鲑鱼(minecraft:salmon) → 死鲑鱼 killfish_0 [死亡生物用]
|
||||
3) 原版生鳕鱼(minecraft:cod) → 死鳕鱼 killcod_0 [死亡生物用]
|
||||
4) minecraft:fish → 死鳕鱼 killcod_0 (网易端 ItemUseOn 事件对
|
||||
生鳕鱼报的 itemName 是 minecraft:fish, 与 GetPlayerItem 的 minecraft:cod 不同)
|
||||
|
||||
字段说明:
|
||||
item: 手持的原版物品
|
||||
target: 放置成的方块
|
||||
consume: 消耗数量(默认1)
|
||||
tip: 放置成功提示
|
||||
================================================================================
|
||||
"""
|
||||
|
||||
ITEM_USE_ON_RULES = [
|
||||
{
|
||||
"item": "minecraft:chicken", # 原版生鸡肉
|
||||
"target": "rtdd:roastchickenplace_0", # 生鸡肉(放置后)
|
||||
"consume": 1,
|
||||
"tip": "§a已放置生鸡肉,可右键支杆上杆烤制",
|
||||
},
|
||||
{
|
||||
"item": "minecraft:salmon", # 原版生鲑鱼
|
||||
"target": "rtdd:killfish_0", # 死鲑鱼
|
||||
"consume": 1,
|
||||
"tip": "§a已放置死鲑鱼",
|
||||
},
|
||||
{
|
||||
"item": "minecraft:cod", # 原版生鳕鱼
|
||||
"target": "rtdd:killcod_0", # 死鳕鱼
|
||||
"consume": 1,
|
||||
"tip": "§a已放置死鳕鱼",
|
||||
},
|
||||
# 网易端 ServerItemUseOnEvent 对 原版生鳕鱼 报的 itemName 是 minecraft:fish
|
||||
# (日志: [FD-ItemUseOn] minecraft:fish), 需额外注册一条, 否则生鳕鱼无法放置。
|
||||
{
|
||||
"item": "minecraft:fish",
|
||||
"target": "rtdd:killcod_0", # 死鳕鱼
|
||||
"consume": 1,
|
||||
"tip": "§a已放置死鳕鱼",
|
||||
},
|
||||
]
|
||||
Whitespace-only changes.
+205
@@ -0,0 +1,205 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
================================================================================
|
||||
原版放置·手持原版物品右键方块表面(服务端)
|
||||
================================================================================
|
||||
统一处理"手持原版物品右键方块表面 → 放置对应方块"的转换(ServerItemUseOnEvent):
|
||||
原版生鸡肉 → 生鸡肉(放置后);原版生鲑鱼/鳕鱼 → 死鲑鱼/死鳕鱼。
|
||||
这些规则原本散落在 烧烤(BarbecueService) 和 死亡生物(DeadmobService) 里,
|
||||
现在单独拆到本目录统一管理。
|
||||
|
||||
【事件监听在哪?】
|
||||
本类【不】监听任何事件!
|
||||
所有事件由 FeatureDispatcher(xiangyemod/service/FeatureDispatcher.py)统一监听:
|
||||
- ServerItemUseOnEvent → OnItemUseOn → 按 itemUseOnOwner 路由到本类 handleItemUseOn
|
||||
被点方块属于某个"右键方块"服务的管辖(肉钩/条箱/锅具等)时, 分发器会跳过本路径,
|
||||
交给 ServerBlockUseEvent 处理(挂鱼/放入/做菜), 避免重复。
|
||||
|
||||
【本类怎么做】
|
||||
handleItemUseOn ← 入口:分发器转发"手持物品右键方块表面"事件
|
||||
├─ 匹配规则 ← 按手持物品名 O(1) 查找
|
||||
├─ 算目标格 ← 被点方块表面相邻的空格
|
||||
├─ checkCooldown← 连点冷却
|
||||
├─ consumeItem ← 消耗1个原版物品
|
||||
└─ replaceBlock ← 放置对应方块 + 提示
|
||||
================================================================================
|
||||
"""
|
||||
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 ..YuanbanData import ITEM_USE_ON_RULES
|
||||
|
||||
# ---- 统一分发器 ----
|
||||
from ...service.FeatureDispatcher import FeatureDispatcher
|
||||
|
||||
# ---- 方块表面方向 → 相邻坐标偏移(0下 1上 2北 3南 4西 5东) ----
|
||||
FACE_OFFSET = {
|
||||
0: (0, -1, 0),
|
||||
1: (0, 1, 0),
|
||||
2: (0, 0, -1),
|
||||
3: (0, 0, 1),
|
||||
4: (-1, 0, 0),
|
||||
5: (1, 0, 0),
|
||||
}
|
||||
|
||||
|
||||
class YuanbanService(BlueFoxServerSystem):
|
||||
"""
|
||||
原版放置·手持原版物品右键方块表面引擎
|
||||
|
||||
【核心数据结构】
|
||||
itemUseOnRecipes = {物品名: 规则dict} # O(1) 查找
|
||||
cooldown = {key: 时间戳} # 连点冷却表
|
||||
"""
|
||||
|
||||
def __init__(self, namespace, systemName):
|
||||
"""
|
||||
初始化:构建放置规则字典,并注册到统一分发器。
|
||||
"""
|
||||
super(YuanbanService, self).__init__(namespace, systemName)
|
||||
print "===== YuanbanService init ====="
|
||||
|
||||
# ---- 构建放置规则字典(O(1) 查找) ----
|
||||
self.itemUseOnRecipes = {}
|
||||
for rule in ITEM_USE_ON_RULES:
|
||||
self.itemUseOnRecipes[rule["item"]] = rule
|
||||
|
||||
# ---- 右键冷却表 ----
|
||||
self.cooldown = {}
|
||||
|
||||
# ---- 注册到统一分发器(只注册 itemUseOn, 不注册任何右键方块) ----
|
||||
FeatureDispatcher.register(self)
|
||||
|
||||
# ============================================================================
|
||||
# 一、给 FeatureDispatcher 的接口
|
||||
# ============================================================================
|
||||
|
||||
def getFeatureBlocks(self):
|
||||
"""本功能不管辖任何右键方块, 返回空"""
|
||||
return set()
|
||||
|
||||
def getItemUseOnRules(self):
|
||||
"""返回"手持物品右键方块表面"的规则: {物品名: 规则dict}"""
|
||||
return self.itemUseOnRecipes
|
||||
|
||||
def handleItemUseOn(self, args):
|
||||
"""
|
||||
由 FeatureDispatcher 转发的"手持物品右键方块表面"事件。
|
||||
在方块表面放置对应方块(生鸡肉/死鲑鱼/死鳕鱼)。
|
||||
返回 True=已处理,False=当前组合无匹配规则。
|
||||
"""
|
||||
itemName = args.get("itemName")
|
||||
# ServerItemUseOnEvent 的玩家键是 entityId,不是 playerId
|
||||
playerId = args.get("playerId") or args.get("entityId")
|
||||
rule = self.itemUseOnRecipes.get(itemName)
|
||||
if not rule:
|
||||
return False
|
||||
|
||||
x, y, z = args.get("x"), args.get("y"), args.get("z")
|
||||
face = args.get("face", 1)
|
||||
dim = comp.CreateDimension(playerId).GetEntityDimensionId()
|
||||
|
||||
# 计算被点方块表面相邻的目标格
|
||||
off = FACE_OFFSET.get(face, (0, 1, 0))
|
||||
targetPos = (x + off[0], y + off[1], z + off[2])
|
||||
|
||||
# 目标格必须为空(可放置)
|
||||
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
|
||||
|
||||
# 消耗 1 个原版物品
|
||||
itemDict = self.getCarriedItem(playerId)
|
||||
if not itemDict:
|
||||
return False
|
||||
self.consumeItem(playerId, itemDict, rule.get("consume", 1))
|
||||
|
||||
# 放置对应方块
|
||||
self.replaceBlock(targetPos, dim, rule["target"], playerId)
|
||||
# 放置成功提示
|
||||
if rule.get("tip"):
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(playerId, rule["tip"])
|
||||
return True
|
||||
|
||||
# ============================================================================
|
||||
# 二、工具方法:获取玩家主手物品
|
||||
# ============================================================================
|
||||
|
||||
def getCarriedItem(self, playerId):
|
||||
itemComp = comp.CreateItem(playerId)
|
||||
return itemComp.GetPlayerItem(
|
||||
serverApi.GetMinecraftEnum().ItemPosType.CARRIED, 0)
|
||||
|
||||
# ============================================================================
|
||||
# 三、工具方法:消耗物品
|
||||
# ============================================================================
|
||||
|
||||
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)})
|
||||
|
||||
# ============================================================================
|
||||
# 四、工具方法:替换方块
|
||||
# ============================================================================
|
||||
|
||||
def replaceBlock(self, pos, dim, newBlockName, playerId=None):
|
||||
"""
|
||||
替换指定位置的方块。
|
||||
playerId 可为 None, 用 LevelId 创建组件。
|
||||
"""
|
||||
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 checkCooldown(self, key, cd=0.5):
|
||||
"""
|
||||
右键冷却:同一目标格 cd 秒内只响应一次, 防止连点刷方块/刷提示。
|
||||
"""
|
||||
now = time.time()
|
||||
last = self.cooldown.get(key, 0)
|
||||
if now - last < cd:
|
||||
return False
|
||||
self.cooldown[key] = now
|
||||
return True
|
||||
Whitespace-only changes.
@@ -4,7 +4,7 @@
|
||||
"description": {
|
||||
"identifier": "rtdd:b_30",
|
||||
"register_to_creative_menu": true,
|
||||
"category": "xy_jinyong"
|
||||
"category": "xy_market"
|
||||
},
|
||||
"components": {
|
||||
"netease:aabb": {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"description": {
|
||||
"identifier": "rtdd:clothbox_1",
|
||||
"register_to_creative_menu": true,
|
||||
"category": "xy_market"
|
||||
"category": "xy_jinyong"
|
||||
},
|
||||
"components": {
|
||||
"netease:aabb": {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"description": {
|
||||
"identifier": "rtdd:clothbox_2",
|
||||
"register_to_creative_menu": true,
|
||||
"category": "xy_market"
|
||||
"category": "xy_jinyong"
|
||||
},
|
||||
"components": {
|
||||
"netease:aabb": {
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
"icon": "rtdd:sellingboxes",
|
||||
"list": [
|
||||
"rtdd:sellingboxes",
|
||||
"rtdd:clothbox_1",
|
||||
"rtdd:clothbox_2",
|
||||
"rtdd:b_30",
|
||||
"rtdd:orangebox",
|
||||
"rtdd:peachbox",
|
||||
"rtdd:sales_box_cod",
|
||||
|
||||
@@ -31,8 +31,8 @@ itemGroup.tabrbulid=乡野-建筑
|
||||
tile.rtdd:codsoup.name=汤锅_30(鳕鱼汤)
|
||||
tile.rtdd:apple_leaves.name=苹果树树叶(苹果树叶)
|
||||
tile.rtdd:lambsoupwithturnips_1.name=汤锅_47(胡萝卜羊肉汤_四分熟)
|
||||
tile.rtdd:clothbox_1.name=售卖盒(黄绿布料)
|
||||
tile.rtdd:clothbox_2.name=售卖盒(棕色布料)
|
||||
tile.rtdd:clothbox_1.name=售卖盒(黄绿布料)_禁用
|
||||
tile.rtdd:clothbox_2.name=售卖盒(棕色布料)_禁用
|
||||
tile.rtdd:salmonsushicubes_1.name=鲑鱼寿司块(一个)
|
||||
tile.rtdd:lambsoupwithturnips_3.name=汤锅_49(胡萝卜羊肉汤_熟)
|
||||
tile.rtdd:plate_8a.name=黄酱牛肉_2(黄酱牛肉)禁用
|
||||
@@ -1042,7 +1042,7 @@ tile.rtdd:norieggsoup_3.name=汤锅_59(瘦肉蛋花汤_熟)
|
||||
tile.rtdd:norieggsoup_2.name=汤锅_58(瘦肉蛋花汤_全熟)
|
||||
tile.rtdd:cookingcookedporkloin_1.name=炒锅_31(小炒五花肉_熟)
|
||||
tile.rtdd:b_31.name=稻草人1
|
||||
tile.rtdd:b_30.name=鲑鱼箱_禁用
|
||||
tile.rtdd:b_30.name=售卖盒(鲑鱼)
|
||||
tile.rtdd:cookingdought.name=炒锅_38(煎面饼_生)
|
||||
tile.rtdd:b_39.name=面包盒_1_禁用
|
||||
tile.rtdd:b_38.name=面包堆_1_禁用
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
========================================
|
||||
【市场贸易】(xy_market) 转化关系
|
||||
========================================
|
||||
说明:
|
||||
- 分为4个分组: 条箱 / 货桶 / 售卖盒 / 摊位设施
|
||||
- 条箱/货桶/售卖盒 均为"手持对应物品右键放入 → 变为对应容器", 可空手右键取出取回
|
||||
- 放入消耗: 除 南瓜/西瓜 消耗1个原版方块(南瓜方块/西瓜方块)外, 其余消耗32个对应物品
|
||||
- 布料两个(售卖盒(黄绿/棕色))已按标注: 名字加"禁用" 调到 禁用(xy_jinyong)标签, 不参与本分类转换
|
||||
- 摊位设施静态, 仅悬赏纸有循环转换
|
||||
|
||||
========================================
|
||||
一、条箱 (手持对应物品右键放入, 消耗32)
|
||||
========================================
|
||||
对应方块: woodenbox_0(条箱_空)、woodenbox_1(条箱(苹果))、woodenbox_2(条箱(胡萝卜))、
|
||||
woodenbox_3(条箱(土豆))、woodenbox_4(条箱(桃子))、woodenbox_5(条箱(橘子))、
|
||||
woodenbox_6(条箱(鳕鱼))、woodenbox_7(条箱(鲑鱼))
|
||||
机制: 手持对应物品右键 条箱(空 woodenbox_0), 消耗32个对应物品, 变为对应条箱
|
||||
1. 条箱(空) + 苹果 -> 条箱(苹果)
|
||||
转换条件:[手持 苹果 右键 进行转换, 消耗32个苹果]
|
||||
2. 条箱(空) + 胡萝卜 -> 条箱(胡萝卜)
|
||||
转换条件:[手持 胡萝卜 右键 进行转换, 消耗32个胡萝卜]
|
||||
3. 条箱(空) + 土豆 -> 条箱(土豆)
|
||||
转换条件:[手持 土豆 右键 进行转换, 消耗32个土豆]
|
||||
4. 条箱(空) + 桃子 -> 条箱(桃子)
|
||||
转换条件:[手持 桃子 右键 进行转换, 消耗32个桃子]
|
||||
5. 条箱(空) + 橘子 -> 条箱(橘子)
|
||||
转换条件:[手持 橘子 右键 进行转换, 消耗32个橘子]
|
||||
6. 条箱(空) + 鳕鱼 -> 条箱(鳕鱼)
|
||||
转换条件:[手持 鳕鱼 右键 进行转换, 消耗32个鳕鱼]
|
||||
7. 条箱(空) + 鲑鱼 -> 条箱(鲑鱼)
|
||||
转换条件:[手持 鲑鱼 右键 进行转换, 消耗32个鲑鱼]
|
||||
|
||||
【取出】条箱(苹果/胡萝卜/土豆/桃子/橘子/鳕鱼/鲑鱼) -> 条箱(空)
|
||||
转换条件:[空手右键 进行转换, 取回对应物品]
|
||||
机制: 空手右键装满的条箱, 变回空条箱, 以掉落物形式取回 32个对应物品
|
||||
|
||||
========================================
|
||||
二、货桶 (手持对应物品右键放入, 消耗32)
|
||||
========================================
|
||||
对应方块: fishbucket_0(货桶_空)、fishbucket_1(货桶(鳕鱼))、fishbucket_2(货桶(鲑鱼))、
|
||||
carrotbarrel(货桶(胡萝卜))、potatobarrel(货桶(土豆))、peachbarrel(货桶(桃子))、
|
||||
orangebarrel(货桶(橘子))、applebox(货桶(苹果))
|
||||
机制: 手持对应物品右键 货桶(空 fishbucket_0), 消耗32个对应物品, 变为对应货桶
|
||||
1. 货桶(空) + 鳕鱼 -> 货桶(鳕鱼)
|
||||
转换条件:[手持 鳕鱼 右键 进行转换, 消耗32个鳕鱼]
|
||||
2. 货桶(空) + 鲑鱼 -> 货桶(鲑鱼)
|
||||
转换条件:[手持 鲑鱼 右键 进行转换, 消耗32个鲑鱼]
|
||||
3. 货桶(空) + 胡萝卜 -> 货桶(胡萝卜)
|
||||
转换条件:[手持 胡萝卜 右键 进行转换, 消耗32个胡萝卜]
|
||||
4. 货桶(空) + 土豆 -> 货桶(土豆)
|
||||
转换条件:[手持 土豆 右键 进行转换, 消耗32个土豆]
|
||||
5. 货桶(空) + 桃子 -> 货桶(桃子)
|
||||
转换条件:[手持 桃子 右键 进行转换, 消耗32个桃子]
|
||||
6. 货桶(空) + 橘子 -> 货桶(橘子)
|
||||
转换条件:[手持 橘子 右键 进行转换, 消耗32个橘子]
|
||||
7. 货桶(空) + 苹果 -> 货桶(苹果)
|
||||
转换条件:[手持 苹果 右键 进行转换, 消耗32个苹果]
|
||||
|
||||
【取出】货桶(鳕鱼/鲑鱼/胡萝卜/土豆/桃子/橘子/苹果) -> 货桶(空)
|
||||
转换条件:[空手右键 进行转换, 取回对应物品]
|
||||
机制: 空手右键装满的货桶, 变回空货桶, 以掉落物形式取回 32个对应物品
|
||||
|
||||
========================================
|
||||
三、售卖盒 (手持对应物品右键放入)
|
||||
========================================
|
||||
对应方块: sellingboxes(售卖盒_空)、orangebox(售卖盒(橘子))、peachbox(售卖盒(桃子))、
|
||||
sales_box_cod(售卖盒(鳕鱼盒))、sales_box_carrot(售卖盒(胡萝卜))、sales_box_bread(售卖盒(面包))、
|
||||
sales_box_apple(售卖盒(苹果))、sales_box_pumpkin(售卖盒(南瓜))、sales_box_watermelon(售卖盒(西瓜))、
|
||||
sales_box_potato(售卖盒(土豆))
|
||||
机制: 手持对应物品右键 售卖盒(空 sellingboxes), 除南瓜/西瓜消耗1个原版方块外, 其余消耗32个对应物品, 变为对应售卖盒
|
||||
1. 售卖盒(空) + 橘子 -> 售卖盒(橘子)
|
||||
转换条件:[手持 橘子 右键 进行转换, 消耗32个橘子]
|
||||
2. 售卖盒(空) + 桃子 -> 售卖盒(桃子)
|
||||
转换条件:[手持 桃子 右键 进行转换, 消耗32个桃子]
|
||||
3. 售卖盒(空) + 鳕鱼 -> 售卖盒(鳕鱼盒)
|
||||
转换条件:[手持 鳕鱼 右键 进行转换, 消耗32个鳕鱼]
|
||||
4. 售卖盒(空) + 胡萝卜 -> 售卖盒(胡萝卜)
|
||||
转换条件:[手持 胡萝卜 右键 进行转换, 消耗32个胡萝卜]
|
||||
5. 售卖盒(空) + 面包 -> 售卖盒(面包)
|
||||
转换条件:[手持 面包 右键 进行转换, 消耗32个面包]
|
||||
6. 售卖盒(空) + 苹果 -> 售卖盒(苹果)
|
||||
转换条件:[手持 苹果 右键 进行转换, 消耗32个苹果]
|
||||
7. 售卖盒(空) + 南瓜(原版方块) -> 售卖盒(南瓜)
|
||||
转换条件:[手持 原版南瓜方块 右键 进行转换, 消耗1个原版南瓜方块]
|
||||
8. 售卖盒(空) + 西瓜(原版方块) -> 售卖盒(西瓜)
|
||||
转换条件:[手持 原版西瓜方块 右键 进行转换, 消耗1个原版西瓜方块]
|
||||
9. 售卖盒(空) + 土豆 -> 售卖盒(土豆)
|
||||
转换条件:[手持 土豆 右键 进行转换, 消耗32个土豆]
|
||||
|
||||
【取出】售卖盒(橘子/桃子/鳕鱼/胡萝卜/面包/苹果/土豆) -> 售卖盒(空)
|
||||
转换条件:[空手右键 进行转换, 取回对应物品]
|
||||
机制: 空手右键装满的售卖盒, 变回空售卖盒, 以掉落物形式取回 32个对应物品
|
||||
- 南瓜/西瓜盒: 空手右键 → 空售卖盒 + 取回 1个原版方块(南瓜方块/西瓜方块)
|
||||
|
||||
【已禁用】售卖盒(黄绿布料 clothbox_1)、售卖盒(棕色布料 clothbox_2)
|
||||
- 按标注: 名字后面加"禁用", 调到 禁用(xy_jinyong) 标签, 不参与市场贸易转换
|
||||
|
||||
========================================
|
||||
四、摊位设施 (静态 + 悬赏纸循环)
|
||||
========================================
|
||||
1. 静态摊位设施(无转换)
|
||||
- b_4(摊位台)、menus(餐牌(菜单))、vending_desk(售货台) 为静态, 无转换
|
||||
|
||||
2. 悬赏纸循环转换 (空手右键逐级切换)
|
||||
- bountypaper(农贸清单/悬赏纸) -> bountypaper_1(悬赏纸_1) -> bountypaper_2(悬赏纸_2) -> bountypaper(农贸清单/悬赏纸)
|
||||
转换条件:[右键 进行转换, 循环切换]
|
||||
机制: 空手右键悬赏纸, 逐级切换到下一张, 末尾回到农贸清单
|
||||
File renamed without changes.
@@ -88,6 +88,8 @@
|
||||
- 事件由 FeatureDispatcher 统一监听路由 (blockOwner/itemUseOnOwner/timerOwner) [已实现]
|
||||
- 右键服务通过 FeatureDispatcher.startTimerFor 把计时启动转发给计时服务 [已实现]
|
||||
- 计时用绝对时间戳写入方块实体数据, 支持退出/重启后继续计时 [已实现]
|
||||
- 原版放置(手持原版生鸡肉/鲑鱼/鳕鱼右键方块表面放置对应方块)已拆到独立目录
|
||||
xiangyemod/yuanbanfangzhi (YuanbanData/YuanbanService), 从烧烤/死亡生物中剔除 [已重构]
|
||||
|
||||
|
||||
########################################
|
||||
@@ -127,6 +129,21 @@
|
||||
- 死鳕鱼: 3刀每刀掉1份生鱼片, 共3份 → 消失 [已实现]
|
||||
- 死鱿鱼: 切须掉5~6个鱿鱼须 → 变死鱿鱼(切掉鱿鱼须) [已实现]
|
||||
|
||||
七、手持原版鱼右键方块表面放置死鱼 (ServerItemUseOnEvent)
|
||||
- 原版生鲑鱼(salmon) 右键方块表面 → 在其表面放置 死鲑鱼(killfish_0), 消耗1条 [已实现]
|
||||
- 原版鳕鱼(cod) 右键方块表面 → 在其表面放置 死鳕鱼(killcod_0), 消耗1条 [已实现]
|
||||
- 注意: 网易端 ItemUseOn 事件对生鳕鱼报的 itemName 是 minecraft:fish, 已额外注册, 否则放置不了 [已实现]
|
||||
- 被点方块是挂肉钩/挂鱼钩/尸体等死亡生物方块时跳过, 交还挂鱼逻辑 [已实现]
|
||||
|
||||
七之补、拆方块掉回原版生食材 (ServerPlayerTryDestroyBlockEvent)
|
||||
- 破坏 死鲑鱼(killfish_0) → 掉落 原版生鲑鱼 1条 [已实现]
|
||||
- 破坏 死鳕鱼(killcod_0) → 掉落 原版生鳕鱼 1条 [已实现]
|
||||
- 破坏 生鸡肉(放置后 roastchickenplace_0) → 掉落 原版生鸡肉 1个 [已实现]
|
||||
- 取消默认掉落, 不把方块本身掉出来
|
||||
|
||||
八、去皮额外掉落原版皮革
|
||||
- 牛/猪/羊 去皮步骤额外掉落 原版皮革(minecraft:leather) 4~6个 [已实现]
|
||||
|
||||
【未做】尸体生成机制(玩家杀死生物生成尸体) 按txt标注暂时不搞
|
||||
|
||||
|
||||
@@ -146,3 +163,25 @@
|
||||
三、静态手办 (无转换)
|
||||
- 赞助者手办_1~6(figurines~5) 仅由盲盒开出, 无右键转换 [已实现]
|
||||
|
||||
|
||||
########################################
|
||||
【市场贸易】(xy_market) 2026-09-03
|
||||
########################################
|
||||
一、条箱 放入/取出 (woodenbox_0~7)
|
||||
- 放入: 手持对应物品右键 空条箱 → 消耗32个 → 变为对应条箱(苹果/胡萝卜/土豆/桃子/橘子/鳕鱼/鲑鱼) [已实现]
|
||||
- 取出: 空手右键装满条箱 → 空条箱 + 掉落32个对应物品 [已实现]
|
||||
|
||||
二、货桶 放入/取出 (fishbucket_0 等)
|
||||
- 放入: 手持对应物品右键 空货桶 → 消耗32个 → 变为对应货桶(鳕鱼/鲑鱼/胡萝卜/土豆/桃子/橘子/苹果) [已实现]
|
||||
- 取出: 空手右键装满货桶 → 空货桶 + 掉落32个对应物品 [已实现]
|
||||
|
||||
三、售卖盒 放入/取出 (sellingboxes 等)
|
||||
- 放入: 手持对应物品右键 空售卖盒 → 除南瓜/西瓜消耗1个原版方块外, 其余消耗32个 → 变为对应售卖盒(含 售卖盒(鲑鱼) b_30) [已实现]
|
||||
- 取出: 空手右键装满售卖盒 → 空售卖盒 + 取回(南瓜/西瓜1个原版方块, 其余32个) [已实现]
|
||||
|
||||
四、悬赏纸循环 (空手右键逐级切换)
|
||||
- bountypaper → bountypaper_1 → bountypaper_2 → bountypaper [已实现]
|
||||
|
||||
五、布料已按标注禁用 [已处理]
|
||||
- 售卖盒(黄绿布料 clothbox_1)、售卖盒(棕色布料 clothbox_2): 名字带"禁用", 已调去 禁用(xy_jinyong) 标签, 移出市场分组, 旧切换规则已移除
|
||||
|
||||
@@ -59,10 +59,6 @@
|
||||
(死牛 dead_cow / 死猪 dead_pig / 死羊 dead_sheep / 死鱿鱼 deadsquida / 村民尸体 dead_villager)
|
||||
- 未做原因: 转化文档 todo 已标注"暂时不搞" (死亡生物转化关系.txt 末尾 todo)
|
||||
|
||||
二、死鲑鱼/死鳕鱼切块掉落物数量【已实现, 仅记录原设计】
|
||||
- 死鲑鱼: 4刀共得4份生鱼片; 死鳕鱼: 3刀共得3份生鱼片; 死鱿鱼: 切须得5~6个鱿鱼须
|
||||
- 说明: 均已按批注实现, 此处仅为对照记录, 无未做项
|
||||
|
||||
|
||||
########################################
|
||||
【方块工具】(xy_blocktools)
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
========================================
|
||||
【市场贸易】(xy_market) 转化关系
|
||||
========================================
|
||||
说明:
|
||||
- 分为4个分组: 条箱 / 货桶 / 售卖盒 / 摊位设施
|
||||
- 只有售卖盒与鲑鱼箱之间存在明确交互转换
|
||||
- 条箱/货桶多为静态容器方块
|
||||
- 【待确认】表示该步骤所需的具体操作尚未最终确定
|
||||
|
||||
========================================
|
||||
一、售卖盒 ↔ 鲑鱼箱
|
||||
========================================
|
||||
1. 售卖盒(黄绿布料) -> 鲑鱼箱
|
||||
转换条件:[手持 鲑鱼 右键 进行转换,消耗1条]
|
||||
机制: 手持鲑鱼右键,消耗1条,放入鲑鱼变为鲑鱼箱
|
||||
|
||||
2. 售卖盒(棕色布料) -> 鲑鱼箱
|
||||
转换条件:[手持 鲑鱼 右键 进行转换,消耗1条]
|
||||
机制: 手持鲑鱼右键,消耗1条,放入鲑鱼变为鲑鱼箱
|
||||
|
||||
3. 鲑鱼箱 -> 售卖盒(棕色布料)
|
||||
转换条件:[右键 进行转换,同时获得鲑鱼]
|
||||
机制: 空手右键,取回鲑鱼,变回售卖盒(棕色布料)
|
||||
|
||||
========================================
|
||||
二、条箱(静态容器)
|
||||
========================================
|
||||
4. 条箱(空) -> 条箱(苹果) / 条箱(胡萝卜) / 条箱(土豆) / 条箱(桃子) / 条箱(橘子) / 条箱(鳕鱼) / 条箱(鲑鱼)
|
||||
转换条件:【待确认】手持对应物品右键放入?或为静态装饰方块
|
||||
机制: 手持对应物品右键,放入后变为对应条箱(机制待确认)
|
||||
|
||||
woodenbox_0(条箱)、woodenbox_1(条箱(苹果))、woodenbox_2(条箱(胡萝卜))、woodenbox_3(条箱(土豆))、
|
||||
woodenbox_4(条箱(桃子))、woodenbox_5(条箱(橘子))、woodenbox_6(条箱(鳕鱼))、woodenbox_7(条箱(鲑鱼))
|
||||
|
||||
========================================
|
||||
三、货桶(静态容器)
|
||||
========================================
|
||||
5. 货桶(空) -> 货桶(鳕鱼) / 货桶(鲑鱼) / 货桶(胡萝卜) / 货桶(土豆) / 货桶(桃子) / 货桶(橘子) / 货桶(苹果)
|
||||
转换条件:【待确认】手持对应物品右键放入?或为静态装饰方块
|
||||
机制: 手持对应物品右键,放入后变为对应货桶(机制待确认)
|
||||
|
||||
fishbucket_0(货桶)、fishbucket_1(货桶(鳕鱼))、fishbucket_2(货桶(鲑鱼))、carrotbarrel(货桶(胡萝卜))、
|
||||
potatobarrel(货桶(土豆))、peachbarrel(货桶(桃子))、orangebarrel(货桶(橘子))、applebox(货桶(苹果))
|
||||
|
||||
========================================
|
||||
四、售卖盒(其他静态售卖盒)
|
||||
========================================
|
||||
sellingboxes(售卖盒)、orangebox(售卖盒(橘子))、peachbox(售卖盒(桃子))、
|
||||
sales_box_cod(售卖盒(鳕鱼盒))、sales_box_carrot(售卖盒(胡萝卜))、sales_box_bread(售卖盒(面包))、
|
||||
sales_box_apple(售卖盒(苹果))、sales_box_pumpkin(售卖盒(南瓜))、sales_box_watermelon(售卖盒(西瓜))、
|
||||
sales_box_potato(售卖盒(土豆))
|
||||
以上售卖盒方块无明确转换关系【待确认】
|
||||
|
||||
========================================
|
||||
五、摊位设施(静态)
|
||||
========================================
|
||||
b_4(摊位台)、bountypaper(农贸清单(悬赏纸))、bountypaper_1(悬赏纸_1)、bountypaper_2(悬赏纸_2)、
|
||||
menus(餐牌(菜单))、vending_desk(售货台)
|
||||
以上为摊位静态设施,无转换关系
|
||||
Reference in new issue
Block a user