烧烤 动物养殖 分类 功能实现1

This commit is contained in:
wenhe committed 2026-09-01 22:18:06 +08:00
1 parent 98335837dd
commit eac9409571
16 files changed
+1493 -5

No files matched your search

@@ -0,0 +1,185 @@
# -*- 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