improve portal gun perf

This commit is contained in:
craisinlord committed 2026-10-12 15:00:42 -05:00
1 parent 759f511b00
commit 0cad456efd
17 files changed
+348 -126

No files matched your search

@@ -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--;
@@ -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<Vec3> 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<Vec3> original) {
Vec3 offset = original.call(entity, item);
AntarchyGravityDirection direction = AntarchyGravityApi.getGravityDirection(entity);
if (!direction.isInverted()) {
return offset;
}
return AntarchyGravityRotationUtil.vecPlayerToWorld(offset, direction);
}
}
@@ -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<Vec3> 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;
@@ -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<PortalGunPortalEntity> ownedPortals = collectOwnedPortals(minecraft);
if (excluded != null) {
ownedPortals.remove(excluded);
}
if (ownedPortals.isEmpty()) {
return;
}
@@ -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<PoseStack> crossingEntities) {
PortalTerrain terrain, Consumer<PoseStack> 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);
@@ -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<Key, QueryState> 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<Map.Entry<Key, QueryState>> 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;
}
}
}
@@ -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);
}
@@ -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--;
@@ -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<Level, Map<UUID, PortalGunPortalEntity>> 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<UUID, PortalGunPortalEntity> 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<UUID, PortalGunPortalEntity> portals = portalsIn(level);
return portals != null && !portals.isEmpty();
}
public static Collection<PortalGunPortalEntity> all(Level level) {
if (TRACKED.get() <= 0) {
return List.of();
}
Map<UUID, PortalGunPortalEntity> portals = portalsIn(level);
return portals == null ? List.of() : portals.values();
}
@@ -54,6 +69,9 @@ public final class PortalGunPortalRegistry {
}
public static List<PortalGunPortalEntity> near(Level level, AABB bounds) {
if (TRACKED.get() <= 0) {
return List.of();
}
Map<UUID, PortalGunPortalEntity> portals = portalsIn(level);
if (portals == null || portals.isEmpty()) {
return List.of();
@@ -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<UUID> PROJECTILE_TICKET = TicketType.create("antarchy_portal_projectile", Comparator.comparing(UUID::toString));
private static final LinkedHashMap<UUID, ProjectileTicket> PROJECTILE_TICKETS = new LinkedHashMap<>();
private static final EntityDataAccessor<Integer> 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<Long, CompletableFuture<Boolean>> generatedChecks = new HashMap<>();
public int portalWidth = 1;
public int portalHeight = 2;
@@ -304,24 +309,69 @@ public class PortalGunProjectileEntity extends ThrowableItemProjectile {
return false;
}
List<ChunkPos> 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<Boolean> 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<ChunkPos> 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));
@@ -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<Vec3> 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<Vec3> 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) {
@@ -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<Boolean> 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;
@@ -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();
@@ -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<Vec3> original) {
Vec3 offset = original.call(entity, item);
AntarchyGravityDirection direction = AntarchyGravityApi.getGravityDirection(entity);
if (!direction.isInverted()) {
return offset;
}
return AntarchyGravityRotationUtil.vecPlayerToWorld(offset, direction);
}
}
@@ -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;
}
}
@@ -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());
}
}
+1 -1
View File
@@ -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