• 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以上的版本。 

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

    接下来我们添加一下常用的引用,我们一般会根据情况选择使用哪些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。我们以后使用到再说,今天只是写一个最最基本的插件。

     小技巧: 全选所有引用,把 复制本地 属性改为否,如果我们不这样选择的话,回头编译的时候,就会把引用到的相关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

  • 相关阅读:
    java计算机毕业设计学生选课系统源码+数据库+系统+lw文档+部署
    Promise与async/await与Generator
    植物大战僵尸变态辅助开发系列教程(E语言实现和VC6实现)(下)
    postgis ST_CoverageInvalidEdges用法
    [yarn]yarn异常
    (pytorch进阶之路)IDDPM之diffusion实现
    计算机毕业设计django基于python的宠物分享网站(源码+系统+mysql数据库+Lw文档)
    线程池优化
    【音视频基础】封装格式与编码数据
    极简opencv操作xml文件
  • 原文地址:https://blog.csdn.net/m0_69824302/article/details/127964615