From 7fa6debd28ea34899e18254909a4499b03d4d8be Mon Sep 17 00:00:00 2001 From: "zolantris@vllc.dev" <151822540+zolantris@users.noreply.github.com> Date: Tue, 21 May 2024 17:53:40 -0700 Subject: [PATCH] searica's MoreVanillaPrefabs and other piece placement mod compatibility - Integrate the new fixes within other patches and remove player parameter - Copy paste similar code from searica's MoreVanillaPrefabs that utilizes the CodeMatcher approach for PlacePiece (#83) --- .../ValheimRAFT.Patches/PlanBuild_Patch.cs | 2 +- .../ValheimRAFT.Patches/Player_Patch.cs | 84 ++++++++++++++----- .../ValheimRAFT.Patches/ValheimRAFT_Patch.cs | 2 +- 3 files changed, 67 insertions(+), 21 deletions(-) diff --git a/src/ValheimRAFT/ValheimRAFT.Patches/PlanBuild_Patch.cs b/src/ValheimRAFT/ValheimRAFT.Patches/PlanBuild_Patch.cs index f17b4c56..2e895734 100644 --- a/src/ValheimRAFT/ValheimRAFT.Patches/PlanBuild_Patch.cs +++ b/src/ValheimRAFT/ValheimRAFT.Patches/PlanBuild_Patch.cs @@ -59,7 +59,7 @@ private static bool PlanPiece_CalculateSupported_Prefix(PlanPiece __instance, re [HarmonyPrefix] private static void BlueprintManager_OnPiecePlaced_Postfix(GameObject placedPiece) { - Player_Patch.PlacedPiece(Player.m_localPlayer, placedPiece); + Player_Patch.PlacedPiece(placedPiece); // ValheimRAFT_Patch.PlacedPiece(Player.m_localPlayer, placedPiece); } diff --git a/src/ValheimRAFT/ValheimRAFT.Patches/Player_Patch.cs b/src/ValheimRAFT/ValheimRAFT.Patches/Player_Patch.cs index 05400ef0..462967f0 100644 --- a/src/ValheimRAFT/ValheimRAFT.Patches/Player_Patch.cs +++ b/src/ValheimRAFT/ValheimRAFT.Patches/Player_Patch.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Reflection.Emit; using HarmonyLib; using UnityEngine; @@ -15,25 +16,68 @@ namespace ValheimRAFT.Patches; public class Player_Patch { - [HarmonyPatch(typeof(Player), "PlacePiece")] - [HarmonyTranspiler] - public static IEnumerable PlacePiece(IEnumerable instructions) + private static bool HasMatchingParameterTypes(int genericParameterCount, Type[] types, + ParameterInfo[] parameters) { - var list = instructions.ToList(); - for (var i = 0; i < list.Count; i++) - if (list[i].operand != null && list[i].operand.ToString() == - "UnityEngine.GameObject Instantiate[GameObject](UnityEngine.GameObject, UnityEngine.Vector3, UnityEngine.Quaternion)") + if (parameters.Length < genericParameterCount || parameters.Length != types.Length) + { + return false; + } + + var num = 0; + for (var i = 0; i < parameters.Length; i++) + { + if (parameters[i].ParameterType.IsGenericParameter) { - list.InsertRange(i + 2, new CodeInstruction[3] - { - new(OpCodes.Ldarg_0), - new(OpCodes.Ldloc_3), - new(OpCodes.Call, AccessTools.Method(typeof(Player_Patch), nameof(PlacedPiece))) - }); - break; + num++; } + else if (types[i] != parameters[i].ParameterType) + { + return false; + } + } - return list; + return num == genericParameterCount; + } + + private static MethodInfo GetGenericMethod(Type type, string name, int genericParameterCount, + Type[] types) + { + var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | + BindingFlags.Public | BindingFlags.NonPublic | + BindingFlags.GetField | BindingFlags.SetField | + BindingFlags.GetProperty | BindingFlags.SetProperty); + foreach (var methodInfo in methods) + { + if (methodInfo.IsGenericMethod && methodInfo.ContainsGenericParameters && + methodInfo.Name == name && + HasMatchingParameterTypes(genericParameterCount, types, methodInfo.GetParameters())) + { + return methodInfo; + } + } + + return null; + } + + [HarmonyTranspiler] + [HarmonyPatch(typeof(Player), "PlacePiece")] + private static IEnumerable PlacePieceTranspiler( + IEnumerable instructions) + { + var operand = GetGenericMethod(typeof(UnityEngine.Object), "Instantiate", 1, new Type[3] + { + typeof(Type), + typeof(Vector3), + typeof(Quaternion) + }).MakeGenericMethod(typeof(GameObject)); + var matches = new CodeMatch[] + { + new(OpCodes.Call, operand) + }; + return new CodeMatcher(instructions).MatchForward(useEnd: true, matches).Advance(1) + .InsertAndAdvance(Transpilers.EmitDelegate>(PlacedPiece)) + .InstructionEnumeration(); } public static void HidePreviewComponent(ZNetView netView) @@ -46,10 +90,10 @@ public static void HidePreviewComponent(ZNetView netView) } } - public static void PlacedPiece(Player player, GameObject gameObject) + public static GameObject PlacedPiece(GameObject gameObject) { var piece = gameObject.GetComponent(); - if (!piece) return; + if (!piece) return gameObject; var rb = piece.GetComponentInChildren(); var netView = piece.GetComponent(); @@ -60,7 +104,7 @@ public static void PlacedPiece(Player player, GameObject gameObject) if (((bool)rb && !rb.isKinematic) || !PatchSharedData.PlayerLastRayPiece) { - return; + return gameObject; } if ((bool)netView) @@ -83,7 +127,7 @@ public static void PlacedPiece(Player player, GameObject gameObject) bvc.AddTemporaryPiece(piece); } - return; + return gameObject; } var mb = PatchSharedData.PlayerLastRayPiece.GetComponentInParent(); @@ -100,6 +144,8 @@ public static void PlacedPiece(Player player, GameObject gameObject) mb.AddTemporaryPiece(piece); } } + + return gameObject; } public static bool HandleGameObjectRayCast(Transform transform, LayerMask layerMask, diff --git a/src/ValheimRAFT/ValheimRAFT.Patches/ValheimRAFT_Patch.cs b/src/ValheimRAFT/ValheimRAFT.Patches/ValheimRAFT_Patch.cs index ebae7d39..655ece16 100644 --- a/src/ValheimRAFT/ValheimRAFT.Patches/ValheimRAFT_Patch.cs +++ b/src/ValheimRAFT/ValheimRAFT.Patches/ValheimRAFT_Patch.cs @@ -16,6 +16,6 @@ public class ValheimRAFT_Patch /// public static void PlacedPiece(Player player, GameObject gameObject) { - Player_Patch.PlacedPiece(player, gameObject); + Player_Patch.PlacedPiece(gameObject); } } \ No newline at end of file