|
1 | 1 | using System.Collections.Generic;
|
| 2 | +using System.Reflection.Emit; |
2 | 3 | using HarmonyLib;
|
| 4 | +using UnityEngine; |
3 | 5 |
|
4 | 6 | namespace Shabby;
|
5 | 7 |
|
@@ -37,6 +39,85 @@ private static bool SetOpacity_Prefix(Part __instance, float opacity)
|
37 | 39 | return false;
|
38 | 40 | }
|
39 | 41 |
|
| 42 | + private static void Highlight_SetRimColor(Part part, Color color) |
| 43 | + { |
| 44 | + highlightProperties[part].SetColor(PropertyIDs._RimColor, color); |
| 45 | + } |
| 46 | + |
| 47 | + [HarmonyTranspiler] |
| 48 | + [HarmonyPatch(nameof(Part.Highlight), typeof(Color))] |
| 49 | + private static IEnumerable<CodeInstruction> Highlight_Transpiler( |
| 50 | + IEnumerable<CodeInstruction> insns) |
| 51 | + { |
| 52 | + var MPB_SetColor = AccessTools.Method( |
| 53 | + typeof(MaterialPropertyBlock), |
| 54 | + nameof(MaterialPropertyBlock.SetColor), |
| 55 | + [typeof(int)]); |
| 56 | + var Part_get_mpb = AccessTools.PropertyGetter(typeof(Part), nameof(Part.mpb)); |
| 57 | + var Part_highlightRenderer = |
| 58 | + AccessTools.Field(typeof(Part), nameof(Part.highlightRenderer)); |
| 59 | + var PropertyIDs__RimColor = |
| 60 | + AccessTools.Field(typeof(PropertyIDs), nameof(PropertyIDs._RimColor)); |
| 61 | + var Renderer_SetPropertyBlock = AccessTools.Method( |
| 62 | + typeof(Renderer), |
| 63 | + nameof(Renderer.SetPropertyBlock), |
| 64 | + [typeof(MaterialPropertyBlock)]); |
| 65 | + |
| 66 | + CodeMatch[] matchDupPop = [new(OpCodes.Dup), new(OpCodes.Pop)]; |
| 67 | + |
| 68 | + // mpb.SetColor(PropertyIDs._RimColor, value); |
| 69 | + // IL_0049: ldarg.0 // this |
| 70 | + // IL_004a: call instance class UnityEngine.MaterialPropertyBlock Part::get_mpb() |
| 71 | + // IL_004f: ldsfld int32 PropertyIDs::_RimColor |
| 72 | + // IL_0054: ldloc.0 // color |
| 73 | + // IL_0055: callvirt instance void UnityEngine.MaterialPropertyBlock::SetColor(int32, valuetype UnityEngine.Color) |
| 74 | + CodeMatch[] matchSetRimColor = [ |
| 75 | + new(OpCodes.Ldarg_0), |
| 76 | + new(OpCodes.Call, Part_get_mpb), |
| 77 | + new(OpCodes.Ldsfld, PropertyIDs__RimColor), |
| 78 | + new(OpCodes.Ldloc_0), |
| 79 | + new(OpCodes.Callvirt, MPB_SetColor) |
| 80 | + ]; |
| 81 | + |
| 82 | + // highlightRenderer[count].SetPropertyBlock(mpb); |
| 83 | + // IL_008a: ldarg.0 // this; jump target |
| 84 | + // IL_008b: ldfld class System.Collections.Generic.List`1<class UnityEngine.Renderer> Part::highlightRenderer |
| 85 | + // IL_0090: ldloc.1 // count |
| 86 | + // IL_0091: callvirt instance !0/*class UnityEngine.Renderer*/ class System.Collections.Generic.List`1<class UnityEngine.Renderer>::get_Item(int32) |
| 87 | + // IL_0096: ldarg.0 // this |
| 88 | + // IL_0097: call instance class UnityEngine.MaterialPropertyBlock Part::get_mpb() |
| 89 | + // IL_009c: callvirt instance void UnityEngine.Renderer::SetPropertyBlock(class UnityEngine.MaterialPropertyBlock) |
| 90 | + CodeMatch[] matchSetMpb = [ |
| 91 | + new(OpCodes.Ldarg_0), |
| 92 | + new(OpCodes.Ldfld, Part_highlightRenderer), |
| 93 | + new(OpCodes.Ldloc_1), |
| 94 | + new(OpCodes.Callvirt), // can't easily specify indexer... |
| 95 | + new(OpCodes.Ldarg_0), |
| 96 | + new(OpCodes.Call, Part_get_mpb), |
| 97 | + new(OpCodes.Callvirt, Renderer_SetPropertyBlock) |
| 98 | + ]; |
| 99 | + |
| 100 | + var matcher = new CodeMatcher(insns); |
| 101 | + matcher |
| 102 | + .MatchStartForward(matchDupPop) |
| 103 | + .Repeat(cm => cm.RemoveInstructions(matchDupPop.Length)) |
| 104 | + .Start() |
| 105 | + .MatchStartForward(matchSetRimColor) |
| 106 | + .ThrowIfNotMatch("failed to find MPB set _RimColor call") |
| 107 | + .RemoveInstructions(matchSetRimColor.Length) |
| 108 | + .InsertAndAdvance( |
| 109 | + // PartPatch.Highlight_SetRimColor(this, value); |
| 110 | + new CodeInstruction(OpCodes.Ldarg_0), // `this` |
| 111 | + new CodeInstruction(OpCodes.Ldloc_0), // `value` |
| 112 | + CodeInstruction.Call(() => Highlight_SetRimColor(default, default))) |
| 113 | + .MatchStartForward(matchSetMpb) |
| 114 | + .ThrowIfNotMatch("failed to find Renderer.SetMPB call") |
| 115 | + // No need to replace application, since that is automatic. |
| 116 | + .SetAndAdvance(OpCodes.Nop, null) // preserve label |
| 117 | + .RemoveInstructions(matchSetMpb.Length - 1); |
| 118 | + return matcher.InstructionEnumeration(); |
| 119 | + } |
| 120 | + |
40 | 121 | [HarmonyPostfix]
|
41 | 122 | [HarmonyPatch("OnDestroy")]
|
42 | 123 | private static void OnDestroy_Postfix(Part __instance)
|
|
0 commit comments