From dcf5eb3cb181815e9502b9f8751ad8ad4b5d57b8 Mon Sep 17 00:00:00 2001 From: craisinlord Date: Wed, 7 Oct 2026 22:14:16 -0500 Subject: [PATCH] portal guns WORK NOW BABYYYYYYY --- .../client/PortalGunCrosshairRenderer.java | 116 -- .../renderer/PortalGunPortalRendererPool.java | 183 --- .../PortalGunPortalSceneRenderer.java | 233 +++ .../renderer/PortalGunPortalSectionViews.java | 165 +++ .../PortalGunPortalViewAreaManager.java | 386 ----- .../renderer/PortalGunPortalViewRenderer.java | 1281 +++++------------ .../renderer/PortalGunProxySceneRenderer.java | 246 ---- .../client/renderer/PortalRenderWatchdog.java | 56 + .../renderer/PortalSectionGraphMarker.java | 5 + .../client/renderer/PortalStencilTarget.java | 209 +-- .../client/renderer/PortalTerrain.java | 33 + .../renderer/PortalViewSectionMarker.java | 7 - .../content/client/renderer/SodiumCompat.java | 124 +- .../client/renderer/VanillaPortalTerrain.java | 134 ++ .../renderer/sodium/SodiumPortalTerrain.java | 208 +++ .../content/entity/DrTrayaurusEntity.java | 2 +- .../trades/DrTrayaurusTradeManager.java | 74 +- .../portalgun/PortalGunPortalEntity.java | 31 +- .../portalgun/PortalGunProjectionUtil.java | 14 +- .../antarchy/mixins/AntarchyMixinPlugin.java | 13 - .../PortalGunPlayerMovePacketMixin.java | 56 + ...verGamePacketListenerTeleportAccessor.java | 12 + .../LevelRendererPortalChunkBudgetMixin.java | 73 - .../LevelRendererPortalLifecycleMixin.java | 28 +- .../LevelRendererPortalSceneInvoker.java | 12 - .../LevelRendererPortalTargetsAccessor.java | 15 - .../LevelRendererPortalViewAreaMixin.java | 37 +- .../MinecraftPortalTransparencyMixin.java | 18 + .../client/PortalViewChunkCacheMixin.java | 4 +- .../client/PortalViewSectionSortingMixin.java | 42 - .../client/PostChainTargetAccessor.java | 17 - .../SectionOcclusionGraphPortalMixin.java | 35 + ...RenderDispatcherPortalUploadsAccessor.java | 12 - .../client/SodiumWorldRendererMixin.java | 19 - .../sodium/RenderSectionManagerAccessor.java | 32 + .../RenderSectionManagerPortalTasksMixin.java | 24 + .../sodium/SodiumWorldRendererAccessor.java | 18 + .../resources/antarchy-common.mixins.json | 11 +- .../resources/antarchy-sodium.mixins.json | 4 +- .../textures/gui/portal_gun_crosshair.png | Bin 341 -> 0 bytes fabric-1.21.1/build.gradle | 5 + .../client/AntarchyFabricClientBootstrap.java | 2 - neoforge-1.21.1/build.gradle | 5 + .../client/AntarchyNeoForgeClient.java | 6 - 44 files changed, 1566 insertions(+), 2441 deletions(-) delete mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/PortalGunCrosshairRenderer.java delete mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalRendererPool.java create mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalSceneRenderer.java create mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalSectionViews.java delete mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalViewAreaManager.java delete mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunProxySceneRenderer.java create mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalRenderWatchdog.java create mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalSectionGraphMarker.java create mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalTerrain.java delete mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalViewSectionMarker.java create mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/VanillaPortalTerrain.java create mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/sodium/SodiumPortalTerrain.java create mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/PortalGunPlayerMovePacketMixin.java create mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/ServerGamePacketListenerTeleportAccessor.java delete mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalChunkBudgetMixin.java delete mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalTargetsAccessor.java create mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/MinecraftPortalTransparencyMixin.java delete mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/PortalViewSectionSortingMixin.java delete mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/PostChainTargetAccessor.java create mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/SectionOcclusionGraphPortalMixin.java delete mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/SectionRenderDispatcherPortalUploadsAccessor.java delete mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/SodiumWorldRendererMixin.java create mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/compat/sodium/RenderSectionManagerAccessor.java create mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/compat/sodium/RenderSectionManagerPortalTasksMixin.java create mode 100644 common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/compat/sodium/SodiumWorldRendererAccessor.java delete mode 100644 common-1.21.1/src/main/resources/assets/antarchy/textures/gui/portal_gun_crosshair.png diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/PortalGunCrosshairRenderer.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/PortalGunCrosshairRenderer.java deleted file mode 100644 index cf680add..00000000 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/PortalGunCrosshairRenderer.java +++ /dev/null @@ -1,116 +0,0 @@ -package com.craisinlord.antarchy.content.client; - -import com.craisinlord.antarchy.Antarchy; -import com.craisinlord.antarchy.content.item.PortalGunItem; -import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity; -import com.craisinlord.antarchy.content.client.PortalGunIndicatorClientState; -import com.craisinlord.antarchy.content.network.PortalGunIndicatorPayload; -import com.craisinlord.antarchy.config.AntarchySettings; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.AABB; - -public final class PortalGunCrosshairRenderer { - private static final ResourceLocation CROSSHAIR = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/gui/portal_gun_crosshair.png"); - private static final int WIDTH = 34; - private static final int HEIGHT = 33; - private static ClientLevel cachedLevel; - private static long cachedGameTime = Long.MIN_VALUE; - private static UUID cachedOwnerId; - private static Set cachedPortals = Set.of(); - - private PortalGunCrosshairRenderer() { - } - - public static void render(GuiGraphics guiGraphics) { - Minecraft minecraft = Minecraft.getInstance(); - if (PortalGunGrabClientState.isActive()) { - return; - } - if (minecraft.player == null || minecraft.screen != null || minecraft.options.hideGui || !minecraft.options.getCameraType().isFirstPerson()) { - return; - } - ItemStack held = minecraft.player.getMainHandItem(); - if (!(held.getItem() instanceof PortalGunItem)) { - held = minecraft.player.getOffhandItem(); - if (!(held.getItem() instanceof PortalGunItem)) { - return; - } - } - UUID gunId = PortalGunItem.getGunId(held); - UUID ownerId = PortalGunItem.getPortalOwnerId(held, minecraft.player.getUUID()); - String channelName = PortalGunItem.getChannelName(held); - PortalGunIndicatorClientState.requestIfNeeded(minecraft, gunId); - Set portals = portalsFor(minecraft, ownerId, channelName); - PortalGunIndicatorPayload serverState = PortalGunIndicatorClientState.get(gunId); - boolean blueAvailable = serverState == null - ? portals.contains(new PortalKey(channelName, PortalGunPortalEntity.PortalSide.BLUE)) - : serverState.blueAvailable(); - boolean orangeAvailable = serverState == null - ? portals.contains(new PortalKey(channelName, PortalGunPortalEntity.PortalSide.ORANGE)) - : serverState.orangeAvailable(); - - int left = (minecraft.getWindow().getGuiScaledWidth() - WIDTH) / 2; - int top = (minecraft.getWindow().getGuiScaledHeight() - HEIGHT) / 2; - guiGraphics.blit(CROSSHAIR, left + 6, top, 0.0F, 0.0F, 17, HEIGHT, WIDTH, HEIGHT); - guiGraphics.blit(CROSSHAIR, left + 11, top, 17.0F, 0.0F, 17, HEIGHT, WIDTH, HEIGHT); - if (!blueAvailable) { - guiGraphics.fill(left + 6, top, left + 23, top + HEIGHT, 0x99000000); - } - if (!orangeAvailable) { - guiGraphics.fill(left + 11, top, left + 28, top + HEIGHT, 0x99000000); - } - int indicatorSize = AntarchySettings.portalGunIndicatorSize(); - if (indicatorSize > 0) { - int dot = Math.max(1, Math.round(HEIGHT * indicatorSize / 100.0F)); - int gap = Math.max(1, dot / 3); - int indicatorLeft = left + (WIDTH - dot * 2 - gap) / 2; - int indicatorTop = top + HEIGHT + 2; - guiGraphics.fill(indicatorLeft, indicatorTop, indicatorLeft + dot, indicatorTop + dot, - blueAvailable ? 0xFF21A8FF : 0xFF33414A); - int orangeLeft = indicatorLeft + dot + gap; - guiGraphics.fill(orangeLeft, indicatorTop, orangeLeft + dot, indicatorTop + dot, - orangeAvailable ? 0xFFFF8A24 : 0xFF4A4035); - } - } - - private static Set portalsFor(Minecraft minecraft, UUID ownerId, String channelName) { - ClientLevel level = minecraft.level; - long gameTime = level.getGameTime(); - if (cachedLevel != level || cachedGameTime != gameTime || !ownerId.equals(cachedOwnerId)) { - Set portals = new HashSet<>(); - if (minecraft.player != null) { - AABB bounds = minecraft.player.getBoundingBox().inflate(128.0D); - for (PortalGunPortalEntity portal : level.getEntitiesOfClass(PortalGunPortalEntity.class, bounds, Entity::isAlive)) { - UUID portalOwnerId = portal.getOwnerId(); - String portalChannelName = portal.getChannelName(); - if (ownerId.equals(portalOwnerId) && portalChannelName != null && !portalChannelName.isEmpty()) { - portals.add(new PortalKey(portalChannelName, portal.getPortalSide())); - if (portal.getLinkedPortalId() != null) { - portals.add(new PortalKey(portalChannelName, PortalGunPortalEntity.PortalSide.BLUE)); - portals.add(new PortalKey(portalChannelName, PortalGunPortalEntity.PortalSide.ORANGE)); - } - } - } - } - cachedLevel = level; - cachedGameTime = gameTime; - cachedOwnerId = ownerId; - cachedPortals = Set.copyOf(portals); - } - if (channelName == null || channelName.isEmpty()) { - return Set.of(); - } - return cachedPortals; - } - - private record PortalKey(String channelName, PortalGunPortalEntity.PortalSide side) { - } -} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalRendererPool.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalRendererPool.java deleted file mode 100644 index ece84b9f..00000000 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalRendererPool.java +++ /dev/null @@ -1,183 +0,0 @@ -package com.craisinlord.antarchy.content.client.renderer; - -import com.craisinlord.antarchy.mixins.client.SectionRenderDispatcherPortalUploadsAccessor; -import java.util.ArrayList; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.RenderBuffers; -import net.minecraft.client.renderer.chunk.RenderRegionCache; -import net.minecraft.client.renderer.chunk.SectionRenderDispatcher; - -public final class PortalGunPortalRendererPool { - private static final int MAX_RENDERERS = 8; - private static final long PORTAL_SECTION_BUDGET_NANOS = 4_166_666L; - private static final long PORTAL_UPLOAD_BUDGET_NANOS = 1_000_000L; - private static final int MAX_PORTAL_UPLOADS_PER_FRAME = 16; - private static final RenderBuffers PORTAL_RENDER_BUFFERS = new RenderBuffers(2); - private static final LinkedHashMap RENDERERS = new LinkedHashMap<>(8, 0.75F, true); - private static final Set PROXY_RENDERERS = java.util.Collections.newSetFromMap(new IdentityHashMap<>()); - private static final ThreadLocal SECTION_BUDGET_DEADLINE = ThreadLocal.withInitial(() -> 0L); - private static final ThreadLocal SCHEDULED_SECTION_REBUILDS = ThreadLocal.withInitial(() -> 0); - private static final ThreadLocal SKIP_SET_NOT_DIRTY = ThreadLocal.withInitial(() -> false); - private static final ThreadLocal UPLOADED_THIS_FRAME = ThreadLocal.withInitial(() -> 0); - private static ClientLevel ownerLevel; - - private PortalGunPortalRendererPool() { - } - - public static LevelRenderer acquire(Minecraft minecraft, UUID destinationId, int width, int height) { - if (ownerLevel != minecraft.level) { - clear(); - ownerLevel = minecraft.level; - } - PortalRenderer state = RENDERERS.get(destinationId); - if (state == null) { - LevelRenderer renderer = new LevelRenderer( - minecraft, - minecraft.getEntityRenderDispatcher(), - minecraft.getBlockEntityRenderDispatcher(), - PORTAL_RENDER_BUFFERS - ); - PROXY_RENDERERS.add(renderer); - renderer.setLevel(minecraft.level); - renderer.resize(width, height); - state = new PortalRenderer(renderer, width, height); - RENDERERS.put(destinationId, state); - trim(); - } else if (state.width() != width || state.height() != height) { - state.renderer().resize(width, height); - RENDERERS.put(destinationId, new PortalRenderer(state.renderer(), width, height)); - } - return state.renderer(); - } - - public static boolean isProxy(LevelRenderer renderer) { - return PROXY_RENDERERS.contains(renderer); - } - - public static net.minecraft.client.renderer.MultiBufferSource.BufferSource bufferSource() { - return PORTAL_RENDER_BUFFERS.bufferSource(); - } - - public static void beginFrame() { - SECTION_BUDGET_DEADLINE.set(System.nanoTime() + PORTAL_SECTION_BUDGET_NANOS); - SCHEDULED_SECTION_REBUILDS.set(0); - SKIP_SET_NOT_DIRTY.set(false); - UPLOADED_THIS_FRAME.set(0); - } - - public static void uploadPending(LevelRenderer renderer, SectionRenderDispatcher dispatcher) { - if (!isProxy(renderer)) { - dispatcher.uploadAllPendingUploads(); - return; - } - java.util.Queue uploads = ((SectionRenderDispatcherPortalUploadsAccessor) dispatcher).antarchy$getToUpload(); - long deadline = System.nanoTime() + PORTAL_UPLOAD_BUDGET_NANOS; - int uploaded = UPLOADED_THIS_FRAME.get(); - while (uploaded < MAX_PORTAL_UPLOADS_PER_FRAME) { - if (uploaded > 0 && System.nanoTime() >= deadline) { - break; - } - Runnable upload = uploads.poll(); - if (upload == null) { - break; - } - upload.run(); - uploaded++; - } - UPLOADED_THIS_FRAME.set(uploaded); - } - - public static int scheduledSectionRebuilds() { - return SCHEDULED_SECTION_REBUILDS.get(); - } - - public static int uploadedThisFrame() { - return UPLOADED_THIS_FRAME.get(); - } - - public static long remainingSectionBudgetNanos() { - return Math.max(0L, SECTION_BUDGET_DEADLINE.get() - System.nanoTime()); - } - - public static void rebuildSection(LevelRenderer renderer, SectionRenderDispatcher dispatcher, SectionRenderDispatcher.RenderSection section, RenderRegionCache cache) { - if (!isProxy(renderer)) { - dispatcher.rebuildSectionSync(section, cache); - SKIP_SET_NOT_DIRTY.set(false); - return; - } - if (remainingSectionBudgetNanos() <= 0L) { - SKIP_SET_NOT_DIRTY.set(true); - return; - } - section.rebuildSectionAsync(dispatcher, cache); - SCHEDULED_SECTION_REBUILDS.set(SCHEDULED_SECTION_REBUILDS.get() + 1); - SKIP_SET_NOT_DIRTY.set(false); - } - - public static void rebuildSectionAsync(LevelRenderer renderer, SectionRenderDispatcher dispatcher, SectionRenderDispatcher.RenderSection section, RenderRegionCache cache) { - if (!isProxy(renderer)) { - section.rebuildSectionAsync(dispatcher, cache); - SKIP_SET_NOT_DIRTY.set(false); - return; - } - if (remainingSectionBudgetNanos() <= 0L) { - SKIP_SET_NOT_DIRTY.set(true); - return; - } - section.rebuildSectionAsync(dispatcher, cache); - SCHEDULED_SECTION_REBUILDS.set(SCHEDULED_SECTION_REBUILDS.get() + 1); - SKIP_SET_NOT_DIRTY.set(false); - } - - public static void setNotDirty(SectionRenderDispatcher.RenderSection section) { - boolean leaveDirty = SKIP_SET_NOT_DIRTY.get(); - SKIP_SET_NOT_DIRTY.set(false); - if (!leaveDirty) { - section.setNotDirty(); - } - } - - public static void clear() { - for (PortalRenderer state : new ArrayList<>(RENDERERS.values())) { - LevelRenderer renderer = state.renderer(); - PortalGunPortalViewAreaManager.releaseRenderer(renderer); - try { - renderer.close(); - } finally { - PROXY_RENDERERS.remove(renderer); - } - } - RENDERERS.clear(); - ownerLevel = null; - SECTION_BUDGET_DEADLINE.remove(); - SCHEDULED_SECTION_REBUILDS.remove(); - SKIP_SET_NOT_DIRTY.remove(); - UPLOADED_THIS_FRAME.remove(); - } - - private static void trim() { - Iterator> iterator = RENDERERS.entrySet().iterator(); - while (RENDERERS.size() > MAX_RENDERERS && iterator.hasNext()) { - PortalRenderer state = iterator.next().getValue(); - iterator.remove(); - LevelRenderer renderer = state.renderer(); - PortalGunPortalViewAreaManager.releaseRenderer(renderer); - try { - renderer.close(); - } finally { - PROXY_RENDERERS.remove(renderer); - } - } - } - - private record PortalRenderer(LevelRenderer renderer, int width, int height) { - } -} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalSceneRenderer.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalSceneRenderer.java new file mode 100644 index 00000000..da8fbbb8 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalSceneRenderer.java @@ -0,0 +1,233 @@ +package com.craisinlord.antarchy.content.client.renderer; + +import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity; +import com.craisinlord.antarchy.mixins.client.LevelRendererPortalSceneInvoker; +import com.craisinlord.antarchy.mixins.client.LevelRendererPortalViewAreaAccessor; +import com.mojang.blaze3d.platform.Lighting; +import com.mojang.blaze3d.shaders.FogShape; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferUploader; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.MeshData; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.blaze3d.vertex.VertexSorting; +import java.util.function.Consumer; +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.FogRenderer; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderBuffers; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.culling.Frustum; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.phys.Vec3; +import org.joml.Matrix4f; +import org.joml.Matrix4fStack; +import org.lwjgl.opengl.GL11; + +public final class PortalGunPortalSceneRenderer { + private static RenderBuffers portalBuffers; + private static boolean renderingScene; + + private PortalGunPortalSceneRenderer() { + } + + public static MultiBufferSource.BufferSource bufferSource() { + if (portalBuffers == null) { + portalBuffers = new RenderBuffers(1); + } + return portalBuffers.bufferSource(); + } + + public static boolean isRenderingScene() { + return renderingScene; + } + + public static void render(Minecraft minecraft, Camera camera, float partialTick, Matrix4f viewMatrix, + Matrix4f projection, Matrix4f skyProjection, Frustum frustum, + PortalTerrain terrain, Consumer crossingEntities, String tracePair) { + LevelRenderer renderer = minecraft.levelRenderer; + LevelRendererPortalViewAreaAccessor state = (LevelRendererPortalViewAreaAccessor) renderer; + LevelRendererPortalSceneInvoker scene = (LevelRendererPortalSceneInvoker) renderer; + Vec3 cameraPosition = camera.getPosition(); + double cameraX = cameraPosition.x; + double cameraY = cameraPosition.y; + double cameraZ = cameraPosition.z; + + int previousRainSoundTime = state.antarchy$getRainSoundTime(); + Matrix4fStack modelViewStack = RenderSystem.getModelViewStack(); + Matrix4f previousProjection = new Matrix4f(RenderSystem.getProjectionMatrix()); + VertexSorting previousSorting = RenderSystem.getVertexSorting(); + float previousFogStart = RenderSystem.getShaderFogStart(); + float previousFogEnd = RenderSystem.getShaderFogEnd(); + float[] previousFogColor = RenderSystem.getShaderFogColor().clone(); + FogShape previousFogShape = RenderSystem.getShaderFogShape(); + Camera previousBlockEntityCamera = minecraft.getBlockEntityRenderDispatcher().camera; + modelViewStack.pushMatrix(); + modelViewStack.identity(); + RenderSystem.applyModelViewMatrix(); + renderingScene = true; + terrain.begin(minecraft); + try { + float renderDistance = minecraft.gameRenderer.getRenderDistance(); + BlockPos cameraBlockPos = BlockPos.containing(cameraX, cameraY, cameraZ); + boolean foggy = minecraft.level.effects().isFoggyAt(cameraBlockPos.getX(), cameraBlockPos.getY()) + || minecraft.gui.getBossOverlay().shouldCreateWorldFog(); + + try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "background-and-sky", "sections=" + terrain.sectionCount())) { + RenderSystem.setShaderGameTime(minecraft.level.getGameTime(), partialTick); + minecraft.getBlockEntityRenderDispatcher().prepare(minecraft.level, camera, minecraft.hitResult); + minecraft.getEntityRenderDispatcher().prepare(minecraft.level, camera, minecraft.crosshairPickEntity); + FogRenderer.setupColor(camera, partialTick, minecraft.level, minecraft.options.getEffectiveRenderDistance(), + minecraft.gameRenderer.getDarkenWorldAmount(partialTick)); + FogRenderer.levelFogColor(); + fillBackground(RenderSystem.getShaderFogColor()); + RenderSystem.setProjectionMatrix(skyProjection, VertexSorting.DISTANCE_TO_ORIGIN); + FogRenderer.setupFog(camera, FogRenderer.FogMode.FOG_SKY, renderDistance, foggy, partialTick); + RenderSystem.setShader(GameRenderer::getPositionShader); + renderer.renderSky(viewMatrix, skyProjection, partialTick, camera, foggy, + () -> FogRenderer.setupFog(camera, FogRenderer.FogMode.FOG_SKY, renderDistance, foggy, partialTick)); + } + + RenderSystem.setProjectionMatrix(projection, VertexSorting.DISTANCE_TO_ORIGIN); + FogRenderer.setupFog(camera, FogRenderer.FogMode.FOG_TERRAIN, Math.max(renderDistance, 32.0F), foggy, partialTick); + try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "opaque-terrain", "sections=" + terrain.sectionCount())) { + RenderSystem.enableDepthTest(); + RenderSystem.depthMask(true); + terrain.drawLayer(minecraft, RenderType.solid(), cameraPosition, viewMatrix, projection); + terrain.drawLayer(minecraft, RenderType.cutoutMipped(), cameraPosition, viewMatrix, projection); + terrain.drawLayer(minecraft, RenderType.cutout(), cameraPosition, viewMatrix, projection); + } + + if (minecraft.level.effects().constantAmbientLight()) { + Lighting.setupNetherLevel(); + } else { + Lighting.setupLevel(); + } + modelViewStack.pushMatrix(); + modelViewStack.mul(viewMatrix); + RenderSystem.applyModelViewMatrix(); + PoseStack poseStack = new PoseStack(); + MultiBufferSource.BufferSource buffers = bufferSource(); + try { + try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "entities", "rendering")) { + for (Entity entity : minecraft.level.entitiesForRendering()) { + if (!minecraft.getEntityRenderDispatcher().shouldRender(entity, frustum, cameraX, cameraY, cameraZ) + && !entity.hasIndirectPassenger(minecraft.player)) { + continue; + } + if (entity instanceof PortalGunPortalEntity portal && !portal.shouldRenderFront(cameraPosition)) { + continue; + } + if (entity == camera.getEntity() + && entity.getBoundingBox().inflate(0.1D).contains(cameraPosition) + && (!(entity instanceof LivingEntity living) || !living.isSleeping())) { + continue; + } + scene.antarchy$renderPortalEntity(entity, cameraX, cameraY, cameraZ, partialTick, poseStack, buffers); + } + crossingEntities.accept(poseStack); + } + buffers.endBatch(); + + try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "block-entities", "rendering")) { + terrain.forEachBlockEntity(minecraft, frustum, blockEntity -> + renderBlockEntity(minecraft, blockEntity, cameraX, cameraY, cameraZ, partialTick, poseStack, buffers)); + } + buffers.endBatch(); + + try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "translucent-and-particles", "rendering")) { + terrain.drawLayer(minecraft, RenderType.translucent(), cameraPosition, viewMatrix, projection); + buffers.endBatch(); + terrain.drawLayer(minecraft, RenderType.tripwire(), cameraPosition, viewMatrix, projection); + minecraft.particleEngine.render(minecraft.gameRenderer.lightTexture(), camera, partialTick); + } + + try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "weather-and-border", "rendering")) { + RenderSystem.depthMask(false); + scene.antarchy$renderPortalWeather(minecraft.gameRenderer.lightTexture(), partialTick, cameraX, cameraY, cameraZ); + scene.antarchy$renderPortalWorldBorder(camera); + } + } finally { + try { + buffers.endBatch(); + } finally { + modelViewStack.popMatrix(); + RenderSystem.applyModelViewMatrix(); + } + } + } finally { + renderingScene = false; + terrain.end(minecraft); + state.antarchy$setRainSoundTime(previousRainSoundTime); + modelViewStack.popMatrix(); + RenderSystem.applyModelViewMatrix(); + RenderSystem.setProjectionMatrix(previousProjection, previousSorting); + RenderSystem.setShaderFogStart(previousFogStart); + RenderSystem.setShaderFogEnd(previousFogEnd); + RenderSystem.setShaderFogColor(previousFogColor[0], previousFogColor[1], previousFogColor[2], previousFogColor[3]); + RenderSystem.setShaderFogShape(previousFogShape); + if (previousBlockEntityCamera != null) { + minecraft.getBlockEntityRenderDispatcher().prepare(minecraft.level, previousBlockEntityCamera, minecraft.hitResult); + } + RenderSystem.depthMask(true); + RenderSystem.enableDepthTest(); + RenderSystem.enableCull(); + RenderSystem.disableBlend(); + RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + } + } + + private static void fillBackground(float[] fogColor) { + int previousDepthFunction = GL11.glGetInteger(GL11.GL_DEPTH_FUNC); + Matrix4f previousProjection = new Matrix4f(RenderSystem.getProjectionMatrix()); + VertexSorting previousSorting = RenderSystem.getVertexSorting(); + BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION); + buffer.addVertex(-1.0F, -1.0F, 0.99999F); + buffer.addVertex(3.0F, -1.0F, 0.99999F); + buffer.addVertex(-1.0F, 3.0F, 0.99999F); + MeshData mesh = buffer.build(); + try { + RenderSystem.enableDepthTest(); + RenderSystem.depthMask(true); + RenderSystem.colorMask(true, true, true, true); + RenderSystem.disableBlend(); + RenderSystem.disableCull(); + GL11.glDepthFunc(GL11.GL_ALWAYS); + RenderSystem.setProjectionMatrix(new Matrix4f(), previousSorting); + RenderSystem.setShader(GameRenderer::getPositionShader); + RenderSystem.setShaderColor(fogColor[0], fogColor[1], fogColor[2], 1.0F); + if (mesh != null) { + BufferUploader.drawWithShader(mesh); + } + } finally { + GL11.glDepthFunc(previousDepthFunction); + RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + RenderSystem.setProjectionMatrix(previousProjection, previousSorting); + RenderSystem.enableCull(); + } + } + + private static void renderBlockEntity(Minecraft minecraft, BlockEntity blockEntity, double cameraX, double cameraY, double cameraZ, + float partialTick, PoseStack poseStack, MultiBufferSource.BufferSource buffers) { + if (!blockEntity.hasLevel() || !blockEntity.getType().isValid(blockEntity.getBlockState())) { + return; + } + BlockPos pos = blockEntity.getBlockPos(); + poseStack.pushPose(); + try { + poseStack.translate(pos.getX() - cameraX, pos.getY() - cameraY, pos.getZ() - cameraZ); + minecraft.getBlockEntityRenderDispatcher().render(blockEntity, partialTick, poseStack, buffers); + } finally { + poseStack.popPose(); + } + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalSectionViews.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalSectionViews.java new file mode 100644 index 00000000..40f6e547 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalSectionViews.java @@ -0,0 +1,165 @@ +package com.craisinlord.antarchy.content.client.renderer; + +import com.craisinlord.antarchy.mixins.client.LevelRendererPortalViewAreaAccessor; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.SectionOcclusionGraph; +import net.minecraft.client.renderer.ViewArea; +import net.minecraft.client.renderer.chunk.SectionRenderDispatcher; +import net.minecraft.client.renderer.culling.Frustum; +import net.minecraft.core.SectionPos; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.phys.Vec3; +import org.joml.Matrix4f; + +public final class PortalGunPortalSectionViews { + private static final int MAX_VIEWS = 8; + private static final double SEED_OFFSET = 0.5D; + private static final LinkedHashMap VIEWS = new LinkedHashMap<>(8, 0.75F, true); + private static volatile SectionOcclusionGraph[] graphs = new SectionOcclusionGraph[0]; + private static ViewArea ownerArea; + private static int mainSectionX = Integer.MIN_VALUE; + private static int mainSectionY = Integer.MIN_VALUE; + private static int mainSectionZ = Integer.MIN_VALUE; + + private PortalGunPortalSectionViews() { + } + + public static boolean canView(Minecraft minecraft, Vec3 exitCenter) { + ViewArea area = ((LevelRendererPortalViewAreaAccessor) minecraft.levelRenderer).antarchy$getViewArea(); + if (area == null) { + return false; + } + LevelRendererPortalViewAreaAccessor accessor = (LevelRendererPortalViewAreaAccessor) minecraft.levelRenderer; + int limit = area.getViewDistance() - 1; + return Math.abs(SectionPos.posToSectionCoord(exitCenter.x) - accessor.antarchy$getLastCameraSectionX()) <= limit + && Math.abs(SectionPos.posToSectionCoord(exitCenter.z) - accessor.antarchy$getLastCameraSectionZ()) <= limit; + } + + public static View prepare(Minecraft minecraft, UUID exitId, Vec3 exitCenter, Vec3 exitNormal, Frustum frustum) { + LevelRendererPortalViewAreaAccessor accessor = (LevelRendererPortalViewAreaAccessor) minecraft.levelRenderer; + ViewArea area = accessor.antarchy$getViewArea(); + if (area != ownerArea) { + clear(); + ownerArea = area; + } + int sectionX = accessor.antarchy$getLastCameraSectionX(); + int sectionY = accessor.antarchy$getLastCameraSectionY(); + int sectionZ = accessor.antarchy$getLastCameraSectionZ(); + if (sectionX != mainSectionX || sectionY != mainSectionY || sectionZ != mainSectionZ) { + mainSectionX = sectionX; + mainSectionY = sectionY; + mainSectionZ = sectionZ; + for (View view : VIEWS.values()) { + view.graph.invalidate(); + } + } + View view = VIEWS.get(exitId); + if (view == null) { + view = new View(area); + VIEWS.put(exitId, view); + trim(); + publishGraphs(); + } + Vec3 seed = exitCenter.add(exitNormal.normalize().scale(SEED_OFFSET)); + if (!seed.equals(view.seed)) { + view.seed = seed; + view.seedCamera = new SeedCamera(seed); + view.updateFrustum = centredFrustum(seed); + view.graph.invalidate(); + } + view.partialUpdates.clear(); + view.graph.update(minecraft.smartCull, view.seedCamera, view.updateFrustum(), view.partialUpdates); + view.visibleSections.clear(); + view.graph.addSectionsInFrustum(frustum, view.visibleSections); + return view; + } + + public static void onSectionCompiled(SectionRenderDispatcher.RenderSection section) { + for (SectionOcclusionGraph graph : graphs) { + graph.onSectionCompiled(section); + } + } + + public static void onChunkLoaded(ChunkPos pos) { + for (SectionOcclusionGraph graph : graphs) { + graph.onChunkLoaded(pos); + } + } + + public static void onChunkDropped(ChunkPos pos) { + for (SectionOcclusionGraph graph : graphs) { + graph.invalidate(); + } + } + + public static void clear() { + for (View view : VIEWS.values()) { + view.release(); + } + VIEWS.clear(); + publishGraphs(); + ownerArea = null; + mainSectionX = Integer.MIN_VALUE; + mainSectionY = Integer.MIN_VALUE; + mainSectionZ = Integer.MIN_VALUE; + } + + private static void publishGraphs() { + graphs = VIEWS.values().stream().map(view -> view.graph).toArray(SectionOcclusionGraph[]::new); + } + + private static void trim() { + Iterator> iterator = VIEWS.entrySet().iterator(); + while (VIEWS.size() > MAX_VIEWS && iterator.hasNext()) { + View view = iterator.next().getValue(); + iterator.remove(); + view.release(); + } + } + + public static final class View { + private final SectionOcclusionGraph graph = new SectionOcclusionGraph(); + private final List partialUpdates = new ArrayList<>(); + private final ObjectArrayList visibleSections = new ObjectArrayList<>(); + private Vec3 seed; + private Camera seedCamera; + private Frustum updateFrustum; + + private View(ViewArea area) { + ((PortalSectionGraphMarker) this.graph).antarchy$markPortalGraph(); + this.graph.waitAndReset(area); + } + + public ObjectArrayList visibleSections() { + return this.visibleSections; + } + + private Frustum updateFrustum() { + return this.updateFrustum; + } + + private void release() { + this.graph.waitAndReset(null); + } + } + + private static Frustum centredFrustum(Vec3 position) { + Frustum frustum = new Frustum(new Matrix4f(), new Matrix4f().setPerspective((float) Math.toRadians(90.0D), 1.0F, 0.05F, 1024.0F)); + frustum.prepare(position.x, position.y, position.z); + return frustum; + } + + private static final class SeedCamera extends Camera { + private SeedCamera(Vec3 position) { + this.setPosition(position); + } + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalViewAreaManager.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalViewAreaManager.java deleted file mode 100644 index ce72e0a2..00000000 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalViewAreaManager.java +++ /dev/null @@ -1,386 +0,0 @@ -package com.craisinlord.antarchy.content.client.renderer; - -import com.craisinlord.antarchy.mixins.client.LevelRendererPortalViewAreaAccessor; -import com.mojang.blaze3d.vertex.VertexBuffer; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import java.util.Collections; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import net.minecraft.client.CloudStatus; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.SectionOcclusionGraph; -import net.minecraft.client.renderer.ViewArea; -import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; -import net.minecraft.client.renderer.chunk.SectionRenderDispatcher; -import net.minecraft.core.SectionPos; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; - -public final class PortalGunPortalViewAreaManager { - private static final int MAX_VIEW_AREAS = 8; - private static final LinkedHashMap VIEW_AREAS = new LinkedHashMap<>(8, 0.75F, true); - private static final Map SECTION_OWNERS = Collections.synchronizedMap(new IdentityHashMap<>()); - private static ClientLevel ownerLevel; - private static int ownerViewDistance = -1; - - private PortalGunPortalViewAreaManager() { - } - - public static Scope enter(Minecraft minecraft, LevelRenderer renderer, UUID destinationId, Vec3 cameraPos, net.minecraft.client.Camera portalCamera) { - if (SodiumCompat.isLoaded()) { - return new SodiumScope(SodiumCompat.beginPortalView()); - } - LevelRendererPortalViewAreaAccessor accessor = (LevelRendererPortalViewAreaAccessor) renderer; - int viewDistance = minecraft.options.getEffectiveRenderDistance(); - if (ownerLevel != minecraft.level || ownerViewDistance != viewDistance) { - clear(); - ownerLevel = minecraft.level; - ownerViewDistance = viewDistance; - } - ViewKey viewKey = new ViewKey(renderer, destinationId); - ViewState state = VIEW_AREAS.get(viewKey); - if (state == null) { - ViewArea area = accessor.antarchy$getViewArea(); - SectionOcclusionGraph graph = accessor.antarchy$getSectionOcclusionGraph(); - ObjectArrayList sections = accessor.antarchy$getVisibleSections(); - state = new ViewState(area, graph, sections, accessor.antarchy$getGlobalBlockEntities()); - state.cloudBuffer = accessor.antarchy$getCloudBuffer(); - state.generateClouds = accessor.antarchy$getGenerateClouds(); - state.prevCloudX = accessor.antarchy$getPrevCloudX(); - state.prevCloudY = accessor.antarchy$getPrevCloudY(); - state.prevCloudZ = accessor.antarchy$getPrevCloudZ(); - state.prevCloudColor = accessor.antarchy$getPrevCloudColor(); - state.prevCloudsType = accessor.antarchy$getPrevCloudsType(); - for (SectionRenderDispatcher.RenderSection section : area.sections) { - ((PortalViewSectionMarker) section).antarchy$markPortalViewSection(); - SECTION_OWNERS.put(section, state); - } - VIEW_AREAS.put(viewKey, state); - trimOldViews(); - } - state.area.repositionCamera(cameraPos.x, cameraPos.z); - int sectionX = SectionPos.posToSectionCoord(cameraPos.x); - int sectionY = SectionPos.posToSectionCoord(cameraPos.y); - int sectionZ = SectionPos.posToSectionCoord(cameraPos.z); - state.cameraPos = cameraPos; - state.lastSectionX = sectionX; - state.lastSectionY = sectionY; - state.lastSectionZ = sectionZ; - Scope scope = new VanillaScope(renderer, accessor, state, minecraft.getBlockEntityRenderDispatcher()); - accessor.antarchy$setViewArea(state.area); - accessor.antarchy$setSectionOcclusionGraph(state.graph); - accessor.antarchy$setVisibleSections(state.visibleSections); - accessor.antarchy$setGlobalBlockEntities(state.globalBlockEntities); - accessor.antarchy$setLastCameraSectionX(sectionX); - accessor.antarchy$setLastCameraSectionY(sectionY); - accessor.antarchy$setLastCameraSectionZ(sectionZ); - return scope; - } - - public static boolean routeSectionCompiled(SectionRenderDispatcher.RenderSection section) { - ViewState state = SECTION_OWNERS.get(section); - if (state == null) { - return ((PortalViewSectionMarker) section).antarchy$isPortalViewSection(); - } - state.graph.onSectionCompiled(section); - return true; - } - - public static Vec3 cameraForSection(SectionRenderDispatcher.RenderSection section, Vec3 fallback) { - ViewState state = SECTION_OWNERS.get(section); - return state == null || state.cameraPos == null ? fallback : state.cameraPos; - } - - public static boolean updateGlobalBlockEntities(SectionRenderDispatcher.RenderSection section, Iterable removed, Iterable added) { - ViewState state = SECTION_OWNERS.get(section); - if (state == null) { - return ((PortalViewSectionMarker) section).antarchy$isPortalViewSection(); - } - synchronized (state.globalBlockEntities) { - for (BlockEntity blockEntity : removed) { - state.globalBlockEntities.remove(blockEntity); - } - for (BlockEntity blockEntity : added) { - state.globalBlockEntities.add(blockEntity); - } - } - return true; - } - - public static void onSectionDirty(int sectionX, int sectionY, int sectionZ, boolean playerChanged) { - for (ViewState state : VIEW_AREAS.values()) { - int sectionRange = state.area.getViewDistance() + 1; - if (Math.abs((long) sectionX - state.lastSectionX) > sectionRange - || Math.abs((long) sectionZ - state.lastSectionZ) > sectionRange - || sectionY < ownerLevel.getMinSection() - || sectionY > ownerLevel.getMaxSection()) { - continue; - } - state.area.setDirty(sectionX, sectionY, sectionZ, playerChanged); - } - } - - public static void onChunkLoaded(net.minecraft.world.level.ChunkPos pos) { - for (ViewState state : VIEW_AREAS.values()) { - state.graph.onChunkLoaded(pos); - markChunkDirty(state, pos); - } - } - - public static void onChunkDropped(net.minecraft.world.level.ChunkPos pos) { - for (ViewState state : VIEW_AREAS.values()) { - markChunkDirty(state, pos); - state.graph.invalidate(); - } - } - - private static void markChunkDirty(ViewState state, net.minecraft.world.level.ChunkPos pos) { - int sectionRange = state.area.getViewDistance() + 1; - if (Math.abs((long) pos.x - state.lastSectionX) <= sectionRange - && Math.abs((long) pos.z - state.lastSectionZ) <= sectionRange) { - for (int sectionY = ownerLevel.getMinSection(); sectionY <= ownerLevel.getMaxSection(); sectionY++) { - state.area.setDirty(pos.x, sectionY, pos.z, true); - } - } - } - - public static void clear() { - SodiumCompat.clear(); - for (ViewState state : VIEW_AREAS.values()) { - state.graph.waitAndReset(state.area); - } - VIEW_AREAS.clear(); - SECTION_OWNERS.clear(); - ownerLevel = null; - ownerViewDistance = -1; - } - - public static void releaseRenderer(LevelRenderer renderer) { - Iterator> iterator = VIEW_AREAS.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - if (entry.getKey().renderer() == renderer) { - ViewState state = entry.getValue(); - state.graph.waitAndReset(state.area); - removeOwners(state); - iterator.remove(); - } - } - } - - private static void trimOldViews() { - Iterator> iterator = VIEW_AREAS.entrySet().iterator(); - while (VIEW_AREAS.size() > MAX_VIEW_AREAS && iterator.hasNext()) { - ViewState state = iterator.next().getValue(); - iterator.remove(); - state.graph.waitAndReset(state.area); - removeOwners(state); - } - } - - private static void removeOwners(ViewState state) { - for (SectionRenderDispatcher.RenderSection section : state.area.sections) { - SECTION_OWNERS.remove(section); - } - } - - private static final class ViewState { - private final ViewArea area; - private final SectionOcclusionGraph graph; - private final ObjectArrayList visibleSections; - private final Set globalBlockEntities; - private VertexBuffer cloudBuffer; - private boolean generateClouds = true; - private int prevCloudX = Integer.MIN_VALUE; - private int prevCloudY = Integer.MIN_VALUE; - private int prevCloudZ = Integer.MIN_VALUE; - private Vec3 prevCloudColor = Vec3.ZERO; - private CloudStatus prevCloudsType; - private int lastSectionX; - private int lastSectionY; - private int lastSectionZ; - private volatile Vec3 cameraPos; - private double transparentSortX = Double.NaN; - private double transparentSortY = Double.NaN; - private double transparentSortZ = Double.NaN; - private double prevCamX = Double.NaN; - private double prevCamY = Double.NaN; - private double prevCamZ = Double.NaN; - private double prevCamRotX = Double.NaN; - private double prevCamRotY = Double.NaN; - - private ViewState(ViewArea area, SectionOcclusionGraph graph, ObjectArrayList visibleSections, Set globalBlockEntities) { - this.area = area; - this.graph = graph; - this.visibleSections = visibleSections; - this.globalBlockEntities = globalBlockEntities; - } - } - - private record ViewKey(LevelRenderer renderer, UUID destinationId) { - } - - public interface Scope extends AutoCloseable { - @Override - void close(); - } - - private static final class SodiumScope implements Scope { - private final SodiumCompat.TerrainScope terrainScope; - - private SodiumScope(SodiumCompat.TerrainScope terrainScope) { - this.terrainScope = terrainScope; - } - - @Override - public void close() { - terrainScope.close(); - } - } - - private static final class VanillaScope implements Scope { - private final LevelRendererPortalViewAreaAccessor accessor; - private final ViewArea previousArea; - private final SectionOcclusionGraph previousGraph; - private final ObjectArrayList previousVisibleSections; - private final Set previousGlobalBlockEntities; - private final VertexBuffer previousCloudBuffer; - private final boolean previousGenerateClouds; - private final int previousCloudX; - private final int previousCloudY; - private final int previousCloudZ; - private final Vec3 previousCloudColor; - private final CloudStatus previousCloudsType; - private final int previousRainSoundTime; - private final int previousSectionX; - private final int previousSectionY; - private final int previousSectionZ; - private final double previousPrevCamX; - private final double previousPrevCamY; - private final double previousPrevCamZ; - private final double previousPrevCamRotX; - private final double previousPrevCamRotY; - private final double previousTransparentSortX; - private final double previousTransparentSortY; - private final double previousTransparentSortZ; - private final Vec3 previousDispatcherCamera; - private final SectionRenderDispatcher dispatcher; - private final BlockEntityRenderDispatcher blockEntityDispatcher; - private final Level previousBlockEntityLevel; - private final net.minecraft.client.Camera previousBlockEntityCamera; - private final HitResult previousBlockEntityHitResult; - private final ViewState state; - private boolean closed; - - private VanillaScope(LevelRenderer renderer, LevelRendererPortalViewAreaAccessor accessor, ViewState state, BlockEntityRenderDispatcher blockEntityDispatcher) { - this.accessor = accessor; - this.state = state; - this.blockEntityDispatcher = blockEntityDispatcher; - this.previousBlockEntityLevel = blockEntityDispatcher.level; - this.previousBlockEntityCamera = blockEntityDispatcher.camera; - this.previousBlockEntityHitResult = blockEntityDispatcher.cameraHitResult; - this.previousArea = accessor.antarchy$getViewArea(); - this.previousGraph = accessor.antarchy$getSectionOcclusionGraph(); - this.previousVisibleSections = accessor.antarchy$getVisibleSections(); - this.previousGlobalBlockEntities = accessor.antarchy$getGlobalBlockEntities(); - this.previousCloudBuffer = accessor.antarchy$getCloudBuffer(); - this.previousGenerateClouds = accessor.antarchy$getGenerateClouds(); - this.previousCloudX = accessor.antarchy$getPrevCloudX(); - this.previousCloudY = accessor.antarchy$getPrevCloudY(); - this.previousCloudZ = accessor.antarchy$getPrevCloudZ(); - this.previousCloudColor = accessor.antarchy$getPrevCloudColor(); - this.previousCloudsType = accessor.antarchy$getPrevCloudsType(); - this.previousRainSoundTime = accessor.antarchy$getRainSoundTime(); - this.previousSectionX = accessor.antarchy$getLastCameraSectionX(); - this.previousSectionY = accessor.antarchy$getLastCameraSectionY(); - this.previousSectionZ = accessor.antarchy$getLastCameraSectionZ(); - this.previousPrevCamX = accessor.antarchy$getPrevCamX(); - this.previousPrevCamY = accessor.antarchy$getPrevCamY(); - this.previousPrevCamZ = accessor.antarchy$getPrevCamZ(); - this.previousPrevCamRotX = accessor.antarchy$getPrevCamRotX(); - this.previousPrevCamRotY = accessor.antarchy$getPrevCamRotY(); - this.previousTransparentSortX = accessor.antarchy$getTransparentSortX(); - this.previousTransparentSortY = accessor.antarchy$getTransparentSortY(); - this.previousTransparentSortZ = accessor.antarchy$getTransparentSortZ(); - this.dispatcher = renderer.getSectionRenderDispatcher(); - this.previousDispatcherCamera = dispatcher.getCameraPosition(); - accessor.antarchy$setLastCameraSectionX(state.lastSectionX); - accessor.antarchy$setLastCameraSectionY(state.lastSectionY); - accessor.antarchy$setLastCameraSectionZ(state.lastSectionZ); - accessor.antarchy$setPrevCamX(state.prevCamX); - accessor.antarchy$setPrevCamY(state.prevCamY); - accessor.antarchy$setPrevCamZ(state.prevCamZ); - accessor.antarchy$setPrevCamRotX(state.prevCamRotX); - accessor.antarchy$setPrevCamRotY(state.prevCamRotY); - accessor.antarchy$setTransparentSortX(state.transparentSortX); - accessor.antarchy$setTransparentSortY(state.transparentSortY); - accessor.antarchy$setTransparentSortZ(state.transparentSortZ); - accessor.antarchy$setCloudBuffer(state.cloudBuffer); - accessor.antarchy$setGenerateClouds(state.generateClouds); - accessor.antarchy$setPrevCloudX(state.prevCloudX); - accessor.antarchy$setPrevCloudY(state.prevCloudY); - accessor.antarchy$setPrevCloudZ(state.prevCloudZ); - accessor.antarchy$setPrevCloudColor(state.prevCloudColor); - accessor.antarchy$setPrevCloudsType(state.prevCloudsType); - } - - @Override - public void close() { - if (closed) { - return; - } - closed = true; - state.lastSectionX = accessor.antarchy$getLastCameraSectionX(); - state.lastSectionY = accessor.antarchy$getLastCameraSectionY(); - state.lastSectionZ = accessor.antarchy$getLastCameraSectionZ(); - state.prevCamX = accessor.antarchy$getPrevCamX(); - state.prevCamY = accessor.antarchy$getPrevCamY(); - state.prevCamZ = accessor.antarchy$getPrevCamZ(); - state.prevCamRotX = accessor.antarchy$getPrevCamRotX(); - state.prevCamRotY = accessor.antarchy$getPrevCamRotY(); - state.transparentSortX = accessor.antarchy$getTransparentSortX(); - state.transparentSortY = accessor.antarchy$getTransparentSortY(); - state.transparentSortZ = accessor.antarchy$getTransparentSortZ(); - state.cloudBuffer = accessor.antarchy$getCloudBuffer(); - state.generateClouds = accessor.antarchy$getGenerateClouds(); - state.prevCloudX = accessor.antarchy$getPrevCloudX(); - state.prevCloudY = accessor.antarchy$getPrevCloudY(); - state.prevCloudZ = accessor.antarchy$getPrevCloudZ(); - state.prevCloudColor = accessor.antarchy$getPrevCloudColor(); - state.prevCloudsType = accessor.antarchy$getPrevCloudsType(); - accessor.antarchy$setViewArea(previousArea); - accessor.antarchy$setSectionOcclusionGraph(previousGraph); - accessor.antarchy$setVisibleSections(previousVisibleSections); - accessor.antarchy$setGlobalBlockEntities(previousGlobalBlockEntities); - accessor.antarchy$setCloudBuffer(previousCloudBuffer); - accessor.antarchy$setGenerateClouds(previousGenerateClouds); - accessor.antarchy$setPrevCloudX(previousCloudX); - accessor.antarchy$setPrevCloudY(previousCloudY); - accessor.antarchy$setPrevCloudZ(previousCloudZ); - accessor.antarchy$setPrevCloudColor(previousCloudColor); - accessor.antarchy$setPrevCloudsType(previousCloudsType); - accessor.antarchy$setRainSoundTime(previousRainSoundTime); - accessor.antarchy$setLastCameraSectionX(previousSectionX); - accessor.antarchy$setLastCameraSectionY(previousSectionY); - accessor.antarchy$setLastCameraSectionZ(previousSectionZ); - accessor.antarchy$setPrevCamX(previousPrevCamX); - accessor.antarchy$setPrevCamY(previousPrevCamY); - accessor.antarchy$setPrevCamZ(previousPrevCamZ); - accessor.antarchy$setPrevCamRotX(previousPrevCamRotX); - accessor.antarchy$setPrevCamRotY(previousPrevCamRotY); - accessor.antarchy$setTransparentSortX(previousTransparentSortX); - accessor.antarchy$setTransparentSortY(previousTransparentSortY); - accessor.antarchy$setTransparentSortZ(previousTransparentSortZ); - dispatcher.setCamera(previousDispatcherCamera); - blockEntityDispatcher.prepare(previousBlockEntityLevel, previousBlockEntityCamera, previousBlockEntityHitResult); - } - } -} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalViewRenderer.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalViewRenderer.java index b5c42993..f8b5fae8 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalViewRenderer.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalViewRenderer.java @@ -4,15 +4,12 @@ import com.craisinlord.antarchy.Antarchy; import com.craisinlord.antarchy.config.AntarchySettings; import com.craisinlord.antarchy.content.client.PortalGunEntityTransformationStack; import com.craisinlord.antarchy.content.client.PortalGunPortalRenderState; -import com.craisinlord.antarchy.mixins.client.MinecraftMainRenderTargetAccessor; -import com.craisinlord.antarchy.mixins.client.LevelRendererPortalTargetsAccessor; -import com.craisinlord.antarchy.mixins.client.PostChainTargetAccessor; -import com.craisinlord.antarchy.content.portalgun.PortalGunTransformUtil; -import com.craisinlord.antarchy.content.portalgun.PortalGunProjectionUtil; import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity; +import com.craisinlord.antarchy.content.portalgun.PortalGunProjectionUtil; +import com.craisinlord.antarchy.content.portalgun.PortalGunTransformUtil; import com.craisinlord.antarchy.content.portalgun.PortalGunWorldPortalShape; import com.craisinlord.antarchy.mixins.client.CameraBasisAccessor; -import com.mojang.blaze3d.platform.GlStateManager; +import com.craisinlord.antarchy.mixins.client.MinecraftMainRenderTargetAccessor; import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.pipeline.TextureTarget; import com.mojang.blaze3d.systems.RenderSystem; @@ -26,50 +23,41 @@ import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.blaze3d.vertex.VertexSorting; import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.IdentityHashMap; import java.util.List; import java.util.Set; import net.minecraft.client.Camera; import net.minecraft.client.DeltaTracker; -import net.minecraft.client.GraphicsStatus; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.PostChain; +import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.ShaderInstance; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.client.renderer.culling.Frustum; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import org.joml.Matrix4f; import org.joml.Matrix4fStack; +import org.joml.Quaternionf; +import org.joml.Vector3f; import org.joml.Vector4f; import org.lwjgl.opengl.GL11; -import org.joml.Quaternionf; public final class PortalGunPortalViewRenderer { - private static final int MAX_RECURSION_DEPTH = 1; - private static final int MAX_PORTAL_VIEWS_PER_FRAME = 2; - private static final double RENDER_TARGET_SCALE = 1.0D; - private static final boolean ENABLE_DESTINATION_SCENE_RENDERING = true; + private static final int MAX_ROOT_VIEWS = 2; + private static final int MAX_VIEW_LEVELS = 2; + private static final int MAX_VIEWS_PER_FRAME = 4; + private static final double PORTAL_SEARCH_RADIUS = 128.0D; private static final int PORTAL_TARGET_FILTER = 9729; - private static final double PORTAL_APERTURE_SCALE = 1.0D; private static final double SURFACE_OFFSET = 0.04D; - private static final double OVERLAY_OFFSET = 0.03135D; - private static final ResourceLocation BLUE_OVERLAY = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/vfx/portal_gun_portal_blue.png"); - private static final ResourceLocation ORANGE_OVERLAY = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/vfx/portal_gun_portal_orange.png"); - private static final TextureTarget[] PORTAL_TARGETS = new TextureTarget[MAX_RECURSION_DEPTH + 1]; + private static final double EXIT_CLIP_OFFSET = 0.01D; + private static TextureTarget offscreenTarget; private static ShaderInstance portalViewShader; private static boolean renderingPortalView; private static boolean loggedRendererActivation; - private static String lastPortalCandidateState = ""; - private static final Set loggedPortalSceneRenders = new HashSet<>(); - private static final Set loggedPortalViewComposites = new HashSet<>(); private static boolean loggedMissingPortalViewShader; - private static final TargetAllocationFailure[] TARGET_ALLOCATION_FAILURES = new TargetAllocationFailure[MAX_RECURSION_DEPTH + 1]; + private static String lastPortalCandidateState = ""; private static long lastRenderFailureTick = Long.MIN_VALUE; private PortalGunPortalViewRenderer() { @@ -85,116 +73,69 @@ public final class PortalGunPortalViewRenderer { } public static boolean isEnabled() { - return ENABLE_DESTINATION_SCENE_RENDERING && AntarchySettings.portalGunSeeThroughPortals(); + return AntarchySettings.portalGunSeeThroughPortals(); } public static void releaseTargets() { PortalSceneRenderTrace.reset(); PortalGunPortalVisibilityQueries.clear(); - for (int i = 0; i < PORTAL_TARGETS.length; i++) { - TextureTarget target = PORTAL_TARGETS[i]; - if (target != null) { - PortalStencilTarget.release(target); - target.destroyBuffers(); - PORTAL_TARGETS[i] = null; - } + PortalGunPortalSectionViews.clear(); + if (offscreenTarget != null) { + offscreenTarget.destroyBuffers(); + offscreenTarget = null; } - java.util.Arrays.fill(TARGET_ALLOCATION_FAILURES, null); } public static void render(Camera camera, Matrix4f poseMatrix, Matrix4f projectionMatrix, DeltaTracker tickCounter) { - if (!isEnabled()) { + if (!isEnabled() || renderingPortalView) { return; } - if (renderingPortalView) { - return; - } - PortalGunPortalRendererPool.beginFrame(); + PortalRenderWatchdog.frame(); Minecraft minecraft = Minecraft.getInstance(); if (minecraft.level == null || minecraft.gameRenderer == null || camera == null || poseMatrix == null || projectionMatrix == null || tickCounter == null) { return; } if (!loggedRendererActivation) { loggedRendererActivation = true; - Antarchy.LOGGER.info("Portal gun view renderer hook active"); + Antarchy.LOGGER.info("Portal gun view renderer hook active (terrain: {})", SodiumCompat.isLoaded() ? "sodium" : "vanilla"); } Entity cameraEntity = minecraft.getCameraEntity(); if (cameraEntity == null) { return; } Vec3 cameraPos = camera.getPosition(); - Vec3 rootLook = new Vec3(camera.getLookVector()).normalize(); - Vec3 rootUp = new Vec3(camera.getUpVector()).normalize(); Matrix4f rootViewMatrix = new Matrix4f(poseMatrix); - List portals = collectVisiblePortals(minecraft, cameraPos); + Matrix4f rootProjection = new Matrix4f(projectionMatrix); + float partialTick = tickCounter.getGameTimeDeltaPartialTick(true); + RenderTarget mainTarget = minecraft.getMainRenderTarget(); + int width = mainTarget.width; + int height = mainTarget.height; + + List portals = collectPortals(minecraft, cameraPos); if (portals.isEmpty()) { return; } - Vec3 effectiveCameraPos = cameraPos; - Matrix4f rootProjectionMatrix = new Matrix4f(projectionMatrix); - float partialTick = tickCounter.getGameTimeDeltaPartialTick(true); - int targetWidth = getPortalTargetWidth(minecraft); - int targetHeight = getPortalTargetHeight(minecraft); - IdentityHashMap rootScreenClips = new IdentityHashMap<>(); + List candidates = new ArrayList<>(); for (PortalGunPortalEntity portal : portals) { - if (!portal.shouldRenderFront(effectiveCameraPos)) { + PortalGunPortalEntity linked = portal.getLinkedPortal(); + if (linked == null || !linked.isAlive() || !portal.shouldRenderFront(cameraPos)) { continue; } - ScreenClip clip = computeScreenClip(cameraPos, rootViewMatrix, rootProjectionMatrix, portal, partialTick, targetWidth, targetHeight); + ScreenClip clip = computeScreenClip(cameraPos, rootViewMatrix, rootProjection, portal, partialTick, width, height); if (clip != null) { - rootScreenClips.put(portal, clip); + candidates.add(new RootCandidate(portal, linked, clip)); } } - List renderablePortals = new ArrayList<>(); - for (PortalGunPortalEntity portal : portals) { - if (rootScreenClips.containsKey(portal)) { - renderablePortals.add(portal); - } + candidates.sort((left, right) -> Integer.compare(right.clip().area(), left.clip().area())); + if (candidates.size() > MAX_ROOT_VIEWS) { + candidates = candidates.subList(0, MAX_ROOT_VIEWS); } - List selectedPortals = renderablePortals.stream() - .filter(portal -> { - PortalGunPortalEntity linked = portal.getLinkedPortal(); - return linked != null && linked.isAlive(); - }) - .sorted((left, right) -> Integer.compare(rootScreenClips.get(right).area(), rootScreenClips.get(left).area())) - .limit(MAX_PORTAL_VIEWS_PER_FRAME) - .toList(); - long linkedPortalCount = renderablePortals.stream() - .filter(portal -> portal.getLinkedPortal() != null && portal.getLinkedPortal().isAlive()) - .count(); - String candidateState = portals.stream() - .map(portal -> portal.getUUID() + ":" + (portal.getLinkedPortal() != null && portal.getLinkedPortal().isAlive() ? portal.getLinkedPortal().getUUID() : "unlinked") + ":" + rootScreenClips.containsKey(portal)) - .sorted() - .toList() - + "|selected=" + selectedPortals.stream().map(portal -> portal.getUUID().toString()).sorted().toList() - + "|shader=" + (portalViewShader != null) - + "|target=" + targetWidth + "x" + targetHeight; - if (!candidateState.equals(lastPortalCandidateState)) { - lastPortalCandidateState = candidateState; - if (!selectedPortals.isEmpty()) { - String selectedPairKey = selectedPortals.stream() - .map(portal -> portal.getUUID() + "->" + portal.getLinkedPortal().getUUID()) - .sorted() - .toList() - .toString(); - PortalSceneRenderTrace.arm(selectedPairKey); - } - Antarchy.LOGGER.info( - "Portal gun view candidate state changed portals={} frontFacing={} linked={} selected={} shader={} target={}x{}", - portals.size(), - renderablePortals.size(), - linkedPortalCount, - selectedPortals.size(), - portalViewShader != null, - targetWidth, - targetHeight - ); - } - if (selectedPortals.isEmpty()) { + logCandidateState(portals, candidates); + if (candidates.isEmpty()) { return; } - RenderContext rootContext = new RenderContext(effectiveCameraPos, rootLook, rootUp, rootViewMatrix); - boolean directStencil = PortalStencilTarget.supportsDirect(minecraft.getMainRenderTarget()); + + boolean directStencil = PortalStencilTarget.supportsDirect(mainTarget); if (!directStencil && portalViewShader == null) { if (!loggedMissingPortalViewShader) { loggedMissingPortalViewShader = true; @@ -202,146 +143,205 @@ public final class PortalGunPortalViewRenderer { } return; } - PortalViewBudget fallbackBudget = directStencil ? null : new PortalViewBudget(MAX_PORTAL_VIEWS_PER_FRAME); + Matrix4f cameraToWorld = new Matrix4f(rootViewMatrix).invert(); + Vector3f rootLook = cameraToWorld.transformDirection(new Vector3f(0.0F, 0.0F, -1.0F)).normalize(); + Vector3f rootUp = cameraToWorld.transformDirection(new Vector3f(0.0F, 1.0F, 0.0F)).normalize(); + RenderContext rootContext = new RenderContext(cameraPos, new Vec3(rootLook), new Vec3(rootUp), rootViewMatrix); + ViewBudget budget = new ViewBudget(MAX_VIEWS_PER_FRAME); + PortalRenderWatchdog.portalViewDrawn(); renderingPortalView = true; - boolean projectionBackedUp = false; + RenderSystem.backupProjectionMatrix(); try { - RenderSystem.backupProjectionMatrix(); - projectionBackedUp = true; - for (PortalGunPortalEntity portal : selectedPortals) { - PortalGunPortalEntity linkedPortal = portal.getLinkedPortal(); - if (linkedPortal == null || !linkedPortal.isAlive()) { - continue; + if (directStencil) { + PortalStencilTarget.beginFrame(mainTarget); + } + for (RootCandidate candidate : candidates) { + if (!budget.tryReserve()) { + break; } - String portalPairKey = portal.getUUID() + "->" + linkedPortal.getUUID(); - boolean rendered; try { - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, - "root-view-dispatch", "backend=" + (directStencil ? "direct-stencil" : "offscreen") - + " aperture=" + rootScreenClips.get(portal).width() + "x" + rootScreenClips.get(portal).height())) { - if (directStencil) { - rendered = renderPortalSurfaceDirect(minecraft, cameraEntity, tickCounter, rootContext, rootProjectionMatrix, portal, linkedPortal, rootScreenClips.get(portal)); - } else { - int textureId = renderPortalSurface(minecraft, cameraEntity, tickCounter, fallbackBudget, rootContext, - rootProjectionMatrix, portal, linkedPortal, 0, rootScreenClips.get(portal)); - minecraft.gameRenderer.resetProjectionMatrix(rootProjectionMatrix); - minecraft.getMainRenderTarget().bindWrite(true); - rendered = textureId >= 0 && drawPortalQuad(cameraPos, rootViewMatrix, rootProjectionMatrix, - minecraft.getMainRenderTarget().width, minecraft.getMainRenderTarget().height, - portal, partialTick, textureId, rootScreenClips.get(portal)); - } + if (directStencil) { + renderViewDirect(minecraft, cameraEntity, partialTick, rootContext, rootProjection, rootProjection, + candidate.portal(), candidate.linked(), 0, candidate.clip(), null, budget); + } else { + renderViewOffscreen(minecraft, cameraEntity, partialTick, rootContext, rootProjection, + candidate.portal(), candidate.linked(), candidate.clip()); } } catch (RuntimeException exception) { logRenderFailure(minecraft, exception); - RenderSystem.restoreProjectionMatrix(); - projectionBackedUp = false; - RenderSystem.backupProjectionMatrix(); - projectionBackedUp = true; - continue; - } - if (!rendered) { - continue; - } - RenderSystem.restoreProjectionMatrix(); - projectionBackedUp = false; - RenderSystem.backupProjectionMatrix(); - projectionBackedUp = true; - minecraft.getMainRenderTarget().bindWrite(true); - if (loggedPortalViewComposites.add(portalPairKey)) { - Antarchy.LOGGER.info("Portal gun destination view rendered directly source={} destination={} target={}x{}", portal.getId(), linkedPortal.getId(), targetWidth, targetHeight); + if (directStencil) { + PortalStencilTarget.beginFrame(mainTarget); + } } } } catch (RuntimeException exception) { logRenderFailure(minecraft, exception); } finally { try { - try { - restorePortalDrawState(); - } catch (RuntimeException exception) { - logRenderFailure(minecraft, exception); - } - try { - minecraft.getMainRenderTarget().bindWrite(true); - } catch (RuntimeException exception) { - logRenderFailure(minecraft, exception); - } - try { - minecraft.getEntityRenderDispatcher().prepare(minecraft.level, camera, minecraft.crosshairPickEntity); - } catch (RuntimeException exception) { - logRenderFailure(minecraft, exception); - } - try { - minecraft.levelRenderer.prepareCullFrustum(cameraPos, rootViewMatrix, rootProjectionMatrix); - } catch (RuntimeException exception) { - logRenderFailure(minecraft, exception); - } - if (projectionBackedUp) { - try { - RenderSystem.restoreProjectionMatrix(); - } catch (RuntimeException exception) { - logRenderFailure(minecraft, exception); - } + if (directStencil) { + PortalStencilTarget.endFrame(); } + restorePortalDrawState(); + mainTarget.bindWrite(true); + minecraft.getEntityRenderDispatcher().prepare(minecraft.level, camera, minecraft.crosshairPickEntity); + minecraft.getBlockEntityRenderDispatcher().prepare(minecraft.level, camera, minecraft.hitResult); + } catch (RuntimeException exception) { + logRenderFailure(minecraft, exception); } finally { + RenderSystem.restoreProjectionMatrix(); renderingPortalView = false; } } } - private static List collectVisiblePortals(Minecraft minecraft, Vec3 cameraPos) { - AABB searchBounds = new AABB(cameraPos, cameraPos).inflate(128.0D); - List portals = minecraft.level.getEntitiesOfClass( - PortalGunPortalEntity.class, - searchBounds, - Entity::isAlive - ); - portals.removeIf(portal -> portal.distanceToSqr(cameraPos) > 16384.0D); + private static void renderViewDirect(Minecraft minecraft, Entity cameraEntity, float partialTick, RenderContext context, + Matrix4f rootProjection, Matrix4f parentProjection, + PortalGunPortalEntity source, PortalGunPortalEntity destination, + int parentLevel, ScreenClip clip, ScreenClip parentClip, ViewBudget budget) { + PortalGunWorldPortalShape exit = destination.getWorldPortalShape(); + if (!PortalTerrain.canView(minecraft, exit.center())) { + return; + } + String pairKey = source.getUUID() + "->" + destination.getUUID(); + boolean root = parentLevel == 0; + boolean visible = !root || PortalGunPortalVisibilityQueries.shouldRender(source.getUUID(), destination.getUUID()); + RenderTarget target = minecraft.getMainRenderTarget(); + PortalStencilTarget.pushAperture(parentLevel, () -> { + boolean queryStarted = root && PortalGunPortalVisibilityQueries.begin(source.getUUID(), destination.getUUID()); + try { + drawPortalMask(context.cameraPos(), context.viewMatrix(), parentProjection, source, partialTick); + } finally { + if (root) { + PortalGunPortalVisibilityQueries.end(source.getUUID(), destination.getUUID(), queryStarted); + } + } + }); + try { + if (!visible) { + return; + } + RenderContext transformed = transformContext(context, source, destination); + Matrix4f clippedProjection = applyPortalClipPlane(rootProjection, transformed, destination); + RenderSystem.enableScissor(clip.x(), clip.y(), clip.width(), clip.height()); + renderScene(minecraft, cameraEntity, partialTick, transformed, rootProjection, clippedProjection, + source, destination, clip, target.width, target.height, parentLevel + 1, pairKey); + if (parentLevel + 1 < MAX_VIEW_LEVELS) { + renderNestedViews(minecraft, cameraEntity, partialTick, transformed, rootProjection, clippedProjection, + destination, parentLevel + 1, clip, budget, target.width, target.height); + } + } finally { + PortalStencilTarget.popAperture(parentLevel, + () -> restorePortalApertureDepth(context.cameraPos(), context.viewMatrix(), parentProjection, source, partialTick)); + if (parentClip == null) { + RenderSystem.disableScissor(); + } else { + RenderSystem.enableScissor(parentClip.x(), parentClip.y(), parentClip.width(), parentClip.height()); + } + } + } + + private static void renderNestedViews(Minecraft minecraft, Entity cameraEntity, float partialTick, RenderContext viewContext, + Matrix4f rootProjection, Matrix4f viewProjection, PortalGunPortalEntity exit, + int level, ScreenClip viewClip, ViewBudget budget, int width, int height) { + PortalGunWorldPortalShape exitShape = exit.getWorldPortalShape(); + for (PortalGunPortalEntity child : collectPortals(minecraft, viewContext.cameraPos())) { + if (!budget.hasRemaining()) { + return; + } + PortalGunPortalEntity childLinked = child.getLinkedPortal(); + if (child == exit || childLinked == null || !childLinked.isAlive() + || !child.shouldRenderFront(viewContext.cameraPos()) + || !exitShape.intersectsFront(child.getBoundingBox(), 0.0D)) { + continue; + } + ScreenClip childClip = computeScreenClip(viewContext.cameraPos(), viewContext.viewMatrix(), viewProjection, + child, partialTick, width, height); + childClip = childClip == null ? null : childClip.intersect(viewClip); + if (childClip == null || !budget.tryReserve()) { + continue; + } + renderViewDirect(minecraft, cameraEntity, partialTick, viewContext, rootProjection, viewProjection, + child, childLinked, level, childClip, viewClip, budget); + } + } + + private static void renderViewOffscreen(Minecraft minecraft, Entity cameraEntity, float partialTick, RenderContext context, + Matrix4f rootProjection, PortalGunPortalEntity source, + PortalGunPortalEntity destination, ScreenClip clip) { + if (!PortalTerrain.canView(minecraft, destination.getWorldPortalShape().center())) { + return; + } + RenderTarget mainTarget = minecraft.getMainRenderTarget(); + TextureTarget target = ensureOffscreenTarget(mainTarget.width, mainTarget.height); + RenderContext transformed = transformContext(context, source, destination); + Matrix4f clippedProjection = applyPortalClipPlane(rootProjection, transformed, destination); + String pairKey = source.getUUID() + "->" + destination.getUUID(); + MinecraftMainRenderTargetAccessor targetAccessor = (MinecraftMainRenderTargetAccessor) minecraft; + targetAccessor.antarchy$setMainRenderTarget(target); + try { + target.bindWrite(true); + RenderSystem.disableScissor(); + target.clear(Minecraft.ON_OSX); + target.bindWrite(true); + RenderSystem.enableScissor(clip.x(), clip.y(), clip.width(), clip.height()); + renderScene(minecraft, cameraEntity, partialTick, transformed, rootProjection, clippedProjection, + source, destination, clip, target.width, target.height, 1, pairKey); + } finally { + RenderSystem.disableScissor(); + targetAccessor.antarchy$setMainRenderTarget(mainTarget); + mainTarget.bindWrite(true); + } + RenderSystem.setProjectionMatrix(rootProjection, VertexSorting.DISTANCE_TO_ORIGIN); + drawPortalComposite(context.cameraPos(), context.viewMatrix(), rootProjection, source, partialTick, target.getColorTextureId()); + } + + private static void renderScene(Minecraft minecraft, Entity cameraEntity, float partialTick, RenderContext transformed, + Matrix4f rootProjection, Matrix4f clippedProjection, + PortalGunPortalEntity source, PortalGunPortalEntity destination, + ScreenClip clip, int width, int height, int level, String pairKey) { + PortalGunWorldPortalShape exit = destination.getWorldPortalShape(); + PortalCamera portalCamera = new PortalCamera(); + portalCamera.setup(minecraft.level, cameraEntity, partialTick, transformed.cameraPos(), transformed.look(), transformed.up()); + Frustum frustum = new Frustum(transformed.viewMatrix(), cropProjectionToScreenClip(rootProjection, clip, width, height)); + frustum.prepare(transformed.cameraPos().x, transformed.cameraPos().y, transformed.cameraPos().z); + PortalGunPortalRenderState.pushPortalView(new PortalGunPortalRenderState.PortalRenderContext( + source.getWorldPortalShape(), exit, transformed.cameraPos(), transformed.look(), transformed.up(), + transformed.viewMatrix(), clippedProjection, level, false, destination.getUUID())); + try { + PortalTerrain terrain; + try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(pairKey, "section-visibility", "level=" + level)) { + terrain = PortalTerrain.prepare(minecraft, destination.getUUID(), exit.center(), exit.normal(), frustum); + } + PortalGunPortalSceneRenderer.render(minecraft, portalCamera, partialTick, transformed.viewMatrix(), clippedProjection, + rootProjection, frustum, terrain, + poseStack -> renderCrossingEntities(minecraft, transformed.cameraPos(), partialTick, source, destination, poseStack), + pairKey); + } finally { + PortalGunPortalRenderState.popPortalView(false); + } + } + + private static List collectPortals(Minecraft minecraft, Vec3 cameraPos) { + List portals = minecraft.level.getEntitiesOfClass(PortalGunPortalEntity.class, + new AABB(cameraPos, cameraPos).inflate(PORTAL_SEARCH_RADIUS), Entity::isAlive); + portals.removeIf(portal -> portal.distanceToSqr(cameraPos) > PORTAL_SEARCH_RADIUS * PORTAL_SEARCH_RADIUS); portals.sort((left, right) -> Double.compare(left.distanceToSqr(cameraPos), right.distanceToSqr(cameraPos))); return portals; } - - private static void ensureTarget(Minecraft minecraft, int depth) { - int width = getPortalTargetWidth(minecraft); - int height = getPortalTargetHeight(minecraft); - if (width <= 0 || height <= 0) { + private static void logCandidateState(List portals, List candidates) { + String state = portals.size() + "|" + candidates.stream() + .map(candidate -> candidate.portal().getUUID() + "->" + candidate.linked().getUUID()) + .sorted() + .toList(); + if (state.equals(lastPortalCandidateState)) { return; } - TextureTarget target = PORTAL_TARGETS[depth]; - if (target == null) { - target = new TextureTarget(width, height, true, Minecraft.ON_OSX); - target.setClearColor(0.0F, 0.0F, 0.0F, 1.0F); - PORTAL_TARGETS[depth] = target; - } else if (target.width != width || target.height != height) { - target.resize(width, height, Minecraft.ON_OSX); + lastPortalCandidateState = state; + if (!candidates.isEmpty()) { + PortalSceneRenderTrace.arm(state); } - target.setFilterMode(PORTAL_TARGET_FILTER); - } - - private static boolean ensureTargetSafely(Minecraft minecraft, int depth) { - int width = getPortalTargetWidth(minecraft); - int height = getPortalTargetHeight(minecraft); - TargetAllocationFailure failure = TARGET_ALLOCATION_FAILURES[depth]; - if (failure != null && failure.width() == width && failure.height() == height) { - return false; - } - try { - TARGET_ALLOCATION_FAILURES[depth] = null; - ensureTarget(minecraft, depth); - return PORTAL_TARGETS[depth] != null; - } catch (RuntimeException exception) { - TARGET_ALLOCATION_FAILURES[depth] = new TargetAllocationFailure(width, height); - Antarchy.LOGGER.error("Portal gun render target allocation failed at recursion depth {}", depth, exception); - return false; - } - } - - private static int getPortalTargetWidth(Minecraft minecraft) { - return Math.max(1, (int) Math.ceil(minecraft.getMainRenderTarget().width * RENDER_TARGET_SCALE)); - } - - private static int getPortalTargetHeight(Minecraft minecraft) { - return Math.max(1, (int) Math.ceil(minecraft.getMainRenderTarget().height * RENDER_TARGET_SCALE)); + Antarchy.LOGGER.info("Portal gun view candidates changed portals={} selected={}", portals.size(), candidates.size()); } private static void logRenderFailure(Minecraft minecraft, RuntimeException exception) { @@ -352,344 +352,38 @@ public final class PortalGunPortalViewRenderer { } } - private static boolean renderPortalSurfaceDirect( - Minecraft minecraft, - Entity cameraEntity, - DeltaTracker tickCounter, - RenderContext currentContext, - Matrix4f baseProjectionMatrix, - PortalGunPortalEntity sourcePortal, - PortalGunPortalEntity destinationPortal, - ScreenClip clip - ) { - RenderTarget target = minecraft.getMainRenderTarget(); - if (clip == null) { - return false; - } - int width = target.width; - int height = target.height; - RenderContext transformedContext = transformContext(currentContext, sourcePortal, destinationPortal); - float partialTick = tickCounter.getGameTimeDeltaPartialTick(true); - Matrix4f clippedProjection = applyPortalClipPlane(baseProjectionMatrix, transformedContext, destinationPortal); - Matrix4f apertureCullProjection = cropProjectionToScreenClip(clippedProjection, clip, width, height); - PortalCamera portalCamera = new PortalCamera(); - portalCamera.setup(minecraft.level, cameraEntity, partialTick, transformedContext.cameraPos(), transformedContext.look(), transformedContext.up()); - String portalPairKey = sourcePortal.getUUID() + "->" + destinationPortal.getUUID(); - boolean renderDestination = PortalGunPortalVisibilityQueries.shouldRender(sourcePortal.getUUID(), destinationPortal.getUUID()); - LevelRenderer proxyRenderer = renderDestination - ? PortalGunPortalRendererPool.acquire(minecraft, destinationPortal.getUUID(), width, height) : null; - LevelRendererPortalTargetsAccessor levelRendererTargets = proxyRenderer == null ? null : (LevelRendererPortalTargetsAccessor) proxyRenderer; - PostChain entityEffect = levelRendererTargets == null ? null : levelRendererTargets.antarchy$getEntityEffect(); - PostChain transparencyChain = levelRendererTargets == null ? null : levelRendererTargets.antarchy$getTransparencyChain(); - PostChainTargetAccessor entityEffectTarget = entityEffect == null ? null : (PostChainTargetAccessor) entityEffect; - PostChainTargetAccessor transparencyTarget = transparencyChain == null ? null : (PostChainTargetAccessor) transparencyChain; - RenderTarget previousEntityEffectTarget = entityEffectTarget == null ? null : entityEffectTarget.antarchy$getScreenTarget(); - RenderTarget previousTransparencyTarget = transparencyTarget == null ? null : transparencyTarget.antarchy$getScreenTarget(); - PortalStencilTarget.Scope stencilScope = null; - boolean contextPushed = false; - PortalSceneRenderTrace.event(portalPairKey, "destination-render-decision", "render=" + renderDestination + " clip=" + clip.width() + "x" + clip.height()); - try { - if (entityEffectTarget != null) { - entityEffectTarget.antarchy$setScreenTarget(target); - } - if (transparencyTarget != null) { - transparencyTarget.antarchy$setScreenTarget(target); - } - minecraft.gameRenderer.resetProjectionMatrix(clippedProjection); - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "direct-stencil-mask", "clip=" + clip.width() + "x" + clip.height())) { - stencilScope = PortalStencilTarget.beginDirect(target, () -> { - boolean queryStarted = PortalGunPortalVisibilityQueries.begin(sourcePortal.getUUID(), destinationPortal.getUUID()); - try { - drawPortalMask(minecraft, currentContext.cameraPos(), currentContext.viewMatrix(), baseProjectionMatrix, - sourcePortal, partialTick); - } finally { - PortalGunPortalVisibilityQueries.end(sourcePortal.getUUID(), destinationPortal.getUUID(), queryStarted); - } - }, - () -> clearDepthInPortalStencil(minecraft), - () -> restorePortalApertureDepth(minecraft, currentContext.cameraPos(), currentContext.viewMatrix(), baseProjectionMatrix, sourcePortal, partialTick)); - } - if (!renderDestination) { - return false; - } - RenderSystem.enableScissor(clip.x(), clip.y(), clip.width(), clip.height()); - PortalGunPortalRenderState.pushPortalView(new PortalGunPortalRenderState.PortalRenderContext( - sourcePortal.getWorldPortalShape(), destinationPortal.getWorldPortalShape(), transformedContext.cameraPos(), - transformedContext.look(), transformedContext.up(), transformedContext.viewMatrix(), clippedProjection, - 0, false, destinationPortal.getUUID())); - contextPushed = true; - proxyRenderer.prepareCullFrustum(portalCamera.getPosition(), transformedContext.viewMatrix(), apertureCullProjection); - PortalGunPortalViewAreaManager.Scope areaScope = PortalGunPortalViewAreaManager.enter( - minecraft, proxyRenderer, destinationPortal.getUUID(), transformedContext.cameraPos(), portalCamera); - try { - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "direct-manual-scene", "target=" + width + "x" + height)) { - PortalGunProxySceneRenderer.render(minecraft, proxyRenderer, portalCamera, partialTick, - transformedContext.viewMatrix(), clippedProjection, apertureCullProjection, portalPairKey); - } - } finally { - areaScope.close(); - } - PortalStencilTarget.activate(target); - RenderSystem.enableScissor(clip.x(), clip.y(), clip.width(), clip.height()); - minecraft.getEntityRenderDispatcher().prepare(minecraft.level, portalCamera, cameraEntity); - renderPortalTransitionEntities(minecraft, transformedContext.cameraPos(), partialTick, sourcePortal, destinationPortal); - return true; - } finally { - try { - try { - if (stencilScope != null) { - stencilScope.close(); - } - } finally { - if (contextPushed) { - PortalGunPortalRenderState.popPortalView(false); - } - } - } finally { - try { - if (transparencyTarget != null) { - transparencyTarget.antarchy$setScreenTarget(previousTransparencyTarget); - } - } finally { - try { - if (entityEffectTarget != null) { - entityEffectTarget.antarchy$setScreenTarget(previousEntityEffectTarget); - } - } finally { - try { - restorePortalDrawState(); - } finally { - try { - target.bindWrite(true); - } finally { - minecraft.gameRenderer.resetProjectionMatrix(baseProjectionMatrix); - } - } - } - } - } + private static TextureTarget ensureOffscreenTarget(int width, int height) { + if (offscreenTarget == null) { + offscreenTarget = new TextureTarget(width, height, true, Minecraft.ON_OSX); + offscreenTarget.setClearColor(0.0F, 0.0F, 0.0F, 1.0F); + } else if (offscreenTarget.width != width || offscreenTarget.height != height) { + offscreenTarget.resize(width, height, Minecraft.ON_OSX); } + offscreenTarget.setFilterMode(PORTAL_TARGET_FILTER); + return offscreenTarget; } - private static int renderPortalSurface( - Minecraft minecraft, - Entity cameraEntity, - DeltaTracker tickCounter, - PortalViewBudget viewBudget, - RenderContext currentContext, - Matrix4f baseProjectionMatrix, - PortalGunPortalEntity sourcePortal, - PortalGunPortalEntity destinationPortal, - int depth, - ScreenClip precomputedClip - ) { - String portalPairKey = sourcePortal.getUUID() + "->" + destinationPortal.getUUID(); - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "ensure-target", depth + ":" + getPortalTargetWidth(minecraft) + "x" + getPortalTargetHeight(minecraft))) { - if (!ensureTargetSafely(minecraft, depth)) { - return -1; - } - } - TextureTarget target = PORTAL_TARGETS[depth]; - RenderContext transformedContext = transformContext(currentContext, sourcePortal, destinationPortal); - float partialTick = tickCounter.getGameTimeDeltaPartialTick(true); - ScreenClip clip = precomputedClip == null - ? computeScreenClip(currentContext.cameraPos(), currentContext.viewMatrix(), baseProjectionMatrix, sourcePortal, partialTick, target.width, target.height) - : precomputedClip; - if (clip == null) { - return -1; - } - if (!viewBudget.tryReserve()) { - return -1; - } - Matrix4f clippedProjectionMatrix = applyPortalClipPlane(baseProjectionMatrix, transformedContext, destinationPortal); - Matrix4f apertureCullProjection = cropProjectionToScreenClip(clippedProjectionMatrix, clip, target.width, target.height); - // The offscreen target is still composited only through this portal's aperture, - // so use the same conservative destination bounds filter as the direct path. - boolean renderAll = false; - PortalCamera portalCamera = new PortalCamera(); - portalCamera.setup(minecraft.level, cameraEntity, tickCounter.getGameTimeDeltaPartialTick(true), transformedContext.cameraPos(), transformedContext.look(), transformedContext.up()); - RenderTarget previousMainTarget = minecraft.getMainRenderTarget(); - MinecraftMainRenderTargetAccessor targetAccessor = (MinecraftMainRenderTargetAccessor) minecraft; - LevelRenderer proxyRenderer; - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "acquire-proxy", "target=" + target.width + "x" + target.height + " renderDistance=" + minecraft.options.getEffectiveRenderDistance())) { - proxyRenderer = PortalGunPortalRendererPool.acquire(minecraft, destinationPortal.getUUID(), target.width, target.height); - } - LevelRendererPortalTargetsAccessor levelRendererTargets = (LevelRendererPortalTargetsAccessor) proxyRenderer; - PostChain entityEffect = levelRendererTargets.antarchy$getEntityEffect(); - PostChain transparencyChain = levelRendererTargets.antarchy$getTransparencyChain(); - PostChainTargetAccessor entityEffectTarget = entityEffect == null ? null : (PostChainTargetAccessor) entityEffect; - PostChainTargetAccessor transparencyTarget = transparencyChain == null ? null : (PostChainTargetAccessor) transparencyChain; - RenderTarget previousEntityEffectTarget = entityEffectTarget == null ? null : entityEffectTarget.antarchy$getScreenTarget(); - RenderTarget previousTransparencyTarget = transparencyTarget == null ? null : transparencyTarget.antarchy$getScreenTarget(); - targetAccessor.antarchy$setMainRenderTarget(target); - boolean portalRenderStatePushed = false; - PortalStencilTarget.Scope stencilScope = null; - try { - if (entityEffectTarget != null) { - entityEffectTarget.antarchy$setScreenTarget(target); - } - if (transparencyTarget != null) { - transparencyTarget.antarchy$setScreenTarget(target); - } - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "clear-and-stencil", "target=" + target.width + "x" + target.height + " clip=" + clip.width() + "x" + clip.height())) { - target.bindWrite(true); - RenderSystem.disableScissor(); - RenderSystem.depthMask(true); - RenderSystem.colorMask(true, true, true, true); - target.clear(Minecraft.ON_OSX); - minecraft.gameRenderer.resetProjectionMatrix(clippedProjectionMatrix); - int maskTextureId = minecraft.getTextureManager().getTexture(BLUE_OVERLAY).getId(); - stencilScope = PortalStencilTarget.begin( - target, - () -> drawPortalQuad(currentContext.cameraPos(), currentContext.viewMatrix(), baseProjectionMatrix, target.width, target.height, sourcePortal, partialTick, maskTextureId, clip) - ); - } - RenderSystem.enableScissor(clip.x(), clip.y(), clip.width(), clip.height()); - PortalGunPortalRenderState.PortalRenderContext portalRenderContext = new PortalGunPortalRenderState.PortalRenderContext( - sourcePortal.getWorldPortalShape(), - destinationPortal.getWorldPortalShape(), - transformedContext.cameraPos(), - transformedContext.look(), - transformedContext.up(), - transformedContext.viewMatrix(), - clippedProjectionMatrix, - depth, - renderAll, - destinationPortal.getUUID() - ); - PortalGunPortalRenderState.pushPortalView(portalRenderContext); - portalRenderStatePushed = true; - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "prepare-portal-view", "camera=" + transformedContext.cameraPos())) { - proxyRenderer.prepareCullFrustum(portalCamera.getPosition(), transformedContext.viewMatrix(), apertureCullProjection); - } - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "activate-view-area", "destination=" + destinationPortal.getUUID())) { - PortalGunPortalViewAreaManager.Scope scope = PortalGunPortalViewAreaManager.enter(minecraft, proxyRenderer, destinationPortal.getUUID(), transformedContext.cameraPos(), portalCamera); - ignored.close(); - try { - try (PortalSceneRenderTrace.Phase sceneTrace = PortalSceneRenderTrace.begin(portalPairKey, "manual-scene-subpass", "target=" + target.width + "x" + target.height)) { - PortalGunProxySceneRenderer.render(minecraft, proxyRenderer, portalCamera, partialTick, transformedContext.viewMatrix(), clippedProjectionMatrix, apertureCullProjection, portalPairKey); - } - } finally { - try (PortalSceneRenderTrace.Phase releaseTrace = PortalSceneRenderTrace.begin(portalPairKey, "release-view-area", "destination=" + destinationPortal.getUUID())) { - scope.close(); - } - } - } - PortalStencilTarget.activate(target); - RenderSystem.enableScissor(clip.x(), clip.y(), clip.width(), clip.height()); - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "transition-entities", "source=" + sourcePortal.getId())) { - target.bindWrite(true); - minecraft.getEntityRenderDispatcher().prepare(minecraft.level, portalCamera, cameraEntity); - renderPortalTransitionEntities(minecraft, transformedContext.cameraPos(), tickCounter.getGameTimeDeltaPartialTick(true), sourcePortal, destinationPortal); - } catch (RuntimeException exception) { - logRenderFailure(minecraft, exception); - } - if (loggedPortalSceneRenders.add(portalPairKey)) { - Antarchy.LOGGER.info("Portal gun destination scene render pass completed source={} destination={} depth={} target={}x{} texture={} scissor={}x{}+{},{} camera={}", sourcePortal.getId(), destinationPortal.getId(), depth, target.width, target.height, target.getColorTextureId(), clip.width(), clip.height(), clip.x(), clip.y(), transformedContext.cameraPos()); - } - if (depth < MAX_RECURSION_DEPTH) { - List nestedPortals = collectVisiblePortals(minecraft, transformedContext.cameraPos()); - for (PortalGunPortalEntity nestedPortal : nestedPortals) { - if (!viewBudget.hasRemaining()) { - break; - } - PortalGunPortalEntity nestedLinked = nestedPortal.getLinkedPortal(); - if (nestedLinked == null || !nestedLinked.isAlive() || nestedPortal == destinationPortal || nestedPortal == sourcePortal) { - continue; - } - ScreenClip nestedClip = computeScreenClip(transformedContext.cameraPos(), transformedContext.viewMatrix(), baseProjectionMatrix, nestedPortal, partialTick, target.width, target.height); - if (nestedClip == null) { - continue; - } - int nestedTextureId; - try { - nestedTextureId = renderPortalSurface(minecraft, cameraEntity, tickCounter, viewBudget, transformedContext, baseProjectionMatrix, nestedPortal, nestedLinked, depth + 1, nestedClip); - } catch (RuntimeException exception) { - logRenderFailure(minecraft, exception); - continue; - } - if (nestedTextureId < 0) { - continue; - } - try { - RenderSystem.restoreProjectionMatrix(); - RenderSystem.backupProjectionMatrix(); - target.bindWrite(true); - PortalStencilTarget.activate(target); - RenderSystem.enableScissor(clip.x(), clip.y(), clip.width(), clip.height()); - drawPortalQuad(transformedContext.cameraPos(), transformedContext.viewMatrix(), baseProjectionMatrix, target.width, target.height, nestedPortal, partialTick, nestedTextureId, nestedClip); - } catch (RuntimeException exception) { - logRenderFailure(minecraft, exception); - } - } - } - } finally { - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "restore-render-state", "depth=" + depth)) { - try { - try { - if (stencilScope != null) { - stencilScope.close(); - } - } finally { - if (portalRenderStatePushed) { - PortalGunPortalRenderState.popPortalView(renderAll); - } - } - } finally { - try { - restorePortalDrawState(); - } finally { - try { - if (transparencyTarget != null) { - transparencyTarget.antarchy$setScreenTarget(previousTransparencyTarget); - } - } finally { - try { - if (entityEffectTarget != null) { - entityEffectTarget.antarchy$setScreenTarget(previousEntityEffectTarget); - } - } finally { - targetAccessor.antarchy$setMainRenderTarget(previousMainTarget); - previousMainTarget.bindWrite(true); - } - } - } - } - } - } - return target.getColorTextureId(); + private static RenderContext transformContext(RenderContext context, PortalGunPortalEntity source, PortalGunPortalEntity destination) { + PortalGunWorldPortalShape sourceShape = source.getWorldPortalShape(); + PortalGunWorldPortalShape destinationShape = destination.getWorldPortalShape(); + Vec3 relativeEye = context.cameraPos().subtract(sourceShape.center()); + Vec3 destinationEye = destinationShape.center().add(PortalGunTransformUtil.transformPosition(sourceShape, destinationShape, relativeEye)); + Vec3 look = PortalGunTransformUtil.transformVector(sourceShape, destinationShape, context.look()).normalize(); + Vec3 up = PortalGunTransformUtil.transformVector(sourceShape, destinationShape, context.up()).normalize(); + Matrix4f viewMatrix = new Matrix4f().rotation(PortalGunTransformUtil.orientationQuaternion(look, up).conjugate(new Quaternionf())); + return new RenderContext(destinationEye, look, up, viewMatrix); } - private static RenderContext transformContext(RenderContext currentContext, PortalGunPortalEntity sourcePortal, PortalGunPortalEntity destinationPortal) { - var sourceShape = sourcePortal.getWorldPortalShape(); - var destinationShape = destinationPortal.getWorldPortalShape(); - Vec3 relativeEye = currentContext.cameraPos().subtract(sourceShape.center()); - Vec3 transformedEyeOffset = PortalGunTransformUtil.transformPosition(sourceShape, destinationShape, relativeEye); - Vec3 destinationEye = destinationShape.center().add(transformedEyeOffset); - Vec3 transformedLook = PortalGunTransformUtil.transformVector(sourceShape, destinationShape, currentContext.look()).normalize(); - Vec3 transformedUp = PortalGunTransformUtil.transformVector(sourceShape, destinationShape, currentContext.up()).normalize(); - Matrix4f viewMatrix = new Matrix4f().rotation(PortalGunTransformUtil.orientationQuaternion(transformedLook, transformedUp).conjugate(new Quaternionf())); - return new RenderContext(destinationEye, transformedLook, transformedUp, viewMatrix); + private static Matrix4f applyPortalClipPlane(Matrix4f projection, RenderContext context, PortalGunPortalEntity destination) { + PortalGunWorldPortalShape exit = destination.getWorldPortalShape(); + return PortalGunProjectionUtil.clipAtExit(projection, context.cameraPos(), context.look(), context.up(), + exit.center().add(exit.normal().scale(EXIT_CLIP_OFFSET)), exit.normal()); } - private static Matrix4f applyPortalClipPlane(Matrix4f projectionMatrix, RenderContext renderContext, PortalGunPortalEntity destinationPortal) { - Vec3 planePointWorld = destinationPortal.position().add(destinationPortal.getNormalVec().normalize().scale(0.01D)); - Vec3 planeNormalWorld = destinationPortal.getNormalVec().normalize(); - return PortalGunProjectionUtil.clipAtExit(projectionMatrix, renderContext.cameraPos(), renderContext.look(), - renderContext.up(), planePointWorld, planeNormalWorld); - } - - private static ScreenClip computeScreenClip(Vec3 cameraPos, Matrix4f viewMatrix, Matrix4f projectionMatrix, PortalGunPortalEntity portal, float partialTick, int width, int height) { - PortalGunWorldPortalShape renderShape = portal.getWorldPortalShape().scaleAperture(portal.getPortalVisualScale(partialTick)); - Vec3[] worldCorners = renderShape.getCorners(SURFACE_OFFSET); - List clipVertices = new java.util.ArrayList<>(worldCorners.length); - Matrix4f combined = new Matrix4f(projectionMatrix).mul(viewMatrix); - for (Vec3 worldCorner : worldCorners) { - Vec3 corner = worldCorner.subtract(cameraPos); - clipVertices.add(new Vector4f((float) corner.x, (float) corner.y, (float) corner.z, 1.0F).mul(combined)); - } - clipVertices = clipPolygon(clipVertices, false); - clipVertices = clipPolygon(clipVertices, true); + private static ScreenClip computeScreenClip(Vec3 cameraPos, Matrix4f viewMatrix, Matrix4f projectionMatrix, + PortalGunPortalEntity portal, float partialTick, int width, int height) { + List clipVertices = projectPortalPolygon(new Matrix4f(projectionMatrix).mul(viewMatrix), cameraPos, + portal.getWorldPortalShape().scaleAperture(portal.getPortalVisualScale(partialTick))); if (clipVertices.size() < 3) { return null; } @@ -699,10 +393,8 @@ public final class PortalGunPortalViewRenderer { float maxY = Float.NEGATIVE_INFINITY; for (Vector4f projected : clipVertices) { float invW = 1.0F / projected.w; - float ndcX = projected.x * invW; - float ndcY = projected.y * invW; - float screenX = (ndcX * 0.5F + 0.5F) * width; - float screenY = (ndcY * 0.5F + 0.5F) * height; + float screenX = (projected.x * invW * 0.5F + 0.5F) * width; + float screenY = (projected.y * invW * 0.5F + 0.5F) * height; minX = Math.min(minX, screenX); minY = Math.min(minY, screenY); maxX = Math.max(maxX, screenX); @@ -711,14 +403,11 @@ public final class PortalGunPortalViewRenderer { if (maxX <= 0.0F || minX >= width || maxY <= 0.0F || minY >= height) { return null; } - int scissorX = Mth.clamp((int) Math.floor(minX), 0, width - 1); - int scissorMaxX = Mth.clamp((int) Math.ceil(maxX), scissorX + 1, width); - int scissorYTop = Mth.clamp((int) Math.floor(minY), 0, height - 1); - int scissorYBottom = Mth.clamp((int) Math.ceil(maxY), scissorYTop + 1, height); - int scissorY = scissorYTop; - int scissorWidth = Math.max(1, scissorMaxX - scissorX); - int scissorHeight = Math.max(1, scissorYBottom - scissorYTop); - return new ScreenClip(scissorX, scissorY, scissorWidth, scissorHeight); + int x = Mth.clamp((int) Math.floor(minX), 0, width - 1); + int maxClipX = Mth.clamp((int) Math.ceil(maxX), x + 1, width); + int y = Mth.clamp((int) Math.floor(minY), 0, height - 1); + int maxClipY = Mth.clamp((int) Math.ceil(maxY), y + 1, height); + return new ScreenClip(x, y, maxClipX - x, maxClipY - y); } private static Matrix4f cropProjectionToScreenClip(Matrix4f projectionMatrix, ScreenClip clip, int width, int height) { @@ -728,18 +417,17 @@ public final class PortalGunPortalViewRenderer { float top = (float) ((clip.y() + clip.height()) * 2.0D / height - 1.0D); float widthNdc = Math.max(1.0E-5F, right - left); float heightNdc = Math.max(1.0E-5F, top - bottom); - float scaleX = 2.0F / widthNdc; - float scaleY = 2.0F / heightNdc; - float offsetX = -(right + left) / widthNdc; - float offsetY = -(top + bottom) / heightNdc; - return new Matrix4f().translate(offsetX, offsetY, 0.0F).scale(scaleX, scaleY, 1.0F).mul(projectionMatrix); + return new Matrix4f() + .translate(-(right + left) / widthNdc, -(top + bottom) / heightNdc, 0.0F) + .scale(2.0F / widthNdc, 2.0F / heightNdc, 1.0F) + .mul(projectionMatrix); } private static List clipPolygon(List vertices, boolean nearPlane) { if (vertices.isEmpty()) { return vertices; } - List clipped = new java.util.ArrayList<>(vertices.size() + 2); + List clipped = new ArrayList<>(vertices.size() + 2); Vector4f previous = vertices.get(vertices.size() - 1); float previousDistance = clipPlaneDistance(previous, nearPlane); for (Vector4f current : vertices) { @@ -768,32 +456,95 @@ public final class PortalGunPortalViewRenderer { return nearPlane ? vertex.z + vertex.w : vertex.w - 0.001F; } - private static boolean drawPortalQuad(Vec3 cameraPos, Matrix4f viewMatrix, Matrix4f projectionMatrix, int width, int height, PortalGunPortalEntity portal, float partialTick, int textureId, ScreenClip clip) { - if (portalViewShader == null) { - if (!loggedMissingPortalViewShader) { - loggedMissingPortalViewShader = true; - Antarchy.LOGGER.error("Portal gun destination view shader became unavailable; skipping destination composite"); - } - return false; + private static List projectPortalPolygon(Matrix4f combined, Vec3 cameraPos, PortalGunWorldPortalShape shape) { + Vec3[] corners = shape.getCorners(SURFACE_OFFSET); + List polygon = new ArrayList<>(corners.length); + for (Vec3 corner : corners) { + Vec3 relative = corner.subtract(cameraPos); + polygon.add(new Vector4f((float) relative.x, (float) relative.y, (float) relative.z, 1.0F).mul(combined)); } - if (clip == null || width <= 0 || height <= 0) { - return false; - } - PortalGunWorldPortalShape shape = portal.getWorldPortalShape().scaleAperture(portal.getPortalVisualScale(partialTick) * PORTAL_APERTURE_SCALE); - Matrix4f combined = new Matrix4f(projectionMatrix).mul(viewMatrix); - List polygon = projectPortalPolygon(combined, cameraPos, shape); + polygon = clipPolygon(polygon, false); + return clipPolygon(polygon, true); + } + + private static MeshData buildAperture(Vec3 cameraPos, Matrix4f viewMatrix, Matrix4f projectionMatrix, + PortalGunPortalEntity portal, float partialTick, boolean withScreenUv) { + PortalGunWorldPortalShape shape = portal.getWorldPortalShape().scaleAperture(portal.getPortalVisualScale(partialTick)); + List polygon = projectPortalPolygon(new Matrix4f(projectionMatrix).mul(viewMatrix), cameraPos, shape); if (polygon.size() < 3) { - return false; + return null; } - BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION_TEX); + BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.TRIANGLES, + withScreenUv ? DefaultVertexFormat.POSITION_TEX : DefaultVertexFormat.POSITION); for (int index = 1; index + 1 < polygon.size(); index++) { - addPortalViewVertex(buffer, polygon.get(0)); - addPortalViewVertex(buffer, polygon.get(index)); - addPortalViewVertex(buffer, polygon.get(index + 1)); + addClipVertex(buffer, polygon.get(0), withScreenUv); + addClipVertex(buffer, polygon.get(index), withScreenUv); + addClipVertex(buffer, polygon.get(index + 1), withScreenUv); } - MeshData mesh = buffer.build(); + return buffer.build(); + } + + private static void addClipVertex(BufferBuilder buffer, Vector4f clipPosition, boolean withScreenUv) { + float inverseW = 1.0F / clipPosition.w(); + float ndcX = clipPosition.x() * inverseW; + float ndcY = clipPosition.y() * inverseW; + float ndcZ = clipPosition.z() * inverseW; + if (withScreenUv) { + buffer.addVertex(ndcX, ndcY, ndcZ).setUv(ndcX * 0.5F + 0.5F, ndcY * 0.5F + 0.5F); + } else { + buffer.addVertex(ndcX, ndcY, ndcZ); + } + } + + private static void drawPortalMask(Vec3 cameraPos, Matrix4f viewMatrix, Matrix4f projectionMatrix, PortalGunPortalEntity portal, float partialTick) { + drawClipSpaceMesh(buildAperture(cameraPos, viewMatrix, projectionMatrix, portal, partialTick, false)); + } + + private static void restorePortalApertureDepth(Vec3 cameraPos, Matrix4f viewMatrix, Matrix4f projectionMatrix, + PortalGunPortalEntity portal, float partialTick) { + MeshData mesh = buildAperture(cameraPos, viewMatrix, projectionMatrix, portal, partialTick, false); + int previousDepthFunction = GL11.glGetInteger(GL11.GL_DEPTH_FUNC); + GL11.glDepthFunc(GL11.GL_ALWAYS); + try { + drawClipSpaceMesh(mesh); + } finally { + GL11.glDepthFunc(previousDepthFunction); + } + } + + private static void drawClipSpaceMesh(MeshData mesh) { if (mesh == null) { - return false; + return; + } + Matrix4fStack modelViewStack = RenderSystem.getModelViewStack(); + Matrix4f previousProjection = new Matrix4f(RenderSystem.getProjectionMatrix()); + VertexSorting previousSorting = RenderSystem.getVertexSorting(); + modelViewStack.pushMatrix(); + try { + RenderSystem.disableCull(); + RenderSystem.disableBlend(); + modelViewStack.identity(); + RenderSystem.applyModelViewMatrix(); + RenderSystem.setProjectionMatrix(new Matrix4f(), previousSorting); + RenderSystem.setShader(GameRenderer::getPositionShader); + RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + BufferUploader.drawWithShader(mesh); + } finally { + RenderSystem.setProjectionMatrix(previousProjection, previousSorting); + modelViewStack.popMatrix(); + RenderSystem.applyModelViewMatrix(); + RenderSystem.enableCull(); + } + } + + private static void drawPortalComposite(Vec3 cameraPos, Matrix4f viewMatrix, Matrix4f projectionMatrix, + PortalGunPortalEntity portal, float partialTick, int textureId) { + MeshData mesh = buildAperture(cameraPos, viewMatrix, projectionMatrix, portal, partialTick, true); + if (mesh == null || portalViewShader == null) { + if (mesh != null) { + mesh.close(); + } + return; } Matrix4fStack modelViewStack = RenderSystem.getModelViewStack(); Matrix4f previousProjection = new Matrix4f(RenderSystem.getProjectionMatrix()); @@ -818,352 +569,58 @@ public final class PortalGunPortalViewRenderer { RenderSystem.applyModelViewMatrix(); restorePortalDrawState(); } - return true; } - private static void drawPortalMask(Minecraft minecraft, Vec3 cameraPos, Matrix4f viewMatrix, Matrix4f projectionMatrix, - PortalGunPortalEntity portal, float partialTick) { - PortalGunWorldPortalShape shape = portal.getWorldPortalShape() - .scaleAperture(portal.getPortalVisualScale(partialTick) * PORTAL_APERTURE_SCALE); - Matrix4f combined = new Matrix4f(projectionMatrix).mul(viewMatrix); - List polygon = projectPortalPolygon(combined, cameraPos, shape); - if (polygon.size() < 3) { - return; - } - BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION); - for (int index = 1; index + 1 < polygon.size(); index++) { - addDepthVertex(buffer, polygon.get(0)); - addDepthVertex(buffer, polygon.get(index)); - addDepthVertex(buffer, polygon.get(index + 1)); - } - drawClipSpaceMesh(minecraft, buffer.build()); - } - - private static void clearDepthInPortalStencil(Minecraft minecraft) { - int previousDepthFunction = GL11.glGetInteger(GL11.GL_DEPTH_FUNC); - RenderSystem.enableDepthTest(); - RenderSystem.depthMask(true); - RenderSystem.colorMask(false, false, false, false); - GL11.glDepthFunc(GL11.GL_ALWAYS); - BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION); - buffer.addVertex(-1.0F, -1.0F, 1.0F); - buffer.addVertex(3.0F, -1.0F, 1.0F); - buffer.addVertex(-1.0F, 3.0F, 1.0F); - MeshData mesh = buffer.build(); + private static void renderCrossingEntities(Minecraft minecraft, Vec3 cameraPos, float partialTick, + PortalGunPortalEntity sourcePortal, PortalGunPortalEntity destinationPortal, PoseStack poseStack) { + MultiBufferSource.BufferSource bufferSource = PortalGunPortalSceneRenderer.bufferSource(); + List entities = minecraft.level.getEntities((Entity) null, sourcePortal.getWorldPortalShape().getBoundsForCulling(), + entity -> isCrossing(entity, sourcePortal, destinationPortal)); + Set rendered = Collections.newSetFromMap(new IdentityHashMap<>()); try { - drawClipSpaceMesh(minecraft, mesh); - } finally { - GL11.glDepthFunc(previousDepthFunction); - RenderSystem.colorMask(true, true, true, true); - RenderSystem.depthMask(true); - RenderSystem.enableDepthTest(); - } - } - - private static void restorePortalApertureDepth(Minecraft minecraft, Vec3 cameraPos, Matrix4f viewMatrix, Matrix4f projectionMatrix, - PortalGunPortalEntity portal, float partialTick) { - PortalGunWorldPortalShape shape = portal.getWorldPortalShape().scaleAperture(portal.getPortalVisualScale(partialTick) * PORTAL_APERTURE_SCALE); - Matrix4f combined = new Matrix4f(projectionMatrix).mul(viewMatrix); - List polygon = projectPortalPolygon(combined, cameraPos, shape); - if (polygon.size() < 3) { - return; - } - BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION); - for (int index = 1; index + 1 < polygon.size(); index++) { - addDepthVertex(buffer, polygon.get(0)); - addDepthVertex(buffer, polygon.get(index)); - addDepthVertex(buffer, polygon.get(index + 1)); - } - MeshData mesh = buffer.build(); - int previousDepthFunction = GL11.glGetInteger(GL11.GL_DEPTH_FUNC); - RenderSystem.enableDepthTest(); - RenderSystem.depthMask(true); - RenderSystem.colorMask(false, false, false, false); - GL11.glDepthFunc(GL11.GL_ALWAYS); - try { - drawClipSpaceMesh(minecraft, mesh); - } finally { - GL11.glDepthFunc(previousDepthFunction); - RenderSystem.colorMask(true, true, true, true); - RenderSystem.depthMask(true); - RenderSystem.enableDepthTest(); - } - } - - private static void addDepthVertex(BufferBuilder buffer, Vector4f clipPosition) { - float inverseW = 1.0F / clipPosition.w(); - buffer.addVertex(clipPosition.x() * inverseW, clipPosition.y() * inverseW, clipPosition.z() * inverseW); - } - - private static void drawClipSpaceMesh(Minecraft minecraft, MeshData mesh) { - if (mesh == null) { - return; - } - Matrix4fStack modelViewStack = RenderSystem.getModelViewStack(); - boolean cullEnabled = GL11.glIsEnabled(GL11.GL_CULL_FACE); - boolean blendEnabled = GL11.glIsEnabled(GL11.GL_BLEND); - Matrix4f previousProjection = new Matrix4f(RenderSystem.getProjectionMatrix()); - VertexSorting previousSorting = RenderSystem.getVertexSorting(); - modelViewStack.pushMatrix(); - try { - RenderSystem.disableCull(); - RenderSystem.disableBlend(); - modelViewStack.identity(); - RenderSystem.applyModelViewMatrix(); - RenderSystem.setProjectionMatrix(new Matrix4f(), previousSorting); - RenderSystem.setShader(GameRenderer::getPositionShader); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - BufferUploader.drawWithShader(mesh); - } finally { - RenderSystem.setProjectionMatrix(previousProjection, previousSorting); - modelViewStack.popMatrix(); - RenderSystem.applyModelViewMatrix(); - if (cullEnabled) { - RenderSystem.enableCull(); - } else { - RenderSystem.disableCull(); - } - if (blendEnabled) { - RenderSystem.enableBlend(); - } else { - RenderSystem.disableBlend(); - } - } - } - - private static List projectPortalPolygon(Matrix4f combined, Vec3 cameraPos, PortalGunWorldPortalShape shape) { - Vec3[] corners = shape.getCorners(SURFACE_OFFSET); - List polygon = new ArrayList<>(corners.length); - for (Vec3 corner : corners) { - Vec3 relative = corner.subtract(cameraPos); - polygon.add(new Vector4f((float) relative.x, (float) relative.y, (float) relative.z, 1.0F).mul(combined)); - } - polygon = clipPolygon(polygon, false); - return clipPolygon(polygon, true); - } - - private static void addPortalViewVertex(BufferBuilder buffer, Vector4f clipPosition) { - float inverseW = 1.0F / clipPosition.w(); - float ndcX = clipPosition.x() * inverseW; - float ndcY = clipPosition.y() * inverseW; - float ndcZ = clipPosition.z() * inverseW; - buffer.addVertex(ndcX, ndcY, ndcZ).setUv(ndcX * 0.5F + 0.5F, ndcY * 0.5F + 0.5F); - } - - private static void renderPortalTransitionEntities(Minecraft minecraft, Vec3 cameraPos, float partialTick, PortalGunPortalEntity sourcePortal, PortalGunPortalEntity destinationPortal) { - if (minecraft.level == null || minecraft.getEntityRenderDispatcher() == null) { - return; - } - MultiBufferSource.BufferSource bufferSource = PortalGunPortalRendererPool.bufferSource(); - PoseStack poseStack = new PoseStack(); - AABB transitionBounds = sourcePortal.getWorldPortalShape().getBoundsForCulling(); - List renderEntities = minecraft.level.getEntities( - (Entity) null, - transitionBounds, - entity -> shouldRenderTransitionEntity(entity, sourcePortal, destinationPortal) - ); - Set renderedEntities = Collections.newSetFromMap(new IdentityHashMap<>()); - try { - for (Entity entity : renderEntities) { - renderTransitionEntityTree(minecraft, cameraPos, partialTick, sourcePortal, destinationPortal, entity, poseStack, bufferSource, renderedEntities); + for (Entity entity : entities) { + renderCrossingEntityTree(minecraft, cameraPos, partialTick, sourcePortal, destinationPortal, entity, poseStack, bufferSource, rendered); } } finally { bufferSource.endBatch(); } } - private static void renderTransitionEntityTree(Minecraft minecraft, Vec3 cameraPos, float partialTick, PortalGunPortalEntity sourcePortal, PortalGunPortalEntity destinationPortal, Entity entity, PoseStack poseStack, MultiBufferSource.BufferSource bufferSource, Set renderedEntities) { - if (!shouldRenderTransitionEntity(entity, sourcePortal, destinationPortal) || !renderedEntities.add(entity)) { + private static void renderCrossingEntityTree(Minecraft minecraft, Vec3 cameraPos, float partialTick, PortalGunPortalEntity sourcePortal, + PortalGunPortalEntity destinationPortal, Entity entity, PoseStack poseStack, + MultiBufferSource.BufferSource bufferSource, Set rendered) { + if (!isCrossing(entity, sourcePortal, destinationPortal) || !rendered.add(entity)) { return; } - renderTransitionEntity(minecraft, cameraPos, partialTick, sourcePortal, destinationPortal, entity, poseStack, bufferSource); - for (Entity passenger : entity.getPassengers()) { - renderTransitionEntityTree(minecraft, cameraPos, partialTick, sourcePortal, destinationPortal, passenger, poseStack, bufferSource, renderedEntities); - } - } - - private static boolean shouldRenderTransitionEntity(Entity entity, PortalGunPortalEntity sourcePortal, PortalGunPortalEntity destinationPortal) { - return entity != null - && entity.isAlive() - && !(entity instanceof PortalGunPortalEntity) - && entity != sourcePortal - && entity != destinationPortal - && sourcePortal.intersectsEntityBounds(entity); - } - - private static void renderTransitionEntity(Minecraft minecraft, Vec3 cameraPos, float partialTick, PortalGunPortalEntity sourcePortal, PortalGunPortalEntity destinationPortal, Entity entity, PoseStack poseStack, MultiBufferSource.BufferSource bufferSource) { PortalGunEntityTransformationStack transformationStack = new PortalGunEntityTransformationStack(entity); transformationStack.push(); try { - Vec3 transformedPosition = transformationStack.moveEntity(sourcePortal, destinationPortal, partialTick); + Vec3 position = transformationStack.moveEntity(sourcePortal, destinationPortal, partialTick); float yaw = Mth.rotLerp(partialTick, entity.yRotO, entity.getYRot()); int light = minecraft.getEntityRenderDispatcher().getPackedLightCoords(entity, partialTick); - RenderSystem.enableDepthTest(); - RenderSystem.depthMask(true); PortalGunPortalRenderState.pushDestinationShape(destinationPortal.getWorldPortalShape()); try { - minecraft.getEntityRenderDispatcher().render( - entity, - transformedPosition.x - cameraPos.x, - transformedPosition.y - cameraPos.y, - transformedPosition.z - cameraPos.z, - yaw, - partialTick, - poseStack, - bufferSource, - light - ); + minecraft.getEntityRenderDispatcher().render(entity, position.x - cameraPos.x, position.y - cameraPos.y, + position.z - cameraPos.z, yaw, partialTick, poseStack, bufferSource, light); } finally { PortalGunPortalRenderState.popDestinationShape(); } } finally { transformationStack.pop(); } - } - - private static void drawPortalOverlay(Minecraft minecraft, Vec3 cameraPos, Matrix4f poseMatrix, PortalGunPortalEntity portal) { - if (!portal.shouldRenderFront(cameraPos)) { - return; - } - RenderSystem.disableScissor(); - float time = (minecraft.level.getGameTime() + minecraft.getTimer().getGameTimeDeltaPartialTick(false)) * 0.075F; - float pulse = 0.72F + 0.18F * (float) Math.sin(time); - float edge = 0.38F + 0.08F * (float) Math.cos(time * 1.7F); - float channelRed = portal.getChannelRed() / 255.0F; - float channelGreen = portal.getChannelGreen() / 255.0F; - float channelBlue = portal.getChannelBlue() / 255.0F; - if (portal.getPortalSide() == PortalGunPortalEntity.PortalSide.BLUE) { - drawTexturedPortal(cameraPos, poseMatrix, portal, BLUE_OVERLAY, OVERLAY_OFFSET, 0.78F, 0.94F, 1.0F, pulse, false); - drawTexturedPortal(cameraPos, poseMatrix, portal, BLUE_OVERLAY, OVERLAY_OFFSET + 0.0008D, channelRed, channelGreen, channelBlue, edge, true); - drawAnimatedPortalOverlay(minecraft, cameraPos, poseMatrix, portal); - return; - } - drawTexturedPortal(cameraPos, poseMatrix, portal, ORANGE_OVERLAY, OVERLAY_OFFSET, 1.0F, 0.84F, 0.46F, pulse, false); - drawTexturedPortal(cameraPos, poseMatrix, portal, ORANGE_OVERLAY, OVERLAY_OFFSET + 0.0008D, channelRed, channelGreen, channelBlue, edge, true); - drawAnimatedPortalOverlay(minecraft, cameraPos, poseMatrix, portal); - } - - private static void drawAnimatedPortalOverlay(Minecraft minecraft, Vec3 cameraPos, Matrix4f poseMatrix, PortalGunPortalEntity portal) { - if (!AntarchySettings.portalGunFancyPortals() - || minecraft.options.graphicsMode().get() != GraphicsStatus.FANCY) { - return; - } - ResourceLocation texture = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, - "textures/entity/portal_gun/" + (portal.getPortalSide() == PortalGunPortalEntity.PortalSide.BLUE - ? "portal_blue_vortex.png" - : "portal_orange_vortex.png")); - float partialTick = minecraft.getTimer().getGameTimeDeltaPartialTick(true); - float portalScale = portal.getPortalVisualScale(partialTick); - Vec3 widthVec = portal.getWidthVec().normalize().scale(portal.getPortalWidth() / 2.0D * portalScale); - Vec3 upVec = portal.getUpVec().normalize().scale(portal.getPortalHeight() / 2.0D * portalScale); - Vec3 normalVec = portal.getNormalVec().normalize().scale(OVERLAY_OFFSET + 0.0016D); - Vec3 center = portal.position().add(normalVec); - Vec3 bottomLeft = center.subtract(widthVec).subtract(upVec).subtract(cameraPos); - Vec3 topLeft = center.subtract(widthVec).add(upVec).subtract(cameraPos); - Vec3 topRight = center.add(widthVec).add(upVec).subtract(cameraPos); - Vec3 bottomRight = center.add(widthVec).subtract(upVec).subtract(cameraPos); - float red = portal.getPortalSide() == PortalGunPortalEntity.PortalSide.BLUE ? 0.78F : 1.0F; - float green = portal.getPortalSide() == PortalGunPortalEntity.PortalSide.BLUE ? 0.94F : 0.84F; - float blue = portal.getPortalSide() == PortalGunPortalEntity.PortalSide.BLUE ? 1.0F : 0.46F; - float frameV = Math.floorMod((int) ((minecraft.level.getGameTime() + minecraft.getTimer().getGameTimeDeltaPartialTick(false)) / 5.0F), 4) * 0.25F; - float frameBottomV = frameV + 0.25F; - BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX); - buffer.addVertex(poseMatrix, (float) bottomLeft.x, (float) bottomLeft.y, (float) bottomLeft.z).setUv(0.0F, frameBottomV); - buffer.addVertex(poseMatrix, (float) topLeft.x, (float) topLeft.y, (float) topLeft.z).setUv(0.0F, frameV); - buffer.addVertex(poseMatrix, (float) topRight.x, (float) topRight.y, (float) topRight.z).setUv(1.0F, frameV); - buffer.addVertex(poseMatrix, (float) bottomRight.x, (float) bottomRight.y, (float) bottomRight.z).setUv(1.0F, frameBottomV); - MeshData mesh = buffer.build(); - try { - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - RenderSystem.depthMask(false); - RenderSystem.enableDepthTest(); - RenderSystem.disableCull(); - RenderSystem.setShader(GameRenderer::getPositionTexShader); - RenderSystem.setShaderTexture(0, texture); - RenderSystem.setShaderColor(red, green, blue, 0.92F); - if (mesh != null) { - BufferUploader.drawWithShader(mesh); - } - } finally { - restorePortalDrawState(); + for (Entity passenger : entity.getPassengers()) { + renderCrossingEntityTree(minecraft, cameraPos, partialTick, sourcePortal, destinationPortal, passenger, poseStack, bufferSource, rendered); } } - private static void drawTexturedPortal(Vec3 cameraPos, Matrix4f poseMatrix, PortalGunPortalEntity portal, ResourceLocation texture, double offset, float red, float green, float blue, float alpha, boolean additive) { - float portalScale = portal.getPortalVisualScale(Minecraft.getInstance().getTimer().getGameTimeDeltaPartialTick(true)); - Vec3 widthVec = portal.getWidthVec().normalize().scale(portal.getPortalWidth() / 2.0D * portalScale); - Vec3 upVec = portal.getUpVec().normalize().scale(portal.getPortalHeight() / 2.0D * portalScale); - Vec3 normalVec = portal.getNormalVec().normalize().scale(offset); - Vec3 center = portal.position().add(normalVec); - Vec3 bottomLeft = center.subtract(widthVec).subtract(upVec).subtract(cameraPos); - Vec3 topLeft = center.subtract(widthVec).add(upVec).subtract(cameraPos); - Vec3 topRight = center.add(widthVec).add(upVec).subtract(cameraPos); - Vec3 bottomRight = center.add(widthVec).subtract(upVec).subtract(cameraPos); - - BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX); - buffer.addVertex(poseMatrix, (float) bottomLeft.x, (float) bottomLeft.y, (float) bottomLeft.z).setUv(0.0F, 1.0F); - buffer.addVertex(poseMatrix, (float) topLeft.x, (float) topLeft.y, (float) topLeft.z).setUv(0.0F, 0.0F); - buffer.addVertex(poseMatrix, (float) topRight.x, (float) topRight.y, (float) topRight.z).setUv(1.0F, 0.0F); - buffer.addVertex(poseMatrix, (float) bottomRight.x, (float) bottomRight.y, (float) bottomRight.z).setUv(1.0F, 1.0F); - MeshData mesh = buffer.build(); - try { - RenderSystem.enableBlend(); - if (additive) { - RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); - } else { - RenderSystem.defaultBlendFunc(); - } - RenderSystem.depthMask(false); - RenderSystem.enableDepthTest(); - RenderSystem.disableCull(); - RenderSystem.setShader(GameRenderer::getPositionTexShader); - RenderSystem.setShaderTexture(0, texture); - RenderSystem.setShaderColor(red, green, blue, alpha); - if (mesh != null) { - BufferUploader.drawWithShader(mesh); - } - } finally { - restorePortalDrawState(); - } - } - - private static void drawTexturedPortal(Vec3 cameraPos, Matrix4f poseMatrix, PortalGunPortalEntity portal, int textureId, double offset, float red, float green, float blue, float alpha, boolean additive, float bottomLeftU, float bottomLeftV, float topLeftU, float topLeftV, float topRightU, float topRightV, float bottomRightU, float bottomRightV) { - float portalScale = portal.getPortalVisualScale(Minecraft.getInstance().getTimer().getGameTimeDeltaPartialTick(true)); - Vec3 widthVec = portal.getWidthVec().normalize().scale(portal.getPortalWidth() / 2.0D * portalScale); - Vec3 upVec = portal.getUpVec().normalize().scale(portal.getPortalHeight() / 2.0D * portalScale); - Vec3 normalVec = portal.getNormalVec().normalize().scale(offset); - Vec3 center = portal.position().add(normalVec); - Vec3 bottomLeft = center.subtract(widthVec).subtract(upVec).subtract(cameraPos); - Vec3 topLeft = center.subtract(widthVec).add(upVec).subtract(cameraPos); - Vec3 topRight = center.add(widthVec).add(upVec).subtract(cameraPos); - Vec3 bottomRight = center.add(widthVec).subtract(upVec).subtract(cameraPos); - - BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX); - buffer.addVertex(poseMatrix, (float) bottomLeft.x, (float) bottomLeft.y, (float) bottomLeft.z).setUv(bottomLeftU, bottomLeftV); - buffer.addVertex(poseMatrix, (float) topLeft.x, (float) topLeft.y, (float) topLeft.z).setUv(topLeftU, topLeftV); - buffer.addVertex(poseMatrix, (float) topRight.x, (float) topRight.y, (float) topRight.z).setUv(topRightU, topRightV); - buffer.addVertex(poseMatrix, (float) bottomRight.x, (float) bottomRight.y, (float) bottomRight.z).setUv(bottomRightU, bottomRightV); - MeshData mesh = buffer.build(); - try { - RenderSystem.enableBlend(); - if (additive) { - RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); - } else { - RenderSystem.defaultBlendFunc(); - } - RenderSystem.depthMask(false); - RenderSystem.enableDepthTest(); - RenderSystem.disableCull(); - RenderSystem.setShader(GameRenderer::getPositionTexShader); - RenderSystem.setShaderTexture(0, textureId); - RenderSystem.setShaderColor(red, green, blue, alpha); - if (mesh != null) { - BufferUploader.drawWithShader(mesh); - } - } finally { - restorePortalDrawState(); - } + private static boolean isCrossing(Entity entity, PortalGunPortalEntity sourcePortal, PortalGunPortalEntity destinationPortal) { + return entity != null + && entity.isAlive() + && !(entity instanceof PortalGunPortalEntity) + && entity != sourcePortal + && entity != destinationPortal + && entity != Minecraft.getInstance().getCameraEntity() + && sourcePortal.intersectsEntityBounds(entity); } private static void restorePortalDrawState() { @@ -1179,13 +636,11 @@ public final class PortalGunPortalViewRenderer { private static final class PortalCamera extends Camera { private void setup(net.minecraft.world.level.BlockGetter level, Entity cameraEntity, float partialTick, Vec3 position, Vec3 look, Vec3 up) { - super.setup(level, cameraEntity, false, false, partialTick); + super.setup(level, cameraEntity, true, false, partialTick); Vec3 normalizedLook = look.normalize(); Vec3 normalizedUp = up.subtract(normalizedLook.scale(up.dot(normalizedLook))).normalize(); - float yaw = PortalGunTransformUtil.yawFromLook(normalizedLook); - float pitch = PortalGunTransformUtil.pitchFromLook(normalizedLook); this.setPosition(position); - this.setRotation(yaw, pitch); + this.setRotation(PortalGunTransformUtil.yawFromLook(normalizedLook), PortalGunTransformUtil.pitchFromLook(normalizedLook)); Quaternionf orientation = PortalGunTransformUtil.orientationQuaternion(normalizedLook, normalizedUp); this.rotation().set(orientation); CameraBasisAccessor basis = (CameraBasisAccessor) (Object) this; @@ -1198,10 +653,13 @@ public final class PortalGunPortalViewRenderer { private record RenderContext(Vec3 cameraPos, Vec3 look, Vec3 up, Matrix4f viewMatrix) { } - private static final class PortalViewBudget { + private record RootCandidate(PortalGunPortalEntity portal, PortalGunPortalEntity linked, ScreenClip clip) { + } + + private static final class ViewBudget { private int remaining; - private PortalViewBudget(int maximumViews) { + private ViewBudget(int maximumViews) { this.remaining = maximumViews; } @@ -1222,8 +680,13 @@ public final class PortalGunPortalViewRenderer { private int area() { return this.width * this.height; } - } - private record TargetAllocationFailure(int width, int height) { + private ScreenClip intersect(ScreenClip other) { + int minX = Math.max(this.x, other.x); + int minY = Math.max(this.y, other.y); + int maxX = Math.min(this.x + this.width, other.x + other.width); + int maxY = Math.min(this.y + this.height, other.y + other.height); + return maxX <= minX || maxY <= minY ? null : new ScreenClip(minX, minY, maxX - minX, maxY - minY); + } } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunProxySceneRenderer.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunProxySceneRenderer.java deleted file mode 100644 index 75e2b9b1..00000000 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunProxySceneRenderer.java +++ /dev/null @@ -1,246 +0,0 @@ -package com.craisinlord.antarchy.content.client.renderer; - -import com.craisinlord.antarchy.content.client.PortalGunPortalRenderState; -import com.craisinlord.antarchy.mixins.client.LevelRendererPortalSceneInvoker; -import com.craisinlord.antarchy.mixins.client.LevelRendererPortalViewAreaAccessor; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.platform.Lighting; -import com.mojang.blaze3d.shaders.FogShape; -import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.Camera; -import net.minecraft.client.CloudStatus; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.FogRenderer; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.chunk.SectionRenderDispatcher; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.culling.Frustum; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.phys.Vec3; -import net.minecraft.world.phys.AABB; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import org.joml.Matrix4f; -import org.joml.Matrix4fStack; - -public final class PortalGunProxySceneRenderer { - private PortalGunProxySceneRenderer() { - } - - public static void render(Minecraft minecraft, LevelRenderer renderer, Camera camera, float partialTick, Matrix4f modelViewMatrix, Matrix4f projectionMatrix, Matrix4f cullProjectionMatrix, String tracePair) { - Matrix4fStack outerModelViewStack = RenderSystem.getModelViewStack(); - float previousFogStart = RenderSystem.getShaderFogStart(); - float previousFogEnd = RenderSystem.getShaderFogEnd(); - float[] previousFogColor = RenderSystem.getShaderFogColor().clone(); - FogShape previousFogShape = RenderSystem.getShaderFogShape(); - outerModelViewStack.pushMatrix(); - outerModelViewStack.identity(); - RenderSystem.applyModelViewMatrix(); - ObjectArrayList originalVisibleSections = null; - try { - Vec3 cameraPosition = camera.getPosition(); - double cameraX = cameraPosition.x; - double cameraY = cameraPosition.y; - double cameraZ = cameraPosition.z; - Frustum frustum = new Frustum(modelViewMatrix, cullProjectionMatrix); - frustum.prepare(cameraX, cameraY, cameraZ); - LevelRendererPortalSceneInvoker scene = (LevelRendererPortalSceneInvoker) renderer; - float renderDistance = minecraft.gameRenderer.getRenderDistance(); - BlockPos cameraBlockPos = BlockPos.containing(cameraX, cameraY, cameraZ); - boolean foggy = minecraft.level.effects().isFoggyAt(cameraBlockPos.getX(), cameraBlockPos.getY()) - || minecraft.gui.getBossOverlay().shouldCreateWorldFog(); - - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "sky", "camera=" + cameraPosition)) { - RenderSystem.setShaderGameTime(minecraft.level.getGameTime(), partialTick); - minecraft.getBlockEntityRenderDispatcher().prepare(minecraft.level, camera, minecraft.hitResult); - minecraft.getEntityRenderDispatcher().prepare(minecraft.level, camera, minecraft.crosshairPickEntity); - FogRenderer.setupColor(camera, partialTick, minecraft.level, minecraft.options.getEffectiveRenderDistance(), minecraft.gameRenderer.getDarkenWorldAmount(partialTick)); - FogRenderer.levelFogColor(); - FogRenderer.setupFog(camera, FogRenderer.FogMode.FOG_SKY, renderDistance, foggy, partialTick); - RenderSystem.setShader(net.minecraft.client.renderer.GameRenderer::getPositionShader); - renderer.renderSky(modelViewMatrix, projectionMatrix, partialTick, camera, foggy, - () -> FogRenderer.setupFog(camera, FogRenderer.FogMode.FOG_SKY, renderDistance, foggy, partialTick)); - } - - boolean sodium = SodiumCompat.isLoaded(); - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "frustum-and-visibility", "renderDistance=" + (sodium ? minecraft.options.getEffectiveRenderDistance() : rendererAccessDistance(renderer)))) { - FogRenderer.setupFog(camera, FogRenderer.FogMode.FOG_TERRAIN, Math.max(renderDistance, 32.0F), foggy, partialTick); - scene.antarchy$setupPortalScene(camera, frustum, false, minecraft.player != null && minecraft.player.isSpectator()); - } - LevelRendererPortalViewAreaAccessor viewAreaAccessor = sodium ? null : (LevelRendererPortalViewAreaAccessor) renderer; - int visibleSectionCount = 0; - int candidateSectionCount = 0; - if (viewAreaAccessor != null) { - originalVisibleSections = viewAreaAccessor.antarchy$getVisibleSections(); - candidateSectionCount = originalVisibleSections.size(); - ObjectArrayList apertureSections = new ObjectArrayList<>(); - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "aperture-section-cull", "candidateSections=" + candidateSectionCount)) { - for (SectionRenderDispatcher.RenderSection section : originalVisibleSections) { - if (PortalGunPortalRenderState.shouldRenderBounds(section.getBoundingBox())) { - apertureSections.add(section); - } - } - } - viewAreaAccessor.antarchy$setVisibleSections(apertureSections); - ObjectArrayList fullVisibleSections = apertureSections; - ObjectArrayList budgetedVisibleSections = new ObjectArrayList<>(); - int scannedVisibleSections = 0; - while (scannedVisibleSections < fullVisibleSections.size() && PortalGunPortalRendererPool.remainingSectionBudgetNanos() > 0L) { - budgetedVisibleSections.add(fullVisibleSections.get(scannedVisibleSections++)); - } - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "compile-visible-sections", "visibleTotal=" + fullVisibleSections.size() + " visibleScanned=" + scannedVisibleSections + " rebuildBudgetNanos=" + PortalGunPortalRendererPool.remainingSectionBudgetNanos())) { - viewAreaAccessor.antarchy$setVisibleSections(budgetedVisibleSections); - try { - scene.antarchy$compilePortalSections(camera); - } finally { - viewAreaAccessor.antarchy$setVisibleSections(fullVisibleSections); - } - } - visibleSectionCount = fullVisibleSections.size(); - } - PortalSceneRenderTrace.event(tracePair, "visible-sections-ready", "renderer=" + (sodium ? "sodium" : "vanilla") - + " count=" + visibleSectionCount + " candidates=" + candidateSectionCount - + " scheduledRebuilds=" + PortalGunPortalRendererPool.scheduledSectionRebuilds() - + " uploaded=" + PortalGunPortalRendererPool.uploadedThisFrame() - + " pendingUploads=" + (sodium ? "sodium-managed" : viewAreaAccessor.antarchy$getSectionRenderDispatcher().getToUpload())); - - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "opaque-terrain-layers", "sections=" + visibleSectionCount)) { - RenderSystem.enableDepthTest(); - RenderSystem.depthMask(true); - scene.antarchy$renderPortalSectionLayer(RenderType.solid(), cameraX, cameraY, cameraZ, modelViewMatrix, projectionMatrix); - scene.antarchy$renderPortalSectionLayer(RenderType.cutoutMipped(), cameraX, cameraY, cameraZ, modelViewMatrix, projectionMatrix); - scene.antarchy$renderPortalSectionLayer(RenderType.cutout(), cameraX, cameraY, cameraZ, modelViewMatrix, projectionMatrix); - } - - if (minecraft.level.effects().constantAmbientLight()) { - Lighting.setupNetherLevel(); - } else { - Lighting.setupLevel(); - } - - Matrix4fStack modelViewStack = RenderSystem.getModelViewStack(); - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "entity-scene-state", "enter-model-view")) { - modelViewStack.pushMatrix(); - modelViewStack.mul(modelViewMatrix); - RenderSystem.applyModelViewMatrix(); - } - PoseStack poseStack = new PoseStack(); - MultiBufferSource.BufferSource buffers = PortalGunPortalRendererPool.bufferSource(); - try { - int entityCount = 0; - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "entities", "dispatch-start")) { - for (Entity entity : minecraft.level.entitiesForRendering()) { - if (!minecraft.getEntityRenderDispatcher().shouldRender(entity, frustum, cameraX, cameraY, cameraZ) - && !entity.hasIndirectPassenger(minecraft.player)) { - continue; - } - if (entity == camera.getEntity() && !camera.isDetached() - && (!(entity instanceof LivingEntity living) || !living.isSleeping())) { - continue; - } - if (entity instanceof Player player && player == minecraft.player && !player.isSpectator() && entity != camera.getEntity()) { - continue; - } - scene.antarchy$renderPortalEntity(entity, cameraX, cameraY, cameraZ, partialTick, poseStack, buffers); - entityCount++; - } - } - buffers.endBatch(); - PortalSceneRenderTrace.event(tracePair, "entities-dispatched", "count=" + entityCount); - - int blockEntityCount = 0; - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "block-entities", "visibleSections=" + visibleSectionCount)) { - if (sodium) { - int[] count = {0}; - SodiumCompat.forEachVisibleBlockEntity(blockEntity -> { - renderBlockEntity(minecraft, blockEntity, cameraX, cameraY, cameraZ, partialTick, poseStack, buffers); - count[0]++; - }); - blockEntityCount = count[0]; - } else { - for (var section : viewAreaAccessor.antarchy$getVisibleSections()) { - for (BlockEntity blockEntity : section.getCompiled().getRenderableBlockEntities()) { - renderBlockEntity(minecraft, blockEntity, cameraX, cameraY, cameraZ, partialTick, poseStack, buffers); - blockEntityCount++; - } - } - synchronized (viewAreaAccessor.antarchy$getGlobalBlockEntities()) { - for (BlockEntity blockEntity : viewAreaAccessor.antarchy$getGlobalBlockEntities()) { - if (frustum.isVisible(new AABB(blockEntity.getBlockPos()).inflate(1.0D))) { - renderBlockEntity(minecraft, blockEntity, cameraX, cameraY, cameraZ, partialTick, poseStack, buffers); - blockEntityCount++; - } - } - } - } - } - buffers.endBatch(); - PortalSceneRenderTrace.event(tracePair, "block-entities-dispatched", "count=" + blockEntityCount); - - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "translucent-and-particles", "rendering")) { - scene.antarchy$renderPortalSectionLayer(RenderType.translucent(), cameraX, cameraY, cameraZ, modelViewMatrix, projectionMatrix); - buffers.endBatch(RenderType.lines()); - buffers.endBatch(); - scene.antarchy$renderPortalSectionLayer(RenderType.tripwire(), cameraX, cameraY, cameraZ, modelViewMatrix, projectionMatrix); - minecraft.particleEngine.render(minecraft.gameRenderer.lightTexture(), camera, partialTick); - } - - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "clouds", minecraft.options.getCloudsType().toString())) { - if (minecraft.options.getCloudsType() != CloudStatus.OFF) { - renderer.renderClouds(poseStack, modelViewMatrix, projectionMatrix, partialTick, cameraX, cameraY, cameraZ); - } - } - - try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "weather-and-border", "rendering")) { - RenderSystem.depthMask(false); - scene.antarchy$renderPortalWeather(minecraft.gameRenderer.lightTexture(), partialTick, cameraX, cameraY, cameraZ); - scene.antarchy$renderPortalWorldBorder(camera); - } - } finally { - try { - buffers.endBatch(); - } finally { - modelViewStack.popMatrix(); - RenderSystem.applyModelViewMatrix(); - RenderSystem.depthMask(true); - RenderSystem.enableDepthTest(); - RenderSystem.enableCull(); - RenderSystem.disableBlend(); - } - } - } finally { - if (originalVisibleSections != null) { - ((LevelRendererPortalViewAreaAccessor) renderer).antarchy$setVisibleSections(originalVisibleSections); - } - outerModelViewStack.popMatrix(); - RenderSystem.applyModelViewMatrix(); - RenderSystem.setShaderFogStart(previousFogStart); - RenderSystem.setShaderFogEnd(previousFogEnd); - RenderSystem.setShaderFogColor(previousFogColor[0], previousFogColor[1], previousFogColor[2], previousFogColor[3]); - RenderSystem.setShaderFogShape(previousFogShape); - } - } - - private static int rendererAccessDistance(LevelRenderer renderer) { - return ((LevelRendererPortalViewAreaAccessor) renderer).antarchy$getViewArea().getViewDistance(); - } - - private static void renderBlockEntity(Minecraft minecraft, BlockEntity blockEntity, double cameraX, double cameraY, double cameraZ, - float partialTick, PoseStack poseStack, MultiBufferSource.BufferSource buffers) { - if (!blockEntity.hasLevel() || !blockEntity.getType().isValid(blockEntity.getBlockState())) { - return; - } - BlockPos pos = blockEntity.getBlockPos(); - poseStack.pushPose(); - try { - poseStack.translate(pos.getX() - cameraX, pos.getY() - cameraY, pos.getZ() - cameraZ); - minecraft.getBlockEntityRenderDispatcher().render(blockEntity, partialTick, poseStack, buffers); - } finally { - poseStack.popPose(); - } - } -} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalRenderWatchdog.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalRenderWatchdog.java new file mode 100644 index 00000000..849a54cb --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalRenderWatchdog.java @@ -0,0 +1,56 @@ +package com.craisinlord.antarchy.content.client.renderer; + +import com.craisinlord.antarchy.Antarchy; + +final class PortalRenderWatchdog { + private static final long STALL_NANOS = 5_000_000_000L; + private static final long RECENT_PORTAL_NANOS = 10_000_000_000L; + private static volatile Thread renderThread; + private static volatile long lastFrameNanos; + private static volatile long lastPortalViewNanos = Long.MIN_VALUE; + private static volatile boolean reportedStall; + private static Thread watcher; + + private PortalRenderWatchdog() { + } + + static void frame() { + lastFrameNanos = System.nanoTime(); + reportedStall = false; + if (watcher == null) { + renderThread = Thread.currentThread(); + watcher = new Thread(PortalRenderWatchdog::watch, "Antarchy portal render watchdog"); + watcher.setDaemon(true); + watcher.start(); + } + } + + static void portalViewDrawn() { + lastPortalViewNanos = System.nanoTime(); + } + + private static void watch() { + while (true) { + try { + Thread.sleep(1000L); + } catch (InterruptedException exception) { + return; + } + long now = System.nanoTime(); + long lastFrame = lastFrameNanos; + long lastPortal = lastPortalViewNanos; + Thread thread = renderThread; + if (reportedStall || thread == null || lastPortal == Long.MIN_VALUE + || now - lastFrame < STALL_NANOS || lastFrame - lastPortal > RECENT_PORTAL_NANOS) { + continue; + } + reportedStall = true; + StringBuilder stack = new StringBuilder(); + for (StackTraceElement element : thread.getStackTrace()) { + stack.append("\n\tat ").append(element); + } + Antarchy.LOGGER.warn("Render thread has not finished a frame for {} ms after portal views were drawn (state {}). Stack:{}", + (now - lastFrame) / 1_000_000L, thread.getState(), stack); + } + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalSectionGraphMarker.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalSectionGraphMarker.java new file mode 100644 index 00000000..9d5e7588 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalSectionGraphMarker.java @@ -0,0 +1,5 @@ +package com.craisinlord.antarchy.content.client.renderer; + +public interface PortalSectionGraphMarker { + void antarchy$markPortalGraph(); +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalStencilTarget.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalStencilTarget.java index 6153f269..3a46d6da 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalStencilTarget.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalStencilTarget.java @@ -7,15 +7,14 @@ import java.util.Collections; import java.util.IdentityHashMap; import java.util.Map; import java.util.Objects; -import java.util.Set; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL30; public final class PortalStencilTarget { - private static final Map ATTACHMENTS = Collections.synchronizedMap(new IdentityHashMap<>()); + private static final int GL_INCR = 7682; + private static final int GL_DECR = 7683; private static final Map MAIN_STENCIL_ATTACHMENTS = Collections.synchronizedMap(new IdentityHashMap<>()); private static final Map UNSUPPORTED_MAIN_TARGETS = Collections.synchronizedMap(new IdentityHashMap<>()); - private static final Set DIRECT_TARGETS = Collections.newSetFromMap(new IdentityHashMap<>()); private PortalStencilTarget() { } @@ -52,105 +51,67 @@ public final class PortalStencilTarget { return stencilBits() > 0; } - public static Scope beginDirect(RenderTarget target, Runnable drawApertureMask, Runnable clearApertureDepth, Runnable restoreApertureDepth) { - target.bindWrite(true); - if (stencilBits() <= 0) { - throw new IllegalStateException("Main render target has no stencil attachment"); - } - DIRECT_TARGETS.add(target); + public static void beginFrame(RenderTarget target) { target.bindWrite(true); RenderSystem.disableScissor(); RenderSystem.stencilMask(0xFF); RenderSystem.clearStencil(0); GL11.glClear(GL11.GL_STENCIL_BUFFER_BIT); - RenderSystem.stencilFunc(GL11.GL_ALWAYS, 1, 0xFF); - RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE); - RenderSystem.colorMask(false, false, false, false); - RenderSystem.depthMask(false); - RenderSystem.enableDepthTest(); GL11.glEnable(GL11.GL_STENCIL_TEST); - try { - Objects.requireNonNull(drawApertureMask).run(); - RenderSystem.colorMask(false, false, false, false); - RenderSystem.depthMask(true); - RenderSystem.stencilMask(0x00); - RenderSystem.stencilFunc(GL11.GL_EQUAL, 1, 0xFF); - RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP); - Objects.requireNonNull(clearApertureDepth).run(); - } catch (RuntimeException | Error exception) { - try { - target.bindWrite(true); - GL11.glEnable(GL11.GL_STENCIL_TEST); - RenderSystem.stencilMask(0x00); - RenderSystem.stencilFunc(GL11.GL_EQUAL, 1, 0xFF); - RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP); - RenderSystem.colorMask(false, false, false, false); - RenderSystem.depthMask(true); - restoreApertureDepth.run(); - } catch (RuntimeException | Error restoreFailure) { - exception.addSuppressed(restoreFailure); - } finally { - DIRECT_TARGETS.remove(target); - resetState(); - } - throw exception; - } - RenderSystem.colorMask(true, true, true, true); - RenderSystem.depthMask(true); - RenderSystem.stencilMask(0x00); - RenderSystem.stencilFunc(GL11.GL_EQUAL, 1, 0xFF); - RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP); - RenderSystem.enableDepthTest(); - return new Scope(target, restoreApertureDepth); + drawInside(0); } - public static Scope begin(RenderTarget target, Runnable drawApertureMask) { - ensureAttachment(target); - target.bindWrite(true); - RenderSystem.disableScissor(); + public static void endFrame() { + GL11.glDisable(GL11.GL_STENCIL_TEST); RenderSystem.stencilMask(0xFF); - RenderSystem.clearStencil(0); - GL11.glClear(GL11.GL_STENCIL_BUFFER_BIT); - RenderSystem.stencilFunc(GL11.GL_ALWAYS, 1, 0xFF); - RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE); - RenderSystem.colorMask(false, false, false, false); - RenderSystem.depthMask(false); - RenderSystem.disableDepthTest(); - GL11.glEnable(GL11.GL_STENCIL_TEST); - try { - Objects.requireNonNull(drawApertureMask).run(); - } catch (RuntimeException | Error exception) { - resetState(); - throw exception; - } + RenderSystem.stencilFunc(GL11.GL_ALWAYS, 0, 0xFF); + RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP); RenderSystem.colorMask(true, true, true, true); RenderSystem.depthMask(true); - RenderSystem.stencilMask(0x00); - RenderSystem.stencilFunc(GL11.GL_EQUAL, 1, 0xFF); - RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP); - GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT); RenderSystem.enableDepthTest(); - return new Scope(target); } - public static void activate(RenderTarget target) { - if (!ATTACHMENTS.containsKey(target) && !DIRECT_TARGETS.contains(target)) { - return; - } - target.bindWrite(true); + public static void pushAperture(int parentLevel, Runnable drawAperture) { GL11.glEnable(GL11.GL_STENCIL_TEST); + RenderSystem.stencilMask(0xFF); + RenderSystem.stencilFunc(GL11.GL_EQUAL, parentLevel, 0xFF); + RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL_INCR); + RenderSystem.colorMask(false, false, false, false); + RenderSystem.depthMask(false); + RenderSystem.enableDepthTest(); + try { + drawAperture.run(); + } finally { + drawInside(parentLevel + 1); + } + } + + public static void popAperture(int parentLevel, Runnable drawApertureDepth) { + GL11.glEnable(GL11.GL_STENCIL_TEST); + RenderSystem.stencilMask(0xFF); + RenderSystem.stencilFunc(GL11.GL_EQUAL, parentLevel + 1, 0xFF); + RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL_DECR); + RenderSystem.colorMask(false, false, false, false); + RenderSystem.depthMask(true); + RenderSystem.enableDepthTest(); + try { + drawApertureDepth.run(); + } finally { + drawInside(parentLevel); + } + } + + public static void drawInside(int level) { RenderSystem.stencilMask(0x00); - RenderSystem.stencilFunc(GL11.GL_EQUAL, 1, 0xFF); + RenderSystem.stencilFunc(GL11.GL_EQUAL, level, 0xFF); RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP); + RenderSystem.colorMask(true, true, true, true); + RenderSystem.depthMask(true); + RenderSystem.enableDepthTest(); } public static void release(RenderTarget target) { - DIRECT_TARGETS.remove(target); UNSUPPORTED_MAIN_TARGETS.remove(target); - Attachment attachment = ATTACHMENTS.remove(target); - if (attachment != null) { - GL30.glDeleteRenderbuffers(attachment.renderbuffer()); - } Attachment mainAttachment = MAIN_STENCIL_ATTACHMENTS.remove(target); if (mainAttachment != null) { GL30.glDeleteRenderbuffers(mainAttachment.renderbuffer()); @@ -158,16 +119,11 @@ public final class PortalStencilTarget { } public static void clear() { - for (Attachment attachment : ATTACHMENTS.values()) { - GL30.glDeleteRenderbuffers(attachment.renderbuffer()); - } - ATTACHMENTS.clear(); for (Attachment attachment : MAIN_STENCIL_ATTACHMENTS.values()) { GL30.glDeleteRenderbuffers(attachment.renderbuffer()); } MAIN_STENCIL_ATTACHMENTS.clear(); UNSUPPORTED_MAIN_TARGETS.clear(); - DIRECT_TARGETS.clear(); } private static void ensureMainStencilAttachment(RenderTarget target) { @@ -203,47 +159,6 @@ public final class PortalStencilTarget { } } - private static void ensureAttachment(RenderTarget target) { - Attachment attachment = ATTACHMENTS.get(target); - if (attachment != null - && attachment.framebuffer() == target.frameBufferId - && attachment.width() == target.width - && attachment.height() == target.height) { - return; - } - if (attachment != null) { - GL30.glDeleteRenderbuffers(attachment.renderbuffer()); - } - int previousFramebuffer = GL11.glGetInteger(GL30.GL_FRAMEBUFFER_BINDING); - int previousRenderbuffer = GL11.glGetInteger(GL30.GL_RENDERBUFFER_BINDING); - int renderbuffer = GL30.glGenRenderbuffers(); - try { - GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, target.frameBufferId); - GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, renderbuffer); - GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL30.GL_DEPTH24_STENCIL8, target.width, target.height); - GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_STENCIL_ATTACHMENT, GL30.GL_RENDERBUFFER, renderbuffer); - int status = GL30.glCheckFramebufferStatus(GL30.GL_FRAMEBUFFER); - if (status != GL30.GL_FRAMEBUFFER_COMPLETE) { - GL30.glDeleteRenderbuffers(renderbuffer); - throw new IllegalStateException("Portal view framebuffer is incomplete with packed depth/stencil attachment: 0x" + Integer.toHexString(status)); - } - ATTACHMENTS.put(target, new Attachment(target.frameBufferId, renderbuffer, target.width, target.height)); - } finally { - GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, previousRenderbuffer); - GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, previousFramebuffer); - } - } - - private static void resetState() { - GL11.glDisable(GL11.GL_STENCIL_TEST); - RenderSystem.stencilMask(0xFF); - RenderSystem.stencilFunc(GL11.GL_ALWAYS, 0, 0xFF); - RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP); - RenderSystem.colorMask(true, true, true, true); - RenderSystem.depthMask(true); - RenderSystem.enableDepthTest(); - } - private static int stencilBits() { int type = GL30.glGetFramebufferAttachmentParameteri(GL30.GL_FRAMEBUFFER, GL30.GL_STENCIL_ATTACHMENT, GL30.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE); @@ -253,44 +168,4 @@ public final class PortalStencilTarget { private record Attachment(int framebuffer, int renderbuffer, int width, int height) { } - - public static final class Scope implements AutoCloseable { - private boolean closed; - private final RenderTarget target; - private final Runnable restoreApertureDepth; - - private Scope(RenderTarget target) { - this(target, null); - } - - private Scope(RenderTarget target, Runnable restoreApertureDepth) { - this.target = Objects.requireNonNull(target); - this.restoreApertureDepth = restoreApertureDepth; - } - - @Override - public void close() { - if (closed) { - return; - } - closed = true; - try { - if (this.restoreApertureDepth != null) { - this.target.bindWrite(true); - GL11.glEnable(GL11.GL_STENCIL_TEST); - RenderSystem.stencilMask(0x00); - RenderSystem.stencilFunc(GL11.GL_EQUAL, 1, 0xFF); - RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP); - RenderSystem.colorMask(false, false, false, false); - RenderSystem.depthMask(true); - this.restoreApertureDepth.run(); - } - } finally { - if (this.restoreApertureDepth != null) { - DIRECT_TARGETS.remove(this.target); - } - resetState(); - } - } - } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalTerrain.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalTerrain.java new file mode 100644 index 00000000..3fede2fd --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalTerrain.java @@ -0,0 +1,33 @@ +package com.craisinlord.antarchy.content.client.renderer; + +import java.util.function.Consumer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.culling.Frustum; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.phys.Vec3; +import org.joml.Matrix4f; + +public interface PortalTerrain { + static boolean canView(Minecraft minecraft, Vec3 exitCenter) { + return SodiumCompat.isLoaded() + ? com.craisinlord.antarchy.content.client.renderer.sodium.SodiumPortalTerrain.canView(minecraft, exitCenter) + : PortalGunPortalSectionViews.canView(minecraft, exitCenter); + } + + static PortalTerrain prepare(Minecraft minecraft, java.util.UUID exitId, Vec3 exitCenter, Vec3 exitNormal, Frustum frustum) { + return SodiumCompat.isLoaded() + ? com.craisinlord.antarchy.content.client.renderer.sodium.SodiumPortalTerrain.prepare(minecraft, frustum) + : VanillaPortalTerrain.prepare(minecraft, exitId, exitCenter, exitNormal, frustum); + } + + int sectionCount(); + + void begin(Minecraft minecraft); + + void end(Minecraft minecraft); + + void drawLayer(Minecraft minecraft, RenderType renderType, Vec3 cameraPosition, Matrix4f viewMatrix, Matrix4f projection); + + void forEachBlockEntity(Minecraft minecraft, Frustum frustum, Consumer consumer); +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalViewSectionMarker.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalViewSectionMarker.java deleted file mode 100644 index 06eaaaa3..00000000 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalViewSectionMarker.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.craisinlord.antarchy.content.client.renderer; - -public interface PortalViewSectionMarker { - void antarchy$markPortalViewSection(); - - boolean antarchy$isPortalViewSection(); -} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/SodiumCompat.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/SodiumCompat.java index 1c767c44..a463d860 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/SodiumCompat.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/SodiumCompat.java @@ -1,23 +1,20 @@ package com.craisinlord.antarchy.content.client.renderer; -import com.craisinlord.antarchy.Antarchy; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.function.Consumer; -import net.minecraft.client.Camera; -import net.minecraft.world.level.block.entity.BlockEntity; - public final class SodiumCompat { private static final String SODIUM_RENDERER_CLASS = "net.caffeinemc.mods.sodium.client.render.SodiumWorldRenderer"; - private static final ThreadLocal RENDER_STATE = ThreadLocal.withInitial(RenderState::new); - private static boolean restoreWarningLogged; + private static Boolean loaded; private SodiumCompat() { } public static boolean isLoaded() { + if (loaded == null) { + loaded = detect(); + } + return loaded; + } + + private static boolean detect() { String resource = SODIUM_RENDERER_CLASS.replace('.', '/') + ".class"; ClassLoader contextLoader = Thread.currentThread().getContextClassLoader(); if (contextLoader != null && contextLoader.getResource(resource) != null) { @@ -26,109 +23,4 @@ public final class SodiumCompat { ClassLoader ownLoader = SodiumCompat.class.getClassLoader(); return ownLoader != null && ownLoader.getResource(resource) != null; } - - public static void captureTerrainSetup(Camera camera, Object viewport, boolean spectator, boolean updateChunks) { - RENDER_STATE.get().activeSetup = new TerrainSetup(camera, viewport, spectator, updateChunks); - } - - public static TerrainScope beginPortalView() { - RenderState state = RENDER_STATE.get(); - TerrainSetup previousSetup = state.activeSetup; - state.previousSetups.push(new PreviousSetup(previousSetup)); - return () -> { - PreviousSetup previous = state.previousSetups.pop(); - if (previous.setup() == null) { - state.activeSetup = null; - return; - } - restoreTerrainSetup(previous.setup(), state); - }; - } - - public static void clear() { - RENDER_STATE.remove(); - } - - public static void forEachVisibleBlockEntity(Consumer consumer) { - try { - ClassLoader contextLoader = Thread.currentThread().getContextClassLoader(); - Class rendererClass = Class.forName(SODIUM_RENDERER_CLASS, false, - contextLoader == null ? SodiumCompat.class.getClassLoader() : contextLoader); - Object renderer = rendererClass.getMethod("instanceNullable").invoke(null); - if (renderer != null) { - rendererClass.getMethod("iterateVisibleBlockEntities", Consumer.class).invoke(renderer, consumer); - } - } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | LinkageError exception) { - logRestoreFailure("Could not iterate Sodium block entities for a portal view", exception); - } - } - - private static void restoreTerrainSetup(TerrainSetup setup, RenderState state) { - try { - ClassLoader contextLoader = Thread.currentThread().getContextClassLoader(); - Class rendererClass = Class.forName(SODIUM_RENDERER_CLASS, false, - contextLoader == null ? SodiumCompat.class.getClassLoader() : contextLoader); - Object renderer = rendererClass.getMethod("instanceNullable").invoke(null); - if (renderer == null) { - return; - } - Method terrainSetup = null; - for (Method method : rendererClass.getMethods()) { - Class[] parameters = method.getParameterTypes(); - if (method.getName().equals("setupTerrain") - && parameters.length == 4 - && parameters[0].isInstance(setup.camera()) - && parameters[1].isInstance(setup.viewport()) - && parameters[2] == boolean.class - && parameters[3] == boolean.class) { - terrainSetup = method; - break; - } - } - if (terrainSetup == null) { - logRestoreFailure("Sodium terrain setup method was not found", null); - state.activeSetup = setup; - return; - } - Class deviceClass = Class.forName("net.caffeinemc.mods.sodium.client.gl.device.RenderDevice", false, - contextLoader == null ? SodiumCompat.class.getClassLoader() : contextLoader); - deviceClass.getMethod("enterManagedCode").invoke(null); - try { - terrainSetup.invoke(renderer, setup.camera(), setup.viewport(), setup.spectator(), setup.updateChunks()); - } finally { - deviceClass.getMethod("exitManagedCode").invoke(null); - } - } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | LinkageError exception) { - logRestoreFailure("Could not restore Sodium terrain after a portal view", exception); - state.activeSetup = setup; - } - } - - private static void logRestoreFailure(String message, Throwable exception) { - if (!restoreWarningLogged) { - restoreWarningLogged = true; - if (exception == null) { - Antarchy.LOGGER.warn(message); - } else { - Antarchy.LOGGER.warn(message, exception); - } - } - } - - @FunctionalInterface - public interface TerrainScope extends AutoCloseable { - @Override - void close(); - } - - private static final class RenderState { - private final Deque previousSetups = new ArrayDeque<>(); - private TerrainSetup activeSetup; - } - - private record PreviousSetup(TerrainSetup setup) { - } - - private record TerrainSetup(Camera camera, Object viewport, boolean spectator, boolean updateChunks) { - } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/VanillaPortalTerrain.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/VanillaPortalTerrain.java new file mode 100644 index 00000000..3a2278a6 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/VanillaPortalTerrain.java @@ -0,0 +1,134 @@ +package com.craisinlord.antarchy.content.client.renderer; + +import com.craisinlord.antarchy.content.client.PortalGunPortalRenderState; +import com.craisinlord.antarchy.mixins.client.LevelRendererPortalViewAreaAccessor; +import com.mojang.blaze3d.shaders.Uniform; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.VertexBuffer; +import com.mojang.blaze3d.vertex.VertexFormat; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.ObjectListIterator; +import java.util.UUID; +import java.util.function.Consumer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.client.renderer.chunk.RenderRegionCache; +import net.minecraft.client.renderer.chunk.SectionRenderDispatcher; +import net.minecraft.client.renderer.culling.Frustum; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import org.joml.Matrix4f; + +final class VanillaPortalTerrain implements PortalTerrain { + private static final int MAX_REBUILDS_PER_SCENE = 32; + + private final ObjectArrayList sections; + + private VanillaPortalTerrain(ObjectArrayList sections) { + this.sections = sections; + } + + static VanillaPortalTerrain prepare(Minecraft minecraft, UUID exitId, Vec3 exitCenter, Vec3 exitNormal, Frustum frustum) { + PortalGunPortalSectionViews.View view = PortalGunPortalSectionViews.prepare(minecraft, exitId, exitCenter, exitNormal, frustum); + view.visibleSections().removeIf(section -> !PortalGunPortalRenderState.shouldRenderBounds(section.getBoundingBox())); + queueDirtySections(minecraft, view.visibleSections()); + return new VanillaPortalTerrain(view.visibleSections()); + } + + @Override + public int sectionCount() { + return this.sections.size(); + } + + @Override + public void begin(Minecraft minecraft) { + } + + @Override + public void end(Minecraft minecraft) { + } + + @Override + public void drawLayer(Minecraft minecraft, RenderType renderType, Vec3 cameraPosition, Matrix4f viewMatrix, Matrix4f projection) { + renderType.setupRenderState(); + ShaderInstance shader = RenderSystem.getShader(); + if (shader == null) { + renderType.clearRenderState(); + return; + } + shader.setDefaultUniforms(VertexFormat.Mode.QUADS, viewMatrix, projection, minecraft.getWindow()); + shader.apply(); + Uniform chunkOffset = shader.CHUNK_OFFSET; + boolean frontToBack = renderType != RenderType.translucent(); + ObjectListIterator iterator = + this.sections.listIterator(frontToBack ? 0 : this.sections.size()); + try { + while (frontToBack ? iterator.hasNext() : iterator.hasPrevious()) { + SectionRenderDispatcher.RenderSection section = frontToBack ? iterator.next() : iterator.previous(); + if (section.getCompiled().isEmpty(renderType)) { + continue; + } + VertexBuffer buffer = section.getBuffer(renderType); + BlockPos origin = section.getOrigin(); + if (chunkOffset != null) { + chunkOffset.set((float) (origin.getX() - cameraPosition.x), (float) (origin.getY() - cameraPosition.y), + (float) (origin.getZ() - cameraPosition.z)); + chunkOffset.upload(); + } + buffer.bind(); + buffer.draw(); + } + } finally { + if (chunkOffset != null) { + chunkOffset.set(0.0F, 0.0F, 0.0F); + } + shader.clear(); + VertexBuffer.unbind(); + renderType.clearRenderState(); + } + } + + @Override + public void forEachBlockEntity(Minecraft minecraft, Frustum frustum, Consumer consumer) { + for (SectionRenderDispatcher.RenderSection section : this.sections) { + for (BlockEntity blockEntity : section.getCompiled().getRenderableBlockEntities()) { + consumer.accept(blockEntity); + } + } + LevelRendererPortalViewAreaAccessor state = (LevelRendererPortalViewAreaAccessor) minecraft.levelRenderer; + synchronized (state.antarchy$getGlobalBlockEntities()) { + for (BlockEntity blockEntity : state.antarchy$getGlobalBlockEntities()) { + if (frustum.isVisible(new AABB(blockEntity.getBlockPos()).inflate(1.0D))) { + consumer.accept(blockEntity); + } + } + } + } + + private static void queueDirtySections(Minecraft minecraft, ObjectArrayList sections) { + SectionRenderDispatcher dispatcher = minecraft.levelRenderer.getSectionRenderDispatcher(); + if (dispatcher == null) { + return; + } + RenderRegionCache cache = null; + int queued = 0; + for (SectionRenderDispatcher.RenderSection section : sections) { + if (queued >= MAX_REBUILDS_PER_SCENE) { + break; + } + if (!section.isDirty() || !minecraft.level.getLightEngine().lightOnInSection(SectionPos.of(section.getOrigin()))) { + continue; + } + if (cache == null) { + cache = new RenderRegionCache(); + } + section.rebuildSectionAsync(dispatcher, cache); + section.setNotDirty(); + queued++; + } + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/sodium/SodiumPortalTerrain.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/sodium/SodiumPortalTerrain.java new file mode 100644 index 00000000..5f73b554 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/sodium/SodiumPortalTerrain.java @@ -0,0 +1,208 @@ +package com.craisinlord.antarchy.content.client.renderer.sodium; + +import com.craisinlord.antarchy.content.client.PortalGunPortalRenderState; +import com.craisinlord.antarchy.content.client.renderer.PortalTerrain; +import com.craisinlord.antarchy.mixins.compat.sodium.RenderSectionManagerAccessor; +import com.craisinlord.antarchy.mixins.compat.sodium.SodiumWorldRendererAccessor; +import java.util.ArrayDeque; +import java.util.EnumMap; +import java.util.Map; +import java.util.function.Consumer; +import net.caffeinemc.mods.sodium.client.SodiumClientMod; +import net.caffeinemc.mods.sodium.client.gl.device.RenderDevice; +import net.caffeinemc.mods.sodium.client.render.SodiumWorldRenderer; +import net.caffeinemc.mods.sodium.client.render.chunk.ChunkRenderMatrices; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionManager; +import net.caffeinemc.mods.sodium.client.render.chunk.TaskQueueType; +import net.caffeinemc.mods.sodium.client.render.chunk.lists.CoordinateSectionVisitor; +import net.caffeinemc.mods.sodium.client.render.chunk.lists.SortedRenderLists; +import net.caffeinemc.mods.sodium.client.render.chunk.lists.TreeSectionCollector; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses; +import net.caffeinemc.mods.sodium.client.render.chunk.terrain.TerrainRenderPass; +import net.caffeinemc.mods.sodium.client.render.viewport.Viewport; +import net.caffeinemc.mods.sodium.client.render.viewport.ViewportProvider; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.culling.Frustum; +import net.minecraft.core.SectionPos; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import org.joml.Matrix4f; + +public final class SodiumPortalTerrain implements PortalTerrain { + private static final int FIRST_PORTAL_FRAME = -1_000_000; + private static final int MAX_PENDING_TASKS_PER_QUEUE = 256; + private static final Map> PENDING_TASKS = new EnumMap<>(TaskQueueType.class); + private static int nextFrame = FIRST_PORTAL_FRAME; + + private final SodiumWorldRenderer worldRenderer; + private final RenderSectionManager sectionManager; + private final SortedRenderLists renderLists; + private final int sectionCount; + private SortedRenderLists previousRenderLists; + private boolean previousEntityCulling; + + private SodiumPortalTerrain(SodiumWorldRenderer worldRenderer, RenderSectionManager sectionManager, SortedRenderLists renderLists, int sectionCount) { + this.worldRenderer = worldRenderer; + this.sectionManager = sectionManager; + this.renderLists = renderLists; + this.sectionCount = sectionCount; + } + + public static boolean canView(Minecraft minecraft, Vec3 exitCenter) { + SodiumWorldRenderer worldRenderer = SodiumWorldRenderer.instanceNullable(); + if (worldRenderer == null || minecraft.player == null + || ((SodiumWorldRendererAccessor) worldRenderer).antarchy$getRenderSectionManager() == null) { + return false; + } + int limit = minecraft.options.getEffectiveRenderDistance(); + return Math.abs(SectionPos.posToSectionCoord(exitCenter.x) - minecraft.player.chunkPosition().x) <= limit + && Math.abs(SectionPos.posToSectionCoord(exitCenter.z) - minecraft.player.chunkPosition().z) <= limit; + } + + public static PortalTerrain prepare(Minecraft minecraft, Frustum frustum) { + SodiumWorldRenderer worldRenderer = SodiumWorldRenderer.instanceNullable(); + RenderSectionManager sectionManager = worldRenderer == null ? null + : ((SodiumWorldRendererAccessor) worldRenderer).antarchy$getRenderSectionManager(); + if (sectionManager == null) { + return EmptyTerrain.INSTANCE; + } + RenderSectionManagerAccessor manager = (RenderSectionManagerAccessor) sectionManager; + int frame = nextFrame--; + if (nextFrame > FIRST_PORTAL_FRAME) { + nextFrame = FIRST_PORTAL_FRAME; + } + Viewport viewport = ((ViewportProvider) frustum).sodium$createViewport(); + TreeSectionCollector collector = new TreeSectionCollector(frame, + SodiumClientMod.options().performance.chunkBuildDeferMode.getImportantRebuildQueueType(), + manager.antarchy$getSortBehavior().getDeferMode().getImportantRebuildQueueType(), + manager.antarchy$getSectionByPosition()); + int[] visited = {0}; + CoordinateSectionVisitor apertureFilter = (x, y, z) -> { + int minX = SectionPos.sectionToBlockCoord(x); + int minY = SectionPos.sectionToBlockCoord(y); + int minZ = SectionPos.sectionToBlockCoord(z); + if (PortalGunPortalRenderState.shouldRenderBounds(new AABB(minX, minY, minZ, minX + 16, minY + 16, minZ + 16))) { + collector.visit(x, y, z); + visited[0]++; + } + }; + manager.antarchy$getRenderableSectionTree().prepareForTraversal(); + manager.antarchy$getRenderableSectionTree().traverse(apertureFilter, viewport, manager.antarchy$getSearchDistance()); + SortedRenderLists renderLists = collector.createRenderLists(viewport); + stashPendingTasks(collector.getTaskLists()); + sectionManager.markGraphDirty(); + return new SodiumPortalTerrain(worldRenderer, sectionManager, renderLists, visited[0]); + } + + public static void drainPendingTasks(Map> taskLists) { + if (PENDING_TASKS.isEmpty() || taskLists == null) { + return; + } + for (Map.Entry> entry : PENDING_TASKS.entrySet()) { + ArrayDeque queue = taskLists.get(entry.getKey()); + if (queue == null) { + continue; + } + int limit = entry.getKey().queueSizeLimit(); + for (RenderSection section : entry.getValue()) { + if (queue.size() >= limit) { + break; + } + if (!section.isDisposed() && section.getPendingUpdate() != 0 && section.getRunningJob() == null) { + queue.add(section); + } + } + } + PENDING_TASKS.clear(); + } + + private static void stashPendingTasks(Map> taskLists) { + for (Map.Entry> entry : taskLists.entrySet()) { + if (entry.getValue().isEmpty()) { + continue; + } + ArrayDeque pending = PENDING_TASKS.computeIfAbsent(entry.getKey(), type -> new ArrayDeque<>()); + for (RenderSection section : entry.getValue()) { + if (pending.size() >= MAX_PENDING_TASKS_PER_QUEUE) { + break; + } + pending.add(section); + } + } + } + + @Override + public int sectionCount() { + return this.sectionCount; + } + + @Override + public void begin(Minecraft minecraft) { + RenderSectionManagerAccessor manager = (RenderSectionManagerAccessor) this.sectionManager; + SodiumWorldRendererAccessor renderer = (SodiumWorldRendererAccessor) this.worldRenderer; + this.previousRenderLists = manager.antarchy$getRenderLists(); + this.previousEntityCulling = renderer.antarchy$getUseEntityCulling(); + manager.antarchy$setRenderLists(this.renderLists); + renderer.antarchy$setUseEntityCulling(false); + } + + @Override + public void end(Minecraft minecraft) { + ((RenderSectionManagerAccessor) this.sectionManager).antarchy$setRenderLists(this.previousRenderLists); + ((SodiumWorldRendererAccessor) this.worldRenderer).antarchy$setUseEntityCulling(this.previousEntityCulling); + } + + @Override + public void forEachBlockEntity(Minecraft minecraft, Frustum frustum, Consumer consumer) { + this.worldRenderer.iterateVisibleBlockEntities(consumer); + } + + @Override + public void drawLayer(Minecraft minecraft, RenderType renderType, Vec3 cameraPosition, Matrix4f viewMatrix, Matrix4f projection) { + TerrainRenderPass[] passes; + if (renderType == RenderType.solid()) { + passes = new TerrainRenderPass[] {DefaultTerrainRenderPasses.SOLID, DefaultTerrainRenderPasses.CUTOUT}; + } else if (renderType == RenderType.translucent()) { + passes = new TerrainRenderPass[] {DefaultTerrainRenderPasses.TRANSLUCENT}; + } else { + return; + } + ChunkRenderMatrices matrices = new ChunkRenderMatrices(projection, viewMatrix); + RenderDevice.enterManagedCode(); + try { + for (TerrainRenderPass pass : passes) { + this.sectionManager.renderLayer(matrices, pass, cameraPosition.x, cameraPosition.y, cameraPosition.z); + } + } finally { + RenderDevice.exitManagedCode(); + } + } + + private enum EmptyTerrain implements PortalTerrain { + INSTANCE; + + @Override + public int sectionCount() { + return 0; + } + + @Override + public void begin(Minecraft minecraft) { + } + + @Override + public void end(Minecraft minecraft) { + } + + @Override + public void drawLayer(Minecraft minecraft, RenderType renderType, Vec3 cameraPosition, Matrix4f viewMatrix, Matrix4f projection) { + } + + @Override + public void forEachBlockEntity(Minecraft minecraft, Frustum frustum, Consumer consumer) { + } + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/DrTrayaurusEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/DrTrayaurusEntity.java index d186471b..c3d03519 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/DrTrayaurusEntity.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/DrTrayaurusEntity.java @@ -102,7 +102,7 @@ public class DrTrayaurusEntity extends AbstractVillager { protected void updateTrades() { MerchantOffers offers = this.getOffers(); offers.clear(); - offers.addAll(DrTrayaurusTradeManager.createOffers()); + offers.addAll(DrTrayaurusTradeManager.createOffers(this.registryAccess())); this.overrideXp(1); this.tradesInitialized = true; } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/trades/DrTrayaurusTradeManager.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/trades/DrTrayaurusTradeManager.java index f35dd67c..6ad087c1 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/trades/DrTrayaurusTradeManager.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/trades/DrTrayaurusTradeManager.java @@ -6,7 +6,13 @@ import com.google.gson.JsonParseException; import com.mojang.serialization.Codec; import com.mojang.serialization.JsonOps; import com.mojang.serialization.codecs.RecordCodecBuilder; +import com.mojang.logging.LogUtils; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.component.DataComponentPredicate; +import net.minecraft.resources.RegistryOps; import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.ExtraCodecs; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener; import net.minecraft.util.profiling.ProfilerFiller; @@ -20,8 +26,10 @@ import net.minecraft.world.item.trading.MerchantOffers; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import org.slf4j.Logger; public final class DrTrayaurusTradeManager extends SimpleJsonResourceReloadListener { + private static final Logger LOGGER = LogUtils.getLogger(); private static final Gson GSON = new Gson(); private static final String DIRECTORY = "trayaurus_trades"; private static final Codec TRADE_FILE_CODEC = RecordCodecBuilder.create(instance -> instance.group( @@ -47,10 +55,10 @@ public final class DrTrayaurusTradeManager extends SimpleJsonResourceReloadListe loadedTrades = parsedTrades.isEmpty() ? defaultTrades() : List.copyOf(parsedTrades); } - public static MerchantOffers createOffers() { + public static MerchantOffers createOffers(HolderLookup.Provider registries) { MerchantOffers offers = new MerchantOffers(); for (TradeEntry trade : loadedTrades) { - trade.toOffer().ifPresent(offers::add); + trade.toOffer(registries).ifPresent(offers::add); } return offers; } @@ -78,18 +86,18 @@ public final class DrTrayaurusTradeManager extends SimpleJsonResourceReloadListe Codec.FLOAT.optionalFieldOf("price_multiplier", 0.05F).forGetter(TradeEntry::priceMultiplier) ).apply(instance, TradeEntry::new)); - private Optional toOffer() { + private Optional toOffer(HolderLookup.Provider registries) { if (this.maxUses < 1 || this.villagerXp < 1 || this.villagerXp > 99) { return Optional.empty(); } - Optional buyCost = this.buy.toCost(); + Optional buyCost = this.buy.toCost(registries); if (buyCost.isEmpty()) { return Optional.empty(); } - Optional secondBuyCost = this.secondBuy.flatMap(StackEntry::toCost); - ItemStack sellStack = this.sell.toStack(); + Optional secondBuyCost = this.secondBuy.flatMap(entry -> entry.toCost(registries)); + ItemStack sellStack = this.sell.toStack(registries); if (sellStack.isEmpty()) { return Optional.empty(); } @@ -105,28 +113,60 @@ public final class DrTrayaurusTradeManager extends SimpleJsonResourceReloadListe } } - private record StackEntry(ResourceLocation itemId, int count) { + /** + * One side of a trade. {@code components} is optional: on {@code sell} it is a data component + * patch applied to the result (enchantments, custom name, ...); on {@code buy}/{@code second_buy} + * it is a component predicate the offered stack must match exactly for each listed component. + * It is kept as raw JSON and parsed per offer because components such as enchantments need + * registry access, which the reload listener does not have. + */ + private record StackEntry(ResourceLocation itemId, int count, Optional components) { private static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( ResourceLocation.CODEC.fieldOf("item").forGetter(StackEntry::itemId), - Codec.INT.optionalFieldOf("count", 1).forGetter(StackEntry::count) + Codec.INT.optionalFieldOf("count", 1).forGetter(StackEntry::count), + ExtraCodecs.JSON.optionalFieldOf("components").forGetter(StackEntry::components) ).apply(instance, StackEntry::new)); + private StackEntry(ResourceLocation itemId, int count) { + this(itemId, count, Optional.empty()); + } + private Optional item() { return BuiltInRegistries.ITEM.getOptional(this.itemId) .filter(item -> item != net.minecraft.world.item.Items.AIR); } - private ItemStack toStack() { - return this.item() - .filter(item -> this.count > 0) - .map(item -> new ItemStack(item, this.count)) - .orElse(ItemStack.EMPTY); + private ItemStack toStack(HolderLookup.Provider registries) { + Optional item = this.item().filter(found -> this.count > 0); + if (item.isEmpty()) { + return ItemStack.EMPTY; + } + ItemStack stack = new ItemStack(item.get(), this.count); + if (this.components.isPresent()) { + Optional patch = DataComponentPatch.CODEC + .parse(RegistryOps.create(JsonOps.INSTANCE, registries), this.components.get()) + .resultOrPartial(message -> LOGGER.error("Dr. Trayaurus trade {}: bad components: {}", this.itemId, message)); + if (patch.isEmpty()) { + return ItemStack.EMPTY; + } + stack.applyComponents(patch.get()); + } + return stack; } - private Optional toCost() { - return this.item() - .filter(item -> this.count > 0) - .map(item -> new ItemCost(item, this.count)); + private Optional toCost(HolderLookup.Provider registries) { + Optional item = this.item().filter(found -> this.count > 0); + if (item.isEmpty()) { + return Optional.empty(); + } + if (this.components.isEmpty()) { + return Optional.of(new ItemCost(item.get(), this.count)); + } + // A predicate that fails to parse drops the trade rather than accepting any stack. + return DataComponentPredicate.CODEC + .parse(RegistryOps.create(JsonOps.INSTANCE, registries), this.components.get()) + .resultOrPartial(message -> LOGGER.error("Dr. Trayaurus trade {}: bad components: {}", this.itemId, message)) + .map(predicate -> new ItemCost(item.get().builtInRegistryHolder(), this.count, predicate)); } } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/portalgun/PortalGunPortalEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/portalgun/PortalGunPortalEntity.java index 71db86b8..454f54d1 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/portalgun/PortalGunPortalEntity.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/portalgun/PortalGunPortalEntity.java @@ -357,28 +357,27 @@ public class PortalGunPortalEntity extends Entity implements GeoEntity { public PortalCrossing resolveCrossing(Entity entity, AABB previousBox, AABB currentBox) { Vec3 previousProbe = this.teleportProbePosition(entity, previousBox); Vec3 currentProbe = this.teleportProbePosition(entity, currentBox); - Vec3 normal = this.getNormalVec().normalize(); - if (entity instanceof Player && Math.abs(normal.y) < 0.5D) { + if (entity instanceof Player) { PortalGunWorldPortalShape shape = this.getWorldPortalShape(); - double previousDepth = shape.localCoords(previousProbe).depth(); - double currentDepth = shape.localCoords(currentProbe).depth(); - double halfBodyDepth = entity.getBbWidth() * 0.5D; - if (previousDepth <= 0.0D || currentDepth >= previousDepth - 1.0E-6D - || currentDepth - halfBodyDepth > 0.02D || currentDepth < -shape.halfDepth()) { - return null; - } Vec3 center = currentBox.getCenter(); PortalGunWorldPortalShape.PortalLocalCoords localCenter = shape.localCoords(center); + double previousDepth = shape.localCoords(previousBox.getCenter()).depth(); + double currentDepth = localCenter.depth(); double halfX = (currentBox.maxX - currentBox.minX) * 0.5D; double halfY = (currentBox.maxY - currentBox.minY) * 0.5D; double halfZ = (currentBox.maxZ - currentBox.minZ) * 0.5D; + double depthExtent = halfX * Math.abs(shape.normal().x) + halfY * Math.abs(shape.normal().y) + halfZ * Math.abs(shape.normal().z); + if (previousDepth <= 0.0D || currentDepth >= previousDepth - 1.0E-6D + || currentDepth - depthExtent > 0.02D || currentDepth < -shape.halfDepth()) { + return null; + } double widthExtent = halfX * Math.abs(shape.right().x) + halfY * Math.abs(shape.right().y) + halfZ * Math.abs(shape.right().z); double heightExtent = halfX * Math.abs(shape.up().x) + halfY * Math.abs(shape.up().y) + halfZ * Math.abs(shape.up().z); if (Math.abs(localCenter.horizontal()) + widthExtent > shape.halfWidth() + 1.0E-3D || Math.abs(localCenter.vertical()) + heightExtent > shape.halfHeight() + 1.0E-3D) { return null; } - return new PortalCrossing(currentProbe, Math.max(0.05D, currentDepth + 0.05D)); + return new PortalCrossing(currentProbe, Math.max(0.05D, shape.localCoords(currentProbe).depth() + 0.05D)); } return this.crossesPortal(previousProbe, currentProbe) ? new PortalCrossing(currentProbe, 0.0D) : null; } @@ -403,10 +402,20 @@ public class PortalGunPortalEntity extends Entity implements GeoEntity { } public static void teleportEntityAfterMovement(Entity entity, AABB previousBox, Vec3 resolvedMovement) { + if (entity instanceof ServerPlayer) { + return; + } + teleportAfterMovement(entity, previousBox, entity.getBoundingBox(), resolvedMovement); + } + + public static void teleportPlayerAfterMovementPacket(ServerPlayer player, AABB previousBox, Vec3 claimedMovement) { + teleportAfterMovement(player, previousBox, previousBox.move(claimedMovement), claimedMovement); + } + + private static void teleportAfterMovement(Entity entity, AABB previousBox, AABB currentBox, Vec3 resolvedMovement) { if (entity.level().isClientSide || !entity.isAlive() || entity.isPassenger() || entity instanceof PortalGunPortalEntity) { return; } - AABB currentBox = entity.getBoundingBox(); if (previousBox.getCenter().distanceToSqr(currentBox.getCenter()) <= 1.0E-10D) { return; } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/portalgun/PortalGunProjectionUtil.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/portalgun/PortalGunProjectionUtil.java index c02d4a21..b5a4e198 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/portalgun/PortalGunProjectionUtil.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/portalgun/PortalGunProjectionUtil.java @@ -6,13 +6,15 @@ import org.joml.Vector4f; /** Applies the destination portal plane as the near plane of a camera projection. */ public final class PortalGunProjectionUtil { + public static final double MIN_EYE_PLANE_DISTANCE = 0.01D; + private PortalGunProjectionUtil() { } public static Matrix4f clipAtExit(Matrix4f projection, Vec3 eye, Vec3 look, Vec3 up, Vec3 planePoint, Vec3 planeNormal) { Vector4f clipPlane = planeInCameraSpace(eye, look, up, planePoint, planeNormal); - if (clipPlane.lengthSquared() <= 1.0E-6F) { + if (clipPlane.w() > -MIN_EYE_PLANE_DISTANCE) { return projection; } Vector4f q = new Vector4f(signNonZero(clipPlane.x()), signNonZero(clipPlane.y()), 1.0F, 1.0F) @@ -42,15 +44,13 @@ public final class PortalGunProjectionUtil { (float) -relativePoint.dot(forward), 1.0F ); + Vec3 unitNormal = planeNormal.normalize(); Vector4f normal = new Vector4f( - (float) planeNormal.dot(right), - (float) planeNormal.dot(correctedUp), - (float) -planeNormal.dot(forward), + (float) unitNormal.dot(right), + (float) unitNormal.dot(correctedUp), + (float) -unitNormal.dot(forward), 0.0F ); - if (normal.z() > 0.0F) { - normal.mul(-1.0F); - } return new Vector4f(normal.x(), normal.y(), normal.z(), -normal.dot(point)); } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/AntarchyMixinPlugin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/AntarchyMixinPlugin.java index 0b376fff..6d5570af 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/AntarchyMixinPlugin.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/AntarchyMixinPlugin.java @@ -1,6 +1,5 @@ package com.craisinlord.antarchy.mixins; -import com.craisinlord.antarchy.content.client.renderer.SodiumCompat; import java.util.List; import java.util.Set; import org.objectweb.asm.tree.ClassNode; @@ -29,18 +28,6 @@ public final class AntarchyMixinPlugin implements IMixinConfigPlugin { if (!classPresent(targetClassName)) { return false; } - if (SodiumCompat.isLoaded() - && (mixinClassName.endsWith(".LevelRendererPortalViewAreaAccessor") - || mixinClassName.endsWith(".LevelRendererPortalViewAreaMixin") - || mixinClassName.endsWith(".LevelRendererPortalChunkBudgetMixin") - || mixinClassName.endsWith(".SectionRenderDispatcherPortalUploadsAccessor") - || mixinClassName.endsWith(".PortalViewChunkCacheMixin") - || mixinClassName.endsWith(".PortalViewSectionSortingMixin"))) { - return false; - } - if (mixinClassName.endsWith(".SodiumWorldRendererMixin")) { - return SodiumCompat.isLoaded(); - } if (mixinClassName.startsWith("com.craisinlord.antarchy.mixins.compat.scguns.")) { return classPresent("top.ribs.scguns.entity.projectile.ProjectileEntity"); } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/PortalGunPlayerMovePacketMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/PortalGunPlayerMovePacketMixin.java new file mode 100644 index 00000000..7bce296f --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/PortalGunPlayerMovePacketMixin.java @@ -0,0 +1,56 @@ +package com.craisinlord.antarchy.mixins; + +import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity; +import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ServerGamePacketListenerImpl.class) +public abstract class PortalGunPlayerMovePacketMixin { + @Unique + private static final double MAX_CLAIMED_MOVEMENT_SQR = 100.0D; + @Unique + private AABB antarchy$portalGunMoveStartBox; + @Unique + private Vec3 antarchy$portalGunMoveStartPosition; + + @Inject(method = "handleMovePlayer", at = @At("HEAD")) + private void antarchy$capturePortalGunMoveStart(ServerboundMovePlayerPacket packet, CallbackInfo ci) { + ServerPlayer player = ((ServerGamePacketListenerImpl) (Object) this).player; + if (player.getServer() == null || !player.getServer().isSameThread()) { + return; + } + this.antarchy$portalGunMoveStartBox = null; + this.antarchy$portalGunMoveStartPosition = null; + if (!packet.hasPosition() || ((ServerGamePacketListenerTeleportAccessor) this).antarchy$getAwaitingPositionFromClient() != null) { + return; + } + this.antarchy$portalGunMoveStartBox = player.getBoundingBox(); + this.antarchy$portalGunMoveStartPosition = player.position(); + } + + @Inject(method = "handleMovePlayer", at = @At("RETURN")) + private void antarchy$teleportPlayerOnPortalCrossing(ServerboundMovePlayerPacket packet, CallbackInfo ci) { + AABB startBox = this.antarchy$portalGunMoveStartBox; + Vec3 startPosition = this.antarchy$portalGunMoveStartPosition; + this.antarchy$portalGunMoveStartBox = null; + this.antarchy$portalGunMoveStartPosition = null; + if (startBox == null || startPosition == null) { + return; + } + ServerPlayer player = ((ServerGamePacketListenerImpl) (Object) this).player; + Vec3 claimedMovement = new Vec3(packet.getX(startPosition.x), packet.getY(startPosition.y), packet.getZ(startPosition.z)) + .subtract(startPosition); + double lengthSqr = claimedMovement.lengthSqr(); + if (lengthSqr > 1.0E-10D && lengthSqr < MAX_CLAIMED_MOVEMENT_SQR) { + PortalGunPortalEntity.teleportPlayerAfterMovementPacket(player, startBox, claimedMovement); + } + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/ServerGamePacketListenerTeleportAccessor.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/ServerGamePacketListenerTeleportAccessor.java new file mode 100644 index 00000000..499845ce --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/ServerGamePacketListenerTeleportAccessor.java @@ -0,0 +1,12 @@ +package com.craisinlord.antarchy.mixins; + +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.world.phys.Vec3; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ServerGamePacketListenerImpl.class) +public interface ServerGamePacketListenerTeleportAccessor { + @Accessor("awaitingPositionFromClient") + Vec3 antarchy$getAwaitingPositionFromClient(); +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalChunkBudgetMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalChunkBudgetMixin.java deleted file mode 100644 index 6edb0d19..00000000 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalChunkBudgetMixin.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.craisinlord.antarchy.mixins.client; - -import com.craisinlord.antarchy.content.client.renderer.PortalGunPortalRendererPool; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.chunk.RenderRegionCache; -import net.minecraft.client.renderer.chunk.SectionRenderDispatcher; -import net.minecraft.world.level.lighting.LevelLightEngine; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(LevelRenderer.class) -public abstract class LevelRendererPortalChunkBudgetMixin { - @Redirect( - method = "compileSections", - at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/chunk/SectionRenderDispatcher;uploadAllPendingUploads()V") - ) - private void antarchy$budgetPortalUploads(SectionRenderDispatcher dispatcher) { - PortalGunPortalRendererPool.uploadPending((LevelRenderer) (Object) this, dispatcher); - } - - @Redirect( - method = "renderLevel", - at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientLevel;pollLightUpdates()V") - ) - private void antarchy$skipProxyLightQueuePoll(ClientLevel level) { - if (!PortalGunPortalRendererPool.isProxy((LevelRenderer) (Object) this)) { - level.pollLightUpdates(); - } - } - - @Redirect( - method = "renderLevel", - at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runLightUpdates()I") - ) - private int antarchy$skipProxyLightQueueDrain(LevelLightEngine lightEngine) { - return PortalGunPortalRendererPool.isProxy((LevelRenderer) (Object) this) ? 0 : lightEngine.runLightUpdates(); - } - - @Redirect( - method = "compileSections", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/renderer/chunk/SectionRenderDispatcher;rebuildSectionSync(Lnet/minecraft/client/renderer/chunk/SectionRenderDispatcher$RenderSection;Lnet/minecraft/client/renderer/chunk/RenderRegionCache;)V" - ) - ) - private void antarchy$queuePortalSyncRebuilds(SectionRenderDispatcher dispatcher, SectionRenderDispatcher.RenderSection section, RenderRegionCache cache) { - PortalGunPortalRendererPool.rebuildSection((LevelRenderer) (Object) this, dispatcher, section, cache); - } - - @Redirect( - method = "compileSections", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/renderer/chunk/SectionRenderDispatcher$RenderSection;rebuildSectionAsync(Lnet/minecraft/client/renderer/chunk/SectionRenderDispatcher;Lnet/minecraft/client/renderer/chunk/RenderRegionCache;)V" - ) - ) - private void antarchy$budgetPortalAsyncRebuilds(SectionRenderDispatcher.RenderSection section, SectionRenderDispatcher dispatcher, RenderRegionCache cache) { - PortalGunPortalRendererPool.rebuildSectionAsync((LevelRenderer) (Object) this, dispatcher, section, cache); - } - - @Redirect( - method = "compileSections", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/renderer/chunk/SectionRenderDispatcher$RenderSection;setNotDirty()V" - ) - ) - private void antarchy$keepUnscheduledPortalSectionsDirty(SectionRenderDispatcher.RenderSection section) { - PortalGunPortalRendererPool.setNotDirty(section); - } -} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalLifecycleMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalLifecycleMixin.java index 0ccc40d6..07754f4d 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalLifecycleMixin.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalLifecycleMixin.java @@ -1,10 +1,6 @@ package com.craisinlord.antarchy.mixins.client; -import com.craisinlord.antarchy.content.client.PortalGunPortalRenderState; -import com.craisinlord.antarchy.content.client.renderer.PortalGunPortalViewAreaManager; -import com.craisinlord.antarchy.content.client.renderer.PortalGunPortalRendererPool; import com.craisinlord.antarchy.content.client.renderer.PortalGunPortalViewRenderer; -import com.craisinlord.antarchy.content.client.renderer.PortalGunPortalVisibilityQueries; import com.craisinlord.antarchy.content.client.renderer.PortalStencilTarget; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; @@ -18,40 +14,24 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; public abstract class LevelRendererPortalLifecycleMixin { @Inject(method = "renderLevel", at = @At("HEAD")) private void antarchy$preparePortalStencil(CallbackInfo ci) { - if (PortalGunPortalViewRenderer.isEnabled() && !PortalGunPortalRendererPool.isProxy((LevelRenderer) (Object) this)) { + if (PortalGunPortalViewRenderer.isEnabled()) { PortalStencilTarget.prepareMainTarget(Minecraft.getInstance().getMainRenderTarget()); } } @Inject(method = "setLevel", at = @At("HEAD")) private void antarchy$clearPortalViewsOnLevelChange(ClientLevel level, CallbackInfo ci) { - if (PortalGunPortalRendererPool.isProxy((LevelRenderer) (Object) this)) { - return; - } - PortalGunPortalRendererPool.clear(); - PortalGunPortalViewAreaManager.clear(); - PortalGunPortalVisibilityQueries.clear(); + PortalGunPortalViewRenderer.releaseTargets(); } @Inject(method = "close", at = @At("HEAD")) private void antarchy$clearPortalViewsOnClose(CallbackInfo ci) { - if (PortalGunPortalRendererPool.isProxy((LevelRenderer) (Object) this)) { - return; - } - PortalGunPortalRendererPool.clear(); - PortalGunPortalViewAreaManager.clear(); PortalGunPortalViewRenderer.releaseTargets(); + PortalStencilTarget.clear(); } @Inject(method = "allChanged", at = @At("TAIL")) private void antarchy$clearPortalViewsOnRendererRebuild(CallbackInfo ci) { - if (PortalGunPortalRendererPool.isProxy((LevelRenderer) (Object) this)) { - return; - } - if (PortalGunPortalRenderState.getContext() == null) { - PortalGunPortalRendererPool.clear(); - PortalGunPortalViewAreaManager.clear(); - PortalGunPortalViewRenderer.releaseTargets(); - } + PortalGunPortalViewRenderer.releaseTargets(); } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalSceneInvoker.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalSceneInvoker.java index 7789063a..da9df656 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalSceneInvoker.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalSceneInvoker.java @@ -2,27 +2,15 @@ package com.craisinlord.antarchy.mixins.client; import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.Camera; -import net.minecraft.client.renderer.culling.Frustum; import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.LightTexture; import net.minecraft.world.entity.Entity; -import org.joml.Matrix4f; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; @Mixin(LevelRenderer.class) public interface LevelRendererPortalSceneInvoker { - @Invoker("setupRender") - void antarchy$setupPortalScene(Camera camera, Frustum frustum, boolean capturedFrustum, boolean spectator); - - @Invoker("compileSections") - void antarchy$compilePortalSections(Camera camera); - - @Invoker("renderSectionLayer") - void antarchy$renderPortalSectionLayer(RenderType renderType, double cameraX, double cameraY, double cameraZ, Matrix4f modelViewMatrix, Matrix4f projectionMatrix); - @Invoker("renderEntity") void antarchy$renderPortalEntity(Entity entity, double cameraX, double cameraY, double cameraZ, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource); diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalTargetsAccessor.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalTargetsAccessor.java deleted file mode 100644 index c76d4d1f..00000000 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalTargetsAccessor.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.craisinlord.antarchy.mixins.client; - -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.PostChain; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(LevelRenderer.class) -public interface LevelRendererPortalTargetsAccessor { - @Accessor("entityEffect") - PostChain antarchy$getEntityEffect(); - - @Accessor("transparencyChain") - PostChain antarchy$getTransparencyChain(); -} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalViewAreaMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalViewAreaMixin.java index f150fc06..f5190727 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalViewAreaMixin.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/LevelRendererPortalViewAreaMixin.java @@ -1,8 +1,7 @@ package com.craisinlord.antarchy.mixins.client; -import com.craisinlord.antarchy.content.client.renderer.PortalGunPortalViewAreaManager; import com.craisinlord.antarchy.content.client.PortalGunPortalRenderState; -import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.craisinlord.antarchy.content.client.renderer.PortalGunPortalSectionViews; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.chunk.SectionRenderDispatcher; @@ -25,39 +24,13 @@ public abstract class LevelRendererPortalViewAreaMixin { } } - @ModifyExpressionValue(method = "setupRender", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;getX()D"), require = 0) - private double antarchy$usePortalCameraX(double original) { - PortalGunPortalRenderState.PortalRenderContext context = PortalGunPortalRenderState.getContext(); - return context == null ? original : context.cameraPos().x; - } - - @ModifyExpressionValue(method = "setupRender", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;getY()D"), require = 0) - private double antarchy$usePortalCameraY(double original) { - PortalGunPortalRenderState.PortalRenderContext context = PortalGunPortalRenderState.getContext(); - return context == null ? original : context.cameraPos().y; - } - - @ModifyExpressionValue(method = "setupRender", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;getZ()D"), require = 0) - private double antarchy$usePortalCameraZ(double original) { - PortalGunPortalRenderState.PortalRenderContext context = PortalGunPortalRenderState.getContext(); - return context == null ? original : context.cameraPos().z; - } - - @Inject(method = "addRecentlyCompiledSection", at = @At("HEAD"), cancellable = true) - private void antarchy$routePortalSectionCompile(SectionRenderDispatcher.RenderSection section, CallbackInfo ci) { - if (PortalGunPortalViewAreaManager.routeSectionCompiled(section)) { - ci.cancel(); - } - } - - @Inject(method = "setSectionDirty(IIIZ)V", at = @At("TAIL")) - private void antarchy$dirtyPortalSection(int sectionX, int sectionY, int sectionZ, boolean playerChanged, CallbackInfo ci) { - PortalGunPortalViewAreaManager.onSectionDirty(sectionX, sectionY, sectionZ, playerChanged); + @Inject(method = "addRecentlyCompiledSection", at = @At("TAIL")) + private void antarchy$notifyPortalGraphs(SectionRenderDispatcher.RenderSection section, CallbackInfo ci) { + PortalGunPortalSectionViews.onSectionCompiled(section); } @Inject(method = "onChunkLoaded", at = @At("TAIL")) private void antarchy$updatePortalChunkGraph(ChunkPos pos, CallbackInfo ci) { - PortalGunPortalViewAreaManager.onChunkLoaded(pos); + PortalGunPortalSectionViews.onChunkLoaded(pos); } - } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/MinecraftPortalTransparencyMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/MinecraftPortalTransparencyMixin.java new file mode 100644 index 00000000..c9194bd7 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/MinecraftPortalTransparencyMixin.java @@ -0,0 +1,18 @@ +package com.craisinlord.antarchy.mixins.client; + +import com.craisinlord.antarchy.content.client.renderer.PortalGunPortalSceneRenderer; +import net.minecraft.client.Minecraft; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(Minecraft.class) +public abstract class MinecraftPortalTransparencyMixin { + @Inject(method = "useShaderTransparency", at = @At("HEAD"), cancellable = true) + private static void antarchy$disableShaderTransparencyInPortalScenes(CallbackInfoReturnable cir) { + if (PortalGunPortalSceneRenderer.isRenderingScene()) { + cir.setReturnValue(false); + } + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/PortalViewChunkCacheMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/PortalViewChunkCacheMixin.java index a75caffa..2f01d057 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/PortalViewChunkCacheMixin.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/PortalViewChunkCacheMixin.java @@ -1,6 +1,6 @@ package com.craisinlord.antarchy.mixins.client; -import com.craisinlord.antarchy.content.client.renderer.PortalGunPortalViewAreaManager; +import com.craisinlord.antarchy.content.client.renderer.PortalGunPortalSectionViews; import net.minecraft.client.multiplayer.ClientChunkCache; import net.minecraft.world.level.ChunkPos; import org.spongepowered.asm.mixin.Mixin; @@ -12,6 +12,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; public abstract class PortalViewChunkCacheMixin { @Inject(method = "drop", at = @At("TAIL")) private void antarchy$invalidatePortalChunk(ChunkPos pos, CallbackInfo ci) { - PortalGunPortalViewAreaManager.onChunkDropped(pos); + PortalGunPortalSectionViews.onChunkDropped(pos); } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/PortalViewSectionSortingMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/PortalViewSectionSortingMixin.java deleted file mode 100644 index 6c808236..00000000 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/PortalViewSectionSortingMixin.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.craisinlord.antarchy.mixins.client; - -import com.craisinlord.antarchy.content.client.renderer.PortalGunPortalViewAreaManager; -import com.craisinlord.antarchy.content.client.renderer.PortalViewSectionMarker; -import com.llamalad7.mixinextras.injector.ModifyExpressionValue; -import org.spongepowered.asm.mixin.Unique; -import java.util.Collection; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.chunk.SectionRenderDispatcher; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.phys.Vec3; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(SectionRenderDispatcher.RenderSection.class) -public abstract class PortalViewSectionSortingMixin implements PortalViewSectionMarker { - @Unique - private boolean antarchy$portalViewSection; - - @Override - public void antarchy$markPortalViewSection() { - this.antarchy$portalViewSection = true; - } - - @Override - public boolean antarchy$isPortalViewSection() { - return this.antarchy$portalViewSection; - } - - @ModifyExpressionValue(method = "createVertexSorting", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/chunk/SectionRenderDispatcher;getCameraPosition()Lnet/minecraft/world/phys/Vec3;")) - private Vec3 antarchy$sortPortalGeometryFromVirtualCamera(Vec3 original) { - return PortalGunPortalViewAreaManager.cameraForSection((SectionRenderDispatcher.RenderSection) (Object) this, original); - } - - @Redirect(method = "updateGlobalBlockEntities", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/LevelRenderer;updateGlobalBlockEntities(Ljava/util/Collection;Ljava/util/Collection;)V")) - private void antarchy$routePortalGlobalBlockEntities(LevelRenderer renderer, Collection removed, Collection added) { - if (!PortalGunPortalViewAreaManager.updateGlobalBlockEntities((SectionRenderDispatcher.RenderSection) (Object) this, removed, added)) { - renderer.updateGlobalBlockEntities(removed, added); - } - } -} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/PostChainTargetAccessor.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/PostChainTargetAccessor.java deleted file mode 100644 index a9d56508..00000000 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/PostChainTargetAccessor.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.craisinlord.antarchy.mixins.client; - -import com.mojang.blaze3d.pipeline.RenderTarget; -import net.minecraft.client.renderer.PostChain; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(PostChain.class) -public interface PostChainTargetAccessor { - @Accessor("screenTarget") - RenderTarget antarchy$getScreenTarget(); - - @Mutable - @Accessor("screenTarget") - void antarchy$setScreenTarget(RenderTarget renderTarget); -} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/SectionOcclusionGraphPortalMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/SectionOcclusionGraphPortalMixin.java new file mode 100644 index 00000000..5656b231 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/SectionOcclusionGraphPortalMixin.java @@ -0,0 +1,35 @@ +package com.craisinlord.antarchy.mixins.client; + +import com.craisinlord.antarchy.content.client.renderer.PortalSectionGraphMarker; +import net.minecraft.client.renderer.SectionOcclusionGraph; +import net.minecraft.client.renderer.chunk.SectionRenderDispatcher; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(SectionOcclusionGraph.class) +public abstract class SectionOcclusionGraphPortalMixin implements PortalSectionGraphMarker { + @Unique + private volatile boolean antarchy$portalGraph; + + @Override + public void antarchy$markPortalGraph() { + this.antarchy$portalGraph = true; + } + + @Inject(method = "getRelativeFrom", at = @At("RETURN"), cancellable = true) + private void antarchy$rejectWrappedPortalSections(BlockPos cameraSectionPos, SectionRenderDispatcher.RenderSection section, + Direction direction, CallbackInfoReturnable cir) { + if (!this.antarchy$portalGraph) { + return; + } + SectionRenderDispatcher.RenderSection relative = cir.getReturnValue(); + if (relative != null && !relative.getOrigin().equals(section.getRelativeOrigin(direction))) { + cir.setReturnValue(null); + } + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/SectionRenderDispatcherPortalUploadsAccessor.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/SectionRenderDispatcherPortalUploadsAccessor.java deleted file mode 100644 index 3b919847..00000000 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/SectionRenderDispatcherPortalUploadsAccessor.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.craisinlord.antarchy.mixins.client; - -import java.util.Queue; -import net.minecraft.client.renderer.chunk.SectionRenderDispatcher; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(SectionRenderDispatcher.class) -public interface SectionRenderDispatcherPortalUploadsAccessor { - @Accessor("toUpload") - Queue antarchy$getToUpload(); -} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/SodiumWorldRendererMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/SodiumWorldRendererMixin.java deleted file mode 100644 index 851afae1..00000000 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/client/SodiumWorldRendererMixin.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.craisinlord.antarchy.mixins.client; - -import com.craisinlord.antarchy.content.client.renderer.SodiumCompat; -import net.minecraft.client.Camera; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Pseudo; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Coerce; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Pseudo -@Mixin(targets = "net.caffeinemc.mods.sodium.client.render.SodiumWorldRenderer", remap = false) -public abstract class SodiumWorldRendererMixin { - @Inject(method = "setupTerrain", at = @At("HEAD"), remap = false) - private void antarchy$captureTerrainSetup(Camera camera, @Coerce Object viewport, boolean spectator, boolean updateChunks, CallbackInfo ci) { - SodiumCompat.captureTerrainSetup(camera, viewport, spectator, updateChunks); - } -} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/compat/sodium/RenderSectionManagerAccessor.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/compat/sodium/RenderSectionManagerAccessor.java new file mode 100644 index 00000000..00c00e4e --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/compat/sodium/RenderSectionManagerAccessor.java @@ -0,0 +1,32 @@ +package com.craisinlord.antarchy.mixins.compat.sodium; + +import it.unimi.dsi.fastutil.longs.Long2ReferenceMap; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionManager; +import net.caffeinemc.mods.sodium.client.render.chunk.lists.SortedRenderLists; +import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior; +import net.caffeinemc.mods.sodium.client.render.chunk.tree.RemovableMultiForest; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(value = RenderSectionManager.class, remap = false) +public interface RenderSectionManagerAccessor { + @Accessor(value = "renderLists", remap = false) + SortedRenderLists antarchy$getRenderLists(); + + @Accessor(value = "renderLists", remap = false) + void antarchy$setRenderLists(SortedRenderLists renderLists); + + @Accessor(value = "renderableSectionTree", remap = false) + RemovableMultiForest antarchy$getRenderableSectionTree(); + + @Accessor(value = "sectionByPosition", remap = false) + Long2ReferenceMap antarchy$getSectionByPosition(); + + @Accessor(value = "sortBehavior", remap = false) + SortBehavior antarchy$getSortBehavior(); + + @Invoker(value = "getSearchDistance", remap = false) + float antarchy$getSearchDistance(); +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/compat/sodium/RenderSectionManagerPortalTasksMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/compat/sodium/RenderSectionManagerPortalTasksMixin.java new file mode 100644 index 00000000..4f409876 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/compat/sodium/RenderSectionManagerPortalTasksMixin.java @@ -0,0 +1,24 @@ +package com.craisinlord.antarchy.mixins.compat.sodium; + +import com.craisinlord.antarchy.content.client.renderer.sodium.SodiumPortalTerrain; +import java.util.ArrayDeque; +import java.util.Map; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionManager; +import net.caffeinemc.mods.sodium.client.render.chunk.TaskQueueType; +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(value = RenderSectionManager.class, remap = false) +public abstract class RenderSectionManagerPortalTasksMixin { + @Shadow(remap = false) + private Map> taskLists; + + @Inject(method = "update", at = @At("TAIL"), remap = false) + private void antarchy$addPortalViewTasks(CallbackInfo ci) { + SodiumPortalTerrain.drainPendingTasks(this.taskLists); + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/compat/sodium/SodiumWorldRendererAccessor.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/compat/sodium/SodiumWorldRendererAccessor.java new file mode 100644 index 00000000..e859bcd0 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/compat/sodium/SodiumWorldRendererAccessor.java @@ -0,0 +1,18 @@ +package com.craisinlord.antarchy.mixins.compat.sodium; + +import net.caffeinemc.mods.sodium.client.render.SodiumWorldRenderer; +import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionManager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(value = SodiumWorldRenderer.class, remap = false) +public interface SodiumWorldRendererAccessor { + @Accessor(value = "renderSectionManager", remap = false) + RenderSectionManager antarchy$getRenderSectionManager(); + + @Accessor(value = "useEntityCulling", remap = false) + boolean antarchy$getUseEntityCulling(); + + @Accessor(value = "useEntityCulling", remap = false) + void antarchy$setUseEntityCulling(boolean useEntityCulling); +} diff --git a/common-1.21.1/src/main/resources/antarchy-common.mixins.json b/common-1.21.1/src/main/resources/antarchy-common.mixins.json index 34db77ee..6e332818 100644 --- a/common-1.21.1/src/main/resources/antarchy-common.mixins.json +++ b/common-1.21.1/src/main/resources/antarchy-common.mixins.json @@ -7,6 +7,8 @@ "AbstractMinecartMixin", "AbstractArrowAccessor", "PortalGunEntityCollisionMixin", + "PortalGunPlayerMovePacketMixin", + "ServerGamePacketListenerTeleportAccessor", "PortalGunZombieMixin", "FallingBlockEntityAccessor", "AccessorFireBlock", @@ -142,15 +144,14 @@ "client.CameraBasisAccessor", "client.LevelRendererPortalViewAreaAccessor", "client.LevelRendererPortalViewAreaMixin", - "client.LevelRendererPortalChunkBudgetMixin", - "client.SectionRenderDispatcherPortalUploadsAccessor", "client.LevelRendererPortalLifecycleMixin", "client.PortalViewChunkCacheMixin", - "client.PortalViewSectionSortingMixin", - "client.LevelRendererPortalTargetsAccessor", "client.LevelRendererPortalSceneInvoker", + "client.SectionOcclusionGraphPortalMixin", + "client.MinecraftPortalTransparencyMixin", + "client.EntityRenderDispatcherPortalMixin", + "client.BlockEntityRenderDispatcherPortalMixin", "client.MinecraftMainRenderTargetAccessor", - "client.PostChainTargetAccessor", "client.AbstractMinecartRendererMixin", "client.EntityLightProbeMixin", "client.CustomBossBarMixin", diff --git a/common-1.21.1/src/main/resources/antarchy-sodium.mixins.json b/common-1.21.1/src/main/resources/antarchy-sodium.mixins.json index 40552668..9f091496 100644 --- a/common-1.21.1/src/main/resources/antarchy-sodium.mixins.json +++ b/common-1.21.1/src/main/resources/antarchy-sodium.mixins.json @@ -4,7 +4,9 @@ "plugin": "com.craisinlord.antarchy.mixins.AntarchyMixinPlugin", "compatibilityLevel": "JAVA_21", "client": [ - "client.SodiumWorldRendererMixin" + "compat.sodium.SodiumWorldRendererAccessor", + "compat.sodium.RenderSectionManagerAccessor", + "compat.sodium.RenderSectionManagerPortalTasksMixin" ], "injectors": { "defaultRequire": 1 diff --git a/common-1.21.1/src/main/resources/assets/antarchy/textures/gui/portal_gun_crosshair.png b/common-1.21.1/src/main/resources/assets/antarchy/textures/gui/portal_gun_crosshair.png deleted file mode 100644 index 1adf142c8305ae800503704ba3b99e9911438f95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 341 zcmeAS@N?(olHy`uVBq!ia0vp^NNn{1`ISV`@iy0XB4ude`@%$AjK*3j@E{-7)?oX!~avgFIa4i$LbL+&lND#l*MF?|aa))A#ugdV8cq zl+?doYq0L`J^z`L6>fWnZ}{`?I;Z_t>mZK}(u!;6Uw9{0YI`!;u&bo~>E?A=Iul-; zUmc}VrNbcGc;bR+s2xXY%1?z%7ajFg3xqnRytbOzp|wJxm*dk!Z@;76)A6e6<5uP2;fu^k=mdKI;Vst0KB4wLI3~& diff --git a/fabric-1.21.1/build.gradle b/fabric-1.21.1/build.gradle index eb353483..d875167c 100644 --- a/fabric-1.21.1/build.gradle +++ b/fabric-1.21.1/build.gradle @@ -43,6 +43,11 @@ dependencies { if (providers.gradleProperty('antarchySodiumCompatTest').orNull == 'true') { modLocalRuntime(files("$rootDir/infinite_dimensions_jars/sodium-fabric-0.8.13+mc1.21.1.jar")) } + // Sodium — compile-only, for portal live views drawn through Sodium's renderer. Compiled + // against the NeoForge build (official Mojang mappings, matching this module's compile + // space; Sodium's own classes are identical across loaders). Never bundled. + compileOnly(files(zipTree("$rootDir/infinite_dimensions_jars/sodium-neoforge-0.8.13+mc1.21.1.jar") + .matching { include "META-INF/jarjar/net.caffeinemc.sodium-neoforge-*-mod.jar" })) modCompileOnly("curse.maven:intapi-${intapi_curseforge_id}:${intapi_curseforge_file_id_fabric}") modLocalRuntime("curse.maven:intapi-${intapi_curseforge_id}:${intapi_curseforge_file_id_fabric}") modLocalRuntime("dev.architectury:architectury-fabric:${architectury_api_version}") diff --git a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/client/AntarchyFabricClientBootstrap.java b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/client/AntarchyFabricClientBootstrap.java index 1683bbd7..3e98e667 100644 --- a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/client/AntarchyFabricClientBootstrap.java +++ b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/client/AntarchyFabricClientBootstrap.java @@ -5,7 +5,6 @@ import com.craisinlord.antarchy.fabric.registry.AntarchyFabricItems; import com.craisinlord.antarchy.fabric.registry.AntarchyFabricMisc; import com.craisinlord.antarchy.Antarchy; -import com.craisinlord.antarchy.content.client.PortalGunCrosshairRenderer; import com.craisinlord.antarchy.content.client.CameraShakeClientState; import com.craisinlord.antarchy.content.client.AntarchyArchivePreviews; import com.craisinlord.antarchy.content.client.HerculesBeetleImpactShakeClientState; @@ -626,7 +625,6 @@ public final class AntarchyFabricClientBootstrap { DorrieJumpHudRenderer.render(guiGraphics); HerculesBeetleChargeHudRenderer.render(guiGraphics); com.craisinlord.antarchy.content.client.KingJudgmentFlashHudRenderer.render(guiGraphics); - PortalGunCrosshairRenderer.render(guiGraphics); }); WorldRenderEvents.LAST.register(context -> { diff --git a/neoforge-1.21.1/build.gradle b/neoforge-1.21.1/build.gradle index 5bbc0fe4..b425ba34 100644 --- a/neoforge-1.21.1/build.gradle +++ b/neoforge-1.21.1/build.gradle @@ -49,6 +49,11 @@ dependencies { if (providers.gradleProperty('antarchySodiumCompatTest').orNull == 'true') { runtimeOnly(files(rootProject.file("infinite_dimensions_jars/sodium-neoforge-0.8.13+mc1.21.1.jar"))) } + // Sodium — compile-only, for portal live views drawn through Sodium's renderer + // (content/client/renderer/sodium, mixins/compat/sodium). Never bundled; that code only + // loads when Sodium is installed. The published jar nests the mod jar, so compile against it. + compileOnly(files(zipTree(rootProject.file("infinite_dimensions_jars/sodium-neoforge-0.8.13+mc1.21.1.jar")) + .matching { include "META-INF/jarjar/net.caffeinemc.sodium-neoforge-*-mod.jar" })) compileOnly(files(rootProject.file("infinite_dimensions_jars/antos-neoforge-1.21.1-${antos_version}.jar"))) runtimeOnly(files(rootProject.file("infinite_dimensions_jars/antos-neoforge-1.21.1-${antos_version}.jar"))) compileOnly("curse.maven:intapi-${intapi_curseforge_id}:${intapi_curseforge_file_id_neoforge}") diff --git a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/client/AntarchyNeoForgeClient.java b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/client/AntarchyNeoForgeClient.java index 23d39194..637588a5 100644 --- a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/client/AntarchyNeoForgeClient.java +++ b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/client/AntarchyNeoForgeClient.java @@ -2,7 +2,6 @@ package com.craisinlord.antarchy.neoforge.client; import com.craisinlord.antarchy.Antarchy; import com.craisinlord.antarchy.content.client.GoopedHudRenderer; -import com.craisinlord.antarchy.content.client.PortalGunCrosshairRenderer; import com.craisinlord.antarchy.content.client.AntarchyArchivePreviews; import com.craisinlord.antarchy.content.client.game.AntarchyComputerGames; import com.craisinlord.antarchy.content.client.HordeHudRenderer; @@ -385,11 +384,6 @@ public final class AntarchyNeoForgeClient { @SubscribeEvent public static void registerGuiLayers(RegisterGuiLayersEvent event) { - event.registerAbove( - VanillaGuiLayers.CROSSHAIR, - ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "portal_gun_crosshair"), - (guiGraphics, partialTick) -> PortalGunCrosshairRenderer.render(guiGraphics) - ); event.registerAboveAll( ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "dread_darkness"), (guiGraphics, partialTick) -> DreadHudRenderer.render(guiGraphics)