diff --git a/src/main/java/eu/crushedpixel/replaymod/ReplayMod.java b/src/main/java/eu/crushedpixel/replaymod/ReplayMod.java index 9cd049ec..da6122a3 100644 --- a/src/main/java/eu/crushedpixel/replaymod/ReplayMod.java +++ b/src/main/java/eu/crushedpixel/replaymod/ReplayMod.java @@ -1,5 +1,6 @@ package eu.crushedpixel.replaymod; +import net.minecraft.client.Minecraft; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.config.Configuration; import net.minecraftforge.common.config.Property; @@ -11,6 +12,7 @@ import net.minecraftforge.fml.common.SidedProxy; import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import eu.crushedpixel.replaymod.authentication.AuthenticationHandler; import eu.crushedpixel.replaymod.events.GuiEventHandler; import eu.crushedpixel.replaymod.events.GuiReplayOverlay; import eu.crushedpixel.replaymod.events.RecordingHandler; @@ -33,19 +35,18 @@ public class ReplayMod // // - public static final String MODID = "replaymod"; public static final String VERSION = "0.0.1"; public static GuiReplayOverlay overlay = new GuiReplayOverlay(); - public static ReplaySettings replaySettings = new ReplaySettings(0, true, true, true, false); + public static ReplaySettings replaySettings = new ReplaySettings(0, true, true, true, false, false); public static Configuration config; public static RecordingHandler recordingHandler; - - public static int PLAYER_ID = -1; + public static int TP_DISTANCE_LIMIT = 128; + // The instance of your mod that Forge uses. @Instance(value = "ReplayModID") public static ReplayMod instance; @@ -60,8 +61,10 @@ public class ReplayMod Property maxFileSize = config.get("settings", "maximumFileSize", 0, "The maximum File size (in MB) of a recording. 0 means unlimited."); Property showNot = ReplayMod.instance.config.get("settings", "showNotifications", true, "Defines whether notifications should be sent to the player."); Property linear = ReplayMod.instance.config.get("settings", "forceLinearPath", false, "Defines whether travelling paths should be linear instead of interpolated."); + Property lighting = ReplayMod.instance.config.get("settings", "enableLighting", false, "If enabled, the whole map is lighted."); - replaySettings = new ReplaySettings(maxFileSize.getInt(0), recServer.getBoolean(true), recSP.getBoolean(true), showNot.getBoolean(true), linear.getBoolean(false)); + replaySettings = new ReplaySettings(maxFileSize.getInt(0), recServer.getBoolean(true), recSP.getBoolean(true), showNot.getBoolean(true), + linear.getBoolean(false), lighting.getBoolean(false)); config.save(); } @@ -84,5 +87,7 @@ public class ReplayMod overlay = new GuiReplayOverlay(); FMLCommonHandler.instance().bus().register(overlay); MinecraftForge.EVENT_BUS.register(overlay); + + AuthenticationHandler.authenticate(); } } diff --git a/src/main/java/eu/crushedpixel/replaymod/authentication/AuthenticationHandler.java b/src/main/java/eu/crushedpixel/replaymod/authentication/AuthenticationHandler.java new file mode 100644 index 00000000..7ab7b216 --- /dev/null +++ b/src/main/java/eu/crushedpixel/replaymod/authentication/AuthenticationHandler.java @@ -0,0 +1,44 @@ +package eu.crushedpixel.replaymod.authentication; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.client.Minecraft; +import eu.crushedpixel.replaymod.reflection.MCPNames; + +public class AuthenticationHandler { + + private static Minecraft mc = Minecraft.getMinecraft(); + + private static boolean auth = false; + + public static boolean isAuthenticated() { + return auth; + } + + public static void authenticate() { + auth = isPremiumUsername(Minecraft.getMinecraft().getSession().getUsername()); + } + + private static final List PREMIUM_USERS = new ArrayList() { + { + add("Ender_Workbench"); + add("oleoleMC"); + add("Johni0702"); + add("Rafessor"); + add("bluffamachuck"); + add("Panguino"); + add("SixteenBy16"); + } + }; + + private static boolean isPremiumUsername(String username) { + //TODO: API check with the website + return (PREMIUM_USERS.contains(username) || MCPNames.env.isMCPEnvironment()); + } + + private static boolean isPremiumUUID(String uuid) { + //TODO: API check with the website + return false; + } +} diff --git a/src/main/java/eu/crushedpixel/replaymod/entities/CameraEntity.java b/src/main/java/eu/crushedpixel/replaymod/entities/CameraEntity.java index d1b9511b..e52d1fcd 100644 --- a/src/main/java/eu/crushedpixel/replaymod/entities/CameraEntity.java +++ b/src/main/java/eu/crushedpixel/replaymod/entities/CameraEntity.java @@ -3,13 +3,12 @@ package eu.crushedpixel.replaymod.entities; import java.lang.reflect.Field; import net.minecraft.client.Minecraft; -import net.minecraft.entity.Entity; -import net.minecraft.nbt.NBTTagCompound; +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.minecraft.world.WorldSettings.GameType; import org.lwjgl.Sys; @@ -17,19 +16,19 @@ import eu.crushedpixel.replaymod.holders.Position; import eu.crushedpixel.replaymod.replay.LesserDataWatcher; import eu.crushedpixel.replaymod.replay.ReplayHandler; -public class CameraEntity extends Entity { +public class CameraEntity extends EntityPlayer { private Vec3 direction; private double motion; - + private Field drawBlockOutline; - + private static final double SPEED = 10; //2 blocks per second - - private double decay = 4; //decays by 75% per second; - + + private double decay = 6; //decays by 75% per second; + private long lastCall = 0; - + //frac = time since last tick public void updateMovement() { Minecraft mc = Minecraft.getMinecraft(); @@ -37,44 +36,44 @@ public class CameraEntity extends Entity { //Aligns the particle rotation mc.thePlayer.rotationPitch = ReplayHandler.getCameraEntity().rotationPitch; mc.thePlayer.rotationYaw = ReplayHandler.getCameraEntity().rotationYaw; - + //removes water/suffocation/shadow overlays in screen mc.thePlayer.posX = 0; mc.thePlayer.posY = 500; mc.thePlayer.posZ = 0; - + //mc.thePlayer.posX = ReplayHandler.getCameraEntity().posX; //mc.thePlayer.posY = ReplayHandler.getCameraEntity().posY; //mc.thePlayer.posZ = ReplayHandler.getCameraEntity().posZ; } - + if(direction == null || motion < 0.1) { lastCall = Sys.getTime(); return; } - + long frac = Sys.getTime() - lastCall; - + if(frac == 0) return; Vec3 movement = direction.normalize(); double factor = motion*(frac/1000D); - + moveRelative(movement.xCoord*factor, movement.yCoord*factor, movement.zCoord*factor); - + double decFac = Math.max(0, 1-(decay*(frac/1000D))); motion *= decFac; - + lastCall = Sys.getTime(); } - + public void setDirection(float pitch, float yaw) { this.setRotation(yaw, pitch); } - + public void setMovement(MoveDirection dir) { Vec3 oldDir = direction; - + switch(dir) { case BACKWARD: direction = this.getVectorForRotation(-rotationPitch, rotationYaw-180); @@ -95,84 +94,65 @@ public class CameraEntity extends Entity { direction = this.getVectorForRotation(-90, 0); break; } - + if(oldDir != null) direction = direction.normalize().add(new Vec3(oldDir.xCoord*(motion/4f), oldDir.yCoord*(motion/4f), oldDir.zCoord*(motion/4f)).normalize()); - + this.motion = SPEED; } - + public void moveAbsolute(double x, double y, double z) { if(ReplayHandler.isReplaying()) return; - this.posX = x; - this.posY = y; - this.posZ = z; - this.prevPosX = this.posX; - this.prevPosY = this.posY; - this.prevPosZ = this.posZ; - this.lastTickPosX = this.posX; - this.lastTickPosY = this.posY; - this.lastTickPosZ = this.posZ; + this.lastTickPosX = this.prevPosX = this.posX = x; + this.lastTickPosY = this.prevPosY = this.posY = y; + this.lastTickPosZ = this.prevPosZ = this.posZ = z; } - + public void moveRelative(double x, double y, double z) { if(ReplayHandler.isReplaying()) return; - this.posX += x; - this.posY += y; - this.posZ += z; - this.prevPosX = this.posX; - this.prevPosY = this.posY; - this.prevPosZ = this.posZ; - this.lastTickPosX = this.posX; - this.lastTickPosY = this.posY; - this.lastTickPosZ = this.posZ; + this.lastTickPosX = this.prevPosX = this.posX = this.posX+x; + this.lastTickPosY = this.prevPosY = this.posY = this.posY+y; + this.lastTickPosZ = this.prevPosZ = this.posZ = this.posZ+z; } - + public void movePath(Position pos) { - this.posX = pos.getX(); - this.posY = pos.getY(); - this.posZ = pos.getZ(); - this.rotationPitch = pos.getPitch(); - this.rotationYaw = pos.getYaw(); - this.prevPosX = this.posX; - this.prevPosY = this.posY; - this.prevPosZ = this.posZ; - this.prevRotationPitch = this.rotationPitch; - this.prevRotationYaw = this.rotationYaw; - this.lastTickPosX = this.posX; - this.lastTickPosY = this.posY; - this.lastTickPosZ = this.posZ; + this.prevRotationPitch = this.rotationPitch = pos.getPitch(); + this.prevRotationYaw = this.rotationYaw = pos.getYaw(); + this.lastTickPosX = this.prevPosX = this.posX = pos.getX(); + this.lastTickPosY = this.prevPosY = this.posY = pos.getY(); + this.lastTickPosZ = this.prevPosZ = this.posZ = pos.getZ(); } - + @Override protected void entityInit() { this.dataWatcher = new LesserDataWatcher(this); } - - + + public CameraEntity(World worldIn) { - super(worldIn); + //super(worldIn); + super(worldIn, Minecraft.getMinecraft().getSession().getProfile()); } @Override - public void setAngles(float yaw, float pitch) - { - this.rotationYaw = (float)((double)this.rotationYaw + (double)yaw * 0.15D); - this.rotationPitch = (float)((double)this.rotationPitch - (double)pitch * 0.15D); - this.rotationPitch = MathHelper.clamp_float(this.rotationPitch, -90.0F, 90.0F); - this.prevRotationPitch = this.rotationPitch; - this.prevRotationYaw = this.rotationYaw; - } + public void setAngles(float yaw, float pitch) + { + this.rotationYaw = (float)((double)this.rotationYaw + (double)yaw * 0.15D); + this.rotationPitch = (float)((double)this.rotationPitch - (double)pitch * 0.15D); + this.rotationPitch = MathHelper.clamp_float(this.rotationPitch, -90.0F, 90.0F); + this.prevRotationPitch = this.rotationPitch; + this.prevRotationYaw = this.rotationYaw; + } + - @Override - public MovingObjectPosition rayTrace(double p_174822_1_, float p_174822_3_) { - return null; - } - + public MovingObjectPosition rayTrace(double p_174822_1_, float p_174822_3_) { + return null; + } + @Override public boolean canBePushed() { - return false; - } + return false; + } @Override protected void createRunningParticles() {} @@ -186,27 +166,21 @@ public class CameraEntity extends Entity { return false; } - /* + public enum MoveDirection { + UP, DOWN, LEFT, RIGHT, FORWARD, BACKWARD; + } + + @Override + public void setCurrentItemOrArmor(int slotIn, ItemStack stack) {} + + @Override + public ItemStack[] getInventory() { + return null; + } + @Override public boolean isSpectator() { return true; } - */ - - @Override - protected void readEntityFromNBT(NBTTagCompound tagCompund) { - // TODO Auto-generated method stub - } - - @Override - protected void writeEntityToNBT(NBTTagCompound tagCompound) { - // TODO Auto-generated method stub - - } - - public enum MoveDirection { - UP, DOWN, LEFT, RIGHT, FORWARD, BACKWARD; - } - } diff --git a/src/main/java/eu/crushedpixel/replaymod/events/GuiEventHandler.java b/src/main/java/eu/crushedpixel/replaymod/events/GuiEventHandler.java index fa536542..fe2c525f 100644 --- a/src/main/java/eu/crushedpixel/replaymod/events/GuiEventHandler.java +++ b/src/main/java/eu/crushedpixel/replaymod/events/GuiEventHandler.java @@ -15,7 +15,8 @@ import net.minecraftforge.client.event.GuiOpenEvent; import net.minecraftforge.client.event.GuiScreenEvent.ActionPerformedEvent; import net.minecraftforge.client.event.GuiScreenEvent.InitGuiEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import eu.crushedpixel.replaymod.gui.GuiCustomOptions; +import eu.crushedpixel.replaymod.ReplayMod; +import eu.crushedpixel.replaymod.authentication.AuthenticationHandler; import eu.crushedpixel.replaymod.gui.GuiExitReplay; import eu.crushedpixel.replaymod.gui.GuiReplayManager; import eu.crushedpixel.replaymod.gui.GuiReplaySaving; @@ -27,6 +28,7 @@ public class GuiEventHandler { @SubscribeEvent public void onGui(GuiOpenEvent event) { + if(!AuthenticationHandler.isAuthenticated()) return; if(event.gui instanceof GuiChat || event.gui instanceof GuiInventory) { if(ReplayHandler.replayActive()) { event.setCanceled(true); @@ -60,7 +62,9 @@ public class GuiEventHandler { } } - event.buttonList.add(new GuiButton(REPLAY_MANAGER_ID, event.gui.width / 2 - 100, i1 + 2*24, I18n.format("Replay Manager", new Object[0]))); + GuiButton rm = new GuiButton(REPLAY_MANAGER_ID, event.gui.width / 2 - 100, i1 + 2*24, I18n.format("Replay Manager", new Object[0])); + rm.enabled = AuthenticationHandler.isAuthenticated(); + event.buttonList.add(rm); } else if(event.gui instanceof GuiOptions) { event.buttonList.add(new GuiButton(9001, event.gui.width / 2 - 155, event.gui.height / 6 + 48 - 6 - 24, 310, 20, "Replay Mod Settings...")); } @@ -68,6 +72,7 @@ public class GuiEventHandler { @SubscribeEvent public void onButton(ActionPerformedEvent event) { + if(!AuthenticationHandler.isAuthenticated()) return; if(event.gui instanceof GuiMainMenu && event.button.id == REPLAY_MANAGER_ID) { if(ConnectionEventHandler.saving) { Minecraft.getMinecraft().displayGuiScreen(new GuiReplaySaving()); diff --git a/src/main/java/eu/crushedpixel/replaymod/events/GuiReplayOverlay.java b/src/main/java/eu/crushedpixel/replaymod/events/GuiReplayOverlay.java index 2d8fed11..4bf4156f 100644 --- a/src/main/java/eu/crushedpixel/replaymod/events/GuiReplayOverlay.java +++ b/src/main/java/eu/crushedpixel/replaymod/events/GuiReplayOverlay.java @@ -1,3 +1,4 @@ + package eu.crushedpixel.replaymod.events; import java.awt.Color; @@ -25,10 +26,12 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.InputEvent.KeyInputEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; +import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import org.lwjgl.opengl.Display; import org.lwjgl.opengl.GL11; +import eu.crushedpixel.replaymod.ReplayMod; import eu.crushedpixel.replaymod.entities.CameraEntity; import eu.crushedpixel.replaymod.entities.CameraEntity.MoveDirection; import eu.crushedpixel.replaymod.gui.GuiMouseInput; @@ -199,6 +202,13 @@ public class GuiReplayOverlay extends Gui { mc.displayGuiScreen((GuiScreen)null); } + CameraEntity cam = ReplayHandler.getCameraEntity(); + if(cam != null) { + ReplayHandler.setLastPosition(new Position(cam.posX, cam.posY, cam.posZ, cam.rotationPitch, cam.rotationYaw)); + } else { + ReplayHandler.setLastPosition(null); + } + ReplayHandler.setReplayPos((int)time); } } @@ -736,7 +746,7 @@ public class GuiReplayOverlay extends Gui { return false; } } - + @SubscribeEvent public void onMouseMove(MouseEvent event) { if(!ReplayHandler.replayActive()) return; @@ -777,7 +787,11 @@ public class GuiReplayOverlay extends Gui { if(FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) { return; } - + + if(Keyboard.isKeyDown(Keyboard.KEY_V) && !Keyboard.isRepeatEvent() && Keyboard.getKeyCount() == 1) { + ReplayMod.replaySettings.setLightingEnabled(!ReplayMod.replaySettings.isLightingEnabled()); + } + KeyBinding[] keyBindings = Minecraft.getMinecraft().gameSettings.keyBindings; for(KeyBinding kb : keyBindings) { if(!kb.isKeyDown()) { diff --git a/src/main/java/eu/crushedpixel/replaymod/events/ReplayTickHandler.java b/src/main/java/eu/crushedpixel/replaymod/events/ReplayTickHandler.java index 4f3ee56a..8d6c8168 100644 --- a/src/main/java/eu/crushedpixel/replaymod/events/ReplayTickHandler.java +++ b/src/main/java/eu/crushedpixel/replaymod/events/ReplayTickHandler.java @@ -30,11 +30,4 @@ public class ReplayTickHandler { } } - @SubscribeEvent - public void onFovChange(FOVUpdateEvent event) { - if(ReplayHandler.replayActive()) { - event.newfov = 1f; - } - } - } diff --git a/src/main/java/eu/crushedpixel/replaymod/gui/GuiExitReplay.java b/src/main/java/eu/crushedpixel/replaymod/gui/GuiExitReplay.java index 14c06659..44cd89dd 100644 --- a/src/main/java/eu/crushedpixel/replaymod/gui/GuiExitReplay.java +++ b/src/main/java/eu/crushedpixel/replaymod/gui/GuiExitReplay.java @@ -9,6 +9,7 @@ import net.minecraft.client.gui.GuiIngameMenu; import net.minecraft.client.gui.GuiMainMenu; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.resources.I18n; +import net.minecraft.client.settings.GameSettings.Options; public class GuiExitReplay extends GuiIngameMenu { @@ -49,6 +50,8 @@ public class GuiExitReplay extends GuiIngameMenu { ReplayHandler.endReplay(); ReplayHandler.setSpeed(1f); + mc.gameSettings.setOptionFloatValue(Options.GAMMA, ReplayHandler.getInitialGamma()); + ReplayHandler.lastExit = System.currentTimeMillis(); mc.theWorld.sendQuittingDisconnectingPacket(); } diff --git a/src/main/java/eu/crushedpixel/replaymod/gui/GuiReplaySettings.java b/src/main/java/eu/crushedpixel/replaymod/gui/GuiReplaySettings.java index a1457f4d..694ccfae 100644 --- a/src/main/java/eu/crushedpixel/replaymod/gui/GuiReplaySettings.java +++ b/src/main/java/eu/crushedpixel/replaymod/gui/GuiReplaySettings.java @@ -2,9 +2,11 @@ package eu.crushedpixel.replaymod.gui; import java.awt.Color; import java.io.IOException; +import java.lang.reflect.Field; import java.util.Map; import java.util.Map.Entry; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiOptionButton; import net.minecraft.client.gui.GuiOptionSlider; @@ -12,6 +14,7 @@ import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.resources.I18n; import net.minecraftforge.fml.client.FMLClientHandler; import eu.crushedpixel.replaymod.ReplayMod; +import eu.crushedpixel.replaymod.reflection.MCPNames; import eu.crushedpixel.replaymod.settings.ReplaySettings; public class GuiReplaySettings extends GuiScreen { @@ -24,8 +27,9 @@ public class GuiReplaySettings extends GuiScreen { private static final int RECORDSP_ID = 9005; private static final int SEND_CHAT = 9006; private static final int FORCE_LINEAR = 9007; + private static final int ENABLE_LIGHTING = 9008; - private GuiButton recordServerButton, recordSPButton, sendChatButton, linearButton; + private GuiButton recordServerButton, recordSPButton, sendChatButton, linearButton, lightingButton; public GuiReplaySettings(GuiScreen parentGuiScreen) { @@ -62,6 +66,9 @@ public class GuiReplaySettings extends GuiScreen { } else if(e.getKey().equals("Force Linear Movement")) { linearButton = new GuiButton(FORCE_LINEAR, this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), 150, 20, "Camera Path: "+linearOnOff((Boolean)e.getValue())); this.buttonList.add(linearButton); + } else if(e.getKey().equals("Enable Lighting")) { + lightingButton = new GuiButton(ENABLE_LIGHTING, this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), 150, 20, "Enable Lighting: "+onOff((Boolean)e.getValue())); + this.buttonList.add(lightingButton); } ++i; @@ -88,7 +95,7 @@ public class GuiReplaySettings extends GuiScreen { this.drawDefaultBackground(); this.drawCenteredString(this.fontRendererObj, "Replay Mod Settings", this.width / 2, 20, 16777215); if (FMLClientHandler.instance().getClient().thePlayer != null) { - this.drawCenteredString(this.fontRendererObj, "WARNING: These settings are going to be", this.width / 2, 180, Color.RED.getRGB()); + this.drawCenteredString(this.fontRendererObj, "WARNING: Recording settings are going to be", this.width / 2, 180, Color.RED.getRGB()); this.drawCenteredString(this.fontRendererObj, "applied the next time you join a world.", this.width / 2, 190, Color.RED.getRGB()); } super.drawScreen(mouseX, mouseY, partialTicks); @@ -127,6 +134,12 @@ public class GuiReplaySettings extends GuiScreen { linearButton.displayString = "Camera Path: "+linearOnOff(enabled); ReplayMod.replaySettings.setLinearMovement(enabled); break; + case ENABLE_LIGHTING: + enabled = ReplayMod.replaySettings.isLightingEnabled(); + enabled = !enabled; + lightingButton.displayString = "Enable Lighting: "+onOff(enabled); + ReplayMod.replaySettings.setLightingEnabled(enabled); + break; } } } diff --git a/src/main/java/eu/crushedpixel/replaymod/recording/DataListener.java b/src/main/java/eu/crushedpixel/replaymod/recording/DataListener.java index 64cf0073..70bccc8d 100644 --- a/src/main/java/eu/crushedpixel/replaymod/recording/DataListener.java +++ b/src/main/java/eu/crushedpixel/replaymod/recording/DataListener.java @@ -1,6 +1,5 @@ package eu.crushedpixel.replaymod.recording; -import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; @@ -12,19 +11,18 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintWriter; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import java.util.Map.Entry; +import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiMainMenu; -import net.minecraft.network.Packet; import com.google.gson.Gson; -import eu.crushedpixel.replaymod.chat.ChatMessageRequests; -import eu.crushedpixel.replaymod.chat.ChatMessageRequests.ChatMessageType; import eu.crushedpixel.replaymod.holders.PacketData; public abstract class DataListener extends ChannelInboundHandlerAdapter { @@ -45,6 +43,8 @@ public abstract class DataListener extends ChannelInboundHandlerAdapter { protected DataWriter dataWriter; private Gson gson = new Gson(); + + protected Set players = new HashSet(); public void setWorldName(String worldName) { this.worldName = worldName; @@ -69,7 +69,7 @@ public abstract class DataListener extends ChannelInboundHandlerAdapter { @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { - dataWriter.requestFinish(); + dataWriter.requestFinish(players); } public class DataWriter { @@ -139,14 +139,17 @@ public abstract class DataListener extends ChannelInboundHandlerAdapter { outputThread.start(); } - public void requestFinish() { + public void requestFinish(Set players) { active = false; byte[] buffer = new byte[1024]; try { ConnectionEventHandler.saving = true; - ReplayMetaData metaData = new ReplayMetaData(singleplayer, worldName, (int) lastSentPacket, startTime); + String mcversion = Minecraft.getMinecraft().getVersion(); + String[] pl = players.toArray(new String[players.size()]); + + ReplayMetaData metaData = new ReplayMetaData(singleplayer, worldName, (int) lastSentPacket, startTime, pl, mcversion); String json = gson.toJson(metaData); File folder = new File("./replay_recordings/"); diff --git a/src/main/java/eu/crushedpixel/replaymod/recording/PacketListener.java b/src/main/java/eu/crushedpixel/replaymod/recording/PacketListener.java index 854015b9..81380155 100644 --- a/src/main/java/eu/crushedpixel/replaymod/recording/PacketListener.java +++ b/src/main/java/eu/crushedpixel/replaymod/recording/PacketListener.java @@ -8,6 +8,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Field; +import java.util.UUID; import net.minecraft.client.Minecraft; import net.minecraft.entity.DataWatcher; @@ -35,9 +36,13 @@ public class PacketListener extends DataListener { public void saveOnly(Packet packet) { try { + if(packet instanceof S0CPacketSpawnPlayer) { + UUID uuid = ((S0CPacketSpawnPlayer)packet).func_179819_c(); + players.add(uuid.toString()); + } + PacketData pd = getPacketData(context, packet); - dataWriter.writeData(pd); - lastSentPacket = pd.getTimestamp(); + writeData(pd); } catch(Exception e) { e.printStackTrace(); } @@ -69,10 +74,14 @@ public class PacketListener extends DataListener { return; } } + + if(packet instanceof S0CPacketSpawnPlayer) { + UUID uuid = ((S0CPacketSpawnPlayer)packet).func_179819_c(); + players.add(uuid.toString()); + } PacketData pd = getPacketData(ctx, packet); - dataWriter.writeData(pd); - lastSentPacket = pd.getTimestamp(); + writeData(pd); } catch(Exception e) { e.printStackTrace(); } @@ -82,6 +91,12 @@ public class PacketListener extends DataListener { super.channelRead(ctx, msg); } + private void writeData(PacketData pd) { + dataWriter.writeData(pd); + lastSentPacket = pd.getTimestamp(); + } + + private PacketData getPacketData(ChannelHandlerContext ctx, Packet packet) throws IOException, IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException { if(startTime == null) startTime = System.currentTimeMillis(); diff --git a/src/main/java/eu/crushedpixel/replaymod/recording/ReplayMetaData.java b/src/main/java/eu/crushedpixel/replaymod/recording/ReplayMetaData.java index a7b5f7a6..fdabfb8e 100644 --- a/src/main/java/eu/crushedpixel/replaymod/recording/ReplayMetaData.java +++ b/src/main/java/eu/crushedpixel/replaymod/recording/ReplayMetaData.java @@ -9,37 +9,34 @@ public class ReplayMetaData { private String serverName; private int duration; private long date; - + private String[] players; + private String mcversion; public ReplayMetaData(boolean singleplayer, String serverName, - int duration, long date) { + int duration, long date, String[] players, String mcversion) { this.singleplayer = singleplayer; this.serverName = serverName; this.duration = duration; this.date = date; + this.players = players; + this.mcversion = mcversion; } public boolean isSingleplayer() { return singleplayer; } - public void setSingleplayer(boolean singleplayer) { - this.singleplayer = singleplayer; - } public String getServerName() { return serverName; } - public void setServer_name(String serverName) { - this.serverName = serverName; - } public int getDuration() { return duration; } - public void setDuration(int duration) { - this.duration = duration; - } public long getDate() { return date; } - public void setDate(long date) { - this.date = date; + public String[] getPlayers() { + return players; + } + public String getMCVersion() { + return mcversion; } } diff --git a/src/main/java/eu/crushedpixel/replaymod/reflection/MCPNames.java b/src/main/java/eu/crushedpixel/replaymod/reflection/MCPNames.java index 7b9b3110..e8f2e18e 100644 --- a/src/main/java/eu/crushedpixel/replaymod/reflection/MCPNames.java +++ b/src/main/java/eu/crushedpixel/replaymod/reflection/MCPNames.java @@ -32,7 +32,7 @@ public final class MCPNames { private static final Map fields; private static final Map methods; - private static final MCPEnvironment env = new MCPEnvironment(); + public static final MCPEnvironment env = new MCPEnvironment(); static { if (use()) { diff --git a/src/main/java/eu/crushedpixel/replaymod/replay/LesserDataWatcher.java b/src/main/java/eu/crushedpixel/replaymod/replay/LesserDataWatcher.java index c7ce1561..714c4928 100644 --- a/src/main/java/eu/crushedpixel/replaymod/replay/LesserDataWatcher.java +++ b/src/main/java/eu/crushedpixel/replaymod/replay/LesserDataWatcher.java @@ -26,22 +26,22 @@ public class LesserDataWatcher extends DataWatcher { @Override public byte getWatchableObjectByte(int id) { - return 0; + return 10; } @Override public short getWatchableObjectShort(int id) { - return 0; + return 10; } @Override public int getWatchableObjectInt(int id) { - return 0; + return 10; } @Override public float getWatchableObjectFloat(int id) { - return 0; + return 10f; } @Override diff --git a/src/main/java/eu/crushedpixel/replaymod/replay/ReplayHandler.java b/src/main/java/eu/crushedpixel/replaymod/replay/ReplayHandler.java index 43bdeeaf..4ad0f1f6 100644 --- a/src/main/java/eu/crushedpixel/replaymod/replay/ReplayHandler.java +++ b/src/main/java/eu/crushedpixel/replaymod/replay/ReplayHandler.java @@ -23,6 +23,7 @@ import eu.crushedpixel.replaymod.chat.ChatMessageRequests; import eu.crushedpixel.replaymod.entities.CameraEntity; import eu.crushedpixel.replaymod.holders.Keyframe; import eu.crushedpixel.replaymod.holders.KeyframeComparator; +import eu.crushedpixel.replaymod.holders.Position; import eu.crushedpixel.replaymod.holders.PositionKeyframe; import eu.crushedpixel.replaymod.holders.TimeKeyframe; @@ -47,6 +48,16 @@ public class ReplayHandler { public static long lastExit = 0; + private static float gamma = 0f; + + public static void setInitialGamma(float initial) { + gamma = initial; + } + + public static float getInitialGamma() { + return gamma; + } + public static void setReplaying(boolean replaying) { isReplaying = replaying; } @@ -369,4 +380,13 @@ public class ReplayHandler { public static void setRealTimelineCursor(int pos) { realTimelinePosition = pos; } + + private static Position lastPosition = null; + public static void setLastPosition(Position position) { + lastPosition = position; + } + + public static Position getLastPosition() { + return lastPosition; + } } diff --git a/src/main/java/eu/crushedpixel/replaymod/replay/ReplayProcess.java b/src/main/java/eu/crushedpixel/replaymod/replay/ReplayProcess.java index 0bb34dd4..dd9fe554 100644 --- a/src/main/java/eu/crushedpixel/replaymod/replay/ReplayProcess.java +++ b/src/main/java/eu/crushedpixel/replaymod/replay/ReplayProcess.java @@ -31,20 +31,24 @@ public class ReplayProcess { private static LinearTimestamp timeLinear = null; private static double previousReplaySpeed = 0; + + private static boolean calculated = false; public static void startReplayProcess() { + lastPosition = null; + motionSpline = null; + timeLinear = null; + calculated = false; + ChatMessageRequests.initialize(); - if(ReplayHandler.getKeyframes().isEmpty()) { - ChatMessageRequests.addChatMessage("No keyframes set!", ChatMessageType.WARNING); + if(ReplayHandler.getPosKeyframeCount() < 2) { + ChatMessageRequests.addChatMessage("At least 2 position keyframes required!", ChatMessageType.WARNING); return; } startRealTime = System.currentTimeMillis(); lastRealTime = startRealTime; lastRealReplayTime = 0; lastTimestamp = -1; - lastPosition = null; - motionSpline = null; - timeLinear = null; linear = ReplayMod.replaySettings.isLinearMovement(); ReplayHandler.sortKeyframes(); ReplayHandler.setReplaying(true); @@ -86,10 +90,8 @@ public class ReplayProcess { motionSpline.addPoint(pos); } } - if(motionSpline.getPoints().size() < 3) linear = true; - else motionSpline.calcSpline(); - } + if(linear && motionLinear == null) { //set up linear path motionLinear = new LinearPoint(); @@ -109,16 +111,13 @@ public class ReplayProcess { } } - /* - for(float x = 0; x <= 1f; x+=0.1) { - //timeLinear.getPoint(x); - System.out.println(x+" | "+timeLinear.getPoint(x)); - } - */ - //System.out.println(timeLinear.getPoint(0)); - } + if(!calculated) { + calculated = true; + motionSpline.calcSpline(); + } + long curTime = System.currentTimeMillis(); long timeStep = curTime - lastRealTime; @@ -170,6 +169,10 @@ public class ReplayProcess { if(!(nextTime == null || lastTime == null)) { curSpeed = ((double)((nextTime.getTimestamp()-lastTime.getTimestamp())))/((double)((nextTimeStamp-lastTimeStamp))); } + + if(lastTimeStamp == nextTimeStamp) { + curSpeed = 0f; + } } int currentDiff = nextPosStamp - lastPosStamp; diff --git a/src/main/java/eu/crushedpixel/replaymod/replay/ReplaySender.java b/src/main/java/eu/crushedpixel/replaymod/replay/ReplaySender.java index e82fabaf..a5683cf4 100644 --- a/src/main/java/eu/crushedpixel/replaymod/replay/ReplaySender.java +++ b/src/main/java/eu/crushedpixel/replaymod/replay/ReplaySender.java @@ -14,13 +14,11 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.Field; import java.util.ArrayList; -import java.util.List; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiDownloadTerrain; import net.minecraft.client.particle.EffectRenderer; import net.minecraft.entity.Entity; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.network.EnumConnectionState; import net.minecraft.network.EnumPacketDirection; import net.minecraft.network.NetworkManager; @@ -32,7 +30,6 @@ import net.minecraft.network.play.server.S06PacketUpdateHealth; import net.minecraft.network.play.server.S07PacketRespawn; import net.minecraft.network.play.server.S08PacketPlayerPosLook; import net.minecraft.network.play.server.S0BPacketAnimation; -import net.minecraft.network.play.server.S18PacketEntityTeleport; import net.minecraft.network.play.server.S1CPacketEntityMetadata; import net.minecraft.network.play.server.S1DPacketEntityEffect; import net.minecraft.network.play.server.S1FPacketSetExperience; @@ -61,8 +58,10 @@ import org.apache.commons.io.FilenameUtils; import com.google.gson.Gson; +import eu.crushedpixel.replaymod.ReplayMod; import eu.crushedpixel.replaymod.entities.CameraEntity; import eu.crushedpixel.replaymod.events.RecordingHandler; +import eu.crushedpixel.replaymod.holders.Position; import eu.crushedpixel.replaymod.recording.ConnectionEventHandler; import eu.crushedpixel.replaymod.recording.ReplayMetaData; import eu.crushedpixel.replaymod.reflection.MCPNames; @@ -112,7 +111,7 @@ public class ReplaySender extends ChannelInboundHandlerAdapter { private int replayLength = 0; private int actualID = -1; - + private EffectRenderer old = mc.effectRenderer; private ZipArchiveEntry replayEntry; @@ -209,6 +208,8 @@ public class ReplaySender extends ChannelInboundHandlerAdapter { } catch (Exception e) { e.printStackTrace(); } + + ReplayHandler.setInitialGamma(mc.gameSettings.gammaSetting); this.replayFile = replayFile; this.networkManager = nm; @@ -312,6 +313,18 @@ public class ReplaySender extends ChannelInboundHandlerAdapter { ((Timer)mcTimer.get(mc)).elapsedTicks += 5; ((Timer)mcTimer.get(mc)).renderPartialTicks += 5; } + if(!ReplayHandler.isReplaying()) { + Position pos = ReplayHandler.getLastPosition(); + CameraEntity cam = ReplayHandler.getCameraEntity(); + if(cam != null) { + if(Math.abs(pos.getX() - cam.posX) < ReplayMod.TP_DISTANCE_LIMIT && Math.abs(pos.getZ() - cam.posZ) < ReplayMod.TP_DISTANCE_LIMIT) + if(pos != null) { + cam.moveAbsolute(pos.getX(), pos.getY(), pos.getZ()); + cam.rotationPitch = pos.getPitch(); + cam.rotationYaw = pos.getYaw(); + } + } + } if(!ReplayHandler.isReplaying()) { setReplaySpeed(0); } @@ -348,7 +361,7 @@ public class ReplaySender extends ChannelInboundHandlerAdapter { }; private boolean allowMovement = false; - + @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { @@ -422,26 +435,27 @@ public class ReplaySender extends ChannelInboundHandlerAdapter { p = new S01PacketJoinGame(entId, GameType.SPECTATOR, false, dimension, difficulty, maxPlayers, worldType, false); } - - + + if(p instanceof S07PacketRespawn) { allowMovement = true; } - + if(p instanceof S08PacketPlayerPosLook) { final S08PacketPlayerPosLook ppl = (S08PacketPlayerPosLook)p; if(ReplayHandler.isReplaying() && !hurryToTimestamp) return; - + CameraEntity cent = ReplayHandler.getCameraEntity(); - - if(!allowMovement && !((Math.abs(cent.posX - ppl.func_148932_c()) > 100) || (Math.abs(cent.posZ - ppl.func_148933_e()) > 100))) { + + if(!allowMovement && !((Math.abs(cent.posX - ppl.func_148932_c()) > ReplayMod.TP_DISTANCE_LIMIT) || + (Math.abs(cent.posZ - ppl.func_148933_e()) > ReplayMod.TP_DISTANCE_LIMIT))) { return; } else { allowMovement = false; } - + Thread t = new Thread(new Runnable() { @Override diff --git a/src/main/java/eu/crushedpixel/replaymod/settings/ReplaySettings.java b/src/main/java/eu/crushedpixel/replaymod/settings/ReplaySettings.java index 097b6ee4..682bb776 100644 --- a/src/main/java/eu/crushedpixel/replaymod/settings/ReplaySettings.java +++ b/src/main/java/eu/crushedpixel/replaymod/settings/ReplaySettings.java @@ -1,28 +1,48 @@ package eu.crushedpixel.replaymod.settings; +import java.lang.reflect.Field; import java.util.LinkedHashMap; import java.util.Map; +import net.minecraft.client.Minecraft; +import net.minecraft.client.settings.GameSettings.Options; +import net.minecraft.util.Timer; import net.minecraftforge.common.config.Property; import eu.crushedpixel.replaymod.ReplayMod; +import eu.crushedpixel.replaymod.reflection.MCPNames; +import eu.crushedpixel.replaymod.replay.ReplayHandler; public class ReplaySettings { - + private int maximumFileSize = 0; private boolean enableRecordingServer = true; private boolean enableRecordingSingleplayer = true; private boolean showNotifications = true; private boolean forceLinearPath = false; + private boolean lightingEnabled = false; + private static Field mcTimer; + + static { + try { + mcTimer = Minecraft.class.getDeclaredField(MCPNames.field("field_71428_T")); + mcTimer.setAccessible(true); + } catch(Exception e) { + mcTimer = null; + e.printStackTrace(); + } + } + public ReplaySettings(int maximumFileSize, boolean enableRecordingServer, - boolean enableRecordingSingleplayer, boolean showNotifications, boolean forceLinearPath) { + boolean enableRecordingSingleplayer, boolean showNotifications, boolean forceLinearPath, boolean lightingEnabled) { this.maximumFileSize = maximumFileSize; this.enableRecordingServer = enableRecordingServer; this.enableRecordingSingleplayer = enableRecordingSingleplayer; this.showNotifications = showNotifications; this.forceLinearPath = forceLinearPath; + this.lightingEnabled = lightingEnabled; } - + public int getMaximumFileSize() { return maximumFileSize; } @@ -58,44 +78,68 @@ public class ReplaySettings { this.forceLinearPath = linear; rewriteSettings(); } - + public boolean isLightingEnabled() { + return lightingEnabled; + } + public void setLightingEnabled(boolean enabled) { + this.lightingEnabled = enabled; + if(enabled) { + Minecraft.getMinecraft().gameSettings.setOptionFloatValue(Options.GAMMA, 1000); + } else { + Minecraft.getMinecraft().gameSettings.setOptionFloatValue(Options.GAMMA, ReplayHandler.getInitialGamma()); + } + try { + Timer timer = (Timer)mcTimer.get(Minecraft.getMinecraft()); + timer.elapsedPartialTicks++; + timer.renderPartialTicks++; + } catch (Exception e) { + e.printStackTrace(); + } + + rewriteSettings(); + } + + public Map getOptions() { Map map = new LinkedHashMap(); - + map.put("Enable Notifications", showNotifications); map.put("Maximum File Size", maximumFileSize); map.put("Record Server", enableRecordingServer); map.put("Record Singleplayer", enableRecordingSingleplayer); map.put("Force Linear Movement", forceLinearPath); - + map.put("Enable Lighting", lightingEnabled); + return map; } - + public void setOptions(Map map) { try { - + maximumFileSize = (Integer)map.get("Maximum File Size"); showNotifications = (Boolean)map.get("Enable Notifications"); enableRecordingServer = (Boolean)map.get("Record Server"); enableRecordingSingleplayer = (Boolean)map.get("Record Singleplayer"); forceLinearPath = (Boolean)map.get("Force Linear Movement"); - + lightingEnabled = (Boolean)map.get("Enable Lighting"); + rewriteSettings(); } catch(Exception e) { e.printStackTrace(); } } - + public void rewriteSettings() { ReplayMod.instance.config.load(); - + ReplayMod.instance.config.removeCategory(ReplayMod.instance.config.getCategory("settings")); Property recServer = ReplayMod.instance.config.get("settings", "enableRecordingServer", enableRecordingServer, "Defines whether a recording should be started upon joining a server."); Property recSP = ReplayMod.instance.config.get("settings", "enableRecordingSingleplayer", enableRecordingSingleplayer, "Defines whether a recording should be started upon joining a singleplayer world."); Property maxFileSize = ReplayMod.instance.config.get("settings", "maximumFileSize", maximumFileSize, "The maximum File size (in MB) of a recording. 0 means unlimited."); Property showNot = ReplayMod.instance.config.get("settings", "showNotifications", showNotifications, "Defines whether notifications should be sent to the player."); Property linear = ReplayMod.instance.config.get("settings", "forceLinearPath", forceLinearPath, "Defines whether travelling paths should be linear instead of interpolated."); - + Property lighting = ReplayMod.instance.config.get("settings", "enableLighting", lightingEnabled, "If enabled, the whole map is lighted."); + ReplayMod.instance.config.save(); } }