From 933ee5f8665d5a7b70c3d3b4406a2e20f02a4a05 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Wed, 16 Aug 2017 14:49:21 +0200 Subject: [PATCH] [Compat] Fix camera entity with BetterSprinting prior to 2.0.0 (fixes #78) --- .../com/replaymod/compat/ReplayModCompat.java | 2 + .../DisableBetterSprinting.java | 97 +++++++++++++++++++ .../replaymod/replay/camera/CameraEntity.java | 8 ++ .../replay/events/ReplayChatMessageEvent.java | 14 +++ 4 files changed, 121 insertions(+) create mode 100644 src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java create mode 100644 src/main/java/com/replaymod/replay/events/ReplayChatMessageEvent.java diff --git a/src/main/java/com/replaymod/compat/ReplayModCompat.java b/src/main/java/com/replaymod/compat/ReplayModCompat.java index 02c65914..9347cd2f 100644 --- a/src/main/java/com/replaymod/compat/ReplayModCompat.java +++ b/src/main/java/com/replaymod/compat/ReplayModCompat.java @@ -1,5 +1,6 @@ package com.replaymod.compat; +import com.replaymod.compat.bettersprinting.DisableBetterSprinting; import com.replaymod.compat.optifine.DisableFastRender; import com.replaymod.compat.oranges17animations.HideInvisibleEntities; import com.replaymod.compat.shaders.ShaderBeginRender; @@ -22,6 +23,7 @@ public class ReplayModCompat { bus.register(new ShaderBeginRender()); bus.register(new DisableFastRender()); bus.register(new HideInvisibleEntities()); + DisableBetterSprinting.register(); } } diff --git a/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java b/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java new file mode 100644 index 00000000..57ab557a --- /dev/null +++ b/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java @@ -0,0 +1,97 @@ +package com.replaymod.compat.bettersprinting; + +import com.replaymod.replay.ReplayModReplay; +import com.replaymod.replay.events.ReplayChatMessageEvent; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.PlayerControllerMP; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.BlockPos; +import net.minecraft.world.IWorldAccess; +import net.minecraftforge.client.event.GuiOpenEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.ModContainer; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.versioning.DefaultArtifactVersion; +import net.minecraftforge.fml.common.versioning.Restriction; +import net.minecraftforge.fml.common.versioning.VersionRange; + +import java.util.Collections; + +/** + * Old Better Sprinting versions replace the vanilla player with their own, overridden instance (replacing the camera entity). + * + * See: https://github.com/chylex/Better-Sprinting/blob/1.8/src/main/java/chylex/bettersprinting/client/player/impl/LogicImplOverride.java + */ +public class DisableBetterSprinting { + private static final VersionRange OLD_VERSION = VersionRange.newRange(null, + Collections.singletonList(new Restriction(null, false, new DefaultArtifactVersion("2.0.0"), false))); + private static final String LOGIC_CLASS_NAME = "chylex.bettersprinting.client.player.impl.LogicImplOverride"; + private static final String CONTROLLER_OVERRIDE_CLASS_NAME = LOGIC_CLASS_NAME + ".PlayerControllerMPOverride"; + + public static void register() { + Loader.instance().getModList().stream() + .filter(mod -> mod.getModId().equalsIgnoreCase("bettersprinting")) + .findFirst() + .map(ModContainer::getProcessedVersion).filter(OLD_VERSION::containsVersion) + .ifPresent($_ -> MinecraftForge.EVENT_BUS.register(new DisableBetterSprinting())); + } + + private DisableBetterSprinting() {} + + private final Minecraft mc = Minecraft.getMinecraft(); + private PlayerControllerMP originalController; + private BetterSprintingWorldAccess worldAccessHook = new BetterSprintingWorldAccess(); + + @SubscribeEvent(priority = EventPriority.HIGH) + public void beforeGuiOpenEvent(GuiOpenEvent event) { + if (ReplayModReplay.instance.getReplayHandler() != null && mc.theWorld != null) { + // During replay, get ready to revert BetterSprinting's overwritten playerController + originalController = mc.playerController; + mc.theWorld.addWorldAccess(worldAccessHook); + } + } + + @SubscribeEvent(priority = EventPriority.LOW) + public void afterGuiOpenEvent(GuiOpenEvent event) { + if (ReplayModReplay.instance.getReplayHandler() != null && mc.theWorld != null) { + mc.theWorld.removeWorldAccess(worldAccessHook); + } + } + + @SubscribeEvent + public void onReplayChatMessage(ReplayChatMessageEvent event) { + // Suppress this message if it's the Better Sprinting warning message + for (StackTraceElement elem : Thread.currentThread().getStackTrace()) { + if (LOGIC_CLASS_NAME.equals(elem.getClassName())) { + event.setCanceled(true); + return; + } + } + } + + private class BetterSprintingWorldAccess implements IWorldAccess { + @Override + public void onEntityRemoved(Entity entityIn) { + if (mc.playerController != null && mc.playerController.getClass().getName().equals(CONTROLLER_OVERRIDE_CLASS_NAME)) { + // Someone has secretly swapped out the player controller and is about to substitute their own player entity. + // This is the right time to destroy their plan. + mc.playerController = originalController; + } + } + + @Override public void markBlockForUpdate(BlockPos pos) {} + @Override public void notifyLightSet(BlockPos pos) {} + @Override public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2) {} + @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) {} + @Override public void playSoundToNearExcept(EntityPlayer except, String soundName, double x, double y, double z, float volume, float pitch) {} + @Override public void spawnParticle(int p_180442_1_, boolean p_180442_2_, double p_180442_3_, double p_180442_5_, double p_180442_7_, double p_180442_9_, double p_180442_11_, double p_180442_13_, int... p_180442_15_) {} + @Override public void onEntityAdded(Entity entityIn) {} + @Override public void playRecord(String recordName, BlockPos blockPosIn) {} + @Override public void broadcastSound(int p_180440_1_, BlockPos p_180440_2_, int p_180440_3_) {} + @Override public void playAusSFX(EntityPlayer p_180439_1_, int p_180439_2_, BlockPos blockPosIn, int p_180439_4_) {} + @Override public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress) {} + } +} diff --git a/src/main/java/com/replaymod/replay/camera/CameraEntity.java b/src/main/java/com/replaymod/replay/camera/CameraEntity.java index 0b5852f9..5db8ecb2 100755 --- a/src/main/java/com/replaymod/replay/camera/CameraEntity.java +++ b/src/main/java/com/replaymod/replay/camera/CameraEntity.java @@ -5,6 +5,7 @@ import com.replaymod.core.events.SettingsChangedEvent; import com.replaymod.core.utils.Utils; import com.replaymod.replay.ReplayModReplay; import com.replaymod.replay.Setting; +import com.replaymod.replay.events.ReplayChatMessageEvent; import com.replaymod.replaystudio.util.Location; import lombok.Getter; import lombok.Setter; @@ -20,6 +21,7 @@ import net.minecraft.entity.item.EntityItemFrame; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.stats.StatFileWriter; import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.IChatComponent; import net.minecraft.util.MovingObjectPosition; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; @@ -348,6 +350,12 @@ public class CameraEntity extends EntityPlayerSP { && (e instanceof EntityPlayer || e instanceof EntityLiving || e instanceof EntityItemFrame); } + @Override + public void addChatMessage(IChatComponent message) { + if (MinecraftForge.EVENT_BUS.post(new ReplayChatMessageEvent(this))) return; + super.addChatMessage(message); + } + private class EventHandler { @SubscribeEvent public void onPreClientTick(TickEvent.ClientTickEvent event) { diff --git a/src/main/java/com/replaymod/replay/events/ReplayChatMessageEvent.java b/src/main/java/com/replaymod/replay/events/ReplayChatMessageEvent.java new file mode 100644 index 00000000..c29c594e --- /dev/null +++ b/src/main/java/com/replaymod/replay/events/ReplayChatMessageEvent.java @@ -0,0 +1,14 @@ +package com.replaymod.replay.events; + +import com.replaymod.replay.camera.CameraEntity; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import net.minecraftforge.fml.common.eventhandler.Cancelable; +import net.minecraftforge.fml.common.eventhandler.Event; + +@Cancelable +@RequiredArgsConstructor +public class ReplayChatMessageEvent extends Event { + @Getter + private final CameraEntity cameraEntity; +}