From 9f8957f468cf99d1f4582d4277b60d7c67c98edc Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Tue, 24 May 2022 10:44:30 +0200 Subject: [PATCH 01/11] Migrate away from deprecated fabric-api modules --- build.gradle | 2 + .../replaymod/core/KeyBindingRegistry.java | 22 +++++-- .../recording/ReplayModRecording.java | 8 +++ src/main/resources/fabric.mod.json | 2 +- .../1.15.2/src/main/resources/fabric.mod.json | 60 +++++++++++++++++++ .../1.17/src/main/resources/fabric.mod.json | 60 +++++++++++++++++++ 6 files changed, 147 insertions(+), 7 deletions(-) create mode 100644 versions/1.15.2/src/main/resources/fabric.mod.json create mode 100644 versions/1.17/src/main/resources/fabric.mod.json diff --git a/build.gradle b/build.gradle index c57fc62f..d809e9ba 100644 --- a/build.gradle +++ b/build.gradle @@ -279,9 +279,11 @@ dependencies { "resource-loader-v0", ] if (mcVersion >= 11600) { + fabricApiModules.remove("keybindings-v0") fabricApiModules.add("key-binding-api-v1") } if (mcVersion >= 11700) { + fabricApiModules.remove("networking-v0") fabricApiModules.add("networking-api-v1") } fabricApiModules.each { module -> diff --git a/src/main/java/com/replaymod/core/KeyBindingRegistry.java b/src/main/java/com/replaymod/core/KeyBindingRegistry.java index 6223717c..40eff2ee 100644 --- a/src/main/java/com/replaymod/core/KeyBindingRegistry.java +++ b/src/main/java/com/replaymod/core/KeyBindingRegistry.java @@ -14,7 +14,11 @@ import net.minecraft.util.crash.CrashException; //#if FABRIC>=1 import com.replaymod.core.versions.LangResourcePack; -import net.fabricmc.fabric.api.client.keybinding.FabricKeyBinding; +//#if MC>=11600 +import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; +//#else +//$$ import net.fabricmc.fabric.api.client.keybinding.FabricKeyBinding; +//#endif import net.minecraft.client.util.InputUtil; import net.minecraft.util.Identifier; import static com.replaymod.core.ReplayMod.MOD_ID; @@ -35,8 +39,8 @@ import java.util.function.Supplier; public class KeyBindingRegistry extends EventRegistrations { private static final String CATEGORY = "replaymod.title"; - //#if FABRIC>=1 - static { net.fabricmc.fabric.api.client.keybinding.KeyBindingRegistry.INSTANCE.addCategory(CATEGORY); } + //#if FABRIC>=1 && MC<11600 + //$$ static { net.fabricmc.fabric.api.client.keybinding.KeyBindingRegistry.INSTANCE.addCategory(CATEGORY); } //#endif private final Map bindings = new HashMap<>(); @@ -63,9 +67,15 @@ public class KeyBindingRegistry extends EventRegistrations { keyCode = -1; } Identifier id = new Identifier(MOD_ID, name.substring(LangResourcePack.LEGACY_KEY_PREFIX.length())); - FabricKeyBinding fabricKeyBinding = FabricKeyBinding.Builder.create(id, InputUtil.Type.KEYSYM, keyCode, CATEGORY).build(); - net.fabricmc.fabric.api.client.keybinding.KeyBindingRegistry.INSTANCE.register(fabricKeyBinding); - KeyBinding keyBinding = fabricKeyBinding; + //#if MC>=11600 + String key = String.format("key.%s.%s", id.getNamespace(), id.getPath()); + KeyBinding keyBinding = new KeyBinding(key, InputUtil.Type.KEYSYM, keyCode, CATEGORY); + KeyBindingHelper.registerKeyBinding(keyBinding); + //#else + //$$ FabricKeyBinding fabricKeyBinding = FabricKeyBinding.Builder.create(id, InputUtil.Type.KEYSYM, keyCode, CATEGORY).build(); + //$$ net.fabricmc.fabric.api.client.keybinding.KeyBindingRegistry.INSTANCE.register(fabricKeyBinding); + //$$ KeyBinding keyBinding = fabricKeyBinding; + //#endif //#else //$$ KeyBinding keyBinding = new KeyBinding(name, keyCode, CATEGORY); //$$ ClientRegistry.registerKeyBinding(keyBinding); diff --git a/src/main/java/com/replaymod/recording/ReplayModRecording.java b/src/main/java/com/replaymod/recording/ReplayModRecording.java index 94ae0902..f65e4467 100644 --- a/src/main/java/com/replaymod/recording/ReplayModRecording.java +++ b/src/main/java/com/replaymod/recording/ReplayModRecording.java @@ -16,7 +16,11 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; //#if FABRIC>=1 +//#if MC>=11700 +//$$ import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; +//#else import net.fabricmc.fabric.api.network.ClientSidePacketRegistry; +//#endif //#else //$$ import net.minecraftforge.fml.network.NetworkRegistry; //#endif @@ -68,7 +72,11 @@ public class ReplayModRecording implements Module { new GuiHandler(core).register(); //#if FABRIC>=1 + //#if MC>=11700 + //$$ ClientPlayNetworking.registerGlobalReceiver(Restrictions.PLUGIN_CHANNEL, (client, handler, buf, resp) -> {}); + //#else ClientSidePacketRegistry.INSTANCE.register(Restrictions.PLUGIN_CHANNEL, (packetContext, packetByteBuf) -> {}); + //#endif //#else //#if MC>=11400 //$$ NetworkRegistry.newEventChannel(Restrictions.PLUGIN_CHANNEL, () -> "0", any -> true, any -> true); diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 73fe9d6e..ef5522ec 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -43,7 +43,7 @@ "depends": { "fabricloader": ">=0.7.0", "fabric-networking-v0": "*", - "fabric-keybindings-v0": "*", + "fabric-key-binding-api-v1": "*", "fabric-resource-loader-v0": "*" }, diff --git a/versions/1.15.2/src/main/resources/fabric.mod.json b/versions/1.15.2/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..73fe9d6e --- /dev/null +++ b/versions/1.15.2/src/main/resources/fabric.mod.json @@ -0,0 +1,60 @@ +{ + "schemaVersion": 1, + "id": "replaymod", + "version": "${version}", + + "name": "Replay Mod", + "description": "A Mod which allows you to record, replay and share your Minecraft experience.", + "authors": [ + "CrushedPixel", + "johni0702" + ], + "contact": { + "homepage": "https://replaymod.com/", + "sources": "https://github.com/ReplayMod/ReplayMod" + }, + + "license": "GPL-3.0-or-later", + "icon": "assets/replaymod/favicon_logo.png", + + "environment": "client", + "entrypoints": { + "client": [ + "com.replaymod.core.ReplayModBackend" + ], + "modmenu": [ + "com.replaymod.core.gui.ModMenuApiImpl" + ], + "frex_flawless_frames": [ + "com.replaymod.render.utils.FlawlessFrames::registerConsumer" + ], + "preLaunch": [ + "com.replaymod.core.DummyChainLoadEntryPoint" + ], + "mm:early_risers": [ + "com.replaymod.core.ReplayModMMLauncher" + ] + }, + "mixins": [ + "mixins.jgui.json", + "mixins.nonmmlauncher.replaymod.json" + ], + + "depends": { + "fabricloader": ">=0.7.0", + "fabric-networking-v0": "*", + "fabric-keybindings-v0": "*", + "fabric-resource-loader-v0": "*" + }, + + "conflicts": { + "iris": "<1.1.3" + }, + + "custom": { + "mm:early_risers": [ + "com.replaymod.core.ReplayModMMLauncher" + ], + "modmenu:clientsideOnly": true + } +} diff --git a/versions/1.17/src/main/resources/fabric.mod.json b/versions/1.17/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..dbb99550 --- /dev/null +++ b/versions/1.17/src/main/resources/fabric.mod.json @@ -0,0 +1,60 @@ +{ + "schemaVersion": 1, + "id": "replaymod", + "version": "${version}", + + "name": "Replay Mod", + "description": "A Mod which allows you to record, replay and share your Minecraft experience.", + "authors": [ + "CrushedPixel", + "johni0702" + ], + "contact": { + "homepage": "https://replaymod.com/", + "sources": "https://github.com/ReplayMod/ReplayMod" + }, + + "license": "GPL-3.0-or-later", + "icon": "assets/replaymod/favicon_logo.png", + + "environment": "client", + "entrypoints": { + "client": [ + "com.replaymod.core.ReplayModBackend" + ], + "modmenu": [ + "com.replaymod.core.gui.ModMenuApiImpl" + ], + "frex_flawless_frames": [ + "com.replaymod.render.utils.FlawlessFrames::registerConsumer" + ], + "preLaunch": [ + "com.replaymod.core.DummyChainLoadEntryPoint" + ], + "mm:early_risers": [ + "com.replaymod.core.ReplayModMMLauncher" + ] + }, + "mixins": [ + "mixins.jgui.json", + "mixins.nonmmlauncher.replaymod.json" + ], + + "depends": { + "fabricloader": ">=0.7.0", + "fabric-networking-api-v1": "*", + "fabric-key-binding-api-v1": "*", + "fabric-resource-loader-v0": "*" + }, + + "conflicts": { + "iris": "<1.1.3" + }, + + "custom": { + "mm:early_risers": [ + "com.replaymod.core.ReplayModMMLauncher" + ], + "modmenu:clientsideOnly": true + } +} From 9ce25f711f6fe665994c1198d3c37b7343f971df Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Fri, 27 May 2022 07:03:35 +0200 Subject: [PATCH 02/11] Port to MC 1.19-pre3 --- build.gradle | 11 ++- jGui | 2 +- root.gradle.kts | 6 +- settings.gradle.kts | 2 + .../java/com/replaymod/core/ReplayMod.java | 9 +- .../core/mixin/SimpleOptionAccessor.java | 1 + .../core/versions/LangResourcePack.java | 11 ++- .../com/replaymod/core/versions/MCVer.java | 3 +- .../com/replaymod/core/versions/Patterns.java | 98 ++++++++++++++++++- .../com/replaymod/extras/FullBrightness.java | 2 +- .../playeroverview/PlayerOverviewGui.java | 4 +- .../handler/RecordingEventHandler.java | 15 +-- .../mixin/MixinDownloadingPackFinder.java | 4 + .../recording/mixin/MixinWorldClient.java | 35 +++++-- .../mixin/SPacketSpawnMobAccessor.java | 32 +++--- .../mixin/SPacketSpawnPlayerAccessor.java | 32 +++--- .../recording/packet/PacketListener.java | 10 +- .../packet/ResourcePackRecorder.java | 18 +++- .../render/blend/BlendMeshBuilder.java | 2 +- .../replaymod/render/blend/BlendState.java | 4 +- .../blend/exporters/EntityExporter.java | 2 +- .../render/blend/exporters/ItemExporter.java | 2 +- .../exporters/ModelRendererExporter.java | 2 +- .../blend/exporters/ParticlesExporter.java | 2 +- .../render/blend/exporters/RenderState.java | 2 +- .../blend/exporters/TileEntityExporter.java | 2 +- .../render/blend/mixin/MixinRenderGlobal.java | 2 +- .../render/blend/mixin/MixinRenderItem.java | 2 +- .../blend/mixin/MixinRenderLivingBase.java | 2 +- .../blend/mixin/MixinRenderManager.java | 2 +- .../render/mixin/MixinParticleManager.java | 8 +- .../replaymod/replay/FullReplaySender.java | 18 +++- .../replaymod/replay/camera/CameraEntity.java | 12 ++- .../replaymod/replay/handler/GuiHandler.java | 10 +- src/main/resources/mixins.core.replaymod.json | 3 + .../resources/mixins.recording.replaymod.json | 6 +- .../mixins.render.blend.replaymod.json | 2 + versions/1.14.4-forge/mapping.txt | 2 + versions/1.19/.gitkeep | 0 .../core/mixin/SimpleOptionAccessor.java | 11 +++ versions/mapping-fabric-1.19-1.18.2.txt | 4 + 41 files changed, 299 insertions(+), 98 deletions(-) create mode 100644 src/main/java/com/replaymod/core/mixin/SimpleOptionAccessor.java create mode 100644 versions/1.19/.gitkeep create mode 100644 versions/1.19/src/main/java/com/replaymod/core/mixin/SimpleOptionAccessor.java create mode 100644 versions/mapping-fabric-1.19-1.18.2.txt diff --git a/build.gradle b/build.gradle index d809e9ba..3a3664ec 100644 --- a/build.gradle +++ b/build.gradle @@ -34,7 +34,7 @@ buildscript { dependencies { classpath 'gradle.plugin.com.github.jengelman.gradle.plugins:shadow:7.0.0' if (fabric) { - classpath 'fabric-loom:fabric-loom.gradle.plugin:0.10-SNAPSHOT' + classpath 'fabric-loom:fabric-loom.gradle.plugin:0.11-SNAPSHOT' } else if (mcVersion >= 11400) { 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 @@ -246,6 +246,7 @@ dependencies { 11800: '1.18', 11801: '1.18.1', 11802: '1.18.2', + 11900: '1.19-pre3', ][mcVersion] mappings 'net.fabricmc:yarn:' + [ 11404: '1.14.4+build.16', @@ -258,8 +259,9 @@ dependencies { 11800: '1.18+build.1:v2', 11801: '1.18.1+build.1:v2', 11802: '1.18.2+build.1:v2', + 11900: '1.19-pre3+build.3:v2', ][mcVersion] - modImplementation 'net.fabricmc:fabric-loader:0.12.5' + modImplementation 'net.fabricmc:fabric-loader:0.14.6' def fabricApiVersion = [ 11404: '0.4.3+build.247-1.14', 11502: '0.5.1+build.294-1.15', @@ -271,6 +273,7 @@ dependencies { 11800: '0.43.1+1.18', 11801: '0.43.1+1.18', 11802: '0.47.9+1.18.2', + 11900: '0.53.4+1.19', ][mcVersion] def fabricApiModules = [ "api-base", @@ -351,7 +354,9 @@ dependencies { shadow 'com.github.ReplayMod:lwjgl-utils:27dcd66' if (FABRIC) { - if (mcVersion >= 11802) { + if (mcVersion >= 11900) { + modCompileOnly 'com.terraformersmc:modmenu:3.1.0' // FIXME update + } else if (mcVersion >= 11802) { modImplementation 'com.terraformersmc:modmenu:3.1.0' } else if (mcVersion >= 11800) { modImplementation 'com.terraformersmc:modmenu:3.0.0' diff --git a/jGui b/jGui index 5e41452b..94278dfd 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 5e41452b0e17700691efd38b8ce793b5200145c8 +Subproject commit 94278dfddbc3f325cf24c1c1f08d6a3547b30f8c diff --git a/root.gradle.kts b/root.gradle.kts index 8ee13ad4..276002e6 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.10-SNAPSHOT" apply false - id("com.replaymod.preprocess") version "7746c47" + id("fabric-loom") version "0.11-SNAPSHOT" apply false + id("com.replaymod.preprocess") version "48e02ad" id("com.github.hierynomus.license") version "0.15.0" } @@ -189,6 +189,7 @@ val doRelease by tasks.registering { defaultTasks("bundleJar") preprocess { + val mc11900 = createNode("1.19", 11900, "yarn") val mc11802 = createNode("1.18.2", 11802, "yarn") val mc11801 = createNode("1.18.1", 11801, "yarn") val mc11701 = createNode("1.17.1", 11701, "yarn") @@ -209,6 +210,7 @@ preprocess { val mc10800 = createNode("1.8", 10800, "srg") val mc10710 = createNode("1.7.10", 10710, "srg") + mc11900.link(mc11802, file("versions/mapping-fabric-1.19-1.18.2.txt")) mc11802.link(mc11801) mc11801.link(mc11701, file("versions/mapping-fabric-1.18.1-1.17.1.txt")) mc11701.link(mc11700) diff --git a/settings.gradle.kts b/settings.gradle.kts index a77be868..b3289dad 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -33,6 +33,7 @@ val jGuiVersions = listOf( "1.17.1", "1.18.1", "1.18.2", + "1.19", ) val replayModVersions = listOf( // "1.7.10", @@ -54,6 +55,7 @@ val replayModVersions = listOf( "1.17.1", "1.18.1", "1.18.2", + "1.19", ) rootProject.buildFileName = "root.gradle.kts" diff --git a/src/main/java/com/replaymod/core/ReplayMod.java b/src/main/java/com/replaymod/core/ReplayMod.java index 39e55c12..d93876b6 100644 --- a/src/main/java/com/replaymod/core/ReplayMod.java +++ b/src/main/java/com/replaymod/core/ReplayMod.java @@ -18,7 +18,6 @@ import com.replaymod.replaystudio.studio.ReplayStudio; import com.replaymod.replaystudio.util.I18n; import com.replaymod.simplepathing.ReplayModSimplePathing; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.options.Option; import net.minecraft.resource.DirectoryResourcePack; import net.minecraft.text.LiteralText; import net.minecraft.text.Style; @@ -37,6 +36,11 @@ import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; +//#if MC>=11900 +//#else +import net.minecraft.client.options.Option; +//#endif + public class ReplayMod implements Module, Scheduler { public static final String MOD_ID = "replaymod"; @@ -162,7 +166,8 @@ public class ReplayMod implements Module, Scheduler { keyBindingRegistry.register(); // 1.7.10 crashes when render distance > 16 - //#if MC>=10800 + // Post 1.19 this has become non-trivial to do, install Sodium+Bobby or OptiFine if you need it + //#if MC>=10800 && MC<11900 if (!MCVer.hasOptifine()) { Option.RENDER_DISTANCE.setMax(64f); } diff --git a/src/main/java/com/replaymod/core/mixin/SimpleOptionAccessor.java b/src/main/java/com/replaymod/core/mixin/SimpleOptionAccessor.java new file mode 100644 index 00000000..07b5fddd --- /dev/null +++ b/src/main/java/com/replaymod/core/mixin/SimpleOptionAccessor.java @@ -0,0 +1 @@ +// 1.19+ diff --git a/src/main/java/com/replaymod/core/versions/LangResourcePack.java b/src/main/java/com/replaymod/core/versions/LangResourcePack.java index 63e4304c..a3594f08 100644 --- a/src/main/java/com/replaymod/core/versions/LangResourcePack.java +++ b/src/main/java/com/replaymod/core/versions/LangResourcePack.java @@ -158,8 +158,12 @@ public class LangResourcePack extends AbstractFileResourcePack { String namespace, //#endif String path, + //#if MC>=11900 + //$$ Predicate filter + //#else int maxDepth, Predicate filter + //#endif ) { if (resourcePackType == ResourceType.CLIENT_RESOURCES && "lang".equals(path)) { Path base = baseLangPath(); @@ -174,8 +178,13 @@ public class LangResourcePack extends AbstractFileResourcePack { .map(LANG_FILE_NAME_PATTERN::matcher) .filter(Matcher::matches) .map(matcher -> String.format("%s_%s.json", matcher.group(1), matcher.group(1))) - .filter(filter::test) + //#if MC<11900 + .filter(filter) + //#endif .map(name -> new Identifier(ReplayMod.MOD_ID, "lang/" + name)) + //#if MC>=11900 + //$$ .filter(filter) + //#endif .collect(Collectors.toList()); } catch (IOException e) { e.printStackTrace(); diff --git a/src/main/java/com/replaymod/core/versions/MCVer.java b/src/main/java/com/replaymod/core/versions/MCVer.java index e53ed093..f24937ca 100644 --- a/src/main/java/com/replaymod/core/versions/MCVer.java +++ b/src/main/java/com/replaymod/core/versions/MCVer.java @@ -34,6 +34,7 @@ import net.minecraft.client.util.Window; import java.util.concurrent.CompletableFuture; //#if MC>=11600 +import net.minecraft.text.Text; import net.minecraft.text.TranslatableText; //#else //$$ import net.minecraft.client.resource.language.I18n; @@ -220,7 +221,7 @@ public class MCVer { //#if MC>=11400 public static Optional findButton(Iterable buttonList, @SuppressWarnings("unused") String text, @SuppressWarnings("unused") int id) { //#if MC>=11600 - final TranslatableText message = new TranslatableText(text); + final Text message = new TranslatableText(text); //#else //$$ final String message = I18n.translate(text); //#endif diff --git a/src/main/java/com/replaymod/core/versions/Patterns.java b/src/main/java/com/replaymod/core/versions/Patterns.java index 884eb955..cfd7d5a9 100644 --- a/src/main/java/com/replaymod/core/versions/Patterns.java +++ b/src/main/java/com/replaymod/core/versions/Patterns.java @@ -6,6 +6,7 @@ import com.google.common.util.concurrent.ListenableFuture; import com.replaymod.core.mixin.MinecraftAccessor; import com.replaymod.gradle.remap.Pattern; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.options.GameOptions; import net.minecraft.client.options.KeyBinding; import net.minecraft.client.render.VertexFormat; import net.minecraft.client.texture.TextureManager; @@ -14,6 +15,11 @@ import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.entity.EntityRenderDispatcher; import net.minecraft.client.sound.PositionedSoundInstance; import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.resource.Resource; +import net.minecraft.resource.ResourceManager; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; import net.minecraft.util.crash.CrashException; import net.minecraft.util.crash.CrashReport; import net.minecraft.util.crash.CrashReportSection; @@ -61,6 +67,7 @@ import net.minecraft.client.render.BufferBuilder; //$$ import net.minecraft.entity.EntityLivingBase; //#endif +import java.io.IOException; import java.util.Collection; import java.util.List; @@ -549,7 +556,9 @@ class Patterns { @Pattern private static void setCrashReport(MinecraftClient mc, CrashReport report) { - //#if MC>=11800 + //#if MC>=11900 + //$$ mc.setCrashReportSupplier(report); + //#elseif MC>=11800 //$$ mc.setCrashReportSupplier(() -> report); //#else mc.setCrashReport(report); @@ -573,4 +582,91 @@ class Patterns { //$$ return com.replaymod.core.versions.MCVer.getTrackedPosition(entity); //#endif } + + @Pattern + private static Text newTextLiteral(String str) { + //#if MC>=11900 + //$$ return net.minecraft.text.Text.literal(str); + //#else + return new LiteralText(str); + //#endif + } + + @Pattern + private static Text newTextTranslatable(String key, Object...args) { + //#if MC>=11900 + //$$ return net.minecraft.text.Text.translatable(key, args); + //#else + return new TranslatableText(key, args); + //#endif + } + + //#if MC>=11500 + @Pattern + private static Vec3d getTrackedPos(Entity entity) { + //#if MC>=11900 + //$$ return entity.getTrackedPosition().withDelta(0, 0, 0); + //#else + return entity.getTrackedPosition(); + //#endif + } + //#else + //$$ @Pattern private static void getTrackedPos() {} + //#endif + + @Pattern + private static void setGamma(GameOptions options, double value) { + //#if MC>=11900 + //$$ ((com.replaymod.core.mixin.SimpleOptionAccessor) (Object) options.getGamma()).setRawValue(value); + //#elseif MC>=11400 + options.gamma = value; + //#else + //$$ options.gammaSetting = (float) value; + //#endif + } + + @Pattern + private static double getGamma(GameOptions options) { + //#if MC>=11900 + //$$ return options.getGamma().getValue(); + //#else + return options.gamma; + //#endif + } + + @Pattern + private static int getViewDistance(GameOptions options) { + //#if MC>=11900 + //$$ return options.getViewDistance().getValue(); + //#else + return options.viewDistance; + //#endif + } + + @Pattern + private static double getFov(GameOptions options) { + //#if MC>=11900 + //$$ return options.getFov().getValue(); + //#else + return options.fov; + //#endif + } + + @Pattern + private static int getGuiScale(GameOptions options) { + //#if MC>=11900 + //$$ return options.getGuiScale().getValue(); + //#else + return options.guiScale; + //#endif + } + + @Pattern + private static Resource getResource(ResourceManager manager, Identifier id) throws IOException { + //#if MC>=11900 + //$$ return manager.getResourceOrThrow(id); + //#else + return manager.getResource(id); + //#endif + } } diff --git a/src/main/java/com/replaymod/extras/FullBrightness.java b/src/main/java/com/replaymod/extras/FullBrightness.java index b6bef691..0dc22f6c 100644 --- a/src/main/java/com/replaymod/extras/FullBrightness.java +++ b/src/main/java/com/replaymod/extras/FullBrightness.java @@ -72,7 +72,7 @@ public class FullBrightness extends EventRegistrations implements Extra { Type type = getType(); if (type == Type.Gamma || type == Type.Both) { originalGamma = mc.options.gamma; - mc.options.gamma = 1000; + mc.options.gamma = 1000.0; } if (type == Type.NightVision || type == Type.Both) { if (mc.player != null) { diff --git a/src/main/java/com/replaymod/extras/playeroverview/PlayerOverviewGui.java b/src/main/java/com/replaymod/extras/playeroverview/PlayerOverviewGui.java index 97e0d20f..01bf1f8f 100644 --- a/src/main/java/com/replaymod/extras/playeroverview/PlayerOverviewGui.java +++ b/src/main/java/com/replaymod/extras/playeroverview/PlayerOverviewGui.java @@ -116,7 +116,7 @@ public class PlayerOverviewGui extends GuiScreen implements Closeable { }.setSize(16, 16), new GuiLabel().setText( //#if MC>=11400 - p.getName().asString() + p.getName().getString() //#else //#if MC>=10800 //$$ p.getName() @@ -181,7 +181,7 @@ public class PlayerOverviewGui extends GuiScreen implements Closeable { if (isSpectator(o1) && !isSpectator(o2)) return 1; if (isSpectator(o2) && !isSpectator(o1)) return -1; //#if MC>=11400 - return o1.getName().asString().compareToIgnoreCase(o2.getName().asString()); + return o1.getName().getString().compareToIgnoreCase(o2.getName().getString()); //#else //#if MC>=10800 //$$ return o1.getName().compareToIgnoreCase(o2.getName()); diff --git a/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java b/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java index 4ccc2d9e..a64be5e0 100644 --- a/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java @@ -42,12 +42,9 @@ import java.util.Collections; //#if MC>=10904 import net.minecraft.network.packet.s2c.play.EntityTrackerUpdateS2CPacket; -import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket; import net.minecraft.network.packet.s2c.play.WorldEventS2CPacket; import net.minecraft.entity.EquipmentSlot; import net.minecraft.util.Hand; -import net.minecraft.sound.SoundCategory; -import net.minecraft.sound.SoundEvent; //#endif //#if MC>=10800 @@ -91,7 +88,7 @@ public class RecordingEventHandler extends EventRegistrations { } } - //#if MC>=11400 + //#if MC>=10904 public void onPacket(Packet packet) { packetListener.save(packet); } @@ -112,16 +109,6 @@ public class RecordingEventHandler extends EventRegistrations { } //#if MC>=10904 - public void onClientSound(SoundEvent sound, SoundCategory category, - double x, double y, double z, float volume, float pitch) { - try { - // Send to all other players in ServerWorldEventHandler#playSoundToAllNearExcept - packetListener.save(new PlaySoundS2CPacket(sound, category, x, y, z, volume, pitch)); - } catch(Exception e) { - e.printStackTrace(); - } - } - public void onClientEffect(int type, BlockPos pos, int data) { try { // Send to all other players in ServerWorldEventHandler#playEvent diff --git a/src/main/java/com/replaymod/recording/mixin/MixinDownloadingPackFinder.java b/src/main/java/com/replaymod/recording/mixin/MixinDownloadingPackFinder.java index 8a581096..196f0ad0 100644 --- a/src/main/java/com/replaymod/recording/mixin/MixinDownloadingPackFinder.java +++ b/src/main/java/com/replaymod/recording/mixin/MixinDownloadingPackFinder.java @@ -33,7 +33,11 @@ public abstract class MixinDownloadingPackFinder implements ResourcePackRecorder } //#if MC>=10800 + //#if MC>=11900 + //$$ @Inject(method = "loadServerPack(Ljava/io/File;Lnet/minecraft/resource/ResourcePackSource;)Ljava/util/concurrent/CompletableFuture;", at = @At("HEAD")) + //#else @Inject(method = "loadServerPack", at = @At("HEAD")) + //#endif private void recordDownloadedPack( File file, //#if MC>=11600 diff --git a/src/main/java/com/replaymod/recording/mixin/MixinWorldClient.java b/src/main/java/com/replaymod/recording/mixin/MixinWorldClient.java index 55bc21b2..d4951d9f 100644 --- a/src/main/java/com/replaymod/recording/mixin/MixinWorldClient.java +++ b/src/main/java/com/replaymod/recording/mixin/MixinWorldClient.java @@ -5,6 +5,7 @@ import com.replaymod.recording.handler.RecordingEventHandler; import net.minecraft.client.MinecraftClient; import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket; import net.minecraft.util.profiler.Profiler; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvent; @@ -61,12 +62,20 @@ public abstract class MixinWorldClient extends World implements RecordingEventHa //#else DimensionType dimensionType, //#endif - Supplier profiler, boolean bl, boolean bl2, long l) { + Supplier profiler, boolean bl, boolean bl2, long l + //#if MC>=11900 + //$$ , int maxChainedNeighborUpdates + //#endif + ) { super(mutableWorldProperties, registryKey, //#if MC<11602 //$$ registryKey2, //#endif - dimensionType, profiler, bl, bl2, l); + dimensionType, profiler, bl, bl2, l + //#if MC>=11900 + //$$ , maxChainedNeighborUpdates + //#endif + ); } //#else //#if MC>=11400 @@ -102,7 +111,10 @@ public abstract class MixinWorldClient extends World implements RecordingEventHa // but are instead played directly by the client. The server only sends these sounds to // other clients so we have to record them manually. // E.g. Block place sounds - //#if MC>=11400 + //#if MC>=11900 + //$$ @Inject(method = "playSound(Lnet/minecraft/entity/player/PlayerEntity;DDDLnet/minecraft/sound/SoundEvent;Lnet/minecraft/sound/SoundCategory;FFJ)V", + //$$ at = @At("HEAD")) + //#elseif MC>=11400 //#if FABRIC>=1 @Inject(method = "playSound(Lnet/minecraft/entity/player/PlayerEntity;DDDLnet/minecraft/sound/SoundEvent;Lnet/minecraft/sound/SoundCategory;FF)V", at = @At("HEAD")) @@ -114,12 +126,23 @@ public abstract class MixinWorldClient extends World implements RecordingEventHa //$$ @Inject(method = "playSound(Lnet/minecraft/entity/player/EntityPlayer;DDDLnet/minecraft/util/SoundEvent;Lnet/minecraft/util/SoundCategory;FF)V", //$$ at = @At("HEAD")) //#endif - public void replayModRecording_recordClientSound(PlayerEntity player, double x, double y, double z, SoundEvent sound, SoundCategory category, - float volume, float pitch, CallbackInfo ci) { + public void replayModRecording_recordClientSound( + PlayerEntity player, double x, double y, double z, SoundEvent sound, SoundCategory category, + float volume, float pitch, + //#if MC>=11900 + //$$ long seed, + //#endif + CallbackInfo ci) { if (player == this.client.player) { RecordingEventHandler handler = replayModRecording_getRecordingEventHandler(); if (handler != null) { - handler.onClientSound(sound, category, x, y, z, volume, pitch); + // Sent to all other players in ServerWorldEventHandler#playSoundToAllNearExcept + handler.onPacket(new PlaySoundS2CPacket( + sound, category, x, y, z, volume, pitch + //#if MC>=11900 + //$$ , seed + //#endif + )); } } } diff --git a/src/main/java/com/replaymod/recording/mixin/SPacketSpawnMobAccessor.java b/src/main/java/com/replaymod/recording/mixin/SPacketSpawnMobAccessor.java index 78b66335..1cc43bbb 100644 --- a/src/main/java/com/replaymod/recording/mixin/SPacketSpawnMobAccessor.java +++ b/src/main/java/com/replaymod/recording/mixin/SPacketSpawnMobAccessor.java @@ -1,16 +1,16 @@ -package com.replaymod.recording.mixin; - -import net.minecraft.entity.data.DataTracker; -import net.minecraft.network.packet.s2c.play.MobSpawnS2CPacket; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(MobSpawnS2CPacket.class) -public interface SPacketSpawnMobAccessor { - //#if MC<11500 - //$$ @Accessor("dataTracker") - //$$ DataTracker getDataManager(); - //$$ @Accessor("dataTracker") - //$$ void setDataManager(DataTracker value); - //#endif -} +//#if MC<11500 +//$$ package com.replaymod.recording.mixin; +//$$ +//$$ import net.minecraft.entity.data.DataTracker; +//$$ import net.minecraft.network.packet.s2c.play.MobSpawnS2CPacket; +//$$ import org.spongepowered.asm.mixin.Mixin; +//$$ import org.spongepowered.asm.mixin.gen.Accessor; +//$$ +//$$ @Mixin(MobSpawnS2CPacket.class) +//$$ public interface SPacketSpawnMobAccessor { +//$$ @Accessor("dataTracker") +//$$ DataTracker getDataManager(); +//$$ @Accessor("dataTracker") +//$$ void setDataManager(DataTracker value); +//$$ } +//#endif diff --git a/src/main/java/com/replaymod/recording/mixin/SPacketSpawnPlayerAccessor.java b/src/main/java/com/replaymod/recording/mixin/SPacketSpawnPlayerAccessor.java index 73f7f667..b2eb8607 100644 --- a/src/main/java/com/replaymod/recording/mixin/SPacketSpawnPlayerAccessor.java +++ b/src/main/java/com/replaymod/recording/mixin/SPacketSpawnPlayerAccessor.java @@ -1,16 +1,16 @@ -package com.replaymod.recording.mixin; - -import net.minecraft.entity.data.DataTracker; -import net.minecraft.network.packet.s2c.play.PlayerSpawnS2CPacket; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(PlayerSpawnS2CPacket.class) -public interface SPacketSpawnPlayerAccessor { - //#if MC<11500 - //$$ @Accessor("dataTracker") - //$$ DataTracker getDataManager(); - //$$ @Accessor("dataTracker") - //$$ void setDataManager(DataTracker value); - //#endif -} +//#if MC<11500 +//$$ package com.replaymod.recording.mixin; +//$$ +//$$ import net.minecraft.entity.data.DataTracker; +//$$ import net.minecraft.network.packet.s2c.play.PlayerSpawnS2CPacket; +//$$ import org.spongepowered.asm.mixin.Mixin; +//$$ import org.spongepowered.asm.mixin.gen.Accessor; +//$$ +//$$ @Mixin(PlayerSpawnS2CPacket.class) +//$$ public interface SPacketSpawnPlayerAccessor { +//$$ @Accessor("dataTracker") +//$$ DataTracker getDataManager(); +//$$ @Accessor("dataTracker") +//$$ void setDataManager(DataTracker value); +//$$ } +//#endif diff --git a/src/main/java/com/replaymod/recording/packet/PacketListener.java b/src/main/java/com/replaymod/recording/packet/PacketListener.java index f99833a5..7fdba653 100644 --- a/src/main/java/com/replaymod/recording/packet/PacketListener.java +++ b/src/main/java/com/replaymod/recording/packet/PacketListener.java @@ -13,8 +13,6 @@ import com.replaymod.recording.ReplayModRecording; import com.replaymod.recording.Setting; import com.replaymod.recording.gui.GuiSavingReplay; import com.replaymod.recording.handler.ConnectionEventHandler; -import com.replaymod.recording.mixin.SPacketSpawnMobAccessor; -import com.replaymod.recording.mixin.SPacketSpawnPlayerAccessor; import com.replaymod.replaystudio.PacketData; import com.replaymod.replaystudio.data.Marker; import com.replaymod.replaystudio.io.ReplayOutputStream; @@ -30,7 +28,6 @@ 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; -import net.minecraft.network.packet.s2c.play.MobSpawnS2CPacket; import net.minecraft.network.packet.s2c.play.PlayerSpawnS2CPacket; import net.minecraft.entity.Entity; import net.minecraft.entity.data.DataTracker; @@ -44,6 +41,13 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +//#if MC>=11500 +//#else +//$$ import com.replaymod.recording.mixin.SPacketSpawnMobAccessor; +//$$ import com.replaymod.recording.mixin.SPacketSpawnPlayerAccessor; +//$$ import net.minecraft.network.packet.s2c.play.MobSpawnS2CPacket; +//#endif + //#if MC>=11400 import net.minecraft.network.packet.s2c.login.LoginSuccessS2CPacket; //#else diff --git a/src/main/java/com/replaymod/recording/packet/ResourcePackRecorder.java b/src/main/java/com/replaymod/recording/packet/ResourcePackRecorder.java index 689f2cfd..01fd26c9 100644 --- a/src/main/java/com/replaymod/recording/packet/ResourcePackRecorder.java +++ b/src/main/java/com/replaymod/recording/packet/ResourcePackRecorder.java @@ -11,6 +11,11 @@ import net.minecraft.client.resource.ClientBuiltinResourcePackProvider; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +//#if MC>=11900 +//$$ import java.net.MalformedURLException; +//$$ import java.net.URL; +//#endif + //#if MC>=11400 import net.minecraft.text.TranslatableText; //#else @@ -192,7 +197,18 @@ 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 + //#if MC>=11900 + //$$ try { + //$$ URL theUrl = new URL(url); + //$$ String protocol = theUrl.getProtocol(); + //$$ if (!"http".equals(protocol) && !"https".equals(protocol)) { + //$$ throw new MalformedURLException("Unsupported protocol."); + //$$ } + //$$ return packFinder.download(theUrl, hash, true); + //$$ } catch (MalformedURLException e) { + //$$ return CompletableFuture.failedFuture(e); + //$$ } + //#elseif MC>=11700 //$$ return packFinder.download(url, hash, true); //#else return packFinder.download(url, hash); diff --git a/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java b/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java index 8b9e2f50..de61bb5f 100644 --- a/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java +++ b/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java @@ -1,4 +1,4 @@ -//#if MC>=10800 +//#if MC>=10800 && MC<11900 package com.replaymod.render.blend; import com.replaymod.render.blend.data.DMaterial; diff --git a/src/main/java/com/replaymod/render/blend/BlendState.java b/src/main/java/com/replaymod/render/blend/BlendState.java index 0ef4a29b..a13c02a3 100644 --- a/src/main/java/com/replaymod/render/blend/BlendState.java +++ b/src/main/java/com/replaymod/render/blend/BlendState.java @@ -2,7 +2,7 @@ package com.replaymod.render.blend; import com.replaymod.render.blend.data.DScene; import com.replaymod.render.blend.data.Serializer; -//#if MC>=10800 +//#if MC>=10800 && MC<11900 // FIXME 1.15 //#if MC<11500 //$$ import com.replaymod.render.blend.exporters.ChunkExporter; @@ -53,7 +53,7 @@ public class BlendState implements Exporter { this.blenderFile = BlenderFactory.newBlenderFile(file); this.factory = new BlenderFactory(blenderFile); - //#if MC>=10800 + //#if MC>=10800 && MC<11900 RenderState renderState = new RenderState(this); register(renderState); // FIXME 1.15 diff --git a/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java b/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java index 8b6834b7..d4dfda21 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java @@ -1,4 +1,4 @@ -//#if MC>=10800 +//#if MC>=10800 && MC<11900 package com.replaymod.render.blend.exporters; import com.replaymod.core.versions.MCVer; diff --git a/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java index b25b6556..368e55b8 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java @@ -1,4 +1,4 @@ -//#if MC>=10800 +//#if MC>=10800 && MC<11900 package com.replaymod.render.blend.exporters; import com.replaymod.render.blend.BlendMeshBuilder; 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 2320f236..9fba791c 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ModelRendererExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ModelRendererExporter.java @@ -1,4 +1,4 @@ -//#if MC>=10800 +//#if MC>=10800 && MC<11900 package com.replaymod.render.blend.exporters; import com.replaymod.render.blend.BlendMeshBuilder; 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 2aecf1a4..ec164ed6 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java @@ -1,4 +1,4 @@ -//#if MC>=10800 +//#if MC>=10800 && MC<11900 package com.replaymod.render.blend.exporters; import com.replaymod.core.versions.MCVer; diff --git a/src/main/java/com/replaymod/render/blend/exporters/RenderState.java b/src/main/java/com/replaymod/render/blend/exporters/RenderState.java index 9f385ce3..72b7abb9 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/RenderState.java +++ b/src/main/java/com/replaymod/render/blend/exporters/RenderState.java @@ -1,4 +1,4 @@ -//#if MC>=10800 +//#if MC>=10800 && MC<11900 package com.replaymod.render.blend.exporters; import com.replaymod.render.blend.BlendState; diff --git a/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java b/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java index 0fd15a81..18b0ce01 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java @@ -1,4 +1,4 @@ -//#if MC>=10800 +//#if MC>=10800 && MC<11900 package com.replaymod.render.blend.exporters; import com.replaymod.core.versions.MCVer; diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java index af495f1d..683b33f1 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java @@ -1,4 +1,4 @@ -//#if MC>=10800 +//#if MC>=10800 && MC<11900 package com.replaymod.render.blend.mixin; import com.replaymod.render.blend.BlendState; diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java index cf41e5e2..48a86d7f 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java @@ -1,4 +1,4 @@ -//#if MC>=10800 +//#if MC>=10800 && MC<11900 package com.replaymod.render.blend.mixin; import com.replaymod.render.blend.BlendState; diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderLivingBase.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderLivingBase.java index 04efa633..fa247467 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderLivingBase.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderLivingBase.java @@ -1,4 +1,4 @@ -//#if MC>=10800 +//#if MC>=10800 && MC<11900 package com.replaymod.render.blend.mixin; import com.replaymod.render.blend.BlendState; diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java index 57764995..1dfb808c 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java @@ -1,4 +1,4 @@ -//#if MC>=10800 +//#if MC>=10800 && MC<11900 package com.replaymod.render.blend.mixin; import com.replaymod.render.blend.BlendState; diff --git a/src/main/java/com/replaymod/render/mixin/MixinParticleManager.java b/src/main/java/com/replaymod/render/mixin/MixinParticleManager.java index 456dceac..98eafe37 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinParticleManager.java +++ b/src/main/java/com/replaymod/render/mixin/MixinParticleManager.java @@ -3,7 +3,6 @@ package com.replaymod.render.mixin; //#if MC>=10904 import com.replaymod.core.versions.MCVer; import com.replaymod.render.blend.BlendState; -import com.replaymod.render.blend.exporters.ParticlesExporter; import com.replaymod.render.hooks.EntityRendererHandler; import net.minecraft.client.particle.Particle; import net.minecraft.client.particle.ParticleManager; @@ -12,6 +11,11 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; +//#if MC>=11900 +//#else +import com.replaymod.render.blend.exporters.ParticlesExporter; +//#endif + //#if MC>=11500 import net.minecraft.client.render.VertexConsumer; import net.minecraft.util.math.Quaternion; @@ -52,10 +56,12 @@ public abstract class MixinParticleManager { } private void buildGeometry(Particle particle, VertexConsumer vertexConsumer, Camera camera, float partialTicks) { + //#if MC<11900 BlendState blendState = BlendState.getState(); if (blendState != null) { blendState.get(ParticlesExporter.class).onRender(particle, partialTicks); } + //#endif particle.buildGeometry(vertexConsumer, camera, partialTicks); } //#else diff --git a/src/main/java/com/replaymod/replay/FullReplaySender.java b/src/main/java/com/replaymod/replay/FullReplaySender.java index d03c7362..aee4dac1 100644 --- a/src/main/java/com/replaymod/replay/FullReplaySender.java +++ b/src/main/java/com/replaymod/replay/FullReplaySender.java @@ -44,8 +44,6 @@ import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket; import net.minecraft.network.packet.s2c.play.ScreenHandlerPropertyUpdateS2CPacket; import net.minecraft.network.packet.s2c.play.HealthUpdateS2CPacket; import net.minecraft.network.packet.s2c.login.LoginSuccessS2CPacket; -import net.minecraft.network.packet.s2c.play.MobSpawnS2CPacket; -import net.minecraft.network.packet.s2c.play.PaintingSpawnS2CPacket; import net.minecraft.network.packet.s2c.play.ParticleS2CPacket; import net.minecraft.network.packet.s2c.play.PlayerAbilitiesS2CPacket; import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket; @@ -59,6 +57,12 @@ import net.minecraft.util.math.Vec3d; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; +//#if MC>=11900 +//#else +import net.minecraft.network.packet.s2c.play.MobSpawnS2CPacket; +import net.minecraft.network.packet.s2c.play.PaintingSpawnS2CPacket; +//#endif + //#if MC>=11600 //#else //$$ import net.minecraft.network.packet.s2c.play.EntitySpawnGlobalS2CPacket; @@ -472,11 +476,13 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend boolean relevantPacket = packet instanceof PlayerSpawnS2CPacket || packet instanceof EntitySpawnS2CPacket + //#if MC<11900 || packet instanceof MobSpawnS2CPacket + || packet instanceof PaintingSpawnS2CPacket + //#endif //#if MC<11600 //$$ || packet instanceof EntitySpawnGlobalS2CPacket //#endif - || packet instanceof PaintingSpawnS2CPacket || packet instanceof ExperienceOrbSpawnS2CPacket || packet instanceof EntitiesDestroyS2CPacket; if (!relevantPacket) { @@ -688,6 +694,9 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend , packet.isDebugWorld() , packet.isFlatWorld() //#endif + //#if MC>=11900 + //$$ , java.util.Optional.empty() + //#endif ); //#else //#if MC>=10800 @@ -744,6 +753,9 @@ public class FullReplaySender extends ChannelDuplexHandler implements ReplaySend //$$ respawn.getGeneratorType(), //$$ GameMode.SPECTATOR //#endif + //#if MC>=11900 + //$$ , java.util.Optional.empty() + //#endif ); //#else //#if MC>=10809 diff --git a/src/main/java/com/replaymod/replay/camera/CameraEntity.java b/src/main/java/com/replaymod/replay/camera/CameraEntity.java index d990240e..797c0ed9 100644 --- a/src/main/java/com/replaymod/replay/camera/CameraEntity.java +++ b/src/main/java/com/replaymod/replay/camera/CameraEntity.java @@ -31,10 +31,6 @@ import net.minecraft.stat.StatHandler; import net.minecraft.util.Identifier; import net.minecraft.util.math.Box; -//#if MC>=11802 -//$$ import net.minecraft.tag.TagKey; -//#endif - //#if FABRIC>=1 //#else //$$ import net.minecraftforge.client.event.EntityViewRenderEvent; @@ -47,7 +43,11 @@ import net.minecraft.util.math.Box; //#if MC>=11400 import net.minecraft.client.world.ClientWorld; import net.minecraft.fluid.Fluid; +//#if MC>=11802 +//$$ import net.minecraft.tag.TagKey; +//#else import net.minecraft.tag.Tag; +//#endif import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.HitResult; //#else @@ -547,7 +547,11 @@ public class CameraEntity //#if MC>=11400 @Override + //#if MC>=11900 + //$$ public void onEquipStack(EquipmentSlot slot, ItemStack stack, ItemStack itemStack) { + //#else protected void onEquipStack(ItemStack itemStack_1) { + //#endif // Suppress equip sounds } //#endif diff --git a/src/main/java/com/replaymod/replay/handler/GuiHandler.java b/src/main/java/com/replaymod/replay/handler/GuiHandler.java index 2bc2f79d..00bb3d9f 100644 --- a/src/main/java/com/replaymod/replay/handler/GuiHandler.java +++ b/src/main/java/com/replaymod/replay/handler/GuiHandler.java @@ -64,11 +64,11 @@ public class GuiHandler extends EventRegistrations { mod.getReplayHandler().getReplaySender().setReplaySpeed(0); //#if MC>=11600 - final TranslatableText BUTTON_OPTIONS = new TranslatableText("menu.options"); - final TranslatableText BUTTON_EXIT_SERVER = new TranslatableText("menu.disconnect"); - final TranslatableText BUTTON_ADVANCEMENTS = new TranslatableText("gui.advancements"); - final TranslatableText BUTTON_STATS = new TranslatableText("gui.stats"); - final TranslatableText BUTTON_OPEN_TO_LAN = new TranslatableText("menu.shareToLan"); + final Text BUTTON_OPTIONS = new TranslatableText("menu.options"); + final Text BUTTON_EXIT_SERVER = new TranslatableText("menu.disconnect"); + final Text BUTTON_ADVANCEMENTS = new TranslatableText("gui.advancements"); + final Text BUTTON_STATS = new TranslatableText("gui.stats"); + final Text BUTTON_OPEN_TO_LAN = new TranslatableText("menu.shareToLan"); //#else //#if MC>=11400 //$$ final String BUTTON_OPTIONS = I18n.translate("menu.options"); diff --git a/src/main/resources/mixins.core.replaymod.json b/src/main/resources/mixins.core.replaymod.json index d1232a20..a326dc8d 100644 --- a/src/main/resources/mixins.core.replaymod.json +++ b/src/main/resources/mixins.core.replaymod.json @@ -22,6 +22,9 @@ "GuiScreenAccessor", "KeyBindingAccessor", "MinecraftAccessor", + //#if MC>=11900 + //$$ "SimpleOptionAccessor", + //#endif "TimerAccessor" ], "compatibilityLevel": "JAVA_8", diff --git a/src/main/resources/mixins.recording.replaymod.json b/src/main/resources/mixins.recording.replaymod.json index 09545afc..4d8edc84 100644 --- a/src/main/resources/mixins.recording.replaymod.json +++ b/src/main/resources/mixins.recording.replaymod.json @@ -8,8 +8,10 @@ "EntityLivingBaseAccessor", "IntegratedServerAccessor", "NetworkManagerAccessor", - "SPacketSpawnMobAccessor", - "SPacketSpawnPlayerAccessor", + //#if MC<11500 + //$$ "SPacketSpawnMobAccessor", + //$$ "SPacketSpawnPlayerAccessor", + //#endif "MixinServerInfo", //#if MC>=10800 "MixinDownloadingPackFinder", diff --git a/src/main/resources/mixins.render.blend.replaymod.json b/src/main/resources/mixins.render.blend.replaymod.json index abf980ae..156da80c 100644 --- a/src/main/resources/mixins.render.blend.replaymod.json +++ b/src/main/resources/mixins.render.blend.replaymod.json @@ -20,11 +20,13 @@ "ItemRendererAccessor", //#endif "ParticleAccessor", + //#if MC<11900 "MixinRenderGlobal", "MixinRenderItem", "MixinRenderLivingBase", "MixinRenderManager" //#endif + //#endif ], "compatibilityLevel": "JAVA_8", "minVersion": "0.6.11", diff --git a/versions/1.14.4-forge/mapping.txt b/versions/1.14.4-forge/mapping.txt index 52a22ceb..3bd9a84e 100644 --- a/versions/1.14.4-forge/mapping.txt +++ b/versions/1.14.4-forge/mapping.txt @@ -3,6 +3,8 @@ net.minecraft.potion.EffectInstance net.minecraft.potion.PotionEffect net.minecraft.client.gui.screen.AddServerScreen net.minecraft.client.gui.GuiScreenAddServer net.minecraft.resources.AbstractResourcePack net.minecraft.client.resources.AbstractResourcePack net.minecraft.resources.FolderPack net.minecraft.client.resources.FolderResourcePack +net.minecraft.resources.IResource net.minecraft.client.resources.IResource +net.minecraft.resources.IResourceManager net.minecraft.client.resources.IResourceManager 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 diff --git a/versions/1.19/.gitkeep b/versions/1.19/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/versions/1.19/src/main/java/com/replaymod/core/mixin/SimpleOptionAccessor.java b/versions/1.19/src/main/java/com/replaymod/core/mixin/SimpleOptionAccessor.java new file mode 100644 index 00000000..e31c2de9 --- /dev/null +++ b/versions/1.19/src/main/java/com/replaymod/core/mixin/SimpleOptionAccessor.java @@ -0,0 +1,11 @@ +package com.replaymod.core.mixin; + +import net.minecraft.client.option.SimpleOption; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(SimpleOption.class) +public interface SimpleOptionAccessor { + @Accessor("value") + void setRawValue(T value); +} diff --git a/versions/mapping-fabric-1.19-1.18.2.txt b/versions/mapping-fabric-1.19-1.18.2.txt new file mode 100644 index 00000000..7ac37640 --- /dev/null +++ b/versions/mapping-fabric-1.19-1.18.2.txt @@ -0,0 +1,4 @@ +# FIXME remap should be able to map these without us explicitly declaring them +net.minecraft.client.render.WorldRenderer fullUpdateFuture field_34808 +net.minecraft.client.render.WorldRenderer updateFinished field_34809 +net.minecraft.client.render.WorldRenderer shouldUpdate field_34810 From df11ba2e365aa98aeeffa8b5b8d12b8f9e57d075 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 12 Jun 2022 13:43:39 +0200 Subject: [PATCH 03/11] Port to MC 1.19 --- build.gradle | 11 +++++++---- jGui | 2 +- .../com/replaymod/editor/gui/MarkerProcessor.java | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 3a3664ec..eef8dfdd 100644 --- a/build.gradle +++ b/build.gradle @@ -246,7 +246,7 @@ dependencies { 11800: '1.18', 11801: '1.18.1', 11802: '1.18.2', - 11900: '1.19-pre3', + 11900: '1.19', ][mcVersion] mappings 'net.fabricmc:yarn:' + [ 11404: '1.14.4+build.16', @@ -259,7 +259,7 @@ dependencies { 11800: '1.18+build.1:v2', 11801: '1.18.1+build.1:v2', 11802: '1.18.2+build.1:v2', - 11900: '1.19-pre3+build.3:v2', + 11900: '1.19+build.2:v2', ][mcVersion] modImplementation 'net.fabricmc:fabric-loader:0.14.6' def fabricApiVersion = [ @@ -273,7 +273,7 @@ dependencies { 11800: '0.43.1+1.18', 11801: '0.43.1+1.18', 11802: '0.47.9+1.18.2', - 11900: '0.53.4+1.19', + 11900: '0.55.3+1.19', ][mcVersion] def fabricApiModules = [ "api-base", @@ -346,7 +346,10 @@ dependencies { shadow 'com.github.ReplayMod.JavaBlend:2.79.0:a0696f8' - shadow "com.github.ReplayMod:ReplayStudio:6fc8e20", shadeExclusions + shadow "com.github.ReplayMod:ReplayStudio:39debfe", shadeExclusions + + // FIXME this should be pulled in by ReplayStudio, and IntelliJ sees it, but javac for some reason does not + implementation 'com.github.viaversion:opennbt:0a02214' // 2.0-SNAPSHOT (ViaVersion Edition) implementation(FABRIC ? dependencies.project(path: jGui.path, configuration: "namedElements") : 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 94278dfd..c1e43fc9 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 94278dfddbc3f325cf24c1c1f08d6a3547b30f8c +Subproject commit c1e43fc9f0550bf6a6ab8685c1008e754e042772 diff --git a/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java b/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java index 7231cecf..54940eb3 100644 --- a/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java +++ b/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java @@ -124,7 +124,7 @@ public class MarkerProcessor { PacketTypeRegistry registry = MCVer.getPacketTypeRegistry(true); DimensionTracker dimensionTracker = new DimensionTracker(); - SquashFilter squashFilter = new SquashFilter(null, null); + SquashFilter squashFilter = new SquashFilter(null, null, null); List> outputPaths = new ArrayList<>(); From 13ac8dcf0ae53e520457782d20460e98550fdc9d Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Wed, 15 Jun 2022 13:04:33 +0200 Subject: [PATCH 04/11] Record raw packets instead of re-encoding decoded packets Until now, recording worked by injecting right before the vanilla packet handler. At that point it was receiving packet classes and had to re-encode them to store them in the replay file. However, not all decoded packets can necessarily be re-encoded without errors, requiring us to have a bunch of workarounds. This commit changes the way recording works by injecting right before the decoder. It therefore receives the raw bytebufs and no longer has to deal with the re-encode issue. --- .../handler/ConnectionEventHandler.java | 10 +- .../handler/RecordingEventHandler.java | 93 ----- .../mixin/MixinClientConnection.java | 39 +++ .../recording/packet/PacketListener.java | 331 ++++++++---------- .../resources/mixins.recording.replaymod.json | 1 + 5 files changed, 195 insertions(+), 279 deletions(-) create mode 100644 src/main/java/com/replaymod/recording/mixin/MixinClientConnection.java diff --git a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java index 0211c8e0..876430fc 100644 --- a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java @@ -3,7 +3,6 @@ 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; @@ -43,7 +42,6 @@ import static com.replaymod.core.versions.MCVer.getMinecraft; */ public class ConnectionEventHandler { - private static final String packetHandlerKey = "packet_handler"; private static final String DATE_FORMAT = "yyyy_MM_dd_HH_mm_ss"; private static final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT); private static final MinecraftClient mc = getMinecraft(); @@ -141,7 +139,13 @@ public class ConnectionEventHandler { metaData.setMcVersion(ReplayMod.instance.getMinecraftVersion()); packetListener = new PacketListener(core, outputPath, replayFile, metaData); Channel channel = ((NetworkManagerAccessor) networkManager).getChannel(); - channel.pipeline().addBefore(packetHandlerKey, "replay_recorder", packetListener); + if (channel.pipeline().get(PacketListener.DECODER_KEY) != null) { + // Regular channel, we'll inject our recorder directly before the decoder + channel.pipeline().addBefore(PacketListener.DECODER_KEY, PacketListener.RAW_RECORDER_KEY, packetListener); + } else { + // Integrated server passes packets directly, there's no splitting, decompression or decoding + channel.pipeline().addFirst(PacketListener.RAW_RECORDER_KEY, packetListener); + } recordingEventHandler = new RecordingEventHandler(packetListener); recordingEventHandler.register(); diff --git a/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java b/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java index a64be5e0..ac303479 100644 --- a/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/RecordingEventHandler.java @@ -321,99 +321,6 @@ public class RecordingEventHandler extends EventRegistrations { } } - //#if FABRIC>=1 - // FIXME fabric - //#else - //$$ @SubscribeEvent - //$$ public void onPickupItem(ItemPickupEvent event) { - //$$ try { - //#if MC>=11100 - //#if MC>=11200 - //#if MC>=11400 - //$$ ItemStack stack = event.getStack(); - //$$ packetListener.save(new SCollectItemPacket( - //$$ event.getOriginalEntity().getEntityId(), - //$$ event.getPlayer().getEntityId(), - //$$ event.getStack().getCount() - //$$ )); - //#else - //$$ packetListener.save(new SPacketCollectItem(event.pickedUp.getEntityId(), event.player.getEntityId(), - //$$ event.pickedUp.getItem().getMaxStackSize())); - //#endif - //#else - //$$ packetListener.save(new SPacketCollectItem(event.pickedUp.getEntityId(), event.player.getEntityId(), - //$$ event.pickedUp.getEntityItem().getMaxStackSize())); - //#endif - //#else - //$$ packetListener.save(new SPacketCollectItem(event.pickedUp.getEntityId(), event.player.getEntityId())); - //#endif - //$$ } catch(Exception e) { - //$$ e.printStackTrace(); - //$$ } - //$$ } - //#endif - - //#if MC>=11400 - // FIXME fabric - //#else - //$$ @SubscribeEvent - //$$ public void onSleep(PlayerSleepInBedEvent event) { - //$$ try { - //#if MC>=10904 - //$$ if (event.getEntityPlayer() != mc.player) { - //$$ return; - //$$ } - //$$ - //$$ packetListener.save(new SPacketUseBed(event.getEntityPlayer(), event.getPos())); - //#else - //$$ if (event.entityPlayer != mc.thePlayer) { - //$$ return; - //$$ } - //$$ - //$$ packetListener.save(new S0APacketUseBed(event.entityPlayer, - //#if MC>=10800 - //$$ event.pos - //#else - //$$ event.x, event.y, event.z - //#endif - //$$ )); - //#endif - //$$ - //$$ wasSleeping = true; - //$$ - //$$ } catch(Exception e) { - //$$ e.printStackTrace(); - //$$ } - //$$ } - //#endif - - /* FIXME event not (yet?) on 1.13 - @SubscribeEvent - public void enterMinecart(MinecartInteractEvent event) { - try { - //#if MC>=10904 - if(event.getEntity() != mc.player) { - return; - } - - packetListener.save(new SPacketEntityAttach(event.getPlayer(), event.getMinecart())); - - lastRiding = event.getMinecart().getEntityId(); - //#else - //$$ if(event.entity != mc.thePlayer) { - //$$ return; - //$$ } - //$$ - //$$ packetListener.save(new S1BPacketEntityAttach(0, event.player, event.minecart)); - //$$ - //$$ lastRiding = event.minecart.getEntityId(); - //#endif - } catch(Exception e) { - e.printStackTrace(); - } - } - */ - //#if MC>=10800 public void onBlockBreakAnim(int breakerId, BlockPos pos, int progress) { //#else diff --git a/src/main/java/com/replaymod/recording/mixin/MixinClientConnection.java b/src/main/java/com/replaymod/recording/mixin/MixinClientConnection.java new file mode 100644 index 00000000..60d1314c --- /dev/null +++ b/src/main/java/com/replaymod/recording/mixin/MixinClientConnection.java @@ -0,0 +1,39 @@ +package com.replaymod.recording.mixin; + +import com.replaymod.recording.packet.PacketListener; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import net.minecraft.network.ClientConnection; +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.Map; + +@Mixin(ClientConnection.class) +public abstract class MixinClientConnection { + @Shadow + private Channel channel; + + @Inject(method = "setCompressionThreshold", at = @At("RETURN")) + private void ensureReplayModRecorderIsAfterDecompress(CallbackInfo ci) { + ChannelHandler recorder = null; + for (Map.Entry entry : channel.pipeline()) { + String key = entry.getKey(); + if (PacketListener.RAW_RECORDER_KEY.equals(key)) { + recorder = entry.getValue(); + } + if (PacketListener.DECOMPRESS_KEY.equals(key)) { + if (recorder != null) { + // If we've already found the recorder, then that means decompress is after recorder. That's no good + // because it means the recorder is getting compressed packets, we need to move the recorder. + channel.pipeline().remove(recorder); + channel.pipeline().addBefore(PacketListener.DECODER_KEY, PacketListener.RAW_RECORDER_KEY, recorder); + return; + } + } + } + } +} diff --git a/src/main/java/com/replaymod/recording/packet/PacketListener.java b/src/main/java/com/replaymod/recording/packet/PacketListener.java index 7fdba653..677673ad 100644 --- a/src/main/java/com/replaymod/recording/packet/PacketListener.java +++ b/src/main/java/com/replaymod/recording/packet/PacketListener.java @@ -2,7 +2,6 @@ package com.replaymod.recording.packet; import com.github.steveice10.netty.buffer.PooledByteBufAllocator; import com.github.steveice10.packetlib.tcp.io.ByteBufNetOutput; -import com.google.common.collect.Lists; import com.google.gson.Gson; import com.replaymod.core.ReplayMod; import com.replaymod.core.utils.Restrictions; @@ -16,23 +15,24 @@ import com.replaymod.recording.handler.ConnectionEventHandler; import com.replaymod.replaystudio.PacketData; import com.replaymod.replaystudio.data.Marker; import com.replaymod.replaystudio.io.ReplayOutputStream; +import com.replaymod.replaystudio.lib.viaversion.api.protocol.packet.State; +import com.replaymod.replaystudio.protocol.Packet; import com.replaymod.replaystudio.replay.ReplayFile; import com.replaymod.replaystudio.replay.ReplayMetaData; import de.johni0702.minecraft.gui.container.VanillaGuiScreen; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.util.AttributeKey; 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; import net.minecraft.network.packet.s2c.play.PlayerSpawnS2CPacket; import net.minecraft.entity.Entity; -import net.minecraft.entity.data.DataTracker; import net.minecraft.network.NetworkState; -import net.minecraft.network.Packet; import net.minecraft.network.PacketByteBuf; import net.minecraft.text.LiteralText; import net.minecraft.util.crash.CrashReport; @@ -41,24 +41,6 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -//#if MC>=11500 -//#else -//$$ import com.replaymod.recording.mixin.SPacketSpawnMobAccessor; -//$$ import com.replaymod.recording.mixin.SPacketSpawnPlayerAccessor; -//$$ import net.minecraft.network.packet.s2c.play.MobSpawnS2CPacket; -//#endif - -//#if MC>=11400 -import net.minecraft.network.packet.s2c.login.LoginSuccessS2CPacket; -//#else -//$$ import net.minecraftforge.fml.common.network.internal.FMLProxyPacket; -//#endif - -//#if MC>=10904 -//#else -//$$ import java.util.List; -//#endif - //#if MC>=10800 //#if MC<10904 //$$ import net.minecraft.network.play.server.S46PacketSetCompressionLevel; @@ -68,7 +50,6 @@ import net.minecraft.network.packet.s2c.play.ResourcePackSendS2CPacket; import net.minecraft.network.NetworkSide; //#endif -import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Files; @@ -86,12 +67,31 @@ import java.util.concurrent.atomic.AtomicInteger; import static com.replaymod.core.versions.MCVer.*; import static com.replaymod.replaystudio.util.Utils.writeInt; +import static java.util.Objects.requireNonNull; +@ChannelHandler.Sharable // so we can re-order it public class PacketListener extends ChannelInboundHandlerAdapter { + public static final String RAW_RECORDER_KEY = "replay_recorder_raw"; + public static final String DECODED_RECORDER_KEY = "replay_recorder_decoded"; + + public static final String DECOMPRESS_KEY = "decompress"; + public static final String DECODER_KEY = "decoder"; + private static final MinecraftClient mc = getMinecraft(); private static final Logger logger = LogManager.getLogger(); + //#if MC>=11700 + //$$ private static final int PACKET_ID_RESOURCE_PACK_SEND = getPacketId(NetworkState.PLAY, new ResourcePackSendS2CPacket("", "", false, null)); + //$$ private static final int PACKET_ID_LOGIN_COMPRESSION = getPacketId(NetworkState.LOGIN, new LoginCompressionS2CPacket(0)); + //#else + private static final int PACKET_ID_RESOURCE_PACK_SEND = getPacketId(NetworkState.PLAY, new ResourcePackSendS2CPacket()); + private static final int PACKET_ID_LOGIN_COMPRESSION = getPacketId(NetworkState.LOGIN, new LoginCompressionS2CPacket()); + //#endif + //#if MC<10904 + //$$ private static final int PACKET_ID_PLAY_COMPRESSION = getPacketId(EnumConnectionState.PLAY, new S46PacketSetCompressionLevel()); + //#endif + private final ReplayMod core; private final Path outputPath; private final ReplayFile replayFile; @@ -109,13 +109,6 @@ public class PacketListener extends ChannelInboundHandlerAdapter { private long lastSentPacket; private long timePassedWhilePaused; private volatile boolean serverWasPaused; - //#if MC>=11400 - private NetworkState connectionState = NetworkState.LOGIN; - private boolean loginPhase = true; - //#else - //$$ private EnumConnectionState connectionState = EnumConnectionState.PLAY; - //$$ private boolean loginPhase = false; - //#endif /** * Used to keep track of the last metadata save job submitted to the save service and @@ -163,6 +156,17 @@ public class PacketListener extends ChannelInboundHandlerAdapter { }); } + public void save(net.minecraft.network.Packet packet) { + Packet encoded; + try { + encoded = encodeMcPacket(getConnectionState(), packet); + } catch (Exception e) { + logger.error("Encoding packet:", e); + return; + } + save(encoded); + } + public void save(Packet packet) { // If we're not on the main thread (i.e. we're on the netty thread), then we need to schedule the saving // to happen on the main thread so we can guarantee correct ordering of inbound and inject packets. @@ -173,24 +177,12 @@ public class PacketListener extends ChannelInboundHandlerAdapter { return; } try { - if(packet instanceof PlayerSpawnS2CPacket) { - //#if MC>=10800 - UUID uuid = ((PlayerSpawnS2CPacket) packet).getPlayerUuid(); - //#else - //$$ UUID uuid = ((S0CPacketSpawnPlayer) packet).func_148948_e().getId(); - //#endif - Set uuids = new HashSet<>(Arrays.asList(metaData.getPlayers())); - uuids.add(uuid.toString()); - metaData.setPlayers(uuids.toArray(new String[uuids.size()])); - saveMetaData(); - } - - //#if MC>=10800 - if (packet instanceof LoginCompressionS2CPacket) { + //#if MC>=11800 + if (packet.getRegistry().getState() == State.LOGIN && packet.getId() == PACKET_ID_LOGIN_COMPRESSION) { return; // Replay data is never compressed on the packet level } //#if MC<10904 - //$$ if (packet instanceof S46PacketSetCompressionLevel) { + //$$ if (packet.getRegistry().getState() == State.PLAY && packet.getId() == PACKET_ID_PLAY_COMPRESSION) { //$$ return; // Replay data is never compressed on the packet level //$$ } //#endif @@ -203,7 +195,7 @@ public class PacketListener extends ChannelInboundHandlerAdapter { } int timestamp = (int) (now - startTime - timePassedWhilePaused); lastSentPacket = timestamp; - PacketData packetData = getPacketData(timestamp, packet); + PacketData packetData = new PacketData(timestamp, packet); saveService.submit(() -> { try { if (ReplayMod.isMinimalMode()) { @@ -230,18 +222,27 @@ public class PacketListener extends ChannelInboundHandlerAdapter { throw new RuntimeException(e); } }); - - //#if MC>=11400 - if (packet instanceof LoginSuccessS2CPacket) { - connectionState = NetworkState.PLAY; - loginPhase = false; - } - //#endif } catch(Exception e) { logger.error("Writing packet:", e); } } + @Override + public void handlerAdded(ChannelHandlerContext ctx) throws Exception { + super.handlerAdded(ctx); + + if (ctx.pipeline().get(DECODED_RECORDER_KEY) == null) { + if (ctx.pipeline().get(PacketListener.DECODER_KEY) != null) { + // Regular channel, we'll inject our decoded recorder directly after the decoder + ctx.pipeline().addAfter(DECODER_KEY, DECODED_RECORDER_KEY, new DecodedPacketListener()); + } else { + // Integrated server passes packets directly, there's no splitting, decompression or decoding + // The decoded packet handler can just go directly behind this hand + ctx.pipeline().addAfter(RAW_RECORDER_KEY, DECODED_RECORDER_KEY, new DecodedPacketListener()); + } + } + } + @Override public void channelInactive(ChannelHandlerContext ctx) { metaData.setDuration((int) lastSentPacket); @@ -328,139 +329,44 @@ public class PacketListener extends ChannelInboundHandlerAdapter { } this.context = ctx; - if (msg instanceof Packet) { - try { - Packet packet = (Packet) msg; + NetworkState connectionState = getConnectionState(); - //#if MC>=10904 - if(packet instanceof ItemPickupAnimationS2CPacket) { - if(mc.player != null || - ((ItemPickupAnimationS2CPacket) packet).getEntityId() == mc.player.getEntityId()) { - //#else - //$$ if(packet instanceof S0DPacketCollectItem) { - //$$ if(mc.thePlayer != null || ((S0DPacketCollectItem) packet).getEntityID() == mc.thePlayer.getEntityId()) { - //#endif - super.channelRead(ctx, msg); - return; - } - } + Packet packet = null; + if (msg instanceof ByteBuf) { + // for regular connections, we're expecting to observe `ByteBuf`s here + ByteBuf buf = (ByteBuf) msg; + if (buf.readableBytes() > 0) { + packet = decodePacket(connectionState, buf); + } + } else if (msg instanceof net.minecraft.network.Packet) { + // for integrated server connections MC is passing the packet objects directly, so we need to encode them + // ourselves to be able to store them + packet = encodeMcPacket(connectionState, (net.minecraft.network.Packet) msg); + } - //#if MC>=10800 - if (packet instanceof ResourcePackSendS2CPacket) { - ClientConnection connection = ctx.pipeline().get(ClientConnection.class); - save(resourcePackRecorder.handleResourcePack(connection, (ResourcePackSendS2CPacket) packet)); - return; - } - //#else - //$$ if (packet instanceof S3FPacketCustomPayload) { - //$$ S3FPacketCustomPayload p = (S3FPacketCustomPayload) packet; - //$$ if ("MC|RPack".equals(p.func_149169_c())) { - //$$ save(resourcePackRecorder.handleResourcePack(p)); - //$$ return; - //$$ } - //$$ } - //#endif - - //#if MC<11400 - //$$ if (packet instanceof FMLProxyPacket) { - //$$ // This packet requires special handling - //#if MC>=10800 - //$$ ((FMLProxyPacket) packet).toS3FPackets().forEach(this::save); - //#else - //$$ save(((FMLProxyPacket) packet).toS3FPacket()); - //#endif - //$$ super.channelRead(ctx, msg); - //$$ return; - //$$ } - //#endif - - //#if MC>=10800 - if (packet instanceof CustomPayloadS2CPacket) { - // Forge may read from this ByteBuf and/or release it during handling - // We want to save the full thing however, so we create a copy and save that one instead of the - // original one - // Note: This isn't an issue with vanilla MC because our saving code runs on the main thread - // shortly before the vanilla handling code does. Forge however does some stuff on the netty - // threads which leads to this race condition - packet = new CustomPayloadS2CPacket( - ((CustomPayloadS2CPacket) packet).getChannel(), - new PacketByteBuf(((CustomPayloadS2CPacket) packet).getData().slice().retain()) - ); - } - //#endif - - save(packet); - - if (packet instanceof CustomPayloadS2CPacket) { - CustomPayloadS2CPacket p = (CustomPayloadS2CPacket) packet; - if (Restrictions.PLUGIN_CHANNEL.equals(p.getChannel())) { - packet = new DisconnectS2CPacket(new LiteralText("Please update to view this replay.")); - save(packet); - } - } - } catch(Exception e) { - logger.error("Handling packet for recording:", e); + if (packet != null) { + if (connectionState == NetworkState.PLAY && packet.getId() == PACKET_ID_RESOURCE_PACK_SEND) { + ClientConnection connection = ctx.pipeline().get(ClientConnection.class); + save(resourcePackRecorder.handleResourcePack(connection, (ResourcePackSendS2CPacket) decodeMcPacket(packet))); + return; } + save(packet); } super.channelRead(ctx, msg); } - //#if MC>=10904 - private void DataManager_set(DataTracker dataManager, DataTracker.Entry entry) { - dataManager.startTracking(entry.getData(), entry.get()); + private NetworkState getConnectionState() { + ChannelHandlerContext ctx = context; + if (ctx == null) { + return NetworkState.LOGIN; + } + AttributeKey key = ClientConnection.ATTR_KEY_PROTOCOL; + return ctx.channel().attr(key).get(); } - //#endif - - @SuppressWarnings("unchecked") - private PacketData getPacketData(int timestamp, Packet packet) throws Exception { - //#if MC<11500 - //$$ if (packet instanceof MobSpawnS2CPacket) { - //$$ MobSpawnS2CPacket p = (MobSpawnS2CPacket) packet; - //$$ SPacketSpawnMobAccessor pa = (SPacketSpawnMobAccessor) p; - //$$ if (pa.getDataManager() == null) { - //$$ pa.setDataManager(new DataTracker(null)); - //$$ if (p.getTrackedValues() != null) { - //$$ Set seen = new HashSet<>(); - //#if MC>=10904 - //$$ for (DataTracker.Entry entry : Lists.reverse(p.getTrackedValues())) { - //$$ if (!seen.add(entry.getData().getId())) continue; - //$$ DataManager_set(pa.getDataManager(), entry); - //$$ } - //#else - //$$ for(DataWatcher.WatchableObject wo : Lists.reverse((List) p.func_149027_c())) { - //$$ if (!seen.add(wo.getDataValueId())) continue; - //$$ pa.getDataManager().addObject(wo.getDataValueId(), wo.getObject()); - //$$ } - //#endif - //$$ } - //$$ } - //$$ } - //$$ - //$$ if (packet instanceof PlayerSpawnS2CPacket) { - //$$ PlayerSpawnS2CPacket p = (PlayerSpawnS2CPacket) packet; - //$$ SPacketSpawnPlayerAccessor pa = (SPacketSpawnPlayerAccessor) p; - //$$ if (pa.getDataManager() == null) { - //$$ pa.setDataManager(new DataTracker(null)); - //$$ if (p.getTrackedValues() != null) { - //$$ Set seen = new HashSet<>(); - //#if MC>=10904 - //$$ for (DataTracker.Entry entry : Lists.reverse(p.getTrackedValues())) { - //$$ if (!seen.add(entry.getData().getId())) continue; - //$$ DataManager_set(pa.getDataManager(), entry); - //$$ } - //#else - //$$ for(DataWatcher.WatchableObject wo : Lists.reverse((List) p.func_148944_c())) { - //$$ if (!seen.add(wo.getDataValueId())) continue; - //$$ pa.getDataManager().addObject(wo.getDataValueId(), wo.getObject()); - //$$ } - //#endif - //$$ } - //$$ } - //$$ } - //#endif + private static Packet encodeMcPacket(NetworkState connectionState, net.minecraft.network.Packet packet) throws Exception { //#if MC>=10800 Integer packetId = connectionState.getPacketId(NetworkSide.CLIENTBOUND, packet); //#else @@ -472,23 +378,55 @@ public class PacketListener extends ChannelInboundHandlerAdapter { ByteBuf byteBuf = Unpooled.buffer(); try { packet.write(new PacketByteBuf(byteBuf)); - return new PacketData(timestamp, new com.replaymod.replaystudio.protocol.Packet( - MCVer.getPacketTypeRegistry(loginPhase), + return new Packet( + MCVer.getPacketTypeRegistry(connectionState == NetworkState.LOGIN), packetId, com.github.steveice10.netty.buffer.Unpooled.wrappedBuffer( byteBuf.array(), byteBuf.arrayOffset(), byteBuf.readableBytes() ) - )); + ); } finally { byteBuf.release(); + } + } - //#if MC>=10800 - if (packet instanceof CustomPayloadS2CPacket) { - ((CustomPayloadS2CPacket) packet).getData().release(); - } - //#endif + private static net.minecraft.network.Packet decodeMcPacket(Packet packet) throws IOException, IllegalAccessException, InstantiationException { + NetworkState connectionState = packet.getRegistry().getState() == State.LOGIN ? NetworkState.LOGIN : NetworkState.PLAY; + int packetId = packet.getId(); + PacketByteBuf packetBuf = new PacketByteBuf(Unpooled.wrappedBuffer(packet.getBuf().nioBuffer())); + + //#if MC>=11700 + //$$ return connectionState.getPacketHandler(NetworkSide.CLIENTBOUND, packetId, packetBuf); + //#else + //#if MC>=10800 + net.minecraft.network.Packet p = connectionState.getPacketHandler(NetworkSide.CLIENTBOUND, packetId); + //#else + //$$ net.minecraft.network.Packet p = net.minecraft.network.Packet.generatePacket(connectionState.func_150755_b(), packetId); + //#endif + p.read(packetBuf); + return p; + //#endif + } + + private static Packet decodePacket(NetworkState connectionState, ByteBuf buf) { + PacketByteBuf packetBuf = new PacketByteBuf(buf.slice()); + int packetId = packetBuf.readVarInt(); + byte[] bytes = new byte[packetBuf.readableBytes()]; + packetBuf.readBytes(bytes); + return new Packet( + MCVer.getPacketTypeRegistry(connectionState == NetworkState.LOGIN), + packetId, + com.github.steveice10.netty.buffer.Unpooled.wrappedBuffer(bytes) + ); + } + + private static int getPacketId(NetworkState networkState, net.minecraft.network.Packet packet) { + try { + return requireNonNull(networkState.getPacketId(NetworkSide.CLIENTBOUND, packet)); + } catch (Exception e) { + throw new RuntimeException("Failed to determine packet id for " + packet.getClass(), e); } } @@ -530,4 +468,31 @@ public class PacketListener extends ChannelInboundHandlerAdapter { public void setServerWasPaused() { this.serverWasPaused = true; } + + private class DecodedPacketListener extends ChannelInboundHandlerAdapter { + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + + if (msg instanceof CustomPayloadS2CPacket) { + CustomPayloadS2CPacket packet = (CustomPayloadS2CPacket) msg; + if (Restrictions.PLUGIN_CHANNEL.equals(packet.getChannel())) { + save(new DisconnectS2CPacket(new LiteralText("Please update to view this replay."))); + } + } + + if (msg instanceof PlayerSpawnS2CPacket) { + //#if MC>=10800 + UUID uuid = ((PlayerSpawnS2CPacket) msg).getPlayerUuid(); + //#else + //$$ UUID uuid = ((S0CPacketSpawnPlayer) msg).func_148948_e().getId(); + //#endif + Set uuids = new HashSet<>(Arrays.asList(metaData.getPlayers())); + uuids.add(uuid.toString()); + metaData.setPlayers(uuids.toArray(new String[uuids.size()])); + saveMetaData(); + } + + super.channelRead(ctx, msg); + } + } } diff --git a/src/main/resources/mixins.recording.replaymod.json b/src/main/resources/mixins.recording.replaymod.json index 4d8edc84..5dec2e07 100644 --- a/src/main/resources/mixins.recording.replaymod.json +++ b/src/main/resources/mixins.recording.replaymod.json @@ -8,6 +8,7 @@ "EntityLivingBaseAccessor", "IntegratedServerAccessor", "NetworkManagerAccessor", + "MixinClientConnection", //#if MC<11500 //$$ "SPacketSpawnMobAccessor", //$$ "SPacketSpawnPlayerAccessor", From 814d0b7c17e4feff1a1f2d2f704eef52bcee3b30 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Wed, 15 Jun 2022 13:46:30 +0200 Subject: [PATCH 05/11] Update ReplayStudio Fixes fatal QuickMode error introduced with the 1.19 update. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index eef8dfdd..573347ee 100644 --- a/build.gradle +++ b/build.gradle @@ -346,7 +346,7 @@ dependencies { shadow 'com.github.ReplayMod.JavaBlend:2.79.0:a0696f8' - shadow "com.github.ReplayMod:ReplayStudio:39debfe", shadeExclusions + shadow "com.github.ReplayMod:ReplayStudio:74d8465", shadeExclusions // FIXME this should be pulled in by ReplayStudio, and IntelliJ sees it, but javac for some reason does not implementation 'com.github.viaversion:opennbt:0a02214' // 2.0-SNAPSHOT (ViaVersion Edition) From 40f07279cffe90d73351c8ba0333836eef425ed4 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 26 Jun 2022 11:57:24 +0200 Subject: [PATCH 06/11] Load tinyexr in its own class loader That way we can simply use whatever version we want and aren't tied to the version of lwjgl which MC provides. This fixes the OpenEXR export on 1.19 crashing either due to the windows workaround or due to differing lwjgl versions (depending on OS). And also enables OpenEXR export on MC versions using lwjgl2 (1.12.2 and below). --- build.gradle | 24 ++-- .../java/com/replaymod/render/EXRWriter.java | 11 +- .../com/replaymod/render/RenderSettings.java | 7 - ...in_WindowsWorkaroundForTinyEXRNatives.java | 81 ----------- .../render/rendering/VideoRenderer.java | 8 +- .../replaymod/render/utils/Lwjgl3Loader.java | 132 ++++++++++++++++++ .../resources/mixins.render.replaymod.json | 1 - 7 files changed, 156 insertions(+), 108 deletions(-) delete mode 100644 src/main/java/com/replaymod/render/mixin/Mixin_WindowsWorkaroundForTinyEXRNatives.java create mode 100644 src/main/java/com/replaymod/render/utils/Lwjgl3Loader.java diff --git a/build.gradle b/build.gradle index 573347ee..40ad0f52 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,5 @@ import com.replaymod.gradle.preprocess.PreprocessTask +import static gg.essential.gradle.util.PrebundleKt.prebundle buildscript { def mcVersion @@ -18,17 +19,17 @@ buildscript { name = "fabric" url = "https://maven.fabricmc.net/" } - if (!fabric) { - maven { - name = "forge" - url = "https://maven.minecraftforge.net" - } + maven { + name = "forge" + url = "https://maven.minecraftforge.net" } maven { name = "sonatype" url = "https://oss.sonatype.org/content/repositories/snapshots/" } maven { url 'https://jitpack.io' } + maven { url "https://maven.architectury.dev" } + maven { url "https://repo.essential.gg/repository/maven-public" } } dependencies { @@ -48,6 +49,7 @@ buildscript { } else { classpath 'com.github.ReplayMod:ForgeGradle:a8a9e0ca:all' // FG 1.2 } + classpath 'gg.essential:essential-gradle-toolkit:0.1.10' } } @@ -323,13 +325,13 @@ dependencies { shadow 'com.google.api-client:google-api-client-java6:1.20.0', shadeExclusions shadow 'com.google.oauth-client:google-oauth-client-jetty:1.20.0' - if (mcVersion >= 11400) { // need lwjgl 3 - for (suffix in ['', ':natives-linux', ':natives-windows', ':natives-macos']) { - shadow('org.lwjgl:lwjgl-tinyexr:3.2.2' + suffix) { - exclude group: 'org.lwjgl', module: 'lwjgl' // comes with MC - } - } + def lwjgl = configurations.create("lwjgl") + for (suffix in ['', ':natives-linux', ':natives-windows', ':natives-macos', ':natives-macos-arm64']) { + add(lwjgl.name, 'org.lwjgl:lwjgl:3.3.1' + suffix) + add(lwjgl.name, 'org.lwjgl:lwjgl-tinyexr:3.3.1' + suffix) } + compileOnly('org.lwjgl:lwjgl-tinyexr:3.3.1') + shadow(prebundle(project, lwjgl, "com/replaymod/render/utils/lwjgl.jar", {})) if (mcVersion < 11200) { // The version which MC ships is too old, we'll need to ship our own diff --git a/src/main/java/com/replaymod/render/EXRWriter.java b/src/main/java/com/replaymod/render/EXRWriter.java index 0bf981d8..17124ccc 100644 --- a/src/main/java/com/replaymod/render/EXRWriter.java +++ b/src/main/java/com/replaymod/render/EXRWriter.java @@ -1,4 +1,3 @@ -//#if MC>=11400 package com.replaymod.render; import com.replaymod.core.versions.MCVer; @@ -6,6 +5,7 @@ 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 com.replaymod.render.utils.Lwjgl3Loader; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; import net.minecraft.util.crash.CrashReport; import org.lwjgl.PointerBuffer; @@ -27,6 +27,14 @@ import static org.lwjgl.util.tinyexr.TinyEXR.*; public class EXRWriter implements FrameConsumer { + public static FrameConsumer create(Path outputFolder, boolean keepAlpha) { + return Lwjgl3Loader.createFrameConsumer( + EXRWriter.class, + new Class[]{ Path.class, boolean.class }, + new Object[]{ outputFolder, keepAlpha } + ); + } + private final Path outputFolder; private final boolean keepAlpha; @@ -128,4 +136,3 @@ public class EXRWriter implements FrameConsumer { public void close() { } } -//#endif diff --git a/src/main/java/com/replaymod/render/RenderSettings.java b/src/main/java/com/replaymod/render/RenderSettings.java index b358b718..f5e92ffb 100644 --- a/src/main/java/com/replaymod/render/RenderSettings.java +++ b/src/main/java/com/replaymod/render/RenderSettings.java @@ -105,13 +105,6 @@ public class RenderSettings { public boolean isSupported() { if (this == BLEND) { return RenderMethod.BLEND.isSupported(); - } else if (this == EXR) { - // Need LJWGL 3 - //#if MC>=11400 - return true; - //#else - //$$ return false; - //#endif } else { return true; } diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_WindowsWorkaroundForTinyEXRNatives.java b/src/main/java/com/replaymod/render/mixin/Mixin_WindowsWorkaroundForTinyEXRNatives.java deleted file mode 100644 index 3df81c08..00000000 --- a/src/main/java/com/replaymod/render/mixin/Mixin_WindowsWorkaroundForTinyEXRNatives.java +++ /dev/null @@ -1,81 +0,0 @@ -//#if MC>=11400 -package com.replaymod.render.mixin; - -import org.lwjgl.system.Library; -import org.lwjgl.system.Platform; -import org.lwjgl.util.tinyexr.TinyEXR; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.ModifyArg; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.function.Consumer; -import java.util.regex.Pattern; - -/** - * It appears like natives on Windows cannot be loaded if one of their dependencies has already been loaded by a - * different class loader. In our case we cannot load tinyexr (on the knot class loader) because lwjgl has already - * been loaded on the system class loader. - * - * If we force the tinyexr native to load on the system class loader (by calling `Library.loadSystem(absPath)`), - * it'll load but we'll get an error when we call any of the native methods. - * - * We can't really load TinyEXR itself via the system class loader because Java does not provide any methods for - * modifying the system class path at runtime and we'd have to use JVM-specific hacks. - * - * Strangely, if we use System.loadLibrary instead of System.load, then it all just works. This mixin implements - * that workaround by finding MC's natives folder, extracting the dll from our jar into that folder and then replacing - * the context class passed to Library.loadSystem (which it uses to find dlls in jars) with Library (which is on the - * system class loader) so it cannot find the dll in our jar and falls back to using System.loadLibrary. - */ -@Mixin(value = TinyEXR.class, remap = false) -public class Mixin_WindowsWorkaroundForTinyEXRNatives { - private static final String LOAD_SYSTEM_CONSUMERS = "Lorg/lwjgl/system/Library;loadSystem(Ljava/util/function/Consumer;Ljava/util/function/Consumer;Ljava/lang/Class;Ljava/lang/String;)V"; - - @ModifyArg(method = "", at = @At(value = "INVOKE", target = LOAD_SYSTEM_CONSUMERS)) - private static Class uglyWindowsHacks(Consumer load, Consumer loadLibrary, Class context, String name) throws IOException { - if (Platform.get() != Platform.WINDOWS) { - return context; // works out of the box on linux - } - - name = System.mapLibraryName(name); - - URL libURL = context.getClassLoader().getResource(name); - if (libURL == null) { - throw new UnsatisfiedLinkError("Failed to locate library: " + name); - } - - String lwjglLibName = Library.JNI_LIBRARY_NAME; - if (!lwjglLibName.endsWith(".dll")) { - lwjglLibName = System.mapLibraryName(lwjglLibName); - } - - String paths = System.getProperty("java.library.path"); - Path nativesDir = null; - for (String dir : Pattern.compile(File.pathSeparator).split(paths)) { - Path path = Paths.get(dir); - if (Files.isReadable(path.resolve(lwjglLibName))) { - nativesDir = path; - break; - } - } - if (nativesDir == null) { - throw new UnsatisfiedLinkError("Failed to locate natives folder in " + paths); - } - - Path libPath = nativesDir.resolve(name); - try (InputStream source = libURL.openStream()) { - Files.copy(source, libPath, StandardCopyOption.REPLACE_EXISTING); - } - - return Library.class; - } -} -//#endif diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index a6b31504..ff8048d2 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.core.versions.MCVer; import com.replaymod.pathing.player.AbstractTimelinePlayer; import com.replaymod.pathing.properties.TimestampProperty; import com.replaymod.render.CameraPathExporter; +import com.replaymod.render.EXRWriter; import com.replaymod.render.PNGWriter; import com.replaymod.render.RenderSettings; import com.replaymod.render.ReplayModRender; @@ -55,7 +56,6 @@ import org.lwjgl.opengl.GL11; //#endif //#if MC>=11400 -import com.replaymod.render.EXRWriter; import net.minecraft.client.gui.screen.Screen; import java.util.concurrent.CompletableFuture; //#else @@ -129,11 +129,7 @@ public class VideoRenderer implements RenderInfo { } else { FrameConsumer frameConsumer; if (settings.getEncodingPreset() == RenderSettings.EncodingPreset.EXR) { - //#if MC>=11400 - frameConsumer = new EXRWriter(settings.getOutputFile().toPath(), settings.isIncludeAlphaChannel()); - //#else - //$$ throw new UnsupportedOperationException("EXR requires LWJGL3"); - //#endif + frameConsumer = EXRWriter.create(settings.getOutputFile().toPath(), settings.isIncludeAlphaChannel()); } else if (settings.getEncodingPreset() == RenderSettings.EncodingPreset.PNG) { frameConsumer = new PNGWriter(settings.getOutputFile().toPath(), settings.isIncludeAlphaChannel()); } else { diff --git a/src/main/java/com/replaymod/render/utils/Lwjgl3Loader.java b/src/main/java/com/replaymod/render/utils/Lwjgl3Loader.java new file mode 100644 index 00000000..8c832acd --- /dev/null +++ b/src/main/java/com/replaymod/render/utils/Lwjgl3Loader.java @@ -0,0 +1,132 @@ +package com.replaymod.render.utils; + +import com.replaymod.core.ReplayMod; +import com.replaymod.render.rendering.Frame; +import com.replaymod.render.rendering.FrameConsumer; +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.ProtectionDomain; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; + +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; + +public class Lwjgl3Loader extends URLClassLoader { + static { registerAsParallelCapable(); } + private static Path tempJarFile; + private static Lwjgl3Loader instance; + + private final Set implClasses = new CopyOnWriteArraySet<>(); + + private Lwjgl3Loader(Path jarFile) throws IOException, ReflectiveOperationException { + super(new URL[] { jarFile.toUri().toURL() }, Lwjgl3Loader.class.getClassLoader()); + + // Need to use a different directory for natives than MC because native files can only be loaded once + Path nativesDir = ReplayMod.instance.folders.getCacheFolder().resolve("lwjgl-natives"); + + Class configClass = Class.forName("org.lwjgl.system.Configuration", true, this); + Object extractDirField = configClass.getField("SHARED_LIBRARY_EXTRACT_DIRECTORY").get(null); + Method setMethod = configClass.getMethod("set", Object.class); + setMethod.invoke(extractDirField, nativesDir.toAbsolutePath().toString()); + } + + private boolean canBeSharedWithMc(String name) { + if (name.startsWith("org.lwjgl.")) { + return false; // MC may have a different version + } + for (String implClass : implClasses) { + if (name.startsWith(implClass)) { + return false; // depends on above lwjgl + } + } + return true; + } + + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + if (!canBeSharedWithMc(name)) { + synchronized (getClassLoadingLock(name)) { + Class cls = findLoadedClass(name); + if (cls == null) { + cls = findClass(name); + } + if (resolve) { + resolveClass(cls); + } + return cls; + } + } else { + return super.loadClass(name, resolve); + } + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + try { + return super.findClass(name); + } catch (ClassNotFoundException e) { + String path = name.replace('.', '/').concat(".class"); + URL url = getParent().getResource(path); + if (url == null) { + throw e; + } + try { + byte[] bytes = IOUtils.toByteArray(url); + return defineClass(name, bytes, 0, bytes.length, (ProtectionDomain) null); + } catch (IOException e1) { + throw new ClassNotFoundException(name, e1); + } + } + } + + private static synchronized Path getJarFile() throws IOException { + if (tempJarFile == null) { + Path jarFile = Files.createTempFile("replaymod-lwjgl", ".jar"); + jarFile.toFile().deleteOnExit(); + try (InputStream in = Lwjgl3Loader.class.getResourceAsStream("lwjgl.jar")) { + if (in == null) { + throw new IOException("Failed to find embedded lwjgl.jar file."); + } + Files.copy(in, jarFile, REPLACE_EXISTING); + } + tempJarFile = jarFile; + } + return tempJarFile; + } + + public static synchronized Lwjgl3Loader instance() { + if (instance == null) { + try { + instance = new Lwjgl3Loader(getJarFile()); + } catch (IOException | ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + return instance; + } + + @SuppressWarnings("unchecked") + public static

FrameConsumer

createFrameConsumer( + Class> implClass, + Class[] parameterTypes, + Object[] args + ) { + try { + Lwjgl3Loader loader = instance(); + loader.implClasses.add(implClass.getName()); + Class realClass = Class.forName(implClass.getName(), true, loader); + Constructor constructor = realClass.getConstructor(parameterTypes); + return (FrameConsumer

) constructor.newInstance(args); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index ff833a38..8bd2c8b6 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -36,7 +36,6 @@ //#endif //#if MC>=11400 "Mixin_PreserveDepthDuringHandRendering", - "Mixin_WindowsWorkaroundForTinyEXRNatives", //#endif "GameRendererAccessor", "MainWindowAccessor", From 4f9a730b6d185b839de08a3a570940c06e353fc7 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 26 Jun 2022 12:28:07 +0200 Subject: [PATCH 07/11] Fix classic camera speed changing way too quickly (fixes #719) On my system, a single scroll tick results in 120 calls, which is fine for the vanilla camera controller because it has a range of 2000, but the classic controller only has a range of 36, making it impossible to select anything but the extremes. This commit changes the size of the range to match that of the vanilla controller. --- .../com/replaymod/replay/camera/ClassicCameraController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java b/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java index 316b4e25..4a1692fe 100644 --- a/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java +++ b/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java @@ -9,9 +9,9 @@ import static net.minecraft.util.math.MathHelper.sin; // TODO: Marius is responsible for this. Please, someone clean it up. public class ClassicCameraController implements CameraController { - private static final double SPEED_CHANGE = 0.5; private static final double LOWER_SPEED = 2; private static final double UPPER_SPEED = 20; + private static final double SPEED_CHANGE = (UPPER_SPEED - LOWER_SPEED) / 2000; private final CameraEntity camera; From a3f40493223f5ceae172e59ad007155069b51ceb Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 26 Jun 2022 12:30:23 +0200 Subject: [PATCH 08/11] Reduces minimum speed of classic camera controller Two blocks per second is still quite fast, so this commit reduces the minimum to a tenth of that, allowing for much finer control. --- .../com/replaymod/replay/camera/ClassicCameraController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java b/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java index 4a1692fe..1d28ce25 100644 --- a/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java +++ b/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java @@ -9,7 +9,7 @@ import static net.minecraft.util.math.MathHelper.sin; // TODO: Marius is responsible for this. Please, someone clean it up. public class ClassicCameraController implements CameraController { - private static final double LOWER_SPEED = 2; + private static final double LOWER_SPEED = 0.2; private static final double UPPER_SPEED = 20; private static final double SPEED_CHANGE = (UPPER_SPEED - LOWER_SPEED) / 2000; From 517591d72a060a01aa01e9786992091481a4cac8 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 26 Jun 2022 13:32:58 +0200 Subject: [PATCH 09/11] Encode OpenEXR and PNG frames in parallel --- .../advancedscreenshots/ScreenshotWriter.java | 5 ++ .../java/com/replaymod/render/EXRWriter.java | 5 ++ .../com/replaymod/render/FFmpegWriter.java | 5 ++ .../java/com/replaymod/render/PNGWriter.java | 5 ++ .../render/rendering/FrameConsumer.java | 2 + .../replaymod/render/rendering/Pipeline.java | 65 +++++++++++++------ .../replaymod/render/rendering/Pipelines.java | 5 ++ .../render/rendering/VideoRenderer.java | 15 ++++- 8 files changed, 87 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java index 70522b22..987e7839 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotWriter.java @@ -63,4 +63,9 @@ public class ScreenshotWriter implements FrameConsumer { public void close() throws IOException { } + + @Override + public boolean isParallelCapable() { + return false; + } } diff --git a/src/main/java/com/replaymod/render/EXRWriter.java b/src/main/java/com/replaymod/render/EXRWriter.java index 17124ccc..f2d9a921 100644 --- a/src/main/java/com/replaymod/render/EXRWriter.java +++ b/src/main/java/com/replaymod/render/EXRWriter.java @@ -135,4 +135,9 @@ public class EXRWriter implements FrameConsumer { @Override public void close() { } + + @Override + public boolean isParallelCapable() { + return true; + } } diff --git a/src/main/java/com/replaymod/render/FFmpegWriter.java b/src/main/java/com/replaymod/render/FFmpegWriter.java index f4e1381c..332f346c 100644 --- a/src/main/java/com/replaymod/render/FFmpegWriter.java +++ b/src/main/java/com/replaymod/render/FFmpegWriter.java @@ -134,6 +134,11 @@ public class FFmpegWriter implements FrameConsumer { } } + @Override + public boolean isParallelCapable() { + return false; + } + private void checkSize(ReadableDimension size) { checkSize(size.getWidth(), size.getHeight()); } diff --git a/src/main/java/com/replaymod/render/PNGWriter.java b/src/main/java/com/replaymod/render/PNGWriter.java index 525d154d..8912dcb0 100644 --- a/src/main/java/com/replaymod/render/PNGWriter.java +++ b/src/main/java/com/replaymod/render/PNGWriter.java @@ -71,4 +71,9 @@ public class PNGWriter implements FrameConsumer { @Override public void close() { } + + @Override + public boolean isParallelCapable() { + return true; + } } diff --git a/src/main/java/com/replaymod/render/rendering/FrameConsumer.java b/src/main/java/com/replaymod/render/rendering/FrameConsumer.java index fd74586c..ae654ca0 100644 --- a/src/main/java/com/replaymod/render/rendering/FrameConsumer.java +++ b/src/main/java/com/replaymod/render/rendering/FrameConsumer.java @@ -7,4 +7,6 @@ public interface FrameConsumer

extends Closeable { void consume(Map channels); + boolean isParallelCapable(); + } diff --git a/src/main/java/com/replaymod/render/rendering/Pipeline.java b/src/main/java/com/replaymod/render/rendering/Pipeline.java index cf7f057d..8696fe29 100644 --- a/src/main/java/com/replaymod/render/rendering/Pipeline.java +++ b/src/main/java/com/replaymod/render/rendering/Pipeline.java @@ -10,6 +10,7 @@ import net.minecraft.util.crash.CrashException; import net.minecraft.util.crash.CrashReport; import org.lwjgl.glfw.GLFW; +import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; @@ -25,8 +26,6 @@ public class Pipeline implements Runnable { private final FrameCapturer capturer; private final FrameProcessor processor; private final GlToAbsoluteDepthProcessor depthProcessor; - private int consumerNextFrame; - private final Object consumerLock = new Object(); private final FrameConsumer

consumer; private volatile boolean abort; @@ -35,7 +34,7 @@ public class Pipeline implements Runnable { this.worldRenderer = worldRenderer; this.capturer = capturer; this.processor = processor; - this.consumer = consumer; + this.consumer = new ParallelSafeConsumer<>(consumer); float near = 0.05f; float far = getMinecraft().options.viewDistance * 16 * 4; @@ -44,7 +43,6 @@ public class Pipeline implements Runnable { @Override public synchronized void run() { - consumerNextFrame = 0; int processors = Runtime.getRuntime().availableProcessors(); int processThreads = Math.max(1, processors - 2); // One processor for the main thread and one for ffmpeg, sorry OS :( ExecutorService processService = new ThreadPoolExecutor(processThreads, processThreads, @@ -106,7 +104,6 @@ public class Pipeline implements Runnable { @Override public void run() { try { - Integer frameId = null; Map processedChannels = new HashMap<>(); for (Map.Entry entry : rawChannels.entrySet()) { P processedFrame = processor.process(entry.getValue()); @@ -114,27 +111,57 @@ public class Pipeline implements Runnable { depthProcessor.process((BitmapFrame) processedFrame); } processedChannels.put(entry.getKey(), processedFrame); - frameId = processedFrame.getFrameId(); } - if (frameId == null) { + if (processedChannels.isEmpty()) { return; } - synchronized (consumerLock) { - while (consumerNextFrame != frameId) { - try { - consumerLock.wait(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - consumer.consume(processedChannels); - consumerNextFrame++; - consumerLock.notifyAll(); - } + consumer.consume(processedChannels); } catch (Throwable t) { CrashReport crashReport = CrashReport.create(t, "Processing frame"); MCVer.getMinecraft().setCrashReport(crashReport); } } } + + private static class ParallelSafeConsumer

implements FrameConsumer

{ + private final FrameConsumer

inner; + + private int nextFrame; + private final Object lock = new Object(); + + private ParallelSafeConsumer(FrameConsumer

inner) { + this.inner = inner; + } + + @Override + public void consume(Map channels) { + if (inner.isParallelCapable()) { + inner.consume(channels); + } else { + int frameId = channels.values().iterator().next().getFrameId(); + synchronized (lock) { + while (nextFrame != frameId) { + try { + lock.wait(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + inner.consume(channels); + nextFrame++; + lock.notifyAll(); + } + } + } + + @Override + public boolean isParallelCapable() { + return true; + } + + @Override + public void close() throws IOException { + inner.close(); + } + } } diff --git a/src/main/java/com/replaymod/render/rendering/Pipelines.java b/src/main/java/com/replaymod/render/rendering/Pipelines.java index e012fb41..bc65fba2 100644 --- a/src/main/java/com/replaymod/render/rendering/Pipelines.java +++ b/src/main/java/com/replaymod/render/rendering/Pipelines.java @@ -128,6 +128,11 @@ public class Pipelines { @Override public void close() { } + + @Override + public boolean isParallelCapable() { + return true; + } }; return new Pipeline<>(worldRenderer, capturer, new DummyProcessor<>(), consumer); } diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index ff8048d2..92021f8b 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -137,11 +137,19 @@ public class VideoRenderer implements RenderInfo { } ffmpegWriter = frameConsumer instanceof FFmpegWriter ? (FFmpegWriter) frameConsumer : null; FrameConsumer previewingFrameConsumer = new FrameConsumer() { + private int lastFrameId = -1; + @Override public void consume(Map channels) { BitmapFrame bgra = channels.get(Channel.BRGA); if (bgra != null) { - gui.updatePreview(bgra.getByteBuffer(), bgra.getSize()); + synchronized (this) { + int frameId = bgra.getFrameId(); + if (lastFrameId < frameId) { + lastFrameId = frameId; + gui.updatePreview(bgra.getByteBuffer(), bgra.getSize()); + } + } } frameConsumer.consume(channels); } @@ -150,6 +158,11 @@ public class VideoRenderer implements RenderInfo { public void close() throws IOException { frameConsumer.close(); } + + @Override + public boolean isParallelCapable() { + return frameConsumer.isParallelCapable(); + } }; this.renderingPipeline = Pipelines.newPipeline(settings.getRenderMethod(), this, previewingFrameConsumer); } From 08c86ce57487d8e8f10bcbc7a0f407a8396c447b Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 26 Jun 2022 13:33:13 +0200 Subject: [PATCH 10/11] Enable compression for OpenEXR if we have the cpu power for it --- src/main/java/com/replaymod/render/EXRWriter.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/replaymod/render/EXRWriter.java b/src/main/java/com/replaymod/render/EXRWriter.java index f2d9a921..2b072bda 100644 --- a/src/main/java/com/replaymod/render/EXRWriter.java +++ b/src/main/java/com/replaymod/render/EXRWriter.java @@ -35,6 +35,11 @@ public class EXRWriter implements FrameConsumer { ); } + // Compression is pretty slow, so we'll only use it when we've got enough cpu cores to make up for that + private static final int COMPRESSION = Runtime.getRuntime().availableProcessors() >= 8 + ? TINYEXR_COMPRESSIONTYPE_ZIPS + : TINYEXR_COMPRESSIONTYPE_NONE; + private final Path outputFolder; private final boolean keepAlpha; @@ -71,6 +76,7 @@ public class EXRWriter implements FrameConsumer { header.channels(channelInfos); header.pixel_types(pixelTypes); header.requested_pixel_types(requestedPixelTypes); + header.compression_type(COMPRESSION); // Some readers ignore this, so we use the most expected order memASCII("A", true, channelInfos.get(0).name()); From 7457f9c13bb4a538e588a8a280e425d1c90b3d89 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 26 Jun 2022 13:54:52 +0200 Subject: [PATCH 11/11] Increase maximum camera speed by about an order of magnitude --- .../com/replaymod/replay/camera/ClassicCameraController.java | 4 ++-- .../com/replaymod/replay/camera/VanillaCameraController.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java b/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java index 1d28ce25..26c5dfb0 100644 --- a/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java +++ b/src/main/java/com/replaymod/replay/camera/ClassicCameraController.java @@ -10,8 +10,8 @@ import static net.minecraft.util.math.MathHelper.sin; // TODO: Marius is responsible for this. Please, someone clean it up. public class ClassicCameraController implements CameraController { private static final double LOWER_SPEED = 0.2; - private static final double UPPER_SPEED = 20; - private static final double SPEED_CHANGE = (UPPER_SPEED - LOWER_SPEED) / 2000; + private static final double UPPER_SPEED = 200; + private static final double SPEED_CHANGE = (UPPER_SPEED - LOWER_SPEED) / 20000; private final CameraEntity camera; diff --git a/src/main/java/com/replaymod/replay/camera/VanillaCameraController.java b/src/main/java/com/replaymod/replay/camera/VanillaCameraController.java index 10354be0..6561436b 100644 --- a/src/main/java/com/replaymod/replay/camera/VanillaCameraController.java +++ b/src/main/java/com/replaymod/replay/camera/VanillaCameraController.java @@ -9,7 +9,7 @@ import net.minecraft.client.options.KeyBinding; * Camera controller performing vanilla creative-like camera movements. */ public class VanillaCameraController implements CameraController { - private static final int MAX_SPEED = 1000; + private static final int MAX_SPEED = 2000; private static final int MIN_SPEED = -1000; private static final Vector3f[] DIRECTIONS = new Vector3f[]{