From cc4d8f67c22fae676633927536af5511aa569e15 Mon Sep 17 00:00:00 2001 From: johni0702 Date: Mon, 1 Jun 2015 22:58:09 +0200 Subject: [PATCH] Play sounds during replay relative to camera --- .../replaymod/coremod/LoadingPlugin.java | 1 + .../replaymod/coremod/SoundManagerCT.java | 71 +++++++++++++++++++ .../replaymod/entities/CameraEntity.java | 22 ++++++ .../replaymod/replay/ReplayHandler.java | 5 ++ .../replaymod/replay/ReplaySender.java | 7 +- 5 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 src/main/java/eu/crushedpixel/replaymod/coremod/SoundManagerCT.java diff --git a/src/main/java/eu/crushedpixel/replaymod/coremod/LoadingPlugin.java b/src/main/java/eu/crushedpixel/replaymod/coremod/LoadingPlugin.java index 8ca266da..492e883e 100755 --- a/src/main/java/eu/crushedpixel/replaymod/coremod/LoadingPlugin.java +++ b/src/main/java/eu/crushedpixel/replaymod/coremod/LoadingPlugin.java @@ -11,6 +11,7 @@ public class LoadingPlugin implements IFMLLoadingPlugin { return new String[]{ CameraRollCT.class.getName(), ForceChunkLoadingCT.class.getName(), + SoundManagerCT.class.getName(), EnchantmentTimerCT.class.getName() }; } diff --git a/src/main/java/eu/crushedpixel/replaymod/coremod/SoundManagerCT.java b/src/main/java/eu/crushedpixel/replaymod/coremod/SoundManagerCT.java new file mode 100644 index 00000000..5b155987 --- /dev/null +++ b/src/main/java/eu/crushedpixel/replaymod/coremod/SoundManagerCT.java @@ -0,0 +1,71 @@ +package eu.crushedpixel.replaymod.coremod; + +import net.minecraft.launchwrapper.IClassTransformer; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.tree.*; + +import java.util.ListIterator; + +import static org.objectweb.asm.Opcodes.*; +import static org.objectweb.asm.Opcodes.INVOKESTATIC; + +public class SoundManagerCT implements IClassTransformer { + + private static final String REPLAY_HANDLER = "eu/crushedpixel/replaymod/replay/ReplayHandler"; + private static final String CAMERA_ENTITY = "eu/crushedpixel/replaymod/entities/CameraEntity"; + private static final String CLASS_NAME = "net.minecraft.client.audio.SoundManager"; + + @Override + public byte[] transform(String name, String transformedName, byte[] bytes) { + if (CLASS_NAME.equals(transformedName)) { + if (name.equals(transformedName)) { + return transform(bytes, "setListener", "(Lnet/minecraft/entity/player/EntityPlayer;F)V"); + } else { + return transform(bytes, "a", "(Lahd;F)V"); + } + } + return bytes; + } + + private byte[] transform(byte[] bytes, String name_setListener, String desc_setListener) { + ClassReader classReader = new ClassReader(bytes); + ClassNode classNode = new ClassNode(); + classReader.accept(classNode, 0); + + boolean success = false; + for (MethodNode m : classNode.methods) { + if (desc_setListener.equals(m.desc) && name_setListener.equals(m.name)) { + ListIterator iter = m.instructions.iterator(); + inject(iter); + success = true; + break; + } + } + if (!success) { + throw new NoSuchMethodError(); + } + + ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); + classNode.accept(classWriter); + return classWriter.toByteArray(); + } + + /** + * public void setListener(EntityPlayer player, float partialTicks) { + * ... + * if (ReplayHandler.isInReplay()) { + * player = ReplayHandler.getCameraEntity(); + * } + * ... + * } + */ + private void inject(ListIterator iter) { + LabelNode l = new LabelNode(); + iter.add(new MethodInsnNode(INVOKESTATIC, REPLAY_HANDLER, "isInReplay", "()Z", false)); + iter.add(new JumpInsnNode(IFEQ, l)); + iter.add(new MethodInsnNode(INVOKESTATIC, REPLAY_HANDLER, "getCameraEntity", "()L" + CAMERA_ENTITY + ";", false)); + iter.add(new VarInsnNode(ASTORE, 1)); + iter.add(l); + } +} diff --git a/src/main/java/eu/crushedpixel/replaymod/entities/CameraEntity.java b/src/main/java/eu/crushedpixel/replaymod/entities/CameraEntity.java index c778ccc5..ddc15d92 100755 --- a/src/main/java/eu/crushedpixel/replaymod/entities/CameraEntity.java +++ b/src/main/java/eu/crushedpixel/replaymod/entities/CameraEntity.java @@ -4,12 +4,15 @@ import eu.crushedpixel.replaymod.holders.Position; import eu.crushedpixel.replaymod.replay.LesserDataWatcher; import eu.crushedpixel.replaymod.replay.ReplayHandler; import net.minecraft.client.Minecraft; +import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.MathHelper; import net.minecraft.util.MovingObjectPosition; import net.minecraft.util.Vec3; import net.minecraft.world.World; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; import org.lwjgl.Sys; import java.lang.reflect.Field; @@ -31,6 +34,25 @@ public class CameraEntity extends EntityPlayer { super(worldIn, Minecraft.getMinecraft().getSession().getProfile()); } + @SubscribeEvent + public void tick(TickEvent.ClientTickEvent event) { + if (event.phase == TickEvent.Phase.END) { + Entity view = Minecraft.getMinecraft().getRenderViewEntity(); + if (view != this) { + prevPosX = view.prevPosX; + prevPosY = view.prevPosY; + prevPosZ = view.prevPosZ; + prevRotationYaw = view.prevRotationYaw; + prevRotationPitch = view.prevRotationPitch; + posX = view.posX; + posY = view.posY; + posZ = view.posZ; + rotationYaw = view.rotationYaw; + rotationPitch = view.rotationPitch; + } + } + } + //frac = time since last tick public void updateMovement() { Minecraft mc = Minecraft.getMinecraft(); diff --git a/src/main/java/eu/crushedpixel/replaymod/replay/ReplayHandler.java b/src/main/java/eu/crushedpixel/replaymod/replay/ReplayHandler.java index f8a45801..bc7b6c61 100755 --- a/src/main/java/eu/crushedpixel/replaymod/replay/ReplayHandler.java +++ b/src/main/java/eu/crushedpixel/replaymod/replay/ReplayHandler.java @@ -15,6 +15,7 @@ import net.minecraft.entity.Entity; import net.minecraft.network.EnumPacketDirection; import net.minecraft.network.NetworkManager; import net.minecraft.network.play.INetHandlerPlayClient; +import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher; import java.io.File; @@ -119,7 +120,11 @@ public class ReplayHandler { public static void setCameraEntity(CameraEntity entity) { if(entity == null) return; + if (cameraEntity != null) { + FMLCommonHandler.instance().bus().unregister(cameraEntity); + } cameraEntity = entity; + FMLCommonHandler.instance().bus().register(cameraEntity); spectateCamera(); } diff --git a/src/main/java/eu/crushedpixel/replaymod/replay/ReplaySender.java b/src/main/java/eu/crushedpixel/replaymod/replay/ReplaySender.java index c407eb6f..6f2dd7c9 100755 --- a/src/main/java/eu/crushedpixel/replaymod/replay/ReplaySender.java +++ b/src/main/java/eu/crushedpixel/replaymod/replay/ReplaySender.java @@ -44,7 +44,6 @@ public class ReplaySender extends ChannelInboundHandlerAdapter { * These packets are ignored completely during replay. */ private static final List BAD_PACKETS = Arrays.asList( - S28PacketEffect.class, S2BPacketChangeGameState.class, S06PacketUpdateHealth.class, S2DPacketOpenWindow.class, @@ -255,8 +254,10 @@ public class ReplaySender extends ChannelInboundHandlerAdapter { protected Packet processPacket(Packet p) throws Exception { if(BAD_PACKETS.contains(p.getClass())) return null; - if(p instanceof S29PacketSoundEffect && ReplayProcess.isVideoRecording()) { - return null; + if (p instanceof S29PacketSoundEffect || p instanceof S28PacketEffect) { + if (!asyncMode || isHurrying()) { + return null; + } } if(p instanceof S03PacketTimeUpdate) {