乡野食材 功能实现 1
This commit is contained in:
1 parent
b947847def
commit
098290c6b6
21 files changed
+697
-1583
No files matched your search
@@ -16,6 +16,7 @@ from xiangyemod.chuju.service.ChujuService import ChujuService
|
||||
from xiangyemod.chuju.service.ChujuTimerService import ChujuTimerService
|
||||
from xiangyemod.ziran.service.NaturalService import NaturalService
|
||||
from xiangyemod.ziran.service.NaturalTimerService import NaturalTimerService
|
||||
from xiangyemod.shicai.service.ShicaiService import ShicaiService
|
||||
|
||||
if not serverApi.IsInServer():
|
||||
pass
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
================================================================================
|
||||
乡野食材(xy_ingredients)·切配与裹粉 规则数据
|
||||
================================================================================
|
||||
统一管理"食材切配"(菜刀切分 / 蒜末) 与 "裹粉半成品" 的规则常量。
|
||||
只被 ShicaiService 读取,FeatureDispatcher 通过方块名 O(1) 路由到服务。
|
||||
|
||||
【一、菜刀切分】(CHOP_CHAINS)
|
||||
手持 菜刀(rtdd:cleaver) 右键"摆放地上"的切配方块, 逐级切分;
|
||||
切到最后一级再切 -> 掉落对应"碎"(数量见 drop) 并把方块变空气。
|
||||
|
||||
【二、蒜末】(GARLIC)
|
||||
手持 菜刀 右键 大蒜(rtdd:cutgarlic) 三次 -> 掉落 16 个蒜末并消失。
|
||||
|
||||
【三、裹粉】(COATING_RULES)
|
||||
手持生食材右键 面粉块(rtdd:farineblock_3) -> 消耗若干生食材 + 面粉块(变空气),
|
||||
掉落对应的裹粉半成品物品(供油锅炸物)。
|
||||
================================================================================
|
||||
"""
|
||||
|
||||
# 菜刀
|
||||
CLEAVER_ITEM = "rtdd:cleaver"
|
||||
|
||||
# 切分链: blocks 为逐级方块序列, 切到最后一级继续切 -> 掉 drop 并变空气
|
||||
CHOP_CHAINS = [
|
||||
{
|
||||
"blocks": [
|
||||
"rtdd:cutcarrot_0", "rtdd:cutcarrot_1", "rtdd:cutcarrot_2",
|
||||
"rtdd:cutcarrot_3", "rtdd:cutcarrot_4",
|
||||
],
|
||||
"drop": {"name": "rtdd:crushed_carrots", "count": 3},
|
||||
"tip": "§a切出了胡萝卜碎",
|
||||
},
|
||||
{
|
||||
"blocks": [
|
||||
"rtdd:cutpotato_0", "rtdd:cutpotato_1", "rtdd:cutpotato_2",
|
||||
"rtdd:cutpotato_3", "rtdd:cutpotato_4",
|
||||
],
|
||||
"drop": {"name": "rtdd:potato_wedges", "count": 3},
|
||||
"tip": "§a切出了土豆块",
|
||||
},
|
||||
{
|
||||
"blocks": [
|
||||
"rtdd:cutvegetable_0", "rtdd:cutvegetable_1",
|
||||
"rtdd:cutvegetable_2", "rtdd:cutvegetable_3",
|
||||
],
|
||||
"drop": {"name": "rtdd:vegetable", "count": 3},
|
||||
"tip": "§a切出了青菜碎",
|
||||
},
|
||||
{
|
||||
"blocks": [
|
||||
"rtdd:cutscallions_1", "rtdd:cutscallions_2",
|
||||
"rtdd:cutscallions_3", "rtdd:cutscallions_4",
|
||||
],
|
||||
"drop": {"name": "rtdd:crushed_scallions", "count": 3},
|
||||
"tip": "§a切出了葱花碎",
|
||||
},
|
||||
]
|
||||
|
||||
# ---- 蒜末: 大蒜 + 菜刀右键 GARLIC_CHOP_COUNT 次 -> 掉落 GARLIC_DROP ----
|
||||
GARLIC_BLOCK = "rtdd:cutgarlic"
|
||||
GARLIC_CHOP_COUNT = 3
|
||||
GARLIC_DROP = {"name": "rtdd:crushedgarlic", "count": 16}
|
||||
|
||||
# ---- 裹粉: 面粉块 + 生食材 -> 掉落裹粉半成品 ----
|
||||
FLOUR_BLOCK = "rtdd:farineblock_3"
|
||||
COATING_RULES = [
|
||||
{"item": "rtdd:sashimi", "count": 6,
|
||||
"drop": {"name": "rtdd:oilfish_0", "count": 1}},
|
||||
{"item": "rtdd:lobster", "count": 2,
|
||||
"drop": {"name": "rtdd:oiltempura", "count": 1}},
|
||||
{"item": "minecraft:porkchop", "count": 1,
|
||||
"drop": {"name": "rtdd:oilpork", "count": 1}},
|
||||
{"item": "minecraft:chicken", "count": 1,
|
||||
"drop": {"name": "rtdd:oil_chickennuggets", "count": 6}},
|
||||
{"item": "minecraft:potato", "count": 1,
|
||||
"drop": {"name": "rtdd:oilfrenchfries", "count": 10}},
|
||||
]
|
||||
|
||||
# ---- 左键破坏掉落: 摆在地上的切配方块 -> 原版食材(相对"切配态"的原版不切物品) ----
|
||||
DESTROY_DROP = {
|
||||
"rtdd:cutcarrot_0": "minecraft:carrot",
|
||||
"rtdd:cutcarrot_1": "minecraft:carrot",
|
||||
"rtdd:cutcarrot_2": "minecraft:carrot",
|
||||
"rtdd:cutcarrot_3": "minecraft:carrot",
|
||||
"rtdd:cutcarrot_4": "minecraft:carrot",
|
||||
"rtdd:cutpotato_0": "minecraft:potato",
|
||||
"rtdd:cutpotato_1": "minecraft:potato",
|
||||
"rtdd:cutpotato_2": "minecraft:potato",
|
||||
"rtdd:cutpotato_3": "minecraft:potato",
|
||||
"rtdd:cutpotato_4": "minecraft:potato",
|
||||
"rtdd:cutvegetable_0": "rtdd:qingcai",
|
||||
"rtdd:cutvegetable_1": "rtdd:qingcai",
|
||||
"rtdd:cutvegetable_2": "rtdd:qingcai",
|
||||
"rtdd:cutvegetable_3": "rtdd:qingcai",
|
||||
"rtdd:cutscallions_1": "rtdd:scallions",
|
||||
"rtdd:cutscallions_2": "rtdd:scallions",
|
||||
"rtdd:cutscallions_3": "rtdd:scallions",
|
||||
"rtdd:cutscallions_4": "rtdd:scallions",
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
+292
@@ -0,0 +1,292 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
================================================================================
|
||||
乡野食材·切配与裹粉 右键转换引擎(服务端)
|
||||
================================================================================
|
||||
处理"乡野食材"(xy_ingredients) 分类下的右键转换:
|
||||
菜刀切分配(胡萝卜/土豆/青菜/葱花 逐级切 + 切碎掉落)、
|
||||
蒜末(大蒜+菜刀右键三次)、裹粉半成品(生食材+面粉块)。
|
||||
|
||||
【事件监听在哪?】
|
||||
本类【不】监听任何事件!
|
||||
所有事件由 FeatureDispatcher 统一监听,按 blockOwner 路由到本类 handleBlockUse。
|
||||
|
||||
【本类怎么做】
|
||||
handleBlockUse ← 入口:分发器转发右键方块事件
|
||||
├─ _handleChop ← 菜刀切分(切配方块逐级推进 / 最后一刀掉碎)
|
||||
├─ _handleGarlic ← 蒜末(菜刀右键大蒜计数)
|
||||
└─ _handleCoating ← 裹粉(生食材右键面粉块)
|
||||
(通用工具) getCarriedItem / consumeItem / dropItems / replaceBlock /
|
||||
clearBlock / 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 ..ShicaiData import (
|
||||
CLEAVER_ITEM, CHOP_CHAINS, GARLIC_BLOCK, GARLIC_CHOP_COUNT,
|
||||
GARLIC_DROP, FLOUR_BLOCK, COATING_RULES, DESTROY_DROP,
|
||||
)
|
||||
|
||||
# ---- 统一分发器 ----
|
||||
from ...service.FeatureDispatcher import FeatureDispatcher
|
||||
|
||||
|
||||
class ShicaiService(BlueFoxServerSystem):
|
||||
"""
|
||||
乡野食材·切配与裹粉 右键转换引擎
|
||||
"""
|
||||
|
||||
def __init__(self, namespace, systemName):
|
||||
super(ShicaiService, self).__init__(namespace, systemName)
|
||||
print "===== ShicaiService init ====="
|
||||
|
||||
# ---- 切分链映射: 方块名 -> (链, 索引) O(1) ----
|
||||
self.chopMap = {}
|
||||
self.featureBlocks = set()
|
||||
for chain in CHOP_CHAINS:
|
||||
for i, b in enumerate(chain["blocks"]):
|
||||
self.chopMap[b] = (chain, i)
|
||||
self.featureBlocks.add(b)
|
||||
|
||||
# ---- 蒜末方块 + 面粉块 ----
|
||||
self.featureBlocks.add(GARLIC_BLOCK)
|
||||
self.featureBlocks.add(FLOUR_BLOCK)
|
||||
|
||||
# ---- 裹粉规则映射: 手持物品名 -> 规则 ----
|
||||
self.coatingMap = {}
|
||||
for r in COATING_RULES:
|
||||
self.coatingMap[r["item"]] = r
|
||||
|
||||
# ---- 蒜末切菜计数 {(dim,x,y,z): n} ----
|
||||
self.garlicChop = {}
|
||||
|
||||
# ---- 右键冷却表 ----
|
||||
self.cooldown = {}
|
||||
|
||||
# ---- 注册到统一分发器 ----
|
||||
FeatureDispatcher.register(self)
|
||||
|
||||
# ============================================================================
|
||||
# 一、给 FeatureDispatcher 的接口
|
||||
# ============================================================================
|
||||
|
||||
def getFeatureBlocks(self):
|
||||
"""返回本功能管辖的所有右键方块名集合"""
|
||||
return self.featureBlocks
|
||||
|
||||
def getItemUseOnRules(self):
|
||||
"""手持物品右键方块表面不需要单独路由, 返回空"""
|
||||
return {}
|
||||
|
||||
def handleDestroy(self, args):
|
||||
"""由 FeatureDispatcher 转发的"玩家左键破坏方块"入口。
|
||||
摆在地上的切配方块(切胡萝卜/切土豆/切青菜/葱花) 被左键打碎 ->
|
||||
掉落对应的原版食材(胡萝卜/土豆/青菜/葱), 并清空方块。
|
||||
返回 True=处理了; False=不属本功能管。"""
|
||||
blockName = args.get("fullName") or args.get("blockName")
|
||||
itemName = DESTROY_DROP.get(blockName)
|
||||
if not itemName:
|
||||
return False
|
||||
playerId = args.get("playerId")
|
||||
x, y, z = args.get("x"), args.get("y"), args.get("z")
|
||||
dim = comp.CreateDimension(playerId).GetEntityDimensionId()
|
||||
|
||||
# 取消默认破坏+默认掉落(不让切配方块本身掉出来)
|
||||
args['cancel'] = True
|
||||
args['spawnResources'] = False
|
||||
|
||||
# 清空方块为空气(aux 强制 0, 保证定向变体正常清除)
|
||||
try:
|
||||
comp.CreateBlockInfo(LevelId).SetBlockNew(
|
||||
(x, y, z), blockDict={"name": "minecraft:air", "aux": 0},
|
||||
oldBlockHandling=0, dimensionId=dim)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 掉落原版食材
|
||||
try:
|
||||
self.CreateEngineItemEntity(
|
||||
{"itemName": itemName, "count": 1, "auxValue": 0},
|
||||
dim, (x, y + 0.5, z))
|
||||
except Exception:
|
||||
pass
|
||||
return 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
|
||||
|
||||
# ---- 菜刀切分 ----
|
||||
if blockName in self.chopMap:
|
||||
return self._handleChop(blockName, playerId, pos, dim, itemDict, itemName, key)
|
||||
|
||||
# ---- 蒜末 ----
|
||||
if blockName == GARLIC_BLOCK:
|
||||
return self._handleGarlic(playerId, pos, dim, itemDict, itemName, key)
|
||||
|
||||
# ---- 裹粉 ----
|
||||
if blockName == FLOUR_BLOCK:
|
||||
return self._handleCoating(playerId, pos, dim, itemDict, itemName, key)
|
||||
|
||||
return False
|
||||
|
||||
# ============================================================================
|
||||
# 二、菜刀切分配
|
||||
# ============================================================================
|
||||
|
||||
def _handleChop(self, blockName, playerId, pos, dim, itemDict, itemName, key):
|
||||
if itemName != CLEAVER_ITEM:
|
||||
return False
|
||||
chain, idx = self.chopMap[blockName]
|
||||
blocks = chain["blocks"]
|
||||
if not self.checkCooldown(key, 0.3):
|
||||
return True
|
||||
if idx < len(blocks) - 1:
|
||||
# 逐级推进到下一刀
|
||||
self.replaceBlock(pos, dim, blocks[idx + 1], playerId)
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(playerId, "§a继续切配…")
|
||||
else:
|
||||
# 最后一级再切 -> 掉碎 + 变空气
|
||||
self.clearBlock(pos, dim)
|
||||
self.dropItems(dim, pos, [chain["drop"]])
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(
|
||||
playerId, chain.get("tip", "§a切好了"))
|
||||
return True
|
||||
|
||||
# ============================================================================
|
||||
# 三、蒜末(大蒜 + 菜刀右键三次 -> 掉 16 蒜末)
|
||||
# ============================================================================
|
||||
|
||||
def _handleGarlic(self, playerId, pos, dim, itemDict, itemName, key):
|
||||
if itemName != CLEAVER_ITEM:
|
||||
return False
|
||||
if not self.checkCooldown(key, 0.3):
|
||||
return True
|
||||
gkey = (dim, pos[0], pos[1], pos[2])
|
||||
n = self.garlicChop.get(gkey, 0) + 1
|
||||
if n >= GARLIC_CHOP_COUNT:
|
||||
self.clearBlock(pos, dim)
|
||||
self.dropItems(dim, pos, [GARLIC_DROP])
|
||||
self.garlicChop.pop(gkey, None)
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(playerId, "§a切好了蒜末")
|
||||
else:
|
||||
self.garlicChop[gkey] = n
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(
|
||||
playerId, "§a切大蒜中…(%d/%d)" % (n, GARLIC_CHOP_COUNT))
|
||||
return True
|
||||
|
||||
# ============================================================================
|
||||
# 四、裹粉(生食材右键面粉块 -> 掉裹粉物品)
|
||||
# ============================================================================
|
||||
|
||||
def _handleCoating(self, playerId, pos, dim, itemDict, itemName, key):
|
||||
rule = self.coatingMap.get(itemName)
|
||||
if not rule:
|
||||
return False
|
||||
need = rule.get("count", 1)
|
||||
if itemDict is not None and (itemDict.get("count") or 0) < need:
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(
|
||||
playerId, "§c数量不足,需要 %d 个" % need)
|
||||
return True
|
||||
if not self.checkCooldown(key, 0.5):
|
||||
return True
|
||||
self.consumeItem(playerId, itemDict, need)
|
||||
self.clearBlock(pos, dim)
|
||||
self.dropItems(dim, pos, [rule["drop"]])
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(playerId, "§a裹粉完成")
|
||||
return True
|
||||
|
||||
# ============================================================================
|
||||
# 五、工具方法:获取玩家主手物品
|
||||
# ============================================================================
|
||||
|
||||
def getCarriedItem(self, playerId):
|
||||
itemComp = comp.CreateItem(playerId)
|
||||
return itemComp.GetPlayerItem(
|
||||
serverApi.GetMinecraftEnum().ItemPosType.CARRIED, 0, True)
|
||||
|
||||
# ============================================================================
|
||||
# 六、工具方法:消耗物品
|
||||
# ============================================================================
|
||||
|
||||
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 clearBlock(self, pos, dim):
|
||||
"""把方块清空为空气(切完拿碎/裹粉耗掉面粉块)"""
|
||||
comp.CreateBlockInfo(LevelId).SetBlockNew(
|
||||
pos, blockDict={"name": "minecraft:air", "aux": 0},
|
||||
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
|
||||
+1
@@ -0,0 +1 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
+25
@@ -53,6 +53,31 @@ ITEM_USE_ON_RULES = [
|
||||
"consume": 1,
|
||||
"tip": "§a已放置死鳕鱼",
|
||||
},
|
||||
# ---- 蔬菜·切配: 原版食材右键放置 -> 摆放地上的切配方块 ----
|
||||
{
|
||||
"item": "minecraft:carrot", # 原版胡萝卜
|
||||
"target": "rtdd:cutcarrot_0", # 切胡萝卜(摆放地上)
|
||||
"consume": 1,
|
||||
"tip": "§a已放置胡萝卜,可手持菜刀切配",
|
||||
},
|
||||
{
|
||||
"item": "minecraft:potato", # 原版土豆
|
||||
"target": "rtdd:cutpotato_0", # 切土豆(摆放地上)
|
||||
"consume": 1,
|
||||
"tip": "§a已放置土豆,可手持菜刀切配",
|
||||
},
|
||||
{
|
||||
"item": "rtdd:qingcai", # 青菜(整颗)
|
||||
"target": "rtdd:cutvegetable_0", # 切青菜(摆放地上)
|
||||
"consume": 1,
|
||||
"tip": "§a已放置青菜,可手持菜刀切配",
|
||||
},
|
||||
{
|
||||
"item": "rtdd:scallions", # 葱
|
||||
"target": "rtdd:cutscallions_1", # 葱花_1
|
||||
"consume": 1,
|
||||
"tip": "§a已放置葱,可手持菜刀切分",
|
||||
},
|
||||
]
|
||||
|
||||
# ---- 二、盘子转换: 手持原版食物右键 空盘子(plate_0), 盘子变为对应成品盘 ----
|
||||
|
||||
Reference in new issue
Block a user