Unity游戏Mod/插件制作教程03 - 插件实例1: HelloWorld

准备工作
作为编程类的教程,果然第一个需要来一个传统项目——HelloWolrd。

在开始之前,我先贴一个链接,这是BepInex官方的开发手册 https://bepinex.github.io/bepinex_docs/v5.0/articles/dev_guide/index.html 有什么问题也可以翻阅官方的手册,也许会有启发。

我们打开VS,新建一个.Net Framework类库项目,Framework版本根据游戏使用的版本决定,打开游戏的Data/Managed文件夹,看看System开头的几个文件,都是使用的什么版本。

我们以【~在魔界当女仆~恶魔天使与勇者的秘密喫茶店】和【装机模拟器】这两款游戏为例,可以看到在前者中,版本为4.6,后者为3.5,大多数的情况下,我们会使用4以上的版本。 

Unity游戏Mod/插件制作教程03 - 插件实例1: HelloWorld_第1张图片

Unity游戏Mod/插件制作教程03 - 插件实例1: HelloWorld_第2张图片

 以【~在魔界当女仆~恶魔天使与勇者的秘密喫茶店】为例,我们新建一个.NetFramework 4.6的类库项目。

Unity游戏Mod/插件制作教程03 - 插件实例1: HelloWorld_第3张图片

接下来我们添加一下常用的引用,我们一般会根据情况选择使用哪些dll,首先BepInex/Core文件夹下的BepInEx.dll和0Harmony20.dll是很常用的dll,我们选择上。在Data/Managed文件夹内有很多游戏使用到的dll,我举几个常用的。

Assembly-CSharp.dll //绝大多数的Unity游戏,逻辑都是放在这里的,所以想调用或者修改游戏内的东西,这个要添加引用
Assembly-CSharp-firstpass.dll //少数游戏会把逻辑放在这里,比如装机模拟器
UnityEngine.dll Unity2017之后,//各种功能都被分散成很多dll,各种dll负责转发引用,所以这个dll我们每次都加上
UnityEngine.CoreModule.dll //引擎的核心dll
UnityEngine.IMGUIModule.dll //OnGUI所使用的dll,也就是通常情况下,我们插件的界面所使用的界面库
其他的dll。我们以后使用到再说,今天只是写一个最最基本的插件。

Unity游戏Mod/插件制作教程03 - 插件实例1: HelloWorld_第4张图片

 小技巧: 全选所有引用,把 复制本地 属性改为否,如果我们不这样选择的话,回头编译的时候,就会把引用到的相关dll也一起复制到输出目录,可能会有一大堆文件,所以这样比较简洁。

开始编写插件
我们给默认的Class1修改一个我们想要的名字,我这里改为PluginTutorial,然后将BepInEx的命名空间using一下。

在BepInEx中,给我们准备了一个类,BaseUnityPlugin,这是继承于MonoBehaviour的,也就是说,我们的插件,最终会以组件的形式挂载,实际上也是这样,每个插件最终都会挂载到游戏中BepInEx的物体身上。所以我们可以使用MonoBehaviour的各种生命周期,比如Awake,Start,Update等等,这些我们以后再说,先来看一下最基础的插件的样子。

using System;
using BepInEx;

namespace PluginTutorial
{
    //插件描述特性 分别为 插件ID 插件名字 插件版本(必须为数字)
    [BepInPlugin("me.xiaoye97.plugin.Tutorial", "Tutorial Plugin", "1.0")]
    public class PluginTutorial : BaseUnityPlugin //继承BaseUnityPlugin
    {
        //Unity的Start生命周期
        void Start()
        {
            //输出日志
            Logger.LogInfo("HelloWorld!");
        }
    }
}
我们将PluginTutorial继承BaseUnityPlugin,并在类上方添加了一个叫做BepInPlugin的特性,这是必须要完成的,只有这样才能正确加载插件。

如果你不知道特性是什么,可以去补一下C#关于特性方面的知识。

在BepInPlugin特性中,我们填入了3个参数,分别是插件的ID,插件的名字,插件的版本号,对于ID,我个人习惯使用域名反写法,一般是me.xiaoye97.plugin.游戏名.插件名,插件的名字没有什么特别的要求,直观即可。在插件版本这里,必须是数字形式的版本号,不能夹杂字母等。

这样。我们第一个插件就完成了,在顶部工具栏选择生成->生成 PluginTutorial,等生成完毕后,打开输出的目录,将生成的PluginTutorial.dll复制到我们的 BepInEx/plugins目录下。
运行游戏,通过控制台我们可以看到我们的插件已经成功加载了,虽然它现在什么功能都没有。
其他事项
插件的特性除了BepInExPlugin之外,还有两个可能会用到的特性。

第一个是BepInProcess特性,大部分情况下,我们不需要写这个特性,但是偶尔会遇到特殊情况。比如,在I社游戏(例如AI少女、恋爱活动等)中,不仅有游戏本体,还有一个工作室程序,将游戏本体与内容创作进行了分割,这样,就会有两个exe,但是,他们是两个不同的exe,有很多地方是不能公用的。那么,只需要用这个特性,就可以限制插件在指定的exe上可以运行。
例如

[BepInPlugin("me.xiaoye97.plugin.Tutorial", "Tutorial Plugin", "1.0")]
[BepInProcess("Maid In Makai.exe")]
public class PluginTutorial : BaseUnityPlugin
{

}
这样,就是限定只在这个exe中运行,如果想限制在几个exe中可以运行,就继续添加这样特性即可。

第二个是BepInDependency特性,如果我们的插件,需要以其他的什么插件为前置插件,那么就需要使用这个特性添加依赖,以保证只有在有前置插件的情况下加载我们的插件。

BepInDependency特性有3种写法,分别是

[BepInPlugin("me.xiaoye97.plugin.Tutorial", "Tutorial Plugin", "1.0")]
// 软依赖,如果没有前置插件,依旧继续加载
[BepInDependency("com.bepinex.plugin.somedependency", BepInDependency.DependencyFlags.SoftDependency)]
// 硬依赖,如果没有前置插件,则停止加载
[BepInDependency("com.bepinex.plugin.importantdependency", BepInDependency.DependencyFlags.HardDependency)]
// 省略参数,则默认为硬依赖
[BepInDependency("com.bepinex.plugin.anotherimportantone")]
public class PluginTutorial : BaseUnityPlugin
{

}

除了这些特性之外,还有一点我们需要注意的是,一个dll中可以包括多个插件,只要我们写多个继承BaseUnityPlugin的类,并为他们赋予BepInPlugin特性即可。


有什么问题或者建议可以在评论区评论或者与我私信交流。 作者:宵夜97 https://www.bilibili.com/read/cv8997577?spm_id_from=333.999.0.0 出处:bilibili

你可能感兴趣的:(游戏,unity,游戏引擎)