Merge branch 'stable' into develop

This commit is contained in:
Jonas Herzig
2021-02-19 11:58:28 +01:00
20 changed files with 153 additions and 87 deletions

View File

@@ -16,8 +16,6 @@ Build the mod via Gradle as explained above at least once (`./gradlew compileJav
Then import the Gradle project from within IDEA: File -> Open -> build.gradle -> Open as Project Then import the Gradle project from within IDEA: File -> Open -> build.gradle -> Open as Project
Finally configure IDEA to build everything by itself instead of delegating it to Gradle (cause that is slow): File -> Settings -> Build, Execution, Deployment -> Build Tools -> Gradle -> Build and run using: IntelliJ IDEA Finally configure IDEA to build everything by itself instead of delegating it to Gradle (cause that is slow): File -> Settings -> Build, Execution, Deployment -> Build Tools -> Gradle -> Build and run using: IntelliJ IDEA
The generation of run configurations for 1.14+ currently depends on https://github.com/FabricMC/fabric-loom/pull/236
### Eclipse ### Eclipse
## Development ## Development

View File

@@ -10,7 +10,9 @@ buildscript {
repositories { repositories {
mavenLocal() mavenLocal()
jcenter() maven {
url = "https://plugins.gradle.org/m2/"
}
mavenCentral() mavenCentral()
maven { maven {
name = "fabric" name = "fabric"
@@ -32,7 +34,7 @@ buildscript {
dependencies { dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.2' classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.2'
if (fabric) { if (fabric) {
classpath 'fabric-loom:fabric-loom.gradle.plugin:0.4-SNAPSHOT' classpath 'fabric-loom:fabric-loom.gradle.plugin:0.5-SNAPSHOT'
} else if (mcVersion >= 11400) { } else if (mcVersion >= 11400) {
classpath('net.minecraftforge.gradle:ForgeGradle:3.+'){ classpath('net.minecraftforge.gradle:ForgeGradle:3.+'){
exclude group: 'trove', module: 'trove' // preprocessor/idea requires more recent one exclude group: 'trove', module: 'trove' // preprocessor/idea requires more recent one
@@ -189,7 +191,7 @@ repositories {
mavenLocal() mavenLocal()
maven { maven {
name = "SpongePowered Repo" name = "SpongePowered Repo"
url = "http://repo.spongepowered.org/maven/" url = "https://repo.spongepowered.org/maven/"
} }
maven { maven {
name = "fabric" name = "fabric"
@@ -272,7 +274,7 @@ dependencies {
if (!FABRIC) { if (!FABRIC) {
// Mixin 0.8 is no longer compatible with MC 1.11.2 or older // Mixin 0.8 is no longer compatible with MC 1.11.2 or older
def mixinVersion = mcVersion >= 11200 ? '0.8' : '0.7.10-SNAPSHOT' def mixinVersion = mcVersion >= 11200 ? '0.8.2' : '0.7.11-SNAPSHOT'
annotationProcessor "org.spongepowered:mixin:$mixinVersion" annotationProcessor "org.spongepowered:mixin:$mixinVersion"
compileOnly "org.spongepowered:mixin:$mixinVersion" compileOnly "org.spongepowered:mixin:$mixinVersion"
shade("org.spongepowered:mixin:$mixinVersion") { shade("org.spongepowered:mixin:$mixinVersion") {
@@ -283,6 +285,7 @@ dependencies {
annotationProcessor 'com.google.code.gson:gson:2.2.4' annotationProcessor 'com.google.code.gson:gson:2.2.4'
annotationProcessor 'com.google.guava:guava:21.0' annotationProcessor 'com.google.guava:guava:21.0'
annotationProcessor 'org.ow2.asm:asm-tree:6.2' annotationProcessor 'org.ow2.asm:asm-tree:6.2'
annotationProcessor 'org.apache.logging.log4j:log4j-core:2.0-beta9'
} }
shadow 'com.googlecode.mp4parser:isoparser:1.1.7' shadow 'com.googlecode.mp4parser:isoparser:1.1.7'
shadow 'org.apache.commons:commons-exec:1.3' shadow 'org.apache.commons:commons-exec:1.3'
@@ -309,7 +312,7 @@ dependencies {
shadow 'com.github.ReplayMod.JavaBlend:2.79.0:a0696f8' shadow 'com.github.ReplayMod.JavaBlend:2.79.0:a0696f8'
shadow "com.github.ReplayMod:ReplayStudio:dac74cc", shadeExclusions shadow "com.github.ReplayMod:ReplayStudio:a1f82a7", shadeExclusions
implementation(jGui){ implementation(jGui){
transitive = false // FG 1.2 puts all MC deps into the compile configuration and we don't want to shade those transitive = false // FG 1.2 puts all MC deps into the compile configuration and we don't want to shade those

2
jGui

Submodule jGui updated: 424959c6d6...3f6e374e0e

View File

@@ -2,7 +2,7 @@ import groovy.json.JsonOutput
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
plugins { plugins {
id("fabric-loom") version "0.4-SNAPSHOT" apply false id("fabric-loom") version "0.5-SNAPSHOT" apply false
id("com.replaymod.preprocess") version "24ac087" id("com.replaymod.preprocess") version "24ac087"
id("com.github.hierynomus.license") version "0.15.0" id("com.github.hierynomus.license") version "0.15.0"
} }

View File

@@ -2,7 +2,6 @@ pluginManagement {
repositories { repositories {
mavenLocal() mavenLocal()
gradlePluginPortal() gradlePluginPortal()
jcenter()
mavenCentral() mavenCentral()
google() google()
maven("https://jitpack.io") maven("https://jitpack.io")
@@ -49,6 +48,8 @@ val replayModVersions = listOf(
"1.16.4" "1.16.4"
) )
rootProject.buildFileName = "root.gradle.kts"
include(":jGui") include(":jGui")
project(":jGui").apply { project(":jGui").apply {
projectDir = file("jGui") projectDir = file("jGui")
@@ -58,7 +59,7 @@ jGuiVersions.forEach { version ->
include(":jGui:$version") include(":jGui:$version")
project(":jGui:$version").apply { project(":jGui:$version").apply {
projectDir = file("jGui/versions/$version") projectDir = file("jGui/versions/$version")
buildFileName = "../common.gradle" buildFileName = "../../build.gradle"
} }
} }
@@ -66,6 +67,6 @@ replayModVersions.forEach { version ->
include(":$version") include(":$version")
project(":$version").apply { project(":$version").apply {
projectDir = file("versions/$version") projectDir = file("versions/$version")
buildFileName = "../common.gradle" buildFileName = "../../build.gradle"
} }
} }

View File

@@ -476,6 +476,14 @@ public class ReplayMod implements
String name = path.getFileName().toString(); String name = path.getFileName().toString();
if (name.endsWith(".mcpr.tmp") && Files.isDirectory(path)) { if (name.endsWith(".mcpr.tmp") && Files.isDirectory(path)) {
Path original = path.resolveSibling(FilenameUtils.getBaseName(name)); Path original = path.resolveSibling(FilenameUtils.getBaseName(name));
Path noRecoverMarker = original.resolveSibling(original.getFileName() + ".no_recover");
if (Files.exists(noRecoverMarker)) {
// This file, when its markers are processed, doesn't actually result in any replays.
// So we don't really need to recover it either, let's just get rid of it.
FileUtils.deleteDirectory(path.toFile());
Files.delete(noRecoverMarker);
continue;
}
new RestoreReplayGui(this, GuiScreen.wrap(mc.currentScreen), original.toFile()).display(); new RestoreReplayGui(this, GuiScreen.wrap(mc.currentScreen), original.toFile()).display();
} }
} }

View File

@@ -80,9 +80,16 @@ import org.lwjgl.glfw.GLFW;
//$$ import java.io.IOException; //$$ import java.io.IOException;
//#endif //#endif
//#if MC>=11400
import net.minecraft.client.sound.PositionedSoundInstance;
//#else
//$$ import net.minecraft.client.audio.PositionedSoundRecord;
//#endif
//#if MC>=10904 //#if MC>=10904
import com.replaymod.render.blend.mixin.ParticleAccessor; import com.replaymod.render.blend.mixin.ParticleAccessor;
import net.minecraft.client.particle.Particle; import net.minecraft.client.particle.Particle;
import net.minecraft.sound.SoundEvent;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
//#endif //#endif
@@ -758,6 +765,20 @@ public class MCVer {
} }
} }
public static void playSound(Identifier sound) {
getMinecraft().getSoundManager().play(
//#if MC>=11400
PositionedSoundInstance.master(new SoundEvent(sound), 1.0F)
//#elseif MC>=10904
//$$ PositionedSoundRecord.getMasterRecord(new SoundEvent(sound), 1.0F)
//#elseif MC>=10800
//$$ PositionedSoundRecord.create(sound, 1.0F)
//#else
//$$ PositionedSoundRecord.createPositionedSoundRecord(sound, 1.0F)
//#endif
);
}
//#if MC>=11400 //#if MC>=11400
private static Boolean hasOptifine; private static Boolean hasOptifine;
public static boolean hasOptifine() { public static boolean hasOptifine() {

View File

@@ -272,6 +272,10 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
// Immediately close the saving popup, the user doesn't care about it // Immediately close the saving popup, the user doesn't care about it
core.runLater(guiSavingReplay::close); core.runLater(guiSavingReplay::close);
// If we crash right here, on the next start we'll prompt the user for recovery
// but we don't really want that, so drop a marker file to skip recovery for this replay.
Files.createFile(outputPath.resolveSibling(outputPath.getFileName() + ".no_recover"));
// We still have the replay, so we just save it (at least for a few weeks) in case they change their mind // We still have the replay, so we just save it (at least for a few weeks) in case they change their mind
String replayName = FilenameUtils.getBaseName(outputPath.getFileName().toString()); String replayName = FilenameUtils.getBaseName(outputPath.getFileName().toString());
Path rawFolder = ReplayMod.instance.getRawReplayFolder(); Path rawFolder = ReplayMod.instance.getRawReplayFolder();

View File

@@ -443,4 +443,32 @@ public class RenderSettings {
public boolean isHighPerformance() { public boolean isHighPerformance() {
return highPerformance; return highPerformance;
} }
@Override
public String toString() {
return "RenderSettings{" +
"renderMethod=" + renderMethod +
", encodingPreset=" + encodingPreset +
", videoWidth=" + videoWidth +
", videoHeight=" + videoHeight +
", framesPerSecond=" + framesPerSecond +
", bitRate=" + bitRate +
", outputFile=" + outputFile +
", renderNameTags=" + renderNameTags +
", stabilizeYaw=" + stabilizeYaw +
", stabilizePitch=" + stabilizePitch +
", stabilizeRoll=" + stabilizeRoll +
", chromaKeyingColor=" + chromaKeyingColor +
", sphericalFovX=" + sphericalFovX +
", sphericalFovY=" + sphericalFovY +
", injectSphericalMetadata=" + injectSphericalMetadata +
", depthMap=" + depthMap +
", cameraPathExport=" + cameraPathExport +
", antiAliasing=" + antiAliasing +
", exportCommand='" + exportCommand + '\'' +
", exportArgumentsPreBgra='" + exportArgumentsPreBgra + '\'' +
", exportArguments='" + exportArguments + '\'' +
", highPerformance=" + highPerformance +
'}';
}
} }

View File

@@ -48,6 +48,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors;
import static com.replaymod.render.ReplayModRender.LOGGER; import static com.replaymod.render.ReplayModRender.LOGGER;
@@ -148,8 +149,15 @@ public class GuiRenderQueue extends AbstractGuiPopup<GuiRenderQueue> implements
renderButton.onClick(() -> { renderButton.onClick(() -> {
LOGGER.trace("Render button clicked"); LOGGER.trace("Render button clicked");
List<RenderJob> renderQueue = new ArrayList<>(); List<RenderJob> renderQueue = new ArrayList<>();
for (Entry entry : selectedEntries) { if (selectedEntries.isEmpty()) {
renderQueue.add(entry.job); renderQueue.addAll(jobs);
} else {
Set<RenderJob> selectedJobs = selectedEntries.stream().map(it -> it.job).collect(Collectors.toSet());
for (RenderJob job : jobs) {
if (selectedJobs.contains(job)) {
renderQueue.add(job);
}
}
} }
ReplayMod.instance.runLaterWithoutLock(() -> processQueue(container, replayHandler, renderQueue, () -> {})); ReplayMod.instance.runLaterWithoutLock(() -> processQueue(container, replayHandler, renderQueue, () -> {}));
}); });
@@ -337,7 +345,7 @@ public class GuiRenderQueue extends AbstractGuiPopup<GuiRenderQueue> implements
addButton.setEnabled(timelineSupplier != null); addButton.setEnabled(timelineSupplier != null);
editButton.setEnabled(selected == 1); editButton.setEnabled(selected == 1);
removeButton.setEnabled(selected >= 1); removeButton.setEnabled(selected >= 1);
renderButton.setEnabled(selected > 0); renderButton.setEnabled(jobs.size() > 0);
renderButton.setI18nLabel("replaymod.gui.renderqueue.render" + (selected > 0 ? "selected" : "all")); renderButton.setI18nLabel("replaymod.gui.renderqueue.render" + (selected > 0 ? "selected" : "all"));
String[] compatError = VideoRenderer.checkCompat(); String[] compatError = VideoRenderer.checkCompat();

View File

@@ -126,7 +126,7 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
public void run() { public void run() {
GuiFileChooserPopup popup = GuiFileChooserPopup.openSaveGui(GuiRenderSettings.this, "replaymod.gui.save", GuiFileChooserPopup popup = GuiFileChooserPopup.openSaveGui(GuiRenderSettings.this, "replaymod.gui.save",
encodingPresetDropdown.getSelectedValue().getFileExtension()); encodingPresetDropdown.getSelectedValue().getFileExtension());
popup.setFolder(outputFile.getParentFile()); popup.setFolder(getParentFile(outputFile));
popup.setFileName(outputFile.getName()); popup.setFileName(outputFile.getName());
popup.onAccept(file -> { popup.onAccept(file -> {
if (!file.getName().equals(outputFile.getName())) { if (!file.getName().equals(outputFile.getName())) {
@@ -523,13 +523,13 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
bitRateUnit.setSelected(0); bitRateUnit.setSelected(0);
} }
File savedOutputFile = settings.getOutputFile(); File savedOutputFile = settings.getOutputFile();
if (savedOutputFile == null || !savedOutputFile.getParentFile().exists()) { if (savedOutputFile == null || !getParentFile(savedOutputFile).exists()) {
this.outputFile = generateOutputFile(encodingPreset); this.outputFile = generateOutputFile(encodingPreset);
userDefinedOutputFileName = false; userDefinedOutputFileName = false;
} else if (savedOutputFile.exists()) { } else if (savedOutputFile.exists()) {
String name = generateOutputFile(encodingPreset).getName(); String name = generateOutputFile(encodingPreset).getName();
boolean isFolder = savedOutputFile.isDirectory() && !savedOutputFile.getName().endsWith(".exr"); boolean isFolder = savedOutputFile.isDirectory() && !savedOutputFile.getName().endsWith(".exr");
this.outputFile = new File(isFolder ? savedOutputFile : savedOutputFile.getParentFile(), name); this.outputFile = new File(isFolder ? savedOutputFile : getParentFile(savedOutputFile), name);
userDefinedOutputFileName = false; userDefinedOutputFileName = false;
} else { } else {
this.outputFile = conformExtension(savedOutputFile, encodingPreset); this.outputFile = conformExtension(savedOutputFile, encodingPreset);
@@ -573,7 +573,7 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
videoHeight.getInteger(), videoHeight.getInteger(),
frameRateSlider.getValue() + 10, frameRateSlider.getValue() + 10,
bitRateField.getInteger() << (10 * bitRateUnit.getSelected()), bitRateField.getInteger() << (10 * bitRateUnit.getSelected()),
serialize && !userDefinedOutputFileName ? outputFile.getParentFile() : outputFile, serialize && !userDefinedOutputFileName ? getParentFile(outputFile) : outputFile,
nametagCheckbox.isChecked(), nametagCheckbox.isChecked(),
stabilizeYaw.isChecked() && (serialize || stabilizeYaw.isEnabled()), stabilizeYaw.isChecked() && (serialize || stabilizeYaw.isEnabled()),
stabilizePitch.isChecked() && (serialize || stabilizePitch.isEnabled()), stabilizePitch.isChecked() && (serialize || stabilizePitch.isEnabled()),
@@ -602,7 +602,7 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
public void setOutputFileBaseName(String base) { public void setOutputFileBaseName(String base) {
RenderSettings.EncodingPreset preset = encodingPresetDropdown.getSelectedValue(); RenderSettings.EncodingPreset preset = encodingPresetDropdown.getSelectedValue();
File file = new File(outputFile.getParentFile(), base + "." + preset.getFileExtension()); File file = new File(getParentFile(outputFile), base + "." + preset.getFileExtension());
// Ensure the file name is valid // Ensure the file name is valid
try { try {
//noinspection ResultOfMethodCallIgnored //noinspection ResultOfMethodCallIgnored
@@ -619,7 +619,7 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
if (name.contains(".")) { if (name.contains(".")) {
name = name.substring(0, name.lastIndexOf('.')); name = name.substring(0, name.lastIndexOf('.'));
} }
return new File(file.getParentFile(), name + "." + preset.getFileExtension()); return new File(getParentFile(file), name + "." + preset.getFileExtension());
} }
protected Path getSettingsPath() { protected Path getSettingsPath() {
@@ -662,4 +662,10 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
screen.setBackground(AbstractGuiScreen.Background.NONE); screen.setBackground(AbstractGuiScreen.Background.NONE);
return screen; return screen;
} }
private static File getParentFile(File file) {
File parent = file.getParentFile();
// parent this can be null if file is just a name (i.e. in CWD)
return parent == null ? new File(".") : parent;
}
} }

View File

@@ -19,7 +19,6 @@ import com.replaymod.render.gui.GuiRenderingDone;
import com.replaymod.render.gui.GuiVideoRenderer; import com.replaymod.render.gui.GuiVideoRenderer;
import com.replaymod.render.metadata.MetadataInjector; import com.replaymod.render.metadata.MetadataInjector;
import com.replaymod.render.mixin.WorldRendererAccessor; import com.replaymod.render.mixin.WorldRendererAccessor;
import com.replaymod.render.utils.SoundHandler;
import com.replaymod.replay.ReplayHandler; import com.replaymod.replay.ReplayHandler;
import com.replaymod.replaystudio.pathing.path.Keyframe; import com.replaymod.replaystudio.pathing.path.Keyframe;
import com.replaymod.replaystudio.pathing.path.Path; import com.replaymod.replaystudio.pathing.path.Path;
@@ -29,6 +28,7 @@ import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import com.mojang.blaze3d.platform.GLX; import com.mojang.blaze3d.platform.GLX;
import net.minecraft.client.gl.Framebuffer; import net.minecraft.client.gl.Framebuffer;
import net.minecraft.util.Identifier;
import net.minecraft.util.crash.CrashException; import net.minecraft.util.crash.CrashException;
import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundCategory;
import net.minecraft.client.render.RenderTickCounter; import net.minecraft.client.render.RenderTickCounter;
@@ -422,7 +422,7 @@ public class VideoRenderer implements RenderInfo {
} }
} }
new SoundHandler().playRenderSuccessSound(); MCVer.playSound(new Identifier("replaymod", "render_success"));
try { try {
if (!hasFailed() && ffmpegWriter != null) { if (!hasFailed() && ffmpegWriter != null) {

View File

@@ -1,39 +0,0 @@
package com.replaymod.render.utils;
import com.replaymod.core.versions.MCVer;
import net.minecraft.util.Identifier;
import org.apache.commons.io.IOUtils;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
public class SoundHandler {
private final Identifier successSoundLocation = new Identifier("replaymod", "render_success.wav");
public void playRenderSuccessSound() {
playSound(successSoundLocation);
}
/**
* Plays a <b>.wav</b> Sound from a ResourceLocation. This method does <b>not</b> respect Game Settings like Audio Volume.
* @param loc The Sound File's ResourceLocation
*/
public void playSound(Identifier loc) {
try {
InputStream is = MCVer.getMinecraft().getResourceManager().getResource(loc).getInputStream();
byte[] bytes = IOUtils.toByteArray(is);
is.close();
AudioInputStream ais = AudioSystem.getAudioInputStream(new ByteArrayInputStream(bytes));
Clip clip = AudioSystem.getClip();
clip.open(ais);
clip.start();
} catch(Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -339,9 +339,8 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
*/ */
@Override @Override
public int currentTimeStamp() { public int currentTimeStamp() {
if (asyncMode) { if (asyncMode && !paused()) {
int timePassed = (int) (System.currentTimeMillis() - lastPacketSent); return (int) ((System.currentTimeMillis() - realTimeStart) * realTimeStartSpeed);
return lastTimeStamp + (int) (timePassed * getReplaySpeed());
} else { } else {
return lastTimeStamp; return lastTimeStamp;
} }
@@ -864,7 +863,11 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
*/ */
@Override @Override
public void setReplaySpeed(final double d) { public void setReplaySpeed(final double d) {
if(d != 0) this.replaySpeed = d; if (d != 0) {
this.replaySpeed = d;
this.realTimeStartSpeed = d;
this.realTimeStart = System.currentTimeMillis() - (long) (lastTimeStamp / d);
}
TimerAccessor timer = (TimerAccessor) ((MinecraftAccessor) mc).getTimer(); TimerAccessor timer = (TimerAccessor) ((MinecraftAccessor) mc).getTimer();
//#if MC>=11200 //#if MC>=11200
timer.setTickLength(WrappedTimer.DEFAULT_MS_PER_TICK / (float) d); timer.setTickLength(WrappedTimer.DEFAULT_MS_PER_TICK / (float) d);
@@ -878,9 +881,18 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
///////////////////////////////////////////////////////// /////////////////////////////////////////////////////////
/** /**
* The real time at which the last packet was sent in milliseconds. * Timestamp in milliseconds of when we started (or would have started when taking pauses and speed into account)
* the playback of the replay.
* Updated only when replay speed changes or on pause/unpause but definitely not on every packet to prevent gradual
* drifting.
*/ */
private long lastPacketSent; private long realTimeStart;
/**
* The replay speed used for {@link #realTimeStart}.
* If the target speed differs from this one, the timestamp is recalculated.
*/
private double realTimeStartSpeed;
/** /**
* There is no waiting performed until a packet with at least this timestamp is reached (but not yet sent). * There is no waiting performed until a packet with at least this timestamp is reached (but not yet sent).
@@ -936,15 +948,13 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
// If we aren't jumping and the world has already been loaded (no dirt-screens) then wait // If we aren't jumping and the world has already been loaded (no dirt-screens) then wait
// the required amount to get proper packet timing // the required amount to get proper packet timing
if (!isHurrying() && hasWorldLoaded) { if (!isHurrying() && hasWorldLoaded) {
// How much time should have passed // Timestamp of when the next packet should be sent
int timeWait = (int) Math.round((nextTimeStamp - lastTimeStamp) / replaySpeed); long expectedTime = realTimeStart + (long) (nextTimeStamp / replaySpeed);
// How much time did pass long now = System.currentTimeMillis();
long timeDiff = System.currentTimeMillis() - lastPacketSent; // If the packet should not yet be sent, wait a bit
// How much time we need to wait to make up for the difference if (expectedTime > now) {
long timeToSleep = Math.max(0, timeWait - timeDiff); Thread.sleep(expectedTime - now);
}
Thread.sleep(timeToSleep);
lastPacketSent = System.currentTimeMillis();
} }
// Process packet // Process packet
@@ -961,7 +971,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
replayHandler.moveCameraToTargetPosition(); replayHandler.moveCameraToTargetPosition();
// Pause after jumping // Pause after jumping (this will also reset realTimeStart accordingly)
setReplaySpeed(0); setReplaySpeed(0);
} }
} catch (EOFException eof) { } catch (EOFException eof) {
@@ -988,7 +998,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
loginPhase = true; loginPhase = true;
startFromBeginning = false; startFromBeginning = false;
nextPacket = null; nextPacket = null;
lastPacketSent = System.currentTimeMillis(); realTimeStart = System.currentTimeMillis();
if (replayIn != null) { if (replayIn != null) {
replayIn.close(); replayIn.close();
replayIn = null; replayIn = null;
@@ -1133,7 +1143,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
} }
// This might be required if we change to async mode anytime soon // This might be required if we change to async mode anytime soon
lastPacketSent = System.currentTimeMillis(); realTimeStart = System.currentTimeMillis() - (long) (timestamp / replaySpeed);
lastTimeStamp = timestamp; lastTimeStamp = timestamp;
} }
} catch (Exception e) { } catch (Exception e) {

View File

@@ -51,6 +51,7 @@ import net.minecraft.util.hit.HitResult;
//$$ import net.minecraft.util.math.RayTraceResult; //$$ import net.minecraft.util.math.RayTraceResult;
//$$ import net.minecraft.util.text.ITextComponent; //$$ import net.minecraft.util.text.ITextComponent;
//$$ import net.minecraft.world.World; //$$ import net.minecraft.world.World;
//$$ import net.minecraftforge.fml.common.gameevent.InputEvent;
//$$ //$$
//#if MC>=11400 //#if MC>=11400
//$$ import net.minecraft.util.math.RayTraceFluidMode; //$$ import net.minecraft.util.math.RayTraceFluidMode;
@@ -637,12 +638,11 @@ public class CameraEntity
} }
public boolean canSpectate(Entity e) { public boolean canSpectate(Entity e) {
return e != null && !e.isInvisible() return e != null
//#if MC>=10800 //#if MC<10800
&& (e instanceof PlayerEntity || e instanceof MobEntity || e instanceof ItemFrameEntity); //$$ && e instanceof EntityPlayer // cannot be more generic since 1.7.10 has no concept of eye height
//#else
//$$ && e instanceof EntityPlayer; // cannot be more generic since 1.7.10 has no concept of eye height
//#endif //#endif
&& !e.isInvisible();
} }
//#if MC<11400 //#if MC<11400
@@ -695,6 +695,16 @@ public class CameraEntity
//#if FABRIC>=1 //#if FABRIC>=1
{ on(KeyBindingEventCallback.EVENT, CameraEntity.this::handleInputEvents); } { on(KeyBindingEventCallback.EVENT, CameraEntity.this::handleInputEvents); }
//#elseif MC<11400
//$$ @SubscribeEvent
//$$ public void onKeyEvent(InputEvent.KeyInputEvent event) {
//$$ handleInputEvents();
//$$ }
//$$
//$$ @SubscribeEvent
//$$ public void onMouseInput(InputEvent.MouseInputEvent event) {
//$$ handleInputEvents();
//$$ }
//#endif //#endif
//#if FABRIC>=1 //#if FABRIC>=1

View File

@@ -67,6 +67,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.concurrent.CancellationException;
import java.util.function.Consumer; import java.util.function.Consumer;
import static com.replaymod.core.utils.Utils.error; import static com.replaymod.core.utils.Utils.error;
@@ -287,7 +288,9 @@ public class GuiPathing {
@Override @Override
public void onFailure(Throwable t) { public void onFailure(Throwable t) {
t.printStackTrace(); if (!(t instanceof CancellationException)) {
t.printStackTrace();
}
overlay.setCloseable(true); overlay.setCloseable(true);
} }
}); });

View File

@@ -0,0 +1,5 @@
{
"render_success": {
"sounds": [{ "name": "replaymod:render_success" }]
}
}

View File

@@ -1 +1 @@
2.5.1 2.5.2