Merge remote-tracking branch 'origin/develop' into snapshot

This commit is contained in:
Jonas Herzig
2020-06-28 22:07:49 +02:00
15 changed files with 238 additions and 265 deletions

View File

@@ -26,7 +26,7 @@ package com.replaymod.core;
//$$ public class LoadingPlugin implements IFMLLoadingPlugin {
//$$
//$$ public LoadingPlugin() {
//$$ if ((Boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment")) {
//$$ if (Launch.blackboard.get("fml.deobfuscatedEnvironment") != Boolean.FALSE) {
//$$ // Outside of the dev env, this is the job of the tweaker
//$$ MixinBootstrap.init();
//$$ }

View File

@@ -28,6 +28,7 @@ import net.minecraft.text.Style;
import net.minecraft.text.LiteralText;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Formatting;
import net.minecraft.util.crash.CrashException;
import org.apache.commons.io.FileUtils;
//#if MC>=11400
@@ -56,6 +57,7 @@ import net.fabricmc.loader.api.FabricLoader;
//$$ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
//$$ import net.minecraftforge.versions.mcp.MCPVersion;
//#else
//$$ import static com.replaymod.core.versions.MCVer.FML_BUS;
//$$ import net.minecraft.client.resources.IResourcePack;
//$$ import net.minecraftforge.common.config.Configuration;
//#endif
@@ -72,14 +74,12 @@ import net.fabricmc.loader.api.FabricLoader;
//$$ import net.minecraftforge.fml.common.Mod.Instance;
//$$ import net.minecraftforge.fml.common.event.FMLInitializationEvent;
//$$ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
//$$ import static com.replaymod.core.versions.MCVer.FORGE_BUS;
//#if MC>=10800
//$$ import net.minecraftforge.fml.client.FMLClientHandler;
//#else
//$$ import com.replaymod.replay.InputReplayTimer;
//$$
//$$ import java.util.ArrayDeque;
//$$ import static com.replaymod.core.versions.MCVer.FML_BUS;
//#endif
//#endif
//$$ import net.minecraftforge.fml.common.Mod;
@@ -544,6 +544,10 @@ public class ReplayMod implements
inRunLater = true;
try {
runnable.run();
} catch (CrashException e) {
e.printStackTrace();
System.err.println(e.getReport().asString());
mc.setCrashReport(e.getReport());
} finally {
inRunLater = false;
}
@@ -552,11 +556,11 @@ public class ReplayMod implements
//#else
//$$ if (mc.isCallingFromMinecraftThread() && inRunLater) {
//#if MC>=10800
//$$ FORGE_BUS.register(new Object() {
//$$ FML_BUS.register(new Object() {
//$$ @SubscribeEvent
//$$ public void onRenderTick(TickEvent.RenderTickEvent event) {
//$$ if (event.phase == TickEvent.Phase.START) {
//$$ FORGE_BUS.unregister(this);
//$$ FML_BUS.unregister(this);
//$$ defer.run();
//$$ }
//$$ }
@@ -578,6 +582,10 @@ public class ReplayMod implements
//$$ inRunLater = true;
//$$ try {
//$$ runnable.run();
//$$ } catch (ReportedException e) {
//$$ e.printStackTrace();
//$$ System.err.println(e.getCrashReport().getCompleteReport());
//$$ mc.crashed(e.getCrashReport());
//$$ } finally {
//$$ inRunLater = false;
//$$ }

View File

