Merge branch '1.8.9-dev' into 1.9.4-dev

This commit is contained in:
Jonas Herzig
2018-01-16 22:09:50 +01:00
37 changed files with 757 additions and 44 deletions

View File

@@ -3,6 +3,7 @@ package com.replaymod.replay;
import com.replaymod.core.utils.WrappedTimer;
import com.replaymod.replay.camera.CameraController;
import com.replaymod.replay.camera.CameraEntity;
import com.replaymod.replay.events.ReplayDispatchKeypressesEvent;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.settings.GameSettings;
@@ -11,6 +12,7 @@ import net.minecraft.crash.CrashReport;
import net.minecraft.util.ReportedException;
import net.minecraft.util.Timer;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.FMLCommonHandler;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
@@ -122,7 +124,9 @@ public class InputReplayTimer extends WrappedTimer {
}
// Twitch, screenshot, fullscreen, etc. (stuff that works everywhere)
mc.dispatchKeypresses();
if (!MinecraftForge.EVENT_BUS.post(new ReplayDispatchKeypressesEvent.Pre())) {
mc.dispatchKeypresses();
}
if (pressed) {
// This might be subject to change as vanilla shaders are still kinda unused in 1.8

View File

@@ -36,6 +36,7 @@ import java.util.Optional;
version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*",
clientSideOnly = true,
useMetadata = true)
public class ReplayModReplay {
public static final String MOD_ID = "replaymod-replay";
@@ -194,6 +195,10 @@ public class ReplayModReplay {
replayHandler = new ReplayHandler(replayFile, true);
}
public void forcefullyStopReplay() {
replayHandler = null;
}
public ReplayMod getCore() {
return core;
}

View File

@@ -5,8 +5,12 @@ import com.google.common.io.Files;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.utils.Restrictions;
import com.replaymod.replay.camera.CameraEntity;
import com.replaymod.replaystudio.io.ReplayInputStream;
import com.replaymod.replaystudio.io.ReplayOutputStream;
import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.studio.ReplayStudio;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufOutputStream;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandler.Sharable;
@@ -105,10 +109,10 @@ public class ReplaySender extends ChannelDuplexHandler {
protected ChannelHandlerContext ctx;
/**
* The data input stream from which new packets are read.
* The replay input stream from which new packets are read.
* When accessing this stream make sure to synchronize on {@code this} as it's used from multiple threads.
*/
protected DataInputStream dis;
protected ReplayInputStream replayIn;
/**
* The next packet that should be sent.
@@ -591,8 +595,8 @@ public class ReplaySender extends ChannelDuplexHandler {
REPLAY_LOOP:
while (!terminate) {
synchronized (ReplaySender.this) {
if (dis == null) {
dis = new DataInputStream(replayFile.getPacketData());
if (replayIn == null) {
replayIn = replayFile.getPacketData();
}
// Packet loop
while (true) {
@@ -619,7 +623,7 @@ public class ReplaySender extends ChannelDuplexHandler {
// Read the next packet if we don't already have one
if (nextPacket == null) {
nextPacket = new PacketData(dis);
nextPacket = new PacketData(replayIn);
}
int nextTimeStamp = nextPacket.timestamp;
@@ -676,9 +680,9 @@ public class ReplaySender extends ChannelDuplexHandler {
nextPacket = null;
lastPacketSent = System.currentTimeMillis();
replayHandler.restartedReplay();
if (dis != null) {
dis.close();
dis = null;
if (replayIn != null) {
replayIn.close();
replayIn = null;
}
}
}
@@ -767,17 +771,17 @@ public class ReplaySender extends ChannelDuplexHandler {
if (timestamp < lastTimeStamp) { // Restart the replay if we need to go backwards in time
hasWorldLoaded = false;
lastTimeStamp = 0;
if (dis != null) {
dis.close();
dis = null;
if (replayIn != null) {
replayIn.close();
replayIn = null;
}
startFromBeginning = false;
nextPacket = null;
replayHandler.restartedReplay();
}
if (dis == null) {
dis = new DataInputStream(replayFile.getPacketData());
if (replayIn == null) {
replayIn = replayFile.getPacketData();
}
while (true) { // Send packets
@@ -789,7 +793,7 @@ public class ReplaySender extends ChannelDuplexHandler {
nextPacket = null;
} else {
// Otherwise read one from the input stream
pd = new PacketData(dis);
pd = new PacketData(replayIn);
}
int nextTimeStamp = pd.timestamp;
@@ -804,7 +808,7 @@ public class ReplaySender extends ChannelDuplexHandler {
} catch (EOFException eof) {
// Shit! We hit the end before finishing our job! What shall we do now?
// well, let's just pretend we're done...
dis = null;
replayIn = null;
break;
} catch (IOException e) {
e.printStackTrace();
@@ -869,13 +873,32 @@ public class ReplaySender extends ChannelDuplexHandler {
}
private static final class PacketData {
private static final ByteBuf byteBuf = Unpooled.buffer();
private static final ByteBufOutputStream byteBufOut = new ByteBufOutputStream(byteBuf);
private static final ReplayOutputStream encoder = new ReplayOutputStream(new ReplayStudio(), byteBufOut);
private final int timestamp;
private final byte[] bytes;
public PacketData(DataInputStream in) throws IOException {
timestamp = in.readInt();
bytes = new byte[in.readInt()];
in.readFully(bytes);
public PacketData(ReplayInputStream in) throws IOException {
com.replaymod.replaystudio.PacketData data = in.readPacket();
timestamp = (int) data.getTime();
// We need to re-encode MCProtocolLib packets, so we can later decode them as NMS packets
// The main reason we aren't reading them as NMS packets is that we want ReplayStudio to be able
// to apply ViaVersion (and potentially other magic) to it.
synchronized (encoder) {
byteBuf.markReaderIndex(); // Mark the current reader and writer index (should be at start)
byteBuf.markWriterIndex();
encoder.write(data); // Re-encode packet, data will end up in byteBuf
encoder.flush();
byteBuf.skipBytes(8); // Skip packet length & timestamp
bytes = new byte[byteBuf.readableBytes()]; // Create bytes array of sufficient size
byteBuf.readBytes(bytes); // Read all data into bytes
byteBuf.resetReaderIndex(); // Reset reader & writer index for next use
byteBuf.resetWriterIndex();
}
}
}
}

View File

@@ -4,6 +4,7 @@ import com.replaymod.core.SettingsRegistry;
public final class Setting<T> extends SettingsRegistry.SettingKeys<T> {
public static final Setting<Boolean> SHOW_CHAT = make("showChat", "showchat", true);
public static final Setting<Boolean> SHOW_SERVER_IPS = new Setting<>("showServerIPs", true);
public static final SettingsRegistry.MultipleChoiceSettingKeys<String> CAMERA =
new SettingsRegistry.MultipleChoiceSettingKeys<>(
"replay", "camera", "replaymod.gui.settings.camera", "replaymod.camera.classic");
@@ -15,4 +16,8 @@ public final class Setting<T> extends SettingsRegistry.SettingKeys<T> {
public Setting(String key, String displayString, T defaultValue) {
super("replay", key, "replaymod.gui.settings." + displayString, defaultValue);
}
public Setting(String key, T defaultValue) {
super("replay", key, null, defaultValue);
}
}

View File

@@ -0,0 +1,10 @@
package com.replaymod.replay.events;
import net.minecraftforge.fml.common.eventhandler.Cancelable;
import net.minecraftforge.fml.common.eventhandler.Event;
public abstract class ReplayDispatchKeypressesEvent extends Event {
@Cancelable
public static class Pre extends ReplayDispatchKeypressesEvent {}
}

View File

@@ -5,9 +5,12 @@ import com.google.common.base.Supplier;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.mojang.realmsclient.gui.ChatFormatting;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.SettingsRegistry;
import com.replaymod.core.gui.GuiReplaySettings;
import com.replaymod.core.utils.Utils;
import com.replaymod.replay.ReplayModReplay;
import com.replaymod.replay.Setting;
import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.replay.ReplayMetaData;
import com.replaymod.replaystudio.replay.ZipReplayFile;
@@ -18,6 +21,7 @@ import de.johni0702.minecraft.gui.container.GuiPanel;
import de.johni0702.minecraft.gui.container.GuiScreen;
import de.johni0702.minecraft.gui.element.*;
import de.johni0702.minecraft.gui.element.advanced.GuiResourceLoadingList;
import de.johni0702.minecraft.gui.function.Typeable;
import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.layout.GridLayout;
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
@@ -34,8 +38,10 @@ import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.helpers.Strings;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableDimension;
import org.lwjgl.util.ReadablePoint;
import java.awt.*;
import java.awt.image.BufferedImage;
@@ -47,7 +53,7 @@ import java.util.Date;
import static com.replaymod.replay.ReplayModReplay.LOGGER;
public class GuiReplayViewer extends GuiScreen {
public class GuiReplayViewer extends GuiScreen implements Typeable {
private final ReplayModReplay mod;
public final GuiResourceLoadingList<GuiReplayEntry> list = new GuiResourceLoadingList<GuiReplayEntry>(this).onSelectionChanged(new Runnable() {
@@ -272,6 +278,18 @@ public class GuiReplayViewer extends GuiScreen {
}
private final GuiImage defaultThumbnail = new GuiImage().setTexture(Utils.DEFAULT_THUMBNAIL);
@Override
public boolean typeKey(ReadablePoint mousePosition, int keyCode, char keyChar, boolean ctrlDown, boolean shiftDown) {
if (keyCode == Keyboard.KEY_F1) {
SettingsRegistry reg = ReplayMod.instance.getSettingsRegistry();
reg.set(Setting.SHOW_SERVER_IPS, !reg.get(Setting.SHOW_SERVER_IPS));
reg.save();
list.load();
}
return false;
}
public class GuiReplayEntry extends AbstractGuiContainer<GuiReplayEntry> implements Comparable<GuiReplayEntry> {
public final File file;
public final GuiLabel name = new GuiLabel();
@@ -303,7 +321,8 @@ public class GuiReplayViewer extends GuiScreen {
this.file = file;
name.setText(ChatFormatting.UNDERLINE + Utils.fileNameToReplayName(file.getName()));
if (Strings.isEmpty(metaData.getServerName())) {
if (Strings.isEmpty(metaData.getServerName())
|| !ReplayMod.instance.getSettingsRegistry().get(Setting.SHOW_SERVER_IPS)) {
server.setI18nText("replaymod.gui.iphidden").setColor(Colors.DARK_RED);
} else {
server.setText(metaData.getServerName());

View File

@@ -15,6 +15,8 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static com.replaymod.replay.ReplayModReplay.LOGGER;
public class GuiHandler {
private static final int BUTTON_EXIT_SERVER = 1;
private static final int BUTTON_ACHIEVEMENTS = 5;
@@ -99,6 +101,20 @@ public class GuiHandler {
return;
}
if (mod.getReplayHandler() != null) {
// Something went terribly wrong and we ended up in the main menu with the replay still active.
// To prevent players from joining live servers and using the CameraEntity, try to stop the replay now.
try {
mod.getReplayHandler().endReplay();
} catch (IOException e) {
LOGGER.error("Trying to stop broken replay: ", e);
} finally {
if (mod.getReplayHandler() != null) {
mod.forcefullyStopReplay();
}
}
}
GuiButton button = new GuiButton(BUTTON_REPLAY_VIEWER, event.getGui().width / 2 - 100,
event.getGui().height / 4 + 10 + 3 * 24, I18n.format("replaymod.gui.replayviewer"));
button.width = button.width / 2 - 2;