blood crystal sounds, fixed variious other sounds. refractored sound folders

This commit is contained in:
craisinlord committed 2026-08-28 09:08:37 -05:00
1 parent 53f223a86c
commit ce66f56c87
350 files changed
+6278 -559

No files matched your search

@@ -82,6 +82,9 @@ public final class AntarchySettings {
private static int bloodCrystalKatanaAttackDamage = 7;
private static double bloodCrystalKatanaLaunchStrength = 1.1D;
private static int bloodCrystalKatanaTrailDurationTicks = 12;
private static double bloodCrystalKatanaReachBonus = 4.0D;
private static int bloodCrystalKatanaInvulnTicks = 8;
private static int bloodCrystalKatanaDashCooldownTicks = 4;
private static double bigBerthaBasiliskCooldownSeconds = 7.0D;
private static double bigBerthaLucidInvertedDurationSeconds = 3.0D;
private static double bigBerthaLucidInvertedDamageBonusPercent = 25.0D;
@@ -226,6 +229,8 @@ public final class AntarchySettings {
private static double diamondMinecartCoastDeceleration = 0.02D;
private static boolean diamondMinecartMobDamageEnabled = false;
private static double diamondMinecartMaxMobDamage = 4.0D;
private static double hoverboardMaxSpeed = 3.0D;
private static double hoverboardAcceleration = 0.05D;
private static boolean dreadHallucinationSoundsEnabled = true;
private static double dreadHallucinationSoundMinInterval = 3.0D;
private static double dreadHallucinationSoundMaxInterval = 10.0D;
@@ -332,6 +337,21 @@ public final class AntarchySettings {
private static double lucidMovementSpeed = 0.22D;
private static double lucidFlyingSpeed = 0.35D;
private static double lucidKnockbackResistance = 0.5D;
private static double vortexHealth = 70.0D;
private static double vortexAttackDamage = 4.0D;
private static double vortexMovementSpeed = 0.22D;
private static double vortexFlyingSpeed = 0.35D;
private static int vortexMaxActiveVortexes = 3;
private static int windVortexDurationTicks = 140;
private static double windVortexPullStrength = 0.32D;
private static double windVortexLaunchStrength = 1.0D;
private static double vortexLensMinRadius = 1.5D;
private static double vortexLensMaxRadius = 10.0D;
private static double vortexLensMinHeight = 3.0D;
private static double vortexLensMaxHeight = 20.0D;
private static double vortexLensPullStrength = 0.42D;
private static double vortexLensPushStrength = 0.38D;
private static double vortexLensLaunchStrength = 1.15D;
private static double missileSquidHealth = 60.0D;
private static double missileSquidAttackDamage = 9.0D;
private static double missileSquidMovementSpeed = 0.84D;
@@ -1861,6 +1881,12 @@ public final class AntarchySettings {
public static double diamondMinecartMaxMobDamage() { return diamondMinecartMaxMobDamage; }
public static void setDiamondMinecartMaxMobDamage(double v) { diamondMinecartMaxMobDamage = v; }
public static double hoverboardMaxSpeed() { return hoverboardMaxSpeed; }
public static void setHoverboardMaxSpeed(double value) { hoverboardMaxSpeed = value; }
public static double hoverboardAcceleration() { return hoverboardAcceleration; }
public static void setHoverboardAcceleration(double value) { hoverboardAcceleration = value; }
public static boolean dreadHallucinationSoundsEnabled() {
return dreadHallucinationSoundsEnabled;
}
@@ -2046,6 +2072,15 @@ public final class AntarchySettings {
public static int bloodCrystalKatanaTrailDurationTicks() { return bloodCrystalKatanaTrailDurationTicks; }
public static void setBloodCrystalKatanaTrailDurationTicks(int value) { bloodCrystalKatanaTrailDurationTicks = value; }
public static double bloodCrystalKatanaReachBonus() { return bloodCrystalKatanaReachBonus; }
public static void setBloodCrystalKatanaReachBonus(double value) { bloodCrystalKatanaReachBonus = value; }
public static int bloodCrystalKatanaInvulnTicks() { return bloodCrystalKatanaInvulnTicks; }
public static void setBloodCrystalKatanaInvulnTicks(int value) { bloodCrystalKatanaInvulnTicks = value; }
public static int bloodCrystalKatanaDashCooldownTicks() { return bloodCrystalKatanaDashCooldownTicks; }
public static void setBloodCrystalKatanaDashCooldownTicks(int value) { bloodCrystalKatanaDashCooldownTicks = value; }
public static double emperorScorpionAttackDamage() { return emperorScorpionAttackDamage; }
public static void setEmperorScorpionAttackDamage(double value) { emperorScorpionAttackDamage = value; }
@@ -2223,6 +2258,51 @@ public final class AntarchySettings {
public static double lucidKnockbackResistance() { return lucidKnockbackResistance; }
public static void setLucidKnockbackResistance(double value) { lucidKnockbackResistance = value; }
public static double vortexHealth() { return vortexHealth; }
public static void setVortexHealth(double value) { vortexHealth = value; }
public static double vortexAttackDamage() { return vortexAttackDamage; }
public static void setVortexAttackDamage(double value) { vortexAttackDamage = value; }
public static double vortexMovementSpeed() { return vortexMovementSpeed; }
public static void setVortexMovementSpeed(double value) { vortexMovementSpeed = value; }
public static double vortexFlyingSpeed() { return vortexFlyingSpeed; }
public static void setVortexFlyingSpeed(double value) { vortexFlyingSpeed = value; }
public static int vortexMaxActiveVortexes() { return vortexMaxActiveVortexes; }
public static void setVortexMaxActiveVortexes(int value) { vortexMaxActiveVortexes = value; }
public static int windVortexDurationTicks() { return windVortexDurationTicks; }
public static void setWindVortexDurationTicks(int value) { windVortexDurationTicks = value; }
public static double windVortexPullStrength() { return windVortexPullStrength; }
public static void setWindVortexPullStrength(double value) { windVortexPullStrength = value; }
public static double windVortexLaunchStrength() { return windVortexLaunchStrength; }
public static void setWindVortexLaunchStrength(double value) { windVortexLaunchStrength = value; }
public static double vortexLensMinRadius() { return vortexLensMinRadius; }
public static void setVortexLensMinRadius(double value) { vortexLensMinRadius = value; }
public static double vortexLensMaxRadius() { return vortexLensMaxRadius; }
public static void setVortexLensMaxRadius(double value) { vortexLensMaxRadius = value; }
public static double vortexLensMinHeight() { return vortexLensMinHeight; }
public static void setVortexLensMinHeight(double value) { vortexLensMinHeight = value; }
public static double vortexLensMaxHeight() { return vortexLensMaxHeight; }
public static void setVortexLensMaxHeight(double value) { vortexLensMaxHeight = value; }
public static double vortexLensPullStrength() { return vortexLensPullStrength; }
public static void setVortexLensPullStrength(double value) { vortexLensPullStrength = value; }
public static double vortexLensPushStrength() { return vortexLensPushStrength; }
public static void setVortexLensPushStrength(double value) { vortexLensPushStrength = value; }
public static double vortexLensLaunchStrength() { return vortexLensLaunchStrength; }
public static void setVortexLensLaunchStrength(double value) { vortexLensLaunchStrength = value; }
public static double missileSquidHealth() { return missileSquidHealth; }
public static void setMissileSquidHealth(double value) { missileSquidHealth = value; }
@@ -17,6 +17,7 @@ import com.craisinlord.antarchy.content.entity.WaspEntity;
import com.craisinlord.antarchy.content.entity.brutalfly.BrutalflyEntity;
import com.craisinlord.antarchy.content.entity.brutalfly.BrutalflyOrbEntity;
import com.craisinlord.antarchy.content.block.entity.HushweedBlockEntity;
import com.craisinlord.antarchy.content.block.entity.VortexLensBlockEntity;
import com.craisinlord.antarchy.content.entity.flying_squirrel.FlyingSquirrelEntity;
import com.craisinlord.antarchy.content.entity.MissileSquidEntity;
import com.craisinlord.antarchy.content.entity.OctopusBombEntity;
@@ -28,6 +29,9 @@ 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.lucid.LucidEntity;
import com.craisinlord.antarchy.content.entity.vortex.VortexChargeProjectileEntity;
import com.craisinlord.antarchy.content.entity.vortex.VortexEntity;
import com.craisinlord.antarchy.content.entity.vortex.WindVortexEntity;
import com.craisinlord.antarchy.content.entity.nightmare.NightmareEntity;
import com.craisinlord.antarchy.content.entity.nightmare.NightmareBiteEntity;
import com.craisinlord.antarchy.content.entity.nightmare.NightmarePortalEntity;
@@ -81,6 +85,16 @@ public final class AntarchyObjects {
@SuppressWarnings("unchecked")
public static Supplier<EntityType<LucidEntity>> LUCID = (Supplier<EntityType<LucidEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<VortexEntity>> VORTEX = (Supplier<EntityType<VortexEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<WindVortexEntity>> WIND_VORTEX = (Supplier<EntityType<WindVortexEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<VortexChargeProjectileEntity>> VORTEX_CHARGE_PROJECTILE = (Supplier<EntityType<VortexChargeProjectileEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> VORTEX_LENS = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<BlockEntityType<VortexLensBlockEntity>> VORTEX_LENS_BLOCK_ENTITY = (Supplier<BlockEntityType<VortexLensBlockEntity>>) 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;
@@ -611,6 +625,26 @@ public final class AntarchyObjects {
LUCID = supplier;
}
public static void setVortex(Supplier<EntityType<VortexEntity>> supplier) {
VORTEX = supplier;
}
public static void setWindVortex(Supplier<EntityType<WindVortexEntity>> supplier) {
WIND_VORTEX = supplier;
}
public static void setVortexChargeProjectile(Supplier<EntityType<VortexChargeProjectileEntity>> supplier) {
VORTEX_CHARGE_PROJECTILE = supplier;
}
public static void setVortexLens(Supplier<Block> supplier) {
VORTEX_LENS = supplier;
}
public static void setVortexLensBlockEntity(Supplier<BlockEntityType<VortexLensBlockEntity>> supplier) {
VORTEX_LENS_BLOCK_ENTITY = supplier;
}
public static void setLotus(Supplier<Block> supplier) {
LOTUS = supplier;
}
@@ -173,6 +173,11 @@ public final class AntarchySoundEvents {
public static Supplier<SoundEvent> JERRY_ADULT_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> JERRY_ADULT_DEATH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> JERRY_ADULT_ATTACK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> WORM_HOOK_FLYING = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BLOOD_CRYSTAL_KATANA_DASH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BLOOD_CRYSTAL_ARMOR_EQUIP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BLOODGLASS_WARD_HEART_BREAK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BLOODGLASS_WARD_HEART_REGEN = (Supplier<SoundEvent>) UNBOUND;
private AntarchySoundEvents() {
}
@@ -341,7 +346,12 @@ public final class AntarchySoundEvents {
Supplier<SoundEvent> jerryAdultIdle,
Supplier<SoundEvent> jerryAdultHurt,
Supplier<SoundEvent> jerryAdultDeath,
Supplier<SoundEvent> jerryAdultAttack
Supplier<SoundEvent> jerryAdultAttack,
Supplier<SoundEvent> wormHookFlying,
Supplier<SoundEvent> bloodCrystalKatanaDash,
Supplier<SoundEvent> bloodCrystalArmorEquip,
Supplier<SoundEvent> bloodglassWardHeartBreak,
Supplier<SoundEvent> bloodglassWardHeartRegen
) {
SQUIDZOOKA_FIRE = squidzookaFire;
SHRINK_RAY_CHARGE = shrinkRayCharge;
@@ -507,5 +517,10 @@ public final class AntarchySoundEvents {
JERRY_ADULT_HURT = jerryAdultHurt;
JERRY_ADULT_DEATH = jerryAdultDeath;
JERRY_ADULT_ATTACK = jerryAdultAttack;
WORM_HOOK_FLYING = wormHookFlying;
BLOOD_CRYSTAL_KATANA_DASH = bloodCrystalKatanaDash;
BLOOD_CRYSTAL_ARMOR_EQUIP = bloodCrystalArmorEquip;
BLOODGLASS_WARD_HEART_BREAK = bloodglassWardHeartBreak;
BLOODGLASS_WARD_HEART_REGEN = bloodglassWardHeartRegen;
}
}
@@ -68,6 +68,7 @@ public final class AntarchyTags {
public static final TagKey<EntityType<?>> GRAVITY_GUN_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("gravity_gun_blacklist"));
public static final TagKey<EntityType<?>> INVERTED_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("inverted_immune"));
public static final TagKey<EntityType<?>> LUCID_BOLT_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("lucid_bolt_immune"));
public static final TagKey<EntityType<?>> WIND_VORTEX_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("wind_vortex_immune"));
public static final TagKey<EntityType<?>> DUCT_TAPE_STICK_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("duct_tape_stick_blacklist"));
public static final TagKey<EntityType<?>> NIGHTMARE_NO_ATTACK = TagKey.create(Registries.ENTITY_TYPE, id("nightmare_no_attack"));
public static final TagKey<EntityType<?>> SIZE_CHANGING_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("size_changing_immune"));
@@ -1,9 +1,14 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.entity.UpwardFallingBlockEntity;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.FallingBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
@@ -25,4 +30,30 @@ public class DreamSandBlock extends FallingBlock {
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
entity.causeFallDamage(fallDistance, 0.0F, level.damageSources().fall());
}
@Override
protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
if (!level.isClientSide) {
level.scheduleTick(pos, this, 2);
}
}
@Override
protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
level.scheduleTick(pos, this, 2);
return state;
}
@Override
protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!level.getBlockState(pos).is(this)) {
return;
}
BlockPos abovePos = pos.above();
BlockState above = level.getBlockState(abovePos);
boolean passable = above.isAir() || above.getCollisionShape(level, abovePos).isEmpty();
if (passable) {
UpwardFallingBlockEntity.fallUp(level, pos, state, false);
}
}
}
@@ -0,0 +1,41 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import java.util.function.Supplier;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.GrowingPlantHeadBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.VoxelShape;
public class SpiralingVinesBlock extends GrowingPlantHeadBlock {
public static final MapCodec<SpiralingVinesBlock> CODEC = simpleCodec(SpiralingVinesBlock::new);
public static final VoxelShape SHAPE = Block.box(4.0D, 0.0D, 4.0D, 12.0D, 16.0D, 12.0D);
public static Supplier<Block> BODY_BLOCK;
public SpiralingVinesBlock(BlockBehaviour.Properties properties) {
super(properties, Direction.UP, SHAPE, false, 0.1D);
}
@Override
public MapCodec<SpiralingVinesBlock> codec() {
return CODEC;
}
@Override
protected int getBlocksToGrowWhenBonemealed(RandomSource random) {
return 1;
}
@Override
protected boolean canGrowInto(BlockState state) {
return state.isAir();
}
@Override
protected Block getBodyBlock() {
return BODY_BLOCK.get();
}
}
@@ -0,0 +1,28 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import java.util.function.Supplier;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.GrowingPlantBodyBlock;
import net.minecraft.world.level.block.GrowingPlantHeadBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
public class SpiralingVinesPlantBlock extends GrowingPlantBodyBlock {
public static final MapCodec<SpiralingVinesPlantBlock> CODEC = simpleCodec(SpiralingVinesPlantBlock::new);
public static Supplier<GrowingPlantHeadBlock> HEAD_BLOCK;
public SpiralingVinesPlantBlock(BlockBehaviour.Properties properties) {
super(properties, Direction.UP, SpiralingVinesBlock.SHAPE, false);
}
@Override
public MapCodec<SpiralingVinesPlantBlock> codec() {
return CODEC;
}
@Override
protected GrowingPlantHeadBlock getHeadBlock() {
return HEAD_BLOCK.get();
}
}
@@ -1,6 +1,7 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.advancement.AntarchyAdvancements;
import com.craisinlord.antarchy.content.worldgen.truffalo.TruffaloTreeGrowers;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
@@ -9,6 +10,7 @@ import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.tags.TagKey;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.BlockGetter;
@@ -22,11 +24,13 @@ import net.minecraft.world.level.block.BushBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class TruffaloSaplingBlock extends BushBlock implements BonemealableBlock {
public static final MapCodec<TruffaloSaplingBlock> CODEC = Block.simpleCodec(TruffaloSaplingBlock::new);
private static final ResourceLocation LET_IT_GROW_ADVANCEMENT = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "let_it_grow");
private static final TagKey<Block> SUPPORTS = TagKey.create(
Registries.BLOCK,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "truffalo_sapling_supports")
@@ -102,6 +106,9 @@ public class TruffaloSaplingBlock extends BushBlock implements BonemealableBlock
level.removeBlock(pos, false);
if (feature.value().place(level, level.getChunkSource().getGenerator(), random, pos)) {
for (ServerPlayer player : level.getEntitiesOfClass(ServerPlayer.class, new AABB(pos).inflate(8.0D))) {
AntarchyAdvancements.award(player, LET_IT_GROW_ADVANCEMENT);
}
return;
}
@@ -0,0 +1,166 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.entity.UpwardFallingBlockEntity;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.item.FallingBlockEntity;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.PointedDripstoneBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.DripstoneThickness;
import net.minecraft.world.level.material.Fluids;
public class TyphoniteSpikeBlock extends PointedDripstoneBlock {
@SuppressWarnings("rawtypes")
public static final MapCodec<PointedDripstoneBlock> CODEC = (MapCodec) Block.simpleCodec(TyphoniteSpikeBlock::new);
public TyphoniteSpikeBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public MapCodec<PointedDripstoneBlock> codec() {
return CODEC;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
LevelAccessor level = context.getLevel();
BlockPos pos = context.getClickedPos();
Direction direction = calculateTipDirection(level, pos, context.getNearestLookingVerticalDirection().getOpposite());
if (direction == null) {
return null;
}
boolean mergeTips = !context.isSecondaryUseActive();
DripstoneThickness thickness = calculateDripstoneThickness(level, pos, direction, mergeTips);
if (thickness == null) {
return null;
}
return this.defaultBlockState()
.setValue(TIP_DIRECTION, direction)
.setValue(THICKNESS, thickness)
.setValue(WATERLOGGED, level.getFluidState(pos).getType() == Fluids.WATER);
}
@Override
protected BlockState updateShape(
BlockState state,
Direction direction,
BlockState neighborState,
LevelAccessor level,
BlockPos pos,
BlockPos neighborPos
) {
if (state.getValue(WATERLOGGED)) {
level.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(level));
}
if (direction != Direction.UP && direction != Direction.DOWN) {
return state;
}
Direction tipDirection = state.getValue(TIP_DIRECTION);
if (tipDirection == Direction.DOWN && level.getBlockTicks().hasScheduledTick(pos, this)) {
return state;
}
if (direction == tipDirection.getOpposite() && !this.canSurvive(state, level, pos)) {
if (tipDirection == Direction.DOWN) {
level.scheduleTick(pos, this, 2);
} else {
level.scheduleTick(pos, this, 1);
}
return state;
}
boolean mergeTips = state.getValue(THICKNESS) == DripstoneThickness.TIP_MERGE;
return state.setValue(THICKNESS, calculateDripstoneThickness(level, pos, tipDirection, mergeTips));
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return isValidPointedDripstonePlacement(level, pos, state.getValue(TIP_DIRECTION));
}
@Override
protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (this.canSurvive(state, level, pos)) {
return;
}
if (state.getValue(TIP_DIRECTION) == Direction.DOWN) {
BlockPos.MutableBlockPos root = pos.mutable();
while (isTyphoniteSpikeWithDirection(level.getBlockState(root.above()), Direction.DOWN)) {
root.move(Direction.UP);
}
BlockPos.MutableBlockPos cursor = root.mutable();
while (isTyphoniteSpikeWithDirection(level.getBlockState(cursor), Direction.DOWN)) {
BlockState fallingState = level.getBlockState(cursor);
if (isTyphoniteSpikeWithDirection(fallingState, Direction.DOWN)) {
FallingBlockEntity.fall(level, cursor, fallingState);
}
cursor.move(Direction.DOWN);
}
return;
}
BlockPos.MutableBlockPos cursor = pos.mutable();
while (isTyphoniteSpikeWithDirection(level.getBlockState(cursor), Direction.UP)) {
BlockState spikeState = level.getBlockState(cursor);
UpwardFallingBlockEntity.fallUp(level, cursor, spikeState);
cursor.move(Direction.UP);
}
}
private static Direction calculateTipDirection(LevelReader level, BlockPos pos, Direction preferredDirection) {
if (isValidPointedDripstonePlacement(level, pos, preferredDirection)) {
return preferredDirection;
}
Direction opposite = preferredDirection.getOpposite();
return isValidPointedDripstonePlacement(level, pos, opposite) ? opposite : null;
}
private static DripstoneThickness calculateDripstoneThickness(LevelReader level, BlockPos pos, Direction direction, boolean mergeTips) {
Direction opposite = direction.getOpposite();
BlockState forwardState = level.getBlockState(pos.relative(direction));
if (isTyphoniteSpikeWithDirection(forwardState, opposite)) {
return !mergeTips && forwardState.getValue(THICKNESS) != DripstoneThickness.TIP_MERGE
? DripstoneThickness.TIP
: DripstoneThickness.TIP_MERGE;
}
if (!isTyphoniteSpikeWithDirection(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 !isTyphoniteSpikeWithDirection(backState, direction) ? DripstoneThickness.BASE : DripstoneThickness.MIDDLE;
}
return DripstoneThickness.FRUSTUM;
}
private static boolean isValidPointedDripstonePlacement(LevelReader level, BlockPos pos, Direction direction) {
BlockPos supportPos = pos.relative(direction.getOpposite());
BlockState supportState = level.getBlockState(supportPos);
return supportState.isFaceSturdy(level, supportPos, direction) || isTyphoniteSpikeWithDirection(supportState, direction);
}
private static boolean isTyphoniteSpikeWithDirection(BlockState state, Direction direction) {
return state.getBlock() instanceof TyphoniteSpikeBlock && state.getValue(TIP_DIRECTION) == direction;
}
}
@@ -0,0 +1,112 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.block.entity.VortexLensBlockEntity;
import com.mojang.serialization.MapCodec;
import java.util.function.Supplier;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext;
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.Mirror;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.Rotation;
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;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import org.jetbrains.annotations.Nullable;
public class VortexLensBlock extends BaseEntityBlock {
public static final DirectionProperty FACING = BlockStateProperties.FACING;
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
private final Supplier<? extends BlockEntityType<VortexLensBlockEntity>> blockEntityTypeSupplier;
private final MapCodec<VortexLensBlock> codec;
public VortexLensBlock(Supplier<? extends BlockEntityType<VortexLensBlockEntity>> blockEntityTypeSupplier,
BlockBehaviour.Properties properties) {
super(properties);
this.blockEntityTypeSupplier = blockEntityTypeSupplier;
this.codec = Block.simpleCodec(ignored -> this);
this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.UP).setValue(POWERED, false));
}
@Override
protected MapCodec<? extends BaseEntityBlock> codec() {
return this.codec;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FACING, POWERED);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return this.defaultBlockState()
.setValue(FACING, context.getClickedFace())
.setValue(POWERED, hasAnySignal(context.getLevel(), context.getClickedPos()));
}
@Override
protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, BlockPos neighborPos,
boolean movedByPiston) {
if (!level.isClientSide && level.getBlockEntity(pos) instanceof VortexLensBlockEntity lens) {
lens.refreshImmediately();
}
}
@Override
protected RenderShape getRenderShape(BlockState state) {
return RenderShape.MODEL;
}
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new VortexLensBlockEntity(pos, state, this.blockEntityTypeSupplier);
}
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state,
BlockEntityType<T> blockEntityType) {
if (level.isClientSide) {
return null;
}
return createTickerHelper(blockEntityType, this.blockEntityTypeSupplier.get(), (tickLevel, tickPos, tickState, blockEntity) -> {
if (tickLevel instanceof net.minecraft.server.level.ServerLevel serverLevel) {
VortexLensBlockEntity.serverTick(serverLevel, tickPos, tickState, blockEntity);
}
});
}
@Override
protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
if (!state.is(newState.getBlock()) && level.getBlockEntity(pos) instanceof VortexLensBlockEntity lens) {
lens.removeActiveVortex();
}
super.onRemove(state, level, pos, newState, movedByPiston);
}
@Override
protected BlockState rotate(BlockState state, Rotation rotation) {
return state.setValue(FACING, rotation.rotate(state.getValue(FACING)));
}
@Override
protected BlockState mirror(BlockState state, Mirror mirror) {
return state.rotate(mirror.getRotation(state.getValue(FACING)));
}
private static boolean hasAnySignal(Level level, BlockPos pos) {
return level.getBestNeighborSignal(pos) > 0 || BluestoneSignalHelper.getBestNeighborSignal(level, pos) > 0;
}
}
@@ -0,0 +1,45 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.BushBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class WhirlflowerBlock extends BushBlock {
public static final MapCodec<WhirlflowerBlock> CODEC = Block.simpleCodec(WhirlflowerBlock::new);
private static final VoxelShape SHAPE = Block.box(3.0D, 0.0D, 3.0D, 13.0D, 13.0D, 13.0D);
private static final ResourceLocation VEINED_TYPHONITE_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "veined_typhonite");
public WhirlflowerBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public MapCodec<WhirlflowerBlock> codec() {
return CODEC;
}
@Override
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
@Override
protected boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos) {
return BuiltInRegistries.BLOCK.getKey(state.getBlock()).equals(VEINED_TYPHONITE_ID);
}
@Override
protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return this.mayPlaceOn(level.getBlockState(pos.below()), level, pos.below());
}
}
@@ -0,0 +1,153 @@
package com.craisinlord.antarchy.content.block.entity;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.block.BluestoneSignalHelper;
import com.craisinlord.antarchy.content.block.VortexLensBlock;
import com.craisinlord.antarchy.content.entity.vortex.WindVortexEntity;
import java.util.UUID;
import java.util.function.Supplier;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
public class VortexLensBlockEntity extends BlockEntity {
private static final String ACTIVE_VORTEX_KEY = "ActiveVortex";
private static final int LENS_VORTEX_REFRESH_DURATION = 40;
@Nullable
private UUID activeVortexUuid;
private boolean refreshNow = true;
public VortexLensBlockEntity(BlockPos pos, BlockState state,
Supplier<? extends BlockEntityType<VortexLensBlockEntity>> typeSupplier) {
super(typeSupplier.get(), pos, state);
}
public static void serverTick(ServerLevel level, BlockPos pos, BlockState state, VortexLensBlockEntity blockEntity) {
blockEntity.tickLens(level, pos, state);
}
public void refreshImmediately() {
this.refreshNow = true;
}
public void removeActiveVortex() {
if (this.level instanceof ServerLevel serverLevel) {
WindVortexEntity vortex = this.getActiveVortex(serverLevel);
if (vortex != null) {
vortex.removeFromLens();
}
}
this.activeVortexUuid = null;
this.setChanged();
}
private void tickLens(ServerLevel level, BlockPos pos, BlockState state) {
if (!this.refreshNow && (level.getGameTime() & 1L) == 1L) {
return;
}
this.refreshNow = false;
int bluestoneSignal = BluestoneSignalHelper.getBestNeighborSignal(level, pos);
int redstoneSignal = level.getBestNeighborSignal(pos);
boolean pushMode = bluestoneSignal > 0;
int signal = pushMode ? bluestoneSignal : redstoneSignal;
if (signal <= 0) {
this.removeActiveVortex();
this.updatePoweredState(level, pos, state, false);
return;
}
WindVortexEntity vortex = this.getOrCreateVortex(level, pos, state);
if (vortex == null) {
return;
}
Direction facing = state.getValue(VortexLensBlock.FACING);
double signalScale = Mth.clamp(signal / 15.0D, 0.0D, 1.0D);
double radius = Mth.lerp(signalScale, AntarchySettings.vortexLensMinRadius(), AntarchySettings.vortexLensMaxRadius());
double height = Mth.lerp(signalScale, AntarchySettings.vortexLensMinHeight(), AntarchySettings.vortexLensMaxHeight());
Vec3 axis = Vec3.atLowerCornerOf(facing.getNormal());
Vec3 origin = Vec3.atCenterOf(pos).add(axis.scale(0.65D));
WindVortexEntity.VortexMode mode = pushMode ? WindVortexEntity.VortexMode.LENS_PUSH : WindVortexEntity.VortexMode.LENS_PULL;
double strength = pushMode ? AntarchySettings.vortexLensPushStrength() : AntarchySettings.vortexLensPullStrength();
vortex.setPos(origin.x, origin.y, origin.z);
vortex.setDeltaMovement(Vec3.ZERO);
vortex.setAxis(facing);
vortex.setMode(mode);
vortex.setVortexSize((float) height, (float) radius);
vortex.setVortexDurationTicks(LENS_VORTEX_REFRESH_DURATION);
vortex.resetVortexAge();
vortex.setVortexStrengths(strength, AntarchySettings.vortexLensLaunchStrength());
vortex.setDamaging(false);
this.updatePoweredState(level, pos, state, true);
}
@Nullable
private WindVortexEntity getOrCreateVortex(ServerLevel level, BlockPos pos, BlockState state) {
WindVortexEntity vortex = this.getActiveVortex(level);
if (vortex != null) {
return vortex;
}
Direction facing = state.getValue(VortexLensBlock.FACING);
Vec3 axis = Vec3.atLowerCornerOf(facing.getNormal());
Vec3 origin = Vec3.atCenterOf(pos).add(axis.scale(0.65D));
vortex = WindVortexEntity.create(level, AntarchyObjects.WIND_VORTEX.get(), origin, Vec3.ZERO, null, false);
vortex.setAxis(facing);
vortex.setMode(WindVortexEntity.VortexMode.LENS_PULL);
vortex.setVortexDurationTicks(LENS_VORTEX_REFRESH_DURATION);
vortex.resetVortexAge();
level.addFreshEntity(vortex);
this.activeVortexUuid = vortex.getUUID();
this.setChanged();
return vortex;
}
@Nullable
private WindVortexEntity getActiveVortex(ServerLevel level) {
if (this.activeVortexUuid == null) {
return null;
}
Entity entity = level.getEntity(this.activeVortexUuid);
if (entity instanceof WindVortexEntity vortex && vortex.isAlive()) {
return vortex;
}
this.activeVortexUuid = null;
this.setChanged();
return null;
}
private void updatePoweredState(ServerLevel level, BlockPos pos, BlockState state, boolean powered) {
if (state.getBlock() instanceof VortexLensBlock && state.getValue(VortexLensBlock.POWERED) != powered) {
level.setBlock(pos, state.setValue(VortexLensBlock.POWERED, powered), Block.UPDATE_CLIENTS);
}
}
@Override
protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.saveAdditional(tag, registries);
if (this.activeVortexUuid != null) {
tag.putUUID(ACTIVE_VORTEX_KEY, this.activeVortexUuid);
}
}
@Override
protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.loadAdditional(tag, registries);
this.activeVortexUuid = tag.hasUUID(ACTIVE_VORTEX_KEY) ? tag.getUUID(ACTIVE_VORTEX_KEY) : null;
}
}
@@ -0,0 +1,275 @@
package com.craisinlord.antarchy.content.client;
import com.craisinlord.antarchy.content.entity.HoverboardEntity;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.BufferUploader;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.MeshData;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.phys.Vec3;
import org.joml.Matrix4f;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
public final class HoverboardTrailSystem {
private static final int MAX_TRAIL_POINTS = 18;
private static final int TRAIL_LIFETIME_TICKS = 12;
private static final float CORE_HALF_WIDTH = 0.0225f;
private static final float GLOW_HALF_WIDTH = 0.055f;
private static final double MIN_DISTANCE_BETWEEN_POINTS = 0.04D;
private static final double LATERAL_OFFSET = 0.34D;
private static final double REAR_OFFSET = 0.52D;
private static final double HEIGHT_OFFSET = 0.14D;
private static final float[] DEFAULT_COLOR = rgb(0xC9A0FF);
private static final Map<Integer, BoardTrails> TRAILS = new HashMap<>();
private HoverboardTrailSystem() {
}
private static final class TrailPoint {
final Vec3 pos;
int age;
TrailPoint(Vec3 pos) {
this.pos = pos;
}
float progress() {
return (float) this.age / (float) TRAIL_LIFETIME_TICKS;
}
boolean expired() {
return this.age >= TRAIL_LIFETIME_TICKS;
}
}
private static final class BoardTrails {
final ArrayDeque<TrailPoint> left = new ArrayDeque<>();
final ArrayDeque<TrailPoint> right = new ArrayDeque<>();
float[] color = DEFAULT_COLOR;
}
public static void tick() {
Minecraft mc = Minecraft.getInstance();
if (mc.level == null) {
TRAILS.clear();
return;
}
if (mc.isPaused()) {
return;
}
Set<Integer> activeIds = new HashSet<>();
for (Entity entity : mc.level.entitiesForRendering()) {
if (!(entity instanceof HoverboardEntity hoverboard)) {
continue;
}
int id = hoverboard.getId();
activeIds.add(id);
BoardTrails boardTrails = TRAILS.computeIfAbsent(id, ignored -> new BoardTrails());
boardTrails.color = colorFor(hoverboard.getColor());
if (hoverboard.isVehicle() && hoverboard.isTrailActive()) {
TrailAnchors anchors = trailAnchors(hoverboard);
addPoint(boardTrails.left, anchors.left());
addPoint(boardTrails.right, anchors.right());
}
age(boardTrails.left);
age(boardTrails.right);
if (boardTrails.left.isEmpty() && boardTrails.right.isEmpty() && !hoverboard.isTrailActive()) {
TRAILS.remove(id);
}
}
TRAILS.keySet().removeIf(id -> !activeIds.contains(id));
}
public static void render(Camera camera, Matrix4f mat) {
if (TRAILS.isEmpty()) {
return;
}
Minecraft mc = Minecraft.getInstance();
if (mc.level == null) {
return;
}
Vec3 camPos = camera.getPosition();
List<TrailSnapshot> snapshots = new ArrayList<>(TRAILS.size() * 2);
for (BoardTrails boardTrails : TRAILS.values()) {
if (boardTrails.left.size() >= 2) {
snapshots.add(new TrailSnapshot(new ArrayList<>(boardTrails.left), boardTrails.color));
}
if (boardTrails.right.size() >= 2) {
snapshots.add(new TrailSnapshot(new ArrayList<>(boardTrails.right), boardTrails.color));
}
}
if (snapshots.isEmpty()) {
return;
}
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
RenderSystem.depthMask(false);
RenderSystem.disableCull();
RenderSystem.setShader(GameRenderer::getPositionColorShader);
Tesselator tesselator = Tesselator.getInstance();
BufferBuilder glowBuf = tesselator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
for (TrailSnapshot snapshot : snapshots) {
buildPass(glowBuf, mat, snapshot.points(), snapshot.color(), camPos, true);
}
MeshData glowMesh = glowBuf.build();
if (glowMesh != null) {
BufferUploader.drawWithShader(glowMesh);
}
BufferBuilder coreBuf = tesselator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
for (TrailSnapshot snapshot : snapshots) {
buildPass(coreBuf, mat, snapshot.points(), snapshot.color(), camPos, false);
}
MeshData coreMesh = coreBuf.build();
if (coreMesh != null) {
BufferUploader.drawWithShader(coreMesh);
}
RenderSystem.enableCull();
RenderSystem.depthMask(true);
RenderSystem.disableBlend();
}
private static void addPoint(ArrayDeque<TrailPoint> points, Vec3 pos) {
if (points.isEmpty()) {
points.addFirst(new TrailPoint(pos));
return;
}
if (points.peekFirst().pos.distanceToSqr(pos) < MIN_DISTANCE_BETWEEN_POINTS * MIN_DISTANCE_BETWEEN_POINTS) {
return;
}
points.addFirst(new TrailPoint(pos));
while (points.size() > MAX_TRAIL_POINTS) {
points.pollLast();
}
}
private static void age(ArrayDeque<TrailPoint> points) {
Iterator<TrailPoint> iterator = points.iterator();
while (iterator.hasNext()) {
TrailPoint point = iterator.next();
point.age++;
if (point.expired()) {
iterator.remove();
}
}
}
private static TrailAnchors trailAnchors(HoverboardEntity hoverboard) {
float yawRad = hoverboard.getYRot() * Mth.DEG_TO_RAD;
Vec3 forward = new Vec3(-Mth.sin(yawRad), 0.0D, Mth.cos(yawRad));
if (forward.lengthSqr() < 1.0E-6D) {
forward = new Vec3(0.0D, 0.0D, 1.0D);
}
forward = forward.normalize();
Vec3 right = new Vec3(forward.z, 0.0D, -forward.x);
Vec3 center = hoverboard.position().add(0.0D, HEIGHT_OFFSET, 0.0D).subtract(forward.scale(REAR_OFFSET));
return new TrailAnchors(center.subtract(right.scale(LATERAL_OFFSET)), center.add(right.scale(LATERAL_OFFSET)));
}
private static void buildPass(BufferBuilder buf, Matrix4f mat, List<TrailPoint> points, float[] color, Vec3 camPos, boolean glow) {
int n = points.size();
for (int i = 0; i < n - 1; i++) {
TrailPoint newer = points.get(i);
TrailPoint older = points.get(i + 1);
float alphaNearer = (glow ? 0.34f : 0.78f) * indexAlpha(i, n) * (1.0f - newer.progress());
float alphaFarther = (glow ? 0.34f : 0.78f) * indexAlpha(i + 1, n) * (1.0f - older.progress());
if (alphaNearer < 0.005f && alphaFarther < 0.005f) {
continue;
}
Vec3 right = cameraFacingRight(newer.pos, older.pos, camPos);
if (right == null) {
continue;
}
right = right.scale(glow ? GLOW_HALF_WIDTH : CORE_HALF_WIDTH);
Vec3 na = newer.pos.subtract(camPos);
Vec3 nb = older.pos.subtract(camPos);
buf.addVertex(mat, (float) (na.x + right.x), (float) (na.y + right.y), (float) (na.z + right.z)).setColor(color[0], color[1], color[2], alphaNearer);
buf.addVertex(mat, (float) (na.x - right.x), (float) (na.y - right.y), (float) (na.z - right.z)).setColor(color[0], color[1], color[2], alphaNearer);
buf.addVertex(mat, (float) (nb.x - right.x), (float) (nb.y - right.y), (float) (nb.z - right.z)).setColor(color[0], color[1], color[2], alphaFarther);
buf.addVertex(mat, (float) (nb.x + right.x), (float) (nb.y + right.y), (float) (nb.z + right.z)).setColor(color[0], color[1], color[2], alphaFarther);
}
}
private static Vec3 cameraFacingRight(Vec3 a, Vec3 b, Vec3 camPos) {
Vec3 segDir = b.subtract(a);
if (segDir.lengthSqr() < 1.0E-12D) {
return null;
}
segDir = segDir.normalize();
Vec3 mid = a.add(b).scale(0.5D);
Vec3 toCamera = camPos.subtract(mid);
if (toCamera.lengthSqr() < 1.0E-12D) {
return null;
}
toCamera = toCamera.normalize();
Vec3 right = segDir.cross(toCamera);
if (right.lengthSqr() < 1.0E-10D) {
right = segDir.cross(new Vec3(0.0D, 1.0D, 0.0D));
if (right.lengthSqr() < 1.0E-10D) {
return null;
}
}
return right.normalize();
}
private static float indexAlpha(int i, int n) {
if (n <= 1) {
return 1.0f;
}
return 1.0f - (float) i / (float) (n - 1);
}
private static float[] colorFor(DyeColor color) {
if (color == null) {
return DEFAULT_COLOR;
}
return rgb(color.getTextureDiffuseColor());
}
private static float[] rgb(int color) {
return new float[] {
((color >> 16) & 255) / 255.0f,
((color >> 8) & 255) / 255.0f,
(color & 255) / 255.0f
};
}
private record TrailAnchors(Vec3 left, Vec3 right) {
}
private record TrailSnapshot(List<TrailPoint> points, float[] color) {
}
}
@@ -0,0 +1,23 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.vortex.VortexEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class VortexModel extends GeoModel<VortexEntity> {
@Override
public ResourceLocation getModelResource(VortexEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/vortex.geo.json");
}
@Override
public ResourceLocation getTextureResource(VortexEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/vortex.png");
}
@Override
public ResourceLocation getAnimationResource(VortexEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/vortex.animation.json");
}
}
@@ -60,7 +60,7 @@ public final class ThoraxisUndersideSkyRenderer {
VertexBuffer skyBuffer
) {
setupFog.run();
if (isFoggy || minecraft.options.hideLightningFlash().get() || minecraft.gameRenderer.getMainCamera() != camera) {
if (minecraft.options.hideLightningFlash().get() || minecraft.gameRenderer.getMainCamera() != camera) {
return;
}
@@ -0,0 +1,19 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.client.model.VortexModel;
import com.craisinlord.antarchy.content.entity.vortex.VortexEntity;
import software.bernie.geckolib.renderer.GeoEntityRenderer;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
public class VortexRenderer extends GeoEntityRenderer<VortexEntity> {
public VortexRenderer(EntityRendererProvider.Context context) {
super(context, new VortexModel());
this.shadowRadius = 0.5F;
this.withScale(0.9F);
}
@Override
protected float getDeathMaxRotation(VortexEntity animatable) {
return 0.0F;
}
}
@@ -0,0 +1,115 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.entity.vortex.WindVortexEntity;
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.EntityRenderer;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
import org.joml.Matrix4f;
public class WindVortexRenderer extends EntityRenderer<WindVortexEntity> {
private static final int RINGS = 8;
private static final int SEGMENTS_PER_RING = 9;
private static final int ARC_STEPS = 4;
private static final float BASE_RADIUS = 0.35F;
public WindVortexRenderer(EntityRendererProvider.Context context) {
super(context);
this.shadowRadius = 0.0F;
}
@Override
public void render(WindVortexEntity entity, float entityYaw, float partialTick, PoseStack poseStack,
MultiBufferSource bufferSource, int packedLight) {
VertexConsumer consumer = bufferSource.getBuffer(RenderType.lightning());
Matrix4f pose = poseStack.last().pose();
float height = entity.getVortexHeight();
float topRadius = entity.getTopRadius();
float age = entity.tickCount + partialTick;
WindVortexEntity.Basis basis = entity.basis();
boolean pull = entity.getMode() == WindVortexEntity.VortexMode.LENS_PULL;
boolean push = entity.getMode() == WindVortexEntity.VortexMode.LENS_PUSH;
float spinDirection = pull ? -1.0F : 1.0F;
for (int ring = 0; ring < RINGS; ring++) {
float progress = (ring + 0.25F) / RINGS;
float axisDistance = progress * height;
float shapeProgress = pull ? 1.0F - progress : progress;
float radius = Mth.lerp(shapeProgress, BASE_RADIUS, topRadius);
float ringSpin = spinDirection * age * (0.13F + progress * 0.045F) + ring * 0.47F;
float alpha = 1.0F;
float thickness = 0.025F + radius * 0.012F;
float arcLength = 0.34F + progress * 0.08F;
int red = push ? 70 : 64;
int green = push ? 220 : 255;
int blue = push ? 255 : 56;
for (int segment = 0; segment < SEGMENTS_PER_RING; segment++) {
float baseAngle = ringSpin + segment * Mth.TWO_PI / SEGMENTS_PER_RING;
float start = baseAngle - arcLength * 0.5F;
float end = baseAngle + arcLength * 0.5F;
drawArc(consumer, pose, basis, radius, axisDistance, thickness, start, end, alpha, red, green, blue);
}
}
super.render(entity, entityYaw, partialTick, poseStack, bufferSource, packedLight);
}
private static void drawArc(VertexConsumer consumer, Matrix4f pose, WindVortexEntity.Basis basis, float radius,
float axisDistance, float thickness, float start, float end, float alpha, int red, int green, int blue) {
float previousAngle = start;
for (int step = 1; step <= ARC_STEPS; step++) {
float angle = Mth.lerp(step / (float) ARC_STEPS, start, end);
addLineQuad(consumer, pose, basis, radius, axisDistance, thickness, previousAngle, angle, alpha, red, green, blue);
previousAngle = angle;
}
}
private static void addLineQuad(VertexConsumer consumer, Matrix4f pose, WindVortexEntity.Basis basis, float radius,
float axisDistance, float thickness, float startAngle, float endAngle, float alpha, int red, int green, int blue) {
org.joml.Vector3f start = point(basis, radius, axisDistance, startAngle);
org.joml.Vector3f end = point(basis, radius, axisDistance, endAngle);
org.joml.Vector3f axisOffset = new org.joml.Vector3f((float) basis.axis.x, (float) basis.axis.y, (float) basis.axis.z).mul(thickness);
float middleAngle = (startAngle + endAngle) * 0.5F;
org.joml.Vector3f radialOffset = new org.joml.Vector3f(
(float) (basis.sideA.x * Mth.cos(middleAngle) + basis.sideB.x * Mth.sin(middleAngle)),
(float) (basis.sideA.y * Mth.cos(middleAngle) + basis.sideB.y * Mth.sin(middleAngle)),
(float) (basis.sideA.z * Mth.cos(middleAngle) + basis.sideB.z * Mth.sin(middleAngle))
).mul(thickness);
int a = Mth.clamp((int) (alpha * 255.0F), 0, 255);
addQuad(consumer, pose, start, end, axisOffset, red, green, blue, a);
addQuad(consumer, pose, start, end, radialOffset, red, green, blue, a);
}
private static void addQuad(VertexConsumer consumer, Matrix4f pose, org.joml.Vector3f start,
org.joml.Vector3f end, org.joml.Vector3f offset, int red, int green, int blue, int alpha) {
addVertex(consumer, pose, start.x - offset.x, start.y - offset.y, start.z - offset.z, red, green, blue, alpha);
addVertex(consumer, pose, end.x - offset.x, end.y - offset.y, end.z - offset.z, red, green, blue, alpha);
addVertex(consumer, pose, end.x + offset.x, end.y + offset.y, end.z + offset.z, red, green, blue, alpha);
addVertex(consumer, pose, start.x + offset.x, start.y + offset.y, start.z + offset.z, red, green, blue, alpha);
}
private static org.joml.Vector3f point(WindVortexEntity.Basis basis, float radius, float axisDistance, float angle) {
double radialA = Mth.cos(angle) * radius;
double radialB = Mth.sin(angle) * radius;
double x = basis.axis.x * axisDistance + basis.sideA.x * radialA + basis.sideB.x * radialB;
double y = basis.axis.y * axisDistance + basis.sideA.y * radialA + basis.sideB.y * radialB;
double z = basis.axis.z * axisDistance + basis.sideA.z * radialA + basis.sideB.z * radialB;
return new org.joml.Vector3f((float) x, (float) y, (float) z);
}
private static void addVertex(VertexConsumer consumer, Matrix4f pose, float x, float y, float z,
int red, int green, int blue, int alpha) {
consumer.addVertex(pose, x, y, z).setColor(red, green, blue, alpha);
}
@Override
public ResourceLocation getTextureLocation(WindVortexEntity entity) {
return ResourceLocation.withDefaultNamespace("textures/misc/unknown_pack.png");
}
}
@@ -197,6 +197,23 @@ 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("typhonite", "building_blocks"),
entry("typhonite_bricks", "building_blocks"),
entry("chiseled_typhonite", "building_blocks"),
entry("polished_typhonite", "building_blocks"),
entry("veined_typhonite", "building_blocks"),
entry("typhonite_spike", "building_blocks"),
entry("typhonite_stairs", "building_blocks"),
entry("typhonite_slab", "building_blocks"),
entry("typhonite_wall", "building_blocks"),
entry("typhonite_brick_stairs", "building_blocks"),
entry("typhonite_brick_slab", "building_blocks"),
entry("typhonite_brick_wall", "building_blocks"),
entry("polished_typhonite_stairs", "building_blocks"),
entry("polished_typhonite_slab", "building_blocks"),
entry("polished_typhonite_wall", "building_blocks"),
entry("spiraling_vines", "natural_blocks"),
entry("whirlflower", "natural_blocks"),
entry("antigravel", "natural_blocks"),
entry("budding_blood_crystal", "building_blocks"),
entry("blood_crystal_block", "building_blocks"),
@@ -270,6 +287,7 @@ public final class CreativeTabContents {
entry("uranium_bars", "building_blocks"),
entry("uranium_bulb", "building_blocks"),
entry("bluestone_block", "redstone_blocks"),
entry("vortex_lens", "redstone_blocks"),
entry("bluestone_repeater", "redstone_blocks"),
entry("bluestone_comparator", "redstone_blocks"),
entry("bluestone_torch", "redstone_blocks"),
@@ -447,7 +465,7 @@ public final class CreativeTabContents {
entry("brutalfly_wing", "ingredients"),
entry("primordial_scute", "ingredients"),
entry("triffid_goo", "ingredients"),
entry("vortex_eye", "ingredients"),
entry("vortex_charge", "ingredients"),
entry("emperor_scorpion_stinger", "ingredients"),
entry("kraken_tooth", "ingredients"),
entry("kraken_tentacle", "ingredients"),
@@ -524,6 +542,7 @@ public final class CreativeTabContents {
entry("nightmare_spawn_egg", "spawn_eggs"),
entry("bed_bug_spawn_egg", "spawn_eggs"),
entry("lucid_spawn_egg", "spawn_eggs"),
entry("vortex_spawn_egg", "spawn_eggs"),
entry("scorpion_spawn_egg", "spawn_eggs"),
entry("basilisk_spawn_egg", "spawn_eggs"),
entry("emperor_scorpion_spawn_egg", "spawn_eggs"),
@@ -0,0 +1,38 @@
package com.craisinlord.antarchy.content.dispenser;
import com.craisinlord.antarchy.content.entity.vortex.VortexChargeProjectileEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.dispenser.BlockSource;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.DispenserBlock;
import net.minecraft.world.level.block.entity.DispenserBlockEntity;
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
public class VortexChargeDispenseBehavior extends DefaultDispenseItemBehavior {
@Override
protected ItemStack execute(BlockSource source, ItemStack stack) {
if (VortexChargeProjectileEntity.defaultItemSupplier == null) {
return super.execute(source, stack);
}
ServerLevel level = source.level();
Direction direction = source.state().getValue(DispenserBlock.FACING);
BlockPos pos = source.pos().relative(direction);
double x = pos.getX() + 0.5D;
double y = pos.getY() + 0.5D;
double z = pos.getZ() + 0.5D;
VortexChargeProjectileEntity projectile = new VortexChargeProjectileEntity(level, x, y, z);
projectile.shoot(direction.getStepX(), direction.getStepY() + 0.1D, direction.getStepZ(), 1.5F, 1.0F);
level.addFreshEntity(projectile);
stack.shrink(1);
return stack;
}
@Override
protected void playSound(BlockSource source) {
source.level().levelEvent(1002, source.pos(), 0);
}
}
@@ -9,6 +9,7 @@ import com.craisinlord.antarchy.content.damage.AntarchyDamageSources;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.Registries;
@@ -162,6 +163,9 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
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());
if (ThoraxisUndersideManager.shouldSpawnInvertedOnDreamSand(level, this.blockPosition())) {
ThoraxisUndersideManager.applyUndersideInversion(this);
}
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
@@ -233,6 +237,9 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
if (!level.getLevel().dimension().equals(THORAXIS_KEY)) {
return false;
}
if (ThoraxisUndersideManager.shouldSpawnInvertedOnDreamSand(level, pos)) {
return level.getDifficulty() != Difficulty.PEACEFUL;
}
return level.getDifficulty() != Difficulty.PEACEFUL
&& Monster.checkMonsterSpawnRules(entityType, level, spawnReason, pos, random);
}
@@ -1,6 +1,10 @@
package com.craisinlord.antarchy.content.entity;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
import com.craisinlord.antarchy.mixins.LivingEntityJumpingAccessor;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@@ -41,13 +45,12 @@ import software.bernie.geckolib.util.GeckoLibUtil;
public class HoverboardEntity extends PathfinderMob implements GeoEntity {
private static final EntityDataAccessor<Integer> COLOR = SynchedEntityData.defineId(HoverboardEntity.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Boolean> TRAIL_ACTIVE = SynchedEntityData.defineId(HoverboardEntity.class, EntityDataSerializers.BOOLEAN);
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
private static final RawAnimation MOVE_ANIM = RawAnimation.begin().thenLoop("move");
private static final double MAX_HOVER_HEIGHT = 5.0D;
private static final double ACCELERATION = 0.08D;
private static final double MAX_SPEED = 1.8D;
private static final double ASCEND_SPEED = 0.15D;
private static final double SETTLE_DESCEND_SPEED = 0.08D;
private static final double DAMPING = 0.955D;
@@ -88,6 +91,7 @@ public class HoverboardEntity extends PathfinderMob implements GeoEntity {
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
builder.define(COLOR, -1);
builder.define(TRAIL_ACTIVE, false);
}
@Nullable
@@ -100,6 +104,14 @@ public class HoverboardEntity extends PathfinderMob implements GeoEntity {
this.entityData.set(COLOR, color == null ? -1 : color.getId());
}
public boolean isTrailActive() {
return this.entityData.get(TRAIL_ACTIVE);
}
private void setTrailActive(boolean active) {
this.entityData.set(TRAIL_ACTIVE, active);
}
@Override
public void addAdditionalSaveData(CompoundTag tag) {
super.addAdditionalSaveData(tag);
@@ -142,7 +154,13 @@ public class HoverboardEntity extends PathfinderMob implements GeoEntity {
if (!this.hasPassenger(passenger)) {
return;
}
moveFunction.accept(passenger, this.getX(), this.getY() + RIDER_Y_OFFSET, this.getZ());
Vec3 riderOffset = AntarchyGravityRotationUtil.vecPlayerToWorld(
0.0D,
RIDER_Y_OFFSET,
0.0D,
AntarchyGravityApi.getGravityDirection(this)
);
moveFunction.accept(passenger, this.getX() + riderOffset.x, this.getY() + riderOffset.y, this.getZ() + riderOffset.z);
}
@Override
@@ -156,15 +174,18 @@ public class HoverboardEntity extends PathfinderMob implements GeoEntity {
Vec3 look = Vec3.directionFromRotation(0.0F, this.getYRot());
float forward = rider.zza;
this.setTrailActive(forward > 0.0F);
boolean holdingJump = ((LivingEntityJumpingAccessor) rider).antarchy$isJumping();
double verticalMotion = this.resolveVerticalMotion(holdingJump);
double acceleration = AntarchySettings.hoverboardAcceleration();
double maxSpeed = AntarchySettings.hoverboardMaxSpeed();
Vec3 currentHorizontal = new Vec3(this.getDeltaMovement().x, 0.0D, this.getDeltaMovement().z);
Vec3 horizontalMotion = currentHorizontal.scale(DAMPING).add(look.scale(forward * ACCELERATION));
Vec3 horizontalMotion = currentHorizontal.scale(DAMPING).add(look.scale(forward * acceleration));
double horizontalSpeed = horizontalMotion.horizontalDistance();
if (horizontalSpeed > MAX_SPEED) {
double scale = MAX_SPEED / horizontalSpeed;
if (horizontalSpeed > maxSpeed) {
double scale = maxSpeed / horizontalSpeed;
horizontalMotion = new Vec3(horizontalMotion.x * scale, 0.0D, horizontalMotion.z * scale);
}
@@ -173,6 +194,7 @@ public class HoverboardEntity extends PathfinderMob implements GeoEntity {
return;
}
this.setTrailActive(false);
double verticalMotion = this.resolveVerticalMotion(false);
Vec3 horizontalMotion = new Vec3(this.getDeltaMovement().x, 0.0D, this.getDeltaMovement().z).scale(DAMPING);
this.setDeltaMovement(horizontalMotion.x, verticalMotion, horizontalMotion.z);
@@ -180,25 +202,44 @@ public class HoverboardEntity extends PathfinderMob implements GeoEntity {
}
private double resolveVerticalMotion(boolean holdingJump) {
double groundHeight = this.findGroundHeight();
double maxY = groundHeight + MAX_HOVER_HEIGHT;
AntarchyGravityDirection gravityDirection = AntarchyGravityApi.getGravityDirection(this);
double supportHeight = this.findSupportHeight(gravityDirection);
if (!gravityDirection.isInverted()) {
double maxY = supportHeight + MAX_HOVER_HEIGHT;
if (this.getY() > maxY) {
return -SETTLE_DESCEND_SPEED;
}
if (holdingJump) {
return this.getY() >= maxY ? 0.0D : ASCEND_SPEED;
}
return this.getY() <= supportHeight ? 0.0D : -SETTLE_DESCEND_SPEED;
}
if (this.getY() > maxY) {
return -SETTLE_DESCEND_SPEED;
double minY = supportHeight - MAX_HOVER_HEIGHT;
if (this.getY() < minY) {
return SETTLE_DESCEND_SPEED;
}
if (holdingJump) {
return this.getY() >= maxY ? 0.0D : ASCEND_SPEED;
return this.getY() <= minY ? 0.0D : -ASCEND_SPEED;
}
return this.getY() <= groundHeight ? 0.0D : -SETTLE_DESCEND_SPEED;
return this.getY() >= supportHeight ? 0.0D : SETTLE_DESCEND_SPEED;
}
private double findGroundHeight() {
private double findSupportHeight(AntarchyGravityDirection gravityDirection) {
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(Mth.floor(this.getX()), Mth.floor(this.getY()), Mth.floor(this.getZ()));
int minY = this.level().getMinBuildHeight();
while (pos.getY() > minY && this.level().getBlockState(pos).isAir()) {
pos.move(Direction.DOWN);
if (!gravityDirection.isInverted()) {
int minY = this.level().getMinBuildHeight();
while (pos.getY() > minY && this.level().getBlockState(pos).isAir()) {
pos.move(Direction.DOWN);
}
return pos.getY() + 1.0D;
}
return pos.getY() + 1.0D;
int maxY = this.level().getMaxBuildHeight() - 1;
while (pos.getY() < maxY && this.level().getBlockState(pos).isAir()) {
pos.move(Direction.UP);
}
return this.level().getBlockState(pos).isAir() ? this.getY() : pos.getY();
}
@Override
@@ -36,8 +36,6 @@ import net.minecraft.world.phys.AABB;
import net.minecraft.world.level.pathfinder.PathType;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.bernie.geckolib.animatable.GeoEntity;
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.animation.AnimatableManager;
@@ -50,7 +48,6 @@ import software.bernie.geckolib.util.GeckoLibUtil;
import java.util.EnumSet;
public class MantisEntity extends Monster implements GeoEntity {
private static final Logger LOGGER = LoggerFactory.getLogger(MantisEntity.class);
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");
@@ -87,7 +84,6 @@ public class MantisEntity extends Monster implements GeoEntity {
protected float committedAttackYaw;
protected boolean attackDamageApplied;
protected boolean attackStartedInFlight;
private int debugLogTicks = 0;
private int configSyncTicks;
public MantisEntity(EntityType<? extends MantisEntity> entityType, Level level) {
@@ -275,7 +271,6 @@ public class MantisEntity extends Monster implements GeoEntity {
this.setNoGravity(this.isFlyingNow());
this.updateAnimationState();
this.tickDebugLog();
}
this.updateFlightRotation();
@@ -574,27 +569,6 @@ public class MantisEntity extends Monster implements GeoEntity {
this.setHealth(syncedHealth);
}
private void tickDebugLog() {
if (++this.debugLogTicks < 100) {
return;
}
this.debugLogTicks = 0;
LivingEntity target = this.getTarget();
int animState = this.getAnimationState();
LOGGER.debug(
"[Mantis id={}] pos={},{},{} target={} anim={} attackTicks={} flyBurst={} flyCooldown={} onGround={} navDone={}",
this.getId(),
(int) this.getX(), (int) this.getY(), (int) this.getZ(),
target != null ? target.getName().getString() : "none",
animState,
this.attackAnimationTicks,
this.flyBurstTicks,
this.flyCooldownTicks,
this.onGround(),
this.getNavigation().isDone()
);
}
private final class MantisCombatGoal extends Goal {
private int repathTicks;
@@ -656,4 +630,3 @@ public class MantisEntity extends Monster implements GeoEntity {
}
@@ -37,6 +37,7 @@ import net.minecraft.world.entity.ai.attributes.AttributeInstance;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.goal.BreedGoal;
import net.minecraft.world.entity.ai.goal.FloatGoal;
import net.minecraft.world.entity.ai.goal.FollowOwnerGoal;
import net.minecraft.world.entity.ai.goal.Goal;
@@ -160,25 +161,26 @@ public class RollyPollyEntity extends TamableAnimal implements GeoEntity {
}
});
this.goalSelector.addGoal(2, new BowlingAttackGoal());
this.goalSelector.addGoal(3, new FertilizeCropGoal());
this.goalSelector.addGoal(4, new EatCompostItemGoal());
this.goalSelector.addGoal(5, new SnuggleOnBedGoal());
this.goalSelector.addGoal(6, new TemptGoal(this, 1.1D, Ingredient.of(AntarchyTags.Items.ROLLY_POLLY_FOOD), false) {
this.goalSelector.addGoal(3, new BreedGoal(this, 1.0D));
this.goalSelector.addGoal(4, new FertilizeCropGoal());
this.goalSelector.addGoal(5, new EatCompostItemGoal());
this.goalSelector.addGoal(6, new SnuggleOnBedGoal());
this.goalSelector.addGoal(7, new TemptGoal(this, 1.1D, Ingredient.of(AntarchyTags.Items.ROLLY_POLLY_FOOD), false) {
@Override
public boolean canUse() {
return !RollyPollyEntity.this.isRolled() && super.canUse();
}
});
this.goalSelector.addGoal(7, new FollowOwnerGoal(this, 1.1D, 10.0F, 2.0F));
this.goalSelector.addGoal(8, new RollingStrollGoal());
this.goalSelector.addGoal(9, new WaterAvoidingRandomStrollGoal(this, 1.0D) {
this.goalSelector.addGoal(8, new FollowOwnerGoal(this, 1.1D, 10.0F, 2.0F));
this.goalSelector.addGoal(9, new RollingStrollGoal());
this.goalSelector.addGoal(10, new WaterAvoidingRandomStrollGoal(this, 1.0D) {
@Override
public boolean canUse() {
return !RollyPollyEntity.this.isRolled() && super.canUse();
}
});
this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Player.class, 8.0F));
this.goalSelector.addGoal(11, new RandomLookAroundGoal(this));
this.goalSelector.addGoal(11, new LookAtPlayerGoal(this, Player.class, 8.0F));
this.goalSelector.addGoal(12, new RandomLookAroundGoal(this));
this.targetSelector.addGoal(1, new OwnerHurtByTargetGoal(this));
this.targetSelector.addGoal(2, new OwnerHurtTargetGoal(this));
}
@@ -192,7 +194,8 @@ public class RollyPollyEntity extends TamableAnimal implements GeoEntity {
public InteractionResult mobInteract(Player player, InteractionHand hand) {
ItemStack stack = player.getItemInHand(hand);
if (this.isFood(stack) && (!this.isTame() || this.getHealth() < this.getMaxHealth())) {
if (this.isFood(stack) && (!this.isTame() || this.getHealth() < this.getMaxHealth()
|| (this.canFallInLove() && !this.isBaby()))) {
if (!this.level().isClientSide) {
if (!player.getAbilities().instabuild) {
stack.shrink(1);
@@ -210,9 +213,11 @@ public class RollyPollyEntity extends TamableAnimal implements GeoEntity {
} else {
this.level().broadcastEntityEvent(this, (byte) 6);
}
} else {
} else if (this.getHealth() < this.getMaxHealth()) {
this.heal(4.0F);
this.level().broadcastEntityEvent(this, (byte) 7);
} else {
this.setInLove(player);
}
}
return InteractionResult.sidedSuccess(this.level().isClientSide);
@@ -239,7 +244,7 @@ public class RollyPollyEntity extends TamableAnimal implements GeoEntity {
@Override
@Nullable
public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob otherParent) {
return null;
return com.craisinlord.antarchy.content.AntarchyObjects.ROLLY_POLLY.get().create(level);
}
private static boolean isCompostable(ItemStack stack) {
@@ -5,6 +5,7 @@ import com.craisinlord.antarchy.content.AntarchySoundEvents;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
@@ -97,6 +98,9 @@ public class ScorpionEntity extends Monster implements GeoEntity {
|| spawnReason == MobSpawnType.COMMAND) {
return true;
}
if (ThoraxisUndersideManager.shouldSpawnInvertedOnDreamSand(level, pos)) {
return level.getDifficulty() != Difficulty.PEACEFUL;
}
return level.getDifficulty() != Difficulty.PEACEFUL
&& Monster.checkMonsterSpawnRules(entityType, level, spawnReason, pos, random);
}
@@ -123,6 +127,9 @@ public class ScorpionEntity extends Monster implements GeoEntity {
public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, MobSpawnType spawnType, @Nullable SpawnGroupData spawnGroupData) {
this.assignRandomTextureVariant();
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.scorpionHealth());
if (ThoraxisUndersideManager.shouldSpawnInvertedOnDreamSand(level, this.blockPosition())) {
ThoraxisUndersideManager.applyUndersideInversion(this);
}
return super.finalizeSpawn(level, difficulty, spawnType, spawnGroupData);
}
@@ -51,6 +51,10 @@ public class UpwardFallingBlockEntity extends Entity {
return this.entityData.get(DATA_BLOCK_STATE);
}
protected double getRiseAccel() {
return RISE_ACCEL;
}
public static void fallUp(Level level, BlockPos pos, BlockState state) {
fallUp(level, pos, state, true);
}
@@ -82,7 +86,7 @@ public class UpwardFallingBlockEntity extends Entity {
}
double beforeY = getY();
setDeltaMovement(getDeltaMovement().add(0.0, RISE_ACCEL, 0.0));
setDeltaMovement(getDeltaMovement().add(0.0, getRiseAccel(), 0.0));
move(MoverType.SELF, getDeltaMovement());
setDeltaMovement(getDeltaMovement().scale(DRAG));
distanceTraveled += Math.max(0.0, getY() - beforeY);
@@ -0,0 +1,69 @@
package com.craisinlord.antarchy.content.entity.vortex;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.projectile.ThrowableItemProjectile;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import java.util.function.Supplier;
public class VortexChargeProjectileEntity extends ThrowableItemProjectile {
public static Supplier<Item> defaultItemSupplier;
public static Supplier<EntityType<VortexChargeProjectileEntity>> projectileTypeSupplier;
public static Supplier<EntityType<WindVortexEntity>> windVortexTypeSupplier;
public VortexChargeProjectileEntity(EntityType<? extends VortexChargeProjectileEntity> entityType, Level level) {
super(entityType, level);
}
public VortexChargeProjectileEntity(EntityType<? extends VortexChargeProjectileEntity> entityType,
LivingEntity thrower, Level level) {
super(entityType, thrower, level);
}
public VortexChargeProjectileEntity(Level level, double x, double y, double z) {
super(projectileTypeSupplier.get(), x, y, z, level);
}
@Override
protected double getDefaultGravity() {
return 0.03D;
}
@Override
protected Item getDefaultItem() {
return defaultItemSupplier != null ? defaultItemSupplier.get() : Items.WIND_CHARGE;
}
@Override
protected void onHit(HitResult hitResult) {
super.onHit(hitResult);
if (this.level() instanceof ServerLevel serverLevel && windVortexTypeSupplier != null) {
Vec3 position = hitResult.getLocation();
WindVortexEntity vortex = WindVortexEntity.create(
serverLevel,
windVortexTypeSupplier.get(),
position,
this.getDeltaMovement().normalize().scale(0.035D),
null,
false
);
serverLevel.addFreshEntity(vortex);
serverLevel.playSound(null, position.x, position.y, position.z,
SoundEvents.BREEZE_WIND_CHARGE_BURST, SoundSource.PLAYERS, 0.9F, 1.0F);
}
if (!this.level().isClientSide) {
this.level().broadcastEntityEvent(this, (byte) 3);
this.discard();
}
}
}
@@ -0,0 +1,427 @@
package com.craisinlord.antarchy.content.entity.vortex;
import com.craisinlord.antarchy.config.AntarchySettings;
import net.minecraft.core.BlockPos;
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.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.Difficulty;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.entity.MoverType;
import net.minecraft.world.entity.SpawnGroupData;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.control.FlyingMoveControl;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation;
import net.minecraft.world.entity.ai.navigation.PathNavigation;
import net.minecraft.world.entity.ai.util.HoverRandomPos;
import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
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.EnumSet;
import java.util.function.Supplier;
public class VortexEntity extends Monster implements GeoEntity {
private static final EntityDataAccessor<Integer> ANIMATION_STATE =
SynchedEntityData.defineId(VortexEntity.class, EntityDataSerializers.INT);
private static final int ANIM_IDLE = 0;
private static final int ANIM_FLY = 1;
private static final int ANIM_ATTACK = 2;
private static final int ANIM_DEATH = 3;
private static final String ATTACK_COOLDOWN_KEY = "AttackCooldown";
private static final String ATTACK_TICKS_KEY = "AttackTicks";
private static final int ATTACK_WINDUP_TICKS = 18;
private static final int ATTACK_RECOVERY_TICKS = 12;
private static final int ATTACK_COOLDOWN_TICKS = 70;
private static final int DEATH_TICKS = 15;
private static final double ATTACK_RANGE = 14.0D;
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
private static final RawAnimation FLY_ANIM = RawAnimation.begin().thenLoop("walk");
private static final RawAnimation ATTACK_ANIM = RawAnimation.begin().thenPlay("wind_gust");
private static final RawAnimation DEATH_ANIM = RawAnimation.begin().thenPlay("death");
public static Supplier<EntityType<WindVortexEntity>> windVortexTypeSupplier;
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
private int attackCooldown;
private int attackTicks;
private boolean spawnedAttackVortex;
public VortexEntity(EntityType<? extends VortexEntity> entityType, Level level) {
super(entityType, level);
this.moveControl = new FlyingMoveControl(this, 2, true);
this.xpReward = 10;
}
public static AttributeSupplier.Builder createAttributes() {
return Mob.createMobAttributes()
.add(Attributes.MAX_HEALTH, AntarchySettings.vortexHealth())
.add(Attributes.ATTACK_DAMAGE, AntarchySettings.vortexAttackDamage())
.add(Attributes.MOVEMENT_SPEED, AntarchySettings.vortexMovementSpeed())
.add(Attributes.FLYING_SPEED, AntarchySettings.vortexFlyingSpeed())
.add(Attributes.FOLLOW_RANGE, 40.0D)
.add(Attributes.KNOCKBACK_RESISTANCE, 0.45D);
}
public static boolean canSpawn(EntityType<VortexEntity> entityType, ServerLevelAccessor level,
MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
return level.getDifficulty() != Difficulty.PEACEFUL
&& level.isEmptyBlock(pos)
&& level.isEmptyBlock(pos.above())
&& level.isEmptyBlock(pos.above(2));
}
@Override
public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, net.minecraft.world.DifficultyInstance difficulty,
MobSpawnType spawnReason, SpawnGroupData spawnData) {
com.craisinlord.antarchy.content.entity.ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.vortexHealth());
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
builder.define(ANIMATION_STATE, ANIM_IDLE);
}
@Override
protected void registerGoals() {
this.goalSelector.addGoal(1, new VortexPatrolGoal());
this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers());
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 20, true, false, this::canTargetEntity));
}
@Override
protected PathNavigation createNavigation(Level level) {
FlyingPathNavigation nav = new FlyingPathNavigation(this, level);
nav.setCanOpenDoors(false);
nav.setCanFloat(true);
nav.setCanPassDoors(true);
return nav;
}
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
controllers.add(new AnimationController<>(this, "main_controller", 0, this::mainAnimController)
.triggerableAnim("attack", ATTACK_ANIM)
.triggerableAnim("death", DEATH_ANIM));
}
private PlayState mainAnimController(AnimationState<VortexEntity> state) {
return switch (this.getAnimationState()) {
case ANIM_FLY -> state.setAndContinue(FLY_ANIM);
case ANIM_ATTACK -> state.setAndContinue(ATTACK_ANIM);
case ANIM_DEATH -> state.setAndContinue(DEATH_ANIM);
default -> state.setAndContinue(IDLE_ANIM);
};
}
@Override
public AnimatableInstanceCache getAnimatableInstanceCache() {
return this.geoCache;
}
@Override
public void tick() {
super.tick();
this.setNoGravity(true);
if (this.level().isClientSide) {
return;
}
if (this.isDeadOrDying()) {
this.updateAnimationState();
return;
}
if (this.attackCooldown > 0) {
this.attackCooldown--;
}
LivingEntity target = this.getTarget();
if (this.attackTicks > 0) {
this.tickAttack(target);
this.updateAnimationState();
return;
}
if (target != null && this.canTargetEntity(target)) {
this.tickCombatMovement(target);
}
this.updateAnimationState();
}
@Override
public void travel(Vec3 travelVector) {
if (this.isEffectiveAi() || this.isNoGravity()) {
this.moveRelative(this.getSpeed(), travelVector);
this.move(MoverType.SELF, this.getDeltaMovement());
this.setDeltaMovement(this.getDeltaMovement().scale(0.91D));
return;
}
super.travel(travelVector);
}
private void tickCombatMovement(LivingEntity target) {
this.faceTowards(target.position().add(0.0D, target.getBbHeight() * 0.5D, 0.0D), 12.0F, 8.0F);
this.getMoveControl().setWantedPosition(target.getX(), target.getY() + 2.5D, target.getZ(), 0.38D);
if (this.attackCooldown <= 0
&& this.distanceToSqr(target) <= ATTACK_RANGE * ATTACK_RANGE
&& this.hasLineOfSight(target)
&& this.countOwnedActiveVortexes() < AntarchySettings.vortexMaxActiveVortexes()) {
this.startAttack();
}
}
private void startAttack() {
this.attackTicks = ATTACK_WINDUP_TICKS + ATTACK_RECOVERY_TICKS;
this.spawnedAttackVortex = false;
this.attackCooldown = ATTACK_COOLDOWN_TICKS;
this.getNavigation().stop();
}
private void tickAttack(@Nullable LivingEntity target) {
this.getNavigation().stop();
this.setDeltaMovement(this.getDeltaMovement().scale(0.84D));
if (target == null || !this.canTargetEntity(target)) {
this.attackTicks = 0;
this.spawnedAttackVortex = false;
return;
}
this.faceTowards(target.getEyePosition(), 16.0F, 10.0F);
this.getMoveControl().setWantedPosition(this.getX(), Math.max(this.getY(), target.getY() + 2.5D), this.getZ(), 0.34D);
int elapsed = ATTACK_WINDUP_TICKS + ATTACK_RECOVERY_TICKS - this.attackTicks;
if (!this.spawnedAttackVortex && elapsed >= ATTACK_WINDUP_TICKS) {
this.spawnAttackVortex(target);
this.spawnedAttackVortex = true;
}
if (--this.attackTicks <= 0) {
this.attackTicks = 0;
}
}
private void spawnAttackVortex(LivingEntity target) {
if (!(this.level() instanceof ServerLevel serverLevel) || windVortexTypeSupplier == null) {
return;
}
Vec3 targetPos = target.position();
Vec3 fromMob = targetPos.subtract(this.position());
Vec3 drift = fromMob.lengthSqr() > 1.0E-6D ? fromMob.normalize().scale(0.045D) : this.getViewVector(0.0F).scale(0.045D);
Vec3 position = targetPos.add(
(this.random.nextDouble() - 0.5D) * 1.6D,
0.05D,
(this.random.nextDouble() - 0.5D) * 1.6D
);
WindVortexEntity vortex = WindVortexEntity.create(serverLevel, windVortexTypeSupplier.get(), position, drift, this, true);
serverLevel.addFreshEntity(vortex);
serverLevel.playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.BREEZE_SHOOT, this.getSoundSource(), 1.0F, 0.9F);
}
private int countOwnedActiveVortexes() {
if (!(this.level() instanceof ServerLevel serverLevel) || windVortexTypeSupplier == null) {
return 0;
}
return serverLevel.getEntities(windVortexTypeSupplier.get(), this.getBoundingBox().inflate(32.0D),
vortex -> vortex.isAlive() && vortex.isDamaging() && vortex.isOwnedBy(this)).size();
}
private void faceTowards(Vec3 targetPos, float maxYawStep, float maxPitchStep) {
Vec3 delta = targetPos.subtract(this.getEyePosition());
double horizontal = Math.sqrt(delta.x * delta.x + delta.z * delta.z);
if (horizontal < 1.0E-6D && Math.abs(delta.y) < 1.0E-6D) {
return;
}
float targetYaw = (float) (Mth.atan2(delta.z, delta.x) * (180.0D / Math.PI)) - 90.0F;
float targetPitch = (float) (-(Mth.atan2(delta.y, horizontal) * (180.0D / Math.PI)));
float nextYaw = Mth.approachDegrees(this.getYRot(), targetYaw, maxYawStep);
float nextPitch = Mth.approachDegrees(this.getXRot(), targetPitch, maxPitchStep);
this.setYRot(nextYaw);
this.setYHeadRot(nextYaw);
this.yBodyRot = nextYaw;
this.setXRot(nextPitch);
}
@Override
public void die(DamageSource damageSource) {
if (!this.level().isClientSide) {
this.setAnimationState(ANIM_DEATH);
this.attackTicks = 0;
this.spawnedAttackVortex = false;
this.getNavigation().stop();
}
super.die(damageSource);
}
@Override
protected void tickDeath() {
this.deathTime++;
if (this.deathTime == 1) {
this.setAnimationState(ANIM_DEATH);
}
if (this.deathTime >= DEATH_TICKS) {
this.remove(RemovalReason.KILLED);
this.dropExperience(this);
}
}
@Override
public boolean causeFallDamage(float fallDistance, float multiplier, DamageSource source) {
return false;
}
@Override
protected void checkFallDamage(double y, boolean onGround, BlockState state, BlockPos pos) {
}
@Override
protected SoundEvent getHurtSound(DamageSource damageSource) {
return SoundEvents.BREEZE_HURT;
}
@Override
protected SoundEvent getDeathSound() {
return SoundEvents.BREEZE_DEATH;
}
@Override
public void addAdditionalSaveData(CompoundTag tag) {
super.addAdditionalSaveData(tag);
tag.putInt(ATTACK_COOLDOWN_KEY, this.attackCooldown);
tag.putInt(ATTACK_TICKS_KEY, this.attackTicks);
}
@Override
public void readAdditionalSaveData(CompoundTag tag) {
super.readAdditionalSaveData(tag);
this.attackCooldown = tag.getInt(ATTACK_COOLDOWN_KEY);
this.attackTicks = 0;
this.spawnedAttackVortex = false;
}
public int getAnimationState() {
return this.entityData.get(ANIMATION_STATE);
}
private void setAnimationState(int state) {
if (this.entityData.get(ANIMATION_STATE) != state) {
this.entityData.set(ANIMATION_STATE, state);
String trigger = switch (state) {
case ANIM_ATTACK -> "wind_gust";
case ANIM_DEATH -> "death";
default -> null;
};
if (trigger != null) {
this.triggerAnim("main_controller", trigger);
}
}
}
private void updateAnimationState() {
if (this.isDeadOrDying()) {
this.setAnimationState(ANIM_DEATH);
} else if (this.attackTicks > 0) {
this.setAnimationState(ANIM_ATTACK);
} else if (this.getTarget() != null && this.canTargetEntity(this.getTarget())) {
this.setAnimationState(ANIM_FLY);
} else {
this.setAnimationState(ANIM_IDLE);
}
}
private boolean canTargetEntity(@Nullable LivingEntity entity) {
if (entity == null || !entity.isAlive() || entity == this || entity.getType() == this.getType()) {
return false;
}
if (entity instanceof Player player) {
return !player.isCreative() && !player.isSpectator()
&& this.level().getDifficulty() != Difficulty.PEACEFUL;
}
return entity.isAttackable();
}
private final class VortexPatrolGoal extends Goal {
private int retargetDelay;
private VortexPatrolGoal() {
this.setFlags(EnumSet.of(Flag.MOVE));
}
@Override
public boolean canUse() {
return VortexEntity.this.getTarget() == null
&& VortexEntity.this.attackTicks <= 0
&& VortexEntity.this.getNavigation().isDone();
}
@Override
public boolean canContinueToUse() {
return VortexEntity.this.getTarget() == null
&& VortexEntity.this.attackTicks <= 0
&& VortexEntity.this.getNavigation().isInProgress();
}
@Override
public void start() {
this.retargetDelay = Mth.nextInt(VortexEntity.this.random, 40, 80);
this.moveToNewTarget();
}
@Override
public void tick() {
if (VortexEntity.this.getTarget() != null || VortexEntity.this.attackTicks > 0) {
VortexEntity.this.getNavigation().stop();
return;
}
if (VortexEntity.this.getNavigation().isDone() && this.retargetDelay-- <= 0) {
this.retargetDelay = Mth.nextInt(VortexEntity.this.random, 40, 80);
this.moveToNewTarget();
}
}
private void moveToNewTarget() {
Vec3 bias = VortexEntity.this.getViewVector(0.0F);
Vec3 hover = HoverRandomPos.getPos(VortexEntity.this, 10, 5, bias.x, bias.z, (float) Math.PI / 2.0F, 3, 1);
if (hover != null) {
VortexEntity.this.getNavigation().moveTo(hover.x, hover.y, hover.z, 0.18D);
}
}
}
}
@@ -0,0 +1,469 @@
package com.craisinlord.antarchy.content.entity.vortex;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.AntarchyTags;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
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.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth;
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.entity.player.Player;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
public class WindVortexEntity extends Entity {
private static final EntityDataAccessor<Float> HEIGHT =
SynchedEntityData.defineId(WindVortexEntity.class, EntityDataSerializers.FLOAT);
private static final EntityDataAccessor<Float> TOP_RADIUS =
SynchedEntityData.defineId(WindVortexEntity.class, EntityDataSerializers.FLOAT);
private static final EntityDataAccessor<Boolean> DAMAGING =
SynchedEntityData.defineId(WindVortexEntity.class, EntityDataSerializers.BOOLEAN);
private static final EntityDataAccessor<Integer> MODE =
SynchedEntityData.defineId(WindVortexEntity.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Float> AXIS_X =
SynchedEntityData.defineId(WindVortexEntity.class, EntityDataSerializers.FLOAT);
private static final EntityDataAccessor<Float> AXIS_Y =
SynchedEntityData.defineId(WindVortexEntity.class, EntityDataSerializers.FLOAT);
private static final EntityDataAccessor<Float> AXIS_Z =
SynchedEntityData.defineId(WindVortexEntity.class, EntityDataSerializers.FLOAT);
private static final String AGE_KEY = "Age";
private static final String DURATION_KEY = "Duration";
private static final String HEIGHT_KEY = "Height";
private static final String TOP_RADIUS_KEY = "TopRadius";
private static final String PULL_STRENGTH_KEY = "PullStrength";
private static final String LAUNCH_STRENGTH_KEY = "LaunchStrength";
private static final String DAMAGING_KEY = "Damaging";
private static final String OWNER_KEY = "Owner";
private static final String MODE_KEY = "Mode";
private static final String AXIS_X_KEY = "AxisX";
private static final String AXIS_Y_KEY = "AxisY";
private static final String AXIS_Z_KEY = "AxisZ";
private static final double BASE_RADIUS = 0.35D;
private static final double DRIFT_FRICTION = 0.96D;
public enum VortexMode {
UPWARD,
LENS_PULL,
LENS_PUSH
}
private int age;
private int durationTicks = 140;
private double pullStrength = 0.32D;
private double launchStrength = 1.0D;
private final Map<UUID, Double> carriedProgress = new HashMap<>();
@Nullable
private UUID ownerUuid;
public WindVortexEntity(EntityType<? extends WindVortexEntity> entityType, Level level) {
super(entityType, level);
this.noCulling = true;
}
public static WindVortexEntity create(Level level, EntityType<? extends WindVortexEntity> type, Vec3 position,
Vec3 drift, @Nullable LivingEntity owner, boolean damaging) {
WindVortexEntity vortex = new WindVortexEntity(type, level);
vortex.setPos(position.x, position.y, position.z);
vortex.setDeltaMovement(drift);
vortex.setVortexSize(5.0F, 1.5F);
vortex.setAxis(Direction.UP);
vortex.setMode(VortexMode.UPWARD);
vortex.durationTicks = Math.max(1, AntarchySettings.windVortexDurationTicks());
vortex.pullStrength = AntarchySettings.windVortexPullStrength();
vortex.launchStrength = AntarchySettings.windVortexLaunchStrength();
vortex.setDamaging(damaging);
if (owner != null) {
vortex.ownerUuid = owner.getUUID();
}
return vortex;
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
builder.define(HEIGHT, 5.0F);
builder.define(TOP_RADIUS, 1.5F);
builder.define(DAMAGING, false);
builder.define(MODE, VortexMode.UPWARD.ordinal());
builder.define(AXIS_X, 0.0F);
builder.define(AXIS_Y, 1.0F);
builder.define(AXIS_Z, 0.0F);
}
@Override
public void tick() {
super.tick();
boolean lensVortex = this.getMode() != VortexMode.UPWARD;
if (!lensVortex && (this.isInLava() || this.isInsideSolidBlock())) {
this.fadeOut();
return;
}
if (this.level().isClientSide) {
return;
}
this.age++;
if (!lensVortex && this.age >= this.durationTicks) {
this.fadeOut();
return;
}
Vec3 drift = this.getDeltaMovement().multiply(DRIFT_FRICTION, DRIFT_FRICTION, DRIFT_FRICTION);
this.setDeltaMovement(drift);
this.move(net.minecraft.world.entity.MoverType.SELF, drift);
if ((this.tickCount & 1) == 0) {
this.applyVortexForces();
}
}
private boolean isInsideSolidBlock() {
BlockPos pos = this.blockPosition();
BlockState state = this.level().getBlockState(pos);
return !state.getCollisionShape(this.level(), pos).isEmpty();
}
private void fadeOut() {
if (!this.level().isClientSide) {
this.level().broadcastEntityEvent(this, (byte) 60);
this.discard();
}
}
@Override
public void handleEntityEvent(byte id) {
if (id == 60) {
return;
}
super.handleEntityEvent(id);
}
private void applyVortexForces() {
double height = this.getVortexHeight();
double maxRadius = this.getTopRadius();
AABB area = this.getBoundingBox().inflate(maxRadius + height + 1.0D);
Basis basis = this.basis();
VortexMode mode = this.getMode();
for (Entity entity : this.level().getEntities(this, area, this::canAffectEntity)) {
Vec3 relative = entity.position().subtract(this.position());
double axisDistance = relative.dot(basis.axis);
if (axisDistance < -0.25D || axisDistance > height + 0.75D) {
continue;
}
double along = Mth.clamp(axisDistance, 0.0D, height);
double currentProgress = height <= 0.0D ? 1.0D : along / height;
double captureProgress = mode == VortexMode.LENS_PULL ? 1.0D - currentProgress : currentProgress;
double shapeProgress = mode == VortexMode.LENS_PULL ? 1.0D - currentProgress : currentProgress;
double radius = this.radiusAt(shapeProgress);
Vec3 axisPoint = basis.axis.scale(axisDistance);
Vec3 radialVector = relative.subtract(axisPoint);
double captureRadius = radius + (entity instanceof Player ? 1.0D : 0.35D);
if (radialVector.lengthSqr() > captureRadius * captureRadius || !this.hasClearPathTo(entity)) {
continue;
}
this.carriedProgress.putIfAbsent(entity.getUUID(), captureProgress);
}
if (!(this.level() instanceof ServerLevel serverLevel)) {
return;
}
Iterator<Map.Entry<UUID, Double>> iterator = this.carriedProgress.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<UUID, Double> entry = iterator.next();
Entity entity = serverLevel.getEntity(entry.getKey());
if (entity == null || !this.canAffectEntity(entity)) {
iterator.remove();
continue;
}
double progress = entry.getValue();
double direction = mode == VortexMode.LENS_PULL ? -1.0D : 1.0D;
progress += direction * 0.055D;
if (mode == VortexMode.LENS_PULL && progress <= 0.0D) {
iterator.remove();
continue;
}
if (mode == VortexMode.UPWARD && progress >= 0.92D) {
this.launch(entity, this.radialVectorAt(entity, progress, basis), progress, basis);
iterator.remove();
continue;
}
if (mode == VortexMode.LENS_PUSH && progress >= 0.94D) {
this.launch(entity, this.radialVectorAt(entity, progress, basis), progress, basis);
iterator.remove();
continue;
}
double shapeProgress = mode == VortexMode.LENS_PULL ? progress : progress;
double radius = this.radiusAt(shapeProgress);
Vec3 relative = entity.position().subtract(this.position());
Vec3 axisPoint = basis.axis.scale(relative.dot(basis.axis));
Vec3 radialVector = relative.subtract(axisPoint);
this.spin(entity, radialVector, progress, shapeProgress, radius, basis, mode);
if (mode == VortexMode.UPWARD) {
entity.setOnGround(false);
}
this.hurtCaughtEntity(entity);
entry.setValue(progress);
}
}
private Vec3 radialVectorAt(Entity entity, double progress, Basis basis) {
Vec3 relative = entity.position().subtract(this.position());
Vec3 axisPoint = basis.axis.scale(relative.dot(basis.axis));
Vec3 radial = relative.subtract(axisPoint);
return radial.lengthSqr() < 1.0E-6D ? basis.sideA.scale(this.radiusAt(progress)) : radial;
}
private boolean canAffectEntity(Entity entity) {
if (!entity.isAlive() || entity.isSpectator() || entity.noPhysics || entity.getType().is(AntarchyTags.Entities.WIND_VORTEX_IMMUNE)) {
return false;
}
if (entity instanceof Player player && player.isCreative()) {
return false;
}
return true;
}
private boolean hasClearPathTo(Entity entity) {
Vec3 from = this.position().add(this.getAxis().scale(Math.min(entity.getBbHeight() * 0.5D, this.getVortexHeight())));
Vec3 to = entity.getBoundingBox().getCenter();
HitResult result = this.level().clip(new ClipContext(from, to, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this));
return result.getType() == HitResult.Type.MISS;
}
private void spin(Entity entity, Vec3 radialVector, double progress, double shapeProgress, double radius, Basis basis, VortexMode mode) {
double horizontal = Math.max(0.08D, radialVector.length());
Vec3 radial = radialVector.lengthSqr() < 1.0E-6D ? basis.sideA : radialVector.scale(1.0D / horizontal);
Vec3 tangent = basis.axis.cross(radial).normalize();
double targetRadius = mode == VortexMode.LENS_PULL
? Math.max(0.05D, radius * 0.18D)
: Mth.lerp(shapeProgress, BASE_RADIUS, radius * 0.82D);
double radialError = targetRadius - horizontal;
double playerScale = entity instanceof Player ? 1.8D : 1.0D;
double pull = this.pullStrength * playerScale * (entity.isShiftKeyDown() ? 0.5D : 1.0D);
double massScale = Mth.clamp(1.35D / Math.max(0.35D, entity.getBbWidth() * entity.getBbHeight()), 0.28D, 1.0D);
double spin = (0.24D + progress * 0.34D) * massScale * playerScale;
double axialSpeed = switch (mode) {
case LENS_PULL -> -(0.18D + (1.0D - progress) * 0.18D) * massScale;
case LENS_PUSH -> (0.18D + progress * 0.22D) * massScale;
case UPWARD -> (0.13D + progress * 0.16D) * massScale;
} * playerScale;
if (mode == VortexMode.UPWARD && entity instanceof Player && entity.onGround()) {
axialSpeed = Math.max(axialSpeed, 0.38D);
}
Vec3 wanted = radial.scale(radialError * pull)
.add(tangent.scale(spin))
.add(basis.axis.scale(axialSpeed));
Vec3 current = entity.getDeltaMovement();
Vec3 updatedMovement = new Vec3(
Mth.lerp(0.72D, current.x, wanted.x),
Mth.lerp(0.58D, current.y, wanted.y),
Mth.lerp(0.72D, current.z, wanted.z)
);
if (mode == VortexMode.UPWARD && entity instanceof Player && entity.onGround()) {
updatedMovement = new Vec3(updatedMovement.x, Math.max(updatedMovement.y, 0.38D), updatedMovement.z);
entity.setOnGround(false);
}
entity.setDeltaMovement(updatedMovement);
entity.fallDistance = 0.0F;
entity.hasImpulse = true;
}
private void launch(Entity entity, Vec3 radialVector, double progress, Basis basis) {
double horizontal = Math.max(0.08D, radialVector.length());
Vec3 radial = radialVector.lengthSqr() < 1.0E-6D ? basis.sideA : radialVector.scale(1.0D / horizontal);
Vec3 tangent = basis.axis.cross(radial).normalize();
double scale = this.launchStrength * Mth.clamp(this.getVortexHeight() / 5.0D, 0.5D, 2.5D);
entity.setDeltaMovement(tangent.scale(0.72D * scale).add(radial.scale(0.34D * scale)).add(basis.axis.scale((0.78D + progress * 0.28D) * scale)));
entity.hasImpulse = true;
}
private void hurtCaughtEntity(Entity entity) {
if (!this.isDamaging() || !(entity instanceof LivingEntity living) || living.tickCount % 20 != 0) {
return;
}
if (living.getType().is(AntarchyTags.Entities.WIND_VORTEX_IMMUNE)) {
return;
}
float damage = (float) (2.0D * Mth.clamp(this.getTopRadius() / 1.5D, 0.5D, 3.0D));
living.hurt(this.damageSource(), damage);
}
private DamageSource damageSource() {
Entity owner = this.getOwnerEntity();
if (owner instanceof LivingEntity living) {
return this.damageSources().mobAttack(living);
}
return this.damageSources().magic();
}
@Nullable
private Entity getOwnerEntity() {
if (this.ownerUuid == null || !(this.level() instanceof ServerLevel serverLevel)) {
return null;
}
return serverLevel.getEntity(this.ownerUuid);
}
private double radiusAt(double progress) {
return Mth.lerp(progress, BASE_RADIUS, this.getTopRadius());
}
public void setVortexSize(float height, float topRadius) {
this.entityData.set(HEIGHT, height);
this.entityData.set(TOP_RADIUS, topRadius);
}
public float getVortexHeight() {
return this.entityData.get(HEIGHT);
}
public float getTopRadius() {
return this.entityData.get(TOP_RADIUS);
}
public void setMode(VortexMode mode) {
this.entityData.set(MODE, mode.ordinal());
}
public VortexMode getMode() {
int ordinal = Mth.clamp(this.entityData.get(MODE), 0, VortexMode.values().length - 1);
return VortexMode.values()[ordinal];
}
public void setAxis(Direction direction) {
this.setAxis(Vec3.atLowerCornerOf(direction.getNormal()));
}
public void setAxis(Vec3 axis) {
Vec3 normalized = axis.lengthSqr() < 1.0E-6D ? new Vec3(0.0D, 1.0D, 0.0D) : axis.normalize();
this.entityData.set(AXIS_X, (float) normalized.x);
this.entityData.set(AXIS_Y, (float) normalized.y);
this.entityData.set(AXIS_Z, (float) normalized.z);
}
public Vec3 getAxis() {
Vec3 axis = new Vec3(this.entityData.get(AXIS_X), this.entityData.get(AXIS_Y), this.entityData.get(AXIS_Z));
return axis.lengthSqr() < 1.0E-6D ? new Vec3(0.0D, 1.0D, 0.0D) : axis.normalize();
}
public int getVortexAge() {
return this.age;
}
public int getVortexDurationTicks() {
return this.durationTicks;
}
public void setVortexDurationTicks(int durationTicks) {
this.durationTicks = Math.max(1, durationTicks);
}
public void resetVortexAge() {
this.age = 0;
}
public void setVortexStrengths(double pullStrength, double launchStrength) {
this.pullStrength = Math.max(0.0D, pullStrength);
this.launchStrength = Math.max(0.0D, launchStrength);
}
public void removeFromLens() {
this.fadeOut();
}
public boolean isDamaging() {
return this.entityData.get(DAMAGING);
}
public boolean isOwnedBy(Entity entity) {
return entity != null && this.ownerUuid != null && this.ownerUuid.equals(entity.getUUID());
}
public void setDamaging(boolean damaging) {
this.entityData.set(DAMAGING, damaging);
}
@Override
protected void readAdditionalSaveData(CompoundTag tag) {
this.age = tag.getInt(AGE_KEY);
this.durationTicks = tag.getInt(DURATION_KEY);
this.setVortexSize(tag.getFloat(HEIGHT_KEY), tag.getFloat(TOP_RADIUS_KEY));
this.pullStrength = tag.getDouble(PULL_STRENGTH_KEY);
this.launchStrength = tag.getDouble(LAUNCH_STRENGTH_KEY);
this.setDamaging(tag.getBoolean(DAMAGING_KEY));
this.setMode(VortexMode.values()[Mth.clamp(tag.getInt(MODE_KEY), 0, VortexMode.values().length - 1)]);
this.setAxis(new Vec3(tag.getFloat(AXIS_X_KEY), tag.getFloat(AXIS_Y_KEY), tag.getFloat(AXIS_Z_KEY)));
if (tag.hasUUID(OWNER_KEY)) {
this.ownerUuid = tag.getUUID(OWNER_KEY);
}
}
@Override
protected void addAdditionalSaveData(CompoundTag tag) {
tag.putInt(AGE_KEY, this.age);
tag.putInt(DURATION_KEY, this.durationTicks);
tag.putFloat(HEIGHT_KEY, this.getVortexHeight());
tag.putFloat(TOP_RADIUS_KEY, this.getTopRadius());
tag.putDouble(PULL_STRENGTH_KEY, this.pullStrength);
tag.putDouble(LAUNCH_STRENGTH_KEY, this.launchStrength);
tag.putBoolean(DAMAGING_KEY, this.isDamaging());
tag.putInt(MODE_KEY, this.getMode().ordinal());
tag.putFloat(AXIS_X_KEY, (float) this.getAxis().x);
tag.putFloat(AXIS_Y_KEY, (float) this.getAxis().y);
tag.putFloat(AXIS_Z_KEY, (float) this.getAxis().z);
if (this.ownerUuid != null) {
tag.putUUID(OWNER_KEY, this.ownerUuid);
}
}
public static final class Basis {
public final Vec3 axis;
public final Vec3 sideA;
public final Vec3 sideB;
private Basis(Vec3 axis, Vec3 sideA, Vec3 sideB) {
this.axis = axis;
this.sideA = sideA;
this.sideB = sideB;
}
}
public Basis basis() {
Vec3 axis = this.getAxis();
Vec3 reference = Math.abs(axis.y) > 0.9D ? new Vec3(1.0D, 0.0D, 0.0D) : new Vec3(0.0D, 1.0D, 0.0D);
Vec3 sideA = reference.cross(axis).normalize();
Vec3 sideB = axis.cross(sideA).normalize();
return new Basis(axis, sideA, sideB);
}
}
@@ -1,7 +1,5 @@
package com.craisinlord.antarchy.content.gravity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.level.PathNavigationRegion;
@@ -11,52 +9,27 @@ import net.minecraft.world.level.pathfinder.PathfindingContext;
import net.minecraft.world.level.pathfinder.WalkNodeEvaluator;
public class GravityWalkNodeEvaluator extends WalkNodeEvaluator {
private static final Logger LOGGER = LoggerFactory.getLogger("Antarchy/Pathfinding");
private static final int[] START_Y_SEARCH = {0, 1, -1, 2, -2, 3, -3, 4, -4};
private static final int[][] INVERTED_NEIGHBOR_OFFSETS = {
private static final int[] START_Y_SEARCH = {0, 1, -1, 2, -2};
private static final int[][] INVERTED_CARDINAL_NEIGHBOR_OFFSETS = {
{1, 0, 0},
{-1, 0, 0},
{0, 0, 1},
{0, 0, -1},
{0, 0, -1}
};
private static final int[][] INVERTED_DIAGONAL_NEIGHBOR_OFFSETS = {
{1, 0, 1},
{1, 0, -1},
{-1, 0, 1},
{-1, 0, -1},
{0, 1, 0},
{0, -1, 0}
{-1, 0, -1}
};
private int antarchy$loggedPrepare;
private int antarchy$loggedGetStart;
private int antarchy$loggedPathType;
private int antarchy$loggedNeighbors;
@Override
public void prepare(PathNavigationRegion sourceIn, Mob mob) {
super.prepare(sourceIn, mob);
this.antarchy$loggedPrepare = 0;
this.antarchy$loggedGetStart = 0;
this.antarchy$loggedPathType = 0;
this.antarchy$loggedNeighbors = 0;
if (AntarchyGravityApi.isGravityInverted(mob)) {
LOGGER.debug(
"[Path] prepare inverted mob={} pos=({}, {}, {}) size=({}, {})",
mob.getClass().getSimpleName(),
Mth.floor(mob.getX()),
Mth.floor(mob.getY()),
Mth.floor(mob.getZ()),
mob.getBbWidth(),
mob.getBbHeight()
);
}
}
@Override
public void done() {
if (this.mob != null && AntarchyGravityApi.isGravityInverted(this.mob)) {
LOGGER.debug("[Path] done inverted mob={}", this.mob.getClass().getSimpleName());
}
super.done();
}
@@ -74,19 +47,6 @@ public class GravityWalkNodeEvaluator extends WalkNodeEvaluator {
return super.getStart();
}
if (this.antarchy$loggedGetStart < 8) {
LOGGER.debug(
"[Path] getStart inverted mob={} node=({}, {}, {}) type={} malus={}",
this.mob.getClass().getSimpleName(),
x,
y,
z,
node.type,
node.costMalus
);
this.antarchy$loggedGetStart++;
}
return node;
}
@@ -154,19 +114,6 @@ public class GravityWalkNodeEvaluator extends WalkNodeEvaluator {
}
}
if (this.antarchy$loggedPathType < 16) {
LOGGER.debug(
"[Path] type inverted mob={} pos=({}, {}, {}) ceiling={} result={}",
mob.getClass().getSimpleName(),
x,
y,
z,
ceilingType,
result
);
this.antarchy$loggedPathType++;
}
return result;
}
@@ -177,46 +124,49 @@ public class GravityWalkNodeEvaluator extends WalkNodeEvaluator {
}
int count = 0;
for (int[] offset : INVERTED_NEIGHBOR_OFFSETS) {
count += this.antarchy$addNeighbor(neighbors, count, current.x + offset[0], current.y + offset[1], current.z + offset[2]);
Node[] cardinalNeighbors = new Node[INVERTED_CARDINAL_NEIGHBOR_OFFSETS.length];
for (int i = 0; i < INVERTED_CARDINAL_NEIGHBOR_OFFSETS.length; i++) {
int[] offset = INVERTED_CARDINAL_NEIGHBOR_OFFSETS[i];
Node neighbor = this.antarchy$getNeighbor(current.x + offset[0], current.y, current.z + offset[2]);
cardinalNeighbors[i] = neighbor;
if (neighbor != null) {
neighbors[count++] = neighbor;
}
}
if (this.antarchy$loggedNeighbors < 16) {
LOGGER.debug(
"[Path] neighbors inverted mob={} node=({}, {}, {}) count={}",
this.mob.getClass().getSimpleName(),
current.x,
current.y,
current.z,
count
);
this.antarchy$loggedNeighbors++;
for (int i = 0; i < INVERTED_DIAGONAL_NEIGHBOR_OFFSETS.length; i++) {
int[] offset = INVERTED_DIAGONAL_NEIGHBOR_OFFSETS[i];
if (!this.antarchy$canUseDiagonal(cardinalNeighbors, i)) {
continue;
}
Node neighbor = this.antarchy$getNeighbor(current.x + offset[0], current.y, current.z + offset[2]);
if (neighbor != null) {
neighbors[count++] = neighbor;
}
}
return count;
}
private int antarchy$addNeighbor(Node[] neighbors, int index, int x, int y, int z) {
private boolean antarchy$canUseDiagonal(Node[] cardinalNeighbors, int diagonalIndex) {
return switch (diagonalIndex) {
case 0 -> cardinalNeighbors[0] != null && cardinalNeighbors[2] != null;
case 1 -> cardinalNeighbors[0] != null && cardinalNeighbors[3] != null;
case 2 -> cardinalNeighbors[1] != null && cardinalNeighbors[2] != null;
case 3 -> cardinalNeighbors[1] != null && cardinalNeighbors[3] != null;
default -> false;
};
}
private Node antarchy$getNeighbor(int x, int y, int z) {
PathType type = this.getPathTypeOfMob(this.currentContext, x, y, z, this.mob);
if (this.mob.getPathfindingMalus(type) < 0.0F) {
if (this.antarchy$loggedNeighbors < 16) {
LOGGER.debug(
"[Path] reject mob={} pos=({}, {}, {}) type={} malus={}",
this.mob.getClass().getSimpleName(),
x,
y,
z,
type,
this.mob.getPathfindingMalus(type)
);
}
return 0;
return null;
}
Node node = this.getNode(x, y, z);
node.type = type;
node.costMalus = this.mob.getPathfindingMalus(type);
neighbors[index] = node;
return 1;
return node;
}
}
@@ -1,10 +1,22 @@
package com.craisinlord.antarchy.content.item;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlotGroup;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.SwordItem;
@@ -13,8 +25,16 @@ import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.item.component.ItemAttributeModifiers;
import net.minecraft.world.phys.Vec3;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.AntarchySoundEvents;
import com.craisinlord.antarchy.content.client.BloodCrystalKatanaTrailClientState;
public class BloodCrystalKatanaItem extends SwordItem {
private static final ResourceLocation ATTACK_RANGE_MODIFIER_ID =
ResourceLocation.fromNamespaceAndPath("antarchy", "blood_crystal_katana_attack_range");
private static final float FULL_SWING_THRESHOLD = 0.9F;
private static final Map<UUID, Long> LAST_DASH_TICK = new ConcurrentHashMap<>();
private static final Map<UUID, Long> DASH_UNTIL_TICK = new ConcurrentHashMap<>();
@FunctionalInterface
public interface TrailCallback {
void trigger(ServerPlayer player, int durationTicks);
@@ -35,7 +55,12 @@ public class BloodCrystalKatanaItem extends SwordItem {
@Override
public ItemAttributeModifiers getDefaultAttributeModifiers() {
return SwordItem.createAttributes(this.tier, this.attackDamage, this.attackSpeed);
return SwordItem.createAttributes(this.tier, this.attackDamage, this.attackSpeed)
.withModifierAdded(
Attributes.ENTITY_INTERACTION_RANGE,
new AttributeModifier(ATTACK_RANGE_MODIFIER_ID, AntarchySettings.bloodCrystalKatanaReachBonus(), AttributeModifier.Operation.ADD_VALUE),
EquipmentSlotGroup.MAINHAND
);
}
public static void setTrailCallback(TrailCallback callback) {
@@ -45,9 +70,20 @@ public class BloodCrystalKatanaItem extends SwordItem {
@Override
public boolean hurtEnemy(ItemStack stack, LivingEntity target, LivingEntity attacker) {
boolean result = super.hurtEnemy(stack, target, attacker);
if (!(attacker instanceof ServerPlayer player)) {
return result;
if (attacker instanceof ServerPlayer player) {
performDash(player, player.getAttackStrengthScale(0.0F) >= FULL_SWING_THRESHOLD);
}
return result;
}
public static void performDash(ServerPlayer player, boolean fullSwing) {
long now = player.level().getGameTime();
Long last = LAST_DASH_TICK.get(player.getUUID());
if (last != null && now - last < AntarchySettings.bloodCrystalKatanaDashCooldownTicks()) {
return;
}
LAST_DASH_TICK.put(player.getUUID(), now);
DASH_UNTIL_TICK.put(player.getUUID(), now + AntarchySettings.bloodCrystalKatanaTrailDurationTicks());
Vec3 look = player.getLookAngle();
Vec3 horizontal = new Vec3(look.x, 0.0D, look.z);
@@ -60,13 +96,39 @@ public class BloodCrystalKatanaItem extends SwordItem {
player.setDeltaMovement(player.getDeltaMovement().add(launch));
player.hasImpulse = true;
player.hurtMarked = true;
trailCallback.trigger(player, AntarchySettings.bloodCrystalKatanaTrailDurationTicks());
return result;
player.level().playSound(null, player.getX(), player.getY(), player.getZ(),
AntarchySoundEvents.BLOOD_CRYSTAL_KATANA_DASH.get(), SoundSource.PLAYERS, 1.0F, 1.0F);
int invulnTicks = AntarchySettings.bloodCrystalKatanaInvulnTicks();
if (fullSwing && invulnTicks > 0) {
player.addEffect(new MobEffectInstance(MobEffects.DAMAGE_RESISTANCE, invulnTicks, 4, false, false, false));
}
}
public static boolean isDashing(Entity entity) {
if (!(entity instanceof Player)) {
return false;
}
if (entity.level().isClientSide()) {
return BloodCrystalKatanaTrailClientState.getRemainingTicks(entity.getId()) > 0;
}
Long until = DASH_UNTIL_TICK.get(entity.getUUID());
if (until == null) {
return false;
}
if (entity.level().getGameTime() >= until) {
DASH_UNTIL_TICK.remove(entity.getUUID());
return false;
}
return true;
}
@Override
public void appendHoverText(ItemStack stack, Item.TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
tooltipComponents.add(Component.translatable("tooltip.antarchy.blood_crystal_katana.launch").withStyle(ChatFormatting.RED));
tooltipComponents.add(Component.translatable("tooltip.antarchy.blood_crystal_katana.dash").withStyle(ChatFormatting.RED));
tooltipComponents.add(Component.translatable("tooltip.antarchy.blood_crystal_katana.trail").withStyle(ChatFormatting.DARK_RED));
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
}
@@ -1,7 +1,9 @@
package com.craisinlord.antarchy.content.item;
import com.craisinlord.antarchy.content.AntarchySoundEvents;
import com.craisinlord.antarchy.content.bloodglass.BloodglassAccess;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.player.Player;
@@ -52,6 +54,8 @@ public class BloodCrystalShardItem extends Item {
}
player.getCooldowns().addCooldown(this, COOLDOWN_TICKS);
level.playSound(null, player.getX(), player.getY(), player.getZ(),
AntarchySoundEvents.BLOODGLASS_WARD_HEART_REGEN.get(), SoundSource.PLAYERS, 1.0F, 1.0F);
SYNC_BLOODGLASS.accept((ServerPlayer) player);
if (!player.getAbilities().instabuild) {
@@ -0,0 +1,50 @@
package com.craisinlord.antarchy.content.item;
import com.craisinlord.antarchy.content.entity.vortex.VortexChargeProjectileEntity;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.stats.Stats;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import java.util.function.Supplier;
public class VortexChargeItem extends Item {
private final Supplier<? extends EntityType<? extends VortexChargeProjectileEntity>> projectileType;
public VortexChargeItem(Properties properties,
Supplier<? extends EntityType<? extends VortexChargeProjectileEntity>> projectileType) {
super(properties);
this.projectileType = projectileType;
}
@Override
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand usedHand) {
ItemStack itemStack = player.getItemInHand(usedHand);
if (player.getCooldowns().isOnCooldown(this)) {
return InteractionResultHolder.fail(itemStack);
}
level.playSound(null, player.getX(), player.getY(), player.getZ(),
SoundEvents.WIND_CHARGE_THROW, SoundSource.NEUTRAL, 0.6F,
0.8F + level.getRandom().nextFloat() * 0.4F);
if (!level.isClientSide) {
VortexChargeProjectileEntity projectile = new VortexChargeProjectileEntity(projectileType.get(), player, level);
projectile.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0F, 1.5F, 1.0F);
level.addFreshEntity(projectile);
if (!player.getAbilities().instabuild) {
itemStack.shrink(1);
}
}
player.awardStat(Stats.ITEM_USED.get(this));
player.getCooldowns().addCooldown(this, 20);
return InteractionResultHolder.consume(itemStack);
}
}
@@ -1,5 +1,6 @@
package com.craisinlord.antarchy.content.item;
import com.craisinlord.antarchy.content.AntarchySoundEvents;
import com.craisinlord.antarchy.content.entity.WormHookProjectileEntity;
import com.craisinlord.antarchy.content.util.WormHookRope;
import java.util.Map;
@@ -29,6 +30,8 @@ public final class WormHookTetherManager {
private static final double DEFAULT_BREAK_RANGE = 48.0D;
private static final double SNAP_BUFFER = 4.0D;
private static final double PULL_CORRECTION = 0.35D;
private static final double FLYING_SOUND_MIN_SPEED_SQR = 0.1D * 0.1D;
private static final int FLYING_SOUND_INTERVAL_TICKS = 24;
private static final Map<UUID, TetherState> TETHERS = new ConcurrentHashMap<>();
@@ -118,6 +121,7 @@ public final class WormHookTetherManager {
Vec3 playerEye = player.getEyePosition();
state.rope.update(hook, anchor, playerEye, state.maxLen);
tickFlyingSound(player, state);
Vec3 pivot = state.rope.getPivot();
double consumed = state.rope.getConsumedLength();
@@ -168,6 +172,19 @@ public final class WormHookTetherManager {
player.fallDistance = 0;
}
private static void tickFlyingSound(ServerPlayer player, TetherState state) {
if (state.flyingSoundCooldown > 0) {
state.flyingSoundCooldown--;
return;
}
if (player.getDeltaMovement().horizontalDistanceSqr() < FLYING_SOUND_MIN_SPEED_SQR) {
return;
}
state.flyingSoundCooldown = FLYING_SOUND_INTERVAL_TICKS;
player.level().playSound(null, player.blockPosition(), AntarchySoundEvents.WORM_HOOK_FLYING.get(),
SoundSource.PLAYERS, 0.6F, 1.0F);
}
private static boolean isValid(ServerPlayer player, WormHookProjectileEntity hook, TetherState state) {
double breakRange = (state.rope == null ? DEFAULT_BREAK_RANGE : state.maxLen) * BREAK_RANGE_MULTIPLIER;
return player.isAlive()
@@ -188,6 +205,7 @@ public final class WormHookTetherManager {
private final int hookEntityId;
private double maxLen;
private WormHookRope rope;
private int flyingSoundCooldown;
private TetherState(int hookEntityId) {
this.hookEntityId = hookEntityId;
@@ -16,8 +16,11 @@ import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.LeavesBlock;
import net.minecraft.world.level.block.RotatedPillarBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.Column;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import java.util.Optional;
import java.util.OptionalInt;
public class NadirTreeFeature extends Feature<NadirTreeConfiguration> {
public NadirTreeFeature(Codec<NadirTreeConfiguration> codec) {
@@ -27,7 +30,7 @@ public class NadirTreeFeature extends Feature<NadirTreeConfiguration> {
@Override
public boolean place(FeaturePlaceContext<NadirTreeConfiguration> context) {
WorldGenLevel level = context.level();
BlockPos origin = context.origin();
BlockPos origin = findCeilingOrigin(level, context.origin(), 72);
BlockPos supportPos = origin.above();
if (!level.getBlockState(supportPos).isFaceSturdy(level, supportPos, Direction.DOWN)) {
return false;
@@ -46,7 +49,7 @@ public class NadirTreeFeature extends Feature<NadirTreeConfiguration> {
Set<BlockPos> foliage = new LinkedHashSet<>();
placeTrunk(spine, bottomRadius, logs, random);
placeLowerMass(spine, bottomRadius, logs, foliage, random, veilRadius);
placeRootWaves(spine, bottomRadius, logs, foliage, random, veilRadius);
placeBranches(spine, branchCount, branchLength, logs, foliage, random, veilRadius);
placeVeilCurtains(spine, foliage, random, veilRadius);
@@ -75,6 +78,21 @@ public class NadirTreeFeature extends Feature<NadirTreeConfiguration> {
return true;
}
private static BlockPos findCeilingOrigin(WorldGenLevel level, BlockPos origin, int searchRange) {
if (level.getBlockState(origin).isAir() && level.getBlockState(origin.above()).isFaceSturdy(level, origin.above(), Direction.DOWN)) {
return origin;
}
Optional<Column> optional = Column.scan(level, origin, searchRange, state -> state.isAir(), state -> !state.isAir());
if (optional.isEmpty()) {
return origin;
}
OptionalInt ceiling = optional.get().getCeiling();
if (ceiling.isEmpty()) {
return origin;
}
return origin.atY(ceiling.getAsInt() - 1);
}
private List<BlockPos> buildSpine(BlockPos origin, int height, RandomSource random) {
List<BlockPos> spine = new ArrayList<>(height);
BlockPos current = origin;
@@ -100,7 +118,11 @@ public class NadirTreeFeature extends Feature<NadirTreeConfiguration> {
for (int index = 0; index < spine.size(); index++) {
BlockPos center = spine.get(index);
float progress = spine.size() == 1 ? 1.0F : index / (float) (spine.size() - 1);
int radius = Mth.clamp(Math.round(progress * bottomRadius), 0, bottomRadius);
float wave = Mth.sin(progress * Mth.PI * 2.75F) * 0.55F + Mth.sin(progress * Mth.PI * 5.5F) * 0.25F;
int radius = Mth.clamp(Math.round((0.45F + progress * 0.3F + wave * 0.22F) * bottomRadius), 0, Math.max(1, bottomRadius - 1));
if (index < 2) {
radius = Math.max(radius, 1);
}
fillTrunkLayer(center, radius, logs, random);
}
}
@@ -118,7 +140,7 @@ public class NadirTreeFeature extends Feature<NadirTreeConfiguration> {
if (dist > radiusSq + 1) {
continue;
}
if (dist > radiusSq - radius && random.nextFloat() < 0.2F) {
if (dist > radiusSq - radius && random.nextFloat() < 0.48F) {
continue;
}
putLog(logs, center.offset(dx, 0, dz), Direction.Axis.Y);
@@ -126,7 +148,7 @@ public class NadirTreeFeature extends Feature<NadirTreeConfiguration> {
}
}
private void placeLowerMass(
private void placeRootWaves(
List<BlockPos> spine,
int bottomRadius,
Map<BlockPos, Direction.Axis> logs,
@@ -134,14 +156,28 @@ public class NadirTreeFeature extends Feature<NadirTreeConfiguration> {
RandomSource random,
int veilRadius
) {
int start = Math.max(0, spine.size() - Math.max(3, bottomRadius + 2));
for (int index = start; index < spine.size(); index++) {
int waveCount = Math.max(4, bottomRadius + 3);
for (int wave = 0; wave < waveCount; wave++) {
int index = Mth.nextInt(random, 0, Math.max(0, spine.size() - 3));
BlockPos center = spine.get(index);
int extraRadius = Math.max(1, bottomRadius - Math.max(0, spine.size() - 1 - index));
for (int dy = 0; dy <= Math.min(2, index - start); dy++) {
fillTrunkLayer(center.below(dy), extraRadius, logs, random);
Direction direction = Direction.Plane.HORIZONTAL.getRandomDirection(random);
int length = Mth.nextInt(random, 2, Math.max(3, bottomRadius + 3));
BlockPos cursor = center;
BlockPos previous = center;
for (int step = 0; step < length; step++) {
cursor = cursor.relative(direction);
if (random.nextFloat() < 0.55F) {
cursor = cursor.below();
}
if (step > 1 && random.nextFloat() < 0.38F) {
direction = random.nextBoolean() ? direction.getClockWise() : direction.getCounterClockWise();
}
putLog(logs, cursor, axisForSegment(previous, cursor));
previous = cursor;
}
if (random.nextFloat() < 0.75F) {
placeVeilRibbon(foliage, cursor, direction, Math.max(2, veilRadius + random.nextInt(2)), random);
}
placeVeilCluster(foliage, center.below(), Math.max(1, veilRadius), random, true);
}
}
@@ -179,8 +215,7 @@ public class NadirTreeFeature extends Feature<NadirTreeConfiguration> {
previous = cursor;
}
placeVeilCluster(foliage, cursor, veilRadius + random.nextInt(2), random, true);
placeVeilCluster(foliage, cursor.below(1 + random.nextInt(2)), Math.max(1, veilRadius - 1), random, true);
placeVeilRibbon(foliage, cursor, direction, Math.max(2, veilRadius + random.nextInt(3)), random);
if (random.nextFloat() < 0.45F) {
BlockPos fork = cursor;
@@ -191,44 +226,41 @@ public class NadirTreeFeature extends Feature<NadirTreeConfiguration> {
putLog(logs, next, axisForSegment(fork, next));
fork = next;
}
placeVeilCluster(foliage, fork, Math.max(1, veilRadius - 1), random, true);
placeVeilRibbon(foliage, fork, forkDirection, Math.max(2, veilRadius), random);
}
}
}
private void placeVeilCurtains(List<BlockPos> spine, Set<BlockPos> foliage, RandomSource random, int veilRadius) {
for (int index = 1; index < spine.size(); index++) {
if (random.nextFloat() > 0.33F) {
if (random.nextFloat() > 0.24F) {
continue;
}
BlockPos anchor = spine.get(index);
Direction side = Direction.Plane.HORIZONTAL.getRandomDirection(random);
BlockPos start = anchor.relative(side);
int length = 2 + random.nextInt(Math.max(2, veilRadius + 1));
for (int i = 0; i < length; i++) {
BlockPos pos = start.below(i);
foliage.add(pos);
if (random.nextFloat() < 0.22F) {
foliage.add(pos.relative(side.getClockWise()));
}
}
placeVeilRibbon(foliage, anchor.relative(side), side, Math.max(2, veilRadius + random.nextInt(3)), random);
}
}
private void placeVeilCluster(Set<BlockPos> foliage, BlockPos center, int radius, RandomSource random, boolean stretchDown) {
int radiusSq = radius * radius;
for (int dx = -radius; dx <= radius; dx++) {
for (int dz = -radius; dz <= radius; dz++) {
for (int dy = -radius; dy <= 1; dy++) {
int adjustedDy = stretchDown ? Math.max(0, -dy) : Math.abs(dy);
int dist = dx * dx + dz * dz + adjustedDy * adjustedDy;
if (dist > radiusSq + 1) {
continue;
}
if (dist > radiusSq - radius && random.nextFloat() < 0.28F) {
continue;
}
foliage.add(center.offset(dx, dy, dz));
private void placeVeilRibbon(Set<BlockPos> foliage, BlockPos start, Direction flow, int length, RandomSource random) {
Direction side = random.nextBoolean() ? flow.getClockWise() : flow.getCounterClockWise();
BlockPos cursor = start;
for (int step = 0; step < length; step++) {
foliage.add(cursor);
if (random.nextFloat() < 0.34F) {
foliage.add(cursor.relative(side));
}
if (random.nextFloat() < 0.18F) {
foliage.add(cursor.relative(side.getOpposite()));
}
cursor = cursor.below();
if (step > 0 && random.nextFloat() < 0.4F) {
cursor = cursor.relative(random.nextBoolean() ? side : side.getOpposite());
}
if (random.nextFloat() < 0.18F) {
BlockPos drift = cursor.relative(flow);
if (random.nextBoolean()) {
foliage.add(drift);
}
}
}
@@ -23,6 +23,8 @@ public final class ThoraxisBiomeSource extends BiomeSource {
private static final int VERTICAL_NOISE_SCALE = 8;
private static final double DUNES_SELECTOR_CUTOFF = 0.38D;
private static final double HILLS_SELECTOR_CUTOFF = 0.24D;
private static final double NADIR_FOREST_SELECTOR_MIN = 0.42D;
private static final double NADIR_FOREST_SELECTOR_MAX = 0.66D;
private static final ResourceKey<Biome> NIGHTMARE_WASTES = ResourceKey.create(
Registries.BIOME,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "nightmare_wastes")
@@ -31,6 +33,10 @@ public final class ThoraxisBiomeSource extends BiomeSource {
Registries.BIOME,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "dream_dunes")
);
private static final ResourceKey<Biome> VORTEX_EXPANSE = ResourceKey.create(
Registries.BIOME,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "vortex_expanse")
);
private static final ResourceKey<Biome> UMBRAL_HILLS = ResourceKey.create(
Registries.BIOME,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "umbral_hills")
@@ -39,16 +45,17 @@ public final class ThoraxisBiomeSource extends BiomeSource {
Registries.BIOME,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "lucid_pools")
);
private static final ResourceKey<Biome> UNDERSIDE = ResourceKey.create(
private static final ResourceKey<Biome> NADIR_FOREST = ResourceKey.create(
Registries.BIOME,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "thoraxis_underside")
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "nadir_forest")
);
public static final MapCodec<ThoraxisBiomeSource> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
MultiNoiseBiomeSource.DIRECT_CODEC.forGetter(ThoraxisBiomeSource::parameters),
Codec.INT.optionalFieldOf("dream_dunes_max_y", 96).forGetter(ThoraxisBiomeSource::dreamDunesMaxY),
Codec.INT.optionalFieldOf("umbral_hills_max_y", 100).forGetter(ThoraxisBiomeSource::umbralHillsMaxY),
Codec.INT.optionalFieldOf("lucid_pools_min_y", 116).forGetter(ThoraxisBiomeSource::lucidPoolsMinY)
Codec.INT.optionalFieldOf("lucid_pools_min_y", 116).forGetter(ThoraxisBiomeSource::lucidPoolsMinY),
Codec.INT.optionalFieldOf("nadir_forest_min_y", 128).forGetter(ThoraxisBiomeSource::nadirForestMinY)
).apply(instance, ThoraxisBiomeSource::new));
private final Climate.ParameterList<Holder<Biome>> parameters;
@@ -56,30 +63,35 @@ public final class ThoraxisBiomeSource extends BiomeSource {
private final int dreamDunesMaxY;
private final int umbralHillsMaxY;
private final int lucidPoolsMinY;
private final int nadirForestMinY;
private final int dreamDunesMaxQuartY;
private final int umbralHillsMaxQuartY;
private final int lucidPoolsMinQuartY;
private final int nadirForestMinQuartY;
private volatile boolean biomesResolved;
private Holder<Biome> nightmareWastesBiome;
private Holder<Biome> dreamDunesBiome;
private Holder<Biome> vortexExpanseBiome;
private Holder<Biome> umbralHillsBiome;
private Holder<Biome> lucidPoolsBiome;
private Holder<Biome> undersideBiome;
private Holder<Biome> nadirForestBiome;
private static final ThreadLocal<Long2DoubleOpenHashMap> REGION_CACHE =
ThreadLocal.withInitial(() -> new Long2DoubleOpenHashMap(512));
private static final ThreadLocal<Long2DoubleOpenHashMap> VERTICAL_CACHE =
ThreadLocal.withInitial(() -> new Long2DoubleOpenHashMap(64));
public ThoraxisBiomeSource(Climate.ParameterList<Holder<Biome>> parameters, int dreamDunesMaxY, int umbralHillsMaxY, int lucidPoolsMinY) {
public ThoraxisBiomeSource(Climate.ParameterList<Holder<Biome>> parameters, int dreamDunesMaxY, int umbralHillsMaxY, int lucidPoolsMinY, int nadirForestMinY) {
this.parameters = parameters;
this.delegate = MultiNoiseBiomeSource.createFromList(parameters);
this.dreamDunesMaxY = dreamDunesMaxY;
this.umbralHillsMaxY = umbralHillsMaxY;
this.lucidPoolsMinY = lucidPoolsMinY;
this.nadirForestMinY = nadirForestMinY;
this.dreamDunesMaxQuartY = QuartPos.fromBlock(dreamDunesMaxY);
this.umbralHillsMaxQuartY = QuartPos.fromBlock(umbralHillsMaxY);
this.lucidPoolsMinQuartY = QuartPos.fromBlock(lucidPoolsMinY);
this.nadirForestMinQuartY = QuartPos.fromBlock(nadirForestMinY);
}
private void resolveBiomesIfNeeded() {
@@ -92,9 +104,10 @@ public final class ThoraxisBiomeSource extends BiomeSource {
}
this.nightmareWastesBiome = this.findBiome(NIGHTMARE_WASTES);
this.dreamDunesBiome = this.findBiome(DREAM_DUNES);
this.vortexExpanseBiome = this.findBiome(VORTEX_EXPANSE);
this.umbralHillsBiome = this.findBiome(UMBRAL_HILLS);
this.lucidPoolsBiome = this.findBiome(LUCID_POOLS);
this.undersideBiome = this.findBiome(UNDERSIDE);
this.nadirForestBiome = this.findBiome(NADIR_FOREST);
this.biomesResolved = true;
}
}
@@ -107,6 +120,10 @@ public final class ThoraxisBiomeSource extends BiomeSource {
return this.lucidPoolsMinY;
}
private int nadirForestMinY() {
return this.nadirForestMinY;
}
private int dreamDunesMaxY() {
return this.dreamDunesMaxY;
}
@@ -128,21 +145,29 @@ public final class ThoraxisBiomeSource extends BiomeSource {
@Override
public Holder<Biome> getNoiseBiome(int x, int y, int z, Climate.Sampler sampler) {
this.resolveBiomesIfNeeded();
if (y < 0 && this.undersideBiome != null) {
return this.undersideBiome;
}
if (y >= this.lucidPoolsMinQuartY && this.lucidPoolsBiome != null) {
return this.lucidPoolsBiome;
if (y < 0 && this.dreamDunesBiome != null) {
return this.dreamDunesBiome;
}
double region = cachedRegionNoise(x, z);
double vertical = cachedVerticalNoise(y);
double dreamDunesSelector = region * 0.65D + (1.0D - vertical) * 0.35D;
double umbralHillsSelector = region * 0.55D + vertical * 0.45D;
double nadirForestSelector = region * 0.78D + vertical * 0.22D;
if (this.dreamDunesBiome != null && y <= this.dreamDunesMaxQuartY && dreamDunesSelector <= DUNES_SELECTOR_CUTOFF) {
return this.dreamDunesBiome;
if (this.nadirForestBiome != null
&& y >= this.nadirForestMinQuartY
&& nadirForestSelector >= NADIR_FOREST_SELECTOR_MIN
&& nadirForestSelector <= NADIR_FOREST_SELECTOR_MAX) {
return this.nadirForestBiome;
}
if (y >= this.lucidPoolsMinQuartY && this.lucidPoolsBiome != null) {
return this.lucidPoolsBiome;
}
if (this.vortexExpanseBiome != null && y <= this.dreamDunesMaxQuartY && dreamDunesSelector <= DUNES_SELECTOR_CUTOFF) {
return this.vortexExpanseBiome;
}
if (this.umbralHillsBiome != null && y <= this.umbralHillsMaxQuartY && umbralHillsSelector <= HILLS_SELECTOR_CUTOFF) {
@@ -158,6 +183,7 @@ public final class ThoraxisBiomeSource extends BiomeSource {
this.delegate.addDebugInfo(debug, pos, sampler);
debug.add("Thoraxis selector: mixed vertical/region noise");
debug.add("Thoraxis Lucid Pools: y>=" + this.lucidPoolsMinY);
debug.add("Thoraxis Nadir Forest: y>=" + this.nadirForestMinY);
}
private Holder<Biome> findBiome(ResourceKey<Biome> key) {
@@ -2,19 +2,24 @@ package com.craisinlord.antarchy.content.worldgen.thoraxis;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.block.DreamSandBlock;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityTransition;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
public final class ThoraxisUndersideManager {
public static final int GRAVITY_FLIP_Y = 0;
@@ -43,10 +48,7 @@ public final class ThoraxisUndersideManager {
if (entity instanceof LivingEntity living) {
UUID uuid = entity.getUUID();
if (inUnderside) {
if (!living.hasEffect(AntarchyObjects.INVERTED_EFFECT.get())) {
living.addEffect(new MobEffectInstance(AntarchyObjects.INVERTED_EFFECT.get(), EFFECT_DURATION_TICKS, 0, true, false, false));
UNDERSIDE_APPLIED_EFFECT.add(uuid);
}
applyUndersideInversion(living);
} else if (UNDERSIDE_APPLIED_EFFECT.remove(uuid)) {
if (living.hasEffect(AntarchyObjects.INVERTED_EFFECT.get())) {
living.removeEffect(AntarchyObjects.INVERTED_EFFECT.get());
@@ -84,6 +86,38 @@ public final class ThoraxisUndersideManager {
UNDERSIDE_FORCED_GRAVITY.retainAll(activeThisTick);
}
public static void applyUndersideInversion(LivingEntity living) {
UNDERSIDE_APPLIED_EFFECT.add(living.getUUID());
if (!living.hasEffect(AntarchyObjects.INVERTED_EFFECT.get())) {
living.addEffect(new MobEffectInstance(AntarchyObjects.INVERTED_EFFECT.get(), EFFECT_DURATION_TICKS, 0, true, false, false));
}
if (AntarchyGravityApi.getGravityDirection(living) != AntarchyGravityDirection.UP
|| !AntarchyGravityApi.isGravityForced(living)) {
AntarchyGravityApi.setForcedGravityDirection(living, AntarchyGravityDirection.UP, TRANSITION);
}
}
public static boolean shouldSpawnInvertedOnDreamSand(ServerLevelAccessor level, BlockPos pos) {
if (!isThoraxis(level.getLevel()) || pos.getY() >= GRAVITY_FLIP_Y) {
return false;
}
BlockState bodyState = level.getBlockState(pos);
if (!bodyState.isAir() && !bodyState.getCollisionShape(level, pos).isEmpty()) {
return false;
}
BlockPos supportPos = pos.above();
BlockState supportState = level.getBlockState(supportPos);
if (!(supportState.getBlock() instanceof DreamSandBlock)) {
return false;
}
return supportState.isFaceSturdy(level, supportPos, Direction.DOWN)
&& level.getFluidState(pos).isEmpty()
&& level.isEmptyBlock(pos.below());
}
public static boolean isThoraxis(Level level) {
return level.dimension().location().equals(THORAXIS_DIMENSION);
}
@@ -0,0 +1,27 @@
package com.craisinlord.antarchy.content.worldgen.thoraxis;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
public record TyphoniteSpikeConfiguration(
int floorToCeilingSearchRange,
int radius,
int maxColumnHeight,
int heightDeviation,
float chanceOfColumnAtMaxDistanceFromCenter,
int maxDistanceFromCenterAffectingChanceOfColumn,
int maxDistanceFromCenterAffectingHeightBias,
int maxHeightDifference
) implements FeatureConfiguration {
public static final Codec<TyphoniteSpikeConfiguration> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.intRange(1, 128).fieldOf("floor_to_ceiling_search_range").forGetter(TyphoniteSpikeConfiguration::floorToCeilingSearchRange),
Codec.intRange(1, 32).fieldOf("radius").forGetter(TyphoniteSpikeConfiguration::radius),
Codec.intRange(1, 32).fieldOf("max_column_height").forGetter(TyphoniteSpikeConfiguration::maxColumnHeight),
Codec.intRange(1, 16).fieldOf("height_deviation").forGetter(TyphoniteSpikeConfiguration::heightDeviation),
Codec.floatRange(0.0F, 1.0F).fieldOf("chance_of_column_at_max_distance_from_center").forGetter(TyphoniteSpikeConfiguration::chanceOfColumnAtMaxDistanceFromCenter),
Codec.intRange(1, 64).fieldOf("max_distance_from_center_affecting_chance_of_column").forGetter(TyphoniteSpikeConfiguration::maxDistanceFromCenterAffectingChanceOfColumn),
Codec.intRange(1, 64).fieldOf("max_distance_from_center_affecting_height_bias").forGetter(TyphoniteSpikeConfiguration::maxDistanceFromCenterAffectingHeightBias),
Codec.intRange(0, 32).fieldOf("max_height_difference").forGetter(TyphoniteSpikeConfiguration::maxHeightDifference)
).apply(instance, TyphoniteSpikeConfiguration::new));
}
@@ -0,0 +1,203 @@
package com.craisinlord.antarchy.content.worldgen.thoraxis;
import com.craisinlord.antarchy.Antarchy;
import com.mojang.serialization.Codec;
import java.util.Optional;
import java.util.OptionalInt;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.PointedDripstoneBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.DripstoneThickness;
import net.minecraft.world.level.levelgen.Column;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
public class TyphoniteSpikeFeature extends Feature<TyphoniteSpikeConfiguration> {
private static final ResourceLocation TYPHONITE_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "typhonite");
private static final ResourceLocation TYPHONITE_SPIKE_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "typhonite_spike");
public TyphoniteSpikeFeature(Codec<TyphoniteSpikeConfiguration> codec) {
super(codec);
}
@Override
public boolean place(FeaturePlaceContext<TyphoniteSpikeConfiguration> context) {
WorldGenLevel level = context.level();
BlockPos origin = context.origin();
TyphoniteSpikeConfiguration config = context.config();
RandomSource random = context.random();
if (!level.getBlockState(origin).isAir()) {
return false;
}
boolean placedAny = false;
int radius = config.radius();
for (int dx = -radius; dx <= radius; dx++) {
for (int dz = -radius; dz <= radius; dz++) {
double chance = this.getChanceOfColumn(radius, dx, dz, config);
if (chance <= 0.0D) {
continue;
}
if (this.placeColumn(level, random, origin.offset(dx, 0, dz), dx, dz, chance, config)) {
placedAny = true;
}
}
}
return placedAny;
}
private boolean placeColumn(
WorldGenLevel level,
RandomSource random,
BlockPos pos,
int dx,
int dz,
double chance,
TyphoniteSpikeConfiguration config
) {
Optional<Column> optional = Column.scan(level, pos, config.floorToCeilingSearchRange(), state -> state.isAir(), state -> !state.isAir());
if (optional.isEmpty()) {
return false;
}
Column column = optional.get();
OptionalInt ceiling = column.getCeiling();
OptionalInt floor = column.getFloor();
boolean canGrowDown = ceiling.isPresent() && isTyphonite(level.getBlockState(pos.atY(ceiling.getAsInt())));
boolean canGrowUp = floor.isPresent() && isTyphonite(level.getBlockState(pos.atY(floor.getAsInt())));
if (!canGrowDown && !canGrowUp) {
return false;
}
int downLength = 0;
int upLength = 0;
if (canGrowDown) {
int maxLength = this.getMaxLength(config, ceiling, floor);
downLength = this.getSpikeHeight(random, dx, dz, chance, maxLength, config);
}
if (canGrowUp) {
int maxLength = this.getMaxLength(config, ceiling, floor);
if (downLength > 0) {
upLength = Mth.clamp(
downLength + Mth.randomBetweenInclusive(random, -config.maxHeightDifference(), config.maxHeightDifference()),
0,
maxLength
);
} else {
upLength = this.getSpikeHeight(random, dx, dz, chance, maxLength, config);
}
}
if (ceiling.isPresent() && floor.isPresent() && downLength > 0 && upLength > 0 && ceiling.getAsInt() - downLength <= floor.getAsInt() + upLength) {
int floorY = floor.getAsInt();
int ceilingY = ceiling.getAsInt();
int minSplit = Math.max(ceilingY - downLength, floorY + 1);
int maxSplit = Math.min(floorY + upLength, ceilingY - 1);
int split = Mth.randomBetweenInclusive(random, minSplit, maxSplit + 1);
int tipBelowCeiling = split - 1;
downLength = ceilingY - split;
upLength = tipBelowCeiling - floorY;
}
boolean placedAny = false;
if (downLength > 0 && ceiling.isPresent()) {
placedAny |= this.growPointedTyphonite(level, pos.atY(ceiling.getAsInt() - 1), Direction.DOWN, downLength);
}
if (upLength > 0 && floor.isPresent()) {
placedAny |= this.growPointedTyphonite(level, pos.atY(floor.getAsInt() + 1), Direction.UP, upLength);
}
return placedAny;
}
private int getMaxLength(TyphoniteSpikeConfiguration config, OptionalInt ceiling, OptionalInt floor) {
if (ceiling.isPresent() && floor.isPresent()) {
return Math.min(config.maxColumnHeight(), ceiling.getAsInt() - floor.getAsInt() - 1);
}
return config.maxColumnHeight();
}
private boolean growPointedTyphonite(WorldGenLevel level, BlockPos rootStart, Direction direction, int length) {
Block typhoniteSpike = BuiltInRegistries.BLOCK.get(TYPHONITE_SPIKE_ID);
boolean placedAny = false;
for (int offset = 0; offset < length; offset++) {
BlockPos spikePos = rootStart.relative(direction, offset);
if (spikePos.getY() < level.getMinBuildHeight() || spikePos.getY() >= level.getMaxBuildHeight()) {
break;
}
if (!level.getBlockState(spikePos).isAir()) {
break;
}
BlockState spikeState = typhoniteSpike.defaultBlockState()
.setValue(PointedDripstoneBlock.TIP_DIRECTION, direction)
.setValue(PointedDripstoneBlock.THICKNESS, getThicknessForRootOffset(offset, length))
.setValue(PointedDripstoneBlock.WATERLOGGED, false);
if (!spikeState.canSurvive(level, spikePos)) {
break;
}
level.setBlock(spikePos, spikeState, 3);
placedAny = true;
}
return placedAny;
}
private static DripstoneThickness getThicknessForRootOffset(int offsetFromRoot, int length) {
if (length <= 1) {
return DripstoneThickness.TIP;
}
if (offsetFromRoot == length - 1) {
return DripstoneThickness.TIP;
}
if (offsetFromRoot == length - 2) {
return DripstoneThickness.FRUSTUM;
}
if (offsetFromRoot == 0) {
return DripstoneThickness.BASE;
}
return DripstoneThickness.MIDDLE;
}
private int getSpikeHeight(RandomSource random, int dx, int dz, double chance, int maxHeight, TyphoniteSpikeConfiguration config) {
if (maxHeight <= 0 || random.nextDouble() > chance) {
return 0;
}
int distance = Math.abs(dx) + Math.abs(dz);
float mean = (float) Mth.clampedMap(
(double) distance,
0.0D,
(double) config.maxDistanceFromCenterAffectingHeightBias(),
(double) maxHeight,
1.0D
);
int sampled = Math.round((float) (mean + random.nextGaussian() * config.heightDeviation()));
return Mth.clamp(sampled, 1, maxHeight);
}
private double getChanceOfColumn(int radius, int dx, int dz, TyphoniteSpikeConfiguration config) {
int remainingX = radius - Math.abs(dx);
int remainingZ = radius - Math.abs(dz);
int edgeDistance = Math.min(remainingX, remainingZ);
return Mth.clampedMap(
(double) edgeDistance,
0.0D,
(double) config.maxDistanceFromCenterAffectingChanceOfColumn(),
(double) config.chanceOfColumnAtMaxDistanceFromCenter(),
1.0D
);
}
private static boolean isTyphonite(BlockState state) {
return BuiltInRegistries.BLOCK.getKey(state.getBlock()).equals(TYPHONITE_ID);
}
}
@@ -0,0 +1,20 @@
package com.craisinlord.antarchy.mixins;
import com.craisinlord.antarchy.content.item.BloodCrystalKatanaItem;
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Entity.class)
public abstract class BloodCrystalKatanaDashPhaseMixin {
@Inject(method = "push(Lnet/minecraft/world/entity/Entity;)V", at = @At("HEAD"), cancellable = true)
private void antarchy$katanaDashPassThrough(Entity entity, CallbackInfo ci) {
Entity self = (Entity) (Object) this;
if (BloodCrystalKatanaItem.isDashing(self) || BloodCrystalKatanaItem.isDashing(entity)) {
ci.cancel();
}
}
}
@@ -2,9 +2,9 @@ package com.craisinlord.antarchy.mixins;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.entity.UpwardFallingBlockEntity;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.item.FallingBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -12,14 +12,14 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(FallingBlockEntity.class)
@Mixin(UpwardFallingBlockEntity.class)
public abstract class DreamSandFallingSpeedMixin {
private static final ResourceLocation DREAM_SAND_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "dream_sand");
@Shadow public abstract BlockState getBlockState();
@Inject(method = "getDefaultGravity", at = @At("RETURN"), cancellable = true)
private void antarchy$slowDreamSandFall(CallbackInfoReturnable<Double> cir) {
@Inject(method = "getRiseAccel", at = @At("RETURN"), cancellable = true, remap = false)
private void antarchy$slowDreamSandRise(CallbackInfoReturnable<Double> cir) {
if (BuiltInRegistries.BLOCK.getKey(this.getBlockState().getBlock()).equals(DREAM_SAND_ID)) {
cir.setReturnValue(cir.getReturnValue() * AntarchySettings.dreamSandFallingBlockGravityMultiplier());
}
@@ -1,14 +1,23 @@
package com.craisinlord.antarchy.mixins;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.block.DreamSandBlock;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
import com.craisinlord.antarchy.content.movement.DreamSandLowGravityAccess;
import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(LivingEntity.class)
/*
* Stores per-entity dream sand low-grav state.
*/
public abstract class DreamSandLowGravityMixin implements DreamSandLowGravityAccess {
@Unique
private boolean antarchy$dreamSandLowGravityActive;
@@ -46,4 +55,79 @@ public abstract class DreamSandLowGravityMixin implements DreamSandLowGravityAcc
public void antarchy$setDreamSandLandingGraceTicks(int ticks) {
this.antarchy$dreamSandLandingGraceTicks = Math.max(0, ticks);
}
@Inject(method = "tick", at = @At("TAIL"))
private void antarchy$updateDreamSandLowGravity(CallbackInfo ci) {
LivingEntity self = (LivingEntity) (Object) this;
if (!AntarchySettings.dreamSandEnabled()) {
this.antarchy$clearDreamSandLowGravity();
return;
}
boolean supportedByDreamSand = this.antarchy$isSupportedByDreamSand(self);
int durationTicks = Math.max(1, Mth.ceil(AntarchySettings.dreamSandEffectDurationSeconds() * 20.0D));
if (supportedByDreamSand) {
this.antarchy$dreamSandLowGravityActive = true;
this.antarchy$dreamSandLowGravityTicksRemaining = durationTicks;
this.antarchy$dreamSandLandingGraceTicks = 5;
} else if (this.antarchy$dreamSandLowGravityTicksRemaining > 0) {
this.antarchy$dreamSandLowGravityTicksRemaining--;
this.antarchy$dreamSandLowGravityActive = true;
} else {
this.antarchy$dreamSandLowGravityActive = false;
}
if (this.antarchy$dreamSandLandingGraceTicks > 0 && !supportedByDreamSand) {
this.antarchy$dreamSandLandingGraceTicks--;
}
if (!this.antarchy$dreamSandLowGravityActive || self.onGround() || self.onClimbable() || self.isInWaterOrBubble() || self.isInLava()) {
return;
}
AntarchyGravityDirection gravityDirection = AntarchyGravityApi.getGravityDirection(self);
Vec3 localMotion = AntarchyGravityRotationUtil.vecWorldToPlayer(self.getDeltaMovement(), gravityDirection);
if (localMotion.y >= 0.0D) {
return;
}
double gravityMultiplier = Math.max(0.0D, Math.min(1.0D, AntarchySettings.dreamSandGravityMultiplier()));
Vec3 adjustedLocalMotion = new Vec3(localMotion.x, localMotion.y * gravityMultiplier, localMotion.z);
self.setDeltaMovement(AntarchyGravityRotationUtil.vecPlayerToWorld(adjustedLocalMotion, gravityDirection));
self.fallDistance = 0.0F;
this.antarchy$dreamSandLandingGraceTicks = 5;
}
@Inject(method = "jumpFromGround", at = @At("TAIL"))
private void antarchy$boostDreamSandJump(CallbackInfo ci) {
if (!this.antarchy$dreamSandLowGravityActive) {
return;
}
LivingEntity self = (LivingEntity) (Object) this;
AntarchyGravityDirection gravityDirection = AntarchyGravityApi.getGravityDirection(self);
Vec3 localMotion = AntarchyGravityRotationUtil.vecWorldToPlayer(self.getDeltaMovement(), gravityDirection);
if (localMotion.y <= 0.0D) {
return;
}
Vec3 adjustedLocalMotion = new Vec3(
localMotion.x,
localMotion.y * AntarchySettings.dreamSandJumpVelocityMultiplier(),
localMotion.z
);
self.setDeltaMovement(AntarchyGravityRotationUtil.vecPlayerToWorld(adjustedLocalMotion, gravityDirection));
self.fallDistance = 0.0F;
this.antarchy$dreamSandLandingGraceTicks = 5;
}
@Unique
private boolean antarchy$isSupportedByDreamSand(LivingEntity entity) {
AntarchyGravityDirection gravityDirection = AntarchyGravityApi.getGravityDirection(entity);
AABB box = entity.getBoundingBox();
BlockPos supportPos = gravityDirection.isInverted()
? BlockPos.containing(entity.getX(), box.maxY + 0.05D, entity.getZ())
: BlockPos.containing(entity.getX(), box.minY - 0.05D, entity.getZ());
return entity.level().getBlockState(supportPos).getBlock() instanceof DreamSandBlock;
}
}
@@ -11,9 +11,6 @@ import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
@@ -28,8 +25,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
* Adds the base gravity state and sync hooks to entities.
*/
public abstract class EntityGravityMixin implements AntarchyGravityAccess {
@Unique
private static final Logger LOGGER = LoggerFactory.getLogger("Antarchy/FallDamage");
@Unique
private static final String ANTARCHY_GRAVITY_DIRECTION_TAG = "AntarchyGravityDirection";
@Unique
@@ -97,21 +92,7 @@ public abstract class EntityGravityMixin implements AntarchyGravityAccess {
return;
}
Vec3 localMotion = AntarchyGravityRotationUtil.vecWorldToPlayer(entity.getDeltaMovement(), direction);
float previousFallDistance = entity.fallDistance;
entity.resetFallDistance();
if (!entity.level().isClientSide && LOGGER.isDebugEnabled()) {
LOGGER.debug(
"[FallDamage] Antiwater contact reset during fluid update: entity={} pos={} localMotion={} previousFallDistance={} onGround={} inWaterStateReturned={}",
entity.getClass().getSimpleName(),
entity.position(),
localMotion,
previousFallDistance,
entity.onGround(),
cir.getReturnValue()
);
}
}
@Override
@@ -211,17 +192,7 @@ public abstract class EntityGravityMixin implements AntarchyGravityAccess {
return worldY;
}
double invertedY = -worldY;
LOGGER.debug(
"[FallDamage] Entity {} inverted checkFallDamage fallback: worldY={} invertedY={} fallDistance={} onGround={} deltaMovement={}",
entity.getClass().getSimpleName(),
worldY,
invertedY,
entity.fallDistance,
entity.onGround(),
entity.getDeltaMovement()
);
return invertedY;
return -worldY;
}
@Unique
@@ -16,8 +16,6 @@ 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;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
@@ -32,9 +30,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
* Fixes move/landing logic that assumes down is always down.
*/
public abstract class EntityMoveMixin {
@Unique
private static final Logger ANTARCHY_FALL_LOGGER = LoggerFactory.getLogger("Antarchy/FallDamage");
@Unique
private double antarchy$lastWorldMoveY = 0.0;
@Unique
@@ -132,20 +127,7 @@ public abstract class EntityMoveMixin {
Vec3 delta = endBox.getCenter().subtract(this.antarchy$moveStartBox.getCenter());
AABB sweptBox = this.antarchy$moveStartBox.expandTowards(delta).minmax(endBox).inflate(0.05D);
if (antarchy$intersectsAntiwater(entity, sweptBox)) {
float previousFallDistance = entity.fallDistance;
entity.resetFallDistance();
if (!entity.level().isClientSide && ANTARCHY_FALL_LOGGER.isDebugEnabled()) {
ANTARCHY_FALL_LOGGER.debug(
"[FallDamage] Antiwater contact reset during move: entity={} startBox={} endBox={} sweptBox={} playerMoveY={} worldMoveY={} previousFallDistance={}",
entity.getClass().getSimpleName(),
this.antarchy$moveStartBox,
endBox,
sweptBox,
this.antarchy$lastPlayerMoveY,
this.antarchy$lastWorldMoveY,
previousFallDistance
);
}
}
}
@@ -2,8 +2,6 @@ package com.craisinlord.antarchy.mixins.gravity;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
import com.craisinlord.antarchy.content.gravity.GravityWalkNodeEvaluator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.minecraft.world.entity.ai.navigation.GroundPathNavigation;
import net.minecraft.world.level.pathfinder.NodeEvaluator;
import net.minecraft.world.level.pathfinder.PathFinder;
@@ -17,20 +15,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
* Makes ground pathing read gravity-aware floor checks.
*/
public abstract class GroundPathNavigationMixin {
private static final Logger LOGGER = LoggerFactory.getLogger("Antarchy/Pathfinding");
@Inject(method = "createPathFinder", at = @At("HEAD"), cancellable = true)
private void antarchy$useGravityEvaluator(int maxVisitedNodes, CallbackInfoReturnable<PathFinder> cir) {
var accessor = (PathNavigationAccessor) (Object) this;
var mob = accessor.antarchy$getMob();
if (AntarchyGravityApi.isGravityInverted(mob)) {
LOGGER.debug(
"[Path] swap evaluator mob={} maxVisitedNodes={}",
mob.getClass().getSimpleName(),
maxVisitedNodes
);
}
NodeEvaluator evaluator = new GravityWalkNodeEvaluator();
accessor.antarchy$setNodeEvaluator(evaluator);
cir.setReturnValue(new PathFinder(evaluator, maxVisitedNodes));
@@ -1,133 +0,0 @@
package com.craisinlord.antarchy.mixins.gravity;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.ai.navigation.PathNavigation;
import net.minecraft.world.level.pathfinder.Path;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(PathNavigation.class)
/*
* Keeps path debug shapes lined up with gravity-aware nav.
*/
public abstract class PathNavigationDebugMixin {
private static final Logger LOGGER = LoggerFactory.getLogger("Antarchy/Pathfinding");
@Unique
private int antarchy$debugTickCooldown;
@Inject(method = "moveTo(DDDD)Z", at = @At("HEAD"))
private void antarchy$logMoveToPosition(double x, double y, double z, double speed, CallbackInfoReturnable<Boolean> cir) {
var mob = ((PathNavigationAccessor) (Object) this).antarchy$getMob();
if (!AntarchyGravityApi.isGravityInverted(mob)) {
return;
}
LOGGER.debug(
"[Path] moveTo(pos) inverted mob={} target=({}, {}, {}) speed={}",
mob.getClass().getSimpleName(),
x,
y,
z,
speed
);
}
@Inject(method = "moveTo(Lnet/minecraft/world/level/pathfinder/Path;D)Z", at = @At("HEAD"))
private void antarchy$logMoveToPath(Path path, double speed, CallbackInfoReturnable<Boolean> cir) {
var mob = ((PathNavigationAccessor) (Object) this).antarchy$getMob();
if (!AntarchyGravityApi.isGravityInverted(mob)) {
return;
}
LOGGER.debug(
"[Path] moveTo(path) inverted mob={} nodes={} nextIndex={} speed={}",
mob.getClass().getSimpleName(),
path == null ? -1 : path.getNodeCount(),
path == null ? -1 : path.getNextNodeIndex(),
speed
);
}
@Inject(method = "createPath(DDDI)Lnet/minecraft/world/level/pathfinder/Path;", at = @At("RETURN"))
private void antarchy$logCreatePath(double x, double y, double z, int accuracy, CallbackInfoReturnable<Path> cir) {
var mob = ((PathNavigationAccessor) (Object) this).antarchy$getMob();
if (!AntarchyGravityApi.isGravityInverted(mob)) {
return;
}
Path path = cir.getReturnValue();
LOGGER.debug(
"[Path] createPath(pos) inverted mob={} target=({}, {}, {}) accuracy={} result={}",
mob.getClass().getSimpleName(),
x,
y,
z,
accuracy,
path == null ? "null" : ("nodes=" + path.getNodeCount() + " nextIndex=" + path.getNextNodeIndex())
);
}
@Inject(method = "createPath(Lnet/minecraft/world/entity/Entity;I)Lnet/minecraft/world/level/pathfinder/Path;", at = @At("RETURN"))
private void antarchy$logCreatePath(Entity target, int accuracy, CallbackInfoReturnable<Path> cir) {
var mob = ((PathNavigationAccessor) (Object) this).antarchy$getMob();
if (!AntarchyGravityApi.isGravityInverted(mob)) {
return;
}
Path path = cir.getReturnValue();
LOGGER.debug(
"[Path] createPath(entity) inverted mob={} target={} accuracy={} result={}",
mob.getClass().getSimpleName(),
target == null ? "null" : target.getClass().getSimpleName(),
accuracy,
path == null ? "null" : ("nodes=" + path.getNodeCount() + " nextIndex=" + path.getNextNodeIndex())
);
}
@Inject(method = "createPath(Lnet/minecraft/core/BlockPos;I)Lnet/minecraft/world/level/pathfinder/Path;", at = @At("RETURN"))
private void antarchy$logCreatePath(BlockPos target, int accuracy, CallbackInfoReturnable<Path> cir) {
var mob = ((PathNavigationAccessor) (Object) this).antarchy$getMob();
if (!AntarchyGravityApi.isGravityInverted(mob)) {
return;
}
Path path = cir.getReturnValue();
LOGGER.debug(
"[Path] createPath(blockpos) inverted mob={} target={} accuracy={} result={}",
mob.getClass().getSimpleName(),
target,
accuracy,
path == null ? "null" : ("nodes=" + path.getNodeCount() + " nextIndex=" + path.getNextNodeIndex())
);
}
@Inject(method = "tick", at = @At("HEAD"))
private void antarchy$logTick(CallbackInfo ci) {
var mob = ((PathNavigationAccessor) (Object) this).antarchy$getMob();
if (!AntarchyGravityApi.isGravityInverted(mob)) {
return;
}
if (this.antarchy$debugTickCooldown-- > 0) {
return;
}
this.antarchy$debugTickCooldown = 20;
Path path = ((PathNavigationAccessor) (Object) this).antarchy$getPath();
LOGGER.debug(
"[Path] tick inverted mob={} pathPresent={} pathDone={}",
mob.getClass().getSimpleName(),
path != null,
path != null && path.isDone()
);
}
}
@@ -9,8 +9,6 @@ import net.minecraft.world.entity.player.Abilities;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -24,8 +22,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
*/
public abstract class PlayerSneakMixin {
private static final Logger LOGGER = LoggerFactory.getLogger("Antarchy/Sneak");
@Shadow @Final private Abilities abilities;
@Shadow protected abstract boolean isStayingOnGroundSurface();
@@ -52,9 +48,6 @@ public abstract class PlayerSneakMixin {
}
}
LOGGER.debug("[Sneak] inverted player maybeBackOffFromEdge: isNearCeiling={} flying={} stayOnGround={} type={}",
isNearCeiling, this.abilities.flying, this.isStayingOnGroundSurface(), type);
if (!this.abilities.flying
&& (type == MoverType.SELF || type == MoverType.PLAYER)
&& this.isStayingOnGroundSurface()
@@ -63,7 +56,6 @@ public abstract class PlayerSneakMixin {
double d = playerMovement.x;
double e = playerMovement.z;
LOGGER.debug("[Sneak] Edge check active: step={} d={} e={}", step, d, e);
while (d != 0.0D && canFallAtLeastInverted(this_, d, 0.0D, step, direction)) {
if (Math.abs(d) <= 0.05D) d = 0.0D;
else if (d > 0.0D) d -= 0.05D;
@@ -84,7 +76,6 @@ public abstract class PlayerSneakMixin {
else e += 0.05D;
}
LOGGER.debug("[Sneak] Adjusted: x {} -> {} z {} -> {}", playerMovement.x, d, playerMovement.z, e);
cir.setReturnValue(AntarchyGravityRotationUtil.vecPlayerToWorld(
new Vec3(d, playerMovement.y, e), direction));
@@ -11,6 +11,7 @@
"AmericanFoodConsumeMixin",
"AmericanFoodNameMixin",
"BlockEntityTypeSignMixin",
"BloodCrystalKatanaDashPhaseMixin",
"BloodglassMixin",
"DreamFireBlockMixin",
"DreamSandFallingSpeedMixin",
@@ -66,7 +67,6 @@
"gravity.LivingEntityMixin",
"gravity.MobHurtMixin",
"gravity.PathNavigationAccessor",
"gravity.PathNavigationDebugMixin",
"gravity.PlayerAttackMixin",
"gravity.PlayerGravityMixin",
"gravity.PlayerPoseFitMixin",
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "antarchy:block/chiseled_typhonite"
}
}
}
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "antarchy:block/polished_typhonite"
}
}
}
@@ -0,0 +1,13 @@
{
"variants": {
"type=double": {
"model": "antarchy:block/polished_typhonite"
},
"type=bottom": {
"model": "antarchy:block/polished_typhonite_slab"
},
"type=top": {
"model": "antarchy:block/polished_typhonite_slab_top"
}
}
}
@@ -0,0 +1,209 @@
{
"variants": {
"facing=east,half=bottom,shape=inner_left": {
"model": "antarchy:block/polished_typhonite_stairs_inner",
"uvlock": true,
"y": 270
},
"facing=east,half=bottom,shape=inner_right": {
"model": "antarchy:block/polished_typhonite_stairs_inner"
},
"facing=east,half=bottom,shape=outer_left": {
"model": "antarchy:block/polished_typhonite_stairs_outer",
"uvlock": true,
"y": 270
},
"facing=east,half=bottom,shape=outer_right": {
"model": "antarchy:block/polished_typhonite_stairs_outer"
},
"facing=east,half=bottom,shape=straight": {
"model": "antarchy:block/polished_typhonite_stairs"
},
"facing=east,half=top,shape=inner_left": {
"model": "antarchy:block/polished_typhonite_stairs_inner",
"uvlock": true,
"x": 180
},
"facing=east,half=top,shape=inner_right": {
"model": "antarchy:block/polished_typhonite_stairs_inner",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=east,half=top,shape=outer_left": {
"model": "antarchy:block/polished_typhonite_stairs_outer",
"uvlock": true,
"x": 180
},
"facing=east,half=top,shape=outer_right": {
"model": "antarchy:block/polished_typhonite_stairs_outer",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=east,half=top,shape=straight": {
"model": "antarchy:block/polished_typhonite_stairs",
"uvlock": true,
"x": 180
},
"facing=north,half=bottom,shape=inner_left": {
"model": "antarchy:block/polished_typhonite_stairs_inner",
"uvlock": true,
"y": 180
},
"facing=north,half=bottom,shape=inner_right": {
"model": "antarchy:block/polished_typhonite_stairs_inner",
"uvlock": true,
"y": 270
},
"facing=north,half=bottom,shape=outer_left": {
"model": "antarchy:block/polished_typhonite_stairs_outer",
"uvlock": true,
"y": 180
},
"facing=north,half=bottom,shape=outer_right": {
"model": "antarchy:block/polished_typhonite_stairs_outer",
"uvlock": true,
"y": 270
},
"facing=north,half=bottom,shape=straight": {
"model": "antarchy:block/polished_typhonite_stairs",
"uvlock": true,
"y": 270
},
"facing=north,half=top,shape=inner_left": {
"model": "antarchy:block/polished_typhonite_stairs_inner",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=north,half=top,shape=inner_right": {
"model": "antarchy:block/polished_typhonite_stairs_inner",
"uvlock": true,
"x": 180
},
"facing=north,half=top,shape=outer_left": {
"model": "antarchy:block/polished_typhonite_stairs_outer",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=north,half=top,shape=outer_right": {
"model": "antarchy:block/polished_typhonite_stairs_outer",
"uvlock": true,
"x": 180
},
"facing=north,half=top,shape=straight": {
"model": "antarchy:block/polished_typhonite_stairs",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=south,half=bottom,shape=inner_left": {
"model": "antarchy:block/polished_typhonite_stairs_inner"
},
"facing=south,half=bottom,shape=inner_right": {
"model": "antarchy:block/polished_typhonite_stairs_inner",
"uvlock": true,
"y": 90
},
"facing=south,half=bottom,shape=outer_left": {
"model": "antarchy:block/polished_typhonite_stairs_outer"
},
"facing=south,half=bottom,shape=outer_right": {
"model": "antarchy:block/polished_typhonite_stairs_outer",
"uvlock": true,
"y": 90
},
"facing=south,half=bottom,shape=straight": {
"model": "antarchy:block/polished_typhonite_stairs",
"uvlock": true,
"y": 90
},
"facing=south,half=top,shape=inner_left": {
"model": "antarchy:block/polished_typhonite_stairs_inner",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=south,half=top,shape=inner_right": {
"model": "antarchy:block/polished_typhonite_stairs_inner",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=south,half=top,shape=outer_left": {
"model": "antarchy:block/polished_typhonite_stairs_outer",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=south,half=top,shape=outer_right": {
"model": "antarchy:block/polished_typhonite_stairs_outer",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=south,half=top,shape=straight": {
"model": "antarchy:block/polished_typhonite_stairs",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=west,half=bottom,shape=inner_left": {
"model": "antarchy:block/polished_typhonite_stairs_inner",
"uvlock": true,
"y": 90
},
"facing=west,half=bottom,shape=inner_right": {
"model": "antarchy:block/polished_typhonite_stairs_inner",
"uvlock": true,
"y": 180
},
"facing=west,half=bottom,shape=outer_left": {
"model": "antarchy:block/polished_typhonite_stairs_outer",
"uvlock": true,
"y": 90
},
"facing=west,half=bottom,shape=outer_right": {
"model": "antarchy:block/polished_typhonite_stairs_outer",
"uvlock": true,
"y": 180
},
"facing=west,half=bottom,shape=straight": {
"model": "antarchy:block/polished_typhonite_stairs",
"uvlock": true,
"y": 180
},
"facing=west,half=top,shape=inner_left": {
"model": "antarchy:block/polished_typhonite_stairs_inner",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=west,half=top,shape=inner_right": {
"model": "antarchy:block/polished_typhonite_stairs_inner",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=west,half=top,shape=outer_left": {
"model": "antarchy:block/polished_typhonite_stairs_outer",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=west,half=top,shape=outer_right": {
"model": "antarchy:block/polished_typhonite_stairs_outer",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=west,half=top,shape=straight": {
"model": "antarchy:block/polished_typhonite_stairs",
"uvlock": true,
"x": 180,
"y": 180
}
}
}
@@ -0,0 +1,40 @@
{
"multipart": [
{
"when": { "up": "true" },
"apply": { "model": "antarchy:block/polished_typhonite_wall_post" }
},
{
"when": { "north": "low" },
"apply": { "model": "antarchy:block/polished_typhonite_wall_side", "uvlock": true }
},
{
"when": { "east": "low" },
"apply": { "model": "antarchy:block/polished_typhonite_wall_side", "y": 90, "uvlock": true }
},
{
"when": { "south": "low" },
"apply": { "model": "antarchy:block/polished_typhonite_wall_side", "y": 180, "uvlock": true }
},
{
"when": { "west": "low" },
"apply": { "model": "antarchy:block/polished_typhonite_wall_side", "y": 270, "uvlock": true }
},
{
"when": { "north": "tall" },
"apply": { "model": "antarchy:block/polished_typhonite_wall_side_tall", "uvlock": true }
},
{
"when": { "east": "tall" },
"apply": { "model": "antarchy:block/polished_typhonite_wall_side_tall", "y": 90, "uvlock": true }
},
{
"when": { "south": "tall" },
"apply": { "model": "antarchy:block/polished_typhonite_wall_side_tall", "y": 180, "uvlock": true }
},
{
"when": { "west": "tall" },
"apply": { "model": "antarchy:block/polished_typhonite_wall_side_tall", "y": 270, "uvlock": true }
}
]
}
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "antarchy:block/spiraling_vines"
}
}
}
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "antarchy:block/spiraling_vines_plant"
}
}
}
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "antarchy:block/typhonite"
}
}
}
@@ -0,0 +1,13 @@
{
"variants": {
"type=double": {
"model": "antarchy:block/typhonite_bricks"
},
"type=bottom": {
"model": "antarchy:block/typhonite_brick_slab"
},
"type=top": {
"model": "antarchy:block/typhonite_brick_slab_top"
}
}
}
@@ -0,0 +1,209 @@
{
"variants": {
"facing=east,half=bottom,shape=inner_left": {
"model": "antarchy:block/typhonite_brick_stairs_inner",
"uvlock": true,
"y": 270
},
"facing=east,half=bottom,shape=inner_right": {
"model": "antarchy:block/typhonite_brick_stairs_inner"
},
"facing=east,half=bottom,shape=outer_left": {
"model": "antarchy:block/typhonite_brick_stairs_outer",
"uvlock": true,
"y": 270
},
"facing=east,half=bottom,shape=outer_right": {
"model": "antarchy:block/typhonite_brick_stairs_outer"
},
"facing=east,half=bottom,shape=straight": {
"model": "antarchy:block/typhonite_brick_stairs"
},
"facing=east,half=top,shape=inner_left": {
"model": "antarchy:block/typhonite_brick_stairs_inner",
"uvlock": true,
"x": 180
},
"facing=east,half=top,shape=inner_right": {
"model": "antarchy:block/typhonite_brick_stairs_inner",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=east,half=top,shape=outer_left": {
"model": "antarchy:block/typhonite_brick_stairs_outer",
"uvlock": true,
"x": 180
},
"facing=east,half=top,shape=outer_right": {
"model": "antarchy:block/typhonite_brick_stairs_outer",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=east,half=top,shape=straight": {
"model": "antarchy:block/typhonite_brick_stairs",
"uvlock": true,
"x": 180
},
"facing=north,half=bottom,shape=inner_left": {
"model": "antarchy:block/typhonite_brick_stairs_inner",
"uvlock": true,
"y": 180
},
"facing=north,half=bottom,shape=inner_right": {
"model": "antarchy:block/typhonite_brick_stairs_inner",
"uvlock": true,
"y": 270
},
"facing=north,half=bottom,shape=outer_left": {
"model": "antarchy:block/typhonite_brick_stairs_outer",
"uvlock": true,
"y": 180
},
"facing=north,half=bottom,shape=outer_right": {
"model": "antarchy:block/typhonite_brick_stairs_outer",
"uvlock": true,
"y": 270
},
"facing=north,half=bottom,shape=straight": {
"model": "antarchy:block/typhonite_brick_stairs",
"uvlock": true,
"y": 270
},
"facing=north,half=top,shape=inner_left": {
"model": "antarchy:block/typhonite_brick_stairs_inner",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=north,half=top,shape=inner_right": {
"model": "antarchy:block/typhonite_brick_stairs_inner",
"uvlock": true,
"x": 180
},
"facing=north,half=top,shape=outer_left": {
"model": "antarchy:block/typhonite_brick_stairs_outer",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=north,half=top,shape=outer_right": {
"model": "antarchy:block/typhonite_brick_stairs_outer",
"uvlock": true,
"x": 180
},
"facing=north,half=top,shape=straight": {
"model": "antarchy:block/typhonite_brick_stairs",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=south,half=bottom,shape=inner_left": {
"model": "antarchy:block/typhonite_brick_stairs_inner"
},
"facing=south,half=bottom,shape=inner_right": {
"model": "antarchy:block/typhonite_brick_stairs_inner",
"uvlock": true,
"y": 90
},
"facing=south,half=bottom,shape=outer_left": {
"model": "antarchy:block/typhonite_brick_stairs_outer"
},
"facing=south,half=bottom,shape=outer_right": {
"model": "antarchy:block/typhonite_brick_stairs_outer",
"uvlock": true,
"y": 90
},
"facing=south,half=bottom,shape=straight": {
"model": "antarchy:block/typhonite_brick_stairs",
"uvlock": true,
"y": 90
},
"facing=south,half=top,shape=inner_left": {
"model": "antarchy:block/typhonite_brick_stairs_inner",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=south,half=top,shape=inner_right": {
"model": "antarchy:block/typhonite_brick_stairs_inner",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=south,half=top,shape=outer_left": {
"model": "antarchy:block/typhonite_brick_stairs_outer",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=south,half=top,shape=outer_right": {
"model": "antarchy:block/typhonite_brick_stairs_outer",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=south,half=top,shape=straight": {
"model": "antarchy:block/typhonite_brick_stairs",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=west,half=bottom,shape=inner_left": {
"model": "antarchy:block/typhonite_brick_stairs_inner",
"uvlock": true,
"y": 90
},
"facing=west,half=bottom,shape=inner_right": {
"model": "antarchy:block/typhonite_brick_stairs_inner",
"uvlock": true,
"y": 180
},
"facing=west,half=bottom,shape=outer_left": {
"model": "antarchy:block/typhonite_brick_stairs_outer",
"uvlock": true,
"y": 90
},
"facing=west,half=bottom,shape=outer_right": {
"model": "antarchy:block/typhonite_brick_stairs_outer",
"uvlock": true,
"y": 180
},
"facing=west,half=bottom,shape=straight": {
"model": "antarchy:block/typhonite_brick_stairs",
"uvlock": true,
"y": 180
},
"facing=west,half=top,shape=inner_left": {
"model": "antarchy:block/typhonite_brick_stairs_inner",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=west,half=top,shape=inner_right": {
"model": "antarchy:block/typhonite_brick_stairs_inner",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=west,half=top,shape=outer_left": {
"model": "antarchy:block/typhonite_brick_stairs_outer",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=west,half=top,shape=outer_right": {
"model": "antarchy:block/typhonite_brick_stairs_outer",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=west,half=top,shape=straight": {
"model": "antarchy:block/typhonite_brick_stairs",
"uvlock": true,
"x": 180,
"y": 180
}
}
}
@@ -0,0 +1,40 @@
{
"multipart": [
{
"when": { "up": "true" },
"apply": { "model": "antarchy:block/typhonite_brick_wall_post" }
},
{
"when": { "north": "low" },
"apply": { "model": "antarchy:block/typhonite_brick_wall_side", "uvlock": true }
},
{
"when": { "east": "low" },
"apply": { "model": "antarchy:block/typhonite_brick_wall_side", "y": 90, "uvlock": true }
},
{
"when": { "south": "low" },
"apply": { "model": "antarchy:block/typhonite_brick_wall_side", "y": 180, "uvlock": true }
},
{
"when": { "west": "low" },
"apply": { "model": "antarchy:block/typhonite_brick_wall_side", "y": 270, "uvlock": true }
},
{
"when": { "north": "tall" },
"apply": { "model": "antarchy:block/typhonite_brick_wall_side_tall", "uvlock": true }
},
{
"when": { "east": "tall" },
"apply": { "model": "antarchy:block/typhonite_brick_wall_side_tall", "y": 90, "uvlock": true }
},
{
"when": { "south": "tall" },
"apply": { "model": "antarchy:block/typhonite_brick_wall_side_tall", "y": 180, "uvlock": true }
},
{
"when": { "west": "tall" },
"apply": { "model": "antarchy:block/typhonite_brick_wall_side_tall", "y": 270, "uvlock": true }
}
]
}
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "antarchy:block/typhonite_bricks"
}
}
}
@@ -0,0 +1,13 @@
{
"variants": {
"type=double": {
"model": "antarchy:block/typhonite"
},
"type=bottom": {
"model": "antarchy:block/typhonite_slab"
},
"type=top": {
"model": "antarchy:block/typhonite_slab_top"
}
}
}
@@ -0,0 +1,34 @@
{
"variants": {
"thickness=base,vertical_direction=down": {
"model": "antarchy:block/typhonite_spike_down_base"
},
"thickness=base,vertical_direction=up": {
"model": "antarchy:block/typhonite_spike_up_base"
},
"thickness=frustum,vertical_direction=down": {
"model": "antarchy:block/typhonite_spike_down_frustum"
},
"thickness=frustum,vertical_direction=up": {
"model": "antarchy:block/typhonite_spike_up_frustum"
},
"thickness=middle,vertical_direction=down": {
"model": "antarchy:block/typhonite_spike_down_middle"
},
"thickness=middle,vertical_direction=up": {
"model": "antarchy:block/typhonite_spike_up_middle"
},
"thickness=tip,vertical_direction=down": {
"model": "antarchy:block/typhonite_spike_down_tip"
},
"thickness=tip,vertical_direction=up": {
"model": "antarchy:block/typhonite_spike_up_tip"
},
"thickness=tip_merge,vertical_direction=down": {
"model": "antarchy:block/typhonite_spike_down_tip_merge"
},
"thickness=tip_merge,vertical_direction=up": {
"model": "antarchy:block/typhonite_spike_up_tip_merge"
}
}
}
@@ -0,0 +1,209 @@
{
"variants": {
"facing=east,half=bottom,shape=inner_left": {
"model": "antarchy:block/typhonite_stairs_inner",
"uvlock": true,
"y": 270
},
"facing=east,half=bottom,shape=inner_right": {
"model": "antarchy:block/typhonite_stairs_inner"
},
"facing=east,half=bottom,shape=outer_left": {
"model": "antarchy:block/typhonite_stairs_outer",
"uvlock": true,
"y": 270
},
"facing=east,half=bottom,shape=outer_right": {
"model": "antarchy:block/typhonite_stairs_outer"
},
"facing=east,half=bottom,shape=straight": {
"model": "antarchy:block/typhonite_stairs"
},
"facing=east,half=top,shape=inner_left": {
"model": "antarchy:block/typhonite_stairs_inner",
"uvlock": true,
"x": 180
},
"facing=east,half=top,shape=inner_right": {
"model": "antarchy:block/typhonite_stairs_inner",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=east,half=top,shape=outer_left": {
"model": "antarchy:block/typhonite_stairs_outer",
"uvlock": true,
"x": 180
},
"facing=east,half=top,shape=outer_right": {
"model": "antarchy:block/typhonite_stairs_outer",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=east,half=top,shape=straight": {
"model": "antarchy:block/typhonite_stairs",
"uvlock": true,
"x": 180
},
"facing=north,half=bottom,shape=inner_left": {
"model": "antarchy:block/typhonite_stairs_inner",
"uvlock": true,
"y": 180
},
"facing=north,half=bottom,shape=inner_right": {
"model": "antarchy:block/typhonite_stairs_inner",
"uvlock": true,
"y": 270
},
"facing=north,half=bottom,shape=outer_left": {
"model": "antarchy:block/typhonite_stairs_outer",
"uvlock": true,
"y": 180
},
"facing=north,half=bottom,shape=outer_right": {
"model": "antarchy:block/typhonite_stairs_outer",
"uvlock": true,
"y": 270
},
"facing=north,half=bottom,shape=straight": {
"model": "antarchy:block/typhonite_stairs",
"uvlock": true,
"y": 270
},
"facing=north,half=top,shape=inner_left": {
"model": "antarchy:block/typhonite_stairs_inner",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=north,half=top,shape=inner_right": {
"model": "antarchy:block/typhonite_stairs_inner",
"uvlock": true,
"x": 180
},
"facing=north,half=top,shape=outer_left": {
"model": "antarchy:block/typhonite_stairs_outer",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=north,half=top,shape=outer_right": {
"model": "antarchy:block/typhonite_stairs_outer",
"uvlock": true,
"x": 180
},
"facing=north,half=top,shape=straight": {
"model": "antarchy:block/typhonite_stairs",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=south,half=bottom,shape=inner_left": {
"model": "antarchy:block/typhonite_stairs_inner"
},
"facing=south,half=bottom,shape=inner_right": {
"model": "antarchy:block/typhonite_stairs_inner",
"uvlock": true,
"y": 90
},
"facing=south,half=bottom,shape=outer_left": {
"model": "antarchy:block/typhonite_stairs_outer"
},
"facing=south,half=bottom,shape=outer_right": {
"model": "antarchy:block/typhonite_stairs_outer",
"uvlock": true,
"y": 90
},
"facing=south,half=bottom,shape=straight": {
"model": "antarchy:block/typhonite_stairs",
"uvlock": true,
"y": 90
},
"facing=south,half=top,shape=inner_left": {
"model": "antarchy:block/typhonite_stairs_inner",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=south,half=top,shape=inner_right": {
"model": "antarchy:block/typhonite_stairs_inner",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=south,half=top,shape=outer_left": {
"model": "antarchy:block/typhonite_stairs_outer",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=south,half=top,shape=outer_right": {
"model": "antarchy:block/typhonite_stairs_outer",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=south,half=top,shape=straight": {
"model": "antarchy:block/typhonite_stairs",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=west,half=bottom,shape=inner_left": {
"model": "antarchy:block/typhonite_stairs_inner",
"uvlock": true,
"y": 90
},
"facing=west,half=bottom,shape=inner_right": {
"model": "antarchy:block/typhonite_stairs_inner",
"uvlock": true,
"y": 180
},
"facing=west,half=bottom,shape=outer_left": {
"model": "antarchy:block/typhonite_stairs_outer",
"uvlock": true,
"y": 90
},
"facing=west,half=bottom,shape=outer_right": {
"model": "antarchy:block/typhonite_stairs_outer",
"uvlock": true,
"y": 180
},
"facing=west,half=bottom,shape=straight": {
"model": "antarchy:block/typhonite_stairs",
"uvlock": true,
"y": 180
},
"facing=west,half=top,shape=inner_left": {
"model": "antarchy:block/typhonite_stairs_inner",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=west,half=top,shape=inner_right": {
"model": "antarchy:block/typhonite_stairs_inner",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=west,half=top,shape=outer_left": {
"model": "antarchy:block/typhonite_stairs_outer",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=west,half=top,shape=outer_right": {
"model": "antarchy:block/typhonite_stairs_outer",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=west,half=top,shape=straight": {
"model": "antarchy:block/typhonite_stairs",
"uvlock": true,
"x": 180,
"y": 180
}
}
}
@@ -0,0 +1,40 @@
{
"multipart": [
{
"when": { "up": "true" },
"apply": { "model": "antarchy:block/typhonite_wall_post" }
},
{
"when": { "north": "low" },
"apply": { "model": "antarchy:block/typhonite_wall_side", "uvlock": true }
},
{
"when": { "east": "low" },
"apply": { "model": "antarchy:block/typhonite_wall_side", "y": 90, "uvlock": true }
},
{
"when": { "south": "low" },
"apply": { "model": "antarchy:block/typhonite_wall_side", "y": 180, "uvlock": true }
},
{
"when": { "west": "low" },
"apply": { "model": "antarchy:block/typhonite_wall_side", "y": 270, "uvlock": true }
},
{
"when": { "north": "tall" },
"apply": { "model": "antarchy:block/typhonite_wall_side_tall", "uvlock": true }
},
{
"when": { "east": "tall" },
"apply": { "model": "antarchy:block/typhonite_wall_side_tall", "y": 90, "uvlock": true }
},
{
"when": { "south": "tall" },
"apply": { "model": "antarchy:block/typhonite_wall_side_tall", "y": 180, "uvlock": true }
},
{
"when": { "west": "tall" },
"apply": { "model": "antarchy:block/typhonite_wall_side_tall", "y": 270, "uvlock": true }
}
]
}
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "antarchy:block/veined_typhonite"
}
}
}
@@ -0,0 +1,16 @@
{
"variants": {
"facing=up,powered=false": { "model": "antarchy:block/vortex_lens" },
"facing=up,powered=true": { "model": "antarchy:block/vortex_lens_on" },
"facing=down,powered=false": { "model": "antarchy:block/vortex_lens", "x": 180 },
"facing=down,powered=true": { "model": "antarchy:block/vortex_lens_on", "x": 180 },
"facing=north,powered=false": { "model": "antarchy:block/vortex_lens", "x": 90 },
"facing=north,powered=true": { "model": "antarchy:block/vortex_lens_on", "x": 90 },
"facing=south,powered=false": { "model": "antarchy:block/vortex_lens", "x": 270 },
"facing=south,powered=true": { "model": "antarchy:block/vortex_lens_on", "x": 270 },
"facing=west,powered=false": { "model": "antarchy:block/vortex_lens", "x": 90, "y": 270 },
"facing=west,powered=true": { "model": "antarchy:block/vortex_lens_on", "x": 90, "y": 270 },
"facing=east,powered=false": { "model": "antarchy:block/vortex_lens", "x": 90, "y": 90 },
"facing=east,powered=true": { "model": "antarchy:block/vortex_lens_on", "x": 90, "y": 90 }
}
}
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "antarchy:block/whirlflower"
}
}
}
@@ -380,7 +380,7 @@
"tooltip.antarchy.scorpion_whip.snap": "Linksklicke erneut auf angebundene Beute, um den Stachel loszureißen.",
"item.antarchy.fallen_king_crown": "Krone des gefallenen Königs",
"tooltip.antarchy.fallen_king_crown.hero": "Das Töten feindlicher Kreaturen gewährt Held des Dorfes",
"item.antarchy.vortex_eye": "Wirbel-Auge",
"item.antarchy.vortex_charge": "Vortex Charge",
"item.antarchy.ultimate_helmet": "Ultimativer Helm",
"item.antarchy.ultimate_chestplate": "Ultimativer Brustpanzer",
"item.antarchy.ultimate_leggings": "Ultimativer Beinschutz",
@@ -715,6 +715,9 @@
"subtitles.antarchy.gravity_gun_hold_loop": "Gravitationskanone summt",
"subtitles.antarchy.gravity_gun_launch": "Gravitationskanone schleudert",
"subtitles.antarchy.gravity_gun_dryfire": "Gravitationskanone klickt leer",
"subtitles.antarchy.antimetal_place": "Antimetall klirrt",
"subtitles.antarchy.antimetal_step": "Antimetall klickt",
"subtitles.antarchy.antimetal_scaffold": "Antimetallgerüst rasselt",
"subtitles.antarchy.bed_bug_ambient": "Bettwanze zwitschert",
"subtitles.antarchy.bed_bug_hurt": "Bettwanze wird verletzt",
"subtitles.antarchy.bed_bug_attack": "Bettwanze beißt",
@@ -206,6 +206,24 @@
"block.antarchy.smooth_dream_sandstone_stairs": "Smooth Dream Sandstone Stairs",
"block.antarchy.smooth_dream_sandstone_slab": "Smooth Dream Sandstone Slab",
"block.antarchy.cut_dream_sandstone_slab": "Cut Dream Sandstone Slab",
"block.antarchy.typhonite": "Typhonite",
"block.antarchy.typhonite_bricks": "Typhonite Bricks",
"block.antarchy.chiseled_typhonite": "Chiseled Typhonite",
"block.antarchy.polished_typhonite": "Polished Typhonite",
"block.antarchy.veined_typhonite": "Veined Typhonite",
"block.antarchy.typhonite_spike": "Typhonite Spike",
"block.antarchy.typhonite_stairs": "Typhonite Stairs",
"block.antarchy.typhonite_slab": "Typhonite Slab",
"block.antarchy.typhonite_wall": "Typhonite Wall",
"block.antarchy.typhonite_brick_stairs": "Typhonite Brick Stairs",
"block.antarchy.typhonite_brick_slab": "Typhonite Brick Slab",
"block.antarchy.typhonite_brick_wall": "Typhonite Brick Wall",
"block.antarchy.polished_typhonite_stairs": "Polished Typhonite Stairs",
"block.antarchy.polished_typhonite_slab": "Polished Typhonite Slab",
"block.antarchy.polished_typhonite_wall": "Polished Typhonite Wall",
"block.antarchy.spiraling_vines": "Spiraling Vines",
"block.antarchy.spiraling_vines_plant": "Spiraling Vines Plant",
"block.antarchy.whirlflower": "Whirlflower",
"block.antarchy.bed_bug_egg": "Bed Bug Egg",
"block.antarchy.wasp_nest": "Wasp Nest",
"block.antarchy.red_ant_nest": "Red Ant Nest",
@@ -217,6 +235,7 @@
"block.antarchy.deepslate_titanium_ore": "Deepslate Titanium Ore",
"block.antarchy.bluestone_ore": "Bluestone Ore",
"block.antarchy.bluestone_block": "Bluestone Block",
"block.antarchy.vortex_lens": "Vortex Lens",
"block.antarchy.bluestone_repeater": "Bluestone Repeater",
"block.antarchy.bluestone_comparator": "Bluestone Comparator",
"block.antarchy.bluestone_torch": "Bluestone Torch",
@@ -337,6 +356,23 @@
"item.antarchy.smooth_dream_sandstone_stairs": "Smooth Dream Sandstone Stairs",
"item.antarchy.smooth_dream_sandstone_slab": "Smooth Dream Sandstone Slab",
"item.antarchy.cut_dream_sandstone_slab": "Cut Dream Sandstone Slab",
"item.antarchy.typhonite": "Typhonite",
"item.antarchy.typhonite_bricks": "Typhonite Bricks",
"item.antarchy.chiseled_typhonite": "Chiseled Typhonite",
"item.antarchy.polished_typhonite": "Polished Typhonite",
"item.antarchy.veined_typhonite": "Veined Typhonite",
"item.antarchy.typhonite_spike": "Typhonite Spike",
"item.antarchy.typhonite_stairs": "Typhonite Stairs",
"item.antarchy.typhonite_slab": "Typhonite Slab",
"item.antarchy.typhonite_wall": "Typhonite Wall",
"item.antarchy.typhonite_brick_stairs": "Typhonite Brick Stairs",
"item.antarchy.typhonite_brick_slab": "Typhonite Brick Slab",
"item.antarchy.typhonite_brick_wall": "Typhonite Brick Wall",
"item.antarchy.polished_typhonite_stairs": "Polished Typhonite Stairs",
"item.antarchy.polished_typhonite_slab": "Polished Typhonite Slab",
"item.antarchy.polished_typhonite_wall": "Polished Typhonite Wall",
"item.antarchy.spiraling_vines": "Spiraling Vines",
"item.antarchy.whirlflower": "Whirlflower",
"item.antarchy.dream_torch": "Dream Torch",
"item.antarchy.dream_lantern": "Dream Lantern",
"item.antarchy.dream_campfire": "Dream Campfire",
@@ -488,6 +524,7 @@
"item.antarchy.blood_crystal_boots.tooltip2": "Cancels fall damage when falling upward while gravity is inverted.",
"item.antarchy.blood_crystal_apple.tooltip": "Grants Bloodglass Ward, providing temporary Bloodglass Hearts that recharge while the effect lasts.",
"tooltip.antarchy.blood_crystal_katana.launch": "Launches you forward on hit.",
"tooltip.antarchy.blood_crystal_katana.dash": "Reaches distant targets you look at; a full swing grants brief immunity.",
"tooltip.antarchy.blood_crystal_katana.trail": "Leaves a crimson trail behind you.",
"item.antarchy.mantis_claw": "Mantis Claw",
"tooltip.antarchy.mantis_claw.wall_cling": "Dual wield to cling to walls and jump upward.",
@@ -526,7 +563,10 @@
"tooltip.antarchy.scorpion_whip.snap": "Attack with tethered prey to snap the stinger free.",
"item.antarchy.fallen_king_crown": "Fallen King\u0027s Crown",
"tooltip.antarchy.fallen_king_crown.hero": "Grants Hero of the Village when you slay hostile mobs",
"item.antarchy.vortex_eye": "Vortex Eye",
"item.antarchy.vortex_charge": "Vortex Charge",
"entity.antarchy.vortex": "Vortex",
"entity.antarchy.wind_vortex": "Wind Vortex",
"item.antarchy.vortex_spawn_egg": "Vortex Spawn Egg",
"item.antarchy.ultimate_helmet": "Ultimate Helmet",
"item.antarchy.ultimate_chestplate": "Ultimate Chestplate",
"item.antarchy.ultimate_leggings": "Ultimate Leggings",
@@ -881,6 +921,9 @@
"subtitles.antarchy.gravity_gun_hold_loop": "Gravity Gun hums",
"subtitles.antarchy.gravity_gun_launch": "Gravity Gun launches",
"subtitles.antarchy.gravity_gun_dryfire": "Gravity Gun dry fires",
"subtitles.antarchy.antimetal_place": "Antimetal clangs",
"subtitles.antarchy.antimetal_step": "Antimetal clinks",
"subtitles.antarchy.antimetal_scaffold": "Antimetal scaffolding rattles",
"subtitles.antarchy.portal_gun_fire_blue": "Portal Gun fires",
"subtitles.antarchy.portal_gun_fire_orange": "Portal Gun fires",
"subtitles.antarchy.portal_gun_invalid_surface": "Portal fizzles",
@@ -910,6 +953,11 @@
"subtitles.antarchy.molevore_attack": "Molevore attacks",
"subtitles.antarchy.molevore_dig": "Molevore digs",
"subtitles.antarchy.duct_tape_use": "Duct Tape tears",
"subtitles.antarchy.worm_hook_flying": "Worm Hook whooshes",
"subtitles.antarchy.blood_crystal_katana_dash": "Blood Crystal Katana dashes",
"subtitles.antarchy.blood_crystal_armor_equip": "Blood Crystal Armor equips",
"subtitles.antarchy.bloodglass_ward_heart_break": "Bloodglass heart shatters",
"subtitles.antarchy.bloodglass_ward_heart_regen": "Bloodglass heart reforms",
"subtitles.antarchy.potent_nyxite_hypnotic_gas": "Potent Nyxite hisses",
"subtitles.antarchy.potent_nyxite_geyser_eruption": "Potent Nyxite erupts",
"subtitles.antarchy.potent_nyxite_geyser_continuous": "Potent Nyxite geyser roars",
@@ -1019,6 +1067,7 @@
"biome.antarchy.umbral_hills": "Umbral Hills",
"biome.antarchy.lucid_pools": "Lucid Pools",
"biome.antarchy.dream_dunes": "Dream Dunes",
"biome.antarchy.vortex_expanse": "Vortex Expanse",
"biome.antarchy.cloud_sea": "Cloud Sea",
"block.antarchy.wild_corn": "Wild Corn",
"trim_material.antarchy.blood_crystal": "Blood Crystal",
@@ -1148,6 +1197,10 @@
"advancements.antarchy.bug_apetit.description": "Eat Cooked Bug Meat.",
"advancements.antarchy.behavioral_correction.title": "Behavioral Correction",
"advancements.antarchy.behavioral_correction.description": "Obtain an Attitude Adjuster.",
"advancements.antarchy.let_it_die.title": "Let It Die!",
"advancements.antarchy.let_it_die.description": "Obtain any Truffalo Tuft.",
"advancements.antarchy.let_it_grow.title": "Let It Grow!",
"advancements.antarchy.let_it_grow.description": "Grow a Truffalo Sapling.",
"advancements.antarchy.beetle_buddies.title": "Beetle Buddies",
"advancements.antarchy.beetle_buddies.description": "Tame a Hercules Beetle.",
"advancements.antarchy.herculean_task.title": "Herculean Task",
@@ -380,7 +380,7 @@
"tooltip.antarchy.scorpion_whip.snap": "Vuelve a hacer clic izquierdo sobre la presa atada para arrancar el aguijón.",
"item.antarchy.fallen_king_crown": "Corona del Rey Caído",
"tooltip.antarchy.fallen_king_crown.hero": "Otorga Héroe de la aldea al matar criaturas hostiles",
"item.antarchy.vortex_eye": "Ojo de Vórtice",
"item.antarchy.vortex_charge": "Vortex Charge",
"item.antarchy.ultimate_helmet": "Casco definitivo",
"item.antarchy.ultimate_chestplate": "Peto definitivo",
"item.antarchy.ultimate_leggings": "Grebas definitivas",
@@ -715,6 +715,9 @@
"subtitles.antarchy.gravity_gun_hold_loop": "Pistola gravitatoria zumba",
"subtitles.antarchy.gravity_gun_launch": "Pistola gravitatoria lanza",
"subtitles.antarchy.gravity_gun_dryfire": "Pistola gravitatoria dispara en seco",
"subtitles.antarchy.antimetal_place": "El antimetal repica",
"subtitles.antarchy.antimetal_step": "El antimetal tintinea",
"subtitles.antarchy.antimetal_scaffold": "El andamio de antimetal traquetea",
"subtitles.antarchy.bed_bug_ambient": "Chinche de cama gorjea",
"subtitles.antarchy.bed_bug_hurt": "Chinche de cama recibe daño",
"subtitles.antarchy.bed_bug_attack": "Chinche de cama muerde",
@@ -380,7 +380,7 @@
"tooltip.antarchy.scorpion_whip.snap": "Frappez à nouveau la proie liée pour arracher le dard.",
"item.antarchy.fallen_king_crown": "Couronne du Roi déchu",
"tooltip.antarchy.fallen_king_crown.hero": "Accorde Héros du village lorsque vous tuez des créatures hostiles",
"item.antarchy.vortex_eye": "Œil de Vortex",
"item.antarchy.vortex_charge": "Vortex Charge",
"item.antarchy.ultimate_helmet": "Casque ultime",
"item.antarchy.ultimate_chestplate": "Plastron ultime",
"item.antarchy.ultimate_leggings": "Jambières ultimes",
@@ -715,6 +715,9 @@
"subtitles.antarchy.gravity_gun_hold_loop": "Canon à gravité bourdonne",
"subtitles.antarchy.gravity_gun_launch": "Canon à gravité projette",
"subtitles.antarchy.gravity_gun_dryfire": "Canon à gravité tire à vide",
"subtitles.antarchy.antimetal_place": "L'antimétal résonne",
"subtitles.antarchy.antimetal_step": "L'antimétal cliquette",
"subtitles.antarchy.antimetal_scaffold": "L'échafaudage d'antimétal cliquette",
"subtitles.antarchy.bed_bug_ambient": "Punaise de lit pépie",
"subtitles.antarchy.bed_bug_hurt": "Punaise de lit est blessé",
"subtitles.antarchy.bed_bug_attack": "Punaise de lit mord",
@@ -380,7 +380,7 @@
"tooltip.antarchy.scorpion_whip.snap": "Colpisci di nuovo la preda legata per strappare via il pungiglione.",
"item.antarchy.fallen_king_crown": "Corona del Re Caduto",
"tooltip.antarchy.fallen_king_crown.hero": "Conferisce Eroe del villaggio quando uccidi creature ostili",
"item.antarchy.vortex_eye": "Occhio di Vortice",
"item.antarchy.vortex_charge": "Vortex Charge",
"item.antarchy.ultimate_helmet": "Elmo di Supremo",
"item.antarchy.ultimate_chestplate": "Corazza di Supremo",
"item.antarchy.ultimate_leggings": "Gambali di Supremo",
@@ -715,6 +715,9 @@
"subtitles.antarchy.gravity_gun_hold_loop": "Il cannone gravitazionale ronza",
"subtitles.antarchy.gravity_gun_launch": "Il cannone gravitazionale lancia",
"subtitles.antarchy.gravity_gun_dryfire": "Il cannone gravitazionale scatta a vuoto",
"subtitles.antarchy.antimetal_place": "L'antimetallo rimbomba",
"subtitles.antarchy.antimetal_step": "L'antimetallo tintinna",
"subtitles.antarchy.antimetal_scaffold": "L'impalcatura di antimetallo sferraglia",
"subtitles.antarchy.bed_bug_ambient": "La cimice dei letti cinguetta",
"subtitles.antarchy.bed_bug_hurt": "La cimice dei letti si ferisce",
"subtitles.antarchy.bed_bug_attack": "La cimice dei letti morde",
@@ -380,7 +380,7 @@
"tooltip.antarchy.scorpion_whip.snap": "つながれた獲物をもう一度左クリックすると針を引き抜きます。",
"item.antarchy.fallen_king_crown": "亡き王の王冠",
"tooltip.antarchy.fallen_king_crown.hero": "敵対モブを倒すと村の英雄を付与します",
"item.antarchy.vortex_eye": "渦の目",
"item.antarchy.vortex_charge": "Vortex Charge",
"item.antarchy.ultimate_helmet": "究極のヘルメット",
"item.antarchy.ultimate_chestplate": "究極のチェストプレート",
"item.antarchy.ultimate_leggings": "究極のレギンス",
@@ -715,6 +715,9 @@
"subtitles.antarchy.gravity_gun_hold_loop": "重力銃が低く唸る",
"subtitles.antarchy.gravity_gun_launch": "重力銃が発射する",
"subtitles.antarchy.gravity_gun_dryfire": "重力銃が空撃ちする",
"subtitles.antarchy.antimetal_place": "アンチメタルが鳴る",
"subtitles.antarchy.antimetal_step": "アンチメタルがカチカチ鳴る",
"subtitles.antarchy.antimetal_scaffold": "アンチメタル足場ががたつく",
"subtitles.antarchy.bed_bug_ambient": "トコジラミがさえずる",
"subtitles.antarchy.bed_bug_hurt": "トコジラミが傷つく",
"subtitles.antarchy.bed_bug_attack": "トコジラミが噛む",
@@ -380,7 +380,7 @@
"tooltip.antarchy.scorpion_whip.snap": "연결된 먹잇감을 다시 좌클릭하여 독침을 뽑습니다.",
"item.antarchy.fallen_king_crown": "몰락한 왕의 왕관",
"tooltip.antarchy.fallen_king_crown.hero": "적대적 생물을 처치하면 마을의 영웅을 부여합니다",
"item.antarchy.vortex_eye": "소용돌이 눈",
"item.antarchy.vortex_charge": "Vortex Charge",
"item.antarchy.ultimate_helmet": "궁극 투구",
"item.antarchy.ultimate_chestplate": "궁극 흉갑",
"item.antarchy.ultimate_leggings": "궁극 레깅스",
@@ -715,6 +715,9 @@
"subtitles.antarchy.gravity_gun_hold_loop": "중력총 웅웅거립니다",
"subtitles.antarchy.gravity_gun_launch": "중력총 발사합니다",
"subtitles.antarchy.gravity_gun_dryfire": "중력총 헛발사됩니다",
"subtitles.antarchy.antimetal_place": "안티메탈이 쨍그랑거립니다",
"subtitles.antarchy.antimetal_step": "안티메탈이 딸깍거립니다",
"subtitles.antarchy.antimetal_scaffold": "안티메탈 비계가 덜컹거립니다",
"subtitles.antarchy.bed_bug_ambient": "빈대 짹짹거립니다",
"subtitles.antarchy.bed_bug_hurt": "빈대 다칩니다",
"subtitles.antarchy.bed_bug_attack": "빈대 뭅니다",
@@ -380,7 +380,7 @@
"tooltip.antarchy.scorpion_whip.snap": "Clique com o botão esquerdo novamente na presa presa para arrancar o ferrão.",
"item.antarchy.fallen_king_crown": "Coroa do Rei Caído",
"tooltip.antarchy.fallen_king_crown.hero": "Concede Herói da Vila ao matar criaturas hostis",
"item.antarchy.vortex_eye": "Olho de Vórtice",
"item.antarchy.vortex_charge": "Vortex Charge",
"item.antarchy.ultimate_helmet": "Capacete Supremo",
"item.antarchy.ultimate_chestplate": "Peitoral Supremo",
"item.antarchy.ultimate_leggings": "Calças Supremas",
@@ -715,6 +715,9 @@
"subtitles.antarchy.gravity_gun_hold_loop": "Arma Gravitacional zune",
"subtitles.antarchy.gravity_gun_launch": "Arma Gravitacional lança",
"subtitles.antarchy.gravity_gun_dryfire": "Arma Gravitacional dispara em seco",
"subtitles.antarchy.antimetal_place": "Antimetal retine",
"subtitles.antarchy.antimetal_step": "Antimetal tilinta",
"subtitles.antarchy.antimetal_scaffold": "Andaime de antimetal chacoalha",
"subtitles.antarchy.bed_bug_ambient": "Percevejo-de-cama chilreia",
"subtitles.antarchy.bed_bug_hurt": "Percevejo-de-cama se machuca",
"subtitles.antarchy.bed_bug_attack": "Percevejo-de-cama morde",
@@ -357,7 +357,7 @@
"tooltip.antarchy.scorpion_whip.snap": "Нажмите ЛКМ по привязанной добыче, чтобы вырвать жало.",
"item.antarchy.fallen_king_crown": "Корона павшего короля",
"tooltip.antarchy.fallen_king_crown.hero": "Даёт эффект «Герой деревни» при убийстве враждебных мобов",
"item.antarchy.vortex_eye": "Око вихря",
"item.antarchy.vortex_charge": "Vortex Charge",
"item.antarchy.ultimate_helmet": "Ультимативный шлем",
"item.antarchy.ultimate_chestplate": "Ультимативный нагрудник",
"item.antarchy.ultimate_leggings": "Ультимативные поножи",
@@ -684,6 +684,9 @@
"subtitles.antarchy.gravity_gun_hold_loop": "Пушка гудит",
"subtitles.antarchy.gravity_gun_launch": "Пушка стреляет",
"subtitles.antarchy.gravity_gun_dryfire": "Осечка пушки",
"subtitles.antarchy.antimetal_place": "Антиметалл звенит",
"subtitles.antarchy.antimetal_step": "Антиметалл щёлкает",
"subtitles.antarchy.antimetal_scaffold": "Антиметаллические леса гремят",
"subtitles.antarchy.bed_bug_ambient": "Постельный клоп стрекочет",
"subtitles.antarchy.bed_bug_hurt": "Постельному клопу больно",
"subtitles.antarchy.bed_bug_attack": "Постельный клоп кусает",
@@ -380,7 +380,7 @@
"tooltip.antarchy.scorpion_whip.snap": "再次左键被牵住的猎物可扯出毒刺。",
"item.antarchy.fallen_king_crown": "陨落之王的王冠",
"tooltip.antarchy.fallen_king_crown.hero": "击杀敌对生物时获得村庄英雄",
"item.antarchy.vortex_eye": "漩涡之眼",
"item.antarchy.vortex_charge": "Vortex Charge",
"item.antarchy.ultimate_helmet": "终极头盔",
"item.antarchy.ultimate_chestplate": "终极胸甲",
"item.antarchy.ultimate_leggings": "终极护腿",
@@ -715,6 +715,9 @@
"subtitles.antarchy.gravity_gun_hold_loop": "重力枪嗡鸣",
"subtitles.antarchy.gravity_gun_launch": "重力枪发射",
"subtitles.antarchy.gravity_gun_dryfire": "重力枪空击",
"subtitles.antarchy.antimetal_place": "反金属发出撞击声",
"subtitles.antarchy.antimetal_step": "反金属发出叮当声",
"subtitles.antarchy.antimetal_scaffold": "反金属脚手架咯吱作响",
"subtitles.antarchy.bed_bug_ambient": "臭虫唧唧叫",
"subtitles.antarchy.bed_bug_hurt": "臭虫受伤",
"subtitles.antarchy.bed_bug_attack": "臭虫啃咬",
@@ -380,7 +380,7 @@
"tooltip.antarchy.scorpion_whip.snap": "再次左鍵被牽住的獵物可扯出毒刺。",
"item.antarchy.fallen_king_crown": "隕落之王的王冠",
"tooltip.antarchy.fallen_king_crown.hero": "擊殺敵對生物時獲得村莊英雄",
"item.antarchy.vortex_eye": "漩渦之眼",
"item.antarchy.vortex_charge": "Vortex Charge",
"item.antarchy.ultimate_helmet": "終極頭盔",
"item.antarchy.ultimate_chestplate": "終極胸甲",
"item.antarchy.ultimate_leggings": "終極護腿",
@@ -715,6 +715,9 @@
"subtitles.antarchy.gravity_gun_hold_loop": "重力槍嗡鳴",
"subtitles.antarchy.gravity_gun_launch": "重力槍發射",
"subtitles.antarchy.gravity_gun_dryfire": "重力槍空擊",
"subtitles.antarchy.antimetal_place": "反金屬發出撞擊聲",
"subtitles.antarchy.antimetal_step": "反金屬發出叮噹聲",
"subtitles.antarchy.antimetal_scaffold": "反金屬鷹架嘎吱作響",
"subtitles.antarchy.bed_bug_ambient": "臭蟲唧唧叫",
"subtitles.antarchy.bed_bug_hurt": "臭蟲受傷",
"subtitles.antarchy.bed_bug_attack": "臭蟲啃咬",
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "antarchy:block/typhonite/chiseled_typhonite"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "antarchy:block/typhonite/polished_typhonite"
}
}
@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/slab",
"textures": {
"bottom": "antarchy:block/typhonite/polished_typhonite",
"side": "antarchy:block/typhonite/polished_typhonite",
"top": "antarchy:block/typhonite/polished_typhonite"
}
}
@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/slab_top",
"textures": {
"bottom": "antarchy:block/typhonite/polished_typhonite",
"side": "antarchy:block/typhonite/polished_typhonite",
"top": "antarchy:block/typhonite/polished_typhonite"
}
}
@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/stairs",
"textures": {
"bottom": "antarchy:block/typhonite/polished_typhonite",
"side": "antarchy:block/typhonite/polished_typhonite",
"top": "antarchy:block/typhonite/polished_typhonite"
}
}
@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/inner_stairs",
"textures": {
"bottom": "antarchy:block/typhonite/polished_typhonite",
"side": "antarchy:block/typhonite/polished_typhonite",
"top": "antarchy:block/typhonite/polished_typhonite"
}
}
@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/outer_stairs",
"textures": {
"bottom": "antarchy:block/typhonite/polished_typhonite",
"side": "antarchy:block/typhonite/polished_typhonite",
"top": "antarchy:block/typhonite/polished_typhonite"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/wall_inventory",
"textures": {
"wall": "antarchy:block/typhonite/polished_typhonite"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/template_wall_post",
"textures": {
"wall": "antarchy:block/typhonite/polished_typhonite"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/template_wall_side",
"textures": {
"wall": "antarchy:block/typhonite/polished_typhonite"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/template_wall_side_tall",
"textures": {
"wall": "antarchy:block/typhonite/polished_typhonite"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cross",
"textures": {
"cross": "antarchy:block/spiraling_vines/spiraling_vines_top"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cross",
"textures": {
"cross": "antarchy:block/spiraling_vines/spiraling_vines"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "antarchy:block/typhonite/typhonite"
}
}
@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/slab",
"textures": {
"bottom": "antarchy:block/typhonite/typhonite_bricks",
"side": "antarchy:block/typhonite/typhonite_bricks",
"top": "antarchy:block/typhonite/typhonite_bricks"
}
}
@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/slab_top",
"textures": {
"bottom": "antarchy:block/typhonite/typhonite_bricks",
"side": "antarchy:block/typhonite/typhonite_bricks",
"top": "antarchy:block/typhonite/typhonite_bricks"
}
}
@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/stairs",
"textures": {
"bottom": "antarchy:block/typhonite/typhonite_bricks",
"side": "antarchy:block/typhonite/typhonite_bricks",
"top": "antarchy:block/typhonite/typhonite_bricks"
}
}
@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/inner_stairs",
"textures": {
"bottom": "antarchy:block/typhonite/typhonite_bricks",
"side": "antarchy:block/typhonite/typhonite_bricks",
"top": "antarchy:block/typhonite/typhonite_bricks"
}
}
@@ -0,0 +1,8 @@
{
"parent": "minecraft:block/outer_stairs",
"textures": {
"bottom": "antarchy:block/typhonite/typhonite_bricks",
"side": "antarchy:block/typhonite/typhonite_bricks",
"top": "antarchy:block/typhonite/typhonite_bricks"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/wall_inventory",
"textures": {
"wall": "antarchy:block/typhonite/typhonite_bricks"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/template_wall_post",
"textures": {
"wall": "antarchy:block/typhonite/typhonite_bricks"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/template_wall_side",
"textures": {
"wall": "antarchy:block/typhonite/typhonite_bricks"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/template_wall_side_tall",
"textures": {
"wall": "antarchy:block/typhonite/typhonite_bricks"
}
}
Loaded 100 of 350 files, more files were not shown because too many files have changed in this diff. Show more