Skip to content

配置文件

引擎启动时自动读取 unison.xml,该文件位于引擎可执行文件所在目录。XML 根元素为 <ppg3d>


完整示例

xml
<ppg3d>
    <pymodules>
        <module name="exio3">
            <function name="add_cpk_to_cpkhub" type="vfs.mount"/>
            <function name="get_file" type="vfs.get_file"/>
            <function name="find_file" type="vfs.find_file"/>
            <function name="list_dir" type="vfs.list_dir"/>
            <function name="get_doc_dir" type="vfs.get_doc_dir"/>
            <function name="get_real_path" type="vfs.get_real_path"/>
        </module>
    </pymodules>
    <client ShowLogWindow="False"
            WindowClientWidth="1600"
            WindowClientHeight="900"
            SysPath="%WORK_DIR%/script/Scripts;%WORK_DIR%/Lib"/>
    <python ThreadEnable="True" />
    <log FileName="%WORK_DIR%/log_inst_%INST%.txt"
         OldFileName="%WORK_DIR%/log_old_%ROTATE%.txt"
         NormalFileName="%WORK_DIR%/log.txt"
         MaxOldNumber="5"/>
    <filesystems>
        <filesystem name="scene" type="scene">
            <loader root="%WORK_DIR%/scene"/>
        </filesystem>
        <filesystem name="Scripts" type="script">
            <loader root="%WORK_DIR%/script"/>
        </filesystem>
        <filesystem name="Lib" type="Lib" fsapi="exio3" key="-231">
            <loader root="%WORK_DIR%/Lib"/>
        </filesystem>
        <filesystem name="fonts" type="res" fsapi="exio3">
            <loader root="%WORK_DIR%/builtin_res_0"/>
        </filesystem>
    </filesystems>
</ppg3d>

<pymodules> — Python 模块映射

定义哪些 Python 第三方模块的函数需要映射到 unison.vfs 供引擎内部使用。

元素结构

xml
<pymodules>
    <module name="exio3">                          <!-- 要 import 的 Python 模块 -->
        <function name="add_cpk_to_cpkhub"          <!-- 模块中的函数名 -->
                  type="vfs.mount"/>                <!-- 映射到 unison.vfs 的目标名 -->
        <function name="get_file" type="vfs.get_file"/>
        <function name="find_file" type="vfs.find_file"/>
        <function name="list_dir" type="vfs.list_dir"/>
        <function name="get_doc_dir" type="vfs.get_doc_dir"/>
        <function name="get_real_path" type="vfs.get_real_path"/>
    </module>
</pymodules>

属性详解

module 子元素

属性类型必填说明
namestrPython 模块名。引擎执行 import <name> 导入该模块

function 子元素

属性类型必填说明
namestr源模块中的函数名。如 add_cpk_to_cpkhub
typestr函数在 unison.vfs 上的目标名,格式 vfs.xxx。解析时取 . 之后的部分作为绑定名

解析规则

  • 引擎按 <module> 顺序逐个导入,import 失败则跳过该模块,继续处理下一个
  • 每个 <function> 检查源模块中是否存在对应函数,存在才绑定到 unison.vfs
  • type 属性格式为 vfs.<target_name>. 之后的部分成为 unison.vfs 的属性名

示例效果

以下配置:

xml
<function name="add_cpk_to_cpkhub" type="vfs.mount"/>

等价于 Python:

python
import exio3
unison.vfs.mount = exio3.add_cpk_to_cpkhub

典型配置

引擎通常只需配置一个 exio3 模块。exio3 是 CEFS 文件系统的 Python 绑定,负责 CPK 加密包的读取。

各函数签名与参数

下表中的"源函数"指 exio3 模块的函数,"目标名"指映射到 unison.vfs 后的属性名。

