吃 3 功能
This commit is contained in:
1 parent
4176eb293c
commit
fb817b5d34
12 files changed
+1021
-118
No files matched your search
+218
@@ -0,0 +1,218 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
================================================================================
|
||||
【总食用】(shiyongfood) 服务 —— 所有成品的"吃"
|
||||
================================================================================
|
||||
【入口(由 FeatureDispatcher 统一转发)】
|
||||
1. handleBlockUse 空手右键 已放置的成品方块 -> 吃一级
|
||||
- 有 target: 方块转换成下一级(半份/下一份)
|
||||
- 无 target: 方块完全消耗(消失) + 掉落容器(脏盘子/木碗/玻璃杯/支杆)
|
||||
2. handleItemUseOn 手持 饭团/水煮蛋/豆腐 右键方块表面 -> 直接吃(消耗1个)
|
||||
3. handleItemTryUse 手持 饭团/水煮蛋/豆腐 长按右键(空中使用) -> 直接吃(消耗1个)
|
||||
|
||||
【数值】
|
||||
- 饱食度: SetPlayerHunger(0~20), 1点 = 半个鸡腿(原版饥饿值)
|
||||
- 效果: AddEffectToEntity(effectName, 时长秒, amplifier)
|
||||
amplifier = 等级-1 (效果I=0, 效果II=1, ...)
|
||||
- 冷却: 0.4 秒(防长按右键连吃刷屏)
|
||||
================================================================================
|
||||
"""
|
||||
import time
|
||||
import mod.server.extraServerApi as serverApi
|
||||
|
||||
ServerSystem = serverApi.GetServerSystemCls() # 服务端系统基类
|
||||
comp = serverApi.GetEngineCompFactory() # 组件工厂
|
||||
|
||||
from ...BlueFoxTools.SpecialFunciton.BlueFoxSystem import BlueFoxServerSystem
|
||||
from ...BlueFoxTools.ToolsConfig import LevelId
|
||||
from ..ShiyongfoodData import EAT_RULE_MAP, TRY_USE_RULES, EFFECT_CN
|
||||
|
||||
|
||||
class ShiyongfoodService(BlueFoxServerSystem):
|
||||
"""总食用服务: 所有成品右键吃(方块吃 + 手持物品直接吃)"""
|
||||
|
||||
def __init__(self, namespace, systemName):
|
||||
BlueFoxServerSystem.__init__(self, namespace, systemName)
|
||||
self.eatBlocks = set(EAT_RULE_MAP.keys()) # 可吃的成品方块
|
||||
self.tryUseItems = set(TRY_USE_RULES.keys()) # 手持直接吃的物品
|
||||
self.cooldown = {} # 右键冷却
|
||||
|
||||
# ---- 注册到统一分发器: 右键方块 + 手持右键表面 + 手持直接吃 ----
|
||||
from ...service.FeatureDispatcher import FeatureDispatcher
|
||||
FeatureDispatcher.register(self)
|
||||
FeatureDispatcher.registerTryUse(self)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 分发器路由表(FeatureDispatcher 调用)
|
||||
# ------------------------------------------------------------------
|
||||
def getFeatureBlocks(self):
|
||||
"""成品方块(空手右键吃)"""
|
||||
return self.eatBlocks
|
||||
|
||||
def getItemUseOnRules(self):
|
||||
"""手持吃物品也注册进"右键方块表面"路由(点方块表面直接吃)"""
|
||||
return {item: True for item in self.tryUseItems}
|
||||
|
||||
def getTryUseRules(self):
|
||||
"""手持直接吃(长按右键/空中使用)"""
|
||||
return {item: True for item in self.tryUseItems}
|
||||
|
||||
# ====================================================================
|
||||
# 入口1: 空手右键 已放置的成品方块 -> 吃一级
|
||||
# ====================================================================
|
||||
def handleBlockUse(self, args):
|
||||
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 itemName and itemName != "minecraft:air":
|
||||
return False
|
||||
|
||||
rule = EAT_RULE_MAP.get(blockName)
|
||||
if not rule:
|
||||
return False
|
||||
if not self.checkCooldown(key, 0.4):
|
||||
return True
|
||||
|
||||
self._applyFood(playerId, rule.get("hunger", 0), rule.get("effects", []))
|
||||
target = rule.get("target")
|
||||
if target:
|
||||
# 方块转换成下一级(半份/下一份)
|
||||
self._replaceBlock(playerId, pos, dim, target)
|
||||
else:
|
||||
# 完全消耗消失 + 掉落容器
|
||||
self._clearBlock(playerId, pos, dim)
|
||||
drop = rule.get("drop")
|
||||
if drop:
|
||||
self.dropItem(dim, pos, drop)
|
||||
self._notify(playerId, rule)
|
||||
return True
|
||||
|
||||
# ====================================================================
|
||||
# 入口2: 手持 饭团/水煮蛋/豆腐 右键方块表面 -> 直接吃
|
||||
# ====================================================================
|
||||
def handleItemUseOn(self, args):
|
||||
itemName = args.get("itemName")
|
||||
rule = TRY_USE_RULES.get(itemName)
|
||||
if not rule:
|
||||
return False
|
||||
playerId = args.get("playerId") or args.get("entityId")
|
||||
return self._eatItemInHand(playerId, itemName, rule)
|
||||
|
||||
# ====================================================================
|
||||
# 入口3: 手持 饭团/水煮蛋/豆腐 长按右键(空中使用) -> 直接吃
|
||||
# ====================================================================
|
||||
def handleItemTryUse(self, args):
|
||||
itemName = args.get("itemName")
|
||||
rule = TRY_USE_RULES.get(itemName)
|
||||
if not rule:
|
||||
return False
|
||||
playerId = args.get("playerId") or args.get("entityId")
|
||||
return self._eatItemInHand(playerId, itemName, rule)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 手持吃公共: 消耗1个 + 回复饱食度 + 效果(无容器掉落)
|
||||
# ------------------------------------------------------------------
|
||||
def _eatItemInHand(self, playerId, itemName, rule):
|
||||
if not playerId:
|
||||
return False
|
||||
if not self.checkCooldown(("p", playerId), 0.4):
|
||||
return True
|
||||
itemDict = self.getCarriedItem(playerId)
|
||||
if not itemDict or itemDict.get("newItemName") != itemName:
|
||||
return False
|
||||
count = itemDict.get("count", 1)
|
||||
comp.CreateItem(playerId).SetEntityItem(
|
||||
serverApi.GetMinecraftEnum().ItemPosType.CARRIED,
|
||||
{"itemName": itemName,
|
||||
"count": max(count - 1, 0),
|
||||
"auxValue": itemDict.get("newAuxValue", 0),
|
||||
"userData": itemDict.get("userData", {})})
|
||||
self._applyFood(playerId, rule.get("hunger", 0), rule.get("effects", []))
|
||||
self._notify(playerId, rule)
|
||||
return True
|
||||
|
||||
# ====================================================================
|
||||
# 工具: 回复饱食度 + 增益效果
|
||||
# ====================================================================
|
||||
def _applyFood(self, playerId, hunger, effects):
|
||||
try:
|
||||
# 饱食度【在现有值上累加】(不是覆盖): 当前值 + 回复值, 上限20点
|
||||
attrComp = comp.CreateAttr(playerId)
|
||||
cur = attrComp.GetPlayerHunger()
|
||||
if cur is None:
|
||||
cur = 0
|
||||
newVal = max(0.0, min(float(cur) + float(hunger), 20.0))
|
||||
attrComp.SetPlayerHunger(newVal)
|
||||
except Exception:
|
||||
pass
|
||||
if effects:
|
||||
try:
|
||||
effectComp = comp.CreateEffect(LevelId)
|
||||
for name, dur, lvl in effects:
|
||||
# 效果I -> amplifier 0, 效果II -> amplifier 1 ...
|
||||
effectComp.AddEffectToEntity(playerId, name, dur, lvl - 1, False)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ====================================================================
|
||||
# 工具: 替换/清除方块
|
||||
# ====================================================================
|
||||
def _replaceBlock(self, creator, pos, dim, blockName):
|
||||
comp.CreateBlockInfo(creator).SetBlockNew(
|
||||
pos, blockDict={"name": blockName, "aux": 0},
|
||||
oldBlockHandling=0, dimensionId=dim)
|
||||
|
||||
def _clearBlock(self, creator, pos, dim):
|
||||
comp.CreateBlockInfo(creator).SetBlockNew(
|
||||
pos, blockDict={"name": "minecraft:air", "aux": 0},
|
||||
oldBlockHandling=0, dimensionId=dim)
|
||||
|
||||
# ====================================================================
|
||||
# 工具: 以掉落物形式生成物品(出现在方块上方)
|
||||
# ====================================================================
|
||||
def dropItem(self, dim, pos, itemName, count=1, aux=0):
|
||||
try:
|
||||
itemDict = {"itemName": itemName, "count": count, "auxValue": aux}
|
||||
self.CreateEngineItemEntity(itemDict, dim, (pos[0], pos[1] + 0.5, pos[2]))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ====================================================================
|
||||
# 工具: 食用提示
|
||||
# ====================================================================
|
||||
def _notify(self, playerId, rule):
|
||||
try:
|
||||
hunger = rule.get("hunger", 0)
|
||||
msg = "\u00a7a回复 %d 点饱食度" % hunger
|
||||
effects = rule.get("effects", [])
|
||||
if effects:
|
||||
parts = []
|
||||
for name, dur, lvl in effects:
|
||||
cn = EFFECT_CN.get(name, name)
|
||||
parts.append("%s%s(%d秒)" % (cn, self._roman(lvl), dur))
|
||||
msg += ", 获得 " + " ".join(parts)
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(playerId, msg)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def _roman(lvl):
|
||||
return {1: "I", 2: "II", 3: "III", 4: "IV", 5: "V"}.get(lvl, "")
|
||||
|
||||
# ====================================================================
|
||||
# 工具: 冷却检查(0.4秒, 防长按右键连吃)
|
||||
# ====================================================================
|
||||
def checkCooldown(self, key, cd=0.4):
|
||||
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 -*-
|
||||
Reference in new issue
Block a user