Replays now support Server Resource Packs

Reworked Replay Settings code
This commit is contained in:
Marius Metzger
2015-04-03 01:22:26 +02:00
parent c23d2a0d0e
commit f3cb4011fc
5 changed files with 220 additions and 117 deletions

View File

@@ -55,7 +55,7 @@ public class ReplayMod
public static GuiReplayOverlay overlay = new GuiReplayOverlay();
public static ReplaySettings replaySettings = new ReplaySettings(true, true, true, false, false, 30, 0.5f);
public static ReplaySettings replaySettings;
public static Configuration config;
public static boolean firstMainMenu = true;

View File

@@ -82,7 +82,6 @@ public class KeyInputHandler {
//Custom registered handlers
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_THUMBNAIL) && kb.isPressed() && !found) {
System.out.println("thumbnail key pressed");
ReplayScreenshot.prepareScreenshot();
GuiReplayOverlay.requestScreenshot();
}

View File

@@ -2,20 +2,14 @@ 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;
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;
import eu.crushedpixel.replaymod.settings.ReplaySettings.Option;
public class GuiReplaySettings extends GuiScreen {
@@ -30,8 +24,9 @@ public class GuiReplaySettings extends GuiScreen {
private static final int FORCE_LINEAR = 9007;
private static final int ENABLE_LIGHTING = 9008;
private static final int FRAMERATE_SLIDER_ID = 9009;
private static final int RESOURCEPACK_ID = 9010;
private GuiButton recordServerButton, recordSPButton, sendChatButton, linearButton, lightingButton;
private GuiButton recordServerButton, recordSPButton, sendChatButton, linearButton, lightingButton, resourcePackButton;
public GuiReplaySettings(GuiScreen parentGuiScreen)
{
@@ -43,31 +38,48 @@ public class GuiReplaySettings extends GuiScreen {
this.buttonList.clear();
this.buttonList.add(new GuiButton(200, this.width / 2 - 100, this.height - 27, I18n.format("gui.done", new Object[0])));
Map<String, Object> aoptions = ReplayMod.replaySettings.getOptions();
Option[] aoptions = Option.values();
int k = 0;
int i = 0;
for (Entry<String, Object> e : aoptions.entrySet()) {
for (Option o : aoptions) {
if(e.getKey().equals("Video Quality")) {
this.buttonList.add(new GuiVideoQualitySlider(QUALITY_SLIDER_ID, this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), (Float)e.getValue(), "Video Quality"));
} else if(e.getKey().equals("Video Framerate")) {
this.buttonList.add(new GuiVideoFramerateSlider(FRAMERATE_SLIDER_ID, this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), (Integer)e.getValue(), "Video Framerate"));
} else if(e.getKey().equals("Enable Notifications")) {
sendChatButton = new GuiButton(SEND_CHAT, this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), 150, 20, "Enable Notifications: "+onOff((Boolean)e.getValue()));
this.buttonList.add(sendChatButton);
} else if(e.getKey().equals("Record Server")) {
recordServerButton = new GuiButton(RECORDSERVER_ID, this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), 150, 20, "Record Server: "+onOff((Boolean)e.getValue()));
this.buttonList.add(recordServerButton);
} else if(e.getKey().equals("Record Singleplayer")) {
recordSPButton = new GuiButton(RECORDSP_ID, this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), 150, 20, "Record Singleplayer: "+onOff((Boolean)e.getValue()));
this.buttonList.add(recordSPButton);
} 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);
switch(o) {
case lighting:
this.buttonList.add(lightingButton = new GuiButton(ENABLE_LIGHTING, this.width / 2 - 155 + i % 2 * 160,
this.height / 6 + 24 * (i >> 1), 150, 20, "Enable Lighting: "+onOff((Boolean)o.getValue())));
break;
case linear:
this.buttonList.add(linearButton = new GuiButton(FORCE_LINEAR, this.width / 2 - 155 + i % 2 * 160,
this.height / 6 + 24 * (i >> 1), 150, 20, "Camera Path: "+linearOnOff((Boolean)o.getValue())));
break;
case notifications:
this.buttonList.add(sendChatButton = new GuiButton(SEND_CHAT,
this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), 150, 20,
"Enable Notifications: "+onOff((Boolean)o.getValue())));
break;
case recordServer:
this.buttonList.add(recordServerButton = new GuiButton(RECORDSERVER_ID,
this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), 150, 20, "Record Server: "+onOff((Boolean)o.getValue())));
break;
case recordSingleplayer:
this.buttonList.add(recordSPButton = new GuiButton(RECORDSP_ID, this.width / 2 - 155 + i % 2 * 160,
this.height / 6 + 24 * (i >> 1), 150, 20, "Record Singleplayer: "+onOff((Boolean)o.getValue())));
break;
case useResources:
this.buttonList.add(resourcePackButton = new GuiButton(RESOURCEPACK_ID, this.width / 2 - 155 + i % 2 * 160,
this.height / 6 + 24 * (i >> 1), 150, 20, "Server Resource Packs: "+onOff((Boolean)o.getValue())));
break;
case videoFramerate:
this.buttonList.add(new GuiVideoFramerateSlider(FRAMERATE_SLIDER_ID,
this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), (Integer)o.getValue(), "Video Framerate"));
break;
case videoQuality:
this.buttonList.add(new GuiVideoQualitySlider(QUALITY_SLIDER_ID,
this.width / 2 - 155 + i % 2 * 160, this.height / 6 + 24 * (i >> 1), (Float)o.getValue(), "Video Quality"));
break;
default:
break;
}
++i;
@@ -136,6 +148,12 @@ public class GuiReplaySettings extends GuiScreen {
lightingButton.displayString = "Enable Lighting: "+onOff(enabled);
ReplayMod.replaySettings.setLightingEnabled(enabled);
break;
case RESOURCEPACK_ID:
enabled = ReplayMod.replaySettings.getUseResourcePacks();
enabled = !enabled;
resourcePackButton.displayString = "Server Resource Packs: "+onOff(enabled);
ReplayMod.replaySettings.setUseResourcePacks(enabled);
break;
}
}
}

