最完整BepInEx入门教程:零基础开发Unity插件

最完整BepInEx入门教程:零基础开发Unity插件

【免费下载链接】BepInEx Unity / XNA game patcher and plugin framework 【免费下载链接】BepInEx 项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx

引言:为什么选择BepInEx?

你还在为Unity游戏插件开发无从下手而烦恼吗?作为Unity生态中最强大的插件框架之一,BepInEx(Bepis Injector Extensible)提供了跨平台、高兼容性的插件开发环境,支持Mono、IL2CPP和.NET框架游戏。本文将从环境搭建到高级功能,带你从零掌握BepInEx插件开发,让你轻松实现游戏功能扩展。

读完本文你将获得:

  • BepInEx完整开发环境搭建指南
  • 插件项目从零创建到打包发布的全流程
  • 配置系统、日志系统、热键系统的核心应用
  • Harmony补丁技术实现游戏逻辑修改
  • 调试与排错的专业技巧
  • 5个实用插件示例代码(含完整注释)

BepInEx框架解析

核心架构概览

BepInEx采用分层架构设计,确保插件开发的灵活性和游戏兼容性:

mermaid

支持平台与兼容性

游戏引擎WindowsmacOSLinux移动端
Unity Mono✔️ 稳定✔️ 稳定✔️ 稳定
Unity IL2CPP✔️ 测试✔️ 实验性
.NET/XNA✔️ 稳定✔️ 有限✔️ 有限

⚠️ 注意:目前IL2CPP后端仍处于测试阶段,部分高级功能可能受限。生产环境建议优先选择Mono后端。

开发环境搭建

基础工具准备

工具用途国内下载链接
.NET SDK 6.0+C#编译环境阿里云镜像
Visual Studio 2022集成开发环境微软中国官网
Rider跨平台IDEJetBrains中国
dnSpy反编译与调试蓝奏云镜像
Unity HubUnity环境管理Unity中国官网

项目创建步骤

  1. 克隆官方模板
git clone https://gitcode.com/GitHub_Trending/be/BepInEx.git
cd BepInEx
  1. 编译基础库
dotnet build BepInEx.sln -c Release
  1. 创建插件项目
dotnet new classlib -n MyFirstPlugin -f net48
cd MyFirstPlugin
  1. 添加项目引用
dotnet add reference ../BepInEx.Core/BepInEx.Core.csproj
dotnet add reference ../Runtimes/Unity/BepInEx.Unity.Mono/BepInEx.Unity.Mono.csproj

插件开发核心技术

插件基础结构

每个BepInEx插件都遵循以下基本结构,继承自BaseUnityPlugin并使用BepInPlugin特性标记:

using BepInEx;
using BepInEx.Logging;
using UnityEngine;

