一. 前言
玩了一天的撒币:双冠,玩法和前代基本上是一样的,不过,钱袋还是一如既往的小,装不了多少就开始撒币了,所以,我们的第一个mod,就以修改钱袋为目标来进行。
二. 观察和分析
对于一个新接触的游戏,我们制作mod大部分的时间都会用来观察游戏逻辑,分析游戏的结构,找到我们需要修改的地方,才能进行mod制作。首先我们打开dnspy,将AC.dll拖入dnspy,观察双冠这几百个类。
我们这次的目标是钱袋,关于钱的修改在mod和修改器里非常常见,有几个高频词语值得关注:gold
money
coin
gem
,这些都是游戏中常见的货币,我们先以此对这些词语进行搜索,果不其然,coin和gem都搜索到了大量的结果,联系到我们游戏中的两种货币,对于这次的游戏我们运气比较好,一次就找到了他们。
对于大钱袋这个mod,其实我们并不一定真的需要让钱袋变大,在游戏中我们可以发现,硬币都是一枚一枚的扔进钱袋的,他们之间存在物理的碰撞,溢出的硬币会掉出来。所以,我们只要让硬币变小,就可以实现大钱袋的效果,这样不会变动钱袋图片的大小,不会对游戏的UI造成影响。
所以接下来,我们就针对涉及到coin的几个类进行工作。
三. 新建项目
关于新建项目的步骤在之前的教程中我们已经说过了,这里我们快速的创建一下。
- 新建.Net Framework类库程序, 平台4.5, 项目名称BigWallet
- 添加常用引用
- 修改Class1为Main
- 添加info.json,属性修改为较新则复制
- using常用命名空间
- 写出mod主体
这样,我们的基础部分就完成了,主类现在应该看起来是这个样子的
using System;
using Harmony12;
using UnityEngine;
using System.Linq;
using System.Text;
using System.Reflection;
using UnityModManagerNet;
using System.Collections.Generic;
namespace BigWallet
{
public static class Main
{
public static UnityModManager.ModEntry mod;
public static bool Load(UnityModManager.ModEntry modEntry)
{
mod = modEntry;
HarmonyInstance.Create(mod.Info.Id).PatchAll(Assembly.GetExecutingAssembly());
return true;
}
}
}
info.json
{
"Id": "BigWallet",
"DisplayName": "大钱袋",
"Author": "xiaoye97",
"Version": "1.0.0",
"AssemblyName": "BigWallet.dll",
"EntryMethod": "BigWallet.Main.Load"
}
四. 补丁
根据观察,我们觉得Coin类应该就是我们要改的地方,观察类可以发现它有物理的相关函数,会参与碰撞,所以我们在Load下面写下补丁如下
[HarmonyPatch(typeof(Coin), "OnEnable")]
class CoinPatch
{
public static void Postfix(Coin __instance)
{
if (mod.Enabled)
{
__instance.gameObject.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f);
}
}
}
这样,我们就在Coin的OnEnable函数调用之后,把Coin的大小修改为0.5倍,需要注意的是,在所有的逻辑前,我们都应该判断一下mod.Enabled,这样的好处是可以在游戏内关闭Mod,如果我们不加判断,即使玩家在游戏内关闭了Mod,实际上逻辑还是在继续执行的,关于Mod什么时候执行的判断,应该是我们开发者的责任。
接下来,我们编译Mod,添加到游戏,然后启动游戏。然而,我们可以看到,我们预想的结果并没有发生,钱袋里的硬币并没有变小,这是怎么回事呢?原来,这个Coin并不是钱袋内的硬币,这个时候如果我们进行花钱操作,就可以发现,漂浮到建筑上的硬币变成了一半大小,也就是说,Coin这个类,控制的是花钱时漂浮出来的这个硬币,我们的目标应该不是它。
我们继续从dnspy观察有关Coin的类,很快,我们发现了真正的目标,BagCoin,这次就显而易见了,根据这个名字我们就能断定它应该就是钱袋内真正发送碰撞的那个硬币。删掉刚才的补丁,我们重新写一个。
[HarmonyPatch(typeof(BagCoin), "Show")]
class BagCoinPatch
{
public static void Postfix(Coin __instance, bool visible)
{
if(mod.Enabled)
{
if (visible)
{
__instance.gameObject.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f);
}
}
}
}
BagCoin中没有OnEnable,但是有个Show方法,大致阅读代码,我们就能发现这个方法就是显示硬币的方法,我们跟在它的后面打上补丁,判断当Show传入visible为true时,改变BagCoin大小为一半。
我们再次编译Mod进入游戏,这次,我们可以之间发现钱袋内的硬币变成了一半大小,至此,我们这个小Mod就完成了。再加上一个UI写上作者信息,整体代码如下
Main.cs
using System;
using Harmony12;
using UnityEngine;
using System.Linq;
using System.Text;
using System.Reflection;
using UnityModManagerNet;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace BigWallet
{
public static class Main
{
public static UnityModManager.ModEntry mod;
public static bool Load(UnityModManager.ModEntry modEntry)
{
mod = modEntry;
HarmonyInstance.Create(mod.Info.Id).PatchAll(Assembly.GetExecutingAssembly());
mod.OnGUI = OnGUI;
return true;
}
public static void OnGUI(UnityModManager.ModEntry modEntry)
{
GUILayout.BeginVertical("大钱包Mod", GUI.skin.window);
GUILayout.Label("作者: xiaoye97");
GUILayout.EndVertical();
}
[HarmonyPatch(typeof(BagCoin), "Show")]
class BagCoinPatch
{
public static void Postfix(Coin __instance, bool visible)
{
if(mod.Enabled)
{
if (visible)
{
__instance.gameObject.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f);
}
}
}
}
}
}