WIP 1.20.1 port
2 new squirrel anims tons of stuff
This commit is contained in:
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() {
|
||||
}
|
||||
|
||||
+13
-13
@@ -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;
|
||||
}
|
||||
}
|
||||
+17
@@ -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)
|
||||
|
||||
+77
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
+344
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
@@ -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();
|
||||
}
|
||||
}
|
||||
+19
@@ -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();
|
||||
}
|
||||
}
|
||||
+33
-4
@@ -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) {
|
||||
}
|
||||
}
|
||||
+26
@@ -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");
|
||||
}
|
||||
}
|
||||
+13
-3
@@ -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;
|
||||
}
|
||||
}
|
||||
+25
@@ -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");
|
||||
}
|
||||
}
|
||||
+127
@@ -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;
|
||||
}
|
||||
}
|
||||
+13
@@ -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;
|
||||
}
|
||||
}
|
||||
+37
@@ -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);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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,
|
||||
|
||||
+57
@@ -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();
|
||||
}
|
||||
}
|
||||
+146
@@ -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;
|
||||
}
|
||||
}
|
||||
+26
-7
@@ -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);
|
||||
}
|
||||
}
|
||||
+20
@@ -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);
|
||||
|
||||
+1
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+6
@@ -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);
|
||||
|
||||
+18
@@ -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);
|
||||
}
|
||||
}
|
||||
+6
@@ -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);
|
||||
}
|
||||
|
||||
+277
-17
@@ -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 {
|
||||
|
||||
+7
@@ -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;
|
||||
|
||||
+7
@@ -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;
|
||||
|
||||
+7
@@ -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
|
||||
|
||||
+6
-1
@@ -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();
|
||||
}
|
||||
|
||||
+7
@@ -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);
|
||||
|
||||
+1
@@ -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;
|
||||
|
||||
+7
@@ -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);
|
||||
|
||||
+22
@@ -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);
|
||||
}
|
||||
|
||||
+7
@@ -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;
|
||||
|
||||
+25
-5
@@ -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) {
|
||||
|
||||
+34
@@ -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) {
|
||||
|
||||
+7
@@ -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);
|
||||
|
||||
+5
@@ -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);
|
||||
}
|
||||
|
||||
+155
-39
@@ -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
|
||||
|
||||
+6
@@ -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
|
||||
|
||||
+51
-6
@@ -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);
|
||||
}
|
||||
|
||||
+5
-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;
|
||||
|
||||
+2
-1
@@ -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
|
||||
|
||||
+7
-1
@@ -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 {
|
||||
|
||||
|
||||
|
||||
|
||||
+123
@@ -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;
|
||||
}
|
||||
}
|
||||
+613
-63
@@ -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;
|
||||
|
||||
+186
@@ -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;
|
||||
}
|
||||
}
|
||||
+7
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+20
-3
@@ -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);
|
||||
|
||||
+77
@@ -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;
|
||||
}
|
||||
}
|
||||
+23
@@ -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);
|
||||
}
|
||||
}
|
||||
+11
-1
@@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
+5
-4
@@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
+16
@@ -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);
|
||||
}
|
||||
}
|
||||
+38
@@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
+126
@@ -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);
|
||||
}
|
||||
}
|
||||
+24
@@ -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;
|
||||
}
|
||||
}
|
||||
+18
@@ -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;
|
||||
}
|
||||
}
|
||||
+11
@@ -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);
|
||||
}
|
||||
+102
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
+41
@@ -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);
|
||||
}
|
||||
}
|
||||
+16
-16
@@ -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));
|
||||
}
|
||||
+14
-14
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -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;
|
||||
}
|
||||
}
|
||||
+28
@@ -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)));
|
||||
}
|
||||
}
|
||||
+71
@@ -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",
|
||||
|
||||
+1819
-1274
File diff suppressed because it is too large.
Load diff
+174
-1400
File diff suppressed because it is too large.
Load diff
+7833
-1
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
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-10
@@ -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
-1
@@ -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
-1
@@ -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
-1
@@ -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
Reference in new issue
Block a user