added 1 billion bugs

This commit is contained in:
craisinlord committed 2026-06-27 02:02:58 -05:00
1 parent b00ee762ab
commit b416c96ea2
133 files changed
+3064 -643

No files matched your search

@@ -90,7 +90,7 @@ public final class AntarchySettings {
private static ResourceKey<Level> rainbowAntNonInfinityFallbackDimension = dimensionKey("antarchy:elythia"); private static ResourceKey<Level> rainbowAntNonInfinityFallbackDimension = dimensionKey("antarchy:elythia");
private static double krakenHealth = 1500.0D; private static double krakenHealth = 1500.0D;
private static double krakenAttackDamage = 45.0D; private static double krakenAttackDamage = 45.0D;
private static double octopusBombHealth = 250.0D; private static double octopusBombHealth = 100.0D;
private static double octopusBombAttackDamage = 16.0D; private static double octopusBombAttackDamage = 16.0D;
private static double brutalflyHealth = 400.0D; private static double brutalflyHealth = 400.0D;
private static double brutalflySwipeDamage = 15.0D; private static double brutalflySwipeDamage = 15.0D;
@@ -148,6 +148,10 @@ public final class AntarchyObjects {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<Block> NYXITE_SPIKE = (Supplier<Block>) UNBOUND; public static Supplier<Block> NYXITE_SPIKE = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<Block> CHITEN_BLOCK = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> CHITEN_SPIKE = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> POTENT_NYXITE = (Supplier<Block>) UNBOUND; public static Supplier<Block> POTENT_NYXITE = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<Block> ANTIMETAL = (Supplier<Block>) UNBOUND; public static Supplier<Block> ANTIMETAL = (Supplier<Block>) UNBOUND;
@@ -276,6 +280,8 @@ public final class AntarchyObjects {
Supplier<Block> triffidGooBlock, Supplier<Block> triffidGooBlock,
Supplier<Block> paleNyxite, Supplier<Block> paleNyxite,
Supplier<Block> nyxiteSpike, Supplier<Block> nyxiteSpike,
Supplier<Block> chitenBlock,
Supplier<Block> chitenSpike,
Supplier<Block> potentNyxite, Supplier<Block> potentNyxite,
Supplier<Block> antimetal, Supplier<Block> antimetal,
Supplier<Block> polishedAntimetal, Supplier<Block> polishedAntimetal,
@@ -364,6 +370,8 @@ public final class AntarchyObjects {
TRIFFID_GOO_BLOCK = triffidGooBlock; TRIFFID_GOO_BLOCK = triffidGooBlock;
PALE_NYXITE = paleNyxite; PALE_NYXITE = paleNyxite;
NYXITE_SPIKE = nyxiteSpike; NYXITE_SPIKE = nyxiteSpike;
CHITEN_BLOCK = chitenBlock;
CHITEN_SPIKE = chitenSpike;
POTENT_NYXITE = potentNyxite; POTENT_NYXITE = potentNyxite;
ANTIMETAL = antimetal; ANTIMETAL = antimetal;
POLISHED_ANTIMETAL = polishedAntimetal; POLISHED_ANTIMETAL = polishedAntimetal;
@@ -76,6 +76,7 @@ public final class AntarchyTags {
public static final TagKey<Item> DUCT_TAPE_BLACKLIST = TagKey.create(Registries.ITEM, id("duct_tape_blacklist")); public static final TagKey<Item> DUCT_TAPE_BLACKLIST = TagKey.create(Registries.ITEM, id("duct_tape_blacklist"));
public static final TagKey<Item> BROWN_ANT_ACTIVATION_ITEMS = TagKey.create(Registries.ITEM, id("brown_ant_activation_items")); public static final TagKey<Item> BROWN_ANT_ACTIVATION_ITEMS = TagKey.create(Registries.ITEM, id("brown_ant_activation_items"));
public static final TagKey<Item> BROWN_ANT_BREEDING_FOODS = TagKey.create(Registries.ITEM, id("brown_ant_breeding_foods")); public static final TagKey<Item> BROWN_ANT_BREEDING_FOODS = TagKey.create(Registries.ITEM, id("brown_ant_breeding_foods"));
public static final TagKey<Item> MULTISHOT_ENCHANTABLE = TagKey.create(Registries.ITEM, id("multishot_enchantable"));
public static final TagKey<Item> RED_ANT_ACTIVATION_ITEMS = TagKey.create(Registries.ITEM, id("red_ant_activation_items")); public static final TagKey<Item> RED_ANT_ACTIVATION_ITEMS = TagKey.create(Registries.ITEM, id("red_ant_activation_items"));
public static final TagKey<Item> RED_ANT_BREEDING_FOODS = TagKey.create(Registries.ITEM, id("red_ant_breeding_foods")); public static final TagKey<Item> RED_ANT_BREEDING_FOODS = TagKey.create(Registries.ITEM, id("red_ant_breeding_foods"));
public static final TagKey<Item> RAINBOW_ANT_ACTIVATION_ITEMS = TagKey.create(Registries.ITEM, id("rainbow_ant_activation_items")); public static final TagKey<Item> RAINBOW_ANT_ACTIVATION_ITEMS = TagKey.create(Registries.ITEM, id("rainbow_ant_activation_items"));
@@ -95,6 +96,7 @@ public final class AntarchyTags {
public static final class Biomes { public static final class Biomes {
public static final TagKey<Biome> MANTIS_SPAWN_BIOMES = TagKey.create(Registries.BIOME, id("mantis_spawn_biomes")); public static final TagKey<Biome> MANTIS_SPAWN_BIOMES = TagKey.create(Registries.BIOME, id("mantis_spawn_biomes"));
public static final TagKey<Biome> MANTIS_OVERWORLD_SPAWN_BIOMES = TagKey.create(Registries.BIOME, id("mantis_overworld_spawn_biomes")); public static final TagKey<Biome> MANTIS_OVERWORLD_SPAWN_BIOMES = TagKey.create(Registries.BIOME, id("mantis_overworld_spawn_biomes"));
public static final TagKey<Biome> ELYTHIA_FIREFLY_PARTICLE_BIOMES = TagKey.create(Registries.BIOME, id("elythia_firefly_particle_biomes"));
private Biomes() { private Biomes() {
} }
@@ -1,6 +1,12 @@
package com.craisinlord.antarchy.content.block; package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import com.mojang.serialization.MapCodec; import com.mojang.serialization.MapCodec;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
@@ -9,9 +15,14 @@ import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.BonemealableBlock; import net.minecraft.world.level.block.BonemealableBlock;
import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
public class AmberMossBlock extends Block implements BonemealableBlock { public class AmberMossBlock extends Block implements BonemealableBlock {
public static final MapCodec<AmberMossBlock> CODEC = Block.simpleCodec(AmberMossBlock::new); public static final MapCodec<AmberMossBlock> CODEC = Block.simpleCodec(AmberMossBlock::new);
private static final ResourceKey<ConfiguredFeature<?, ?>> AMBER_MOSS_PATCH_BONEMEAL = ResourceKey.create(
Registries.CONFIGURED_FEATURE,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "amber_moss_patch_bonemeal")
);
public AmberMossBlock(BlockBehaviour.Properties properties) { public AmberMossBlock(BlockBehaviour.Properties properties) {
super(properties); super(properties);
@@ -24,15 +35,19 @@ public class AmberMossBlock extends Block implements BonemealableBlock {
@Override @Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state) { public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state) {
return false; return level.getBlockState(pos.above()).isAir();
} }
@Override @Override
public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, BlockState state) { public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, BlockState state) {
return false; return true;
} }
@Override @Override
public void performBonemeal(net.minecraft.server.level.ServerLevel level, RandomSource random, BlockPos pos, BlockState state) { public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) {
Holder.Reference<ConfiguredFeature<?, ?>> feature = level.registryAccess()
.lookupOrThrow(Registries.CONFIGURED_FEATURE)
.getOrThrow(AMBER_MOSS_PATCH_BONEMEAL);
feature.value().place(level, level.getChunkSource().getGenerator(), random, pos);
} }
} }
@@ -0,0 +1,166 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.PointedDripstoneBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.DripstoneThickness;
import net.minecraft.world.level.material.Fluids;
public class ChitenSpikeBlock extends PointedDripstoneBlock {
@SuppressWarnings("rawtypes")
public static final MapCodec<PointedDripstoneBlock> CODEC = (MapCodec) Block.simpleCodec(ChitenSpikeBlock::new);
public ChitenSpikeBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public MapCodec<PointedDripstoneBlock> codec() {
return CODEC;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
LevelAccessor level = context.getLevel();
BlockPos pos = context.getClickedPos();
Direction direction = calculateTipDirection(level, pos, context.getNearestLookingVerticalDirection().getOpposite());
if (direction == null) {
return null;
}
boolean mergeTips = !context.isSecondaryUseActive();
DripstoneThickness thickness = calculateDripstoneThickness(level, pos, direction, mergeTips);
if (thickness == null) {
return null;
}
return this.defaultBlockState()
.setValue(TIP_DIRECTION, direction)
.setValue(THICKNESS, thickness)
.setValue(WATERLOGGED, level.getFluidState(pos).getType() == Fluids.WATER);
}
@Override
protected BlockState updateShape(
BlockState state,
Direction direction,
BlockState neighborState,
LevelAccessor level,
BlockPos pos,
BlockPos neighborPos
) {
if (state.getValue(WATERLOGGED)) {
level.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(level));
}
if (direction != Direction.UP && direction != Direction.DOWN) {
return state;
}
Direction tipDirection = state.getValue(TIP_DIRECTION);
if (tipDirection == Direction.DOWN && level.getBlockTicks().hasScheduledTick(pos, this)) {
return state;
}
if (direction == tipDirection.getOpposite() && !this.canSurvive(state, level, pos)) {
if (tipDirection == Direction.DOWN) {
level.scheduleTick(pos, this, 2);
} else {
level.scheduleTick(pos, this, 1);
}
return state;
}
boolean mergeTips = state.getValue(THICKNESS) == DripstoneThickness.TIP_MERGE;
return state.setValue(THICKNESS, calculateDripstoneThickness(level, pos, tipDirection, mergeTips));
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return isValidPointedDripstonePlacement(level, pos, state.getValue(TIP_DIRECTION));
}
@Override
protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (this.canSurvive(state, level, pos)) {
return;
}
if (state.getValue(TIP_DIRECTION) == Direction.DOWN) {
BlockPos.MutableBlockPos root = pos.mutable();
while (isChitenSpikeWithDirection(level.getBlockState(root.above()), Direction.DOWN)) {
root.move(Direction.UP);
}
BlockPos.MutableBlockPos cursor = root.mutable();
while (isChitenSpikeWithDirection(level.getBlockState(cursor), Direction.DOWN)) {
BlockState fallingState = level.getBlockState(cursor);
if (isChitenSpikeWithDirection(fallingState, Direction.DOWN)) {
net.minecraft.world.entity.item.FallingBlockEntity.fall(level, cursor, fallingState);
}
cursor.move(Direction.DOWN);
}
return;
}
BlockPos.MutableBlockPos cursor = pos.mutable();
while (isChitenSpikeWithDirection(level.getBlockState(cursor), Direction.UP)) {
BlockState spikeState = level.getBlockState(cursor);
dropResources(spikeState, level, cursor);
level.removeBlock(cursor, false);
cursor.move(Direction.UP);
}
}
private static Direction calculateTipDirection(LevelReader level, BlockPos pos, Direction preferredDirection) {
if (isValidPointedDripstonePlacement(level, pos, preferredDirection)) {
return preferredDirection;
}
Direction opposite = preferredDirection.getOpposite();
return isValidPointedDripstonePlacement(level, pos, opposite) ? opposite : null;
}
private static DripstoneThickness calculateDripstoneThickness(LevelReader level, BlockPos pos, Direction direction, boolean mergeTips) {
Direction opposite = direction.getOpposite();
BlockState forwardState = level.getBlockState(pos.relative(direction));
if (isChitenSpikeWithDirection(forwardState, opposite)) {
return !mergeTips && forwardState.getValue(THICKNESS) != DripstoneThickness.TIP_MERGE
? DripstoneThickness.TIP
: DripstoneThickness.TIP_MERGE;
}
if (!isChitenSpikeWithDirection(forwardState, direction)) {
return DripstoneThickness.TIP;
}
DripstoneThickness forwardThickness = forwardState.getValue(THICKNESS);
if (forwardThickness != DripstoneThickness.TIP && forwardThickness != DripstoneThickness.TIP_MERGE) {
BlockState backState = level.getBlockState(pos.relative(opposite));
return !isChitenSpikeWithDirection(backState, direction) ? DripstoneThickness.BASE : DripstoneThickness.MIDDLE;
}
return DripstoneThickness.FRUSTUM;
}
private static boolean isValidPointedDripstonePlacement(LevelReader level, BlockPos pos, Direction direction) {
BlockPos supportPos = pos.relative(direction.getOpposite());
BlockState supportState = level.getBlockState(supportPos);
return supportState.isFaceSturdy(level, supportPos, direction) || isChitenSpikeWithDirection(supportState, direction);
}
private static boolean isChitenSpikeWithDirection(BlockState state, Direction direction) {
return state.is(AntarchyObjects.CHITEN_SPIKE.get()) && state.getValue(TIP_DIRECTION) == direction;
}
}
@@ -0,0 +1,54 @@
package com.craisinlord.antarchy.content.client.particle;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.ParticleProvider;
import net.minecraft.client.particle.ParticleRenderType;
import net.minecraft.client.particle.SpriteSet;
import net.minecraft.client.particle.TextureSheetParticle;
import net.minecraft.core.particles.SimpleParticleType;
public final class OrangeAshParticle extends TextureSheetParticle {
private final SpriteSet sprites;
private OrangeAshParticle(ClientLevel level, double x, double y, double z, double xd, double yd, double zd, SpriteSet sprites) {
super(level, x, y, z, xd, yd, zd);
this.sprites = sprites;
this.friction = 0.98F;
this.gravity = 0.0025F;
this.speedUpWhenYMotionIsBlocked = false;
this.hasPhysics = false;
this.xd = xd * 0.08D + (this.random.nextDouble() - 0.5D) * 0.01D;
this.yd = yd * 0.02D - 0.01D - this.random.nextDouble() * 0.01D;
this.zd = zd * 0.08D + (this.random.nextDouble() - 0.5D) * 0.01D;
this.quadSize *= 0.75F + this.random.nextFloat() * 0.5F;
this.lifetime = 40 + this.random.nextInt(28);
this.setColor(0.96F, 0.46F, 0.12F);
this.setAlpha(0.72F);
this.pickSprite(sprites);
}
@Override
public void tick() {
super.tick();
this.pickSprite(this.sprites);
}
@Override
public ParticleRenderType getRenderType() {
return ParticleRenderType.PARTICLE_SHEET_OPAQUE;
}
public static final class Provider implements ParticleProvider<SimpleParticleType> {
private final SpriteSet sprites;
public Provider(SpriteSet sprites) {
this.sprites = sprites;
}
@Override
public Particle createParticle(SimpleParticleType type, ClientLevel level, double x, double y, double z, double xd, double yd, double zd) {
return new OrangeAshParticle(level, x, y, z, xd, yd, zd, this.sprites);
}
}
}
@@ -0,0 +1,155 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.Antarchy;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.BufferUploader;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.MeshData;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.blaze3d.vertex.VertexBuffer;
import com.mojang.blaze3d.vertex.VertexFormat;
import java.util.Random;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.Level;
public final class CavarynSkyRenderer {
public static final ResourceKey<Level> CAVARYN = ResourceKey.create(
Registries.DIMENSION,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "cavaryn")
);
@org.jetbrains.annotations.Nullable
private static VertexBuffer orangeStarBuffer;
private CavarynSkyRenderer() {
}
public static boolean shouldRender(ClientLevel level) {
return level.dimension().equals(CAVARYN);
}
public static void render(
Minecraft minecraft,
ClientLevel level,
PoseStack poseStack,
org.joml.Matrix4f projectionMatrix,
float partialTick,
Camera camera,
boolean isFoggy,
Runnable setupFog,
VertexBuffer skyBuffer,
VertexBuffer darkBuffer
) {
setupFog.run();
if (isFoggy || minecraft.gameRenderer.getMainCamera() != camera) {
return;
}
float red = 0.015F;
float green = 0.085F;
float blue = 0.035F;
RenderSystem.depthMask(false);
RenderSystem.setShaderColor(red, green, blue, 1.0F);
skyBuffer.bind();
skyBuffer.drawWithShader(poseStack.last().pose(), projectionMatrix, GameRenderer.getPositionShader());
VertexBuffer.unbind();
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
float starBrightness = 0.8F;
if (orangeStarBuffer == null) {
orangeStarBuffer = buildOrangeStarBuffer();
}
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
RenderSystem.setShaderColor(starBrightness, starBrightness, starBrightness, starBrightness);
orangeStarBuffer.bind();
orangeStarBuffer.drawWithShader(poseStack.last().pose(), projectionMatrix, GameRenderer.getPositionColorShader());
VertexBuffer.unbind();
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.disableBlend();
if (camera.getEntity() != null) {
double horizon = camera.getEntity().getEyePosition(partialTick).y - level.getLevelData().getHorizonHeight(level);
if (horizon < 0.0D) {
poseStack.pushPose();
poseStack.translate(0.0F, 12.0F, 0.0F);
darkBuffer.bind();
darkBuffer.drawWithShader(poseStack.last().pose(), projectionMatrix, GameRenderer.getPositionShader());
VertexBuffer.unbind();
poseStack.popPose();
}
}
RenderSystem.depthMask(true);
}
private static VertexBuffer buildOrangeStarBuffer() {
Random random = new Random(548721L);
BufferBuilder builder = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
for (int i = 0; i < 1800; i++) {
double x = random.nextFloat() * 2.0F - 1.0F;
double y = random.nextFloat() * 2.0F - 1.0F;
double z = random.nextFloat() * 2.0F - 1.0F;
double size = 0.12F + random.nextFloat() * 0.12F;
double lenSq = x * x + y * y + z * z;
if (lenSq < 1.0D && lenSq > 0.01D) {
double len = 1.0D / Math.sqrt(lenSq);
x *= len;
y *= len;
z *= len;
double sx = x * 100.0D;
double sy = y * 100.0D;
double sz = z * 100.0D;
double yaw = Math.atan2(x, z);
double sinYaw = Math.sin(yaw);
double cosYaw = Math.cos(yaw);
double pitch = Math.atan2(Math.sqrt(x * x + z * z), y);
double sinPitch = Math.sin(pitch);
double cosPitch = Math.cos(pitch);
double rot = random.nextDouble() * Math.PI * 2.0D;
double sinRot = Math.sin(rot);
double cosRot = Math.cos(rot);
float[] color = pickStarColor(random);
for (int j = 0; j < 4; j++) {
double u = (j & 2) - 1;
double v = (j + 1 & 2) - 1;
double px = u * cosRot - v * sinRot;
double py = v * cosRot + u * sinRot;
double qx = px * sinPitch;
double qy = -px * cosPitch;
double rx = qy * sinYaw - py * cosYaw;
double ry = py * sinYaw + qy * cosYaw;
builder.addVertex((float) (sx + rx * size), (float) (sy + qx * size), (float) (sz + ry * size))
.setColor(color[0], color[1], color[2], 1.0F);
}
}
}
MeshData mesh = builder.buildOrThrow();
VertexBuffer buffer = new VertexBuffer(VertexBuffer.Usage.STATIC);
buffer.bind();
buffer.upload(mesh);
VertexBuffer.unbind();
return buffer;
}
private static float[] pickStarColor(Random random) {
float roll = random.nextFloat();
if (roll < 0.70F) return new float[]{1.00F, 0.55F, 0.14F};
if (roll < 0.90F) return new float[]{1.00F, 0.70F, 0.24F};
return new float[]{1.00F, 0.84F, 0.40F};
}
}
@@ -1,10 +1,23 @@
package com.craisinlord.antarchy.content.effect; package com.craisinlord.antarchy.content.effect;
import com.craisinlord.antarchy.content.StinkyBehavior;
import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectCategory; import net.minecraft.world.effect.MobEffectCategory;
import net.minecraft.world.entity.LivingEntity;
public final class StinkyMobEffect extends MobEffect { public final class StinkyMobEffect extends MobEffect {
public StinkyMobEffect() { public StinkyMobEffect() {
super(MobEffectCategory.HARMFUL, 0x66773A); super(MobEffectCategory.HARMFUL, 0x66773A);
} }
@Override
public boolean applyEffectTick(LivingEntity entity, int amplifier) {
StinkyBehavior.tickStinkyTrail(entity);
return true;
}
@Override
public boolean shouldApplyEffectTickThisTick(int duration, int amplifier) {
return true;
}
} }
@@ -1,11 +1,16 @@
package com.craisinlord.antarchy.content.entity; package com.craisinlord.antarchy.content.entity;
import com.craisinlord.antarchy.config.AntarchySettings; import com.craisinlord.antarchy.config.AntarchySettings;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.Difficulty;
import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.goal.FloatGoal; import net.minecraft.world.entity.ai.goal.FloatGoal;
@@ -18,6 +23,9 @@ import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.monster.Monster; import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import software.bernie.geckolib.animatable.GeoEntity; import software.bernie.geckolib.animatable.GeoEntity;
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.animation.AnimatableManager; import software.bernie.geckolib.animation.AnimatableManager;
@@ -62,6 +70,25 @@ public class CreepingHorrorEntity extends Monster implements GeoEntity {
.add(Attributes.FOLLOW_RANGE, 16.0D); .add(Attributes.FOLLOW_RANGE, 16.0D);
} }
public static boolean canSpawn(EntityType<CreepingHorrorEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
if (spawnReason == MobSpawnType.SPAWN_EGG || spawnReason == MobSpawnType.SPAWNER || spawnReason == MobSpawnType.COMMAND) {
return true;
}
BlockPos belowPos = pos.below();
BlockState belowState = level.getBlockState(belowPos);
boolean validSupport = !belowState.is(Blocks.BEDROCK)
&& belowState.blocksMotion()
&& belowState.isFaceSturdy(level, belowPos, Direction.UP)
&& belowState.isCollisionShapeFullBlock(level, belowPos);
return level.getDifficulty() != Difficulty.PEACEFUL
&& validSupport
&& level.isEmptyBlock(pos)
&& level.isEmptyBlock(pos.above())
&& Monster.checkMonsterSpawnRules(entityType, level, spawnReason, pos, random);
}
@Override @Override
protected void registerGoals() { protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this)); this.goalSelector.addGoal(0, new FloatGoal(this));
@@ -1,8 +1,13 @@
package com.craisinlord.antarchy.content.entity; package com.craisinlord.antarchy.content.entity;
import com.craisinlord.antarchy.config.AntarchySettings; import com.craisinlord.antarchy.config.AntarchySettings;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.Difficulty;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.control.FlyingMoveControl; import net.minecraft.world.entity.ai.control.FlyingMoveControl;
@@ -18,6 +23,9 @@ import net.minecraft.world.entity.ai.navigation.PathNavigation;
import net.minecraft.world.entity.monster.Monster; import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import software.bernie.geckolib.animatable.GeoEntity; import software.bernie.geckolib.animatable.GeoEntity;
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.animation.AnimatableManager; import software.bernie.geckolib.animation.AnimatableManager;
@@ -52,6 +60,25 @@ public class LurkingTerrorEntity extends Monster implements GeoEntity {
.add(Attributes.FLYING_SPEED, 0.55D); .add(Attributes.FLYING_SPEED, 0.55D);
} }
public static boolean canSpawn(EntityType<LurkingTerrorEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
if (spawnReason == MobSpawnType.SPAWN_EGG || spawnReason == MobSpawnType.SPAWNER || spawnReason == MobSpawnType.COMMAND) {
return true;
}
BlockPos belowPos = pos.below();
BlockState belowState = level.getBlockState(belowPos);
boolean validSupport = !belowState.is(Blocks.BEDROCK)
&& belowState.blocksMotion()
&& belowState.isFaceSturdy(level, belowPos, Direction.UP)
&& belowState.isCollisionShapeFullBlock(level, belowPos);
return level.getDifficulty() != Difficulty.PEACEFUL
&& validSupport
&& level.isEmptyBlock(pos)
&& level.isEmptyBlock(pos.above())
&& Monster.checkMonsterSpawnRules(entityType, level, spawnReason, pos, random);
}
@Override @Override
protected PathNavigation createNavigation(Level level) { protected PathNavigation createNavigation(Level level) {
FlyingPathNavigation nav = new FlyingPathNavigation(this, level); FlyingPathNavigation nav = new FlyingPathNavigation(this, level);
@@ -2,8 +2,7 @@ package com.craisinlord.antarchy.content.entity;
import com.craisinlord.antarchy.content.AntarchySoundEvents; import com.craisinlord.antarchy.content.AntarchySoundEvents;
import com.craisinlord.antarchy.content.damage.AntarchyDamageSources; import com.craisinlord.antarchy.content.damage.AntarchyDamageSources;
import net.minecraft.core.BlockPos; import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.tags.FluidTags;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.EntityDataSerializers;
@@ -11,7 +10,6 @@ import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvent;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.DifficultyInstance; import net.minecraft.world.DifficultyInstance;
@@ -24,6 +22,7 @@ import net.minecraft.world.entity.ai.control.SmoothSwimmingMoveControl;
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal; import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal; import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation; import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation;
import net.minecraft.world.entity.ai.navigation.PathNavigation; import net.minecraft.world.entity.ai.navigation.PathNavigation;
import net.minecraft.world.entity.ai.navigation.WaterBoundPathNavigation; import net.minecraft.world.entity.ai.navigation.WaterBoundPathNavigation;
@@ -46,28 +45,21 @@ import java.util.Objects;
public class OctopusBombEntity extends Monster implements GeoEntity { public class OctopusBombEntity extends Monster implements GeoEntity {
private static final EntityDataAccessor<Integer> ATTACK_STATE = SynchedEntityData.defineId(OctopusBombEntity.class, EntityDataSerializers.INT); private static final EntityDataAccessor<Integer> ATTACK_STATE = SynchedEntityData.defineId(OctopusBombEntity.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Boolean> ROARING = SynchedEntityData.defineId(OctopusBombEntity.class, EntityDataSerializers.BOOLEAN);
private static final EntityDataAccessor<Integer> ANIMATION_STATE = SynchedEntityData.defineId(OctopusBombEntity.class, EntityDataSerializers.INT); private static final EntityDataAccessor<Integer> ANIMATION_STATE = SynchedEntityData.defineId(OctopusBombEntity.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Boolean> CAN_FLY = SynchedEntityData.defineId(OctopusBombEntity.class, EntityDataSerializers.BOOLEAN); private static final EntityDataAccessor<Boolean> CAN_FLY = SynchedEntityData.defineId(OctopusBombEntity.class, EntityDataSerializers.BOOLEAN);
private static final String ATTACK_COOLDOWN_KEY = "AttackCooldown";
private static final String ACTION_TICKS_KEY = "ActionTicks";
private static final String LAST_ATTACK_STATE_KEY = "LastAttackState";
private static final String AGGRO_TRIGGERED_KEY = "AggroTriggered";
private static final String GRAB_TARGET_KEY = "GrabTarget";
private static final String CAN_FLY_KEY = "CanFly";
private static final String SPAWNED_BY_KRAKEN_KEY = "SpawnedByKraken";
private static final int ATTACK_NONE = 0; private static final int ATTACK_NONE = 0;
private static final int ATTACK_GRAB = 1; private static final int ATTACK_GRAB = 1;
private static final int ATTACK_SWIPE = 2; private static final int ATTACK_SWIPE = 2;
private static final int ANIM_IDLE = 0; private static final int ANIM_IDLE = 0;
private static final int ANIM_SWIM = 2; private static final int ANIM_SWIM = 2;
private static final int ANIM_SWIPE = 3; private static final int ANIM_SWIPE = 3;
private static final int ANIM_GRAB = 4; private static final int ANIM_GRAB = 4;
private static final int ANIM_DEATH = 5; private static final int ANIM_DEATH = 5;
private static final int DEATH_ANIM_TICKS = 60; private static final int DEATH_ANIM_TICKS = 60;
private static final int INK_SPRAY_RANGE = 6; private static final int INK_SPRAY_RANGE = 8;
private static final int INK_SPRAY_COOLDOWN = 80; private static final int INK_SPRAY_COOLDOWN = 80;
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle"); private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
@@ -77,16 +69,21 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
private static final RawAnimation DEATH_ANIM = RawAnimation.begin().thenPlay("Death"); private static final RawAnimation DEATH_ANIM = RawAnimation.begin().thenPlay("Death");
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this); private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
// Squid-style wander
private float wanderDx, wanderDy, wanderDz; private float wanderDx, wanderDy, wanderDz;
private int wanderRetargetTicks; private int wanderRetargetTicks;
// Combat
private int attackCooldown; private int attackCooldown;
private int actionTicks; private int actionTicks;
private int lastAttackState; private int lastAttackState;
private boolean aggroTriggered;
private int grabbedTargetId = -1; private int grabbedTargetId = -1;
private int strafeRetargetTicks; private int strafeRetargetTicks;
private int inkSprayCooldown;
private float orbitDirection = 1.0F; private float orbitDirection = 1.0F;
private int inkSprayCooldown;
// Kraken spawn flag
private boolean spawnedByKraken; private boolean spawnedByKraken;
public OctopusBombEntity(EntityType<? extends Monster> entityType, Level level) { public OctopusBombEntity(EntityType<? extends Monster> entityType, Level level) {
@@ -97,7 +94,7 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
public static AttributeSupplier.Builder createAttributes() { public static AttributeSupplier.Builder createAttributes() {
return Mob.createMobAttributes() return Mob.createMobAttributes()
.add(Attributes.MAX_HEALTH, 250.0D) .add(Attributes.MAX_HEALTH, 100.0D)
.add(Attributes.ATTACK_DAMAGE, 16.0D) .add(Attributes.ATTACK_DAMAGE, 16.0D)
.add(Attributes.MOVEMENT_SPEED, 0.28D) .add(Attributes.MOVEMENT_SPEED, 0.28D)
.add(Attributes.FLYING_SPEED, 0.28D) .add(Attributes.FLYING_SPEED, 0.28D)
@@ -105,15 +102,15 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
.add(Attributes.KNOCKBACK_RESISTANCE, 0.4D); .add(Attributes.KNOCKBACK_RESISTANCE, 0.4D);
} }
public static boolean canSpawn(EntityType<OctopusBombEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { public static boolean canSpawn(EntityType<OctopusBombEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, net.minecraft.core.BlockPos pos, RandomSource random) {
return level.getFluidState(pos).is(FluidTags.WATER) && level.getFluidState(pos.above()).is(FluidTags.WATER); return level.getFluidState(pos).is(net.minecraft.tags.FluidTags.WATER)
&& level.getFluidState(pos.above()).is(net.minecraft.tags.FluidTags.WATER);
} }
@Override @Override
protected void defineSynchedData(SynchedEntityData.Builder builder) { protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder); super.defineSynchedData(builder);
builder.define(ATTACK_STATE, ATTACK_NONE); builder.define(ATTACK_STATE, ATTACK_NONE);
builder.define(ROARING, false);
builder.define(ANIMATION_STATE, ANIM_IDLE); builder.define(ANIMATION_STATE, ANIM_IDLE);
builder.define(CAN_FLY, false); builder.define(CAN_FLY, false);
} }
@@ -133,12 +130,26 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
@Override @Override
protected void registerGoals() { protected void registerGoals() {
this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 20.0F)); this.goalSelector.addGoal(5, new LookAtPlayerGoal(this, Player.class, 20.0F));
this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); this.goalSelector.addGoal(6, new RandomLookAroundGoal(this));
HurtByTargetGoal hurtByTargetGoal = new HurtByTargetGoal(this); // Only retaliate when hit — neutral otherwise
hurtByTargetGoal.setAlertOthers(MissileSquidEntity.class); this.targetSelector.addGoal(1, new HurtByTargetGoal(this));
this.targetSelector.addGoal(1, hurtByTargetGoal); // When spawned by Kraken and flying, target nearest player
this.targetSelector.addGoal(2, new KrakenSummonTargetGoal(this));
}
@Override
protected PathNavigation createNavigation(Level level) {
return new WaterBoundPathNavigation(this, level);
}
@Override
public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData spawnData) {
Objects.requireNonNull(this.getAttribute(Attributes.MAX_HEALTH)).setBaseValue(com.craisinlord.antarchy.config.AntarchySettings.octopusBombHealth());
this.setHealth((float) com.craisinlord.antarchy.config.AntarchySettings.octopusBombHealth());
Objects.requireNonNull(this.getAttribute(Attributes.ATTACK_DAMAGE)).setBaseValue(com.craisinlord.antarchy.config.AntarchySettings.octopusBombAttackDamage());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
} }
@Override @Override
@@ -162,19 +173,6 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
return this.geoCache; return this.geoCache;
} }
@Override
protected PathNavigation createNavigation(Level level) {
return new WaterBoundPathNavigation(this, level);
}
@Override
public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData spawnData) {
Objects.requireNonNull(this.getAttribute(Attributes.MAX_HEALTH)).setBaseValue(com.craisinlord.antarchy.config.AntarchySettings.octopusBombHealth());
this.setHealth((float) com.craisinlord.antarchy.config.AntarchySettings.octopusBombHealth());
Objects.requireNonNull(this.getAttribute(Attributes.ATTACK_DAMAGE)).setBaseValue(com.craisinlord.antarchy.config.AntarchySettings.octopusBombAttackDamage());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
@Override @Override
public void baseTick() { public void baseTick() {
int airSupply = this.getAirSupply(); int airSupply = this.getAirSupply();
@@ -196,22 +194,17 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
return; return;
} }
if (this.attackCooldown > 0) { if (this.attackCooldown > 0) this.attackCooldown--;
this.attackCooldown--; if (this.inkSprayCooldown > 0) this.inkSprayCooldown--;
}
if (this.inkSprayCooldown > 0) { // Ink spray — always active regardless of aggro state
this.inkSprayCooldown--; this.tickInkSpray();
}
LivingEntity target = this.getTarget(); LivingEntity target = this.getTarget();
this.tickDefensiveInkSpray();
if (target == null || !target.isAlive()) { if (target == null || !target.isAlive()) {
this.resetCombatState(); this.resetCombatState();
if (this.isInWater()) { if (this.isInWater()) this.tickWanderMovement();
this.tickWanderMovement();
}
this.updateSwimRotation(); this.updateSwimRotation();
this.updateAnimationState(); this.updateAnimationState();
return; return;
@@ -219,30 +212,15 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
this.getLookControl().setLookAt(target, 25.0F, 20.0F); this.getLookControl().setLookAt(target, 25.0F, 20.0F);
if (!this.aggroTriggered) {
this.startAggroRoar();
}
if (this.isRoaring()) {
this.tickRoarState(target);
this.updateSwimRotation();
this.updateAnimationState();
return;
}
if (this.getAttackState() != ATTACK_NONE) { if (this.getAttackState() != ATTACK_NONE) {
this.tickCurrentAttack(target); this.tickCurrentAttack(target);
this.updateSwimRotation(); } else {
this.updateAnimationState(); this.tickPursuitMovement(target);
return; if (this.attackCooldown <= 0) {
} int nextAttack = this.chooseNextAttack(target);
if (nextAttack != ATTACK_NONE) {
this.tickPursuitMovement(target); this.startAttack(nextAttack);
}
if (this.attackCooldown <= 0) {
int nextAttack = this.chooseNextAttack(target);
if (nextAttack != ATTACK_NONE) {
this.startAttack(nextAttack);
} }
} }
@@ -258,7 +236,6 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
this.setDeltaMovement(this.getDeltaMovement().scale(this.isInWater() ? 0.92D : 0.91D)); this.setDeltaMovement(this.getDeltaMovement().scale(this.isInWater() ? 0.92D : 0.91D));
return; return;
} }
super.travel(travelVector); super.travel(travelVector);
} }
@@ -296,16 +273,12 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
@Override @Override
public void addAdditionalSaveData(CompoundTag tag) { public void addAdditionalSaveData(CompoundTag tag) {
super.addAdditionalSaveData(tag); super.addAdditionalSaveData(tag);
tag.putInt(ATTACK_COOLDOWN_KEY, this.attackCooldown); tag.putInt("AttackCooldown", this.attackCooldown);
tag.putInt(ACTION_TICKS_KEY, this.actionTicks); tag.putInt("ActionTicks", this.actionTicks);
tag.putInt(LAST_ATTACK_STATE_KEY, this.lastAttackState); tag.putInt("LastAttackState", this.lastAttackState);
tag.putBoolean(AGGRO_TRIGGERED_KEY, this.aggroTriggered); tag.putBoolean("CanFly", this.canFly());
tag.putBoolean(CAN_FLY_KEY, this.canFly()); tag.putBoolean("SpawnedByKraken", this.spawnedByKraken);
tag.putBoolean(SPAWNED_BY_KRAKEN_KEY, this.spawnedByKraken); if (this.grabbedTargetId >= 0) tag.putInt("GrabTarget", this.grabbedTargetId);
if (this.grabbedTargetId >= 0) {
tag.putInt(GRAB_TARGET_KEY, this.grabbedTargetId);
}
tag.putBoolean("Roaring", this.isRoaring());
tag.putInt("AttackState", this.getAttackState()); tag.putInt("AttackState", this.getAttackState());
tag.putInt("AnimationState", this.getAnimationState()); tag.putInt("AnimationState", this.getAnimationState());
} }
@@ -313,27 +286,24 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
@Override @Override
public void readAdditionalSaveData(CompoundTag tag) { public void readAdditionalSaveData(CompoundTag tag) {
super.readAdditionalSaveData(tag); super.readAdditionalSaveData(tag);
this.attackCooldown = tag.getInt(ATTACK_COOLDOWN_KEY); this.attackCooldown = tag.getInt("AttackCooldown");
this.actionTicks = tag.getInt(ACTION_TICKS_KEY); this.actionTicks = tag.getInt("ActionTicks");
this.lastAttackState = tag.contains(LAST_ATTACK_STATE_KEY) ? tag.getInt(LAST_ATTACK_STATE_KEY) : ATTACK_NONE; this.lastAttackState = tag.contains("LastAttackState") ? tag.getInt("LastAttackState") : ATTACK_NONE;
this.aggroTriggered = tag.getBoolean(AGGRO_TRIGGERED_KEY); this.setCanFly(tag.getBoolean("CanFly"));
this.setCanFly(tag.getBoolean(CAN_FLY_KEY)); this.spawnedByKraken = tag.getBoolean("SpawnedByKraken");
this.spawnedByKraken = tag.getBoolean(SPAWNED_BY_KRAKEN_KEY); this.grabbedTargetId = tag.contains("GrabTarget") ? tag.getInt("GrabTarget") : -1;
this.grabbedTargetId = tag.contains(GRAB_TARGET_KEY) ? tag.getInt(GRAB_TARGET_KEY) : -1;
this.entityData.set(ROARING, tag.getBoolean("Roaring"));
this.entityData.set(ATTACK_STATE, tag.getInt("AttackState")); this.entityData.set(ATTACK_STATE, tag.getInt("AttackState"));
this.entityData.set(ANIMATION_STATE, tag.contains("AnimationState") ? tag.getInt("AnimationState") : ANIM_IDLE); this.entityData.set(ANIMATION_STATE, tag.contains("AnimationState") ? tag.getInt("AnimationState") : ANIM_IDLE);
this.updateAnimationState();
}
public boolean isRoaring() {
return this.entityData.get(ROARING);
} }
public boolean canFly() { public boolean canFly() {
return this.entityData.get(CAN_FLY); return this.entityData.get(CAN_FLY);
} }
public void setCanFly(boolean canFly) {
this.entityData.set(CAN_FLY, canFly);
}
public int getAttackState() { public int getAttackState() {
return this.entityData.get(ATTACK_STATE); return this.entityData.get(ATTACK_STATE);
} }
@@ -342,49 +312,79 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
return this.entityData.get(ANIMATION_STATE); return this.entityData.get(ANIMATION_STATE);
} }
private void setRoaring(boolean roaring) { private void setAttackState(int state) {
this.entityData.set(ROARING, roaring); this.entityData.set(ATTACK_STATE, state);
} }
public void setCanFly(boolean canFly) { private void setAnimationState(int state) {
this.entityData.set(CAN_FLY, canFly); this.entityData.set(ANIMATION_STATE, state);
} }
public void launchAsProjectile(net.minecraft.world.entity.Entity owner, net.minecraft.world.phys.Vec3 velocity) { public void launchAsProjectile(net.minecraft.world.entity.Entity owner, Vec3 velocity) {
this.spawnedByKraken = true; this.spawnedByKraken = true;
this.setCanFly(true); this.setCanFly(true);
this.setDeltaMovement(velocity); this.setDeltaMovement(velocity);
} }
private void setAttackState(int attackState) { // -------------------------------------------------------------------------
this.entityData.set(ATTACK_STATE, attackState); // Squid-style wander
} // -------------------------------------------------------------------------
private void setAnimationState(int animationState) { private void tickWanderMovement() {
this.entityData.set(ANIMATION_STATE, animationState); if (--this.wanderRetargetTicks <= 0) {
} this.wanderRetargetTicks = 40 + this.random.nextInt(40);
float angle = this.random.nextFloat() * (float) (Math.PI * 2);
private void startAggroRoar() { this.wanderDx = Mth.cos(angle) * 0.1f;
this.aggroTriggered = true; this.wanderDy = -0.05f + this.random.nextFloat() * 0.1f;
this.actionTicks = 30; this.wanderDz = Mth.sin(angle) * 0.1f;
this.setRoaring(true);
this.playSound(AntarchySoundEvents.KRAKEN_ROAR.get(), 1.4F, 1.07F);
this.getNavigation().stop();
this.setDeltaMovement(this.getDeltaMovement().scale(0.2D));
this.updateAnimationState();
}
private void tickRoarState(LivingEntity target) {
this.getNavigation().stop();
this.getMoveControl().setWantedPosition(this.getX(), this.getY(), this.getZ(), 0.0D);
this.setDeltaMovement(this.getDeltaMovement().scale(0.6D));
this.getLookControl().setLookAt(target, 25.0F, 20.0F);
if (--this.actionTicks <= 0) {
this.actionTicks = 0;
this.setRoaring(false);
this.attackCooldown = 18;
} }
this.setDeltaMovement(this.getDeltaMovement().add(this.wanderDx, this.wanderDy, this.wanderDz));
}
// -------------------------------------------------------------------------
// Ink spray
// -------------------------------------------------------------------------
private void tickInkSpray() {
if (this.inkSprayCooldown > 0 || !(this.level() instanceof ServerLevel serverLevel)) return;
Player nearbyPlayer = this.level().getNearestPlayer(this, INK_SPRAY_RANGE);
if (nearbyPlayer == null || nearbyPlayer.isCreative() || nearbyPlayer.isSpectator()) return;
this.inkSprayCooldown = INK_SPRAY_COOLDOWN;
this.playSound(AntarchySoundEvents.KRAKEN_HURT.get(), 1.0F, 1.49F);
double cx = this.getX();
double cy = this.getY() + this.getBbHeight() * 0.5D;
double cz = this.getZ();
serverLevel.sendParticles(ParticleTypes.SQUID_INK, cx, cy, cz, 120, 2.0D, 1.2D, 2.0D, 0.04D);
serverLevel.sendParticles(ParticleTypes.SQUID_INK, cx, cy, cz, 60, 3.5D, 1.8D, 3.5D, 0.02D);
}
// -------------------------------------------------------------------------
// Combat
// -------------------------------------------------------------------------
private void tickPursuitMovement(LivingEntity target) {
if (this.strafeRetargetTicks-- <= 0) {
this.strafeRetargetTicks = 10 + this.random.nextInt(12);
if (this.random.nextFloat() < 0.4F) this.orbitDirection *= -1.0F;
}
Vec3 attackPoint = this.createCombatTarget(target);
this.getMoveControl().setWantedPosition(attackPoint.x, attackPoint.y, attackPoint.z, 1.1D);
}
private Vec3 createCombatTarget(LivingEntity target) {
double radius = 9.0D;
double angle = this.tickCount * 0.16D * this.orbitDirection + this.getId() * 0.11D;
double x = target.getX() + Math.cos(angle) * radius;
double z = target.getZ() + Math.sin(angle) * radius;
double y = Mth.clamp(
target.getY() + 1.0D + Math.sin((this.tickCount + this.getId()) * 0.18D),
target.getY() - 3.0D,
target.getY() + 4.0D
);
return new Vec3(x, y, z);
} }
private void tickCurrentAttack(LivingEntity target) { private void tickCurrentAttack(LivingEntity target) {
@@ -402,7 +402,6 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
private void startAttack(int attackState) { private void startAttack(int attackState) {
this.setAttackState(attackState); this.setAttackState(attackState);
this.grabbedTargetId = -1; this.grabbedTargetId = -1;
if (attackState == ATTACK_GRAB) { if (attackState == ATTACK_GRAB) {
this.actionTicks = 55; this.actionTicks = 55;
this.playSound(AntarchySoundEvents.KRAKEN_ATTACK.get(), 1.2F, 1.07F); this.playSound(AntarchySoundEvents.KRAKEN_ATTACK.get(), 1.2F, 1.07F);
@@ -417,33 +416,26 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
this.grabbedTargetId = target.getId(); this.grabbedTargetId = target.getId();
} }
LivingEntity grabbedTarget = this.getGrabbedTarget(); LivingEntity grabbed = this.getGrabbedTarget();
if (grabbedTarget != null && grabbedTarget.isAlive()) { if (grabbed != null && grabbed.isAlive()) {
this.holdGrabbedTarget(grabbedTarget); this.holdGrabbedTarget(grabbed);
if (this.actionTicks <= 45 && this.actionTicks > 10 && this.actionTicks % 10 == 0) { if (this.actionTicks <= 45 && this.actionTicks > 10 && this.actionTicks % 10 == 0) {
if (this.level() instanceof ServerLevel serverLevel) { if (this.level() instanceof ServerLevel serverLevel) {
grabbedTarget.hurt(AntarchyDamageSources.krakenMauling(serverLevel, this), 4.0F); grabbed.hurt(AntarchyDamageSources.krakenMauling(serverLevel, this), 4.0F);
} }
} }
} }
if (--this.actionTicks <= 0) { if (--this.actionTicks <= 0) {
if (grabbedTarget != null && grabbedTarget.isAlive()) { if (grabbed != null && grabbed.isAlive()) this.pullDown(grabbed, 2.5D);
this.pullDown(grabbedTarget, 2.5D);
}
this.grabbedTargetId = -1; this.grabbedTargetId = -1;
this.finishAttack(); this.finishAttack();
} }
} }
private void tickSwipeAttack() { private void tickSwipeAttack() {
if (this.actionTicks == 10) { if (this.actionTicks == 10) this.performSwipe();
this.performSwipe(); if (--this.actionTicks <= 0) this.finishAttack();
}
if (--this.actionTicks <= 0) {
this.finishAttack();
}
} }
private void finishAttack() { private void finishAttack() {
@@ -453,70 +445,13 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
this.attackCooldown = 18; this.attackCooldown = 18;
this.grabbedTargetId = -1; this.grabbedTargetId = -1;
this.lastAttackState = finished; this.lastAttackState = finished;
this.updateAnimationState();
}
private void tickPursuitMovement(LivingEntity target) {
if (this.strafeRetargetTicks-- <= 0) {
this.strafeRetargetTicks = 10 + this.random.nextInt(12);
if (this.random.nextFloat() < 0.4F) {
this.orbitDirection *= -1.0F;
}
}
Vec3 attackPoint = this.createCombatTarget(target);
this.getMoveControl().setWantedPosition(attackPoint.x, attackPoint.y, attackPoint.z, 1.1D);
}
private void resetCombatState() {
this.setAttackState(ATTACK_NONE);
this.setRoaring(false);
this.setTarget(null);
this.actionTicks = 0;
this.grabbedTargetId = -1;
this.aggroTriggered = false;
this.updateAnimationState();
}
private void handleAirSupply(int previousAirSupply) {
if (this.isInWaterOrBubble()) {
this.setAirSupply(this.getMaxAirSupply());
return;
}
this.setAirSupply(previousAirSupply - 1);
if (this.getAirSupply() <= -20) {
this.setAirSupply(0);
this.hurt(this.damageSources().drown(), 2.0F);
}
}
private void tickDefensiveInkSpray() {
if (this.inkSprayCooldown > 0 || !(this.level() instanceof ServerLevel serverLevel)) {
return;
}
Player nearbyPlayer = this.level().getNearestPlayer(this, INK_SPRAY_RANGE);
if (nearbyPlayer == null || nearbyPlayer.isCreative() || nearbyPlayer.isSpectator()) {
return;
}
this.inkSprayCooldown = INK_SPRAY_COOLDOWN;
this.playSound(AntarchySoundEvents.KRAKEN_HURT.get(), 1.0F, 1.49F);
double centerY = this.getY() + this.getBbHeight() * 0.5D;
serverLevel.sendParticles(ParticleTypes.SQUID_INK, this.getX(), centerY, this.getZ(), 55, 1.2D, 0.8D, 1.2D, 0.02D);
serverLevel.sendParticles(ParticleTypes.SQUID_INK, this.getX(), centerY, this.getZ(), 35, 2.0D, 1.1D, 2.0D, 0.01D);
} }
private int chooseNextAttack(LivingEntity target) { private int chooseNextAttack(LivingEntity target) {
double distSqr = this.distanceToSqr(target); double distSqr = this.distanceToSqr(target);
boolean canGrab = distSqr <= 42.25D; boolean canGrab = distSqr <= 42.25D;
boolean canSwipe = distSqr <= 81.0D && this.isTargetInFront(target, -0.15D); boolean canSwipe = distSqr <= 81.0D && this.isTargetInFront(target, -0.15D);
if (!canGrab && !canSwipe) return ATTACK_NONE;
if (!canGrab && !canSwipe) {
return ATTACK_NONE;
}
int grabWeight = canGrab ? (this.lastAttackState == ATTACK_GRAB ? 1 : 4) : 0; int grabWeight = canGrab ? (this.lastAttackState == ATTACK_GRAB ? 1 : 4) : 0;
int swipeWeight = canSwipe ? (this.lastAttackState == ATTACK_SWIPE ? 1 : 5) : 0; int swipeWeight = canSwipe ? (this.lastAttackState == ATTACK_SWIPE ? 1 : 5) : 0;
@@ -524,19 +459,19 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
if (total == 0) return ATTACK_NONE; if (total == 0) return ATTACK_NONE;
int roll = this.random.nextInt(total); int roll = this.random.nextInt(total);
if (roll < grabWeight) return ATTACK_GRAB; return roll < grabWeight ? ATTACK_GRAB : ATTACK_SWIPE;
return ATTACK_SWIPE;
} }
private void performSwipe() { private void performSwipe() {
AABB hitBox = this.getBoundingBox().inflate(7.0D, 3.0D, 7.0D); AABB hitBox = this.getBoundingBox().inflate(7.0D, 3.0D, 7.0D);
List<Player> players = this.level().getEntitiesOfClass(Player.class, hitBox, player -> player.isAlive() && this.isTargetInFront(player, -0.15D)); List<Player> players = this.level().getEntitiesOfClass(Player.class, hitBox,
p -> p.isAlive() && this.isTargetInFront(p, -0.15D));
float damage = (float) this.getAttributeValue(Attributes.ATTACK_DAMAGE); float damage = (float) this.getAttributeValue(Attributes.ATTACK_DAMAGE);
for (Player player : players) { for (Player player : players) {
if (this.level() instanceof ServerLevel serverLevel) { if (this.level() instanceof ServerLevel serverLevel) {
player.hurt(AntarchyDamageSources.krakenMauling(serverLevel, this), damage); player.hurt(AntarchyDamageSources.krakenMauling(serverLevel, this), damage);
Vec3 direction = player.position().subtract(this.position()); Vec3 dir = player.position().subtract(this.position());
Vec3 horizontal = new Vec3(direction.x, 0.0D, direction.z).normalize().scale(1.75D); Vec3 horizontal = new Vec3(dir.x, 0.0D, dir.z).normalize().scale(1.75D);
player.push(horizontal.x, 0.3D, horizontal.z); player.push(horizontal.x, 0.3D, horizontal.z);
player.hurtMarked = true; player.hurtMarked = true;
} }
@@ -547,45 +482,49 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
Vec3 anchor = this.position().add(0.0D, -this.getBbHeight() * 0.4D, 0.0D); Vec3 anchor = this.position().add(0.0D, -this.getBbHeight() * 0.4D, 0.0D);
target.setDeltaMovement(anchor.subtract(target.position()).scale(0.35D)); target.setDeltaMovement(anchor.subtract(target.position()).scale(0.35D));
target.resetFallDistance(); target.resetFallDistance();
if (target instanceof ServerPlayer serverPlayer) { if (target instanceof ServerPlayer sp) {
serverPlayer.connection.teleport(anchor.x, anchor.y, anchor.z, target.getYRot(), target.getXRot()); sp.connection.teleport(anchor.x, anchor.y, anchor.z, target.getYRot(), target.getXRot());
} else { } else {
target.moveTo(anchor.x, anchor.y, anchor.z, target.getYRot(), target.getXRot()); target.moveTo(anchor.x, anchor.y, anchor.z, target.getYRot(), target.getXRot());
} }
target.hurtMarked = true; target.hurtMarked = true;
} }
private void pullDown(LivingEntity target, double downwardStrength) { private void pullDown(LivingEntity target, double strength) {
target.push(0.0D, -downwardStrength, 0.0D); target.push(0.0D, -strength, 0.0D);
target.hurtMarked = true; target.hurtMarked = true;
} }
@Nullable @Nullable
private LivingEntity getGrabbedTarget() { private LivingEntity getGrabbedTarget() {
if (this.grabbedTargetId < 0) { if (this.grabbedTargetId < 0) return null;
return null; net.minecraft.world.entity.Entity e = this.level().getEntity(this.grabbedTargetId);
} return e instanceof LivingEntity le ? le : null;
net.minecraft.world.entity.Entity entity = this.level().getEntity(this.grabbedTargetId);
return entity instanceof LivingEntity livingEntity ? livingEntity : null;
} }
private boolean isTargetInFront(LivingEntity target, double minimumDot) { private boolean isTargetInFront(LivingEntity target, double minDot) {
Vec3 forward = this.getViewVector(1.0F); Vec3 forward = this.getViewVector(1.0F);
Vec3 toTarget = target.position().subtract(this.position()).normalize(); Vec3 toTarget = target.position().subtract(this.position()).normalize();
return forward.dot(toTarget) >= minimumDot; return forward.dot(toTarget) >= minDot;
} }
private Vec3 createCombatTarget(LivingEntity target) { private void resetCombatState() {
double radius = 9.0D; this.setAttackState(ATTACK_NONE);
double angle = this.tickCount * 0.16D * this.orbitDirection + this.getId() * 0.11D; this.setTarget(null);
double x = target.getX() + Math.cos(angle) * radius; this.actionTicks = 0;
double z = target.getZ() + Math.sin(angle) * radius; this.grabbedTargetId = -1;
double y = Mth.clamp( }
target.getY() + 1.0D + Math.sin((this.tickCount + this.getId()) * 0.18D),
target.getY() - 3.0D, private void handleAirSupply(int previousAirSupply) {
target.getY() + 4.0D if (this.isInWaterOrBubble()) {
); this.setAirSupply(this.getMaxAirSupply());
return new Vec3(x, y, z); return;
}
this.setAirSupply(previousAirSupply - 1);
if (this.getAirSupply() <= -20) {
this.setAirSupply(0);
this.hurt(this.damageSources().drown(), 2.0F);
}
} }
private void updateSwimRotation() { private void updateSwimRotation() {
@@ -596,21 +535,41 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
this.yBodyRot = this.getYRot(); this.yBodyRot = this.getYRot();
this.yHeadRot = this.getYRot(); this.yHeadRot = this.getYRot();
} }
if (velocity.lengthSqr() > 1.0E-4D) { if (velocity.lengthSqr() > 1.0E-4D) {
float targetPitch = (float) (-(Mth.atan2(velocity.y, velocity.horizontalDistance()) * (180.0D / Math.PI))); float targetPitch = (float) (-(Mth.atan2(velocity.y, velocity.horizontalDistance()) * (180.0D / Math.PI)));
this.setXRot(Mth.approachDegrees(this.getXRot(), targetPitch, 4.0F)); this.setXRot(Mth.approachDegrees(this.getXRot(), targetPitch, 4.0F));
} }
} }
private void updateAnimationState() {
if (this.isDeadOrDying()) {
this.setAnimationState(ANIM_DEATH);
return;
}
switch (this.getAttackState()) {
case ATTACK_GRAB -> { this.setAnimationState(ANIM_GRAB); return; }
case ATTACK_SWIPE -> { this.setAnimationState(ANIM_SWIPE); return; }
default -> {}
}
if (!this.isInWater()) {
this.setAnimationState(ANIM_SWIM);
return;
}
Vec3 vel = this.getDeltaMovement();
double hSqr = vel.horizontalDistanceSqr();
double vSqr = vel.y * vel.y;
if (hSqr > 0.03D && hSqr > vSqr * 2.5D) {
this.setAnimationState(ANIM_SWIM);
return;
}
this.setAnimationState(ANIM_IDLE);
}
@Override @Override
public void die(DamageSource damageSource) { public void die(DamageSource damageSource) {
if (!this.level().isClientSide) { if (!this.level().isClientSide) {
this.setAnimationState(ANIM_DEATH); this.setAnimationState(ANIM_DEATH);
this.actionTicks = 0;
this.attackCooldown = 0;
this.setAttackState(ATTACK_NONE); this.setAttackState(ATTACK_NONE);
this.setRoaring(false);
this.setDeltaMovement(Vec3.ZERO); this.setDeltaMovement(Vec3.ZERO);
this.getNavigation().stop(); this.getNavigation().stop();
} }
@@ -620,65 +579,28 @@ public class OctopusBombEntity extends Monster implements GeoEntity {
@Override @Override
protected void tickDeath() { protected void tickDeath() {
this.deathTime++; this.deathTime++;
if (this.deathTime == 1) this.setAnimationState(ANIM_DEATH);
if (this.deathTime == 1) {
this.setAnimationState(ANIM_DEATH);
}
if (this.deathTime >= DEATH_ANIM_TICKS) { if (this.deathTime >= DEATH_ANIM_TICKS) {
this.remove(RemovalReason.KILLED); this.remove(RemovalReason.KILLED);
this.dropExperience(this); this.dropExperience(this);
} }
} }
private void updateAnimationState() { // -------------------------------------------------------------------------
if (this.isDeadOrDying()) { // Inner goal: only target players when spawned by Kraken in fly mode
this.setAnimationState(ANIM_DEATH); // -------------------------------------------------------------------------
return;
private static final class KrakenSummonTargetGoal extends NearestAttackableTargetGoal<Player> {
private final OctopusBombEntity octopus;
KrakenSummonTargetGoal(OctopusBombEntity octopus) {
super(octopus, Player.class, true);
this.octopus = octopus;
} }
if (this.isRoaring()) { @Override
this.setAnimationState(ANIM_IDLE); public boolean canUse() {
return; return this.octopus.spawnedByKraken && this.octopus.canFly() && super.canUse();
} }
switch (this.getAttackState()) {
case ATTACK_GRAB -> {
this.setAnimationState(ANIM_GRAB);
return;
}
case ATTACK_SWIPE -> {
this.setAnimationState(ANIM_SWIPE);
return;
}
default -> {
}
}
if (!this.isInWater()) {
this.setAnimationState(ANIM_SWIM);
return;
}
Vec3 velocity = this.getDeltaMovement();
double horizontalSpeedSqr = velocity.horizontalDistanceSqr();
double verticalSpeedSqr = velocity.y * velocity.y;
if (horizontalSpeedSqr > 0.03D && horizontalSpeedSqr > verticalSpeedSqr * 2.5D) {
this.setAnimationState(ANIM_SWIM);
return;
}
this.setAnimationState(ANIM_IDLE);
}
private void tickWanderMovement() {
if (--this.wanderRetargetTicks <= 0) {
this.wanderRetargetTicks = 40 + this.random.nextInt(40);
float angle = this.random.nextFloat() * (float) (Math.PI * 2);
this.wanderDx = Mth.cos(angle) * 0.1f;
this.wanderDy = -0.05f + this.random.nextFloat() * 0.1f;
this.wanderDz = Mth.sin(angle) * 0.1f;
}
this.setDeltaMovement(this.getDeltaMovement().add(this.wanderDx, this.wanderDy, this.wanderDz));
} }
} }
@@ -1230,11 +1230,11 @@ public abstract class BaseAntEntity extends Animal implements GeoEntity {
} }
private boolean shouldPlayAttackAnimation() { private boolean shouldPlayAttackAnimation() {
if (!(this instanceof RedAntEntity)) { return this.shouldUseBiteAnimation() && this.getBiteAnimationTicks() > 0;
return false; }
}
return this.getBiteAnimationTicks() > 0; protected boolean shouldUseBiteAnimation() {
return this instanceof RedAntEntity;
} }
private int getBiteAnimationTicks() { private int getBiteAnimationTicks() {
@@ -1245,6 +1245,10 @@ public abstract class BaseAntEntity extends Animal implements GeoEntity {
this.entityData.set(BITE_ANIM_TICKS, Math.max(0, ticks)); this.entityData.set(BITE_ANIM_TICKS, Math.max(0, ticks));
} }
protected final void triggerBiteAnimation(int ticks) {
this.setBiteAnimationTicks(ticks);
}
private void syncAttribute(@Nullable AttributeInstance attributeInstance, double desiredValue, boolean rescaleCurrentHealth) { private void syncAttribute(@Nullable AttributeInstance attributeInstance, double desiredValue, boolean rescaleCurrentHealth) {
if (attributeInstance == null || Math.abs(attributeInstance.getBaseValue() - desiredValue) < ATTRIBUTE_EPSILON) { if (attributeInstance == null || Math.abs(attributeInstance.getBaseValue() - desiredValue) < ATTRIBUTE_EPSILON) {
return; return;
@@ -17,6 +17,7 @@ import org.jetbrains.annotations.Nullable;
import software.bernie.geckolib.animatable.GeoEntity; import software.bernie.geckolib.animatable.GeoEntity;
public class TermiteEntity extends BaseAntEntity implements GeoEntity { public class TermiteEntity extends BaseAntEntity implements GeoEntity {
private static final int WOOD_BITE_ANIMATION_TICKS = 8;
private static final int WOOD_SEARCH_INTERVAL_TICKS = 10; private static final int WOOD_SEARCH_INTERVAL_TICKS = 10;
private static final int WOOD_REPATH_INTERVAL_TICKS = 6; private static final int WOOD_REPATH_INTERVAL_TICKS = 6;
private static final int WOOD_SEARCH_RADIUS_HORIZONTAL = 12; private static final int WOOD_SEARCH_RADIUS_HORIZONTAL = 12;
@@ -88,6 +89,11 @@ public class TermiteEntity extends BaseAntEntity implements GeoEntity {
return false; return false;
} }
@Override
protected boolean shouldUseBiteAnimation() {
return true;
}
@Override @Override
protected boolean handlePriorityForaging() { protected boolean handlePriorityForaging() {
if (!this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { if (!this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
@@ -126,6 +132,7 @@ public class TermiteEntity extends BaseAntEntity implements GeoEntity {
} }
SoundType soundType = targetState.getSoundType(); SoundType soundType = targetState.getSoundType();
this.triggerBiteAnimation(WOOD_BITE_ANIMATION_TICKS);
this.level().destroyBlock(targetPos, false, this); this.level().destroyBlock(targetPos, false, this);
this.level().playSound(null, targetPos, soundType.getBreakSound(), this.getSoundSource(), 0.7F, 1.1F); this.level().playSound(null, targetPos, soundType.getBreakSound(), this.getSoundSource(), 0.7F, 1.1F);
return true; return true;
@@ -0,0 +1,42 @@
package com.craisinlord.antarchy.content.fluid;
import com.craisinlord.antarchy.content.AntarchyObjects;
import net.minecraft.core.BlockPos;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.tags.EntityTypeTags;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.LiquidBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FlowingFluid;
import net.minecraft.world.phys.Vec3;
public class BileLiquidBlock extends LiquidBlock {
private static final int EFFECT_DURATION_TICKS = 100;
private static final Vec3 SLOW_MOVEMENT = new Vec3(0.85D, 0.95D, 0.85D);
public BileLiquidBlock(FlowingFluid fluid, BlockBehaviour.Properties properties) {
super(fluid, properties);
}
@Override
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
super.entityInside(state, level, pos, entity);
if (entity instanceof LivingEntity livingEntity) {
if (!level.isClientSide) {
livingEntity.addEffect(new MobEffectInstance(AntarchyObjects.STINKY_EFFECT.get(), EFFECT_DURATION_TICKS, 0, false, true, true));
livingEntity.addEffect(new MobEffectInstance(MobEffects.WEAKNESS, EFFECT_DURATION_TICKS, 0, false, true, true));
}
if (livingEntity.getType().is(EntityTypeTags.SENSITIVE_TO_BANE_OF_ARTHROPODS)) {
return;
}
}
entity.makeStuckInBlock(state, SLOW_MOVEMENT);
}
}
@@ -0,0 +1,150 @@
package com.craisinlord.antarchy.content.worldgen.cavaryn;
import com.craisinlord.antarchy.Antarchy;
import com.mojang.serialization.Codec;
import java.util.Optional;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.LiquidBlock;
import net.minecraft.world.level.block.state.BlockState;
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;
import net.minecraft.world.level.material.FluidState;
public final class CavarynBilePoolFeature extends Feature<NoneFeatureConfiguration> {
private static final ResourceLocation BILE_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "bile");
private static final int SEARCH_RADIUS = 8;
private static final int SEARCH_ATTEMPTS = 24;
private static final int FLOOR_SCAN_RANGE = 14;
public CavarynBilePoolFeature(Codec<NoneFeatureConfiguration> codec) {
super(codec);
}
@Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> context) {
Block bileBlock = getBlock(BILE_ID);
if (!(bileBlock instanceof LiquidBlock)) {
return false;
}
WorldGenLevel level = context.level();
RandomSource random = context.random();
BlockPos floorCenter = findPoolFloor(level, context.origin(), random);
if (floorCenter == null) {
return false;
}
return placePool(level, floorCenter, bileBlock.defaultBlockState(), random);
}
private static BlockPos findPoolFloor(WorldGenLevel level, BlockPos origin, RandomSource random) {
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
for (int attempt = 0; attempt < SEARCH_ATTEMPTS; attempt++) {
int x = origin.getX() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS;
int z = origin.getZ() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS;
int startY = origin.getY() + random.nextInt(FLOOR_SCAN_RANGE * 2 + 1) - FLOOR_SCAN_RANGE;
startY = Math.max(level.getMinBuildHeight() + 3, Math.min(level.getMaxBuildHeight() - 4, startY));
for (int y = startY; y >= Math.max(level.getMinBuildHeight() + 2, startY - FLOOR_SCAN_RANGE); y--) {
mutable.set(x, y, z);
BlockState floorState = level.getBlockState(mutable);
if (!isValidFloor(level, mutable, floorState)) {
continue;
}
BlockState aboveState = level.getBlockState(mutable.above());
if (!isOpenBlock(aboveState)) {
continue;
}
if (countSolidNeighbors(level, mutable) >= 3) {
return mutable.immutable();
}
}
}
return null;
}
private static boolean placePool(WorldGenLevel level, BlockPos center, BlockState bileState, RandomSource random) {
boolean placedAny = false;
int radius = 2 + random.nextInt(3);
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
for (int dx = -radius; dx <= radius; dx++) {
for (int dz = -radius; dz <= radius; dz++) {
double normalized = (dx * dx + dz * dz) / (double) Math.max(1, radius * radius);
if (normalized > 1.0D + random.nextDouble() * 0.2D) {
continue;
}
double density = 1.0D - Math.min(1.0D, normalized);
int localDepth = density > 0.45D || random.nextFloat() < 0.35F ? 2 : 1;
localDepth = Mth.clamp(localDepth, 1, 2);
for (int depth = 0; depth < localDepth; depth++) {
mutable.set(center.getX() + dx, center.getY() - depth, center.getZ() + dz);
BlockState existing = level.getBlockState(mutable);
FluidState existingFluid = existing.getFluidState();
if (existing.is(Blocks.BEDROCK)) {
break;
}
if (!existing.canBeReplaced() && existingFluid.isEmpty() && !existing.blocksMotion()) {
continue;
}
level.setBlock(mutable, bileState, 2);
scheduleFluidTick(level, mutable, bileState);
placedAny = true;
}
}
}
return placedAny;
}
private static boolean isValidFloor(WorldGenLevel level, BlockPos pos, BlockState state) {
return !state.isAir()
&& !state.is(Blocks.BEDROCK)
&& state.getFluidState().isEmpty()
&& state.blocksMotion()
&& state.isFaceSturdy(level, pos, Direction.UP);
}
private static boolean isOpenBlock(BlockState state) {
return state.isAir() || state.canBeReplaced() || !state.getFluidState().isEmpty();
}
private static int countSolidNeighbors(WorldGenLevel level, BlockPos pos) {
int solidNeighbors = 0;
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
for (Direction direction : Direction.Plane.HORIZONTAL) {
mutable.setWithOffset(pos, direction);
if (isValidFloor(level, mutable, level.getBlockState(mutable))) {
solidNeighbors++;
}
}
return solidNeighbors;
}
private static void scheduleFluidTick(WorldGenLevel level, BlockPos pos, BlockState state) {
FluidState fluidState = state.getFluidState();
if (!fluidState.isEmpty()) {
level.scheduleTick(pos, fluidState.getType(), fluidState.getType().getTickDelay(level));
}
}
private static Block getBlock(ResourceLocation id) {
Optional<Block> block = BuiltInRegistries.BLOCK.getOptional(id);
return block.orElse(null);
}
}
@@ -0,0 +1,118 @@
package com.craisinlord.antarchy.content.worldgen.cavaryn;
import com.craisinlord.antarchy.Antarchy;
import com.mojang.serialization.Codec;
import java.util.Optional;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.VineBlock;
import net.minecraft.world.level.block.state.BlockState;
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;
public final class CavarynCreepvineFeature extends Feature<NoneFeatureConfiguration> {
private static final ResourceLocation CREEPVINE_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "creepvine");
private static final int SEARCH_RADIUS = 8;
private static final int SEARCH_ATTEMPTS = 24;
private static final int VERTICAL_SCAN = 12;
public CavarynCreepvineFeature(Codec<NoneFeatureConfiguration> codec) {
super(codec);
}
@Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> context) {
Block creepvineBlock = getBlock(CREEPVINE_ID);
if (!(creepvineBlock instanceof VineBlock vineBlock)) {
return false;
}
WorldGenLevel level = context.level();
RandomSource random = context.random();
Anchor anchor = findAnchor(level, context.origin(), random);
if (anchor == null) {
return false;
}
return placeVineColumn(level, vineBlock, anchor, random);
}
private static Anchor findAnchor(WorldGenLevel level, BlockPos origin, RandomSource random) {
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
for (int attempt = 0; attempt < SEARCH_ATTEMPTS; attempt++) {
int x = origin.getX() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS;
int z = origin.getZ() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS;
int startY = origin.getY() + random.nextInt(VERTICAL_SCAN * 2 + 1) - VERTICAL_SCAN;
startY = Math.max(level.getMinBuildHeight() + 3, Math.min(level.getMaxBuildHeight() - 3, startY));
for (int y = startY; y >= Math.max(level.getMinBuildHeight() + 1, startY - VERTICAL_SCAN); y--) {
mutable.set(x, y, z);
if (!level.getBlockState(mutable).canBeReplaced()) {
continue;
}
for (Direction direction : Direction.Plane.HORIZONTAL) {
BlockPos supportPos = mutable.relative(direction);
BlockState supportState = level.getBlockState(supportPos);
if (supportState.isFaceSturdy(level, supportPos, direction.getOpposite())) {
return new Anchor(mutable.immutable(), direction);
}
}
}
}
return null;
}
private static boolean placeVineColumn(WorldGenLevel level, VineBlock vineBlock, Anchor anchor, RandomSource random) {
boolean placedAny = false;
int length = 3 + random.nextInt(6);
for (int offset = 0; offset < length; offset++) {
BlockPos vinePos = anchor.pos().below(offset);
if (vinePos.getY() <= level.getMinBuildHeight()) {
break;
}
BlockState existing = level.getBlockState(vinePos);
if (!existing.canBeReplaced() && !existing.is(vineBlock)) {
break;
}
BlockState vineState = createVineState(vineBlock, anchor.supportDirection());
if (vineState == null || !vineState.canSurvive(level, vinePos)) {
break;
}
level.setBlock(vinePos, vineState, 3);
placedAny = true;
}
return placedAny;
}
private static BlockState createVineState(VineBlock vineBlock, Direction attachedFace) {
BlockState state = vineBlock.defaultBlockState();
return switch (attachedFace) {
case NORTH -> state.setValue(VineBlock.NORTH, Boolean.TRUE);
case SOUTH -> state.setValue(VineBlock.SOUTH, Boolean.TRUE);
case EAST -> state.setValue(VineBlock.EAST, Boolean.TRUE);
case WEST -> state.setValue(VineBlock.WEST, Boolean.TRUE);
default -> null;
};
}
private static Block getBlock(ResourceLocation id) {
Optional<Block> block = BuiltInRegistries.BLOCK.getOptional(id);
return block.orElse(null);
}
private record Anchor(BlockPos pos, Direction supportDirection) {
}
}
@@ -0,0 +1,122 @@
package com.craisinlord.antarchy.content.worldgen.cavaryn;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.block.CreepingHorrorEggBlock;
import com.craisinlord.antarchy.content.block.LurkingTerrorEggBlock;
import com.mojang.serialization.Codec;
import java.util.List;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.state.BlockState;
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;
public final class CavarynEggPatchFeature extends Feature<NoneFeatureConfiguration> {
private static final int SEARCH_RADIUS = 8;
private static final int SEARCH_ATTEMPTS = 20;
private static final int FLOOR_SCAN_RANGE = 10;
public CavarynEggPatchFeature(Codec<NoneFeatureConfiguration> codec) {
super(codec);
}
@Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> context) {
WorldGenLevel level = context.level();
RandomSource random = context.random();
BlockPos origin = context.origin();
BlockPos surfacePos = findSurfacePos(level, origin, random);
if (surfacePos == null) {
return false;
}
EggType eggType = random.nextBoolean() ? EggType.CREEPING_HORROR : EggType.LURKING_TERROR;
return placePatch(level, surfacePos, random, eggType);
}
private static BlockPos findSurfacePos(WorldGenLevel level, BlockPos origin, RandomSource random) {
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
for (int attempt = 0; attempt < SEARCH_ATTEMPTS; attempt++) {
int x = origin.getX() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS;
int z = origin.getZ() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS;
int startY = origin.getY() + random.nextInt(FLOOR_SCAN_RANGE * 2 + 1) - FLOOR_SCAN_RANGE;
startY = Math.max(level.getMinBuildHeight() + 2, Math.min(level.getMaxBuildHeight() - 3, startY));
for (int y = startY; y >= Math.max(level.getMinBuildHeight() + 1, startY - FLOOR_SCAN_RANGE); y--) {
mutable.set(x, y, z);
BlockState floorState = level.getBlockState(mutable);
BlockState airState = level.getBlockState(mutable.above());
if (floorState.getFluidState().isEmpty()
&& floorState.blocksMotion()
&& floorState.isFaceSturdy(level, mutable, Direction.UP)
&& airState.canBeReplaced()) {
return mutable.immutable();
}
}
}
return null;
}
private boolean placePatch(WorldGenLevel level, BlockPos center, RandomSource random, EggType eggType) {
int radius = 2 + random.nextInt(3);
boolean placedAny = false;
List<BlockPos> eggSpots = new java.util.ArrayList<>();
for (int dx = -radius; dx <= radius; dx++) {
for (int dz = -radius; dz <= radius; dz++) {
double distance = dx * dx + dz * dz;
if (distance > radius * radius + random.nextInt(2)) {
continue;
}
BlockPos floorPos = center.offset(dx, 0, dz);
BlockState floorState = level.getBlockState(floorPos);
BlockPos eggPos = floorPos.above();
BlockState aboveState = level.getBlockState(eggPos);
if (!isValidEggFloor(level, floorPos, floorState, aboveState)) {
continue;
}
eggSpots.add(eggPos);
}
}
if (eggSpots.isEmpty()) {
return placedAny;
}
int eggCount = Math.min(eggSpots.size(), 2 + random.nextInt(3));
for (int i = 0; i < eggCount; i++) {
BlockPos eggPos = eggSpots.get(random.nextInt(eggSpots.size()));
if (!level.getBlockState(eggPos).canBeReplaced()) {
continue;
}
BlockState eggState = eggType == EggType.CREEPING_HORROR
? AntarchyObjects.CREEPING_HORROR_EGGS.get().defaultBlockState()
: AntarchyObjects.LURKING_TERROR_EGGS.get().defaultBlockState();
eggState = eggState.setValue(eggType == EggType.CREEPING_HORROR ? CreepingHorrorEggBlock.EGGS : LurkingTerrorEggBlock.EGGS, 1 + random.nextInt(4));
level.setBlock(eggPos, eggState, 3);
placedAny = true;
}
return placedAny;
}
private static boolean isValidEggFloor(WorldGenLevel level, BlockPos floorPos, BlockState floorState, BlockState aboveState) {
return !floorState.isAir()
&& floorState.getFluidState().isEmpty()
&& floorState.blocksMotion()
&& floorState.isFaceSturdy(level, floorPos, Direction.UP)
&& aboveState.canBeReplaced();
}
private enum EggType {
CREEPING_HORROR,
LURKING_TERROR
}
}
@@ -0,0 +1,165 @@
package com.craisinlord.antarchy.content.worldgen.cavaryn;
import com.craisinlord.antarchy.Antarchy;
import com.mojang.serialization.Codec;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.MultifaceBlock;
import net.minecraft.world.level.block.state.BlockState;
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;
public final class CavarynWallAmberMossFeature extends Feature<NoneFeatureConfiguration> {
private static final ResourceLocation AMBER_LICHEN_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "amber_lichen");
private static final ResourceLocation GLOW_LICHEN_ID = ResourceLocation.withDefaultNamespace("glow_lichen");
private static final int SEARCH_RADIUS = 8;
private static final int SEARCH_ATTEMPTS = 28;
private static final int VERTICAL_SCAN = 10;
public CavarynWallAmberMossFeature(Codec<NoneFeatureConfiguration> codec) {
super(codec);
}
@Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> context) {
WorldGenLevel level = context.level();
RandomSource random = context.random();
Block amberLichenBlock = getBlock(AMBER_LICHEN_ID);
Block glowLichenBlock = getBlock(GLOW_LICHEN_ID);
if (amberLichenBlock == null || glowLichenBlock == null) {
return false;
}
Anchor anchor = findAnchor(level, context.origin(), random);
if (anchor == null) {
return false;
}
List<BlockPos> placedPatch = placeWallPatch(level, anchor, amberLichenBlock, random);
if (placedPatch.isEmpty()) {
return false;
}
placeLichenFringe(level, placedPatch, anchor.supportDirection(), amberLichenBlock, glowLichenBlock, random);
return true;
}
private static Anchor findAnchor(WorldGenLevel level, BlockPos origin, RandomSource random) {
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
for (int attempt = 0; attempt < SEARCH_ATTEMPTS; attempt++) {
int x = origin.getX() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS;
int z = origin.getZ() + random.nextInt(SEARCH_RADIUS * 2 + 1) - SEARCH_RADIUS;
int startY = origin.getY() + random.nextInt(VERTICAL_SCAN * 2 + 1) - VERTICAL_SCAN;
startY = Math.max(level.getMinBuildHeight() + 2, Math.min(level.getMaxBuildHeight() - 3, startY));
for (int y = startY; y >= Math.max(level.getMinBuildHeight() + 1, startY - VERTICAL_SCAN); y--) {
mutable.set(x, y, z);
if (!level.getBlockState(mutable).canBeReplaced()) {
continue;
}
for (Direction direction : Direction.Plane.HORIZONTAL) {
BlockPos supportPos = mutable.relative(direction);
BlockState supportState = level.getBlockState(supportPos);
if (supportState.isFaceSturdy(level, supportPos, direction.getOpposite())) {
return new Anchor(mutable.immutable(), direction);
}
}
}
}
return null;
}
private static List<BlockPos> placeWallPatch(WorldGenLevel level, Anchor anchor, Block amberLichenBlock, RandomSource random) {
List<BlockPos> placed = new ArrayList<>();
Direction lateral = anchor.supportDirection().getClockWise();
int width = 1 + random.nextInt(3);
int height = 2 + random.nextInt(4);
for (int yOffset = 0; yOffset < height; yOffset++) {
for (int lateralOffset = -width; lateralOffset <= width; lateralOffset++) {
if (Math.abs(lateralOffset) == width && random.nextBoolean()) {
continue;
}
BlockPos pos = anchor.pos().above(yOffset).relative(lateral, lateralOffset);
if (!canPlaceWallMoss(level, pos, anchor.supportDirection())) {
continue;
}
BlockState state = createLichenState(amberLichenBlock, anchor.supportDirection());
if (!state.canSurvive(level, pos)) {
continue;
}
level.setBlock(pos, state, 3);
placed.add(pos.immutable());
}
}
return placed;
}
private static void placeLichenFringe(
WorldGenLevel level,
List<BlockPos> patchPositions,
Direction supportDirection,
Block amberLichenBlock,
Block glowLichenBlock,
RandomSource random
) {
for (BlockPos patchPos : patchPositions) {
for (Direction spread : List.of(Direction.UP, Direction.DOWN, supportDirection.getClockWise(), supportDirection.getCounterClockWise())) {
if (random.nextFloat() > 0.45F) {
continue;
}
BlockPos targetPos = patchPos.relative(spread);
if (!level.getBlockState(targetPos).canBeReplaced()) {
continue;
}
if (!hasSupport(level, targetPos, supportDirection)) {
continue;
}
BlockState state = createLichenState(random.nextFloat() < 0.65F ? amberLichenBlock : glowLichenBlock, supportDirection);
if (!state.canSurvive(level, targetPos)) {
continue;
}
level.setBlock(targetPos, state, 3);
}
}
}
private static boolean canPlaceWallMoss(WorldGenLevel level, BlockPos pos, Direction supportDirection) {
return level.getBlockState(pos).canBeReplaced() && hasSupport(level, pos, supportDirection);
}
private static boolean hasSupport(WorldGenLevel level, BlockPos pos, Direction supportDirection) {
BlockPos supportPos = pos.relative(supportDirection);
return level.getBlockState(supportPos).isFaceSturdy(level, supportPos, supportDirection.getOpposite());
}
private static BlockState createLichenState(Block lichenBlock, Direction supportDirection) {
return lichenBlock.defaultBlockState().setValue(MultifaceBlock.getFaceProperty(supportDirection), true);
}
private static Block getBlock(ResourceLocation id) {
Optional<Block> block = BuiltInRegistries.BLOCK.getOptional(id);
return block.orElse(null);
}
private record Anchor(BlockPos pos, Direction supportDirection) {
}
}
@@ -0,0 +1,37 @@
package com.craisinlord.antarchy.content.worldgen.cavaryn;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
public record ChitenSpikeConfiguration(
int floorToCeilingSearchRange,
int radius,
int maxColumnHeight,
int heightDeviation,
float chanceOfColumnAtMaxDistanceFromCenter,
int maxDistanceFromCenterAffectingChanceOfColumn,
int maxDistanceFromCenterAffectingHeightBias,
int maxHeightDifference,
float largeVariantChance,
int largeVariantExtraRadius,
int largeVariantExtraHeight,
int largeVariantExtraHeightDeviation,
float largeVariantSurfaceSpikeMultiplier
) implements FeatureConfiguration {
public static final Codec<ChitenSpikeConfiguration> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.intRange(1, 128).fieldOf("floor_to_ceiling_search_range").forGetter(ChitenSpikeConfiguration::floorToCeilingSearchRange),
Codec.intRange(1, 32).fieldOf("radius").forGetter(ChitenSpikeConfiguration::radius),
Codec.intRange(1, 32).fieldOf("max_column_height").forGetter(ChitenSpikeConfiguration::maxColumnHeight),
Codec.intRange(1, 16).fieldOf("height_deviation").forGetter(ChitenSpikeConfiguration::heightDeviation),
Codec.floatRange(0.0F, 1.0F).fieldOf("chance_of_column_at_max_distance_from_center").forGetter(ChitenSpikeConfiguration::chanceOfColumnAtMaxDistanceFromCenter),
Codec.intRange(1, 64).fieldOf("max_distance_from_center_affecting_chance_of_column").forGetter(ChitenSpikeConfiguration::maxDistanceFromCenterAffectingChanceOfColumn),
Codec.intRange(1, 64).fieldOf("max_distance_from_center_affecting_height_bias").forGetter(ChitenSpikeConfiguration::maxDistanceFromCenterAffectingHeightBias),
Codec.intRange(0, 32).fieldOf("max_height_difference").forGetter(ChitenSpikeConfiguration::maxHeightDifference),
Codec.floatRange(0.0F, 1.0F).optionalFieldOf("large_variant_chance", 0.0F).forGetter(ChitenSpikeConfiguration::largeVariantChance),
Codec.intRange(0, 24).optionalFieldOf("large_variant_extra_radius", 0).forGetter(ChitenSpikeConfiguration::largeVariantExtraRadius),
Codec.intRange(0, 32).optionalFieldOf("large_variant_extra_height", 0).forGetter(ChitenSpikeConfiguration::largeVariantExtraHeight),
Codec.intRange(0, 16).optionalFieldOf("large_variant_extra_height_deviation", 0).forGetter(ChitenSpikeConfiguration::largeVariantExtraHeightDeviation),
Codec.floatRange(1.0F, 8.0F).optionalFieldOf("large_variant_surface_spike_multiplier", 1.0F).forGetter(ChitenSpikeConfiguration::largeVariantSurfaceSpikeMultiplier)
).apply(instance, ChitenSpikeConfiguration::new));
}
@@ -0,0 +1,253 @@
package com.craisinlord.antarchy.content.worldgen.cavaryn;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.mojang.serialization.Codec;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.OptionalInt;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.PointedDripstoneBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.DripstoneThickness;
import net.minecraft.world.level.levelgen.Column;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
public final class ChitenSpikeFeature extends Feature<ChitenSpikeConfiguration> {
private record ResolvedVariant(int radius, int maxColumnHeight, int heightDeviation, int surfaceSpikeAttempts) {
}
public ChitenSpikeFeature(Codec<ChitenSpikeConfiguration> codec) {
super(codec);
}
@Override
public boolean place(FeaturePlaceContext<ChitenSpikeConfiguration> context) {
WorldGenLevel level = context.level();
BlockPos origin = context.origin();
ChitenSpikeConfiguration config = context.config();
RandomSource random = context.random();
if (!level.getBlockState(origin).isAir()) {
return false;
}
boolean placedAny = false;
List<BlockPos> placedBlocks = new ArrayList<>();
ResolvedVariant variant = this.resolveVariant(config, random);
int radius = variant.radius();
for (int dx = -radius; dx <= radius; dx++) {
for (int dz = -radius; dz <= radius; dz++) {
double chance = this.getChanceOfColumn(radius, dx, dz, config);
if (chance <= 0.0D) {
continue;
}
if (this.placeColumn(level, random, origin.offset(dx, 0, dz), dx, dz, chance, config, variant, placedBlocks)) {
placedAny = true;
}
}
}
if (this.dotSurfaceSpikes(level, random, placedBlocks, config, variant)) {
placedAny = true;
}
return placedAny;
}
private ResolvedVariant resolveVariant(ChitenSpikeConfiguration config, RandomSource random) {
if (config.largeVariantChance() > 0.0F && random.nextFloat() < config.largeVariantChance()) {
int radius = config.radius() + config.largeVariantExtraRadius();
int maxColumnHeight = config.maxColumnHeight() + config.largeVariantExtraHeight();
int heightDeviation = config.heightDeviation() + config.largeVariantExtraHeightDeviation();
int baseAttempts = Math.max(8, ((radius * 2) + 1) * ((radius * 2) + 1) / 6);
int surfaceSpikeAttempts = Math.max(baseAttempts + 4, Math.round(baseAttempts * config.largeVariantSurfaceSpikeMultiplier()));
return new ResolvedVariant(radius, maxColumnHeight, heightDeviation, surfaceSpikeAttempts);
}
int radius = config.radius();
int baseAttempts = Math.max(8, ((radius * 2) + 1) * ((radius * 2) + 1) / 6);
return new ResolvedVariant(radius, config.maxColumnHeight(), config.heightDeviation(), baseAttempts);
}
private boolean placeColumn(
WorldGenLevel level,
RandomSource random,
BlockPos pos,
int dx,
int dz,
double chance,
ChitenSpikeConfiguration config,
ResolvedVariant variant,
List<BlockPos> placedBlocks
) {
Optional<Column> optional = Column.scan(level, pos, config.floorToCeilingSearchRange(), state -> state.isAir(), state -> !state.isAir());
if (optional.isEmpty()) {
return false;
}
Column column = optional.get();
OptionalInt ceiling = column.getCeiling();
OptionalInt floor = column.getFloor();
int maxHeight = this.getMaxLength(variant, ceiling, floor);
int downLength = 0;
int upLength = 0;
if (ceiling.isPresent()) {
downLength = this.getSpikeHeight(random, dx, dz, chance, maxHeight, config.maxDistanceFromCenterAffectingHeightBias(), variant.heightDeviation());
}
if (floor.isPresent()) {
if (downLength > 0) {
upLength = Mth.clamp(
downLength + Mth.randomBetweenInclusive(random, -config.maxHeightDifference(), config.maxHeightDifference()),
0,
maxHeight
);
} else {
upLength = this.getSpikeHeight(random, dx, dz, chance, maxHeight, config.maxDistanceFromCenterAffectingHeightBias(), variant.heightDeviation());
}
}
boolean placedAny = false;
if (ceiling.isPresent() && downLength > 0) {
placedAny |= this.growChitenColumn(level, pos.atY(ceiling.getAsInt() - 1), Direction.DOWN, downLength, placedBlocks);
}
if (floor.isPresent() && upLength > 0) {
placedAny |= this.growChitenColumn(level, pos.atY(floor.getAsInt() + 1), Direction.UP, upLength, placedBlocks);
}
return placedAny;
}
private int getMaxLength(ResolvedVariant variant, OptionalInt ceiling, OptionalInt floor) {
if (ceiling.isPresent() && floor.isPresent()) {
return Math.min(variant.maxColumnHeight(), ceiling.getAsInt() - floor.getAsInt() - 1);
}
return variant.maxColumnHeight();
}
private boolean growChitenColumn(WorldGenLevel level, BlockPos rootStart, Direction direction, int length, List<BlockPos> placedBlocks) {
boolean placedAny = false;
for (int offset = 0; offset < length; offset++) {
BlockPos spikePos = rootStart.relative(direction, offset);
if (spikePos.getY() < level.getMinBuildHeight() || spikePos.getY() >= level.getMaxBuildHeight()) {
break;
}
BlockState current = level.getBlockState(spikePos);
if (!current.isAir()) {
break;
}
BlockState chitenState = AntarchyObjects.CHITEN_BLOCK.get().defaultBlockState();
level.setBlock(spikePos, chitenState, 3);
placedBlocks.add(spikePos.immutable());
placedAny = true;
}
return placedAny;
}
private boolean dotSurfaceSpikes(
WorldGenLevel level,
RandomSource random,
List<BlockPos> placedBlocks,
ChitenSpikeConfiguration config,
ResolvedVariant variant
) {
boolean placedAny = false;
if (placedBlocks.isEmpty()) {
return false;
}
int attempts = Math.max(variant.surfaceSpikeAttempts(), placedBlocks.size() / 6);
for (int i = 0; i < attempts; i++) {
BlockPos anchor = placedBlocks.get(random.nextInt(placedBlocks.size()));
Direction direction = random.nextBoolean() ? Direction.UP : Direction.DOWN;
int length = 1 + random.nextInt(Math.max(1, config.maxHeightDifference() + 1));
BlockPos start = anchor.relative(direction);
if (this.growSurfaceSpike(level, start, direction, length)) {
placedAny = true;
}
}
return placedAny;
}
private boolean growSurfaceSpike(WorldGenLevel level, BlockPos startPos, Direction direction, int length) {
boolean placedAny = false;
for (int offset = 0; offset < length; offset++) {
BlockPos spikePos = startPos.relative(direction, offset);
if (spikePos.getY() < level.getMinBuildHeight() || spikePos.getY() >= level.getMaxBuildHeight()) {
break;
}
if (!level.getBlockState(spikePos).isAir()) {
break;
}
BlockState spikeState = AntarchyObjects.CHITEN_SPIKE.get().defaultBlockState()
.setValue(PointedDripstoneBlock.TIP_DIRECTION, direction)
.setValue(PointedDripstoneBlock.THICKNESS, getThicknessForRootOffset(offset, length))
.setValue(PointedDripstoneBlock.WATERLOGGED, false);
if (!spikeState.canSurvive(level, spikePos)) {
break;
}
level.setBlock(spikePos, spikeState, 3);
placedAny = true;
}
return placedAny;
}
private static DripstoneThickness getThicknessForRootOffset(int offsetFromRoot, int length) {
if (length <= 1 || offsetFromRoot == length - 1) {
return DripstoneThickness.TIP;
}
if (offsetFromRoot == length - 2) {
return DripstoneThickness.FRUSTUM;
}
if (offsetFromRoot == 0) {
return DripstoneThickness.BASE;
}
return DripstoneThickness.MIDDLE;
}
private int getSpikeHeight(
RandomSource random,
int dx,
int dz,
double chance,
int maxHeight,
int maxDistanceFromCenterAffectingHeightBias,
int heightDeviation
) {
if (maxHeight <= 0 || random.nextDouble() > chance) {
return 0;
}
int distance = Math.abs(dx) + Math.abs(dz);
float mean = (float) Mth.clampedMap(
(double) distance,
0.0D,
(double) maxDistanceFromCenterAffectingHeightBias,
(double) maxHeight,
1.0D
);
int sampled = Math.round((float) (mean + random.nextGaussian() * Math.max(1, Math.min(maxHeight, heightDeviation))));
return Mth.clamp(sampled, 1, maxHeight);
}
private double getChanceOfColumn(int radius, int dx, int dz, ChitenSpikeConfiguration config) {
int remainingX = radius - Math.abs(dx);
int remainingZ = radius - Math.abs(dz);
int edgeDistance = Math.min(remainingX, remainingZ);
return Mth.clampedMap(
(double) edgeDistance,
0.0D,
(double) config.maxDistanceFromCenterAffectingChanceOfColumn(),
(double) config.chanceOfColumnAtMaxDistanceFromCenter(),
1.0D
);
}
}
@@ -0,0 +1,178 @@
package com.craisinlord.antarchy.content.worldgen.elythia;
import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.SeaPickleBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.levelgen.Heightmap;
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;
public class CoralSpikeFeature extends Feature<NoneFeatureConfiguration> {
private record CoralSet(
net.minecraft.world.level.block.Block block,
net.minecraft.world.level.block.Block coral,
net.minecraft.world.level.block.Block wallFan,
net.minecraft.world.level.block.Block floorFan
) {}
private static final CoralSet[] CORAL_SETS = {
new CoralSet(Blocks.TUBE_CORAL_BLOCK, Blocks.TUBE_CORAL, Blocks.TUBE_CORAL_WALL_FAN, Blocks.TUBE_CORAL_FAN),
new CoralSet(Blocks.BRAIN_CORAL_BLOCK, Blocks.BRAIN_CORAL, Blocks.BRAIN_CORAL_WALL_FAN, Blocks.BRAIN_CORAL_FAN),
new CoralSet(Blocks.BUBBLE_CORAL_BLOCK, Blocks.BUBBLE_CORAL, Blocks.BUBBLE_CORAL_WALL_FAN, Blocks.BUBBLE_CORAL_FAN),
new CoralSet(Blocks.FIRE_CORAL_BLOCK, Blocks.FIRE_CORAL, Blocks.FIRE_CORAL_WALL_FAN, Blocks.FIRE_CORAL_FAN),
new CoralSet(Blocks.HORN_CORAL_BLOCK, Blocks.HORN_CORAL, Blocks.HORN_CORAL_WALL_FAN, Blocks.HORN_CORAL_FAN),
};
public CoralSpikeFeature(Codec<NoneFeatureConfiguration> codec) {
super(codec);
}
@Override
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> context) {
WorldGenLevel level = context.level();
RandomSource random = context.random();
BlockPos origin = context.origin();
int seaLevel = level.getSeaLevel();
int spikes = 1 + random.nextInt(3);
boolean placed = false;
for (int i = 0; i < spikes; i++) {
int offX = random.nextInt(11) - 5;
int offZ = random.nextInt(11) - 5;
placed |= placeSpike(level, random, origin.offset(offX, 0, offZ), seaLevel);
}
return placed;
}
private boolean placeSpike(WorldGenLevel level, RandomSource random, BlockPos origin, int seaLevel) {
int floorY = level.getHeight(Heightmap.Types.OCEAN_FLOOR_WG, origin.getX(), origin.getZ());
if (floorY >= seaLevel) return false;
CoralSet coral = CORAL_SETS[random.nextInt(CORAL_SETS.length)];
int baseRadius = 2 + random.nextInt(2); // 2–3 wide at base
int totalHeight = 20 + random.nextInt(15); // 20–34 blocks tall
// Curve: lean toward a random horizontal direction, accelerating toward the tip
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
boolean placed = false;
for (int dy = 0; dy < totalHeight; dy++) {
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));
for (int dx = -(radius + 1); dx <= radius + 1; dx++) {
for (int dz = -(radius + 1); dz <= radius + 1; dz++) {
double dist = Math.sqrt(
(origin.getX() + dx - centerX) * (origin.getX() + dx - centerX)
+ (origin.getZ() + dz - centerZ) * (origin.getZ() + dz - centerZ));
if (dist > radius + 0.5) continue;
BlockPos pos = new BlockPos(origin.getX() + dx, blockY, origin.getZ() + dz);
if (!canReplace(level.getBlockState(pos))) continue;
level.setBlock(pos, coral.block().defaultBlockState(), 2);
placed = true;
// Coral plants growing off the top of outer-surface blocks
if (dist >= radius - 0.6 && radius > 0) {
BlockPos above = pos.above();
if (canReplace(level.getBlockState(above))) {
boolean aboveInWater = level.getBlockState(above).is(Blocks.WATER);
if (random.nextFloat() < 0.35f && aboveInWater) {
level.setBlock(above,
coral.coral().defaultBlockState()
.setValue(BlockStateProperties.WATERLOGGED, true),
2);
}
}
}
// Wall fans on the outer surface
if (dist >= radius - 0.5) {
for (Direction dir : Direction.Plane.HORIZONTAL) {
if (random.nextFloat() >= 0.4f) continue;
BlockPos fanPos = pos.relative(dir);
BlockState existing = level.getBlockState(fanPos);
if (!existing.isAir() && !existing.is(Blocks.WATER)) continue;
boolean fanInWater = existing.is(Blocks.WATER);
level.setBlock(fanPos,
coral.wallFan().defaultBlockState()
.setValue(BlockStateProperties.HORIZONTAL_FACING, dir)
.setValue(BlockStateProperties.WATERLOGGED, fanInWater),
2);
}
}
}
}
}
// 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;
int fz = origin.getZ() + random.nextInt(13) - 6;
int fy = level.getHeight(Heightmap.Types.OCEAN_FLOOR_WG, fx, fz);
BlockPos decorPos = new BlockPos(fx, fy, fz);
if (!canReplace(level.getBlockState(decorPos))) continue;
BlockState below = level.getBlockState(decorPos.below());
if (below.isAir() || !below.isFaceSturdy(level, decorPos.below(), Direction.UP)) continue;
boolean decorInWater = level.getBlockState(decorPos).is(Blocks.WATER);
float roll = random.nextFloat();
CoralSet randomCoral = CORAL_SETS[random.nextInt(CORAL_SETS.length)];
if (roll < 0.35f && decorInWater) {
// Coral plant (frond)
BlockState coralState = randomCoral.coral().defaultBlockState()
.setValue(BlockStateProperties.WATERLOGGED, true);
if (coralState.canSurvive(level, decorPos)) {
level.setBlock(decorPos, coralState, 2);
}
} else if (roll < 0.65f) {
// Floor fan
BlockState fanState = randomCoral.floorFan().defaultBlockState()
.setValue(BlockStateProperties.WATERLOGGED, decorInWater);
if (fanState.canSurvive(level, decorPos)) {
level.setBlock(decorPos, fanState, 2);
}
} else {
// Sea pickle cluster
BlockState pickle = Blocks.SEA_PICKLE.defaultBlockState()
.setValue(SeaPickleBlock.PICKLES, 1 + random.nextInt(4));
if (pickle.canSurvive(level, decorPos)) {
level.setBlock(decorPos, pickle, 2);
}
}
}
return placed;
}
private static boolean canReplace(BlockState state) {
return state.isAir() || state.is(Blocks.WATER) || state.canBeReplaced();
}
}
@@ -1,6 +1,7 @@
package com.craisinlord.antarchy.content.worldgen.elythia; package com.craisinlord.antarchy.content.worldgen.elythia;
import com.craisinlord.antarchy.Antarchy; import com.craisinlord.antarchy.Antarchy;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec; import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder; import com.mojang.serialization.codecs.RecordCodecBuilder;
@@ -20,10 +21,18 @@ public class ElythiaBiomeSource extends BiomeSource {
Registries.BIOME, Registries.BIOME,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "moleworm_caves") ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "moleworm_caves")
); );
private static final ResourceKey<Biome> ELYTHIA_LUSH_CAVES = ResourceKey.create(
Registries.BIOME,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "elythia_lush_caves")
);
private static final ResourceKey<Biome> ELYTHIA_OCEAN = ResourceKey.create( private static final ResourceKey<Biome> ELYTHIA_OCEAN = ResourceKey.create(
Registries.BIOME, Registries.BIOME,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "elythia_ocean") ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "elythia_ocean")
); );
private static final ResourceKey<Biome> ELYTHIA_CORAL_SPIKES = ResourceKey.create(
Registries.BIOME,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "elythia_coral_spikes")
);
private static final ResourceKey<Biome> ELYTHIA_BEACH = ResourceKey.create( private static final ResourceKey<Biome> ELYTHIA_BEACH = ResourceKey.create(
Registries.BIOME, Registries.BIOME,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "elythia_beach") ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "elythia_beach")
@@ -34,7 +43,8 @@ public class ElythiaBiomeSource extends BiomeSource {
MultiNoiseBiomeSource.DIRECT_CODEC.forGetter(ElythiaBiomeSource::parameters), MultiNoiseBiomeSource.DIRECT_CODEC.forGetter(ElythiaBiomeSource::parameters),
Codec.INT.optionalFieldOf("moleworm_caves_max_y", 72).forGetter(ElythiaBiomeSource::molewormCavesMaxY), Codec.INT.optionalFieldOf("moleworm_caves_max_y", 72).forGetter(ElythiaBiomeSource::molewormCavesMaxY),
Codec.INT.optionalFieldOf("surface_biome_sample_y", 160).forGetter(ElythiaBiomeSource::surfaceBiomeSampleY), Codec.INT.optionalFieldOf("surface_biome_sample_y", 160).forGetter(ElythiaBiomeSource::surfaceBiomeSampleY),
Codec.INT.optionalFieldOf("ocean_max_y", 85).forGetter(ElythiaBiomeSource::oceanMaxY) Codec.INT.optionalFieldOf("ocean_max_y", 85).forGetter(ElythiaBiomeSource::oceanMaxY),
Codec.INT.optionalFieldOf("sea_level", 78).forGetter(ElythiaBiomeSource::seaLevel)
).apply(instance, ElythiaBiomeSource::new)); ).apply(instance, ElythiaBiomeSource::new));
private final Climate.ParameterList<Holder<Biome>> parameters; private final Climate.ParameterList<Holder<Biome>> parameters;
@@ -42,36 +52,41 @@ public class ElythiaBiomeSource extends BiomeSource {
private final int molewormCavesMaxY; private final int molewormCavesMaxY;
private final int surfaceBiomeSampleY; private final int surfaceBiomeSampleY;
private final int oceanMaxY; private final int oceanMaxY;
private final int seaLevel;
private final int molewormCavesMaxQuartY; private final int molewormCavesMaxQuartY;
private final int surfaceBiomeSampleQuartY; private final int surfaceBiomeSampleQuartY;
private final int oceanMaxQuartY; private final int seaLevelQuartY;
private final Holder<Biome> oceanHolder;
private final Holder<Biome> defaultLandHolder;
public ElythiaBiomeSource(Climate.ParameterList<Holder<Biome>> parameters, int molewormCavesMaxY, int surfaceBiomeSampleY, int oceanMaxY) { public ElythiaBiomeSource(Climate.ParameterList<Holder<Biome>> parameters, int molewormCavesMaxY, int surfaceBiomeSampleY, int oceanMaxY, int seaLevel) {
this.parameters = parameters; this.parameters = parameters;
this.delegate = MultiNoiseBiomeSource.createFromList(parameters); this.delegate = MultiNoiseBiomeSource.createFromList(parameters);
this.molewormCavesMaxY = molewormCavesMaxY; this.molewormCavesMaxY = molewormCavesMaxY;
this.surfaceBiomeSampleY = surfaceBiomeSampleY; this.surfaceBiomeSampleY = surfaceBiomeSampleY;
this.oceanMaxY = oceanMaxY; this.oceanMaxY = oceanMaxY;
this.seaLevel = seaLevel;
this.molewormCavesMaxQuartY = QuartPos.fromBlock(molewormCavesMaxY); this.molewormCavesMaxQuartY = QuartPos.fromBlock(molewormCavesMaxY);
this.surfaceBiomeSampleQuartY = QuartPos.fromBlock(surfaceBiomeSampleY); this.surfaceBiomeSampleQuartY = QuartPos.fromBlock(surfaceBiomeSampleY);
this.oceanMaxQuartY = QuartPos.fromBlock(oceanMaxY); this.seaLevelQuartY = QuartPos.fromBlock(seaLevel);
this.oceanHolder = parameters.values().stream()
.map(Pair::getSecond)
.filter(h -> h.is(ELYTHIA_OCEAN))
.findFirst()
.orElse(null);
this.defaultLandHolder = parameters.values().stream()
.map(Pair::getSecond)
.filter(h -> !isOceanBiome(h) && !h.is(ELYTHIA_BEACH)
&& !h.is(MOLEWORM_CAVES) && !h.is(ELYTHIA_LUSH_CAVES))
.findFirst()
.orElse(null);
} }
private Climate.ParameterList<Holder<Biome>> parameters() { private Climate.ParameterList<Holder<Biome>> parameters() { return this.parameters; }
return this.parameters; private int molewormCavesMaxY() { return this.molewormCavesMaxY; }
} private int surfaceBiomeSampleY() { return this.surfaceBiomeSampleY; }
private int oceanMaxY() { return this.oceanMaxY; }
private int molewormCavesMaxY() { private int seaLevel() { return this.seaLevel; }
return this.molewormCavesMaxY;
}
private int surfaceBiomeSampleY() {
return this.surfaceBiomeSampleY;
}
private int oceanMaxY() {
return this.oceanMaxY;
}
@Override @Override
protected MapCodec<? extends BiomeSource> codec() { protected MapCodec<? extends BiomeSource> codec() {
@@ -83,24 +98,53 @@ public class ElythiaBiomeSource extends BiomeSource {
return this.delegate.possibleBiomes().stream(); return this.delegate.possibleBiomes().stream();
} }
// Conservative threshold well inside the ocean entry range (-0.85 to -0.92).
// At continentalness < -0.80 the terrain is reliably below sea level.
// Transition-zone columns (-0.80 to -0.85) are treated as land to avoid
// ocean biome appearing over above-sea-level terrain.
private static final long OCEAN_CONTINENTALNESS_THRESHOLD = Climate.quantizeCoord(-0.80f);
@Override @Override
public Holder<Biome> getNoiseBiome(int x, int y, int z, Climate.Sampler sampler) { public Holder<Biome> getNoiseBiome(int x, int y, int z, Climate.Sampler sampler) {
Holder<Biome> biome = this.delegate.getNoiseBiome(x, y, z, sampler); Holder<Biome> biome = this.delegate.getNoiseBiome(x, y, z, sampler);
// Cap moleworm caves below their max Y // Cap moleworm caves below their max Y — replace with surface biome above it
if (biome.is(MOLEWORM_CAVES) && y > this.molewormCavesMaxQuartY) { if (biome.is(MOLEWORM_CAVES) && y > this.molewormCavesMaxQuartY) {
return resolveSurfaceFallback(x, y, z, sampler, MOLEWORM_CAVES); return resolveSurfaceFallback(x, y, z, sampler, MOLEWORM_CAVES);
} }
// Cap ocean/beach biomes above sea level — if terrain noise puts these biomes // Use continentalness (XZ-only noise) to classify the column.
// too high, replace with whatever surface biome would naturally be there // Ocean columns get the ocean biome at every Y so structures, particles,
if ((biome.is(ELYTHIA_OCEAN) || biome.is(ELYTHIA_BEACH)) && y > this.oceanMaxQuartY) { // and ambient effects work correctly above the water surface.
return resolveSurfaceFallback(x, y, z, sampler, ELYTHIA_OCEAN, ELYTHIA_BEACH); Climate.TargetPoint target = sampler.sample(x, this.seaLevelQuartY, z);
if (target.continentalness() < OCEAN_CONTINENTALNESS_THRESHOLD) {
return this.delegate.getNoiseBiome(x, this.seaLevelQuartY, z, sampler);
}
// Land column below or at sea level: force ocean for any biome not allowed there.
// Use <= so quart 19 (blocks 76-79, partly underwater) is covered.
if (y <= this.seaLevelQuartY && oceanHolder != null && !allowedBelowSeaLevel(biome)) {
return oceanHolder;
}
// Land column: prevent ocean biomes from bleeding in at any Y
if (isOceanBiome(biome)) {
return resolveLandFallback(x, z, sampler);
} }
return biome; return biome;
} }
private static boolean allowedBelowSeaLevel(Holder<Biome> biome) {
return biome.is(MOLEWORM_CAVES) || biome.is(ELYTHIA_LUSH_CAVES)
|| biome.is(ELYTHIA_OCEAN) || biome.is(ELYTHIA_CORAL_SPIKES);
}
private static boolean isOceanBiome(Holder<Biome> biome) {
return biome.is(ELYTHIA_OCEAN) || biome.is(ELYTHIA_CORAL_SPIKES);
}
// Used for moleworm caves — returns best Y-sample, falls back to whatever the delegate gives
@SafeVarargs @SafeVarargs
private Holder<Biome> resolveSurfaceFallback(int x, int y, int z, Climate.Sampler sampler, ResourceKey<Biome>... excluded) { private Holder<Biome> resolveSurfaceFallback(int x, int y, int z, Climate.Sampler sampler, ResourceKey<Biome>... excluded) {
Holder<Biome> fallback = this.delegate.getNoiseBiome(x, this.surfaceBiomeSampleQuartY, z, sampler); Holder<Biome> fallback = this.delegate.getNoiseBiome(x, this.surfaceBiomeSampleQuartY, z, sampler);
@@ -118,6 +162,19 @@ public class ElythiaBiomeSource extends BiomeSource {
return fallback; return fallback;
} }
// Used when ocean bleeds into a land column — guaranteed to never return an ocean/cave biome
private Holder<Biome> resolveLandFallback(int x, int z, Climate.Sampler sampler) {
Holder<Biome> fallback = this.delegate.getNoiseBiome(x, this.surfaceBiomeSampleQuartY, z, sampler);
if (!isOceanOrCave(fallback)) return fallback;
for (int sampleBlockY : SURFACE_FALLBACK_BLOCK_YS) {
Holder<Biome> candidate = this.delegate.getNoiseBiome(x, QuartPos.fromBlock(sampleBlockY), z, sampler);
if (!isOceanOrCave(candidate)) return candidate;
}
return defaultLandHolder != null ? defaultLandHolder : fallback;
}
@SafeVarargs @SafeVarargs
private static boolean isExcluded(Holder<Biome> biome, ResourceKey<Biome>... excluded) { private static boolean isExcluded(Holder<Biome> biome, ResourceKey<Biome>... excluded) {
for (ResourceKey<Biome> key : excluded) { for (ResourceKey<Biome> key : excluded) {
@@ -126,10 +183,15 @@ public class ElythiaBiomeSource extends BiomeSource {
return false; return false;
} }
private static boolean isOceanOrCave(Holder<Biome> biome) {
return isOceanBiome(biome) || biome.is(ELYTHIA_BEACH)
|| biome.is(MOLEWORM_CAVES) || biome.is(ELYTHIA_LUSH_CAVES);
}
@Override @Override
public void addDebugInfo(java.util.List<String> debug, net.minecraft.core.BlockPos pos, Climate.Sampler sampler) { public void addDebugInfo(java.util.List<String> debug, net.minecraft.core.BlockPos pos, Climate.Sampler sampler) {
this.delegate.addDebugInfo(debug, pos, sampler); this.delegate.addDebugInfo(debug, pos, sampler);
debug.add("Elythia mole cave cap: y<=" + this.molewormCavesMaxY); debug.add("Elythia mole cave cap: y<=" + this.molewormCavesMaxY);
debug.add("Elythia ocean cap: y<=" + this.oceanMaxY); debug.add("Elythia sea level: " + this.seaLevel);
} }
} }
@@ -0,0 +1,37 @@
package com.craisinlord.antarchy.mixins;
import com.craisinlord.antarchy.Antarchy;
import java.util.Optional;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.state.BlockState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(net.minecraft.world.level.block.entity.BlockEntity.class)
public abstract class BlockEntitySignMixin {
private static final ResourceLocation OURANWOOD_SIGN_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "ouranwood_sign");
private static final ResourceLocation OURANWOOD_WALL_SIGN_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "ouranwood_wall_sign");
private static final ResourceLocation OURANWOOD_HANGING_SIGN_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "ouranwood_hanging_sign");
private static final ResourceLocation OURANWOOD_WALL_HANGING_SIGN_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "ouranwood_wall_hanging_sign");
@Inject(method = "validateBlockState", at = @At("HEAD"), cancellable = true)
private static void antarchy$skipOuranwoodSignValidation(BlockState state, CallbackInfo ci) {
if (isOuranwoodSign(state)) {
ci.cancel();
}
}
private static boolean isOuranwoodSign(BlockState state) {
return matches(state, OURANWOOD_SIGN_ID)
|| matches(state, OURANWOOD_WALL_SIGN_ID)
|| matches(state, OURANWOOD_HANGING_SIGN_ID)
|| matches(state, OURANWOOD_WALL_HANGING_SIGN_ID);
}
private static boolean matches(BlockState state, ResourceLocation id) {
return BuiltInRegistries.BLOCK.getOptional(id).map(state::is).orElse(false);
}
}
@@ -1,72 +1,31 @@
package com.craisinlord.antarchy.mixins; package com.craisinlord.antarchy.mixins;
import com.craisinlord.antarchy.content.item.SquidzookaItem; import com.craisinlord.antarchy.content.AntarchyTags;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.HolderGetter;
import net.minecraft.core.Registry; import net.minecraft.core.HolderSet;
import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.ItemTags;
import net.minecraft.world.item.ItemStack; import net.minecraft.tags.TagKey;
import net.minecraft.world.item.enchantment.Enchantment; import net.minecraft.world.item.Item;
import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.item.enchantment.Enchantments;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(Enchantment.class) @Mixin(Enchantments.class)
public abstract class SquidzookaEnchantMixin { public abstract class SquidzookaEnchantMixin {
private static final Registry<Enchantment> ENCHANTMENT_REGISTRY = resolveEnchantmentRegistry(); @Redirect(
method = "bootstrap",
@Inject(method = "canEnchant", at = @At("HEAD"), cancellable = true) at = @At(value = "INVOKE", target = "Lnet/minecraft/core/HolderGetter;getOrThrow(Lnet/minecraft/tags/TagKey;)Lnet/minecraft/core/HolderSet$Named;"),
private void antarchy$limitSquidzookaCrossbowEnchants(ItemStack stack, CallbackInfoReturnable<Boolean> cir) { slice = @org.spongepowered.asm.mixin.injection.Slice(
this.antarchy$applySquidzookaEnchantRules(stack, cir); from = @At(value = "FIELD", target = "Lnet/minecraft/world/item/enchantment/Enchantments;MULTISHOT:Lnet/minecraft/resources/ResourceKey;"),
} to = @At(value = "FIELD", target = "Lnet/minecraft/world/item/enchantment/Enchantments;QUICK_CHARGE:Lnet/minecraft/resources/ResourceKey;")
)
@Inject(method = "isPrimaryItem", at = @At("HEAD"), cancellable = true) )
private void antarchy$limitSquidzookaPrimaryItem(ItemStack stack, CallbackInfoReturnable<Boolean> cir) { private static HolderSet.Named<Item> antarchy$allowSquidzookaForMultishot(HolderGetter<Item> holderGetter, TagKey<Item> tag) {
this.antarchy$applySquidzookaEnchantRules(stack, cir); if (tag.equals(ItemTags.CROSSBOW_ENCHANTABLE)) {
} return holderGetter.getOrThrow(AntarchyTags.Items.MULTISHOT_ENCHANTABLE);
@Inject(method = "isSupportedItem", at = @At("HEAD"), cancellable = true)
private void antarchy$limitSquidzookaSupportedItem(ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
this.antarchy$applySquidzookaEnchantRules(stack, cir);
}
private void antarchy$applySquidzookaEnchantRules(ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
if (!(stack.getItem() instanceof SquidzookaItem)) {
return;
} }
if (ENCHANTMENT_REGISTRY == null) { return holderGetter.getOrThrow(tag);
return;
}
Enchantment enchantment = (Enchantment) (Object) this;
ResourceLocation enchantmentId = ENCHANTMENT_REGISTRY.getKey(enchantment);
if (enchantmentId == null) {
return;
}
if (enchantmentId.equals(Enchantments.MULTISHOT.location())) {
cir.setReturnValue(true);
return;
}
if (enchantmentId.equals(Enchantments.QUICK_CHARGE.location())
|| enchantmentId.equals(Enchantments.PIERCING.location())) {
cir.setReturnValue(false);
}
}
@SuppressWarnings("unchecked")
private static Registry<Enchantment> resolveEnchantmentRegistry() {
try {
return (Registry<Enchantment>) BuiltInRegistries.class.getField("ENCHANTMENT").get(null);
} catch (ReflectiveOperationException primary) {
try {
return (Registry<Enchantment>) BuiltInRegistries.class.getField("ENCHANTMENTS").get(null);
} catch (ReflectiveOperationException ignored) {
return null;
}
}
} }
} }
@@ -0,0 +1,37 @@
package com.craisinlord.antarchy.mixins;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.Enchantment;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(Enchantment.class)
public abstract class SquidzookaMultishotMixin {
@Inject(method = "canEnchant", at = @At("HEAD"), cancellable = true)
private void antarchy$allowSquidzookaForMultishot(ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
if (antarchy$isMultishot() && antarchy$isSquidzooka(stack)) {
cir.setReturnValue(true);
}
}
@Inject(method = "isPrimaryItem", at = @At("HEAD"), cancellable = true)
private void antarchy$allowSquidzookaAsPrimaryItem(ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
if (antarchy$isMultishot() && antarchy$isSquidzooka(stack)) {
cir.setReturnValue(true);
}
}
@Unique
private boolean antarchy$isMultishot() {
return "Multishot".equals(((Enchantment) (Object) this).description().getString());
}
@Unique
private boolean antarchy$isSquidzooka(ItemStack stack) {
return "squidzooka".equals(BuiltInRegistries.ITEM.getKey(stack.getItem()).getPath());
}
}
@@ -0,0 +1,64 @@
package com.craisinlord.antarchy.mixins.client;
import com.craisinlord.antarchy.content.client.renderer.CavarynSkyRenderer;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexBuffer;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.LevelRenderer;
import org.joml.Matrix4f;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(LevelRenderer.class)
public abstract class CavarynSkyMixin {
@Shadow
@Final
private Minecraft minecraft;
@Shadow
private ClientLevel level;
@Shadow
@Final
private VertexBuffer skyBuffer;
@Shadow
@Final
private VertexBuffer darkBuffer;
@Inject(method = "renderSky", at = @At("HEAD"), cancellable = true)
private void antarchy$renderCavarynSky(Matrix4f modelViewMatrix, Matrix4f projectionMatrix, float partialTick, Camera camera, boolean isFoggy, Runnable setupFog, CallbackInfo ci) {
if (this.level == null || !CavarynSkyRenderer.shouldRender(this.level)) {
return;
}
PoseStack poseStack = new PoseStack();
poseStack.mulPose(modelViewMatrix);
CavarynSkyRenderer.render(
this.minecraft,
this.level,
poseStack,
projectionMatrix,
partialTick,
camera,
isFoggy,
setupFog,
this.skyBuffer,
this.darkBuffer
);
ci.cancel();
}
@Inject(method = "renderClouds", at = @At("HEAD"), cancellable = true)
private void antarchy$skipCavarynClouds(PoseStack poseStack, Matrix4f modelViewMatrix, Matrix4f projectionMatrix, float partialTick, double camX, double camY, double camZ, CallbackInfo ci) {
if (this.level != null && CavarynSkyRenderer.shouldRender(this.level)) {
ci.cancel();
}
}
}
@@ -1,63 +0,0 @@
package com.craisinlord.antarchy.mixins.stellaris;
import com.st0x0ef.stellaris.common.oxygen.DimensionOxygenManager;
import net.minecraft.core.component.DataComponentType;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(value = DimensionOxygenManager.class, priority = 2000)
/*
* Tweaks Stellaris oxygen checks for Antarchy dimensions.
*/
public abstract class DimensionOxygenManagerMixin {
@Unique
private static final TagKey<Item> ANTARCHY_MARK_39_ARMOR = TagKey.create(
Registries.ITEM,
ResourceLocation.fromNamespaceAndPath("marvel", "iron_man_mark_39_armor")
);
@Unique
private static final ResourceLocation ANTARCHY_HELMET_OPEN_ID =
ResourceLocation.fromNamespaceAndPath("marvel", "helmet_open");
@Inject(method = "breath", at = @At("HEAD"), cancellable = true)
private void antarchy$allowClosedMark39SuitToBreathe(
LivingEntity entity,
CallbackInfoReturnable<Boolean> cir
) {
if (antarchy$hasArmor(entity)) {
cir.setReturnValue(true);
}
}
@Unique
private static boolean antarchy$hasArmor(LivingEntity entity) {
ItemStack helmet = entity.getItemBySlot(EquipmentSlot.HEAD);
boolean hasHelmet = helmet.is(ANTARCHY_MARK_39_ARMOR) && !antarchy$isHelmetOpen(helmet);
boolean hasChestplate = entity.getItemBySlot(EquipmentSlot.CHEST).is(ANTARCHY_MARK_39_ARMOR);
boolean hasLeggings = entity.getItemBySlot(EquipmentSlot.LEGS).is(ANTARCHY_MARK_39_ARMOR);
boolean hasBoots = entity.getItemBySlot(EquipmentSlot.FEET).is(ANTARCHY_MARK_39_ARMOR);
return hasHelmet && hasChestplate && hasLeggings && hasBoots;
}
@Unique
@SuppressWarnings("unchecked")
private static boolean antarchy$isHelmetOpen(ItemStack helmet) {
DataComponentType<?> componentType = BuiltInRegistries.DATA_COMPONENT_TYPE.get(ANTARCHY_HELMET_OPEN_ID);
if (componentType == null) {
return false;
}
return Boolean.TRUE.equals(helmet.get((DataComponentType<Boolean>) componentType));
}
}
@@ -1,10 +1,12 @@
{ {
"required": true, "required": true,
"package": "com.craisinlord.antarchy.mixins", "package": "com.craisinlord.antarchy.mixins",
"refmap": "antarchy.refmap.json",
"plugin": "com.craisinlord.antarchy.mixins.AntarchyMixinPlugin", "plugin": "com.craisinlord.antarchy.mixins.AntarchyMixinPlugin",
"compatibilityLevel": "JAVA_21", "compatibilityLevel": "JAVA_21",
"mixins": [ "mixins": [
"AccessorRangedAttribute", "AccessorRangedAttribute",
"BlockEntitySignMixin",
"BloodglassMixin", "BloodglassMixin",
"DreamFireBlockMixin", "DreamFireBlockMixin",
"DreamSandLowGravityMixin", "DreamSandLowGravityMixin",
@@ -13,7 +15,7 @@
"GlowVinesUnderLeavesMixin", "GlowVinesUnderLeavesMixin",
"ServerPlayerGameModeMixin", "ServerPlayerGameModeMixin",
"SquidzookaEnchantMixin", "SquidzookaEnchantMixin",
"StinkyLivingEntityMixin", "SquidzookaMultishotMixin",
"TorchflowerBlockStateMixin", "TorchflowerBlockStateMixin",
"gravity.AbstractArrowGravityMixin", "gravity.AbstractArrowGravityMixin",
"gravity.BucketItemGravityMixin", "gravity.BucketItemGravityMixin",
@@ -43,10 +45,10 @@
"gravity.ServerPlayerGravityMixin", "gravity.ServerPlayerGravityMixin",
"gravity.ThrowableProjectileGravityMixin", "gravity.ThrowableProjectileGravityMixin",
"gravity.TrackedEntityAccessor", "gravity.TrackedEntityAccessor",
"multipart.EntityMultipartLifecycleMixin", "multipart.EntityMultipartLifecycleMixin"
"stellaris.DimensionOxygenManagerMixin"
], ],
"client": [ "client": [
"client.CavarynSkyMixin",
"client.ElythiaSkyMixin", "client.ElythiaSkyMixin",
"client.ElytraModelAccessor", "client.ElytraModelAccessor",
"client.LightningBoltRendererMixin", "client.LightningBoltRendererMixin",
@@ -5524,6 +5524,22 @@
"lerp_mode": "catmullrom" "lerp_mode": "catmullrom"
} }
} }
},
"Kraken": {
"position": {
"0.0": {
"post": {
"vector": [0, 218.48, 0]
},
"lerp_mode": "catmullrom"
},
"3.0": {
"post": {
"vector": [0, 218.48, 0]
},
"lerp_mode": "catmullrom"
}
}
} }
} }
} }
@@ -0,0 +1,20 @@
{
"variants": {
"level=0": { "model": "minecraft:block/water" },
"level=1": { "model": "minecraft:block/water" },
"level=2": { "model": "minecraft:block/water" },
"level=3": { "model": "minecraft:block/water" },
"level=4": { "model": "minecraft:block/water" },
"level=5": { "model": "minecraft:block/water" },
"level=6": { "model": "minecraft:block/water" },
"level=7": { "model": "minecraft:block/water" },
"level=8": { "model": "minecraft:block/water" },
"level=9": { "model": "minecraft:block/water" },
"level=10": { "model": "minecraft:block/water" },
"level=11": { "model": "minecraft:block/water" },
"level=12": { "model": "minecraft:block/water" },
"level=13": { "model": "minecraft:block/water" },
"level=14": { "model": "minecraft:block/water" },
"level=15": { "model": "minecraft:block/water" }
}
}
@@ -0,0 +1,14 @@
{
"variants": {
"thickness=base,vertical_direction=down": { "model": "antarchy:block/chiten_spike_down_base" },
"thickness=base,vertical_direction=up": { "model": "antarchy:block/chiten_spike_up_base" },
"thickness=frustum,vertical_direction=down": { "model": "antarchy:block/chiten_spike_down_frustum" },
"thickness=frustum,vertical_direction=up": { "model": "antarchy:block/chiten_spike_up_frustum" },
"thickness=middle,vertical_direction=down": { "model": "antarchy:block/chiten_spike_down_middle" },
"thickness=middle,vertical_direction=up": { "model": "antarchy:block/chiten_spike_up_middle" },
"thickness=tip,vertical_direction=down": { "model": "antarchy:block/chiten_spike_down_tip" },
"thickness=tip,vertical_direction=up": { "model": "antarchy:block/chiten_spike_up_tip" },
"thickness=tip_merge,vertical_direction=down": { "model": "antarchy:block/chiten_spike_down_tip_merge" },
"thickness=tip_merge,vertical_direction=up": { "model": "antarchy:block/chiten_spike_up_tip_merge" }
}
}
@@ -38,6 +38,7 @@
"block.antarchy.chiseled_nyxite": "Chiseled Nyxite", "block.antarchy.chiseled_nyxite": "Chiseled Nyxite",
"block.antarchy.nyxite_bricks": "Nyxite Bricks", "block.antarchy.nyxite_bricks": "Nyxite Bricks",
"block.antarchy.chiten_block": "Chiten Block", "block.antarchy.chiten_block": "Chiten Block",
"block.antarchy.chiten_spike": "Chiten Spike",
"block.antarchy.shellstone": "Shellstone", "block.antarchy.shellstone": "Shellstone",
"block.antarchy.polished_shellstone": "Polished Shellstone", "block.antarchy.polished_shellstone": "Polished Shellstone",
"block.antarchy.shellstone_bricks": "Shellstone Bricks", "block.antarchy.shellstone_bricks": "Shellstone Bricks",
@@ -130,6 +131,7 @@
"block.antarchy.uranium_bars": "Uranium Bars", "block.antarchy.uranium_bars": "Uranium Bars",
"block.antarchy.titanium_bars": "Titanium Bars", "block.antarchy.titanium_bars": "Titanium Bars",
"tooltip.antarchy.signal_saving_bulb": "Toggles on/off. Has light level equal to the signal strength stored on it.", "tooltip.antarchy.signal_saving_bulb": "Toggles on/off. Has light level equal to the signal strength stored on it.",
"block.antarchy.bile": "Bile",
"block.antarchy.ichor": "Ichor", "block.antarchy.ichor": "Ichor",
"block.antarchy.antiwater": "Antiwater", "block.antarchy.antiwater": "Antiwater",
"entity.antarchy.apple_cow": "Apple Cow", "entity.antarchy.apple_cow": "Apple Cow",
@@ -273,6 +275,7 @@
"item.antarchy.creepvine": "Creepvine", "item.antarchy.creepvine": "Creepvine",
"item.antarchy.chiten": "Chiten", "item.antarchy.chiten": "Chiten",
"item.antarchy.chiten_block": "Chiten Block", "item.antarchy.chiten_block": "Chiten Block",
"item.antarchy.chiten_spike": "Chiten Spike",
"item.antarchy.myrmite": "Myrmite", "item.antarchy.myrmite": "Myrmite",
"item.antarchy.torchflower_bush": "Torchflower Bush", "item.antarchy.torchflower_bush": "Torchflower Bush",
"block.antarchy.torchflower_bush": "Torchflower Bush", "block.antarchy.torchflower_bush": "Torchflower Bush",
@@ -339,6 +342,7 @@
"item.antarchy.ultimate_mace": "Ultimate Mace", "item.antarchy.ultimate_mace": "Ultimate Mace",
"item.antarchy.moggles": "Moggles", "item.antarchy.moggles": "Moggles",
"itemGroup.antarchy.antarchy": "Antarchy", "itemGroup.antarchy.antarchy": "Antarchy",
"item.antarchy.bile_bucket": "Bile Bucket",
"item.antarchy.ichor_bucket": "Ichor Bucket", "item.antarchy.ichor_bucket": "Ichor Bucket",
"item.antarchy.antiwater_bucket": "Antiwater Bucket", "item.antarchy.antiwater_bucket": "Antiwater Bucket",
"item.antarchy.reverie_bottle": "Bottle of Reverie", "item.antarchy.reverie_bottle": "Bottle of Reverie",
@@ -393,6 +397,7 @@
"biome.antarchy.butterfly_fields": "Butterfly Fields", "biome.antarchy.butterfly_fields": "Butterfly Fields",
"biome.antarchy.torchflower_fields": "Torchflower Fields", "biome.antarchy.torchflower_fields": "Torchflower Fields",
"biome.antarchy.ouranwood_forest": "Ouranwood Forest", "biome.antarchy.ouranwood_forest": "Ouranwood Forest",
"biome.antarchy.fungal_ouranwood_forest": "Fungal Ouranwood Forest",
"message.antarchy.brown_ant_activated": "The brown ant is ready to open its destination.", "message.antarchy.brown_ant_activated": "The brown ant is ready to open its destination.",
"message.antarchy.brown_ant_needs_reagent": "This brown ant needs a reagent before it can open its destination.", "message.antarchy.brown_ant_needs_reagent": "This brown ant needs a reagent before it can open its destination.",
"message.antarchy.rainbow_ant_activated": "The rainbow ant hums with a new Infinity destination.", "message.antarchy.rainbow_ant_activated": "The rainbow ant hums with a new Infinity destination.",
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/pointed_dripstone",
"textures": {
"cross": "antarchy:block/chiten_spike/chiten_spike_down_base"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/pointed_dripstone",
"textures": {
"cross": "antarchy:block/chiten_spike/chiten_spike_down_frustum"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/pointed_dripstone",
"textures": {
"cross": "antarchy:block/chiten_spike/chiten_spike_down_middle"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/pointed_dripstone",
"textures": {
"cross": "antarchy:block/chiten_spike/chiten_spike_down_tip"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/pointed_dripstone",
"textures": {
"cross": "antarchy:block/chiten_spike/chiten_spike_down_tip_merge"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/pointed_dripstone",
"textures": {
"cross": "antarchy:block/chiten_spike/chiten_spike_up_base"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/pointed_dripstone",
"textures": {
"cross": "antarchy:block/chiten_spike/chiten_spike_up_frustum"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/pointed_dripstone",
"textures": {
"cross": "antarchy:block/chiten_spike/chiten_spike_up_middle"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/pointed_dripstone",
"textures": {
"cross": "antarchy:block/chiten_spike/chiten_spike_up_tip"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/pointed_dripstone",
"textures": {
"cross": "antarchy:block/chiten_spike/chiten_spike_up_tip_merge"
}
}
@@ -1,6 +1,6 @@
{ {
"parent": "minecraft:block/template_turtle_egg", "parent": "minecraft:block/template_turtle_egg",
"textures": { "textures": {
"all": "antarchy:block/creeping_horror_eggs/creeping_horror_eggs" "all": "antarchy:block/creeping_horror_egg/creeping_horror_egg"
} }
} }
@@ -1,6 +1,6 @@
{ {
"parent": "minecraft:block/template_two_turtle_eggs", "parent": "minecraft:block/template_two_turtle_eggs",
"textures": { "textures": {
"all": "antarchy:block/creeping_horror_eggs/creeping_horror_eggs" "all": "antarchy:block/creeping_horror_egg/creeping_horror_egg"
} }
} }
@@ -1,6 +1,6 @@
{ {
"parent": "minecraft:block/template_three_turtle_eggs", "parent": "minecraft:block/template_three_turtle_eggs",
"textures": { "textures": {
"all": "antarchy:block/creeping_horror_eggs/creeping_horror_eggs" "all": "antarchy:block/creeping_horror_egg/creeping_horror_egg"
} }
} }
@@ -1,6 +1,6 @@
{ {
"parent": "minecraft:block/template_four_turtle_eggs", "parent": "minecraft:block/template_four_turtle_eggs",
"textures": { "textures": {
"all": "antarchy:block/creeping_horror_eggs/creeping_horror_eggs" "all": "antarchy:block/creeping_horror_egg/creeping_horror_egg"
} }
} }
@@ -1,6 +1,6 @@
{ {
"parent": "minecraft:block/template_turtle_egg", "parent": "minecraft:block/template_turtle_egg",
"textures": { "textures": {
"all": "antarchy:block/creeping_horror_eggs/creeping_horror_eggs_slightly_cracked" "all": "antarchy:block/creeping_horror_egg/creeping_horror_egg_slightly_cracked"
} }
} }
@@ -1,6 +1,6 @@
{ {
"parent": "minecraft:block/template_two_turtle_eggs", "parent": "minecraft:block/template_two_turtle_eggs",
"textures": { "textures": {
"all": "antarchy:block/creeping_horror_eggs/creeping_horror_eggs_slightly_cracked" "all": "antarchy:block/creeping_horror_egg/creeping_horror_egg_slightly_cracked"
} }
} }
@@ -1,6 +1,6 @@
{ {
"parent": "minecraft:block/template_three_turtle_eggs", "parent": "minecraft:block/template_three_turtle_eggs",
"textures": { "textures": {
"all": "antarchy:block/creeping_horror_eggs/creeping_horror_eggs_slightly_cracked" "all": "antarchy:block/creeping_horror_egg/creeping_horror_egg_slightly_cracked"
} }
} }
@@ -1,6 +1,6 @@
{ {
"parent": "minecraft:block/template_four_turtle_eggs", "parent": "minecraft:block/template_four_turtle_eggs",
"textures": { "textures": {
"all": "antarchy:block/creeping_horror_eggs/creeping_horror_eggs_slightly_cracked" "all": "antarchy:block/creeping_horror_egg/creeping_horror_egg_slightly_cracked"
} }
} }
@@ -1,6 +1,6 @@
{ {
"parent": "minecraft:block/template_turtle_egg", "parent": "minecraft:block/template_turtle_egg",
"textures": { "textures": {
"all": "antarchy:block/creeping_horror_eggs/creeping_horror_eggs_very_cracked" "all": "antarchy:block/creeping_horror_egg/creeping_horror_egg_very_cracked"
} }
} }
@@ -1,6 +1,6 @@
{ {
"parent": "minecraft:block/template_two_turtle_eggs", "parent": "minecraft:block/template_two_turtle_eggs",
"textures": { "textures": {
"all": "antarchy:block/creeping_horror_eggs/creeping_horror_eggs_very_cracked" "all": "antarchy:block/creeping_horror_egg/creeping_horror_egg_very_cracked"
} }
} }
@@ -1,6 +1,6 @@
{ {
"parent": "minecraft:block/template_three_turtle_eggs", "parent": "minecraft:block/template_three_turtle_eggs",
"textures": { "textures": {
"all": "antarchy:block/creeping_horror_eggs/creeping_horror_eggs_very_cracked" "all": "antarchy:block/creeping_horror_egg/creeping_horror_egg_very_cracked"
} }
} }
@@ -1,6 +1,6 @@
{ {
"parent": "minecraft:block/template_four_turtle_eggs", "parent": "minecraft:block/template_four_turtle_eggs",
"textures": { "textures": {
"all": "antarchy:block/creeping_horror_eggs/creeping_horror_eggs_very_cracked" "all": "antarchy:block/creeping_horror_egg/creeping_horror_egg_very_cracked"
} }
} }
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "antarchy:item/chiten_spike"
}
}
@@ -1,6 +1,6 @@
{ {
"parent": "minecraft:item/generated", "parent": "minecraft:item/generated",
"textures": { "textures": {
"layer0": "antarchy:block/uranium/uranium_bars" "layer0": "antarchy:item/uranium/uranium_bars"
} }
} }
@@ -0,0 +1,5 @@
{
"textures": [
"minecraft:generic_0"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

@@ -0,0 +1,6 @@
{
"animation": {
"frametime": 3,
"interpolate": true
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

@@ -0,0 +1,6 @@
{
"animation": {
"frametime": 4,
"interpolate": true
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 B

@@ -7,7 +7,7 @@
"type": "antarchy:elythia_biome_source", "type": "antarchy:elythia_biome_source",
"moleworm_caves_max_y": 30, "moleworm_caves_max_y": 30,
"surface_biome_sample_y": 160, "surface_biome_sample_y": 160,
"ocean_max_y": 85, "ocean_max_y": 75,
"biomes": [ "biomes": [
{ {
"biome": "antarchy:moleworm_caves", "biome": "antarchy:moleworm_caves",
@@ -225,6 +225,30 @@
"offset": 0.0 "offset": 0.0
} }
}, },
{
"biome": "antarchy:fungal_ouranwood_forest",
"parameters": {
"temperature": 0.55,
"humidity": 0.9,
"continentalness": 0.75,
"erosion": 0.0,
"weirdness": 0.85,
"depth": 0.45,
"offset": 0.0
}
},
{
"biome": "antarchy:fungal_ouranwood_forest",
"parameters": {
"temperature": 0.55,
"humidity": 0.9,
"continentalness": 0.75,
"erosion": 0.0,
"weirdness": 0.85,
"depth": 0.0,
"offset": 0.0
}
},
{ {
"biome": "antarchy:torchflower_fields", "biome": "antarchy:torchflower_fields",
"parameters": { "parameters": {
@@ -398,7 +422,7 @@
"parameters": { "parameters": {
"temperature": 0.65, "temperature": 0.65,
"humidity": 0.90, "humidity": 0.90,
"continentalness": -0.50, "continentalness": -0.88,
"erosion": 0.30, "erosion": 0.30,
"weirdness": 0.0, "weirdness": 0.0,
"depth": 0.0, "depth": 0.0,
@@ -410,7 +434,7 @@
"parameters": { "parameters": {
"temperature": 0.60, "temperature": 0.60,
"humidity": 0.88, "humidity": 0.88,
"continentalness": -0.55, "continentalness": -0.92,
"erosion": 0.25, "erosion": 0.25,
"weirdness": -0.40, "weirdness": -0.40,
"depth": 0.0, "depth": 0.0,
@@ -422,7 +446,7 @@
"parameters": { "parameters": {
"temperature": 0.70, "temperature": 0.70,
"humidity": 0.92, "humidity": 0.92,
"continentalness": -0.45, "continentalness": -0.85,
"erosion": 0.35, "erosion": 0.35,
"weirdness": 0.40, "weirdness": 0.40,
"depth": 0.0, "depth": 0.0,
@@ -434,7 +458,7 @@
"parameters": { "parameters": {
"temperature": 0.65, "temperature": 0.65,
"humidity": 0.90, "humidity": 0.90,
"continentalness": -0.50, "continentalness": -0.88,
"erosion": 0.30, "erosion": 0.30,
"weirdness": 0.0, "weirdness": 0.0,
"depth": 0.5, "depth": 0.5,
@@ -446,7 +470,7 @@
"parameters": { "parameters": {
"temperature": 0.60, "temperature": 0.60,
"humidity": 0.88, "humidity": 0.88,
"continentalness": -0.55, "continentalness": -0.92,
"erosion": 0.25, "erosion": 0.25,
"weirdness": -0.40, "weirdness": -0.40,
"depth": 0.5, "depth": 0.5,
@@ -454,38 +478,50 @@
} }
}, },
{ {
"biome": "antarchy:elythia_beach", "biome": "antarchy:elythia_coral_spikes",
"parameters": { "parameters": {
"temperature": 0.68, "temperature": 0.80,
"humidity": 0.91, "humidity": 0.85,
"continentalness": -0.08, "continentalness": -0.88,
"erosion": 0.50, "erosion": 0.20,
"weirdness": 0.0, "weirdness": 0.60,
"depth": 0.0, "depth": 0.0,
"offset": 0.0 "offset": 0.0
} }
}, },
{ {
"biome": "antarchy:elythia_beach", "biome": "antarchy:elythia_coral_spikes",
"parameters": { "parameters": {
"temperature": 0.65, "temperature": 0.75,
"humidity": 0.89, "humidity": 0.82,
"continentalness": -0.05, "continentalness": -0.90,
"erosion": 0.60, "erosion": 0.15,
"weirdness": -0.30, "weirdness": -0.65,
"depth": 0.0, "depth": 0.0,
"offset": 0.0 "offset": 0.0
} }
}, },
{ {
"biome": "antarchy:elythia_beach", "biome": "antarchy:elythia_coral_spikes",
"parameters": { "parameters": {
"temperature": 0.70, "temperature": 0.80,
"humidity": 0.93, "humidity": 0.85,
"continentalness": -0.02, "continentalness": -0.88,
"erosion": 0.55, "erosion": 0.20,
"weirdness": 0.30, "weirdness": 0.60,
"depth": 0.0, "depth": 0.5,
"offset": 0.0
}
},
{
"biome": "antarchy:elythia_coral_spikes",
"parameters": {
"temperature": 0.75,
"humidity": 0.82,
"continentalness": -0.90,
"erosion": 0.15,
"weirdness": -0.65,
"depth": 0.5,
"offset": 0.0 "offset": 0.0
} }
} }
@@ -1,18 +1,18 @@
{ {
"ultrawarm": false, "ultrawarm": true,
"natural": false, "natural": false,
"coordinate_scale": 1.0, "coordinate_scale": 64.0,
"bed_works": false, "bed_works": false,
"respawn_anchor_works": false, "respawn_anchor_works": false,
"min_y": 0, "min_y": 0,
"height": 256, "height": 208,
"logical_height": 240, "logical_height": 192,
"infiniburn": "#minecraft:infiniburn_overworld", "infiniburn": "#minecraft:infiniburn_overworld",
"effects": "minecraft:the_end", "effects": "minecraft:overworld",
"ambient_light": 0.0, "ambient_light": 0.0,
"piglin_safe": false, "piglin_safe": false,
"has_raids": false, "has_raids": false,
"monster_spawn_light_level": 7, "monster_spawn_light_level": 0,
"monster_spawn_block_light_limit": 0, "monster_spawn_block_light_limit": 0,
"has_skylight": false, "has_skylight": false,
"has_ceiling": true, "has_ceiling": true,
@@ -0,0 +1,19 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "antarchy:chiten_spike"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}
@@ -0,0 +1,39 @@
{
"type": "minecraft:entity",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "antarchy:chiten",
"functions": [
{
"function": "minecraft:set_count",
"count": {
"type": "minecraft:uniform",
"min": 1.0,
"max": 2.0
}
},
{
"function": "minecraft:enchanted_count_increase",
"enchantment": "minecraft:looting",
"count": {
"type": "minecraft:uniform",
"min": 0.0,
"max": 1.0
}
}
]
}
],
"conditions": [
{
"condition": "minecraft:killed_by_player"
}
]
}
],
"random_sequence": "antarchy:entities/creeping_horror"
}
@@ -28,6 +28,39 @@
] ]
} }
] ]
},
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "antarchy:chiten",
"functions": [
{
"function": "minecraft:set_count",
"count": {
"type": "minecraft:uniform",
"min": 1.0,
"max": 2.0
}
},
{
"function": "minecraft:enchanted_count_increase",
"enchantment": "minecraft:looting",
"count": {
"type": "minecraft:uniform",
"min": 0.0,
"max": 1.0
}
}
]
}
],
"conditions": [
{
"condition": "minecraft:killed_by_player"
}
]
} }
] ]
} }
@@ -0,0 +1,39 @@
{
"type": "minecraft:entity",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "antarchy:chiten",
"functions": [
{
"function": "minecraft:set_count",
"count": {
"type": "minecraft:uniform",
"min": 1.0,
"max": 2.0
}
},
{
"function": "minecraft:enchanted_count_increase",
"enchantment": "minecraft:looting",
"count": {
"type": "minecraft:uniform",
"min": 0.0,
"max": 1.0
}
}
]
}
],
"conditions": [
{
"condition": "minecraft:killed_by_player"
}
]
}
],
"random_sequence": "antarchy:entities/lurking_terror"
}
@@ -0,0 +1,18 @@
{
"type": "minecraft:entity",
"pools": [
{
"rolls": {
"type": "minecraft:uniform",
"min": 5,
"max": 10
},
"entries": [
{
"type": "minecraft:item",
"name": "minecraft:ink_sac"
}
]
}
]
}
@@ -17,6 +17,7 @@
}, },
{ {
"function": "minecraft:enchanted_count_increase", "function": "minecraft:enchanted_count_increase",
"enchantment": "minecraft:looting",
"count": { "count": {
"type": "minecraft:uniform", "type": "minecraft:uniform",
"min": 0.0, "min": 0.0,
@@ -51,7 +52,13 @@
"name": "antarchy:water_cannon" "name": "antarchy:water_cannon"
} }
], ],
"conditions": [
{
"condition": "minecraft:killed_by_player"
}
],
"rolls": 1.0 "rolls": 1.0
} }
] ],
"random_sequence": "antarchy:entities/toreterror"
} }
@@ -0,0 +1,13 @@
{
"type": "minecraft:crafting_shapeless",
"category": "misc",
"ingredients": [
{
"item": "antarchy:chiten"
}
],
"result": {
"count": 1,
"id": "minecraft:bone_meal"
}
}
@@ -7,8 +7,9 @@
} }
}, },
"pattern": [ "pattern": [
"##", "###",
"##" "###",
"###"
], ],
"result": { "result": {
"count": 1, "count": 1,
@@ -0,0 +1,7 @@
{
"values": [
"#minecraft:moss_replaceable",
"antarchy:myrmite",
"antarchy:amber_moss_block"
]
}
@@ -1,5 +1,6 @@
{ {
"values": [ "values": [
"#minecraft:moss_replaceable",
"antarchy:nyxite", "antarchy:nyxite",
"minecraft:blackstone", "minecraft:blackstone",
"antarchy:umbral_moss_block" "antarchy:umbral_moss_block"
@@ -0,0 +1,7 @@
{
"replace": false,
"values": [
"#minecraft:enchantable/crossbow",
"antarchy:squidzooka"
]
}
@@ -0,0 +1,10 @@
{
"replace": false,
"values": [
"antarchy:elythia_meadow",
"antarchy:torchflower_fields",
"antarchy:butterfly_fields",
"antarchy:ouranwood_forest",
"antarchy:sparse_ouranwood_forest"
]
}
@@ -1,23 +1,6 @@
{ {
"replace": false, "replace": false,
"values": [ "values": [
"#minecraft:is_ocean", "#antarchy:is_elythia_ocean"
"#minecraft:is_deep_ocean",
{
"id": "#neoforge:is_ocean",
"required": false
},
{
"id": "#c:ocean",
"required": false
},
{
"id": "#c:shallow_ocean",
"required": false
},
{
"id": "#c:deep_ocean",
"required": false
}
] ]
} }
@@ -10,6 +10,7 @@
"antarchy:ouranwood_forest", "antarchy:ouranwood_forest",
"antarchy:sparse_ouranwood_forest", "antarchy:sparse_ouranwood_forest",
"antarchy:elythia_ocean", "antarchy:elythia_ocean",
"antarchy:elythia_beach" "antarchy:elythia_coral_spikes",
"antarchy:fungal_ouranwood_forest"
] ]
} }
@@ -0,0 +1,7 @@
{
"replace": false,
"values": [
"antarchy:elythia_ocean",
"antarchy:elythia_coral_spikes"
]
}
@@ -9,17 +9,16 @@
"sky_color": 524288, "sky_color": 524288,
"grass_color": 4211262, "grass_color": 4211262,
"foliage_color": 4211262, "foliage_color": 4211262,
"ambient_sound": "minecraft:ambient.cave",
"mood_sound": { "mood_sound": {
"sound": "minecraft:ambient.cave", "sound": "minecraft:ambient.cave",
"tick_delay": 6000, "tick_delay": 1200000,
"block_search_extent": 8, "block_search_extent": 8,
"offset": 2.0 "offset": 2.0
}, },
"particle": { "particle": {
"probability": 0.002, "probability": 0.002,
"options": { "options": {
"type": "minecraft:ash" "type": "antarchy:orange_ash"
} }
} }
}, },
@@ -29,106 +28,39 @@
"liquid": [] "liquid": []
}, },
"features": [ "features": [
[
"minecraft:lake_lava_surface"
],
[], [],
[ [],
"minecraft:amethyst_geode" [],
], [],
[ [],
"minecraft:monster_room", [],
"minecraft:monster_room_deep"
],
[], [],
[], [],
[ [
"minecraft:ore_dirt", "antarchy:cavaryn_bile_pools",
"minecraft:ore_gravel", "antarchy:cavaryn_amber_moss_patch",
"minecraft:ore_granite_upper", "antarchy:cavaryn_wall_amber_moss",
"minecraft:ore_granite_lower", "antarchy:cavaryn_creepvine",
"minecraft:ore_diorite_upper", "minecraft:glow_lichen",
"minecraft:ore_diorite_lower", "antarchy:cavaryn_chiten_spikes",
"minecraft:ore_andesite_upper", "antarchy:cavaryn_terror_egg_patch"
"minecraft:ore_andesite_lower",
"minecraft:ore_tuff",
"minecraft:ore_coal_upper",
"minecraft:ore_coal_lower",
"minecraft:ore_iron_upper",
"minecraft:ore_iron_middle",
"minecraft:ore_iron_small",
"minecraft:ore_gold",
"minecraft:ore_gold_lower",
"minecraft:ore_redstone",
"minecraft:ore_redstone_lower",
"minecraft:ore_diamond",
"minecraft:ore_diamond_medium",
"minecraft:ore_diamond_large",
"minecraft:ore_diamond_buried",
"minecraft:ore_lapis",
"minecraft:ore_lapis_buried",
"minecraft:ore_copper",
"minecraft:underwater_magma"
],
[
"minecraft:large_dripstone",
"minecraft:pointed_dripstone",
"minecraft:glow_lichen"
],
[
"minecraft:spring_water",
"minecraft:spring_lava"
],
[
"minecraft:brown_mushroom_normal",
"minecraft:red_mushroom_normal"
], ],
[] []
], ],
"creature_spawn_probability": 0.08, "creature_spawn_probability": 0.06,
"spawners": { "spawners": {
"monster": [ "monster": [
{ {
"type": "minecraft:zombie", "type": "antarchy:creeping_horror",
"weight": 95, "weight": 95,
"minCount": 2, "minCount": 2,
"maxCount": 4 "maxCount": 5
}, },
{ {
"type": "minecraft:skeleton", "type": "antarchy:lurking_terror",
"weight": 90, "weight": 95,
"minCount": 2, "minCount": 2,
"maxCount": 4 "maxCount": 5
},
{
"type": "minecraft:creeper",
"weight": 80,
"minCount": 1,
"maxCount": 2
},
{
"type": "minecraft:spider",
"weight": 70,
"minCount": 1,
"maxCount": 3
},
{
"type": "minecraft:cave_spider",
"weight": 45,
"minCount": 1,
"maxCount": 2
},
{
"type": "minecraft:enderman",
"weight": 12,
"minCount": 1,
"maxCount": 2
},
{
"type": "minecraft:witch",
"weight": 6,
"minCount": 1,
"maxCount": 1
} }
], ],
"creature": [], "creature": [],
@@ -0,0 +1,77 @@
{
"has_precipitation": false,
"temperature": 0.78,
"downfall": 1.0,
"effects": {
"fog_color": 6245375,
"water_color": 3461580,
"water_fog_color": 1741620,
"sky_color": 8084735,
"foliage_color": 2867501,
"grass_color": 4304168,
"grass_color_modifier": "none",
"mood_sound": {
"sound": "minecraft:ambient.underwater.loop",
"tick_delay": 6000,
"block_search_extent": 8,
"offset": 2.0
}
},
"spawn_costs": {},
"carvers": {
"air": [],
"liquid": []
},
"features": [
[],
[],
[],
[],
[],
[],
[
"minecraft:ore_coal_upper",
"minecraft:ore_coal_lower",
"minecraft:ore_iron_upper",
"minecraft:ore_iron_middle",
"minecraft:ore_iron_small",
"minecraft:ore_gold",
"minecraft:ore_gold_lower",
"minecraft:ore_redstone",
"minecraft:ore_redstone_lower",
"minecraft:ore_diamond",
"minecraft:ore_diamond_medium",
"minecraft:ore_diamond_large",
"minecraft:ore_diamond_buried",
"minecraft:ore_lapis",
"minecraft:ore_lapis_buried",
"minecraft:ore_copper"
],
[
"antarchy:elythia_underground"
],
[],
[
"antarchy:elythia_coral_spike"
],
[]
],
"creature_spawn_probability": 0.04,
"spawners": {
"monster": [
{ "type": "antarchy:missile_squid", "weight": 12, "minCount": 1, "maxCount": 3 },
{ "type": "antarchy:octopus_bomb", "weight": 4, "minCount": 1, "maxCount": 2 }
],
"creature": [
{ "type": "minecraft:turtle", "weight": 5, "minCount": 1, "maxCount": 2 }
],
"ambient": [],
"axolotls": [],
"underground_water_creature": [],
"water_creature": [],
"water_ambient": [
{ "type": "minecraft:tropical_fish", "weight": 20, "minCount": 4, "maxCount": 8 }
],
"misc": []
}
}
@@ -51,18 +51,28 @@
"antarchy:elythia_underground" "antarchy:elythia_underground"
], ],
[], [],
[], [
"minecraft:sea_pickle",
"minecraft:warm_ocean_vegetation"
],
[] []
], ],
"creature_spawn_probability": 0.04, "creature_spawn_probability": 0.04,
"spawners": { "spawners": {
"monster": [], "monster": [
"creature": [], { "type": "antarchy:missile_squid", "weight": 12, "minCount": 1, "maxCount": 3 },
{ "type": "antarchy:octopus_bomb", "weight": 4, "minCount": 1, "maxCount": 2 }
],
"creature": [
{ "type": "minecraft:turtle", "weight": 5, "minCount": 1, "maxCount": 2 }
],
"ambient": [], "ambient": [],
"axolotls": [], "axolotls": [],
"underground_water_creature": [], "underground_water_creature": [],
"water_creature": [], "water_creature": [],
"water_ambient": [], "water_ambient": [
{ "type": "minecraft:tropical_fish", "weight": 20, "minCount": 4, "maxCount": 8 }
],
"misc": [] "misc": []
} }
} }
@@ -0,0 +1,27 @@
{
"type": "minecraft:vegetation_patch",
"config": {
"depth": 1,
"extra_bottom_block_chance": 0.0,
"extra_edge_column_chance": 0.75,
"ground_state": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "antarchy:amber_moss_block"
}
},
"replaceable": "#antarchy:amber_moss_replaceable",
"surface": "floor",
"vegetation_chance": 0.6,
"vegetation_feature": {
"feature": "antarchy:amber_moss_vegetation",
"placement": []
},
"vertical_range": 5,
"xz_radius": {
"type": "minecraft:uniform",
"max_inclusive": 2,
"min_inclusive": 1
}
}
}
@@ -0,0 +1,18 @@
{
"type": "minecraft:simple_block",
"config": {
"to_place": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "antarchy:amber_moss_carpet",
"Properties": {
"bottom": "true",
"east": "none",
"north": "none",
"south": "none",
"west": "none"
}
}
}
}
}
@@ -0,0 +1,4 @@
{
"type": "antarchy:cavaryn_bile_pools",
"config": {}
}
@@ -0,0 +1,18 @@
{
"type": "antarchy:cavaryn_chiten_spikes",
"config": {
"floor_to_ceiling_search_range": 10,
"radius": 4,
"max_column_height": 5,
"height_deviation": 1,
"chance_of_column_at_max_distance_from_center": 0.3,
"max_distance_from_center_affecting_chance_of_column": 4,
"max_distance_from_center_affecting_height_bias": 4,
"max_height_difference": 1,
"large_variant_chance": 0.35,
"large_variant_extra_radius": 3,
"large_variant_extra_height": 4,
"large_variant_extra_height_deviation": 2,
"large_variant_surface_spike_multiplier": 2.5
}
}
@@ -0,0 +1,4 @@
{
"type": "antarchy:cavaryn_creepvine",
"config": {}
}
@@ -0,0 +1,4 @@
{
"type": "antarchy:cavaryn_terror_egg_patch",
"config": {}
}
Loaded 100 of 133 files, more files were not shown because too many files have changed in this diff. Show more