Files
rtdd/behavior_pack_v8jz0zSR/Script_NeteaseModousIY5aSF/xiangyemod/service/FeatureDispatcher.py
T

186 lines
8.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""
================================================================================
统一事件分发器(服务端)—— 方案A核心
================================================================================
【为什么需要它】
以前每个功能(做菜/工具切换)都各自监听 ServerBlockUseEvent,
玩家每次右键,所有系统都会被触发一遍、各自跑一次数据库拦截判断,
功能越多损耗越大。
【它做什么】
FeatureDispatcher 是"唯一"监听右键相关事件的服务端系统:
- ServerBlockUseEvent 玩家右键方块
- ServerItemUseOnEvent 手持物品右键方块表面(如放置生鸡肉)
- ServerItemTryUseEvent 拦截喝药水/吃食物等默认行为
各功能服务在初始化时通过 FeatureDispatcher.register(self) 上报:
- 自己管辖的方块名集合 → 构建 方块名→服务 的 O(1) 路由表
- 自己处理的手持物品 → 构建 物品名→服务 的 O(1) 路由表
事件进来后,分发器先用 blockName / itemName 在路由表里 O(1) 定位到
唯一的那个功能服务,再调用它的 handleBlockUse / handleItemUseOn。
→ 每个右键事件只命中一个数据库,其余功能的数据库根本不会被查询。
【如何新增一个功能】
1. 新建 xxx/xxxData.py 写转换规则
2. 新建 xxx/service/XxxService.py(继承 BlueFoxServerSystem):
- __init__ 里构建自己的规则字典
- 实现 getFeatureBlocks() / getItemUseOnRules()
- 实现 handleBlockUse(args) / handleItemUseOn(args)
- 调用 FeatureDispatcher.register(self)
3. 在 modMain.py import 这个服务类即可
================================================================================
"""
import mod.server.extraServerApi as serverApi
# ---- 网易API基础对象 ----
ServerSystem = serverApi.GetServerSystemCls() # 服务端系统基类
comp = serverApi.GetEngineCompFactory() # 组件工厂
# ---- 继承 BlueFox 框架的系统基类 ----
from ...BlueFoxTools.SpecialFunciton.BlueFoxSystem import BlueFoxServerSystem
class FeatureDispatcher(BlueFoxServerSystem):
"""
统一事件分发器
【类级注册表(所有功能服务共享同一份路由表)】
blockOwner = {方块名: 功能服务实例}
blockSet = {方块名} # 全部功能方块集合
itemUseOnOwner = {物品名: 功能服务实例}
itemUseOnSet = {物品名} # 全部"手持物品右键方块表面"集合
"""
# ---- 类级共享路由表(用类变量,任何实例都能读写) ----
blockOwner = {}
blockSet = set()
itemUseOnOwner = {}
itemUseOnSet = set()
@classmethod
def register(cls, service):
"""
功能服务初始化时调用,把管辖的方块和物品注册进路由表。
同一方块/物品只会归属最后一个注册的服务(一般不会冲突)。
"""
# 右键方块路由:方块名 → 服务
for block in service.getFeatureBlocks():
cls.blockOwner[block] = service
cls.blockSet.add(block)
# 手持物品右键方块表面路由:物品名 → 服务
for itemName in service.getItemUseOnRules():
cls.itemUseOnOwner[itemName] = service
cls.itemUseOnSet.add(itemName)
def __init__(self, namespace, systemName):
"""
初始化:注册三个事件监听。
注意:本类自身不注册任何功能方块,只负责把事件分发给已注册的服务。
"""
super(FeatureDispatcher, self).__init__(namespace, systemName)
print "===== FeatureDispatcher init ====="
self._cancelItemUse = {} # 将要取消下一次物品使用的玩家ID集合(防止喝药水等)
self.ListenEvent()
def Destroy(self):
print "===== FeatureDispatcher Destroy ====="
self.UnListenEvent()
# ============================================================================
# 事件注册与注销
# ============================================================================
def ListenEvent(self):
"""
注册三个事件:
1. ServerBlockUseEvent —— 玩家右键方块(所有功能的右键转换入口)
2. ServerItemUseOnEvent —— 手持物品右键方块表面(如放置生鸡肉)
3. ServerItemTryUseEvent —— 玩家尝试使用物品(拦截喝药水/吃食物等默认行为)
"""
self.ListenForEvent(serverApi.GetEngineNamespace(),
serverApi.GetEngineSystemName(),
"ServerBlockUseEvent", self, self.OnBlockUse)
self.ListenForEvent(serverApi.GetEngineNamespace(),
serverApi.GetEngineSystemName(),
"ServerItemUseOnEvent", self, self.OnItemUseOn)
self.ListenForEvent(serverApi.GetEngineNamespace(),
serverApi.GetEngineSystemName(),
"ServerItemTryUseEvent", self, self.OnItemTryUse)
def UnListenEvent(self):
self.UnListenForEvent(serverApi.GetEngineNamespace(),
serverApi.GetEngineSystemName(),
"ServerBlockUseEvent", self, self.OnBlockUse)
self.UnListenForEvent(serverApi.GetEngineNamespace(),
serverApi.GetEngineSystemName(),
"ServerItemUseOnEvent", self, self.OnItemUseOn)
self.UnListenForEvent(serverApi.GetEngineNamespace(),
serverApi.GetEngineSystemName(),
"ServerItemTryUseEvent", self, self.OnItemTryUse)
# ============================================================================
# 主入口1:玩家右键方块
# ============================================================================
def OnBlockUse(self, args):
"""
玩家右键方块时触发。
用被右键的方块名 O(1) 定位到唯一的功能服务,转发给它的 handleBlockUse。
服务返回 True = 处理成功 → 取消默认行为(如防止喝药水),并标记拦截下一次物品使用
服务返回 False = 当前组合无匹配规则 → 交还默认行为
"""
blockName = args.get("blockName")
service = self.blockOwner.get(blockName)
if not service:
# 这个方块不属于任何已注册的功能 → 交给原版/其他模组处理
return
handled = service.handleBlockUse(args)
if handled:
args['cancel'] = True
playerId = args.get("playerId")
self._cancelItemUse[playerId] = True
# ============================================================================
# 主入口2:手持物品右键方块表面
# ============================================================================
def OnItemUseOn(self, args):
"""
手持物品右键某个方块表面时触发(如手持原版生鸡肉右键地面)。
用手持物品名 O(1) 定位到唯一的功能服务,转发给它的 handleItemUseOn。
注意:取消"使用物品于方块"的字段是 ret(不是 cancel),
官方要求双端设置才能真正取消默认行为。本分发器已在服务端设 ret=True,
服务端不会执行默认放置/使用逻辑;客户端如需完美取消动画,
可再增加一个监听 ClientItemUseOnEvent 的客户端配对系统。
"""
itemName = args.get("itemName")
service = self.itemUseOnOwner.get(itemName)
if not service:
return
handled = service.handleItemUseOn(args)
if handled:
args['ret'] = True
playerId = args.get("playerId")
self._cancelItemUse[playerId] = True
# ============================================================================
# 主入口3:拦截物品使用(防止喝药水/吃食物等默认行为)
# ============================================================================
def OnItemTryUse(self, args):
"""
玩家尝试使用物品(喝药水、吃食物等)时触发。
如果该玩家刚被标记为"取消下一次物品使用"(_cancelItemUse),
就取消这次默认行为,避免右键转换方块时误喝药水。
"""
playerId = args.get("playerId")
if self._cancelItemUse.pop(playerId, False):
args['cancel'] = True