fix king and queen attack anim bug

stabalize RainbowAntEntity dims
patch config inconsitency
fixed undervault
performance improvements
This commit is contained in:
craisinlord committed 2026-09-12 23:58:24 -05:00
1 parent 377f3785af
commit 37e941915d
47 files changed
+778 -225

No files matched your search

@@ -22,8 +22,8 @@ public interface InfinityCompatBridge {
return getRandomDimensionId(random);
}
default boolean requestWarp(ServerPlayer player, ResourceLocation dimensionId) {
return false;
default InfinityWarpResult requestWarp(ServerPlayer player, ResourceLocation dimensionId) {
return InfinityWarpResult.REJECTED;
}
/**
@@ -0,0 +1,9 @@
package com.craisinlord.antarchy.compat.infinity;
public enum InfinityWarpResult {
REJECTED,
PENDING,
READY,
FAILED_GENERATION,
TIMEOUT
}
@@ -5,6 +5,9 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.ItemInteractionResult;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
@@ -16,6 +19,7 @@ import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.phys.BlockHitResult;
import java.util.function.Supplier;
@@ -60,6 +64,25 @@ public final class UnderVaultBlock extends VaultBlock {
return new UnderVaultBlockEntity(pos, state, blockEntityType);
}
@Override
public ItemInteractionResult useItemOn(ItemStack stack, BlockState state, Level level, BlockPos pos,
net.minecraft.world.entity.player.Player player, InteractionHand hand,
BlockHitResult hitResult) {
if (stack.isEmpty() || state.getValue(STATE) != net.minecraft.world.level.block.entity.vault.VaultState.ACTIVE) {
return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
}
if (level instanceof ServerLevel serverLevel
&& level.getBlockEntity(pos) instanceof UnderVaultBlockEntity underVault) {
net.minecraft.world.level.block.entity.vault.VaultBlockEntity.Server.tryInsertKey(
serverLevel, pos, state, underVault.getVaultData().getConfig(),
underVault.getVaultData().getServerData(), underVault.getVaultData().getSharedData(),
player, stack);
return ItemInteractionResult.SUCCESS;
}
return level.isClientSide ? ItemInteractionResult.CONSUME
: ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
}
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) {
if (this.blockEntityType == null || type != this.blockEntityType.get()) {
@@ -163,4 +163,9 @@ public final class ClientTimeDilationTicker {
public static void applyFields(List<TimeDilationFieldSnapshot> fields) {
activeFields = List.copyOf(fields);
}
public static boolean hasActiveDilation() {
return !activeFields.isEmpty()
|| com.craisinlord.antarchy.content.time.TimeDilationApi.hasSyncedClientRates();
}
}
@@ -33,21 +33,20 @@ public final class ContractionAfterimages {
iterator.remove();
}
}
if (holder == null) {
return;
}
for (Entity entity : level.entitiesForRendering()) {
if (!(entity instanceof LivingEntity living) || living.isInvisible() || !living.hasEffect(holder)) {
continue;
public static void observe(LivingEntity living) {
Holder<MobEffect> holder = RoyalEffectHooks.contractedHolder();
if (holder == null || living.isInvisible() || !living.hasEffect(holder)) {
return;
}
int now = (int) (living.level().getGameTime() & 0x7fffffffL);
Deque<Sample> samples = HISTORY.computeIfAbsent(living, ignored -> new ArrayDeque<>());
samples.addFirst(new Sample(living, now));
while (samples.size() > MAX_SAMPLES) {
samples.removeLast();
}
}
}
public static Deque<Sample> samples(LivingEntity entity) {
return HISTORY.get(entity);
@@ -4,7 +4,6 @@ import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.royal.RoyalBossEntity;
import com.craisinlord.antarchy.content.entity.royal.RoyalHead;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import software.bernie.geckolib.animation.AnimationState;
@@ -15,11 +14,6 @@ public class RoyalBossModel extends GeoModel<RoyalBossEntity> {
private static final String[] BEAM_ANCHORS = {
"beam_anchor_left", "beam_anchor_center", "beam_anchor_right"
};
private static final String[][] AIM_CHAINS = {
{"L_neck", "L_neck2", "L_neck3"},
{"neck", "neck3", "neck4"},
{"R_neck", "R_neck2", "R_neck3"}
};
@Override
public ResourceLocation getModelResource(RoyalBossEntity animatable) {
@@ -45,33 +39,6 @@ public class RoyalBossModel extends GeoModel<RoyalBossEntity> {
this.getBone(anchor).ifPresent(bone -> bone.setTrackingMatrices(true));
}
float partialTick = animationState.getPartialTick();
for (RoyalHead.Slot slot : RoyalHead.Slot.values()) {
Vec3 beamEnd = animatable.getRoyalBeamEndPosition(slot);
if (!animatable.isFiringRoyalBeam(slot) || beamEnd == null) continue;
Vec3 origin = animatable.getRoyalBeamShootFrom(slot, partialTick);
Vec3 direction = com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil.vecWorldToPlayer(
beamEnd.subtract(origin),
com.craisinlord.antarchy.content.gravity.AntarchyGravityApi.getGravityDirection(animatable));
double horizontal = Math.sqrt(direction.x * direction.x + direction.z * direction.z);
if (direction.lengthSqr() < 1.0E-6D || horizontal < 1.0E-4D) continue;
float desiredYaw = (float) (Mth.atan2(-direction.x, direction.z) * Mth.RAD_TO_DEG);
float bodyYaw = Mth.rotLerp(partialTick, animatable.yRotO, animatable.getYRot());
float relativeYaw = Mth.clamp(Mth.wrapDegrees(desiredYaw - bodyYaw), -55.0F, 55.0F) * Mth.DEG_TO_RAD;
float pitch = Mth.clamp((float) -Mth.atan2(direction.y, horizontal) * Mth.RAD_TO_DEG,
-45.0F, 45.0F) * Mth.DEG_TO_RAD;
String[] chain = AIM_CHAINS[slot.ordinal()];
float yawPerBone = relativeYaw / chain.length;
float pitchPerBone = pitch / chain.length;
for (String boneName : chain) {
this.getBone(boneName).ifPresent(bone -> {
bone.setRotY(yawPerBone);
bone.setRotX(pitchPerBone);
});
}
}
}
@Nullable
@@ -3,9 +3,15 @@ package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.royal.RoyalMountEntity;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import software.bernie.geckolib.animation.AnimationState;
import software.bernie.geckolib.cache.object.GeoBone;
import software.bernie.geckolib.model.GeoModel;
public class RoyalMountModel extends GeoModel<RoyalMountEntity> {
private static final String[] HEADS = {"head_left", "head", "head_right"};
@Override
public ResourceLocation getModelResource(RoyalMountEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/" + animatable.geoNameForRender() + ".geo.json");
@@ -20,4 +26,22 @@ public class RoyalMountModel extends GeoModel<RoyalMountEntity> {
public ResourceLocation getAnimationResource(RoyalMountEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/" + animatable.geoNameForRender() + ".animation.json");
}
@Override
public void setCustomAnimations(RoyalMountEntity animatable, long instanceId,
AnimationState<RoyalMountEntity> animationState) {
super.setCustomAnimations(animatable, instanceId, animationState);
for (String head : HEADS) {
this.getBone(head).ifPresent(bone -> bone.setTrackingMatrices(true));
}
}
@Nullable
public Vec3 getTrackedBeamAnchor(int head) {
if (head < 0 || head >= HEADS.length) return null;
GeoBone bone = this.getBone(HEADS[head]).orElse(null);
if (bone == null || !bone.isTrackingMatrices()) return null;
org.joml.Vector3d position = bone.getWorldPosition();
return new Vec3(position.x, position.y, position.z);
}
}
@@ -0,0 +1,26 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.client.renderer.RenderStateShard;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.resources.ResourceLocation;
public class RoyalBeamRenderTypes extends RenderType {
public RoyalBeamRenderTypes(String name, VertexFormat format, VertexFormat.Mode mode, int bufferSize,
boolean affectsCrumbling, boolean sortOnUpload, Runnable setupState, Runnable clearState) {
super(name, format, mode, bufferSize, affectsCrumbling, sortOnUpload, setupState, clearState);
}
public static RenderType beam(ResourceLocation texture) {
return create("royal_beam", DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, true, true,
CompositeState.builder()
.setTextureState(new TextureStateShard(texture, false, false))
.setShaderState(RenderStateShard.RENDERTYPE_ENERGY_SWIRL_SHADER)
.setTransparencyState(RenderStateShard.TRANSLUCENT_TRANSPARENCY)
.setCullState(RenderStateShard.NO_CULL)
.setLightmapState(RenderStateShard.LIGHTMAP)
.setOutputState(RenderStateShard.ITEM_ENTITY_TARGET)
.createCompositeState(false));
}
}
@@ -25,22 +25,28 @@ import software.bernie.geckolib.util.Color;
public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
private static final ResourceLocation QUEEN_PURPLE_BEAM_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_purple_beam_outer.png");
private static final ResourceLocation QUEEN_PURPLE_BEAM_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_purple_beam_inner.png");
private static final ResourceLocation QUEEN_PURPLE_BEAM_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_purple_beam_end_1.png");
private static final ResourceLocation QUEEN_PURPLE_BEAM_END_1 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_purple_beam_end_1.png");
private static final ResourceLocation QUEEN_PURPLE_BEAM_END_2 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_purple_beam_end_2.png");
private static final ResourceLocation QUEEN_RED_BEAM_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_red_beam_outer.png");
private static final ResourceLocation QUEEN_RED_BEAM_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_red_beam_inner.png");
private static final ResourceLocation QUEEN_RED_BEAM_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_red_beam_end_1.png");
private static final ResourceLocation QUEEN_RED_BEAM_END_1 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_red_beam_end_1.png");
private static final ResourceLocation QUEEN_RED_BEAM_END_2 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_red_beam_end_2.png");
private static final ResourceLocation QUEEN_BLACK_BEAM_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_black_beam_outer.png");
private static final ResourceLocation QUEEN_BLACK_BEAM_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_black_beam_inner.png");
private static final ResourceLocation QUEEN_BLACK_BEAM_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_black_beam_end_1.png");
private static final ResourceLocation QUEEN_BLACK_BEAM_END_1 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_black_beam_end_1.png");
private static final ResourceLocation QUEEN_BLACK_BEAM_END_2 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_black_beam_end_2.png");
private static final ResourceLocation KING_FIRE_BEAM_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_outer.png");
private static final ResourceLocation KING_FIRE_BEAM_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_inner.png");
private static final ResourceLocation KING_FIRE_BEAM_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_end_1.png");
private static final ResourceLocation KING_FIRE_BEAM_END_1 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_end_1.png");
private static final ResourceLocation KING_FIRE_BEAM_END_2 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_end_2.png");
private static final ResourceLocation KING_LIGHTNING_BEAM_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/lightning_beam_outer.png");
private static final ResourceLocation KING_LIGHTNING_BEAM_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/lightning_beam_inner.png");
private static final ResourceLocation KING_LIGHTNING_BEAM_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/lightning_beam_end_1.png");
private static final ResourceLocation KING_LIGHTNING_BEAM_END_1 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/lightning_beam_end_1.png");
private static final ResourceLocation KING_LIGHTNING_BEAM_END_2 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/lightning_beam_end_2.png");
private static final ResourceLocation KING_ICE_BEAM_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/ice_beam_outer.png");
private static final ResourceLocation KING_ICE_BEAM_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/ice_beam_inner.png");
private static final ResourceLocation KING_ICE_BEAM_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/ice_beam_end_1.png");
private static final ResourceLocation KING_ICE_BEAM_END_1 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/ice_beam_end_1.png");
private static final ResourceLocation KING_ICE_BEAM_END_2 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/ice_beam_end_2.png");
public RoyalBossRenderer(EntityRendererProvider.Context context) {
super(context, new RoyalBossModel());
this.shadowRadius = 8.0F;
@@ -110,10 +116,8 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
this.shadowRadius = 8.0F * RoyalBossEntity.MODEL_RENDER_SCALE;
}
private static final float BEAM_OUTER_RADIUS = 0.55F;
private static final float BEAM_INNER_RADIUS = 0.32F;
private static final float BEAM_TILE_BLOCKS = 3.0F;
private static final float BEAM_SCROLL_SPEED = 0.32F;
private static final float BEAM_OUTER_RADIUS = 1.75F;
private static final float BEAM_INNER_RADIUS = 1.5F;
@Override
public void render(RoyalBossEntity entity, float entityYaw, float partialTick, PoseStack poseStack,
@@ -152,23 +156,23 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
ResourceLocation outer = QUEEN_PURPLE_BEAM_OUTER;
ResourceLocation inner = QUEEN_PURPLE_BEAM_INNER;
ResourceLocation endTexture = QUEEN_PURPLE_BEAM_END;
ResourceLocation[] endTextures = {QUEEN_PURPLE_BEAM_END_1, QUEEN_PURPLE_BEAM_END_2};
if (entity instanceof KingEntity) {
switch (entity.getRoyalBeamElement()) {
case FIRE -> {
outer = KING_FIRE_BEAM_OUTER;
inner = KING_FIRE_BEAM_INNER;
endTexture = KING_FIRE_BEAM_END;
endTextures = new ResourceLocation[]{KING_FIRE_BEAM_END_1, KING_FIRE_BEAM_END_2};
}
case LIGHTNING -> {
outer = KING_LIGHTNING_BEAM_OUTER;
inner = KING_LIGHTNING_BEAM_INNER;
endTexture = KING_LIGHTNING_BEAM_END;
endTextures = new ResourceLocation[]{KING_LIGHTNING_BEAM_END_1, KING_LIGHTNING_BEAM_END_2};
}
case ICE -> {
outer = KING_ICE_BEAM_OUTER;
inner = KING_ICE_BEAM_INNER;
endTexture = KING_ICE_BEAM_END;
endTextures = new ResourceLocation[]{KING_ICE_BEAM_END_1, KING_ICE_BEAM_END_2};
}
case GENERIC -> {
}
@@ -178,12 +182,12 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
case QUEEN_RED -> {
outer = QUEEN_RED_BEAM_OUTER;
inner = QUEEN_RED_BEAM_INNER;
endTexture = QUEEN_RED_BEAM_END;
endTextures = new ResourceLocation[]{QUEEN_RED_BEAM_END_1, QUEEN_RED_BEAM_END_2};
}
case QUEEN_BLACK -> {
outer = QUEEN_BLACK_BEAM_OUTER;
inner = QUEEN_BLACK_BEAM_INNER;
endTexture = QUEEN_BLACK_BEAM_END;
endTextures = new ResourceLocation[]{QUEEN_BLACK_BEAM_END_1, QUEEN_BLACK_BEAM_END_2};
}
default -> {
}
@@ -191,34 +195,53 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
}
float time = entity.tickCount + partialTick;
float tiles = (float) (length / BEAM_TILE_BLOCKS);
float scroll = -time * BEAM_SCROLL_SPEED;
float outerV = -time * 0.25F;
var pose = poseStack.last().pose();
VertexConsumer outerBuffer = bufferSource.getBuffer(RenderType.entityTranslucentEmissive(outer));
drawBeamPlane(outerBuffer, pose, start, finish, side1.scale(BEAM_OUTER_RADIUS), scroll, scroll + tiles);
drawBeamPlane(outerBuffer, pose, start, finish, side2.scale(BEAM_OUTER_RADIUS), scroll, scroll + tiles);
float innerV = -time * 0.25F * 0.5F;
VertexConsumer innerBuffer = bufferSource.getBuffer(RoyalBeamRenderTypes.beam(inner));
drawBeamTube(innerBuffer, pose, start, finish, side1, side2, BEAM_INNER_RADIUS, 4, innerV, 0.0F, 0.55F, 0.5F, 255);
float innerScroll = -time * BEAM_SCROLL_SPEED * 1.6F;
VertexConsumer innerBuffer = bufferSource.getBuffer(RenderType.entityTranslucentEmissive(inner));
drawBeamPlane(innerBuffer, pose, start, finish, side1.scale(BEAM_INNER_RADIUS), innerScroll, innerScroll + tiles);
drawBeamPlane(innerBuffer, pose, start, finish, side2.scale(BEAM_INNER_RADIUS), innerScroll, innerScroll + tiles);
VertexConsumer outerBuffer = bufferSource.getBuffer(RoyalBeamRenderTypes.beam(outer));
// Tremorzilla's outer shell stays fully visible all the way to the impact;
// fading the far ring makes the beam look like a translucent cone.
drawBeamTube(outerBuffer, pose, start, finish, side1, side2, BEAM_OUTER_RADIUS, 8, outerV, 0.0F, 0.55F, 0.15F, 255);
float impactSize = 1.1F + 0.35F * Mth.sin(time * 0.6F);
Vec3 camLeft = new Vec3(this.entityRenderDispatcher.camera.getLeftVector());
Vec3 camUp = new Vec3(this.entityRenderDispatcher.camera.getUpVector());
VertexConsumer endBuffer = bufferSource.getBuffer(RenderType.entityTranslucentEmissive(endTexture));
drawBillboard(endBuffer, pose, finish, camLeft.scale(impactSize), camUp.scale(impactSize));
float impactSize = 1.5F + 0.35F * Mth.sin(time * 0.6F);
ResourceLocation endTexture = endTextures[(entity.tickCount / 2) % endTextures.length];
VertexConsumer endBuffer = bufferSource.getBuffer(RoyalBeamRenderTypes.beam(endTexture));
drawBeamImpact(endBuffer, pose, finish.subtract(dir.scale(1.5D)), dir, side1, side2, impactSize);
}
private static void drawBeamPlane(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 start, Vec3 end, Vec3 half,
float startV, float endV) {
emitQuad(vertices, pose,
start.subtract(half), start.add(half), end.add(half), end.subtract(half),
0.0F, startV, 1.0F, endV);
emitQuad(vertices, pose,
start.add(half), start.subtract(half), end.subtract(half), end.add(half),
0.0F, startV, 1.0F, endV);
private static void drawBeamTube(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 start, Vec3 end,
Vec3 side1, Vec3 side2, float radius, int sections, float scroll, float phase,
float startScale, float uvLengthScale, int endAlpha) {
Vec3[] startRing = new Vec3[sections];
Vec3[] endRing = new Vec3[sections];
for (int i = 0; i < sections; i++) {
double angle = Math.PI * 2.0D * i / sections + phase;
Vec3 offset = side1.scale(Math.cos(angle) * radius).add(side2.scale(Math.sin(angle) * radius));
startRing[i] = start.add(offset.scale(startScale));
endRing[i] = end.add(offset);
}
float endV = scroll + (float) start.distanceTo(end) * uvLengthScale;
for (int i = 0; i < sections; i++) {
int next = (i + 1) % sections;
// Alex's beam renderer intentionally uses section indices for U rather
// than normalizing them. This is part of the authored 16x16 texture
// pattern and keeps the strip continuous around the tube.
emitBeamQuad(vertices, pose, startRing[i], endRing[i], endRing[next], startRing[next],
i, scroll, next, endV, endAlpha);
}
}
private static void emitBeamQuad(VertexConsumer vertices, org.joml.Matrix4f pose,
Vec3 a, Vec3 b, Vec3 c, Vec3 d,
float minU, float minV, float maxU, float maxV, int endAlpha) {
beamVertex(vertices, pose, a, minU, minV, 255);
beamVertex(vertices, pose, b, maxU, minV, endAlpha);
beamVertex(vertices, pose, c, maxU, maxV, endAlpha);
beamVertex(vertices, pose, d, minU, maxV, 255);
}
private static void drawBillboard(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 center, Vec3 left, Vec3 up) {
@@ -232,6 +255,17 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
0.0F, 0.0F, 1.0F, 1.0F);
}
private static void drawBeamImpact(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 center, Vec3 direction,
Vec3 side1, Vec3 side2, float size) {
// The end textures are atlas textures used by Tremorzilla's crossed flame
// planes, not a texture meant to be repeated on eight radial billboards.
// Two crossed planes preserve the same readable four-point impact without
// stretching the atlas into the noisy starburst the old code produced.
drawBillboard(vertices, pose, center, side1.scale(size), side2.scale(size));
drawBillboard(vertices, pose, center.subtract(direction.scale(size * 0.35D)),
side1.scale(size * 0.82D), direction.scale(size * 0.82D));
}
private static void emitQuad(VertexConsumer vertices, org.joml.Matrix4f pose,
Vec3 a, Vec3 b, Vec3 c, Vec3 d,
float minU, float minV, float maxU, float maxV) {
@@ -248,4 +282,12 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
.setLight(0x00F000F0)
.setNormal(0.0F, 1.0F, 0.0F);
}
private static void beamVertex(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 pos, float u, float v, int alpha) {
vertices.addVertex(pose, (float) pos.x, (float) pos.y, (float) pos.z)
.setColor(255, 255, 255, alpha).setUv(u, v)
.setOverlay(OverlayTexture.NO_OVERLAY)
.setLight(0x00F000F0)
.setNormal(0.0F, -1.0F, 0.0F);
}
}
@@ -19,16 +19,20 @@ import software.bernie.geckolib.renderer.GeoEntityRenderer;
public class RoyalMountRenderer extends GeoEntityRenderer<RoyalMountEntity> {
private static final ResourceLocation QUEEN_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_purple_beam_outer.png");
private static final ResourceLocation QUEEN_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_purple_beam_inner.png");
private static final ResourceLocation QUEEN_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_purple_beam_end_1.png");
private static final ResourceLocation QUEEN_END_1 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_purple_beam_end_1.png");
private static final ResourceLocation QUEEN_END_2 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_purple_beam_end_2.png");
private static final ResourceLocation KING_FIRE_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_outer.png");
private static final ResourceLocation KING_FIRE_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_inner.png");
private static final ResourceLocation KING_FIRE_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_end_1.png");
private static final ResourceLocation KING_FIRE_END_1 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_end_1.png");
private static final ResourceLocation KING_FIRE_END_2 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_end_2.png");
private static final ResourceLocation KING_LIGHTNING_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/lightning_beam_outer.png");
private static final ResourceLocation KING_LIGHTNING_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/lightning_beam_inner.png");
private static final ResourceLocation KING_LIGHTNING_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/lightning_beam_end_1.png");
private static final ResourceLocation KING_LIGHTNING_END_1 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/lightning_beam_end_1.png");
private static final ResourceLocation KING_LIGHTNING_END_2 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/lightning_beam_end_2.png");
private static final ResourceLocation KING_ICE_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/ice_beam_outer.png");
private static final ResourceLocation KING_ICE_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/ice_beam_inner.png");
private static final ResourceLocation KING_ICE_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/ice_beam_end_1.png");
private static final ResourceLocation KING_ICE_END_1 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/ice_beam_end_1.png");
private static final ResourceLocation KING_ICE_END_2 = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/ice_beam_end_2.png");
public RoyalMountRenderer(EntityRendererProvider.Context context) {
super(context, new RoyalMountModel());
this.shadowRadius = 1.1F;
@@ -58,7 +62,9 @@ public class RoyalMountRenderer extends GeoEntityRenderer<RoyalMountEntity> {
double x = Mth.lerp(partialTick, entity.xo, entity.getX());
double y = Mth.lerp(partialTick, entity.yo, entity.getY());
double z = Mth.lerp(partialTick, entity.zo, entity.getZ());
Vec3 start = entity.beamShootFrom().subtract(x, y, z);
int beamHead = entity.getBeamHead();
Vec3 trackedAnchor = ((RoyalMountModel) this.getGeoModel()).getTrackedBeamAnchor(beamHead);
Vec3 start = (trackedAnchor != null ? trackedAnchor : entity.beamShootFrom()).subtract(x, y, z);
Vec3 finish = end.subtract(x, y, z);
Vec3 axis = finish.subtract(start);
double length = axis.length();
@@ -69,39 +75,90 @@ public class RoyalMountRenderer extends GeoEntityRenderer<RoyalMountEntity> {
side = side.normalize();
ResourceLocation outer = QUEEN_OUTER;
ResourceLocation inner = QUEEN_INNER;
ResourceLocation endTexture = QUEEN_END;
ResourceLocation[] endTextures = {QUEEN_END_1, QUEEN_END_2};
if (entity instanceof PrinceEntity) {
switch (entity.getBeamElement()) {
case FIRE -> { outer = KING_FIRE_OUTER; inner = KING_FIRE_INNER; endTexture = KING_FIRE_END; }
case ICE -> { outer = KING_ICE_OUTER; inner = KING_ICE_INNER; endTexture = KING_ICE_END; }
default -> { outer = KING_LIGHTNING_OUTER; inner = KING_LIGHTNING_INNER; endTexture = KING_LIGHTNING_END; }
case FIRE -> { outer = KING_FIRE_OUTER; inner = KING_FIRE_INNER; endTextures = new ResourceLocation[]{KING_FIRE_END_1, KING_FIRE_END_2}; }
case ICE -> { outer = KING_ICE_OUTER; inner = KING_ICE_INNER; endTextures = new ResourceLocation[]{KING_ICE_END_1, KING_ICE_END_2}; }
default -> { outer = KING_LIGHTNING_OUTER; inner = KING_LIGHTNING_INNER; endTextures = new ResourceLocation[]{KING_LIGHTNING_END_1, KING_LIGHTNING_END_2}; }
}
}
float time = entity.tickCount + partialTick;
float tiles = (float) (length / 3.0D);
float outerV = -time * 0.25F;
org.joml.Matrix4f pose = poseStack.last().pose();
drawBeam(bufferSource.getBuffer(RenderType.entityTranslucentEmissive(outer)), pose, start, finish, side.scale(0.24D), -time * 0.32F, -time * 0.32F + tiles);
drawBeam(bufferSource.getBuffer(RenderType.entityTranslucentEmissive(inner)), pose, start, finish, side.scale(0.13D), -time * 0.5F, -time * 0.5F + tiles);
Vec3 up = new Vec3(this.entityRenderDispatcher.camera.getUpVector()).scale(0.55D);
Vec3 left = new Vec3(this.entityRenderDispatcher.camera.getLeftVector()).scale(0.55D);
drawQuad(bufferSource.getBuffer(RenderType.entityTranslucentEmissive(endTexture)), pose, finish.add(left).add(up), finish.subtract(left).add(up), finish.subtract(left).subtract(up), finish.add(left).subtract(up));
Vec3 side2 = dir.cross(side).normalize();
VertexConsumer outerBuffer = bufferSource.getBuffer(RoyalBeamRenderTypes.beam(outer));
drawBeamTube(outerBuffer, pose, start, finish, side, side2, 0.44F, 8, outerV, 0.0F, 0.55F, 0.15F, 0);
float innerV = -time * 0.25F * 0.5F;
VertexConsumer innerBuffer = bufferSource.getBuffer(RoyalBeamRenderTypes.beam(inner));
drawBeamTube(innerBuffer, pose, start, finish, side, side2, 0.375F, 4, innerV, 1.0F, 0.55F, 0.5F, 255);
float impactSize = 0.375F + 0.09F * Mth.sin(time * 0.6F);
ResourceLocation endTexture = endTextures[(entity.tickCount / 2) % endTextures.length];
VertexConsumer endBuffer = bufferSource.getBuffer(RoyalBeamRenderTypes.beam(endTexture));
drawBeamImpact(endBuffer, pose, finish.subtract(dir.scale(0.375D)), dir, side, side2, impactSize);
}
private static void drawBeam(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 start, Vec3 end, Vec3 half, float startV, float endV) {
drawQuad(vertices, pose, start.subtract(half), start.add(half), end.add(half), end.subtract(half), startV, endV);
drawQuad(vertices, pose, start.add(half), start.subtract(half), end.subtract(half), end.add(half), startV, endV);
private static void drawBeamTube(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 start, Vec3 end,
Vec3 side1, Vec3 side2, float radius, int sections, float scroll, float phase,
float startScale, float uvLengthScale, int endAlpha) {
Vec3[] startRing = new Vec3[sections];
Vec3[] endRing = new Vec3[sections];
for (int i = 0; i < sections; i++) {
double angle = Math.PI * 2.0D * i / sections + phase;
Vec3 offset = side1.scale(Math.cos(angle) * radius).add(side2.scale(Math.sin(angle) * radius));
startRing[i] = start.add(offset.scale(startScale));
endRing[i] = end.add(offset);
}
float endV = scroll + (float) start.distanceTo(end) * uvLengthScale;
for (int i = 0; i < sections; i++) {
int next = (i + 1) % sections;
emitBeamQuad(vertices, pose, startRing[i], endRing[i], endRing[next], startRing[next],
i / (float) sections, scroll, next / (float) sections, endV, endAlpha);
}
}
private static void drawQuad(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 a, Vec3 b, Vec3 c, Vec3 d) {
drawQuad(vertices, pose, a, b, c, d, 0.0F, 1.0F);
private static void emitBeamQuad(VertexConsumer vertices, org.joml.Matrix4f pose,
Vec3 a, Vec3 b, Vec3 c, Vec3 d,
float minU, float minV, float maxU, float maxV, int endAlpha) {
beamVertex(vertices, pose, a, minU, minV, 255);
beamVertex(vertices, pose, b, maxU, minV, endAlpha);
beamVertex(vertices, pose, c, maxU, maxV, endAlpha);
beamVertex(vertices, pose, d, minU, maxV, 255);
}
private static void drawQuad(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 a, Vec3 b, Vec3 c, Vec3 d, float startV, float endV) {
vertex(vertices, pose, a, 0.0F, startV); vertex(vertices, pose, b, 1.0F, startV); vertex(vertices, pose, c, 1.0F, endV); vertex(vertices, pose, d, 0.0F, endV);
private static void drawBeamImpact(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 center, Vec3 direction,
Vec3 side1, Vec3 side2, float size) {
drawBillboard(vertices, pose, center, side1.scale(size), side2.scale(size));
for (int i = 0; i < 8; i++) {
double angle = (i + 0.5D) * Math.PI * 0.25D;
Vec3 radial = side1.scale(Math.cos(angle)).add(side2.scale(Math.sin(angle))).scale(size);
Vec3 back = direction.scale(size * (i % 2 == 0 ? 1.5D : 1.0D));
emitQuad(vertices, pose, center.add(radial), center.subtract(radial),
center.subtract(radial).subtract(back), center.add(radial).subtract(back));
}
}
private static void drawBillboard(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 center, Vec3 left, Vec3 up) {
emitQuad(vertices, pose, center.add(left).add(up), center.subtract(left).add(up),
center.subtract(left).subtract(up), center.add(left).subtract(up));
emitQuad(vertices, pose, center.subtract(left).add(up), center.add(left).add(up),
center.add(left).subtract(up), center.subtract(left).subtract(up));
}
private static void emitQuad(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 a, Vec3 b, Vec3 c, Vec3 d) {
vertex(vertices, pose, a, 0.0F, 0.0F);
vertex(vertices, pose, b, 1.0F, 0.0F);
vertex(vertices, pose, c, 1.0F, 1.0F);
vertex(vertices, pose, d, 0.0F, 1.0F);
}
private static void vertex(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 pos, float u, float v) {
vertices.addVertex(pose, (float) pos.x, (float) pos.y, (float) pos.z).setColor(255, 255, 255, 255).setUv(u, v)
.setOverlay(net.minecraft.client.renderer.texture.OverlayTexture.NO_OVERLAY).setLight(0x00F000F0).setNormal(0.0F, 1.0F, 0.0F);
}
private static void beamVertex(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 pos, float u, float v, int alpha) {
vertices.addVertex(pose, (float) pos.x, (float) pos.y, (float) pos.z).setColor(255, 255, 255, alpha).setUv(u, v)
.setOverlay(net.minecraft.client.renderer.texture.OverlayTexture.NO_OVERLAY).setLight(0x00F000F0).setNormal(0.0F, -1.0F, 0.0F);
}
}
@@ -2,6 +2,7 @@ package com.craisinlord.antarchy.content.entity.ant;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.compat.infinity.InfinityCompat;
import com.craisinlord.antarchy.compat.infinity.InfinityWarpResult;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.AntarchyTags;
import com.craisinlord.antarchy.content.portal.RainbowPortalIgniter;
@@ -62,7 +63,8 @@ public class RainbowAntEntity extends BaseAntEntity implements GeoEntity {
return AntTeleportHelper.teleportPlayerToDimension(player, AntarchySettings.rainbowAntNonInfinityFallbackDimension());
}
if (!InfinityCompat.get().requestWarp(player, dimensionId)) {
InfinityWarpResult result = InfinityCompat.get().requestWarp(player, dimensionId);
if (result == InfinityWarpResult.REJECTED) {
player.displayClientMessage(Component.translatable("message.antarchy.rainbow_ant_failed_dimension_create"), true);
return InteractionResult.CONSUME;
}
@@ -356,9 +358,13 @@ public class RainbowAntEntity extends BaseAntEntity implements GeoEntity {
}
private boolean teleportToInfinity(ServerPlayer player, ResourceLocation dimensionId) {
if (!InfinityCompat.get().requestWarp(player, dimensionId)) {
InfinityWarpResult result = InfinityCompat.get().requestWarp(player, dimensionId);
if (result == InfinityWarpResult.FAILED_GENERATION) {
this.deleteGeneratedArtifacts(player.server, dimensionId);
this.markForRerollOnNextReagent();
player.displayClientMessage(Component.translatable("message.antarchy.rainbow_ant_failed_dimension_create"), true);
return false;
}
if (result == InfinityWarpResult.REJECTED) {
player.displayClientMessage(Component.translatable("message.antarchy.rainbow_ant_failed_dimension_create"), true);
return false;
}
@@ -377,10 +383,8 @@ public class RainbowAntEntity extends BaseAntEntity implements GeoEntity {
.resolve(dimensionId.getPath());
this.deletePathRecursively(datapackPath);
if (dimensionPath != null) {
this.deletePathRecursively(dimensionPath);
}
}
private void deletePathRecursively(Path path) {
if (!Files.exists(path)) {
@@ -33,6 +33,7 @@ import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import software.bernie.geckolib.animatable.GeoEntity;
@@ -75,6 +76,8 @@ public class LucidEntity extends Monster implements GeoEntity {
private static final double MIN_HOVER_RANGE = 6.5D;
private static final double CLOSE_RANGE = 4.5D;
private static final double DEFAULT_HOVER_HEIGHT = 2.75D;
private static final double NATURAL_SPAWN_LIMIT_RADIUS = 64.0D;
private static final int NATURAL_SPAWN_LIMIT = 5;
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
private static final RawAnimation FLY_ANIM = RawAnimation.begin().thenLoop("fly");
@@ -118,6 +121,7 @@ public class LucidEntity extends Monster implements GeoEntity {
return level.getDifficulty() != Difficulty.PEACEFUL;
}
return level.getDifficulty() != Difficulty.PEACEFUL
&& level.getEntitiesOfClass(LucidEntity.class, new AABB(pos).inflate(NATURAL_SPAWN_LIMIT_RADIUS), lucid -> lucid.isAlive()).size() < NATURAL_SPAWN_LIMIT
&& pos.getY() <= 250
&& level.isEmptyBlock(pos)
&& level.isEmptyBlock(pos.above())
@@ -571,6 +575,3 @@ public class LucidEntity extends Monster implements GeoEntity {
}
@@ -1,6 +1,5 @@
package com.craisinlord.antarchy.content.entity.portal;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.AntarchySoundEvents;
@@ -181,13 +180,6 @@ public class DimensionalTearEntity extends Entity implements GeoEntity {
DimensionalTearEntity linked = this.findLinkedTear();
if (linked == null || !linked.isAlive()) {
Antarchy.LOGGER.warn(
"[antarchy-dimensional-tear] discarding unlinked tear uuid={} pos=({}, {}, {}) dim={} linkedTearId={} fallback=({}, {}, {}) ageTicks={} lifetimeTicks={}",
this.getUUID(), this.getX(), this.getY(), this.getZ(), this.level().dimension().location(),
this.linkedTearId,
this.linkedFallbackPos.x, this.linkedFallbackPos.y, this.linkedFallbackPos.z,
this.ageTicks, this.lifetimeTicks
);
this.discard();
return;
}
@@ -360,7 +352,6 @@ public class DimensionalTearEntity extends Entity implements GeoEntity {
private void teleportEntity(Entity entity, DimensionalTearEntity destination) {
Vec3 motion = entity.getDeltaMovement();
Vec3 startPos = entity.position();
Vec3 exitPos = destination.exitPosition();
TELEPORT_COOLDOWNS.put(entity.getUUID(), this.level().getGameTime() + TELEPORT_COOLDOWN_TICKS);
@@ -374,13 +365,6 @@ public class DimensionalTearEntity extends Entity implements GeoEntity {
entity.hasImpulse = true;
if (entity instanceof LivingEntity living) {
int invertedDuration = AntarchySettings.dimensionalTearInvertedDurationTicks();
Antarchy.LOGGER.debug(
"[antarchy-dimensional-tear] applying inverted effect targetType={} uuid={} fromTear={} toTear={} startPos=({}, {}, {}) exitPos=({}, {}, {}) dim={} durationTicks={}",
living.getType(), living.getUUID(), this.getUUID(), destination.getUUID(),
startPos.x, startPos.y, startPos.z,
exitPos.x, exitPos.y, exitPos.z,
this.level().dimension().location(), invertedDuration
);
living.addEffect(new MobEffectInstance(AntarchyObjects.INVERTED_EFFECT.get(), invertedDuration, 0));
}
this.level().playSound(null, this.blockPosition(), SoundEvents.ENDERMAN_TELEPORT, SoundSource.NEUTRAL, 0.7F, 0.65F + this.random.nextFloat() * 0.2F);
@@ -550,16 +534,6 @@ public class DimensionalTearEntity extends Entity implements GeoEntity {
this.queenManticoreCount = tag.getInt("QueenManticoreCount");
this.queenManticoreSpawned = tag.getBoolean("QueenManticoreSpawned");
}
if (!this.level().isClientSide) {
Antarchy.LOGGER.info(
"[antarchy-dimensional-tear] loaded tear uuid={} pos=({}, {}, {}) dim={} linkedTearId={} fallback=({}, {}, {}) ageTicks={} lifetimeTicks={} eventTicks={} nextEventTicks={} pendingEvent={} queenOwner={} queenManticoreCount={} queenManticoreSpawned={}",
this.getUUID(), this.getX(), this.getY(), this.getZ(), this.level().dimension().location(),
this.linkedTearId,
this.linkedFallbackPos.x, this.linkedFallbackPos.y, this.linkedFallbackPos.z,
this.ageTicks, this.lifetimeTicks, this.eventTicks, this.nextEventTicks, this.pendingEvent,
this.queenOwnerId, this.queenManticoreCount, this.queenManticoreSpawned
);
}
}
@Override
@@ -114,6 +114,7 @@ public class KingEntity extends RoyalBossEntity {
@Nullable
private ServerPlayer exileTarget;
private int exileTicks;
private boolean exileWingAnimationPending;
@Nullable
private ServerPlayer titheTarget;
private int titheTicks;
@@ -364,6 +365,7 @@ public class KingEntity extends RoyalBossEntity {
return;
}
this.tickRoyalPunishment();
this.tickPendingExileAnimation();
long gameTime = this.level().getGameTime();
this.judgmentCooldowns.entrySet().removeIf(entry -> entry.getValue() <= gameTime);
this.lastPlayerDamageTime.entrySet().removeIf(entry -> gameTime - entry.getValue() > 600L);
@@ -489,8 +491,25 @@ public class KingEntity extends RoyalBossEntity {
away = away.normalize();
this.exileTarget.setDeltaMovement(away.x * 2.6D, 1.35D, away.z * 2.6D);
this.exileTarget.hasImpulse = true;
this.triggerAnim("wing_action", "wing_gust");
this.playRoyalSound(AntarchySoundEvents.KING_WING_FLAP.get(), 0.82F);
this.exileWingAnimationPending = true;
}
}
private void tickPendingExileAnimation() {
if (!this.exileWingAnimationPending
|| !this.attackScheduler.ready("exile_wing_animation", RoyalAttackLane.BODY)) {
return;
}
if (this.beginRoyalAttack("exile_wing_animation", RoyalAttackLane.BODY, 1, 0, 1,
this.animationRecovery(55, 0, 1, 0), new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
@Override
public void onStart() {
KingEntity.this.exileWingAnimationPending = false;
KingEntity.this.triggerAnim("wing_action", "wing_gust");
}
})) {
this.exileWingAnimationPending = false;
}
}
@@ -551,6 +570,7 @@ public class KingEntity extends RoyalBossEntity {
}
this.exileTarget = null;
this.exileTicks = 0;
this.exileWingAnimationPending = false;
}
private void clearTithe() {
@@ -763,7 +783,7 @@ public class KingEntity extends RoyalBossEntity {
} else if (this.attackScheduler.ready("wing_gust", RoyalAttackLane.BODY)
&& distance <= WING_GUST_RADIUS && (forceFar || this.random.nextInt(3) == 0)
&& this.beginRoyalAttack("wing_gust", RoyalAttackLane.BODY, WING_GUST_COOLDOWN_TICKS,
WING_GUST_WINDUP_TICKS, 1, 16, new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
WING_GUST_WINDUP_TICKS, 1, this.animationRecovery(55, WING_GUST_WINDUP_TICKS, 1, 16), new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
@Override public void onStart() {
KingEntity.this.triggerAnim("wing_action", "wing_gust");
KingEntity.this.playRoyalSound(AntarchySoundEvents.KING_WING_FLAP.get(), 0.85F);
@@ -777,7 +797,8 @@ public class KingEntity extends RoyalBossEntity {
&& (forceFar || this.random.nextInt(4) == 0)
&& this.beginRoyalAttack("royal_muster", RoyalAttackLane.BODY,
AntarchySettings.kingRoyalMusterCooldownTicks(),
AntarchySettings.kingRoyalMusterWindupTicks(), 1, 20,
AntarchySettings.kingRoyalMusterWindupTicks(), 1,
this.animationRecovery(59, AntarchySettings.kingRoyalMusterWindupTicks(), 1, 20),
new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
@Override public void onStart() {
KingEntity.this.triggerAnim("body_action", "minion_spawn");
@@ -971,6 +992,15 @@ public class KingEntity extends RoyalBossEntity {
}
private void tickDecree(ServerLevel level, LivingEntity target) {
if (!(target instanceof ServerPlayer player) || !target.isAlive() || target.level() != level) {
if (this.activeDecree != null) {
this.endDecree(target);
}
this.activeDecree = null;
this.activeDecreeTicks = 0;
this.decreeRetreatPressure = false;
return;
}
if (this.activeDecree == null) {
if (this.decreeCooldownTicks-- > 0) {
return;
@@ -985,7 +1015,7 @@ public class KingEntity extends RoyalBossEntity {
this.playRoyalSound(AntarchySoundEvents.KING_DECREE_CAST.get(), 0.9F + this.random.nextFloat() * 0.15F);
this.playRoyalSound(AntarchySoundEvents.KING_ROAR.get(), 0.8F + this.random.nextFloat() * 0.12F);
this.projectRoyalSound(AntarchySoundEvents.KING_DECREE.get(), 4.0F, 1.0F, target);
if (target instanceof ServerPlayer player) this.sendDecreeTitle(player);
this.sendDecreeTitle(player);
}
int countdown = this.activeDecree.countdownTicks(target);
if (countdown > 0 && countdown <= 100 && this.tickCount % 20 == 0) {
@@ -76,6 +76,7 @@ public class QueenEntity extends RoyalBossEntity {
private int blackHoleCooldownTicks;
private final int[] dreamFireballCooldownTicks = new int[3];
private int idleWanderCooldownTicks;
private boolean manticoreAnimationPending;
private final RoyalEffectController royalEffects = new RoyalEffectController();
private final Map<UUID, Vec3> frozenVelocities = new HashMap<>();
private long naturalTrailSiteId = Long.MIN_VALUE;
@@ -229,6 +230,7 @@ public class QueenEntity extends RoyalBossEntity {
this.tickIdleWander();
}
this.tickManticoreSummon();
this.tickPendingManticoreAnimation();
this.tickQueenAbilities();
this.tickDreamFireballs();
this.tickFinalAcceleration();
@@ -370,13 +372,30 @@ public class QueenEntity extends RoyalBossEntity {
? this.cooldown(Math.max(20, AntarchySettings.queenManticoreSummonCooldownTicks()))
: FAILED_SUMMON_RETRY_TICKS;
if (spawned > 0) {
this.triggerAnim("body_action", "minion_spawn");
this.manticoreAnimationPending = true;
this.playRoyalSound(AntarchySoundEvents.QUEEN_ROAR.get(), 0.8F + this.random.nextFloat() * 0.12F);
serverLevel.sendParticles(ParticleTypes.PORTAL, this.getX(), this.getY() + 2.0D, this.getZ(),
36, 3.0D, 2.0D, 3.0D, 0.15D);
}
}
private void tickPendingManticoreAnimation() {
if (!this.manticoreAnimationPending
|| !this.attackScheduler.ready("manticore_summon_animation", RoyalAttackLane.BODY)) {
return;
}
if (this.beginRoyalAttack("manticore_summon_animation", RoyalAttackLane.BODY, 1, 0, 1,
this.animationRecovery(59, 0, 1, 0),
new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
@Override public void onStart() {
QueenEntity.this.manticoreAnimationPending = false;
QueenEntity.this.triggerAnim("body_action", "minion_spawn");
}
})) {
this.manticoreAnimationPending = false;
}
}
private int spawnManticoreTears(ServerLevel level, LivingEntity target, int count) {
int pairs = Math.max(1, Math.min(3, (count + 1) / 2));
int created = 0;
@@ -387,18 +406,26 @@ public class QueenEntity extends RoyalBossEntity {
towardTarget = towardTarget.normalize();
Vec3 behindTarget = target.position().add(towardTarget.scale(8.0D));
Vec3 lateral = new Vec3(-towardTarget.z, 0.0D, towardTarget.x);
float tearYaw = (float) Math.toDegrees(Math.atan2(-towardTarget.x, towardTarget.z));
double vertical = AntarchyGravityApi.isGravityInverted(this) ? -2.0D : 2.0D;
for (int i = 0; i < pairs; i++) {
double angle = this.random.nextDouble() * Mth.TWO_PI;
double distance = Math.max(8.0D, AntarchySettings.queenManticoreSummonRange() * 0.65D);
double spread = (i - (pairs - 1) * 0.5D) * 5.0D;
Vec3 pairCenter = behindTarget.add(lateral.scale(spread)).add(0.0D, vertical, 0.0D);
Vec3 firstPos = pairCenter.add(lateral.scale(3.0D));
Vec3 secondPos = pairCenter.add(lateral.scale(-3.0D));
double forwardScatter = 3.0D + this.random.nextDouble() * 9.0D;
double lateralScatter = (this.random.nextDouble() * 2.0D - 1.0D) * 11.0D;
double heightScatter = (this.random.nextDouble() * 2.0D - 1.0D) * 3.0D;
Vec3 pairCenter = behindTarget
.add(towardTarget.scale(forwardScatter))
.add(lateral.scale(lateralScatter))
.add(0.0D, vertical + heightScatter, 0.0D);
double pairAngle = this.random.nextDouble() * Mth.TWO_PI;
Vec3 pairDirection = towardTarget.scale(Math.cos(pairAngle))
.add(lateral.scale(Math.sin(pairAngle)));
double pairSeparation = 3.5D + this.random.nextDouble() * 3.0D;
Vec3 firstPos = pairCenter.add(pairDirection.scale(pairSeparation));
Vec3 secondPos = pairCenter.add(pairDirection.scale(-pairSeparation));
DimensionalTearEntity first = DimensionalTearEntity.createQueenManticoreTear(level, firstPos,
(float) Math.toDegrees(angle), 240, this.getUUID(), Math.min(3, count));
tearYaw, 240, this.getUUID(), Math.min(3, count));
DimensionalTearEntity second = DimensionalTearEntity.createQueenManticoreTear(level, secondPos,
(float) Math.toDegrees(angle + Math.PI), 240, this.getUUID(), Math.min(3, count));
tearYaw, 240, this.getUUID(), Math.min(3, count));
first.linkTo(second);
second.linkTo(first);
level.addFreshEntity(first);
@@ -446,8 +473,12 @@ public class QueenEntity extends RoyalBossEntity {
default -> ACCELERATION_COOLDOWN;
};
RoyalAttackLane lane = "black_hole".equals(selected) ? RoyalAttackLane.CENTER_HEAD : RoyalAttackLane.HAZARD;
int actionWindup = 10;
int actionRecovery = "momentum_lock".equals(selected)
? this.animationRecovery(55, actionWindup, 1, 14)
: this.animationRecovery(25, actionWindup, 1, 14);
if (!this.beginRoyalAttack(selected, lane, this.cooldown(cooldown),
10, 1, 14, new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
actionWindup, 1, actionRecovery, new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
@Override public void onStart() {
if ("gravity_stomp".equals(selected)) {
QueenEntity.this.triggerAnim("body_action", "stomp");
@@ -93,6 +93,10 @@ public class RoyalBoltEntity extends AbstractHurtingProjectile {
if (target == owner || (owner != null && target == owner.getVehicle())) {
return;
}
if (owner instanceof RoyalMountEntity royal && target instanceof RoyalMountEntity other
&& royal.isTame() && other.isTame()) {
return;
}
float damage = (float) AntarchySettings.royalBoltDamage();
target.hurt(this.damageSources().mobProjectile(this, owner instanceof LivingEntity le ? le : null), damage);
if (target instanceof LivingEntity living) {
@@ -64,7 +64,7 @@ import software.bernie.geckolib.util.GeckoLibUtil;
public abstract class RoyalBossEntity extends Monster implements GeoEntity, MultipartEntityOwner {
public static final float MODEL_RENDER_SCALE = 2.0F;
public static final float GAMEPLAY_WIDTH = 30.0F;
public static final float GAMEPLAY_WIDTH = 28.0F;
public static final float GAMEPLAY_HEIGHT = 15.0F;
public enum Phase {
@@ -515,6 +515,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
}
controller.tick(
this.beamAnchor(head),
this.beamDirection(head),
beamTarget,
this.royalBeamSettings(),
this.royalBeamTerrainMode(head),
@@ -535,7 +536,8 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
if (!head.readyToAttack() || this.attackScheduler.laneBusy(this.headLane(head))
|| target == null || !this.canAttack(target)
|| this.distanceTo(target) < this.royalBeamMinimumRange()
|| this.headWithinBiteReach(head, target)) {
|| this.headWithinBiteReach(head, target)
|| !this.targetInBeamLine(head, target)) {
continue;
}
RoyalBeamSettings beamSettings = this.royalBeamSettings();
@@ -588,7 +590,6 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
int index = head.slot().ordinal();
head.setBeamActive(false);
head.stopShoot();
this.stopTriggeredAnim(head.slot().controllerName(), null);
this.beamControllers[index].stop();
this.entityData.set(BEAM_ACTIVE[index], false);
this.entityData.set(BEAM_ELEMENT[index], RoyalBeamElement.GENERIC.ordinal());
@@ -656,7 +657,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
? new Vec3(-dx / horizontalDistance, 0.0D, -dz / horizontalDistance)
: this.getViewVector(1.0F).multiply(-1.0D, 0.0D, -1.0D).normalize();
double standoff = Math.max(this.getBbWidth() * 0.55D,
BEAM_MUZZLE_FORWARD - this.biteReach() * 0.65D);
BEAM_MUZZLE_FORWARD - this.biteReach() * 0.65D + 1.0D);
Vec3 wanted = target.position().add(awayFromTarget.scale(standoff));
boolean atStandoff = this.position().multiply(1.0D, 0.0D, 1.0D)
.distanceToSqr(wanted.multiply(1.0D, 0.0D, 1.0D)) <= 4.0D;
@@ -827,6 +828,10 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
return this.attackScheduler.start(id, lane, cooldownTicks, windupTicks, activeTicks, protectedRecovery, action);
}
protected int animationRecovery(int animationTicks, int windupTicks, int activeTicks, int recoveryTicks) {
return Math.max(recoveryTicks, animationTicks - Math.max(0, windupTicks) - Math.max(1, activeTicks));
}
private void applyBiteHit(RoyalHead head) {
if (this.level().isClientSide) {
return;
@@ -889,6 +894,26 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
return beamAnchor(head.slot(), this.getX(), this.getY(), this.getZ(), this.getYRot());
}
protected Vec3 beamDirection(RoyalHead head) {
float yaw = this.getYRot() * Mth.DEG_TO_RAD;
Vec3 localDirection = new Vec3(-Math.sin(yaw), 0.0D, Math.cos(yaw));
return AntarchyGravityRotationUtil.vecPlayerToWorld(localDirection,
AntarchyGravityApi.getGravityDirection(this)).normalize();
}
private boolean targetInBeamLine(RoyalHead head, LivingEntity target) {
Vec3 origin = this.beamAnchor(head);
Vec3 direction = this.beamDirection(head);
Vec3 toTarget = target.getEyePosition().subtract(origin);
double forwardDistance = toTarget.dot(direction);
if (forwardDistance <= 0.0D) {
return false;
}
Vec3 perpendicular = toTarget.subtract(direction.scale(forwardDistance));
double tolerance = Math.max(1.5D, target.getBbWidth() * 1.5D);
return perpendicular.lengthSqr() <= tolerance * tolerance;
}
private Vec3 beamAnchor(RoyalHead.Slot slot, double x, double y, double z, float yaw) {
double yawRadians = yaw * Mth.DEG_TO_RAD;
Vec3 forward = new Vec3(-Math.sin(yawRadians), 0.0D, Math.cos(yawRadians));
@@ -936,6 +961,9 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
this.setRoyalFlying(false);
this.getNavigation().stop();
this.setDeltaMovement(Vec3.ZERO);
this.setXRot(0.0F);
this.setYHeadRot(this.getYRot());
this.yBodyRot = this.getYRot();
}
super.die(damageSource);
}
@@ -967,6 +995,9 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
protected void tickDeath() {
this.deathTime++;
this.setNoGravity(false);
this.setXRot(0.0F);
this.setYHeadRot(this.getYRot());
this.yBodyRot = this.getYRot();
Vec3 movement = this.getDeltaMovement();
if (this.onGround()) {
this.setDeltaMovement(movement.x * 0.6D, 0.0D, movement.z * 0.6D);
@@ -445,6 +445,11 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
return;
}
LivingEntity target = this.getTarget();
if (target != null && !this.canAttack(target)) {
this.setTarget(null);
}
if (this.spitCooldown > 0) {
this.spitCooldown--;
}
@@ -625,11 +630,17 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
if (target == null && this.getControllingPassenger() instanceof Player) {
target = this.frontTarget();
}
if (target != null && target.distanceTo(this) < 5.0D) {
if (target != null && this.canAttack(target) && target.distanceTo(this) < 5.0D) {
target.hurt(this.damageSources().mobAttack(this), (float) this.getAttributeValue(Attributes.ATTACK_DAMAGE));
}
}
@Override
public boolean canAttack(LivingEntity target) {
return !(target instanceof RoyalMountEntity other && this.isTame() && other.isTame())
&& super.canAttack(target);
}
@Nullable
private LivingEntity frontTarget() {
Vec3 look = this.getLookAngle();
@@ -640,6 +651,9 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit
if (candidate == this || candidate == this.getControllingPassenger() || candidate == this.getOwner()) {
continue;
}
if (!this.canAttack(candidate)) {
continue;
}
Vec3 to = candidate.getEyePosition().subtract(eye);
double dist = to.length();
if (dist > 6.0D || dist < 1.0E-3D) {
@@ -17,7 +17,7 @@ public class RoyalMountSpitGoal extends Goal {
return false;
}
LivingEntity target = this.mount.getTarget();
if (target == null || !target.isAlive()) {
if (target == null || !target.isAlive() || !this.mount.canAttack(target)) {
return false;
}
double distance = this.mount.distanceTo(target);
@@ -32,7 +32,7 @@ public class RoyalMountSpitGoal extends Goal {
@Override
public void tick() {
LivingEntity target = this.mount.getTarget();
if (target == null) {
if (target == null || !this.mount.canAttack(target)) {
return;
}
this.mount.getLookControl().setLookAt(target, 30.0F, 30.0F);
@@ -77,6 +77,17 @@ public final class RoyalBeamController {
RoyalBeamSettings settings,
RoyalBeamTerrainMode terrainMode,
Consumer<@Nullable Vec3> syncedEndPosition
) {
this.tick(shootFrom, owner.getLookAngle(), target, settings, terrainMode, syncedEndPosition);
}
public void tick(
Vec3 shootFrom,
Vec3 shootDirection,
@Nullable LivingEntity target,
RoyalBeamSettings settings,
RoyalBeamTerrainMode terrainMode,
Consumer<@Nullable Vec3> syncedEndPosition
) {
if (this.beamTicks <= 0) {
syncedEndPosition.accept(null);
@@ -100,11 +111,11 @@ public final class RoyalBeamController {
return;
}
Vec3 direction = this.serverTarget.subtract(shootFrom).normalize();
if (direction.lengthSqr() < 1.0E-7D) {
direction = this.owner.getLookAngle();
}
double committedDistance = Math.min(settings.range(), shootFrom.distanceTo(this.serverTarget));
Vec3 direction = shootDirection.lengthSqr() < 1.0E-7D
? this.owner.getLookAngle().normalize()
: shootDirection.normalize();
double committedDistance = Math.min(settings.range(), Math.max(settings.pathStep(),
this.serverTarget.subtract(shootFrom).dot(direction)));
double travelProgress = Mth.clamp(this.beamAgeTicks / (double) settings.travelTicks(), 0.0D, 1.0D);
double currentRange = Math.max(settings.pathStep(), committedDistance * travelProgress);
Vec3 clipEnd = shootFrom.add(direction.scale(currentRange));
@@ -106,7 +106,6 @@ public class WindVortexEntity extends Entity {
public WindVortexEntity(EntityType<? extends WindVortexEntity> entityType, Level level) {
super(entityType, level);
this.noCulling = true;
}
public static WindVortexEntity create(Level level, EntityType<? extends WindVortexEntity> type, Vec3 position,
@@ -379,12 +378,6 @@ public class WindVortexEntity extends Entity {
return;
}
for (ServerPlayer player : serverLevel.players()) {
if (area.intersects(player.getBoundingBox())) {
this.captureEntity(player, height, basis, mode);
}
}
Iterator<Map.Entry<UUID, Double>> iterator = this.carriedProgress.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<UUID, Double> entry = iterator.next();
@@ -62,6 +62,11 @@ public final class TimeDilationApi {
return getRate(entity) < TimeDilationMath.NORMAL_RATE;
}
public static double getVehicleRate(Entity entity) {
Entity vehicle = entity.getVehicle();
return vehicle == null ? TimeDilationMath.NORMAL_RATE : getRate(vehicle);
}
public static void enterRotationBypass() {
ROTATION_BYPASS_DEPTH.set(ROTATION_BYPASS_DEPTH.get() + 1);
}
@@ -112,6 +117,10 @@ public final class TimeDilationApi {
SYNCED_CLIENT_RATES.clear();
}
public static boolean hasSyncedClientRates() {
return !SYNCED_CLIENT_RATES.isEmpty();
}
public static void syncEntityRate(Entity entity, double rate) {
syncDispatcher.accept(entity, TimeDilationMath.clampRate(rate));
}
@@ -114,6 +114,7 @@ public class TimeDilationFieldEntity extends Entity {
if (this.level().isClientSide) {
return;
}
TimeDilationManager.registerActiveField(this);
if (this.anchorId != null && this.level() instanceof ServerLevel level) {
Entity anchor = level.getEntity(this.anchorId);
if (anchor != null && anchor.isAlive()) {
@@ -19,14 +19,29 @@ import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
public final class TimeDilationManager {
private static final Map<ServerLevel, TrackingState> TRACKING = new WeakHashMap<>();
private static final Map<ServerLevel, Set<TimeDilationFieldEntity>> ACTIVE_FIELDS = new WeakHashMap<>();
private TimeDilationManager() {
}
public static void tickServer(MinecraftServer server) {
for (ServerLevel level : server.getAllLevels()) {
List<TimeDilationFieldEntity> fields = collectFields(level);
TrackingState tracking = TRACKING.computeIfAbsent(level, ignored -> new TrackingState());
Set<TimeDilationFieldEntity> activeFields = ACTIVE_FIELDS.get(level);
if (activeFields != null) {
activeFields.removeIf(field -> !field.isAlive() || field.isRemoved());
if (activeFields.isEmpty()) {
ACTIVE_FIELDS.remove(level);
activeFields = null;
}
}
TrackingState tracking = TRACKING.get(level);
if (activeFields == null && (tracking == null || tracking.entities.isEmpty())) {
continue;
}
List<TimeDilationFieldEntity> fields = activeFields == null ? List.of() : List.copyOf(activeFields);
if (tracking == null) {
tracking = TRACKING.computeIfAbsent(level, ignored -> new TrackingState());
}
discoverFieldEntities(level, fields, tracking);
syncFieldSnapshots(level, fields, tracking);
updateEntities(level, fields, tracking);
@@ -39,6 +54,12 @@ public final class TimeDilationManager {
}
}
public static void registerActiveField(TimeDilationFieldEntity field) {
if (field.level() instanceof ServerLevel level) {
ACTIVE_FIELDS.computeIfAbsent(level, ignored -> Collections.newSetFromMap(new IdentityHashMap<>())).add(field);
}
}
public static void trackPotentiallyAffected(Entity entity) {
if (!(entity.level() instanceof ServerLevel level) || entity instanceof TimeDilationFieldEntity) {
return;
@@ -46,6 +67,7 @@ public final class TimeDilationManager {
if (entity instanceof TimeDilationEntityAccess access
&& Math.abs(access.antarchy$getTimeDilationRate() - TimeDilationMath.NORMAL_RATE) < 0.001D
&& Math.abs(access.antarchy$getInheritedTimeDilationRate() - TimeDilationMath.NORMAL_RATE) < 0.001D
&& Math.abs(TimeDilationApi.getVehicleRate(entity) - TimeDilationMath.NORMAL_RATE) < 0.001D
&& (!(entity instanceof net.minecraft.world.entity.LivingEntity living)
|| ((RoyalEffectHooks.dilatedHolder() == null || !living.hasEffect(RoyalEffectHooks.dilatedHolder()))
&& (RoyalEffectHooks.contractedHolder() == null || !living.hasEffect(RoyalEffectHooks.contractedHolder()))))) {
@@ -54,6 +76,32 @@ public final class TimeDilationManager {
TRACKING.computeIfAbsent(level, ignored -> new TrackingState()).entities.add(entity);
}
public static void resyncPersistentEffects(ServerPlayer player) {
if (!(player instanceof TimeDilationEntityAccess access)) {
return;
}
double targetRate = TimeDilationMath.NORMAL_RATE;
if (RoyalEffectHooks.dilatedHolder() != null) {
var effect = player.getEffect(RoyalEffectHooks.dilatedHolder());
if (effect != null) {
targetRate = Math.min(targetRate, DilatedMobEffect.rateForAmplifier(effect.getAmplifier()));
}
}
if (RoyalEffectHooks.contractedHolder() != null) {
var effect = player.getEffect(RoyalEffectHooks.contractedHolder());
if (effect != null && targetRate >= TimeDilationMath.NORMAL_RATE) {
targetRate = Math.max(targetRate, ContractedMobEffect.rateForAmplifier(effect.getAmplifier()));
}
}
if (Math.abs(targetRate - TimeDilationMath.NORMAL_RATE) >= 0.001D) {
access.antarchy$setTimeDilationRate(targetRate);
TimeDilationApi.syncEntityRate(player, targetRate);
}
trackPotentiallyAffected(player);
}
private static void syncFieldSnapshots(ServerLevel level, List<TimeDilationFieldEntity> fields, TrackingState tracking) {
List<TimeDilationFieldSnapshot> snapshots = fields.stream()
.filter(field -> !field.isChronosphere())
@@ -71,16 +119,6 @@ public final class TimeDilationManager {
}
}
private static List<TimeDilationFieldEntity> collectFields(ServerLevel level) {
List<TimeDilationFieldEntity> fields = new ArrayList<>();
for (Entity entity : level.getAllEntities()) {
if (entity instanceof TimeDilationFieldEntity field && field.isAlive()) {
fields.add(field);
}
}
return fields;
}
private static void discoverFieldEntities(ServerLevel level, List<TimeDilationFieldEntity> fields, TrackingState tracking) {
for (TimeDilationFieldEntity field : fields) {
double radius = field.influenceRadius();
@@ -128,6 +166,12 @@ public final class TimeDilationManager {
}
}
double inheritedRate = access.antarchy$getInheritedTimeDilationRate();
double vehicleRate = TimeDilationApi.getVehicleRate(entity);
if (vehicleRate < TimeDilationMath.NORMAL_RATE) {
inheritedRate = Math.min(inheritedRate, vehicleRate);
} else {
inheritedRate = Math.max(inheritedRate, vehicleRate);
}
if (entity instanceof Projectile projectile && projectile.getOwner() != null) {
double ownerRate = TimeDilationApi.getRate(projectile.getOwner());
inheritedRate = ownerRate < TimeDilationMath.NORMAL_RATE
@@ -18,6 +18,8 @@ import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
@@ -35,6 +37,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
* Fixes move/landing logic that assumes down is always down.
*/
public abstract class EntityMoveMixin {
@Unique
private static final Logger ANTARCHY_STEP_LOGGER = LoggerFactory.getLogger("Antarchy/GravityStep");
@Unique
private boolean antarchy$loggedInvertedCollide;
@Unique
private boolean antarchy$loggedHorizontalBlock;
@Unique
private boolean antarchy$loggedInvertedMove;
@Unique
private double antarchy$lastWorldMoveY = 0.0;
@Unique
@@ -49,6 +59,12 @@ public abstract class EntityMoveMixin {
Entity entity = (Entity) (Object) this;
this.antarchy$moveStartBox = entity.getBoundingBox();
this.antarchy$lastPlayerMoveY = movement.y;
if (AntarchyGravityApi.isGravityInverted(entity) && !this.antarchy$loggedInvertedMove) {
this.antarchy$loggedInvertedMove = true;
ANTARCHY_STEP_LOGGER.warn(
"Inverted move entered: entity={} movement={} noPhysics={} onGround={} box={}",
entity.getClass().getSimpleName(), movement, entity.noPhysics, entity.onGround(), entity.getBoundingBox());
}
}
@ModifyVariable(method = "move", at = @At("HEAD"), ordinal = 0, argsOnly = true)
@@ -149,6 +165,13 @@ public abstract class EntityMoveMixin {
@Inject(method = "collide", at = @At("HEAD"))
private void antarchy$captureCollideWorldMovement(Vec3 movement, CallbackInfoReturnable<Vec3> cir) {
this.antarchy$collideWorldMovement = movement;
Entity entity = (Entity) (Object) this;
if (AntarchyGravityApi.isGravityInverted(entity) && !this.antarchy$loggedInvertedCollide) {
this.antarchy$loggedInvertedCollide = true;
ANTARCHY_STEP_LOGGER.warn(
"Inverted collide entered: entity={} movement={} onGround={} maxUpStep={} box={}",
entity.getClass().getSimpleName(), movement, entity.onGround(), entity.maxUpStep(), entity.getBoundingBox());
}
}
/*
@@ -239,6 +262,36 @@ public abstract class EntityMoveMixin {
return AntarchyGravityRotationUtil.vecWorldToPlayer(worldResult, direction);
}
/*
* Vanilla uses collideWithShapes directly for each step-height candidate,
* bypassing collideBoundingBox. At this point collide() is operating in the
* gravity-local frame, so leaving this call untouched makes an inverted
* entity test the candidate in the opposite horizontal and vertical world
* directions. The candidate consequently never beats the blocked movement.
*/
@WrapOperation(
method = "collide",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/Entity;collideWithShapes(Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/AABB;Ljava/util/List;)Lnet/minecraft/world/phys/Vec3;"
)
)
private Vec3 antarchy$collideStepCandidateInLocalFrame(
Vec3 localMovement,
AABB box,
List<VoxelShape> collisions,
Operation<Vec3> original
) {
Entity entity = (Entity) (Object) this;
AntarchyGravityDirection direction = AntarchyGravityApi.getGravityDirection(entity);
if (!direction.isInverted()) {
return original.call(localMovement, box, collisions);
}
Vec3 worldMovement = AntarchyGravityRotationUtil.vecPlayerToWorld(localMovement, direction);
Vec3 worldResult = original.call(worldMovement, box, collisions);
return AntarchyGravityRotationUtil.vecWorldToPlayer(worldResult, direction);
}
@Redirect(
method = "collide",
at = @At(
@@ -287,6 +340,15 @@ public abstract class EntityMoveMixin {
return;
}
Vec3 worldResult = AntarchyGravityRotationUtil.vecPlayerToWorld(cir.getReturnValue(), direction);
Vec3 localMovement = AntarchyGravityRotationUtil.vecWorldToPlayer(this.antarchy$collideWorldMovement, direction);
if (!this.antarchy$loggedHorizontalBlock
&& (localMovement.x != cir.getReturnValue().x || localMovement.z != cir.getReturnValue().z)) {
this.antarchy$loggedHorizontalBlock = true;
ANTARCHY_STEP_LOGGER.warn(
"Inverted horizontal block: localMovement={} localResult={} worldMovement={} worldResult={} onGround={} maxUpStep={} box={}",
localMovement, cir.getReturnValue(), this.antarchy$collideWorldMovement, worldResult,
entity.onGround(), entity.maxUpStep(), entity.getBoundingBox());
}
cir.setReturnValue(PortalGunCollisionHelper.resolveCollision(
entity,
entity.getBoundingBox(),
@@ -2,6 +2,8 @@ package com.craisinlord.antarchy.mixins.time;
import com.craisinlord.antarchy.content.time.TimeDilationApi;
import com.craisinlord.antarchy.content.time.TimeDilationManager;
import com.craisinlord.antarchy.content.client.ContractionAfterimages;
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
@@ -14,7 +16,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public abstract class LivingEntityTimeDilationMixin {
@Inject(method = "tickEffects", at = @At("HEAD"))
private void antarchy$trackTemporalEffects(CallbackInfo ci) {
TimeDilationManager.trackPotentiallyAffected((Entity) (Object) this);
Entity entity = (Entity) (Object) this;
TimeDilationManager.trackPotentiallyAffected(entity);
if (entity.level().isClientSide && RoyalEffectHooks.contractedHolder() != null) {
ContractionAfterimages.observe((LivingEntity) entity);
}
}
@Inject(method = "updateSwingTime", at = @At("HEAD"), cancellable = true)
@@ -9,15 +9,33 @@ import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
import com.craisinlord.antarchy.mixins.client.EntityBoundSoundInstanceAccessor;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import net.minecraft.client.resources.sounds.SoundInstance;
import net.minecraft.client.sounds.ChannelAccess;
import net.minecraft.client.sounds.SoundEngine;
import net.minecraft.client.Minecraft;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Map;
@Mixin(SoundEngine.class)
public abstract class SoundEngineTimeDilationMixin {
@Shadow @Final private Map<SoundInstance, ChannelAccess.ChannelHandle> instanceToChannel;
@Inject(method = "tickNonPaused", at = @At("TAIL"))
private void antarchy$refreshActiveSoundPitches(CallbackInfo ci) {
if (!ClientTimeDilationTicker.hasActiveDilation()) {
return;
}
this.instanceToChannel.forEach((sound, channel) ->
channel.execute(audioChannel -> audioChannel.setPitch(this.antarchy$dilatePitch(sound.getPitch(), sound))));
}
@ModifyReturnValue(method = "calculatePitch", at = @At("RETURN"))
private float antarchy$dilatePitch(float pitch, SoundInstance sound) {
double rate = ClientTimeDilationTicker.rateAt(sound.getX(), sound.getY(), sound.getZ());
@@ -26,7 +26,7 @@
},
{
"type": "minecraft:item",
"name": "antarchy:cornea_stalk",
"name": "antarchy:cornea_ear",
"weight": 8,
"functions": [
{
@@ -10,7 +10,12 @@
"biomes": "#antarchy:has_structure/underside_castle_biomes",
"step": "underground_structures",
"enhanced_terrain_adaptation": {
"type": "integrated_api:none"
"type": "integrated_api:custom",
"carves": true,
"beards": true,
"kernel_size": 35,
"kernel_distance": 35,
"direction": "up"
},
"start_height": {
"type": "minecraft:constant",
@@ -10,7 +10,12 @@
"biomes": "#antarchy:has_structure/underside_ruins_biomes",
"step": "underground_structures",
"enhanced_terrain_adaptation": {
"type": "integrated_api:none"
"type": "integrated_api:custom",
"carves": true,
"beards": true,
"kernel_size": 35,
"kernel_distance": 35,
"direction": "up"
},
"start_height": {
"type": "minecraft:constant",
@@ -1,7 +1,6 @@
{
"replace": false,
"values": [
"minecraft:slime_ball",
"antarchy:flytrap_goo"
"minecraft:slime_ball"
]
}
@@ -72,8 +72,14 @@ public final class AntarchyFabricEvents {
}
public static void register() {
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> ChronosphereManager.refresh(handler.player));
ServerPlayerEvents.AFTER_RESPAWN.register((oldPlayer, newPlayer, alive) -> ChronosphereManager.refresh(newPlayer));
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {
ChronosphereManager.refresh(handler.player);
TimeDilationManager.resyncPersistentEffects(handler.player);
});
ServerPlayerEvents.AFTER_RESPAWN.register((oldPlayer, newPlayer, alive) -> {
ChronosphereManager.refresh(newPlayer);
TimeDilationManager.resyncPersistentEffects(newPlayer);
});
ServerEntityWorldChangeEvents.AFTER_PLAYER_CHANGE_WORLD.register((player, origin, destination) -> ChronosphereManager.refresh(player));
net.fabricmc.fabric.api.networking.v1.EntityTrackingEvents.START_TRACKING.register((trackedEntity, player) -> {
if (trackedEntity instanceof com.craisinlord.antarchy.content.time.TimeDilationEntityAccess access
@@ -2,6 +2,7 @@ package com.craisinlord.antarchy.fabric;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.compat.infinity.InfinityCompatBridge;
import com.craisinlord.antarchy.compat.infinity.InfinityWarpResult;
import net.lerariemann.infinity.util.InfinityMethods;
import net.lerariemann.infinity.util.teleport.PortalCreator;
import net.lerariemann.infinity.util.teleport.WarpLogic;
@@ -38,13 +39,15 @@ public final class FabricInfinityCompat implements InfinityCompatBridge {
}
@Override
public boolean requestWarp(ServerPlayer player, ResourceLocation dimensionId) {
public InfinityWarpResult requestWarp(ServerPlayer player, ResourceLocation dimensionId) {
try {
WarpLogic.requestWarp(player, dimensionId, false);
return true;
return InfinityWarpResult.PENDING;
} catch (Throwable throwable) {
Antarchy.LOGGER.error("[Antarchy] Failed to request an Infinity warp to {}", dimensionId, throwable);
return false;
return InfinityGenerationFailure.consume(dimensionId)
? InfinityWarpResult.FAILED_GENERATION
: InfinityWarpResult.REJECTED;
}
}
@@ -0,0 +1,20 @@
package com.craisinlord.antarchy.fabric;
import net.minecraft.resources.ResourceLocation;
public final class InfinityGenerationFailure {
private static final ThreadLocal<ResourceLocation> FAILURE = new ThreadLocal<>();
private InfinityGenerationFailure() {
}
public static void mark(ResourceLocation dimensionId) {
FAILURE.set(dimensionId);
}
public static boolean consume(ResourceLocation dimensionId) {
ResourceLocation failed = FAILURE.get();
FAILURE.remove();
return dimensionId.equals(failed);
}
}
@@ -4,6 +4,8 @@ import com.craisinlord.antarchy.content.entity.multipart.MultipartEntityOwner;
import com.craisinlord.antarchy.content.entity.multipart.MultipartFramework;
import com.craisinlord.antarchy.content.entity.multipart.MultipartPartAccess;
import com.craisinlord.antarchy.content.entity.multipart.MultipartPartDefinition;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
@@ -64,17 +66,27 @@ public class MultipartPartEntity extends Entity implements MultipartPartAccess {
return;
}
AntarchyGravityApi.applySyncedState(
this,
AntarchyGravityApi.getGravityDirection(parent),
AntarchyGravityApi.getPrevGravityDirection(parent),
AntarchyGravityApi.isGravityForced(parent),
AntarchyGravityApi.getTransitionDuration(parent),
AntarchyGravityApi.getTransitionRemaining(parent)
);
double oldX = this.getX();
double oldY = this.getY();
double oldZ = this.getZ();
double yawRadians = Math.toRadians(parent.getYRot());
Vec3 forward = new Vec3(-Math.sin(yawRadians), 0.0D, Math.cos(yawRadians));
Vec3 right = new Vec3(forward.z, 0.0D, -forward.x);
Vec3 position = new Vec3(
parent.getX() + forward.x * definition.forwardOffset() + right.x * definition.lateralOffset(),
parent.getY() + definition.yOffset(),
parent.getZ() + forward.z * definition.forwardOffset() + right.z * definition.lateralOffset()
);
Vec3 localOffset = new Vec3(
forward.x * definition.forwardOffset() + right.x * definition.lateralOffset(),
definition.yOffset() + (AntarchyGravityApi.isGravityInverted(parent) ? definition.height() : 0.0D),
forward.z * definition.forwardOffset() + right.z * definition.lateralOffset());
Vec3 offset = AntarchyGravityRotationUtil.vecPlayerToWorld(localOffset, AntarchyGravityApi.getGravityDirection(parent));
Vec3 position = parent.position().add(offset);
this.setPos(position.x, position.y, position.z);
this.setYRot(parent.getYRot());
this.setXRot(parent.getXRot());
@@ -0,0 +1,34 @@
package com.craisinlord.antarchy.fabric.mixin.infinity;
import com.craisinlord.antarchy.fabric.InfinityGenerationFailure;
import net.lerariemann.infinity.access.MinecraftServerAccess;
import net.lerariemann.infinity.util.teleport.PortalCreator;
import net.lerariemann.infinity.util.teleport.WarpLogic;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(WarpLogic.class)
public interface WarpLogicMixin {
@Redirect(
method = "requestWarp(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/resources/ResourceLocation;Z)V",
at = @At(value = "INVOKE", target = "Lnet/lerariemann/infinity/util/teleport/PortalCreator;tryAddInfinityDimension(Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/resources/ResourceLocation;)Z")
)
private static boolean antarchy$queuedDimensionCountsAsNew(MinecraftServer server, ResourceLocation dimensionId) throws Throwable {
ResourceKey<Level> key = ResourceKey.create(Registries.DIMENSION, dimensionId);
if (server instanceof MinecraftServerAccess access && access.infinity$hasToAdd(key)) {
return true;
}
try {
return PortalCreator.tryAddInfinityDimension(server, dimensionId);
} catch (Throwable throwable) {
InfinityGenerationFailure.mark(dimensionId);
throw throwable;
}
}
}
@@ -1036,10 +1036,10 @@ public final class AntarchyFabricItems {
public static final DeferredItem<Item> HERCULES_HORN = ITEMS.registerSimpleItem("hercules_horn", new Item.Properties().rarity(Rarity.UNCOMMON));
public static final DeferredItem<Item> KING_SCALE = ITEMS.registerSimpleItem("king_scale", new Item.Properties().rarity(Rarity.RARE));
public static final DeferredItem<Item> KING_SCALE = ITEMS.registerSimpleItem("king_scale", new Item.Properties().rarity(Rarity.RARE).fireResistant());
public static final DeferredItem<Item> QUEEN_SCALE = ITEMS.registerSimpleItem("queen_scale", new Item.Properties().rarity(Rarity.RARE));
public static final DeferredItem<Item> QUEEN_SCALE = ITEMS.registerSimpleItem("queen_scale", new Item.Properties().rarity(Rarity.RARE).fireResistant());
public static final DeferredItem<Item> CHITIN = ITEMS.registerSimpleItem("chitin", new Item.Properties().rarity(Rarity.UNCOMMON));
@@ -21,6 +21,7 @@
"entity.MultipartEntityLevelRegistryMixin",
"WoodTypeInvoker",
"infinity.PortalCreatorMixin",
"infinity.WarpLogicMixin",
"infinity.AmendmentRareOresMixin"
],
"client": [
@@ -0,0 +1,20 @@
package com.craisinlord.antarchy.neoforge;
import net.minecraft.resources.ResourceLocation;
public final class InfinityGenerationFailure {
private static final ThreadLocal<ResourceLocation> FAILURE = new ThreadLocal<>();
private InfinityGenerationFailure() {
}
public static void mark(ResourceLocation dimensionId) {
FAILURE.set(dimensionId);
}
public static boolean consume(ResourceLocation dimensionId) {
ResourceLocation failed = FAILURE.get();
FAILURE.remove();
return dimensionId.equals(failed);
}
}
@@ -2,6 +2,7 @@ package com.craisinlord.antarchy.neoforge;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.compat.infinity.InfinityCompatBridge;
import com.craisinlord.antarchy.compat.infinity.InfinityWarpResult;
import net.lerariemann.infinity.InfinityMod;
import net.lerariemann.infinity.util.InfinityMethods;
import net.lerariemann.infinity.util.teleport.PortalCreator;
@@ -69,13 +70,15 @@ public final class NeoForgeInfinityCompat implements InfinityCompatBridge {
}
@Override
public boolean requestWarp(ServerPlayer player, ResourceLocation dimensionId) {
public InfinityWarpResult requestWarp(ServerPlayer player, ResourceLocation dimensionId) {
try {
WarpLogic.requestWarp(player, dimensionId, false);
return true;
return InfinityWarpResult.PENDING;
} catch (Throwable throwable) {
Antarchy.LOGGER.error("[Antarchy] Failed to request an Infinity warp to {}", dimensionId, throwable);
return false;
return InfinityGenerationFailure.consume(dimensionId)
? InfinityWarpResult.FAILED_GENERATION
: InfinityWarpResult.REJECTED;
}
}
@@ -4,6 +4,8 @@ import com.craisinlord.antarchy.content.entity.multipart.MultipartEntityOwner;
import com.craisinlord.antarchy.content.entity.multipart.MultipartFramework;
import com.craisinlord.antarchy.content.entity.multipart.MultipartPartAccess;
import com.craisinlord.antarchy.content.entity.multipart.MultipartPartDefinition;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
@@ -67,17 +69,27 @@ public class MultipartPartEntity extends PartEntity<Entity> implements OwnableEn
return;
}
AntarchyGravityApi.applySyncedState(
this,
AntarchyGravityApi.getGravityDirection(parent),
AntarchyGravityApi.getPrevGravityDirection(parent),
AntarchyGravityApi.isGravityForced(parent),
AntarchyGravityApi.getTransitionDuration(parent),
AntarchyGravityApi.getTransitionRemaining(parent)
);
double oldX = this.getX();
double oldY = this.getY();
double oldZ = this.getZ();
double yawRadians = Math.toRadians(parent.getYRot());
Vec3 forward = new Vec3(-Math.sin(yawRadians), 0.0D, Math.cos(yawRadians));
Vec3 right = new Vec3(forward.z, 0.0D, -forward.x);
Vec3 position = new Vec3(
parent.getX() + forward.x * this.definition.forwardOffset() + right.x * this.definition.lateralOffset(),
parent.getY() + this.definition.yOffset(),
parent.getZ() + forward.z * this.definition.forwardOffset() + right.z * this.definition.lateralOffset()
);
Vec3 localOffset = new Vec3(
forward.x * this.definition.forwardOffset() + right.x * this.definition.lateralOffset(),
this.definition.yOffset() + (AntarchyGravityApi.isGravityInverted(parent) ? this.definition.height() : 0.0D),
forward.z * this.definition.forwardOffset() + right.z * this.definition.lateralOffset());
Vec3 offset = AntarchyGravityRotationUtil.vecPlayerToWorld(localOffset, AntarchyGravityApi.getGravityDirection(parent));
Vec3 position = parent.position().add(offset);
this.setPos(position.x, position.y, position.z);
this.setRot(parent.getYRot(), parent.getXRot());
this.xo = oldX;
@@ -9,11 +9,6 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(value = ConfigGenInvocation.class, remap = false)
/*
* Guards against a NPE in Infinite Dimensions' SurfaceRuleScanner when another mod
* registers a surface rule with a missing "biome_is" field. Without this, the crash
* propagates up through PlayerList.placeNewPlayer and kicks the player on login
*/
public class ConfigGenInvocationMixin {
@Redirect(
@@ -0,0 +1,35 @@
package com.craisinlord.antarchy.neoforge.mixins.infinity;
import com.craisinlord.antarchy.neoforge.InfinityGenerationFailure;
import net.lerariemann.infinity.access.MinecraftServerAccess;
import net.lerariemann.infinity.util.teleport.PortalCreator;
import net.lerariemann.infinity.util.teleport.WarpLogic;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(value = WarpLogic.class, remap = false)
public interface WarpLogicMixin {
@Redirect(
method = "requestWarp(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/resources/ResourceLocation;Z)V",
at = @At(value = "INVOKE", target = "Lnet/lerariemann/infinity/util/teleport/PortalCreator;tryAddInfinityDimension(Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/resources/ResourceLocation;)Z"),
remap = false
)
private static boolean antarchy$queuedDimensionCountsAsNew(MinecraftServer server, ResourceLocation dimensionId) throws Throwable {
ResourceKey<Level> key = ResourceKey.create(Registries.DIMENSION, dimensionId);
if (server instanceof MinecraftServerAccess access && access.infinity$hasToAdd(key)) {
return true;
}
try {
return PortalCreator.tryAddInfinityDimension(server, dimensionId);
} catch (Throwable throwable) {
InfinityGenerationFailure.mark(dimensionId);
throw throwable;
}
}
}
@@ -57,8 +57,7 @@ public final class MultipartNetworking {
return;
}
DamageSource source = serverPlayer.level().damageSources().playerAttack(serverPlayer);
owner.antarchy$hurtMultipartPart(part, source, payload.damage());
serverPlayer.attack(part);
});
}
@@ -143,6 +143,8 @@ public final class AntarchyNeoForgeEvents {
NeoForge.EVENT_BUS.addListener(AntarchyNeoForgeEvents::handleBloodglassPlayerDeath);
NeoForge.EVENT_BUS.addListener(AntarchyNeoForgeEvents::handleBloodglassRespawn);
NeoForge.EVENT_BUS.addListener(AntarchyNeoForgeEvents::handleBloodglassLogin);
NeoForge.EVENT_BUS.addListener(AntarchyNeoForgeEvents::handleTimeDilationLogin);
NeoForge.EVENT_BUS.addListener(AntarchyNeoForgeEvents::handleTimeDilationRespawn);
NeoForge.EVENT_BUS.addListener(AntarchyNeoForgeEvents::handleCavarynHordeKill);
NeoForge.EVENT_BUS.addListener(AntarchyNeoForgeEvents::handleCavarynHordeBlockBreak);
NeoForge.EVENT_BUS.addListener(AntarchyNeoForgeEvents::tickCavarynHordes);
@@ -213,7 +215,8 @@ public final class AntarchyNeoForgeEvents {
&& tickEnd > 0L
&& now - tickEnd >= SERVER_IDLE_BUSY_WARN_NANOS
&& state != Thread.State.WAITING
&& state != Thread.State.TIMED_WAITING;
&& state != Thread.State.TIMED_WAITING
&& !antarchy$isServerThreadIdleWait(tickThread);
if (idleBusy) {
antarchy$dumpServerThreadWatchdog(
"server thread busy outside active tick",
@@ -238,6 +241,18 @@ public final class AntarchyNeoForgeEvents {
}
}
private static boolean antarchy$isServerThreadIdleWait(Thread tickThread) {
for (StackTraceElement element : tickThread.getStackTrace()) {
String method = element.getMethodName();
if (method.equals("waitUntilNextTick")
|| method.equals("waitForTasks")
|| method.equals("managedBlock")) {
return true;
}
}
return false;
}
static void onVillagerTrades(VillagerTradesEvent event) {
if (event.getType() == VillagerProfession.FARMER) {
event.getTrades().get(1).add(emeraldForItems(AntarchyObjects.CORN.get(), 20, 16, 2));
@@ -384,6 +399,18 @@ public final class AntarchyNeoForgeEvents {
}
}
static void handleTimeDilationLogin(PlayerEvent.PlayerLoggedInEvent event) {
if (event.getEntity() instanceof ServerPlayer player) {
TimeDilationManager.resyncPersistentEffects(player);
}
}
static void handleTimeDilationRespawn(PlayerEvent.PlayerRespawnEvent event) {
if (event.getEntity() instanceof ServerPlayer player) {
TimeDilationManager.resyncPersistentEffects(player);
}
}
static void handleTigerEyeLogout(PlayerEvent.PlayerLoggedOutEvent event) {
if (event.getEntity() instanceof ServerPlayer player) {
TigerEyeCamouflageController.deactivate(player, false);
@@ -561,15 +588,6 @@ public final class AntarchyNeoForgeEvents {
}
if (existingInverted == null || existingInverted.getDuration() <= ANTIMETAL_INVERTED_REFRESH_THRESHOLD_TICKS) {
if (livingEntity instanceof Player || livingEntity.level().dimension().location().toString().equals("antarchy:thoraxis")) {
Antarchy.LOGGER.info(
"[antarchy-gravity] overhead antimetal applying inverted effect targetType={} uuid={} pos=({}, {}, {}) dim={} existingDuration={} gameTime={}",
livingEntity.getType(), livingEntity.getUUID(), livingEntity.getX(), livingEntity.getY(), livingEntity.getZ(),
livingEntity.level().dimension().location(),
existingInverted != null ? existingInverted.getDuration() : -1,
gameTime
);
}
livingEntity.addEffect(new MobEffectInstance(AntarchyNeoforgeMisc.INVERTED, ANTIMETAL_INVERTED_REFRESH_TICKS, 0, false, false, false));
spawnAntimetalInversionParticles(livingEntity);
}
@@ -717,8 +717,8 @@ public final class AntarchyNeoforgeItems {
public static final DeferredItem<MantisClawItem> MANTIS_CLAW = ITEMS.register("mantis_claw",
() -> new MantisClawItem(Tiers.IRON, new Item.Properties().stacksTo(1).durability(50).rarity(Rarity.UNCOMMON)));
public static final DeferredItem<Item> HERCULES_HORN = ITEMS.registerSimpleItem("hercules_horn", new Item.Properties().rarity(Rarity.UNCOMMON));
public static final DeferredItem<Item> KING_SCALE = ITEMS.registerSimpleItem("king_scale", new Item.Properties().rarity(Rarity.RARE));
public static final DeferredItem<Item> QUEEN_SCALE = ITEMS.registerSimpleItem("queen_scale", new Item.Properties().rarity(Rarity.RARE));
public static final DeferredItem<Item> KING_SCALE = ITEMS.registerSimpleItem("king_scale", new Item.Properties().rarity(Rarity.RARE).fireResistant());
public static final DeferredItem<Item> QUEEN_SCALE = ITEMS.registerSimpleItem("queen_scale", new Item.Properties().rarity(Rarity.RARE).fireResistant());
public static final DeferredItem<Item> CHITIN = ITEMS.registerSimpleItem("chitin", new Item.Properties().rarity(Rarity.UNCOMMON));
public static final DeferredItem<Item> JERRY_NUCLEUS = ITEMS.register("jerry_nucleus",
() -> new com.craisinlord.antarchy.content.item.JerryNucleusItem(new Item.Properties().rarity(Rarity.UNCOMMON)
@@ -12,6 +12,7 @@
"infinity.AmendmentRareOresMixin",
"infinity.ConfigGenInvocationMixin",
"infinity.PortalCreatorMixin",
"infinity.WarpLogicMixin",
"level.ClientLevelPartEntitiesAccessor",
"level.ServerLevelPartEntitiesAccessor"
],