BepInEx:强大的Unity游戏插件框架

68 阅读3分钟

BepInEx:强大的Unity游戏插件框架

项目描述

BepInEx(Bepis Injector Extensible)是一个专业的Unity游戏插件/模组框架,支持Unity Mono、IL2CPP以及.NET框架游戏(包括XNA、FNA、MonoGame等)。该项目提供了完整的插件加载系统、配置管理、日志记录和运行时修补功能,为游戏模组开发者提供稳定可靠的开发环境。

功能特性

🎯 多平台支持

  • Unity Mono: Windows、OSX、Linux全面支持
  • Unity IL2CPP: Windows和Linux支持
  • .NET框架: 兼容XNA、FNA、MonoGame等框架

🔧 核心功能

  • 插件自动加载: 自动发现和加载插件程序集
  • 配置系统: 强大的配置文件管理,支持数据验证和事件通知
  • 日志系统: 多源日志记录,支持控制台、文件和Unity日志输出
  • 运行时修补: 基于Harmony的程序集修补功能
  • 依赖管理: 完整的插件依赖关系解析

🛠 开发工具

  • 插件元数据: 通过属性标记插件信息和依赖关系
  • 类型转换器: 支持多种数据类型的序列化和反序列化
  • 控制台管理: 跨平台控制台支持,包含颜色和编码处理
  • 缓存系统: 程序集缓存加速加载过程

安装指南

系统要求

  • Windows 7+ / macOS 10.12+ / Linux (各主要发行版)
  • .NET Framework 4.0+ 或 .NET Core 3.1+
  • 支持的Unity游戏

安装步骤

  1. 下载最新版本

    # 从GitHub Releases页面下载对应版本
    https://github.com/BepInEx/BepInEx/releases
    
  2. 安装到游戏目录

    • 将BepInEx文件解压到游戏根目录
    • 确保目录结构如下:
      Game/
      ├── BepInEx/
      │   ├── core/          # 核心库
      │   ├── plugins/       # 插件目录
      │   └── config/        # 配置文件
      ├── doorstop_config.ini
      └── winhttp.dll        # Windows注入器
      
  3. 验证安装

    • 启动游戏,查看BepInEx控制台输出
    • 检查BepInEx/LogOutput.log文件确认运行状态

使用说明

基础插件开发

using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;

[BepInPlugin("com.author.pluginname", "My Plugin", "1.0.0")]
[BepInProcess("game.exe")]
public class MyPlugin : BasePlugin
{
    internal static ManualLogSource Logger;
    
    private ConfigEntry<bool> ConfigExample;

    public override void Load()
    {
        Logger = Log;
        
        // 配置绑定
        ConfigExample = Config.Bind("General", "EnableFeature", true, 
            "是否启用特定功能");
        
        // Harmony补丁
        Harmony.CreateAndPatchAll(typeof(MyPatches));
        
        Logger.LogInfo("插件加载完成!");
    }
    
    [HarmonyPatch(typeof(GameManager))]
    class MyPatches
    {
        [HarmonyPostfix, HarmonyPatch("Start")]
        static void PostfixStart()
        {
            Logger.LogInfo("游戏已启动!");
        }
    }
}

配置系统使用

// 创建配置项
ConfigEntry<int> numberSetting = Config.Bind(
    "Section", 
    "Key", 
    42, 
    new ConfigDescription("数值设置示例", 
        new AcceptableValueRange<int>(0, 100))
);

// 监听配置变化
numberSetting.SettingChanged += (sender, args) => 
{
    Logger.LogInfo($"配置已更改: {numberSetting.Value}");
};

日志记录

// 不同级别的日志记录
Log.LogDebug("调试信息");
Log.LogInfo("普通信息");
Log.LogWarning("警告信息");
Log.LogError("错误信息");
Log.LogFatal("严重错误");

核心代码

插件加载系统

/// <summary>
/// 链式加载器核心类,负责插件的发现、加载和初始化
/// </summary>
public abstract class BaseChainloader<TPlugin>
{
    protected static readonly string CurrentAssemblyName = 
        Assembly.GetExecutingAssembly().GetName().Name;
    
