This commit is contained in:
craisinlord committed 2026-10-26 16:52:32 -05:00
1 parent 5a8cb58cb0
commit 8626d205f7
132 files changed
+18 -931

No files matched your search

@@ -31,11 +31,6 @@ public interface InfinityCompatBridge {
return InfinityWarpResult.REJECTED;
}
/**
* Converts an already-ignited vanilla Nether portal frame at {@code anyPortalBlockPos} into a real, permanent
* Infinite Dimensions portal to {@code dimensionId}, generating the dimension first if it doesn't exist yet.
* Mirrors what Infinity itself does when a written book is thrown into a lit portal.
*/
default boolean createPhysicalPortal(ServerLevel level, BlockPos anyPortalBlockPos, ResourceLocation dimensionId) {
return false;
}
@@ -567,7 +567,6 @@ public final class AntarchySettings {
private static int bloodCrystalAppleDurationTicks = 2400;
private static int bloodCrystalAppleShieldRechargeTicks = 600;
private static int bloodCrystalHardMaxShields = 10;
// Armor stats (iron defense, gold durability, 0 toughness by default)
private static int bloodCrystalHelmetDefense = 3;
private static int bloodCrystalChestplateDefense = 7;
private static int bloodCrystalLeggingsDefense = 6;
@@ -2530,7 +2529,6 @@ public final class AntarchySettings {
public static int reverieDuplicationCooldownTicks() { return reverieDuplicationCooldownTicks; }
public static void setReverieDuplicationCooldownTicks(int v){ reverieDuplicationCooldownTicks = v; }
// Hardcoded AI tuning — getters only, no config wiring
public static double reveriePreferredFollowMinDistance() { return reveriePreferredFollowMinDistance; }
public static double reveriePreferredFollowMaxDistance() { return reveriePreferredFollowMaxDistance; }
public static double reverieCatchUpDistance() { return reverieCatchUpDistance; }
@@ -30,11 +30,6 @@ public final class AntarchyAdvancementTriggers {
register((id, trigger) -> CriteriaTriggers.register(id.toString(), trigger));
}
/**
* Registers these triggers through the active loader's lifecycle hook.
* NeoForge calls this from its trigger-type RegisterEvent; Fabric can call
* the no-argument overload during its initializer.
*/
public static void register(BiConsumer<ResourceLocation, CriterionTrigger<?>> registrar) {
registrar.accept(ResourceLocation.fromNamespaceAndPath("antarchy", "crossed_gravity_throat"), CROSSING);
registrar.accept(ResourceLocation.fromNamespaceAndPath("antarchy", "horde_phase_changed"), HORDE_PHASE);
@@ -25,7 +25,6 @@ public final class DuplicatorTreeLogic {
private static final int LOG_SEARCH_BELOW = 5;
private static final int LOG_SEARCH_ABOVE = 1;
// Cache center log pos per chunk. WeakHashMap lets levels be GC'd when unloaded.
private static final WeakHashMap<ServerLevel, HashMap<Long, BlockPos>> CENTER_LOG_CACHE = new WeakHashMap<>();
private DuplicatorTreeLogic() {
@@ -20,7 +20,6 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
import net.minecraft.world.phys.BlockHitResult;
/** A two-block-tall, light-emitting reed found around Lumen pools. */
public final class GlimmeringReedBlock extends DoublePlantBlock implements BonemealableBlock {
public static final MapCodec<GlimmeringReedBlock> CODEC = Block.simpleCodec(GlimmeringReedBlock::new);
@@ -25,12 +25,6 @@ import net.minecraft.world.level.material.Fluids;
public class OuranwoodLeavesBlock extends LeavesBlock implements BonemealableBlock {
public static final MapCodec<OuranwoodLeavesBlock> CODEC = Block.simpleCodec(OuranwoodLeavesBlock::new);
/*
* We still include vanilla LeavesBlock.DISTANCE in the state definition because
* LeavesBlock's constructor sets it.
*
* This is the real Ouranwood decay distance.
*/
public static final IntegerProperty OURANWOOD_DISTANCE = IntegerProperty.create("ouranwood_distance", 1, 17);
public static final BooleanProperty PERSISTENT = LeavesBlock.PERSISTENT;
@@ -13,12 +13,6 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
/**
* Invisible world-gen-only marker placed inside a flying squirrel hollow.
* Schedules itself to replace with COARSE_DIRT and spawn squirrels shortly
* after the chunk loads, so entity creation never blocks the gen thread.
* No BlockItem is registered, so this block never appears in creative or JEI.
*/
public class OuranwoodSquirrelNestBlock extends Block {
public static final IntegerProperty SQUIRREL_COUNT = IntegerProperty.create("squirrels", 1, 3);
@@ -168,11 +168,6 @@ public abstract class RoyalEggBlock extends BaseEntityBlock {
}
}
/**
* Vanilla FallingBlockEntity always falls in world-down direction, so an
* unsupported egg placed with inverted underside gravity is stepped
* upward toward its support instead of being handed to that entity.
*/
private void tickInvertedFall(BlockState state, ServerLevel level, BlockPos pos) {
BlockPos above = pos.above();
if (!FallingBlock.isFree(level.getBlockState(above)) || above.getY() > level.getMaxBuildHeight()) {
@@ -65,8 +65,6 @@ public final class QueenTrailSpawnMarkerBlockEntity extends BlockEntity {
if (!nearbyPlayer) {
return;
}
// The Queen is large enough to span several chunks. Ensure the area around
// the arrival point is available before checking its collision box.
for (int chunkX = (marker.spawnPos.getX() - 16) >> 4; chunkX <= (marker.spawnPos.getX() + 16) >> 4; chunkX++) {
for (int chunkZ = (marker.spawnPos.getZ() - 16) >> 4; chunkZ <= (marker.spawnPos.getZ() + 16) >> 4; chunkZ++) {
level.getChunk(chunkX, chunkZ);
@@ -47,9 +47,6 @@ public final class UnderVaultBlockEntity extends BlockEntity {
public static void serverTick(ServerLevel level, BlockPos pos, BlockState state, UnderVaultBlockEntity blockEntity) {
blockEntity.vaultData.setLevel(level);
// The vanilla vault detector can miss this ceiling-mounted wrapper because its
// block state has a separate render-facing property. Keep the state synchronized
// with the same four-block activation range before running vanilla's state machine.
boolean playerNearby = !level.getEntitiesOfClass(Player.class, new AABB(pos).inflate(4.0D), player -> !player.isSpectator()).isEmpty();
if (state.getValue(UnderVaultBlock.STATE) == VaultState.INACTIVE && playerNearby && !blockEntity.playerWasNearby) {
state = state.setValue(UnderVaultBlock.STATE, VaultState.ACTIVE);
@@ -1,10 +1,5 @@
package com.craisinlord.antarchy.content.block.entity;
/**
* Identifies spawn-rule checks made by an Undertrial spawner's vanilla
* TrialSpawner tick. The context is scoped to the current server-thread call
* so ordinary trial spawners and all other spawn paths retain vanilla rules.
*/
public final class UndertrialSpawnContext implements AutoCloseable {
private static final ThreadLocal<Integer> DEPTH = ThreadLocal.withInitial(() -> 0);
@@ -190,8 +190,6 @@ public final class UndertrialSpawnerBlockEntity extends BlockEntity implements T
if (this.level == null) {
return;
}
// Match vanilla Trial Spawner interaction: override the next mob's entity id while
// preserving weighted potentials, ominous settings, and the trial's reward configuration.
this.trialSpawner.getData().setEntityId(this.trialSpawner, this.level.random, entityType);
this.markUpdated();
}
@@ -6,7 +6,6 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.core.BlockPos;
/** Client state for Antarchy-owned games hosted by AntOS. */
public final class AntarchyGameClientState {
private static final Map<String, String> GAME_STATES = new ConcurrentHashMap<>();
@@ -17,7 +17,6 @@ public final class MoonSkyTracker {
private static final long MAX_AGE_MILLIS = 1500L;
private static final double AIM_COSINE = Math.cos(Math.toRadians(PortalGunMoonMath.AIM_TOLERANCE_DEGREES));
private static Vec3 direction;
// Weak so a dimension change or logout doesn't pin the old client world in memory.
private static WeakReference<ClientLevel> level = new WeakReference<>(null);
private static long recordedAt;
private static Consumer<PortalGunMoonAimPayload> sender = payload -> {};
@@ -20,7 +20,6 @@ public final class PortalGunCrosshairRenderer {
private static final int HALF_WIDTH = 17;
private static final float MISSING_BRIGHTNESS = 0.3F;
private static final float MISSING_ALPHA = 0.75F;
// Weak so a dimension change or logout doesn't pin the old client world in memory.
private static WeakReference<ClientLevel> cachedLevel = new WeakReference<>(null);
private static long cachedGameTime = Long.MIN_VALUE;
private static UUID cachedGunId;
@@ -12,7 +12,6 @@ import net.minecraft.client.multiplayer.ClientLevel;
public final class PortalGunIndicatorClientState {
private static final Map<UUID, PortalGunIndicatorPayload> STATES = new HashMap<>();
// Weak so a dimension change or logout doesn't pin the old client world in memory.
private static WeakReference<ClientLevel> level = new WeakReference<>(null);
private static long lastRequestTick = Long.MIN_VALUE;
private static UUID lastRequestedGun;
@@ -8,14 +8,11 @@ import net.minecraft.resources.ResourceLocation;
import java.util.function.IntPredicate;
import java.util.function.Predicate;
/** Registers Antarchy's native games with the AntOS Games app. */
public final class AntarchyComputerGames {
private AntarchyComputerGames() {}
public static void register() {
registerIfMissing(game("basilisk", "BASILISK", () -> {
// AntOS 1.2.1 creates game sessions without passing the computer position.
// Keep Basilisk playable without a position-bound score callback.
BasiliskProgram program = new BasiliskProgram(true, 0, 0, score -> {});
return new GameSession(program::tick, program::render, program::keyPressed, ignored -> false);
}));
@@ -8,11 +8,6 @@ import net.minecraft.client.model.FrogModel;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.util.Mth;
/**
* Reuses vanilla Frog geometry ({@link FrogModel}/{@code ModelLayers.FROG}) for the Frog
* Glimmer variant instead of an ill-fitting GeckoLib placeholder mesh, with a simplified
* walk/idle animation (GlimmerEntity has no Frog-specific jump/tongue state).
*/
public class GlimmerFrogModel extends EntityModel<GlimmerEntity> {
private final ModelPart root;
private final ModelPart head;
@@ -9,7 +9,6 @@ public class AlphaMantisRenderer extends GeoEntityRenderer<AlphaMantisEntity> {
public AlphaMantisRenderer(EntityRendererProvider.Context context) {
super(context, new AlphaMantisModel());
this.shadowRadius = 1.5F;
// Mantis renders at 1.25x; the alpha is 1.5x bigger overall
this.withScale(1.875F);
}
}
@@ -74,7 +74,6 @@ public final class ElythiaSkyRenderer {
float starBrightness = level.getStarBrightness(partialTick) * (1.0F - rainLevel);
double timeDegrees = (level.getDayTime() + partialTick) * (360.0D / 24000.0D);
// Blend in a dark purple when it's night (starBrightness > 0)
float nightPurpleR = 0.055F;
float nightPurpleG = 0.010F;
float nightPurpleB = 0.120F;
@@ -169,10 +168,10 @@ public final class ElythiaSkyRenderer {
private static float[] pickStarColor(Random random) {
float roll = random.nextFloat();
if (roll < 0.80F) return new float[]{1.0F, 1.0F, 1.0F}; // white
if (roll < 0.87F) return new float[]{0.85F, 0.60F, 1.00F}; // light purple
if (roll < 0.94F) return new float[]{1.00F, 0.95F, 0.50F}; // yellow
return new float[]{1.0F, 0.45F, 0.45F}; // red
if (roll < 0.80F) return new float[]{1.0F, 1.0F, 1.0F};
if (roll < 0.87F) return new float[]{0.85F, 0.60F, 1.00F};
if (roll < 0.94F) return new float[]{1.00F, 0.95F, 0.50F};
return new float[]{1.0F, 0.45F, 0.45F};
}
private static void renderSunrise(PoseStack poseStack, Matrix4f projectionMatrix, ClientLevel level, float partialTick, float rainLevel) {
@@ -212,22 +211,18 @@ public final class ElythiaSkyRenderer {
private static void renderCelestialBodies(Matrix4f modelViewMatrix, Matrix4f projectionMatrix, double timeDegrees, float rainLevel) {
// Purple sun
float sun1Orbit = orbitAngle(timeDegrees, 1.0D, 0.0D);
renderBodyGlow(modelViewMatrix, projectionMatrix, sun1Orbit, 0.0F, 0xD06BFF, rainLevel, 70.0F);
renderTexturedBody(modelViewMatrix, projectionMatrix, sun1Orbit, 0.0F, 38.0F, 0xD06BFF, 1.0F, SUN_TEXTURE, false, 0, orbitAngle(timeDegrees, 0.8D, 0.0D));
// Orange sub
float sun2Orbit = orbitAngle(timeDegrees, 0.73D, 54.0D);
renderBodyGlow(modelViewMatrix, projectionMatrix, sun2Orbit, -14.0F, 0xFF9A33, rainLevel, 70.0F);
renderTexturedBody(modelViewMatrix, projectionMatrix, sun2Orbit, -14.0F, 16.0F, 0xFF9A33, 1.0F, SUN_TEXTURE, false, 0, orbitAngle(timeDegrees, -0.5D, 0.0D));
// Dark green moon
float moon2Orbit = orbitAngle(timeDegrees, 1.27D, 228.0D);
renderBodyGlow(modelViewMatrix, projectionMatrix, moon2Orbit, 36.0F, 0x4FD84D, rainLevel, 78.0F);
renderTexturedBody(modelViewMatrix, projectionMatrix, moon2Orbit, 36.0F, 14.0F, 0x4FD84D, 1.0F, MOON_TEXTURE, true, 1, orbitAngle(timeDegrees, 0.3D, 0.0D));
// Light green moon
float moon3Orbit = orbitAngle(timeDegrees, 0.38D, 122.0D);
renderBodyGlow(modelViewMatrix, projectionMatrix, moon3Orbit, -34.0F, 0xA3FF8F, rainLevel, 78.0F);
renderTexturedBody(modelViewMatrix, projectionMatrix, moon3Orbit, -34.0F, 12.0F, 0xA3FF8F, 1.0F, MOON_TEXTURE, true, 2, orbitAngle(timeDegrees, -0.6D, 0.0D));
@@ -193,9 +193,6 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
float outerV = -time * 0.25F;
float innerV = -time * 0.25F * 0.5F;
// Tremorzilla renders the beam in local +Z space. Keeping the mesh in that
// space is important: the beam textures are authored for these exact face
// coordinates and are not interchangeable with a world-space billboard.
float yaw = (float) Math.atan2(dir.z, dir.x);
float pitch = (float) Math.acos(dir.y);
poseStack.pushPose();
@@ -79,8 +79,6 @@ public final class RoyalIndicatorRenderer {
out.addVertex(pose, right, top, depth).setUv(1.0F, 0.0F).setOverlay(0).setLight(packedLight).setNormal(pose, 0.0F, 0.0F, 1.0F);
out.addVertex(pose, left, top, depth).setUv(0.0F, 0.0F).setOverlay(0).setLight(packedLight).setNormal(pose, 0.0F, 0.0F, 1.0F);
// Emit the reverse winding as well. The crown is viewed from every angle, and
// a single-sided quad can vanish when the renderer's culling state rejects it.
out.addVertex(pose, left, top, depth).setUv(0.0F, 0.0F).setOverlay(0).setLight(packedLight).setNormal(pose, 0.0F, 0.0F, -1.0F);
out.addVertex(pose, right, top, depth).setUv(1.0F, 0.0F).setOverlay(0).setLight(packedLight).setNormal(pose, 0.0F, 0.0F, -1.0F);
out.addVertex(pose, right, bottom, depth).setUv(1.0F, 1.0F).setOverlay(0).setLight(packedLight).setNormal(pose, 0.0F, 0.0F, -1.0F);
@@ -22,9 +22,6 @@ import net.minecraft.world.level.block.state.BlockState;
public final class TigerEyeCamouflageTextureResolver {
public record ResolvedTexture(ResourceLocation texture, int argbTint) {}
// PlayerModel's skin layout is always laid out on a 64x64 canvas, regardless of the
// block texture's actual size, so the generated overlay texture must match that grid
// for every body part to sample the block texture at the same pixel density.
private static final int SKIN_SIZE = 64;
private static final Map<Integer, ResolvedTexture> CACHE = new ConcurrentHashMap<>();
private static final ResourceLocation FALLBACK_TEXTURE = ResourceLocation.withDefaultNamespace("textures/block/stone.png");
@@ -102,7 +99,6 @@ public final class TigerEyeCamouflageTextureResolver {
try (NativeImage sourceImage = NativeImage.read(stream)) {
int tileWidth = sourceImage.getWidth();
// Animated block textures stack frames vertically below a square first frame.
int tileHeight = tileWidth <= sourceImage.getHeight() ? tileWidth : sourceImage.getHeight();
NativeImage canvas = new NativeImage(SKIN_SIZE, SKIN_SIZE, false);
@@ -94,9 +94,6 @@ public class WindVortexRenderer extends EntityRenderer<WindVortexEntity> {
addVertex(consumer, pose, end.x + offset.x, end.y + offset.y, end.z + offset.z, red, green, blue, alpha);
addVertex(consumer, pose, start.x + offset.x, start.y + offset.y, start.z + offset.z, red, green, blue, alpha);
// The lightning render type can cull one winding from some camera
// angles. Emit the opposite winding as well so every ribbon is
// visible from both sides.
addVertex(consumer, pose, start.x + offset.x, start.y + offset.y, start.z + offset.z, red, green, blue, alpha);
addVertex(consumer, pose, end.x + offset.x, end.y + offset.y, end.z + offset.z, red, green, blue, alpha);
addVertex(consumer, pose, end.x - offset.x, end.y - offset.y, end.z - offset.z, red, green, blue, alpha);
@@ -48,9 +48,6 @@ public class GlimmerRenderer extends GeoEntityRenderer<GlimmerEntity> {
float growth = entity.getGrowthScale();
poseStack.scale(growth, growth, growth);
// Compute body yaw directly from the entity's own tracked fields rather than trusting
// the ambient entityYaw parameter, so the body pose and the head-offset math below stay
// self-consistent.
float bodyYaw = Mth.rotLerp(partialTick, entity.yBodyRotO, entity.yBodyRot);
poseStack.mulPose(Axis.YP.rotationDegrees(180.0F - bodyYaw));
poseStack.scale(-1.0F, -1.0F, 1.0F);
@@ -82,7 +82,6 @@ public final class QueenLocateCommand {
return 0;
}
/** Finds the nearest generated Queen spawn site without spawning her. Loads (and may generate) the checked chunks. */
public static NearestSite findNearestSite(ServerLevel thoraxis, int originX, int originZ) {
int cellX = Math.floorDiv(originX, QueenTrailGrid.SPACING);
int cellZ = Math.floorDiv(originZ, QueenTrailGrid.SPACING);
@@ -10,7 +10,6 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.phys.AABB;
/** Archive coordinate lookups for royals that live on grids rather than in vanilla structures. */
public final class AntarchyArchiveLocators {
private AntarchyArchiveLocators() {
}
@@ -10,7 +10,6 @@ import net.minecraft.nbt.ListTag;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.saveddata.SavedData;
/** Persistent Antarchy game progress keyed by AntOS computer location. */
public final class AntarchyGameSavedData extends SavedData {
private static final String ID = "antarchy_computer_games";
private final Map<String, GameState> games = new HashMap<>();
@@ -1,6 +1,5 @@
package com.craisinlord.antarchy.content.effect;
/** Synchronized, presentation-only state for the short-lived Royal Judgment mark. */
public interface JudgmentMarkAccess {
boolean antarchy$isJudgmentMarked();
@@ -14,14 +14,12 @@ import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
/** Server-owned, player-specific Judgment marks. The visible bit is synchronized by vanilla entity data. */
public final class JudgmentMarkManager {
private static final Map<ServerLevel, MarkBook> MARKS = new WeakHashMap<>();
private JudgmentMarkManager() {
}
/** Returns true when this owner had already marked this target before the current hit. */
public static boolean recordSuccessfulHit(Player owner, LivingEntity target) {
if (!(owner instanceof ServerPlayer serverPlayer) || !(target.level() instanceof ServerLevel level)
|| owner.level() != target.level() || !hasGuardianArmor(owner) || !target.isAlive()) {
@@ -66,7 +64,6 @@ public final class JudgmentMarkManager {
return entity instanceof LivingEntity living && living.isAlive() ? living : null;
}
/** Prunes marks from this target and updates the vanilla-synchronized render bit. */
public static void tickTarget(LivingEntity target) {
if (!(target.level() instanceof ServerLevel level)) {
return;
@@ -23,7 +23,6 @@ import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.joml.Vector3f;
/** Server-authoritative Royal Guardian chestplate field and temporary projectile arrest state. */
public final class RoyalBoundaryManager {
private static final int ALLY_REFRESH_INTERVAL = 10;
private static final DustParticleOptions ROYAL_GOLD = new DustParticleOptions(new Vector3f(1.0F, 0.72F, 0.12F), 1.15F);
@@ -51,7 +50,6 @@ public final class RoyalBoundaryManager {
return true;
}
/** Called from ServerPlayer.tick; ends fields immediately when their owner can no longer sustain them. */
public static void tickOwner(ServerPlayer owner) {
if (!(owner.level() instanceof ServerLevel level)) return;
UUID ownerId = owner.getUUID();
@@ -92,7 +90,6 @@ public final class RoyalBoundaryManager {
}
}
/** Predicts this tick's movement so a fast projectile is arrested before its own collision pass. */
public static void prepareProjectile(Projectile projectile) {
if (!(projectile.level() instanceof ServerLevel level) || projectile.isRemoved()) return;
Map<UUID, ArrestedProjectile> arrested = ARRESTED.get(level);
@@ -111,7 +108,6 @@ public final class RoyalBoundaryManager {
}
}
/** Swept fallback for unusual projectiles and arrest-state progression. */
public static void tickProjectile(Projectile projectile) {
if (!(projectile.level() instanceof ServerLevel level)) return;
Map<UUID, ArrestedProjectile> arrested = ARRESTED.get(level);
@@ -408,10 +408,6 @@ public class FlytrapEntity extends Monster implements GeoEntity {
continue;
}
// Put the entity on cooldown before hurting it, regardless of hurt()'s result: a
// shield or armor effect can absorb the damage and make hurt() return false without
// granting the vanilla invulnerability window, which would otherwise let this attack
// re-attempt damage on the same entity every single tick of the active window.
this.sweepHitCooldowns.put(candidate.getUUID(), AntarchySettings.flytrapSweepHitCooldownTicks());
candidate.hurt(AntarchyDamageSources.flytrapMauling(serverLevel, this), (float) AntarchySettings.flytrapAttackDamage());
}
@@ -149,12 +149,10 @@ public class MantisEntity extends Monster implements GeoEntity {
boolean ignoreLightLevel = AntarchySettings.mantisIgnoreLightLevel();
// Daytime overworld spawns can't pass the vanilla darkness check, so no light gate here
if (level.getLevel().isDay() && level.getBiome(pos).is(AntarchyTags.Biomes.MANTIS_OVERWORLD_SPAWN_BIOMES)) {
return atSurface && level.canSeeSky(pos);
}
// Elythia meadow (and any future mantis_spawn_biomes): nighttime, no sky-access requirement
if (level.getLevel().isNight() && level.getBiome(pos).is(AntarchyTags.Biomes.MANTIS_SPAWN_BIOMES)) {
return atSurface && (ignoreLightLevel || Monster.checkMonsterSpawnRules(entityType, level, spawnReason, pos, random));
}
@@ -184,7 +182,6 @@ public class MantisEntity extends Monster implements GeoEntity {
HurtByTargetGoal hurtByTargetGoal = new HurtByTargetGoal(this);
this.targetSelector.addGoal(1, hurtByTargetGoal);
// randomInterval lowered from default 10 to 5 for faster re-acquisition
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 5, true, false, null));
}
@@ -88,7 +88,6 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
private boolean spawnedByKraken;
// Explosive impact (fired from the R.P.O. Launcher)
private boolean explosiveImpact;
private java.util.UUID explosiveLauncherId;
private int explosiveArmTicks;
@@ -140,9 +139,7 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
this.goalSelector.addGoal(5, new LookAtPlayerGoal(this, Player.class, 20.0F));
this.goalSelector.addGoal(6, new RandomLookAroundGoal(this));
// Only retaliate when hit — neutral otherwise
this.targetSelector.addGoal(1, new HurtByTargetGoal(this));
// When spawned by Kraken and flying, target nearest player
this.targetSelector.addGoal(2, new KrakenSummonTargetGoal(this));
}
@@ -215,7 +212,6 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
if (this.attackCooldown > 0) this.attackCooldown--;
if (this.inkSprayCooldown > 0) this.inkSprayCooldown--;
// Ink spray — always active regardless of aggro state
this.tickInkSpray();
LivingEntity target = this.getTarget();
@@ -375,10 +371,9 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
float angle = this.random.nextFloat() * (float) (Math.PI * 2);
this.wanderDx = Mth.cos(angle) * 0.015f;
this.wanderDz = Mth.sin(angle) * 0.015f;
this.wanderDy = -0.01f + this.random.nextFloat() * 0.01f; // slight downward bias
this.wanderDy = -0.01f + this.random.nextFloat() * 0.01f;
}
// Surface avoidance: if the block above is not water, push down
float dy = this.wanderDy;
if (!this.level().getFluidState(this.blockPosition().above()).is(net.minecraft.tags.FluidTags.WATER)) {
dy = -0.03f;
@@ -663,10 +658,6 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
}
}
// -------------------------------------------------------------------------
// Inner goal: only target players when spawned by Kraken in fly mode
// -------------------------------------------------------------------------
private static final class KrakenSummonTargetGoal extends NearestAttackableTargetGoal<Player> {
private final OctopusBombEntity octopus;
@@ -84,7 +84,6 @@ public class RollyPollyEntity extends TamableAnimal implements GeoEntity {
private static final int ANIM_ROLL_UP = 2;
private static final int ANIM_UNROLL = 4;
// wheel_mode is 0.75s, normal_mode is ~0.42s
private static final int ROLL_UP_TICKS = 15;
private static final int UNROLL_TICKS = 9;
private static final int DEFENSIVE_CURL_TICKS = 100;
@@ -156,7 +155,6 @@ public class RollyPollyEntity extends TamableAnimal implements GeoEntity {
this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D) {
@Override
public boolean canUse() {
// Curled-up or tamed rolly pollies stand their ground
return !RollyPollyEntity.this.isRolled() && !RollyPollyEntity.this.isTame() && super.canUse();
}
});
@@ -318,7 +316,6 @@ public class RollyPollyEntity extends TamableAnimal implements GeoEntity {
amount *= 0.25F;
}
boolean hurt = super.hurt(source, amount);
// Wild rolly pollies curl up defensively when attacked
if (hurt && !this.level().isClientSide && !this.isTame() && this.isAlive()
&& !this.isRolled() && this.rollTransitionTicks <= 0) {
this.defensiveCurlTicks = DEFENSIVE_CURL_TICKS;
@@ -111,9 +111,6 @@ public class ScorpionEntity extends Monster implements GeoEntity {
|| spawnReason == MobSpawnType.COMMAND) {
return true;
}
// The Dream Dunes biome is the entire underside below Y=0. Its higher
// spawn weight is therefore targeted there without doubling the small
// surface-side Dream Dunes band as well.
if (pos.getY() >= 0 && level.getBiome(pos).is(DREAM_DUNES) && random.nextBoolean()) {
return false;
}
@@ -356,8 +353,6 @@ public class ScorpionEntity extends Monster implements GeoEntity {
ScorpionEntity.this.getNavigation().stop();
return;
}
// This goal overrides MeleeAttackGoal.tick, so the gravity mixin on the
// vanilla method cannot supply the inverted movement frame here.
LivingEntity target = ScorpionEntity.this.getTarget();
if (target != null && ThoraxisUndersideManager.shouldInvertInUnderside(ScorpionEntity.this)) {
ScorpionEntity.this.getNavigation().stop();
@@ -379,9 +374,6 @@ public class ScorpionEntity extends Monster implements GeoEntity {
if (ScorpionEntity.this.isAttackLocked()) {
return;
}
// Inverted melee tick handling replaces vanilla MeleeAttackGoal.tick,
// so vanilla's internal attack timer is not advanced. The Scorpion's
// own cooldown already covers its wind-up and hit timing.
if (this.canPerformAttack(enemy) && ScorpionEntity.this.attackCooldownTicks <= 0) {
ScorpionEntity.this.beginAttack(enemy);
return;
@@ -774,11 +774,9 @@ public class ToreterrorEntity extends Monster implements GeoEntity {
double dh = Math.sqrt(diff.x * diff.x + diff.z * diff.z);
double dy = diff.y;
double gravity = AntarchySettings.waterBombGravity();
// Choose travel time based on horizontal distance at minSpeed, minimum 8 ticks
double t = Math.max(8.0, dh / minSpeed);
double vx = diff.x / t;
double vz = diff.z / t;
// Compensate for gravity accumulating over t ticks
double vy = dy / t + 0.5 * gravity * t;
return new Vec3(vx, vy, vz);
}
@@ -46,10 +46,6 @@ public class UpwardFallingBlockEntity extends Entity {
public UpwardFallingBlockEntity(EntityType<UpwardFallingBlockEntity> type, Level level) {
super(type, level);
// This entity has its own simple upward-flight and landing checks below. Do not
// send it through the normal entity collision solver: Thoraxis can create many of
// these at once while chunks are loading, and swept entity collision is needlessly
// expensive for a block that only collides with the block directly above it.
this.noPhysics = true;
}
@@ -148,8 +144,6 @@ public class UpwardFallingBlockEntity extends Entity {
BlockPos headPos = BlockPos.containing(getX(), getBoundingBox().maxY, getZ());
BlockState above = level().getBlockState(headPos);
// Leaves block the entity but can't hold scaffolding — drop as item, unless this
// instance is allowed to land on leaves like a normal falling block would
if (above.is(BlockTags.LEAVES) && this.breaksOnLeaves) {
dropAndRemove(blockState);
return;
@@ -15,10 +15,6 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.HitResult;
/**
* Thrown out by the worm hook item. Sticks into the first block it hits and stays there,
* anchoring a swing rope back to the thrower until the player detaches.
*/
public class WormHookProjectileEntity extends ThrowableItemProjectile {
private boolean stuck = false;
@@ -302,8 +302,6 @@ public final class AntTeleportHelper {
return safePos;
}
// The bounded search can fail near rough or sparsely-generated terrain.
// Retry once with a wider radius before giving up.
loadArrivalSearchArea(destination, preferredPos, EXPANDED_ARRIVAL_SEARCH_RADIUS);
Vec3 expandedSafePos = findSafeArrivalPositionInYRange(
player, destination, preferredPos, yRange[0], yRange[1],
@@ -393,11 +391,6 @@ public final class AntTeleportHelper {
return null;
}
/**
* Arrival validation needs neighboring chunks for collision checks. Load a
* bounded area up front so unloaded terrain is not mistaken for an unsafe
* destination and rejected prematurely.
*/
public static void loadArrivalSearchArea(ServerLevel destination, BlockPos preferredPos, int searchRadius) {
ChunkPos center = new ChunkPos(preferredPos);
int chunkRadius = (searchRadius >> 4) + 1;
@@ -462,9 +455,6 @@ public final class AntTeleportHelper {
}
}
// Prefer actual generated surfaces. This is especially important in
// Elythia, where the configured spawn height is not necessarily the
// playable surface.
for (BlockPos candidate : surfaceCandidates) {
if (candidate.getY() < minY || candidate.getY() > maxY) {
continue;
@@ -475,15 +465,10 @@ public final class AntTeleportHelper {
}
}
// Elythia arrivals must stay on the generated surface; a vertical scan
// can otherwise select an underground cave floor after a surface miss.
if (elythia) {
return null;
}
// Heightmaps can be stale or unsuitable around structures, so retain a
// bounded exhaustive search as a final generated-terrain attempt in
// dimensions whose configured arrival ranges intentionally allow it.
for (int radius = 0; radius <= searchRadius; radius++) {
for (int xOff = -radius; xOff <= radius; xOff++) {
for (int zOff = -radius; zOff <= radius; zOff++) {
@@ -78,11 +78,6 @@ public class RainbowAntEntity extends BaseAntEntity implements GeoEntity {
return this.hasActiveInfinityDestination() || super.requiresCustomPersistence();
}
/**
* Called on death. If this ant has already been activated (fed its reagent) and Infinity integration is
* enabled, looks for a nearby unlit obsidian Nether-portal frame and, if found, ignites it as a permanent
* physical Infinity Dimensions portal to this ant's assigned dimension.
*/
public boolean tryIgniteInfinityPortalOnDeath() {
if (!this.infinityActivated) {
return false;
@@ -260,7 +260,6 @@ public class TermiteEntity extends BaseAntEntity implements GeoEntity {
}
continue;
}
// North/South faces (dz = ±r)
for (int dx = -r; dx <= r; dx++) {
candidate.set(ox + dx, oy + dy, oz - r);
if (this.isValidWoodTarget(candidate)) {
@@ -273,7 +272,6 @@ public class TermiteEntity extends BaseAntEntity implements GeoEntity {
if (d < bestDistSq) { bestDistSq = d; bestPos = candidate.immutable(); }
}
}
// East/West faces (dx = ±r, corners already covered above)
for (int dz = -r + 1; dz <= r - 1; dz++) {
candidate.set(ox - r, oy + dy, oz + dz);
if (this.isValidWoodTarget(candidate)) {
@@ -669,13 +669,11 @@ public class BasiliskEntity extends Monster implements GeoEntity {
this.stopActiveMovement();
}
/** Scales turn rate by intended movement speed so the long body pivots tighter when slow and wider when fast. */
private static final class BasiliskMoveControl extends MoveControl {
private BasiliskMoveControl(Mob mob) {
super(mob);
}
/** Call this to prevent the move control from reapplying speed this tick. */
public void halt() {
this.operation = MoveControl.Operation.WAIT;
}
@@ -735,7 +733,6 @@ public class BasiliskEntity extends Monster implements GeoEntity {
BasiliskEntity.this.getLookControl().setLookAt(target, 30.0F, 30.0F);
}
// super handles path recalc and cooldown timer
super.tick();
if (target != null && BasiliskEntity.this.isWithinMeleeAttackRange(target)) {
@@ -113,7 +113,6 @@ public class BrutalflyEntity extends Monster implements GeoEntity {
private double currentStrafeAngleOffset = this.random.nextDouble() * (Math.PI * 2.0D);
private boolean spawnedDeathButterflies;
// Cocoon state (server-side)
@Nullable
BlockPos anchorPos;
private int cocoonHits;
@@ -312,7 +311,6 @@ public class BrutalflyEntity extends Monster implements GeoEntity {
}
if (this.getAnimationState() == ANIM_COCOON_IDLE) {
// Will be reset to COCOON after idle ticks counted down
} else if (this.tickCount % 200 == 17 && this.random.nextFloat() < 0.4F) {
this.setAnimationState(ANIM_COCOON_IDLE);
this.cocoonAnimTicks = COCOON_IDLE_ANIM_TICKS;
@@ -77,7 +77,6 @@ public class GlimmerAntBehavior implements GlimmerVariantBehavior {
@Override
public EntityDimensions adultDimensions() {
// Matches the real ant's hitbox.
return EntityDimensions.scalable(0.6375F, 0.2125F);
}
@@ -80,7 +80,6 @@ public class GlimmerAppleCowBehavior implements GlimmerVariantBehavior {
@Override
public EntityDimensions adultDimensions() {
// Matches the real Apple Cow's hitbox (extends vanilla Cow).
return EntityDimensions.scalable(0.9F, 1.4F);
}
@@ -11,10 +11,6 @@ import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.saveddata.SavedData;
/**
* Tracks each player's current Glimmer companion so taming a new one despawns the old,
* even if the old companion is in a different loaded dimension.
*/
public class GlimmerCompanionSavedData extends SavedData {
private static final String ID = "antarchy_glimmer_companions";
private static final String ENTRIES_KEY = "Entries";
@@ -56,11 +52,6 @@ public class GlimmerCompanionSavedData extends SavedData {
);
}
/**
* Records {@code newCompanion} as {@code owner}'s current Glimmer. Any previous
* companion found in a currently loaded dimension isn't removed - it just loses
* its owner and becomes a wild, re-tameable Glimmer again.
*/
public static void replaceCompanion(MinecraftServer server, UUID owner, UUID newCompanion) {
GlimmerCompanionSavedData data = get(server);
UUID previous = data.companionByOwner.put(owner, newCompanion);
@@ -80,10 +71,6 @@ public class GlimmerCompanionSavedData extends SavedData {
}
}
/**
* Removes {@code owner}'s companion record if it currently points at {@code companion},
* used when that Glimmer is captured into a bottle rather than replaced by a new one.
*/
public static void clearCompanion(MinecraftServer server, UUID owner, UUID companion) {
GlimmerCompanionSavedData data = get(server);
if (companion.equals(data.companionByOwner.get(owner))) {
@@ -147,7 +147,6 @@ public class GlimmerEntity extends TamableAnimal implements GeoEntity {
@Override
public void push(Entity entity) {
// no-op: Glimmers pass through other entities
}
@Override
@@ -179,10 +178,6 @@ public class GlimmerEntity extends TamableAnimal implements GeoEntity {
this.entityData.set(ABILITY_ANIM_TICKS, ticks);
}
/**
* Ticks remaining in the daytime despawn fade-out, or 0 if not currently fading.
* Used client-side to fade the render alpha to nothing before the entity is removed.
*/
public int getFadeTicks() {
return this.entityData.get(FADE_TICKS);
}
@@ -499,10 +494,6 @@ public class GlimmerEntity extends TamableAnimal implements GeoEntity {
return GlimmerVariant.random(this.random);
}
/**
* Wild Glimmers are common in Glimmering Pools, but only rarely (and only at night)
* turn up in Ouranwood Forest, the Elythia Meadow, and the Peach Forest.
*/
public static boolean checkGlimmerSpawnRules(EntityType<GlimmerEntity> type, ServerLevelAccessor level,
MobSpawnType spawnType, BlockPos pos, net.minecraft.util.RandomSource random) {
if (!net.minecraft.world.entity.animal.Animal.checkAnimalSpawnRules(type, level, spawnType, pos, random)) {
@@ -601,12 +592,6 @@ public class GlimmerEntity extends TamableAnimal implements GeoEntity {
}
}
/**
* With {@code noPhysics} true, Glimmers never travel through vanilla's normal movement path,
* so the usual body-follows-head catch-up never runs and a stationary Glimmer looking around
* (LookAtPlayerGoal/RandomLookAroundGoal only move the head) ends up with its head rendered
* far past the model's body — this keeps the body snapped within {@link #getMaxHeadYRot()} of it.
*/
private void clampBodyToHeadRotation() {
float maxYaw = this.getMaxHeadYRot();
float delta = Mth.wrapDegrees(this.yHeadRot - this.yBodyRot);
@@ -111,7 +111,6 @@ public class GlimmerFrogBehavior implements GlimmerVariantBehavior {
@Override
public EntityDimensions adultDimensions() {
// Matches vanilla Frog's real hitbox.
return EntityDimensions.scalable(0.5F, 0.5F);
}
@@ -155,7 +154,6 @@ public class GlimmerFrogBehavior implements GlimmerVariantBehavior {
pending.ticksRemaining--;
if (pending.ticksRemaining == TONGUE_ANIM_TICKS - TONGUE_GRAB_TICK) {
// The tongue "catches" the target partway through the animation and reels it in.
entity.playSound(SoundEvents.FROG_TONGUE, 1.0F, 1.0F);
}
if (pending.ticksRemaining <= TONGUE_ANIM_TICKS - TONGUE_GRAB_TICK) {
@@ -10,11 +10,6 @@ import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.Nullable;
/**
* Per-variant behavior for the composite {@link GlimmerEntity}: AI, model/texture selection, and sounds.
* One concrete implementation per {@link GlimmerVariant}, chosen via composition rather than subclassing
* so a single EntityType can be reliably reconstructed across save/load.
*/
public interface GlimmerVariantBehavior {
void registerGoals(GlimmerEntity entity);
@@ -32,124 +27,62 @@ public interface GlimmerVariantBehavior {
SoundEvent deathSound();
/**
* Optional variant-specific interaction (e.g. shearing the Apple Cow variant for a Spirit Apple).
* Return null to fall through to the entity's default interaction handling.
*/
@Nullable
default InteractionResult onInteract(GlimmerEntity entity, Player player, ItemStack stack, InteractionHand hand) {
return null;
}
/**
* Optional per-tick hook for variant-specific server logic (e.g. the Basilisk's petrify gaze).
*/
default void customTick(GlimmerEntity entity) {
}
/**
* Optional hook fired after {@code entity} lands a successful hit on {@code target}
* (e.g. the Frog variant dropping Lumen Froglight when it kills a small Magma Cube).
*/
default void onHurtTarget(GlimmerEntity entity, Entity target) {
}
/**
* Called periodically (roughly once a second) while this Glimmer is tamed and its
* owner is nearby and loaded. Should (re)apply the variant's passive effect with a
* short duration so it naturally lapses if the owner leaves range.
*/
default void tickPassive(GlimmerEntity entity, Player owner) {
}
/**
* Called every server tick (not just the coarse refresh interval) while nearby, for
* passives that need finer-grained bookkeeping than a periodic effect refresh (e.g.
* the Apple Cow's exhaustion dampening).
*/
default void tickPassiveEveryTick(GlimmerEntity entity, Player owner) {
}
/**
* Called once the tick the owner leaves range (or the companion is otherwise no
* longer eligible) so any directly-applied (non-MobEffect) passive state can be undone.
*/
default void clearPassive(GlimmerEntity entity, Player owner) {
}
/**
* Animation (from this variant's own animation file) to play while
* {@link GlimmerEntity#playAbilityAnimation(int)} is active. Null plays no override.
*/
@Nullable
default software.bernie.geckolib.animation.RawAnimation abilityAnimation() {
return null;
}
/**
* Animation to play in place of the default walk loop while moving. Null uses the
* default walk animation (e.g. the Deer switches to its run clip while following its owner).
*/
@Nullable
default software.bernie.geckolib.animation.RawAnimation movingAnimation(GlimmerEntity entity) {
return null;
}
/**
* Animation to play while idle in place of the default idle loop. Null uses the
* shared Glimmer idle animation.
*/
@Nullable
default software.bernie.geckolib.animation.RawAnimation idleAnimation(GlimmerEntity entity) {
return null;
}
/**
* Navigation speed multiplier used while following the owner (see {@link GlimmerFollowOwnerGoal}).
*/
default double followSpeedModifier() {
return 1.15D;
}
/**
* Shared action-bar feedback helper for ability-use messages.
*/
default void sendAbilityMessage(Player owner, net.minecraft.network.chat.Component message) {
owner.displayClientMessage(message, true);
}
/**
* Called every server tick while the owner is nearby and the ability is off cooldown.
* Implementations should check their own trigger condition and, if it fires, perform
* the ability and call {@link GlimmerEntity#startAbilityCooldown()}.
*/
default void tickAbilityCheck(GlimmerEntity entity, Player owner) {
}
/**
* Cooldown duration for this variant's active ability, in ticks.
*/
default int abilityCooldownTicks() {
return 20 * 120;
}
/**
* Per-tick shrink/growth-recovery rate used to decay {@link GlimmerEntity#getGrowthScale()}
* back toward 1.0 after an ability temporarily changes it. 0 means the variant never changes scale.
*/
default double growthDecayPerTick() {
return 0.0D;
}
/**
* Hitbox size matching the real creature this variant is a "spirit" of, rather than
* a single hitbox shared by every variant.
*/
EntityDimensions adultDimensions();
/**
* Defaults to half the adult size, matching vanilla's typical baby scaling.
*/
default EntityDimensions babyDimensions() {
return this.adultDimensions().scale(0.5F);
}
@@ -85,7 +85,6 @@ public class KrakenEntity extends Monster implements GeoEntity, MultipartEntityO
private static final int ATTACK_SWING_RIGHT = 3;
private static final int ATTACK_SLAM = 4;
// Synced animation state values
private static final int ANIM_NONE = 0;
private static final int ANIM_CRY = 1;
private static final int ANIM_GRAB = 2;
@@ -199,7 +198,6 @@ public class KrakenEntity extends Monster implements GeoEntity, MultipartEntityO
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
// idle_controller always loops idle; action_controller layers on top when active
controllers.add(new AnimationController<>(this, "idle_controller", 0, state -> {
if (this.getAnimationState() == ANIM_DEATH) {
return PlayState.STOP;
@@ -646,7 +644,6 @@ public class KrakenEntity extends Monster implements GeoEntity, MultipartEntityO
}
}
// swingRight=true means ATTACK_SWING_RIGHT, which knocks players to the Kraken's LEFT
private void tickSwingAttack(boolean swingRight) {
if (this.actionTicks == 10) {
this.performSwing(swingRight);
@@ -749,9 +746,6 @@ public class KrakenEntity extends Monster implements GeoEntity, MultipartEntityO
return attackState == ATTACK_SLAM;
}
// Determines left vs right based on which side the target is on relative to the Kraken.
// Kraken's right vector is forward x world-up. If target is on the Kraken's right side,
// use swing_right (which knocks them left). If on the left, use swing_left (knocks them right).
private int resolveSwingDirection(LivingEntity target) {
Vec3 forward = this.getViewVector(1.0F);
Vec3 right = forward.cross(new Vec3(0, 1, 0)).normalize();
@@ -765,7 +759,6 @@ public class KrakenEntity extends Monster implements GeoEntity, MultipartEntityO
float damage = (float) this.getAttributeValue(Attributes.ATTACK_DAMAGE);
Vec3 forward = this.getViewVector(1.0F);
// swingRight knocks to Kraken's left (-right), swingLeft knocks to Kraken's right (+right)
Vec3 right = forward.cross(new Vec3(0, 1, 0)).normalize();
Vec3 knockDir = swingRight ? right.scale(-1) : right;
@@ -642,7 +642,6 @@ public class NightmareEntity extends Monster implements GeoEntity {
return this.entityData.get(ANIMATION_STATE);
}
/** Selects the looping flight pose for the isolated computer archive preview instance. */
public void setArchivePreviewFlying() {
this.setAnimationState(ANIM_FLY);
}
@@ -105,7 +105,6 @@ public class KingEntity extends RoyalBossEntity {
private static final double CHAIN_LIGHTNING_JUMP_RANGE = 9.0D;
private static final int ICE_FREEZE_PER_TICK = 7;
private static final int BEHAVIOR_SCORE_CAP = 12;
/** Keep the tree-bound patrol safely inside the authored tree footprint. */
private static final double TREE_ORBIT_RADIUS = 128.0D;
private static final double TREE_ORBIT_ANGLE_STEP = 0.014D;
private static final int TREE_ORBIT_PATH_SAMPLES = 16;
@@ -994,8 +993,6 @@ public class KingEntity extends RoyalBossEntity {
this.kingCombatWaypoint = null;
this.playRoyalSound(AntarchySoundEvents.KING_ROAR.get(), 1.12F);
} else {
// Keep Close Quarters from silently dissolving when the first ring is obstructed.
// The next aerial tick will retry the expanded landing search.
this.kingLandingWaypoint = null;
this.groundAssaultCooldownTicks = 100;
this.kingLandingRetryTicks = LANDING_RETRY_TICKS;
@@ -1077,9 +1074,6 @@ public class KingEntity extends RoyalBossEntity {
if (this.level().noCollision(this, fallbackBox)) {
return fallback;
}
// Last resort: land directly beneath the King if the target ring is obstructed.
// This still gives Close Quarters a committed ground sequence instead of silently
// remaining airborne over difficult tree geometry.
double directY = GravityApi.isGravityInverted(this)
? this.position().y - 0.1D
: this.groundYBelow(this.getX(), this.getZ()) + 0.1D;
@@ -1143,8 +1137,6 @@ public class KingEntity extends RoyalBossEntity {
}
}
if (orbitWaypoint == null && treeBoundCombat) {
// If the tree blocks the next orbital lane, turn away and try the opposite side
// before falling back to a clear target-relative position.
this.kingStrafeDirection *= -1;
double angle = currentAngle + this.kingStrafeDirection * COMBAT_ORBIT_ANGLE_STEP;
double x = target.getX() + Math.cos(angle) * range;
@@ -1173,7 +1165,6 @@ public class KingEntity extends RoyalBossEntity {
+ this.random.nextInt(COMBAT_WAYPOINT_VARIANCE + 1);
this.kingCombatProgressPosition = this.position();
this.kingCombatProgressTicks = 0;
// Keep a consistent orbit direction for several passes so movement reads as circling.
}
private void stabilizeKingRotation() {
@@ -248,7 +248,6 @@ public class RoyalBlackHoleEntity extends Entity implements GeoEntity, TimeDilat
return AntarchySettings.queenBlackHoleBlockSuctionCap();
}
/** Returns the center of the animated black-hole cube in world coordinates. */
@Override
public Vec3 timeDilationCenter() {
return this.effectCenter();
@@ -344,7 +344,6 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
return 0.35D;
}
/** Lets a boss provide a bespoke air/ground cadence without changing the other royal encounter. */
protected boolean managesOwnCombatLocomotion() {
return false;
}
@@ -357,12 +356,10 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
return 1.3D;
}
/** Prevents normal head/body scheduling while a bespoke movement sequence owns the boss. */
protected boolean blocksRoyalAttacksForMovement() {
return false;
}
/** Prevents new beam volleys while a bespoke attack has reserved the heads. */
protected boolean blocksRoyalBeamScheduling() {
return false;
}
@@ -380,17 +377,14 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
protected void onRoyalPhaseTransitionCompleted(Phase nextPhase) {
}
/** Allows a boss to tune its head-bite concurrency without changing the other royal boss. */
protected int maxConcurrentHeadAttacks(Phase phase) {
return phase.maxConcurrentHeadAttacks();
}
/** Allows a boss to tune bite pacing without changing the other royal boss. */
protected int biteCooldownTicks(Phase phase) {
return Math.max(10, Mth.floor(AntarchySettings.royalBossBiteCooldownTicks() * phase.cooldownScale()));
}
/** Allows either royal boss to tune bite damage without changing the other. */
protected double biteDamageMultiplier() {
return AntarchySettings.royalBossBiteDamageMultiplier();
}
@@ -825,7 +819,6 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
return phase.maxConcurrentHeadAttacks();
}
/** Uses the beam controller's smoothed target point instead of the boss body's forward axis. */
protected boolean royalBeamUsesTrackedAim() {
return false;
}
@@ -862,7 +855,6 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
this.onRoyalPhaseTransitionStarted(previousPhase, nextPhase);
}
/** Returns the live players currently participating in the encounter. */
protected final List<ServerPlayer> royalEncounterPlayers(ServerLevel level) {
double range = Math.max(32.0D, this.getAttributeValue(Attributes.FOLLOW_RANGE));
LinkedHashSet<ServerPlayer> players = new LinkedHashSet<>(this.bossEvent.getPlayers());
@@ -68,7 +68,6 @@ public class RoyalElementalProjectileEntity extends ThrowableProjectile implemen
return projectile;
}
/** Solves a discrete ballistic lead against the projectile's drag and gravity. */
public static Vec3 aimDirection(Vec3 origin, LivingEntity target, RoyalBeamElement element) {
double speed = element == RoyalBeamElement.ICE ? ICEBALL_SPEED : FIREBALL_SPEED;
double gravity = element == RoyalBeamElement.ICE ? 0.006D : 0.018D;
@@ -15,7 +15,6 @@ public final class StandYourGroundDecree implements RoyalDecree {
}
@Override public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
if (target instanceof net.minecraft.server.level.ServerPlayer player && player.isFallFlying()) {
// Gliding carries unavoidable momentum; begin measuring again from the landing point.
this.anchors.put(target.getUUID(), target.position());
return Evaluation.COMPLIANT;
}
@@ -20,7 +20,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/** Loads Computer Scientist offers from data/computer_scientist_trades/*.json. */
public final class ComputerScientistTradeManager extends SimpleJsonResourceReloadListener {
private static final Gson GSON = new Gson();
private static final String DIRECTORY = "computer_scientist_trades";
@@ -113,13 +113,6 @@ public final class DrTrayaurusTradeManager extends SimpleJsonResourceReloadListe
}
}
/**
* One side of a trade. {@code components} is optional: on {@code sell} it is a data component
* patch applied to the result (enchantments, custom name, ...); on {@code buy}/{@code second_buy}
* it is a component predicate the offered stack must match exactly for each listed component.
* It is kept as raw JSON and parsed per offer because components such as enchantments need
* registry access, which the reload listener does not have.
*/
private record StackEntry(ResourceLocation itemId, int count, Optional<JsonElement> components) {
private static final Codec<StackEntry> CODEC = RecordCodecBuilder.create(instance -> instance.group(
ResourceLocation.CODEC.fieldOf("item").forGetter(StackEntry::itemId),
@@ -162,7 +155,6 @@ public final class DrTrayaurusTradeManager extends SimpleJsonResourceReloadListe
if (this.components.isEmpty()) {
return Optional.of(new ItemCost(item.get(), this.count));
}
// A predicate that fails to parse drops the trade rather than accepting any stack.
return DataComponentPredicate.CODEC
.parse(RegistryOps.create(JsonOps.INSTANCE, registries), this.components.get())
.resultOrPartial(message -> LOGGER.error("Dr. Trayaurus trade {}: bad components: {}", this.itemId, message))
@@ -51,11 +51,6 @@ public final class AntarchyFluidChecks {
return BILE_VEIN_ID.equals(blockId);
}
/**
* Bile always wins: worldgen foliage must not anchor on or near bile fluid or its solid
* bile_vein shell, since cyst/vein features can carve into a neighboring chunk after this
* chunk's vegetation has already been placed.
*/
public static boolean hasBileNearby(LevelAccessor level, BlockPos center, int radius) {
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
for (int dx = -radius; dx <= radius; dx++) {
@@ -21,15 +21,6 @@ import net.minecraft.world.phys.AABB;
import java.util.HashMap;
import java.util.Map;
/**
* Tops up stink bug / rolly polly populations near players in Cavaryn.
*
* Vanilla's NaturalSpawner picks a spawn Y uniformly at random between the dimension's min_y
* and a column's heightmap top. In Cavaryn that range spans the full 208-block dimension height,
* but any given column's actual floor only occupies a sliver of that, so the vanilla algorithm
* almost never lands on real ground even though floor itself is common. This scans a column
* directly for a real floor spot instead.
*/
public final class CavarynCreatureSpawner {
private static final ResourceKey<Level> CAVARYN = ResourceKey.create(
net.minecraft.core.registries.Registries.DIMENSION,
@@ -70,7 +70,6 @@ public class BigBerthaItem extends SwordItem implements GeoItem {
private static final int TORETERROR_COOLDOWN_TICKS = 200;
private static final int TORETERROR_SHAKE_TICKS = 25;
/** Client-side only: how many ticks of camera shake remain from a Toreterror landing. */
public static int clientShakeTicks = 0;
private static final ResourceLocation ATTACK_RANGE_MODIFIER_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "big_bertha_attack_range");
private final Tier tier;
@@ -178,7 +177,7 @@ public class BigBerthaItem extends SwordItem implements GeoItem {
}
if (isToreterrorJumping(stack) && player.getMainHandItem() == stack) {
player.fallDistance = 0.0F; // prevent fall damage during the crash-down
player.fallDistance = 0.0F;
boolean launched = readInt(stack, TORETERROR_LAUNCHED_TAG) == 1;
if (!launched && !player.onGround()) {
CustomData.update(DataComponents.CUSTOM_DATA, stack, tag -> tag.putInt(TORETERROR_LAUNCHED_TAG, 1));
@@ -38,7 +38,6 @@ public class BloodCrystalShardItem extends Item {
return InteractionResultHolder.fail(stack);
}
// Restore armor shields first, then apple shields
if (armorLost > 0) {
access.antarchy$setArmorShieldsActive(access.antarchy$getArmorShieldsActive() + 1);
access.antarchy$setArmorShieldLostCount(armorLost - 1);
@@ -22,7 +22,6 @@ public final class BrutalflyElytraItem extends ElytraItem {
private static final ResourceLocation ARMOR_MODIFIER_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "brutalfly_elytra_armor");
private static final ResourceLocation TOUGHNESS_MODIFIER_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "brutalfly_elytra_toughness");
// Set by NeoForge client setup to return the actual bound key name
public static Supplier<Component> FLAP_KEY_NAME = () -> Component.literal("Shift");
public BrutalflyElytraItem(Properties properties) {
@@ -377,8 +377,6 @@ public class GravityGunItem extends Item implements GeoItem {
Vec2 holdRotation = getHoldRotation(player);
heldTarget.setNoGravity(true);
// Snap back only when the held entity has drifted badly; otherwise drive it with
// velocity so the client can interpolate the motion smoothly between server updates.
if (movement.lengthSqr() > 16.0D) {
heldTarget.moveTo(holdPosition.x, holdPosition.y, holdPosition.z, holdRotation.x, holdRotation.y);
heldTarget.setDeltaMovement(Vec3.ZERO);
@@ -11,20 +11,10 @@ import java.util.HashSet;
import java.util.Queue;
import java.util.Set;
/**
* Client-side cave finder for Moggles.
*
* <p>Every {@link #SCAN_INTERVAL} ticks, BFS-maps the player's current connected
* air space, then scans outward to find the nearest underground air pocket that
* is NOT part of that space. The result is stored in {@link #caveTarget} and
* read each tick by the particle renderer.
*/
public final class MogglesCaveDetector {
private static final int SCAN_INTERVAL = 40;
/** How far to flood-fill the player's own air pocket before stopping. */
private static final int PLAYER_SPACE_LIMIT = 8;
/** Minimum number of air neighbors a candidate block must have (filters tiny cracks). */
private static final int MIN_AIR_NEIGHBORS = 2;
private static volatile BlockPos caveTarget = null;
@@ -36,7 +26,6 @@ public final class MogglesCaveDetector {
return caveTarget;
}
/** Call once per client tick while Moggles are equipped. */
public static void tick(Player player, Level level) {
if (--cooldown > 0) return;
cooldown = SCAN_INTERVAL;
@@ -51,11 +40,10 @@ public final class MogglesCaveDetector {
private static BlockPos scan(Player player, Level level) {
BlockPos origin = player.blockPosition();
// BFS through air from the player's feet to map their current open space.
Set<Long> playerSpace = new HashSet<>();
Queue<BlockPos> queue = new ArrayDeque<>();
BlockPos eyePos = origin.above(); // also include the eye block
BlockPos eyePos = origin.above();
for (BlockPos seed : new BlockPos[]{origin, eyePos}) {
if (level.isLoaded(seed) && level.getBlockState(seed).isAir()) {
long key = seed.asLong();
@@ -77,7 +65,6 @@ public final class MogglesCaveDetector {
}
}
// Scan the wider radius for underground air NOT in the player's space.
BlockPos nearest = null;
double nearestDistSq = Double.MAX_VALUE;
int r = (int) AntarchySettings.mogglesVisionRadius();
@@ -91,7 +78,7 @@ public final class MogglesCaveDetector {
if (playerSpace.contains(key)) continue;
if (!level.isLoaded(pos)) continue;
if (!level.getBlockState(pos).isAir()) continue;
if (level.canSeeSky(pos)) continue; // ignore surface air
if (level.canSeeSky(pos)) continue;
int airNeighbors = 0;
for (Direction dir : Direction.values()) {
@@ -122,6 +122,6 @@ public class RoyalGuardianShieldItem extends ShieldItem {
private static boolean isInCommandLookCone(Player player, Mob mob) {
var direction = mob.getBoundingBox().getCenter().subtract(player.getEyePosition()).normalize();
return player.getViewVector(1.0F).dot(direction) >= 0.9063078D; // 25-degree half-angle
return player.getViewVector(1.0F).dot(direction) >= 0.9063078D;
}
}
@@ -31,7 +31,6 @@ import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.joml.Vector3f;
/** Player-safe kernels for the Royal Guardian Sword's King-derived elemental modes. */
public final class RoyalGuardianSwordAbilities {
private static final ThreadLocal<Integer> SECONDARY_DAMAGE_DEPTH = ThreadLocal.withInitial(() -> 0);
private static final ThreadLocal<MeleeAttackContext> MELEE_ATTACK = new ThreadLocal<>();
@@ -31,7 +31,7 @@ import java.util.List;
public class UltimateCrossbowItem extends CrossbowItem {
private static final int MAX_ARROWS = 16;
private static final int FIRE_COOLDOWN_TICKS = 5; // 4 shots/sec
private static final int FIRE_COOLDOWN_TICKS = 5;
private static final float SHOOTING_POWER = 3.15F;
private static final double VANILLA_CROSSBOW_ARROW_DAMAGE = 7.0D;
private static final String RESERVE_PROJECTILES_TAG = "UltimateCrossbowProjectiles";
@@ -110,11 +110,9 @@ public class UltimateCrossbowItem extends CrossbowItem {
toFire.add(arrow);
}
// Temporarily set only the arrows for this shot so performShooting fires exactly them
stack.set(DataComponents.CHARGED_PROJECTILES, ChargedProjectiles.of(toFire));
this.performShooting(level, player, hand, stack, SHOOTING_POWER, 1.0F, null);
// performShooting clears CHARGED_PROJECTILES; restore remaining valid arrows if any
saveLoadedProjectiles(stack, player.registryAccess(), all);
}
@@ -17,17 +17,6 @@ import net.minecraft.world.level.block.state.properties.RailShape;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
/**
* A direct mirror of {@code AbstractMinecart.moveAlongTrack}/{@code getPos}/{@code getPosOffs},
* adapted for ceiling-mounted track. The world-Y meaning of "ascending"/"descending" does not
* need to be sign-flipped anywhere here — lower world Y is lower world Y whether a rail rests on
* a floor or hangs from a ceiling. What actually differs from vanilla is: the rail sits near the
* top of its cell instead of near the bottom (see {@link AntimetalRailHelper#attachY}), support
* is required above instead of below, and the "which cell owns this position" disambiguation
* checks the cell above instead of the cell below. Everything else — the exit-projection math,
* the slope acceleration constant, the player-push nudge, using real collision-checked
* {@code Entity.move} rather than a hand-rolled collision test — is a straight port.
*/
public final class AntimetalMinecartPhysics {
private static final double SLOPE_ACCEL = 0.0078125D;
private static final double MAX_RAIL_SPEED = 0.4D;
@@ -8,7 +8,6 @@ import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.Level;
/** Handles Antarchy-specific game progress sent by AntOS game extensions. */
public final class AntarchyGameNetworkHandler {
private static BiConsumer<ServerPlayer, AntarchyGameResultPayload> resultSender = (player, result) -> { };
@@ -3,7 +3,6 @@ package com.craisinlord.antarchy.content.network;
import net.minecraft.core.BlockPos;
import java.util.function.Consumer;
/** Small Antarchy game-progress bridge over the AntOS computer session. */
public final class AntarchyGameNetworking {
private static Consumer<AntarchyGamePayload> sender = payload -> { };
private AntarchyGameNetworking() { }
@@ -13,12 +13,6 @@ import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
/**
* Converts an unlit obsidian frame near a killed rainbow ant into a real, permanent Infinite Dimensions
* portal to that ant's assigned dimension. Lights the frame as a normal vanilla Nether portal first, then
* hands it to Infinity's own portal-creation pipeline (the same one used when a book is thrown into a lit
* portal), so the result behaves exactly like any other physical Infinity portal from then on.
*/
public final class RainbowPortalIgniter {
private static final int SEARCH_RADIUS = 2;
@@ -170,7 +170,6 @@ public final class PortalGunSavedData extends SavedData {
return clearMatching(server, record -> record.ownerId() != null && ownerIds.contains(record.ownerId()));
}
/** Clears portal pairs for guns that an owner no longer has in their player inventory. */
public static int clearMissingGuns(ServerPlayer player) {
PortalGunSavedData data = get(player.serverLevel().getServer());
if (data.pairs.isEmpty()) {
@@ -12,16 +12,6 @@ import net.minecraft.world.phys.Vec3;
import java.util.ArrayList;
import java.util.List;
/**
* Tracks the path of a taut rope from a fixed anchor point to a moving end point (the
* player's eyes), bending around block corners when the straight-line path would otherwise
* clip through terrain. The anchor never moves (the worm hook is stuck in a block), so this
* only needs to add/remove bends on the player's side of the rope.
*
* Ported from the corner-wrapping algorithm in Yyon's GrappleMod (GPL-3.0), adapted from a
* custom vector class to vanilla Vec3 and from a moving-hook/moving-player pair to a fixed
* anchor.
*/
public final class WormHookRope {
private static final double BEND_OFFSET = 0.05D;
private static final double INTO_BLOCK = 0.05D;
@@ -44,7 +34,6 @@ public final class WormHookRope {
this.prevEnd = end;
}
/** Recomputes the bend list for the current anchor/end positions. Anchor must stay constant. */
public void update(Entity context, Vec3 anchor, Vec3 end, double ropeLength) {
this.ropeLength = ropeLength;
Level level = context.level();
@@ -52,7 +41,6 @@ public final class WormHookRope {
points.set(0, anchor);
points.set(points.size() - 1, end);
// Unwind bends the rope has swung clear of.
while (points.size() > 2) {
int index = points.size() - 2;
Vec3 closest = points.get(index);
@@ -153,12 +141,10 @@ public final class WormHookRope {
topSides.remove(index);
}
/** The pivot point closest to the moving end: either the anchor, or the last bend before it. */
public Vec3 getPivot() {
return points.get(points.size() - 2);
}
/** Rope length used up getting from the anchor to the pivot (0 if the rope has no bends). */
public double getConsumedLength() {
double dist = 0;
for (int i = 0; i < points.size() - 2; i++) {
@@ -26,7 +26,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/** Applies Antarchy-owned additions to existing vanilla jigsaw pools without replacing them. */
public final class VillagePoolAdditions {
private static final Gson GSON = new Gson();
private static final String DIRECTORY = "structure_pool_additions";
@@ -101,8 +100,6 @@ public final class VillagePoolAdditions {
templates.add(Pair.of(poolElement, weight));
accessor.integratedapi_setRawTemplates(templates);
// StructureTemplatePool caches its weighted list in addition to the raw entries.
// Keep both views synchronized so the new house is immediately eligible.
ObjectArrayList<StructurePoolElement> expandedTemplates = new ObjectArrayList<>(accessor.integratedapi_getTemplates());
for (int i = 0; i < weight; i++) {
expandedTemplates.add(poolElement);
@@ -34,7 +34,6 @@ public class TermiteNestFeature extends SurfaceAntNestFeature {
protected BlockPos resolveNestPos(WorldGenLevel level, BlockPos origin) {
int x = origin.getX();
int z = origin.getZ();
// Start from the placement height so roofed dimensions like Cavaryn get nests on every cave layer, not just the top one.
int startY = Math.min(origin.getY(), level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, x, z) - 1);
int minY = level.getMinBuildHeight() + 1;
@@ -8,12 +8,6 @@ import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.VineBlock;
import net.minecraft.world.level.block.state.BlockState;
/**
* Bile always wins on placement, but once a vine/creeproots/molting-vine column already exists,
* bile carving and oozing must not eat the block it's anchored to — otherwise a later-generated
* neighboring chunk's bile cyst/vein can undermine foliage placed earlier and leave it floating
* or pop it as a dropped item.
*/
public final class CavarynFoliageGuard {
private CavarynFoliageGuard() {
}
@@ -67,13 +67,13 @@ public class CoralSpikeFeature extends Feature<NoneFeatureConfiguration> {
CoralSet[] coralSets = coralSets();
CoralSet coral = coralSets[random.nextInt(coralSets.length)];
int baseRadius = 2 + random.nextInt(2); // 2-3 wide at base
int totalHeight = 20 + random.nextInt(15); // 20-34 blocks tall
int baseRadius = 2 + random.nextInt(2);
int totalHeight = 20 + random.nextInt(15);
double curveAngle = random.nextDouble() * Math.PI * 2;
double curveDX = Math.cos(curveAngle);
double curveDZ = Math.sin(curveAngle);
double maxCurve = 4.0 + random.nextDouble() * 5.0; // 4-9 block lean at tip
double maxCurve = 4.0 + random.nextDouble() * 5.0;
boolean placed = false;
@@ -81,12 +81,10 @@ public class CoralSpikeFeature extends Feature<NoneFeatureConfiguration> {
int blockY = floorY + dy;
double progress = (double) dy / totalHeight;
// Quadratic lean -- slow at base, bending hard near tip
double curveOffset = maxCurve * progress * progress;
double centerX = origin.getX() + curveDX * curveOffset;
double centerZ = origin.getZ() + curveDZ * curveOffset;
// Taper: full width for bottom 25%, then narrows sharply to a point
double taperT = Math.max(0.0, (progress - 0.25) / 0.75);
int radius = (int) Math.max(0, baseRadius * (1.0 - taperT * taperT * 1.3));
@@ -147,7 +145,6 @@ public class CoralSpikeFeature extends Feature<NoneFeatureConfiguration> {
}
}
// Floor scatter: coral plants, fans, and sea pickles around the base
int decorCount = 10 + random.nextInt(12);
for (int i = 0; i < decorCount; i++) {
int fx = origin.getX() + random.nextInt(13) - 6;
@@ -192,7 +189,6 @@ public class CoralSpikeFeature extends Feature<NoneFeatureConfiguration> {
}
}
} else if (decorInWater) {
// Sea pickle cluster -- only underwater
BlockState pickle = Blocks.SEA_PICKLE.defaultBlockState()
.setValue(SeaPickleBlock.PICKLES, 1 + random.nextInt(4));
if (pickle.canSurvive(level, decorPos)) {
@@ -16,11 +16,6 @@ import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.Climate;
import net.minecraft.world.level.biome.MultiNoiseBiomeSource;
/**
* Plain multi-noise biome source with one addition: everything at or above
* {@code cloud_sea_min_y} is the cloud sea. Below that line, biome selection is
* identical to {@code minecraft:multi_noise} over the same list minus the cloud sea entry.
*/
public final class ElythiaBiomeSource extends BiomeSource {
private static final ResourceKey<Biome> CLOUD_SEA = ResourceKey.create(
Registries.BIOME,
@@ -47,7 +42,6 @@ public final class ElythiaBiomeSource extends BiomeSource {
.filter(holder -> holder.is(CLOUD_SEA))
.findFirst()
.orElse(null);
// Keep the cloud sea out of the noise search so terrain biomes resolve exactly as before.
this.delegate = MultiNoiseBiomeSource.createFromList(new Climate.ParameterList<>(
parameters.values().stream()
.filter(entry -> !entry.getSecond().is(CLOUD_SEA))
@@ -10,10 +10,6 @@ import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
/**
* Scatters solid puffs of {@link AntarchyObjects#CLOUD_BLOCK} sized and shaped
* anywhere from thin wispy veils to large, dense masses, with a softly feathered edge.
*/
public final class ElythiaCloudFeature extends Feature<NoneFeatureConfiguration> {
public ElythiaCloudFeature(Codec<NoneFeatureConfiguration> codec) {
super(codec);
@@ -76,9 +72,6 @@ public final class ElythiaCloudFeature extends Feature<NoneFeatureConfiguration>
int yRange = Math.max(1, radiusY);
int zRange = Math.max(1, radiusZ);
BlockState cloud = AntarchyObjects.CLOUD_BLOCK.get().defaultBlockState();
// Clouds are solid puffs, not hollow shells — only the outer rind is feathered for a
// soft, ragged edge. Wispy clouds get a lower edge-fill chance so they read as thin
// and sparse without turning the whole body into visible holes.
float edgeFillChance = size == CloudSize.WISPY ? 0.55F : 0.85F;
double edgeStart = 0.7D;
@@ -5,21 +5,6 @@ import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.util.KeyDispatchDataCodec;
import net.minecraft.world.level.levelgen.DensityFunction;
/**
* Custom density function that carves narrow river channels in Elythia.
*
* Logic:
* - Outside river-erosion territory (erosion <= EROSION_THRESHOLD): behaves identically
* to the original "-0.06 * erosion" term in elythia_surface.json.
* - Inside river-erosion territory (erosion > EROSION_THRESHOLD): additionally applies
* a strong negative carve when the ridges value is near 0, producing a narrow channel.
* The carve tapers quadratically from full depth at ridges=0 to zero at |ridges|=CHANNEL_HALF_WIDTH.
*
* Tuning:
* - EROSION_THRESHOLD: raise to make rivers rarer, lower to make them appear in more terrain
* - CHANNEL_HALF_WIDTH: controls channel width in blocks (wider noise band = wider river)
* - CHANNEL_DEPTH: controls how far below sea level the river floor sits
*/
public record ElythiaRiverCarveFunction(
DensityFunction erosion,
DensityFunction ridges
@@ -35,16 +20,9 @@ public record ElythiaRiverCarveFunction(
public static final KeyDispatchDataCodec<ElythiaRiverCarveFunction> KEY_CODEC =
KeyDispatchDataCodec.of(CODEC);
// Erosion must exceed this for river carving to engage
private static final double EROSION_THRESHOLD = 0.70;
// Half-width of the channel in ridges-space. Ridges ranges roughly -1 to 1 across
// the landscape; this controls the physical width of the carved channel.
private static final double CHANNEL_HALF_WIDTH = 0.08;
// Maximum density reduction applied at the center of the channel.
// ~0.35 pushes the terrain floor roughly 25 blocks below its normal level,
// landing below sea level (63) so the channel fills with water naturally.
private static final double CHANNEL_DEPTH = 0.35;
// Matches the original elythia_surface.json erosion multiplier so non-river areas are unchanged
private static final double BASE_EROSION_FACTOR = -0.06;
@Override
@@ -31,8 +31,8 @@ public class FallenOuranwoodFeature extends Feature<NoneFeatureConfiguration> {
BlockPos origin = context.origin();
Direction.Axis axis = random.nextBoolean() ? Direction.Axis.X : Direction.Axis.Z;
int length = 36 + random.nextInt(44); // 36–79 blocks long
int outerRadius = 1 + random.nextInt(3); // 1–3 (cross-section up to 7-wide)
int length = 36 + random.nextInt(44);
int outerRadius = 1 + random.nextInt(3);
boolean hollow = outerRadius >= 2;
Block ouranwoodLog = BuiltInRegistries.BLOCK.getOptional(
@@ -46,7 +46,6 @@ public class FallenOuranwoodFeature extends Feature<NoneFeatureConfiguration> {
BlockState woodState = AntarchyObjects.MOSSY_OURANWOOD_WOOD.get().defaultBlockState()
.setValue(RotatedPillarBlock.AXIS, Direction.Axis.Y);
// Pre-generate a smoothed damage profile along the length (0=solid, 1=gap)
float[] damage = new float[length];
for (int i = 0; i < length; i++) damage[i] = random.nextFloat();
for (int pass = 0; pass < 4; pass++) {
@@ -54,7 +53,6 @@ public class FallenOuranwoodFeature extends Feature<NoneFeatureConfiguration> {
damage[i] = (damage[i - 1] + damage[i] * 2 + damage[i + 1]) / 4f;
}
}
// Bias upward so more sections are heavily damaged
for (int i = 0; i < length; i++) damage[i] = damage[i] * damage[i];
int anchorY = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, origin.getX(), origin.getZ());
@@ -39,7 +39,7 @@ public class FungalMushroomFeature extends Feature<NoneFeatureConfiguration> {
double maxLean = 2.0 + random.nextDouble() * 3.5;
int baseY = origin.getY();
int stemOffset = stemSize == 2 ? 0 : -1; // center 3x3 on origin
int stemOffset = stemSize == 2 ? 0 : -1;
BlockState stemPore = Blocks.MUSHROOM_STEM.defaultBlockState()
.setValue(HugeMushroomBlock.NORTH, false)
@@ -98,7 +98,6 @@ public class FungalMushroomFeature extends Feature<NoneFeatureConfiguration> {
double nomRadius = baseCapRadius - cl;
if (nomRadius < 0) break;
// The cap center also shifts slightly with lean for a drooping overhang feel
double layerCapX = capCenterX + leanDX * cl * 0.3;
double layerCapZ = capCenterZ + leanDZ * cl * 0.3;
@@ -30,7 +30,6 @@ import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
/** Places the authored King's Tree as independently generated chunk slices on a fixed world grid. */
public final class KingsTreeGridFeature extends Feature<NoneFeatureConfiguration> {
private static final Map<ServerLevel, Set<Long>> CLAIMED_TREE_KINGS = new WeakHashMap<>();
private static final ConcurrentLinkedQueue<PendingKingSpawn> PENDING_KING_SPAWNS = new ConcurrentLinkedQueue<>();
@@ -573,8 +573,6 @@ public class OuranwoodTreeFeature extends Feature<OuranwoodTreeConfiguration> {
return;
}
// The tick is scheduled here on the WorldGenLevel because onPlace() is never
// called during world generation, so the block cannot self-schedule.
int squirrelCount = 1 + random.nextInt(3);
BlockPos markerPos = floorBlocks.get(0);
setBlock(level, markerPos, AntarchyObjects.SQUIRREL_NEST_BLOCK.get().defaultBlockState()
@@ -687,13 +685,8 @@ public class OuranwoodTreeFeature extends Feature<OuranwoodTreeConfiguration> {
}
protected void placeCaterpillarChrysalis(WorldGenLevel level, BlockPos origin, OuranwoodTreeConfiguration config, RandomSource random, BlockPos canopyCenter, int canopyRadius, int canopyDepth) {
// Tree-grown chrysalis placement is intentionally disabled for now.
}
/**
* Finds a log or leaf block in the canopy that has sufficient clear space beneath it.
* {@code clearBelow} is the vertical depth to check; {@code clearRadius} is the XZ half-width (0 = 1x1, 1 = 3x3).
*/
protected @Nullable BlockPos findCanopyAnchor(WorldGenLevel level, RandomSource random, BlockPos canopyCenter, int canopyRadius, int canopyDepth, int clearBelow, int clearRadius, int attempts) {
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
int r = Math.max(1, canopyRadius - 1);
@@ -831,7 +824,6 @@ public class OuranwoodTreeFeature extends Feature<OuranwoodTreeConfiguration> {
int worldX = origin.getX() + x;
int worldZ = origin.getZ() + z;
// Raise soil to form a mound around the base (from adaptTerrain)
int currentTopY = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, worldX, worldZ) - 1;
int falloff = (int) Math.floor(Math.sqrt(distanceSq) / 2.1D);
int desiredTopY = baseY - falloff + (distanceSq <= trunkRadiusSq ? 0 : random.nextInt(2));
@@ -4,9 +4,6 @@ import org.spongepowered.asm.mixin.extensibility.IMixinConfig;
import org.spongepowered.asm.mixin.extensibility.IMixinErrorHandler;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
/*
* Keeps bad mixins from hard-crashing startup.
*/
public final class AntarchyMixinErrorHandler implements IMixinErrorHandler {
private static final String BROKEN_MARVEL_STELLARIS_MIXIN =
"net.tintankgames.marvel.mixin.integration.stellaris.DimensionOxygenManagerMixin";
@@ -7,9 +7,6 @@ import org.spongepowered.asm.mixin.Mixins;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
/*
* Mixin plugin for compat-gated mixins and optional deps.
*/
public final class AntarchyMixinPlugin implements IMixinConfigPlugin {
private static final AntarchyRangedAttackPatcher RANGED_ATTACK_PATCHER = new AntarchyRangedAttackPatcher();
@@ -42,14 +39,9 @@ public final class AntarchyMixinPlugin implements IMixinConfigPlugin {
&& classPresent("com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod");
}
if (mixinClassName.startsWith("com.craisinlord.antarchy.mixins.compat.alexscaves.")) {
// The target class was found above. Checking the target itself avoids depending on
// whether a loader exposes Alex's Caves' entrypoint resource to this classloader.
return true;
}
if (mixinClassName.endsWith(".VillagerTradesMixin")) {
// Trade registration is platform-driven on every supported loader now. Keeping the
// static VillagerTrades class-init mixin around risks touching AntarchyObjects before
// registration is finished on Fabric and duplicates trades on event-driven loaders.
return false;
}
return true;
@@ -15,9 +15,6 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(BaseFireBlock.class)
/*
* Lets dream fire pick the floor or ceiling variant from the same support tag.
*/
public abstract class DreamFireBlockMixin {
private static final ResourceLocation DREAM_FIRE_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "dream_fire");
private static final ResourceLocation DREAM_CEILING_FIRE_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "dream_fire_ceiling");
@@ -13,7 +13,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(LivingEntity.class)
public abstract class GlimmeringDamageImmunityMixin {
// Magic damage (potions, spells) is tagged bypasses_armor, so it's excluded
@Inject(method = "hurt", at = @At("HEAD"), cancellable = true)
private void antarchy$glimmeringIgnoresAttacks(DamageSource source, float amount, CallbackInfoReturnable<Boolean> cir) {
LivingEntity self = (LivingEntity) (Object) this;
@@ -9,8 +9,6 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
// LivingEntity.isPushable()/isPickable() are full overrides of Entity's versions (they don't call
// super), so this has to target LivingEntity directly, not Entity, or the injected code never runs.
@Mixin(LivingEntity.class)
public abstract class GlimmeringPushableMixin {
@Inject(method = "isPushable", at = @At("RETURN"), cancellable = true)
@@ -26,9 +24,6 @@ public abstract class GlimmeringPushableMixin {
}
}
// Projectiles (and entity-picking in general) skip targets that aren't isPickable(), so this
// is what actually lets arrows/tridents/etc. pass through a glimmering entity instead of
// colliding with it; the damage-immunity mixin alone only stopped the damage, not the impact.
@Inject(method = "isPickable", at = @At("RETURN"), cancellable = true)
private void antarchy$glimmeringNotPickable(CallbackInfoReturnable<Boolean> cir) {
if (!cir.getReturnValueZ()) {
@@ -33,7 +33,6 @@ public abstract class PoiTypesMixin {
BuiltInRegistries.POINT_OF_INTEREST_TYPE.getHolder(key)
.ifPresent(holder -> callback.setReturnValue(Optional.of(holder)));
} catch (IllegalStateException ignored) {
// Registration can be queried during bootstrap before loader bindings finish.
}
}
}
@@ -8,7 +8,6 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/** Captures attack charge before vanilla resets the player's attack-strength ticker. */
@Mixin(Player.class)
public abstract class RoyalGuardianPlayerAttackMixin {
@Inject(method = "attack", at = @At("HEAD"))
@@ -14,9 +14,6 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ServerPlayerGameMode.class)
/*
* Keeps custom sapling stage updates synced like vanilla.
*/
public abstract class ServerPlayerGameModeMixin {
@Shadow protected ServerLevel level;
@Shadow @Final protected ServerPlayer player;
@@ -8,11 +8,6 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
/**
* Lets the Undertrial's vanilla TrialSpawner path spawn entities whose normal
* placement predicate assumes floor support. TrialSpawner already performs
* its own no-collision and obstruction checks before this method is reached.
*/
@Mixin(SpawnPlacements.class)
public abstract class UndertrialSpawnPlacementsMixin {
@Inject(method = "checkSpawnRules", at = @At("RETURN"), cancellable = true)
@@ -18,8 +18,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(LivingEntityRenderer.class)
public abstract class GlimmeringTranslucencyMixin<T extends LivingEntity> {
// Vertex-color alpha applied to the base skin render while glimmering, on top of the recolor
// overlay, so the body itself reads as see-through rather than just tinted.
private static final int GLIMMERING_ALPHA = 0x40;
@Unique
@@ -30,9 +30,6 @@ import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(FallingBlockEntity.class)
/*
* Preserves full block data on carried falling blocks.
*/
public abstract class FallingBlockEntityBlockDataMixin {
@Shadow public CompoundTag blockData;
@Shadow public abstract BlockState getBlockState();
@@ -17,9 +17,6 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Player.class)
/*
* Fixes player attack checks under inverted gravity.
*/
public abstract class PlayerAttackMixin {
@Inject(method = "attack", at = @At("HEAD"), cancellable = true)
private void antarchy$blockGravityGunMelee(Entity target, CallbackInfo ci) {
@@ -34,9 +31,6 @@ public abstract class PlayerAttackMixin {
}
}
/*
* Primordial's full set bonus makes player melee knockback ignore the target's knockback resistance.
*/
@WrapOperation(method = "attack", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;knockback(DDD)V"))
private void antarchy$ignorePrimordialKnockbackResistance(LivingEntity target, double strength, double x, double z, Operation<Void> original) {
Player player = (Player) (Object) this;
@@ -6,9 +6,6 @@ import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(ServerChunkCache.class)
/*
* Accessor for server chunk source internals used by gravity sync.
*/
public interface ServerChunkCacheAccessor {
@Accessor("chunkMap")
ChunkMap antarchy$getChunkMap();
@@ -19,9 +19,6 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(FallingBlockRenderer.class)
/*
* Keeps falling block render data lined up with carried state.
*/
public abstract class FallingBlockRendererBlockEntityMixin {
@Inject(
method = "render(Lnet/minecraft/world/entity/item/FallingBlockEntity;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V",