From af4ef66db5e0db8f39336de6de7ff93344b457ec Mon Sep 17 00:00:00 2001 From: Terry Hearst Date: Tue, 2 Jan 2024 01:22:31 -0500 Subject: [PATCH] Combine multiplayer and replay skin hijacking Really nice simplification here, I could remove two patches at once and clear out some headaches. Now, the logic for switching skins in multiplayer and in replays is in the same place, which is great and will make it more expandable in the future --- Patches/MarbleControllerPatches.cs | 53 +------------- Patches/MarbleHolderPatches.cs | 107 +++++++++-------------------- 2 files changed, 36 insertions(+), 124 deletions(-) diff --git a/Patches/MarbleControllerPatches.cs b/Patches/MarbleControllerPatches.cs index b2e595d..173581d 100644 --- a/Patches/MarbleControllerPatches.cs +++ b/Patches/MarbleControllerPatches.cs @@ -1,12 +1,9 @@ using HarmonyLib; -using MIU; -using System.Collections.Generic; namespace CustomCosmeticLoader.Patches { /* - * Hijack the cosmetic of the marble in single player. This doesn't apply the custom texture, just swaps out the - * marble with the designated marble to hijack. + * Hijack the cosmetic of the marble in single player, then apply the custom skin texture. */ [HarmonyPatch(typeof(MarbleController), nameof(MarbleController.ApplyMyCosmetics))] internal class MarbleControllerApplyMyCosmeticsPatch @@ -27,55 +24,9 @@ namespace CustomCosmeticLoader.Patches MarbleHolder mHolder = __instance.MHolder; string actualSkinId = mHolder.CosmeticSet.skin; mHolder.SetMarble(Shared.SkinToHijack); + Shared.ApplyCustomTexture(mHolder.currentMarble); // Setting the skin id here allows others in multiplayer/replays to see your normal skin mHolder.CosmeticSet.skin = actualSkinId; } } - - /* - * Hijack the cosmetic of the marble when watching Replays. This doesn't apply the custom texture, just swaps out - * the marble with the designated marble to hijack. If overrideReplayCosmetics is enabled, we swap out all cosmetics - * to match our current configuration to view the replay that way. - */ - [HarmonyPatch(typeof(MarbleController), nameof(MarbleController.ApplyCosmetics))] - internal class MarbleControllerApplyCosmeticsPatch - { - static void Prefix(MarbleController __instance, ref ReplayCosmetics cosmetics) - { - // Actually, we can let this one run even if the custom skins are disabled - //if (!Config.enabled) - // return; - - if (Config.overrideReplayCosmetics) - { - cosmetics.Skin = CosmeticManager.MySkin.Id; - cosmetics.Trail = CosmeticManager.MyTrail.Id; - cosmetics.Respawn = CosmeticManager.MyRespawn.Id; - cosmetics.Hat = CosmeticManager.MyHat.Id; - cosmetics.Blast = CosmeticManager.MyBlast.Id; - } - - if (!Config.enabled || Config.skinNameToHijack == "*") - return; - - if (Config.inAllReplays) - { - cosmetics.Skin = Config.skinNameToHijack; - return; - } - - string replayName = null; - - GamePlayManager.Get().GetCurrentReplays(delegate (List replays) - { - if (replays.Count > 0) - replayName = replays[0].Player; - }); - - Shared.Log("MarbleControllerApplyCosmeticsPatch Replay name: " + replayName); - - if (Config.otherPlayers.ContainsKey(replayName) || replayName == Player.Current.Name) - cosmetics.Skin = Config.skinNameToHijack; - } - } } diff --git a/Patches/MarbleHolderPatches.cs b/Patches/MarbleHolderPatches.cs index 36edae5..4635f91 100644 --- a/Patches/MarbleHolderPatches.cs +++ b/Patches/MarbleHolderPatches.cs @@ -6,34 +6,34 @@ using UnityEngine; namespace CustomCosmeticLoader.Patches { + /* + * Private fields/values for MarbleHolder to be used in the patches + */ internal static class MarbleHolderValues { - private static FieldInfo _mbcField = typeof(MarbleHolder).GetField("mbc", BindingFlags.NonPublic | BindingFlags.Instance); - public static FieldInfo MbcField - { - get - { - return _mbcField; - } - } + internal static FieldInfo mbcField = typeof(MarbleHolder).GetField("mbc", BindingFlags.NonPublic | BindingFlags.Instance); } /* - * 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 + * In multiplayer and Replays, hijack the current marble and set it to be the marble we're hijacking, then apply the skin */ - [HarmonyPatch(typeof(MarbleHolder), nameof(MarbleHolder.SetMarble))] - internal class MarbleHolderSetMarblePatch + [HarmonyPatch(typeof(MarbleHolder), nameof(MarbleHolder.CheckSet))] + internal class MarbleHolderCheckSetPatch { - static void Postfix(MarbleHolder __instance, Cosmetic marbleObject) + static void Postfix(MarbleHolder __instance, Cosmetic.Set cs) { if (!Config.enabled) return; - if (marbleObject.Id != Config.skinNameToHijack && Config.skinNameToHijack != "*") + if (!NetworkManager.IsMultiplayer && !MarbleManager.Replaying) return; - MarbleController controller = MarbleHolderValues.MbcField.GetValue(__instance) as MarbleController; + // Don't hijack the soccer ball or zombie skins + if (cs.skin == "SoccerBall_V4" || cs.skin == "Zombie") + return; + + MarbleController controller = MarbleHolderValues.mbcField.GetValue(__instance) as MarbleController; + if (controller == null) return; @@ -47,78 +47,39 @@ namespace CustomCosmeticLoader.Patches } else { - if (!Config.otherPlayers.ContainsKey(controller.nickname)) - return; - skin = Config.skins[Config.otherPlayers[controller.nickname]]; + if (Config.otherPlayers.ContainsKey(controller.nickname)) + skin = Config.skins[Config.otherPlayers[controller.nickname]]; } } - else + else if (MarbleManager.Replaying) // Should always be true { - if (MarbleManager.Replaying && !Config.inAllReplays) + string replayName = null; + + GamePlayManager.Get().GetCurrentReplays(delegate (List replays) { - string replayName = null; + if (replays.Count > 0) + replayName = replays[0].Player; + }); - GamePlayManager.Get().GetCurrentReplays(delegate (List replays) - { - if (replays.Count > 0) - replayName = replays[0].Player; - }); - - Shared.Log("MarbleHolderSetMarblePatch Replay name: " + replayName); - if (replayName == Player.Current.Name) - { - skin = Config.skins[Config.currentSkin]; - } - else - { - if (Config.otherPlayers.ContainsKey(replayName)) - skin = Config.skins[Config.otherPlayers[replayName]]; - } - } - else + Shared.Log("MarbleHolderCheckSetPatch Replay name: " + replayName); + if (replayName == Player.Current.Name) { skin = Config.skins[Config.currentSkin]; } + else + { + if (Config.otherPlayers.ContainsKey(replayName)) + skin = Config.skins[Config.otherPlayers[replayName]]; + } } - if (skin != null) - { - 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") + if (skin == null) return; __instance.SetMarble(Shared.SkinToHijack); + Shared.ApplyCustomTexture(__instance.currentMarble, skin); + // Reset this to what it should be incase it's used later __instance.CosmeticSet.skin = cs.skin; } }