    /// <summary>
    /// 分析类型定义并转换为插件信息
    /// </summary>
    public static PluginInfo ToPluginInfo(TypeDefinition type, string assemblyLocation)
    {
        if (type.IsInterface || type.IsAbstract)
            return null;

        try
        {
            if (!type.IsSubtypeOf(typeof(TPlugin)))
                return null;
        }
        catch (AssemblyResolutionException)
        {
            return null;
        }

        var metadata = BepInPlugin.FromCecilType(type);
        if (metadata == null)
        {
            Logger.Log(LogLevel.Warning, 
                $"跳过类型 [{type.FullName}],未指定元数据属性");
            return null;
        }

        if (string.IsNullOrEmpty(metadata.GUID) || 
            !allowedGuidRegex.IsMatch(metadata.GUID))
        {
            Logger.Log(LogLevel.Error, 
                $"插件GUID无效: {metadata.GUID}");
            return null;
        }

        return new PluginInfo
        {
            Metadata = metadata,
            Location = assemblyLocation,
            TypeName = type.FullName
        };
    }
}

配置管理系统

/// <summary>
/// 配置文件管理类,支持线程安全的配置操作
/// </summary>
public class ConfigFile : IDictionary<ConfigDefinition, ConfigEntryBase>
{
    private readonly BepInPlugin _ownerMetadata;
    protected Dictionary<ConfigDefinition, ConfigEntryBase> Entries { get; } = new();
    
    /// <summary>
    /// 创建新的配置文件
    /// </summary>
    public ConfigFile(string configPath, bool saveOnInit, BepInPlugin ownerMetadata)
    {
        _ownerMetadata = ownerMetadata;
        ConfigFilePath = Path.GetFullPath(configPath);

        if (File.Exists(ConfigFilePath))
            Reload();
        else if (saveOnInit) 
            Save();
    }
    
    /// <summary>
    /// 绑定配置项
    /// </summary>
    public ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, 
        ConfigDescription configDescription = null)
    {
        var definition = new ConfigDefinition(section, key);
        var entry = new ConfigEntry<T>(this, definition, defaultValue, 
            configDescription ?? ConfigDescription.Empty);
        
        Entries[definition] = entry;
        return entry;
    }
}

路径管理系统

/// <summary>
/// BepInEx使用的路径管理静态类
/// </summary>
public static class Paths
{
    /// <summary>
    /// BepInEx版本信息
    /// </summary>
    public static Version BepInExVersion { get; } =
        Version.Parse(MetadataHelper.GetAttributes<AssemblyInformationalVersionAttribute>(
            typeof(Paths).Assembly)[0].InformationalVersion);

    /// <summary>
    /// 包含主要托管程序集的Managed文件夹路径
    /// </summary>
    public static string ManagedPath { get; private set; }

    /// <summary>
    /// 当前运行的Unity游戏的游戏数据文件夹路径
    /// </summary>
    public static string GameDataPath { get; private set; }

    /// <summary>
    /// 核心BepInEx DLL所在的目录
    /// </summary>
    public static string BepInExAssemblyDirectory { get; private set; }

    /// <summary>
    /// 主要BepInEx文件夹的路径
    /// </summary>
    public static string BepInExRootPath { get; private set; }
}

日志系统架构

/// <summary>
/// 手动日志源,提供简单的API来手动发出日志
/// </summary>
public class ManualLogSource : ILogSource
{
    private readonly string _sourceName;
    
    public ManualLogSource(string sourceName)
    {
        _sourceName = sourceName;
    }

    public string SourceName => _sourceName;
    public event EventHandler<LogEventArgs> LogEvent;

    /// <summary>
    /// 使用指定的日志级别记录消息
    /// </summary>
    public void Log(LogLevel level, object data) => 
        LogEvent?.Invoke(this, new LogEventArgs(data, level, this));

    /// <summary>
    /// 记录插值字符串消息
    /// </summary>
    public void Log(LogLevel level,
        [InterpolatedStringHandlerArgument("level")]
        BepInExLogInterpolatedStringHandler logHandler)
    {
        if (logHandler.Enabled)
            LogEvent?.Invoke(this, 
                new LogEventArgs(logHandler.ToString(), level, this));
    }
}

BepInEx框架通过这些核心组件提供了完整的插件开发解决方案,使得开发者可以专注于业务逻辑而不必担心底层基础设施的实现。