@@ -8,6 +8,10 @@ import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.Queue;
//#if MC>=11400
import java.util.concurrent.CompletableFuture;
//#endif
//#if MC<11400
//$$ import java.util.concurrent.FutureTask;
//#endif
@@ -24,6 +28,13 @@ public interface MinecraftAccessor {
@Accessor("renderTickCounter")
void setTimer(RenderTickCounter value);
//#if MC>=11400
@Accessor
CompletableFuture<Void> getResourceReloadFuture();
@Accessor
void setResourceReloadFuture(CompletableFuture<Void> value);
//#endif
//#if MC>=11400
@Accessor
Queue<Runnable> getRenderTaskQueue();

View File

@@ -104,17 +104,14 @@ public class RecordingEventHandler extends EventRegistrations {
}
//#endif
public void onPlayerJoin() {
public void spawnRecordingPlayer() {
try {
packetListener.save(new PlayerSpawnS2CPacket(mc.player));
} catch(Exception e1) {
e1.printStackTrace();
}
}
public void onPlayerRespawn() {
try {
packetListener.save(new PlayerSpawnS2CPacket(mc.player));
ClientPlayerEntity player = mc.player;
assert player != null;
packetListener.save(new PlayerSpawnS2CPacket(player));
//#if MC>=11500
packetListener.save(new EntityTrackerUpdateS2CPacket(player.getEntityId(), player.getDataTracker(), true));
//#endif
lastX = lastY = lastZ = null;
} catch(Exception e) {
e.printStackTrace();

View File

@@ -81,7 +81,7 @@ public abstract class MixinNetHandlerPlayClient {
// Only add spawn packet for our own player and only if he isn't known yet
if (data.getUuid().equals(mcStatic.player.getGameProfile().getId())
&& !this.playerListEntries.containsKey(data.getUuid())) {
handler.onPlayerJoin();
handler.spawnRecordingPlayer();
}
}
} catch (IOException e) {
@@ -96,7 +96,7 @@ public abstract class MixinNetHandlerPlayClient {
//$$ public void recordOwnJoin(S01PacketJoinGame packet, CallbackInfo ci) {
//$$ RecordingEventHandler handler = getRecordingEventHandler();
//$$ if (handler != null) {
//$$ handler.onPlayerJoin();
//$$ handler.spawnRecordingPlayer();
//$$ }
//$$ }
//#endif
@@ -116,7 +116,7 @@ public abstract class MixinNetHandlerPlayClient {
public void recordOwnRespawn(PlayerRespawnS2CPacket packet, CallbackInfo ci) {
RecordingEventHandler handler = getRecordingEventHandler();
if (handler != null) {
handler.onPlayerRespawn();
handler.spawnRecordingPlayer();
}
}
}

View File

@@ -95,10 +95,9 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
}
// Update export arguments to match new Preset
exportArguments.setText(newPreset.getValue());
// If the user hasn't changed the output file by themselves,
if (!outputFileManuallySet) {
// generate a new output file name with updated file extension
outputFile = generateOutputFile(newPreset);
// Update output file ending
if (outputFile != null) {
outputFile = conformExtension(outputFile, newPreset);
outputFileButton.setLabel(outputFile.getName());
}
updateInputs();
@@ -125,15 +124,20 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
public final GuiButton outputFileButton = new GuiButton().setMinSize(new Dimension(0, 20)).onClick(new Runnable() {
@Override
public void run() {
GuiFileChooserPopup popup = GuiFileChooserPopup.openSaveGui(GuiRenderSettings.this, "replaymod.gui.save",
encodingPresetDropdown.getSelectedValue().getFileExtension());
popup.setFolder(outputFile.getParentFile());
popup.setFileName(outputFile.getName());
Futures.addCallback(
GuiFileChooserPopup.openSaveGui(GuiRenderSettings.this, "replaymod.gui.save",
encodingPresetDropdown.getSelectedValue().getFileExtension()).getFuture(),
popup.getFuture(),
new FutureCallback<File>() {
@Override
public void onSuccess(@Nullable File result) {
if (result != null) {
if (!result.getName().equals(outputFile.getName())) {
userDefinedOutputFileName = true;
}
outputFile = result;
outputFileManuallySet = true;
outputFileButton.setLabel(result.getName());
}
}
@@ -318,7 +322,7 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
private final ReplayHandler replayHandler;
private final Timeline timeline;
private File outputFile;
private boolean outputFileManuallySet;
private boolean userDefinedOutputFileName;
public GuiRenderSettings(ReplayHandler replayHandler, Timeline timeline) {
this.replayHandler = replayHandler;
@@ -500,14 +504,19 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
bitRateField.setValue(settings.getBitRate());
bitRateUnit.setSelected(0);
}
if (settings.getOutputFile() == null) {
outputFile = generateOutputFile(settings.getEncodingPreset());
outputFileManuallySet = false;
File savedOutputFile = settings.getOutputFile();
if (savedOutputFile == null || !savedOutputFile.getParentFile().exists()) {
this.outputFile = generateOutputFile(settings.getEncodingPreset());
userDefinedOutputFileName = false;
} else if (savedOutputFile.exists()) {
String name = generateOutputFile(settings.getEncodingPreset()).getName();
this.outputFile = new File(savedOutputFile.isDirectory() ? savedOutputFile : savedOutputFile.getParentFile(), name);
userDefinedOutputFileName = false;
} else {
outputFile = settings.getOutputFile();
outputFileManuallySet = true;
this.outputFile = conformExtension(savedOutputFile, settings.getEncodingPreset());
userDefinedOutputFileName = true;
}
outputFileButton.setLabel(outputFile.getName());
outputFileButton.setLabel(this.outputFile.getName());
nametagCheckbox.setChecked(settings.isRenderNameTags());
stabilizeYaw.setChecked(settings.isStabilizeYaw());
stabilizePitch.setChecked(settings.isStabilizePitch());
@@ -543,7 +552,7 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
videoHeight.getInteger(),
frameRateSlider.getValue() + 10,
bitRateField.getInteger() << (10 * bitRateUnit.getSelected()),
serialize ? null : outputFile,
serialize && !userDefinedOutputFileName ? outputFile.getParentFile() : outputFile,
nametagCheckbox.isChecked(),
stabilizeYaw.isChecked() && (serialize || stabilizeYaw.isEnabled()),
stabilizePitch.isChecked() && (serialize || stabilizePitch.isEnabled()),
@@ -564,6 +573,14 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
return new File(folder, fileName + "." + encodingPreset.getFileExtension());
}
protected File conformExtension(File file, RenderSettings.EncodingPreset preset) {
String name = file.getName();
if (name.contains(".")) {
name = name.substring(0, name.lastIndexOf('.'));
}
return new File(file.getParentFile(), name + "." + preset.getFileExtension());
}
protected Path getSettingsPath() {
return ReplayModRender.instance.getRenderSettingsPath();
}

View File

@@ -44,7 +44,9 @@ import org.lwjgl.opengl.GL11;
//#if MC>=11400
import com.replaymod.render.mixin.MainWindowAccessor;
import net.minecraft.client.gui.screen.Screen;
import org.lwjgl.glfw.GLFW;
import java.util.concurrent.CompletableFuture;
//#else
//$$ import net.minecraft.client.gui.ScaledResolution;
//$$ import org.lwjgl.input.Mouse;
@@ -219,7 +221,15 @@ public class VideoRenderer implements RenderInfo {
//#endif
if (!settings.isHighPerformance() || framesDone % fps == 0) {
drawGui();
while (drawGui() && paused) {
try {
//noinspection BusyWait
Thread.sleep(50);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
// Updating the timer will cause the timeline player to update the game state
@@ -398,6 +408,20 @@ public class VideoRenderer implements RenderInfo {
private void executeTaskQueue() {
//#if MC>=11400
while (true) {
while (mc.overlay != null) {
drawGui();
((MinecraftMethodAccessor) mc).replayModExecuteTaskQueue();
}
CompletableFuture<Void> resourceReloadFuture = ((MinecraftAccessor) mc).getResourceReloadFuture();
if (resourceReloadFuture != null) {
((MinecraftAccessor) mc).setResourceReloadFuture(null);
mc.reloadResources().thenRun(() -> resourceReloadFuture.complete(null));
continue;
}
break;
}
((MCVer.MinecraftMethodAccessor) mc).replayModExecuteTaskQueue();
//#else
//$$ Queue<FutureTask<?>> scheduledTasks = ((MinecraftAccessor) mc).getScheduledTasks();
@@ -430,14 +454,14 @@ public class VideoRenderer implements RenderInfo {
//#endif
}
public void drawGui() {
public boolean drawGui() {
do {
//#if MC>=11400
if (GLFW.glfwWindowShouldClose(getWindow(mc).getHandle()) || ((MinecraftAccessor) mc).getCrashReporter() != null) {
//#else
//$$ if (Display.isCloseRequested() || ((MinecraftAccessor) mc).getCrashReporter() != null) {
//#endif
return;
return false;
}
// Resize the GUI framebuffer if the display size changed
@@ -510,12 +534,26 @@ public class VideoRenderer implements RenderInfo {
int mouseX = (int) mc.mouse.getX() * getWindow(mc).getScaledWidth() / displayWidth;
int mouseY = (int) mc.mouse.getY() * getWindow(mc).getScaledHeight() / displayHeight;
gui.toMinecraft().tick();
gui.toMinecraft().render(
//#if MC>=11600
//$$ new MatrixStack(),
//#endif
mouseX, mouseY, 0);
if (mc.overlay != null) {
Screen orgScreen = mc.currentScreen;
try {
mc.currentScreen = gui.toMinecraft();
mc.overlay.render(
//#if MC>=11600
//$$ new MatrixStack(),
//#endif
mouseX, mouseY, 0);
} finally {
mc.currentScreen = orgScreen;
}
} else {
gui.toMinecraft().tick();
gui.toMinecraft().render(
//#if MC>=11600
//$$ new MatrixStack(),
//#endif
mouseX, mouseY, 0);
}
//#else
//$$ int mouseX = Mouse.getX() * scaled.getScaledWidth() / mc.displayWidth;
//$$ int mouseY = scaled.getScaledHeight() - Mouse.getY() * scaled.getScaledHeight() / mc.displayHeight - 1;
@@ -558,15 +596,9 @@ public class VideoRenderer implements RenderInfo {
//$$ Mouse.setGrabbed(false);
//$$ }
//#endif
if (paused) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
} while (paused && !hasFailed() && !cancelled);
return !hasFailed() && !cancelled;
} while (true);
}
private boolean displaySizeChanged() {

View File

@@ -70,11 +70,14 @@ import net.minecraft.network.packet.s2c.play.EntitySpawnGlobalS2CPacket;
//#endif
//#if MC>=11400
import com.replaymod.core.versions.MCVer;
import net.minecraft.network.packet.s2c.play.ChunkDataS2CPacket;
import net.minecraft.network.packet.s2c.play.PlayerActionResponseS2CPacket;
import net.minecraft.network.packet.s2c.play.OpenContainerS2CPacket;
import net.minecraft.network.packet.s2c.play.OpenWrittenBookS2CPacket;
import net.minecraft.entity.EntityType;
import net.minecraft.text.TranslatableText;
import net.minecraft.world.chunk.light.LightingProvider;
//#else
//$$ import net.minecraft.client.resources.I18n;
//$$ import net.minecraft.entity.Entity;
@@ -459,6 +462,24 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend
//#endif
}
}
//#if MC>=11400
if (p instanceof ChunkDataS2CPacket) {
Runnable doLightUpdates = () -> {
if (mc.world != null) {
LightingProvider provider = mc.world.getChunkManager().getLightingProvider();
while (provider.hasUpdates()) {
provider.doLightUpdates(Integer.MAX_VALUE, true, true);
}
}
};
if (MCVer.isOnMainThread()) {
doLightUpdates.run();
} else {
MCVer.scheduleOnMainThread(doLightUpdates);
}
}
//#endif
}
} catch (Exception e) {
// We'd rather not have a failure parsing one packet screw up the whole replay process

View File

@@ -284,7 +284,7 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe
//$$ public void onTick(TickEvent.ClientTickEvent event) {
//$$ if (event.phase != TickEvent.Phase.START) return;
//#endif
if (!asyncMode) return;
if (!asyncMode || paused()) return;
long now = System.currentTimeMillis();
long realTimePassed = now - lastAsyncUpdateTime;

View File

@@ -578,7 +578,7 @@ public class CameraEntity
private void handleInputEvents() {
if (this.client.options.keyAttack.wasPressed() || this.client.options.keyUse.wasPressed()) {
if (canSpectate(this.client.targetedEntity)) {
if (this.client.currentScreen == null && canSpectate(this.client.targetedEntity)) {
ReplayModReplay.instance.getReplayHandler().spectateEntity(
//#if MC<=10710
//$$ (EntityLivingBase)

View File

@@ -100,7 +100,7 @@ public class GuiPathing {
public final GuiTexturedButton renderButton = new GuiTexturedButton().onClick(new Runnable() {
@Override
public void run() {
if (!preparePathsForPlayback()) return;
if (!preparePathsForPlayback(false)) return;
// Clone the timeline passed to the settings gui as it may be stored for later rendering in a queue
SPTimeline spTimeline = mod.getCurrentTimeline();
@@ -299,11 +299,12 @@ public class GuiPathing {
if (player.isActive()) {
player.getFuture().cancel(false);
} else {
boolean ignoreTimeKeyframes = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT);
Path timePath = mod.getCurrentTimeline().getTimePath();
if (!preparePathsForPlayback()) return;
if (!preparePathsForPlayback(ignoreTimeKeyframes)) return;
timePath.setActive(!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT));
timePath.setActive(!ignoreTimeKeyframes);
// Start from cursor time unless the control key is pressed (then start from beginning)
int startTime = Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)? 0 : GuiPathing.this.timeline.getCursorPosition();
ListenableFuture<Void> future = player.start(mod.getCurrentTimeline().getTimeline(), startTime);
@@ -519,10 +520,20 @@ public class GuiPathing {
}).start();
}
private boolean preparePathsForPlayback() {
private boolean preparePathsForPlayback(boolean ignoreTimeKeyframes) {
SPTimeline timeline = mod.getCurrentTimeline();
timeline.getTimeline().getPaths().forEach(Path::updateAll);
// Make sure there are at least two position keyframes
if (timeline.getPositionPath().getSegments().isEmpty()) {
GuiInfoPopup.open(replayHandler.getOverlay(), "replaymod.chat.morekeyframes");
return false;
}
if (ignoreTimeKeyframes) {
return true;
}
// Make sure time keyframes's values are monotonically increasing
int lastTime = 0;
for (Keyframe keyframe : timeline.getTimePath().getKeyframes()) {
@@ -538,9 +549,8 @@ public class GuiPathing {
lastTime = time;
}
// Make sure there are at least two position- and two time-keyframes
if (timeline.getPositionPath().getSegments().isEmpty()
|| timeline.getTimePath().getSegments().isEmpty()) {
// Make sure there are at least two time keyframes
if (timeline.getTimePath().getSegments().isEmpty()) {
GuiInfoPopup.open(replayHandler.getOverlay(), "replaymod.chat.morekeyframes");
return false;
}