// 插件元数据:GUID必须唯一,建议使用"作者.插件名"格式
[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
public class MyFirstPlugin : BaseUnityPlugin
{
    // 日志源实例,用于输出调试信息
    private ManualLogSource _logger;
    
    // 插件加载时调用
    private void Awake()
    {
        _logger = Logger;
        _logger.LogInfo($"插件 {PluginInfo.PLUGIN_GUID} 已加载!");
        
        // 初始化配置
        InitializeConfig();
        
        // 注册热键
        RegisterHotkeys();
        
        // 应用Harmony补丁
        ApplyHarmonyPatches();
    }
    
    // 游戏更新时调用(每帧)
    private void Update()
    {
        // 实现每帧逻辑
    }
    
    // 插件卸载时调用
    private void OnDestroy()
    {
        _logger.LogInfo($"插件 {PluginInfo.PLUGIN_GUID} 已卸载!");
    }
    
    // 其他方法...
}

// 插件信息常量
public static class PluginInfo
{
    public const string PLUGIN_GUID = "com.example.myfirstplugin";
    public const string PLUGIN_NAME = "My First Plugin";
    public const string PLUGIN_VERSION = "1.0.0";
}

配置系统详解

BepInEx提供了强大的配置系统,支持自动生成配置文件并实时监听变更:

private ConfigEntry<float> _moveSpeed;
private ConfigEntry<KeyboardShortcut> _menuHotkey;
private ConfigEntry<bool> _enableFeature;

private void InitializeConfig()
{
    // 基础数值配置
    _moveSpeed = Config.Bind<float>(
        "游戏设置",          // 配置节名称
        "移动速度",          // 配置项名称
        5.0f,               // 默认值
        new ConfigDescription(
            "玩家移动速度倍率", // 描述
            new AcceptableValueRange<float>(1.0f, 10.0f) // 取值范围限制
        )
    );
    
    // 热键配置
    _menuHotkey = Config.Bind<KeyboardShortcut>(
        "控制设置", 
        "菜单热键", 
        new KeyboardShortcut(KeyCode.F5), 
        "打开插件菜单的快捷键"
    );
    
    // 开关配置
    _enableFeature = Config.Bind<bool>(
        "功能设置", 
        "启用新功能", 
        true, 
        "是否启用插件的实验性功能"
    );
    
    // 监听配置变更
    _enableFeature.SettingChanged += (sender, args) =>
    {
        _logger.LogInfo($"新功能已{(bool)_enableFeature.Value ? "启用" : "禁用"}");
        // 应用配置变更逻辑
    };
}

生成的配置文件(位于BepInEx/config/com.example.myfirstplugin.cfg)自动包含说明:

## Settings file was created by plugin My First Plugin v1.0.0
## Plugin GUID: com.example.myfirstplugin

[游戏设置]

## 玩家移动速度倍率
# Setting type: Single
# Acceptable value range: From 1 to 10
移动速度 = 5

[控制设置]

## 打开插件菜单的快捷键
# Setting type: KeyboardShortcut
菜单热键 = F5

[功能设置]

## 是否启用插件的实验性功能
# Setting type: Boolean
启用新功能 = true

日志系统应用

BepInEx提供多级别日志系统,帮助开发者调试和监控插件运行状态:

private void LoggingExamples()
{
    // 不同级别的日志
    Logger.LogDebug("这是调试信息,仅开发时可见");
    Logger.LogInfo("这是普通信息,记录正常操作");
    Logger.LogWarning("这是警告信息,提示潜在问题");
    Logger.LogError("这是错误信息,记录非致命错误");
    Logger.LogFatal("这是致命错误,通常导致插件崩溃");
    
    // 格式化日志
    var playerName = "Player1";
    var score = 100;
    Logger.LogInfo($"玩家 {playerName} 获得了 {score} 分");
    
    // 创建自定义日志源
    var customLogger = Logger.CreateLogSource("战斗系统");
    customLogger.LogInfo("自定义日志源可以更好地组织日志输出");
}

日志输出位置:

  • 控制台窗口
  • BepInEx/LogOutput.log 文件
  • Unity编辑器控制台(开发时)

Harmony补丁技术

使用Harmony库可以修改游戏现有方法,实现功能扩展或修复:

using HarmonyLib;
using UnityEngine;

// 定义补丁类
[HarmonyPatch(typeof(PlayerController), "Jump")] // 目标类和方法
public static class PlayerJumpPatch
{
    // 在目标方法执行前调用
    static bool Prefix(PlayerController __instance, ref float ___jumpForce)
    {
        // 修改跳跃力(增加50%)
        ___jumpForce *= 1.5f;
        Logger.LogInfo($"修改跳跃力为: {___jumpForce}");
        
        // 返回true继续执行原方法,false则阻止原方法执行
        return true;
    }
    
    // 在目标方法执行后调用
    static void Postfix(PlayerController __instance, bool __result)
    {
        if (__result) // 如果跳跃成功
        {
            Logger.LogInfo("玩家跳跃成功!");
            // 添加跳跃特效
            Object.Instantiate(jumpEffectPrefab, __instance.transform.position, Quaternion.identity);
        }
    }
}

// 在插件中应用补丁
private Harmony _harmony;

private void ApplyHarmonyPatches()
{
    _harmony = new Harmony(PluginInfo.PLUGIN_GUID);
    _harmony.PatchAll(typeof(PlayerJumpPatch));
    Logger.LogInfo("Harmony补丁已应用");
}

// 插件卸载时取消补丁
private void OnDestroy()
{
    _harmony?.UnpatchSelf();
}

常用补丁类型:

  • Prefix:目标方法执行前调用
  • Postfix:目标方法执行后调用
  • Transpiler:修改目标方法的IL代码
  • Finalizer:目标方法执行完成后(包括异常情况)调用

高级功能实现

热键系统

BepInEx提供KeyboardShortcut结构,轻松实现自定义热键:

private void RegisterHotkeys()
{
    // 在Update中检查热键
    void Update()
    {
        if (_menuHotkey.Value.IsDown())
        {
            OpenMenu(); // 打开菜单
        }
        
        // 组合键示例 (Ctrl+Shift+F1)
        if (new KeyboardShortcut(KeyCode.F1, KeyCode.LeftControl, KeyCode.LeftShift).IsPressed())
        {
            ShowDebugPanel(); // 显示调试面板
        }
    }
}

// 热键冲突检测
private void CheckHotkeyConflicts()
{
    var conflictingHotkeys = new List<KeyboardShortcut>
    {
        new KeyboardShortcut(KeyCode.F5), // 与我们的菜单热键冲突
        new KeyboardShortcut(KeyCode.Escape)
    };
    
    foreach (var hotkey in conflictingHotkeys)
    {
        if (hotkey == _menuHotkey.Value)
        {
            Logger.LogWarning($"热键冲突: {hotkey} 已被其他插件使用");
        }
    }
}

协程与异步操作

在Unity环境中使用协程处理异步任务:

// 启动协程示例
private void Start()
{
    StartCoroutine(DelayedAction(3.0f, () => 
    {
        Logger.LogInfo("3秒后执行的操作");
    }));
    
    StartCoroutine(DownloadFileCoroutine("https://example.com/data.json", ProcessData));
}

// 延迟执行协程
IEnumerator DelayedAction(float delaySeconds, Action action)
{
    yield return new WaitForSeconds(delaySeconds);
    action?.Invoke();
}

// 异步下载文件协程
IEnumerator DownloadFileCoroutine(string url, Action<string> onComplete)
{
    using (var webRequest = UnityEngine.Networking.UnityWebRequest.Get(url))
    {
        yield return webRequest.SendWebRequest();
        
        if (webRequest.result == UnityEngine.Networking.UnityWebRequest.Result.Success)
        {
            onComplete?.Invoke(webRequest.downloadHandler.text);
        }
        else
        {
            Logger.LogError($"下载失败: {webRequest.error}");
        }
    }
}

// 处理下载数据
private void ProcessData(string data)
{
    Logger.LogInfo($"下载的数据: {data}");
    // 解析JSON等数据处理
}

配置文件管理

高级配置管理技巧,包括配置文件的导入导出和动态更新:

private void AdvancedConfigManagement()
{
    // 手动保存配置
    Config.Save();
    
    // 监听配置文件修改
    Config.ConfigReloaded += (sender, args) =>
    {
        Logger.LogInfo("配置文件已重新加载");
        // 重新应用配置
        ApplyConfigChanges();
    };
    
    // 导出配置
    var configPath = Path.Combine(Paths.ConfigPath, $"{PluginInfo.PLUGIN_GUID}.cfg");
    File.Copy(configPath, Path.Combine(Paths.PluginPath, "config_backup.cfg"), overwrite: true);
    
    // 导入配置
    var importPath = Path.Combine(Paths.PluginPath, "config_import.cfg");
    if (File.Exists(importPath))
    {
        File.Copy(importPath, configPath, overwrite: true);
        Config.Reload(); // 重新加载配置
    }
}

private void ApplyConfigChanges()
{
    // 重新应用所有配置项
    Logger.LogInfo($"应用新的移动速度: {_moveSpeed.Value}");
    // 其他配置应用逻辑...
}

调试与排错技巧

调试环境设置

  1. Visual Studio调试配置
<!-- .vscode/launch.json -->
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "附加到游戏进程",
            "type": "clr",
            "request": "attach",
            "processId": "${command:pickProcess}",
            "justMyCode": false,
            "symbolOptions": {
                "searchPaths": ["${workspaceFolder}/bin/Debug"]
            }
        }
    ]
}
  1. 启用详细日志: 编辑BepInEx/config/BepInEx.cfg
