入口脚本
在游戏运行时,将自动扫描行为包(Behavior-Pack,简称 BH,请牢记此缩写)中的 modMain.py
文件,并将其作为入口脚本执行。
modMain入口
modMain.py
是入口模块,其具体位置并未被强制规定,但通常建议将其放置在 BH/<符合命名规范的项目名称>/modMain.py
路径,以便于管理和维护。
基本内容
通常来说一个官方的入口加载逻辑有以下内容
python
# -*- coding: utf-8 -*-
from mod.common.mod import Mod
import mod.server.extraServerApi as serverApi
import mod.client.extraClientApi as clientApi
@Mod.Binding(name = "<符合命名规范的MOD名称>", version = "1.0.0")
class MyMod(object): # 类名是什么无所谓 网易历史遗留的加载器扫描方式
@Mod.InitServer()
def serverInit(self):
pass
@Mod.InitClient()
def clientInit(self):
pass
@Mod.DestroyServer()
def serverDestroy(self):
pass
@Mod.DestroyClient()
def clientDestroy(self):
pass
编码问题
由于网易采用的Python版本是2.7.18
默认仅支持ASCII源代码字符,若需中文支持请在顶部使用声明语句。
python
# -*- coding: utf-8 -*-
模块解析
静态类 mod.common.mod.Mod
,通常来说需要其中的@Mod.xxx
装饰器,用来标记Mod加载逻辑。
python
from mod.common.mod import Mod
端侧API serverApi
clientApi
,包含服务端和客户端所需的游戏接口
,如您所见 MC是网络游戏
设计模式。
python
# 使用 as 语句重新命名别名 方便调用
import mod.server.extraServerApi as serverApi
import mod.client.extraClientApi as clientApi
MOD加载流程
1.扫描加载类
MOD加载器将自动搜索所有@Mod.Binding
标记的类,并在对应的服务端
或客户端
线程执行
python
@Mod.Binding(name = "...", version = "1.0.0")
class MyMod_1(object):
# MOD加载器会自动构造该class
...
@Mod.Binding(name = "...", version = "1.0.0")
class MyMod_2(object):
# 同上
...
class OtherCls(object):
# 无@Mod.Binding修饰 不会被自动构造执行
pass
...
2.线程环境执行
@Mod.InitServer
用于标记是服务端
的执行入口,@Mod.InitClient
则是客户端
的执行入口
python
@Mod.Binding(name = "...", version = "1.0.0")
class MyMod(object):
# 标记为端侧的入口执行方法,用于初始化您的MOD业务
@Mod.InitServer()
def serverInit(self):
# 服务端加载时执行
pass
@Mod.InitClient()
def clientInit(self):
# 客户端加载时执行
pass
# 同理,对应端侧关闭时的执行方法(析构),可用于作回收逻辑(若有需要)。
@Mod.DestroyServer()
def serverDestroy(self):
pass
@Mod.DestroyClient()
def clientDestroy(self):
pass
注意:类名/方法名取什么都无所谓,扫描器只识别特定标记(注解)。
游戏线程环境
环境类型 | 描述 |
---|---|
服务端 | 处理游戏的真实数据,如生物血量、位置、属性数据、物理引擎等。 |
客户端 | 负责画面渲染、用户操作、GUI 等逻辑,如渲染服务端传递的生物位置信息。 |
------------ | ------------------------------------------------ |
单人模式 | 房主同时加载服务端与客户端,模拟网络环境。 |
联机模式 | 房主加载服务端与客户端,其他成员仅加载客户端。 |
网络游戏 | 服务端由网易服务器运行,所有玩家仅加载客户端。 |
第一个MOD项目
在了解了以上信息后,接下来可以进入正式开发环节。此处我们假设项目所在路径: BH/TestMod/modMain.py
注册服务端业务
通俗点来说就是加载特定的业务文件
python
# 注意@Mod.Binding的参数,若有多个MOD持有相同的name只会加载版本号最高的一代
# 大多数情况下我们并不需要这个功能,因此请确保您的名称独一无二。
@Mod.Binding(name = "TestMod", version = "1.0.0")
class MyMod(object):
# @Mod.InitServer 只有服务端环境的持有者会加载这部分
@Mod.InitServer()
def serverInit(self):
# 使用serverApi注册(加载)一个系统类
serverApi.RegisterSystem("test", "ser1", "TestMod.Server.MyServer")
参数说明:
- serverApi.RegisterSystem("命名空间", "系统名", "模块路径.类名"):
- 命名空间: 用于区分不同模块的标识,例如
minecraft:zombie
中的minecraft
。 - 系统名: 系统的唯一名称,用于标识注册的系统,例如
zombie
。 - 模块路径.类名: 从 BH 目录开始,使用点号分隔的文件路径和类名。例如
TestMod.Server.MyServer
。
- 命名空间: 用于区分不同模块的标识,例如
示例解析:
- 模块路径:
TestMod(文件夹).Server(文件).MyServer(类名)
- 对应文件路径:
TestMod/Server.py
中的class MyServer
。
- 对应文件路径:
- 命名空间: 早期用于模块隔离的设计,通过命名空间+名称组合减少重复的可能性。
- 注意: 网易的 Python 环境未实现严格隔离,因此需要通过命名区分模块,避免多 MOD 冲突导致未定义行为。
编写服务端业务
根据我们的注册路径TestMod.Server.MyServer
新建对应的文件并编写MyServer
类
python
# -*- coding: utf-8 -*-
# 文件:BH/TestMod/Server.py
import mod.server.extraServerApi as serverApi
ServerSystem = serverApi.GetServerSystemCls() # 获取服务端基类
# 定义MyServer类 正如注册参数上所写
class MyServer(ServerSystem):
def __init__(self, namespace, systemName):
ServerSystem.__init__(self, namespace, systemName)
print("服务端业务初始化")
# 系统类相关讲解请见后文
...
总结
MOD 加载器的核心流程如下:
- 加载器扫描
modMain.py
文件。 - 执行端侧初始化/销毁方法(服务端或客户端)。
- 加载具体业务逻辑(一般另外注册文件)。
如果对加载逻辑不熟悉,可以参考本文示例,逐步实现。
[MOD加载器] -> 扫描 -> modMain.py
modMain.py -> 提供 -> 不同端侧的处理方法
端侧处理方法 -> 加载 -> 具体业务文件
提示
使用QuModLibs框架可以简化开发流程,提升效率,但本篇仅讲解原版开发框架,稍后您可以单独了解。