diff --git a/common-1.20.1/src/main/java/com/craisinlord/antarchy/content/item/WormHookTetherManager.java b/common-1.20.1/src/main/java/com/craisinlord/antarchy/content/item/WormHookTetherManager.java index 5edf26af..45c499a4 100644 --- a/common-1.20.1/src/main/java/com/craisinlord/antarchy/content/item/WormHookTetherManager.java +++ b/common-1.20.1/src/main/java/com/craisinlord/antarchy/content/item/WormHookTetherManager.java @@ -2,6 +2,8 @@ package com.craisinlord.antarchy.content.item; import com.craisinlord.antarchy.content.AntarchySoundEvents; import com.craisinlord.antarchy.content.entity.WormHookProjectileEntity; +import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi; +import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil; import com.craisinlord.antarchy.content.util.WormHookRope; import java.util.Map; import java.util.UUID; @@ -139,9 +141,9 @@ public final class WormHookTetherManager { // the max length (which alone has no effect until the rope goes taut). if (reeling && dist > MIN_LEN) { Vec3 pull = towardPivot.scale(-REEL_PULL_STRENGTH); - Vec3 reelMotion = player.getDeltaMovement().add(pull); + Vec3 reelMotion = getWorldMotion(player).add(pull); reelMotion = new Vec3(reelMotion.x, Mth.clamp(reelMotion.y, -0.6D, 0.6D), reelMotion.z); - player.setDeltaMovement(reelMotion); + setWorldMotion(player, reelMotion); player.hurtMarked = true; player.fallDistance = 0; } @@ -158,7 +160,7 @@ public final class WormHookTetherManager { return; } - Vec3 motion = player.getDeltaMovement(); + Vec3 motion = getWorldMotion(player); double outward = motion.dot(towardPivot); if (outward > 0) { motion = motion.subtract(towardPivot.scale(outward)); @@ -167,11 +169,19 @@ public final class WormHookTetherManager { Vec3 correction = towardPivot.scale(-overshoot * PULL_CORRECTION); Vec3 newMotion = motion.add(correction); newMotion = new Vec3(newMotion.x, Mth.clamp(newMotion.y, -1.0D, 1.0D), newMotion.z); - player.setDeltaMovement(newMotion); + setWorldMotion(player, newMotion); player.hurtMarked = true; player.fallDistance = 0; } + private static Vec3 getWorldMotion(ServerPlayer player) { + return AntarchyGravityRotationUtil.vecPlayerToWorld(player.getDeltaMovement(), AntarchyGravityApi.getGravityDirection(player)); + } + + private static void setWorldMotion(ServerPlayer player, Vec3 worldMotion) { + player.setDeltaMovement(AntarchyGravityRotationUtil.vecWorldToPlayer(worldMotion, AntarchyGravityApi.getGravityDirection(player))); + } + private static void tickFlyingSound(ServerPlayer player, TetherState state) { if (state.flyingSoundCooldown > 0) { state.flyingSoundCooldown--; diff --git a/common-1.20.1/src/main/java/com/craisinlord/antarchy/mixins/gravity/FireworkRocketGravityMixin.java b/common-1.20.1/src/main/java/com/craisinlord/antarchy/mixins/gravity/FireworkRocketGravityMixin.java index 29d2f0d7..23ea875e 100644 --- a/common-1.20.1/src/main/java/com/craisinlord/antarchy/mixins/gravity/FireworkRocketGravityMixin.java +++ b/common-1.20.1/src/main/java/com/craisinlord/antarchy/mixins/gravity/FireworkRocketGravityMixin.java @@ -1,35 +1,41 @@ package com.craisinlord.antarchy.mixins.gravity; import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi; +import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection; import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil; -import com.craisinlord.antarchy.config.AntarchySettings; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.FireworkRocketEntity; +import net.minecraft.world.item.Item; import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; 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.ModifyVariable; @Mixin(FireworkRocketEntity.class) -/* - * Fixes firework boost dir for inverted elytra flight. - */ public abstract class FireworkRocketGravityMixin { - @Shadow - @Nullable - private LivingEntity attachedToEntity; + @WrapOperation(method = "tick", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/LivingEntity;getLookAngle()Lnet/minecraft/world/phys/Vec3;")) + private Vec3 antarchy$fixFireworkThrustDirection(LivingEntity entity, Operation original) { + Vec3 look = original.call(entity); + AntarchyGravityDirection direction = AntarchyGravityApi.getGravityDirection(entity); + if (!direction.isInverted()) { + return look; + } + return AntarchyGravityRotationUtil.vecWorldToPlayer(look, direction); + } - @ModifyVariable(method = "tick", at = @At(value = "STORE"), ordinal = 0) - private Vec3 antarchy$fixFireworkThrustDirection(Vec3 velocity) { - if (!(this.attachedToEntity instanceof Player player)) return velocity; - if (!AntarchyGravityApi.isGravityInverted(player)) return velocity; - return AntarchyGravityRotationUtil.vecWorldToPlayer( - velocity, - AntarchyGravityApi.getGravityDirection(player) - ); + @WrapOperation(method = "tick", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/LivingEntity;getHandHoldingItemAngle(Lnet/minecraft/world/item/Item;)Lnet/minecraft/world/phys/Vec3;")) + private Vec3 antarchy$rotateAttachedRocketOffset(LivingEntity entity, Item item, Operation original) { + Vec3 offset = original.call(entity, item); + AntarchyGravityDirection direction = AntarchyGravityApi.getGravityDirection(entity); + if (!direction.isInverted()) { + return offset; + } + return AntarchyGravityRotationUtil.vecPlayerToWorld(offset, direction); } } diff --git a/common-1.20.1/src/main/java/com/craisinlord/antarchy/mixins/gravity/LivingEntityMixin.java b/common-1.20.1/src/main/java/com/craisinlord/antarchy/mixins/gravity/LivingEntityMixin.java index 76b5ff93..72d60635 100644 --- a/common-1.20.1/src/main/java/com/craisinlord/antarchy/mixins/gravity/LivingEntityMixin.java +++ b/common-1.20.1/src/main/java/com/craisinlord/antarchy/mixins/gravity/LivingEntityMixin.java @@ -39,6 +39,15 @@ public abstract class LivingEntityMixin { return AntarchyGravityRotationUtil.vecWorldToPlayer(entity.position(), direction).y; } + @WrapOperation(method = "travel", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;getLookAngle()Lnet/minecraft/world/phys/Vec3;")) + private Vec3 antarchy$fixTravelLookAngle(LivingEntity entity, Operation original) { + Vec3 look = original.call(entity); + AntarchyGravityDirection direction = AntarchyGravityApi.getGravityDirection(entity); + if (!direction.isInverted() || !entity.isFallFlying()) return look; + return AntarchyGravityRotationUtil.vecWorldToPlayer(look, direction); + } + @ModifyVariable(method = "checkFallDamage", at = @At("HEAD"), ordinal = 0, argsOnly = true) private double antarchy$invertLivingFallDamageY(double worldY) { LivingEntity entity = (LivingEntity) (Object) this; diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalRim.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalRim.java index 92f03e25..135b8339 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalRim.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalRim.java @@ -53,10 +53,18 @@ public final class PortalGunPortalRim { } static void drawHiddenOutlines(Minecraft minecraft, Vec3 cameraPos, Matrix4f viewMatrix, Matrix4f projectionMatrix, float partialTick) { + drawHiddenOutlines(minecraft, cameraPos, viewMatrix, projectionMatrix, partialTick, null); + } + + static void drawHiddenOutlines(Minecraft minecraft, Vec3 cameraPos, Matrix4f viewMatrix, Matrix4f projectionMatrix, float partialTick, + PortalGunPortalEntity excluded) { if (minecraft.level == null || minecraft.player == null) { return; } List ownedPortals = collectOwnedPortals(minecraft); + if (excluded != null) { + ownedPortals.remove(excluded); + } if (ownedPortals.isEmpty()) { return; } 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 index e9f62769..cb35171b 100644 --- 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 @@ -14,6 +14,7 @@ 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.UUID; import java.util.function.Consumer; import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; @@ -53,7 +54,8 @@ public final class PortalGunPortalSceneRenderer { public static void render(Minecraft minecraft, Camera camera, float partialTick, Matrix4f viewMatrix, Matrix4f projection, Matrix4f skyProjection, Frustum frustum, - PortalTerrain terrain, Consumer crossingEntities) { + PortalTerrain terrain, Consumer crossingEntities, + UUID sourceId, UUID destinationId, int viewLevel) { LevelRenderer renderer = minecraft.levelRenderer; LevelRendererPortalViewAreaAccessor state = (LevelRendererPortalViewAreaAccessor) renderer; LevelRendererPortalSceneInvoker scene = (LevelRendererPortalSceneInvoker) renderer; @@ -94,8 +96,10 @@ public final class PortalGunPortalSceneRenderer { 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)); + if (irisPipelineInstalled || PortalGunPortalSkyQueries.shouldRenderSky(sourceId, destinationId, viewLevel)) { + renderer.renderSky(viewMatrix, skyProjection, partialTick, camera, foggy, + () -> FogRenderer.setupFog(camera, FogRenderer.FogMode.FOG_SKY, renderDistance, foggy, partialTick)); + } } RenderSystem.setProjectionMatrix(projection, VertexSorting.DISTANCE_TO_ORIGIN); @@ -144,6 +148,9 @@ public final class PortalGunPortalSceneRenderer { renderBlockEntity(minecraft, blockEntity, cameraX, cameraY, cameraZ, partialTick, poseStack, buffers)); } buffers.endBatch(); + if (!irisPipelineInstalled) { + PortalGunPortalSkyQueries.querySkyVisibility(sourceId, destinationId, viewLevel); + } { terrain.drawLayer(minecraft, RenderType.translucent(), cameraPosition, viewMatrix, projection); diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalSkyQueries.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalSkyQueries.java new file mode 100644 index 00000000..4b2caaee --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/PortalGunPortalSkyQueries.java @@ -0,0 +1,129 @@ +package com.craisinlord.antarchy.content.client.renderer; + +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.Tesselator; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.blaze3d.vertex.VertexSorting; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.UUID; +import net.minecraft.client.renderer.GameRenderer; +import org.joml.Matrix4f; +import org.joml.Matrix4fStack; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL15; + +public final class PortalGunPortalSkyQueries { + private static final int MAX_ENTRIES = 128; + private static final LinkedHashMap QUERIES = new LinkedHashMap<>(16, 0.75F, true); + + private PortalGunPortalSkyQueries() { + } + + public static boolean shouldRenderSky(UUID source, UUID destination, int level) { + QueryState state = QUERIES.get(new Key(source, destination, level)); + if (state == null) { + return true; + } + poll(state); + return !state.hasResult || state.visible; + } + + public static void querySkyVisibility(UUID source, UUID destination, int level) { + Key key = new Key(source, destination, level); + QueryState state = QUERIES.computeIfAbsent(key, ignored -> new QueryState(GL15.glGenQueries())); + poll(state); + if (state.inFlight) { + trim(); + return; + } + MeshData mesh = buildFarPlane(); + if (mesh == null) { + trim(); + return; + } + Matrix4fStack modelViewStack = RenderSystem.getModelViewStack(); + Matrix4f previousProjection = new Matrix4f(RenderSystem.getProjectionMatrix()); + VertexSorting previousSorting = RenderSystem.getVertexSorting(); + int previousDepthFunction = GL11.glGetInteger(GL11.GL_DEPTH_FUNC); + modelViewStack.pushMatrix(); + GL15.glBeginQuery(GL15.GL_SAMPLES_PASSED, state.query); + try { + RenderSystem.enableDepthTest(); + RenderSystem.depthMask(false); + RenderSystem.colorMask(false, false, false, false); + RenderSystem.disableBlend(); + RenderSystem.disableCull(); + GL11.glDepthFunc(GL11.GL_LEQUAL); + modelViewStack.identity(); + RenderSystem.applyModelViewMatrix(); + RenderSystem.setProjectionMatrix(new Matrix4f(), previousSorting); + RenderSystem.setShader(GameRenderer::getPositionShader); + BufferUploader.drawWithShader(mesh); + } finally { + GL15.glEndQuery(GL15.GL_SAMPLES_PASSED); + state.inFlight = true; + GL11.glDepthFunc(previousDepthFunction); + RenderSystem.colorMask(true, true, true, true); + RenderSystem.depthMask(true); + RenderSystem.enableCull(); + RenderSystem.setProjectionMatrix(previousProjection, previousSorting); + modelViewStack.popMatrix(); + RenderSystem.applyModelViewMatrix(); + } + trim(); + } + + public static void clear() { + for (QueryState state : QUERIES.values()) { + GL15.glDeleteQueries(state.query); + } + QUERIES.clear(); + } + + private static void poll(QueryState state) { + if (state.inFlight && GL15.glGetQueryObjecti(state.query, GL15.GL_QUERY_RESULT_AVAILABLE) != 0) { + state.visible = GL15.glGetQueryObjecti(state.query, GL15.GL_QUERY_RESULT) != 0; + state.hasResult = true; + state.inFlight = false; + } + } + + private static MeshData buildFarPlane() { + 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); + return buffer.build(); + } + + private static void trim() { + Iterator> iterator = QUERIES.entrySet().iterator(); + while (QUERIES.size() > MAX_ENTRIES && iterator.hasNext()) { + QueryState state = iterator.next().getValue(); + if (!state.inFlight) { + GL15.glDeleteQueries(state.query); + iterator.remove(); + } + } + } + + private record Key(UUID source, UUID destination, int level) { + } + + private static final class QueryState { + private final int query; + private boolean inFlight; + private boolean hasResult; + private boolean visible = true; + + private QueryState(int query) { + this.query = query; + } + } +} 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 cb7fee3b..9e993b52 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 @@ -75,6 +75,7 @@ public final class PortalGunPortalViewRenderer { public static void releaseTargets() { PortalGunPortalVisibilityQueries.clear(); + PortalGunPortalSkyQueries.clear(); PortalGunPortalSectionViews.clear(); if (offscreenTarget != null) { offscreenTarget.destroyBuffers(); @@ -86,10 +87,10 @@ public final class PortalGunPortalViewRenderer { if (renderingPortalView) { return; } + renderHiddenOutlines(camera, poseMatrix, projectionMatrix, tickCounter); if (isEnabled()) { renderViews(camera, poseMatrix, projectionMatrix, tickCounter); } - renderHiddenOutlines(camera, poseMatrix, projectionMatrix, tickCounter); } private static void renderHiddenOutlines(Camera camera, Matrix4f poseMatrix, Matrix4f projectionMatrix, DeltaTracker tickCounter) { @@ -244,6 +245,8 @@ public final class PortalGunPortalViewRenderer { 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); + PortalGunPortalRim.drawHiddenOutlines(minecraft, transformed.cameraPos(), transformed.viewMatrix(), clippedProjection, + partialTick, destination); if (parentLevel + 1 < MAX_VIEW_LEVELS) { renderNestedViews(minecraft, cameraEntity, partialTick, transformed, rootProjection, clippedProjection, destination, parentLevel + 1, clip, budget, target.width, target.height); @@ -353,6 +356,8 @@ public final class PortalGunPortalViewRenderer { 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); + PortalGunPortalRim.drawHiddenOutlines(minecraft, transformed.cameraPos(), transformed.viewMatrix(), clippedProjection, + partialTick, destination); } finally { RenderSystem.disableScissor(); targetAccessor.antarchy$setMainRenderTarget(mainTarget); @@ -378,7 +383,8 @@ public final class PortalGunPortalViewRenderer { PortalTerrain 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)); + poseStack -> renderCrossingEntities(minecraft, transformed.cameraPos(), partialTick, source, destination, poseStack), + source.getUUID(), destination.getUUID(), level); } finally { PortalGunPortalRenderState.popPortalView(false); } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/item/WormHookTetherManager.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/item/WormHookTetherManager.java index 117f0048..5e765760 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/item/WormHookTetherManager.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/item/WormHookTetherManager.java @@ -2,6 +2,8 @@ package com.craisinlord.antarchy.content.item; import com.craisinlord.antarchy.content.AntarchySoundEvents; import com.craisinlord.antarchy.content.entity.WormHookProjectileEntity; +import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi; +import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil; import com.craisinlord.antarchy.content.util.WormHookRope; import java.util.Map; import java.util.UUID; @@ -125,9 +127,9 @@ public final class WormHookTetherManager { if (reeling && dist > MIN_LEN) { Vec3 pull = towardPivot.scale(-REEL_PULL_STRENGTH); - Vec3 reelMotion = player.getDeltaMovement().add(pull); + Vec3 reelMotion = getWorldMotion(player).add(pull); reelMotion = new Vec3(reelMotion.x, Mth.clamp(reelMotion.y, -0.6D, 0.6D), reelMotion.z); - player.setDeltaMovement(reelMotion); + setWorldMotion(player, reelMotion); player.hurtMarked = true; player.fallDistance = 0; } @@ -144,7 +146,7 @@ public final class WormHookTetherManager { return; } - Vec3 motion = player.getDeltaMovement(); + Vec3 motion = getWorldMotion(player); double outward = motion.dot(towardPivot); if (outward > 0) { motion = motion.subtract(towardPivot.scale(outward)); @@ -153,11 +155,19 @@ public final class WormHookTetherManager { Vec3 correction = towardPivot.scale(-overshoot * PULL_CORRECTION); Vec3 newMotion = motion.add(correction); newMotion = new Vec3(newMotion.x, Mth.clamp(newMotion.y, -1.0D, 1.0D), newMotion.z); - player.setDeltaMovement(newMotion); + setWorldMotion(player, newMotion); player.hurtMarked = true; player.fallDistance = 0; } + private static Vec3 getWorldMotion(ServerPlayer player) { + return AntarchyGravityRotationUtil.vecPlayerToWorld(player.getDeltaMovement(), AntarchyGravityApi.getGravityDirection(player)); + } + + private static void setWorldMotion(ServerPlayer player, Vec3 worldMotion) { + player.setDeltaMovement(AntarchyGravityRotationUtil.vecWorldToPlayer(worldMotion, AntarchyGravityApi.getGravityDirection(player))); + } + private static void tickFlyingSound(ServerPlayer player, TetherState state) { if (state.flyingSoundCooldown > 0) { state.flyingSoundCooldown--; diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/portalgun/PortalGunPortalRegistry.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/portalgun/PortalGunPortalRegistry.java index 3b46b343..ba56313b 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/portalgun/PortalGunPortalRegistry.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/portalgun/PortalGunPortalRegistry.java @@ -8,11 +8,13 @@ import java.util.Map; import java.util.UUID; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; import net.minecraft.world.level.Level; import net.minecraft.world.phys.AABB; public final class PortalGunPortalRegistry { private static final Map> LEVELS = Collections.synchronizedMap(new WeakHashMap<>()); + private static final AtomicInteger TRACKED = new AtomicInteger(); private PortalGunPortalRegistry() { } @@ -26,17 +28,30 @@ public final class PortalGunPortalRegistry { synchronized (LEVELS) { portals = LEVELS.computeIfAbsent(level, ignored -> new ConcurrentHashMap<>()); } - portals.put(portal.getUUID(), portal); + if (portals.put(portal.getUUID(), portal) == null) { + TRACKED.incrementAndGet(); + } } static void untrack(PortalGunPortalEntity portal) { Map portals = portalsIn(portal.level()); - if (portals != null) { - portals.remove(portal.getUUID(), portal); + if (portals != null && portals.remove(portal.getUUID(), portal)) { + TRACKED.decrementAndGet(); } } + public static boolean hasAny(Level level) { + if (TRACKED.get() <= 0) { + return false; + } + Map portals = portalsIn(level); + return portals != null && !portals.isEmpty(); + } + public static Collection all(Level level) { + if (TRACKED.get() <= 0) { + return List.of(); + } Map portals = portalsIn(level); return portals == null ? List.of() : portals.values(); } @@ -54,6 +69,9 @@ public final class PortalGunPortalRegistry { } public static List near(Level level, AABB bounds) { + if (TRACKED.get() <= 0) { + return List.of(); + } Map portals = portalsIn(level); if (portals == null || portals.isEmpty()) { return List.of(); diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/portalgun/PortalGunProjectileEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/portalgun/PortalGunProjectileEntity.java index 64fe075e..0f293419 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/portalgun/PortalGunProjectileEntity.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/portalgun/PortalGunProjectileEntity.java @@ -7,10 +7,12 @@ import com.craisinlord.antarchy.content.gravity.AntarchyGravityTransition; import com.craisinlord.antarchy.config.AntarchySettings; import java.util.ArrayList; import java.util.Comparator; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.concurrent.CompletableFuture; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.core.component.DataComponents; @@ -38,6 +40,7 @@ import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.block.StainedGlassBlock; import net.minecraft.world.level.block.StainedGlassPaneBlock; import net.minecraft.world.level.block.TintedGlassBlock; @@ -53,6 +56,7 @@ public class PortalGunProjectileEntity extends ThrowableItemProjectile { private static final int MAX_TICKETED_PROJECTILES = 20; private static final int PROJECTILE_TICKET_LEVEL = 31; private static final int MAX_CHUNK_WAIT_TICKS = 200; + private static final int GENERATED_CHECK_RADIUS = 3; private static final TicketType PROJECTILE_TICKET = TicketType.create("antarchy_portal_projectile", Comparator.comparing(UUID::toString)); private static final LinkedHashMap PROJECTILE_TICKETS = new LinkedHashMap<>(); private static final EntityDataAccessor SIDE = SynchedEntityData.defineId(PortalGunProjectileEntity.class, EntityDataSerializers.INT); @@ -79,6 +83,7 @@ public class PortalGunProjectileEntity extends ThrowableItemProjectile { private boolean spawnSynced; private boolean ticketRegistered; private int chunkWaitTicks; + private final Map> generatedChecks = new HashMap<>(); public int portalWidth = 1; public int portalHeight = 2; @@ -304,24 +309,69 @@ public class PortalGunProjectileEntity extends ThrowableItemProjectile { return false; } List path = chunksAlong(position, position.add(motion)); - boolean chunkload = AntarchySettings.portalGunCanPortalProjectilesChunkload(); - if (chunkload) { - this.updateProjectileTicket(level, path); - } else { + boolean playerArea = true; + for (ChunkPos chunk : path) { + if (!level.isPositionEntityTicking(chunk.getMiddleBlockPosition(0))) { + playerArea = false; + break; + } + } + if (playerArea) { this.releaseProjectileTicket(); + this.chunkWaitTicks = 0; + return true; + } + if (!AntarchySettings.portalGunCanPortalProjectilesChunkload()) { + this.releaseProjectileTicket(); + this.discard(); + return false; } for (ChunkPos chunk : path) { - if (level.getChunkSource().getChunkNow(chunk.x, chunk.z) == null) { - if (!chunkload || ++this.chunkWaitTicks > MAX_CHUNK_WAIT_TICKS) { - this.discard(); + for (int dx = -GENERATED_CHECK_RADIUS; dx <= GENERATED_CHECK_RADIUS; dx++) { + for (int dz = -GENERATED_CHECK_RADIUS; dz <= GENERATED_CHECK_RADIUS; dz++) { + ChunkPos around = new ChunkPos(chunk.x + dx, chunk.z + dz); + if (level.getChunkSource().getChunkNow(around.x, around.z) != null) { + continue; + } + Boolean generated = this.isGenerated(level, around); + if (generated == null) { + return this.waitForChunks(); + } + if (!generated) { + this.discard(); + return false; + } } - return false; + } + } + this.updateProjectileTicket(level, path); + for (ChunkPos chunk : path) { + if (!level.isPositionEntityTicking(chunk.getMiddleBlockPosition(0))) { + return this.waitForChunks(); } } this.chunkWaitTicks = 0; return true; } + private boolean waitForChunks() { + if (++this.chunkWaitTicks > MAX_CHUNK_WAIT_TICKS) { + this.discard(); + } + return false; + } + + private Boolean isGenerated(ServerLevel level, ChunkPos chunk) { + CompletableFuture check = this.generatedChecks.computeIfAbsent(chunk.toLong(), key -> level.getChunkSource().chunkMap.read(chunk) + .thenApply(tag -> tag.map(PortalGunProjectileEntity::isFullChunk).orElse(false)) + .exceptionally(error -> false)); + return check.isDone() ? check.join() : null; + } + + private static boolean isFullChunk(CompoundTag tag) { + return ChunkStatus.byName(tag.getString("Status")).isOrAfter(ChunkStatus.FULL); + } + private static List chunksAlong(Vec3 start, Vec3 end) { int minX = SectionPos.blockToSectionCoord(Math.min(start.x, end.x)); int maxX = SectionPos.blockToSectionCoord(Math.max(start.x, end.x)); diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/PortalGunEntityCollisionMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/PortalGunEntityCollisionMixin.java index d93e15c0..0b5d9770 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/PortalGunEntityCollisionMixin.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/PortalGunEntityCollisionMixin.java @@ -2,6 +2,7 @@ package com.craisinlord.antarchy.mixins; import com.craisinlord.antarchy.content.portalgun.PortalGunCollisionHelper; import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity; +import com.craisinlord.antarchy.content.portalgun.PortalGunPortalRegistry; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.MoverType; import net.minecraft.world.phys.AABB; @@ -24,12 +25,21 @@ public abstract class PortalGunEntityCollisionMixin { @Inject(method = "move", at = @At("HEAD")) private void antarchy$capturePortalGunMovementStart(MoverType type, Vec3 movement, CallbackInfo ci) { - this.antarchy$portalGunMoveStartBox = ((Entity) (Object) this).getBoundingBox(); - this.antarchy$portalGunMoveStartVelocity = ((Entity) (Object) this).getDeltaMovement(); + Entity entity = (Entity) (Object) this; + if (!PortalGunPortalRegistry.hasAny(entity.level())) { + this.antarchy$portalGunMoveStartBox = null; + this.antarchy$portalGunMoveStartVelocity = null; + return; + } + this.antarchy$portalGunMoveStartBox = entity.getBoundingBox(); + this.antarchy$portalGunMoveStartVelocity = entity.getDeltaMovement(); } @Inject(method = "move", at = @At("RETURN")) private void antarchy$teleportMobOnPortalCrossing(MoverType type, Vec3 movement, CallbackInfo ci) { + if (this.antarchy$portalGunMoveStartBox == null) { + return; + } AABB startBox = this.antarchy$portalGunMoveStartBox; Vec3 startVelocity = this.antarchy$portalGunMoveStartVelocity; this.antarchy$portalGunMoveStartBox = null; @@ -41,15 +51,16 @@ public abstract class PortalGunEntityCollisionMixin { @Inject(method = "collide", at = @At("HEAD")) private void antarchy$capturePortalGunStartBox(Vec3 movement, CallbackInfoReturnable cir) { - this.antarchy$portalGunStartBox = ((Entity) (Object) this).getBoundingBox(); + Entity entity = (Entity) (Object) this; + this.antarchy$portalGunStartBox = PortalGunPortalRegistry.hasAny(entity.level()) ? entity.getBoundingBox() : null; } @Inject(method = "collide", at = @At("RETURN"), cancellable = true) private void antarchy$restorePortalCrossingMotion(Vec3 movement, CallbackInfoReturnable cir) { - Entity entity = (Entity) (Object) this; if (this.antarchy$portalGunStartBox == null) { return; } + Entity entity = (Entity) (Object) this; Vec3 collided = cir.getReturnValue(); Vec3 adjusted = PortalGunCollisionHelper.resolveCollision(entity, this.antarchy$portalGunStartBox, movement, collided); if (adjusted != collided) { diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/PortalGunEntityInWallMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/PortalGunEntityInWallMixin.java index 43802a05..ef3c22e9 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/PortalGunEntityInWallMixin.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/PortalGunEntityInWallMixin.java @@ -1,6 +1,7 @@ package com.craisinlord.antarchy.mixins; import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity; +import com.craisinlord.antarchy.content.portalgun.PortalGunPortalRegistry; import net.minecraft.world.entity.Entity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -12,10 +13,10 @@ public abstract class PortalGunEntityInWallMixin { @Inject(method = "isInWall", at = @At("HEAD"), cancellable = true) private void antarchy$ignorePortalInWall(CallbackInfoReturnable cir) { Entity entity = (Entity) (Object) this; - if (entity.level() == null) { + if (entity.level() == null || !PortalGunPortalRegistry.hasAny(entity.level())) { return; } - for (PortalGunPortalEntity portal : com.craisinlord.antarchy.content.portalgun.PortalGunPortalRegistry.near(entity.level(), entity.getBoundingBox().inflate(2.0D))) { + for (PortalGunPortalEntity portal : PortalGunPortalRegistry.near(entity.level(), entity.getBoundingBox().inflate(2.0D))) { if (portal.intersectsEntityBounds(entity) || portal.getCollisionRemovalAabbForEntity(entity).intersects(entity.getBoundingBox())) { cir.setReturnValue(false); return; 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 index 7bce296f..1f5d9a7f 100644 --- 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 @@ -1,6 +1,7 @@ package com.craisinlord.antarchy.mixins; import com.craisinlord.antarchy.content.portalgun.PortalGunPortalEntity; +import com.craisinlord.antarchy.content.portalgun.PortalGunPortalRegistry; import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.ServerGamePacketListenerImpl; @@ -29,7 +30,7 @@ public abstract class PortalGunPlayerMovePacketMixin { } this.antarchy$portalGunMoveStartBox = null; this.antarchy$portalGunMoveStartPosition = null; - if (!packet.hasPosition() || ((ServerGamePacketListenerTeleportAccessor) this).antarchy$getAwaitingPositionFromClient() != null) { + if (!packet.hasPosition() || !PortalGunPortalRegistry.hasAny(player.level()) || ((ServerGamePacketListenerTeleportAccessor) this).antarchy$getAwaitingPositionFromClient() != null) { return; } this.antarchy$portalGunMoveStartBox = player.getBoundingBox(); diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/gravity/FireworkRocketGravityMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/gravity/FireworkRocketGravityMixin.java index 29d2f0d7..6bf1410d 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/gravity/FireworkRocketGravityMixin.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/gravity/FireworkRocketGravityMixin.java @@ -1,35 +1,29 @@ package com.craisinlord.antarchy.mixins.gravity; import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi; +import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection; import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil; -import com.craisinlord.antarchy.config.AntarchySettings; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.FireworkRocketEntity; +import net.minecraft.world.item.Item; import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; 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.ModifyVariable; @Mixin(FireworkRocketEntity.class) -/* - * Fixes firework boost dir for inverted elytra flight. - */ public abstract class FireworkRocketGravityMixin { - @Shadow - @Nullable - private LivingEntity attachedToEntity; - - @ModifyVariable(method = "tick", at = @At(value = "STORE"), ordinal = 0) - private Vec3 antarchy$fixFireworkThrustDirection(Vec3 velocity) { - if (!(this.attachedToEntity instanceof Player player)) return velocity; - if (!AntarchyGravityApi.isGravityInverted(player)) return velocity; - return AntarchyGravityRotationUtil.vecWorldToPlayer( - velocity, - AntarchyGravityApi.getGravityDirection(player) - ); + @WrapOperation(method = "tick", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/entity/LivingEntity;getHandHoldingItemAngle(Lnet/minecraft/world/item/Item;)Lnet/minecraft/world/phys/Vec3;")) + private Vec3 antarchy$rotateAttachedRocketOffset(LivingEntity entity, Item item, Operation original) { + Vec3 offset = original.call(entity, item); + AntarchyGravityDirection direction = AntarchyGravityApi.getGravityDirection(entity); + if (!direction.isInverted()) { + return offset; + } + return AntarchyGravityRotationUtil.vecPlayerToWorld(offset, direction); } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/gravity/client/CameraGravityMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/gravity/client/CameraGravityMixin.java index 3481cb58..42ccba3a 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/gravity/client/CameraGravityMixin.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/gravity/client/CameraGravityMixin.java @@ -17,12 +17,6 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(Camera.class) -/* - * Fixes camera pos/rot for inverted gravity and the flip anim. - * Rotation is applied before move() so third-person pull-back uses the - * correct gravity-adjusted forward direction. First-person falls through - * to the TAIL inject since setup never calls move() in that case. - */ public abstract class CameraGravityMixin { @Shadow private Entity entity; @@ -37,18 +31,13 @@ public abstract class CameraGravityMixin { private float eyeHeightOld; private float antarchy$storedTickDelta; - private boolean antarchy$gravityApplied; @Shadow protected abstract void setPosition(double x, double y, double z); - @Shadow - protected abstract void move(float forward, float up, float left); - @Inject(method = "setup", at = @At("HEAD")) private void antarchy$storeTickDelta(BlockGetter level, Entity entity, boolean detached, boolean mirrored, float partialTick, CallbackInfo ci) { this.antarchy$storedTickDelta = partialTick; - this.antarchy$gravityApplied = false; } @Redirect( @@ -88,53 +77,17 @@ public abstract class CameraGravityMixin { ); } - /* - * Intercept the move() call inside setup so the pull-back direction - * already has gravity rotation applied. This covers detached (third-person) - * and sleeping cameras. Sets a flag so the TAIL inject doesn't double-apply. - */ - @Redirect( - method = "setup", - at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;move(FFF)V") + @Inject( + method = "setRotation", + at = @At(value = "INVOKE", target = "Lorg/joml/Quaternionf;rotationYXZ(FFF)Lorg/joml/Quaternionf;", shift = At.Shift.AFTER) ) - private void antarchy$moveWithGravity( - Camera camera, - float forward, - float up, - float left, - BlockGetter level, - Entity entity, - boolean detached, - boolean mirrored, - float partialTick - ) { - antarchy$applyGravityRotationOnce(); - this.move(forward, up, left); - } - - /* - * First-person fallthrough: setup never calls move(), so gravity rotation - * hasn't been applied yet when we reach the end of the method. - */ - @Inject(method = "setup", at = @At("TAIL")) - private void antarchy$applyGravityAtTail(BlockGetter level, Entity entity, boolean detached, boolean mirrored, float partialTick, CallbackInfo ci) { - antarchy$applyGravityRotationOnce(); - } - - private void antarchy$applyGravityRotationOnce() { - if (this.antarchy$gravityApplied) { - return; - } + private void antarchy$applyGravityRotation(CallbackInfo ci) { if (this.entity == null) { return; } - if (!AntarchyGravityApi.isGravityInverted(this.entity) && AntarchyGravityApi.getGravityFlipProgress(this.entity, this.antarchy$storedTickDelta) <= 0.0F) { - this.rotation.premul(new Quaternionf().fromAxisAngleDeg(0.0F, 0.0F, -1.0F, PortalGunRollClientState.getRollDegrees(this.antarchy$storedTickDelta))); - this.antarchy$gravityApplied = true; - return; + if (AntarchyGravityApi.isGravityInverted(this.entity) || AntarchyGravityApi.getGravityFlipProgress(this.entity, this.antarchy$storedTickDelta) > 0.0F) { + this.rotation.premul(AntarchyGravityRotationUtil.getCameraRotationQuaternion(this.entity, this.antarchy$storedTickDelta)); } - this.rotation.premul(AntarchyGravityRotationUtil.getCameraRotationQuaternion(this.entity, this.antarchy$storedTickDelta)); this.rotation.premul(new Quaternionf().fromAxisAngleDeg(0.0F, 0.0F, -1.0F, PortalGunRollClientState.getRollDegrees(this.antarchy$storedTickDelta))); - this.antarchy$gravityApplied = true; } } diff --git a/forge-1.20.1/src/main/java/com/craisinlord/antarchy/forge/client/GravityCameraRollHandler.java b/forge-1.20.1/src/main/java/com/craisinlord/antarchy/forge/client/GravityCameraRollHandler.java index 1c3bb956..6a3a9fd4 100644 --- a/forge-1.20.1/src/main/java/com/craisinlord/antarchy/forge/client/GravityCameraRollHandler.java +++ b/forge-1.20.1/src/main/java/com/craisinlord/antarchy/forge/client/GravityCameraRollHandler.java @@ -2,11 +2,13 @@ package com.craisinlord.antarchy.forge.client; import com.craisinlord.antarchy.Antarchy; import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi; +import net.minecraft.client.Camera; import net.minecraft.world.entity.Entity; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.ViewportEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; +import org.joml.Vector3f; @Mod.EventBusSubscriber(modid = Antarchy.MODID, value = Dist.CLIENT) public final class GravityCameraRollHandler { @@ -15,7 +17,8 @@ public final class GravityCameraRollHandler { @SubscribeEvent public static void onComputeCameraAngles(ViewportEvent.ComputeCameraAngles event) { - Entity entity = event.getCamera().getEntity(); + Camera camera = event.getCamera(); + Entity entity = camera.getEntity(); if (entity == null) { return; } @@ -25,6 +28,12 @@ public final class GravityCameraRollHandler { return; } - event.setRoll(event.getRoll() + 180.0F * flipProgress); + float gravityRoll = 180.0F * flipProgress; + event.setRoll(event.getRoll() + gravityRoll); + + Vector3f look = camera.getLookVector(); + float radians = (float) Math.toRadians(gravityRoll); + camera.getUpVector().rotateAxis(radians, look.x(), look.y(), look.z()); + camera.getLeftVector().rotateAxis(radians, look.x(), look.y(), look.z()); } } diff --git a/gradle.properties b/gradle.properties index bccaf1c6..c8a01030 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ org.gradle.configureondemand=true minecraft_version_1_21_1=1.21.1 modid=antarchy mod_id=antarchy -mod_version=2.2.1 +mod_version=2.2.2 maven_group=com.craisinlord mixin_version=0.15.4+mixin.0.8.7