Doorstop入口点与启动机制
BepInEx通过Doorstop实现Unity游戏的插件注入机制,Doorstop作为一个轻量级的注入器,能够在游戏启动前加载BepInEx的核心组件。整个配置与启动流程涉及多个关键配置文件和启动脚本,为不同Unity运行时环境(Mono和IL2CPP)提供定制化的注入方案,包括详细的配置参数、环境变量设置和平台特定的处理逻辑。
Doorstop配置与启动流程
BepInEx通过Doorstop实现Unity游戏的插件注入机制,Doorstop作为一个轻量级的注入器,能够在游戏启动前加载BepInEx的核心组件。整个配置与启动流程涉及多个关键配置文件和启动脚本,为不同Unity运行时环境提供定制化的注入方案。
配置文件架构
Doorstop支持两种主要的Unity运行时配置:Mono和IL2CPP。每种运行时都有对应的配置文件,采用INI格式进行配置管理。
Mono运行时配置 (doorstop_config_mono.ini)
[General]
enabled = true
target_assembly = BepInEx\core\BepInEx.Unity.Mono.Preloader.dll
redirect_output_log = false
boot_config_override =
ignore_disable_switch = false
[UnityMono]
dll_search_path_override = "BepInEx\core"
debug_enabled = false
debug_start_server = true
debug_address = 127.0.0.1:10000
debug_suspend = false
IL2CPP运行时配置 (doorstop_config_il2cpp.ini)
[General]
enabled = true
target_assembly = BepInEx\core\BepInEx.Unity.IL2CPP.dll
redirect_output_log = false
boot_config_override =
ignore_disable_switch = false
[UnityMono]
dll_search_path_override =
debug_enabled = false
debug_start_server = true
debug_address = 127.0.0.1:10000
debug_suspend = false
[Il2Cpp]
coreclr_path = dotnet\coreclr.dll
corlib_dir = dotnet
配置参数详解
| 配置节 | 参数名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|---|
| General | enabled | bool | true | 启用Doorstop注入功能 |
| General | target_assembly | string | 运行时特定 | 目标程序集路径,包含入口点方法 |
| General | redirect_output_log | bool | false | 是否重定向Unity输出日志 |
| General | boot_config_override | string | 空 | 覆盖默认boot.config文件路径 |
| General | ignore_disable_switch | bool | false | 忽略DOORSTOP_DISABLE环境变量 |
| UnityMono | dll_search_path_override | string | 运行时特定 | Mono DLL搜索路径覆盖 |
| UnityMono | debug_enabled | bool | false | 启用Mono调试器服务器 |
| UnityMono | debug_start_server | bool | true | Doorstop是否初始化调试器服务器 |
| UnityMono | debug_address | string | 127.0.0.1:10000 | 调试器服务器地址 |
| UnityMono | debug_suspend | bool | false | 调试时是否挂起游戏执行 |
| Il2Cpp | coreclr_path | string | dotnet\coreclr.dll | CoreCLR运行时路径 |
| Il2Cpp | corlib_dir | string | dotnet | CoreCLR托管核心库目录 |
启动脚本机制
BepInEx提供了跨平台的启动脚本(run_bepinex_mono.sh和run_bepinex_il2cpp.sh),这些脚本负责设置环境变量并启动游戏进程。
启动流程序列图
sequenceDiagram
participant User
participant LaunchScript
participant DoorstopLib
participant UnityProcess
participant BepInExPreloader
User->>LaunchScript: 执行启动命令
LaunchScript->>LaunchScript: 解析配置参数
LaunchScript->>LaunchScript: 设置环境变量
LaunchScript->>UnityProcess: 启动Unity进程
UnityProcess->>DoorstopLib: 加载libdoorstop
DoorstopLib->>BepInExPreloader: 调用target_assembly
BepInExPreloader->>BepInExPreloader: 执行Start()方法
BepInExPreloader->>UnityProcess: 继续正常启动流程
环境变量设置
启动脚本通过设置以下环境变量来控制Doorstop行为:
export DOORSTOP_ENABLED="1"
export DOORSTOP_TARGET_ASSEMBLY="BepInEx/core/BepInEx.Unity.Mono.Preloader.dll"
export DOORSTOP_IGNORE_DISABLED_ENV="0"
export DOORSTOP_MONO_DLL_SEARCH_PATH_OVERRIDE="BepInEx/core"
export DOORSTOP_MONO_DEBUG_ENABLED="0"
export DOORSTOP_MONO_DEBUG_START_SERVER="0"
export DOORSTOP_MONO_DEBUG_ADDRESS="127.0.0.1:10000"
export DOORSTOP_MONO_DEBUG_SUSPEND="0"
export DOORSTOP_CLR_RUNTIME_CORECLR_PATH=""
export DOORSTOP_CLR_CORLIB_DIR=""
入口点实现
Doorstop要求目标程序集包含特定签名的入口点方法。BepInEx的实现如下:
// ReSharper disable once CheckNamespace
namespace Doorstop;
internal static class Entrypoint
{
/// <summary>
/// The main entrypoint of BepInEx, called from Doorstop.
/// </summary>
public static void Start()
{
try
{
EnvVars.LoadVars();
var gamePath = Path.GetDirectoryName(EnvVars.DOORSTOP_PROCESS_PATH) ?? ".";
// 使用反射调用预加载器以避免过早的程序集解析问题
typeof(Entrypoint).Assembly.GetType($"BepInEx.Unity.Mono.Preloader.{nameof(UnityPreloaderRunner)}")
?.GetMethod(nameof(UnityPreloaderRunner.PreloaderPreMain))
?.Invoke(null, null);
}
catch (Exception ex)
{
File.WriteAllText(silentExceptionLog, ex.ToString());
}
}
}
平台特定处理
启动脚本包含针对不同操作系统的处理逻辑:
| 操作系统 | 可执行文件处理 | 库文件扩展名 | 环境变量 |
|---|---|---|---|
| Linux | 直接路径处理 | .so | LD_PRELOAD, LD_LIBRARY_PATH |
| macOS | .app包解析 | .dylib | DYLD_INSERT_LIBRARIES, DYLD_LIBRARY_PATH |
| Windows | 不适用(使用Windows版本) | .dll | 不适用 |
Steam启动兼容性
启动脚本特别处理了通过Steam启动的情况,确保Steam覆盖功能正常工作:
if [ "$2" = "SteamLaunch" ]; then
# 重新组织参数并通过Steam启动器重新执行
exec "$@"
fi
架构检测与验证
脚本包含架构检测逻辑,确保只在支持的架构上运行:
file_out="$(LD_PRELOAD="" file -b "${executable_path}")"
case "${file_out}" in
*PE32*)
echo "Windows可执行文件,请使用Windows版BepInEx"
exit 1
;;
*64-bit*)
arch="x64"
;;
*32-bit*)
arch="x86"
;;
*)
echo "不支持的架构"
exit 1
;;
esac
这种配置与启动机制确保了BepInEx能够在各种Unity游戏环境中稳定运行,为mod开发者提供了统一的插件加载基础。
Mono与IL2CPP差异化配置
在Unity游戏开发中,Mono和IL2CPP是两种不同的脚本后端运行时环境,BepInEx通过Doorstop入口点机制为这两种运行时提供了精细化的差异化配置支持。这种配置差异主要体现在目标程序集、运行时路径设置、调试选项以及核心库处理等多个方面。
配置文件结构对比
BepInEx为Mono和IL2CPP运行时分别提供了专门的配置文件,两者在结构上保持一致性但在具体参数上存在显著差异:
| 配置项 | Mono配置 | IL2CPP配置 | 说明 |
|---|---|---|---|
| target_assembly | BepInEx\core\BepInEx.Unity.Mono.Preloader.dll | BepInEx\core\BepInEx.Unity.IL2CPP.dll | 目标程序集路径 |
| dll_search_path_override | "BepInEx\core" | 空值 | DLL搜索路径重写 |
| coreclr_path | 无此配置 | dotnet\coreclr.dll | CoreCLR运行时路径 |
| corlib_dir | 无此配置 | dotnet | 核心库目录 |
运行时特性差异分析
Mono运行时配置特点
Mono配置主要针对传统的Mono运行时环境,其核心特性包括:
[UnityMono]
dll_search_path_override = "BepInEx\core"
debug_enabled = false
debug_start_server = true
debug_address = 127.0.0.1:10000
debug_suspend = false
Mono配置中的dll_search_path_override参数尤为重要,它指示Mono运行时优先从BepInEx的核心目录搜索程序集,这在游戏原始Managed文件夹中的mscorlib等核心库被剥离的情况下尤为关键。
IL2CPP运行时配置特点
IL2CPP配置则针对现代化的IL2CPP运行时,新增了CoreCLR相关的配置节:
[Il2Cpp]
coreclr_path = dotnet\coreclr.dll
corlib_dir = dotnet
IL2CPP配置取消了Mono特有的DLL搜索路径重写,因为IL2CPP使用完全不同的程序集加载机制,转而专注于CoreCLR运行时的正确配置。
技术实现机制
BepInEx通过统一的配置接口处理两种运行时的差异,在代码层面通过运行时检测自动选择相应的配置策略:
flowchart TD
A[Doorstop启动] --> B{检测运行时类型}
B -->|Mono| C[加载Mono配置]
B -->|IL2CPP| D[加载IL2CPP配置]
C --> E[设置DLL搜索路径]
C --> F[配置Mono调试器]
D --> G[定位CoreCLR运行时]
D --> H[设置核心库目录]
E --> I[加载BepInEx.Mono.Preloader]
F --> I
G --> J[加载BepInEx.IL2CPP]
H --> J
调试配置的统一处理
尽管两种运行时在底层实现上存在差异,但在调试配置方面保持了高度的一致性:
# 通用调试配置
debug_enabled = false
debug_start_server = true
debug_address = 127.0.0.1:10000
debug_suspend = false
这种统一的设计使得开发者可以在不同的运行时环境下使用相同的调试工作流,降低了学习和使用的复杂度。
实际应用场景
在实际游戏模组开发中,这种差异化配置机制确保了:
- 兼容性保障:自动适应不同Unity版本和运行时环境
- 性能优化:针对不同运行时特性进行针对性优化
- 调试便利:统一的调试接口简化开发流程
- 部署简化:自动化的配置选择减少手动干预
通过这种精细化的配置差异处理,BepInEx为Unity游戏模组开发者提供了稳定可靠的运行时环境支持,无论是传统的Mono后端还是现代的IL2CPP后端都能获得最佳的使用体验。
调试支持与输出重定向
BepInEx 提供了强大的调试支持和输出重定向机制,确保在复杂的 Unity 游戏环境中能够准确捕获和分析运行时信息。这些功能对于插件开发和故障排查至关重要。
标准输出重定向机制
BepInEx 通过 ConsoleSetOutFix 类实现了标准输出的重定向和日志记录功能。该机制确保所有控制台输出都被正确捕获并记录到 BepInEx 的日志系统中。
public static class ConsoleSetOutFix
{
private static LoggedTextWriter loggedTextWriter;
internal static ManualLogSource ConsoleLogSource = Logger.CreateLogSource("Console");
public static void Apply()
{
loggedTextWriter = new LoggedTextWriter { Parent = Console.Out };
Console.SetOut(loggedTextWriter);
Harmony.CreateAndPatchAll(typeof(ConsoleSetOutFix));
}
[HarmonyPatch(typeof(Console), nameof(Console.SetOut))]
[HarmonyPrefix]
private static bool OnSetOut(TextWriter newOut)
{
loggedTextWriter.Parent = newOut;
return false;
}
}
该实现的核心是一个自定义的 LoggedTextWriter 类,它继承自 TextWriter 并重写了关键的写入方法:
internal class LoggedTextWriter : TextWriter
{
public override Encoding Encoding { get; } = Encoding.UTF8;
public TextWriter Parent { get; set; }
public override void Flush() => Parent.Flush();
public override void Write(string value)
{
ConsoleSetOutFix.ConsoleLogSource.Log(LogLevel.Info, value);
Parent.Write(value);
}
public override void WriteLine(string value)
{
ConsoleSetOutFix.ConsoleLogSource.Log(LogLevel.Info, value);
Parent.WriteLine(value);
}
}
这种设计确保了:
- 所有控制台输出都被记录到 BepInEx 日志系统
- 原始输出功能保持不变
- 支持动态切换输出目标
标准错误重定向
对于 IL2CPP 运行时,BepInEx 提供了专门的 RedirectStdErrFix 来处理标准错误输出:
flowchart TD
A[应用程序标准错误输出] --> B[Windows 平台]
A --> C[Unix 平台]
B --> D[CreateFile API 创建日志文件]
D --> E[SetStdHandle 重定向句柄]
E --> F[ErrorLog.log 文件]
C --> G[系统管道重定向]
G --> H[标准错误日志文件]
Windows 平台的具体实现:
public static void Apply()
{
if (PlatformHelper.Is(Platform.Windows))
{
var errorFile = CreateFile(Path.Combine(Paths.BepInExRootPath, "ErrorLog.log"),
GENERIC_WRITE, FILE_SHARE_READ, 0,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (errorFile != INVALID_HANDLE_VALUE)
{
SetStdHandle(STD_ERROR_HANDLE, errorFile);
}
}
// Unix 平台使用标准管道重定向
}
终端信息修复 (XTermFix)
对于 Unix 系统上的终端兼容性问题,BepInEx 提供了 XTermFix 类来解决老版本 Unity 的终端信息读取问题:
internal static class XTermFix
{
public static int intOffset;
public static void Apply()
{
if (PlatformHelper.Is(Platform.Windows))
return;
var harmony = new Harmony("com.bepinex.xtermfix");
harmony.Patch(AccessTools.Method("System.TermInfoReader:ReadHeader"),
new HarmonyMethod(typeof(XTermFix), nameof(ReadHeaderPrefix)));
harmony.Patch(AccessTools.Method("System.TermInfoReader:Get",
new[] { AccessTools.TypeByName("System.TermInfoNumbers") }),
transpiler: new HarmonyMethod(typeof(XTermFix),
nameof(GetTermInfoNumbersTranspiler)));
}
}
该修复主要处理两种不同的终端信息格式:
| 格式标识 | 整数偏移量 | 描述 |
|---|---|---|
| 0x11a | 2 bytes | 旧版终端信息格式 |
| 0x21e | 4 bytes | 新版终端信息格式 |
调试输出流程
BepInEx 的调试输出重定向遵循以下处理流程:
sequenceDiagram
participant App as 应用程序
participant Console as System.Console
participant LoggedWriter as LoggedTextWriter
participant BepInExLog as BepInEx 日志系统
participant File as 日志文件
App->>Console: Write/WriteLine 调用
Console->>LoggedWriter: 转发输出
LoggedWriter->>BepInExLog: 记录到日志系统
LoggedWriter->>Console.Out: 原始输出
BepInExLog->>File: 写入磁盘日志
平台特定的调试支持
BepInEx 针对不同平台提供了专门的调试支持:
Windows 平台特性:
- 使用内核 API 进行标准错误重定向
- 支持完整的句柄管理
- 提供详细的错误日志记录
Unix 平台特性:
- 利用系统管道进行输出重定向
- 终端信息格式自动检测和修复
- 兼容多种终端类型
调试配置选项
通过 Doorstop 配置文件,用户可以调整调试相关的设置:
[Debug]
; 启用详细调试输出
debug.enabled = true
; 调试日志级别
debug.logLevel = Info
; 控制台输出重定向
redirectOutput = true
; 标准错误重定向
redirectError = true
故障排查与日志分析
BepInEx 的调试系统提供了丰富的日志信息,帮助开发者快速定位问题:
- 控制台输出日志:记录所有控制台输出内容
- 错误日志:专门的标准错误输出记录
- 调试日志:详细的运行时调试信息
- 性能日志:插件加载和执行性能数据
这种多层次的调试支持确保了在各种复杂的游戏环境中都能够获得准确的运行时信息,为插件开发和问题排查提供了强有力的工具支持。
Shell启动脚本实现
BepInEx在Linux和macOS平台上的启动机制依赖于精心设计的Shell脚本,这些脚本负责配置环境变量、处理平台差异以及确保Doorstop注入器正确工作。run_bepinex_il2cpp.sh和run_bepinex_mono.sh是两个核心启动脚本,它们分别针对IL2CPP和Mono运行时环境进行了优化。
脚本架构与设计理念
启动脚本采用模块化设计,分为配置段、平台检测段、参数处理段和环境设置段四个主要部分。这种设计使得脚本既可以通过命令行参数动态配置,也可以通过编辑脚本内部的默认值进行静态配置。
#!/bin/sh
# BepInEx start script
#
# Run the script to start the game with BepInEx enabled
#
# There are two ways to use this script
#
# 1. Via CLI: Run ./run_bepinex.sh <path to game> [doorstop arguments] [game arguments]
# 2. Via config: edit the options below and run ./run.sh without any arguments
核心配置参数详解
脚本提供了丰富的配置选项,涵盖了Doorstop注入器的各个方面:
| 配置参数 | 默认值 | 说明 |
|---|---|---|
enabled |
"1" | 是否启用Doorstop注入 |
target_assembly |
IL2CPP: "BepInEx/core/BepInEx.Unity.IL2CPP.dll" Mono: "BepInEx/core/BepInEx.Unity.Mono.Preloader.dll" |
目标程序集路径 |
dll_search_path_override |
IL2CPP: "" Mono: "BepInEx/core" |
Mono DLL搜索路径覆盖 |
debug_enable |
"0" | 是否启用Mono调试器 |
coreclr_path |
IL2CPP: "dotnet/libcoreclr" Mono: "" |
CoreCLR运行时路径 |
平台检测与路径解析机制
脚本通过uname -s命令检测操作系统类型,并据此设置相应的库文件扩展名和可执行文件路径处理逻辑:
flowchart TD
A[检测操作系统类型] --> B{Linux系统?}
A --> C{macOS系统?}
A --> D[其他系统]
B --> E[设置lib_extension为.so]
B --> F[处理Linux可执行文件路径]
C --> G[设置lib_extension为.dylib]
C --> H[处理macOS .app包结构]
E --> I[路径解析完成]
F --> I
G --> I
H --> I
D --> J[报错并退出]
对于macOS平台,脚本需要特殊处理.app应用程序包的结构:
# macOS特殊处理
real_executable_name="${executable_name}"
if ! echo "$real_executable_name" | grep "^.*\.app$"; then
real_executable_name="${real_executable_name}.app"
fi
inner_executable_name=$(defaults read "${real_executable_name}/Contents/Info" CFBundleExecutable)
executable_path="${real_executable_name}/Contents/MacOS/${inner_executable_name}"
Steam启动兼容性处理
脚本特别考虑了通过Steam启动的情况,确保Steam覆盖层能够正常工作:
# Special case: program is launched via Steam
if [ "$2" = "SteamLaunch" ]; then
# 重新通过Steam的启动器运行脚本
to_rotate=4
rotated=0
while [ $((to_rotate-=1)) -ge 0 ]; do
while [ "z$1" = "z--" ]; do
set -- "$@" "$1"
shift
rotated=$((rotated+1))
done
set -- "$@" "$1"
shift
rotated=$((rotated+1))
done
exec "$@"
fi
环境变量配置与注入机制
脚本的核心功能是通过设置环境变量来配置Doorstop注入器:
# 设置Doorstop环境变量
export DOORSTOP_ENABLED="$enabled"
export DOORSTOP_TARGET_ASSEMBLY="$target_assembly"
export DOORSTOP_IGNORE_DISABLED_ENV="$ignore_disable_switch"
# 设置库加载路径
export LD_LIBRARY_PATH="${doorstop_directory}:${corlib_dir}:${LD_LIBRARY_PATH}"
if [ -z "$LD_PRELOAD" ]; then
export LD_PRELOAD="${doorstop_name}"
else
export LD_PRELOAD="${doorstop_name}:${LD_PRELOAD}"
fi
架构检测与错误处理
脚本使用file命令检测可执行文件的架构,确保兼容性:
# 检测可执行文件架构
file_out="$(LD_PRELOAD="" file -b "${executable_path}")"
case "${file_out}" in
*PE32*)
echo "Windows可执行文件,需要使用Wine/Proton"
exit 1
;;
*64-bit*)
arch="x64"
;;
*32-bit*)
arch="x86"
;;
*)
echo "不支持的架构: ${file_out}"
exit 1
;;
esac
参数解析与布尔值处理
脚本提供了灵活的命令行参数解析机制,包括布尔值转换函数:
# 布尔值转换辅助函数
doorstop_bool() {
case "$1" in
TRUE|true|t|T|1|Y|y|yes)
echo "1"
;;
FALSE|false|f|F|0|N|n|no)
echo "0"
;;
esac
}
# 命令行参数解析
while :; do
case "$1" in
--doorstop_enabled)
enabled="$(doorstop_bool "$2")"
shift
;;
# 其他参数处理...
esac
shift
done
跨平台路径处理
脚本实现了完整的路径解析链,确保在不同平台和符号链接情况下都能正确找到目标文件:
sequenceDiagram
participant User
participant Script
participant System
participant Doorstop
User->>Script: 执行启动脚本
Script->>System: 检测操作系统类型
System-->>Script: 返回系统信息
Script->>Script: 解析可执行文件路径
Script->>System: 检测文件架构
System-->>Script: 返回架构信息
Script->>Script: 处理命令行参数
Script->>Script: 设置环境变量
Script->>Doorstop: 配置注入参数
Script->>System: 启动游戏进程
System-->>User: 游戏运行中
这种精心的Shell脚本设计确保了BepInEx在Unix-like系统上的可靠运行,为Unity游戏模组生态提供了稳定的基础环境。脚本的模块化设计和丰富的配置选项使得它能够适应各种复杂的部署场景,从简单的本地测试到通过Steam等平台的复杂启动流程。
BepInEx的Shell启动脚本实现了跨平台的Unity游戏插件注入机制,通过精心的模块化设计和丰富的配置选项,确保了在Linux和macOS系统上的可靠运行。脚本提供了完整的路径解析、架构检测、环境变量配置和Steam启动兼容性处理,能够适应各种复杂的部署场景。这种设计为Unity游戏模组生态提供了稳定的基础环境,从简单的本地测试到通过Steam等平台的复杂启动流程都能得到良好支持。
Kimi-K2.5Kimi K2.5 是一款开源的原生多模态智能体模型,它在 Kimi-K2-Base 的基础上,通过对约 15 万亿混合视觉和文本 tokens 进行持续预训练构建而成。该模型将视觉与语言理解、高级智能体能力、即时模式与思考模式,以及对话式与智能体范式无缝融合。Python00- QQwen3-Coder-Next2026年2月4日,正式发布的Qwen3-Coder-Next,一款专为编码智能体和本地开发场景设计的开源语言模型。Python00
xw-cli实现国产算力大模型零门槛部署,一键跑通 Qwen、GLM-4.7、Minimax-2.1、DeepSeek-OCR 等模型Go06
PaddleOCR-VL-1.5PaddleOCR-VL-1.5 是 PaddleOCR-VL 的新一代进阶模型,在 OmniDocBench v1.5 上实现了 94.5% 的全新 state-of-the-art 准确率。 为了严格评估模型在真实物理畸变下的鲁棒性——包括扫描伪影、倾斜、扭曲、屏幕拍摄和光照变化——我们提出了 Real5-OmniDocBench 基准测试集。实验结果表明,该增强模型在新构建的基准测试集上达到了 SOTA 性能。此外,我们通过整合印章识别和文本检测识别(text spotting)任务扩展了模型的能力,同时保持 0.9B 的超紧凑 VLM 规模,具备高效率特性。Python00
KuiklyUI基于KMP技术的高性能、全平台开发框架,具备统一代码库、极致易用性和动态灵活性。 Provide a high-performance, full-platform development framework with unified codebase, ultimate ease of use, and dynamic flexibility. 注意:本仓库为Github仓库镜像,PR或Issue请移步至Github发起,感谢支持!Kotlin08
VLOOKVLOOK™ 是优雅好用的 Typora/Markdown 主题包和增强插件。 VLOOK™ is an elegant and practical THEME PACKAGE × ENHANCEMENT PLUGIN for Typora/Markdown.Less00