mod吧 关注:15,435贴子:23,947

【Mod教程】从0开始教你使用BepInEx为游戏制作插件Mod

只看楼主收藏回复

介绍:
什么是BepInEx?BepInEx是一个注入unity引擎游戏,为Mod开发者提供开发入口的一个插件;
BepInEx提供了诸多功能,包括:
- 嵌入式安装
- 内置配置和日志
- 使用Harmony 补丁运行方法;[包括Harmony 和 MonoMod,用于启动时方法注入]
- 内置组件补丁,借助 UnityDoorstop 可以使用游戏游戏中的 Mono.Cecil


IP属地:上海1楼2021-03-01 16:30回复
    开一个新坑,这个系列主要来介绍BepInEx的使用方法以及插件的制作方法;
    2楼留作补充,所有相关链接都会在对应楼层的评论区进行发布,如有被系统删帖的情况记得反馈


    IP属地:上海2楼2021-03-01 16:33
    收起回复
      1.BepInEx的说明与介绍
      介绍:
      什么是BepInEx?BepInEx是一个注入unity引擎游戏,为Mod开发者提供开发入口的一个插件;
      BepInEx提供了诸多功能,包括:
      - 嵌入式安装
      - 内置配置和日志
      - 使用Harmony 补丁运行方法;[包括Harmony 和 MonoMod,用于启动时方法注入]
      - 内置组件补丁,借助 UnityDoorstop 可以使用游戏游戏中的 Mono.Cecil
      与 Unity Mod Manager的区别
      (这段摘自B站-宵夜97)
      两者的相同点:
      UMM和BepInEx都使用Harmony库作为核心来对游戏进行功能修改。两者的不允许游戏路径出现中文或其他特殊符号,所以请保证游戏安装在纯英文路径。
      两者的不同点:
      UMM使用一个单独的exe程序来安装Mod环境,此程序基于.Net,需要玩家电脑安装.Net4.5之后的版本才能启动。Mod环境的安装有两种方式,一种是直接修改程序集来加入环境,一种是通过UnityDoorStop在游戏启动时加载Mod环境,第一种方式因为破坏了游戏原有的程序,所以每次游戏更新的时候,都会导致Mod环境丢失需要重新安装,第二种方式不会破坏游戏的原有程序集,所以不会因为游戏更新而丢失环境。在Mod安装方面,UMM也有两种方式,一种是直观的,将Mod压缩包拖动到安装器内来安装,另一种是手动解压Mod包,放到正确的路径。UMM还内置了一个Mod管理界面,在游戏中按Ctrl+F10可以呼出管理界面,修改Mod配置、开启关闭Mod等。
      BepInEx没有单独的exe程序,环境的安装只是需要将BepInEx解压到游戏根目录即可。插件的加载方式上,等于UMM的第二种,也是通过UnityDoorStop来运行时加载。插件的安装方式上只有一种,将插件解压到指定的目录下(BepInEx/plugins)即可,没有UMM要求目录那么严格。BepInEx本身并不含有可视化的插件管理等功能。


      IP属地:上海本楼含有高级字体3楼2021-03-01 16:34
      收起回复
        2.BepInEx的下载与安装


        发不出来,详细见博客:aoe.top/mod/403


        IP属地:上海本楼含有高级字体5楼2021-03-01 16:43
        收起回复
          3.开发环境的搭建与调试以及有用的工具们
          必备工具:
          在正式开始编写Mod插件之前,我们需要准备一些工具:
          - Visual Studio(VS)任意版本
          - dnSpy [或其他你觉得用的顺手的反汇编工具]
          - Visual Studio Code(VSC) [或其他你觉得用的顺手的高级文本编


          IP属地:上海本楼含有高级字体6楼2021-03-01 16:44
          收起回复
            3.2开启BepInEx Debug模式


            用VSC打开“BepInEx\config\BepInEx.cfg”,
            修改
            [Logging.Console]Enabled = false

            [Logging.Console]Enabled = true



            IP属地:上海本楼含有高级字体7楼2021-03-01 16:50
            回复
              3.3提取需要的库
              我们在项目文件夹中新建一个文件夹,取名为"libs",然后从游戏目录中复制一些我们需要用到的dll文件库出来:
              “XXXX_Data\Managed”中的
              "Assembly-CSharp.dll","UnityEngine.dll",可选复制文件"UnityEngine.ClothModule.dll","UnityEngine.UI.dll"
              “\BepInEx\core”中的
              "0Harmony.dll","BepInEx.dll","BepInEx.Harmony.dll"
              到此,开发环境搭建好了,下一章我们开始创建项目



              IP属地:上海本楼含有高级字体8楼2021-03-01 16:51
              回复
                3.4可选安装
                - BepInEx.ConfigurationManager
                - BepInEx.Debug tools
                说明:
                1.BepInEx.ConfigurationManager:
                BepInEx.ConfigurationManager是BepInEx的一个内置管理UI,解压放到“BepInEx/plugins”,
                进游戏按F1即可查看当前所有在运作中的插件;
                2. BepInEx.Debug:
                BepInEx.Debug是BepInEx的一个调试工具库,里面也包含了一些其他的工具:
                ScriptEngine:允许直接重新加载插件而无需重新运行游戏,将你的插件放到“BepInEx/scripts”文件夹中,并在游戏中按F6即可。你可以通过创建“OnDestroy()”方法来处理脚本重载时的需要卸载的资源;
                Startup profiler:记录每个脚本的加载所需时间;
                Mono Profiler:unity游戏的监听器,用来记录所有被调用的方法,调用次数和调用时间;
                Demystify Exceptions:更加人性化的处理报错格式,并正确解析IEnumerables,lambdas 和 async 的状态


                IP属地:上海本楼含有高级字体9楼2021-03-01 16:51
                回复
                  4.1.创建插件,实现“Hello, world”的输出
                  创建插件:
                  通过前面几章的熟悉,现在可以开始创建我们的BepInEx插件了。
                  新建项目
                  打开Visual Studio,新建项目,选择“C# NET Framework 类库”

                  接着继续创建项目,.NET框架暂时没有什么特别的要求,别太低就行了


                  IP属地:上海本楼含有高级字体10楼2021-03-01 16:58
                  收起回复
                    4.2引入游戏类库
                    将我们之前拿出来的几个dll库引用进来

                    接下来,将刚刚引用进来的库全选,然后将“复制到本地”改为“false”

                    顺便将默认的“Class1.cs”改名成我们自己的名称。


                    IP属地:上海本楼含有高级字体11楼2021-03-01 17:00
                    回复
                      4.3定义插件
                      我们需要从 BaseUnityPlugin 继承类,并将BepInPlugin添加到该类
                      using System;
                      using BepInEx;
                      using UnityEngine;


                      namespace MyFirstBepInExMod
                      {
                      [BepInPlugin("aoe.top.plugins.MyFirstBepInExMod", "这是我的第一个BepIn插件", "1.0.0.0")]
                      public class MyFirstBepInExMod : BaseUnityPlugin
                      {


                      }
                      }
                      至此,我们就已经完成一个插件的基本结构了,现在来解释一下
                      public BepInPlugin(string GUID, string Name, string Version);
                      string GUID:插件的唯一ID标识符,绝对且是唯一的,不能存在重复,大家在命名的时候尽量避免重复的现象,请用自己专属的唯一标识符来命名;
                      string Name:插件名称,可以使用中文,
                      string Version:插件版本,必须使用系统可解析的格式,如“1.0.0”、“0.2.1”、“2.6.0”之类的


                      IP属地:上海本楼含有高级字体12楼2021-03-01 17:02
                      收起回复
                        4.4启动函数
                        BepInEx中有4个函数比较常用的函数,大家可以简单记一下:
                        Awake():在插件启动时会直接调用Awake()方法;
                        Start():在所有插件全部执行完成后会调用Start()方法,执行顺序在Awake()后面;
                        Update():插件启动后会一直循环执行Update()方法,可用于监听事件或判断键盘按键,执行顺序在Start()后面;
                        OnDestroy():在插件关闭时会调用OnDestroy()方法,可处理前面提到的“ScriptEngine”插件重启时需要做的操作。


                        IP属地:上海本楼含有高级字体13楼2021-03-01 17:04
                        回复
                          4.5测试和编译插件
                          了解了上面这些后,现在,我们开始写代码:
                          // 在插件启动时会直接调用Awake()方法
                          void Awake()
                          {
                          // 使用Debug.Log()方法来将文本输出到控制台
                          Debug.Log("Hello, world!");


                          }


                          // 在所有插件全部启动完成后会调用Start()方法,执行顺序在Awake()后面;
                          void Start()
                          {
                          Debug.Log("这里是Start()方法中的内容!");
                          }


                          // 插件启动后会一直循环执行Update()方法,可用于监听事件或判断键盘按键,执行顺序在Start()后面
                          void Update()
                          {
                          var key = new BepInEx.Configuration.KeyboardShortcut(KeyCode.F9);


                          if (key.IsDown())
                          {
                          Debug.Log("这里是Updatet()方法中的内容,你看到这条消息是因为你按下了F9");
                          }
                          }
                          // 在插件关闭时会调用OnDestroy()方法
                          void OnDestroy()
                          {
                          Debug.Log("当你看到这条消息时,就表示我已经被关闭一次了!");
                          }
                          确认没有报错后,在VS中按F6,编译我们的插件,然后打开“MyFirstBepInExMod\bin\Debug”就可以看到我们刚刚编译好的插件了,
                          将插件复制到“\BepInEx\scripts”中,运行游戏,
                          注意:我这里是默认你安装了“ScriptEngine”,如果没有,则是放入“BepInEx\plugins”文件夹,如需安装,可以参考3.4,第9楼


                          IP属地:上海本楼含有高级字体14楼2021-03-01 17:06
                          回复
                            4.6控制台调试
                            在游戏中按F6,载入“\BepInEx\scripts”文件夹中的脚本,就可以看到我们的内容了

                            如果看到控制台输出了内容,那么恭喜你,你已经成功的制作了一个 BepInEx Mod


                            IP属地:上海本楼含有高级字体15楼2021-03-01 17:07
                            回复
                              4.7 完整代码:
                              using System;
                              using BepInEx;
                              using UnityEngine;


                              namespace MyFirstBepInExMod
                              {
                              [BepInPlugin("aoe.top.plugins.MyFirstBepInExMod", "这是我的第一个BepIn插件", "1.0.0.0")]
                              public class MyFirstBepInExMod : BaseUnityPlugin
                              {
                              // 在插件启动时会直接调用Awake()方法
                              void Awake()
                              {
                              // 使用Debug.Log()方法来将文本输出到控制台
                              Debug.Log("Hello, world!");


                              }


                              // 在所有插件全部启动完成后会调用Start()方法,执行顺序在Awake()后面;
                              void Start()
                              {
                              Debug.Log("这里是Start()方法中的内容!");
                              }


                              // 插件启动后会一直循环执行Update()方法,可用于监听事件或判断键盘按键,执行顺序在Start()后面
                              void Update()
                              {
                              var key = new BepInEx.Configuration.KeyboardShortcut(KeyCode.F9);


                              if (key.IsDown())
                              {
                              Debug.Log("这里是Updatet()方法中的内容,你看到这条消息是因为你按下了F9");
                              }
                              }
                              // 在插件关闭时会调用OnDestroy()方法
                              void OnDestroy()
                              {
                              Debug.Log("当你看到这条消息时,就表示我已经被关闭一次了!");
                              }
                              }
                              }


                              IP属地:上海本楼含有高级字体16楼2021-03-01 17:08
                              收起回复