diff --git a/docs/content.md b/docs/content.md index 4bf0a01e..14e7ef52 100755 --- a/docs/content.md +++ b/docs/content.md @@ -20,7 +20,7 @@ After installing Forge, simply put the downloaded `ReplayMod.jar` file in the `/ To render your creations with **Replay Mod** you will need to have FFmpeg installed. ### Windows [windows] -Download the **latest** FFmpeg build from . +Download the **latest** FFmpeg build from (the essentials version is sufficient). Extract the downloaded .zip file into your `.minecraft` folder. diff --git a/jGui b/jGui index 9c7bf29f..5e515a2e 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 9c7bf29f7785e10b494bf9cd0459acc62292c38d +Subproject commit 5e515a2ecc4d1faa02aeafd48f366a08ab183e46 diff --git a/src/main/java/com/replaymod/core/utils/Utils.java b/src/main/java/com/replaymod/core/utils/Utils.java index 81448cb5..f15ec91f 100644 --- a/src/main/java/com/replaymod/core/utils/Utils.java +++ b/src/main/java/com/replaymod/core/utils/Utils.java @@ -66,6 +66,7 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.text.SimpleDateFormat; import java.util.Arrays; +import java.util.Comparator; import java.util.Date; import java.util.UUID; import java.util.function.Consumer; @@ -350,6 +351,10 @@ public class Utils { super(container); setBackgroundColor(Colors.DARK_TRANSPARENT); + ProtocolVersion latestVersion = ProtocolVersion.getProtocols() + .stream() + .max(Comparator.comparing(ProtocolVersion::getId)) + .orElseThrow(RuntimeException::new); getInfo().addElements(new VerticalLayout.Data(0.5), new GuiLabel() .setColor(Colors.BLACK) @@ -357,10 +362,7 @@ public class Utils { new GuiLabel() .setColor(Colors.BLACK) .setI18nText("replaymod.gui.minimalmode.supportedversion", - ProtocolVersion.v1_7_6.getName() - + " - " - + Iterables.getLast(ProtocolVersion.getProtocols()).getName() - )); + "1.7.10 - " + latestVersion.getName())); open(); } diff --git a/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java b/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java index 377e9c14..b9d560c6 100644 --- a/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java +++ b/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java @@ -127,6 +127,9 @@ public class MarkerProcessor { List> outputPaths = new ArrayList<>(); Path inputPath = path.resolveSibling("raw").resolve(path.getFileName()); + for (int i = 1; Files.exists(inputPath); i++) { + inputPath = inputPath.resolveSibling(replayName + "." + i + ".mcpr"); + } Files.createDirectories(inputPath.getParent()); Files.move(path, inputPath); diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java b/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java index be3f43f3..5e831ebb 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java @@ -97,6 +97,7 @@ public class GuiCreateScreenshot extends GuiRenderSettings implements Loadable { protected File generateOutputFile(RenderSettings.EncodingPreset encodingPreset) { DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss"); File screenshotFolder = new File(getMinecraft().runDirectory, "screenshots"); + screenshotFolder.mkdirs(); String baseName = DATE_FORMAT.format(new Date()); for (int i = 1; ; i++) { File screenshotFile = new File(screenshotFolder, baseName + (i == 1 ? "" : "_" + i) + ".png"); @@ -106,6 +107,11 @@ public class GuiCreateScreenshot extends GuiRenderSettings implements Loadable { } } + @Override + public void load(RenderSettings settings) { + super.load(settings.withEncodingPreset(RenderSettings.EncodingPreset.PNG)); + } + @Override protected Path getSettingsPath() { return getMinecraft().runDirectory.toPath().resolve("config/replaymod-screenshotsettings.json"); diff --git a/src/main/java/com/replaymod/render/RenderSettings.java b/src/main/java/com/replaymod/render/RenderSettings.java index 94538026..3b057e91 100644 --- a/src/main/java/com/replaymod/render/RenderSettings.java +++ b/src/main/java/com/replaymod/render/RenderSettings.java @@ -212,6 +212,30 @@ public class RenderSettings { this.highPerformance = highPerformance; } + public RenderSettings withEncodingPreset(EncodingPreset encodingPreset) { + return new RenderSettings( + renderMethod, + encodingPreset, + videoWidth, + videoHeight, + framesPerSecond, + bitRate, + outputFile, + renderNameTags, + stabilizeYaw, + stabilizePitch, + stabilizeRoll, + chromaKeyingColor, + sphericalFovX, + sphericalFovY, + injectSphericalMetadata, + antiAliasing, + exportCommand, + exportArguments, + highPerformance + ); + } + /** * @return the width of the output video during rendering, including the upscale for Anti-Aliasing. */ diff --git a/src/main/java/com/replaymod/render/capturer/OpenGlFrameCapturer.java b/src/main/java/com/replaymod/render/capturer/OpenGlFrameCapturer.java index 496b65d8..9f296caf 100644 --- a/src/main/java/com/replaymod/render/capturer/OpenGlFrameCapturer.java +++ b/src/main/java/com/replaymod/render/capturer/OpenGlFrameCapturer.java @@ -141,6 +141,5 @@ public abstract class OpenGlFrameCapturer implements Runnable { + private final WorldRenderer worldRenderer; private final FrameCapturer capturer; private final FrameProcessor processor; private int consumerNextFrame; @@ -31,7 +33,8 @@ public class Pipeline implements Runnable { private volatile boolean abort; - public Pipeline(FrameCapturer capturer, FrameProcessor processor, FrameConsumer

consumer) { + public Pipeline(WorldRenderer worldRenderer, FrameCapturer capturer, FrameProcessor processor, FrameConsumer

consumer) { + this.worldRenderer = worldRenderer; this.capturer = capturer; this.processor = processor; this.consumer = consumer; @@ -81,6 +84,7 @@ public class Pipeline implements Runnable { } try { + worldRenderer.close(); capturer.close(); processor.close(); consumer.close(); diff --git a/src/main/java/com/replaymod/render/rendering/Pipelines.java b/src/main/java/com/replaymod/render/rendering/Pipelines.java index 51437bfb..51c4a2a8 100644 --- a/src/main/java/com/replaymod/render/rendering/Pipelines.java +++ b/src/main/java/com/replaymod/render/rendering/Pipelines.java @@ -10,6 +10,7 @@ import com.replaymod.render.capturer.SimpleOpenGlFrameCapturer; import com.replaymod.render.capturer.SimplePboOpenGlFrameCapturer; import com.replaymod.render.capturer.StereoscopicOpenGlFrameCapturer; import com.replaymod.render.capturer.StereoscopicPboOpenGlFrameCapturer; +import com.replaymod.render.capturer.WorldRenderer; import com.replaymod.render.frame.CubicOpenGlFrame; import com.replaymod.render.frame.ODSOpenGlFrame; import com.replaymod.render.frame.OpenGlFrame; @@ -45,66 +46,72 @@ public class Pipelines { public static Pipeline newDefaultPipeline(RenderInfo renderInfo, FrameConsumer consumer) { RenderSettings settings = renderInfo.getRenderSettings(); + WorldRenderer worldRenderer = new EntityRendererHandler(settings, renderInfo); FrameCapturer capturer; if (PixelBufferObject.SUPPORTED) { - capturer = new SimplePboOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo); + capturer = new SimplePboOpenGlFrameCapturer(worldRenderer, renderInfo); } else { - capturer = new SimpleOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo); + capturer = new SimpleOpenGlFrameCapturer(worldRenderer, renderInfo); } - return new Pipeline<>(capturer, new OpenGlToRGBProcessor(), consumer); + return new Pipeline<>(worldRenderer, capturer, new OpenGlToRGBProcessor(), consumer); } public static Pipeline newStereoscopicPipeline(RenderInfo renderInfo, FrameConsumer consumer) { RenderSettings settings = renderInfo.getRenderSettings(); + WorldRenderer worldRenderer = new EntityRendererHandler(settings, renderInfo); FrameCapturer capturer; if (PixelBufferObject.SUPPORTED) { - capturer = new StereoscopicPboOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo); + capturer = new StereoscopicPboOpenGlFrameCapturer(worldRenderer, renderInfo); } else { - capturer = new StereoscopicOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo); + capturer = new StereoscopicOpenGlFrameCapturer(worldRenderer, renderInfo); } - return new Pipeline<>(capturer, new StereoscopicToRGBProcessor(), consumer); + return new Pipeline<>(worldRenderer, capturer, new StereoscopicToRGBProcessor(), consumer); } public static Pipeline newCubicPipeline(RenderInfo renderInfo, FrameConsumer consumer) { RenderSettings settings = renderInfo.getRenderSettings(); + WorldRenderer worldRenderer = new EntityRendererHandler(settings, renderInfo); FrameCapturer capturer; if (PixelBufferObject.SUPPORTED) { - capturer = new CubicPboOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo, settings.getVideoWidth() / 4); + capturer = new CubicPboOpenGlFrameCapturer(worldRenderer, renderInfo, settings.getVideoWidth() / 4); } else { - capturer = new CubicOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo, settings.getVideoWidth() / 4); + capturer = new CubicOpenGlFrameCapturer(worldRenderer, renderInfo, settings.getVideoWidth() / 4); } - return new Pipeline<>(capturer, new CubicToRGBProcessor(), consumer); + return new Pipeline<>(worldRenderer, capturer, new CubicToRGBProcessor(), consumer); } public static Pipeline newEquirectangularPipeline(RenderInfo renderInfo, FrameConsumer consumer) { RenderSettings settings = renderInfo.getRenderSettings(); + WorldRenderer worldRenderer = new EntityRendererHandler(settings, renderInfo); EquirectangularToRGBProcessor processor = new EquirectangularToRGBProcessor(settings.getVideoWidth(), settings.getVideoHeight(), settings.getSphericalFovX()); FrameCapturer capturer; if (PixelBufferObject.SUPPORTED) { - capturer = new CubicPboOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo, processor.getFrameSize()); + capturer = new CubicPboOpenGlFrameCapturer(worldRenderer, renderInfo, processor.getFrameSize()); } else { - capturer = new CubicOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo, processor.getFrameSize()); + capturer = new CubicOpenGlFrameCapturer(worldRenderer, renderInfo, processor.getFrameSize()); } - return new Pipeline<>(capturer, processor, consumer); + return new Pipeline<>(worldRenderer, capturer, processor, consumer); } public static Pipeline newODSPipeline(RenderInfo renderInfo, FrameConsumer consumer) { RenderSettings settings = renderInfo.getRenderSettings(); + WorldRenderer worldRenderer = new EntityRendererHandler(settings, renderInfo); ODSToRGBProcessor processor = new ODSToRGBProcessor(settings.getVideoWidth(), settings.getVideoHeight(), settings.getSphericalFovX()); FrameCapturer capturer = - new ODSFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo, processor.getFrameSize()); - return new Pipeline<>(capturer, processor, consumer); + new ODSFrameCapturer(worldRenderer, renderInfo, processor.getFrameSize()); + return new Pipeline<>(worldRenderer, capturer, processor, consumer); } public static Pipeline newBlendPipeline(RenderInfo renderInfo) { RenderSettings settings = renderInfo.getRenderSettings(); - FrameCapturer capturer = new BlendFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo); + WorldRenderer worldRenderer = new EntityRendererHandler(settings, renderInfo); + FrameCapturer capturer = new BlendFrameCapturer(worldRenderer, renderInfo); FrameConsumer consumer = new FrameConsumer() { @Override public void consume(RGBFrame frame) { @@ -114,6 +121,6 @@ public class Pipelines { public void close() { } }; - return new Pipeline<>(capturer, new DummyProcessor<>(), consumer); + return new Pipeline<>(worldRenderer, capturer, new DummyProcessor<>(), consumer); } } diff --git a/src/main/java/com/replaymod/replay/FullReplaySender.java b/src/main/java/com/replaymod/replay/FullReplaySender.java index 953cf7f2..c5ee6517 100644 --- a/src/main/java/com/replaymod/replay/FullReplaySender.java +++ b/src/main/java/com/replaymod/replay/FullReplaySender.java @@ -729,10 +729,12 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend final PlayerPositionLookS2CPacket ppl = (PlayerPositionLookS2CPacket) p; if(!hasWorldLoaded) hasWorldLoaded = true; - if (mc.currentScreen instanceof DownloadingTerrainScreen) { - // Close the world loading screen manually in case we swallow the packet - mc.openScreen(null); - } + ReplayMod.instance.runLater(() -> { + if (mc.currentScreen instanceof DownloadingTerrainScreen) { + // Close the world loading screen manually in case we swallow the packet + mc.openScreen(null); + } + }); if(replayHandler.shouldSuppressCameraMovements()) return null; diff --git a/src/main/java/com/replaymod/replay/ReplayHandler.java b/src/main/java/com/replaymod/replay/ReplayHandler.java index 3cec022f..d20a7f41 100644 --- a/src/main/java/com/replaymod/replay/ReplayHandler.java +++ b/src/main/java/com/replaymod/replay/ReplayHandler.java @@ -519,10 +519,6 @@ public class ReplayHandler { return spectating; } - public void setTargetPosition(Location pos) { - targetCameraPosition = pos; - } - public void moveCameraToTargetPosition() { CameraEntity cam = getCameraEntity(); if (cam != null && targetCameraPosition != null) { @@ -592,7 +588,7 @@ public class ReplayHandler { } } - long diff = targetTime - replaySender.getDesiredTimestamp(); + long diff = targetTime - (replaySender.isHurrying() ? replaySender.getDesiredTimestamp() : replaySender.currentTimeStamp()); if (diff != 0) { if (diff > 0 && diff < 5000) { // Small difference and no time travel replaySender.jumpToTime(targetTime); diff --git a/src/main/java/com/replaymod/replay/camera/CameraEntity.java b/src/main/java/com/replaymod/replay/camera/CameraEntity.java index c6a298f2..d8b999b8 100644 --- a/src/main/java/com/replaymod/replay/camera/CameraEntity.java +++ b/src/main/java/com/replaymod/replay/camera/CameraEntity.java @@ -74,11 +74,13 @@ import net.minecraft.util.Hand; //#if MC>=10800 import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.client.render.entity.PlayerModelPart; //#else //$$ import net.minecraft.client.entity.EntityClientPlayerMP; //$$ import net.minecraft.util.Session; //#endif +import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.UUID; import java.util.function.Function; @@ -98,6 +100,8 @@ public class CameraEntity //$$ extends EntityClientPlayerMP //#endif { + private static final UUID CAMERA_UUID = UUID.nameUUIDFromBytes("ReplayModCamera".getBytes(StandardCharsets.UTF_8)); + /** * Roll of this camera in degrees. */ @@ -154,6 +158,11 @@ public class CameraEntity , false //#endif ); + //#if MC>=10900 + setUuid(CAMERA_UUID); + //#else + //$$ entityUniqueID = CAMERA_UUID; + //#endif eventHandler.register(); if (ReplayModReplay.instance.getReplayHandler().getSpectatedUUID() == null) { cameraController = ReplayModReplay.instance.createCameraController(this); @@ -423,6 +432,15 @@ public class CameraEntity } return super.getModel(); } + + @Override + public boolean isPartVisible(PlayerModelPart modelPart) { + Entity view = getRenderViewEntity(this.client); + if (view != this && view instanceof PlayerEntity) { + return ((PlayerEntity) view).isPartVisible(modelPart); + } + return super.isPartVisible(modelPart); + } //#endif @Override diff --git a/src/main/java/com/replaymod/replay/gui/overlay/GuiMarkerTimeline.java b/src/main/java/com/replaymod/replay/gui/overlay/GuiMarkerTimeline.java index d312d670..f1c140b4 100644 --- a/src/main/java/com/replaymod/replay/gui/overlay/GuiMarkerTimeline.java +++ b/src/main/java/com/replaymod/replay/gui/overlay/GuiMarkerTimeline.java @@ -4,6 +4,7 @@ import com.replaymod.core.ReplayMod; import com.replaymod.core.versions.MCVer.Keyboard; import com.replaymod.replay.ReplayHandler; import com.replaymod.replay.ReplayModReplay; +import com.replaymod.replay.camera.CameraEntity; import com.replaymod.replaystudio.data.Marker; import com.replaymod.replaystudio.util.Location; import de.johni0702.minecraft.gui.GuiRenderer; @@ -168,11 +169,14 @@ public class GuiMarkerTimeline extends AbstractGuiTimeline im } else if (button == 1) { // Right click selectedMarker = null; if (replayHandler != null) { - replayHandler.setTargetPosition(new Location( - marker.getX(), marker.getY(), marker.getZ(), - marker.getPitch(), marker.getYaw() - )); - replayHandler.doJump(marker.getTime(), false); + CameraEntity cameraEntity = replayHandler.getCameraEntity(); + if (cameraEntity != null) { + cameraEntity.setCameraPosRot(new Location( + marker.getX(), marker.getY(), marker.getZ(), + marker.getYaw(), marker.getPitch() + )); + } + replayHandler.doJump(marker.getTime(), true); } else { setCursorPosition(marker.getTime()); } diff --git a/src/main/java/com/replaymod/replay/mixin/Mixin_MoveRealmsButton.java b/src/main/java/com/replaymod/replay/mixin/Mixin_MoveRealmsButton.java new file mode 100644 index 00000000..12f19084 --- /dev/null +++ b/src/main/java/com/replaymod/replay/mixin/Mixin_MoveRealmsButton.java @@ -0,0 +1,20 @@ +//#if MC>=11600 +package com.replaymod.replay.mixin; + +import net.minecraft.client.gui.screen.TitleScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; + +@Mixin(TitleScreen.class) +public abstract class Mixin_MoveRealmsButton { + @ModifyArg( + method = "init", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;init(Lnet/minecraft/client/MinecraftClient;II)V"), + index = 2 + ) + private int adjustRealmsButton(int height) { + return height - 24 * 4; + } +} +//#endif diff --git a/src/main/resources/mixins.replay.replaymod.json b/src/main/resources/mixins.replay.replaymod.json index 67b9da55..ff2737f1 100644 --- a/src/main/resources/mixins.replay.replaymod.json +++ b/src/main/resources/mixins.replay.replaymod.json @@ -5,6 +5,9 @@ "mixins": [], "server": [], "client": [ + //#if MC>=11600 + "Mixin_MoveRealmsButton", + //#endif //#if MC>=11400 "MixinCamera", "MixinInGameHud", diff --git a/version.txt b/version.txt index 79a61441..59aa62c1 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.4.4 +2.4.5 diff --git a/versions/1.8.9/mapping.txt b/versions/1.8.9/mapping.txt index 96c38ef4..43123ad0 100644 --- a/versions/1.8.9/mapping.txt +++ b/versions/1.8.9/mapping.txt @@ -1,3 +1,4 @@ +net.minecraft.entity.player.EntityPlayer isWearing() func_175148_a() net.minecraft.client.renderer.WorldRenderer begin() startDrawing() net.minecraft.network.play.server.S38PacketPlayerListItem getAction() func_179768_b() net.minecraft.network.play.server.S40PacketDisconnect getReason() func_149165_c() diff --git a/versions/common.gradle b/versions/common.gradle index b7cc1f3d..8f1bb427 100644 --- a/versions/common.gradle +++ b/versions/common.gradle @@ -295,7 +295,7 @@ dependencies { shadow 'com.github.ReplayMod.JavaBlend:2.79.0:a0696f8' - shadow "com.github.ReplayMod:ReplayStudio:2773270", shadeExclusions + shadow "com.github.ReplayMod:ReplayStudio:b29955e", shadeExclusions implementation(jGui){ transitive = false // FG 1.2 puts all MC deps into the compile configuration and we don't want to shade those