搬运了原版食材 死亡生物 手办 功能实现 小bug 1
This commit is contained in:
1 parent
4f032234c0
commit
213c74cb55
12 files changed
+1304
No files matched your search
+203
@@ -0,0 +1,203 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
================================================================================
|
||||
手办·右键转换引擎(服务端)
|
||||
================================================================================
|
||||
只处理"手办"(xy_shouban) 分类下的【右键切换型】转换:
|
||||
盲盒开盒、猫/狐狸手办循环切换。
|
||||
全部为即时右键转换, 无计时, 因此只有一个服务类, 不需要拆分 TimerService。
|
||||
|
||||
【事件监听在哪?】
|
||||
本类【不】监听任何事件!
|
||||
所有事件由 FeatureDispatcher(xiangyemod/service/FeatureDispatcher.py)统一监听:
|
||||
- ServerBlockUseEvent → OnBlockUse → 按 blockOwner 路由到本类 handleBlockUse
|
||||
本类只实现被分发器调用的接口方法, 不关心事件来源。
|
||||
|
||||
【本类怎么做(自上而下的方法系列)】
|
||||
handleBlockUse ← 入口:分发器转发右键方块事件
|
||||
├─ 空手确认 ← 盲盒/循环都要求空手
|
||||
├─ checkCooldown← 连点冷却(防刷手办)
|
||||
├─ openBlindBox ← 盲盒: 换为"开过"盒 + 随机掉落 1 个手办 + 提示
|
||||
└─ replaceBlock ← 猫/狐狸: 逐级切到链上下一个形态
|
||||
================================================================================
|
||||
"""
|
||||
import time
|
||||
import random
|
||||
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 ..ShoubanData import (
|
||||
BLIND_BOX_SOURCE, BLIND_BOX_TARGET,
|
||||
BLIND_BOX_POOL, FIGURINE_NAMES, CYCLE_CHAINS,
|
||||
)
|
||||
|
||||
# ---- 统一分发器(本类把自己注册进去, 让分发器把右键事件转发过来) ----
|
||||
from ...service.FeatureDispatcher import FeatureDispatcher
|
||||
|
||||
|
||||
class ShoubanService(BlueFoxServerSystem):
|
||||
"""
|
||||
手办·右键转换引擎
|
||||
|
||||
【核心数据结构】
|
||||
shoubanBlockSet = {方块名, ...} # 管辖方块(盲盒 + 猫/狐狸链上所有方块)
|
||||
cooldown = {key: 时间戳} # 连点冷却表
|
||||
"""
|
||||
|
||||
def __init__(self, namespace, systemName):
|
||||
"""
|
||||
初始化:构建管辖方块集合, 并注册到统一分发器。
|
||||
"""
|
||||
super(ShoubanService, self).__init__(namespace, systemName)
|
||||
print "===== ShoubanService init ====="
|
||||
|
||||
# ---- 管辖方块: 盲盒(未开) + 猫/狐狸循环链上所有方块 ----
|
||||
self.shoubanBlockSet = set([BLIND_BOX_SOURCE]) | set(CYCLE_CHAINS.keys())
|
||||
|
||||
# ---- 右键冷却表 ----
|
||||
self.cooldown = {}
|
||||
|
||||
# ---- 注册到统一分发器 ----
|
||||
FeatureDispatcher.register(self)
|
||||
|
||||
# ============================================================================
|
||||
# 一、给 FeatureDispatcher 的接口
|
||||
# ============================================================================
|
||||
|
||||
def getFeatureBlocks(self):
|
||||
"""返回本功能管辖的所有方块名集合(右键路由用)"""
|
||||
return self.shoubanBlockSet
|
||||
|
||||
def getItemUseOnRules(self):
|
||||
"""返回"手持物品右键方块表面"的规则(手办分类没有, 返回空)"""
|
||||
return {}
|
||||
|
||||
def handleBlockUse(self, args):
|
||||
"""
|
||||
由 FeatureDispatcher 转发的右键方块入口。
|
||||
只有 blockName 在本功能的方块集合里才会被调用。
|
||||
|
||||
盲盒开盒 / 手办循环均要求【空手】右键:
|
||||
- 盲盒: 空手右键 → 换为"开过"盒 + 随机掉落 1 个手办
|
||||
- 猫/狐狸: 空手右键 → 逐级切到链上下一个形态
|
||||
|
||||
返回 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)
|
||||
itemName = itemDict.get("newItemName") if itemDict else None
|
||||
if itemName and itemName != "minecraft:air":
|
||||
return False
|
||||
|
||||
# ---- 连点冷却 ----
|
||||
if not self.checkCooldown(key, 0.5):
|
||||
return True
|
||||
|
||||
# ---- 盲盒开盒 ----
|
||||
if blockName == BLIND_BOX_SOURCE:
|
||||
self.openBlindBox(playerId, pos, dim)
|
||||
return True
|
||||
|
||||
# ---- 猫/狐狸手办循环切换 ----
|
||||
if blockName in CYCLE_CHAINS:
|
||||
self.replaceBlock(pos, dim, CYCLE_CHAINS[blockName], playerId)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
# ============================================================================
|
||||
# 二、盲盒开盒
|
||||
# ============================================================================
|
||||
|
||||
def openBlindBox(self, playerId, pos, dim):
|
||||
"""
|
||||
盲盒开盒:换为"开过"盒, 随机掉落 1 个手办方块, 提示开出内容。
|
||||
"""
|
||||
# 随机开出一个手办
|
||||
fig = random.choice(BLIND_BOX_POOL)
|
||||
# 盒子变为"开过"
|
||||
self.replaceBlock(pos, dim, BLIND_BOX_TARGET, playerId)
|
||||
# 掉落手办
|
||||
self.dropItems(dim, pos, [{"name": fig, "count": 1}])
|
||||
# 提示开出内容
|
||||
name = FIGURINE_NAMES.get(fig, "手办")
|
||||
comp.CreateMsg(playerId).NotifyOneMessage(playerId, "§a盲盒开出了" + name + "!")
|
||||
|
||||
# ============================================================================
|
||||
# 三、工具方法:获取玩家主手物品
|
||||
# ============================================================================
|
||||
|
||||
def getCarriedItem(self, playerId):
|
||||
itemComp = comp.CreateItem(playerId)
|
||||
return itemComp.GetPlayerItem(
|
||||
serverApi.GetMinecraftEnum().ItemPosType.CARRIED, 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.
Reference in new issue
Block a user