using HarmonyLib; using Parse.Common.Internal; using System; using System.Reflection; using UnityEngine; namespace CustomCosmeticLoader.Patches { internal static class MarbleHolderValues { private static FieldInfo _mbcField = typeof(MarbleHolder).GetField("mbc", BindingFlags.NonPublic | BindingFlags.Instance); public static FieldInfo MbcField { get { return _mbcField; } } } /* * Applies the custom skin texture to the marble in both singleplayer and multiplayer, if the cosmetic chosen is the * one we're hijacking. In multiplayer, do some extra checks to only apply the custom texture to our marble */ [HarmonyPatch(typeof(MarbleHolder), nameof(MarbleHolder.SetMarble))] internal class MarbleHolderSetMarblePatch { static void Postfix(MarbleHolder __instance, Cosmetic marbleObject) { if (!Config.enabled) return; if (marbleObject.Id != Config.skinNameToHijack && Config.skinNameToHijack != "*") return; if (!Config.inCosmeticMenu && __instance == CosmeticPanel.cosmHolder) return; Texture2D skin = null; if (NetworkManager.IsMultiplayer) { MarbleController controller = MarbleHolderValues.MbcField.GetValue(__instance) as MarbleController; if (controller == null) return; if (!controller.isMyClientMarble()) { if (!Config.otherPlayers.ContainsKey(controller.nickname)) return; skin = Config.skins[Config.otherPlayers[controller.nickname]]; } } Shared.ApplyCustomTexture(__instance.currentMarble, skin); } } /* * In multiplayer, hijack the current marble and set it to be the marble we're hijacking. Later, the actual texture * will be replaced by the patch above */ [HarmonyPatch(typeof(MarbleHolder), nameof(MarbleHolder.CheckSet))] internal class MarbleHolderCheckSetPatch { static void Postfix(MarbleHolder __instance, Cosmetic.Set cs) { if (!Config.enabled) return; if (!NetworkManager.IsMultiplayer) return; MarbleController controller = MarbleHolderValues.MbcField.GetValue(__instance) as MarbleController; if (controller == null) return; if (!controller.isMyClientMarble()) { if (!Config.otherPlayers.ContainsKey(controller.nickname)) return; } // Don't hijack the soccer ball or zombie skins if (cs.skin == "SoccerBall_V4" || cs.skin == "Zombie") return; __instance.SetMarble(Shared.SkinToHijack); __instance.CosmeticSet.skin = cs.skin; } } }