From ec862f05960c46e168f48ebf9d3d9fba7f06c81c Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 7 Nov 2020 13:18:10 +0100 Subject: [PATCH 001/102] Update jGui --- jGui | 2 +- .../java/com/replaymod/core/utils/Utils.java | 32 ++----- .../playeroverview/PlayerOverviewGui.java | 4 +- .../extras/youtube/GuiYoutubeUpload.java | 54 +++++------- .../pathing/gui/GuiKeyframeRepository.java | 86 ++++++------------- .../render/gui/GuiRenderSettings.java | 33 ++----- .../gui/overlay/GuiEditMarkerPopup.java | 2 +- .../replay/gui/screen/GuiReplayViewer.java | 85 +++++++----------- .../simplepathing/gui/GuiEditKeyframe.java | 6 +- .../simplepathing/gui/GuiPathing.java | 21 ++--- 10 files changed, 108 insertions(+), 217 deletions(-) diff --git a/jGui b/jGui index 6b16892d..424959c6 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 6b16892d6489bf28cbf6945329f71c2effb52bc2 +Subproject commit 424959c6d6819b0c680463e38615063af816bc59 diff --git a/src/main/java/com/replaymod/core/utils/Utils.java b/src/main/java/com/replaymod/core/utils/Utils.java index a318c793..a1cda2bc 100644 --- a/src/main/java/com/replaymod/core/utils/Utils.java +++ b/src/main/java/com/replaymod/core/utils/Utils.java @@ -245,18 +245,10 @@ public class Utils { logger.trace("Opening crash report popup GUI"); GuiCrashReportPopup popup = new GuiCrashReportPopup(container, crashReportStr); - Futures.addCallback(popup.getFuture(), new FutureCallback() { - @Override - public void onSuccess(@Nullable Void result) { - logger.trace("Crash report popup closed"); - if (onClose != null) { - onClose.run(); - } - } - - @Override - public void onFailure(Throwable t) { - logger.error("During error popup:", t); + popup.onClosed(() -> { + logger.trace("Crash report popup closed"); + if (onClose != null) { + onClose.run(); } }); return popup; @@ -329,18 +321,10 @@ public class Utils { LOGGER.trace("Minimal mode active, denying action, opening popup"); MinimalModeUnsupportedPopup popup = new MinimalModeUnsupportedPopup(container); - Futures.addCallback(popup.getFuture(), new FutureCallback() { - @Override - public void onSuccess(@Nullable Void result) { - LOGGER.trace("Minimal mode popup closed"); - if (onPopupClosed != null) { - onPopupClosed.run(); - } - } - - @Override - public void onFailure(Throwable t) { - LOGGER.error("During minimal mode popup:", t); + popup.onClosed(() -> { + LOGGER.trace("Minimal mode popup closed"); + if (onPopupClosed != null) { + onPopupClosed.run(); } }); return false; diff --git a/src/main/java/com/replaymod/extras/playeroverview/PlayerOverviewGui.java b/src/main/java/com/replaymod/extras/playeroverview/PlayerOverviewGui.java index 01824f4f..97e0d20f 100644 --- a/src/main/java/com/replaymod/extras/playeroverview/PlayerOverviewGui.java +++ b/src/main/java/com/replaymod/extras/playeroverview/PlayerOverviewGui.java @@ -53,13 +53,13 @@ public class PlayerOverviewGui extends GuiScreen implements Closeable { public final GuiCheckbox checkAll = new GuiCheckbox(contentPanel){ @Override public void onClick() { - playersScrollable.forEach(IGuiCheckbox.class).setChecked(true); + playersScrollable.invokeAll(IGuiCheckbox.class, e -> e.setChecked(true)); } }.setLabel("").setChecked(true).setTooltip(new GuiTooltip().setI18nText("replaymod.gui.playeroverview.showall")); public final GuiCheckbox uncheckAll = new GuiCheckbox(contentPanel){ @Override public void onClick() { - playersScrollable.forEach(IGuiCheckbox.class).setChecked(false); + playersScrollable.invokeAll(IGuiCheckbox.class, e -> e.setChecked(false)); } }.setLabel("").setChecked(false).setTooltip(new GuiTooltip().setI18nText("replaymod.gui.playeroverview.hideall")); diff --git a/src/main/java/com/replaymod/extras/youtube/GuiYoutubeUpload.java b/src/main/java/com/replaymod/extras/youtube/GuiYoutubeUpload.java index e3097841..6c1358ef 100644 --- a/src/main/java/com/replaymod/extras/youtube/GuiYoutubeUpload.java +++ b/src/main/java/com/replaymod/extras/youtube/GuiYoutubeUpload.java @@ -31,7 +31,6 @@ import net.minecraft.util.Util; //$$ import org.lwjgl.Sys; //#endif -import javax.annotation.Nullable; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.stream.ImageInputStream; @@ -116,36 +115,27 @@ public class GuiYoutubeUpload extends GuiScreen { public final GuiButton thumbnailButton = new GuiButton().onClick(new Runnable() { @Override public void run() { - Futures.addCallback( - GuiFileChooserPopup.openLoadGui(GuiYoutubeUpload.this, "replaymod.gui.load", - ImageIO.getReaderFileSuffixes()).getFuture(), - new FutureCallback() { - @Override - public void onSuccess(@Nullable File result) { - if (result != null) { - thumbnailButton.setLabel(result.getName()); - Image image; - try { - thumbnailImage = IOUtils.toByteArray(new FileInputStream(result)); - ImageInputStream in = ImageIO.createImageInputStream(new ByteArrayInputStream(thumbnailImage)); - ImageReader reader = ImageIO.getImageReaders(in).next(); - thumbnailFormat = reader.getFormatName().toLowerCase(); - image = Image.read(new ByteArrayInputStream(thumbnailImage)); - } catch (Throwable t) { - t.printStackTrace(); - thumbnailImage = null; - image = null; - } - thumbnail.setTexture(image); - inputValidation.run(); - } - } - - @Override - public void onFailure(Throwable t) { - throw new RuntimeException(t); - } - }); + GuiFileChooserPopup.openLoadGui( + GuiYoutubeUpload.this, + "replaymod.gui.load", + ImageIO.getReaderFileSuffixes() + ).onAccept(file -> { + thumbnailButton.setLabel(file.getName()); + Image image; + try { + thumbnailImage = IOUtils.toByteArray(new FileInputStream(file)); + ImageInputStream in = ImageIO.createImageInputStream(new ByteArrayInputStream(thumbnailImage)); + ImageReader reader = ImageIO.getImageReaders(in).next(); + thumbnailFormat = reader.getFormatName().toLowerCase(); + image = Image.read(new ByteArrayInputStream(thumbnailImage)); + } catch (Throwable t) { + t.printStackTrace(); + thumbnailImage = null; + image = null; + } + thumbnail.setTexture(image); + inputValidation.run(); + }); } }).setSize(200, 20).setI18nLabel("replaymod.gui.videothumbnail"); @@ -191,7 +181,7 @@ public class GuiYoutubeUpload extends GuiScreen { } private void setState(boolean uploading) { - forEach(GuiElement.class).setEnabled(!uploading); + invokeAll(GuiElement.class, e -> e.setEnabled(!uploading)); uploadButton.setEnabled(); if (uploading) { uploadButton.onClick(() -> { diff --git a/src/main/java/com/replaymod/pathing/gui/GuiKeyframeRepository.java b/src/main/java/com/replaymod/pathing/gui/GuiKeyframeRepository.java index 34760873..6ac40e61 100644 --- a/src/main/java/com/replaymod/pathing/gui/GuiKeyframeRepository.java +++ b/src/main/java/com/replaymod/pathing/gui/GuiKeyframeRepository.java @@ -65,18 +65,15 @@ public class GuiKeyframeRepository extends GuiScreen implements Closeable, Typea public final GuiButton overwriteButton = new GuiButton().onClick(new Runnable() { @Override public void run() { - GuiYesNoPopup popup = GuiYesNoPopup.open(GuiKeyframeRepository.this, + GuiYesNoPopup.open(GuiKeyframeRepository.this, new GuiLabel().setI18nText("replaymod.gui.keyframerepo.overwrite").setColor(Colors.BLACK) - ).setYesI18nLabel("gui.yes").setNoI18nLabel("gui.no"); - Utils.addCallback(popup.getFuture(), doIt -> { - if (doIt) { - for (Entry entry : selectedEntries) { - timelines.put(entry.name, currentTimeline); - } - overwriteButton.setDisabled(); - save(); + ).setYesI18nLabel("gui.yes").setNoI18nLabel("gui.no").onAccept(() -> { + for (Entry entry : selectedEntries) { + timelines.put(entry.name, currentTimeline); } - }, Throwable::printStackTrace); + overwriteButton.setDisabled(); + save(); + }); } }).setSize(75, 20).setI18nLabel("replaymod.gui.overwrite").setDisabled(); public final GuiButton saveAsButton = new GuiButton().onClick(new Runnable() { @@ -103,21 +100,11 @@ public class GuiKeyframeRepository extends GuiScreen implements Closeable, Typea && !timelines.containsKey(nameField.getText())); } }); - Futures.addCallback(popup.getFuture(), new FutureCallback() { - @Override - public void onSuccess(Boolean save) { - if (save) { - String name = nameField.getText(); - timelines.put(name, currentTimeline); - list.getListPanel().addElements(null, new Entry(name)); - save(); - } - } - - @Override - public void onFailure(Throwable t) { - t.printStackTrace(); - } + popup.onAccept(() -> { + String name = nameField.getText(); + timelines.put(name, currentTimeline); + list.getListPanel().addElements(null, new Entry(name)); + save(); }); } }).setSize(75, 20).setI18nLabel("replaymod.gui.saveas"); @@ -161,50 +148,29 @@ public class GuiKeyframeRepository extends GuiScreen implements Closeable, Typea && !timelines.containsKey(nameField.getText())); } }); - Futures.addCallback(popup.getFuture(), new FutureCallback() { - @Override - public void onSuccess(Boolean save) { - if (save) { - String name = nameField.getText(); - timelines.put(name, timelines.remove(selectedEntry.name)); - selectedEntry.name = name; - selectedEntry.label.setText(name); - save(); - } - } - - @Override - public void onFailure(Throwable t) { - t.printStackTrace(); - } + popup.onAccept(() -> { + String name = nameField.getText(); + timelines.put(name, timelines.remove(selectedEntry.name)); + selectedEntry.name = name; + selectedEntry.label.setText(name); + save(); }); } }).setSize(75, 20).setI18nLabel("replaymod.gui.rename").setDisabled(); public final GuiButton removeButton = new GuiButton().onClick(new Runnable() { @Override public void run() { - GuiYesNoPopup popup = GuiYesNoPopup.open(GuiKeyframeRepository.this, + GuiYesNoPopup.open(GuiKeyframeRepository.this, new GuiLabel().setI18nText("replaymod.gui.keyframerepo.delete").setColor(Colors.BLACK) - ).setYesI18nLabel("replaymod.gui.delete").setNoI18nLabel("replaymod.gui.cancel"); - Futures.addCallback(popup.getFuture(), new FutureCallback() { - @Override - public void onSuccess(Boolean delete) { - if (delete) { - for (Entry entry : selectedEntries) { - timelines.remove(entry.name); - list.getListPanel().removeElement(entry); - } - - selectedEntries.clear(); - updateButtons(); - save(); - } + ).setYesI18nLabel("replaymod.gui.delete").setNoI18nLabel("replaymod.gui.cancel").onAccept(() -> { + for (Entry entry : selectedEntries) { + timelines.remove(entry.name); + list.getListPanel().removeElement(entry); } - @Override - public void onFailure(Throwable t) { - t.printStackTrace(); - } + selectedEntries.clear(); + updateButtons(); + save(); }); } }).setSize(75, 20).setI18nLabel("replaymod.gui.remove").setDisabled(); diff --git a/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java b/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java index 5a632c57..7333b58b 100644 --- a/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java +++ b/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java @@ -1,8 +1,6 @@ package com.replaymod.render.gui; import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.InstanceCreator; @@ -39,7 +37,6 @@ import net.minecraft.client.gui.screen.NoticeScreen; import net.minecraft.client.resource.language.I18n; import net.minecraft.util.crash.CrashReport; -import javax.annotation.Nullable; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -131,25 +128,13 @@ public class GuiRenderSettings extends AbstractGuiPopup { encodingPresetDropdown.getSelectedValue().getFileExtension()); popup.setFolder(outputFile.getParentFile()); popup.setFileName(outputFile.getName()); - Futures.addCallback( - popup.getFuture(), - new FutureCallback() { - @Override - public void onSuccess(@Nullable File result) { - if (result != null) { - if (!result.getName().equals(outputFile.getName())) { - userDefinedOutputFileName = true; - } - outputFile = result; - outputFileButton.setLabel(result.getName()); - } - } - - @Override - public void onFailure(Throwable t) { - throw new RuntimeException(t); - } - }); + popup.onAccept(file -> { + if (!file.getName().equals(outputFile.getName())) { + userDefinedOutputFileName = true; + } + outputFile = file; + outputFileButton.setLabel(file.getName()); + }); } }); @@ -401,10 +386,10 @@ public class GuiRenderSettings extends AbstractGuiPopup { case CUBIC: case EQUIRECTANGULAR: case ODS: - stabilizePanel.forEach(IGuiCheckbox.class).setEnabled(); + stabilizePanel.invokeAll(IGuiCheckbox.class, GuiElement::setEnabled); break; default: - stabilizePanel.forEach(IGuiCheckbox.class).setDisabled(); + stabilizePanel.invokeAll(IGuiCheckbox.class, GuiElement::setDisabled); } // Enable/Disable Spherical FOV slider diff --git a/src/main/java/com/replaymod/replay/gui/overlay/GuiEditMarkerPopup.java b/src/main/java/com/replaymod/replay/gui/overlay/GuiEditMarkerPopup.java index 2d0d5be4..ab2a3d78 100644 --- a/src/main/java/com/replaymod/replay/gui/overlay/GuiEditMarkerPopup.java +++ b/src/main/java/com/replaymod/replay/gui/overlay/GuiEditMarkerPopup.java @@ -93,7 +93,7 @@ public class GuiEditMarkerPopup extends AbstractGuiPopup imp popup.setLayout(new VerticalLayout().setSpacing(5)) .addElements(new VerticalLayout.Data(0.5), title, inputs, buttons); - popup.forEach(IGuiLabel.class).setColor(Colors.BLACK); + popup.invokeAll(IGuiLabel.class, e -> e.setColor(Colors.BLACK)); nameField.setText(Strings.nullToEmpty(marker.getName())); timeField.setValue(marker.getTime()); diff --git a/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java b/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java index 5c227644..7e4ea045 100644 --- a/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java +++ b/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java @@ -1,8 +1,5 @@ package com.replaymod.replay.gui.screen; -import com.google.common.base.Supplier; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.SettableFuture; import com.replaymod.render.gui.GuiRenderQueue; import com.replaymod.render.rendering.VideoRenderer; @@ -63,6 +60,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.function.Supplier; import java.util.stream.Collectors; import static com.replaymod.replay.ReplayModReplay.LOGGER; @@ -151,67 +149,46 @@ public class GuiReplayViewer extends GuiScreen { popup.getYesButton().setEnabled(!nameField.getText().isEmpty() && !new File(file.getParentFile(), Utils.replayNameToFileName(nameField.getText())).exists()); }); - Futures.addCallback(popup.getFuture(), new FutureCallback() { - @Override - public void onSuccess(Boolean delete) { - if (delete) { - // Sanitize their input - String name = nameField.getText().trim(); - // This file is what they want - File targetFile = new File(file.getParentFile(), Utils.replayNameToFileName(name)); - try { - // Finally, try to move it - FileUtils.moveFile(file, targetFile); - } catch (IOException e) { - // We failed (might also be their OS) - e.printStackTrace(); - getMinecraft().openScreen(new NoticeScreen( - //#if MC>=11400 - GuiReplayViewer.this::display, - new TranslatableText("replaymod.gui.viewer.delete.failed1"), - new TranslatableText("replaymod.gui.viewer.delete.failed2") - //#else - //$$ I18n.format("replaymod.gui.viewer.delete.failed1"), - //$$ I18n.format("replaymod.gui.viewer.delete.failed2") - //#endif - )); - return; - } - list.load(); - } - } - - @Override - public void onFailure(Throwable t) { - t.printStackTrace(); + popup.onAccept(() -> { + // Sanitize their input + String newName = nameField.getText().trim(); + // This file is what they want + File targetFile = new File(file.getParentFile(), Utils.replayNameToFileName(newName)); + try { + // Finally, try to move it + FileUtils.moveFile(file, targetFile); + } catch (IOException e) { + // We failed (might also be their OS) + e.printStackTrace(); + getMinecraft().openScreen(new NoticeScreen( + //#if MC>=11400 + GuiReplayViewer.this::display, + new TranslatableText("replaymod.gui.viewer.delete.failed1"), + new TranslatableText("replaymod.gui.viewer.delete.failed2") + //#else + //$$ I18n.format("replaymod.gui.viewer.delete.failed1"), + //$$ I18n.format("replaymod.gui.viewer.delete.failed2") + //#endif + )); + return; } + list.load(); }); } }).setSize(73, 20).setI18nLabel("replaymod.gui.rename").setDisabled(); public final GuiButton deleteButton = new GuiButton().onClick(() -> { for (GuiReplayEntry entry : list.getSelected()) { String name = entry.name.getText(); - GuiYesNoPopup popup = GuiYesNoPopup.open(GuiReplayViewer.this, + GuiYesNoPopup.open(GuiReplayViewer.this, new GuiLabel().setI18nText("replaymod.gui.viewer.delete.linea").setColor(Colors.BLACK), new GuiLabel().setI18nText("replaymod.gui.viewer.delete.lineb", name + Formatting.RESET).setColor(Colors.BLACK) - ).setYesI18nLabel("replaymod.gui.delete").setNoI18nLabel("replaymod.gui.cancel"); - Futures.addCallback(popup.getFuture(), new FutureCallback() { - @Override - public void onSuccess(Boolean delete) { - if (delete) { - try { - FileUtils.forceDelete(entry.file); - } catch (IOException e) { - e.printStackTrace(); - } - list.load(); - } - } - - @Override - public void onFailure(Throwable t) { - t.printStackTrace(); + ).setYesI18nLabel("replaymod.gui.delete").setNoI18nLabel("replaymod.gui.cancel").onAccept(() -> { + try { + FileUtils.forceDelete(entry.file); + } catch (IOException e) { + e.printStackTrace(); } + list.load(); }); } }).setSize(73, 20).setI18nLabel("replaymod.gui.delete").setDisabled(); diff --git a/src/main/java/com/replaymod/simplepathing/gui/GuiEditKeyframe.java b/src/main/java/com/replaymod/simplepathing/gui/GuiEditKeyframe.java index 27fd2fd1..eb3561ec 100644 --- a/src/main/java/com/replaymod/simplepathing/gui/GuiEditKeyframe.java +++ b/src/main/java/com/replaymod/simplepathing/gui/GuiEditKeyframe.java @@ -155,7 +155,7 @@ public abstract class GuiEditKeyframe> extends Abst link(timeMinField, timeSecField, timeMSecField); - popup.forEach(IGuiLabel.class).setColor(Colors.BLACK); + popup.invokeAll(IGuiLabel.class, e -> e.setColor(Colors.BLACK)); } @Override @@ -194,7 +194,7 @@ public abstract class GuiEditKeyframe> extends Abst link(timestampMinField, timestampSecField, timestampMSecField, timeMinField, timeSecField, timeMSecField); - popup.forEach(IGuiLabel.class).setColor(Colors.BLACK); + popup.invokeAll(IGuiLabel.class, e -> e.setColor(Colors.BLACK)); } @Override @@ -252,7 +252,7 @@ public abstract class GuiEditKeyframe> extends Abst link(xField, yField, zField, yawField, pitchField, rollField, timeMinField, timeSecField, timeMSecField); - popup.forEach(IGuiLabel.class).setColor(Colors.BLACK); + popup.invokeAll(IGuiLabel.class, e -> e.setColor(Colors.BLACK)); } @Override diff --git a/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java b/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java index f805dd58..dc9c6b4b 100644 --- a/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java +++ b/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java @@ -399,23 +399,12 @@ public class GuiPathing { } public void clearKeyframesButtonPressed() { - GuiYesNoPopup popup = GuiYesNoPopup.open(replayHandler.getOverlay(), + GuiYesNoPopup.open(replayHandler.getOverlay(), new GuiLabel().setI18nText("replaymod.gui.clearcallback.title").setColor(Colors.BLACK) - ).setYesI18nLabel("gui.yes").setNoI18nLabel("gui.no"); - Futures.addCallback(popup.getFuture(), new FutureCallback() { - @Override - public void onSuccess(Boolean delete) { - if (delete) { - mod.clearCurrentTimeline(); - if (entityTracker != null) { - mod.getCurrentTimeline().setEntityTracker(entityTracker); - } - } - } - - @Override - public void onFailure(Throwable t) { - t.printStackTrace(); + ).setYesI18nLabel("gui.yes").setNoI18nLabel("gui.no").onAccept(() -> { + mod.clearCurrentTimeline(); + if (entityTracker != null) { + mod.getCurrentTimeline().setEntityTracker(entityTracker); } }); } From bcde675775056ee86ae06fc80eff309f91af8d7e Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Fri, 19 Feb 2021 17:32:41 +0100 Subject: [PATCH 002/102] Update jGui --- jGui | 2 +- .../java/com/replaymod/recording/gui/GuiRecordingOverlay.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jGui b/jGui index 3f6e374e..64f683f1 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 3f6e374e0e5019bc42d09f4f655134c35aa06103 +Subproject commit 64f683f1035d989de6e564cb2e920c7c41bdb77b diff --git a/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java b/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java index f2e1b73f..41844484 100644 --- a/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java +++ b/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java @@ -61,7 +61,7 @@ public class GuiRecordingOverlay extends EventRegistrations { text.toUpperCase(), 30, 18 - (fontRenderer.fontHeight / 2), 0xffffffff); bindTexture(TEXTURE); enableAlphaTest(); - GuiRenderer renderer = new MinecraftGuiRenderer(stack, MCVer.newScaledResolution(mc)); + GuiRenderer renderer = new MinecraftGuiRenderer(stack); renderer.drawTexturedRect(10, 10, 58, 20, 16, 16, 16, 16, TEXTURE_SIZE, TEXTURE_SIZE); } } From 9d81265213bfc560cbc65eb1ebe2b7d04d58c65d Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Fri, 19 Feb 2021 23:01:43 +0100 Subject: [PATCH 003/102] Update preprocessor plugin --- jGui | 2 +- root.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jGui b/jGui index 64f683f1..80ff9223 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 64f683f1035d989de6e564cb2e920c7c41bdb77b +Subproject commit 80ff9223d3fd3947f76b8535e73e0fd62a9fab1c diff --git a/root.gradle.kts b/root.gradle.kts index 61825fc4..88e23880 100755 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -3,7 +3,7 @@ import java.io.ByteArrayOutputStream plugins { id("fabric-loom") version "0.5-SNAPSHOT" apply false - id("com.replaymod.preprocess") version "24ac087" + id("com.replaymod.preprocess") version "7c4f90e" id("com.github.hierynomus.license") version "0.15.0" } From 1a35234b0ad8dc09f1ffd3bf24dacdc8cc2dc47c Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Fri, 19 Feb 2021 23:02:39 +0100 Subject: [PATCH 004/102] Move LoadingPlugin into 1.12.2 project --- .../com/replaymod/core/LoadingPlugin.java | 105 +----------------- .../com/replaymod/core/LoadingPlugin.java | 102 +++++++++++++++++ 2 files changed, 103 insertions(+), 104 deletions(-) create mode 100644 versions/1.12.2/src/main/java/com/replaymod/core/LoadingPlugin.java diff --git a/src/main/java/com/replaymod/core/LoadingPlugin.java b/src/main/java/com/replaymod/core/LoadingPlugin.java index 5598ca01..fca4cd6c 100644 --- a/src/main/java/com/replaymod/core/LoadingPlugin.java +++ b/src/main/java/com/replaymod/core/LoadingPlugin.java @@ -1,104 +1 @@ -package com.replaymod.core; - -//#if MC<11400 -//$$ import net.minecraft.launchwrapper.Launch; -//$$ import org.apache.logging.log4j.LogManager; -//$$ import org.spongepowered.asm.launch.MixinBootstrap; -//$$ import org.spongepowered.asm.mixin.Mixins; -//$$ -//$$ import net.minecraftforge.fml.relauncher.CoreModManager; -//$$ import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin; -//#if MC<10800 -//$$ import com.replaymod.core.asm.GLErrorTransformer; -//$$ import com.replaymod.core.asm.GLStateTrackerTransformer; -//$$ -//$$ import java.util.ArrayList; -//$$ import java.util.List; -//#endif -//$$ -//$$ import java.io.File; -//$$ import java.net.URISyntaxException; -//$$ import java.net.URL; -//$$ import java.security.CodeSource; -//$$ import java.util.Map; -//$$ -//$$ @IFMLLoadingPlugin.TransformerExclusions("com.replaymod.core.asm.") -//$$ public class LoadingPlugin implements IFMLLoadingPlugin { -//$$ -//$$ public LoadingPlugin() { -//$$ if (Launch.blackboard.get("fml.deobfuscatedEnvironment") != Boolean.FALSE) { -//$$ // Outside of the dev env, this is the job of the tweaker -//$$ MixinBootstrap.init(); -//$$ } -//$$ -//$$ Mixins.addConfiguration("mixins.core.replaymod.json"); -//$$ Mixins.addConfiguration("mixins.recording.replaymod.json"); -//$$ Mixins.addConfiguration("mixins.render.replaymod.json"); -//$$ Mixins.addConfiguration("mixins.render.blend.replaymod.json"); -//$$ Mixins.addConfiguration("mixins.replay.replaymod.json"); -//$$ Mixins.addConfiguration("mixins.compat.mapwriter.replaymod.json"); -//$$ Mixins.addConfiguration("mixins.compat.shaders.replaymod.json"); -//$$ Mixins.addConfiguration("mixins.extras.playeroverview.replaymod.json"); -//$$ -//$$ CodeSource codeSource = getClass().getProtectionDomain().getCodeSource(); -//$$ if (codeSource != null) { -//$$ URL location = codeSource.getLocation(); -//$$ try { -//$$ File file = new File(location.toURI()); -//$$ if (file.isFile()) { -//$$ // This forces forge to reexamine the jar file for FML mods -//$$ // Should eventually be handled by Mixin itself, maybe? - //#if MC>=10809 - //$$ CoreModManager.getIgnoredMods().remove(file.getName()); - //#else - //$$ CoreModManager.getLoadedCoremods().remove(file.getName()); - //#if MC<=10710 - //$$ CoreModManager.getReparseableCoremods().add(file.getName()); - //#endif - //#endif -//$$ } -//$$ } catch (URISyntaxException e) { -//$$ e.printStackTrace(); -//$$ } -//$$ } else { -//$$ LogManager.getLogger().warn("No CodeSource, if this is not a development environment we might run into problems!"); -//$$ LogManager.getLogger().warn(getClass().getProtectionDomain()); -//$$ } -//$$ } -//$$ -//$$ @Override -//$$ public String[] getASMTransformerClass() { - //#if MC>=10800 - //$$ return new String[]{ - //$$ }; - //#else - //$$ List transformers = new ArrayList<>(); - //$$ if ("true".equals(System.getProperty("replaymod.glerrors", "false"))) { - //$$ transformers.add(GLErrorTransformer.class.getName()); - //$$ } - //$$ transformers.add(GLStateTrackerTransformer.class.getName()); - //$$ return transformers.stream().toArray(String[]::new); - //#endif -//$$ } -//$$ -//$$ @Override -//$$ public String getModContainerClass() { -//$$ return null; -//$$ } -//$$ -//$$ @Override -//$$ public String getSetupClass() { -//$$ return null; -//$$ } -//$$ -//$$ @Override -//$$ public void injectData(Map data) { -//$$ } -//$$ -//$$ @Override -//$$ public String getAccessTransformerClass() { -//$$ return null; -//$$ } -//$$ -//$$ } -//#endif +// 1.12.2 and below diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/LoadingPlugin.java b/versions/1.12.2/src/main/java/com/replaymod/core/LoadingPlugin.java new file mode 100644 index 00000000..cf6d0389 --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/core/LoadingPlugin.java @@ -0,0 +1,102 @@ +package com.replaymod.core; + +import net.minecraft.launchwrapper.Launch; +import org.apache.logging.log4j.LogManager; +import org.spongepowered.asm.launch.MixinBootstrap; +import org.spongepowered.asm.mixin.Mixins; + +import net.minecraftforge.fml.relauncher.CoreModManager; +import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin; +//#if MC<10800 +//$$ import com.replaymod.core.asm.GLErrorTransformer; +//$$ import com.replaymod.core.asm.GLStateTrackerTransformer; +//$$ +//$$ import java.util.ArrayList; +//$$ import java.util.List; +//#endif + +import java.io.File; +import java.net.URISyntaxException; +import java.net.URL; +import java.security.CodeSource; +import java.util.Map; + +@IFMLLoadingPlugin.TransformerExclusions("com.replaymod.core.asm.") +public class LoadingPlugin implements IFMLLoadingPlugin { + + public LoadingPlugin() { + if (Launch.blackboard.get("fml.deobfuscatedEnvironment") != Boolean.FALSE) { + // Outside of the dev env, this is the job of the tweaker + MixinBootstrap.init(); + } + + Mixins.addConfiguration("mixins.core.replaymod.json"); + Mixins.addConfiguration("mixins.recording.replaymod.json"); + Mixins.addConfiguration("mixins.render.replaymod.json"); + Mixins.addConfiguration("mixins.render.blend.replaymod.json"); + Mixins.addConfiguration("mixins.replay.replaymod.json"); + Mixins.addConfiguration("mixins.compat.mapwriter.replaymod.json"); + Mixins.addConfiguration("mixins.compat.shaders.replaymod.json"); + Mixins.addConfiguration("mixins.extras.playeroverview.replaymod.json"); + + CodeSource codeSource = getClass().getProtectionDomain().getCodeSource(); + if (codeSource != null) { + URL location = codeSource.getLocation(); + try { + File file = new File(location.toURI()); + if (file.isFile()) { + // This forces forge to reexamine the jar file for FML mods + // Should eventually be handled by Mixin itself, maybe? + //#if MC>=10809 + CoreModManager.getIgnoredMods().remove(file.getName()); + //#else + //$$ CoreModManager.getLoadedCoremods().remove(file.getName()); + //#if MC<=10710 + //$$ CoreModManager.getReparseableCoremods().add(file.getName()); + //#endif + //#endif + } + } catch (URISyntaxException e) { + e.printStackTrace(); + } + } else { + LogManager.getLogger().warn("No CodeSource, if this is not a development environment we might run into problems!"); + LogManager.getLogger().warn(getClass().getProtectionDomain()); + } + } + + @Override + public String[] getASMTransformerClass() { + //#if MC>=10800 + return new String[]{ + }; + //#else + //$$ List transformers = new ArrayList<>(); + //$$ if ("true".equals(System.getProperty("replaymod.glerrors", "false"))) { + //$$ transformers.add(GLErrorTransformer.class.getName()); + //$$ } + //$$ transformers.add(GLStateTrackerTransformer.class.getName()); + //$$ return transformers.stream().toArray(String[]::new); + //#endif + } + + @Override + public String getModContainerClass() { + return null; + } + + @Override + public String getSetupClass() { + return null; + } + + @Override + public void injectData(Map data) { + } + + @Override + public String getAccessTransformerClass() { + return null; + } + +} From 9a67a6455525e38ebda7257237c16af77cfeaf77 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Fri, 19 Feb 2021 23:15:39 +0100 Subject: [PATCH 005/102] Drop server-side restrictions implementation I don't think this sees sufficient use to justify updating. Especially because it's non-trivial with forge's network changes. Ping me if you actually used this. --- .../restrictions/ReplayModRestrictions.java | 124 ------------------ .../com/replaymod/restrictions/Setting.java | 19 --- src/main/resources/mcmod.info | 16 --- 3 files changed, 159 deletions(-) delete mode 100644 src/main/java/com/replaymod/restrictions/ReplayModRestrictions.java delete mode 100644 src/main/java/com/replaymod/restrictions/Setting.java diff --git a/src/main/java/com/replaymod/restrictions/ReplayModRestrictions.java b/src/main/java/com/replaymod/restrictions/ReplayModRestrictions.java deleted file mode 100644 index d05741ac..00000000 --- a/src/main/java/com/replaymod/restrictions/ReplayModRestrictions.java +++ /dev/null @@ -1,124 +0,0 @@ -// I don't think this sees sufficient use to justify updating. -// Especially because it's non-trivial with forge's network changes. -// PRs welcome. Ping me if you actually used this. - -//#if MC<11400 -//$$ package com.replaymod.restrictions; -//$$ -//$$ import com.replaymod.core.SettingsRegistry; -//$$ import com.replaymod.core.utils.Restrictions; -//$$ import io.netty.buffer.Unpooled; -//$$ import io.netty.channel.ChannelDuplexHandler; -//$$ import io.netty.channel.ChannelFutureListener; -//$$ import io.netty.channel.ChannelHandler; -//$$ import net.minecraft.network.PacketBuffer; -//$$ import net.minecraftforge.common.config.Configuration; -//$$ import org.apache.logging.log4j.Logger; -//$$ -//#if MC>=10800 -//$$ import net.minecraftforge.fml.common.Mod; -//$$ import net.minecraftforge.fml.common.event.FMLInitializationEvent; -//$$ import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; -//$$ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; -//$$ import net.minecraftforge.fml.common.eventhandler.EventBus; -//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -//$$ import net.minecraftforge.fml.common.gameevent.PlayerEvent; -//$$ import net.minecraftforge.fml.common.network.FMLEmbeddedChannel; -//$$ import net.minecraftforge.fml.common.network.FMLOutboundHandler; -//$$ import net.minecraftforge.fml.common.network.NetworkRegistry; -//$$ import net.minecraftforge.fml.common.network.internal.FMLProxyPacket; -//$$ import net.minecraftforge.fml.relauncher.Side; -//#else -//$$ import cpw.mods.fml.common.FMLCommonHandler; -//$$ import cpw.mods.fml.common.Mod; -//$$ import cpw.mods.fml.common.event.FMLInitializationEvent; -//$$ import cpw.mods.fml.common.event.FMLPostInitializationEvent; -//$$ import cpw.mods.fml.common.event.FMLPreInitializationEvent; -//$$ import cpw.mods.fml.common.eventhandler.EventBus; -//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent; -//$$ import cpw.mods.fml.common.gameevent.PlayerEvent; -//$$ import cpw.mods.fml.common.network.FMLEmbeddedChannel; -//$$ import cpw.mods.fml.common.network.FMLOutboundHandler; -//$$ import cpw.mods.fml.common.network.NetworkRegistry; -//$$ import cpw.mods.fml.common.network.internal.FMLProxyPacket; -//$$ import cpw.mods.fml.relauncher.Side; -//#endif -//$$ -//$$ import java.io.IOException; -//$$ import java.util.HashMap; -//$$ import java.util.Map; -//$$ -//$$ import static com.replaymod.core.versions.MCVer.*; -//$$ -//$$ @Mod(modid = ReplayModRestrictions.MOD_ID, -//$$ version = "@MOD_VERSION@", -//$$ acceptedMinecraftVersions = "@MC_VERSION@", -//$$ acceptableRemoteVersions = "*", - //#if MC>=10800 - //$$ serverSideOnly = true, - //#endif -//$$ useMetadata = true) -//$$ public class ReplayModRestrictions { -//$$ public static final String MOD_ID = "replaymod-restrictions"; -//$$ -//$$ public static Logger LOGGER; -//$$ -//$$ private final SettingsRegistry settingsRegistry = new SettingsRegistry(); -//$$ private FMLEmbeddedChannel channel; -//$$ -//$$ @Mod.EventHandler -//$$ public void preInit(FMLPreInitializationEvent event) { -//$$ LOGGER = event.getModLog(); -//$$ -//$$ Configuration config = new Configuration(event.getSuggestedConfigurationFile()); -//$$ config.load(); -//$$ settingsRegistry.setConfiguration(config); -//$$ -//$$ settingsRegistry.register(Setting.class); -//$$ } -//$$ -//$$ @Mod.EventHandler -//$$ public void init(FMLInitializationEvent event) { - //#if MC<=10710 - //$$ if (FMLCommonHandler.instance().getSide() == Side.CLIENT) return; - //#endif -//$$ EventBus bus = FML_BUS; -//$$ bus.register(this); -//$$ -//$$ channel = NetworkRegistry.INSTANCE.newChannel(Restrictions.PLUGIN_CHANNEL, new RestrictionsChannelHandler()).get(Side.SERVER); -//$$ } -//$$ -//$$ @Mod.EventHandler -//$$ public void postInit(FMLPostInitializationEvent event) throws IOException { -//$$ settingsRegistry.save(); // Save default values to disk -//$$ } -//$$ -//$$ @ChannelHandler.Sharable -//$$ private static class RestrictionsChannelHandler extends ChannelDuplexHandler {} -//$$ -//$$ @SubscribeEvent -//$$ public void onUserJoin(PlayerEvent.PlayerLoggedInEvent event) { -//$$ Map restrictions = new HashMap<>(); -//$$ if (settingsRegistry.get(Setting.NO_XRAY)) restrictions.put("no_xray", new byte[0]); -//$$ if (settingsRegistry.get(Setting.NO_NOCLIP)) restrictions.put("no_noclip", new byte[0]); -//$$ if (settingsRegistry.get(Setting.ONLY_FIRST_PERSON)) restrictions.put("only_first_person", new byte[0]); -//$$ if (settingsRegistry.get(Setting.ONLY_RECORDING_PLAYER)) restrictions.put("only_recording_player", new byte[0]); -//$$ if (settingsRegistry.get(Setting.HIDE_COORDINATES)) restrictions.put("hide_coordinates", new byte[0]); -//$$ -//$$ PacketBuffer buf = new PacketBuffer(Unpooled.buffer()); -//$$ for (Map.Entry e : restrictions.entrySet()) { -//$$ byte[] bytes = e.getKey().getBytes(); -//$$ buf.writeByte(bytes.length); -//$$ buf.writeBytes(bytes); -//$$ buf.writeByte(1); -//$$ buf.writeBytes(e.getValue()); -//$$ } -//$$ -//$$ FMLProxyPacket packet = new FMLProxyPacket(buf, Restrictions.PLUGIN_CHANNEL); -//$$ -//$$ channel.attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.PLAYER); -//$$ channel.attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(event.player); -//$$ channel.writeAndFlush(packet).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); -//$$ } -//$$ } -//#endif diff --git a/src/main/java/com/replaymod/restrictions/Setting.java b/src/main/java/com/replaymod/restrictions/Setting.java deleted file mode 100644 index 7a36e936..00000000 --- a/src/main/java/com/replaymod/restrictions/Setting.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.replaymod.restrictions; - -import com.replaymod.core.SettingsRegistry; - -public final class Setting extends SettingsRegistry.SettingKeys { - public static final Setting NO_XRAY = make("no_xray", false); - public static final Setting NO_NOCLIP = make("no_noclip", false); - public static final Setting ONLY_FIRST_PERSON = make("only_first_person", false); - public static final Setting ONLY_RECORDING_PLAYER = make("only_recording_player", false); - public static final Setting HIDE_COORDINATES = make("hide_coordinates", false); - - private static Setting make(String key, T defaultValue) { - return new Setting<>("restrictions", key, defaultValue); - } - - public Setting(String category, String key, T defaultValue) { - super(category, key, null, defaultValue); - } -} diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index 3432d978..4c7f1a50 100644 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -117,22 +117,6 @@ "screenshots": [], "dependencies": [] }, - { - "modid": "replaymod-restrictions", - "name": "Replay Mod - Restrictions", - "description": "Server-side Restrictions Module of the ReplayMod - Restrict what clients can do in replays", - "version": "${version}", - "mcversion": "${mcversion}", - "url": "https://replaymod.com", - "updateUrl": "https://replaymod.com/download", - "authorList": [ - "CrushedPixel", - "johni0702" - ], - "logoFile": "replaymod_logo.png", - "screenshots": [], - "dependencies": [] - }, { "modid": "replaymod-compat", "name": "Replay Mod - Compatibility", From bc9d8cb3d1f42f84d7f66c8b5675fc812fce96c3 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Fri, 19 Feb 2021 23:03:51 +0100 Subject: [PATCH 006/102] Split off highly version dependent code from SettingsRegistry --- .../java/com/replaymod/core/ReplayMod.java | 4 +- .../com/replaymod/core/SettingsRegistry.java | 205 +----------------- .../core/SettingsRegistryBackend.java | 110 ++++++++++ .../core/SettingsRegistryBackend.java | 66 ++++++ 4 files changed, 183 insertions(+), 202 deletions(-) create mode 100644 src/main/java/com/replaymod/core/SettingsRegistryBackend.java create mode 100644 versions/1.12.2/src/main/java/com/replaymod/core/SettingsRegistryBackend.java diff --git a/src/main/java/com/replaymod/core/ReplayMod.java b/src/main/java/com/replaymod/core/ReplayMod.java index 6afd4bdd..c08416db 100644 --- a/src/main/java/com/replaymod/core/ReplayMod.java +++ b/src/main/java/com/replaymod/core/ReplayMod.java @@ -202,9 +202,7 @@ public class ReplayMod implements modules.add(new ReplayModExtras(this)); modules.add(new ReplayModCompat()); - //#if MC>=11400 settingsRegistry.register(); - //#endif } //#if MC<=11400 @@ -212,7 +210,7 @@ public class ReplayMod implements //$$ public void init(FMLPreInitializationEvent event) { //$$ config = new Configuration(event.getSuggestedConfigurationFile()); //$$ config.load(); - //$$ settingsRegistry.setConfiguration(config); + //$$ settingsRegistry.backend.setConfiguration(config); //$$ settingsRegistry.save(); // Save default values to disk //$$ } //#endif diff --git a/src/main/java/com/replaymod/core/SettingsRegistry.java b/src/main/java/com/replaymod/core/SettingsRegistry.java index ff911a1d..79bbcb60 100644 --- a/src/main/java/com/replaymod/core/SettingsRegistry.java +++ b/src/main/java/com/replaymod/core/SettingsRegistry.java @@ -1,130 +1,18 @@ package com.replaymod.core; import com.replaymod.core.events.SettingsChangedCallback; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.*; -//#if MC>=11400 -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -//#else -//#if MC>=11400 -//$$ import net.minecraftforge.common.ForgeConfigSpec; -//$$ import net.minecraftforge.fml.ModLoadingContext; -//$$ import net.minecraftforge.fml.config.ModConfig; -//$$ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -//#else -//$$ import net.minecraftforge.common.config.Configuration; -//#endif -//#endif - -import static com.replaymod.core.versions.MCVer.*; - public class SettingsRegistry { - private static Logger LOGGER = LogManager.getLogger(); - private Map, Object> settings = Collections.synchronizedMap(new LinkedHashMap<>()); - //#if MC>=11400 - private final Path configFile = getMinecraft().runDirectory.toPath().resolve("config/replaymod.json"); - //#else - //$$ private static final Object NULL_OBJECT = new Object(); - //#if MC>=11400 - //$$ private ForgeConfigSpec spec; - //$$ private ModConfig config; - //#else - //$$ private Configuration configuration; - //#endif - //#endif + private final Map, Object> settings = Collections.synchronizedMap(new LinkedHashMap<>()); + final SettingsRegistryBackend backend = new SettingsRegistryBackend(settings); - //#if MC>=11400 public void register() { - String config; - if (Files.exists(configFile)) { - try { - config = new String(Files.readAllBytes(configFile), StandardCharsets.UTF_8); - } catch (IOException e) { - e.printStackTrace(); - return; - } - } else { - save(); - return; - } - Gson gson = new Gson(); - JsonObject root = gson.fromJson(config, JsonObject.class); - if (root == null) { - LOGGER.error("Config file {} appears corrupted: {}", configFile, config); - save(); - return; - } - for (Map.Entry, Object> entry : settings.entrySet()) { - SettingKey key = entry.getKey(); - JsonElement category = root.get(key.getCategory()); - if (category != null && category.isJsonObject()) { - JsonElement valueElem = category.getAsJsonObject().get(key.getKey()); - if (valueElem == null || !valueElem.isJsonPrimitive()) continue; - JsonPrimitive value = valueElem.getAsJsonPrimitive(); - if (key.getDefault() instanceof Boolean && value.isBoolean()) { - entry.setValue(value.getAsBoolean()); - } - if (key.getDefault() instanceof Integer && value.isNumber()) { - entry.setValue(value.getAsNumber().intValue()); - } - if (key.getDefault() instanceof Double && value.isNumber()) { - entry.setValue(value.getAsNumber().doubleValue()); - } - if (key.getDefault() instanceof String && value.isString()) { - entry.setValue(value.getAsString()); - } - } - } + backend.register(); } - //#else - //#if MC>=11400 - //$$ public void register() { - //$$ if (spec == null) { - //$$ ForgeConfigSpec.Builder builder = new ForgeConfigSpec.Builder(); - //$$ for (SettingKey key : settings.keySet()) { - //$$ builder - //$$ .translation(key.getDisplayString()) - //$$ .define(key.getCategory() + "." + key.getKey(), key.getDefault()); - //$$ } - //$$ spec = builder.build(); - //$$ } - //$$ FMLJavaModLoadingContext.get().getModEventBus().addListener(this::load); - //$$ ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, spec); - //$$ } - //$$ - //$$ private void load(ModConfig.Loading event) { - //$$ config = event.getConfig(); - //$$ for (Map.Entry, Object> entry : settings.entrySet()) { - //$$ SettingKey key = entry.getKey(); - //$$ Object value = config.getConfigData().get(key.getCategory() + "." + key.getKey()); - //$$ entry.setValue(value == null ? key.getDefault() : value); - //$$ } - //$$ } - //#else - //$$ public void setConfiguration(Configuration configuration) { - //$$ this.configuration = configuration; - //$$ - //$$ List> keys = new ArrayList<>(settings.keySet()); - //$$ settings.clear(); - //$$ for (SettingKey key : keys) { - //$$ register(key); - //$$ } - //$$ } - //#endif - //#endif public void register(Class settingsClass) { for (Field field : settingsClass.getDeclaredFields()) { @@ -140,34 +28,8 @@ public class SettingsRegistry { } public void register(SettingKey key) { - //#if MC>=11400 settings.put(key, key.getDefault()); - //#else - //#if MC>=11400 - //$$ if (spec != null) { - //$$ throw new IllegalStateException("Cannot register more settings are spec has been built."); - //$$ } - //$$ settings.put(key, NULL_OBJECT); - //#else - //$$ Object value; - //$$ if (configuration != null) { - //$$ if (key.getDefault() instanceof Boolean) { - //$$ value = configuration.get(key.getCategory(), key.getKey(), (Boolean) key.getDefault()).getBoolean(); - //$$ } else if (key.getDefault() instanceof Integer) { - //$$ value = configuration.get(key.getCategory(), key.getKey(), (Integer) key.getDefault()).getInt(); - //$$ } else if (key.getDefault() instanceof Double) { - //$$ value = configuration.get(key.getCategory(), key.getKey(), (Double) key.getDefault()).getDouble(); - //$$ } else if (key.getDefault() instanceof String) { - //$$ value = configuration.get(key.getCategory(), key.getKey(), (String) key.getDefault()).getString(); - //$$ } else { - //$$ throw new IllegalArgumentException("Default type " + key.getDefault().getClass() + " not supported."); - //$$ } - //$$ } else { - //$$ value = NULL_OBJECT; - //$$ } - //$$ settings.put(key, value); - //#endif - //#endif + backend.register(key); } public Set> getSettings() { @@ -183,68 +45,13 @@ public class SettingsRegistry { } public void set(SettingKey key, T value) { - //#if MC<11400 - //#if MC>=11400 - //$$ if (config != null) { - //$$ config.getConfigData().set(key.getCategory() + "." + key.getKey(), value); - //$$ } - //#else - //$$ if (key.getDefault() instanceof Boolean) { - //$$ configuration.get(key.getCategory(), key.getKey(), (Boolean) key.getDefault()).set((Boolean) value); - //$$ } else if (key.getDefault() instanceof Integer) { - //$$ configuration.get(key.getCategory(), key.getKey(), (Integer) key.getDefault()).set((Integer) value); - //$$ } else if (key.getDefault() instanceof Double) { - //$$ configuration.get(key.getCategory(), key.getKey(), (Double) key.getDefault()).set((Double) value); - //$$ } else if (key.getDefault() instanceof String) { - //$$ configuration.get(key.getCategory(), key.getKey(), (String) key.getDefault()).set((String) value); - //$$ } else { - //$$ throw new IllegalArgumentException("Default type " + key.getDefault().getClass() + " not supported."); - //$$ } - //#endif - //#endif + backend.update(key, value); settings.put(key, value); SettingsChangedCallback.EVENT.invoker().onSettingsChanged(this, key); } public void save() { - //#if MC>=11400 - JsonObject root = new JsonObject(); - for (Map.Entry, Object> entry : settings.entrySet()) { - SettingKey key = entry.getKey(); - JsonObject category = root.getAsJsonObject(key.getCategory()); - if (category == null) { - category = new JsonObject(); - root.add(key.getCategory(), category); - } - - Object value = entry.getValue(); - if (value instanceof Boolean) { - category.addProperty(key.getKey(), (Boolean) value); - } - if (value instanceof Number) { - category.addProperty(key.getKey(), (Number) value); - } - if (value instanceof String) { - category.addProperty(key.getKey(), (String) value); - } - } - Gson gson = new GsonBuilder().setPrettyPrinting().create(); - String config = gson.toJson(root); - try { - Files.createDirectories(configFile.getParent()); - Files.write(configFile, config.getBytes(StandardCharsets.UTF_8)); - } catch (IOException e) { - e.printStackTrace(); - } - //#else - //#if MC>=11400 - //$$ if (config != null) { - //$$ config.save(); - //$$ } - //#else - //$$ configuration.save(); - //#endif - //#endif + backend.save(); } public interface SettingKey { diff --git a/src/main/java/com/replaymod/core/SettingsRegistryBackend.java b/src/main/java/com/replaymod/core/SettingsRegistryBackend.java new file mode 100644 index 00000000..66a8eaae --- /dev/null +++ b/src/main/java/com/replaymod/core/SettingsRegistryBackend.java @@ -0,0 +1,110 @@ +package com.replaymod.core; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; + +import static com.replaymod.core.versions.MCVer.getMinecraft; + +class SettingsRegistryBackend { + private static final Logger LOGGER = LogManager.getLogger(); + private final Map, Object> settings; + + private final Path configFile = getMinecraft().runDirectory.toPath().resolve("config/replaymod.json"); + + SettingsRegistryBackend(Map, Object> settings) { + this.settings = settings; + } + + public void register() { + String config; + if (Files.exists(configFile)) { + try { + config = new String(Files.readAllBytes(configFile), StandardCharsets.UTF_8); + } catch (IOException e) { + e.printStackTrace(); + return; + } + } else { + save(); + return; + } + Gson gson = new Gson(); + JsonObject root = gson.fromJson(config, JsonObject.class); + if (root == null) { + LOGGER.error("Config file {} appears corrupted: {}", configFile, config); + save(); + return; + } + for (Map.Entry, Object> entry : settings.entrySet()) { + SettingsRegistry.SettingKey key = entry.getKey(); + JsonElement category = root.get(key.getCategory()); + if (category != null && category.isJsonObject()) { + JsonElement valueElem = category.getAsJsonObject().get(key.getKey()); + if (valueElem == null || !valueElem.isJsonPrimitive()) continue; + JsonPrimitive value = valueElem.getAsJsonPrimitive(); + if (key.getDefault() instanceof Boolean && value.isBoolean()) { + entry.setValue(value.getAsBoolean()); + } + if (key.getDefault() instanceof Integer && value.isNumber()) { + entry.setValue(value.getAsNumber().intValue()); + } + if (key.getDefault() instanceof Double && value.isNumber()) { + entry.setValue(value.getAsNumber().doubleValue()); + } + if (key.getDefault() instanceof String && value.isString()) { + entry.setValue(value.getAsString()); + } + } + } + } + + @SuppressWarnings("unused") + public void register(SettingsRegistry.SettingKey key) { + } + + @SuppressWarnings("unused") + public void update(SettingsRegistry.SettingKey key, T value) { + } + + public void save() { + JsonObject root = new JsonObject(); + for (Map.Entry, Object> entry : settings.entrySet()) { + SettingsRegistry.SettingKey key = entry.getKey(); + JsonObject category = root.getAsJsonObject(key.getCategory()); + if (category == null) { + category = new JsonObject(); + root.add(key.getCategory(), category); + } + + Object value = entry.getValue(); + if (value instanceof Boolean) { + category.addProperty(key.getKey(), (Boolean) value); + } + if (value instanceof Number) { + category.addProperty(key.getKey(), (Number) value); + } + if (value instanceof String) { + category.addProperty(key.getKey(), (String) value); + } + } + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + String config = gson.toJson(root); + try { + Files.createDirectories(configFile.getParent()); + Files.write(configFile, config.getBytes(StandardCharsets.UTF_8)); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/SettingsRegistryBackend.java b/versions/1.12.2/src/main/java/com/replaymod/core/SettingsRegistryBackend.java new file mode 100644 index 00000000..c33727fd --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/core/SettingsRegistryBackend.java @@ -0,0 +1,66 @@ +package com.replaymod.core; + +import net.minecraftforge.common.config.Configuration; + +import java.util.ArrayList; +import java.util.Map; + +class SettingsRegistryBackend { + private final Map, Object> settings; + + private static final Object NULL_OBJECT = new Object(); + private Configuration configuration; + + SettingsRegistryBackend(Map, Object> settings) { + this.settings = settings; + } + + public void register() { + } + + public void setConfiguration(Configuration configuration) { + this.configuration = configuration; + + for (SettingsRegistry.SettingKey key : new ArrayList<>(settings.keySet())) { + register(key); + } + } + + public void register(SettingsRegistry.SettingKey key) { + Object value; + if (configuration != null) { + if (key.getDefault() instanceof Boolean) { + value = configuration.get(key.getCategory(), key.getKey(), (Boolean) key.getDefault()).getBoolean(); + } else if (key.getDefault() instanceof Integer) { + value = configuration.get(key.getCategory(), key.getKey(), (Integer) key.getDefault()).getInt(); + } else if (key.getDefault() instanceof Double) { + value = configuration.get(key.getCategory(), key.getKey(), (Double) key.getDefault()).getDouble(); + } else if (key.getDefault() instanceof String) { + value = configuration.get(key.getCategory(), key.getKey(), (String) key.getDefault()).getString(); + } else { + throw new IllegalArgumentException("Default type " + key.getDefault().getClass() + " not supported."); + } + } else { + value = NULL_OBJECT; + } + settings.put(key, value); + } + + public void update(SettingsRegistry.SettingKey key, T value) { + if (key.getDefault() instanceof Boolean) { + configuration.get(key.getCategory(), key.getKey(), (Boolean) key.getDefault()).set((Boolean) value); + } else if (key.getDefault() instanceof Integer) { + configuration.get(key.getCategory(), key.getKey(), (Integer) key.getDefault()).set((Integer) value); + } else if (key.getDefault() instanceof Double) { + configuration.get(key.getCategory(), key.getKey(), (Double) key.getDefault()).set((Double) value); + } else if (key.getDefault() instanceof String) { + configuration.get(key.getCategory(), key.getKey(), (String) key.getDefault()).set((String) value); + } else { + throw new IllegalArgumentException("Default type " + key.getDefault().getClass() + " not supported."); + } + } + + public void save() { + configuration.save(); + } +} From 0be2082fe7d0830bcec57371decfe56a216e2885 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 20 Feb 2021 00:41:40 +0100 Subject: [PATCH 007/102] Split off highly version dependent code from ReplayMod --- .../java/com/replaymod/core/ReplayMod.java | 404 ++---------------- .../com/replaymod/core/ReplayModBackend.java | 21 + .../com/replaymod/core/versions/MCVer.java | 8 + .../core/versions/scheduler/Scheduler.java | 30 ++ .../versions/scheduler/SchedulerImpl.java | 124 ++++++ .../com/replaymod/extras/OpenEyeExtra.java | 4 +- .../handler/ConnectionEventHandler.java | 3 +- .../replaymod/replay/InputReplayTimer.java | 21 +- src/main/resources/fabric.mod.json | 2 +- .../com/replaymod/core/ReplayModBackend.java | 85 ++++ .../versions/scheduler/SchedulerImpl.java | 131 ++++++ .../com/replaymod/core/ReplayModBackend.java | 11 + 12 files changed, 443 insertions(+), 401 deletions(-) create mode 100644 src/main/java/com/replaymod/core/ReplayModBackend.java create mode 100644 src/main/java/com/replaymod/core/versions/scheduler/Scheduler.java create mode 100644 src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java create mode 100644 versions/1.12.2/src/main/java/com/replaymod/core/ReplayModBackend.java create mode 100644 versions/1.12.2/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java create mode 100644 versions/1.14.4-forge/src/main/java/com/replaymod/core/ReplayModBackend.java diff --git a/src/main/java/com/replaymod/core/ReplayMod.java b/src/main/java/com/replaymod/core/ReplayMod.java index c08416db..797ea79e 100644 --- a/src/main/java/com/replaymod/core/ReplayMod.java +++ b/src/main/java/com/replaymod/core/ReplayMod.java @@ -5,8 +5,9 @@ import com.replaymod.compat.ReplayModCompat; import com.replaymod.core.gui.GuiBackgroundProcesses; import com.replaymod.core.gui.GuiReplaySettings; import com.replaymod.core.gui.RestoreReplayGui; -import com.replaymod.core.mixin.MinecraftAccessor; import com.replaymod.core.versions.MCVer; +import com.replaymod.core.versions.scheduler.Scheduler; +import com.replaymod.core.versions.scheduler.SchedulerImpl; import com.replaymod.editor.ReplayModEditor; import com.replaymod.extras.ReplayModExtras; import com.replaymod.recording.ReplayModRecording; @@ -17,7 +18,6 @@ import com.replaymod.replaystudio.replay.ZipReplayFile; import com.replaymod.replaystudio.studio.ReplayStudio; import com.replaymod.replaystudio.us.myles.ViaVersion.api.protocol.ProtocolVersion; import com.replaymod.replaystudio.util.I18n; -import com.replaymod.replaystudio.viaversion.ViaVersionPacketConverter; import com.replaymod.simplepathing.ReplayModSimplePathing; import de.johni0702.minecraft.gui.container.GuiScreen; import net.minecraft.client.MinecraftClient; @@ -28,63 +28,13 @@ 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.FilenameUtils; import org.apache.commons.io.FileUtils; //#if MC>=11400 import net.minecraft.client.options.Option; -import net.minecraft.util.thread.ReentrantThreadExecutor; -//#endif - -//#if FABRIC>=1 -import net.fabricmc.api.ClientModInitializer; -import net.fabricmc.loader.api.FabricLoader; //#else -//$$ import com.google.common.util.concurrent.ListenableFutureTask; -//$$ import net.minecraftforge.eventbus.api.SubscribeEvent; -//$$ import java.util.Queue; -//$$ import java.util.concurrent.FutureTask; -//$$ -//#if MC>=11400 -//$$ import com.replaymod.core.versions.LangResourcePack; -//$$ import net.minecraft.resources.IPackFinder; -//$$ import net.minecraft.resources.ResourcePackInfo; -//$$ import net.minecraftforge.fml.DeferredWorkQueue; -//$$ import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; -//$$ import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -//$$ 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 -//$$ -//#if MC>=10800 -//$$ import net.minecraft.client.GameSettings; -//#endif -//$$ -//#if MC>=11400 -//$$ import net.minecraftforge.fml.ModList; -//#else -//$$ import net.minecraftforge.fml.common.Loader; -//$$ import net.minecraftforge.fml.common.Mod.EventHandler; -//$$ import net.minecraftforge.fml.common.Mod.Instance; -//$$ import net.minecraftforge.fml.common.event.FMLInitializationEvent; -//$$ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; -//#if MC>=10800 -//$$ import net.minecraftforge.fml.client.FMLClientHandler; -//#else -//$$ import com.replaymod.replay.InputReplayTimer; -//$$ -//$$ import java.util.ArrayDeque; -//#endif -//#endif -//$$ import net.minecraftforge.fml.common.Mod; -//#if MC<11400 -//$$ import net.minecraftforge.fml.common.gameevent.TickEvent; -//#endif +//$$ import net.minecraft.client.settings.GameSettings; //#endif import java.io.ByteArrayInputStream; @@ -102,43 +52,9 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -//#if FABRIC<=0 -//#if MC>=11400 -//$$ @Mod(ReplayMod.MOD_ID) -//#else -//$$ @Mod(modid = ReplayMod.MOD_ID, -//$$ useMetadata = true, -//$$ version = "@MOD_VERSION@", -//$$ acceptedMinecraftVersions = "@MC_VERSION@", -//$$ acceptableRemoteVersions = "*", - //#if MC>=10800 - //$$ clientSideOnly = true, - //$$ updateJSON = "https://raw.githubusercontent.com/ReplayMod/ReplayMod/master/versions.json", - //#endif -//$$ guiFactory = "com.replaymod.core.gui.GuiFactory") -//#endif -//#endif -public class ReplayMod implements - //#if FABRIC>=1 - ClientModInitializer, - //#endif - Module -{ - - public static String getMinecraftVersion() { - //#if MC>=11400 - return MinecraftClient.getInstance().getGame().getVersion().getName(); - //#else - //#if MC>=11400 - //$$ return MCPVersion.getMCVersion(); - //#else - //$$ return Loader.MC_VERSION; - //#endif - //#endif - } +public class ReplayMod implements Module, Scheduler { public static final String MOD_ID = "replaymod"; @@ -148,23 +64,15 @@ public class ReplayMod implements private static final MinecraftClient mc = MCVer.getMinecraft(); - //#if MC<11400 - //$$ @Deprecated - //$$ public static Configuration config; - //#endif - + private final ReplayModBackend backend; + private final SchedulerImpl scheduler = new SchedulerImpl(); private final KeyBindingRegistry keyBindingRegistry = new KeyBindingRegistry(); private final SettingsRegistry settingsRegistry = new SettingsRegistry(); { settingsRegistry.register(Setting.class); } - // The instance of your mod that Forge uses. - //#if MC>=11400 { instance = this; } - //#else - //$$ @Instance(MOD_ID) - //#endif public static ReplayMod instance; private final List modules = new ArrayList<>(); @@ -181,15 +89,15 @@ public class ReplayMod implements */ private boolean minimalMode; - public ReplayMod() { + public ReplayMod(ReplayModBackend backend) { + this.backend = backend; + I18n.setI18n(net.minecraft.client.resource.language.I18n::translate); - //#if MC>=11400 // Check Minecraft protocol version for compatibility if (!ProtocolVersion.isRegistered(MCVer.getProtocolVersion()) && !Boolean.parseBoolean(System.getProperty("replaymod.skipversioncheck", "false"))) { minimalMode = true; } - //#endif // Register all RM modules modules.add(this); @@ -205,16 +113,6 @@ public class ReplayMod implements settingsRegistry.register(); } - //#if MC<=11400 - //$$ @EventHandler - //$$ public void init(FMLPreInitializationEvent event) { - //$$ config = new Configuration(event.getSuggestedConfigurationFile()); - //$$ config.load(); - //$$ settingsRegistry.backend.setConfiguration(config); - //$$ settingsRegistry.save(); // Save default values to disk - //$$ } - //#endif - public KeyBindingRegistry getKeyBindingRegistry() { return keyBindingRegistry; } @@ -273,19 +171,14 @@ public class ReplayMod implements return replayFolder.resolve(relative); } - public static final DirectoryResourcePack jGuiResourcePack; + public static final DirectoryResourcePack jGuiResourcePack = createJGuiResourcePack(); public static final String JGUI_RESOURCE_PACK_NAME = "replaymod_jgui"; - static { // Note: even preInit is too late and we'd have to issue another resource reload - jGuiResourcePack = initJGuiResourcePack(); - } - - private static DirectoryResourcePack initJGuiResourcePack() { + private static DirectoryResourcePack createJGuiResourcePack() { File folder = new File("../jGui/src/main/resources"); if (!folder.exists()) { return null; } - //noinspection UnnecessaryLocalVariable - DirectoryResourcePack jGuiResourcePack = new DirectoryResourcePack(folder) { + return new DirectoryResourcePack(folder) { @Override //#if MC>=11400 public String getName() { @@ -313,56 +206,13 @@ public class ReplayMod implements } } }; - - //#if MC<=11202 - //$$ @SuppressWarnings("unchecked") - //$$ List defaultResourcePacks = ((MinecraftAccessor) mc).getDefaultResourcePacks(); - //$$ defaultResourcePacks.add(jGuiResourcePack); - //#endif - - //#if MC<=10710 - //$$ FolderResourcePack mainResourcePack = new FolderResourcePack(new File("../src/main/resources")) { - //$$ @Override - //$$ protected InputStream getInputStreamByName(String resourceName) throws IOException { - //$$ try { - //$$ return super.getInputStreamByName(resourceName); - //$$ } catch (IOException e) { - //$$ if ("pack.mcmeta".equals(resourceName)) { - //$$ return new ByteArrayInputStream(("{\"pack\": {\"description\": \"dummy pack for mod resources in dev-env\", \"pack_format\": 1}}").getBytes(StandardCharsets.UTF_8)); - //$$ } - //$$ throw e; - //$$ } - //$$ } - //$$ }; - //$$ defaultResourcePacks.add(mainResourcePack); - //#endif - - return jGuiResourcePack; } - //#if FABRIC>=1 - @Override - public void onInitializeClient() { + void initModules() { modules.forEach(Module::initCommon); modules.forEach(Module::initClient); modules.forEach(m -> m.registerKeyBindings(keyBindingRegistry)); } - //#else - //#if MC>=11400 - //$$ { - //$$ FMLJavaModLoadingContext.get().getModEventBus().addListener((FMLCommonSetupEvent event) -> modules.forEach(Module::initCommon)); - //$$ FMLJavaModLoadingContext.get().getModEventBus().addListener((FMLClientSetupEvent event) -> modules.forEach(Module::initClient)); - //$$ FMLJavaModLoadingContext.get().getModEventBus().addListener((FMLClientSetupEvent event) -> modules.forEach(m -> m.registerKeyBindings(keyBindingRegistry))); - //$$ } - //#else - //$$ @EventHandler - //$$ public void init(FMLInitializationEvent event) { - //$$ modules.forEach(Module::initCommon); - //$$ modules.forEach(Module::initClient); - //$$ modules.forEach(m -> m.registerKeyBindings(keyBindingRegistry)); - //$$ } - //#endif - //#endif @Override public void registerKeyBindings(KeyBindingRegistry registry) { @@ -373,10 +223,6 @@ public class ReplayMod implements @Override public void initClient() { - //#if MC<=10710 - //$$ FML_BUS.register(this); // For runLater(Runnable) - //#endif - backgroundProcesses.register(); keyBindingRegistry.register(); @@ -391,8 +237,6 @@ public class ReplayMod implements } //#endif - testIfMoeshAndExitMinecraft(); - runPostStartup(() -> { final long DAYS = 24 * 60 * 60 * 1000; @@ -491,231 +335,33 @@ public class ReplayMod implements }); } - /** - * Execute the given runnable on the main client thread, returning only after it has been run (or after 30 seconds). - */ + @Override public void runSync(Runnable runnable) throws InterruptedException, ExecutionException, TimeoutException { - //#if MC>=11400 - if (mc.isOnThread()) { - runnable.run(); - } else { - executor.submit(() -> { - runnable.run(); - return null; - }).get(30, TimeUnit.SECONDS); - } - //#else - //$$ if (mc.isCallingFromMinecraftThread()) { - //$$ runnable.run(); - //$$ } else { - //$$ FutureTask future = new FutureTask<>(runnable, null); - //$$ runLater(future); - //$$ future.get(30, TimeUnit.SECONDS); - //$$ } - //#endif + scheduler.runSync(runnable); } - /** - * Execute the given runnable after game has started (once the overlay has been closed). - * Most importantly, it will run after resources (including language keys!) have been loaded. - * Below 1.14, this is equivalent to {@link #runLater(Runnable)}. - */ + @Override public void runPostStartup(Runnable runnable) { - runLater(new Runnable() { - @Override - public void run() { - //#if MC>=11400 - if (getMinecraft().overlay != null) { - // delay until after resources have been loaded - runLater(this); - return; - } - //#endif - runnable.run(); - } - }); + scheduler.runPostStartup(runnable); } - /** - * Set when the currently running code has been scheduled by runLater. - * If this is the case, subsequent calls to runLater have to be delayed until all scheduled tasks have been - * processed, otherwise a livelock may occur. - */ - private boolean inRunLater = false; - //#if MC>=11400 - private boolean inRenderTaskQueue = false; - // Starting 1.14 MC clears the queue of scheduled tasks on disconnect. - // This works fine for MC since it uses the queue only for packet handling but breaks our assumption that - // stuff submitted via runLater is actually always run (e.g. recording might not be fully stopped because parts - // of that are run via runLater and stopping the recording happens right around the time MC clears the queue). - // Luckily, that's also the version where MC pulled out the executor implementation, so we can just spin up our own. - public static class ReplayModExecutor extends ReentrantThreadExecutor { - private final Thread mcThread = Thread.currentThread(); - // Fail-fast in case we ever switch to async loading and forget to change this - // (except for fabric 1.15+ because it loads the mod before the client thread is set) - //#if FABRIC<1 || MC<11500 - //$$ { if (!MinecraftClient.getInstance().isOnThread()) throw new RuntimeException(); } - //#endif - - private ReplayModExecutor(String string_1) { - super(string_1); - } - - @Override - protected Runnable createTask(Runnable runnable) { - return runnable; - } - - @Override - protected boolean canExecute(Runnable runnable) { - return true; - } - - @Override - protected Thread getThread() { - return mcThread; - } - - @Override - public void runTasks() { - super.runTasks(); - } - } - public final ReplayModExecutor executor = new ReplayModExecutor("Client/ReplayMod"); - //#endif - - // Pre-1.14 MC would hold the lock on the scheduledTasks queue while executing its tasks - // such that no new tasks could be submitted while one of them was running. - // This would cause issues with long-running tasks (e.g. video rendering) as it would - // block all async tasks (e.g. skin loading). + @Override public void runLaterWithoutLock(Runnable runnable) { - //#if MC>=11400 - // MC 1.14+ no longer synchronizes on the queue while running its tasks - runLater(runnable); - //#else - //$$ runLater(() -> runLaterWithoutLock(runnable), runnable); - //#endif + scheduler.runLaterWithoutLock(runnable); } + @Override public void runLater(Runnable runnable) { - runLater(runnable, () -> runLater(runnable)); + scheduler.runLater(runnable); } - private void runLater(Runnable runnable, Runnable defer) { - //#if MC>=11400 - if (mc.isOnThread() && inRunLater && !inRenderTaskQueue) { - ((MinecraftAccessor) mc).getRenderTaskQueue().offer(() -> { - inRenderTaskQueue = true; - try { - defer.run(); - } finally { - inRenderTaskQueue = false; - } - }); - } else { - executor.send(() -> { - inRunLater = true; - try { - runnable.run(); - } catch (CrashException e) { - e.printStackTrace(); - System.err.println(e.getReport().asString()); - mc.setCrashReport(e.getReport()); - } finally { - inRunLater = false; - } - }); - } - //#else - //$$ if (mc.isCallingFromMinecraftThread() && inRunLater) { - //#if MC>=10800 - //$$ FML_BUS.register(new Object() { - //$$ @SubscribeEvent - //$$ public void onRenderTick(TickEvent.RenderTickEvent event) { - //$$ if (event.phase == TickEvent.Phase.START) { - //$$ FML_BUS.unregister(this); - //$$ defer.run(); - //$$ } - //$$ } - //$$ }); - //#else - //$$ FML_BUS.register(new RunLaterHelper(defer)); - //#endif - //$$ return; - //$$ } - //#if MC>=10800 - //$$ Queue> tasks = ((MinecraftAccessor) mc).getScheduledTasks(); - //$$ //noinspection SynchronizationOnLocalVariableOrMethodParameter - //$$ synchronized (tasks) { - //#else - //$$ Queue> tasks = scheduledTasks; - //$$ synchronized (scheduledTasks) { - //#endif - //$$ tasks.add(ListenableFutureTask.create(() -> { - //$$ inRunLater = true; - //$$ try { - //$$ runnable.run(); - //$$ } catch (ReportedException e) { - //$$ e.printStackTrace(); - //$$ System.err.println(e.getCrashReport().getCompleteReport()); - //$$ mc.crashed(e.getCrashReport()); - //$$ } finally { - //$$ inRunLater = false; - //$$ } - //$$ }, null)); - //$$ } - //#endif + @Override + public void runTasks() { + scheduler.runTasks(); } - //#if MC<=10710 - //$$ // 1.7.10: Cannot use MC's because it is processed only during ticks (so not at all when replay is paused) - //$$ private final Queue> scheduledTasks = new ArrayDeque<>(); - //$$ - //$$ // in 1.7.10 apparently events can't be delivered to anonymous classes - //$$ public class RunLaterHelper { - //$$ private final Runnable defer; - //$$ - //$$ private RunLaterHelper(Runnable defer) { - //$$ this.defer = defer; - //$$ } - //$$ - //$$ @SubscribeEvent - //$$ public void onRenderTick(TickEvent.RenderTickEvent event) { - //$$ if (event.phase == TickEvent.Phase.START) { - //$$ FML_BUS.unregister(this); - //$$ defer.run(); - //$$ } - //$$ } - //$$ } - //$$ - //$$ @SubscribeEvent - //$$ public void runScheduledTasks(InputReplayTimer.RunScheduledTasks event) { - //$$ synchronized (scheduledTasks) { - //$$ while (!scheduledTasks.isEmpty()) { - //$$ scheduledTasks.poll().run(); - //$$ } - //$$ } - //$$ } - //#endif - public String getVersion() { - //#if FABRIC>=1 - return FabricLoader.getInstance().getModContainer(MOD_ID) - .orElseThrow(IllegalStateException::new) - .getMetadata().getVersion().toString(); - //#else - //#if MC>=11400 - //$$ return ModList.get().getModContainerById(MOD_ID).get().getModInfo().getVersion().toString(); - //#else - //$$ return Loader.instance().getIndexedModList().get(MOD_ID).getVersion(); - //#endif - //#endif - } - - private void testIfMoeshAndExitMinecraft() { - if("currentPlayer".equals("Moesh")) { - System.exit(-1); - } + return backend.getVersion(); } public MinecraftClient getMinecraft() { diff --git a/src/main/java/com/replaymod/core/ReplayModBackend.java b/src/main/java/com/replaymod/core/ReplayModBackend.java new file mode 100644 index 00000000..826f10f9 --- /dev/null +++ b/src/main/java/com/replaymod/core/ReplayModBackend.java @@ -0,0 +1,21 @@ +package com.replaymod.core; + +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.loader.api.FabricLoader; + +import static com.replaymod.core.ReplayMod.MOD_ID; + +public class ReplayModBackend implements ClientModInitializer { + private final ReplayMod mod = new ReplayMod(this); + + @Override + public void onInitializeClient() { + mod.initModules(); + } + + public String getVersion() { + return FabricLoader.getInstance().getModContainer(MOD_ID) + .orElseThrow(IllegalStateException::new) + .getMetadata().getVersion().toString(); + } +} diff --git a/src/main/java/com/replaymod/core/versions/MCVer.java b/src/main/java/com/replaymod/core/versions/MCVer.java index 75d17f50..83e44b1c 100644 --- a/src/main/java/com/replaymod/core/versions/MCVer.java +++ b/src/main/java/com/replaymod/core/versions/MCVer.java @@ -176,6 +176,14 @@ public class MCVer { ); } + public static String getMinecraftVersion() { + //#if MC>=11400 + return getMinecraft().getGame().getVersion().getName(); + //#else + //$$ return Loader.MC_VERSION; + //#endif + } + public static void addDetail(CrashReportSection category, String name, Callable callable) { //#if MC>=10904 //#if MC>=11200 diff --git a/src/main/java/com/replaymod/core/versions/scheduler/Scheduler.java b/src/main/java/com/replaymod/core/versions/scheduler/Scheduler.java new file mode 100644 index 00000000..df66ddc3 --- /dev/null +++ b/src/main/java/com/replaymod/core/versions/scheduler/Scheduler.java @@ -0,0 +1,30 @@ +package com.replaymod.core.versions.scheduler; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +public interface Scheduler { + /** + * Execute the given runnable on the main client thread, returning only after it has been run (or after 30 seconds). + */ + void runSync(Runnable runnable) throws InterruptedException, ExecutionException, TimeoutException; + + /** + * Execute the given runnable after game has started (once the overlay has been closed). + * Most importantly, it will run after resources (including language keys!) have been loaded. + * Below 1.14, this is equivalent to {@link #runLater(Runnable)}. + */ + void runPostStartup(Runnable runnable); + + /** + * Pre-1.14 MC would hold the lock on the scheduledTasks queue while executing its tasks + * such that no new tasks could be submitted while one of them was running. + * This would cause issues with long-running tasks (e.g. video rendering) as it would + * block all async tasks (e.g. skin loading). + */ + void runLaterWithoutLock(Runnable runnable); + + void runLater(Runnable runnable); + + void runTasks(); +} diff --git a/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java b/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java new file mode 100644 index 00000000..2da1760a --- /dev/null +++ b/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java @@ -0,0 +1,124 @@ +package com.replaymod.core.versions.scheduler; + +import com.replaymod.core.mixin.MinecraftAccessor; +import net.minecraft.client.MinecraftClient; +import net.minecraft.util.crash.CrashException; +import net.minecraft.util.thread.ReentrantThreadExecutor; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class SchedulerImpl implements Scheduler { + private static final MinecraftClient mc = MinecraftClient.getInstance(); + + @Override + public void runSync(Runnable runnable) throws InterruptedException, ExecutionException, TimeoutException { + if (mc.isOnThread()) { + runnable.run(); + } else { + executor.submit(() -> { + runnable.run(); + return null; + }).get(30, TimeUnit.SECONDS); + } + } + + @Override + public void runPostStartup(Runnable runnable) { + runLater(new Runnable() { + @Override + public void run() { + if (mc.overlay != null) { + // delay until after resources have been loaded + runLater(this); + return; + } + runnable.run(); + } + }); + } + + /** + * Set when the currently running code has been scheduled by runLater. + * If this is the case, subsequent calls to runLater have to be delayed until all scheduled tasks have been + * processed, otherwise a livelock may occur. + */ + private boolean inRunLater = false; + private boolean inRenderTaskQueue = false; + // Starting 1.14 MC clears the queue of scheduled tasks on disconnect. + // This works fine for MC since it uses the queue only for packet handling but breaks our assumption that + // stuff submitted via runLater is actually always run (e.g. recording might not be fully stopped because parts + // of that are run via runLater and stopping the recording happens right around the time MC clears the queue). + // Luckily, that's also the version where MC pulled out the executor implementation, so we can just spin up our own. + public static class ReplayModExecutor extends ReentrantThreadExecutor { + private final Thread mcThread = Thread.currentThread(); + + private ReplayModExecutor(String string_1) { + super(string_1); + } + + @Override + protected Runnable createTask(Runnable runnable) { + return runnable; + } + + @Override + protected boolean canExecute(Runnable runnable) { + return true; + } + + @Override + protected Thread getThread() { + return mcThread; + } + + @Override + public void runTasks() { + super.runTasks(); + } + } + public final ReplayModExecutor executor = new ReplayModExecutor("Client/ReplayMod"); + + @Override + public void runTasks() { + executor.runTasks(); + } + + @Override + public void runLaterWithoutLock(Runnable runnable) { + // MC 1.14+ no longer synchronizes on the queue while running its tasks + runLater(runnable); + } + + @Override + public void runLater(Runnable runnable) { + runLater(runnable, () -> runLater(runnable)); + } + + private void runLater(Runnable runnable, Runnable defer) { + if (mc.isOnThread() && inRunLater && !inRenderTaskQueue) { + ((MinecraftAccessor) mc).getRenderTaskQueue().offer(() -> { + inRenderTaskQueue = true; + try { + defer.run(); + } finally { + inRenderTaskQueue = false; + } + }); + } else { + executor.send(() -> { + inRunLater = true; + try { + runnable.run(); + } catch (CrashException e) { + e.printStackTrace(); + System.err.println(e.getReport().asString()); + mc.setCrashReport(e.getReport()); + } finally { + inRunLater = false; + } + }); + } + } +} diff --git a/src/main/java/com/replaymod/extras/OpenEyeExtra.java b/src/main/java/com/replaymod/extras/OpenEyeExtra.java index 49675f01..9c7b6941 100644 --- a/src/main/java/com/replaymod/extras/OpenEyeExtra.java +++ b/src/main/java/com/replaymod/extras/OpenEyeExtra.java @@ -28,7 +28,7 @@ import static com.replaymod.core.utils.Utils.SSL_SOCKET_FACTORY; import static com.replaymod.extras.ReplayModExtras.LOGGER; public class OpenEyeExtra implements Extra { - private static final String DOWNLOAD_URL = "https://www.replaymod.com/dl/openeye/" + ReplayMod.getMinecraftVersion(); + private static final String DOWNLOAD_URL = "https://www.replaymod.com/dl/openeye/" + MCVer.getMinecraftVersion(); private ReplayMod mod; @@ -86,7 +86,7 @@ public class OpenEyeExtra implements Extra { GuiPopup popup = new GuiPopup(OfferGui.this); new Thread(() -> { try { - File targetFile = new File(mod.getMinecraft().runDirectory, "mods/" + ReplayMod.getMinecraftVersion() + "/OpenEye.jar"); + File targetFile = new File(mod.getMinecraft().runDirectory, "mods/" + MCVer.getMinecraftVersion() + "/OpenEye.jar"); FileUtils.forceMkdir(targetFile.getParentFile()); HttpsURLConnection connection = (HttpsURLConnection) new URL(DOWNLOAD_URL).openConnection(); diff --git a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java index 9707020a..4c638f50 100644 --- a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java @@ -3,6 +3,7 @@ package com.replaymod.recording.handler; import com.replaymod.core.ReplayMod; import com.replaymod.core.utils.ModCompat; import com.replaymod.core.utils.Utils; +import com.replaymod.core.versions.MCVer; import com.replaymod.editor.gui.MarkerProcessor; import com.replaymod.recording.ServerInfoExt; import com.replaymod.recording.Setting; @@ -137,7 +138,7 @@ public class ConnectionEventHandler { metaData.setCustomServerName(serverName); metaData.setGenerator("ReplayMod v" + ReplayMod.instance.getVersion()); metaData.setDate(System.currentTimeMillis()); - metaData.setMcVersion(ReplayMod.getMinecraftVersion()); + metaData.setMcVersion(MCVer.getMinecraftVersion()); packetListener = new PacketListener(core, outputPath, replayFile, metaData); Channel channel = ((NetworkManagerAccessor) networkManager).getChannel(); channel.pipeline().addBefore(packetHandlerKey, "replay_recorder", packetListener); diff --git a/src/main/java/com/replaymod/replay/InputReplayTimer.java b/src/main/java/com/replaymod/replay/InputReplayTimer.java index 3f5c8ec5..394fdd50 100644 --- a/src/main/java/com/replaymod/replay/InputReplayTimer.java +++ b/src/main/java/com/replaymod/replay/InputReplayTimer.java @@ -1,5 +1,6 @@ package com.replaymod.replay; +import com.replaymod.core.ReplayMod; import com.replaymod.core.utils.WrappedTimer; import com.replaymod.core.versions.MCVer; import com.replaymod.replay.camera.CameraController; @@ -7,10 +8,6 @@ import com.replaymod.replay.camera.CameraEntity; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.RenderTickCounter; -//#if MC>=11400 -import com.replaymod.core.ReplayMod; -//#endif - //#if MC>=11400 import org.lwjgl.glfw.GLFW; //#else @@ -22,10 +19,7 @@ import org.lwjgl.glfw.GLFW; //$$ import java.io.IOException; //#else //$$ import com.replaymod.replay.gui.screen.GuiOpeningReplay; -//$$ import cpw.mods.fml.common.eventhandler.Event; //$$ import net.minecraft.client.renderer.entity.RenderManager; -//$$ -//$$ import static com.replaymod.core.versions.MCVer.FML_BUS; //#endif //#endif @@ -65,10 +59,9 @@ public class InputReplayTimer extends WrappedTimer { //#endif ); - // 1.7.10: We have to run the scheduled executables (ours only) because MC would only run them every tick + ReplayMod.instance.runTasks(); + //#if MC<=10710 - //$$ FML_BUS.post(new RunScheduledTasks()); - //$$ //$$ // Code below only updates the current screen when a world and player is loaded. This may not be the case for //$$ // the GuiOpeningReplay screen resulting in a livelock. //$$ // To counteract that, we always update that screen (doesn't matter if we do it twice). @@ -77,10 +70,6 @@ public class InputReplayTimer extends WrappedTimer { //$$ } //#endif - //#if MC>=11400 - ReplayMod.instance.executor.runTasks(); - //#endif - // If we are in a replay, we have to manually process key and mouse events as the // tick speed may vary or there may not be any ticks at all (when the replay is paused) if (mod.getReplayHandler() != null && mc.world != null && mc.player != null) { @@ -147,8 +136,4 @@ public class InputReplayTimer extends WrappedTimer { } } } - - //#if MC<=10710 - //$$ public static class RunScheduledTasks extends Event {} - //#endif } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 6bc530eb..8dc61a19 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -20,7 +20,7 @@ "environment": "client", "entrypoints": { "client": [ - "com.replaymod.core.ReplayMod" + "com.replaymod.core.ReplayModBackend" ], "modmenu": [ "com.replaymod.core.gui.ModMenuApiImpl" diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/ReplayModBackend.java b/versions/1.12.2/src/main/java/com/replaymod/core/ReplayModBackend.java new file mode 100644 index 00000000..75fb9e91 --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/core/ReplayModBackend.java @@ -0,0 +1,85 @@ +package com.replaymod.core; + +import com.replaymod.core.mixin.MinecraftAccessor; +import net.minecraft.client.resources.IResourcePack; +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventHandler; +import net.minecraftforge.fml.common.event.FMLInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; + +import java.util.List; + +import static com.replaymod.core.ReplayMod.MOD_ID; +import static com.replaymod.core.ReplayMod.jGuiResourcePack; +import static com.replaymod.core.versions.MCVer.getMinecraft; + +//#if MC<=10710 +//$$ import net.minecraft.client.resources.FolderResourcePack; +//$$ import java.io.ByteArrayInputStream; +//$$ import java.io.File; +//$$ import java.io.IOException; +//$$ import java.io.InputStream; +//$$ import java.nio.charset.StandardCharsets; +//#endif + +@Mod(modid = ReplayMod.MOD_ID, + useMetadata = true, + version = "@MOD_VERSION@", + acceptedMinecraftVersions = "@MC_VERSION@", + acceptableRemoteVersions = "*", + //#if MC>=10800 + clientSideOnly = true, + updateJSON = "https://raw.githubusercontent.com/ReplayMod/ReplayMod/master/versions.json", + //#endif + guiFactory = "com.replaymod.core.gui.GuiFactory") +public class ReplayModBackend { + private final ReplayMod mod = new ReplayMod(this); + + @Deprecated + public static Configuration config; + + @EventHandler + public void init(FMLPreInitializationEvent event) { + config = new Configuration(event.getSuggestedConfigurationFile()); + config.load(); + SettingsRegistry settingsRegistry = mod.getSettingsRegistry(); + settingsRegistry.backend.setConfiguration(config); + settingsRegistry.save(); // Save default values to disk + } + + @EventHandler + public void init(FMLInitializationEvent event) { + mod.initModules(); + } + + public String getVersion() { + return Loader.instance().getIndexedModList().get(MOD_ID).getVersion(); + } + + static { // Note: even preInit is too late and we'd have to issue another resource reload + List defaultResourcePacks = ((MinecraftAccessor) getMinecraft()).getDefaultResourcePacks(); + + if (jGuiResourcePack != null) { + defaultResourcePacks.add(jGuiResourcePack); + } + + //#if MC<=10710 + //$$ FolderResourcePack mainResourcePack = new FolderResourcePack(new File("../src/main/resources")) { + //$$ @Override + //$$ protected InputStream getInputStreamByName(String resourceName) throws IOException { + //$$ try { + //$$ return super.getInputStreamByName(resourceName); + //$$ } catch (IOException e) { + //$$ if ("pack.mcmeta".equals(resourceName)) { + //$$ return new ByteArrayInputStream(("{\"pack\": {\"description\": \"dummy pack for mod resources in dev-env\", \"pack_format\": 1}}").getBytes(StandardCharsets.UTF_8)); + //$$ } + //$$ throw e; + //$$ } + //$$ } + //$$ }; + //$$ defaultResourcePacks.add(mainResourcePack); + //#endif + } +} diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java b/versions/1.12.2/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java new file mode 100644 index 00000000..9938ce24 --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java @@ -0,0 +1,131 @@ +package com.replaymod.core.versions.scheduler; + +import com.google.common.util.concurrent.ListenableFutureTask; +import com.replaymod.core.mixin.MinecraftAccessor; +import net.minecraft.client.Minecraft; +import net.minecraft.util.ReportedException; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +import java.util.Queue; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +//#if MC<10800 +//$$ import java.util.ArrayDeque; +//#endif + +import static com.replaymod.core.versions.MCVer.FML_BUS; + +public class SchedulerImpl implements Scheduler { + private static final Minecraft mc = Minecraft.getMinecraft(); + + @Override + public void runSync(Runnable runnable) throws InterruptedException, ExecutionException, TimeoutException { + if (mc.isCallingFromMinecraftThread()) { + runnable.run(); + } else { + FutureTask future = new FutureTask<>(runnable, null); + runLater(future); + future.get(30, TimeUnit.SECONDS); + } + } + + @Override + public void runPostStartup(Runnable runnable) { + runLater(runnable); + } + + /** + * Set when the currently running code has been scheduled by runLater. + * If this is the case, subsequent calls to runLater have to be delayed until all scheduled tasks have been + * processed, otherwise a livelock may occur. + */ + private boolean inRunLater = false; + + @Override + public void runLaterWithoutLock(Runnable runnable) { + runLater(() -> runLaterWithoutLock(runnable), runnable); + } + + public void runLater(Runnable runnable) { + runLater(runnable, () -> runLater(runnable)); + } + + private void runLater(Runnable runnable, Runnable defer) { + if (mc.isCallingFromMinecraftThread() && inRunLater) { + //#if MC>=10800 + FML_BUS.register(new Object() { + @SubscribeEvent + public void onRenderTick(TickEvent.RenderTickEvent event) { + if (event.phase == TickEvent.Phase.START) { + FML_BUS.unregister(this); + defer.run(); + } + } + }); + //#else + //$$ FML_BUS.register(new RunLaterHelper(defer)); + //#endif + return; + } + //#if MC>=10800 + Queue> tasks = ((MinecraftAccessor) mc).getScheduledTasks(); + //noinspection SynchronizationOnLocalVariableOrMethodParameter + synchronized (tasks) { + //#else + //$$ Queue> tasks = scheduledTasks; + //$$ synchronized (scheduledTasks) { + //#endif + tasks.add(ListenableFutureTask.create(() -> { + inRunLater = true; + try { + runnable.run(); + } catch (ReportedException e) { + e.printStackTrace(); + System.err.println(e.getCrashReport().getCompleteReport()); + mc.crashed(e.getCrashReport()); + } finally { + inRunLater = false; + } + }, null)); + } + } + + //#if MC>=10800 + @Override + public void runTasks() { + } + //#else + //$$ // 1.7.10: Cannot use MC's because it is processed only during ticks (so not at all when replay is paused) + //$$ private final Queue> scheduledTasks = new ArrayDeque<>(); + //$$ + //$$ // in 1.7.10 apparently events can't be delivered to anonymous classes + //$$ public class RunLaterHelper { + //$$ private final Runnable defer; + //$$ + //$$ private RunLaterHelper(Runnable defer) { + //$$ this.defer = defer; + //$$ } + //$$ + //$$ @SubscribeEvent + //$$ public void onRenderTick(TickEvent.RenderTickEvent event) { + //$$ if (event.phase == TickEvent.Phase.START) { + //$$ FML_BUS.unregister(this); + //$$ defer.run(); + //$$ } + //$$ } + //$$ } + //$$ + //$$ @Override + //$$ public void runTasks() { + //$$ synchronized (scheduledTasks) { + //$$ while (!scheduledTasks.isEmpty()) { + //$$ scheduledTasks.poll().run(); + //$$ } + //$$ } + //$$ } + //#endif +} diff --git a/versions/1.14.4-forge/src/main/java/com/replaymod/core/ReplayModBackend.java b/versions/1.14.4-forge/src/main/java/com/replaymod/core/ReplayModBackend.java new file mode 100644 index 00000000..3527ca6d --- /dev/null +++ b/versions/1.14.4-forge/src/main/java/com/replaymod/core/ReplayModBackend.java @@ -0,0 +1,11 @@ +package com.replaymod.core; + +import net.minecraftforge.fml.ModList; + +import static com.replaymod.core.ReplayMod.MOD_ID; + +public class ReplayModBackend { + public String getVersion() { + return ModList.get().getModContainerById(MOD_ID).get().getModInfo().getVersion().toString(); + } +} From 633bc19650025391c24a2fdc1401df486d00dbf5 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 22 Feb 2021 23:11:34 +0100 Subject: [PATCH 008/102] Use callback-style events throughout all versions Removes the need for //#if statements on each and every event handler. Instead we now always use the equivalent Callback and have one central 1.12.2 class which forwards Forge events to the callbacks. --- jGui | 2 +- .../compat/shaders/ShaderBeginRender.java | 14 +---- .../replaymod/core/KeyBindingRegistry.java | 18 +----- .../core/events/PostRenderCallback.java | 2 - .../core/events/PostRenderWorldCallback.java | 21 +------ .../core/events/PreRenderCallback.java | 2 - .../core/events/PreRenderHandCallback.java | 2 - .../core/gui/GuiBackgroundProcesses.java | 17 +---- .../core/mixin/MixinGameRenderer.java | 14 ++--- .../core/versions/forge/EventsAdapter.java | 1 + .../replaymod/editor/handler/GuiHandler.java | 25 ++------ .../com/replaymod/extras/FullBrightness.java | 22 +------ .../extras/playeroverview/PlayerOverview.java | 22 +------ .../extras/youtube/YoutubeUpload.java | 25 ++------ .../recording/gui/GuiRecordingControls.java | 31 +++------- .../recording/gui/GuiRecordingOverlay.java | 17 +---- .../recording/handler/GuiHandler.java | 20 +----- .../handler/RecordingEventHandler.java | 20 +----- .../render/hooks/EntityRendererHandler.java | 4 +- .../replaymod/replay/FullReplaySender.java | 23 +------ .../replaymod/replay/QuickReplaySender.java | 16 +---- .../replaymod/replay/camera/CameraEntity.java | 62 +++---------------- .../replay/gui/overlay/GuiReplayOverlay.java | 7 +-- .../replaymod/replay/handler/GuiHandler.java | 27 +------- .../preview/PathPreviewRenderer.java | 21 +------ .../com/replaymod/core/ReplayModBackend.java | 3 + .../core/versions/forge/EventsAdapter.java | 50 +++++++++++++++ 27 files changed, 110 insertions(+), 378 deletions(-) create mode 100644 src/main/java/com/replaymod/core/versions/forge/EventsAdapter.java create mode 100644 versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/EventsAdapter.java diff --git a/jGui b/jGui index 80ff9223..96edf0fe 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 80ff9223d3fd3947f76b8535e73e0fd62a9fab1c +Subproject commit 96edf0fe31a1bef9ed286c01af994527566ab45c diff --git a/src/main/java/com/replaymod/compat/shaders/ShaderBeginRender.java b/src/main/java/com/replaymod/compat/shaders/ShaderBeginRender.java index f9fd2cf5..fd7048be 100644 --- a/src/main/java/com/replaymod/compat/shaders/ShaderBeginRender.java +++ b/src/main/java/com/replaymod/compat/shaders/ShaderBeginRender.java @@ -1,6 +1,7 @@ //#if MC>=10800 package com.replaymod.compat.shaders; +import com.replaymod.core.events.PreRenderCallback; import com.replaymod.render.hooks.EntityRendererHandler; import de.johni0702.minecraft.gui.utils.EventRegistrations; import net.minecraft.client.MinecraftClient; @@ -9,13 +10,6 @@ import java.lang.reflect.InvocationTargetException; import static com.replaymod.core.versions.MCVer.getRenderPartialTicks; -//#if FABRIC>=1 -import com.replaymod.core.events.PreRenderCallback; -//#else -//$$ import net.minecraftforge.eventbus.api.SubscribeEvent; -//$$ import net.minecraftforge.event.TickEvent; -//#endif - public class ShaderBeginRender extends EventRegistrations { private final MinecraftClient mc = MinecraftClient.getInstance(); @@ -25,14 +19,8 @@ public class ShaderBeginRender extends EventRegistrations { * as this would usually get called by EntityRenderer#renderWorld, * which we're not calling during rendering. */ - //#if FABRIC>=1 { on(PreRenderCallback.EVENT, this::onRenderTickStart); } private void onRenderTickStart() { - //#else - //$$ @SubscribeEvent - //$$ public void onRenderTickStart(TickEvent.RenderTickEvent event) { - //$$ if (event.phase != TickEvent.Phase.START) return; - //#endif if (ShaderReflection.shaders_beginRender == null) return; if (ShaderReflection.config_isShaders == null) return; diff --git a/src/main/java/com/replaymod/core/KeyBindingRegistry.java b/src/main/java/com/replaymod/core/KeyBindingRegistry.java index 3c6d2d14..9884c9c6 100644 --- a/src/main/java/com/replaymod/core/KeyBindingRegistry.java +++ b/src/main/java/com/replaymod/core/KeyBindingRegistry.java @@ -2,6 +2,7 @@ package com.replaymod.core; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; +import com.replaymod.core.events.PreRenderCallback; import com.replaymod.core.mixin.KeyBindingAccessor; import de.johni0702.minecraft.gui.utils.EventRegistrations; import com.replaymod.core.events.KeyBindingEventCallback; @@ -22,15 +23,6 @@ import static com.replaymod.core.ReplayMod.MOD_ID; //$$ import net.minecraftforge.fml.client.registry.ClientRegistry; //#endif -//#if MC>=11400 -import com.replaymod.core.events.PreRenderCallback; -//#else -//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -//$$ import net.minecraftforge.fml.common.gameevent.TickEvent; -//$$ import org.lwjgl.input.Keyboard; -//$$ import static com.replaymod.core.versions.MCVer.FML_BUS; -//#endif - import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -102,15 +94,7 @@ public class KeyBindingRegistry extends EventRegistrations { return Collections.unmodifiableSet(onlyInReplay); } - //#if MC>=11400 { on(PreRenderCallback.EVENT, this::handleRepeatedKeyBindings); } - //#else - //$$ @SubscribeEvent - //$$ public void onTick(TickEvent.RenderTickEvent event) { - //$$ if (event.phase != TickEvent.Phase.START) return; - //$$ handleRepeatedKeyBindings(); - //$$ } - //#endif public void handleRepeatedKeyBindings() { for (Binding binding : bindings.values()) { diff --git a/src/main/java/com/replaymod/core/events/PostRenderCallback.java b/src/main/java/com/replaymod/core/events/PostRenderCallback.java index c508b949..a72f0d6c 100644 --- a/src/main/java/com/replaymod/core/events/PostRenderCallback.java +++ b/src/main/java/com/replaymod/core/events/PostRenderCallback.java @@ -1,4 +1,3 @@ -//#if MC>=11400 package com.replaymod.core.events; import de.johni0702.minecraft.gui.utils.Event; @@ -14,4 +13,3 @@ public interface PostRenderCallback { void postRender(); } -//#endif diff --git a/src/main/java/com/replaymod/core/events/PostRenderWorldCallback.java b/src/main/java/com/replaymod/core/events/PostRenderWorldCallback.java index 9e8cb335..1445ae43 100644 --- a/src/main/java/com/replaymod/core/events/PostRenderWorldCallback.java +++ b/src/main/java/com/replaymod/core/events/PostRenderWorldCallback.java @@ -1,33 +1,16 @@ -//#if MC>=11400 package com.replaymod.core.events; import de.johni0702.minecraft.gui.utils.Event; - -//#if MC>=11500 import net.minecraft.client.util.math.MatrixStack; -//#endif public interface PostRenderWorldCallback { Event EVENT = Event.create((listeners) -> - //#if MC>=11500 (MatrixStack matrixStack) -> { - //#else - //$$ () -> { - //#endif for (PostRenderWorldCallback listener : listeners) { - listener.postRenderWorld( - //#if MC>=11500 - matrixStack - //#endif - ); + listener.postRenderWorld(matrixStack); } } ); - void postRenderWorld( - //#if MC>=11500 - MatrixStack matrixStack - //#endif - ); + void postRenderWorld(MatrixStack matrixStack); } -//#endif diff --git a/src/main/java/com/replaymod/core/events/PreRenderCallback.java b/src/main/java/com/replaymod/core/events/PreRenderCallback.java index 65afa3e3..907ed0cb 100644 --- a/src/main/java/com/replaymod/core/events/PreRenderCallback.java +++ b/src/main/java/com/replaymod/core/events/PreRenderCallback.java @@ -1,4 +1,3 @@ -//#if MC>=11400 package com.replaymod.core.events; import de.johni0702.minecraft.gui.utils.Event; @@ -14,4 +13,3 @@ public interface PreRenderCallback { void preRender(); } -//#endif diff --git a/src/main/java/com/replaymod/core/events/PreRenderHandCallback.java b/src/main/java/com/replaymod/core/events/PreRenderHandCallback.java index d5d8d268..ea231cf6 100644 --- a/src/main/java/com/replaymod/core/events/PreRenderHandCallback.java +++ b/src/main/java/com/replaymod/core/events/PreRenderHandCallback.java @@ -1,4 +1,3 @@ -//#if MC>=11400 package com.replaymod.core.events; import de.johni0702.minecraft.gui.utils.Event; @@ -17,4 +16,3 @@ public interface PreRenderHandCallback { boolean preRenderHand(); } -//#endif diff --git a/src/main/java/com/replaymod/core/gui/GuiBackgroundProcesses.java b/src/main/java/com/replaymod/core/gui/GuiBackgroundProcesses.java index 39b71973..27f6834d 100644 --- a/src/main/java/com/replaymod/core/gui/GuiBackgroundProcesses.java +++ b/src/main/java/com/replaymod/core/gui/GuiBackgroundProcesses.java @@ -12,30 +12,15 @@ import de.johni0702.minecraft.gui.layout.VerticalLayout; import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.utils.lwjgl.Dimension; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; - -//#if FABRIC>=1 import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback; -import net.minecraft.client.gui.screen.Screen; -//#else -//$$ import net.minecraftforge.client.event.GuiScreenEvent; -//$$ import net.minecraftforge.common.MinecraftForge; -//$$ import net.minecraftforge.eventbus.api.SubscribeEvent; -//$$ import static com.replaymod.core.versions.MCVer.getGui; -//#endif import static com.replaymod.core.versions.MCVer.getMinecraft; public class GuiBackgroundProcesses extends EventRegistrations { private GuiPanel panel = new GuiPanel().setLayout(new VerticalLayout().setSpacing(10)); - //#if FABRIC>=1 { on(InitScreenCallback.EVENT, (screen, buttons) -> onGuiInit(screen)); } - private void onGuiInit(Screen guiScreen) { - //#else - //$$ @SubscribeEvent - //$$ public void onGuiInit(GuiScreenEvent.InitGuiEvent.Post event) { - //$$ net.minecraft.client.gui.screen.Screen guiScreen = getGui(event); - //#endif + private void onGuiInit(net.minecraft.client.gui.screen.Screen guiScreen) { if (guiScreen != getMinecraft().currentScreen) return; // people tend to construct GuiScreens without opening them VanillaGuiScreen vanillaGui = VanillaGuiScreen.wrap(guiScreen); diff --git a/src/main/java/com/replaymod/core/mixin/MixinGameRenderer.java b/src/main/java/com/replaymod/core/mixin/MixinGameRenderer.java index aefceb3b..a7c817a9 100644 --- a/src/main/java/com/replaymod/core/mixin/MixinGameRenderer.java +++ b/src/main/java/com/replaymod/core/mixin/MixinGameRenderer.java @@ -5,15 +5,12 @@ import com.replaymod.core.events.PostRenderWorldCallback; import com.replaymod.core.events.PreRenderHandCallback; import net.minecraft.client.render.Camera; import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.util.math.MatrixStack; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -//#if MC>=11500 -import net.minecraft.client.util.math.MatrixStack; -//#endif - @Mixin(GameRenderer.class) public class MixinGameRenderer { @Inject( @@ -30,11 +27,10 @@ public class MixinGameRenderer { MatrixStack matrixStack, //#endif CallbackInfo ci) { - PostRenderWorldCallback.EVENT.invoker().postRenderWorld( - //#if MC>=11500 - matrixStack - //#endif - ); + //#if MC<11500 + //$$ MatrixStack matrixStack = new MatrixStack(); + //#endif + PostRenderWorldCallback.EVENT.invoker().postRenderWorld(matrixStack); } @Inject(method = "renderHand", at = @At("HEAD"), cancellable = true) diff --git a/src/main/java/com/replaymod/core/versions/forge/EventsAdapter.java b/src/main/java/com/replaymod/core/versions/forge/EventsAdapter.java new file mode 100644 index 00000000..c690defc --- /dev/null +++ b/src/main/java/com/replaymod/core/versions/forge/EventsAdapter.java @@ -0,0 +1 @@ +// Forge only diff --git a/src/main/java/com/replaymod/editor/handler/GuiHandler.java b/src/main/java/com/replaymod/editor/handler/GuiHandler.java index 7f5f4727..38628e83 100644 --- a/src/main/java/com/replaymod/editor/handler/GuiHandler.java +++ b/src/main/java/com/replaymod/editor/handler/GuiHandler.java @@ -1,6 +1,5 @@ package com.replaymod.editor.handler; -import de.johni0702.minecraft.gui.utils.EventRegistrations; import com.replaymod.core.utils.Utils; import com.replaymod.editor.ReplayModEditor; import com.replaymod.editor.gui.GuiEditReplay; @@ -8,31 +7,15 @@ import com.replaymod.replay.gui.screen.GuiReplayViewer; import de.johni0702.minecraft.gui.container.AbstractGuiScreen; import de.johni0702.minecraft.gui.container.GuiScreen; import de.johni0702.minecraft.gui.element.GuiButton; -import net.minecraft.util.crash.CrashReport; - -//#if FABRIC>=1 +import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.widget.AbstractButtonWidget; -import java.util.List; -//#else -//$$ import net.minecraftforge.client.event.GuiScreenEvent; -//$$ import net.minecraftforge.eventbus.api.SubscribeEvent; -//#endif +import net.minecraft.util.crash.CrashReport; import java.io.IOException; -import static com.replaymod.core.versions.MCVer.*; - public class GuiHandler extends EventRegistrations { - //#if FABRIC>=1 - { on(InitScreenCallback.EVENT, this::injectIntoReplayViewer); } - public void injectIntoReplayViewer(Screen vanillaGuiScreen, List buttonList) { - //#else - //$$ @SubscribeEvent - //$$ public void injectIntoReplayViewer(GuiScreenEvent.InitGuiEvent.Post event) { - //$$ net.minecraft.client.gui.screen.Screen vanillaGuiScreen = getGui(event); - //#endif + { on(InitScreenCallback.EVENT, (vanillaGuiScreen, buttonList) -> injectIntoReplayViewer(vanillaGuiScreen)); } + public void injectIntoReplayViewer(net.minecraft.client.gui.screen.Screen vanillaGuiScreen) { AbstractGuiScreen guiScreen = GuiScreen.from(vanillaGuiScreen); if (!(guiScreen instanceof GuiReplayViewer)) { return; diff --git a/src/main/java/com/replaymod/extras/FullBrightness.java b/src/main/java/com/replaymod/extras/FullBrightness.java index 63fe5c16..b6bef691 100644 --- a/src/main/java/com/replaymod/extras/FullBrightness.java +++ b/src/main/java/com/replaymod/extras/FullBrightness.java @@ -1,6 +1,8 @@ package com.replaymod.extras; import com.replaymod.core.ReplayMod; +import com.replaymod.core.events.PostRenderCallback; +import com.replaymod.core.events.PreRenderCallback; import com.replaymod.core.versions.MCVer.Keyboard; import com.replaymod.replay.ReplayHandler; import com.replaymod.replay.ReplayModReplay; @@ -14,14 +16,6 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.entity.effect.StatusEffectInstance; import net.minecraft.entity.effect.StatusEffects; -//#if FABRIC>=1 -import com.replaymod.core.events.PreRenderCallback; -import com.replaymod.core.events.PostRenderCallback; -//#else -//$$ import net.minecraftforge.eventbus.api.SubscribeEvent; -//$$ import net.minecraftforge.event.TickEvent; -//#endif - public class FullBrightness extends EventRegistrations implements Extra { private ReplayMod core; private ReplayModReplay module; @@ -72,14 +66,8 @@ public class FullBrightness extends EventRegistrations implements Extra { return Type.Gamma; } - //#if FABRIC>=1 { on(PreRenderCallback.EVENT, this::preRender); } private void preRender() { - //#else - //$$ @SubscribeEvent - //$$ public void preRender(TickEvent.RenderTickEvent event) { - //$$ if (event.phase != TickEvent.Phase.START) return; - //#endif if (active && module.getReplayHandler() != null) { Type type = getType(); if (type == Type.Gamma || type == Type.Both) { @@ -98,14 +86,8 @@ public class FullBrightness extends EventRegistrations implements Extra { } } - //#if FABRIC>=1 { on(PostRenderCallback.EVENT, this::postRender); } private void postRender() { - //#else - //$$ @SubscribeEvent - //$$ public void postRender(TickEvent.RenderTickEvent event) { - //$$ if (event.phase != TickEvent.Phase.END) return; - //#endif if (active && module.getReplayHandler() != null) { Type type = getType(); if (type == Type.Gamma || type == Type.Both) { diff --git a/src/main/java/com/replaymod/extras/playeroverview/PlayerOverview.java b/src/main/java/com/replaymod/extras/playeroverview/PlayerOverview.java index 0cbbbf8c..6152e5e3 100644 --- a/src/main/java/com/replaymod/extras/playeroverview/PlayerOverview.java +++ b/src/main/java/com/replaymod/extras/playeroverview/PlayerOverview.java @@ -2,6 +2,7 @@ package com.replaymod.extras.playeroverview; import com.google.common.base.Optional; import com.replaymod.core.ReplayMod; +import com.replaymod.core.events.PreRenderHandCallback; import com.replaymod.core.utils.Utils; import com.replaymod.extras.Extra; import com.replaymod.replay.ReplayHandler; @@ -14,23 +15,11 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; //#if MC>=11400 -import com.replaymod.core.events.PreRenderHandCallback; import java.util.stream.Collectors; //#else -//$$ import net.minecraftforge.client.event.RenderHandEvent; -//$$ -//#if MC>=11400 -//#else //$$ import org.lwjgl.input.Keyboard; -//#endif -//$$ //#if MC>=10800 //$$ import com.google.common.base.Predicate; -//#if MC>=11400 -//$$ import net.minecraftforge.eventbus.api.SubscribeEvent; -//#else -//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -//#endif //#else //$$ import cpw.mods.fml.common.eventhandler.EventPriority; //$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent; @@ -126,16 +115,7 @@ public class PlayerOverview extends EventRegistrations implements Extra { hiddenPlayers.clear(); } - //#if MC>=11400 { on(PreRenderHandCallback.EVENT, this::shouldHideHand); } - //#else - //$$ @SubscribeEvent - //$$ public void oRenderHand(RenderHandEvent event) { - //$$ if (shouldHideHand()) { - //$$ event.setCanceled(true); - //$$ } - //$$ } - //#endif private boolean shouldHideHand() { Entity view = getRenderViewEntity(module.getCore().getMinecraft()); return view != null && isHidden(view.getUuid()); diff --git a/src/main/java/com/replaymod/extras/youtube/YoutubeUpload.java b/src/main/java/com/replaymod/extras/youtube/YoutubeUpload.java index 5fde32a5..fa284bc0 100644 --- a/src/main/java/com/replaymod/extras/youtube/YoutubeUpload.java +++ b/src/main/java/com/replaymod/extras/youtube/YoutubeUpload.java @@ -3,19 +3,11 @@ package com.replaymod.extras.youtube; import com.replaymod.core.ReplayMod; import com.replaymod.extras.Extra; import com.replaymod.render.gui.GuiRenderingDone; -import de.johni0702.minecraft.gui.container.GuiScreen; +import de.johni0702.minecraft.gui.container.AbstractGuiScreen; import de.johni0702.minecraft.gui.element.GuiButton; import de.johni0702.minecraft.gui.utils.EventRegistrations; - -//#if FABRIC>=1 -import de.johni0702.minecraft.gui.versions.callbacks.OpenGuiScreenCallback; +import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback; import net.minecraft.client.gui.screen.Screen; -//#else -//$$ import net.minecraftforge.client.event.GuiScreenEvent; -//$$ import net.minecraftforge.eventbus.api.SubscribeEvent; -//#endif - -import static com.replaymod.core.versions.MCVer.*; public class YoutubeUpload extends EventRegistrations implements Extra { @Override @@ -23,16 +15,11 @@ public class YoutubeUpload extends EventRegistrations implements Extra { register(); } - //#if FABRIC>=1 - { on(OpenGuiScreenCallback.EVENT, this::onGuiOpen); } + { on(InitScreenCallback.EVENT, ((screen, buttons) -> onGuiOpen(screen))); } private void onGuiOpen(Screen vanillaGui) { - //#else - //$$ @SubscribeEvent - //$$ public void onGuiOpen(GuiScreenEvent.InitGuiEvent.Post event) { - //$$ net.minecraft.client.gui.screen.Screen vanillaGui = getGui(event); - //#endif - if (GuiScreen.from(vanillaGui) instanceof GuiRenderingDone) { - GuiRenderingDone gui = (GuiRenderingDone) GuiScreen.from(vanillaGui); + AbstractGuiScreen abstractScreen = de.johni0702.minecraft.gui.container.GuiScreen.from(vanillaGui); + if (abstractScreen instanceof GuiRenderingDone) { + GuiRenderingDone gui = (GuiRenderingDone) abstractScreen; // Check if there already is a youtube button if (gui.actionsPanel.getChildren().stream().anyMatch(it -> it instanceof YoutubeButton)) { return; // Button already added diff --git a/src/main/java/com/replaymod/recording/gui/GuiRecordingControls.java b/src/main/java/com/replaymod/recording/gui/GuiRecordingControls.java index df97260f..b9af9692 100644 --- a/src/main/java/com/replaymod/recording/gui/GuiRecordingControls.java +++ b/src/main/java/com/replaymod/recording/gui/GuiRecordingControls.java @@ -4,7 +4,6 @@ import com.replaymod.core.ReplayMod; import com.replaymod.core.utils.Utils; import com.replaymod.core.versions.MCVer; import com.replaymod.editor.gui.MarkerProcessor; -import com.replaymod.recording.Setting; import com.replaymod.recording.packet.PacketListener; import de.johni0702.minecraft.gui.container.GuiPanel; import de.johni0702.minecraft.gui.container.VanillaGuiScreen; @@ -12,19 +11,10 @@ import de.johni0702.minecraft.gui.element.GuiButton; import de.johni0702.minecraft.gui.layout.CustomLayout; import de.johni0702.minecraft.gui.layout.HorizontalLayout; import de.johni0702.minecraft.gui.utils.EventRegistrations; +import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback; import net.minecraft.client.gui.screen.GameMenuScreen; import net.minecraft.client.gui.screen.Screen; -//#if FABRIC>=1 -import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback; -//#else -//$$ import net.minecraftforge.client.event.GuiScreenEvent; -//$$ import net.minecraftforge.common.MinecraftForge; -//$$ import net.minecraftforge.eventbus.api.SubscribeEvent; -//$$ -//$$ import static com.replaymod.core.versions.MCVer.getGui; -//#endif - //#if MC>=11400 import net.minecraft.client.gui.widget.AbstractButtonWidget; //#endif @@ -85,19 +75,14 @@ public class GuiRecordingControls extends EventRegistrations { buttonPauseResume.setEnabled(!stopped); } - //#if FABRIC>=1 { on(InitScreenCallback.EVENT, this::injectIntoIngameMenu); } - private void injectIntoIngameMenu(Screen guiScreen, List buttonList) { - //#else - //$$ @SubscribeEvent - //$$ public void injectIntoIngameMenu(GuiScreenEvent.InitGuiEvent.Post event) { - //$$ Screen guiScreen = getGui(event); - //#if MC>=11400 - //$$ List buttonList = MCVer.getButtonList(event); - //#else - //$$ List buttonList = MCVer.getButtonList(event); - //#endif - //#endif + private void injectIntoIngameMenu(Screen guiScreen, + //#if MC>=11400 + List buttonList + //#else + //$$ List buttonList + //#endif + ) { if (!(guiScreen instanceof GameMenuScreen)) { return; } diff --git a/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java b/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java index 41844484..8ed65093 100644 --- a/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java +++ b/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java @@ -1,24 +1,16 @@ package com.replaymod.recording.gui; import com.replaymod.core.SettingsRegistry; -import com.replaymod.core.versions.MCVer; import com.replaymod.recording.Setting; import de.johni0702.minecraft.gui.GuiRenderer; import de.johni0702.minecraft.gui.MinecraftGuiRenderer; import de.johni0702.minecraft.gui.utils.EventRegistrations; +import de.johni0702.minecraft.gui.versions.callbacks.RenderHudCallback; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.resource.language.I18n; import net.minecraft.client.util.math.MatrixStack; -//#if FABRIC>=1 -import de.johni0702.minecraft.gui.versions.callbacks.RenderHudCallback; -//#else -//$$ import net.minecraftforge.client.event.RenderGameOverlayEvent; -//$$ import net.minecraftforge.common.MinecraftForge; -//$$ import net.minecraftforge.eventbus.api.SubscribeEvent; -//#endif - import static com.replaymod.core.ReplayMod.TEXTURE; import static com.replaymod.core.ReplayMod.TEXTURE_SIZE; import static com.replaymod.core.versions.MCVer.*; @@ -41,15 +33,8 @@ public class GuiRecordingOverlay extends EventRegistrations { /** * Render the recording icon and text in the top left corner of the screen. */ - //#if FABRIC>=1 { on(RenderHudCallback.EVENT, (stack, partialTicks) -> renderRecordingIndicator(stack)); } private void renderRecordingIndicator(MatrixStack stack) { - //#else - //$$ @SubscribeEvent - //$$ public void renderRecordingIndicator(RenderGameOverlayEvent.Post event) { - //$$ if (getType(event) != RenderGameOverlayEvent.ElementType.ALL) return; - //$$ MatrixStack stack = new MatrixStack(); - //#endif if (guiControls.isStopped()) return; if (settingsRegistry.get(Setting.INDICATOR)) { TextRenderer fontRenderer = mc.textRenderer; diff --git a/src/main/java/com/replaymod/recording/handler/GuiHandler.java b/src/main/java/com/replaymod/recording/handler/GuiHandler.java index ffeb1e87..10f7c920 100644 --- a/src/main/java/com/replaymod/recording/handler/GuiHandler.java +++ b/src/main/java/com/replaymod/recording/handler/GuiHandler.java @@ -14,23 +14,13 @@ import de.johni0702.minecraft.gui.element.GuiToggleButton; import de.johni0702.minecraft.gui.layout.CustomLayout; import de.johni0702.minecraft.gui.popup.GuiInfoPopup; import de.johni0702.minecraft.gui.utils.EventRegistrations; +import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback; import net.minecraft.client.gui.screen.AddServerScreen; import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen; import net.minecraft.client.gui.screen.world.SelectWorldScreen; import net.minecraft.client.network.ServerInfo; import net.minecraft.client.resource.language.I18n; -//#if FABRIC>=1 -import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback; -import net.minecraft.client.gui.screen.Screen; -//#else -//$$ import net.minecraftforge.client.event.GuiScreenEvent; -//$$ import net.minecraftforge.common.MinecraftForge; -//$$ import net.minecraftforge.eventbus.api.SubscribeEvent; -//$$ -//$$ import static com.replaymod.core.versions.MCVer.getGui; -//#endif - public class GuiHandler extends EventRegistrations { private final ReplayMod mod; @@ -39,14 +29,8 @@ public class GuiHandler extends EventRegistrations { this.mod = mod; } - //#if FABRIC>=1 { on(InitScreenCallback.EVENT, (screen, buttons) -> onGuiInit(screen)); } - private void onGuiInit(Screen gui) { - //#else - //$$ @SubscribeEvent - //$$ public void onGuiInit(GuiScreenEvent.InitGuiEvent.Post event) { - //$$ net.minecraft.client.gui.screen.Screen gui = getGui(event); - //#endif + private void onGuiInit(net.minecraft.client.gui.screen.Screen gui) { if (gui instanceof SelectWorldScreen || gui instanceof MultiplayerScreen) { boolean sp = gui instanceof SelectWorldScreen; SettingsRegistry settingsRegistry = mod.getSettingsRegistry(); diff --git a/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java b/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java index 7894fef8..40c6eefe 100644 --- a/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java @@ -1,8 +1,10 @@ package com.replaymod.recording.handler; +import com.replaymod.core.events.PreRenderCallback; import com.replaymod.recording.mixin.IntegratedServerAccessor; import com.replaymod.recording.packet.PacketListener; import de.johni0702.minecraft.gui.utils.EventRegistrations; +import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.network.packet.s2c.play.BlockBreakingProgressS2CPacket; @@ -20,15 +22,11 @@ import net.minecraft.network.Packet; import net.minecraft.server.integrated.IntegratedServer; // FIXME not (yet?) 1.13 import net.minecraftforge.event.entity.minecart.MinecartInteractEvent; -//#if FABRIC>=1 -import com.replaymod.core.events.PreRenderCallback; -import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback; -//#else +//#if FABRIC<1 //$$ import net.minecraft.network.play.server.SCollectItemPacket; //$$ import net.minecraftforge.event.entity.player.PlayerSleepInBedEvent; //$$ import net.minecraftforge.eventbus.api.SubscribeEvent; //$$ import net.minecraftforge.event.entity.player.PlayerEvent.ItemPickupEvent; -//$$ import net.minecraftforge.event.TickEvent; //#endif //#if MC>=11600 @@ -139,15 +137,9 @@ public class RecordingEventHandler extends EventRegistrations { } //#endif - //#if FABRIC>=1 { on(PreTickCallback.EVENT, this::onPlayerTick); } private void onPlayerTick() { if (mc.player == null) return; - //#else - //$$ @SubscribeEvent - //$$ public void onPlayerTick(TickEvent.ClientTickEvent e) { - //$$ if(e.phase != TickEvent.Phase.START || mc.player == null) return; - //#endif ClientPlayerEntity player = mc.player; try { @@ -465,14 +457,8 @@ public class RecordingEventHandler extends EventRegistrations { } } - //#if FABRIC>=1 { on(PreRenderCallback.EVENT, this::checkForGamePaused); } private void checkForGamePaused() { - //#else - //$$ @SubscribeEvent - //$$ public void checkForGamePaused(TickEvent.RenderTickEvent event) { - //$$ if (event.phase != TickEvent.Phase.START) return; - //#endif if (mc.isIntegratedServerRunning()) { IntegratedServer server = mc.getServer(); if (server != null && ((IntegratedServerAccessor) server).isGamePaused()) { diff --git a/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java b/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java index dba61c99..54560f1d 100644 --- a/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java +++ b/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java @@ -1,5 +1,6 @@ package com.replaymod.render.hooks; +import com.replaymod.core.events.PreRenderHandCallback; import com.replaymod.core.versions.MCVer; import com.replaymod.render.RenderSettings; import com.replaymod.render.capturer.CaptureData; @@ -15,7 +16,6 @@ import net.minecraft.client.util.math.MatrixStack; //#if MC>=11400 import com.replaymod.core.events.PostRenderCallback; import com.replaymod.core.events.PreRenderCallback; -import com.replaymod.core.events.PreRenderHandCallback; //#else //#if MC>=11400 //$$ import net.minecraftforge.fml.hooks.BasicEventHooks; @@ -41,9 +41,7 @@ public class EntityRendererHandler extends EventRegistrations implements WorldRe this.settings = settings; this.renderInfo = renderInfo; - //#if MC>=11400 on(PreRenderHandCallback.EVENT, () -> omnidirectional); - //#endif ((IEntityRenderer) mc.gameRenderer).replayModRender_setHandler(this); register(); diff --git a/src/main/java/com/replaymod/replay/FullReplaySender.java b/src/main/java/com/replaymod/replay/FullReplaySender.java index 20ab761d..bb760016 100644 --- a/src/main/java/com/replaymod/replay/FullReplaySender.java +++ b/src/main/java/com/replaymod/replay/FullReplaySender.java @@ -12,6 +12,7 @@ import com.replaymod.replay.camera.CameraEntity; import com.replaymod.replaystudio.io.ReplayInputStream; import com.replaymod.replaystudio.replay.ReplayFile; import de.johni0702.minecraft.gui.utils.EventRegistrations; +import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelDuplexHandler; @@ -57,13 +58,6 @@ import net.minecraft.util.math.MathHelper; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; -//#if FABRIC>=1 -import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback; -//#else -//$$ import net.minecraftforge.eventbus.api.SubscribeEvent; -//$$ import net.minecraftforge.event.TickEvent; -//#endif - //#if MC>=11600 //#else //$$ import net.minecraft.network.packet.s2c.play.EntitySpawnGlobalS2CPacket; @@ -364,22 +358,9 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend } } - //#if MC>=10800 - private - //#else - //$$ public // All event handlers need to be public in 1.7.10 - //#endif - class EventHandler extends EventRegistrations { - //#if FABRIC>=1 + private class EventHandler extends EventRegistrations { { on(PreTickCallback.EVENT, this::onWorldTick); } private void onWorldTick() { - //#else - //$$ @SubscribeEvent - //$$ public void onWorldTick(TickEvent.ClientTickEvent event) { - //$$ // Unfortunately the WorldTickEvent doesn't seem to be emitted on the CLIENT side - //$$ if (event.phase != TickEvent.Phase.START) return; - //#endif - // Spawning a player into an empty chunk (which we might do with the recording player) // prevents it from being moved by teleport packets (it essentially gets stuck) because // Entity#addedToChunk is not set and it is therefore not updated every tick. diff --git a/src/main/java/com/replaymod/replay/QuickReplaySender.java b/src/main/java/com/replaymod/replay/QuickReplaySender.java index 601efec8..18b30a0c 100644 --- a/src/main/java/com/replaymod/replay/QuickReplaySender.java +++ b/src/main/java/com/replaymod/replay/QuickReplaySender.java @@ -12,6 +12,7 @@ import com.replaymod.core.mixin.TimerAccessor; import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.util.RandomAccessReplay; import de.johni0702.minecraft.gui.utils.EventRegistrations; +import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler; @@ -25,15 +26,6 @@ import net.minecraft.network.NetworkSide; import net.minecraft.network.Packet; import net.minecraft.network.PacketByteBuf; -//#if FABRIC>=1 -import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback; -//#else -//$$ import net.minecraftforge.eventbus.api.SubscribeEvent; -//$$ import net.minecraftforge.event.TickEvent; -//$$ -//$$ import static com.replaymod.core.versions.MCVer.FML_BUS; -//#endif - import javax.annotation.Nullable; import java.io.IOException; import java.util.Collections; @@ -285,14 +277,8 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe } private class EventHandler extends EventRegistrations { - //#if FABRIC>=1 { on(PreTickCallback.EVENT, this::onTick); } private void onTick() { - //#else - //$$ @SubscribeEvent - //$$ public void onTick(TickEvent.ClientTickEvent event) { - //$$ if (event.phase != TickEvent.Phase.START) return; - //#endif if (!asyncMode || paused()) return; long now = System.currentTimeMillis(); diff --git a/src/main/java/com/replaymod/replay/camera/CameraEntity.java b/src/main/java/com/replaymod/replay/camera/CameraEntity.java index 591a37d2..ea28d740 100644 --- a/src/main/java/com/replaymod/replay/camera/CameraEntity.java +++ b/src/main/java/com/replaymod/replay/camera/CameraEntity.java @@ -3,9 +3,13 @@ package com.replaymod.replay.camera; import com.replaymod.core.KeyBindingRegistry; import com.replaymod.core.ReplayMod; import com.replaymod.core.SettingsRegistry; +import com.replaymod.core.events.KeyBindingEventCallback; +import com.replaymod.core.events.PreRenderCallback; +import com.replaymod.core.events.PreRenderHandCallback; import com.replaymod.core.events.SettingsChangedCallback; import com.replaymod.replay.ReplayHandler; import de.johni0702.minecraft.gui.utils.EventRegistrations; +import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback; import com.replaymod.core.utils.Utils; import com.replaymod.replay.ReplayModReplay; import com.replaymod.replay.Setting; @@ -24,20 +28,14 @@ import net.minecraft.util.Identifier; import net.minecraft.util.math.Box; //#if FABRIC>=1 -import com.replaymod.core.events.KeyBindingEventCallback; -import com.replaymod.core.events.PreRenderCallback; -import com.replaymod.core.events.PreRenderHandCallback; import com.replaymod.replay.events.RenderSpectatorCrosshairCallback; -import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback; //#else //$$ import com.replaymod.core.versions.MCVer; //$$ import net.minecraftforge.client.event.EntityViewRenderEvent; //$$ import net.minecraftforge.client.event.RenderGameOverlayEvent; -//$$ import net.minecraftforge.client.event.RenderHandEvent; //$$ import net.minecraftforge.common.MinecraftForge; //$$ import net.minecraftforge.eventbus.api.EventPriority; //$$ import net.minecraftforge.eventbus.api.SubscribeEvent; -//$$ import net.minecraftforge.event.TickEvent; //#endif //#if MC>=11400 @@ -51,7 +49,6 @@ import net.minecraft.util.hit.HitResult; //$$ import net.minecraft.util.math.RayTraceResult; //$$ import net.minecraft.util.text.ITextComponent; //$$ import net.minecraft.world.World; -//$$ import net.minecraftforge.fml.common.gameevent.InputEvent; //$$ //#if MC>=11400 //$$ import net.minecraft.util.math.RayTraceFluidMode; @@ -671,41 +668,17 @@ public class CameraEntity private EventHandler() {} - //#if FABRIC>=1 { on(PreTickCallback.EVENT, this::onPreClientTick); } private void onPreClientTick() { - //#else - //$$ @SubscribeEvent - //$$ public void onPreClientTick(TickEvent.ClientTickEvent event) { - //$$ if (event.phase != TickEvent.Phase.START) return; - //#endif updateArmYawAndPitch(); } - //#if FABRIC>=1 { on(PreRenderCallback.EVENT, this::onRenderUpdate); } private void onRenderUpdate() { - //#else - //$$ @SubscribeEvent - //$$ public void onRenderUpdate(TickEvent.RenderTickEvent event) { - //$$ if (event.phase != TickEvent.Phase.START) return; - //#endif update(); } - //#if FABRIC>=1 { 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 //#if FABRIC>=1 { on(RenderSpectatorCrosshairCallback.EVENT, this::shouldRenderSpectatorCrosshair); } @@ -737,35 +710,13 @@ public class CameraEntity } } - //#if FABRIC>=1 { on(PreRenderHandCallback.EVENT, this::onRenderHand); } private boolean onRenderHand() { // Unless we are spectating another player, don't render our hand - if (getRenderViewEntity(mc) == CameraEntity.this || !(getRenderViewEntity(mc) instanceof PlayerEntity)) { + Entity view = getRenderViewEntity(mc); + if (view == CameraEntity.this || !(view instanceof PlayerEntity)) { return true; // cancel hand rendering } else { - onRenderHandMonitor(); - return false; - } - } - //#else - //$$ @SubscribeEvent - //$$ public void onRenderHand(RenderHandEvent event) { - //$$ // Unless we are spectating another player, don't render our hand - //$$ if (getRenderViewEntity(mc) == CameraEntity.this || !(getRenderViewEntity(mc) instanceof PlayerEntity)) { - //$$ event.setCanceled(true); - //$$ } - //$$ } - //#endif - - //#if FABRIC>=1 - private void onRenderHandMonitor() { - //#else - //$$ @SubscribeEvent(priority = EventPriority.LOWEST) - //$$ public void onRenderHandMonitor(RenderHandEvent event) { - //#endif - Entity view = getRenderViewEntity(mc); - if (view instanceof PlayerEntity) { PlayerEntity player = (PlayerEntity) view; // When the spectated player has changed, force equip their items to prevent the equip animation if (lastHandRendered != player) { @@ -790,6 +741,7 @@ public class CameraEntity mc.player.renderYaw = mc.player.lastRenderYaw = player.yaw; mc.player.renderPitch = mc.player.lastRenderPitch = player.pitch; } + return false; } } diff --git a/src/main/java/com/replaymod/replay/gui/overlay/GuiReplayOverlay.java b/src/main/java/com/replaymod/replay/gui/overlay/GuiReplayOverlay.java index 7a53b071..14bef7b1 100644 --- a/src/main/java/com/replaymod/replay/gui/overlay/GuiReplayOverlay.java +++ b/src/main/java/com/replaymod/replay/gui/overlay/GuiReplayOverlay.java @@ -170,12 +170,7 @@ public class GuiReplayOverlay extends AbstractGuiOverlay { return this; } - //#if MC>=10800 - private - //#else - //$$ public // All event handlers need to be public in 1.7.10 - //#endif - class EventHandler extends EventRegistrations { + private class EventHandler extends EventRegistrations { { on(KeyBindingEventCallback.EVENT, this::onKeyBindingEvent); } private void onKeyBindingEvent() { GameOptions gameSettings = getMinecraft().options; diff --git a/src/main/java/com/replaymod/replay/handler/GuiHandler.java b/src/main/java/com/replaymod/replay/handler/GuiHandler.java index 88eea893..e727134c 100644 --- a/src/main/java/com/replaymod/replay/handler/GuiHandler.java +++ b/src/main/java/com/replaymod/replay/handler/GuiHandler.java @@ -1,6 +1,7 @@ package com.replaymod.replay.handler; import de.johni0702.minecraft.gui.utils.EventRegistrations; +import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback; import com.replaymod.replay.ReplayModReplay; import com.replaymod.replay.gui.screen.GuiReplayViewer; import net.minecraft.client.gui.screen.GameMenuScreen; @@ -16,9 +17,7 @@ import net.minecraft.text.TranslatableText; //$$ import net.minecraft.client.resource.language.I18n; //#endif -//#if FABRIC>=1 -import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback; -//#else +//#if FABRIC<1 //$$ import net.minecraftforge.client.event.GuiScreenEvent; //$$ import net.minecraftforge.eventbus.api.SubscribeEvent; //#endif @@ -46,15 +45,8 @@ public class GuiHandler extends EventRegistrations { this.mod = mod; } - //#if FABRIC>=1 { on(InitScreenCallback.EVENT, this::injectIntoIngameMenu); } private void injectIntoIngameMenu(Screen guiScreen, List buttonList) { - //#else - //$$ @SubscribeEvent - //$$ public void injectIntoIngameMenu(GuiScreenEvent.InitGuiEvent.Post event) { - //$$ Screen guiScreen = getGui(event); - //$$ List buttonList = getButtonList(event); - //#endif if (!(guiScreen instanceof GameMenuScreen)) { return; } @@ -198,14 +190,8 @@ public class GuiHandler extends EventRegistrations { .forEach(button -> button.y += moveBy); } - //#if FABRIC>=1 { on(InitScreenCallback.EVENT, this::ensureReplayStopped); } private void ensureReplayStopped(Screen guiScreen, List buttonList) { - //#else - //$$ @SubscribeEvent - //$$ public void ensureReplayStopped(GuiScreenEvent.InitGuiEvent event) { - //$$ Screen guiScreen = getGui(event); - //#endif if (!(guiScreen instanceof TitleScreen || guiScreen instanceof MultiplayerScreen)) { return; } @@ -225,15 +211,8 @@ public class GuiHandler extends EventRegistrations { } } - //#if FABRIC>=1 { on(InitScreenCallback.EVENT, this::injectIntoMainMenu); } private void injectIntoMainMenu(Screen guiScreen, List buttonList) { - //#else - //$$ @SubscribeEvent - //$$ public void injectIntoMainMenu(GuiScreenEvent.InitGuiEvent event) { - //$$ Screen guiScreen = getGui(event); - //$$ List buttonList = getButtonList(event); - //#endif if (!(guiScreen instanceof TitleScreen)) { return; } @@ -269,7 +248,7 @@ public class GuiHandler extends EventRegistrations { //#if FABRIC<=0 //$$ if (guiScreen.getClass().getName().endsWith("custommainmenu.gui.GuiFakeMain")) { //$$ // CustomMainMenu uses a different list in the event than in its Fake gui - //$$ addButton(event, button); + //$$ buttonList.add(button); //$$ return; //$$ } //#endif diff --git a/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java b/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java index d4ff56cd..450d853e 100644 --- a/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java +++ b/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java @@ -1,6 +1,8 @@ package com.replaymod.simplepathing.preview; +import com.mojang.blaze3d.platform.GlStateManager; import com.replaymod.core.ReplayMod; +import com.replaymod.core.events.PostRenderWorldCallback; import com.replaymod.core.versions.MCVer; import com.replaymod.pathing.properties.CameraProperties; import com.replaymod.pathing.properties.SpectatorProperty; @@ -17,7 +19,7 @@ import com.replaymod.simplepathing.SPTimeline; import com.replaymod.simplepathing.gui.GuiPathing; import de.johni0702.minecraft.gui.utils.EventRegistrations; import net.minecraft.client.MinecraftClient; -import com.mojang.blaze3d.platform.GlStateManager; +import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; import net.minecraft.util.Identifier; import org.apache.commons.lang3.tuple.Pair; @@ -26,14 +28,6 @@ import org.lwjgl.opengl.GL11; //#if MC>=11500 import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.util.math.MatrixStack; -//#endif - -//#if FABRIC>=1 -import com.replaymod.core.events.PostRenderWorldCallback; -//#else -//$$ import net.minecraftforge.client.event.RenderWorldLastEvent; -//$$ import net.minecraftforge.eventbus.api.SubscribeEvent; //#endif import java.util.Comparator; @@ -58,17 +52,8 @@ public class PathPreviewRenderer extends EventRegistrations { this.replayHandler = replayHandler; } - //#if FABRIC>=1 { on(PostRenderWorldCallback.EVENT, this::renderCameraPath); } - //#if MC>=11500 private void renderCameraPath(MatrixStack matrixStack) { - //#else - //$$ private void renderCameraPath() { - //#endif - //#else - //$$ @SubscribeEvent - //$$ public void renderCameraPath(RenderWorldLastEvent event) { - //#endif if (!replayHandler.getReplaySender().isAsyncMode() || mc.options.hudHidden) return; Entity view = getRenderViewEntity(mc); diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/ReplayModBackend.java b/versions/1.12.2/src/main/java/com/replaymod/core/ReplayModBackend.java index 75fb9e91..d0f1fb62 100644 --- a/versions/1.12.2/src/main/java/com/replaymod/core/ReplayModBackend.java +++ b/versions/1.12.2/src/main/java/com/replaymod/core/ReplayModBackend.java @@ -1,6 +1,7 @@ package com.replaymod.core; import com.replaymod.core.mixin.MinecraftAccessor; +import com.replaymod.core.versions.forge.EventsAdapter; import net.minecraft.client.resources.IResourcePack; import net.minecraftforge.common.config.Configuration; import net.minecraftforge.fml.common.Loader; @@ -36,6 +37,7 @@ import static com.replaymod.core.versions.MCVer.getMinecraft; guiFactory = "com.replaymod.core.gui.GuiFactory") public class ReplayModBackend { private final ReplayMod mod = new ReplayMod(this); + private final EventsAdapter eventsAdapter = new EventsAdapter(); @Deprecated public static Configuration config; @@ -52,6 +54,7 @@ public class ReplayModBackend { @EventHandler public void init(FMLInitializationEvent event) { mod.initModules(); + eventsAdapter.register(); } public String getVersion() { diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/EventsAdapter.java b/versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/EventsAdapter.java new file mode 100644 index 00000000..02e5574f --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/EventsAdapter.java @@ -0,0 +1,50 @@ +package com.replaymod.core.versions.forge; + +import com.replaymod.core.events.KeyBindingEventCallback; +import com.replaymod.core.events.PostRenderCallback; +import com.replaymod.core.events.PostRenderWorldCallback; +import com.replaymod.core.events.PreRenderCallback; +import com.replaymod.core.events.PreRenderHandCallback; +import de.johni0702.minecraft.gui.utils.EventRegistrations; +import de.johni0702.minecraft.gui.versions.MatrixStack; +import net.minecraftforge.client.event.RenderHandEvent; +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.InputEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +public class EventsAdapter extends EventRegistrations { + @SubscribeEvent + public void onKeyEvent(InputEvent.KeyInputEvent event) { + KeyBindingEventCallback.EVENT.invoker().onKeybindingEvent(); + } + + @SubscribeEvent + public void onMouseInput(InputEvent.MouseInputEvent event) { + KeyBindingEventCallback.EVENT.invoker().onKeybindingEvent(); + } + + @SubscribeEvent + public void preRender(TickEvent.RenderTickEvent event) { + if (event.phase != TickEvent.Phase.START) return; + PreRenderCallback.EVENT.invoker().preRender(); + } + + @SubscribeEvent + public void postRender(TickEvent.RenderTickEvent event) { + if (event.phase != TickEvent.Phase.END) return; + PostRenderCallback.EVENT.invoker().postRender(); + } + + @SubscribeEvent + public void renderCameraPath(RenderWorldLastEvent event) { + PostRenderWorldCallback.EVENT.invoker().postRenderWorld(new MatrixStack()); + } + + @SubscribeEvent + public void oRenderHand(RenderHandEvent event) { + if (PreRenderHandCallback.EVENT.invoker().preRenderHand()) { + event.setCanceled(true); + } + } +} From 66c1f63219e218ff3d3cb839d49aa1a70070158f Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 22 Feb 2021 23:31:59 +0100 Subject: [PATCH 009/102] Move GuiFactory into 1.12.2 project --- .../com/replaymod/core/gui/GuiFactory.java | 64 +------------------ .../com/replaymod/core/gui/GuiFactory.java | 61 ++++++++++++++++++ 2 files changed, 62 insertions(+), 63 deletions(-) create mode 100644 versions/1.12.2/src/main/java/com/replaymod/core/gui/GuiFactory.java diff --git a/src/main/java/com/replaymod/core/gui/GuiFactory.java b/src/main/java/com/replaymod/core/gui/GuiFactory.java index 31ff16a9..fca4cd6c 100644 --- a/src/main/java/com/replaymod/core/gui/GuiFactory.java +++ b/src/main/java/com/replaymod/core/gui/GuiFactory.java @@ -1,63 +1 @@ -//#if MC<11400 -//$$ package com.replaymod.core.gui; -//$$ -//$$ import com.replaymod.core.ReplayMod; -//$$ import net.minecraft.client.Minecraft; -//$$ import net.minecraft.client.gui.GuiScreen; -//$$ -//#if MC>=10800 -//$$ import net.minecraftforge.fml.client.IModGuiFactory; -//#else -//$$ import cpw.mods.fml.client.IModGuiFactory; -//#endif -//$$ -//$$ import java.util.Set; -//$$ -//$$ @SuppressWarnings("unused") -//$$ public class GuiFactory implements IModGuiFactory { -//$$ @Override -//$$ public void initialize(Minecraft minecraftInstance) { -//$$ -//$$ } -//$$ - //#if MC>=11200 - //$$ @Override - //$$ public boolean hasConfigGui() { - //$$ return true; - //$$ } - //$$ - //$$ @Override - //$$ public GuiScreen createConfigGui(GuiScreen parentScreen) { - //$$ return new GuiReplaySettings(parentScreen, ReplayMod.instance.getSettingsRegistry()).toMinecraft(); - //$$ } - //#else - //$$ @Override - //$$ public Class mainConfigGuiClass() { - //$$ return ConfigGuiWrapper.class; - //$$ } - //$$ - //$$ @Override - //$$ public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element) { - //$$ return null; - //$$ } - //$$ - //$$ public static class ConfigGuiWrapper extends GuiScreen { - //$$ private final GuiScreen parent; - //$$ - //$$ public ConfigGuiWrapper(GuiScreen parent) { - //$$ this.parent = parent; - //$$ } - //$$ - //$$ @Override - //$$ public void initGui() { - //$$ new GuiReplaySettings(parent, ReplayMod.instance.getSettingsRegistry()).display(); - //$$ } - //$$ } - //#endif -//$$ -//$$ @Override -//$$ public Set runtimeGuiCategories() { -//$$ return null; -//$$ } -//$$ } -//#endif +// 1.12.2 and below diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/gui/GuiFactory.java b/versions/1.12.2/src/main/java/com/replaymod/core/gui/GuiFactory.java new file mode 100644 index 00000000..e2ac1ed4 --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/core/gui/GuiFactory.java @@ -0,0 +1,61 @@ +package com.replaymod.core.gui; + +import com.replaymod.core.ReplayMod; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; + +//#if MC>=10800 +import net.minecraftforge.fml.client.IModGuiFactory; +//#else +//$$ import cpw.mods.fml.client.IModGuiFactory; +//#endif + +import java.util.Set; + +@SuppressWarnings("unused") +public class GuiFactory implements IModGuiFactory { + @Override + public void initialize(Minecraft minecraftInstance) { + + } + + //#if MC>=11200 + @Override + public boolean hasConfigGui() { + return true; + } + + @Override + public GuiScreen createConfigGui(GuiScreen parentScreen) { + return new GuiReplaySettings(parentScreen, ReplayMod.instance.getSettingsRegistry()).toMinecraft(); + } + //#else + //$$ @Override + //$$ public Class mainConfigGuiClass() { + //$$ return ConfigGuiWrapper.class; + //$$ } + //$$ + //$$ @Override + //$$ public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element) { + //$$ return null; + //$$ } + //$$ + //$$ public static class ConfigGuiWrapper extends GuiScreen { + //$$ private final GuiScreen parent; + //$$ + //$$ public ConfigGuiWrapper(GuiScreen parent) { + //$$ this.parent = parent; + //$$ } + //$$ + //$$ @Override + //$$ public void initGui() { + //$$ new GuiReplaySettings(parent, ReplayMod.instance.getSettingsRegistry()).display(); + //$$ } + //$$ } + //#endif + + @Override + public Set runtimeGuiCategories() { + return null; + } +} From 1329f2d7036b2aba492861046cbcf0022ad17af7 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 22 Feb 2021 23:35:42 +0100 Subject: [PATCH 010/102] Move GLErrorTransformer into 1.7.10 project --- .../core/asm/GLErrorTransformer.java | 96 +------------------ .../core/asm/GLErrorTransformer.java | 93 ++++++++++++++++++ 2 files changed, 94 insertions(+), 95 deletions(-) create mode 100644 versions/1.7.10/src/main/java/com/replaymod/core/asm/GLErrorTransformer.java diff --git a/src/main/java/com/replaymod/core/asm/GLErrorTransformer.java b/src/main/java/com/replaymod/core/asm/GLErrorTransformer.java index dac9dde9..743815c4 100644 --- a/src/main/java/com/replaymod/core/asm/GLErrorTransformer.java +++ b/src/main/java/com/replaymod/core/asm/GLErrorTransformer.java @@ -1,95 +1 @@ -//#if MC<=10710 -//$$ package com.replaymod.core.asm; -//$$ -//$$ import net.minecraft.launchwrapper.IClassTransformer; -//$$ import org.lwjgl.opengl.GL11; -//$$ import org.lwjgl.util.glu.GLU; -//$$ import org.objectweb.asm.ClassReader; -//$$ import org.objectweb.asm.ClassVisitor; -//$$ import org.objectweb.asm.ClassWriter; -//$$ import org.objectweb.asm.MethodVisitor; -//$$ import org.objectweb.asm.Opcodes; -//$$ -//$$ /** -//$$ * Insert glGetError checks after all calls to any method in any GL*, ARB* and EXT* classes -//$$ */ -//$$ public class GLErrorTransformer implements IClassTransformer { -//$$ private static final String GL_CLASS = "org.lwjgl.opengl.GL"; -//$$ private static final String GL = GL_CLASS.replace('.', '/'); -//$$ private static final String ARB_CLASS = "org.lwjgl.opengl.ARB"; -//$$ private static final String ARB = ARB_CLASS.replace('.', '/'); -//$$ private static final String EXT_CLASS = "org.lwjgl.opengl.EXT"; -//$$ private static final String EXT = EXT_CLASS.replace('.', '/'); -//$$ private static final String GLErrorTransformer_CLASS = GLErrorTransformer.class.getName(); -//$$ private static final String GLErrorTransformer = GLErrorTransformer_CLASS.replace('.', '/'); -//$$ -//$$ @Override -//$$ public byte[] transform(String name, String transformedName, byte[] basicClass) { -//$$ if (basicClass == null) return null; -//$$ -//$$ ClassReader reader = new ClassReader(basicClass); -//$$ ClassWriter writer = new ClassWriter(reader, 0); -//$$ reader.accept(new ClassVisitor(Opcodes.ASM5, writer) { -//$$ @Override -//$$ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { -//$$ MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); -//$$ return new MethodVisitor(Opcodes.ASM5, mv) { -//$$ @Override -//$$ public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { -//$$ super.visitMethodInsn(opcode, owner, name, desc, itf); -//$$ if (owner.startsWith(GL) || owner.startsWith(ARB) || owner.startsWith(EXT)) { -//$$ visitLdcInsn(owner.replace('/', '.')); -//$$ visitLdcInsn(name); -//$$ super.visitMethodInsn(Opcodes.INVOKESTATIC, GLErrorTransformer, "glErrorCheck", "(Ljava/lang/String;Ljava/lang/String;)V", false); -//$$ } -//$$ } -//$$ -//$$ @Override -//$$ public void visitMaxs(int maxStack, int maxLocals) { -//$$ super.visitMaxs(maxStack + 2, maxLocals); -//$$ } -//$$ }; -//$$ } -//$$ }, 0); -//$$ return writer.toByteArray(); -//$$ } -//$$ -//$$ private static boolean inGlBegin; -//$$ -//$$ @SuppressWarnings("unused") // Called via ASM -//$$ public static void glErrorCheck(String cls, String method) { -//$$ if (method.equals("glBegin") && cls.equals(GL_CLASS + "11")) { -//$$ if (inGlBegin) { -//$$ // glBegin within glBegin -//$$ throw new GLError(GL11.GL_INVALID_OPERATION, cls, method); -//$$ } -//$$ inGlBegin = true; -//$$ return; -//$$ } -//$$ if (inGlBegin && method.equals("glEnd") && cls.equals(GL_CLASS + "11")) { -//$$ inGlBegin = false; -//$$ } -//$$ if (inGlBegin) { -//$$ return; // Cannot call glGetError in between of glBegin and glEnd -//$$ } -//$$ int err = GL11.glGetError(); -//$$ if (err != 0) { -//$$ GLError e = new GLError(err, cls, method); -//$$ if ("true".equals(System.getProperty("replaymod.glerrors.throw", "true"))) { -//$$ throw e; -//$$ } else { -//$$ e.printStackTrace(); -//$$ } -//$$ } -//$$ } -//$$ -//$$ public static class GLError extends RuntimeException { -//$$ private GLError(int err, String cls, String method) { -//$$ super(GLU.gluErrorString(err) + " (" + err + ")"); -//$$ StackTraceElement[] stack = getStackTrace(); -//$$ stack[0] = new StackTraceElement(cls, method, stack[0].getFileName(), stack[0].getLineNumber()); -//$$ setStackTrace(stack); -//$$ } -//$$ } -//$$ } -//#endif +// 1.7.10 and below diff --git a/versions/1.7.10/src/main/java/com/replaymod/core/asm/GLErrorTransformer.java b/versions/1.7.10/src/main/java/com/replaymod/core/asm/GLErrorTransformer.java new file mode 100644 index 00000000..06098167 --- /dev/null +++ b/versions/1.7.10/src/main/java/com/replaymod/core/asm/GLErrorTransformer.java @@ -0,0 +1,93 @@ +package com.replaymod.core.asm; + +import net.minecraft.launchwrapper.IClassTransformer; +import org.lwjgl.opengl.GL11; +import org.lwjgl.util.glu.GLU; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * Insert glGetError checks after all calls to any method in any GL*, ARB* and EXT* classes + */ +public class GLErrorTransformer implements IClassTransformer { + private static final String GL_CLASS = "org.lwjgl.opengl.GL"; + private static final String GL = GL_CLASS.replace('.', '/'); + private static final String ARB_CLASS = "org.lwjgl.opengl.ARB"; + private static final String ARB = ARB_CLASS.replace('.', '/'); + private static final String EXT_CLASS = "org.lwjgl.opengl.EXT"; + private static final String EXT = EXT_CLASS.replace('.', '/'); + private static final String GLErrorTransformer_CLASS = GLErrorTransformer.class.getName(); + private static final String GLErrorTransformer = GLErrorTransformer_CLASS.replace('.', '/'); + + @Override + public byte[] transform(String name, String transformedName, byte[] basicClass) { + if (basicClass == null) return null; + + ClassReader reader = new ClassReader(basicClass); + ClassWriter writer = new ClassWriter(reader, 0); + reader.accept(new ClassVisitor(Opcodes.ASM5, writer) { + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); + return new MethodVisitor(Opcodes.ASM5, mv) { + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + if (owner.startsWith(GL) || owner.startsWith(ARB) || owner.startsWith(EXT)) { + visitLdcInsn(owner.replace('/', '.')); + visitLdcInsn(name); + super.visitMethodInsn(Opcodes.INVOKESTATIC, GLErrorTransformer, "glErrorCheck", "(Ljava/lang/String;Ljava/lang/String;)V", false); + } + } + + @Override + public void visitMaxs(int maxStack, int maxLocals) { + super.visitMaxs(maxStack + 2, maxLocals); + } + }; + } + }, 0); + return writer.toByteArray(); + } + + private static boolean inGlBegin; + + @SuppressWarnings("unused") // Called via ASM + public static void glErrorCheck(String cls, String method) { + if (method.equals("glBegin") && cls.equals(GL_CLASS + "11")) { + if (inGlBegin) { + // glBegin within glBegin + throw new GLError(GL11.GL_INVALID_OPERATION, cls, method); + } + inGlBegin = true; + return; + } + if (inGlBegin && method.equals("glEnd") && cls.equals(GL_CLASS + "11")) { + inGlBegin = false; + } + if (inGlBegin) { + return; // Cannot call glGetError in between of glBegin and glEnd + } + int err = GL11.glGetError(); + if (err != 0) { + GLError e = new GLError(err, cls, method); + if ("true".equals(System.getProperty("replaymod.glerrors.throw", "true"))) { + throw e; + } else { + e.printStackTrace(); + } + } + } + + public static class GLError extends RuntimeException { + private GLError(int err, String cls, String method) { + super(GLU.gluErrorString(err) + " (" + err + ")"); + StackTraceElement[] stack = getStackTrace(); + stack[0] = new StackTraceElement(cls, method, stack[0].getFileName(), stack[0].getLineNumber()); + setStackTrace(stack); + } + } +} From 9e152f2655edefa165b958edcd2ead6c984e719b Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 22 Feb 2021 23:36:10 +0100 Subject: [PATCH 011/102] Move GLStateTrackerTransformer into 1.7.10 project --- .../core/asm/GLStateTrackerTransformer.java | 107 +----------------- .../core/asm/GLStateTrackerTransformer.java | 104 +++++++++++++++++ 2 files changed, 105 insertions(+), 106 deletions(-) create mode 100644 versions/1.7.10/src/main/java/com/replaymod/core/asm/GLStateTrackerTransformer.java diff --git a/src/main/java/com/replaymod/core/asm/GLStateTrackerTransformer.java b/src/main/java/com/replaymod/core/asm/GLStateTrackerTransformer.java index 26129095..743815c4 100644 --- a/src/main/java/com/replaymod/core/asm/GLStateTrackerTransformer.java +++ b/src/main/java/com/replaymod/core/asm/GLStateTrackerTransformer.java @@ -1,106 +1 @@ -//#if MC<=10710 -//$$ package com.replaymod.core.asm; -//$$ -//$$ import net.minecraft.launchwrapper.IClassTransformer; -//$$ import org.objectweb.asm.ClassReader; -//$$ import org.objectweb.asm.ClassVisitor; -//$$ import org.objectweb.asm.ClassWriter; -//$$ import org.objectweb.asm.MethodVisitor; -//$$ import org.objectweb.asm.Opcodes; -//$$ -//$$ import java.util.HashSet; -//$$ import java.util.Set; -//$$ -//$$ /** -//$$ * Redirect all calls to GL11.glEnable and GL11.glDisable to the GLStateTracker (excluding that class itself). -//$$ */ -//$$ public class GLStateTrackerTransformer implements IClassTransformer { -//$$ private static final String GL11_CLASS = "org.lwjgl.opengl.GL11"; -//$$ private static final String GL11 = GL11_CLASS.replace('.', '/'); -//$$ private static final String glEnable = "glEnable"; -//$$ private static final String glDisable = "glDisable"; -//$$ private static final String GLStateTracker_CLASS = "com.replaymod.render.hooks.GLStateTracker"; -//$$ private static final String GLStateTracker = GLStateTracker_CLASS.replace('.', '/'); -//$$ private static final String hook_glEnable = "hook_glEnable"; -//$$ private static final String hook_glDisable = "hook_glDisable"; -//$$ -//$$ @Override -//$$ public byte[] transform(String name, String transformedName, byte[] basicClass) { -//$$ if (basicClass == null) return null; -//$$ // Ignore the state tracker itself -//$$ if (name.equals(GLStateTracker_CLASS)) return basicClass; -//$$ -//$$ ClassReader reader = new ClassReader(basicClass); -//$$ Set eligibleMethods = findEligibleMethods(reader); -//$$ if (eligibleMethods.isEmpty()) { -//$$ return basicClass; -//$$ } -//$$ -//$$ ClassWriter writer = new ClassWriter(reader, 0); -//$$ reader.accept(new ClassVisitor(Opcodes.ASM5, writer) { -//$$ @Override -//$$ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { -//$$ MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); -//$$ if (!eligibleMethods.contains(new Method(name, desc))) { -//$$ return mv; -//$$ } -//$$ return new MethodVisitor(Opcodes.ASM5, mv) { -//$$ @Override -//$$ public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { -//$$ if (owner.equals(GL11)) { -//$$ if (name.equals(glEnable)) { -//$$ owner = GLStateTracker; -//$$ name = hook_glEnable; -//$$ } else if (name.equals(glDisable)) { -//$$ owner = GLStateTracker; -//$$ name = hook_glDisable; -//$$ } -//$$ } -//$$ super.visitMethodInsn(opcode, owner, name, desc, itf); -//$$ } -//$$ }; -//$$ } -//$$ }, 0); -//$$ return writer.toByteArray(); -//$$ } -//$$ -//$$ private Set findEligibleMethods(ClassReader reader) { -//$$ Set eligibleMethods = new HashSet<>(); -//$$ reader.accept(new ClassVisitor(Opcodes.ASM5) { -//$$ @Override -//$$ public MethodVisitor visitMethod(int access, String methodName, String methodDesc, String signature, String[] exceptions) { -//$$ return new MethodVisitor(Opcodes.ASM5) { -//$$ @Override -//$$ public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { -//$$ if (owner.equals(GL11) && (name.equals(glEnable) || name.equals(glDisable))) { -//$$ eligibleMethods.add(new Method(methodName, methodDesc)); -//$$ } -//$$ } -//$$ }; -//$$ } -//$$ }, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); -//$$ return eligibleMethods; -//$$ } -//$$ -//$$ private static class Method { -//$$ private final String name, desc; -//$$ -//$$ private Method(String name, String desc) { -//$$ this.name = name; -//$$ this.desc = desc; -//$$ } -//$$ -//$$ @Override -//$$ public boolean equals(Object o) { -//$$ if (o == null || getClass() != o.getClass()) return false; -//$$ Method method = (Method) o; -//$$ return name.equals(method.name) && desc.equals(method.desc); -//$$ } -//$$ -//$$ @Override -//$$ public int hashCode() { -//$$ return name.hashCode() ^ desc.hashCode(); -//$$ } -//$$ } -//$$ } -//#endif +// 1.7.10 and below diff --git a/versions/1.7.10/src/main/java/com/replaymod/core/asm/GLStateTrackerTransformer.java b/versions/1.7.10/src/main/java/com/replaymod/core/asm/GLStateTrackerTransformer.java new file mode 100644 index 00000000..641cf104 --- /dev/null +++ b/versions/1.7.10/src/main/java/com/replaymod/core/asm/GLStateTrackerTransformer.java @@ -0,0 +1,104 @@ +package com.replaymod.core.asm; + +import net.minecraft.launchwrapper.IClassTransformer; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +import java.util.HashSet; +import java.util.Set; + +/** + * Redirect all calls to GL11.glEnable and GL11.glDisable to the GLStateTracker (excluding that class itself). + */ +public class GLStateTrackerTransformer implements IClassTransformer { + private static final String GL11_CLASS = "org.lwjgl.opengl.GL11"; + private static final String GL11 = GL11_CLASS.replace('.', '/'); + private static final String glEnable = "glEnable"; + private static final String glDisable = "glDisable"; + private static final String GLStateTracker_CLASS = "com.replaymod.render.hooks.GLStateTracker"; + private static final String GLStateTracker = GLStateTracker_CLASS.replace('.', '/'); + private static final String hook_glEnable = "hook_glEnable"; + private static final String hook_glDisable = "hook_glDisable"; + + @Override + public byte[] transform(String name, String transformedName, byte[] basicClass) { + if (basicClass == null) return null; + // Ignore the state tracker itself + if (name.equals(GLStateTracker_CLASS)) return basicClass; + + ClassReader reader = new ClassReader(basicClass); + Set eligibleMethods = findEligibleMethods(reader); + if (eligibleMethods.isEmpty()) { + return basicClass; + } + + ClassWriter writer = new ClassWriter(reader, 0); + reader.accept(new ClassVisitor(Opcodes.ASM5, writer) { + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); + if (!eligibleMethods.contains(new Method(name, desc))) { + return mv; + } + return new MethodVisitor(Opcodes.ASM5, mv) { + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + if (owner.equals(GL11)) { + if (name.equals(glEnable)) { + owner = GLStateTracker; + name = hook_glEnable; + } else if (name.equals(glDisable)) { + owner = GLStateTracker; + name = hook_glDisable; + } + } + super.visitMethodInsn(opcode, owner, name, desc, itf); + } + }; + } + }, 0); + return writer.toByteArray(); + } + + private Set findEligibleMethods(ClassReader reader) { + Set eligibleMethods = new HashSet<>(); + reader.accept(new ClassVisitor(Opcodes.ASM5) { + @Override + public MethodVisitor visitMethod(int access, String methodName, String methodDesc, String signature, String[] exceptions) { + return new MethodVisitor(Opcodes.ASM5) { + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + if (owner.equals(GL11) && (name.equals(glEnable) || name.equals(glDisable))) { + eligibleMethods.add(new Method(methodName, methodDesc)); + } + } + }; + } + }, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + return eligibleMethods; + } + + private static class Method { + private final String name, desc; + + private Method(String name, String desc) { + this.name = name; + this.desc = desc; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + Method method = (Method) o; + return name.equals(method.name) && desc.equals(method.desc); + } + + @Override + public int hashCode() { + return name.hashCode() ^ desc.hashCode(); + } + } +} From f15eaf95c165d728e1acb5117195aff320493a24 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 22 Feb 2021 23:38:42 +0100 Subject: [PATCH 012/102] Split off 1.12.2 overwrite from MixinKeyboardListener --- .../core/mixin/MixinKeyboardListener.java | 27 +------------------ .../core/mixin/MixinKeyboardListener.java | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 26 deletions(-) create mode 100644 versions/1.12.2/src/main/java/com/replaymod/core/mixin/MixinKeyboardListener.java diff --git a/src/main/java/com/replaymod/core/mixin/MixinKeyboardListener.java b/src/main/java/com/replaymod/core/mixin/MixinKeyboardListener.java index 3a7c680c..3c218b89 100644 --- a/src/main/java/com/replaymod/core/mixin/MixinKeyboardListener.java +++ b/src/main/java/com/replaymod/core/mixin/MixinKeyboardListener.java @@ -2,19 +2,12 @@ package com.replaymod.core.mixin; import com.replaymod.core.events.KeyBindingEventCallback; import com.replaymod.core.events.KeyEventCallback; +import net.minecraft.client.Keyboard; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -//#if MC>=11400 -import net.minecraft.client.Keyboard; -//#else -//$$ import net.minecraft.client.settings.KeyBinding; -//$$ import org.lwjgl.input.Keyboard; -//#endif - -//#if MC>=11400 @Mixin(Keyboard.class) public class MixinKeyboardListener { private static final String ON_KEY_PRESSED = "Lnet/minecraft/client/options/KeyBinding;onKeyPressed(Lnet/minecraft/client/util/InputUtil$Key;)V"; @@ -31,21 +24,3 @@ public class MixinKeyboardListener { KeyBindingEventCallback.EVENT.invoker().onKeybindingEvent(); } } -//#else -//$$ @Mixin(KeyBinding.class) -//$$ public class MixinKeyboardListener { -//$$ @Inject(method = "onTick", at = @At("HEAD"), cancellable = true) -//$$ private static void beforeKeyBindingTick(CallbackInfo ci) { -//$$ int keyCode = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey(); -//$$ int action = Keyboard.getEventKeyState() ? KeyEventCallback.ACTION_PRESS : KeyEventCallback.ACTION_RELEASE; -//$$ if (KeyEventCallback.EVENT.invoker().onKeyEvent(keyCode, 0, action, 0)) { -//$$ ci.cancel(); -//$$ } -//$$ } -//$$ -//$$ @Inject(method = "onTick", at = @At("RETURN")) -//$$ private static void afterKeyBindingTick(CallbackInfo ci) { -//$$ KeyBindingEventCallback.EVENT.invoker().onKeybindingEvent(); -//$$ } -//$$ } -//#endif diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/mixin/MixinKeyboardListener.java b/versions/1.12.2/src/main/java/com/replaymod/core/mixin/MixinKeyboardListener.java new file mode 100644 index 00000000..2e29e2ed --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/core/mixin/MixinKeyboardListener.java @@ -0,0 +1,27 @@ +package com.replaymod.core.mixin; + +import com.replaymod.core.events.KeyBindingEventCallback; +import com.replaymod.core.events.KeyEventCallback; +import net.minecraft.client.settings.KeyBinding; +import org.lwjgl.input.Keyboard; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(KeyBinding.class) +public class MixinKeyboardListener { + @Inject(method = "onTick", at = @At("HEAD"), cancellable = true) + private static void beforeKeyBindingTick(CallbackInfo ci) { + int keyCode = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey(); + int action = Keyboard.getEventKeyState() ? KeyEventCallback.ACTION_PRESS : KeyEventCallback.ACTION_RELEASE; + if (KeyEventCallback.EVENT.invoker().onKeyEvent(keyCode, 0, action, 0)) { + ci.cancel(); + } + } + + @Inject(method = "onTick", at = @At("RETURN")) + private static void afterKeyBindingTick(CallbackInfo ci) { + KeyBindingEventCallback.EVENT.invoker().onKeybindingEvent(); + } +} From 9bde5fae4917470355e0437e835c27ff90acdc17 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 22 Feb 2021 23:41:39 +0100 Subject: [PATCH 013/102] Move ResourcePackRepositoryAccessor into 1.7.10 project --- .../mixin/ResourcePackRepositoryAccessor.java | 23 +------------------ .../mixin/ResourcePackRepositoryAccessor.java | 20 ++++++++++++++++ 2 files changed, 21 insertions(+), 22 deletions(-) create mode 100644 versions/1.7.10/src/main/java/com/replaymod/core/mixin/ResourcePackRepositoryAccessor.java diff --git a/src/main/java/com/replaymod/core/mixin/ResourcePackRepositoryAccessor.java b/src/main/java/com/replaymod/core/mixin/ResourcePackRepositoryAccessor.java index 81a00bcf..743815c4 100644 --- a/src/main/java/com/replaymod/core/mixin/ResourcePackRepositoryAccessor.java +++ b/src/main/java/com/replaymod/core/mixin/ResourcePackRepositoryAccessor.java @@ -1,22 +1 @@ -//#if MC<10800 -//$$ package com.replaymod.core.mixin; -//$$ -//$$ import net.minecraft.client.resources.IResourcePack; -//$$ import net.minecraft.client.resources.ResourcePackRepository; -//$$ import org.spongepowered.asm.mixin.Mixin; -//$$ import org.spongepowered.asm.mixin.gen.Accessor; -//$$ -//$$ import java.io.File; -//$$ -//$$ @Mixin(ResourcePackRepository.class) -//$$ public interface ResourcePackRepositoryAccessor { -//$$ @Accessor("field_148533_g") -//$$ boolean isActive(); -//$$ @Accessor("field_148533_g") -//$$ void setActive(boolean value); -//$$ @Accessor("field_148532_f") -//$$ void setPack(IResourcePack value); -//$$ @Accessor("field_148534_e") -//$$ File getCacheDir(); -//$$ } -//#endif +// 1.7.10 and below diff --git a/versions/1.7.10/src/main/java/com/replaymod/core/mixin/ResourcePackRepositoryAccessor.java b/versions/1.7.10/src/main/java/com/replaymod/core/mixin/ResourcePackRepositoryAccessor.java new file mode 100644 index 00000000..d9c16a24 --- /dev/null +++ b/versions/1.7.10/src/main/java/com/replaymod/core/mixin/ResourcePackRepositoryAccessor.java @@ -0,0 +1,20 @@ +package com.replaymod.core.mixin; + +import net.minecraft.client.resources.IResourcePack; +import net.minecraft.client.resources.ResourcePackRepository; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.io.File; + +@Mixin(ResourcePackRepository.class) +public interface ResourcePackRepositoryAccessor { + @Accessor("field_148533_g") + boolean isActive(); + @Accessor("field_148533_g") + void setActive(boolean value); + @Accessor("field_148532_f") + void setPack(IResourcePack value); + @Accessor("field_148534_e") + File getCacheDir(); +} From 029b228b26f2ff9e9418b44205b295f6c50b7384 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 22 Feb 2021 23:43:48 +0100 Subject: [PATCH 014/102] Move ReplayModTweaker into 1.12.2 project --- .../core/tweaker/ReplayModTweaker.java | 128 +----------------- .../core/tweaker/ReplayModTweaker.java | 120 ++++++++++++++++ 2 files changed, 121 insertions(+), 127 deletions(-) create mode 100644 versions/1.12.2/src/main/java/com/replaymod/core/tweaker/ReplayModTweaker.java diff --git a/src/main/java/com/replaymod/core/tweaker/ReplayModTweaker.java b/src/main/java/com/replaymod/core/tweaker/ReplayModTweaker.java index 403ead3d..c690defc 100644 --- a/src/main/java/com/replaymod/core/tweaker/ReplayModTweaker.java +++ b/src/main/java/com/replaymod/core/tweaker/ReplayModTweaker.java @@ -1,127 +1 @@ -//#if FABRIC>=1 -// Fabric equivalent is in ReplayModMMLauncher -//#else -//#if MC>=11400 -//$$ // Generally not supported by RM -//#else -//$$ package com.replaymod.core.tweaker; -//$$ -//$$ import com.replaymod.extras.modcore.ModCoreInstaller; -//$$ import net.minecraft.launchwrapper.ITweaker; -//$$ import net.minecraft.launchwrapper.Launch; -//$$ import net.minecraft.launchwrapper.LaunchClassLoader; -//$$ import org.spongepowered.asm.launch.GlobalProperties; -//$$ import org.spongepowered.asm.launch.MixinBootstrap; -//$$ import org.spongepowered.asm.launch.platform.MixinPlatformManager; -//$$ -//$$ import java.io.File; -//$$ import java.net.URI; -//$$ import java.net.URISyntaxException; -//$$ import java.util.List; -//$$ -//#if MC>=11200 -//$$ import org.spongepowered.asm.launch.platform.container.ContainerHandleURI; -//#endif -//$$ -//$$ public class ReplayModTweaker implements ITweaker { -//$$ -//$$ private static final String MIXIN_TWEAKER = "org.spongepowered.asm.launch.MixinTweaker"; -//$$ -//$$ public ReplayModTweaker() { -//$$ injectMixinTweaker(); -//$$ } -//$$ -//$$ private void injectMixinTweaker() { -//$$ @SuppressWarnings("unchecked") -//$$ List tweakClasses = (List) Launch.blackboard.get("TweakClasses"); -//$$ -//$$ // If the MixinTweaker is already queued (because of another mod), then there's nothing we need to to -//$$ if (tweakClasses.contains(MIXIN_TWEAKER)) { -//$$ return; -//$$ } -//$$ -//$$ // If it is already booted, we're also good to go -//$$ if (GlobalProperties.get(GlobalProperties.Keys.INIT) != null) { -//$$ return; -//$$ } -//$$ -//$$ System.out.println("Injecting MixinTweaker from ReplayModTweaker"); -//$$ -//$$ // Otherwise, we need to take things into our own hands because the normal way to chainload a tweaker -//$$ // (by adding it to the TweakClasses list during injectIntoClassLoader) is too late for Mixin. -//$$ // Instead we instantiate the MixinTweaker on our own and add it to the current Tweaks list immediately. -//$$ Launch.classLoader.addClassLoaderExclusion(MIXIN_TWEAKER.substring(0, MIXIN_TWEAKER.lastIndexOf('.'))); -//$$ @SuppressWarnings("unchecked") -//$$ List tweaks = (List) Launch.blackboard.get("Tweaks"); -//$$ try { -//$$ tweaks.add((ITweaker) Class.forName(MIXIN_TWEAKER, true, Launch.classLoader).newInstance()); -//$$ } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { -//$$ throw new RuntimeException(e); -//$$ } -//$$ } -//$$ -//$$ @Override -//$$ public void acceptOptions(List args, File gameDir, File assetsDir, String profile) { -//$$ } -//$$ -//$$ @Override -//$$ public void injectIntoClassLoader(LaunchClassLoader classLoader) { -//$$ // Add our jar as a Mixin container (cause normally Mixin detects those via the TweakClass manifest entry) -//$$ URI uri; -//$$ try { -//$$ uri = this.getClass().getProtectionDomain().getCodeSource().getLocation().toURI(); -//$$ } catch (URISyntaxException e) { -//$$ throw new RuntimeException(e); -//$$ } -//$$ MixinPlatformManager platform = MixinBootstrap.getPlatform(); - //#if MC>=11200 - //$$ platform.addContainer(new ContainerHandleURI(uri)); - //#else - //$$ platform.addContainer(uri); - //#endif -//$$ - //#if MC>=11202 && MC<=11202 - //$$ initModCore("1.12.2"); - //#endif - //#if MC>=10809 && MC<=10809 - //$$ initModCore("1.8.9"); - //#endif -//$$ } -//$$ -//$$ @Override -//$$ public String getLaunchTarget() { -//$$ return null; -//$$ } -//$$ -//$$ @Override -//$$ public String[] getLaunchArguments() { -//$$ return new String[0]; -//$$ } -//$$ -//$$ private void initModCore(String mcVer) { -//$$ try { -//$$ if (System.getProperty("REPLAYMOD_SKIP_MODCORE", "false").equalsIgnoreCase("true")) { -//$$ System.out.println("ReplayMod not initializing ModCore because REPLAYMOD_SKIP_MODCORE is true."); -//$$ return; -//$$ } -//$$ -//$$ if ((Boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment")) { -//$$ System.out.println("ReplayMod not initializing ModCore because we're in a development environment."); -//$$ return; -//$$ } -//$$ -//$$ int result = ModCoreInstaller.initialize(Launch.minecraftHome, mcVer + "_forge"); -//$$ if (result != -2) { // Don't even bother logging the result if there's no ModCore for this version. -//$$ System.out.println("ReplayMod ModCore init result: " + result); -//$$ } -//$$ if (ModCoreInstaller.isErrored()) { -//$$ System.err.println(ModCoreInstaller.getError()); -//$$ } -//$$ } catch (Throwable t) { -//$$ System.err.println("ReplayMod caught error during ModCore init:"); -//$$ t.printStackTrace(); -//$$ } -//$$ } -//$$ } -//#endif -//#endif +// Forge only diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/tweaker/ReplayModTweaker.java b/versions/1.12.2/src/main/java/com/replaymod/core/tweaker/ReplayModTweaker.java new file mode 100644 index 00000000..b6205d1c --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/core/tweaker/ReplayModTweaker.java @@ -0,0 +1,120 @@ +package com.replaymod.core.tweaker; + +import com.replaymod.extras.modcore.ModCoreInstaller; +import net.minecraft.launchwrapper.ITweaker; +import net.minecraft.launchwrapper.Launch; +import net.minecraft.launchwrapper.LaunchClassLoader; +import org.spongepowered.asm.launch.GlobalProperties; +import org.spongepowered.asm.launch.MixinBootstrap; +import org.spongepowered.asm.launch.platform.MixinPlatformManager; + +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +//#if MC>=11200 +import org.spongepowered.asm.launch.platform.container.ContainerHandleURI; +//#endif + +// Fabric equivalent is in ReplayModMMLauncher +public class ReplayModTweaker implements ITweaker { + + private static final String MIXIN_TWEAKER = "org.spongepowered.asm.launch.MixinTweaker"; + + public ReplayModTweaker() { + injectMixinTweaker(); + } + + private void injectMixinTweaker() { + @SuppressWarnings("unchecked") + List tweakClasses = (List) Launch.blackboard.get("TweakClasses"); + + // If the MixinTweaker is already queued (because of another mod), then there's nothing we need to to + if (tweakClasses.contains(MIXIN_TWEAKER)) { + return; + } + + // If it is already booted, we're also good to go + if (GlobalProperties.get(GlobalProperties.Keys.INIT) != null) { + return; + } + + System.out.println("Injecting MixinTweaker from ReplayModTweaker"); + + // Otherwise, we need to take things into our own hands because the normal way to chainload a tweaker + // (by adding it to the TweakClasses list during injectIntoClassLoader) is too late for Mixin. + // Instead we instantiate the MixinTweaker on our own and add it to the current Tweaks list immediately. + Launch.classLoader.addClassLoaderExclusion(MIXIN_TWEAKER.substring(0, MIXIN_TWEAKER.lastIndexOf('.'))); + @SuppressWarnings("unchecked") + List tweaks = (List) Launch.blackboard.get("Tweaks"); + try { + tweaks.add((ITweaker) Class.forName(MIXIN_TWEAKER, true, Launch.classLoader).newInstance()); + } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + @Override + public void acceptOptions(List args, File gameDir, File assetsDir, String profile) { + } + + @Override + public void injectIntoClassLoader(LaunchClassLoader classLoader) { + // Add our jar as a Mixin container (cause normally Mixin detects those via the TweakClass manifest entry) + URI uri; + try { + uri = this.getClass().getProtectionDomain().getCodeSource().getLocation().toURI(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + MixinPlatformManager platform = MixinBootstrap.getPlatform(); + //#if MC>=11200 + platform.addContainer(new ContainerHandleURI(uri)); + //#else + //$$ platform.addContainer(uri); + //#endif + + //#if MC>=11202 && MC<=11202 + initModCore("1.12.2"); + //#endif + //#if MC>=10809 && MC<=10809 + //$$ initModCore("1.8.9"); + //#endif + } + + @Override + public String getLaunchTarget() { + return null; + } + + @Override + public String[] getLaunchArguments() { + return new String[0]; + } + + private void initModCore(String mcVer) { + try { + if (System.getProperty("REPLAYMOD_SKIP_MODCORE", "false").equalsIgnoreCase("true")) { + System.out.println("ReplayMod not initializing ModCore because REPLAYMOD_SKIP_MODCORE is true."); + return; + } + + if ((Boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment")) { + System.out.println("ReplayMod not initializing ModCore because we're in a development environment."); + return; + } + + int result = ModCoreInstaller.initialize(Launch.minecraftHome, mcVer + "_forge"); + if (result != -2) { // Don't even bother logging the result if there's no ModCore for this version. + System.out.println("ReplayMod ModCore init result: " + result); + } + if (ModCoreInstaller.isErrored()) { + System.err.println(ModCoreInstaller.getError()); + } + } catch (Throwable t) { + System.err.println("ReplayMod caught error during ModCore init:"); + t.printStackTrace(); + } + } +} From 6094422792808b28c03e9d1eb405e56cb6314543 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 22 Feb 2021 23:56:22 +0100 Subject: [PATCH 015/102] Split off highly version-dependent code from ModCompat --- .../com/replaymod/core/utils/ModCompat.java | 79 +------------------ .../replaymod/core/utils/ModInfoGetter.java | 25 ++++++ .../replaymod/core/utils/ModInfoGetter.java | 29 +++++++ .../replaymod/core/utils/ModInfoGetter.java | 29 +++++++ .../replaymod/core/utils/ModInfoGetter.java | 11 +++ .../replaymod/core/utils/ModInfoGetter.java | 32 ++++++++ 6 files changed, 127 insertions(+), 78 deletions(-) create mode 100644 src/main/java/com/replaymod/core/utils/ModInfoGetter.java create mode 100644 versions/1.11.2/src/main/java/com/replaymod/core/utils/ModInfoGetter.java create mode 100644 versions/1.12.2/src/main/java/com/replaymod/core/utils/ModInfoGetter.java create mode 100644 versions/1.14.4-forge/src/main/java/com/replaymod/core/utils/ModInfoGetter.java create mode 100644 versions/1.7.10/src/main/java/com/replaymod/core/utils/ModInfoGetter.java diff --git a/src/main/java/com/replaymod/core/utils/ModCompat.java b/src/main/java/com/replaymod/core/utils/ModCompat.java index 453011bd..44a6173b 100644 --- a/src/main/java/com/replaymod/core/utils/ModCompat.java +++ b/src/main/java/com/replaymod/core/utils/ModCompat.java @@ -1,89 +1,12 @@ package com.replaymod.core.utils; import com.replaymod.replaystudio.data.ModInfo; -import net.minecraft.util.Identifier; - -//#if FABRIC>=1 -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.ModContainer; -import net.minecraft.util.registry.Registry; -//#else -//#if MC>=11200 -//$$ import net.minecraftforge.registries.ForgeRegistry; -//$$ import net.minecraftforge.registries.RegistryManager; -//#else -//$$ import net.minecraftforge.fml.common.registry.GameData; -//$$ import java.util.stream.Stream; -//#endif -//$$ -//#if MC>=11400 -//$$ import net.minecraftforge.fml.ModList; -//#else -//$$ import net.minecraftforge.fml.common.Loader; -//$$ import net.minecraftforge.fml.common.ModContainer; -//#endif -//#endif import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; public class ModCompat { - @SuppressWarnings("unchecked") public static Collection getInstalledNetworkMods() { - //#if MC>=11400 - //#if FABRIC>=1 - Map modInfoMap = FabricLoader.getInstance().getAllMods().stream() - .map(ModContainer::getMetadata) - .map(m -> new ModInfo(m.getId(), m.getName(), m.getVersion().toString())) - .collect(Collectors.toMap(ModInfo::getId, Function.identity())); - return Registry.REGISTRIES.stream() - .map(Registry::getIds).flatMap(Set::stream) - //#else - //$$ Map modInfoMap = ModList.get().getMods().stream() - //$$ .map(m -> new ModInfo(m.getModId(), m.getDisplayName(), m.getVersion().toString())) - //$$ .collect(Collectors.toMap(ModInfo::getId, Function.identity())); - //$$ return RegistryManager.ACTIVE.takeSnapshot(false).keySet().stream() - //$$ .map(RegistryManager.ACTIVE::getRegistry) - //$$ .map(ForgeRegistry::getKeys).flatMap(Set::stream) - //#endif - .map(Identifier::getNamespace).filter(s -> !s.equals("minecraft")).distinct() - .map(modInfoMap::get).filter(Objects::nonNull) - .collect(Collectors.toList()); - //#else - //$$ Map ignoreCaseMap = Loader.instance().getModList().stream() - //$$ .collect(Collectors.toMap(m -> m.getModId().toLowerCase(), Function.identity())); - //#if MC>=11200 - //$$ return RegistryManager.ACTIVE.takeSnapshot(false).keySet().stream() - //$$ .map(RegistryManager.ACTIVE::getRegistry) - //$$ .map(ForgeRegistry::getKeys).flatMap(Set::stream) - //$$ .map(ResourceLocation::getResourceDomain).filter(s -> !s.equals("minecraft")).distinct() - //$$ .map(String::toLowerCase).map(ignoreCaseMap::get).filter(mod -> mod != null) - //$$ .map(mod -> new ModInfo(mod.getModId(), mod.getName(), mod.getVersion())) - //$$ .collect(Collectors.toList()); - //#else - //#if MC>=10800 - //$$ return Stream.concat( - //$$ ((Set) GameData.getBlockRegistry().getKeys()).stream(), - //$$ ((Set) GameData.getItemRegistry().getKeys()).stream() - //$$ ).map(ResourceLocation::getResourceDomain).filter(s -> !s.equals("minecraft")).distinct() - //$$ .map(String::toLowerCase).map(ignoreCaseMap::get).filter(mod -> mod != null) - //$$ .map(mod -> new ModInfo(mod.getModId(), mod.getName(), mod.getVersion())) - //$$ .collect(Collectors.toList()); - //#else - //$$ return Stream.concat( - //$$ ((Set) GameData.getBlockRegistry().getKeys()).stream(), - //$$ ((Set) GameData.getItemRegistry().getKeys()).stream() - //$$ ).map(name -> { - //$$ if (!name.contains(":")) return null; // Still using old names without namespace, can't do anything, ignore - //$$ return name.split(":", 2)[0]; - //$$ }).filter(s -> !s.equals("minecraft")).distinct() - //$$ .map(String::toLowerCase).map(ignoreCaseMap::get).filter(mod -> mod != null) - //$$ .map(mod -> new ModInfo(mod.getModId(), mod.getName(), mod.getVersion())) - //$$ .collect(Collectors.toList()); - //#endif - //#endif - //#endif + return ModInfoGetter.getInstalledNetworkMods(); } public static final class ModInfoDifference { diff --git a/src/main/java/com/replaymod/core/utils/ModInfoGetter.java b/src/main/java/com/replaymod/core/utils/ModInfoGetter.java new file mode 100644 index 00000000..d4bbe156 --- /dev/null +++ b/src/main/java/com/replaymod/core/utils/ModInfoGetter.java @@ -0,0 +1,25 @@ +package com.replaymod.core.utils; +import com.replaymod.replaystudio.data.ModInfo; +import net.minecraft.util.Identifier; + +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; +import net.minecraft.util.registry.Registry; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +class ModInfoGetter { + static Collection getInstalledNetworkMods() { + Map modInfoMap = FabricLoader.getInstance().getAllMods().stream() + .map(ModContainer::getMetadata) + .map(m -> new ModInfo(m.getId(), m.getName(), m.getVersion().toString())) + .collect(Collectors.toMap(ModInfo::getId, Function.identity())); + return Registry.REGISTRIES.stream() + .map(Registry::getIds).flatMap(Set::stream) + .map(Identifier::getNamespace).filter(s -> !s.equals("minecraft")).distinct() + .map(modInfoMap::get).filter(Objects::nonNull) + .collect(Collectors.toList()); + } +} diff --git a/versions/1.11.2/src/main/java/com/replaymod/core/utils/ModInfoGetter.java b/versions/1.11.2/src/main/java/com/replaymod/core/utils/ModInfoGetter.java new file mode 100644 index 00000000..0d9db53a --- /dev/null +++ b/versions/1.11.2/src/main/java/com/replaymod/core/utils/ModInfoGetter.java @@ -0,0 +1,29 @@ +package com.replaymod.core.utils; + +import com.replaymod.replaystudio.data.ModInfo; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.ModContainer; +import net.minecraftforge.fml.common.registry.GameData; + +import java.util.Collection; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class ModInfoGetter { + static Collection getInstalledNetworkMods() { + Map ignoreCaseMap = Loader.instance().getModList().stream() + .collect(Collectors.toMap(m -> m.getModId().toLowerCase(), Function.identity())); + return Stream.concat( + ((Set) GameData.getBlockRegistry().getKeys()).stream(), + ((Set) GameData.getItemRegistry().getKeys()).stream() + ).map(ResourceLocation::getResourceDomain).filter(s -> !s.equals("minecraft")).distinct() + .map(String::toLowerCase).map(ignoreCaseMap::get).filter(Objects::nonNull) + .map(mod -> new ModInfo(mod.getModId(), mod.getName(), mod.getVersion())) + .collect(Collectors.toList()); + } +} diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/utils/ModInfoGetter.java b/versions/1.12.2/src/main/java/com/replaymod/core/utils/ModInfoGetter.java new file mode 100644 index 00000000..1ec326e3 --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/core/utils/ModInfoGetter.java @@ -0,0 +1,29 @@ +package com.replaymod.core.utils; + +import com.replaymod.replaystudio.data.ModInfo; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.ModContainer; +import net.minecraftforge.registries.ForgeRegistry; +import net.minecraftforge.registries.RegistryManager; + +import java.util.Collection; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +class ModInfoGetter { + static Collection getInstalledNetworkMods() { + Map ignoreCaseMap = Loader.instance().getModList().stream() + .collect(Collectors.toMap(m -> m.getModId().toLowerCase(), Function.identity())); + return RegistryManager.ACTIVE.takeSnapshot(false).keySet().stream() + .map(RegistryManager.ACTIVE::getRegistry) + .map(ForgeRegistry::getKeys).flatMap(Set::stream) + .map(ResourceLocation::getResourceDomain).filter(s -> !s.equals("minecraft")).distinct() + .map(String::toLowerCase).map(ignoreCaseMap::get).filter(Objects::nonNull) + .map(mod -> new ModInfo(mod.getModId(), mod.getName(), mod.getVersion())) + .collect(Collectors.toList()); + } +} diff --git a/versions/1.14.4-forge/src/main/java/com/replaymod/core/utils/ModInfoGetter.java b/versions/1.14.4-forge/src/main/java/com/replaymod/core/utils/ModInfoGetter.java new file mode 100644 index 00000000..7bb66d98 --- /dev/null +++ b/versions/1.14.4-forge/src/main/java/com/replaymod/core/utils/ModInfoGetter.java @@ -0,0 +1,11 @@ +package com.replaymod.core.utils; + +import com.replaymod.replaystudio.data.ModInfo; + +import java.util.Collection; + +class ModInfoGetter { + static Collection getInstalledNetworkMods() { + throw new UnsupportedOperationException(); + } +} diff --git a/versions/1.7.10/src/main/java/com/replaymod/core/utils/ModInfoGetter.java b/versions/1.7.10/src/main/java/com/replaymod/core/utils/ModInfoGetter.java new file mode 100644 index 00000000..c8b8e842 --- /dev/null +++ b/versions/1.7.10/src/main/java/com/replaymod/core/utils/ModInfoGetter.java @@ -0,0 +1,32 @@ +package com.replaymod.core.utils; + +import com.replaymod.replaystudio.data.ModInfo; +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.common.ModContainer; +import cpw.mods.fml.common.registry.GameData; + +import java.util.Collection; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class ModInfoGetter { + static Collection getInstalledNetworkMods() { + Map ignoreCaseMap = Loader.instance().getModList().stream() + .collect(Collectors.toMap(m -> m.getModId().toLowerCase(), Function.identity())); + return Stream.concat( + ((Set) GameData.getBlockRegistry().getKeys()).stream(), + ((Set) GameData.getItemRegistry().getKeys()).stream() + ).map(name -> { + if (!name.contains(":")) return null; // Still using old names without namespace, can't do anything, ignore + return name.split(":", 2)[0]; + }).filter(Objects::nonNull) + .filter(s -> !s.equals("minecraft")).distinct() + .map(String::toLowerCase).map(ignoreCaseMap::get).filter(Objects::nonNull) + .map(mod -> new ModInfo(mod.getModId(), mod.getName(), mod.getVersion())) + .collect(Collectors.toList()); + } +} From 22d1048999e030d88beddd42aa7b8fb39ee7b5f4 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 00:22:00 +0100 Subject: [PATCH 016/102] Move FMLHandshakeFilter into 1.12.2 project --- .../recording/handler/FMLHandshakeFilter.java | 32 +------------------ .../recording/handler/FMLHandshakeFilter.java | 29 +++++++++++++++++ 2 files changed, 30 insertions(+), 31 deletions(-) create mode 100644 versions/1.12.2/src/main/java/com/replaymod/recording/handler/FMLHandshakeFilter.java diff --git a/src/main/java/com/replaymod/recording/handler/FMLHandshakeFilter.java b/src/main/java/com/replaymod/recording/handler/FMLHandshakeFilter.java index f280ca13..fca4cd6c 100644 --- a/src/main/java/com/replaymod/recording/handler/FMLHandshakeFilter.java +++ b/src/main/java/com/replaymod/recording/handler/FMLHandshakeFilter.java @@ -1,31 +1 @@ -//#if MC<11400 -//$$ package com.replaymod.recording.handler; -//$$ -//$$ import io.netty.channel.ChannelHandlerContext; -//$$ import io.netty.channel.SimpleChannelInboundHandler; -//$$ import net.minecraftforge.fml.common.network.handshake.FMLHandshakeMessage; -//$$ -//$$ /** -//$$ * Filters out all handshake packets that were sent for recording but must -//$$ * not actually be handled. -//$$ * This handler is only present when connected to the integrated server as -//$$ * otherwise all packets must be handled. -//$$ * -//$$ * When in single player, the game state packets must never be handled -//$$ * otherwise wired bugs related to semi-singletons can occur. -//$$ * See https://bugs.replaymod.com/show_bug.cgi?id=44 -//$$ */ -//$$ public class FMLHandshakeFilter extends SimpleChannelInboundHandler { -//$$ @Override -//$$ protected void channelRead0(ChannelHandlerContext ctx, FMLHandshakeMessage msg) throws Exception { - //#if MC>=10800 - //$$ if (!(msg instanceof FMLHandshakeMessage.RegistryData)) { - //#else - //$$ if (!(msg instanceof FMLHandshakeMessage.ModIdData)) { - //#endif -//$$ // Pass on everything but RegistryData messages -//$$ ctx.fireChannelRead(msg); -//$$ } -//$$ } -//$$ } -//#endif +// 1.12.2 and below diff --git a/versions/1.12.2/src/main/java/com/replaymod/recording/handler/FMLHandshakeFilter.java b/versions/1.12.2/src/main/java/com/replaymod/recording/handler/FMLHandshakeFilter.java new file mode 100644 index 00000000..f53c5533 --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/recording/handler/FMLHandshakeFilter.java @@ -0,0 +1,29 @@ +package com.replaymod.recording.handler; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import net.minecraftforge.fml.common.network.handshake.FMLHandshakeMessage; + +/** + * Filters out all handshake packets that were sent for recording but must + * not actually be handled. + * This handler is only present when connected to the integrated server as + * otherwise all packets must be handled. + * + * When in single player, the game state packets must never be handled + * otherwise wired bugs related to semi-singletons can occur. + * See https://bugs.replaymod.com/show_bug.cgi?id=44 + */ +public class FMLHandshakeFilter extends SimpleChannelInboundHandler { + @Override + protected void channelRead0(ChannelHandlerContext ctx, FMLHandshakeMessage msg) throws Exception { + //#if MC>=10800 + if (!(msg instanceof FMLHandshakeMessage.RegistryData)) { + //#else + //$$ if (!(msg instanceof FMLHandshakeMessage.ModIdData)) { + //#endif + // Pass on everything but RegistryData messages + ctx.fireChannelRead(msg); + } + } +} From 25247a2371be5c1d3e675e27fdb541c4d29c4aa6 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 00:29:55 +0100 Subject: [PATCH 017/102] Move MixinGuiScreen into 1.7.10 project --- .../recording/mixin/MixinGuiScreen.java | 46 +------------------ .../recording/mixin/MixinGuiScreen.java | 43 +++++++++++++++++ 2 files changed, 44 insertions(+), 45 deletions(-) create mode 100644 versions/1.7.10/src/main/java/com/replaymod/recording/mixin/MixinGuiScreen.java diff --git a/src/main/java/com/replaymod/recording/mixin/MixinGuiScreen.java b/src/main/java/com/replaymod/recording/mixin/MixinGuiScreen.java index c205f9ac..743815c4 100644 --- a/src/main/java/com/replaymod/recording/mixin/MixinGuiScreen.java +++ b/src/main/java/com/replaymod/recording/mixin/MixinGuiScreen.java @@ -1,45 +1 @@ -//#if MC<=10710 -//$$ package com.replaymod.recording.mixin; -//$$ -//$$ import de.johni0702.minecraft.gui.container.VanillaGuiScreen; -//$$ import net.minecraft.client.gui.GuiScreen; -//$$ import org.lwjgl.input.Keyboard; -//$$ import org.lwjgl.input.Mouse; -//$$ 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; -//$$ -//$$ import static com.replaymod.core.versions.MCVer.*; -//$$ -//$$ @Mixin(GuiScreen.class) -//$$ public abstract class MixinGuiScreen { -//$$ -//$$ @Inject(method = "handleInput", at = @At("HEAD"), cancellable = true) -//$$ private void handleJGuiInput(CallbackInfo ci) { -//$$ ci.cancel(); -//$$ if (Mouse.isCreated()) { -//$$ while (Mouse.next()) { -//$$ if (FORGE_BUS.post(new VanillaGuiScreen.MouseInputEvent())) { -//$$ continue; -//$$ } -//$$ handleMouseInput(); -//$$ } -//$$ } -//$$ -//$$ if (Keyboard.isCreated()) { -//$$ while (Keyboard.next()) { -//$$ if (FORGE_BUS.post(new VanillaGuiScreen.KeyboardInputEvent())) { -//$$ continue; -//$$ } -//$$ handleKeyboardInput(); -//$$ } -//$$ } -//$$ } -//$$ -//$$ @Shadow public abstract void handleMouseInput(); -//$$ -//$$ @Shadow public abstract void handleKeyboardInput(); -//$$ } -//#endif +// 1.7.10 and below diff --git a/versions/1.7.10/src/main/java/com/replaymod/recording/mixin/MixinGuiScreen.java b/versions/1.7.10/src/main/java/com/replaymod/recording/mixin/MixinGuiScreen.java new file mode 100644 index 00000000..c9d30754 --- /dev/null +++ b/versions/1.7.10/src/main/java/com/replaymod/recording/mixin/MixinGuiScreen.java @@ -0,0 +1,43 @@ +package com.replaymod.recording.mixin; + +import de.johni0702.minecraft.gui.container.VanillaGuiScreen; +import net.minecraft.client.gui.GuiScreen; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; +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; + +import static com.replaymod.core.versions.MCVer.*; + +@Mixin(GuiScreen.class) +public abstract class MixinGuiScreen { + + @Inject(method = "handleInput", at = @At("HEAD"), cancellable = true) + private void handleJGuiInput(CallbackInfo ci) { + ci.cancel(); + if (Mouse.isCreated()) { + while (Mouse.next()) { + if (FORGE_BUS.post(new VanillaGuiScreen.MouseInputEvent())) { + continue; + } + handleMouseInput(); + } + } + + if (Keyboard.isCreated()) { + while (Keyboard.next()) { + if (FORGE_BUS.post(new VanillaGuiScreen.KeyboardInputEvent())) { + continue; + } + handleKeyboardInput(); + } + } + } + + @Shadow public abstract void handleMouseInput(); + + @Shadow public abstract void handleKeyboardInput(); +} From ba7c478da1469fd9898ad68b8866beda63f780c8 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 00:35:37 +0100 Subject: [PATCH 018/102] Split off 1.12.2 overwrite from MixinNetHandlerLoginClient --- .../mixin/MixinNetHandlerLoginClient.java | 46 +++---------------- .../mixin/MixinNetHandlerLoginClient.java | 37 +++++++++++++++ versions/1.8/mapping.txt | 1 + 3 files changed, 45 insertions(+), 39 deletions(-) create mode 100644 versions/1.12.2/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java diff --git a/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java index 54cf8e67..b67d40bc 100644 --- a/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java +++ b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java @@ -1,35 +1,26 @@ package com.replaymod.recording.mixin; +import com.replaymod.core.versions.MCVer; import com.replaymod.recording.ReplayModRecording; +import com.replaymod.recording.handler.RecordingEventHandler.RecordingEventSender; import net.minecraft.client.network.ClientLoginNetworkHandler; import net.minecraft.network.ClientConnection; +import net.minecraft.network.Packet; +import net.minecraft.network.packet.s2c.login.LoginQueryRequestS2CPacket; +import net.minecraft.network.packet.s2c.login.LoginSuccessS2CPacket; +import org.spongepowered.asm.mixin.Final; 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; -//#if MC>=11400 -import com.replaymod.core.versions.MCVer; -import com.replaymod.recording.handler.RecordingEventHandler.RecordingEventSender; -import net.minecraft.network.Packet; -import net.minecraft.network.packet.s2c.login.LoginQueryRequestS2CPacket; -import net.minecraft.network.packet.s2c.login.LoginSuccessS2CPacket; -//#else -//$$ import net.minecraftforge.fml.common.network.FMLNetworkEvent; -//#endif - @Mixin(ClientLoginNetworkHandler.class) public abstract class MixinNetHandlerLoginClient { - @Shadow - //#if MC>=10800 + @Final @Shadow private ClientConnection connection; - //#else - //$$ private NetworkManager field_147393_d; - //#endif - //#if MC>=11400 @Inject(method = "onQueryRequest", at=@At("HEAD")) private void earlyInitiateRecording(LoginQueryRequestS2CPacket packet, CallbackInfo ci) { initiateRecording(packet); @@ -50,27 +41,4 @@ public abstract class MixinNetHandlerLoginClient { eventSender.getRecordingEventHandler().onPacket(packet); } } - //#else - //$$ /** - //$$ * Starts the recording right before switching into PLAY state. - //$$ * We cannot use the {@link FMLNetworkEvent.ClientConnectedToServerEvent} - //$$ * as it only fires after the forge handshake. - //$$ */ - //$$ @Inject(method = "handleLoginSuccess", at=@At("HEAD")) - //$$ public void replayModRecording_initiateRecording(CallbackInfo cb) { - //#if MC>=10800 - //$$ ReplayModRecording.instance.initiateRecording(this.networkManager); - //#else - //$$ ReplayModRecording.instance.initiateRecording(this.field_147393_d); - //#endif - //$$ } - //#endif - - // Race condition in Forge's networking (not sure if still present in 1.13) - //#if MC>=11200 && MC<11400 - //$$ @Inject(method = "handleLoginSuccess", at=@At("RETURN")) - //$$ public void replayModRecording_raceConditionWorkAround(CallbackInfo cb) { - //$$ ((NetworkManagerAccessor) this.networkManager).getChannel().config().setAutoRead(true); - //$$ } - //#endif } diff --git a/versions/1.12.2/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java b/versions/1.12.2/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java new file mode 100644 index 00000000..10c052e8 --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerLoginClient.java @@ -0,0 +1,37 @@ +package com.replaymod.recording.mixin; + +import com.replaymod.recording.ReplayModRecording; +import net.minecraft.client.network.NetHandlerLoginClient; +import net.minecraft.network.NetworkManager; +import net.minecraftforge.fml.common.network.FMLNetworkEvent; +import org.spongepowered.asm.mixin.Final; +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(NetHandlerLoginClient.class) +public abstract class MixinNetHandlerLoginClient { + + @Final @Shadow + private NetworkManager networkManager; + + /** + * Starts the recording right before switching into PLAY state. + * We cannot use the {@link FMLNetworkEvent.ClientConnectedToServerEvent} + * as it only fires after the forge handshake. + */ + @Inject(method = "handleLoginSuccess", at=@At("HEAD")) + public void replayModRecording_initiateRecording(CallbackInfo cb) { + ReplayModRecording.instance.initiateRecording(this.networkManager); + } + + // Race condition in Forge's networking (not sure if still present in 1.13) + //#if MC>=11200 && MC<11400 + @Inject(method = "handleLoginSuccess", at=@At("RETURN")) + public void replayModRecording_raceConditionWorkAround(CallbackInfo cb) { + ((NetworkManagerAccessor) this.networkManager).getChannel().config().setAutoRead(true); + } + //#endif +} diff --git a/versions/1.8/mapping.txt b/versions/1.8/mapping.txt index 8f452af4..3712d8e0 100644 --- a/versions/1.8/mapping.txt +++ b/versions/1.8/mapping.txt @@ -34,3 +34,4 @@ net.minecraftforge.fml.common.gameevent.InputEvent cpw.mods.fml.common.gameevent net.minecraft.client.renderer.tileentity.TileEntityEndPortalRenderer net.minecraft.client.renderer.tileentity.RenderEndPortal net.minecraft.network.play.server.S3FPacketCustomPayload getChannelName() func_149169_c() net.minecraft.network.play.server.S01PacketJoinGame getEntityId() func_149197_c() +net.minecraft.client.network.NetHandlerLoginClient networkManager field_147393_d From 6bc130312a4d6e3791ac4fd4984e6d899d4a527a Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 00:37:50 +0100 Subject: [PATCH 019/102] Move MixinNetworkDispatcher into 1.12.2 project --- .../mixin/MixinNetworkDispatcher.java | 71 +------------------ .../mixin/MixinNetworkDispatcher.java | 69 ++++++++++++++++++ 2 files changed, 70 insertions(+), 70 deletions(-) create mode 100644 versions/1.12.2/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java diff --git a/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java b/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java index 0ea736a1..fca4cd6c 100644 --- a/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java +++ b/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java @@ -1,70 +1 @@ -//#if MC<11400 -//$$ package com.replaymod.recording.mixin; -//$$ -//$$ import com.replaymod.recording.handler.FMLHandshakeFilter; -//$$ import io.netty.channel.ChannelPipeline; -//$$ import io.netty.channel.embedded.EmbeddedChannel; -//$$ import net.minecraftforge.fml.common.network.handshake.FMLHandshakeCodec; -//$$ import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher; -//$$ import net.minecraftforge.fml.relauncher.Side; -//$$ 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; -//$$ -//#if MC>=11200 -//$$ import io.netty.channel.ChannelConfig; -//$$ import net.minecraft.network.EnumConnectionState; -//$$ import net.minecraft.network.NetworkManager; -//$$ import org.spongepowered.asm.mixin.injection.Redirect; -//#endif -//$$ -//$$ @Mixin(value = NetworkDispatcher.class, remap = false) -//$$ public abstract class MixinNetworkDispatcher { -//$$ -//$$ @Shadow -//$$ private Side side; -//$$ -//$$ @Shadow -//$$ private EmbeddedChannel handshakeChannel; -//$$ -//$$ /** -//$$ * Always sets fml:isLocal to false on the server side. -//$$ * This effectively removes the difference in the FML handshake between SP and MP -//$$ * and forces the block/item ids, etc. to always be send. -//$$ * Injects a {@link FMLHandshakeFilter} on the client side to filter out -//$$ * those extra, unexpected packets. -//$$ */ -//$$ @Inject(method = "insertIntoChannel", at=@At("HEAD")) -//$$ public void replayModRecording_setupForLocalRecording(CallbackInfo cb) { -//$$ // If we're in multiplayer, everything is fine as is -//$$ if (!handshakeChannel.attr(NetworkDispatcher.IS_LOCAL).get()) return; -//$$ -//$$ if (side == Side.SERVER) { -//$$ // On the server side, force all packets to be sent -//$$ handshakeChannel.attr(NetworkDispatcher.IS_LOCAL).set(false); -//$$ } else { -//$$ // On the client side, discard additional packets -//$$ ChannelPipeline pipeline = handshakeChannel.pipeline(); -//$$ pipeline.addAfter(pipeline.context(FMLHandshakeCodec.class).name(), -//$$ "replaymod_filter", new FMLHandshakeFilter()); -//$$ } -//$$ } -//$$ - //#if MC>=11200 - //$$ @Redirect(method = "clientListenForServerHandshake", at = @At(value = "INVOKE", remap = true, target = - //$$ "Lnet/minecraft/network/NetworkManager;setConnectionState(Lnet/minecraft/network/EnumConnectionState;)V")) - //$$ public void replayModRecording_raceConditionWorkAround1(NetworkManager self, EnumConnectionState ignored) { } - //$$ - //$$ @Redirect(method = "insertIntoChannel", at = @At(value = "INVOKE", target = - //$$ "Lio/netty/channel/ChannelConfig;setAutoRead(Z)Lio/netty/channel/ChannelConfig;")) - //$$ public ChannelConfig replayModRecording_raceConditionWorkAround2(ChannelConfig self, boolean autoRead) { - //$$ if (side == Side.CLIENT) { - //$$ autoRead = false; - //$$ } - //$$ return self.setAutoRead(autoRead); - //$$ } - //#endif -//$$ } -//#endif +// 1.12.2 and below diff --git a/versions/1.12.2/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java b/versions/1.12.2/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java new file mode 100644 index 00000000..120dd947 --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/recording/mixin/MixinNetworkDispatcher.java @@ -0,0 +1,69 @@ +package com.replaymod.recording.mixin; + +import com.replaymod.recording.handler.FMLHandshakeFilter; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.embedded.EmbeddedChannel; +import net.minecraftforge.fml.common.network.handshake.FMLHandshakeCodec; +import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher; +import net.minecraftforge.fml.relauncher.Side; +import org.spongepowered.asm.mixin.Final; +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; + +//#if MC>=11200 +import io.netty.channel.ChannelConfig; +import net.minecraft.network.EnumConnectionState; +import net.minecraft.network.NetworkManager; +import org.spongepowered.asm.mixin.injection.Redirect; +//#endif + +@Mixin(value = NetworkDispatcher.class, remap = false) +public abstract class MixinNetworkDispatcher { + + @Final @Shadow + private Side side; + + @Final @Shadow + private EmbeddedChannel handshakeChannel; + + /** + * Always sets fml:isLocal to false on the server side. + * This effectively removes the difference in the FML handshake between SP and MP + * and forces the block/item ids, etc. to always be send. + * Injects a {@link FMLHandshakeFilter} on the client side to filter out + * those extra, unexpected packets. + */ + @Inject(method = "insertIntoChannel", at=@At("HEAD")) + public void replayModRecording_setupForLocalRecording(CallbackInfo cb) { + // If we're in multiplayer, everything is fine as is + if (!handshakeChannel.attr(NetworkDispatcher.IS_LOCAL).get()) return; + + if (side == Side.SERVER) { + // On the server side, force all packets to be sent + handshakeChannel.attr(NetworkDispatcher.IS_LOCAL).set(false); + } else { + // On the client side, discard additional packets + ChannelPipeline pipeline = handshakeChannel.pipeline(); + pipeline.addAfter(pipeline.context(FMLHandshakeCodec.class).name(), + "replaymod_filter", new FMLHandshakeFilter()); + } + } + + //#if MC>=11200 + @Redirect(method = "clientListenForServerHandshake", at = @At(value = "INVOKE", remap = true, target = + "Lnet/minecraft/network/NetworkManager;setConnectionState(Lnet/minecraft/network/EnumConnectionState;)V")) + public void replayModRecording_raceConditionWorkAround1(NetworkManager self, EnumConnectionState ignored) { } + + @Redirect(method = "insertIntoChannel", at = @At(value = "INVOKE", target = + "Lio/netty/channel/ChannelConfig;setAutoRead(Z)Lio/netty/channel/ChannelConfig;")) + public ChannelConfig replayModRecording_raceConditionWorkAround2(ChannelConfig self, boolean autoRead) { + if (side == Side.CLIENT) { + autoRead = false; + } + return self.setAutoRead(autoRead); + } + //#endif +} From 6068aabea748ced1473e5ac3007270deb71238e1 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 00:45:12 +0100 Subject: [PATCH 020/102] Move MixinPlayerControllerMP into 1.12.2 project --- .../mixin/MixinPlayerControllerMP.java | 33 +------------------ .../mixin/MixinPlayerControllerMP.java | 33 +++++++++++++++++++ .../mixin/MixinPlayerControllerMP.java | 1 + 3 files changed, 35 insertions(+), 32 deletions(-) create mode 100644 versions/1.12.2/src/main/java/com/replaymod/recording/mixin/MixinPlayerControllerMP.java create mode 100644 versions/1.8.9/src/main/java/com/replaymod/recording/mixin/MixinPlayerControllerMP.java diff --git a/src/main/java/com/replaymod/recording/mixin/MixinPlayerControllerMP.java b/src/main/java/com/replaymod/recording/mixin/MixinPlayerControllerMP.java index 2084aa75..1adc3fa2 100644 --- a/src/main/java/com/replaymod/recording/mixin/MixinPlayerControllerMP.java +++ b/src/main/java/com/replaymod/recording/mixin/MixinPlayerControllerMP.java @@ -1,32 +1 @@ -package com.replaymod.recording.mixin; - -//#if MC>=10904 && MC<11400 -//$$ 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; -//$$ -//$$ import static com.replaymod.core.versions.MCVer.*; -//$$ -//$$ @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.player, type, pos, data); -//$$ } -//$$ } -//#endif +// 1.9.4 - 1.12.2 diff --git a/versions/1.12.2/src/main/java/com/replaymod/recording/mixin/MixinPlayerControllerMP.java b/versions/1.12.2/src/main/java/com/replaymod/recording/mixin/MixinPlayerControllerMP.java new file mode 100644 index 00000000..11e08b99 --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/recording/mixin/MixinPlayerControllerMP.java @@ -0,0 +1,33 @@ +package com.replaymod.recording.mixin; + +//#if MC>=10904 && MC<11400 +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.Final; +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; + +import static com.replaymod.core.versions.MCVer.*; + +@Mixin(PlayerControllerMP.class) +public abstract class MixinPlayerControllerMP implements RecordingEventHandler.RecordingEventSender { + + @Final @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.player, type, pos, data); + } +} +//#endif diff --git a/versions/1.8.9/src/main/java/com/replaymod/recording/mixin/MixinPlayerControllerMP.java b/versions/1.8.9/src/main/java/com/replaymod/recording/mixin/MixinPlayerControllerMP.java new file mode 100644 index 00000000..1adc3fa2 --- /dev/null +++ b/versions/1.8.9/src/main/java/com/replaymod/recording/mixin/MixinPlayerControllerMP.java @@ -0,0 +1 @@ +// 1.9.4 - 1.12.2 From 06db2ebb92875f833b9be1cbf0ff45a2082ca1c0 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 00:46:28 +0100 Subject: [PATCH 021/102] Move MixinS26PacketMapChunkBulk into 1.7.10 project --- .../mixin/MixinS26PacketMapChunkBulk.java | 39 +------------------ .../mixin/MixinS26PacketMapChunkBulk.java | 36 +++++++++++++++++ 2 files changed, 37 insertions(+), 38 deletions(-) create mode 100644 versions/1.7.10/src/main/java/com/replaymod/recording/mixin/MixinS26PacketMapChunkBulk.java diff --git a/src/main/java/com/replaymod/recording/mixin/MixinS26PacketMapChunkBulk.java b/src/main/java/com/replaymod/recording/mixin/MixinS26PacketMapChunkBulk.java index be5ef086..743815c4 100644 --- a/src/main/java/com/replaymod/recording/mixin/MixinS26PacketMapChunkBulk.java +++ b/src/main/java/com/replaymod/recording/mixin/MixinS26PacketMapChunkBulk.java @@ -1,38 +1 @@ -//#if MC<=10710 -//$$ package com.replaymod.recording.mixin; -//$$ -//$$ import net.minecraft.network.PacketBuffer; -//$$ import net.minecraft.network.play.server.S21PacketChunkData; -//$$ import net.minecraft.network.play.server.S26PacketMapChunkBulk; -//$$ 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; -//$$ -//$$ import java.util.concurrent.Semaphore; -//$$ -//$$ @Mixin({ S21PacketChunkData.class, S26PacketMapChunkBulk.class }) -//$$ public abstract class MixinS26PacketMapChunkBulk { -//$$ -//$$ private byte[] rawData; -//$$ -//$$ @Shadow(remap = false) -//$$ private Semaphore deflateGate; -//$$ -//$$ @Inject(method = "readPacketData", at = @At("HEAD")) -//$$ private void replayModRecording_readRawPacketData(PacketBuffer data, CallbackInfo ci) { -//$$ int readerIndex = data.readerIndex(); -//$$ data.readBytes(rawData = new byte[data.readableBytes()]); -//$$ data.readerIndex(readerIndex); -//$$ } -//$$ -//$$ @Inject(method = "writePacketData", at = @At("HEAD"), cancellable = true) -//$$ private void replayModRecording_writePacketData(PacketBuffer data, CallbackInfo ci) { -//$$ if (rawData != null && deflateGate == null) { -//$$ data.writeBytes(rawData); -//$$ ci.cancel(); -//$$ } -//$$ } -//$$ } -//#endif +// 1.7.10 and below diff --git a/versions/1.7.10/src/main/java/com/replaymod/recording/mixin/MixinS26PacketMapChunkBulk.java b/versions/1.7.10/src/main/java/com/replaymod/recording/mixin/MixinS26PacketMapChunkBulk.java new file mode 100644 index 00000000..b7c64009 --- /dev/null +++ b/versions/1.7.10/src/main/java/com/replaymod/recording/mixin/MixinS26PacketMapChunkBulk.java @@ -0,0 +1,36 @@ +package com.replaymod.recording.mixin; + +import net.minecraft.network.PacketBuffer; +import net.minecraft.network.play.server.S21PacketChunkData; +import net.minecraft.network.play.server.S26PacketMapChunkBulk; +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; + +import java.util.concurrent.Semaphore; + +@Mixin({ S21PacketChunkData.class, S26PacketMapChunkBulk.class }) +public abstract class MixinS26PacketMapChunkBulk { + + private byte[] rawData; + + @Shadow(remap = false) + private Semaphore deflateGate; + + @Inject(method = "readPacketData", at = @At("HEAD")) + private void replayModRecording_readRawPacketData(PacketBuffer data, CallbackInfo ci) { + int readerIndex = data.readerIndex(); + data.readBytes(rawData = new byte[data.readableBytes()]); + data.readerIndex(readerIndex); + } + + @Inject(method = "writePacketData", at = @At("HEAD"), cancellable = true) + private void replayModRecording_writePacketData(PacketBuffer data, CallbackInfo ci) { + if (rawData != null && deflateGate == null) { + data.writeBytes(rawData); + ci.cancel(); + } + } +} From 01d47279fdea15a706cbbd3753847026cde491bf Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 00:59:56 +0100 Subject: [PATCH 022/102] Split off 1.12.2 overwrite from MixinCamera --- .../replaymod/replay/mixin/MixinCamera.java | 41 ++++--------------- .../replaymod/replay/mixin/MixinCamera.java | 30 ++++++++++++++ 2 files changed, 37 insertions(+), 34 deletions(-) create mode 100644 versions/1.14.4/src/main/java/com/replaymod/replay/mixin/MixinCamera.java diff --git a/src/main/java/com/replaymod/replay/mixin/MixinCamera.java b/src/main/java/com/replaymod/replay/mixin/MixinCamera.java index 75c5f79c..7c1166d6 100644 --- a/src/main/java/com/replaymod/replay/mixin/MixinCamera.java +++ b/src/main/java/com/replaymod/replay/mixin/MixinCamera.java @@ -1,31 +1,20 @@ -//#if MC>=11400 package com.replaymod.replay.mixin; import com.replaymod.replay.camera.CameraEntity; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.util.math.Vector3f; import net.minecraft.entity.Entity; +import org.spongepowered.asm.mixin.Final; 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; -//#if MC>=11500 -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.client.util.math.Vector3f; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Shadow; -//#else -//$$ import com.mojang.blaze3d.platform.GlStateManager; -//$$ import net.minecraft.world.BlockView; -//#endif - -//#if MC>=11500 -@Mixin(net.minecraft.client.render.GameRenderer.class) -//#else -//$$ @Mixin(net.minecraft.client.render.Camera.class) -//#endif +@Mixin(GameRenderer.class) public class MixinCamera { - //#if MC>=11500 @Shadow @Final private MinecraftClient client; @Inject( method = "renderWorld", @@ -40,20 +29,4 @@ public class MixinCamera { matrixStack.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion(((CameraEntity) entity).roll)); } } - //#else - //$$ @Inject( - //$$ method = "update", - //$$ at = @At( - //$$ value = "INVOKE", - //$$ target = "Lcom/mojang/blaze3d/platform/GlStateManager;rotatef(FFFF)V", - //$$ ordinal = 0 - //$$ ) - //$$ ) - //$$ private void applyRoll(BlockView blockView, Entity view, boolean boolean_1, boolean boolean_2, float float_1, CallbackInfo ci) { - //$$ if (view instanceof CameraEntity) { - //$$ GlStateManager.rotatef(((CameraEntity) view).roll, 0.0F, 0.0F, 1.0F); - //$$ } - //$$ } - //#endif } -//#endif diff --git a/versions/1.14.4/src/main/java/com/replaymod/replay/mixin/MixinCamera.java b/versions/1.14.4/src/main/java/com/replaymod/replay/mixin/MixinCamera.java new file mode 100644 index 00000000..a0c0d58a --- /dev/null +++ b/versions/1.14.4/src/main/java/com/replaymod/replay/mixin/MixinCamera.java @@ -0,0 +1,30 @@ +//#if MC>=11400 +package com.replaymod.replay.mixin; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.replaymod.replay.camera.CameraEntity; +import net.minecraft.client.render.Camera; +import net.minecraft.entity.Entity; +import net.minecraft.world.BlockView; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Camera.class) +public class MixinCamera { + @Inject( + method = "update", + at = @At( + value = "INVOKE", + target = "Lcom/mojang/blaze3d/platform/GlStateManager;rotatef(FFFF)V", + ordinal = 0 + ) + ) + private void applyRoll(BlockView blockView, Entity view, boolean boolean_1, boolean boolean_2, float float_1, CallbackInfo ci) { + if (view instanceof CameraEntity) { + GlStateManager.rotatef(((CameraEntity) view).roll, 0.0F, 0.0F, 1.0F); + } + } +} +//#endif From 6fa746a2e3a68084ae3727da333fcfb4820bd8dd Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 01:01:55 +0100 Subject: [PATCH 023/102] Move MixinEntityRenderer into 1.7.10 project --- .../replay/mixin/MixinEntityRenderer.java | 29 +------------------ .../replay/mixin/MixinEntityRenderer.java | 26 +++++++++++++++++ 2 files changed, 27 insertions(+), 28 deletions(-) create mode 100644 versions/1.7.10/src/main/java/com/replaymod/replay/mixin/MixinEntityRenderer.java diff --git a/src/main/java/com/replaymod/replay/mixin/MixinEntityRenderer.java b/src/main/java/com/replaymod/replay/mixin/MixinEntityRenderer.java index fbf6d1ae..743815c4 100644 --- a/src/main/java/com/replaymod/replay/mixin/MixinEntityRenderer.java +++ b/src/main/java/com/replaymod/replay/mixin/MixinEntityRenderer.java @@ -1,28 +1 @@ -//#if MC<10800 -//$$ package com.replaymod.replay.mixin; -//$$ -//$$ import com.replaymod.replay.camera.CameraEntity; -//$$ import net.minecraft.client.Minecraft; -//$$ import net.minecraft.client.renderer.EntityRenderer; -//$$ import net.minecraft.entity.EntityLivingBase; -//$$ 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(EntityRenderer.class) -//$$ public class MixinEntityRenderer { -//$$ @Shadow private float prevCamRoll; -//$$ @Shadow private float camRoll; -//$$ @Shadow private Minecraft mc; -//$$ -//$$ @Inject(method = "orientCamera", at = @At("HEAD")) -//$$ private void applyRoll(float partialTicks, CallbackInfo ci) { -//$$ EntityLivingBase view = mc.renderViewEntity; -//$$ if (view instanceof CameraEntity) { -//$$ prevCamRoll = camRoll = ((CameraEntity) view).roll; -//$$ } -//$$ } -//$$ } -//#endif +// 1.7.10 and below diff --git a/versions/1.7.10/src/main/java/com/replaymod/replay/mixin/MixinEntityRenderer.java b/versions/1.7.10/src/main/java/com/replaymod/replay/mixin/MixinEntityRenderer.java new file mode 100644 index 00000000..40c44332 --- /dev/null +++ b/versions/1.7.10/src/main/java/com/replaymod/replay/mixin/MixinEntityRenderer.java @@ -0,0 +1,26 @@ +package com.replaymod.replay.mixin; + +import com.replaymod.replay.camera.CameraEntity; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.entity.EntityLivingBase; +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(EntityRenderer.class) +public class MixinEntityRenderer { + @Shadow private float prevCamRoll; + @Shadow private float camRoll; + @Shadow private Minecraft mc; + + @Inject(method = "orientCamera", at = @At("HEAD")) + private void applyRoll(float partialTicks, CallbackInfo ci) { + EntityLivingBase view = mc.renderViewEntity; + if (view instanceof CameraEntity) { + prevCamRoll = camRoll = ((CameraEntity) view).roll; + } + } +} From b8bcb4967fa1a4fd04a00320079d29c7cd44e8fc Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 01:05:48 +0100 Subject: [PATCH 024/102] Move MixinFMLClientHandler into 1.7.10 project --- .../replay/mixin/MixinFMLClientHandler.java | 30 +------------------ .../replay/mixin/MixinFMLClientHandler.java | 27 +++++++++++++++++ 2 files changed, 28 insertions(+), 29 deletions(-) create mode 100644 versions/1.7.10/src/main/java/com/replaymod/replay/mixin/MixinFMLClientHandler.java diff --git a/src/main/java/com/replaymod/replay/mixin/MixinFMLClientHandler.java b/src/main/java/com/replaymod/replay/mixin/MixinFMLClientHandler.java index d239e2e9..743815c4 100644 --- a/src/main/java/com/replaymod/replay/mixin/MixinFMLClientHandler.java +++ b/src/main/java/com/replaymod/replay/mixin/MixinFMLClientHandler.java @@ -1,29 +1 @@ -//#if MC<10800 -//$$ package com.replaymod.replay.mixin; -//$$ -//$$ import com.replaymod.replay.gui.screen.GuiOpeningReplay; -//$$ import cpw.mods.fml.client.FMLClientHandler; -//$$ import net.minecraft.client.Minecraft; -//$$ import net.minecraft.client.gui.GuiScreen; -//$$ import org.spongepowered.asm.mixin.Mixin; -//$$ import org.spongepowered.asm.mixin.injection.At; -//$$ import org.spongepowered.asm.mixin.injection.Inject; -//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -//$$ -//$$ @Mixin(value = FMLClientHandler.class, remap = false) -//$$ public class MixinFMLClientHandler { -//$$ // Usually this method is called async and can just block and wait for MC to tick the network manager -//$$ // Since we sometimes call it sync though, we need to take care of ticking ourselves. -//$$ @Inject(method = "waitForPlayClient", at = @At("HEAD"), remap = false) -//$$ private void tickNetworkManager(CallbackInfo ci) { -//$$ Minecraft mc = Minecraft.getMinecraft(); -//$$ if (!mc.isCallingFromMinecraftThread()) { -//$$ return; -//$$ } -//$$ GuiScreen gui = mc.currentScreen; -//$$ if (gui instanceof GuiOpeningReplay) { -//$$ gui.handleInput(); -//$$ } -//$$ } -//$$ } -//#endif +// 1.7.10 and below diff --git a/versions/1.7.10/src/main/java/com/replaymod/replay/mixin/MixinFMLClientHandler.java b/versions/1.7.10/src/main/java/com/replaymod/replay/mixin/MixinFMLClientHandler.java new file mode 100644 index 00000000..b5e45632 --- /dev/null +++ b/versions/1.7.10/src/main/java/com/replaymod/replay/mixin/MixinFMLClientHandler.java @@ -0,0 +1,27 @@ +package com.replaymod.replay.mixin; + +import com.replaymod.replay.gui.screen.GuiOpeningReplay; +import cpw.mods.fml.client.FMLClientHandler; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value = FMLClientHandler.class, remap = false) +public class MixinFMLClientHandler { + // Usually this method is called async and can just block and wait for MC to tick the network manager + // Since we sometimes call it sync though, we need to take care of ticking ourselves. + @Inject(method = "waitForPlayClient", at = @At("HEAD"), remap = false) + private void tickNetworkManager(CallbackInfo ci) { + Minecraft mc = Minecraft.getMinecraft(); + if (!mc.isCallingFromMinecraftThread()) { + return; + } + GuiScreen gui = mc.currentScreen; + if (gui instanceof GuiOpeningReplay) { + gui.handleInput(); + } + } +} From 470669b1f74f13b2c511794e5176eb891827840a Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 01:21:44 +0100 Subject: [PATCH 025/102] Move MixinRenderManager into 1.12.2 project --- .../replay/mixin/MixinRenderManager.java | 30 +------------------ .../replay/mixin/MixinRenderManager.java | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 29 deletions(-) create mode 100644 versions/1.12.2/src/main/java/com/replaymod/replay/mixin/MixinRenderManager.java diff --git a/src/main/java/com/replaymod/replay/mixin/MixinRenderManager.java b/src/main/java/com/replaymod/replay/mixin/MixinRenderManager.java index 5050349c..2350c64e 100644 --- a/src/main/java/com/replaymod/replay/mixin/MixinRenderManager.java +++ b/src/main/java/com/replaymod/replay/mixin/MixinRenderManager.java @@ -1,30 +1,2 @@ // Appears to no longer be needed in 1.14+ (maybe not even 1.13?) -//#if MC>=10800 && MC<11400 -//$$ package com.replaymod.replay.mixin; -//$$ -//$$ import net.minecraft.client.settings.GameSettings; -//$$ import net.minecraft.client.gui.FontRenderer; -//$$ import net.minecraft.client.renderer.entity.RenderManager; -//$$ import net.minecraft.entity.Entity; -//$$ import net.minecraft.entity.passive.EntityAnimal; -//$$ 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.Inject; -//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -//$$ -//$$ @Mixin(RenderManager.class) -//$$ public class MixinRenderManager { -//$$ @Shadow -//$$ private float playerViewY; -//$$ -//$$ @Inject(method = "cacheActiveRenderInfo", at = @At("RETURN")) -//$$ public void fixHeadRotationForAnimals(World world, FontRenderer font, Entity view, Entity target, GameSettings settings, float partialRenderTick, CallbackInfo ci) { -//$$ if (view instanceof EntityAnimal && !((EntityAnimal) view).isPlayerSleeping()) { -//$$ EntityAnimal e = (EntityAnimal) view; -//$$ this.playerViewY = e.prevRotationYawHead + (e.rotationYawHead - e.prevRotationYawHead) * partialRenderTick; -//$$ } -//$$ } -//$$ } -//#endif +// 1.8 - 1.12.2 diff --git a/versions/1.12.2/src/main/java/com/replaymod/replay/mixin/MixinRenderManager.java b/versions/1.12.2/src/main/java/com/replaymod/replay/mixin/MixinRenderManager.java new file mode 100644 index 00000000..38080714 --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/replay/mixin/MixinRenderManager.java @@ -0,0 +1,30 @@ +// Appears to no longer be needed in 1.14+ (maybe not even 1.13?) +//#if MC>=10800 +package com.replaymod.replay.mixin; + +import net.minecraft.client.settings.GameSettings; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.entity.Entity; +import net.minecraft.entity.passive.EntityAnimal; +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.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(RenderManager.class) +public class MixinRenderManager { + @Shadow + public float playerViewY; + + @Inject(method = "cacheActiveRenderInfo", at = @At("RETURN")) + public void fixHeadRotationForAnimals(World world, FontRenderer font, Entity view, Entity target, GameSettings settings, float partialRenderTick, CallbackInfo ci) { + if (view instanceof EntityAnimal && !((EntityAnimal) view).isPlayerSleeping()) { + EntityAnimal e = (EntityAnimal) view; + this.playerViewY = e.prevRotationYawHead + (e.rotationYawHead - e.prevRotationYawHead) * partialRenderTick; + } + } +} +//#endif From 026bc1fdcbe403971f46f8ee3991a5c94dc9d7ea Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 01:23:44 +0100 Subject: [PATCH 026/102] Move MixinWorldClient into 1.12.2 project --- .../replay/mixin/MixinWorldClient.java | 26 +--------------- .../replay/mixin/MixinWorldClient.java | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+), 25 deletions(-) create mode 100644 versions/1.12.2/src/main/java/com/replaymod/replay/mixin/MixinWorldClient.java diff --git a/src/main/java/com/replaymod/replay/mixin/MixinWorldClient.java b/src/main/java/com/replaymod/replay/mixin/MixinWorldClient.java index 64e6e252..c5d79e4d 100644 --- a/src/main/java/com/replaymod/replay/mixin/MixinWorldClient.java +++ b/src/main/java/com/replaymod/replay/mixin/MixinWorldClient.java @@ -1,34 +1,10 @@ package com.replaymod.replay.mixin; import net.minecraft.client.world.ClientWorld; -import net.minecraft.entity.Entity; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(ClientWorld.class) public abstract class MixinWorldClient { - // Looks like this has finally been fixed in 1.14 (or been moved somewhere else entirely, guess we'll find out) - //#if MC<11400 - //$$ /** - //$$ * Fixes a bug in vanilla Minecraft that leaves entities remaining in the entityList even after respawn. - //$$ * The entityList in WorldClient is a Set that assumes that the entity ID of its entities does not change. - //$$ * However in {@link WorldClient#addEntityToWorld(int, Entity)}, the entity passed in is first added to the - //$$ * set and subsequently its id is changed, leaving it stuck in he Set. That is the buggy method. - //$$ * This wouldn't be too much of a problem if the entity had the correct id to begin with, however the handler for - //$$ * the spawn player packet creates an EntityOtherPlayerMP which takes its id from a counter and then passes it to - //$$ * this method with the wrong id. - //$$ * This mixin fixes the id of the entity before it is added to the set instead of right after. - //$$ * The original id change right after is not changed, however it should not have any effect. - //$$ * @param entityId The id to be set for the entity - //$$ * @param entity The entity to be added - //$$ * @param ci Callback info - //$$ */ - //$$ @Inject(method = "addEntityToWorld", at=@At("HEAD")) - //$$ public void replayModReplay_fix_addEntityToWorld(int entityId, Entity entity, CallbackInfo ci) { - //$$ entity.setEntityId(entityId); - //$$ } - //#endif + // 1.12.2 and below } diff --git a/versions/1.12.2/src/main/java/com/replaymod/replay/mixin/MixinWorldClient.java b/versions/1.12.2/src/main/java/com/replaymod/replay/mixin/MixinWorldClient.java new file mode 100644 index 00000000..643ac038 --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/replay/mixin/MixinWorldClient.java @@ -0,0 +1,31 @@ +package com.replaymod.replay.mixin; + +import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +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 { + + /** + * Fixes a bug in vanilla Minecraft that leaves entities remaining in the entityList even after respawn. + * The entityList in WorldClient is a Set that assumes that the entity ID of its entities does not change. + * However in {@link WorldClient#addEntityToWorld(int, Entity)}, the entity passed in is first added to the + * set and subsequently its id is changed, leaving it stuck in he Set. That is the buggy method. + * This wouldn't be too much of a problem if the entity had the correct id to begin with, however the handler for + * the spawn player packet creates an EntityOtherPlayerMP which takes its id from a counter and then passes it to + * this method with the wrong id. + * This mixin fixes the id of the entity before it is added to the set instead of right after. + * The original id change right after is not changed, however it should not have any effect. + * @param entityId The id to be set for the entity + * @param entity The entity to be added + * @param ci Callback info + */ + @Inject(method = "addEntityToWorld", at=@At("HEAD")) + public void replayModReplay_fix_addEntityToWorld(int entityId, Entity entity, CallbackInfo ci) { + entity.setEntityId(entityId); + } +} From 87b55e187c50a755dbf64bdbe66c676901e8182d Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 01:32:29 +0100 Subject: [PATCH 027/102] Replace a few //#if statements with mapping file entries --- .../java/com/replaymod/render/RenderSettings.java | 11 +---------- .../replaymod/replay/mixin/MixinParticleManager.java | 11 ++--------- versions/1.14.4-forge/mapping.txt | 2 ++ versions/1.8/mapping.txt | 1 + 4 files changed, 6 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/replaymod/render/RenderSettings.java b/src/main/java/com/replaymod/render/RenderSettings.java index 511ef027..4117389d 100644 --- a/src/main/java/com/replaymod/render/RenderSettings.java +++ b/src/main/java/com/replaymod/render/RenderSettings.java @@ -5,6 +5,7 @@ import com.replaymod.core.versions.MCVer; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableColor; import net.minecraft.client.resource.language.I18n; import net.minecraft.util.Util; +import org.apache.maven.artifact.versioning.ComparableVersion; import java.io.File; import java.io.IOException; @@ -19,16 +20,6 @@ import java.util.Optional; import static com.replaymod.render.ReplayModRender.LOGGER; -//#if MC>=11400 -import org.apache.maven.artifact.versioning.ComparableVersion; -//#else -//#if MC>=10800 -//$$ import net.minecraftforge.fml.common.versioning.ComparableVersion; -//#else -//$$ import cpw.mods.fml.common.versioning.ComparableVersion; -//#endif -//#endif - public class RenderSettings { public enum RenderMethod { DEFAULT, STEREOSCOPIC, CUBIC, EQUIRECTANGULAR, ODS, BLEND; diff --git a/src/main/java/com/replaymod/replay/mixin/MixinParticleManager.java b/src/main/java/com/replaymod/replay/mixin/MixinParticleManager.java index 4ce7a6e5..6e9b8649 100644 --- a/src/main/java/com/replaymod/replay/mixin/MixinParticleManager.java +++ b/src/main/java/com/replaymod/replay/mixin/MixinParticleManager.java @@ -3,6 +3,7 @@ package com.replaymod.replay.mixin; //#if MC>=10904 import net.minecraft.client.particle.Particle; import net.minecraft.client.particle.ParticleManager; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -19,12 +20,8 @@ import java.util.Queue; @Mixin(ParticleManager.class) public abstract class MixinParticleManager { - @Shadow - //#if MC>=11400 + @Final @Shadow private Queue newParticles; - //#else - //$$ private Queue queueEntityFX; - //#endif /** * This method additionally clears the queue of particles to be added when the world is changed. @@ -42,11 +39,7 @@ public abstract class MixinParticleManager { //$$ World world, //#endif CallbackInfo ci) { - //#if MC>=11400 this.newParticles.clear(); - //#else - //$$ this.queueEntityFX.clear(); - //#endif } } //#endif diff --git a/versions/1.14.4-forge/mapping.txt b/versions/1.14.4-forge/mapping.txt index 029bf807..09a126b7 100644 --- a/versions/1.14.4-forge/mapping.txt +++ b/versions/1.14.4-forge/mapping.txt @@ -12,6 +12,8 @@ net.minecraft.crash.ReportedException net.minecraft.util.ReportedException net.minecraftforge.eventbus.api.IEventBus net.minecraftforge.fml.common.eventhandler.EventBus net.minecraft.network.play.server.SPacketEntity.Move net.minecraft.network.play.server.SPacketEntity.S17PacketEntityLookMove net.minecraftforge.fml.network.NetworkRegistry net.minecraftforge.fml.common.network.NetworkRegistry +net.minecraft.client.particle.ParticleManager queue queueEntityFX +org.apache.maven.artifact.versioning.ComparableVersion net.minecraftforge.fml.common.versioning.ComparableVersion net.minecraft.resources.FolderPack getInputStream() getInputStreamByName() net.minecraft.client.gui.GuiYesNoCallback confirmResult() confirmClicked() diff --git a/versions/1.8/mapping.txt b/versions/1.8/mapping.txt index 3712d8e0..c5cece6f 100644 --- a/versions/1.8/mapping.txt +++ b/versions/1.8/mapping.txt @@ -31,6 +31,7 @@ net.minecraftforge.fml.common.network.handshake.FMLHandshakeMessage.RegistryData net.minecraftforge.fml.common.network.internal.FMLProxyPacket cpw.mods.fml.common.network.internal.FMLProxyPacket net.minecraftforge.fml.common.network.NetworkRegistry cpw.mods.fml.common.network.NetworkRegistry net.minecraftforge.fml.common.gameevent.InputEvent cpw.mods.fml.common.gameevent.InputEvent +net.minecraftforge.fml.common.versioning.ComparableVersion cpw.mods.fml.common.versioning.ComparableVersion net.minecraft.client.renderer.tileentity.TileEntityEndPortalRenderer net.minecraft.client.renderer.tileentity.RenderEndPortal net.minecraft.network.play.server.S3FPacketCustomPayload getChannelName() func_149169_c() net.minecraft.network.play.server.S01PacketJoinGame getEntityId() func_149197_c() From 74580e6649a82e3be123f3dfcea5682e99a0107e Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 11:27:36 +0100 Subject: [PATCH 028/102] Remove redundant preprocessor statements --- .../hooks/ChunkLoadingRenderGlobal.java | 20 +------------------ .../render/mixin/Mixin_ForceChunkLoading.java | 11 +--------- 2 files changed, 2 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java b/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java index f15097cf..f43a0c9c 100644 --- a/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java +++ b/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java @@ -27,11 +27,7 @@ import java.util.concurrent.PriorityBlockingQueue; public class ChunkLoadingRenderGlobal { - //#if MC>=11400 private final WorldRenderer hooked; - //#else - //$$ private final RenderGlobal hooked; - //#endif //#if MC>=11500 //#else @@ -45,13 +41,7 @@ public class ChunkLoadingRenderGlobal { //$$ private int frame; //#endif - public ChunkLoadingRenderGlobal( - //#if MC>=11400 - WorldRenderer renderGlobal - //#else - //$$ RenderGlobal renderGlobal - //#endif - ) { + public ChunkLoadingRenderGlobal(WorldRenderer renderGlobal) { this.hooked = renderGlobal; //#if MC>=11500 @@ -64,11 +54,7 @@ public class ChunkLoadingRenderGlobal { private void install() { try { - //#if MC>=11400 Field hookField = WorldRenderer.class.getField("replayModRender_hook"); - //#else - //$$ Field hookField = RenderGlobal.class.getField("replayModRender_hook"); - //#endif hookField.set(hooked, this); } catch (NoSuchFieldException | IllegalAccessException e) { throw new Error(e); @@ -168,11 +154,7 @@ public class ChunkLoadingRenderGlobal { //#endif try { - //#if MC>=11400 Field hookField = WorldRenderer.class.getField("replayModRender_hook"); - //#else - //$$ Field hookField = RenderGlobal.class.getField("replayModRender_hook"); - //#endif hookField.set(hooked, null); } catch (NoSuchFieldException | IllegalAccessException e) { throw new Error(e); diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java b/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java index f7b8b80b..23f98910 100644 --- a/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java +++ b/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java @@ -5,6 +5,7 @@ import com.replaymod.compat.shaders.ShaderReflection; import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; import net.minecraft.client.render.Camera; import net.minecraft.client.render.Frustum; +import net.minecraft.client.render.WorldRenderer; import net.minecraft.client.render.chunk.ChunkBuilder; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -23,23 +24,13 @@ import java.util.Set; //$$ import net.minecraft.client.render.Camera; //#endif -//#if MC>=11400 -import net.minecraft.client.render.WorldRenderer; -//#else -//$$ import net.minecraft.client.renderer.RenderGlobal; -//#endif - //#if MC<10904 //$$ import net.minecraft.client.renderer.chunk.RenderChunk; //$$ import net.minecraft.util.BlockPos; //$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; //#endif -//#if MC>=11400 @Mixin(WorldRenderer.class) -//#else -//$$ @Mixin(RenderGlobal.class) -//#endif public abstract class Mixin_ForceChunkLoading { public ChunkLoadingRenderGlobal replayModRender_hook; From 4b4d18026b1c57ed9fe89af0ad1e04badf499b18 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 11:31:27 +0100 Subject: [PATCH 029/102] Move GLStateTracker into 1.7.10 project --- .../render/hooks/GLStateTracker.java | 47 +------------------ .../render/hooks/GLStateTracker.java | 44 +++++++++++++++++ 2 files changed, 45 insertions(+), 46 deletions(-) create mode 100644 versions/1.7.10/src/main/java/com/replaymod/render/hooks/GLStateTracker.java diff --git a/src/main/java/com/replaymod/render/hooks/GLStateTracker.java b/src/main/java/com/replaymod/render/hooks/GLStateTracker.java index bf6b3c9e..743815c4 100644 --- a/src/main/java/com/replaymod/render/hooks/GLStateTracker.java +++ b/src/main/java/com/replaymod/render/hooks/GLStateTracker.java @@ -1,46 +1 @@ -//#if MC<=10710 -//$$ package com.replaymod.render.hooks; -//$$ -//$$ import org.lwjgl.opengl.GL11; -//$$ import org.lwjgl.opengl.GL13; -//$$ -//$$ /** -//$$ * Tracks OpenGL state for use in the ODS shader. -//$$ * All methods should be called from the GL mixins only. -//$$ */ -//$$ public class GLStateTracker { -//$$ private static ThreadLocal stateTracker = ThreadLocal.withInitial(GLStateTracker::new); -//$$ public static GLStateTracker getInstance() { -//$$ return stateTracker.get(); -//$$ } -//$$ -//$$ public int activeTexture; -//$$ -//$$ public void updateActiveTexture(int magic) { -//$$ this.activeTexture = magic - GL13.GL_TEXTURE0; -//$$ } -//$$ -//$$ public void updateEnabledState(int magic, boolean enabled) { -//$$ switch (magic) { -//$$ case GL11.GL_FOG: FogStateCallback.EVENT.invoker().fogStateChanged(enabled); break; -//$$ case GL11.GL_TEXTURE_2D: Texture2DStateCallback.EVENT.invoker().texture2DStateChanged(activeTexture, enabled); break; -//$$ } -//$$ } -//$$ -//$$ // Called via ASM (see GLStateTrackerTransformer) -//$$ @Deprecated -//$$ @SuppressWarnings("unused") -//$$ public static void hook_glEnable(int magic) { -//$$ GL11.glEnable(magic); -//$$ getInstance().updateEnabledState(magic, true); -//$$ } -//$$ -//$$ // Called via ASM (see GLStateTrackerTransformer) -//$$ @Deprecated -//$$ @SuppressWarnings("unused") -//$$ public static void hook_glDisable(int magic) { -//$$ GL11.glDisable(magic); -//$$ getInstance().updateEnabledState(magic, false); -//$$ } -//$$ } -//#endif +// 1.7.10 and below diff --git a/versions/1.7.10/src/main/java/com/replaymod/render/hooks/GLStateTracker.java b/versions/1.7.10/src/main/java/com/replaymod/render/hooks/GLStateTracker.java new file mode 100644 index 00000000..54c06ce4 --- /dev/null +++ b/versions/1.7.10/src/main/java/com/replaymod/render/hooks/GLStateTracker.java @@ -0,0 +1,44 @@ +package com.replaymod.render.hooks; + +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; + +/** + * Tracks OpenGL state for use in the ODS shader. + * All methods should be called from the GL mixins only. + */ +public class GLStateTracker { + private static ThreadLocal stateTracker = ThreadLocal.withInitial(GLStateTracker::new); + public static GLStateTracker getInstance() { + return stateTracker.get(); + } + + public int activeTexture; + + public void updateActiveTexture(int magic) { + this.activeTexture = magic - GL13.GL_TEXTURE0; + } + + public void updateEnabledState(int magic, boolean enabled) { + switch (magic) { + case GL11.GL_FOG: FogStateCallback.EVENT.invoker().fogStateChanged(enabled); break; + case GL11.GL_TEXTURE_2D: Texture2DStateCallback.EVENT.invoker().texture2DStateChanged(activeTexture, enabled); break; + } + } + + // Called via ASM (see GLStateTrackerTransformer) + @Deprecated + @SuppressWarnings("unused") + public static void hook_glEnable(int magic) { + GL11.glEnable(magic); + getInstance().updateEnabledState(magic, true); + } + + // Called via ASM (see GLStateTrackerTransformer) + @Deprecated + @SuppressWarnings("unused") + public static void hook_glDisable(int magic) { + GL11.glDisable(magic); + getInstance().updateEnabledState(magic, false); + } +} From 90bbc6844399eb2045b7943407437331a951a9b9 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 11:45:08 +0100 Subject: [PATCH 030/102] Replace reflection in ChunkLoadingRenderGlobal with mixin --- .../hooks/ChunkLoadingRenderGlobal.java | 21 ++----------------- .../render/hooks/IForceChunkLoading.java | 13 ++++++++++++ .../render/mixin/Mixin_ForceChunkLoading.java | 10 +++++++-- 3 files changed, 23 insertions(+), 21 deletions(-) create mode 100644 src/main/java/com/replaymod/render/hooks/IForceChunkLoading.java diff --git a/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java b/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java index f43a0c9c..2fa09213 100644 --- a/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java +++ b/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java @@ -3,8 +3,6 @@ package com.replaymod.render.hooks; import net.minecraft.client.render.WorldRenderer; -import java.lang.reflect.Field; - //#if MC>=11500 //#else //$$ import com.replaymod.render.mixin.ChunkRenderDispatcherAccessor; @@ -45,20 +43,10 @@ public class ChunkLoadingRenderGlobal { this.hooked = renderGlobal; //#if MC>=11500 - install(); //#else //$$ setup(((WorldRendererAccessor) renderGlobal).getRenderDispatcher()); - //$$ install(); //#endif - } - - private void install() { - try { - Field hookField = WorldRenderer.class.getField("replayModRender_hook"); - hookField.set(hooked, this); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new Error(e); - } + IForceChunkLoading.from(renderGlobal).replayModRender_setHook(this); } //#if MC>=11500 @@ -153,12 +141,7 @@ public class ChunkLoadingRenderGlobal { //$$ workerJailingQueue.freeAll(); //#endif - try { - Field hookField = WorldRenderer.class.getField("replayModRender_hook"); - hookField.set(hooked, null); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new Error(e); - } + IForceChunkLoading.from(hooked).replayModRender_setHook(null); } //#if MC>=11500 diff --git a/src/main/java/com/replaymod/render/hooks/IForceChunkLoading.java b/src/main/java/com/replaymod/render/hooks/IForceChunkLoading.java new file mode 100644 index 00000000..57b8c943 --- /dev/null +++ b/src/main/java/com/replaymod/render/hooks/IForceChunkLoading.java @@ -0,0 +1,13 @@ +//#if MC>=10800 +package com.replaymod.render.hooks; + +import net.minecraft.client.render.WorldRenderer; + +public interface IForceChunkLoading { + void replayModRender_setHook(ChunkLoadingRenderGlobal hook); + + static IForceChunkLoading from(WorldRenderer worldRenderer) { + return (IForceChunkLoading) worldRenderer; + } +} +//#endif diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java b/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java index 23f98910..8e6741a6 100644 --- a/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java +++ b/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java @@ -3,6 +3,7 @@ package com.replaymod.render.mixin; //#if MC>=10800 import com.replaymod.compat.shaders.ShaderReflection; import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; +import com.replaymod.render.hooks.IForceChunkLoading; import net.minecraft.client.render.Camera; import net.minecraft.client.render.Frustum; import net.minecraft.client.render.WorldRenderer; @@ -31,8 +32,13 @@ import java.util.Set; //#endif @Mixin(WorldRenderer.class) -public abstract class Mixin_ForceChunkLoading { - public ChunkLoadingRenderGlobal replayModRender_hook; +public abstract class Mixin_ForceChunkLoading implements IForceChunkLoading { + private ChunkLoadingRenderGlobal replayModRender_hook; + + @Override + public void replayModRender_setHook(ChunkLoadingRenderGlobal hook) { + this.replayModRender_hook = hook; + } //#if MC>=11500 @Shadow private Set chunksToRebuild; From f19ee8ba63451bdc6a5084fc995693ecada432f9 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 11:53:18 +0100 Subject: [PATCH 031/102] Split off 1.14.4 overwrite from Mixin_ForceChunkLoading --- .../render/mixin/Mixin_ForceChunkLoading.java | 123 ---------------- .../render/mixin/Mixin_ForceChunkLoading.java | 131 ++++++++++++++++++ 2 files changed, 131 insertions(+), 123 deletions(-) create mode 100644 versions/1.14.4/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java b/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java index 8e6741a6..eb322b1c 100644 --- a/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java +++ b/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java @@ -1,6 +1,5 @@ package com.replaymod.render.mixin; -//#if MC>=10800 import com.replaymod.compat.shaders.ShaderReflection; import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; import com.replaymod.render.hooks.IForceChunkLoading; @@ -14,22 +13,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -//#if MC>=11500 import java.util.Set; -//#else -//$$ import net.minecraft.client.render.VisibleRegion; -//$$ import net.minecraft.entity.Entity; -//#endif - -//#if MC>=11400 && MC<11500 -//$$ import net.minecraft.client.render.Camera; -//#endif - -//#if MC<10904 -//$$ import net.minecraft.client.renderer.chunk.RenderChunk; -//$$ import net.minecraft.util.BlockPos; -//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -//#endif @Mixin(WorldRenderer.class) public abstract class Mixin_ForceChunkLoading implements IForceChunkLoading { @@ -40,15 +24,12 @@ public abstract class Mixin_ForceChunkLoading implements IForceChunkLoading { this.replayModRender_hook = hook; } - //#if MC>=11500 @Shadow private Set chunksToRebuild; @Shadow private ChunkBuilder chunkBuilder; @Shadow private boolean needsTerrainUpdate; - @Shadow public abstract void scheduleTerrainUpdate(); - @Shadow protected abstract void setupTerrain(Camera camera_1, Frustum frustum_1, boolean boolean_1, int int_1, boolean boolean_2); @Shadow private int frame; @@ -93,108 +74,4 @@ public abstract class Mixin_ForceChunkLoading implements IForceChunkLoading { passThrough = false; } } - //#else - //$$ private boolean replayModRender_passThroughSetupTerrain; - //$$ - //$$ @Shadow - //$$ public boolean needsTerrainUpdate; - //$$ - //$$ @Shadow - //$$ public ChunkBuilder chunkBuilder; - //$$ - //$$ @Shadow - //$$ public abstract void setUpTerrain( - //#if MC>=11400 - //$$ Camera viewEntity, - //#else - //$$ Entity viewEntity, - //#if MC>=11400 - //$$ float partialTicks, - //#else - //$$ double partialTicks, - //#endif - //#endif - //$$ VisibleRegion camera, - //$$ int frameCount, - //$$ boolean playerSpectator - //$$ ); - //$$ - //$$ @Inject(method = "setUpTerrain", at = @At("HEAD"), cancellable = true) - //$$ private void replayModRender_setupTerrain( - //#if MC>=11400 - //$$ Camera viewEntity, - //#else - //$$ Entity viewEntity, - //#if MC>=11400 - //$$ float partialTicks, - //#else - //$$ double partialTicks, - //#endif - //#endif - //$$ VisibleRegion camera, - //$$ int frameCount, - //$$ boolean playerSpectator, - //$$ CallbackInfo ci - //$$ ) throws IllegalAccessException { - //$$ if (ShaderReflection.shaders_isShadowPass != null && (boolean) ShaderReflection.shaders_isShadowPass.get(null)) { - //$$ return; - //$$ } - //$$ if (replayModRender_hook != null && !replayModRender_passThroughSetupTerrain) { - //$$ replayModRender_passThroughSetupTerrain = true; - //$$ - //$$ do { - //$$ setUpTerrain( - //$$ viewEntity, - //#if MC<11400 - //$$ partialTicks, - //#endif - //$$ camera, - //$$ replayModRender_hook.nextFrameId(), - //$$ playerSpectator - //$$ ); - //$$ replayModRender_hook.updateChunks(); - //$$ } while (this.needsTerrainUpdate); - //$$ - //$$ this.needsTerrainUpdate = true; - //$$ - //$$ replayModRender_passThroughSetupTerrain = false; - //$$ ci.cancel(); - //$$ } - //$$ } - //$$ - //#if MC<10904 - //$$ @Inject(method = "isPositionInRenderChunk", at = @At("HEAD"), cancellable = true) - //$$ public void replayModRender_isPositionInRenderChunk(BlockPos pos, RenderChunk chunk, CallbackInfoReturnable ci) { - //$$ if (replayModRender_hook != null) { - //$$ ci.setReturnValue(true); - //$$ } - //$$ } - //#endif - //$$ - //$$ @Inject(method = "updateChunks", at = @At("HEAD"), cancellable = true) - //$$ public void replayModRender_updateChunks(long finishTimeNano, CallbackInfo ci) { - //$$ if (replayModRender_hook != null) { - //$$ replayModRender_hook.updateChunks(); - //$$ ci.cancel(); - //$$ } - //$$ } - //$$ - //$$ // Prior to 1.9.4, MC always uses the same ChunkRenderDispatcher instance - //#if MC>=10904 - //$$ @Inject(method = "setWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/chunk/ChunkBuilder;stop()V")) - //$$ private void stopWorkerThreadsAndChunkLoadingRenderGlobal(CallbackInfo ci) { - //$$ if (replayModRender_hook != null) { - //$$ replayModRender_hook.updateRenderDispatcher(null); - //$$ } - //$$ } - //#endif - //$$ - //$$ @Inject(method = "reload", at = @At(value = "RETURN")) - //$$ private void setupChunkLoadingRenderGlobal(CallbackInfo ci) { - //$$ if (replayModRender_hook != null) { - //$$ replayModRender_hook.updateRenderDispatcher(this.chunkBuilder); - //$$ } - //$$ } - //#endif } -//#endif diff --git a/versions/1.14.4/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java b/versions/1.14.4/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java new file mode 100644 index 00000000..593c61ad --- /dev/null +++ b/versions/1.14.4/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java @@ -0,0 +1,131 @@ +package com.replaymod.render.mixin; + +//#if MC>=10800 +import com.replaymod.compat.shaders.ShaderReflection; +import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; +import com.replaymod.render.hooks.IForceChunkLoading; +import net.minecraft.client.render.VisibleRegion; +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.client.render.chunk.ChunkBuilder; +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; + +//#if MC>=11400 +import net.minecraft.client.render.Camera; +//#else +//$$ import net.minecraft.entity.Entity; +//#endif + +//#if MC<10904 +//$$ import net.minecraft.client.renderer.chunk.RenderChunk; +//$$ import net.minecraft.util.BlockPos; +//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +//#endif + +@Mixin(WorldRenderer.class) +public abstract class Mixin_ForceChunkLoading implements IForceChunkLoading { + private ChunkLoadingRenderGlobal replayModRender_hook; + + @Override + public void replayModRender_setHook(ChunkLoadingRenderGlobal hook) { + this.replayModRender_hook = hook; + } + + private boolean replayModRender_passThroughSetupTerrain; + + @Shadow + private boolean needsTerrainUpdate; + + @Shadow + private ChunkBuilder chunkBuilder; + + @Shadow + public abstract void setUpTerrain( + //#if MC>=11400 + Camera viewEntity, + //#else + //$$ Entity viewEntity, + //$$ double partialTicks, + //#endif + VisibleRegion camera, + int frameCount, + boolean playerSpectator + ); + + @Inject(method = "setUpTerrain", at = @At("HEAD"), cancellable = true) + private void replayModRender_setupTerrain( + //#if MC>=11400 + Camera viewEntity, + //#else + //$$ Entity viewEntity, + //$$ double partialTicks, + //#endif + VisibleRegion camera, + int frameCount, + boolean playerSpectator, + CallbackInfo ci + ) throws IllegalAccessException { + if (ShaderReflection.shaders_isShadowPass != null && (boolean) ShaderReflection.shaders_isShadowPass.get(null)) { + return; + } + if (replayModRender_hook != null && !replayModRender_passThroughSetupTerrain) { + replayModRender_passThroughSetupTerrain = true; + + do { + setUpTerrain( + viewEntity, + //#if MC<11400 + //$$ partialTicks, + //#endif + camera, + replayModRender_hook.nextFrameId(), + playerSpectator + ); + replayModRender_hook.updateChunks(); + } while (this.needsTerrainUpdate); + + this.needsTerrainUpdate = true; + + replayModRender_passThroughSetupTerrain = false; + ci.cancel(); + } + } + + //#if MC<10904 + //$$ @Inject(method = "isPositionInRenderChunk", at = @At("HEAD"), cancellable = true) + //$$ public void replayModRender_isPositionInRenderChunk(BlockPos pos, RenderChunk chunk, CallbackInfoReturnable ci) { + //$$ if (replayModRender_hook != null) { + //$$ ci.setReturnValue(true); + //$$ } + //$$ } + //#endif + + @Inject(method = "updateChunks", at = @At("HEAD"), cancellable = true) + public void replayModRender_updateChunks(long finishTimeNano, CallbackInfo ci) { + if (replayModRender_hook != null) { + replayModRender_hook.updateChunks(); + ci.cancel(); + } + } + + // Prior to 1.9.4, MC always uses the same ChunkRenderDispatcher instance + //#if MC>=10904 + @Inject(method = "setWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/chunk/ChunkBuilder;stop()V")) + private void stopWorkerThreadsAndChunkLoadingRenderGlobal(CallbackInfo ci) { + if (replayModRender_hook != null) { + replayModRender_hook.updateRenderDispatcher(null); + } + } + //#endif + + @Inject(method = "reload", at = @At(value = "RETURN")) + private void setupChunkLoadingRenderGlobal(CallbackInfo ci) { + if (replayModRender_hook != null) { + replayModRender_hook.updateRenderDispatcher(this.chunkBuilder); + } + } +} +//#endif From c729654f04f16628cbdca1478a597040c638f628 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 11:57:05 +0100 Subject: [PATCH 032/102] Split off 1.14.4 overwrite from ChunkLoadingRenderGlobal --- .../hooks/ChunkLoadingRenderGlobal.java | 131 ----------------- .../hooks/ChunkLoadingRenderGlobal.java | 133 ++++++++++++++++++ 2 files changed, 133 insertions(+), 131 deletions(-) create mode 100644 versions/1.14.4/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java diff --git a/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java b/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java index 2fa09213..147a0a20 100644 --- a/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java +++ b/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java @@ -1,153 +1,22 @@ -//#if MC>=10800 package com.replaymod.render.hooks; import net.minecraft.client.render.WorldRenderer; -//#if MC>=11500 -//#else -//$$ import com.replaymod.render.mixin.ChunkRenderDispatcherAccessor; -//$$ import com.replaymod.render.mixin.WorldRendererAccessor; -//$$ import com.replaymod.render.utils.JailingQueue; -//$$ import net.minecraft.client.render.chunk.BlockBufferBuilderStorage; -//$$ import net.minecraft.client.render.chunk.ChunkBuilder; -//$$ import net.minecraft.client.render.chunk.ChunkRenderTask; -//$$ import net.minecraft.client.render.chunk.ChunkRenderWorker; -//$$ import net.minecraft.client.render.chunk.ChunkRenderer; -//$$ import java.util.Iterator; -//$$ import static com.replaymod.core.versions.MCVer.*; -//#endif - -//#if MC>=10904 -import java.util.concurrent.PriorityBlockingQueue; -//#else -//$$ import java.util.concurrent.BlockingQueue; -//#endif - public class ChunkLoadingRenderGlobal { private final WorldRenderer hooked; - //#if MC>=11500 - //#else - //$$ private ChunkBuilder renderDispatcher; - //#if MC>=11400 - //$$ private JailingQueue workerJailingQueue; - //#else - //$$ private JailingQueue workerJailingQueue; - //#endif - //$$ private ChunkRenderWorkerAccessor renderWorker; - //$$ private int frame; - //#endif - public ChunkLoadingRenderGlobal(WorldRenderer renderGlobal) { this.hooked = renderGlobal; - //#if MC>=11500 - //#else - //$$ setup(((WorldRendererAccessor) renderGlobal).getRenderDispatcher()); - //#endif IForceChunkLoading.from(renderGlobal).replayModRender_setHook(this); } - //#if MC>=11500 - //#else - //$$ public void updateRenderDispatcher(ChunkBuilder renderDispatcher) { - //$$ if (this.renderDispatcher != null) { - //$$ workerJailingQueue.freeAll(); - //$$ this.renderDispatcher = null; - //$$ } - //$$ if (renderDispatcher != null) { - //$$ setup(renderDispatcher); - //$$ } - //$$ } - //$$ - //$$ private void setup(ChunkBuilder renderDispatcher) { - //$$ this.renderDispatcher = renderDispatcher; - //$$ this.renderWorker = (ChunkRenderWorkerAccessor) new ChunkRenderWorker(renderDispatcher, new BlockBufferBuilderStorage()); - //$$ ChunkRenderDispatcherAccessor renderDispatcherAcc = (ChunkRenderDispatcherAccessor) renderDispatcher; - //$$ - //$$ int workerThreads = renderDispatcherAcc.getListThreadedWorkers().size(); - //#if MC>=10904 - //$$ PriorityBlockingQueue queueChunkUpdates = renderDispatcherAcc.getQueueChunkUpdates(); - //#else - //$$ BlockingQueue queueChunkUpdates = renderDispatcherAcc.getQueueChunkUpdates(); - //#endif - //$$ workerJailingQueue = new JailingQueue<>(queueChunkUpdates); - //$$ renderDispatcherAcc.setQueueChunkUpdates(workerJailingQueue); - //#if MC>=10904 - //$$ ChunkRenderTask element = new ChunkRenderTask( - //$$ null, - //$$ null, - //$$ 0 - //#if MC>=11400 - //$$ , null - //#endif - //$$ ); - //#else - //$$ ChunkCompileTaskGenerator element = new ChunkCompileTaskGenerator(null, null); - //#endif - //$$ element.cancel(); - //$$ for (int i = 0; i < workerThreads; i++) { - //$$ queueChunkUpdates.add(element); - //$$ } - //$$ - //$$ // Temporary workaround for dead lock, will be replaced by a new (ShaderMod compatible) mechanism later - //$$ //noinspection StatementWithEmptyBody - //$$ while (renderDispatcher.runTasksSync(0)) {} - //$$ - //$$ workerJailingQueue.jail(workerThreads); - //$$ renderDispatcherAcc.setQueueChunkUpdates(queueChunkUpdates); - //$$ } - //$$ - //$$ public void updateChunks() { - //$$ while (renderDispatcher.runTasksSync(0)) { - //$$ ((WorldRendererAccessor) hooked).setDisplayListEntitiesDirty(true); - //$$ } - //$$ - //#if MC>=10904 - //$$ PriorityBlockingQueue queueChunkUpdates; - //#else - //$$ BlockingQueue queueChunkUpdates; - //#endif - //$$ queueChunkUpdates = ((ChunkRenderDispatcherAccessor) renderDispatcher).getQueueChunkUpdates(); - //$$ while (!queueChunkUpdates.isEmpty()) { - //$$ try { - //$$ renderWorker.doRunTask(queueChunkUpdates.poll()); - //$$ } catch (InterruptedException ignored) { } - //$$ } - //$$ - //$$ Iterator iterator = ((WorldRendererAccessor) hooked).getChunksToUpdate().iterator(); - //$$ while (iterator.hasNext()) { - //$$ ChunkRenderer renderchunk = iterator.next(); - //$$ - //$$ renderDispatcher.rebuildSync(renderchunk); - //$$ - //#if MC>=10904 - //$$ renderchunk.unscheduleRebuild(); - //#else - //$$ renderchunk.setNeedsUpdate(false); - //#endif - //$$ iterator.remove(); - //$$ } - //$$ } - //$$ - //$$ public int nextFrameId() { - //$$ return frame++; - //$$ } - //#endif - public void uninstall() { - //#if MC<11500 - //$$ workerJailingQueue.freeAll(); - //#endif - IForceChunkLoading.from(hooked).replayModRender_setHook(null); } - //#if MC>=11500 public interface IBlockOnChunkRebuilds { boolean uploadEverythingBlocking(); } - //#endif } -//#endif diff --git a/versions/1.14.4/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java b/versions/1.14.4/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java new file mode 100644 index 00000000..6b1acf48 --- /dev/null +++ b/versions/1.14.4/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java @@ -0,0 +1,133 @@ +//#if MC>=10800 +package com.replaymod.render.hooks; + +import com.replaymod.render.mixin.ChunkRenderDispatcherAccessor; +import com.replaymod.render.mixin.WorldRendererAccessor; +import com.replaymod.render.utils.JailingQueue; +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.client.render.chunk.BlockBufferBuilderStorage; +import net.minecraft.client.render.chunk.ChunkBuilder; +import net.minecraft.client.render.chunk.ChunkRenderTask; +import net.minecraft.client.render.chunk.ChunkRenderWorker; +import net.minecraft.client.render.chunk.ChunkRenderer; + +import java.util.Iterator; + +//#if MC>=10904 +import java.util.concurrent.PriorityBlockingQueue; +//#else +//$$ import java.util.concurrent.BlockingQueue; +//#endif + +import static com.replaymod.core.versions.MCVer.ChunkRenderWorkerAccessor; + +public class ChunkLoadingRenderGlobal { + + private final WorldRenderer hooked; + + private ChunkBuilder renderDispatcher; + //#if MC>=11400 + private JailingQueue workerJailingQueue; + //#else + //$$ private JailingQueue workerJailingQueue; + //#endif + private ChunkRenderWorkerAccessor renderWorker; + private int frame; + + public ChunkLoadingRenderGlobal(WorldRenderer renderGlobal) { + this.hooked = renderGlobal; + + setup(((WorldRendererAccessor) renderGlobal).getRenderDispatcher()); + IForceChunkLoading.from(renderGlobal).replayModRender_setHook(this); + } + + public void updateRenderDispatcher(ChunkBuilder renderDispatcher) { + if (this.renderDispatcher != null) { + workerJailingQueue.freeAll(); + this.renderDispatcher = null; + } + if (renderDispatcher != null) { + setup(renderDispatcher); + } + } + + private void setup(ChunkBuilder renderDispatcher) { + this.renderDispatcher = renderDispatcher; + this.renderWorker = (ChunkRenderWorkerAccessor) new ChunkRenderWorker(renderDispatcher, new BlockBufferBuilderStorage()); + ChunkRenderDispatcherAccessor renderDispatcherAcc = (ChunkRenderDispatcherAccessor) renderDispatcher; + + int workerThreads = renderDispatcherAcc.getListThreadedWorkers().size(); + //#if MC>=10904 + PriorityBlockingQueue queueChunkUpdates = renderDispatcherAcc.getQueueChunkUpdates(); + //#else + //$$ BlockingQueue queueChunkUpdates = renderDispatcherAcc.getQueueChunkUpdates(); + //#endif + workerJailingQueue = new JailingQueue<>(queueChunkUpdates); + renderDispatcherAcc.setQueueChunkUpdates(workerJailingQueue); + //#if MC>=10904 + ChunkRenderTask element = new ChunkRenderTask( + null, + null, + 0 + //#if MC>=11400 + , null + //#endif + ); + //#else + //$$ ChunkCompileTaskGenerator element = new ChunkCompileTaskGenerator(null, null); + //#endif + element.cancel(); + for (int i = 0; i < workerThreads; i++) { + queueChunkUpdates.add(element); + } + + // Temporary workaround for dead lock, will be replaced by a new (ShaderMod compatible) mechanism later + //noinspection StatementWithEmptyBody + while (renderDispatcher.runTasksSync(0)) {} + + workerJailingQueue.jail(workerThreads); + renderDispatcherAcc.setQueueChunkUpdates(queueChunkUpdates); + } + + public void updateChunks() { + while (renderDispatcher.runTasksSync(0)) { + ((WorldRendererAccessor) hooked).setDisplayListEntitiesDirty(true); + } + + //#if MC>=10904 + PriorityBlockingQueue queueChunkUpdates; + //#else + //$$ BlockingQueue queueChunkUpdates; + //#endif + queueChunkUpdates = ((ChunkRenderDispatcherAccessor) renderDispatcher).getQueueChunkUpdates(); + while (!queueChunkUpdates.isEmpty()) { + try { + renderWorker.doRunTask(queueChunkUpdates.poll()); + } catch (InterruptedException ignored) { } + } + + Iterator iterator = ((WorldRendererAccessor) hooked).getChunksToUpdate().iterator(); + while (iterator.hasNext()) { + ChunkRenderer renderchunk = iterator.next(); + + renderDispatcher.rebuildSync(renderchunk); + + //#if MC>=10904 + renderchunk.unscheduleRebuild(); + //#else + //$$ renderchunk.setNeedsUpdate(false); + //#endif + iterator.remove(); + } + } + + public int nextFrameId() { + return frame++; + } + + public void uninstall() { + workerJailingQueue.freeAll(); + IForceChunkLoading.from(hooked).replayModRender_setHook(null); + } +} +//#endif From ab5b101f96bfef4f1b3fd0ef54aa20de1bab58ed Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 12:01:15 +0100 Subject: [PATCH 033/102] Add stub ChunkLoadingRenderGlobal for 1.7.10 Allows us to get rid of all preprocessor guards around its usages. --- .../advancedscreenshots/ScreenshotRenderer.java | 9 +-------- .../replaymod/render/hooks/IForceChunkLoading.java | 2 -- .../replaymod/render/rendering/VideoRenderer.java | 12 ++---------- .../render/hooks/ChunkLoadingRenderGlobal.java | 2 -- .../render/hooks/ChunkLoadingRenderGlobal.java | 11 +++++++++++ 5 files changed, 14 insertions(+), 22 deletions(-) create mode 100644 versions/1.7.10/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java index e5b292e3..4a0e2e98 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java @@ -4,6 +4,7 @@ import com.replaymod.core.versions.MCVer; import com.replaymod.render.RenderSettings; import com.replaymod.render.blend.BlendState; import com.replaymod.render.capturer.RenderInfo; +import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; import com.replaymod.render.rendering.Pipelines; import de.johni0702.minecraft.gui.utils.lwjgl.Dimension; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; @@ -15,10 +16,6 @@ import com.replaymod.render.mixin.MainWindowAccessor; import static com.replaymod.core.versions.MCVer.getWindow; //#endif -//#if MC>=10800 -import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; -//#endif - import static com.replaymod.core.versions.MCVer.getRenderPartialTicks; public class ScreenshotRenderer implements RenderInfo { @@ -46,9 +43,7 @@ public class ScreenshotRenderer implements RenderInfo { boolean hideGUIBefore = mc.options.hudHidden; mc.options.hudHidden = true; - //#if MC>=10800 ChunkLoadingRenderGlobal clrg = new ChunkLoadingRenderGlobal(mc.worldRenderer); - //#endif if (settings.getRenderMethod() == RenderSettings.RenderMethod.BLEND) { BlendState.setState(new BlendState(settings.getOutputFile())); @@ -58,9 +53,7 @@ public class ScreenshotRenderer implements RenderInfo { new ScreenshotWriter(settings.getOutputFile())).run(); } - //#if MC>=10800 clrg.uninstall(); - //#endif mc.options.hudHidden = hideGUIBefore; //#if MC>=11400 diff --git a/src/main/java/com/replaymod/render/hooks/IForceChunkLoading.java b/src/main/java/com/replaymod/render/hooks/IForceChunkLoading.java index 57b8c943..83de7bcc 100644 --- a/src/main/java/com/replaymod/render/hooks/IForceChunkLoading.java +++ b/src/main/java/com/replaymod/render/hooks/IForceChunkLoading.java @@ -1,4 +1,3 @@ -//#if MC>=10800 package com.replaymod.render.hooks; import net.minecraft.client.render.WorldRenderer; @@ -10,4 +9,3 @@ public interface IForceChunkLoading { return (IForceChunkLoading) worldRenderer; } } -//#endif diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index 46f56a04..9dd07878 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -17,6 +17,7 @@ import com.replaymod.render.events.ReplayRenderCallback; import com.replaymod.render.frame.BitmapFrame; import com.replaymod.render.gui.GuiRenderingDone; import com.replaymod.render.gui.GuiVideoRenderer; +import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; import com.replaymod.render.metadata.MetadataInjector; import com.replaymod.render.mixin.WorldRendererAccessor; import com.replaymod.replay.ReplayHandler; @@ -57,7 +58,6 @@ import java.util.concurrent.CompletableFuture; //#endif //#if MC>=10800 -import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; import static com.mojang.blaze3d.platform.GlStateManager.*; //#else //$$ import com.replaymod.replay.gui.screen.GuiOpeningReplay; @@ -95,9 +95,7 @@ public class VideoRenderer implements RenderInfo { private TimelinePlayer timelinePlayer; private Future timelinePlayerFuture; - //#if MC>=10800 private ChunkLoadingRenderGlobal chunkLoadingRenderGlobal; - //#endif //#if MC<10800 //$$ private GuiOpeningReplay guiOpeningReplay; //#endif @@ -371,9 +369,7 @@ public class VideoRenderer implements RenderInfo { //$$ gui.toMinecraft().setWorldAndResolution(mc, scaled.getScaledWidth(), scaled.getScaledHeight()); //#endif - //#if MC>=10800 chunkLoadingRenderGlobal = new ChunkLoadingRenderGlobal(mc.worldRenderer); - //#endif // Set up our own framebuffer to render the GUI to guiFramebuffer = new Framebuffer(displayWidth, displayHeight, true @@ -408,11 +404,7 @@ public class VideoRenderer implements RenderInfo { mc.options.setSoundVolume(entry.getKey(), entry.getValue()); } mc.openScreen(null); - //#if MC>=10800 - if (chunkLoadingRenderGlobal != null) { - chunkLoadingRenderGlobal.uninstall(); - } - //#endif + chunkLoadingRenderGlobal.uninstall(); if (!hasFailed() && cameraPathExporter != null) { try { diff --git a/versions/1.14.4/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java b/versions/1.14.4/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java index 6b1acf48..c87e64a8 100644 --- a/versions/1.14.4/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java +++ b/versions/1.14.4/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java @@ -1,4 +1,3 @@ -//#if MC>=10800 package com.replaymod.render.hooks; import com.replaymod.render.mixin.ChunkRenderDispatcherAccessor; @@ -130,4 +129,3 @@ public class ChunkLoadingRenderGlobal { IForceChunkLoading.from(hooked).replayModRender_setHook(null); } } -//#endif diff --git a/versions/1.7.10/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java b/versions/1.7.10/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java new file mode 100644 index 00000000..7366d092 --- /dev/null +++ b/versions/1.7.10/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java @@ -0,0 +1,11 @@ +package com.replaymod.render.hooks; + +import net.minecraft.client.renderer.RenderGlobal; + +public class ChunkLoadingRenderGlobal { + public ChunkLoadingRenderGlobal(RenderGlobal renderGlobal) { + } + + public void uninstall() { + } +} From 3fbb4b50ea277de2ef1f25374aa5943f51840ed9 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 12:06:15 +0100 Subject: [PATCH 034/102] =?UTF-8?q?Rename=20ChunkLoadingRenderGlobal=20?= =?UTF-8?q?=E2=86=92=20ForceChunkLoadingHook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More descriptive, less MCP. --- .../extras/advancedscreenshots/ScreenshotRenderer.java | 4 ++-- ...oadingRenderGlobal.java => ForceChunkLoadingHook.java} | 4 ++-- .../com/replaymod/render/hooks/IForceChunkLoading.java | 2 +- .../render/mixin/Mixin_BlockOnChunkRebuilds.java | 4 ++-- .../replaymod/render/mixin/Mixin_ForceChunkLoading.java | 8 ++++---- .../com/replaymod/render/rendering/VideoRenderer.java | 8 ++++---- ...oadingRenderGlobal.java => ForceChunkLoadingHook.java} | 4 ++-- .../replaymod/render/mixin/Mixin_ForceChunkLoading.java | 6 +++--- ...oadingRenderGlobal.java => ForceChunkLoadingHook.java} | 4 ++-- 9 files changed, 22 insertions(+), 22 deletions(-) rename src/main/java/com/replaymod/render/hooks/{ChunkLoadingRenderGlobal.java => ForceChunkLoadingHook.java} (81%) rename versions/1.14.4/src/main/java/com/replaymod/render/hooks/{ChunkLoadingRenderGlobal.java => ForceChunkLoadingHook.java} (97%) rename versions/1.7.10/src/main/java/com/replaymod/render/hooks/{ChunkLoadingRenderGlobal.java => ForceChunkLoadingHook.java} (56%) diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java index 4a0e2e98..7b730a86 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java @@ -4,7 +4,7 @@ import com.replaymod.core.versions.MCVer; import com.replaymod.render.RenderSettings; import com.replaymod.render.blend.BlendState; import com.replaymod.render.capturer.RenderInfo; -import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; +import com.replaymod.render.hooks.ForceChunkLoadingHook; import com.replaymod.render.rendering.Pipelines; import de.johni0702.minecraft.gui.utils.lwjgl.Dimension; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; @@ -43,7 +43,7 @@ public class ScreenshotRenderer implements RenderInfo { boolean hideGUIBefore = mc.options.hudHidden; mc.options.hudHidden = true; - ChunkLoadingRenderGlobal clrg = new ChunkLoadingRenderGlobal(mc.worldRenderer); + ForceChunkLoadingHook clrg = new ForceChunkLoadingHook(mc.worldRenderer); if (settings.getRenderMethod() == RenderSettings.RenderMethod.BLEND) { BlendState.setState(new BlendState(settings.getOutputFile())); diff --git a/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java b/src/main/java/com/replaymod/render/hooks/ForceChunkLoadingHook.java similarity index 81% rename from src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java rename to src/main/java/com/replaymod/render/hooks/ForceChunkLoadingHook.java index 147a0a20..14143698 100644 --- a/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java +++ b/src/main/java/com/replaymod/render/hooks/ForceChunkLoadingHook.java @@ -2,11 +2,11 @@ package com.replaymod.render.hooks; import net.minecraft.client.render.WorldRenderer; -public class ChunkLoadingRenderGlobal { +public class ForceChunkLoadingHook { private final WorldRenderer hooked; - public ChunkLoadingRenderGlobal(WorldRenderer renderGlobal) { + public ForceChunkLoadingHook(WorldRenderer renderGlobal) { this.hooked = renderGlobal; IForceChunkLoading.from(renderGlobal).replayModRender_setHook(this); diff --git a/src/main/java/com/replaymod/render/hooks/IForceChunkLoading.java b/src/main/java/com/replaymod/render/hooks/IForceChunkLoading.java index 83de7bcc..7c21c77e 100644 --- a/src/main/java/com/replaymod/render/hooks/IForceChunkLoading.java +++ b/src/main/java/com/replaymod/render/hooks/IForceChunkLoading.java @@ -3,7 +3,7 @@ package com.replaymod.render.hooks; import net.minecraft.client.render.WorldRenderer; public interface IForceChunkLoading { - void replayModRender_setHook(ChunkLoadingRenderGlobal hook); + void replayModRender_setHook(ForceChunkLoadingHook hook); static IForceChunkLoading from(WorldRenderer worldRenderer) { return (IForceChunkLoading) worldRenderer; diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_BlockOnChunkRebuilds.java b/src/main/java/com/replaymod/render/mixin/Mixin_BlockOnChunkRebuilds.java index dff22e27..a11818c4 100644 --- a/src/main/java/com/replaymod/render/mixin/Mixin_BlockOnChunkRebuilds.java +++ b/src/main/java/com/replaymod/render/mixin/Mixin_BlockOnChunkRebuilds.java @@ -2,7 +2,7 @@ package com.replaymod.render.mixin; //#if MC>=11500 import com.mojang.blaze3d.systems.RenderSystem; -import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; +import com.replaymod.render.hooks.ForceChunkLoadingHook; import net.minecraft.client.render.chunk.BlockBufferBuilderStorage; import net.minecraft.client.render.chunk.ChunkBuilder; import net.minecraft.util.thread.TaskExecutor; @@ -21,7 +21,7 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @Mixin(ChunkBuilder.class) -public abstract class Mixin_BlockOnChunkRebuilds implements ChunkLoadingRenderGlobal.IBlockOnChunkRebuilds { +public abstract class Mixin_BlockOnChunkRebuilds implements ForceChunkLoadingHook.IBlockOnChunkRebuilds { @Shadow @Final private Queue threadBuffers; @Shadow public abstract boolean upload(); diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java b/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java index eb322b1c..3312a60e 100644 --- a/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java +++ b/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java @@ -1,7 +1,7 @@ package com.replaymod.render.mixin; import com.replaymod.compat.shaders.ShaderReflection; -import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; +import com.replaymod.render.hooks.ForceChunkLoadingHook; import com.replaymod.render.hooks.IForceChunkLoading; import net.minecraft.client.render.Camera; import net.minecraft.client.render.Frustum; @@ -17,10 +17,10 @@ import java.util.Set; @Mixin(WorldRenderer.class) public abstract class Mixin_ForceChunkLoading implements IForceChunkLoading { - private ChunkLoadingRenderGlobal replayModRender_hook; + private ForceChunkLoadingHook replayModRender_hook; @Override - public void replayModRender_setHook(ChunkLoadingRenderGlobal hook) { + public void replayModRender_setHook(ForceChunkLoadingHook hook) { this.replayModRender_hook = hook; } @@ -66,7 +66,7 @@ public abstract class Mixin_ForceChunkLoading implements IForceChunkLoading { this.chunksToRebuild.clear(); // Upload all chunks - this.needsTerrainUpdate |= ((ChunkLoadingRenderGlobal.IBlockOnChunkRebuilds) this.chunkBuilder).uploadEverythingBlocking(); + this.needsTerrainUpdate |= ((ForceChunkLoadingHook.IBlockOnChunkRebuilds) this.chunkBuilder).uploadEverythingBlocking(); // Repeat until no more updates are needed } while (this.needsTerrainUpdate); diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index 9dd07878..1fa40c7c 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -17,7 +17,7 @@ import com.replaymod.render.events.ReplayRenderCallback; import com.replaymod.render.frame.BitmapFrame; import com.replaymod.render.gui.GuiRenderingDone; import com.replaymod.render.gui.GuiVideoRenderer; -import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; +import com.replaymod.render.hooks.ForceChunkLoadingHook; import com.replaymod.render.metadata.MetadataInjector; import com.replaymod.render.mixin.WorldRendererAccessor; import com.replaymod.replay.ReplayHandler; @@ -95,7 +95,7 @@ public class VideoRenderer implements RenderInfo { private TimelinePlayer timelinePlayer; private Future timelinePlayerFuture; - private ChunkLoadingRenderGlobal chunkLoadingRenderGlobal; + private ForceChunkLoadingHook forceChunkLoadingHook; //#if MC<10800 //$$ private GuiOpeningReplay guiOpeningReplay; //#endif @@ -369,7 +369,7 @@ public class VideoRenderer implements RenderInfo { //$$ gui.toMinecraft().setWorldAndResolution(mc, scaled.getScaledWidth(), scaled.getScaledHeight()); //#endif - chunkLoadingRenderGlobal = new ChunkLoadingRenderGlobal(mc.worldRenderer); + forceChunkLoadingHook = new ForceChunkLoadingHook(mc.worldRenderer); // Set up our own framebuffer to render the GUI to guiFramebuffer = new Framebuffer(displayWidth, displayHeight, true @@ -404,7 +404,7 @@ public class VideoRenderer implements RenderInfo { mc.options.setSoundVolume(entry.getKey(), entry.getValue()); } mc.openScreen(null); - chunkLoadingRenderGlobal.uninstall(); + forceChunkLoadingHook.uninstall(); if (!hasFailed() && cameraPathExporter != null) { try { diff --git a/versions/1.14.4/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java b/versions/1.14.4/src/main/java/com/replaymod/render/hooks/ForceChunkLoadingHook.java similarity index 97% rename from versions/1.14.4/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java rename to versions/1.14.4/src/main/java/com/replaymod/render/hooks/ForceChunkLoadingHook.java index c87e64a8..181c7fc1 100644 --- a/versions/1.14.4/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java +++ b/versions/1.14.4/src/main/java/com/replaymod/render/hooks/ForceChunkLoadingHook.java @@ -20,7 +20,7 @@ import java.util.concurrent.PriorityBlockingQueue; import static com.replaymod.core.versions.MCVer.ChunkRenderWorkerAccessor; -public class ChunkLoadingRenderGlobal { +public class ForceChunkLoadingHook { private final WorldRenderer hooked; @@ -33,7 +33,7 @@ public class ChunkLoadingRenderGlobal { private ChunkRenderWorkerAccessor renderWorker; private int frame; - public ChunkLoadingRenderGlobal(WorldRenderer renderGlobal) { + public ForceChunkLoadingHook(WorldRenderer renderGlobal) { this.hooked = renderGlobal; setup(((WorldRendererAccessor) renderGlobal).getRenderDispatcher()); diff --git a/versions/1.14.4/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java b/versions/1.14.4/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java index 593c61ad..92120a32 100644 --- a/versions/1.14.4/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java +++ b/versions/1.14.4/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java @@ -2,7 +2,7 @@ package com.replaymod.render.mixin; //#if MC>=10800 import com.replaymod.compat.shaders.ShaderReflection; -import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; +import com.replaymod.render.hooks.ForceChunkLoadingHook; import com.replaymod.render.hooks.IForceChunkLoading; import net.minecraft.client.render.VisibleRegion; import net.minecraft.client.render.WorldRenderer; @@ -27,10 +27,10 @@ import net.minecraft.client.render.Camera; @Mixin(WorldRenderer.class) public abstract class Mixin_ForceChunkLoading implements IForceChunkLoading { - private ChunkLoadingRenderGlobal replayModRender_hook; + private ForceChunkLoadingHook replayModRender_hook; @Override - public void replayModRender_setHook(ChunkLoadingRenderGlobal hook) { + public void replayModRender_setHook(ForceChunkLoadingHook hook) { this.replayModRender_hook = hook; } diff --git a/versions/1.7.10/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java b/versions/1.7.10/src/main/java/com/replaymod/render/hooks/ForceChunkLoadingHook.java similarity index 56% rename from versions/1.7.10/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java rename to versions/1.7.10/src/main/java/com/replaymod/render/hooks/ForceChunkLoadingHook.java index 7366d092..670c7426 100644 --- a/versions/1.7.10/src/main/java/com/replaymod/render/hooks/ChunkLoadingRenderGlobal.java +++ b/versions/1.7.10/src/main/java/com/replaymod/render/hooks/ForceChunkLoadingHook.java @@ -2,8 +2,8 @@ package com.replaymod.render.hooks; import net.minecraft.client.renderer.RenderGlobal; -public class ChunkLoadingRenderGlobal { - public ChunkLoadingRenderGlobal(RenderGlobal renderGlobal) { +public class ForceChunkLoadingHook { + public ForceChunkLoadingHook(RenderGlobal renderGlobal) { } public void uninstall() { From e4da7f331bc377c710c392d9b0217763ac35744b Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 13:00:52 +0100 Subject: [PATCH 035/102] DRY main MC window resizing --- .../com/replaymod/core/versions/MCVer.java | 35 +++++++++++++++++++ .../ScreenshotRenderer.java | 33 +++-------------- .../render/capturer/ODSFrameCapturer.java | 3 +- .../render/capturer/OpenGlFrameCapturer.java | 34 ++---------------- .../render/rendering/VideoRenderer.java | 17 +-------- 5 files changed, 45 insertions(+), 77 deletions(-) diff --git a/src/main/java/com/replaymod/core/versions/MCVer.java b/src/main/java/com/replaymod/core/versions/MCVer.java index 83e44b1c..333ef194 100644 --- a/src/main/java/com/replaymod/core/versions/MCVer.java +++ b/src/main/java/com/replaymod/core/versions/MCVer.java @@ -5,6 +5,7 @@ import com.replaymod.core.mixin.MinecraftAccessor; import com.replaymod.replaystudio.protocol.PacketTypeRegistry; import com.replaymod.replaystudio.us.myles.ViaVersion.api.protocol.ProtocolVersion; import com.replaymod.replaystudio.us.myles.ViaVersion.packets.State; +import de.johni0702.minecraft.gui.utils.lwjgl.Dimension; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.options.KeyBinding; @@ -37,7 +38,9 @@ import java.util.ArrayList; //#if MC>=11400 import com.replaymod.core.mixin.AbstractButtonWidgetAccessor; +import com.replaymod.render.mixin.MainWindowAccessor; import net.minecraft.SharedConstants; +import net.minecraft.client.gl.Framebuffer; import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.AbstractButtonWidget; @@ -196,6 +199,38 @@ public class MCVer { //#endif } + public static Dimension getMainWindowSize(MinecraftClient mc) { + return new Dimension( + //#if MC>=11400 + getWindow(mc).getFramebufferWidth(), + getWindow(mc).getFramebufferHeight() + //#else + //$$ mc.displayWidth, + //$$ mc.displayHeight + //#endif + ); + } + + public static void resizeMainWindow(MinecraftClient mc, int width, int height) { + //#if MC>=11400 + Framebuffer fb = mc.getFramebuffer(); + if (fb.viewportWidth != width || fb.viewportHeight != height) { + fb.resize(width, height, false); + } + //noinspection ConstantConditions + MainWindowAccessor mainWindow = (MainWindowAccessor) (Object) getWindow(mc); + mainWindow.setFramebufferWidth(width); + mainWindow.setFramebufferHeight(height); + //#if MC>=11500 + mc.gameRenderer.onResized(width, height); + //#endif + //#else + //$$ if (width != mc.displayWidth || height != mc.displayHeight) { + //$$ mc.resize(width, height); + //$$ } + //#endif + } + public static double Entity_getX(Entity entity) { //#if MC>=11500 return entity.getX(); diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java index 7b730a86..54e8d01f 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java @@ -11,12 +11,9 @@ import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; import net.minecraft.client.MinecraftClient; import net.minecraft.util.crash.CrashReport; -//#if MC>=11400 -import com.replaymod.render.mixin.MainWindowAccessor; -import static com.replaymod.core.versions.MCVer.getWindow; -//#endif - +import static com.replaymod.core.versions.MCVer.getMainWindowSize; import static com.replaymod.core.versions.MCVer.getRenderPartialTicks; +import static com.replaymod.core.versions.MCVer.resizeMainWindow; public class ScreenshotRenderer implements RenderInfo { @@ -32,14 +29,7 @@ public class ScreenshotRenderer implements RenderInfo { public boolean renderScreenshot() throws Throwable { try { - //#if MC>=11400 - int displayWidthBefore = getWindow(mc).getFramebufferWidth(); - int displayHeightBefore = getWindow(mc).getFramebufferHeight(); - //#else - //$$ int displayWidthBefore = mc.displayWidth; - //$$ int displayHeightBefore = mc.displayHeight; - //#endif - + Dimension sizeBefore = getMainWindowSize(mc); boolean hideGUIBefore = mc.options.hudHidden; mc.options.hudHidden = true; @@ -56,22 +46,7 @@ public class ScreenshotRenderer implements RenderInfo { clrg.uninstall(); mc.options.hudHidden = hideGUIBefore; - //#if MC>=11400 - //noinspection ConstantConditions - MainWindowAccessor acc = (MainWindowAccessor) (Object) getWindow(mc); - acc.setFramebufferWidth(displayWidthBefore); - acc.setFramebufferHeight(displayHeightBefore); - mc.getFramebuffer().resize(displayWidthBefore, displayHeightBefore - //#if MC>=11400 - , false - //#endif - ); - //#if MC>=11500 - mc.gameRenderer.onResized(displayWidthBefore, displayHeightBefore); - //#endif - //#else - //$$ mc.resize(displayWidthBefore, displayHeightBefore); - //#endif + resizeMainWindow(mc, sizeBefore.getWidth(), sizeBefore.getHeight()); return true; } catch (OutOfMemoryError e) { e.printStackTrace(); diff --git a/src/main/java/com/replaymod/render/capturer/ODSFrameCapturer.java b/src/main/java/com/replaymod/render/capturer/ODSFrameCapturer.java index 5f8d1713..d4bb955a 100644 --- a/src/main/java/com/replaymod/render/capturer/ODSFrameCapturer.java +++ b/src/main/java/com/replaymod/render/capturer/ODSFrameCapturer.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; +import static com.replaymod.core.versions.MCVer.resizeMainWindow; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; @@ -164,7 +165,7 @@ public class ODSFrameCapturer implements FrameCapturer { @Override protected OpenGlFrame renderFrame(int frameId, float partialTicks, CubicOpenGlFrameCapturer.Data captureData) { - resize(getFrameWidth(), getFrameHeight()); + resizeMainWindow(mc, getFrameWidth(), getFrameHeight()); pushMatrix(); frameBuffer().beginWrite(true); diff --git a/src/main/java/com/replaymod/render/capturer/OpenGlFrameCapturer.java b/src/main/java/com/replaymod/render/capturer/OpenGlFrameCapturer.java index 571d5164..f5b89064 100644 --- a/src/main/java/com/replaymod/render/capturer/OpenGlFrameCapturer.java +++ b/src/main/java/com/replaymod/render/capturer/OpenGlFrameCapturer.java @@ -16,17 +16,13 @@ import org.lwjgl.opengl.GL12; import java.io.IOException; import java.nio.ByteBuffer; -//#if MC>=11400 -import com.replaymod.render.mixin.MainWindowAccessor; -import static com.replaymod.core.versions.MCVer.getWindow; -//#endif - //#if MC>=10800 import static com.mojang.blaze3d.platform.GlStateManager.*; //#else //$$ import static com.replaymod.core.versions.MCVer.GlStateManager.*; //#endif +import static com.replaymod.core.versions.MCVer.resizeMainWindow; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; @@ -36,7 +32,7 @@ public abstract class OpenGlFrameCapturer=11400 - Framebuffer fb = mc.getFramebuffer(); - if (fb.viewportWidth != width || fb.viewportHeight != height) { - fb.resize(width, height - //#if MC>=11400 - , false - //#endif - ); - } - //noinspection ConstantConditions - MainWindowAccessor mainWindow = (MainWindowAccessor) (Object) getWindow(mc); - mainWindow.setFramebufferWidth(width); - mainWindow.setFramebufferHeight(height); - //#if MC>=11500 - mc.gameRenderer.onResized(width, height); - //#endif - //#else - //$$ if (width != mc.displayWidth || height != mc.displayHeight) { - //$$ mc.resize(width, height); - //$$ } - //#endif - } - @Override public void close() throws IOException { } diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index 1fa40c7c..32f8accc 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -425,22 +425,7 @@ public class VideoRenderer implements RenderInfo { } // Finally, resize the Minecraft framebuffer to the actual width/height of the window - //#if MC>=11400 - mc.getFramebuffer().resize(displayWidth, displayHeight - //#if MC>=11400 - , false - //#endif - ); - //noinspection ConstantConditions - MainWindowAccessor acc = (MainWindowAccessor) (Object) getWindow(mc); - acc.setFramebufferWidth(displayWidth); - acc.setFramebufferHeight(displayHeight); - //#if MC>=11500 - mc.gameRenderer.onResized(displayWidth, displayHeight); - //#endif - //#else - //$$ mc.resize(displayWidth, displayHeight); - //#endif + resizeMainWindow(mc, displayWidth, displayHeight); } private void executeTaskQueue() { From 4eeaca5af16f5bdfb4a16b90fe7ffd0ab35124c1 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 23 Feb 2021 13:37:06 +0100 Subject: [PATCH 036/102] Use MainWindowAccessor across all versions --- .../com/replaymod/core/versions/MCVer.java | 9 +++++++-- .../render/mixin/MainWindowAccessor.java | 6 ++++-- .../render/rendering/VideoRenderer.java | 19 +++---------------- .../resources/mixins.render.replaymod.json | 2 +- .../render/mixin/MainWindowAccessor.java | 17 +++++++++++++++++ 5 files changed, 32 insertions(+), 21 deletions(-) create mode 100644 versions/1.12.2/src/main/java/com/replaymod/render/mixin/MainWindowAccessor.java diff --git a/src/main/java/com/replaymod/core/versions/MCVer.java b/src/main/java/com/replaymod/core/versions/MCVer.java index 333ef194..854c4a8f 100644 --- a/src/main/java/com/replaymod/core/versions/MCVer.java +++ b/src/main/java/com/replaymod/core/versions/MCVer.java @@ -2,9 +2,11 @@ package com.replaymod.core.versions; import com.replaymod.core.mixin.GuiScreenAccessor; import com.replaymod.core.mixin.MinecraftAccessor; +import com.replaymod.render.mixin.MainWindowAccessor; import com.replaymod.replaystudio.protocol.PacketTypeRegistry; import com.replaymod.replaystudio.us.myles.ViaVersion.api.protocol.ProtocolVersion; import com.replaymod.replaystudio.us.myles.ViaVersion.packets.State; +import de.johni0702.minecraft.gui.utils.NonNull; import de.johni0702.minecraft.gui.utils.lwjgl.Dimension; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; @@ -38,7 +40,6 @@ import java.util.ArrayList; //#if MC>=11400 import com.replaymod.core.mixin.AbstractButtonWidgetAccessor; -import com.replaymod.render.mixin.MainWindowAccessor; import net.minecraft.SharedConstants; import net.minecraft.client.gl.Framebuffer; import net.minecraft.client.gui.widget.ButtonWidget; @@ -464,13 +465,17 @@ public class MCVer { } //#if MC>=11400 - public static Window getWindow(MinecraftClient mc) { + public static @NonNull Window getWindow(MinecraftClient mc) { //#if MC>=11500 return mc.getWindow(); //#else //$$ return mc.window; //#endif } + //#else + //$$ public static @NonNull MainWindowAccessor getWindow(Minecraft mc) { + //$$ return (MainWindowAccessor) mc; + //$$ } //#endif //#if MC>=11400 diff --git a/src/main/java/com/replaymod/render/mixin/MainWindowAccessor.java b/src/main/java/com/replaymod/render/mixin/MainWindowAccessor.java index bb276fa2..335c9908 100644 --- a/src/main/java/com/replaymod/render/mixin/MainWindowAccessor.java +++ b/src/main/java/com/replaymod/render/mixin/MainWindowAccessor.java @@ -1,4 +1,3 @@ -//#if MC>=11400 package com.replaymod.render.mixin; import net.minecraft.client.util.Window; @@ -7,9 +6,12 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(Window.class) public interface MainWindowAccessor { + @Accessor + int getFramebufferWidth(); @Accessor void setFramebufferWidth(int value); @Accessor + int getFramebufferHeight(); + @Accessor void setFramebufferHeight(int value); } -//#endif diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index 32f8accc..a265e245 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -19,6 +19,7 @@ import com.replaymod.render.gui.GuiRenderingDone; import com.replaymod.render.gui.GuiVideoRenderer; import com.replaymod.render.hooks.ForceChunkLoadingHook; import com.replaymod.render.metadata.MetadataInjector; +import com.replaymod.render.mixin.MainWindowAccessor; import com.replaymod.render.mixin.WorldRendererAccessor; import com.replaymod.replay.ReplayHandler; import com.replaymod.replaystudio.pathing.path.Keyframe; @@ -46,7 +47,6 @@ import org.lwjgl.opengl.GL11; //#if MC>=11400 import com.replaymod.render.EXRWriter; -import com.replaymod.render.mixin.MainWindowAccessor; import net.minecraft.client.gui.screen.Screen; import org.lwjgl.glfw.GLFW; import java.util.concurrent.CompletableFuture; @@ -232,19 +232,11 @@ public class VideoRenderer implements RenderInfo { @Override public float updateForNextFrame() { // because the jGui lib uses Minecraft's displayWidth and displayHeight values, update these temporarily - //#if MC>=11400 - int displayWidthBefore = getWindow(mc).getFramebufferWidth(); - int displayHeightBefore = getWindow(mc).getFramebufferHeight(); - //noinspection ConstantConditions MainWindowAccessor acc = (MainWindowAccessor) (Object) getWindow(mc); + int displayWidthBefore = acc.getFramebufferWidth(); + int displayHeightBefore = acc.getFramebufferHeight(); acc.setFramebufferWidth(displayWidth); acc.setFramebufferHeight(displayHeight); - //#else - //$$ int displayWidthBefore = mc.displayWidth; - //$$ int displayHeightBefore = mc.displayHeight; - //$$ mc.displayWidth = displayWidth; - //$$ mc.displayHeight = displayHeight; - //#endif if (!settings.isHighPerformance() || framesDone % fps == 0) { while (drawGui() && paused) { @@ -285,13 +277,8 @@ public class VideoRenderer implements RenderInfo { } // change Minecraft's display size back - //#if MC>=11400 acc.setFramebufferWidth(displayWidthBefore); acc.setFramebufferHeight(displayHeightBefore); - //#else - //$$ mc.displayWidth = displayWidthBefore; - //$$ mc.displayHeight = displayHeightBefore; - //#endif if (cameraPathExporter != null) { cameraPathExporter.recordFrame(timer.tickDelta); diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index 976fbf9b..3e47b65d 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -20,8 +20,8 @@ //#if MC>=11400 "Mixin_PreserveDepthDuringHandRendering", "Mixin_WindowsWorkaroundForTinyEXRNatives", - "MainWindowAccessor", //#endif + "MainWindowAccessor", "WorldRendererAccessor", //#if MC>=10904 "MixinParticleManager", diff --git a/versions/1.12.2/src/main/java/com/replaymod/render/mixin/MainWindowAccessor.java b/versions/1.12.2/src/main/java/com/replaymod/render/mixin/MainWindowAccessor.java new file mode 100644 index 00000000..2d91cb58 --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/render/mixin/MainWindowAccessor.java @@ -0,0 +1,17 @@ +package com.replaymod.render.mixin; + +import net.minecraft.client.Minecraft; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(Minecraft.class) +public interface MainWindowAccessor { + @Accessor("displayWidth") + int getFramebufferWidth(); + @Accessor("displayWidth") + void setFramebufferWidth(int value); + @Accessor("displayHeight") + int getFramebufferHeight(); + @Accessor("displayHeight") + void setFramebufferHeight(int value); +} From 05d7971332d3b39fc3d71b41d183ecebc8748e41 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 14:42:24 +0100 Subject: [PATCH 037/102] Move mapwriter.MixinMinecraft into 1.12.2 project --- .../mapwriter/mixin/MixinMinecraft.java | 47 +------------------ .../mapwriter/mixin/MixinMinecraft.java | 44 +++++++++++++++++ 2 files changed, 45 insertions(+), 46 deletions(-) create mode 100644 versions/1.12.2/src/main/java/com/replaymod/compat/mapwriter/mixin/MixinMinecraft.java diff --git a/src/main/java/com/replaymod/compat/mapwriter/mixin/MixinMinecraft.java b/src/main/java/com/replaymod/compat/mapwriter/mixin/MixinMinecraft.java index e9119205..fca4cd6c 100644 --- a/src/main/java/com/replaymod/compat/mapwriter/mixin/MixinMinecraft.java +++ b/src/main/java/com/replaymod/compat/mapwriter/mixin/MixinMinecraft.java @@ -1,46 +1 @@ -//#if MC<11400 -//$$ package com.replaymod.compat.mapwriter.mixin; -//$$ -//$$ import com.replaymod.replay.ReplayModReplay; -//$$ import net.minecraft.client.Minecraft; -//$$ import net.minecraft.client.multiplayer.ServerData; -//$$ 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.CallbackInfoReturnable; -//$$ -//#if MC>=10800 -//$$ import net.minecraftforge.fml.common.Loader; -//#else -//$$ import cpw.mods.fml.common.Loader; -//#endif -//$$ -//$$ /** -//$$ * Approximately this for <1.12: https://github.com/Vectron/mapwriter/commit/68234520c7a3a0ae8201a085d7e66369900586ac -//$$ */ -//$$ @Mixin(Minecraft.class) -//$$ public abstract class MixinMinecraft { -//$$ -//$$ @Shadow -//$$ private ServerData currentServerData; -//$$ -//$$ @Inject(method = "getCurrentServerData", cancellable = true, at = @At("HEAD")) -//$$ private void replayModCompat_fixBug96(CallbackInfoReturnable ci) { -//$$ if (currentServerData == null -//$$ && (Loader.isModLoaded("mapwriter") || Loader.isModLoaded("MapWriter")) -//$$ && ReplayModReplay.instance.getReplayHandler() != null) { -//$$ for (StackTraceElement elem : Thread.currentThread().getStackTrace()) { -//$$ if ("mapwriter.util.Utils".equals(elem.getClassName()) && "getWorldName".equals(elem.getMethodName())) { - //#if MC>=10809 - //$$ ci.setReturnValue(new ServerData(null, "replay", false)); - //#else - //$$ ci.setReturnValue(new ServerData(null, "replay")); - //#endif -//$$ return; -//$$ } -//$$ } -//$$ } -//$$ } -//$$ } -//#endif +// 1.12.2 and below diff --git a/versions/1.12.2/src/main/java/com/replaymod/compat/mapwriter/mixin/MixinMinecraft.java b/versions/1.12.2/src/main/java/com/replaymod/compat/mapwriter/mixin/MixinMinecraft.java new file mode 100644 index 00000000..7a4a792c --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/compat/mapwriter/mixin/MixinMinecraft.java @@ -0,0 +1,44 @@ +package com.replaymod.compat.mapwriter.mixin; + +import com.replaymod.replay.ReplayModReplay; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ServerData; +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.CallbackInfoReturnable; + +//#if MC>=10800 +import net.minecraftforge.fml.common.Loader; +//#else +//$$ import cpw.mods.fml.common.Loader; +//#endif + +/** + * Approximately this for <1.12: https://github.com/Vectron/mapwriter/commit/68234520c7a3a0ae8201a085d7e66369900586ac + */ +@Mixin(Minecraft.class) +public abstract class MixinMinecraft { + + @Shadow + private ServerData currentServerData; + + @Inject(method = "getCurrentServerData", cancellable = true, at = @At("HEAD")) + private void replayModCompat_fixBug96(CallbackInfoReturnable ci) { + if (currentServerData == null + && (Loader.isModLoaded("mapwriter") || Loader.isModLoaded("MapWriter")) + && ReplayModReplay.instance.getReplayHandler() != null) { + for (StackTraceElement elem : Thread.currentThread().getStackTrace()) { + if ("mapwriter.util.Utils".equals(elem.getClassName()) && "getWorldName".equals(elem.getMethodName())) { + //#if MC>=10809 + ci.setReturnValue(new ServerData(null, "replay", false)); + //#else + //$$ ci.setReturnValue(new ServerData(null, "replay")); + //#endif + return; + } + } + } + } +} From 5f652ec7f2f06305824eb5f602ec7caaa1a64119 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 14:43:31 +0100 Subject: [PATCH 038/102] Move DisableBetterSprinting into 1.12.2 project --- .../DisableBetterSprinting.java | 186 +----------------- .../DisableBetterSprinting.java | 183 +++++++++++++++++ 2 files changed, 184 insertions(+), 185 deletions(-) create mode 100644 versions/1.12.2/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java diff --git a/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java b/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java index 6d0ec973..fca4cd6c 100644 --- a/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java +++ b/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java @@ -1,185 +1 @@ -//#if MC<11400 -//$$ package com.replaymod.compat.bettersprinting; -//$$ -//$$ import com.replaymod.replay.ReplayModReplay; -//$$ import com.replaymod.replay.events.ReplayChatMessageEvent; -//$$ import net.minecraft.client.Minecraft; -//$$ import net.minecraft.client.multiplayer.PlayerControllerMP; -//$$ import net.minecraft.entity.Entity; -//$$ import net.minecraft.entity.player.EntityPlayer; -//$$ import net.minecraftforge.client.event.GuiOpenEvent; -//$$ import net.minecraftforge.common.MinecraftForge; -//$$ -//#if MC>=10904 -//$$ import net.minecraft.block.state.IBlockState; -//$$ import net.minecraft.util.SoundCategory; -//$$ import net.minecraft.util.SoundEvent; -//$$ import net.minecraft.util.math.BlockPos; -//$$ import net.minecraft.world.IWorldEventListener; -//$$ import net.minecraft.world.World; -//$$ -//$$ import javax.annotation.Nullable; -//#else -//#if MC>= 10800 -//$$ import net.minecraft.util.BlockPos; -//#endif -//$$ import net.minecraft.world.IWorldAccess; -//#endif -//$$ -//#if MC>=10800 -//$$ import net.minecraftforge.fml.common.Loader; -//$$ import net.minecraftforge.fml.common.ModContainer; -//$$ import net.minecraftforge.fml.common.eventhandler.EventPriority; -//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -//$$ import net.minecraftforge.fml.common.versioning.DefaultArtifactVersion; -//$$ import net.minecraftforge.fml.common.versioning.Restriction; -//$$ import net.minecraftforge.fml.common.versioning.VersionRange; -//#else -//$$ import cpw.mods.fml.common.Loader; -//$$ import cpw.mods.fml.common.ModContainer; -//$$ import cpw.mods.fml.common.eventhandler.EventPriority; -//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent; -//$$ import cpw.mods.fml.common.versioning.DefaultArtifactVersion; -//$$ import cpw.mods.fml.common.versioning.Restriction; -//$$ import cpw.mods.fml.common.versioning.VersionRange; -//#endif -//$$ -//$$ import java.util.Collections; -//$$ -//$$ import static com.replaymod.compat.ReplayModCompat.LOGGER; -//$$ import static com.replaymod.core.versions.MCVer.*; -//$$ -//$$ /** -//$$ * Old Better Sprinting versions replace the vanilla player with their own, overridden instance (replacing the camera entity). -//$$ * -//$$ * See: https://github.com/chylex/Better-Sprinting/blob/1.8/src/main/java/chylex/bettersprinting/client/player/impl/LogicImplOverride.java -//$$ */ -//$$ public class DisableBetterSprinting { -//$$ private static final VersionRange OLD_VERSION = VersionRange.newRange(null, -//$$ Collections.singletonList(new Restriction(null, false, new DefaultArtifactVersion("2.0.0"), false))); -//$$ private static final String LOGIC_CLASS_NAME = "chylex.bettersprinting.client.player.impl.LogicImplOverride"; -//$$ private static final String CONTROLLER_OVERRIDE_CLASS_NAME = LOGIC_CLASS_NAME + "$PlayerControllerMPOverride"; -//$$ -//$$ public static void register() { -//$$ Loader.instance().getModList().stream() -//$$ .filter(mod -> mod.getModId().equalsIgnoreCase("bettersprinting")) -//$$ .findFirst() -//$$ .map(ModContainer::getProcessedVersion).filter(OLD_VERSION::containsVersion) -//$$ .ifPresent($_ -> MinecraftForge.EVENT_BUS.register(new DisableBetterSprinting())); -//$$ } -//$$ -//$$ private DisableBetterSprinting() { -//$$ LOGGER.info("BetterSprinting workaround enabled"); -//$$ } -//$$ -//$$ private final Minecraft mc = Minecraft.getMinecraft(); -//$$ private PlayerControllerMP originalController; -//$$ private BetterSprintingWorldAccess worldAccessHook = new BetterSprintingWorldAccess(); -//$$ -//$$ @SubscribeEvent(priority = EventPriority.HIGH) -//$$ public void beforeGuiOpenEvent(GuiOpenEvent event) { -//$$ if (ReplayModReplay.instance.getReplayHandler() != null && mc.world != null) { -//$$ // During replay, get ready to revert BetterSprinting's overwritten playerController -//$$ originalController = mc.playerController; - //#if MC>=10904 - //$$ mc.world.addEventListener(worldAccessHook); - //#else - //$$ mc.theWorld.addWorldAccess(worldAccessHook); - //#endif -//$$ } -//$$ } -//$$ -//$$ @SubscribeEvent(priority = EventPriority.LOW) -//$$ public void afterGuiOpenEvent(GuiOpenEvent event) { -//$$ if (ReplayModReplay.instance.getReplayHandler() != null && mc.world != null) { - //#if MC>=10904 - //$$ mc.world.addEventListener(worldAccessHook); - //#else - //$$ mc.theWorld.addWorldAccess(worldAccessHook); - //#endif -//$$ } -//$$ } -//$$ -//$$ @SubscribeEvent -//$$ public void onReplayChatMessage(ReplayChatMessageEvent event) { -//$$ // Suppress this message if it's the Better Sprinting warning message -//$$ for (StackTraceElement elem : Thread.currentThread().getStackTrace()) { -//$$ if (LOGIC_CLASS_NAME.equals(elem.getClassName())) { -//$$ LOGGER.info("BetterSprinting warning message suppressed."); -//$$ event.setCanceled(true); -//$$ return; -//$$ } -//$$ } -//$$ } -//$$ -//$$ private class BetterSprintingWorldAccess - //#if MC>=10904 - //$$ implements IWorldEventListener - //#else - //$$ implements IWorldAccess - //#endif -//$$ { -//$$ @Override - //#if MC>=10800 - //$$ public void onEntityRemoved(Entity entityIn) { - //#else - //$$ public void onEntityDestroy(Entity entityIn) { - //#endif -//$$ if (mc.playerController != null && mc.playerController.getClass().getName().equals(CONTROLLER_OVERRIDE_CLASS_NAME)) { -//$$ // Someone has secretly swapped out the player controller and is about to substitute their own player entity. -//$$ // This is the right time to destroy their plan. -//$$ LOGGER.info("Preventing player controller {} from being replaced by BetterSprinting with {}.", originalController, mc.playerController); -//$$ mc.playerController = originalController; -//$$ } -//$$ } -//$$ -//$$ @Override public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2) {} - //#if MC>=10800 - //$$ @Override public void notifyLightSet(BlockPos pos) {} - //$$ @Override public void spawnParticle(int p_180442_1_, boolean p_180442_2_, double p_180442_3_, double p_180442_5_, double p_180442_7_, double p_180442_9_, double p_180442_11_, double p_180442_13_, int... p_180442_15_) {} - //$$ @Override public void onEntityAdded(Entity entityIn) {} - //$$ @Override public void broadcastSound(int p_180440_1_, BlockPos p_180440_2_, int p_180440_3_) {} - //$$ @Override public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress) {} - //#else - //$$ @Override public void markBlockForRenderUpdate(int x, int y, int z) {} - //$$ @Override public void spawnParticle(String p_72708_1_, double p_72708_2_, double p_72708_4_, double p_72708_6_, double p_72708_8_, double p_72708_10_, double p_72708_12_) {} - //$$ @Override public void onEntityCreate(Entity entityIn) {} - //$$ @Override public void broadcastSound(int p_180440_1_, int x, int y, int z, int p_180440_3_) {} - //$$ @Override public void destroyBlockPartially(int breakerId, int x, int y, int z, int progress) {} - //$$ @Override public void onStaticEntitiesChanged() {} - //#endif - //#if MC>=10904 - //$$ @Override public void notifyBlockUpdate(World worldIn, BlockPos pos, IBlockState oldState, IBlockState newState, int flags) {} - //$$ @Override public void playSoundToAllNearExcept(@Nullable EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch) {} - //$$ @Override public void playRecord(SoundEvent soundIn, BlockPos pos) {} - //$$ @Override public void playEvent(EntityPlayer player, int type, BlockPos blockPosIn, int data) {} - //#if MC>=11100 - //#if MC>=11102 - //$$ @Override public void spawnParticle(int p_190570_1_, boolean p_190570_2_, boolean p_190570_3_, double p_190570_4_, double p_190570_6_, double p_190570_8_, double p_190570_10_, double p_190570_12_, double p_190570_14_, int... p_190570_16_) {} - //#else - //$$ @Override public void func_190570_a(int p_190570_1_, boolean p_190570_2_, boolean p_190570_3_, double p_190570_4_, double p_190570_6_, double p_190570_8_, double p_190570_10_, double p_190570_12_, double p_190570_14_, int... p_190570_16_) {} - //#endif - //#endif - //#else - //#if MC>=10800 - //$$ @Override public void markBlockForUpdate(BlockPos pos) {} - //$$ @Override public void playRecord(String recordName, BlockPos blockPosIn) {} - //#else - //$$ @Override public void markBlockForUpdate(int x, int y, int z) {} - //$$ @Override public void playRecord(String recordName, int x, int y, int z) {} - //#endif - //$$ @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) {} - //$$ @Override public void playSoundToNearExcept(EntityPlayer except, String soundName, double x, double y, double z, float volume, float pitch) {} - //#if MC>=10809 - //$$ @Override public void playAuxSFX(EntityPlayer p_180439_1_, int p_180439_2_, BlockPos blockPosIn, int p_180439_4_) {} - //#else - //#if MC>=10800 - //$$ @Override public void playAusSFX(EntityPlayer p_180439_1_, int p_180439_2_, BlockPos blockPosIn, int p_180439_4_) {} - //#else - //$$ @Override public void playAuxSFX(EntityPlayer p_72706_1_, int p_72706_2_, int p_72706_3_, int p_72706_4_, int p_72706_5_, int p_72706_6_) {} - //#endif - //#endif - //#endif -//$$ } -//$$ } -//#endif +// 1.12.2 and below diff --git a/versions/1.12.2/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java b/versions/1.12.2/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java new file mode 100644 index 00000000..127450d5 --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/compat/bettersprinting/DisableBetterSprinting.java @@ -0,0 +1,183 @@ +package com.replaymod.compat.bettersprinting; + +import com.replaymod.replay.ReplayModReplay; +import com.replaymod.replay.events.ReplayChatMessageEvent; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.PlayerControllerMP; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraftforge.client.event.GuiOpenEvent; +import net.minecraftforge.common.MinecraftForge; + +//#if MC>=10904 +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorldEventListener; +import net.minecraft.world.World; + +import javax.annotation.Nullable; +//#else +//#if MC>= 10800 +//$$ import net.minecraft.util.BlockPos; +//#endif +//$$ import net.minecraft.world.IWorldAccess; +//#endif + +//#if MC>=10800 +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.ModContainer; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.versioning.DefaultArtifactVersion; +import net.minecraftforge.fml.common.versioning.Restriction; +import net.minecraftforge.fml.common.versioning.VersionRange; +//#else +//$$ import cpw.mods.fml.common.Loader; +//$$ import cpw.mods.fml.common.ModContainer; +//$$ import cpw.mods.fml.common.eventhandler.EventPriority; +//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent; +//$$ import cpw.mods.fml.common.versioning.DefaultArtifactVersion; +//$$ import cpw.mods.fml.common.versioning.Restriction; +//$$ import cpw.mods.fml.common.versioning.VersionRange; +//#endif + +import java.util.Collections; + +import static com.replaymod.compat.ReplayModCompat.LOGGER; +import static com.replaymod.core.versions.MCVer.*; + +/** + * Old Better Sprinting versions replace the vanilla player with their own, overridden instance (replacing the camera entity). + * + * See: https://github.com/chylex/Better-Sprinting/blob/1.8/src/main/java/chylex/bettersprinting/client/player/impl/LogicImplOverride.java + */ +public class DisableBetterSprinting { + private static final VersionRange OLD_VERSION = VersionRange.newRange(null, + Collections.singletonList(new Restriction(null, false, new DefaultArtifactVersion("2.0.0"), false))); + private static final String LOGIC_CLASS_NAME = "chylex.bettersprinting.client.player.impl.LogicImplOverride"; + private static final String CONTROLLER_OVERRIDE_CLASS_NAME = LOGIC_CLASS_NAME + "$PlayerControllerMPOverride"; + + public static void register() { + Loader.instance().getModList().stream() + .filter(mod -> mod.getModId().equalsIgnoreCase("bettersprinting")) + .findFirst() + .map(ModContainer::getProcessedVersion).filter(OLD_VERSION::containsVersion) + .ifPresent($_ -> MinecraftForge.EVENT_BUS.register(new DisableBetterSprinting())); + } + + private DisableBetterSprinting() { + LOGGER.info("BetterSprinting workaround enabled"); + } + + private final Minecraft mc = Minecraft.getMinecraft(); + private PlayerControllerMP originalController; + private BetterSprintingWorldAccess worldAccessHook = new BetterSprintingWorldAccess(); + + @SubscribeEvent(priority = EventPriority.HIGH) + public void beforeGuiOpenEvent(GuiOpenEvent event) { + if (ReplayModReplay.instance.getReplayHandler() != null && mc.world != null) { + // During replay, get ready to revert BetterSprinting's overwritten playerController + originalController = mc.playerController; + //#if MC>=10904 + mc.world.addEventListener(worldAccessHook); + //#else + //$$ mc.theWorld.addWorldAccess(worldAccessHook); + //#endif + } + } + + @SubscribeEvent(priority = EventPriority.LOW) + public void afterGuiOpenEvent(GuiOpenEvent event) { + if (ReplayModReplay.instance.getReplayHandler() != null && mc.world != null) { + //#if MC>=10904 + mc.world.addEventListener(worldAccessHook); + //#else + //$$ mc.theWorld.addWorldAccess(worldAccessHook); + //#endif + } + } + + @SubscribeEvent + public void onReplayChatMessage(ReplayChatMessageEvent event) { + // Suppress this message if it's the Better Sprinting warning message + for (StackTraceElement elem : Thread.currentThread().getStackTrace()) { + if (LOGIC_CLASS_NAME.equals(elem.getClassName())) { + LOGGER.info("BetterSprinting warning message suppressed."); + event.setCanceled(true); + return; + } + } + } + + private class BetterSprintingWorldAccess + //#if MC>=10904 + implements IWorldEventListener + //#else + //$$ implements IWorldAccess + //#endif + { + @Override + //#if MC>=10800 + public void onEntityRemoved(Entity entityIn) { + //#else + //$$ public void onEntityDestroy(Entity entityIn) { + //#endif + if (mc.playerController != null && mc.playerController.getClass().getName().equals(CONTROLLER_OVERRIDE_CLASS_NAME)) { + // Someone has secretly swapped out the player controller and is about to substitute their own player entity. + // This is the right time to destroy their plan. + LOGGER.info("Preventing player controller {} from being replaced by BetterSprinting with {}.", originalController, mc.playerController); + mc.playerController = originalController; + } + } + + @Override public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2) {} + //#if MC>=10800 + @Override public void notifyLightSet(BlockPos pos) {} + @Override public void spawnParticle(int p_180442_1_, boolean p_180442_2_, double p_180442_3_, double p_180442_5_, double p_180442_7_, double p_180442_9_, double p_180442_11_, double p_180442_13_, int... p_180442_15_) {} + @Override public void onEntityAdded(Entity entityIn) {} + @Override public void broadcastSound(int p_180440_1_, BlockPos p_180440_2_, int p_180440_3_) {} + @Override public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress) {} + //#else + //$$ @Override public void markBlockForRenderUpdate(int x, int y, int z) {} + //$$ @Override public void spawnParticle(String p_72708_1_, double p_72708_2_, double p_72708_4_, double p_72708_6_, double p_72708_8_, double p_72708_10_, double p_72708_12_) {} + //$$ @Override public void onEntityCreate(Entity entityIn) {} + //$$ @Override public void broadcastSound(int p_180440_1_, int x, int y, int z, int p_180440_3_) {} + //$$ @Override public void destroyBlockPartially(int breakerId, int x, int y, int z, int progress) {} + //$$ @Override public void onStaticEntitiesChanged() {} + //#endif + //#if MC>=10904 + @Override public void notifyBlockUpdate(World worldIn, BlockPos pos, IBlockState oldState, IBlockState newState, int flags) {} + @Override public void playSoundToAllNearExcept(@Nullable EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch) {} + @Override public void playRecord(SoundEvent soundIn, BlockPos pos) {} + @Override public void playEvent(EntityPlayer player, int type, BlockPos blockPosIn, int data) {} + //#if MC>=11100 + //#if MC>=11102 + @Override public void spawnParticle(int p_190570_1_, boolean p_190570_2_, boolean p_190570_3_, double p_190570_4_, double p_190570_6_, double p_190570_8_, double p_190570_10_, double p_190570_12_, double p_190570_14_, int... p_190570_16_) {} + //#else + //$$ @Override public void func_190570_a(int p_190570_1_, boolean p_190570_2_, boolean p_190570_3_, double p_190570_4_, double p_190570_6_, double p_190570_8_, double p_190570_10_, double p_190570_12_, double p_190570_14_, int... p_190570_16_) {} + //#endif + //#endif + //#else + //#if MC>=10800 + //$$ @Override public void markBlockForUpdate(BlockPos pos) {} + //$$ @Override public void playRecord(String recordName, BlockPos blockPosIn) {} + //#else + //$$ @Override public void markBlockForUpdate(int x, int y, int z) {} + //$$ @Override public void playRecord(String recordName, int x, int y, int z) {} + //#endif + //$$ @Override public void playSound(String soundName, double x, double y, double z, float volume, float pitch) {} + //$$ @Override public void playSoundToNearExcept(EntityPlayer except, String soundName, double x, double y, double z, float volume, float pitch) {} + //#if MC>=10809 + //$$ @Override public void playAuxSFX(EntityPlayer p_180439_1_, int p_180439_2_, BlockPos blockPosIn, int p_180439_4_) {} + //#else + //#if MC>=10800 + //$$ @Override public void playAusSFX(EntityPlayer p_180439_1_, int p_180439_2_, BlockPos blockPosIn, int p_180439_4_) {} + //#else + //$$ @Override public void playAuxSFX(EntityPlayer p_72706_1_, int p_72706_2_, int p_72706_3_, int p_72706_4_, int p_72706_5_, int p_72706_6_) {} + //#endif + //#endif + //#endif + } +} From d7dde42add73db33c7b068ac12faa24d5a450714 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 14:44:34 +0100 Subject: [PATCH 039/102] Move HideInvisibleEntities into 1.12.2 project --- .../HideInvisibleEntities.java | 33 +------------------ .../HideInvisibleEntities.java | 30 +++++++++++++++++ 2 files changed, 31 insertions(+), 32 deletions(-) create mode 100644 versions/1.12.2/src/main/java/com/replaymod/compat/oranges17animations/HideInvisibleEntities.java diff --git a/src/main/java/com/replaymod/compat/oranges17animations/HideInvisibleEntities.java b/src/main/java/com/replaymod/compat/oranges17animations/HideInvisibleEntities.java index 75ac3000..fca4cd6c 100644 --- a/src/main/java/com/replaymod/compat/oranges17animations/HideInvisibleEntities.java +++ b/src/main/java/com/replaymod/compat/oranges17animations/HideInvisibleEntities.java @@ -1,32 +1 @@ -//#if MC<11400 -//$$ package com.replaymod.compat.oranges17animations; -//$$ -//$$ import com.replaymod.replay.camera.CameraEntity; -//$$ import de.johni0702.minecraft.gui.utils.EventRegistrations; -//$$ import net.minecraft.client.Minecraft; -//$$ import net.minecraftforge.client.event.RenderLivingEvent; -//$$ import net.minecraftforge.fml.common.eventhandler.EventPriority; -//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -//$$ -//$$ import static com.replaymod.core.versions.MCVer.*; -//$$ -//$$ /** -//$$ * Orange seems to have copied vast parts of the RendererLivingEntity into their ArmorAnimation class which cancels the RenderLivingEvent.Pre and calls its own code instead. -//$$ * This breaks our mixin which assures that, even though the camera is in spectator mode, it cannot see invisible entities. -//$$ * -//$$ * To fix this issue, we simply cancel the RenderLivingEvent.Pre before it gets to ArmorAnimation if the entity is invisible. -//$$ */ -//$$ public class HideInvisibleEntities extends EventRegistrations { -//$$ private final Minecraft mc = Minecraft.getMinecraft(); -//$$ private final boolean modLoaded = isModLoaded("animations"); -//$$ -//$$ @SubscribeEvent(priority = EventPriority.HIGH) -//$$ public void preRenderLiving(RenderLivingEvent.Pre event) { -//$$ if (modLoaded) { -//$$ if (mc.player instanceof CameraEntity && getEntity(event).isInvisible()) { -//$$ event.setCanceled(true); -//$$ } -//$$ } -//$$ } -//$$ } -//#endif +// 1.12.2 and below diff --git a/versions/1.12.2/src/main/java/com/replaymod/compat/oranges17animations/HideInvisibleEntities.java b/versions/1.12.2/src/main/java/com/replaymod/compat/oranges17animations/HideInvisibleEntities.java new file mode 100644 index 00000000..d97a953a --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/compat/oranges17animations/HideInvisibleEntities.java @@ -0,0 +1,30 @@ +package com.replaymod.compat.oranges17animations; + +import com.replaymod.replay.camera.CameraEntity; +import de.johni0702.minecraft.gui.utils.EventRegistrations; +import net.minecraft.client.Minecraft; +import net.minecraftforge.client.event.RenderLivingEvent; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import static com.replaymod.core.versions.MCVer.*; + +/** + * Orange seems to have copied vast parts of the RendererLivingEntity into their ArmorAnimation class which cancels the RenderLivingEvent.Pre and calls its own code instead. + * This breaks our mixin which assures that, even though the camera is in spectator mode, it cannot see invisible entities. + * + * To fix this issue, we simply cancel the RenderLivingEvent.Pre before it gets to ArmorAnimation if the entity is invisible. + */ +public class HideInvisibleEntities extends EventRegistrations { + private final Minecraft mc = Minecraft.getMinecraft(); + private final boolean modLoaded = isModLoaded("animations"); + + @SubscribeEvent(priority = EventPriority.HIGH) + public void preRenderLiving(RenderLivingEvent.Pre event) { + if (modLoaded) { + if (mc.player instanceof CameraEntity && getEntity(event).isInvisible()) { + event.setCanceled(true); + } + } + } +} From f34b88cf7eb9e007848706f425f49bf99d925060 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 14:45:45 +0100 Subject: [PATCH 040/102] Move MixinShader into 1.7.10 project --- .../compat/shaders/mixin/MixinShaders.java | 53 +------------------ .../compat/shaders/mixin/MixinShaders.java | 52 ++++++++++++++++++ 2 files changed, 53 insertions(+), 52 deletions(-) create mode 100644 versions/1.7.10/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaders.java diff --git a/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaders.java b/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaders.java index d14764d2..743815c4 100644 --- a/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaders.java +++ b/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaders.java @@ -1,52 +1 @@ -//#if MC<=10710 -//$$ package com.replaymod.compat.shaders.mixin; -//$$ -//$$ import com.replaymod.render.hooks.EntityRendererHandler; -//$$ import com.replaymod.replay.ReplayHandler; -//$$ import com.replaymod.replay.ReplayModReplay; -//$$ import net.minecraft.client.Minecraft; -//$$ import org.spongepowered.asm.mixin.Mixin; -//$$ import org.spongepowered.asm.mixin.Pseudo; -//$$ import org.spongepowered.asm.mixin.Shadow; -//$$ import org.spongepowered.asm.mixin.injection.At; -//$$ import org.spongepowered.asm.mixin.injection.Redirect; -//$$ -//$$ @Pseudo -//$$ @Mixin(targets = "shadersmod/client/Shaders", remap = false) -//$$ public abstract class MixinShaders { -//$$ -//$$ @Shadow static Minecraft mc; -//$$ @Shadow static long systemTime; -//$$ @Shadow static long lastSystemTime; -//$$ @Shadow static long diffSystemTime; -//$$ @Shadow static int frameCounter; -//$$ @Shadow static float frameTime; -//$$ @Shadow static float frameTimeCounter; -//$$ -//$$ @Redirect(method = "beginRender", at = @At(value = "INVOKE", target = "Ljava/lang/System;currentTimeMillis()J")) -//$$ private static long replayModCompat_currentTimeMillis() { -//$$ ReplayHandler replayHandler = ReplayModReplay.instance.getReplayHandler(); -//$$ if (replayHandler != null) { -//$$ systemTime = replayHandler.getReplaySender().currentTimeStamp(); -//$$ -//$$ // We need to manipulate all the other previous-frame-time-based variables too -//$$ -//$$ lastSystemTime = 0; // Draw all frames as if they were the first ones -//$$ // diffSystemTime will be set to 0 by Shaders -//$$ // frameTime will be set to 0 by Shaders -//$$ frameTimeCounter = systemTime / 1000f; // will be %= 3600f by Shaders -//$$ -//$$ // Set frameCounter only if rendering is in progress -//$$ EntityRendererHandler entityRendererHandler = -//$$ ((EntityRendererHandler.IEntityRenderer) mc.entityRenderer).replayModRender_getHandler(); -//$$ if (entityRendererHandler != null) { -//$$ frameCounter = entityRendererHandler.getRenderInfo().getFramesDone(); -//$$ } -//$$ -//$$ return systemTime; -//$$ } -//$$ return System.currentTimeMillis(); -//$$ } -//$$ -//$$ } -//#endif +// 1.7.10 and below diff --git a/versions/1.7.10/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaders.java b/versions/1.7.10/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaders.java new file mode 100644 index 00000000..cec9d0a5 --- /dev/null +++ b/versions/1.7.10/src/main/java/com/replaymod/compat/shaders/mixin/MixinShaders.java @@ -0,0 +1,52 @@ +//#if MC<=10710 +package com.replaymod.compat.shaders.mixin; + +import com.replaymod.render.hooks.EntityRendererHandler; +import com.replaymod.replay.ReplayHandler; +import com.replaymod.replay.ReplayModReplay; +import net.minecraft.client.Minecraft; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Pseudo +@Mixin(targets = "shadersmod/client/Shaders", remap = false) +public abstract class MixinShaders { + + @Shadow static Minecraft mc; + @Shadow static long systemTime; + @Shadow static long lastSystemTime; + @Shadow static long diffSystemTime; + @Shadow static int frameCounter; + @Shadow static float frameTime; + @Shadow static float frameTimeCounter; + + @Redirect(method = "beginRender", at = @At(value = "INVOKE", target = "Ljava/lang/System;currentTimeMillis()J")) + private static long replayModCompat_currentTimeMillis() { + ReplayHandler replayHandler = ReplayModReplay.instance.getReplayHandler(); + if (replayHandler != null) { + systemTime = replayHandler.getReplaySender().currentTimeStamp(); + + // We need to manipulate all the other previous-frame-time-based variables too + + lastSystemTime = 0; // Draw all frames as if they were the first ones + // diffSystemTime will be set to 0 by Shaders + // frameTime will be set to 0 by Shaders + frameTimeCounter = systemTime / 1000f; // will be %= 3600f by Shaders + + // Set frameCounter only if rendering is in progress + EntityRendererHandler entityRendererHandler = + ((EntityRendererHandler.IEntityRenderer) mc.entityRenderer).replayModRender_getHandler(); + if (entityRendererHandler != null) { + frameCounter = entityRendererHandler.getRenderInfo().getFramesDone(); + } + + return systemTime; + } + return System.currentTimeMillis(); + } + +} +//#endif From da16b0fb7851ab14e26768c72d137898a44cd9dd Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 15:03:10 +0100 Subject: [PATCH 041/102] Add 1.14.4 <> 1.12.2 mapping for Option <> GameSettings.Options --- src/main/java/com/replaymod/core/ReplayMod.java | 11 +---------- versions/1.14.4-forge/mapping.txt | 2 ++ 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/replaymod/core/ReplayMod.java b/src/main/java/com/replaymod/core/ReplayMod.java index 797ea79e..ba1805b2 100644 --- a/src/main/java/com/replaymod/core/ReplayMod.java +++ b/src/main/java/com/replaymod/core/ReplayMod.java @@ -21,6 +21,7 @@ import com.replaymod.replaystudio.util.I18n; import com.replaymod.simplepathing.ReplayModSimplePathing; import de.johni0702.minecraft.gui.container.GuiScreen; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.options.Option; import net.minecraft.util.Identifier; import net.minecraft.resource.DirectoryResourcePack; import net.minecraft.text.Text; @@ -31,12 +32,6 @@ import net.minecraft.util.Formatting; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FileUtils; -//#if MC>=11400 -import net.minecraft.client.options.Option; -//#else -//$$ import net.minecraft.client.settings.GameSettings; -//#endif - import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; @@ -229,11 +224,7 @@ public class ReplayMod implements Module, Scheduler { // 1.7.10 crashes when render distance > 16 //#if MC>=10800 if (!MCVer.hasOptifine()) { - //#if MC>=11400 Option.RENDER_DISTANCE.setMax(64f); - //#else - //$$ GameSettings.Options.RENDER_DISTANCE.setValueMax(64f); - //#endif } //#endif diff --git a/versions/1.14.4-forge/mapping.txt b/versions/1.14.4-forge/mapping.txt index 09a126b7..6a1960e7 100644 --- a/versions/1.14.4-forge/mapping.txt +++ b/versions/1.14.4-forge/mapping.txt @@ -4,6 +4,8 @@ net.minecraft.resources.AbstractResourcePack net.minecraft.client.resources.Abst net.minecraft.resources.FolderPack net.minecraft.client.resources.FolderResourcePack net.minecraft.client.resources.DownloadingPackFinder net.minecraft.client.resources.ResourcePackRepository net.minecraft.client.renderer.chunk.ChunkRenderTask net.minecraft.client.renderer.chunk.ChunkCompileTaskGenerator +net.minecraft.client.settings.AbstractOption net.minecraft.client.settings.GameSettings.Options +net.minecraft.client.settings.AbstractOption func_216728_a() setValueMax() net.minecraftforge.eventbus.api.SubscribeEvent net.minecraftforge.fml.common.eventhandler.SubscribeEvent net.minecraftforge.eventbus.api.EventPriority net.minecraftforge.fml.common.eventhandler.EventPriority net.minecraftforge.eventbus.api.Cancelable net.minecraftforge.fml.common.eventhandler.Cancelable From 06a46e6f386d828a12187bcb53171cfb2cd29f04 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 15:49:40 +0100 Subject: [PATCH 042/102] Use callback-style events for crosshair and hotbar render events --- .../replaymod/replay/camera/CameraEntity.java | 22 ++++++------------- .../replay/events/RenderHotbarCallback.java | 19 ++++++++++++++++ .../RenderSpectatorCrosshairCallback.java | 2 -- .../replay/mixin/MixinInGameHud.java | 10 +++++++++ .../core/versions/forge/EventsAdapter.java | 20 +++++++++++++++++ 5 files changed, 56 insertions(+), 17 deletions(-) create mode 100644 src/main/java/com/replaymod/replay/events/RenderHotbarCallback.java diff --git a/src/main/java/com/replaymod/replay/camera/CameraEntity.java b/src/main/java/com/replaymod/replay/camera/CameraEntity.java index ea28d740..31151cac 100644 --- a/src/main/java/com/replaymod/replay/camera/CameraEntity.java +++ b/src/main/java/com/replaymod/replay/camera/CameraEntity.java @@ -8,6 +8,8 @@ import com.replaymod.core.events.PreRenderCallback; import com.replaymod.core.events.PreRenderHandCallback; import com.replaymod.core.events.SettingsChangedCallback; import com.replaymod.replay.ReplayHandler; +import com.replaymod.replay.events.RenderHotbarCallback; +import com.replaymod.replay.events.RenderSpectatorCrosshairCallback; import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback; import com.replaymod.core.utils.Utils; @@ -28,7 +30,6 @@ import net.minecraft.util.Identifier; import net.minecraft.util.math.Box; //#if FABRIC>=1 -import com.replaymod.replay.events.RenderSpectatorCrosshairCallback; //#else //$$ import com.replaymod.core.versions.MCVer; //$$ import net.minecraftforge.client.event.EntityViewRenderEvent; @@ -680,24 +681,15 @@ public class CameraEntity { on(KeyBindingEventCallback.EVENT, CameraEntity.this::handleInputEvents); } - //#if FABRIC>=1 { on(RenderSpectatorCrosshairCallback.EVENT, this::shouldRenderSpectatorCrosshair); } private Boolean shouldRenderSpectatorCrosshair() { return canSpectate(mc.targetedEntity); } - //#else - //$$ @SubscribeEvent - //$$ public void preCrosshairRender(RenderGameOverlayEvent.Pre event) { - //$$ // The crosshair should only render if targeted entity can actually be spectated - //$$ if (MCVer.getType(event) == RenderGameOverlayEvent.ElementType.CROSSHAIRS) { - //$$ event.setCanceled(!canSpectate(mc.pointedEntity)); - //$$ } - //$$ // Hotbar should never be rendered - //$$ if (MCVer.getType(event) == RenderGameOverlayEvent.ElementType.HOTBAR) { - //$$ event.setCanceled(true); - //$$ } - //$$ } - //#endif + + { on(RenderHotbarCallback.EVENT, this::shouldRenderHotbar); } + private Boolean shouldRenderHotbar() { + return false; + } { on(SettingsChangedCallback.EVENT, this::onSettingsChanged); } private void onSettingsChanged(SettingsRegistry registry, SettingsRegistry.SettingKey key) { diff --git a/src/main/java/com/replaymod/replay/events/RenderHotbarCallback.java b/src/main/java/com/replaymod/replay/events/RenderHotbarCallback.java new file mode 100644 index 00000000..36e1667c --- /dev/null +++ b/src/main/java/com/replaymod/replay/events/RenderHotbarCallback.java @@ -0,0 +1,19 @@ +package com.replaymod.replay.events; + +import de.johni0702.minecraft.gui.utils.Event; + +public interface RenderHotbarCallback { + Event EVENT = Event.create((listeners) -> + () -> { + for (RenderHotbarCallback listener : listeners) { + Boolean state = listener.shouldRenderHotbar(); + if (state != null) { + return state; + } + } + return null; + } + ); + + Boolean shouldRenderHotbar(); +} diff --git a/src/main/java/com/replaymod/replay/events/RenderSpectatorCrosshairCallback.java b/src/main/java/com/replaymod/replay/events/RenderSpectatorCrosshairCallback.java index 47ce1418..bad49102 100644 --- a/src/main/java/com/replaymod/replay/events/RenderSpectatorCrosshairCallback.java +++ b/src/main/java/com/replaymod/replay/events/RenderSpectatorCrosshairCallback.java @@ -1,4 +1,3 @@ -//#if MC>=11400 package com.replaymod.replay.events; import de.johni0702.minecraft.gui.utils.Event; @@ -18,4 +17,3 @@ public interface RenderSpectatorCrosshairCallback { Boolean shouldRenderSpectatorCrosshair(); } -//#endif diff --git a/src/main/java/com/replaymod/replay/mixin/MixinInGameHud.java b/src/main/java/com/replaymod/replay/mixin/MixinInGameHud.java index 82f720a8..88431748 100644 --- a/src/main/java/com/replaymod/replay/mixin/MixinInGameHud.java +++ b/src/main/java/com/replaymod/replay/mixin/MixinInGameHud.java @@ -1,11 +1,13 @@ //#if MC>=11400 package com.replaymod.replay.mixin; +import com.replaymod.replay.events.RenderHotbarCallback; import com.replaymod.replay.events.RenderSpectatorCrosshairCallback; import net.minecraft.client.gui.hud.InGameHud; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(InGameHud.class) @@ -17,5 +19,13 @@ public class MixinInGameHud { ci.setReturnValue(state); } } + + @Inject(method = "renderHotbar", at = @At("HEAD"), cancellable = true) + private void shouldRenderHotbar(CallbackInfo ci) { + Boolean state = RenderHotbarCallback.EVENT.invoker().shouldRenderHotbar(); + if (state == Boolean.FALSE) { + ci.cancel(); + } + } } //#endif diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/EventsAdapter.java b/versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/EventsAdapter.java index 02e5574f..2083b9fc 100644 --- a/versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/EventsAdapter.java +++ b/versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/EventsAdapter.java @@ -5,8 +5,12 @@ import com.replaymod.core.events.PostRenderCallback; import com.replaymod.core.events.PostRenderWorldCallback; import com.replaymod.core.events.PreRenderCallback; import com.replaymod.core.events.PreRenderHandCallback; +import com.replaymod.core.versions.MCVer; +import com.replaymod.replay.events.RenderHotbarCallback; +import com.replaymod.replay.events.RenderSpectatorCrosshairCallback; import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.versions.MatrixStack; +import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.client.event.RenderHandEvent; import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @@ -47,4 +51,20 @@ public class EventsAdapter extends EventRegistrations { event.setCanceled(true); } } + + @SubscribeEvent + public void preRenderGameOverlay(RenderGameOverlayEvent.Pre event) { + Boolean result = null; + switch (MCVer.getType(event)) { + case CROSSHAIRS: + result = RenderSpectatorCrosshairCallback.EVENT.invoker().shouldRenderSpectatorCrosshair(); + break; + case HOTBAR: + result = RenderHotbarCallback.EVENT.invoker().shouldRenderHotbar(); + break; + } + if (result == Boolean.FALSE) { + event.setCanceled(true); + } + } } From cfb9e15b8a732ca32d3944ec80fd05094e094168 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 17:54:49 +0100 Subject: [PATCH 043/102] Make use of new @Pattern feature to centralize version-aware code That is, most of the business code should not be aware that it is being compiled to multiple versions even when it heavily interacts with MC, preprocessor statements should be an escape hatch, not the norm. Similarly, code should not be forced to do `MCVer.getWindow(mc)` instead of the much more intuitive `mc.getWindow()`, and a new preprocessor (technically remap) feature makes this possible by defining "search and replace"-like patterns (but smarter in that they are type-aware) in one or more central places (the "Patterns.java" files) which then are applied all over the code base. In a way, this is another step in the automatic back-porting process where preprocessor statements are used when we cannot yet do something automatically. Previously we "merely" automatically converted between different mapping, this new feature now also allows us to automatically perform simple refactoring tasks like changing field access to a getter+setter (e.g. `mc.getWindow()`), or changing how a method is called (e.g. `BufferBuilder.begin`), or changing a method call chain (e.g. `dispatcher.camera.getYaw()`), or most other search-and-replace-like changes and any combination of those. The only major limitation is that the replacement itself is not smart, so arguments must be kept in same order (or be temporarily assigned to local variables which then can be used in any order). --- README.md | 52 +- build.gradle | 2 + root.gradle.kts | 2 +- .../compat/shaders/ShaderBeginRender.java | 4 +- .../replaymod/core/KeyBindingRegistry.java | 16 +- .../java/com/replaymod/core/ReplayMod.java | 16 +- .../com/replaymod/core/ReplayModBackend.java | 8 + .../replaymod/core/utils/Restrictions.java | 4 +- .../core/versions/BufferBuilder.java | 1 + .../com/replaymod/core/versions/GLFW.java | 1 + .../com/replaymod/core/versions/MCVer.java | 517 +----------------- .../com/replaymod/core/versions/Patterns.java | 376 +++++++++++++ .../com/replaymod/core/versions/Window.java | 1 + .../core/versions/forge/Patterns.java | 1 + .../com/replaymod/extras/OpenEyeExtra.java | 12 +- .../ScreenshotRenderer.java | 11 +- .../extras/playeroverview/PlayerOverview.java | 2 +- .../com/replaymod/gradle/remap/Pattern.java | 11 + .../recording/gui/GuiRecordingOverlay.java | 3 +- .../handler/ConnectionEventHandler.java | 2 +- .../handler/RecordingEventHandler.java | 33 +- .../mixin/MixinNetHandlerPlayClient.java | 2 +- .../recording/packet/PacketListener.java | 12 +- .../com/replaymod/render/FFmpegWriter.java | 4 +- .../render/blend/BlendFrameCapturer.java | 4 +- .../render/blend/BlendMeshBuilder.java | 3 +- .../replaymod/render/blend/BlendState.java | 12 +- .../exporters/ModelRendererExporter.java | 11 +- .../replaymod/render/gui/GuiExportFailed.java | 5 +- .../replaymod/render/mixin/MixinCamera.java | 6 +- .../render/mixin/MixinEntityRenderer.java | 2 +- .../replaymod/render/rendering/Pipeline.java | 16 +- .../render/rendering/VideoRenderer.java | 65 +-- .../replaymod/replay/FullReplaySender.java | 22 +- .../com/replaymod/replay/NoGuiScreenshot.java | 21 +- .../com/replaymod/replay/ReplayHandler.java | 65 +-- .../com/replaymod/replay/ReplayModReplay.java | 8 +- .../replaymod/replay/camera/CameraEntity.java | 40 +- .../camera/ClassicCameraController.java | 6 +- .../camera/SpectatorCameraController.java | 4 +- .../replaymod/replay/handler/GuiHandler.java | 18 +- .../replaymod/simplepathing/SPTimeline.java | 5 +- .../gui/GuiKeyframeTimeline.java | 41 +- .../simplepathing/gui/GuiPathing.java | 4 +- .../preview/PathPreviewRenderer.java | 124 +++-- .../HideInvisibleEntities.java | 7 +- .../com/replaymod/core/ReplayModBackend.java | 8 + .../com/replaymod/core/versions/GLFW.java | 9 + .../com/replaymod/core/versions/Window.java | 69 +++ .../core/versions/forge/EventsAdapter.java | 2 +- .../core/versions/forge/Patterns.java | 47 ++ versions/1.14.4-forge/mapping.txt | 3 + .../com/replaymod/core/ReplayModBackend.java | 9 + .../core/versions/BufferBuilder.java | 30 + versions/1.8/mapping.txt | 2 + versions/1.9.4/mapping.txt | 1 + 56 files changed, 890 insertions(+), 872 deletions(-) create mode 100644 src/main/java/com/replaymod/core/versions/BufferBuilder.java create mode 100644 src/main/java/com/replaymod/core/versions/GLFW.java create mode 100644 src/main/java/com/replaymod/core/versions/Patterns.java create mode 100644 src/main/java/com/replaymod/core/versions/Window.java create mode 100644 src/main/java/com/replaymod/core/versions/forge/Patterns.java create mode 100644 src/main/java/com/replaymod/gradle/remap/Pattern.java create mode 100644 versions/1.12.2/src/main/java/com/replaymod/core/versions/GLFW.java create mode 100644 versions/1.12.2/src/main/java/com/replaymod/core/versions/Window.java create mode 100644 versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/Patterns.java create mode 100644 versions/1.7.10/src/main/java/com/replaymod/core/versions/BufferBuilder.java diff --git a/README.md b/README.md index a05f2b8e..d9f32cc9 100644 --- a/README.md +++ b/README.md @@ -30,55 +30,9 @@ The `master` branch is solely to be used for the `version.json` file that contai used by the clients to check for updates of this mod. ### The Preprocessor -To support multiple Minecraft versions with the ReplayMod, a [JCP](https://github.com/raydac/java-comment-preprocessor)-inspired preprocessor is used: -```java - //#if MC>=11200 - // This is the block for MC >= 1.12.0 - category.addDetail(name, callable::call); - //#else - //$$ // This is the block for MC < 1.12.0 - //$$ category.setDetail(name, callable::call); - //#endif -``` -Any comments starting with `//$$` will automatically be introduced / removed based on the surrounding condition(s). -Normal comments are left untouched. The `//#else` branch is optional. - -Conditions can be nested arbitrarily but their indention shall always be equal to the indention of the code at the `//#if` line. -The `//$$` shall be aligned with the inner-most `//#if`. -```java - //#if MC>=10904 - public CPacketResourcePackStatus makeStatusPacket(String hash, Action action) { - //#if MC>=11002 - return new CPacketResourcePackStatus(action); - //#else - //$$ return new CPacketResourcePackStatus(hash, action); - //#endif - } - //#else - //$$ public C19PacketResourcePackStatus makeStatusPacket(String hash, Action action) { - //$$ return new C19PacketResourcePackStatus(hash, action); - //$$ } - //#endif -``` -Code for the more recent MC version shall be placed in the first branch of the if-else-construct. -Version-dependent import statements shall be placed separately from and after all other imports. -Common version dependent code (including the fml and forge event bus) are available as static methods/fields in the `MCVer` class. - -The source code in `src/main` is generally for the most recent Minecraft version and is automatically passed through the -preprocessor when any of the other versions are built (gradle projects `:1.8`, `:1.8.9`, etc.). -Do **NOT** edit any of the code in `versions/$MCVERSION/build/` as it is automatically generated and will be overwritten without warning. - -You can change the version of the code in `src/main` if you wish to develop/debug with another version of Minecraft: -```bash -./gradle :1.9.4:setCoreVersion # switches all sources in src/main to 1.9.4 -``` -If you do so, you'll also have to refresh the project in your IDE. - -Make sure to switch back to the most recent branch before committing! -Care should also be taken that switching to a different branch and back doesn't introduce any uncommitted changes (e.g. due to different indention, especially in case of nested conditions). - -Some files may use the same preprocessor with different keywords. -If required, more file extensions and keywords can be added in the `preprocess` block of the `versions/common.gradle` script. +To support multiple Minecraft versions with the ReplayMod, a [JCP](https://github.com/raydac/java-comment-preprocessor)-inspired preprocessor is used. +It has by now acquired a lot more sophisticated features to make it as noninvasive as possible. +Please read the [preprocessor's README](https://github.com/ReplayMod/preprocessor/blob/master/README.md) to understand how it works. ### Versioning The ReplayMod uses the versioning scheme outlined [here](http://mcforge.readthedocs.io/en/latest/conventions/versioning/) diff --git a/build.gradle b/build.gradle index e103e23f..38d975af 100644 --- a/build.gradle +++ b/build.gradle @@ -102,6 +102,8 @@ preprocess { ".vert": PreprocessTask.DEFAULT_KEYWORDS, ".frag": PreprocessTask.DEFAULT_KEYWORDS, ]) + + patternAnnotation.set("com.replaymod.gradle.remap.Pattern") } def mcVersionStr = "${(int)(mcVersion/10000)}.${(int)(mcVersion/100)%100}" + (mcVersion%100==0 ? '' : ".${mcVersion%100}") diff --git a/root.gradle.kts b/root.gradle.kts index 88e23880..07a56fa3 100755 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -3,7 +3,7 @@ import java.io.ByteArrayOutputStream plugins { id("fabric-loom") version "0.5-SNAPSHOT" apply false - id("com.replaymod.preprocess") version "7c4f90e" + id("com.replaymod.preprocess") version "3d85a00" id("com.github.hierynomus.license") version "0.15.0" } diff --git a/src/main/java/com/replaymod/compat/shaders/ShaderBeginRender.java b/src/main/java/com/replaymod/compat/shaders/ShaderBeginRender.java index fd7048be..8a782e8b 100644 --- a/src/main/java/com/replaymod/compat/shaders/ShaderBeginRender.java +++ b/src/main/java/com/replaymod/compat/shaders/ShaderBeginRender.java @@ -8,8 +8,6 @@ import net.minecraft.client.MinecraftClient; import java.lang.reflect.InvocationTargetException; -import static com.replaymod.core.versions.MCVer.getRenderPartialTicks; - public class ShaderBeginRender extends EventRegistrations { private final MinecraftClient mc = MinecraftClient.getInstance(); @@ -36,7 +34,7 @@ public class ShaderBeginRender extends EventRegistrations { //#if MC>=11400 mc.gameRenderer.getCamera(), //#endif - getRenderPartialTicks(), 0); + mc.getTickDelta(), 0); } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } diff --git a/src/main/java/com/replaymod/core/KeyBindingRegistry.java b/src/main/java/com/replaymod/core/KeyBindingRegistry.java index 9884c9c6..6223717c 100644 --- a/src/main/java/com/replaymod/core/KeyBindingRegistry.java +++ b/src/main/java/com/replaymod/core/KeyBindingRegistry.java @@ -7,7 +7,6 @@ import com.replaymod.core.mixin.KeyBindingAccessor; import de.johni0702.minecraft.gui.utils.EventRegistrations; import com.replaymod.core.events.KeyBindingEventCallback; import com.replaymod.core.events.KeyEventCallback; -import com.replaymod.core.versions.MCVer; import net.minecraft.client.options.KeyBinding; import net.minecraft.util.crash.CrashReport; import net.minecraft.util.crash.CrashReportSection; @@ -121,8 +120,8 @@ public class KeyBindingRegistry extends EventRegistrations { } catch (Throwable cause) { CrashReport crashReport = CrashReport.create(cause, "Handling Key Binding"); CrashReportSection category = crashReport.addElement("Key Binding"); - MCVer.addDetail(category, "Key Binding", () -> binding.name); - MCVer.addDetail(category, "Handler", runnable::toString); + category.add("Key Binding", () -> binding.name); + category.add("Handler", runnable::toString); throw new CrashException(crashReport); } } @@ -139,8 +138,8 @@ public class KeyBindingRegistry extends EventRegistrations { } catch (Throwable cause) { CrashReport crashReport = CrashReport.create(cause, "Handling Raw Key Binding"); CrashReportSection category = crashReport.addElement("Key Binding"); - MCVer.addDetail(category, "Key Code", () -> "" + keyCode); - MCVer.addDetail(category, "Handler", handler::toString); + category.add("Key Code", () -> "" + keyCode); + category.add("Handler", handler::toString); throw new CrashException(crashReport); } } @@ -161,7 +160,12 @@ public class KeyBindingRegistry extends EventRegistrations { } public String getBoundKey() { - return MCVer.getBoundKey(keyBinding); + try { + return keyBinding.getBoundKeyLocalizedText().getString(); + } catch (ArrayIndexOutOfBoundsException e) { + // Apparently windows likes to press strange keys, see https://www.replaymod.com/forum/thread/55 + return "Unknown"; + } } public boolean isBound() { diff --git a/src/main/java/com/replaymod/core/ReplayMod.java b/src/main/java/com/replaymod/core/ReplayMod.java index ba1805b2..99a78700 100644 --- a/src/main/java/com/replaymod/core/ReplayMod.java +++ b/src/main/java/com/replaymod/core/ReplayMod.java @@ -22,15 +22,15 @@ import com.replaymod.simplepathing.ReplayModSimplePathing; import de.johni0702.minecraft.gui.container.GuiScreen; import net.minecraft.client.MinecraftClient; import net.minecraft.client.options.Option; -import net.minecraft.util.Identifier; import net.minecraft.resource.DirectoryResourcePack; -import net.minecraft.text.Text; -import net.minecraft.text.Style; import net.minecraft.text.LiteralText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; import net.minecraft.text.TranslatableText; import net.minecraft.util.Formatting; -import org.apache.commons.io.FilenameUtils; +import net.minecraft.util.Identifier; import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; import java.io.ByteArrayInputStream; import java.io.File; @@ -355,6 +355,14 @@ public class ReplayMod implements Module, Scheduler { return backend.getVersion(); } + public String getMinecraftVersion() { + return backend.getMinecraftVersion(); + } + + public boolean isModLoaded(String id) { + return backend.isModLoaded(id); + } + public MinecraftClient getMinecraft() { return mc; } diff --git a/src/main/java/com/replaymod/core/ReplayModBackend.java b/src/main/java/com/replaymod/core/ReplayModBackend.java index 826f10f9..d6313852 100644 --- a/src/main/java/com/replaymod/core/ReplayModBackend.java +++ b/src/main/java/com/replaymod/core/ReplayModBackend.java @@ -18,4 +18,12 @@ public class ReplayModBackend implements ClientModInitializer { .orElseThrow(IllegalStateException::new) .getMetadata().getVersion().toString(); } + + public String getMinecraftVersion() { + return mod.getMinecraft().getGame().getVersion().getName(); + } + + public boolean isModLoaded(String id) { + return FabricLoader.getInstance().isModLoaded(id.toLowerCase()); + } } diff --git a/src/main/java/com/replaymod/core/utils/Restrictions.java b/src/main/java/com/replaymod/core/utils/Restrictions.java index 02c3eb3e..359eaf77 100644 --- a/src/main/java/com/replaymod/core/utils/Restrictions.java +++ b/src/main/java/com/replaymod/core/utils/Restrictions.java @@ -10,8 +10,6 @@ import net.minecraft.util.Identifier; //$$ import io.netty.buffer.Unpooled; //#endif -import static com.replaymod.core.versions.MCVer.readString; - /** * Restrictions set by the server, * @see Replay Restrictions Gist @@ -34,7 +32,7 @@ public class Restrictions { //$$ PacketBuffer buffer = new PacketBuffer(Unpooled.wrappedBuffer(packet.func_149168_d())); //#endif while (buffer.isReadable()) { - String name = readString(buffer, 64); + String name = buffer.readString(64); boolean active = buffer.readBoolean(); // if ("no_xray".equals(name)) { // noXray = active; diff --git a/src/main/java/com/replaymod/core/versions/BufferBuilder.java b/src/main/java/com/replaymod/core/versions/BufferBuilder.java new file mode 100644 index 00000000..743815c4 --- /dev/null +++ b/src/main/java/com/replaymod/core/versions/BufferBuilder.java @@ -0,0 +1 @@ +// 1.7.10 and below diff --git a/src/main/java/com/replaymod/core/versions/GLFW.java b/src/main/java/com/replaymod/core/versions/GLFW.java new file mode 100644 index 00000000..fca4cd6c --- /dev/null +++ b/src/main/java/com/replaymod/core/versions/GLFW.java @@ -0,0 +1 @@ +// 1.12.2 and below diff --git a/src/main/java/com/replaymod/core/versions/MCVer.java b/src/main/java/com/replaymod/core/versions/MCVer.java index 854c4a8f..73b77d47 100644 --- a/src/main/java/com/replaymod/core/versions/MCVer.java +++ b/src/main/java/com/replaymod/core/versions/MCVer.java @@ -1,45 +1,19 @@ package com.replaymod.core.versions; import com.replaymod.core.mixin.GuiScreenAccessor; -import com.replaymod.core.mixin.MinecraftAccessor; -import com.replaymod.render.mixin.MainWindowAccessor; import com.replaymod.replaystudio.protocol.PacketTypeRegistry; import com.replaymod.replaystudio.us.myles.ViaVersion.api.protocol.ProtocolVersion; import com.replaymod.replaystudio.us.myles.ViaVersion.packets.State; -import de.johni0702.minecraft.gui.utils.NonNull; -import de.johni0702.minecraft.gui.utils.lwjgl.Dimension; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.options.KeyBinding; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.client.render.Tessellator; -import net.minecraft.client.render.entity.EntityRenderDispatcher; -import net.minecraft.client.model.ModelPart; -import net.minecraft.util.crash.CrashReportSection; -import net.minecraft.entity.Entity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.util.Identifier; import net.minecraft.util.Util; -import net.minecraft.util.math.MathHelper; -import net.minecraft.world.World; -import net.minecraft.world.chunk.WorldChunk; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; //#if MC>=11600 import net.minecraft.resource.ResourcePackSource; //#endif -//#if MC>=11500 -import net.minecraft.client.model.ModelPart.Cuboid; -import java.util.ArrayList; -//#else -//$$ import net.minecraft.client.model.Box; -//#endif - //#if MC>=11400 -import com.replaymod.core.mixin.AbstractButtonWidgetAccessor; +import com.replaymod.render.mixin.MainWindowAccessor; import net.minecraft.SharedConstants; import net.minecraft.client.gl.Framebuffer; import net.minecraft.client.gui.widget.ButtonWidget; @@ -62,20 +36,14 @@ import net.minecraft.text.TranslatableText; //#if FABRIC>=1 //#else -//$$ import net.minecraft.entity.LivingEntity; -//$$ import net.minecraftforge.client.event.GuiScreenEvent; -//$$ import net.minecraftforge.client.event.RenderGameOverlayEvent; -//$$ import net.minecraftforge.client.event.RenderLivingEvent; //$$ import net.minecraftforge.common.MinecraftForge; //$$ import net.minecraftforge.eventbus.api.IEventBus; //#endif //#if MC>=11400 -import net.minecraft.client.util.Window; import net.minecraft.client.util.InputUtil; import org.lwjgl.glfw.GLFW; //#else -//$$ import net.minecraft.client.gui.ScaledResolution; //$$ import net.minecraft.client.resources.ResourcePackRepository; //$$ import net.minecraftforge.fml.client.FMLClientHandler; //$$ import org.apache.logging.log4j.LogManager; @@ -84,28 +52,18 @@ import org.lwjgl.glfw.GLFW; //$$ import java.io.IOException; //#endif -//#if MC>=11400 -import net.minecraft.client.sound.PositionedSoundInstance; -//#else -//$$ import net.minecraft.client.audio.PositionedSoundRecord; -//#endif - //#if MC>=10904 import com.replaymod.render.blend.mixin.ParticleAccessor; import net.minecraft.client.particle.Particle; -import net.minecraft.sound.SoundEvent; import net.minecraft.util.math.Vec3d; //#endif //#if MC>=10809 -import net.minecraft.client.render.VertexFormats; //#else //$$ import net.minecraftforge.fml.common.FMLCommonHandler; //#endif //#if MC>=10800 -import net.minecraft.client.render.BufferBuilder; -import com.mojang.blaze3d.platform.GlStateManager; import net.minecraft.client.render.VertexFormat; import net.minecraft.client.render.VertexFormatElement; //#if MC<11500 @@ -113,28 +71,17 @@ import net.minecraft.client.render.VertexFormatElement; //#endif //#else //$$ import com.replaymod.core.mixin.ResourcePackRepositoryAccessor; -//$$ import com.google.common.util.concurrent.Futures; //$$ import io.netty.handler.codec.DecoderException; +//$$ import net.minecraft.client.renderer.entity.RenderManager; //$$ import net.minecraft.client.resources.FileResourcePack; +//$$ import net.minecraft.network.PacketBuffer; //$$ //$$ import static org.lwjgl.opengl.GL11.*; //#endif -//#if FABRIC>=1 -import net.fabricmc.loader.api.FabricLoader; -//#else -//#if MC>=11400 -//$$ import net.minecraftforge.fml.ModList; -//#else -//$$ import net.minecraftforge.fml.common.Loader; -//#endif -//#endif - import java.io.File; import java.net.URI; -import java.util.Collection; import java.util.List; -import java.util.concurrent.Callable; import java.util.function.Consumer; import java.util.Optional; @@ -142,8 +89,6 @@ import java.util.Optional; * Abstraction over things that have changed between different MC versions. */ public class MCVer { - private static Logger LOGGER = LogManager.getLogger(); - //#if FABRIC<=0 //$$ public static IEventBus FORGE_BUS = MinecraftForge.EVENT_BUS; //#if MC>=10809 @@ -153,18 +98,6 @@ public class MCVer { //#endif //#endif - public static boolean isModLoaded(String id) { - //#if FABRIC>=1 - return FabricLoader.getInstance().isModLoaded(id.toLowerCase()); - //#else - //#if MC>=11400 - //$$ return ModList.get().isLoaded(id.toLowerCase()); - //#else - //$$ return Loader.isModLoaded(id); - //#endif - //#endif - } - public static int getProtocolVersion() { //#if MC>=11400 return SharedConstants.getGameVersion().getProtocolVersion(); @@ -180,38 +113,6 @@ public class MCVer { ); } - public static String getMinecraftVersion() { - //#if MC>=11400 - return getMinecraft().getGame().getVersion().getName(); - //#else - //$$ return Loader.MC_VERSION; - //#endif - } - - public static void addDetail(CrashReportSection category, String name, Callable callable) { - //#if MC>=10904 - //#if MC>=11200 - category.add(name, callable::call); - //#else - //$$ category.setDetail(name, callable::call); - //#endif - //#else - //$$ category.addCrashSectionCallable(name, callable); - //#endif - } - - public static Dimension getMainWindowSize(MinecraftClient mc) { - return new Dimension( - //#if MC>=11400 - getWindow(mc).getFramebufferWidth(), - getWindow(mc).getFramebufferHeight() - //#else - //$$ mc.displayWidth, - //$$ mc.displayHeight - //#endif - ); - } - public static void resizeMainWindow(MinecraftClient mc, int width, int height) { //#if MC>=11400 Framebuffer fb = mc.getFramebuffer(); @@ -219,7 +120,7 @@ public class MCVer { fb.resize(width, height, false); } //noinspection ConstantConditions - MainWindowAccessor mainWindow = (MainWindowAccessor) (Object) getWindow(mc); + MainWindowAccessor mainWindow = (MainWindowAccessor) (Object) mc.getWindow(); mainWindow.setFramebufferWidth(width); mainWindow.setFramebufferHeight(height); //#if MC>=11500 @@ -232,263 +133,13 @@ public class MCVer { //#endif } - public static double Entity_getX(Entity entity) { - //#if MC>=11500 - return entity.getX(); - //#else - //$$ return entity.x; - //#endif - } - - public static double Entity_getY(Entity entity) { - //#if MC>=11500 - return entity.getY(); - //#else - //$$ return entity.y; - //#endif - } - - public static double Entity_getZ(Entity entity) { - //#if MC>=11500 - return entity.getZ(); - //#else - //$$ return entity.z; - //#endif - } - - public static void Entity_setPos(Entity entity, double x, double y, double z) { - //#if MC>=11500 - entity.setPos(x, y, z); - //#else - //$$ entity.x = x; - //$$ entity.y = y; - //$$ entity.z = z; - //#endif - } - - //#if MC>=11400 - public static void width(AbstractButtonWidget button, int value) { - button.setWidth(value); - } - - public static int width(AbstractButtonWidget button) { - return button.getWidth(); - } - - public static int height(AbstractButtonWidget button) { - return ((AbstractButtonWidgetAccessor) button).getHeight(); - } - //#else - //$$ public static void width(GuiButton button, int value) { - //$$ button.width = value; - //$$ } - //$$ - //$$ public static int width(GuiButton button) { - //$$ return button.width; - //$$ } - //$$ - //$$ public static int height(GuiButton button) { - //$$ return button.height; - //$$ } - //#endif - - //#if FABRIC<=0 - //#if MC>=11400 - //$$ public static void addButton(GuiScreenEvent.InitGuiEvent event, Widget button) { - //$$ event.addWidget(button); - //$$ } - //$$ - //$$ public static void removeButton(GuiScreenEvent.InitGuiEvent event, Widget button) { - //$$ event.removeWidget(button); - //$$ } - //$$ - //$$ public static List getButtonList(GuiScreenEvent.InitGuiEvent event) { - //$$ return event.getWidgetList(); - //$$ } - //$$ - //$$ public static Widget getButton(GuiScreenEvent.ActionPerformedEvent event) { - //$$ return event.getButton(); - //$$ } - //#else - //$$ public static void addButton(GuiScreenEvent.InitGuiEvent event, GuiButton button) { - //#if MC>=11400 - //$$ event.addButton(button); - //#else - //$$ getButtonList(event).add(button); - //#endif - //$$ } - //$$ - //$$ public static void removeButton(GuiScreenEvent.InitGuiEvent event, GuiButton button) { - //#if MC>=11400 - //$$ event.removeButton(button); - //#else - //$$ getButtonList(event).remove(button); - //#endif - //$$ } - //$$ - //$$ @SuppressWarnings("unchecked") - //$$ public static List getButtonList(GuiScreenEvent.InitGuiEvent event) { - //#if MC>=10904 - //$$ return event.getButtonList(); - //#else - //$$ return event.buttonList; - //#endif - //$$ } - //$$ - //$$ public static GuiButton getButton(GuiScreenEvent.ActionPerformedEvent event) { - //#if MC>=10904 - //$$ return event.getButton(); - //#else - //$$ return event.button; - //#endif - //$$ } - //#endif - //$$ - //$$ public static Screen getGui(GuiScreenEvent event) { - //#if MC>=10904 - //$$ return event.getGui(); - //#else - //$$ return event.gui; - //#endif - //$$ } - //$$ - //$$ public static LivingEntity getEntity(RenderLivingEvent event) { - //#if MC>=10904 - //$$ return event.getEntity(); - //#else - //$$ return event.entity; - //#endif - //$$ } - //#endif - - public static String readString(PacketByteBuf buffer, int max) { - //#if MC>=10800 - return buffer.readString(max); - //#else - //$$ try { - //$$ return buffer.readStringFromBuffer(max); - //$$ } catch (IOException e) { - //$$ throw new DecoderException(e); - //$$ } - //#endif - } - - //#if FABRIC<=0 - //$$ public static RenderGameOverlayEvent.ElementType getType(RenderGameOverlayEvent event) { - //#if MC>=10904 - //$$ return event.getType(); - //#else - //$$ return event.type; - //#endif - //$$ } - //#endif - - //#if MC>=10800 - public static Entity getRenderViewEntity(MinecraftClient mc) { - return mc.getCameraEntity(); - } - //#else - //$$ public static EntityLivingBase getRenderViewEntity(Minecraft mc) { - //$$ return mc.renderViewEntity; - //$$ } - //#endif - - //#if MC>=10800 - public static void setRenderViewEntity(MinecraftClient mc, Entity entity) { - mc.setCameraEntity(entity); - } - //#else - //$$ public static void setRenderViewEntity(Minecraft mc, EntityLivingBase entity) { - //$$ mc.renderViewEntity = entity; - //$$ } - //#endif - - public static Entity getRiddenEntity(Entity ridden) { - //#if MC>=10904 - return ridden.getVehicle(); - //#else - //$$ return ridden.ridingEntity; - //#endif - } - - public static Iterable loadedEntityList(ClientWorld world) { - //#if MC>=11400 - return world.getEntities(); - //#else - //$$ return world.loadedEntityList; - //#endif - } - - @SuppressWarnings("unchecked") - public static Collection[] getEntityLists(WorldChunk chunk) { - //#if MC>=10800 - return chunk.getEntitySectionArray(); - //#else - //$$ return chunk.entityLists; - //#endif - } - - @SuppressWarnings("unchecked") - //#if MC>=11500 - public static List cubeList(ModelPart modelRenderer) { - return new ArrayList<>(); // FIXME 1.15 - } - //#else - //$$ public static List cubeList(ModelPart modelRenderer) { - //$$ return modelRenderer.boxes; - //$$ } - //#endif - - @SuppressWarnings("unchecked") - public static List playerEntities(World world) { - //#if MC>=11400 - return (List) world.getPlayers(); - //#else - //$$ return world.playerEntities; - //#endif - } - - public static boolean isOnMainThread() { - //#if MC>=11400 - return getMinecraft().isOnThread(); - //#else - //$$ return getMinecraft().isCallingFromMinecraftThread(); - //#endif - } - - public static void scheduleOnMainThread(Runnable runnable) { - //#if MC>=11400 - getMinecraft().send(runnable); - //#else - //$$ getMinecraft().addScheduledTask(runnable); - //#endif - } - - //#if MC>=11400 - public static @NonNull Window getWindow(MinecraftClient mc) { - //#if MC>=11500 - return mc.getWindow(); - //#else - //$$ return mc.window; - //#endif - } - //#else - //$$ public static @NonNull MainWindowAccessor getWindow(Minecraft mc) { - //$$ return (MainWindowAccessor) mc; - //$$ } - //#endif - - //#if MC>=11400 - public static Window newScaledResolution(MinecraftClient mc) { - return getWindow(mc); - } - //#else - //$$ public static ScaledResolution newScaledResolution(Minecraft mc) { - //#if MC>=10809 - //$$ return new ScaledResolution(mc); - //#else - //$$ return new ScaledResolution(mc, mc.displayWidth, mc.displayHeight); - //#endif + //#if MC<10800 + //$$ public static String tryReadString(PacketBuffer buffer, int max) { + //$$ try { + //$$ return buffer.readStringFromBuffer(max); + //$$ } catch (IOException e) { + //$$ throw new DecoderException(e); + //$$ } //$$ } //#endif @@ -549,69 +200,6 @@ public class MCVer { //#endif } - //#if MC>=10800 - public static BufferBuilder Tessellator_getBufferBuilder() { - return Tessellator.getInstance().getBuffer(); - } - //#else - //$$ public static Tessellator Tessellator_getBufferBuilder() { - //$$ return Tessellator.instance; - //$$ } - //#endif - - public static void BufferBuilder_beginPosCol(int mode) { - Tessellator_getBufferBuilder().begin( - mode - //#if MC>=10809 - , VertexFormats.POSITION_COLOR - //#endif - ); - } - - public static void BufferBuilder_addPosCol(double x, double y, double z, int r, int g, int b, int a) { - //#if MC>=10809 - Tessellator_getBufferBuilder().vertex(x, y, z).color(r, g, b, a).next(); - //#else - //$$ Tessellator_getBufferBuilder().setColorRGBA(r, g, b, a); - //$$ Tessellator_getBufferBuilder().addVertex(x, y, z); - //#endif - } - - public static void BufferBuilder_beginPosTex(int mode) { - Tessellator_getBufferBuilder().begin( - mode - //#if MC>=10809 - , VertexFormats.POSITION_TEXTURE - //#endif - ); - } - - public static void BufferBuilder_addPosTex(double x, double y, double z, float u, float v) { - //#if MC>=10809 - Tessellator_getBufferBuilder().vertex(x, y, z).texture(u, v).next(); - //#else - //$$ Tessellator_getBufferBuilder().addVertexWithUV(x, y, z, u, v); - //#endif - } - - public static void BufferBuilder_beginPosTexCol(int mode) { - Tessellator_getBufferBuilder().begin( - mode - //#if MC>=10809 - , VertexFormats.POSITION_TEXTURE_COLOR - //#endif - ); - } - - public static void BufferBuilder_addPosTexCol(double x, double y, double z, float u, float v, int r, int g, int b, int a) { - //#if MC>=10809 - Tessellator_getBufferBuilder().vertex(x, y, z).texture(u, v).color(r, g, b, a).next(); - //#else - //$$ Tessellator_getBufferBuilder().setColorRGBA(r, g, b, a); - //$$ Tessellator_getBufferBuilder().addVertexWithUV(x, y, z, u, v); - //#endif - } - //#if MC>=10800 @SuppressWarnings("unchecked") public static List getElements(VertexFormat vertexFormat) { @@ -619,30 +207,16 @@ public class MCVer { } //#endif - public static Tessellator Tessellator_getInstance() { - //#if MC>=10800 - return Tessellator.getInstance(); - //#else - //$$ return Tessellator.instance; - //#endif - } - - public static EntityRenderDispatcher getRenderManager() { - //#if MC>=10800 - return getMinecraft().getEntityRenderDispatcher(); - //#else - //$$ return RenderManager.instance; - //#endif - } + //#if MC<10800 + //$$ public static RenderManager getRenderManager(@SuppressWarnings("unused") Minecraft mc) { + //$$ return RenderManager.instance; + //$$ } + //#endif public static MinecraftClient getMinecraft() { return MinecraftClient.getInstance(); } - public static float getRenderPartialTicks() { - return ((MinecraftAccessor) getMinecraft()).getTimer().tickDelta; - } - public static void addButton( Screen screen, //#if MC>=11400 @@ -719,26 +293,6 @@ public class MCVer { //#endif } - public static void bindTexture(Identifier texture) { - //#if MC>=11500 - getMinecraft().getTextureManager().bindTexture(texture); - //#else - //#if MC>=11400 - //$$ getMinecraft().getTextureManager().bindTexture(texture); - //#else - //$$ getMinecraft().renderEngine.bindTexture(texture); - //#endif - //#endif - } - - public static float cos(float val) { - return MathHelper.cos(val); - } - - public static float sin(float val) { - return MathHelper.sin(val); - } - //#if MC>=10904 // TODO: this can be inlined once https://github.com/SpongePowered/Mixin/issues/305 is fixed public static Vec3d getPosition(Particle particle, float partialTicks) { @@ -781,51 +335,20 @@ public class MCVer { } public static void openURL(URI url) { - //#if MC>=11400 //#if MC>=11400 Util.getOperatingSystem().open(url); //#else - //$$ Util.getOSType().openURI(url); - //#endif - //#else //$$ try { //$$ Desktop.getDesktop().browse(url); //$$ } catch (Throwable e) { - //$$ LOGGER.error("Failed to open URL: ", e); + //$$ LogManager.getLogger().error("Failed to open URL: ", e); //$$ } //#endif } - public static String getBoundKey(KeyBinding keyBinding) { - try { - //#if MC>=11600 - return keyBinding.getBoundKeyLocalizedText().getString(); - //#else - //#if MC>=11400 - //$$ return keyBinding.getLocalizedName(); - //#else - //$$ return Keyboard.getKeyName(keyBinding.getKeyCode()); - //#endif - //#endif - } catch (ArrayIndexOutOfBoundsException e) { - // Apparently windows likes to press strange keys, see https://www.replaymod.com/forum/thread/55 - return "Unknown"; - } - } - - 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<10900 + //$$ public static class SoundEvent {} + //#endif //#if MC>=11400 private static Boolean hasOptifine; diff --git a/src/main/java/com/replaymod/core/versions/Patterns.java b/src/main/java/com/replaymod/core/versions/Patterns.java new file mode 100644 index 00000000..65570e88 --- /dev/null +++ b/src/main/java/com/replaymod/core/versions/Patterns.java @@ -0,0 +1,376 @@ +package com.replaymod.core.versions; + +import com.replaymod.gradle.remap.Pattern; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.options.KeyBinding; +import net.minecraft.client.texture.TextureManager; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.client.render.Tessellator; +import net.minecraft.client.render.entity.EntityRenderDispatcher; +import net.minecraft.client.sound.PositionedSoundInstance; +import net.minecraft.util.crash.CrashReportSection; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.util.Identifier; +import net.minecraft.world.World; +import net.minecraft.world.chunk.WorldChunk; + +//#if MC>=11400 +import net.minecraft.client.gui.widget.AbstractButtonWidget; +import net.minecraft.client.util.Window; +//#else +//$$ import net.minecraft.client.gui.GuiButton; +//#endif + +//#if MC>=10904 +import net.minecraft.sound.SoundEvent; +import net.minecraft.util.crash.CrashCallable; +//#else +//$$ import java.util.concurrent.Callable; +//#endif + +//#if MC>=10809 +import net.minecraft.client.render.VertexFormats; +//#else +//#endif + +//#if MC>=10800 +import net.minecraft.client.render.BufferBuilder; +//#else +//$$ import net.minecraft.entity.EntityLivingBase; +//#endif + +import java.util.Collection; +import java.util.List; + +class Patterns { + //#if MC>=10904 + @Pattern + private static void addCrashCallable(CrashReportSection category, String name, CrashCallable callable) { + //#if MC>=11200 + category.add(name, callable); + //#else + //$$ category.setDetail(name, callable); + //#endif + } + //#else + //$$ @Pattern + //$$ private static void addCrashCallable(CrashReportCategory category, String name, Callable callable) { + //$$ category.addCrashSectionCallable(name, callable); + //$$ } + //#endif + + @Pattern + private static double Entity_getX(Entity entity) { + //#if MC>=11500 + return entity.getX(); + //#else + //$$ return entity.x; + //#endif + } + + @Pattern + private static double Entity_getY(Entity entity) { + //#if MC>=11500 + return entity.getY(); + //#else + //$$ return entity.y; + //#endif + } + + @Pattern + private static double Entity_getZ(Entity entity) { + //#if MC>=11500 + return entity.getZ(); + //#else + //$$ return entity.z; + //#endif + } + + @Pattern + private static void Entity_setPos(Entity entity, double x, double y, double z) { + //#if MC>=11500 + entity.setPos(x, y, z); + //#else + //$$ { net.minecraft.entity.Entity self = entity; self.x = x; self.y = y; self.z = z; } + //#endif + } + + //#if MC>=11400 + @Pattern + private static void setWidth(AbstractButtonWidget button, int value) { + button.setWidth(value); + } + + @Pattern + private static int getWidth(AbstractButtonWidget button) { + return button.getWidth(); + } + + @Pattern + private static int getHeight(AbstractButtonWidget button) { + //#if MC>=11600 + return button.getHeight(); + //#else + //$$ return ((com.replaymod.core.mixin.AbstractButtonWidgetAccessor) button).getHeight(); + //#endif + } + //#else + //$$ @Pattern + //$$ private static void setWidth(GuiButton button, int value) { + //$$ button.width = value; + //$$ } + //$$ + //$$ @Pattern + //$$ private static int getWidth(GuiButton button) { + //$$ return button.width; + //$$ } + //$$ + //$$ @Pattern + //$$ private static int getHeight(GuiButton button) { + //$$ return button.height; + //$$ } + //#endif + + @Pattern + private static String readString(PacketByteBuf buffer, int max) { + //#if MC>=10800 + return buffer.readString(max); + //#else + //$$ return com.replaymod.core.versions.MCVer.tryReadString(buffer, max); + //#endif + } + + @Pattern + //#if MC>=10800 + private static Entity getRenderViewEntity(MinecraftClient mc) { + return mc.getCameraEntity(); + } + //#else + //$$ private static EntityLivingBase getRenderViewEntity(Minecraft mc) { + //$$ return mc.renderViewEntity; + //$$ } + //#endif + + @Pattern + //#if MC>=10800 + private static void setRenderViewEntity(MinecraftClient mc, Entity entity) { + mc.setCameraEntity(entity); + } + //#else + //$$ private static void setRenderViewEntity(Minecraft mc, EntityLivingBase entity) { + //$$ mc.renderViewEntity = entity; + //$$ } + //#endif + + @Pattern + private static Entity getVehicle(Entity passenger) { + //#if MC>=10904 + return passenger.getVehicle(); + //#else + //$$ return passenger.ridingEntity; + //#endif + } + + @Pattern + private static Iterable loadedEntityList(ClientWorld world) { + //#if MC>=11400 + return world.getEntities(); + //#else + //#if MC>=10809 + //$$ return world.loadedEntityList; + //#else + //$$ return ((java.util.List) world.loadedEntityList); + //#endif + //#endif + } + + @Pattern + private static Collection[] getEntitySectionArray(WorldChunk chunk) { + //#if MC>=10800 + return chunk.getEntitySectionArray(); + //#else + //$$ return chunk.entityLists; + //#endif + } + + @Pattern + private static List playerEntities(World world) { + //#if MC>=11400 + return world.getPlayers(); + //#elseif MC>=10809 + //$$ return world.playerEntities; + //#else + //$$ return ((List) world.playerEntities); + //#endif + } + + @Pattern + private static boolean isOnMainThread(MinecraftClient mc) { + //#if MC>=11400 + return mc.isOnThread(); + //#else + //$$ return mc.isCallingFromMinecraftThread(); + //#endif + } + + @Pattern + private static void scheduleOnMainThread(MinecraftClient mc, Runnable runnable) { + //#if MC>=11400 + mc.send(runnable); + //#else + //$$ mc.addScheduledTask(runnable); + //#endif + } + + @Pattern + private static Window getWindow(MinecraftClient mc) { + //#if MC>=11500 + return mc.getWindow(); + //#elseif MC>=11400 + //$$ return mc.window; + //#else + //$$ return new com.replaymod.core.versions.Window(mc); + //#endif + } + + @Pattern + private static BufferBuilder Tessellator_getBuffer(Tessellator tessellator) { + //#if MC>=10800 + return tessellator.getBuffer(); + //#else + //$$ return new BufferBuilder(tessellator); + //#endif + } + + @Pattern + private static void BufferBuilder_beginPosCol(BufferBuilder buffer, int mode) { + //#if MC>=10809 + buffer.begin(mode, VertexFormats.POSITION_COLOR); + //#else + //$$ buffer.startDrawing(mode /* POSITION_COLOR */); + //#endif + } + + @Pattern + private static void BufferBuilder_addPosCol(BufferBuilder buffer, double x, double y, double z, int r, int g, int b, int a) { + //#if MC>=10809 + buffer.vertex(x, y, z).color(r, g, b, a).next(); + //#else + //$$ { WorldRenderer $buffer = buffer; double $x = x; double $y = y; double $z = z; $buffer.setColorRGBA(r, g, b, a); $buffer.addVertex($x, $y, $z); } + //#endif + } + + @Pattern + private static void BufferBuilder_beginPosTex(BufferBuilder buffer, int mode) { + //#if MC>=10809 + buffer.begin(mode, VertexFormats.POSITION_TEXTURE); + //#else + //$$ buffer.startDrawing(mode /* POSITION_TEXTURE */); + //#endif + } + + @Pattern + private static void BufferBuilder_addPosTex(BufferBuilder buffer, double x, double y, double z, float u, float v) { + //#if MC>=10809 + buffer.vertex(x, y, z).texture(u, v).next(); + //#else + //$$ buffer.addVertexWithUV(x, y, z, u, v); + //#endif + } + + @Pattern + private static void BufferBuilder_beginPosTexCol(BufferBuilder buffer, int mode) { + //#if MC>=10809 + buffer.begin(mode, VertexFormats.POSITION_TEXTURE_COLOR); + //#else + //$$ buffer.startDrawing(mode /* POSITION_TEXTURE_COLOR */); + //#endif + } + + @Pattern + private static void BufferBuilder_addPosTexCol(BufferBuilder buffer, double x, double y, double z, float u, float v, int r, int g, int b, int a) { + //#if MC>=10809 + buffer.vertex(x, y, z).texture(u, v).color(r, g, b, a).next(); + //#else + //$$ { WorldRenderer $buffer = buffer; double $x = x; double $y = y; double $z = z; float $u = u; float $v = v; $buffer.setColorRGBA(r, g, b, a); $buffer.addVertexWithUV($x, $y, $z, $u, $v); } + //#endif + } + + @Pattern + private static Tessellator Tessellator_getInstance() { + //#if MC>=10800 + return Tessellator.getInstance(); + //#else + //$$ return Tessellator.instance; + //#endif + } + + @Pattern + private static EntityRenderDispatcher getEntityRenderDispatcher(MinecraftClient mc) { + //#if MC>=10800 + return mc.getEntityRenderDispatcher(); + //#else + //$$ return com.replaymod.core.versions.MCVer.getRenderManager(mc); + //#endif + } + + @Pattern + private static float getCameraYaw(EntityRenderDispatcher dispatcher) { + //#if MC>=11500 + return dispatcher.camera.getYaw(); + //#else + //$$ return dispatcher.cameraYaw; + //#endif + } + + @Pattern + private static float getCameraPitch(EntityRenderDispatcher dispatcher) { + //#if MC>=11500 + return dispatcher.camera.getPitch(); + //#else + //$$ return dispatcher.cameraPitch; + //#endif + } + + @Pattern + private static float getRenderPartialTicks(MinecraftClient mc) { + //#if MC>=10900 + return mc.getTickDelta(); + //#else + //$$ return ((com.replaymod.core.mixin.MinecraftAccessor) mc).getTimer().renderPartialTicks; + //#endif + } + + @Pattern + private static TextureManager getTextureManager(MinecraftClient mc) { + //#if MC>=11400 + return mc.getTextureManager(); + //#else + //$$ return mc.renderEngine; + //#endif + } + + @Pattern + private static String getBoundKeyName(KeyBinding keyBinding) { + //#if MC>=11600 + return keyBinding.getBoundKeyLocalizedText().getString(); + //#elseif MC>=11400 + //$$ return keyBinding.getLocalizedName(); + //#else + //$$ return org.lwjgl.input.Keyboard.getKeyName(keyBinding.getKeyCode()); + //#endif + } + + @Pattern + private static PositionedSoundInstance master(Identifier sound, float pitch) { + //#if MC>=10900 + return PositionedSoundInstance.master(new SoundEvent(sound), pitch); + //#elseif MC>=10800 + //$$ return PositionedSoundRecord.create(sound, pitch); + //#else + //$$ return PositionedSoundRecord.createPositionedSoundRecord(sound, pitch); + //#endif + } +} diff --git a/src/main/java/com/replaymod/core/versions/Window.java b/src/main/java/com/replaymod/core/versions/Window.java new file mode 100644 index 00000000..fca4cd6c --- /dev/null +++ b/src/main/java/com/replaymod/core/versions/Window.java @@ -0,0 +1 @@ +// 1.12.2 and below diff --git a/src/main/java/com/replaymod/core/versions/forge/Patterns.java b/src/main/java/com/replaymod/core/versions/forge/Patterns.java new file mode 100644 index 00000000..6b1e174a --- /dev/null +++ b/src/main/java/com/replaymod/core/versions/forge/Patterns.java @@ -0,0 +1 @@ +// 1.12.2 and before diff --git a/src/main/java/com/replaymod/extras/OpenEyeExtra.java b/src/main/java/com/replaymod/extras/OpenEyeExtra.java index 9c7b6941..688c3e9b 100644 --- a/src/main/java/com/replaymod/extras/OpenEyeExtra.java +++ b/src/main/java/com/replaymod/extras/OpenEyeExtra.java @@ -28,20 +28,20 @@ import static com.replaymod.core.utils.Utils.SSL_SOCKET_FACTORY; import static com.replaymod.extras.ReplayModExtras.LOGGER; public class OpenEyeExtra implements Extra { - private static final String DOWNLOAD_URL = "https://www.replaymod.com/dl/openeye/" + MCVer.getMinecraftVersion(); - + private URL url; private ReplayMod mod; @Override public void register(ReplayMod mod) throws Exception { this.mod = mod; + this.url = new URL("https://www.replaymod.com/dl/openeye/" + mod.getMinecraftVersion()); - boolean isOpenEyeLoaded = MCVer.isModLoaded("OpenEye"); + boolean isOpenEyeLoaded = mod.isModLoaded("OpenEye"); if (!isOpenEyeLoaded && mod.getSettingsRegistry().get(Setting.ASK_FOR_OPEN_EYE)) { new Thread(() -> { try { LOGGER.trace("Checking for OpenEye availability"); - HttpsURLConnection connection = (HttpsURLConnection) new URL(DOWNLOAD_URL).openConnection(); + HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); connection.setSSLSocketFactory(SSL_SOCKET_FACTORY); connection.setRequestMethod("HEAD"); connection.connect(); @@ -86,10 +86,10 @@ public class OpenEyeExtra implements Extra { GuiPopup popup = new GuiPopup(OfferGui.this); new Thread(() -> { try { - File targetFile = new File(mod.getMinecraft().runDirectory, "mods/" + MCVer.getMinecraftVersion() + "/OpenEye.jar"); + File targetFile = new File(mod.getMinecraft().runDirectory, "mods/" + mod.getMinecraftVersion() + "/OpenEye.jar"); FileUtils.forceMkdir(targetFile.getParentFile()); - HttpsURLConnection connection = (HttpsURLConnection) new URL(DOWNLOAD_URL).openConnection(); + HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); connection.setSSLSocketFactory(SSL_SOCKET_FACTORY); ReadableByteChannel in = Channels.newChannel(connection.getInputStream()); FileChannel out = new FileOutputStream(targetFile).getChannel(); diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java index 54e8d01f..0f38c79d 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java @@ -9,10 +9,9 @@ import com.replaymod.render.rendering.Pipelines; import de.johni0702.minecraft.gui.utils.lwjgl.Dimension; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.util.Window; import net.minecraft.util.crash.CrashReport; -import static com.replaymod.core.versions.MCVer.getMainWindowSize; -import static com.replaymod.core.versions.MCVer.getRenderPartialTicks; import static com.replaymod.core.versions.MCVer.resizeMainWindow; public class ScreenshotRenderer implements RenderInfo { @@ -29,7 +28,9 @@ public class ScreenshotRenderer implements RenderInfo { public boolean renderScreenshot() throws Throwable { try { - Dimension sizeBefore = getMainWindowSize(mc); + Window window = mc.getWindow(); + int widthBefore = window.getFramebufferWidth(); + int heightBefore = window.getFramebufferHeight(); boolean hideGUIBefore = mc.options.hudHidden; mc.options.hudHidden = true; @@ -46,7 +47,7 @@ public class ScreenshotRenderer implements RenderInfo { clrg.uninstall(); mc.options.hudHidden = hideGUIBefore; - resizeMainWindow(mc, sizeBefore.getWidth(), sizeBefore.getHeight()); + resizeMainWindow(mc, widthBefore, heightBefore); return true; } catch (OutOfMemoryError e) { e.printStackTrace(); @@ -75,7 +76,7 @@ public class ScreenshotRenderer implements RenderInfo { @Override public float updateForNextFrame() { framesDone++; - return getRenderPartialTicks(); + return mc.getTickDelta(); } @Override diff --git a/src/main/java/com/replaymod/extras/playeroverview/PlayerOverview.java b/src/main/java/com/replaymod/extras/playeroverview/PlayerOverview.java index 6152e5e3..d5ecb0be 100644 --- a/src/main/java/com/replaymod/extras/playeroverview/PlayerOverview.java +++ b/src/main/java/com/replaymod/extras/playeroverview/PlayerOverview.java @@ -117,7 +117,7 @@ public class PlayerOverview extends EventRegistrations implements Extra { { on(PreRenderHandCallback.EVENT, this::shouldHideHand); } private boolean shouldHideHand() { - Entity view = getRenderViewEntity(module.getCore().getMinecraft()); + Entity view = module.getCore().getMinecraft().getCameraEntity(); return view != null && isHidden(view.getUuid()); } diff --git a/src/main/java/com/replaymod/gradle/remap/Pattern.java b/src/main/java/com/replaymod/gradle/remap/Pattern.java new file mode 100644 index 00000000..c57f51a3 --- /dev/null +++ b/src/main/java/com/replaymod/gradle/remap/Pattern.java @@ -0,0 +1,11 @@ +package com.replaymod.gradle.remap; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.METHOD) +public @interface Pattern { +} diff --git a/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java b/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java index 8ed65093..06783108 100644 --- a/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java +++ b/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java @@ -13,7 +13,6 @@ import net.minecraft.client.util.math.MatrixStack; import static com.replaymod.core.ReplayMod.TEXTURE; import static com.replaymod.core.ReplayMod.TEXTURE_SIZE; -import static com.replaymod.core.versions.MCVer.*; import static com.mojang.blaze3d.platform.GlStateManager.*; /** @@ -44,7 +43,7 @@ public class GuiRecordingOverlay extends EventRegistrations { stack, //#endif text.toUpperCase(), 30, 18 - (fontRenderer.fontHeight / 2), 0xffffffff); - bindTexture(TEXTURE); + mc.getTextureManager().bindTexture(TEXTURE); enableAlphaTest(); GuiRenderer renderer = new MinecraftGuiRenderer(stack); renderer.drawTexturedRect(10, 10, 58, 20, 16, 16, 16, 16, TEXTURE_SIZE, TEXTURE_SIZE); diff --git a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java index 4c638f50..0e90c7eb 100644 --- a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java @@ -138,7 +138,7 @@ public class ConnectionEventHandler { metaData.setCustomServerName(serverName); metaData.setGenerator("ReplayMod v" + ReplayMod.instance.getVersion()); metaData.setDate(System.currentTimeMillis()); - metaData.setMcVersion(MCVer.getMinecraftVersion()); + metaData.setMcVersion(ReplayMod.instance.getMinecraftVersion()); packetListener = new PacketListener(core, outputPath, replayFile, metaData); Channel channel = ((NetworkManagerAccessor) networkManager).getChannel(); channel.pipeline().addBefore(packetHandlerKey, "replay_recorder", packetListener); diff --git a/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java b/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java index 40c6eefe..a04cbee6 100644 --- a/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java @@ -7,6 +7,7 @@ import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.entity.Entity; import net.minecraft.network.packet.s2c.play.BlockBreakingProgressS2CPacket; import net.minecraft.network.packet.s2c.play.EntityAnimationS2CPacket; import net.minecraft.network.packet.s2c.play.EntityAttachS2CPacket; @@ -146,9 +147,9 @@ public class RecordingEventHandler extends EventRegistrations { boolean force = false; if(lastX == null || lastY == null || lastZ == null) { force = true; - lastX = Entity_getX(player); - lastY = Entity_getY(player); - lastZ = Entity_getZ(player); + lastX = player.getX(); + lastY = player.getY(); + lastZ = player.getZ(); } ticksSinceLastCorrection++; @@ -157,13 +158,13 @@ public class RecordingEventHandler extends EventRegistrations { force = true; } - double dx = Entity_getX(player) - lastX; - double dy = Entity_getY(player) - lastY; - double dz = Entity_getZ(player) - lastZ; + double dx = player.getX() - lastX; + double dy = player.getY() - lastY; + double dz = player.getZ() - lastZ; - lastX = Entity_getX(player); - lastY = Entity_getY(player); - lastZ = Entity_getZ(player); + lastX = player.getX(); + lastY = player.getY(); + lastZ = player.getZ(); Packet packet; if (force || Math.abs(dx) > 8.0 || Math.abs(dy) > 8.0 || Math.abs(dz) > 8.0) { @@ -309,18 +310,16 @@ public class RecordingEventHandler extends EventRegistrations { //Leaving Ride - if((!player.isRiding() && lastRiding != -1) || - (player.isRiding() && lastRiding != getRiddenEntity(player).getEntityId())) { - if(!player.isRiding()) { - lastRiding = -1; - } else { - lastRiding = getRiddenEntity(player).getEntityId(); - } + Entity vehicle = player.getVehicle(); + int vehicleId = vehicle == null ? -1 : vehicle.getEntityId(); + if (lastRiding != vehicleId) { + lastRiding = vehicleId; packetListener.save(new EntityAttachS2CPacket( //#if MC<10904 //$$ 0, //#endif - player, getRiddenEntity(player) + player, + vehicle )); } diff --git a/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java index 2212424c..8c1841fc 100644 --- a/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java +++ b/src/main/java/com/replaymod/recording/mixin/MixinNetHandlerPlayClient.java @@ -57,7 +57,7 @@ public abstract class MixinNetHandlerPlayClient { //$$ @Inject(method = "handlePlayerListItem", at=@At("HEAD")) //#endif public void recordOwnJoin(PlayerListS2CPacket packet, CallbackInfo ci) { - if (!MCVer.isOnMainThread()) return; + if (!mcStatic.isOnThread()) return; if (mcStatic.player == null) return; RecordingEventHandler handler = getRecordingEventHandler(); diff --git a/src/main/java/com/replaymod/recording/packet/PacketListener.java b/src/main/java/com/replaymod/recording/packet/PacketListener.java index 83f573cd..78dd21ec 100644 --- a/src/main/java/com/replaymod/recording/packet/PacketListener.java +++ b/src/main/java/com/replaymod/recording/packet/PacketListener.java @@ -163,8 +163,8 @@ public class PacketListener extends ChannelInboundHandlerAdapter { // to happen on the main thread so we can guarantee correct ordering of inbound and inject packets. // Otherwise, injected packets may end up further down the packet stream than they were supposed to and other // inbound packets which may rely on the injected packet would behave incorrectly when played back. - if (!MCVer.isOnMainThread()) { - MCVer.scheduleOnMainThread(() -> save(packet)); + if (!mc.isOnThread()) { + mc.send(() -> save(packet)); return; } try { @@ -488,15 +488,15 @@ public class PacketListener extends ChannelInboundHandlerAdapter { } public void addMarker(String name, int timestamp) { - Entity view = getRenderViewEntity(mc); + Entity view = mc.getCameraEntity(); Marker marker = new Marker(); marker.setName(name); marker.setTime(timestamp); if (view != null) { - marker.setX(Entity_getX(view)); - marker.setY(Entity_getY(view)); - marker.setZ(Entity_getZ(view)); + marker.setX(view.getX()); + marker.setY(view.getY()); + marker.setZ(view.getZ()); marker.setYaw(view.yaw); marker.setPitch(view.pitch); } diff --git a/src/main/java/com/replaymod/render/FFmpegWriter.java b/src/main/java/com/replaymod/render/FFmpegWriter.java index c0067e3a..f4e1381c 100644 --- a/src/main/java/com/replaymod/render/FFmpegWriter.java +++ b/src/main/java/com/replaymod/render/FFmpegWriter.java @@ -126,8 +126,8 @@ public class FFmpegWriter implements FrameConsumer { } CrashReport report = CrashReport.create(t, "Exporting frame"); CrashReportSection exportDetails = report.addElement("Export details"); - MCVer.addDetail(exportDetails, "Export command", settings::getExportCommand); - MCVer.addDetail(exportDetails, "Export args", commandArgs::toString); + exportDetails.add("Export command", settings::getExportCommand); + exportDetails.add("Export args", commandArgs::toString); MCVer.getMinecraft().setCrashReport(report); } finally { channels.values().forEach(it -> ByteBufferPool.release(it.getByteBuffer())); diff --git a/src/main/java/com/replaymod/render/blend/BlendFrameCapturer.java b/src/main/java/com/replaymod/render/blend/BlendFrameCapturer.java index 1047a78b..d9db73ee 100644 --- a/src/main/java/com/replaymod/render/blend/BlendFrameCapturer.java +++ b/src/main/java/com/replaymod/render/blend/BlendFrameCapturer.java @@ -1,6 +1,5 @@ package com.replaymod.render.blend; -import com.replaymod.core.versions.MCVer; import com.replaymod.render.capturer.RenderInfo; import com.replaymod.render.capturer.WorldRenderer; import com.replaymod.render.frame.BitmapFrame; @@ -8,6 +7,7 @@ import com.replaymod.render.rendering.Channel; import com.replaymod.render.rendering.FrameCapturer; import com.replaymod.render.utils.ByteBufferPool; import de.johni0702.minecraft.gui.utils.lwjgl.Dimension; +import net.minecraft.client.MinecraftClient; import java.io.IOException; import java.util.Collections; @@ -37,7 +37,7 @@ public class BlendFrameCapturer implements FrameCapturer { renderInfo.updateForNextFrame(); BlendState.getState().preFrame(framesDone); - worldRenderer.renderWorld(MCVer.getRenderPartialTicks(), null); + worldRenderer.renderWorld(MinecraftClient.getInstance().getTickDelta(), null); BlendState.getState().postFrame(framesDone); BitmapFrame frame = new BitmapFrame(framesDone++, new Dimension(0, 0), 0, ByteBufferPool.allocate(0)); diff --git a/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java b/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java index ebf38b75..49dba018 100644 --- a/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java +++ b/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java @@ -9,6 +9,7 @@ import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f; import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.VertexFormat; import net.minecraft.client.render.VertexFormatElement; +import net.minecraft.client.render.VertexFormats; import org.lwjgl.opengl.GL11; //#if MC>=11500 @@ -82,7 +83,7 @@ public class BlendMeshBuilder if (!wellBehaved) { // In case the calling code finishes with Tessellator.getInstance().draw() - BufferBuilder_beginPosTexCol(mode); + Tessellator.getInstance().getBuffer().begin(mode, VertexFormats.POSITION_TEXTURE_COLOR); } //#if MC>=10809 diff --git a/src/main/java/com/replaymod/render/blend/BlendState.java b/src/main/java/com/replaymod/render/blend/BlendState.java index 0b3333b7..0ef4a29b 100644 --- a/src/main/java/com/replaymod/render/blend/BlendState.java +++ b/src/main/java/com/replaymod/render/blend/BlendState.java @@ -88,7 +88,7 @@ public class BlendState implements Exporter { } catch (IOException e) { CrashReport report = CrashReport.create(e, "Setup of blend exporter"); CrashReportSection category = report.addElement("Exporter"); - addDetail(category, "Exporter", exporter::toString); + category.add("Exporter", exporter::toString); throw new CrashException(report); } } @@ -102,7 +102,7 @@ public class BlendState implements Exporter { } catch (IOException e) { CrashReport report = CrashReport.create(e, "Tear down of blend exporter"); CrashReportSection category = report.addElement("Exporter"); - addDetail(category, "Exporter", exporter::toString); + category.add("Exporter", exporter::toString); throw new CrashException(report); } } @@ -139,8 +139,8 @@ public class BlendState implements Exporter { } catch (IOException e) { CrashReport report = CrashReport.create(e, "Pre frame of blend exporter"); CrashReportSection category = report.addElement("Exporter"); - addDetail(category, "Exporter", exporter::toString); - addDetail(category, "Frame", () -> String.valueOf(frame)); + category.add("Exporter", exporter::toString); + category.add("Frame", () -> String.valueOf(frame)); throw new CrashException(report); } } @@ -154,8 +154,8 @@ public class BlendState implements Exporter { } catch (IOException e) { CrashReport report = CrashReport.create(e, "Post frame of blend exporter"); CrashReportSection category = report.addElement("Exporter"); - addDetail(category, "Exporter", exporter::toString); - addDetail(category, "Frame", () -> String.valueOf(frame)); + category.add("Exporter", exporter::toString); + category.add("Frame", () -> String.valueOf(frame)); throw new CrashException(report); } } diff --git a/src/main/java/com/replaymod/render/blend/exporters/ModelRendererExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ModelRendererExporter.java index 909e7c6e..2320f236 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ModelRendererExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ModelRendererExporter.java @@ -21,7 +21,6 @@ import net.minecraft.client.model.ModelPart; import java.io.IOException; -import static com.replaymod.core.versions.MCVer.*; import static com.replaymod.render.blend.Util.isGlTextureMatrixIdentity; public class ModelRendererExporter implements Exporter { @@ -86,11 +85,13 @@ public class ModelRendererExporter implements Exporter { DMesh mesh = new DMesh(); BlendMeshBuilder builder = new BlendMeshBuilder(mesh); //#if MC>=11500 - for (Cuboid box : cubeList(model)) { - // FIXME 1.15 - } + // FIXME 1.15 + //#elseif MC>=10809 + //$$ for (Box box : model.boxes) { + //$$ box.render(builder, scale); + //$$ } //#else - //$$ for (Box box : cubeList(model)) { + //$$ for (ModelBox box : (java.util.List) model.cubeList) { //$$ box.render(builder, scale); //$$ } //#endif diff --git a/src/main/java/com/replaymod/render/gui/GuiExportFailed.java b/src/main/java/com/replaymod/render/gui/GuiExportFailed.java index b3a8a702..de5e9c0e 100644 --- a/src/main/java/com/replaymod/render/gui/GuiExportFailed.java +++ b/src/main/java/com/replaymod/render/gui/GuiExportFailed.java @@ -19,7 +19,6 @@ import net.minecraft.util.crash.CrashException; import java.util.Arrays; import java.util.function.Consumer; -import static com.replaymod.core.versions.MCVer.addDetail; import static com.replaymod.render.ReplayModRender.LOGGER; public class GuiExportFailed extends GuiScreen { @@ -33,8 +32,8 @@ public class GuiExportFailed extends GuiScreen { // If they haven't, then this is probably a faulty ffmpeg installation and there's nothing we can do CrashReport crashReport = CrashReport.create(e, "Exporting video"); CrashReportSection details = crashReport.addElement("Export details"); - addDetail(details, "Settings", settings::toString); - addDetail(details, "FFmpeg log", e::getLog); + details.add("Settings", settings::toString); + details.add("FFmpeg log", e::getLog); throw new CrashException(crashReport); } else { // If they have, ask them whether it was intentional diff --git a/src/main/java/com/replaymod/render/mixin/MixinCamera.java b/src/main/java/com/replaymod/render/mixin/MixinCamera.java index 63044901..126c3278 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinCamera.java +++ b/src/main/java/com/replaymod/render/mixin/MixinCamera.java @@ -59,7 +59,7 @@ public abstract class MixinCamera { ) { if (getHandler() != null) { //#if MC<11400 - //$$ Entity entity = getRenderViewEntity(getMinecraft()); + //$$ Entity entity = getMinecraft().getRenderViewEntity(); //#endif orgYaw = entity.yaw; orgPitch = entity.pitch; @@ -79,7 +79,7 @@ public abstract class MixinCamera { //#endif if (getHandler() != null) { //#if MC<11400 - //$$ Entity entity = getRenderViewEntity(getMinecraft()); + //$$ Entity entity = getMinecraft().getRenderViewEntity(); //#endif RenderSettings settings = getHandler().getSettings(); if (settings.isStabilizeYaw()) { @@ -117,7 +117,7 @@ public abstract class MixinCamera { ) { if (getHandler() != null) { //#if MC<11400 - //$$ Entity entity = getRenderViewEntity(getMinecraft()); + //$$ Entity entity = getMinecraft().getRenderViewEntity(); //#endif entity.yaw = orgYaw; entity.pitch = orgPitch; diff --git a/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java b/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java index b82e5be6..ddf431ea 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java +++ b/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java @@ -117,7 +117,7 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti } //#else //$$ } else { - //$$ Entity currentEntity = getRenderViewEntity(MCVer.getMinecraft()); + //$$ Entity currentEntity = this.mc.getRenderViewEntity(); //$$ if (currentEntity instanceof EntityPlayer && !(currentEntity instanceof CameraEntity)) { //$$ if (renderPass == 2) { // Need to update render pass //$$ renderPass = replayModRender_handler.data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE ? 1 : 0; diff --git a/src/main/java/com/replaymod/render/rendering/Pipeline.java b/src/main/java/com/replaymod/render/rendering/Pipeline.java index 23c22895..cf7f057d 100644 --- a/src/main/java/com/replaymod/render/rendering/Pipeline.java +++ b/src/main/java/com/replaymod/render/rendering/Pipeline.java @@ -6,14 +6,9 @@ import com.replaymod.render.capturer.WorldRenderer; import com.replaymod.render.frame.BitmapFrame; import com.replaymod.render.processor.GlToAbsoluteDepthProcessor; import net.minecraft.client.MinecraftClient; -import net.minecraft.util.crash.CrashReport; import net.minecraft.util.crash.CrashException; - -//#if MC>=11400 +import net.minecraft.util.crash.CrashReport; import org.lwjgl.glfw.GLFW; -//#else -//$$ import org.lwjgl.opengl.Display; -//#endif import java.util.HashMap; import java.util.Map; @@ -23,9 +18,6 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import static com.replaymod.core.versions.MCVer.getMinecraft; -//#if MC>=11400 -import static com.replaymod.core.versions.MCVer.getWindow; -//#endif public class Pipeline implements Runnable { @@ -72,11 +64,7 @@ public class Pipeline implements Runnable { MinecraftClient mc = MCVer.getMinecraft(); while (!capturer.isDone() && !abort) { - //#if MC>=11400 - if (GLFW.glfwWindowShouldClose(getWindow(mc).getHandle()) || ((MinecraftAccessor) mc).getCrashReporter() != null) { - //#else - //$$ if (Display.isCloseRequested() || ((MinecraftAccessor) mc).getCrashReporter() != null) { - //#endif + if (GLFW.glfwWindowShouldClose(mc.getWindow().getHandle()) || ((MinecraftAccessor) mc).getCrashReporter() != null) { processService.shutdown(); return; } diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index a265e245..4db4a2fc 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -30,10 +30,14 @@ import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; import net.minecraft.client.MinecraftClient; import com.mojang.blaze3d.platform.GLX; import net.minecraft.client.gl.Framebuffer; +import net.minecraft.client.sound.PositionedSoundInstance; +import net.minecraft.client.util.Window; +import net.minecraft.sound.SoundEvent; import net.minecraft.util.Identifier; import net.minecraft.util.crash.CrashException; import net.minecraft.sound.SoundCategory; import net.minecraft.client.render.RenderTickCounter; +import org.lwjgl.glfw.GLFW; //#if MC>=11600 import net.minecraft.client.util.math.MatrixStack; @@ -41,20 +45,16 @@ import net.minecraft.client.util.math.MatrixStack; //#if MC>=11500 import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.util.Window; import org.lwjgl.opengl.GL11; //#endif //#if MC>=11400 import com.replaymod.render.EXRWriter; 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; //$$ import org.lwjgl.opengl.Display; -//$$ import static com.replaymod.core.versions.MCVer.newScaledResolution; //#endif //#if MC>=10800 @@ -80,6 +80,7 @@ import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; public class VideoRenderer implements RenderInfo { + private static final Identifier SOUND_RENDER_SUCCESS = new Identifier("replaymod", "render_success"); private final MinecraftClient mc = MCVer.getMinecraft(); private final RenderSettings settings; private final ReplayHandler replayHandler; @@ -232,7 +233,7 @@ public class VideoRenderer implements RenderInfo { @Override public float updateForNextFrame() { // because the jGui lib uses Minecraft's displayWidth and displayHeight values, update these temporarily - MainWindowAccessor acc = (MainWindowAccessor) (Object) getWindow(mc); + MainWindowAccessor acc = (MainWindowAccessor) (Object) mc.getWindow(); int displayWidthBefore = acc.getFramebufferWidth(); int displayHeightBefore = acc.getFramebufferHeight(); acc.setFramebufferWidth(displayWidth); @@ -351,10 +352,7 @@ public class VideoRenderer implements RenderInfo { updateDisplaySize(); - //#if MC<=10809 - //$$ ScaledResolution scaled = newScaledResolution(mc); - //$$ gui.toMinecraft().setWorldAndResolution(mc, scaled.getScaledWidth(), scaled.getScaledHeight()); - //#endif + gui.toMinecraft().init(mc, mc.getWindow().getScaledWidth(), mc.getWindow().getScaledHeight()); forceChunkLoadingHook = new ForceChunkLoadingHook(mc.worldRenderer); @@ -401,7 +399,7 @@ public class VideoRenderer implements RenderInfo { } } - MCVer.playSound(new Identifier("replaymod", "render_success")); + mc.getSoundManager().play(PositionedSoundInstance.master(new SoundEvent(SOUND_RENDER_SUCCESS), 1)); try { if (!hasFailed() && ffmpegWriter != null) { @@ -464,12 +462,9 @@ public class VideoRenderer implements RenderInfo { } public boolean drawGui() { + Window window = mc.getWindow(); do { - //#if MC>=11400 - if (GLFW.glfwWindowShouldClose(getWindow(mc).getHandle()) || ((MinecraftAccessor) mc).getCrashReporter() != null) { - //#else - //$$ if (Display.isCloseRequested() || ((MinecraftAccessor) mc).getCrashReporter() != null) { - //#endif + if (GLFW.glfwWindowShouldClose(window.getHandle()) || ((MinecraftAccessor) mc).getCrashReporter() != null) { return false; } @@ -497,7 +492,6 @@ public class VideoRenderer implements RenderInfo { guiFramebuffer.beginWrite(true); //#if MC>=11500 - Window window = getWindow(mc); RenderSystem.clear(256, MinecraftClient.IS_SYSTEM_MAC); RenderSystem.matrixMode(GL11.GL_PROJECTION); RenderSystem.loadIdentity(); @@ -507,7 +501,7 @@ public class VideoRenderer implements RenderInfo { RenderSystem.translatef(0, 0, -2000); //#else //#if MC>=11400 - //$$ getWindow(mc).method_4493( + //$$ window.method_4493( //#if MC>=11400 //$$ false //#endif @@ -517,12 +511,7 @@ public class VideoRenderer implements RenderInfo { //#endif //#endif - //#if MC>=11400 - gui.toMinecraft().init(mc, getWindow(mc).getScaledWidth(), getWindow(mc).getScaledHeight()); - //#else - //$$ ScaledResolution scaled = newScaledResolution(mc); - //$$ gui.toMinecraft().setWorldAndResolution(mc, scaled.getScaledWidth(), scaled.getScaledHeight()); - //#endif + gui.toMinecraft().init(mc, window.getScaledWidth(), window.getScaledHeight()); // Events are polled on 1.13+ in mainWindow.update which is called later //#if MC<11400 @@ -540,8 +529,8 @@ public class VideoRenderer implements RenderInfo { //#endif //#if MC>=11400 - int mouseX = (int) mc.mouse.getX() * getWindow(mc).getScaledWidth() / displayWidth; - int mouseY = (int) mc.mouse.getY() * getWindow(mc).getScaledHeight() / displayHeight; + int mouseX = (int) mc.mouse.getX() * window.getScaledWidth() / displayWidth; + int mouseY = (int) mc.mouse.getY() * window.getScaledHeight() / displayHeight; if (mc.overlay != null) { Screen orgScreen = mc.currentScreen; @@ -564,8 +553,8 @@ public class VideoRenderer implements RenderInfo { mouseX, mouseY, 0); } //#else - //$$ int mouseX = Mouse.getX() * scaled.getScaledWidth() / mc.displayWidth; - //$$ int mouseY = scaled.getScaledHeight() - Mouse.getY() * scaled.getScaledHeight() / mc.displayHeight - 1; + //$$ int mouseX = Mouse.getX() * window.getScaledWidth() / mc.displayWidth; + //$$ int mouseY = window.getScaledHeight() - Mouse.getY() * window.getScaledHeight() / mc.displayHeight - 1; //$$ //$$ gui.toMinecraft().updateScreen(); //$$ gui.toMinecraft().drawScreen(mouseX, mouseY, 0); @@ -578,10 +567,10 @@ public class VideoRenderer implements RenderInfo { popMatrix(); //#if MC>=11500 - getWindow(mc).swapBuffers(); + window.swapBuffers(); //#else //#if MC>=11400 - //$$ getWindow(mc).setFullscreen(false); + //$$ window.setFullscreen(false); //#else //$$ // if not in high performance mode, update the gui size if screen size changed //$$ // otherwise just swap the progress gui to screen @@ -611,13 +600,8 @@ public class VideoRenderer implements RenderInfo { } private boolean displaySizeChanged() { - //#if MC>=11400 - int realWidth = getWindow(mc).getWidth(); - int realHeight = getWindow(mc).getHeight(); - //#else - //$$ int realWidth = Display.getWidth(); - //$$ int realHeight = Display.getHeight(); - //#endif + int realWidth = mc.getWindow().getWidth(); + int realHeight = mc.getWindow().getHeight(); if (realWidth == 0 || realHeight == 0) { // These can be zero on Windows if minimized. // Creating zero-sized framebuffers however will throw an error, so we never want to switch to zero values. @@ -627,13 +611,8 @@ public class VideoRenderer implements RenderInfo { } private void updateDisplaySize() { - //#if MC>=11400 - displayWidth = getWindow(mc).getWidth(); - displayHeight = getWindow(mc).getHeight(); - //#else - //$$ displayWidth = Display.getWidth(); - //$$ displayHeight = Display.getHeight(); - //#endif + displayWidth = mc.getWindow().getWidth(); + displayHeight = mc.getWindow().getHeight(); } public int getFramesDone() { diff --git a/src/main/java/com/replaymod/replay/FullReplaySender.java b/src/main/java/com/replaymod/replay/FullReplaySender.java index bb760016..99b4c31a 100644 --- a/src/main/java/com/replaymod/replay/FullReplaySender.java +++ b/src/main/java/com/replaymod/replay/FullReplaySender.java @@ -367,7 +367,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend // To counteract this, we need to manually update it's position if it hasn't been added // to any chunk yet. if (mc.world != null) { - for (PlayerEntity playerEntity : playerEntities(mc.world)) { + for (PlayerEntity playerEntity : mc.world.getPlayers()) { if (!playerEntity.updateNeeded && playerEntity instanceof OtherClientPlayerEntity) { playerEntity.tickMovement(); } @@ -417,7 +417,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend // Note: Not sure if it's still required but there's this really handy method anyway world.finishRemovingEntities(); //#else - //$$ Iterator iter = loadedEntityList(world).iterator(); + //$$ Iterator iter = world.loadedEntityList.iterator(); //$$ while (iter.hasNext()) { //$$ Entity entity = iter.next(); //$$ if (entity.isDead) { @@ -455,10 +455,10 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend } } }; - if (MCVer.isOnMainThread()) { + if (mc.isOnThread()) { doLightUpdates.run(); } else { - MCVer.scheduleOnMainThread(doLightUpdates); + mc.send(doLightUpdates); } } //#endif @@ -742,8 +742,8 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend //#endif if(cent != null) { - if(!allowMovement && !((Math.abs(Entity_getX(cent) - ppl.getX()) > TP_DISTANCE_LIMIT) || - (Math.abs(Entity_getZ(cent) - ppl.getZ()) > TP_DISTANCE_LIMIT))) { + if(!allowMovement && !((Math.abs(cent.getX() - ppl.getX()) > TP_DISTANCE_LIMIT) || + (Math.abs(cent.getZ() - ppl.getZ()) > TP_DISTANCE_LIMIT))) { return null; } else { allowMovement = false; @@ -754,7 +754,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend @Override @SuppressWarnings("unchecked") public void run() { - if (mc.world == null || !isOnMainThread()) { + if (mc.world == null || !mc.isOnThread()) { ReplayMod.instance.runLater(this); return; } @@ -1171,7 +1171,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend //#endif List entitiesInChunk = new ArrayList<>(); // Gather all entities in that chunk - for (Collection entityList : getEntityLists(chunk)) { + for (Collection entityList : chunk.getEntitySectionArray()) { entitiesInChunk.addAll(entityList); } for (Entity entity : entitiesInChunk) { @@ -1189,9 +1189,9 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend // Check whether the entity has left the chunk //#if MC>=11404 - int chunkX = MathHelper.floor(Entity_getX(entity) / 16); - int chunkY = MathHelper.floor(Entity_getY(entity) / 16); - int chunkZ = MathHelper.floor(Entity_getZ(entity) / 16); + int chunkX = MathHelper.floor(entity.getX() / 16); + int chunkY = MathHelper.floor(entity.getY() / 16); + int chunkZ = MathHelper.floor(entity.getZ() / 16); if (entity.chunkX != chunkX || entity.chunkY != chunkY || entity.chunkZ != chunkZ) { if (entity.updateNeeded) { // Entity has left the chunk diff --git a/src/main/java/com/replaymod/replay/NoGuiScreenshot.java b/src/main/java/com/replaymod/replay/NoGuiScreenshot.java index c438144b..5345c2bc 100644 --- a/src/main/java/com/replaymod/replay/NoGuiScreenshot.java +++ b/src/main/java/com/replaymod/replay/NoGuiScreenshot.java @@ -3,7 +3,6 @@ package com.replaymod.replay; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import com.replaymod.core.ReplayMod; -import com.replaymod.core.versions.MCVer; import de.johni0702.minecraft.gui.versions.Image; import net.minecraft.client.MinecraftClient; import com.mojang.blaze3d.platform.GlStateManager; @@ -13,10 +12,6 @@ import net.minecraft.client.util.ScreenshotUtils; import net.minecraft.client.util.math.MatrixStack; //#endif -//#if MC>=11400 -import static com.replaymod.core.versions.MCVer.getWindow; -//#endif - //#if MC<11400 //$$ import com.google.common.io.Files; //$$ import org.apache.commons.io.FileUtils; @@ -55,11 +50,8 @@ public class NoGuiScreenshot { return; } - //#if MC>=11400 - int frameWidth = getWindow(mc).getFramebufferWidth(), frameHeight = getWindow(mc).getFramebufferHeight(); - //#else - //$$ int frameWidth = mc.displayWidth, frameHeight = mc.displayHeight; - //#endif + int frameWidth = mc.getWindow().getFramebufferWidth(); + int frameHeight = mc.getWindow().getFramebufferHeight(); final boolean guiHidden = mc.options.hudHidden; try { @@ -76,16 +68,17 @@ public class NoGuiScreenshot { mc.getFramebuffer().beginWrite(true); GlStateManager.enableTexture(); + float tickDelta = mc.getTickDelta(); //#if MC>=11500 - mc.gameRenderer.renderWorld(MCVer.getRenderPartialTicks(), System.nanoTime(), new MatrixStack()); + mc.gameRenderer.renderWorld(tickDelta, System.nanoTime(), new MatrixStack()); //#else //#if MC>=11400 - //$$ mc.gameRenderer.renderWorld(MCVer.getRenderPartialTicks(), System.nanoTime()); + //$$ mc.gameRenderer.renderWorld(tickDelta, System.nanoTime()); //#else //#if MC>=10809 - //$$ mc.entityRenderer.updateCameraAndRender(MCVer.getRenderPartialTicks(), System.nanoTime()); + //$$ mc.entityRenderer.updateCameraAndRender(tickDelta, System.nanoTime()); //#else - //$$ mc.entityRenderer.updateCameraAndRender(MCVer.getRenderPartialTicks()); + //$$ mc.entityRenderer.updateCameraAndRender(tickDelta); //#endif //#endif //#endif diff --git a/src/main/java/com/replaymod/replay/ReplayHandler.java b/src/main/java/com/replaymod/replay/ReplayHandler.java index 6669145a..bddee69a 100644 --- a/src/main/java/com/replaymod/replay/ReplayHandler.java +++ b/src/main/java/com/replaymod/replay/ReplayHandler.java @@ -31,6 +31,7 @@ import io.netty.channel.embedded.EmbeddedChannel; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.DownloadingTerrainScreen; import net.minecraft.client.network.ClientLoginNetworkHandler; +import net.minecraft.client.util.Window; import net.minecraft.util.crash.CrashReport; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; @@ -50,12 +51,10 @@ import org.lwjgl.opengl.GL11; //#if MC>=11400 import com.replaymod.replay.mixin.EntityLivingBaseAccessor; -import net.minecraft.client.util.Window; import net.minecraft.entity.LivingEntity; //#else //$$ import com.replaymod.replay.mixin.EntityOtherPlayerMPAccessor; //$$ import net.minecraft.client.entity.EntityOtherPlayerMP; -//$$ import net.minecraft.client.gui.ScaledResolution; //$$ import org.lwjgl.opengl.Display; //#endif @@ -148,7 +147,7 @@ public class ReplayHandler { private UUID spectating; public ReplayHandler(ReplayFile replayFile, boolean asyncMode) throws IOException { - Preconditions.checkState(isOnMainThread(), "Must be called from Minecraft thread."); + Preconditions.checkState(mc.isOnThread(), "Must be called from Minecraft thread."); this.replayFile = replayFile; replayDuration = replayFile.getMetaData().getDuration(); @@ -171,7 +170,7 @@ public class ReplayHandler { } void restartedReplay() { - Preconditions.checkState(isOnMainThread(), "Must be called from Minecraft thread."); + Preconditions.checkState(mc.isOnThread(), "Must be called from Minecraft thread."); channel.close(); @@ -197,7 +196,7 @@ public class ReplayHandler { } public void endReplay() throws IOException { - Preconditions.checkState(isOnMainThread(), "Must be called from Minecraft thread."); + Preconditions.checkState(mc.isOnThread(), "Must be called from Minecraft thread."); ReplayClosingCallback.EVENT.invoker().replayClosing(this); @@ -246,7 +245,7 @@ public class ReplayHandler { } private void setup() { - Preconditions.checkState(isOnMainThread(), "Must be called from Minecraft thread."); + Preconditions.checkState(mc.isOnThread(), "Must be called from Minecraft thread."); //#if MC>=11100 mc.inGameHud.getChatHud().clear(false); @@ -403,7 +402,7 @@ public class ReplayHandler { CameraEntity cam = getCameraEntity(); if (cam != null) { - targetCameraPosition = new Location(Entity_getX(cam), Entity_getY(cam), Entity_getZ(cam), cam.yaw, cam.pitch); + targetCameraPosition = new Location(cam.getX(), cam.getY(), cam.getZ(), cam.yaw, cam.pitch); } else { targetCameraPosition = null; } @@ -486,8 +485,8 @@ public class ReplayHandler { cameraEntity.setCameraController(new SpectatorCameraController(cameraEntity)); } - if (getRenderViewEntity(mc) != e) { - setRenderViewEntity(mc, e); + if (mc.getCameraEntity() != e) { + mc.setCameraEntity(e); cameraEntity.setCameraPosRot(e); } } @@ -505,7 +504,7 @@ public class ReplayHandler { * @return {@code true} if the camera is the view entity, {@code false} otherwise */ public boolean isCameraView() { - return mc.player instanceof CameraEntity && mc.player == getRenderViewEntity(mc); + return mc.player instanceof CameraEntity && mc.player == mc.getCameraEntity(); } /** @@ -539,11 +538,11 @@ public class ReplayHandler { } // Update all entity positions (especially prev/lastTick values) - for (Entity entity : loadedEntityList(mc.world)) { + for (Entity entity : mc.world.getEntities()) { skipTeleportInterpolation(entity); - entity.lastRenderX = entity.prevX = Entity_getX(entity); - entity.lastRenderY = entity.prevY = Entity_getY(entity); - entity.lastRenderZ = entity.prevZ = Entity_getZ(entity); + entity.lastRenderX = entity.prevX = entity.getX(); + entity.lastRenderY = entity.prevY = entity.getY(); + entity.lastRenderZ = entity.prevZ = entity.getZ(); entity.prevYaw = entity.yaw; entity.prevPitch = entity.pitch; } @@ -563,7 +562,7 @@ public class ReplayHandler { quickReplaySender.sendPacketsTill(targetTime); // Immediately apply player teleport interpolation - for (Entity entity : loadedEntityList(mc.world)) { + for (Entity entity : mc.world.getEntities()) { skipTeleportInterpolation(entity); } return; @@ -582,7 +581,7 @@ public class ReplayHandler { if (retainCameraPosition) { CameraEntity cam = getCameraEntity(); if (cam != null) { - targetCameraPosition = new Location(Entity_getX(cam), Entity_getY(cam), Entity_getZ(cam), + targetCameraPosition = new Location(cam.getX(), cam.getY(), cam.getZ(), cam.yaw, cam.pitch); } else { targetCameraPosition = null; @@ -612,8 +611,8 @@ public class ReplayHandler { ); enableTexture(); mc.getFramebuffer().beginWrite(true); + Window window = mc.getWindow(); //#if MC>=11500 - Window window = getWindow(mc); RenderSystem.clear(256, MinecraftClient.IS_SYSTEM_MAC); RenderSystem.matrixMode(GL11.GL_PROJECTION); RenderSystem.loadIdentity(); @@ -623,23 +622,13 @@ public class ReplayHandler { RenderSystem.translatef(0, 0, -2000); //#else //#if MC>=11400 - //$$ getWindow(mc).method_4493(true); - //#else - //#if MC>=11400 - //$$ mc.mainWindow.setupOverlayRendering(); + //$$ window.method_4493(true); //#else //$$ mc.entityRenderer.setupOverlayRendering(); //#endif //#endif - //#endif - //#if MC>=11400 - Window - //#else - //$$ ScaledResolution - //#endif - resolution = newScaledResolution(mc); - guiScreen.toMinecraft().init(mc, resolution.getScaledWidth(), resolution.getScaledHeight()); + guiScreen.toMinecraft().init(mc, window.getScaledWidth(), window.getScaledHeight()); //#if MC>=11600 guiScreen.toMinecraft().render(new MatrixStack(), 0, 0, 0); //#else @@ -654,18 +643,14 @@ public class ReplayHandler { mc.getFramebuffer().endWrite(); popMatrix(); pushMatrix(); - //#if MC>=11400 - mc.getFramebuffer().draw(getWindow(mc).getFramebufferWidth(), getWindow(mc).getFramebufferHeight()); - //#else - //$$ mc.getFramebuffer().framebufferRender(mc.displayWidth, mc.displayHeight); - //#endif + mc.getFramebuffer().draw(mc.getWindow().getFramebufferWidth(), mc.getWindow().getFramebufferHeight()); popMatrix(); //#if MC>=11500 - getWindow(mc).swapBuffers(); + mc.getWindow().swapBuffers(); //#else //#if MC>=11400 - //$$ getWindow(mc).setFullscreen(true); + //$$ mc.window.setFullscreen(true); //#else //$$ Display.update(); //#endif @@ -691,11 +676,11 @@ public class ReplayHandler { //#else //$$ .processReceivedPackets(); //#endif - for (Entity entity : loadedEntityList(mc.world)) { + for (Entity entity : mc.world.getEntities()) { skipTeleportInterpolation(entity); - entity.lastRenderX = entity.prevX = Entity_getX(entity); - entity.lastRenderY = entity.prevY = Entity_getY(entity); - entity.lastRenderZ = entity.prevZ = Entity_getZ(entity); + entity.lastRenderX = entity.prevX = entity.getX(); + entity.lastRenderY = entity.prevY = entity.getY(); + entity.lastRenderZ = entity.prevZ = entity.getZ(); entity.prevYaw = entity.yaw; entity.prevPitch = entity.pitch; } diff --git a/src/main/java/com/replaymod/replay/ReplayModReplay.java b/src/main/java/com/replaymod/replay/ReplayModReplay.java index 0fd60a70..8d4e050c 100644 --- a/src/main/java/com/replaymod/replay/ReplayModReplay.java +++ b/src/main/java/com/replaymod/replay/ReplayModReplay.java @@ -32,8 +32,6 @@ import java.io.File; import java.io.IOException; import java.util.Optional; -import static com.replaymod.core.versions.MCVer.*; - public class ReplayModReplay implements Module { { instance = this; } @@ -68,9 +66,9 @@ public class ReplayModReplay implements Module { if (camera != null) { Marker marker = new Marker(); marker.setTime(replayHandler.getReplaySender().currentTimeStamp()); - marker.setX(Entity_getX(camera)); - marker.setY(Entity_getY(camera)); - marker.setZ(Entity_getZ(camera)); + marker.setX(camera.getX()); + marker.setY(camera.getY()); + marker.setZ(camera.getZ()); marker.setYaw(camera.yaw); marker.setPitch(camera.pitch); marker.setRoll(camera.roll); diff --git a/src/main/java/com/replaymod/replay/camera/CameraEntity.java b/src/main/java/com/replaymod/replay/camera/CameraEntity.java index 31151cac..e5bd3b1f 100644 --- a/src/main/java/com/replaymod/replay/camera/CameraEntity.java +++ b/src/main/java/com/replaymod/replay/camera/CameraEntity.java @@ -31,7 +31,6 @@ import net.minecraft.util.math.Box; //#if FABRIC>=1 //#else -//$$ import com.replaymod.core.versions.MCVer; //$$ import net.minecraftforge.client.event.EntityViewRenderEvent; //$$ import net.minecraftforge.client.event.RenderGameOverlayEvent; //$$ import net.minecraftforge.common.MinecraftForge; @@ -185,7 +184,7 @@ public class CameraEntity * @param z Delta in Z direction */ public void moveCamera(double x, double y, double z) { - setCameraPosition(Entity_getX(this) + x, Entity_getY(this) + y, Entity_getZ(this) + z); + setCameraPosition(this.getX() + x, this.getY() + y, this.getZ() + z); } /** @@ -198,7 +197,7 @@ public class CameraEntity this.lastRenderX = this.prevX = x; this.lastRenderY = this.prevY = y; this.lastRenderZ = this.prevZ = z; - Entity_setPos(this, x, y, z); + this.setPos(x, y, z); updateBoundingBox(); } @@ -239,7 +238,7 @@ public class CameraEntity this.prevZ = to.prevZ; this.prevYaw = to.prevYaw; this.prevPitch = to.prevPitch; - Entity_setPos(this, Entity_getX(to), Entity_getY(to), Entity_getZ(to)); + this.setPos(to.getX(), to.getY(), to.getZ()); this.yaw = to.yaw; this.pitch = to.pitch; this.lastRenderX = to.lastRenderX; @@ -258,17 +257,18 @@ public class CameraEntity //#else //$$ this.boundingBox.setBB(AxisAlignedBB.getBoundingBox( //#endif - Entity_getX(this) - width / 2, Entity_getY(this), Entity_getZ(this) - width / 2, - Entity_getX(this) + width / 2, Entity_getY(this) + height, Entity_getZ(this) + width / 2)); + this.getX() - width / 2, this.getY(), this.getZ() - width / 2, + this.getX() + width / 2, this.getY() + height, this.getZ() + width / 2)); } @Override public void tick() { //#if MC>=10800 - Entity view = getRenderViewEntity(this.client); + Entity view = //#else - //$$ EntityLivingBase view = getRenderViewEntity(this.mc); + //$$ EntityLivingBase view = //#endif + this.client.getCameraEntity(); if (view != null) { // Make sure we're always spectating the right entity // This is important if the spectated player respawns as their @@ -284,9 +284,9 @@ public class CameraEntity } view = this.world.getPlayerByUuid(spectating); if (view != null) { - setRenderViewEntity(this.client, view); + this.client.setCameraEntity(view); } else { - setRenderViewEntity(this.client, this); + this.client.setCameraEntity(this); return; } } @@ -309,7 +309,7 @@ public class CameraEntity @Override public void setRotation(float yaw, float pitch) { - if (getRenderViewEntity(this.client) == this) { + if (this.client.getCameraEntity() == this) { // Only update camera rotation when the camera is the view super.setRotation(yaw, pitch); } @@ -357,7 +357,7 @@ public class CameraEntity } private boolean falseUnlessSpectating(Function property) { - Entity view = getRenderViewEntity(this.client); + Entity view = this.client.getCameraEntity(); if (view != null && view != this) { return property.apply(view); } @@ -407,7 +407,7 @@ public class CameraEntity //#if MC>=10800 @Override public float getSpeed() { - Entity view = getRenderViewEntity(this.client); + Entity view = this.client.getCameraEntity(); if (view != this && view instanceof AbstractClientPlayerEntity) { return ((AbstractClientPlayerEntity) view).getSpeed(); } @@ -422,7 +422,7 @@ public class CameraEntity @Override public boolean isInvisible() { - Entity view = getRenderViewEntity(this.client); + Entity view = this.client.getCameraEntity(); if (view != this) { return view.isInvisible(); } @@ -431,7 +431,7 @@ public class CameraEntity @Override public Identifier getSkinTexture() { - Entity view = getRenderViewEntity(this.client); + Entity view = this.client.getCameraEntity(); if (view != this && view instanceof PlayerEntity) { return Utils.getResourceLocationForPlayerUUID(view.getUuid()); } @@ -450,7 +450,7 @@ public class CameraEntity @Override public boolean isPartVisible(PlayerModelPart modelPart) { - Entity view = getRenderViewEntity(this.client); + Entity view = this.client.getCameraEntity(); if (view != this && view instanceof PlayerEntity) { return ((PlayerEntity) view).isPartVisible(modelPart); } @@ -460,7 +460,7 @@ public class CameraEntity @Override public float getHandSwingProgress(float renderPartialTicks) { - Entity view = getRenderViewEntity(this.client); + Entity view = this.client.getCameraEntity(); if (view != this && view instanceof PlayerEntity) { return ((PlayerEntity) view).getHandSwingProgress(renderPartialTicks); } @@ -705,7 +705,7 @@ public class CameraEntity { on(PreRenderHandCallback.EVENT, this::onRenderHand); } private boolean onRenderHand() { // Unless we are spectating another player, don't render our hand - Entity view = getRenderViewEntity(mc); + Entity view = mc.getCameraEntity(); if (view == CameraEntity.this || !(view instanceof PlayerEntity)) { return true; // cancel hand rendering } else { @@ -761,7 +761,7 @@ public class CameraEntity //#else //$$ @SubscribeEvent //$$ public void preRenderGameOverlay(RenderGameOverlayEvent.Pre event) { - //$$ switch (MCVer.getType(event)) { + //$$ switch (event.getType()) { //$$ case ALL: //$$ heldItemTooltipsWasTrue = mc.gameSettings.heldItemTooltips; //$$ mc.gameSettings.heldItemTooltips = false; @@ -797,7 +797,7 @@ public class CameraEntity //$$ //$$ @SubscribeEvent //$$ public void postRenderGameOverlay(RenderGameOverlayEvent.Post event) { - //$$ if (MCVer.getType(event) != RenderGameOverlayEvent.ElementType.ALL) return; + //$$ if (event.getType() != RenderGameOverlayEvent.ElementType.ALL) return; //$$ mc.gameSettings.heldItemTooltips = heldItemTooltipsWasTrue; //$$ } //#endif diff --git a/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java b/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java index 9e0c02f7..316b4e25 100644 --- a/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java +++ b/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java @@ -1,9 +1,11 @@ package com.replaymod.replay.camera; import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.options.KeyBinding; -import static com.replaymod.core.versions.MCVer.*; +import static net.minecraft.util.math.MathHelper.cos; +import static net.minecraft.util.math.MathHelper.sin; // TODO: Marius is responsible for this. Please, someone clean it up. public class ClassicCameraController implements CameraController { @@ -32,7 +34,7 @@ public class ClassicCameraController implements CameraController { public void update(float partialTicksPassed) { boolean forward = false, backward = false, left = false, right = false, up = false, down = false; speedup = false; - for(KeyBinding kb : getMinecraft().options.keysAll) { + for(KeyBinding kb : MinecraftClient.getInstance().options.keysAll) { if(!kb.isPressed()) continue; if(kb.getTranslationKey().equals("key.forward")) { forward = true; diff --git a/src/main/java/com/replaymod/replay/camera/SpectatorCameraController.java b/src/main/java/com/replaymod/replay/camera/SpectatorCameraController.java index faf15be6..30a15018 100644 --- a/src/main/java/com/replaymod/replay/camera/SpectatorCameraController.java +++ b/src/main/java/com/replaymod/replay/camera/SpectatorCameraController.java @@ -52,9 +52,9 @@ public class SpectatorCameraController implements CameraController { // Always make sure the camera is in the exact same spot as the spectated entity // This is necessary as some rendering code for the hand doesn't respect the view entity // and always uses mc.thePlayer - Entity view = getRenderViewEntity(mc); + Entity view = mc.getCameraEntity(); if (view != null && view != camera) { - camera.setCameraPosRot(getRenderViewEntity(mc)); + camera.setCameraPosRot(mc.getCameraEntity()); // If it's a player, also 'steal' its inventory so the rendering code knows what item to render if (view instanceof PlayerEntity) { PlayerEntity viewPlayer = (PlayerEntity) view; diff --git a/src/main/java/com/replaymod/replay/handler/GuiHandler.java b/src/main/java/com/replaymod/replay/handler/GuiHandler.java index e727134c..af8f67ff 100644 --- a/src/main/java/com/replaymod/replay/handler/GuiHandler.java +++ b/src/main/java/com/replaymod/replay/handler/GuiHandler.java @@ -113,8 +113,8 @@ public class GuiHandler extends EventRegistrations { BUTTON_EXIT_REPLAY, b.x, b.y, - width(b), - height(b), + b.getWidth(), + b.getHeight(), "replaymod.gui.exit", this::onButton )); @@ -133,9 +133,9 @@ public class GuiHandler extends EventRegistrations { //#if MC>=11400 } else if (id.equals(BUTTON_OPTIONS)) { //#if MC>=11400 - width(b, 204); + b.setWidth(204); //#else - //$$ width(b, 200); + //$$ b.width = 200 //#endif //#endif } @@ -147,7 +147,7 @@ public class GuiHandler extends EventRegistrations { } if (achievements != null && stats != null) { moveAllButtonsInRect(buttonList, - achievements.x, stats.x + width(stats), + achievements.x, stats.x + stats.getWidth(), achievements.y, Integer.MAX_VALUE, -24); } @@ -185,8 +185,8 @@ public class GuiHandler extends EventRegistrations { int moveBy ) { buttons.stream() - .filter(button -> button.x <= xEnd && button.x + width(button) >= xStart) - .filter(button -> button.y <= yEnd && button.y + height(button) >= yStart) + .filter(button -> button.x <= xEnd && button.x + button.getWidth() >= xStart) + .filter(button -> button.y <= yEnd && button.y + button.getHeight() >= yStart) .forEach(button -> button.y += moveBy); } @@ -261,8 +261,8 @@ public class GuiHandler extends EventRegistrations { //#else //$$ @SubscribeEvent //$$ public void onButton(GuiScreenEvent.ActionPerformedEvent.Pre event) { - //$$ GuiScreen guiScreen = getGui(event); - //$$ GuiButton button = getButton(event); + //$$ GuiScreen guiScreen = event.getGui(); + //$$ GuiButton button = event.getButton(); //#endif if(!button.active) return; diff --git a/src/main/java/com/replaymod/simplepathing/SPTimeline.java b/src/main/java/com/replaymod/simplepathing/SPTimeline.java index 6a035759..561122d4 100644 --- a/src/main/java/com/replaymod/simplepathing/SPTimeline.java +++ b/src/main/java/com/replaymod/simplepathing/SPTimeline.java @@ -49,7 +49,6 @@ import java.util.Map; import java.util.Optional; import java.util.Set; -import static com.replaymod.core.versions.MCVer.*; import static com.replaymod.replaystudio.pathing.change.RemoveKeyframe.create; import static com.replaymod.simplepathing.ReplayModSimplePathing.LOGGER; @@ -674,7 +673,7 @@ public class SPTimeline implements PathingRegistry { } catch (IOException e) { CrashReport crash = CrashReport.create(e, "Serializing interpolator"); CrashReportSection category = crash.addElement("Serializing interpolator"); - addDetail(category, "Interpolator", interpolator::toString); + category.add("Interpolator", interpolator::toString); throw new CrashException(crash); } @@ -689,7 +688,7 @@ public class SPTimeline implements PathingRegistry { } catch (IOException e) { CrashReport crash = CrashReport.create(e, "De-serializing interpolator"); CrashReportSection category = crash.addElement("De-serializing interpolator"); - addDetail(category, "Interpolator", json::toString); + category.add("Interpolator", json::toString); throw new CrashException(crash); } } diff --git a/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java b/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java index ece93360..784e5a10 100644 --- a/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java +++ b/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java @@ -18,6 +18,9 @@ import com.replaymod.simplepathing.SPTimeline.SPPath; import de.johni0702.minecraft.gui.GuiRenderer; import de.johni0702.minecraft.gui.element.advanced.AbstractGuiTimeline; import de.johni0702.minecraft.gui.function.Draggable; +import net.minecraft.client.render.BufferBuilder; +import net.minecraft.client.render.Tessellator; +import net.minecraft.client.render.VertexFormats; import org.apache.commons.lang3.tuple.Pair; import de.johni0702.minecraft.gui.utils.lwjgl.Point; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; @@ -27,10 +30,6 @@ import org.lwjgl.opengl.GL11; import java.util.Comparator; import java.util.Optional; -import static com.replaymod.core.versions.MCVer.BufferBuilder_addPosCol; -import static com.replaymod.core.versions.MCVer.BufferBuilder_beginPosCol; -import static com.replaymod.core.versions.MCVer.Tessellator_getInstance; - public class GuiKeyframeTimeline extends AbstractGuiTimeline implements Draggable { protected static final int KEYFRAME_SIZE = 5; protected static final int KEYFRAME_TEXTURE_X = 74; @@ -142,55 +141,61 @@ public class GuiKeyframeTimeline extends AbstractGuiTimeline> 24 & 0xff, color >> 16 & 0xff, color >> 8 & 0xff, color & 0xff - ); + ).next(); // Draw vertically over the replay timeline, including its bottom border - BufferBuilder_addPosCol( + buffer.vertex( replayTimelineLeft + positionXReplayTimeline, replayTimelineBottom, - 0, + 0 + ).color( color >> 24 & 0xff, color >> 16 & 0xff, color >> 8 & 0xff, color & 0xff - ); + ).next(); // Now for the important part: connecting to the keyframe timeline - BufferBuilder_addPosCol( + buffer.vertex( keyframeTimelineLeft + positionXKeyframeTimeline, keyframeTimelineTop, - 0, + 0 + ).color( color >> 24 & 0xff, color >> 16 & 0xff, color >> 8 & 0xff, color & 0xff - ); + ).next(); // And finally another vertical bit (the timeline is already crammed enough, so only the border) - BufferBuilder_addPosCol( + buffer.vertex( keyframeTimelineLeft + positionXKeyframeTimeline, keyframeTimelineTop + BORDER_TOP, - 0, + 0 + ).color( color >> 24 & 0xff, color >> 16 & 0xff, color >> 8 & 0xff, color & 0xff - ); + ).next(); GL11.glEnable(GL11.GL_LINE_SMOOTH); GL11.glDisable(GL11.GL_TEXTURE_2D); GL11.glPushAttrib(GL11.GL_SCISSOR_BIT); GL11.glDisable(GL11.GL_SCISSOR_TEST); GL11.glLineWidth(1); - Tessellator_getInstance().draw(); + tessellator.draw(); GL11.glPopAttrib(); GL11.glEnable(GL11.GL_TEXTURE_2D); GL11.glDisable(GL11.GL_LINE_SMOOTH); diff --git a/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java b/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java index 54eb6529..cdce5a51 100644 --- a/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java +++ b/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java @@ -644,9 +644,9 @@ public class GuiPathing { CameraEntity camera = replayHandler.getCameraEntity(); int spectatedId = -1; if (!replayHandler.isCameraView() && !neverSpectator) { - spectatedId = getRenderViewEntity(replayHandler.getOverlay().getMinecraft()).getEntityId(); + spectatedId = replayHandler.getOverlay().getMinecraft().getCameraEntity().getEntityId(); } - timeline.addPositionKeyframe(time, Entity_getX(camera), Entity_getY(camera), Entity_getZ(camera), + timeline.addPositionKeyframe(time, camera.getX(), camera.getY(), camera.getZ(), camera.yaw, camera.pitch, camera.roll, spectatedId); mod.setSelected(path, time); } diff --git a/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java b/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java index 450d853e..4aa42bb0 100644 --- a/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java +++ b/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java @@ -19,6 +19,9 @@ import com.replaymod.simplepathing.SPTimeline; import com.replaymod.simplepathing.gui.GuiPathing; import de.johni0702.minecraft.gui.utils.EventRegistrations; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.BufferBuilder; +import net.minecraft.client.render.Tessellator; +import net.minecraft.client.render.VertexFormats; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; import net.minecraft.util.Identifier; @@ -34,7 +37,6 @@ import java.util.Comparator; import java.util.Optional; import static com.replaymod.core.ReplayMod.TEXTURE; -import static com.replaymod.core.versions.MCVer.*; public class PathPreviewRenderer extends EventRegistrations { private static final Identifier CAMERA_HEAD = new Identifier("replaymod", "camera_head.png"); @@ -56,7 +58,7 @@ public class PathPreviewRenderer extends EventRegistrations { private void renderCameraPath(MatrixStack matrixStack) { if (!replayHandler.getReplaySender().isAsyncMode() || mc.options.hudHidden) return; - Entity view = getRenderViewEntity(mc); + Entity view = mc.getCameraEntity(); if (view == null) return; GuiPathing guiPathing = mod.getGuiPathing(); @@ -75,14 +77,15 @@ public class PathPreviewRenderer extends EventRegistrations { int renderDistanceSquared = renderDistance * renderDistance; Triple viewPos = Triple.of( - Entity_getX(view), + view.getX(), + view.getY() //#if MC>=10800 && MC<11500 //$$ // Eye height is subtracted to make path appear higher (at eye height) than it actually is (at foot height) - //$$ Entity_getY(view) - view.getStandingEyeHeight(), + //$$ - view.getStandingEyeHeight(), //#else - Entity_getY(view), + , //#endif - Entity_getZ(view) + view.getZ() ); GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); @@ -212,36 +215,40 @@ public class PathPreviewRenderer extends EventRegistrations { if (distanceSquared(view, pos1) > renderDistanceSquared) return; if (distanceSquared(view, pos2) > renderDistanceSquared) return; - BufferBuilder_beginPosCol(GL11.GL_LINES); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + buffer.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR); - BufferBuilder_addPosCol( + buffer.vertex( pos1.getLeft() - view.getLeft(), pos1.getMiddle() - view.getMiddle(), - pos1.getRight() - view.getRight(), + pos1.getRight() - view.getRight() + ).color( color >> 16 & 0xff, color >> 8 & 0xff, color & 0xff, 255 - ); - BufferBuilder_addPosCol( + ).next(); + buffer.vertex( pos2.getLeft() - view.getLeft(), pos2.getMiddle() - view.getMiddle(), - pos2.getRight() - view.getRight(), + pos2.getRight() - view.getRight() + ).color( color >> 16 & 0xff, color >> 8 & 0xff, color & 0xff, 255 - ); + ).next(); GL11.glLineWidth(3); - Tessellator_getInstance().draw(); + tessellator.draw(); } private void drawPoint(Triple view, Triple pos, Keyframe keyframe) { - MCVer.bindTexture(TEXTURE); + mc.getTextureManager().bindTexture(TEXTURE); float posX = 80f / ReplayMod.TEXTURE_SIZE; float posY = 0f; @@ -260,12 +267,14 @@ public class PathPreviewRenderer extends EventRegistrations { float maxX = 0.5f; float maxY = 0.5f; - BufferBuilder_beginPosTex(GL11.GL_QUADS); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + buffer.begin(GL11.GL_QUADS, VertexFormats.POSITION_TEXTURE); - BufferBuilder_addPosTex(minX, minY, 0, posX + size, posY + size); - BufferBuilder_addPosTex(minX, maxY, 0, posX + size, posY); - BufferBuilder_addPosTex(maxX, maxY, 0, posX, posY); - BufferBuilder_addPosTex(maxX, minY, 0, posX, posY + size); + buffer.vertex(minX, minY, 0).texture(posX + size, posY + size).next(); + buffer.vertex(minX, maxY, 0).texture(posX + size, posY).next(); + buffer.vertex(maxX, maxY, 0).texture(posX, posY).next(); + buffer.vertex(maxX, minY, 0).texture(posX, posY + size).next(); GL11.glPushMatrix(); @@ -275,15 +284,10 @@ public class PathPreviewRenderer extends EventRegistrations { pos.getRight() - view.getRight() ); GL11.glNormal3f(0, 1, 0); - //#if MC>=11500 - GL11.glRotatef(-getRenderManager().camera.getYaw(), 0, 1, 0); - GL11.glRotatef(getRenderManager().camera.getPitch(), 1, 0, 0); - //#else - //$$ GL11.glRotatef(-getRenderManager().cameraYaw, 0, 1, 0); - //$$ GL11.glRotatef(getRenderManager().cameraPitch, 1, 0, 0); - //#endif + GL11.glRotatef(-mc.getEntityRenderDispatcher().camera.getYaw(), 0, 1, 0); + GL11.glRotatef(mc.getEntityRenderDispatcher().camera.getPitch(), 1, 0, 0); - Tessellator_getInstance().draw(); + tessellator.draw(); GL11.glPopMatrix(); } @@ -292,7 +296,7 @@ public class PathPreviewRenderer extends EventRegistrations { Triple pos, Triple rot) { - MCVer.bindTexture(CAMERA_HEAD); + mc.getTextureManager().bindTexture(CAMERA_HEAD); GL11.glPushMatrix(); @@ -308,12 +312,14 @@ public class PathPreviewRenderer extends EventRegistrations { //draw the position line GL11.glDisable(GL11.GL_TEXTURE_2D); - BufferBuilder_beginPosCol(GL11.GL_LINES); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + buffer.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR); - BufferBuilder_addPosCol(0, 0, 0, 0, 255, 0, 170); - BufferBuilder_addPosCol(0, 0, 2, 0, 255, 0, 170); + buffer.vertex(0, 0, 0).color(0, 255, 0, 170).next(); + buffer.vertex(0, 0, 2).color(0, 255, 0, 170).next(); - Tessellator_getInstance().draw(); + tessellator.draw(); // draw camera cube GL11.glEnable(GL11.GL_TEXTURE_2D); @@ -322,45 +328,45 @@ public class PathPreviewRenderer extends EventRegistrations { double r = -cubeSize/2; - BufferBuilder_beginPosTexCol(GL11.GL_QUADS); + buffer.begin(GL11.GL_QUADS, VertexFormats.POSITION_TEXTURE_COLOR); //back - BufferBuilder_addPosTexCol(r, r + cubeSize, r, 3 * 8 / 64f, 8 / 64f, 255, 255, 255, 200); - BufferBuilder_addPosTexCol(r + cubeSize, r + cubeSize, r, 4*8/64f, 8/64f, 255, 255, 255, 200); - BufferBuilder_addPosTexCol(r + cubeSize, r, r, 4*8/64f, 2*8/64f, 255, 255, 255, 200); - BufferBuilder_addPosTexCol(r, r, r, 3*8/64f, 2*8/64f, 255, 255, 255, 200); + buffer.vertex(r, r + cubeSize, r).texture(3 * 8 / 64f, 8 / 64f).color(255, 255, 255, 200).next(); + buffer.vertex(r + cubeSize, r + cubeSize, r).texture(4*8/64f, 8/64f).color(255, 255, 255, 200).next(); + buffer.vertex(r + cubeSize, r, r).texture(4*8/64f, 2*8/64f).color(255, 255, 255, 200).next(); + buffer.vertex(r, r, r).texture(3*8/64f, 2*8/64f).color(255, 255, 255, 200).next(); //front - BufferBuilder_addPosTexCol(r + cubeSize, r, r + cubeSize, 2 * 8 / 64f, 2*8/64f, 255, 255, 255, 200); - BufferBuilder_addPosTexCol(r + cubeSize, r + cubeSize, r + cubeSize, 2 * 8 / 64f, 8/64f, 255, 255, 255, 200); - BufferBuilder_addPosTexCol(r, r + cubeSize, r + cubeSize, 8 / 64f, 8 / 64f, 255, 255, 255, 200); - BufferBuilder_addPosTexCol(r, r, r + cubeSize, 8 / 64f, 2*8/64f, 255, 255, 255, 200); + buffer.vertex(r + cubeSize, r, r + cubeSize).texture(2 * 8 / 64f, 2*8/64f).color(255, 255, 255, 200).next(); + buffer.vertex(r + cubeSize, r + cubeSize, r + cubeSize).texture(2 * 8 / 64f, 8/64f).color(255, 255, 255, 200).next(); + buffer.vertex(r, r + cubeSize, r + cubeSize).texture(8 / 64f, 8 / 64f).color(255, 255, 255, 200).next(); + buffer.vertex(r, r, r + cubeSize).texture(8 / 64f, 2*8/64f).color(255, 255, 255, 200).next(); //left - BufferBuilder_addPosTexCol(r + cubeSize, r + cubeSize, r, 0, 8/64f, 255, 255, 255, 200); - BufferBuilder_addPosTexCol(r + cubeSize, r + cubeSize, r + cubeSize, 8/64f, 8/64f, 255, 255, 255, 200); - BufferBuilder_addPosTexCol(r + cubeSize, r, r + cubeSize, 8/64f, 2*8/64f, 255, 255, 255, 200); - BufferBuilder_addPosTexCol(r+cubeSize, r, r, 0, 2*8/64f, 255, 255, 255, 200); + buffer.vertex(r + cubeSize, r + cubeSize, r).texture(0, 8/64f).color(255, 255, 255, 200).next(); + buffer.vertex(r + cubeSize, r + cubeSize, r + cubeSize).texture(8/64f, 8/64f).color(255, 255, 255, 200).next(); + buffer.vertex(r + cubeSize, r, r + cubeSize).texture(8/64f, 2*8/64f).color(255, 255, 255, 200).next(); + buffer.vertex(r+cubeSize, r, r).texture(0, 2*8/64f).color(255, 255, 255, 200).next(); //right - BufferBuilder_addPosTexCol(r, r + cubeSize, r + cubeSize, 2*8/64f, 8/64f, 255, 255, 255, 200); - BufferBuilder_addPosTexCol(r, r + cubeSize, r, 3*8/64f, 8/64f, 255, 255, 255, 200); - BufferBuilder_addPosTexCol(r, r, r, 3*8/64f, 2*8/64f, 255, 255, 255, 200); - BufferBuilder_addPosTexCol(r, r, r + cubeSize, 2 * 8 / 64f, 2 * 8 / 64f, 255, 255, 255, 200); + buffer.vertex(r, r + cubeSize, r + cubeSize).texture(2*8/64f, 8/64f).color(255, 255, 255, 200).next(); + buffer.vertex(r, r + cubeSize, r).texture(3*8/64f, 8/64f).color(255, 255, 255, 200).next(); + buffer.vertex(r, r, r).texture(3*8/64f, 2*8/64f).color(255, 255, 255, 200).next(); + buffer.vertex(r, r, r + cubeSize).texture(2 * 8 / 64f, 2 * 8 / 64f).color(255, 255, 255, 200).next(); //bottom - BufferBuilder_addPosTexCol(r + cubeSize, r, r, 3*8/64f, 0, 255, 255, 255, 200); - BufferBuilder_addPosTexCol(r + cubeSize, r, r + cubeSize, 3*8/64f, 8/64f, 255, 255, 255, 200); - BufferBuilder_addPosTexCol(r, r, r + cubeSize, 2*8/64f, 8/64f, 255, 255, 255, 200); - BufferBuilder_addPosTexCol(r, r, r, 2 * 8 / 64f, 0, 255, 255, 255, 200); + buffer.vertex(r + cubeSize, r, r).texture(3*8/64f, 0).color(255, 255, 255, 200).next(); + buffer.vertex(r + cubeSize, r, r + cubeSize).texture(3*8/64f, 8/64f).color(255, 255, 255, 200).next(); + buffer.vertex(r, r, r + cubeSize).texture(2*8/64f, 8/64f).color(255, 255, 255, 200).next(); + buffer.vertex(r, r, r).texture(2 * 8 / 64f, 0).color(255, 255, 255, 200).next(); //top - BufferBuilder_addPosTexCol(r, r + cubeSize, r, 8/64f, 0, 255, 255, 255, 200); - BufferBuilder_addPosTexCol(r, r + cubeSize, r + cubeSize, 8/64f, 8/64f, 255, 255, 255, 200); - BufferBuilder_addPosTexCol(r + cubeSize, r + cubeSize, r + cubeSize, 2*8/64f, 8/64f, 255, 255, 255, 200); - BufferBuilder_addPosTexCol(r + cubeSize, r + cubeSize, r, 2 * 8 / 64f, 0, 255, 255, 255, 200); + buffer.vertex(r, r + cubeSize, r).texture(8/64f, 0).color(255, 255, 255, 200).next(); + buffer.vertex(r, r + cubeSize, r + cubeSize).texture(8/64f, 8/64f).color(255, 255, 255, 200).next(); + buffer.vertex(r + cubeSize, r + cubeSize, r + cubeSize).texture(2*8/64f, 8/64f).color(255, 255, 255, 200).next(); + buffer.vertex(r + cubeSize, r + cubeSize, r).texture(2 * 8 / 64f, 0).color(255, 255, 255, 200).next(); - Tessellator_getInstance().draw(); + tessellator.draw(); GL11.glPopMatrix(); } diff --git a/versions/1.12.2/src/main/java/com/replaymod/compat/oranges17animations/HideInvisibleEntities.java b/versions/1.12.2/src/main/java/com/replaymod/compat/oranges17animations/HideInvisibleEntities.java index d97a953a..01aec589 100644 --- a/versions/1.12.2/src/main/java/com/replaymod/compat/oranges17animations/HideInvisibleEntities.java +++ b/versions/1.12.2/src/main/java/com/replaymod/compat/oranges17animations/HideInvisibleEntities.java @@ -1,5 +1,6 @@ package com.replaymod.compat.oranges17animations; +import com.replaymod.core.ReplayMod; import com.replaymod.replay.camera.CameraEntity; import de.johni0702.minecraft.gui.utils.EventRegistrations; import net.minecraft.client.Minecraft; @@ -7,8 +8,6 @@ import net.minecraftforge.client.event.RenderLivingEvent; import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import static com.replaymod.core.versions.MCVer.*; - /** * Orange seems to have copied vast parts of the RendererLivingEntity into their ArmorAnimation class which cancels the RenderLivingEvent.Pre and calls its own code instead. * This breaks our mixin which assures that, even though the camera is in spectator mode, it cannot see invisible entities. @@ -17,12 +16,12 @@ import static com.replaymod.core.versions.MCVer.*; */ public class HideInvisibleEntities extends EventRegistrations { private final Minecraft mc = Minecraft.getMinecraft(); - private final boolean modLoaded = isModLoaded("animations"); + private final boolean modLoaded = ReplayMod.instance.isModLoaded("animations"); @SubscribeEvent(priority = EventPriority.HIGH) public void preRenderLiving(RenderLivingEvent.Pre event) { if (modLoaded) { - if (mc.player instanceof CameraEntity && getEntity(event).isInvisible()) { + if (mc.player instanceof CameraEntity && event.getEntity().isInvisible()) { event.setCanceled(true); } } diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/ReplayModBackend.java b/versions/1.12.2/src/main/java/com/replaymod/core/ReplayModBackend.java index d0f1fb62..6da12741 100644 --- a/versions/1.12.2/src/main/java/com/replaymod/core/ReplayModBackend.java +++ b/versions/1.12.2/src/main/java/com/replaymod/core/ReplayModBackend.java @@ -61,6 +61,14 @@ public class ReplayModBackend { return Loader.instance().getIndexedModList().get(MOD_ID).getVersion(); } + public String getMinecraftVersion() { + return Loader.MC_VERSION; + } + + public boolean isModLoaded(String id) { + return Loader.isModLoaded(id); + } + static { // Note: even preInit is too late and we'd have to issue another resource reload List defaultResourcePacks = ((MinecraftAccessor) getMinecraft()).getDefaultResourcePacks(); diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/versions/GLFW.java b/versions/1.12.2/src/main/java/com/replaymod/core/versions/GLFW.java new file mode 100644 index 00000000..0c30d254 --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/core/versions/GLFW.java @@ -0,0 +1,9 @@ +package com.replaymod.core.versions; + +import org.lwjgl.opengl.Display; + +public class GLFW { + public static boolean glfwWindowShouldClose(@SuppressWarnings("unused") long handle) { + return Display.isCloseRequested(); + } +} diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/versions/Window.java b/versions/1.12.2/src/main/java/com/replaymod/core/versions/Window.java new file mode 100644 index 00000000..d0a3ddba --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/core/versions/Window.java @@ -0,0 +1,69 @@ +package com.replaymod.core.versions; + +import com.replaymod.render.mixin.MainWindowAccessor; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import org.lwjgl.opengl.Display; + +public class Window implements MainWindowAccessor { + + private final Minecraft mc; + private ScaledResolution scaledResolution; + + public Window(Minecraft mc) { + this.mc = mc; + } + + @Override + public int getFramebufferWidth() { + return mc.displayWidth; + } + + @Override + public void setFramebufferWidth(int value) { + mc.displayWidth = value; + } + + @Override + public int getFramebufferHeight() { + return mc.displayHeight; + } + + @Override + public void setFramebufferHeight(int value) { + mc.displayHeight = value; + } + + public long getHandle() { + return 0; + } + + public int getWidth() { + return Display.getWidth(); + } + + public int getHeight() { + return Display.getHeight(); + } + + private ScaledResolution scaledResolution() { + ScaledResolution scaledResolution = this.scaledResolution; + if (scaledResolution == null) { + //#if MC>=10809 + scaledResolution = new ScaledResolution(mc); + //#else + //$$ scaledResolution = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight); + //#endif + this.scaledResolution = scaledResolution; + } + return scaledResolution; + } + + public int getScaledWidth() { + return scaledResolution().getScaledWidth(); + } + + public int getScaledHeight() { + return scaledResolution().getScaledWidth(); + } +} diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/EventsAdapter.java b/versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/EventsAdapter.java index 2083b9fc..4a567d0c 100644 --- a/versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/EventsAdapter.java +++ b/versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/EventsAdapter.java @@ -55,7 +55,7 @@ public class EventsAdapter extends EventRegistrations { @SubscribeEvent public void preRenderGameOverlay(RenderGameOverlayEvent.Pre event) { Boolean result = null; - switch (MCVer.getType(event)) { + switch (event.getType()) { case CROSSHAIRS: result = RenderSpectatorCrosshairCallback.EVENT.invoker().shouldRenderSpectatorCrosshair(); break; diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/Patterns.java b/versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/Patterns.java new file mode 100644 index 00000000..cf16de42 --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/Patterns.java @@ -0,0 +1,47 @@ +package com.replaymod.core.versions.forge; + +import com.replaymod.gradle.remap.Pattern; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.entity.EntityLivingBase; +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.client.event.RenderLivingEvent; + +class Patterns { + @Pattern + private static GuiButton getButton(GuiScreenEvent.ActionPerformedEvent event) { + //#if MC>=10904 + return event.getButton(); + //#else + //$$ return event.button; + //#endif + } + + @Pattern + private static GuiScreen getGui(GuiScreenEvent event) { + //#if MC>=10904 + return event.getGui(); + //#else + //$$ return event.gui; + //#endif + } + + @Pattern + private static EntityLivingBase getEntity(RenderLivingEvent event) { + //#if MC>=10904 + return event.getEntity(); + //#else + //$$ return event.entity; + //#endif + } + + @Pattern + private static RenderGameOverlayEvent.ElementType getType(RenderGameOverlayEvent event) { + //#if MC>=10904 + return event.getType(); + //#else + //$$ return event.type; + //#endif + } +} diff --git a/versions/1.14.4-forge/mapping.txt b/versions/1.14.4-forge/mapping.txt index 6a1960e7..ec310305 100644 --- a/versions/1.14.4-forge/mapping.txt +++ b/versions/1.14.4-forge/mapping.txt @@ -16,6 +16,9 @@ net.minecraft.network.play.server.SPacketEntity.Move net.minecraft.network.play. net.minecraftforge.fml.network.NetworkRegistry net.minecraftforge.fml.common.network.NetworkRegistry net.minecraft.client.particle.ParticleManager queue queueEntityFX org.apache.maven.artifact.versioning.ComparableVersion net.minecraftforge.fml.common.versioning.ComparableVersion +org.lwjgl.glfw.GLFW com.replaymod.core.versions.GLFW +net.minecraft.client.MainWindow com.replaymod.core.versions.Window +net.minecraft.client.audio.SimpleSound net.minecraft.client.audio.PositionedSoundRecord net.minecraft.resources.FolderPack getInputStream() getInputStreamByName() net.minecraft.client.gui.GuiYesNoCallback confirmResult() confirmClicked() diff --git a/versions/1.14.4-forge/src/main/java/com/replaymod/core/ReplayModBackend.java b/versions/1.14.4-forge/src/main/java/com/replaymod/core/ReplayModBackend.java index 3527ca6d..2ba2eab7 100644 --- a/versions/1.14.4-forge/src/main/java/com/replaymod/core/ReplayModBackend.java +++ b/versions/1.14.4-forge/src/main/java/com/replaymod/core/ReplayModBackend.java @@ -1,5 +1,6 @@ package com.replaymod.core; +import net.minecraft.client.Minecraft; import net.minecraftforge.fml.ModList; import static com.replaymod.core.ReplayMod.MOD_ID; @@ -8,4 +9,12 @@ public class ReplayModBackend { public String getVersion() { return ModList.get().getModContainerById(MOD_ID).get().getModInfo().getVersion().toString(); } + + public String getMinecraftVersion() { + return Minecraft.getInstance().getMinecraftGame().getVersion().getName(); + } + + public boolean isModLoaded(String id) { + return ModList.get().isLoaded(id.toLowerCase()); + } } diff --git a/versions/1.7.10/src/main/java/com/replaymod/core/versions/BufferBuilder.java b/versions/1.7.10/src/main/java/com/replaymod/core/versions/BufferBuilder.java new file mode 100644 index 00000000..73628626 --- /dev/null +++ b/versions/1.7.10/src/main/java/com/replaymod/core/versions/BufferBuilder.java @@ -0,0 +1,30 @@ +package com.replaymod.core.versions; + +import net.minecraft.client.renderer.Tessellator; + +public class BufferBuilder { + + private final Tessellator inner; + + public BufferBuilder(Tessellator inner) { + this.inner = inner; + } + + public void startDrawing(int glQuads) { + inner.startDrawing(glQuads); + } + + public void addVertexWithUV(double x, double y, double z, float u, float v) { + inner.addVertexWithUV(x, y, z, u, v); + } + + public void setColorRGBA(int r, int g, int b, int a) { + inner.setColorRGBA(r, g, b, a); + } + + public void addVertex(double x, double y, double z) { + inner.addVertex(x, y, z); + } + + public static class VertexFormats {} +} diff --git a/versions/1.8/mapping.txt b/versions/1.8/mapping.txt index c5cece6f..3096beb7 100644 --- a/versions/1.8/mapping.txt +++ b/versions/1.8/mapping.txt @@ -36,3 +36,5 @@ net.minecraft.client.renderer.tileentity.TileEntityEndPortalRenderer net.minecra net.minecraft.network.play.server.S3FPacketCustomPayload getChannelName() func_149169_c() net.minecraft.network.play.server.S01PacketJoinGame getEntityId() func_149197_c() net.minecraft.client.network.NetHandlerLoginClient networkManager field_147393_d +net.minecraft.client.renderer.WorldRenderer com.replaymod.core.versions.BufferBuilder +net.minecraft.client.renderer.vertex.DefaultVertexFormats com.replaymod.core.versions.BufferBuilder.VertexFormats diff --git a/versions/1.9.4/mapping.txt b/versions/1.9.4/mapping.txt index d0fcbe20..9225b4c1 100644 --- a/versions/1.9.4/mapping.txt +++ b/versions/1.9.4/mapping.txt @@ -20,6 +20,7 @@ net.minecraft.network.play.server.SPacketSpawnMob dataManager field_149043_l net.minecraft.network.play.server.SPacketSpawnMob getDataManagerEntries() func_149027_c() net.minecraft.network.play.server.SPacketSpawnPlayer getDataManagerEntries() func_148944_c() net.minecraft.client.multiplayer.ServerList saveSingleServer() func_147414_b() +net.minecraft.util.SoundEvent com.replaymod.core.versions.MCVer.SoundEvent net.minecraft.network.play.server.SPacketJoinGame net.minecraft.network.play.server.S01PacketJoinGame net.minecraft.network.play.server.SPacketChat net.minecraft.network.play.server.S02PacketChat From 6289545d84746a343f2d0a22753ec5a6f375286f Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 18:16:18 +0100 Subject: [PATCH 044/102] Remove forge/fml event bus from MCVer --- .../com/replaymod/core/versions/MCVer.java | 20 ------------------- .../versions/scheduler/SchedulerImpl.java | 15 ++++++++++++-- .../recording/mixin/MixinGuiScreen.java | 7 +++---- 3 files changed, 16 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/replaymod/core/versions/MCVer.java b/src/main/java/com/replaymod/core/versions/MCVer.java index 73b77d47..b14cc869 100644 --- a/src/main/java/com/replaymod/core/versions/MCVer.java +++ b/src/main/java/com/replaymod/core/versions/MCVer.java @@ -34,12 +34,6 @@ import net.minecraft.text.TranslatableText; //$$ import net.minecraft.realms.RealmsSharedConstants; //#endif -//#if FABRIC>=1 -//#else -//$$ import net.minecraftforge.common.MinecraftForge; -//$$ import net.minecraftforge.eventbus.api.IEventBus; -//#endif - //#if MC>=11400 import net.minecraft.client.util.InputUtil; import org.lwjgl.glfw.GLFW; @@ -58,11 +52,6 @@ import net.minecraft.client.particle.Particle; import net.minecraft.util.math.Vec3d; //#endif -//#if MC>=10809 -//#else -//$$ import net.minecraftforge.fml.common.FMLCommonHandler; -//#endif - //#if MC>=10800 import net.minecraft.client.render.VertexFormat; import net.minecraft.client.render.VertexFormatElement; @@ -89,15 +78,6 @@ import java.util.Optional; * Abstraction over things that have changed between different MC versions. */ public class MCVer { - //#if FABRIC<=0 - //$$ public static IEventBus FORGE_BUS = MinecraftForge.EVENT_BUS; - //#if MC>=10809 - //$$ public static IEventBus FML_BUS = FORGE_BUS; - //#else - //$$ public static EventBus FML_BUS = FMLCommonHandler.instance().bus(); - //#endif - //#endif - public static int getProtocolVersion() { //#if MC>=11400 return SharedConstants.getGameVersion().getProtocolVersion(); diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java b/versions/1.12.2/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java index 9938ce24..65444afc 100644 --- a/versions/1.12.2/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java +++ b/versions/1.12.2/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java @@ -4,6 +4,7 @@ import com.google.common.util.concurrent.ListenableFutureTask; import com.replaymod.core.mixin.MinecraftAccessor; import net.minecraft.client.Minecraft; import net.minecraft.util.ReportedException; +import net.minecraftforge.fml.common.eventhandler.EventBus; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; @@ -13,15 +14,25 @@ import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +//#if MC>=10809 +import net.minecraftforge.common.MinecraftForge; +//#else +//$$ import net.minecraftforge.fml.common.FMLCommonHandler; +//#endif + //#if MC<10800 //$$ import java.util.ArrayDeque; //#endif -import static com.replaymod.core.versions.MCVer.FML_BUS; - public class SchedulerImpl implements Scheduler { private static final Minecraft mc = Minecraft.getMinecraft(); + //#if MC>=10809 + private static final EventBus FML_BUS = MinecraftForge.EVENT_BUS; + //#else + //$$ private static final EventBus FML_BUS = FMLCommonHandler.instance().bus(); + //#endif + @Override public void runSync(Runnable runnable) throws InterruptedException, ExecutionException, TimeoutException { if (mc.isCallingFromMinecraftThread()) { diff --git a/versions/1.7.10/src/main/java/com/replaymod/recording/mixin/MixinGuiScreen.java b/versions/1.7.10/src/main/java/com/replaymod/recording/mixin/MixinGuiScreen.java index c9d30754..1f795d7c 100644 --- a/versions/1.7.10/src/main/java/com/replaymod/recording/mixin/MixinGuiScreen.java +++ b/versions/1.7.10/src/main/java/com/replaymod/recording/mixin/MixinGuiScreen.java @@ -2,6 +2,7 @@ package com.replaymod.recording.mixin; import de.johni0702.minecraft.gui.container.VanillaGuiScreen; import net.minecraft.client.gui.GuiScreen; +import net.minecraftforge.common.MinecraftForge; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import org.spongepowered.asm.mixin.Mixin; @@ -10,8 +11,6 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import static com.replaymod.core.versions.MCVer.*; - @Mixin(GuiScreen.class) public abstract class MixinGuiScreen { @@ -20,7 +19,7 @@ public abstract class MixinGuiScreen { ci.cancel(); if (Mouse.isCreated()) { while (Mouse.next()) { - if (FORGE_BUS.post(new VanillaGuiScreen.MouseInputEvent())) { + if (MinecraftForge.EVENT_BUS.post(new VanillaGuiScreen.MouseInputEvent())) { continue; } handleMouseInput(); @@ -29,7 +28,7 @@ public abstract class MixinGuiScreen { if (Keyboard.isCreated()) { while (Keyboard.next()) { - if (FORGE_BUS.post(new VanillaGuiScreen.KeyboardInputEvent())) { + if (MinecraftForge.EVENT_BUS.post(new VanillaGuiScreen.KeyboardInputEvent())) { continue; } handleKeyboardInput(); From 2fb4f73ae4d4ad304f9a3c272bdcbad99af483b0 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 18:29:11 +0100 Subject: [PATCH 045/102] Move ChunkRenderDispatcherAccessor into 1.14.4 project --- .../mixin/ChunkRenderDispatcherAccessor.java | 35 +------------------ .../mixin/ChunkRenderDispatcherAccessor.java | 34 ++++++++++++++++++ 2 files changed, 35 insertions(+), 34 deletions(-) create mode 100644 versions/1.14.4/src/main/java/com/replaymod/render/mixin/ChunkRenderDispatcherAccessor.java diff --git a/src/main/java/com/replaymod/render/mixin/ChunkRenderDispatcherAccessor.java b/src/main/java/com/replaymod/render/mixin/ChunkRenderDispatcherAccessor.java index 2e1ed260..a6f9a3fe 100644 --- a/src/main/java/com/replaymod/render/mixin/ChunkRenderDispatcherAccessor.java +++ b/src/main/java/com/replaymod/render/mixin/ChunkRenderDispatcherAccessor.java @@ -1,34 +1 @@ -//#if MC>=10800 && MC<11500 -//$$ package com.replaymod.render.mixin; -//$$ -//$$ import net.minecraft.client.render.chunk.ChunkBuilder; -//$$ import net.minecraft.client.render.chunk.ChunkRenderTask; -//$$ import net.minecraft.client.render.chunk.ChunkRenderWorker; -//$$ import org.spongepowered.asm.mixin.Mixin; -//$$ import org.spongepowered.asm.mixin.gen.Accessor; -//$$ -//$$ import java.util.List; -//#if MC>=10904 -//$$ import java.util.concurrent.PriorityBlockingQueue; -//#else -//$$ import java.util.concurrent.BlockingQueue; -//#endif -//$$ -//$$ @Mixin(ChunkBuilder.class) -//$$ public interface ChunkRenderDispatcherAccessor { -//$$ @Accessor("workers") -//$$ List getListThreadedWorkers(); -//$$ - //#if MC>=10904 - //$$ @Accessor("pendingChunks") - //$$ PriorityBlockingQueue getQueueChunkUpdates(); - //$$ @Accessor("pendingChunks") - //$$ void setQueueChunkUpdates(PriorityBlockingQueue value); - //#else - //$$ @Accessor - //$$ BlockingQueue getQueueChunkUpdates(); - //$$ @Accessor - //$$ void setQueueChunkUpdates(BlockingQueue value); - //#endif -//$$ } -//#endif +// 1.14.4 to 1.8 diff --git a/versions/1.14.4/src/main/java/com/replaymod/render/mixin/ChunkRenderDispatcherAccessor.java b/versions/1.14.4/src/main/java/com/replaymod/render/mixin/ChunkRenderDispatcherAccessor.java new file mode 100644 index 00000000..2c62b138 --- /dev/null +++ b/versions/1.14.4/src/main/java/com/replaymod/render/mixin/ChunkRenderDispatcherAccessor.java @@ -0,0 +1,34 @@ +//#if MC>=10800 +package com.replaymod.render.mixin; + +import net.minecraft.client.render.chunk.ChunkBuilder; +import net.minecraft.client.render.chunk.ChunkRenderTask; +import net.minecraft.client.render.chunk.ChunkRenderWorker; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; +//#if MC>=10904 +import java.util.concurrent.PriorityBlockingQueue; +//#else +//$$ import java.util.concurrent.BlockingQueue; +//#endif + +@Mixin(ChunkBuilder.class) +public interface ChunkRenderDispatcherAccessor { + @Accessor("workers") + List getListThreadedWorkers(); + + //#if MC>=10904 + @Accessor("pendingChunks") + PriorityBlockingQueue getQueueChunkUpdates(); + @Accessor("pendingChunks") + void setQueueChunkUpdates(PriorityBlockingQueue value); + //#else + //$$ @Accessor + //$$ BlockingQueue getQueueChunkUpdates(); + //$$ @Accessor + //$$ void setQueueChunkUpdates(BlockingQueue value); + //#endif +} +//#endif From 10426f9d39187b8c786c66288dad59d223a69763 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 18:35:32 +0100 Subject: [PATCH 046/102] Move MixinChunkRenderWorker into 1.14.4 project --- .../render/mixin/MixinChunkRenderWorker.java | 20 +------------------ .../render/mixin/MixinChunkRenderWorker.java | 18 +++++++++++++++++ 2 files changed, 19 insertions(+), 19 deletions(-) create mode 100644 versions/1.14.4/src/main/java/com/replaymod/render/mixin/MixinChunkRenderWorker.java diff --git a/src/main/java/com/replaymod/render/mixin/MixinChunkRenderWorker.java b/src/main/java/com/replaymod/render/mixin/MixinChunkRenderWorker.java index aea88e0c..c0669fe9 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinChunkRenderWorker.java +++ b/src/main/java/com/replaymod/render/mixin/MixinChunkRenderWorker.java @@ -1,19 +1 @@ -package com.replaymod.render.mixin; - -//#if MC>=10800 && MC<11500 -//$$ -//$$ import com.replaymod.core.versions.MCVer; -//$$ import net.minecraft.client.render.chunk.ChunkRenderTask; -//$$ import net.minecraft.client.render.chunk.ChunkRenderWorker; -//$$ import org.spongepowered.asm.mixin.Mixin; -//$$ import org.spongepowered.asm.mixin.Shadow; -//$$ -//$$ @Mixin(ChunkRenderWorker.class) -//$$ public abstract class MixinChunkRenderWorker implements MCVer.ChunkRenderWorkerAccessor { -//$$ @Shadow abstract void runTask(ChunkRenderTask task) throws InterruptedException; -//$$ -//$$ public void doRunTask(ChunkRenderTask task) throws InterruptedException { -//$$ runTask(task); -//$$ } -//$$ } -//#endif +// 1.14.4 - 1.8 diff --git a/versions/1.14.4/src/main/java/com/replaymod/render/mixin/MixinChunkRenderWorker.java b/versions/1.14.4/src/main/java/com/replaymod/render/mixin/MixinChunkRenderWorker.java new file mode 100644 index 00000000..6e4a2a00 --- /dev/null +++ b/versions/1.14.4/src/main/java/com/replaymod/render/mixin/MixinChunkRenderWorker.java @@ -0,0 +1,18 @@ +//#if MC>=10800 +package com.replaymod.render.mixin; + +import com.replaymod.core.versions.MCVer; +import net.minecraft.client.render.chunk.ChunkRenderTask; +import net.minecraft.client.render.chunk.ChunkRenderWorker; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(ChunkRenderWorker.class) +public abstract class MixinChunkRenderWorker implements MCVer.ChunkRenderWorkerAccessor { + @Shadow abstract void runTask(ChunkRenderTask task) throws InterruptedException; + + public void doRunTask(ChunkRenderTask task) throws InterruptedException { + runTask(task); + } +} +//#endif From cf1d7537e8108b363833b2b033da22f8050bad76 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 18:37:06 +0100 Subject: [PATCH 047/102] Move MixinEffectRenderer into 1.8.9 project --- .../render/mixin/MixinEffectRenderer.java | 104 +----------------- .../render/mixin/MixinEffectRenderer.java | 101 +++++++++++++++++ 2 files changed, 102 insertions(+), 103 deletions(-) create mode 100644 versions/1.8.9/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java diff --git a/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java b/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java index 9a9269f8..3387d168 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java +++ b/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java @@ -1,103 +1 @@ -package com.replaymod.render.mixin; - -//#if MC<10904 -//$$ import com.replaymod.render.blend.BlendState; -//$$ import com.replaymod.render.hooks.EntityRendererHandler; -//$$ import net.minecraft.client.Minecraft; -//$$ import net.minecraft.client.particle.EffectRenderer; -//$$ import net.minecraft.client.particle.EntityFX; -//$$ import net.minecraft.entity.Entity; -//$$ import org.spongepowered.asm.mixin.Mixin; -//$$ import org.spongepowered.asm.mixin.injection.At; -//$$ import org.spongepowered.asm.mixin.injection.Redirect; -//$$ -//#if MC>=10800 -//$$ import com.replaymod.render.blend.exporters.ParticlesExporter; -//$$ import net.minecraft.client.renderer.WorldRenderer; -//#else -//$$ import net.minecraft.client.renderer.Tessellator; -//#endif -//$$ -//$$ @Mixin(EffectRenderer.class) -//$$ public abstract class MixinEffectRenderer { - //#if MC>=10800 - //#if MC>=10809 - //$$ @Redirect(method = "renderParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;renderParticle(Lnet/minecraft/client/renderer/WorldRenderer;Lnet/minecraft/entity/Entity;FFFFFF)V")) - //#else - //$$ @Redirect(method = "renderParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;func_180434_a(Lnet/minecraft/client/renderer/WorldRenderer;Lnet/minecraft/entity/Entity;FFFFFF)V")) - //#endif - //$$ private void renderNormalParticle(EntityFX fx, WorldRenderer worldRenderer, Entity view, float partialTicks, - //$$ float rotX, float rotXZ, float rotZ, float rotYZ, float rotXY) { - //$$ renderParticle(fx, worldRenderer, view, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); - //$$ } - //#else - //$$ @Redirect(method = "renderParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;renderParticle(Lnet/minecraft/client/renderer/Tessellator;FFFFFF)V")) - //$$ private void renderNormalParticle(EntityFX fx, Tessellator tesselator, float partialTicks, - //$$ float rotX, float rotXZ, float rotZ, float rotYZ, float rotXY) { - //$$ renderParticle(fx, tesselator, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); - //$$ } - //#endif -//$$ - //#if MC>=10800 - //#if MC>=10809 - //$$ @Redirect(method = "renderLitParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;renderParticle(Lnet/minecraft/client/renderer/WorldRenderer;Lnet/minecraft/entity/Entity;FFFFFF)V")) - //#else - //$$ @Redirect(method = "renderLitParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;func_180434_a(Lnet/minecraft/client/renderer/WorldRenderer;Lnet/minecraft/entity/Entity;FFFFFF)V")) - //#endif - //$$ private void renderLitParticle(EntityFX fx, WorldRenderer worldRenderer, Entity view, float partialTicks, - //$$ float rotX, float rotXZ, float rotZ, float rotYZ, float rotXY) { - //$$ renderParticle(fx, worldRenderer, view, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); - //$$ } - //#else - //$$ @Redirect(method = "renderLitParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;renderParticle(Lnet/minecraft/client/renderer/Tessellator;FFFFFF)V")) - //$$ private void renderLitParticle(EntityFX fx, Tessellator tessellator, float partialTicks, - //$$ float rotX, float rotXZ, float rotZ, float rotYZ, float rotXY) { - //$$ renderParticle(fx, tessellator, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); - //$$ } - //#endif -//$$ -//$$ private void renderParticle(EntityFX fx, - //#if MC>=10800 - //$$ WorldRenderer worldRenderer, Entity view, - //#else - //$$ Tessellator tessellator, - //#endif -//$$ float partialTicks, -//$$ float rotX, float rotXZ, float rotZ, float rotYZ, float rotXY) { -//$$ EntityRendererHandler handler = ((EntityRendererHandler.IEntityRenderer) Minecraft.getMinecraft().entityRenderer).replayModRender_getHandler(); -//$$ if (handler != null && handler.omnidirectional) { - //#if MC<=10710 - //$$ Entity view = Minecraft.getMinecraft().renderViewEntity; - //#endif -//$$ // Align all particles towards the camera -//$$ double dx = fx.prevPosX + (fx.posX - fx.prevPosX) * partialTicks - view.posX; -//$$ double dy = fx.prevPosY + (fx.posY - fx.prevPosY) * partialTicks - view.posY; -//$$ double dz = fx.prevPosZ + (fx.posZ - fx.prevPosZ) * partialTicks - view.posZ; -//$$ double pitch = -Math.atan2(dy, Math.sqrt(dx * dx + dz * dz)); -//$$ double yaw = -Math.atan2(dx, dz); -//$$ -//$$ rotX = (float) Math.cos(yaw); -//$$ rotZ = (float) Math.sin(yaw); -//$$ rotXZ = (float) Math.cos(pitch); -//$$ -//$$ rotYZ = (float) (-rotZ * Math.sin(pitch)); -//$$ rotXY = (float) (rotX * Math.sin(pitch)); -//$$ } - //#if MC>=10800 - //$$ BlendState blendState = BlendState.getState(); - //$$ if (blendState != null) { - //$$ blendState.get(ParticlesExporter.class).onRender(fx, partialTicks); - //$$ } - //#endif - //#if MC>=10809 - //$$ fx.renderParticle(worldRenderer, view, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); - //#else - //#if MC>=10800 - //$$ fx.func_180434_a(worldRenderer, view, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); - //#else - //$$ fx.renderParticle(tessellator, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); - //#endif - //#endif -//$$ } -//$$ } -//#endif +// 1.8.9 and below diff --git a/versions/1.8.9/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java b/versions/1.8.9/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java new file mode 100644 index 00000000..a7dd45eb --- /dev/null +++ b/versions/1.8.9/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java @@ -0,0 +1,101 @@ +package com.replaymod.render.mixin; + +import com.replaymod.render.blend.BlendState; +import com.replaymod.render.hooks.EntityRendererHandler; +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.EffectRenderer; +import net.minecraft.client.particle.EntityFX; +import net.minecraft.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +//#if MC>=10800 +import com.replaymod.render.blend.exporters.ParticlesExporter; +import net.minecraft.client.renderer.WorldRenderer; +//#else +//$$ import net.minecraft.client.renderer.Tessellator; +//#endif + +@Mixin(EffectRenderer.class) +public abstract class MixinEffectRenderer { + //#if MC>=10800 + //#if MC>=10809 + @Redirect(method = "renderParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;renderParticle(Lnet/minecraft/client/renderer/WorldRenderer;Lnet/minecraft/entity/Entity;FFFFFF)V")) + //#else + //$$ @Redirect(method = "renderParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;func_180434_a(Lnet/minecraft/client/renderer/WorldRenderer;Lnet/minecraft/entity/Entity;FFFFFF)V")) + //#endif + private void renderNormalParticle(EntityFX fx, WorldRenderer worldRenderer, Entity view, float partialTicks, + float rotX, float rotXZ, float rotZ, float rotYZ, float rotXY) { + renderParticle(fx, worldRenderer, view, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); + } + //#else + //$$ @Redirect(method = "renderParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;renderParticle(Lnet/minecraft/client/renderer/Tessellator;FFFFFF)V")) + //$$ private void renderNormalParticle(EntityFX fx, Tessellator tesselator, float partialTicks, + //$$ float rotX, float rotXZ, float rotZ, float rotYZ, float rotXY) { + //$$ renderParticle(fx, tesselator, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); + //$$ } + //#endif + + //#if MC>=10800 + //#if MC>=10809 + @Redirect(method = "renderLitParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;renderParticle(Lnet/minecraft/client/renderer/WorldRenderer;Lnet/minecraft/entity/Entity;FFFFFF)V")) + //#else + //$$ @Redirect(method = "renderLitParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;func_180434_a(Lnet/minecraft/client/renderer/WorldRenderer;Lnet/minecraft/entity/Entity;FFFFFF)V")) + //#endif + private void renderLitParticle(EntityFX fx, WorldRenderer worldRenderer, Entity view, float partialTicks, + float rotX, float rotXZ, float rotZ, float rotYZ, float rotXY) { + renderParticle(fx, worldRenderer, view, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); + } + //#else + //$$ @Redirect(method = "renderLitParticles", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;renderParticle(Lnet/minecraft/client/renderer/Tessellator;FFFFFF)V")) + //$$ private void renderLitParticle(EntityFX fx, Tessellator tessellator, float partialTicks, + //$$ float rotX, float rotXZ, float rotZ, float rotYZ, float rotXY) { + //$$ renderParticle(fx, tessellator, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); + //$$ } + //#endif + + private void renderParticle(EntityFX fx, + //#if MC>=10800 + WorldRenderer worldRenderer, Entity view, + //#else + //$$ Tessellator tessellator, + //#endif + float partialTicks, + float rotX, float rotXZ, float rotZ, float rotYZ, float rotXY) { + EntityRendererHandler handler = ((EntityRendererHandler.IEntityRenderer) Minecraft.getMinecraft().entityRenderer).replayModRender_getHandler(); + if (handler != null && handler.omnidirectional) { + //#if MC<=10710 + //$$ Entity view = Minecraft.getMinecraft().renderViewEntity; + //#endif + // Align all particles towards the camera + double dx = fx.prevPosX + (fx.posX - fx.prevPosX) * partialTicks - view.posX; + double dy = fx.prevPosY + (fx.posY - fx.prevPosY) * partialTicks - view.posY; + double dz = fx.prevPosZ + (fx.posZ - fx.prevPosZ) * partialTicks - view.posZ; + double pitch = -Math.atan2(dy, Math.sqrt(dx * dx + dz * dz)); + double yaw = -Math.atan2(dx, dz); + + rotX = (float) Math.cos(yaw); + rotZ = (float) Math.sin(yaw); + rotXZ = (float) Math.cos(pitch); + + rotYZ = (float) (-rotZ * Math.sin(pitch)); + rotXY = (float) (rotX * Math.sin(pitch)); + } + //#if MC>=10800 + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(ParticlesExporter.class).onRender(fx, partialTicks); + } + //#endif + //#if MC>=10809 + fx.renderParticle(worldRenderer, view, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); + //#else + //#if MC>=10800 + //$$ fx.func_180434_a(worldRenderer, view, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); + //#else + //$$ fx.renderParticle(tessellator, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); + //#endif + //#endif + } +} From e7a1fafdf91f64134db30d8143a97717f9b56430 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 19:21:54 +0100 Subject: [PATCH 048/102] Extract Mixin_ChromaKeyDisableFog from other mixins --- .../render/mixin/MixinEntityRenderer.java | 11 ----------- ...er.java => Mixin_ChromaKeyDisableFog.java} | 8 +------- .../resources/mixins.render.replaymod.json | 4 +--- .../mixin/Mixin_ChromaKeyDisableFog.java | 19 +++++++++++++++++++ 4 files changed, 21 insertions(+), 21 deletions(-) rename src/main/java/com/replaymod/render/mixin/{MixinFogRenderer.java => Mixin_ChromaKeyDisableFog.java} (87%) create mode 100644 versions/1.12.2/src/main/java/com/replaymod/render/mixin/Mixin_ChromaKeyDisableFog.java diff --git a/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java b/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java index ddf431ea..a2161e3d 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java +++ b/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java @@ -84,17 +84,6 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti //$$ } //#endif - // Moved to MixinFogRenderer in 1.13 - //#if MC<11400 - //$$ @Inject(method = "setupFog", at = @At("HEAD"), cancellable = true) - //$$ private void replayModRender_onSetupFog(int fogDistanceFlag, float partialTicks, CallbackInfo ci) { - //$$ if (replayModRender_handler == null) return; - //$$ if (replayModRender_handler.getSettings().getChromaKeyingColor() != null) { - //$$ ci.cancel(); - //$$ } - //$$ } - //#endif - @Inject(method = "renderHand", at = @At("HEAD"), cancellable = true) private void replayModRender_renderSpectatorHand( //#if MC>=11500 diff --git a/src/main/java/com/replaymod/render/mixin/MixinFogRenderer.java b/src/main/java/com/replaymod/render/mixin/Mixin_ChromaKeyDisableFog.java similarity index 87% rename from src/main/java/com/replaymod/render/mixin/MixinFogRenderer.java rename to src/main/java/com/replaymod/render/mixin/Mixin_ChromaKeyDisableFog.java index 8249e6c8..48719c54 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinFogRenderer.java +++ b/src/main/java/com/replaymod/render/mixin/Mixin_ChromaKeyDisableFog.java @@ -1,4 +1,3 @@ -//#if MC>=11400 package com.replaymod.render.mixin; import com.replaymod.core.versions.MCVer; @@ -9,12 +8,8 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -//#if MC>=11400 -import net.minecraft.client.render.Camera; -//#endif - @Mixin(BackgroundRenderer.class) -public abstract class MixinFogRenderer { +public abstract class Mixin_ChromaKeyDisableFog { @Inject(method = "applyFog", at = @At("HEAD"), cancellable = true) private //#if MC>=11500 @@ -29,4 +24,3 @@ public abstract class MixinFogRenderer { } } } -//#endif diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index 3e47b65d..c22eb4f9 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -5,6 +5,7 @@ "server": [], "client": [ "Mixin_ChromaKeyColorSky", + "Mixin_ChromaKeyDisableFog", "Mixin_ChromaKeyForceSky", "Mixin_CubicRotation", "Mixin_SkipBlockOutlinesDuringRender", @@ -31,9 +32,6 @@ //#endif "MixinCamera", "MixinEntityRenderer", - //#if MC>=11400 - "MixinFogRenderer", - //#endif //#if MC>=10800 "MixinGlStateManager", //#endif diff --git a/versions/1.12.2/src/main/java/com/replaymod/render/mixin/Mixin_ChromaKeyDisableFog.java b/versions/1.12.2/src/main/java/com/replaymod/render/mixin/Mixin_ChromaKeyDisableFog.java new file mode 100644 index 00000000..e3c1e00c --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/render/mixin/Mixin_ChromaKeyDisableFog.java @@ -0,0 +1,19 @@ +package com.replaymod.render.mixin; + +import com.replaymod.render.hooks.EntityRendererHandler; +import net.minecraft.client.renderer.EntityRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(EntityRenderer.class) +public abstract class Mixin_ChromaKeyDisableFog implements EntityRendererHandler.IEntityRenderer { + @Inject(method = "setupFog", at = @At("HEAD"), cancellable = true) + private void replayModRender_onSetupFog(int fogDistanceFlag, float partialTicks, CallbackInfo ci) { + EntityRendererHandler handler = replayModRender_getHandler(); + if (handler != null && handler.getSettings().getChromaKeyingColor() != null) { + ci.cancel(); + } + } +} From fad89626e5f060df90d2ad8ba29b3ce157f80b8f Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 19:45:00 +0100 Subject: [PATCH 049/102] Move 1.7.10 code from MixinEntityRenderer to Mixin_ForceChunkLoading --- .../render/mixin/MixinEntityRenderer.java | 11 -------- .../resources/mixins.render.replaymod.json | 2 +- .../render/hooks/ForceChunkLoadingHook.java | 6 +++++ .../render/mixin/Mixin_ForceChunkLoading.java | 27 +++++++++++++++++++ 4 files changed, 34 insertions(+), 12 deletions(-) create mode 100644 versions/1.7.10/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java diff --git a/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java b/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java index a2161e3d..348f86e8 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java +++ b/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java @@ -73,17 +73,6 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti return replayModRender_handler; } - //#if MC<=10710 - //$$ @Redirect(method = "renderWorld", at = @At(value = "INVOKE",target = - //$$ "Lnet/minecraft/client/renderer/RenderGlobal;updateRenderers(Lnet/minecraft/entity/EntityLivingBase;Z)Z")) - //$$ private boolean replayModRender_updateAllChunks(RenderGlobal self, EntityLivingBase view, boolean renderAllChunks) { - //$$ if (replayModRender_handler != null) { - //$$ renderAllChunks = true; - //$$ } - //$$ return self.updateRenderers(view, renderAllChunks); - //$$ } - //#endif - @Inject(method = "renderHand", at = @At("HEAD"), cancellable = true) private void replayModRender_renderSpectatorHand( //#if MC>=11500 diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index c22eb4f9..72c246e8 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -8,6 +8,7 @@ "Mixin_ChromaKeyDisableFog", "Mixin_ChromaKeyForceSky", "Mixin_CubicRotation", + "Mixin_ForceChunkLoading", "Mixin_SkipBlockOutlinesDuringRender", //#if MC>=10800 //#if MC>=11500 @@ -16,7 +17,6 @@ //$$ "ChunkRenderDispatcherAccessor", //$$ "MixinChunkRenderWorker", //#endif - "Mixin_ForceChunkLoading", //#endif //#if MC>=11400 "Mixin_PreserveDepthDuringHandRendering", diff --git a/versions/1.7.10/src/main/java/com/replaymod/render/hooks/ForceChunkLoadingHook.java b/versions/1.7.10/src/main/java/com/replaymod/render/hooks/ForceChunkLoadingHook.java index 670c7426..eb4134eb 100644 --- a/versions/1.7.10/src/main/java/com/replaymod/render/hooks/ForceChunkLoadingHook.java +++ b/versions/1.7.10/src/main/java/com/replaymod/render/hooks/ForceChunkLoadingHook.java @@ -3,9 +3,15 @@ package com.replaymod.render.hooks; import net.minecraft.client.renderer.RenderGlobal; public class ForceChunkLoadingHook { + private final RenderGlobal hooked; + public ForceChunkLoadingHook(RenderGlobal renderGlobal) { + this.hooked = renderGlobal; + + IForceChunkLoading.from(renderGlobal).replayModRender_setHook(this); } public void uninstall() { + IForceChunkLoading.from(hooked).replayModRender_setHook(null); } } diff --git a/versions/1.7.10/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java b/versions/1.7.10/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java new file mode 100644 index 00000000..3d319182 --- /dev/null +++ b/versions/1.7.10/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java @@ -0,0 +1,27 @@ +package com.replaymod.render.mixin; + +import com.replaymod.render.hooks.ForceChunkLoadingHook; +import com.replaymod.render.hooks.IForceChunkLoading; +import net.minecraft.client.renderer.RenderGlobal; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Mixin(RenderGlobal.class) +public abstract class Mixin_ForceChunkLoading implements IForceChunkLoading { + private ForceChunkLoadingHook replayModRender_hook; + + @Override + public void replayModRender_setHook(ForceChunkLoadingHook hook) { + this.replayModRender_hook = hook; + } + + @ModifyVariable(method = "updateRenderers", at = @At("HEAD"), argsOnly = true) + private boolean replayModRender_updateAllChunks(boolean renderAllChunks) { + if (replayModRender_hook != null) { + renderAllChunks = true; + } + return renderAllChunks; + } +} + From 3ec81d5c35b9c08748ce6bb73e54383fa8f24849 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 20:45:19 +0100 Subject: [PATCH 050/102] Split MixinEntityRenderer into multiple, more focused files --- .../render/mixin/MixinEntityRenderer.java | 240 +----------------- .../mixin/Mixin_Omnidirectional_Camera.java | 24 ++ .../mixin/Mixin_Omnidirectional_SkipHand.java | 34 +++ .../mixin/Mixin_Stereoscopic_Camera.java | 42 +++ .../Mixin_Stereoscopic_HandRenderPass.java | 10 + .../resources/mixins.render.replaymod.json | 4 + .../mixin/Mixin_Omnidirectional_Camera.java | 40 +++ .../Mixin_Stereoscopic_HandRenderPass.java | 29 +++ .../mixin/Mixin_Omnidirectional_Camera.java | 34 +++ .../mixin/Mixin_Stereoscopic_Camera.java | 43 ++++ 10 files changed, 262 insertions(+), 238 deletions(-) create mode 100644 src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Camera.java create mode 100644 src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_SkipHand.java create mode 100644 src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_Camera.java create mode 100644 src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_HandRenderPass.java create mode 100644 versions/1.12.2/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Camera.java create mode 100644 versions/1.12.2/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_HandRenderPass.java create mode 100644 versions/1.14.4/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Camera.java create mode 100644 versions/1.14.4/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_Camera.java diff --git a/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java b/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java index 348f86e8..559f2336 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java +++ b/src/main/java/com/replaymod/render/mixin/MixinEntityRenderer.java @@ -1,66 +1,11 @@ package com.replaymod.render.mixin; -import com.replaymod.core.versions.MCVer; -import com.replaymod.render.capturer.StereoscopicOpenGlFrameCapturer; import com.replaymod.render.hooks.EntityRendererHandler; -import net.minecraft.client.MinecraftClient; -import net.minecraft.entity.player.PlayerEntity; -import org.lwjgl.opengl.GL11; -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.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -//#if MC>=11500 -import net.minecraft.client.util.math.MatrixStack; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -//#endif - -//#if MC>=11400 -import net.minecraft.client.render.Camera; -import net.minecraft.util.hit.HitResult; -//#endif - -//#if MC>=11400 -import net.minecraft.client.options.GameOptions; import net.minecraft.client.render.GameRenderer; -import net.minecraft.util.math.Matrix4f; -import net.minecraft.client.render.WorldRenderer; -//#else -//$$ import com.replaymod.replay.camera.CameraEntity; -//$$ import net.minecraft.client.renderer.EntityRenderer; -//$$ import net.minecraft.client.renderer.RenderGlobal; -//$$ import net.minecraft.client.settings.GameSettings; -//$$ import net.minecraft.entity.Entity; -//$$ import org.lwjgl.util.glu.Project; -//#endif +import org.spongepowered.asm.mixin.Mixin; -//#if MC>=10904 -import net.minecraft.world.RaycastContext; -//#else -//$$ import net.minecraft.util.MovingObjectPosition; -//#endif - -//#if MC>=10800 -import com.mojang.blaze3d.platform.GlStateManager; -//#else -//$$ import net.minecraft.entity.EntityLivingBase; -//$$ import com.replaymod.core.versions.MCVer.GlStateManager; -//#endif - -import static com.replaymod.core.versions.MCVer.*; - -//#if MC>=11400 -@Mixin(value = GameRenderer.class) -//#else -//$$ @Mixin(value = EntityRenderer.class) -//#endif +@Mixin(GameRenderer.class) public abstract class MixinEntityRenderer implements EntityRendererHandler.IEntityRenderer { - @Shadow - public MinecraftClient client; - private EntityRendererHandler replayModRender_handler; @Override @@ -72,185 +17,4 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti public EntityRendererHandler replayModRender_getHandler() { return replayModRender_handler; } - - @Inject(method = "renderHand", at = @At("HEAD"), cancellable = true) - private void replayModRender_renderSpectatorHand( - //#if MC>=11500 - MatrixStack matrixStack, - //#endif - //#if MC>=11400 - Camera camera, - //#endif - float partialTicks, - //#if MC<11400 - //$$ int renderPass, - //#endif - CallbackInfo ci - ) { - if (replayModRender_handler != null) { - if (replayModRender_handler.omnidirectional) { - // No spectator hands during 360° view, we wouldn't even know where to put it - ci.cancel(); - //#if MC>=11400 - } - //#else - //$$ } else { - //$$ Entity currentEntity = this.mc.getRenderViewEntity(); - //$$ if (currentEntity instanceof EntityPlayer && !(currentEntity instanceof CameraEntity)) { - //$$ if (renderPass == 2) { // Need to update render pass - //$$ renderPass = replayModRender_handler.data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE ? 1 : 0; - //$$ renderHand(partialTicks, renderPass); - //$$ ci.cancel(); - //$$ } // else, render normally - //$$ } - //$$ } - //#endif - } - } - - //#if MC<11400 - //$$ @Shadow - //$$ public abstract void renderHand(float partialTicks, int renderPass); - //#endif - - /* - * Stereoscopic Renderer - */ - - //#if MC>=11500 - @Inject(method = "method_22973", at = @At("RETURN"), cancellable = true) - private void replayModRender_setupStereoscopicProjection(CallbackInfoReturnable ci) { - if (replayModRender_getHandler() != null) { - Matrix4f offset; - if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE) { - offset = Matrix4f.translate(0.07f, 0, 0); - } else if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.RIGHT_EYE) { - offset = Matrix4f.translate(-0.07f, 0, 0); - } else { - return; - } - offset.multiply(ci.getReturnValue()); - ci.setReturnValue(offset); - } - } - //#else - //#if MC>=10800 - //$$ @Inject(method = "applyCameraTransformations", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/GlStateManager;loadIdentity()V", shift = At.Shift.AFTER, ordinal = 0)) - //#else - //$$ @Inject(method = "setupCameraTransform", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glLoadIdentity()V", shift = At.Shift.AFTER, ordinal = 0, remap = false)) - //#endif - //$$ private void replayModRender_setupStereoscopicProjection( - //$$ float partialTicks, - //#if MC<11400 - //$$ int renderPass, - //#endif - //$$ CallbackInfo ci - //$$ ) { - //$$ if (replayModRender_getHandler() != null) { - //$$ if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE) { - //$$ GL11.glTranslatef(0.07f, 0, 0); - //$$ } else if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.RIGHT_EYE) { - //$$ GL11.glTranslatef(-0.07f, 0, 0); - //$$ } - //$$ } - //$$ } - //#endif - - //#if MC>=11500 - @Inject(method = "renderWorld", at = @At("HEAD")) - private void replayModRender_setupStereoscopicProjection(float partialTicks, long frameStartNano, MatrixStack matrixStack, CallbackInfo ci) { - if (replayModRender_getHandler() != null) { - if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE) { - matrixStack.translate(0.1, 0, 0); - } else if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.RIGHT_EYE) { - matrixStack.translate(-0.1, 0, 0); - } - } - } - //#else - //#if MC>=10800 - //$$ @Inject(method = "applyCameraTransformations", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/GlStateManager;loadIdentity()V", shift = At.Shift.AFTER, ordinal = 1)) - //#else - //$$ @Inject(method = "setupCameraTransform", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glLoadIdentity()V", shift = At.Shift.AFTER, ordinal = 1, remap = false)) - //#endif - //$$ private void replayModRender_setupStereoscopicModelView( - //$$ float partialTicks, - //#if MC<11400 - //$$ int renderPass, - //#endif - //$$ CallbackInfo ci - //$$ ) { - //$$ if (replayModRender_getHandler() != null) { - //$$ if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE) { - //$$ GL11.glTranslatef(0.1f, 0, 0); - //$$ } else if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.RIGHT_EYE) { - //$$ GL11.glTranslatef(-0.1f, 0, 0); - //$$ } - //$$ } - //$$ } - //#endif - - /* - * Cubic Renderer - */ - - //#if MC>=11400 - @Redirect(method = "method_22973", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/math/Matrix4f;viewboxMatrix(DFFF)Lnet/minecraft/util/math/Matrix4f;")) - private Matrix4f replayModRender_perspective$0(double fovY, float aspect, float zNear, float zFar) { - return replayModRender_perspective((float) fovY, aspect, zNear, zFar); - } - - //#if MC<11500 - //#if MC>=11400 - //$$ @Redirect(method = "renderCenter", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/math/Matrix4f;method_4929(DFFF)Lnet/minecraft/client/util/math/Matrix4f;")) - //#else - //$$ @Redirect(method = "updateCameraAndRender(FJ)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/Matrix4f;perspective(DFFF)Lnet/minecraft/client/renderer/Matrix4f;")) - //#endif - //$$ private Matrix4f replayModRender_perspective$1(double fovY, float aspect, float zNear, float zFar) { - //$$ return replayModRender_perspective((float) fovY, aspect, zNear, zFar); - //$$ } - //$$ - //$$ @Redirect(method = "renderAboveClouds", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/math/Matrix4f;method_4929(DFFF)Lnet/minecraft/client/util/math/Matrix4f;")) - //$$ private Matrix4f replayModRender_perspective$2(double fovY, float aspect, float zNear, float zFar) { - //$$ return replayModRender_perspective((float) fovY, aspect, zNear, zFar); - //$$ } - //#endif - - private Matrix4f replayModRender_perspective(float fovY, float aspect, float zNear, float zFar) { - if (replayModRender_getHandler() != null && replayModRender_getHandler().omnidirectional) { - fovY = 90; - aspect = 1; - } - return Matrix4f.viewboxMatrix(fovY, aspect, zNear, zFar); - } - //#else - //$$ @Redirect(method = "setupCameraTransform", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false)) - //$$ private void replayModRender_gluPerspective$0(float fovY, float aspect, float zNear, float zFar) { - //$$ replayModRender_gluPerspective(fovY, aspect, zNear, zFar); - //$$ } - //$$ - //#if MC>=10800 - //$$ @Redirect(method = "renderWorldPass", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false)) - //#else - //$$ @Redirect(method = "renderHand", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false)) - //#endif - //$$ private void replayModRender_gluPerspective$1(float fovY, float aspect, float zNear, float zFar) { - //$$ replayModRender_gluPerspective(fovY, aspect, zNear, zFar); - //$$ } - //$$ - //#if MC>=10800 - //$$ @Redirect(method = "renderCloudsCheck", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false)) - //$$ private void replayModRender_gluPerspective$2(float fovY, float aspect, float zNear, float zFar) { - //$$ replayModRender_gluPerspective(fovY, aspect, zNear, zFar); - //$$ } - //#endif - //$$ - //$$ private void replayModRender_gluPerspective(float fovY, float aspect, float zNear, float zFar) { - //$$ if (replayModRender_getHandler() != null && replayModRender_getHandler().omnidirectional) { - //$$ fovY = 90; - //$$ aspect = 1; - //$$ } - //$$ Project.gluPerspective(fovY, aspect, zNear, zFar); - //$$ } - //#endif } diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Camera.java b/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Camera.java new file mode 100644 index 00000000..fb58ab87 --- /dev/null +++ b/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Camera.java @@ -0,0 +1,24 @@ +package com.replaymod.render.mixin; + +import com.replaymod.render.hooks.EntityRendererHandler; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.util.math.Matrix4f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(GameRenderer.class) +public abstract class Mixin_Omnidirectional_Camera implements EntityRendererHandler.IEntityRenderer { + @Redirect(method = "method_22973", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/math/Matrix4f;viewboxMatrix(DFFF)Lnet/minecraft/util/math/Matrix4f;")) + private Matrix4f replayModRender_perspective$0(double fovY, float aspect, float zNear, float zFar) { + return replayModRender_perspective((float) fovY, aspect, zNear, zFar); + } + + private Matrix4f replayModRender_perspective(float fovY, float aspect, float zNear, float zFar) { + if (replayModRender_getHandler() != null && replayModRender_getHandler().omnidirectional) { + fovY = 90; + aspect = 1; + } + return Matrix4f.viewboxMatrix(fovY, aspect, zNear, zFar); + } +} diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_SkipHand.java b/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_SkipHand.java new file mode 100644 index 00000000..939f6ec8 --- /dev/null +++ b/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_SkipHand.java @@ -0,0 +1,34 @@ +package com.replaymod.render.mixin; + +import com.replaymod.render.hooks.EntityRendererHandler; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.util.math.MatrixStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(GameRenderer.class) +public abstract class Mixin_Omnidirectional_SkipHand implements EntityRendererHandler.IEntityRenderer { + @Inject(method = "renderHand", at = @At("HEAD"), cancellable = true) + private void replayModRender_renderSpectatorHand( + //#if MC>=11500 + MatrixStack matrixStack, + //#endif + //#if MC>=11400 + Camera camera, + //#endif + float partialTicks, + //#if MC<11400 + //$$ int renderPass, + //#endif + CallbackInfo ci + ) { + EntityRendererHandler handler = replayModRender_getHandler(); + if (handler != null && handler.omnidirectional) { + // No spectator hands during 360° view, we wouldn't even know where to put it + ci.cancel(); + } + } +} diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_Camera.java b/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_Camera.java new file mode 100644 index 00000000..945ac107 --- /dev/null +++ b/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_Camera.java @@ -0,0 +1,42 @@ +package com.replaymod.render.mixin; + +import com.replaymod.render.capturer.StereoscopicOpenGlFrameCapturer; +import com.replaymod.render.hooks.EntityRendererHandler; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.Matrix4f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(GameRenderer.class) +public abstract class Mixin_Stereoscopic_Camera implements EntityRendererHandler.IEntityRenderer { + @Inject(method = "method_22973", at = @At("RETURN"), cancellable = true) + private void replayModRender_setupStereoscopicProjection(CallbackInfoReturnable ci) { + if (replayModRender_getHandler() != null) { + Matrix4f offset; + if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE) { + offset = Matrix4f.translate(0.07f, 0, 0); + } else if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.RIGHT_EYE) { + offset = Matrix4f.translate(-0.07f, 0, 0); + } else { + return; + } + offset.multiply(ci.getReturnValue()); + ci.setReturnValue(offset); + } + } + + @Inject(method = "renderWorld", at = @At("HEAD")) + private void replayModRender_setupStereoscopicProjection(float partialTicks, long frameStartNano, MatrixStack matrixStack, CallbackInfo ci) { + if (replayModRender_getHandler() != null) { + if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE) { + matrixStack.translate(0.1, 0, 0); + } else if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.RIGHT_EYE) { + matrixStack.translate(-0.1, 0, 0); + } + } + } +} diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_HandRenderPass.java b/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_HandRenderPass.java new file mode 100644 index 00000000..c4facf6d --- /dev/null +++ b/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_HandRenderPass.java @@ -0,0 +1,10 @@ +package com.replaymod.render.mixin; + +import net.minecraft.client.render.GameRenderer; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(GameRenderer.class) +public abstract class Mixin_Stereoscopic_HandRenderPass { + // MC's builtin stereoscopic 3D feature was dropped + // 1.12.2 and before +} diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index 72c246e8..18efc908 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -9,7 +9,11 @@ "Mixin_ChromaKeyForceSky", "Mixin_CubicRotation", "Mixin_ForceChunkLoading", + "Mixin_Omnidirectional_Camera", + "Mixin_Omnidirectional_SkipHand", "Mixin_SkipBlockOutlinesDuringRender", + "Mixin_Stereoscopic_Camera", + "Mixin_Stereoscopic_HandRenderPass", //#if MC>=10800 //#if MC>=11500 "Mixin_BlockOnChunkRebuilds", diff --git a/versions/1.12.2/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Camera.java b/versions/1.12.2/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Camera.java new file mode 100644 index 00000000..9f7d56de --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Camera.java @@ -0,0 +1,40 @@ +package com.replaymod.render.mixin; + +import com.replaymod.render.hooks.EntityRendererHandler; +import net.minecraft.client.renderer.EntityRenderer; +import org.lwjgl.util.glu.Project; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(EntityRenderer.class) +public abstract class Mixin_Omnidirectional_Camera implements EntityRendererHandler.IEntityRenderer { + @Redirect(method = "setupCameraTransform", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false)) + private void replayModRender_gluPerspective$0(float fovY, float aspect, float zNear, float zFar) { + replayModRender_gluPerspective(fovY, aspect, zNear, zFar); + } + + //#if MC>=10800 + @Redirect(method = "renderWorldPass", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false)) + //#else + //$$ @Redirect(method = "renderHand", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false)) + //#endif + private void replayModRender_gluPerspective$1(float fovY, float aspect, float zNear, float zFar) { + replayModRender_gluPerspective(fovY, aspect, zNear, zFar); + } + + //#if MC>=10800 + @Redirect(method = "renderCloudsCheck", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false)) + private void replayModRender_gluPerspective$2(float fovY, float aspect, float zNear, float zFar) { + replayModRender_gluPerspective(fovY, aspect, zNear, zFar); + } + //#endif + + private void replayModRender_gluPerspective(float fovY, float aspect, float zNear, float zFar) { + if (replayModRender_getHandler() != null && replayModRender_getHandler().omnidirectional) { + fovY = 90; + aspect = 1; + } + Project.gluPerspective(fovY, aspect, zNear, zFar); + } +} diff --git a/versions/1.12.2/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_HandRenderPass.java b/versions/1.12.2/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_HandRenderPass.java new file mode 100644 index 00000000..5cf178a5 --- /dev/null +++ b/versions/1.12.2/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_HandRenderPass.java @@ -0,0 +1,29 @@ +package com.replaymod.render.mixin; + +import com.replaymod.render.capturer.StereoscopicOpenGlFrameCapturer; +import com.replaymod.render.hooks.EntityRendererHandler; +import com.replaymod.replay.camera.CameraEntity; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Mixin(EntityRenderer.class) +public abstract class Mixin_Stereoscopic_HandRenderPass implements EntityRendererHandler.IEntityRenderer { + @ModifyVariable(method = "renderHand", at = @At("HEAD"), argsOnly = true) + private int replayModRender_renderSpectatorHand(int renderPass) { + EntityRendererHandler handler = replayModRender_getHandler(); + if (handler != null) { + Entity currentEntity = Minecraft.getMinecraft().getRenderViewEntity(); + if (currentEntity instanceof EntityPlayer && !(currentEntity instanceof CameraEntity)) { + if (renderPass == 2) { // Need to update render pass + renderPass = handler.data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE ? 1 : 0; + } + } + } + return renderPass; + } +} diff --git a/versions/1.14.4/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Camera.java b/versions/1.14.4/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Camera.java new file mode 100644 index 00000000..6a0dd1e4 --- /dev/null +++ b/versions/1.14.4/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Camera.java @@ -0,0 +1,34 @@ +package com.replaymod.render.mixin; + +import com.replaymod.render.hooks.EntityRendererHandler; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.util.math.Matrix4f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(GameRenderer.class) +public abstract class Mixin_Omnidirectional_Camera implements EntityRendererHandler.IEntityRenderer { + @Redirect(method = "applyCameraTransformations", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/math/Matrix4f;method_4929(DFFF)Lnet/minecraft/client/util/math/Matrix4f;")) + private Matrix4f replayModRender_perspective$0(double fovY, float aspect, float zNear, float zFar) { + return replayModRender_perspective((float) fovY, aspect, zNear, zFar); + } + + @Redirect(method = "renderCenter", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/math/Matrix4f;method_4929(DFFF)Lnet/minecraft/client/util/math/Matrix4f;")) + private Matrix4f replayModRender_perspective$1(double fovY, float aspect, float zNear, float zFar) { + return replayModRender_perspective((float) fovY, aspect, zNear, zFar); + } + + @Redirect(method = "renderAboveClouds", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/math/Matrix4f;method_4929(DFFF)Lnet/minecraft/client/util/math/Matrix4f;")) + private Matrix4f replayModRender_perspective$2(double fovY, float aspect, float zNear, float zFar) { + return replayModRender_perspective((float) fovY, aspect, zNear, zFar); + } + + private Matrix4f replayModRender_perspective(float fovY, float aspect, float zNear, float zFar) { + if (replayModRender_getHandler() != null && replayModRender_getHandler().omnidirectional) { + fovY = 90; + aspect = 1; + } + return Matrix4f.method_4929(fovY, aspect, zNear, zFar); + } +} diff --git a/versions/1.14.4/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_Camera.java b/versions/1.14.4/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_Camera.java new file mode 100644 index 00000000..400e80e7 --- /dev/null +++ b/versions/1.14.4/src/main/java/com/replaymod/render/mixin/Mixin_Stereoscopic_Camera.java @@ -0,0 +1,43 @@ +package com.replaymod.render.mixin; + +import com.replaymod.render.capturer.StereoscopicOpenGlFrameCapturer; +import com.replaymod.render.hooks.EntityRendererHandler; +import net.minecraft.client.render.GameRenderer; +import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(GameRenderer.class) +public abstract class Mixin_Stereoscopic_Camera implements EntityRendererHandler.IEntityRenderer { + //#if MC>=10800 + @Inject(method = "applyCameraTransformations", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/GlStateManager;loadIdentity()V", shift = At.Shift.AFTER, ordinal = 0)) + //#else + //$$ @Inject(method = "setupCameraTransform", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glLoadIdentity()V", shift = At.Shift.AFTER, ordinal = 0, remap = false)) + //#endif + private void replayModRender_setupStereoscopicProjection(CallbackInfo ci) { + if (replayModRender_getHandler() != null) { + if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE) { + GL11.glTranslatef(0.07f, 0, 0); + } else if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.RIGHT_EYE) { + GL11.glTranslatef(-0.07f, 0, 0); + } + } + } + + //#if MC>=10800 + @Inject(method = "applyCameraTransformations", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/GlStateManager;loadIdentity()V", shift = At.Shift.AFTER, ordinal = 1)) + //#else + //$$ @Inject(method = "setupCameraTransform", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glLoadIdentity()V", shift = At.Shift.AFTER, ordinal = 1, remap = false)) + //#endif + private void replayModRender_setupStereoscopicModelView(CallbackInfo ci) { + if (replayModRender_getHandler() != null) { + if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE) { + GL11.glTranslatef(0.1f, 0, 0); + } else if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.RIGHT_EYE) { + GL11.glTranslatef(-0.1f, 0, 0); + } + } + } +} From 6974f8e60c07f17b1e48ab935aabcec486c01b26 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 20:54:27 +0100 Subject: [PATCH 051/102] Rename MixinCamera -> Mixin_StabilizeCamera --- .../mixin/{MixinCamera.java => Mixin_StabilizeCamera.java} | 2 +- src/main/resources/mixins.render.replaymod.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/main/java/com/replaymod/render/mixin/{MixinCamera.java => Mixin_StabilizeCamera.java} (99%) diff --git a/src/main/java/com/replaymod/render/mixin/MixinCamera.java b/src/main/java/com/replaymod/render/mixin/Mixin_StabilizeCamera.java similarity index 99% rename from src/main/java/com/replaymod/render/mixin/MixinCamera.java rename to src/main/java/com/replaymod/render/mixin/Mixin_StabilizeCamera.java index 126c3278..564c805c 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinCamera.java +++ b/src/main/java/com/replaymod/render/mixin/Mixin_StabilizeCamera.java @@ -24,7 +24,7 @@ import net.minecraft.world.BlockView; //#else //$$ @Mixin(value = EntityRenderer.class) //#endif -public abstract class MixinCamera { +public abstract class Mixin_StabilizeCamera { private EntityRendererHandler getHandler() { return ((EntityRendererHandler.IEntityRenderer) getMinecraft().gameRenderer).replayModRender_getHandler(); } diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index 18efc908..6fdb5b8c 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -12,6 +12,7 @@ "Mixin_Omnidirectional_Camera", "Mixin_Omnidirectional_SkipHand", "Mixin_SkipBlockOutlinesDuringRender", + "Mixin_StabilizeCamera", "Mixin_Stereoscopic_Camera", "Mixin_Stereoscopic_HandRenderPass", //#if MC>=10800 @@ -34,7 +35,6 @@ //$$ "MixinEffectRenderer", //$$ "MixinRendererLivingEntity", //#endif - "MixinCamera", "MixinEntityRenderer", //#if MC>=10800 "MixinGlStateManager", From db5708f338c0ad89eba791ef07d3ecc00a36613b Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 20:56:21 +0100 Subject: [PATCH 052/102] Rename MixinFrustum -> Mixin_Omnidirectional_DisableFrustumCulling --- ...um.java => Mixin_Omnidirectional_DisableFrustumCulling.java} | 2 +- src/main/resources/mixins.render.replaymod.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/main/java/com/replaymod/render/mixin/{MixinFrustum.java => Mixin_Omnidirectional_DisableFrustumCulling.java} (95%) diff --git a/src/main/java/com/replaymod/render/mixin/MixinFrustum.java b/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_DisableFrustumCulling.java similarity index 95% rename from src/main/java/com/replaymod/render/mixin/MixinFrustum.java rename to src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_DisableFrustumCulling.java index c23ac874..f174e0a3 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinFrustum.java +++ b/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_DisableFrustumCulling.java @@ -18,7 +18,7 @@ import net.minecraft.client.render.Frustum; //#else //$$ @Mixin(Frustrum.class) //#endif -public abstract class MixinFrustum { +public abstract class Mixin_Omnidirectional_DisableFrustumCulling { //#if MC>=11500 @Inject(method = "isAnyCornerVisible", at = @At("HEAD"), cancellable = true) //#else diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index 6fdb5b8c..0a7c2d54 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -10,6 +10,7 @@ "Mixin_CubicRotation", "Mixin_ForceChunkLoading", "Mixin_Omnidirectional_Camera", + "Mixin_Omnidirectional_DisableFrustumCulling", "Mixin_Omnidirectional_SkipHand", "Mixin_SkipBlockOutlinesDuringRender", "Mixin_StabilizeCamera", @@ -39,7 +40,6 @@ //#if MC>=10800 "MixinGlStateManager", //#endif - "MixinFrustum", "MixinRender", //#if MC>=10800 //#else From aba34d6c6fd0ea895c7af1e2d6fd13a6ac57fa67 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 20:58:10 +0100 Subject: [PATCH 053/102] Rename Mixin_CubicRotation -> Mixin_Omnidirectional_Rotation --- ...n_CubicRotation.java => Mixin_Omnidirectional_Rotation.java} | 2 +- src/main/resources/mixins.render.replaymod.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/main/java/com/replaymod/render/mixin/{Mixin_CubicRotation.java => Mixin_Omnidirectional_Rotation.java} (98%) diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_CubicRotation.java b/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Rotation.java similarity index 98% rename from src/main/java/com/replaymod/render/mixin/Mixin_CubicRotation.java rename to src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Rotation.java index 089d41fc..6107028e 100644 --- a/src/main/java/com/replaymod/render/mixin/Mixin_CubicRotation.java +++ b/src/main/java/com/replaymod/render/mixin/Mixin_Omnidirectional_Rotation.java @@ -25,7 +25,7 @@ import static com.replaymod.core.versions.MCVer.getMinecraft; //$$ @Mixin(value = net.minecraft.client.renderer.EntityRenderer.class) //#endif //#endif -public abstract class Mixin_CubicRotation { +public abstract class Mixin_Omnidirectional_Rotation { private EntityRendererHandler getHandler() { return ((EntityRendererHandler.IEntityRenderer) getMinecraft().gameRenderer).replayModRender_getHandler(); } diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index 0a7c2d54..c99b8a0e 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -7,10 +7,10 @@ "Mixin_ChromaKeyColorSky", "Mixin_ChromaKeyDisableFog", "Mixin_ChromaKeyForceSky", - "Mixin_CubicRotation", "Mixin_ForceChunkLoading", "Mixin_Omnidirectional_Camera", "Mixin_Omnidirectional_DisableFrustumCulling", + "Mixin_Omnidirectional_Rotation", "Mixin_Omnidirectional_SkipHand", "Mixin_SkipBlockOutlinesDuringRender", "Mixin_StabilizeCamera", From 1924963d75b9062f7bbff98da370ee3859b37c95 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 20:59:56 +0100 Subject: [PATCH 054/102] Move MixinOpenGlHelper into 1.7.10 project --- .../render/mixin/MixinOpenGlHelper.java | 19 +------------------ .../render/mixin/MixinOpenGlHelper.java | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 18 deletions(-) create mode 100644 versions/1.7.10/src/main/java/com/replaymod/render/mixin/MixinOpenGlHelper.java diff --git a/src/main/java/com/replaymod/render/mixin/MixinOpenGlHelper.java b/src/main/java/com/replaymod/render/mixin/MixinOpenGlHelper.java index 7c2380f2..743815c4 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinOpenGlHelper.java +++ b/src/main/java/com/replaymod/render/mixin/MixinOpenGlHelper.java @@ -1,18 +1 @@ -//#if MC<=10710 -//$$ package com.replaymod.render.mixin; -//$$ -//$$ import com.replaymod.render.hooks.GLStateTracker; -//$$ import net.minecraft.client.renderer.OpenGlHelper; -//$$ import org.spongepowered.asm.mixin.Mixin; -//$$ import org.spongepowered.asm.mixin.injection.At; -//$$ import org.spongepowered.asm.mixin.injection.Inject; -//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -//$$ -//$$ @Mixin(OpenGlHelper.class) -//$$ public abstract class MixinOpenGlHelper { -//$$ @Inject(method = "setActiveTexture", at = @At("RETURN")) -//$$ private static void replayModRender_trackActiveTexture(int magic, CallbackInfo ci) { -//$$ GLStateTracker.getInstance().updateActiveTexture(magic); -//$$ } -//$$ } -//#endif +// 1.7.10 and below diff --git a/versions/1.7.10/src/main/java/com/replaymod/render/mixin/MixinOpenGlHelper.java b/versions/1.7.10/src/main/java/com/replaymod/render/mixin/MixinOpenGlHelper.java new file mode 100644 index 00000000..8a20ca74 --- /dev/null +++ b/versions/1.7.10/src/main/java/com/replaymod/render/mixin/MixinOpenGlHelper.java @@ -0,0 +1,16 @@ +package com.replaymod.render.mixin; + +import com.replaymod.render.hooks.GLStateTracker; +import net.minecraft.client.renderer.OpenGlHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(OpenGlHelper.class) +public abstract class MixinOpenGlHelper { + @Inject(method = "setActiveTexture", at = @At("RETURN")) + private static void replayModRender_trackActiveTexture(int magic, CallbackInfo ci) { + GLStateTracker.getInstance().updateActiveTexture(magic); + } +} From c17fc79ab2fca925cf4639635774a871cce4b343 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 21:01:11 +0100 Subject: [PATCH 055/102] Rename MixinRender -> Mixin_HideNameTags --- .../render/mixin/{MixinRender.java => Mixin_HideNameTags.java} | 2 +- src/main/resources/mixins.render.replaymod.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/main/java/com/replaymod/render/mixin/{MixinRender.java => Mixin_HideNameTags.java} (96%) diff --git a/src/main/java/com/replaymod/render/mixin/MixinRender.java b/src/main/java/com/replaymod/render/mixin/Mixin_HideNameTags.java similarity index 96% rename from src/main/java/com/replaymod/render/mixin/MixinRender.java rename to src/main/java/com/replaymod/render/mixin/Mixin_HideNameTags.java index 39473e39..6377afda 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinRender.java +++ b/src/main/java/com/replaymod/render/mixin/Mixin_HideNameTags.java @@ -9,7 +9,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(EntityRenderer.class) -public abstract class MixinRender { +public abstract class Mixin_HideNameTags { //#if MC>=11500 @Inject(method = "renderLabelIfPresent", at = @At("HEAD"), cancellable = true) //#else diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index c99b8a0e..65cbba1c 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -8,6 +8,7 @@ "Mixin_ChromaKeyDisableFog", "Mixin_ChromaKeyForceSky", "Mixin_ForceChunkLoading", + "Mixin_HideNameTags", "Mixin_Omnidirectional_Camera", "Mixin_Omnidirectional_DisableFrustumCulling", "Mixin_Omnidirectional_Rotation", @@ -40,7 +41,6 @@ //#if MC>=10800 "MixinGlStateManager", //#endif - "MixinRender", //#if MC>=10800 //#else //$$ "MixinOpenGlHelper", From a97190de1e86e020e523758dca65b9d4b0b4c21d Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 21:04:39 +0100 Subject: [PATCH 056/102] Move MixinRendererLivingEntity into 1.8.9 project --- .../mixin/MixinRendererLivingEntity.java | 24 +------------------ .../mixin/MixinRendererLivingEntity.java | 21 ++++++++++++++++ 2 files changed, 22 insertions(+), 23 deletions(-) create mode 100644 versions/1.8.9/src/main/java/com/replaymod/render/mixin/MixinRendererLivingEntity.java diff --git a/src/main/java/com/replaymod/render/mixin/MixinRendererLivingEntity.java b/src/main/java/com/replaymod/render/mixin/MixinRendererLivingEntity.java index b936efda..3387d168 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinRendererLivingEntity.java +++ b/src/main/java/com/replaymod/render/mixin/MixinRendererLivingEntity.java @@ -1,23 +1 @@ -package com.replaymod.render.mixin; - -//#if MC<10904 -//$$ import com.replaymod.render.hooks.EntityRendererHandler; -//$$ import net.minecraft.client.Minecraft; -//$$ import net.minecraft.client.renderer.entity.RendererLivingEntity; -//$$ import net.minecraft.entity.EntityLivingBase; -//$$ import org.spongepowered.asm.mixin.Mixin; -//$$ import org.spongepowered.asm.mixin.injection.At; -//$$ import org.spongepowered.asm.mixin.injection.Inject; -//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -//$$ -//$$ @Mixin(RendererLivingEntity.class) -//$$ public abstract class MixinRendererLivingEntity { -//$$ @Inject(method = "canRenderName", at = @At("HEAD"), cancellable = true) -//$$ private void replayModRender_areAllNamesHidden(EntityLivingBase entity, CallbackInfoReturnable ci) { -//$$ EntityRendererHandler handler = ((EntityRendererHandler.IEntityRenderer) Minecraft.getMinecraft().entityRenderer).replayModRender_getHandler(); -//$$ if (handler != null && !handler.getSettings().isRenderNameTags()) { -//$$ ci.setReturnValue(false); //this calls the cancel method -//$$ } -//$$ } -//$$ } -//#endif +// 1.8.9 and below diff --git a/versions/1.8.9/src/main/java/com/replaymod/render/mixin/MixinRendererLivingEntity.java b/versions/1.8.9/src/main/java/com/replaymod/render/mixin/MixinRendererLivingEntity.java new file mode 100644 index 00000000..38cbe2ae --- /dev/null +++ b/versions/1.8.9/src/main/java/com/replaymod/render/mixin/MixinRendererLivingEntity.java @@ -0,0 +1,21 @@ +package com.replaymod.render.mixin; + +import com.replaymod.render.hooks.EntityRendererHandler; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.entity.RendererLivingEntity; +import net.minecraft.entity.EntityLivingBase; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(RendererLivingEntity.class) +public abstract class MixinRendererLivingEntity { + @Inject(method = "canRenderName", at = @At("HEAD"), cancellable = true) + private void replayModRender_areAllNamesHidden(EntityLivingBase entity, CallbackInfoReturnable ci) { + EntityRendererHandler handler = ((EntityRendererHandler.IEntityRenderer) Minecraft.getMinecraft().entityRenderer).replayModRender_getHandler(); + if (handler != null && !handler.getSettings().isRenderNameTags()) { + ci.setReturnValue(false); //this calls the cancel method + } + } +} From b7309283e9155eee4336161d8bcbc21ea48e4c88 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 21:09:53 +0100 Subject: [PATCH 057/102] Rename MixinRendererLivingEntity -> Mixin_HideNameTags_LivingEntity --- .../render/mixin/MixinRendererLivingEntity.java | 1 - .../render/mixin/Mixin_HideNameTags_LivingEntity.java | 9 +++++++++ src/main/resources/mixins.render.replaymod.json | 2 +- ...gEntity.java => Mixin_HideNameTags_LivingEntity.java} | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) delete mode 100644 src/main/java/com/replaymod/render/mixin/MixinRendererLivingEntity.java create mode 100644 src/main/java/com/replaymod/render/mixin/Mixin_HideNameTags_LivingEntity.java rename versions/1.8.9/src/main/java/com/replaymod/render/mixin/{MixinRendererLivingEntity.java => Mixin_HideNameTags_LivingEntity.java} (94%) diff --git a/src/main/java/com/replaymod/render/mixin/MixinRendererLivingEntity.java b/src/main/java/com/replaymod/render/mixin/MixinRendererLivingEntity.java deleted file mode 100644 index 3387d168..00000000 --- a/src/main/java/com/replaymod/render/mixin/MixinRendererLivingEntity.java +++ /dev/null @@ -1 +0,0 @@ -// 1.8.9 and below diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_HideNameTags_LivingEntity.java b/src/main/java/com/replaymod/render/mixin/Mixin_HideNameTags_LivingEntity.java new file mode 100644 index 00000000..cafbe9f8 --- /dev/null +++ b/src/main/java/com/replaymod/render/mixin/Mixin_HideNameTags_LivingEntity.java @@ -0,0 +1,9 @@ +package com.replaymod.render.mixin; + +import net.minecraft.client.render.entity.LivingEntityRenderer; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(LivingEntityRenderer.class) +public abstract class Mixin_HideNameTags_LivingEntity { + // 1.8.9 and below +} diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index 65cbba1c..a7a4bdb4 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -9,6 +9,7 @@ "Mixin_ChromaKeyForceSky", "Mixin_ForceChunkLoading", "Mixin_HideNameTags", + "Mixin_HideNameTags_LivingEntity", "Mixin_Omnidirectional_Camera", "Mixin_Omnidirectional_DisableFrustumCulling", "Mixin_Omnidirectional_Rotation", @@ -35,7 +36,6 @@ "MixinParticleManager", //#else //$$ "MixinEffectRenderer", - //$$ "MixinRendererLivingEntity", //#endif "MixinEntityRenderer", //#if MC>=10800 diff --git a/versions/1.8.9/src/main/java/com/replaymod/render/mixin/MixinRendererLivingEntity.java b/versions/1.8.9/src/main/java/com/replaymod/render/mixin/Mixin_HideNameTags_LivingEntity.java similarity index 94% rename from versions/1.8.9/src/main/java/com/replaymod/render/mixin/MixinRendererLivingEntity.java rename to versions/1.8.9/src/main/java/com/replaymod/render/mixin/Mixin_HideNameTags_LivingEntity.java index 38cbe2ae..edbd70ef 100644 --- a/versions/1.8.9/src/main/java/com/replaymod/render/mixin/MixinRendererLivingEntity.java +++ b/versions/1.8.9/src/main/java/com/replaymod/render/mixin/Mixin_HideNameTags_LivingEntity.java @@ -10,7 +10,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(RendererLivingEntity.class) -public abstract class MixinRendererLivingEntity { +public abstract class Mixin_HideNameTags_LivingEntity { @Inject(method = "canRenderName", at = @At("HEAD"), cancellable = true) private void replayModRender_areAllNamesHidden(EntityLivingBase entity, CallbackInfoReturnable ci) { EntityRendererHandler handler = ((EntityRendererHandler.IEntityRenderer) Minecraft.getMinecraft().entityRenderer).replayModRender_getHandler(); From 61d67a5e803ca645c1a6f7e57d958393fd218b6b Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 27 Feb 2021 21:28:47 +0100 Subject: [PATCH 058/102] Remove OpenEye (closes #465) It is not available for Fabric and we stopped using it. --- .../com/replaymod/extras/OpenEyeExtra.java | 164 ------------------ .../com/replaymod/extras/ReplayModExtras.java | 3 +- 2 files changed, 1 insertion(+), 166 deletions(-) delete mode 100644 src/main/java/com/replaymod/extras/OpenEyeExtra.java diff --git a/src/main/java/com/replaymod/extras/OpenEyeExtra.java b/src/main/java/com/replaymod/extras/OpenEyeExtra.java deleted file mode 100644 index 688c3e9b..00000000 --- a/src/main/java/com/replaymod/extras/OpenEyeExtra.java +++ /dev/null @@ -1,164 +0,0 @@ -package com.replaymod.extras; - -import com.replaymod.core.ReplayMod; -import com.replaymod.core.versions.MCVer; -import de.johni0702.minecraft.gui.container.AbstractGuiScreen; -import de.johni0702.minecraft.gui.container.GuiContainer; -import de.johni0702.minecraft.gui.container.GuiPanel; -import de.johni0702.minecraft.gui.container.GuiScreen; -import de.johni0702.minecraft.gui.element.GuiButton; -import de.johni0702.minecraft.gui.element.GuiLabel; -import de.johni0702.minecraft.gui.function.Tickable; -import de.johni0702.minecraft.gui.layout.CustomLayout; -import de.johni0702.minecraft.gui.layout.HorizontalLayout; -import de.johni0702.minecraft.gui.layout.VerticalLayout; -import de.johni0702.minecraft.gui.popup.AbstractGuiPopup; -import de.johni0702.minecraft.gui.utils.Colors; -import org.apache.commons.io.FileUtils; - -import javax.net.ssl.HttpsURLConnection; -import java.io.File; -import java.io.FileOutputStream; -import java.net.URL; -import java.nio.channels.Channels; -import java.nio.channels.FileChannel; -import java.nio.channels.ReadableByteChannel; - -import static com.replaymod.core.utils.Utils.SSL_SOCKET_FACTORY; -import static com.replaymod.extras.ReplayModExtras.LOGGER; - -public class OpenEyeExtra implements Extra { - private URL url; - private ReplayMod mod; - - @Override - public void register(ReplayMod mod) throws Exception { - this.mod = mod; - this.url = new URL("https://www.replaymod.com/dl/openeye/" + mod.getMinecraftVersion()); - - boolean isOpenEyeLoaded = mod.isModLoaded("OpenEye"); - if (!isOpenEyeLoaded && mod.getSettingsRegistry().get(Setting.ASK_FOR_OPEN_EYE)) { - new Thread(() -> { - try { - LOGGER.trace("Checking for OpenEye availability"); - HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); - connection.setSSLSocketFactory(SSL_SOCKET_FACTORY); - connection.setRequestMethod("HEAD"); - connection.connect(); - LOGGER.trace("Got response code: {}", connection.getResponseCode()); - if (connection.getResponseCode() == 200) { - mod.runLater(() -> new OfferGui(GuiScreen.wrap(mod.getMinecraft().currentScreen)).display()); - } else { - LOGGER.info("Cannot offer OpenEye, server returned: {} {}", - connection.getResponseCode(), connection.getResponseMessage()); - } - connection.disconnect(); - } catch (Throwable e) { - LOGGER.error("Failed to check for OpenEye availability:", e); - } - }).start(); - } - } - - public class OfferGui extends AbstractGuiScreen { - public final GuiScreen parent; - public final GuiPanel textPanel = new GuiPanel().setLayout(new VerticalLayout().setSpacing(3)) - .addElements(new VerticalLayout.Data(0.5), - new GuiLabel().setI18nText("replaymod.gui.offeropeneye1"), - new GuiLabel().setI18nText("replaymod.gui.offeropeneye2"), - new GuiLabel().setI18nText("replaymod.gui.offeropeneye3"), - new GuiLabel().setI18nText("replaymod.gui.offeropeneye4"), - new GuiLabel().setI18nText("replaymod.gui.offeropeneye5"), - new GuiLabel().setI18nText("replaymod.gui.offeropeneye6"), - new GuiLabel().setI18nText("replaymod.gui.offeropeneye7"), - new GuiLabel().setI18nText("replaymod.gui.offeropeneye8")); - public final GuiPanel buttonPanel = new GuiPanel() - .setLayout(new HorizontalLayout(HorizontalLayout.Alignment.CENTER).setSpacing(5)); - public final GuiPanel contentPanel = new GuiPanel(this).setLayout(new VerticalLayout().setSpacing(20)) - .addElements(new VerticalLayout.Data(0.5), textPanel, buttonPanel); - public final GuiButton yesButton = new GuiButton(buttonPanel).setSize(150, 20).setI18nLabel("gui.yes"); - public final GuiButton noButton = new GuiButton(buttonPanel).setSize(150, 20).setI18nLabel("gui.no"); - - public OfferGui(GuiScreen parent) { - this.parent = parent; - - yesButton.onClick(() -> { - GuiPopup popup = new GuiPopup(OfferGui.this); - new Thread(() -> { - try { - File targetFile = new File(mod.getMinecraft().runDirectory, "mods/" + mod.getMinecraftVersion() + "/OpenEye.jar"); - FileUtils.forceMkdir(targetFile.getParentFile()); - - HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); - connection.setSSLSocketFactory(SSL_SOCKET_FACTORY); - ReadableByteChannel in = Channels.newChannel(connection.getInputStream()); - FileChannel out = new FileOutputStream(targetFile).getChannel(); - out.transferFrom(in, 0, Long.MAX_VALUE); - } catch (Throwable e) { - e.printStackTrace(); - } finally { - mod.runLater(() -> { - popup.close(); - parent.display(); - }); - } - }).start(); - }); - noButton.onClick(() -> { - mod.getSettingsRegistry().set(Setting.ASK_FOR_OPEN_EYE, false); - mod.getSettingsRegistry().save(); - parent.display(); - }); - - setLayout(new CustomLayout() { - @Override - protected void layout(OfferGui container, int width, int height) { - pos(contentPanel, width / 2 - width(contentPanel) / 2, height / 2 - height(contentPanel) / 2); - } - }); - } - - @Override - protected OfferGui getThis() { - return this; - } - } - - public static final class GuiPopup extends AbstractGuiPopup { - GuiPopup(GuiContainer container) { - super(container); - popup.addElements(null, new GuiIndicator().setColor(Colors.BLACK)); - setBackgroundColor(Colors.DARK_TRANSPARENT); - open(); - } - - @Override - public void close() { - super.close(); - } - - @Override - protected GuiPopup getThis() { - return this; - } - - private static final class GuiIndicator extends GuiLabel implements Tickable { - private int tick; - - @Override - public void tick() { - tick++; - setText(new String[]{ - "Ooooo", - "oOooo", - "ooOoo", - "oooOo", - "ooooO", - "oooOo", - "ooOoo", - "oOooo", - }[tick / 5 % 8]); - } - } - } -} diff --git a/src/main/java/com/replaymod/extras/ReplayModExtras.java b/src/main/java/com/replaymod/extras/ReplayModExtras.java index d22ed045..add19778 100644 --- a/src/main/java/com/replaymod/extras/ReplayModExtras.java +++ b/src/main/java/com/replaymod/extras/ReplayModExtras.java @@ -24,8 +24,7 @@ public class ReplayModExtras implements Module { YoutubeUpload.class, FullBrightness.class, QuickMode.class, - HotkeyButtons.class, - OpenEyeExtra.class + HotkeyButtons.class ); private final Map, Extra> instances = new HashMap<>(); From 4ca4f2def61a97f18aa69a54b038a621f82ba645 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 28 Feb 2021 00:16:20 +0100 Subject: [PATCH 059/102] Auto-reload config file on changes (Fabric only) --- .../core/SettingsRegistryBackend.java | 74 ++++++++++++++++++- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/replaymod/core/SettingsRegistryBackend.java b/src/main/java/com/replaymod/core/SettingsRegistryBackend.java index 66a8eaae..79615a8b 100644 --- a/src/main/java/com/replaymod/core/SettingsRegistryBackend.java +++ b/src/main/java/com/replaymod/core/SettingsRegistryBackend.java @@ -5,6 +5,8 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import com.replaymod.core.events.SettingsChangedCallback; +import net.minecraft.client.MinecraftClient; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -12,6 +14,11 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import java.util.List; import java.util.Map; import static com.replaymod.core.versions.MCVer.getMinecraft; @@ -27,6 +34,15 @@ class SettingsRegistryBackend { } public void register() { + load(true); + try { + registerWatcher(); + } catch (IOException e) { + LOGGER.warn("Failed to setup file watcher for {}, live-reloading is disabled. Cause: {}", configFile, e); + } + } + + private void load(boolean createIfMissingOrBroken) { String config; if (Files.exists(configFile)) { try { @@ -36,14 +52,18 @@ class SettingsRegistryBackend { return; } } else { - save(); + if (createIfMissingOrBroken) { + save(); + } return; } Gson gson = new Gson(); JsonObject root = gson.fromJson(config, JsonObject.class); if (root == null) { LOGGER.error("Config file {} appears corrupted: {}", configFile, config); - save(); + if (createIfMissingOrBroken) { + save(); + } return; } for (Map.Entry, Object> entry : settings.entrySet()) { @@ -63,12 +83,60 @@ class SettingsRegistryBackend { entry.setValue(value.getAsNumber().doubleValue()); } if (key.getDefault() instanceof String && value.isString()) { - entry.setValue(value.getAsString()); + String valueStr = value.getAsString(); + if (entry instanceof SettingsRegistry.MultipleChoiceSettingKey) { + @SuppressWarnings("unchecked") + List choices = ((SettingsRegistry.MultipleChoiceSettingKey) entry).getChoices(); + if (choices.stream().noneMatch(valueStr::equals)) { + continue; + } + } + entry.setValue(valueStr); } } } } + private void registerWatcher() throws IOException { + WatchService watchService = configFile.getFileSystem().newWatchService(); + configFile.getParent().register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY); + Thread thread = new Thread(() -> { + while (true) { + WatchKey nextKey; + try { + nextKey = watchService.take(); + } catch (InterruptedException e) { + return; + } + for (WatchEvent event : nextKey.pollEvents()) { + WatchEvent.Kind kind = event.kind(); + if (kind == StandardWatchEventKinds.OVERFLOW) { + continue; + } + Path fileName = ((Path) event.context()); + if (fileName.equals(configFile.getFileName())) { + MinecraftClient.getInstance().send(this::reload); + } + } + if (!nextKey.reset()) { + return; + } + } + }); + thread.setName("replaymod-config-watcher"); + thread.setDaemon(true); + thread.start(); + } + + private void reload() { + load(false); + + SettingsRegistry settingsRegistry = ReplayMod.instance.getSettingsRegistry(); + for (SettingsRegistry.SettingKey key : settings.keySet()) { + SettingsChangedCallback.EVENT.invoker().onSettingsChanged(settingsRegistry, key); + } + } + @SuppressWarnings("unused") public void register(SettingsRegistry.SettingKey key) { } From c6b41d76fa5119e17ba4958aa33c5eceea30cc9b Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 28 Feb 2021 00:31:13 +0100 Subject: [PATCH 060/102] Document valid values for MultipleChoiceSettings in config file --- .../com/replaymod/core/SettingsRegistryBackend.java | 10 ++++++++++ .../com/replaymod/core/SettingsRegistryBackend.java | 11 ++++++++++- .../com/replaymod/core/versions/forge/Patterns.java | 10 ++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/replaymod/core/SettingsRegistryBackend.java b/src/main/java/com/replaymod/core/SettingsRegistryBackend.java index 79615a8b..eb996915 100644 --- a/src/main/java/com/replaymod/core/SettingsRegistryBackend.java +++ b/src/main/java/com/replaymod/core/SettingsRegistryBackend.java @@ -2,6 +2,7 @@ package com.replaymod.core; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; @@ -164,6 +165,15 @@ class SettingsRegistryBackend { } if (value instanceof String) { category.addProperty(key.getKey(), (String) value); + if (key instanceof SettingsRegistry.MultipleChoiceSettingKey) { + @SuppressWarnings("unchecked") + List choices = ((SettingsRegistry.MultipleChoiceSettingKey) key).getChoices(); + JsonArray array = new JsonArray(); + for (String choice : choices) { + array.add(choice); + } + category.add(key.getKey() + "_valid_values", array); + } } } Gson gson = new GsonBuilder().setPrettyPrinting().create(); diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/SettingsRegistryBackend.java b/versions/1.12.2/src/main/java/com/replaymod/core/SettingsRegistryBackend.java index c33727fd..41fa3211 100644 --- a/versions/1.12.2/src/main/java/com/replaymod/core/SettingsRegistryBackend.java +++ b/versions/1.12.2/src/main/java/com/replaymod/core/SettingsRegistryBackend.java @@ -1,8 +1,10 @@ package com.replaymod.core; import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.common.config.Property; import java.util.ArrayList; +import java.util.List; import java.util.Map; class SettingsRegistryBackend { @@ -36,7 +38,14 @@ class SettingsRegistryBackend { } else if (key.getDefault() instanceof Double) { value = configuration.get(key.getCategory(), key.getKey(), (Double) key.getDefault()).getDouble(); } else if (key.getDefault() instanceof String) { - value = configuration.get(key.getCategory(), key.getKey(), (String) key.getDefault()).getString(); + Property property = configuration.get(key.getCategory(), key.getKey(), (String) key.getDefault()); + value = property.getString(); + if (key instanceof SettingsRegistry.MultipleChoiceSettingKey) { + @SuppressWarnings("unchecked") + List choices = ((SettingsRegistry.MultipleChoiceSettingKey) key).getChoices(); + property.setValidValues(choices.toArray(new String[0])); + property.setComment("Valid values: " + String.join(", ", choices)); + } } else { throw new IllegalArgumentException("Default type " + key.getDefault().getClass() + " not supported."); } diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/Patterns.java b/versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/Patterns.java index cf16de42..0f8a6ff3 100644 --- a/versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/Patterns.java +++ b/versions/1.12.2/src/main/java/com/replaymod/core/versions/forge/Patterns.java @@ -7,6 +7,7 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.client.event.RenderLivingEvent; +import net.minecraftforge.common.config.Property; class Patterns { @Pattern @@ -44,4 +45,13 @@ class Patterns { //$$ return event.type; //#endif } + + @Pattern + private static void setComment(Property property, String comment) { + //#if MC>=10900 + property.setComment(comment); + //#else + //$$ property.comment = comment; + //#endif + } } From 8ff27437afdae52974d52623ae9d52f823c10aa4 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 28 Feb 2021 00:32:33 +0100 Subject: [PATCH 061/102] Add configurable, small Replay Viewer button (closes #471) --- build.gradle | 9 +- .../com/replaymod/core/versions/MCVer.java | 6 + .../java/com/replaymod/replay/Setting.java | 10 ++ .../replaymod/replay/handler/GuiHandler.java | 120 +++++++++++++++++- .../replay/mixin/Mixin_MoveRealmsButton.java | 9 +- 5 files changed, 150 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 38d975af..5e9b99ab 100644 --- a/build.gradle +++ b/build.gradle @@ -199,6 +199,12 @@ repositories { name = "fabric" url = "https://maven.fabricmc.net/" } + maven { + url 'https://maven.terraformersmc.com/releases/' + content { + includeGroup 'com.terraformersmc' + } + } maven { url 'https://jitpack.io' content { @@ -323,8 +329,7 @@ dependencies { if (FABRIC) { if (mcVersion >= 11602) { - // TODO re-add to runtime once available - modCompileOnly 'io.github.prospector:modmenu:1.14.0+build.24' + modCompile 'com.terraformersmc:modmenu:1.16.8' } else if (mcVersion >= 11600) { modCompile 'io.github.prospector:modmenu:1.14.0+build.24' } else { diff --git a/src/main/java/com/replaymod/core/versions/MCVer.java b/src/main/java/com/replaymod/core/versions/MCVer.java index b14cc869..d5282f4b 100644 --- a/src/main/java/com/replaymod/core/versions/MCVer.java +++ b/src/main/java/com/replaymod/core/versions/MCVer.java @@ -223,6 +223,12 @@ public class MCVer { if (message.equals(b.getMessage())) { return Optional.of(b); } + //#if MC>=11600 + // Fuzzy match (copy does not include children) + if (b.getMessage() != null && b.getMessage().copy().equals(message)) { + return Optional.of(b); + } + //#endif } return Optional.empty(); } diff --git a/src/main/java/com/replaymod/replay/Setting.java b/src/main/java/com/replaymod/replay/Setting.java index a16e42e7..b2303c61 100644 --- a/src/main/java/com/replaymod/replay/Setting.java +++ b/src/main/java/com/replaymod/replay/Setting.java @@ -1,6 +1,10 @@ package com.replaymod.replay; import com.replaymod.core.SettingsRegistry; +import com.replaymod.replay.handler.GuiHandler.MainMenuButtonPosition; + +import java.util.Arrays; +import java.util.stream.Collectors; public final class Setting extends SettingsRegistry.SettingKeys { public static final Setting SHOW_CHAT = make("showChat", "showchat", true); @@ -8,6 +12,12 @@ public final class Setting extends SettingsRegistry.SettingKeys { public static final SettingsRegistry.MultipleChoiceSettingKeys CAMERA = new SettingsRegistry.MultipleChoiceSettingKeys<>( "replay", "camera", "replaymod.gui.settings.camera", "replaymod.camera.classic"); + public static final SettingsRegistry.MultipleChoiceSettingKeys MAIN_MENU_BUTTON = + new SettingsRegistry.MultipleChoiceSettingKeys<>( + "replay", "mainMenuButton", null, MainMenuButtonPosition.DEFAULT.name()); + static { + MAIN_MENU_BUTTON.setChoices(Arrays.stream(MainMenuButtonPosition.values()).map(Enum::name).collect(Collectors.toList())); + } private static Setting make(String key, String displayName, T defaultValue) { return new Setting<>(key, displayName, defaultValue); diff --git a/src/main/java/com/replaymod/replay/handler/GuiHandler.java b/src/main/java/com/replaymod/replay/handler/GuiHandler.java index af8f67ff..8f8b4a85 100644 --- a/src/main/java/com/replaymod/replay/handler/GuiHandler.java +++ b/src/main/java/com/replaymod/replay/handler/GuiHandler.java @@ -1,6 +1,12 @@ package com.replaymod.replay.handler; +import com.replaymod.core.gui.GuiReplayButton; +import com.replaymod.replay.Setting; +import de.johni0702.minecraft.gui.container.VanillaGuiScreen; +import de.johni0702.minecraft.gui.element.GuiTooltip; +import de.johni0702.minecraft.gui.layout.CustomLayout; import de.johni0702.minecraft.gui.utils.EventRegistrations; +import de.johni0702.minecraft.gui.utils.lwjgl.Point; import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback; import com.replaymod.replay.ReplayModReplay; import com.replaymod.replay.gui.screen.GuiReplayViewer; @@ -28,9 +34,11 @@ import net.minecraft.client.gui.widget.ButtonWidget; import java.io.IOException; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.Optional; import java.util.function.Consumer; +import java.util.stream.Stream; import static com.replaymod.core.versions.MCVer.*; import static com.replaymod.replay.ReplayModReplay.LOGGER; @@ -217,6 +225,34 @@ public class GuiHandler extends EventRegistrations { return; } + boolean isCustomMainMenuMod = guiScreen.getClass().getName().endsWith("custommainmenu.gui.GuiFakeMain"); + + MainMenuButtonPosition buttonPosition = MainMenuButtonPosition.valueOf(mod.getCore().getSettingsRegistry().get(Setting.MAIN_MENU_BUTTON)); + if (buttonPosition != MainMenuButtonPosition.BIG && !isCustomMainMenuMod) { + VanillaGuiScreen vanillaGui = VanillaGuiScreen.wrap(guiScreen); + + GuiReplayButton replayButton = new GuiReplayButton(); + replayButton + .onClick(() -> new GuiReplayViewer(mod).display()) + .setTooltip(new GuiTooltip().setI18nText("replaymod.gui.replayviewer")); + + vanillaGui.setLayout(new CustomLayout(vanillaGui.getLayout()) { + private Point pos; + + @Override + protected void layout(de.johni0702.minecraft.gui.container.GuiScreen container, int width, int height) { + if (pos == null) { + // Delaying computation so we can take into account buttons + // added after our callback. + pos = determineButtonPos(buttonPosition, guiScreen, buttonList); + } + size(replayButton, 20, 20); + pos(replayButton, pos.getX(), pos.getY()); + } + }).addElements(null, replayButton); + return; + } + int x = guiScreen.width / 2 - 100; // We want to position our button below the realms button int y = findButton(buttonList, "menu.online", 14) @@ -246,7 +282,7 @@ public class GuiHandler extends EventRegistrations { this::onButton ); //#if FABRIC<=0 - //$$ if (guiScreen.getClass().getName().endsWith("custommainmenu.gui.GuiFakeMain")) { + //$$ if (isCustomMainMenuMod) { //$$ // CustomMainMenu uses a different list in the event than in its Fake gui //$$ buttonList.add(button); //$$ return; @@ -255,6 +291,70 @@ public class GuiHandler extends EventRegistrations { addButton(guiScreen, button); } + private Point determineButtonPos(MainMenuButtonPosition buttonPosition, Screen guiScreen, List buttonList) { + Point topRight = new Point(guiScreen.width - 20 - 5, 5); + + if (buttonPosition == MainMenuButtonPosition.TOP_LEFT) { + return new Point(5, 5); + } else if (buttonPosition == MainMenuButtonPosition.TOP_RIGHT) { + return topRight; + } else if (buttonPosition == MainMenuButtonPosition.DEFAULT) { + return Stream.of( + findButton(buttonList, "menu.singleplayer", 1), + findButton(buttonList, "menu.multiplayer", 2), + findButton(buttonList, "menu.online", 14), + findButton(buttonList, "modmenu.title", 6) + ) + // skip buttons which do not exist + .flatMap(it -> it.map(Stream::of).orElseGet(Stream::empty)) + // skip buttons which already have something next to them + .filter(it -> buttonList.stream().noneMatch(button -> + button.x <= it.x + it.getWidth() + 4 + 20 + && button.y <= it.y + it.getHeight() + && button.x + button.getWidth() >= it.x + it.getWidth() + 4 + && button.y + button.getHeight() >= it.y + )) + // then take the bottom-most and if there's two, the right-most + .max(Comparator.comparingInt(it -> it.y).thenComparingInt(it -> it.x)) + // and place ourselves next to it + .map(it -> new Point(it.x + it.getWidth() + 4, it.y)) + // if all fails, just go with TOP_RIGHT + .orElse(topRight); + } else { + return Optional.of(buttonList).flatMap(buttons -> { + switch (buttonPosition) { + case LEFT_OF_SINGLEPLAYER: + case RIGHT_OF_SINGLEPLAYER: + return findButton(buttons, "menu.singleplayer", 1); + case LEFT_OF_MULTIPLAYER: + case RIGHT_OF_MULTIPLAYER: + return findButton(buttons, "menu.multiplayer", 2); + case LEFT_OF_REALMS: + case RIGHT_OF_REALMS: + return findButton(buttons, "menu.online", 14); + case LEFT_OF_MODS: + case RIGHT_OF_MODS: + return findButton(buttons, "modmenu.title", 6); + } + throw new RuntimeException(); + }).map(button -> { + switch (buttonPosition) { + case LEFT_OF_SINGLEPLAYER: + case LEFT_OF_MULTIPLAYER: + case LEFT_OF_REALMS: + case LEFT_OF_MODS: + return new Point(button.x - 4 - 20, button.y); + case RIGHT_OF_MODS: + case RIGHT_OF_SINGLEPLAYER: + case RIGHT_OF_MULTIPLAYER: + case RIGHT_OF_REALMS: + return new Point(button.x + button.getWidth() + 4, button.y); + } + throw new RuntimeException(); + }).orElse(topRight); + } + } + //#if MC>=11400 private void onButton(InjectedButton button) { Screen guiScreen = button.guiScreen; @@ -334,4 +434,22 @@ public class GuiHandler extends EventRegistrations { //$$ } //#endif } + + public enum MainMenuButtonPosition { + // The old big button below Realms/Mods which pushes other buttons around. + BIG, + // Right of the bottom-most button in the main block of buttons (so not the quit button). + // That will generally be either RIGHT_OF_REALMS or RIGHT_OF_MODS depending on version and installed mods. + DEFAULT, + TOP_LEFT, + TOP_RIGHT, + LEFT_OF_SINGLEPLAYER, + RIGHT_OF_SINGLEPLAYER, + LEFT_OF_MULTIPLAYER, + RIGHT_OF_MULTIPLAYER, + LEFT_OF_REALMS, + RIGHT_OF_REALMS, + LEFT_OF_MODS, + RIGHT_OF_MODS, + } } diff --git a/src/main/java/com/replaymod/replay/mixin/Mixin_MoveRealmsButton.java b/src/main/java/com/replaymod/replay/mixin/Mixin_MoveRealmsButton.java index 12f19084..3066899f 100644 --- a/src/main/java/com/replaymod/replay/mixin/Mixin_MoveRealmsButton.java +++ b/src/main/java/com/replaymod/replay/mixin/Mixin_MoveRealmsButton.java @@ -1,6 +1,9 @@ //#if MC>=11600 package com.replaymod.replay.mixin; +import com.replaymod.core.ReplayMod; +import com.replaymod.replay.Setting; +import com.replaymod.replay.handler.GuiHandler.MainMenuButtonPosition; import net.minecraft.client.gui.screen.TitleScreen; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -14,7 +17,11 @@ public abstract class Mixin_MoveRealmsButton { index = 2 ) private int adjustRealmsButton(int height) { - return height - 24 * 4; + String setting = ReplayMod.instance.getSettingsRegistry().get(Setting.MAIN_MENU_BUTTON); + if (MainMenuButtonPosition.valueOf(setting) == MainMenuButtonPosition.BIG) { + height -= 24 * 4; + } + return height; } } //#endif From dda6bd41b678a1801b40b72ac4e4804a0df61785 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 28 Feb 2021 01:36:30 +0100 Subject: [PATCH 062/102] Implement ffmpeg-independent PNGWriter (closes #476) Creates a dedicated folder for each video and does not depend on ffmpeg, just like the EXRWriter (but supporting all MC versions). Also does 32 bit depth export by chunking the 32-bit float into the 8-bit BGRA component channels. --- docs/content.md | 3 +- .../java/com/replaymod/render/PNGWriter.java | 71 +++++++++++++++++++ .../com/replaymod/render/RenderSettings.java | 2 +- .../render/gui/GuiRenderSettings.java | 7 +- .../render/rendering/VideoRenderer.java | 7 +- src/main/resources/assets/replaymod/lang | 2 +- 6 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/replaymod/render/PNGWriter.java diff --git a/docs/content.md b/docs/content.md index 139c7f5b..faea3ff2 100755 --- a/docs/content.md +++ b/docs/content.md @@ -358,7 +358,8 @@ There are **7 Encoding Presets** you can choose from: While these video files are of perfect quality, most **non-FFmpeg-based video players and video editing software** (e.g. QuickTime Player, Sony Vegas and Adobe Premiere) can't play these videos. Therefore, you should instead use the **MP4 - High Quality** preset in most cases. - **PNG Sequence** Exports the sequence as individual frames in the **PNG Format**. - **Warning:** This can create a huge amount of files, so make sure to save them in a separate folder. + The images are of perfect quality. + Depth map images are 32-bit float encoded in the 8-bit components in BGRA order and will need some kind of post-processing to be useful in most editors. - **OpenEXR Sequence** (Minecraft 1.14 and above) Exports the sequence as individual frames in the **OpenEXR Format**. The images are of perfect quality and may contain diff --git a/src/main/java/com/replaymod/render/PNGWriter.java b/src/main/java/com/replaymod/render/PNGWriter.java new file mode 100644 index 00000000..846e63be --- /dev/null +++ b/src/main/java/com/replaymod/render/PNGWriter.java @@ -0,0 +1,71 @@ +package com.replaymod.render; + +import com.replaymod.core.versions.MCVer; +import com.replaymod.render.blend.Util.IOConsumer; +import com.replaymod.render.frame.BitmapFrame; +import com.replaymod.render.rendering.Channel; +import com.replaymod.render.rendering.FrameConsumer; +import com.replaymod.render.utils.ByteBufferPool; +import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; +import de.johni0702.minecraft.gui.versions.Image; +import net.minecraft.util.crash.CrashReport; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; + +public class PNGWriter implements FrameConsumer { + + private final Path outputFolder; + + public PNGWriter(Path outputFolder) throws IOException { + this.outputFolder = outputFolder; + + Files.createDirectories(outputFolder); + } + + @Override + public void consume(Map channels) { + BitmapFrame bgraFrame = channels.get(Channel.BRGA); + BitmapFrame depthFrame = channels.get(Channel.DEPTH); + try { + if (bgraFrame != null) { + withImage(bgraFrame, image -> + image.writePNG(outputFolder.resolve(bgraFrame.getFrameId() + ".png").toFile())); + } + if (depthFrame != null) { + withImage(depthFrame, image -> + image.writePNG(outputFolder.resolve(depthFrame.getFrameId() + ".depth.png").toFile())); + } + } catch (Throwable t) { + MCVer.getMinecraft().setCrashReport(CrashReport.create(t, "Exporting EXR frame")); + } finally { + channels.values().forEach(it -> ByteBufferPool.release(it.getByteBuffer())); + } + } + + private void withImage(BitmapFrame frame, IOConsumer consumer) throws IOException { + ByteBuffer buffer = frame.getByteBuffer(); + ReadableDimension size = frame.getSize(); + int width = size.getWidth(); + int height = size.getHeight(); + try (Image image = new Image(width, height)) { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + byte b = buffer.get(); + byte g = buffer.get(); + byte r = buffer.get(); + byte a = buffer.get(); + image.setRGBA(x, y, r, g, b, a); + } + } + consumer.accept(image); + } + } + + @Override + public void close() { + } +} diff --git a/src/main/java/com/replaymod/render/RenderSettings.java b/src/main/java/com/replaymod/render/RenderSettings.java index 4117389d..bfc8783f 100644 --- a/src/main/java/com/replaymod/render/RenderSettings.java +++ b/src/main/java/com/replaymod/render/RenderSettings.java @@ -72,7 +72,7 @@ public class RenderSettings { EXR(null, "exr"), - PNG("\"%FILENAME%-%06d.png\"", "png"); + PNG(null, "png"); private final String preset; private final String fileExtension; diff --git a/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java b/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java index af9f5cf0..b6eae92f 100644 --- a/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java +++ b/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java @@ -406,8 +406,9 @@ public class GuiRenderSettings extends AbstractGuiPopup { // Enable/Disable various options for blend export boolean isEXR = encodingPresetDropdown.getSelectedValue() == RenderSettings.EncodingPreset.EXR; + boolean isPNG = encodingPresetDropdown.getSelectedValue() == RenderSettings.EncodingPreset.PNG; boolean isBlend = renderMethod == RenderSettings.RenderMethod.BLEND; - boolean isFFmpeg = !isBlend && !isEXR; + boolean isFFmpeg = !isBlend && !isEXR && !isPNG; if (isBlend) { videoWidth.setDisabled(); videoHeight.setDisabled(); @@ -417,11 +418,11 @@ public class GuiRenderSettings extends AbstractGuiPopup { exportArguments.setEnabled(isFFmpeg); antiAliasingDropdown.setEnabled(isFFmpeg); - if (isEXR) { + if (isEXR || isPNG) { depthMap.setEnabled().setTooltip(null); } else { depthMap.setDisabled().setTooltip(new GuiTooltip().setColor(Colors.RED) - .setI18nText("replaymod.gui.rendersettings.depthmap.onlyexr")); + .setI18nText("replaymod.gui.rendersettings.depthmap.only_exr_or_png")); } // Enable/Disable export args reset button diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index 4db4a2fc..762c74e9 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -8,6 +8,7 @@ import com.replaymod.pathing.player.AbstractTimelinePlayer; import com.replaymod.pathing.player.ReplayTimer; import com.replaymod.pathing.properties.TimestampProperty; import com.replaymod.render.CameraPathExporter; +import com.replaymod.render.PNGWriter; import com.replaymod.render.RenderSettings; import com.replaymod.render.ReplayModRender; import com.replaymod.render.FFmpegWriter; @@ -125,15 +126,17 @@ public class VideoRenderer implements RenderInfo { } else { FrameConsumer frameConsumer; if (settings.getEncodingPreset() == RenderSettings.EncodingPreset.EXR) { - ffmpegWriter = null; //#if MC>=11400 frameConsumer = new EXRWriter(settings.getOutputFile().toPath()); //#else //$$ throw new UnsupportedOperationException("EXR requires LWJGL3"); //#endif + } else if (settings.getEncodingPreset() == RenderSettings.EncodingPreset.PNG) { + frameConsumer = new PNGWriter(settings.getOutputFile().toPath()); } else { - frameConsumer = ffmpegWriter = new FFmpegWriter(this); + frameConsumer = new FFmpegWriter(this); } + ffmpegWriter = frameConsumer instanceof FFmpegWriter ? (FFmpegWriter) frameConsumer : null; FrameConsumer previewingFrameConsumer = new FrameConsumer() { @Override public void consume(Map channels) { diff --git a/src/main/resources/assets/replaymod/lang b/src/main/resources/assets/replaymod/lang index 63b7a8be..54ab62bd 160000 --- a/src/main/resources/assets/replaymod/lang +++ b/src/main/resources/assets/replaymod/lang @@ -1 +1 @@ -Subproject commit 63b7a8bea1ab9a9f005c9ae0e1c54b4432cbc9e6 +Subproject commit 54ab62bdbb646c6b4f4b6d61a26183258e5a017d From 537795f9ca594c35ac4db4a70498f98d575f034e Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 28 Feb 2021 11:55:58 +0100 Subject: [PATCH 063/102] Backport contextual key bindings to 1.12.2 and below (closes #478) --- .../mixin/Mixin_ContextualKeyBindings.java | 29 ++++++++++++++----- .../com/replaymod/core/versions/Patterns.java | 9 ++++++ .../com/replaymod/replay/ReplayModReplay.java | 4 --- src/main/resources/mixins.core.replaymod.json | 2 +- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/replaymod/core/mixin/Mixin_ContextualKeyBindings.java b/src/main/java/com/replaymod/core/mixin/Mixin_ContextualKeyBindings.java index ad7b8093..6b246c3f 100644 --- a/src/main/java/com/replaymod/core/mixin/Mixin_ContextualKeyBindings.java +++ b/src/main/java/com/replaymod/core/mixin/Mixin_ContextualKeyBindings.java @@ -1,4 +1,3 @@ -//#if MC>=11400 package com.replaymod.core.mixin; import com.replaymod.core.ReplayMod; @@ -13,6 +12,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; @@ -24,16 +24,26 @@ import java.util.Set; */ @Mixin(KeyBinding.class) public class Mixin_ContextualKeyBindings { + //#if MC>=11200 @Shadow @Final private static Map keysById; + @Unique private static Collection keyBindings() { return Mixin_ContextualKeyBindings.keysById.values(); } + //#else + //$$ @Shadow @Final private static List KEYBIND_ARRAY; + //$$ @Unique private static Collection keyBindings() { return Mixin_ContextualKeyBindings.KEYBIND_ARRAY; } + //#endif @Unique private static final List temporarilyRemoved = new ArrayList<>(); @Inject(method = "updateKeysByCode", at = @At("HEAD")) private static void preContextualKeyBindings(CallbackInfo ci) { - Set onlyInReplay = ReplayMod.instance.getKeyBindingRegistry().getOnlyInReplay(); + ReplayMod mod = ReplayMod.instance; + if (mod == null) { + return; + } + Set onlyInReplay = mod.getKeyBindingRegistry().getOnlyInReplay(); if (ReplayModReplay.instance.getReplayHandler() != null) { // In replay, remove any conflicting key bindings, so that ours are guaranteed in - Mixin_ContextualKeyBindings.keysById.values().removeIf(keyBinding -> { + keyBindings().removeIf(keyBinding -> { for (KeyBinding exclusiveBinding : onlyInReplay) { if (keyBinding.equals(exclusiveBinding) && keyBinding != exclusiveBinding) { temporarilyRemoved.add(keyBinding); @@ -44,20 +54,25 @@ public class Mixin_ContextualKeyBindings { }); } else { // Not in a replay, remove all replay-exclusive keybindings - for (KeyBinding keyBinding : onlyInReplay) { - if (Mixin_ContextualKeyBindings.keysById.remove(keyBinding.getTranslationKey()) != null) { + keyBindings().removeIf(keyBinding -> { + if (onlyInReplay.contains(keyBinding)) { temporarilyRemoved.add(keyBinding); + return true; } - } + return false; + }); } } @Inject(method = "updateKeysByCode", at = @At("RETURN")) private static void postContextualKeyBindings(CallbackInfo ci) { for (KeyBinding keyBinding : temporarilyRemoved) { + //#if MC>=11200 Mixin_ContextualKeyBindings.keysById.put(keyBinding.getTranslationKey(), keyBinding); + //#else + //$$ keyBindings().add(keyBinding); + //#endif } temporarilyRemoved.clear(); } } -//#endif diff --git a/src/main/java/com/replaymod/core/versions/Patterns.java b/src/main/java/com/replaymod/core/versions/Patterns.java index 65570e88..8c62dd6c 100644 --- a/src/main/java/com/replaymod/core/versions/Patterns.java +++ b/src/main/java/com/replaymod/core/versions/Patterns.java @@ -373,4 +373,13 @@ class Patterns { //$$ return PositionedSoundRecord.createPositionedSoundRecord(sound, pitch); //#endif } + + @Pattern + private static boolean isKeyBindingConflicting(KeyBinding a, KeyBinding b) { + //#if MC>=10900 + return a.equals(b); + //#else + //$$ return (a.getKeyCode() == b.getKeyCode()); + //#endif + } } diff --git a/src/main/java/com/replaymod/replay/ReplayModReplay.java b/src/main/java/com/replaymod/replay/ReplayModReplay.java index 8d4e050c..05113411 100644 --- a/src/main/java/com/replaymod/replay/ReplayModReplay.java +++ b/src/main/java/com/replaymod/replay/ReplayModReplay.java @@ -186,18 +186,14 @@ public class ReplayModReplay implements Module { } } replayHandler = new ReplayHandler(replayFile, asyncMode); - //#if MC>=11400 KeyBinding.updateKeysByCode(); // see Mixin_ContextualKeyBindings - //#endif return replayHandler; } public void forcefullyStopReplay() { replayHandler = null; - //#if MC>=11400 KeyBinding.updateKeysByCode(); // see Mixin_ContextualKeyBindings - //#endif } public ReplayMod getCore() { diff --git a/src/main/resources/mixins.core.replaymod.json b/src/main/resources/mixins.core.replaymod.json index c002fc17..c0b0a787 100644 --- a/src/main/resources/mixins.core.replaymod.json +++ b/src/main/resources/mixins.core.replaymod.json @@ -4,9 +4,9 @@ "mixins": [], "server": [], "client": [ + "Mixin_ContextualKeyBindings", //#if MC>=11400 "AbstractButtonWidgetAccessor", - "Mixin_ContextualKeyBindings", "MixinGameRenderer", "Mixin_HideDynamicResourcePacks", "Mixin_RegisterDynamicResourcePacks", From 3440b8d8a82109603d5aebf0ed90172929c22304 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 28 Feb 2021 12:17:05 +0100 Subject: [PATCH 064/102] Update loom to 0.6 --- build.gradle | 6 ++++-- jGui | 2 +- root.gradle.kts | 7 +------ 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index 5e9b99ab..0cb9e844 100644 --- a/build.gradle +++ b/build.gradle @@ -34,7 +34,7 @@ buildscript { dependencies { classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.2' if (fabric) { - classpath 'fabric-loom:fabric-loom.gradle.plugin:0.5-SNAPSHOT' + classpath 'fabric-loom:fabric-loom.gradle.plugin:0.6-SNAPSHOT' } else if (mcVersion >= 11400) { classpath('net.minecraftforge.gradle:ForgeGradle:3.+'){ exclude group: 'trove', module: 'trove' // preprocessor/idea requires more recent one @@ -124,7 +124,9 @@ archivesBaseName = "replaymod" if (FABRIC) { minecraft { refmapName = 'mixins.replaymod.refmap.json' - autoGenIDERuns = true + runConfigs.all { + ideConfigGenerated = true + } } } else { minecraft { diff --git a/jGui b/jGui index 96edf0fe..3b654f3a 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 96edf0fe31a1bef9ed286c01af994527566ab45c +Subproject commit 3b654f3a388fa649d144c0d93a3b4a84dda4ae56 diff --git a/root.gradle.kts b/root.gradle.kts index 07a56fa3..abecc8c4 100755 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -2,7 +2,7 @@ import groovy.json.JsonOutput import java.io.ByteArrayOutputStream plugins { - id("fabric-loom") version "0.5-SNAPSHOT" apply false + id("fabric-loom") version "0.6-SNAPSHOT" apply false id("com.replaymod.preprocess") version "3d85a00" id("com.github.hierynomus.license") version "0.15.0" } @@ -25,11 +25,6 @@ if (gitDescribe().endsWith("*")) { group = "com.replaymod" -// Loom tries to find the active mixin version by recursing up to the root project and checking each project's -// compileClasspath and build script classpath (in that order). Since we've loom in our root project's classpath, -// loom will only find it after checking the root project's compileClasspath (which doesn't exist by default). -configurations.register("compileClasspath") - val shadowJar by tasks.creating(Copy::class) { into("$buildDir/libs") } From f5af283492d2d23aa6c74e1c67b9e72a6c7f65f2 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Thu, 22 Apr 2021 14:09:58 +0200 Subject: [PATCH 065/102] Update for new forge maven repo --- build.gradle | 10 +++++----- jGui | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 0cb9e844..d551c7dd 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ buildscript { if (!fabric) { maven { name = "forge" - url = "https://files.minecraftforge.net/maven" + url = "https://maven.minecraftforge.net" } } maven { @@ -41,12 +41,12 @@ buildscript { } } else if (mcVersion >= 10800) { classpath('com.github.ReplayMod:ForgeGradle:' + ( - mcVersion >= 11200 ? 'b64de9c' : // FG 2.3 - mcVersion >= 10904 ? '5bb7a53' : // FG 2.2 - 'fc1eabc' // FG 2.1 + mcVersion >= 11200 ? '541e1485' : // FG 2.3 + mcVersion >= 10904 ? '5c1f53dc' : // FG 2.2 + '48c4f0c6' // FG 2.1 ) + ':all') } else { - classpath 'com.github.ReplayMod:ForgeGradle:5fca6853:all' // FG 1.2 + classpath 'com.github.ReplayMod:ForgeGradle:a8a9e0ca:all' // FG 1.2 } } } diff --git a/jGui b/jGui index 3b654f3a..a4cf2604 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 3b654f3a388fa649d144c0d93a3b4a84dda4ae56 +Subproject commit a4cf26044dfb4f13abd61644fa15126c89dfcb91 From 59fb58c6fc669ccd8af6a0253531e7ae621da463 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Fri, 4 Jun 2021 22:58:28 +0200 Subject: [PATCH 066/102] Disable 1.7.10 for now Continued support would require porting FG1.2 to Gradle 7 / Java 16. --- Jenkinsfile | 2 +- settings.gradle.kts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index a92bad02..1e1686cb 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -13,7 +13,7 @@ pipeline { [$class: 'ArbitraryFileCache', excludes: '', includes: '**/*', path: '.gradle/user_home/wrapper'], [$class: 'ArbitraryFileCache', excludes: '', includes: '**/*', path: '.gradle/loom-cache'], ]) { - sh './gradlew :jGui:1.7.10:setupCIWorkspace :1.7.10:setupCIWorkspace' + // sh './gradlew :jGui:1.7.10:setupCIWorkspace :1.7.10:setupCIWorkspace' sh './gradlew --parallel' } archiveArtifacts 'versions/*/build/libs/*.jar' diff --git a/settings.gradle.kts b/settings.gradle.kts index b99f2a4a..83b337e3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -19,7 +19,7 @@ pluginManagement { } val jGuiVersions = listOf( - "1.7.10", + // "1.7.10", "1.8", "1.8.9", "1.9.4", @@ -31,7 +31,7 @@ val jGuiVersions = listOf( "1.16.4" ) val replayModVersions = listOf( - "1.7.10", + // "1.7.10", "1.8", "1.8.9", "1.9.4", From 4cdbfb7c4634f2c0e77da6370edbd3aa33dc62e5 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Fri, 4 Jun 2021 23:38:48 +0200 Subject: [PATCH 067/102] Update Gradle to 7.0.2 --- README.md | 4 +-- build.gradle | 38 +++++++++++++---------- gradle/wrapper/gradle-wrapper.jar | Bin 54413 -> 55616 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 18 ++++++++++- gradlew.bat | 18 ++++++++++- jGui | 2 +- root.gradle.kts | 16 +++++----- 8 files changed, 67 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index d9f32cc9..b8d5f000 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ Make sure your sub-projects are up-to-date: `git submodule update --init --recur For compiling 1.7.10, you must run `./gradlew :jGui:1.7.10:setupDecompWorkspace :1.7.10:setupDecompWorkspace` once after the initial clone. This may take quite some time. ### No IDE -You can build the mod by running `./gradlew build` (or just `./gradlew shadowJar`). You can then find the final jar files in `versions/$MCVERSION/build/libs/`. -You can also build single versions by running `./gradlew :1.8:build` (or just `./gradlew :1.8:shadowJar`) (builds the MC 1.8 version). +You can build the mod by running `./gradlew build` (or just `./gradlew bundleJar`). You can then find the final jar files in `versions/$MCVERSION/build/libs/`. +You can also build single versions by running `./gradlew :1.8:build` (or just `./gradlew :1.8:bundleJar`) (builds the MC 1.8 version). ### IntelliJ Ensure you have at least IDEA 2020.1. diff --git a/build.gradle b/build.gradle index d551c7dd..a0a3e43a 100644 --- a/build.gradle +++ b/build.gradle @@ -32,18 +32,18 @@ buildscript { } dependencies { - classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.2' + classpath 'gradle.plugin.com.github.jengelman.gradle.plugins:shadow:7.0.0' if (fabric) { - classpath 'fabric-loom:fabric-loom.gradle.plugin:0.6-SNAPSHOT' + classpath 'fabric-loom:fabric-loom.gradle.plugin:0.8-SNAPSHOT' } else if (mcVersion >= 11400) { - classpath('net.minecraftforge.gradle:ForgeGradle:3.+'){ + classpath('net.minecraftforge.gradle:ForgeGradle:5.+'){ exclude group: 'trove', module: 'trove' // preprocessor/idea requires more recent one } } else if (mcVersion >= 10800) { classpath('com.github.ReplayMod:ForgeGradle:' + ( - mcVersion >= 11200 ? '541e1485' : // FG 2.3 - mcVersion >= 10904 ? '5c1f53dc' : // FG 2.2 - '48c4f0c6' // FG 2.1 + mcVersion >= 11200 ? '34ab703' : // FG 2.3 + mcVersion >= 10904 ? '5d1e8d8' : // FG 2.2 + 'd1a7165' // FG 2.1 ) + ':all') } else { classpath 'com.github.ReplayMod:ForgeGradle:a8a9e0ca:all' // FG 1.2 @@ -218,10 +218,10 @@ repositories { configurations { // Include dep in fat jar without relocation and, when forge supports it, without exploding (TODO) shade - compile.extendsFrom shade + implementation.extendsFrom shade // Include dep in fat jar with relocation and minimization shadow - compile.extendsFrom shadow + implementation.extendsFrom shadow } def shadeExclusions = { @@ -247,7 +247,7 @@ dependencies { 11603: '1.16.3+build.1:v2', 11604: '1.16.4+build.6:v2', ][mcVersion] - modCompile 'net.fabricmc:fabric-loader:' + [ + modImplementation 'net.fabricmc:fabric-loader:' + [ 11404: '0.7.8+build.189', 11502: '0.7.8+build.189', 11601: '0.8.8+build.202', @@ -271,7 +271,7 @@ dependencies { fabricApiModules.add("key-binding-api-v1") } fabricApiModules.each { module -> - modCompile fabricApi.module("fabric-$module", fabricApiVersion) + modImplementation fabricApi.module("fabric-$module", fabricApiVersion) include fabricApi.module("fabric-$module", fabricApiVersion) } } @@ -331,15 +331,15 @@ dependencies { if (FABRIC) { if (mcVersion >= 11602) { - modCompile 'com.terraformersmc:modmenu:1.16.8' + modImplementation 'com.terraformersmc:modmenu:1.16.8' } else if (mcVersion >= 11600) { - modCompile 'io.github.prospector:modmenu:1.14.0+build.24' + modImplementation 'io.github.prospector:modmenu:1.14.0+build.24' } else { - modCompile 'io.github.prospector.modmenu:ModMenu:1.6.2-92' + modImplementation 'io.github.prospector.modmenu:ModMenu:1.6.2-92' } } - testCompile 'junit:junit:4.11' + testImplementation 'junit:junit:4.11' } if (mcVersion <= 10710) { @@ -431,8 +431,12 @@ task configureRelocation() { } } -tasks.removeByName('shadowJar') // we want to base our shadowed jar on the reobfJar output, not the sourceSet output -task shadowJar(type: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { +// we want to base our shadowed jar on the reobfJar output, not the sourceSet output +// Tried tasks.replace but that does not actually seem to replace everything. +tasks.shadowJar.doFirst { + throw new GradleException("Wrong task! You want to run 'bundleJar' instead.") +} +tasks.register('bundleJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar).configure { from { (FABRIC ? tasks.remapJar : tasks.jar).archiveFile.get() } dependsOn { FABRIC ? tasks.remapJar : (mcVersion >= 10800 ? tasks.reobfJar : tasks.reobf) } @@ -478,7 +482,7 @@ task shadowJar(type: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) exclude(dependency('.*spongepowered:mixin:.*')) } } -tasks.assemble.dependsOn tasks.shadowJar +tasks.assemble.dependsOn tasks.bundleJar jar { classifier = 'raw' diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 0d4a9516871afd710a9d84d89e31ba77745607bd..5c2d1cf016b3885f6930543d57b744ea8c220a1a 100755 GIT binary patch literal 55616 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 722328d2..0f80bbf5 100755 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=7bdbad1e4f54f13c8a78abc00c26d44dd8709d4aedb704d913fb1bb78ac025dc -distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index cccdd3d5..b0d6d0ab 100755 --- a/gradlew +++ b/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,7 +44,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" diff --git a/gradlew.bat b/gradlew.bat index e95643d6..15e1ee37 100755 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/jGui b/jGui index a4cf2604..c3efefdc 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit a4cf26044dfb4f13abd61644fa15126c89dfcb91 +Subproject commit c3efefdc99bcc3fc1dcd57707e50887789cd4d3a diff --git a/root.gradle.kts b/root.gradle.kts index abecc8c4..b8674183 100755 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -2,8 +2,8 @@ import groovy.json.JsonOutput import java.io.ByteArrayOutputStream plugins { - id("fabric-loom") version "0.6-SNAPSHOT" apply false - id("com.replaymod.preprocess") version "3d85a00" + id("fabric-loom") version "0.8-SNAPSHOT" apply false + id("com.replaymod.preprocess") version "4b4dfe5" id("com.github.hierynomus.license") version "0.15.0" } @@ -25,7 +25,7 @@ if (gitDescribe().endsWith("*")) { group = "com.replaymod" -val shadowJar by tasks.creating(Copy::class) { +val bundleJar by tasks.creating(Copy::class) { into("$buildDir/libs") } @@ -37,10 +37,10 @@ subprojects { } afterEvaluate { - val projectShadowJar = project.tasks.findByName("shadowJar") - if (projectShadowJar != null && projectShadowJar.hasProperty("archivePath") && project.name != "core") { - shadowJar.dependsOn(projectShadowJar) - shadowJar.from(projectShadowJar.withGroovyBuilder { getProperty("archivePath") }) + val projectBundleJar = project.tasks.findByName("bundleJar") + if (projectBundleJar != null && projectBundleJar.hasProperty("archivePath") && project.name != "core") { + bundleJar.dependsOn(projectBundleJar) + bundleJar.from(projectBundleJar.withGroovyBuilder { getProperty("archivePath") }) } } } @@ -173,7 +173,7 @@ val doRelease by tasks.registering { } } -defaultTasks("shadowJar") +defaultTasks("bundleJar") preprocess { "1.16.4"(11604, "yarn") { From e38090733444d7a65c2734ddadd57356eed82bdb Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 5 Jun 2021 00:14:38 +0200 Subject: [PATCH 068/102] Switch preprocessor config to flat style --- root.gradle.kts | 59 +++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/root.gradle.kts b/root.gradle.kts index b8674183..2f0ff78f 100755 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -176,33 +176,34 @@ val doRelease by tasks.registering { defaultTasks("bundleJar") preprocess { - "1.16.4"(11604, "yarn") { - "1.16.1"(11601, "yarn") { - "1.15.2"(11502, "yarn") { - "1.14.4"(11404, "yarn", file("versions/mapping-fabric-1.15.2-1.14.4.txt")) { - "1.14.4-forge"(11404, "srg", file("versions/mapping-1.14.4-fabric-forge.txt")) { - "1.12.2"(11202, "srg", file("versions/1.14.4-forge/mapping.txt")) { - "1.12.1"(11201, "srg") { - "1.12"(11200, "srg") { - "1.11.2"(11102, "srg", file("versions/1.12/mapping.txt")) { - "1.11"(11100, "srg", file("versions/1.11.2/mapping.txt")) { - "1.10.2"(11002, "srg", file("versions/1.11/mapping.txt")) { - "1.9.4"(10904, "srg") { - "1.8.9"(10809, "srg", file("versions/1.9.4/mapping.txt")) { - "1.8"(10800, "srg", file("versions/1.8.9/mapping.txt")) { - "1.7.10"(10710, "srg", file("versions/1.8/mapping.txt")) - } - } - } - } - } - } - } - } - } - } - } - } - } - } + val mc11604 = createNode("1.16.4", 11604, "yarn") + val mc11601 = createNode("1.16.1", 11601, "yarn") + val mc11502 = createNode("1.15.2", 11502, "yarn") + val mc11404 = createNode("1.14.4", 11404, "yarn") + val mc11404Forge = createNode("1.14.4-forge", 11404, "srg") + val mc11202 = createNode("1.12.2", 11202, "srg") + val mc11201 = createNode("1.12.1", 11201, "srg") + val mc11200 = createNode("1.12", 11200, "srg") + val mc11102 = createNode("1.11.2", 11102, "srg") + val mc11100 = createNode("1.11", 11100, "srg") + val mc11002 = createNode("1.10.2", 11002, "srg") + val mc10904 = createNode("1.9.4", 10904, "srg") + val mc10809 = createNode("1.8.9", 10809, "srg") + val mc10800 = createNode("1.8", 10800, "srg") + val mc10710 = createNode("1.7.10", 10710, "srg") + + mc11604.link(mc11601) + mc11601.link(mc11502) + mc11502.link(mc11404, file("versions/mapping-fabric-1.15.2-1.14.4.txt")) + mc11404.link(mc11404Forge, file("versions/mapping-1.14.4-fabric-forge.txt")) + mc11404Forge.link(mc11202, file("versions/1.14.4-forge/mapping.txt")) + mc11202.link(mc11201) + mc11201.link(mc11200) + mc11200.link(mc11102, file("versions/1.12/mapping.txt")) + mc11102.link(mc11100, file("versions/1.11.2/mapping.txt")) + mc11100.link(mc11002, file("versions/1.11/mapping.txt")) + mc11002.link(mc10904) + mc10904.link(mc10809, file("versions/1.9.4/mapping.txt")) + mc10809.link(mc10800, file("versions/1.8.9/mapping.txt")) + mc10800.link(mc10710, file("versions/1.8/mapping.txt")) } From 9d3583293bd375548bb4687711b8e9e6e5c12b05 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 5 Jun 2021 18:06:06 +0200 Subject: [PATCH 069/102] Bundle Gson on 1.11.2 and below (fixes #421) Decided to go with 1.11.2 because the Gson from that version is the first to not have the JsonAdapter annotiation, which we want for fixing #520. --- build.gradle | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a0a3e43a..93f5c79d 100644 --- a/build.gradle +++ b/build.gradle @@ -228,7 +228,7 @@ def shadeExclusions = { // Cannot just add these to the shade configuration because they'd be inherited by the compile configuration then exclude group: 'com.google.guava', module: 'guava-jdk5' exclude group: 'com.google.guava', module: 'guava' // provided by MC - exclude group: 'com.google.code.gson', module: 'gson' // provided by MC + exclude group: 'com.google.code.gson', module: 'gson' // provided by MC (or manually bundled for 1.11.2 and below) } dependencies { @@ -312,6 +312,11 @@ dependencies { } } + if (mcVersion < 11200) { + // The version which MC ships is too old, we'll need to ship our own + shadow 'com.google.code.gson:gson:2.8.7' + } + shadow 'com.github.javagl.JglTF:jgltf-model:3af6de4' if (FABRIC) { From 25a6cdc502f2800be69249c5e7f2863b67039564 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 5 Jun 2021 13:04:23 +0200 Subject: [PATCH 070/102] Fix RenderSettings (de)serialization with Java 16 (fixes #520) Turns out we were relying on the implementation detail of the File class, and Java 16 ensures we cannot do that. --- .../replaymod/core/utils/FileTypeAdapter.java | 30 +++++++++++++++++++ .../com/replaymod/render/RenderSettings.java | 3 ++ 2 files changed, 33 insertions(+) create mode 100644 src/main/java/com/replaymod/core/utils/FileTypeAdapter.java diff --git a/src/main/java/com/replaymod/core/utils/FileTypeAdapter.java b/src/main/java/com/replaymod/core/utils/FileTypeAdapter.java new file mode 100644 index 00000000..78d76f90 --- /dev/null +++ b/src/main/java/com/replaymod/core/utils/FileTypeAdapter.java @@ -0,0 +1,30 @@ +package com.replaymod.core.utils; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; + +import java.io.File; +import java.io.IOException; + +public class FileTypeAdapter extends TypeAdapter { + @Override + public void write(JsonWriter out, File value) throws IOException { + out.value(value.getPath()); + } + + @Override + public File read(JsonReader in) throws IOException { + String path; + if (in.peek() == JsonToken.BEGIN_OBJECT) { + in.beginObject(); + in.nextName(); + path = in.nextString(); + in.endObject(); + } else { + path = in.nextString(); + } + return new File(path); + } +} diff --git a/src/main/java/com/replaymod/render/RenderSettings.java b/src/main/java/com/replaymod/render/RenderSettings.java index bfc8783f..0eea5951 100644 --- a/src/main/java/com/replaymod/render/RenderSettings.java +++ b/src/main/java/com/replaymod/render/RenderSettings.java @@ -1,6 +1,8 @@ package com.replaymod.render; +import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; +import com.replaymod.core.utils.FileTypeAdapter; import com.replaymod.core.versions.MCVer; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableColor; import net.minecraft.client.resource.language.I18n; @@ -146,6 +148,7 @@ public class RenderSettings { private final int videoHeight; private final int framesPerSecond; private final int bitRate; + @JsonAdapter(FileTypeAdapter.class) private final File outputFile; private final boolean renderNameTags; From 5f2dca08d1be89f019c2281d42edd96d96894667 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 5 Jun 2021 13:34:48 +0200 Subject: [PATCH 071/102] Fix "Cannot register receiver while client is not logging in!" Since MC provides no reliable way to get the connection while still in the login phase, Fabric API tries to determine it either from MinecraftClient's connection field (for the integrated server) or from the ConnectScreen (for multiplayer). However, neither is present during a replay, leading to the aforementioned error. To fix this, we store our ClientConnection in MinecraftClient's connection field. This should have no significant effect on vanilla behavior. Also remove the dead Forge 1.14 code which was in the same place. --- .../java/com/replaymod/core/mixin/MinecraftAccessor.java | 6 ++++++ src/main/java/com/replaymod/replay/ReplayHandler.java | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/replaymod/core/mixin/MinecraftAccessor.java b/src/main/java/com/replaymod/core/mixin/MinecraftAccessor.java index 1ec58296..10eb4f06 100644 --- a/src/main/java/com/replaymod/core/mixin/MinecraftAccessor.java +++ b/src/main/java/com/replaymod/core/mixin/MinecraftAccessor.java @@ -1,6 +1,7 @@ package com.replaymod.core.mixin; import net.minecraft.client.MinecraftClient; +import net.minecraft.network.ClientConnection; import net.minecraft.util.crash.CrashReport; import net.minecraft.client.render.RenderTickCounter; import org.spongepowered.asm.mixin.Mixin; @@ -50,4 +51,9 @@ public interface MinecraftAccessor { //$$ @Accessor //$$ List getDefaultResourcePacks(); //#endif + + //#if MC>=11400 + @Accessor + void setConnection(ClientConnection connection); + //#endif } diff --git a/src/main/java/com/replaymod/replay/ReplayHandler.java b/src/main/java/com/replaymod/replay/ReplayHandler.java index bddee69a..5863fffa 100644 --- a/src/main/java/com/replaymod/replay/ReplayHandler.java +++ b/src/main/java/com/replaymod/replay/ReplayHandler.java @@ -308,8 +308,8 @@ public class ReplayHandler { channel.pipeline().addLast("packet_handler", networkManager); channel.pipeline().fireChannelActive(); - //#if MC>=11400 && MC<11400 - //$$ NetworkHooks.registerClientLoginChannel(networkManager); + //#if MC>=11400 + ((MinecraftAccessor) mc).setConnection(networkManager); //#endif } From 1802b1a7d076588b68a4a9e20eef09654b625d8b Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 5 Jun 2021 18:05:26 +0200 Subject: [PATCH 072/102] Port to 1.17-pre1 --- build.gradle | 20 +- jGui | 2 +- root.gradle.kts | 4 +- settings.gradle.kts | 6 +- .../replaymod/core/gui/ModMenuApiImpl.java | 14 +- .../core/mixin/GuiScreenAccessor.java | 31 +-- .../core/mixin/MinecraftAccessor.java | 4 + .../replaymod/core/mixin/TimerAccessor.java | 2 + .../com/replaymod/core/versions/MCVer.java | 62 +++++- .../com/replaymod/core/versions/Patterns.java | 119 ++++++++++- .../versions/scheduler/SchedulerImpl.java | 2 +- .../recording/gui/GuiRecordingControls.java | 5 +- .../recording/gui/GuiRecordingOverlay.java | 12 +- .../packet/ResourcePackRecorder.java | 11 +- .../render/blend/BlendMeshBuilder.java | 37 +++- .../blend/exporters/ParticlesExporter.java | 3 +- .../render/capturer/ODSFrameCapturer.java | 9 +- .../render/capturer/OpenGlFrameCapturer.java | 13 +- .../render/mixin/MixinGlStateManager.java | 2 +- .../render/mixin/Mixin_StabilizeCamera.java | 6 +- .../render/rendering/VideoRenderer.java | 39 +++- .../replaymod/replay/FullReplaySender.java | 15 +- .../com/replaymod/replay/NoGuiScreenshot.java | 11 +- .../replaymod/replay/QuickReplaySender.java | 29 ++- .../com/replaymod/replay/ReplayHandler.java | 29 ++- .../replaymod/replay/camera/CameraEntity.java | 11 +- .../replaymod/replay/handler/GuiHandler.java | 16 +- .../replay/mixin/MixinRenderArrow.java | 13 +- .../MixinTileEntityEndPortalRenderer.java | 2 +- .../gui/GuiKeyframeTimeline.java | 73 +++---- .../preview/PathPreviewRenderer.java | 189 ++++++++++-------- .../resources/mixins.render.replaymod.json | 2 +- .../render/mixin/MixinGlStateManager.java | 1 + .../MixinTileEntityEndPortalRenderer.java | 9 + versions/mapping-fabric-1.17-1.16.4.txt | 4 + 35 files changed, 582 insertions(+), 225 deletions(-) create mode 100644 versions/1.17/src/main/java/com/replaymod/render/mixin/MixinGlStateManager.java create mode 100644 versions/1.17/src/main/java/com/replaymod/replay/mixin/MixinTileEntityEndPortalRenderer.java create mode 100644 versions/mapping-fabric-1.17-1.16.4.txt diff --git a/build.gradle b/build.gradle index 93f5c79d..96bacf0d 100644 --- a/build.gradle +++ b/build.gradle @@ -108,8 +108,7 @@ preprocess { def mcVersionStr = "${(int)(mcVersion/10000)}.${(int)(mcVersion/100)%100}" + (mcVersion%100==0 ? '' : ".${mcVersion%100}") -sourceCompatibility = 1.8 -targetCompatibility = 1.8 +sourceCompatibility = targetCompatibility = mcVersion >= 11700 ? 16 : 1.8 if (mcVersion >= 11400) { sourceSets { @@ -239,6 +238,7 @@ dependencies { 11601: '1.16.1', 11603: '1.16.3', 11604: '1.16.4', + 11700: '1.17-rc1', ][mcVersion] mappings 'net.fabricmc:yarn:' + [ 11404: '1.14.4+build.16', @@ -246,6 +246,7 @@ dependencies { 11601: '1.16.1+build.17:v2', 11603: '1.16.3+build.1:v2', 11604: '1.16.4+build.6:v2', + 11700: '1.17-rc1+build.1:v2', ][mcVersion] modImplementation 'net.fabricmc:fabric-loader:' + [ 11404: '0.7.8+build.189', @@ -253,6 +254,7 @@ dependencies { 11601: '0.8.8+build.202', 11603: '0.9.1+build.205', 11604: '0.10.6+build.214', + 11700: '0.11.3', ][mcVersion] def fabricApiVersion = [ 11404: '0.4.3+build.247-1.14', @@ -260,6 +262,7 @@ dependencies { 11601: '0.14.0+build.371-1.16', 11603: '0.17.1+build.394-1.16', 11604: '0.25.1+build.416-1.16', + 11700: '0.34.8+1.17', ][mcVersion] def fabricApiModules = [ "api-base", @@ -335,7 +338,9 @@ dependencies { shadow 'com.github.ReplayMod:lwjgl-utils:27dcd66' if (FABRIC) { - if (mcVersion >= 11602) { + if (mcVersion >= 11700) { + modImplementation 'com.terraformersmc:modmenu:2.0.0-beta.7' + } else if (mcVersion >= 11602) { modImplementation 'com.terraformersmc:modmenu:1.16.8' } else if (mcVersion >= 11600) { modImplementation 'io.github.prospector:modmenu:1.14.0+build.24' @@ -502,6 +507,15 @@ jar { 'FMLAT': 'replaymod_at.cfg' } } + + if (mcVersion >= 11700) { + // Workaround a mixin bug which generates invalid refmaps for the `addDrawableChild` invoker + filesMatching("mixins.replaymod.refmap.json") { + it.filter { + it.replace("addDrawableChild(L/;)L/;", "method_37063(Lnet/minecraft/class_364;)Lnet/minecraft/class_364;") + } + } + } } processResources { diff --git a/jGui b/jGui index c3efefdc..cbf01d5c 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit c3efefdc99bcc3fc1dcd57707e50887789cd4d3a +Subproject commit cbf01d5c8d195784684f6bec37788829ab2be2ab diff --git a/root.gradle.kts b/root.gradle.kts index 2f0ff78f..d72ef4f5 100755 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -3,7 +3,7 @@ import java.io.ByteArrayOutputStream plugins { id("fabric-loom") version "0.8-SNAPSHOT" apply false - id("com.replaymod.preprocess") version "4b4dfe5" + id("com.replaymod.preprocess") version "123fb7a" id("com.github.hierynomus.license") version "0.15.0" } @@ -176,6 +176,7 @@ val doRelease by tasks.registering { defaultTasks("bundleJar") preprocess { + val mc11700 = createNode("1.17", 11700, "yarn") val mc11604 = createNode("1.16.4", 11604, "yarn") val mc11601 = createNode("1.16.1", 11601, "yarn") val mc11502 = createNode("1.15.2", 11502, "yarn") @@ -192,6 +193,7 @@ preprocess { val mc10800 = createNode("1.8", 10800, "srg") val mc10710 = createNode("1.7.10", 10710, "srg") + mc11700.link(mc11604, file("versions/mapping-fabric-1.17-1.16.4.txt")) mc11604.link(mc11601) mc11601.link(mc11502) mc11502.link(mc11404, file("versions/mapping-fabric-1.15.2-1.14.4.txt")) diff --git a/settings.gradle.kts b/settings.gradle.kts index 83b337e3..8ef8c7df 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -28,7 +28,8 @@ val jGuiVersions = listOf( "1.14.4", "1.15.2", "1.16.1", - "1.16.4" + "1.16.4", + "1.17", ) val replayModVersions = listOf( // "1.7.10", @@ -45,7 +46,8 @@ val replayModVersions = listOf( "1.14.4", "1.15.2", "1.16.1", - "1.16.4" + "1.16.4", + "1.17", ) rootProject.buildFileName = "root.gradle.kts" diff --git a/src/main/java/com/replaymod/core/gui/ModMenuApiImpl.java b/src/main/java/com/replaymod/core/gui/ModMenuApiImpl.java index 666a3174..46f75da0 100644 --- a/src/main/java/com/replaymod/core/gui/ModMenuApiImpl.java +++ b/src/main/java/com/replaymod/core/gui/ModMenuApiImpl.java @@ -2,19 +2,31 @@ package com.replaymod.core.gui; import com.replaymod.core.ReplayMod; -import io.github.prospector.modmenu.api.ModMenuApi; import net.minecraft.client.gui.screen.Screen; import java.util.function.Function; +//#if MC>=11700 +//$$ import com.terraformersmc.modmenu.api.ConfigScreenFactory; +//$$ import com.terraformersmc.modmenu.api.ModMenuApi; +//#else +import io.github.prospector.modmenu.api.ModMenuApi; +//#endif + public class ModMenuApiImpl implements ModMenuApi { + //#if MC<11700 @Override public String getModId() { return ReplayMod.MOD_ID; } + //#endif @Override + //#if MC>=11700 + //$$ public ConfigScreenFactory getModConfigScreenFactory() { + //#else public Function getConfigScreenFactory() { + //#endif return parent -> new GuiReplaySettings(parent, ReplayMod.instance.getSettingsRegistry()).toMinecraft(); } } diff --git a/src/main/java/com/replaymod/core/mixin/GuiScreenAccessor.java b/src/main/java/com/replaymod/core/mixin/GuiScreenAccessor.java index d55529b2..9bdc5323 100644 --- a/src/main/java/com/replaymod/core/mixin/GuiScreenAccessor.java +++ b/src/main/java/com/replaymod/core/mixin/GuiScreenAccessor.java @@ -2,32 +2,33 @@ package com.replaymod.core.mixin; import net.minecraft.client.gui.screen.Screen; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; -import java.util.List; - -//#if MC>=11400 -import net.minecraft.client.gui.widget.AbstractButtonWidget; +//#if MC>=11700 +//$$ import net.minecraft.client.gui.Drawable; +//$$ import net.minecraft.client.gui.Element; +//$$ import net.minecraft.client.gui.Selectable; //#else -//$$ import net.minecraft.client.gui.GuiButton; //#endif //#if MC>=11400 -import net.minecraft.client.gui.Element; +import net.minecraft.client.gui.widget.AbstractButtonWidget; +import org.spongepowered.asm.mixin.gen.Invoker; +//#else +//$$ import net.minecraft.client.gui.GuiButton; +//$$ import org.spongepowered.asm.mixin.gen.Accessor; +//$$ import java.util.List; //#endif @Mixin(Screen.class) public interface GuiScreenAccessor { - //#if MC>=11400 - @Accessor - List getButtons(); + //#if MC>=11700 + //$$ @Invoker("addDrawableChild") + //$$ T invokeAddButton(T drawableElement); + //#elseif MC>=11400 + @Invoker + T invokeAddButton(T button); //#else //$$ @Accessor("buttonList") //$$ List getButtons(); //#endif - - //#if MC>=11400 - @Accessor - List getChildren(); - //#endif } diff --git a/src/main/java/com/replaymod/core/mixin/MinecraftAccessor.java b/src/main/java/com/replaymod/core/mixin/MinecraftAccessor.java index 10eb4f06..8f26e4f5 100644 --- a/src/main/java/com/replaymod/core/mixin/MinecraftAccessor.java +++ b/src/main/java/com/replaymod/core/mixin/MinecraftAccessor.java @@ -5,6 +5,7 @@ import net.minecraft.network.ClientConnection; import net.minecraft.util.crash.CrashReport; import net.minecraft.client.render.RenderTickCounter; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; import org.spongepowered.asm.mixin.gen.Accessor; import java.util.Queue; @@ -27,6 +28,9 @@ public interface MinecraftAccessor { @Accessor("renderTickCounter") RenderTickCounter getTimer(); @Accessor("renderTickCounter") + //#if MC>=11200 + @Mutable + //#endif void setTimer(RenderTickCounter value); //#if MC>=11400 diff --git a/src/main/java/com/replaymod/core/mixin/TimerAccessor.java b/src/main/java/com/replaymod/core/mixin/TimerAccessor.java index 0f10f261..78f7da1a 100644 --- a/src/main/java/com/replaymod/core/mixin/TimerAccessor.java +++ b/src/main/java/com/replaymod/core/mixin/TimerAccessor.java @@ -2,6 +2,7 @@ package com.replaymod.core.mixin; import net.minecraft.client.render.RenderTickCounter; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(RenderTickCounter.class) @@ -15,6 +16,7 @@ public interface TimerAccessor { @Accessor("tickTime") float getTickLength(); @Accessor("tickTime") + @Mutable void setTickLength(float value); //#else //$$ @Accessor diff --git a/src/main/java/com/replaymod/core/versions/MCVer.java b/src/main/java/com/replaymod/core/versions/MCVer.java index d5282f4b..a2702d6a 100644 --- a/src/main/java/com/replaymod/core/versions/MCVer.java +++ b/src/main/java/com/replaymod/core/versions/MCVer.java @@ -1,11 +1,17 @@ package com.replaymod.core.versions; +import com.mojang.blaze3d.platform.GlStateManager; import com.replaymod.core.mixin.GuiScreenAccessor; import com.replaymod.replaystudio.protocol.PacketTypeRegistry; import com.replaymod.replaystudio.us.myles.ViaVersion.api.protocol.ProtocolVersion; import com.replaymod.replaystudio.us.myles.ViaVersion.packets.State; +import de.johni0702.minecraft.gui.MinecraftGuiRenderer; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector2f; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.render.BufferBuilder; +import net.minecraft.util.Identifier; import net.minecraft.util.Util; //#if MC>=11600 @@ -206,14 +212,15 @@ public class MCVer { //#endif ) { GuiScreenAccessor acc = (GuiScreenAccessor) screen; - acc.getButtons().add(button); //#if MC>=11400 - acc.getChildren().add(button); + acc.invokeAddButton(button); + //#else + //$$ acc.getButtons().add(button); //#endif } //#if MC>=11400 - public static Optional findButton(List buttonList, @SuppressWarnings("unused") String text, @SuppressWarnings("unused") int id) { + public static Optional findButton(Iterable buttonList, @SuppressWarnings("unused") String text, @SuppressWarnings("unused") int id) { //#if MC>=11600 final TranslatableText message = new TranslatableText(text); //#else @@ -233,7 +240,7 @@ public class MCVer { return Optional.empty(); } //#else - //$$ public static Optional findButton(List buttonList, @SuppressWarnings("unused") String text, int id) { + //$$ public static Optional findButton(Iterable buttonList, @SuppressWarnings("unused") String text, int id) { //$$ for (GuiButton b : buttonList) { //$$ if (b.id == id) { //$$ return Optional.of(b); @@ -332,6 +339,53 @@ public class MCVer { //#endif } + public static void pushMatrix() { + //#if MC>=11700 + //$$ RenderSystem.getModelViewStack().push(); + //#else + GlStateManager.pushMatrix(); + //#endif + } + + public static void popMatrix() { + //#if MC>=11700 + //$$ RenderSystem.getModelViewStack().pop(); + //$$ RenderSystem.applyModelViewMatrix(); + //#else + GlStateManager.popMatrix(); + //#endif + } + + public static void emitLine(BufferBuilder buffer, Vector2f p1, Vector2f p2, int color) { + emitLine(buffer, new Vector3f(p1.x, p1.y, 0), new Vector3f(p2.x, p2.y, 0), color); + } + + public static void emitLine(BufferBuilder buffer, Vector3f p1, Vector3f p2, int color) { + int r = color >> 24 & 0xff; + int g = color >> 16 & 0xff; + int b = color >> 8 & 0xff; + int a = color & 0xff; + //#if MC>=11700 + //$$ Vector3f n = Vector3f.sub(p2, p1, null); + //#endif + buffer.vertex(p1.x, p1.y, p1.z) + .color(r, g, b, a) + //#if MC>=11700 + //$$ .normal(n.x, n.y, n.z) + //#endif + .next(); + buffer.vertex(p2.x, p2.y, p2.z) + .color(r, g, b, a) + //#if MC>=11700 + //$$ .normal(n.x, n.y, n.z) + //#endif + .next(); + } + + public static void bindTexture(Identifier id) { + new MinecraftGuiRenderer(null).bindTexture(id); + } + //#if MC<10900 //$$ public static class SoundEvent {} //#endif diff --git a/src/main/java/com/replaymod/core/versions/Patterns.java b/src/main/java/com/replaymod/core/versions/Patterns.java index 8c62dd6c..c7e1371d 100644 --- a/src/main/java/com/replaymod/core/versions/Patterns.java +++ b/src/main/java/com/replaymod/core/versions/Patterns.java @@ -3,6 +3,7 @@ package com.replaymod.core.versions; import com.replaymod.gradle.remap.Pattern; import net.minecraft.client.MinecraftClient; import net.minecraft.client.options.KeyBinding; +import net.minecraft.client.render.VertexFormat; import net.minecraft.client.texture.TextureManager; import net.minecraft.client.world.ClientWorld; import net.minecraft.client.render.Tessellator; @@ -16,6 +17,11 @@ import net.minecraft.util.Identifier; import net.minecraft.world.World; import net.minecraft.world.chunk.WorldChunk; +//#if MC>=11700 +//#else +import org.lwjgl.opengl.GL11; +//#endif + //#if MC>=11400 import net.minecraft.client.gui.widget.AbstractButtonWidget; import net.minecraft.client.util.Window; @@ -88,6 +94,42 @@ class Patterns { //#endif } + @Pattern + private static void Entity_setYaw(Entity entity, float value) { + //#if MC>=11700 + //$$ entity.setYaw(value); + //#else + entity.yaw = value; + //#endif + } + + @Pattern + private static float Entity_getYaw(Entity entity) { + //#if MC>=11700 + //$$ return entity.getYaw(); + //#else + return entity.yaw; + //#endif + } + + @Pattern + private static void Entity_setPitch(Entity entity, float value) { + //#if MC>=11700 + //$$ entity.setPitch(value); + //#else + entity.pitch = value; + //#endif + } + + @Pattern + private static float Entity_getPitch(Entity entity) { + //#if MC>=11700 + //$$ return entity.getPitch(); + //#else + return entity.pitch; + //#endif + } + @Pattern private static void Entity_setPos(Entity entity, double x, double y, double z) { //#if MC>=11500 @@ -187,13 +229,19 @@ class Patterns { } @Pattern + //#if MC>=11700 + //$$ private static void getEntitySectionArray() {} + //#else private static Collection[] getEntitySectionArray(WorldChunk chunk) { - //#if MC>=10800 + //#if MC>=11700 + //$$ return obsolete(chunk); + //#elseif MC>=10800 return chunk.getEntitySectionArray(); //#else //$$ return chunk.entityLists; //#endif } + //#endif @Pattern private static List playerEntities(World world) { @@ -244,6 +292,7 @@ class Patterns { //#endif } + //#if MC<11700 @Pattern private static void BufferBuilder_beginPosCol(BufferBuilder buffer, int mode) { //#if MC>=10809 @@ -297,6 +346,14 @@ class Patterns { //$$ { WorldRenderer $buffer = buffer; double $x = x; double $y = y; double $z = z; float $u = u; float $v = v; $buffer.setColorRGBA(r, g, b, a); $buffer.addVertexWithUV($x, $y, $z, $u, $v); } //#endif } + //#else + @Pattern private static void BufferBuilder_beginPosCol() {} + @Pattern private static void BufferBuilder_addPosCol() {} + @Pattern private static void BufferBuilder_beginPosTex() {} + @Pattern private static void BufferBuilder_addPosTex() {} + @Pattern private static void BufferBuilder_beginPosTexCol() {} + @Pattern private static void BufferBuilder_addPosTexCol() {} + //#endif @Pattern private static Tessellator Tessellator_getInstance() { @@ -382,4 +439,64 @@ class Patterns { //$$ return (a.getKeyCode() == b.getKeyCode()); //#endif } + + //#if MC>=11600 + @Pattern + private static void BufferBuilder_beginLineStrip(BufferBuilder buffer, VertexFormat vertexFormat) { + //#if MC>=11700 + //$$ buffer.begin(net.minecraft.client.render.VertexFormat.DrawMode.LINE_STRIP, VertexFormats.LINES); + //#else + buffer.begin(GL11.GL_LINE_STRIP, VertexFormats.POSITION_COLOR); + //#endif + } + + @Pattern + private static void BufferBuilder_beginLines(BufferBuilder buffer) { + //#if MC>=11700 + //$$ buffer.begin(net.minecraft.client.render.VertexFormat.DrawMode.LINES, VertexFormats.LINES); + //#else + buffer.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR); + //#endif + } + + @Pattern + private static void BufferBuilder_beginQuads(BufferBuilder buffer, VertexFormat vertexFormat) { + //#if MC>=11700 + //$$ buffer.begin(net.minecraft.client.render.VertexFormat.DrawMode.QUADS, vertexFormat); + //#else + buffer.begin(GL11.GL_QUADS, vertexFormat); + //#endif + } + //#else + //$$ @Pattern private static void BufferBuilder_beginLineStrip() {} + //$$ @Pattern private static void BufferBuilder_beginLines() {} + //$$ @Pattern private static void BufferBuilder_beginQuads() {} + //#endif + + @Pattern + private static void GL11_glLineWidth(float width) { + //#if MC>=11700 + //$$ com.mojang.blaze3d.systems.RenderSystem.lineWidth(width); + //#else + GL11.glLineWidth(width); + //#endif + } + + @Pattern + private static void GL11_glTranslatef(float x, float y, float z) { + //#if MC>=11700 + //$$ com.mojang.blaze3d.systems.RenderSystem.getModelViewStack().translate(x, y, z); + //#else + GL11.glTranslatef(x, y, z); + //#endif + } + + @Pattern + private static void GL11_glRotatef(float angle, float x, float y, float z) { + //#if MC>=11700 + //$$ { float $angle = angle; com.mojang.blaze3d.systems.RenderSystem.getModelViewStack().multiply(new net.minecraft.util.math.Quaternion(new net.minecraft.util.math.Vec3f(x, y, z), $angle, true)); } + //#else + GL11.glRotatef(angle, x, y, z); + //#endif + } } diff --git a/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java b/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java index 2da1760a..dc3664fe 100644 --- a/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java +++ b/src/main/java/com/replaymod/core/versions/scheduler/SchedulerImpl.java @@ -29,7 +29,7 @@ public class SchedulerImpl implements Scheduler { runLater(new Runnable() { @Override public void run() { - if (mc.overlay != null) { + if (mc.getOverlay() != null) { // delay until after resources have been loaded runLater(this); return; diff --git a/src/main/java/com/replaymod/recording/gui/GuiRecordingControls.java b/src/main/java/com/replaymod/recording/gui/GuiRecordingControls.java index b9af9692..e766f0a5 100644 --- a/src/main/java/com/replaymod/recording/gui/GuiRecordingControls.java +++ b/src/main/java/com/replaymod/recording/gui/GuiRecordingControls.java @@ -19,6 +19,7 @@ import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.AbstractButtonWidget; //#endif +import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.function.Function; @@ -78,9 +79,9 @@ public class GuiRecordingControls extends EventRegistrations { { on(InitScreenCallback.EVENT, this::injectIntoIngameMenu); } private void injectIntoIngameMenu(Screen guiScreen, //#if MC>=11400 - List buttonList + Collection buttonList //#else - //$$ List buttonList + //$$ Collection buttonList //#endif ) { if (!(guiScreen instanceof GameMenuScreen)) { diff --git a/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java b/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java index 06783108..ab9ee2e6 100644 --- a/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java +++ b/src/main/java/com/replaymod/recording/gui/GuiRecordingOverlay.java @@ -38,14 +38,12 @@ public class GuiRecordingOverlay extends EventRegistrations { if (settingsRegistry.get(Setting.INDICATOR)) { TextRenderer fontRenderer = mc.textRenderer; String text = guiControls.isPaused() ? I18n.translate("replaymod.gui.paused") : I18n.translate("replaymod.gui.recording"); - fontRenderer.draw( - //#if MC>=11600 - stack, - //#endif - text.toUpperCase(), 30, 18 - (fontRenderer.fontHeight / 2), 0xffffffff); - mc.getTextureManager().bindTexture(TEXTURE); + MinecraftGuiRenderer renderer = new MinecraftGuiRenderer(stack); + renderer.drawString(30, 18 - (fontRenderer.fontHeight / 2), 0xffffffff, text.toUpperCase()); + renderer.bindTexture(TEXTURE); + //#if MC<11700 enableAlphaTest(); - GuiRenderer renderer = new MinecraftGuiRenderer(stack); + //#endif renderer.drawTexturedRect(10, 10, 58, 20, 16, 16, 16, 16, TEXTURE_SIZE, TEXTURE_SIZE); } } diff --git a/src/main/java/com/replaymod/recording/packet/ResourcePackRecorder.java b/src/main/java/com/replaymod/recording/packet/ResourcePackRecorder.java index 6c28c388..05a219b4 100644 --- a/src/main/java/com/replaymod/recording/packet/ResourcePackRecorder.java +++ b/src/main/java/com/replaymod/recording/packet/ResourcePackRecorder.java @@ -172,7 +172,12 @@ public class ResourcePackRecorder { } } - return new ResourcePackSendS2CPacket("replay://" + requestId, ""); + return new ResourcePackSendS2CPacket( + "replay://" + requestId, "" + //#if MC>=11700 + //$$ , packet.isRequired(), packet.getPrompt() + //#endif + ); } private void downloadResourcePackFuture(int requestId, String url, final String hash) { @@ -190,7 +195,11 @@ public class ResourcePackRecorder { downloadResourcePack(final int requestId, String url, String hash) { ClientBuiltinResourcePackProvider packFinder = mc.getResourcePackDownloader(); ((IDownloadingPackFinder) packFinder).setRequestCallback(file -> recordResourcePack(file, requestId)); + //#if MC>=11700 + //$$ return packFinder.download(url, hash, true); + //#else return packFinder.download(url, hash); + //#endif } public interface IDownloadingPackFinder { diff --git a/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java b/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java index 49dba018..8b9e2f50 100644 --- a/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java +++ b/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java @@ -63,7 +63,9 @@ public class BlendMeshBuilder } @Override - //#if MC>=10809 + //#if MC>=11700 + //$$ public void begin(VertexFormat.DrawMode mode, VertexFormat vertexFormat) { + //#elseif MC>=10809 public void begin(int mode, VertexFormat vertexFormat) { //#else //$$ public void startDrawing(int mode) { @@ -148,7 +150,17 @@ public class BlendMeshBuilder //#endif } - public static DMesh addBufferToMesh(ByteBuffer buffer, int mode, VertexFormat vertexFormat, DMesh mesh, ReadableVector3f vertOffset) { + public static DMesh addBufferToMesh( + ByteBuffer buffer, + //#if MC>=11700 + //$$ VertexFormat.DrawMode mode, + //#else + int mode, + //#endif + VertexFormat vertexFormat, + DMesh mesh, + ReadableVector3f vertOffset + ) { //#if MC>=11400 int vertexCount = buffer.remaining() / vertexFormat.getVertexSize(); //#else @@ -157,7 +169,18 @@ public class BlendMeshBuilder return addBufferToMesh(buffer, vertexCount, mode, vertexFormat, mesh, vertOffset); } - public static DMesh addBufferToMesh(ByteBuffer buffer, int vertexCount, int mode, VertexFormat vertexFormat, DMesh mesh, ReadableVector3f vertOffset) { + public static DMesh addBufferToMesh( + ByteBuffer buffer, + int vertexCount, + //#if MC>=11700 + //$$ VertexFormat.DrawMode mode, + //#else + int mode, + //#endif + VertexFormat vertexFormat, + DMesh mesh, + ReadableVector3f vertOffset + ) { if (mesh == null) { mesh = new DMesh(); } @@ -261,7 +284,11 @@ public class BlendMeshBuilder // Bundle vertices into shapes and add them to the mesh switch (mode) { + //#if MC>=11700 + //$$ case TRIANGLES: + //#else case GL11.GL_TRIANGLES: + //#endif for (int i = 0; i < vertices.size(); i+=3) { mesh.addTriangle( vertices.get(i ), @@ -277,7 +304,11 @@ public class BlendMeshBuilder ); } break; + //#if MC>=11700 + //$$ case QUADS: + //#else case GL11.GL_QUADS: + //#endif for (int i = 0; i < vertices.size(); i+=4) { mesh.addQuad( vertices.get(i ), diff --git a/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java index 3cf2fb1a..2aecf1a4 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java @@ -11,6 +11,7 @@ import com.replaymod.render.blend.mixin.ParticleAccessor; import de.johni0702.minecraft.gui.utils.lwjgl.vector.Matrix4f; import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f; import net.minecraft.client.MinecraftClient; +import org.lwjgl.opengl.GL11; //#if MC>=11400 import net.minecraft.util.math.Vec3d; @@ -169,7 +170,7 @@ public class ParticlesExporter implements Exporter { builder.setReverseOffset(offset); builder.setWellBehaved(true); //#if MC>=10809 - builder.begin(7, VertexFormats.POSITION_TEXTURE_COLOR_LIGHT); + builder.begin(GL11.GL_QUADS, VertexFormats.POSITION_TEXTURE_COLOR_LIGHT); //#else //$$ builder.startDrawingQuads(); //#endif diff --git a/src/main/java/com/replaymod/render/capturer/ODSFrameCapturer.java b/src/main/java/com/replaymod/render/capturer/ODSFrameCapturer.java index d4bb955a..4df2fa18 100644 --- a/src/main/java/com/replaymod/render/capturer/ODSFrameCapturer.java +++ b/src/main/java/com/replaymod/render/capturer/ODSFrameCapturer.java @@ -1,5 +1,6 @@ package com.replaymod.render.capturer; +import com.mojang.blaze3d.platform.GlStateManager; import com.replaymod.render.rendering.Channel; import de.johni0702.minecraft.gui.utils.EventRegistrations; import com.replaymod.render.RenderSettings; @@ -15,12 +16,12 @@ import net.minecraft.util.crash.CrashReport; import net.minecraft.util.crash.CrashException; import net.minecraft.util.Identifier; -import static com.mojang.blaze3d.platform.GlStateManager.*; - import java.io.IOException; import java.util.HashMap; import java.util.Map; +import static com.replaymod.core.versions.MCVer.popMatrix; +import static com.replaymod.core.versions.MCVer.pushMatrix; import static com.replaymod.core.versions.MCVer.resizeMainWindow; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; @@ -170,12 +171,12 @@ public class ODSFrameCapturer implements FrameCapturer { pushMatrix(); frameBuffer().beginWrite(true); - clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT + GlStateManager.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT //#if MC>=11400 , false //#endif ); - enableTexture(); + GlStateManager.enableTexture(); directionVariable.set(captureData.ordinal()); worldRenderer.renderWorld(partialTicks, null); diff --git a/src/main/java/com/replaymod/render/capturer/OpenGlFrameCapturer.java b/src/main/java/com/replaymod/render/capturer/OpenGlFrameCapturer.java index f5b89064..eb26e0bc 100644 --- a/src/main/java/com/replaymod/render/capturer/OpenGlFrameCapturer.java +++ b/src/main/java/com/replaymod/render/capturer/OpenGlFrameCapturer.java @@ -1,5 +1,6 @@ package com.replaymod.render.capturer; +import com.mojang.blaze3d.platform.GlStateManager; import com.replaymod.core.versions.MCVer; import com.replaymod.render.frame.OpenGlFrame; import com.replaymod.render.rendering.Frame; @@ -16,12 +17,8 @@ import org.lwjgl.opengl.GL12; import java.io.IOException; import java.nio.ByteBuffer; -//#if MC>=10800 -import static com.mojang.blaze3d.platform.GlStateManager.*; -//#else -//$$ import static com.replaymod.core.versions.MCVer.GlStateManager.*; -//#endif - +import static com.replaymod.core.versions.MCVer.popMatrix; +import static com.replaymod.core.versions.MCVer.pushMatrix; import static com.replaymod.core.versions.MCVer.resizeMainWindow; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; @@ -86,12 +83,12 @@ public abstract class OpenGlFrameCapturer=11400 , false //#endif ); - enableTexture(); + GlStateManager.enableTexture(); worldRenderer.renderWorld(partialTicks, captureData); diff --git a/src/main/java/com/replaymod/render/mixin/MixinGlStateManager.java b/src/main/java/com/replaymod/render/mixin/MixinGlStateManager.java index 84a06a3d..71aecaa2 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinGlStateManager.java +++ b/src/main/java/com/replaymod/render/mixin/MixinGlStateManager.java @@ -1,4 +1,4 @@ -//#if MC>=10800 +//#if MC>=10800 && MC<11700 package com.replaymod.render.mixin; import com.replaymod.render.hooks.FogStateCallback; diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_StabilizeCamera.java b/src/main/java/com/replaymod/render/mixin/Mixin_StabilizeCamera.java index 564c805c..1ff658ac 100644 --- a/src/main/java/com/replaymod/render/mixin/Mixin_StabilizeCamera.java +++ b/src/main/java/com/replaymod/render/mixin/Mixin_StabilizeCamera.java @@ -83,13 +83,15 @@ public abstract class Mixin_StabilizeCamera { //#endif RenderSettings settings = getHandler().getSettings(); if (settings.isStabilizeYaw()) { - entity.prevYaw = entity.yaw = 0; + entity.prevYaw = 0; + entity.yaw = 0; if (entity instanceof LivingEntity) { ((LivingEntity) entity).prevHeadYaw = ((LivingEntity) entity).headYaw = 0; } } if (settings.isStabilizePitch()) { - entity.prevPitch = entity.pitch = 0; + entity.prevPitch = 0; + entity.pitch = 0; } if (settings.isStabilizeRoll() && entity instanceof CameraEntity) { ((CameraEntity) entity).roll = 0; diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index 762c74e9..5ce80a9a 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -1,5 +1,6 @@ package com.replaymod.render.rendering; +import com.mojang.blaze3d.platform.GlStateManager; import com.replaymod.core.mixin.MinecraftAccessor; import com.replaymod.core.mixin.TimerAccessor; import com.replaymod.core.utils.WrappedTimer; @@ -40,6 +41,12 @@ import net.minecraft.sound.SoundCategory; import net.minecraft.client.render.RenderTickCounter; import org.lwjgl.glfw.GLFW; +//#if MC>=11700 +//$$ import net.minecraft.client.gl.WindowFramebuffer; +//$$ import net.minecraft.client.render.DiffuseLighting; +//$$ import net.minecraft.util.math.Matrix4f; +//#endif + //#if MC>=11600 import net.minecraft.client.util.math.MatrixStack; //#endif @@ -59,10 +66,8 @@ import java.util.concurrent.CompletableFuture; //#endif //#if MC>=10800 -import static com.mojang.blaze3d.platform.GlStateManager.*; //#else //$$ import com.replaymod.replay.gui.screen.GuiOpeningReplay; -//$$ import static com.replaymod.core.versions.MCVer.GlStateManager.*; //#endif import java.io.IOException; @@ -360,11 +365,15 @@ public class VideoRenderer implements RenderInfo { forceChunkLoadingHook = new ForceChunkLoadingHook(mc.worldRenderer); // Set up our own framebuffer to render the GUI to + //#if MC>=11700 + //$$ guiFramebuffer = new WindowFramebuffer(displayWidth, displayHeight); + //#else guiFramebuffer = new Framebuffer(displayWidth, displayHeight, true //#if MC>=11400 , false //#endif ); + //#endif } private void finish() { @@ -419,7 +428,7 @@ public class VideoRenderer implements RenderInfo { private void executeTaskQueue() { //#if MC>=11400 while (true) { - while (mc.overlay != null) { + while (mc.getOverlay() != null) { drawGui(); ((MinecraftMethodAccessor) mc).replayModExecuteTaskQueue(); } @@ -486,22 +495,38 @@ public class VideoRenderer implements RenderInfo { } pushMatrix(); - clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT + GlStateManager.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT //#if MC>=11400 , false //#endif ); - enableTexture(); + GlStateManager.enableTexture(); guiFramebuffer.beginWrite(true); //#if MC>=11500 RenderSystem.clear(256, MinecraftClient.IS_SYSTEM_MAC); + //#if MC>=11700 + //$$ RenderSystem.setProjectionMatrix(Matrix4f.projectionMatrix( + //$$ 0, + //$$ (float) (window.getFramebufferWidth() / window.getScaleFactor()), + //$$ 0, + //$$ (float) (window.getFramebufferHeight() / window.getScaleFactor()), + //$$ 1000, + //$$ 3000 + //$$ )); + //$$ MatrixStack matrixStack = RenderSystem.getModelViewStack(); + //$$ matrixStack.loadIdentity(); + //$$ matrixStack.translate(0, 0, -2000); + //$$ RenderSystem.applyModelViewMatrix(); + //$$ DiffuseLighting.enableGuiDepthLighting(); + //#else RenderSystem.matrixMode(GL11.GL_PROJECTION); RenderSystem.loadIdentity(); RenderSystem.ortho(0, window.getFramebufferWidth() / window.getScaleFactor(), window.getFramebufferHeight() / window.getScaleFactor(), 0, 1000, 3000); RenderSystem.matrixMode(GL11.GL_MODELVIEW); RenderSystem.loadIdentity(); RenderSystem.translatef(0, 0, -2000); + //#endif //#else //#if MC>=11400 //$$ window.method_4493( @@ -535,11 +560,11 @@ public class VideoRenderer implements RenderInfo { int mouseX = (int) mc.mouse.getX() * window.getScaledWidth() / displayWidth; int mouseY = (int) mc.mouse.getY() * window.getScaledHeight() / displayHeight; - if (mc.overlay != null) { + if (mc.getOverlay() != null) { Screen orgScreen = mc.currentScreen; try { mc.currentScreen = gui.toMinecraft(); - mc.overlay.render( + mc.getOverlay().render( //#if MC>=11600 new MatrixStack(), //#endif diff --git a/src/main/java/com/replaymod/replay/FullReplaySender.java b/src/main/java/com/replaymod/replay/FullReplaySender.java index 99b4c31a..03ef31a9 100644 --- a/src/main/java/com/replaymod/replay/FullReplaySender.java +++ b/src/main/java/com/replaymod/replay/FullReplaySender.java @@ -366,6 +366,8 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend // Entity#addedToChunk is not set and it is therefore not updated every tick. // To counteract this, we need to manually update it's position if it hasn't been added // to any chunk yet. + // The `updateNeeded` flag appears to have been removed in 1.17, so this should no longer be an issue. + //#if MC<11700 if (mc.world != null) { for (PlayerEntity playerEntity : mc.world.getPlayers()) { if (!playerEntity.updateNeeded && playerEntity instanceof OtherClientPlayerEntity) { @@ -373,6 +375,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend } } } + //#endif } } @@ -413,7 +416,9 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend || p instanceof ExperienceOrbSpawnS2CPacket || p instanceof EntitiesDestroyS2CPacket) { ClientWorld world = mc.world; - //#if MC>=11400 + //#if MC>=11700 + //$$ // From the looks of it, this has now been resolved (thanks to EntityChangeListener) + //#elseif MC>=11400 // Note: Not sure if it's still required but there's this really handy method anyway world.finishRemovingEntities(); //#else @@ -478,12 +483,16 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend int i = pb.readVarInt(); NetworkState state = loginPhase ? NetworkState.LOGIN : NetworkState.PLAY; + //#if MC>=11700 + //$$ Packet p = state.getPacketHandler(NetworkSide.CLIENTBOUND, i, pb); + //#else //#if MC>=10800 Packet p = state.getPacketHandler(NetworkSide.CLIENTBOUND, i); //#else //$$ Packet p = Packet.generatePacket(state.func_150755_b(), i); //#endif p.read(pb); + //#endif return p; } @@ -1154,6 +1163,9 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend // 1.14+: The update issue remains but only for non-players and the unloading list bug appears to have been // fixed (chunk unloading no longer removes the entities). // Get the chunk that will be unloaded + //#if MC>=11700 + //$$ // From the looks of it, this may be fixed now (thanks to EntityChangeListener), guess we'll see + //#else //#if MC>=11400 ClientWorld world = mc.world; ChunkManager chunkProvider = world.getChunkManager(); @@ -1250,6 +1262,7 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend //#endif } } + //#endif } return p; // During synchronous playback everything is sent normally } diff --git a/src/main/java/com/replaymod/replay/NoGuiScreenshot.java b/src/main/java/com/replaymod/replay/NoGuiScreenshot.java index 5345c2bc..0cd7ed44 100644 --- a/src/main/java/com/replaymod/replay/NoGuiScreenshot.java +++ b/src/main/java/com/replaymod/replay/NoGuiScreenshot.java @@ -8,6 +8,9 @@ import net.minecraft.client.MinecraftClient; import com.mojang.blaze3d.platform.GlStateManager; import net.minecraft.client.util.ScreenshotUtils; +import static com.replaymod.core.versions.MCVer.popMatrix; +import static com.replaymod.core.versions.MCVer.pushMatrix; + //#if MC>=11500 import net.minecraft.client.util.math.MatrixStack; //#endif @@ -58,7 +61,7 @@ public class NoGuiScreenshot { mc.options.hudHidden = true; // Render frame without GUI - GlStateManager.pushMatrix(); + pushMatrix(); GlStateManager.clear( 16640 //#if MC>=11400 @@ -84,10 +87,10 @@ public class NoGuiScreenshot { //#endif mc.getFramebuffer().endWrite(); - GlStateManager.popMatrix(); - GlStateManager.pushMatrix(); + popMatrix(); + pushMatrix(); mc.getFramebuffer().draw(frameWidth, frameHeight); - GlStateManager.popMatrix(); + popMatrix(); } catch (Throwable t) { future.setException(t); return; diff --git a/src/main/java/com/replaymod/replay/QuickReplaySender.java b/src/main/java/com/replaymod/replay/QuickReplaySender.java index 18b30a0c..857a38f7 100644 --- a/src/main/java/com/replaymod/replay/QuickReplaySender.java +++ b/src/main/java/com/replaymod/replay/QuickReplaySender.java @@ -99,6 +99,18 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe @Override protected Packet decode(com.github.steveice10.netty.buffer.ByteBuf byteBuf) throws IOException { int packetId = new ByteBufNetInput(byteBuf).readVarInt(); + int size = byteBuf.readableBytes(); + if (buf.length < size) { + buf = new byte[size]; + } + byteBuf.readBytes(buf, 0, size); + ByteBuf wrappedBuf = Unpooled.wrappedBuffer(buf); + wrappedBuf.writerIndex(size); + PacketByteBuf packetByteBuf = new PacketByteBuf(wrappedBuf); + + //#if MC>=11700 + //$$ return NetworkState.PLAY.getPacketHandler(NetworkSide.CLIENTBOUND, packetId, packetByteBuf); + //#else //#if MC>=11500 Packet mcPacket = NetworkState.PLAY.getPacketHandler(NetworkSide.CLIENTBOUND, packetId); //#else @@ -110,16 +122,10 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe //$$ } //#endif if (mcPacket != null) { - int size = byteBuf.readableBytes(); - if (buf.length < size) { - buf = new byte[size]; - } - byteBuf.readBytes(buf, 0, size); - ByteBuf wrappedBuf = Unpooled.wrappedBuffer(buf); - wrappedBuf.writerIndex(size); - mcPacket.read(new PacketByteBuf(wrappedBuf)); + mcPacket.read(packetByteBuf); } return mcPacket; + //#endif } @Override @@ -220,7 +226,12 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe //$$ GameMode.SPECTATOR //#endif )); - ctx.fireChannelRead(new PlayerPositionLookS2CPacket(0, 0, 0, 0, 0, Collections.emptySet(), 0)); + ctx.fireChannelRead(new PlayerPositionLookS2CPacket( + 0, 0, 0, 0, 0, Collections.emptySet(), 0 + //#if MC>=11700 + //$$ , true + //#endif + )); } @Override diff --git a/src/main/java/com/replaymod/replay/ReplayHandler.java b/src/main/java/com/replaymod/replay/ReplayHandler.java index 5863fffa..adac3806 100644 --- a/src/main/java/com/replaymod/replay/ReplayHandler.java +++ b/src/main/java/com/replaymod/replay/ReplayHandler.java @@ -4,6 +4,7 @@ import com.google.common.base.Preconditions; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import com.mojang.blaze3d.platform.GlStateManager; import com.replaymod.core.ReplayMod; import com.replaymod.core.mixin.MinecraftAccessor; import com.replaymod.core.mixin.TimerAccessor; @@ -40,6 +41,11 @@ import net.minecraft.network.ClientConnection; import java.io.IOException; import java.util.*; +//#if MC>=11700 +//$$ import net.minecraft.client.render.DiffuseLighting; +//$$ import net.minecraft.util.math.Matrix4f; +//#endif + //#if MC>=11600 import net.minecraft.client.util.math.MatrixStack; //#endif @@ -97,7 +103,6 @@ import javax.annotation.Nullable; import static com.replaymod.core.versions.MCVer.*; import static com.replaymod.replay.ReplayModReplay.LOGGER; -import static com.mojang.blaze3d.platform.GlStateManager.*; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; @@ -213,11 +218,13 @@ public class ReplayHandler { channel.close().awaitUninterruptibly(); if (mc.player instanceof CameraEntity) { + //#if MC<11700 //#if MC>=11400 mc.player.remove(); //#else //$$ mc.player.setDead(); //#endif + //#endif } if (mc.world != null) { @@ -604,22 +611,38 @@ public class ReplayHandler { // Perform the rendering using OpenGL pushMatrix(); - clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT + GlStateManager.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT //#if MC>=11400 , true //#endif ); - enableTexture(); + GlStateManager.enableTexture(); mc.getFramebuffer().beginWrite(true); Window window = mc.getWindow(); //#if MC>=11500 RenderSystem.clear(256, MinecraftClient.IS_SYSTEM_MAC); + //#if MC>=11700 + //$$ RenderSystem.setProjectionMatrix(Matrix4f.projectionMatrix( + //$$ 0, + //$$ (float) (window.getFramebufferWidth() / window.getScaleFactor()), + //$$ 0, + //$$ (float) (window.getFramebufferHeight() / window.getScaleFactor()), + //$$ 1000, + //$$ 3000 + //$$ )); + //$$ MatrixStack matrixStack = RenderSystem.getModelViewStack(); + //$$ matrixStack.loadIdentity(); + //$$ matrixStack.translate(0, 0, -2000); + //$$ RenderSystem.applyModelViewMatrix(); + //$$ DiffuseLighting.enableGuiDepthLighting(); + //#else RenderSystem.matrixMode(GL11.GL_PROJECTION); RenderSystem.loadIdentity(); RenderSystem.ortho(0, window.getFramebufferWidth() / window.getScaleFactor(), window.getFramebufferHeight() / window.getScaleFactor(), 0, 1000, 3000); RenderSystem.matrixMode(GL11.GL_MODELVIEW); RenderSystem.loadIdentity(); RenderSystem.translatef(0, 0, -2000); + //#endif //#else //#if MC>=11400 //$$ window.method_4493(true); diff --git a/src/main/java/com/replaymod/replay/camera/CameraEntity.java b/src/main/java/com/replaymod/replay/camera/CameraEntity.java index e5bd3b1f..973e4fbc 100644 --- a/src/main/java/com/replaymod/replay/camera/CameraEntity.java +++ b/src/main/java/com/replaymod/replay/camera/CameraEntity.java @@ -208,8 +208,10 @@ public class CameraEntity * @param roll Roll in degrees */ public void setCameraRotation(float yaw, float pitch, float roll) { - this.prevYaw = this.yaw = yaw; - this.prevPitch = this.pitch = pitch; + this.prevYaw = yaw; + this.prevPitch = pitch; + this.yaw = yaw; + this.pitch = pitch; this.roll = roll; } @@ -575,8 +577,13 @@ public class CameraEntity //#endif @Override + //#if MC>=11700 + //$$ public void remove(RemovalReason reason) { + //$$ super.remove(reason); + //#else public void remove() { super.remove(); + //#endif if (eventHandler != null) { eventHandler.unregister(); eventHandler = null; diff --git a/src/main/java/com/replaymod/replay/handler/GuiHandler.java b/src/main/java/com/replaymod/replay/handler/GuiHandler.java index 8f8b4a85..2bc2f79d 100644 --- a/src/main/java/com/replaymod/replay/handler/GuiHandler.java +++ b/src/main/java/com/replaymod/replay/handler/GuiHandler.java @@ -34,8 +34,8 @@ import net.minecraft.client.gui.widget.ButtonWidget; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.Comparator; -import java.util.List; import java.util.Optional; import java.util.function.Consumer; import java.util.stream.Stream; @@ -54,7 +54,7 @@ public class GuiHandler extends EventRegistrations { } { on(InitScreenCallback.EVENT, this::injectIntoIngameMenu); } - private void injectIntoIngameMenu(Screen guiScreen, List buttonList) { + private void injectIntoIngameMenu(Screen guiScreen, Collection buttonList) { if (!(guiScreen instanceof GameMenuScreen)) { return; } @@ -182,9 +182,9 @@ public class GuiHandler extends EventRegistrations { */ private void moveAllButtonsInRect( //#if MC>=11400 - List buttons, + Collection buttons, //#else - //$$ List buttons, + //$$ Collection buttons, //#endif int xStart, int xEnd, @@ -198,8 +198,8 @@ public class GuiHandler extends EventRegistrations { .forEach(button -> button.y += moveBy); } - { on(InitScreenCallback.EVENT, this::ensureReplayStopped); } - private void ensureReplayStopped(Screen guiScreen, List buttonList) { + { on(InitScreenCallback.EVENT, (screen, buttons) -> ensureReplayStopped(screen)); } + private void ensureReplayStopped(Screen guiScreen) { if (!(guiScreen instanceof TitleScreen || guiScreen instanceof MultiplayerScreen)) { return; } @@ -220,7 +220,7 @@ public class GuiHandler extends EventRegistrations { } { on(InitScreenCallback.EVENT, this::injectIntoMainMenu); } - private void injectIntoMainMenu(Screen guiScreen, List buttonList) { + private void injectIntoMainMenu(Screen guiScreen, Collection buttonList) { if (!(guiScreen instanceof TitleScreen)) { return; } @@ -291,7 +291,7 @@ public class GuiHandler extends EventRegistrations { addButton(guiScreen, button); } - private Point determineButtonPos(MainMenuButtonPosition buttonPosition, Screen guiScreen, List buttonList) { + private Point determineButtonPos(MainMenuButtonPosition buttonPosition, Screen guiScreen, Collection buttonList) { Point topRight = new Point(guiScreen.width - 20 - 5, 5); if (buttonPosition == MainMenuButtonPosition.TOP_LEFT) { diff --git a/src/main/java/com/replaymod/replay/mixin/MixinRenderArrow.java b/src/main/java/com/replaymod/replay/mixin/MixinRenderArrow.java index bc20c96e..7b067f21 100644 --- a/src/main/java/com/replaymod/replay/mixin/MixinRenderArrow.java +++ b/src/main/java/com/replaymod/replay/mixin/MixinRenderArrow.java @@ -4,10 +4,15 @@ package com.replaymod.replay.mixin; import com.replaymod.replay.ReplayModReplay; import net.minecraft.client.render.entity.EntityRenderer; import net.minecraft.client.render.entity.ArrowEntityRenderer; -import net.minecraft.client.render.entity.EntityRenderDispatcher; import net.minecraft.entity.Entity; import org.spongepowered.asm.mixin.Mixin; +//#if MC>=11700 +//$$ import net.minecraft.client.render.entity.EntityRendererFactory.Context; +//#else +import net.minecraft.client.render.entity.EntityRenderDispatcher; +//#endif + //#if MC>=11500 import net.minecraft.client.render.Frustum; //#else @@ -16,9 +21,15 @@ import net.minecraft.client.render.Frustum; @Mixin(ArrowEntityRenderer.class) public abstract class MixinRenderArrow extends EntityRenderer { + //#if MC>=11700 + //$$ protected MixinRenderArrow(Context context) { + //$$ super(context); + //$$ } + //#else protected MixinRenderArrow(EntityRenderDispatcher renderManager) { super(renderManager); } + //#endif @SuppressWarnings("unchecked") @Override diff --git a/src/main/java/com/replaymod/replay/mixin/MixinTileEntityEndPortalRenderer.java b/src/main/java/com/replaymod/replay/mixin/MixinTileEntityEndPortalRenderer.java index 9139c516..20d75a52 100644 --- a/src/main/java/com/replaymod/replay/mixin/MixinTileEntityEndPortalRenderer.java +++ b/src/main/java/com/replaymod/replay/mixin/MixinTileEntityEndPortalRenderer.java @@ -40,7 +40,7 @@ public class MixinTileEntityEndPortalRenderer { //#endif //#endif //#endif - private long replayModReplay_getEnchantmentTime() { + private long replayModReplay_getPortalTime() { ReplayHandler replayHandler = ReplayModReplay.instance.getReplayHandler(); if (replayHandler != null) { return replayHandler.getReplaySender().currentTimeStamp(); diff --git a/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java b/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java index 784e5a10..3576ffa0 100644 --- a/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java +++ b/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java @@ -18,6 +18,7 @@ import com.replaymod.simplepathing.SPTimeline.SPPath; import de.johni0702.minecraft.gui.GuiRenderer; import de.johni0702.minecraft.gui.element.advanced.AbstractGuiTimeline; import de.johni0702.minecraft.gui.function.Draggable; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector2f; import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.VertexFormats; @@ -30,6 +31,16 @@ import org.lwjgl.opengl.GL11; import java.util.Comparator; import java.util.Optional; +import static com.replaymod.core.versions.MCVer.emitLine; +import static de.johni0702.minecraft.gui.versions.MCVer.popScissorState; +import static de.johni0702.minecraft.gui.versions.MCVer.pushScissorState; +import static de.johni0702.minecraft.gui.versions.MCVer.setScissorState; + +//#if MC>=11700 +//$$ import com.mojang.blaze3d.systems.RenderSystem; +//$$ import net.minecraft.client.render.GameRenderer; +//#endif + public class GuiKeyframeTimeline extends AbstractGuiTimeline implements Draggable { protected static final int KEYFRAME_SIZE = 5; protected static final int KEYFRAME_TEXTURE_X = 74; @@ -146,59 +157,33 @@ public class GuiKeyframeTimeline extends AbstractGuiTimeline> 24 & 0xff, - color >> 16 & 0xff, - color >> 8 & 0xff, - color & 0xff - ).next(); + Vector2f p1 = new Vector2f(replayTimelineLeft + positionXReplayTimeline, replayTimelineTop + BORDER_TOP); // Draw vertically over the replay timeline, including its bottom border - buffer.vertex( - replayTimelineLeft + positionXReplayTimeline, - replayTimelineBottom, - 0 - ).color( - color >> 24 & 0xff, - color >> 16 & 0xff, - color >> 8 & 0xff, - color & 0xff - ).next(); + Vector2f p2 = new Vector2f(replayTimelineLeft + positionXReplayTimeline, replayTimelineBottom); // Now for the important part: connecting to the keyframe timeline - buffer.vertex( - keyframeTimelineLeft + positionXKeyframeTimeline, - keyframeTimelineTop, - 0 - ).color( - color >> 24 & 0xff, - color >> 16 & 0xff, - color >> 8 & 0xff, - color & 0xff - ).next(); + Vector2f p3 = new Vector2f(keyframeTimelineLeft + positionXKeyframeTimeline, keyframeTimelineTop); // And finally another vertical bit (the timeline is already crammed enough, so only the border) - buffer.vertex( - keyframeTimelineLeft + positionXKeyframeTimeline, - keyframeTimelineTop + BORDER_TOP, - 0 - ).color( - color >> 24 & 0xff, - color >> 16 & 0xff, - color >> 8 & 0xff, - color & 0xff - ).next(); + Vector2f p4 = new Vector2f(keyframeTimelineLeft + positionXKeyframeTimeline, keyframeTimelineTop + BORDER_TOP); + emitLine(buffer, p1, p2, color); + emitLine(buffer, p2, p3, color); + emitLine(buffer, p3, p4, color); + + //#if MC>=11700 + //$$ RenderSystem.setShader(GameRenderer::getRenderTypeLinesShader); + //#else GL11.glEnable(GL11.GL_LINE_SMOOTH); GL11.glDisable(GL11.GL_TEXTURE_2D); - GL11.glPushAttrib(GL11.GL_SCISSOR_BIT); - GL11.glDisable(GL11.GL_SCISSOR_TEST); - GL11.glLineWidth(1); + //#endif + pushScissorState(); + setScissorState(false); + GL11.glLineWidth(2); tessellator.draw(); - GL11.glPopAttrib(); + popScissorState(); + //#if MC<11700 GL11.glEnable(GL11.GL_TEXTURE_2D); GL11.glDisable(GL11.GL_LINE_SMOOTH); + //#endif } } }); diff --git a/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java b/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java index 4aa42bb0..d682b92a 100644 --- a/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java +++ b/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java @@ -18,6 +18,7 @@ import com.replaymod.simplepathing.ReplayModSimplePathing; import com.replaymod.simplepathing.SPTimeline; import com.replaymod.simplepathing.gui.GuiPathing; import de.johni0702.minecraft.gui.utils.EventRegistrations; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.Tessellator; @@ -29,6 +30,10 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; import org.lwjgl.opengl.GL11; +//#if MC>=11700 +//$$ import net.minecraft.client.render.GameRenderer; +//#endif + //#if MC>=11500 import com.mojang.blaze3d.systems.RenderSystem; //#endif @@ -37,6 +42,10 @@ import java.util.Comparator; import java.util.Optional; import static com.replaymod.core.ReplayMod.TEXTURE; +import static com.replaymod.core.versions.MCVer.bindTexture; +import static com.replaymod.core.versions.MCVer.emitLine; +import static com.replaymod.core.versions.MCVer.popMatrix; +import static com.replaymod.core.versions.MCVer.pushMatrix; public class PathPreviewRenderer extends EventRegistrations { private static final Identifier CAMERA_HEAD = new Identifier("replaymod", "camera_head.png"); @@ -76,25 +85,32 @@ public class PathPreviewRenderer extends EventRegistrations { int renderDistance = mc.options.viewDistance * 16; int renderDistanceSquared = renderDistance * renderDistance; - Triple viewPos = Triple.of( - view.getX(), - view.getY() + Vector3f viewPos = new Vector3f( + (float) view.getX(), + (float) view.getY() //#if MC>=10800 && MC<11500 //$$ // Eye height is subtracted to make path appear higher (at eye height) than it actually is (at foot height) //$$ - view.getStandingEyeHeight(), //#else , //#endif - view.getZ() + (float) view.getZ() ); + //#if MC<11700 GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); - GL11.glPushMatrix(); + //#endif + pushMatrix(); try { + //#if MC<11700 GL11.glDisable(GL11.GL_LIGHTING); GL11.glDisable(GL11.GL_TEXTURE_2D); + //#endif - //#if MC>=11500 + //#if MC>=11700 + //$$ RenderSystem.getModelViewStack().method_34425(matrixStack.peek().getModel()); + //$$ RenderSystem.applyModelViewMatrix(); + //#elseif MC>=11500 RenderSystem.multMatrix(matrixStack.peek().getModel()); //#endif @@ -110,7 +126,7 @@ public class PathPreviewRenderer extends EventRegistrations { } // Spectator segments have 20 lines per second (at least 10) whereas normal segments have a fixed 100 long steps = spectator ? Math.max(diff / 50, 10) : 100; - Triple prevPos = null; + Vector3f prevPos = null; for (int i = 0; i <= steps; i++) { long time = start.getTime() + diff * i / steps; if (spectator) { @@ -119,24 +135,24 @@ public class PathPreviewRenderer extends EventRegistrations { if (entityId.isPresent() && replayTime.isPresent()) { Location loc = entityTracker.getEntityPositionAtTimestamp(entityId.get(), replayTime.get()); if (loc != null) { - Triple pos = Triple.of(loc.getX(), loc.getY(), loc.getZ()); + Vector3f pos = loc2Vec(loc); if (prevPos != null) { - drawConnection(viewPos, prevPos, pos, 0x0000ff, renderDistanceSquared); + drawConnection(viewPos, prevPos, pos, 0x0000ffff, renderDistanceSquared); } prevPos = pos; continue; } } } else { - Optional> optPos = path.getValue(CameraProperties.POSITION, time); + Optional optPos = path.getValue(CameraProperties.POSITION, time).map(this::tripleD2Vec); if (optPos.isPresent()) { - Triple pos = optPos.get(); + Vector3f pos = optPos.get(); if (prevPos != null) { double distance = Math.sqrt(distanceSquared(prevPos, pos)); double speed = Math.min(distance / (diff / steps), FASTEST_PATH_SPEED); double speedFraction = speed / FASTEST_PATH_SPEED; int color = interpolateColor(SLOW_PATH_COLOR, FAST_PATH_COLOR, speedFraction); - drawConnection(viewPos, prevPos, pos, color, renderDistanceSquared); + drawConnection(viewPos, prevPos, pos, (color << 8) | 0xff, renderDistanceSquared); } prevPos = pos; continue; @@ -147,12 +163,14 @@ public class PathPreviewRenderer extends EventRegistrations { } GL11.glEnable(GL11.GL_BLEND); - GL11.glEnable(GL11.GL_TEXTURE_2D); GL11.glBlendFunc(GL11.GL_DST_COLOR, GL11.GL_SRC_COLOR); GL11.glDisable(GL11.GL_DEPTH_TEST); + //#if MC<11700 + GL11.glEnable(GL11.GL_TEXTURE_2D); + //#endif path.getKeyframes().stream() - .map(k -> Pair.of(k, k.getValue(CameraProperties.POSITION))) + .map(k -> Pair.of(k, k.getValue(CameraProperties.POSITION).map(this::tripleD2Vec))) .filter(p -> p.getRight().isPresent()) .map(p -> Pair.of(p.getLeft(), p.getRight().get())) .filter(p -> distanceSquared(p.getRight(), viewPos) < renderDistanceSquared) @@ -171,26 +189,40 @@ public class PathPreviewRenderer extends EventRegistrations { if (replayTime.isPresent()) { Location loc = entityTracker.getEntityPositionAtTimestamp(entityId.get(), replayTime.get()); if (loc != null) { - drawCamera(viewPos, - Triple.of(loc.getX(), loc.getY(), loc.getZ()), - Triple.of(loc.getYaw(), loc.getPitch(), 0f)); + drawCamera(viewPos, loc2Vec(loc), new Vector3f(loc.getYaw(), loc.getPitch(), 0f)); } } } } else { // Normal camera path - Optional> cameraPos = path.getValue(CameraProperties.POSITION, time); - Optional> cameraRot = path.getValue(CameraProperties.ROTATION, time); + Optional cameraPos = path.getValue(CameraProperties.POSITION, time).map(this::tripleD2Vec); + Optional cameraRot = path.getValue(CameraProperties.ROTATION, time).map(this::tripleF2Vec); if (cameraPos.isPresent() && cameraRot.isPresent()) { drawCamera(viewPos, cameraPos.get(), cameraRot.get()); } } } finally { - GL11.glPopMatrix(); - GlStateManager.popAttributes(); + popMatrix(); + //#if MC>=11700 + GL11.glDisable(GL11.GL_BLEND); + //#else + GL11.glPopAttrib(); + //#endif } } + private Vector3f loc2Vec(Location loc) { + return new Vector3f((float) loc.getX(), (float) loc.getY(), (float) loc.getZ()); + } + + private Vector3f tripleD2Vec(Triple loc) { + return new Vector3f(loc.getLeft().floatValue(), loc.getMiddle().floatValue(), loc.getRight().floatValue()); + } + + private Vector3f tripleF2Vec(Triple loc) { + return new Vector3f(loc.getLeft(), loc.getMiddle(), loc.getRight()); + } + private static int interpolateColor(int c1, int c2, double weight) { return (interpolateColorComponent((c1 >> 16) & 0xff, (c2 >> 16) & 0xff, weight) << 16) | (interpolateColorComponent((c1 >> 8) & 0xff, (c2 >> 8) & 0xff, weight) << 8) @@ -201,17 +233,11 @@ public class PathPreviewRenderer extends EventRegistrations { return (int) (c1 + (1 - Math.pow(Math.E, -4 * weight)) * (c2 - c1)) & 0xff; } - private static double distanceSquared(Triple p1, Triple p2) { - double dx = p1.getLeft() - p2.getLeft(); - double dy = p1.getMiddle() - p2.getMiddle(); - double dz = p1.getRight() - p2.getRight(); - return dx * dx + dy * dy + dz * dz; + private static double distanceSquared(Vector3f p1, Vector3f p2) { + return Vector3f.sub(p1, p2, null).lengthSquared(); } - private void drawConnection(Triple view, - Triple pos1, - Triple pos2, - int color, int renderDistanceSquared) { + private void drawConnection(Vector3f view, Vector3f pos1, Vector3f pos2, int color, int renderDistanceSquared) { if (distanceSquared(view, pos1) > renderDistanceSquared) return; if (distanceSquared(view, pos2) > renderDistanceSquared) return; @@ -219,36 +245,22 @@ public class PathPreviewRenderer extends EventRegistrations { BufferBuilder buffer = tessellator.getBuffer(); buffer.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR); - buffer.vertex( - pos1.getLeft() - view.getLeft(), - pos1.getMiddle() - view.getMiddle(), - pos1.getRight() - view.getRight() - ).color( - color >> 16 & 0xff, - color >> 8 & 0xff, - color & 0xff, - 255 - ).next(); - buffer.vertex( - pos2.getLeft() - view.getLeft(), - pos2.getMiddle() - view.getMiddle(), - pos2.getRight() - view.getRight() - ).color( - color >> 16 & 0xff, - color >> 8 & 0xff, - color & 0xff, - 255 - ).next(); + emitLine(buffer, Vector3f.sub(pos1, view, null), Vector3f.sub(pos2, view, null), color); + //#if MC>=11700 + //$$ RenderSystem.setShader(GameRenderer::getRenderTypeLinesShader); + //$$ RenderSystem.disableCull(); + //#endif GL11.glLineWidth(3); tessellator.draw(); + //#if MC>=11700 + //$$ RenderSystem.enableCull(); + //#endif } - private void drawPoint(Triple view, - Triple pos, - Keyframe keyframe) { + private void drawPoint(Vector3f view, Vector3f pos, Keyframe keyframe) { - mc.getTextureManager().bindTexture(TEXTURE); + bindTexture(TEXTURE); float posX = 80f / ReplayMod.TEXTURE_SIZE; float posY = 0f; @@ -276,53 +288,55 @@ public class PathPreviewRenderer extends EventRegistrations { buffer.vertex(maxX, maxY, 0).texture(posX, posY).next(); buffer.vertex(maxX, minY, 0).texture(posX, posY + size).next(); - GL11.glPushMatrix(); + pushMatrix(); - GL11.glTranslated( - pos.getLeft() - view.getLeft(), - pos.getMiddle() - view.getMiddle(), - pos.getRight() - view.getRight() - ); - GL11.glNormal3f(0, 1, 0); + Vector3f t = Vector3f.sub(pos, view, null); + GL11.glTranslatef(t.x, t.y, t.z); GL11.glRotatef(-mc.getEntityRenderDispatcher().camera.getYaw(), 0, 1, 0); GL11.glRotatef(mc.getEntityRenderDispatcher().camera.getPitch(), 1, 0, 0); + //#if MC>=11700 + //$$ RenderSystem.applyModelViewMatrix(); + //$$ RenderSystem.setShader(GameRenderer::getPositionTexShader); + //#endif tessellator.draw(); - GL11.glPopMatrix(); + popMatrix(); } - private void drawCamera(Triple view, - Triple pos, - Triple rot) { + private void drawCamera(Vector3f view, Vector3f pos, Vector3f rot) { - mc.getTextureManager().bindTexture(CAMERA_HEAD); + bindTexture(CAMERA_HEAD); - GL11.glPushMatrix(); + pushMatrix(); - GL11.glTranslated( - pos.getLeft() - view.getLeft(), - pos.getMiddle() - view.getMiddle(), - pos.getRight() - view.getRight() - ); - GL11.glRotated(-rot.getLeft(), 0, 1, 0); // Yaw - GL11.glRotated(rot.getMiddle(), 1, 0, 0); // Pitch - GL11.glRotated(rot.getRight(), 0, 0, 1); // Roll - GL11.glNormal3f(0, 1, 0); + Vector3f t = Vector3f.sub(pos, view, null); + GL11.glTranslatef(t.x, t.y, t.z); + GL11.glRotatef(-rot.x, 0, 1, 0); // Yaw + GL11.glRotatef(rot.y, 1, 0, 0); // Pitch + GL11.glRotatef(rot.z, 0, 0, 1); // Roll //draw the position line - GL11.glDisable(GL11.GL_TEXTURE_2D); Tessellator tessellator = Tessellator.getInstance(); BufferBuilder buffer = tessellator.getBuffer(); buffer.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR); - buffer.vertex(0, 0, 0).color(0, 255, 0, 170).next(); - buffer.vertex(0, 0, 2).color(0, 255, 0, 170).next(); + emitLine(buffer, new Vector3f(0, 0, 0), new Vector3f(0, 0, 2), 0x00ff00aa); + + //#if MC>=11700 + //$$ RenderSystem.applyModelViewMatrix(); + //$$ RenderSystem.setShader(GameRenderer::getRenderTypeLinesShader); + //#else + GL11.glDisable(GL11.GL_TEXTURE_2D); + //#endif tessellator.draw(); - // draw camera cube + //#if MC<11700 GL11.glEnable(GL11.GL_TEXTURE_2D); + //#endif + + // draw camera cube float cubeSize = 0.5f; @@ -366,21 +380,24 @@ public class PathPreviewRenderer extends EventRegistrations { buffer.vertex(r + cubeSize, r + cubeSize, r + cubeSize).texture(2*8/64f, 8/64f).color(255, 255, 255, 200).next(); buffer.vertex(r + cubeSize, r + cubeSize, r).texture(2 * 8 / 64f, 0).color(255, 255, 255, 200).next(); + //#if MC>=11700 + //$$ RenderSystem.applyModelViewMatrix(); + //$$ RenderSystem.setShader(GameRenderer::getPositionTexColorShader); + //#endif tessellator.draw(); - GL11.glPopMatrix(); + popMatrix(); } - private class KeyframeComparator implements Comparator>> { - private final Triple viewPos; + private class KeyframeComparator implements Comparator> { + private final Vector3f viewPos; - public KeyframeComparator(Triple viewPos) { + public KeyframeComparator(Vector3f viewPos) { this.viewPos = viewPos; } @Override - public int compare(Pair> o1, - Pair> o2) { + public int compare(Pair o1, Pair o2) { return -Double.compare(distanceSquared(o1.getRight(), viewPos), distanceSquared(o2.getRight(), viewPos)); } } diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index a7a4bdb4..3118ccd3 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -38,7 +38,7 @@ //$$ "MixinEffectRenderer", //#endif "MixinEntityRenderer", - //#if MC>=10800 + //#if MC>=10800 && MC<11700 "MixinGlStateManager", //#endif //#if MC>=10800 diff --git a/versions/1.17/src/main/java/com/replaymod/render/mixin/MixinGlStateManager.java b/versions/1.17/src/main/java/com/replaymod/render/mixin/MixinGlStateManager.java new file mode 100644 index 00000000..135f5079 --- /dev/null +++ b/versions/1.17/src/main/java/com/replaymod/render/mixin/MixinGlStateManager.java @@ -0,0 +1 @@ +// 1.16.5 and below diff --git a/versions/1.17/src/main/java/com/replaymod/replay/mixin/MixinTileEntityEndPortalRenderer.java b/versions/1.17/src/main/java/com/replaymod/replay/mixin/MixinTileEntityEndPortalRenderer.java new file mode 100644 index 00000000..ded0c4de --- /dev/null +++ b/versions/1.17/src/main/java/com/replaymod/replay/mixin/MixinTileEntityEndPortalRenderer.java @@ -0,0 +1,9 @@ +package com.replaymod.replay.mixin; + +import com.mojang.blaze3d.systems.RenderSystem; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(RenderSystem.class) +public class MixinTileEntityEndPortalRenderer { + // All shaders now use the game time +} diff --git a/versions/mapping-fabric-1.17-1.16.4.txt b/versions/mapping-fabric-1.17-1.16.4.txt new file mode 100644 index 00000000..300a639a --- /dev/null +++ b/versions/mapping-fabric-1.17-1.16.4.txt @@ -0,0 +1,4 @@ +com.mojang.blaze3d.systems.RenderSystem com.mojang.blaze3d.platform.GlStateManager +net.minecraft.network.packet.s2c.play.PlayerRespawnS2CPacket getDimensionType() method_29445() +net.minecraft.entity.Entity getId() getEntityId() +net.minecraft.client.network.ClientPlayerEntity init() net.minecraft.entity.player.PlayerEntity afterSpawn() From 08165252d51e56928afd1c18e3856d2773a2402b Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 5 Jun 2021 22:39:19 +0200 Subject: [PATCH 073/102] Switch to new Quick Mode backend --- build.gradle | 2 +- .../replaymod/replay/QuickReplaySender.java | 49 +++++++++---------- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/build.gradle b/build.gradle index 96bacf0d..369888bd 100644 --- a/build.gradle +++ b/build.gradle @@ -330,7 +330,7 @@ dependencies { shadow 'com.github.ReplayMod.JavaBlend:2.79.0:a0696f8' - shadow "com.github.ReplayMod:ReplayStudio:a1f82a7", shadeExclusions + shadow "com.github.ReplayMod:ReplayStudio:0664fb7", shadeExclusions implementation(jGui){ transitive = false // FG 1.2 puts all MC deps into the compile configuration and we don't want to shade those diff --git a/src/main/java/com/replaymod/replay/QuickReplaySender.java b/src/main/java/com/replaymod/replay/QuickReplaySender.java index 857a38f7..7c7c359d 100644 --- a/src/main/java/com/replaymod/replay/QuickReplaySender.java +++ b/src/main/java/com/replaymod/replay/QuickReplaySender.java @@ -1,8 +1,6 @@ //#if MC>=10904 package com.replaymod.replay; -import com.github.steveice10.packetlib.io.NetInput; -import com.github.steveice10.packetlib.tcp.io.ByteBufNetInput; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -10,7 +8,7 @@ import com.google.common.util.concurrent.SettableFuture; import com.replaymod.core.mixin.MinecraftAccessor; import com.replaymod.core.mixin.TimerAccessor; import com.replaymod.replaystudio.replay.ReplayFile; -import com.replaymod.replaystudio.util.RandomAccessReplay; +import com.replaymod.replaystudio.rar.RandomAccessReplay; import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.versions.callbacks.PreTickCallback; import io.netty.buffer.ByteBuf; @@ -72,7 +70,7 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe private final MinecraftClient mc = getMinecraft(); private final ReplayModReplay mod; - private final RandomAccessReplay> replay; + private final RandomAccessReplay replay; private final EventHandler eventHandler = new EventHandler(); private ChannelHandlerContext ctx; @@ -88,49 +86,48 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe private ListenableFuture initPromise; - private com.github.steveice10.netty.buffer.ByteBuf buf; - private NetInput bufInput; - public QuickReplaySender(ReplayModReplay mod, ReplayFile replayFile) { this.mod = mod; - this.replay = new RandomAccessReplay>(replayFile, getPacketTypeRegistry(false)) { + this.replay = new RandomAccessReplay(replayFile, getPacketTypeRegistry(false)) { private byte[] buf = new byte[0]; @Override - protected Packet decode(com.github.steveice10.netty.buffer.ByteBuf byteBuf) throws IOException { - int packetId = new ByteBufNetInput(byteBuf).readVarInt(); + protected void dispatch(com.replaymod.replaystudio.protocol.Packet packet) { + com.github.steveice10.netty.buffer.ByteBuf byteBuf = packet.getBuf(); int size = byteBuf.readableBytes(); if (buf.length < size) { buf = new byte[size]; } - byteBuf.readBytes(buf, 0, size); + byteBuf.getBytes(byteBuf.readerIndex(), buf, 0, size); ByteBuf wrappedBuf = Unpooled.wrappedBuffer(buf); wrappedBuf.writerIndex(size); PacketByteBuf packetByteBuf = new PacketByteBuf(wrappedBuf); + Packet mcPacket; //#if MC>=11700 - //$$ return NetworkState.PLAY.getPacketHandler(NetworkSide.CLIENTBOUND, packetId, packetByteBuf); + //$$ mcPacket = NetworkState.PLAY.getPacketHandler(NetworkSide.CLIENTBOUND, packet.getId(), packetByteBuf); + //#elseif MC>=11500 + mcPacket = NetworkState.PLAY.getPacketHandler(NetworkSide.CLIENTBOUND, packet.getId()); //#else - //#if MC>=11500 - Packet mcPacket = NetworkState.PLAY.getPacketHandler(NetworkSide.CLIENTBOUND, packetId); - //#else - //$$ Packet mcPacket; //$$ try { - //$$ mcPacket = NetworkState.PLAY.getPacketHandler(NetworkSide.CLIENTBOUND, packetId); + //$$ mcPacket = NetworkState.PLAY.getPacketHandler(NetworkSide.CLIENTBOUND, packet.getId()); //$$ } catch (IllegalAccessException | InstantiationException e) { - //$$ throw new IOException(e); + //$$ e.printStackTrace(); + //$$ return; //$$ } //#endif if (mcPacket != null) { - mcPacket.read(packetByteBuf); - } - return mcPacket; - //#endif - } + //#if MC<11700 + try { + mcPacket.read(packetByteBuf); + } catch (IOException e) { + e.printStackTrace(); + return; + } + //#endif - @Override - protected void dispatch(Packet packet) { - ctx.fireChannelRead(packet); + ctx.fireChannelRead(mcPacket); + } } }; } From 766d3346ee7629ea7e9aabbdfeb8c91b27c17bfc Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 27 Jun 2021 14:43:19 +0200 Subject: [PATCH 074/102] Pin FG5 version because its maintainers cannot be trusted Versions after 5.0.5 emit tsrg2 instead of tsrg, breaking anything which reads those files (e.g. Mixin and the preprocessor), later versions even bump the required Gradle version. --- build.gradle | 2 +- jGui | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 369888bd..75013687 100644 --- a/build.gradle +++ b/build.gradle @@ -36,7 +36,7 @@ buildscript { if (fabric) { classpath 'fabric-loom:fabric-loom.gradle.plugin:0.8-SNAPSHOT' } else if (mcVersion >= 11400) { - classpath('net.minecraftforge.gradle:ForgeGradle:5.+'){ + classpath('net.minecraftforge.gradle:ForgeGradle:5.0.5') { // the FG people still haven't learned to not do breaking changes exclude group: 'trove', module: 'trove' // preprocessor/idea requires more recent one } } else if (mcVersion >= 10800) { diff --git a/jGui b/jGui index cbf01d5c..09955508 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit cbf01d5c8d195784684f6bec37788829ab2be2ab +Subproject commit 09955508ca0e92b0658bfa4569bb46af7de16c43 From 8d3d705fed2f111b5de217bcd4c2ae74ca557e4c Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 28 Jun 2021 14:35:57 +0200 Subject: [PATCH 075/102] Switch to commons-lang Pair instead of the ViaVersion one Cause that one will be removed in a future version, and the lang one is just fine. --- src/main/java/com/replaymod/editor/gui/MarkerProcessor.java | 6 +++--- .../java/com/replaymod/recording/gui/GuiSavingReplay.java | 2 +- .../java/com/replaymod/recording/packet/PacketListener.java | 4 ++-- src/main/java/com/replaymod/render/gui/GuiRenderQueue.java | 2 +- .../com/replaymod/replay/gui/screen/GuiReplayViewer.java | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java b/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java index 80e6494d..e3c40d5a 100644 --- a/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java +++ b/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java @@ -12,9 +12,9 @@ import com.replaymod.replaystudio.protocol.PacketTypeRegistry; import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ReplayMetaData; import com.replaymod.replaystudio.stream.IteratorStream; -import com.replaymod.replaystudio.us.myles.ViaVersion.api.Pair; import com.replaymod.replaystudio.util.Utils; import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.tuple.Pair; import java.io.IOException; import java.io.InputStream; @@ -115,7 +115,7 @@ public class MarkerProcessor { try (ReplayFile inputReplayFile = mod.openReplay(path)) { metaData = inputReplayFile.getMetaData(); } - return Collections.singletonList(new Pair<>(path, metaData)); + return Collections.singletonList(Pair.of(path, metaData)); } String replayName = FilenameUtils.getBaseName(path.getFileName().toString()); @@ -249,7 +249,7 @@ public class MarkerProcessor { outputReplayFile.save(); - outputPaths.add(new Pair(outputPath, metaData)); + outputPaths.add(Pair.of(outputPath, metaData)); } } diff --git a/src/main/java/com/replaymod/recording/gui/GuiSavingReplay.java b/src/main/java/com/replaymod/recording/gui/GuiSavingReplay.java index 7f1a1238..5ca75e7e 100644 --- a/src/main/java/com/replaymod/recording/gui/GuiSavingReplay.java +++ b/src/main/java/com/replaymod/recording/gui/GuiSavingReplay.java @@ -5,7 +5,6 @@ import com.replaymod.core.utils.Utils; import com.replaymod.recording.Setting; import com.replaymod.replay.gui.screen.GuiReplayViewer; import com.replaymod.replaystudio.replay.ReplayMetaData; -import com.replaymod.replaystudio.us.myles.ViaVersion.api.Pair; import de.johni0702.minecraft.gui.container.AbstractGuiScreen; import de.johni0702.minecraft.gui.container.GuiContainer; import de.johni0702.minecraft.gui.container.GuiPanel; @@ -25,6 +24,7 @@ import de.johni0702.minecraft.gui.utils.lwjgl.Dimension; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; import net.minecraft.client.MinecraftClient; import net.minecraft.util.crash.CrashReport; +import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/com/replaymod/recording/packet/PacketListener.java b/src/main/java/com/replaymod/recording/packet/PacketListener.java index 78dd21ec..2fafe7dc 100644 --- a/src/main/java/com/replaymod/recording/packet/PacketListener.java +++ b/src/main/java/com/replaymod/recording/packet/PacketListener.java @@ -20,7 +20,6 @@ import com.replaymod.replaystudio.data.Marker; import com.replaymod.replaystudio.io.ReplayOutputStream; import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ReplayMetaData; -import com.replaymod.replaystudio.us.myles.ViaVersion.api.Pair; import de.johni0702.minecraft.gui.container.VanillaGuiScreen; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; @@ -40,6 +39,7 @@ import net.minecraft.network.PacketByteBuf; import net.minecraft.text.LiteralText; import net.minecraft.util.crash.CrashReport; import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -295,7 +295,7 @@ public class PacketListener extends ChannelInboundHandlerAdapter { if (core.getSettingsRegistry().get(Setting.AUTO_POST_PROCESS) && !ReplayMod.isMinimalMode()) { outputPaths = MarkerProcessor.apply(outputPath, guiSavingReplay.getProgressBar()::setProgress); } else { - outputPaths = Collections.singletonList(new Pair<>(outputPath, metaData)); + outputPaths = Collections.singletonList(Pair.of(outputPath, metaData)); } } catch (Exception e) { logger.error("Saving replay file:", e); diff --git a/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java b/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java index 7cd0a6cd..0ab59405 100644 --- a/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java +++ b/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java @@ -14,7 +14,6 @@ import com.replaymod.replay.ReplayModReplay; import com.replaymod.replay.ReplaySender; import com.replaymod.replaystudio.pathing.path.Timeline; import com.replaymod.replaystudio.replay.ReplayFile; -import com.replaymod.replaystudio.us.myles.ViaVersion.api.Pair; import de.johni0702.minecraft.gui.GuiRenderer; import de.johni0702.minecraft.gui.RenderInfo; import de.johni0702.minecraft.gui.container.AbstractGuiClickableContainer; @@ -39,6 +38,7 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.NoticeScreen; import net.minecraft.util.crash.CrashReport; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.tuple.Pair; import java.io.File; import java.io.IOException; diff --git a/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java b/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java index 7e4ea045..7fe0e49f 100644 --- a/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java +++ b/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java @@ -4,7 +4,6 @@ import com.google.common.util.concurrent.SettableFuture; import com.replaymod.render.gui.GuiRenderQueue; import com.replaymod.render.rendering.VideoRenderer; import com.replaymod.render.utils.RenderJob; -import com.replaymod.replaystudio.us.myles.ViaVersion.api.Pair; import de.johni0702.minecraft.gui.GuiRenderer; import de.johni0702.minecraft.gui.RenderInfo; import de.johni0702.minecraft.gui.versions.Image; @@ -44,6 +43,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOCase; import org.apache.commons.io.filefilter.SuffixFileFilter; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import java.io.File; import java.io.FileFilter; @@ -103,7 +103,7 @@ public class GuiReplayViewer extends GuiScreen { } else { Iterator>> replays = selected.stream() .filter(it -> !it.renderQueue.isEmpty()) - .map(it -> new Pair<>(it.file, it.renderQueue)) + .map(it -> Pair.of(it.file, it.renderQueue)) .iterator(); GuiRenderQueue.processMultipleReplays(GuiReplayViewer.this, mod, replays, () -> { loading = false; From 1af4add93258aba83ef390a4002cfa433fca8ffa Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 28 Jun 2021 14:36:56 +0200 Subject: [PATCH 076/102] Update ReplayStudio - MC 1.17 - Updated ViaVersion - Quick Mode supports multiple worlds now (and no longer needs a manual Respawn) --- build.gradle | 2 +- .../java/com/replaymod/core/ReplayMod.java | 2 +- .../java/com/replaymod/core/utils/Utils.java | 4 +- .../com/replaymod/core/versions/MCVer.java | 4 +- .../replaymod/replay/QuickReplaySender.java | 61 ------------------- 5 files changed, 6 insertions(+), 67 deletions(-) diff --git a/build.gradle b/build.gradle index 75013687..8a7cec14 100644 --- a/build.gradle +++ b/build.gradle @@ -330,7 +330,7 @@ dependencies { shadow 'com.github.ReplayMod.JavaBlend:2.79.0:a0696f8' - shadow "com.github.ReplayMod:ReplayStudio:0664fb7", shadeExclusions + shadow "com.github.ReplayMod:ReplayStudio:d82ef5b", shadeExclusions implementation(jGui){ transitive = false // FG 1.2 puts all MC deps into the compile configuration and we don't want to shade those diff --git a/src/main/java/com/replaymod/core/ReplayMod.java b/src/main/java/com/replaymod/core/ReplayMod.java index 99a78700..3fe653d9 100644 --- a/src/main/java/com/replaymod/core/ReplayMod.java +++ b/src/main/java/com/replaymod/core/ReplayMod.java @@ -13,10 +13,10 @@ import com.replaymod.extras.ReplayModExtras; import com.replaymod.recording.ReplayModRecording; import com.replaymod.render.ReplayModRender; import com.replaymod.replay.ReplayModReplay; +import com.replaymod.replaystudio.lib.viaversion.api.protocol.version.ProtocolVersion; import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ZipReplayFile; import com.replaymod.replaystudio.studio.ReplayStudio; -import com.replaymod.replaystudio.us.myles.ViaVersion.api.protocol.ProtocolVersion; import com.replaymod.replaystudio.util.I18n; import com.replaymod.simplepathing.ReplayModSimplePathing; import de.johni0702.minecraft.gui.container.GuiScreen; diff --git a/src/main/java/com/replaymod/core/utils/Utils.java b/src/main/java/com/replaymod/core/utils/Utils.java index a1cda2bc..50c328c8 100644 --- a/src/main/java/com/replaymod/core/utils/Utils.java +++ b/src/main/java/com/replaymod/core/utils/Utils.java @@ -7,7 +7,7 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.replaymod.core.ReplayMod; -import com.replaymod.replaystudio.us.myles.ViaVersion.api.protocol.ProtocolVersion; +import com.replaymod.replaystudio.lib.viaversion.api.protocol.version.ProtocolVersion; import de.johni0702.minecraft.gui.GuiRenderer; import de.johni0702.minecraft.gui.RenderInfo; import de.johni0702.minecraft.gui.container.AbstractGuiScrollable; @@ -337,7 +337,7 @@ public class Utils { ProtocolVersion latestVersion = ProtocolVersion.getProtocols() .stream() - .max(Comparator.comparing(ProtocolVersion::getId)) + .max(Comparator.comparing(ProtocolVersion::getVersion)) .orElseThrow(RuntimeException::new); getInfo().addElements(new VerticalLayout.Data(0.5), new GuiLabel() diff --git a/src/main/java/com/replaymod/core/versions/MCVer.java b/src/main/java/com/replaymod/core/versions/MCVer.java index a2702d6a..ac4dd754 100644 --- a/src/main/java/com/replaymod/core/versions/MCVer.java +++ b/src/main/java/com/replaymod/core/versions/MCVer.java @@ -2,9 +2,9 @@ package com.replaymod.core.versions; import com.mojang.blaze3d.platform.GlStateManager; import com.replaymod.core.mixin.GuiScreenAccessor; +import com.replaymod.replaystudio.lib.viaversion.api.protocol.packet.State; +import com.replaymod.replaystudio.lib.viaversion.api.protocol.version.ProtocolVersion; import com.replaymod.replaystudio.protocol.PacketTypeRegistry; -import com.replaymod.replaystudio.us.myles.ViaVersion.api.protocol.ProtocolVersion; -import com.replaymod.replaystudio.us.myles.ViaVersion.packets.State; import de.johni0702.minecraft.gui.MinecraftGuiRenderer; import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector2f; import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f; diff --git a/src/main/java/com/replaymod/replay/QuickReplaySender.java b/src/main/java/com/replaymod/replay/QuickReplaySender.java index 7c7c359d..5f5d7462 100644 --- a/src/main/java/com/replaymod/replay/QuickReplaySender.java +++ b/src/main/java/com/replaymod/replay/QuickReplaySender.java @@ -17,8 +17,6 @@ import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; import net.minecraft.client.MinecraftClient; -import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket; -import net.minecraft.network.packet.s2c.play.PlayerRespawnS2CPacket; import net.minecraft.network.NetworkState; import net.minecraft.network.NetworkSide; import net.minecraft.network.Packet; @@ -26,35 +24,12 @@ import net.minecraft.network.PacketByteBuf; import javax.annotation.Nullable; import java.io.IOException; -import java.util.Collections; import java.util.function.Consumer; -//#if MC>=11602 -import net.minecraft.util.registry.DynamicRegistryManager; -import net.minecraft.util.registry.Registry; -//#endif - -//#if MC>=11600 -import net.minecraft.world.World; -//#else -//$$ import net.minecraft.world.level.LevelGeneratorType; -//#endif -//#if MC>=11400 -import net.minecraft.world.dimension.DimensionType; -//#else -//$$ import net.minecraft.world.EnumDifficulty; -//#endif - //#if MC>=11200 import com.replaymod.core.utils.WrappedTimer; //#endif -//#if MC>=11002 -import net.minecraft.world.GameMode; -//#else -//$$ import net.minecraft.world.WorldSettings.GameType; -//#endif - import static com.replaymod.core.versions.MCVer.getMinecraft; import static com.replaymod.core.versions.MCVer.getPacketTypeRegistry; import static com.replaymod.replay.ReplayModReplay.LOGGER; @@ -193,42 +168,6 @@ public class QuickReplaySender extends ChannelHandlerAdapter implements ReplaySe public void restart() { replay.reset(); - ctx.fireChannelRead(new PlayerRespawnS2CPacket( - //#if MC>=11600 - //#if MC>=11602 - DimensionType.addRegistryDefaults(new DynamicRegistryManager.Impl()).get(Registry.DIMENSION_TYPE_KEY).get(DimensionType.OVERWORLD_REGISTRY_KEY), - //#else - //$$ DimensionType.OVERWORLD_REGISTRY_KEY, - //#endif - World.OVERWORLD, - 0, - GameMode.SPECTATOR, - GameMode.SPECTATOR, - false, - false, - false - //#else - //#if MC>=11400 - //$$ DimensionType.OVERWORLD, - //#else - //$$ 0, - //#endif - //#if MC>=11500 - //$$ 0, - //#endif - //#if MC<11400 - //$$ EnumDifficulty.NORMAL, - //#endif - //$$ LevelGeneratorType.DEFAULT, - //$$ GameMode.SPECTATOR - //#endif - )); - ctx.fireChannelRead(new PlayerPositionLookS2CPacket( - 0, 0, 0, 0, 0, Collections.emptySet(), 0 - //#if MC>=11700 - //$$ , true - //#endif - )); } @Override From 2be47e98109a0b28f114d6d72ce2ab8a7142a075 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 28 Jun 2021 17:47:15 +0200 Subject: [PATCH 077/102] Change ReplayButton icon to be white with shadow for better contrast The previous one, blue with no shadow, had horrible contrast with the button background and did not fit well with any of the other buttons. Now it does (except that it's not yet in the 20-pixel width/height style). --- .../com/replaymod/core/gui/GuiReplayButton.java | 6 ++++-- .../resources/assets/replaymod/logo_button.png | Bin 0 -> 18762 bytes 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 src/main/resources/assets/replaymod/logo_button.png diff --git a/src/main/java/com/replaymod/core/gui/GuiReplayButton.java b/src/main/java/com/replaymod/core/gui/GuiReplayButton.java index 9bd3476f..2ee4d9e4 100644 --- a/src/main/java/com/replaymod/core/gui/GuiReplayButton.java +++ b/src/main/java/com/replaymod/core/gui/GuiReplayButton.java @@ -1,17 +1,19 @@ package com.replaymod.core.gui; -import com.replaymod.core.ReplayMod; import de.johni0702.minecraft.gui.GuiRenderer; import de.johni0702.minecraft.gui.RenderInfo; import de.johni0702.minecraft.gui.element.GuiButton; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; +import net.minecraft.util.Identifier; public class GuiReplayButton extends GuiButton { + public static final Identifier ICON = new Identifier("replaymod", "logo_button.png"); + @Override public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) { super.draw(renderer, size, renderInfo); - renderer.bindTexture(ReplayMod.LOGO_FAVICON); + renderer.bindTexture(ICON); renderer.drawTexturedRect(3, 3, 0, 0, size.getWidth() - 6, size.getHeight() - 6, 1, 1, 1, 1); } } diff --git a/src/main/resources/assets/replaymod/logo_button.png b/src/main/resources/assets/replaymod/logo_button.png new file mode 100644 index 0000000000000000000000000000000000000000..6e4d88f1ef2bc100852e1c483d6c72eda90862da GIT binary patch literal 18762 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 Date: Mon, 28 Jun 2021 18:20:42 +0200 Subject: [PATCH 078/102] Bump MC to 1.17 proper --- build.gradle | 6 +++--- jGui | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 8a7cec14..16f2279f 100644 --- a/build.gradle +++ b/build.gradle @@ -238,7 +238,7 @@ dependencies { 11601: '1.16.1', 11603: '1.16.3', 11604: '1.16.4', - 11700: '1.17-rc1', + 11700: '1.17', ][mcVersion] mappings 'net.fabricmc:yarn:' + [ 11404: '1.14.4+build.16', @@ -246,7 +246,7 @@ dependencies { 11601: '1.16.1+build.17:v2', 11603: '1.16.3+build.1:v2', 11604: '1.16.4+build.6:v2', - 11700: '1.17-rc1+build.1:v2', + 11700: '1.17+build.13:v2', ][mcVersion] modImplementation 'net.fabricmc:fabric-loader:' + [ 11404: '0.7.8+build.189', @@ -262,7 +262,7 @@ dependencies { 11601: '0.14.0+build.371-1.16', 11603: '0.17.1+build.394-1.16', 11604: '0.25.1+build.416-1.16', - 11700: '0.34.8+1.17', + 11700: '0.36.0+1.17', ][mcVersion] def fabricApiModules = [ "api-base", diff --git a/jGui b/jGui index 09955508..797b8b83 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 09955508ca0e92b0658bfa4569bb46af7de16c43 +Subproject commit 797b8b8316251454dd35b4c840a628664afbf09b From 0fcb27c6b26e8a3e3d90b5a8d75be1e75a06342e Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 28 Jun 2021 18:57:01 +0200 Subject: [PATCH 079/102] Fix keyPressed/keyReleased injection targets --- jGui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jGui b/jGui index 797b8b83..088d3ef2 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 797b8b8316251454dd35b4c840a628664afbf09b +Subproject commit 088d3ef2a38148961754b2b56136797f25cbf592 From ed99e240eca9143585476abd80dbc0178dcc7231 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 28 Jun 2021 19:03:49 +0200 Subject: [PATCH 080/102] Bundle missing transitive fabric-api dependency --- build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle b/build.gradle index 16f2279f..a22d6932 100644 --- a/build.gradle +++ b/build.gradle @@ -273,6 +273,9 @@ dependencies { if (mcVersion >= 11600) { fabricApiModules.add("key-binding-api-v1") } + if (mcVersion >= 11700) { + fabricApiModules.add("networking-api-v1") + } fabricApiModules.each { module -> modImplementation fabricApi.module("fabric-$module", fabricApiVersion) include fabricApi.module("fabric-$module", fabricApiVersion) From 3f2456ba654d9ce9bc473cd48c0ab66b1e68716b Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 29 Jun 2021 12:39:06 +0200 Subject: [PATCH 081/102] Use GameRenderer.render instead of renderWorld, improves compat In particular, Iris updates its frame counter and timer in the outer method, so if we only call the inner one, then its shadows and sky will not update properly. Since the render method also renders the GUI, we set the current screen to null and cancel the HUD during rendering. MC also clears the depth before rendering the HUD, which we don't want because it breaks the depth map export, so we cancel that as well. This also allows Vanilla post-processing (aka Super Secret Settings, aka Vanilla Shaders) as well as entity outlines to function properly cause those are applied in that method as well. Should have done this a long time ago but better late than never. Closes #321 --- .../render/hooks/EntityRendererHandler.java | 26 +++++++++++++---- ...Mixin_PreserveDepthDuringGuiRendering.java | 28 +++++++++++++++++++ .../mixin/Mixin_SkipHudDuringRender.java | 23 +++++++++++++++ .../resources/mixins.render.replaymod.json | 2 ++ versions/1.14.4-forge/mapping.txt | 2 +- 5 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/replaymod/render/mixin/Mixin_PreserveDepthDuringGuiRendering.java create mode 100644 src/main/java/com/replaymod/render/mixin/Mixin_SkipHudDuringRender.java diff --git a/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java b/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java index 54560f1d..20e10c07 100644 --- a/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java +++ b/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java @@ -8,6 +8,7 @@ import com.replaymod.render.capturer.RenderInfo; import com.replaymod.render.capturer.WorldRenderer; import de.johni0702.minecraft.gui.utils.EventRegistrations; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; //#if MC>=11500 import net.minecraft.client.util.math.MatrixStack; @@ -65,11 +66,26 @@ public class EntityRendererHandler extends EventRegistrations implements WorldRe //#endif if (mc.world != null && mc.player != null) { - //#if MC>=11500 - mc.gameRenderer.renderWorld(partialTicks, finishTimeNano, new MatrixStack()); - //#else - //$$ mc.gameRenderer.renderWorld(partialTicks, finishTimeNano); - //#endif + Screen orgScreen = mc.currentScreen; + boolean orgPauseOnLostFocus = mc.options.pauseOnLostFocus; + try { + mc.currentScreen = null; // do not want to render the current screen (that'd just be the progress gui) + mc.options.pauseOnLostFocus = false; // do not want the pause menu to open if the window is unfocused + + //#if MC>=11400 + mc.gameRenderer.render(partialTicks, finishTimeNano, true); + //#else + //$$ mc.setIngameNotInFocus(); // this should already be the case but it somehow still sometimes is not + //#if MC>=10809 + //$$ mc.entityRenderer.updateCameraAndRender(partialTicks, finishTimeNano); + //#else + //$$ mc.entityRenderer.updateCameraAndRender(partialTicks); + //#endif + //#endif + } finally { + mc.currentScreen = orgScreen; + mc.options.pauseOnLostFocus = orgPauseOnLostFocus; + } } //#if MC>=11400 diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_PreserveDepthDuringGuiRendering.java b/src/main/java/com/replaymod/render/mixin/Mixin_PreserveDepthDuringGuiRendering.java new file mode 100644 index 00000000..0e9ab2c0 --- /dev/null +++ b/src/main/java/com/replaymod/render/mixin/Mixin_PreserveDepthDuringGuiRendering.java @@ -0,0 +1,28 @@ +package com.replaymod.render.mixin; + +import com.replaymod.render.hooks.EntityRendererHandler; +import net.minecraft.client.render.GameRenderer; +import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; + +@Mixin(GameRenderer.class) +public abstract class Mixin_PreserveDepthDuringGuiRendering { + @ModifyArg( + //#if MC>=11700 + method = "render", + at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;clear(IZ)V"), index = 0 + //#else + //$$ method = "setupOverlayRendering", + //$$ at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GlStateManager;clear(I)V"), index = 0 + //#endif + ) + private int replayModRender_skipClearWhenRecordingDepth(int mask) { + EntityRendererHandler handler = ((EntityRendererHandler.IEntityRenderer) this).replayModRender_getHandler(); + if (handler != null && handler.getSettings().isDepthMap()) { + mask = mask & ~GL11.GL_DEPTH_BUFFER_BIT; + } + return mask; + } +} diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_SkipHudDuringRender.java b/src/main/java/com/replaymod/render/mixin/Mixin_SkipHudDuringRender.java new file mode 100644 index 00000000..328b726d --- /dev/null +++ b/src/main/java/com/replaymod/render/mixin/Mixin_SkipHudDuringRender.java @@ -0,0 +1,23 @@ +package com.replaymod.render.mixin; + +import com.replaymod.render.hooks.EntityRendererHandler; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.hud.InGameHud; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +//#if MC>=11400 +@Mixin(InGameHud.class) +//#else +//$$ @Mixin({ GuiIngame.class, net.minecraftforge.client.GuiIngameForge.class }) +//#endif +public abstract class Mixin_SkipHudDuringRender { + @Inject(method = "render", at = @At("HEAD"), cancellable = true) + private void replayModRender_skipHudDuringRender(CallbackInfo ci) { + if (((EntityRendererHandler.IEntityRenderer) MinecraftClient.getInstance().gameRenderer).replayModRender_getHandler() != null) { + ci.cancel(); + } + } +} diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index 3118ccd3..05ba5423 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -14,7 +14,9 @@ "Mixin_Omnidirectional_DisableFrustumCulling", "Mixin_Omnidirectional_Rotation", "Mixin_Omnidirectional_SkipHand", + "Mixin_PreserveDepthDuringGuiRendering", "Mixin_SkipBlockOutlinesDuringRender", + "Mixin_SkipHudDuringRender", "Mixin_StabilizeCamera", "Mixin_Stereoscopic_Camera", "Mixin_Stereoscopic_HandRenderPass", diff --git a/versions/1.14.4-forge/mapping.txt b/versions/1.14.4-forge/mapping.txt index ec310305..d57a46f3 100644 --- a/versions/1.14.4-forge/mapping.txt +++ b/versions/1.14.4-forge/mapping.txt @@ -19,6 +19,7 @@ org.apache.maven.artifact.versioning.ComparableVersion net.minecraftforge.fml.co org.lwjgl.glfw.GLFW com.replaymod.core.versions.GLFW net.minecraft.client.MainWindow com.replaymod.core.versions.Window net.minecraft.client.audio.SimpleSound net.minecraft.client.audio.PositionedSoundRecord +net.minecraft.client.gui.IngameGui net.minecraft.client.gui.GuiIngame net.minecraft.resources.FolderPack getInputStream() getInputStreamByName() net.minecraft.client.gui.GuiYesNoCallback confirmResult() confirmClicked() @@ -183,7 +184,6 @@ net.minecraft.client.gui.screen.Screen removed() onGuiClosed() net.minecraft.client.gui.screen.Screen renderBackground() drawDefaultBackground() net.minecraft.client.gui.screen.Screen renderDirtBackground() drawBackground() net.minecraft.client.gui.hud.ChatHud net.minecraft.client.gui.GuiNewChat -net.minecraft.client.gui.hud.InGameHud net.minecraft.client.gui.GuiIngame net.minecraft.client.GameSettings net.minecraft.client.settings.GameSettings net.minecraft.client.GameSettings debugEnabled showDebugInfo net.minecraft.client.GameSettings viewDistance renderDistanceChunks From e85618a27c09e74dc79b19f8df4edd89d5b6eded Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 29 Jun 2021 12:48:38 +0200 Subject: [PATCH 082/102] Change frame time (used by Iris) to be based on replay or video time Iris derives that one from the frameStartNanos argument passed to the render method and shaders usually use it to do animations. Prior to this commit we always pass 0 which effectively froze any shader animations. With this commit, we now compute the frameStartNanos based on the FPS of the video we are rendering (so animations will happen in real time when watching the video) or based on the time in the replay (so animations will be influenced by playback speed / be frozen if the replay is frozen). We default to the video time based approach because the replay time one may produce undesirable results when it comes to things like motion blur and TAA. --- .../java/com/replaymod/render/Setting.java | 2 ++ .../render/hooks/EntityRendererHandler.java | 25 +++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/replaymod/render/Setting.java b/src/main/java/com/replaymod/render/Setting.java index d8426126..c8a58037 100644 --- a/src/main/java/com/replaymod/render/Setting.java +++ b/src/main/java/com/replaymod/render/Setting.java @@ -7,4 +7,6 @@ public final class Setting { new SettingsRegistry.SettingKeys<>("advanced", "renderPath", null, "./replay_videos/"); public static final SettingsRegistry.SettingKey SKIP_POST_RENDER_GUI = new SettingsRegistry.SettingKeys<>("advanced", "skipPostRenderGui", null, false); + public static final SettingsRegistry.SettingKey FRAME_TIME_FROM_WORLD_TIME = + new SettingsRegistry.SettingKeys<>("render", "frameTimeFromWorldTime", null, false); } diff --git a/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java b/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java index 20e10c07..8dbd50f7 100644 --- a/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java +++ b/src/main/java/com/replaymod/render/hooks/EntityRendererHandler.java @@ -1,22 +1,22 @@ package com.replaymod.render.hooks; +import com.replaymod.core.ReplayMod; import com.replaymod.core.events.PreRenderHandCallback; import com.replaymod.core.versions.MCVer; import com.replaymod.render.RenderSettings; +import com.replaymod.render.Setting; import com.replaymod.render.capturer.CaptureData; import com.replaymod.render.capturer.RenderInfo; import com.replaymod.render.capturer.WorldRenderer; +import com.replaymod.replay.ReplayModReplay; import de.johni0702.minecraft.gui.utils.EventRegistrations; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; -//#if MC>=11500 -import net.minecraft.client.util.math.MatrixStack; -//#endif - //#if MC>=11400 import com.replaymod.core.events.PostRenderCallback; import com.replaymod.core.events.PreRenderCallback; +import net.minecraft.util.Util; //#else //#if MC>=11400 //$$ import net.minecraftforge.fml.hooks.BasicEventHooks; @@ -38,10 +38,18 @@ public class EntityRendererHandler extends EventRegistrations implements WorldRe public boolean omnidirectional; + private final long startTime; + public EntityRendererHandler(RenderSettings settings, RenderInfo renderInfo) { this.settings = settings; this.renderInfo = renderInfo; + //#if MC>=11400 + this.startTime = Util.getMeasuringTimeNano(); + //#else + //$$ this.startTime = System.nanoTime(); + //#endif + on(PreRenderHandCallback.EVENT, () -> omnidirectional); ((IEntityRenderer) mc.gameRenderer).replayModRender_setHandler(this); @@ -51,7 +59,14 @@ public class EntityRendererHandler extends EventRegistrations implements WorldRe @Override public void renderWorld(final float partialTicks, CaptureData data) { this.data = data; - renderWorld(partialTicks, 0); + long offsetMillis; + if (ReplayMod.instance.getSettingsRegistry().get(Setting.FRAME_TIME_FROM_WORLD_TIME)) { + offsetMillis = ReplayModReplay.instance.getReplayHandler().getReplaySender().currentTimeStamp(); + } else { + offsetMillis = renderInfo.getFramesDone() * 1_000L / settings.getFramesPerSecond(); + } + long frameStartTimeNano = startTime + offsetMillis * 1_000_000L; + renderWorld(partialTicks, frameStartTimeNano); } public void renderWorld(float partialTicks, long finishTimeNano) { From f462a5b391d40912de389b0297431954df942cef Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 29 Jun 2021 13:54:57 +0200 Subject: [PATCH 083/102] Fix 1.12 shim Window.getScaledHeight --- .../src/main/java/com/replaymod/core/versions/Window.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/versions/Window.java b/versions/1.12.2/src/main/java/com/replaymod/core/versions/Window.java index d0a3ddba..fdcadef3 100644 --- a/versions/1.12.2/src/main/java/com/replaymod/core/versions/Window.java +++ b/versions/1.12.2/src/main/java/com/replaymod/core/versions/Window.java @@ -64,6 +64,6 @@ public class Window implements MainWindowAccessor { } public int getScaledHeight() { - return scaledResolution().getScaledWidth(); + return scaledResolution().getScaledHeight(); } } From 7ab2edd7386ecb2674a3b771289c9f0bcc0c75a6 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 29 Jun 2021 17:57:11 +0200 Subject: [PATCH 084/102] Implement ODS rendering via Iris Shader for MC 1.17 --- build.gradle | 4 + .../render/capturer/IrisODSFrameCapturer.java | 156 ++++++++++++++++++ .../replaymod/render/gui/GuiRenderQueue.java | 2 +- .../render/gui/GuiRenderSettings.java | 2 +- .../mixin/Mixin_AddIrisOdsShaderUniforms.java | 27 +++ .../mixin/Mixin_LoadIrisOdsShaderPack.java | 29 ++++ .../replaymod/render/rendering/Pipelines.java | 10 +- .../render/rendering/VideoRenderer.java | 19 ++- .../replay/gui/screen/GuiReplayViewer.java | 2 +- .../ods/shaders/gbuffers_textured_lit.fsh | 15 ++ .../ods/shaders/gbuffers_textured_lit.vsh | 69 ++++++++ .../resources/mixins.render.replaymod.json | 4 + 12 files changed, 333 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/replaymod/render/capturer/IrisODSFrameCapturer.java create mode 100644 src/main/java/com/replaymod/render/mixin/Mixin_AddIrisOdsShaderUniforms.java create mode 100644 src/main/java/com/replaymod/render/mixin/Mixin_LoadIrisOdsShaderPack.java create mode 100644 src/main/resources/assets/replaymod/iris/ods/shaders/gbuffers_textured_lit.fsh create mode 100644 src/main/resources/assets/replaymod/iris/ods/shaders/gbuffers_textured_lit.vsh diff --git a/build.gradle b/build.gradle index a22d6932..311f481f 100644 --- a/build.gradle +++ b/build.gradle @@ -352,6 +352,10 @@ dependencies { } } + if (mcVersion >= 11600) { + modCompileOnly 'com.github.IrisShaders:Iris:1.0.0' + } + testImplementation 'junit:junit:4.11' } diff --git a/src/main/java/com/replaymod/render/capturer/IrisODSFrameCapturer.java b/src/main/java/com/replaymod/render/capturer/IrisODSFrameCapturer.java new file mode 100644 index 00000000..a1d31055 --- /dev/null +++ b/src/main/java/com/replaymod/render/capturer/IrisODSFrameCapturer.java @@ -0,0 +1,156 @@ +//#if MC>=11600 +package com.replaymod.render.capturer; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.replaymod.render.RenderSettings; +import com.replaymod.render.frame.CubicOpenGlFrame; +import com.replaymod.render.frame.ODSOpenGlFrame; +import com.replaymod.render.frame.OpenGlFrame; +import com.replaymod.render.rendering.Channel; +import com.replaymod.render.rendering.FrameCapturer; +import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; +import net.coderbot.iris.Iris; +import net.coderbot.iris.config.IrisConfig; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static com.replaymod.core.versions.MCVer.popMatrix; +import static com.replaymod.core.versions.MCVer.pushMatrix; +import static com.replaymod.core.versions.MCVer.resizeMainWindow; +import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; +import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; + +public class IrisODSFrameCapturer implements FrameCapturer { + + public static final String SHADER_PACK_NAME = "assets/replaymod/iris/ods"; + public static IrisODSFrameCapturer INSTANCE; + private final CubicPboOpenGlFrameCapturer left, right; + private final String prevShaderPack; + private int direction; + private boolean isLeftEye; + + public IrisODSFrameCapturer(WorldRenderer worldRenderer, final RenderInfo renderInfo, int frameSize) { + RenderInfo fakeInfo = new RenderInfo() { + private int call; + private float partialTicks; + @Override + public ReadableDimension getFrameSize() { + return renderInfo.getFrameSize(); + } + + @Override + public int getFramesDone() { + return renderInfo.getFramesDone(); + } + + @Override + public int getTotalFrames() { + return renderInfo.getTotalFrames(); + } + + @Override + public float updateForNextFrame() { + if (call++ % 2 == 0) { + partialTicks = renderInfo.updateForNextFrame(); + } + return partialTicks; + } + + @Override + public RenderSettings getRenderSettings() { + return renderInfo.getRenderSettings(); + } + }; + left = new CubicStereoFrameCapturer(worldRenderer, fakeInfo, frameSize); + right = new CubicStereoFrameCapturer(worldRenderer, fakeInfo, frameSize); + + INSTANCE = this; + prevShaderPack = Iris.getIrisConfig().getShaderPackName().orElse(null); + setShaderPack(SHADER_PACK_NAME); + } + + private static void setShaderPack(String name) { + IrisConfig irisConfig = Iris.getIrisConfig(); + irisConfig.setShaderPackName(name); + try { + irisConfig.save(); + Iris.reload(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public int getDirection() { + return direction; + } + + public boolean isLeftEye() { + return isLeftEye; + } + + @Override + public boolean isDone() { + return left.isDone() && right.isDone(); + } + + @Override + public Map process() { + isLeftEye = true; + Map leftChannels = left.process(); + isLeftEye = false; + Map rightChannels = right.process(); + + if (leftChannels != null && rightChannels != null) { + Map result = new HashMap<>(); + for (Channel channel : Channel.values()) { + CubicOpenGlFrame leftFrame = leftChannels.get(channel); + CubicOpenGlFrame rightFrame = rightChannels.get(channel); + if (leftFrame != null && rightFrame != null) { + result.put(channel, new ODSOpenGlFrame(leftFrame, rightFrame)); + } + } + return result; + } + return null; + } + + @Override + public void close() throws IOException { + left.close(); + right.close(); + INSTANCE = null; + setShaderPack(prevShaderPack); + } + + private class CubicStereoFrameCapturer extends CubicPboOpenGlFrameCapturer { + public CubicStereoFrameCapturer(WorldRenderer worldRenderer, RenderInfo renderInfo, int frameSize) { + super(worldRenderer, renderInfo, frameSize); + } + + @Override + protected OpenGlFrame renderFrame(int frameId, float partialTicks, CubicOpenGlFrameCapturer.Data captureData) { + resizeMainWindow(mc, getFrameWidth(), getFrameHeight()); + + pushMatrix(); + frameBuffer().beginWrite(true); + + GlStateManager.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT + //#if MC>=11400 + , false + //#endif + ); + GlStateManager.enableTexture(); + + direction = captureData.ordinal(); + worldRenderer.renderWorld(partialTicks, null); + + frameBuffer().endWrite(); + popMatrix(); + + return captureFrame(frameId, captureData); + } + } +} +//#endif diff --git a/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java b/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java index 0ab59405..8e9d92ea 100644 --- a/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java +++ b/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java @@ -348,7 +348,7 @@ public class GuiRenderQueue extends AbstractGuiPopup implements renderButton.setEnabled(jobs.size() > 0); renderButton.setI18nLabel("replaymod.gui.renderqueue.render" + (selected > 0 ? "selected" : "all")); - String[] compatError = VideoRenderer.checkCompat(); + String[] compatError = VideoRenderer.checkCompat(jobs.stream().map(RenderJob::getSettings)); if (compatError != null) { renderButton.setDisabled().setTooltip(new GuiTooltip().setText(compatError)); } diff --git a/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java b/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java index b6eae92f..1d8b9c9a 100644 --- a/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java +++ b/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java @@ -363,7 +363,7 @@ public class GuiRenderSettings extends AbstractGuiPopup { videoHeight.setTextColor(Colors.RED); } - String[] compatError = VideoRenderer.checkCompat(); + String[] compatError = VideoRenderer.checkCompat(save(false)); if (resolutionError != null) { renderButton.setDisabled().setTooltip(new GuiTooltip().setI18nText(resolutionError)); } else if (compatError != null) { diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_AddIrisOdsShaderUniforms.java b/src/main/java/com/replaymod/render/mixin/Mixin_AddIrisOdsShaderUniforms.java new file mode 100644 index 00000000..e034a547 --- /dev/null +++ b/src/main/java/com/replaymod/render/mixin/Mixin_AddIrisOdsShaderUniforms.java @@ -0,0 +1,27 @@ +//#if MC>=11600 +package com.replaymod.render.mixin; + +import com.replaymod.render.capturer.IrisODSFrameCapturer; +import net.coderbot.iris.gl.uniform.UniformHolder; +import net.coderbot.iris.gl.uniform.UniformUpdateFrequency; +import net.coderbot.iris.uniforms.CommonUniforms; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Pseudo +@Mixin(value = CommonUniforms.class, remap = false) +public class Mixin_AddIrisOdsShaderUniforms { + // Using ModifyVariable, so we only depend on a single argument. Hoping that reduces the chance of breaking changes. + @ModifyVariable(method = "generalCommonUniforms", at = @At("HEAD"), argsOnly = true) + private static UniformHolder addReplayModOdsUniforms(UniformHolder uniforms) { + IrisODSFrameCapturer ods = IrisODSFrameCapturer.INSTANCE; + if (ods != null) { + uniforms.uniform1b(UniformUpdateFrequency.PER_FRAME, "leftEye", ods::isLeftEye); + uniforms.uniform1i(UniformUpdateFrequency.PER_FRAME, "direction", ods::getDirection); + } + return uniforms; + } +} +//#endif diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_LoadIrisOdsShaderPack.java b/src/main/java/com/replaymod/render/mixin/Mixin_LoadIrisOdsShaderPack.java new file mode 100644 index 00000000..d8756e7b --- /dev/null +++ b/src/main/java/com/replaymod/render/mixin/Mixin_LoadIrisOdsShaderPack.java @@ -0,0 +1,29 @@ +//#if MC>=11600 +package com.replaymod.render.mixin; + +import com.replaymod.render.capturer.IrisODSFrameCapturer; +import net.coderbot.iris.Iris; +import net.fabricmc.loader.api.FabricLoader; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.nio.file.Path; + +@Pseudo +@Mixin(value = Iris.class, remap = false) +public class Mixin_LoadIrisOdsShaderPack { + @Redirect(method = "loadExternalShaderpack", at = @At(value = "FIELD", opcode = Opcodes.GETSTATIC, target = "Lnet/coderbot/iris/Iris;SHADERPACKS_DIRECTORY:Ljava/nio/file/Path;")) + private static Path loadReplayModOdsPack(String name) { + if (IrisODSFrameCapturer.INSTANCE != null && IrisODSFrameCapturer.SHADER_PACK_NAME.equals(name)) { + return FabricLoader.getInstance().getModContainer("replaymod") + .orElseThrow(() -> new RuntimeException("Failed to get mod container for ReplayMod")) + .getRootPath(); + } else { + return Iris.SHADERPACKS_DIRECTORY; + } + } +} +//#endif diff --git a/src/main/java/com/replaymod/render/rendering/Pipelines.java b/src/main/java/com/replaymod/render/rendering/Pipelines.java index 62a2b502..e012fb41 100644 --- a/src/main/java/com/replaymod/render/rendering/Pipelines.java +++ b/src/main/java/com/replaymod/render/rendering/Pipelines.java @@ -105,8 +105,14 @@ public class Pipelines { ODSToBitmapProcessor processor = new ODSToBitmapProcessor(settings.getVideoWidth(), settings.getVideoHeight(), settings.getSphericalFovX()); - FrameCapturer capturer = - new ODSFrameCapturer(worldRenderer, renderInfo, processor.getFrameSize()); + //#if MC>=11600 + boolean iris = net.fabricmc.loader.api.FabricLoader.getInstance().isModLoaded("iris"); + FrameCapturer capturer = iris + ? new com.replaymod.render.capturer.IrisODSFrameCapturer(worldRenderer, renderInfo, processor.getFrameSize()) + : new ODSFrameCapturer(worldRenderer, renderInfo, processor.getFrameSize()); + //#else + //$$ FrameCapturer capturer = new ODSFrameCapturer(worldRenderer, renderInfo, processor.getFrameSize()); + //#endif return new Pipeline<>(worldRenderer, capturer, processor, consumer); } diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index 5ce80a9a..6baf7a28 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -74,10 +74,12 @@ import java.io.IOException; import java.util.Collection; import java.util.EnumMap; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Queue; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; +import java.util.stream.Stream; import static com.google.common.collect.Iterables.getLast; import static com.replaymod.core.versions.MCVer.*; @@ -699,7 +701,11 @@ public class VideoRenderer implements RenderInfo { } } - public static String[] checkCompat() { + public static String[] checkCompat(Stream settings) { + return settings.map(VideoRenderer::checkCompat).filter(Objects::nonNull).findFirst().orElse(null); + } + + public static String[] checkCompat(RenderSettings settings) { //#if FABRIC>=1 if (net.fabricmc.loader.api.FabricLoader.getInstance().isModLoaded("sodium")) { return new String[] { @@ -708,6 +714,17 @@ public class VideoRenderer implements RenderInfo { "For now, you need to uninstall Sodium before rendering!" }; } + //#if MC>=11700 + //$$ if (settings.getRenderMethod() == RenderSettings.RenderMethod.ODS + //$$ && !net.fabricmc.loader.api.FabricLoader.getInstance().isModLoaded("iris")) { + //$$ return new String[] { + //$$ "ODS export requires Iris to be installed for Minecraft 1.17 and above.", + //$$ "Note that it is nevertheless incompatible with other shaders and will simply replace them.", + //$$ "Get it from: https://irisshaders.net/", + //$$ "Use the Standalone version! Sodium is not currently compatible with rendering!", + //$$ }; + //$$ } + //#endif //#endif return null; } diff --git a/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java b/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java index 7fe0e49f..bd889eb0 100644 --- a/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java +++ b/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java @@ -260,7 +260,7 @@ public class GuiReplayViewer extends GuiScreen { loadButton.setTooltip(new GuiTooltip().setText(tooltipLines)); loadButton.setEnabled(!jobs.isEmpty()); - String[] compatError = VideoRenderer.checkCompat(); + String[] compatError = VideoRenderer.checkCompat(jobs.stream().map(RenderJob::getSettings)); if (compatError != null) { loadButton.setDisabled().setTooltip(new GuiTooltip().setText(compatError)); } diff --git a/src/main/resources/assets/replaymod/iris/ods/shaders/gbuffers_textured_lit.fsh b/src/main/resources/assets/replaymod/iris/ods/shaders/gbuffers_textured_lit.fsh new file mode 100644 index 00000000..76b37f95 --- /dev/null +++ b/src/main/resources/assets/replaymod/iris/ods/shaders/gbuffers_textured_lit.fsh @@ -0,0 +1,15 @@ +#version 120 + +uniform sampler2D texture; +uniform sampler2D lightmap; + +varying vec4 color; +varying vec2 texcoord; +varying vec2 lmcoord; + +void main() { + vec4 lightmap = texture2D(lightmap, lmcoord); + vec4 color = texture2D(texture, texcoord) * color; + color *= lightmap; + gl_FragColor = color; +} \ No newline at end of file diff --git a/src/main/resources/assets/replaymod/iris/ods/shaders/gbuffers_textured_lit.vsh b/src/main/resources/assets/replaymod/iris/ods/shaders/gbuffers_textured_lit.vsh new file mode 100644 index 00000000..3b53c589 --- /dev/null +++ b/src/main/resources/assets/replaymod/iris/ods/shaders/gbuffers_textured_lit.vsh @@ -0,0 +1,69 @@ +#version 120 + +varying vec4 color; +varying vec2 texcoord; +varying vec2 lmcoord; + +uniform int leftEye; +uniform int direction; + +const float eyeDistance = 0.14; + +void main() { + // Transform to view space + vec4 position = gl_ModelViewMatrix * gl_Vertex; + + // Distort for ODS + // O := The origin + // P := The current vertex/point + // T := Point of tangency with the tangent going through P + // Distance between P and O + float distPO = sqrt(position.x * position.x + position.z * position.z); + float distTO = eyeDistance * 0.5; + // Angle between PO and PT + float angP = acos(distTO / distPO); + // Angle between PO and TO (angle at the origin) + float angO = 90.0 - angP; + if (leftEye == 0) { + angO = -angO; + } + // The angel of OP within the circle, that is between OP and O(0,1) + float angOP = atan(position.x, position.z); + // The angle of OT within the circle, that is between OT and O(0,1) + float angOT = angO + angOP; + // Calculate the vector between O and T and finally move the vertex by that vector + position -= vec4(distTO * sin(angOT), 0, distTO * cos(angOT), 0); + + // Rotate for different cubic views + float z; + if (direction == 0) { // LEFT + z = position.z; + position.z = position.x; + position.x = -z; + } else if (direction == 1) { // RIGHT + z = position.z; + position.z = -position.x; + position.x = z; + } else if (direction == 2) { // FRONT + // No changes required + } else if (direction == 3) { // BACK + position.x = -position.x; + position.z = -position.z; + } else if (direction == 4) { // TOP + z = position.z; + position.z = -position.y; + position.y = z; + } else if (direction == 5) { // BOTTOM + z = position.z; + position.z = position.y; + position.y = -z; + } + + // Transform to screen space + gl_Position = gl_ProjectionMatrix * position; + + // Misc. + color = gl_Color; + texcoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy; + lmcoord = (gl_TextureMatrix[1] * gl_MultiTexCoord1).xy; +} \ No newline at end of file diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index 05ba5423..7bddb362 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -20,6 +20,10 @@ "Mixin_StabilizeCamera", "Mixin_Stereoscopic_Camera", "Mixin_Stereoscopic_HandRenderPass", + //#if MC>=11600 + "Mixin_AddIrisOdsShaderUniforms", + "Mixin_LoadIrisOdsShaderPack", + //#endif //#if MC>=10800 //#if MC>=11500 "Mixin_BlockOnChunkRebuilds", From 7a52a29ef38f493e4f374563c7c828851855084b Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Thu, 1 Jul 2021 10:20:44 +0200 Subject: [PATCH 085/102] Fix race condition in resource pack recording (fixes #521) If the server sends the resource pack right on connect (rather than when switching to a sub-server), then `mc.getNetworkHandler()` will be null. --- .../recording/packet/PacketListener.java | 4 +++- .../recording/packet/ResourcePackRecorder.java | 15 ++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/replaymod/recording/packet/PacketListener.java b/src/main/java/com/replaymod/recording/packet/PacketListener.java index 2fafe7dc..e7236e5b 100644 --- a/src/main/java/com/replaymod/recording/packet/PacketListener.java +++ b/src/main/java/com/replaymod/recording/packet/PacketListener.java @@ -26,6 +26,7 @@ import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import net.minecraft.client.MinecraftClient; +import net.minecraft.network.ClientConnection; import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; import net.minecraft.network.packet.s2c.play.DisconnectS2CPacket; import net.minecraft.network.packet.s2c.play.ItemPickupAnimationS2CPacket; @@ -339,7 +340,8 @@ public class PacketListener extends ChannelInboundHandlerAdapter { //#if MC>=10800 if (packet instanceof ResourcePackSendS2CPacket) { - save(resourcePackRecorder.handleResourcePack((ResourcePackSendS2CPacket) packet)); + ClientConnection connection = ctx.pipeline().get(ClientConnection.class); + save(resourcePackRecorder.handleResourcePack(connection, (ResourcePackSendS2CPacket) packet)); return; } //#else diff --git a/src/main/java/com/replaymod/recording/packet/ResourcePackRecorder.java b/src/main/java/com/replaymod/recording/packet/ResourcePackRecorder.java index 05a219b4..689f2cfd 100644 --- a/src/main/java/com/replaymod/recording/packet/ResourcePackRecorder.java +++ b/src/main/java/com/replaymod/recording/packet/ResourcePackRecorder.java @@ -37,7 +37,6 @@ import java.util.concurrent.CompletableFuture; //#else //$$ import com.google.common.util.concurrent.ListenableFuture; //#endif -import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.network.ClientConnection; //#else //$$ import com.replaymod.core.mixin.ResourcePackRepositoryAccessor; @@ -111,10 +110,8 @@ public class ResourcePackRecorder { } - public synchronized ResourcePackSendS2CPacket handleResourcePack(ResourcePackSendS2CPacket packet) { + public synchronized ResourcePackSendS2CPacket handleResourcePack(ClientConnection netManager, ResourcePackSendS2CPacket packet) { final int requestId = nextRequestId++; - final ClientPlayNetworkHandler netHandler = mc.getNetworkHandler(); - final ClientConnection netManager = netHandler.getConnection(); final String url = packet.getURL(); final String hash = packet.getSHA1(); @@ -138,7 +135,7 @@ public class ResourcePackRecorder { final ServerInfo serverData = mc.getCurrentServerEntry(); if (serverData != null && serverData.getResourcePack() == ServerInfo.ResourcePackState.ENABLED) { netManager.send(makeStatusPacket(hash, Status.ACCEPTED)); - downloadResourcePackFuture(requestId, url, hash); + downloadResourcePackFuture(netManager, requestId, url, hash); } else if (serverData != null && serverData.getResourcePack() != ServerInfo.ResourcePackState.PROMPT) { netManager.send(makeStatusPacket(hash, Status.DECLINED)); } else { @@ -156,7 +153,7 @@ public class ResourcePackRecorder { } if (result) { netManager.send(makeStatusPacket(hash, Status.ACCEPTED)); - downloadResourcePackFuture(requestId, url, hash); + downloadResourcePackFuture(netManager, requestId, url, hash); } else { netManager.send(makeStatusPacket(hash, Status.DECLINED)); } @@ -180,10 +177,10 @@ public class ResourcePackRecorder { ); } - private void downloadResourcePackFuture(int requestId, String url, final String hash) { + private void downloadResourcePackFuture(ClientConnection connection, int requestId, String url, final String hash) { addCallback(downloadResourcePack(requestId, url, hash), - result -> mc.getNetworkHandler().sendPacket(makeStatusPacket(hash, Status.SUCCESSFULLY_LOADED)), - throwable -> mc.getNetworkHandler().sendPacket(makeStatusPacket(hash, Status.FAILED_DOWNLOAD))); + result -> connection.send(makeStatusPacket(hash, Status.SUCCESSFULLY_LOADED)), + throwable -> connection.send(makeStatusPacket(hash, Status.FAILED_DOWNLOAD))); } private From 96bb1abc1d62feab55be9d898d3956ce8381f6cc Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Thu, 1 Jul 2021 13:57:11 +0200 Subject: [PATCH 086/102] Update ReplayStudio 0e72e36 Add workaround for lack of way to determine global palette size 872bc75 Update vanilla global palette size 19d3dab Fix OOB when converting local palette storage to global palette (fixes #509) c93a370 Fix incorrect packet release during SquashFilter.flush (fixes #490, fixes #492) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 311f481f..ec72276d 100644 --- a/build.gradle +++ b/build.gradle @@ -333,7 +333,7 @@ dependencies { shadow 'com.github.ReplayMod.JavaBlend:2.79.0:a0696f8' - shadow "com.github.ReplayMod:ReplayStudio:d82ef5b", shadeExclusions + shadow "com.github.ReplayMod:ReplayStudio:0e72e36", shadeExclusions implementation(jGui){ transitive = false // FG 1.2 puts all MC deps into the compile configuration and we don't want to shade those From d0620091d2e5323096147740e464b1aa6cbb2711 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 24 Jul 2021 09:11:34 +0200 Subject: [PATCH 087/102] Add support for FREX Flawless Frames API (fixes #150) --- .../render/hooks/ForceChunkLoadingHook.java | 3 ++ .../render/rendering/VideoRenderer.java | 10 ++--- .../render/utils/FlawlessFrames.java | 40 +++++++++++++++++++ src/main/resources/fabric.mod.json | 3 ++ 4 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/replaymod/render/utils/FlawlessFrames.java diff --git a/src/main/java/com/replaymod/render/hooks/ForceChunkLoadingHook.java b/src/main/java/com/replaymod/render/hooks/ForceChunkLoadingHook.java index 14143698..7352945f 100644 --- a/src/main/java/com/replaymod/render/hooks/ForceChunkLoadingHook.java +++ b/src/main/java/com/replaymod/render/hooks/ForceChunkLoadingHook.java @@ -1,5 +1,6 @@ package com.replaymod.render.hooks; +import com.replaymod.render.utils.FlawlessFrames; import net.minecraft.client.render.WorldRenderer; public class ForceChunkLoadingHook { @@ -9,11 +10,13 @@ public class ForceChunkLoadingHook { public ForceChunkLoadingHook(WorldRenderer renderGlobal) { this.hooked = renderGlobal; + FlawlessFrames.setEnabled(true); IForceChunkLoading.from(renderGlobal).replayModRender_setHook(this); } public void uninstall() { IForceChunkLoading.from(hooked).replayModRender_setHook(null); + FlawlessFrames.setEnabled(false); } public interface IBlockOnChunkRebuilds { diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index 6baf7a28..dfa7e096 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -23,6 +23,7 @@ import com.replaymod.render.hooks.ForceChunkLoadingHook; import com.replaymod.render.metadata.MetadataInjector; import com.replaymod.render.mixin.MainWindowAccessor; import com.replaymod.render.mixin.WorldRendererAccessor; +import com.replaymod.render.utils.FlawlessFrames; import com.replaymod.replay.ReplayHandler; import com.replaymod.replaystudio.pathing.path.Keyframe; import com.replaymod.replaystudio.pathing.path.Path; @@ -707,11 +708,11 @@ public class VideoRenderer implements RenderInfo { public static String[] checkCompat(RenderSettings settings) { //#if FABRIC>=1 - if (net.fabricmc.loader.api.FabricLoader.getInstance().isModLoaded("sodium")) { + if (net.fabricmc.loader.api.FabricLoader.getInstance().isModLoaded("sodium") && !FlawlessFrames.hasSodium()) { return new String[] { - "Rendering is not currently supported while Sodium is installed.", - "See https://github.com/ReplayMod/ReplayMod/issues/150", - "For now, you need to uninstall Sodium before rendering!" + "Rendering is not supported with your Sodium version.", + "It is missing support for the FREX Flawless Frames API.", + "Either update to the latest version or uninstall Sodium before rendering!", }; } //#if MC>=11700 @@ -721,7 +722,6 @@ public class VideoRenderer implements RenderInfo { //$$ "ODS export requires Iris to be installed for Minecraft 1.17 and above.", //$$ "Note that it is nevertheless incompatible with other shaders and will simply replace them.", //$$ "Get it from: https://irisshaders.net/", - //$$ "Use the Standalone version! Sodium is not currently compatible with rendering!", //$$ }; //$$ } //#endif diff --git a/src/main/java/com/replaymod/render/utils/FlawlessFrames.java b/src/main/java/com/replaymod/render/utils/FlawlessFrames.java new file mode 100644 index 00000000..e419adef --- /dev/null +++ b/src/main/java/com/replaymod/render/utils/FlawlessFrames.java @@ -0,0 +1,40 @@ +package com.replaymod.render.utils; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; +import java.util.function.Function; + +import static com.replaymod.core.ReplayMod.MOD_ID; + +/** + * Uses the "Flawless Frames" FREX feature which allows us to instruct third-party mods to sacrifice performance (even + * beyond the point where it can no longer achieve interactive frame rates) in exchange for a noticeable boost to + * quality. + * In particular also to force-load all chunks with Canvas/Sodium/Bobby. + * + * See https://github.com/grondag/frex/pull/9 + */ +public class FlawlessFrames { + private static final List> CONSUMERS = new CopyOnWriteArrayList<>(); + private static boolean hasSodium; + + private FlawlessFrames() {} + + public static void registerConsumer(Function> provider) { + Consumer consumer = provider.apply(MOD_ID); + CONSUMERS.add(consumer); + + if (provider.getClass().getName().contains(".sodium.") || consumer.getClass().getName().contains(".sodium.")) { + hasSodium = true; + } + } + + public static void setEnabled(boolean enabled) { + CONSUMERS.forEach(it -> it.accept(enabled)); + } + + public static boolean hasSodium() { + return hasSodium; + } +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 8dc61a19..6eb336ce 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -25,6 +25,9 @@ "modmenu": [ "com.replaymod.core.gui.ModMenuApiImpl" ], + "frex_flawless_frames": [ + "com.replaymod.render.utils.FlawlessFrames::registerConsumer" + ], "preLaunch": [ "com.replaymod.core.DummyChainLoadEntryPoint" ], From 927db36baa84c96d909ccd7034c0e3e9610b3f07 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 24 Jul 2021 11:05:00 +0200 Subject: [PATCH 088/102] Use same fabric-loader version across all MC versions --- build.gradle | 9 +-------- jGui | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index ec72276d..47ae0818 100644 --- a/build.gradle +++ b/build.gradle @@ -248,14 +248,7 @@ dependencies { 11604: '1.16.4+build.6:v2', 11700: '1.17+build.13:v2', ][mcVersion] - modImplementation 'net.fabricmc:fabric-loader:' + [ - 11404: '0.7.8+build.189', - 11502: '0.7.8+build.189', - 11601: '0.8.8+build.202', - 11603: '0.9.1+build.205', - 11604: '0.10.6+build.214', - 11700: '0.11.3', - ][mcVersion] + modImplementation 'net.fabricmc:fabric-loader:0.11.6' def fabricApiVersion = [ 11404: '0.4.3+build.247-1.14', 11502: '0.5.1+build.294-1.15', diff --git a/jGui b/jGui index 088d3ef2..9b5e0192 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 088d3ef2a38148961754b2b56136797f25cbf592 +Subproject commit 9b5e0192ab2cb90f200005ab53f9e1a85ce29393 From 2415a886e290892c8c8a606c54790b3a972860b1 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 24 Jul 2021 11:05:39 +0200 Subject: [PATCH 089/102] Update to 1.17.1 --- build.gradle | 5 ++++- jGui | 2 +- root.gradle.kts | 2 ++ settings.gradle.kts | 2 ++ src/main/java/com/replaymod/render/blend/Util.java | 2 +- src/main/java/com/replaymod/replay/NoGuiScreenshot.java | 7 ++++++- 6 files changed, 16 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 47ae0818..a59dedb6 100644 --- a/build.gradle +++ b/build.gradle @@ -239,6 +239,7 @@ dependencies { 11603: '1.16.3', 11604: '1.16.4', 11700: '1.17', + 11701: '1.17.1', ][mcVersion] mappings 'net.fabricmc:yarn:' + [ 11404: '1.14.4+build.16', @@ -247,6 +248,7 @@ dependencies { 11603: '1.16.3+build.1:v2', 11604: '1.16.4+build.6:v2', 11700: '1.17+build.13:v2', + 11701: '1.17.1+build.29:v2', ][mcVersion] modImplementation 'net.fabricmc:fabric-loader:0.11.6' def fabricApiVersion = [ @@ -256,6 +258,7 @@ dependencies { 11603: '0.17.1+build.394-1.16', 11604: '0.25.1+build.416-1.16', 11700: '0.36.0+1.17', + 11701: '0.37.1+1.17', ][mcVersion] def fabricApiModules = [ "api-base", @@ -326,7 +329,7 @@ dependencies { shadow 'com.github.ReplayMod.JavaBlend:2.79.0:a0696f8' - shadow "com.github.ReplayMod:ReplayStudio:0e72e36", shadeExclusions + shadow "com.github.ReplayMod:ReplayStudio:a67fb11", shadeExclusions implementation(jGui){ transitive = false // FG 1.2 puts all MC deps into the compile configuration and we don't want to shade those diff --git a/jGui b/jGui index 9b5e0192..943ddc84 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 9b5e0192ab2cb90f200005ab53f9e1a85ce29393 +Subproject commit 943ddc84bc2657990ac5eb1500270464194ddcdf diff --git a/root.gradle.kts b/root.gradle.kts index d72ef4f5..de90b92f 100755 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -176,6 +176,7 @@ val doRelease by tasks.registering { defaultTasks("bundleJar") preprocess { + val mc11701 = createNode("1.17.1", 11701, "yarn") val mc11700 = createNode("1.17", 11700, "yarn") val mc11604 = createNode("1.16.4", 11604, "yarn") val mc11601 = createNode("1.16.1", 11601, "yarn") @@ -193,6 +194,7 @@ preprocess { val mc10800 = createNode("1.8", 10800, "srg") val mc10710 = createNode("1.7.10", 10710, "srg") + mc11701.link(mc11700) mc11700.link(mc11604, file("versions/mapping-fabric-1.17-1.16.4.txt")) mc11604.link(mc11601) mc11601.link(mc11502) diff --git a/settings.gradle.kts b/settings.gradle.kts index 8ef8c7df..02c25403 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -30,6 +30,7 @@ val jGuiVersions = listOf( "1.16.1", "1.16.4", "1.17", + "1.17.1", ) val replayModVersions = listOf( // "1.7.10", @@ -48,6 +49,7 @@ val replayModVersions = listOf( "1.16.1", "1.16.4", "1.17", + "1.17.1", ) rootProject.buildFileName = "root.gradle.kts" diff --git a/src/main/java/com/replaymod/render/blend/Util.java b/src/main/java/com/replaymod/render/blend/Util.java index d47092e7..c43e695a 100644 --- a/src/main/java/com/replaymod/render/blend/Util.java +++ b/src/main/java/com/replaymod/render/blend/Util.java @@ -39,7 +39,7 @@ public class Util { } } - private static FloatBuffer floatBuffer = GlAllocationUtils.allocateFloatBuffer(16); + private static FloatBuffer floatBuffer = GlAllocationUtils.allocateByteBuffer(16 * 4).asFloatBuffer(); public static Matrix4f getGlMatrix(int matrix) { floatBuffer.clear(); //#if MC>=11400 diff --git a/src/main/java/com/replaymod/replay/NoGuiScreenshot.java b/src/main/java/com/replaymod/replay/NoGuiScreenshot.java index 0cd7ed44..a3cd6d56 100644 --- a/src/main/java/com/replaymod/replay/NoGuiScreenshot.java +++ b/src/main/java/com/replaymod/replay/NoGuiScreenshot.java @@ -103,7 +103,12 @@ public class NoGuiScreenshot { // Read it, create the screenshot and finish the future try { //#if MC>=11400 - Image image = new Image(ScreenshotUtils.takeScreenshot(frameWidth, frameHeight, mc.getFramebuffer())); + Image image = new Image(ScreenshotUtils.takeScreenshot( + //#if MC<11701 + frameWidth, frameHeight, + //#endif + mc.getFramebuffer() + )); //#else //$$ // We're using Minecraft's ScreenShotHelper even though it writes the screenshot to //$$ // disk for better maintainability From 2f4360a2a19c3fbb8e43e67cf61cebb3f1ef75a6 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 24 Jul 2021 11:22:34 +0200 Subject: [PATCH 090/102] Fix Mixin_PreserveDepthDuringGuiRendering for 1.14-16 --- .../render/mixin/Mixin_PreserveDepthDuringGuiRendering.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_PreserveDepthDuringGuiRendering.java b/src/main/java/com/replaymod/render/mixin/Mixin_PreserveDepthDuringGuiRendering.java index 0e9ab2c0..4e380f62 100644 --- a/src/main/java/com/replaymod/render/mixin/Mixin_PreserveDepthDuringGuiRendering.java +++ b/src/main/java/com/replaymod/render/mixin/Mixin_PreserveDepthDuringGuiRendering.java @@ -10,7 +10,7 @@ import org.spongepowered.asm.mixin.injection.ModifyArg; @Mixin(GameRenderer.class) public abstract class Mixin_PreserveDepthDuringGuiRendering { @ModifyArg( - //#if MC>=11700 + //#if MC>=11400 method = "render", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;clear(IZ)V"), index = 0 //#else From 3f4dae05dbe25500b7346f9cb953d47ebf955f4f Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 24 Jul 2021 11:30:34 +0200 Subject: [PATCH 091/102] Fix missing preprocessor comments --- .../java/com/replaymod/core/versions/Patterns.java | 12 ++++++------ .../simplepathing/preview/PathPreviewRenderer.java | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/replaymod/core/versions/Patterns.java b/src/main/java/com/replaymod/core/versions/Patterns.java index c7e1371d..2de3d7b5 100644 --- a/src/main/java/com/replaymod/core/versions/Patterns.java +++ b/src/main/java/com/replaymod/core/versions/Patterns.java @@ -347,12 +347,12 @@ class Patterns { //#endif } //#else - @Pattern private static void BufferBuilder_beginPosCol() {} - @Pattern private static void BufferBuilder_addPosCol() {} - @Pattern private static void BufferBuilder_beginPosTex() {} - @Pattern private static void BufferBuilder_addPosTex() {} - @Pattern private static void BufferBuilder_beginPosTexCol() {} - @Pattern private static void BufferBuilder_addPosTexCol() {} + //$$ @Pattern private static void BufferBuilder_beginPosCol() {} + //$$ @Pattern private static void BufferBuilder_addPosCol() {} + //$$ @Pattern private static void BufferBuilder_beginPosTex() {} + //$$ @Pattern private static void BufferBuilder_addPosTex() {} + //$$ @Pattern private static void BufferBuilder_beginPosTexCol() {} + //$$ @Pattern private static void BufferBuilder_addPosTexCol() {} //#endif @Pattern diff --git a/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java b/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java index d682b92a..50782934 100644 --- a/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java +++ b/src/main/java/com/replaymod/simplepathing/preview/PathPreviewRenderer.java @@ -204,7 +204,7 @@ public class PathPreviewRenderer extends EventRegistrations { } finally { popMatrix(); //#if MC>=11700 - GL11.glDisable(GL11.GL_BLEND); + //$$ GL11.glDisable(GL11.GL_BLEND); //#else GL11.glPopAttrib(); //#endif From 83cb459957559bd67383b2494f005d6d8f41a61b Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 24 Jul 2021 11:54:14 +0200 Subject: [PATCH 092/102] Fix keyframes being required to open render queue window Half the reason we swapped the render queue / settings parent relationship was so we don't need to go through the settings screen to access the queue. But for some reason I stopped half way through and didn't also move the "You need at last two keyframes." popup. This commit rectifies that. --- .../java/com/replaymod/core/utils/Result.java | 142 ++++++++++++++++++ .../replaymod/render/gui/GuiRenderQueue.java | 22 ++- .../simplepathing/gui/GuiPathing.java | 37 ++--- 3 files changed, 171 insertions(+), 30 deletions(-) create mode 100644 src/main/java/com/replaymod/core/utils/Result.java diff --git a/src/main/java/com/replaymod/core/utils/Result.java b/src/main/java/com/replaymod/core/utils/Result.java new file mode 100644 index 00000000..d2c70c2f --- /dev/null +++ b/src/main/java/com/replaymod/core/utils/Result.java @@ -0,0 +1,142 @@ +package com.replaymod.core.utils; + +import java.util.function.Consumer; +import java.util.function.Function; + +public abstract class Result { + + public static OkImpl ok(Ok value) { + return new OkImpl<>(value); + } + + public static ErrImpl err(Err value) { + return new ErrImpl<>(value); + } + + public abstract boolean isOk(); + public abstract boolean isErr(); + public abstract Ok okOrNull(); + public abstract Err errOrNull(); + public abstract void ifOk(Consumer consumer); + public abstract void ifErr(Consumer consumer); + public abstract Ok okOrElse(Function orElse); + public abstract Err errOrElse(Function orElse); + public abstract Result mapOk(Function func); + public abstract Result mapErr(Function func); + + private static class OkImpl extends Result { + private final Ok value; + + public OkImpl(Ok value) { + this.value = value; + } + + @Override + public boolean isOk() { + return true; + } + + @Override + public boolean isErr() { + return false; + } + + @Override + public Ok okOrNull() { + return this.value; + } + + @Override + public Err errOrNull() { + return null; + } + + @Override + public void ifOk(Consumer consumer) { + consumer.accept(this.value); + } + + @Override + public void ifErr(Consumer consumer) { + } + + @Override + public Ok okOrElse(Function orElse) { + return this.value; + } + + @Override + public Err errOrElse(Function orElse) { + return orElse.apply(this.value); + } + + @Override + public Result mapOk(Function func) { + return ok(func.apply(this.value)); + } + + @SuppressWarnings("unchecked") + @Override + public Result mapErr(Function func) { + return (Result) this; + } + } + + private static class ErrImpl extends Result { + private final Err value; + + public ErrImpl(Err value) { + this.value = value; + } + + @Override + public boolean isOk() { + return false; + } + + @Override + public boolean isErr() { + return true; + } + + @Override + public Ok okOrNull() { + return null; + } + + @Override + public Err errOrNull() { + return this.value; + } + + @Override + public void ifOk(Consumer consumer) { + } + + @Override + public void ifErr(Consumer consumer) { + consumer.accept(this.value); + } + + @Override + public Ok okOrElse(Function orElse) { + return orElse.apply(this.value); + } + + @Override + public Err errOrElse(Function orElse) { + return this.value; + } + + @SuppressWarnings("unchecked") + @Override + public Result mapOk(Function func) { + return (Result) this; + } + + @Override + public Result mapErr(Function func) { + return err(func.apply(this.value)); + } + } +} diff --git a/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java b/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java index 8e9d92ea..a019b565 100644 --- a/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java +++ b/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java @@ -2,6 +2,7 @@ package com.replaymod.render.gui; import com.google.common.collect.Iterables; import com.replaymod.core.ReplayMod; +import com.replaymod.core.utils.Result; import com.replaymod.core.utils.Utils; import com.replaymod.core.versions.MCVer; import com.replaymod.render.RenderSettings; @@ -30,6 +31,7 @@ import de.johni0702.minecraft.gui.layout.CustomLayout; import de.johni0702.minecraft.gui.layout.GridLayout; import de.johni0702.minecraft.gui.layout.HorizontalLayout; import de.johni0702.minecraft.gui.popup.AbstractGuiPopup; +import de.johni0702.minecraft.gui.popup.GuiInfoPopup; import de.johni0702.minecraft.gui.utils.Colors; import de.johni0702.minecraft.gui.utils.lwjgl.Dimension; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; @@ -88,7 +90,7 @@ public class GuiRenderQueue extends AbstractGuiPopup implements private final AbstractGuiScreen container; private final ReplayHandler replayHandler; private final Set selectedEntries = new HashSet<>(); - private final Supplier timelineSupplier; + private final Supplier> timelineSupplier; private boolean opened; { @@ -113,7 +115,7 @@ public class GuiRenderQueue extends AbstractGuiPopup implements private final ReplayModRender mod = ReplayModRender.instance; private final List jobs = mod.getRenderQueue(); - public GuiRenderQueue(AbstractGuiScreen container, ReplayHandler replayHandler, Supplier timelineSupplier) { + public GuiRenderQueue(AbstractGuiScreen container, ReplayHandler replayHandler, Supplier> timelineSupplier) { super(container); this.container = container; this.replayHandler = replayHandler; @@ -127,7 +129,7 @@ public class GuiRenderQueue extends AbstractGuiPopup implements list.getListPanel().addElements(null, new Entry(renderJob)); } - addButton.onClick(this::addButtonClicked); + addButton.onClick(() -> addButtonClicked().ifErr(lines -> GuiInfoPopup.open(container, lines))); editButton.onClick(() -> { Entry job = selectedEntries.iterator().next(); @@ -267,15 +269,12 @@ public class GuiRenderQueue extends AbstractGuiPopup implements }); } - private GuiRenderSettings addButtonClicked() { - Timeline timeline = timelineSupplier.get(); - if (timeline != null) { + private Result addButtonClicked() { + return timelineSupplier.get().mapOk(timeline -> { GuiRenderSettings popup = addJob(timeline); popup.open(); return popup; - } else { - return null; - } + }); } public GuiRenderSettings addJob(Timeline timeline) { @@ -317,9 +316,8 @@ public class GuiRenderQueue extends AbstractGuiPopup implements @Override public void open() { if (jobs.isEmpty() && timelineSupplier != null) { - if (addButtonClicked() == null) { - close(); - } + addButtonClicked().ifErr(lines -> + GuiInfoPopup.open(container, lines).onClosed(this::close)); return; } diff --git a/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java b/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java index cdce5a51..8df8f8f2 100644 --- a/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java +++ b/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java @@ -6,6 +6,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import com.replaymod.core.ReplayMod; +import com.replaymod.core.utils.Result; import com.replaymod.core.utils.Utils; import com.replaymod.pathing.gui.GuiKeyframeRepository; import com.replaymod.pathing.player.RealtimeTimelinePlayer; @@ -101,8 +102,6 @@ public class GuiPathing { public final GuiButton renderButton = new GuiButton().onClick(new Runnable() { @Override public void run() { - Timeline timeline = preparePathsForPlayback(false); - if (timeline == null) return; GuiScreen screen = GuiRenderSettings.createBaseScreen(); new GuiRenderQueue(screen, replayHandler, () -> preparePathsForPlayback(false)) { @Override @@ -263,7 +262,10 @@ public class GuiPathing { } else { boolean ignoreTimeKeyframes = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT); - Timeline timeline = preparePathsForPlayback(ignoreTimeKeyframes); + Timeline timeline = preparePathsForPlayback(ignoreTimeKeyframes).okOrElse(err -> { + GuiInfoPopup.open(overlay, err); + return null; + }); if (timeline == null) return; Path timePath = new SPTimeline(timeline).getTimePath(); @@ -497,11 +499,12 @@ public class GuiPathing { }).start(); } - private Timeline preparePathsForPlayback(boolean ignoreTimeKeyframes) { + private Result preparePathsForPlayback(boolean ignoreTimeKeyframes) { SPTimeline spTimeline = mod.getCurrentTimeline(); - if (!validatePathsForPlayback(spTimeline, ignoreTimeKeyframes)) { - return null; + String[] errors = validatePathsForPlayback(spTimeline, ignoreTimeKeyframes); + if (errors != null) { + return Result.err(errors); } try { @@ -509,24 +512,23 @@ public class GuiPathing { String serialized = serialization.serialize(Collections.singletonMap("", spTimeline.getTimeline())); Timeline timeline = serialization.deserialize(serialized).get(""); timeline.getPaths().forEach(Path::updateAll); - return timeline; + return Result.ok(timeline); } catch (Throwable t) { error(LOGGER, replayHandler.getOverlay(), CrashReport.create(t, "Cloning timeline"), () -> {}); - return null; + return Result.err(null); } } - private boolean validatePathsForPlayback(SPTimeline timeline, boolean ignoreTimeKeyframes) { + private String[] validatePathsForPlayback(SPTimeline timeline, boolean ignoreTimeKeyframes) { 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; + return new String[]{ "replaymod.chat.morekeyframes" }; } if (ignoreTimeKeyframes) { - return true; + return null; } // Make sure time keyframes's values are monotonically increasing @@ -535,22 +537,21 @@ public class GuiPathing { int time = keyframe.getValue(TimestampProperty.PROPERTY).orElseThrow(IllegalStateException::new); if (time < lastTime) { // We are going backwards in time - GuiInfoPopup.open(replayHandler.getOverlay(), + return new String[]{ "replaymod.error.negativetime1", "replaymod.error.negativetime2", - "replaymod.error.negativetime3"); - return false; + "replaymod.error.negativetime3" + }; } lastTime = time; } // Make sure there are at least two time keyframes if (timeline.getTimePath().getSegments().isEmpty()) { - GuiInfoPopup.open(replayHandler.getOverlay(), "replaymod.chat.morekeyframes"); - return false; + return new String[]{ "replaymod.chat.morekeyframes" }; } - return true; + return null; } public void zoomTimeline(double factor) { From 2891c4e8fa9b65a2a788113b236924d77b908434 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 24 Jul 2021 12:59:06 +0200 Subject: [PATCH 093/102] Remove MP4 Default Quality preset (closes #475) Similar to High Quality, it is too unpredictable, sometimes giving bad quality and sometimes being unbearably slow. We should just encourage everyone to set their bitrate manually. --- .../java/com/replaymod/render/RenderSettings.java | 2 -- .../com/replaymod/render/gui/GuiRenderSettings.java | 11 ++++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/replaymod/render/RenderSettings.java b/src/main/java/com/replaymod/render/RenderSettings.java index 0eea5951..d350f5e6 100644 --- a/src/main/java/com/replaymod/render/RenderSettings.java +++ b/src/main/java/com/replaymod/render/RenderSettings.java @@ -62,8 +62,6 @@ public class RenderSettings { public enum EncodingPreset { MP4_CUSTOM("-an -c:v libx264 -b:v %BITRATE% -pix_fmt yuv420p \"%FILENAME%\"", "mp4"), - MP4_DEFAULT("-an -c:v libx264 -preset ultrafast -pix_fmt yuv420p \"%FILENAME%\"", "mp4"), - MP4_POTATO("-an -c:v libx264 -preset ultrafast -crf 51 -pix_fmt yuv420p \"%FILENAME%\"", "mp4"), WEBM_CUSTOM("-an -c:v libvpx -b:v %BITRATE% -pix_fmt yuv420p \"%FILENAME%\"", "webm"), diff --git a/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java b/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java index 1d8b9c9a..2073a6f2 100644 --- a/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java +++ b/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java @@ -70,7 +70,7 @@ public class GuiRenderSettings extends AbstractGuiPopup { if (renderMethodDropdown.getSelectedValue() == RenderSettings.RenderMethod.BLEND) { encodingPresetDropdown.setSelected(RenderSettings.EncodingPreset.BLEND); } else { - encodingPresetDropdown.setSelected(RenderSettings.EncodingPreset.MP4_DEFAULT); + encodingPresetDropdown.setSelected(RenderSettings.EncodingPreset.MP4_CUSTOM); } } updateInputs(); @@ -506,7 +506,8 @@ public class GuiRenderSettings extends AbstractGuiPopup { } RenderSettings.EncodingPreset encodingPreset = settings.getEncodingPreset(); /* encodingPreset can be null from a previously supported and later removed preset */ - if (encodingPreset == null || !encodingPreset.isSupported()) { + boolean invalidEncodingPreset = encodingPreset == null || !encodingPreset.isSupported(); + if (invalidEncodingPreset) { encodingPreset = getDefaultRenderSettings().getEncodingPreset(); } encodingPresetDropdown.setSelected(encodingPreset); @@ -555,7 +556,7 @@ public class GuiRenderSettings extends AbstractGuiPopup { antiAliasingDropdown.setSelected(settings.getAntiAliasing()); exportCommand.setText(settings.getExportCommand()); String exportArguments = settings.getExportArguments(); - if (exportArguments == null || settings.getEncodingPreset() == null) { + if (exportArguments == null || settings.getEncodingPreset() == null || invalidEncodingPreset) { // backwards compat, see RenderSettings#exportArguments exportArguments = encodingPreset.getValue(); } @@ -628,8 +629,8 @@ public class GuiRenderSettings extends AbstractGuiPopup { } private RenderSettings getDefaultRenderSettings() { - return new RenderSettings(RenderSettings.RenderMethod.DEFAULT, RenderSettings.EncodingPreset.MP4_DEFAULT, 1920, 1080, 60, 10 << 20, null, - true, false, false, false, null, 360, 180, false, false, false, RenderSettings.AntiAliasing.NONE, "", RenderSettings.EncodingPreset.MP4_DEFAULT.getValue(), false); + return new RenderSettings(RenderSettings.RenderMethod.DEFAULT, RenderSettings.EncodingPreset.MP4_CUSTOM, 1920, 1080, 60, 10 << 20, null, + true, false, false, false, null, 360, 180, false, false, false, RenderSettings.AntiAliasing.NONE, "", RenderSettings.EncodingPreset.MP4_CUSTOM.getValue(), false); } @Override From 4090e7b540aae4abfd617e6fff5a65c58a59f942 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 24 Jul 2021 13:14:23 +0200 Subject: [PATCH 094/102] Search for homebrew in /opt as well (fixes #496) --- src/main/java/com/replaymod/render/RenderSettings.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/replaymod/render/RenderSettings.java b/src/main/java/com/replaymod/render/RenderSettings.java index d350f5e6..28558f3c 100644 --- a/src/main/java/com/replaymod/render/RenderSettings.java +++ b/src/main/java/com/replaymod/render/RenderSettings.java @@ -334,9 +334,13 @@ public class RenderSettings { } } // Homebrew doesn't seem to reliably symlink its installed binaries either - File homebrewFolder = new File("/usr/local/Cellar/ffmpeg"); - String[] homebrewVersions = homebrewFolder.list(); - if (homebrewVersions != null) { + // and there's multiple locations for where Homebrew is. + for (String path : new String[]{"/usr/local", "/opt/homebrew"}) { + File homebrewFolder = new File(path + "/Cellar/ffmpeg"); + String[] homebrewVersions = homebrewFolder.list(); + if (homebrewVersions == null) { + continue; + } Optional latestOpt = Arrays.stream(homebrewVersions) .map(ComparableVersion::new) // Convert file name to comparable version .sorted(Comparator.reverseOrder()) // Sort for latest version From 3ef355a2678b447476a429ad6848e2b76fa246fd Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 24 Jul 2021 13:16:24 +0200 Subject: [PATCH 095/102] Failure to hide cache folder should never be fatal (closes #512) --- src/main/java/com/replaymod/core/ReplayMod.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/replaymod/core/ReplayMod.java b/src/main/java/com/replaymod/core/ReplayMod.java index 3fe653d9..8176cadc 100644 --- a/src/main/java/com/replaymod/core/ReplayMod.java +++ b/src/main/java/com/replaymod/core/ReplayMod.java @@ -147,6 +147,8 @@ public class ReplayMod implements Module, Scheduler { try { Files.setAttribute(path, "dos:hidden", true); } catch (UnsupportedOperationException ignored) { + } catch (Exception e) { + e.printStackTrace(); } return path; } From 35fef5176d81e917526a9c28718bb91a1aa1a291 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 24 Jul 2021 14:41:41 +0200 Subject: [PATCH 096/102] Fix skins of server-only NPCs being unreliable (fixes #486) --- .../replay/mixin/Mixin_FixNPCSkinCaching.java | 31 +++++++++++++++++++ .../resources/mixins.replay.replaymod.json | 1 + 2 files changed, 32 insertions(+) create mode 100644 src/main/java/com/replaymod/replay/mixin/Mixin_FixNPCSkinCaching.java diff --git a/src/main/java/com/replaymod/replay/mixin/Mixin_FixNPCSkinCaching.java b/src/main/java/com/replaymod/replay/mixin/Mixin_FixNPCSkinCaching.java new file mode 100644 index 00000000..925c2b0e --- /dev/null +++ b/src/main/java/com/replaymod/replay/mixin/Mixin_FixNPCSkinCaching.java @@ -0,0 +1,31 @@ +package com.replaymod.replay.mixin; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.AbstractClientPlayerEntity; +import net.minecraft.client.network.PlayerListEntry; +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; + +import javax.annotation.Nullable; + +@Mixin(AbstractClientPlayerEntity.class) +public abstract class Mixin_FixNPCSkinCaching { + @Shadow @Nullable protected abstract PlayerListEntry getPlayerListEntry(); + + @Inject(method = "", at = @At("RETURN")) + private void forceCachePlayerListEntry(CallbackInfo ci) { + // Server-side NPCs (without a client mod) rely on the player list entry being cached in this class to function + // because the remove the entry shortly after spawning the player. However this method is only called when the + // player is rendered, and if we are currently jumping around in a replay then it most likely will not be + // rendered while the entry is still there. The result is that most NPCs get Steve/Alex skins instead of the + // intended ones. To fix that, we make this caching-glitch which servers have come to rely on an actual feature + // by just fetching the cache in the constructor which arguably is what MC should have done to begin with, + // especially because the spawn packet handling code already requires the entry to be present). + if (MinecraftClient.getInstance().getNetworkHandler() != null) { // will be null if this is the client player + this.getPlayerListEntry(); + } + } +} diff --git a/src/main/resources/mixins.replay.replaymod.json b/src/main/resources/mixins.replay.replaymod.json index ff2737f1..feb30fa7 100644 --- a/src/main/resources/mixins.replay.replaymod.json +++ b/src/main/resources/mixins.replay.replaymod.json @@ -5,6 +5,7 @@ "mixins": [], "server": [], "client": [ + "Mixin_FixNPCSkinCaching", //#if MC>=11600 "Mixin_MoveRealmsButton", //#endif From 0cb14a91065e46b30eb7a1f713ec36c553a76f55 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 24 Jul 2021 17:06:46 +0200 Subject: [PATCH 097/102] Re-introduce entity-in-wrong-chunk-at-unload workaround (fixes #548) Nope, this was not fixed, they just changed where the chunkCoords are stored but the interpolation issue remains. --- .../com/replaymod/replay/FullReplaySender.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/replaymod/replay/FullReplaySender.java b/src/main/java/com/replaymod/replay/FullReplaySender.java index 03ef31a9..c4cc978e 100644 --- a/src/main/java/com/replaymod/replay/FullReplaySender.java +++ b/src/main/java/com/replaymod/replay/FullReplaySender.java @@ -1163,9 +1163,6 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend // 1.14+: The update issue remains but only for non-players and the unloading list bug appears to have been // fixed (chunk unloading no longer removes the entities). // Get the chunk that will be unloaded - //#if MC>=11700 - //$$ // From the looks of it, this may be fixed now (thanks to EntityChangeListener), guess we'll see - //#else //#if MC>=11400 ClientWorld world = mc.world; ChunkManager chunkProvider = world.getChunkManager(); @@ -1183,9 +1180,17 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend //#endif List entitiesInChunk = new ArrayList<>(); // Gather all entities in that chunk + //#if MC>=11700 + //$$ for (Entity entity : mc.world.getEntities()) { + //$$ if (entity.getChunkPos().equals(chunk.getPos())) { + //$$ entitiesInChunk.add(entity); + //$$ } + //$$ } + //#else for (Collection entityList : chunk.getEntitySectionArray()) { entitiesInChunk.addAll(entityList); } + //#endif for (Entity entity : entitiesInChunk) { // Skip interpolation of position updates coming from server // (See: newX in EntityLivingBase or otherPlayerMPX in EntityOtherPlayerMP) @@ -1200,7 +1205,9 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend } // Check whether the entity has left the chunk - //#if MC>=11404 + //#if MC>=11700 + //$$ // This is now handled automatically in Entity.setPos (called from tick()) + //#elseif MC>=11404 int chunkX = MathHelper.floor(entity.getX() / 16); int chunkY = MathHelper.floor(entity.getY() / 16); int chunkZ = MathHelper.floor(entity.getZ() / 16); @@ -1262,7 +1269,6 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend //#endif } } - //#endif } return p; // During synchronous playback everything is sent normally } From 5bede327f31775abd08700076ec15325b2052a7b Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 24 Jul 2021 17:09:16 +0200 Subject: [PATCH 098/102] Update jGui (fixes textures with Sodium) --- jGui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jGui b/jGui index 943ddc84..71d36174 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 943ddc84bc2657990ac5eb1500270464194ddcdf +Subproject commit 71d361746ef7d3b9b2bd9a8029296a895498ad39 From e9bf75b4d6af77de4c43082673ba261bb0951ca4 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 24 Jul 2021 19:15:08 +0200 Subject: [PATCH 099/102] Remove ModCore That was never actually finished and we do not need to keep it around anymore. Whether we add its successor once that is ready for production use remains to be seen. --- .../replaymod/core/ReplayModMMLauncher.java | 43 -- .../extras/modcore/ModCoreInstaller.java | 485 ------------------ .../core/tweaker/ReplayModTweaker.java | 33 -- 3 files changed, 561 deletions(-) delete mode 100644 src/main/java/com/replaymod/extras/modcore/ModCoreInstaller.java diff --git a/src/main/java/com/replaymod/core/ReplayModMMLauncher.java b/src/main/java/com/replaymod/core/ReplayModMMLauncher.java index e8de4c90..782d0fde 100644 --- a/src/main/java/com/replaymod/core/ReplayModMMLauncher.java +++ b/src/main/java/com/replaymod/core/ReplayModMMLauncher.java @@ -1,14 +1,8 @@ //#if FABRIC>=1 package com.replaymod.core; -import com.replaymod.extras.modcore.ModCoreInstaller; -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.ModContainer; import org.spongepowered.asm.mixin.Mixins; -import java.io.File; -import java.util.Optional; - // We need to wait for MM to call us, otherwise we might initialize our mixins before it calls optifabric which would // result in OF classes not existing while our mixins get resolved. public class ReplayModMMLauncher implements Runnable { @@ -32,43 +26,6 @@ public class ReplayModMMLauncher implements Runnable { Mixins.addConfiguration("mixins.render.blend.replaymod.json"); Mixins.addConfiguration("mixins.render.replaymod.json"); Mixins.addConfiguration("mixins.replay.replaymod.json"); - - try { - initModCore(); - } catch (Throwable t) { - System.err.println("ReplayMod caught error during ModCore init:"); - t.printStackTrace(); - } - } - - // Forge equivalent is in ReplayModTweaker - private void initModCore() { - if (System.getProperty("REPLAYMOD_SKIP_MODCORE", "false").equalsIgnoreCase("true")) { - System.out.println("ReplayMod not initializing ModCore because REPLAYMOD_SKIP_MODCORE is true."); - return; - } - - if (FabricLoader.getInstance().isDevelopmentEnvironment()) { - System.out.println("ReplayMod not initializing ModCore because we're in a development environment."); - return; - } - - File gameDir = FabricLoader.getInstance().getGameDirectory(); - - Optional minecraft = FabricLoader.getInstance().getModContainer("minecraft"); - if (!minecraft.isPresent()) { - System.err.println("ReplayMod could not determine Minecraft version, skipping ModCore."); - return; - } - String mcVer = minecraft.get().getMetadata().getVersion().getFriendlyString(); - - int result = ModCoreInstaller.initialize(gameDir, mcVer + "_fabric"); - if (result != -2) { // Don't even bother logging the result if there's no ModCore for this version. - System.out.println("ReplayMod ModCore init result: " + result); - } - if (ModCoreInstaller.isErrored()) { - System.err.println(ModCoreInstaller.getError()); - } } } //#endif diff --git a/src/main/java/com/replaymod/extras/modcore/ModCoreInstaller.java b/src/main/java/com/replaymod/extras/modcore/ModCoreInstaller.java deleted file mode 100644 index 40615608..00000000 --- a/src/main/java/com/replaymod/extras/modcore/ModCoreInstaller.java +++ /dev/null @@ -1,485 +0,0 @@ -/* Based on https://github.com/Sk1erLLC/ModCore-Example-Mod/blob/4a362fa1c67cee28bdfc82bd5a99a30896b081fb/src/main/java/club/sk1er/mods/modcoreexample/ModCoreInstaller.java - * - * MIT License - * - * Copyright (c) 2020 Sk1er LLC - * Copyright (c) 2020 ModCore Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.replaymod.extras.modcore; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; - -import javax.swing.JFrame; -import javax.swing.JProgressBar; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.GridLayout; -import java.awt.TextArea; -import java.awt.Toolkit; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.List; - -//#if FABRIC>=1 -import net.fabricmc.loader.api.FabricLoader; -//#else -//#if MC>=11400 -//#else -//$$ import net.minecraft.launchwrapper.Launch; -//$$ import java.net.URLClassLoader; -//$$ import java.util.LinkedHashSet; -//#endif -//#endif - -public class ModCoreInstaller { - - private static final String VERSION_URL = "https://api.sk1er.club/modcore_versions"; - private static final String className = "club.sk1er.mods.core.tweaker.ModCoreTweaker"; - private static boolean errored = false; - private static String error; - private static File dataDir = null; - - - private static boolean isInitalized() { - try { - //#if MC<11400 - //$$ LinkedHashSet objects = new LinkedHashSet<>(); - //$$ objects.add(className); - //$$ Launch.classLoader.clearNegativeEntries(objects); - //#endif - return Class.forName(className) != null; - } catch (ClassNotFoundException ignored) { - } - return false; - } - - public static boolean isErrored() { - return errored; - } - - public static String getError() { - return error; - } - - private static void bail(String error) { - errored = true; - ModCoreInstaller.error = error; - } - - private static JsonHolder readFile(File in) { - try { - return new JsonHolder(FileUtils.readFileToString(in)); - } catch (IOException ignored) { - - } - return new JsonHolder(); - } - - private static boolean initializeModCore(File gameDir) { - try { - Class modCore = Class.forName("club.sk1er.mods.core.tweaker.ModCoreTweaker"); - Method initialize = modCore.getMethod("initialize", File.class); - initialize.invoke(null, gameDir); - System.out.println("Loaded ModCore Successfully"); - return true; - } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - } - System.out.println("Did NOT initialize ModCore Successfully"); - return false; - } - - public static int initialize(File gameDir, String minecraftVersion) { - if (isInitalized()) return -1; - JsonHolder jsonHolder = fetchJSON(VERSION_URL); - if (!jsonHolder.has(minecraftVersion)) { - System.out.println("No ModCore target for " + minecraftVersion + ". This in fine, unless you're specifically looking for ModCore."); - return -2; - } - dataDir = new File(gameDir, "modcore"); - if (!dataDir.exists()) { - if (!dataDir.mkdirs()) { - bail("Unable to create necessary files"); - return 1; - } - } - String latestRemote = jsonHolder.optString(minecraftVersion); - boolean failed = jsonHolder.getKeys().size() == 0 || (jsonHolder.has("success") && !jsonHolder.optBoolean("success")); - - File metadataFile = new File(dataDir, "metadata.json"); - JsonHolder localMetadata = readFile(metadataFile); - if (failed) latestRemote = localMetadata.optString(minecraftVersion); - File modcoreFile = new File(dataDir, "Sk1er Modcore-" + latestRemote + " (" + minecraftVersion + ").jar"); - - if (!modcoreFile.exists() || !localMetadata.optString(minecraftVersion).equalsIgnoreCase(latestRemote) && !failed) { - //File does not exist, or is out of date, download it - File old = new File(dataDir, "Sk1er Modcore-" + localMetadata.optString(minecraftVersion) + " (" + minecraftVersion + ").jar"); - if (old.exists()) old.delete(); - - if (!download("https://static.sk1er.club/repo/mods/modcore/" + latestRemote + "/" + minecraftVersion + "/ModCore-" + latestRemote + " (" + minecraftVersion + ").jar", latestRemote, modcoreFile, minecraftVersion, localMetadata)) { - bail("Unable to download"); - return 2; - } - - } - - addToClasspath(modcoreFile); - - if (!isInitalized()) { - bail("Something went wrong and it did not add the jar to the class path. Local file exists? " + modcoreFile.exists()); - return 3; - } - return initializeModCore(gameDir) ? 0 : 4; - - } - - - public static void addToClasspath(File file) { - try { - URL url = file.toURI().toURL(); - ClassLoader classLoader = ModCoreInstaller.class.getClassLoader(); - //#if MC>=11400 - Method method = classLoader.getClass().getDeclaredMethod("addURL", URL.class); - //#else - //$$ Launch.classLoader.addURL(url); - //$$ Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); - //#endif - method.setAccessible(true); - method.invoke(classLoader, url); - } catch (Exception e) { - throw new RuntimeException("Unexpected exception", e); - } - } - - private static boolean download(String url, String version, File file, String mcver, JsonHolder versionData) { - url = url.replace(" ", "%20"); - System.out.println("Downloading ModCore " + " version " + version + " from: " + url); - JFrame frame = new JFrame("ModCore Initializer"); - JProgressBar bar = new JProgressBar(); - TextArea comp = new TextArea("", 1, 1, TextArea.SCROLLBARS_NONE); - frame.getContentPane().add(comp); - frame.getContentPane().add(bar); - GridLayout manager = new GridLayout(); - frame.setLayout(manager); - manager.setColumns(1); - manager.setRows(2); - comp.setText("Downloading Sk1er ModCore Library Version " + version + " for Minecraft " + mcver); - comp.setSize(399, 80); - comp.setEditable(false); - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - - - Dimension preferredSize = new Dimension(400, 225); - bar.setSize(preferredSize); - frame.setSize(preferredSize); - frame.setResizable(false); - bar.setBorderPainted(true); - bar.setMinimum(0); - bar.setStringPainted(true); - frame.setVisible(true); - frame.setLocation(dim.width / 2 - frame.getSize().width / 2, dim.height / 2 - frame.getSize().height / 2); - Font font = bar.getFont(); - bar.setFont(new Font(font.getName(), font.getStyle(), font.getSize() * 4)); - comp.setFont(new Font(font.getName(), font.getStyle(), font.getSize() * 2)); - - try { - - URL u = new URL(url); - HttpURLConnection connection = (HttpURLConnection) u.openConnection(); - connection.setRequestMethod("GET"); - connection.setUseCaches(true); - connection.addRequestProperty("User-Agent", "Mozilla/4.76 (Sk1er Modcore Initializer)"); - connection.setReadTimeout(15000); - connection.setConnectTimeout(15000); - connection.setDoOutput(true); - InputStream is = connection.getInputStream(); - int contentLength = connection.getContentLength(); - FileOutputStream outputStream = new FileOutputStream(file); - byte[] buffer = new byte[1024]; - System.out.println("MAX: " + contentLength); - bar.setMaximum(contentLength); - int read; - bar.setValue(0); - while ((read = is.read(buffer)) > 0) { - outputStream.write(buffer, 0, read); - bar.setValue(bar.getValue() + 1024); - } - outputStream.close(); - FileUtils.write(new File(dataDir, "metadata.json"), versionData.put(mcver, version).toString()); - } catch (Exception e) { - e.printStackTrace(); - frame.dispose(); - return false; - } - frame.dispose(); - return true; - } - - public static final JsonHolder fetchJSON(String url) { - return new JsonHolder(fetchString(url)); - } - - public static final String fetchString(String url) { - url = url.replace(" ", "%20"); - System.out.println("Fetching " + url); - try { - URL u = new URL(url); - HttpURLConnection connection = (HttpURLConnection) u.openConnection(); - connection.setRequestMethod("GET"); - connection.setUseCaches(true); - connection.addRequestProperty("User-Agent", "Mozilla/4.76 (Sk1er ModCore)"); - connection.setReadTimeout(15000); - connection.setConnectTimeout(15000); - connection.setDoOutput(true); - InputStream is = connection.getInputStream(); - return IOUtils.toString(is, Charset.defaultCharset()); - } catch (Exception e) { - e.printStackTrace(); - } - return "Failed to fetch"; - } - - - //Added because we need to use before ModCore is loaded - static class JsonHolder { - private JsonObject object; - - public JsonHolder(JsonObject object) { - this.object = object; - } - - public JsonHolder(String raw) { - if (raw == null) - object = new JsonObject(); - else - try { - this.object = new JsonParser().parse(raw).getAsJsonObject(); - } catch (Exception e) { - this.object = new JsonObject(); - e.printStackTrace(); - } - } - - public JsonHolder() { - this(new JsonObject()); - } - - @Override - public String toString() { - if (object != null) - return object.toString(); - return "{}"; - } - - public JsonHolder put(String key, boolean value) { - object.addProperty(key, value); - return this; - } - - public void mergeNotOverride(JsonHolder merge) { - merge(merge, false); - } - - public void mergeOverride(JsonHolder merge) { - merge(merge, true); - } - - public void merge(JsonHolder merge, boolean override) { - JsonObject object = merge.getObject(); - for (String s : merge.getKeys()) { - if (override || !this.has(s)) - put(s, object.get(s)); - } - } - - private void put(String s, JsonElement element) { - this.object.add(s, element); - } - - public JsonHolder put(String key, String value) { - object.addProperty(key, value); - return this; - } - - public JsonHolder put(String key, int value) { - object.addProperty(key, value); - return this; - } - - public JsonHolder put(String key, double value) { - object.addProperty(key, value); - return this; - } - - public JsonHolder put(String key, long value) { - object.addProperty(key, value); - return this; - } - - private JsonHolder defaultOptJSONObject(String key, JsonObject fallBack) { - try { - return new JsonHolder(object.get(key).getAsJsonObject()); - } catch (Exception e) { - return new JsonHolder(fallBack); - } - } - - public JsonArray defaultOptJSONArray(String key, JsonArray fallback) { - try { - return object.get(key).getAsJsonArray(); - } catch (Exception e) { - return fallback; - } - } - - public JsonArray optJSONArray(String key) { - return defaultOptJSONArray(key, new JsonArray()); - } - - - public boolean has(String key) { - return object.has(key); - } - - public long optLong(String key, long fallback) { - try { - return object.get(key).getAsLong(); - } catch (Exception e) { - return fallback; - } - } - - public long optLong(String key) { - return optLong(key, 0); - } - - public boolean optBoolean(String key, boolean fallback) { - try { - return object.get(key).getAsBoolean(); - } catch (Exception e) { - return fallback; - } - } - - public boolean optBoolean(String key) { - return optBoolean(key, false); - } - - public JsonObject optActualJSONObject(String key) { - try { - return object.get(key).getAsJsonObject(); - } catch (Exception e) { - return new JsonObject(); - } - } - - public JsonHolder optJSONObject(String key) { - return defaultOptJSONObject(key, new JsonObject()); - } - - - public int optInt(String key, int fallBack) { - try { - return object.get(key).getAsInt(); - } catch (Exception e) { - return fallBack; - } - } - - public int optInt(String key) { - return optInt(key, 0); - } - - - public String defaultOptString(String key, String fallBack) { - try { - return object.get(key).getAsString(); - } catch (Exception e) { - return fallBack; - } - } - - public String optString(String key) { - return defaultOptString(key, ""); - } - - - public double optDouble(String key, double fallBack) { - try { - return object.get(key).getAsDouble(); - } catch (Exception e) { - return fallBack; - } - } - - public List getKeys() { - List tmp = new ArrayList<>(); - object.entrySet().forEach(e -> tmp.add(e.getKey())); - return tmp; - } - - public double optDouble(String key) { - return optDouble(key, 0.0); - } - - - public JsonObject getObject() { - return object; - } - - public boolean isNull(String key) { - return object.has(key) && object.get(key).isJsonNull(); - } - - public JsonHolder put(String values, JsonHolder values1) { - return put(values, values1.getObject()); - } - - public JsonHolder put(String values, JsonObject object) { - this.object.add(values, object); - return this; - } - - public void put(String blacklisted, JsonArray jsonElements) { - this.object.add(blacklisted, jsonElements); - } - - public void remove(String header) { - object.remove(header); - } - } - - -} - diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/tweaker/ReplayModTweaker.java b/versions/1.12.2/src/main/java/com/replaymod/core/tweaker/ReplayModTweaker.java index b6205d1c..dc20dd20 100644 --- a/versions/1.12.2/src/main/java/com/replaymod/core/tweaker/ReplayModTweaker.java +++ b/versions/1.12.2/src/main/java/com/replaymod/core/tweaker/ReplayModTweaker.java @@ -1,6 +1,5 @@ package com.replaymod.core.tweaker; -import com.replaymod.extras.modcore.ModCoreInstaller; import net.minecraft.launchwrapper.ITweaker; import net.minecraft.launchwrapper.Launch; import net.minecraft.launchwrapper.LaunchClassLoader; @@ -74,13 +73,6 @@ public class ReplayModTweaker implements ITweaker { //#else //$$ platform.addContainer(uri); //#endif - - //#if MC>=11202 && MC<=11202 - initModCore("1.12.2"); - //#endif - //#if MC>=10809 && MC<=10809 - //$$ initModCore("1.8.9"); - //#endif } @Override @@ -92,29 +84,4 @@ public class ReplayModTweaker implements ITweaker { public String[] getLaunchArguments() { return new String[0]; } - - private void initModCore(String mcVer) { - try { - if (System.getProperty("REPLAYMOD_SKIP_MODCORE", "false").equalsIgnoreCase("true")) { - System.out.println("ReplayMod not initializing ModCore because REPLAYMOD_SKIP_MODCORE is true."); - return; - } - - if ((Boolean) Launch.blackboard.get("fml.deobfuscatedEnvironment")) { - System.out.println("ReplayMod not initializing ModCore because we're in a development environment."); - return; - } - - int result = ModCoreInstaller.initialize(Launch.minecraftHome, mcVer + "_forge"); - if (result != -2) { // Don't even bother logging the result if there's no ModCore for this version. - System.out.println("ReplayMod ModCore init result: " + result); - } - if (ModCoreInstaller.isErrored()) { - System.err.println(ModCoreInstaller.getError()); - } - } catch (Throwable t) { - System.err.println("ReplayMod caught error during ModCore init:"); - t.printStackTrace(); - } - } } From 3cba99068e2d1c6699d528c3a0be20215c7d85b6 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 31 Jul 2021 14:37:10 +0200 Subject: [PATCH 100/102] Increase default bitrate to from 10 to 20mbps --- src/main/java/com/replaymod/render/gui/GuiRenderSettings.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java b/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java index 2073a6f2..0a1fbdcd 100644 --- a/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java +++ b/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java @@ -629,7 +629,7 @@ public class GuiRenderSettings extends AbstractGuiPopup { } private RenderSettings getDefaultRenderSettings() { - return new RenderSettings(RenderSettings.RenderMethod.DEFAULT, RenderSettings.EncodingPreset.MP4_CUSTOM, 1920, 1080, 60, 10 << 20, null, + return new RenderSettings(RenderSettings.RenderMethod.DEFAULT, RenderSettings.EncodingPreset.MP4_CUSTOM, 1920, 1080, 60, 20 << 20, null, true, false, false, false, null, 360, 180, false, false, false, RenderSettings.AntiAliasing.NONE, "", RenderSettings.EncodingPreset.MP4_CUSTOM.getValue(), false); } From a457bccf12000b6bea872380b0b78617236b58e9 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 31 Jul 2021 15:13:15 +0200 Subject: [PATCH 101/102] Fix Java 9+ ABI being used for Java 8 versions --- build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle b/build.gradle index a59dedb6..c7085f95 100644 --- a/build.gradle +++ b/build.gradle @@ -109,6 +109,9 @@ preprocess { def mcVersionStr = "${(int)(mcVersion/10000)}.${(int)(mcVersion/100)%100}" + (mcVersion%100==0 ? '' : ".${mcVersion%100}") sourceCompatibility = targetCompatibility = mcVersion >= 11700 ? 16 : 1.8 +tasks.withType(JavaCompile).configureEach { + options.release = mcVersion >= 11700 ? 16 : 8 +} if (mcVersion >= 11400) { sourceSets { From c88b4c1e76a23814ff536c8e1c7a46500e69ccb0 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 31 Jul 2021 16:01:11 +0200 Subject: [PATCH 102/102] Add missing .gitkeep files --- versions/1.17.1/.gitkeep | 0 versions/1.17/.gitkeep | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 versions/1.17.1/.gitkeep create mode 100644 versions/1.17/.gitkeep diff --git a/versions/1.17.1/.gitkeep b/versions/1.17.1/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/versions/1.17/.gitkeep b/versions/1.17/.gitkeep new file mode 100644 index 00000000..e69de29b