[Logging]
# 设置日志级别为Debug
LogLevel = Debug

[Preloader]
# 启用预加载器调试日志
DebugLog = true
  1. 常用调试技巧
  • 使用System.Diagnostics.Debugger.Break()设置断点
  • 通过Logger.LogInfo($"变量值: {variable}")输出调试信息
  • 使用dnSpy动态调试已编译插件

常见问题解决方案

问题原因解决方案
插件未加载GUID冲突或依赖缺失检查日志中的GUID冲突,确保所有依赖已安装
Harmony补丁失败方法签名不匹配使用HarmonyLib.Tools验证方法签名,确保参数和返回类型匹配
配置文件不生成未调用Config.Bind确保在Awake或Start中绑定所有配置项
日志无输出日志级别设置过高在BepInEx.cfg中降低日志级别至Info或Debug
游戏崩溃空引用异常使用空值检查,如if (obj != null) { ... }

插件打包与发布

打包流程

  1. 创建发布脚本
#!/bin/bash
# build_plugin.sh

# 编译项目
dotnet build -c Release

# 创建输出目录
mkdir -p ./dist/MyFirstPlugin

# 复制插件文件
cp ./bin/Release/net48/MyFirstPlugin.dll ./dist/MyFirstPlugin/
cp ./bin/Release/net48/MyFirstPlugin.pdb ./dist/MyFirstPlugin/  # 调试符号(可选)

