big king and queen dev
This commit is contained in:
1 parent
d34830a99b
commit
68eba61022
169 files changed
+4779
-942
No files matched your search
@@ -1368,6 +1368,8 @@ public final class AntarchySettings {
|
|||||||
public static void setKrakensGraspAttackSpeed(double value) { krakensGraspAttackSpeed = value; }
|
public static void setKrakensGraspAttackSpeed(double value) { krakensGraspAttackSpeed = value; }
|
||||||
public static void setKrakensGraspThrownDamage(double value) { krakensGraspThrownDamage = value; }
|
public static void setKrakensGraspThrownDamage(double value) { krakensGraspThrownDamage = value; }
|
||||||
public static void setKrakensGraspLightningDamage(double value) { krakensGraspLightningDamage = value; }
|
public static void setKrakensGraspLightningDamage(double value) { krakensGraspLightningDamage = value; }
|
||||||
|
|
||||||
|
public static double krakensGraspLightningDamage() { return krakensGraspLightningDamage; }
|
||||||
public static void setKrakensGraspInnateLoyalty(boolean value) { krakensGraspInnateLoyalty = value; }
|
public static void setKrakensGraspInnateLoyalty(boolean value) { krakensGraspInnateLoyalty = value; }
|
||||||
public static void setKrakensGraspInnateLoyaltyLevel(int value) { krakensGraspInnateLoyaltyLevel = value; }
|
public static void setKrakensGraspInnateLoyaltyLevel(int value) { krakensGraspInnateLoyaltyLevel = value; }
|
||||||
public static void setKrakensGraspTentacleDurationTicks(int value) { krakensGraspTentacleDurationTicks = value; }
|
public static void setKrakensGraspTentacleDurationTicks(int value) { krakensGraspTentacleDurationTicks = value; }
|
||||||
|
|||||||
+2
-1
@@ -73,6 +73,7 @@ import software.bernie.geckolib.core.animation.RawAnimation;
|
|||||||
import software.bernie.geckolib.util.GeckoLibUtil;
|
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||||
|
|
||||||
public class ReverieEntity extends PathfinderMob implements FlyingAnimal, GeoEntity {
|
public class ReverieEntity extends PathfinderMob implements FlyingAnimal, GeoEntity {
|
||||||
|
private static final int DAMAGE_REACTION_DURATION_TICKS = 40;
|
||||||
private static final EntityDataAccessor<Integer> MOOD =
|
private static final EntityDataAccessor<Integer> MOOD =
|
||||||
SynchedEntityData.defineId(ReverieEntity.class, EntityDataSerializers.INT);
|
SynchedEntityData.defineId(ReverieEntity.class, EntityDataSerializers.INT);
|
||||||
private static final EntityDataAccessor<Integer> ANIMATION_STATE =
|
private static final EntityDataAccessor<Integer> ANIMATION_STATE =
|
||||||
@@ -309,7 +310,7 @@ public class ReverieEntity extends PathfinderMob implements FlyingAnimal, GeoEnt
|
|||||||
this.releaseFocus();
|
this.releaseFocus();
|
||||||
this.clearNoticePlayer();
|
this.clearNoticePlayer();
|
||||||
this.ambientTarget = null;
|
this.ambientTarget = null;
|
||||||
this.damageReactionTicks = 0;
|
this.damageReactionTicks = DAMAGE_REACTION_DURATION_TICKS;
|
||||||
this.inversionReactionTicks = 0;
|
this.inversionReactionTicks = 0;
|
||||||
this.transitionToMood(Mood.WHITE);
|
this.transitionToMood(Mood.WHITE);
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-4
@@ -15,6 +15,8 @@ import net.minecraft.world.entity.MobSpawnType;
|
|||||||
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||||
import net.minecraft.world.entity.ai.goal.FloatGoal;
|
import net.minecraft.world.entity.ai.goal.FloatGoal;
|
||||||
|
import net.minecraft.world.entity.ai.goal.BreedGoal;
|
||||||
|
import net.minecraft.world.entity.ai.goal.TemptGoal;
|
||||||
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
|
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
|
||||||
import net.minecraft.world.entity.ai.goal.PanicGoal;
|
import net.minecraft.world.entity.ai.goal.PanicGoal;
|
||||||
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
|
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
|
||||||
@@ -23,6 +25,8 @@ import net.minecraft.world.entity.animal.Animal;
|
|||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.sounds.SoundEvent;
|
import net.minecraft.sounds.SoundEvent;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
|
import net.minecraft.world.item.crafting.Ingredient;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.ServerLevelAccessor;
|
import net.minecraft.world.level.ServerLevelAccessor;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -76,9 +80,11 @@ public class StinkBugEntity extends Animal implements GeoEntity {
|
|||||||
protected void registerGoals() {
|
protected void registerGoals() {
|
||||||
this.goalSelector.addGoal(0, new FloatGoal(this));
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
||||||
this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D));
|
this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D));
|
||||||
this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 0.9D));
|
this.goalSelector.addGoal(2, new TemptGoal(this, 1.0D, Ingredient.of(Items.ROTTEN_FLESH), false));
|
||||||
this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 6.0F));
|
this.goalSelector.addGoal(3, new BreedGoal(this, 0.9D));
|
||||||
this.goalSelector.addGoal(4, new RandomLookAroundGoal(this));
|
this.goalSelector.addGoal(4, new WaterAvoidingRandomStrollGoal(this, 0.9D));
|
||||||
|
this.goalSelector.addGoal(5, new LookAtPlayerGoal(this, Player.class, 6.0F));
|
||||||
|
this.goalSelector.addGoal(6, new RandomLookAroundGoal(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -108,7 +114,7 @@ public class StinkBugEntity extends Animal implements GeoEntity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFood(ItemStack stack) {
|
public boolean isFood(ItemStack stack) {
|
||||||
return false;
|
return stack.is(Items.ROTTEN_FLESH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+2
-1
@@ -1026,7 +1026,8 @@ public class KrakenEntity extends Monster implements GeoEntity, MultipartEntityO
|
|||||||
for (int i = 0; i < strikeBolts; i++) {
|
for (int i = 0; i < strikeBolts; i++) {
|
||||||
this.spawnVisualLightning(serverLevel, this.getTargetStormStrikePos(target));
|
this.spawnVisualLightning(serverLevel, this.getTargetStormStrikePos(target));
|
||||||
}
|
}
|
||||||
target.hurt(AntarchyDamageSources.krakenLightning(serverLevel, this), this.isPhaseTwo() ? 12.0F : 8.0F);
|
target.hurt(AntarchyDamageSources.krakenLightning(serverLevel, this),
|
||||||
|
this.isPhaseTwo() ? 12.0F : AntarchySettings.krakenLightningDamagePhaseOne());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.lightningStrikeCooldown = this.isPhaseTwo() ? 30 : 60;
|
this.lightningStrikeCooldown = this.isPhaseTwo() ? 30 : 60;
|
||||||
|
|||||||
+2
@@ -91,12 +91,14 @@ public class KrakensGraspItem extends TridentItem {
|
|||||||
|
|
||||||
public static void strikeLightning(LivingEntity target, ServerLevel level) {
|
public static void strikeLightning(LivingEntity target, ServerLevel level) {
|
||||||
strikeLightningAt(level, target.getX(), target.getY(), target.getZ());
|
strikeLightningAt(level, target.getX(), target.getY(), target.getZ());
|
||||||
|
target.hurt(level.damageSources().lightningBolt(), (float) AntarchySettings.krakensGraspLightningDamage());
|
||||||
level.sendParticles(ParticleTypes.ELECTRIC_SPARK, target.getX(), target.getY(0.7D), target.getZ(), 10, 0.25D, 0.25D, 0.25D, 0.02D);
|
level.sendParticles(ParticleTypes.ELECTRIC_SPARK, target.getX(), target.getY(0.7D), target.getZ(), 10, 0.25D, 0.25D, 0.25D, 0.02D);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void strikeLightningAt(ServerLevel level, double x, double y, double z) {
|
public static void strikeLightningAt(ServerLevel level, double x, double y, double z) {
|
||||||
LightningBolt lightningBolt = new LightningBolt(net.minecraft.world.entity.EntityType.LIGHTNING_BOLT, level);
|
LightningBolt lightningBolt = new LightningBolt(net.minecraft.world.entity.EntityType.LIGHTNING_BOLT, level);
|
||||||
lightningBolt.moveTo(x, y, z);
|
lightningBolt.moveTo(x, y, z);
|
||||||
|
lightningBolt.setVisualOnly(true);
|
||||||
level.addFreshEntity(lightningBolt);
|
level.addFreshEntity(lightningBolt);
|
||||||
level.sendParticles(ParticleTypes.ELECTRIC_SPARK, x, y + 0.2D, z, 10, 0.25D, 0.25D, 0.25D, 0.02D);
|
level.sendParticles(ParticleTypes.ELECTRIC_SPARK, x, y + 0.2D, z, 10, 0.25D, 0.25D, 0.25D, 0.02D);
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "minecraft:block/air"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "minecraft:block/air"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "minecraft:block/air"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"format_version": "1.21.110",
|
"format_version": "1.12.0",
|
||||||
"minecraft:geometry": [
|
"minecraft:geometry": [
|
||||||
{
|
{
|
||||||
"description": {
|
"description": {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"format_version": "1.21.110",
|
"format_version": "1.12.0",
|
||||||
"minecraft:geometry": [
|
"minecraft:geometry": [
|
||||||
{
|
{
|
||||||
"description": {
|
"description": {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"format_version": "1.21.110",
|
"format_version": "1.12.0",
|
||||||
"minecraft:geometry": [
|
"minecraft:geometry": [
|
||||||
{
|
{
|
||||||
"description": {
|
"description": {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"format_version": "1.21.110",
|
"format_version": "1.12.0",
|
||||||
"minecraft:geometry": [
|
"minecraft:geometry": [
|
||||||
{
|
{
|
||||||
"description": {
|
"description": {
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"textures": {
|
"textures": {
|
||||||
"particle": "antarchy:block/nadir/nadir_hanging"
|
"particle": "antarchy:block/nadir/nadir_planks"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"textures": {
|
"textures": {
|
||||||
"particle": "antarchy:block/nadir/nadir_hanging"
|
"particle": "antarchy:block/nadir/nadir_planks"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,11 +91,11 @@ public final class AntarchySettings {
|
|||||||
private static double bigBerthaNoneModeDamageBonusPercent = 15.0D;
|
private static double bigBerthaNoneModeDamageBonusPercent = 15.0D;
|
||||||
private static double bigBerthaNightmareDamageBonusPercent = 30.0D;
|
private static double bigBerthaNightmareDamageBonusPercent = 30.0D;
|
||||||
private static double potentNyxiteInvertedDurationSeconds = 60.0D;
|
private static double potentNyxiteInvertedDurationSeconds = 60.0D;
|
||||||
private static boolean dimensionalTearsSpawnNaturally = false;
|
private static boolean dimensionalTearsSpawnNaturally = true;
|
||||||
private static int dimensionalTearLifetimeTicks = 24000;
|
private static int dimensionalTearLifetimeTicks = 24000;
|
||||||
private static int dimensionalTearInvertedDurationTicks = 2400;
|
private static int dimensionalTearInvertedDurationTicks = 2400;
|
||||||
private static int dimensionalTearEmergenceMinIntervalTicks = 2400;
|
private static int dimensionalTearEmergenceMinIntervalTicks = 400;
|
||||||
private static int dimensionalTearEmergenceMaxIntervalTicks = 7200;
|
private static int dimensionalTearEmergenceMaxIntervalTicks = 1200;
|
||||||
private static float dimensionalTearLucidEventChance = 0.65F;
|
private static float dimensionalTearLucidEventChance = 0.65F;
|
||||||
private static int ultimateToolEnchantability = 25;
|
private static int ultimateToolEnchantability = 25;
|
||||||
private static int ultimateArmorEnchantability = 10;
|
private static int ultimateArmorEnchantability = 10;
|
||||||
@@ -250,6 +250,23 @@ public final class AntarchySettings {
|
|||||||
private static double queenHealth = 6000.0D;
|
private static double queenHealth = 6000.0D;
|
||||||
private static double kingAttackDamage = 50.0D;
|
private static double kingAttackDamage = 50.0D;
|
||||||
private static double queenAttackDamage = 45.0D;
|
private static double queenAttackDamage = 45.0D;
|
||||||
|
private static double royalBossSoundVolume = 4.5D;
|
||||||
|
private static double queenBlackHoleRadius = 14.0D;
|
||||||
|
private static int queenBlackHoleActiveTicks = 120;
|
||||||
|
private static double queenBlackHolePullStrength = 0.16D;
|
||||||
|
private static double queenFinalTimeFieldRadius = 20.0D;
|
||||||
|
private static double queenFinalTimeFieldRate = 0.05D;
|
||||||
|
private static int queenFinalTimeFieldDurationTicks = 45;
|
||||||
|
private static int queenFinalTimeFieldCooldownTicks = 80;
|
||||||
|
private static double kingFireballDamage = 32.0D;
|
||||||
|
private static double kingFireballRadius = 4.5D;
|
||||||
|
private static int kingFireballCooldownTicks = 150;
|
||||||
|
private static double kingIceballDamage = 18.0D;
|
||||||
|
private static double kingIceballRadius = 5.0D;
|
||||||
|
private static int kingIceballCooldownTicks = 190;
|
||||||
|
private static double kingIceSpikeDamage = 24.0D;
|
||||||
|
private static int kingIceSpikeCooldownTicks = 240;
|
||||||
|
private static int kingElementalTerrainCap = 256;
|
||||||
private static double royalBossArmor = 20.0D;
|
private static double royalBossArmor = 20.0D;
|
||||||
private static double royalBossFollowRange = 128.0D;
|
private static double royalBossFollowRange = 128.0D;
|
||||||
private static double royalBossMovementSpeed = 0.22D;
|
private static double royalBossMovementSpeed = 0.22D;
|
||||||
@@ -391,7 +408,7 @@ public final class AntarchySettings {
|
|||||||
private static double toreterrorDamageRange = 25.0D;
|
private static double toreterrorDamageRange = 25.0D;
|
||||||
private static double brutalflyDamageRange = 25.0D;
|
private static double brutalflyDamageRange = 25.0D;
|
||||||
private static double alphaMantisDamageRange = 25.0D;
|
private static double alphaMantisDamageRange = 25.0D;
|
||||||
private static float krakenLightningDamagePhaseOne = 12.0F;
|
private static float krakenLightningDamagePhaseOne = 6.0F;
|
||||||
private static double lucidHealth = 70.0D;
|
private static double lucidHealth = 70.0D;
|
||||||
private static double lucidAttackDamage = 4.0D;
|
private static double lucidAttackDamage = 4.0D;
|
||||||
private static double lucidMovementSpeed = 0.22D;
|
private static double lucidMovementSpeed = 0.22D;
|
||||||
@@ -402,7 +419,7 @@ public final class AntarchySettings {
|
|||||||
private static double vortexMovementSpeed = 0.22D;
|
private static double vortexMovementSpeed = 0.22D;
|
||||||
private static double vortexFlyingSpeed = 0.35D;
|
private static double vortexFlyingSpeed = 0.35D;
|
||||||
private static int vortexMaxActiveVortexes = 3;
|
private static int vortexMaxActiveVortexes = 3;
|
||||||
private static int windVortexDurationTicks = 140;
|
private static int windVortexDurationTicks = 240;
|
||||||
private static double windVortexPullStrength = 0.32D;
|
private static double windVortexPullStrength = 0.32D;
|
||||||
private static double windVortexLaunchStrength = 1.0D;
|
private static double windVortexLaunchStrength = 1.0D;
|
||||||
private static boolean eyeOfTheStormEnabled = true;
|
private static boolean eyeOfTheStormEnabled = true;
|
||||||
@@ -534,6 +551,8 @@ public final class AntarchySettings {
|
|||||||
private static double queenBeamDamage = 45.0D;
|
private static double queenBeamDamage = 45.0D;
|
||||||
private static double queenBeamRange = 100.0D;
|
private static double queenBeamRange = 100.0D;
|
||||||
private static int queenBeamDurationTicks = 30;
|
private static int queenBeamDurationTicks = 30;
|
||||||
|
private static int queenBeamWindupTicks = 20;
|
||||||
|
private static int queenBeamTravelTicks = 12;
|
||||||
private static int queenBeamCooldownTicks = 90;
|
private static int queenBeamCooldownTicks = 90;
|
||||||
private static double queenBeamTracking = 0.1D;
|
private static double queenBeamTracking = 0.1D;
|
||||||
private static double queenBeamTerrainRadius = 5.0D;
|
private static double queenBeamTerrainRadius = 5.0D;
|
||||||
@@ -541,6 +560,8 @@ public final class AntarchySettings {
|
|||||||
private static double kingBeamDamage = 50.0D;
|
private static double kingBeamDamage = 50.0D;
|
||||||
private static double kingBeamRange = 100.0D;
|
private static double kingBeamRange = 100.0D;
|
||||||
private static int kingBeamDurationTicks = 30;
|
private static int kingBeamDurationTicks = 30;
|
||||||
|
private static int kingBeamWindupTicks = 20;
|
||||||
|
private static int kingBeamTravelTicks = 12;
|
||||||
private static int kingBeamCooldownTicks = 90;
|
private static int kingBeamCooldownTicks = 90;
|
||||||
private static double kingBeamTracking = 0.1D;
|
private static double kingBeamTracking = 0.1D;
|
||||||
private static double kingBeamTerrainRadius = 5.0D;
|
private static double kingBeamTerrainRadius = 5.0D;
|
||||||
@@ -803,6 +824,8 @@ public final class AntarchySettings {
|
|||||||
return bigBerthaNightmareDamageBonusPercent;
|
return bigBerthaNightmareDamageBonusPercent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static double krakensGraspLightningDamage() { return krakensGraspLightningDamage; }
|
||||||
|
|
||||||
public static double potentNyxiteInvertedDurationSeconds() {
|
public static double potentNyxiteInvertedDurationSeconds() {
|
||||||
return potentNyxiteInvertedDurationSeconds;
|
return potentNyxiteInvertedDurationSeconds;
|
||||||
}
|
}
|
||||||
@@ -2013,6 +2036,40 @@ public final class AntarchySettings {
|
|||||||
|
|
||||||
public static double queenAttackDamage() { return queenAttackDamage; }
|
public static double queenAttackDamage() { return queenAttackDamage; }
|
||||||
public static void setQueenAttackDamage(double v) { queenAttackDamage = v; }
|
public static void setQueenAttackDamage(double v) { queenAttackDamage = v; }
|
||||||
|
public static double royalBossSoundVolume() { return royalBossSoundVolume; }
|
||||||
|
public static void setRoyalBossSoundVolume(double v) { royalBossSoundVolume = v; }
|
||||||
|
public static double queenBlackHoleRadius() { return queenBlackHoleRadius; }
|
||||||
|
public static void setQueenBlackHoleRadius(double v) { queenBlackHoleRadius = v; }
|
||||||
|
public static int queenBlackHoleActiveTicks() { return queenBlackHoleActiveTicks; }
|
||||||
|
public static void setQueenBlackHoleActiveTicks(int v) { queenBlackHoleActiveTicks = v; }
|
||||||
|
public static double queenBlackHolePullStrength() { return queenBlackHolePullStrength; }
|
||||||
|
public static void setQueenBlackHolePullStrength(double v) { queenBlackHolePullStrength = v; }
|
||||||
|
public static double queenFinalTimeFieldRadius() { return queenFinalTimeFieldRadius; }
|
||||||
|
public static void setQueenFinalTimeFieldRadius(double v) { queenFinalTimeFieldRadius = v; }
|
||||||
|
public static double queenFinalTimeFieldRate() { return queenFinalTimeFieldRate; }
|
||||||
|
public static void setQueenFinalTimeFieldRate(double v) { queenFinalTimeFieldRate = v; }
|
||||||
|
public static int queenFinalTimeFieldDurationTicks() { return queenFinalTimeFieldDurationTicks; }
|
||||||
|
public static void setQueenFinalTimeFieldDurationTicks(int v) { queenFinalTimeFieldDurationTicks = v; }
|
||||||
|
public static int queenFinalTimeFieldCooldownTicks() { return queenFinalTimeFieldCooldownTicks; }
|
||||||
|
public static void setQueenFinalTimeFieldCooldownTicks(int v) { queenFinalTimeFieldCooldownTicks = v; }
|
||||||
|
public static double kingFireballDamage() { return kingFireballDamage; }
|
||||||
|
public static void setKingFireballDamage(double v) { kingFireballDamage = v; }
|
||||||
|
public static double kingFireballRadius() { return kingFireballRadius; }
|
||||||
|
public static void setKingFireballRadius(double v) { kingFireballRadius = v; }
|
||||||
|
public static int kingFireballCooldownTicks() { return kingFireballCooldownTicks; }
|
||||||
|
public static void setKingFireballCooldownTicks(int v) { kingFireballCooldownTicks = v; }
|
||||||
|
public static double kingIceballDamage() { return kingIceballDamage; }
|
||||||
|
public static void setKingIceballDamage(double v) { kingIceballDamage = v; }
|
||||||
|
public static double kingIceballRadius() { return kingIceballRadius; }
|
||||||
|
public static void setKingIceballRadius(double v) { kingIceballRadius = v; }
|
||||||
|
public static int kingIceballCooldownTicks() { return kingIceballCooldownTicks; }
|
||||||
|
public static void setKingIceballCooldownTicks(int v) { kingIceballCooldownTicks = v; }
|
||||||
|
public static double kingIceSpikeDamage() { return kingIceSpikeDamage; }
|
||||||
|
public static void setKingIceSpikeDamage(double v) { kingIceSpikeDamage = v; }
|
||||||
|
public static int kingIceSpikeCooldownTicks() { return kingIceSpikeCooldownTicks; }
|
||||||
|
public static void setKingIceSpikeCooldownTicks(int v) { kingIceSpikeCooldownTicks = v; }
|
||||||
|
public static int kingElementalTerrainCap() { return kingElementalTerrainCap; }
|
||||||
|
public static void setKingElementalTerrainCap(int v) { kingElementalTerrainCap = v; }
|
||||||
|
|
||||||
public static double royalBossArmor() { return royalBossArmor; }
|
public static double royalBossArmor() { return royalBossArmor; }
|
||||||
public static void setRoyalBossArmor(double v) { royalBossArmor = v; }
|
public static void setRoyalBossArmor(double v) { royalBossArmor = v; }
|
||||||
@@ -2832,6 +2889,10 @@ public final class AntarchySettings {
|
|||||||
public static void setQueenBeamRange(double v) { queenBeamRange = v; }
|
public static void setQueenBeamRange(double v) { queenBeamRange = v; }
|
||||||
public static int queenBeamDurationTicks() { return queenBeamDurationTicks; }
|
public static int queenBeamDurationTicks() { return queenBeamDurationTicks; }
|
||||||
public static void setQueenBeamDurationTicks(int v) { queenBeamDurationTicks = v; }
|
public static void setQueenBeamDurationTicks(int v) { queenBeamDurationTicks = v; }
|
||||||
|
public static int queenBeamWindupTicks() { return queenBeamWindupTicks; }
|
||||||
|
public static void setQueenBeamWindupTicks(int v) { queenBeamWindupTicks = v; }
|
||||||
|
public static int queenBeamTravelTicks() { return queenBeamTravelTicks; }
|
||||||
|
public static void setQueenBeamTravelTicks(int v) { queenBeamTravelTicks = v; }
|
||||||
public static int queenBeamCooldownTicks() { return queenBeamCooldownTicks; }
|
public static int queenBeamCooldownTicks() { return queenBeamCooldownTicks; }
|
||||||
public static void setQueenBeamCooldownTicks(int v) { queenBeamCooldownTicks = v; }
|
public static void setQueenBeamCooldownTicks(int v) { queenBeamCooldownTicks = v; }
|
||||||
public static double queenBeamTracking() { return queenBeamTracking; }
|
public static double queenBeamTracking() { return queenBeamTracking; }
|
||||||
@@ -2846,6 +2907,10 @@ public final class AntarchySettings {
|
|||||||
public static void setKingBeamRange(double v) { kingBeamRange = v; }
|
public static void setKingBeamRange(double v) { kingBeamRange = v; }
|
||||||
public static int kingBeamDurationTicks() { return kingBeamDurationTicks; }
|
public static int kingBeamDurationTicks() { return kingBeamDurationTicks; }
|
||||||
public static void setKingBeamDurationTicks(int v) { kingBeamDurationTicks = v; }
|
public static void setKingBeamDurationTicks(int v) { kingBeamDurationTicks = v; }
|
||||||
|
public static int kingBeamWindupTicks() { return kingBeamWindupTicks; }
|
||||||
|
public static void setKingBeamWindupTicks(int v) { kingBeamWindupTicks = v; }
|
||||||
|
public static int kingBeamTravelTicks() { return kingBeamTravelTicks; }
|
||||||
|
public static void setKingBeamTravelTicks(int v) { kingBeamTravelTicks = v; }
|
||||||
public static int kingBeamCooldownTicks() { return kingBeamCooldownTicks; }
|
public static int kingBeamCooldownTicks() { return kingBeamCooldownTicks; }
|
||||||
public static void setKingBeamCooldownTicks(int v) { kingBeamCooldownTicks = v; }
|
public static void setKingBeamCooldownTicks(int v) { kingBeamCooldownTicks = v; }
|
||||||
public static double kingBeamTracking() { return kingBeamTracking; }
|
public static double kingBeamTracking() { return kingBeamTracking; }
|
||||||
|
|||||||
@@ -157,6 +157,10 @@ public final class AntarchyObjects {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalBoltEntity>> ROYAL_BOLT = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalBoltEntity>>) UNBOUND;
|
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalBoltEntity>> ROYAL_BOLT = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalBoltEntity>>) UNBOUND;
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalElementalProjectileEntity>> ROYAL_ELEMENTAL_PROJECTILE = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalElementalProjectileEntity>>) UNBOUND;
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalIceSpikeEntity>> ROYAL_ICE_SPIKE = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalIceSpikeEntity>>) UNBOUND;
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.KingEntity>> KING = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.KingEntity>>) UNBOUND;
|
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.KingEntity>> KING = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.KingEntity>>) UNBOUND;
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.QueenEntity>> QUEEN = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.QueenEntity>>) UNBOUND;
|
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.QueenEntity>> QUEEN = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.QueenEntity>>) UNBOUND;
|
||||||
@@ -725,6 +729,14 @@ public final class AntarchyObjects {
|
|||||||
ROYAL_BOLT = supplier;
|
ROYAL_BOLT = supplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setRoyalElementalProjectile(Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalElementalProjectileEntity>> supplier) {
|
||||||
|
ROYAL_ELEMENTAL_PROJECTILE = supplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setRoyalIceSpike(Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalIceSpikeEntity>> supplier) {
|
||||||
|
ROYAL_ICE_SPIKE = supplier;
|
||||||
|
}
|
||||||
|
|
||||||
public static void setKing(Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.KingEntity>> supplier) {
|
public static void setKing(Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.KingEntity>> supplier) {
|
||||||
KING = supplier;
|
KING = supplier;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -202,6 +202,7 @@ public final class AntarchySoundEvents {
|
|||||||
public static Supplier<SoundEvent> KING_ROAR = (Supplier<SoundEvent>) UNBOUND;
|
public static Supplier<SoundEvent> KING_ROAR = (Supplier<SoundEvent>) UNBOUND;
|
||||||
public static Supplier<SoundEvent> KING_WING_FLAP = (Supplier<SoundEvent>) UNBOUND;
|
public static Supplier<SoundEvent> KING_WING_FLAP = (Supplier<SoundEvent>) UNBOUND;
|
||||||
public static Supplier<SoundEvent> KING_FLY_LOOP = (Supplier<SoundEvent>) UNBOUND;
|
public static Supplier<SoundEvent> KING_FLY_LOOP = (Supplier<SoundEvent>) UNBOUND;
|
||||||
|
public static Supplier<SoundEvent> QUEEN_FLY_LOOP = (Supplier<SoundEvent>) UNBOUND;
|
||||||
public static Supplier<SoundEvent> PRINCE_IDLE = (Supplier<SoundEvent>) UNBOUND;
|
public static Supplier<SoundEvent> PRINCE_IDLE = (Supplier<SoundEvent>) UNBOUND;
|
||||||
public static Supplier<SoundEvent> PRINCE_BITE = (Supplier<SoundEvent>) UNBOUND;
|
public static Supplier<SoundEvent> PRINCE_BITE = (Supplier<SoundEvent>) UNBOUND;
|
||||||
public static Supplier<SoundEvent> PRINCE_SHOOT = (Supplier<SoundEvent>) UNBOUND;
|
public static Supplier<SoundEvent> PRINCE_SHOOT = (Supplier<SoundEvent>) UNBOUND;
|
||||||
@@ -406,6 +407,7 @@ public final class AntarchySoundEvents {
|
|||||||
Supplier<SoundEvent> kingRoar,
|
Supplier<SoundEvent> kingRoar,
|
||||||
Supplier<SoundEvent> kingWingFlap,
|
Supplier<SoundEvent> kingWingFlap,
|
||||||
Supplier<SoundEvent> kingFlyLoop,
|
Supplier<SoundEvent> kingFlyLoop,
|
||||||
|
Supplier<SoundEvent> queenFlyLoop,
|
||||||
Supplier<SoundEvent> princeIdle,
|
Supplier<SoundEvent> princeIdle,
|
||||||
Supplier<SoundEvent> princeBite,
|
Supplier<SoundEvent> princeBite,
|
||||||
Supplier<SoundEvent> princeShoot,
|
Supplier<SoundEvent> princeShoot,
|
||||||
@@ -606,6 +608,7 @@ public final class AntarchySoundEvents {
|
|||||||
KING_ROAR = kingRoar;
|
KING_ROAR = kingRoar;
|
||||||
KING_WING_FLAP = kingWingFlap;
|
KING_WING_FLAP = kingWingFlap;
|
||||||
KING_FLY_LOOP = kingFlyLoop;
|
KING_FLY_LOOP = kingFlyLoop;
|
||||||
|
QUEEN_FLY_LOOP = queenFlyLoop;
|
||||||
PRINCE_IDLE = princeIdle;
|
PRINCE_IDLE = princeIdle;
|
||||||
PRINCE_BITE = princeBite;
|
PRINCE_BITE = princeBite;
|
||||||
PRINCE_SHOOT = princeShoot;
|
PRINCE_SHOOT = princeShoot;
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ public final class AntarchyTags {
|
|||||||
public static final TagKey<EntityType<?>> DIMENSIONAL_TEAR_COMMON_SPAWNS = TagKey.create(Registries.ENTITY_TYPE, id("dimensional_tear_common_spawns"));
|
public static final TagKey<EntityType<?>> DIMENSIONAL_TEAR_COMMON_SPAWNS = TagKey.create(Registries.ENTITY_TYPE, id("dimensional_tear_common_spawns"));
|
||||||
public static final TagKey<EntityType<?>> DIMENSIONAL_TEAR_RARE_SPAWNS = TagKey.create(Registries.ENTITY_TYPE, id("dimensional_tear_rare_spawns"));
|
public static final TagKey<EntityType<?>> DIMENSIONAL_TEAR_RARE_SPAWNS = TagKey.create(Registries.ENTITY_TYPE, id("dimensional_tear_rare_spawns"));
|
||||||
public static final TagKey<EntityType<?>> TIME_DILATION_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("time_dilation_immune"));
|
public static final TagKey<EntityType<?>> TIME_DILATION_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("time_dilation_immune"));
|
||||||
|
public static final TagKey<EntityType<?>> COMMANDED_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("commanded_blacklist"));
|
||||||
|
public static final TagKey<EntityType<?>> DILATED_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("dilated_blacklist"));
|
||||||
|
|
||||||
private Entities() {
|
private Entities() {
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-7
@@ -12,17 +12,23 @@ import net.minecraft.util.RandomSource;
|
|||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public class DimensionalTearMarkerBlockEntity extends BlockEntity {
|
public class DimensionalTearMarkerBlockEntity extends BlockEntity {
|
||||||
private static final int MAX_ATTEMPT_TICKS = 100;
|
private static final int MAX_ATTEMPT_TICKS = 80;
|
||||||
private static final int MIN_LINK_RANGE = 50;
|
private static final int MIN_LINK_RANGE = 50;
|
||||||
private static final int MAX_LINK_RANGE = 500;
|
private static final int MAX_LINK_RANGE = 500;
|
||||||
private static final int PARTNER_ORIGIN_ATTEMPTS = 12;
|
private static final int PARTNER_ORIGIN_ATTEMPTS = 8;
|
||||||
private static final int PARTNER_SEARCH_ATTEMPTS = 48;
|
private static final int PARTNER_SEARCH_ATTEMPTS = 32;
|
||||||
private static final int LOCAL_SEARCH_ATTEMPTS = 18;
|
private static final int LOCAL_SEARCH_ATTEMPTS = 12;
|
||||||
private static final int SEARCH_ATTEMPTS_PER_TICK = 2;
|
private static final int SEARCH_ATTEMPTS_PER_TICK = 1;
|
||||||
|
private static final int MIN_VERTICAL_SEPARATION = 24;
|
||||||
|
private static final int MIN_PARTNER_VERTICAL_OFFSET = 48;
|
||||||
|
private static final int MAX_PARTNER_VERTICAL_OFFSET = 96;
|
||||||
|
private static final int NATURAL_TEAR_LOCAL_RADIUS = 512;
|
||||||
|
private static final int NATURAL_TEAR_LOCAL_CAP = 6;
|
||||||
|
|
||||||
private int attemptTicks;
|
private int attemptTicks;
|
||||||
private int localAttempts;
|
private int localAttempts;
|
||||||
@@ -64,6 +70,11 @@ public class DimensionalTearMarkerBlockEntity extends BlockEntity {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (partnerOrigin == null && partnerOriginAttempts == 0
|
||||||
|
&& countNearbyTears(level, origin) >= NATURAL_TEAR_LOCAL_CAP) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (partnerOrigin == null || partnerSearchAttempts >= PARTNER_SEARCH_ATTEMPTS) {
|
if (partnerOrigin == null || partnerSearchAttempts >= PARTNER_SEARCH_ATTEMPTS) {
|
||||||
if (partnerOriginAttempts >= PARTNER_ORIGIN_ATTEMPTS) {
|
if (partnerOriginAttempts >= PARTNER_ORIGIN_ATTEMPTS) {
|
||||||
return false;
|
return false;
|
||||||
@@ -75,7 +86,8 @@ public class DimensionalTearMarkerBlockEntity extends BlockEntity {
|
|||||||
|
|
||||||
partnerSearchAttempts++;
|
partnerSearchAttempts++;
|
||||||
BlockPos candidate = randomCandidate(partnerOrigin, random);
|
BlockPos candidate = randomCandidate(partnerOrigin, random);
|
||||||
if (!isUsablePocket(level, candidate)) {
|
if (Math.abs(candidate.getY() - firstPocket.getY()) < MIN_VERTICAL_SEPARATION
|
||||||
|
|| !isUsablePocket(level, candidate)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return spawnPair(level, random, firstPocket, candidate);
|
return spawnPair(level, random, firstPocket, candidate);
|
||||||
@@ -111,10 +123,16 @@ public class DimensionalTearMarkerBlockEntity extends BlockEntity {
|
|||||||
int distance = Mth.nextInt(random, MIN_LINK_RANGE, MAX_LINK_RANGE);
|
int distance = Mth.nextInt(random, MIN_LINK_RANGE, MAX_LINK_RANGE);
|
||||||
int dx = Mth.floor(Math.cos(angle) * distance);
|
int dx = Mth.floor(Math.cos(angle) * distance);
|
||||||
int dz = Mth.floor(Math.sin(angle) * distance);
|
int dz = Mth.floor(Math.sin(angle) * distance);
|
||||||
int dy = Mth.nextInt(random, -36, 36);
|
int verticalOffset = Mth.nextInt(random, MIN_PARTNER_VERTICAL_OFFSET, MAX_PARTNER_VERTICAL_OFFSET);
|
||||||
|
int dy = random.nextBoolean() ? verticalOffset : -verticalOffset;
|
||||||
return first.offset(dx, dy, dz);
|
return first.offset(dx, dy, dz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int countNearbyTears(ServerLevel level, BlockPos origin) {
|
||||||
|
AABB area = new AABB(origin).inflate(NATURAL_TEAR_LOCAL_RADIUS);
|
||||||
|
return level.getEntitiesOfClass(DimensionalTearEntity.class, area).size();
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isUsablePocket(ServerLevel level, BlockPos pos) {
|
private static boolean isUsablePocket(ServerLevel level, BlockPos pos) {
|
||||||
int minY = level.getMinBuildHeight() + 8;
|
int minY = level.getMinBuildHeight() + 8;
|
||||||
int maxY = level.getMaxBuildHeight() - 8;
|
int maxY = level.getMaxBuildHeight() - 8;
|
||||||
|
|||||||
+6
@@ -10,6 +10,7 @@ import net.minecraft.client.multiplayer.ClientLevel;
|
|||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.item.ItemEntity;
|
import net.minecraft.world.entity.item.ItemEntity;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
|
|
||||||
public final class ClientTimeDilationTicker {
|
public final class ClientTimeDilationTicker {
|
||||||
@@ -32,6 +33,11 @@ public final class ClientTimeDilationTicker {
|
|||||||
com.craisinlord.antarchy.content.time.TimeDilationApi.clearSyncedClientRates();
|
com.craisinlord.antarchy.content.time.TimeDilationApi.clearSyncedClientRates();
|
||||||
}
|
}
|
||||||
// Entity rates come from the server. Field snapshots are used only for local effects.
|
// Entity rates come from the server. Field snapshots are used only for local effects.
|
||||||
|
for (Player player : level.players()) {
|
||||||
|
if (player.isDeadOrDying() || rateAt(player.getX(), player.getY(), player.getZ()) >= TimeDilationMath.NORMAL_RATE) {
|
||||||
|
com.craisinlord.antarchy.content.time.TimeDilationApi.clearRate(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float dilateAnimationTime(Entity entity, float vanillaTime) {
|
public static float dilateAnimationTime(Entity entity, float vanillaTime) {
|
||||||
|
|||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client.model;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import software.bernie.geckolib.model.GeoModel;
|
||||||
|
|
||||||
|
public class RoyalBlackHoleModel extends GeoModel<RoyalBlackHoleEntity> {
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getModelResource(RoyalBlackHoleEntity animatable) {
|
||||||
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/black_hole.geo.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getTextureResource(RoyalBlackHoleEntity animatable) {
|
||||||
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/queen/black_hole.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getAnimationResource(RoyalBlackHoleEntity animatable) {
|
||||||
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/black_hole.animation.json");
|
||||||
|
}
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client.model;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.RoyalElementalProjectileEntity;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import software.bernie.geckolib.model.GeoModel;
|
||||||
|
|
||||||
|
public class RoyalElementalProjectileModel extends GeoModel<RoyalElementalProjectileEntity> {
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getModelResource(RoyalElementalProjectileEntity animatable) {
|
||||||
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID,
|
||||||
|
"geo/" + (animatable.isIceball() ? "ice_ball" : "fire_ball") + ".geo.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getTextureResource(RoyalElementalProjectileEntity animatable) {
|
||||||
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID,
|
||||||
|
"textures/entity/king/" + (animatable.isIceball() ? "ice_ball" : "fire_ball") + ".png");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getAnimationResource(RoyalElementalProjectileEntity animatable) {
|
||||||
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID,
|
||||||
|
"animations/" + (animatable.isIceball() ? "ice_ball" : "fire_ball") + ".animation.json");
|
||||||
|
}
|
||||||
|
}
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client.model;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.RoyalIceSpikeEntity;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import software.bernie.geckolib.model.GeoModel;
|
||||||
|
|
||||||
|
public class RoyalIceSpikeModel extends GeoModel<RoyalIceSpikeEntity> {
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getModelResource(RoyalIceSpikeEntity animatable) {
|
||||||
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/ice_spike.geo.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getTextureResource(RoyalIceSpikeEntity animatable) {
|
||||||
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/king/ice_spike.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getAnimationResource(RoyalIceSpikeEntity animatable) {
|
||||||
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/ice_spike.animation.json");
|
||||||
|
}
|
||||||
|
}
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client.renderer;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.client.model.RoyalBlackHoleModel;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.RoyalBlackHoleEntity;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
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 org.jetbrains.annotations.Nullable;
|
||||||
|
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
||||||
|
|
||||||
|
public class RoyalBlackHoleRenderer extends GeoEntityRenderer<RoyalBlackHoleEntity> {
|
||||||
|
public RoyalBlackHoleRenderer(EntityRendererProvider.Context context) {
|
||||||
|
super(context, new RoyalBlackHoleModel());
|
||||||
|
this.shadowRadius = 0.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(RoyalBlackHoleEntity entity, float entityYaw, float partialTick, PoseStack poseStack,
|
||||||
|
MultiBufferSource bufferSource, int packedLight) {
|
||||||
|
super.render(entity, entityYaw, partialTick, poseStack, bufferSource, 0xF000F0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable RenderType getRenderType(RoyalBlackHoleEntity animatable, ResourceLocation texture,
|
||||||
|
@Nullable MultiBufferSource bufferSource, float partialTick) {
|
||||||
|
return RenderType.entityTranslucent(this.getTextureLocation(animatable));
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -58,8 +58,8 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
|
|||||||
this.shadowRadius = 8.0F * RoyalBossEntity.MODEL_RENDER_SCALE;
|
this.shadowRadius = 8.0F * RoyalBossEntity.MODEL_RENDER_SCALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final float BEAM_OUTER_RADIUS = 0.55F;
|
private static final float BEAM_OUTER_RADIUS = 1.10F;
|
||||||
private static final float BEAM_INNER_RADIUS = 0.26F;
|
private static final float BEAM_INNER_RADIUS = 0.52F;
|
||||||
private static final float BEAM_TILE_BLOCKS = 3.0F;
|
private static final float BEAM_TILE_BLOCKS = 3.0F;
|
||||||
private static final float BEAM_SCROLL_SPEED = 0.32F;
|
private static final float BEAM_SCROLL_SPEED = 0.32F;
|
||||||
|
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client.renderer;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.client.model.RoyalElementalProjectileModel;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.RoyalElementalProjectileEntity;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
import com.mojang.math.Axis;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import software.bernie.geckolib.cache.object.BakedGeoModel;
|
||||||
|
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
||||||
|
|
||||||
|
public class RoyalElementalProjectileRenderer extends GeoEntityRenderer<RoyalElementalProjectileEntity> {
|
||||||
|
public RoyalElementalProjectileRenderer(EntityRendererProvider.Context context) {
|
||||||
|
super(context, new RoyalElementalProjectileModel());
|
||||||
|
this.shadowRadius = 0.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preRender(PoseStack poseStack, RoyalElementalProjectileEntity animatable, BakedGeoModel model,
|
||||||
|
MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender,
|
||||||
|
float partialTick, int packedLight, int packedOverlay, int colour) {
|
||||||
|
super.preRender(poseStack, animatable, model, bufferSource, buffer, isReRender, partialTick,
|
||||||
|
packedLight, packedOverlay, colour);
|
||||||
|
float scale = animatable.isIceball() ? 0.75F : 0.36F;
|
||||||
|
poseStack.scale(scale, scale, scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyRotations(RoyalElementalProjectileEntity entity, PoseStack poseStack, float ageInTicks,
|
||||||
|
float rotationYaw, float partialTick, float nativeScale) {
|
||||||
|
float yaw = Mth.rotLerp(partialTick, entity.yRotO, entity.getYRot());
|
||||||
|
float pitch = Mth.lerp(partialTick, entity.xRotO, entity.getXRot());
|
||||||
|
poseStack.mulPose(Axis.YP.rotationDegrees(180.0F - yaw));
|
||||||
|
poseStack.mulPose(Axis.XP.rotationDegrees(-pitch));
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client.renderer;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.client.model.RoyalIceSpikeModel;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.RoyalIceSpikeEntity;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||||
|
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
||||||
|
|
||||||
|
public class RoyalIceSpikeRenderer extends GeoEntityRenderer<RoyalIceSpikeEntity> {
|
||||||
|
public RoyalIceSpikeRenderer(EntityRendererProvider.Context context) {
|
||||||
|
super(context, new RoyalIceSpikeModel());
|
||||||
|
this.shadowRadius = 0.0F;
|
||||||
|
}
|
||||||
|
}
|
||||||
+62
-40
@@ -12,9 +12,8 @@ import net.minecraft.util.Mth;
|
|||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
|
|
||||||
public class WindVortexRenderer extends EntityRenderer<WindVortexEntity> {
|
public class WindVortexRenderer extends EntityRenderer<WindVortexEntity> {
|
||||||
private static final int RINGS = 10;
|
private static final int RINGS = 11;
|
||||||
private static final int SEGMENTS_PER_RING = 12;
|
private static final int SQUARES_PER_SIDE = 3;
|
||||||
private static final int ARC_STEPS = 6;
|
|
||||||
private static final float BASE_RADIUS = 0.35F;
|
private static final float BASE_RADIUS = 0.35F;
|
||||||
|
|
||||||
public WindVortexRenderer(EntityRendererProvider.Context context) {
|
public WindVortexRenderer(EntityRendererProvider.Context context) {
|
||||||
@@ -44,48 +43,72 @@ public class WindVortexRenderer extends EntityRenderer<WindVortexEntity> {
|
|||||||
float radius = Mth.lerp(shapeProgress, BASE_RADIUS, topRadius);
|
float radius = Mth.lerp(shapeProgress, BASE_RADIUS, topRadius);
|
||||||
float ringSpin = spinDirection * age * (0.13F + progress * 0.045F) + ring * 0.47F;
|
float ringSpin = spinDirection * age * (0.13F + progress * 0.045F) + ring * 0.47F;
|
||||||
float alpha = alphaMultiplier;
|
float alpha = alphaMultiplier;
|
||||||
float thickness = 0.025F + radius * 0.012F;
|
float halfSide = radius * 0.92F;
|
||||||
float arcLength = 0.34F + progress * 0.08F;
|
float tileSize = Math.max(0.035F, radius * 0.12F);
|
||||||
int red = push ? 70 : 64;
|
int red = push ? 70 : 64;
|
||||||
int green = push ? 220 : 255;
|
int green = push ? 220 : 255;
|
||||||
int blue = push ? 255 : 56;
|
int blue = push ? 255 : 56;
|
||||||
|
drawSquareRing(consumer, pose, basis, halfSide, axisDistance, tileSize, ringSpin,
|
||||||
for (int segment = 0; segment < SEGMENTS_PER_RING; segment++) {
|
alpha, red, green, blue);
|
||||||
float baseAngle = ringSpin + segment * Mth.TWO_PI / SEGMENTS_PER_RING;
|
|
||||||
float start = baseAngle - arcLength * 0.5F;
|
|
||||||
float end = baseAngle + arcLength * 0.5F;
|
|
||||||
drawArc(consumer, pose, basis, radius, axisDistance, thickness, start, end, alpha, red, green, blue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
super.render(entity, entityYaw, partialTick, poseStack, bufferSource, packedLight);
|
super.render(entity, entityYaw, partialTick, poseStack, bufferSource, packedLight);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void drawArc(VertexConsumer consumer, Matrix4f pose, WindVortexEntity.Basis basis, float radius,
|
private static void drawSquareRing(VertexConsumer consumer, Matrix4f pose, WindVortexEntity.Basis basis,
|
||||||
float axisDistance, float thickness, float start, float end, float alpha, int red, int green, int blue) {
|
float halfSide, float axisDistance, float tileSize, float rotation, float alpha,
|
||||||
float previousAngle = start;
|
int red, int green, int blue) {
|
||||||
for (int step = 1; step <= ARC_STEPS; step++) {
|
for (int side = 0; side < 4; side++) {
|
||||||
float angle = Mth.lerp(step / (float) ARC_STEPS, start, end);
|
for (int tile = 0; tile < SQUARES_PER_SIDE; tile++) {
|
||||||
addLineQuad(consumer, pose, basis, radius, axisDistance, thickness, previousAngle, angle, alpha, red, green, blue);
|
float start = -halfSide + (tile + 0.18F) * (2.0F * halfSide / SQUARES_PER_SIDE);
|
||||||
previousAngle = angle;
|
float end = -halfSide + (tile + 0.82F) * (2.0F * halfSide / SQUARES_PER_SIDE);
|
||||||
|
float sideAngle = rotation + side * (Mth.TWO_PI / 4.0F);
|
||||||
|
addSquareTile(consumer, pose, basis, halfSide, axisDistance, tileSize,
|
||||||
|
sideAngle, start, end, alpha, red, green, blue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addLineQuad(VertexConsumer consumer, Matrix4f pose, WindVortexEntity.Basis basis, float radius,
|
private static void addSquareTile(VertexConsumer consumer, Matrix4f pose, WindVortexEntity.Basis basis,
|
||||||
float axisDistance, float thickness, float startAngle, float endAngle, float alpha, int red, int green, int blue) {
|
float halfSide, float axisDistance, float tileSize, float sideAngle, float start, float end,
|
||||||
org.joml.Vector3f start = point(basis, radius, axisDistance, startAngle);
|
float alpha, int red, int green, int blue) {
|
||||||
org.joml.Vector3f end = point(basis, radius, axisDistance, endAngle);
|
org.joml.Vector3f center = squarePoint(basis, halfSide, axisDistance, sideAngle, (start + end) * 0.5F);
|
||||||
org.joml.Vector3f axisOffset = new org.joml.Vector3f((float) basis.axis.x, (float) basis.axis.y, (float) basis.axis.z).mul(thickness);
|
org.joml.Vector3f tangent = new org.joml.Vector3f(
|
||||||
float middleAngle = (startAngle + endAngle) * 0.5F;
|
(float) (-basis.sideA.x * Mth.sin(sideAngle) + basis.sideB.x * Mth.cos(sideAngle)),
|
||||||
org.joml.Vector3f radialOffset = new org.joml.Vector3f(
|
(float) (-basis.sideA.y * Mth.sin(sideAngle) + basis.sideB.y * Mth.cos(sideAngle)),
|
||||||
(float) (basis.sideA.x * Mth.cos(middleAngle) + basis.sideB.x * Mth.sin(middleAngle)),
|
(float) (-basis.sideA.z * Mth.sin(sideAngle) + basis.sideB.z * Mth.cos(sideAngle)));
|
||||||
(float) (basis.sideA.y * Mth.cos(middleAngle) + basis.sideB.y * Mth.sin(middleAngle)),
|
org.joml.Vector3f axisOffset = new org.joml.Vector3f(
|
||||||
(float) (basis.sideA.z * Mth.cos(middleAngle) + basis.sideB.z * Mth.sin(middleAngle))
|
(float) basis.axis.x, (float) basis.axis.y, (float) basis.axis.z).mul(tileSize * 0.5F);
|
||||||
).mul(thickness);
|
tangent.mul(tileSize * 0.5F);
|
||||||
int a = Mth.clamp((int) (alpha * 255.0F), 0, 255);
|
int a = Mth.clamp((int) (alpha * 255.0F), 0, 255);
|
||||||
|
addVertex(consumer, pose, center.x - tangent.x - axisOffset.x, center.y - tangent.y - axisOffset.y,
|
||||||
|
center.z - tangent.z - axisOffset.z, red, green, blue, a);
|
||||||
|
addVertex(consumer, pose, center.x + tangent.x - axisOffset.x, center.y + tangent.y - axisOffset.y,
|
||||||
|
center.z + tangent.z - axisOffset.z, red, green, blue, a);
|
||||||
|
addVertex(consumer, pose, center.x + tangent.x + axisOffset.x, center.y + tangent.y + axisOffset.y,
|
||||||
|
center.z + tangent.z + axisOffset.z, red, green, blue, a);
|
||||||
|
addVertex(consumer, pose, center.x - tangent.x + axisOffset.x, center.y - tangent.y + axisOffset.y,
|
||||||
|
center.z - tangent.z + axisOffset.z, red, green, blue, a);
|
||||||
|
addVertex(consumer, pose, center.x - tangent.x + axisOffset.x, center.y - tangent.y + axisOffset.y,
|
||||||
|
center.z - tangent.z + axisOffset.z, red, green, blue, a);
|
||||||
|
addVertex(consumer, pose, center.x + tangent.x + axisOffset.x, center.y + tangent.y + axisOffset.y,
|
||||||
|
center.z + tangent.z + axisOffset.z, red, green, blue, a);
|
||||||
|
addVertex(consumer, pose, center.x + tangent.x - axisOffset.x, center.y + tangent.y - axisOffset.y,
|
||||||
|
center.z + tangent.z - axisOffset.z, red, green, blue, a);
|
||||||
|
addVertex(consumer, pose, center.x - tangent.x - axisOffset.x, center.y - tangent.y - axisOffset.y,
|
||||||
|
center.z - tangent.z - axisOffset.z, red, green, blue, a);
|
||||||
|
}
|
||||||
|
|
||||||
addQuad(consumer, pose, start, end, axisOffset, red, green, blue, a);
|
private static org.joml.Vector3f squarePoint(WindVortexEntity.Basis basis, float halfSide,
|
||||||
addQuad(consumer, pose, start, end, radialOffset, red, green, blue, a);
|
float axisDistance, float sideAngle, float along) {
|
||||||
|
float x = Mth.cos(sideAngle) * halfSide;
|
||||||
|
float z = Mth.sin(sideAngle) * halfSide;
|
||||||
|
float tangentX = -Mth.sin(sideAngle) * along;
|
||||||
|
float tangentZ = Mth.cos(sideAngle) * along;
|
||||||
|
return new org.joml.Vector3f(
|
||||||
|
(float) (basis.axis.x * axisDistance + basis.sideA.x * (x + tangentX) + basis.sideB.x * (z + tangentZ)),
|
||||||
|
(float) (basis.axis.y * axisDistance + basis.sideA.y * (x + tangentX) + basis.sideB.y * (z + tangentZ)),
|
||||||
|
(float) (basis.axis.z * axisDistance + basis.sideA.z * (x + tangentX) + basis.sideB.z * (z + tangentZ)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addQuad(VertexConsumer consumer, Matrix4f pose, org.joml.Vector3f start,
|
private static void addQuad(VertexConsumer consumer, Matrix4f pose, org.joml.Vector3f start,
|
||||||
@@ -94,15 +117,14 @@ public class WindVortexRenderer extends EntityRenderer<WindVortexEntity> {
|
|||||||
addVertex(consumer, pose, end.x - offset.x, end.y - offset.y, end.z - offset.z, red, green, blue, alpha);
|
addVertex(consumer, pose, end.x - offset.x, end.y - offset.y, end.z - offset.z, red, green, blue, alpha);
|
||||||
addVertex(consumer, pose, end.x + offset.x, end.y + offset.y, end.z + offset.z, red, green, blue, alpha);
|
addVertex(consumer, pose, end.x + offset.x, end.y + offset.y, end.z + offset.z, red, green, blue, alpha);
|
||||||
addVertex(consumer, pose, start.x + offset.x, start.y + offset.y, start.z + offset.z, red, green, blue, alpha);
|
addVertex(consumer, pose, start.x + offset.x, start.y + offset.y, start.z + offset.z, red, green, blue, alpha);
|
||||||
}
|
|
||||||
|
|
||||||
private static org.joml.Vector3f point(WindVortexEntity.Basis basis, float radius, float axisDistance, float angle) {
|
// The lightning render type can cull one winding from some camera
|
||||||
double radialA = Mth.cos(angle) * radius;
|
// angles. Emit the opposite winding as well so every ribbon is
|
||||||
double radialB = Mth.sin(angle) * radius;
|
// visible from both sides.
|
||||||
double x = basis.axis.x * axisDistance + basis.sideA.x * radialA + basis.sideB.x * radialB;
|
addVertex(consumer, pose, start.x + offset.x, start.y + offset.y, start.z + offset.z, red, green, blue, alpha);
|
||||||
double y = basis.axis.y * axisDistance + basis.sideA.y * radialA + basis.sideB.y * radialB;
|
addVertex(consumer, pose, end.x + offset.x, end.y + offset.y, end.z + offset.z, red, green, blue, alpha);
|
||||||
double z = basis.axis.z * axisDistance + basis.sideA.z * radialA + basis.sideB.z * radialB;
|
addVertex(consumer, pose, end.x - offset.x, end.y - offset.y, end.z - offset.z, red, green, blue, alpha);
|
||||||
return new org.joml.Vector3f((float) x, (float) y, (float) z);
|
addVertex(consumer, pose, start.x - offset.x, start.y - offset.y, start.z - offset.z, red, green, blue, alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addVertex(VertexConsumer consumer, Matrix4f pose, float x, float y, float z,
|
private static void addVertex(VertexConsumer consumer, Matrix4f pose, float x, float y, float z,
|
||||||
|
|||||||
+2
-1
@@ -594,7 +594,8 @@ public final class CreativeTabContents {
|
|||||||
private static final List<String> ANTARCHY_POTION_FAMILIES = List.of(
|
private static final List<String> ANTARCHY_POTION_FAMILIES = List.of(
|
||||||
"dread", "long_dread", "inversion", "long_inversion", "stinky", "long_stinky",
|
"dread", "long_dread", "inversion", "long_inversion", "stinky", "long_stinky",
|
||||||
"paralysis", "long_paralysis", "haste", "strong_haste", "shrinking",
|
"paralysis", "long_paralysis", "haste", "strong_haste", "shrinking",
|
||||||
"strong_shrinking", "extreme_shrinking", "growing", "strong_growing", "extreme_growing"
|
"strong_shrinking", "extreme_shrinking", "growing", "strong_growing", "extreme_growing",
|
||||||
|
"command", "long_command", "time_dilation", "long_time_dilation"
|
||||||
);
|
);
|
||||||
|
|
||||||
private static final Map<String, Integer> ORDER_INDEX = createOrderIndex();
|
private static final Map<String, Integer> ORDER_INDEX = createOrderIndex();
|
||||||
|
|||||||
+99
@@ -0,0 +1,99 @@
|
|||||||
|
package com.craisinlord.antarchy.content.effect;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
|
||||||
|
public final class CommandedBehavior {
|
||||||
|
private CommandedBehavior() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void tick(Mob mob) {
|
||||||
|
if (!(mob instanceof CommandedEntityAccess access)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
UUID commanderUuid = access.antarchy$getCommanderUuid();
|
||||||
|
if (commanderUuid == null || mob.level().getServer() == null) {
|
||||||
|
clear(mob);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ServerPlayer commander = mob.level().getServer().getPlayerList().getPlayer(commanderUuid);
|
||||||
|
if (commander == null || commander.level() != mob.level() || !RoyalEffectEligibility.canApplyCommanded(mob)) {
|
||||||
|
mob.removeEffect(RoyalEffectHooks.commandedHolder());
|
||||||
|
clear(mob);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LivingEntity target = mob.getTarget();
|
||||||
|
if (target != null && isProtectedAlly(mob, target)) {
|
||||||
|
mob.setTarget(null);
|
||||||
|
target = null;
|
||||||
|
}
|
||||||
|
if (mob.tickCount % 10 != 0 || target != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LivingEntity candidate = commander.getLastHurtByMob();
|
||||||
|
if (!isValidTarget(mob, commander, candidate)) {
|
||||||
|
candidate = commander.getLastHurtMob();
|
||||||
|
}
|
||||||
|
if (!isValidTarget(mob, commander, candidate)) {
|
||||||
|
candidate = mob.getLastHurtByMob();
|
||||||
|
}
|
||||||
|
if (!isValidTarget(mob, commander, candidate)) {
|
||||||
|
candidate = mob.level().getEntitiesOfClass(LivingEntity.class, mob.getBoundingBox().inflate(16.0D),
|
||||||
|
entity -> isValidTarget(mob, commander, entity)).stream()
|
||||||
|
.min((a, b) -> {
|
||||||
|
int distance = Double.compare(mob.distanceToSqr(a), mob.distanceToSqr(b));
|
||||||
|
return distance != 0 ? distance : Integer.compare(a.getId(), b.getId());
|
||||||
|
}).orElse(null);
|
||||||
|
}
|
||||||
|
if (candidate != null) {
|
||||||
|
mob.setTarget(candidate);
|
||||||
|
access.antarchy$setCommandedTargetOwned(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isProtectedAlly(Mob mob, Entity entity) {
|
||||||
|
if (!(mob instanceof CommandedEntityAccess access) || entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
UUID commanderUuid = access.antarchy$getCommanderUuid();
|
||||||
|
if (commanderUuid == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (entity.getUUID().equals(commanderUuid)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (entity instanceof Mob other && other instanceof CommandedEntityAccess otherAccess) {
|
||||||
|
return commanderUuid.equals(otherAccess.antarchy$getCommanderUuid());
|
||||||
|
}
|
||||||
|
if (entity instanceof LivingEntity living && living.isAlliedTo(mob)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (mob.level().getServer() != null
|
||||||
|
&& mob.level().getServer().getPlayerList().getPlayer(commanderUuid) instanceof Player commander
|
||||||
|
&& entity instanceof LivingEntity living) {
|
||||||
|
return living.isAlliedTo(commander);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isValidTarget(Mob mob, ServerPlayer commander, LivingEntity target) {
|
||||||
|
return target != null && target.isAlive() && target != mob && target != commander
|
||||||
|
&& !isProtectedAlly(mob, target) && !target.isAlliedTo(commander)
|
||||||
|
&& mob.canAttack(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clear(Mob mob) {
|
||||||
|
if (!(mob instanceof CommandedEntityAccess access)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (access.antarchy$isCommandedTargetOwned()) {
|
||||||
|
mob.setTarget(null);
|
||||||
|
}
|
||||||
|
access.antarchy$setCommandedTargetOwned(false);
|
||||||
|
access.antarchy$setCommanderUuid(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package com.craisinlord.antarchy.content.effect;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public interface CommandedEntityAccess {
|
||||||
|
UUID antarchy$getCommanderUuid();
|
||||||
|
void antarchy$setCommanderUuid(UUID uuid);
|
||||||
|
boolean antarchy$isCommandedTargetOwned();
|
||||||
|
void antarchy$setCommandedTargetOwned(boolean owned);
|
||||||
|
}
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
package com.craisinlord.antarchy.content.effect;
|
||||||
|
|
||||||
|
import net.minecraft.world.effect.MobEffect;
|
||||||
|
import net.minecraft.world.effect.MobEffectCategory;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
|
||||||
|
public final class CommandedMobEffect extends MobEffect {
|
||||||
|
public CommandedMobEffect() {
|
||||||
|
super(MobEffectCategory.HARMFUL, 0xD4AF37);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applyEffectTick(LivingEntity entity, int amplifier) {
|
||||||
|
if (!entity.level().isClientSide() && entity instanceof Mob mob) {
|
||||||
|
CommandedBehavior.tick(mob);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldApplyEffectTickThisTick(int duration, int amplifier) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
package com.craisinlord.antarchy.content.effect;
|
||||||
|
|
||||||
|
import net.minecraft.world.effect.MobEffect;
|
||||||
|
import net.minecraft.world.effect.MobEffectCategory;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
|
||||||
|
public final class DilatedMobEffect extends MobEffect {
|
||||||
|
public static final double RATE = 0.35D;
|
||||||
|
|
||||||
|
public DilatedMobEffect() {
|
||||||
|
super(MobEffectCategory.HARMFUL, 0x6C4AB6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applyEffectTick(LivingEntity entity, int amplifier) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldApplyEffectTickThisTick(int duration, int amplifier) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
@@ -1,11 +1,14 @@
|
|||||||
package com.craisinlord.antarchy.content.effect;
|
package com.craisinlord.antarchy.content.effect;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityTransition;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityTransition;
|
||||||
|
import net.minecraft.world.effect.MobEffectInstance;
|
||||||
import net.minecraft.world.effect.MobEffect;
|
import net.minecraft.world.effect.MobEffect;
|
||||||
import net.minecraft.world.effect.MobEffectCategory;
|
import net.minecraft.world.effect.MobEffectCategory;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
|
||||||
public final class InvertedMobEffect extends MobEffect {
|
public final class InvertedMobEffect extends MobEffect {
|
||||||
private static final AntarchyGravityTransition EFFECT_TRANSITION = new AntarchyGravityTransition(12);
|
private static final AntarchyGravityTransition EFFECT_TRANSITION = new AntarchyGravityTransition(12);
|
||||||
@@ -19,6 +22,19 @@ public final class InvertedMobEffect extends MobEffect {
|
|||||||
public boolean applyEffectTick(LivingEntity entity, int amplifier) {
|
public boolean applyEffectTick(LivingEntity entity, int amplifier) {
|
||||||
if (!entity.level().isClientSide()) {
|
if (!entity.level().isClientSide()) {
|
||||||
if (AntarchyGravityApi.getGravityDirection(entity) != AntarchyGravityDirection.UP || !AntarchyGravityApi.isGravityForced(entity)) {
|
if (AntarchyGravityApi.getGravityDirection(entity) != AntarchyGravityDirection.UP || !AntarchyGravityApi.isGravityForced(entity)) {
|
||||||
|
MobEffectInstance effect = entity.getEffect(com.craisinlord.antarchy.content.AntarchyObjects.INVERTED_EFFECT.get());
|
||||||
|
if (entity instanceof Player || com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager.isThoraxis(entity.level())) {
|
||||||
|
Antarchy.LOGGER.info(
|
||||||
|
"[antarchy-gravity] applying inverted gravity from effect targetType={} uuid={} pos=({}, {}, {}) dim={} duration={} ambient={} visible={} forcedBefore={} gameTime={}",
|
||||||
|
entity.getType(), entity.getUUID(), entity.getX(), entity.getY(), entity.getZ(),
|
||||||
|
entity.level().dimension().location(),
|
||||||
|
effect != null ? effect.getDuration() : -1,
|
||||||
|
effect != null && effect.isAmbient(),
|
||||||
|
effect != null && effect.isVisible(),
|
||||||
|
AntarchyGravityApi.isGravityForced(entity),
|
||||||
|
entity.level().getGameTime()
|
||||||
|
);
|
||||||
|
}
|
||||||
AntarchyGravityApi.setForcedGravityDirection(entity, AntarchyGravityDirection.UP, EFFECT_TRANSITION);
|
AntarchyGravityApi.setForcedGravityDirection(entity, AntarchyGravityDirection.UP, EFFECT_TRANSITION);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+57
@@ -0,0 +1,57 @@
|
|||||||
|
package com.craisinlord.antarchy.content.effect;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.AntarchyTags;
|
||||||
|
import com.craisinlord.antarchy.content.item.RoyalAssailantArmorItem;
|
||||||
|
import com.craisinlord.antarchy.content.item.RoyalGuardianArmorItem;
|
||||||
|
import net.minecraft.world.effect.MobEffectInstance;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
|
||||||
|
public final class RoyalEffectEligibility {
|
||||||
|
private RoyalEffectEligibility() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isCommanded(MobEffectInstance instance) {
|
||||||
|
return RoyalEffectHooks.commandedHolder() != null && instance.is(RoyalEffectHooks.commandedHolder());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isDilated(MobEffectInstance instance) {
|
||||||
|
return RoyalEffectHooks.dilatedHolder() != null && instance.is(RoyalEffectHooks.dilatedHolder());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean canApplyCommanded(LivingEntity entity) {
|
||||||
|
return entity instanceof Mob mob
|
||||||
|
&& !(entity instanceof Player)
|
||||||
|
&& !entity.getType().is(AntarchyTags.Entities.COMMANDED_BLACKLIST)
|
||||||
|
&& !(mob.isNoAi())
|
||||||
|
&& !(entity.getItemBySlot(net.minecraft.world.entity.EquipmentSlot.HEAD).getItem() instanceof RoyalGuardianArmorItem)
|
||||||
|
&& !(entity.getItemBySlot(net.minecraft.world.entity.EquipmentSlot.CHEST).getItem() instanceof RoyalGuardianArmorItem)
|
||||||
|
&& !(entity.getItemBySlot(net.minecraft.world.entity.EquipmentSlot.LEGS).getItem() instanceof RoyalGuardianArmorItem)
|
||||||
|
&& !(entity.getItemBySlot(net.minecraft.world.entity.EquipmentSlot.FEET).getItem() instanceof RoyalGuardianArmorItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean canApplyDilated(LivingEntity entity) {
|
||||||
|
return !entity.getType().is(AntarchyTags.Entities.DILATED_BLACKLIST)
|
||||||
|
&& !entity.getType().is(AntarchyTags.Entities.TIME_DILATION_IMMUNE)
|
||||||
|
&& !(entity.getItemBySlot(net.minecraft.world.entity.EquipmentSlot.HEAD).getItem() instanceof RoyalAssailantArmorItem)
|
||||||
|
&& !(entity.getItemBySlot(net.minecraft.world.entity.EquipmentSlot.CHEST).getItem() instanceof RoyalAssailantArmorItem)
|
||||||
|
&& !(entity.getItemBySlot(net.minecraft.world.entity.EquipmentSlot.LEGS).getItem() instanceof RoyalAssailantArmorItem)
|
||||||
|
&& !(entity.getItemBySlot(net.minecraft.world.entity.EquipmentSlot.FEET).getItem() instanceof RoyalAssailantArmorItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean canApply(LivingEntity entity, MobEffectInstance instance) {
|
||||||
|
if (isCommanded(instance)) {
|
||||||
|
return canApplyCommanded(entity);
|
||||||
|
}
|
||||||
|
if (isDilated(instance)) {
|
||||||
|
return canApplyDilated(entity);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean canUseCommandSource(Entity source) {
|
||||||
|
return source instanceof Player;
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
package com.craisinlord.antarchy.content.effect;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import net.minecraft.core.Holder;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.effect.MobEffect;
|
||||||
|
|
||||||
|
public final class RoyalEffectHooks {
|
||||||
|
private static final ResourceKey<MobEffect> COMMANDED_KEY = ResourceKey.create(Registries.MOB_EFFECT,
|
||||||
|
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "commanded"));
|
||||||
|
private static final ResourceKey<MobEffect> DILATED_KEY = ResourceKey.create(Registries.MOB_EFFECT,
|
||||||
|
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "dilated"));
|
||||||
|
|
||||||
|
private RoyalEffectHooks() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Holder<MobEffect> commandedHolder() {
|
||||||
|
return BuiltInRegistries.MOB_EFFECT.getHolder(COMMANDED_KEY).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Holder<MobEffect> dilatedHolder() {
|
||||||
|
return BuiltInRegistries.MOB_EFFECT.getHolder(DILATED_KEY).orElse(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
+34
-3
@@ -98,6 +98,8 @@ public class BedBugEntity extends Animal implements GeoEntity {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private ItemEntity cachedRottenFlesh;
|
private ItemEntity cachedRottenFlesh;
|
||||||
private int nextFoodSearchTick;
|
private int nextFoodSearchTick;
|
||||||
|
private int ignoredRottenFleshId = -1;
|
||||||
|
private int ignoredRottenFleshUntilTick;
|
||||||
private int guardNestCooldown;
|
private int guardNestCooldown;
|
||||||
|
|
||||||
public BedBugEntity(EntityType<? extends BedBugEntity> entityType, Level level) {
|
public BedBugEntity(EntityType<? extends BedBugEntity> entityType, Level level) {
|
||||||
@@ -450,6 +452,24 @@ public class BedBugEntity extends Animal implements GeoEntity {
|
|||||||
this.nextFoodSearchTick = 0;
|
this.nextFoodSearchTick = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void temporarilyIgnoreRottenFlesh(ItemEntity itemEntity) {
|
||||||
|
this.ignoredRottenFleshId = itemEntity.getId();
|
||||||
|
this.ignoredRottenFleshUntilTick = this.tickCount + 100;
|
||||||
|
this.invalidateFoodCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTemporarilyIgnoredFood(ItemEntity itemEntity) {
|
||||||
|
if (itemEntity.getId() != this.ignoredRottenFleshId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.tickCount >= this.ignoredRottenFleshUntilTick) {
|
||||||
|
this.ignoredRottenFleshId = -1;
|
||||||
|
this.ignoredRottenFleshUntilTick = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private ItemEntity findNearestRottenFlesh() {
|
private ItemEntity findNearestRottenFlesh() {
|
||||||
return this.level().getEntitiesOfClass(
|
return this.level().getEntitiesOfClass(
|
||||||
@@ -457,7 +477,8 @@ public class BedBugEntity extends Animal implements GeoEntity {
|
|||||||
this.getBoundingBox().inflate(FOOD_SEARCH_RADIUS, 2.0D, FOOD_SEARCH_RADIUS),
|
this.getBoundingBox().inflate(FOOD_SEARCH_RADIUS, 2.0D, FOOD_SEARCH_RADIUS),
|
||||||
itemEntity -> itemEntity.isAlive()
|
itemEntity -> itemEntity.isAlive()
|
||||||
&& !itemEntity.getItem().isEmpty()
|
&& !itemEntity.getItem().isEmpty()
|
||||||
&& itemEntity.getItem().is(Items.ROTTEN_FLESH))
|
&& itemEntity.getItem().is(Items.ROTTEN_FLESH)
|
||||||
|
&& !this.isTemporarilyIgnoredFood(itemEntity))
|
||||||
.stream()
|
.stream()
|
||||||
.min(Comparator.comparingDouble(this::distanceToSqr))
|
.min(Comparator.comparingDouble(this::distanceToSqr))
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
@@ -581,6 +602,7 @@ public class BedBugEntity extends Animal implements GeoEntity {
|
|||||||
private ItemEntity targetFood;
|
private ItemEntity targetFood;
|
||||||
private double lastDistanceSqr;
|
private double lastDistanceSqr;
|
||||||
private int stuckTicks;
|
private int stuckTicks;
|
||||||
|
private int pathRefreshCooldown;
|
||||||
|
|
||||||
private SeekRottenFleshGoal() {
|
private SeekRottenFleshGoal() {
|
||||||
this.setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK));
|
this.setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK));
|
||||||
@@ -614,6 +636,7 @@ public class BedBugEntity extends Animal implements GeoEntity {
|
|||||||
BedBugEntity.this.setTarget(null);
|
BedBugEntity.this.setTarget(null);
|
||||||
this.lastDistanceSqr = Double.MAX_VALUE;
|
this.lastDistanceSqr = Double.MAX_VALUE;
|
||||||
this.stuckTicks = 0;
|
this.stuckTicks = 0;
|
||||||
|
this.pathRefreshCooldown = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -622,6 +645,7 @@ public class BedBugEntity extends Animal implements GeoEntity {
|
|||||||
this.targetFood = null;
|
this.targetFood = null;
|
||||||
this.lastDistanceSqr = Double.MAX_VALUE;
|
this.lastDistanceSqr = Double.MAX_VALUE;
|
||||||
this.stuckTicks = 0;
|
this.stuckTicks = 0;
|
||||||
|
this.pathRefreshCooldown = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -631,7 +655,14 @@ public class BedBugEntity extends Animal implements GeoEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BedBugEntity.this.getLookControl().setLookAt(this.targetFood, 30.0F, 30.0F);
|
BedBugEntity.this.getLookControl().setLookAt(this.targetFood, 30.0F, 30.0F);
|
||||||
BedBugEntity.this.getNavigation().moveTo(this.targetFood, 1.0D);
|
if (this.pathRefreshCooldown-- <= 0) {
|
||||||
|
if (!BedBugEntity.this.getNavigation().moveTo(this.targetFood, 1.0D)) {
|
||||||
|
BedBugEntity.this.temporarilyIgnoreRottenFlesh(this.targetFood);
|
||||||
|
this.targetFood = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.pathRefreshCooldown = 10;
|
||||||
|
}
|
||||||
double distanceSqr = BedBugEntity.this.distanceToSqr(this.targetFood);
|
double distanceSqr = BedBugEntity.this.distanceToSqr(this.targetFood);
|
||||||
|
|
||||||
if (distanceSqr < this.lastDistanceSqr - 0.2D) {
|
if (distanceSqr < this.lastDistanceSqr - 0.2D) {
|
||||||
@@ -639,7 +670,7 @@ public class BedBugEntity extends Animal implements GeoEntity {
|
|||||||
this.stuckTicks = 0;
|
this.stuckTicks = 0;
|
||||||
} else if (BedBugEntity.this.getNavigation().isDone() && distanceSqr > 4.0D) {
|
} else if (BedBugEntity.this.getNavigation().isDone() && distanceSqr > 4.0D) {
|
||||||
if (++this.stuckTicks >= 20) {
|
if (++this.stuckTicks >= 20) {
|
||||||
BedBugEntity.this.invalidateFoodCache();
|
BedBugEntity.this.temporarilyIgnoreRottenFlesh(this.targetFood);
|
||||||
this.targetFood = null;
|
this.targetFood = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-1
@@ -29,12 +29,14 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class DiamondMinecartEntity extends Minecart {
|
public class DiamondMinecartEntity extends Minecart {
|
||||||
|
private static final long INPUT_TIMEOUT_TICKS = 5L;
|
||||||
private static final EntityDataAccessor<Float> SYNCED_SPEED =
|
private static final EntityDataAccessor<Float> SYNCED_SPEED =
|
||||||
SynchedEntityData.defineId(DiamondMinecartEntity.class, EntityDataSerializers.FLOAT);
|
SynchedEntityData.defineId(DiamondMinecartEntity.class, EntityDataSerializers.FLOAT);
|
||||||
private static final EntityDataAccessor<Integer> SYNCED_FACING =
|
private static final EntityDataAccessor<Integer> SYNCED_FACING =
|
||||||
SynchedEntityData.defineId(DiamondMinecartEntity.class, EntityDataSerializers.INT);
|
SynchedEntityData.defineId(DiamondMinecartEntity.class, EntityDataSerializers.INT);
|
||||||
|
|
||||||
private byte inputFlags = 0;
|
private byte inputFlags = 0;
|
||||||
|
private long lastInputGameTime = Long.MIN_VALUE;
|
||||||
private float currentSpeed = 0.0F;
|
private float currentSpeed = 0.0F;
|
||||||
private Direction facingDir = Direction.SOUTH;
|
private Direction facingDir = Direction.SOUTH;
|
||||||
private BlockPos lastBlockPos = null;
|
private BlockPos lastBlockPos = null;
|
||||||
@@ -109,19 +111,38 @@ public class DiamondMinecartEntity extends Minecart {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected double getMaxSpeed() {
|
protected double getMaxSpeed() {
|
||||||
return 0.4D;
|
return AntarchySettings.diamondMinecartEnabled()
|
||||||
|
? AntarchySettings.diamondMinecartMaxSpeed()
|
||||||
|
: 0.4D;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onInputReceived(byte flags) {
|
public void onInputReceived(byte flags) {
|
||||||
this.inputFlags = flags;
|
this.inputFlags = flags;
|
||||||
|
this.lastInputGameTime = this.level().getGameTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
super.tick();
|
super.tick();
|
||||||
|
if (!this.level().isClientSide) {
|
||||||
|
this.serverTick();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void serverTick() {
|
private void serverTick() {
|
||||||
|
if (!AntarchySettings.diamondMinecartEnabled()) {
|
||||||
|
this.inputFlags = 0;
|
||||||
|
this.lastInputGameTime = Long.MIN_VALUE;
|
||||||
|
this.currentSpeed = 0.0F;
|
||||||
|
this.entityData.set(SYNCED_SPEED, 0.0F);
|
||||||
|
this.setDeltaMovement(0.0D, this.getDeltaMovement().y, 0.0D);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.level().getGameTime() - this.lastInputGameTime > INPUT_TIMEOUT_TICKS) {
|
||||||
|
this.inputFlags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
Player rider = this.getRidingPlayer();
|
Player rider = this.getRidingPlayer();
|
||||||
boolean hasRider = rider != null;
|
boolean hasRider = rider != null;
|
||||||
|
|
||||||
@@ -176,6 +197,17 @@ public class DiamondMinecartEntity extends Minecart {
|
|||||||
if (AntarchySettings.diamondMinecartMobDamageEnabled() && this.currentSpeed > 0.15F && hasRider) {
|
if (AntarchySettings.diamondMinecartMobDamageEnabled() && this.currentSpeed > 0.15F && hasRider) {
|
||||||
this.applyMobCollisionDamage();
|
this.applyMobCollisionDamage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.applyControlledVelocity();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyControlledVelocity() {
|
||||||
|
double speed = this.currentSpeed;
|
||||||
|
this.setDeltaMovement(
|
||||||
|
this.facingDir.getStepX() * speed,
|
||||||
|
this.getDeltaMovement().y,
|
||||||
|
this.facingDir.getStepZ() * speed
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onEnteredNewBlock(BlockPos currentPos, @Nullable Player rider) {
|
private void onEnteredNewBlock(BlockPos currentPos, @Nullable Player rider) {
|
||||||
|
|||||||
+36
@@ -1,8 +1,11 @@
|
|||||||
package com.craisinlord.antarchy.content.entity;
|
package com.craisinlord.antarchy.content.entity;
|
||||||
|
|
||||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
|
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||||
import com.craisinlord.antarchy.content.entity.royal.QueenEntity;
|
import com.craisinlord.antarchy.content.entity.royal.QueenEntity;
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||||
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
||||||
|
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
@@ -89,6 +92,11 @@ public class ManticoreEntity extends Monster implements GeoEntity {
|
|||||||
this.xpReward = 12;
|
this.xpReward = 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean fireImmune() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static AttributeSupplier.Builder createAttributes() {
|
public static AttributeSupplier.Builder createAttributes() {
|
||||||
return Mob.createMobAttributes()
|
return Mob.createMobAttributes()
|
||||||
.add(Attributes.MAX_HEALTH, AntarchySettings.manticoreHealth())
|
.add(Attributes.MAX_HEALTH, AntarchySettings.manticoreHealth())
|
||||||
@@ -206,6 +214,8 @@ public class ManticoreEntity extends Monster implements GeoEntity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.tickQueenSummonInversionRule();
|
||||||
|
|
||||||
boolean flying = !this.onGround();
|
boolean flying = !this.onGround();
|
||||||
if (flying != this.wasFlyingLastTick) {
|
if (flying != this.wasFlyingLastTick) {
|
||||||
this.triggerAnim("controller", flying ? "fly_start" : "fly_land");
|
this.triggerAnim("controller", flying ? "fly_start" : "fly_land");
|
||||||
@@ -367,6 +377,24 @@ public class ManticoreEntity extends Monster implements GeoEntity {
|
|||||||
return AntarchyGravityApi.isGravityInverted(entity) ? new Vec3(0.0D, -1.0D, 0.0D) : new Vec3(0.0D, 1.0D, 0.0D);
|
return AntarchyGravityApi.isGravityInverted(entity) ? new Vec3(0.0D, -1.0D, 0.0D) : new Vec3(0.0D, 1.0D, 0.0D);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void tickQueenSummonInversionRule() {
|
||||||
|
if (!this.isQueenSummoned() || this.canUseQueenSummonInversion()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.hasEffect(AntarchyObjects.INVERTED_EFFECT.get())) {
|
||||||
|
this.removeEffect(AntarchyObjects.INVERTED_EFFECT.get());
|
||||||
|
}
|
||||||
|
if (AntarchyGravityApi.isGravityInverted(this) && AntarchyGravityApi.isGravityForced(this)) {
|
||||||
|
AntarchyGravityApi.setGravityDirection(this, AntarchyGravityDirection.DOWN, false);
|
||||||
|
}
|
||||||
|
this.setNoGravity(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canUseQueenSummonInversion() {
|
||||||
|
return ThoraxisUndersideManager.isThoraxis(this.level())
|
||||||
|
&& this.getY() < ThoraxisUndersideManager.GRAVITY_FLIP_Y + 4;
|
||||||
|
}
|
||||||
|
|
||||||
void performSting(LivingEntity enemy) {
|
void performSting(LivingEntity enemy) {
|
||||||
this.swing(InteractionHand.MAIN_HAND);
|
this.swing(InteractionHand.MAIN_HAND);
|
||||||
if (enemy.hurt(this.damageSources().mobAttack(this), (float) this.getAttributeValue(Attributes.ATTACK_DAMAGE))) {
|
if (enemy.hurt(this.damageSources().mobAttack(this), (float) this.getAttributeValue(Attributes.ATTACK_DAMAGE))) {
|
||||||
@@ -394,6 +422,14 @@ public class ManticoreEntity extends Monster implements GeoEntity {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canBeAffected(MobEffectInstance effectInstance) {
|
||||||
|
if (this.isQueenSummoned() && effectInstance.is(AntarchyObjects.INVERTED_EFFECT.get())) {
|
||||||
|
return this.canUseQueenSummonInversion();
|
||||||
|
}
|
||||||
|
return super.canBeAffected(effectInstance);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInWall() {
|
public boolean isInWall() {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
+2
-1
@@ -75,6 +75,7 @@ import software.bernie.geckolib.animation.RawAnimation;
|
|||||||
import software.bernie.geckolib.util.GeckoLibUtil;
|
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||||
|
|
||||||
public class ReverieEntity extends PathfinderMob implements FlyingAnimal, GeoEntity {
|
public class ReverieEntity extends PathfinderMob implements FlyingAnimal, GeoEntity {
|
||||||
|
private static final int DAMAGE_REACTION_DURATION_TICKS = 40;
|
||||||
private static final EntityDataAccessor<Integer> MOOD =
|
private static final EntityDataAccessor<Integer> MOOD =
|
||||||
SynchedEntityData.defineId(ReverieEntity.class, EntityDataSerializers.INT);
|
SynchedEntityData.defineId(ReverieEntity.class, EntityDataSerializers.INT);
|
||||||
private static final EntityDataAccessor<Integer> ANIMATION_STATE =
|
private static final EntityDataAccessor<Integer> ANIMATION_STATE =
|
||||||
@@ -318,7 +319,7 @@ public class ReverieEntity extends PathfinderMob implements FlyingAnimal, GeoEnt
|
|||||||
this.releaseFocus();
|
this.releaseFocus();
|
||||||
this.clearNoticePlayer();
|
this.clearNoticePlayer();
|
||||||
this.ambientTarget = null;
|
this.ambientTarget = null;
|
||||||
this.damageReactionTicks = 0;
|
this.damageReactionTicks = DAMAGE_REACTION_DURATION_TICKS;
|
||||||
this.inversionReactionTicks = 0;
|
this.inversionReactionTicks = 0;
|
||||||
this.transitionToMood(Mood.WHITE);
|
this.transitionToMood(Mood.WHITE);
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-3
@@ -38,6 +38,9 @@ import net.minecraft.world.entity.monster.Monster;
|
|||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.ServerLevelAccessor;
|
import net.minecraft.world.level.ServerLevelAccessor;
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import software.bernie.geckolib.animatable.GeoEntity;
|
import software.bernie.geckolib.animatable.GeoEntity;
|
||||||
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
||||||
import software.bernie.geckolib.animation.AnimatableManager;
|
import software.bernie.geckolib.animation.AnimatableManager;
|
||||||
@@ -51,6 +54,10 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class ScorpionEntity extends Monster implements GeoEntity {
|
public class ScorpionEntity extends Monster implements GeoEntity {
|
||||||
|
private static final ResourceKey<net.minecraft.world.level.biome.Biome> DREAM_DUNES = ResourceKey.create(
|
||||||
|
Registries.BIOME,
|
||||||
|
ResourceLocation.fromNamespaceAndPath("antarchy", "dream_dunes")
|
||||||
|
);
|
||||||
private static final byte ATTACK_ANIM_EVENT = 4;
|
private static final byte ATTACK_ANIM_EVENT = 4;
|
||||||
private static final EntityDataAccessor<Integer> TEXTURE_VARIANT =
|
private static final EntityDataAccessor<Integer> TEXTURE_VARIANT =
|
||||||
SynchedEntityData.defineId(ScorpionEntity.class, EntityDataSerializers.INT);
|
SynchedEntityData.defineId(ScorpionEntity.class, EntityDataSerializers.INT);
|
||||||
@@ -81,6 +88,11 @@ public class ScorpionEntity extends Monster implements GeoEntity {
|
|||||||
this.xpReward = 5;
|
this.xpReward = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean fireImmune() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static AttributeSupplier.Builder createAttributes() {
|
public static AttributeSupplier.Builder createAttributes() {
|
||||||
return Mob.createMobAttributes()
|
return Mob.createMobAttributes()
|
||||||
.add(Attributes.MAX_HEALTH, AntarchySettings.scorpionHealth())
|
.add(Attributes.MAX_HEALTH, AntarchySettings.scorpionHealth())
|
||||||
@@ -98,6 +110,12 @@ public class ScorpionEntity extends Monster implements GeoEntity {
|
|||||||
|| spawnReason == MobSpawnType.COMMAND) {
|
|| spawnReason == MobSpawnType.COMMAND) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// The Dream Dunes biome is the entire underside below Y=0. Its higher
|
||||||
|
// spawn weight is therefore targeted there without doubling the small
|
||||||
|
// surface-side Dream Dunes band as well.
|
||||||
|
if (pos.getY() >= 0 && level.getBiome(pos).is(DREAM_DUNES) && random.nextBoolean()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (ThoraxisUndersideManager.shouldSpawnInvertedOnDreamSand(level, pos)) {
|
if (ThoraxisUndersideManager.shouldSpawnInvertedOnDreamSand(level, pos)) {
|
||||||
return level.getDifficulty() != Difficulty.PEACEFUL;
|
return level.getDifficulty() != Difficulty.PEACEFUL;
|
||||||
}
|
}
|
||||||
@@ -182,7 +200,8 @@ public class ScorpionEntity extends Monster implements GeoEntity {
|
|||||||
|
|
||||||
this.getLookControl().setLookAt(this.attackTarget, 30.0F, 30.0F);
|
this.getLookControl().setLookAt(this.attackTarget, 30.0F, 30.0F);
|
||||||
if (!this.attackDamageApplied
|
if (!this.attackDamageApplied
|
||||||
&& this.attackAnimTicks == ATTACK_HIT_TICK
|
&& this.attackAnimTicks > 0
|
||||||
|
&& this.attackAnimTicks <= ATTACK_HIT_TICK
|
||||||
&& this.distanceToSqr(this.attackTarget) <= this.getAttackReachSqr(this.attackTarget)) {
|
&& this.distanceToSqr(this.attackTarget) <= this.getAttackReachSqr(this.attackTarget)) {
|
||||||
this.attackDamageApplied = true;
|
this.attackDamageApplied = true;
|
||||||
this.doHurtTarget(this.attackTarget);
|
this.doHurtTarget(this.attackTarget);
|
||||||
@@ -328,6 +347,10 @@ public class ScorpionEntity extends Monster implements GeoEntity {
|
|||||||
if (ScorpionEntity.this.attackTarget != null) {
|
if (ScorpionEntity.this.attackTarget != null) {
|
||||||
ScorpionEntity.this.getLookControl().setLookAt(ScorpionEntity.this.attackTarget, 30.0F, 30.0F);
|
ScorpionEntity.this.getLookControl().setLookAt(ScorpionEntity.this.attackTarget, 30.0F, 30.0F);
|
||||||
}
|
}
|
||||||
|
if (ScorpionEntity.this.isAttackLocked()) {
|
||||||
|
ScorpionEntity.this.getNavigation().stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
super.tick();
|
super.tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,8 +364,10 @@ public class ScorpionEntity extends Monster implements GeoEntity {
|
|||||||
if (ScorpionEntity.this.isAttackLocked()) {
|
if (ScorpionEntity.this.isAttackLocked()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.canPerformAttack(enemy) && this.isTimeToAttack() && ScorpionEntity.this.attackCooldownTicks <= 0) {
|
// Inverted melee tick handling replaces vanilla MeleeAttackGoal.tick,
|
||||||
this.resetAttackCooldown();
|
// so vanilla's internal attack timer is not advanced. The Scorpion's
|
||||||
|
// own cooldown already covers its wind-up and hit timing.
|
||||||
|
if (this.canPerformAttack(enemy) && ScorpionEntity.this.attackCooldownTicks <= 0) {
|
||||||
ScorpionEntity.this.beginAttack(enemy);
|
ScorpionEntity.this.beginAttack(enemy);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-4
@@ -15,6 +15,8 @@ import net.minecraft.world.entity.MobSpawnType;
|
|||||||
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||||
import net.minecraft.world.entity.ai.goal.FloatGoal;
|
import net.minecraft.world.entity.ai.goal.FloatGoal;
|
||||||
|
import net.minecraft.world.entity.ai.goal.BreedGoal;
|
||||||
|
import net.minecraft.world.entity.ai.goal.TemptGoal;
|
||||||
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
|
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
|
||||||
import net.minecraft.world.entity.ai.goal.PanicGoal;
|
import net.minecraft.world.entity.ai.goal.PanicGoal;
|
||||||
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
|
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
|
||||||
@@ -23,6 +25,8 @@ import net.minecraft.world.entity.animal.Animal;
|
|||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.sounds.SoundEvent;
|
import net.minecraft.sounds.SoundEvent;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
|
import net.minecraft.world.item.crafting.Ingredient;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.ServerLevelAccessor;
|
import net.minecraft.world.level.ServerLevelAccessor;
|
||||||
import net.minecraft.world.Difficulty;
|
import net.minecraft.world.Difficulty;
|
||||||
@@ -86,9 +90,11 @@ public class StinkBugEntity extends Animal implements GeoEntity {
|
|||||||
protected void registerGoals() {
|
protected void registerGoals() {
|
||||||
this.goalSelector.addGoal(0, new FloatGoal(this));
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
||||||
this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D));
|
this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D));
|
||||||
this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 0.9D));
|
this.goalSelector.addGoal(2, new TemptGoal(this, 1.0D, Ingredient.of(Items.ROTTEN_FLESH), false));
|
||||||
this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 6.0F));
|
this.goalSelector.addGoal(3, new BreedGoal(this, 0.9D));
|
||||||
this.goalSelector.addGoal(4, new RandomLookAroundGoal(this));
|
this.goalSelector.addGoal(4, new WaterAvoidingRandomStrollGoal(this, 0.9D));
|
||||||
|
this.goalSelector.addGoal(5, new LookAtPlayerGoal(this, Player.class, 6.0F));
|
||||||
|
this.goalSelector.addGoal(6, new RandomLookAroundGoal(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -118,7 +124,7 @@ public class StinkBugEntity extends Animal implements GeoEntity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFood(ItemStack stack) {
|
public boolean isFood(ItemStack stack) {
|
||||||
return false;
|
return stack.is(Items.ROTTEN_FLESH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+5
-2
@@ -313,7 +313,10 @@ public final class AntTeleportHelper {
|
|||||||
return new int[]{100, 200};
|
return new int[]{100, 200};
|
||||||
}
|
}
|
||||||
if (dim == AntarchySettings.brownAntDestinationDimension()) {
|
if (dim == AntarchySettings.brownAntDestinationDimension()) {
|
||||||
return new int[]{75, 120};
|
return new int[]{60, 240};
|
||||||
|
}
|
||||||
|
if (dim == AntarchySettings.redAntDestinationDimension()) {
|
||||||
|
return new int[]{0, 220};
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -328,7 +331,7 @@ public final class AntTeleportHelper {
|
|||||||
}
|
}
|
||||||
int x = preferredPos.getX() + xOff;
|
int x = preferredPos.getX() + xOff;
|
||||||
int z = preferredPos.getZ() + zOff;
|
int z = preferredPos.getZ() + zOff;
|
||||||
for (int y = maxY; y >= minY + 1; y--) {
|
for (int y = minY + 1; y <= maxY; y++) {
|
||||||
Vec3 safePos = tryFindSafeDismount(player, destination, new BlockPos(x, y, z));
|
Vec3 safePos = tryFindSafeDismount(player, destination, new BlockPos(x, y, z));
|
||||||
if (safePos != null && safePos.y >= minY && safePos.y <= maxY) {
|
if (safePos != null && safePos.y >= minY && safePos.y <= maxY) {
|
||||||
return safePos;
|
return safePos;
|
||||||
|
|||||||
+2
-1
@@ -1035,7 +1035,8 @@ public class KrakenEntity extends Monster implements GeoEntity, MultipartEntityO
|
|||||||
for (int i = 0; i < strikeBolts; i++) {
|
for (int i = 0; i < strikeBolts; i++) {
|
||||||
this.spawnVisualLightning(serverLevel, this.getTargetStormStrikePos(target));
|
this.spawnVisualLightning(serverLevel, this.getTargetStormStrikePos(target));
|
||||||
}
|
}
|
||||||
target.hurt(AntarchyDamageSources.krakenLightning(serverLevel, this), this.isPhaseTwo() ? 12.0F : 8.0F);
|
target.hurt(AntarchyDamageSources.krakenLightning(serverLevel, this),
|
||||||
|
this.isPhaseTwo() ? 12.0F : AntarchySettings.krakenLightningDamagePhaseOne());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.lightningStrikeCooldown = this.isPhaseTwo() ? 30 : 60;
|
this.lightningStrikeCooldown = this.isPhaseTwo() ? 30 : 60;
|
||||||
|
|||||||
+29
-2
@@ -1,5 +1,6 @@
|
|||||||
package com.craisinlord.antarchy.content.entity.portal;
|
package com.craisinlord.antarchy.content.entity.portal;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||||
import com.craisinlord.antarchy.content.AntarchySoundEvents;
|
import com.craisinlord.antarchy.content.AntarchySoundEvents;
|
||||||
@@ -176,6 +177,13 @@ public class DimensionalTearEntity extends Entity implements GeoEntity {
|
|||||||
|
|
||||||
DimensionalTearEntity linked = this.findLinkedTear();
|
DimensionalTearEntity linked = this.findLinkedTear();
|
||||||
if (linked == null || !linked.isAlive()) {
|
if (linked == null || !linked.isAlive()) {
|
||||||
|
Antarchy.LOGGER.warn(
|
||||||
|
"[antarchy-dimensional-tear] discarding unlinked tear uuid={} pos=({}, {}, {}) dim={} linkedTearId={} fallback=({}, {}, {}) ageTicks={} lifetimeTicks={}",
|
||||||
|
this.getUUID(), this.getX(), this.getY(), this.getZ(), this.level().dimension().location(),
|
||||||
|
this.linkedTearId,
|
||||||
|
this.linkedFallbackPos.x, this.linkedFallbackPos.y, this.linkedFallbackPos.z,
|
||||||
|
this.ageTicks, this.lifetimeTicks
|
||||||
|
);
|
||||||
this.discard();
|
this.discard();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -264,7 +272,7 @@ public class DimensionalTearEntity extends Entity implements GeoEntity {
|
|||||||
manticore.setTarget(target);
|
manticore.setTarget(target);
|
||||||
}
|
}
|
||||||
manticore.setDeltaMovement(this.getViewVector(1.0F).scale(0.2D).add(0.0D, 0.08D, 0.0D));
|
manticore.setDeltaMovement(this.getViewVector(1.0F).scale(0.2D).add(0.0D, 0.08D, 0.0D));
|
||||||
manticore.setNoGravity(true);
|
manticore.setNoGravity(false);
|
||||||
level.addFreshEntity(manticore);
|
level.addFreshEntity(manticore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -348,6 +356,7 @@ public class DimensionalTearEntity extends Entity implements GeoEntity {
|
|||||||
|
|
||||||
private void teleportEntity(Entity entity, DimensionalTearEntity destination) {
|
private void teleportEntity(Entity entity, DimensionalTearEntity destination) {
|
||||||
Vec3 motion = entity.getDeltaMovement();
|
Vec3 motion = entity.getDeltaMovement();
|
||||||
|
Vec3 startPos = entity.position();
|
||||||
Vec3 exitPos = destination.exitPosition();
|
Vec3 exitPos = destination.exitPosition();
|
||||||
TELEPORT_COOLDOWNS.put(entity.getUUID(), this.level().getGameTime() + TELEPORT_COOLDOWN_TICKS);
|
TELEPORT_COOLDOWNS.put(entity.getUUID(), this.level().getGameTime() + TELEPORT_COOLDOWN_TICKS);
|
||||||
|
|
||||||
@@ -360,7 +369,15 @@ public class DimensionalTearEntity extends Entity implements GeoEntity {
|
|||||||
entity.setDeltaMovement(motion);
|
entity.setDeltaMovement(motion);
|
||||||
entity.hasImpulse = true;
|
entity.hasImpulse = true;
|
||||||
if (entity instanceof LivingEntity living) {
|
if (entity instanceof LivingEntity living) {
|
||||||
living.addEffect(new MobEffectInstance(AntarchyObjects.INVERTED_EFFECT.get(), AntarchySettings.dimensionalTearInvertedDurationTicks(), 0));
|
int invertedDuration = AntarchySettings.dimensionalTearInvertedDurationTicks();
|
||||||
|
Antarchy.LOGGER.info(
|
||||||
|
"[antarchy-dimensional-tear] applying inverted effect targetType={} uuid={} fromTear={} toTear={} startPos=({}, {}, {}) exitPos=({}, {}, {}) dim={} durationTicks={}",
|
||||||
|
living.getType(), living.getUUID(), this.getUUID(), destination.getUUID(),
|
||||||
|
startPos.x, startPos.y, startPos.z,
|
||||||
|
exitPos.x, exitPos.y, exitPos.z,
|
||||||
|
this.level().dimension().location(), invertedDuration
|
||||||
|
);
|
||||||
|
living.addEffect(new MobEffectInstance(AntarchyObjects.INVERTED_EFFECT.get(), invertedDuration, 0));
|
||||||
}
|
}
|
||||||
this.level().playSound(null, this.blockPosition(), SoundEvents.ENDERMAN_TELEPORT, SoundSource.NEUTRAL, 0.7F, 0.65F + this.random.nextFloat() * 0.2F);
|
this.level().playSound(null, this.blockPosition(), SoundEvents.ENDERMAN_TELEPORT, SoundSource.NEUTRAL, 0.7F, 0.65F + this.random.nextFloat() * 0.2F);
|
||||||
}
|
}
|
||||||
@@ -516,6 +533,16 @@ public class DimensionalTearEntity extends Entity implements GeoEntity {
|
|||||||
this.queenManticoreCount = tag.getInt("QueenManticoreCount");
|
this.queenManticoreCount = tag.getInt("QueenManticoreCount");
|
||||||
this.queenManticoreSpawned = tag.getBoolean("QueenManticoreSpawned");
|
this.queenManticoreSpawned = tag.getBoolean("QueenManticoreSpawned");
|
||||||
}
|
}
|
||||||
|
if (!this.level().isClientSide) {
|
||||||
|
Antarchy.LOGGER.info(
|
||||||
|
"[antarchy-dimensional-tear] loaded tear uuid={} pos=({}, {}, {}) dim={} linkedTearId={} fallback=({}, {}, {}) ageTicks={} lifetimeTicks={} eventTicks={} nextEventTicks={} pendingEvent={} queenOwner={} queenManticoreCount={} queenManticoreSpawned={}",
|
||||||
|
this.getUUID(), this.getX(), this.getY(), this.getZ(), this.level().dimension().location(),
|
||||||
|
this.linkedTearId,
|
||||||
|
this.linkedFallbackPos.x, this.linkedFallbackPos.y, this.linkedFallbackPos.z,
|
||||||
|
this.ageTicks, this.lifetimeTicks, this.eventTicks, this.nextEventTicks, this.pendingEvent,
|
||||||
|
this.queenOwnerId, this.queenManticoreCount, this.queenManticoreSpawned
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+162
-38
@@ -1,6 +1,7 @@
|
|||||||
package com.craisinlord.antarchy.content.entity.royal;
|
package com.craisinlord.antarchy.content.entity.royal;
|
||||||
|
|
||||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
|
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||||
import com.craisinlord.antarchy.content.AntarchySoundEvents;
|
import com.craisinlord.antarchy.content.AntarchySoundEvents;
|
||||||
import net.minecraft.sounds.SoundEvent;
|
import net.minecraft.sounds.SoundEvent;
|
||||||
import net.minecraft.sounds.SoundEvents;
|
import net.minecraft.sounds.SoundEvents;
|
||||||
@@ -35,7 +36,6 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamSettings;
|
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.RoyalBeamTerrainMode;
|
||||||
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement;
|
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.CloseQuartersDecree;
|
||||||
import com.craisinlord.antarchy.content.entity.royal.decree.ComeNoCloserDecree;
|
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.DoNotRunDecree;
|
||||||
@@ -50,6 +50,7 @@ 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.SkyIsMineDecree;
|
||||||
import com.craisinlord.antarchy.content.entity.royal.decree.StandTallDecree;
|
import com.craisinlord.antarchy.content.entity.royal.decree.StandTallDecree;
|
||||||
import com.craisinlord.antarchy.content.entity.royal.decree.StandYourGroundDecree;
|
import com.craisinlord.antarchy.content.entity.royal.decree.StandYourGroundDecree;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackLane;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -79,9 +80,10 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
private int decreeCooldownTicks;
|
private int decreeCooldownTicks;
|
||||||
private int activeDecreeTicks;
|
private int activeDecreeTicks;
|
||||||
private int stompCooldownTicks;
|
private int stompCooldownTicks;
|
||||||
private int stompWindupTicks;
|
|
||||||
private int wingGustCooldownTicks;
|
private int wingGustCooldownTicks;
|
||||||
private int wingGustWindupTicks;
|
private int fireballCooldownTicks = 80;
|
||||||
|
private int iceballCooldownTicks = 120;
|
||||||
|
private int iceSpikeCooldownTicks = 160;
|
||||||
private boolean decreeRetreatPressure;
|
private boolean decreeRetreatPressure;
|
||||||
private final Map<UUID, Long> judgmentCooldowns = new HashMap<>();
|
private final Map<UUID, Long> judgmentCooldowns = new HashMap<>();
|
||||||
private final Map<UUID, Long> lastPlayerDamageTime = new HashMap<>();
|
private final Map<UUID, Long> lastPlayerDamageTime = new HashMap<>();
|
||||||
@@ -91,9 +93,9 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
private RoyalDecree activeDecree;
|
private RoyalDecree activeDecree;
|
||||||
private static final List<RoyalDecree> DECREES = List.of(
|
private static final List<RoyalDecree> DECREES = List.of(
|
||||||
new SkyIsMineDecree(), new DoNotRunDecree(), new KneelDecree(), new CloseQuartersDecree(),
|
new SkyIsMineDecree(), new DoNotRunDecree(), new KneelDecree(), new CloseQuartersDecree(),
|
||||||
new ComeNoCloserDecree(), new FightMeCowardDecree(), new NoRespiteDecree(), new NoRetreatDecree(),
|
new ComeNoCloserDecree(), new FightMeCowardDecree(), new NoRespiteDecree(),
|
||||||
new KeepYourDistanceDecree(), new StandTallDecree(), new StandYourGroundDecree(),
|
new StandTallDecree(), new StandYourGroundDecree(),
|
||||||
new HandsOffTheCrownDecree(), new AdvanceDecree(), new ShowNoMercyDecree());
|
new HandsOffTheCrownDecree(), new ShowNoMercyDecree());
|
||||||
|
|
||||||
public KingEntity(EntityType<? extends KingEntity> entityType, Level level) {
|
public KingEntity(EntityType<? extends KingEntity> entityType, Level level) {
|
||||||
super(entityType, level);
|
super(entityType, level);
|
||||||
@@ -133,6 +135,11 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
return AntarchySoundEvents.KING_DEATH.get();
|
return AntarchySoundEvents.KING_DEATH.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SoundEvent royalFlyLoopSound() {
|
||||||
|
return AntarchySoundEvents.KING_FLY_LOOP.get();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SoundEvent royalBiteSound() {
|
protected SoundEvent royalBiteSound() {
|
||||||
return AntarchySoundEvents.KING_BITE.get();
|
return AntarchySoundEvents.KING_BITE.get();
|
||||||
@@ -160,7 +167,7 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
@Override
|
@Override
|
||||||
protected RoyalBeamSettings royalBeamSettings() {
|
protected RoyalBeamSettings royalBeamSettings() {
|
||||||
return new RoyalBeamSettings(AntarchySettings.kingBeamRange(), AntarchySettings.kingBeamTracking(), 7.5D,
|
return new RoyalBeamSettings(AntarchySettings.kingBeamRange(), AntarchySettings.kingBeamTracking(), 7.5D,
|
||||||
AntarchySettings.kingBeamDurationTicks(), AntarchySettings.kingBeamCooldownTicks(), 6.0F, 6.0F,
|
AntarchySettings.kingBeamDurationTicks(), AntarchySettings.kingBeamTravelTicks(), AntarchySettings.kingBeamCooldownTicks(), 6.0F, 6.0F,
|
||||||
(float) AntarchySettings.kingBeamDamage(), 1.0F, 3, 100.0D,
|
(float) AntarchySettings.kingBeamDamage(), 1.0F, 3, 100.0D,
|
||||||
(float) AntarchySettings.kingBeamTerrainRadius(), 4.0F, AntarchySettings.kingBeamTerrainCap(),
|
(float) AntarchySettings.kingBeamTerrainRadius(), 4.0F, AntarchySettings.kingBeamTerrainCap(),
|
||||||
1.0F, 0.08F, 15.0F, true, true);
|
1.0F, 0.08F, 15.0F, true, true);
|
||||||
@@ -194,13 +201,13 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var particle = switch (head.slot()) {
|
var particle = switch (head.slot()) {
|
||||||
case LEFT -> ParticleTypes.FLAME;
|
case LEFT -> null;
|
||||||
case CENTER -> ParticleTypes.ELECTRIC_SPARK;
|
case CENTER -> ParticleTypes.ELECTRIC_SPARK;
|
||||||
case RIGHT -> ParticleTypes.SNOWFLAKE;
|
case RIGHT -> ParticleTypes.SNOWFLAKE;
|
||||||
};
|
};
|
||||||
Vec3 direction = end.subtract(start);
|
Vec3 direction = end.subtract(start);
|
||||||
double distance = direction.length();
|
double distance = direction.length();
|
||||||
if (distance > 0.001D) {
|
if (particle != null && distance > 0.001D) {
|
||||||
direction = direction.scale(1.0D / distance);
|
direction = direction.scale(1.0D / distance);
|
||||||
for (double walked = 0.0D; walked <= distance; walked += 2.5D) {
|
for (double walked = 0.0D; walked <= distance; walked += 2.5D) {
|
||||||
Vec3 point = start.add(direction.scale(walked));
|
Vec3 point = start.add(direction.scale(walked));
|
||||||
@@ -311,7 +318,7 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
}
|
}
|
||||||
if (this.patrolCooldownTicks-- <= 0) {
|
if (this.patrolCooldownTicks-- <= 0) {
|
||||||
this.patrolCooldownTicks = 100 + this.random.nextInt(100);
|
this.patrolCooldownTicks = 100 + this.random.nextInt(100);
|
||||||
this.playSound(AntarchySoundEvents.KING_WING_FLAP.get(), 2.0F, 0.9F + this.random.nextFloat() * 0.15F);
|
this.playRoyalSound(AntarchySoundEvents.KING_WING_FLAP.get(), 0.9F + this.random.nextFloat() * 0.15F);
|
||||||
double angle = this.random.nextDouble() * Math.PI * 2.0D;
|
double angle = this.random.nextDouble() * Math.PI * 2.0D;
|
||||||
double radius = 12.0D + this.random.nextDouble() * 18.0D;
|
double radius = 12.0D + this.random.nextDouble() * 18.0D;
|
||||||
double px = this.patrolCenter.x + Math.cos(angle) * radius;
|
double px = this.patrolCenter.x + Math.cos(angle) * radius;
|
||||||
@@ -347,37 +354,41 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void tickKingWholeBody(ServerLevel level, LivingEntity target) {
|
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 skyIsMine = this.activeDecree instanceof SkyIsMineDecree;
|
||||||
boolean forceFar = this.decreeRetreatPressure
|
boolean forceFar = this.decreeRetreatPressure
|
||||||
|| this.activeDecree instanceof ComeNoCloserDecree
|
|| this.activeDecree instanceof ComeNoCloserDecree
|
||||||
|| this.activeDecree instanceof KeepYourDistanceDecree;
|
|| 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);
|
double distance = target.distanceTo(this);
|
||||||
if (this.stompCooldownTicks <= 0 && (distance <= STOMP_RADIUS || skyIsMine)) {
|
if (this.attackScheduler.ready("stomp", RoyalAttackLane.BODY)
|
||||||
this.stompCooldownTicks = skyIsMine ? STOMP_COOLDOWN_TICKS / 2 : STOMP_COOLDOWN_TICKS;
|
&& (distance <= STOMP_RADIUS || skyIsMine)
|
||||||
this.stompWindupTicks = STOMP_WINDUP_TICKS;
|
&& this.beginRoyalAttack("stomp", RoyalAttackLane.BODY,
|
||||||
this.triggerAnim("body_action", "stomp");
|
skyIsMine ? STOMP_COOLDOWN_TICKS / 2 : STOMP_COOLDOWN_TICKS,
|
||||||
this.playSound(AntarchySoundEvents.KING_ROAR.get(), 3.0F, 0.7F);
|
STOMP_WINDUP_TICKS, 1, 18, new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
|
||||||
|
@Override public void onStart() {
|
||||||
|
KingEntity.this.triggerAnim("body_action", "stomp");
|
||||||
|
KingEntity.this.playRoyalSound(AntarchySoundEvents.KING_ROAR.get(), 0.7F);
|
||||||
|
}
|
||||||
|
@Override public void onActive(int elapsedTicks) {
|
||||||
|
KingEntity.this.performStomp(level, target);
|
||||||
|
}
|
||||||
|
})) {
|
||||||
if (skyIsMine) {
|
if (skyIsMine) {
|
||||||
this.getMoveControl().setWantedPosition(this.getX(), target.getY(), this.getZ(), 1.2D);
|
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)) {
|
} else if (this.attackScheduler.ready("wing_gust", RoyalAttackLane.BODY)
|
||||||
this.wingGustCooldownTicks = WING_GUST_COOLDOWN_TICKS;
|
&& distance <= WING_GUST_RADIUS && (forceFar || this.random.nextInt(3) == 0)
|
||||||
this.wingGustWindupTicks = WING_GUST_WINDUP_TICKS;
|
&& this.beginRoyalAttack("wing_gust", RoyalAttackLane.BODY, WING_GUST_COOLDOWN_TICKS,
|
||||||
this.triggerAnim("body_action", "wing_gust");
|
WING_GUST_WINDUP_TICKS, 1, 16, new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
|
||||||
this.playSound(AntarchySoundEvents.KING_WING_FLAP.get(), 3.0F, 0.85F);
|
@Override public void onStart() {
|
||||||
|
KingEntity.this.triggerAnim("body_action", "wing_gust");
|
||||||
|
KingEntity.this.playRoyalSound(AntarchySoundEvents.KING_WING_FLAP.get(), 0.85F);
|
||||||
|
}
|
||||||
|
@Override public void onActive(int elapsedTicks) {
|
||||||
|
KingEntity.this.performWingGust(level, target);
|
||||||
|
}
|
||||||
|
})) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,6 +399,101 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
double ay = this.groundYBelow(ax, az) + FLYING_PREFERRED_HOVER + 6.0D;
|
double ay = this.groundYBelow(ax, az) + FLYING_PREFERRED_HOVER + 6.0D;
|
||||||
this.getMoveControl().setWantedPosition(ax, ay, az, 1.3D);
|
this.getMoveControl().setWantedPosition(ax, ay, az, 1.3D);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.tickKingElementalProjectiles(level, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tickKingElementalProjectiles(ServerLevel level, LivingEntity target) {
|
||||||
|
if (this.fireballCooldownTicks > 0) this.fireballCooldownTicks--;
|
||||||
|
if (this.iceballCooldownTicks > 0) this.iceballCooldownTicks--;
|
||||||
|
if (this.iceSpikeCooldownTicks > 0) this.iceSpikeCooldownTicks--;
|
||||||
|
|
||||||
|
double distance = this.distanceTo(target);
|
||||||
|
String[] candidates = {"fireball", "iceball", "ice_spikes"};
|
||||||
|
String selected = this.attackScheduler.chooseWeighted(candidates, id -> {
|
||||||
|
boolean ready = switch (id) {
|
||||||
|
case "fireball" -> distance >= 14.0D && distance <= 48.0D && this.fireballCooldownTicks <= 0
|
||||||
|
&& this.royalHead(RoyalHead.Slot.LEFT).readyToAttack();
|
||||||
|
case "iceball" -> distance >= 10.0D && distance <= 42.0D && this.iceballCooldownTicks <= 0
|
||||||
|
&& this.royalHead(RoyalHead.Slot.RIGHT).readyToAttack();
|
||||||
|
default -> distance <= 36.0D && this.iceSpikeCooldownTicks <= 0
|
||||||
|
&& this.royalHead(RoyalHead.Slot.RIGHT).readyToAttack();
|
||||||
|
};
|
||||||
|
if (!ready) return 0;
|
||||||
|
return switch (id) {
|
||||||
|
case "fireball" -> this.behaviorScore(Behavior.KEEPING_FAR) + 4;
|
||||||
|
case "iceball" -> this.behaviorScore(Behavior.RETREATING) + 4;
|
||||||
|
default -> this.behaviorScore(Behavior.HUGGING) + 3;
|
||||||
|
};
|
||||||
|
}, this.random);
|
||||||
|
if (selected == null) return;
|
||||||
|
if ("fireball".equals(selected)) {
|
||||||
|
if (!this.beginRoyalAttack("fireball", RoyalAttackLane.LEFT_HEAD,
|
||||||
|
AntarchySettings.kingFireballCooldownTicks(), 14, 1, 5,
|
||||||
|
new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
|
||||||
|
@Override public void onStart() {
|
||||||
|
KingEntity.this.triggerAnim(RoyalHead.Slot.LEFT.controllerName(), "shoot");
|
||||||
|
}
|
||||||
|
@Override public void onActive(int elapsedTicks) {
|
||||||
|
Vec3 origin = KingEntity.this.headAnchor(KingEntity.this.royalHead(RoyalHead.Slot.LEFT));
|
||||||
|
Vec3 predicted = target.position().add(target.getDeltaMovement().scale(10.0D));
|
||||||
|
Vec3 direction = predicted.add(0.0D, target.getBbHeight() * 0.5D, 0.0D).subtract(origin).normalize();
|
||||||
|
RoyalElementalProjectileEntity fireball = RoyalElementalProjectileEntity.create(level, KingEntity.this,
|
||||||
|
RoyalBeamElement.FIRE, origin, direction);
|
||||||
|
level.addFreshEntity(fireball);
|
||||||
|
KingEntity.this.playRoyalSound(AntarchySoundEvents.KING_FIREBALL_SHOOT.get(), 0.9F);
|
||||||
|
}
|
||||||
|
})) return;
|
||||||
|
this.fireballCooldownTicks = AntarchySettings.kingFireballCooldownTicks();
|
||||||
|
} else if ("iceball".equals(selected)) {
|
||||||
|
if (!this.beginRoyalAttack("iceball", RoyalAttackLane.RIGHT_HEAD,
|
||||||
|
AntarchySettings.kingIceballCooldownTicks(), 16, 1, 5,
|
||||||
|
new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
|
||||||
|
@Override public void onStart() {
|
||||||
|
KingEntity.this.triggerAnim(RoyalHead.Slot.RIGHT.controllerName(), "shoot");
|
||||||
|
}
|
||||||
|
@Override public void onActive(int elapsedTicks) {
|
||||||
|
Vec3 origin = KingEntity.this.headAnchor(KingEntity.this.royalHead(RoyalHead.Slot.RIGHT));
|
||||||
|
Vec3 direction = target.getEyePosition().subtract(origin).normalize();
|
||||||
|
RoyalElementalProjectileEntity iceball = RoyalElementalProjectileEntity.create(level, KingEntity.this,
|
||||||
|
RoyalBeamElement.ICE, origin, direction);
|
||||||
|
level.addFreshEntity(iceball);
|
||||||
|
KingEntity.this.playRoyalSound(AntarchySoundEvents.KING_BEAM_SHOOT.get(), 1.2F);
|
||||||
|
}
|
||||||
|
})) return;
|
||||||
|
this.iceballCooldownTicks = AntarchySettings.kingIceballCooldownTicks();
|
||||||
|
} else {
|
||||||
|
if (!this.beginRoyalAttack("ice_spikes", RoyalAttackLane.RIGHT_HEAD,
|
||||||
|
AntarchySettings.kingIceSpikeCooldownTicks(), 20, 1, 5,
|
||||||
|
new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
|
||||||
|
@Override public void onStart() {
|
||||||
|
KingEntity.this.triggerAnim(RoyalHead.Slot.RIGHT.controllerName(), "shoot");
|
||||||
|
}
|
||||||
|
@Override public void onActive(int elapsedTicks) {
|
||||||
|
KingEntity.this.raiseIceSpikes(level, target);
|
||||||
|
KingEntity.this.playRoyalSound(AntarchySoundEvents.KING_BEAM_SHOOT.get(), 0.8F);
|
||||||
|
}
|
||||||
|
})) return;
|
||||||
|
this.iceSpikeCooldownTicks = AntarchySettings.kingIceSpikeCooldownTicks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void raiseIceSpikes(ServerLevel level, LivingEntity target) {
|
||||||
|
Vec3 start = this.position();
|
||||||
|
Vec3 end = target.position();
|
||||||
|
Vec3 line = end.subtract(start).multiply(1.0D, 0.0D, 1.0D);
|
||||||
|
if (line.lengthSqr() < 1.0E-4D) return;
|
||||||
|
line = line.normalize();
|
||||||
|
Vec3 side = new Vec3(-line.z, 0.0D, line.x);
|
||||||
|
for (int i = 1; i <= 5; i++) {
|
||||||
|
double distance = i * 4.0D;
|
||||||
|
for (int lane = -1; lane <= 1; lane++) {
|
||||||
|
Vec3 point = start.add(line.scale(distance)).add(side.scale(lane * (i % 2 == 0 ? 2.0D : 0.0D)));
|
||||||
|
double y = this.groundYBelow(point.x, point.z) + 0.1D;
|
||||||
|
RoyalIceSpikeEntity spike = RoyalIceSpikeEntity.create(level, new Vec3(point.x, y, point.z));
|
||||||
|
level.addFreshEntity(spike);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void performStomp(ServerLevel level, LivingEntity target) {
|
private void performStomp(ServerLevel level, LivingEntity target) {
|
||||||
@@ -406,7 +512,7 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
RoyalBlockDestruction.destroySphere(level, this,
|
RoyalBlockDestruction.destroySphere(level, this,
|
||||||
new Vec3(this.getX(), this.getY(), this.getZ()), STOMP_RADIUS * 0.5D, 96, 80.0D, 0.15F);
|
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);
|
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);
|
this.playRoyalSound(AntarchySoundEvents.KING_STOMP.get(), 0.8F);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void performWingGust(ServerLevel level, LivingEntity target) {
|
private void performWingGust(ServerLevel level, LivingEntity target) {
|
||||||
@@ -434,11 +540,15 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
if (this.decreeCooldownTicks-- > 0) {
|
if (this.decreeCooldownTicks-- > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!this.beginRoyalAttack("decree", RoyalAttackLane.DECREE,
|
||||||
|
AntarchySettings.royalDecreeCooldownTicks(), 300)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.activeDecreeTicks = 300;
|
this.activeDecreeTicks = 300;
|
||||||
this.activeDecree = this.pickDecree(target);
|
this.activeDecree = this.pickDecree(target);
|
||||||
this.decreeRetreatPressure = false;
|
this.decreeRetreatPressure = false;
|
||||||
this.playSound(AntarchySoundEvents.KING_DECREE_CAST.get(), 3.0F, 0.9F + this.random.nextFloat() * 0.15F);
|
this.playRoyalSound(AntarchySoundEvents.KING_DECREE_CAST.get(), 0.9F + this.random.nextFloat() * 0.15F);
|
||||||
this.playSound(AntarchySoundEvents.KING_ROAR.get(), 3.0F, 0.8F + this.random.nextFloat() * 0.12F);
|
this.playRoyalSound(AntarchySoundEvents.KING_ROAR.get(), 0.8F + this.random.nextFloat() * 0.12F);
|
||||||
if (target instanceof ServerPlayer player) {
|
if (target instanceof ServerPlayer player) {
|
||||||
player.connection.send(new ClientboundSetTitlesAnimationPacket(5, 300, 10));
|
player.connection.send(new ClientboundSetTitlesAnimationPacket(5, 300, 10));
|
||||||
player.connection.send(new ClientboundSetTitleTextPacket(Component.translatable(this.activeDecree.translationKey())
|
player.connection.send(new ClientboundSetTitleTextPacket(Component.translatable(this.activeDecree.translationKey())
|
||||||
@@ -452,6 +562,11 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
level.playSound(null, target.blockPosition(), SoundEvents.BELL_BLOCK, SoundSource.HOSTILE, 0.8F, 1.0F + countdown / 500.0F);
|
level.playSound(null, target.blockPosition(), SoundEvents.BELL_BLOCK, SoundSource.HOSTILE, 0.8F, 1.0F + countdown / 500.0F);
|
||||||
}
|
}
|
||||||
this.activeDecree.apply(level, this, target);
|
this.activeDecree.apply(level, this, target);
|
||||||
|
if (this.activeDecree != null
|
||||||
|
&& this.activeDecree.evaluate(level, this, target) == RoyalDecree.Evaluation.VIOLATED) {
|
||||||
|
this.failActiveDecree(target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (this.activeDecree != null && --this.activeDecreeTicks <= 0) {
|
if (this.activeDecree != null && --this.activeDecreeTicks <= 0) {
|
||||||
this.endDecree(target);
|
this.endDecree(target);
|
||||||
}
|
}
|
||||||
@@ -495,6 +610,15 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
this.endDecree(target);
|
this.endDecree(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Resolves a decree violation once, using the existing bounded judgment while the new judgment system is pending. */
|
||||||
|
public void failActiveDecree(@Nullable LivingEntity target) {
|
||||||
|
if (this.activeDecree == null || target == null || !target.isAlive()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.invokeJudgment(target);
|
||||||
|
this.endDecree(target);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean blocksHealing() {
|
public boolean blocksHealing() {
|
||||||
return this.activeDecree instanceof NoRespiteDecree;
|
return this.activeDecree instanceof NoRespiteDecree;
|
||||||
}
|
}
|
||||||
@@ -520,11 +644,11 @@ public class KingEntity extends RoyalBossEntity {
|
|||||||
boolean projectile = source.getDirectEntity() instanceof Projectile;
|
boolean projectile = source.getDirectEntity() instanceof Projectile;
|
||||||
this.bumpBehavior(projectile ? Behavior.RANGED : Behavior.HUGGING, 2);
|
this.bumpBehavior(projectile ? Behavior.RANGED : Behavior.HUGGING, 2);
|
||||||
if (this.activeDecree instanceof CloseQuartersDecree && projectile) {
|
if (this.activeDecree instanceof CloseQuartersDecree && projectile) {
|
||||||
this.invokeJudgment(attacker);
|
this.failActiveDecree(attacker);
|
||||||
} else if (this.activeDecree instanceof ComeNoCloserDecree && !projectile) {
|
} else if (this.activeDecree instanceof ComeNoCloserDecree && !projectile) {
|
||||||
this.invokeJudgment(attacker);
|
this.failActiveDecree(attacker);
|
||||||
} else if (this.activeDecree instanceof HandsOffTheCrownDecree) {
|
} else if (this.activeDecree instanceof HandsOffTheCrownDecree) {
|
||||||
this.invokeJudgment(attacker);
|
this.failActiveDecree(attacker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.hurt(source, amount);
|
return super.hurt(source, amount);
|
||||||
|
|||||||
+121
-68
@@ -30,6 +30,8 @@ import net.minecraft.world.level.Level;
|
|||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamSettings;
|
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.RoyalBeamTerrainMode;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackLane;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.attack.RoyalEffectController;
|
||||||
import com.craisinlord.antarchy.content.entity.portal.DimensionalTearEntity;
|
import com.craisinlord.antarchy.content.entity.portal.DimensionalTearEntity;
|
||||||
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
||||||
import net.minecraft.world.damagesource.DamageSource;
|
import net.minecraft.world.damagesource.DamageSource;
|
||||||
@@ -61,13 +63,12 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
private int gravityStompCooldownTicks;
|
private int gravityStompCooldownTicks;
|
||||||
private int timeFieldCooldownTicks;
|
private int timeFieldCooldownTicks;
|
||||||
private int momentumLockCooldownTicks;
|
private int momentumLockCooldownTicks;
|
||||||
private int momentumLockTicks;
|
|
||||||
private int crushingGravityCooldownTicks;
|
private int crushingGravityCooldownTicks;
|
||||||
private int crushingGravityTicks;
|
|
||||||
private int accelerationCooldownTicks;
|
private int accelerationCooldownTicks;
|
||||||
private int accelerationTicks;
|
|
||||||
private int blackHoleCooldownTicks;
|
private int blackHoleCooldownTicks;
|
||||||
private int idleWanderCooldownTicks;
|
private int idleWanderCooldownTicks;
|
||||||
|
private int finalTimeControlTicks;
|
||||||
|
private final RoyalEffectController royalEffects = new RoyalEffectController();
|
||||||
private final Map<UUID, Vec3> frozenVelocities = new HashMap<>();
|
private final Map<UUID, Vec3> frozenVelocities = new HashMap<>();
|
||||||
|
|
||||||
public QueenEntity(EntityType<? extends QueenEntity> entityType, Level level) {
|
public QueenEntity(EntityType<? extends QueenEntity> entityType, Level level) {
|
||||||
@@ -85,7 +86,12 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isFlyingBoss() {
|
protected boolean isFlyingBoss() {
|
||||||
return false;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SoundEvent royalFlyLoopSound() {
|
||||||
|
return AntarchySoundEvents.QUEEN_FLY_LOOP.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -128,7 +134,7 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
@Override
|
@Override
|
||||||
protected RoyalBeamSettings royalBeamSettings() {
|
protected RoyalBeamSettings royalBeamSettings() {
|
||||||
return new RoyalBeamSettings(AntarchySettings.queenBeamRange(), AntarchySettings.queenBeamTracking(), 7.5D,
|
return new RoyalBeamSettings(AntarchySettings.queenBeamRange(), AntarchySettings.queenBeamTracking(), 7.5D,
|
||||||
AntarchySettings.queenBeamDurationTicks(), AntarchySettings.queenBeamCooldownTicks(), 6.0F, 6.0F,
|
AntarchySettings.queenBeamDurationTicks(), AntarchySettings.queenBeamTravelTicks(), AntarchySettings.queenBeamCooldownTicks(), 6.0F, 6.0F,
|
||||||
(float) AntarchySettings.queenBeamDamage(), 1.0F, 3, 100.0D,
|
(float) AntarchySettings.queenBeamDamage(), 1.0F, 3, 100.0D,
|
||||||
(float) AntarchySettings.queenBeamTerrainRadius(), 4.0F, AntarchySettings.queenBeamTerrainCap(),
|
(float) AntarchySettings.queenBeamTerrainRadius(), 4.0F, AntarchySettings.queenBeamTerrainCap(),
|
||||||
1.0F, 0.08F, 15.0F, true, true);
|
1.0F, 0.08F, 15.0F, true, true);
|
||||||
@@ -156,9 +162,8 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
}
|
}
|
||||||
this.tickManticoreSummon();
|
this.tickManticoreSummon();
|
||||||
this.tickQueenAbilities();
|
this.tickQueenAbilities();
|
||||||
this.tickRoyalAcceleration();
|
this.tickFinalTimeControl();
|
||||||
this.tickMomentumLock();
|
this.royalEffects.tick();
|
||||||
this.tickCrushingGravity();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tickIdleWander() {
|
private void tickIdleWander() {
|
||||||
@@ -174,7 +179,7 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int cooldown(int base) {
|
private int cooldown(int base) {
|
||||||
return this.accelerationTicks > 0 ? Math.max(20, base / 2) : base;
|
return this.royalEffects.active("acceleration") ? Math.max(20, base / 2) : base;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tickManticoreSummon() {
|
private void tickManticoreSummon() {
|
||||||
@@ -205,7 +210,7 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
: FAILED_SUMMON_RETRY_TICKS;
|
: FAILED_SUMMON_RETRY_TICKS;
|
||||||
if (spawned > 0) {
|
if (spawned > 0) {
|
||||||
this.triggerAnim("body_action", "minion_spawn");
|
this.triggerAnim("body_action", "minion_spawn");
|
||||||
this.playSound(AntarchySoundEvents.QUEEN_ROAR.get(), 3.0F, 0.8F + this.random.nextFloat() * 0.12F);
|
this.playRoyalSound(AntarchySoundEvents.QUEEN_ROAR.get(), 0.8F + this.random.nextFloat() * 0.12F);
|
||||||
serverLevel.sendParticles(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);
|
36, 3.0D, 2.0D, 3.0D, 0.15D);
|
||||||
}
|
}
|
||||||
@@ -249,40 +254,97 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Phase phase = this.phase();
|
Phase phase = this.phase();
|
||||||
boolean majorBusy = this.momentumLockTicks > 0 || this.crushingGravityTicks > 0;
|
boolean majorBusy = this.royalEffects.active("momentum_lock") || this.royalEffects.active("crushing_gravity");
|
||||||
boolean allowOverlap = phase != Phase.ONE;
|
boolean allowOverlap = phase != Phase.ONE;
|
||||||
|
String[] candidates = phase == Phase.ONE
|
||||||
if (this.gravityStompCooldownTicks <= 0 && (allowOverlap || !majorBusy)) {
|
? new String[] {"gravity_stomp", "time_field", "black_hole"}
|
||||||
this.gravityStompCooldownTicks = this.cooldown(GRAVITY_STOMP_COOLDOWN);
|
: new String[] {"gravity_stomp", "time_field", "black_hole", "momentum_lock", "crushing_gravity", "acceleration"};
|
||||||
this.performGravityStomp(level, target);
|
String selected = this.attackScheduler.chooseWeighted(candidates, id -> {
|
||||||
|
if (!this.queenAttackReady(id, phase, majorBusy, allowOverlap)) return 0;
|
||||||
|
return switch (id) {
|
||||||
|
case "black_hole", "crushing_gravity" -> phase == Phase.THREE ? 5 : 3;
|
||||||
|
case "momentum_lock", "acceleration" -> phase == Phase.THREE ? 4 : 2;
|
||||||
|
default -> 4;
|
||||||
|
};
|
||||||
|
}, this.random);
|
||||||
|
if (selected == null) return;
|
||||||
|
int cooldown = switch (selected) {
|
||||||
|
case "gravity_stomp" -> GRAVITY_STOMP_COOLDOWN;
|
||||||
|
case "time_field" -> TIME_FIELD_COOLDOWN;
|
||||||
|
case "black_hole" -> BLACK_HOLE_COOLDOWN;
|
||||||
|
case "momentum_lock" -> MOMENTUM_LOCK_COOLDOWN;
|
||||||
|
case "crushing_gravity" -> CRUSHING_GRAVITY_COOLDOWN;
|
||||||
|
default -> ACCELERATION_COOLDOWN;
|
||||||
|
};
|
||||||
|
if (!this.beginRoyalAttack(selected, RoyalAttackLane.HAZARD, this.cooldown(cooldown),
|
||||||
|
10, 1, 14, new com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler.Action() {
|
||||||
|
@Override public void onStart() {
|
||||||
|
if ("gravity_stomp".equals(selected)) {
|
||||||
|
QueenEntity.this.triggerAnim("body_action", "stomp");
|
||||||
|
} else {
|
||||||
|
QueenEntity.this.triggerAnim("body_action", "wing_gust");
|
||||||
}
|
}
|
||||||
if (this.timeFieldCooldownTicks <= 0 && (allowOverlap || !majorBusy)) {
|
}
|
||||||
this.timeFieldCooldownTicks = this.cooldown(TIME_FIELD_COOLDOWN);
|
@Override public void onActive(int elapsedTicks) {
|
||||||
|
QueenEntity.this.performSelectedQueenAttack(selected, phase, cooldown, level, target);
|
||||||
|
}
|
||||||
|
})) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performSelectedQueenAttack(String selected, Phase phase, int cooldown,
|
||||||
|
ServerLevel level, LivingEntity target) {
|
||||||
|
switch (selected) {
|
||||||
|
case "gravity_stomp" -> { this.gravityStompCooldownTicks = cooldown; this.performGravityStomp(level, target); }
|
||||||
|
case "time_field" -> {
|
||||||
|
this.timeFieldCooldownTicks = cooldown;
|
||||||
double fieldRate = phase == Phase.THREE ? 0.1D : 0.4D;
|
double fieldRate = phase == Phase.THREE ? 0.1D : 0.4D;
|
||||||
TimeDilationApi.createField(level, target.position(), 12.0D, fieldRate, 140 + phase.ordinal() * 40);
|
TimeDilationApi.createField(level, target.position(), 12.0D, fieldRate, 140 + phase.ordinal() * 40);
|
||||||
this.triggerAnim("body_action", "wing_gust");
|
|
||||||
}
|
}
|
||||||
if (this.blackHoleCooldownTicks <= 0 && (allowOverlap || !majorBusy)) {
|
case "black_hole" -> { this.blackHoleCooldownTicks = cooldown; this.castBlackHole(level, target); }
|
||||||
this.blackHoleCooldownTicks = this.cooldown(BLACK_HOLE_COOLDOWN);
|
case "momentum_lock" -> { this.momentumLockCooldownTicks = cooldown; this.startMomentumLock(level); }
|
||||||
this.castBlackHole(level, target);
|
case "crushing_gravity" -> {
|
||||||
|
this.crushingGravityCooldownTicks = cooldown;
|
||||||
|
this.royalEffects.start("crushing_gravity", CRUSHING_GRAVITY_DURATION,
|
||||||
|
() -> {}, this::tickCrushingGravity, () -> {});
|
||||||
|
this.playRoyalSound(AntarchySoundEvents.QUEEN_ROAR.get(), 0.6F);
|
||||||
}
|
}
|
||||||
if (this.momentumLockTicks <= 0 && this.momentumLockCooldownTicks <= 0 && (allowOverlap || !majorBusy)) {
|
case "acceleration" -> { this.accelerationCooldownTicks = cooldown; this.startRoyalAcceleration(); }
|
||||||
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))) {
|
private boolean queenAttackReady(String id, Phase phase, boolean majorBusy, boolean allowOverlap) {
|
||||||
|
if (!allowOverlap && majorBusy) return false;
|
||||||
|
return switch (id) {
|
||||||
|
case "gravity_stomp" -> this.gravityStompCooldownTicks <= 0;
|
||||||
|
case "time_field" -> this.timeFieldCooldownTicks <= 0;
|
||||||
|
case "black_hole" -> this.blackHoleCooldownTicks <= 0;
|
||||||
|
case "momentum_lock" -> !this.royalEffects.active("momentum_lock") && this.momentumLockCooldownTicks <= 0;
|
||||||
|
case "crushing_gravity" -> phase != Phase.ONE && !this.royalEffects.active("crushing_gravity") && this.crushingGravityCooldownTicks <= 0;
|
||||||
|
case "acceleration" -> phase == Phase.THREE && !this.royalEffects.active("acceleration") && this.accelerationCooldownTicks <= 0;
|
||||||
|
default -> false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tickFinalTimeControl() {
|
||||||
|
if (this.phase() != Phase.THREE || !(this.level() instanceof ServerLevel level)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.royalEffects.active("acceleration") && this.accelerationCooldownTicks <= 0) {
|
||||||
this.startRoyalAcceleration();
|
this.startRoyalAcceleration();
|
||||||
}
|
}
|
||||||
|
if (this.finalTimeControlTicks-- <= 0) {
|
||||||
|
this.finalTimeControlTicks = AntarchySettings.queenFinalTimeFieldCooldownTicks();
|
||||||
|
LivingEntity target = this.getTarget();
|
||||||
|
if (target != null && target.isAlive()) {
|
||||||
|
TimeDilationApi.createField(level, target.position(), AntarchySettings.queenFinalTimeFieldRadius(),
|
||||||
|
AntarchySettings.queenFinalTimeFieldRate(), AntarchySettings.queenFinalTimeFieldDurationTicks());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void performGravityStomp(ServerLevel level, LivingEntity target) {
|
private void performGravityStomp(ServerLevel level, LivingEntity target) {
|
||||||
this.triggerAnim("body_action", "stomp");
|
this.triggerAnim("body_action", "stomp");
|
||||||
this.playSound(AntarchySoundEvents.QUEEN_ROAR.get(), 3.0F, 0.7F);
|
this.playRoyalSound(AntarchySoundEvents.QUEEN_ROAR.get(), 0.7F);
|
||||||
DamageSource source = this.damageSources().mobAttack(this);
|
DamageSource source = this.damageSources().mobAttack(this);
|
||||||
for (LivingEntity living : level.getEntitiesOfClass(LivingEntity.class,
|
for (LivingEntity living : level.getEntitiesOfClass(LivingEntity.class,
|
||||||
this.getBoundingBox().inflate(18.0D), entity -> entity instanceof Player && entity.isAlive())) {
|
this.getBoundingBox().inflate(18.0D), entity -> entity instanceof Player && entity.isAlive())) {
|
||||||
@@ -303,16 +365,14 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
RoyalBlackHoleEntity hole = RoyalBlackHoleEntity.create(level, anchor, this.getUUID());
|
RoyalBlackHoleEntity hole = RoyalBlackHoleEntity.create(level, anchor, this.getUUID());
|
||||||
level.addFreshEntity(hole);
|
level.addFreshEntity(hole);
|
||||||
this.triggerAnim("body_action", "wing_gust");
|
this.triggerAnim("body_action", "wing_gust");
|
||||||
this.playSound(AntarchySoundEvents.QUEEN_ROAR.get(), 3.0F, 1.15F);
|
this.playRoyalSound(AntarchySoundEvents.QUEEN_ROAR.get(), 1.0F);
|
||||||
level.sendParticles(ParticleTypes.REVERSE_PORTAL, anchor.x, anchor.y, anchor.z, 60, 1.0D, 1.0D, 1.0D, 0.4D);
|
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) {
|
private void startMomentumLock(ServerLevel level) {
|
||||||
this.momentumLockCooldownTicks = MOMENTUM_LOCK_COOLDOWN;
|
this.momentumLockCooldownTicks = MOMENTUM_LOCK_COOLDOWN;
|
||||||
this.momentumLockTicks = MOMENTUM_LOCK_DURATION;
|
this.royalEffects.start("momentum_lock", MOMENTUM_LOCK_DURATION, () -> {
|
||||||
this.frozenVelocities.clear();
|
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,
|
for (Entity entity : level.getEntitiesOfClass(Entity.class,
|
||||||
this.getBoundingBox().inflate(MOMENTUM_LOCK_RADIUS))) {
|
this.getBoundingBox().inflate(MOMENTUM_LOCK_RADIUS))) {
|
||||||
if (entity == this || isFieldImmune(entity) || entity instanceof Player player && player.isCreative()) {
|
if (entity == this || isFieldImmune(entity) || entity instanceof Player player && player.isCreative()) {
|
||||||
@@ -320,13 +380,21 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
}
|
}
|
||||||
this.frozenVelocities.put(entity.getUUID(), entity.getDeltaMovement());
|
this.frozenVelocities.put(entity.getUUID(), entity.getDeltaMovement());
|
||||||
}
|
}
|
||||||
|
}, this::tickMomentumLockEffect, () -> {
|
||||||
|
for (Map.Entry<UUID, Vec3> entry : this.frozenVelocities.entrySet()) {
|
||||||
|
Entity entity = level.getEntity(entry.getKey());
|
||||||
|
if (entity != null && entity.isAlive()) {
|
||||||
|
entity.setDeltaMovement(entry.getValue());
|
||||||
|
entity.hasImpulse = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.frozenVelocities.clear();
|
||||||
|
});
|
||||||
|
this.triggerAnim("body_action", "wing_gust");
|
||||||
|
this.playRoyalSound(AntarchySoundEvents.QUEEN_ROAR.get(), 0.5F);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tickMomentumLock() {
|
private void tickMomentumLockEffect() {
|
||||||
if (this.momentumLockTicks <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.momentumLockTicks--;
|
|
||||||
if (!(this.level() instanceof ServerLevel level)) {
|
if (!(this.level() instanceof ServerLevel level)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -335,29 +403,20 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
if (entity == null || !entity.isAlive()) {
|
if (entity == null || !entity.isAlive()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (this.momentumLockTicks <= 0) {
|
|
||||||
entity.setDeltaMovement(entry.getValue());
|
|
||||||
entity.hasImpulse = true;
|
|
||||||
} else {
|
|
||||||
entity.setDeltaMovement(Vec3.ZERO);
|
entity.setDeltaMovement(Vec3.ZERO);
|
||||||
entity.fallDistance = 0.0F;
|
entity.fallDistance = 0.0F;
|
||||||
entity.hasImpulse = true;
|
entity.hasImpulse = true;
|
||||||
if (this.tickCount % 6 == 0 && level instanceof ServerLevel serverLevel) {
|
if (this.tickCount % 6 == 0) {
|
||||||
serverLevel.sendParticles(ParticleTypes.END_ROD, entity.getX(), entity.getY() + entity.getBbHeight() * 0.5D, entity.getZ(),
|
level.sendParticles(ParticleTypes.END_ROD, entity.getX(), entity.getY() + entity.getBbHeight() * 0.5D, entity.getZ(),
|
||||||
2, 0.2D, 0.2D, 0.2D, 0.0D);
|
2, 0.2D, 0.2D, 0.2D, 0.0D);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.momentumLockTicks <= 0) {
|
|
||||||
this.frozenVelocities.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void tickCrushingGravity() {
|
private void tickCrushingGravity() {
|
||||||
if (this.crushingGravityTicks <= 0) {
|
if (!this.royalEffects.active("crushing_gravity")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.crushingGravityTicks--;
|
|
||||||
if (!(this.level() instanceof ServerLevel level)) {
|
if (!(this.level() instanceof ServerLevel level)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -378,11 +437,16 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
|
|
||||||
private void startRoyalAcceleration() {
|
private void startRoyalAcceleration() {
|
||||||
this.accelerationCooldownTicks = ACCELERATION_COOLDOWN;
|
this.accelerationCooldownTicks = ACCELERATION_COOLDOWN;
|
||||||
this.accelerationTicks = ACCELERATION_DURATION;
|
this.royalEffects.start("acceleration", ACCELERATION_DURATION, () -> {
|
||||||
this.setRoyalAccelerated(true);
|
this.setRoyalAccelerated(true);
|
||||||
this.playSound(AntarchySoundEvents.QUEEN_ROAR.get(), 3.5F, 1.4F);
|
this.playRoyalSound(AntarchySoundEvents.QUEEN_ROAR.get(), 1.4F);
|
||||||
applyAccelModifier(this.getAttribute(Attributes.MOVEMENT_SPEED), ACCEL_SPEED_ID);
|
applyAccelModifier(this.getAttribute(Attributes.MOVEMENT_SPEED), ACCEL_SPEED_ID);
|
||||||
applyAccelModifier(this.getAttribute(Attributes.FLYING_SPEED), ACCEL_FLY_ID);
|
applyAccelModifier(this.getAttribute(Attributes.FLYING_SPEED), ACCEL_FLY_ID);
|
||||||
|
}, this::tickRoyalAccelerationEffect, () -> {
|
||||||
|
this.setRoyalAccelerated(false);
|
||||||
|
removeAccelModifier(this.getAttribute(Attributes.MOVEMENT_SPEED), ACCEL_SPEED_ID);
|
||||||
|
removeAccelModifier(this.getAttribute(Attributes.FLYING_SPEED), ACCEL_FLY_ID);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void applyAccelModifier(AttributeInstance attribute, ResourceLocation id) {
|
private static void applyAccelModifier(AttributeInstance attribute, ResourceLocation id) {
|
||||||
@@ -398,16 +462,10 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tickRoyalAcceleration() {
|
private void tickRoyalAccelerationEffect() {
|
||||||
if (this.accelerationTicks <= 0) {
|
if (!this.isRoyalAccelerated()) {
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
this.accelerationTicks--;
|
|
||||||
if (this.level() instanceof ServerLevel level && this.tickCount % 2 == 0) {
|
if (this.level() instanceof ServerLevel level && this.tickCount % 2 == 0) {
|
||||||
level.sendParticles(ACCEL_DUST,
|
level.sendParticles(ACCEL_DUST,
|
||||||
this.getX() + (this.random.nextDouble() - 0.5D) * this.getBbWidth(),
|
this.getX() + (this.random.nextDouble() - 0.5D) * this.getBbWidth(),
|
||||||
@@ -415,11 +473,6 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
this.getZ() + (this.random.nextDouble() - 0.5D) * this.getBbWidth(),
|
this.getZ() + (this.random.nextDouble() - 0.5D) * this.getBbWidth(),
|
||||||
6, 0.4D, 0.6D, 0.4D, 0.02D);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -427,6 +480,8 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
if (!this.level().isClientSide && this.level() instanceof ServerLevel level) {
|
if (!this.level().isClientSide && this.level() instanceof ServerLevel level) {
|
||||||
DimensionalTearEntity.discardQueenOwnedTears(level, this.getUUID());
|
DimensionalTearEntity.discardQueenOwnedTears(level, this.getUUID());
|
||||||
}
|
}
|
||||||
|
this.royalEffects.clear();
|
||||||
|
this.frozenVelocities.clear();
|
||||||
removeAccelModifier(this.getAttribute(Attributes.MOVEMENT_SPEED), ACCEL_SPEED_ID);
|
removeAccelModifier(this.getAttribute(Attributes.MOVEMENT_SPEED), ACCEL_SPEED_ID);
|
||||||
removeAccelModifier(this.getAttribute(Attributes.FLYING_SPEED), ACCEL_FLY_ID);
|
removeAccelModifier(this.getAttribute(Attributes.FLYING_SPEED), ACCEL_FLY_ID);
|
||||||
super.die(damageSource);
|
super.die(damageSource);
|
||||||
@@ -468,8 +523,6 @@ public class QueenEntity extends RoyalBossEntity {
|
|||||||
tag.putInt(SUMMON_COOLDOWN_KEY, this.manticoreSummonCooldownTicks);
|
tag.putInt(SUMMON_COOLDOWN_KEY, this.manticoreSummonCooldownTicks);
|
||||||
tag.putInt("GravityStompCooldownTicks", this.gravityStompCooldownTicks);
|
tag.putInt("GravityStompCooldownTicks", this.gravityStompCooldownTicks);
|
||||||
tag.putInt("TimeFieldCooldownTicks", this.timeFieldCooldownTicks);
|
tag.putInt("TimeFieldCooldownTicks", this.timeFieldCooldownTicks);
|
||||||
tag.putInt("MomentumLockCooldownTicks", this.momentumLockCooldownTicks);
|
|
||||||
tag.putInt("CrushingGravityCooldownTicks", this.crushingGravityCooldownTicks);
|
|
||||||
tag.putInt("AccelerationCooldownTicks", this.accelerationCooldownTicks);
|
tag.putInt("AccelerationCooldownTicks", this.accelerationCooldownTicks);
|
||||||
tag.putInt("BlackHoleCooldownTicks", this.blackHoleCooldownTicks);
|
tag.putInt("BlackHoleCooldownTicks", this.blackHoleCooldownTicks);
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-5
@@ -1,6 +1,8 @@
|
|||||||
package com.craisinlord.antarchy.content.entity.royal;
|
package com.craisinlord.antarchy.content.entity.royal;
|
||||||
|
|
||||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
||||||
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import net.minecraft.core.particles.ParticleTypes;
|
import net.minecraft.core.particles.ParticleTypes;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
@@ -17,8 +19,16 @@ import net.minecraft.world.level.Level;
|
|||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import software.bernie.geckolib.animatable.GeoEntity;
|
||||||
|
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
||||||
|
import software.bernie.geckolib.animation.AnimatableManager;
|
||||||
|
import software.bernie.geckolib.animation.AnimationController;
|
||||||
|
import software.bernie.geckolib.animation.AnimationState;
|
||||||
|
import software.bernie.geckolib.animation.PlayState;
|
||||||
|
import software.bernie.geckolib.animation.RawAnimation;
|
||||||
|
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||||
|
|
||||||
public class RoyalBlackHoleEntity extends Entity {
|
public class RoyalBlackHoleEntity extends Entity implements GeoEntity {
|
||||||
private static final EntityDataAccessor<Float> RADIUS =
|
private static final EntityDataAccessor<Float> RADIUS =
|
||||||
SynchedEntityData.defineId(RoyalBlackHoleEntity.class, EntityDataSerializers.FLOAT);
|
SynchedEntityData.defineId(RoyalBlackHoleEntity.class, EntityDataSerializers.FLOAT);
|
||||||
private static final EntityDataAccessor<Boolean> COLLAPSING =
|
private static final EntityDataAccessor<Boolean> COLLAPSING =
|
||||||
@@ -36,6 +46,7 @@ public class RoyalBlackHoleEntity extends Entity {
|
|||||||
private UUID ownerId;
|
private UUID ownerId;
|
||||||
private int age;
|
private int age;
|
||||||
private int activeTicks = DEFAULT_ACTIVE_TICKS;
|
private int activeTicks = DEFAULT_ACTIVE_TICKS;
|
||||||
|
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
|
|
||||||
public RoyalBlackHoleEntity(EntityType<? extends RoyalBlackHoleEntity> entityType, Level level) {
|
public RoyalBlackHoleEntity(EntityType<? extends RoyalBlackHoleEntity> entityType, Level level) {
|
||||||
super(entityType, level);
|
super(entityType, level);
|
||||||
@@ -46,14 +57,14 @@ public class RoyalBlackHoleEntity extends Entity {
|
|||||||
public static RoyalBlackHoleEntity create(ServerLevel level, Vec3 center, double radius, int activeTicks, @Nullable UUID ownerId) {
|
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);
|
RoyalBlackHoleEntity hole = new RoyalBlackHoleEntity(AntarchyObjects.ROYAL_BLACK_HOLE.get(), level);
|
||||||
hole.setPos(center.x, center.y, center.z);
|
hole.setPos(center.x, center.y, center.z);
|
||||||
hole.setRadius(radius);
|
hole.setRadius(radius > 0.0D ? radius : AntarchySettings.queenBlackHoleRadius());
|
||||||
hole.activeTicks = Math.max(20, activeTicks);
|
hole.activeTicks = activeTicks > 0 ? Math.max(20, activeTicks) : AntarchySettings.queenBlackHoleActiveTicks();
|
||||||
hole.ownerId = ownerId;
|
hole.ownerId = ownerId;
|
||||||
return hole;
|
return hole;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RoyalBlackHoleEntity create(ServerLevel level, Vec3 center, @Nullable UUID ownerId) {
|
public static RoyalBlackHoleEntity create(ServerLevel level, Vec3 center, @Nullable UUID ownerId) {
|
||||||
return create(level, center, DEFAULT_RADIUS, DEFAULT_ACTIVE_TICKS, ownerId);
|
return create(level, center, AntarchySettings.queenBlackHoleRadius(), AntarchySettings.queenBlackHoleActiveTicks(), ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -84,6 +95,12 @@ public class RoyalBlackHoleEntity extends Entity {
|
|||||||
this.age++;
|
this.age++;
|
||||||
if (!this.isCollapsing()) {
|
if (!this.isCollapsing()) {
|
||||||
this.applyPull();
|
this.applyPull();
|
||||||
|
if (this.age % 10 == 0 && this.level() instanceof ServerLevel level) {
|
||||||
|
TimeDilationApi.createField(level, this.position(), Math.max(2.0D, this.radius() * 0.55D), 0.18D, 14);
|
||||||
|
if (this.age % 20 == 0 && level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
|
||||||
|
RoyalBlockDestruction.destroySphere(level, this, this.position(), Math.min(2.0D, this.radius() * 0.2D), 8, 30.0D, 0.0F);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (this.age >= this.activeTicks) {
|
if (this.age >= this.activeTicks) {
|
||||||
this.entityData.set(COLLAPSING, true);
|
this.entityData.set(COLLAPSING, true);
|
||||||
this.age = 0;
|
this.age = 0;
|
||||||
@@ -108,7 +125,7 @@ public class RoyalBlackHoleEntity extends Entity {
|
|||||||
if (distance < 0.5D || distance > radius) {
|
if (distance < 0.5D || distance > radius) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
double strength = 0.16D * (1.0D - distance / radius);
|
double strength = AntarchySettings.queenBlackHolePullStrength() * (1.0D - distance / radius);
|
||||||
Vec3 pull = toCenter.scale(strength / distance);
|
Vec3 pull = toCenter.scale(strength / distance);
|
||||||
entity.setDeltaMovement(entity.getDeltaMovement().scale(0.86D).add(pull));
|
entity.setDeltaMovement(entity.getDeltaMovement().scale(0.86D).add(pull));
|
||||||
entity.hasImpulse = true;
|
entity.hasImpulse = true;
|
||||||
@@ -201,4 +218,18 @@ public class RoyalBlackHoleEntity extends Entity {
|
|||||||
tag.putUUID(OWNER_KEY, this.ownerId);
|
tag.putUUID(OWNER_KEY, this.ownerId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
|
||||||
|
controllers.add(new AnimationController<>(this, "black_hole_controller", 0, this::blackHoleController));
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlayState blackHoleController(AnimationState<RoyalBlackHoleEntity> state) {
|
||||||
|
return state.setAndContinue(RawAnimation.begin().thenLoop("animation"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnimatableInstanceCache getAnimatableInstanceCache() {
|
||||||
|
return this.geoCache;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+148
-32
@@ -8,6 +8,10 @@ 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.RoyalBeamSettings;
|
||||||
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamTerrainMode;
|
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.beam.RoyalBeamElement;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackLane;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.attack.RoyalAttackScheduler;
|
||||||
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||||
|
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||||
@@ -89,6 +93,11 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
private static final int CRUSH_MAX_BLOCKS = 24;
|
private static final int CRUSH_MAX_BLOCKS = 24;
|
||||||
private static final double CRUSH_MAX_RESISTANCE = 60.0D;
|
private static final double CRUSH_MAX_RESISTANCE = 60.0D;
|
||||||
private static final float CRUSH_DROP_CHANCE = 0.1F;
|
private static final float CRUSH_DROP_CHANCE = 0.1F;
|
||||||
|
private static final int OBSTRUCTION_CLEAR_INTERVAL_TICKS = 5;
|
||||||
|
private static final double OBSTRUCTION_CLEAR_RADIUS = 3.5D;
|
||||||
|
private static final int OBSTRUCTION_CLEAR_MAX_BLOCKS = 24;
|
||||||
|
private static final double OBSTRUCTION_CLEAR_MAX_RESISTANCE = 60.0D;
|
||||||
|
private static final float OBSTRUCTION_CLEAR_DROP_CHANCE = 0.1F;
|
||||||
|
|
||||||
protected static final double FLYING_MIN_HOVER = 2.5D;
|
protected static final double FLYING_MIN_HOVER = 2.5D;
|
||||||
protected static final double FLYING_PREFERRED_HOVER = 6.0D;
|
protected static final double FLYING_PREFERRED_HOVER = 6.0D;
|
||||||
@@ -116,6 +125,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
|
|
||||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
protected final RoyalBeamController beamController = new RoyalBeamController(this);
|
protected final RoyalBeamController beamController = new RoyalBeamController(this);
|
||||||
|
protected final RoyalAttackScheduler attackScheduler = new RoyalAttackScheduler();
|
||||||
private final ServerBossEvent bossEvent;
|
private final ServerBossEvent bossEvent;
|
||||||
private final RoyalHead[] heads = {
|
private final RoyalHead[] heads = {
|
||||||
new RoyalHead(RoyalHead.Slot.LEFT),
|
new RoyalHead(RoyalHead.Slot.LEFT),
|
||||||
@@ -127,6 +137,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
private RoyalHead activeBeamHead;
|
private RoyalHead activeBeamHead;
|
||||||
private int beamLoopSoundTicks;
|
private int beamLoopSoundTicks;
|
||||||
private int beamHeadCursor;
|
private int beamHeadCursor;
|
||||||
|
private boolean beamStarted;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Entity[] multipartParts;
|
private Entity[] multipartParts;
|
||||||
@@ -152,6 +163,11 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
|
|
||||||
protected abstract SoundEvent royalDeathSound();
|
protected abstract SoundEvent royalDeathSound();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
protected SoundEvent royalFlyLoopSound() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract SoundEvent royalBiteSound();
|
protected abstract SoundEvent royalBiteSound();
|
||||||
|
|
||||||
protected abstract SoundEvent royalBeamShootSound();
|
protected abstract SoundEvent royalBeamShootSound();
|
||||||
@@ -275,7 +291,11 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected float getSoundVolume() {
|
protected float getSoundVolume() {
|
||||||
return 2.5F;
|
return (float) AntarchySettings.royalBossSoundVolume();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void playRoyalSound(SoundEvent sound, float pitch) {
|
||||||
|
this.playSound(sound, (float) AntarchySettings.royalBossSoundVolume(), pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -292,8 +312,21 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
super.tick();
|
super.tick();
|
||||||
|
if (!this.level().isClientSide
|
||||||
|
&& !this.isDeadOrDying()
|
||||||
|
&& this.tickCount % OBSTRUCTION_CLEAR_INTERVAL_TICKS == 0
|
||||||
|
&& this.isInWall()) {
|
||||||
|
RoyalBlockDestruction.destroySphere(
|
||||||
|
(ServerLevel) this.level(),
|
||||||
|
this,
|
||||||
|
this.position().add(0.0D, this.getBbHeight() * 0.5D, 0.0D),
|
||||||
|
OBSTRUCTION_CLEAR_RADIUS,
|
||||||
|
OBSTRUCTION_CLEAR_MAX_BLOCKS,
|
||||||
|
OBSTRUCTION_CLEAR_MAX_RESISTANCE,
|
||||||
|
OBSTRUCTION_CLEAR_DROP_CHANCE);
|
||||||
|
}
|
||||||
if (this.isFlyingBoss()) {
|
if (this.isFlyingBoss()) {
|
||||||
this.setNoGravity(true);
|
this.setNoGravity(!AntarchyGravityApi.isGravityInverted(this));
|
||||||
}
|
}
|
||||||
if (this.level().isClientSide) {
|
if (this.level().isClientSide) {
|
||||||
return;
|
return;
|
||||||
@@ -303,9 +336,10 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth());
|
this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth());
|
||||||
|
this.attackScheduler.tick();
|
||||||
|
|
||||||
for (RoyalHead head : this.heads) {
|
if (this.isFlyingBoss() && this.tickCount % 40 == 0 && this.royalFlyLoopSound() != null) {
|
||||||
head.tick();
|
this.playRoyalSound(this.royalFlyLoopSound(), 0.92F + this.random.nextFloat() * 0.12F);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isDeadOrDying()) {
|
if (this.isDeadOrDying()) {
|
||||||
@@ -326,16 +360,10 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
this.steerTowardTarget(primaryTarget);
|
this.steerTowardTarget(primaryTarget);
|
||||||
this.tickBodyCrush();
|
this.tickBodyCrush();
|
||||||
|
|
||||||
for (RoyalHead head : this.heads) {
|
|
||||||
if (head.tickBiteHit()) {
|
|
||||||
this.applyBiteHit(head);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Phase phase = this.phase();
|
Phase phase = this.phase();
|
||||||
int activeHeadAttacks = 0;
|
int activeHeadAttacks = 0;
|
||||||
for (RoyalHead head : this.heads) {
|
for (RoyalHead head : this.heads) {
|
||||||
if (head.busy()) {
|
if (this.attackScheduler.laneBusy(this.headLane(head))) {
|
||||||
activeHeadAttacks++;
|
activeHeadAttacks++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -344,7 +372,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
if (activeHeadAttacks >= phase.maxConcurrentHeadAttacks()) {
|
if (activeHeadAttacks >= phase.maxConcurrentHeadAttacks()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!head.readyToAttack()) {
|
if (!head.readyToAttack() || this.attackScheduler.laneBusy(this.headLane(head))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
LivingEntity headTarget = head.target(this.level());
|
LivingEntity headTarget = head.target(this.level());
|
||||||
@@ -355,8 +383,14 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInvulnerableTo(DamageSource source) {
|
||||||
|
return source.is(net.minecraft.world.damagesource.DamageTypes.IN_WALL)
|
||||||
|
|| super.isInvulnerableTo(source);
|
||||||
|
}
|
||||||
|
|
||||||
private void tickRoyalBeam(LivingEntity primaryTarget) {
|
private void tickRoyalBeam(LivingEntity primaryTarget) {
|
||||||
if (this.beamCooldownTicks > 0) {
|
if (this.beamCooldownTicks > 0 || this.attackScheduler.laneBusy(this.beamLane())) {
|
||||||
this.beamCooldownTicks--;
|
this.beamCooldownTicks--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,10 +398,12 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
LivingEntity beamTarget = this.activeBeamHead.target(this.level());
|
LivingEntity beamTarget = this.activeBeamHead.target(this.level());
|
||||||
if (!this.activeBeamHead.shooting() || beamTarget == null || !beamTarget.isAlive()) {
|
if (!this.activeBeamHead.shooting() || beamTarget == null || !beamTarget.isAlive()) {
|
||||||
this.stopRoyalBeam();
|
this.stopRoyalBeam();
|
||||||
|
} else if (!this.beamStarted) {
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (this.beamLoopSoundTicks-- <= 0) {
|
if (this.beamLoopSoundTicks-- <= 0) {
|
||||||
this.beamLoopSoundTicks = 20;
|
this.beamLoopSoundTicks = 20;
|
||||||
this.playSound(this.royalBeamLoopSound(), 2.5F, 1.0F);
|
this.playRoyalSound(this.royalBeamLoopSound(), 1.0F);
|
||||||
}
|
}
|
||||||
this.beamController.tick(
|
this.beamController.tick(
|
||||||
this.headAnchor(this.activeBeamHead),
|
this.headAnchor(this.activeBeamHead),
|
||||||
@@ -393,24 +429,56 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
for (int offset = 0; offset < this.heads.length; offset++) {
|
for (int offset = 0; offset < this.heads.length; offset++) {
|
||||||
RoyalHead head = this.heads[(this.beamHeadCursor + offset) % this.heads.length];
|
RoyalHead head = this.heads[(this.beamHeadCursor + offset) % this.heads.length];
|
||||||
LivingEntity target = head.target(this.level());
|
LivingEntity target = head.target(this.level());
|
||||||
if (!head.readyToAttack() || target == null || !this.canAttack(target)
|
if (!head.readyToAttack() || this.attackScheduler.laneBusy(this.headLane(head))
|
||||||
|
|| target == null || !this.canAttack(target)
|
||||||
|| this.headWithinBiteReach(head, target)) {
|
|| this.headWithinBiteReach(head, target)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int duration = Math.max(1, this.royalBeamSettings().durationTicks());
|
RoyalBeamSettings beamSettings = this.royalBeamSettings();
|
||||||
int cooldown = Math.max(1, Mth.floor(this.royalBeamSettings().cooldownTicks() * phase.cooldownScale()));
|
int duration = Math.max(1, beamSettings.durationTicks());
|
||||||
head.startShoot(duration, cooldown);
|
int cooldown = Math.max(1, Mth.floor(beamSettings.cooldownTicks() * phase.cooldownScale()));
|
||||||
|
int windup = Math.max(0, AntarchySettings.queenBeamWindupTicks());
|
||||||
|
if (this instanceof KingEntity) {
|
||||||
|
windup = Math.max(0, AntarchySettings.kingBeamWindupTicks());
|
||||||
|
}
|
||||||
|
LivingEntity committedTarget = target;
|
||||||
|
if (!this.attackScheduler.start("beam_" + head.slot().name(), this.beamLane(), cooldown,
|
||||||
|
windup, duration, 8, new RoyalAttackScheduler.Action() {
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
head.startShoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActive(int elapsedTicks) {
|
||||||
|
if (elapsedTicks != 0 || RoyalBossEntity.this.beamStarted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RoyalBossEntity.this.beamStarted = true;
|
||||||
|
RoyalBossEntity.this.beamController.start(
|
||||||
|
RoyalBossEntity.this.headAnchor(head), committedTarget.getEyePosition(), duration);
|
||||||
|
RoyalBossEntity.this.entityData.set(BEAM_ELEMENT, RoyalBossEntity.this.royalBeamElement(head).ordinal());
|
||||||
|
RoyalBossEntity.this.setFiringRoyalBeam(true);
|
||||||
|
RoyalBossEntity.this.triggerAnim(head.slot().controllerName(), "shoot");
|
||||||
|
RoyalBossEntity.this.beamLoopSoundTicks = 20;
|
||||||
|
RoyalBossEntity.this.playRoyalSound(RoyalBossEntity.this.royalBeamStartSound(head), 1.0F);
|
||||||
|
RoyalBossEntity.this.playRoyalSound(RoyalBossEntity.this.royalBeamShootSound(), 1.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onComplete() {
|
||||||
|
if (RoyalBossEntity.this.activeBeamHead == head) {
|
||||||
|
RoyalBossEntity.this.stopRoyalBeam();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
head.setBeamActive(true);
|
head.setBeamActive(true);
|
||||||
this.activeBeamHead = head;
|
this.activeBeamHead = head;
|
||||||
this.beamHeadCursor = (head.slot().partIndex()) % this.heads.length;
|
this.beamHeadCursor = (head.slot().partIndex()) % this.heads.length;
|
||||||
this.beamCooldownTicks = cooldown;
|
this.beamCooldownTicks = cooldown;
|
||||||
this.beamController.start(this.headAnchor(head), target.getEyePosition(), duration);
|
this.beamStarted = false;
|
||||||
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(head), 3.0F, 1.0F);
|
|
||||||
this.playSound(this.royalBeamShootSound(), 3.0F, 1.0F);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -418,11 +486,14 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
private void stopRoyalBeam() {
|
private void stopRoyalBeam() {
|
||||||
if (this.activeBeamHead != null) {
|
if (this.activeBeamHead != null) {
|
||||||
this.activeBeamHead.setBeamActive(false);
|
this.activeBeamHead.setBeamActive(false);
|
||||||
|
this.activeBeamHead.stopShoot();
|
||||||
}
|
}
|
||||||
this.activeBeamHead = null;
|
this.activeBeamHead = null;
|
||||||
|
this.beamStarted = false;
|
||||||
|
this.attackScheduler.cancel(this.beamLane());
|
||||||
this.beamController.stop();
|
this.beamController.stop();
|
||||||
this.entityData.set(BEAM_ELEMENT, RoyalBeamElement.GENERIC.ordinal());
|
this.entityData.set(BEAM_ELEMENT, RoyalBeamElement.GENERIC.ordinal());
|
||||||
this.playSound(this.royalBeamEndSound(), 2.5F, 1.0F);
|
this.playRoyalSound(this.royalBeamEndSound(), 1.0F);
|
||||||
this.setFiringRoyalBeam(false);
|
this.setFiringRoyalBeam(false);
|
||||||
this.setRoyalBeamEndPosition(null);
|
this.setRoyalBeamEndPosition(null);
|
||||||
}
|
}
|
||||||
@@ -484,8 +555,11 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean inverted = AntarchyGravityApi.isGravityInverted(this);
|
||||||
double groundBelowTarget = this.groundYBelow(target.getX(), target.getZ());
|
double groundBelowTarget = this.groundYBelow(target.getX(), target.getZ());
|
||||||
double wantedY = Mth.clamp(target.getY() + 3.0D,
|
double wantedY = inverted
|
||||||
|
? target.getY() - 3.0D
|
||||||
|
: Mth.clamp(target.getY() + 3.0D,
|
||||||
groundBelowTarget + FLYING_MIN_HOVER,
|
groundBelowTarget + FLYING_MIN_HOVER,
|
||||||
groundBelowTarget + FLYING_MAX_HOVER_ABOVE_GROUND);
|
groundBelowTarget + FLYING_MAX_HOVER_ABOVE_GROUND);
|
||||||
boolean closeVertically = Math.abs(wantedY - this.getY()) <= 2.5D;
|
boolean closeVertically = Math.abs(wantedY - this.getY()) <= 2.5D;
|
||||||
@@ -502,6 +576,9 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void tickFlyingAltitude() {
|
private void tickFlyingAltitude() {
|
||||||
|
if (AntarchyGravityApi.isGravityInverted(this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (this.onGround()) {
|
if (this.onGround()) {
|
||||||
this.setDeltaMovement(this.getDeltaMovement().add(0.0D, 0.2D, 0.0D));
|
this.setDeltaMovement(this.getDeltaMovement().add(0.0D, 0.2D, 0.0D));
|
||||||
}
|
}
|
||||||
@@ -535,9 +612,44 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
|
|
||||||
private void startBite(RoyalHead head, Phase phase) {
|
private void startBite(RoyalHead head, Phase phase) {
|
||||||
int cooldown = Math.max(10, Mth.floor(AntarchySettings.royalBossBiteCooldownTicks() * phase.cooldownScale()));
|
int cooldown = Math.max(10, Mth.floor(AntarchySettings.royalBossBiteCooldownTicks() * phase.cooldownScale()));
|
||||||
head.startBite(BITE_DURATION_TICKS, BITE_HIT_TICK, cooldown);
|
if (!this.attackScheduler.start("bite_" + head.slot().name(), headLane(head), cooldown,
|
||||||
this.triggerAnim(head.slot().controllerName(), "bite");
|
BITE_HIT_TICK, 1, BITE_DURATION_TICKS - BITE_HIT_TICK,
|
||||||
this.playSound(this.royalBiteSound(), 3.0F, 0.9F + this.random.nextFloat() * 0.2F);
|
new RoyalAttackScheduler.Action() {
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
RoyalBossEntity.this.triggerAnim(head.slot().controllerName(), "bite");
|
||||||
|
RoyalBossEntity.this.playRoyalSound(RoyalBossEntity.this.royalBiteSound(),
|
||||||
|
0.9F + RoyalBossEntity.this.random.nextFloat() * 0.2F);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActive(int elapsedTicks) {
|
||||||
|
RoyalBossEntity.this.applyBiteHit(head);
|
||||||
|
}
|
||||||
|
})) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected RoyalAttackLane headLane(RoyalHead head) {
|
||||||
|
return switch (head.slot()) {
|
||||||
|
case LEFT -> RoyalAttackLane.LEFT_HEAD;
|
||||||
|
case CENTER -> RoyalAttackLane.CENTER_HEAD;
|
||||||
|
case RIGHT -> RoyalAttackLane.RIGHT_HEAD;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected RoyalAttackLane beamLane() {
|
||||||
|
return RoyalAttackLane.BODY;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean beginRoyalAttack(String id, RoyalAttackLane lane, int cooldownTicks, int activeTicks) {
|
||||||
|
return this.attackScheduler.start(id, lane, cooldownTicks, activeTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean beginRoyalAttack(String id, RoyalAttackLane lane, int cooldownTicks, int windupTicks,
|
||||||
|
int activeTicks, int recoveryTicks, RoyalAttackScheduler.Action action) {
|
||||||
|
return this.attackScheduler.start(id, lane, cooldownTicks, windupTicks, activeTicks, recoveryTicks, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyBiteHit(RoyalHead head) {
|
private void applyBiteHit(RoyalHead head) {
|
||||||
@@ -578,7 +690,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
return AntarchySettings.royalBossBiteReach();
|
return AntarchySettings.royalBossBiteReach();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vec3 headAnchor(RoyalHead head) {
|
protected Vec3 headAnchor(RoyalHead head) {
|
||||||
int partIndex = head.slot().partIndex();
|
int partIndex = head.slot().partIndex();
|
||||||
Entity[] parts = this.multipartParts;
|
Entity[] parts = this.multipartParts;
|
||||||
if (parts != null && partIndex < parts.length && parts[partIndex] != null) {
|
if (parts != null && partIndex < parts.length && parts[partIndex] != null) {
|
||||||
@@ -596,6 +708,10 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
this.getZ() + forward.z * spec.forwardOffset() + right.z * spec.lateralOffset());
|
this.getZ() + forward.z * spec.forwardOffset() + right.z * spec.lateralOffset());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected RoyalHead royalHead(RoyalHead.Slot slot) {
|
||||||
|
return this.heads[slot.ordinal()];
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void die(DamageSource damageSource) {
|
public void die(DamageSource damageSource) {
|
||||||
if (!this.level().isClientSide) {
|
if (!this.level().isClientSide) {
|
||||||
@@ -667,7 +783,7 @@ public abstract class RoyalBossEntity extends Monster implements GeoEntity, Mult
|
|||||||
@Override
|
@Override
|
||||||
public boolean canBeAffected(net.minecraft.world.effect.MobEffectInstance effectInstance) {
|
public boolean canBeAffected(net.minecraft.world.effect.MobEffectInstance effectInstance) {
|
||||||
if (effectInstance.is(com.craisinlord.antarchy.content.AntarchyObjects.INVERTED_EFFECT.get())) {
|
if (effectInstance.is(com.craisinlord.antarchy.content.AntarchyObjects.INVERTED_EFFECT.get())) {
|
||||||
return false;
|
return ThoraxisUndersideManager.isThoraxis(this.level());
|
||||||
}
|
}
|
||||||
return super.canBeAffected(effectInstance);
|
return super.canBeAffected(effectInstance);
|
||||||
}
|
}
|
||||||
|
|||||||
+199
@@ -0,0 +1,199 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity.royal;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamElement;
|
||||||
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
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.entity.projectile.ThrowableProjectile;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import net.minecraft.world.phys.EntityHitResult;
|
||||||
|
import net.minecraft.world.phys.HitResult;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import software.bernie.geckolib.animatable.GeoEntity;
|
||||||
|
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
||||||
|
import software.bernie.geckolib.animation.AnimatableManager;
|
||||||
|
import software.bernie.geckolib.animation.AnimationController;
|
||||||
|
import software.bernie.geckolib.animation.AnimationState;
|
||||||
|
import software.bernie.geckolib.animation.PlayState;
|
||||||
|
import software.bernie.geckolib.animation.RawAnimation;
|
||||||
|
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||||
|
|
||||||
|
/** Shared travelling shell for the King's fireball and iceball. Impact rules stay element-specific. */
|
||||||
|
public class RoyalElementalProjectileEntity extends ThrowableProjectile implements GeoEntity {
|
||||||
|
private static final EntityDataAccessor<Integer> ATTACK_TYPE =
|
||||||
|
SynchedEntityData.defineId(RoyalElementalProjectileEntity.class, EntityDataSerializers.INT);
|
||||||
|
private static final int FIREBALL = 0;
|
||||||
|
private static final int ICEBALL = 1;
|
||||||
|
private static final int MAX_LIFETIME = 100;
|
||||||
|
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
|
|
||||||
|
public RoyalElementalProjectileEntity(EntityType<? extends RoyalElementalProjectileEntity> type, Level level) {
|
||||||
|
super(type, level);
|
||||||
|
this.noCulling = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RoyalElementalProjectileEntity create(Level level, LivingEntity owner, RoyalBeamElement element,
|
||||||
|
Vec3 position, Vec3 direction) {
|
||||||
|
RoyalElementalProjectileEntity projectile = new RoyalElementalProjectileEntity(
|
||||||
|
AntarchyObjects.ROYAL_ELEMENTAL_PROJECTILE.get(), level);
|
||||||
|
projectile.setOwner(owner);
|
||||||
|
projectile.setPos(position.x, position.y, position.z);
|
||||||
|
projectile.setAttackType(element == RoyalBeamElement.ICE ? ICEBALL : FIREBALL);
|
||||||
|
projectile.shoot(direction.x, direction.y, direction.z, element == RoyalBeamElement.ICE ? 0.8F : 1.05F, 0.0F);
|
||||||
|
return projectile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
||||||
|
builder.define(ATTACK_TYPE, FIREBALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isIceball() {
|
||||||
|
return this.entityData.get(ATTACK_TYPE) == ICEBALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setAttackType(int type) {
|
||||||
|
this.entityData.set(ATTACK_TYPE, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected double getDefaultGravity() {
|
||||||
|
return this.isIceball() ? 0.012D : 0.018D;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected float getInertia() {
|
||||||
|
return this.isIceball() ? 0.985F : 0.96F;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
if (!this.level().isClientSide && this.tickCount > MAX_LIFETIME) {
|
||||||
|
this.discard();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
super.tick();
|
||||||
|
if (this.level().isClientSide) {
|
||||||
|
this.level().addParticle(this.isIceball() ? ParticleTypes.SNOWFLAKE : ParticleTypes.FLAME,
|
||||||
|
this.getX(), this.getY(), this.getZ(), 0.0D, 0.0D, 0.0D);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onHitEntity(EntityHitResult result) {
|
||||||
|
if (!this.level().isClientSide && this.level() instanceof ServerLevel level) {
|
||||||
|
this.impact(level, result.getLocation());
|
||||||
|
}
|
||||||
|
this.discard();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onHitBlock(BlockHitResult result) {
|
||||||
|
if (!this.level().isClientSide && this.level() instanceof ServerLevel level) {
|
||||||
|
this.impact(level, result.getLocation());
|
||||||
|
}
|
||||||
|
this.discard();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onHit(HitResult result) {
|
||||||
|
super.onHit(result);
|
||||||
|
if (!this.level().isClientSide && result.getType() == HitResult.Type.MISS) {
|
||||||
|
this.discard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void impact(ServerLevel level, Vec3 center) {
|
||||||
|
if (this.isIceball()) {
|
||||||
|
impactIce(level, center);
|
||||||
|
} else {
|
||||||
|
impactFire(level, center);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void impactFire(ServerLevel level, Vec3 center) {
|
||||||
|
DamageSource source = this.damageSources().mobProjectile(this, this.getOwner() instanceof LivingEntity living ? living : null);
|
||||||
|
for (LivingEntity living : level.getEntitiesOfClass(LivingEntity.class, new AABB(center, center).inflate(5.0D),
|
||||||
|
entity -> entity.isAlive() && entity != this.getOwner())) {
|
||||||
|
double distance = Math.max(0.5D, living.position().distanceTo(center));
|
||||||
|
float falloff = (float) Math.max(0.25D, 1.0D - distance / 5.0D);
|
||||||
|
living.hurt(source, (float) (AntarchySettings.kingFireballDamage() * falloff));
|
||||||
|
living.setRemainingFireTicks(Math.max(living.getRemainingFireTicks(), 120));
|
||||||
|
}
|
||||||
|
RoyalBlockDestruction.destroySphere(level, this, center, AntarchySettings.kingFireballRadius(), AntarchySettings.kingElementalTerrainCap(), 80.0D, 0.15F);
|
||||||
|
level.sendParticles(ParticleTypes.EXPLOSION_EMITTER, center.x, center.y, center.z, 4, 1.5D, 1.5D, 1.5D, 0.0D);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void impactIce(ServerLevel level, Vec3 center) {
|
||||||
|
DamageSource source = this.damageSources().mobProjectile(this, this.getOwner() instanceof LivingEntity living ? living : null);
|
||||||
|
for (LivingEntity living : level.getEntitiesOfClass(LivingEntity.class, new AABB(center, center).inflate(5.0D),
|
||||||
|
entity -> entity.isAlive() && entity != this.getOwner())) {
|
||||||
|
living.hurt(source, (float) AntarchySettings.kingIceballDamage());
|
||||||
|
living.setTicksFrozen(Math.min(living.getTicksRequiredToFreeze() + 80, living.getTicksFrozen() + 180));
|
||||||
|
living.addEffect(new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.MOVEMENT_SLOWDOWN, 120, 3));
|
||||||
|
}
|
||||||
|
coverInIce(level, center, AntarchySettings.kingIceballRadius(), AntarchySettings.kingElementalTerrainCap());
|
||||||
|
level.sendParticles(ParticleTypes.SNOWFLAKE, center.x, center.y, center.z, 80, 4.0D, 2.0D, 4.0D, 0.08D);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void coverInIce(ServerLevel level, Vec3 center, double radius, int cap) {
|
||||||
|
int changed = 0;
|
||||||
|
int minX = (int) Math.floor(center.x - radius);
|
||||||
|
int minY = (int) Math.floor(center.y - radius);
|
||||||
|
int minZ = (int) Math.floor(center.z - radius);
|
||||||
|
int maxX = (int) Math.floor(center.x + radius);
|
||||||
|
int maxY = (int) Math.floor(center.y + radius);
|
||||||
|
int maxZ = (int) Math.floor(center.z + radius);
|
||||||
|
for (BlockPos pos : BlockPos.betweenClosed(minX, minY, minZ, maxX, maxY, maxZ)) {
|
||||||
|
if (changed >= cap || pos.distToCenterSqr(center.x, center.y, center.z) > radius * radius) continue;
|
||||||
|
BlockState existing = level.getBlockState(pos);
|
||||||
|
if (existing.isAir() || !existing.getFluidState().isEmpty() || existing.hasBlockEntity()) continue;
|
||||||
|
if (existing.getDestroySpeed(level, pos) < 0.0F || existing.getBlock().getExplosionResistance() > 80.0F) continue;
|
||||||
|
BlockState frozen = pos.getY() >= center.y + 1.0D ? Blocks.SNOW_BLOCK.defaultBlockState() : Blocks.PACKED_ICE.defaultBlockState();
|
||||||
|
if (existing != frozen && level.setBlockAndUpdate(pos, frozen)) changed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected net.minecraft.core.particles.ParticleOptions getTrailParticle() {
|
||||||
|
return this.isIceball() ? ParticleTypes.SNOWFLAKE : ParticleTypes.FLAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAdditionalSaveData(CompoundTag tag) {
|
||||||
|
super.addAdditionalSaveData(tag);
|
||||||
|
tag.putInt("AttackType", this.entityData.get(ATTACK_TYPE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readAdditionalSaveData(CompoundTag tag) {
|
||||||
|
super.readAdditionalSaveData(tag);
|
||||||
|
this.setAttackType(tag.getInt("AttackType"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
|
||||||
|
controllers.add(new AnimationController<>(this, "elemental_projectile", 0, this::animation));
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlayState animation(AnimationState<RoyalElementalProjectileEntity> state) {
|
||||||
|
return state.setAndContinue(RawAnimation.begin().thenLoop(this.isIceball() ? "animation.ice_ball" : "animation.fire_ball"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnimatableInstanceCache getAnimatableInstanceCache() {
|
||||||
|
return this.geoCache;
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
-39
@@ -41,10 +41,7 @@ public final class RoyalHead {
|
|||||||
|
|
||||||
private final Slot slot;
|
private final Slot slot;
|
||||||
private int targetId = -1;
|
private int targetId = -1;
|
||||||
private int attackCooldown;
|
private boolean shooting;
|
||||||
private int biteTicks;
|
|
||||||
private int biteHitTick = -1;
|
|
||||||
private int shootTicks;
|
|
||||||
private boolean beamActive;
|
private boolean beamActive;
|
||||||
|
|
||||||
public RoyalHead(Slot slot) {
|
public RoyalHead(Slot slot) {
|
||||||
@@ -68,22 +65,19 @@ public final class RoyalHead {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean busy() {
|
public boolean busy() {
|
||||||
return this.biteTicks > 0 || this.shootTicks > 0 || this.beamActive;
|
return this.shooting || this.beamActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean readyToAttack() {
|
public boolean readyToAttack() {
|
||||||
return !this.busy() && this.attackCooldown <= 0;
|
return !this.busy();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startBite(int durationTicks, int hitTick, int cooldownTicks) {
|
public void startShoot() {
|
||||||
this.biteTicks = durationTicks;
|
this.shooting = true;
|
||||||
this.biteHitTick = hitTick;
|
|
||||||
this.attackCooldown = cooldownTicks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startShoot(int durationTicks, int cooldownTicks) {
|
public void stopShoot() {
|
||||||
this.shootTicks = durationTicks;
|
this.shooting = false;
|
||||||
this.attackCooldown = cooldownTicks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBeamActive(boolean beamActive) {
|
public void setBeamActive(boolean beamActive) {
|
||||||
@@ -95,36 +89,12 @@ public final class RoyalHead {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean shooting() {
|
public boolean shooting() {
|
||||||
return this.shootTicks > 0;
|
return this.shooting;
|
||||||
}
|
|
||||||
|
|
||||||
public boolean tickBiteHit() {
|
|
||||||
if (this.biteTicks <= 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
this.biteTicks--;
|
|
||||||
boolean hit = this.biteTicks == this.biteHitTick;
|
|
||||||
if (hit) {
|
|
||||||
this.biteHitTick = -1;
|
|
||||||
}
|
|
||||||
return hit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void tick() {
|
|
||||||
if (this.attackCooldown > 0) {
|
|
||||||
this.attackCooldown--;
|
|
||||||
}
|
|
||||||
if (this.shootTicks > 0) {
|
|
||||||
this.shootTicks--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
this.targetId = -1;
|
this.targetId = -1;
|
||||||
this.attackCooldown = 0;
|
this.shooting = false;
|
||||||
this.biteTicks = 0;
|
|
||||||
this.biteHitTick = -1;
|
|
||||||
this.shootTicks = 0;
|
|
||||||
this.beamActive = false;
|
this.beamActive = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+98
@@ -0,0 +1,98 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity.royal;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||||
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
|
import net.minecraft.core.particles.ParticleTypes;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.damagesource.DamageSource;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import software.bernie.geckolib.animatable.GeoEntity;
|
||||||
|
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
||||||
|
import software.bernie.geckolib.animation.AnimatableManager;
|
||||||
|
import software.bernie.geckolib.animation.AnimationController;
|
||||||
|
import software.bernie.geckolib.animation.AnimationState;
|
||||||
|
import software.bernie.geckolib.animation.PlayState;
|
||||||
|
import software.bernie.geckolib.animation.RawAnimation;
|
||||||
|
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||||
|
|
||||||
|
public class RoyalIceSpikeEntity extends Entity implements GeoEntity {
|
||||||
|
private static final RawAnimation EMERGE_ANIMATION = RawAnimation.begin().thenPlay("ice_spike");
|
||||||
|
private static final RawAnimation IMPACT_ANIMATION = RawAnimation.begin().thenPlay("ice_spike_impact");
|
||||||
|
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
|
private boolean impacted;
|
||||||
|
|
||||||
|
public RoyalIceSpikeEntity(EntityType<? extends RoyalIceSpikeEntity> type, Level level) {
|
||||||
|
super(type, level);
|
||||||
|
this.noPhysics = true;
|
||||||
|
this.noCulling = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RoyalIceSpikeEntity create(ServerLevel level, Vec3 position) {
|
||||||
|
RoyalIceSpikeEntity spike = new RoyalIceSpikeEntity(AntarchyObjects.ROYAL_ICE_SPIKE.get(), level);
|
||||||
|
spike.setPos(position.x, position.y, position.z);
|
||||||
|
return spike;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void defineSynchedData(net.minecraft.network.syncher.SynchedEntityData.Builder builder) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
if (!this.level().isClientSide && this.tickCount == 1) {
|
||||||
|
this.triggerAnim("ice_spike", "emerge");
|
||||||
|
}
|
||||||
|
if (!this.level().isClientSide && this.tickCount == 6 && !this.impacted) {
|
||||||
|
this.impacted = true;
|
||||||
|
this.impact((ServerLevel) this.level());
|
||||||
|
this.triggerAnim("ice_spike", "impact");
|
||||||
|
}
|
||||||
|
if (!this.level().isClientSide && this.tickCount > 45) {
|
||||||
|
this.discard();
|
||||||
|
}
|
||||||
|
if (this.level().isClientSide && this.tickCount < 10) {
|
||||||
|
this.level().addParticle(ParticleTypes.SNOWFLAKE, this.getX(), this.getY() + this.tickCount * 0.4D, this.getZ(), 0.0D, 0.03D, 0.0D);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void impact(ServerLevel level) {
|
||||||
|
DamageSource source = this.damageSources().magic();
|
||||||
|
for (LivingEntity living : level.getEntitiesOfClass(LivingEntity.class,
|
||||||
|
new AABB(this.blockPosition()).inflate(2.2D), entity -> entity.isAlive())) {
|
||||||
|
living.hurt(source, (float) AntarchySettings.kingIceSpikeDamage());
|
||||||
|
living.setTicksFrozen(Math.min(living.getTicksRequiredToFreeze() + 60, living.getTicksFrozen() + 100));
|
||||||
|
living.setDeltaMovement(living.getDeltaMovement().add(0.0D, 0.35D, 0.0D));
|
||||||
|
living.hasImpulse = true;
|
||||||
|
}
|
||||||
|
level.sendParticles(ParticleTypes.SNOWFLAKE, this.getX(), this.getY() + 1.5D, this.getZ(), 25, 1.5D, 1.0D, 1.5D, 0.04D);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void readAdditionalSaveData(CompoundTag tag) {
|
||||||
|
this.impacted = tag.getBoolean("Impacted");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addAdditionalSaveData(CompoundTag tag) {
|
||||||
|
tag.putBoolean("Impacted", this.impacted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
|
||||||
|
controllers.add(new AnimationController<>(this, "ice_spike", 0, state -> PlayState.STOP)
|
||||||
|
.triggerableAnim("emerge", EMERGE_ANIMATION)
|
||||||
|
.triggerableAnim("impact", IMPACT_ANIMATION));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnimatableInstanceCache getAnimatableInstanceCache() {
|
||||||
|
return this.geoCache;
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity.royal.attack;
|
||||||
|
|
||||||
|
public enum RoyalAttackLane {
|
||||||
|
BODY,
|
||||||
|
LEFT_HEAD,
|
||||||
|
CENTER_HEAD,
|
||||||
|
RIGHT_HEAD,
|
||||||
|
HAZARD,
|
||||||
|
SUMMON,
|
||||||
|
DECREE,
|
||||||
|
MOVEMENT
|
||||||
|
}
|
||||||
+123
@@ -0,0 +1,123 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity.royal.attack;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.ToIntFunction;
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
|
|
||||||
|
/** Shared server-side arbitration for Royal attack lifecycles. */
|
||||||
|
public final class RoyalAttackScheduler {
|
||||||
|
public interface Action {
|
||||||
|
default void onStart() {}
|
||||||
|
default void onActive(int elapsedTicks) {}
|
||||||
|
default void onComplete() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class RunningAction {
|
||||||
|
private final Action action;
|
||||||
|
private final int windupTicks;
|
||||||
|
private final int activeTicks;
|
||||||
|
private final int recoveryTicks;
|
||||||
|
private int elapsedTicks;
|
||||||
|
|
||||||
|
private RunningAction(Action action, int windupTicks, int activeTicks, int recoveryTicks) {
|
||||||
|
this.action = action;
|
||||||
|
this.windupTicks = Math.max(0, windupTicks);
|
||||||
|
this.activeTicks = Math.max(1, activeTicks);
|
||||||
|
this.recoveryTicks = Math.max(0, recoveryTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int totalTicks() {
|
||||||
|
return this.windupTicks + this.activeTicks + this.recoveryTicks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private final Map<String, Integer> cooldowns = new HashMap<>();
|
||||||
|
private final Map<RoyalAttackLane, RunningAction> active = new EnumMap<>(RoyalAttackLane.class);
|
||||||
|
private final Deque<String> recent = new ArrayDeque<>();
|
||||||
|
|
||||||
|
public void tick() {
|
||||||
|
cooldowns.replaceAll((key, value) -> Math.max(0, value - 1));
|
||||||
|
for (var iterator = active.entrySet().iterator(); iterator.hasNext();) {
|
||||||
|
RunningAction running = iterator.next().getValue();
|
||||||
|
running.elapsedTicks++;
|
||||||
|
int activeStart = running.windupTicks;
|
||||||
|
int activeEnd = activeStart + running.activeTicks;
|
||||||
|
if (running.elapsedTicks >= activeStart && running.elapsedTicks < activeEnd) {
|
||||||
|
running.action.onActive(running.elapsedTicks - activeStart);
|
||||||
|
}
|
||||||
|
if (running.elapsedTicks >= running.totalTicks()) {
|
||||||
|
iterator.remove();
|
||||||
|
running.action.onComplete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean ready(String id, RoyalAttackLane lane) {
|
||||||
|
return cooldowns.getOrDefault(id, 0) <= 0 && !active.containsKey(lane);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean laneBusy(RoyalAttackLane lane) {
|
||||||
|
return active.containsKey(lane);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean start(String id, RoyalAttackLane lane, int cooldownTicks, int activeTicks) {
|
||||||
|
return start(id, lane, cooldownTicks, 0, activeTicks, 0, new Action() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean start(String id, RoyalAttackLane lane, int cooldownTicks, int windupTicks,
|
||||||
|
int activeTicks, int recoveryTicks, Action action) {
|
||||||
|
if (!ready(id, lane)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cooldowns.put(id, Math.max(1, cooldownTicks));
|
||||||
|
active.put(lane, new RunningAction(action, windupTicks, activeTicks, recoveryTicks));
|
||||||
|
action.onStart();
|
||||||
|
recent.remove(id);
|
||||||
|
recent.addFirst(id);
|
||||||
|
while (recent.size() > 8) {
|
||||||
|
recent.removeLast();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int repetitionPenalty(String id) {
|
||||||
|
int penalty = 0;
|
||||||
|
for (String previous : recent) {
|
||||||
|
if (previous.equals(id)) {
|
||||||
|
penalty += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return penalty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String chooseWeighted(String[] ids, ToIntFunction<String> weightFunction, RandomSource random) {
|
||||||
|
int total = 0;
|
||||||
|
int[] weights = new int[ids.length];
|
||||||
|
for (int i = 0; i < ids.length; i++) {
|
||||||
|
weights[i] = Math.max(0, weightFunction.applyAsInt(ids[i]) - repetitionPenalty(ids[i]));
|
||||||
|
total += weights[i];
|
||||||
|
}
|
||||||
|
if (total <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int roll = random.nextInt(total);
|
||||||
|
for (int i = 0; i < ids.length; i++) {
|
||||||
|
roll -= weights[i];
|
||||||
|
if (roll < 0) {
|
||||||
|
return ids[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int cooldown(String id) {
|
||||||
|
return cooldowns.getOrDefault(id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancel(RoyalAttackLane lane) {
|
||||||
|
active.remove(lane);
|
||||||
|
}
|
||||||
|
}
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity.royal.attack;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/** Owns persistent per-tick effects started by a Royal attack. */
|
||||||
|
public final class RoyalEffectController {
|
||||||
|
private record Effect(Runnable tick, Runnable end, int duration, int age) {
|
||||||
|
private Effect advance() {
|
||||||
|
return new Effect(this.tick, this.end, this.duration, this.age + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<String, Effect> active = new HashMap<>();
|
||||||
|
|
||||||
|
public void tick() {
|
||||||
|
for (var iterator = this.active.entrySet().iterator(); iterator.hasNext();) {
|
||||||
|
var entry = iterator.next();
|
||||||
|
Effect effect = entry.getValue();
|
||||||
|
effect.tick().run();
|
||||||
|
Effect next = effect.advance();
|
||||||
|
if (next.age() >= next.duration()) {
|
||||||
|
next.end().run();
|
||||||
|
iterator.remove();
|
||||||
|
} else {
|
||||||
|
entry.setValue(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start(String id, int duration, Runnable onStart, Runnable tick, Runnable end) {
|
||||||
|
this.stop(id);
|
||||||
|
onStart.run();
|
||||||
|
this.active.put(id, new Effect(tick, end, Math.max(1, duration), 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean active(String id) {
|
||||||
|
return this.active.containsKey(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop(String id) {
|
||||||
|
Effect effect = this.active.remove(id);
|
||||||
|
if (effect != null) {
|
||||||
|
effect.end().run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
for (Effect effect : this.active.values()) {
|
||||||
|
effect.end().run();
|
||||||
|
}
|
||||||
|
this.active.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
-2
@@ -26,10 +26,13 @@ import net.minecraft.world.phys.Vec3;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public final class RoyalBeamController {
|
public final class RoyalBeamController {
|
||||||
|
private static final int INITIAL_TRACKING_DELAY_TICKS = 8;
|
||||||
private final Mob owner;
|
private final Mob owner;
|
||||||
private Vec3 serverTarget;
|
private Vec3 serverTarget;
|
||||||
private Vec3 beamEndPosition;
|
private Vec3 beamEndPosition;
|
||||||
private int beamTicks;
|
private int beamTicks;
|
||||||
|
private int beamAgeTicks;
|
||||||
|
private int trackingDelayTicks;
|
||||||
private int terrainMutationsThisTick;
|
private int terrainMutationsThisTick;
|
||||||
private static final int ICE_MUTATIONS_PER_TICK = 3;
|
private static final int ICE_MUTATIONS_PER_TICK = 3;
|
||||||
private static final float ICE_IMPACT_RADIUS = 2.0F;
|
private static final float ICE_IMPACT_RADIUS = 2.0F;
|
||||||
@@ -55,12 +58,15 @@ public final class RoyalBeamController {
|
|||||||
this.serverTarget = target;
|
this.serverTarget = target;
|
||||||
this.beamEndPosition = target;
|
this.beamEndPosition = target;
|
||||||
this.beamTicks = Math.max(1, durationTicks);
|
this.beamTicks = Math.max(1, durationTicks);
|
||||||
|
this.beamAgeTicks = 0;
|
||||||
|
this.trackingDelayTicks = INITIAL_TRACKING_DELAY_TICKS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
this.serverTarget = null;
|
this.serverTarget = null;
|
||||||
this.beamEndPosition = null;
|
this.beamEndPosition = null;
|
||||||
this.beamTicks = 0;
|
this.beamTicks = 0;
|
||||||
|
this.beamAgeTicks = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tick(
|
public void tick(
|
||||||
@@ -76,8 +82,11 @@ public final class RoyalBeamController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.beamTicks--;
|
this.beamTicks--;
|
||||||
|
this.beamAgeTicks++;
|
||||||
this.terrainMutationsThisTick = 0;
|
this.terrainMutationsThisTick = 0;
|
||||||
if (target != null && target.isAlive()) {
|
if (this.trackingDelayTicks > 0) {
|
||||||
|
this.trackingDelayTicks--;
|
||||||
|
} else if (target != null && target.isAlive()) {
|
||||||
Vec3 targetEye = target.getEyePosition();
|
Vec3 targetEye = target.getEyePosition();
|
||||||
this.serverTarget = this.serverTarget == null
|
this.serverTarget = this.serverTarget == null
|
||||||
? targetEye
|
? targetEye
|
||||||
@@ -93,7 +102,10 @@ public final class RoyalBeamController {
|
|||||||
if (direction.lengthSqr() < 1.0E-7D) {
|
if (direction.lengthSqr() < 1.0E-7D) {
|
||||||
direction = this.owner.getLookAngle();
|
direction = this.owner.getLookAngle();
|
||||||
}
|
}
|
||||||
Vec3 clipEnd = shootFrom.add(direction.scale(settings.range()));
|
double committedDistance = Math.min(settings.range(), shootFrom.distanceTo(this.serverTarget));
|
||||||
|
double travelProgress = Mth.clamp(this.beamAgeTicks / (double) settings.travelTicks(), 0.0D, 1.0D);
|
||||||
|
double currentRange = Math.max(settings.pathStep(), committedDistance * travelProgress);
|
||||||
|
Vec3 clipEnd = shootFrom.add(direction.scale(currentRange));
|
||||||
HitResult hit = this.owner.level().clip(new ClipContext(
|
HitResult hit = this.owner.level().clip(new ClipContext(
|
||||||
shootFrom,
|
shootFrom,
|
||||||
clipEnd,
|
clipEnd,
|
||||||
|
|||||||
+3
@@ -5,6 +5,7 @@ public record RoyalBeamSettings(
|
|||||||
double targetTracking,
|
double targetTracking,
|
||||||
double pathStep,
|
double pathStep,
|
||||||
int durationTicks,
|
int durationTicks,
|
||||||
|
int travelTicks,
|
||||||
int cooldownTicks,
|
int cooldownTicks,
|
||||||
float pathDamageRadius,
|
float pathDamageRadius,
|
||||||
float impactDamageRadius,
|
float impactDamageRadius,
|
||||||
@@ -27,6 +28,7 @@ public record RoyalBeamSettings(
|
|||||||
0.1D,
|
0.1D,
|
||||||
7.5D,
|
7.5D,
|
||||||
30,
|
30,
|
||||||
|
12,
|
||||||
90,
|
90,
|
||||||
6.0F,
|
6.0F,
|
||||||
6.0F,
|
6.0F,
|
||||||
@@ -50,6 +52,7 @@ public record RoyalBeamSettings(
|
|||||||
targetTracking = Math.clamp(targetTracking, 0.0D, 1.0D);
|
targetTracking = Math.clamp(targetTracking, 0.0D, 1.0D);
|
||||||
pathStep = Math.max(1.0D, pathStep);
|
pathStep = Math.max(1.0D, pathStep);
|
||||||
durationTicks = Math.max(1, durationTicks);
|
durationTicks = Math.max(1, durationTicks);
|
||||||
|
travelTicks = Math.max(1, travelTicks);
|
||||||
cooldownTicks = Math.max(1, cooldownTicks);
|
cooldownTicks = Math.max(1, cooldownTicks);
|
||||||
pathDamageRadius = Math.max(0.0F, pathDamageRadius);
|
pathDamageRadius = Math.max(0.0F, pathDamageRadius);
|
||||||
impactDamageRadius = Math.max(0.0F, impactDamageRadius);
|
impactDamageRadius = Math.max(0.0F, impactDamageRadius);
|
||||||
|
|||||||
+3
-5
@@ -5,11 +5,9 @@ import net.minecraft.world.entity.LivingEntity;
|
|||||||
public final class AdvanceDecree implements RoyalDecree {
|
public final class AdvanceDecree implements RoyalDecree {
|
||||||
private static final double REQUIRED_RANGE = 14.0D;
|
private static final double REQUIRED_RANGE = 14.0D;
|
||||||
public String translationKey() { return "decree.antarchy.advance"; }
|
public String translationKey() { return "decree.antarchy.advance"; }
|
||||||
public void apply(ServerLevel level, KingEntity king, LivingEntity target) {
|
public void apply(ServerLevel level, KingEntity king, LivingEntity target) { king.setDecreeRetreatPressure(true); }
|
||||||
king.setDecreeRetreatPressure(true);
|
@Override public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
if (target.distanceTo(king) > REQUIRED_RANGE) {
|
return target.distanceTo(king) > REQUIRED_RANGE ? Evaluation.VIOLATED : Evaluation.COMPLIANT;
|
||||||
king.invokeJudgment(target);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public int contextWeight(KingEntity king, LivingEntity target) {
|
public int contextWeight(KingEntity king, LivingEntity target) {
|
||||||
|
|||||||
+3
@@ -5,6 +5,9 @@ import net.minecraft.world.entity.LivingEntity;
|
|||||||
public final class ComeNoCloserDecree implements RoyalDecree {
|
public final class ComeNoCloserDecree implements RoyalDecree {
|
||||||
public String translationKey() { return "decree.antarchy.come_no_closer"; }
|
public String translationKey() { return "decree.antarchy.come_no_closer"; }
|
||||||
public void apply(ServerLevel level, KingEntity king, LivingEntity target) { }
|
public void apply(ServerLevel level, KingEntity king, LivingEntity target) { }
|
||||||
|
@Override public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
|
return target.distanceTo(king) <= 16.0D ? Evaluation.VIOLATED : Evaluation.COMPLIANT;
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public int contextWeight(KingEntity king, LivingEntity target) {
|
public int contextWeight(KingEntity king, LivingEntity target) {
|
||||||
return 4 + king.behaviorScore(KingEntity.Behavior.HUGGING);
|
return 4 + king.behaviorScore(KingEntity.Behavior.HUGGING);
|
||||||
|
|||||||
+4
-1
@@ -4,7 +4,10 @@ import net.minecraft.server.level.ServerLevel;
|
|||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
public final class DoNotRunDecree implements RoyalDecree {
|
public final class DoNotRunDecree implements RoyalDecree {
|
||||||
public String translationKey() { return "decree.antarchy.do_not_run"; }
|
public String translationKey() { return "decree.antarchy.do_not_run"; }
|
||||||
public void apply(ServerLevel level, KingEntity king, LivingEntity target) { if (target.isSprinting()) king.invokeJudgment(target); }
|
public void apply(ServerLevel level, KingEntity king, LivingEntity target) { }
|
||||||
|
@Override public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
|
return target.isSprinting() ? Evaluation.VIOLATED : Evaluation.COMPLIANT;
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public int contextWeight(KingEntity king, LivingEntity target) {
|
public int contextWeight(KingEntity king, LivingEntity target) {
|
||||||
return 4 + king.behaviorScore(KingEntity.Behavior.SPRINTING);
|
return 4 + king.behaviorScore(KingEntity.Behavior.SPRINTING);
|
||||||
|
|||||||
+4
@@ -13,4 +13,8 @@ public final class FightMeCowardDecree implements RoyalDecree {
|
|||||||
target.hasImpulse = true;
|
target.hasImpulse = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
|
return target.distanceTo(king) > 28.0D ? Evaluation.VIOLATED : Evaluation.COMPLIANT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+3
-4
@@ -5,10 +5,9 @@ import net.minecraft.world.entity.LivingEntity;
|
|||||||
public final class KeepYourDistanceDecree implements RoyalDecree {
|
public final class KeepYourDistanceDecree implements RoyalDecree {
|
||||||
private static final double INNER_RADIUS = 16.0D;
|
private static final double INNER_RADIUS = 16.0D;
|
||||||
public String translationKey() { return "decree.antarchy.keep_your_distance"; }
|
public String translationKey() { return "decree.antarchy.keep_your_distance"; }
|
||||||
public void apply(ServerLevel level, KingEntity king, LivingEntity target) {
|
public void apply(ServerLevel level, KingEntity king, LivingEntity target) { }
|
||||||
if (target.distanceTo(king) <= INNER_RADIUS) {
|
@Override public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
king.invokeJudgment(target);
|
return target.distanceTo(king) <= INNER_RADIUS ? Evaluation.VIOLATED : Evaluation.COMPLIANT;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public int contextWeight(KingEntity king, LivingEntity target) {
|
public int contextWeight(KingEntity king, LivingEntity target) {
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ public final class KneelDecree implements RoyalDecree {
|
|||||||
UUID id = target.getUUID();
|
UUID id = target.getUUID();
|
||||||
if (target.isCrouching()) { deadlines.remove(id); king.clearActiveDecree(target); return; }
|
if (target.isCrouching()) { deadlines.remove(id); king.clearActiveDecree(target); return; }
|
||||||
int deadline = deadlines.computeIfAbsent(id, ignored -> target.tickCount + 100);
|
int deadline = deadlines.computeIfAbsent(id, ignored -> target.tickCount + 100);
|
||||||
if (target.tickCount >= deadline) { king.invokeJudgment(target); deadlines.put(id, target.tickCount + 100); }
|
if (target.tickCount >= deadline) { king.failActiveDecree(target); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+10
@@ -5,9 +5,19 @@ import net.minecraft.server.level.ServerLevel;
|
|||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
|
||||||
public interface RoyalDecree {
|
public interface RoyalDecree {
|
||||||
|
enum Evaluation {
|
||||||
|
COMPLIANT,
|
||||||
|
VIOLATED,
|
||||||
|
COMPLETE
|
||||||
|
}
|
||||||
|
|
||||||
String translationKey();
|
String translationKey();
|
||||||
void apply(ServerLevel level, KingEntity king, LivingEntity target);
|
void apply(ServerLevel level, KingEntity king, LivingEntity target);
|
||||||
|
|
||||||
|
default Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
|
return Evaluation.COMPLIANT;
|
||||||
|
}
|
||||||
|
|
||||||
default int countdownTicks(LivingEntity target) {
|
default int countdownTicks(LivingEntity target) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -6,8 +6,9 @@ public final class ShowNoMercyDecree implements RoyalDecree {
|
|||||||
private static final long IDLE_DAMAGE_LIMIT_TICKS = 80L;
|
private static final long IDLE_DAMAGE_LIMIT_TICKS = 80L;
|
||||||
public String translationKey() { return "decree.antarchy.show_no_mercy"; }
|
public String translationKey() { return "decree.antarchy.show_no_mercy"; }
|
||||||
public void apply(ServerLevel level, KingEntity king, LivingEntity target) {
|
public void apply(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
if (king.ticksSincePlayerDamage(target) > IDLE_DAMAGE_LIMIT_TICKS) {
|
}
|
||||||
king.invokeJudgment(target);
|
@Override public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
}
|
return king.ticksSincePlayerDamage(target) > IDLE_DAMAGE_LIMIT_TICKS
|
||||||
|
? Evaluation.VIOLATED : Evaluation.COMPLIANT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+4
-1
@@ -4,7 +4,10 @@ import net.minecraft.server.level.ServerLevel;
|
|||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
public final class SkyIsMineDecree implements RoyalDecree {
|
public final class SkyIsMineDecree implements RoyalDecree {
|
||||||
public String translationKey() { return "decree.antarchy.the_sky_is_mine"; }
|
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); }
|
public void apply(ServerLevel level, KingEntity king, LivingEntity target) { }
|
||||||
|
@Override public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
|
return !target.onGround() && !target.isPassenger() ? Evaluation.VIOLATED : Evaluation.COMPLIANT;
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public int contextWeight(KingEntity king, LivingEntity target) {
|
public int contextWeight(KingEntity king, LivingEntity target) {
|
||||||
return 4 + king.behaviorScore(KingEntity.Behavior.AIRBORNE);
|
return 4 + king.behaviorScore(KingEntity.Behavior.AIRBORNE);
|
||||||
|
|||||||
+3
-3
@@ -5,8 +5,8 @@ import net.minecraft.world.entity.LivingEntity;
|
|||||||
public final class StandTallDecree implements RoyalDecree {
|
public final class StandTallDecree implements RoyalDecree {
|
||||||
public String translationKey() { return "decree.antarchy.stand_tall"; }
|
public String translationKey() { return "decree.antarchy.stand_tall"; }
|
||||||
public void apply(ServerLevel level, KingEntity king, LivingEntity target) {
|
public void apply(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
if (target.isCrouching()) {
|
}
|
||||||
king.invokeJudgment(target);
|
@Override public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
}
|
return target.isCrouching() ? Evaluation.VIOLATED : Evaluation.COMPLIANT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+4
-2
@@ -12,9 +12,11 @@ public final class StandYourGroundDecree implements RoyalDecree {
|
|||||||
public String translationKey() { return "decree.antarchy.stand_your_ground"; }
|
public String translationKey() { return "decree.antarchy.stand_your_ground"; }
|
||||||
public void apply(ServerLevel level, KingEntity king, LivingEntity target) {
|
public void apply(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
Vec3 anchor = this.anchors.computeIfAbsent(target.getUUID(), ignored -> target.position());
|
Vec3 anchor = this.anchors.computeIfAbsent(target.getUUID(), ignored -> target.position());
|
||||||
if (target.position().distanceToSqr(anchor) > ALLOWED_DRIFT * ALLOWED_DRIFT) {
|
|
||||||
king.invokeJudgment(target);
|
|
||||||
}
|
}
|
||||||
|
@Override public Evaluation evaluate(ServerLevel level, KingEntity king, LivingEntity target) {
|
||||||
|
Vec3 anchor = this.anchors.computeIfAbsent(target.getUUID(), ignored -> target.position());
|
||||||
|
return target.position().distanceToSqr(anchor) > ALLOWED_DRIFT * ALLOWED_DRIFT
|
||||||
|
? Evaluation.VIOLATED : Evaluation.COMPLIANT;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onEnded() {
|
public void onEnded() {
|
||||||
|
|||||||
+122
-12
@@ -8,6 +8,7 @@ import net.minecraft.nbt.CompoundTag;
|
|||||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||||
import net.minecraft.network.syncher.SynchedEntityData;
|
import net.minecraft.network.syncher.SynchedEntityData;
|
||||||
|
import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.sounds.SoundEvents;
|
import net.minecraft.sounds.SoundEvents;
|
||||||
@@ -66,6 +67,8 @@ public class WindVortexEntity extends Entity {
|
|||||||
private static final String TRAVEL_Z_KEY = "TravelZ";
|
private static final String TRAVEL_Z_KEY = "TravelZ";
|
||||||
private static final String TRAVELLING_KEY = "Travelling";
|
private static final String TRAVELLING_KEY = "Travelling";
|
||||||
private static final String HOMING_KEY = "Homing";
|
private static final String HOMING_KEY = "Homing";
|
||||||
|
private static final String ANCHORED_KEY = "Anchored";
|
||||||
|
private static final String BOUNCE_ON_IMPACT_KEY = "BounceOnImpact";
|
||||||
|
|
||||||
private static final double BASE_RADIUS = 0.35D;
|
private static final double BASE_RADIUS = 0.35D;
|
||||||
private static final double DRIFT_FRICTION = 0.995D;
|
private static final double DRIFT_FRICTION = 0.995D;
|
||||||
@@ -82,15 +85,20 @@ public class WindVortexEntity extends Entity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int age;
|
private int age;
|
||||||
private int durationTicks = 140;
|
private int durationTicks = 240;
|
||||||
private double pullStrength = 0.32D;
|
private double pullStrength = 0.32D;
|
||||||
private double launchStrength = 1.0D;
|
private double launchStrength = 1.0D;
|
||||||
private float damageOverride = -1.0F;
|
private float damageOverride = -1.0F;
|
||||||
private Vec3 travelVelocity = Vec3.ZERO;
|
private Vec3 travelVelocity = Vec3.ZERO;
|
||||||
private boolean travelling = false;
|
private boolean travelling = false;
|
||||||
private boolean homing = false;
|
private boolean homing = false;
|
||||||
|
private boolean bounceOnImpact = false;
|
||||||
private int travelTicksRemaining;
|
private int travelTicksRemaining;
|
||||||
private int fadeOutTicksRemaining;
|
private int fadeOutTicksRemaining;
|
||||||
|
private boolean anchoredAtBlock;
|
||||||
|
private double flowTurnRate;
|
||||||
|
private double flowTurnTarget;
|
||||||
|
private int flowTurnChangeTicks;
|
||||||
private final Map<UUID, Double> carriedProgress = new HashMap<>();
|
private final Map<UUID, Double> carriedProgress = new HashMap<>();
|
||||||
@Nullable
|
@Nullable
|
||||||
private UUID ownerUuid;
|
private UUID ownerUuid;
|
||||||
@@ -148,6 +156,18 @@ public class WindVortexEntity extends Entity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.anchoredAtBlock) {
|
||||||
|
this.setDeltaMovement(Vec3.ZERO);
|
||||||
|
if ((this.tickCount & 1) == 0) {
|
||||||
|
this.applyVortexForces();
|
||||||
|
}
|
||||||
|
this.age++;
|
||||||
|
if (this.age >= this.durationTicks) {
|
||||||
|
this.fadeOut();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
boolean lensVortex = this.getMode() != VortexMode.UPWARD;
|
boolean lensVortex = this.getMode() != VortexMode.UPWARD;
|
||||||
if (!lensVortex && (this.isInLava() || this.isInsideSolidBlock())) {
|
if (!lensVortex && (this.isInLava() || this.isInsideSolidBlock())) {
|
||||||
this.fadeOut();
|
this.fadeOut();
|
||||||
@@ -164,14 +184,20 @@ public class WindVortexEntity extends Entity {
|
|||||||
if (this.homing) {
|
if (this.homing) {
|
||||||
this.steerTowardPrey();
|
this.steerTowardPrey();
|
||||||
}
|
}
|
||||||
|
if (this.bounceOnImpact) {
|
||||||
|
this.updateFluidDrift();
|
||||||
|
}
|
||||||
Vec3 from = this.position();
|
Vec3 from = this.position();
|
||||||
Vec3 to = from.add(this.travelVelocity);
|
Vec3 to = from.add(this.travelVelocity);
|
||||||
HitResult blockHit = this.level().clip(
|
HitResult blockHit = this.level().clip(
|
||||||
new ClipContext(from, to, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this));
|
new ClipContext(from, to, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this));
|
||||||
if (blockHit.getType() != HitResult.Type.MISS) {
|
if (blockHit.getType() != HitResult.Type.MISS) {
|
||||||
this.fadeOut();
|
if (this.bounceOnImpact) {
|
||||||
return;
|
this.flowAroundBlock(blockHit);
|
||||||
|
} else {
|
||||||
|
this.anchorAtBlock(blockHit);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
this.setDeltaMovement(this.travelVelocity);
|
this.setDeltaMovement(this.travelVelocity);
|
||||||
this.move(net.minecraft.world.entity.MoverType.SELF, this.travelVelocity);
|
this.move(net.minecraft.world.entity.MoverType.SELF, this.travelVelocity);
|
||||||
if (--this.travelTicksRemaining <= 0) {
|
if (--this.travelTicksRemaining <= 0) {
|
||||||
@@ -179,6 +205,7 @@ public class WindVortexEntity extends Entity {
|
|||||||
this.noPhysics = false;
|
this.noPhysics = false;
|
||||||
this.setDeltaMovement(this.travelVelocity);
|
this.setDeltaMovement(this.travelVelocity);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (!lensVortex) {
|
} else if (!lensVortex) {
|
||||||
Vec3 current = this.getDeltaMovement();
|
Vec3 current = this.getDeltaMovement();
|
||||||
double downwardSpeed = Math.min(MAX_FALL_SPEED, Math.max(MINIMUM_DOWNWARD_DRIFT,
|
double downwardSpeed = Math.min(MAX_FALL_SPEED, Math.max(MINIMUM_DOWNWARD_DRIFT,
|
||||||
@@ -192,11 +219,15 @@ public class WindVortexEntity extends Entity {
|
|||||||
HitResult blockHit = this.level().clip(
|
HitResult blockHit = this.level().clip(
|
||||||
new ClipContext(from, to, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this));
|
new ClipContext(from, to, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this));
|
||||||
if (blockHit.getType() != HitResult.Type.MISS) {
|
if (blockHit.getType() != HitResult.Type.MISS) {
|
||||||
this.fadeOut();
|
if (this.bounceOnImpact) {
|
||||||
return;
|
this.flowAroundBlock(blockHit);
|
||||||
|
} else {
|
||||||
|
this.anchorAtBlock(blockHit);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
this.setDeltaMovement(drift);
|
this.setDeltaMovement(drift);
|
||||||
this.move(net.minecraft.world.entity.MoverType.SELF, drift);
|
this.move(net.minecraft.world.entity.MoverType.SELF, drift);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Vec3 drift = this.getDeltaMovement().multiply(DRIFT_FRICTION, DRIFT_FRICTION, DRIFT_FRICTION);
|
Vec3 drift = this.getDeltaMovement().multiply(DRIFT_FRICTION, DRIFT_FRICTION, DRIFT_FRICTION);
|
||||||
this.setDeltaMovement(drift);
|
this.setDeltaMovement(drift);
|
||||||
@@ -256,6 +287,73 @@ public class WindVortexEntity extends Entity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void anchorAtBlock(HitResult hit) {
|
||||||
|
this.travelling = false;
|
||||||
|
this.noPhysics = false;
|
||||||
|
this.travelVelocity = Vec3.ZERO;
|
||||||
|
this.setDeltaMovement(Vec3.ZERO);
|
||||||
|
if (hit instanceof net.minecraft.world.phys.BlockHitResult blockHit) {
|
||||||
|
Vec3 normal = Vec3.atLowerCornerOf(blockHit.getDirection().getNormal());
|
||||||
|
this.setPos(blockHit.getLocation().add(normal.scale(0.05D)));
|
||||||
|
}
|
||||||
|
this.anchoredAtBlock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateFluidDrift() {
|
||||||
|
if (--this.flowTurnChangeTicks <= 0) {
|
||||||
|
this.flowTurnChangeTicks = 24 + this.random.nextInt(32);
|
||||||
|
this.flowTurnTarget = (this.random.nextDouble() * 2.0D - 1.0D) * 0.012D;
|
||||||
|
}
|
||||||
|
this.flowTurnRate = Mth.lerp(0.08D, this.flowTurnRate, this.flowTurnTarget);
|
||||||
|
Vec3 horizontal = new Vec3(this.travelVelocity.x, 0.0D, this.travelVelocity.z);
|
||||||
|
if (horizontal.lengthSqr() > 1.0E-6D) {
|
||||||
|
Vec3 turned = horizontal.yRot((float) this.flowTurnRate);
|
||||||
|
this.travelVelocity = new Vec3(turned.x, this.travelVelocity.y, turned.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void flowAroundBlock(HitResult hit) {
|
||||||
|
if (!(hit instanceof net.minecraft.world.phys.BlockHitResult blockHit)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 normal = Vec3.atLowerCornerOf(blockHit.getDirection().getNormal());
|
||||||
|
Vec3 incoming = this.travelVelocity.lengthSqr() > 1.0E-6D
|
||||||
|
? this.travelVelocity
|
||||||
|
: this.getDeltaMovement();
|
||||||
|
double speed = Mth.clamp(incoming.length(), 0.2D, 0.9D);
|
||||||
|
Vec3 flow = incoming;
|
||||||
|
if (normal.y > 0.5D) {
|
||||||
|
flow = new Vec3(incoming.x, 0.0D, incoming.z);
|
||||||
|
} else if (normal.y < -0.5D) {
|
||||||
|
flow = new Vec3(incoming.x, 0.0D, incoming.z).add(0.0D, -0.08D, 0.0D);
|
||||||
|
} else {
|
||||||
|
Vec3 tangent = incoming.subtract(normal.scale(incoming.dot(normal)));
|
||||||
|
if (tangent.lengthSqr() < 1.0E-6D) {
|
||||||
|
tangent = new Vec3(-normal.z, 0.0D, normal.x);
|
||||||
|
if (tangent.lengthSqr() < 1.0E-6D) {
|
||||||
|
tangent = new Vec3(0.0D, 0.0D, 1.0D);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flow = tangent.normalize().scale(speed);
|
||||||
|
}
|
||||||
|
if (flow.lengthSqr() < 1.0E-6D) {
|
||||||
|
this.travelVelocity = Vec3.ZERO;
|
||||||
|
this.setDeltaMovement(Vec3.ZERO);
|
||||||
|
this.travelling = false;
|
||||||
|
this.noPhysics = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setPos(blockHit.getLocation().add(normal.scale(0.08D)));
|
||||||
|
this.travelVelocity = flow.normalize().scale(speed * 0.82D);
|
||||||
|
this.setDeltaMovement(this.travelVelocity);
|
||||||
|
this.noPhysics = true;
|
||||||
|
if (--this.travelTicksRemaining <= 0) {
|
||||||
|
this.travelling = false;
|
||||||
|
this.noPhysics = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleEntityEvent(byte id) {
|
public void handleEntityEvent(byte id) {
|
||||||
if (id == 60) {
|
if (id == 60) {
|
||||||
@@ -431,18 +529,13 @@ public class WindVortexEntity extends Entity {
|
|||||||
updatedMovement = new Vec3(updatedMovement.x, Math.max(updatedMovement.y, minRise), updatedMovement.z);
|
updatedMovement = new Vec3(updatedMovement.x, Math.max(updatedMovement.y, minRise), updatedMovement.z);
|
||||||
entity.setOnGround(false);
|
entity.setOnGround(false);
|
||||||
}
|
}
|
||||||
|
entity.setDeltaMovement(updatedMovement);
|
||||||
if (entity instanceof Player) {
|
if (entity instanceof Player) {
|
||||||
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.setOnGround(false);
|
||||||
}
|
}
|
||||||
entity.setDeltaMovement(updatedMovement);
|
|
||||||
entity.fallDistance = 0.0F;
|
entity.fallDistance = 0.0F;
|
||||||
entity.hasImpulse = true;
|
entity.hasImpulse = true;
|
||||||
|
this.syncPlayerMotion(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void launch(Entity entity, Vec3 radialVector, double progress, Basis basis) {
|
private void launch(Entity entity, Vec3 radialVector, double progress, Basis basis) {
|
||||||
@@ -452,6 +545,7 @@ public class WindVortexEntity extends Entity {
|
|||||||
double scale = this.launchStrength * Mth.clamp(this.getVortexHeight() / 5.0D, 0.5D, 2.5D);
|
double scale = this.launchStrength * Mth.clamp(this.getVortexHeight() / 5.0D, 0.5D, 2.5D);
|
||||||
entity.setDeltaMovement(tangent.scale(0.72D * scale).add(radial.scale(0.34D * scale)).add(basis.axis.scale((0.78D + progress * 0.28D) * scale)));
|
entity.setDeltaMovement(tangent.scale(0.72D * scale).add(radial.scale(0.34D * scale)).add(basis.axis.scale((0.78D + progress * 0.28D) * scale)));
|
||||||
entity.hasImpulse = true;
|
entity.hasImpulse = true;
|
||||||
|
this.syncPlayerMotion(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void hurtCaughtEntity(Entity entity) {
|
private void hurtCaughtEntity(Entity entity) {
|
||||||
@@ -487,12 +581,20 @@ public class WindVortexEntity extends Entity {
|
|||||||
entity.fallDistance = 0.0F;
|
entity.fallDistance = 0.0F;
|
||||||
entity.hasImpulse = true;
|
entity.hasImpulse = true;
|
||||||
entity.hurtMarked = true;
|
entity.hurtMarked = true;
|
||||||
|
this.syncPlayerMotion(entity);
|
||||||
if (this.isDamaging() && entity instanceof LivingEntity living
|
if (this.isDamaging() && entity instanceof LivingEntity living
|
||||||
&& !living.getType().is(AntarchyTags.Entities.WIND_VORTEX_IMMUNE)) {
|
&& !living.getType().is(AntarchyTags.Entities.WIND_VORTEX_IMMUNE)) {
|
||||||
living.hurt(this.damageSource(), this.resolveDamage());
|
living.hurt(this.damageSource(), this.resolveDamage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void syncPlayerMotion(Entity entity) {
|
||||||
|
if (entity instanceof ServerPlayer player) {
|
||||||
|
player.hurtMarked = true;
|
||||||
|
player.connection.send(new ClientboundSetEntityMotionPacket(player));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private DamageSource damageSource() {
|
private DamageSource damageSource() {
|
||||||
Entity owner = this.getOwnerEntity();
|
Entity owner = this.getOwnerEntity();
|
||||||
if (owner instanceof LivingEntity living) {
|
if (owner instanceof LivingEntity living) {
|
||||||
@@ -582,6 +684,10 @@ public class WindVortexEntity extends Entity {
|
|||||||
this.homing = homing;
|
this.homing = homing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setBounceOnImpact(boolean bounceOnImpact) {
|
||||||
|
this.bounceOnImpact = bounceOnImpact;
|
||||||
|
}
|
||||||
|
|
||||||
public void setVortexStrengths(double pullStrength, double launchStrength) {
|
public void setVortexStrengths(double pullStrength, double launchStrength) {
|
||||||
this.pullStrength = Math.max(0.0D, pullStrength);
|
this.pullStrength = Math.max(0.0D, pullStrength);
|
||||||
this.launchStrength = Math.max(0.0D, launchStrength);
|
this.launchStrength = Math.max(0.0D, launchStrength);
|
||||||
@@ -630,6 +736,8 @@ public class WindVortexEntity extends Entity {
|
|||||||
this.setAxis(new Vec3(tag.getFloat(AXIS_X_KEY), tag.getFloat(AXIS_Y_KEY), tag.getFloat(AXIS_Z_KEY)));
|
this.setAxis(new Vec3(tag.getFloat(AXIS_X_KEY), tag.getFloat(AXIS_Y_KEY), tag.getFloat(AXIS_Z_KEY)));
|
||||||
this.travelling = tag.getBoolean(TRAVELLING_KEY);
|
this.travelling = tag.getBoolean(TRAVELLING_KEY);
|
||||||
this.homing = tag.getBoolean(HOMING_KEY);
|
this.homing = tag.getBoolean(HOMING_KEY);
|
||||||
|
this.bounceOnImpact = tag.getBoolean(BOUNCE_ON_IMPACT_KEY);
|
||||||
|
this.anchoredAtBlock = tag.getBoolean(ANCHORED_KEY);
|
||||||
this.travelVelocity = new Vec3(tag.getDouble(TRAVEL_X_KEY), tag.getDouble(TRAVEL_Y_KEY), tag.getDouble(TRAVEL_Z_KEY));
|
this.travelVelocity = new Vec3(tag.getDouble(TRAVEL_X_KEY), tag.getDouble(TRAVEL_Y_KEY), tag.getDouble(TRAVEL_Z_KEY));
|
||||||
if (this.travelling) {
|
if (this.travelling) {
|
||||||
this.noPhysics = true;
|
this.noPhysics = true;
|
||||||
@@ -654,6 +762,8 @@ public class WindVortexEntity extends Entity {
|
|||||||
tag.putFloat(AXIS_Z_KEY, (float) this.getAxis().z);
|
tag.putFloat(AXIS_Z_KEY, (float) this.getAxis().z);
|
||||||
tag.putBoolean(TRAVELLING_KEY, this.travelling);
|
tag.putBoolean(TRAVELLING_KEY, this.travelling);
|
||||||
tag.putBoolean(HOMING_KEY, this.homing);
|
tag.putBoolean(HOMING_KEY, this.homing);
|
||||||
|
tag.putBoolean(BOUNCE_ON_IMPACT_KEY, this.bounceOnImpact);
|
||||||
|
tag.putBoolean(ANCHORED_KEY, this.anchoredAtBlock);
|
||||||
tag.putDouble(TRAVEL_X_KEY, this.travelVelocity.x);
|
tag.putDouble(TRAVEL_X_KEY, this.travelVelocity.x);
|
||||||
tag.putDouble(TRAVEL_Y_KEY, this.travelVelocity.y);
|
tag.putDouble(TRAVEL_Y_KEY, this.travelVelocity.y);
|
||||||
tag.putDouble(TRAVEL_Z_KEY, this.travelVelocity.z);
|
tag.putDouble(TRAVEL_Z_KEY, this.travelVelocity.z);
|
||||||
|
|||||||
+53
-11
@@ -1,6 +1,8 @@
|
|||||||
package com.craisinlord.antarchy.content.gravity;
|
package com.craisinlord.antarchy.content.gravity;
|
||||||
|
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.world.entity.Mob;
|
import net.minecraft.world.entity.Mob;
|
||||||
import net.minecraft.world.level.PathNavigationRegion;
|
import net.minecraft.world.level.PathNavigationRegion;
|
||||||
import net.minecraft.world.level.pathfinder.Node;
|
import net.minecraft.world.level.pathfinder.Node;
|
||||||
@@ -9,6 +11,11 @@ import net.minecraft.world.level.pathfinder.PathfindingContext;
|
|||||||
import net.minecraft.world.level.pathfinder.WalkNodeEvaluator;
|
import net.minecraft.world.level.pathfinder.WalkNodeEvaluator;
|
||||||
|
|
||||||
public class GravityWalkNodeEvaluator extends WalkNodeEvaluator {
|
public class GravityWalkNodeEvaluator extends WalkNodeEvaluator {
|
||||||
|
private static final long LOG_TIME_THRESHOLD_NANOS = 25_000_000L;
|
||||||
|
|
||||||
|
private long antarchy$prepareStartNanos;
|
||||||
|
private int antarchy$nodeProbeCount;
|
||||||
|
|
||||||
private static final int[] START_Y_SEARCH = {0, 1, -1, 2, -2};
|
private static final int[] START_Y_SEARCH = {0, 1, -1, 2, -2};
|
||||||
private static final int[][] INVERTED_CARDINAL_NEIGHBOR_OFFSETS = {
|
private static final int[][] INVERTED_CARDINAL_NEIGHBOR_OFFSETS = {
|
||||||
{1, 0, 0},
|
{1, 0, 0},
|
||||||
@@ -26,10 +33,23 @@ public class GravityWalkNodeEvaluator extends WalkNodeEvaluator {
|
|||||||
@Override
|
@Override
|
||||||
public void prepare(PathNavigationRegion sourceIn, Mob mob) {
|
public void prepare(PathNavigationRegion sourceIn, Mob mob) {
|
||||||
super.prepare(sourceIn, mob);
|
super.prepare(sourceIn, mob);
|
||||||
|
this.antarchy$prepareStartNanos = System.nanoTime();
|
||||||
|
this.antarchy$nodeProbeCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void done() {
|
public void done() {
|
||||||
|
if (this.mob != null && AntarchyGravityApi.isGravityInverted(this.mob)) {
|
||||||
|
long elapsedNanos = System.nanoTime() - this.antarchy$prepareStartNanos;
|
||||||
|
if (elapsedNanos > LOG_TIME_THRESHOLD_NANOS) {
|
||||||
|
com.craisinlord.antarchy.Antarchy.LOGGER.warn(
|
||||||
|
"[antarchy-gravity] slow inverted pathfind: type={} uuid={} pos=({}, {}, {}) nodeProbes={} elapsedMs={}",
|
||||||
|
this.mob.getType(), this.mob.getUUID(),
|
||||||
|
this.mob.getX(), this.mob.getY(), this.mob.getZ(),
|
||||||
|
this.antarchy$nodeProbeCount, elapsedNanos / 1_000_000.0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
super.done();
|
super.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,10 +63,9 @@ public class GravityWalkNodeEvaluator extends WalkNodeEvaluator {
|
|||||||
int z = Mth.floor(this.mob.getZ());
|
int z = Mth.floor(this.mob.getZ());
|
||||||
int y = Mth.floor(this.mob.getY() + this.mob.getBbHeight()) - 1;
|
int y = Mth.floor(this.mob.getY() + this.mob.getBbHeight()) - 1;
|
||||||
Node node = this.antarchy$findStartNode(x, y, z);
|
Node node = this.antarchy$findStartNode(x, y, z);
|
||||||
if (node == null) {
|
// A floor-oriented start is a different coordinate model and must not
|
||||||
return super.getStart();
|
// be mixed into an inverted search. PathFinder treats null as a clean
|
||||||
}
|
// no-path result.
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +85,8 @@ public class GravityWalkNodeEvaluator extends WalkNodeEvaluator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Node antarchy$createStartNode(int x, int y, int z) {
|
private Node antarchy$createStartNode(int x, int y, int z) {
|
||||||
if (!this.antarchy$hasCeilingSupport(x, y, z)) {
|
this.antarchy$nodeProbeCount++;
|
||||||
|
if (!this.antarchy$hasCeilingSupport(this.currentContext, x, y, z)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,9 +102,16 @@ public class GravityWalkNodeEvaluator extends WalkNodeEvaluator {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean antarchy$hasCeilingSupport(int x, int y, int z) {
|
private boolean antarchy$hasCeilingSupport(PathfindingContext context, int x, int y, int z) {
|
||||||
PathType ceilingType = this.getPathType(this.currentContext, x, y + 1, z);
|
for (int dx = 0; dx < this.entityWidth; dx++) {
|
||||||
return this.mob.getPathfindingMalus(ceilingType) < 0.0F;
|
for (int dz = 0; dz < this.entityDepth; dz++) {
|
||||||
|
BlockPos ceilingPos = new BlockPos(x + dx, y + 1, z + dz);
|
||||||
|
if (!context.level().getBlockState(ceilingPos).isFaceSturdy(context.level(), ceilingPos, Direction.DOWN)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -93,8 +120,7 @@ public class GravityWalkNodeEvaluator extends WalkNodeEvaluator {
|
|||||||
return super.getPathTypeOfMob(context, x, y, z, mob);
|
return super.getPathTypeOfMob(context, x, y, z, mob);
|
||||||
}
|
}
|
||||||
|
|
||||||
PathType ceilingType = this.getPathType(context, x, y + 1, z);
|
if (!this.antarchy$hasCeilingSupport(context, x, y, z)) {
|
||||||
if (mob.getPathfindingMalus(ceilingType) >= 0.0F) {
|
|
||||||
return PathType.OPEN;
|
return PathType.OPEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,6 +171,18 @@ public class GravityWalkNodeEvaluator extends WalkNodeEvaluator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Relative "up" for an inverted mob is world-Y down. Keep both
|
||||||
|
// vertical directions available so a one-block ceiling step can be
|
||||||
|
// represented in the path instead of trapping the mob below it.
|
||||||
|
Node stepTowardInvertedUp = this.antarchy$getNeighbor(current.x, current.y - 1, current.z);
|
||||||
|
if (stepTowardInvertedUp != null) {
|
||||||
|
neighbors[count++] = stepTowardInvertedUp;
|
||||||
|
}
|
||||||
|
Node stepTowardInvertedDown = this.antarchy$getNeighbor(current.x, current.y + 1, current.z);
|
||||||
|
if (stepTowardInvertedDown != null) {
|
||||||
|
neighbors[count++] = stepTowardInvertedDown;
|
||||||
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,12 +197,16 @@ public class GravityWalkNodeEvaluator extends WalkNodeEvaluator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Node antarchy$getNeighbor(int x, int y, int z) {
|
private Node antarchy$getNeighbor(int x, int y, int z) {
|
||||||
|
this.antarchy$nodeProbeCount++;
|
||||||
PathType type = this.getPathTypeOfMob(this.currentContext, x, y, z, this.mob);
|
PathType type = this.getPathTypeOfMob(this.currentContext, x, y, z, this.mob);
|
||||||
if (this.mob.getPathfindingMalus(type) < 0.0F) {
|
if (type == PathType.OPEN || this.mob.getPathfindingMalus(type) < 0.0F) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node node = this.getNode(x, y, z);
|
Node node = this.getNode(x, y, z);
|
||||||
|
if (node.closed) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
node.type = type;
|
node.type = type;
|
||||||
node.costMalus = this.mob.getPathfindingMalus(type);
|
node.costMalus = this.mob.getPathfindingMalus(type);
|
||||||
return node;
|
return node;
|
||||||
|
|||||||
+1
@@ -137,6 +137,7 @@ public class EyeOfTheStormItem extends Item implements GeoItem {
|
|||||||
vortex.setDamageOverride(AntarchySettings.eyeOfTheStormSurgeDamage());
|
vortex.setDamageOverride(AntarchySettings.eyeOfTheStormSurgeDamage());
|
||||||
vortex.setTravel(dir.scale(SURGE_PROJECTILE_SPEED));
|
vortex.setTravel(dir.scale(SURGE_PROJECTILE_SPEED));
|
||||||
vortex.setHoming(true);
|
vortex.setHoming(true);
|
||||||
|
vortex.setBounceOnImpact(true);
|
||||||
level.addFreshEntity(vortex);
|
level.addFreshEntity(vortex);
|
||||||
|
|
||||||
level.playSound(null, origin.x, origin.y, origin.z,
|
level.playSound(null, origin.x, origin.y, origin.z,
|
||||||
|
|||||||
+2
@@ -79,12 +79,14 @@ public class KrakensGraspItem extends TridentItem {
|
|||||||
|
|
||||||
public static void strikeLightning(LivingEntity target, ServerLevel level) {
|
public static void strikeLightning(LivingEntity target, ServerLevel level) {
|
||||||
strikeLightningAt(level, target.getX(), target.getY(), target.getZ());
|
strikeLightningAt(level, target.getX(), target.getY(), target.getZ());
|
||||||
|
target.hurt(level.damageSources().lightningBolt(), (float) AntarchySettings.krakensGraspLightningDamage());
|
||||||
level.sendParticles(ParticleTypes.ELECTRIC_SPARK, target.getX(), target.getY(0.7D), target.getZ(), 10, 0.25D, 0.25D, 0.25D, 0.02D);
|
level.sendParticles(ParticleTypes.ELECTRIC_SPARK, target.getX(), target.getY(0.7D), target.getZ(), 10, 0.25D, 0.25D, 0.25D, 0.02D);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void strikeLightningAt(ServerLevel level, double x, double y, double z) {
|
public static void strikeLightningAt(ServerLevel level, double x, double y, double z) {
|
||||||
LightningBolt lightningBolt = new LightningBolt(net.minecraft.world.entity.EntityType.LIGHTNING_BOLT, level);
|
LightningBolt lightningBolt = new LightningBolt(net.minecraft.world.entity.EntityType.LIGHTNING_BOLT, level);
|
||||||
lightningBolt.moveTo(x, y, z);
|
lightningBolt.moveTo(x, y, z);
|
||||||
|
lightningBolt.setVisualOnly(true);
|
||||||
level.addFreshEntity(lightningBolt);
|
level.addFreshEntity(lightningBolt);
|
||||||
level.sendParticles(ParticleTypes.ELECTRIC_SPARK, x, y + 0.2D, z, 10, 0.25D, 0.25D, 0.25D, 0.02D);
|
level.sendParticles(ParticleTypes.ELECTRIC_SPARK, x, y + 0.2D, z, 10, 0.25D, 0.25D, 0.25D, 0.02D);
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-2
@@ -21,7 +21,9 @@ import net.minecraft.world.level.Level;
|
|||||||
public final class ManticoreWingsItem extends ElytraItem {
|
public final class ManticoreWingsItem extends ElytraItem {
|
||||||
private static final ResourceLocation REPAIR_MATERIAL_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "manticore_wing");
|
private static final ResourceLocation REPAIR_MATERIAL_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "manticore_wing");
|
||||||
private static final int DAMAGE_COOLDOWN_TICKS = 10;
|
private static final int DAMAGE_COOLDOWN_TICKS = 10;
|
||||||
private static final float COLLISION_DAMAGE = 8.0F;
|
private static final double MIN_COLLISION_SPEED = 0.2D;
|
||||||
|
private static final float COLLISION_DAMAGE_PER_BLOCK_PER_TICK = 8.0F;
|
||||||
|
private static final float MAX_COLLISION_DAMAGE = 20.0F;
|
||||||
private static final Map<UUID, Long> LAST_COLLISION_DAMAGE = new ConcurrentHashMap<>();
|
private static final Map<UUID, Long> LAST_COLLISION_DAMAGE = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public ManticoreWingsItem(Properties properties) {
|
public ManticoreWingsItem(Properties properties) {
|
||||||
@@ -41,10 +43,16 @@ public final class ManticoreWingsItem extends ElytraItem {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
long gameTime = level.getGameTime();
|
long gameTime = level.getGameTime();
|
||||||
|
double speed = player.getDeltaMovement().length();
|
||||||
|
if (speed < MIN_COLLISION_SPEED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
float collisionDamage = Math.min(MAX_COLLISION_DAMAGE,
|
||||||
|
Math.max(1.0F, (float) speed * COLLISION_DAMAGE_PER_BLOCK_PER_TICK));
|
||||||
for (LivingEntity target : level.getEntitiesOfClass(LivingEntity.class, player.getBoundingBox().inflate(0.45D), living ->
|
for (LivingEntity target : level.getEntitiesOfClass(LivingEntity.class, player.getBoundingBox().inflate(0.45D), living ->
|
||||||
living != player && living.isAlive() && !player.isAlliedTo(living) && !living.isAlliedTo(player))) {
|
living != player && living.isAlive() && !player.isAlliedTo(living) && !living.isAlliedTo(player))) {
|
||||||
long availableAt = LAST_COLLISION_DAMAGE.getOrDefault(target.getUUID(), 0L);
|
long availableAt = LAST_COLLISION_DAMAGE.getOrDefault(target.getUUID(), 0L);
|
||||||
if (availableAt <= gameTime && target.hurt(level.damageSources().playerAttack(player), COLLISION_DAMAGE)) {
|
if (availableAt <= gameTime && target.hurt(level.damageSources().playerAttack(player), collisionDamage)) {
|
||||||
LAST_COLLISION_DAMAGE.put(target.getUUID(), gameTime + DAMAGE_COOLDOWN_TICKS);
|
LAST_COLLISION_DAMAGE.put(target.getUUID(), gameTime + DAMAGE_COOLDOWN_TICKS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
@@ -1,5 +1,6 @@
|
|||||||
package com.craisinlord.antarchy.content.item;
|
package com.craisinlord.antarchy.content.item;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||||
import com.craisinlord.antarchy.content.item.royal.RoyalGearHelper;
|
import com.craisinlord.antarchy.content.item.royal.RoyalGearHelper;
|
||||||
@@ -142,8 +143,18 @@ public class RoyalAssailantArmorItem extends ArmorItem {
|
|||||||
}
|
}
|
||||||
MobEffectInstance existing = player.getEffect(AntarchyObjects.INVERTED_EFFECT.get());
|
MobEffectInstance existing = player.getEffect(AntarchyObjects.INVERTED_EFFECT.get());
|
||||||
if (existing != null && existing.isInfiniteDuration()) {
|
if (existing != null && existing.isInfiniteDuration()) {
|
||||||
|
Antarchy.LOGGER.info(
|
||||||
|
"[antarchy-gravity] royal chestplate toggling inversion off player={} uuid={} pos=({}, {}, {}) dim={} existingDuration={} gameTime={}",
|
||||||
|
player.getGameProfile().getName(), player.getUUID(), player.getX(), player.getY(), player.getZ(),
|
||||||
|
player.level().dimension().location(), existing.getDuration(), player.level().getGameTime()
|
||||||
|
);
|
||||||
player.removeEffect(AntarchyObjects.INVERTED_EFFECT.get());
|
player.removeEffect(AntarchyObjects.INVERTED_EFFECT.get());
|
||||||
} else {
|
} else {
|
||||||
|
Antarchy.LOGGER.info(
|
||||||
|
"[antarchy-gravity] royal chestplate toggling inversion on player={} uuid={} pos=({}, {}, {}) dim={} existingDuration={} gameTime={}",
|
||||||
|
player.getGameProfile().getName(), player.getUUID(), player.getX(), player.getY(), player.getZ(),
|
||||||
|
player.level().dimension().location(), existing != null ? existing.getDuration() : -1, player.level().getGameTime()
|
||||||
|
);
|
||||||
player.addEffect(new MobEffectInstance(AntarchyObjects.INVERTED_EFFECT.get(), -1, 0, false, false, true));
|
player.addEffect(new MobEffectInstance(AntarchyObjects.INVERTED_EFFECT.get(), -1, 0, false, false, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
@@ -65,6 +65,18 @@ public final class TimeDilationApi {
|
|||||||
SYNCED_CLIENT_RATES.put(entityUuid, clampedRate);
|
SYNCED_CLIENT_RATES.put(entityUuid, clampedRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Clears both the authoritative entity state and any client-side UUID cache. */
|
||||||
|
public static void clearRate(Entity entity) {
|
||||||
|
if (entity instanceof TimeDilationEntityAccess access) {
|
||||||
|
boolean wasDilated = access.antarchy$getTimeDilationRate() < TimeDilationMath.NORMAL_RATE;
|
||||||
|
access.antarchy$setTimeDilationRate(TimeDilationMath.NORMAL_RATE);
|
||||||
|
if (wasDilated) {
|
||||||
|
syncEntityRate(entity, TimeDilationMath.NORMAL_RATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SYNCED_CLIENT_RATES.remove(entity.getUUID());
|
||||||
|
}
|
||||||
|
|
||||||
public static void clearSyncedClientRates() {
|
public static void clearSyncedClientRates() {
|
||||||
SYNCED_CLIENT_RATES.clear();
|
SYNCED_CLIENT_RATES.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-31
@@ -1,19 +1,16 @@
|
|||||||
package com.craisinlord.antarchy.content.time;
|
package com.craisinlord.antarchy.content.time;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.level.Level;
|
import com.craisinlord.antarchy.content.effect.DilatedMobEffect;
|
||||||
|
import com.craisinlord.antarchy.content.effect.RoyalEffectEligibility;
|
||||||
|
import com.craisinlord.antarchy.content.effect.RoyalEffectHooks;
|
||||||
|
|
||||||
public final class TimeDilationManager {
|
public final class TimeDilationManager {
|
||||||
private static final Set<ResourceKey<Level>> DILATED_LEVELS = new HashSet<>();
|
|
||||||
|
|
||||||
private TimeDilationManager() {
|
private TimeDilationManager() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,17 +18,12 @@ public final class TimeDilationManager {
|
|||||||
for (ServerLevel level : server.getAllLevels()) {
|
for (ServerLevel level : server.getAllLevels()) {
|
||||||
List<TimeDilationFieldEntity> fields = collectFields(level);
|
List<TimeDilationFieldEntity> fields = collectFields(level);
|
||||||
syncFieldSnapshots(level, fields);
|
syncFieldSnapshots(level, fields);
|
||||||
if (fields.isEmpty()) {
|
|
||||||
if (DILATED_LEVELS.remove(level.dimension())) {
|
|
||||||
resetRates(level);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
DILATED_LEVELS.add(level.dimension());
|
|
||||||
updateEntities(level, fields);
|
updateEntities(level, fields);
|
||||||
|
if (!fields.isEmpty()) {
|
||||||
TimeDilationParticles.spawnFieldBorders(level, fields);
|
TimeDilationParticles.spawnFieldBorders(level, fields);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void syncFieldSnapshots(ServerLevel level, List<TimeDilationFieldEntity> fields) {
|
private static void syncFieldSnapshots(ServerLevel level, List<TimeDilationFieldEntity> fields) {
|
||||||
List<TimeDilationFieldSnapshot> snapshots = fields.stream()
|
List<TimeDilationFieldSnapshot> snapshots = fields.stream()
|
||||||
@@ -60,32 +52,30 @@ public final class TimeDilationManager {
|
|||||||
if (!(entity instanceof TimeDilationEntityAccess access) || entity instanceof TimeDilationFieldEntity) {
|
if (!(entity instanceof TimeDilationEntityAccess access) || entity instanceof TimeDilationFieldEntity) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (entity.getType().is(com.craisinlord.antarchy.content.AntarchyTags.Entities.TIME_DILATION_IMMUNE)) {
|
if (entity.getType().is(com.craisinlord.antarchy.content.AntarchyTags.Entities.TIME_DILATION_IMMUNE)
|
||||||
if (access.antarchy$getTimeDilationRate() < TimeDilationMath.NORMAL_RATE) {
|
|| (entity instanceof net.minecraft.world.entity.LivingEntity living && !RoyalEffectEligibility.canApplyDilated(living))) {
|
||||||
access.antarchy$setTimeDilationRate(TimeDilationMath.NORMAL_RATE);
|
if (RoyalEffectHooks.dilatedHolder() != null && entity instanceof net.minecraft.world.entity.LivingEntity living) {
|
||||||
TimeDilationApi.syncEntityRate(entity, TimeDilationMath.NORMAL_RATE);
|
living.removeEffect(RoyalEffectHooks.dilatedHolder());
|
||||||
}
|
}
|
||||||
|
TimeDilationApi.clearRate(entity);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
double previousRate = access.antarchy$getTimeDilationRate();
|
double previousRate = access.antarchy$getTimeDilationRate();
|
||||||
double rate = TimeDilationFieldSampler.sample(fields, entity.position());
|
double fieldRate = TimeDilationFieldSampler.sample(fields, entity.position());
|
||||||
|
double effectRate = RoyalEffectHooks.dilatedHolder() != null
|
||||||
|
&& entity instanceof net.minecraft.world.entity.LivingEntity living
|
||||||
|
&& living.hasEffect(RoyalEffectHooks.dilatedHolder())
|
||||||
|
? DilatedMobEffect.RATE : TimeDilationMath.NORMAL_RATE;
|
||||||
|
double rate = Math.min(fieldRate, effectRate);
|
||||||
|
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||||
|
TimeDilationApi.clearRate(entity);
|
||||||
|
} else {
|
||||||
access.antarchy$setTimeDilationRate(rate);
|
access.antarchy$setTimeDilationRate(rate);
|
||||||
if (Math.abs(previousRate - rate) > 0.001D) {
|
}
|
||||||
|
if (rate < TimeDilationMath.NORMAL_RATE && Math.abs(previousRate - rate) > 0.001D) {
|
||||||
TimeDilationApi.syncEntityRate(entity, rate);
|
TimeDilationApi.syncEntityRate(entity, rate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void resetRates(ServerLevel level) {
|
|
||||||
for (Entity entity : level.getAllEntities()) {
|
|
||||||
if (!(entity instanceof TimeDilationEntityAccess access) || entity instanceof TimeDilationFieldEntity) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (access.antarchy$getTimeDilationRate() >= TimeDilationMath.NORMAL_RATE) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
access.antarchy$setTimeDilationRate(TimeDilationMath.NORMAL_RATE);
|
|
||||||
TimeDilationApi.syncEntityRate(entity, TimeDilationMath.NORMAL_RATE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+40
-25
@@ -20,6 +20,8 @@ import net.minecraft.world.level.levelgen.Heightmap;
|
|||||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||||
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
|
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
||||||
private static final String SIZEABLE_FOLIAGE_MODID = "sizeable_foliage";
|
private static final String SIZEABLE_FOLIAGE_MODID = "sizeable_foliage";
|
||||||
@@ -38,6 +40,8 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
|||||||
WorldGenLevel level = context.level();
|
WorldGenLevel level = context.level();
|
||||||
RandomSource random = context.random();
|
RandomSource random = context.random();
|
||||||
BlockPos origin = context.origin();
|
BlockPos origin = context.origin();
|
||||||
|
Map<Long, Integer> surfaceHeightCache = new HashMap<>();
|
||||||
|
Map<Long, Integer> oceanFloorHeightCache = new HashMap<>();
|
||||||
int attempts = switch (this.variant) {
|
int attempts = switch (this.variant) {
|
||||||
case FOREST -> 185;
|
case FOREST -> 185;
|
||||||
case MEADOW -> 95;
|
case MEADOW -> 95;
|
||||||
@@ -68,7 +72,7 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
|||||||
case FLOWER_FOREST_MILKWEED -> 0.0F;
|
case FLOWER_FOREST_MILKWEED -> 0.0F;
|
||||||
};
|
};
|
||||||
if (random.nextFloat() < torchflowerChance) {
|
if (random.nextFloat() < torchflowerChance) {
|
||||||
placedAny |= this.placeTorchflowerPatch(level, origin, random);
|
placedAny |= this.placeTorchflowerPatch(level, origin, random, surfaceHeightCache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +83,7 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
|||||||
case FOREST -> 0.05F;
|
case FOREST -> 0.05F;
|
||||||
case FLOWER_FOREST_MILKWEED -> 0.0F;
|
case FLOWER_FOREST_MILKWEED -> 0.0F;
|
||||||
}) {
|
}) {
|
||||||
placedAny |= this.placePitcherPatch(level, origin, random);
|
placedAny |= this.placePitcherPatch(level, origin, random, surfaceHeightCache);
|
||||||
}
|
}
|
||||||
if (random.nextFloat() < switch (this.variant) {
|
if (random.nextFloat() < switch (this.variant) {
|
||||||
case MEADOW -> 0.16F;
|
case MEADOW -> 0.16F;
|
||||||
@@ -88,7 +92,7 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
|||||||
case FOREST -> 0.06F;
|
case FOREST -> 0.06F;
|
||||||
case FLOWER_FOREST_MILKWEED -> 0.18F;
|
case FLOWER_FOREST_MILKWEED -> 0.18F;
|
||||||
}) {
|
}) {
|
||||||
placedAny |= this.placeMilkweedPatch(level, origin, random, AntarchyObjects.ORANGE_MILKWEED.get());
|
placedAny |= this.placeMilkweedPatch(level, origin, random, AntarchyObjects.ORANGE_MILKWEED.get(), surfaceHeightCache);
|
||||||
}
|
}
|
||||||
if (random.nextFloat() < switch (this.variant) {
|
if (random.nextFloat() < switch (this.variant) {
|
||||||
case MEADOW -> 0.16F;
|
case MEADOW -> 0.16F;
|
||||||
@@ -97,20 +101,20 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
|||||||
case FOREST -> 0.06F;
|
case FOREST -> 0.06F;
|
||||||
case FLOWER_FOREST_MILKWEED -> 0.18F;
|
case FLOWER_FOREST_MILKWEED -> 0.18F;
|
||||||
}) {
|
}) {
|
||||||
placedAny |= this.placeMilkweedPatch(level, origin, random, AntarchyObjects.PINK_MILKWEED.get());
|
placedAny |= this.placeMilkweedPatch(level, origin, random, AntarchyObjects.PINK_MILKWEED.get(), surfaceHeightCache);
|
||||||
}
|
}
|
||||||
if (this.variant == Variant.PEACH_FOREST && random.nextFloat() < 0.14F) {
|
if (this.variant == Variant.PEACH_FOREST && random.nextFloat() < 0.14F) {
|
||||||
placedAny |= this.placeMilkweedPatch(level, origin, random, antarchyBlock(CAMELLIA_ID));
|
placedAny |= this.placeMilkweedPatch(level, origin, random, antarchyBlock(CAMELLIA_ID), surfaceHeightCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.variant == Variant.FOREST || this.variant == Variant.PEACH_FOREST) {
|
if (this.variant == Variant.FOREST || this.variant == Variant.PEACH_FOREST) {
|
||||||
placedAny |= this.placeBigBushes(level, origin, random, radius);
|
placedAny |= this.placeBigBushes(level, origin, random, radius, surfaceHeightCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < attempts; i++) {
|
for (int i = 0; i < attempts; i++) {
|
||||||
int x = origin.getX() + random.nextInt(radius * 2 + 1) - radius;
|
int x = origin.getX() + random.nextInt(radius * 2 + 1) - radius;
|
||||||
int z = origin.getZ() + random.nextInt(radius * 2 + 1) - radius;
|
int z = origin.getZ() + random.nextInt(radius * 2 + 1) - radius;
|
||||||
int y = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, x, z);
|
int y = cachedHeight(level, Heightmap.Types.WORLD_SURFACE_WG, x, z, surfaceHeightCache);
|
||||||
BlockPos plantPos = new BlockPos(x, y, z);
|
BlockPos plantPos = new BlockPos(x, y, z);
|
||||||
BlockPos groundPos = plantPos.below();
|
BlockPos groundPos = plantPos.below();
|
||||||
|
|
||||||
@@ -125,7 +129,7 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
placedAny |= this.placeSeagrass(level, origin, random, radius);
|
placedAny |= this.placeSeagrass(level, origin, random, radius, oceanFloorHeightCache);
|
||||||
|
|
||||||
return placedAny;
|
return placedAny;
|
||||||
}
|
}
|
||||||
@@ -227,7 +231,7 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
|||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean placeBigBushes(WorldGenLevel level, BlockPos origin, RandomSource random, int radius) {
|
private boolean placeBigBushes(WorldGenLevel level, BlockPos origin, RandomSource random, int radius, Map<Long, Integer> surfaceHeightCache) {
|
||||||
Block bushBlock = BuiltInRegistries.BLOCK.get(ResourceLocation.fromNamespaceAndPath(SIZEABLE_FOLIAGE_MODID, "big_bush"));
|
Block bushBlock = BuiltInRegistries.BLOCK.get(ResourceLocation.fromNamespaceAndPath(SIZEABLE_FOLIAGE_MODID, "big_bush"));
|
||||||
if (!(bushBlock instanceof BigBushBlock)) {
|
if (!(bushBlock instanceof BigBushBlock)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -241,7 +245,7 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
|||||||
for (int i = 0; i < bushAttempts; i++) {
|
for (int i = 0; i < bushAttempts; i++) {
|
||||||
int x = origin.getX() + random.nextInt(radius * 2 + 1) - radius;
|
int x = origin.getX() + random.nextInt(radius * 2 + 1) - radius;
|
||||||
int z = origin.getZ() + random.nextInt(radius * 2 + 1) - radius;
|
int z = origin.getZ() + random.nextInt(radius * 2 + 1) - radius;
|
||||||
int y = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, x, z);
|
int y = cachedHeight(level, Heightmap.Types.WORLD_SURFACE_WG, x, z, surfaceHeightCache);
|
||||||
BlockPos plantPos = new BlockPos(x, y, z);
|
BlockPos plantPos = new BlockPos(x, y, z);
|
||||||
|
|
||||||
if (!isValidPlantSpot(level, plantPos, plantPos.below())) {
|
if (!isValidPlantSpot(level, plantPos, plantPos.below())) {
|
||||||
@@ -333,8 +337,8 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean placeTorchflowerPatch(WorldGenLevel level, BlockPos origin, RandomSource random) {
|
private boolean placeTorchflowerPatch(WorldGenLevel level, BlockPos origin, RandomSource random, Map<Long, Integer> surfaceHeightCache) {
|
||||||
BlockPos patchCenter = sampleSurface(level, origin, random, this.variant == Variant.FOREST ? 8 : 12);
|
BlockPos patchCenter = sampleSurface(level, origin, random, this.variant == Variant.FOREST ? 8 : 12, surfaceHeightCache);
|
||||||
if (patchCenter == null) {
|
if (patchCenter == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -346,7 +350,7 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
|||||||
boolean bushEligible = this.variant == Variant.FOREST || this.variant == Variant.MEADOW;
|
boolean bushEligible = this.variant == Variant.FOREST || this.variant == Variant.MEADOW;
|
||||||
boolean placed = false;
|
boolean placed = false;
|
||||||
for (int i = 0; i < plants; i++) {
|
for (int i = 0; i < plants; i++) {
|
||||||
BlockPos plantPos = samplePatchPos(level, patchCenter, radius, random);
|
BlockPos plantPos = samplePatchPos(level, patchCenter, radius, random, surfaceHeightCache);
|
||||||
if (plantPos == null) {
|
if (plantPos == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -369,8 +373,8 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
|||||||
return placed;
|
return placed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean placePitcherPatch(WorldGenLevel level, BlockPos origin, RandomSource random) {
|
private boolean placePitcherPatch(WorldGenLevel level, BlockPos origin, RandomSource random, Map<Long, Integer> surfaceHeightCache) {
|
||||||
BlockPos patchCenter = sampleSurface(level, origin, random, this.variant == Variant.FOREST ? 8 : 13);
|
BlockPos patchCenter = sampleSurface(level, origin, random, this.variant == Variant.FOREST ? 8 : 13, surfaceHeightCache);
|
||||||
if (patchCenter == null) {
|
if (patchCenter == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -379,7 +383,7 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
|||||||
int plants = this.variant == Variant.BUTTERFLY_FIELDS ? 10 + random.nextInt(12) : this.variant == Variant.FLOWER_FOREST_MILKWEED ? 2 + random.nextInt(3) : 5 + random.nextInt(11);
|
int plants = this.variant == Variant.BUTTERFLY_FIELDS ? 10 + random.nextInt(12) : this.variant == Variant.FLOWER_FOREST_MILKWEED ? 2 + random.nextInt(3) : 5 + random.nextInt(11);
|
||||||
boolean placed = false;
|
boolean placed = false;
|
||||||
for (int i = 0; i < plants; i++) {
|
for (int i = 0; i < plants; i++) {
|
||||||
BlockPos plantPos = samplePatchPos(level, patchCenter, radius, random);
|
BlockPos plantPos = samplePatchPos(level, patchCenter, radius, random, surfaceHeightCache);
|
||||||
if (plantPos == null) {
|
if (plantPos == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -396,8 +400,8 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
|||||||
return placed;
|
return placed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean placeMilkweedPatch(WorldGenLevel level, BlockPos origin, RandomSource random, Block flower) {
|
private boolean placeMilkweedPatch(WorldGenLevel level, BlockPos origin, RandomSource random, Block flower, Map<Long, Integer> surfaceHeightCache) {
|
||||||
BlockPos patchCenter = sampleSurface(level, origin, random, this.variant == Variant.FOREST ? 8 : 13);
|
BlockPos patchCenter = sampleSurface(level, origin, random, this.variant == Variant.FOREST ? 8 : 13, surfaceHeightCache);
|
||||||
if (patchCenter == null) {
|
if (patchCenter == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -406,7 +410,7 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
|||||||
int plants = this.variant == Variant.BUTTERFLY_FIELDS ? 14 + random.nextInt(16) : this.variant == Variant.FLOWER_FOREST_MILKWEED ? 2 + random.nextInt(4) : 4 + random.nextInt(9);
|
int plants = this.variant == Variant.BUTTERFLY_FIELDS ? 14 + random.nextInt(16) : this.variant == Variant.FLOWER_FOREST_MILKWEED ? 2 + random.nextInt(4) : 4 + random.nextInt(9);
|
||||||
boolean placed = false;
|
boolean placed = false;
|
||||||
for (int i = 0; i < plants; i++) {
|
for (int i = 0; i < plants; i++) {
|
||||||
BlockPos plantPos = samplePatchPos(level, patchCenter, radius, random);
|
BlockPos plantPos = samplePatchPos(level, patchCenter, radius, random, surfaceHeightCache);
|
||||||
if (plantPos == null) {
|
if (plantPos == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -423,7 +427,7 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
|||||||
return placed;
|
return placed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean placeSeagrass(WorldGenLevel level, BlockPos origin, RandomSource random, int radius) {
|
private boolean placeSeagrass(WorldGenLevel level, BlockPos origin, RandomSource random, int radius, Map<Long, Integer> oceanFloorHeightCache) {
|
||||||
int attempts = switch (this.variant) {
|
int attempts = switch (this.variant) {
|
||||||
case FOREST -> 3;
|
case FOREST -> 3;
|
||||||
case MEADOW -> 5;
|
case MEADOW -> 5;
|
||||||
@@ -436,7 +440,7 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
|||||||
for (int i = 0; i < attempts; i++) {
|
for (int i = 0; i < attempts; i++) {
|
||||||
int x = origin.getX() + random.nextInt(radius * 2 + 1) - radius;
|
int x = origin.getX() + random.nextInt(radius * 2 + 1) - radius;
|
||||||
int z = origin.getZ() + random.nextInt(radius * 2 + 1) - radius;
|
int z = origin.getZ() + random.nextInt(radius * 2 + 1) - radius;
|
||||||
int y = level.getHeight(Heightmap.Types.OCEAN_FLOOR_WG, x, z);
|
int y = cachedHeight(level, Heightmap.Types.OCEAN_FLOOR_WG, x, z, oceanFloorHeightCache);
|
||||||
BlockPos seagrassPos = new BlockPos(x, y, z);
|
BlockPos seagrassPos = new BlockPos(x, y, z);
|
||||||
BlockPos floorPos = seagrassPos.below();
|
BlockPos floorPos = seagrassPos.below();
|
||||||
|
|
||||||
@@ -455,11 +459,11 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
|||||||
return placed;
|
return placed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BlockPos sampleSurface(WorldGenLevel level, BlockPos origin, RandomSource random, int radius) {
|
private static BlockPos sampleSurface(WorldGenLevel level, BlockPos origin, RandomSource random, int radius, Map<Long, Integer> surfaceHeightCache) {
|
||||||
for (int attempt = 0; attempt < 8; attempt++) {
|
for (int attempt = 0; attempt < 8; attempt++) {
|
||||||
int x = origin.getX() + random.nextInt(radius * 2 + 1) - radius;
|
int x = origin.getX() + random.nextInt(radius * 2 + 1) - radius;
|
||||||
int z = origin.getZ() + random.nextInt(radius * 2 + 1) - radius;
|
int z = origin.getZ() + random.nextInt(radius * 2 + 1) - radius;
|
||||||
int y = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, x, z);
|
int y = cachedHeight(level, Heightmap.Types.WORLD_SURFACE_WG, x, z, surfaceHeightCache);
|
||||||
BlockPos plantPos = new BlockPos(x, y, z);
|
BlockPos plantPos = new BlockPos(x, y, z);
|
||||||
if (isValidPlantSpot(level, plantPos, plantPos.below())) {
|
if (isValidPlantSpot(level, plantPos, plantPos.below())) {
|
||||||
return plantPos;
|
return plantPos;
|
||||||
@@ -468,14 +472,25 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BlockPos samplePatchPos(WorldGenLevel level, BlockPos center, int radius, RandomSource random) {
|
private static BlockPos samplePatchPos(WorldGenLevel level, BlockPos center, int radius, RandomSource random, Map<Long, Integer> surfaceHeightCache) {
|
||||||
int x = center.getX() + random.nextInt(radius * 2 + 1) - radius;
|
int x = center.getX() + random.nextInt(radius * 2 + 1) - radius;
|
||||||
int z = center.getZ() + random.nextInt(radius * 2 + 1) - radius;
|
int z = center.getZ() + random.nextInt(radius * 2 + 1) - radius;
|
||||||
int y = level.getHeight(Heightmap.Types.WORLD_SURFACE_WG, x, z);
|
int y = cachedHeight(level, Heightmap.Types.WORLD_SURFACE_WG, x, z, surfaceHeightCache);
|
||||||
BlockPos plantPos = new BlockPos(x, y, z);
|
BlockPos plantPos = new BlockPos(x, y, z);
|
||||||
return isOpenPlantSpot(level, plantPos) ? plantPos : null;
|
return isOpenPlantSpot(level, plantPos) ? plantPos : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int cachedHeight(WorldGenLevel level, Heightmap.Types type, int x, int z, Map<Long, Integer> cache) {
|
||||||
|
long key = ((long) x << 32) ^ (z & 0xFFFFFFFFL);
|
||||||
|
Integer cached = cache.get(key);
|
||||||
|
if (cached != null) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
int height = level.getHeight(type, x, z);
|
||||||
|
cache.put(key, height);
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
private static void normalizePeachForestGround(WorldGenLevel level, BlockPos groundPos, Variant variant) {
|
private static void normalizePeachForestGround(WorldGenLevel level, BlockPos groundPos, Variant variant) {
|
||||||
if (variant != Variant.PEACH_FOREST) {
|
if (variant != Variant.PEACH_FOREST) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
+57
-10
@@ -7,7 +7,10 @@ import com.craisinlord.antarchy.content.block.OuranwoodLeavesBlock;
|
|||||||
import com.craisinlord.antarchy.content.entity.flying_squirrel.FlyingSquirrelEntity;
|
import com.craisinlord.antarchy.content.entity.flying_squirrel.FlyingSquirrelEntity;
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
@@ -1113,29 +1116,76 @@ public class OuranwoodTreeFeature extends Feature<OuranwoodTreeConfiguration> {
|
|||||||
int minY = Math.max(level.getMinBuildHeight(), origin.getY() - 2);
|
int minY = Math.max(level.getMinBuildHeight(), origin.getY() - 2);
|
||||||
int maxY = Math.min(level.getMaxBuildHeight() - 1, origin.getY() + height + canopyDepth + 8);
|
int maxY = Math.min(level.getMaxBuildHeight() - 1, origin.getY() + height + canopyDepth + 8);
|
||||||
List<BlockPos> leafPositions = new ArrayList<>();
|
List<BlockPos> leafPositions = new ArrayList<>();
|
||||||
|
Map<BlockPos, Integer> distances = new HashMap<>();
|
||||||
|
ArrayDeque<BlockPos> queue = new ArrayDeque<>();
|
||||||
BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos();
|
BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos();
|
||||||
|
|
||||||
for (int x = origin.getX() - horizontalRadius; x <= origin.getX() + horizontalRadius; x++) {
|
for (int x = origin.getX() - horizontalRadius; x <= origin.getX() + horizontalRadius; x++) {
|
||||||
for (int z = origin.getZ() - horizontalRadius; z <= origin.getZ() + horizontalRadius; z++) {
|
for (int z = origin.getZ() - horizontalRadius; z <= origin.getZ() + horizontalRadius; z++) {
|
||||||
for (int y = minY; y <= maxY; y++) {
|
for (int y = minY; y <= maxY; y++) {
|
||||||
cursor.set(x, y, z);
|
cursor.set(x, y, z);
|
||||||
if (level.getBlockState(cursor).getBlock() instanceof LeavesBlock) {
|
BlockState state = level.getBlockState(cursor);
|
||||||
leafPositions.add(cursor.immutable());
|
if (state.getBlock() instanceof LeavesBlock && this.getLeafDistanceProperty(state) != null) {
|
||||||
|
BlockPos pos = cursor.immutable();
|
||||||
|
leafPositions.add(pos);
|
||||||
|
distances.put(pos, this.getLeafDistanceLimit(state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int pass = 1; pass <= 16; pass++) {
|
|
||||||
boolean anyChanged = false;
|
|
||||||
for (BlockPos pos : leafPositions) {
|
for (BlockPos pos : leafPositions) {
|
||||||
BlockState state = level.getBlockState(pos);
|
BlockState state = level.getBlockState(pos);
|
||||||
IntegerProperty distanceProperty = this.getLeafDistanceProperty(state);
|
int limit = this.getLeafDistanceLimit(state);
|
||||||
if (!(state.getBlock() instanceof LeavesBlock) || distanceProperty == null) {
|
int bestDistance = limit;
|
||||||
|
for (Direction direction : Direction.values()) {
|
||||||
|
BlockPos neighborPos = pos.relative(direction);
|
||||||
|
BlockState neighbor = level.getBlockState(neighborPos);
|
||||||
|
if (neighbor.is(BlockTags.LOGS)) {
|
||||||
|
bestDistance = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!distances.containsKey(neighborPos)) {
|
||||||
|
IntegerProperty neighborProperty = this.getLeafDistanceProperty(neighbor);
|
||||||
|
if (neighborProperty != null) {
|
||||||
|
bestDistance = Math.min(bestDistance, neighbor.getValue(neighborProperty) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bestDistance < distances.get(pos)) {
|
||||||
|
distances.put(pos, bestDistance);
|
||||||
|
queue.add(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
BlockPos pos = queue.removeFirst();
|
||||||
|
int distance = distances.get(pos);
|
||||||
|
for (Direction direction : Direction.values()) {
|
||||||
|
BlockPos neighborPos = pos.relative(direction);
|
||||||
|
Integer neighborDistance = distances.get(neighborPos);
|
||||||
|
if (neighborDistance == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int computedDistance = this.computeLeafDistance(level, pos, state);
|
BlockState neighborState = level.getBlockState(neighborPos);
|
||||||
|
int candidate = Math.min(this.getLeafDistanceLimit(neighborState), distance + 1);
|
||||||
|
if (candidate < neighborDistance) {
|
||||||
|
distances.put(neighborPos, candidate);
|
||||||
|
queue.addLast(neighborPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BlockPos pos : leafPositions) {
|
||||||
|
BlockState state = level.getBlockState(pos);
|
||||||
|
IntegerProperty distanceProperty = this.getLeafDistanceProperty(state);
|
||||||
|
if (distanceProperty == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int computedDistance = distances.get(pos);
|
||||||
if (computedDistance == state.getValue(distanceProperty)) {
|
if (computedDistance == state.getValue(distanceProperty)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1147,9 +1197,6 @@ public class OuranwoodTreeFeature extends Feature<OuranwoodTreeConfiguration> {
|
|||||||
updatedState = state.setValue(distanceProperty, computedDistance);
|
updatedState = state.setValue(distanceProperty, computedDistance);
|
||||||
}
|
}
|
||||||
setBlock(level, pos, updatedState);
|
setBlock(level, pos, updatedState);
|
||||||
anyChanged = true;
|
|
||||||
}
|
|
||||||
if (!anyChanged) break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
package com.craisinlord.antarchy.content.worldgen.thoraxis;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.level.WorldGenLevel;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||||
|
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||||
|
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills the low, open main-side Thoraxis basin with source ichor during chunk generation.
|
||||||
|
* The feature works one chunk at a time so it does not depend on runtime fluid spreading.
|
||||||
|
*/
|
||||||
|
public final class ThoraxisIchorLakeFeature extends Feature<NoneFeatureConfiguration> {
|
||||||
|
private static final int LAKE_FLOOR_Y = 1;
|
||||||
|
private static final int LAKE_SURFACE_Y = 8;
|
||||||
|
private static final ResourceLocation ICHOR_BLOCK_ID =
|
||||||
|
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "ichor");
|
||||||
|
|
||||||
|
public ThoraxisIchorLakeFeature(Codec<NoneFeatureConfiguration> codec) {
|
||||||
|
super(codec);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> context) {
|
||||||
|
WorldGenLevel level = context.level();
|
||||||
|
BlockPos origin = context.origin();
|
||||||
|
BlockState ichorState = BuiltInRegistries.BLOCK.get(ICHOR_BLOCK_ID).defaultBlockState();
|
||||||
|
if (ichorState.isAir() || ichorState.getFluidState().isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int chunkMinX = origin.getX() >> 4 << 4;
|
||||||
|
int chunkMinZ = origin.getZ() >> 4 << 4;
|
||||||
|
boolean placedAny = false;
|
||||||
|
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||||
|
|
||||||
|
for (int x = chunkMinX; x < chunkMinX + 16; x++) {
|
||||||
|
for (int z = chunkMinZ; z < chunkMinZ + 16; z++) {
|
||||||
|
for (int y = LAKE_FLOOR_Y; y <= LAKE_SURFACE_Y; y++) {
|
||||||
|
mutable.set(x, y, z);
|
||||||
|
BlockState current = level.getBlockState(mutable);
|
||||||
|
if (!isOpenForLake(current)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
level.setBlock(mutable, ichorState, 2);
|
||||||
|
placedAny = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return placedAny;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isOpenForLake(BlockState state) {
|
||||||
|
return state.isAir() || state.canBeReplaced() || !state.blocksMotion();
|
||||||
|
}
|
||||||
|
}
|
||||||
+44
-6
@@ -35,6 +35,8 @@ public final class ThoraxisUndersideManager {
|
|||||||
private static final int DISCOVERY_INTERVAL_TICKS = 5;
|
private static final int DISCOVERY_INTERVAL_TICKS = 5;
|
||||||
private static final int SIMULATION_DISTANCE_MARGIN_CHUNKS = 1;
|
private static final int SIMULATION_DISTANCE_MARGIN_CHUNKS = 1;
|
||||||
private static final int MAX_FLIPS_PER_TICK = 8;
|
private static final int MAX_FLIPS_PER_TICK = 8;
|
||||||
|
private static final double SLOW_TICK_WARN_MS = 25.0D;
|
||||||
|
private static final long DIAGNOSTIC_INTERVAL_TICKS = 100L;
|
||||||
private static final int ENTER_UNDERSIDE_Y = GRAVITY_FLIP_Y - 4;
|
private static final int ENTER_UNDERSIDE_Y = GRAVITY_FLIP_Y - 4;
|
||||||
private static final int EXIT_UNDERSIDE_Y = GRAVITY_FLIP_Y + 4;
|
private static final int EXIT_UNDERSIDE_Y = GRAVITY_FLIP_Y + 4;
|
||||||
private static final int FLIP_COOLDOWN_TICKS = 40;
|
private static final int FLIP_COOLDOWN_TICKS = 40;
|
||||||
@@ -55,12 +57,20 @@ public final class ThoraxisUndersideManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long startNanos = System.nanoTime();
|
||||||
long now = level.getGameTime();
|
long now = level.getGameTime();
|
||||||
|
int discoveredLiving = 0;
|
||||||
|
int discoveredItems = 0;
|
||||||
if (now % DISCOVERY_INTERVAL_TICKS == 0L) {
|
if (now % DISCOVERY_INTERVAL_TICKS == 0L) {
|
||||||
tracking.discover(level);
|
DiscoveryStats stats = tracking.discover(level);
|
||||||
|
discoveredLiving = stats.livingEntities();
|
||||||
|
discoveredItems = stats.itemEntities();
|
||||||
}
|
}
|
||||||
|
|
||||||
int flipsRemaining = MAX_FLIPS_PER_TICK;
|
int flipsRemaining = MAX_FLIPS_PER_TICK;
|
||||||
|
int refreshedLiving = 0;
|
||||||
|
int flippedItems = 0;
|
||||||
|
int restoredItems = 0;
|
||||||
for (Entity entity : tracking.entities) {
|
for (Entity entity : tracking.entities) {
|
||||||
if (!entity.isAlive() || entity.isSpectator()) {
|
if (!entity.isAlive() || entity.isSpectator()) {
|
||||||
continue;
|
continue;
|
||||||
@@ -71,6 +81,7 @@ public final class ThoraxisUndersideManager {
|
|||||||
int threshold = hasEffect ? EXIT_UNDERSIDE_Y : ENTER_UNDERSIDE_Y;
|
int threshold = hasEffect ? EXIT_UNDERSIDE_Y : ENTER_UNDERSIDE_Y;
|
||||||
if (living.getY() < threshold) {
|
if (living.getY() < threshold) {
|
||||||
refreshInvertedEffect(living);
|
refreshInvertedEffect(living);
|
||||||
|
refreshedLiving++;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -94,6 +105,7 @@ public final class ThoraxisUndersideManager {
|
|||||||
flipsRemaining--;
|
flipsRemaining--;
|
||||||
tracking.lastFlipTick.put(uuid, now);
|
tracking.lastFlipTick.put(uuid, now);
|
||||||
AntarchyGravityApi.setForcedGravityDirection(entity, AntarchyGravityDirection.UP, TRANSITION);
|
AntarchyGravityApi.setForcedGravityDirection(entity, AntarchyGravityDirection.UP, TRANSITION);
|
||||||
|
flippedItems++;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -108,6 +120,7 @@ public final class ThoraxisUndersideManager {
|
|||||||
if (isForcedUp) {
|
if (isForcedUp) {
|
||||||
tracking.lastFlipTick.put(uuid, now);
|
tracking.lastFlipTick.put(uuid, now);
|
||||||
AntarchyGravityApi.setGravityDirection(entity, AntarchyGravityDirection.DOWN, false, TRANSITION);
|
AntarchyGravityApi.setGravityDirection(entity, AntarchyGravityDirection.DOWN, false, TRANSITION);
|
||||||
|
restoredItems++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,26 +128,44 @@ public final class ThoraxisUndersideManager {
|
|||||||
tracking.entities.removeIf(entity -> !entity.isAlive() || entity.isRemoved());
|
tracking.entities.removeIf(entity -> !entity.isAlive() || entity.isRemoved());
|
||||||
tracking.forcedItems.removeIf(entity -> !entity.isAlive() || entity.isRemoved());
|
tracking.forcedItems.removeIf(entity -> !entity.isAlive() || entity.isRemoved());
|
||||||
tracking.lastFlipTick.entrySet().removeIf(entry -> now - entry.getValue() > FLIP_COOLDOWN_TICKS * 4L);
|
tracking.lastFlipTick.entrySet().removeIf(entry -> now - entry.getValue() > FLIP_COOLDOWN_TICKS * 4L);
|
||||||
|
|
||||||
|
double elapsedMs = (System.nanoTime() - startNanos) / 1_000_000.0D;
|
||||||
|
if (elapsedMs >= SLOW_TICK_WARN_MS && now - tracking.lastDiagnosticTick >= DIAGNOSTIC_INTERVAL_TICKS) {
|
||||||
|
tracking.lastDiagnosticTick = now;
|
||||||
|
Antarchy.LOGGER.warn(
|
||||||
|
"[antarchy-thoraxis] slow underside tick dim={} gameTime={} elapsedMs={} trackedEntities={} forcedItems={} discoveredLiving={} discoveredItems={} refreshedLiving={} flippedItems={} restoredItems={} players={}",
|
||||||
|
level.dimension().location(), now, elapsedMs, tracking.entities.size(), tracking.forcedItems.size(),
|
||||||
|
discoveredLiving, discoveredItems, refreshedLiving, flippedItems, restoredItems, level.players().size()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class TrackingState {
|
private static final class TrackingState {
|
||||||
private final Set<Entity> entities = Collections.newSetFromMap(new IdentityHashMap<>());
|
private final Set<Entity> entities = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||||
private final Set<Entity> forcedItems = Collections.newSetFromMap(new IdentityHashMap<>());
|
private final Set<Entity> forcedItems = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||||
private final Map<UUID, Long> lastFlipTick = new java.util.HashMap<>();
|
private final Map<UUID, Long> lastFlipTick = new java.util.HashMap<>();
|
||||||
|
private long lastDiagnosticTick = Long.MIN_VALUE / 2L;
|
||||||
|
|
||||||
private void discover(ServerLevel level) {
|
private DiscoveryStats discover(ServerLevel level) {
|
||||||
int radius = (level.getServer().getPlayerList().getSimulationDistance() + SIMULATION_DISTANCE_MARGIN_CHUNKS) * 16;
|
int radius = (level.getServer().getPlayerList().getSimulationDistance() + SIMULATION_DISTANCE_MARGIN_CHUNKS) * 16;
|
||||||
|
int discoveredLiving = 0;
|
||||||
|
int discoveredItems = 0;
|
||||||
for (ServerPlayer player : level.players()) {
|
for (ServerPlayer player : level.players()) {
|
||||||
AABB area = new AABB(
|
AABB area = new AABB(
|
||||||
player.getX() - radius, level.getMinBuildHeight(), player.getZ() - radius,
|
player.getX() - radius, level.getMinBuildHeight(), player.getZ() - radius,
|
||||||
player.getX() + radius, level.getMaxBuildHeight(), player.getZ() + radius
|
player.getX() + radius, level.getMaxBuildHeight(), player.getZ() + radius
|
||||||
);
|
);
|
||||||
entities.add(player);
|
entities.add(player);
|
||||||
entities.addAll(level.getEntitiesOfClass(LivingEntity.class, area,
|
java.util.List<LivingEntity> livingEntities = level.getEntitiesOfClass(LivingEntity.class, area,
|
||||||
entity -> !entity.isSpectator() && entity.getY() < EXIT_UNDERSIDE_Y));
|
entity -> !entity.isSpectator() && entity.getY() < EXIT_UNDERSIDE_Y);
|
||||||
entities.addAll(level.getEntitiesOfClass(ItemEntity.class, area,
|
java.util.List<ItemEntity> itemEntities = level.getEntitiesOfClass(ItemEntity.class, area,
|
||||||
entity -> !entity.isSpectator() && entity.getY() < EXIT_UNDERSIDE_Y));
|
entity -> !entity.isSpectator() && entity.getY() < EXIT_UNDERSIDE_Y);
|
||||||
|
discoveredLiving += livingEntities.size();
|
||||||
|
discoveredItems += itemEntities.size();
|
||||||
|
entities.addAll(livingEntities);
|
||||||
|
entities.addAll(itemEntities);
|
||||||
}
|
}
|
||||||
|
return new DiscoveryStats(discoveredLiving, discoveredItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clear() {
|
private void clear() {
|
||||||
@@ -149,6 +180,9 @@ public final class ThoraxisUndersideManager {
|
|||||||
return last == null || now - last >= FLIP_COOLDOWN_TICKS;
|
return last == null || now - last >= FLIP_COOLDOWN_TICKS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private record DiscoveryStats(int livingEntities, int itemEntities) {
|
||||||
|
}
|
||||||
|
|
||||||
public static void applyUndersideInversion(LivingEntity living) {
|
public static void applyUndersideInversion(LivingEntity living) {
|
||||||
refreshInvertedEffect(living);
|
refreshInvertedEffect(living);
|
||||||
}
|
}
|
||||||
@@ -184,4 +218,8 @@ public final class ThoraxisUndersideManager {
|
|||||||
public static boolean isThoraxis(Level level) {
|
public static boolean isThoraxis(Level level) {
|
||||||
return level.dimension().location().equals(THORAXIS_DIMENSION);
|
return level.dimension().location().equals(THORAXIS_DIMENSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isAboveUndersideExit(Entity entity) {
|
||||||
|
return isThoraxis(entity.level()) && entity.getY() >= EXIT_UNDERSIDE_Y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+6
-2
@@ -8,10 +8,14 @@ import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvi
|
|||||||
|
|
||||||
public record TruffaloTreeConfiguration(
|
public record TruffaloTreeConfiguration(
|
||||||
BlockStateProvider trunkProvider,
|
BlockStateProvider trunkProvider,
|
||||||
IntProvider height
|
IntProvider height,
|
||||||
|
int tuftRadius,
|
||||||
|
int tuftHeight
|
||||||
) implements FeatureConfiguration {
|
) implements FeatureConfiguration {
|
||||||
public static final Codec<TruffaloTreeConfiguration> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
public static final Codec<TruffaloTreeConfiguration> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||||
BlockStateProvider.CODEC.fieldOf("trunk_provider").forGetter(TruffaloTreeConfiguration::trunkProvider),
|
BlockStateProvider.CODEC.fieldOf("trunk_provider").forGetter(TruffaloTreeConfiguration::trunkProvider),
|
||||||
IntProvider.codec(4, 9).fieldOf("height").forGetter(TruffaloTreeConfiguration::height)
|
IntProvider.codec(4, 18).fieldOf("height").forGetter(TruffaloTreeConfiguration::height),
|
||||||
|
Codec.INT.optionalFieldOf("tuft_radius", 1).forGetter(TruffaloTreeConfiguration::tuftRadius),
|
||||||
|
Codec.INT.optionalFieldOf("tuft_height", 3).forGetter(TruffaloTreeConfiguration::tuftHeight)
|
||||||
).apply(instance, TruffaloTreeConfiguration::new));
|
).apply(instance, TruffaloTreeConfiguration::new));
|
||||||
}
|
}
|
||||||
+6
-6
@@ -58,9 +58,9 @@ public class TruffaloTreeFeature extends Feature<TruffaloTreeConfiguration> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int dy = 0; dy <= 2; dy++) {
|
for (int dy = 0; dy < config.tuftHeight(); dy++) {
|
||||||
for (int dx = -1; dx <= 1; dx++) {
|
for (int dx = -config.tuftRadius(); dx <= config.tuftRadius(); dx++) {
|
||||||
for (int dz = -1; dz <= 1; dz++) {
|
for (int dz = -config.tuftRadius(); dz <= config.tuftRadius(); dz++) {
|
||||||
if (!canReplace(level, capBase.offset(dx, dy, dz))) {
|
if (!canReplace(level, capBase.offset(dx, dy, dz))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -74,9 +74,9 @@ public class TruffaloTreeFeature extends Feature<TruffaloTreeConfiguration> {
|
|||||||
|
|
||||||
Block tuft = BuiltInRegistries.BLOCK.get(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, color.getName() + "_truffalo_tuft"));
|
Block tuft = BuiltInRegistries.BLOCK.get(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, color.getName() + "_truffalo_tuft"));
|
||||||
BlockState tuftState = tuft.defaultBlockState();
|
BlockState tuftState = tuft.defaultBlockState();
|
||||||
for (int dy = 0; dy <= 2; dy++) {
|
for (int dy = 0; dy < config.tuftHeight(); dy++) {
|
||||||
for (int dx = -1; dx <= 1; dx++) {
|
for (int dx = -config.tuftRadius(); dx <= config.tuftRadius(); dx++) {
|
||||||
for (int dz = -1; dz <= 1; dz++) {
|
for (int dz = -config.tuftRadius(); dz <= config.tuftRadius(); dz++) {
|
||||||
setBlock(level, capBase.offset(dx, dy, dz), tuftState);
|
setBlock(level, capBase.offset(dx, dy, dz), tuftState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.effect.CommandedEntityAccess;
|
||||||
|
import java.util.UUID;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
|
||||||
|
@Mixin(Mob.class)
|
||||||
|
public abstract class CommandedMobMixin implements CommandedEntityAccess {
|
||||||
|
@Unique
|
||||||
|
private UUID antarchy$commanderUuid;
|
||||||
|
@Unique
|
||||||
|
private boolean antarchy$commandedTargetOwned;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID antarchy$getCommanderUuid() {
|
||||||
|
return antarchy$commanderUuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void antarchy$setCommanderUuid(UUID uuid) {
|
||||||
|
antarchy$commanderUuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean antarchy$isCommandedTargetOwned() {
|
||||||
|
return antarchy$commandedTargetOwned;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void antarchy$setCommandedTargetOwned(boolean owned) {
|
||||||
|
antarchy$commandedTargetOwned = owned;
|
||||||
|
}
|
||||||
|
|
||||||
|
@org.spongepowered.asm.mixin.injection.Inject(method = "addAdditionalSaveData", at = @org.spongepowered.asm.mixin.injection.At("TAIL"))
|
||||||
|
private void antarchy$saveCommandedData(CompoundTag tag, org.spongepowered.asm.mixin.injection.callback.CallbackInfo ci) {
|
||||||
|
if (antarchy$commanderUuid != null) {
|
||||||
|
tag.putUUID("AntarchyCommander", antarchy$commanderUuid);
|
||||||
|
tag.putBoolean("AntarchyCommandedTargetOwned", antarchy$commandedTargetOwned);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@org.spongepowered.asm.mixin.injection.Inject(method = "readAdditionalSaveData", at = @org.spongepowered.asm.mixin.injection.At("TAIL"))
|
||||||
|
private void antarchy$loadCommandedData(CompoundTag tag, org.spongepowered.asm.mixin.injection.callback.CallbackInfo ci) {
|
||||||
|
if (tag.hasUUID("AntarchyCommander")) {
|
||||||
|
antarchy$commanderUuid = tag.getUUID("AntarchyCommander");
|
||||||
|
antarchy$commandedTargetOwned = tag.getBoolean("AntarchyCommandedTargetOwned");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+90
@@ -0,0 +1,90 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.effect.CommandedEntityAccess;
|
||||||
|
import com.craisinlord.antarchy.content.effect.RoyalEffectEligibility;
|
||||||
|
import java.util.UUID;
|
||||||
|
import net.minecraft.world.effect.MobEffectInstance;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
import net.minecraft.world.entity.AreaEffectCloud;
|
||||||
|
import net.minecraft.world.entity.projectile.Projectile;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(LivingEntity.class)
|
||||||
|
public abstract class LivingEntityRoyalEffectsMixin {
|
||||||
|
@Unique
|
||||||
|
private UUID antarchy$previousCommander;
|
||||||
|
|
||||||
|
@Inject(method = "canBeAffected", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$checkRoyalEffectBlacklist(MobEffectInstance instance, CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
if (!RoyalEffectEligibility.canApply((LivingEntity) (Object) this, instance)) {
|
||||||
|
cir.setReturnValue(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "addEffect(Lnet/minecraft/world/effect/MobEffectInstance;Lnet/minecraft/world/entity/Entity;)Z", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$prepareCommandedSource(MobEffectInstance instance, Entity source, CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
if (!RoyalEffectEligibility.isCommanded(instance)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LivingEntity entity = (LivingEntity) (Object) this;
|
||||||
|
if (!RoyalEffectEligibility.canApplyCommanded(entity) || !(entity instanceof Mob mob)) {
|
||||||
|
cir.setReturnValue(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PlayerSource playerSource = antarchy$resolvePlayer(source);
|
||||||
|
if (playerSource == null) {
|
||||||
|
cir.setReturnValue(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CommandedEntityAccess access = (CommandedEntityAccess) mob;
|
||||||
|
UUID current = access.antarchy$getCommanderUuid();
|
||||||
|
if (current != null && !current.equals(playerSource.player().getUUID())) {
|
||||||
|
cir.setReturnValue(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
antarchy$previousCommander = current;
|
||||||
|
access.antarchy$setCommanderUuid(playerSource.player().getUUID());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "addEffect(Lnet/minecraft/world/effect/MobEffectInstance;Lnet/minecraft/world/entity/Entity;)Z", at = @At("RETURN"))
|
||||||
|
private void antarchy$finishCommandedSource(MobEffectInstance instance, Entity source, CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
if (!RoyalEffectEligibility.isCommanded(instance) || cir.getReturnValue()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LivingEntity entity = (LivingEntity) (Object) this;
|
||||||
|
if (entity instanceof CommandedEntityAccess access) {
|
||||||
|
access.antarchy$setCommanderUuid(antarchy$previousCommander);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "onEffectRemoved", at = @At("HEAD"))
|
||||||
|
private void antarchy$clearCommandedState(MobEffectInstance instance, org.spongepowered.asm.mixin.injection.callback.CallbackInfo ci) {
|
||||||
|
if (RoyalEffectEligibility.isCommanded(instance) && (Object) this instanceof Mob mob) {
|
||||||
|
com.craisinlord.antarchy.content.effect.CommandedBehavior.clear(mob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private PlayerSource antarchy$resolvePlayer(Entity source) {
|
||||||
|
if (source instanceof net.minecraft.world.entity.player.Player player) {
|
||||||
|
return new PlayerSource(player);
|
||||||
|
}
|
||||||
|
if (source instanceof Projectile projectile && projectile.getOwner() instanceof net.minecraft.world.entity.player.Player player) {
|
||||||
|
return new PlayerSource(player);
|
||||||
|
}
|
||||||
|
if (source instanceof AreaEffectCloud cloud && cloud.getOwner() instanceof net.minecraft.world.entity.player.Player player) {
|
||||||
|
return new PlayerSource(player);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private record PlayerSource(net.minecraft.world.entity.player.Player player) {
|
||||||
|
}
|
||||||
|
}
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.effect.CommandedBehavior;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
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(Mob.class)
|
||||||
|
public abstract class MobCommandedTargetMixin {
|
||||||
|
@Inject(method = "setTarget", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$protectCommandedAllies(LivingEntity target, CallbackInfo ci) {
|
||||||
|
Mob mob = (Mob) (Object) this;
|
||||||
|
if (target != null && CommandedBehavior.isProtectedAlly(mob, target)) {
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "doHurtTarget", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$preventCommandedFriendlyFire(net.minecraft.world.entity.Entity target,
|
||||||
|
org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
Mob mob = (Mob) (Object) this;
|
||||||
|
if (CommandedBehavior.isProtectedAlly(mob, target)) {
|
||||||
|
cir.setReturnValue(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+79
@@ -5,10 +5,16 @@ import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
|||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityTransition;
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityTransition;
|
||||||
|
import com.craisinlord.antarchy.content.entity.BedBugEntity;
|
||||||
|
import com.craisinlord.antarchy.content.entity.portal.DimensionalTearEntity;
|
||||||
|
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisUndersideManager;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.effect.MobEffectInstance;
|
||||||
import net.minecraft.world.level.material.FluidState;
|
import net.minecraft.world.level.material.FluidState;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
@@ -71,6 +77,51 @@ public abstract class EntityGravityMixin implements AntarchyGravityAccess {
|
|||||||
this.antarchy$gravityForced = tag.getBoolean(ANTARCHY_GRAVITY_FORCED_TAG);
|
this.antarchy$gravityForced = tag.getBoolean(ANTARCHY_GRAVITY_FORCED_TAG);
|
||||||
this.antarchy$gravityTransitionDuration = Math.max(0, tag.getInt(ANTARCHY_GRAVITY_TRANSITION_DURATION_TAG));
|
this.antarchy$gravityTransitionDuration = Math.max(0, tag.getInt(ANTARCHY_GRAVITY_TRANSITION_DURATION_TAG));
|
||||||
this.antarchy$gravityTransitionRemaining = Math.max(0, tag.getInt(ANTARCHY_GRAVITY_TRANSITION_REMAINING_TAG));
|
this.antarchy$gravityTransitionRemaining = Math.max(0, tag.getInt(ANTARCHY_GRAVITY_TRANSITION_REMAINING_TAG));
|
||||||
|
|
||||||
|
Entity entity = this.antarchy$entity();
|
||||||
|
if (this.antarchy$gravityDirection.isInverted() && this.antarchy$gravityForced
|
||||||
|
&& entity instanceof Mob mob) {
|
||||||
|
MobEffectInstance invertedEffect = mob.getEffect(com.craisinlord.antarchy.content.AntarchyObjects.INVERTED_EFFECT.get());
|
||||||
|
boolean aboveUndersideExit = ThoraxisUndersideManager.isAboveUndersideExit(mob);
|
||||||
|
int nearbyDimensionalTears = this.antarchy$countNearbyDimensionalTears(mob);
|
||||||
|
if (invertedEffect != null
|
||||||
|
&& invertedEffect.isAmbient()
|
||||||
|
&& !invertedEffect.isVisible()
|
||||||
|
&& aboveUndersideExit) {
|
||||||
|
this.antarchy$clearLoadedInversion(mob);
|
||||||
|
com.craisinlord.antarchy.Antarchy.LOGGER.warn(
|
||||||
|
"[antarchy-gravity] cleared stale underside inversion from loaded mob type={} uuid={} pos=({}, {}, {}) dim={} effectDuration={} nearbyDimensionalTears={}",
|
||||||
|
mob.getType(), mob.getUUID(), mob.getX(), mob.getY(), mob.getZ(),
|
||||||
|
mob.level() != null ? mob.level().dimension().location() : "?",
|
||||||
|
invertedEffect.getDuration(), nearbyDimensionalTears
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (invertedEffect != null
|
||||||
|
&& mob instanceof BedBugEntity
|
||||||
|
&& aboveUndersideExit
|
||||||
|
&& ThoraxisUndersideManager.isThoraxis(mob.level())) {
|
||||||
|
this.antarchy$clearLoadedInversion(mob);
|
||||||
|
com.craisinlord.antarchy.Antarchy.LOGGER.warn(
|
||||||
|
"[antarchy-gravity] cleared loaded inverted bed bug above underside exit type={} uuid={} pos=({}, {}, {}) dim={} effectDuration={} effectAmbient={} effectVisible={} nearbyDimensionalTears={}",
|
||||||
|
mob.getType(), mob.getUUID(), mob.getX(), mob.getY(), mob.getZ(),
|
||||||
|
mob.level() != null ? mob.level().dimension().location() : "?",
|
||||||
|
invertedEffect.getDuration(), invertedEffect.isAmbient(), invertedEffect.isVisible(), nearbyDimensionalTears
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
com.craisinlord.antarchy.Antarchy.LOGGER.info(
|
||||||
|
"[antarchy-gravity] loaded inverted mob type={} uuid={} pos=({}, {}, {}) dim={} hasInvertedEffect={} effectDuration={} effectAmbient={} effectVisible={} aboveUndersideExit={} nearbyDimensionalTears={}",
|
||||||
|
mob.getType(), mob.getUUID(), mob.getX(), mob.getY(), mob.getZ(),
|
||||||
|
mob.level() != null ? mob.level().dimension().location() : "?",
|
||||||
|
invertedEffect != null,
|
||||||
|
invertedEffect != null ? invertedEffect.getDuration() : -1,
|
||||||
|
invertedEffect != null && invertedEffect.isAmbient(),
|
||||||
|
invertedEffect != null && invertedEffect.isVisible(),
|
||||||
|
aboveUndersideExit,
|
||||||
|
nearbyDimensionalTears
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject(method = "baseTick", at = @At("TAIL"))
|
@Inject(method = "baseTick", at = @At("TAIL"))
|
||||||
@@ -134,6 +185,11 @@ public abstract class EntityGravityMixin implements AntarchyGravityAccess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.antarchy$gravityForced = forced;
|
this.antarchy$gravityForced = forced;
|
||||||
|
if (changed && this.antarchy$entity() instanceof Mob mob) {
|
||||||
|
// Any existing path is expressed in the previous gravity frame.
|
||||||
|
// Keep goals from following stale nodes after a flip.
|
||||||
|
mob.getNavigation().stop();
|
||||||
|
}
|
||||||
if (changed && !this.antarchy$entity().level().isClientSide) {
|
if (changed && !this.antarchy$entity().level().isClientSide) {
|
||||||
AntarchyGravityApi.notifyGravityStateChanged(this.antarchy$entity());
|
AntarchyGravityApi.notifyGravityStateChanged(this.antarchy$entity());
|
||||||
}
|
}
|
||||||
@@ -172,6 +228,29 @@ public abstract class EntityGravityMixin implements AntarchyGravityAccess {
|
|||||||
this.setBoundingBox(this.makeBoundingBox());
|
this.setBoundingBox(this.makeBoundingBox());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private void antarchy$clearLoadedInversion(Mob mob) {
|
||||||
|
mob.removeEffect(com.craisinlord.antarchy.content.AntarchyObjects.INVERTED_EFFECT.get());
|
||||||
|
this.antarchy$gravityDirection = AntarchyGravityDirection.DOWN;
|
||||||
|
this.antarchy$prevGravityDirection = AntarchyGravityDirection.DOWN;
|
||||||
|
this.antarchy$gravityForced = false;
|
||||||
|
this.antarchy$gravityTransitionDuration = 0;
|
||||||
|
this.antarchy$gravityTransitionRemaining = 0;
|
||||||
|
this.antarchy$refreshGravityBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private int antarchy$countNearbyDimensionalTears(Mob mob) {
|
||||||
|
if (!(mob.level() instanceof ServerLevel serverLevel)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return serverLevel.getEntitiesOfClass(
|
||||||
|
DimensionalTearEntity.class,
|
||||||
|
mob.getBoundingBox().inflate(48.0D),
|
||||||
|
Entity::isAlive
|
||||||
|
).size();
|
||||||
|
}
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private void antarchy$adjustPositionForGravityChange(AntarchyGravityDirection oldDirection, AntarchyGravityDirection newDirection) {
|
private void antarchy$adjustPositionForGravityChange(AntarchyGravityDirection oldDirection, AntarchyGravityDirection newDirection) {
|
||||||
if (oldDirection == newDirection) {
|
if (oldDirection == newDirection) {
|
||||||
|
|||||||
+68
-5
@@ -1,26 +1,89 @@
|
|||||||
package com.craisinlord.antarchy.mixins.gravity;
|
package com.craisinlord.antarchy.mixins.gravity;
|
||||||
|
|
||||||
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
|
||||||
import com.craisinlord.antarchy.content.gravity.GravityWalkNodeEvaluator;
|
import com.craisinlord.antarchy.content.gravity.GravityWalkNodeEvaluator;
|
||||||
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.world.entity.EntityDimensions;
|
||||||
|
import net.minecraft.world.entity.Pose;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
import net.minecraft.world.entity.ai.navigation.GroundPathNavigation;
|
import net.minecraft.world.entity.ai.navigation.GroundPathNavigation;
|
||||||
import net.minecraft.world.level.pathfinder.NodeEvaluator;
|
import net.minecraft.world.level.pathfinder.NodeEvaluator;
|
||||||
import net.minecraft.world.level.pathfinder.PathFinder;
|
import net.minecraft.world.level.pathfinder.PathFinder;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
@Mixin(GroundPathNavigation.class)
|
@Mixin(GroundPathNavigation.class)
|
||||||
/*
|
|
||||||
* Makes ground pathing read gravity-aware floor checks.
|
|
||||||
*/
|
|
||||||
public abstract class GroundPathNavigationMixin {
|
public abstract class GroundPathNavigationMixin {
|
||||||
@Inject(method = "createPathFinder", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "createPathFinder", at = @At("HEAD"), cancellable = true)
|
||||||
private void antarchy$useGravityEvaluator(int maxVisitedNodes, CallbackInfoReturnable<PathFinder> cir) {
|
private void antarchy$useGravityEvaluator(int maxVisitedNodes, CallbackInfoReturnable<PathFinder> cir) {
|
||||||
var accessor = (PathNavigationAccessor) (Object) this;
|
var accessor = (PathNavigationAccessor) (Object) this;
|
||||||
var mob = accessor.antarchy$getMob();
|
|
||||||
NodeEvaluator evaluator = new GravityWalkNodeEvaluator();
|
NodeEvaluator evaluator = new GravityWalkNodeEvaluator();
|
||||||
|
// GroundPathNavigation enables door passing on its vanilla evaluator.
|
||||||
|
// Preserve that setting when swapping in the gravity-aware evaluator.
|
||||||
|
evaluator.setCanPassDoors(true);
|
||||||
accessor.antarchy$setNodeEvaluator(evaluator);
|
accessor.antarchy$setNodeEvaluator(evaluator);
|
||||||
cir.setReturnValue(new PathFinder(evaluator, maxVisitedNodes));
|
cir.setReturnValue(new PathFinder(evaluator, maxVisitedNodes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GroundPathNavigation normalizes entity destinations toward the floor
|
||||||
|
* before delegating to PathNavigation. For inverted mobs, replace that
|
||||||
|
* final destination with a bounded, collision-free ceiling anchor.
|
||||||
|
*/
|
||||||
|
@org.spongepowered.asm.mixin.injection.ModifyArg(
|
||||||
|
method = "createPath(Lnet/minecraft/core/BlockPos;I)Lnet/minecraft/world/level/pathfinder/Path;",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/world/entity/ai/navigation/PathNavigation;createPath(Lnet/minecraft/core/BlockPos;I)Lnet/minecraft/world/level/pathfinder/Path;"
|
||||||
|
),
|
||||||
|
index = 0
|
||||||
|
)
|
||||||
|
private BlockPos antarchy$projectInvertedDestination(BlockPos normalizedDestination) {
|
||||||
|
Mob mob = ((PathNavigationAccessor) (Object) this).antarchy$getMob();
|
||||||
|
if (!AntarchyGravityApi.isGravityInverted(mob)) {
|
||||||
|
return normalizedDestination;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityDimensions dimensions = mob.getDimensions(mob.getPose());
|
||||||
|
int centerX = normalizedDestination.getX();
|
||||||
|
int centerZ = normalizedDestination.getZ();
|
||||||
|
int baseY = normalizedDestination.getY();
|
||||||
|
int minY = Math.max(mob.level().getMinBuildHeight(), baseY - 32);
|
||||||
|
int maxY = Math.min(mob.level().getMaxBuildHeight() - 2, baseY + 32);
|
||||||
|
for (int candidateY = baseY; candidateY <= maxY; candidateY++) {
|
||||||
|
BlockPos support = new BlockPos(centerX, candidateY + 1, centerZ);
|
||||||
|
if (!mob.level().getBlockState(support).isFaceSturdy(mob.level(), support, Direction.DOWN)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
double topY = candidateY + 1.0D - 1.0E-3D;
|
||||||
|
double halfWidth = dimensions.width() / 2.0D;
|
||||||
|
AABB body = new AABB(
|
||||||
|
centerX + 0.5D - halfWidth,
|
||||||
|
topY - dimensions.height(),
|
||||||
|
centerZ + 0.5D - halfWidth,
|
||||||
|
centerX + 0.5D + halfWidth,
|
||||||
|
topY,
|
||||||
|
centerZ + 0.5D + halfWidth
|
||||||
|
).deflate(1.0E-4D);
|
||||||
|
if (mob.level().noCollision(mob, body)) {
|
||||||
|
return new BlockPos(centerX, candidateY, centerZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalizedDestination;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "getTempMobPos", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$useInvertedMobAnchor(CallbackInfoReturnable<Vec3> cir) {
|
||||||
|
Mob mob = ((PathNavigationAccessor) (Object) this).antarchy$getMob();
|
||||||
|
if (AntarchyGravityApi.isGravityInverted(mob)) {
|
||||||
|
cir.setReturnValue(new Vec3(mob.getX(), mob.getY(), mob.getZ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+101
@@ -0,0 +1,101 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.gravity;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.PathfinderMob;
|
||||||
|
import net.minecraft.world.entity.ai.goal.MeleeAttackGoal;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(MeleeAttackGoal.class)
|
||||||
|
public abstract class MeleeAttackGoalGravityMixin {
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
protected PathfinderMob mob;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private double speedModifier;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private boolean followingTargetEvenIfNotSeen;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
private int ticksUntilNextAttack;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
protected abstract void checkAndPerformAttack(LivingEntity enemy);
|
||||||
|
|
||||||
|
@Inject(method = "canUse", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$useInvertedMelee(CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
if (!AntarchyGravityApi.isGravityInverted(this.mob)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LivingEntity target = this.mob.getTarget();
|
||||||
|
cir.setReturnValue(this.antarchy$isValidInvertedMeleeTarget(target));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "canContinueToUse", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$continueInvertedMelee(CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
if (!AntarchyGravityApi.isGravityInverted(this.mob)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LivingEntity target = this.mob.getTarget();
|
||||||
|
cir.setReturnValue(this.antarchy$isValidInvertedMeleeTarget(target));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "start", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$startInvertedMelee(CallbackInfo ci) {
|
||||||
|
if (!AntarchyGravityApi.isGravityInverted(this.mob)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LivingEntity target = this.mob.getTarget();
|
||||||
|
this.mob.getNavigation().stop();
|
||||||
|
this.mob.setAggressive(true);
|
||||||
|
this.ticksUntilNextAttack = 0;
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "tick", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$tickInvertedMelee(CallbackInfo ci) {
|
||||||
|
if (!AntarchyGravityApi.isGravityInverted(this.mob)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LivingEntity target = this.mob.getTarget();
|
||||||
|
if (!this.antarchy$isValidInvertedMeleeTarget(target)) {
|
||||||
|
this.mob.getNavigation().stop();
|
||||||
|
ci.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mob.getLookControl().setLookAt(target, 30.0F, 30.0F);
|
||||||
|
// Do not call PathNavigation.moveTo here: that starts the unsafe vanilla
|
||||||
|
// path acquisition path. MoveControl receives a world-space target and
|
||||||
|
// the gravity movement mixin converts it into the inverted frame.
|
||||||
|
this.mob.getMoveControl().setWantedPosition(target.getX(), target.getY(), target.getZ(), this.speedModifier);
|
||||||
|
this.ticksUntilNextAttack = Math.max(0, this.ticksUntilNextAttack - 1);
|
||||||
|
this.checkAndPerformAttack(target);
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean antarchy$isValidInvertedMeleeTarget(LivingEntity target) {
|
||||||
|
if (target == null || !target.isAlive()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.followingTargetEvenIfNotSeen && !this.mob.isWithinRestriction(target.blockPosition())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !(target instanceof Player player) || (!player.isSpectator() && !player.isCreative());
|
||||||
|
}
|
||||||
|
}
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.gravity;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||||
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
import net.minecraft.world.entity.ai.control.MoveControl;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(MoveControl.class)
|
||||||
|
public abstract class MoveControlGravityMixin {
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
protected Mob mob;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
protected double wantedX;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
protected double wantedY;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
protected double wantedZ;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
protected double speedModifier;
|
||||||
|
|
||||||
|
@Inject(method = "setWantedPosition", at = @At("TAIL"))
|
||||||
|
private void antarchy$convertInvertedWantedPosition(double x, double y, double z, double speed, CallbackInfo ci) {
|
||||||
|
if (!AntarchyGravityApi.isGravityInverted(this.mob)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 worldOffset = new Vec3(x - this.mob.getX(), y - this.mob.getY(), z - this.mob.getZ());
|
||||||
|
Vec3 localOffset = AntarchyGravityRotationUtil.vecWorldToPlayer(
|
||||||
|
worldOffset,
|
||||||
|
AntarchyGravityApi.getGravityDirection(this.mob));
|
||||||
|
this.wantedX = this.mob.getX() + localOffset.x;
|
||||||
|
this.wantedY = this.mob.getY() + localOffset.y;
|
||||||
|
this.wantedZ = this.mob.getZ() + localOffset.z;
|
||||||
|
this.speedModifier = speed;
|
||||||
|
}
|
||||||
|
}
|
||||||
+161
@@ -0,0 +1,161 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.gravity;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.entity.PathfinderMob;
|
||||||
|
import net.minecraft.world.entity.Pose;
|
||||||
|
import net.minecraft.world.entity.ai.goal.RandomStrollGoal;
|
||||||
|
import net.minecraft.world.entity.EntityDimensions;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(RandomStrollGoal.class)
|
||||||
|
public abstract class RandomStrollGoalGravityMixin {
|
||||||
|
@Unique
|
||||||
|
private static final int ANTARCHY$INVERTED_STROLL_ATTEMPTS = 12;
|
||||||
|
@Unique
|
||||||
|
private static final int ANTARCHY$INVERTED_STROLL_HORIZONTAL_RANGE = 7;
|
||||||
|
@Unique
|
||||||
|
private static final int ANTARCHY$INVERTED_STROLL_VERTICAL_RANGE = 2;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
protected PathfinderMob mob;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
protected double wantedX;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
protected double wantedY;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
protected double wantedZ;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
protected double speedModifier;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
protected int interval;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
protected boolean forceTrigger;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private boolean checkNoActionTime;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private int antarchy$invertedStrollTicks;
|
||||||
|
|
||||||
|
@Inject(method = "canUse", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$useInvertedRandomStroll(CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
if (!AntarchyGravityApi.isGravityInverted(this.mob)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mob.hasControllingPassenger()) {
|
||||||
|
cir.setReturnValue(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.forceTrigger) {
|
||||||
|
if (this.checkNoActionTime && this.mob.getNoActionTime() >= 100) {
|
||||||
|
cir.setReturnValue(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int chance = Math.max(1, this.interval);
|
||||||
|
if (this.mob.getRandom().nextInt(chance) != 0) {
|
||||||
|
cir.setReturnValue(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cir.setReturnValue(this.antarchy$findInvertedStrollTarget());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "start", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$startInvertedRandomStroll(CallbackInfo ci) {
|
||||||
|
if (!AntarchyGravityApi.isGravityInverted(this.mob)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mob.getNavigation().stop();
|
||||||
|
this.mob.getMoveControl().setWantedPosition(this.wantedX, this.wantedY, this.wantedZ, this.speedModifier);
|
||||||
|
this.antarchy$invertedStrollTicks = 0;
|
||||||
|
this.forceTrigger = false;
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "canContinueToUse", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$continueInvertedRandomStroll(CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
if (!AntarchyGravityApi.isGravityInverted(this.mob)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double dx = this.wantedX - this.mob.getX();
|
||||||
|
double dy = this.wantedY - this.mob.getY();
|
||||||
|
double dz = this.wantedZ - this.mob.getZ();
|
||||||
|
boolean arrived = dx * dx + dy * dy + dz * dz <= 1.0D;
|
||||||
|
boolean timedOut = this.antarchy$invertedStrollTicks++ >= 200;
|
||||||
|
if (!arrived && !timedOut && !this.mob.hasControllingPassenger()) {
|
||||||
|
// RandomStrollGoal inherits Goal.tick(), so continuation is the
|
||||||
|
// declared per-tick hook available for refreshing direct movement.
|
||||||
|
this.mob.getMoveControl().setWantedPosition(this.wantedX, this.wantedY, this.wantedZ, this.speedModifier);
|
||||||
|
}
|
||||||
|
cir.setReturnValue(!this.mob.hasControllingPassenger() && !arrived && !timedOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private boolean antarchy$findInvertedStrollTarget() {
|
||||||
|
int baseX = Mth.floor(this.mob.getX());
|
||||||
|
int baseY = Mth.floor(this.mob.getY() + this.mob.getBbHeight()) - 1;
|
||||||
|
int baseZ = Mth.floor(this.mob.getZ());
|
||||||
|
|
||||||
|
for (int attempt = 0; attempt < ANTARCHY$INVERTED_STROLL_ATTEMPTS; attempt++) {
|
||||||
|
int x = baseX + this.mob.getRandom().nextInt(ANTARCHY$INVERTED_STROLL_HORIZONTAL_RANGE * 2 + 1) - ANTARCHY$INVERTED_STROLL_HORIZONTAL_RANGE;
|
||||||
|
int y = baseY + this.mob.getRandom().nextInt(ANTARCHY$INVERTED_STROLL_VERTICAL_RANGE * 2 + 1) - ANTARCHY$INVERTED_STROLL_VERTICAL_RANGE;
|
||||||
|
int z = baseZ + this.mob.getRandom().nextInt(ANTARCHY$INVERTED_STROLL_HORIZONTAL_RANGE * 2 + 1) - ANTARCHY$INVERTED_STROLL_HORIZONTAL_RANGE;
|
||||||
|
if (this.antarchy$isValidInvertedStrollTarget(x, y, z)) {
|
||||||
|
this.wantedX = x + 0.5D;
|
||||||
|
this.wantedY = y + 1.0D - 1.0E-3D;
|
||||||
|
this.wantedZ = z + 0.5D;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private boolean antarchy$isValidInvertedStrollTarget(int x, int y, int z) {
|
||||||
|
Level level = this.mob.level();
|
||||||
|
BlockPos ceilingPos = new BlockPos(x, y + 1, z);
|
||||||
|
if (!level.getBlockState(ceilingPos).isFaceSturdy(level, ceilingPos, Direction.DOWN)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityDimensions dimensions = this.mob.getDimensions(Pose.STANDING);
|
||||||
|
double halfWidth = dimensions.width() / 2.0D;
|
||||||
|
double topY = y + 1.0D - 1.0E-3D;
|
||||||
|
AABB bodyBox = new AABB(
|
||||||
|
x + 0.5D - halfWidth,
|
||||||
|
topY - dimensions.height(),
|
||||||
|
z + 0.5D - halfWidth,
|
||||||
|
x + 0.5D + halfWidth,
|
||||||
|
topY,
|
||||||
|
z + 0.5D + halfWidth
|
||||||
|
).deflate(1.0E-4D);
|
||||||
|
return level.noCollision(this.mob, bodyBox);
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.time;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
||||||
|
import net.minecraft.world.damagesource.DamageSource;
|
||||||
|
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 LivingEntityTimeDilationCleanupMixin {
|
||||||
|
@Inject(method = "die", at = @At("HEAD"))
|
||||||
|
private void antarchy$clearTimeDilationOnDeath(DamageSource damageSource, CallbackInfo ci) {
|
||||||
|
TimeDilationApi.clearRate((LivingEntity) (Object) this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,9 @@
|
|||||||
"GlowVinesUnderLeavesMixin",
|
"GlowVinesUnderLeavesMixin",
|
||||||
"GrindstoneMenuMixin",
|
"GrindstoneMenuMixin",
|
||||||
"LivingEntityJumpingAccessor",
|
"LivingEntityJumpingAccessor",
|
||||||
|
"CommandedMobMixin",
|
||||||
|
"LivingEntityRoyalEffectsMixin",
|
||||||
|
"MobCommandedTargetMixin",
|
||||||
"RoyalNoRespiteMixin",
|
"RoyalNoRespiteMixin",
|
||||||
"MantisClawWallClimbMixin",
|
"MantisClawWallClimbMixin",
|
||||||
"MilkBucketSizeResetMixin",
|
"MilkBucketSizeResetMixin",
|
||||||
@@ -64,12 +67,15 @@
|
|||||||
"gravity.FireworkRocketGravityMixin",
|
"gravity.FireworkRocketGravityMixin",
|
||||||
"gravity.GroundPathNavigationMixin",
|
"gravity.GroundPathNavigationMixin",
|
||||||
"gravity.LivingEntityMixin",
|
"gravity.LivingEntityMixin",
|
||||||
|
"gravity.MeleeAttackGoalGravityMixin",
|
||||||
|
"gravity.MoveControlGravityMixin",
|
||||||
"gravity.MobHurtMixin",
|
"gravity.MobHurtMixin",
|
||||||
"gravity.PathNavigationAccessor",
|
"gravity.PathNavigationAccessor",
|
||||||
"gravity.PlayerAttackMixin",
|
"gravity.PlayerAttackMixin",
|
||||||
"gravity.PlayerGravityMixin",
|
"gravity.PlayerGravityMixin",
|
||||||
"gravity.PlayerPoseFitMixin",
|
"gravity.PlayerPoseFitMixin",
|
||||||
"gravity.PlayerSneakMixin",
|
"gravity.PlayerSneakMixin",
|
||||||
|
"gravity.RandomStrollGoalGravityMixin",
|
||||||
"gravity.ProjectileGravityMixin",
|
"gravity.ProjectileGravityMixin",
|
||||||
"gravity.ServerChunkCacheAccessor",
|
"gravity.ServerChunkCacheAccessor",
|
||||||
"gravity.ServerEntityAccessor",
|
"gravity.ServerEntityAccessor",
|
||||||
@@ -86,6 +92,7 @@
|
|||||||
"time.CreeperTimeDilationMixin",
|
"time.CreeperTimeDilationMixin",
|
||||||
"time.EndCrystalTimeDilationMixin",
|
"time.EndCrystalTimeDilationMixin",
|
||||||
"time.LivingEntityTimeDilationMixin",
|
"time.LivingEntityTimeDilationMixin",
|
||||||
|
"time.LivingEntityTimeDilationCleanupMixin",
|
||||||
"time.LivingEntityAttackCooldownTimeDilationMixin",
|
"time.LivingEntityAttackCooldownTimeDilationMixin",
|
||||||
"time.LookControlTimeDilationMixin",
|
"time.LookControlTimeDilationMixin",
|
||||||
"time.MeleeAttackGoalTimeDilationMixin",
|
"time.MeleeAttackGoalTimeDilationMixin",
|
||||||
|
|||||||
+381
@@ -0,0 +1,381 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.8.0",
|
||||||
|
"animations": {
|
||||||
|
"animation": {
|
||||||
|
"loop": true,
|
||||||
|
"animation_length": 20.125,
|
||||||
|
"bones": {
|
||||||
|
"black_hole": {
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [0, -100, 0]
|
||||||
|
},
|
||||||
|
"19.125": {
|
||||||
|
"vector": [0, 505, 0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"19.125": {
|
||||||
|
"vector": [10, 10, 10]
|
||||||
|
},
|
||||||
|
"19.25": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"blocks": {
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.875": {
|
||||||
|
"post": {
|
||||||
|
"vector": [-141, 71, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"2.375": {
|
||||||
|
"post": {
|
||||||
|
"vector": [-141, 104, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"2.4583": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"blocks2": {
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.875": {
|
||||||
|
"post": {
|
||||||
|
"vector": [116, 72, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"2.375": {
|
||||||
|
"post": {
|
||||||
|
"vector": [116, 124, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"2.4583": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"blocks3": {
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"1.4167": {
|
||||||
|
"post": {
|
||||||
|
"vector": [-69, 96, -164]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"2.4583": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"blocks4": {
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.9583": {
|
||||||
|
"post": {
|
||||||
|
"vector": [35, 96, 135]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"2.4583": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"blocks5": {
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"2.375": {
|
||||||
|
"post": {
|
||||||
|
"vector": [113, 118, -188]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"2.4583": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"blocks6": {
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.7083": {
|
||||||
|
"post": {
|
||||||
|
"vector": [-114, 64, 112]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"1.2083": {
|
||||||
|
"post": {
|
||||||
|
"vector": [-146, 81, 162]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"1.9583": {
|
||||||
|
"post": {
|
||||||
|
"vector": [-146, 94, 162]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"2.4583": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"blocks7": {
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"1.9583": {
|
||||||
|
"post": {
|
||||||
|
"vector": [187, 123, 137]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"2.4583": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"blocks8": {
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"2.375": {
|
||||||
|
"post": {
|
||||||
|
"vector": [236, 124, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"2.4583": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"blocks9": {
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"1.9583": {
|
||||||
|
"post": {
|
||||||
|
"vector": [-239, 106, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"2.4583": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"blocks10": {
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.375": {
|
||||||
|
"post": {
|
||||||
|
"vector": [-10, 65, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"2.375": {
|
||||||
|
"post": {
|
||||||
|
"vector": [-10, 119, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"2.4583": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"blocks11": {
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"2.375": {
|
||||||
|
"post": {
|
||||||
|
"vector": [-223, 106, -145]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"2.4583": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"beam": {
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0.2, 0.5, 0.5]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.4167": {
|
||||||
|
"post": {
|
||||||
|
"vector": [-0.2, 3.6, 0.1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"1.5833": {
|
||||||
|
"post": {
|
||||||
|
"vector": [-0.1, 3.6, 0.1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"13.0833": {
|
||||||
|
"post": {
|
||||||
|
"vector": [0.4, 122.1, -0.4]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"18.9167": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"19.125": {
|
||||||
|
"vector": [0, 445, 0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"18.9167": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"19.5833": {
|
||||||
|
"vector": [83.7, 1, 0]
|
||||||
|
},
|
||||||
|
"20.125": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.8.0",
|
||||||
|
"animations": {
|
||||||
|
"idle": {
|
||||||
|
"loop": true,
|
||||||
|
"animation_length": 0.25,
|
||||||
|
"bones": {
|
||||||
|
"fireball": {
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.125": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1, 1.2]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.25": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.8.0",
|
||||||
|
"animations": {
|
||||||
|
"animation": {
|
||||||
|
"loop": true,
|
||||||
|
"animation_length": 0.5,
|
||||||
|
"bones": {
|
||||||
|
"ice_ball": {
|
||||||
|
"rotation": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"0.25": {
|
||||||
|
"vector": [180, 0, 52.5]
|
||||||
|
},
|
||||||
|
"0.5": {
|
||||||
|
"vector": [360, 0, 0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.125": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1.1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.25": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.375": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1.1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
},
|
||||||
|
"0.5": {
|
||||||
|
"post": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"lerp_mode": "catmullrom"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,363 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.8.0",
|
||||||
|
"animations": {
|
||||||
|
"animation": {
|
||||||
|
"animation_length": 5.0833,
|
||||||
|
"bones": {
|
||||||
|
"ice_spike": {
|
||||||
|
"position": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [0, -80, 0]
|
||||||
|
},
|
||||||
|
"0.0417": {
|
||||||
|
"vector": [-6, -66.67, 0]
|
||||||
|
},
|
||||||
|
"0.0833": {
|
||||||
|
"vector": [0, -53.34, 0]
|
||||||
|
},
|
||||||
|
"0.125": {
|
||||||
|
"vector": [-5, -40.01, 0]
|
||||||
|
},
|
||||||
|
"0.1667": {
|
||||||
|
"vector": [-0.33, -26.67, 0]
|
||||||
|
},
|
||||||
|
"0.25": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"0.8333": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"1.0": {
|
||||||
|
"vector": [0, -47, 0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"0.2083": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"0.25": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"0.3333": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"0.8333": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"1.0": {
|
||||||
|
"vector": [1, 0, 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ice_spike_impact": {
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"0.0417": [0, 0, 0],
|
||||||
|
"0.2083": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"0.25": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"0.2917": {
|
||||||
|
"vector": [1, 1.3, 1]
|
||||||
|
},
|
||||||
|
"0.3333": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sparkle": {
|
||||||
|
"scale": {
|
||||||
|
"0.0": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"0.2917": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"0.4583": {
|
||||||
|
"vector": [1.2, 2.5, 1]
|
||||||
|
},
|
||||||
|
"0.625": {
|
||||||
|
"vector": [0, 1, 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ice_spike_impact2": {
|
||||||
|
"scale": {
|
||||||
|
"1.0": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"1.0417": [0, 0, 0],
|
||||||
|
"1.2083": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"1.25": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"1.2917": {
|
||||||
|
"vector": [1, 1.3, 1]
|
||||||
|
},
|
||||||
|
"1.3333": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ice_spike2": {
|
||||||
|
"position": {
|
||||||
|
"1.0": {
|
||||||
|
"vector": [0, -80, 0]
|
||||||
|
},
|
||||||
|
"1.0417": {
|
||||||
|
"vector": [-6, -66.67, 0]
|
||||||
|
},
|
||||||
|
"1.0833": {
|
||||||
|
"vector": [0, -53.34, 0]
|
||||||
|
},
|
||||||
|
"1.125": {
|
||||||
|
"vector": [-5, -40.01, 0]
|
||||||
|
},
|
||||||
|
"1.1667": {
|
||||||
|
"vector": [-0.33, -26.67, 0]
|
||||||
|
},
|
||||||
|
"1.25": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"1.8333": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"2.0": {
|
||||||
|
"vector": [0, -47, 0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"1.0": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"1.2083": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"1.25": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"1.3333": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"1.8333": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"2.0": {
|
||||||
|
"vector": [1, 0, 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sparkle2": {
|
||||||
|
"scale": {
|
||||||
|
"1.0": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"1.2917": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"1.4583": {
|
||||||
|
"vector": [1.2, 2.5, 1]
|
||||||
|
},
|
||||||
|
"1.625": {
|
||||||
|
"vector": [0, 1, 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ice_spike_impact3": {
|
||||||
|
"scale": {
|
||||||
|
"2.0": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"2.0417": [0, 0, 0],
|
||||||
|
"2.2083": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"2.25": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"2.2917": {
|
||||||
|
"vector": [1, 1.3, 1]
|
||||||
|
},
|
||||||
|
"2.3333": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ice_spike3": {
|
||||||
|
"position": {
|
||||||
|
"2.0": {
|
||||||
|
"vector": [0, -80, 0]
|
||||||
|
},
|
||||||
|
"2.0417": {
|
||||||
|
"vector": [-6, -66.67, 0]
|
||||||
|
},
|
||||||
|
"2.0833": {
|
||||||
|
"vector": [0, -53.34, 0]
|
||||||
|
},
|
||||||
|
"2.125": {
|
||||||
|
"vector": [-5, -40.01, 0]
|
||||||
|
},
|
||||||
|
"2.1667": {
|
||||||
|
"vector": [-0.33, -26.67, 0]
|
||||||
|
},
|
||||||
|
"2.25": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"2.8333": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"3.0": {
|
||||||
|
"vector": [0, -47, 0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"2.0": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"2.2083": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"2.25": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"2.3333": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"2.8333": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"3.0": {
|
||||||
|
"vector": [1, 0, 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sparkle3": {
|
||||||
|
"scale": {
|
||||||
|
"2.0": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"2.2917": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"2.4583": {
|
||||||
|
"vector": [1.2, 2.5, 1]
|
||||||
|
},
|
||||||
|
"2.625": {
|
||||||
|
"vector": [0, 1, 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ice_spike_impact4": {
|
||||||
|
"scale": {
|
||||||
|
"3.0": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"3.0417": [0, 0, 0],
|
||||||
|
"3.2083": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"3.25": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"3.2917": {
|
||||||
|
"vector": [1, 1.3, 1]
|
||||||
|
},
|
||||||
|
"3.3333": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ice_spike4": {
|
||||||
|
"position": {
|
||||||
|
"3.0": {
|
||||||
|
"vector": [0, -80, 0]
|
||||||
|
},
|
||||||
|
"3.0417": {
|
||||||
|
"vector": [-6, -66.67, 0]
|
||||||
|
},
|
||||||
|
"3.0833": {
|
||||||
|
"vector": [0, -53.34, 0]
|
||||||
|
},
|
||||||
|
"3.125": {
|
||||||
|
"vector": [-5, -40.01, 0]
|
||||||
|
},
|
||||||
|
"3.1667": {
|
||||||
|
"vector": [-0.33, -26.67, 0]
|
||||||
|
},
|
||||||
|
"3.25": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"3.8333": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"4.0": {
|
||||||
|
"vector": [0, -47, 0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"3.0": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"3.2083": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"3.25": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"3.3333": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"3.8333": {
|
||||||
|
"vector": [1, 1, 1]
|
||||||
|
},
|
||||||
|
"4.0": {
|
||||||
|
"vector": [1, 0, 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sparkle4": {
|
||||||
|
"scale": {
|
||||||
|
"3.0": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"3.2917": {
|
||||||
|
"vector": [0, 0, 0]
|
||||||
|
},
|
||||||
|
"3.4583": {
|
||||||
|
"vector": [1.2, 2.5, 1]
|
||||||
|
},
|
||||||
|
"3.625": {
|
||||||
|
"vector": [0, 1, 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"particle_effects": {
|
||||||
|
"0.0": {
|
||||||
|
"effect": "particles"
|
||||||
|
},
|
||||||
|
"1.0": {
|
||||||
|
"effect": "particles",
|
||||||
|
"locator": "spike_2"
|
||||||
|
},
|
||||||
|
"2.0": {
|
||||||
|
"effect": "particles",
|
||||||
|
"locator": "spike_3"
|
||||||
|
},
|
||||||
|
"3.0": {
|
||||||
|
"effect": "particles",
|
||||||
|
"locator": "spike_4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "minecraft:block/air"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "minecraft:block/air"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"": {
|
||||||
|
"model": "minecraft:block/air"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,31 +1,41 @@
|
|||||||
{
|
{
|
||||||
"variants": {
|
"variants": {
|
||||||
"thickness=base,vertical_direction=down": {
|
"thickness=base,vertical_direction=down": {
|
||||||
"model": "antarchy:block/typhonite_spike_down_base"
|
"model": "antarchy:block/typhonite_spike_down_base",
|
||||||
|
"x": 180,
|
||||||
|
"uvlock": true
|
||||||
},
|
},
|
||||||
"thickness=base,vertical_direction=up": {
|
"thickness=base,vertical_direction=up": {
|
||||||
"model": "antarchy:block/typhonite_spike_up_base"
|
"model": "antarchy:block/typhonite_spike_up_base"
|
||||||
},
|
},
|
||||||
"thickness=frustum,vertical_direction=down": {
|
"thickness=frustum,vertical_direction=down": {
|
||||||
"model": "antarchy:block/typhonite_spike_down_frustum"
|
"model": "antarchy:block/typhonite_spike_down_frustum",
|
||||||
|
"x": 180,
|
||||||
|
"uvlock": true
|
||||||
},
|
},
|
||||||
"thickness=frustum,vertical_direction=up": {
|
"thickness=frustum,vertical_direction=up": {
|
||||||
"model": "antarchy:block/typhonite_spike_up_frustum"
|
"model": "antarchy:block/typhonite_spike_up_frustum"
|
||||||
},
|
},
|
||||||
"thickness=middle,vertical_direction=down": {
|
"thickness=middle,vertical_direction=down": {
|
||||||
"model": "antarchy:block/typhonite_spike_down_middle"
|
"model": "antarchy:block/typhonite_spike_down_middle",
|
||||||
|
"x": 180,
|
||||||
|
"uvlock": true
|
||||||
},
|
},
|
||||||
"thickness=middle,vertical_direction=up": {
|
"thickness=middle,vertical_direction=up": {
|
||||||
"model": "antarchy:block/typhonite_spike_up_middle"
|
"model": "antarchy:block/typhonite_spike_up_middle"
|
||||||
},
|
},
|
||||||
"thickness=tip,vertical_direction=down": {
|
"thickness=tip,vertical_direction=down": {
|
||||||
"model": "antarchy:block/typhonite_spike_down_tip"
|
"model": "antarchy:block/typhonite_spike_down_tip",
|
||||||
|
"x": 180,
|
||||||
|
"uvlock": true
|
||||||
},
|
},
|
||||||
"thickness=tip,vertical_direction=up": {
|
"thickness=tip,vertical_direction=up": {
|
||||||
"model": "antarchy:block/typhonite_spike_up_tip"
|
"model": "antarchy:block/typhonite_spike_up_tip"
|
||||||
},
|
},
|
||||||
"thickness=tip_merge,vertical_direction=down": {
|
"thickness=tip_merge,vertical_direction=down": {
|
||||||
"model": "antarchy:block/typhonite_spike_down_tip_merge"
|
"model": "antarchy:block/typhonite_spike_down_tip_merge",
|
||||||
|
"x": 180,
|
||||||
|
"uvlock": true
|
||||||
},
|
},
|
||||||
"thickness=tip_merge,vertical_direction=up": {
|
"thickness=tip_merge,vertical_direction=up": {
|
||||||
"model": "antarchy:block/typhonite_spike_up_tip_merge"
|
"model": "antarchy:block/typhonite_spike_up_tip_merge"
|
||||||
|
|||||||
Loaded 100 of 169 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user