diff --git a/common-1.20.1/src/main/java/com/craisinlord/antarchy/content/block/entity/AntNestBlockEntity.java b/common-1.20.1/src/main/java/com/craisinlord/antarchy/content/block/entity/AntNestBlockEntity.java index 43141acc..1b720e17 100644 --- a/common-1.20.1/src/main/java/com/craisinlord/antarchy/content/block/entity/AntNestBlockEntity.java +++ b/common-1.20.1/src/main/java/com/craisinlord/antarchy/content/block/entity/AntNestBlockEntity.java @@ -20,16 +20,20 @@ import net.minecraft.world.level.block.state.BlockState; public class AntNestBlockEntity extends BlockEntity { private static final String STORED_ANTS = "StoredAnts"; private static final String NBT_INITIALIZED = "Initialized"; + private static final String NBT_REBROOD_COOLDOWN = "RebroodCooldown"; private static final int RELEASE_COOLDOWN_MIN = 80; private static final int RELEASE_COOLDOWN_RANGE = 100; private static final int ENTER_NEST_COOLDOWN = 200; private static final int INITIAL_ANT_COUNT_MIN = 2; private static final int INITIAL_ANT_COUNT_RANGE = 4; + private static final int REBROOD_COOLDOWN_TICKS = 20 * 60 * 5; + private static final double PLAYER_ACTIVATION_RANGE = 16.0D; private static final double SPAWN_OFFSET_XZ = 0.5D; private static final double SPAWN_OFFSET_Y = 0.05D; private final List storedAnts = new ArrayList<>(); private int releaseCooldown = RELEASE_COOLDOWN_MIN; + private int rebroodCooldown = REBROOD_COOLDOWN_TICKS; private boolean initialized = false; public AntNestBlockEntity(BlockPos pos, BlockState blockState) { @@ -37,8 +41,19 @@ public class AntNestBlockEntity extends BlockEntity { } public static void serverTick(ServerLevel level, BlockPos pos, BlockState state, AntNestBlockEntity nest) { + boolean playerNearby = level.hasNearbyAlivePlayer( + pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, PLAYER_ACTIVATION_RANGE); + if (!playerNearby) { + return; + } + if (!nest.initialized) { nest.populateInitialAnts(level); + } else if (nest.storedAnts.isEmpty() && nest.nestBlock().shouldPopulateInitialAnts()) { + if (--nest.rebroodCooldown <= 0) { + nest.rebroodCooldown = REBROOD_COOLDOWN_TICKS; + nest.fillWithAnts(level); + } } boolean ignoreNight = level.dimensionType().hasFixedTime(); @@ -68,11 +83,16 @@ public class AntNestBlockEntity extends BlockEntity { return; } + this.fillWithAnts(level); + } + + private void fillWithAnts(ServerLevel level) { int amount = INITIAL_ANT_COUNT_MIN + level.random.nextInt(INITIAL_ANT_COUNT_RANGE); for (int i = 0; i < amount && this.storedAnts.size() < this.maxOccupants(); i++) { EntityType antType = this.nestBlock().initialAntType(level.random); this.storedAnts.add(this.createStoredAnt(level, antType)); } + this.rebroodCooldown = REBROOD_COOLDOWN_TICKS; this.setChanged(); } @@ -153,6 +173,7 @@ public class AntNestBlockEntity extends BlockEntity { protected void saveAdditional(CompoundTag tag) { super.saveAdditional(tag); tag.putBoolean(NBT_INITIALIZED, this.initialized); + tag.putInt(NBT_REBROOD_COOLDOWN, this.rebroodCooldown); ListTag listTag = new ListTag(); for (StoredAnt storedAnt : this.storedAnts) { listTag.add(storedAnt.save()); @@ -164,6 +185,7 @@ public class AntNestBlockEntity extends BlockEntity { public void load(CompoundTag tag) { super.load(tag); this.initialized = tag.getBoolean(NBT_INITIALIZED); + this.rebroodCooldown = tag.contains(NBT_REBROOD_COOLDOWN) ? tag.getInt(NBT_REBROOD_COOLDOWN) : REBROOD_COOLDOWN_TICKS; this.storedAnts.clear(); ListTag listTag = tag.getList(STORED_ANTS, Tag.TAG_COMPOUND); for (int i = 0; i < listTag.size(); i++) { diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/config/AntarchySettings.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/config/AntarchySettings.java index de54bc70..7bfe5623 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/config/AntarchySettings.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/config/AntarchySettings.java @@ -91,6 +91,7 @@ public final class AntarchySettings { private static double bigBerthaNoneModeDamageBonusPercent = 15.0D; private static double bigBerthaNightmareDamageBonusPercent = 30.0D; private static double potentNyxiteInvertedDurationSeconds = 60.0D; + private static boolean dimensionalTearsSpawnNaturally = false; private static int dimensionalTearLifetimeTicks = 24000; private static int dimensionalTearInvertedDurationTicks = 2400; private static int dimensionalTearEmergenceMinIntervalTicks = 2400; @@ -231,6 +232,20 @@ public final class AntarchySettings { private static int royalGuardianShieldDurability = 1008; private static double royalBoltDamage = 6.0D; private static int royalEggHatchChance = 3; + private static double princeHealth = 120.0D; + private static double princeAttackDamage = 14.0D; + private static double princeMovementSpeed = 0.28D; + private static double princeFlyingSpeed = 0.9D; + private static double princeArmor = 10.0D; + private static double princeKnockbackResistance = 0.6D; + private static double princeFollowRange = 48.0D; + private static double princessHealth = 110.0D; + private static double princessAttackDamage = 10.0D; + private static double princessMovementSpeed = 0.28D; + private static double princessFlyingSpeed = 0.95D; + private static double princessArmor = 8.0D; + private static double princessKnockbackResistance = 0.5D; + private static double princessFollowRange = 48.0D; private static double kingHealth = 6000.0D; private static double queenHealth = 6000.0D; private static double kingAttackDamage = 50.0D; @@ -530,6 +545,7 @@ public final class AntarchySettings { private static double kingBeamTracking = 0.1D; private static double kingBeamTerrainRadius = 5.0D; private static int kingBeamTerrainCap = 192; + private static int royalDecreeCooldownTicks = 1200; private static double jerryInfantHealth = 20.0D; private static double jerryInfantAttackDamage = 2.0D; private static double jerryMatureHealth = 40.0D; @@ -791,6 +807,14 @@ public final class AntarchySettings { return potentNyxiteInvertedDurationSeconds; } + public static boolean dimensionalTearsSpawnNaturally() { + return dimensionalTearsSpawnNaturally; + } + + public static void setDimensionalTearsSpawnNaturally(boolean value) { + dimensionalTearsSpawnNaturally = value; + } + public static int dimensionalTearLifetimeTicks() { return dimensionalTearLifetimeTicks; } @@ -1948,6 +1972,36 @@ public final class AntarchySettings { public static int royalEggHatchChance() { return royalEggHatchChance; } public static void setRoyalEggHatchChance(int v) { royalEggHatchChance = v; } + public static double princeHealth() { return princeHealth; } + public static void setPrinceHealth(double v) { princeHealth = v; } + public static double princeAttackDamage() { return princeAttackDamage; } + public static void setPrinceAttackDamage(double v) { princeAttackDamage = v; } + public static double princeMovementSpeed() { return princeMovementSpeed; } + public static void setPrinceMovementSpeed(double v) { princeMovementSpeed = v; } + public static double princeFlyingSpeed() { return princeFlyingSpeed; } + public static void setPrinceFlyingSpeed(double v) { princeFlyingSpeed = v; } + public static double princeArmor() { return princeArmor; } + public static void setPrinceArmor(double v) { princeArmor = v; } + public static double princeKnockbackResistance() { return princeKnockbackResistance; } + public static void setPrinceKnockbackResistance(double v) { princeKnockbackResistance = v; } + public static double princeFollowRange() { return princeFollowRange; } + public static void setPrinceFollowRange(double v) { princeFollowRange = v; } + + public static double princessHealth() { return princessHealth; } + public static void setPrincessHealth(double v) { princessHealth = v; } + public static double princessAttackDamage() { return princessAttackDamage; } + public static void setPrincessAttackDamage(double v) { princessAttackDamage = v; } + public static double princessMovementSpeed() { return princessMovementSpeed; } + public static void setPrincessMovementSpeed(double v) { princessMovementSpeed = v; } + public static double princessFlyingSpeed() { return princessFlyingSpeed; } + public static void setPrincessFlyingSpeed(double v) { princessFlyingSpeed = v; } + public static double princessArmor() { return princessArmor; } + public static void setPrincessArmor(double v) { princessArmor = v; } + public static double princessKnockbackResistance() { return princessKnockbackResistance; } + public static void setPrincessKnockbackResistance(double v) { princessKnockbackResistance = v; } + public static double princessFollowRange() { return princessFollowRange; } + public static void setPrincessFollowRange(double v) { princessFollowRange = v; } + public static double kingHealth() { return kingHealth; } public static void setKingHealth(double v) { kingHealth = v; } @@ -2800,6 +2854,8 @@ public final class AntarchySettings { public static void setKingBeamTerrainRadius(double v) { kingBeamTerrainRadius = v; } public static int kingBeamTerrainCap() { return kingBeamTerrainCap; } public static void setKingBeamTerrainCap(int v) { kingBeamTerrainCap = v; } + public static int royalDecreeCooldownTicks() { return royalDecreeCooldownTicks; } + public static void setRoyalDecreeCooldownTicks(int v) { royalDecreeCooldownTicks = v; } public static double jerryInfantHealth() { return jerryInfantHealth; } public static void setJerryInfantHealth(double v) { jerryInfantHealth = v; } public static double jerryInfantAttackDamage() { return jerryInfantAttackDamage; } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/AntarchyObjects.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/AntarchyObjects.java index 4a2e8bcc..129654d0 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/AntarchyObjects.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/AntarchyObjects.java @@ -99,6 +99,8 @@ public final class AntarchyObjects { @SuppressWarnings("unchecked") public static Supplier> TIME_DILATION_FIELD = (Supplier>) UNBOUND; @SuppressWarnings("unchecked") + public static Supplier> ROYAL_BLACK_HOLE = (Supplier>) UNBOUND; + @SuppressWarnings("unchecked") public static Supplier VORTEX_LENS = (Supplier) UNBOUND; @SuppressWarnings("unchecked") public static Supplier> VORTEX_LENS_BLOCK_ENTITY = (Supplier>) UNBOUND; @@ -677,6 +679,10 @@ public final class AntarchyObjects { TIME_DILATION_FIELD = supplier; } + public static void setRoyalBlackHole(Supplier> supplier) { + ROYAL_BLACK_HOLE = supplier; + } + public static void setVortexLens(Supplier supplier) { VORTEX_LENS = supplier; } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/AntarchySoundEvents.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/AntarchySoundEvents.java index 8a2764e6..6dc60927 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/AntarchySoundEvents.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/AntarchySoundEvents.java @@ -194,6 +194,20 @@ public final class AntarchySoundEvents { public static Supplier QUEEN_BEAM_START = (Supplier) UNBOUND; public static Supplier QUEEN_BEAM_LOOP = (Supplier) UNBOUND; public static Supplier QUEEN_BEAM_END = (Supplier) UNBOUND; + public static Supplier KING_STOMP = (Supplier) UNBOUND; + public static Supplier KING_ROAR = (Supplier) UNBOUND; + public static Supplier KING_WING_FLAP = (Supplier) UNBOUND; + public static Supplier KING_FLY_LOOP = (Supplier) UNBOUND; + public static Supplier PRINCE_IDLE = (Supplier) UNBOUND; + public static Supplier PRINCE_BITE = (Supplier) UNBOUND; + public static Supplier PRINCE_SHOOT = (Supplier) UNBOUND; + public static Supplier PRINCE_FLY = (Supplier) UNBOUND; + public static Supplier PRINCE_STEP = (Supplier) UNBOUND; + public static Supplier PRINCESS_IDLE = (Supplier) UNBOUND; + public static Supplier PRINCESS_BITE = (Supplier) UNBOUND; + public static Supplier PRINCESS_SHOOT = (Supplier) UNBOUND; + public static Supplier PRINCESS_FLY = (Supplier) UNBOUND; + public static Supplier PRINCESS_STEP = (Supplier) UNBOUND; private AntarchySoundEvents() { } @@ -383,7 +397,21 @@ public final class AntarchySoundEvents { Supplier queenBeamShoot, Supplier queenBeamStart, Supplier queenBeamLoop, - Supplier queenBeamEnd + Supplier queenBeamEnd, + Supplier kingStomp, + Supplier kingRoar, + Supplier kingWingFlap, + Supplier kingFlyLoop, + Supplier princeIdle, + Supplier princeBite, + Supplier princeShoot, + Supplier princeFly, + Supplier princeStep, + Supplier princessIdle, + Supplier princessBite, + Supplier princessShoot, + Supplier princessFly, + Supplier princessStep ) { SQUIDZOOKA_FIRE = squidzookaFire; SHRINK_RAY_CHARGE = shrinkRayCharge; @@ -570,5 +598,19 @@ public final class AntarchySoundEvents { QUEEN_BEAM_START = queenBeamStart; QUEEN_BEAM_LOOP = queenBeamLoop; QUEEN_BEAM_END = queenBeamEnd; + KING_STOMP = kingStomp; + KING_ROAR = kingRoar; + KING_WING_FLAP = kingWingFlap; + KING_FLY_LOOP = kingFlyLoop; + PRINCE_IDLE = princeIdle; + PRINCE_BITE = princeBite; + PRINCE_SHOOT = princeShoot; + PRINCE_FLY = princeFly; + PRINCE_STEP = princeStep; + PRINCESS_IDLE = princessIdle; + PRINCESS_BITE = princessBite; + PRINCESS_SHOOT = princessShoot; + PRINCESS_FLY = princessFly; + PRINCESS_STEP = princessStep; } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/AntarchyTags.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/AntarchyTags.java index 618f7fc1..cf0ab609 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/AntarchyTags.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/AntarchyTags.java @@ -83,6 +83,7 @@ public final class AntarchyTags { public static final TagKey> LUCID_ANCHOR_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("lucid_anchor_immune")); public static final TagKey> DIMENSIONAL_TEAR_COMMON_SPAWNS = TagKey.create(Registries.ENTITY_TYPE, id("dimensional_tear_common_spawns")); public static final TagKey> DIMENSIONAL_TEAR_RARE_SPAWNS = TagKey.create(Registries.ENTITY_TYPE, id("dimensional_tear_rare_spawns")); + public static final TagKey> TIME_DILATION_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("time_dilation_immune")); private Entities() { } @@ -114,6 +115,7 @@ public final class AntarchyTags { public static final TagKey BUTTERFLY_BREEDING_FOODS = TagKey.create(Registries.ITEM, id("butterfly_breeding_foods")); public static final TagKey REVERIE_DUPLICATION_ITEMS = TagKey.create(Registries.ITEM, id("reverie_duplication_items")); public static final TagKey HERCULES_BEETLE_FOOD = TagKey.create(Registries.ITEM, id("hercules_beetle_food")); + public static final TagKey ROYAL_MOUNT_FOOD = TagKey.create(Registries.ITEM, id("royal_mount_food")); public static final TagKey ROLLY_POLLY_FOOD = TagKey.create(Registries.ITEM, id("rolly_polly_food")); public static final TagKey OURANWOOD_DEER_FOOD = TagKey.create(Registries.ITEM, id("ouranwood_deer_food")); public static final TagKey GLIMMER_AUGMENT_APPLE_COW = TagKey.create(Registries.ITEM, id("glimmer_augment_apple_cow")); diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/block/AntigravelBlock.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/block/AntigravelBlock.java index ccaee8a1..29e6320b 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/block/AntigravelBlock.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/block/AntigravelBlock.java @@ -15,6 +15,9 @@ import net.minecraft.world.level.block.state.BlockState; public class AntigravelBlock extends Block { public static final MapCodec CODEC = simpleCodec(AntigravelBlock::new); + private static final int SETTLE_DELAY = 6; + private static final int SETTLE_ATTEMPT_DENOMINATOR = 3; + public AntigravelBlock(BlockBehaviour.Properties properties) { super(properties); } @@ -28,13 +31,13 @@ public class AntigravelBlock extends Block { protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { super.onPlace(state, level, pos, oldState, movedByPiston); if (!level.isClientSide) { - level.scheduleTick(pos, this, 2); + level.scheduleTick(pos, this, SETTLE_DELAY); } } @Override protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) { - level.scheduleTick(pos, this, 2); + level.scheduleTick(pos, this, SETTLE_DELAY); return super.updateShape(state, direction, neighborState, level, pos, neighborPos); } @@ -46,8 +49,13 @@ public class AntigravelBlock extends Block { 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); + if (!passable) { + return; } + if (random.nextInt(SETTLE_ATTEMPT_DENOMINATOR) != 0) { + level.scheduleTick(pos, this, SETTLE_DELAY + random.nextInt(SETTLE_DELAY)); + return; + } + UpwardFallingBlockEntity.fallUp(level, pos, state, false); } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/block/entity/AntNestBlockEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/block/entity/AntNestBlockEntity.java index b2c39916..76c68ee4 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/block/entity/AntNestBlockEntity.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/block/entity/AntNestBlockEntity.java @@ -19,16 +19,20 @@ import net.minecraft.world.level.block.state.BlockState; public class AntNestBlockEntity extends BlockEntity { private static final String STORED_ANTS = "StoredAnts"; private static final String NBT_INITIALIZED = "Initialized"; + private static final String NBT_REBROOD_COOLDOWN = "RebroodCooldown"; private static final int RELEASE_COOLDOWN_MIN = 80; private static final int RELEASE_COOLDOWN_RANGE = 100; private static final int ENTER_NEST_COOLDOWN = 200; private static final int INITIAL_ANT_COUNT_MIN = 2; private static final int INITIAL_ANT_COUNT_RANGE = 4; + private static final int REBROOD_COOLDOWN_TICKS = 20 * 60 * 5; + private static final double PLAYER_ACTIVATION_RANGE = 16.0D; private static final double SPAWN_OFFSET_XZ = 0.5D; private static final double SPAWN_OFFSET_Y = 0.05D; private final List storedAnts = new ArrayList<>(); private int releaseCooldown = RELEASE_COOLDOWN_MIN; + private int rebroodCooldown = REBROOD_COOLDOWN_TICKS; private boolean initialized = false; public AntNestBlockEntity(BlockPos pos, BlockState blockState) { @@ -36,8 +40,19 @@ public class AntNestBlockEntity extends BlockEntity { } public static void serverTick(ServerLevel level, BlockPos pos, BlockState state, AntNestBlockEntity nest) { + boolean playerNearby = level.hasNearbyAlivePlayer( + pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, PLAYER_ACTIVATION_RANGE); + if (!playerNearby) { + return; + } + if (!nest.initialized) { nest.populateInitialAnts(level); + } else if (nest.storedAnts.isEmpty() && nest.nestBlock().shouldPopulateInitialAnts()) { + if (--nest.rebroodCooldown <= 0) { + nest.rebroodCooldown = REBROOD_COOLDOWN_TICKS; + nest.fillWithAnts(level); + } } boolean ignoreNight = level.dimensionType().hasFixedTime(); @@ -67,11 +82,16 @@ public class AntNestBlockEntity extends BlockEntity { return; } + this.fillWithAnts(level); + } + + private void fillWithAnts(ServerLevel level) { int amount = INITIAL_ANT_COUNT_MIN + level.random.nextInt(INITIAL_ANT_COUNT_RANGE); for (int i = 0; i < amount && this.storedAnts.size() < this.maxOccupants(); i++) { EntityType antType = this.nestBlock().initialAntType(level.random); this.storedAnts.add(this.createStoredAnt(level, antType)); } + this.rebroodCooldown = REBROOD_COOLDOWN_TICKS; this.setChanged(); } @@ -152,6 +172,7 @@ public class AntNestBlockEntity extends BlockEntity { protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) { super.saveAdditional(tag, registries); tag.putBoolean(NBT_INITIALIZED, this.initialized); + tag.putInt(NBT_REBROOD_COOLDOWN, this.rebroodCooldown); ListTag listTag = new ListTag(); for (StoredAnt storedAnt : this.storedAnts) { listTag.add(storedAnt.save()); @@ -163,6 +184,7 @@ public class AntNestBlockEntity extends BlockEntity { protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) { super.loadAdditional(tag, registries); this.initialized = tag.getBoolean(NBT_INITIALIZED); + this.rebroodCooldown = tag.contains(NBT_REBROOD_COOLDOWN) ? tag.getInt(NBT_REBROOD_COOLDOWN) : REBROOD_COOLDOWN_TICKS; this.storedAnts.clear(); ListTag listTag = tag.getList(STORED_ANTS, Tag.TAG_COMPOUND); for (int i = 0; i < listTag.size(); i++) { diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/ClientTimeDilationTicker.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/ClientTimeDilationTicker.java index 2f08963f..97886a73 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/ClientTimeDilationTicker.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/ClientTimeDilationTicker.java @@ -1,75 +1,147 @@ package com.craisinlord.antarchy.content.client; -import com.craisinlord.antarchy.content.time.TimeDilationEntityAccess; -import com.craisinlord.antarchy.content.time.TimeDilationFieldEntity; -import com.craisinlord.antarchy.content.time.TimeDilationFieldSampler; +import com.craisinlord.antarchy.content.time.TimeDilationFieldSnapshot; +import com.craisinlord.antarchy.content.time.TimeDilationFieldSnapshotSampler; import com.craisinlord.antarchy.content.time.TimeDilationMath; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.WeakHashMap; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.util.Mth; public final class ClientTimeDilationTicker { - private static boolean hadFields; - private static volatile List activeFields = List.of(); - private static final Map ANIM_OFFSETS = new WeakHashMap<>(); + private static volatile List activeFields = List.of(); + private static ClientLevel activeLevel; + private static final Map ITEM_SPIN_STATES = new WeakHashMap<>(); + private static final Map ATTACK_ANIMATION_STATES = new WeakHashMap<>(); + private static final Map ANIMATION_CLOCKS = new WeakHashMap<>(); private ClientTimeDilationTicker() { } public static void tick(ClientLevel level) { - List fields = new ArrayList<>(); - for (Entity entity : level.entitiesForRendering()) { - if (entity instanceof TimeDilationFieldEntity field && field.isAlive()) { - fields.add(field); - } - } - activeFields = fields; - - if (fields.isEmpty()) { - if (hadFields) { - resetRates(level); - hadFields = false; - } - return; - } - hadFields = true; - - for (Entity entity : level.entitiesForRendering()) { - if (!(entity instanceof TimeDilationEntityAccess access) || entity instanceof TimeDilationFieldEntity) { - continue; - } - double rate = TimeDilationFieldSampler.sample(fields, entity.position()); - access.antarchy$setTimeDilationRate(rate); - if (rate < TimeDilationMath.NORMAL_RATE) { - ANIM_OFFSETS.merge(entity, rate - TimeDilationMath.NORMAL_RATE, Double::sum); - } + if (activeLevel != level) { + activeLevel = level; + activeFields = List.of(); + ITEM_SPIN_STATES.clear(); + ATTACK_ANIMATION_STATES.clear(); + ANIMATION_CLOCKS.clear(); + com.craisinlord.antarchy.content.time.TimeDilationApi.clearSyncedClientRates(); } + // Entity rates come from the server. Field snapshots are used only for local effects. } public static float dilateAnimationTime(Entity entity, float vanillaTime) { - Double offset = ANIM_OFFSETS.get(entity); - return offset == null ? vanillaTime : (float) (vanillaTime + offset); + double rate = com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(entity); + if (rate >= TimeDilationMath.NORMAL_RATE) { + ANIMATION_CLOCKS.remove(entity); + return vanillaTime; + } + AnimationClockState state = ANIMATION_CLOCKS.computeIfAbsent(entity, + ignored -> new AnimationClockState(vanillaTime)); + float delta = vanillaTime - state.lastVanillaTime; + if (delta >= 0.0F) { + state.temporalTime += delta * (float) rate; + } + state.lastVanillaTime = vanillaTime; + return state.temporalTime; + } + + public static float dilateAttackAnimation(LivingEntity entity, float partialTick, float vanillaAnimation) { + double rate = com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(entity); + if (rate >= TimeDilationMath.NORMAL_RATE) { + ATTACK_ANIMATION_STATES.remove(entity); + return vanillaAnimation; + } + AttackAnimationState state = ATTACK_ANIMATION_STATES.computeIfAbsent( + entity, ignored -> new AttackAnimationState(entity.tickCount, vanillaAnimation) + ); + if (state.lastTick != entity.tickCount) { + state.previous = state.current; + state.current += (vanillaAnimation - state.current) * (float) rate; + state.lastTick = entity.tickCount; + } + return state.previous + (state.current - state.previous) * partialTick; + } + + public static float dilateRotation(LivingEntity entity, float previous, float current, float partialTick) { + double rate = com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(entity); + if (rate >= TimeDilationMath.NORMAL_RATE) { + return Mth.rotLerp(partialTick, previous, current); + } + return previous + Mth.wrapDegrees(current - previous) * partialTick * (float) rate; + } + + public static float dilatePitch(LivingEntity entity, float previous, float current, float partialTick) { + double rate = com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(entity); + if (rate >= TimeDilationMath.NORMAL_RATE) { + return Mth.lerp(partialTick, previous, current); + } + return previous + (current - previous) * partialTick * (float) rate; + } + + public static float dilateWalkAmount(LivingEntity entity, float amount) { + double rate = com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(entity); + return rate >= TimeDilationMath.NORMAL_RATE ? amount : amount * (float) rate; + } + + public static float dilateItemSpin(ItemEntity item, float vanillaSpin) { + double rate = com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(item); + if (rate >= TimeDilationMath.NORMAL_RATE) { + ITEM_SPIN_STATES.remove(item); + return vanillaSpin; + } + ItemSpinState state = ITEM_SPIN_STATES.computeIfAbsent(item, ignored -> new ItemSpinState(vanillaSpin)); + float rawDelta = vanillaSpin - state.lastVanillaSpin; + state.lastVanillaSpin = vanillaSpin; + state.temporalSpin += rawDelta * (float) rate; + return state.temporalSpin; + } + + private static final class ItemSpinState { + private float lastVanillaSpin; + private float temporalSpin; + + private ItemSpinState(float initialSpin) { + this.lastVanillaSpin = initialSpin; + this.temporalSpin = initialSpin; + } + } + + private static final class AttackAnimationState { + private int lastTick; + private float previous; + private float current; + + private AttackAnimationState(int tick, float initial) { + this.lastTick = tick; + this.previous = initial; + this.current = initial; + } + } + + private static final class AnimationClockState { + private float lastVanillaTime; + private float temporalTime; + + private AnimationClockState(float initialTime) { + this.lastVanillaTime = initialTime; + this.temporalTime = initialTime; + } } public static double rateAt(double x, double y, double z) { - List fields = activeFields; + List fields = activeFields; if (fields.isEmpty()) { return TimeDilationMath.NORMAL_RATE; } - return TimeDilationFieldSampler.sample(fields, x, y, z); + return TimeDilationFieldSnapshotSampler.sample(fields, x, y, z); } - private static void resetRates(ClientLevel level) { - for (Entity entity : level.entitiesForRendering()) { - if (!(entity instanceof TimeDilationEntityAccess access) || entity instanceof TimeDilationFieldEntity) { - continue; - } - if (access.antarchy$getTimeDilationRate() < TimeDilationMath.NORMAL_RATE) { - access.antarchy$setTimeDilationRate(TimeDilationMath.NORMAL_RATE); - } - } + public static void applyFields(List fields) { + activeFields = List.copyOf(fields); } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/RoyalBossRenderer.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/RoyalBossRenderer.java index 56e60ed7..7717bb46 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/RoyalBossRenderer.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/client/renderer/RoyalBossRenderer.java @@ -2,18 +2,34 @@ package com.craisinlord.antarchy.content.client.renderer; import com.craisinlord.antarchy.content.client.model.RoyalBossModel; import com.craisinlord.antarchy.content.entity.royal.RoyalBossEntity; +import com.craisinlord.antarchy.content.entity.royal.KingEntity; +import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; import software.bernie.geckolib.cache.object.BakedGeoModel; import software.bernie.geckolib.renderer.GeoEntityRenderer; +import software.bernie.geckolib.util.Color; public class RoyalBossRenderer extends GeoEntityRenderer { + private static final ResourceLocation QUEEN_BEAM_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_beam_outer.png"); + private static final ResourceLocation QUEEN_BEAM_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_beam_inner.png"); + private static final ResourceLocation QUEEN_BEAM_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/queen/queen_beam_end_1.png"); + private static final ResourceLocation KING_FIRE_BEAM_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_outer.png"); + private static final ResourceLocation KING_FIRE_BEAM_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_inner.png"); + private static final ResourceLocation KING_FIRE_BEAM_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/fire_beam_end_1.png"); + private static final ResourceLocation KING_LIGHTNING_BEAM_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/lightning_beam_outer.png"); + private static final ResourceLocation KING_LIGHTNING_BEAM_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/lightning_beam_inner.png"); + private static final ResourceLocation KING_LIGHTNING_BEAM_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/lightning_beam_end_1.png"); + private static final ResourceLocation KING_ICE_BEAM_OUTER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/ice_beam_outer.png"); + private static final ResourceLocation KING_ICE_BEAM_INNER = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/ice_beam_inner.png"); + private static final ResourceLocation KING_ICE_BEAM_END = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/king/ice_beam_end_1.png"); public RoyalBossRenderer(EntityRendererProvider.Context context) { super(context, new RoyalBossModel()); this.shadowRadius = 8.0F; @@ -24,6 +40,16 @@ public class RoyalBossRenderer extends GeoEntityRenderer { return RenderType.entityCutoutNoCull(texture); } + @Override + public Color getRenderColor(RoyalBossEntity animatable, float partialTick, int packedLight) { + if (!animatable.isRoyalAccelerated()) { + return Color.ofRGBA(255, 255, 255, 255); + } + float pulse = 0.5F + 0.5F * (float) Math.sin((animatable.tickCount + partialTick) * 0.4F); + int green = 60 + Math.round(60.0F * pulse); + return Color.ofRGBA(255, green, green, 255); + } + @Override public void preRender(PoseStack poseStack, RoyalBossEntity animatable, BakedGeoModel model, @Nullable MultiBufferSource bufferSource, @Nullable VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) { @@ -32,6 +58,11 @@ public class RoyalBossRenderer extends GeoEntityRenderer { this.shadowRadius = 8.0F * RoyalBossEntity.MODEL_RENDER_SCALE; } + private static final float BEAM_OUTER_RADIUS = 0.55F; + private static final float BEAM_INNER_RADIUS = 0.26F; + private static final float BEAM_TILE_BLOCKS = 3.0F; + private static final float BEAM_SCROLL_SPEED = 0.32F; + @Override public void render(RoyalBossEntity entity, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight) { @@ -40,36 +71,105 @@ public class RoyalBossRenderer extends GeoEntityRenderer { if (!entity.isFiringRoyalBeam() || end == null) { return; } - double x = net.minecraft.util.Mth.lerp(partialTick, entity.xo, entity.getX()); - double y = net.minecraft.util.Mth.lerp(partialTick, entity.yo, entity.getY()); - double z = net.minecraft.util.Mth.lerp(partialTick, entity.zo, entity.getZ()); + double x = Mth.lerp(partialTick, entity.xo, entity.getX()); + double y = Mth.lerp(partialTick, entity.yo, entity.getY()); + double z = Mth.lerp(partialTick, entity.zo, entity.getZ()); Vec3 start = entity.getRoyalBeamShootFrom(partialTick).subtract(x, y, z); Vec3 finish = end.subtract(x, y, z); - Vec3 direction = finish.subtract(start).normalize(); - Vec3 side = direction.cross(new Vec3(0.0D, 1.0D, 0.0D)); - if (side.lengthSqr() < 1.0E-4D) { - side = direction.cross(new Vec3(1.0D, 0.0D, 0.0D)); + Vec3 axis = finish.subtract(start); + double length = axis.length(); + if (length < 0.05D) { + return; } - side = side.normalize().scale(0.22D); - VertexConsumer vertices = bufferSource.getBuffer(RenderType.lightning()); - poseStack.pushPose(); - poseStack.scale(0.5F, 0.5F, 0.5F); - drawBeamQuad(vertices, poseStack, start, finish, side); - drawBeamQuad(vertices, poseStack, start, finish, new Vec3(-side.z, side.y, side.x)); - poseStack.popPose(); - } + Vec3 dir = axis.scale(1.0D / length); + Vec3 side1 = dir.cross(new Vec3(0.0D, 1.0D, 0.0D)); + if (side1.lengthSqr() < 1.0E-4D) { + side1 = dir.cross(new Vec3(1.0D, 0.0D, 0.0D)); + } + side1 = side1.normalize(); + Vec3 side2 = dir.cross(side1).normalize(); - private static void drawBeamQuad(VertexConsumer vertices, PoseStack poseStack, Vec3 start, Vec3 end, Vec3 side) { + ResourceLocation outer = QUEEN_BEAM_OUTER; + ResourceLocation inner = QUEEN_BEAM_INNER; + ResourceLocation endTexture = QUEEN_BEAM_END; + if (entity instanceof KingEntity) { + switch (entity.getRoyalBeamElement()) { + case FIRE -> { + outer = KING_FIRE_BEAM_OUTER; + inner = KING_FIRE_BEAM_INNER; + endTexture = KING_FIRE_BEAM_END; + } + case LIGHTNING -> { + outer = KING_LIGHTNING_BEAM_OUTER; + inner = KING_LIGHTNING_BEAM_INNER; + endTexture = KING_LIGHTNING_BEAM_END; + } + case ICE -> { + outer = KING_ICE_BEAM_OUTER; + inner = KING_ICE_BEAM_INNER; + endTexture = KING_ICE_BEAM_END; + } + case GENERIC -> { + } + } + } + + float time = entity.tickCount + partialTick; + float tiles = (float) (length / BEAM_TILE_BLOCKS); + float scroll = -time * BEAM_SCROLL_SPEED; var pose = poseStack.last().pose(); - vertex(vertices, pose, start.subtract(side)); - vertex(vertices, pose, start.add(side)); - vertex(vertices, pose, end.add(side)); - vertex(vertices, pose, end.subtract(side)); + + VertexConsumer outerBuffer = bufferSource.getBuffer(RenderType.entityTranslucent(outer)); + drawBeamPlane(outerBuffer, pose, start, finish, side1.scale(BEAM_OUTER_RADIUS), scroll, scroll + tiles); + drawBeamPlane(outerBuffer, pose, start, finish, side2.scale(BEAM_OUTER_RADIUS), scroll, scroll + tiles); + + float innerScroll = -time * BEAM_SCROLL_SPEED * 1.6F; + VertexConsumer innerBuffer = bufferSource.getBuffer(RenderType.entityTranslucent(inner)); + drawBeamPlane(innerBuffer, pose, start, finish, side1.scale(BEAM_INNER_RADIUS), innerScroll, innerScroll + tiles); + drawBeamPlane(innerBuffer, pose, start, finish, side2.scale(BEAM_INNER_RADIUS), innerScroll, innerScroll + tiles); + + float impactSize = 1.1F + 0.35F * Mth.sin(time * 0.6F); + Vec3 camLeft = new Vec3(this.entityRenderDispatcher.camera.getLeftVector()); + Vec3 camUp = new Vec3(this.entityRenderDispatcher.camera.getUpVector()); + VertexConsumer endBuffer = bufferSource.getBuffer(RenderType.entityTranslucent(endTexture)); + drawBillboard(endBuffer, pose, finish, camLeft.scale(impactSize), camUp.scale(impactSize)); } - private static void vertex(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 pos) { + private static void drawBeamPlane(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 start, Vec3 end, Vec3 half, + float startV, float endV) { + emitQuad(vertices, pose, + start.subtract(half), start.add(half), end.add(half), end.subtract(half), + 0.0F, startV, 1.0F, endV); + emitQuad(vertices, pose, + start.add(half), start.subtract(half), end.subtract(half), end.add(half), + 0.0F, startV, 1.0F, endV); + } + + private static void drawBillboard(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 center, Vec3 left, Vec3 up) { + emitQuad(vertices, pose, + center.add(left).add(up), center.subtract(left).add(up), + center.subtract(left).subtract(up), center.add(left).subtract(up), + 0.0F, 0.0F, 1.0F, 1.0F); + emitQuad(vertices, pose, + center.subtract(left).add(up), center.add(left).add(up), + center.add(left).subtract(up), center.subtract(left).subtract(up), + 0.0F, 0.0F, 1.0F, 1.0F); + } + + private static void emitQuad(VertexConsumer vertices, org.joml.Matrix4f pose, + Vec3 a, Vec3 b, Vec3 c, Vec3 d, + float minU, float minV, float maxU, float maxV) { + vertex(vertices, pose, a, minU, minV); + vertex(vertices, pose, b, maxU, minV); + vertex(vertices, pose, c, maxU, maxV); + vertex(vertices, pose, d, minU, maxV); + } + + private static void vertex(VertexConsumer vertices, org.joml.Matrix4f pose, Vec3 pos, float u, float v) { vertices.addVertex(pose, (float) pos.x, (float) pos.y, (float) pos.z) - .setColor(255, 255, 255, 255).setUv(0.0F, 0.0F).setUv2(15728880 & 65535, 15728880 >> 16) + .setColor(255, 255, 255, 255).setUv(u, v) + .setOverlay(net.minecraft.client.renderer.texture.OverlayTexture.NO_OVERLAY) + .setLight(0x00F000F0) .setNormal(0.0F, 1.0F, 0.0F); } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/command/DimensionalTearCommand.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/command/DimensionalTearCommand.java new file mode 100644 index 00000000..7cfdbfcc --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/command/DimensionalTearCommand.java @@ -0,0 +1,76 @@ +package com.craisinlord.antarchy.content.command; + +import com.craisinlord.antarchy.config.AntarchySettings; +import com.craisinlord.antarchy.content.entity.portal.DimensionalTearEntity; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.DoubleArgumentType; +import com.mojang.brigadier.context.CommandContext; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; + +public final class DimensionalTearCommand { + private static final double DEFAULT_GAP = 24.0D; + private static final double VERTICAL_OFFSET = 1.0D; + + private DimensionalTearCommand() { + } + + public static void register(CommandDispatcher dispatcher) { + dispatcher.register( + Commands.literal("dimensionaltear") + .requires(source -> source.hasPermission(2)) + .executes(context -> spawnPair(context, DEFAULT_GAP)) + .then(Commands.literal("single") + .executes(DimensionalTearCommand::spawnSingle)) + .then(Commands.argument("blocksAhead", DoubleArgumentType.doubleArg(2.0D, 512.0D)) + .executes(context -> spawnPair(context, DoubleArgumentType.getDouble(context, "blocksAhead")))) + ); + } + + private static int lifetime() { + return Math.max(1200, AntarchySettings.dimensionalTearLifetimeTicks()); + } + + private static Vec3 anchorPos(ServerPlayer player) { + return player.position().add(0.0D, VERTICAL_OFFSET, 0.0D); + } + + private static int spawnSingle(CommandContext context) throws com.mojang.brigadier.exceptions.CommandSyntaxException { + ServerPlayer player = context.getSource().getPlayerOrException(); + ServerLevel level = context.getSource().getLevel(); + DimensionalTearEntity tear = DimensionalTearEntity.create(level, anchorPos(player), player.getYRot(), lifetime()); + level.addFreshEntity(tear); + context.getSource().sendSuccess(() -> Component.literal("Spawned an unlinked dimensional tear"), true); + return 1; + } + + private static int spawnPair(CommandContext context, double gap) throws com.mojang.brigadier.exceptions.CommandSyntaxException { + ServerPlayer player = context.getSource().getPlayerOrException(); + ServerLevel level = context.getSource().getLevel(); + + float yawA = player.getYRot(); + Vec3 posA = anchorPos(player); + Vec3 forward = Vec3.directionFromRotation(0.0F, yawA); + Vec3 posB = posA.add(forward.scale(gap)); + float yawB = Mth.wrapDegrees(yawA + 180.0F); + + DimensionalTearEntity tearA = DimensionalTearEntity.create(level, posA, yawA, lifetime()); + DimensionalTearEntity tearB = DimensionalTearEntity.create(level, posB, yawB, lifetime()); + tearA.linkTo(tearB); + tearB.linkTo(tearA); + level.addFreshEntity(tearA); + level.addFreshEntity(tearB); + + int spacing = Mth.floor(gap); + context.getSource().sendSuccess( + () -> Component.literal("Spawned a linked dimensional tear pair, " + spacing + " blocks apart"), + true + ); + return 1; + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/UpwardFallingBlockEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/UpwardFallingBlockEntity.java index 9130a266..4767558b 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/UpwardFallingBlockEntity.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/UpwardFallingBlockEntity.java @@ -1,14 +1,19 @@ package com.craisinlord.antarchy.content.entity; import com.craisinlord.antarchy.content.block.AntimetalScaffoldingBlock; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.BlockTags; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntitySelector; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.MoverType; @@ -32,10 +37,17 @@ public class UpwardFallingBlockEntity extends Entity { private static final double RISE_ACCEL = 0.04; private static final double DRAG = 0.98; private static final int MAX_TICKS = 200; + private static final int MAX_LIVE_PER_LEVEL = 200; + private static final double PLAYER_ACTIVATION_RADIUS = 128.0; + private static final int INSTANT_MOVE_MAX_DISTANCE = 48; + private static final double MIN_TRAVEL_FOR_DAMAGE = 1.5; + + private static final Object2IntOpenHashMap> LIVE_COUNT = new Object2IntOpenHashMap<>(); public int time = 0; private boolean breaksOnLeaves = true; private double distanceTraveled = 0.0; + private boolean counted = false; public UpwardFallingBlockEntity(EntityType type, Level level) { super(type, level); @@ -60,16 +72,90 @@ public class UpwardFallingBlockEntity extends Entity { } public static void fallUp(Level level, BlockPos pos, BlockState state, boolean breaksOnLeaves) { - if (level.isClientSide) return; - // Prevent stacking multiple entities from the same block position - if (!level.getEntitiesOfClass(UpwardFallingBlockEntity.class, new AABB(pos)).isEmpty()) return; + if (!(level instanceof ServerLevel serverLevel)) { + return; + } - level.removeBlock(pos, false); - UpwardFallingBlockEntity entity = new UpwardFallingBlockEntity(TYPE.get(), level); + ResourceKey dimension = serverLevel.dimension(); + int live = LIVE_COUNT.getInt(dimension); + if (live >= MAX_LIVE_PER_LEVEL) { + live = serverLevel.getEntities(TYPE.get(), Entity::isAlive).size(); + if (live <= 0) { + LIVE_COUNT.removeInt(dimension); + } else { + LIVE_COUNT.put(dimension, live); + } + } + + boolean noPlayerNearby = serverLevel.getNearestPlayer( + pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, PLAYER_ACTIVATION_RADIUS, EntitySelector.NO_SPECTATORS) == null; + if (live >= MAX_LIVE_PER_LEVEL || noPlayerNearby) { + resolveInstantly(serverLevel, pos, state, breaksOnLeaves); + return; + } + + serverLevel.removeBlock(pos, false); + UpwardFallingBlockEntity entity = new UpwardFallingBlockEntity(TYPE.get(), serverLevel); entity.entityData.set(DATA_BLOCK_STATE, state); entity.breaksOnLeaves = breaksOnLeaves; entity.setPos(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); - level.addFreshEntity(entity); + if (serverLevel.addFreshEntity(entity)) { + entity.counted = true; + LIVE_COUNT.addTo(serverLevel.dimension(), 1); + } + } + + private static void resolveInstantly(ServerLevel level, BlockPos pos, BlockState state, boolean breaksOnLeaves) { + level.removeBlock(pos, false); + + BlockPos.MutableBlockPos rest = pos.mutable(); + for (int i = 0; i < INSTANT_MOVE_MAX_DISTANCE; i++) { + BlockPos above = rest.above(); + if (above.getY() >= level.getMaxBuildHeight()) { + break; + } + BlockState aboveState = level.getBlockState(above); + if (aboveState.getBlock() instanceof AntimetalScaffoldingBlock) { + break; + } + if (breaksOnLeaves && aboveState.is(BlockTags.LEAVES)) { + dropAsItem(level, rest, state); + return; + } + if (!aboveState.canBeReplaced()) { + break; + } + rest.move(Direction.UP); + } + + if (level.getBlockState(rest).canBeReplaced()) { + level.setBlock(rest, state, Block.UPDATE_ALL); + } else { + dropAsItem(level, rest, state); + } + } + + private static void dropAsItem(Level level, BlockPos pos, BlockState state) { + if (state.isAir()) { + return; + } + ItemStack drop = new ItemStack(state.getBlock().asItem()); + if (!drop.isEmpty()) { + Block.popResource(level, pos, drop); + } + } + + @Override + public void remove(Entity.RemovalReason reason) { + if (this.counted) { + this.counted = false; + ResourceKey key = this.level().dimension(); + int remaining = LIVE_COUNT.addTo(key, -1) - 1; + if (remaining <= 0) { + LIVE_COUNT.removeInt(key); + } + } + super.remove(reason); } @Override @@ -99,7 +185,9 @@ public class UpwardFallingBlockEntity extends Entity { return; } - damageEntitiesAlongPath(blockState); + if (distanceTraveled > MIN_TRAVEL_FOR_DAMAGE) { + damageEntitiesAlongPath(blockState); + } BlockPos headPos = BlockPos.containing(getX(), getBoundingBox().maxY, getZ()); BlockState above = level().getBlockState(headPos); diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/cloud_shark/CloudSharkEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/cloud_shark/CloudSharkEntity.java index b55512d0..92e65936 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/cloud_shark/CloudSharkEntity.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/cloud_shark/CloudSharkEntity.java @@ -120,12 +120,22 @@ public class CloudSharkEntity extends Monster implements GeoEntity { return super.finalizeSpawn(level, difficulty, spawnReason, spawnData); } + private static final int MIN_SPAWN_HEIGHT_ABOVE_TERRAIN = 16; + public static boolean canSpawn(EntityType entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { - return level.getDifficulty() != Difficulty.PEACEFUL - && level.isEmptyBlock(pos) - && (level.isEmptyBlock(pos.above()) || level.isEmptyBlock(pos.below())) - && level.getFluidState(pos).isEmpty(); + if (level.getDifficulty() == Difficulty.PEACEFUL || !level.getFluidState(pos).isEmpty()) { + return false; + } + if (!level.isEmptyBlock(pos) || !level.isEmptyBlock(pos.above()) || !level.isEmptyBlock(pos.below())) { + return false; + } + if (spawnReason == MobSpawnType.SPAWNER || spawnReason == MobSpawnType.SPAWN_EGG + || spawnReason == MobSpawnType.COMMAND || spawnReason == MobSpawnType.BUCKET) { + return true; + } + int terrainHeight = level.getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, pos.getX(), pos.getZ()); + return pos.getY() >= terrainHeight + MIN_SPAWN_HEIGHT_ABOVE_TERRAIN; } @Override diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/nightmare/NightmareEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/nightmare/NightmareEntity.java index b30b0f5e..c3703656 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/nightmare/NightmareEntity.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/nightmare/NightmareEntity.java @@ -183,6 +183,7 @@ public class NightmareEntity extends Monster implements GeoEntity { private static final RawAnimation PHASE_TWO_WALK_ANIM = RawAnimation.begin().thenLoop("walk_P2"); private static final RawAnimation PHASE_TWO_FLY_ANIM = RawAnimation.begin().thenLoop("fly_P2"); private static final String LOCOMOTION_CONTROLLER = "main_controller"; + private static final int LOCOMOTION_TRANSITION_TICKS = 5; private static final String SPECIAL_CONTROLLER = "special_controller"; private static final String SPECIAL_ATTACK_TRIGGER = "attack"; private static final String SPECIAL_ATTACK_P2_TRIGGER = "attack_P2"; @@ -293,7 +294,7 @@ public class NightmareEntity extends Monster implements GeoEntity { @Override public void registerControllers(AnimatableManager.ControllerRegistrar controllers) { - controllers.add(new AnimationController<>(this, LOCOMOTION_CONTROLLER, 0, this::mainAnimController)); + controllers.add(new AnimationController<>(this, LOCOMOTION_CONTROLLER, LOCOMOTION_TRANSITION_TICKS, this::mainAnimController)); controllers.add(new AnimationController<>(this, SPECIAL_CONTROLLER, 0, state -> PlayState.STOP) .triggerableAnim(SPECIAL_ATTACK_TRIGGER, ATTACK_ANIM) .triggerableAnim(SPECIAL_ATTACK_P2_TRIGGER, ATTACK_P2_ANIM) diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/KingEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/KingEntity.java index 578ea957..1da0efc6 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/KingEntity.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/KingEntity.java @@ -3,34 +3,98 @@ package com.craisinlord.antarchy.content.entity.royal; import com.craisinlord.antarchy.config.AntarchySettings; import com.craisinlord.antarchy.content.AntarchySoundEvents; import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.network.chat.Component; +import net.minecraft.ChatFormatting; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.network.protocol.game.ClientboundClearTitlesPacket; +import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket; import net.minecraft.world.BossEvent; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LightningBolt; +import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.Projectile; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.ArmorMaterials; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; -import net.minecraft.world.entity.LightningBolt; -import net.minecraft.world.entity.EntityType; -import com.craisinlord.antarchy.content.AntarchyObjects; import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamSettings; import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamTerrainMode; +import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement; import com.craisinlord.antarchy.content.entity.royal.decree.AdvanceDecree; import com.craisinlord.antarchy.content.entity.royal.decree.CloseQuartersDecree; +import com.craisinlord.antarchy.content.entity.royal.decree.ComeNoCloserDecree; +import com.craisinlord.antarchy.content.entity.royal.decree.DoNotRunDecree; +import com.craisinlord.antarchy.content.entity.royal.decree.FightMeCowardDecree; +import com.craisinlord.antarchy.content.entity.royal.decree.HandsOffTheCrownDecree; import com.craisinlord.antarchy.content.entity.royal.decree.KeepYourDistanceDecree; +import com.craisinlord.antarchy.content.entity.royal.decree.KneelDecree; +import com.craisinlord.antarchy.content.entity.royal.decree.NoRespiteDecree; import com.craisinlord.antarchy.content.entity.royal.decree.NoRetreatDecree; import com.craisinlord.antarchy.content.entity.royal.decree.RoyalDecree; +import com.craisinlord.antarchy.content.entity.royal.decree.ShowNoMercyDecree; +import com.craisinlord.antarchy.content.entity.royal.decree.SkyIsMineDecree; +import com.craisinlord.antarchy.content.entity.royal.decree.StandTallDecree; +import com.craisinlord.antarchy.content.entity.royal.decree.StandYourGroundDecree; +import java.util.EnumMap; import java.util.List; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; public class KingEntity extends RoyalBossEntity { + public enum Behavior { + AIRBORNE, SPRINTING, RETREATING, HUGGING, RANGED, KEEPING_FAR + } + + private static final int STOMP_COOLDOWN_TICKS = 220; + private static final int STOMP_WINDUP_TICKS = 18; + private static final double STOMP_RADIUS = 15.0D; + private static final int WING_GUST_COOLDOWN_TICKS = 320; + private static final int WING_GUST_WINDUP_TICKS = 14; + private static final double WING_GUST_RADIUS = 22.0D; + private static final int CHAIN_LIGHTNING_INTERVAL = 12; + private static final int CHAIN_LIGHTNING_JUMPS = 4; + private static final double CHAIN_LIGHTNING_JUMP_RANGE = 9.0D; + private static final int ICE_FREEZE_PER_TICK = 7; + private static final int BEHAVIOR_SCORE_CAP = 12; + @Nullable private Vec3 patrolCenter; private int patrolCooldownTicks; private int decreeCooldownTicks; - private int fireAttackCooldownTicks; - private int lightningAttackCooldownTicks; - private RoyalDecree activeDecree = new AdvanceDecree(); - private static final List DECREES = List.of(new CloseQuartersDecree(), new KeepYourDistanceDecree(), new NoRetreatDecree(), new AdvanceDecree()); + private int activeDecreeTicks; + private int stompCooldownTicks; + private int stompWindupTicks; + private int wingGustCooldownTicks; + private int wingGustWindupTicks; + private boolean decreeRetreatPressure; + private final Map judgmentCooldowns = new HashMap<>(); + private final Map lastPlayerDamageTime = new HashMap<>(); + private final Map iceBuildup = new HashMap<>(); + private final EnumMap behaviorScores = new EnumMap<>(Behavior.class); + @Nullable + private RoyalDecree activeDecree; + private static final List DECREES = List.of( + new SkyIsMineDecree(), new DoNotRunDecree(), new KneelDecree(), new CloseQuartersDecree(), + new ComeNoCloserDecree(), new FightMeCowardDecree(), new NoRespiteDecree(), new NoRetreatDecree(), + new KeepYourDistanceDecree(), new StandTallDecree(), new StandYourGroundDecree(), + new HandsOffTheCrownDecree(), new AdvanceDecree(), new ShowNoMercyDecree()); + public KingEntity(EntityType entityType, Level level) { super(entityType, level); } @@ -80,6 +144,13 @@ public class KingEntity extends RoyalBossEntity { @Override protected SoundEvent royalBeamStartSound() { return AntarchySoundEvents.KING_BEAM_SHOOT.get(); } + @Override + protected SoundEvent royalBeamStartSound(RoyalHead head) { + return head.slot() == RoyalHead.Slot.LEFT + ? AntarchySoundEvents.KING_FIREBALL_SHOOT.get() + : AntarchySoundEvents.KING_BEAM_SHOOT.get(); + } + @Override protected SoundEvent royalBeamLoopSound() { return AntarchySoundEvents.KING_BEAM_SHOOT.get(); } @@ -106,61 +177,362 @@ public class KingEntity extends RoyalBossEntity { } @Override - public void tick() { - super.tick(); - if (!this.level().isClientSide && this.getTarget() != null && this.level() instanceof ServerLevel level) { - this.tickElementalAttacks(level, this.getTarget()); + protected RoyalBeamElement royalBeamElement(@Nullable RoyalHead head) { + if (head == null) { + return RoyalBeamElement.GENERIC; } - if (this.level().isClientSide || this.getTarget() != null || this.isDeadOrDying() - || !(this.level() instanceof ServerLevel)) { - if (!this.level().isClientSide && this.getTarget() != null && this.level() instanceof ServerLevel level) { - this.tickDecree(level, this.getTarget()); - } + return switch (head.slot()) { + case LEFT -> RoyalBeamElement.FIRE; + case CENTER -> RoyalBeamElement.LIGHTNING; + case RIGHT -> RoyalBeamElement.ICE; + }; + } + + @Override + protected void tickRoyalBeamEffects(RoyalHead head, Vec3 start, Vec3 end) { + if (!(this.level() instanceof ServerLevel level)) { return; } - if (this.patrolCenter == null) { + var particle = switch (head.slot()) { + case LEFT -> ParticleTypes.FLAME; + case CENTER -> ParticleTypes.ELECTRIC_SPARK; + case RIGHT -> ParticleTypes.SNOWFLAKE; + }; + Vec3 direction = end.subtract(start); + double distance = direction.length(); + if (distance > 0.001D) { + direction = direction.scale(1.0D / distance); + for (double walked = 0.0D; walked <= distance; walked += 2.5D) { + Vec3 point = start.add(direction.scale(walked)); + level.sendParticles(particle, point.x, point.y, point.z, 2, 0.12D, 0.12D, 0.12D, 0.01D); + } + } + LivingEntity target = head.target(this.level()); + switch (head.slot()) { + case LEFT -> { + if (target != null && target.isAlive()) { + target.setRemainingFireTicks(Math.max(target.getRemainingFireTicks(), 40)); + } + } + case CENTER -> { + if (this.tickCount % CHAIN_LIGHTNING_INTERVAL == 0) { + this.chainLightning(level, end); + } + } + case RIGHT -> { + if (target != null && target.isAlive()) { + this.applyIceFreezePressure(target); + } + } + } + } + + private void chainLightning(ServerLevel level, Vec3 origin) { + java.util.Set struck = new java.util.HashSet<>(); + Vec3 from = origin; + float damage = (float) AntarchySettings.kingBeamDamage() * 0.6F; + for (int jump = 0; jump < CHAIN_LIGHTNING_JUMPS; jump++) { + LivingEntity next = null; + double bestScore = Double.MAX_VALUE; + for (LivingEntity candidate : level.getEntitiesOfClass(LivingEntity.class, + new AABB(from, from).inflate(CHAIN_LIGHTNING_JUMP_RANGE), + e -> e.isAlive() && !(e instanceof RoyalBossEntity) && e.getType() != this.getType())) { + if (struck.contains(candidate.getUUID())) { + continue; + } + double score = candidate.position().distanceToSqr(from) - (isConductive(candidate) ? 16.0D : 0.0D); + if (score < bestScore) { + bestScore = score; + next = candidate; + } + } + if (next == null) { + break; + } + struck.add(next.getUUID()); + LightningBolt bolt = EntityType.LIGHTNING_BOLT.create(level); + if (bolt != null) { + bolt.moveTo(next.getX(), next.getY(), next.getZ()); + bolt.setVisualOnly(true); + level.addFreshEntity(bolt); + } + next.hurt(this.damageSources().lightningBolt(), damage); + from = next.position().add(0.0D, next.getBbHeight() * 0.5D, 0.0D); + if (isConductive(next)) { + jump--; + } + } + } + + private static boolean isConductive(LivingEntity entity) { + for (ItemStack stack : entity.getArmorSlots()) { + if (stack.getItem() instanceof ArmorItem armor) { + var material = armor.getMaterial(); + if (material == ArmorMaterials.IRON || material == ArmorMaterials.NETHERITE || material == ArmorMaterials.CHAIN) { + return true; + } + } + } + return false; + } + + private void applyIceFreezePressure(LivingEntity target) { + int buildup = this.iceBuildup.merge(target.getUUID(), ICE_FREEZE_PER_TICK, Integer::sum); + target.setTicksFrozen(Math.min(target.getTicksRequiredToFreeze() + 60, target.getTicksFrozen() + ICE_FREEZE_PER_TICK * 2)); + if (buildup >= 60) { + target.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 40, 3, false, true)); + this.iceBuildup.put(target.getUUID(), 20); + } + } + + @Override + public void tick() { + super.tick(); + if (this.level().isClientSide) { + return; + } + if (this.iceBuildup.size() > 16) { + this.iceBuildup.clear(); + } + LivingEntity target = this.getTarget(); + if (target != null && !this.isDeadOrDying() && this.level() instanceof ServerLevel level) { + this.trackBehavior(target); + this.tickDecree(level, target); + this.tickKingWholeBody(level, target); + return; + } + + if (this.isDeadOrDying() || !(this.level() instanceof ServerLevel)) { + return; + } + this.decreeRetreatPressure = false; + if (this.patrolCenter == null || this.position().distanceToSqr(this.patrolCenter) > 64.0D * 64.0D) { this.patrolCenter = this.position(); } if (this.patrolCooldownTicks-- <= 0) { this.patrolCooldownTicks = 100 + this.random.nextInt(100); + this.playSound(AntarchySoundEvents.KING_WING_FLAP.get(), 2.0F, 0.9F + this.random.nextFloat() * 0.15F); double angle = this.random.nextDouble() * Math.PI * 2.0D; double radius = 12.0D + this.random.nextDouble() * 18.0D; - this.getMoveControl().setWantedPosition(this.patrolCenter.x + Math.cos(angle) * radius, - this.patrolCenter.y + 6.0D + this.random.nextDouble() * 12.0D, - this.patrolCenter.z + Math.sin(angle) * radius, 1.0D); + double px = this.patrolCenter.x + Math.cos(angle) * radius; + double pz = this.patrolCenter.z + Math.sin(angle) * radius; + double py = this.groundYBelow(px, pz) + FLYING_PREFERRED_HOVER + this.random.nextDouble() * 5.0D; + this.getMoveControl().setWantedPosition(px, py, pz, 1.0D); } } - private void tickDecree(ServerLevel level, net.minecraft.world.entity.LivingEntity target) { - if (this.decreeCooldownTicks-- <= 0) { - this.decreeCooldownTicks = 220; - this.activeDecree = DECREES.get(this.random.nextInt(DECREES.size())); - this.playSound(AntarchySoundEvents.KING_DECREE_CAST.get(), 3.0F, 0.9F + this.random.nextFloat() * 0.15F); + private void trackBehavior(LivingEntity target) { + double distance = target.distanceTo(this); + this.bumpBehavior(Behavior.AIRBORNE, !target.onGround() && !target.isPassenger() ? 1 : -1); + this.bumpBehavior(Behavior.SPRINTING, target.isSprinting() ? 1 : -1); + this.bumpBehavior(Behavior.HUGGING, distance <= 10.0D ? 1 : -1); + this.bumpBehavior(Behavior.KEEPING_FAR, distance >= 22.0D ? 1 : -1); + if (this.patrolCenter != null) { + this.bumpBehavior(Behavior.RETREATING, distance > 20.0D && target.getDeltaMovement().horizontalDistanceSqr() > 0.02D + && target.position().subtract(this.position()).dot(target.getDeltaMovement()) > 0.0D ? 1 : -1); } - this.activeDecree.apply(level, this, target); } - private void tickElementalAttacks(ServerLevel level, net.minecraft.world.entity.LivingEntity target) { - if (this.fireAttackCooldownTicks-- <= 0) { - this.fireAttackCooldownTicks = 110; - Vec3 start = this.position().add(0.0D, 5.0D, 0.0D); - RoyalBoltEntity bolt = new RoyalBoltEntity(AntarchyObjects.ROYAL_BOLT.get(), level); - bolt.setOwner(this); - bolt.setPos(start); - Vec3 delta = target.getEyePosition().subtract(start); - bolt.shoot(delta.x, delta.y, delta.z, 1.15F, 0.0F); - level.addFreshEntity(bolt); - this.playSound(AntarchySoundEvents.KING_FIREBALL_SHOOT.get(), 3.0F, 1.0F); - } - if (this.lightningAttackCooldownTicks-- <= 0) { - this.lightningAttackCooldownTicks = 150; - for (net.minecraft.world.entity.LivingEntity living : level.getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, - target.getBoundingBox().inflate(5.0D), entity -> entity.isAlive() && entity != this)) { - LightningBolt bolt = EntityType.LIGHTNING_BOLT.create(level); - if (bolt == null) continue; - bolt.moveTo(living.getX(), living.getY(), living.getZ()); - level.addFreshEntity(bolt); + private void bumpBehavior(Behavior behavior, int delta) { + int updated = Math.max(0, Math.min(BEHAVIOR_SCORE_CAP, this.behaviorScores.getOrDefault(behavior, 0) + delta)); + this.behaviorScores.put(behavior, updated); + } + + public int behaviorScore(Behavior behavior) { + return this.behaviorScores.getOrDefault(behavior, 0); + } + + public void setDecreeRetreatPressure(boolean value) { + this.decreeRetreatPressure = value; + } + + private void tickKingWholeBody(ServerLevel level, LivingEntity target) { + if (this.stompCooldownTicks > 0) this.stompCooldownTicks--; + if (this.wingGustCooldownTicks > 0) this.wingGustCooldownTicks--; + + boolean skyIsMine = this.activeDecree instanceof SkyIsMineDecree; + boolean forceFar = this.decreeRetreatPressure + || this.activeDecree instanceof ComeNoCloserDecree + || this.activeDecree instanceof KeepYourDistanceDecree; + + if (this.stompWindupTicks > 0) { + if (--this.stompWindupTicks == 0) { + this.performStomp(level, target); + } + } else if (this.wingGustWindupTicks > 0) { + if (--this.wingGustWindupTicks == 0) { + this.performWingGust(level, target); + } + } else { + double distance = target.distanceTo(this); + if (this.stompCooldownTicks <= 0 && (distance <= STOMP_RADIUS || skyIsMine)) { + this.stompCooldownTicks = skyIsMine ? STOMP_COOLDOWN_TICKS / 2 : STOMP_COOLDOWN_TICKS; + this.stompWindupTicks = STOMP_WINDUP_TICKS; + this.triggerAnim("body_action", "stomp"); + this.playSound(AntarchySoundEvents.KING_ROAR.get(), 3.0F, 0.7F); + if (skyIsMine) { + this.getMoveControl().setWantedPosition(this.getX(), target.getY(), this.getZ(), 1.2D); + } + } else if (this.wingGustCooldownTicks <= 0 && distance <= WING_GUST_RADIUS && (forceFar || this.random.nextInt(3) == 0)) { + this.wingGustCooldownTicks = WING_GUST_COOLDOWN_TICKS; + this.wingGustWindupTicks = WING_GUST_WINDUP_TICKS; + this.triggerAnim("body_action", "wing_gust"); + this.playSound(AntarchySoundEvents.KING_WING_FLAP.get(), 3.0F, 0.85F); } } + + if (forceFar && target.distanceTo(this) < 18.0D) { + Vec3 away = this.position().subtract(target.position()).normalize().scale(24.0D); + double ax = this.getX() + away.x; + double az = this.getZ() + away.z; + double ay = this.groundYBelow(ax, az) + FLYING_PREFERRED_HOVER + 6.0D; + this.getMoveControl().setWantedPosition(ax, ay, az, 1.3D); + } + } + + private void performStomp(ServerLevel level, LivingEntity target) { + DamageSource source = this.damageSources().mobAttack(this); + float base = (float) this.getAttributeValue(Attributes.ATTACK_DAMAGE) * 1.4F; + for (LivingEntity living : level.getEntitiesOfClass(LivingEntity.class, + this.getBoundingBox().inflate(STOMP_RADIUS), + e -> e.isAlive() && e instanceof Player)) { + double distance = Math.max(1.0D, living.distanceTo(this)); + float falloff = (float) Math.max(0.2D, 1.0D - distance / (STOMP_RADIUS + 6.0D)); + living.hurt(source, base * falloff); + Vec3 push = living.position().subtract(this.position()).normalize().scale(2.4D * falloff); + living.setDeltaMovement(living.getDeltaMovement().add(push.x, 0.85D, push.z)); + living.hasImpulse = true; + } + RoyalBlockDestruction.destroySphere(level, this, + new Vec3(this.getX(), this.getY(), this.getZ()), STOMP_RADIUS * 0.5D, 96, 80.0D, 0.15F); + level.sendParticles(ParticleTypes.EXPLOSION_EMITTER, this.getX(), this.getY(), this.getZ(), 6, 4.0D, 0.5D, 4.0D, 0.0D); + this.playSound(AntarchySoundEvents.KING_STOMP.get(), 3.5F, 0.8F); + } + + private void performWingGust(ServerLevel level, LivingEntity target) { + Vec3 flat = this.getForward().multiply(1.0D, 0.0D, 1.0D); + Vec3 forward = flat.lengthSqr() < 1.0E-4D + ? target.position().subtract(this.position()).multiply(1.0D, 0.0D, 1.0D).normalize() + : flat.normalize(); + for (LivingEntity living : level.getEntitiesOfClass(LivingEntity.class, + this.getBoundingBox().inflate(WING_GUST_RADIUS), + e -> e.isAlive() && e instanceof Player)) { + Vec3 toTarget = living.position().subtract(this.position()).multiply(1.0D, 0.0D, 1.0D); + if (toTarget.lengthSqr() < 1.0E-4D || forward.dot(toTarget.normalize()) < 0.1D) { + continue; + } + Vec3 push = toTarget.normalize().scale(3.2D); + living.setDeltaMovement(living.getDeltaMovement().add(push.x, 0.5D, push.z)); + living.hasImpulse = true; + living.hurt(this.damageSources().mobAttack(this), 6.0F); + } + level.sendParticles(ParticleTypes.SWEEP_ATTACK, this.getX() + forward.x * 6.0D, this.getY() + 4.0D, this.getZ() + forward.z * 6.0D, 12, 4.0D, 2.0D, 4.0D, 0.0D); + } + + private void tickDecree(ServerLevel level, LivingEntity target) { + if (this.activeDecree == null) { + if (this.decreeCooldownTicks-- > 0) { + return; + } + this.activeDecreeTicks = 300; + this.activeDecree = this.pickDecree(target); + this.decreeRetreatPressure = false; + this.playSound(AntarchySoundEvents.KING_DECREE_CAST.get(), 3.0F, 0.9F + this.random.nextFloat() * 0.15F); + this.playSound(AntarchySoundEvents.KING_ROAR.get(), 3.0F, 0.8F + this.random.nextFloat() * 0.12F); + if (target instanceof ServerPlayer player) { + player.connection.send(new ClientboundSetTitlesAnimationPacket(5, 300, 10)); + player.connection.send(new ClientboundSetTitleTextPacket(Component.translatable(this.activeDecree.translationKey()) + .withStyle(style -> style.withColor(ChatFormatting.GOLD).withBold(true)))); + player.connection.send(new ClientboundSetSubtitleTextPacket(Component.translatable(this.activeDecree.instructionKey()) + .withStyle(style -> style.withColor(ChatFormatting.WHITE)))); + } + } + int countdown = this.activeDecree.countdownTicks(target); + if (countdown > 0 && countdown <= 100 && this.tickCount % 20 == 0) { + level.playSound(null, target.blockPosition(), SoundEvents.BELL_BLOCK, SoundSource.HOSTILE, 0.8F, 1.0F + countdown / 500.0F); + } + this.activeDecree.apply(level, this, target); + if (this.activeDecree != null && --this.activeDecreeTicks <= 0) { + this.endDecree(target); + } + } + + private RoyalDecree pickDecree(LivingEntity target) { + int totalWeight = 0; + int[] weights = new int[DECREES.size()]; + for (int i = 0; i < DECREES.size(); i++) { + weights[i] = Math.max(1, DECREES.get(i).contextWeight(this, target)); + totalWeight += weights[i]; + } + int roll = this.random.nextInt(totalWeight); + for (int i = 0; i < DECREES.size(); i++) { + roll -= weights[i]; + if (roll < 0) { + return DECREES.get(i); + } + } + return DECREES.get(this.random.nextInt(DECREES.size())); + } + + private void endDecree(@Nullable LivingEntity target) { + if (target instanceof ServerPlayer player) { + player.connection.send(new ClientboundClearTitlesPacket(false)); + } + if (this.activeDecree != null) { + this.activeDecree.onEnded(); + } + this.activeDecree = null; + this.activeDecreeTicks = 0; + this.decreeRetreatPressure = false; + this.decreeCooldownTicks = AntarchySettings.royalDecreeCooldownTicks(); + } + + public void clearActiveDecree() { + this.clearActiveDecree(null); + } + + public void clearActiveDecree(@Nullable LivingEntity target) { + this.endDecree(target); + } + + public boolean blocksHealing() { + return this.activeDecree instanceof NoRespiteDecree; + } + + public long ticksSincePlayerDamage(LivingEntity target) { + long last = this.lastPlayerDamageTime.getOrDefault(target.getUUID(), 0L); + return this.level().getGameTime() - last; + } + + public void invokeJudgment(LivingEntity target) { + if (target == null || !target.isAlive()) return; + long now = this.level().getGameTime(); + if (this.judgmentCooldowns.getOrDefault(target.getUUID(), 0L) <= now) { + this.judgmentCooldowns.put(target.getUUID(), now + 20L); + target.hurt(this.damageSources().magic(), 6.0F); + } + } + + @Override + public boolean hurt(DamageSource source, float amount) { + if (!this.level().isClientSide && source.getEntity() instanceof LivingEntity attacker) { + this.lastPlayerDamageTime.put(attacker.getUUID(), this.level().getGameTime()); + boolean projectile = source.getDirectEntity() instanceof Projectile; + this.bumpBehavior(projectile ? Behavior.RANGED : Behavior.HUGGING, 2); + if (this.activeDecree instanceof CloseQuartersDecree && projectile) { + this.invokeJudgment(attacker); + } else if (this.activeDecree instanceof ComeNoCloserDecree && !projectile) { + this.invokeJudgment(attacker); + } else if (this.activeDecree instanceof HandsOffTheCrownDecree) { + this.invokeJudgment(attacker); + } + } + return super.hurt(source, amount); + } + + public static boolean blocksHealingAround(LivingEntity target) { + if (target.level().isClientSide) return false; + return target.level().getEntitiesOfClass(KingEntity.class, target.getBoundingBox().inflate(128.0D), + king -> king.isAlive() && king.blocksHealing()).stream().findFirst().isPresent(); } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/PrinceEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/PrinceEntity.java index 75a340bb..6464b270 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/PrinceEntity.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/PrinceEntity.java @@ -1,9 +1,12 @@ package com.craisinlord.antarchy.content.entity.royal; +import com.craisinlord.antarchy.config.AntarchySettings; import com.craisinlord.antarchy.content.AntarchyObjects; +import com.craisinlord.antarchy.content.AntarchySoundEvents; +import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement; +import net.minecraft.sounds.SoundEvent; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; -import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.level.Level; public class PrinceEntity extends RoyalMountEntity { @@ -12,9 +15,20 @@ public class PrinceEntity extends RoyalMountEntity { } public static AttributeSupplier.Builder createAttributes() { - return RoyalMountEntity.createBaseAttributes() - .add(Attributes.MAX_HEALTH, 120.0D) - .add(Attributes.ATTACK_DAMAGE, 14.0D); + return RoyalMountEntity.createBaseAttributes( + AntarchySettings.princeHealth(), AntarchySettings.princeAttackDamage(), + AntarchySettings.princeMovementSpeed(), AntarchySettings.princeFlyingSpeed(), + AntarchySettings.princeArmor(), AntarchySettings.princeKnockbackResistance(), + AntarchySettings.princeFollowRange()); + } + + @Override + protected RoyalBeamElement boltElement(int lateralIndex) { + return switch (lateralIndex) { + case -1 -> RoyalBeamElement.FIRE; + case 1 -> RoyalBeamElement.ICE; + default -> RoyalBeamElement.LIGHTNING; + }; } @Override @@ -26,4 +40,29 @@ public class PrinceEntity extends RoyalMountEntity { protected EntityType boltType() { return AntarchyObjects.ROYAL_BOLT.get(); } + + @Override + protected SoundEvent idleSound() { + return AntarchySoundEvents.PRINCE_IDLE.get(); + } + + @Override + protected SoundEvent biteSound() { + return AntarchySoundEvents.PRINCE_BITE.get(); + } + + @Override + protected SoundEvent shootSound() { + return AntarchySoundEvents.PRINCE_SHOOT.get(); + } + + @Override + protected SoundEvent flySound() { + return AntarchySoundEvents.PRINCE_FLY.get(); + } + + @Override + protected SoundEvent stepSound() { + return AntarchySoundEvents.PRINCE_STEP.get(); + } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/PrincessEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/PrincessEntity.java index 6c84aeca..8dafbac9 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/PrincessEntity.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/PrincessEntity.java @@ -1,9 +1,11 @@ package com.craisinlord.antarchy.content.entity.royal; +import com.craisinlord.antarchy.config.AntarchySettings; import com.craisinlord.antarchy.content.AntarchyObjects; +import com.craisinlord.antarchy.content.AntarchySoundEvents; +import net.minecraft.sounds.SoundEvent; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; -import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.level.Level; public class PrincessEntity extends RoyalMountEntity { @@ -12,10 +14,11 @@ public class PrincessEntity extends RoyalMountEntity { } public static AttributeSupplier.Builder createAttributes() { - return RoyalMountEntity.createBaseAttributes() - .add(Attributes.MAX_HEALTH, 110.0D) - .add(Attributes.ATTACK_DAMAGE, 10.0D) - .add(Attributes.FLYING_SPEED, 0.95D); + return RoyalMountEntity.createBaseAttributes( + AntarchySettings.princessHealth(), AntarchySettings.princessAttackDamage(), + AntarchySettings.princessMovementSpeed(), AntarchySettings.princessFlyingSpeed(), + AntarchySettings.princessArmor(), AntarchySettings.princessKnockbackResistance(), + AntarchySettings.princessFollowRange()); } @Override @@ -27,4 +30,29 @@ public class PrincessEntity extends RoyalMountEntity { protected EntityType boltType() { return AntarchyObjects.ROYAL_BOLT.get(); } + + @Override + protected SoundEvent idleSound() { + return AntarchySoundEvents.PRINCESS_IDLE.get(); + } + + @Override + protected SoundEvent biteSound() { + return AntarchySoundEvents.PRINCESS_BITE.get(); + } + + @Override + protected SoundEvent shootSound() { + return AntarchySoundEvents.PRINCESS_SHOOT.get(); + } + + @Override + protected SoundEvent flySound() { + return AntarchySoundEvents.PRINCESS_FLY.get(); + } + + @Override + protected SoundEvent stepSound() { + return AntarchySoundEvents.PRINCESS_STEP.get(); + } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/QueenEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/QueenEntity.java index 1a682234..c1fc60d1 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/QueenEntity.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/QueenEntity.java @@ -3,16 +3,28 @@ package com.craisinlord.antarchy.content.entity.royal; import com.craisinlord.antarchy.config.AntarchySettings; import com.craisinlord.antarchy.content.AntarchySoundEvents; import com.craisinlord.antarchy.content.AntarchyObjects; +import com.craisinlord.antarchy.content.AntarchyTags; import com.craisinlord.antarchy.content.entity.ManticoreEntity; +import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.DustParticleOptions; +import net.minecraft.core.particles.ParticleTypes; import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvent; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.BossEvent; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +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.MobSpawnType; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; @@ -22,15 +34,41 @@ import com.craisinlord.antarchy.content.entity.portal.DimensionalTearEntity; import com.craisinlord.antarchy.content.time.TimeDilationApi; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.phys.AABB; public class QueenEntity extends RoyalBossEntity { private static final String SUMMON_COOLDOWN_KEY = "ManticoreSummonCooldownTicks"; private static final int FAILED_SUMMON_RETRY_TICKS = 20; private static final int POSITION_ATTEMPTS_PER_MANTICORE = 8; + + private static final ResourceLocation ACCEL_SPEED_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "queen_royal_acceleration_speed"); + private static final ResourceLocation ACCEL_FLY_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "queen_royal_acceleration_fly"); + private static final DustParticleOptions ACCEL_DUST = new DustParticleOptions(new org.joml.Vector3f(1.0F, 0.15F, 0.15F), 2.0F); + + private static final int GRAVITY_STOMP_COOLDOWN = 180; + private static final int TIME_FIELD_COOLDOWN = 260; + private static final int MOMENTUM_LOCK_COOLDOWN = 420; + private static final int MOMENTUM_LOCK_DURATION = 90; + private static final double MOMENTUM_LOCK_RADIUS = 26.0D; + private static final int CRUSHING_GRAVITY_COOLDOWN = 360; + private static final int CRUSHING_GRAVITY_DURATION = 120; + private static final double CRUSHING_GRAVITY_RADIUS = 18.0D; + private static final double CRUSHING_GRAVITY_STRENGTH = 0.12D; + private static final int ACCELERATION_COOLDOWN = 500; + private static final int ACCELERATION_DURATION = 140; + private static final int BLACK_HOLE_COOLDOWN = 340; + private int manticoreSummonCooldownTicks; private int gravityStompCooldownTicks; private int timeFieldCooldownTicks; + private int momentumLockCooldownTicks; + private int momentumLockTicks; + private int crushingGravityCooldownTicks; + private int crushingGravityTicks; + private int accelerationCooldownTicks; + private int accelerationTicks; + private int blackHoleCooldownTicks; + private int idleWanderCooldownTicks; + private final Map frozenVelocities = new HashMap<>(); public QueenEntity(EntityType entityType, Level level) { super(entityType, level); @@ -101,14 +139,42 @@ public class QueenEntity extends RoyalBossEntity { return RoyalBeamTerrainMode.DESTROY; } + public static boolean isFieldImmune(Entity entity) { + return entity instanceof RoyalBossEntity + || entity.getType().is(AntarchyTags.Entities.TIME_DILATION_IMMUNE); + } + @Override public void tick() { super.tick(); if (this.level().isClientSide || this.isDeadOrDying()) { return; } + LivingEntity target = this.getTarget(); + if (target == null || !target.isAlive() || !this.canAttack(target)) { + this.tickIdleWander(); + } this.tickManticoreSummon(); - this.tickGravityAttacks(); + this.tickQueenAbilities(); + this.tickRoyalAcceleration(); + this.tickMomentumLock(); + this.tickCrushingGravity(); + } + + private void tickIdleWander() { + if (this.idleWanderCooldownTicks-- > 0) { + return; + } + this.idleWanderCooldownTicks = 80 + this.random.nextInt(80); + double angle = this.random.nextDouble() * Mth.TWO_PI; + double radius = 6.0D + this.random.nextDouble() * 14.0D; + double wx = this.getX() + Math.cos(angle) * radius; + double wz = this.getZ() + Math.sin(angle) * radius; + this.getMoveControl().setWantedPosition(wx, this.groundYBelow(wx, wz), wz, 0.7D); + } + + private int cooldown(int base) { + return this.accelerationTicks > 0 ? Math.max(20, base / 2) : base; } private void tickManticoreSummon() { @@ -116,11 +182,10 @@ public class QueenEntity extends RoyalBossEntity { this.manticoreSummonCooldownTicks--; return; } - if (!(this.level() instanceof ServerLevel serverLevel)) { return; } - net.minecraft.world.entity.LivingEntity target = this.getTarget(); + LivingEntity target = this.getTarget(); if (target == null || !target.isAlive() || !this.canAttack(target)) { return; } @@ -136,19 +201,17 @@ public class QueenEntity extends RoyalBossEntity { int spawned = this.spawnManticoreTears(serverLevel, target, summonCount); this.manticoreSummonCooldownTicks = spawned > 0 - ? Math.max(20, AntarchySettings.queenManticoreSummonCooldownTicks()) + ? this.cooldown(Math.max(20, AntarchySettings.queenManticoreSummonCooldownTicks())) : FAILED_SUMMON_RETRY_TICKS; if (spawned > 0) { this.triggerAnim("body_action", "minion_spawn"); this.playSound(AntarchySoundEvents.QUEEN_ROAR.get(), 3.0F, 0.8F + this.random.nextFloat() * 0.12F); - serverLevel.sendParticles( - net.minecraft.core.particles.ParticleTypes.PORTAL, - this.getX(), this.getY() + 2.0D, this.getZ(), + serverLevel.sendParticles(ParticleTypes.PORTAL, this.getX(), this.getY() + 2.0D, this.getZ(), 36, 3.0D, 2.0D, 3.0D, 0.15D); } } - private int spawnManticoreTears(ServerLevel level, net.minecraft.world.entity.LivingEntity target, int count) { + private int spawnManticoreTears(ServerLevel level, LivingEntity target, int count) { int pairs = Math.max(1, Math.min(3, (count + 1) / 2)); int created = 0; for (int i = 0; i < pairs; i++) { @@ -169,38 +232,193 @@ public class QueenEntity extends RoyalBossEntity { return created; } - private void tickGravityAttacks() { - if (this.gravityStompCooldownTicks > 0) { - this.gravityStompCooldownTicks--; - } - if (this.timeFieldCooldownTicks > 0) { - this.timeFieldCooldownTicks--; - } + private void tickQueenAbilities() { + if (this.gravityStompCooldownTicks > 0) this.gravityStompCooldownTicks--; + if (this.timeFieldCooldownTicks > 0) this.timeFieldCooldownTicks--; + if (this.momentumLockCooldownTicks > 0) this.momentumLockCooldownTicks--; + if (this.crushingGravityCooldownTicks > 0) this.crushingGravityCooldownTicks--; + if (this.accelerationCooldownTicks > 0) this.accelerationCooldownTicks--; + if (this.blackHoleCooldownTicks > 0) this.blackHoleCooldownTicks--; + if (!(this.level() instanceof ServerLevel level)) { return; } - net.minecraft.world.entity.LivingEntity target = this.getTarget(); + LivingEntity target = this.getTarget(); if (target == null || !target.isAlive()) { return; } - if (this.gravityStompCooldownTicks <= 0) { - this.gravityStompCooldownTicks = 180; - this.triggerAnim("body_action", "stomp"); - this.playSound(AntarchySoundEvents.QUEEN_ROAR.get(), 3.0F, 0.7F); - DamageSource source = this.damageSources().mobAttack(this); - for (net.minecraft.world.entity.LivingEntity living : level.getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, - this.getBoundingBox().inflate(18.0D), entity -> entity instanceof Player && entity.isAlive())) { - double distance = Math.max(1.0D, living.distanceTo(this)); - living.hurt(source, (float) (12.0D * Math.max(0.25D, 1.0D - distance / 24.0D))); - Vec3 push = living.position().subtract(this.position()).normalize().scale(1.3D); - living.setDeltaMovement(living.getDeltaMovement().add(push.x, 0.65D, push.z)); - living.hasImpulse = true; + + Phase phase = this.phase(); + boolean majorBusy = this.momentumLockTicks > 0 || this.crushingGravityTicks > 0; + boolean allowOverlap = phase != Phase.ONE; + + if (this.gravityStompCooldownTicks <= 0 && (allowOverlap || !majorBusy)) { + this.gravityStompCooldownTicks = this.cooldown(GRAVITY_STOMP_COOLDOWN); + this.performGravityStomp(level, target); + } + if (this.timeFieldCooldownTicks <= 0 && (allowOverlap || !majorBusy)) { + this.timeFieldCooldownTicks = this.cooldown(TIME_FIELD_COOLDOWN); + double fieldRate = phase == Phase.THREE ? 0.1D : 0.4D; + TimeDilationApi.createField(level, target.position(), 12.0D, fieldRate, 140 + phase.ordinal() * 40); + this.triggerAnim("body_action", "wing_gust"); + } + if (this.blackHoleCooldownTicks <= 0 && (allowOverlap || !majorBusy)) { + this.blackHoleCooldownTicks = this.cooldown(BLACK_HOLE_COOLDOWN); + this.castBlackHole(level, target); + } + if (this.momentumLockTicks <= 0 && this.momentumLockCooldownTicks <= 0 && (allowOverlap || !majorBusy)) { + this.startMomentumLock(level); + } + if (this.crushingGravityTicks <= 0 && this.crushingGravityCooldownTicks <= 0 && phase != Phase.ONE) { + this.crushingGravityCooldownTicks = CRUSHING_GRAVITY_COOLDOWN; + this.crushingGravityTicks = CRUSHING_GRAVITY_DURATION; + this.playSound(AntarchySoundEvents.QUEEN_ROAR.get(), 3.0F, 0.6F); + } + if (this.accelerationTicks <= 0 && this.accelerationCooldownTicks <= 0 + && (phase == Phase.THREE || (phase == Phase.TWO && this.random.nextInt(3) == 0))) { + this.startRoyalAcceleration(); + } + } + + private void performGravityStomp(ServerLevel level, LivingEntity target) { + this.triggerAnim("body_action", "stomp"); + this.playSound(AntarchySoundEvents.QUEEN_ROAR.get(), 3.0F, 0.7F); + DamageSource source = this.damageSources().mobAttack(this); + for (LivingEntity living : level.getEntitiesOfClass(LivingEntity.class, + this.getBoundingBox().inflate(18.0D), entity -> entity instanceof Player && entity.isAlive())) { + double distance = Math.max(1.0D, living.distanceTo(this)); + living.hurt(source, (float) (12.0D * Math.max(0.25D, 1.0D - distance / 24.0D))); + Vec3 push = living.position().subtract(this.position()).normalize().scale(1.3D); + living.setDeltaMovement(living.getDeltaMovement().add(push.x, 0.65D, push.z)); + living.hasImpulse = true; + } + level.sendParticles(ParticleTypes.SONIC_BOOM, this.getX(), this.getY() + 1.0D, this.getZ(), 4, 2.0D, 0.5D, 2.0D, 0.0D); + } + + private void castBlackHole(ServerLevel level, LivingEntity target) { + Vec3 anchor = target.position().add( + (this.random.nextDouble() - 0.5D) * 4.0D, + 2.0D + this.random.nextDouble() * 2.0D, + (this.random.nextDouble() - 0.5D) * 4.0D); + RoyalBlackHoleEntity hole = RoyalBlackHoleEntity.create(level, anchor, this.getUUID()); + level.addFreshEntity(hole); + this.triggerAnim("body_action", "wing_gust"); + this.playSound(AntarchySoundEvents.QUEEN_ROAR.get(), 3.0F, 1.15F); + level.sendParticles(ParticleTypes.REVERSE_PORTAL, anchor.x, anchor.y, anchor.z, 60, 1.0D, 1.0D, 1.0D, 0.4D); + } + + private void startMomentumLock(ServerLevel level) { + this.momentumLockCooldownTicks = MOMENTUM_LOCK_COOLDOWN; + this.momentumLockTicks = MOMENTUM_LOCK_DURATION; + this.frozenVelocities.clear(); + this.triggerAnim("body_action", "wing_gust"); + this.playSound(AntarchySoundEvents.QUEEN_ROAR.get(), 3.0F, 0.5F); + for (Entity entity : level.getEntitiesOfClass(Entity.class, + this.getBoundingBox().inflate(MOMENTUM_LOCK_RADIUS))) { + if (entity == this || isFieldImmune(entity) || entity instanceof Player player && player.isCreative()) { + continue; + } + this.frozenVelocities.put(entity.getUUID(), entity.getDeltaMovement()); + } + } + + private void tickMomentumLock() { + if (this.momentumLockTicks <= 0) { + return; + } + this.momentumLockTicks--; + if (!(this.level() instanceof ServerLevel level)) { + return; + } + for (Map.Entry entry : this.frozenVelocities.entrySet()) { + Entity entity = level.getEntity(entry.getKey()); + if (entity == null || !entity.isAlive()) { + continue; + } + if (this.momentumLockTicks <= 0) { + entity.setDeltaMovement(entry.getValue()); + entity.hasImpulse = true; + } else { + entity.setDeltaMovement(Vec3.ZERO); + entity.fallDistance = 0.0F; + entity.hasImpulse = true; + if (this.tickCount % 6 == 0 && level instanceof ServerLevel serverLevel) { + serverLevel.sendParticles(ParticleTypes.END_ROD, entity.getX(), entity.getY() + entity.getBbHeight() * 0.5D, entity.getZ(), + 2, 0.2D, 0.2D, 0.2D, 0.0D); + } } } - if (this.timeFieldCooldownTicks <= 0) { - this.timeFieldCooldownTicks = 260; - TimeDilationApi.createField(level, target.position(), 12.0D, 0.45D, 140); - this.triggerAnim("body_action", "wing_gust"); + if (this.momentumLockTicks <= 0) { + this.frozenVelocities.clear(); + } + } + + private void tickCrushingGravity() { + if (this.crushingGravityTicks <= 0) { + return; + } + this.crushingGravityTicks--; + if (!(this.level() instanceof ServerLevel level)) { + return; + } + for (Entity entity : level.getEntitiesOfClass(Entity.class, + this.getBoundingBox().inflate(CRUSHING_GRAVITY_RADIUS))) { + if (entity == this || isFieldImmune(entity) || entity instanceof Player player && player.isCreative()) { + continue; + } + double downSign = AntarchyGravityApi.isGravityInverted(entity) ? 1.0D : -1.0D; + entity.setDeltaMovement(entity.getDeltaMovement().add(0.0D, downSign * CRUSHING_GRAVITY_STRENGTH, 0.0D)); + entity.hasImpulse = true; + } + if (this.tickCount % 8 == 0) { + level.sendParticles(ACCEL_DUST, this.getX(), this.getY() + 1.0D, this.getZ(), 20, + CRUSHING_GRAVITY_RADIUS * 0.5D, 1.0D, CRUSHING_GRAVITY_RADIUS * 0.5D, 0.0D); + } + } + + private void startRoyalAcceleration() { + this.accelerationCooldownTicks = ACCELERATION_COOLDOWN; + this.accelerationTicks = ACCELERATION_DURATION; + this.setRoyalAccelerated(true); + this.playSound(AntarchySoundEvents.QUEEN_ROAR.get(), 3.5F, 1.4F); + applyAccelModifier(this.getAttribute(Attributes.MOVEMENT_SPEED), ACCEL_SPEED_ID); + applyAccelModifier(this.getAttribute(Attributes.FLYING_SPEED), ACCEL_FLY_ID); + } + + private static void applyAccelModifier(AttributeInstance attribute, ResourceLocation id) { + if (attribute == null || attribute.getModifier(id) != null) { + return; + } + attribute.addTransientModifier(new AttributeModifier(id, 0.9D, AttributeModifier.Operation.ADD_MULTIPLIED_BASE)); + } + + private static void removeAccelModifier(AttributeInstance attribute, ResourceLocation id) { + if (attribute != null) { + attribute.removeModifier(id); + } + } + + private void tickRoyalAcceleration() { + if (this.accelerationTicks <= 0) { + if (this.isRoyalAccelerated()) { + this.setRoyalAccelerated(false); + removeAccelModifier(this.getAttribute(Attributes.MOVEMENT_SPEED), ACCEL_SPEED_ID); + removeAccelModifier(this.getAttribute(Attributes.FLYING_SPEED), ACCEL_FLY_ID); + } + return; + } + this.accelerationTicks--; + if (this.level() instanceof ServerLevel level && this.tickCount % 2 == 0) { + level.sendParticles(ACCEL_DUST, + this.getX() + (this.random.nextDouble() - 0.5D) * this.getBbWidth(), + this.getY() + this.random.nextDouble() * this.getBbHeight(), + this.getZ() + (this.random.nextDouble() - 0.5D) * this.getBbWidth(), + 6, 0.4D, 0.6D, 0.4D, 0.02D); + } + if (this.accelerationTicks <= 0) { + this.setRoyalAccelerated(false); + removeAccelModifier(this.getAttribute(Attributes.MOVEMENT_SPEED), ACCEL_SPEED_ID); + removeAccelModifier(this.getAttribute(Attributes.FLYING_SPEED), ACCEL_FLY_ID); } } @@ -209,10 +427,12 @@ public class QueenEntity extends RoyalBossEntity { if (!this.level().isClientSide && this.level() instanceof ServerLevel level) { DimensionalTearEntity.discardQueenOwnedTears(level, this.getUUID()); } + removeAccelModifier(this.getAttribute(Attributes.MOVEMENT_SPEED), ACCEL_SPEED_ID); + removeAccelModifier(this.getAttribute(Attributes.FLYING_SPEED), ACCEL_FLY_ID); super.die(damageSource); } - private boolean spawnManticore(ServerLevel serverLevel, net.minecraft.world.entity.LivingEntity target) { + private boolean spawnManticore(ServerLevel serverLevel, LivingEntity target) { double minimumDistance = Math.max(4.0D, this.getBbWidth() * 0.55D); double maximumDistance = Math.max(minimumDistance + 1.0D, AntarchySettings.queenManticoreSummonRange()); for (int attempt = 0; attempt < POSITION_ATTEMPTS_PER_MANTICORE; attempt++) { @@ -248,6 +468,10 @@ public class QueenEntity extends RoyalBossEntity { tag.putInt(SUMMON_COOLDOWN_KEY, this.manticoreSummonCooldownTicks); tag.putInt("GravityStompCooldownTicks", this.gravityStompCooldownTicks); tag.putInt("TimeFieldCooldownTicks", this.timeFieldCooldownTicks); + tag.putInt("MomentumLockCooldownTicks", this.momentumLockCooldownTicks); + tag.putInt("CrushingGravityCooldownTicks", this.crushingGravityCooldownTicks); + tag.putInt("AccelerationCooldownTicks", this.accelerationCooldownTicks); + tag.putInt("BlackHoleCooldownTicks", this.blackHoleCooldownTicks); } @Override @@ -256,5 +480,9 @@ public class QueenEntity extends RoyalBossEntity { this.manticoreSummonCooldownTicks = Math.max(0, tag.getInt(SUMMON_COOLDOWN_KEY)); this.gravityStompCooldownTicks = Math.max(0, tag.getInt("GravityStompCooldownTicks")); this.timeFieldCooldownTicks = Math.max(0, tag.getInt("TimeFieldCooldownTicks")); + this.momentumLockCooldownTicks = Math.max(0, tag.getInt("MomentumLockCooldownTicks")); + this.crushingGravityCooldownTicks = Math.max(0, tag.getInt("CrushingGravityCooldownTicks")); + this.accelerationCooldownTicks = Math.max(0, tag.getInt("AccelerationCooldownTicks")); + this.blackHoleCooldownTicks = Math.max(0, tag.getInt("BlackHoleCooldownTicks")); } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalBlackHoleEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalBlackHoleEntity.java new file mode 100644 index 00000000..3d69918d --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalBlackHoleEntity.java @@ -0,0 +1,204 @@ +package com.craisinlord.antarchy.content.entity.royal; + +import com.craisinlord.antarchy.content.AntarchyObjects; +import java.util.UUID; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.EntityDataSerializers; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.Nullable; + +public class RoyalBlackHoleEntity extends Entity { + private static final EntityDataAccessor RADIUS = + SynchedEntityData.defineId(RoyalBlackHoleEntity.class, EntityDataSerializers.FLOAT); + private static final EntityDataAccessor COLLAPSING = + SynchedEntityData.defineId(RoyalBlackHoleEntity.class, EntityDataSerializers.BOOLEAN); + + private static final String OWNER_KEY = "OwnerUuid"; + private static final String AGE_KEY = "Age"; + private static final String ACTIVE_KEY = "ActiveTicks"; + + private static final double DEFAULT_RADIUS = 14.0D; + private static final int DEFAULT_ACTIVE_TICKS = 120; + private static final int COLLAPSE_TICKS = 12; + + @Nullable + private UUID ownerId; + private int age; + private int activeTicks = DEFAULT_ACTIVE_TICKS; + + public RoyalBlackHoleEntity(EntityType entityType, Level level) { + super(entityType, level); + this.noPhysics = true; + this.noCulling = true; + } + + public static RoyalBlackHoleEntity create(ServerLevel level, Vec3 center, double radius, int activeTicks, @Nullable UUID ownerId) { + RoyalBlackHoleEntity hole = new RoyalBlackHoleEntity(AntarchyObjects.ROYAL_BLACK_HOLE.get(), level); + hole.setPos(center.x, center.y, center.z); + hole.setRadius(radius); + hole.activeTicks = Math.max(20, activeTicks); + hole.ownerId = ownerId; + return hole; + } + + public static RoyalBlackHoleEntity create(ServerLevel level, Vec3 center, @Nullable UUID ownerId) { + return create(level, center, DEFAULT_RADIUS, DEFAULT_ACTIVE_TICKS, ownerId); + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + builder.define(RADIUS, (float) DEFAULT_RADIUS); + builder.define(COLLAPSING, false); + } + + public void setRadius(double radius) { + this.entityData.set(RADIUS, (float) Math.max(1.0D, radius)); + } + + public double radius() { + return this.entityData.get(RADIUS); + } + + public boolean isCollapsing() { + return this.entityData.get(COLLAPSING); + } + + @Override + public void tick() { + super.tick(); + if (this.level().isClientSide) { + this.spawnClientParticles(); + return; + } + this.age++; + if (!this.isCollapsing()) { + this.applyPull(); + if (this.age >= this.activeTicks) { + this.entityData.set(COLLAPSING, true); + this.age = 0; + } + return; + } + if (this.age >= COLLAPSE_TICKS) { + this.collapse(); + this.discard(); + } + } + + private void applyPull() { + Vec3 center = this.position(); + double radius = this.radius(); + for (Entity entity : this.level().getEntitiesOfClass(Entity.class, new AABB(center, center).inflate(radius))) { + if (entity == this || this.isImmune(entity)) { + continue; + } + Vec3 toCenter = center.subtract(entity.position()); + double distance = toCenter.length(); + if (distance < 0.5D || distance > radius) { + continue; + } + double strength = 0.16D * (1.0D - distance / radius); + Vec3 pull = toCenter.scale(strength / distance); + entity.setDeltaMovement(entity.getDeltaMovement().scale(0.86D).add(pull)); + entity.hasImpulse = true; + entity.fallDistance = 0.0F; + } + } + + private void collapse() { + if (!(this.level() instanceof ServerLevel level)) { + return; + } + Vec3 center = this.position(); + double radius = this.radius(); + DamageSource source = this.ownerEntity() != null + ? this.damageSources().mobAttack(this.ownerEntity()) + : this.damageSources().magic(); + for (LivingEntity living : level.getEntitiesOfClass(LivingEntity.class, new AABB(center, center).inflate(radius))) { + if (this.isImmune(living)) { + continue; + } + double distance = Math.max(1.0D, living.position().distanceTo(center)); + float falloff = (float) Math.max(0.25D, 1.0D - distance / radius); + living.hurt(source, 26.0F * falloff); + Vec3 launch = living.position().subtract(center).normalize().scale(2.6D * falloff); + living.setDeltaMovement(launch.x, 1.1D * falloff + 0.4D, launch.z); + living.hasImpulse = true; + } + if (level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { + RoyalBlockDestruction.destroySphere(level, this, center, radius * 0.4D, 160, 60.0D, 0.1F); + } + level.sendParticles(ParticleTypes.EXPLOSION_EMITTER, center.x, center.y, center.z, 8, 3.0D, 3.0D, 3.0D, 0.0D); + level.sendParticles(ParticleTypes.REVERSE_PORTAL, center.x, center.y, center.z, 120, 4.0D, 4.0D, 4.0D, 0.6D); + } + + private boolean isImmune(Entity entity) { + if (entity instanceof RoyalBossEntity) { + return true; + } + if (this.ownerId != null && this.ownerId.equals(entity.getUUID())) { + return true; + } + return entity.getType().is(com.craisinlord.antarchy.content.AntarchyTags.Entities.TIME_DILATION_IMMUNE); + } + + @Nullable + private LivingEntity ownerEntity() { + if (this.ownerId == null || !(this.level() instanceof ServerLevel level)) { + return null; + } + return level.getEntity(this.ownerId) instanceof LivingEntity living ? living : null; + } + + private void spawnClientParticles() { + Vec3 center = this.position(); + for (int i = 0; i < 6; i++) { + double angle = this.random.nextDouble() * Math.PI * 2.0D; + double r = this.radius() * (0.3D + this.random.nextDouble() * 0.7D); + double px = center.x + Math.cos(angle) * r; + double pz = center.z + Math.sin(angle) * r; + double py = center.y + (this.random.nextDouble() - 0.5D) * 3.0D; + this.level().addParticle(ParticleTypes.PORTAL, px, py, pz, + (center.x - px) * 0.18D, (center.y - py) * 0.18D, (center.z - pz) * 0.18D); + } + } + + @Override + public boolean isPickable() { + return false; + } + + @Override + public boolean isIgnoringBlockTriggers() { + return true; + } + + @Override + protected void readAdditionalSaveData(CompoundTag tag) { + this.setRadius(tag.getDouble("Radius")); + this.age = tag.getInt(AGE_KEY); + this.activeTicks = tag.contains(ACTIVE_KEY) ? tag.getInt(ACTIVE_KEY) : DEFAULT_ACTIVE_TICKS; + this.ownerId = tag.hasUUID(OWNER_KEY) ? tag.getUUID(OWNER_KEY) : null; + } + + @Override + protected void addAdditionalSaveData(CompoundTag tag) { + tag.putDouble("Radius", this.radius()); + tag.putInt(AGE_KEY, this.age); + tag.putInt(ACTIVE_KEY, this.activeTicks); + if (this.ownerId != null) { + tag.putUUID(OWNER_KEY, this.ownerId); + } + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalBoltEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalBoltEntity.java index 1e593b10..da08884f 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalBoltEntity.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalBoltEntity.java @@ -1,10 +1,19 @@ package com.craisinlord.antarchy.content.entity.royal; import com.craisinlord.antarchy.config.AntarchySettings; +import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement; import net.minecraft.core.particles.ParticleOptions; import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.EntityDataSerializers; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LightningBolt; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.projectile.AbstractHurtingProjectile; import net.minecraft.world.level.Level; @@ -12,10 +21,42 @@ import net.minecraft.world.phys.EntityHitResult; import net.minecraft.world.phys.HitResult; public class RoyalBoltEntity extends AbstractHurtingProjectile { + private static final EntityDataAccessor ELEMENT = + SynchedEntityData.defineId(RoyalBoltEntity.class, EntityDataSerializers.INT); + public RoyalBoltEntity(EntityType entityType, Level level) { super(entityType, level); } + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); + builder.define(ELEMENT, RoyalBeamElement.GENERIC.ordinal()); + } + + public void setElement(RoyalBeamElement element) { + this.entityData.set(ELEMENT, element.ordinal()); + } + + public RoyalBeamElement getElement() { + RoyalBeamElement[] values = RoyalBeamElement.values(); + return values[Math.floorMod(this.entityData.get(ELEMENT), values.length)]; + } + + @Override + public void addAdditionalSaveData(CompoundTag tag) { + super.addAdditionalSaveData(tag); + tag.putInt("Element", this.entityData.get(ELEMENT)); + } + + @Override + public void readAdditionalSaveData(CompoundTag tag) { + super.readAdditionalSaveData(tag); + if (tag.contains("Element")) { + this.entityData.set(ELEMENT, tag.getInt("Element")); + } + } + @Override protected double getDefaultGravity() { return 0.02D; @@ -33,7 +74,12 @@ public class RoyalBoltEntity extends AbstractHurtingProjectile { @Override protected ParticleOptions getTrailParticle() { - return ParticleTypes.END_ROD; + return switch (this.getElement()) { + case FIRE -> ParticleTypes.FLAME; + case LIGHTNING -> ParticleTypes.ELECTRIC_SPARK; + case ICE -> ParticleTypes.SNOWFLAKE; + case GENERIC -> ParticleTypes.WITCH; + }; } @Override @@ -51,6 +97,28 @@ public class RoyalBoltEntity extends AbstractHurtingProjectile { target.hurt(this.damageSources().mobProjectile(this, owner instanceof LivingEntity le ? le : null), damage); if (target instanceof LivingEntity living) { living.knockback(0.35D, this.getX() - target.getX(), this.getZ() - target.getZ()); + switch (this.getElement()) { + case FIRE -> living.setRemainingFireTicks(Math.max(living.getRemainingFireTicks(), 80)); + case ICE -> { + living.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 100, 1)); + living.setTicksFrozen(Math.min(living.getTicksRequiredToFreeze() + 40, living.getTicksFrozen() + 140)); + } + case LIGHTNING -> { + if (this.level() instanceof ServerLevel serverLevel) { + LightningBolt bolt = EntityType.LIGHTNING_BOLT.create(serverLevel); + if (bolt != null) { + bolt.moveTo(target.getX(), target.getY(), target.getZ()); + bolt.setVisualOnly(true); + if (owner instanceof net.minecraft.server.level.ServerPlayer serverPlayer) { + bolt.setCause(serverPlayer); + } + serverLevel.addFreshEntity(bolt); + } + } + } + case GENERIC -> { + } + } } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalBossEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalBossEntity.java index a47a4fe1..78f9d030 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalBossEntity.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalBossEntity.java @@ -7,6 +7,7 @@ import com.craisinlord.antarchy.content.entity.multipart.MultipartPartDefinition import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamController; import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamSettings; import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamTerrainMode; +import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement; import java.util.List; import net.minecraft.network.chat.Component; import net.minecraft.network.syncher.EntityDataAccessor; @@ -24,6 +25,8 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.MoverType; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.control.FlyingMoveControl; @@ -87,10 +90,18 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult private static final double CRUSH_MAX_RESISTANCE = 60.0D; private static final float CRUSH_DROP_CHANCE = 0.1F; + protected static final double FLYING_MIN_HOVER = 2.5D; + protected static final double FLYING_PREFERRED_HOVER = 6.0D; + protected static final double FLYING_MAX_HOVER_ABOVE_GROUND = 24.0D; + private static final EntityDataAccessor FIRING = SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.BOOLEAN); private static final EntityDataAccessor HAS_BEAM_END = SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.BOOLEAN); + private static final EntityDataAccessor ACCELERATED = + SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.BOOLEAN); + private static final EntityDataAccessor BEAM_ELEMENT = + SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.INT); private static final EntityDataAccessor BEAM_END_X = SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.FLOAT); private static final EntityDataAccessor BEAM_END_Y = @@ -115,6 +126,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult @Nullable private RoyalHead activeBeamHead; private int beamLoopSoundTicks; + private int beamHeadCursor; @Nullable private Entity[] multipartParts; @@ -154,6 +166,17 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult protected abstract RoyalBeamTerrainMode royalBeamTerrainMode(); + protected RoyalBeamElement royalBeamElement(@Nullable RoyalHead head) { + return RoyalBeamElement.GENERIC; + } + + protected SoundEvent royalBeamStartSound(RoyalHead head) { + return this.royalBeamStartSound(); + } + + protected void tickRoyalBeamEffects(RoyalHead head, Vec3 start, Vec3 end) { + } + protected RoyalBeamTerrainMode royalBeamTerrainMode(@Nullable RoyalHead head) { return this.royalBeamTerrainMode(); } @@ -219,6 +242,8 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult super.defineSynchedData(builder); builder.define(FIRING, false); builder.define(HAS_BEAM_END, false); + builder.define(ACCELERATED, false); + builder.define(BEAM_ELEMENT, RoyalBeamElement.GENERIC.ordinal()); builder.define(BEAM_END_X, 0.0F); builder.define(BEAM_END_Y, 0.0F); builder.define(BEAM_END_Z, 0.0F); @@ -273,6 +298,9 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult if (this.level().isClientSide) { return; } + if (this.isFlyingBoss() && !this.isDeadOrDying()) { + this.tickFlyingAltitude(); + } this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth()); @@ -347,6 +375,10 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult this.royalBeamSettings(), this.royalBeamTerrainMode(this.activeBeamHead), this::setRoyalBeamEndPosition); + Vec3 beamEnd = this.beamController.beamEndPosition(); + if (beamEnd != null) { + this.tickRoyalBeamEffects(this.activeBeamHead, this.headAnchor(this.activeBeamHead), beamEnd); + } if (!this.beamController.isFiring()) { this.stopRoyalBeam(); } @@ -358,7 +390,8 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult return; } Phase phase = this.phase(); - for (RoyalHead head : this.heads) { + for (int offset = 0; offset < this.heads.length; offset++) { + RoyalHead head = this.heads[(this.beamHeadCursor + offset) % this.heads.length]; LivingEntity target = head.target(this.level()); if (!head.readyToAttack() || target == null || !this.canAttack(target) || this.headWithinBiteReach(head, target)) { @@ -369,12 +402,14 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult head.startShoot(duration, cooldown); head.setBeamActive(true); this.activeBeamHead = head; + this.beamHeadCursor = (head.slot().partIndex()) % this.heads.length; this.beamCooldownTicks = cooldown; this.beamController.start(this.headAnchor(head), target.getEyePosition(), duration); + this.entityData.set(BEAM_ELEMENT, this.royalBeamElement(head).ordinal()); this.setFiringRoyalBeam(true); this.triggerAnim(head.slot().controllerName(), "shoot"); this.beamLoopSoundTicks = 20; - this.playSound(this.royalBeamStartSound(), 3.0F, 1.0F); + this.playSound(this.royalBeamStartSound(head), 3.0F, 1.0F); this.playSound(this.royalBeamShootSound(), 3.0F, 1.0F); return; } @@ -386,6 +421,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult } this.activeBeamHead = null; this.beamController.stop(); + this.entityData.set(BEAM_ELEMENT, RoyalBeamElement.GENERIC.ordinal()); this.playSound(this.royalBeamEndSound(), 2.5F, 1.0F); this.setFiringRoyalBeam(false); this.setRoyalBeamEndPosition(null); @@ -437,11 +473,47 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult double reach = this.getBbWidth() * 0.5D + this.biteReach() * 0.5D; double dx = target.getX() - this.getX(); double dz = target.getZ() - this.getZ(); - if ((dx * dx + dz * dz) > reach * reach) { - double wantedY = this.isFlyingBoss() ? target.getY() + 3.0D : target.getY(); - this.getMoveControl().setWantedPosition(target.getX(), wantedY, target.getZ(), this.isFlyingBoss() ? 1.1D : 1.0D); - } else { + boolean closeHorizontally = (dx * dx + dz * dz) <= reach * reach; + + if (!this.isFlyingBoss()) { + if (closeHorizontally) { + this.getNavigation().stop(); + } else { + this.getMoveControl().setWantedPosition(target.getX(), target.getY(), target.getZ(), 1.0D); + } + return; + } + + double groundBelowTarget = this.groundYBelow(target.getX(), target.getZ()); + double wantedY = Mth.clamp(target.getY() + 3.0D, + groundBelowTarget + FLYING_MIN_HOVER, + groundBelowTarget + FLYING_MAX_HOVER_ABOVE_GROUND); + boolean closeVertically = Math.abs(wantedY - this.getY()) <= 2.5D; + if (closeHorizontally && closeVertically) { this.getNavigation().stop(); + } else { + this.getMoveControl().setWantedPosition(target.getX(), wantedY, target.getZ(), 1.1D); + } + } + + protected double groundYBelow(double x, double z) { + return this.level().getHeight(net.minecraft.world.level.levelgen.Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, + Mth.floor(x), Mth.floor(z)); + } + + private void tickFlyingAltitude() { + if (this.onGround()) { + this.setDeltaMovement(this.getDeltaMovement().add(0.0D, 0.2D, 0.0D)); + } + double groundY = this.groundYBelow(this.getX(), this.getZ()); + double ceiling = groundY + FLYING_MAX_HOVER_ABOVE_GROUND; + if (this.getY() > ceiling) { + double desiredY = groundY + FLYING_PREFERRED_HOVER; + this.getMoveControl().setWantedPosition(this.getX(), desiredY, this.getZ(), 1.0D); + Vec3 delta = this.getDeltaMovement(); + if (delta.y > -0.1D) { + this.setDeltaMovement(delta.x, Math.max(-0.5D, delta.y - 0.1D), delta.z); + } } } @@ -539,6 +611,29 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult super.die(damageSource); } + @Override + @Nullable + public ItemEntity spawnAtLocation(ItemStack stack, float offsetY) { + if (stack.isEmpty() || this.level().isClientSide) { + return null; + } + double spread = this.getBbWidth() * 0.6D; + double height = 20.0D + this.random.nextDouble() * 10.0D; + ItemEntity itemEntity = new ItemEntity( + this.level(), + this.getX() + (this.random.nextDouble() - 0.5D) * spread, + this.getY() + height, + this.getZ() + (this.random.nextDouble() - 0.5D) * spread, + stack); + itemEntity.setDeltaMovement( + (this.random.nextDouble() - 0.5D) * 0.12D, + -0.2D - this.random.nextDouble() * 0.15D, + (this.random.nextDouble() - 0.5D) * 0.12D); + itemEntity.setDefaultPickUpDelay(); + this.level().addFreshEntity(itemEntity); + return itemEntity; + } + @Override protected void tickDeath() { this.deathTime++; @@ -569,6 +664,22 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult return super.hurt(source, cappedAmount); } + @Override + public boolean canBeAffected(net.minecraft.world.effect.MobEffectInstance effectInstance) { + if (effectInstance.is(com.craisinlord.antarchy.content.AntarchyObjects.INVERTED_EFFECT.get())) { + return false; + } + return super.canBeAffected(effectInstance); + } + + public boolean isRoyalAccelerated() { + return this.entityData.get(ACCELERATED); + } + + public void setRoyalAccelerated(boolean accelerated) { + this.entityData.set(ACCELERATED, accelerated); + } + public boolean isFiringRoyalBeam() { return this.entityData.get(FIRING); } @@ -608,18 +719,25 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult return new Vec3(x, y, z); } + public RoyalBeamElement getRoyalBeamElement() { + int ordinal = this.entityData.get(BEAM_ELEMENT); + return ordinal >= 0 && ordinal < RoyalBeamElement.values().length + ? RoyalBeamElement.values()[ordinal] + : RoyalBeamElement.GENERIC; + } + @Override public void registerControllers(AnimatableManager.ControllerRegistrar controllers) { controllers.add(new AnimationController<>(this, "locomotion", 4, this::locomotionPredicate)); controllers.add(new AnimationController<>(this, "head_left", 0, RoyalBossEntity::headIdle) .triggerableAnim("bite", RawAnimation.begin().thenPlay("bite_1")) - .triggerableAnim("shoot", RawAnimation.begin().thenLoop("shoot_1"))); + .triggerableAnim("shoot", RawAnimation.begin().thenPlay("shoot_1"))); controllers.add(new AnimationController<>(this, "head_center", 0, RoyalBossEntity::headIdle) .triggerableAnim("bite", RawAnimation.begin().thenPlay("bite_2")) - .triggerableAnim("shoot", RawAnimation.begin().thenLoop("shoot_2"))); + .triggerableAnim("shoot", RawAnimation.begin().thenPlay("shoot_2"))); controllers.add(new AnimationController<>(this, "head_right", 0, RoyalBossEntity::headIdle) .triggerableAnim("bite", RawAnimation.begin().thenPlay("bite_3")) - .triggerableAnim("shoot", RawAnimation.begin().thenLoop("shoot_3"))); + .triggerableAnim("shoot", RawAnimation.begin().thenPlay("shoot_3"))); controllers.add(new AnimationController<>(this, "body_action", 0, this::bodyActionPredicate) .triggerableAnim("stomp", RawAnimation.begin().thenPlay("stomp")) .triggerableAnim("wing_gust", RawAnimation.begin().thenPlay("wing_gust")) diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalMountEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalMountEntity.java index 33cd1e06..c370fc05 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalMountEntity.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/RoyalMountEntity.java @@ -1,13 +1,18 @@ package com.craisinlord.antarchy.content.entity.royal; import com.craisinlord.antarchy.config.AntarchySettings; +import com.craisinlord.antarchy.content.AntarchySoundEvents; +import com.craisinlord.antarchy.content.AntarchyTags; +import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement; import java.util.UUID; +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.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.util.Mth; import net.minecraft.world.InteractionHand; @@ -40,6 +45,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.pathfinder.PathType; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; @@ -91,6 +97,7 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit private boolean actionHit; private int spitCooldown; private int quirkTimer; + private int flapSoundTimer; private boolean riderAscendPressed; private boolean riderDescendPressed; @@ -109,15 +116,17 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit this.xpReward = 20; } - public static AttributeSupplier.Builder createBaseAttributes() { + public static AttributeSupplier.Builder createBaseAttributes( + double health, double attackDamage, double movementSpeed, double flyingSpeed, + double armor, double knockbackResistance, double followRange) { return Mob.createMobAttributes() - .add(Attributes.MAX_HEALTH, 120.0D) - .add(Attributes.ATTACK_DAMAGE, 12.0D) - .add(Attributes.MOVEMENT_SPEED, 0.28D) - .add(Attributes.FLYING_SPEED, 0.9D) - .add(Attributes.FOLLOW_RANGE, 48.0D) - .add(Attributes.KNOCKBACK_RESISTANCE, 0.6D) - .add(Attributes.ARMOR, 10.0D) + .add(Attributes.MAX_HEALTH, health) + .add(Attributes.ATTACK_DAMAGE, attackDamage) + .add(Attributes.MOVEMENT_SPEED, movementSpeed) + .add(Attributes.FLYING_SPEED, flyingSpeed) + .add(Attributes.FOLLOW_RANGE, followRange) + .add(Attributes.KNOCKBACK_RESISTANCE, knockbackResistance) + .add(Attributes.ARMOR, armor) .add(Attributes.STEP_HEIGHT, 1.5D); } @@ -125,6 +134,26 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit protected abstract EntityType boltType(); + protected abstract SoundEvent idleSound(); + + protected abstract SoundEvent biteSound(); + + protected abstract SoundEvent shootSound(); + + protected abstract SoundEvent flySound(); + + protected abstract SoundEvent stepSound(); + + @Override + protected SoundEvent getAmbientSound() { + return this.idleSound(); + } + + @Override + protected void playStepSound(BlockPos pos, BlockState state) { + this.playSound(this.stepSound(), 0.16F, 1.0F + (this.random.nextFloat() - 0.5F) * 0.2F); + } + @Override protected PathNavigation createNavigation(Level level) { GroundPathNavigation navigation = new GroundPathNavigation(this, level); @@ -135,7 +164,12 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit @Override protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); - this.goalSelector.addGoal(1, new SitWhenOrderedToGoal(this)); + this.goalSelector.addGoal(1, new SitWhenOrderedToGoal(this) { + @Override + public boolean canUse() { + return !RoyalMountEntity.this.isBaby() && super.canUse(); + } + }); this.goalSelector.addGoal(2, new RoyalMountSpitGoal(this)); this.goalSelector.addGoal(3, new net.minecraft.world.entity.ai.goal.MeleeAttackGoal(this, 1.2D, true) { @Override @@ -155,14 +189,35 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit this.goalSelector.addGoal(6, new WaterAvoidingRandomStrollGoal(this, 0.8D) { @Override public boolean canUse() { - return !RoyalMountEntity.this.isVehicle() && !RoyalMountEntity.this.isOrderedToSit() && super.canUse(); + return !RoyalMountEntity.this.isBaby() && !RoyalMountEntity.this.isVehicle() + && !RoyalMountEntity.this.isOrderedToSit() && super.canUse(); } }); this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 12.0F)); - this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); - this.targetSelector.addGoal(1, new OwnerHurtByTargetGoal(this)); - this.targetSelector.addGoal(2, new OwnerHurtTargetGoal(this)); - this.targetSelector.addGoal(3, new HurtByTargetGoal(this).setAlertOthers()); + this.goalSelector.addGoal(8, new RandomLookAroundGoal(this) { + @Override + public boolean canUse() { + return !RoyalMountEntity.this.isBaby() && super.canUse(); + } + }); + this.targetSelector.addGoal(1, new OwnerHurtByTargetGoal(this) { + @Override + public boolean canUse() { + return !RoyalMountEntity.this.isBaby() && super.canUse(); + } + }); + this.targetSelector.addGoal(2, new OwnerHurtTargetGoal(this) { + @Override + public boolean canUse() { + return !RoyalMountEntity.this.isBaby() && super.canUse(); + } + }); + this.targetSelector.addGoal(3, new HurtByTargetGoal(this) { + @Override + public boolean canUse() { + return !RoyalMountEntity.this.isBaby() && super.canUse(); + } + }.setAlertOthers()); } @Override @@ -197,6 +252,9 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit this.moveControl = flying ? this.flyingMoveControl : this.groundMoveControl; this.navigation = flying ? this.flyingNavigation : this.groundNavigation; this.setNoGravity(flying); + if (flying && !this.level().isClientSide) { + this.playSound(this.flySound(), 1.0F, 1.0F + (this.random.nextFloat() - 0.5F) * 0.2F); + } } } @@ -226,15 +284,7 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit @Override public boolean isFood(ItemStack stack) { - return isGoldenTreat(stack); - } - - public static boolean isGoldenTreat(ItemStack stack) { - if (stack.isEmpty()) { - return false; - } - String path = net.minecraft.core.registries.BuiltInRegistries.ITEM.getKey(stack.getItem()).getPath(); - return path.contains("gold") || path.contains("golden"); + return stack.is(AntarchyTags.Items.ROYAL_MOUNT_FOOD); } @Override @@ -327,6 +377,11 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit this.spitCooldown--; } + if ((this.isFlying() || !this.onGround()) && --this.flapSoundTimer <= 0) { + this.flapSoundTimer = 24 + this.random.nextInt(12); + this.playSound(this.flySound(), 0.6F, 1.0F + (this.random.nextFloat() - 0.5F) * 0.3F); + } + if (this.actionTicks > 0) { this.actionTicks--; if (!this.actionHit && this.actionTicks <= ACTION_TICKS - BITE_HIT_TICK @@ -385,6 +440,7 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit this.actionHit = false; this.setAnimState(this.isFlying() ? ANIM_FLY_BITE : ANIM_BITE); this.triggerAnim("main", this.isFlying() ? "fly_bite" : "bite"); + this.playSound(this.biteSound(), 1.2F, 0.9F + this.random.nextFloat() * 0.2F); } private void applyBiteDamage() { @@ -445,12 +501,17 @@ public abstract class RoyalMountEntity extends TamableAnimal implements GeoEntit Vec3 dir = aim.add(right.scale(i * 0.14D)).normalize(); RoyalBoltEntity bolt = new RoyalBoltEntity(this.boltType(), this.level()); bolt.setOwner(this); + bolt.setElement(this.boltElement(i)); Vec3 spawn = this.getEyePosition().add(aim.scale(1.6D)).add(right.scale(i * 0.9D)); bolt.setPos(spawn.x, spawn.y, spawn.z); bolt.shoot(dir.x, dir.y, dir.z, 1.4F, 1.0F); this.level().addFreshEntity(bolt); } - this.playSound(SoundEvents.BREEZE_SHOOT, 1.2F, 0.9F); + this.playSound(this.shootSound(), 1.2F, 0.9F + this.random.nextFloat() * 0.2F); + } + + protected RoyalBeamElement boltElement(int lateralIndex) { + return RoyalBeamElement.GENERIC; } public boolean toggleMountedFlight(ServerPlayer player) { diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/beam/RoyalBeamController.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/beam/RoyalBeamController.java index 54f4a040..4ae93ee8 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/beam/RoyalBeamController.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/beam/RoyalBeamController.java @@ -5,6 +5,8 @@ import java.util.HashSet; import java.util.Set; import java.util.function.Consumer; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.tags.BlockTags; import net.minecraft.util.Mth; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; @@ -29,6 +31,8 @@ public final class RoyalBeamController { private Vec3 beamEndPosition; private int beamTicks; private int terrainMutationsThisTick; + private static final int ICE_MUTATIONS_PER_TICK = 3; + private static final float ICE_IMPACT_RADIUS = 2.0F; public RoyalBeamController(Mob owner) { this.owner = owner; @@ -101,7 +105,8 @@ public final class RoyalBeamController { syncedEndPosition.accept(this.beamEndPosition); if (!this.owner.level().isClientSide && this.beamEndPosition != null) { - marchDamageAndTerrain(shootFrom, this.beamEndPosition, settings, terrainMode); + boolean impactedBlock = hit.getType() == HitResult.Type.BLOCK; + marchDamageAndTerrain(shootFrom, this.beamEndPosition, settings, terrainMode, impactedBlock); } if (this.beamTicks <= 0) { @@ -114,22 +119,32 @@ public final class RoyalBeamController { Vec3 shootFrom, Vec3 beamEnd, RoyalBeamSettings settings, - RoyalBeamTerrainMode terrainMode + RoyalBeamTerrainMode terrainMode, + boolean impactedBlock ) { Vec3 direction = beamEnd.subtract(shootFrom).normalize(); double distance = shootFrom.distanceTo(beamEnd); DamageSource damageSource = this.owner.damageSources().mobAttack(this.owner); Set damagedThisTick = new HashSet<>(); + boolean pathMutates = terrainMode == RoyalBeamTerrainMode.DESTROY; for (double walked = settings.pathStep(); walked < Math.min(distance, settings.range()); walked += settings.pathStep()) { Vec3 sample = shootFrom.add(direction.scale(walked)); hurtEntitiesAround(sample, settings.pathDamageRadius(), settings.damage(), settings.knockback(), damageSource, settings.requireLineOfSightForDamage(), damagedThisTick); - if (shouldMutateTerrain(settings, walked)) { + if (pathMutates && shouldMutateTerrain(settings, walked)) { mutateTerrainAround(sample, settings.pathTerrainRadius(), settings, terrainMode); } } hurtEntitiesAround(beamEnd, settings.impactDamageRadius(), settings.damage(), settings.knockback(), damageSource, settings.requireLineOfSightForDamage(), damagedThisTick); - if (shouldMutateTerrain(settings, shootFrom.distanceTo(beamEnd))) { + + if (!shouldMutateTerrain(settings, distance)) { + return; + } + if (terrainMode == RoyalBeamTerrainMode.BUILD_ICE) { + if (impactedBlock) { + mutateTerrainAround(beamEnd, ICE_IMPACT_RADIUS, settings, terrainMode); + } + } else { mutateTerrainAround(beamEnd, settings.impactTerrainRadius(), settings, terrainMode); } } @@ -233,8 +248,11 @@ public final class RoyalBeamController { int maxZ = Mth.floor(center.z + radius); float radiusSqr = radius * radius; + int cap = terrainMode == RoyalBeamTerrainMode.BUILD_ICE + ? Math.min(ICE_MUTATIONS_PER_TICK, settings.maxTerrainMutationsPerTick()) + : settings.maxTerrainMutationsPerTick(); for (BlockPos cursor : BlockPos.betweenClosed(minX, minY, minZ, maxX, maxY, maxZ)) { - if (this.terrainMutationsThisTick >= settings.maxTerrainMutationsPerTick()) { + if (this.terrainMutationsThisTick >= cap) { return; } BlockPos pos = cursor.immutable(); @@ -274,13 +292,13 @@ public final class RoyalBeamController { } private void buildIceBlock(Level level, BlockPos pos, BlockState existing, RoyalBeamSettings settings) { - boolean softTarget = existing.isAir() + boolean replaceable = existing.isAir() || existing.canBeReplaced() - || !existing.getFluidState().isEmpty() - || existing.getBlock().getExplosionResistance() <= settings.maxTerrainResistance() - && existing.getDestroySpeed(level, pos) >= 0.0F - && level.getBlockEntity(pos) == null; - if (!softTarget) { + || !existing.getFluidState().isEmpty(); + if (!replaceable || level.getBlockEntity(pos) != null || existing.is(BlockTags.ICE)) { + return; + } + if (!touchesFreezableSurface(level, pos)) { return; } @@ -289,6 +307,20 @@ public final class RoyalBeamController { this.terrainMutationsThisTick++; } + private static boolean touchesFreezableSurface(Level level, BlockPos pos) { + for (Direction direction : Direction.values()) { + BlockPos neighbor = pos.relative(direction); + BlockState state = level.getBlockState(neighbor); + if (state.is(BlockTags.ICE) || state.is(Blocks.SNOW_BLOCK)) { + continue; + } + if (state.isFaceSturdy(level, neighbor, direction.getOpposite())) { + return true; + } + } + return false; + } + private Block randomIceBlock() { return switch (this.owner.getRandom().nextInt(5)) { case 0 -> Blocks.BLUE_ICE; diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/beam/RoyalBeamElement.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/beam/RoyalBeamElement.java new file mode 100644 index 00000000..3706166d --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/beam/RoyalBeamElement.java @@ -0,0 +1,8 @@ +package com.craisinlord.antarchy.content.entity.royal.beam; + +public enum RoyalBeamElement { + GENERIC, + FIRE, + LIGHTNING, + ICE +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/AdvanceDecree.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/AdvanceDecree.java index 480f0029..c5d0e13b 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/AdvanceDecree.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/AdvanceDecree.java @@ -2,8 +2,17 @@ package com.craisinlord.antarchy.content.entity.royal.decree; import com.craisinlord.antarchy.content.entity.royal.KingEntity; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.phys.Vec3; public final class AdvanceDecree implements RoyalDecree { - public String name() { return "ADVANCE"; } - public void apply(ServerLevel level, KingEntity king, LivingEntity target) { Vec3 p = king.position().subtract(target.position()).normalize().scale(0.35D); target.setDeltaMovement(target.getDeltaMovement().add(p.x, 0.05D, p.z)); target.hasImpulse = true; } + private static final double REQUIRED_RANGE = 14.0D; + public String translationKey() { return "decree.antarchy.advance"; } + public void apply(ServerLevel level, KingEntity king, LivingEntity target) { + king.setDecreeRetreatPressure(true); + if (target.distanceTo(king) > REQUIRED_RANGE) { + king.invokeJudgment(target); + } + } + @Override + public int contextWeight(KingEntity king, LivingEntity target) { + return 4 + king.behaviorScore(KingEntity.Behavior.KEEPING_FAR); + } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/CloseQuartersDecree.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/CloseQuartersDecree.java index e0eeb77d..7c0f6d19 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/CloseQuartersDecree.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/CloseQuartersDecree.java @@ -3,6 +3,10 @@ import com.craisinlord.antarchy.content.entity.royal.KingEntity; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.LivingEntity; public final class CloseQuartersDecree implements RoyalDecree { - public String name() { return "CLOSE QUARTERS"; } - public void apply(ServerLevel level, KingEntity king, LivingEntity target) { if (target.distanceTo(king) <= 12.0D) target.hurt(king.damageSources().mobAttack(king), 4.0F); } + public String translationKey() { return "decree.antarchy.close_quarters"; } + public void apply(ServerLevel level, KingEntity king, LivingEntity target) { } + @Override + public int contextWeight(KingEntity king, LivingEntity target) { + return 4 + king.behaviorScore(KingEntity.Behavior.RANGED); + } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/ComeNoCloserDecree.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/ComeNoCloserDecree.java new file mode 100644 index 00000000..25120910 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/ComeNoCloserDecree.java @@ -0,0 +1,12 @@ +package com.craisinlord.antarchy.content.entity.royal.decree; +import com.craisinlord.antarchy.content.entity.royal.KingEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.LivingEntity; +public final class ComeNoCloserDecree implements RoyalDecree { + public String translationKey() { return "decree.antarchy.come_no_closer"; } + public void apply(ServerLevel level, KingEntity king, LivingEntity target) { } + @Override + public int contextWeight(KingEntity king, LivingEntity target) { + return 4 + king.behaviorScore(KingEntity.Behavior.HUGGING); + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/DoNotRunDecree.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/DoNotRunDecree.java new file mode 100644 index 00000000..17e3f9b9 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/DoNotRunDecree.java @@ -0,0 +1,12 @@ +package com.craisinlord.antarchy.content.entity.royal.decree; +import com.craisinlord.antarchy.content.entity.royal.KingEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.LivingEntity; +public final class DoNotRunDecree implements RoyalDecree { + public String translationKey() { return "decree.antarchy.do_not_run"; } + public void apply(ServerLevel level, KingEntity king, LivingEntity target) { if (target.isSprinting()) king.invokeJudgment(target); } + @Override + public int contextWeight(KingEntity king, LivingEntity target) { + return 4 + king.behaviorScore(KingEntity.Behavior.SPRINTING); + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/FightMeCowardDecree.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/FightMeCowardDecree.java new file mode 100644 index 00000000..24cebe64 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/FightMeCowardDecree.java @@ -0,0 +1,16 @@ +package com.craisinlord.antarchy.content.entity.royal.decree; +import com.craisinlord.antarchy.content.entity.royal.KingEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.phys.Vec3; +public final class FightMeCowardDecree implements RoyalDecree { + public String name() { return "FIGHT ME, COWARD!"; } + public String translationKey() { return "decree.antarchy.fight_me_coward"; } + public void apply(ServerLevel level, KingEntity king, LivingEntity target) { + if (target.distanceTo(king) > 28.0D) { + Vec3 pull = king.position().subtract(target.position()).normalize().scale(0.35D); + target.setDeltaMovement(target.getDeltaMovement().add(pull.x, 0.05D, pull.z)); + target.hasImpulse = true; + } + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/HandsOffTheCrownDecree.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/HandsOffTheCrownDecree.java new file mode 100644 index 00000000..7b5e9f9d --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/HandsOffTheCrownDecree.java @@ -0,0 +1,8 @@ +package com.craisinlord.antarchy.content.entity.royal.decree; +import com.craisinlord.antarchy.content.entity.royal.KingEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.LivingEntity; +public final class HandsOffTheCrownDecree implements RoyalDecree { + public String translationKey() { return "decree.antarchy.hands_off_the_crown"; } + public void apply(ServerLevel level, KingEntity king, LivingEntity target) { } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/KeepYourDistanceDecree.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/KeepYourDistanceDecree.java index 35da79bd..f009eabb 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/KeepYourDistanceDecree.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/KeepYourDistanceDecree.java @@ -2,8 +2,16 @@ package com.craisinlord.antarchy.content.entity.royal.decree; import com.craisinlord.antarchy.content.entity.royal.KingEntity; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.phys.Vec3; public final class KeepYourDistanceDecree implements RoyalDecree { - public String name() { return "KEEP YOUR DISTANCE"; } - public void apply(ServerLevel level, KingEntity king, LivingEntity target) { if (target.distanceTo(king) < 18.0D) { Vec3 p = target.position().subtract(king.position()).normalize().scale(0.8D); target.setDeltaMovement(target.getDeltaMovement().add(p.x, 0.2D, p.z)); target.hasImpulse = true; } } + private static final double INNER_RADIUS = 16.0D; + public String translationKey() { return "decree.antarchy.keep_your_distance"; } + public void apply(ServerLevel level, KingEntity king, LivingEntity target) { + if (target.distanceTo(king) <= INNER_RADIUS) { + king.invokeJudgment(target); + } + } + @Override + public int contextWeight(KingEntity king, LivingEntity target) { + return 4 + king.behaviorScore(KingEntity.Behavior.HUGGING); + } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/KneelDecree.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/KneelDecree.java new file mode 100644 index 00000000..fe1514ba --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/KneelDecree.java @@ -0,0 +1,22 @@ +package com.craisinlord.antarchy.content.entity.royal.decree; +import com.craisinlord.antarchy.content.entity.royal.KingEntity; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.LivingEntity; +public final class KneelDecree implements RoyalDecree { + private final Map deadlines = new HashMap<>(); + public String translationKey() { return "decree.antarchy.kneel"; } + public void apply(ServerLevel level, KingEntity king, LivingEntity target) { + UUID id = target.getUUID(); + if (target.isCrouching()) { deadlines.remove(id); king.clearActiveDecree(target); return; } + int deadline = deadlines.computeIfAbsent(id, ignored -> target.tickCount + 100); + if (target.tickCount >= deadline) { king.invokeJudgment(target); deadlines.put(id, target.tickCount + 100); } + } + + @Override + public int countdownTicks(LivingEntity target) { + return this.deadlines.getOrDefault(target.getUUID(), target.tickCount + 100) - target.tickCount; + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/NoRespiteDecree.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/NoRespiteDecree.java new file mode 100644 index 00000000..0b3e9610 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/NoRespiteDecree.java @@ -0,0 +1,8 @@ +package com.craisinlord.antarchy.content.entity.royal.decree; +import com.craisinlord.antarchy.content.entity.royal.KingEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.LivingEntity; +public final class NoRespiteDecree implements RoyalDecree { + public String translationKey() { return "decree.antarchy.no_respite"; } + public void apply(ServerLevel level, KingEntity king, LivingEntity target) { } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/NoRetreatDecree.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/NoRetreatDecree.java index 0a0b8ebf..53a8ed1f 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/NoRetreatDecree.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/NoRetreatDecree.java @@ -3,6 +3,15 @@ import com.craisinlord.antarchy.content.entity.royal.KingEntity; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.LivingEntity; public final class NoRetreatDecree implements RoyalDecree { - public String name() { return "NO RETREAT"; } - public void apply(ServerLevel level, KingEntity king, LivingEntity target) { if (target.distanceTo(king) > 28.0D) target.hurt(king.damageSources().mobAttack(king), 3.0F); } + private static final double ALLOWED_RANGE = 26.0D; + public String translationKey() { return "decree.antarchy.no_retreat"; } + public void apply(ServerLevel level, KingEntity king, LivingEntity target) { + if (target.distanceTo(king) > ALLOWED_RANGE) { + king.invokeJudgment(target); + } + } + @Override + public int contextWeight(KingEntity king, LivingEntity target) { + return 4 + king.behaviorScore(KingEntity.Behavior.RETREATING); + } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/RoyalDecree.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/RoyalDecree.java index ba93acdb..d0c29d5e 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/RoyalDecree.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/RoyalDecree.java @@ -5,6 +5,21 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.LivingEntity; public interface RoyalDecree { - String name(); + String translationKey(); void apply(ServerLevel level, KingEntity king, LivingEntity target); + + default int countdownTicks(LivingEntity target) { + return -1; + } + + default String instructionKey() { + return this.translationKey() + ".subtitle"; + } + + default int contextWeight(KingEntity king, LivingEntity target) { + return 4; + } + + default void onEnded() { + } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/ShowNoMercyDecree.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/ShowNoMercyDecree.java new file mode 100644 index 00000000..44ff3e2e --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/ShowNoMercyDecree.java @@ -0,0 +1,13 @@ +package com.craisinlord.antarchy.content.entity.royal.decree; +import com.craisinlord.antarchy.content.entity.royal.KingEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.LivingEntity; +public final class ShowNoMercyDecree implements RoyalDecree { + private static final long IDLE_DAMAGE_LIMIT_TICKS = 80L; + public String translationKey() { return "decree.antarchy.show_no_mercy"; } + public void apply(ServerLevel level, KingEntity king, LivingEntity target) { + if (king.ticksSincePlayerDamage(target) > IDLE_DAMAGE_LIMIT_TICKS) { + king.invokeJudgment(target); + } + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/SkyIsMineDecree.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/SkyIsMineDecree.java new file mode 100644 index 00000000..3525844f --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/SkyIsMineDecree.java @@ -0,0 +1,12 @@ +package com.craisinlord.antarchy.content.entity.royal.decree; +import com.craisinlord.antarchy.content.entity.royal.KingEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.LivingEntity; +public final class SkyIsMineDecree implements RoyalDecree { + public String translationKey() { return "decree.antarchy.the_sky_is_mine"; } + public void apply(ServerLevel level, KingEntity king, LivingEntity target) { if (!target.onGround() && !target.isPassenger()) king.invokeJudgment(target); } + @Override + public int contextWeight(KingEntity king, LivingEntity target) { + return 4 + king.behaviorScore(KingEntity.Behavior.AIRBORNE); + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/StandTallDecree.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/StandTallDecree.java new file mode 100644 index 00000000..7a04453d --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/StandTallDecree.java @@ -0,0 +1,12 @@ +package com.craisinlord.antarchy.content.entity.royal.decree; +import com.craisinlord.antarchy.content.entity.royal.KingEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.LivingEntity; +public final class StandTallDecree implements RoyalDecree { + public String translationKey() { return "decree.antarchy.stand_tall"; } + public void apply(ServerLevel level, KingEntity king, LivingEntity target) { + if (target.isCrouching()) { + king.invokeJudgment(target); + } + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/StandYourGroundDecree.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/StandYourGroundDecree.java new file mode 100644 index 00000000..5e46e984 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/royal/decree/StandYourGroundDecree.java @@ -0,0 +1,23 @@ +package com.craisinlord.antarchy.content.entity.royal.decree; +import com.craisinlord.antarchy.content.entity.royal.KingEntity; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.phys.Vec3; +public final class StandYourGroundDecree implements RoyalDecree { + private static final double ALLOWED_DRIFT = 6.0D; + private final Map anchors = new HashMap<>(); + public String translationKey() { return "decree.antarchy.stand_your_ground"; } + public void apply(ServerLevel level, KingEntity king, LivingEntity target) { + Vec3 anchor = this.anchors.computeIfAbsent(target.getUUID(), ignored -> target.position()); + if (target.position().distanceToSqr(anchor) > ALLOWED_DRIFT * ALLOWED_DRIFT) { + king.invokeJudgment(target); + } + } + @Override + public void onEnded() { + this.anchors.clear(); + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/vortex/WindVortexEntity.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/vortex/WindVortexEntity.java index 8daff363..85a43331 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/vortex/WindVortexEntity.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/entity/vortex/WindVortexEntity.java @@ -9,6 +9,7 @@ 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.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.util.Mth; @@ -228,33 +229,19 @@ public class WindVortexEntity extends Entity { 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 < -1.0D || axisDistance > height + 2.0D) { - 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 * 1.35D + (entity instanceof Player ? 1.5D : 1.75D); - boolean requireLos = !this.travelling && mode == VortexMode.GATHER_RETURN; - - if (radialVector.lengthSqr() > captureRadius * captureRadius - || (requireLos && !this.hasClearPathTo(entity))) { - continue; - } - - this.carriedProgress.putIfAbsent(entity.getUUID(), captureProgress); + this.captureEntity(entity, height, basis, mode); } if (!(this.level() instanceof ServerLevel serverLevel)) { return; } + for (ServerPlayer player : serverLevel.players()) { + if (area.intersects(player.getBoundingBox())) { + this.captureEntity(player, height, basis, mode); + } + } + Iterator> iterator = this.carriedProgress.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = iterator.next(); @@ -314,8 +301,39 @@ public class WindVortexEntity extends Entity { return radial.lengthSqr() < 1.0E-6D ? basis.sideA.scale(this.radiusAt(progress)) : radial; } + private void captureEntity(Entity entity, double height, Basis basis, VortexMode mode) { + if (!this.canAffectEntity(entity)) { + return; + } + Vec3 relative = entity.position().subtract(this.position()); + double axisDistance = relative.dot(basis.axis); + if (axisDistance < -1.0D || axisDistance > height + 2.0D) { + return; + } + 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 * 1.35D + (entity instanceof Player ? 1.5D : 1.75D); + boolean requireLos = !this.travelling && mode == VortexMode.GATHER_RETURN; + + if (radialVector.lengthSqr() > captureRadius * captureRadius + || (requireLos && !this.hasClearPathTo(entity))) { + return; + } + + this.carriedProgress.putIfAbsent(entity.getUUID(), captureProgress); + } + private boolean canAffectEntity(Entity entity) { - if (!entity.isAlive() || entity.isSpectator() || entity.noPhysics || entity.getType().is(AntarchyTags.Entities.WIND_VORTEX_IMMUNE)) { + if (entity instanceof WindVortexEntity + || !entity.isAlive() + || entity.isSpectator() + || entity.noPhysics + || entity.getType().is(AntarchyTags.Entities.WIND_VORTEX_IMMUNE)) { return false; } return true; @@ -370,7 +388,12 @@ public class WindVortexEntity extends Entity { entity.setOnGround(false); } if (entity instanceof Player) { - entity.move(net.minecraft.world.entity.MoverType.SELF, wanted.scale(0.65D)); + Vec3 before = entity.position(); + Vec3 playerCarry = wanted.scale(0.65D); + entity.move(net.minecraft.world.entity.MoverType.SELF, playerCarry); + if (entity.position().distanceToSqr(before) < 1.0E-6D && playerCarry.lengthSqr() > 1.0E-6D) { + entity.setPos(before.add(playerCarry)); + } entity.setOnGround(false); } entity.setDeltaMovement(updatedMovement); diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/network/TimeDilationFieldsPayload.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/network/TimeDilationFieldsPayload.java new file mode 100644 index 00000000..ef89e944 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/network/TimeDilationFieldsPayload.java @@ -0,0 +1,46 @@ +package com.craisinlord.antarchy.content.network; + +import com.craisinlord.antarchy.Antarchy; +import com.craisinlord.antarchy.content.time.TimeDilationFieldSnapshot; +import io.netty.buffer.ByteBuf; +import java.util.List; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; + +public record TimeDilationFieldsPayload(List fields) implements CustomPacketPayload { + public static final Type TYPE = + new Type<>(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "time_dilation_fields")); + + private static final StreamCodec FIELD_CODEC = StreamCodec.of( + (buf, field) -> { + buf.writeDouble(field.x()); + buf.writeDouble(field.y()); + buf.writeDouble(field.z()); + buf.writeDouble(field.radius()); + buf.writeDouble(field.rate()); + buf.writeInt(field.age()); + buf.writeInt(field.durationTicks()); + }, + buf -> new TimeDilationFieldSnapshot( + buf.readDouble(), buf.readDouble(), buf.readDouble(), buf.readDouble(), + buf.readDouble(), buf.readInt(), buf.readInt() + ) + ); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.collection(java.util.ArrayList::new, FIELD_CODEC, 128), + TimeDilationFieldsPayload::fields, + TimeDilationFieldsPayload::new + ); + + public TimeDilationFieldsPayload { + fields = List.copyOf(fields); + } + + @Override + public Type type() { + return TYPE; + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/network/TimeDilationRatePayload.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/network/TimeDilationRatePayload.java index dc649deb..e97d8280 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/network/TimeDilationRatePayload.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/network/TimeDilationRatePayload.java @@ -2,17 +2,25 @@ package com.craisinlord.antarchy.content.network; import com.craisinlord.antarchy.Antarchy; import io.netty.buffer.ByteBuf; +import java.util.UUID; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; -public record TimeDilationRatePayload(int entityId, double rate) implements CustomPacketPayload { +public record TimeDilationRatePayload(UUID entityUuid, double rate) implements CustomPacketPayload { public static final Type TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "time_dilation_rate")); + private static final StreamCodec UUID_CODEC = StreamCodec.of( + (buf, uuid) -> { + buf.writeLong(uuid.getMostSignificantBits()); + buf.writeLong(uuid.getLeastSignificantBits()); + }, + buf -> new UUID(buf.readLong(), buf.readLong()) + ); public static final StreamCodec STREAM_CODEC = StreamCodec.composite( - ByteBufCodecs.VAR_INT, - TimeDilationRatePayload::entityId, + UUID_CODEC, + TimeDilationRatePayload::entityUuid, ByteBufCodecs.DOUBLE, TimeDilationRatePayload::rate, TimeDilationRatePayload::new diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/time/TimeDilationApi.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/time/TimeDilationApi.java index 8a9d6844..cf369de1 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/time/TimeDilationApi.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/time/TimeDilationApi.java @@ -1,21 +1,32 @@ package com.craisinlord.antarchy.content.time; import java.util.function.BiConsumer; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.List; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.Vec3; public final class TimeDilationApi { - private static BiConsumer syncDispatcher = (player, rate) -> { + private static BiConsumer syncDispatcher = (entity, rate) -> { }; + private static BiConsumer> fieldSyncDispatcher = (player, fields) -> { + }; + private static final Map SYNCED_CLIENT_RATES = new ConcurrentHashMap<>(); private TimeDilationApi() { } - public static void setSyncDispatcher(BiConsumer dispatcher) { - syncDispatcher = dispatcher != null ? dispatcher : (player, rate) -> { + public static void setSyncDispatcher(BiConsumer dispatcher) { + syncDispatcher = dispatcher != null ? dispatcher : (entity, rate) -> { + }; + } + + public static void setFieldSyncDispatcher(BiConsumer> dispatcher) { + fieldSyncDispatcher = dispatcher != null ? dispatcher : (player, fields) -> { }; } @@ -27,6 +38,12 @@ public final class TimeDilationApi { public static double getRate(Entity entity) { if (entity instanceof TimeDilationEntityAccess access) { + if (entity.level().isClientSide) { + Double syncedRate = SYNCED_CLIENT_RATES.get(entity.getUUID()); + if (syncedRate != null) { + return syncedRate; + } + } return access.antarchy$getTimeDilationRate(); } return TimeDilationMath.NORMAL_RATE; @@ -37,19 +54,30 @@ public final class TimeDilationApi { } public static void applySyncedRate(Entity entity, double rate) { + applySyncedRate(entity.getUUID(), rate); if (entity instanceof TimeDilationEntityAccess access) { access.antarchy$setTimeDilationRate(rate); } } - public static void syncPlayerRate(ServerPlayer player, double rate) { - syncDispatcher.accept(player, TimeDilationMath.clampRate(rate)); + public static void applySyncedRate(UUID entityUuid, double rate) { + double clampedRate = TimeDilationMath.clampRate(rate); + SYNCED_CLIENT_RATES.put(entityUuid, clampedRate); + } + + public static void clearSyncedClientRates() { + SYNCED_CLIENT_RATES.clear(); + } + + public static void syncEntityRate(Entity entity, double rate) { + syncDispatcher.accept(entity, TimeDilationMath.clampRate(rate)); + } + + public static void syncFields(ServerPlayer player, List fields) { + fieldSyncDispatcher.accept(player, fields); } public static boolean consumeTick(Entity entity, String timerKey) { - if (entity instanceof Player) { - return true; - } double rate = getRate(entity); if (rate >= TimeDilationMath.NORMAL_RATE || !(entity instanceof TimeDilationEntityAccess access)) { return true; diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/time/TimeDilationEntityAccess.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/time/TimeDilationEntityAccess.java index 3ecae3cd..46179f4e 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/time/TimeDilationEntityAccess.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/time/TimeDilationEntityAccess.java @@ -10,4 +10,8 @@ public interface TimeDilationEntityAccess { boolean antarchy$isInTimeDilationMove(); void antarchy$setInTimeDilationMove(boolean inMove); + + boolean antarchy$isApplyingExternalImpulse(); + + void antarchy$setApplyingExternalImpulse(boolean applying); } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/time/TimeDilationFieldSnapshot.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/time/TimeDilationFieldSnapshot.java new file mode 100644 index 00000000..3a888752 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/time/TimeDilationFieldSnapshot.java @@ -0,0 +1,19 @@ +package com.craisinlord.antarchy.content.time; + +public record TimeDilationFieldSnapshot( + double x, + double y, + double z, + double radius, + double rate, + int age, + int durationTicks +) { + public double radiusSquared() { + return this.radius * this.radius; + } + + public double effectiveRate() { + return TimeDilationMath.effectiveFieldRate(this.rate, this.age, this.durationTicks); + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/time/TimeDilationFieldSnapshotSampler.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/time/TimeDilationFieldSnapshotSampler.java new file mode 100644 index 00000000..96a27f27 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/time/TimeDilationFieldSnapshotSampler.java @@ -0,0 +1,22 @@ +package com.craisinlord.antarchy.content.time; + +public final class TimeDilationFieldSnapshotSampler { + private TimeDilationFieldSnapshotSampler() { + } + + public static double sample(Iterable fields, double x, double y, double z) { + double combinedRate = TimeDilationMath.NORMAL_RATE; + for (TimeDilationFieldSnapshot field : fields) { + double dx = field.x() - x; + double dy = field.y() - y; + double dz = field.z() - z; + double distanceSqr = dx * dx + dy * dy + dz * dz; + if (distanceSqr >= field.radiusSquared()) { + continue; + } + double falloff = TimeDilationMath.gaussianFalloff(Math.sqrt(distanceSqr), field.radius()); + combinedRate *= TimeDilationMath.localFieldRate(field.effectiveRate(), falloff); + } + return TimeDilationMath.clampRate(combinedRate); + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/time/TimeDilationManager.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/time/TimeDilationManager.java index 50cf9368..c213de90 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/time/TimeDilationManager.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/time/TimeDilationManager.java @@ -20,6 +20,7 @@ public final class TimeDilationManager { public static void tickServer(MinecraftServer server) { for (ServerLevel level : server.getAllLevels()) { List fields = collectFields(level); + syncFieldSnapshots(level, fields); if (fields.isEmpty()) { if (DILATED_LEVELS.remove(level.dimension())) { resetRates(level); @@ -32,6 +33,18 @@ public final class TimeDilationManager { } } + private static void syncFieldSnapshots(ServerLevel level, List fields) { + List snapshots = fields.stream() + .map(field -> new TimeDilationFieldSnapshot( + field.getX(), field.getY(), field.getZ(), field.fieldRadius(), field.fieldRate(), + field.fieldAge(), field.fieldDurationTicks())) + .limit(128) + .toList(); + for (ServerPlayer player : level.players()) { + TimeDilationApi.syncFields(player, snapshots); + } + } + private static List collectFields(ServerLevel level) { List fields = new ArrayList<>(); for (Entity entity : level.getAllEntities()) { @@ -47,11 +60,18 @@ public final class TimeDilationManager { if (!(entity instanceof TimeDilationEntityAccess access) || entity instanceof TimeDilationFieldEntity) { continue; } + if (entity.getType().is(com.craisinlord.antarchy.content.AntarchyTags.Entities.TIME_DILATION_IMMUNE)) { + if (access.antarchy$getTimeDilationRate() < TimeDilationMath.NORMAL_RATE) { + access.antarchy$setTimeDilationRate(TimeDilationMath.NORMAL_RATE); + TimeDilationApi.syncEntityRate(entity, TimeDilationMath.NORMAL_RATE); + } + continue; + } double previousRate = access.antarchy$getTimeDilationRate(); double rate = TimeDilationFieldSampler.sample(fields, entity.position()); access.antarchy$setTimeDilationRate(rate); - if (entity instanceof ServerPlayer player && Math.abs(previousRate - rate) > 0.001D) { - TimeDilationApi.syncPlayerRate(player, rate); + if (Math.abs(previousRate - rate) > 0.001D) { + TimeDilationApi.syncEntityRate(entity, rate); } } } @@ -65,9 +85,7 @@ public final class TimeDilationManager { continue; } access.antarchy$setTimeDilationRate(TimeDilationMath.NORMAL_RATE); - if (entity instanceof ServerPlayer player) { - TimeDilationApi.syncPlayerRate(player, TimeDilationMath.NORMAL_RATE); - } + TimeDilationApi.syncEntityRate(entity, TimeDilationMath.NORMAL_RATE); } } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/worldgen/elythia/ElythiaBiomeSource.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/worldgen/elythia/ElythiaBiomeSource.java index 2867f200..9968acfe 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/worldgen/elythia/ElythiaBiomeSource.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/worldgen/elythia/ElythiaBiomeSource.java @@ -196,7 +196,7 @@ public class ElythiaBiomeSource extends BiomeSource { } if (biome.is(MOLEWORM_CAVES) && y > this.molewormCavesMaxQuartY) { - return resolveSurfaceFallback(x, z, sampler, this.molewormSurfaceFallbackCache, MOLEWORM_CAVES, GLIMMERING_POOLS); + return resolveSurfaceFallback(x, z, sampler, this.molewormSurfaceFallbackCache, MOLEWORM_CAVES, GLIMMERING_POOLS, CLOUD_SEA); } Climate.TargetPoint target = sampler.sample(x, this.seaLevelQuartY, z); @@ -222,7 +222,7 @@ public class ElythiaBiomeSource extends BiomeSource { biome = this.glimmeringPoolsHolder != null ? this.glimmeringPoolsHolder : biome; } if ((biome.is(PEACH_FOREST) || biome.is(GLIMMERING_POOLS)) && y <= this.undergroundGuardMaxQuartY) { - return resolveSurfaceFallback(x, z, sampler, this.peachForestSurfaceFallbackCache, PEACH_FOREST, GLIMMERING_POOLS); + return resolveSurfaceFallback(x, z, sampler, this.peachForestSurfaceFallbackCache, PEACH_FOREST, GLIMMERING_POOLS, CLOUD_SEA); } return biome; @@ -320,6 +320,9 @@ public class ElythiaBiomeSource extends BiomeSource { } } result = nullToConfiguredFallback(result, x, this.surfaceBiomeSampleQuartY, z, sampler); + if (result != null && result.is(CLOUD_SEA) && this.defaultLandHolder != null) { + result = this.defaultLandHolder; + } cache.key = key; cache.value = result; @@ -384,7 +387,6 @@ public class ElythiaBiomeSource extends BiomeSource { if (this.ouranwoodForestHolder != null) return this.ouranwoodForestHolder; if (this.glimmeringPoolsHolder != null) return this.glimmeringPoolsHolder; if (this.oceanHolder != null) return this.oceanHolder; - if (this.cloudSeaHolder != null) return this.cloudSeaHolder; return this.firstConfiguredHolder; } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/worldgen/thoraxis/DimensionalTearFeature.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/worldgen/thoraxis/DimensionalTearFeature.java index c61e2eff..67cf31d8 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/worldgen/thoraxis/DimensionalTearFeature.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/content/worldgen/thoraxis/DimensionalTearFeature.java @@ -1,5 +1,6 @@ package com.craisinlord.antarchy.content.worldgen.thoraxis; +import com.craisinlord.antarchy.config.AntarchySettings; import com.craisinlord.antarchy.content.AntarchyObjects; import com.mojang.serialization.Codec; import net.minecraft.core.BlockPos; @@ -22,6 +23,10 @@ public final class DimensionalTearFeature extends Feature context) { + if (!AntarchySettings.dimensionalTearsSpawnNaturally()) { + return false; + } + WorldGenLevel level = context.level(); if (!(level instanceof ServerLevelAccessor)) { return false; diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/RoyalNoRespiteMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/RoyalNoRespiteMixin.java new file mode 100644 index 00000000..490b2d98 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/RoyalNoRespiteMixin.java @@ -0,0 +1,18 @@ +package com.craisinlord.antarchy.mixins; + +import com.craisinlord.antarchy.content.entity.royal.KingEntity; +import net.minecraft.world.entity.LivingEntity; +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(LivingEntity.class) +public abstract class RoyalNoRespiteMixin { + @Inject(method = "heal", at = @At("HEAD"), cancellable = true) + private void antarchy$blockRoyalNoRespiteHealing(float amount, CallbackInfo ci) { + if (KingEntity.blocksHealingAround((LivingEntity) (Object) this)) { + ci.cancel(); + } + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/AbstractArrowActionTimeDilationMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/AbstractArrowActionTimeDilationMixin.java new file mode 100644 index 00000000..f14765a1 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/AbstractArrowActionTimeDilationMixin.java @@ -0,0 +1,36 @@ +package com.craisinlord.antarchy.mixins.time; + +import com.craisinlord.antarchy.content.time.TimeDilationApi; +import net.minecraft.world.entity.projectile.AbstractArrow; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(AbstractArrow.class) +public abstract class AbstractArrowActionTimeDilationMixin { + @Shadow private int life; + @Shadow protected int inGroundTime; + @Shadow public int shakeTime; + + @Redirect(method = "tick", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/projectile/AbstractArrow;shakeTime:I", opcode = Opcodes.PUTFIELD)) + private void antarchy$slowShakeTime(AbstractArrow arrow, int value) { + if (TimeDilationApi.consumeTick(arrow, "arrow_shake")) this.shakeTime = value; + } + + @Redirect(method = "tick", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/projectile/AbstractArrow;inGroundTime:I", opcode = Opcodes.PUTFIELD, ordinal = 0)) + private void antarchy$slowInGroundTime(AbstractArrow arrow, int value) { + if (TimeDilationApi.consumeTick(arrow, "arrow_in_ground")) this.inGroundTime = value; + } + + @Redirect(method = "tick", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/projectile/AbstractArrow;inGroundTime:I", opcode = Opcodes.PUTFIELD, ordinal = 1)) + private void antarchy$resetInGroundTime(AbstractArrow arrow, int value) { + this.inGroundTime = value; + } + + @Redirect(method = "tickDespawn", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/projectile/AbstractArrow;life:I", opcode = Opcodes.PUTFIELD)) + private void antarchy$slowLifetime(AbstractArrow arrow, int value) { + if (TimeDilationApi.consumeTick(arrow, "arrow_lifetime")) this.life = value; + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/AbstractArrowMovementTimeDilationMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/AbstractArrowMovementTimeDilationMixin.java new file mode 100644 index 00000000..4ed3936d --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/AbstractArrowMovementTimeDilationMixin.java @@ -0,0 +1,30 @@ +package com.craisinlord.antarchy.mixins.time; + +import com.craisinlord.antarchy.content.time.TimeDilationApi; +import com.craisinlord.antarchy.content.time.TimeDilationMath; +import net.minecraft.world.entity.projectile.AbstractArrow; +import net.minecraft.world.phys.Vec3; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(AbstractArrow.class) +public abstract class AbstractArrowMovementTimeDilationMixin { + @Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/phys/Vec3;add(Lnet/minecraft/world/phys/Vec3;)Lnet/minecraft/world/phys/Vec3;")) + private Vec3 antarchy$slowCollisionPath(Vec3 position, Vec3 movement) { + double rate = TimeDilationApi.getRate((AbstractArrow) (Object) this); + return position.add(rate >= TimeDilationMath.NORMAL_RATE ? movement : movement.scale(rate)); + } + + @Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/AbstractArrow;setPos(DDD)V")) + private void antarchy$slowPosition(AbstractArrow arrow, double x, double y, double z) { + double rate = Math.max(TimeDilationMath.MIN_RATE, TimeDilationApi.getRate(arrow)); + if (rate >= TimeDilationMath.NORMAL_RATE) { + arrow.setPos(x, y, z); + return; + } + arrow.setPos(arrow.getX() + (x - arrow.getX()) * rate, + arrow.getY() + (y - arrow.getY()) * rate, + arrow.getZ() + (z - arrow.getZ()) * rate); + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/CreeperTimeDilationMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/CreeperTimeDilationMixin.java new file mode 100644 index 00000000..d9541586 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/CreeperTimeDilationMixin.java @@ -0,0 +1,16 @@ +package com.craisinlord.antarchy.mixins.time; + +import com.craisinlord.antarchy.content.time.TimeDilationApi; +import net.minecraft.world.entity.monster.Creeper; +import org.spongepowered.asm.mixin.Mixin; +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(Creeper.class) +public abstract class CreeperTimeDilationMixin { + @ModifyReturnValue(method = "getSwellDir", at = @At("RETURN")) + private int antarchy$slowSwellProgress(int direction) { + Creeper creeper = (Creeper) (Object) this; + return TimeDilationApi.consumeTick(creeper, "creeper_swell") ? direction : 0; + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/EndCrystalTimeDilationMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/EndCrystalTimeDilationMixin.java new file mode 100644 index 00000000..f6545b33 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/EndCrystalTimeDilationMixin.java @@ -0,0 +1,19 @@ +package com.craisinlord.antarchy.mixins.time; + +import com.craisinlord.antarchy.content.time.TimeDilationApi; +import net.minecraft.world.entity.boss.enderdragon.EndCrystal; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; + +@Mixin(EndCrystal.class) +public abstract class EndCrystalTimeDilationMixin { + @WrapOperation(method = "tick", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/boss/enderdragon/EndCrystal;time:I", opcode = Opcodes.PUTFIELD)) + private void antarchy$slowCrystalTime(EndCrystal crystal, int value, Operation original) { + if (TimeDilationApi.consumeTick(crystal, "end_crystal_time")) { + original.call(crystal, value); + } + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/EntityDeltaMovementTimeDilationMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/EntityDeltaMovementTimeDilationMixin.java index 0720cc14..834d3b71 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/EntityDeltaMovementTimeDilationMixin.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/EntityDeltaMovementTimeDilationMixin.java @@ -15,7 +15,8 @@ public abstract class EntityDeltaMovementTimeDilationMixin { private Vec3 antarchy$scaleTimeDilatedVelocityChange(Vec3 nextMovement) { Entity entity = (Entity) (Object) this; if (!(entity instanceof TimeDilationEntityAccess access) - || access.antarchy$isInTimeDilationMove()) { + || access.antarchy$isInTimeDilationMove() + || access.antarchy$isApplyingExternalImpulse()) { return nextMovement; } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/EntityRotationTimeDilationMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/EntityRotationTimeDilationMixin.java new file mode 100644 index 00000000..92667d79 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/EntityRotationTimeDilationMixin.java @@ -0,0 +1,32 @@ +package com.craisinlord.antarchy.mixins.time; + +import com.craisinlord.antarchy.content.time.TimeDilationApi; +import com.craisinlord.antarchy.content.time.TimeDilationMath; +import net.minecraft.util.Mth; +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.ModifyVariable; + +@Mixin(Entity.class) +public abstract class EntityRotationTimeDilationMixin { + @ModifyVariable(method = "setYRot", at = @At("HEAD"), argsOnly = true) + private float antarchy$slowYaw(float nextYaw) { + Entity entity = (Entity) (Object) this; + double rate = TimeDilationApi.getRate(entity); + if (rate >= TimeDilationMath.NORMAL_RATE) { + return nextYaw; + } + return entity.getYRot() + Mth.wrapDegrees(nextYaw - entity.getYRot()) * (float) rate; + } + + @ModifyVariable(method = "setXRot", at = @At("HEAD"), argsOnly = true) + private float antarchy$slowPitch(float nextPitch) { + Entity entity = (Entity) (Object) this; + double rate = TimeDilationApi.getRate(entity); + if (rate >= TimeDilationMath.NORMAL_RATE) { + return nextPitch; + } + return entity.getXRot() + (nextPitch - entity.getXRot()) * (float) rate; + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/EntityTimeDilationStateMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/EntityTimeDilationStateMixin.java index bc170b3d..69f8c82d 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/EntityTimeDilationStateMixin.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/EntityTimeDilationStateMixin.java @@ -16,6 +16,8 @@ public abstract class EntityTimeDilationStateMixin implements TimeDilationEntity private final Map antarchy$timeDilationTimerProgress = new HashMap<>(); @Unique private boolean antarchy$inTimeDilationMove; + @Unique + private boolean antarchy$applyingExternalImpulse; @Override public double antarchy$getTimeDilationRate() { @@ -57,4 +59,14 @@ public abstract class EntityTimeDilationStateMixin implements TimeDilationEntity public void antarchy$setInTimeDilationMove(boolean inMove) { this.antarchy$inTimeDilationMove = inMove; } + + @Override + public boolean antarchy$isApplyingExternalImpulse() { + return this.antarchy$applyingExternalImpulse; + } + + @Override + public void antarchy$setApplyingExternalImpulse(boolean applying) { + this.antarchy$applyingExternalImpulse = applying; + } } diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/HurtingProjectileMovementTimeDilationMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/HurtingProjectileMovementTimeDilationMixin.java new file mode 100644 index 00000000..1f717d6f --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/HurtingProjectileMovementTimeDilationMixin.java @@ -0,0 +1,23 @@ +package com.craisinlord.antarchy.mixins.time; + +import com.craisinlord.antarchy.content.time.TimeDilationApi; +import com.craisinlord.antarchy.content.time.TimeDilationMath; +import net.minecraft.world.entity.projectile.AbstractHurtingProjectile; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(AbstractHurtingProjectile.class) +public abstract class HurtingProjectileMovementTimeDilationMixin { + @Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/AbstractHurtingProjectile;setPos(DDD)V")) + private void antarchy$slowPosition(AbstractHurtingProjectile projectile, double x, double y, double z) { + double rate = Math.max(TimeDilationMath.MIN_RATE, TimeDilationApi.getRate(projectile)); + if (rate >= TimeDilationMath.NORMAL_RATE) { + projectile.setPos(x, y, z); + return; + } + projectile.setPos(projectile.getX() + (x - projectile.getX()) * rate, + projectile.getY() + (y - projectile.getY()) * rate, + projectile.getZ() + (z - projectile.getZ()) * rate); + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/ItemEntityRendererTimeDilationMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/ItemEntityRendererTimeDilationMixin.java new file mode 100644 index 00000000..514e6c30 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/ItemEntityRendererTimeDilationMixin.java @@ -0,0 +1,43 @@ +package com.craisinlord.antarchy.mixins.time; + +import com.craisinlord.antarchy.content.client.ClientTimeDilationTicker; +import net.minecraft.client.renderer.entity.ItemEntityRenderer; +import net.minecraft.world.entity.item.ItemEntity; +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.ModifyArg; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ItemEntityRenderer.class) +public abstract class ItemEntityRendererTimeDilationMixin { + @Unique + private static final ThreadLocal antarchy$renderingItem = new ThreadLocal<>(); + + @Inject(method = "render", at = @At("HEAD")) + private void antarchy$beginItemRender(ItemEntity item, float entityYaw, float partialTick, + com.mojang.blaze3d.vertex.PoseStack poseStack, + net.minecraft.client.renderer.MultiBufferSource buffer, + int packedLight, CallbackInfo ci) { + antarchy$renderingItem.set(item); + } + + @Inject(method = "render", at = @At("RETURN")) + private void antarchy$endItemRender(ItemEntity item, float entityYaw, float partialTick, + com.mojang.blaze3d.vertex.PoseStack poseStack, + net.minecraft.client.renderer.MultiBufferSource buffer, + int packedLight, CallbackInfo ci) { + antarchy$renderingItem.remove(); + } + + @ModifyArg(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Mth;sin(F)F"), index = 0) + private float antarchy$slowItemBob(float phase) { + ItemEntity item = antarchy$renderingItem.get(); + if (item == null) { + return phase; + } + double rate = com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(item); + return rate >= 1.0D ? phase : phase * (float) rate; + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/ItemEntityRotationTimeDilationMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/ItemEntityRotationTimeDilationMixin.java new file mode 100644 index 00000000..f9bcd369 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/ItemEntityRotationTimeDilationMixin.java @@ -0,0 +1,15 @@ +package com.craisinlord.antarchy.mixins.time; + +import com.craisinlord.antarchy.content.client.ClientTimeDilationTicker; +import net.minecraft.world.entity.item.ItemEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import com.llamalad7.mixinextras.injector.ModifyReturnValue; + +@Mixin(ItemEntity.class) +public abstract class ItemEntityRotationTimeDilationMixin { + @ModifyReturnValue(method = "getSpin", at = @At("RETURN")) + private float antarchy$slowSpin(float spin) { + return ClientTimeDilationTicker.dilateItemSpin((ItemEntity) (Object) this, spin); + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/LivingEntityAttackCooldownTimeDilationMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/LivingEntityAttackCooldownTimeDilationMixin.java new file mode 100644 index 00000000..0415fb3c --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/LivingEntityAttackCooldownTimeDilationMixin.java @@ -0,0 +1,23 @@ +package com.craisinlord.antarchy.mixins.time; + +import com.craisinlord.antarchy.content.time.TimeDilationApi; +import net.minecraft.world.entity.LivingEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(LivingEntity.class) +public abstract class LivingEntityAttackCooldownTimeDilationMixin { + @Shadow + private int attackStrengthTicker; + + @Inject(method = "tick", at = @At("RETURN")) + private void antarchy$slowAttackCooldown(CallbackInfo ci) { + LivingEntity entity = (LivingEntity) (Object) this; + if (!TimeDilationApi.consumeTick(entity, "living_attack_cooldown")) { + this.attackStrengthTicker = Math.max(0, this.attackStrengthTicker - 1); + } + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/LivingEntityKnockbackTimeDilationMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/LivingEntityKnockbackTimeDilationMixin.java new file mode 100644 index 00000000..1b033a45 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/LivingEntityKnockbackTimeDilationMixin.java @@ -0,0 +1,25 @@ +package com.craisinlord.antarchy.mixins.time; + +import com.craisinlord.antarchy.content.time.TimeDilationEntityAccess; +import net.minecraft.world.entity.LivingEntity; +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(LivingEntity.class) +public abstract class LivingEntityKnockbackTimeDilationMixin { + @Inject(method = "knockback", at = @At("HEAD")) + private void antarchy$beginExternalImpulse(double strength, double x, double z, CallbackInfo ci) { + if (this instanceof TimeDilationEntityAccess access) { + access.antarchy$setApplyingExternalImpulse(true); + } + } + + @Inject(method = "knockback", at = @At("RETURN")) + private void antarchy$endExternalImpulse(double strength, double x, double z, CallbackInfo ci) { + if (this instanceof TimeDilationEntityAccess access) { + access.antarchy$setApplyingExternalImpulse(false); + } + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/LivingEntityRendererAnimationTimeDilationMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/LivingEntityRendererAnimationTimeDilationMixin.java index 01a279aa..e2d0d06c 100644 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/LivingEntityRendererAnimationTimeDilationMixin.java +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/LivingEntityRendererAnimationTimeDilationMixin.java @@ -4,11 +4,72 @@ import com.craisinlord.antarchy.content.client.ClientTimeDilationTicker; import com.llamalad7.mixinextras.injector.ModifyReturnValue; import net.minecraft.client.renderer.entity.LivingEntityRenderer; import net.minecraft.world.entity.LivingEntity; +import net.minecraft.util.Mth; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @Mixin(LivingEntityRenderer.class) public abstract class LivingEntityRendererAnimationTimeDilationMixin { + private static final ThreadLocal antarchy$renderingEntity = new ThreadLocal<>(); + + @org.spongepowered.asm.mixin.injection.Inject(method = "render", at = @At("HEAD")) + private void antarchy$beginRender(LivingEntity entity, float entityYaw, float partialTick, + com.mojang.blaze3d.vertex.PoseStack poseStack, + net.minecraft.client.renderer.MultiBufferSource buffer, + int packedLight, org.spongepowered.asm.mixin.injection.callback.CallbackInfo ci) { + antarchy$renderingEntity.set(entity); + } + + @org.spongepowered.asm.mixin.injection.Inject(method = "render", at = @At("RETURN")) + private void antarchy$endRender(LivingEntity entity, float entityYaw, float partialTick, + com.mojang.blaze3d.vertex.PoseStack poseStack, + net.minecraft.client.renderer.MultiBufferSource buffer, + int packedLight, org.spongepowered.asm.mixin.injection.callback.CallbackInfo ci) { + antarchy$renderingEntity.remove(); + } + + @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Mth;rotLerp(FFF)F", ordinal = 0)) + private float antarchy$slowBodyYaw(float partialTick, float previous, float current) { + LivingEntity entity = antarchy$renderingEntity.get(); + return entity == null ? Mth.rotLerp(partialTick, previous, current) + : ClientTimeDilationTicker.dilateRotation(entity, previous, current, partialTick); + } + + @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Mth;rotLerp(FFF)F", ordinal = 1)) + private float antarchy$slowHeadYaw(float partialTick, float previous, float current) { + LivingEntity entity = antarchy$renderingEntity.get(); + return entity == null ? Mth.rotLerp(partialTick, previous, current) + : ClientTimeDilationTicker.dilateRotation(entity, previous, current, partialTick); + } + + @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Mth;lerp(FFF)F", ordinal = 0)) + private float antarchy$slowHeadPitch(float partialTick, float previous, float current) { + LivingEntity entity = antarchy$renderingEntity.get(); + return entity == null ? Mth.lerp(partialTick, previous, current) + : ClientTimeDilationTicker.dilatePitch(entity, previous, current, partialTick); + } + + @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/WalkAnimationState;speed(F)F")) + private float antarchy$slowWalkAmount(net.minecraft.world.entity.WalkAnimationState state, float partialTick) { + LivingEntity entity = antarchy$renderingEntity.get(); + float amount = state.speed(partialTick); + return entity == null ? amount : ClientTimeDilationTicker.dilateWalkAmount(entity, amount); + } + + @org.spongepowered.asm.mixin.injection.Inject(method = "getOverlayCoords", at = @At("HEAD"), cancellable = true) + private static void antarchy$slowHurtOverlay(LivingEntity entity, float partialTick, CallbackInfoReturnable cir) { + if (com.craisinlord.antarchy.content.time.TimeDilationApi.getRate(entity) < 1.0D + && (entity.hurtTime > 0 || entity.deathTime > 0)) { + cir.setReturnValue(net.minecraft.client.renderer.texture.OverlayTexture.pack(1.0F, entity.deathTime > 0)); + } + } + @ModifyReturnValue(method = "getAttackAnim", at = @At("RETURN")) + private float antarchy$slowAttackAnimation(float animation, LivingEntity entity, float partialTick) { + return ClientTimeDilationTicker.dilateAttackAnimation(entity, partialTick, animation); + } + @ModifyReturnValue(method = "getBob", at = @At("RETURN")) private float antarchy$slowIdleAnimation(float bob, LivingEntity entity, float partialTick) { return ClientTimeDilationTicker.dilateAnimationTime(entity, bob); diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/ParticlePositionAccessor.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/ParticlePositionAccessor.java new file mode 100644 index 00000000..c38a965e --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/ParticlePositionAccessor.java @@ -0,0 +1,17 @@ +package com.craisinlord.antarchy.mixins.time; + +import net.minecraft.client.particle.Particle; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(Particle.class) +public interface ParticlePositionAccessor { + @Accessor("x") + double antarchy$getX(); + + @Accessor("y") + double antarchy$getY(); + + @Accessor("z") + double antarchy$getZ(); +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/PortalParticleTimeDilationMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/PortalParticleTimeDilationMixin.java new file mode 100644 index 00000000..ec676bb8 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/PortalParticleTimeDilationMixin.java @@ -0,0 +1,30 @@ +package com.craisinlord.antarchy.mixins.time; + +import com.craisinlord.antarchy.content.client.ClientTimeDilationTicker; +import net.minecraft.client.particle.PortalParticle; +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(PortalParticle.class) +public abstract class PortalParticleTimeDilationMixin { + @Unique + private double antarchy$timeProgress; + + @Inject(method = "tick", at = @At("HEAD"), cancellable = true) + private void antarchy$slowPortalParticle(CallbackInfo ci) { + ParticlePositionAccessor position = (ParticlePositionAccessor) (Object) this; + double rate = ClientTimeDilationTicker.rateAt(position.antarchy$getX(), position.antarchy$getY(), position.antarchy$getZ()); + if (rate >= 1.0D) { + return; + } + this.antarchy$timeProgress += rate; + if (this.antarchy$timeProgress < 1.0D) { + ci.cancel(); + } else { + this.antarchy$timeProgress -= 1.0D; + } + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/ProjectileMovementTimeDilationMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/ProjectileMovementTimeDilationMixin.java deleted file mode 100644 index 90a3dd7d..00000000 --- a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/ProjectileMovementTimeDilationMixin.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.craisinlord.antarchy.mixins.time; - -import com.craisinlord.antarchy.content.time.TimeDilationApi; -import com.craisinlord.antarchy.content.time.TimeDilationMath; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.projectile.AbstractArrow; -import net.minecraft.world.entity.projectile.AbstractHurtingProjectile; -import net.minecraft.world.entity.projectile.ThrowableProjectile; -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({AbstractArrow.class, ThrowableProjectile.class, AbstractHurtingProjectile.class}) -public abstract class ProjectileMovementTimeDilationMixin { - @Unique - private Vec3 antarchy$preTickPos; - @Unique - private Vec3 antarchy$preTickDelta; - - @Inject(method = "tick", at = @At("HEAD")) - private void antarchy$recordPreTickMotion(CallbackInfo ci) { - Entity entity = (Entity) (Object) this; - if (TimeDilationApi.getRate(entity) < TimeDilationMath.NORMAL_RATE) { - this.antarchy$preTickPos = entity.position(); - this.antarchy$preTickDelta = entity.getDeltaMovement(); - } else { - this.antarchy$preTickPos = null; - this.antarchy$preTickDelta = null; - } - } - - @Inject(method = "tick", at = @At("RETURN")) - private void antarchy$scaleTickDisplacement(CallbackInfo ci) { - Vec3 pre = this.antarchy$preTickPos; - Vec3 preDelta = this.antarchy$preTickDelta; - this.antarchy$preTickPos = null; - this.antarchy$preTickDelta = null; - if (pre == null) { - return; - } - - Entity entity = (Entity) (Object) this; - if (entity.isRemoved()) { - return; - } - double rate = TimeDilationApi.getRate(entity); - if (rate >= TimeDilationMath.NORMAL_RATE) { - return; - } - - Vec3 actual = entity.position().subtract(pre); - if (actual.lengthSqr() < 1.0E-12D) { - return; - } - if (preDelta != null && actual.lengthSqr() + 1.0E-9D < preDelta.lengthSqr()) { - return; - } - - Vec3 lerped = pre.add(actual.scale(rate)); - entity.setPos(lerped.x, lerped.y, lerped.z); - } -} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/ReversePortalParticleTimeDilationMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/ReversePortalParticleTimeDilationMixin.java new file mode 100644 index 00000000..a7d5aa85 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/ReversePortalParticleTimeDilationMixin.java @@ -0,0 +1,30 @@ +package com.craisinlord.antarchy.mixins.time; + +import com.craisinlord.antarchy.content.client.ClientTimeDilationTicker; +import net.minecraft.client.particle.ReversePortalParticle; +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(ReversePortalParticle.class) +public abstract class ReversePortalParticleTimeDilationMixin { + @Unique + private double antarchy$timeProgress; + + @Inject(method = "tick", at = @At("HEAD"), cancellable = true) + private void antarchy$slowReversePortalParticle(CallbackInfo ci) { + ParticlePositionAccessor position = (ParticlePositionAccessor) (Object) this; + double rate = ClientTimeDilationTicker.rateAt(position.antarchy$getX(), position.antarchy$getY(), position.antarchy$getZ()); + if (rate >= 1.0D) { + return; + } + this.antarchy$timeProgress += rate; + if (this.antarchy$timeProgress < 1.0D) { + ci.cancel(); + } else { + this.antarchy$timeProgress -= 1.0D; + } + } +} diff --git a/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/ThrowableProjectileMovementTimeDilationMixin.java b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/ThrowableProjectileMovementTimeDilationMixin.java new file mode 100644 index 00000000..23f8de85 --- /dev/null +++ b/common-1.21.1/src/main/java/com/craisinlord/antarchy/mixins/time/ThrowableProjectileMovementTimeDilationMixin.java @@ -0,0 +1,23 @@ +package com.craisinlord.antarchy.mixins.time; + +import com.craisinlord.antarchy.content.time.TimeDilationApi; +import com.craisinlord.antarchy.content.time.TimeDilationMath; +import net.minecraft.world.entity.projectile.ThrowableProjectile; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(ThrowableProjectile.class) +public abstract class ThrowableProjectileMovementTimeDilationMixin { + @Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/ThrowableProjectile;setPos(DDD)V")) + private void antarchy$slowPosition(ThrowableProjectile projectile, double x, double y, double z) { + double rate = Math.max(TimeDilationMath.MIN_RATE, TimeDilationApi.getRate(projectile)); + if (rate >= TimeDilationMath.NORMAL_RATE) { + projectile.setPos(x, y, z); + return; + } + projectile.setPos(projectile.getX() + (x - projectile.getX()) * rate, + projectile.getY() + (y - projectile.getY()) * rate, + projectile.getZ() + (z - projectile.getZ()) * rate); + } +} diff --git a/common-1.21.1/src/main/resources/antarchy-common.mixins.json b/common-1.21.1/src/main/resources/antarchy-common.mixins.json index 1ada941d..77a33c27 100644 --- a/common-1.21.1/src/main/resources/antarchy-common.mixins.json +++ b/common-1.21.1/src/main/resources/antarchy-common.mixins.json @@ -30,6 +30,7 @@ "GlowVinesUnderLeavesMixin", "GrindstoneMenuMixin", "LivingEntityJumpingAccessor", + "RoyalNoRespiteMixin", "MantisClawWallClimbMixin", "MilkBucketSizeResetMixin", "MinecartItemMixin", @@ -82,12 +83,20 @@ "time.EntityDeltaMovementTimeDilationMixin", "time.EntityMoveTimeDilationMixin", "time.EntityTimeDilationStateMixin", - "time.LivingEntityTimeDilationMixin", + "time.EntityRotationTimeDilationMixin", + "time.LivingEntityKnockbackTimeDilationMixin", + "time.CreeperTimeDilationMixin", + "time.EndCrystalTimeDilationMixin", + "time.LivingEntityTimeDilationMixin", + "time.LivingEntityAttackCooldownTimeDilationMixin", "time.LookControlTimeDilationMixin", "time.MeleeAttackGoalTimeDilationMixin", "time.MobAttackTimeDilationMixin", "time.PrimedTntTimeDilationMixin", - "time.ProjectileMovementTimeDilationMixin", + "time.AbstractArrowMovementTimeDilationMixin", + "time.ThrowableProjectileMovementTimeDilationMixin", + "time.HurtingProjectileMovementTimeDilationMixin", + "time.AbstractArrowActionTimeDilationMixin", "time.RangedAttackGoalTimeDilationMixin", "time.RangedBowAttackGoalTimeDilationMixin" ], @@ -124,7 +133,12 @@ "gravity.client.FallingBlockRendererBlockEntityMixin", "time.LivingEntityRendererAnimationTimeDilationMixin", "time.ParticleTimeDilationMixin", - "time.SoundEngineTimeDilationMixin" + "time.PortalParticleTimeDilationMixin", + "time.ReversePortalParticleTimeDilationMixin", + "time.SoundEngineTimeDilationMixin", + "time.ItemEntityRotationTimeDilationMixin", + "time.ItemEntityRendererTimeDilationMixin", + "time.ParticlePositionAccessor" ], "injectors": { "defaultRequire": 1 diff --git a/common-1.21.1/src/main/resources/assets/antarchy/lang/en_us.json b/common-1.21.1/src/main/resources/assets/antarchy/lang/en_us.json index 3a43397e..a49aab9a 100644 --- a/common-1.21.1/src/main/resources/assets/antarchy/lang/en_us.json +++ b/common-1.21.1/src/main/resources/assets/antarchy/lang/en_us.json @@ -549,7 +549,6 @@ "item.antarchy.queen_scale": "Queen Scale", "item.antarchy.jerry_nucleus": "Jerry Nucleus", "tooltip.antarchy.jerry_nucleus.hatch": "While holding, interact with any bug egg or turtle egg to hatch it instantly.", - "key.antarchy.dorrie_charge_jump": "Dorrie Charge Jump", "key.antarchy.mount_special": "Mount: Special / Charge", "key.antarchy.mount_flight_toggle": "Mount: Toggle Flight", "item.antarchy.jumpy_bug_leg": "Jumpy Bug Leg", @@ -800,6 +799,10 @@ "advancements.antarchy.cops_n_robbers.description": "This is just a nostalgic structure, no affiliation with Sky :)", "advancements.antarchy.fallen_king_crown.title": "Chunks would load when I gave the word...", "advancements.antarchy.fallen_king_crown.description": "Obtain the Fallen King\u0027s Crown.", + "advancements.antarchy.long_live_the_prince.title": "Long Live the Prince", + "advancements.antarchy.long_live_the_prince.description": "Hatch and tame a Prince.", + "advancements.antarchy.long_live_the_princess.title": "Long Live the Princess", + "advancements.antarchy.long_live_the_princess.description": "Hatch and tame a Princess.", "advancements.antarchy.the_lab.title": "Hey everyone, Dan here", "advancements.antarchy.the_lab.description": "Discover Dr. Trayaurus\u0027 lab.", "advancements.antarchy.sweater_dreams.title": "Sweeter Dreams", @@ -1036,6 +1039,16 @@ "subtitles.antarchy.queen_beam_end": "The Queen's beam fades", "subtitles.antarchy.queen_black_hole_shoot": "The Queen tears open a singularity", "subtitles.antarchy.queen_cast_shoot": "The Queen casts", + "subtitles.antarchy.prince_idle": "The Prince chitters", + "subtitles.antarchy.prince_bite": "The Prince bites", + "subtitles.antarchy.prince_shoot": "The Prince spits a volley", + "subtitles.antarchy.prince_fly": "The Prince's wings beat", + "subtitles.antarchy.prince_step": "The Prince's footfalls", + "subtitles.antarchy.princess_idle": "The Princess chitters", + "subtitles.antarchy.princess_bite": "The Princess bites", + "subtitles.antarchy.princess_shoot": "The Princess spits a volley", + "subtitles.antarchy.princess_fly": "The Princess's wings beat", + "subtitles.antarchy.princess_step": "The Princess's footfalls", "subtitles.antarchy.stinky_fly": "Stinky flies buzz", "item.minecraft.potion.effect.inversion": "Potion of Inversion", "item.minecraft.potion.effect.long_inversion": "Potion of Inversion", @@ -1167,6 +1180,7 @@ "entity.antarchy.king": "The King", "entity.antarchy.queen": "The Queen", "entity.antarchy.manticore": "Manticore", + "entity.antarchy.royal_black_hole": "Singularity", "entity.antarchy.royal_bolt": "Royal Bolt", "block.antarchy.prince_egg": "Prince Egg", "block.antarchy.princess_egg": "Princess Egg", @@ -1323,4 +1337,32 @@ "block.antarchy.chiseled_loam_bricks": "Chiseled Loam Bricks", "item.antarchy.cooked_cheep": "Cooked Cheep", "item.antarchy.cheep_bucket": "Bucket of Cheep" + ,"decree.antarchy.the_sky_is_mine": "THE SKY IS MINE" + ,"decree.antarchy.the_sky_is_mine.subtitle": "Stay grounded." + ,"decree.antarchy.do_not_run": "DO NOT RUN" + ,"decree.antarchy.do_not_run.subtitle": "Stop sprinting." + ,"decree.antarchy.kneel": "KNEEL" + ,"decree.antarchy.kneel.subtitle": "Crouch within five seconds." + ,"decree.antarchy.close_quarters": "CLOSE QUARTERS" + ,"decree.antarchy.close_quarters.subtitle": "Projectiles are forbidden." + ,"decree.antarchy.come_no_closer": "COME NO CLOSER" + ,"decree.antarchy.come_no_closer.subtitle": "Keep out of the King's inner radius." + ,"decree.antarchy.fight_me_coward": "FIGHT ME, COWARD!" + ,"decree.antarchy.fight_me_coward.subtitle": "Approach the King." + ,"decree.antarchy.no_respite": "NO RESPITE" + ,"decree.antarchy.no_respite.subtitle": "Healing is sealed." + ,"decree.antarchy.no_retreat": "NO RETREAT" + ,"decree.antarchy.no_retreat.subtitle": "Do not flee the King's presence." + ,"decree.antarchy.keep_your_distance": "KEEP YOUR DISTANCE" + ,"decree.antarchy.keep_your_distance.subtitle": "Stay out of the King's reach." + ,"decree.antarchy.stand_tall": "STAND TALL" + ,"decree.antarchy.stand_tall.subtitle": "Do not crouch before the King." + ,"decree.antarchy.stand_your_ground": "STAND YOUR GROUND" + ,"decree.antarchy.stand_your_ground.subtitle": "Do not stray from where you stand." + ,"decree.antarchy.hands_off_the_crown": "HANDS OFF THE CROWN" + ,"decree.antarchy.hands_off_the_crown.subtitle": "Strike the King and be judged." + ,"decree.antarchy.advance": "ADVANCE" + ,"decree.antarchy.advance.subtitle": "Close on the King or be judged." + ,"decree.antarchy.show_no_mercy": "SHOW NO MERCY" + ,"decree.antarchy.show_no_mercy.subtitle": "Keep dealing damage." } diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds.json b/common-1.21.1/src/main/resources/assets/antarchy/sounds.json index 9b18c956..433fe69f 100644 --- a/common-1.21.1/src/main/resources/assets/antarchy/sounds.json +++ b/common-1.21.1/src/main/resources/assets/antarchy/sounds.json @@ -2940,5 +2940,83 @@ "name": "antarchy:mob/queen/fireball_shoot" } ] + }, + "prince_idle": { + "subtitle": "subtitles.antarchy.prince_idle", + "sounds": [ + { "name": "antarchy:mob/prince/idle1" }, + { "name": "antarchy:mob/prince/idle2" } + ] + }, + "prince_bite": { + "subtitle": "subtitles.antarchy.prince_bite", + "sounds": [ + { "name": "antarchy:mob/prince/bite1" } + ] + }, + "prince_shoot": { + "subtitle": "subtitles.antarchy.prince_shoot", + "sounds": [ + { "name": "antarchy:mob/prince/shoot1" } + ] + }, + "prince_fly": { + "subtitle": "subtitles.antarchy.prince_fly", + "sounds": [ + { "name": "antarchy:mob/prince/flt4" }, + { "name": "antarchy:mob/prince/fly1" }, + { "name": "antarchy:mob/prince/fly2" }, + { "name": "antarchy:mob/prince/fly3" }, + { "name": "antarchy:mob/prince/fly5" }, + { "name": "antarchy:mob/prince/fly6" } + ] + }, + "prince_step": { + "subtitle": "subtitles.antarchy.prince_step", + "sounds": [ + { "name": "antarchy:mob/prince/walk1" }, + { "name": "antarchy:mob/prince/walk2" }, + { "name": "antarchy:mob/prince/walk3" }, + { "name": "antarchy:mob/prince/walk4" } + ] + }, + "princess_idle": { + "subtitle": "subtitles.antarchy.princess_idle", + "sounds": [ + { "name": "antarchy:mob/princess/idle1" }, + { "name": "antarchy:mob/princess/idle2" } + ] + }, + "princess_bite": { + "subtitle": "subtitles.antarchy.princess_bite", + "sounds": [ + { "name": "antarchy:mob/princess/bite1" } + ] + }, + "princess_shoot": { + "subtitle": "subtitles.antarchy.princess_shoot", + "sounds": [ + { "name": "antarchy:mob/princess/shoot1" } + ] + }, + "princess_fly": { + "subtitle": "subtitles.antarchy.princess_fly", + "sounds": [ + { "name": "antarchy:mob/princess/flt4" }, + { "name": "antarchy:mob/princess/fly1" }, + { "name": "antarchy:mob/princess/fly2" }, + { "name": "antarchy:mob/princess/fly3" }, + { "name": "antarchy:mob/princess/fly5" }, + { "name": "antarchy:mob/princess/fly6" } + ] + }, + "princess_step": { + "subtitle": "subtitles.antarchy.princess_step", + "sounds": [ + { "name": "antarchy:mob/princess/walk1" }, + { "name": "antarchy:mob/princess/walk2" }, + { "name": "antarchy:mob/princess/walk3" }, + { "name": "antarchy:mob/princess/walk4" } + ] } } diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/bite1.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/bite1.ogg new file mode 100644 index 00000000..59a0ee3a Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/bite1.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/flt4.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/flt4.ogg new file mode 100644 index 00000000..b1cffa7b Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/flt4.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/fly1.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/fly1.ogg new file mode 100644 index 00000000..6319fc08 Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/fly1.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/fly2.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/fly2.ogg new file mode 100644 index 00000000..c9f2e383 Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/fly2.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/fly3.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/fly3.ogg new file mode 100644 index 00000000..6f3dd34a Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/fly3.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/fly5.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/fly5.ogg new file mode 100644 index 00000000..58243908 Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/fly5.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/fly6.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/fly6.ogg new file mode 100644 index 00000000..a8ccecab Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/fly6.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/idle1.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/idle1.ogg new file mode 100644 index 00000000..cd2e45f4 Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/idle1.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/idle2.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/idle2.ogg new file mode 100644 index 00000000..342f727f Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/idle2.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/shoot1.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/shoot1.ogg new file mode 100644 index 00000000..cd90afe7 Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/shoot1.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/walk1.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/walk1.ogg new file mode 100644 index 00000000..4b24dd3a Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/walk1.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/walk2.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/walk2.ogg new file mode 100644 index 00000000..e1a1e6aa Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/walk2.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/walk3.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/walk3.ogg new file mode 100644 index 00000000..ae165bf4 Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/walk3.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/walk4.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/walk4.ogg new file mode 100644 index 00000000..6695876f Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/prince/walk4.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/bite1.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/bite1.ogg new file mode 100644 index 00000000..59a0ee3a Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/bite1.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/flt4.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/flt4.ogg new file mode 100644 index 00000000..b1cffa7b Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/flt4.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/fly1.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/fly1.ogg new file mode 100644 index 00000000..6319fc08 Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/fly1.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/fly2.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/fly2.ogg new file mode 100644 index 00000000..c9f2e383 Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/fly2.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/fly3.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/fly3.ogg new file mode 100644 index 00000000..6f3dd34a Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/fly3.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/fly5.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/fly5.ogg new file mode 100644 index 00000000..58243908 Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/fly5.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/fly6.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/fly6.ogg new file mode 100644 index 00000000..a8ccecab Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/fly6.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/idle1.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/idle1.ogg new file mode 100644 index 00000000..cd2e45f4 Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/idle1.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/idle2.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/idle2.ogg new file mode 100644 index 00000000..342f727f Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/idle2.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/shoot1.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/shoot1.ogg new file mode 100644 index 00000000..cd90afe7 Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/shoot1.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/walk1.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/walk1.ogg new file mode 100644 index 00000000..4b24dd3a Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/walk1.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/walk2.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/walk2.ogg new file mode 100644 index 00000000..e1a1e6aa Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/walk2.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/walk3.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/walk3.ogg new file mode 100644 index 00000000..ae165bf4 Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/walk3.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/walk4.ogg b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/walk4.ogg new file mode 100644 index 00000000..6695876f Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/sounds/mob/princess/walk4.ogg differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/fire_beam_end_1.png b/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/fire_beam_end_1.png new file mode 100644 index 00000000..d0cad387 Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/fire_beam_end_1.png differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/fire_beam_end_2.png b/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/fire_beam_end_2.png new file mode 100644 index 00000000..0433b515 Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/fire_beam_end_2.png differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/fire_beam_inner.png b/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/fire_beam_inner.png new file mode 100644 index 00000000..7e58eb62 Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/fire_beam_inner.png differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/fire_beam_outer.png b/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/fire_beam_outer.png new file mode 100644 index 00000000..69056eaf Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/fire_beam_outer.png differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/lightning_beam_end_1.png b/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/lightning_beam_end_1.png new file mode 100644 index 00000000..be830b53 Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/lightning_beam_end_1.png differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/lightning_beam_end_2.png b/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/lightning_beam_end_2.png new file mode 100644 index 00000000..fdd601cd Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/lightning_beam_end_2.png differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/lightning_beam_inner.png b/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/lightning_beam_inner.png new file mode 100644 index 00000000..c1b4cfcb Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/lightning_beam_inner.png differ diff --git a/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/lightning_beam_outer.png b/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/lightning_beam_outer.png new file mode 100644 index 00000000..261a037e Binary files /dev/null and b/common-1.21.1/src/main/resources/assets/antarchy/textures/entity/king/lightning_beam_outer.png differ diff --git a/common-1.21.1/src/main/resources/data/antarchy/advancement/long_live_the_prince.json b/common-1.21.1/src/main/resources/data/antarchy/advancement/long_live_the_prince.json new file mode 100644 index 00000000..bd7b288a --- /dev/null +++ b/common-1.21.1/src/main/resources/data/antarchy/advancement/long_live_the_prince.json @@ -0,0 +1,34 @@ +{ + "parent": "antarchy:fallen_kingdom_castle", + "criteria": { + "tame_prince": { + "conditions": { + "entity": { + "type": "antarchy:prince" + } + }, + "trigger": "minecraft:tame_animal" + } + }, + "display": { + "announce_to_chat": true, + "description": { + "translate": "advancements.antarchy.long_live_the_prince.description" + }, + "frame": "goal", + "icon": { + "count": 1, + "id": "antarchy:prince_egg" + }, + "show_toast": true, + "title": { + "translate": "advancements.antarchy.long_live_the_prince.title" + } + }, + "requirements": [ + [ + "tame_prince" + ] + ], + "sends_telemetry_event": true +} diff --git a/common-1.21.1/src/main/resources/data/antarchy/advancement/long_live_the_princess.json b/common-1.21.1/src/main/resources/data/antarchy/advancement/long_live_the_princess.json new file mode 100644 index 00000000..d12d5e02 --- /dev/null +++ b/common-1.21.1/src/main/resources/data/antarchy/advancement/long_live_the_princess.json @@ -0,0 +1,34 @@ +{ + "parent": "antarchy:fallen_kingdom_castle", + "criteria": { + "tame_princess": { + "conditions": { + "entity": { + "type": "antarchy:princess" + } + }, + "trigger": "minecraft:tame_animal" + } + }, + "display": { + "announce_to_chat": true, + "description": { + "translate": "advancements.antarchy.long_live_the_princess.description" + }, + "frame": "goal", + "icon": { + "count": 1, + "id": "antarchy:princess_egg" + }, + "show_toast": true, + "title": { + "translate": "advancements.antarchy.long_live_the_princess.title" + } + }, + "requirements": [ + [ + "tame_princess" + ] + ], + "sends_telemetry_event": true +} diff --git a/common-1.21.1/src/main/resources/data/antarchy/loot_table/entities/king.json b/common-1.21.1/src/main/resources/data/antarchy/loot_table/entities/king.json new file mode 100644 index 00000000..b949f080 --- /dev/null +++ b/common-1.21.1/src/main/resources/data/antarchy/loot_table/entities/king.json @@ -0,0 +1,109 @@ +{ + "type": "minecraft:entity", + "random_sequence": "antarchy:entities/king", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "antarchy:prince_egg", + "functions": [ + { + "function": "minecraft:set_count", + "count": 1 + } + ] + } + ] + }, + { + "rolls": { + "type": "minecraft:uniform", + "min": 4.0, + "max": 6.0 + }, + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:killed_by_player" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "antarchy:king_scale", + "functions": [ + { + "function": "minecraft:set_count", + "count": { + "type": "minecraft:uniform", + "min": 8.0, + "max": 16.0 + } + } + ] + } + ] + }, + { + "rolls": { + "type": "minecraft:uniform", + "min": 8.0, + "max": 12.0 + }, + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:killed_by_player" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "minecraft:gold_block", + "functions": [ + { + "function": "minecraft:set_count", + "count": { + "type": "minecraft:uniform", + "min": 12.0, + "max": 20.0 + } + } + ] + } + ] + }, + { + "rolls": { + "type": "minecraft:uniform", + "min": 3.0, + "max": 5.0 + }, + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:killed_by_player" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "minecraft:diamond", + "functions": [ + { + "function": "minecraft:set_count", + "count": { + "type": "minecraft:uniform", + "min": 10.0, + "max": 16.0 + } + } + ] + } + ] + } + ] +} diff --git a/common-1.21.1/src/main/resources/data/antarchy/loot_table/entities/queen.json b/common-1.21.1/src/main/resources/data/antarchy/loot_table/entities/queen.json new file mode 100644 index 00000000..39697c66 --- /dev/null +++ b/common-1.21.1/src/main/resources/data/antarchy/loot_table/entities/queen.json @@ -0,0 +1,109 @@ +{ + "type": "minecraft:entity", + "random_sequence": "antarchy:entities/queen", + "pools": [ + { + "rolls": 1.0, + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "antarchy:princess_egg", + "functions": [ + { + "function": "minecraft:set_count", + "count": 1 + } + ] + } + ] + }, + { + "rolls": { + "type": "minecraft:uniform", + "min": 4.0, + "max": 6.0 + }, + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:killed_by_player" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "antarchy:queen_scale", + "functions": [ + { + "function": "minecraft:set_count", + "count": { + "type": "minecraft:uniform", + "min": 8.0, + "max": 16.0 + } + } + ] + } + ] + }, + { + "rolls": { + "type": "minecraft:uniform", + "min": 8.0, + "max": 12.0 + }, + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:killed_by_player" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "antarchy:blood_crystal_shard", + "functions": [ + { + "function": "minecraft:set_count", + "count": { + "type": "minecraft:uniform", + "min": 12.0, + "max": 20.0 + } + } + ] + } + ] + }, + { + "rolls": { + "type": "minecraft:uniform", + "min": 3.0, + "max": 5.0 + }, + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:killed_by_player" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "minecraft:netherite_scrap", + "functions": [ + { + "function": "minecraft:set_count", + "count": { + "type": "minecraft:uniform", + "min": 10.0, + "max": 16.0 + } + } + ] + } + ] + } + ] +} diff --git a/common-1.21.1/src/main/resources/data/antarchy/tags/entity_type/inverted_immune.json b/common-1.21.1/src/main/resources/data/antarchy/tags/entity_type/inverted_immune.json index aa39f4dd..68f9edaf 100644 --- a/common-1.21.1/src/main/resources/data/antarchy/tags/entity_type/inverted_immune.json +++ b/common-1.21.1/src/main/resources/data/antarchy/tags/entity_type/inverted_immune.json @@ -5,6 +5,8 @@ "antarchy:kraken", "antarchy:reverie", "antarchy:lucid", - "antarchy:triffid" + "antarchy:triffid", + "antarchy:king", + "antarchy:queen" ] } diff --git a/common-1.21.1/src/main/resources/data/antarchy/tags/entity_type/time_dilation_immune.json b/common-1.21.1/src/main/resources/data/antarchy/tags/entity_type/time_dilation_immune.json new file mode 100644 index 00000000..bc3a319e --- /dev/null +++ b/common-1.21.1/src/main/resources/data/antarchy/tags/entity_type/time_dilation_immune.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "antarchy:king", + "antarchy:queen" + ] +} diff --git a/common-1.21.1/src/main/resources/data/antarchy/tags/item/royal_mount_food.json b/common-1.21.1/src/main/resources/data/antarchy/tags/item/royal_mount_food.json new file mode 100644 index 00000000..309a6662 --- /dev/null +++ b/common-1.21.1/src/main/resources/data/antarchy/tags/item/royal_mount_food.json @@ -0,0 +1,11 @@ +{ + "replace": false, + "values": [ + "minecraft:golden_apple", + "minecraft:enchanted_golden_apple", + "minecraft:golden_carrot", + "minecraft:glistering_melon_slice", + "antarchy:king_scale", + "antarchy:queen_scale" + ] +} diff --git a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/AntarchyFabricContent.java b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/AntarchyFabricContent.java index 56738aac..d37ffc3a 100644 --- a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/AntarchyFabricContent.java +++ b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/AntarchyFabricContent.java @@ -321,7 +321,21 @@ public final class AntarchyFabricContent { AntarchyFabricSounds.QUEEN_BEAM_SHOOT, AntarchyFabricSounds.QUEEN_BEAM_START, AntarchyFabricSounds.QUEEN_BEAM_LOOP, - AntarchyFabricSounds.QUEEN_BEAM_END + AntarchyFabricSounds.QUEEN_BEAM_END, + AntarchyFabricSounds.KING_STOMP, + AntarchyFabricSounds.KING_ROAR, + AntarchyFabricSounds.KING_WING_FLAP, + AntarchyFabricSounds.KING_FLY_LOOP, + AntarchyFabricSounds.PRINCE_IDLE, + AntarchyFabricSounds.PRINCE_BITE, + AntarchyFabricSounds.PRINCE_SHOOT, + AntarchyFabricSounds.PRINCE_FLY, + AntarchyFabricSounds.PRINCE_STEP, + AntarchyFabricSounds.PRINCESS_IDLE, + AntarchyFabricSounds.PRINCESS_BITE, + AntarchyFabricSounds.PRINCESS_SHOOT, + AntarchyFabricSounds.PRINCESS_FLY, + AntarchyFabricSounds.PRINCESS_STEP ); AntarchyObjects.setOctopusBomb(AntarchyFabricEntities.OCTOPUS_BOMB); @@ -334,6 +348,7 @@ public final class AntarchyFabricContent { AntarchyObjects.setVortex(AntarchyFabricEntities.VORTEX); AntarchyObjects.setWindVortex(() -> AntarchyFabricEntities.WIND_VORTEX.get()); AntarchyObjects.setTimeDilationField(() -> AntarchyFabricEntities.TIME_DILATION_FIELD.get()); + AntarchyObjects.setRoyalBlackHole(() -> AntarchyFabricEntities.ROYAL_BLACK_HOLE.get()); AntarchyObjects.setVortexChargeProjectile(() -> AntarchyFabricEntities.VORTEX_CHARGE_PROJECTILE.get()); AntarchyObjects.setPrince(() -> AntarchyFabricEntities.PRINCE.get()); AntarchyObjects.setPrincess(() -> AntarchyFabricEntities.PRINCESS.get()); @@ -516,6 +531,9 @@ public final class AntarchyFabricContent { com.craisinlord.antarchy.content.time.TimeDilationApi.setSyncDispatcher( com.craisinlord.antarchy.fabric.network.AntarchyFabricTimeDilationNetworking::syncRate ); + com.craisinlord.antarchy.content.time.TimeDilationApi.setFieldSyncDispatcher( + com.craisinlord.antarchy.fabric.network.AntarchyFabricTimeDilationNetworking::syncFields + ); AntarchyFabricEvents.register(); if (isSupportedInfinityLoaded()) { diff --git a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/AntarchyFabricEvents.java b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/AntarchyFabricEvents.java index 7a9c66a0..94f7b245 100644 --- a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/AntarchyFabricEvents.java +++ b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/AntarchyFabricEvents.java @@ -19,6 +19,7 @@ import com.craisinlord.antarchy.content.horde.CavarynHordeManager; import com.craisinlord.antarchy.content.portal.PermanentPortalManager; import com.craisinlord.antarchy.content.command.CavarynCommand; import com.craisinlord.antarchy.content.command.CaterpillarCommand; +import com.craisinlord.antarchy.content.command.DimensionalTearCommand; import com.craisinlord.antarchy.content.command.GravityCommand; import com.craisinlord.antarchy.content.time.TimeDilationCommand; import com.craisinlord.antarchy.content.time.TimeDilationManager; @@ -65,10 +66,19 @@ public final class AntarchyFabricEvents { } public static void register() { + net.fabricmc.fabric.api.networking.v1.EntityTrackingEvents.START_TRACKING.register((trackedEntity, player) -> { + if (trackedEntity instanceof com.craisinlord.antarchy.content.time.TimeDilationEntityAccess access + && player instanceof ServerPlayer serverPlayer) { + com.craisinlord.antarchy.fabric.network.AntarchyFabricTimeDilationNetworking.syncRateToPlayer( + serverPlayer, trackedEntity, access.antarchy$getTimeDilationRate() + ); + } + }); CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { CavarynCommand.register(dispatcher); GravityCommand.register(dispatcher); CaterpillarCommand.register(dispatcher); + DimensionalTearCommand.register(dispatcher); TimeDilationCommand.register(dispatcher); }); diff --git a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/client/AntarchyFabricClientBootstrap.java b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/client/AntarchyFabricClientBootstrap.java index 642c23e6..ae8a6902 100644 --- a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/client/AntarchyFabricClientBootstrap.java +++ b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/client/AntarchyFabricClientBootstrap.java @@ -146,6 +146,7 @@ public final class AntarchyFabricClientBootstrap { EntityRendererRegistry.register(AntarchyFabricEntities.VORTEX_CHARGE_PROJECTILE.get(), ThrownItemRenderer::new); EntityRendererRegistry.register(AntarchyFabricEntities.WIND_VORTEX.get(), WindVortexRenderer::new); EntityRendererRegistry.register(AntarchyFabricEntities.TIME_DILATION_FIELD.get(), TimeDilationFieldRenderer::new); + EntityRendererRegistry.register(AntarchyFabricEntities.ROYAL_BLACK_HOLE.get(), net.minecraft.client.renderer.entity.NoopRenderer::new); EntityRendererRegistry.register(AntarchyFabricEntities.CRITTER_CAGE_PROJECTILE.get(), ThrownItemRenderer::new); EntityRendererRegistry.register(AntarchyFabricEntities.WORM_HOOK_PROJECTILE.get(), ThrownItemRenderer::new); EntityRendererRegistry.register(AntarchyFabricEntities.HUSH_PROJECTILE.get(), HushProjectileRenderer::new); diff --git a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/client/AntarchyKeyBindings.java b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/client/AntarchyKeyBindings.java index b847212e..4d8f581a 100644 --- a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/client/AntarchyKeyBindings.java +++ b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/client/AntarchyKeyBindings.java @@ -17,13 +17,6 @@ public final class AntarchyKeyBindings { CATEGORY ); - public static final KeyMapping DORRIE_CHARGE_JUMP = new KeyMapping( - "key.antarchy.dorrie_charge_jump", - InputConstants.Type.KEYSYM, - GLFW.GLFW_KEY_LEFT_CONTROL, - CATEGORY - ); - public static final KeyMapping MOUNT_SPECIAL = new KeyMapping( "key.antarchy.mount_special", InputConstants.Type.KEYSYM, @@ -55,7 +48,6 @@ public final class AntarchyKeyBindings { public static void register() { KeyBindingHelper.registerKeyBinding(BRUTALFLY_FLAP); - KeyBindingHelper.registerKeyBinding(DORRIE_CHARGE_JUMP); KeyBindingHelper.registerKeyBinding(MOUNT_SPECIAL); KeyBindingHelper.registerKeyBinding(MOUNT_FLIGHT_TOGGLE); KeyBindingHelper.registerKeyBinding(TIGERS_EYE_CAMOUFLAGE); @@ -66,10 +58,6 @@ public final class AntarchyKeyBindings { return Minecraft.getInstance().screen == null && BRUTALFLY_FLAP.isDown(); } - public static boolean isDorrieChargeJumpPressed() { - return Minecraft.getInstance().screen == null && DORRIE_CHARGE_JUMP.isDown(); - } - public static boolean isMountSpecialPressed() { return Minecraft.getInstance().screen == null && MOUNT_SPECIAL.isDown(); } diff --git a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/client/DorrieJumpClientHandler.java b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/client/DorrieJumpClientHandler.java index 5e469b65..37f9b3af 100644 --- a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/client/DorrieJumpClientHandler.java +++ b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/client/DorrieJumpClientHandler.java @@ -35,7 +35,7 @@ public final class DorrieJumpClientHandler { } // Left ctrl → charge jump. - boolean pressingCharge = AntarchyKeyBindings.isDorrieChargeJumpPressed(); + boolean pressingCharge = AntarchyKeyBindings.isMountSpecialPressed(); if (pressingCharge != wasPressingCharge) { ClientPlayNetworking.send(new DorrieChargeJumpPayload(pressingCharge)); if (!pressingCharge && player.getVehicle() instanceof DorrieEntity dorrie) { diff --git a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/mixin/AntiwaterItemEntityMixin.java b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/mixin/AntiwaterItemEntityMixin.java index 44148469..0aa53d7d 100644 --- a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/mixin/AntiwaterItemEntityMixin.java +++ b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/mixin/AntiwaterItemEntityMixin.java @@ -1,10 +1,7 @@ package com.craisinlord.antarchy.fabric.mixin; -import com.craisinlord.antarchy.content.fluid.AntarchyFluidChecks; import com.craisinlord.antarchy.fabric.util.CustomFluidPhysicsChecks; -import net.minecraft.core.BlockPos; import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.level.material.FluidState; import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -16,7 +13,7 @@ public abstract class AntiwaterItemEntityMixin { @Inject(method = "tick", at = @At("TAIL")) private void antarchy$applyAntiwaterItemMovement(CallbackInfo ci) { ItemEntity entity = (ItemEntity) (Object) this; - if (!antarchy$isTouchingAntiwater(entity)) { + if (!CustomFluidPhysicsChecks.isTouchingAntiwater(entity)) { return; } @@ -29,22 +26,4 @@ public abstract class AntiwaterItemEntityMixin { motion.z * 0.99D + push.z ); } - - private boolean antarchy$isTouchingAntiwater(ItemEntity entity) { - BlockPos min = BlockPos.containing(entity.getBoundingBox().minX, entity.getBoundingBox().minY, entity.getBoundingBox().minZ); - BlockPos max = BlockPos.containing(entity.getBoundingBox().maxX, entity.getBoundingBox().maxY, entity.getBoundingBox().maxZ); - BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos(); - for (int x = min.getX(); x <= max.getX(); x++) { - for (int y = min.getY(); y <= max.getY(); y++) { - for (int z = min.getZ(); z <= max.getZ(); z++) { - cursor.set(x, y, z); - FluidState fluidState = entity.level().getFluidState(cursor); - if (AntarchyFluidChecks.isAntiwater(fluidState)) { - return true; - } - } - } - } - return false; - } } diff --git a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/mixin/AntiwaterLivingEntityMixin.java b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/mixin/AntiwaterLivingEntityMixin.java index b5229227..7abc586f 100644 --- a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/mixin/AntiwaterLivingEntityMixin.java +++ b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/mixin/AntiwaterLivingEntityMixin.java @@ -1,17 +1,13 @@ package com.craisinlord.antarchy.fabric.mixin; import com.craisinlord.antarchy.content.AntarchyObjects; -import com.craisinlord.antarchy.content.fluid.AntarchyFluidChecks; import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi; import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection; import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil; import com.craisinlord.antarchy.fabric.util.CustomFluidPhysicsChecks; -import net.minecraft.core.BlockPos; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.MoverType; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -23,7 +19,7 @@ public abstract class AntiwaterLivingEntityMixin { @Inject(method = "travel", at = @At("HEAD"), cancellable = true) private void antarchy$moveInAntiwater(Vec3 travelVector, CallbackInfo ci) { LivingEntity entity = (LivingEntity) (Object) this; - if (!antarchy$isTouchingAntiwaterLocal(entity)) { + if (!CustomFluidPhysicsChecks.isTouchingAntiwater(entity)) { return; } @@ -88,23 +84,4 @@ public abstract class AntiwaterLivingEntityMixin { return AntarchyGravityDirection.UP; } - - private boolean antarchy$isTouchingAntiwaterLocal(LivingEntity entity) { - AABB box = entity.getBoundingBox().inflate(0.05D); - BlockPos min = BlockPos.containing(box.minX, box.minY, box.minZ); - BlockPos max = BlockPos.containing(box.maxX, box.maxY, box.maxZ); - BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos(); - for (int x = min.getX(); x <= max.getX(); x++) { - for (int y = min.getY(); y <= max.getY(); y++) { - for (int z = min.getZ(); z <= max.getZ(); z++) { - cursor.set(x, y, z); - FluidState fluidState = entity.level().getFluidState(cursor); - if (AntarchyFluidChecks.isAntiwater(fluidState)) { - return true; - } - } - } - } - return false; - } } diff --git a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/network/AntarchyFabricTimeDilationNetworking.java b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/network/AntarchyFabricTimeDilationNetworking.java index 987ad980..62751aa0 100644 --- a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/network/AntarchyFabricTimeDilationNetworking.java +++ b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/network/AntarchyFabricTimeDilationNetworking.java @@ -1,12 +1,16 @@ package com.craisinlord.antarchy.fabric.network; import com.craisinlord.antarchy.content.network.TimeDilationRatePayload; +import com.craisinlord.antarchy.content.network.TimeDilationFieldsPayload; import com.craisinlord.antarchy.content.time.TimeDilationApi; +import com.craisinlord.antarchy.content.time.TimeDilationFieldSnapshot; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; +import net.fabricmc.fabric.api.networking.v1.PlayerLookup; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; +import java.util.List; public final class AntarchyFabricTimeDilationNetworking { private AntarchyFabricTimeDilationNetworking() { @@ -14,24 +18,35 @@ public final class AntarchyFabricTimeDilationNetworking { public static void registerPayloadTypes() { PayloadTypeRegistry.playS2C().register(TimeDilationRatePayload.TYPE, TimeDilationRatePayload.STREAM_CODEC); + PayloadTypeRegistry.playS2C().register(TimeDilationFieldsPayload.TYPE, TimeDilationFieldsPayload.STREAM_CODEC); } public static void registerClientReceiver() { ClientPlayNetworking.registerGlobalReceiver(TimeDilationRatePayload.TYPE, (payload, context) -> context.client().execute(() -> handleRate(context.player(), payload))); + ClientPlayNetworking.registerGlobalReceiver(TimeDilationFieldsPayload.TYPE, (payload, context) -> + context.client().execute(() -> com.craisinlord.antarchy.content.client.ClientTimeDilationTicker.applyFields(payload.fields()))); } - public static void syncRate(ServerPlayer player, double rate) { - ServerPlayNetworking.send(player, new TimeDilationRatePayload(player.getId(), rate)); + public static void syncRate(Entity entity, double rate) { + TimeDilationRatePayload payload = new TimeDilationRatePayload(entity.getUUID(), rate); + for (ServerPlayer player : PlayerLookup.tracking(entity)) { + ServerPlayNetworking.send(player, payload); + } + if (entity instanceof ServerPlayer player) { + ServerPlayNetworking.send(player, payload); + } + } + + public static void syncRateToPlayer(ServerPlayer player, Entity entity, double rate) { + ServerPlayNetworking.send(player, new TimeDilationRatePayload(entity.getUUID(), rate)); + } + + public static void syncFields(ServerPlayer player, List fields) { + ServerPlayNetworking.send(player, new TimeDilationFieldsPayload(fields)); } private static void handleRate(Entity contextPlayer, TimeDilationRatePayload payload) { - Entity entity = contextPlayer.level().getEntity(payload.entityId()); - if (entity == null && contextPlayer.getId() == payload.entityId()) { - entity = contextPlayer; - } - if (entity != null) { - TimeDilationApi.applySyncedRate(entity, payload.rate()); - } + TimeDilationApi.applySyncedRate(payload.entityUuid(), payload.rate()); } } diff --git a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/registry/AntarchyFabricEntities.java b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/registry/AntarchyFabricEntities.java index e91dda50..528f1309 100644 --- a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/registry/AntarchyFabricEntities.java +++ b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/registry/AntarchyFabricEntities.java @@ -475,6 +475,14 @@ public final class AntarchyFabricEntities { .fireImmune() .build("time_dilation_field")); + public static final DeferredHolder, EntityType> ROYAL_BLACK_HOLE = ENTITY_TYPES.register("royal_black_hole", + () -> EntityType.Builder.of(com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity::new, MobCategory.MISC) + .sized(1.0F, 1.0F) + .clientTrackingRange(16) + .updateInterval(2) + .fireImmune() + .build("royal_black_hole")); + public static final DeferredHolder, EntityType> LUCID_BOLT = ENTITY_TYPES.register("lucid_bolt", () -> EntityType.Builder.of(LucidBoltEntity::new, MobCategory.MISC) diff --git a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/registry/AntarchyFabricSounds.java b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/registry/AntarchyFabricSounds.java index f546380e..13f9e746 100644 --- a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/registry/AntarchyFabricSounds.java +++ b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/registry/AntarchyFabricSounds.java @@ -556,6 +556,17 @@ public final class AntarchyFabricSounds { public static final DeferredHolder QUEEN_BLACK_HOLE_SHOOT = registerSoundEvent("queen_black_hole_shoot"); public static final DeferredHolder QUEEN_CAST_SHOOT = registerSoundEvent("queen_cast_shoot"); + public static final DeferredHolder PRINCE_IDLE = registerSoundEvent("prince_idle"); + public static final DeferredHolder PRINCE_BITE = registerSoundEvent("prince_bite"); + public static final DeferredHolder PRINCE_SHOOT = registerSoundEvent("prince_shoot"); + public static final DeferredHolder PRINCE_FLY = registerSoundEvent("prince_fly"); + public static final DeferredHolder PRINCE_STEP = registerSoundEvent("prince_step"); + public static final DeferredHolder PRINCESS_IDLE = registerSoundEvent("princess_idle"); + public static final DeferredHolder PRINCESS_BITE = registerSoundEvent("princess_bite"); + public static final DeferredHolder PRINCESS_SHOOT = registerSoundEvent("princess_shoot"); + public static final DeferredHolder PRINCESS_FLY = registerSoundEvent("princess_fly"); + public static final DeferredHolder PRINCESS_STEP = registerSoundEvent("princess_step"); + diff --git a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/util/CustomFluidPhysicsChecks.java b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/util/CustomFluidPhysicsChecks.java index e25839d3..251b0ed2 100644 --- a/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/util/CustomFluidPhysicsChecks.java +++ b/fabric-1.21.1/src/main/java/com/craisinlord/antarchy/fabric/util/CustomFluidPhysicsChecks.java @@ -2,45 +2,45 @@ package com.craisinlord.antarchy.fabric.util; import com.craisinlord.antarchy.content.fluid.AntarchyFluidChecks; import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; +import java.util.function.Predicate; + public final class CustomFluidPhysicsChecks { private CustomFluidPhysicsChecks() { } public static boolean isTouchingAntiwater(Entity entity) { - AABB box = entity.getBoundingBox().inflate(0.05D); - BlockPos min = BlockPos.containing(box.minX, box.minY, box.minZ); - BlockPos max = BlockPos.containing(box.maxX, box.maxY, box.maxZ); - BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos(); - for (int x = min.getX(); x <= max.getX(); x++) { - for (int y = min.getY(); y <= max.getY(); y++) { - for (int z = min.getZ(); z <= max.getZ(); z++) { - cursor.set(x, y, z); - FluidState fluidState = entity.level().getFluidState(cursor); - if (AntarchyFluidChecks.isAntiwater(fluidState)) { - return true; - } - } - } - } - return false; + return isTouching(entity, AntarchyFluidChecks::isAntiwater); } public static boolean isTouchingWaterlikeFluid(Entity entity) { - AABB box = entity.getBoundingBox().inflate(0.05D); - BlockPos min = BlockPos.containing(box.minX, box.minY, box.minZ); - BlockPos max = BlockPos.containing(box.maxX, box.maxY, box.maxZ); + return isTouching(entity, AntarchyFluidChecks::usesWaterLikePhysics); + } + + public static Vec3 getAntiwaterFlow(Entity entity) { + return getAverageFlow(entity, AntarchyFluidChecks::isAntiwater); + } + + public static Vec3 getWaterlikeFlow(Entity entity) { + return getAverageFlow(entity, AntarchyFluidChecks::usesWaterLikePhysics); + } + + private static boolean isTouching(Entity entity, Predicate matches) { + AABB box = entity.getBoundingBox().deflate(0.001D); + Level level = entity.level(); BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos(); - for (int x = min.getX(); x <= max.getX(); x++) { - for (int y = min.getY(); y <= max.getY(); y++) { - for (int z = min.getZ(); z <= max.getZ(); z++) { + for (int x = Mth.floor(box.minX); x < Mth.ceil(box.maxX); x++) { + for (int y = Mth.floor(box.minY); y < Mth.ceil(box.maxY); y++) { + for (int z = Mth.floor(box.minZ); z < Mth.ceil(box.maxZ); z++) { cursor.set(x, y, z); - FluidState fluidState = entity.level().getFluidState(cursor); - if (AntarchyFluidChecks.usesWaterLikePhysics(fluidState)) { + FluidState fluidState = level.getFluidState(cursor); + if (matches.test(fluidState) && y + fluidState.getHeight(level, cursor) >= box.minY) { return true; } } @@ -49,43 +49,31 @@ public final class CustomFluidPhysicsChecks { return false; } - public static Vec3 getAntiwaterFlow(Entity entity) { - return getAverageFlow(entity, true); - } - - public static Vec3 getWaterlikeFlow(Entity entity) { - return getAverageFlow(entity, false); - } - - private static Vec3 getAverageFlow(Entity entity, boolean antiwater) { - AABB box = entity.getBoundingBox().inflate(0.05D); - BlockPos min = BlockPos.containing(box.minX, box.minY, box.minZ); - BlockPos max = BlockPos.containing(box.maxX, box.maxY, box.maxZ); + private static Vec3 getAverageFlow(Entity entity, Predicate matches) { + AABB box = entity.getBoundingBox().deflate(0.001D); + Level level = entity.level(); BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos(); Vec3 totalFlow = Vec3.ZERO; - int matches = 0; - for (int x = min.getX(); x <= max.getX(); x++) { - for (int y = min.getY(); y <= max.getY(); y++) { - for (int z = min.getZ(); z <= max.getZ(); z++) { + int count = 0; + for (int x = Mth.floor(box.minX); x < Mth.ceil(box.maxX); x++) { + for (int y = Mth.floor(box.minY); y < Mth.ceil(box.maxY); y++) { + for (int z = Mth.floor(box.minZ); z < Mth.ceil(box.maxZ); z++) { cursor.set(x, y, z); - FluidState fluidState = entity.level().getFluidState(cursor); - boolean matchesFluid = antiwater - ? AntarchyFluidChecks.isAntiwater(fluidState) - : AntarchyFluidChecks.usesWaterLikePhysics(fluidState); - if (!matchesFluid) { + FluidState fluidState = level.getFluidState(cursor); + if (!matches.test(fluidState) || y + fluidState.getHeight(level, cursor) < box.minY) { continue; } - totalFlow = totalFlow.add(fluidState.getFlow(entity.level(), cursor)); - matches++; + totalFlow = totalFlow.add(fluidState.getFlow(level, cursor)); + count++; } } } - if (matches == 0 || totalFlow.lengthSqr() < 1.0E-6D) { + if (count == 0 || totalFlow.lengthSqr() < 1.0E-6D) { return Vec3.ZERO; } - return totalFlow.scale(1.0D / matches); + return totalFlow.scale(1.0D / count); } } diff --git a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyConfigModuleNeoforge.java b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyConfigModuleNeoforge.java index 4faeb123..2483c026 100644 --- a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyConfigModuleNeoforge.java +++ b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyConfigModuleNeoforge.java @@ -163,6 +163,7 @@ public final class AntarchyConfigModuleNeoforge { AntarchySettings.setKingBeamTracking(AntarchyMobsConfig.kingBeamTracking()); AntarchySettings.setKingBeamTerrainRadius(AntarchyMobsConfig.kingBeamTerrainRadius()); AntarchySettings.setKingBeamTerrainCap(AntarchyMobsConfig.kingBeamTerrainCap()); + AntarchySettings.setRoyalDecreeCooldownTicks(AntarchyMobsConfig.royalDecreeCooldownTicks()); AntarchySettings.setBrutalflyHealth(AntarchyMobsConfig.brutalflyHealth()); AntarchySettings.setBrutalflySwipeDamage(AntarchyMobsConfig.brutalflySwipeDamage()); diff --git a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyMobsConfig.java b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyMobsConfig.java index 0c368b83..1d3c7a14 100644 --- a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyMobsConfig.java +++ b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyMobsConfig.java @@ -128,6 +128,7 @@ public final class AntarchyMobsConfig { private static final ModConfigSpec.IntValue QUEEN_BEAM_DURATION_TICKS, QUEEN_BEAM_COOLDOWN_TICKS, QUEEN_BEAM_TERRAIN_CAP; private static final ModConfigSpec.DoubleValue KING_BEAM_DAMAGE, KING_BEAM_RANGE, KING_BEAM_TRACKING, KING_BEAM_TERRAIN_RADIUS; private static final ModConfigSpec.IntValue KING_BEAM_DURATION_TICKS, KING_BEAM_COOLDOWN_TICKS, KING_BEAM_TERRAIN_CAP; + private static final ModConfigSpec.IntValue ROYAL_DECREE_COOLDOWN_TICKS; // Brutalfly @@ -570,6 +571,7 @@ public final class AntarchyMobsConfig { KING_BEAM_TRACKING = b.defineInRange("kingBeamTracking", 0.1D, 0.0D, 1.0D); KING_BEAM_TERRAIN_RADIUS = b.defineInRange("kingBeamTerrainRadius", 5.0D, 0.0D, 32.0D); KING_BEAM_TERRAIN_CAP = b.defineInRange("kingBeamTerrainCap", 192, 0, 4096); + ROYAL_DECREE_COOLDOWN_TICKS = b.comment("Cooldown in ticks between the end of one King decree and the next.").defineInRange("royalDecreeCooldownTicks", 1200, 1, 72000); b.pop(); @@ -966,6 +968,7 @@ public final class AntarchyMobsConfig { static double kingBeamTracking() { return KING_BEAM_TRACKING.get(); } static double kingBeamTerrainRadius() { return KING_BEAM_TERRAIN_RADIUS.get(); } static int kingBeamTerrainCap() { return KING_BEAM_TERRAIN_CAP.get(); } + static int royalDecreeCooldownTicks() { return ROYAL_DECREE_COOLDOWN_TICKS.get(); } static double brutalflyHealth() { return BRUTALFLY_HEALTH.get(); } static double brutalflySwipeDamage() { return BRUTALFLY_SWIPE_DAMAGE.get(); } diff --git a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyNeoforge.java b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyNeoforge.java index cd0e3aa9..a420f2af 100644 --- a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyNeoforge.java +++ b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyNeoforge.java @@ -216,7 +216,21 @@ public class AntarchyNeoforge { AntarchyNeoforgeSounds.QUEEN_BEAM_SHOOT, AntarchyNeoforgeSounds.QUEEN_BEAM_START, AntarchyNeoforgeSounds.QUEEN_BEAM_LOOP, - AntarchyNeoforgeSounds.QUEEN_BEAM_END + AntarchyNeoforgeSounds.QUEEN_BEAM_END, + AntarchyNeoforgeSounds.KING_STOMP, + AntarchyNeoforgeSounds.KING_ROAR, + AntarchyNeoforgeSounds.KING_WING_FLAP, + AntarchyNeoforgeSounds.KING_FLY_LOOP, + AntarchyNeoforgeSounds.PRINCE_IDLE, + AntarchyNeoforgeSounds.PRINCE_BITE, + AntarchyNeoforgeSounds.PRINCE_SHOOT, + AntarchyNeoforgeSounds.PRINCE_FLY, + AntarchyNeoforgeSounds.PRINCE_STEP, + AntarchyNeoforgeSounds.PRINCESS_IDLE, + AntarchyNeoforgeSounds.PRINCESS_BITE, + AntarchyNeoforgeSounds.PRINCESS_SHOOT, + AntarchyNeoforgeSounds.PRINCESS_FLY, + AntarchyNeoforgeSounds.PRINCESS_STEP ); bindCommonObjects(); ScorpionWhipTetherSync.setSink((player, targetId) -> PacketDistributor.sendToPlayersTrackingEntityAndSelf( @@ -242,6 +256,9 @@ public class AntarchyNeoforge { com.craisinlord.antarchy.content.time.TimeDilationApi.setSyncDispatcher( com.craisinlord.antarchy.neoforge.network.AntarchyTimeDilationNetworking::syncRate ); + com.craisinlord.antarchy.content.time.TimeDilationApi.setFieldSyncDispatcher( + com.craisinlord.antarchy.neoforge.network.AntarchyTimeDilationNetworking::syncFields + ); if (isSupportedInfinityLoaded()) { InfinityCompat.bind(new NeoForgeInfinityCompat()); } @@ -407,6 +424,7 @@ public class AntarchyNeoforge { AntarchyObjects.setVortex(AntarchyNeoforgeEntites.VORTEX); AntarchyObjects.setWindVortex(() -> AntarchyNeoforgeEntites.WIND_VORTEX.get()); AntarchyObjects.setTimeDilationField(() -> AntarchyNeoforgeEntites.TIME_DILATION_FIELD.get()); + AntarchyObjects.setRoyalBlackHole(() -> AntarchyNeoforgeEntites.ROYAL_BLACK_HOLE.get()); AntarchyObjects.setVortexChargeProjectile(() -> AntarchyNeoforgeEntites.VORTEX_CHARGE_PROJECTILE.get()); AntarchyObjects.setPrince(() -> AntarchyNeoforgeEntites.PRINCE.get()); AntarchyObjects.setPrincess(() -> AntarchyNeoforgeEntites.PRINCESS.get()); diff --git a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyNeoforgeEvents.java b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyNeoforgeEvents.java index 7e841bba..06457009 100644 --- a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyNeoforgeEvents.java +++ b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/AntarchyNeoforgeEvents.java @@ -3,6 +3,7 @@ package com.craisinlord.antarchy.neoforge; import com.craisinlord.antarchy.Antarchy; import com.craisinlord.antarchy.content.command.CavarynCommand; import com.craisinlord.antarchy.content.command.CaterpillarCommand; +import com.craisinlord.antarchy.content.command.DimensionalTearCommand; import com.craisinlord.antarchy.content.command.GravityCommand; import com.craisinlord.antarchy.content.time.TimeDilationCommand; import net.neoforged.bus.api.SubscribeEvent; @@ -19,6 +20,7 @@ public final class AntarchyNeoforgeEvents { CavarynCommand.register(event.getDispatcher()); GravityCommand.register(event.getDispatcher()); CaterpillarCommand.register(event.getDispatcher()); + DimensionalTearCommand.register(event.getDispatcher()); TimeDilationCommand.register(event.getDispatcher()); } } diff --git a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/client/AntarchyKeyBindings.java b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/client/AntarchyKeyBindings.java index d8e87901..cda2d19f 100644 --- a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/client/AntarchyKeyBindings.java +++ b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/client/AntarchyKeyBindings.java @@ -21,14 +21,6 @@ public final class AntarchyKeyBindings { CATEGORY ); - public static final KeyMapping DORRIE_CHARGE_JUMP = new KeyMapping( - "key.antarchy.dorrie_charge_jump", - KeyConflictContext.IN_GAME, - InputConstants.Type.KEYSYM, - InputConstants.KEY_LCONTROL, - CATEGORY - ); - public static final KeyMapping MOUNT_SPECIAL = new KeyMapping( "key.antarchy.mount_special", KeyConflictContext.IN_GAME, @@ -65,7 +57,6 @@ public final class AntarchyKeyBindings { @SubscribeEvent public static void onRegisterKeyMappings(RegisterKeyMappingsEvent event) { event.register(BRUTALFLY_FLAP); - event.register(DORRIE_CHARGE_JUMP); event.register(MOUNT_SPECIAL); event.register(MOUNT_FLIGHT_TOGGLE); event.register(TIGERS_EYE_CAMOUFLAGE); diff --git a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/client/AntarchyNeoForgeClient.java b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/client/AntarchyNeoForgeClient.java index b652a5ae..e6162024 100644 --- a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/client/AntarchyNeoForgeClient.java +++ b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/client/AntarchyNeoForgeClient.java @@ -150,6 +150,7 @@ public final class AntarchyNeoForgeClient { event.registerEntityRenderer(AntarchyNeoforgeEntites.VORTEX_CHARGE_PROJECTILE.get(), ThrownItemRenderer::new); event.registerEntityRenderer(AntarchyNeoforgeEntites.WIND_VORTEX.get(), WindVortexRenderer::new); event.registerEntityRenderer(AntarchyNeoforgeEntites.TIME_DILATION_FIELD.get(), TimeDilationFieldRenderer::new); + event.registerEntityRenderer(AntarchyNeoforgeEntites.ROYAL_BLACK_HOLE.get(), net.minecraft.client.renderer.entity.NoopRenderer::new); event.registerEntityRenderer(AntarchyNeoforgeEntites.CRITTER_CAGE_PROJECTILE.get(), ThrownItemRenderer::new); event.registerEntityRenderer(AntarchyNeoforgeEntites.WORM_HOOK_PROJECTILE.get(), ThrownItemRenderer::new); event.registerEntityRenderer(AntarchyNeoforgeEntites.HUSH_PROJECTILE.get(), HushProjectileRenderer::new); diff --git a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/client/DorrieJumpClientHandler.java b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/client/DorrieJumpClientHandler.java index d0386426..53350aa1 100644 --- a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/client/DorrieJumpClientHandler.java +++ b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/client/DorrieJumpClientHandler.java @@ -40,7 +40,7 @@ public final class DorrieJumpClientHandler { wasPressingJump = pressingJump; } - boolean pressingCharge = AntarchyKeyBindings.DORRIE_CHARGE_JUMP.isDown(); + boolean pressingCharge = AntarchyKeyBindings.MOUNT_SPECIAL.isDown(); if (pressingCharge != wasPressingCharge) { PacketDistributor.sendToServer(new DorrieChargeJumpPayload(pressingCharge)); if (!pressingCharge && player.getVehicle() instanceof DorrieEntity dorrie) { diff --git a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/network/AntarchyTimeDilationNetworking.java b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/network/AntarchyTimeDilationNetworking.java index 9f12b17d..4521fa3c 100644 --- a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/network/AntarchyTimeDilationNetworking.java +++ b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/network/AntarchyTimeDilationNetworking.java @@ -1,9 +1,13 @@ package com.craisinlord.antarchy.neoforge.network; import com.craisinlord.antarchy.content.network.TimeDilationRatePayload; +import com.craisinlord.antarchy.content.network.TimeDilationFieldsPayload; +import com.craisinlord.antarchy.content.time.TimeDilationFieldSnapshot; +import java.util.List; import com.craisinlord.antarchy.content.time.TimeDilationApi; -import net.minecraft.server.level.ServerPlayer; +import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.world.entity.Entity; +import net.minecraft.server.level.ServerPlayer; import net.neoforged.neoforge.network.PacketDistributor; import net.neoforged.neoforge.network.handling.IPayloadContext; import net.neoforged.neoforge.network.registration.PayloadRegistrar; @@ -18,21 +22,32 @@ public final class AntarchyTimeDilationNetworking { TimeDilationRatePayload.STREAM_CODEC, AntarchyTimeDilationNetworking::handleTimeDilationRate ); + registrar.playToClient( + TimeDilationFieldsPayload.TYPE, + TimeDilationFieldsPayload.STREAM_CODEC, + AntarchyTimeDilationNetworking::handleTimeDilationFields + ); } - public static void syncRate(ServerPlayer player, double rate) { - PacketDistributor.sendToPlayer(player, new TimeDilationRatePayload(player.getId(), rate)); + public static void syncRate(Entity entity, double rate) { + PacketDistributor.sendToPlayersTrackingEntityAndSelf(entity, new TimeDilationRatePayload(entity.getUUID(), rate)); + } + + public static void syncRateToPlayer(ServerPlayer player, Entity entity, double rate) { + PacketDistributor.sendToPlayer(player, new TimeDilationRatePayload(entity.getUUID(), rate)); + } + + public static void syncFields(ServerPlayer player, List fields) { + PacketDistributor.sendToPlayer(player, new TimeDilationFieldsPayload(fields)); } private static void handleTimeDilationRate(TimeDilationRatePayload payload, IPayloadContext context) { context.enqueueWork(() -> { - Entity entity = context.player().level().getEntity(payload.entityId()); - if (entity == null && context.player().getId() == payload.entityId()) { - entity = context.player(); - } - if (entity != null) { - TimeDilationApi.applySyncedRate(entity, payload.rate()); - } + TimeDilationApi.applySyncedRate(payload.entityUuid(), payload.rate()); }); } + + private static void handleTimeDilationFields(TimeDilationFieldsPayload payload, IPayloadContext context) { + context.enqueueWork(() -> com.craisinlord.antarchy.content.client.ClientTimeDilationTicker.applyFields(payload.fields())); + } } diff --git a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoForgeEvents.java b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoForgeEvents.java index 1ba97851..cac6d5c8 100644 --- a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoForgeEvents.java +++ b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoForgeEvents.java @@ -304,6 +304,12 @@ public final class AntarchyNeoForgeEvents { } AntarchyGravityNetworking.syncEntity(event.getTarget()); + if (event.getTarget() instanceof com.craisinlord.antarchy.content.time.TimeDilationEntityAccess access + && event.getEntity() instanceof ServerPlayer trackingPlayer) { + com.craisinlord.antarchy.neoforge.network.AntarchyTimeDilationNetworking.syncRateToPlayer( + trackingPlayer, event.getTarget(), access.antarchy$getTimeDilationRate() + ); + } if (event.getTarget() instanceof ServerPlayer trackedPlayer && event.getEntity() instanceof ServerPlayer trackingPlayer) { TigerEyeCamouflageSync.syncTo(trackingPlayer, trackedPlayer); } diff --git a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeEntites.java b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeEntites.java index ebcc019e..5ef287a5 100644 --- a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeEntites.java +++ b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeEntites.java @@ -384,6 +384,13 @@ public final class AntarchyNeoforgeEntites { .clientTrackingRange(10) .updateInterval(1) .build("wind_vortex")); + public static final DeferredHolder, EntityType> ROYAL_BLACK_HOLE = ENTITY_TYPES.register("royal_black_hole", + () -> EntityType.Builder.of(com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity::new, MobCategory.MISC) + .sized(1.0F, 1.0F) + .clientTrackingRange(16) + .updateInterval(2) + .fireImmune() + .build("royal_black_hole")); public static final DeferredHolder, EntityType> TIME_DILATION_FIELD = ENTITY_TYPES.register("time_dilation_field", () -> EntityType.Builder.of(TimeDilationFieldEntity::new, MobCategory.MISC) .sized(0.5F, 0.5F) diff --git a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeSounds.java b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeSounds.java index bef946c0..c89e66d9 100644 --- a/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeSounds.java +++ b/neoforge-1.21.1/src/main/java/com/craisinlord/antarchy/neoforge/registry/AntarchyNeoforgeSounds.java @@ -235,6 +235,17 @@ public final class AntarchyNeoforgeSounds { public static final DeferredHolder QUEEN_BLACK_HOLE_SHOOT = registerSoundEvent("queen_black_hole_shoot"); public static final DeferredHolder QUEEN_CAST_SHOOT = registerSoundEvent("queen_cast_shoot"); + public static final DeferredHolder PRINCE_IDLE = registerSoundEvent("prince_idle"); + public static final DeferredHolder PRINCE_BITE = registerSoundEvent("prince_bite"); + public static final DeferredHolder PRINCE_SHOOT = registerSoundEvent("prince_shoot"); + public static final DeferredHolder PRINCE_FLY = registerSoundEvent("prince_fly"); + public static final DeferredHolder PRINCE_STEP = registerSoundEvent("prince_step"); + public static final DeferredHolder PRINCESS_IDLE = registerSoundEvent("princess_idle"); + public static final DeferredHolder PRINCESS_BITE = registerSoundEvent("princess_bite"); + public static final DeferredHolder PRINCESS_SHOOT = registerSoundEvent("princess_shoot"); + public static final DeferredHolder PRINCESS_FLY = registerSoundEvent("princess_fly"); + public static final DeferredHolder PRINCESS_STEP = registerSoundEvent("princess_step"); + private AntarchyNeoforgeSounds() {} public static void register(IEventBus modEventBus) {