源函数目标名引擎内部用途函数签名
add_cpk_to_cpkhubmount挂载 CPK 文件到虚拟文件系统add_cpk_to_cpkhub(cpk_path: str, mount_point: str, encryption_key: int = 0)
find_filefind_file在 VFS 中查找文件是否存在find_file(vfs_path: str) -> bool
get_fileget_file从 VFS 读取文件内容get_file(vfs_path: str) -> bytes
list_dirlist_dir列出 VFS 目录内容list_dir(vfs_path: str) -> list[str]
get_doc_dirget_doc_dir获取文档目录路径get_doc_dir() -> str
get_real_pathget_real_path虚拟路径转真实路径get_real_path(vfs_path: str) -> str

add_cpk_to_cpkhub / mount 参数详解:

参数类型必填说明
cpk_pathstrCPK 文件的绝对路径
mount_pointstr挂载点目录名,以 / 结尾。如 "Lib/"
encryption_keyintAES 解密密钥,正整数或负整数。默认为 0(不加密)。密钥通过 PBKDF2 派生

示例:

python
# 引擎内部调用(由配置自动生成)
exio3.add_cpk_to_cpkhub("C:/game/Lib.cpk", "Lib/", encryption_key=-231)
exio3.add_cpk_to_cpkhub("C:/game/fonts.cpk", "fonts/")

get_file 返回值:

  • 返回 bytes,调用方自行解码为 str 或直接处理二进制数据

find_file 返回值:

  • 返回 bool,只检测文件是否存在,不读取内容

<pymodules> 时的行为

如果配置文件中没有 <pymodules>(或为空),引擎仍然会创建 unison.vfs 模块并注册混合 API(如 file_existsread_file_bytes),但 mountfind_fileget_file 等基础 VFS 函数不会可用,CPK 将无法挂载。


<client> — 客户端设置

控制引擎窗口和运行时参数。

属性列表

属性类型默认值说明
WindowClientWidthint1280游戏窗口客户区宽度(像素)。值必须 > 0
WindowClientHeightint720游戏窗口客户区高度(像素)。值必须 > 0
ShowLogWindowboolfalse是否显示调试日志窗口。值: True/False/true/false/1/0
SysPathstrPython 的 sys.path 额外搜索路径,多个路径用 ; 分隔。支持 %WORK_DIR% 等宏

SysPath 示例

xml
<client SysPath="%WORK_DIR%/extra;%WORK_DIR%/tools"/>

注意SysPath 在 CPK 挂载之前生效。CPK 挂载完成后,sys.path 会被引擎清理并仅保留以下类型的文件系统路径:scriptLibtoolsscene


<python> — Python 运行时

控制内嵌 NEPython 3.13.14 运行时的行为。

属性列表

属性类型默认值说明
ThreadEnablebooltrue是否启用 Python 子线程支持。值: True/False/true/false/1/0

行为说明

  • True:允许 Python 脚本创建子线程,适合有异步需求的游戏逻辑
  • False:禁用多线程,所有 Python 代码在引擎主线程执行。略微减少开销,适合纯同步游戏逻辑

<log> — 日志配置

控制引擎日志文件的命名和轮转。如果未配置 <log> 节点,日志仅输出到控制台,不写入文件。

属性列表

属性类型默认值说明
FileNamestr首次启动的日志文件名。支持 %INST%
OldFileNamestr日志轮转时的旧文件名。支持 %ROTATE%
NormalFileNamestr正常运行的日志文件名
MaxOldNumberint5最多保留的旧日志文件数量

日志轮转流程

  1. 引擎启动时,如果 NormalFileName 文件已存在,将其重命名为 OldFileName 格式(%ROTATE% 依次递增)
  2. MaxOldNumber 限制最多保留的文件数(0 表示不限制)
  3. FileName 用于实例化启动(如配置 %INST% 为不同值以区分多个进程)

示例配置

xml
<log FileName="%WORK_DIR%/log_inst_%INST%.txt"
     OldFileName="%WORK_DIR%/log_old_%ROTATE%.txt"
     NormalFileName="%WORK_DIR%/log.txt"
     MaxOldNumber="5"/>

轮转效果(假设 MaxOldNumber=3):

