差分
このページの2つのバージョン間の差分を表示します。
両方とも前のリビジョン 前のリビジョン 次のリビジョン | 前のリビジョン | ||
appendix:harmonyがある時 [2024/12/18 15:10] fumble |
appendix:harmonyがある時 [2024/12/29 00:31] (現在) fumble |
||
---|---|---|---|
行 54: | 行 54: | ||
それぞれ渡すべきプロトタイプは | それぞれ渡すべきプロトタイプは | ||
- | prefixはパッチを当てるものと同じもの。 | + | prefixはパッチを当てるものと同じもの。\\ |
- | postfixはパッチを当てるものの戻り値を受け取る戻りに無しのもの。 | + | postfixはパッチを当てるものの戻り値を受け取る戻りに無しのもの。\\ |
- | finalizerはExceptionを貰ってExceptionを返すもの。 | + | finalizerはExceptionを貰ってExceptionを返すもの。\\ |
- | transpilerとilmanipulatorは以下の様なもの。 | + | transpilerとilmanipulatorは以下の様なもの。\\ |
<code csharp> | <code csharp> | ||
static IEnumerable< | static IEnumerable< | ||
static void ILManipulator(ILContext il, MethodBase original, ILLabel retLabel) | static void ILManipulator(ILContext il, MethodBase original, ILLabel retLabel) | ||
static void SomeOtherILManipulator(ILContext ctx, MethodBase orig) | static void SomeOtherILManipulator(ILContext ctx, MethodBase orig) | ||
+ | </ | ||
+ | |||
+ | 渡すときはHarmonyMethod(MethodInfo method)の変換、つまりコンストラクターを呼んで変換させる。 | ||
+ | <code csharp> | ||
+ | var transpilermethod = typeof(トランスパイラーのあるクラス).GetMethod(トランスパイラーのメソッド名); | ||
+ | var transpiler = Activator.CreateInstance(typeHarmonyMethod, | ||
</ | </ | ||
問題が起こりそうなのはTranspilerとILManipulatorのパターンでCodeInstructionがHarmonyの中で、ILLabelがMonoMod.Cliの中で宣言されているので参照出来ない状況だと面倒になる。\\ | 問題が起こりそうなのはTranspilerとILManipulatorのパターンでCodeInstructionがHarmonyの中で、ILLabelがMonoMod.Cliの中で宣言されているので参照出来ない状況だと面倒になる。\\ | ||
- | ILContextはMono.CecilなのでSybaris2/ | + | ※ILContextはMono.CecilなのでSybaris2/ |
特に面倒が起こりそうな Transpiler の実装方法を示す。 | 特に面倒が起こりそうな Transpiler の実装方法を示す。 | ||
<code csharp> | <code csharp> | ||
- | static object Transpiler(IEnumerable< | + | static object Transpiler(IEnumerable instructions) |
{ | { | ||
- | var type = instructions.First().GetType(); | + | var enumerator |
- | | + | |
- | var fldOperand | + | |
- | var newInstructions = Activator.CreateInstance(typeof(List<> | + | |
- | foreach (var instruction in instructions) | + | |
{ | { | ||
- | var opecode = fldOpecode.GetValue(instruction); | + | |
- | var operand = fldOperand.GetValue(instruction); | + | var fldOpecode = type.GetField(" |
- | if (opecode.Equals(変えたいところのOpCode) && operand.Equals(変えたいところのOperand)) | + | var fldOperand = type.GetField(" |
- | newInstructions.Add(Activator.CreateInstance(type, | + | var newInstructions = Activator.CreateInstance(typeof(List<> |
- | else | + | foreach (var instruction in instructions) |
- | newInstructions.Add(instruction); | + | { |
+ | | ||
+ | var operand = fldOperand.GetValue(instruction); | ||
+ | if (opecode.Equals(変えたいところのOpCode) | ||
+ | newInstructions.Add(Activator.CreateInstance(type, | ||
+ | else | ||
+ | newInstructions.Add(instruction); | ||
+ | } | ||
} | } | ||
return newInstructions; | return newInstructions; | ||
} | } | ||
</ | </ | ||
+ | 引数をIEnumerableで受けて戻り値をobjectとかで宣言してしまいます。\\ | ||
+ | 引数で貰った IEnumerable< | ||
+ | |||
+ | <code csharp> | ||
+ | var newInstructions = Activator.CreateInstance(typeof(List<> | ||
+ | return newInstructions; | ||
+ | </ | ||
+ | |||
+ | こんなのでいいの?って思うかもしれませんが多分これで良いのです。\\ | ||
+ | あとは変えたいところだけ、全部変えたいなら全部詰め直して返せば良いです。\\ | ||
+ | OpCodeはSystem.Reflection.Emit.OpCodeっぽいのでこれを参照すればHarmonyLibの参照はなしでいけます。\\ | ||
+ | ILManipulatorの方もILLabel retLabelをobjectで受けてリフレクションを使えばいけると思います、必要が無い限りILLabelのない方を使えばいいと思います。\\ | ||
- | はい、引数も戻り値も大嘘で宣言します。\\ |