Skip to content

Commit

Permalink
searica's MoreVanillaPrefabs and other piece placement mod compatibility
Browse files Browse the repository at this point in the history
- 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)
  • Loading branch information
zolantris committed May 22, 2024
1 parent 0f540c2 commit 7fa6deb
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 21 deletions.
2 changes: 1 addition & 1 deletion src/ValheimRAFT/ValheimRAFT.Patches/PlanBuild_Patch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
84 changes: 65 additions & 19 deletions src/ValheimRAFT/ValheimRAFT.Patches/Player_Patch.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using HarmonyLib;
using UnityEngine;
Expand All @@ -15,25 +16,68 @@ namespace ValheimRAFT.Patches;

public class Player_Patch
{
[HarmonyPatch(typeof(Player), "PlacePiece")]
[HarmonyTranspiler]
public static IEnumerable<CodeInstruction> PlacePiece(IEnumerable<CodeInstruction> 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<CodeInstruction> PlacePieceTranspiler(
IEnumerable<CodeInstruction> 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<Func<GameObject, GameObject>>(PlacedPiece))
.InstructionEnumeration();
}

public static void HidePreviewComponent(ZNetView netView)
Expand All @@ -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<Piece>();
if (!piece) return;
if (!piece) return gameObject;
var rb = piece.GetComponentInChildren<Rigidbody>();
var netView = piece.GetComponent<ZNetView>();

Expand All @@ -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)
Expand All @@ -83,7 +127,7 @@ public static void PlacedPiece(Player player, GameObject gameObject)
bvc.AddTemporaryPiece(piece);
}

return;
return gameObject;
}

var mb = PatchSharedData.PlayerLastRayPiece.GetComponentInParent<MoveableBaseRootComponent>();
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/ValheimRAFT/ValheimRAFT.Patches/ValheimRAFT_Patch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ public class ValheimRAFT_Patch
/// <param name="gameObject"></param>
public static void PlacedPiece(Player player, GameObject gameObject)
{
Player_Patch.PlacedPiece(player, gameObject);
Player_Patch.PlacedPiece(gameObject);
}
}

0 comments on commit 7fa6deb

Please sign in to comment.