# 复制依赖项(如果需要)
# cp ../libs/SomeDependency.dll ./dist/MyFirstPlugin/

# 复制配置文件模板
cp ./config_template.cfg ./dist/MyFirstPlugin/com.example.myfirstplugin.cfg

# 创建压缩包
cd dist
zip -r MyFirstPlugin_v1.0.0.zip MyFirstPlugin/
  1. 手动打包步骤
    • 编译插件为Release版本
    • 创建插件文件夹(通常以GUID命名)
    • 复制DLL文件和配置模板
    • 压缩为ZIP包,包含版本号

发布渠道

  1. Nexus Mods:主流游戏 mods 分享平台
  2. Steam创意工坊:针对Steam游戏
  3. GitHub Releases:适合技术用户
  4. 国内平台:如3DM论坛、NGA插件区

发布时应包含:

  • 插件功能说明
  • 安装步骤
  • 配置说明
  • 变更日志
  • 截图或视频演示(可选)

实战示例:5个实用插件模板

1. 简单配置插件

[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
public class SimpleConfigPlugin : BaseUnityPlugin
{
    private ConfigEntry<float> _volume;
    private ConfigEntry<KeyboardShortcut> _muteHotkey;
    
    private void Awake()
    {
        // 配置音量
        _volume = Config.Bind<float>(
            "音频设置", 
            "音量", 
            0.7f, 
            new ConfigDescription(
                "游戏主音量",
                new AcceptableValueRange<float>(0f, 1f)
            )
        );
        
        // 配置静音热键
        _muteHotkey = Config.Bind<KeyboardShortcut>(
            "控制设置", 
            "静音热键", 
            new KeyboardShortcut(KeyCode.M, KeyCode.LeftControl),
            "快速静音的快捷键"
        );
        
        Logger.LogInfo("简单配置插件已加载!");
    }
    
    private void Update()
    {
        if (_muteHotkey.Value.IsDown())
        {
            var newVolume = _volume.Value > 0 ? 0 : 0.7f;
            _volume.Value = newVolume;
            Logger.LogInfo(newVolume > 0 ? "取消静音" : "已静音");
        }
    }
}

2. UI显示插件

using UnityEngine;
using UnityEngine.UI;

[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
public class UiDisplayPlugin : BaseUnityPlugin
{
    private GameObject _uiPanel;
    private Text _infoText;
    
    private void Awake()
    {
        // 创建UI面板
        _uiPanel = new GameObject("PluginUI");
        _uiPanel.transform.SetParent(GameObject.Find("Canvas").transform);
        
        // 添加RectTransform
        var rect = _uiPanel.AddComponent<RectTransform>();
        rect.anchoredPosition = new Vector2(10, -10);
        rect.sizeDelta = new Vector2(300, 100);
        
        // 添加背景
        var image = _uiPanel.AddComponent<Image>();
        image.color = new Color(0, 0, 0, 0.7f); // 半透明黑色
        
        // 添加文本
        _infoText = _uiPanel.AddComponent<Text>();
        _infoText.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
        _infoText.color = Color.white;
        _infoText.fontSize = 14;
        _infoText.alignment = TextAnchor.UpperLeft;
        _infoText.margin = new RectOffset(5, 5, 5, 5);
        
        // 更新显示信息
        UpdateInfoText();
        
        Logger.LogInfo("UI显示插件已加载!");
    }
    
    private void UpdateInfoText()
    {
        _infoText.text = $"FPS: {Mathf.Round(1 / Time.deltaTime)}\n" +
                         $"位置: {PlayerController.Instance.transform.position}";
    }
    
    private void Update()
    {
        if (_uiPanel != null)
            UpdateInfoText();
    }
    
    private void OnDestroy()
    {
        Destroy(_uiPanel);
    }
}

3. Harmony补丁插件

using HarmonyLib;

[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
public class HarmonyPatchPlugin : BaseUnityPlugin
{
    private Harmony _harmony;
    
    private void Awake()
    {
        _harmony = new Harmony(PluginInfo.PLUGIN_GUID);
        
        // 应用所有补丁
        _harmony.PatchAll(typeof(HealthPatch));
        _harmony.PatchAll(typeof(DamagePatch));
        
        Logger.LogInfo("Harmony补丁插件已加载!");
    }
    
    private void OnDestroy()
    {
        _harmony.UnpatchSelf();
    }
}

// 生命值显示补丁
[HarmonyPatch(typeof(PlayerStats), "SetHealth")]
public static class HealthPatch
{
    static void Postfix(PlayerStats __instance, float value)
    {
        Logger.LogInfo($"玩家生命值变更为: {value}");
        
        // 在屏幕显示生命值
        HUD.ShowNotification($"生命值: {value}/{__instance.maxHealth}");
    }
}

// 伤害倍率补丁
[HarmonyPatch(typeof(Weapon), "CalculateDamage")]
public static class DamagePatch
{
    static void Prefix(ref float damage)
    {
        // 增加50%伤害
        damage *= 1.5f;
    }
}

4. 配置菜单插件

using UnityEngine;
using UnityEngine.UI;

[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
public class ConfigMenuPlugin : BaseUnityPlugin
{
    private GameObject _menuWindow;
    private ConfigEntry<KeyboardShortcut> _menuHotkey;
    
    private void Awake()
    {
        // 注册热键
        _menuHotkey = Config.Bind<KeyboardShortcut>(
            "控制", 
            "菜单热键", 
            new KeyboardShortcut(KeyCode.F1), 
            "打开配置菜单的快捷键"
        );
        
        // 创建菜单UI
        CreateMenuUI();
        _menuWindow.SetActive(false); // 默认隐藏
        
        Logger.LogInfo("配置菜单插件已加载!按F1打开菜单");
    }
    
    private void Update()
    {
        // 切换菜单显示
        if (_menuHotkey.Value.IsDown())
        {
            _menuWindow.SetActive(!_menuWindow.activeSelf);
        }
    }
    
    private void CreateMenuUI()
    {
        // 创建菜单窗口
        _menuWindow = new GameObject("ConfigMenu");
        var canvas = _menuWindow.AddComponent<Canvas>();
        canvas.renderMode = RenderMode.ScreenSpaceOverlay;
        _menuWindow.AddComponent<CanvasScaler>();
        _menuWindow.AddComponent<GraphicRaycaster>();
        
        // 创建背景面板
        var panel = new GameObject("Panel");
        panel.transform.SetParent(_menuWindow.transform);
        var rect = panel.AddComponent<RectTransform>();
        rect.sizeDelta = new Vector2(400, 300);
        rect.anchoredPosition = Vector2.zero;
        panel.AddComponent<Image>().color = new Color(0.1f, 0.1f, 0.1f, 0.9f);
        
        // 创建标题
        var title = new GameObject("Title");
        title.transform.SetParent(panel.transform);
        title.AddComponent<RectTransform>().sizeDelta = new Vector2(380, 30);
        title.GetComponent<RectTransform>().anchoredPosition = new Vector2(0, 130);
        var text = title.AddComponent<Text>();
        text.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
        text.text = "插件配置菜单";
        text.fontSize = 20;
        text.alignment = TextAnchor.MiddleCenter;
        text.color = Color.white;
        
        // 添加更多UI元素...
    }
}

5. 保存数据管理插件

using System.IO;
using System.Text.Json;

[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
public class SaveDataPlugin : BaseUnityPlugin
{
    private string _savePath;
    private PlayerData _playerData;
    
    // 数据结构
    public class PlayerData
    {
        public int TotalKills { get; set; } = 0;
        public float BestTime { get; set; } = float.MaxValue;
        public string LastPlayed { get; set; } = "";
        public int[] UnlockedItems { get; set; } = new int[0];
    }
    
    private void Awake()
    {
        // 设置保存路径
        _savePath = Path.Combine(Paths.GameRootPath, "BepInEx", "save_data.json");
        
        // 加载数据
        LoadData();
        
        // 注册事件监听
        GameEvents.OnEnemyKilled += OnEnemyKilled;
        GameEvents.OnLevelCompleted += OnLevelCompleted;
        
        Logger.LogInfo("保存数据管理插件已加载!");
    }
    
    private void OnDestroy()
    {
        // 保存数据
        SaveData();
        
        // 取消事件监听
        GameEvents.OnEnemyKilled -= OnEnemyKilled;
        GameEvents.OnLevelCompleted -= OnLevelCompleted;
    }
    
    private void LoadData()
    {
        try
        {
            if (File.Exists(_savePath))
            {
                var json = File.ReadAllText(_savePath);
                _playerData = JsonSerializer.Deserialize<PlayerData>(json);
                Logger.LogInfo("数据加载成功!");
            }
            else
            {
                _playerData = new PlayerData();
                Logger.LogInfo("创建新的保存数据!");
            }
        }
        catch (Exception e)
        {
            Logger.LogError($"数据加载失败: {e.Message}");
            _playerData = new PlayerData();
        }
    }
    
    private void SaveData()
    {
        try
        {
            _playerData.LastPlayed = System.DateTime.Now.ToString();
            var json = JsonSerializer.Serialize(_playerData, new JsonSerializerOptions { WriteIndented = true });
            File.WriteAllText(_savePath, json);
            Logger.LogInfo("数据保存成功!");
        }
        catch (Exception e)
        {
            Logger.LogError($"数据保存失败: {e.Message}");
        }
    }
    
    private void OnEnemyKilled()
    {
        _playerData.TotalKills++;
        Logger.LogInfo($"总击杀数: {_playerData.TotalKills}");
    }
    
    private void OnLevelCompleted(float time)
    {
        if (time < _playerData.BestTime)
        {
            _playerData.BestTime = time;
            Logger.LogInfo($"新纪录: {time}秒");
        }
    }
}

总结与进阶学习路径

知识点回顾

通过本文学习,你已经掌握了:

  • BepInEx框架的核心架构和工作原理
  • 插件开发的基础结构和生命周期
  • 配置系统、日志系统和热键系统的使用
  • Harmony补丁技术实现游戏方法修改
  • 插件调试、打包和发布的完整流程
  • 5个实用插件模板的实现

进阶学习路径

mermaid

学习资源推荐

  1. 官方文档

    • BepInEx官方文档:https://docs.bepinex.dev
    • HarmonyLib文档:https://harmony.pardeike.net
  2. 示例项目

    • BepInEx插件模板:https://gitcode.com/GitHub_Trending/be/BepInEx
    • 社区插件集合:https://github.com/bbepis/BepisPlugins
  3. 开发工具

    • dnSpy:.NET反编译与调试工具
    • ILSpy:C#代码反编译工具
    • Unity Profiler:性能分析工具
  4. 社区支持

    • BepInEx Discord:https://discord.gg/MpFEDAg
    • 插件开发论坛:https://forum.unity.com/

附录:常用API速查表

类别常用API用途
插件基础BaseUnityPlugin插件基类,提供生命周期方法
BepInPlugin标记插件元数据的特性
PluginInfo存储插件GUID、名称和版本
配置系统Config.Bind<T>()绑定配置项
ConfigEntry<T>.Value获取或设置配置值
Config.Save()手动保存配置
日志系统Logger.LogInfo()输出信息日志
Logger.LogError()输出错误日志
ManualLogSource创建自定义日志源
HarmonyHarmony.PatchAll()应用所有补丁
[HarmonyPatch]标记补丁类
Prefix/Postfix补丁方法前缀/后缀
工具类Paths提供常用路径(插件目录、配置目录等)
UnityEngine.ObjectUnity对象操作
Time时间相关功能

如果觉得本教程对你有帮助,请点赞、收藏并关注作者,获取更多游戏开发教程!下期预告:《BepInEx高级技巧:IL2CPP游戏插件开发实战》

【免费下载链接】BepInEx Unity / XNA game patcher and plugin framework 【免费下载链接】BepInEx 项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值