diff --git a/build.gradle.kts b/build.gradle.kts index 261015d5..5dd08053 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -91,6 +91,7 @@ dependencies { 12104 -> "0.111.0+1.21.4" 12105 -> "0.119.9+1.21.5" 12107 -> "0.128.1+1.21.7" + 12110 -> "0.135.0+1.21.10" else -> throw UnsupportedOperationException() } val fabricApiModules = mutableListOf( @@ -169,6 +170,7 @@ dependencies { if (platform.isFabric) { val modMenuVersion = when { + mcVersion >= 12110 -> "16.0.0-rc.1" mcVersion >= 12107 -> "15.0.0-beta.3" mcVersion >= 12105 -> "14.0.0-rc.2" mcVersion >= 12104 -> "13.0.0-beta.1" diff --git a/gradle.properties b/gradle.properties index 5307edab..ac4cbd2a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ essential.defaults.loom=0 -essential.defaults.loom.fabric-loader=net.fabricmc:fabric-loader:0.16.14 +essential.defaults.loom.fabric-loader=net.fabricmc:fabric-loader:0.17.3 # Sets default memory used for gradle commands. Can be overridden by user or command line properties. # This is required to provide enough memory for the Minecraft decompilation process. diff --git a/jGui b/jGui index 2aa52916..84a8c543 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 2aa5291668aad88eb02c8d3a20063a060a4b0349 +Subproject commit 84a8c5438db578f5f7445bfe852770cc004af29a diff --git a/libs/ReplayStudio b/libs/ReplayStudio index 3fdc6c42..03d5609f 160000 --- a/libs/ReplayStudio +++ b/libs/ReplayStudio @@ -1 +1 @@ -Subproject commit 3fdc6c42e36041ae666bcba174a638569dc2791d +Subproject commit 03d5609f7729d735acb875e0e40371026f7fef0c diff --git a/root.gradle.kts b/root.gradle.kts index f11f809c..cdf2af2e 100755 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -3,7 +3,7 @@ import java.io.ByteArrayOutputStream plugins { id("gg.essential.multi-version.root") - id("gg.essential.loom") version "1.7.28" apply false + id("gg.essential.loom") version "1.7.35" apply false id("com.github.hierynomus.license") version "0.15.0" } @@ -204,6 +204,7 @@ defaultTasks("bundleJar") preprocess { strictExtraMappings.set(true) + val mc12110 = createNode("1.21.10", 12110, "yarn") val mc12107 = createNode("1.21.7", 12107, "yarn") val mc12105 = createNode("1.21.5", 12105, "yarn") val mc12104 = createNode("1.21.4", 12104, "yarn") @@ -237,6 +238,7 @@ preprocess { val mc10800 = createNode("1.8", 10800, "srg") val mc10710 = createNode("1.7.10", 10710, "srg") + mc12110.link(mc12107, file("versions/mapping-fabric-1.21.10-1.21.7.txt")) mc12107.link(mc12105) mc12105.link(mc12104, file("versions/mapping-fabric-1.21.5-1.21.4.txt")) mc12104.link(mc12102) diff --git a/settings.gradle.kts b/settings.gradle.kts index 0c43f946..6a8fe27c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -44,6 +44,7 @@ val jGuiVersions = listOf( "1.21.4", "1.21.5", "1.21.7", + "1.21.10", ) val replayModVersions = listOf( // "1.7.10", @@ -78,6 +79,7 @@ val replayModVersions = listOf( "1.21.4", "1.21.5", "1.21.7", + "1.21.10", ) rootProject.buildFileName = "root.gradle.kts" diff --git a/src/main/java/com/replaymod/core/KeyBindingRegistry.java b/src/main/java/com/replaymod/core/KeyBindingRegistry.java index 0d5f738e..2211d667 100644 --- a/src/main/java/com/replaymod/core/KeyBindingRegistry.java +++ b/src/main/java/com/replaymod/core/KeyBindingRegistry.java @@ -40,10 +40,14 @@ import java.util.function.Consumer; import java.util.function.Function; public class KeyBindingRegistry extends EventRegistrations { + //#if MC>=12109 + //$$ private static final KeyBinding.Category CATEGORY = KeyBinding.Category.create(identifier(MOD_ID, "general")); + //#else private static final String CATEGORY = "replaymod.title"; //#if FABRIC>=1 && MC<11600 //$$ static { net.fabricmc.fabric.api.client.keybinding.KeyBindingRegistry.INSTANCE.addCategory(CATEGORY); } //#endif + //#endif private final Map bindings = new HashMap<>(); private Set onlyInReplay = new HashSet<>(); diff --git a/src/main/java/com/replaymod/core/ReplayMod.java b/src/main/java/com/replaymod/core/ReplayMod.java index ed1535dc..ad8a8e53 100644 --- a/src/main/java/com/replaymod/core/ReplayMod.java +++ b/src/main/java/com/replaymod/core/ReplayMod.java @@ -258,6 +258,10 @@ public class ReplayMod implements Module, Scheduler { } private void printToChat(boolean warning, String message, Object... args) { + if (!mc.isOnThread()) { + runLater(() -> printToChat(warning, message, args)); + return; + } if (getSettingsRegistry().get(Setting.NOTIFICATIONS)) { // Some nostalgia: "§8[§6Replay Mod§8]§r Your message goes here" //#if MC>=10904 diff --git a/src/main/java/com/replaymod/core/mixin/MixinKeyboardListener.java b/src/main/java/com/replaymod/core/mixin/MixinKeyboardListener.java index bb497eda..1092592f 100644 --- a/src/main/java/com/replaymod/core/mixin/MixinKeyboardListener.java +++ b/src/main/java/com/replaymod/core/mixin/MixinKeyboardListener.java @@ -14,15 +14,20 @@ public class MixinKeyboardListener { private static final String ON_KEY_PRESSED = "Lnet/minecraft/client/options/KeyBinding;onKeyPressed(Lnet/minecraft/client/util/InputUtil$Key;)V"; @Inject(method = "onKey", at = @At(value = "INVOKE", target = ON_KEY_PRESSED), cancellable = true) + //#if MC>=12109 + //$$ private void beforeKeyBindingTick(long window, int action, net.minecraft.client.input.KeyInput mcKeyInput, CallbackInfo ci) { + //$$ KeyInput keyInput = new KeyInput(mcKeyInput); + //#else private void beforeKeyBindingTick(long windowPointer, int key, int scanCode, int action, int modifiers, CallbackInfo ci) { KeyInput keyInput = new KeyInput(key, scanCode, modifiers); + //#endif if (KeyEventCallback.EVENT.invoker().onKeyEvent(keyInput, action)) { ci.cancel(); } } @Inject(method = "onKey", at = @At(value = "INVOKE", target = ON_KEY_PRESSED, shift = At.Shift.AFTER)) - private void afterKeyBindingTick(long windowPointer, int key, int scanCode, int action, int modifiers, CallbackInfo ci) { + private void afterKeyBindingTick(CallbackInfo ci) { KeyBindingEventCallback.EVENT.invoker().onKeybindingEvent(); } } diff --git a/src/main/java/com/replaymod/core/mixin/MixinMinecraft.java b/src/main/java/com/replaymod/core/mixin/MixinMinecraft.java index f9f93277..2ed8c67e 100644 --- a/src/main/java/com/replaymod/core/mixin/MixinMinecraft.java +++ b/src/main/java/com/replaymod/core/mixin/MixinMinecraft.java @@ -8,6 +8,11 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +//#if MC>=12109 +//$$ import net.minecraft.network.PacketApplyBatcher; +//$$ import org.spongepowered.asm.mixin.Final; +//#endif + //#if MC>=11400 import com.replaymod.core.events.PostRenderCallback; import com.replaymod.core.events.PreRenderCallback; @@ -42,8 +47,14 @@ public abstract class MixinMinecraft } //#if MC>=11400 + //#if MC>=12109 + //$$ @Shadow @Final private PacketApplyBatcher packetApplyBatcher; + //#endif @Override public void replayModExecuteTaskQueue() { + //#if MC>=12109 + //$$ this.packetApplyBatcher.apply(); + //#endif runTasks(); } //#endif diff --git a/src/main/java/com/replaymod/core/utils/Utils.java b/src/main/java/com/replaymod/core/utils/Utils.java index 061598fe..21b55739 100644 --- a/src/main/java/com/replaymod/core/utils/Utils.java +++ b/src/main/java/com/replaymod/core/utils/Utils.java @@ -68,6 +68,11 @@ import java.util.function.Consumer; import static com.replaymod.core.versions.MCVer.getMinecraft; +//#if MC>=12109 +//$$ import com.replaymod.core.versions.MCVer.Keyboard; +//$$ import net.minecraft.client.input.SystemKeycodes; +//#endif + //#if MC>=12100 //$$ import net.minecraft.util.crash.ReportType; //#endif @@ -229,7 +234,9 @@ public class Utils { } public static boolean isCtrlDown() { - //#if MC>=11400 + //#if MC>=12109 + //$$ return Keyboard.isKeyDown(SystemKeycodes.LEFT_CTRL) || Keyboard.isKeyDown(SystemKeycodes.RIGHT_CTRL); + //#elseif MC>=11400 return Screen.hasControlDown(); //#else //$$ return Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL); diff --git a/src/main/java/com/replaymod/core/versions/LangResourcePack.java b/src/main/java/com/replaymod/core/versions/LangResourcePack.java index 03c0c74d..2bb31a29 100644 --- a/src/main/java/com/replaymod/core/versions/LangResourcePack.java +++ b/src/main/java/com/replaymod/core/versions/LangResourcePack.java @@ -190,6 +190,11 @@ public class LangResourcePack extends AbstractFileResourcePack { key = String.format(FABRIC_KEY_FORMAT, key.substring(LEGACY_KEY_PREFIX.length())); } //#endif + //#if MC>=12109 + if (key.equals("replaymod.title")) { + properties.put("key.category.replaymod.general", value); + } + //#endif properties.put(key, value); } diff --git a/src/main/java/com/replaymod/core/versions/MCVer.java b/src/main/java/com/replaymod/core/versions/MCVer.java index 651dd108..5945b188 100644 --- a/src/main/java/com/replaymod/core/versions/MCVer.java +++ b/src/main/java/com/replaymod/core/versions/MCVer.java @@ -622,7 +622,9 @@ public class MCVer { //#endif public static boolean isKeyDown(int keyCode) { - //#if MC>=11500 + //#if MC>=12109 + //$$ return InputUtil.isKeyPressed(getMinecraft().getWindow(), keyCode); + //#elseif MC>=11500 return InputUtil.isKeyPressed(getMinecraft().getWindow().getHandle(), keyCode); //#else //#if MC>=11400 diff --git a/src/main/java/com/replaymod/core/versions/Patterns.java b/src/main/java/com/replaymod/core/versions/Patterns.java index fb998515..ba8b193e 100644 --- a/src/main/java/com/replaymod/core/versions/Patterns.java +++ b/src/main/java/com/replaymod/core/versions/Patterns.java @@ -982,7 +982,9 @@ class Patterns { @Pattern public Identifier getSkinTexture(AbstractClientPlayerEntity player) { - //#if MC>=12002 + //#if MC>=12109 + //$$ return player.getSkin().body().texturePath(); + //#elseif MC>=12002 //$$ return player.getSkinTextures().texture(); //#else return player.getSkinTexture(); diff --git a/src/main/java/com/replaymod/recording/packet/PacketListener.java b/src/main/java/com/replaymod/recording/packet/PacketListener.java index 59a0d26a..99adeb71 100644 --- a/src/main/java/com/replaymod/recording/packet/PacketListener.java +++ b/src/main/java/com/replaymod/recording/packet/PacketListener.java @@ -191,7 +191,21 @@ public class PacketListener extends ChannelInboundHandlerAdapter { // Otherwise, injected packets may end up further down the packet stream than they were supposed to and other // inbound packets which may rely on the injected packet would behave incorrectly when played back. if (!mc.isOnThread()) { + // Note that we must use the same queue as regular packets, otherwise stuff will be out of order! + //#if MC>=12109 + //$$ mc.getPacketApplyBatcher().add(channel.pipeline().get(ClientConnection.class).getPacketListener(), new net.minecraft.network.packet.Packet<>() { + //$$ @Override + //$$ public net.minecraft.network.packet.PacketType> getPacketType() { + //$$ return null; + //$$ } + //$$ @Override + //$$ public void apply(net.minecraft.network.listener.PacketListener listener) { + //$$ save(packet); + //$$ } + //$$ }); + //#else mc.send(() -> save(packet)); + //#endif return; } try { diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index d3c5d21f..c872d550 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -40,6 +40,10 @@ import net.minecraft.util.crash.CrashException; import net.minecraft.sound.SoundCategory; import org.lwjgl.glfw.GLFW; +//#if MC>=12109 +//$$ import net.minecraft.client.gui.screen.Overlay; +//#endif + //#if MC>=12106 //$$ import com.replaymod.render.mixin.GameRendererAccessor; //$$ import net.minecraft.client.gui.render.GuiRenderer; @@ -335,13 +339,18 @@ public class VideoRenderer implements RenderInfo { //$$ Display.setResizable(false); //$$ } //#endif + //#if MC>=12109 + //$$ if (mc.debugHudEntryList.isF3Enabled()) { + //$$ mc.debugHudEntryList.setF3Enabled(false); + //#else if (mc.options.debugEnabled) { - debugInfoWasShown = true; //#if MC>=12002 //$$ mc.getDebugHud().toggleDebugHud(); //#else mc.options.debugEnabled = false; //#endif + //#endif + debugInfoWasShown = true; } //#if MC>=11400 if (mc.mouse.isCursorLocked()) { @@ -406,7 +415,9 @@ public class VideoRenderer implements RenderInfo { //$$ } //#endif if (debugInfoWasShown) { - //#if MC>=12002 + //#if MC>=12109 + //$$ mc.debugHudEntryList.setF3Enabled(true); + //#elseif MC>=12002 //$$ mc.getDebugHud().toggleDebugHud(); //#else mc.options.debugEnabled = true; @@ -453,6 +464,15 @@ public class VideoRenderer implements RenderInfo { while (mc.getOverlay() != null) { drawGui(); ((MinecraftMethodAccessor) mc).replayModExecuteTaskQueue(); + + //#if MC>=12109 + //$$ // The SplashOverlay now only closes on `tick`, but there are no ticks while we're waiting, + //$$ // so we need to manually tick it to not get stuck. + //$$ Overlay overlay = mc.getOverlay(); + //$$ if (overlay != null) { + //$$ overlay.tick(); + //$$ } + //#endif } CompletableFuture resourceReloadFuture = ((MinecraftAccessor) mc).getResourceReloadFuture(); diff --git a/src/main/java/com/replaymod/replay/FullReplaySender.java b/src/main/java/com/replaymod/replay/FullReplaySender.java index 6202afbc..521078e2 100644 --- a/src/main/java/com/replaymod/replay/FullReplaySender.java +++ b/src/main/java/com/replaymod/replay/FullReplaySender.java @@ -23,7 +23,6 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.OtherClientPlayerEntity; -import net.minecraft.client.gui.screen.DownloadingTerrainScreen; import net.minecraft.client.gui.screen.NoticeScreen; import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.Entity; @@ -56,6 +55,17 @@ import net.minecraft.util.math.Vec3d; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; +//#if MC>=12109 +//$$ import net.minecraft.network.ClientConnection; +//$$ import net.minecraft.network.listener.PacketListener; +//#endif + +//#if MC>=12109 +//$$ import net.minecraft.client.gui.screen.world.LevelLoadingScreen; +//#else +import net.minecraft.client.gui.screen.DownloadingTerrainScreen; +//#endif + //#if MC>=12105 //#else import net.minecraft.network.packet.s2c.play.ExperienceOrbSpawnS2CPacket; @@ -853,7 +863,11 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re if(!hasWorldLoaded) hasWorldLoaded = true; ReplayMod.instance.runLater(() -> { + //#if MC>=12109 + //$$ if (mc.currentScreen instanceof LevelLoadingScreen) { + //#else if (mc.currentScreen instanceof DownloadingTerrainScreen) { + //#endif // Close the world loading screen manually in case we swallow the packet mc.openScreen(null); } @@ -969,7 +983,7 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re return processPacketAsync(p); } else { Packet fp = p; - mc.send(() -> processPacketSync(fp)); + schedulePacketHandler(() -> processPacketSync(fp)); return p; } } @@ -1383,7 +1397,18 @@ public class FullReplaySender extends ChannelInboundHandlerAdapter implements Re if (mc.isOnThread()) { runnable.run(); } else { - //#if MC>=11400 + //#if MC>=12109 + //$$ mc.getPacketApplyBatcher().add(channel.pipeline().get(ClientConnection.class).getPacketListener(), new Packet<>() { + //$$ @Override + //$$ public net.minecraft.network.packet.PacketType> getPacketType() { + //$$ return null; + //$$ } + //$$ @Override + //$$ public void apply(PacketListener listener) { + //$$ runnable.run(); + //$$ } + //$$ }); + //#elseif MC>=11400 mc.execute(runnable); //#else //$$ mc.addScheduledTask(runnable); diff --git a/src/main/java/com/replaymod/replay/InputReplayTimer.java b/src/main/java/com/replaymod/replay/InputReplayTimer.java index dd64014f..cf577ad7 100644 --- a/src/main/java/com/replaymod/replay/InputReplayTimer.java +++ b/src/main/java/com/replaymod/replay/InputReplayTimer.java @@ -7,9 +7,17 @@ import com.replaymod.replay.camera.CameraEntity; import de.johni0702.minecraft.gui.versions.ScreenExt; import net.minecraft.client.MinecraftClient; +//#if MC>=12109 +//$$ import net.minecraft.client.gui.screen.Overlay; +//#endif + +//#if MC>=12109 +//$$ import net.minecraft.client.gui.screen.world.LevelLoadingScreen; +//#else //#if MC>=11802 //$$ import net.minecraft.client.gui.screen.DownloadingTerrainScreen; //#endif +//#endif //#if MC>=11400 import org.lwjgl.glfw.GLFW; @@ -92,11 +100,23 @@ public class InputReplayTimer { //#if MC>=11802 //$$ // As of 1.18.2, this screen always stays open for at least two seconds, and requires ticking to close. //$$ // Thanks, but we'll have none of that (at least while in a replay). + //#if MC>=12109 + //$$ if (mc.currentScreen instanceof LevelLoadingScreen) { + //#else //$$ if (mc.currentScreen instanceof DownloadingTerrainScreen) { + //#endif //$$ mc.currentScreen.close(); //$$ } //#endif + //#if MC>=12109 + //$$ // The SplashOverlay now only closes on `tick`, but there are no ticks while the replay is paused. + //$$ // so we need to manually tick it to not get stuck. + //$$ Overlay overlay = mc.getOverlay(); + //$$ if (overlay != null) { + //$$ overlay.tick(); + //$$ } + //#endif } } diff --git a/src/main/java/com/replaymod/replay/ReplayHandler.java b/src/main/java/com/replaymod/replay/ReplayHandler.java index 5b6454df..c6675484 100644 --- a/src/main/java/com/replaymod/replay/ReplayHandler.java +++ b/src/main/java/com/replaymod/replay/ReplayHandler.java @@ -31,7 +31,6 @@ import io.netty.channel.ChannelOutboundHandlerAdapter; import io.netty.channel.ChannelPromise; import io.netty.channel.embedded.EmbeddedChannel; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.DownloadingTerrainScreen; import net.minecraft.client.network.ClientLoginNetworkHandler; import net.minecraft.client.util.Window; import net.minecraft.network.DecoderHandler; @@ -45,6 +44,12 @@ import net.minecraft.network.ClientConnection; import java.io.IOException; import java.util.*; +//#if MC>=12109 +//$$ import net.minecraft.client.gui.screen.world.LevelLoadingScreen; +//#else +import net.minecraft.client.gui.screen.DownloadingTerrainScreen; +//#endif + //#if MC>=12106 //$$ import com.replaymod.render.mixin.GameRendererAccessor; //$$ import net.minecraft.client.gui.render.state.GuiRenderState; @@ -373,7 +378,11 @@ public class ReplayHandler { // We don't send any packets (there is no server to receive them), so we need to switch manually. //#if MC>=12006 //$$ networkManager.transitionInbound(LoginStates.S2C, new ClientLoginNetworkHandler( - //$$ networkManager, mc, null, null, false, null, it -> {}, null + //$$ networkManager, mc, null, null, false, null, it -> {}, + //#if MC>=12109 + //$$ new net.minecraft.client.world.ClientChunkLoadProgress(), + //#endif + //$$ null //$$ )); //$$ networkManager.transitionOutbound(LoginStates.C2S); //#else @@ -697,7 +706,11 @@ public class ReplayHandler { do { replaySender.sendPacketsTill(targetTime); targetTime += 500; + //#if MC>=12109 + //$$ } while (mc.player == null || mc.currentScreen instanceof LevelLoadingScreen); + //#else } while (mc.player == null || mc.currentScreen instanceof DownloadingTerrainScreen); + //#endif replaySender.setAsyncMode(true); for (int i = 0; i < Math.min(diff / 50, 3); i++) { @@ -852,7 +865,11 @@ public class ReplayHandler { do { replaySender.sendPacketsTill(targetTime); targetTime += 500; + //#if MC>=12109 + //$$ } while (mc.player == null || mc.currentScreen instanceof LevelLoadingScreen); + //#else } while (mc.player == null || mc.currentScreen instanceof DownloadingTerrainScreen); + //#endif replaySender.setAsyncMode(true); replaySender.setReplaySpeed(0); diff --git a/src/main/java/com/replaymod/replay/camera/CameraEntity.java b/src/main/java/com/replaymod/replay/camera/CameraEntity.java index 1e16cf61..e6d5acac 100644 --- a/src/main/java/com/replaymod/replay/camera/CameraEntity.java +++ b/src/main/java/com/replaymod/replay/camera/CameraEntity.java @@ -30,6 +30,12 @@ import net.minecraft.item.ItemStack; import net.minecraft.stat.StatHandler; import net.minecraft.util.Identifier; import net.minecraft.util.math.Box; +import net.minecraft.world.World; + +//#if MC>=12109 +//$$ import net.minecraft.client.network.ClientPlayerLikeEntity; +//$$ import net.minecraft.entity.PlayerLikeEntity; +//#endif //#if MC>=12106 //$$ import net.minecraft.util.PlayerInput; @@ -322,15 +328,18 @@ public class CameraEntity // This is important if the spectated player respawns as their // entity is recreated and we have to spectate a new entity UUID spectating = ReplayModReplay.instance.getReplayHandler().getSpectatedUUID(); + // FIXME remap bug: Pattern doesn't work when these two are inlined + World cameraWorld = this.world; + World viewWorld = view.world; if (spectating != null && (view.getUuid() != spectating - || view.world != this.world) - || this.world.getEntityById(view.getEntityId()) != view) { + || viewWorld != cameraWorld) + || cameraWorld.getEntityById(view.getEntityId()) != view) { if (spectating == null) { // Entity (non-player) died, stop spectating ReplayModReplay.instance.getReplayHandler().spectateEntity(this); return; } - view = this.world.getPlayerByUuid(spectating); + view = cameraWorld.getPlayerByUuid(spectating); if (view != null) { this.client.setCameraEntity(view); } else { @@ -502,7 +511,16 @@ public class CameraEntity return super.isInvisible(); } - //#if MC>=12002 + //#if MC>=12109 + //$$ @Override + //$$ public SkinTextures getSkin() { + //$$ Entity view = this.client.getCameraEntity(); + //$$ if (view != this && view instanceof ClientPlayerLikeEntity) { + //$$ return ((ClientPlayerLikeEntity) view).getSkin(); + //$$ } + //$$ return super.getSkin(); + //$$ } + //#elseif MC>=12002 //$$ @Override //$$ public SkinTextures getSkinTextures() { //$$ Entity view = this.client.getCameraEntity(); @@ -533,7 +551,16 @@ public class CameraEntity //#endif //#endif - //#if MC>=10800 + //#if MC>=12109 + //$$ @Override + //$$ public boolean isModelPartVisible(PlayerModelPart modelPart) { + //$$ Entity view = this.client.getCameraEntity(); + //$$ if (view != this && view instanceof PlayerLikeEntity) { + //$$ return ((PlayerLikeEntity) view).isModelPartVisible(modelPart); + //$$ } + //$$ return super.isModelPartVisible(modelPart); + //$$ } + //#elseif MC>=10800 @Override public boolean isPartVisible(PlayerModelPart modelPart) { Entity view = this.client.getCameraEntity(); diff --git a/versions/1.20.2/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java b/versions/1.20.2/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java index be2f6f38..a278a9e4 100644 --- a/versions/1.20.2/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java +++ b/versions/1.20.2/src/main/java/com/replaymod/render/mixin/Mixin_ForceChunkLoading.java @@ -31,6 +31,12 @@ import java.util.concurrent.TimeoutException; public abstract class Mixin_ForceChunkLoading implements IForceChunkLoading { private ForceChunkLoadingHook replayModRender_hook; + //#if MC>=12109 + //$$ private static final String SETUP_TERRAIN = "Lnet/minecraft/client/render/WorldRenderer;method_74752(Lnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/Frustum;Z)V"; + //#else + private static final String SETUP_TERRAIN = "Lnet/minecraft/client/render/WorldRenderer;setupTerrain(Lnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/Frustum;ZZ)V"; + //#endif + @Override public void replayModRender_setHook(ForceChunkLoadingHook hook) { this.replayModRender_hook = hook; @@ -40,18 +46,28 @@ public abstract class Mixin_ForceChunkLoading implements IForceChunkLoading { @Shadow @Final private ChunkRenderingDataPreparer field_45615; + //#if MC>=12109 + //$$ @Shadow protected abstract void method_74752(Camera par1, Frustum par2, boolean par3); + //#else @Shadow protected abstract void setupTerrain(Camera par1, Frustum par2, boolean par3, boolean par4); @Shadow private Frustum frustum; @Shadow private Frustum capturedFrustum; + //#endif @Shadow @Final private MinecraftClient client; @Shadow protected abstract void applyFrustum(Frustum par1); - @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;setupTerrain(Lnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/Frustum;ZZ)V")) - private void forceAllChunks(CallbackInfo ci, @Local(argsOnly = true) Camera camera) { + @Inject(method = "render", at = @At(value = "INVOKE", target = SETUP_TERRAIN)) + private void forceAllChunks( + CallbackInfo ci, + //#if MC>=12109 + //$$ @Local Frustum frustum, + //#endif + @Local(argsOnly = true) Camera camera + ) { if (replayModRender_hook == null) { return; } @@ -69,7 +85,11 @@ public abstract class Mixin_ForceChunkLoading implements IForceChunkLoading { boolean areWeDoneYet = true; // Determine which chunks shall be visible + //#if MC>=12109 + //$$ method_74752(camera, frustum, this.client.player.isSpectator()); + //#else setupTerrain(camera, this.frustum, this.capturedFrustum != null, this.client.player.isSpectator()); + //#endif // Wait for async processing to be complete Future fullUpdateFuture = renderingDataAcc.fullUpdateFuture(); diff --git a/versions/1.21.10/.gitkeep b/versions/1.21.10/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/versions/1.21.10/gradle.properties b/versions/1.21.10/gradle.properties new file mode 100644 index 00000000..e48a92a5 --- /dev/null +++ b/versions/1.21.10/gradle.properties @@ -0,0 +1,3 @@ +essential.defaults.loom.minecraft=com.mojang:minecraft:1.21.10 +essential.defaults.loom.mappings=net.fabricmc:yarn:1.21.10+build.2:v2 +essential.loom.disableUnpick=true diff --git a/versions/1.21.10/src/main/java/com/replaymod/render/mixin/MixinParticleManager.java b/versions/1.21.10/src/main/java/com/replaymod/render/mixin/MixinParticleManager.java new file mode 100644 index 00000000..1e3c87e9 --- /dev/null +++ b/versions/1.21.10/src/main/java/com/replaymod/render/mixin/MixinParticleManager.java @@ -0,0 +1,60 @@ +package com.replaymod.render.mixin; + +import com.llamalad7.mixinextras.sugar.Local; +import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalRef; +import com.replaymod.core.versions.MCVer; +import com.replaymod.render.hooks.EntityRendererHandler; +import net.minecraft.client.particle.BillboardParticle; +import net.minecraft.client.particle.BillboardParticleSubmittable; +import net.minecraft.client.render.Camera; +import net.minecraft.util.math.Vec3d; +import org.joml.Quaternionf; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(BillboardParticle.class) +public abstract class MixinParticleManager { + @Shadow public abstract void render(BillboardParticleSubmittable par1, Camera par2, float par3); + + @Inject(method = "render(Lnet/minecraft/client/particle/BillboardParticleSubmittable;Lnet/minecraft/client/render/Camera;F)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/BillboardParticle$Rotator;setRotation(Lorg/joml/Quaternionf;Lnet/minecraft/client/render/Camera;F)V")) + private void faceCameraAtParticle( + CallbackInfo ci, + @Local(argsOnly = true) float partialTicks, + @Local(argsOnly = true) Camera camera, + @Share("orgRotation") LocalRef orgRotationRef + ) { + EntityRendererHandler handler = ((EntityRendererHandler.IEntityRenderer) MCVer.getMinecraft().gameRenderer).replayModRender_getHandler(); + if (handler == null || !handler.omnidirectional) { + return; + } + + Quaternionf rotation = camera.getRotation(); + orgRotationRef.set(new Quaternionf(rotation)); + + Vec3d from = new Vec3d(0, 0, -1); + Vec3d to = MCVer.getPosition((BillboardParticle)(Object) this, partialTicks) + .subtract(camera.getPos()) + .normalize(); + Vec3d axis = from.crossProduct(to); + rotation.set((float) axis.x, (float) axis.y, (float) axis.z, (float) (1 + from.dotProduct(to))); + rotation.normalize(); + } + + @Inject(method = "render(Lnet/minecraft/client/particle/BillboardParticleSubmittable;Lnet/minecraft/client/render/Camera;F)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/BillboardParticle$Rotator;setRotation(Lorg/joml/Quaternionf;Lnet/minecraft/client/render/Camera;F)V", shift = At.Shift.AFTER)) + private void faceCameraAtParticleCleanup( + CallbackInfo ci, + @Local(argsOnly = true) Camera camera, + @Share("orgRotation") LocalRef orgRotationRef + ) { + Quaternionf orgRotation = orgRotationRef.get(); + if (orgRotation == null) { + return; + } + + camera.getRotation().set(orgRotation.x, orgRotation.y, orgRotation.z, orgRotation.w); + } +} diff --git a/versions/1.21.10/src/main/java/com/replaymod/render/mixin/MixinRenderManager.java b/versions/1.21.10/src/main/java/com/replaymod/render/mixin/MixinRenderManager.java new file mode 100644 index 00000000..d23609d7 --- /dev/null +++ b/versions/1.21.10/src/main/java/com/replaymod/render/mixin/MixinRenderManager.java @@ -0,0 +1,38 @@ +package com.replaymod.render.mixin; + +import com.llamalad7.mixinextras.sugar.Local; +import com.llamalad7.mixinextras.sugar.ref.LocalRef; +import com.replaymod.core.versions.MCVer; +import com.replaymod.render.hooks.EntityRendererHandler; +import net.minecraft.client.render.entity.EntityRenderManager; +import net.minecraft.client.render.state.CameraRenderState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(EntityRenderManager.class) +public abstract class MixinRenderManager { + @Inject(method = "render", at = @At("HEAD")) + private void replayModRender_reorientForCubicRendering( + CallbackInfo ci, + @Local(argsOnly = true, ordinal = 0) double dx, + @Local(argsOnly = true, ordinal = 1) double dy, + @Local(argsOnly = true, ordinal = 2) double dz, + @Local(argsOnly = true) LocalRef cameraRenderStateRef + ) { + EntityRendererHandler handler = ((EntityRendererHandler.IEntityRenderer) MCVer.getMinecraft().gameRenderer).replayModRender_getHandler(); + if (handler == null || !handler.omnidirectional) { + return; + } + + CameraRenderState org = cameraRenderStateRef.get(); + CameraRenderState copy = new CameraRenderState(); + copy.blockPos = org.blockPos; + copy.pos = org.pos; + copy.initialized = org.initialized; + copy.entityPos = org.entityPos; + copy.orientation.lookAlong((float) dx, (float) dy, (float) dz, 0f, 1f, 0f); + cameraRenderStateRef.set(copy); + } +} diff --git a/versions/mapping-fabric-1.21.10-1.21.7.txt b/versions/mapping-fabric-1.21.10-1.21.7.txt new file mode 100644 index 00000000..38a54161 --- /dev/null +++ b/versions/mapping-fabric-1.21.10-1.21.7.txt @@ -0,0 +1,9 @@ +net.minecraft.util.HeldItemContext getEntityWorld() net.minecraft.entity.Entity getWorld() +net.minecraft.util.HeldItemContext getEntityPos() net.minecraft.entity.Entity getPos() +net.minecraft.client.network.ClientPlayerLikeEntity getSkin() net.minecraft.client.network.AbstractClientPlayerEntity getSkinTextures() +net.minecraft.entity.PlayerLikeEntity isModelPartVisible() net.minecraft.entity.player.PlayerEntity isPartVisible() + +com.mojang.authlib.GameProfile com.mojang.authlib.GameProfile +com.mojang.authlib.GameProfile id() getId()Ljava/util/UUID; +com.mojang.authlib.GameProfile name() getName()Ljava/lang/String; +com.mojang.authlib.GameProfile properties() getProperties()Lcom/mojang/authlib/properties/PropertyMap;