log.txt            → log_old_0.txt  → log_old_1.txt  → log_old_2.txt  → 删除
(当前)               (旧日志)        (更旧)          (最旧)          (超出限制)

<filesystems> — 文件系统

定义引擎需要挂载的虚拟文件系统。这是配置中最核心的部分。

元素结构

xml
<filesystems>
    <filesystem name="名称"
                type="类型"
                [key="加密密钥"]
                [fsapi="后端模块"]>
        <loader root="%WORK_DIR%/路径"
                [type="directory"]/>
    </filesystem>
</filesystems>

filesystem 属性

属性类型必填说明
namestr文件系统名称,同时作为挂载点目录名
typestr文件系统类型,决定挂载后如何处理
keyintCPK 加密密钥。不设置或设为 0 表示不加密。注意:负数也是有效密钥
fsapistr强制使用的 VFS 后端模块名(如 exio3)。有值时引擎直接通过该模块挂载 CPK

loader 子元素

属性类型必填说明
rootstr文件系统根路径,支持 %WORK_DIR%%DOC_DIR%
typestr设为 directory 时,以目录模式挂载(直接读取真实文件夹)。不设置或留空时,以CPK 模式挂载

CPK 文件查找策略

引擎按以下优先级查找文件系统对应的 CPK 文件:

  1. <root>.cpk — 优先尝试(如 %WORK_DIR%/scriptC:\game\script.cpk
  2. <root> 本身 — 如果 .cpk 文件不存在,则尝试直接使用 root 路径(适用于文件本身就带扩展名的情况)
xml
<!-- 情况 A:root="script" → 查找 script.cpk → 如果不存在 → 再查 script -->
<filesystem name="Scripts" type="script" key="241">
    <loader root="%WORK_DIR%/script"/>
</filesystem>

<!-- 情况 B:root="data.apd" → 查找 data.apd.cpk → 如果不存在 → 再查 data.apd -->
<filesystem name="Data" type="res">
    <loader root="%WORK_DIR%/data.apd"/>
</filesystem>

只有两次尝试都失败时,才输出警告日志并跳过该文件系统。

type 取值与行为

type对应的 sys.path场景挂载点说明
scene场景资源目录。添加到 sys.path 并注册为脚本搜索路径
script游戏脚本目录。添加到 sys.path 和脚本搜索路径
Lib引擎库目录(Python 标准库扩展)。添加到 sys.path;优先于其他文件系统挂载
tools工具脚本目录。添加到 sys.path
res纯资源目录(字体/纹理等)。添加到 sys.path
其他自定义值不添加到 sys.path,仅文件系统挂载

关键行为:

  • scene — 不仅挂载文件,还作为场景管理系统的基础搜索路径
  • script — 挂载后,其中的 .py 文件可被 import 直接导入(通过 CpkImporter)
  • Lib — 优先挂载顺序:在 preMountLibOnly 阶段最先挂载,确保 CpkImporter 等基础模块先可用
  • res 和自定义类型 — 仅文件访问,不参与 Python 导入

key 加密密钥

xml
<!-- 不加密 -->
<filesystem name="data" type="res">
    <loader root="%WORK_DIR%/data"/>
</filesystem>

<!-- AES 加密,密钥 241 -->
<filesystem name="Scripts" type="script" key="241">
    <loader root="%WORK_DIR%/script"/>
</filesystem>

<!-- AES 加密,密钥 -231 -->
<filesystem name="Lib" type="Lib" key="-231">
    <loader root="%WORK_DIR%/Lib"/>
</filesystem>
  • 密钥为 有符号整数,正负均可
  • 密钥通过 PBKDF2 从数值派生 AES 密钥
  • CPK 文件 <root>.cpk 中的资源使用对应密钥加密后才能正确读取

fsapi 后端模块

xml
<!-- 默认:通过 unison.vfs (pymodules 映射) 挂载 -->
<filesystem name="Scripts" type="script" key="241">
    <loader root="%WORK_DIR%/script"/>
</filesystem>

<!-- fsapi="exio3":直接通过 exio3 模块挂载,不经过 pymodules 映射 -->
<filesystem name="Lib" type="Lib" fsapi="exio3" key="-231">
    <loader root="%WORK_DIR%/Lib"/>
</filesystem>

区别:

情况挂载调用
fsapivfs.mount(path, mount_point, encryption_key=key) — 使用 pymodules 映射
fsapi="exio3"exio3.add_cpk_to_cpkhub(path, mount_point, encryption_key=key) — 直接调用

使用 fsapi 的场景:当某些文件系统需绕过 unison.vfs 的 pymodules 映射链路,直接由指定后端处理。

loader.type="directory" — 目录模式

xml
<!-- 目录模式:直接挂载真实文件夹 -->
<filesystem name="scene" type="scene">
    <loader root="%WORK_DIR%/scene" type="directory"/>
</filesystem>

目录模式下:

  • 不查找 .cpk 文件,直接读取真实磁盘目录
  • 通过 DirectoryVFS 挂载,不依赖 exio3
  • 适合开发调试阶段(资源未打包为 CPK)

sys.path 最终列表

引擎在挂载所有文件系统后,重置 sys.path 为仅包含 ['.'],然后重新添加以下类型的文件系统路径:

sys.path = ['.', 'Scripts/', 'Lib/', 'scene/']

只有 typescriptLibtoolsscene 的文件系统才进入 sys.path

挂载顺序

  1. Lib 类型优先挂载(preMountLibOnly 阶段)— 确保基础模块先可用
  2. 其他类型按 XML 配置顺序挂载
  3. 引擎脚本搜索路径按配置顺序排列(先配的优先查找)

完整配置示例

xml
<filesystems>
    <!-- 1. 场景资源(目录模式,开发调试用) -->
    <filesystem name="scene" type="scene">
        <loader root="%WORK_DIR%/scene" type="directory"/>
    </filesystem>

    <!-- 2. 游戏脚本(加密 CPK) -->
    <filesystem name="Scripts" type="script" key="241">
        <loader root="%WORK_DIR%/script"/>
    </filesystem>

    <!-- 3. 引擎库(加密 CPK,直接使用 exio3 挂载) -->
    <filesystem name="Lib" type="Lib" fsapi="exio3" key="-231">
        <loader root="%WORK_DIR%/Lib"/>
    </filesystem>

    <!-- 4. 字体资源(CPK,exio3 挂载) -->
    <filesystem name="fonts" type="res" fsapi="exio3">
        <loader root="%WORK_DIR%/builtin_res_0"/>
    </filesystem>

    <!-- 5. 自定义资源(CPK,无加密) -->
    <filesystem name="data" type="res">
        <loader root="%WORK_DIR%/data"/>
    </filesystem>
</filesystems>

最终效果:

  • scene/ — 目录访问 + sys.path + 脚本搜索路径
  • Scripts/ — CPK 加密访问 + sys.path + 脚本搜索路径
  • Lib/ — CPK 加密访问 + sys.path,优先挂载
  • fonts/ — CPK 访问,仅文件读取
  • data/ — CPK 访问,仅文件读取

路径宏

替换为示例
%WORK_DIR%引擎工作目录(exe 所在目录)C:\MyGame\
%DOC_DIR%用户 Documents 文件夹C:\Users\xxx\Documents\
%INST%进程实例号(递增)0, 1, 2...
%ROTATE%日志轮转编号(递增)0, 1, 2...

路径解析

所有路径宏在引擎初始化时被替换为绝对路径:

  • %WORK_DIR%/scriptC:\MyGame\script
  • CPK 文件路径:<root>.cpk,如 C:\MyGame\script.cpk
  • 挂载点:以 / 结尾,如 Scripts/

配置优先级

  1. 引擎首先搜索 unison.xml
  2. 如果找不到,使用全部默认值(窗口 1280×720,无加密,无 VFS)
  3. 配置文件中未写的属性全部使用默认值
  4. XML 解析错误会输出警告但不阻断启动