Compare commits
11 Commits
1.9.4-2.0.
...
1.9.4-2.0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5100f36b2c | ||
|
|
7ef6a6d166 | ||
|
|
c93a3e384c | ||
|
|
8bb5d11cb4 | ||
|
|
f3142a714c | ||
|
|
3abaa1bcbb | ||
|
|
4b47f2cbf8 | ||
|
|
446b9be384 | ||
|
|
ada460c384 | ||
|
|
ad62060368 | ||
|
|
82246a5f48 |
Submodule ReplayStudio updated: ebdef6fc1b...99955dd564
2
jGui
2
jGui
Submodule jGui updated: f7270bb5f9...87f7f27009
@@ -122,6 +122,22 @@ public class ReplayMod {
|
|||||||
testIfMoeshAndExitMinecraft();
|
testIfMoeshAndExitMinecraft();
|
||||||
|
|
||||||
runLater(() -> {
|
runLater(() -> {
|
||||||
|
// Cleanup deleted corrupted replays
|
||||||
|
try {
|
||||||
|
File[] files = getReplayFolder().listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
for (File file : files) {
|
||||||
|
if (file.isDirectory() && file.getName().endsWith(".mcpr.del")) {
|
||||||
|
if (file.lastModified() + 2 * 24 * 60 * 60 * 1000 < System.currentTimeMillis()) {
|
||||||
|
FileUtils.deleteDirectory(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
// Restore corrupted replays
|
// Restore corrupted replays
|
||||||
try {
|
try {
|
||||||
File[] files = getReplayFolder().listFiles();
|
File[] files = getReplayFolder().listFiles();
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ public abstract class AbstractTimelinePlayer {
|
|||||||
public void onTick(ReplayTimer.UpdatedEvent event) {
|
public void onTick(ReplayTimer.UpdatedEvent event) {
|
||||||
if (future.isDone()) {
|
if (future.isDone()) {
|
||||||
mc.timer = ((ReplayTimer) mc.timer).getWrapped();
|
mc.timer = ((ReplayTimer) mc.timer).getWrapped();
|
||||||
|
replayHandler.getReplaySender().setReplaySpeed(0);
|
||||||
replayHandler.getReplaySender().setAsyncMode(true);
|
replayHandler.getReplaySender().setAsyncMode(true);
|
||||||
MinecraftForge.EVENT_BUS.unregister(this);
|
MinecraftForge.EVENT_BUS.unregister(this);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import net.minecraft.network.datasync.EntityDataManager;
|
|||||||
import net.minecraft.network.play.server.*;
|
import net.minecraft.network.play.server.*;
|
||||||
import net.minecraft.server.integrated.IntegratedServer;
|
import net.minecraft.server.integrated.IntegratedServer;
|
||||||
import net.minecraft.util.EnumHand;
|
import net.minecraft.util.EnumHand;
|
||||||
|
import net.minecraft.util.SoundCategory;
|
||||||
|
import net.minecraft.util.SoundEvent;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.event.entity.minecart.MinecartInteractEvent;
|
import net.minecraftforge.event.entity.minecart.MinecartInteractEvent;
|
||||||
@@ -69,6 +71,25 @@ public class RecordingEventHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onClientSound(SoundEvent sound, SoundCategory category,
|
||||||
|
double x, double y, double z, float volume, float pitch) {
|
||||||
|
try {
|
||||||
|
// Send to all other players in ServerWorldEventHandler#playSoundToAllNearExcept
|
||||||
|
packetListener.save(new SPacketSoundEffect(sound, category, x, y, z, volume, pitch));
|
||||||
|
} catch(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onClientEffect(int type, BlockPos pos, int data) {
|
||||||
|
try {
|
||||||
|
// Send to all other players in ServerWorldEventHandler#playEvent
|
||||||
|
packetListener.save(new SPacketEffect(type, pos, data, false));
|
||||||
|
} catch(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void onPlayerTick(PlayerTickEvent e) {
|
public void onPlayerTick(PlayerTickEvent e) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.replaymod.recording.mixin;
|
||||||
|
|
||||||
|
import com.replaymod.recording.handler.RecordingEventHandler;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.multiplayer.PlayerControllerMP;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
@Mixin(PlayerControllerMP.class)
|
||||||
|
public abstract class MixinPlayerControllerMP implements RecordingEventHandler.RecordingEventSender {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
private Minecraft mc;
|
||||||
|
|
||||||
|
// Redirects the call to playEvent without the initial player argument to the method with that argument
|
||||||
|
// The new method will then play it and (if applicable) record it. (See MixinWorldClient)
|
||||||
|
// This is necessary for the block break event (particles and sound) to be recorded. Otherwise it looks like the
|
||||||
|
// event was emitted because of a packet (player will be null) and not as it actually was (by the player).
|
||||||
|
@Redirect(method = "onPlayerDestroyBlock", at = @At(value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/world/World;playEvent(ILnet/minecraft/util/math/BlockPos;I)V"))
|
||||||
|
public void replayModRecording_playEvent_fixed(World world, int type, BlockPos pos, int data) {
|
||||||
|
world.playEvent(mc.thePlayer, type, pos, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package com.replaymod.recording.mixin;
|
||||||
|
|
||||||
|
import com.replaymod.recording.handler.RecordingEventHandler;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.multiplayer.WorldClient;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.profiler.Profiler;
|
||||||
|
import net.minecraft.util.SoundCategory;
|
||||||
|
import net.minecraft.util.SoundEvent;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldProvider;
|
||||||
|
import net.minecraft.world.storage.ISaveHandler;
|
||||||
|
import net.minecraft.world.storage.WorldInfo;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(WorldClient.class)
|
||||||
|
public abstract class MixinWorldClient extends World implements RecordingEventHandler.RecordingEventSender {
|
||||||
|
@Shadow
|
||||||
|
private Minecraft mc;
|
||||||
|
|
||||||
|
protected MixinWorldClient(ISaveHandler saveHandlerIn, WorldInfo info, WorldProvider providerIn, Profiler profilerIn, boolean client) {
|
||||||
|
super(saveHandlerIn, info, providerIn, profilerIn, client);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RecordingEventHandler replayModRecording_getRecordingEventHandler() {
|
||||||
|
return ((RecordingEventHandler.RecordingEventSender) mc.renderGlobal).getRecordingEventHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sounds that are emitted by thePlayer no longer take the long way over the server
|
||||||
|
// but are instead played directly by the client. The server only sends these sounds to
|
||||||
|
// other clients so we have to record them manually.
|
||||||
|
// E.g. Block place sounds
|
||||||
|
@Inject(method = "playSound", at = @At("HEAD"))
|
||||||
|
public void replayModRecording_recordClientSound(EntityPlayer player, double x, double y, double z, SoundEvent sound, SoundCategory category,
|
||||||
|
float volume, float pitch, CallbackInfo ci) {
|
||||||
|
if (player == mc.thePlayer) {
|
||||||
|
RecordingEventHandler handler = replayModRecording_getRecordingEventHandler();
|
||||||
|
if (handler != null) {
|
||||||
|
handler.onClientSound(sound, category, x, y, z, volume, pitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same goes for level events (also called effects). E.g. door open, block break, etc.
|
||||||
|
// These are handled in the World class, so we override the method in WorldClient and add our special handling.
|
||||||
|
@Override
|
||||||
|
public void playEvent(EntityPlayer player, int type, BlockPos pos, int data) {
|
||||||
|
if (player == mc.thePlayer) {
|
||||||
|
// We caused this event, the server won't send it to us
|
||||||
|
RecordingEventHandler handler = replayModRecording_getRecordingEventHandler();
|
||||||
|
if (handler != null) {
|
||||||
|
handler.onClientEffect(type, pos, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.playEvent(player, type, pos, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -186,7 +186,7 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
|
|||||||
// Closing this GUI ensures that settings are saved
|
// Closing this GUI ensures that settings are saved
|
||||||
getMinecraft().displayGuiScreen(null);
|
getMinecraft().displayGuiScreen(null);
|
||||||
try {
|
try {
|
||||||
VideoRenderer videoRenderer = new VideoRenderer(save(true), replayHandler, timeline);
|
VideoRenderer videoRenderer = new VideoRenderer(save(false), replayHandler, timeline);
|
||||||
videoRenderer.renderVideo();
|
videoRenderer.renderVideo();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -378,7 +378,7 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
|
|||||||
updateInputs();
|
updateInputs();
|
||||||
}
|
}
|
||||||
|
|
||||||
public RenderSettings save(boolean saveOutputFile) {
|
public RenderSettings save(boolean serialize) {
|
||||||
return new RenderSettings(
|
return new RenderSettings(
|
||||||
renderMethodDropdown.getSelectedValue(),
|
renderMethodDropdown.getSelectedValue(),
|
||||||
encodingPresetDropdown.getSelectedValue(),
|
encodingPresetDropdown.getSelectedValue(),
|
||||||
@@ -386,13 +386,13 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
|
|||||||
videoHeight.getInteger(),
|
videoHeight.getInteger(),
|
||||||
frameRateSlider.getValue() + 10,
|
frameRateSlider.getValue() + 10,
|
||||||
bitRateField.getInteger() << (10 * bitRateUnit.getSelected()),
|
bitRateField.getInteger() << (10 * bitRateUnit.getSelected()),
|
||||||
saveOutputFile ? outputFile : null,
|
serialize ? null : outputFile,
|
||||||
nametagCheckbox.isChecked(),
|
nametagCheckbox.isChecked(),
|
||||||
stabilizeYaw.isChecked(),
|
stabilizeYaw.isChecked() && (serialize || stabilizeYaw.isEnabled()),
|
||||||
stabilizePitch.isChecked(),
|
stabilizePitch.isChecked() && (serialize || stabilizePitch.isEnabled()),
|
||||||
stabilizeRoll.isChecked(),
|
stabilizeRoll.isChecked() && (serialize || stabilizeRoll.isEnabled()),
|
||||||
chromaKeyingCheckbox.isChecked() ? chromaKeyingColor.getColor() : null,
|
chromaKeyingCheckbox.isChecked() ? chromaKeyingColor.getColor() : null,
|
||||||
inject360Metadata.isChecked(),
|
inject360Metadata.isChecked() && (serialize || inject360Metadata.isEnabled()),
|
||||||
exportCommand.getText(),
|
exportCommand.getText(),
|
||||||
exportArguments.getText(),
|
exportArguments.getText(),
|
||||||
net.minecraft.client.gui.GuiScreen.isCtrlKeyDown()
|
net.minecraft.client.gui.GuiScreen.isCtrlKeyDown()
|
||||||
@@ -412,7 +412,7 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
RenderSettings settings = save(false);
|
RenderSettings settings = save(true);
|
||||||
String json = new Gson().toJson(settings);
|
String json = new Gson().toJson(settings);
|
||||||
Configuration config = ReplayModRender.instance.getConfiguration();
|
Configuration config = ReplayModRender.instance.getConfiguration();
|
||||||
getConfigProperty(config).set(json);
|
getConfigProperty(config).set(json);
|
||||||
|
|||||||
@@ -6,7 +6,12 @@ import com.google.common.util.concurrent.FutureCallback;
|
|||||||
import com.google.common.util.concurrent.Futures;
|
import com.google.common.util.concurrent.Futures;
|
||||||
import com.mojang.realmsclient.gui.ChatFormatting;
|
import com.mojang.realmsclient.gui.ChatFormatting;
|
||||||
import com.replaymod.core.gui.GuiReplaySettings;
|
import com.replaymod.core.gui.GuiReplaySettings;
|
||||||
|
import com.replaymod.core.utils.Utils;
|
||||||
import com.replaymod.replay.ReplayModReplay;
|
import com.replaymod.replay.ReplayModReplay;
|
||||||
|
import com.replaymod.replaystudio.replay.ReplayFile;
|
||||||
|
import com.replaymod.replaystudio.replay.ReplayMetaData;
|
||||||
|
import com.replaymod.replaystudio.replay.ZipReplayFile;
|
||||||
|
import com.replaymod.replaystudio.studio.ReplayStudio;
|
||||||
import de.johni0702.minecraft.gui.container.AbstractGuiContainer;
|
import de.johni0702.minecraft.gui.container.AbstractGuiContainer;
|
||||||
import de.johni0702.minecraft.gui.container.GuiContainer;
|
import de.johni0702.minecraft.gui.container.GuiContainer;
|
||||||
import de.johni0702.minecraft.gui.container.GuiPanel;
|
import de.johni0702.minecraft.gui.container.GuiPanel;
|
||||||
@@ -20,11 +25,6 @@ import de.johni0702.minecraft.gui.layout.VerticalLayout;
|
|||||||
import de.johni0702.minecraft.gui.popup.GuiYesNoPopup;
|
import de.johni0702.minecraft.gui.popup.GuiYesNoPopup;
|
||||||
import de.johni0702.minecraft.gui.utils.Colors;
|
import de.johni0702.minecraft.gui.utils.Colors;
|
||||||
import de.johni0702.minecraft.gui.utils.Consumer;
|
import de.johni0702.minecraft.gui.utils.Consumer;
|
||||||
import com.replaymod.replaystudio.replay.ReplayFile;
|
|
||||||
import com.replaymod.replaystudio.replay.ReplayMetaData;
|
|
||||||
import com.replaymod.replaystudio.replay.ZipReplayFile;
|
|
||||||
import com.replaymod.replaystudio.studio.ReplayStudio;
|
|
||||||
import com.replaymod.core.utils.Utils;
|
|
||||||
import net.minecraft.client.gui.GuiErrorScreen;
|
import net.minecraft.client.gui.GuiErrorScreen;
|
||||||
import net.minecraft.client.resources.I18n;
|
import net.minecraft.client.resources.I18n;
|
||||||
import net.minecraft.util.Util;
|
import net.minecraft.util.Util;
|
||||||
@@ -54,6 +54,9 @@ public class GuiReplayViewer extends GuiScreen {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
replayButtonPanel.forEach(IGuiButton.class).setEnabled(list.getSelected() != null);
|
replayButtonPanel.forEach(IGuiButton.class).setEnabled(list.getSelected() != null);
|
||||||
|
if (list.getSelected() != null && list.getSelected().incompatible) {
|
||||||
|
loadButton.setDisabled();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}).onLoad(new Consumer<Consumer<Supplier<GuiReplayEntry>>> () {
|
}).onLoad(new Consumer<Consumer<Supplier<GuiReplayEntry>>> () {
|
||||||
@Override
|
@Override
|
||||||
@@ -95,6 +98,10 @@ public class GuiReplayViewer extends GuiScreen {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}).onSelectionDoubleClicked(() -> {
|
||||||
|
if (this.loadButton.isEnabled()) {
|
||||||
|
this.loadButton.onClick();
|
||||||
|
}
|
||||||
}).setDrawShadow(true).setDrawSlider(true);
|
}).setDrawShadow(true).setDrawSlider(true);
|
||||||
|
|
||||||
public final GuiButton loadButton = new GuiButton().onClick(new Runnable() {
|
public final GuiButton loadButton = new GuiButton().onClick(new Runnable() {
|
||||||
@@ -270,6 +277,7 @@ public class GuiReplayViewer extends GuiScreen {
|
|||||||
public final GuiLabel date = new GuiLabel().setColor(Colors.LIGHT_GRAY);
|
public final GuiLabel date = new GuiLabel().setColor(Colors.LIGHT_GRAY);
|
||||||
public final GuiPanel infoPanel = new GuiPanel(this).setLayout(new VerticalLayout().setSpacing(2))
|
public final GuiPanel infoPanel = new GuiPanel(this).setLayout(new VerticalLayout().setSpacing(2))
|
||||||
.addElements(null, name, server, date);
|
.addElements(null, name, server, date);
|
||||||
|
public final GuiLabel version = new GuiLabel(this).setColor(Colors.RED);
|
||||||
public final GuiImage thumbnail;
|
public final GuiImage thumbnail;
|
||||||
public final GuiLabel duration = new GuiLabel();
|
public final GuiLabel duration = new GuiLabel();
|
||||||
public final GuiPanel durationPanel = new GuiPanel().setBackgroundColor(Colors.HALF_TRANSPARENT)
|
public final GuiPanel durationPanel = new GuiPanel().setBackgroundColor(Colors.HALF_TRANSPARENT)
|
||||||
@@ -287,6 +295,7 @@ public class GuiReplayViewer extends GuiScreen {
|
|||||||
});
|
});
|
||||||
|
|
||||||
private final long dateMillis;
|
private final long dateMillis;
|
||||||
|
private final boolean incompatible;
|
||||||
|
|
||||||
public GuiReplayEntry(File file, ReplayMetaData metaData, BufferedImage thumbImage) {
|
public GuiReplayEntry(File file, ReplayMetaData metaData, BufferedImage thumbImage) {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
@@ -297,6 +306,10 @@ public class GuiReplayViewer extends GuiScreen {
|
|||||||
} else {
|
} else {
|
||||||
server.setText(metaData.getServerName());
|
server.setText(metaData.getServerName());
|
||||||
}
|
}
|
||||||
|
incompatible = !new ReplayStudio().isCompatible(metaData.getFileFormatVersion());
|
||||||
|
if (incompatible) {
|
||||||
|
version.setText("Minecraft " + metaData.getMcVersion());
|
||||||
|
}
|
||||||
dateMillis = metaData.getDate();
|
dateMillis = metaData.getDate();
|
||||||
date.setText(new SimpleDateFormat().format(new Date(dateMillis)));
|
date.setText(new SimpleDateFormat().format(new Date(dateMillis)));
|
||||||
if (thumbImage == null) {
|
if (thumbImage == null) {
|
||||||
@@ -316,6 +329,7 @@ public class GuiReplayViewer extends GuiScreen {
|
|||||||
y(durationPanel, height(thumbnail) - height(durationPanel));
|
y(durationPanel, height(thumbnail) - height(durationPanel));
|
||||||
|
|
||||||
pos(infoPanel, width(thumbnail) + 5, 0);
|
pos(infoPanel, width(thumbnail) + 5, 0);
|
||||||
|
pos(version, width - width(version), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -84,6 +84,9 @@ public class ReplayModSimplePathing implements PathingRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setCurrentTimeline(Timeline currentTimeline) {
|
public void setCurrentTimeline(Timeline currentTimeline) {
|
||||||
|
if (this.currentTimeline != currentTimeline) {
|
||||||
|
selectedKeyframe = null;
|
||||||
|
}
|
||||||
this.currentTimeline = currentTimeline;
|
this.currentTimeline = currentTimeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -208,6 +208,7 @@ public class GuiKeyframeTimeline extends AbstractGuiTimeline<GuiKeyframeTimeline
|
|||||||
// Clicked on timeline but not on any keyframe
|
// Clicked on timeline but not on any keyframe
|
||||||
if (button == 0) { // Left click
|
if (button == 0) { // Left click
|
||||||
setCursorPosition(time);
|
setCursorPosition(time);
|
||||||
|
gui.getMod().setSelectedKeyframe(null);
|
||||||
} else if (button == 1) { // Right click
|
} else if (button == 1) { // Right click
|
||||||
if (pathKeyframePair.getLeft() != null) {
|
if (pathKeyframePair.getLeft() != null) {
|
||||||
// Apply the value of the clicked path at the clicked position
|
// Apply the value of the clicked path at the clicked position
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
"server": [],
|
"server": [],
|
||||||
"client": [
|
"client": [
|
||||||
"MixinNetHandlerPlayClient",
|
"MixinNetHandlerPlayClient",
|
||||||
"MixinRenderGlobal"
|
"MixinPlayerControllerMP",
|
||||||
|
"MixinRenderGlobal",
|
||||||
|
"MixinWorldClient"
|
||||||
],
|
],
|
||||||
"compatibilityLevel": "JAVA_8",
|
"compatibilityLevel": "JAVA_8",
|
||||||
"refmap": "mixins.replaymod.refmap.json"
|
"refmap": "mixins.replaymod.refmap.json"
|
||||||
|
|||||||
Reference in New Issue
Block a user