TimberbornのModを作ったのでメモ。
作ったのは結構前(ヒマワリが追加される前くらいだったはず)
C#についてはメインブログで書いているけどメモなのでこちらのブログに残しておくことにする。
Timberboneの紹介をば
ビーバーが街づくりをするゲーム。
雨季と乾季が交互にやってくる世界で雨季の間にダムを作って水をためて乾季に耐えながら街を大きくしていく感じ。
乾季は水源から出てくる水が止まってしまう。おもしろいよ。
モッドを作ってみた
作ったのは乾季になっても水が枯れないというモッド
モッドはざっくり分けると、
・3Dモデルとかアイテムとかそれに付属する設定ファイルとかを改造したやつ
・システムを改造したやつ
がある、今回は「システムを改造したやつ」になる
Unityで作られたゲームのシステムを改造するにはゲームフォルダ内にあるdllをいじることになる。
配布とかを考えなければ、dllを逆コンパイルしてソースファイルを書き換えて再コンパイルでdllに戻して配置という感じになる。
この方法はゲーム自体のアップデートでそのdllが上書きされてしまうことがある。
ちゃんと作るには、「BepInEx」というUnity製ゲーム(mono)でMODを読み込むようにするフレームワークと「Harmony」というC#でつくられたdllにあるメソッドの前後にコードを割り込みで実行できるようするライブラリを使う。
この2つを使うことで元のDLLはそのままで自分の書いたコードを途中にインジェクトすることができる。
BepInExはTimberbornがインストールされているフォルダーに配置すればよかったはず。
んで、どのDLLのどのコードをいじればいいかの調査は、DLLを逆コンパイルしてみていく感じ、自分が使ったのは「dnSpy」というツール
で、さがしてみると「Timberborn.WaterSourceSystem.dll」に「ShouldStopWaterFlow」というプロパティを発見、こいつで水源を止める止めないをフラグ管理しているみたい。常にこれがfalseを返せば水は止まらないはず、とりあえずdllをdnSpyで直接書き換えてみたらいい感じに!
で、いざmod用のdllを作るときにつまづいた。
「ShouldStopWaterFlow」プロパティを持っている「DroughtWaterSourceController」クラスはpublicではなく外部からTypeを取得できなかったので、System.Reflection.Assemlyを使ってメタ情報からGetTypeする必要があった。
ので、「Timberborn.WaterSourceSystem.dll」があるフルパスを指定する必要がありインストール先に依存してしまった。
using BepInEx;
using HarmonyLib;
using System.Linq;
using System.Reflection;
namespace InfiniteWaterSource {
[BepInPlugin("yasnote.timberborn.infinite_water_source", "Infinete Water Souce", "0.0.9")]
[BepInProcess("Timberborn.exe")]
public class Plugin : BaseUnityPlugin {
void Awake() {
var harmony = new Harmony("yasnote.timberborn.infinite_water_source");
//なんとかしてTypeを取得したい
var asm = Assembly.LoadFile("Timberborn.WaterSourceSystem.dllのフルパス");
var type = asm.GetType("Timberborn.WaterSourceSystem.DroughtWaterSourceController");
var original_method = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly).FirstOrDefault(x => x.Name == "get_ShouldStopWaterFlow");
//割り込ませる処理を指定(Prefixはオリジナルの処理が実行される前に割り込ませるというパラメータ)
var pre_method = new HarmonyMethod(typeof(PatchClass), "Prefix");
pre_method.methodType = MethodType.Getter;
harmony.Patch(original_method, pre_method, null, null, null, null);
Logger.LogInfo($"Plugin InfiniteWaterSource is loaded...!!!");
}
//割り込ませる処理
public static class PatchClass{
public static bool Prefix(ref bool __result) {
__result = false; //水源は何があっても止まらない
return false;
}
}
}
}
あとがき
HarmonyはもとになるDLLをいじらずに処理を挿入できるのでゲームじゃなくてもいろいろできそう。
見た感じ.Net Framework4.8が対象っぽいけれど・・・
作ったModをいれて遊んだけれど完全にヌルゲーになってしまった、、、
MODは自己責任ということですね!!
コメント