View File

@@ -12,15 +12,14 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.net.URL;
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.client.resources.ResourcePackRepository;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.projectile.EntityArrow;
import net.minecraft.network.EnumConnectionState;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
@@ -32,8 +31,6 @@ 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.S0CPacketSpawnPlayer;
import net.minecraft.network.play.server.S0EPacketSpawnObject;
import net.minecraft.network.play.server.S0FPacketSpawnMob;
import net.minecraft.network.play.server.S1CPacketEntityMetadata;
import net.minecraft.network.play.server.S1DPacketEntityEffect;
import net.minecraft.network.play.server.S1FPacketSetExperience;
@@ -59,9 +56,9 @@ import net.minecraftforge.fml.client.FMLClientHandler;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import com.google.common.base.Predicate;
import com.google.gson.Gson;
import eu.crushedpixel.replaymod.ReplayMod;
@@ -144,7 +141,7 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
e.printStackTrace();
}
}
public long getDesiredTimestamp() {
return desiredTimeStamp;
}
@@ -346,7 +343,6 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
private ArrayList<Class> badPackets = new ArrayList<Class>() {
{
add(S28PacketEffect.class);
add(S48PacketResourcePackSend.class);
add(S2BPacketChangeGameState.class);
add(S06PacketUpdateHealth.class);
add(S2DPacketOpenWindow.class);
@@ -368,6 +364,98 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
//private static Field dataWatcherField;
private static class ResourcePackCheck extends Thread {
public ResourcePackCheck(String url, String hash) {
this.url = url;
this.hash = hash;
}
private String url, hash;
private static Field serverResourcePackDirectory;
private static Minecraft mc = Minecraft.getMinecraft();
private static ResourcePackRepository repo = mc.getResourcePackRepository();
static {
try {
serverResourcePackDirectory = ResourcePackRepository.class.getDeclaredField(MCPNames.field("field_148534_e"));
serverResourcePackDirectory.setAccessible(true);
} catch(Exception e) {
e.printStackTrace();
}
}
private File getServerResourcePackLocation(String url, String hash) throws IOException, IllegalArgumentException, IllegalAccessException {
String filename;
if (hash.matches("^[a-f0-9]{40}$")) {
filename = hash;
} else {
filename = url.substring(url.lastIndexOf("/") + 1);
if (filename.contains("?"))
{
filename = filename.substring(0, filename.indexOf("?"));
}
if (!filename.endsWith(".zip"))
{
return null;
}
filename = "legacy_" + filename.replaceAll("\\W", "");
}
File folder = (File)serverResourcePackDirectory.get(repo);
File rp = new File(folder, filename);
return rp;
}
private boolean downloadServerResourcePack(String url, File file) {
try {
FileUtils.copyURLToFile(new URL(url), file);
return true;
} catch(Exception e) {
e.printStackTrace();
}
return false;
}
@Override
public void run() {
try {
boolean use = ReplayMod.instance.replaySettings.getUseResourcePacks();
if(!use) return;
System.out.println("Looking for downloaded Resource Pack...");
File rp = getServerResourcePackLocation(url, hash);
if(rp == null) {
System.out.println("Invalid Resource Pack provided");
return;
}
if(rp.exists()) {
System.out.println("Resource Pack found!");
repo.func_177319_a(rp);
} else {
System.out.println("No Resource Pack found.");
System.out.println("Attempting to download Resource Pack...");
boolean success = downloadServerResourcePack(url, rp);
System.out.println(success ? "Resource pack was successfully downloaded!" : "Resource Pack download failed.");
if(success) {
repo.func_177319_a(rp);
}
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
static {
try {
playerUUIDField = S0CPacketSpawnPlayer.class.getDeclaredField(MCPNames.field("field_179820_b"));
@@ -402,7 +490,7 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
try {
Packet p = ReplayFileIO.deserializePacket(ba);
if(p == null) return;
//If hurrying, ignore some packets, unless during Replay Path and *not* in initial hurry
@@ -419,6 +507,14 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
p = TimeHandler.getTimePacket((S03PacketTimeUpdate)p);
}
if(p instanceof S48PacketResourcePackSend) {
S48PacketResourcePackSend pa = (S48PacketResourcePackSend)p;
Thread t = new ResourcePackCheck(pa.func_179783_a(), pa.func_179784_b());
t.start();
return;
}
if(p instanceof S02PacketChat) {
byte pos = (Byte)chatPacketPosition.get(p);
if(pos == 1) { //Ignores command block output sent
@@ -442,7 +538,7 @@ public class ReplaySender extends ChannelInboundHandlerAdapter {
}
}
}
*/
*/
try {
if(p instanceof S1CPacketEntityMetadata) {

View File

@@ -1,29 +1,35 @@
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.gui.GuiOptions;
import net.minecraft.client.gui.GuiVideoSettings;
import net.minecraft.client.settings.GameSettings.Options;
import net.minecraft.entity.player.EnumPlayerModelParts;
import net.minecraft.util.Timer;
import net.minecraftforge.common.config.Property;
import net.minecraftforge.common.config.Configuration;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.reflection.MCPNames;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
public class ReplaySettings {
private boolean enableRecordingServer = true;
private boolean enableRecordingSingleplayer = true;
private boolean showNotifications = true;
private boolean forceLinearPath = false;
private boolean lightingEnabled = false;
private float videoQuality = 0.5f;
private int videoFramerate = 30;
public enum Option {
recordServer(true), recordSingleplayer(true), notifications(true), linear(false),
lighting(false), useResources(true), videoQuality(0.5f), videoFramerate(30);
private Object value;
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
Option(Object value) {
this.value = value;
}
}
private static Field mcTimer;
@@ -39,63 +45,71 @@ public class ReplaySettings {
public ReplaySettings(boolean enableRecordingServer,
boolean enableRecordingSingleplayer, boolean showNotifications, boolean forceLinearPath, boolean lightingEnabled, int framerate, float videoQuality) {
this.enableRecordingServer = enableRecordingServer;
this.enableRecordingSingleplayer = enableRecordingSingleplayer;
this.showNotifications = showNotifications;
this.forceLinearPath = forceLinearPath;
this.lightingEnabled = lightingEnabled;
this.videoFramerate = Math.min(120, Math.max(10, framerate));
this.videoQuality = Math.min(0.9f, Math.max(0.1f, videoQuality));
setEnableRecordingServer(enableRecordingServer);
setEnableRecordingSingleplayer(enableRecordingSingleplayer);
setLinearMovement(forceLinearPath);
setShowNotifications(showNotifications);
setLightingEnabled(lightingEnabled);
setVideoFramerate(Math.min(120, Math.max(10, framerate)));
setVideoQuality(Math.min(0.9f, Math.max(0.1f, videoQuality)));
}
public int getVideoFramerate() {
return videoFramerate;
return (Integer)Option.videoFramerate.getValue();
}
public void setVideoFramerate(int framerate) {
this.videoFramerate = Math.min(120, Math.max(10, framerate));
Option.videoFramerate.setValue(Math.min(120, Math.max(10, framerate)));
rewriteSettings();
}
public float getVideoQuality() {
return videoQuality;
return (Float)Option.videoQuality.getValue();
}
public void setVideoQuality(float videoQuality) {
this.videoQuality = Math.min(0.9f, Math.max(0.1f, videoQuality));
Option.videoQuality.setValue(Math.min(0.9f, Math.max(0.1f, videoQuality)));
rewriteSettings();
}
public boolean isEnableRecordingServer() {
return enableRecordingServer;
return (Boolean)Option.recordServer.getValue();
}
public void setEnableRecordingServer(boolean enableRecordingServer) {
this.enableRecordingServer = enableRecordingServer;
Option.recordServer.setValue(enableRecordingServer);
rewriteSettings();
}
public boolean isEnableRecordingSingleplayer() {
return enableRecordingSingleplayer;
return (Boolean)Option.recordSingleplayer.getValue();
}
public void setEnableRecordingSingleplayer(boolean enableRecordingSingleplayer) {
this.enableRecordingSingleplayer = enableRecordingSingleplayer;
Option.recordSingleplayer.setValue(enableRecordingSingleplayer);
rewriteSettings();
}
public boolean isShowNotifications() {
return showNotifications;
return (Boolean)Option.notifications.getValue();
}
public void setShowNotifications(boolean showNotifications) {
this.showNotifications = showNotifications;
Option.notifications.setValue(showNotifications);
rewriteSettings();
}
public boolean isLinearMovement() {
return forceLinearPath;
return (Boolean)Option.linear.getValue();
}
public void setLinearMovement(boolean linear) {
this.forceLinearPath = linear;
Option.linear.setValue(linear);
rewriteSettings();
}
public boolean isLightingEnabled() {
return lightingEnabled;
return (Boolean)Option.lighting.getValue();
}
public void setUseResourcePacks(boolean use) {
Option.useResources.setValue(use);
rewriteSettings();
}
public boolean getUseResourcePacks() {
return (Boolean)Option.useResources.getValue();
}
//TODO: FIX
public void setLightingEnabled(boolean enabled) {
this.lightingEnabled = enabled;
Option.lighting.setValue(enabled);
if(enabled) {
Minecraft.getMinecraft().gameSettings.setOptionFloatValue(Options.GAMMA, 1000);
} else {
@@ -115,52 +129,28 @@ public class ReplaySettings {
rewriteSettings();
}
public Map<String, Object> getOptions() {
Map<String, Object> map = new LinkedHashMap<String, Object>();
map.put("Enable Notifications", showNotifications);
map.put("Record Server", enableRecordingServer);
map.put("Record Singleplayer", enableRecordingSingleplayer);
map.put("Placeholder 1", null);
map.put("Force Linear Movement", forceLinearPath);
map.put("Enable Lighting", lightingEnabled);
map.put("Video Quality", videoQuality);
map.put("Video Framerate", videoFramerate);
return map;
}
public void setOptions(Map<String, Object> map) {
try {
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");
videoQuality = (Float)map.get("Video Quality");
videoFramerate = (Integer)map.get("Video Framerate");
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 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.");
Property vq = ReplayMod.instance.config.get("settings", "videoQuality", videoQuality, "The quality of the exported video files from 0.1 to 0.9");
Property framerate = ReplayMod.instance.config.get("settings", "videoFramerate", videoFramerate, "The framerate of the exported video files from 10 to 120");
for(Option o : Option.values()) {
addConfigSetting(ReplayMod.instance.config, o);
}
ReplayMod.instance.config.save();
}
private void addConfigSetting(Configuration config, Option o) {
Object value = o.getValue();
if(value instanceof Integer) {
config.get("settings", o.name(), (Integer)o.getValue());
} else if(value instanceof Boolean) {
config.get("settings", o.name(), (Boolean)o.getValue());
} else if(value instanceof Double) {
config.get("settings", o.name(), (Double)o.getValue());
} else if(value instanceof String) {
config.get("settings", o.name(), (String)o.getValue());
}
}
}