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
This commit is contained in:
Terry Hearst 2024-01-02 01:22:31 -05:00
parent ea688c8bec
commit af4ef66db5
2 changed files with 36 additions and 124 deletions

View file

@ -1,12 +1,9 @@
using HarmonyLib; using HarmonyLib;
using MIU;
using System.Collections.Generic;
namespace CustomCosmeticLoader.Patches namespace CustomCosmeticLoader.Patches
{ {
/* /*
* Hijack the cosmetic of the marble in single player. This doesn't apply the custom texture, just swaps out the * Hijack the cosmetic of the marble in single player, then apply the custom skin texture.
* marble with the designated marble to hijack.
*/ */
[HarmonyPatch(typeof(MarbleController), nameof(MarbleController.ApplyMyCosmetics))] [HarmonyPatch(typeof(MarbleController), nameof(MarbleController.ApplyMyCosmetics))]
internal class MarbleControllerApplyMyCosmeticsPatch internal class MarbleControllerApplyMyCosmeticsPatch
@ -27,55 +24,9 @@ namespace CustomCosmeticLoader.Patches
MarbleHolder mHolder = __instance.MHolder; MarbleHolder mHolder = __instance.MHolder;
string actualSkinId = mHolder.CosmeticSet.skin; string actualSkinId = mHolder.CosmeticSet.skin;
mHolder.SetMarble(Shared.SkinToHijack); mHolder.SetMarble(Shared.SkinToHijack);
Shared.ApplyCustomTexture(mHolder.currentMarble);
// Setting the skin id here allows others in multiplayer/replays to see your normal skin // Setting the skin id here allows others in multiplayer/replays to see your normal skin
mHolder.CosmeticSet.skin = actualSkinId; 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<Replay> 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;
}
}
} }

View file

@ -6,34 +6,34 @@ using UnityEngine;
namespace CustomCosmeticLoader.Patches namespace CustomCosmeticLoader.Patches
{ {
/*
* Private fields/values for MarbleHolder to be used in the patches
*/
internal static class MarbleHolderValues internal static class MarbleHolderValues
{ {
private static FieldInfo _mbcField = typeof(MarbleHolder).GetField("mbc", BindingFlags.NonPublic | BindingFlags.Instance); internal 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 * In multiplayer and Replays, hijack the current marble and set it to be the marble we're hijacking, then apply the skin
* 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))] [HarmonyPatch(typeof(MarbleHolder), nameof(MarbleHolder.CheckSet))]
internal class MarbleHolderSetMarblePatch internal class MarbleHolderCheckSetPatch
{ {
static void Postfix(MarbleHolder __instance, Cosmetic marbleObject) static void Postfix(MarbleHolder __instance, Cosmetic.Set cs)
{ {
if (!Config.enabled) if (!Config.enabled)
return; return;
if (marbleObject.Id != Config.skinNameToHijack && Config.skinNameToHijack != "*") if (!NetworkManager.IsMultiplayer && !MarbleManager.Replaying)
return; 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) if (controller == null)
return; return;
@ -47,78 +47,39 @@ namespace CustomCosmeticLoader.Patches
} }
else else
{ {
if (!Config.otherPlayers.ContainsKey(controller.nickname)) if (Config.otherPlayers.ContainsKey(controller.nickname))
return; skin = Config.skins[Config.otherPlayers[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<Replay> replays)
{ {
string replayName = null; if (replays.Count > 0)
replayName = replays[0].Player;
});
GamePlayManager.Get().GetCurrentReplays(delegate (List<Replay> replays) Shared.Log("MarbleHolderCheckSetPatch Replay name: " + replayName);
{ if (replayName == Player.Current.Name)
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
{ {
skin = Config.skins[Config.currentSkin]; 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);
}
}
}
/* if (skin == null)
* 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; return;
__instance.SetMarble(Shared.SkinToHijack); __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; __instance.CosmeticSet.skin = cs.skin;
} }
} }