WIP 1.20.1 port

2 new squirrel anims
tons of stuff
This commit is contained in:
craisinlord committed 2026-08-02 21:52:56 -05:00
1 parent 94c3676dea
commit 58e504cf1d
264 files changed
+14996 -3287

No files matched your search

@@ -10,9 +10,13 @@ public final class AntarchySettings {
private static int easterBunnyNaturalSpawnChancePercent = 1;
private static boolean rainbowAntsLeadToInfinityDimensions = true;
private static boolean brownAntRequiresReagent = false;
private static boolean brownAntRightClickDimension = true;
private static boolean redAntRequiresReagent = false;
private static boolean redAntRightClickDimension = true;
private static boolean rainbowAntRequiresReagent = true;
private static boolean rainbowAntRightClickDimension = true;
private static boolean termiteRequiresReagent = false;
private static boolean termiteRightClickDimension = true;
private static boolean antsStealFromChests = true;
private static boolean duplicatorTreeEnabled = true;
private static boolean glowVinesUnderLeaves = true;
@@ -461,6 +465,22 @@ public final class AntarchySettings {
return rainbowAntsLeadToInfinityDimensions;
}
public static boolean brownAntRightClickDimension() {
return brownAntRightClickDimension;
}
public static boolean redAntRightClickDimension() {
return redAntRightClickDimension;
}
public static boolean rainbowAntRightClickDimension() {
return rainbowAntRightClickDimension;
}
public static boolean termiteRightClickDimension() {
return termiteRightClickDimension;
}
public static boolean brownAntRequiresReagent() {
return brownAntRequiresReagent;
}
@@ -984,6 +1004,22 @@ public final class AntarchySettings {
rainbowAntsLeadToInfinityDimensions = value;
}
public static void setBrownAntRightClickDimension(boolean value) {
brownAntRightClickDimension = value;
}
public static void setRedAntRightClickDimension(boolean value) {
redAntRightClickDimension = value;
}
public static void setRainbowAntRightClickDimension(boolean value) {
rainbowAntRightClickDimension = value;
}
public static void setTermiteRightClickDimension(boolean value) {
termiteRightClickDimension = value;
}
public static void setPermanentPortalsEnabled(boolean value) {
permanentPortalsEnabled = value;
}
@@ -27,6 +27,8 @@ import com.craisinlord.antarchy.content.entity.MolewormEntity;
import com.craisinlord.antarchy.content.entity.MantisEntity;
import com.craisinlord.antarchy.content.entity.ReverieEntity;
import com.craisinlord.antarchy.content.entity.ScorpionEntity;
import com.craisinlord.antarchy.content.entity.nightmare.NightmareBiteEntity;
import com.craisinlord.antarchy.content.entity.nightmare.NightmarePortalEntity;
import com.craisinlord.antarchy.content.block.entity.AntNestBlockEntity;
import com.craisinlord.antarchy.content.block.entity.DreamCampfireBlockEntity;
import com.craisinlord.antarchy.content.block.entity.SeashellBlockEntity;
@@ -66,6 +68,10 @@ public final class AntarchyObjects {
@SuppressWarnings("unchecked")
public static Supplier<EntityType<OctopusBombEntity>> OCTOPUS_BOMB = (Supplier<EntityType<OctopusBombEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<NightmarePortalEntity>> NIGHTMARE_PORTAL = (Supplier<EntityType<NightmarePortalEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<NightmareBiteEntity>> NIGHTMARE_BITE = (Supplier<EntityType<NightmareBiteEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<MolewormEntity>> MOLEWORM = (Supplier<EntityType<MolewormEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<MantisEntity>> MANTIS = (Supplier<EntityType<MantisEntity>>) UNBOUND;
@@ -201,9 +207,9 @@ public final class AntarchyObjects {
@SuppressWarnings("unchecked")
public static Supplier<Block> NYXITE_SPIKE = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> CHITEN_BLOCK = (Supplier<Block>) UNBOUND;
public static Supplier<Block> CHITIN_BLOCK = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> CHITEN_SPIKE = (Supplier<Block>) UNBOUND;
public static Supplier<Block> CHITIN_SPIKE = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> POTENT_NYXITE = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
@@ -251,6 +257,8 @@ public final class AntarchyObjects {
@SuppressWarnings("unchecked")
public static Supplier<Holder<MobEffect>> STINKY_EFFECT = (Supplier<Holder<MobEffect>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Holder<MobEffect>> GLIMMERING_EFFECT = (Supplier<Holder<MobEffect>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Fluid> LUMEN = (Supplier<Fluid>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Fluid> FLOWING_LUMEN = (Supplier<Fluid>) UNBOUND;
@@ -301,6 +309,8 @@ public final class AntarchyObjects {
@SuppressWarnings("unchecked")
public static Supplier<Block> CRITTER_CAGE_BLOCK = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> LUCID_ANCHOR = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<BlockEntityType<AntNestBlockEntity>> ANT_NEST_BLOCK_ENTITY = (Supplier<BlockEntityType<AntNestBlockEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<BlockEntityType<DreamCampfireBlockEntity>> DREAM_CAMPFIRE_BLOCK_ENTITY = (Supplier<BlockEntityType<DreamCampfireBlockEntity>>) UNBOUND;
@@ -314,6 +324,9 @@ public final class AntarchyObjects {
public static Supplier<BlockEntityType<com.craisinlord.antarchy.content.block.entity.CritterCageBlockEntity>> CRITTER_CAGE_BLOCK_ENTITY =
(Supplier<BlockEntityType<com.craisinlord.antarchy.content.block.entity.CritterCageBlockEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<BlockEntityType<com.craisinlord.antarchy.content.block.entity.LucidAnchorBlockEntity>> LUCID_ANCHOR_BLOCK_ENTITY =
(Supplier<BlockEntityType<com.craisinlord.antarchy.content.block.entity.LucidAnchorBlockEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<SimpleParticleType> STINKY_GAS = (Supplier<SimpleParticleType>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<SimpleParticleType> STINKY_FLY = (Supplier<SimpleParticleType>) UNBOUND;
@@ -393,8 +406,8 @@ public final class AntarchyObjects {
Supplier<Block> triffidGooBlock,
Supplier<Block> paleNyxite,
Supplier<Block> nyxiteSpike,
Supplier<Block> chitenBlock,
Supplier<Block> chitenSpike,
Supplier<Block> chitinBlock,
Supplier<Block> chitinSpike,
Supplier<Block> potentNyxite,
Supplier<Block> antimetal,
Supplier<Block> polishedAntimetal,
@@ -494,8 +507,8 @@ public final class AntarchyObjects {
TRIFFID_GOO_BLOCK = triffidGooBlock;
PALE_NYXITE = paleNyxite;
NYXITE_SPIKE = nyxiteSpike;
CHITEN_BLOCK = chitenBlock;
CHITEN_SPIKE = chitenSpike;
CHITIN_BLOCK = chitinBlock;
CHITIN_SPIKE = chitinSpike;
POTENT_NYXITE = potentNyxite;
ANTIMETAL = antimetal;
POLISHED_ANTIMETAL = polishedAntimetal;
@@ -556,6 +569,14 @@ public final class AntarchyObjects {
TENTACLE = supplier;
}
public static void setNightmarePortal(Supplier<EntityType<NightmarePortalEntity>> supplier) {
NIGHTMARE_PORTAL = supplier;
}
public static void setNightmareBite(Supplier<EntityType<NightmareBiteEntity>> supplier) {
NIGHTMARE_BITE = supplier;
}
public static void setLotus(Supplier<Block> supplier) {
LOTUS = supplier;
}
@@ -608,6 +629,10 @@ public final class AntarchyObjects {
SPIRIT_APPLE = supplier;
}
public static void setGlimmeringEffect(Supplier<Holder<MobEffect>> supplier) {
GLIMMERING_EFFECT = supplier;
}
public static void setElka(Supplier<EntityType<com.craisinlord.antarchy.content.entity.ElkaEntity>> supplier) {
ELKA = supplier;
}
@@ -632,6 +657,10 @@ public final class AntarchyObjects {
CRITTER_CAGE_BLOCK = supplier;
}
public static void setLucidAnchor(Supplier<Block> supplier) {
LUCID_ANCHOR = supplier;
}
public static void setStarCoralBlock(Supplier<Block> supplier) {
STAR_CORAL_BLOCK = supplier;
}
@@ -688,6 +717,10 @@ public final class AntarchyObjects {
CRITTER_CAGE_BLOCK_ENTITY = supplier;
}
public static void setLucidAnchorBlockEntity(Supplier<BlockEntityType<com.craisinlord.antarchy.content.block.entity.LucidAnchorBlockEntity>> supplier) {
LUCID_ANCHOR_BLOCK_ENTITY = supplier;
}
public static void setCritterCageProjectile(Supplier<net.minecraft.world.entity.EntityType<com.craisinlord.antarchy.content.entity.CritterCageProjectileEntity>> supplier) {
CRITTER_CAGE_PROJECTILE = supplier;
}
@@ -42,6 +42,9 @@ public final class AntarchyTags {
public static final TagKey<Block> MINERS_DREAM_CARVABLE = TagKey.create(Registries.BLOCK, id("miners_dream_carvable"));
public static final TagKey<Block> BLUESTONE_COMPONENTS = TagKey.create(Registries.BLOCK, id("bluestone_components"));
public static final TagKey<Block> BLUESTONE_CONNECTABLE = TagKey.create(Registries.BLOCK, id("bluestone_connectable"));
public static final TagKey<Block> ANTIMETAL_INVERSION_BLOCKS = TagKey.create(Registries.BLOCK, id("antimetal_inversion_blocks"));
public static final TagKey<Block> TIGER_EYE_CAMOUFLAGE_BLACKLIST = TagKey.create(Registries.BLOCK, id("tiger_eye_camouflage_blacklist"));
public static final TagKey<Block> LUCID_ANCHOR_BASE_BLOCKS = TagKey.create(Registries.BLOCK, id("lucid_anchor_base_blocks"));
private Blocks() {
}
@@ -71,6 +74,8 @@ public final class AntarchyTags {
public static final TagKey<EntityType<?>> STINKY_REPELLED_HOSTILES = TagKey.create(Registries.ENTITY_TYPE, id("stinky_repelled_hostiles"));
public static final TagKey<EntityType<?>> SCORPION_WHIP_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("scorpion_whip_immune"));
public static final TagKey<EntityType<?>> SCORPION_WHIP_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("scorpion_whip_blacklist"));
public static final TagKey<EntityType<?>> TIGER_EYE_DETECTION_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("tiger_eye_detection_immune"));
public static final TagKey<EntityType<?>> LUCID_ANCHOR_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("lucid_anchor_immune"));
private Entities() {
}
@@ -110,6 +115,7 @@ public final class AntarchyTags {
public static final TagKey<Item> GLIMMER_AUGMENT_ANT = TagKey.create(Registries.ITEM, id("glimmer_augment_ant"));
public static final TagKey<Item> GLIMMER_AUGMENT_ELKA = TagKey.create(Registries.ITEM, id("glimmer_augment_elka"));
public static final TagKey<Item> HFCS_CANNOT_AMERICANIZE = TagKey.create(Registries.ITEM, id("hfcs_cannot_americanize"));
public static final TagKey<Item> TIGER_EYE_ARMOR = TagKey.create(Registries.ITEM, id("tigers_eye_armor"));
private Items() {
}
@@ -16,11 +16,11 @@ 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 {
public class ChitinSpikeBlock extends PointedDripstoneBlock {
@SuppressWarnings("rawtypes")
public static final MapCodec<PointedDripstoneBlock> CODEC = (MapCodec) Block.simpleCodec(ChitenSpikeBlock::new);
public static final MapCodec<PointedDripstoneBlock> CODEC = (MapCodec) Block.simpleCodec(ChitinSpikeBlock::new);
public ChitenSpikeBlock(BlockBehaviour.Properties properties) {
public ChitinSpikeBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@@ -99,14 +99,14 @@ public class ChitenSpikeBlock extends PointedDripstoneBlock {
if (state.getValue(TIP_DIRECTION) == Direction.DOWN) {
BlockPos.MutableBlockPos root = pos.mutable();
while (isChitenSpikeWithDirection(level.getBlockState(root.above()), Direction.DOWN)) {
while (isChitinSpikeWithDirection(level.getBlockState(root.above()), Direction.DOWN)) {
root.move(Direction.UP);
}
BlockPos.MutableBlockPos cursor = root.mutable();
while (isChitenSpikeWithDirection(level.getBlockState(cursor), Direction.DOWN)) {
while (isChitinSpikeWithDirection(level.getBlockState(cursor), Direction.DOWN)) {
BlockState fallingState = level.getBlockState(cursor);
if (isChitenSpikeWithDirection(fallingState, Direction.DOWN)) {
if (isChitinSpikeWithDirection(fallingState, Direction.DOWN)) {
net.minecraft.world.entity.item.FallingBlockEntity.fall(level, cursor, fallingState);
}
cursor.move(Direction.DOWN);
@@ -115,7 +115,7 @@ public class ChitenSpikeBlock extends PointedDripstoneBlock {
}
BlockPos.MutableBlockPos cursor = pos.mutable();
while (isChitenSpikeWithDirection(level.getBlockState(cursor), Direction.UP)) {
while (isChitinSpikeWithDirection(level.getBlockState(cursor), Direction.UP)) {
BlockState spikeState = level.getBlockState(cursor);
dropResources(spikeState, level, cursor);
level.removeBlock(cursor, false);
@@ -135,20 +135,20 @@ public class ChitenSpikeBlock extends PointedDripstoneBlock {
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)) {
if (isChitinSpikeWithDirection(forwardState, opposite)) {
return !mergeTips && forwardState.getValue(THICKNESS) != DripstoneThickness.TIP_MERGE
? DripstoneThickness.TIP
: DripstoneThickness.TIP_MERGE;
}
if (!isChitenSpikeWithDirection(forwardState, direction)) {
if (!isChitinSpikeWithDirection(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 !isChitinSpikeWithDirection(backState, direction) ? DripstoneThickness.BASE : DripstoneThickness.MIDDLE;
}
return DripstoneThickness.FRUSTUM;
@@ -157,10 +157,10 @@ public class ChitenSpikeBlock extends PointedDripstoneBlock {
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);
return supportState.isFaceSturdy(level, supportPos, direction) || isChitinSpikeWithDirection(supportState, direction);
}
private static boolean isChitenSpikeWithDirection(BlockState state, Direction direction) {
return state.is(AntarchyObjects.CHITEN_SPIKE.get()) && state.getValue(TIP_DIRECTION) == direction;
private static boolean isChitinSpikeWithDirection(BlockState state, Direction direction) {
return state.is(AntarchyObjects.CHITIN_SPIKE.get()) && state.getValue(TIP_DIRECTION) == direction;
}
}
@@ -5,6 +5,8 @@ import com.craisinlord.antarchy.mixins.AccessorFireBlock;
import com.mojang.serialization.MapCodec;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.FireBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
@@ -25,6 +27,21 @@ public class DreamFireBlock extends FireBlock {
return CODEC;
}
@Override
protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (level.getBlockState(pos.below()).is(AntarchyTags.Blocks.DREAM_FIRE_BASE_BLOCKS)) {
if (!this.canSurvive(state, level, pos)) {
level.removeBlock(pos, false);
return;
}
level.scheduleTick(pos, this, 30 + random.nextInt(10));
return;
}
super.tick(state, level, pos, random);
}
@Override
protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).is(AntarchyTags.Blocks.DREAM_FIRE_BASE_BLOCKS)
@@ -0,0 +1,77 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.block.entity.LucidAnchorBlockEntity;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BaseEntityBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
public class LucidAnchorBlock extends BaseEntityBlock {
public static final MapCodec<LucidAnchorBlock> CODEC = Block.simpleCodec(LucidAnchorBlock::new);
public static final BooleanProperty ACTIVE = BlockStateProperties.LIT;
public LucidAnchorBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(ACTIVE, false));
}
@Override
public MapCodec<LucidAnchorBlock> codec() {
return CODEC;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(ACTIVE);
}
@Override
protected RenderShape getRenderShape(BlockState state) {
return RenderShape.MODEL;
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new LucidAnchorBlockEntity(pos, state);
}
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
return level.isClientSide
? null
: createTickerHelper(blockEntityType, AntarchyObjects.LUCID_ANCHOR_BLOCK_ENTITY.get(), (tickLevel, tickPos, tickState, blockEntity) -> {
if (tickLevel instanceof net.minecraft.server.level.ServerLevel serverLevel) {
LucidAnchorBlockEntity.serverTick(serverLevel, tickPos, tickState, blockEntity);
}
});
}
@Override
protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
super.onPlace(state, level, pos, oldState, movedByPiston);
markStructureDirty(level, pos);
}
@Override
protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block block, BlockPos neighborPos, boolean movedByPiston) {
super.neighborChanged(state, level, pos, block, neighborPos, movedByPiston);
markStructureDirty(level, pos);
}
private static void markStructureDirty(Level level, BlockPos pos) {
if (level.getBlockEntity(pos) instanceof LucidAnchorBlockEntity lucidAnchor) {
lucidAnchor.markStructureDirty();
}
}
}
@@ -0,0 +1,344 @@
package com.craisinlord.antarchy.content.block.entity;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.AntarchySoundEvents;
import com.craisinlord.antarchy.content.AntarchyTags;
import com.craisinlord.antarchy.content.block.LucidAnchorBlock;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.IntArrayTag;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.EntitySelector;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BeaconBeamBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
public class LucidAnchorBlockEntity extends BlockEntity {
private static final int EFFECT_INTERVAL_TICKS = 20;
private static final int VALIDATION_INTERVAL_TICKS = 60;
private static final int EFFECT_DURATION_TICKS = 60;
private static final int EFFECT_REFRESH_THRESHOLD_TICKS = 30;
private static final int DEFAULT_BEAM_COLOR = 0xFFFF1A1A;
private int pyramidLevel;
private boolean active;
private boolean beamPathClear;
private int beamLength;
private boolean structureDirty = true;
private long lastValidationTick = Long.MIN_VALUE;
private List<BeamSection> beamSections = List.of();
public LucidAnchorBlockEntity(BlockPos pos, BlockState blockState) {
super(AntarchyObjects.LUCID_ANCHOR_BLOCK_ENTITY.get(), pos, blockState);
}
public static void serverTick(ServerLevel level, BlockPos pos, BlockState state, LucidAnchorBlockEntity blockEntity) {
blockEntity.serverTick(level, pos, state);
}
public void markStructureDirty() {
this.structureDirty = true;
this.setChanged();
}
public boolean isActive() {
return this.active;
}
public int getPyramidLevel() {
return this.pyramidLevel;
}
public int getBeamLength() {
return this.beamLength;
}
public List<BeamSection> getBeamSections() {
return this.beamSections;
}
private void serverTick(ServerLevel level, BlockPos pos, BlockState state) {
long gameTime = level.getGameTime();
if (this.structureDirty || gameTime - this.lastValidationTick >= VALIDATION_INTERVAL_TICKS) {
this.revalidate(level, pos, state);
this.structureDirty = false;
this.lastValidationTick = gameTime;
}
if (this.active && gameTime % EFFECT_INTERVAL_TICKS == 0L) {
this.applyInvertedField(level, pos);
}
}
private void revalidate(ServerLevel level, BlockPos pos, BlockState state) {
int newPyramidLevel = calculatePyramidLevel(level, pos);
BeamValidation beamValidation = validateBeamPath(level, pos);
boolean newActive = newPyramidLevel > 0 && beamValidation.clear();
boolean stateChanged = this.pyramidLevel != newPyramidLevel
|| this.beamPathClear != beamValidation.clear()
|| this.active != newActive
|| this.beamLength != beamValidation.length()
|| !this.beamSections.equals(beamValidation.sections());
boolean activeChanged = this.active != newActive;
this.pyramidLevel = newPyramidLevel;
this.beamPathClear = beamValidation.clear();
this.beamLength = beamValidation.length();
this.beamSections = beamValidation.sections();
this.active = newActive;
if (state.getBlock() instanceof LucidAnchorBlock && state.getValue(LucidAnchorBlock.ACTIVE) != newActive) {
level.setBlock(pos, state.setValue(LucidAnchorBlock.ACTIVE, newActive), Block.UPDATE_CLIENTS);
state = level.getBlockState(pos);
}
if (activeChanged) {
level.playSound(null, pos, newActive ? SoundEvents.BEACON_ACTIVATE : SoundEvents.BEACON_DEACTIVATE, SoundSource.BLOCKS, 1.0F, 1.0F);
}
if (stateChanged) {
this.syncVisualState(state);
}
}
private void applyInvertedField(ServerLevel level, BlockPos pos) {
if (this.pyramidLevel <= 0) {
return;
}
int radius = 10 + this.pyramidLevel * 10;
AABB area = new AABB(
pos.getX() - radius,
level.getMinBuildHeight(),
pos.getZ() - radius,
pos.getX() + radius + 1.0D,
pos.getY() + 1.0D,
pos.getZ() + radius + 1.0D
);
Holder<MobEffect> invertedEffect = AntarchyObjects.INVERTED_EFFECT.get();
for (LivingEntity entity : level.getEntitiesOfClass(LivingEntity.class, area, entity -> EntitySelector.NO_SPECTATORS.test(entity) && entity.isAlive())) {
if (entity.getType().is(AntarchyTags.Entities.LUCID_ANCHOR_IMMUNE) || entity.getType().is(AntarchyTags.Entities.INVERTED_IMMUNE)) {
continue;
}
MobEffectInstance current = entity.getEffect(invertedEffect);
if (current != null && current.getDuration() > EFFECT_REFRESH_THRESHOLD_TICKS && current.getAmplifier() == 0) {
continue;
}
entity.addEffect(new MobEffectInstance(invertedEffect, EFFECT_DURATION_TICKS, 0, true, true, true));
}
}
private void syncVisualState(BlockState state) {
this.setChanged();
if (this.level != null) {
this.level.sendBlockUpdated(this.worldPosition, state, state, Block.UPDATE_CLIENTS);
}
}
@Override
protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.saveAdditional(tag, registries);
tag.putInt("PyramidLevel", this.pyramidLevel);
tag.putBoolean("Active", this.active);
tag.putBoolean("BeamPathClear", this.beamPathClear);
tag.putInt("BeamLength", this.beamLength);
tag.putBoolean("StructureDirty", this.structureDirty);
int[] colors = new int[this.beamSections.size()];
int[] lengths = new int[this.beamSections.size()];
for (int i = 0; i < this.beamSections.size(); i++) {
BeamSection section = this.beamSections.get(i);
colors[i] = section.color();
lengths[i] = section.length();
}
tag.put("BeamColors", new IntArrayTag(colors));
tag.put("BeamLengths", new IntArrayTag(lengths));
}
@Override
protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.loadAdditional(tag, registries);
this.pyramidLevel = tag.getInt("PyramidLevel");
this.active = tag.getBoolean("Active");
this.beamPathClear = tag.getBoolean("BeamPathClear");
this.beamLength = tag.getInt("BeamLength");
this.structureDirty = true;
int[] colors = tag.getIntArray("BeamColors");
int[] lengths = tag.getIntArray("BeamLengths");
List<BeamSection> sections = new ArrayList<>();
for (int i = 0; i < Math.min(colors.length, lengths.length); i++) {
if (lengths[i] > 0) {
sections.add(new BeamSection(colors[i], lengths[i]));
}
}
this.beamSections = sections.isEmpty() ? List.of() : List.copyOf(sections);
}
@Override
public CompoundTag getUpdateTag(HolderLookup.Provider registries) {
return this.saveCustomOnly(registries);
}
@Override
public Packet<ClientGamePacketListener> getUpdatePacket() {
return ClientboundBlockEntityDataPacket.create(this);
}
public static int calculatePyramidLevel(Level level, BlockPos anchorPos) {
int completedLayers = 0;
BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos();
for (int layer = 1; layer <= 4; layer++) {
int y = anchorPos.getY() + layer;
if (y > level.getMaxBuildHeight()) {
break;
}
boolean complete = true;
for (int x = anchorPos.getX() - layer; x <= anchorPos.getX() + layer && complete; x++) {
for (int z = anchorPos.getZ() - layer; z <= anchorPos.getZ() + layer; z++) {
cursor.set(x, y, z);
if (!level.getBlockState(cursor).is(AntarchyTags.Blocks.LUCID_ANCHOR_BASE_BLOCKS)) {
complete = false;
break;
}
}
}
if (!complete) {
break;
}
completedLayers = layer;
}
return completedLayers;
}
private static BeamValidation validateBeamPath(Level level, BlockPos anchorPos) {
int minBuildHeight = level.getMinBuildHeight();
int floorTolerance = minBuildHeight + 5;
if (anchorPos.getY() <= minBuildHeight) {
return BeamValidation.inactive();
}
BlockPos.MutableBlockPos cursor = anchorPos.below().mutable();
List<BeamSection> sections = new ArrayList<>();
int currentColor = DEFAULT_BEAM_COLOR;
int currentLength = 0;
int totalLength = 0;
boolean clear = false;
for (int y = anchorPos.getY() - 1; y >= minBuildHeight; y--) {
cursor.set(anchorPos.getX(), y, anchorPos.getZ());
BlockState state = level.getBlockState(cursor);
if (state.is(Blocks.BEDROCK)) {
if (y <= floorTolerance) {
currentLength++;
totalLength++;
clear = true;
}
break;
}
if (!isBeamPassable(level, cursor, state)) {
if (y <= floorTolerance) {
currentLength++;
totalLength++;
clear = true;
break;
}
return BeamValidation.inactive();
}
int encounteredColor = colorForBeamState(state, currentColor);
if (encounteredColor != currentColor && currentLength > 0) {
sections.add(new BeamSection(currentColor, currentLength));
currentColor = encounteredColor;
currentLength = 0;
} else {
currentColor = encounteredColor;
}
currentLength++;
totalLength++;
if (y <= floorTolerance && state.isAir()) {
clear = true;
}
if (y == minBuildHeight) {
clear = true;
}
}
if (!clear || totalLength <= 0) {
return BeamValidation.inactive();
}
if (currentLength > 0) {
sections.add(new BeamSection(currentColor, currentLength));
}
return new BeamValidation(true, totalLength, List.copyOf(sections));
}
private static boolean isBeamPassable(Level level, BlockPos pos, BlockState state) {
if (state.isAir()) {
return true;
}
if (!level.getFluidState(pos).isEmpty()) {
return true;
}
if (state.getBlock() instanceof BeaconBeamBlock) {
return true;
}
return state.getLightBlock(level, pos) < 15;
}
private static int colorForBeamState(BlockState state, int fallbackColor) {
if (!(state.getBlock() instanceof BeaconBeamBlock beamBlock)) {
return fallbackColor;
}
int diffuse = beamBlock.getColor().getTextureDiffuseColor();
int red = (diffuse >> 16) & 0xFF;
int green = (diffuse >> 8) & 0xFF;
int blue = diffuse & 0xFF;
if (fallbackColor == DEFAULT_BEAM_COLOR) {
return 0xFF000000 | diffuse;
}
int fallbackRed = (fallbackColor >> 16) & 0xFF;
int fallbackGreen = (fallbackColor >> 8) & 0xFF;
int fallbackBlue = fallbackColor & 0xFF;
return 0xFF000000
| (((fallbackRed + red) / 2) << 16)
| (((fallbackGreen + green) / 2) << 8)
| ((fallbackBlue + blue) / 2);
}
public record BeamSection(int color, int length) {
}
private record BeamValidation(boolean clear, int length, List<BeamSection> sections) {
private static BeamValidation inactive() {
return new BeamValidation(false, 0, List.of());
}
}
}
@@ -0,0 +1,29 @@
package com.craisinlord.antarchy.content.client;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public final class TigerEyeCamouflageClientState {
public record CamouflageState(boolean active, int blockStateId) {}
private static final Map<Integer, CamouflageState> STATES = new ConcurrentHashMap<>();
private TigerEyeCamouflageClientState() {
}
public static void update(int entityId, boolean active, int blockStateId) {
if (!active) {
STATES.remove(entityId);
return;
}
STATES.put(entityId, new CamouflageState(true, blockStateId));
}
public static CamouflageState get(int entityId) {
return STATES.get(entityId);
}
public static void clear() {
STATES.clear();
}
}
@@ -0,0 +1,19 @@
package com.craisinlord.antarchy.content.client;
import java.util.function.Supplier;
import net.minecraft.network.chat.Component;
public final class TigerEyeClientHooks {
private static Supplier<Component> camouflageKeyText = () -> Component.translatable("key.antarchy.tigers_eye_camouflage");
private TigerEyeClientHooks() {
}
public static void setCamouflageKeyTextSupplier(Supplier<Component> supplier) {
camouflageKeyText = supplier;
}
public static Component camouflageKeyText() {
return camouflageKeyText.get();
}
}
@@ -7,10 +7,12 @@ import com.craisinlord.antarchy.content.entity.HerculesBeetleEntity;
import com.craisinlord.antarchy.content.entity.ToreterrorEntity;
import com.craisinlord.antarchy.content.entity.brutalfly.BrutalflyEntity;
import com.craisinlord.antarchy.content.entity.kraken.KrakenEntity;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.BossEvent;
import net.minecraft.world.entity.Entity;
@@ -19,6 +21,7 @@ public final class CustomBossBarRenderer {
private static final int BAR_WIDTH = 182;
private static final int BAR_HEIGHT = 5;
private static final int GLOBAL_Y_OFFSET = 15;
private static final Map<UUID, Textures> TEXTURES_BY_BOSS_ID = new HashMap<>();
private static final Map<Class<? extends Entity>, Textures> BY_ENTITY_CLASS = Map.of(
KrakenEntity.class, textures("blue", "kraken", 204, 56, 4),
@@ -28,6 +31,14 @@ public final class CustomBossBarRenderer {
HerculesBeetleEntity.class, textures("beetle", "hercules_beetle", 194, 33, 1),
EmperorScorpionEntity.class, textures("purple", "scorpion", 218, 34, -2)
);
private static final Map<String, Textures> BY_LOCALIZED_NAME_AND_COLOR = Map.of(
key(Component.translatable("entity.antarchy.kraken").getString(), BossEvent.BossBarColor.BLUE), BY_ENTITY_CLASS.get(KrakenEntity.class),
key(Component.translatable("entity.antarchy.toreterror").getString(), BossEvent.BossBarColor.GREEN), BY_ENTITY_CLASS.get(ToreterrorEntity.class),
key(Component.translatable("entity.antarchy.alpha_mantis").getString(), BossEvent.BossBarColor.GREEN), BY_ENTITY_CLASS.get(AlphaMantisEntity.class),
key(Component.translatable("entity.antarchy.brutalfly").getString(), BossEvent.BossBarColor.YELLOW), BY_ENTITY_CLASS.get(BrutalflyEntity.class),
key(Component.translatable("entity.antarchy.hercules_beetle").getString(), BossEvent.BossBarColor.RED), BY_ENTITY_CLASS.get(HerculesBeetleEntity.class),
key(Component.translatable("entity.antarchy.emperor_scorpion").getString(), BossEvent.BossBarColor.PURPLE), BY_ENTITY_CLASS.get(EmperorScorpionEntity.class)
);
private CustomBossBarRenderer() {
}
@@ -60,11 +71,25 @@ public final class CustomBossBarRenderer {
}
private static Textures lookup(BossEvent bossEvent) {
Entity entity = findEntity(bossEvent.getId());
if (entity == null) {
return null;
Textures cached = TEXTURES_BY_BOSS_ID.get(bossEvent.getId());
if (cached != null) {
return cached;
}
return BY_ENTITY_CLASS.get(entity.getClass());
Entity entity = findEntity(bossEvent.getId());
if (entity != null) {
Textures textures = BY_ENTITY_CLASS.get(entity.getClass());
if (textures != null) {
TEXTURES_BY_BOSS_ID.put(bossEvent.getId(), textures);
return textures;
}
}
Textures fallback = BY_LOCALIZED_NAME_AND_COLOR.get(key(bossEvent.getName().getString(), bossEvent.getColor()));
if (fallback != null) {
TEXTURES_BY_BOSS_ID.put(bossEvent.getId(), fallback);
}
return fallback;
}
private static Entity findEntity(UUID id) {
@@ -91,6 +116,10 @@ public final class CustomBossBarRenderer {
);
}
private static String key(String name, BossEvent.BossBarColor color) {
return color.name() + "|" + name;
}
private record Textures(ResourceLocation background, ResourceLocation progress, ResourceLocation overlay, int overlayWidth, int overlayHeight, int barYOffset) {
}
}
@@ -0,0 +1,26 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.nightmare.NightmareBiteEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class NightmareBiteModel extends GeoModel<NightmareBiteEntity> {
private static final ResourceLocation PHASE_ONE_TEXTURE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/vfx/nightmare_bite.png");
private static final ResourceLocation PHASE_TWO_TEXTURE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/vfx/nightmare_bite_phase_2.png");
@Override
public ResourceLocation getModelResource(NightmareBiteEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/nightmare_bite.geo.json");
}
@Override
public ResourceLocation getTextureResource(NightmareBiteEntity animatable) {
return animatable.isPhaseTwo() ? PHASE_TWO_TEXTURE : PHASE_ONE_TEXTURE;
}
@Override
public ResourceLocation getAnimationResource(NightmareBiteEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/nightmare_bite.animation.json");
}
}
@@ -6,8 +6,10 @@ import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class NightmareModel extends GeoModel<NightmareEntity> {
public static final ResourceLocation EMISSIVE_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/nightmare_emissive.png");
private static final ResourceLocation PHASE_ONE_TEXTURE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/nightmare/nightmare.png");
private static final ResourceLocation PHASE_TWO_TEXTURE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/nightmare/nightmare_phase_2.png");
private static final ResourceLocation PHASE_ONE_EMISSIVE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/nightmare/nightmare_emissive.png");
private static final ResourceLocation PHASE_TWO_EMISSIVE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/nightmare/nightmare_phase_2_emissive.png");
@Override
public ResourceLocation getModelResource(NightmareEntity animatable) {
@@ -16,11 +18,19 @@ public class NightmareModel extends GeoModel<NightmareEntity> {
@Override
public ResourceLocation getTextureResource(NightmareEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/nightmare.png");
return textureFor(animatable);
}
@Override
public ResourceLocation getAnimationResource(NightmareEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/nightmare.animation.json");
}
public static ResourceLocation textureFor(NightmareEntity animatable) {
return animatable.hasPhaseTwoTexture() ? PHASE_TWO_TEXTURE : PHASE_ONE_TEXTURE;
}
public static ResourceLocation emissiveTextureFor(NightmareEntity animatable) {
return animatable.hasPhaseTwoTexture() ? PHASE_TWO_EMISSIVE : PHASE_ONE_EMISSIVE;
}
}
@@ -0,0 +1,25 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.nightmare.NightmarePortalEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class NightmarePortalModel extends GeoModel<NightmarePortalEntity> {
public static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/vfx/nightmare_portal.png");
@Override
public ResourceLocation getModelResource(NightmarePortalEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/nightmare_portal.geo.json");
}
@Override
public ResourceLocation getTextureResource(NightmarePortalEntity animatable) {
return TEXTURE;
}
@Override
public ResourceLocation getAnimationResource(NightmarePortalEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/nightmare_portal.animation.json");
}
}
@@ -0,0 +1,127 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.block.entity.LucidAnchorBlockEntity;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Axis;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.resources.ResourceLocation;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
public class LucidAnchorBlockEntityRenderer implements BlockEntityRenderer<LucidAnchorBlockEntity> {
private static final ResourceLocation BEAM_TEXTURE = ResourceLocation.withDefaultNamespace("textures/entity/beacon_beam.png");
private static final float INNER_RADIUS = 0.14F;
private static final float OUTER_RADIUS = 0.28F;
private static final float START_OFFSET = -0.02F;
public LucidAnchorBlockEntityRenderer(BlockEntityRendererProvider.Context context) {
}
@Override
public void render(LucidAnchorBlockEntity blockEntity, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight, int packedOverlay) {
if (!blockEntity.isActive() || blockEntity.getBeamLength() <= 0 || blockEntity.getBeamSections().isEmpty() || blockEntity.getLevel() == null) {
return;
}
long gameTime = blockEntity.getLevel().getGameTime();
float scroll = (gameTime + partialTick) * 0.02F;
float startY = START_OFFSET;
float endY = START_OFFSET - blockEntity.getBeamLength();
poseStack.pushPose();
poseStack.translate(0.5D, 0.0D, 0.5D);
float currentTop = startY;
for (LucidAnchorBlockEntity.BeamSection section : blockEntity.getBeamSections()) {
float sectionBottom = currentTop - section.length();
renderBeamPrism(poseStack, buffer.getBuffer(RenderType.entityTranslucent(BEAM_TEXTURE)), currentTop, sectionBottom, INNER_RADIUS, section.color(), 1.0F, scroll);
renderBeamPrism(poseStack, buffer.getBuffer(RenderType.entityTranslucent(BEAM_TEXTURE)), currentTop, sectionBottom, OUTER_RADIUS, darken(section.color()), 0.45F, -scroll);
currentTop = sectionBottom;
}
if (currentTop > endY) {
renderBeamPrism(poseStack, buffer.getBuffer(RenderType.entityTranslucent(BEAM_TEXTURE)), currentTop, endY, INNER_RADIUS, 0xFFFF1A1A, 1.0F, scroll);
renderBeamPrism(poseStack, buffer.getBuffer(RenderType.entityTranslucent(BEAM_TEXTURE)), currentTop, endY, OUTER_RADIUS, 0xFF7A0000, 0.45F, -scroll);
}
poseStack.popPose();
}
@Override
public int getViewDistance() {
return 256;
}
private static void renderBeamPrism(PoseStack poseStack, VertexConsumer consumer, float topY, float bottomY, float radius, int color, float alphaScale, float scroll) {
PoseStack.Pose pose = poseStack.last();
Matrix4f matrix = pose.pose();
Matrix3f normal = pose.normal();
float red = ((color >> 16) & 0xFF) / 255.0F;
float green = ((color >> 8) & 0xFF) / 255.0F;
float blue = (color & 0xFF) / 255.0F;
float alpha = ((color >>> 24) & 0xFF) / 255.0F * alphaScale;
float vTop = scroll + topY * 0.25F;
float vBottom = scroll + bottomY * 0.25F;
addFace(consumer, matrix, normal, -radius, topY, -radius, radius, topY, -radius, radius, bottomY, -radius, -radius, bottomY, -radius, red, green, blue, alpha, vTop, vBottom);
addFace(consumer, matrix, normal, radius, topY, radius, -radius, topY, radius, -radius, bottomY, radius, radius, bottomY, radius, red, green, blue, alpha, vTop, vBottom);
addFace(consumer, matrix, normal, -radius, topY, radius, -radius, topY, -radius, -radius, bottomY, -radius, -radius, bottomY, radius, red, green, blue, alpha, vTop, vBottom);
addFace(consumer, matrix, normal, radius, topY, -radius, radius, topY, radius, radius, bottomY, radius, radius, bottomY, -radius, red, green, blue, alpha, vTop, vBottom);
}
private static void addFace(
VertexConsumer consumer,
Matrix4f matrix,
Matrix3f normal,
float x0,
float y0,
float z0,
float x1,
float y1,
float z1,
float x2,
float y2,
float z2,
float x3,
float y3,
float z3,
float red,
float green,
float blue,
float alpha,
float vTop,
float vBottom
) {
addVertex(consumer, matrix, normal, x0, y0, z0, red, green, blue, alpha, 0.0F, vTop);
addVertex(consumer, matrix, normal, x1, y1, z1, red, green, blue, alpha, 1.0F, vTop);
addVertex(consumer, matrix, normal, x2, y2, z2, red, green, blue, alpha, 1.0F, vBottom);
addVertex(consumer, matrix, normal, x3, y3, z3, red, green, blue, alpha, 0.0F, vBottom);
addVertex(consumer, matrix, normal, x3, y3, z3, red, green, blue, alpha, 0.0F, vBottom);
addVertex(consumer, matrix, normal, x2, y2, z2, red, green, blue, alpha, 1.0F, vBottom);
addVertex(consumer, matrix, normal, x1, y1, z1, red, green, blue, alpha, 1.0F, vTop);
addVertex(consumer, matrix, normal, x0, y0, z0, red, green, blue, alpha, 0.0F, vTop);
}
private static void addVertex(VertexConsumer consumer, Matrix4f matrix, Matrix3f normal, float x, float y, float z, float red, float green, float blue, float alpha, float u, float v) {
consumer.addVertex(matrix, x, y, z)
.setColor(red, green, blue, alpha)
.setUv(u, v)
.setOverlay(OverlayTexture.NO_OVERLAY)
.setLight(LightTexture.FULL_BRIGHT)
.setNormal(0.0F, 1.0F, 0.0F);
}
private static int darken(int color) {
int red = (int) (((color >> 16) & 0xFF) * 0.45F);
int green = (int) (((color >> 8) & 0xFF) * 0.2F);
int blue = (int) ((color & 0xFF) * 0.2F);
return (color & 0xFF000000) | (red << 16) | (green << 8) | blue;
}
}
@@ -0,0 +1,13 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.client.model.NightmareBiteModel;
import com.craisinlord.antarchy.content.entity.nightmare.NightmareBiteEntity;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import software.bernie.geckolib.renderer.GeoEntityRenderer;
public class NightmareBiteRenderer extends GeoEntityRenderer<NightmareBiteEntity> {
public NightmareBiteRenderer(EntityRendererProvider.Context context) {
super(context, new NightmareBiteModel());
this.shadowRadius = 0.0F;
}
}
@@ -0,0 +1,37 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.client.model.NightmarePortalModel;
import com.craisinlord.antarchy.content.entity.nightmare.NightmarePortalEntity;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.Nullable;
import software.bernie.geckolib.cache.object.BakedGeoModel;
import software.bernie.geckolib.renderer.GeoEntityRenderer;
public class NightmarePortalRenderer extends GeoEntityRenderer<NightmarePortalEntity> {
public NightmarePortalRenderer(EntityRendererProvider.Context context) {
super(context, new NightmarePortalModel());
this.shadowRadius = 0.0F;
}
@Override
public void render(NightmarePortalEntity entity, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight) {
BakedGeoModel model = this.getGeoModel().getBakedModel(this.getGeoModel().getModelResource(entity));
RenderType renderType = RenderType.eyes(NightmarePortalModel.TEXTURE);
VertexConsumer buffer = bufferSource.getBuffer(renderType);
poseStack.pushPose();
poseStack.scale(1.0F, 1.0F, 1.0F);
this.reRender(model, poseStack, bufferSource, entity, renderType, buffer, partialTick, 0xF000F0, OverlayTexture.NO_OVERLAY, 0xFFFFFFFF);
poseStack.popPose();
}
@Override
public @Nullable RenderType getRenderType(NightmarePortalEntity animatable, ResourceLocation texture, @Nullable MultiBufferSource bufferSource, float partialTick) {
return RenderType.eyes(NightmarePortalModel.TEXTURE);
}
}
@@ -35,7 +35,7 @@ public class NightmareRenderer extends GeoEntityRenderer<NightmareEntity> {
public void render(PoseStack poseStack, NightmareEntity animatable, BakedGeoModel bakedModel, @Nullable RenderType renderType,
MultiBufferSource bufferSource, @Nullable VertexConsumer buffer, float partialTick,
int packedLight, int packedOverlay) {
RenderType emissiveType = RenderType.eyes(NightmareModel.EMISSIVE_TEXTURE);
RenderType emissiveType = RenderType.eyes(NightmareModel.emissiveTextureFor(animatable));
VertexConsumer emissiveBuffer = bufferSource.getBuffer(emissiveType);
this.getRenderer().reRender(
bakedModel,
@@ -0,0 +1,57 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.client.TigerEyeCamouflageClientState;
import com.craisinlord.antarchy.content.item.TigerEyeArmorUtil;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.model.PlayerModel;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
import net.minecraft.client.renderer.entity.RenderLayerParent;
import net.minecraft.client.renderer.entity.layers.RenderLayer;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.Block;
public final class TigerEyeCamouflagePlayerLayer extends RenderLayer<AbstractClientPlayer, PlayerModel<AbstractClientPlayer>> {
public TigerEyeCamouflagePlayerLayer(RenderLayerParent<AbstractClientPlayer, PlayerModel<AbstractClientPlayer>> renderer) {
super(renderer);
}
@Override
public void render(PoseStack poseStack, MultiBufferSource buffer, int packedLight, AbstractClientPlayer player,
float limbSwing, float limbSwingAmount, float partialTick, float ageInTicks, float netHeadYaw,
float headPitch) {
if (player.isSpectator() || player.isInvisible() || player.hasEffect(AntarchyObjects.PARALYZED_EFFECT.get())) {
return;
}
if (!TigerEyeArmorUtil.hasFullSet(player)) {
return;
}
TigerEyeCamouflageClientState.CamouflageState state = TigerEyeCamouflageClientState.get(player.getId());
if (state == null || !state.active()) {
return;
}
var blockState = Block.stateById(state.blockStateId());
if (!TigerEyeArmorUtil.isValidCamouflageBlock(blockState)) {
return;
}
poseStack.pushPose();
poseStack.scale(1.1F, 1.1F, 1.1F);
var resolved = TigerEyeCamouflageTextureResolver.resolve(blockState, BlockPos.containing(player.position()));
VertexConsumer vertexConsumer = buffer.getBuffer(RenderType.entityCutoutNoCull(resolved.texture()));
this.getParentModel().renderToBuffer(
poseStack,
vertexConsumer,
packedLight,
LivingEntityRenderer.getOverlayCoords(player, 0.0F),
resolved.argbTint()
);
poseStack.popPose();
}
}
@@ -0,0 +1,146 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.mojang.blaze3d.platform.NativeImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.client.Minecraft;
import net.minecraft.client.color.block.BlockColors;
import net.minecraft.client.renderer.block.BlockRenderDispatcher;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
public final class TigerEyeCamouflageTextureResolver {
public record ResolvedTexture(ResourceLocation texture, int argbTint) {}
// PlayerModel's skin layout is always laid out on a 64x64 canvas, regardless of the
// block texture's actual size, so the generated overlay texture must match that grid
// for every body part to sample the block texture at the same pixel density.
private static final int SKIN_SIZE = 64;
private static final Map<Integer, ResolvedTexture> CACHE = new ConcurrentHashMap<>();
private static final ResourceLocation FALLBACK_TEXTURE = ResourceLocation.withDefaultNamespace("textures/block/stone.png");
private static final long QUAD_SEED = 0x54EADL;
private TigerEyeCamouflageTextureResolver() {
}
public static ResolvedTexture resolve(BlockState state, BlockPos pos) {
int stateId = Block.getId(state);
ResolvedTexture cached = CACHE.get(stateId);
if (cached != null) {
return cached;
}
ResolvedTexture resolved = resolveUncached(state, pos);
CACHE.put(stateId, resolved);
return resolved;
}
public static void clearCache() {
Minecraft minecraft = Minecraft.getInstance();
for (ResolvedTexture resolved : CACHE.values()) {
if (!resolved.texture().equals(FALLBACK_TEXTURE)) {
minecraft.getTextureManager().release(resolved.texture());
}
}
CACHE.clear();
}
private static ResolvedTexture resolveUncached(BlockState state, BlockPos pos) {
Minecraft minecraft = Minecraft.getInstance();
BlockRenderDispatcher dispatcher = minecraft.getBlockRenderer();
var model = dispatcher.getBlockModel(state);
List<BakedQuad> upwardQuads = model.getQuads(state, Direction.UP, RandomSource.create(QUAD_SEED));
TextureAtlasSprite sprite = firstSprite(upwardQuads);
int tintIndex = -1;
if (sprite == null) {
sprite = model.getParticleIcon();
} else if (!upwardQuads.isEmpty()) {
tintIndex = upwardQuads.getFirst().getTintIndex();
}
if (sprite == null) {
return new ResolvedTexture(FALLBACK_TEXTURE, 0xFFFFFFFF);
}
int tint = 0xFFFFFFFF;
if (tintIndex >= 0) {
BlockColors colors = minecraft.getBlockColors();
int color = colors.getColor(state, minecraft.level, pos, tintIndex);
if (color != -1) {
tint = 0xFF000000 | color;
}
}
ResourceLocation tiled = buildTiledSkin(minecraft, sprite.contents().name());
return new ResolvedTexture(tiled, tint);
}
private static ResourceLocation buildTiledSkin(Minecraft minecraft, ResourceLocation spriteId) {
ResourceLocation source = ResourceLocation.fromNamespaceAndPath(
spriteId.getNamespace(),
"textures/" + spriteId.getPath() + ".png"
);
ResourceLocation target = ResourceLocation.fromNamespaceAndPath(
spriteId.getNamespace(),
"dynamic/tiger_eye_camouflage/" + spriteId.getPath()
);
try (InputStream stream = openStream(minecraft, source)) {
if (stream == null) {
return FALLBACK_TEXTURE;
}
try (NativeImage sourceImage = NativeImage.read(stream)) {
int tileWidth = sourceImage.getWidth();
// Animated block textures stack frames vertically below a square first frame.
int tileHeight = tileWidth <= sourceImage.getHeight() ? tileWidth : sourceImage.getHeight();
NativeImage canvas = new NativeImage(SKIN_SIZE, SKIN_SIZE, false);
for (int y = 0; y < SKIN_SIZE; y++) {
for (int x = 0; x < SKIN_SIZE; x++) {
canvas.setPixelRGBA(x, y, sourceImage.getPixelRGBA(x % tileWidth, y % tileHeight));
}
}
minecraft.getTextureManager().register(target, new DynamicTexture(canvas));
return target;
}
} catch (IOException e) {
return FALLBACK_TEXTURE;
}
}
private static InputStream openStream(Minecraft minecraft, ResourceLocation location) {
return minecraft.getResourceManager().getResource(location)
.map(resource -> {
try {
return resource.open();
} catch (IOException e) {
return null;
}
})
.orElse(null);
}
private static TextureAtlasSprite firstSprite(List<BakedQuad> quads) {
if (quads == null || quads.isEmpty()) {
return null;
}
for (BakedQuad quad : quads) {
if (quad != null && quad.getSprite() != null) {
return quad.getSprite();
}
}
return null;
}
}
@@ -1,6 +1,5 @@
package com.craisinlord.antarchy.content.creative;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.glimmer.GlimmerVariant;
import com.craisinlord.antarchy.content.item.GlimmerBottleItem;
import com.craisinlord.antarchy.content.item.ultimate.UltimateGearHelper;
@@ -21,6 +20,8 @@ import net.minecraft.world.item.alchemy.PotionContents;
import net.minecraft.world.level.ItemLike;
public final class CreativeTabContents {
private static final String MODID = "antarchy";
private CreativeTabContents() {}
private record CatalogEntry(String path, String neoTabPath, String insertAfterPath) {}
@@ -89,6 +90,7 @@ public final class CreativeTabContents {
entry("mossy_shellstone_brick_slab", "building_blocks"),
entry("mossy_shellstone_brick_wall", "building_blocks"),
entry("cracked_shellstone_bricks", "building_blocks"),
entry("shellstone_pillar", "building_blocks"),
entry("blush_moss_block", "building_blocks"),
entry("blush_moss_carpet", "building_blocks"),
entry("lumen_froglight", "natural_blocks"),
@@ -108,16 +110,22 @@ public final class CreativeTabContents {
entry("nyxite_brick_slab", "building_blocks"),
entry("nyxite_brick_wall", "building_blocks"),
entry("chiseled_nyxite", "building_blocks"),
entry("nyxite_pillar", "building_blocks"),
entry("pale_nyxite", "building_blocks"),
entry("nyxite_spike", "building_blocks"),
entry("potent_nyxite", "building_blocks"),
entry("antimetal", "building_blocks"),
entry("antimetal_stairs", "building_blocks"),
entry("antimetal_slab", "building_blocks"),
entry("polished_antimetal", "building_blocks"),
entry("polished_antimetal_stairs", "building_blocks"),
entry("polished_antimetal_slab", "building_blocks"),
entry("antimetal_scaffolding", "building_blocks"),
entry("antimetal_rail", "redstone_blocks"),
entry("antimetal_powered_rail", "redstone_blocks"),
entry("antimetal_detector_rail", "redstone_blocks"),
entry("antimetal_activator_rail", "redstone_blocks"),
entry("upper", "redstone_blocks"),
entry("umbral_moss_block", "building_blocks"),
entry("umbral_moss_carpet", "building_blocks"),
entry("dream_torch", "building_blocks"),
@@ -134,6 +142,7 @@ public final class CreativeTabContents {
entry("smooth_dream_sandstone_stairs", "building_blocks"),
entry("smooth_dream_sandstone_slab", "building_blocks"),
entry("cut_dream_sandstone_slab", "building_blocks"),
entry("antigravel", "natural_blocks"),
entry("budding_blood_crystal", "building_blocks"),
entry("blood_crystal_block", "building_blocks"),
entry("blood_crystal_cluster", "building_blocks"),
@@ -145,6 +154,7 @@ public final class CreativeTabContents {
entry("biomite_turf", "building_blocks"),
entry("biowart", "building_blocks"),
entry("biowart_tendrils", "building_blocks"),
entry("loam", "natural_blocks"),
entry("broodstone", "building_blocks"),
entry("polished_broodstone", "building_blocks"),
entry("chiseled_broodstone", "building_blocks"),
@@ -158,12 +168,13 @@ public final class CreativeTabContents {
entry("broodstone_brick_stairs", "building_blocks"),
entry("broodstone_brick_slab", "building_blocks"),
entry("broodstone_brick_wall", "building_blocks"),
entry("broodstone_pillar", "building_blocks"),
entry("myrmite_coal_ore", "building_blocks"),
entry("broodstone_uranium_ore", "building_blocks"),
entry("broodstone_titanium_ore", "building_blocks"),
entry("bile_vein", "building_blocks"),
entry("chiten_block", "building_blocks"),
entry("chiten_spike", "building_blocks"),
entry("chitin_block", "building_blocks"),
entry("chitin_spike", "building_blocks"),
entry("amber_moss_block", "building_blocks"),
entry("amber_moss_carpet", "building_blocks"),
entry("uranium_block", "building_blocks"),
@@ -180,6 +191,7 @@ public final class CreativeTabContents {
entry("bluestone_repeater", "redstone_blocks"),
entry("bluestone_comparator", "redstone_blocks"),
entry("bluestone_torch", "redstone_blocks"),
entry("bluestone_lamp", "redstone_blocks"),
entry("titanium_block", "building_blocks"),
entry("raw_titanium_block", "building_blocks"),
entry("cut_titanium", "building_blocks"),
@@ -205,6 +217,7 @@ public final class CreativeTabContents {
entry("seashell", "natural_blocks"),
entry("hushweed", "natural_blocks"),
entry("amber_lichen", "natural_blocks"),
entry("mucus", "natural_blocks"),
entry("creepvine", "natural_blocks"),
entry("hanging_creeproots", "natural_blocks"),
entry("molting_vines", "natural_blocks"),
@@ -243,6 +256,7 @@ public final class CreativeTabContents {
entry("antiwater_bucket", "tools_and_utilities"),
entry("lumen_bucket", "tools_and_utilities"),
entry("cloud_bucket", "tools_and_utilities"),
entry("lucid_anchor", "tools_and_utilities"),
entry("reverie_bottle", "tools_and_utilities"),
entry("glimmer_bottle", "tools_and_utilities"),
entry("critter_cage", "tools_and_utilities"),
@@ -283,6 +297,10 @@ public final class CreativeTabContents {
entry("blood_crystal_chestplate", "combat"),
entry("blood_crystal_leggings", "combat"),
entry("blood_crystal_boots", "combat"),
entry("tigers_eye_helmet", "combat"),
entry("tigers_eye_chestplate", "combat"),
entry("tigers_eye_leggings", "combat"),
entry("tigers_eye_boots", "combat"),
entry("moggles", "combat"),
entry("scorpion_whip", "combat"),
entry("fallen_king_crown", "combat"),
@@ -306,15 +324,15 @@ public final class CreativeTabContents {
entry("mud_pie", "ingredients"),
entry("lucid_eye", "ingredients"),
entry("blood_crystal_shard", "ingredients"),
entry("tigers_eye", "ingredients"),
entry("blood_crystal_apple", "ingredients"),
entry("spirit_apple", "ingredients"),
entry("mantis_claw", "combat"),
entry("hercules_horn", "ingredients"),
entry("king_scale", "ingredients"),
entry("queen_scale", "ingredients"),
entry("chiten", "ingredients"),
entry("chitin", "ingredients"),
entry("jerry_nucleus", "ingredients"),
entry("carapace", "ingredients"),
entry("stink_bug", "ingredients"),
entry("brutalfly_wing", "ingredients"),
entry("primordial_scute", "ingredients"),
@@ -323,6 +341,7 @@ public final class CreativeTabContents {
entry("emperor_scorpion_stinger", "ingredients"),
entry("kraken_tooth", "ingredients"),
entry("kraken_tentacle", "ingredients"),
entry("kraken_kalamari", "ingredients"),
entry("jumpy_bug_leg", "ingredients"),
entry("cornea_ear", "ingredients"),
entry("corn", "ingredients"),
@@ -493,7 +512,7 @@ public final class CreativeTabContents {
}
private static Item item(String path) {
return BuiltInRegistries.ITEM.get(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, path));
return BuiltInRegistries.ITEM.get(ResourceLocation.fromNamespaceAndPath(MODID, path));
}
private static Item vanillaItem(String path) {
@@ -501,7 +520,7 @@ public final class CreativeTabContents {
}
private static Holder<Potion> potion(String path) {
Potion potion = BuiltInRegistries.POTION.get(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, path));
Potion potion = BuiltInRegistries.POTION.get(ResourceLocation.fromNamespaceAndPath(MODID, path));
return potion == null ? null : BuiltInRegistries.POTION.wrapAsHolder(potion);
}
}
@@ -103,6 +103,26 @@ public class AlphaMantisEntity extends MantisEntity {
return 1.05D;
}
@Override
protected double configuredMaxHealth() {
return AntarchySettings.alphaMantisHealth();
}
@Override
protected double configuredAttackDamage() {
return AntarchySettings.alphaMantisAttackDamage();
}
@Override
protected double configuredMovementSpeed() {
return AntarchySettings.alphaMantisMovementSpeed();
}
@Override
protected double configuredFlyingSpeed() {
return AntarchySettings.alphaMantisFlyingSpeed();
}
@Override
public void tick() {
super.tick();
@@ -251,6 +251,7 @@ public class BedBugEntity extends Animal implements GeoEntity {
public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData spawnGroupData) {
BedBugSpawnData bedBugSpawnData = spawnGroupData instanceof BedBugSpawnData data ? data : new BedBugSpawnData();
super.finalizeSpawn(level, difficulty, spawnReason, null);
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.bedBugHealth());
if (bedBugSpawnData.eggNestPos == null && (spawnReason == MobSpawnType.NATURAL || spawnReason == MobSpawnType.CHUNK_GENERATION) && this.random.nextFloat() < 0.55F) {
bedBugSpawnData.eggNestPos = this.createNaturalEggNest(level);
@@ -234,6 +234,7 @@ public class ButterflyEntity extends Animal implements FlyingAnimal, GeoEntity {
@Override
public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, MobSpawnType spawnType, @Nullable SpawnGroupData spawnGroupData) {
this.assignRandomTextureVariant();
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.butterflyHealth());
return super.finalizeSpawn(level, difficulty, spawnType, spawnGroupData);
}
@@ -128,6 +128,12 @@ public class CaterpillarEntity extends Animal implements GeoEntity {
.add(Attributes.FOLLOW_RANGE, 14.0D);
}
@Override
public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData spawnData) {
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.caterpillarHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
@Override
protected PathNavigation createNavigation(Level level) {
GroundPathNavigation navigation = new GroundPathNavigation(this, level) {
@@ -48,6 +48,12 @@ public class CheepEntity extends AbstractFish implements GeoEntity {
.add(Attributes.MOVEMENT_SPEED, 0.5D);
}
@Override
public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData spawnData) {
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.cheepHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
@Override
public ItemStack getBucketItemStack() {
return new ItemStack(Items.WATER_BUCKET);
@@ -0,0 +1,18 @@
package com.craisinlord.antarchy.content.entity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
import net.minecraft.world.entity.ai.attributes.Attributes;
public final class ConfiguredMobSpawnUtil {
private ConfiguredMobSpawnUtil() {
}
public static void applyConfiguredHealth(Mob mob, double maxHealth) {
AttributeInstance maxHealthAttribute = mob.getAttribute(Attributes.MAX_HEALTH);
if (maxHealthAttribute != null) {
maxHealthAttribute.setBaseValue(maxHealth);
}
mob.setHealth((float) maxHealth);
}
}
@@ -74,6 +74,12 @@ public class CreepingHorrorEntity extends Monster implements GeoEntity {
.add(Attributes.FOLLOW_RANGE, 16.0D);
}
@Override
public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData spawnData) {
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.creepingHorrorHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
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;
@@ -160,6 +160,12 @@ public class DorrieEntity extends Animal implements GeoEntity {
.add(Attributes.ATTACK_DAMAGE, 4.0D);
}
@Override
public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData spawnData) {
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.dorrieHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
public boolean hasSaddle() {
return this.entityData.get(HAS_SADDLE);
}
@@ -15,6 +15,7 @@ import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerBossEvent;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.util.RandomSource;
@@ -37,7 +38,6 @@ import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
import net.minecraft.world.entity.ai.goal.RandomStrollGoal;
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.entity.player.Player;
@@ -55,6 +55,9 @@ import software.bernie.geckolib.animation.RawAnimation;
import software.bernie.geckolib.util.GeckoLibUtil;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
public class EmperorScorpionEntity extends Monster implements GeoEntity {
private static final byte CLAW_ATTACK_EVENT = 4;
@@ -85,6 +88,21 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
private static final float HARDEN_HEAL_AMOUNT = 2.0F;
private static final int HARDEN_MIN_DURATION_TICKS = 100;
private static final int HARDEN_MAX_DURATION_TICKS = 200;
private static final double CLAW_VERTICAL_TOLERANCE = 2.5D;
private static final double STING_VERTICAL_TOLERANCE = 3.25D;
private static final double CLAW_FORWARD_DOT = 0.05D;
private static final double STING_FORWARD_DOT = 0.45D;
private static final double CLAW_STRIKE_FORWARD = 2.6D;
private static final double STING_STRIKE_FORWARD = 3.4D;
private static final double CLAW_STRIKE_RADIUS = 2.35D;
private static final double STING_STRIKE_RADIUS = 2.15D;
private static final double ENCOUNTER_HOME_RADIUS = 72.0D;
private static final double ENCOUNTER_LEASH_RADIUS = 96.0D;
private static final double HOME_REACHED_RADIUS = 9.0D;
private static final double FORCED_RETURN_RADIUS = 144.0D;
private static final int RESET_DELAY_TICKS = 240;
private static final double HOME_RETURN_SPEED = 1.0D;
private static final double NEARBY_SCORPION_CHECK_RADIUS = 32.0D;
private static final ResourceKey<Level> THORAXIS_KEY =
ResourceKey.create(Registries.DIMENSION,
@@ -113,12 +131,17 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
private int hardenDurationTicks;
private int hardenHealTicks;
private int hardenSummonedScorpions;
private int disengageTicks;
private float hardenLockedYaw;
private float hardenLockedPitch;
private float attackYaw;
private boolean attackDamageApplied;
private AttackType currentAttack = AttackType.NONE;
private HardenPhase hardenPhase = HardenPhase.NONE;
private AttackType previousAttack = AttackType.NONE;
@Nullable private BlockPos encounterHome;
@Nullable private LivingEntity attackTarget;
private final Set<UUID> summonedScorpionIds = new HashSet<>();
public EmperorScorpionEntity(EntityType<? extends EmperorScorpionEntity> entityType, Level level) {
super(entityType, level);
@@ -137,6 +160,13 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
.add(Attributes.FOLLOW_RANGE, AntarchySettings.emperorScorpionFollowRange());
}
@Override
public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty,
MobSpawnType spawnReason, @Nullable net.minecraft.world.entity.SpawnGroupData spawnData) {
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.emperorScorpionHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
@@ -204,7 +234,11 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
@Override
public void tick() {
super.tick();
if (!this.level().isClientSide) {
this.tickEncounterState();
}
this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth());
this.bossEvent.setVisible(this.shouldShowBossBar());
if (this.clawCooldownTicks > 0) {
this.clawCooldownTicks--;
@@ -271,8 +305,10 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
}
this.attackTarget = target;
this.currentAttack = attackType;
this.previousAttack = attackType;
this.attackAnimTicks = attackType.animTicks();
this.attackDamageApplied = false;
this.attackYaw = this.getYRot();
this.getNavigation().stop();
if (attackType == AttackType.CLAW) {
this.clawCooldownTicks = AntarchySettings.emperorScorpionClawCooldownTicks();
@@ -291,7 +327,12 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
return;
}
this.getLookControl().setLookAt(this.attackTarget, 30.0F, 30.0F);
if (this.attackAnimTicks > this.currentAttack.commitTick()) {
this.getLookControl().setLookAt(this.attackTarget, 30.0F, 30.0F);
this.attackYaw = this.getYRot();
} else {
this.lockAttackRotation();
}
if (!this.attackDamageApplied
&& this.attackAnimTicks == this.currentAttack.hitTick()
&& this.canHitAttackTarget(this.attackTarget, this.currentAttack)) {
@@ -305,8 +346,28 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
}
private boolean canHitAttackTarget(LivingEntity target, AttackType attackType) {
double range = attackType == AttackType.STING ? STING_RANGE : CLAW_RANGE;
return this.distanceToSqr(target) <= range * range && this.hasLineOfSight(target);
if (!target.isAlive() || !this.hasLineOfSight(target)) {
return false;
}
Vec3 origin = this.getStrikeOrigin(attackType);
Vec3 targetCenter = target.position().add(0.0D, target.getBbHeight() * 0.5D, 0.0D);
Vec3 offset = targetCenter.subtract(origin);
double verticalTolerance = attackType == AttackType.STING ? STING_VERTICAL_TOLERANCE : CLAW_VERTICAL_TOLERANCE;
if (Math.abs(offset.y) > verticalTolerance) {
return false;
}
Vec3 horizontal = new Vec3(offset.x, 0.0D, offset.z);
if (horizontal.lengthSqr() < 1.0E-6D) {
return true;
}
Vec3 forward = Vec3.directionFromRotation(0.0F, this.attackYaw);
double forwardDot = horizontal.normalize().dot(new Vec3(forward.x, 0.0D, forward.z).normalize());
double minForwardDot = attackType == AttackType.STING ? STING_FORWARD_DOT : CLAW_FORWARD_DOT;
if (forwardDot < minForwardDot) {
return false;
}
double strikeRadius = attackType == AttackType.STING ? STING_STRIKE_RADIUS : CLAW_STRIKE_RADIUS;
return origin.distanceToSqr(targetCenter) <= strikeRadius * strikeRadius;
}
private void resetAttackState() {
@@ -316,6 +377,13 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
this.attackTarget = null;
}
private Vec3 getStrikeOrigin(AttackType attackType) {
Vec3 forward = Vec3.directionFromRotation(0.0F, this.attackYaw);
double forwardOffset = attackType == AttackType.STING ? STING_STRIKE_FORWARD : CLAW_STRIKE_FORWARD;
double verticalOffset = attackType == AttackType.STING ? this.getBbHeight() * 0.8D : this.getBbHeight() * 0.52D;
return this.position().add(forward.x * forwardOffset, verticalOffset, forward.z * forwardOffset);
}
private void tickHardenState() {
if (this.getHardenPhase() == HardenPhase.NONE) {
if (this.hardenCooldownTicks <= 0 && this.getTarget() != null && this.getTarget().isAlive()) {
@@ -330,9 +398,13 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
switch (this.getHardenPhase()) {
case CASTING -> {
LivingEntity target = this.getTarget();
if (target != null) {
this.getLookControl().setLookAt(target, 20.0F, 20.0F);
}
if (this.hardenCastTicks % this.hardenCastSpawnTicks == 0
&& this.hardenSummonedScorpions < AntarchySettings.emperorScorpionMaxSummonedScorpions()
&& this.countNearbyScorpionMinions() < AntarchySettings.emperorScorpionMaxNearbyScorpions()) {
&& this.countOwnedNearbyScorpionMinions() < AntarchySettings.emperorScorpionMaxNearbyScorpions()) {
this.summonScorpionMinion();
this.hardenSummonedScorpions++;
if (this.hardenSummonedScorpions >= AntarchySettings.emperorScorpionMaxSummonedScorpions()) {
@@ -369,7 +441,7 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
this.setDeltaMovement(0.0D, motion.y, 0.0D);
if (--this.hardenStateTicks <= 0) {
this.setHardenPhase(HardenPhase.NONE);
this.hardenCooldownTicks = Math.max(1, AntarchySettings.emperorScorpionSummonIntervalTicks());
this.hardenCooldownTicks = Math.max(1, AntarchySettings.emperorScorpionHardenCooldownTicks());
}
}
}
@@ -384,6 +456,7 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
this.hardenHealTicks = 0;
this.hardenSummonedScorpions = 0;
this.resetAttackState();
this.previousAttack = AttackType.NONE;
this.getNavigation().stop();
}
@@ -408,13 +481,12 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
this.setAggressive(false);
}
private static final double NEARBY_SCORPION_CHECK_RADIUS = 24.0D;
private int countNearbyScorpionMinions() {
private int countOwnedNearbyScorpionMinions() {
UUID ownerId = this.getUUID();
return this.level().getEntitiesOfClass(
ScorpionEntity.class,
this.getBoundingBox().inflate(NEARBY_SCORPION_CHECK_RADIUS),
Entity::isAlive
scorpion -> scorpion.isAlive() && scorpion.isSummonedFor(ownerId)
).size();
}
@@ -428,16 +500,19 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
return;
}
Vec3 anchor = this.getTarget() != null ? this.getTarget().position() : this.position();
Vec3 ring = Vec3.directionFromRotation(0.0F, this.random.nextFloat() * 360.0F)
.scale(2.75D + this.random.nextDouble() * 1.75D);
BlockPos spawnPos = BlockPos.containing(this.getX() + ring.x, this.getY(), this.getZ() + ring.z);
BlockPos spawnPos = BlockPos.containing(anchor.x + ring.x, this.getY(), anchor.z + ring.z);
scorpion.moveTo(spawnPos.getX() + 0.5D, spawnPos.getY(), spawnPos.getZ() + 0.5D, this.random.nextFloat() * 360.0F, 0.0F);
scorpion.finalizeSpawn(serverLevel, serverLevel.getCurrentDifficultyAt(spawnPos), MobSpawnType.MOB_SUMMONED, null);
scorpion.setPersistenceRequired();
scorpion.setSummonOwner(this.getUUID());
if (this.getTarget() instanceof LivingEntity target) {
scorpion.setTarget(target);
}
serverLevel.addFreshEntity(scorpion);
this.summonedScorpionIds.add(scorpion.getUUID());
}
private void commitLunge(LivingEntity target, double horizontalSpeed, double verticalSpeed) {
@@ -447,6 +522,7 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
return;
}
horizontal = horizontal.normalize().scale(horizontalSpeed);
this.attackYaw = (float) (net.minecraft.util.Mth.atan2(horizontal.z, horizontal.x) * (180.0D / Math.PI)) - 90.0F;
this.setDeltaMovement(this.getDeltaMovement().add(horizontal.x, verticalSpeed, horizontal.z));
this.hasImpulse = true;
}
@@ -509,6 +585,14 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
this.entityData.set(HARDEN_PHASE, phase.ordinal());
}
private void lockAttackRotation() {
this.setYRot(this.attackYaw);
this.setYHeadRot(this.attackYaw);
this.yBodyRot = this.attackYaw;
this.yBodyRotO = this.attackYaw;
this.yHeadRotO = this.attackYaw;
}
private void lockHardenRotation() {
if (!this.isHardenSequenceActive()) {
return;
@@ -600,6 +684,11 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
tag.putInt("HardenDurationTicks", this.hardenDurationTicks);
tag.putInt("HardenHealTicks", this.hardenHealTicks);
tag.putInt("HardenSummonedScorpions", this.hardenSummonedScorpions);
if (this.encounterHome != null) {
tag.putInt("EncounterHomeX", this.encounterHome.getX());
tag.putInt("EncounterHomeY", this.encounterHome.getY());
tag.putInt("EncounterHomeZ", this.encounterHome.getZ());
}
}
@Override
@@ -631,6 +720,16 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
if (tag.contains("HardenSummonedScorpions")) {
this.hardenSummonedScorpions = tag.getInt("HardenSummonedScorpions");
}
if (tag.contains("EncounterHomeX") && tag.contains("EncounterHomeY") && tag.contains("EncounterHomeZ")) {
this.encounterHome = new BlockPos(tag.getInt("EncounterHomeX"), tag.getInt("EncounterHomeY"), tag.getInt("EncounterHomeZ"));
}
this.resetAttackState();
this.attackYaw = this.getYRot();
if (this.getHardenPhase() == HardenPhase.CASTING) {
this.setHardenPhase(HardenPhase.NONE);
}
this.disengageTicks = 0;
this.summonedScorpionIds.clear();
}
@Override
@@ -653,6 +752,9 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
@Override
public void remove(RemovalReason reason) {
if (!this.level().isClientSide) {
this.discardOwnedScorpions();
}
super.remove(reason);
this.bossEvent.removeAllPlayers();
}
@@ -661,6 +763,148 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
return this.attackAnimTicks > 0;
}
private void tickEncounterState() {
if (this.encounterHome == null) {
this.encounterHome = this.blockPosition();
}
LivingEntity target = this.getTarget();
if (!this.isValidEncounterTarget(target)) {
if (target != null) {
this.setTarget(null);
}
target = null;
}
if (target != null) {
this.disengageTicks = 0;
if (this.isOutsideLeashRadius()) {
this.resetEncounter(true);
}
return;
}
if (this.isAttackLocked() || this.isHardenSequenceActive()) {
return;
}
if (this.hasOwnedScorpionsNearby()) {
this.disengageTicks = 0;
return;
}
if (!this.isAtEncounterHome()) {
this.disengageTicks++;
if (this.disengageTicks >= RESET_DELAY_TICKS) {
this.resetEncounter(true);
} else {
this.navigateHome();
}
return;
}
this.disengageTicks = 0;
}
private boolean isValidEncounterTarget(@Nullable LivingEntity target) {
if (target == null || !target.isAlive() || !target.level().equals(this.level())) {
return false;
}
if (target instanceof Player player && (player.isCreative() || player.isSpectator())) {
return false;
}
if (this.encounterHome == null) {
return true;
}
return target.distanceToSqr(Vec3.atCenterOf(this.encounterHome)) <= ENCOUNTER_LEASH_RADIUS * ENCOUNTER_LEASH_RADIUS;
}
private boolean shouldShowBossBar() {
return this.getTarget() != null
|| this.isAttackLocked()
|| this.isHardenSequenceActive()
|| this.hasOwnedScorpionsNearby()
|| !this.isAtEncounterHome();
}
private boolean isAtEncounterHome() {
if (this.encounterHome == null) {
return true;
}
return this.distanceToSqr(Vec3.atCenterOf(this.encounterHome)) <= HOME_REACHED_RADIUS;
}
private boolean isOutsideLeashRadius() {
if (this.encounterHome == null) {
return false;
}
return this.distanceToSqr(Vec3.atCenterOf(this.encounterHome)) > ENCOUNTER_LEASH_RADIUS * ENCOUNTER_LEASH_RADIUS;
}
private boolean hasOwnedScorpionsNearby() {
return this.countOwnedNearbyScorpionMinions() > 0;
}
private void navigateHome() {
if (this.encounterHome == null) {
return;
}
Vec3 homeCenter = Vec3.atCenterOf(this.encounterHome);
if (this.distanceToSqr(homeCenter) > FORCED_RETURN_RADIUS * FORCED_RETURN_RADIUS) {
this.moveTo(homeCenter.x, this.encounterHome.getY(), homeCenter.z, this.getYRot(), this.getXRot());
this.setDeltaMovement(Vec3.ZERO);
this.hasImpulse = true;
return;
}
this.getNavigation().moveTo(homeCenter.x, this.encounterHome.getY(), homeCenter.z, HOME_RETURN_SPEED);
}
private void resetEncounter(boolean restoreHealth) {
this.resetAttackState();
this.getNavigation().stop();
this.setTarget(null);
this.setAggressive(false);
this.setHardenPhase(HardenPhase.NONE);
this.hardenCastTicks = 0;
this.hardenCastSpawnTicks = 0;
this.hardenStateTicks = 0;
this.hardenDurationTicks = 0;
this.hardenHealTicks = 0;
this.hardenSummonedScorpions = 0;
this.hardenCooldownTicks = Math.max(1, AntarchySettings.emperorScorpionHardenCooldownTicks());
this.disengageTicks = 0;
this.previousAttack = AttackType.NONE;
if (restoreHealth) {
this.setHealth(this.getMaxHealth());
}
this.discardOwnedScorpions();
if (this.encounterHome != null) {
Vec3 homeCenter = Vec3.atCenterOf(this.encounterHome);
this.moveTo(homeCenter.x, this.encounterHome.getY(), homeCenter.z, this.getYRot(), this.getXRot());
this.setDeltaMovement(Vec3.ZERO);
}
}
private void discardOwnedScorpions() {
if (!(this.level() instanceof ServerLevel serverLevel)) {
this.summonedScorpionIds.clear();
return;
}
UUID ownerId = this.getUUID();
for (UUID scorpionId : Set.copyOf(this.summonedScorpionIds)) {
Entity entity = serverLevel.getEntity(scorpionId);
if (entity instanceof ScorpionEntity scorpion && scorpion.isAlive() && scorpion.isSummonedFor(ownerId)) {
scorpion.remove(RemovalReason.DISCARDED);
}
}
this.level().getEntitiesOfClass(
ScorpionEntity.class,
this.getBoundingBox().inflate(NEARBY_SCORPION_CHECK_RADIUS * 2.0D),
scorpion -> scorpion.isAlive() && scorpion.isSummonedFor(ownerId)
).forEach(scorpion -> scorpion.remove(RemovalReason.DISCARDED));
this.summonedScorpionIds.clear();
}
public boolean isHardenSequenceActive() {
return this.getHardenPhase() != HardenPhase.NONE;
}
@@ -761,23 +1005,31 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
@Override
public boolean isWithinMeleeAttackRange(LivingEntity target) {
if (this.encounterHome != null && target.distanceToSqr(Vec3.atCenterOf(this.encounterHome)) > ENCOUNTER_HOME_RADIUS * ENCOUNTER_HOME_RADIUS) {
return false;
}
return this.distanceToSqr(target) <= STING_RANGE * STING_RANGE;
}
private AttackType selectAttack(LivingEntity target) {
boolean inClawRange = this.clawCooldownTicks <= 0 && this.distanceToSqr(target) <= CLAW_RANGE * CLAW_RANGE;
boolean inStingRange = this.stingCooldownTicks <= 0 && this.distanceToSqr(target) <= STING_RANGE * STING_RANGE;
double horizontalDistance = this.distanceToSqr(target);
boolean inClawRange = this.clawCooldownTicks <= 0 && horizontalDistance <= CLAW_RANGE * CLAW_RANGE;
boolean inStingRange = this.stingCooldownTicks <= 0 && horizontalDistance <= STING_RANGE * STING_RANGE;
boolean canClaw = inClawRange && this.hasLineOfSight(target);
boolean canSting = inStingRange && this.hasLineOfSight(target);
if (canSting && (!canClaw || this.random.nextFloat() < 0.3F)) {
if (canClaw && canSting) {
double heightDifference = target.getY() - this.getY();
if (heightDifference > 1.25D || horizontalDistance > CLAW_RANGE * CLAW_RANGE * 0.7D) {
return this.previousAttack == AttackType.STING && this.random.nextFloat() < 0.5F ? AttackType.CLAW : AttackType.STING;
}
return this.previousAttack == AttackType.CLAW && this.random.nextFloat() < 0.55F ? AttackType.STING : AttackType.CLAW;
}
if (canSting) {
return AttackType.STING;
}
if (canClaw) {
return AttackType.CLAW;
}
if (canSting) {
return AttackType.STING;
}
return AttackType.NONE;
}
@@ -801,6 +1053,14 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
default -> 0;
};
}
private int commitTick() {
return switch (this) {
case CLAW -> Math.max(1, this.hitTick() + 3);
case STING -> Math.max(1, this.hitTick() + 4);
default -> 0;
};
}
}
private enum HardenPhase {
@@ -202,6 +202,13 @@ public class HerculesBeetleEntity extends TamableAnimal implements GeoEntity, Fl
.add(Attributes.ARMOR, 12.0D);
}
@Override
public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty,
MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData spawnData) {
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.herculesBeetleHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
public static boolean canSpawn(EntityType<HerculesBeetleEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
if (spawnReason == MobSpawnType.SPAWN_EGG || spawnReason == MobSpawnType.SPAWNER || spawnReason == MobSpawnType.COMMAND) {
return true;
@@ -62,6 +62,13 @@ public class LurkingTerrorEntity extends Monster implements GeoEntity {
.add(Attributes.FLYING_SPEED, 0.55D);
}
@Override
public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty,
MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData spawnData) {
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.lurkingTerrorHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
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;
@@ -15,6 +15,7 @@ import net.minecraft.world.entity.LivingEntity;
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.AttributeInstance;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.goal.FloatGoal;
import net.minecraft.world.entity.ai.goal.MeleeAttackGoal;
@@ -24,6 +25,7 @@ import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.ai.navigation.GroundPathNavigation;
import net.minecraft.world.entity.ai.navigation.PathNavigation;
import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.entity.SpawnGroupData;
import net.minecraft.world.level.block.LeavesBlock;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
@@ -68,6 +70,7 @@ public class MantisEntity extends Monster implements GeoEntity {
protected int flyBurstTicks;
protected int flyCooldownTicks;
private int debugLogTicks = 0;
private int configSyncTicks;
public MantisEntity(EntityType<? extends MantisEntity> entityType, Level level) {
super(entityType, level);
@@ -89,6 +92,13 @@ public class MantisEntity extends Monster implements GeoEntity {
.add(Attributes.ARMOR, 4.0D);
}
@Override
public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData spawnData) {
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, this.configuredMaxHealth());
this.syncConfiguredAttributes(false);
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
public static boolean canSpawn(EntityType<MantisEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
if (spawnReason == MobSpawnType.SPAWN_EGG
|| spawnReason == MobSpawnType.SPAWNER
@@ -200,6 +210,11 @@ public class MantisEntity extends Monster implements GeoEntity {
public void tick() {
super.tick();
if (!this.level().isClientSide) {
if (this.configSyncTicks-- <= 0) {
this.configSyncTicks = 20;
this.syncConfiguredAttributes(true);
}
if (this.attackAnimationTicks > 0) {
this.attackAnimationTicks--;
}
@@ -278,6 +293,22 @@ public class MantisEntity extends Monster implements GeoEntity {
return COMBAT_SPEED;
}
protected double configuredMaxHealth() {
return AntarchySettings.mantisHealth();
}
protected double configuredAttackDamage() {
return AntarchySettings.mantisAttackDamage();
}
protected double configuredMovementSpeed() {
return AntarchySettings.mantisMovementSpeed();
}
protected double configuredFlyingSpeed() {
return AntarchySettings.mantisFlyingSpeed();
}
protected void onActiveTarget(LivingEntity target) {
}
@@ -349,6 +380,36 @@ public class MantisEntity extends Monster implements GeoEntity {
return this.flyBurstTicks > 0;
}
private void syncConfiguredAttributes(boolean rescaleCurrentHealth) {
syncAttribute(this.getAttribute(Attributes.MAX_HEALTH), this.configuredMaxHealth(), rescaleCurrentHealth);
syncAttribute(this.getAttribute(Attributes.ATTACK_DAMAGE), this.configuredAttackDamage(), false);
syncAttribute(this.getAttribute(Attributes.MOVEMENT_SPEED), this.configuredMovementSpeed(), false);
syncAttribute(this.getAttribute(Attributes.FLYING_SPEED), this.configuredFlyingSpeed(), false);
}
private void syncAttribute(@Nullable AttributeInstance attributeInstance, double desiredValue, boolean rescaleCurrentHealth) {
if (attributeInstance == null) {
return;
}
double previousValue = attributeInstance.getBaseValue();
if (Math.abs(previousValue - desiredValue) < 1.0E-6D) {
return;
}
attributeInstance.setBaseValue(desiredValue);
if (!rescaleCurrentHealth) {
this.setHealth((float) this.getMaxHealth());
return;
}
float currentHealth = this.getHealth();
float syncedHealth = previousValue > 0.0D
? (float) net.minecraft.util.Mth.clamp((currentHealth / (float) previousValue) * desiredValue, 0.0D, desiredValue)
: (float) desiredValue;
this.setHealth(syncedHealth);
}
private void tickDebugLog() {
if (++this.debugLogTicks < 100) {
return;
@@ -109,6 +109,13 @@ public class MissileSquidEntity extends Monster implements GeoEntity {
.add(Attributes.KNOCKBACK_RESISTANCE, AntarchySettings.missileSquidKnockbackResistance());
}
@Override
public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty,
MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData spawnData) {
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.missileSquidHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
public static boolean canSpawn(EntityType<MissileSquidEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
return level.getDifficulty() != Difficulty.PEACEFUL
&& pos.getY() <= level.getSeaLevel() - 10
@@ -59,6 +59,10 @@ public class MolevoreEntity extends Monster implements GeoEntity {
Registries.BIOME,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "moleworm_caves")
);
private static final ResourceKey<Biome> CAVARYN_MOLEWORM_CAVES = ResourceKey.create(
Registries.BIOME,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "cavaryn_moleworm_caves")
);
private static final EntityDataAccessor<Integer> ACTION_STATE = SynchedEntityData.defineId(MolevoreEntity.class, EntityDataSerializers.INT);
private static final int ACTION_NONE = 0;
@@ -122,7 +126,7 @@ public class MolevoreEntity extends Monster implements GeoEntity {
}
private static boolean hasSpawnPocket(LevelAccessor level, BlockPos pos) {
if (!level.getBiome(pos).is(MOLEWORM_CAVES)) {
if (!level.getBiome(pos).is(MOLEWORM_CAVES) && !level.getBiome(pos).is(CAVARYN_MOLEWORM_CAVES)) {
return false;
}
@@ -180,6 +184,7 @@ public class MolevoreEntity extends Monster implements GeoEntity {
@Nullable
public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData spawnGroupData) {
SpawnGroupData finalized = super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData);
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.molevoreHealth());
if (spawnReason != MobSpawnType.SPAWN_EGG) {
this.startDigUp();
}
@@ -80,6 +80,13 @@ public class MolewormEntity extends Monster implements GeoEntity {
.add(Attributes.ATTACK_DAMAGE, AntarchySettings.molewormAttackDamage());
}
@Override
public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty,
MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData spawnData) {
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.molewormHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
@SuppressWarnings("unchecked")
public static boolean canSpawn(EntityType<MolewormEntity> entityType, LevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
return Silverfish.checkSilverfishSpawnRules((EntityType<Silverfish>) (EntityType<?>) entityType, level, spawnReason, pos, random);
@@ -160,6 +160,7 @@ public class OuranwoodDeerEntity extends Animal implements GeoEntity {
public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData spawnGroupData) {
DeerSpawnData deerSpawnData = spawnGroupData instanceof DeerSpawnData data ? data : new DeerSpawnData();
SpawnGroupData result = super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData);
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.ouranwoodDeerHealth());
if (spawnReason == MobSpawnType.NATURAL || spawnReason == MobSpawnType.CHUNK_GENERATION || spawnReason == MobSpawnType.SPAWN_EGG) {
this.setVariant(Variant.values()[this.random.nextInt(Variant.values().length)]);
@@ -204,6 +204,13 @@ public class ReverieEntity extends PathfinderMob implements FlyingAnimal, GeoEnt
.add(Attributes.FOLLOW_RANGE, 32.0D);
}
@Override
public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty,
MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData spawnData) {
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.reverieHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
public static boolean canSpawn(EntityType<ReverieEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
if (spawnReason == MobSpawnType.SPAWN_EGG || spawnReason == MobSpawnType.SPAWNER || spawnReason == MobSpawnType.COMMAND) {
return true;
@@ -120,6 +120,13 @@ public class RollyPollyEntity extends TamableAnimal implements GeoEntity {
.add(Attributes.FOLLOW_RANGE, 16.0D);
}
@Override
public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty,
net.minecraft.world.entity.MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData spawnData) {
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.rollyPollyHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
@@ -44,11 +44,14 @@ import software.bernie.geckolib.animation.RawAnimation;
import software.bernie.geckolib.util.GeckoLibUtil;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
public class ScorpionEntity extends Monster implements GeoEntity {
private static final byte ATTACK_ANIM_EVENT = 4;
private static final EntityDataAccessor<Integer> TEXTURE_VARIANT =
SynchedEntityData.defineId(ScorpionEntity.class, EntityDataSerializers.INT);
private static final String TEXTURE_VARIANT_KEY = "TextureVariant";
private static final String SUMMON_OWNER_KEY = "SummonOwner";
public static final int BLUE_VARIANT = 0;
public static final int GREEN_VARIANT = 1;
@@ -67,6 +70,7 @@ public class ScorpionEntity extends Monster implements GeoEntity {
private int attackCooldownTicks = 0;
private boolean attackDamageApplied = false;
@Nullable private LivingEntity attackTarget;
@Nullable private UUID summonOwner;
public ScorpionEntity(EntityType<? extends ScorpionEntity> entityType, Level level) {
super(entityType, level);
@@ -115,6 +119,7 @@ public class ScorpionEntity extends Monster implements GeoEntity {
@Override
public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, MobSpawnType spawnType, @Nullable SpawnGroupData spawnGroupData) {
this.assignRandomTextureVariant();
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.scorpionHealth());
return super.finalizeSpawn(level, difficulty, spawnType, spawnGroupData);
}
@@ -237,6 +242,9 @@ public class ScorpionEntity extends Monster implements GeoEntity {
public void addAdditionalSaveData(CompoundTag tag) {
super.addAdditionalSaveData(tag);
tag.putInt(TEXTURE_VARIANT_KEY, this.getTextureVariant());
if (this.summonOwner != null) {
tag.putUUID(SUMMON_OWNER_KEY, this.summonOwner);
}
}
@Override
@@ -247,6 +255,7 @@ public class ScorpionEntity extends Monster implements GeoEntity {
} else {
this.assignRandomTextureVariant();
}
this.summonOwner = tag.hasUUID(SUMMON_OWNER_KEY) ? tag.getUUID(SUMMON_OWNER_KEY) : null;
}
@Override
@@ -277,6 +286,19 @@ public class ScorpionEntity extends Monster implements GeoEntity {
this.entityData.set(TEXTURE_VARIANT, variant == GREEN_VARIANT ? GREEN_VARIANT : BLUE_VARIANT);
}
public void setSummonOwner(@Nullable UUID summonOwner) {
this.summonOwner = summonOwner;
}
@Nullable
public UUID getSummonOwner() {
return this.summonOwner;
}
public boolean isSummonedFor(UUID ownerId) {
return ownerId.equals(this.summonOwner);
}
private void assignRandomTextureVariant() {
this.setTextureVariant(this.random.nextBoolean() ? BLUE_VARIANT : GREEN_VARIANT);
}
@@ -153,6 +153,13 @@ public class ToreterrorEntity extends Monster implements GeoEntity {
.add(Attributes.ARMOR_TOUGHNESS, 4.0D);
}
@Override
public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty,
MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData spawnData) {
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.toreterrorHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
public static boolean canSpawn(EntityType<ToreterrorEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, net.minecraft.util.RandomSource random) {
boolean sturdy = level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
return level.getDifficulty() != Difficulty.PEACEFUL && sturdy;
@@ -101,6 +101,13 @@ public class TriffidEntity extends Monster implements GeoEntity {
.add(Attributes.MOVEMENT_SPEED, 0.0D);
}
@Override
public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty,
MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData spawnData) {
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.triffidHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
public static boolean canSpawn(EntityType<TriffidEntity> entityType, LevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
if (pos.getY() < level.getMinBuildHeight() || pos.getY() + 7 >= level.getMaxBuildHeight()) {
return false;
@@ -2,7 +2,6 @@ package com.craisinlord.antarchy.content.entity;
import com.craisinlord.antarchy.content.block.AntimetalScaffoldingBlock;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.network.syncher.EntityDataAccessor;
@@ -14,6 +13,7 @@ import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.PointedDripstoneBlock;
import net.minecraft.world.level.block.state.BlockState;
@@ -32,6 +32,7 @@ public class UpwardFallingBlockEntity extends Entity {
private static final int MAX_TICKS = 200;
public int time = 0;
private boolean breaksOnLeaves = true;
public UpwardFallingBlockEntity(EntityType<UpwardFallingBlockEntity> type, Level level) {
super(type, level);
@@ -48,6 +49,10 @@ public class UpwardFallingBlockEntity extends Entity {
}
public static void fallUp(Level level, BlockPos pos, BlockState state) {
fallUp(level, pos, state, true);
}
public static void fallUp(Level level, BlockPos pos, BlockState state, boolean breaksOnLeaves) {
if (level.isClientSide) return;
// Prevent stacking multiple entities from the same block position
if (!level.getEntitiesOfClass(UpwardFallingBlockEntity.class, new AABB(pos)).isEmpty()) return;
@@ -55,6 +60,7 @@ public class UpwardFallingBlockEntity extends Entity {
level.removeBlock(pos, false);
UpwardFallingBlockEntity entity = new UpwardFallingBlockEntity(TYPE.get(), level);
entity.entityData.set(DATA_BLOCK_STATE, state);
entity.breaksOnLeaves = breaksOnLeaves;
entity.setPos(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5);
level.addFreshEntity(entity);
}
@@ -90,21 +96,35 @@ public class UpwardFallingBlockEntity extends Entity {
BlockPos headPos = BlockPos.containing(getX(), getY() + getBbHeight(), getZ());
BlockState above = level().getBlockState(headPos);
// Leaves block the entity but can't hold scaffolding — drop as item
if (above.is(BlockTags.LEAVES)) {
// Leaves block the entity but can't hold scaffolding — drop as item, unless this
// instance is allowed to land on leaves like a normal falling block would
if (above.is(BlockTags.LEAVES) && this.breaksOnLeaves) {
dropAndRemove(blockState);
return;
}
boolean hitCeiling = above.isFaceSturdy(level(), headPos, Direction.DOWN);
boolean hitCeiling = !above.isAir() && !above.getCollisionShape(level(), headPos).isEmpty();
boolean hitScaffolding = above.getBlock() instanceof AntimetalScaffoldingBlock;
if (hitCeiling || hitScaffolding) {
dropAndRemove(blockState);
placeAtLanding(blockState, headPos.below());
return;
}
}
private void placeAtLanding(BlockState state, BlockPos landingPos) {
if (!level().isClientSide) {
BlockState existing = level().getBlockState(landingPos);
if (existing.canBeReplaced()) {
level().setBlock(landingPos, state, Block.UPDATE_ALL);
} else {
dropAndRemove(state);
return;
}
}
discard();
}
private void damageEntitiesAlongPath(BlockState state) {
float damage = getImpactDamage(state);
if (damage <= 0.0F) {
@@ -125,6 +125,10 @@ public final class AntTeleportHelper {
return InteractionResult.PASS;
}
if (!isRightClickDimensionEnabled(entityTypeId)) {
return InteractionResult.PASS;
}
if (entityTypeId.equals(ResourceLocation.fromNamespaceAndPath("antarchy", "brown_ant"))) {
return teleportToOrFromConfiguredDimension(player, AntarchySettings.brownAntDestinationDimension());
}
@@ -156,6 +160,10 @@ public final class AntTeleportHelper {
}
static InteractionResult handleInteraction(BaseAntEntity ant, Player player, ItemStack itemStack) {
if (!isRightClickDimensionEnabled(ant)) {
return InteractionResult.PASS;
}
if (ant.requiresActivationReagent() && !ant.isTeleportActivatedState()) {
if (!(player instanceof ServerPlayer serverPlayer)) {
return InteractionResult.SUCCESS;
@@ -184,6 +192,32 @@ public final class AntTeleportHelper {
return teleportToOrFromConfiguredDimension(serverPlayer, ant.destinationDimension());
}
static boolean isRightClickDimensionEnabled(BaseAntEntity ant) {
return ant instanceof BrownAntEntity
? AntarchySettings.brownAntRightClickDimension()
: ant instanceof RedAntEntity
? AntarchySettings.redAntRightClickDimension()
: ant instanceof RainbowAntEntity
? AntarchySettings.rainbowAntRightClickDimension()
: ant instanceof TermiteEntity && AntarchySettings.termiteRightClickDimension();
}
static boolean isRightClickDimensionEnabled(ResourceLocation entityTypeId) {
if (entityTypeId.equals(ResourceLocation.fromNamespaceAndPath("antarchy", "brown_ant"))) {
return AntarchySettings.brownAntRightClickDimension();
}
if (entityTypeId.equals(ResourceLocation.fromNamespaceAndPath("antarchy", "red_ant"))) {
return AntarchySettings.redAntRightClickDimension();
}
if (entityTypeId.equals(ResourceLocation.fromNamespaceAndPath("antarchy", "rainbow_ant"))) {
return AntarchySettings.rainbowAntRightClickDimension();
}
if (entityTypeId.equals(ResourceLocation.fromNamespaceAndPath("antarchy", "termite"))) {
return AntarchySettings.termiteRightClickDimension();
}
return true;
}
private static InteractionResult activateTeleport(BaseAntEntity ant, ServerPlayer player, ItemStack stack) {
ant.setTeleportActivatedState(true);
if (!player.getAbilities().instabuild) {
@@ -158,6 +158,13 @@ public abstract class BaseAntEntity extends Animal implements GeoEntity {
super(entityType, level);
}
@Override
public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty,
net.minecraft.world.entity.MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData spawnData) {
com.craisinlord.antarchy.content.entity.ConfiguredMobSpawnUtil.applyConfiguredHealth(this, this.configuredMaxHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
@@ -77,6 +77,11 @@ public class RainbowAntEntity extends BaseAntEntity implements GeoEntity {
@Override
public InteractionResult mobInteract(Player player, InteractionHand hand) {
if (!AntTeleportHelper.isRightClickDimensionEnabled(this)) {
ItemStack heldItem = player.getItemInHand(hand);
return this.isFood(heldItem) ? super.mobInteract(player, hand) : InteractionResult.PASS;
}
if (!AntarchySettings.rainbowAntsLeadToInfinityDimensions() || !InfinityCompat.get().isAvailable()) {
return super.mobInteract(player, hand);
}
@@ -7,6 +7,7 @@ import com.craisinlord.antarchy.content.AntarchyTags;
import com.craisinlord.antarchy.content.damage.AntarchyDamageSources;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.util.Mth;
@@ -63,6 +64,8 @@ public class BasiliskEntity extends Monster implements GeoEntity {
SynchedEntityData.defineId(BasiliskEntity.class, EntityDataSerializers.INT);
private static final byte ATTACK_ENTITY_EVENT = 4;
private static final int DEATH_TICKS = 25;
private static final String TAG_HISS_COOLDOWN = "BasiliskHissCooldown";
private static final String TAG_PREY_PETRIFY_COOLDOWN = "BasiliskPreyPetrifyCooldown";
private static final int ANIM_IDLE = 0;
private static final int ANIM_WALK = 1;
@@ -74,13 +77,15 @@ public class BasiliskEntity extends Monster implements GeoEntity {
private static final RawAnimation ATTACK_ANIM = RawAnimation.begin().thenPlay("attack");
private static final RawAnimation DEATH_ANIM = RawAnimation.begin().thenPlay("death");
private static final float TURN_RATE_DEG_PER_TICK = 10.0F;
private static final float MIN_TURN_RATE_DEG_PER_TICK = 5.5F;
private static final float MAX_TURN_RATE_DEG_PER_TICK = 13.5F;
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
private int attackAnimTicks = 0;
private boolean attackDamagePending = false;
private int attackCooldown = 0;
private float committedAttackYaw = Float.NaN;
private int hissCooldown = AntarchySettings.basiliskHissCooldownTicks();
private int hissChargeTimer = 0;
@@ -110,6 +115,12 @@ public class BasiliskEntity extends Monster implements GeoEntity {
.add(Attributes.FOLLOW_RANGE, AntarchySettings.basiliskFollowRange());
}
@Override
public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData spawnData) {
com.craisinlord.antarchy.content.entity.ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.basiliskHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
public static boolean canSpawn(EntityType<BasiliskEntity> entityType, ServerLevelAccessor level,
MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
if (spawnReason == MobSpawnType.SPAWN_EGG
@@ -160,9 +171,12 @@ public class BasiliskEntity extends Monster implements GeoEntity {
private void performAoeAttack() {
if (this.level().isClientSide) return;
// Start the animation; damage fires later in tick() when attackAnimTicks reaches the damage threshold
this.committedAttackYaw = this.resolveCommittedAttackYaw();
this.attackAnimTicks = AntarchySettings.basiliskAttackAnimTicks();
this.attackDamagePending = true;
this.stopActiveMovement();
this.lockBodyYaw(this.committedAttackYaw);
this.setAnimationState(ANIM_ATTACK);
this.level().broadcastEntityEvent(this, ATTACK_ENTITY_EVENT);
}
@@ -173,33 +187,42 @@ public class BasiliskEntity extends Monster implements GeoEntity {
this.attackDamagePending = false;
Vec3 forward = Vec3.directionFromRotation(0, this.yBodyRot);
float attackYaw = Float.isNaN(this.committedAttackYaw) ? this.yBodyRot : this.committedAttackYaw;
Vec3 forward = Vec3.directionFromRotation(0, attackYaw);
Vec3 right = new Vec3(-forward.z, 0, forward.x);
Vec3 origin = this.position();
double attackReach = AntarchySettings.basiliskAttackReach();
Vec3 attackOrigin = this.position();
double attackReach = AntarchySettings.basiliskAttackReach() + 4.0D;
double verticalMin = attackOrigin.y - 0.9D;
double verticalMax = attackOrigin.y + 2.6D;
List<LivingEntity> candidates = this.level().getEntitiesOfClass(
LivingEntity.class,
this.getBoundingBox().inflate(Math.max(8.0D, attackReach + 3.5D)),
new AABB(attackOrigin, attackOrigin).inflate(attackReach + 1.5D, 3.0D, attackReach + 1.5D),
e -> e != this && e.isAlive()
);
boolean hitAnything = false;
for (LivingEntity entity : candidates) {
Vec3 toEntity = entity.position().subtract(origin);
if (!this.canAttack(entity) || this.isAlliedTo(entity) || !this.hasLineOfSight(entity)) {
continue;
}
AABB entityBox = entity.getBoundingBox();
if (entityBox.maxY < verticalMin || entityBox.minY > verticalMax) {
continue;
}
Vec3 toEntity = entityBox.getCenter().subtract(attackOrigin);
double fwdDist = toEntity.dot(forward);
double sideDist = toEntity.dot(right);
double upDist = toEntity.y;
if (fwdDist >= 2.0 && fwdDist <= 7.0 && Math.abs(sideDist) <= 2.25 && upDist >= -1.0 && upDist <= 3.0) {
if (entity.hurt(AntarchyDamageSources.basiliskBite(serverLevel, this),
(float) this.getAttributeValue(Attributes.ATTACK_DAMAGE))) {
hitAnything = true;
}
double sideAllowance = 1.35D + entity.getBbWidth() * 0.5D + Math.max(0.0D, fwdDist * 0.2D);
if (fwdDist < 1.0D || fwdDist > attackReach || Math.abs(sideDist) > sideAllowance) {
continue;
}
}
if (hitAnything) {
this.playSound(AntarchySoundEvents.BASILISK_BITE.get(), 1.1F, 0.95F + this.random.nextFloat() * 0.08F);
entity.hurt(
AntarchyDamageSources.basiliskBite(serverLevel, this),
(float) this.getAttributeValue(Attributes.ATTACK_DAMAGE)
);
}
}
@@ -210,6 +233,12 @@ public class BasiliskEntity extends Monster implements GeoEntity {
if (this.attackAnimTicks > 0) {
this.attackAnimTicks--;
}
if (this.level() instanceof ServerLevel && this.attackAnimTicks > 0 && !Float.isNaN(this.committedAttackYaw)) {
this.lockBodyYaw(this.committedAttackYaw);
}
if (this.attackAnimTicks <= 0) {
this.committedAttackYaw = Float.NaN;
}
if (this.isDeadOrDying()) {
this.updateAnimationState();
@@ -228,6 +257,10 @@ public class BasiliskEntity extends Monster implements GeoEntity {
}
private void tickPlayerPetrification() {
if (this.isCommittedAttackActive()) {
return;
}
if (this.hissChargeTimer > 0) {
Player target = this.getPendingPlayerTarget();
if (!this.canMaintainGazeOn(target)) {
@@ -236,7 +269,7 @@ public class BasiliskEntity extends Monster implements GeoEntity {
return;
}
this.getNavigation().stop();
this.stopActiveMovement();
this.getLookControl().setLookAt(target, 30.0F, 30.0F);
this.hissChargeTimer--;
if (this.hissChargeTimer == 0) {
@@ -274,7 +307,7 @@ public class BasiliskEntity extends Monster implements GeoEntity {
this.pendingTargetId = target.getUUID();
this.hissChargeTimer = AntarchySettings.basiliskHissChargeTicks();
this.hissCooldown = AntarchySettings.basiliskHissCooldownTicks();
this.getNavigation().stop();
this.stopActiveMovement();
this.getLookControl().setLookAt(target, 30.0F, 30.0F);
}
@@ -284,7 +317,7 @@ public class BasiliskEntity extends Monster implements GeoEntity {
return;
}
if (this.getTarget() != null || this.hissChargeTimer > 0) {
if (this.getTarget() != null || this.hissChargeTimer > 0 || this.isCommittedAttackActive()) {
return;
}
@@ -447,17 +480,34 @@ public class BasiliskEntity extends Monster implements GeoEntity {
public void die(DamageSource damageSource) {
if (!this.level().isClientSide) {
this.setAnimationState(ANIM_DEATH);
this.attackAnimTicks = 0;
this.attackDamagePending = false;
this.attackCooldown = 0;
this.hissChargeTimer = 0;
this.pendingTargetId = null;
this.getNavigation().stop();
this.resetTransientCombatState();
this.hissCooldown = AntarchySettings.basiliskHissCooldownTicks();
this.preyPetrifyCooldown = AntarchySettings.basiliskPreyPetrifyCooldownTicks();
this.setDeltaMovement(Vec3.ZERO);
}
super.die(damageSource);
}
@Override
public void addAdditionalSaveData(CompoundTag tag) {
super.addAdditionalSaveData(tag);
tag.putInt(TAG_HISS_COOLDOWN, this.hissCooldown);
tag.putInt(TAG_PREY_PETRIFY_COOLDOWN, this.preyPetrifyCooldown);
}
@Override
public void readAdditionalSaveData(CompoundTag tag) {
super.readAdditionalSaveData(tag);
this.hissCooldown = tag.contains(TAG_HISS_COOLDOWN)
? Math.max(0, tag.getInt(TAG_HISS_COOLDOWN))
: AntarchySettings.basiliskHissCooldownTicks();
this.preyPetrifyCooldown = tag.contains(TAG_PREY_PETRIFY_COOLDOWN)
? Math.max(0, tag.getInt(TAG_PREY_PETRIFY_COOLDOWN))
: AntarchySettings.basiliskPreyPetrifyCooldownTicks();
this.resetTransientCombatState();
this.setAnimationState(ANIM_IDLE);
}
@Override
protected void tickDeath() {
this.deathTime++;
@@ -555,7 +605,54 @@ public class BasiliskEntity extends Monster implements GeoEntity {
return 0.7F;
}
/** Limits body rotation to TURN_RATE_DEG_PER_TICK so the long snake turns gradually. */
private boolean isCommittedAttackActive() {
return this.attackAnimTicks > 0;
}
private boolean isBusyWithAction() {
return this.hissChargeTimer > 0 || this.isCommittedAttackActive();
}
private float resolveCommittedAttackYaw() {
LivingEntity target = this.getTarget();
if (target != null) {
Vec3 toTarget = target.position().subtract(this.position());
if (toTarget.horizontalDistanceSqr() > 1.0E-6D) {
return (float)(Mth.atan2(toTarget.z, toTarget.x) * (180.0D / Math.PI)) - 90.0F;
}
}
return this.yBodyRot;
}
private void lockBodyYaw(float yaw) {
this.setYRot(yaw);
this.yRotO = yaw;
this.yBodyRot = yaw;
this.yBodyRotO = yaw;
this.yHeadRot = yaw;
this.yHeadRotO = yaw;
}
private void stopActiveMovement() {
this.getNavigation().stop();
if (this.getMoveControl() instanceof BasiliskMoveControl moveControl) {
moveControl.halt();
}
this.setSpeed(0.0F);
this.setZza(0.0F);
}
private void resetTransientCombatState() {
this.attackAnimTicks = 0;
this.attackDamagePending = false;
this.attackCooldown = 0;
this.committedAttackYaw = Float.NaN;
this.hissChargeTimer = 0;
this.pendingTargetId = null;
this.stopActiveMovement();
}
/** Scales turn rate by intended movement speed so the long body pivots tighter when slow and wider when fast. */
private static final class BasiliskMoveControl extends MoveControl {
private BasiliskMoveControl(Mob mob) {
super(mob);
@@ -568,6 +665,10 @@ public class BasiliskEntity extends Monster implements GeoEntity {
@Override
public void tick() {
if (((BasiliskEntity) this.mob).isBusyWithAction()) {
this.mob.setZza(0.0F);
return;
}
if (this.operation == MoveControl.Operation.MOVE_TO) {
this.operation = MoveControl.Operation.WAIT;
double dx = this.wantedX - this.mob.getX();
@@ -577,12 +678,20 @@ public class BasiliskEntity extends Monster implements GeoEntity {
this.mob.setZza(0.0F);
return;
}
float turnRate = this.getDynamicTurnRate();
float targetYaw = (float)(Mth.atan2(dz, dx) * (180.0 / Math.PI)) - 90.0F;
this.mob.setYRot(this.rotlerp(this.mob.getYRot(), targetYaw, TURN_RATE_DEG_PER_TICK));
this.mob.setYRot(this.rotlerp(this.mob.getYRot(), targetYaw, turnRate));
this.mob.setSpeed((float)(this.speedModifier * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED)));
this.mob.setZza(1.0F);
}
}
private float getDynamicTurnRate() {
double baseSpeed = Math.max(0.01D, this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED));
double intendedSpeed = Math.max(0.0D, this.speedModifier * baseSpeed);
double normalizedSpeed = Mth.clamp(intendedSpeed / (baseSpeed * 1.2D), 0.0D, 1.0D);
return Mth.lerp((float) normalizedSpeed, MAX_TURN_RATE_DEG_PER_TICK, MIN_TURN_RATE_DEG_PER_TICK);
}
}
private final class PersistentNearestAttackableTargetGoal<T extends LivingEntity> extends NearestAttackableTargetGoal<T> {
@@ -599,6 +708,11 @@ public class BasiliskEntity extends Monster implements GeoEntity {
@Override
public void tick() {
if (BasiliskEntity.this.hissChargeTimer > 0 || BasiliskEntity.this.attackAnimTicks > 0) {
this.stopMovement();
return;
}
LivingEntity target = BasiliskEntity.this.getTarget();
if (target != null) {
BasiliskEntity.this.getLookControl().setLookAt(target, 30.0F, 30.0F);
@@ -607,11 +721,6 @@ public class BasiliskEntity extends Monster implements GeoEntity {
// super handles path recalc and cooldown timer
super.tick();
if (BasiliskEntity.this.hissChargeTimer > 0 || BasiliskEntity.this.attackAnimTicks > 0) {
this.stopMovement();
return;
}
if (target != null && BasiliskEntity.this.isWithinMeleeAttackRange(target)) {
this.stopMovement();
this.checkAndPerformAttack(target);
@@ -619,14 +728,14 @@ public class BasiliskEntity extends Monster implements GeoEntity {
}
private void stopMovement() {
BasiliskEntity.this.getNavigation().stop();
((BasiliskMoveControl) BasiliskEntity.this.getMoveControl()).halt();
BasiliskEntity.this.setSpeed(0.0F);
BasiliskEntity.this.setZza(0.0F);
BasiliskEntity.this.stopActiveMovement();
}
@Override
public boolean canUse() {
if (BasiliskEntity.this.isBusyWithAction()) {
return false;
}
LivingEntity target = BasiliskEntity.this.getTarget();
if (target == null || !target.isAlive()) return false;
if (target instanceof Player p && (p.isCreative() || p.isSpectator())) return false;
@@ -636,7 +745,7 @@ public class BasiliskEntity extends Monster implements GeoEntity {
@Override
public void start() {
LivingEntity target = BasiliskEntity.this.getTarget();
if (target != null) {
if (target != null && !BasiliskEntity.this.isBusyWithAction()) {
BasiliskEntity.this.getNavigation().moveTo(target, 1.2D);
}
BasiliskEntity.this.setAggressive(true);
@@ -644,7 +753,14 @@ public class BasiliskEntity extends Monster implements GeoEntity {
@Override
public boolean canContinueToUse() {
return BasiliskEntity.this.attackAnimTicks > 0 || super.canContinueToUse();
return BasiliskEntity.this.isBusyWithAction() || super.canContinueToUse();
}
@Override
public void stop() {
super.stop();
BasiliskEntity.this.setAggressive(false);
this.stopMovement();
}
@Override
@@ -111,6 +111,12 @@ public class CloudSharkEntity extends Monster implements GeoEntity {
.add(Attributes.KNOCKBACK_RESISTANCE, AntarchySettings.cloudSharkKnockbackResistance());
}
@Override
public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(net.minecraft.world.level.ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty, net.minecraft.world.entity.MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData spawnData) {
com.craisinlord.antarchy.content.entity.ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.cloudSharkHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
public static boolean canSpawn(EntityType<CloudSharkEntity> entityType, ServerLevelAccessor level,
MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
return level.getDifficulty() != Difficulty.PEACEFUL
@@ -6,6 +6,7 @@ import com.craisinlord.antarchy.content.AntarchyTags;
import com.craisinlord.antarchy.content.AntarchySoundEvents;
import com.craisinlord.antarchy.content.block.OuranwoodAcornBlock;
import com.craisinlord.antarchy.content.block.OuranwoodLeavesBlock;
import com.mojang.logging.LogUtils;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ItemParticleOption;
@@ -54,12 +55,14 @@ import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.animation.*;
import software.bernie.geckolib.animation.AnimationState;
import software.bernie.geckolib.util.GeckoLibUtil;
import org.slf4j.Logger;
import java.util.EnumSet;
import java.util.Optional;
import java.util.UUID;
public class FlyingSquirrelEntity extends TamableAnimal implements GeoEntity {
private static final Logger LOGGER = LogUtils.getLogger();
private static final ResourceKey<Level> ELYTHIA_DIMENSION = ResourceKey.create(
Registries.DIMENSION,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "elythia")
@@ -81,6 +84,8 @@ public class FlyingSquirrelEntity extends TamableAnimal implements GeoEntity {
SynchedEntityData.defineId(FlyingSquirrelEntity.class, EntityDataSerializers.OPTIONAL_UUID);
private static final String PICKUP_ANIM_TICKS_KEY = "PickupAnimTicks";
private static final String QUIRK_TICKS_KEY = "QuirkTicks";
private static final String QUIRK_VARIANT_KEY = "QuirkVariant";
private static final String TEXTURE_VARIANT_KEY = "TextureVariant";
private static final String GLIDE_DIR_X_KEY = "GlideDirX";
private static final String GLIDE_DIR_Y_KEY = "GlideDirY";
@@ -129,6 +134,9 @@ public class FlyingSquirrelEntity extends TamableAnimal implements GeoEntity {
private static final RawAnimation CLIMB_ANIM = RawAnimation.begin().thenLoop("climbing");
private static final RawAnimation GLIDE_ANIM = RawAnimation.begin().thenLoop("gliding");
private static final RawAnimation PICKUP_ANIM = RawAnimation.begin().thenPlay("item_pickup");
private static final String QUIRK_CONTROLLER = "quirk_controller";
private static final String QUIRK_1_TRIGGER = "quirk1";
private static final String QUIRK_2_TRIGGER = "quirk2";
private static final RawAnimation QUIRK_1_ANIM = RawAnimation.begin().thenPlay("quirk1");
private static final RawAnimation QUIRK_2_ANIM = RawAnimation.begin().thenPlay("quirk2");
@@ -178,11 +186,13 @@ public class FlyingSquirrelEntity extends TamableAnimal implements GeoEntity {
private ItemEntity cachedNutItem;
@Nullable
private BlockPos cachedHarvestableAcorn;
private int quirkCooldownTicks = MIN_QUIRK_COOLDOWN_TICKS;
private int quirkCooldownTicks;
private int lastTriggeredQuirkVariant = QUIRK_NONE;
public FlyingSquirrelEntity(EntityType<? extends FlyingSquirrelEntity> entityType, Level level) {
super(entityType, level);
this.setPathfindingMalus(PathType.LEAVES, -2.0F);
this.quirkCooldownTicks = this.nextQuirkCooldown();
}
@Override
@@ -253,9 +263,16 @@ public class FlyingSquirrelEntity extends TamableAnimal implements GeoEntity {
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
controllers.add(new AnimationController<>(this, "main_controller", 5, this::mainAnimController));
controllers.add(new AnimationController<>(this, QUIRK_CONTROLLER, 0, state -> PlayState.STOP)
.triggerableAnim(QUIRK_1_TRIGGER, QUIRK_1_ANIM)
.triggerableAnim(QUIRK_2_TRIGGER, QUIRK_2_ANIM));
}
private PlayState mainAnimController(AnimationState<FlyingSquirrelEntity> state) {
if (this.hasActiveQuirkAnimation()) {
return PlayState.STOP;
}
if (this.isPickingUpNut()) {
return state.setAndContinue(PICKUP_ANIM);
}
@@ -273,11 +290,6 @@ public class FlyingSquirrelEntity extends TamableAnimal implements GeoEntity {
return state.setAndContinue(CLIMB_ANIM);
}
if (this.getQuirkTicks() > 0) {
state.getController().setAnimationSpeed(1.0D);
return state.setAndContinue(this.getQuirkVariant() == QUIRK_2 ? QUIRK_2_ANIM : QUIRK_1_ANIM);
}
Vec3 motion = this.getDeltaMovement();
double horizontalSpeed = motion.horizontalDistanceSqr();
if (!this.isGliding() && !this.isClimbingTrunk() && motion.horizontalDistanceSqr() > 1.0E-4D) {
@@ -303,6 +315,8 @@ public class FlyingSquirrelEntity extends TamableAnimal implements GeoEntity {
public void addAdditionalSaveData(CompoundTag tag) {
super.addAdditionalSaveData(tag);
tag.putInt(PICKUP_ANIM_TICKS_KEY, this.pickupAnimTicks);
tag.putInt(QUIRK_TICKS_KEY, this.getQuirkTicks());
tag.putInt(QUIRK_VARIANT_KEY, this.getQuirkVariant());
tag.putInt(TEXTURE_VARIANT_KEY, this.getTextureVariant());
if (this.glideDirection != null) {
tag.putDouble(GLIDE_DIR_X_KEY, this.glideDirection.x);
@@ -316,6 +330,8 @@ public class FlyingSquirrelEntity extends TamableAnimal implements GeoEntity {
super.readAdditionalSaveData(tag);
this.pickupAnimTicks = Math.max(0, tag.getInt(PICKUP_ANIM_TICKS_KEY));
this.setPickingUpNut(this.pickupAnimTicks > 0);
this.setQuirkTicks(Math.max(0, tag.getInt(QUIRK_TICKS_KEY)));
this.setQuirkVariant(tag.contains(QUIRK_VARIANT_KEY) ? tag.getInt(QUIRK_VARIANT_KEY) : QUIRK_NONE);
if (tag.contains(TEXTURE_VARIANT_KEY)) {
this.setTextureVariant(tag.getInt(TEXTURE_VARIANT_KEY));
} else {
@@ -388,6 +404,7 @@ public class FlyingSquirrelEntity extends TamableAnimal implements GeoEntity {
if (!this.level().isClientSide) {
this.tickPickupAnimation();
this.tickQuirkAnimation();
this.syncQuirkAnimationTrigger();
if (this.isClimbingToShoulder()) {
Player shoulderPlayer = this.shoulderPlayerId != null
@@ -467,6 +484,9 @@ public class FlyingSquirrelEntity extends TamableAnimal implements GeoEntity {
this.tickIdleStallLogging(horizontalSpeed);
}
if (this.level().isClientSide) {
this.syncQuirkAnimationTrigger();
}
if (this.isOnShoulder() && this.level().isClientSide) {
Player shoulderPlayer = this.getShoulderPlayer();
if (shoulderPlayer != null) {
@@ -647,6 +667,7 @@ public class FlyingSquirrelEntity extends TamableAnimal implements GeoEntity {
@Nullable
public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData spawnGroupData) {
SpawnGroupData finalized = super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData);
com.craisinlord.antarchy.content.entity.ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.flyingSquirrelHealth());
this.assignRandomTextureVariant();
this.stopGliding("spawn_initialized");
this.wanderCooldown = 40 + this.random.nextInt(60);
@@ -791,14 +812,38 @@ public class FlyingSquirrelEntity extends TamableAnimal implements GeoEntity {
int variant = this.random.nextBoolean() ? QUIRK_1 : QUIRK_2;
this.setQuirkVariant(variant);
this.setQuirkTicks(variant == QUIRK_1 ? QUIRK_1_DURATION_TICKS : QUIRK_2_DURATION_TICKS);
LOGGER.info("FlyingSquirrel animation selected={} tick={}", variant == QUIRK_2 ? QUIRK_2_TRIGGER : QUIRK_1_TRIGGER, this.tickCount);
this.quirkCooldownTicks = this.nextQuirkCooldown();
}
private void stopQuirkAnimation() {
if (this.getQuirkVariant() != QUIRK_NONE || this.getQuirkTicks() > 0) {
LOGGER.info("FlyingSquirrel animation state cleared variant={} tick={}", this.getQuirkVariant(), this.tickCount);
}
this.setQuirkTicks(0);
this.setQuirkVariant(QUIRK_NONE);
}
private void syncQuirkAnimationTrigger() {
int quirkVariant = this.getQuirkVariant();
if (quirkVariant != QUIRK_NONE && this.getQuirkTicks() > 0 && this.lastTriggeredQuirkVariant != quirkVariant) {
String triggerName = quirkVariant == QUIRK_2 ? QUIRK_2_TRIGGER : QUIRK_1_TRIGGER;
if (!this.level().isClientSide) {
LOGGER.info("FlyingSquirrel triggerAnim called={} tick={}", triggerName, this.tickCount);
}
this.triggerAnim(QUIRK_CONTROLLER, triggerName);
this.lastTriggeredQuirkVariant = quirkVariant;
return;
}
if (quirkVariant == QUIRK_NONE) {
this.lastTriggeredQuirkVariant = QUIRK_NONE;
}
}
private boolean hasActiveQuirkAnimation() {
return this.getQuirkVariant() != QUIRK_NONE && this.getQuirkTicks() > 0;
}
private int nextQuirkCooldown() {
return MIN_QUIRK_COOLDOWN_TICKS + this.random.nextInt(MAX_QUIRK_COOLDOWN_TICKS - MIN_QUIRK_COOLDOWN_TICKS + 1);
}
@@ -4,6 +4,7 @@ import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.advancement.AntarchyAdvancements;
import com.craisinlord.antarchy.content.client.particle.GlimmerParticles;
import com.craisinlord.antarchy.content.entity.ConfiguredMobSpawnUtil;
import com.craisinlord.antarchy.Antarchy;
import net.minecraft.network.chat.Component;
import net.minecraft.nbt.CompoundTag;
@@ -133,6 +134,7 @@ public class GlimmerEntity extends TamableAnimal implements GeoEntity {
public static AttributeSupplier.Builder createAttributes() {
return TamableAnimal.createMobAttributes()
.add(Attributes.MAX_HEALTH, AntarchySettings.glimmerHealth())
.add(Attributes.ATTACK_DAMAGE, 1.0D)
.add(Attributes.MOVEMENT_SPEED, 0.3D)
.add(Attributes.FOLLOW_RANGE, 24.0D);
}
@@ -443,7 +445,8 @@ public class GlimmerEntity extends TamableAnimal implements GeoEntity {
return InteractionResult.CONSUME;
}
ItemStack filled = com.craisinlord.antarchy.content.item.GlimmerBottleItem.create(this.getVariant(), this.entityData.get(ABILITY_COOLDOWN));
ItemStack filled = com.craisinlord.antarchy.content.item.GlimmerBottleItem.create(
this.getVariant(), this.entityData.get(ABILITY_COOLDOWN), this.entityData.get(SHEAR_COOLDOWN));
ItemStack result = net.minecraft.world.item.ItemUtils.createFilledResult(stack, player, filled);
player.setItemInHand(hand, result);
this.playSound(net.minecraft.sounds.SoundEvents.BOTTLE_FILL, 1.0F, 1.0F);
@@ -460,6 +463,7 @@ public class GlimmerEntity extends TamableAnimal implements GeoEntity {
@Nullable
public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData spawnGroupData) {
SpawnGroupData result = super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData);
com.craisinlord.antarchy.content.entity.ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.glimmerHealth());
if (!this.variantLocked) {
this.setVariant(selectNaturalVariant(level, this.blockPosition()));
this.variantLocked = true;
@@ -31,6 +31,7 @@ import java.util.UUID;
public class TentacleEntity extends Mob implements GeoEntity {
private static final RawAnimation GRASP_ANIM = RawAnimation.begin().thenLoop("animation");
private static final float SPAWN_SOUND_VOLUME = 0.35F;
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
private int lifetimeTicks;
@@ -82,7 +83,7 @@ public class TentacleEntity extends Mob implements GeoEntity {
tentacle.ownerId = owner.getUUID();
}
level.addFreshEntity(tentacle);
level.playSound(null, pos.x, pos.y, pos.z, AntarchySoundEvents.KRAKEN_ATTACK.get(), SoundSource.HOSTILE, 1.0F, 1.0F);
level.playSound(null, pos.x, pos.y, pos.z, AntarchySoundEvents.KRAKEN_ATTACK.get(), SoundSource.HOSTILE, SPAWN_SOUND_VOLUME, 1.0F);
}
@Override
@@ -104,6 +104,13 @@ public class LucidEntity extends Monster implements GeoEntity {
.add(Attributes.KNOCKBACK_RESISTANCE, AntarchySettings.lucidKnockbackResistance());
}
@Override
public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty,
MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData spawnData) {
com.craisinlord.antarchy.content.entity.ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.lucidHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
public static boolean canSpawn(EntityType<LucidEntity> entityType, ServerLevelAccessor level,
MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
return level.getDifficulty() != Difficulty.PEACEFUL
@@ -552,4 +559,3 @@ public class LucidEntity extends Monster implements GeoEntity {
@@ -0,0 +1,123 @@
package com.craisinlord.antarchy.content.entity.nightmare;
import com.craisinlord.antarchy.content.AntarchyObjects;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import software.bernie.geckolib.animatable.GeoEntity;
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.animation.AnimatableManager;
import software.bernie.geckolib.animation.AnimationController;
import software.bernie.geckolib.animation.AnimationState;
import software.bernie.geckolib.animation.PlayState;
import software.bernie.geckolib.animation.RawAnimation;
import software.bernie.geckolib.util.GeckoLibUtil;
public class NightmareBiteEntity extends Entity implements GeoEntity {
private static final EntityDataAccessor<Boolean> PHASE_TWO = SynchedEntityData.defineId(NightmareBiteEntity.class, EntityDataSerializers.BOOLEAN);
private static final RawAnimation BITE_ANIM = RawAnimation.begin().thenPlay("bite");
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
private int ageTicks;
public NightmareBiteEntity(EntityType<? extends NightmareBiteEntity> entityType, Level level) {
super(entityType, level);
this.setInvulnerable(true);
this.noPhysics = true;
this.noCulling = true;
}
public static NightmareBiteEntity spawnAt(ServerLevel level, Vec3 pos, float yaw, boolean phaseTwo) {
NightmareBiteEntity bite = new NightmareBiteEntity(AntarchyObjects.NIGHTMARE_BITE.get(), level);
bite.moveTo(pos.x, pos.y, pos.z, yaw, 0.0F);
bite.setPhaseTwo(phaseTwo);
level.addFreshEntity(bite);
return bite;
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
builder.define(PHASE_TWO, false);
}
@Override
public boolean isInvulnerableTo(DamageSource damageSource) {
return true;
}
@Override
public boolean fireImmune() {
return true;
}
@Override
public void lavaHurt() {
}
@Override
public boolean isPushable() {
return false;
}
@Override
public boolean canBeCollidedWith() {
return false;
}
@Override
public boolean isPickable() {
return false;
}
public boolean isPhaseTwo() {
return this.entityData.get(PHASE_TWO);
}
private void setPhaseTwo(boolean phaseTwo) {
this.getEntityData().set(PHASE_TWO, phaseTwo);
}
@Override
public void tick() {
super.tick();
if (this.level().isClientSide) {
return;
}
if (++this.ageTicks >= 12) {
this.discard();
}
}
@Override
public void addAdditionalSaveData(CompoundTag tag) {
tag.putBoolean("PhaseTwo", this.isPhaseTwo());
tag.putInt("AgeTicks", this.ageTicks);
}
@Override
public void readAdditionalSaveData(CompoundTag tag) {
this.setPhaseTwo(tag.getBoolean("PhaseTwo"));
this.ageTicks = tag.getInt("AgeTicks");
}
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
controllers.add(new AnimationController<>(this, "bite_controller", 0, this::biteController));
}
private PlayState biteController(AnimationState<NightmareBiteEntity> state) {
return state.setAndContinue(BITE_ANIM);
}
@Override
public AnimatableInstanceCache getAnimatableInstanceCache() {
return this.geoCache;
}
}
@@ -5,7 +5,7 @@ import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.AntarchySoundEvents;
import com.craisinlord.antarchy.content.AntarchyTags;
import com.craisinlord.antarchy.content.damage.AntarchyDamageSources;
import com.mojang.logging.LogUtils;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes;
@@ -22,6 +22,7 @@ import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
@@ -53,14 +54,19 @@ import software.bernie.geckolib.animation.AnimationState;
import software.bernie.geckolib.animation.PlayState;
import software.bernie.geckolib.animation.RawAnimation;
import software.bernie.geckolib.util.GeckoLibUtil;
import org.slf4j.Logger;
import java.util.EnumSet;
import java.util.List;
public class NightmareEntity extends Monster implements GeoEntity {
private static final Logger LOGGER = LogUtils.getLogger();
private static final EntityDataAccessor<Integer> ANIMATION_STATE = SynchedEntityData.defineId(NightmareEntity.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Integer> ACTIVE_SPECIAL_ANIMATION = SynchedEntityData.defineId(NightmareEntity.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Boolean> ROARING = SynchedEntityData.defineId(NightmareEntity.class, EntityDataSerializers.BOOLEAN);
private static final EntityDataAccessor<Boolean> PHASE_TWO = SynchedEntityData.defineId(NightmareEntity.class, EntityDataSerializers.BOOLEAN);
private static final EntityDataAccessor<Boolean> PHASE_TWO_TEXTURE = SynchedEntityData.defineId(NightmareEntity.class, EntityDataSerializers.BOOLEAN);
private static final EntityDataAccessor<Boolean> PHASE_TRANSITIONING = SynchedEntityData.defineId(NightmareEntity.class, EntityDataSerializers.BOOLEAN);
private static final String ATTACK_COOLDOWN_KEY = "AttackCooldown";
private static final String ATTACK_ANIMATION_TICKS_KEY = "AttackAnimationTicks";
@@ -70,13 +76,33 @@ public class NightmareEntity extends Monster implements GeoEntity {
private static final String INTRO_ROAR_USED_KEY = "IntroRoarUsed";
private static final String TARGETLESS_TICKS_KEY = "TargetlessTicks";
private static final String ANIMATION_STATE_KEY = "AnimationState";
private static final String ACTIVE_SPECIAL_ANIMATION_KEY = "ActiveSpecialAnimation";
private static final String PHASE_TWO_KEY = "PhaseTwo";
private static final String PHASE_TWO_TEXTURE_KEY = "PhaseTwoTexture";
private static final String PHASE_TRANSITIONING_KEY = "PhaseTransitioning";
private static final String PHASE_TRANSITION_TICKS_KEY = "PhaseTransitionTicks";
private static final String PORTAL_COOLDOWN_KEY = "PortalCooldown";
private static final String PORTAL_ATTACK_TICKS_KEY = "PortalAttackTicks";
private static final String PORTAL_ATTACK_HIT_KEY = "PortalAttackHitApplied";
private static final String PORTAL_TRAVEL_TICKS_KEY = "PortalTravelTicks";
private static final String PORTAL_ENTRY_ID_KEY = "PortalEntryId";
private static final String PORTAL_EXIT_ID_KEY = "PortalExitId";
private static final String PORTAL_EXIT_X_KEY = "PortalExitX";
private static final String PORTAL_EXIT_Y_KEY = "PortalExitY";
private static final String PORTAL_EXIT_Z_KEY = "PortalExitZ";
private static final int ANIM_IDLE = 0;
private static final int ANIM_WALK = 1;
private static final int ANIM_FLY = 2;
private static final int ANIM_ATTACK = 3;
private static final int ANIM_FLY_ATTACK = 4;
private static final int ANIM_ROAR = 5;
private static final int SPECIAL_NONE = 0;
private static final int SPECIAL_ATTACK = 1;
private static final int SPECIAL_ATTACK_P2 = 2;
private static final int SPECIAL_FLY_ATTACK = 3;
private static final int SPECIAL_FLY_ATTACK_P2 = 4;
private static final int SPECIAL_ROAR = 5;
private static final int SPECIAL_ROAR_P2 = 6;
private static final int SPECIAL_PHASE_TWO = 7;
private static final int SPECIAL_PORTAL = 8;
private static final int ATTACK_TOTAL_TICKS = 20;
private static final int ATTACK_DAMAGE_TICK = 10;
private static final int INTRO_ROAR_TICKS = 30;
@@ -88,6 +114,13 @@ public class NightmareEntity extends Monster implements GeoEntity {
private static final int WEAKNESS_TICKS = 100;
private static final int BLOCK_BREAK_TICKS = 10;
private static final int FLIGHT_CEILING_CLEARANCE_BLOCKS = 4;
private static final int PHASE_TWO_TRANSITION_TICKS = 80;
private static final int PHASE_TWO_TEXTURE_SWAP_TICKS = 53;
private static final int PORTAL_TOTAL_TICKS = 28;
private static final int PORTAL_TELEPORT_TICK = 12;
private static final int PORTAL_DAMAGE_TICK = 18;
private static final int PORTAL_TRAVEL_INVULNERABLE_TICKS = 8;
private static final int PORTAL_LIFETIME_TICKS = 60;
private static final double PATROL_SPEED = 0.34D;
private static final double COMBAT_FLIGHT_SPEED = 0.725D;
@@ -95,16 +128,47 @@ public class NightmareEntity extends Monster implements GeoEntity {
private static final double ATTACK_START_RANGE_SQR = 42.25D;
private static final double ATTACK_REACH_RADIUS = 2.65D;
private static final double ATTACK_COMMIT_HORIZONTAL_RANGE = 4.2D;
private static final double FLIGHT_ENGAGE_RANGE_SQR = 100.0D;
private static final double FLIGHT_DISENGAGE_RANGE_SQR = 36.0D;
private static final double ATTACK_COMMIT_HORIZONTAL_RANGE_SQR = ATTACK_COMMIT_HORIZONTAL_RANGE * ATTACK_COMMIT_HORIZONTAL_RANGE;
private static final double FLIGHT_ENGAGE_RANGE_SQR = 42.25D;
private static final double FLIGHT_DISENGAGE_RANGE_SQR = 20.25D;
private static final double FLIGHT_ATTACK_RANGE_SQR = 49.0D;
private static final double ROAR_RETRY_DISTANCE_SQR = 400.0D;
private static final double PHASE_TWO_HEALTH_FRACTION = 0.5D;
private static final double PORTAL_RANGE = 32.0D;
private static final double PORTAL_MIN_RANGE_SQR = 49.0D;
private static final double PORTAL_EXIT_OFFSET = 2.35D;
private static final double PORTAL_TRANSPORT_RADIUS = 1.25D;
private static final double FLYING_APPROACH_STRAFE_OFFSET = 2.1D;
private static final double FLYING_APPROACH_HEIGHT = 0.45D;
private static final double FLYING_APPROACH_HEIGHT_PHASE_TWO = 0.8D;
private static final double FLYING_APPROACH_TOO_CLOSE_RANGE_SQR = 9.0D;
private static final double ANIMATION_MOVEMENT_THRESHOLD_SQR = 0.01D;
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
private static final RawAnimation WALK_ANIM = RawAnimation.begin().thenLoop("walk");
private static final RawAnimation FLY_ANIM = RawAnimation.begin().thenLoop("fly");
private static final RawAnimation ATTACK_ANIM = RawAnimation.begin().thenPlay("attack").thenLoop("idle");
private static final RawAnimation FLY_ATTACK_ANIM = RawAnimation.begin().thenPlay("attack2").thenLoop("fly");
private static final RawAnimation ROAR_ANIM = RawAnimation.begin().thenPlay("roar").thenLoop("idle");
private static final RawAnimation PHASE_TWO_IDLE_ANIM = RawAnimation.begin().thenLoop("idle_P2");
private static final RawAnimation PHASE_TWO_WALK_ANIM = RawAnimation.begin().thenLoop("walk_P2");
private static final RawAnimation PHASE_TWO_FLY_ANIM = RawAnimation.begin().thenLoop("fly_P2");
private static final String LOCOMOTION_CONTROLLER = "main_controller";
private static final String SPECIAL_CONTROLLER = "special_controller";
private static final String SPECIAL_ATTACK_TRIGGER = "attack";
private static final String SPECIAL_ATTACK_P2_TRIGGER = "attack_P2";
private static final String SPECIAL_FLY_ATTACK_TRIGGER = "attack2";
private static final String SPECIAL_FLY_ATTACK_P2_TRIGGER = "attack2_P2";
private static final String SPECIAL_ROAR_TRIGGER = "roar";
private static final String SPECIAL_ROAR_P2_TRIGGER = "roar_P2";
private static final String SPECIAL_PHASE_TWO_TRIGGER = "phase2";
private static final String SPECIAL_PORTAL_TRIGGER = "portal_out";
private static final RawAnimation ATTACK_ANIM = RawAnimation.begin().thenPlayAndHold("attack");
private static final RawAnimation ATTACK_P2_ANIM = RawAnimation.begin().thenPlayAndHold("attack_P2");
private static final RawAnimation FLY_ATTACK_ANIM = RawAnimation.begin().thenPlayAndHold("attack2");
private static final RawAnimation FLY_ATTACK_P2_ANIM = RawAnimation.begin().thenPlayAndHold("attack2_P2");
private static final RawAnimation ROAR_ANIM = RawAnimation.begin().thenPlayAndHold("roar");
private static final RawAnimation ROAR_P2_ANIM = RawAnimation.begin().thenPlayAndHold("roar_P2");
private static final RawAnimation PHASE_TWO_TRANSITION_ANIM = RawAnimation.begin().thenPlayAndHold("phase2");
private static final RawAnimation PORTAL_ATTACK_ANIM = RawAnimation.begin().thenPlayAndHold("portal_out");
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
private int attackCooldown;
@@ -117,9 +181,20 @@ public class NightmareEntity extends Monster implements GeoEntity {
private int groundMoveTicks;
private int wingFlapCooldown;
private int blockBreakCooldown;
private int phaseTransitionTicks;
private int portalCooldown;
private int portalAttackTicks;
private int portalTravelTicks;
private boolean attackHitApplied;
private boolean introRoarUsed;
private boolean flyingToTarget;
private boolean portalAttackHitApplied;
private int lastTriggeredSpecialAnimation = SPECIAL_NONE;
private Vec3 portalExitPos;
@Nullable
private NightmarePortalEntity entryPortal;
@Nullable
private NightmarePortalEntity exitPortal;
public NightmareEntity(EntityType<? extends NightmareEntity> entityType, Level level) {
super(entityType, level);
@@ -138,6 +213,13 @@ public class NightmareEntity extends Monster implements GeoEntity {
.add(Attributes.ARMOR, 8.0D);
}
@Override
public net.minecraft.world.entity.SpawnGroupData finalizeSpawn(ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty,
MobSpawnType spawnReason, net.minecraft.world.entity.SpawnGroupData spawnData) {
com.craisinlord.antarchy.content.entity.ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.nightmareHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
public static boolean canSpawn(EntityType<NightmareEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
boolean sturdy = level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
boolean posEmpty = level.isEmptyBlock(pos);
@@ -149,17 +231,23 @@ public class NightmareEntity extends Monster implements GeoEntity {
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
builder.define(ANIMATION_STATE, ANIM_IDLE);
builder.define(ACTIVE_SPECIAL_ANIMATION, SPECIAL_NONE);
builder.define(ROARING, false);
builder.define(PHASE_TWO, false);
builder.define(PHASE_TWO_TEXTURE, false);
builder.define(PHASE_TRANSITIONING, false);
}
@Override
protected void registerGoals() {
this.goalSelector.addGoal(1, new NightmareRoarGoal());
this.goalSelector.addGoal(2, new NightmareFlyToTargetGoal());
this.goalSelector.addGoal(3, new NightmareMeleeGoal());
this.goalSelector.addGoal(5, new LookAtPlayerGoal(this, Player.class, 16.0F));
this.goalSelector.addGoal(6, new RandomLookAroundGoal(this));
this.goalSelector.addGoal(7, new NightmareWanderGoal());
this.goalSelector.addGoal(1, new NightmarePhaseTransitionGoal());
this.goalSelector.addGoal(2, new NightmarePortalGoal());
this.goalSelector.addGoal(3, new NightmareRoarGoal());
this.goalSelector.addGoal(4, new NightmareFlyToTargetGoal());
this.goalSelector.addGoal(5, new NightmareMeleeGoal());
this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 16.0F));
this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
this.goalSelector.addGoal(9, new NightmareWanderGoal());
this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers());
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::canTargetEntity));
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Mob.class, 10, true, false, this::canTargetEntity));
@@ -167,22 +255,29 @@ public class NightmareEntity extends Monster implements GeoEntity {
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
controllers.add(new AnimationController<>(this, "main_controller", 0, this::mainAnimController));
controllers.add(new AnimationController<>(this, LOCOMOTION_CONTROLLER, 0, this::mainAnimController));
controllers.add(new AnimationController<>(this, SPECIAL_CONTROLLER, 0, state -> PlayState.STOP)
.triggerableAnim(SPECIAL_ATTACK_TRIGGER, ATTACK_ANIM)
.triggerableAnim(SPECIAL_ATTACK_P2_TRIGGER, ATTACK_P2_ANIM)
.triggerableAnim(SPECIAL_FLY_ATTACK_TRIGGER, FLY_ATTACK_ANIM)
.triggerableAnim(SPECIAL_FLY_ATTACK_P2_TRIGGER, FLY_ATTACK_P2_ANIM)
.triggerableAnim(SPECIAL_ROAR_TRIGGER, ROAR_ANIM)
.triggerableAnim(SPECIAL_ROAR_P2_TRIGGER, ROAR_P2_ANIM)
.triggerableAnim(SPECIAL_PHASE_TWO_TRIGGER, PHASE_TWO_TRANSITION_ANIM)
.triggerableAnim(SPECIAL_PORTAL_TRIGGER, PORTAL_ATTACK_ANIM));
}
private PlayState mainAnimController(AnimationState<NightmareEntity> state) {
if (this.hasActiveSpecialAnimation()) {
return PlayState.STOP;
}
int animState = this.getAnimationState();
state.getController().setAnimationSpeed(switch (animState) {
case ANIM_FLY -> 0.45D;
default -> 1.0D;
});
state.getController().setAnimationSpeed(animState == ANIM_FLY ? 0.45D : 1.0D);
boolean phaseTwo = this.isPhaseTwo();
return switch (animState) {
case ANIM_WALK -> state.setAndContinue(WALK_ANIM);
case ANIM_FLY -> state.setAndContinue(FLY_ANIM);
case ANIM_ATTACK -> state.setAndContinue(ATTACK_ANIM);
case ANIM_FLY_ATTACK -> state.setAndContinue(FLY_ATTACK_ANIM);
case ANIM_ROAR -> state.setAndContinue(ROAR_ANIM);
default -> state.setAndContinue(IDLE_ANIM);
case ANIM_WALK -> state.setAndContinue(phaseTwo ? PHASE_TWO_WALK_ANIM : WALK_ANIM);
case ANIM_FLY -> state.setAndContinue(phaseTwo ? PHASE_TWO_FLY_ANIM : FLY_ANIM);
default -> state.setAndContinue(phaseTwo ? PHASE_TWO_IDLE_ANIM : IDLE_ANIM);
};
}
@@ -205,6 +300,7 @@ public class NightmareEntity extends Monster implements GeoEntity {
super.tick();
if (this.level().isClientSide) {
this.syncSpecialAnimationTrigger();
this.tickClientParticles();
this.updateFlightRotation();
if (this.isRoaring()) {
@@ -218,18 +314,20 @@ public class NightmareEntity extends Monster implements GeoEntity {
return;
}
this.setNoGravity(this.flyingToTarget && !this.isTooCloseToCeiling());
this.setNoGravity((this.flyingToTarget || this.portalAttackTicks > 0 || this.portalTravelTicks > 0) && !this.isTooCloseToCeiling());
int prevAirborneTicks = this.airborneTicks;
this.airborneTicks = this.onGround() ? 0 : this.airborneTicks + 1;
if (this.onGround() && prevAirborneTicks > 5) {
this.landingCooldown = 100;
this.landingCooldown = 32;
}
if (this.attackCooldown > 0) this.attackCooldown--;
if (this.roarCooldown > 0) this.roarCooldown--;
if (this.blockBreakCooldown > 0) this.blockBreakCooldown--;
if (this.landingCooldown > 0) this.landingCooldown--;
if (this.portalCooldown > 0) this.portalCooldown--;
if (this.portalTravelTicks > 0) this.portalTravelTicks--;
LivingEntity target = this.getTarget();
if (!this.canTargetEntity(target)) {
@@ -248,15 +346,21 @@ public class NightmareEntity extends Monster implements GeoEntity {
}
if (this.isDeadOrDying()) {
this.clearNightmarePortals();
this.updateFlightRotation();
return;
}
if (this.attackAnimationTicks > 0) {
if (this.isPhaseTransitioning()) {
this.tickPhaseTransition(target);
} else if (this.portalAttackTicks > 0) {
this.tickPortalAttack(target);
} else if (this.attackAnimationTicks > 0) {
this.tickAttack(target);
}
this.updateAnimationState();
this.syncSpecialAnimationTrigger();
this.updateFlightRotation();
}
@@ -271,6 +375,27 @@ public class NightmareEntity extends Monster implements GeoEntity {
super.travel(travelVector);
}
@Override
public boolean hurt(DamageSource source, float amount) {
if (this.isPhaseTransitioning() || this.portalTravelTicks > 0 || this.portalAttackTicks > 0) {
return false;
}
if (!this.isPhaseTwo() && amount > 0.0F) {
float threshold = (float) (this.getMaxHealth() * PHASE_TWO_HEALTH_FRACTION);
if (this.getHealth() > threshold && this.getHealth() - amount <= threshold) {
float clampedAmount = this.getHealth() - threshold;
boolean hurt = clampedAmount > 0.0F && super.hurt(source, clampedAmount);
if (hurt || clampedAmount <= 0.0F) {
this.setHealth(threshold);
this.startPhaseTransition();
return true;
}
return false;
}
}
return super.hurt(source, amount);
}
@Override
public boolean doHurtTarget(Entity target) {
if (!(target instanceof LivingEntity livingTarget)) return false;
@@ -358,6 +483,26 @@ public class NightmareEntity extends Monster implements GeoEntity {
tag.putInt("AirborneTicks", this.airborneTicks);
tag.putBoolean("Roaring", this.isRoaring());
tag.putInt(ANIMATION_STATE_KEY, this.getAnimationState());
tag.putInt(ACTIVE_SPECIAL_ANIMATION_KEY, this.getActiveSpecialAnimation());
tag.putBoolean(PHASE_TWO_KEY, this.isPhaseTwo());
tag.putBoolean(PHASE_TWO_TEXTURE_KEY, this.hasPhaseTwoTexture());
tag.putBoolean(PHASE_TRANSITIONING_KEY, this.isPhaseTransitioning());
tag.putInt(PHASE_TRANSITION_TICKS_KEY, this.phaseTransitionTicks);
tag.putInt(PORTAL_COOLDOWN_KEY, this.portalCooldown);
tag.putInt(PORTAL_ATTACK_TICKS_KEY, this.portalAttackTicks);
tag.putBoolean(PORTAL_ATTACK_HIT_KEY, this.portalAttackHitApplied);
tag.putInt(PORTAL_TRAVEL_TICKS_KEY, this.portalTravelTicks);
if (this.portalExitPos != null) {
tag.putDouble(PORTAL_EXIT_X_KEY, this.portalExitPos.x);
tag.putDouble(PORTAL_EXIT_Y_KEY, this.portalExitPos.y);
tag.putDouble(PORTAL_EXIT_Z_KEY, this.portalExitPos.z);
}
if (this.entryPortal != null) {
tag.putUUID(PORTAL_ENTRY_ID_KEY, this.entryPortal.getUUID());
}
if (this.exitPortal != null) {
tag.putUUID(PORTAL_EXIT_ID_KEY, this.exitPortal.getUUID());
}
}
@Override
@@ -371,8 +516,22 @@ public class NightmareEntity extends Monster implements GeoEntity {
this.introRoarUsed = tag.getBoolean(INTRO_ROAR_USED_KEY);
this.targetlessTicks = tag.getInt(TARGETLESS_TICKS_KEY);
this.airborneTicks = tag.getInt("AirborneTicks");
this.portalCooldown = tag.getInt(PORTAL_COOLDOWN_KEY);
this.portalAttackTicks = tag.getInt(PORTAL_ATTACK_TICKS_KEY);
this.portalAttackHitApplied = tag.getBoolean(PORTAL_ATTACK_HIT_KEY);
this.portalTravelTicks = tag.getInt(PORTAL_TRAVEL_TICKS_KEY);
this.entityData.set(ROARING, tag.getBoolean("Roaring"));
this.entityData.set(ANIMATION_STATE, tag.contains(ANIMATION_STATE_KEY) ? tag.getInt(ANIMATION_STATE_KEY) : ANIM_IDLE);
this.entityData.set(ACTIVE_SPECIAL_ANIMATION, tag.contains(ACTIVE_SPECIAL_ANIMATION_KEY) ? tag.getInt(ACTIVE_SPECIAL_ANIMATION_KEY) : SPECIAL_NONE);
this.setPhaseTwo(tag.getBoolean(PHASE_TWO_KEY));
this.setPhaseTwoTexture(tag.contains(PHASE_TWO_TEXTURE_KEY) ? tag.getBoolean(PHASE_TWO_TEXTURE_KEY) : this.isPhaseTwo() && !this.isPhaseTransitioning());
this.setPhaseTransitioning(tag.getBoolean(PHASE_TRANSITIONING_KEY));
this.phaseTransitionTicks = tag.getInt(PHASE_TRANSITION_TICKS_KEY);
if (tag.contains(PORTAL_EXIT_X_KEY)) {
this.portalExitPos = new Vec3(tag.getDouble(PORTAL_EXIT_X_KEY), tag.getDouble(PORTAL_EXIT_Y_KEY), tag.getDouble(PORTAL_EXIT_Z_KEY));
} else {
this.portalExitPos = null;
}
}
@Override
@@ -381,9 +540,14 @@ public class NightmareEntity extends Monster implements GeoEntity {
this.attackAnimationTicks = 0;
this.attackCooldown = 0;
this.roarTicks = 0;
this.portalAttackTicks = 0;
this.portalTravelTicks = 0;
this.phaseTransitionTicks = 0;
this.clearActiveSpecialAnimation();
this.setRoaring(false);
this.setDeltaMovement(Vec3.ZERO);
this.getNavigation().stop();
this.clearNightmarePortals();
}
super.die(damageSource);
}
@@ -405,6 +569,22 @@ public class NightmareEntity extends Monster implements GeoEntity {
return this.entityData.get(ANIMATION_STATE);
}
public int getActiveSpecialAnimation() {
return this.entityData.get(ACTIVE_SPECIAL_ANIMATION);
}
public boolean isPhaseTwo() {
return this.entityData.get(PHASE_TWO);
}
public boolean hasPhaseTwoTexture() {
return this.entityData.get(PHASE_TWO_TEXTURE);
}
public boolean isPhaseTransitioning() {
return this.entityData.get(PHASE_TRANSITIONING);
}
private void setRoaring(boolean roaring) {
this.entityData.set(ROARING, roaring);
}
@@ -415,13 +595,29 @@ public class NightmareEntity extends Monster implements GeoEntity {
}
}
private void setActiveSpecialAnimation(int specialAnimation) {
if (this.entityData.get(ACTIVE_SPECIAL_ANIMATION) != specialAnimation) {
this.entityData.set(ACTIVE_SPECIAL_ANIMATION, specialAnimation);
}
}
private void setPhaseTwo(boolean phaseTwo) {
this.entityData.set(PHASE_TWO, phaseTwo);
}
private void setPhaseTwoTexture(boolean phaseTwoTexture) {
this.entityData.set(PHASE_TWO_TEXTURE, phaseTwoTexture);
}
private void setPhaseTransitioning(boolean phaseTransitioning) {
this.entityData.set(PHASE_TRANSITIONING, phaseTransitioning);
}
private boolean shouldStartRoar(LivingEntity target) {
if (!this.onGround() || this.roarCooldown > 0 || !this.hasLineOfSight(target)) return false;
double distanceSqr = this.distanceToSqr(target);
if (distanceSqr > ROAR_RETRY_DISTANCE_SQR || !this.isInFront(target.position(), -0.1D)) return false;
boolean pressureWindow = distanceSqr > ATTACK_START_RANGE_SQR;
boolean wounded = this.getHealth() <= this.getMaxHealth() * 0.5F;
return pressureWindow || wounded;
return distanceSqr > ATTACK_START_RANGE_SQR || this.isPhaseTwo();
}
private void startRoar() {
@@ -431,6 +627,7 @@ public class NightmareEntity extends Monster implements GeoEntity {
this.attackAnimationTicks = 0;
this.attackHitApplied = false;
this.setRoaring(true);
this.selectSpecialAnimation(this.isPhaseTwo() ? SPECIAL_ROAR_P2 : SPECIAL_ROAR);
this.getNavigation().stop();
this.setDeltaMovement(this.getDeltaMovement().scale(0.18D));
this.playSound(AntarchySoundEvents.NIGHTMARE_ROAR.get(), 2.2F, 0.7F + this.random.nextFloat() * 0.06F);
@@ -451,6 +648,7 @@ public class NightmareEntity extends Monster implements GeoEntity {
if (--this.roarTicks <= 0) {
this.roarTicks = 0;
this.setRoaring(false);
this.clearActiveSpecialAnimation();
this.attackCooldown = Math.max(this.attackCooldown, 18);
}
}
@@ -459,6 +657,7 @@ public class NightmareEntity extends Monster implements GeoEntity {
this.attackAnimationTicks = ATTACK_TOTAL_TICKS;
this.attackHitApplied = false;
this.attackCooldown = ATTACK_TOTAL_TICKS + 12;
this.selectSpecialAnimation(this.selectAttackSpecialAnimation());
this.getNavigation().stop();
Vec3 lunge = target.getEyePosition().subtract(this.getEyePosition());
if (lunge.lengthSqr() > 1.0E-4D) {
@@ -479,13 +678,122 @@ public class NightmareEntity extends Monster implements GeoEntity {
if (!this.attackHitApplied && elapsed >= ATTACK_DAMAGE_TICK) {
this.attackHitApplied = true;
this.playNightmareBiteSound();
this.spawnBiteEffect();
this.performAttackHit();
}
if (--this.attackAnimationTicks <= 0) {
this.attackAnimationTicks = 0;
this.clearActiveSpecialAnimation();
}
}
private void startPhaseTransition() {
this.setPhaseTwo(true);
this.setPhaseTwoTexture(false);
this.setPhaseTransitioning(true);
this.selectSpecialAnimation(SPECIAL_PHASE_TWO);
this.phaseTransitionTicks = PHASE_TWO_TRANSITION_TICKS;
this.attackAnimationTicks = 0;
this.portalAttackTicks = 0;
this.portalTravelTicks = 0;
this.attackHitApplied = false;
this.portalAttackHitApplied = false;
this.portalExitPos = null;
this.clearNightmarePortals();
this.getNavigation().stop();
this.setRoaring(false);
this.setDeltaMovement(Vec3.ZERO);
this.roarCooldown = Math.max(this.roarCooldown, 80);
this.portalCooldown = Math.max(this.portalCooldown, 140);
}
private void tickPhaseTransition(@Nullable LivingEntity target) {
this.getNavigation().stop();
this.setDeltaMovement(this.getDeltaMovement().scale(0.45D));
this.getMoveControl().setWantedPosition(this.getX(), this.getY(), this.getZ(), 0.0D);
if (target != null) {
this.getLookControl().setLookAt(target, 35.0F, 20.0F);
}
if (this.phaseTransitionTicks % 8 == 0 && this.level() instanceof ServerLevel serverLevel) {
serverLevel.sendParticles(ParticleTypes.SOUL_FIRE_FLAME, this.getX(), this.getY() + 1.9D, this.getZ(), 12, 1.0D, 0.7D, 1.0D, 0.01D);
serverLevel.sendParticles(ParticleTypes.SMOKE, this.getX(), this.getY() + 1.9D, this.getZ(), 10, 0.8D, 0.5D, 0.8D, 0.02D);
}
if (!this.hasPhaseTwoTexture() && PHASE_TWO_TRANSITION_TICKS - this.phaseTransitionTicks >= PHASE_TWO_TEXTURE_SWAP_TICKS) {
this.setPhaseTwoTexture(true);
}
if (--this.phaseTransitionTicks <= 0) {
this.phaseTransitionTicks = 0;
this.setPhaseTwoTexture(true);
this.setPhaseTransitioning(false);
this.clearActiveSpecialAnimation();
this.attackCooldown = Math.max(this.attackCooldown, 18);
}
}
private boolean canStartPortalAttack(LivingEntity target) {
if (!this.isPhaseTwo() || this.isPhaseTransitioning() || this.portalCooldown > 0 || this.attackAnimationTicks > 0 || this.roarTicks > 0) return false;
if (!this.hasLineOfSight(target) || this.distanceToSqr(target) > PORTAL_RANGE * PORTAL_RANGE) return false;
if (this.horizontalDistanceToSqr(target) < PORTAL_MIN_RANGE_SQR) return false;
return this.portalAttackTicks <= 0 && this.findPortalExitPos(target) != null;
}
private void startPortalAttack(LivingEntity target) {
Vec3 exitPos = this.findPortalExitPos(target);
if (exitPos == null || !(this.level() instanceof ServerLevel serverLevel)) return;
this.clearNightmarePortals();
this.portalExitPos = exitPos;
this.portalAttackTicks = PORTAL_TOTAL_TICKS;
this.portalTravelTicks = 0;
this.portalAttackHitApplied = false;
this.attackAnimationTicks = 0;
this.attackHitApplied = false;
this.attackCooldown = 24;
this.portalCooldown = 180 + this.random.nextInt(100);
this.selectSpecialAnimation(SPECIAL_PORTAL);
this.getNavigation().stop();
this.entryPortal = NightmarePortalEntity.spawnAt(serverLevel, this.position().add(this.getViewVector(1.0F).multiply(1.6D, 0.0D, 1.6D)), this, this.position(), PORTAL_LIFETIME_TICKS);
this.exitPortal = NightmarePortalEntity.spawnAt(serverLevel, exitPos, this, this.position(), PORTAL_LIFETIME_TICKS);
if (this.entryPortal != null && this.exitPortal != null) {
this.entryPortal.linkTo(this.exitPortal);
this.exitPortal.linkTo(this.entryPortal);
}
}
private void tickPortalAttack(@Nullable LivingEntity target) {
this.getNavigation().stop();
this.setDeltaMovement(this.getDeltaMovement().scale(0.55D));
if (target != null) {
this.getLookControl().setLookAt(target, 35.0F, 20.0F);
}
int elapsed = PORTAL_TOTAL_TICKS - this.portalAttackTicks;
if (elapsed == PORTAL_TELEPORT_TICK && this.portalExitPos != null) {
this.executePortalTeleport(target);
}
if (!this.portalAttackHitApplied && elapsed >= PORTAL_DAMAGE_TICK) {
this.portalAttackHitApplied = true;
this.spawnBiteEffect();
this.performPortalExitHit();
}
if (--this.portalAttackTicks <= 0) {
this.portalAttackTicks = 0;
this.portalExitPos = null;
this.clearNightmarePortals();
this.clearActiveSpecialAnimation();
}
}
private void executePortalTeleport(@Nullable LivingEntity target) {
if (this.portalExitPos == null) return;
this.portalTravelTicks = PORTAL_TRAVEL_INVULNERABLE_TICKS;
this.setPortalCooldown();
this.teleportTo(this.portalExitPos.x, this.portalExitPos.y, this.portalExitPos.z);
if (target != null) {
this.faceTowardTarget(target, 180.0F);
}
this.setDeltaMovement(Vec3.ZERO);
this.hasImpulse = true;
}
private void performAttackHit() {
AABB hitBox = this.getBoundingBox()
.inflate(ATTACK_REACH_RADIUS, 1.5D, ATTACK_REACH_RADIUS)
@@ -505,6 +813,38 @@ public class NightmareEntity extends Monster implements GeoEntity {
}
}
private void performPortalExitHit() {
if (this.portalExitPos == null) return;
AABB hitBox = this.getBoundingBox().move(this.portalExitPos.subtract(this.position())).inflate(1.7D, 1.2D, 1.7D);
float damage = (float) (this.getAttributeValue(Attributes.ATTACK_DAMAGE) * 1.15F);
List<LivingEntity> victims = this.level().getEntitiesOfClass(LivingEntity.class, hitBox, this::canTargetEntity);
for (LivingEntity victim : victims) {
if (victim.hurt(this.nightmareDamageSource(), damage)) {
this.spawnBiteEffectAt(victim);
this.applyNightmareStrikeEffects(victim);
this.knockAway(victim, 1.35D, 0.35D);
}
}
if (this.level() instanceof ServerLevel serverLevel) {
serverLevel.sendParticles(ParticleTypes.SOUL_FIRE_FLAME, this.portalExitPos.x, this.portalExitPos.y + 1.0D, this.portalExitPos.z, 18, 0.9D, 0.45D, 0.9D, 0.02D);
serverLevel.sendParticles(ParticleTypes.SMOKE, this.portalExitPos.x, this.portalExitPos.y + 1.0D, this.portalExitPos.z, 14, 0.8D, 0.3D, 0.8D, 0.03D);
}
}
private void spawnBiteEffect() {
if (!(this.level() instanceof ServerLevel serverLevel)) return;
Vec3 forward = this.getViewVector(1.0F).normalize();
Vec3 spawnPos = this.getEyePosition().add(forward.scale(this.getBbWidth() * 0.65D)).add(0.0D, -0.45D, 0.0D);
NightmareBiteEntity.spawnAt(serverLevel, spawnPos, this.getYRot(), this.isPhaseTwo());
}
private void spawnBiteEffectAt(LivingEntity target) {
if (!(this.level() instanceof ServerLevel serverLevel)) return;
float yaw = target.getYRot() + 180.0F;
Vec3 spawnPos = target.getEyePosition().add(0.0D, -0.35D, 0.0D);
NightmareBiteEntity.spawnAt(serverLevel, spawnPos, yaw, this.isPhaseTwo());
}
private void playNightmareBiteSound() {
this.playSound(AntarchySoundEvents.NIGHTMARE_BITE.get(), 1.3F, 0.72F + this.random.nextFloat() * 0.08F);
}
@@ -564,19 +904,48 @@ public class NightmareEntity extends Monster implements GeoEntity {
return entity instanceof Mob && entity.isAttackable();
}
private boolean shouldUseFlight() {
if (this.landingCooldown > 0) return false;
LivingEntity target = this.getTarget();
return target != null
&& this.distanceToSqr(target) > FLIGHT_ENGAGE_RANGE_SQR
&& !this.isTooCloseToCeiling();
}
private boolean canStartAttackOn(LivingEntity target) {
if (!this.hasLineOfSight(target) || this.distanceToSqr(target) > ATTACK_START_RANGE_SQR) return false;
double hdSqr = this.horizontalDistanceToSqr(target);
double verticalDistance = Math.abs(target.getEyeY() - this.getEyeY());
return hdSqr <= ATTACK_COMMIT_HORIZONTAL_RANGE * ATTACK_COMMIT_HORIZONTAL_RANGE && verticalDistance <= 4.0D;
return hdSqr <= ATTACK_COMMIT_HORIZONTAL_RANGE_SQR && verticalDistance <= 4.0D;
}
private boolean shouldUseFlightPressure(LivingEntity target) {
if (target == null || this.isTooCloseToCeiling()) {
return false;
}
double distanceSqr = this.distanceToSqr(target);
double verticalDistance = Math.abs(target.getEyeY() - this.getEyeY());
if (this.flyingToTarget) {
return distanceSqr > ATTACK_COMMIT_HORIZONTAL_RANGE_SQR || verticalDistance > 1.25D;
}
if (distanceSqr >= FLIGHT_ENGAGE_RANGE_SQR) {
return true;
}
return this.isPhaseTwo() && (distanceSqr >= FLIGHT_DISENGAGE_RANGE_SQR || verticalDistance > 1.5D);
}
private Vec3 getFlightApproachPosition(LivingEntity target) {
Vec3 toTarget = target.position().subtract(this.position()).multiply(1.0D, 0.0D, 1.0D);
if (toTarget.lengthSqr() < 1.0E-4D) {
toTarget = target.getLookAngle().multiply(1.0D, 0.0D, 1.0D);
}
if (toTarget.lengthSqr() < 1.0E-4D) {
toTarget = this.getViewVector(1.0F).multiply(1.0D, 0.0D, 1.0D);
}
if (toTarget.lengthSqr() < 1.0E-4D) {
toTarget = new Vec3(0.0D, 0.0D, 1.0D);
}
Vec3 forward = toTarget.normalize();
Vec3 right = new Vec3(-forward.z, 0.0D, forward.x);
double strafe = this.tickCount % 32 < 16 ? FLYING_APPROACH_STRAFE_OFFSET : -FLYING_APPROACH_STRAFE_OFFSET;
double height = this.isPhaseTwo() ? FLYING_APPROACH_HEIGHT_PHASE_TWO : FLYING_APPROACH_HEIGHT;
Vec3 anchor = target.position().subtract(forward.scale(1.4D)).add(right.scale(strafe));
if (this.horizontalDistanceToSqr(target) <= FLYING_APPROACH_TOO_CLOSE_RANGE_SQR) {
anchor = target.position().subtract(forward.scale(2.4D));
}
return new Vec3(anchor.x, target.getEyeY() + height, anchor.z);
}
private double horizontalDistanceToSqr(LivingEntity target) {
@@ -608,7 +977,6 @@ public class NightmareEntity extends Monster implements GeoEntity {
}
}
private boolean isTooCloseToCeiling() {
BlockPos current = BlockPos.containing(this.getX(), this.getY(), this.getZ());
for (int i = 1; i <= FLIGHT_CEILING_CLEARANCE_BLOCKS; i++) {
@@ -617,8 +985,58 @@ public class NightmareEntity extends Monster implements GeoEntity {
return false;
}
@Nullable
private Vec3 findPortalExitPos(LivingEntity target) {
Vec3 forward = target.getLookAngle().multiply(1.0D, 0.0D, 1.0D);
if (forward.lengthSqr() < 1.0E-4D) {
forward = this.getViewVector(1.0F).multiply(1.0D, 0.0D, 1.0D);
}
if (forward.lengthSqr() < 1.0E-4D) {
forward = new Vec3(0.0D, 0.0D, 1.0D);
}
forward = forward.normalize();
Vec3 right = new Vec3(-forward.z, 0.0D, forward.x);
Vec3[] candidates = new Vec3[] {
target.position().subtract(forward.scale(PORTAL_EXIT_OFFSET)),
target.position().subtract(forward.scale(1.4D)).add(right.scale(2.25D)),
target.position().subtract(forward.scale(1.4D)).subtract(right.scale(2.25D)),
target.position().add(forward.scale(2.4D))
};
for (Vec3 candidate : candidates) {
Vec3 adjusted = this.findValidPortalPosition(candidate);
if (adjusted != null && adjusted.distanceToSqr(this.position()) <= PORTAL_RANGE * PORTAL_RANGE) {
return adjusted;
}
}
return null;
}
@Nullable
private Vec3 findValidPortalPosition(Vec3 base) {
EntityDimensions dimensions = this.getType().getDimensions();
for (int yOffset = 1; yOffset >= -1; yOffset--) {
Vec3 candidate = new Vec3(base.x, base.y + yOffset, base.z);
AABB box = dimensions.makeBoundingBox(candidate);
if (this.level().noCollision(this, box)) {
return candidate;
}
}
return null;
}
private void clearNightmarePortals() {
if (this.entryPortal != null && this.entryPortal.isAlive()) {
this.entryPortal.discard();
}
if (this.exitPortal != null && this.exitPortal.isAlive()) {
this.exitPortal.discard();
}
this.entryPortal = null;
this.exitPortal = null;
}
private void tickClientParticles() {
if ((this.isRoaring() || this.attackAnimationTicks > 0) && this.tickCount % 3 == 0) {
if ((this.isRoaring() || this.attackAnimationTicks > 0 || this.portalAttackTicks > 0 || this.isPhaseTransitioning()) && this.tickCount % 3 == 0) {
this.level().addParticle(
ParticleTypes.SOUL_FIRE_FLAME,
this.getX() + (this.random.nextDouble() - 0.5D) * this.getBbWidth(),
@@ -652,14 +1070,7 @@ public class NightmareEntity extends Monster implements GeoEntity {
this.wingFlapCooldown = 0;
return;
}
if (this.isRoaring()) {
this.setAnimationState(ANIM_ROAR);
this.groundMoveTicks = 0;
this.wingFlapCooldown = 0;
return;
}
if (this.attackAnimationTicks > 0) {
this.setAnimationState(this.isNoGravity() || this.airborneTicks >= MIN_AIRBORNE_TICKS_FOR_FLY_ANIM ? ANIM_FLY_ATTACK : ANIM_ATTACK);
if (this.hasActiveSpecialAnimation()) {
this.groundMoveTicks = 0;
this.tickWingFlapSound();
return;
@@ -676,7 +1087,8 @@ public class NightmareEntity extends Monster implements GeoEntity {
this.tickWingFlapSound();
return;
}
if (this.walkDist - this.walkDistO > 0.005F) {
Vec3 horizontalVelocity = this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D);
if (horizontalVelocity.lengthSqr() > ANIMATION_MOVEMENT_THRESHOLD_SQR) {
this.groundMoveTicks = 6;
}
if (this.groundMoveTicks > 0) {
@@ -705,6 +1117,112 @@ public class NightmareEntity extends Monster implements GeoEntity {
this.wingFlapCooldown = 5 + this.random.nextInt(4);
}
private boolean hasActiveSpecialAnimation() {
return this.getActiveSpecialAnimation() != SPECIAL_NONE;
}
private int selectAttackSpecialAnimation() {
boolean flyingAttack = this.isNoGravity() || this.airborneTicks >= MIN_AIRBORNE_TICKS_FOR_FLY_ANIM || this.flyingToTarget;
if (flyingAttack) {
return this.isPhaseTwo() ? SPECIAL_FLY_ATTACK_P2 : SPECIAL_FLY_ATTACK;
}
return this.isPhaseTwo() ? SPECIAL_ATTACK_P2 : SPECIAL_ATTACK;
}
private void selectSpecialAnimation(int specialAnimation) {
this.setActiveSpecialAnimation(specialAnimation);
if (!this.level().isClientSide) {
LOGGER.info("Nightmare animation selected={} tick={}", this.specialAnimationName(specialAnimation), this.tickCount);
}
}
private void clearActiveSpecialAnimation() {
int specialAnimation = this.getActiveSpecialAnimation();
if (specialAnimation != SPECIAL_NONE && !this.level().isClientSide) {
LOGGER.info("Nightmare animation state cleared={} tick={}", this.specialAnimationName(specialAnimation), this.tickCount);
}
this.setActiveSpecialAnimation(SPECIAL_NONE);
}
private void syncSpecialAnimationTrigger() {
int activeSpecialAnimation = this.getActiveSpecialAnimation();
if (activeSpecialAnimation != SPECIAL_NONE && this.lastTriggeredSpecialAnimation != activeSpecialAnimation) {
String triggerName = this.specialAnimationTrigger(activeSpecialAnimation);
if (triggerName != null) {
if (!this.level().isClientSide) {
LOGGER.info("Nightmare triggerAnim called={} tick={}", triggerName, this.tickCount);
}
this.triggerAnim(SPECIAL_CONTROLLER, triggerName);
}
this.lastTriggeredSpecialAnimation = activeSpecialAnimation;
return;
}
if (activeSpecialAnimation == SPECIAL_NONE) {
this.lastTriggeredSpecialAnimation = SPECIAL_NONE;
}
}
@Nullable
private String specialAnimationTrigger(int specialAnimation) {
return switch (specialAnimation) {
case SPECIAL_ATTACK -> SPECIAL_ATTACK_TRIGGER;
case SPECIAL_ATTACK_P2 -> SPECIAL_ATTACK_P2_TRIGGER;
case SPECIAL_FLY_ATTACK -> SPECIAL_FLY_ATTACK_TRIGGER;
case SPECIAL_FLY_ATTACK_P2 -> SPECIAL_FLY_ATTACK_P2_TRIGGER;
case SPECIAL_ROAR -> SPECIAL_ROAR_TRIGGER;
case SPECIAL_ROAR_P2 -> SPECIAL_ROAR_P2_TRIGGER;
case SPECIAL_PHASE_TWO -> SPECIAL_PHASE_TWO_TRIGGER;
case SPECIAL_PORTAL -> SPECIAL_PORTAL_TRIGGER;
default -> null;
};
}
private String specialAnimationName(int specialAnimation) {
String triggerName = this.specialAnimationTrigger(specialAnimation);
return triggerName != null ? triggerName : "none";
}
private final class NightmarePhaseTransitionGoal extends Goal {
NightmarePhaseTransitionGoal() {
this.setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK, Flag.JUMP));
}
@Override
public boolean canUse() {
return NightmareEntity.this.isPhaseTransitioning();
}
@Override
public boolean canContinueToUse() {
return NightmareEntity.this.isPhaseTransitioning();
}
}
private final class NightmarePortalGoal extends Goal {
NightmarePortalGoal() {
this.setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK));
}
@Override
public boolean canUse() {
LivingEntity target = NightmareEntity.this.getTarget();
return target != null && NightmareEntity.this.canStartPortalAttack(target);
}
@Override
public boolean canContinueToUse() {
return NightmareEntity.this.portalAttackTicks > 0;
}
@Override
public void start() {
LivingEntity target = NightmareEntity.this.getTarget();
if (target != null) {
NightmareEntity.this.startPortalAttack(target);
}
}
}
private final class NightmareRoarGoal extends Goal {
NightmareRoarGoal() {
this.setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK));
@@ -713,7 +1231,7 @@ public class NightmareEntity extends Monster implements GeoEntity {
@Override
public boolean canUse() {
LivingEntity target = NightmareEntity.this.getTarget();
return target instanceof Player && NightmareEntity.this.shouldStartRoar(target);
return target instanceof Player && NightmareEntity.this.shouldStartRoar(target) && !NightmareEntity.this.isPhaseTransitioning() && NightmareEntity.this.portalAttackTicks <= 0;
}
@Override
@@ -748,14 +1266,17 @@ public class NightmareEntity extends Monster implements GeoEntity {
LivingEntity target = NightmareEntity.this.getTarget();
return target != null
&& NightmareEntity.this.landingCooldown <= 0
&& NightmareEntity.this.distanceToSqr(target) > FLIGHT_ENGAGE_RANGE_SQR
&& !NightmareEntity.this.isTooCloseToCeiling();
&& NightmareEntity.this.shouldUseFlightPressure(target)
&& !NightmareEntity.this.isPhaseTransitioning()
&& NightmareEntity.this.portalAttackTicks <= 0;
}
@Override
public boolean canContinueToUse() {
LivingEntity target = NightmareEntity.this.getTarget();
return target != null && NightmareEntity.this.distanceToSqr(target) > FLIGHT_DISENGAGE_RANGE_SQR;
return target != null
&& NightmareEntity.this.shouldUseFlightPressure(target)
&& NightmareEntity.this.portalAttackTicks <= 0;
}
@Override
@@ -766,7 +1287,7 @@ public class NightmareEntity extends Monster implements GeoEntity {
@Override
public void stop() {
NightmareEntity.this.flyingToTarget = false;
NightmareEntity.this.landingCooldown = 80;
NightmareEntity.this.landingCooldown = 18;
NightmareEntity.this.getNavigation().stop();
}
@@ -779,13 +1300,17 @@ public class NightmareEntity extends Monster implements GeoEntity {
NightmareEntity.this.getNavigation().stop();
return;
}
if (NightmareEntity.this.onGround() && NightmareEntity.this.distanceToSqr(target) >= FLIGHT_DISENGAGE_RANGE_SQR) {
NightmareEntity.this.setDeltaMovement(NightmareEntity.this.getDeltaMovement().add(0.0D, 0.38D, 0.0D));
NightmareEntity.this.hasImpulse = true;
}
if (NightmareEntity.this.attackCooldown <= 0 && NightmareEntity.this.canStartAttackOn(target)) {
NightmareEntity.this.startAttack(target);
return;
}
NightmareEntity.this.getMoveControl().setWantedPosition(
target.getX(), target.getEyeY() + 0.5D, target.getZ(), COMBAT_FLIGHT_SPEED
);
Vec3 approachPos = NightmareEntity.this.getFlightApproachPosition(target);
NightmareEntity.this.faceTowardTarget(target, 10.0F);
NightmareEntity.this.getMoveControl().setWantedPosition(approachPos.x, approachPos.y, approachPos.z, COMBAT_FLIGHT_SPEED);
}
}
@@ -794,6 +1319,26 @@ public class NightmareEntity extends Monster implements GeoEntity {
super(NightmareEntity.this, GROUND_APPROACH_SPEED, true);
}
@Override
public boolean canUse() {
LivingEntity target = NightmareEntity.this.getTarget();
return !NightmareEntity.this.isPhaseTransitioning()
&& NightmareEntity.this.portalAttackTicks <= 0
&& target != null
&& !NightmareEntity.this.shouldUseFlightPressure(target)
&& super.canUse();
}
@Override
public boolean canContinueToUse() {
LivingEntity target = NightmareEntity.this.getTarget();
return !NightmareEntity.this.isPhaseTransitioning()
&& NightmareEntity.this.portalAttackTicks <= 0
&& target != null
&& !NightmareEntity.this.shouldUseFlightPressure(target)
&& super.canContinueToUse();
}
@Override
public void tick() {
LivingEntity target = NightmareEntity.this.getTarget();
@@ -809,6 +1354,9 @@ public class NightmareEntity extends Monster implements GeoEntity {
@Override
protected void checkAndPerformAttack(LivingEntity target) {
if (NightmareEntity.this.shouldUseFlightPressure(target) && NightmareEntity.this.distanceToSqr(target) >= FLIGHT_ATTACK_RANGE_SQR) {
return;
}
if (NightmareEntity.this.attackCooldown <= 0 && NightmareEntity.this.canStartAttackOn(target)) {
NightmareEntity.this.startAttack(target);
}
@@ -816,7 +1364,9 @@ public class NightmareEntity extends Monster implements GeoEntity {
}
private final class NightmareWanderGoal extends Goal {
private double x, y, z;
private double x;
private double y;
private double z;
private int wanderTicks;
NightmareWanderGoal() {
@@ -825,7 +1375,7 @@ public class NightmareEntity extends Monster implements GeoEntity {
@Override
public boolean canUse() {
if (NightmareEntity.this.getTarget() != null || NightmareEntity.this.isDeadOrDying()) return false;
if (NightmareEntity.this.getTarget() != null || NightmareEntity.this.isDeadOrDying() || NightmareEntity.this.isPhaseTransitioning() || NightmareEntity.this.portalAttackTicks > 0) return false;
if (NightmareEntity.this.random.nextInt(40) != 0) return false;
double angle = NightmareEntity.this.random.nextDouble() * Math.PI * 2;
double dist = 4 + NightmareEntity.this.random.nextDouble() * 10;
@@ -0,0 +1,186 @@
package com.craisinlord.antarchy.content.entity.nightmare;
import com.craisinlord.antarchy.content.AntarchyObjects;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import software.bernie.geckolib.animatable.GeoEntity;
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.animation.AnimatableManager;
import software.bernie.geckolib.animation.AnimationController;
import software.bernie.geckolib.animation.AnimationState;
import software.bernie.geckolib.animation.PlayState;
import software.bernie.geckolib.animation.RawAnimation;
import software.bernie.geckolib.util.GeckoLibUtil;
import java.util.List;
import java.util.UUID;
public class NightmarePortalEntity extends Entity implements GeoEntity {
private static final EntityDataAccessor<Boolean> CLOSING = SynchedEntityData.defineId(NightmarePortalEntity.class, EntityDataSerializers.BOOLEAN);
private static final RawAnimation OPEN_ANIM = RawAnimation.begin().thenPlay("open").thenLoop("idle");
private static final RawAnimation CLOSE_ANIM = RawAnimation.begin().thenPlay("close");
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
private int lifetimeTicks;
private int ageTicks;
private UUID ownerId;
private UUID linkedPortalId;
private Vec3 fallbackDestination = Vec3.ZERO;
public NightmarePortalEntity(EntityType<? extends NightmarePortalEntity> entityType, Level level) {
super(entityType, level);
this.setInvulnerable(true);
this.noPhysics = true;
this.noCulling = true;
}
public static NightmarePortalEntity spawnAt(ServerLevel level, Vec3 pos, NightmareEntity owner, Vec3 fallbackDestination, int lifetimeTicks) {
NightmarePortalEntity portal = new NightmarePortalEntity(AntarchyObjects.NIGHTMARE_PORTAL.get(), level);
portal.moveTo(pos.x, pos.y, pos.z, owner.getYRot(), 0.0F);
portal.ownerId = owner.getUUID();
portal.fallbackDestination = fallbackDestination;
portal.lifetimeTicks = lifetimeTicks;
level.addFreshEntity(portal);
return portal;
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
builder.define(CLOSING, false);
}
@Override
public boolean isInvulnerableTo(DamageSource damageSource) {
return true;
}
@Override
public boolean fireImmune() {
return true;
}
@Override
public void lavaHurt() {
}
@Override
public boolean isPushable() {
return false;
}
@Override
public boolean canBeCollidedWith() {
return false;
}
@Override
public boolean isPickable() {
return false;
}
@Override
public void tick() {
super.tick();
if (this.level().isClientSide) {
return;
}
this.ageTicks++;
if (this.ageTicks >= this.lifetimeTicks - 10) {
this.entityData.set(CLOSING, true);
}
if (this.ageTicks >= this.lifetimeTicks) {
this.discard();
return;
}
this.transportEntities();
}
private void transportEntities() {
NightmarePortalEntity other = this.getLinkedPortal();
Vec3 destination = other != null ? other.position() : this.fallbackDestination;
AABB area = this.getBoundingBox().inflate(1.05D, 0.75D, 1.05D);
List<LivingEntity> entities = this.level().getEntitiesOfClass(LivingEntity.class, area, entity -> entity.isAlive() && !entity.isSpectator());
for (LivingEntity entity : entities) {
if (entity.getUUID().equals(this.ownerId)) {
continue;
}
if (entity.isOnPortalCooldown()) {
continue;
}
entity.teleportTo(destination.x, destination.y, destination.z);
entity.setPortalCooldown();
entity.setDeltaMovement(entity.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D));
entity.hurtMarked = true;
}
}
public void linkTo(NightmarePortalEntity other) {
this.linkedPortalId = other.getUUID();
this.fallbackDestination = other.position();
}
private NightmarePortalEntity getLinkedPortal() {
if (!(this.level() instanceof ServerLevel serverLevel) || this.linkedPortalId == null) {
return null;
}
Entity entity = serverLevel.getEntity(this.linkedPortalId);
return entity instanceof NightmarePortalEntity portal ? portal : null;
}
public boolean isClosing() {
return this.getEntityData().get(CLOSING);
}
@Override
public void addAdditionalSaveData(CompoundTag tag) {
tag.putInt("LifetimeTicks", this.lifetimeTicks);
tag.putInt("AgeTicks", this.ageTicks);
if (this.ownerId != null) {
tag.putUUID("OwnerId", this.ownerId);
}
if (this.linkedPortalId != null) {
tag.putUUID("LinkedPortalId", this.linkedPortalId);
}
tag.putDouble("FallbackX", this.fallbackDestination.x);
tag.putDouble("FallbackY", this.fallbackDestination.y);
tag.putDouble("FallbackZ", this.fallbackDestination.z);
}
@Override
public void readAdditionalSaveData(CompoundTag tag) {
this.lifetimeTicks = tag.getInt("LifetimeTicks");
this.ageTicks = tag.getInt("AgeTicks");
if (tag.hasUUID("OwnerId")) {
this.ownerId = tag.getUUID("OwnerId");
}
if (tag.hasUUID("LinkedPortalId")) {
this.linkedPortalId = tag.getUUID("LinkedPortalId");
}
this.fallbackDestination = new Vec3(tag.getDouble("FallbackX"), tag.getDouble("FallbackY"), tag.getDouble("FallbackZ"));
}
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
controllers.add(new AnimationController<>(this, "portal_controller", 0, this::portalController));
}
private PlayState portalController(AnimationState<NightmarePortalEntity> state) {
return state.setAndContinue(this.isClosing() ? CLOSE_ANIM : OPEN_ANIM);
}
@Override
public AnimatableInstanceCache getAnimatableInstanceCache() {
return this.geoCache;
}
}
@@ -55,6 +55,10 @@ public final class CavarynHordeManager {
Registries.BIOME,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "biowart_caves")
);
private static final ResourceKey<Biome> CAVARYN_MOLEWORM_CAVES = ResourceKey.create(
Registries.BIOME,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "cavaryn_moleworm_caves")
);
private static final ResourceLocation DORMANT_HORDE = hordeId("dormant");
private static final ResourceLocation AWAKENING_HORDE = hordeId("awakening");
private static final ResourceLocation WAVE_ONE_HORDE = hordeId("wave_1");
@@ -542,6 +546,9 @@ public final class CavarynHordeManager {
if (level.getBiome(pos).is(BIOWART_CAVES)) {
return ResourceLocation.fromNamespaceAndPath(horde.getNamespace(), "biowart_caves/" + horde.getPath());
}
if (level.getBiome(pos).is(CAVARYN_MOLEWORM_CAVES)) {
return ResourceLocation.fromNamespaceAndPath(horde.getNamespace(), "cavaryn_moleworm_caves/" + horde.getPath());
}
return horde;
}
@@ -26,20 +26,32 @@ import org.jetbrains.annotations.Nullable;
public class GlimmerBottleItem extends Item {
private static final String ABILITY_COOLDOWN_TAG = "AbilityCooldown";
private static final String SHEAR_COOLDOWN_TAG = "ShearCooldown";
public GlimmerBottleItem() {
super(new Item.Properties().stacksTo(1));
}
public static ItemStack create(GlimmerVariant variant) {
return create(variant, 0);
return create(variant, 0, 0);
}
public static ItemStack create(GlimmerVariant variant, int abilityCooldown) {
return create(variant, abilityCooldown, 0);
}
public static ItemStack create(GlimmerVariant variant, int abilityCooldown, int shearCooldown) {
ItemStack stack = new ItemStack(AntarchyObjects.GLIMMER_BOTTLE.get());
stack.set(AntarchyObjects.GLIMMER_VARIANT_COMPONENT.get(), variant);
if (abilityCooldown > 0) {
CustomData.update(DataComponents.CUSTOM_DATA, stack, tag -> tag.putInt(ABILITY_COOLDOWN_TAG, abilityCooldown));
if (abilityCooldown > 0 || shearCooldown > 0) {
CustomData.update(DataComponents.CUSTOM_DATA, stack, tag -> {
if (abilityCooldown > 0) {
tag.putInt(ABILITY_COOLDOWN_TAG, abilityCooldown);
}
if (shearCooldown > 0) {
tag.putInt(SHEAR_COOLDOWN_TAG, shearCooldown);
}
});
}
return stack;
}
@@ -53,6 +65,10 @@ public class GlimmerBottleItem extends Item {
return stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag().getInt(ABILITY_COOLDOWN_TAG);
}
public static int getStoredShearCooldown(ItemStack stack) {
return stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag().getInt(SHEAR_COOLDOWN_TAG);
}
@Override
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
ItemStack stack = player.getItemInHand(hand);
@@ -75,6 +91,7 @@ public class GlimmerBottleItem extends Item {
glimmer.tame(player);
glimmer.setOrderedToSit(false);
glimmer.setAbilityCooldown(getStoredAbilityCooldown(stack));
glimmer.startShearCooldown(getStoredShearCooldown(stack));
level.addFreshEntity(glimmer);
GlimmerCompanionSavedData.replaceCompanion(((ServerLevel) level).getServer(), player.getUUID(), glimmer.getUUID());
GlimmerParticles.tickBurst(glimmer);
@@ -0,0 +1,77 @@
package com.craisinlord.antarchy.content.item;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.item.ultimate.UltimateArmorItem;
import com.craisinlord.antarchy.content.item.ultimate.UltimateBowItem;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.minecraft.core.Holder;
import net.minecraft.tags.EnchantmentTags;
import net.minecraft.util.Mth;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.world.item.enchantment.ItemEnchantments;
public final class InnateEnchantmentHelper {
private InnateEnchantmentHelper() {
}
public static boolean hasInnateNonCurseEnchantments(ItemStack stack) {
for (Object2IntMap.Entry<Holder<Enchantment>> entry : EnchantmentHelper.getEnchantmentsForCrafting(stack).entrySet()) {
Holder<Enchantment> enchantment = entry.getKey();
if (!enchantment.is(EnchantmentTags.CURSE) && isInnateEnchantment(stack, enchantment, entry.getIntValue())) {
return true;
}
}
return false;
}
public static boolean hasRemovableNonCurseEnchantments(ItemStack stack) {
for (Object2IntMap.Entry<Holder<Enchantment>> entry : EnchantmentHelper.getEnchantmentsForCrafting(stack).entrySet()) {
Holder<Enchantment> enchantment = entry.getKey();
if (!enchantment.is(EnchantmentTags.CURSE) && !isInnateEnchantment(stack, enchantment, entry.getIntValue())) {
return true;
}
}
return false;
}
public static ItemStack stripOnlyRemovableNonCurseEnchantments(ItemStack stack) {
EnchantmentHelper.updateEnchantments(stack, mutable ->
mutable.removeIf(enchantment ->
!enchantment.is(EnchantmentTags.CURSE)
&& !isInnateEnchantment(stack, enchantment, mutable.getLevel(enchantment))));
return stack;
}
private static boolean isInnateEnchantment(ItemStack stack, Holder<Enchantment> enchantment, int level) {
if (level <= 0) {
return false;
}
if (stack.getItem() instanceof UltimateArmorItem) {
return AntarchySettings.ultimateArmorComesEnchanted()
&& level == 5
&& (enchantment.is(Enchantments.PROTECTION)
|| enchantment.is(Enchantments.FIRE_PROTECTION)
|| enchantment.is(Enchantments.PROJECTILE_PROTECTION)
|| enchantment.is(Enchantments.BLAST_PROTECTION));
}
if (stack.getItem() instanceof UltimateBowItem) {
return AntarchySettings.ultimateBowComesEnchantedWithFlame()
&& level == 1
&& enchantment.is(Enchantments.FLAME);
}
if (stack.getItem() instanceof KrakensGraspItem) {
int desiredLevel = Mth.clamp(AntarchySettings.krakensGraspInnateLoyaltyLevel(), 1, 3);
return AntarchySettings.krakensGraspInnateLoyalty()
&& level == desiredLevel
&& enchantment.is(Enchantments.LOYALTY);
}
return false;
}
}
@@ -0,0 +1,23 @@
package com.craisinlord.antarchy.content.item;
import java.util.List;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.block.Block;
public class LucidAnchorBlockItem extends BlockItem {
public LucidAnchorBlockItem(Block block, Properties properties) {
super(block, properties);
}
@Override
public void appendHoverText(ItemStack stack, Item.TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
tooltipComponents.add(Component.translatable("tooltip.antarchy.lucid_anchor.pyramid").withStyle(ChatFormatting.DARK_RED));
tooltipComponents.add(Component.translatable("tooltip.antarchy.lucid_anchor.path").withStyle(ChatFormatting.GRAY));
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
}
}
@@ -19,10 +19,11 @@ import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.item.component.ItemAttributeModifiers;
public class NightmareArmorItem extends ArmorItem {
private static final int BASE_DURABILITY_MULTIPLIER = 33;
private final Type armorType;
public NightmareArmorItem(Holder<ArmorMaterial> material, Type type, Properties properties) {
super(material, type, properties);
super(material, type, properties.stacksTo(1).durability(resolveDurability(type)));
this.armorType = type;
}
@@ -119,4 +120,13 @@ public class NightmareArmorItem extends ArmorItem {
tooltipComponents.add(Component.translatable("tooltip.antarchy.nightmare_armor_set_bonus").withStyle(ChatFormatting.DARK_RED));
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
}
private static int resolveDurability(Type armorType) {
return switch (armorType) {
case HELMET -> Type.HELMET.getDurability(BASE_DURABILITY_MULTIPLIER);
case CHESTPLATE, BODY -> Type.CHESTPLATE.getDurability(BASE_DURABILITY_MULTIPLIER);
case LEGGINGS -> Type.LEGGINGS.getDurability(BASE_DURABILITY_MULTIPLIER);
case BOOTS -> Type.BOOTS.getDurability(BASE_DURABILITY_MULTIPLIER);
};
}
}
@@ -24,6 +24,7 @@ import net.minecraft.world.item.component.ItemAttributeModifiers;
import net.minecraft.world.level.Level;
public class PrimordialArmorItem extends ArmorItem {
private static final int BASE_DURABILITY_MULTIPLIER = 33;
private final Type armorType;
public PrimordialArmorItem(Holder<ArmorMaterial> material, Type type, Properties properties) {
@@ -144,10 +145,10 @@ public class PrimordialArmorItem extends ArmorItem {
private static int resolveDurability(Type armorType) {
return switch (armorType) {
case HELMET -> Type.HELMET.getDurability(37);
case CHESTPLATE, BODY -> Type.CHESTPLATE.getDurability(37);
case LEGGINGS -> Type.LEGGINGS.getDurability(37);
case BOOTS -> Type.BOOTS.getDurability(37);
case HELMET -> Type.HELMET.getDurability(BASE_DURABILITY_MULTIPLIER);
case CHESTPLATE, BODY -> Type.CHESTPLATE.getDurability(BASE_DURABILITY_MULTIPLIER);
case LEGGINGS -> Type.LEGGINGS.getDurability(BASE_DURABILITY_MULTIPLIER);
case BOOTS -> Type.BOOTS.getDurability(BASE_DURABILITY_MULTIPLIER);
};
}
}
@@ -1,21 +1,37 @@
package com.craisinlord.antarchy.content.item;
import com.craisinlord.antarchy.content.AntarchyObjects;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.Level;
import java.util.List;
public class SpiritAppleItem extends Item {
public static final int GLIMMERING_DURATION_TICKS = 20 * 8;
public SpiritAppleItem(Properties properties) {
super(properties);
}
@Override
public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity livingEntity) {
ItemStack result = super.finishUsingItem(stack, level, livingEntity);
if (!level.isClientSide()) {
livingEntity.addEffect(new MobEffectInstance(AntarchyObjects.GLIMMERING_EFFECT.get(), GLIMMERING_DURATION_TICKS, 0, false, false, true));
}
return result;
}
@Override
public void appendHoverText(ItemStack stack, Item.TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
tooltipComponents.add(Component.translatable("tooltip.antarchy.spirit_apple").withStyle(ChatFormatting.GRAY));
tooltipComponents.add(Component.translatable("tooltip.antarchy.spirit_apple.eaten").withStyle(ChatFormatting.GRAY));
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
}
}
@@ -0,0 +1,38 @@
package com.craisinlord.antarchy.content.item;
import com.craisinlord.antarchy.content.client.TigerEyeClientHooks;
import java.util.List;
import net.minecraft.ChatFormatting;
import net.minecraft.core.Holder;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ArmorItem;
import net.minecraft.world.item.ArmorMaterial;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
public final class TigerEyeArmorItem extends ArmorItem {
private static final int BASE_DURABILITY_MULTIPLIER = 33;
public TigerEyeArmorItem(Holder<ArmorMaterial> material, Type type, Properties properties) {
super(material, type, properties.stacksTo(1).durability(resolveDurability(type)));
}
@Override
public void appendHoverText(ItemStack stack, Item.TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
tooltipComponents.add(Component.translatable("item.antarchy.tigers_eye_armor.passive").withStyle(ChatFormatting.GOLD));
tooltipComponents.add(Component.translatable("item.antarchy.tigers_eye_armor.full_set").withStyle(ChatFormatting.YELLOW));
tooltipComponents.add(Component.translatable("item.antarchy.tigers_eye_armor.activate", TigerEyeClientHooks.camouflageKeyText()).withStyle(ChatFormatting.GRAY));
tooltipComponents.add(Component.translatable("item.antarchy.tigers_eye_armor.active_bonus").withStyle(ChatFormatting.DARK_AQUA));
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
}
private static int resolveDurability(Type armorType) {
return switch (armorType) {
case HELMET -> Type.HELMET.getDurability(BASE_DURABILITY_MULTIPLIER);
case CHESTPLATE, BODY -> Type.CHESTPLATE.getDurability(BASE_DURABILITY_MULTIPLIER);
case LEGGINGS -> Type.LEGGINGS.getDurability(BASE_DURABILITY_MULTIPLIER);
case BOOTS -> Type.BOOTS.getDurability(BASE_DURABILITY_MULTIPLIER);
};
}
}
@@ -0,0 +1,126 @@
package com.craisinlord.antarchy.content.item;
import com.craisinlord.antarchy.content.AntarchyTags;
import com.craisinlord.antarchy.content.tigereye.TigerEyeCamouflageAccess;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.Vec3;
public final class TigerEyeArmorUtil {
public static final double DETECTION_REDUCTION_PER_PIECE = 0.10D;
public static final double MAX_PASSIVE_REDUCTION = 0.40D;
public static final double WALKING_MULTIPLIER = 0.50D;
public static final double SPRINTING_MULTIPLIER = 0.25D;
public static final double ACTIVE_CAMOUFLAGE_MULTIPLIER = 2.0D;
public static final double MAX_ACTIVE_REDUCTION = 0.80D;
private static final double STATIONARY_HORIZONTAL_SPEED_SQR = 0.0009D;
private TigerEyeArmorUtil() {
}
public static int countEquippedPieces(Player player) {
int count = 0;
for (EquipmentSlot slot : new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET}) {
if (player.getItemBySlot(slot).is(AntarchyTags.Items.TIGER_EYE_ARMOR)) {
count++;
}
}
return count;
}
public static boolean hasFullSet(Player player) {
return player.getItemBySlot(EquipmentSlot.HEAD).is(AntarchyTags.Items.TIGER_EYE_ARMOR)
&& player.getItemBySlot(EquipmentSlot.CHEST).is(AntarchyTags.Items.TIGER_EYE_ARMOR)
&& player.getItemBySlot(EquipmentSlot.LEGS).is(AntarchyTags.Items.TIGER_EYE_ARMOR)
&& player.getItemBySlot(EquipmentSlot.FEET).is(AntarchyTags.Items.TIGER_EYE_ARMOR);
}
public static double getPassiveMaximumReduction(Player player) {
return Math.min(MAX_PASSIVE_REDUCTION, countEquippedPieces(player) * DETECTION_REDUCTION_PER_PIECE);
}
public static double getMovementMultiplier(Player player) {
if (player.isCrouching()) {
return 1.0D;
}
Vec3 delta = player.getDeltaMovement();
double horizontalSpeedSqr = delta.x * delta.x + delta.z * delta.z;
if (horizontalSpeedSqr < STATIONARY_HORIZONTAL_SPEED_SQR) {
return 1.0D;
}
if (player.isSprinting()) {
return SPRINTING_MULTIPLIER;
}
return WALKING_MULTIPLIER;
}
public static double getDetectionReduction(Player player) {
double reduction = getPassiveMaximumReduction(player) * getMovementMultiplier(player);
if (isAdaptiveCamouflageActive(player)) {
reduction = Math.min(MAX_ACTIVE_REDUCTION, reduction * ACTIVE_CAMOUFLAGE_MULTIPLIER);
}
return reduction;
}
public static boolean mayActivateAdaptiveCamouflage(Player player) {
return hasFullSet(player) && !player.isSpectator() && player.isAlive();
}
public static boolean isAdaptiveCamouflageActive(Player player) {
return player instanceof TigerEyeCamouflageAccess access && access.antarchy$isTigerEyeCamouflageActive();
}
public static boolean isValidCamouflageBlock(BlockState state) {
if (state.isAir() || state.is(AntarchyTags.Blocks.TIGER_EYE_CAMOUFLAGE_BLACKLIST)) {
return false;
}
if (state.getRenderShape() == RenderShape.INVISIBLE) {
return false;
}
if (state.is(Blocks.BARRIER) || state.is(Blocks.STRUCTURE_VOID) || state.is(Blocks.LIGHT)) {
return false;
}
if (state.is(Blocks.NETHER_PORTAL) || state.is(Blocks.END_PORTAL) || state.is(Blocks.END_GATEWAY)) {
return false;
}
if (!Block.isShapeFullBlock(state.getShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO))) {
return false;
}
FluidState fluidState = state.getFluidState();
return fluidState == null || fluidState.isEmpty();
}
public static boolean shouldReduceDetection(Mob observer, Player player) {
if (countEquippedPieces(player) <= 0) {
return false;
}
if (observer.getType().is(AntarchyTags.Entities.TIGER_EYE_DETECTION_IMMUNE)) {
return false;
}
if (observer.getTarget() == player || observer.getLastHurtByMob() == player) {
return false;
}
if (observer instanceof net.minecraft.world.entity.NeutralMob neutralMob && neutralMob.isAngryAt(player)) {
return false;
}
return observer.canAttack(player);
}
public static BlockPos getCamouflageSamplePos(Player player) {
double centerX = (player.getBoundingBox().minX + player.getBoundingBox().maxX) * 0.5D;
double centerZ = (player.getBoundingBox().minZ + player.getBoundingBox().maxZ) * 0.5D;
return BlockPos.containing(centerX, player.getBoundingBox().minY - 0.05D, centerZ);
}
}
@@ -0,0 +1,24 @@
package com.craisinlord.antarchy.content.network;
import com.craisinlord.antarchy.Antarchy;
import io.netty.buffer.ByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
public record TigerEyeCamouflageStatePayload(int entityId, boolean active, int blockStateId) implements CustomPacketPayload {
public static final Type<TigerEyeCamouflageStatePayload> TYPE =
new Type<>(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "tiger_eye_camouflage_state"));
public static final StreamCodec<ByteBuf, TigerEyeCamouflageStatePayload> STREAM_CODEC = StreamCodec.composite(
ByteBufCodecs.VAR_INT, TigerEyeCamouflageStatePayload::entityId,
ByteBufCodecs.BOOL, TigerEyeCamouflageStatePayload::active,
ByteBufCodecs.VAR_INT, TigerEyeCamouflageStatePayload::blockStateId,
TigerEyeCamouflageStatePayload::new
);
@Override
public Type<TigerEyeCamouflageStatePayload> type() {
return TYPE;
}
}
@@ -0,0 +1,18 @@
package com.craisinlord.antarchy.content.network;
import com.craisinlord.antarchy.Antarchy;
import io.netty.buffer.ByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
public record ToggleTigerEyeCamouflagePayload() implements CustomPacketPayload {
public static final Type<ToggleTigerEyeCamouflagePayload> TYPE =
new Type<>(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "toggle_tiger_eye_camouflage"));
public static final StreamCodec<ByteBuf, ToggleTigerEyeCamouflagePayload> STREAM_CODEC = StreamCodec.unit(new ToggleTigerEyeCamouflagePayload());
@Override
public Type<ToggleTigerEyeCamouflagePayload> type() {
return TYPE;
}
}
@@ -0,0 +1,11 @@
package com.craisinlord.antarchy.content.tigereye;
public interface TigerEyeCamouflageAccess {
boolean antarchy$isTigerEyeCamouflageActive();
void antarchy$setTigerEyeCamouflageActive(boolean active);
int antarchy$getTigerEyeCamouflageBlockStateId();
void antarchy$setTigerEyeCamouflageBlockStateId(int blockStateId);
}
@@ -0,0 +1,102 @@
package com.craisinlord.antarchy.content.tigereye;
import com.craisinlord.antarchy.content.item.TigerEyeArmorUtil;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.BlockParticleOption;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
public final class TigerEyeCamouflageController {
public enum ToggleResult {
ACTIVATED,
DEACTIVATED,
FULL_SET_REQUIRED,
INVALID_BLOCK,
NO_CHANGE
}
private TigerEyeCamouflageController() {
}
public static ToggleResult toggle(ServerPlayer player) {
if (!(player instanceof TigerEyeCamouflageAccess access)) {
return ToggleResult.NO_CHANGE;
}
if (access.antarchy$isTigerEyeCamouflageActive()) {
deactivate(player, true);
return ToggleResult.DEACTIVATED;
}
if (!TigerEyeArmorUtil.mayActivateAdaptiveCamouflage(player)) {
return ToggleResult.FULL_SET_REQUIRED;
}
BlockPos samplePos = TigerEyeArmorUtil.getCamouflageSamplePos(player);
BlockState state = player.level().getBlockState(samplePos);
if (!TigerEyeArmorUtil.isValidCamouflageBlock(state)) {
return ToggleResult.INVALID_BLOCK;
}
access.antarchy$setTigerEyeCamouflageBlockStateId(Block.getId(state));
access.antarchy$setTigerEyeCamouflageActive(true);
spawnEffects(player, state, true);
return ToggleResult.ACTIVATED;
}
public static boolean validateOrDeactivate(ServerPlayer player) {
if (!(player instanceof TigerEyeCamouflageAccess access) || !access.antarchy$isTigerEyeCamouflageActive()) {
return false;
}
if (TigerEyeArmorUtil.hasFullSet(player)) {
return false;
}
deactivate(player, true);
return true;
}
public static void deactivate(ServerPlayer player, boolean spawnEffects) {
if (!(player instanceof TigerEyeCamouflageAccess access)) {
return;
}
boolean wasActive = access.antarchy$isTigerEyeCamouflageActive();
int blockStateId = access.antarchy$getTigerEyeCamouflageBlockStateId();
access.antarchy$setTigerEyeCamouflageActive(false);
access.antarchy$setTigerEyeCamouflageBlockStateId(0);
if (spawnEffects && wasActive) {
spawnEffects(player, Block.stateById(blockStateId), false);
}
}
private static void spawnEffects(ServerPlayer player, BlockState state, boolean activate) {
if (!(player.level() instanceof ServerLevel serverLevel)) {
return;
}
int count = activate ? 18 : 8;
serverLevel.sendParticles(
new BlockParticleOption(ParticleTypes.BLOCK, state),
player.getX(),
player.getY() + 1.0D,
player.getZ(),
count,
0.35D,
0.6D,
0.35D,
0.03D
);
serverLevel.playSound(
null,
player.blockPosition(),
activate ? SoundEvents.AMETHYST_BLOCK_CHIME : SoundEvents.AMETHYST_BLOCK_HIT,
SoundSource.PLAYERS,
0.8F,
activate ? 0.9F : 0.7F
);
}
}
@@ -0,0 +1,41 @@
package com.craisinlord.antarchy.content.tigereye;
import com.craisinlord.antarchy.content.network.TigerEyeCamouflageStatePayload;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import net.minecraft.server.level.ServerPlayer;
public final class TigerEyeCamouflageSync {
private static BiConsumer<ServerPlayer, TigerEyeCamouflageStatePayload> sendToPlayer = (player, payload) -> {};
private static Consumer<ServerPlayer> syncSelfAndTracking = player -> {};
private TigerEyeCamouflageSync() {
}
public static void setSendToPlayer(BiConsumer<ServerPlayer, TigerEyeCamouflageStatePayload> sender) {
sendToPlayer = sender;
}
public static void setSyncSelfAndTracking(Consumer<ServerPlayer> syncer) {
syncSelfAndTracking = syncer;
}
public static void sync(ServerPlayer player) {
syncSelfAndTracking.accept(player);
}
public static void syncTo(ServerPlayer viewer, ServerPlayer target) {
sendToPlayer.accept(viewer, payload(target));
}
public static TigerEyeCamouflageStatePayload payload(ServerPlayer player) {
if (player instanceof TigerEyeCamouflageAccess access) {
return new TigerEyeCamouflageStatePayload(
player.getId(),
access.antarchy$isTigerEyeCamouflageActive(),
access.antarchy$getTigerEyeCamouflageBlockStateId()
);
}
return new TigerEyeCamouflageStatePayload(player.getId(), false, 0);
}
}
@@ -4,7 +4,7 @@ import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
public record ChitenSpikeConfiguration(
public record ChitinSpikeConfiguration(
int floorToCeilingSearchRange,
int radius,
int maxColumnHeight,
@@ -19,19 +19,19 @@ public record ChitenSpikeConfiguration(
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));
public static final Codec<ChitinSpikeConfiguration> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.intRange(1, 128).fieldOf("floor_to_ceiling_search_range").forGetter(ChitinSpikeConfiguration::floorToCeilingSearchRange),
Codec.intRange(1, 32).fieldOf("radius").forGetter(ChitinSpikeConfiguration::radius),
Codec.intRange(1, 32).fieldOf("max_column_height").forGetter(ChitinSpikeConfiguration::maxColumnHeight),
Codec.intRange(1, 16).fieldOf("height_deviation").forGetter(ChitinSpikeConfiguration::heightDeviation),
Codec.floatRange(0.0F, 1.0F).fieldOf("chance_of_column_at_max_distance_from_center").forGetter(ChitinSpikeConfiguration::chanceOfColumnAtMaxDistanceFromCenter),
Codec.intRange(1, 64).fieldOf("max_distance_from_center_affecting_chance_of_column").forGetter(ChitinSpikeConfiguration::maxDistanceFromCenterAffectingChanceOfColumn),
Codec.intRange(1, 64).fieldOf("max_distance_from_center_affecting_height_bias").forGetter(ChitinSpikeConfiguration::maxDistanceFromCenterAffectingHeightBias),
Codec.intRange(0, 32).fieldOf("max_height_difference").forGetter(ChitinSpikeConfiguration::maxHeightDifference),
Codec.floatRange(0.0F, 1.0F).optionalFieldOf("large_variant_chance", 0.0F).forGetter(ChitinSpikeConfiguration::largeVariantChance),
Codec.intRange(0, 24).optionalFieldOf("large_variant_extra_radius", 0).forGetter(ChitinSpikeConfiguration::largeVariantExtraRadius),
Codec.intRange(0, 32).optionalFieldOf("large_variant_extra_height", 0).forGetter(ChitinSpikeConfiguration::largeVariantExtraHeight),
Codec.intRange(0, 16).optionalFieldOf("large_variant_extra_height_deviation", 0).forGetter(ChitinSpikeConfiguration::largeVariantExtraHeightDeviation),
Codec.floatRange(1.0F, 8.0F).optionalFieldOf("large_variant_surface_spike_multiplier", 1.0F).forGetter(ChitinSpikeConfiguration::largeVariantSurfaceSpikeMultiplier)
).apply(instance, ChitinSpikeConfiguration::new));
}
@@ -18,19 +18,19 @@ 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> {
public final class ChitinSpikeFeature extends Feature<ChitinSpikeConfiguration> {
private record ResolvedVariant(int radius, int maxColumnHeight, int heightDeviation, int surfaceSpikeAttempts) {
}
public ChitenSpikeFeature(Codec<ChitenSpikeConfiguration> codec) {
public ChitinSpikeFeature(Codec<ChitinSpikeConfiguration> codec) {
super(codec);
}
@Override
public boolean place(FeaturePlaceContext<ChitenSpikeConfiguration> context) {
public boolean place(FeaturePlaceContext<ChitinSpikeConfiguration> context) {
WorldGenLevel level = context.level();
BlockPos origin = context.origin();
ChitenSpikeConfiguration config = context.config();
ChitinSpikeConfiguration config = context.config();
RandomSource random = context.random();
if (!level.getBlockState(origin).isAir()) {
@@ -59,7 +59,7 @@ public final class ChitenSpikeFeature extends Feature<ChitenSpikeConfiguration>
return placedAny;
}
private ResolvedVariant resolveVariant(ChitenSpikeConfiguration config, RandomSource random) {
private ResolvedVariant resolveVariant(ChitinSpikeConfiguration config, RandomSource random) {
if (config.largeVariantChance() > 0.0F && random.nextFloat() < config.largeVariantChance()) {
int radius = config.radius() + config.largeVariantExtraRadius();
int maxColumnHeight = config.maxColumnHeight() + config.largeVariantExtraHeight();
@@ -81,7 +81,7 @@ public final class ChitenSpikeFeature extends Feature<ChitenSpikeConfiguration>
int dx,
int dz,
double chance,
ChitenSpikeConfiguration config,
ChitinSpikeConfiguration config,
ResolvedVariant variant,
List<BlockPos> placedBlocks
) {
@@ -114,10 +114,10 @@ public final class ChitenSpikeFeature extends Feature<ChitenSpikeConfiguration>
boolean placedAny = false;
if (ceiling.isPresent() && downLength > 0) {
placedAny |= this.growChitenColumn(level, pos.atY(ceiling.getAsInt() - 1), Direction.DOWN, downLength, placedBlocks);
placedAny |= this.growChitinColumn(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);
placedAny |= this.growChitinColumn(level, pos.atY(floor.getAsInt() + 1), Direction.UP, upLength, placedBlocks);
}
return placedAny;
}
@@ -129,7 +129,7 @@ public final class ChitenSpikeFeature extends Feature<ChitenSpikeConfiguration>
return variant.maxColumnHeight();
}
private boolean growChitenColumn(WorldGenLevel level, BlockPos rootStart, Direction direction, int length, List<BlockPos> placedBlocks) {
private boolean growChitinColumn(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);
@@ -142,8 +142,8 @@ public final class ChitenSpikeFeature extends Feature<ChitenSpikeConfiguration>
break;
}
BlockState chitenState = AntarchyObjects.CHITEN_BLOCK.get().defaultBlockState();
level.setBlock(spikePos, chitenState, 3);
BlockState chitinState = AntarchyObjects.CHITIN_BLOCK.get().defaultBlockState();
level.setBlock(spikePos, chitinState, 3);
placedBlocks.add(spikePos.immutable());
placedAny = true;
}
@@ -154,7 +154,7 @@ public final class ChitenSpikeFeature extends Feature<ChitenSpikeConfiguration>
WorldGenLevel level,
RandomSource random,
List<BlockPos> placedBlocks,
ChitenSpikeConfiguration config,
ChitinSpikeConfiguration config,
ResolvedVariant variant
) {
boolean placedAny = false;
@@ -186,7 +186,7 @@ public final class ChitenSpikeFeature extends Feature<ChitenSpikeConfiguration>
break;
}
BlockState spikeState = AntarchyObjects.CHITEN_SPIKE.get().defaultBlockState()
BlockState spikeState = AntarchyObjects.CHITIN_SPIKE.get().defaultBlockState()
.setValue(PointedDripstoneBlock.TIP_DIRECTION, direction)
.setValue(PointedDripstoneBlock.THICKNESS, getThicknessForRootOffset(offset, length))
.setValue(PointedDripstoneBlock.WATERLOGGED, false);
@@ -238,7 +238,7 @@ public final class ChitenSpikeFeature extends Feature<ChitenSpikeConfiguration>
return Mth.clamp(sampled, 1, maxHeight);
}
private double getChanceOfColumn(int radius, int dx, int dz, ChitenSpikeConfiguration config) {
private double getChanceOfColumn(int radius, int dx, int dz, ChitinSpikeConfiguration config) {
int remainingX = radius - Math.abs(dx);
int remainingZ = radius - Math.abs(dz);
int edgeDistance = Math.min(remainingX, remainingZ);
@@ -0,0 +1,35 @@
package com.craisinlord.antarchy.mixins;
import com.craisinlord.antarchy.content.item.InnateEnchantmentHelper;
import net.minecraft.world.inventory.GrindstoneMenu;
import net.minecraft.world.item.ItemStack;
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.CallbackInfoReturnable;
@Mixin(GrindstoneMenu.class)
public abstract class GrindstoneMenuMixin {
@Inject(method = "removeNonCursesFrom", at = @At("HEAD"), cancellable = true)
private void antarchy$preserveInnateEnchantments(ItemStack stack, CallbackInfoReturnable<ItemStack> cir) {
if (InnateEnchantmentHelper.hasInnateNonCurseEnchantments(stack)) {
cir.setReturnValue(InnateEnchantmentHelper.stripOnlyRemovableNonCurseEnchantments(stack));
}
}
@Inject(method = "computeResult", at = @At("RETURN"), cancellable = true)
private void antarchy$blockInnateOnlyNoOp(ItemStack firstInput, ItemStack secondInput, CallbackInfoReturnable<ItemStack> cir) {
if (!firstInput.isEmpty() && secondInput.isEmpty()
&& InnateEnchantmentHelper.hasInnateNonCurseEnchantments(firstInput)
&& !InnateEnchantmentHelper.hasRemovableNonCurseEnchantments(firstInput)) {
cir.setReturnValue(ItemStack.EMPTY);
return;
}
if (firstInput.isEmpty() && !secondInput.isEmpty()
&& InnateEnchantmentHelper.hasInnateNonCurseEnchantments(secondInput)
&& !InnateEnchantmentHelper.hasRemovableNonCurseEnchantments(secondInput)) {
cir.setReturnValue(ItemStack.EMPTY);
}
}
}
@@ -0,0 +1,32 @@
package com.craisinlord.antarchy.mixins;
import com.craisinlord.antarchy.content.tigereye.TigerEyeCamouflageAccess;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
@Mixin(Player.class)
public abstract class TigerEyeCamouflageMixin implements TigerEyeCamouflageAccess {
@Unique private boolean antarchy$tigerEyeCamouflageActive;
@Unique private int antarchy$tigerEyeCamouflageBlockStateId;
@Override
public boolean antarchy$isTigerEyeCamouflageActive() {
return antarchy$tigerEyeCamouflageActive;
}
@Override
public void antarchy$setTigerEyeCamouflageActive(boolean active) {
antarchy$tigerEyeCamouflageActive = active;
}
@Override
public int antarchy$getTigerEyeCamouflageBlockStateId() {
return antarchy$tigerEyeCamouflageBlockStateId;
}
@Override
public void antarchy$setTigerEyeCamouflageBlockStateId(int blockStateId) {
antarchy$tigerEyeCamouflageBlockStateId = blockStateId;
}
}
@@ -0,0 +1,28 @@
package com.craisinlord.antarchy.mixins;
import com.craisinlord.antarchy.content.item.TigerEyeArmorUtil;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Player;
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.CallbackInfoReturnable;
@Mixin(LivingEntity.class)
public abstract class TigerEyeVisibilityMixin {
@Inject(method = "getVisibilityPercent", at = @At("RETURN"), cancellable = true)
private void antarchy$applyTigerEyeStealth(Entity observer, CallbackInfoReturnable<Double> cir) {
if (!((Object) this instanceof Player player)) {
return;
}
if (!(observer instanceof Mob mob)) {
return;
}
if (!TigerEyeArmorUtil.shouldReduceDetection(mob, player)) {
return;
}
cir.setReturnValue(cir.getReturnValueD() * (1.0D - TigerEyeArmorUtil.getDetectionReduction(player)));
}
}
@@ -4,12 +4,17 @@ import com.craisinlord.antarchy.content.fluid.AntarchyFluidChecks;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.MoverType;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongepowered.asm.mixin.Mixin;
@@ -19,6 +24,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(Entity.class)
/*
@@ -150,6 +156,71 @@ public abstract class EntityMoveMixin {
}
}
@Inject(method = "collide", at = @At("HEAD"), cancellable = true)
private void antarchy$invertedStepUp(Vec3 movement, CallbackInfoReturnable<Vec3> cir) {
Entity entity = (Entity) (Object) this;
if (!AntarchyGravityApi.isGravityInverted(entity)) {
return;
}
AABB aabb = entity.getBoundingBox();
List<VoxelShape> entityShapes = entity.level().getEntityCollisions(entity, aabb.expandTowards(movement));
Vec3 collided = movement.lengthSqr() == 0.0 ? movement : Entity.collideBoundingBox(entity, movement, aabb, entity.level(), entityShapes);
boolean movedX = movement.x != collided.x;
boolean movedY = movement.y != collided.y;
boolean movedZ = movement.z != collided.z;
boolean pressingIntoCeiling = movedY && movement.y > 0.0D;
float maxUpStep = entity.maxUpStep();
if (!(maxUpStep > 0.0F) || !(pressingIntoCeiling || entity.onGround()) || !(movedX || movedZ)) {
cir.setReturnValue(collided);
return;
}
AABB steppedBox = pressingIntoCeiling ? aabb.move(0.0, collided.y, 0.0) : aabb;
AABB searchBox = steppedBox.expandTowards(movement.x, -(double) maxUpStep, movement.z);
if (!pressingIntoCeiling) {
searchBox = searchBox.expandTowards(0.0, 1.0E-5D, 0.0);
}
List<VoxelShape> stepShapes = new ArrayList<>(entityShapes);
entity.level().getBlockCollisions(entity, searchBox).forEach(stepShapes::add);
float currentStepY = (float) collided.y;
float[] candidateHeights = antarchy$collectCandidateStepDownHeights(steppedBox, stepShapes, maxUpStep, currentStepY);
for (float candidate : candidateHeights) {
Vec3 stepped = Entity.collideBoundingBox(entity, new Vec3(movement.x, -(double) candidate, movement.z), steppedBox, entity.level(), stepShapes);
if (stepped.horizontalDistanceSqr() > collided.horizontalDistanceSqr()) {
double offset = steppedBox.maxY - aabb.maxY;
cir.setReturnValue(stepped.add(0.0, offset, 0.0));
return;
}
}
cir.setReturnValue(collided);
}
@Unique
private static float[] antarchy$collectCandidateStepDownHeights(AABB box, List<VoxelShape> shapes, float maxStep, float currentY) {
TreeSet<Float> heights = new TreeSet<>();
for (VoxelShape shape : shapes) {
for (double coord : shape.getCoords(Direction.Axis.Y)) {
float height = (float) (box.maxY - coord);
if (height >= 0.0F && height != currentY && height <= maxStep) {
heights.add(height);
}
}
}
float[] result = new float[heights.size()];
int i = 0;
for (float height : heights) {
result[i++] = height;
}
return result;
}
@Unique
private boolean antarchy$intersectsAntiwater(Entity entity, AABB box) {
BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos();
@@ -21,8 +21,12 @@
"FlintAndSteelPortalIgnitionMixin",
"FrogSpawnVariantMixin",
"FrogVariantBootstrapMixin",
"GlimmeringDamageImmunityMixin",
"GlimmeringPushableMixin",
"GlimmeringPushEntitiesMixin",
"GlowSquidLumenSpawnMixin",
"GlowVinesUnderLeavesMixin",
"GrindstoneMenuMixin",
"MantisClawWallClimbMixin",
"MilkBucketSizeResetMixin",
"MinecartItemMixin",
@@ -38,6 +42,8 @@
"SpongeAntiwaterMixin",
"SquidzookaEnchantMixin",
"SquidzookaMultishotMixin",
"TigerEyeCamouflageMixin",
"TigerEyeVisibilityMixin",
"gravity.AbstractArrowGravityMixin",
"gravity.BucketItemGravityMixin",
"gravity.ChunkMapAccessor",
@@ -85,8 +91,11 @@
"client.MountedVehicleCameraMixin",
"client.ParalyzedMouseTurnMixin",
"client.ScreenEffectRendererFireVisualMixin",
"client.GlimmeringTranslucencyMixin",
"client.SplashManagerMixin",
"client.ThoraxisFogMixin",
"client.TigerEyeArmorHideMixin",
"client.TigerEyeNameTagHideMixin",
"client.WolfRendererGrimMixin",
"gravity.client.CameraGravityMixin",
"gravity.client.ClientPacketListenerGravityMixin",
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -1,16 +0,0 @@
{
"variants": {
"axis=x": {
"model": "antarchy:block/chiten_block",
"x": 90,
"y": 90
},
"axis=y": {
"model": "antarchy:block/chiten_block"
},
"axis=z": {
"model": "antarchy:block/chiten_block",
"x": 90
}
}
}
@@ -0,0 +1,16 @@
{
"variants": {
"axis=x": {
"model": "antarchy:block/chitin_block",
"x": 90,
"y": 90
},
"axis=y": {
"model": "antarchy:block/chitin_block"
},
"axis=z": {
"model": "antarchy:block/chitin_block",
"x": 90
}
}
}
@@ -1,14 +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" }
"thickness=base,vertical_direction=down": { "model": "antarchy:block/chitin_spike_down_base" },
"thickness=base,vertical_direction=up": { "model": "antarchy:block/chitin_spike_up_base" },
"thickness=frustum,vertical_direction=down": { "model": "antarchy:block/chitin_spike_down_frustum" },
"thickness=frustum,vertical_direction=up": { "model": "antarchy:block/chitin_spike_up_frustum" },
"thickness=middle,vertical_direction=down": { "model": "antarchy:block/chitin_spike_down_middle" },
"thickness=middle,vertical_direction=up": { "model": "antarchy:block/chitin_spike_up_middle" },
"thickness=tip,vertical_direction=down": { "model": "antarchy:block/chitin_spike_down_tip" },
"thickness=tip,vertical_direction=up": { "model": "antarchy:block/chitin_spike_up_tip" },
"thickness=tip_merge,vertical_direction=down": { "model": "antarchy:block/chitin_spike_down_tip_merge" },
"thickness=tip_merge,vertical_direction=up": { "model": "antarchy:block/chitin_spike_up_tip_merge" }
}
}
@@ -1,40 +0,0 @@
{
"multipart": [
{
"when": { "up": "true" },
"apply": { "model": "antarchy:block/cut_titanium_wall_post" }
},
{
"when": { "north": "low" },
"apply": { "model": "antarchy:block/cut_titanium_wall_side", "uvlock": true }
},
{
"when": { "east": "low" },
"apply": { "model": "antarchy:block/cut_titanium_wall_side", "y": 90, "uvlock": true }
},
{
"when": { "south": "low" },
"apply": { "model": "antarchy:block/cut_titanium_wall_side", "y": 180, "uvlock": true }
},
{
"when": { "west": "low" },
"apply": { "model": "antarchy:block/cut_titanium_wall_side", "y": 270, "uvlock": true }
},
{
"when": { "north": "tall" },
"apply": { "model": "antarchy:block/cut_titanium_wall_side_tall", "uvlock": true }
},
{
"when": { "east": "tall" },
"apply": { "model": "antarchy:block/cut_titanium_wall_side_tall", "y": 90, "uvlock": true }
},
{
"when": { "south": "tall" },
"apply": { "model": "antarchy:block/cut_titanium_wall_side_tall", "y": 180, "uvlock": true }
},
{
"when": { "west": "tall" },
"apply": { "model": "antarchy:block/cut_titanium_wall_side_tall", "y": 270, "uvlock": true }
}
]
}
@@ -1,40 +0,0 @@
{
"multipart": [
{
"when": { "up": "true" },
"apply": { "model": "antarchy:block/cut_uranium_wall_post" }
},
{
"when": { "north": "low" },
"apply": { "model": "antarchy:block/cut_uranium_wall_side", "uvlock": true }
},
{
"when": { "east": "low" },
"apply": { "model": "antarchy:block/cut_uranium_wall_side", "y": 90, "uvlock": true }
},
{
"when": { "south": "low" },
"apply": { "model": "antarchy:block/cut_uranium_wall_side", "y": 180, "uvlock": true }
},
{
"when": { "west": "low" },
"apply": { "model": "antarchy:block/cut_uranium_wall_side", "y": 270, "uvlock": true }
},
{
"when": { "north": "tall" },
"apply": { "model": "antarchy:block/cut_uranium_wall_side_tall", "uvlock": true }
},
{
"when": { "east": "tall" },
"apply": { "model": "antarchy:block/cut_uranium_wall_side_tall", "y": 90, "uvlock": true }
},
{
"when": { "south": "tall" },
"apply": { "model": "antarchy:block/cut_uranium_wall_side_tall", "y": 180, "uvlock": true }
},
{
"when": { "west": "tall" },
"apply": { "model": "antarchy:block/cut_uranium_wall_side_tall", "y": 270, "uvlock": true }
}
]
}
@@ -0,0 +1,10 @@
{
"variants": {
"lit=false": {
"model": "antarchy:block/lucid_anchor"
},
"lit=true": {
"model": "antarchy:block/lucid_anchor"
}
}
}
@@ -105,6 +105,14 @@
{"origin": [-3, 30, 56], "size": [6, 7, 21], "uv": [70, 0]}
]
},
{
"name": "spike",
"parent": "torso",
"pivot": [0, 39, 2.5],
"cubes": [
{"origin": [-3.5, 29, -3], "size": [7, 20, 11], "uv": [148, 128]}
]
},
{
"name": "neck",
"parent": "torso",
@@ -113,6 +121,14 @@
{"origin": [-9, 13, -24], "size": [18, 19, 16], "uv": [0, 42]}
]
},
{
"name": "spike2",
"parent": "neck",
"pivot": [0, 30, -14.5],
"cubes": [
{"origin": [-3.5, 30, -19], "size": [7, 14, 9], "uv": [129, 49]}
]
},
{
"name": "head",
"parent": "neck",
@@ -123,11 +139,13 @@
{"origin": [-8, 22, -42], "size": [16, 5, 19], "uv": [0, 0]},
{"origin": [0, 27, -42], "size": [0, 13, 9], "uv": [0, 75]},
{"origin": [0, 27, -52], "size": [0, 4, 9], "uv": [0, 70]},
{"origin": [-11, 28, -36], "size": [0, 4, 9], "uv": [0, 70]},
{"origin": [11, 28, -36], "size": [0, 4, 9], "uv": [0, 70], "mirror": true},
{"origin": [-15, 24, -36], "size": [9, 4, 12], "uv": [0, 202]},
{"origin": [6, 24, -36], "size": [9, 4, 12], "uv": [0, 202], "mirror": true},
{"origin": [-6, 18, -54], "size": [12, 5, 12], "inflate": 0.1, "uv": [68, 179]},
{"origin": [-6, 21, -54], "size": [12, 6, 12], "uv": [0, 24]},
{"origin": [-3, 27, -55], "size": [6, 6, 0], "uv": [53, 51]}
{"origin": [-3, 27, -53.75], "size": [6, 6, 0], "uv": [53, 51]}
]
},
{
@@ -869,8 +869,8 @@
"advancements.antarchy.gravity_gun_craft.description": "Stelle eine Gravitationskanone her.",
"block.antarchy.cavaryn_portal": "Cavaryn-Portal",
"block.antarchy.termite_nest": "Termite-Nest",
"block.antarchy.chiten_spike": "Chitin-Stachel",
"block.antarchy.chiten_block": "Chitin-Block",
"block.antarchy.chitin_spike": "Chitin-Stachel",
"block.antarchy.chitin_block": "Chitin-Block",
"block.antarchy.myrmite": "Myrmite",
"block.antarchy.broodstone": "Broodstone",
"block.antarchy.amber_moss_block": "Bernsteinmoosblock",
@@ -896,7 +896,7 @@
"item.antarchy.creeping_horror_spawn_egg": "Kriechender Schrecken-Spawn-Ei",
"item.antarchy.lurking_terror_spawn_egg": "Lauernder Terror-Spawn-Ei",
"item.antarchy.hercules_beetle_spawn_egg": "Herkuleskäfer-Spawn-Ei",
"item.antarchy.chiten": "Chitin",
"item.antarchy.chitin": "Chitin",
"block.antarchy.polished_broodstone": "Poliert Broodstone",
"block.antarchy.chiseled_broodstone": "Gemeißelt Broodstone",
"block.antarchy.broodstone_bricks": "Broodstoneziegel",
@@ -46,6 +46,7 @@
"item.antarchy.critter_cage": "Critter Cage",
"block.antarchy.giant_lily_pad": "Giant Lily Pad",
"block.antarchy.seashell": "Seashell",
"block.antarchy.lucid_anchor": "Lucid Anchor",
"block.antarchy.critter_cage_block": "Critter Cage",
"block.antarchy.hushweed": "Hushweed",
"block.antarchy.umbral_moss_block": "Umbral Moss Block",
@@ -60,6 +61,7 @@
"block.antarchy.polished_nyxite": "Polished Nyxite",
"block.antarchy.chiseled_nyxite": "Chiseled Nyxite",
"block.antarchy.nyxite_bricks": "Nyxite Bricks",
"block.antarchy.nyxite_pillar": "Nyxite Pillar",
"block.antarchy.shellstone": "Shellstone",
"block.antarchy.polished_shellstone": "Polished Shellstone",
"block.antarchy.shellstone_bricks": "Shellstone Bricks",
@@ -69,6 +71,7 @@
"block.antarchy.mossy_shellstone_brick_slab": "Mossy Shellstone Brick Slab",
"block.antarchy.mossy_shellstone_brick_wall": "Mossy Shellstone Brick Wall",
"block.antarchy.cracked_shellstone_bricks": "Cracked Shellstone Bricks",
"block.antarchy.shellstone_pillar": "Shellstone Pillar",
"block.antarchy.shellstone_stairs": "Shellstone Stairs",
"block.antarchy.shellstone_slab": "Shellstone Slab",
"block.antarchy.shellstone_wall": "Shellstone Wall",
@@ -97,12 +100,18 @@
"block.antarchy.cloud_block": "Cloud Block",
"block.antarchy.thoraxis_portal": "Thoraxis Portal",
"block.antarchy.antimetal": "Antimetal",
"block.antarchy.antimetal_stairs": "Antimetal Stairs",
"block.antarchy.antimetal_slab": "Antimetal Slab",
"block.antarchy.polished_antimetal": "Polished Antimetal",
"block.antarchy.polished_antimetal_stairs": "Polished Antimetal Stairs",
"block.antarchy.polished_antimetal_slab": "Polished Antimetal Slab",
"block.antarchy.antimetal_scaffolding": "Antimetal Scaffolding",
"block.antarchy.antimetal_rail": "Antimetal Rail",
"block.antarchy.antimetal_powered_rail": "Antimetal Powered Rail",
"block.antarchy.antimetal_detector_rail": "Antimetal Detector Rail",
"block.antarchy.antimetal_activator_rail": "Antimetal Activator Rail",
"block.antarchy.upper": "Upper",
"container.antarchy.upper": "Upper",
"block.antarchy.cornea_stalk": "Cornea Stalk",
"block.antarchy.corn_crop": "Corn Crop",
"block.antarchy.dream_torch": "Dream Torch",
@@ -118,6 +127,8 @@
"block.antarchy.large_blood_crystal_bud": "Large Blood Crystal Bud",
"block.antarchy.blood_crystal_cluster": "Blood Crystal Cluster",
"block.antarchy.dream_sand": "Dream Sand",
"block.antarchy.antigravel": "Antigravel",
"block.antarchy.loam": "Loam",
"block.antarchy.dream_sandstone": "Dream Sandstone",
"block.antarchy.chiseled_dream_sandstone": "Chiseled Dream Sandstone",
"block.antarchy.cut_dream_sandstone": "Cut Dream Sandstone",
@@ -142,6 +153,7 @@
"block.antarchy.bluestone_repeater": "Bluestone Repeater",
"block.antarchy.bluestone_comparator": "Bluestone Comparator",
"block.antarchy.bluestone_torch": "Bluestone Torch",
"block.antarchy.bluestone_lamp": "Bluestone Lamp",
"block.antarchy.uranium_block": "Block of Uranium",
"block.antarchy.titanium_block": "Block of Titanium",
"block.antarchy.raw_uranium_block": "Block of Raw Uranium",
@@ -236,6 +248,7 @@
"tooltip.antarchy.critter_cage.place": "Shift + click to place",
"item.antarchy.kraken_tooth": "Kraken Tooth",
"item.antarchy.kraken_tentacle": "Kraken Tentacle",
"item.antarchy.kraken_kalamari": "Kraken Calamari",
"item.antarchy.krakens_grasp": "Kraken's Grasp",
"entity.antarchy.tentacle": "Tentacle",
"item.antarchy.basilisk_fang": "Basilisk Fang",
@@ -376,7 +389,6 @@
"key.antarchy.dorrie_charge_jump": "Dorrie Charge Jump",
"key.antarchy.hercules_beetle_charge": "Hercules Beetle Charge",
"key.antarchy.hercules_beetle_flight_toggle": "Hercules Beetle Flight Toggle",
"item.antarchy.carapace": "Carapace",
"item.antarchy.jumpy_bug_leg": "Jumpy Bug Leg",
"item.antarchy.jumpy_boots": "Jumpy Boots",
"tooltip.antarchy.jumpy_boots": "Sneak to charge, then jump to spring upward.",
@@ -459,6 +471,7 @@
"item.antarchy.ouranwood_deer_spawn_egg": "Ouranwood Deer Spawn Egg",
"item.antarchy.spirit_apple": "Spirit Apple",
"tooltip.antarchy.spirit_apple": "Tames a Glimmer",
"tooltip.antarchy.spirit_apple.eaten": "Grants Glimmering when eaten",
"item.antarchy.elka_spawn_egg": "Elka Spawn Egg",
"item.antarchy.glimmer_bottle": "Bottle of Glimmer",
"item.antarchy.glimmer_bottle.contains": "Contains: %s",
@@ -568,6 +581,8 @@
"effect.antarchy.growth": "Growth",
"effect.antarchy.bloodglass_ward": "Bloodglass Ward",
"effect.antarchy.bloodglass_ward.description": "Gives hearts that shatter, absorbing an entire hit of damage. They regenerate over time.",
"effect.antarchy.glimmering": "Glimmering",
"effect.antarchy.glimmering.description": "Passes through entities and attacks unharmed, like a spirit.",
"death.attack.triffid_mauling": "%1$s was mauled to death by a plant",
"death.attack.triffid_mauling.player": "%1$s was mauled to death by a plant",
"death.attack.triffid_swallow": "%1$s was swallowed by a triffid",
@@ -606,9 +621,9 @@
"advancements.antarchy.fallen_kingdom_castle.description": "Discover the Fallen Kingdom Castle.",
"advancements.antarchy.fallen_king_crown.title": "Chunks would load when I gave the word...",
"advancements.antarchy.fallen_king_crown.description": "Obtain the Fallen King\u0027s Crown.",
"advancements.antarchy.the_lab.title": "Hello Everyone, Dan Here!",
"advancements.antarchy.the_lab.title": "Hey everyone, Dan here",
"advancements.antarchy.the_lab.description": "Discover Dr. Trayaurus\u0027 lab.",
"advancements.antarchy.sweater_dreams.title": "Sweater Dreams",
"advancements.antarchy.sweater_dreams.title": "Sweeter Dreams",
"advancements.antarchy.sweater_dreams.description": "Defeat the Nightmare.",
"advancements.antarchy.stone_cold.title": "Stone Cold",
"advancements.antarchy.stone_cold.description": "Defeat a Basilisk.",
@@ -899,15 +914,22 @@
"advancements.antarchy.rocket_powered_octopus.description": "Craft an R.P.O. Launcher.",
"advancements.antarchy.gravity_gun_craft.title": "Pick Up Artist",
"advancements.antarchy.gravity_gun_craft.description": "Craft a Gravity Gun.",
"advancements.antarchy.upper_craft.title": "Uppies?? Uppies!!!",
"advancements.antarchy.upper_craft.description": "Craft an Upper.",
"advancements.antarchy.mucus_obtained.title": "Gazuntite!",
"advancements.antarchy.mucus_obtained.description": "Obtain some Mucus.",
"block.antarchy.cavaryn_portal": "Cavaryn Portal",
"biome.antarchy.cavaryn_moleworm_caves": "Moleworm Caves",
"block.antarchy.termite_nest": "Termite Nest",
"block.antarchy.chiten_spike": "Chiten Spike",
"block.antarchy.chiten_block": "Chiten Block",
"block.antarchy.chitin_spike": "Chitin Spike",
"block.antarchy.chitin_block": "Chitin Block",
"block.antarchy.myrmite": "Myrmite",
"block.antarchy.broodstone": "Broodstone",
"block.antarchy.amber_moss_block": "Amber Moss Block",
"block.antarchy.amber_moss_carpet": "Amber Moss Carpet",
"block.antarchy.amber_lichen": "Amber Lichen",
"block.antarchy.mucus": "Mucus",
"tooltip.antarchy.mucus_slippery": "Makes the block it's on slippery like ice",
"block.antarchy.bile_vein": "Bile Vein",
"block.antarchy.creepvine": "Creepvine",
"block.antarchy.creeping_horror_egg": "Creeping Horror Egg",
@@ -928,7 +950,7 @@
"item.antarchy.creeping_horror_spawn_egg": "Creeping Horror Spawn Egg",
"item.antarchy.lurking_terror_spawn_egg": "Lurking Terror Spawn Egg",
"item.antarchy.hercules_beetle_spawn_egg": "Hercules Beetle Spawn Egg",
"item.antarchy.chiten": "Chiten",
"item.antarchy.chitin": "Chitin",
"block.antarchy.polished_broodstone": "Polished Broodstone",
"block.antarchy.chiseled_broodstone": "Chiseled Broodstone",
"block.antarchy.broodstone_bricks": "Broodstone Bricks",
@@ -941,6 +963,7 @@
"block.antarchy.broodstone_brick_stairs": "Broodstone Brick Stairs",
"block.antarchy.broodstone_brick_slab": "Broodstone Brick Slab",
"block.antarchy.broodstone_brick_wall": "Broodstone Brick Wall",
"block.antarchy.broodstone_pillar": "Broodstone Pillar",
"block.antarchy.myrmite_coal_ore": "Myrmite Coal Ore",
"block.antarchy.broodstone_uranium_ore": "Broodstone Uranium Ore",
"block.antarchy.broodstone_titanium_ore": "Broodstone Titanium Ore",
@@ -1001,5 +1024,26 @@
"advancements.antarchy.beetle_buddies.title": "Beetle Buddies",
"advancements.antarchy.beetle_buddies.description": "Tame a Hercules Beetle.",
"advancements.antarchy.herculean_task.title": "Herculean Task",
"advancements.antarchy.herculean_task.description": "Slay a Hercules Beetle."
"advancements.antarchy.herculean_task.description": "Slay a Hercules Beetle.",
"item.antarchy.tigers_eye": "Tiger's Eye",
"item.antarchy.tigers_eye_helmet": "Tiger's Eye Helmet",
"item.antarchy.tigers_eye_chestplate": "Tiger's Eye Chestplate",
"item.antarchy.tigers_eye_leggings": "Tiger's Eye Leggings",
"item.antarchy.tigers_eye_boots": "Tiger's Eye Boots",
"trim_material.antarchy.tigers_eye": "Tiger's Eye",
"item.antarchy.tigers_eye_armor.passive": "Up to 10% detection reduction",
"item.antarchy.tigers_eye_armor.full_set": "Full Set: Adaptive Camouflage",
"item.antarchy.tigers_eye_armor.activate": "Press %s to mimic the block beneath you",
"item.antarchy.tigers_eye_armor.active_bonus": "Doubles detection reduction while active",
"key.antarchy.tigers_eye_camouflage": "Adaptive Camouflage",
"message.antarchy.tiger_eye_camouflage.activated": "Adaptive Camouflage activated",
"message.antarchy.tiger_eye_camouflage.disabled": "Adaptive Camouflage disabled",
"message.antarchy.tiger_eye_camouflage.full_set_required": "A full set of Tiger's Eye armor is required",
"message.antarchy.tiger_eye_camouflage.invalid_block": "There is no suitable block beneath you",
"music.antarchy.lucid_lullaby": "Lucid Lullaby",
"music.antarchy.lucid_lullaby.credit": "hewo_",
"music.antarchy.venenatus": "Venenatus",
"music.antarchy.venenatus.credit": "hewo_",
"tooltip.antarchy.lucid_anchor.pyramid": "Requires an Antimetal Beacon pyramid above it",
"tooltip.antarchy.lucid_anchor.path": "Projects Inverted downward while it has an unobstructed path to the world below"
}
@@ -869,8 +869,8 @@
"advancements.antarchy.gravity_gun_craft.description": "Fabrica una pistola gravitatoria.",
"block.antarchy.cavaryn_portal": "Portal de Cavaryn",
"block.antarchy.termite_nest": "Nido de Termita",
"block.antarchy.chiten_spike": "Púa de Quitina",
"block.antarchy.chiten_block": "Bloque de Quitina",
"block.antarchy.chitin_spike": "Púa de Quitina",
"block.antarchy.chitin_block": "Bloque de Quitina",
"block.antarchy.myrmite": "Myrmite",
"block.antarchy.broodstone": "Broodstone",
"block.antarchy.amber_moss_block": "Bloque de musgo ámbar",
@@ -896,7 +896,7 @@
"item.antarchy.creeping_horror_spawn_egg": "Huevo generador de Horror rastrero",
"item.antarchy.lurking_terror_spawn_egg": "Huevo generador de Terror acechante",
"item.antarchy.hercules_beetle_spawn_egg": "Huevo generador de Escarabajo hércules",
"item.antarchy.chiten": "Quitina",
"item.antarchy.chitin": "Quitina",
"block.antarchy.polished_broodstone": "Broodstone pulido",
"block.antarchy.chiseled_broodstone": "Broodstone cincelado",
"block.antarchy.broodstone_bricks": "Ladrillos de Broodstone",
@@ -869,8 +869,8 @@
"advancements.antarchy.gravity_gun_craft.description": "Fabriquez un canon à gravité.",
"block.antarchy.cavaryn_portal": "Portail de Cavaryn",
"block.antarchy.termite_nest": "Nid de Termite",
"block.antarchy.chiten_spike": "Pointe de Chitine",
"block.antarchy.chiten_block": "Bloc de Chitine",
"block.antarchy.chitin_spike": "Pointe de Chitine",
"block.antarchy.chitin_block": "Bloc de Chitine",
"block.antarchy.myrmite": "Myrmite",
"block.antarchy.broodstone": "Broodstone",
"block.antarchy.amber_moss_block": "Bloc de mousse ambrée",
@@ -896,7 +896,7 @@
"item.antarchy.creeping_horror_spawn_egg": "Œuf d’apparition de Horreur rampante",
"item.antarchy.lurking_terror_spawn_egg": "Œuf d’apparition de Terreur tapie",
"item.antarchy.hercules_beetle_spawn_egg": "Œuf d’apparition de Scarabée Hercule",
"item.antarchy.chiten": "Chitine",
"item.antarchy.chitin": "Chitine",
"block.antarchy.polished_broodstone": "Broodstone poli",
"block.antarchy.chiseled_broodstone": "Broodstone ciselé",
"block.antarchy.broodstone_bricks": "Briques de Broodstone",
@@ -869,8 +869,8 @@
"advancements.antarchy.gravity_gun_craft.description": "Fabbrica un Cannone gravitazionale.",
"block.antarchy.cavaryn_portal": "Portale per Cavaryn",
"block.antarchy.termite_nest": "Nido di Termite",
"block.antarchy.chiten_spike": "Spuntone di Chiten",
"block.antarchy.chiten_block": "Blocco di Chiten",
"block.antarchy.chitin_spike": "Spuntone di Chiten",
"block.antarchy.chitin_block": "Blocco di Chiten",
"block.antarchy.myrmite": "Myrmite",
"block.antarchy.broodstone": "Broodstone",
"block.antarchy.amber_moss_block": "Blocco di muschio ambrato",
@@ -896,7 +896,7 @@
"item.antarchy.creeping_horror_spawn_egg": "Uovo generatore di Orrore strisciante",
"item.antarchy.lurking_terror_spawn_egg": "Uovo generatore di Terrore in agguato",
"item.antarchy.hercules_beetle_spawn_egg": "Uovo generatore di Scarabeo Ercole",
"item.antarchy.chiten": "Chiten",
"item.antarchy.chitin": "Chiten",
"block.antarchy.polished_broodstone": "Broodstone levigato",
"block.antarchy.chiseled_broodstone": "Broodstone cesellato",
"block.antarchy.broodstone_bricks": "Mattoni di Broodstone",
@@ -869,8 +869,8 @@
"advancements.antarchy.gravity_gun_craft.description": "重力銃をクラフトする。",
"block.antarchy.cavaryn_portal": "カヴァリンのポータル",
"block.antarchy.termite_nest": "シロアリの巣",
"block.antarchy.chiten_spike": "キチンのトゲ",
"block.antarchy.chiten_block": "キチンのブロック",
"block.antarchy.chitin_spike": "キチンのトゲ",
"block.antarchy.chitin_block": "キチンのブロック",
"block.antarchy.myrmite": "ミルマイト",
"block.antarchy.broodstone": "ブルードストーン",
"block.antarchy.amber_moss_block": "琥珀色の苔ブロック",
@@ -896,7 +896,7 @@
"item.antarchy.creeping_horror_spawn_egg": "這い寄る恐怖のスポーンエッグ",
"item.antarchy.lurking_terror_spawn_egg": "潜む恐怖のスポーンエッグ",
"item.antarchy.hercules_beetle_spawn_egg": "ヘラクレスオオカブトのスポーンエッグ",
"item.antarchy.chiten": "キチン",
"item.antarchy.chitin": "キチン",
"block.antarchy.polished_broodstone": "磨かれたブルードストーン",
"block.antarchy.chiseled_broodstone": "模様入りのブルードストーン",
"block.antarchy.broodstone_bricks": "ブルードストーンレンガ",
@@ -869,8 +869,8 @@
"advancements.antarchy.gravity_gun_craft.description": "중력총을 제작하세요.",
"block.antarchy.cavaryn_portal": "카바린 차원문",
"block.antarchy.termite_nest": "흰개미 둥지",
"block.antarchy.chiten_spike": "치텐 가시",
"block.antarchy.chiten_block": "치텐 블록",
"block.antarchy.chitin_spike": "치텐 가시",
"block.antarchy.chitin_block": "치텐 블록",
"block.antarchy.myrmite": "미르마이트",
"block.antarchy.broodstone": "브루드스톤",
"block.antarchy.amber_moss_block": "호박색 이끼 블록",
@@ -896,7 +896,7 @@
"item.antarchy.creeping_horror_spawn_egg": "기어오는 공포 생성 알",
"item.antarchy.lurking_terror_spawn_egg": "도사린 공포 생성 알",
"item.antarchy.hercules_beetle_spawn_egg": "헤라클레스장수풍뎅이 생성 알",
"item.antarchy.chiten": "치텐",
"item.antarchy.chitin": "치텐",
"block.antarchy.polished_broodstone": "윤나는 브루드스톤",
"block.antarchy.chiseled_broodstone": "조각된 브루드스톤",
"block.antarchy.broodstone_bricks": "브루드스톤 벽돌",
@@ -869,8 +869,8 @@
"advancements.antarchy.gravity_gun_craft.description": "Fabrique uma arma gravitacional.",
"block.antarchy.cavaryn_portal": "Portal de Cavaryn",
"block.antarchy.termite_nest": "Ninho de Cupim",
"block.antarchy.chiten_spike": "Espinho de Quitina",
"block.antarchy.chiten_block": "Bloco de Quitina",
"block.antarchy.chitin_spike": "Espinho de Quitina",
"block.antarchy.chitin_block": "Bloco de Quitina",
"block.antarchy.myrmite": "Myrmite",
"block.antarchy.broodstone": "Broodstone",
"block.antarchy.amber_moss_block": "Bloco de Musgo Âmbar",
@@ -896,7 +896,7 @@
"item.antarchy.creeping_horror_spawn_egg": "Ovo Gerador de Horror Rastejante",
"item.antarchy.lurking_terror_spawn_egg": "Ovo Gerador de Terror à Espreita",
"item.antarchy.hercules_beetle_spawn_egg": "Ovo Gerador de Besouro-hércules",
"item.antarchy.chiten": "Quitina",
"item.antarchy.chitin": "Quitina",
"block.antarchy.polished_broodstone": "Broodstone polido",
"block.antarchy.chiseled_broodstone": "Broodstone talhado",
"block.antarchy.broodstone_bricks": "Tijolos de Broodstone",
@@ -869,8 +869,8 @@
"advancements.antarchy.gravity_gun_craft.description": "合成重力枪。",
"block.antarchy.cavaryn_portal": "卡瓦林传送门",
"block.antarchy.termite_nest": "白蚁巢",
"block.antarchy.chiten_spike": "甲壳素尖刺",
"block.antarchy.chiten_block": "甲壳素块",
"block.antarchy.chitin_spike": "甲壳素尖刺",
"block.antarchy.chitin_block": "甲壳素块",
"block.antarchy.myrmite": "米尔迈特",
"block.antarchy.broodstone": "布鲁德斯通",
"block.antarchy.amber_moss_block": "琥珀苔藓块",
@@ -896,7 +896,7 @@
"item.antarchy.creeping_horror_spawn_egg": "爬行恐魔刷怪蛋",
"item.antarchy.lurking_terror_spawn_egg": "潜伏恐魔刷怪蛋",
"item.antarchy.hercules_beetle_spawn_egg": "赫拉克勒斯甲虫刷怪蛋",
"item.antarchy.chiten": "甲壳素",
"item.antarchy.chitin": "甲壳素",
"block.antarchy.polished_broodstone": "磨制布鲁德斯通",
"block.antarchy.chiseled_broodstone": "雕纹布鲁德斯通",
"block.antarchy.broodstone_bricks": "布鲁德斯通砖块",
@@ -869,8 +869,8 @@
"advancements.antarchy.gravity_gun_craft.description": "合成重力槍。",
"block.antarchy.cavaryn_portal": "卡瓦林傳送門",
"block.antarchy.termite_nest": "白蟻巢",
"block.antarchy.chiten_spike": "甲殼素尖刺",
"block.antarchy.chiten_block": "甲殼素塊",
"block.antarchy.chitin_spike": "甲殼素尖刺",
"block.antarchy.chitin_block": "甲殼素塊",
"block.antarchy.myrmite": "米爾邁特",
"block.antarchy.broodstone": "布魯德斯通",
"block.antarchy.amber_moss_block": "琥珀苔蘚塊",
@@ -896,7 +896,7 @@
"item.antarchy.creeping_horror_spawn_egg": "爬行恐魔刷怪蛋",
"item.antarchy.lurking_terror_spawn_egg": "潛伏恐魔刷怪蛋",
"item.antarchy.hercules_beetle_spawn_egg": "赫拉克勒斯甲蟲刷怪蛋",
"item.antarchy.chiten": "甲殼素",
"item.antarchy.chitin": "甲殼素",
"block.antarchy.polished_broodstone": "磨製布魯德斯通",
"block.antarchy.chiseled_broodstone": "雕紋布魯德斯通",
"block.antarchy.broodstone_bricks": "布魯德斯通磚塊",
@@ -1,7 +0,0 @@
{
"parent": "minecraft:block/cube_column",
"textures": {
"end": "antarchy:block/chiten_block",
"side": "antarchy:block/chiten_block"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:block/cube_column",
"textures": {
"end": "antarchy:block/chitin_block",
"side": "antarchy:block/chitin_block"
}
}
@@ -1,6 +1,6 @@
{
"parent": "minecraft:block/pointed_dripstone",
"textures": {
"cross": "antarchy:block/chiten_spike/chiten_spike_down_base"
"cross": "antarchy:block/chitin_spike/chitin_spike_down_base"
}
}
@@ -1,6 +1,6 @@
{
"parent": "minecraft:block/pointed_dripstone",
"textures": {
"cross": "antarchy:block/chiten_spike/chiten_spike_down_frustum"
"cross": "antarchy:block/chitin_spike/chitin_spike_down_frustum"
}
}
@@ -1,6 +1,6 @@
{
"parent": "minecraft:block/pointed_dripstone",
"textures": {
"cross": "antarchy:block/chiten_spike/chiten_spike_down_middle"
"cross": "antarchy:block/chitin_spike/chitin_spike_down_middle"
}
}
Loaded 100 of 264 files, more files were not shown because too many files have changed in this diff. Show more