Merge beta7 into master

This commit is contained in:
craisinlord committed 2026-07-09 20:16:39 -05:00
commit 0db80e3cb7
335 files changed
+18289 -8157

No files matched your search

+11 -4
View File
@@ -27,14 +27,18 @@ dependencies {
// compileOnly(files("$rootDir/infinite_dimensions_jars/soul-fire-d-neoforge-1.21-6.1.0.jar")) // compileOnly(files("$rootDir/infinite_dimensions_jars/soul-fire-d-neoforge-1.21-6.1.0.jar"))
// compileOnly(files("$rootDir/infinite_dimensions_jars/prometheus-neoforge-1.21-1.2.5.jar")) // compileOnly(files("$rootDir/infinite_dimensions_jars/prometheus-neoforge-1.21-1.2.5.jar"))
compileOnly(files("$rootDir/infinite_dimensions_jars/sable-neoforge-1.21.1-2.0.3.jar")) compileOnly(files("$rootDir/infinite_dimensions_jars/sable-neoforge-1.21.1-2.0.3.jar"))
compileOnly(files("$rootDir/infinite_dimensions_jars/antarchy-1.0.0+1.21.1-neoforge.jar")) // compileOnly(files("$rootDir/infinite_dimensions_jars/antarchy-1.0.0+1.21.1-neoforge.jar"))
// NeoForge jar (not fabric) — sizeable_foliage's fabric jar is intermediary-mapped
// (Fabric remaps to intermediary for shipping, not official names), which common's
// official-Mojang-mapped compile can't resolve directly. NeoForge jars use official
// names throughout, so this is the one common can safely compile against.
compileOnly(files("$rootDir/sizeable_foliage_jars/sizeable_foliage-neoforge-1.21.1-1.0.0.jar"))
compileOnly("software.bernie.geckolib:geckolib-neoforge-${minecraft_version}:${geckolib_version}") compileOnly("software.bernie.geckolib:geckolib-neoforge-${minecraft_version}:${geckolib_version}")
// //
// compileOnly group: 'org.ow2.asm', name: 'asm-tree', version: '9.4' // compileOnly group: 'org.ow2.asm', name: 'asm-tree', version: '9.4'
// implementation group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.2' // implementation group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.2'
annotationProcessor "org.spongepowered:mixin:0.8.7:processor"
implementation(annotationProcessor("io.github.llamalad7:mixinextras-common:${rootProject.mixin_extras}")) implementation(annotationProcessor("io.github.llamalad7:mixinextras-common:${rootProject.mixin_extras}"))
} }
@@ -42,10 +46,13 @@ architectury {
common("fabric", "neoforge") common("fabric", "neoforge")
} }
// No mixin AP / refmap in common: the fabric project compiles common's sources itself
// and generates its own refmap. With the legacy AP enabled here, loom injects a
// "refmap" line into the built antarchy-common.mixins.json, which breaks NeoForge
// (it resolves to fabric-only intermediary names like field_6353).
loom { loom {
mixin { mixin {
useLegacyMixinAp = true useLegacyMixinAp = false
defaultRefmapName = "antarchy.refmap.json"
} }
} }
@@ -17,6 +17,7 @@ public final class AntarchySettings {
private static boolean duplicatorTreeEnabled = true; private static boolean duplicatorTreeEnabled = true;
private static boolean glowingTorchflowers = true; private static boolean glowingTorchflowers = true;
private static boolean glowVinesUnderLeaves = true; private static boolean glowVinesUnderLeaves = true;
private static boolean swingThroughGrassEnabled = true;
private static boolean sizeChangingRaysEnabled = true; private static boolean sizeChangingRaysEnabled = true;
private static double sizeRayMinScale = 0.1D; private static double sizeRayMinScale = 0.1D;
private static double sizeRayMaxScale = 10.0D; private static double sizeRayMaxScale = 10.0D;
@@ -100,12 +101,17 @@ public final class AntarchySettings {
private static double mantisMovementSpeed = 0.42D; private static double mantisMovementSpeed = 0.42D;
private static double mantisFlyingSpeed = 0.77D; private static double mantisFlyingSpeed = 0.77D;
private static boolean mantisIgnoreLightLevel = false; private static boolean mantisIgnoreLightLevel = false;
private static double alphaMantisHealth = 500.0D; private static double alphaMantisHealth = 250.0D;
private static double alphaMantisAttackDamage = 18.0D; private static double alphaMantisAttackDamage = 18.0D;
private static double alphaMantisMovementSpeed = 0.42D; private static double alphaMantisMovementSpeed = 0.546D;
private static double alphaMantisFlyingSpeed = 0.77D; private static double alphaMantisFlyingSpeed = 0.77D;
private static int alphaMantisSummonIntervalTicks = 300; private static int alphaMantisSummonIntervalTicks = 300;
private static int alphaMantisMaxMinions = 4; private static int alphaMantisMaxMinions = 4;
private static double rollyPollyHealth = 12.0D;
private static double rollyPollyMovementSpeed = 0.3D;
private static double rollyPollyRollSpeedMultiplier = 2.2D;
private static double rollyPollyTumbleDamage = 1.0D;
private static int rollyPollyTameChance = 3;
private static double krakenProjectileDamageTakenMultiplier = 0.5D; private static double krakenProjectileDamageTakenMultiplier = 0.5D;
private static boolean krakenSquidSpawnEnabled = true; private static boolean krakenSquidSpawnEnabled = true;
private static boolean krakenMassSpawnEnabled = true; private static boolean krakenMassSpawnEnabled = true;
@@ -156,7 +162,7 @@ public final class AntarchySettings {
private static int basiliskSpawnMaxLightLevel = 5; private static int basiliskSpawnMaxLightLevel = 5;
private static double basiliskHealth = 150.0D; private static double basiliskHealth = 150.0D;
private static double basiliskAttackDamage = 36.0D; private static double basiliskAttackDamage = 36.0D;
private static double basiliskMovementSpeed = 0.225D; private static double basiliskMovementSpeed = 0.18D;
private static double basiliskArmor = 6.0D; private static double basiliskArmor = 6.0D;
private static double basiliskKnockbackResistance = 0.5D; private static double basiliskKnockbackResistance = 0.5D;
private static double basiliskFollowRange = 28.0D; private static double basiliskFollowRange = 28.0D;
@@ -233,10 +239,10 @@ public final class AntarchySettings {
private static final int reverieAmbientTargetMaxAgeTicks = 40; private static final int reverieAmbientTargetMaxAgeTicks = 40;
private static final int reverieAmbientPulseIntervalMinTicks = 12; private static final int reverieAmbientPulseIntervalMinTicks = 12;
private static final int reverieAmbientPulseIntervalMaxTicks = 19; private static final int reverieAmbientPulseIntervalMaxTicks = 19;
private static double emperorScorpionHealth = 400.0D; private static double emperorScorpionHealth = 300.0D;
private static double emperorScorpionAttackDamage = 28.0D; private static double emperorScorpionAttackDamage = 28.0D;
private static double emperorScorpionMovementSpeed = 0.32D; private static double emperorScorpionMovementSpeed = 0.384D;
private static double emperorScorpionArmor = 25.0D; private static double emperorScorpionArmor = 22.0D;
private static double emperorScorpionKnockbackResistance = 0.8D; private static double emperorScorpionKnockbackResistance = 0.8D;
private static double emperorScorpionFollowRange = 40.0D; private static double emperorScorpionFollowRange = 40.0D;
private static int emperorScorpionXpReward = 25; private static int emperorScorpionXpReward = 25;
@@ -441,6 +447,11 @@ public final class AntarchySettings {
private static double primordialArmorKnockbackPerPiece = 0.5D; private static double primordialArmorKnockbackPerPiece = 0.5D;
private static int fallenKingCrownArmorValue = 2; private static int fallenKingCrownArmorValue = 2;
private static double fallenKingCrownArmorToughness = 0.0D; private static double fallenKingCrownArmorToughness = 0.0D;
private static boolean permanentPortalsEnabled = true;
private static boolean permanentPortalsFlintAndSteelEnabled = false;
private static boolean elythiaPortalEnabled = true;
private static boolean thoraxisPortalEnabled = true;
private static boolean cavarynPortalEnabled = true;
private static boolean elythiaFireflyParticlesEnabled = true; private static boolean elythiaFireflyParticlesEnabled = true;
private static int bloodCrystalArmorShieldRechargeTicks = 600; private static int bloodCrystalArmorShieldRechargeTicks = 600;
private static int bloodCrystalAppleShieldCount = 2; private static int bloodCrystalAppleShieldCount = 2;
@@ -479,6 +490,7 @@ public final class AntarchySettings {
private static double herculesBeetleHealth = 500.0D; private static double herculesBeetleHealth = 500.0D;
private static double herculesBeetleAttackDamage = 30.0D; private static double herculesBeetleAttackDamage = 30.0D;
private static double herculesBeetleChargeDamage = 40.0D; private static double herculesBeetleChargeDamage = 40.0D;
private static double glimmerHealth = 20.0D;
private AntarchySettings() { private AntarchySettings() {
} }
@@ -535,6 +547,10 @@ public final class AntarchySettings {
return glowVinesUnderLeaves; return glowVinesUnderLeaves;
} }
public static boolean swingThroughGrassEnabled() {
return swingThroughGrassEnabled;
}
public static boolean sizeChangingRaysEnabled() { public static boolean sizeChangingRaysEnabled() {
return sizeChangingRaysEnabled; return sizeChangingRaysEnabled;
} }
@@ -819,6 +835,26 @@ public final class AntarchySettings {
return alphaMantisMaxMinions; return alphaMantisMaxMinions;
} }
public static double rollyPollyHealth() {
return rollyPollyHealth;
}
public static double rollyPollyMovementSpeed() {
return rollyPollyMovementSpeed;
}
public static double rollyPollyRollSpeedMultiplier() {
return rollyPollyRollSpeedMultiplier;
}
public static double rollyPollyTumbleDamage() {
return rollyPollyTumbleDamage;
}
public static int rollyPollyTameChance() {
return rollyPollyTameChance;
}
public static double waspHealth() { public static double waspHealth() {
return waspHealth; return waspHealth;
} }
@@ -927,6 +963,32 @@ public final class AntarchySettings {
rainbowAntsLeadToInfinityDimensions = value; rainbowAntsLeadToInfinityDimensions = value;
} }
public static void setPermanentPortalsEnabled(boolean value) {
permanentPortalsEnabled = value;
}
public static void setPermanentPortalsFlintAndSteelEnabled(boolean value) {
permanentPortalsFlintAndSteelEnabled = value;
}
public static void setElythiaPortalEnabled(boolean value) {
elythiaPortalEnabled = value;
}
public static void setThoraxisPortalEnabled(boolean value) {
thoraxisPortalEnabled = value;
}
public static void setCavarynPortalEnabled(boolean value) {
cavarynPortalEnabled = value;
}
public static boolean permanentPortalsEnabled() { return permanentPortalsEnabled; }
public static boolean permanentPortalsFlintAndSteelEnabled() { return permanentPortalsFlintAndSteelEnabled; }
public static boolean elythiaPortalEnabled() { return elythiaPortalEnabled; }
public static boolean thoraxisPortalEnabled() { return thoraxisPortalEnabled; }
public static boolean cavarynPortalEnabled() { return cavarynPortalEnabled; }
public static void setBrownAntRequiresReagent(boolean value) { public static void setBrownAntRequiresReagent(boolean value) {
brownAntRequiresReagent = value; brownAntRequiresReagent = value;
} }
@@ -959,6 +1021,10 @@ public final class AntarchySettings {
glowVinesUnderLeaves = value; glowVinesUnderLeaves = value;
} }
public static void setSwingThroughGrassEnabled(boolean value) {
swingThroughGrassEnabled = value;
}
public static void setSizeChangingRaysEnabled(boolean value) { public static void setSizeChangingRaysEnabled(boolean value) {
sizeChangingRaysEnabled = value; sizeChangingRaysEnabled = value;
} }
@@ -1247,6 +1313,26 @@ public final class AntarchySettings {
alphaMantisMaxMinions = value; alphaMantisMaxMinions = value;
} }
public static void setRollyPollyHealth(double value) {
rollyPollyHealth = value;
}
public static void setRollyPollyMovementSpeed(double value) {
rollyPollyMovementSpeed = value;
}
public static void setRollyPollyRollSpeedMultiplier(double value) {
rollyPollyRollSpeedMultiplier = value;
}
public static void setRollyPollyTumbleDamage(double value) {
rollyPollyTumbleDamage = value;
}
public static void setRollyPollyTameChance(int value) {
rollyPollyTameChance = value;
}
public static void setKrakenProjectileDamageTakenMultiplier(double value) { public static void setKrakenProjectileDamageTakenMultiplier(double value) {
krakenProjectileDamageTakenMultiplier = value; krakenProjectileDamageTakenMultiplier = value;
} }
@@ -2462,4 +2548,6 @@ public final class AntarchySettings {
public static double herculesBeetleChargeDamage() { return herculesBeetleChargeDamage; } public static double herculesBeetleChargeDamage() { return herculesBeetleChargeDamage; }
public static void setHerculesBeetleChargeDamage(double v) { herculesBeetleChargeDamage = v; } public static void setHerculesBeetleChargeDamage(double v) { herculesBeetleChargeDamage = v; }
public static void setDorrieHealth(double v) { dorrieHealth = v; } public static void setDorrieHealth(double v) { dorrieHealth = v; }
public static double glimmerHealth() { return glimmerHealth; }
public static void setGlimmerHealth(double v) { glimmerHealth = v; }
} }
@@ -6,7 +6,7 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
public final class ConfigResetGuard { public final class ConfigResetGuard {
public static final int RESET_GENERATION = 1; public static final int RESET_GENERATION = 2;
private static final String MARKER_FILE_NAME = ".config_generation"; private static final String MARKER_FILE_NAME = ".config_generation";
private ConfigResetGuard() { private ConfigResetGuard() {
@@ -99,6 +99,10 @@ public final class AntarchyObjects {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<EntityType<HerculesBeetleEntity>> HERCULES_BEETLE = (Supplier<EntityType<HerculesBeetleEntity>>) UNBOUND; public static Supplier<EntityType<HerculesBeetleEntity>> HERCULES_BEETLE = (Supplier<EntityType<HerculesBeetleEntity>>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.GlimmerEntity>> GLIMMER = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.GlimmerEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Holder<MobEffect>> GLIMMERS_GRACE = (Supplier<Holder<MobEffect>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<net.minecraft.world.item.Item> CHEEP_ITEM = (Supplier<net.minecraft.world.item.Item>) UNBOUND; public static Supplier<net.minecraft.world.item.Item> CHEEP_ITEM = (Supplier<net.minecraft.world.item.Item>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<Block> DUPLICATOR_LOG = (Supplier<Block>) UNBOUND; public static Supplier<Block> DUPLICATOR_LOG = (Supplier<Block>) UNBOUND;
@@ -211,8 +215,6 @@ public final class AntarchyObjects {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<Block> PINK_MILKWEED = (Supplier<Block>) UNBOUND; public static Supplier<Block> PINK_MILKWEED = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<Block> TORCHFLOWER_BUSH = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> BED_BUG_EGG = (Supplier<Block>) UNBOUND; public static Supplier<Block> BED_BUG_EGG = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Supplier<Block> CREEPING_HORROR_EGGS = (Supplier<Block>) UNBOUND; public static Supplier<Block> CREEPING_HORROR_EGGS = (Supplier<Block>) UNBOUND;
@@ -262,7 +264,11 @@ public final class AntarchyObjects {
Supplier<EntityType<HushProjectileEntity>> hushProjectile, Supplier<EntityType<HushProjectileEntity>> hushProjectile,
Supplier<EntityType<ToreterrorEntity>> toreterror, Supplier<EntityType<ToreterrorEntity>> toreterror,
Supplier<EntityType<WaterBombEntity>> waterBomb, Supplier<EntityType<WaterBombEntity>> waterBomb,
Supplier<EntityType<CreepingHorrorEntity>> creepingHorror,
Supplier<EntityType<LurkingTerrorEntity>> lurkingTerror,
Supplier<EntityType<StinkBugEntity>> stinkBug,
Supplier<EntityType<com.craisinlord.antarchy.content.entity.CheepEntity>> cheep, Supplier<EntityType<com.craisinlord.antarchy.content.entity.CheepEntity>> cheep,
Supplier<EntityType<com.craisinlord.antarchy.content.entity.DorrieEntity>> dorrie,
Supplier<Block> duplicatorLog, Supplier<Block> duplicatorLog,
Supplier<Block> duplicatorSapling, Supplier<Block> duplicatorSapling,
Supplier<Block> ductTape, Supplier<Block> ductTape,
@@ -291,6 +297,8 @@ public final class AntarchyObjects {
Supplier<Block> triffidGooBlock, Supplier<Block> triffidGooBlock,
Supplier<Block> paleNyxite, Supplier<Block> paleNyxite,
Supplier<Block> nyxiteSpike, Supplier<Block> nyxiteSpike,
Supplier<Block> chitenBlock,
Supplier<Block> chitenSpike,
Supplier<Block> potentNyxite, Supplier<Block> potentNyxite,
Supplier<Block> antimetal, Supplier<Block> antimetal,
Supplier<Block> polishedAntimetal, Supplier<Block> polishedAntimetal,
@@ -303,6 +311,7 @@ public final class AntarchyObjects {
Supplier<Item> krakenTooth, Supplier<Item> krakenTooth,
Supplier<Item> moggles, Supplier<Item> moggles,
Supplier<Item> reverieBottle, Supplier<Item> reverieBottle,
Supplier<Item> stinkBugItem,
Supplier<Holder<MobEffect>> dread, Supplier<Holder<MobEffect>> dread,
Supplier<Holder<MobEffect>> paralyzedEffect, Supplier<Holder<MobEffect>> paralyzedEffect,
Supplier<Holder<MobEffect>> invertedEffect, Supplier<Holder<MobEffect>> invertedEffect,
@@ -312,8 +321,9 @@ public final class AntarchyObjects {
Supplier<Block> mossyOuranwoodWood, Supplier<Block> mossyOuranwoodWood,
Supplier<Block> orangeMilkweed, Supplier<Block> orangeMilkweed,
Supplier<Block> pinkMilkweed, Supplier<Block> pinkMilkweed,
Supplier<Block> torchflowerBush,
Supplier<Block> bedBugEggs, Supplier<Block> bedBugEggs,
Supplier<Block> creepingHorrorEggs,
Supplier<Block> lurkingTerrorEggs,
Supplier<Block> waspNest, Supplier<Block> waspNest,
Supplier<Block> hushweed, Supplier<Block> hushweed,
Supplier<Block> squirrelNestBlock, Supplier<Block> squirrelNestBlock,
@@ -347,7 +357,11 @@ public final class AntarchyObjects {
HUSH_PROJECTILE = hushProjectile; HUSH_PROJECTILE = hushProjectile;
TORETERROR = toreterror; TORETERROR = toreterror;
WATER_BOMB = waterBomb; WATER_BOMB = waterBomb;
CREEPING_HORROR = creepingHorror;
LURKING_TERROR = lurkingTerror;
STINK_BUG = stinkBug;
CHEEP = cheep; CHEEP = cheep;
DORRIE = dorrie;
DUPLICATOR_LOG = duplicatorLog; DUPLICATOR_LOG = duplicatorLog;
DUPLICATOR_SAPLING = duplicatorSapling; DUPLICATOR_SAPLING = duplicatorSapling;
DUCT_TAPE = ductTape; DUCT_TAPE = ductTape;
@@ -376,6 +390,8 @@ public final class AntarchyObjects {
TRIFFID_GOO_BLOCK = triffidGooBlock; TRIFFID_GOO_BLOCK = triffidGooBlock;
PALE_NYXITE = paleNyxite; PALE_NYXITE = paleNyxite;
NYXITE_SPIKE = nyxiteSpike; NYXITE_SPIKE = nyxiteSpike;
CHITEN_BLOCK = chitenBlock;
CHITEN_SPIKE = chitenSpike;
POTENT_NYXITE = potentNyxite; POTENT_NYXITE = potentNyxite;
ANTIMETAL = antimetal; ANTIMETAL = antimetal;
POLISHED_ANTIMETAL = polishedAntimetal; POLISHED_ANTIMETAL = polishedAntimetal;
@@ -388,6 +404,7 @@ public final class AntarchyObjects {
KRAKEN_TOOTH = krakenTooth; KRAKEN_TOOTH = krakenTooth;
MOGGLES = moggles; MOGGLES = moggles;
REVERIE_BOTTLE = reverieBottle; REVERIE_BOTTLE = reverieBottle;
STINK_BUG_ITEM = stinkBugItem;
DREAD = dread; DREAD = dread;
PARALYZED_EFFECT = paralyzedEffect; PARALYZED_EFFECT = paralyzedEffect;
INVERTED_EFFECT = invertedEffect; INVERTED_EFFECT = invertedEffect;
@@ -397,8 +414,9 @@ public final class AntarchyObjects {
MOSSY_OURANWOOD_WOOD = mossyOuranwoodWood; MOSSY_OURANWOOD_WOOD = mossyOuranwoodWood;
ORANGE_MILKWEED = orangeMilkweed; ORANGE_MILKWEED = orangeMilkweed;
PINK_MILKWEED = pinkMilkweed; PINK_MILKWEED = pinkMilkweed;
TORCHFLOWER_BUSH = torchflowerBush;
BED_BUG_EGG = bedBugEggs; BED_BUG_EGG = bedBugEggs;
CREEPING_HORROR_EGGS = creepingHorrorEggs;
LURKING_TERROR_EGGS = lurkingTerrorEggs;
WASP_NEST = waspNest; WASP_NEST = waspNest;
HUSHWEED = hushweed; HUSHWEED = hushweed;
SQUIRREL_NEST_BLOCK = squirrelNestBlock; SQUIRREL_NEST_BLOCK = squirrelNestBlock;
@@ -426,6 +444,14 @@ public final class AntarchyObjects {
HERCULES_BEETLE = supplier; HERCULES_BEETLE = supplier;
} }
public static void setGlimmer(Supplier<EntityType<com.craisinlord.antarchy.content.entity.GlimmerEntity>> supplier) {
GLIMMER = supplier;
}
public static void setGlimmersGrace(Supplier<Holder<MobEffect>> supplier) {
GLIMMERS_GRACE = supplier;
}
public static BlockBehaviour.Properties shellstoneProperties() { public static BlockBehaviour.Properties shellstoneProperties() {
return BlockBehaviour.Properties.ofFullCopy(Blocks.STONE).requiresCorrectToolForDrops(); return BlockBehaviour.Properties.ofFullCopy(Blocks.STONE).requiresCorrectToolForDrops();
} }
@@ -126,6 +126,9 @@ public final class AntarchySoundEvents {
public static Supplier<SoundEvent> TORETERROR_HURT = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> TORETERROR_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TORETERROR_DEATH = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> TORETERROR_DEATH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TORETERROR_BOMBER_FIRE = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> TORETERROR_BOMBER_FIRE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TORETERROR_SPIN = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TORETERROR_RICOCHET = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> WATER_CANNON_FIRE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TORETERROR_JUMP_UP = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> TORETERROR_JUMP_UP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TORETERROR_JUMP_LAND = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> TORETERROR_JUMP_LAND = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> STINKY_FLY = (Supplier<SoundEvent>) UNBOUND; public static Supplier<SoundEvent> STINKY_FLY = (Supplier<SoundEvent>) UNBOUND;
@@ -259,6 +262,9 @@ public final class AntarchySoundEvents {
Supplier<SoundEvent> toreterrorHurt, Supplier<SoundEvent> toreterrorHurt,
Supplier<SoundEvent> toreterrorDeath, Supplier<SoundEvent> toreterrorDeath,
Supplier<SoundEvent> toreterrorBomberFire, Supplier<SoundEvent> toreterrorBomberFire,
Supplier<SoundEvent> toreterrorSpin,
Supplier<SoundEvent> toreterrorRicochet,
Supplier<SoundEvent> waterCannonFire,
Supplier<SoundEvent> toreterrorJumpUp, Supplier<SoundEvent> toreterrorJumpUp,
Supplier<SoundEvent> toreterrorJumpLand, Supplier<SoundEvent> toreterrorJumpLand,
Supplier<SoundEvent> stinkyFly, Supplier<SoundEvent> stinkyFly,
@@ -388,6 +394,9 @@ public final class AntarchySoundEvents {
TORETERROR_HURT = toreterrorHurt; TORETERROR_HURT = toreterrorHurt;
TORETERROR_DEATH = toreterrorDeath; TORETERROR_DEATH = toreterrorDeath;
TORETERROR_BOMBER_FIRE = toreterrorBomberFire; TORETERROR_BOMBER_FIRE = toreterrorBomberFire;
TORETERROR_SPIN = toreterrorSpin;
TORETERROR_RICOCHET = toreterrorRicochet;
WATER_CANNON_FIRE = waterCannonFire;
TORETERROR_JUMP_UP = toreterrorJumpUp; TORETERROR_JUMP_UP = toreterrorJumpUp;
TORETERROR_JUMP_LAND = toreterrorJumpLand; TORETERROR_JUMP_LAND = toreterrorJumpLand;
STINKY_FLY = stinkyFly; STINKY_FLY = stinkyFly;
@@ -31,6 +31,9 @@ public final class AntarchyTags {
public static final TagKey<Block> TERMITE_FOODS = TagKey.create(Registries.BLOCK, id("termite_foods")); public static final TagKey<Block> TERMITE_FOODS = TagKey.create(Registries.BLOCK, id("termite_foods"));
public static final TagKey<Block> UMBRAL_MOSS_REPLACEABLE = TagKey.create(Registries.BLOCK, id("umbral_moss_replaceable")); public static final TagKey<Block> UMBRAL_MOSS_REPLACEABLE = TagKey.create(Registries.BLOCK, id("umbral_moss_replaceable"));
public static final TagKey<Block> HERCULES_BEETLE_CHARGE_IMMUNE_BLOCKS = TagKey.create(Registries.BLOCK, id("hercules_beetle_charge_immune_blocks")); public static final TagKey<Block> HERCULES_BEETLE_CHARGE_IMMUNE_BLOCKS = TagKey.create(Registries.BLOCK, id("hercules_beetle_charge_immune_blocks"));
public static final TagKey<Block> ELYTHIA_PORTAL_FRAMES = TagKey.create(Registries.BLOCK, id("elythia_portal_frames"));
public static final TagKey<Block> THORAXIS_PORTAL_FRAMES = TagKey.create(Registries.BLOCK, id("thoraxis_portal_frames"));
public static final TagKey<Block> CAVARYN_PORTAL_FRAMES = TagKey.create(Registries.BLOCK, id("cavaryn_portal_frames"));
private Blocks() { private Blocks() {
} }
@@ -90,6 +93,8 @@ public final class AntarchyTags {
public static final TagKey<Item> BUTTERFLY_BREEDING_FOODS = TagKey.create(Registries.ITEM, id("butterfly_breeding_foods")); public static final TagKey<Item> BUTTERFLY_BREEDING_FOODS = TagKey.create(Registries.ITEM, id("butterfly_breeding_foods"));
public static final TagKey<Item> REVERIE_DUPLICATION_ITEMS = TagKey.create(Registries.ITEM, id("reverie_duplication_items")); public static final TagKey<Item> REVERIE_DUPLICATION_ITEMS = TagKey.create(Registries.ITEM, id("reverie_duplication_items"));
public static final TagKey<Item> HERCULES_BEETLE_FOOD = TagKey.create(Registries.ITEM, id("hercules_beetle_food")); public static final TagKey<Item> HERCULES_BEETLE_FOOD = TagKey.create(Registries.ITEM, id("hercules_beetle_food"));
public static final TagKey<Item> ROLLY_POLLY_FOOD = TagKey.create(Registries.ITEM, id("rolly_polly_food"));
public static final TagKey<Item> GLIMMER_FOOD = TagKey.create(Registries.ITEM, id("glimmer_food"));
private Items() { private Items() {
} }
@@ -0,0 +1,45 @@
package com.craisinlord.antarchy.content;
import net.minecraft.core.particles.DustParticleOptions;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.phys.Vec3;
import org.joml.Vector3f;
public final class GlimmerParticles {
private static final int AMBIENT_INTERVAL_TICKS = 6;
private static final DustParticleOptions AMBIENT = new DustParticleOptions(new Vector3f(0.55F, 0.85F, 1.0F), 0.9F);
private static final DustParticleOptions TRAIL = new DustParticleOptions(new Vector3f(0.6F, 0.9F, 1.0F), 1.1F);
private GlimmerParticles() {
}
public static void tickAmbient(LivingEntity entity, boolean running) {
if (!(entity.level() instanceof ServerLevel serverLevel)) {
return;
}
if (!entity.isAlive() || entity.tickCount % AMBIENT_INTERVAL_TICKS != 0) {
return;
}
int count = running ? 2 : 1;
serverLevel.sendParticles(
AMBIENT,
entity.getRandomX(0.6D),
entity.getY(0.3D) + entity.getBbHeight() * 0.6D,
entity.getRandomZ(0.6D),
count,
0.15D,
0.2D,
0.15D,
0.0D
);
Vec3 motion = entity.getDeltaMovement();
if (running && motion.horizontalDistanceSqr() > 1.0E-4D) {
Vec3 direction = new Vec3(motion.x, 0.0D, motion.z).normalize();
Vec3 behind = entity.position().subtract(direction.scale(0.4D)).add(0.0D, 0.15D, 0.0D);
serverLevel.sendParticles(TRAIL, behind.x, behind.y, behind.z, 1, 0.05D, 0.05D, 0.05D, 0.0D);
}
}
}
@@ -0,0 +1,171 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.portal.PermanentPortalManager;
import com.craisinlord.antarchy.content.portal.PermanentPortalType;
import com.craisinlord.antarchy.content.portal.PermanentPortalTeleporter;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.portal.DimensionTransition;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public final class AntDimensionPortalBlock extends Block implements net.minecraft.world.level.block.Portal {
public static final EnumProperty<Direction.Axis> AXIS = BlockStateProperties.HORIZONTAL_AXIS;
private static final VoxelShape X_SHAPE = Block.box(0.0D, 0.0D, 6.0D, 16.0D, 16.0D, 10.0D);
private static final VoxelShape Z_SHAPE = Block.box(6.0D, 0.0D, 0.0D, 10.0D, 16.0D, 16.0D);
private final PermanentPortalType type;
private final MapCodec<AntDimensionPortalBlock> codec;
public AntDimensionPortalBlock(PermanentPortalType type, BlockBehaviour.Properties properties) {
super(properties);
this.type = type;
this.codec = Block.simpleCodec(ignored -> this);
this.registerDefaultState(this.stateDefinition.any().setValue(AXIS, Direction.Axis.X));
}
@Override
public MapCodec<AntDimensionPortalBlock> codec() {
return this.codec;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(AXIS);
}
@Override
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(AXIS) == Direction.Axis.X ? X_SHAPE : Z_SHAPE;
}
@Override
protected VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return Shapes.empty();
}
@Override
protected VoxelShape getVisualShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return Shapes.empty();
}
@Override
protected VoxelShape getBlockSupportShape(BlockState state, BlockGetter level, BlockPos pos) {
return Shapes.empty();
}
@Override
protected RenderShape getRenderShape(BlockState state) {
return RenderShape.MODEL;
}
@Override
protected boolean skipRendering(BlockState state, BlockState adjacentBlockState, Direction side) {
return adjacentBlockState.is(this) || super.skipRendering(state, adjacentBlockState, side);
}
@Override
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
if (!level.isClientSide()) {
entity.setAsInsidePortal(this, pos);
}
}
@Override
public net.minecraft.world.level.block.Portal.Transition getLocalTransition() {
return net.minecraft.world.level.block.Portal.Transition.CONFUSION;
}
@Override
public int getPortalTransitionTime(ServerLevel level, Entity entity) {
return 20;
}
@Override
public DimensionTransition getPortalDestination(ServerLevel level, Entity entity, BlockPos pos) {
return PermanentPortalTeleporter.createTransition(level, entity, pos, this.type);
}
@Override
protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
super.onPlace(state, level, pos, oldState, movedByPiston);
if (!level.isClientSide() && !state.is(oldState.getBlock())) {
level.scheduleTick(pos, this, 1);
}
}
@Override
protected BlockState updateShape(
BlockState state,
Direction direction,
BlockState neighborState,
LevelAccessor level,
BlockPos pos,
BlockPos neighborPos
) {
if (level instanceof ServerLevel serverLevel) {
serverLevel.scheduleTick(pos, this, 1);
}
return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
}
@Override
protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!PermanentPortalManager.isPortalStillValid(level, pos, this.type, state.getValue(AXIS))) {
level.setBlock(pos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL);
}
}
@Override
public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) {
if (random.nextInt(100) == 0) {
level.playLocalSound(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, SoundEvents.PORTAL_AMBIENT, SoundSource.BLOCKS, 0.35F, 0.9F + random.nextFloat() * 0.2F, false);
}
ParticleOptions particle = switch (this.type) {
case ELYTHIA -> ParticleTypes.SPORE_BLOSSOM_AIR;
case THORAXIS -> ParticleTypes.PORTAL;
case CAVARYN -> ParticleTypes.MYCELIUM;
};
for (int i = 0; i < 4; i++) {
double x = pos.getX() + random.nextDouble();
double y = pos.getY() + random.nextDouble();
double z = pos.getZ() + random.nextDouble();
if (state.getValue(AXIS) == Direction.Axis.X) {
z = pos.getZ() + 0.5D + (random.nextDouble() - 0.5D) * 0.25D;
} else {
x = pos.getX() + 0.5D + (random.nextDouble() - 0.5D) * 0.25D;
}
level.addParticle(
particle,
x,
y,
z,
(random.nextDouble() - 0.5D) * 0.2D,
(random.nextDouble() - 0.5D) * 0.2D,
(random.nextDouble() - 0.5D) * 0.2D
);
}
}
}
@@ -0,0 +1,291 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.ItemInteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.BonemealableBlock;
import net.minecraft.world.level.block.BushBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Multiblock bush grown with bonemeal. The origin block carries the
* loot/age; the rest of the footprint is filled with invisible
* {@link BigBushPartBlock}s.
*
* age 0: single block (1x1x1)
* age 1: 2x2x2 footprint; FACING + FACING.getClockWise() pick the horizontal quadrant
* age 2: 3x3x3 footprint centered on the origin column
*
* Grown stages require a sturdy support block under every column of their
* footprint. Growing from 2x2 to 3x3 may relocate the origin to any of the four
* occupied columns to find room.
*/
public class BigBushBlock extends BushBlock implements BonemealableBlock {
public static final MapCodec<BigBushBlock> CODEC = Block.simpleCodec(BigBushBlock::new);
public static final IntegerProperty AGE = BlockStateProperties.AGE_2;
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
private static final VoxelShape SMALL_SHAPE = Block.box(2.0, 0.0, 2.0, 14.0, 13.0, 14.0);
public BigBushBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any()
.setValue(AGE, 0)
.setValue(FACING, Direction.EAST));
}
@Override
public MapCodec<BigBushBlock> codec() {
return CODEC;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(AGE, FACING);
}
@Override
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(AGE) == 0 ? SMALL_SHAPE : Shapes.block();
}
/** All part positions belonging to a bush with the given origin state/pos */
public static List<BlockPos> partPositions(BlockState state, BlockPos origin) {
List<BlockPos> positions = new ArrayList<>();
int age = state.getValue(AGE);
if (age == 1) {
Direction forward = state.getValue(FACING);
Direction side = forward.getClockWise();
for (int dy = 0; dy <= 1; dy++) {
for (BlockPos column : new BlockPos[]{
origin, origin.relative(forward), origin.relative(side), origin.relative(forward).relative(side)}) {
BlockPos pos = column.above(dy);
if (!pos.equals(origin)) {
positions.add(pos);
}
}
}
} else if (age == 2) {
for (int dx = -1; dx <= 1; dx++) {
for (int dy = 0; dy <= 2; dy++) {
for (int dz = -1; dz <= 1; dz++) {
if (dx == 0 && dy == 0 && dz == 0) {
continue;
}
positions.add(origin.offset(dx, dy, dz));
}
}
}
}
return positions;
}
/** Ground columns of the footprint, each needs a sturdy block below it. */
public static List<BlockPos> supportColumns(BlockState state, BlockPos origin) {
List<BlockPos> columns = new ArrayList<>();
int age = state.getValue(AGE);
if (age == 1) {
Direction forward = state.getValue(FACING);
Direction side = forward.getClockWise();
columns.add(origin);
columns.add(origin.relative(forward));
columns.add(origin.relative(side));
columns.add(origin.relative(forward).relative(side));
} else if (age == 2) {
for (int dx = -1; dx <= 1; dx++) {
for (int dz = -1; dz <= 1; dz++) {
columns.add(origin.offset(dx, 0, dz));
}
}
} else {
columns.add(origin);
}
return columns;
}
public static boolean hasFullSupport(BlockState state, LevelReader level, BlockPos origin) {
for (BlockPos column : supportColumns(state, origin)) {
BlockPos below = column.below();
if (!level.getBlockState(below).isFaceSturdy(level, below, Direction.UP)) {
return false;
}
}
return true;
}
@Override
protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
if (state.getValue(AGE) == 0) {
return super.canSurvive(state, level, pos);
}
return hasFullSupport(state, level, pos);
}
private static Block partBlock() {
return BuiltInRegistries.BLOCK.get(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "big_bush_part"));
}
private record GrowthTarget(BlockPos origin, BlockState state) {}
@Nullable
private GrowthTarget findGrowthTarget(LevelReader level, BlockPos pos, BlockState state, RandomSource random) {
int age = state.getValue(AGE);
if (age == 0) {
List<Direction> facings = new ArrayList<>(Direction.Plane.HORIZONTAL.stream().toList());
for (int i = facings.size() - 1; i > 0; i--) {
Direction swap = facings.set(random.nextInt(i + 1), facings.get(i));
facings.set(i, swap);
}
for (Direction facing : facings) {
BlockState grown = state.setValue(AGE, 1).setValue(FACING, facing);
if (canGrowTo(level, pos, grown, Set.of(pos))) {
return new GrowthTarget(pos, grown);
}
}
return null;
}
if (age == 1) {
Direction forward = state.getValue(FACING);
Direction side = forward.getClockWise();
Set<BlockPos> owned = new HashSet<>(partPositions(state, pos));
owned.add(pos);
BlockState grown = state.setValue(AGE, 2);
// Any of the four occupied columns can become the new center of the 3x3.
for (BlockPos candidate : new BlockPos[]{
pos, pos.relative(forward).relative(side), pos.relative(forward), pos.relative(side)}) {
if (canGrowTo(level, candidate, grown, owned)) {
return new GrowthTarget(candidate, grown);
}
}
}
return null;
}
private boolean canGrowTo(LevelReader level, BlockPos newOrigin, BlockState grownState, Set<BlockPos> owned) {
if (!hasFullSupport(grownState, level, newOrigin)) {
return false;
}
List<BlockPos> positions = new ArrayList<>(partPositions(grownState, newOrigin));
positions.add(newOrigin);
for (BlockPos pos : positions) {
if (owned.contains(pos)) {
continue;
}
if (!level.getBlockState(pos).canBeReplaced()) {
return false;
}
}
return true;
}
public static void placeBushBlocks(LevelAccessor level, BlockPos origin, BlockState grownState, int flags) {
level.setBlock(origin, grownState, flags);
Block part = partBlock();
BlockPos capPos = grownState.getValue(AGE) == 2 ? origin.above(2) : null;
for (BlockPos pos : partPositions(grownState, origin)) {
level.setBlock(pos, part.defaultBlockState()
.setValue(BigBushPartBlock.CAP, pos.equals(capPos)), flags);
}
}
private void placeStage(ServerLevel level, BlockPos origin, BlockState grownState) {
placeBushBlocks(level, origin, grownState, 3);
}
@Override
protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
if (!state.is(newState.getBlock())) {
for (BlockPos partPos : partPositions(state, pos)) {
if (level.getBlockState(partPos).getBlock() instanceof BigBushPartBlock) {
level.setBlock(partPos, Blocks.AIR.defaultBlockState(), 35);
}
}
}
super.onRemove(state, level, pos, newState, movedByPiston);
}
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state) {
return state.getValue(AGE) < 2;
}
@Override
public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, BlockState state) {
return findGrowthTarget(level, pos, state, random) != null;
}
@Override
public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) {
GrowthTarget target = findGrowthTarget(level, pos, state, random);
if (target == null) {
return;
}
if (!target.origin().equals(pos)) {
level.removeBlock(pos, false);
}
placeStage(level, target.origin(), target.state());
}
/** Pops a bonus item when bone meal is used on a fully-grown (age 2) bush; shared with {@link BigBushPartBlock}. */
public static boolean grantBonemealBonus(Level level, BlockPos originPos, BlockState originState, Player player, ItemStack stack) {
if (!(originState.getBlock() instanceof BigBushBlock bigBush) || originState.getValue(AGE) != 2) {
return false;
}
if (!level.isClientSide) {
bigBush.popResource(level, originPos, new ItemStack(bigBush, 1));
if (!player.getAbilities().instabuild) {
stack.shrink(1);
}
level.levelEvent(1505, originPos, 15);
}
return true;
}
@Override
protected ItemInteractionResult useItemOn(
ItemStack stack,
BlockState state,
Level level,
BlockPos pos,
Player player,
InteractionHand hand,
BlockHitResult hitResult
) {
if (stack.is(Items.BONE_MEAL) && grantBonemealBonus(level, pos, state, player, stack)) {
return ItemInteractionResult.sidedSuccess(level.isClientSide);
}
return super.useItemOn(stack, state, level, pos, player, hand, hitResult);
}
}
@@ -0,0 +1,177 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.ItemInteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.BonemealableBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jetbrains.annotations.Nullable;
/**
* Invisible filler block for the grown {@link BigBushBlock} footprint. Breaking a
* part destroys the whole bush (drops come from the origin's loot table). The one
* part directly two above the origin of a stage-3 bush renders the top slice of
* the oversized cross model
*/
public class BigBushPartBlock extends Block implements BonemealableBlock {
public static final MapCodec<BigBushPartBlock> CODEC = Block.simpleCodec(BigBushPartBlock::new);
public static final BooleanProperty CAP = BooleanProperty.create("cap");
public BigBushPartBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(CAP, false));
}
@Override
public MapCodec<BigBushPartBlock> codec() {
return CODEC;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(CAP);
}
@Override
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return Shapes.block();
}
/** Finds the origin bush this part belongs to, or null if orphaned. */
@Nullable
public static BlockPos findOrigin(LevelReader level, BlockPos partPos) {
for (int dx = -1; dx <= 1; dx++) {
for (int dy = -2; dy <= 0; dy++) {
for (int dz = -1; dz <= 1; dz++) {
if (dx == 0 && dy == 0 && dz == 0) {
continue;
}
BlockPos candidate = partPos.offset(dx, dy, dz);
BlockState state = level.getBlockState(candidate);
if (state.getBlock() instanceof BigBushBlock
&& BigBushBlock.partPositions(state, candidate).contains(partPos)) {
return candidate;
}
}
}
}
return null;
}
@Override
public BlockState playerWillDestroy(Level level, BlockPos pos, BlockState state, Player player) {
if (!level.isClientSide) {
BlockPos origin = findOrigin(level, pos);
if (origin != null) {
BlockState originState = level.getBlockState(origin);
if (!player.getAbilities().instabuild) {
Block.dropResources(originState, level, origin, null, player, player.getMainHandItem());
}
level.destroyBlock(origin, false);
}
}
return super.playerWillDestroy(level, pos, state, player);
}
@Override
protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
if (!state.is(newState.getBlock()) && !level.isClientSide) {
BlockPos origin = findOrigin(level, pos);
if (origin != null) {
level.destroyBlock(origin, true);
}
}
super.onRemove(state, level, pos, newState, movedByPiston);
}
@Override
protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState,
LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
level.scheduleTick(pos, this, 1);
return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
}
@Override
protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
BlockPos origin = findOrigin(level, pos);
if (origin == null) {
level.removeBlock(pos, false);
return;
}
BlockState originState = level.getBlockState(origin);
if (!originState.canSurvive(level, origin)) {
level.destroyBlock(origin, true);
}
}
/** Bonemeal applied to any part of a growing bush grows the whole thing, same as clicking the origin. */
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state) {
BlockPos origin = findOrigin(level, pos);
return origin != null && level.getBlockState(origin).getBlock() instanceof BigBushBlock bigBush
&& bigBush.isValidBonemealTarget(level, origin, level.getBlockState(origin));
}
@Override
public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, BlockState state) {
BlockPos origin = findOrigin(level, pos);
return origin != null && level.getBlockState(origin).getBlock() instanceof BigBushBlock bigBush
&& bigBush.isBonemealSuccess(level, random, origin, level.getBlockState(origin));
}
@Override
public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) {
BlockPos origin = findOrigin(level, pos);
if (origin != null && level.getBlockState(origin).getBlock() instanceof BigBushBlock bigBush) {
bigBush.performBonemeal(level, random, origin, level.getBlockState(origin));
}
}
@Override
protected ItemInteractionResult useItemOn(
ItemStack stack,
BlockState state,
Level level,
BlockPos pos,
Player player,
InteractionHand hand,
BlockHitResult hitResult
) {
if (stack.is(Items.BONE_MEAL)) {
BlockPos origin = findOrigin(level, pos);
if (origin != null && BigBushBlock.grantBonemealBonus(level, origin, level.getBlockState(origin), player, stack)) {
return ItemInteractionResult.sidedSuccess(level.isClientSide);
}
}
return super.useItemOn(stack, state, level, pos, player, hand, hitResult);
}
@Override
public ItemStack getCloneItemStack(LevelReader level, BlockPos pos, BlockState state) {
BlockPos origin = findOrigin(level, pos);
if (origin != null) {
return new ItemStack(level.getBlockState(origin).getBlock());
}
return ItemStack.EMPTY;
}
}
@@ -0,0 +1,41 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.WeepingVinesBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
@SuppressWarnings({"rawtypes", "unchecked"})
public class OuranwoodVineBlock extends WeepingVinesBlock {
public static final MapCodec<OuranwoodVineBlock> CODEC = simpleCodec(OuranwoodVineBlock::new);
private static Block bodyBlock;
public OuranwoodVineBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public MapCodec<WeepingVinesBlock> codec() {
return (MapCodec) CODEC;
}
@Override
protected Block getBodyBlock() {
return bodyBlock;
}
@Override
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return Shapes.block();
}
public static void bindBodyBlock(Block block) {
bodyBlock = block;
}
}
@@ -0,0 +1,42 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.GrowingPlantHeadBlock;
import net.minecraft.world.level.block.WeepingVinesBlock;
import net.minecraft.world.level.block.WeepingVinesPlantBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
@SuppressWarnings({"rawtypes", "unchecked"})
public class OuranwoodVinePlantBlock extends WeepingVinesPlantBlock {
public static final MapCodec<OuranwoodVinePlantBlock> CODEC = simpleCodec(OuranwoodVinePlantBlock::new);
private static GrowingPlantHeadBlock headBlock;
public OuranwoodVinePlantBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public MapCodec<WeepingVinesPlantBlock> codec() {
return (MapCodec) CODEC;
}
@Override
protected GrowingPlantHeadBlock getHeadBlock() {
return headBlock;
}
@Override
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return Shapes.block();
}
public static void bindHeadBlock(WeepingVinesBlock block) {
headBlock = block;
}
}
@@ -0,0 +1,52 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.BonemealableBlock;
import net.minecraft.world.level.block.BushBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class VeryShortGrassBlock extends BushBlock implements BonemealableBlock {
public static final MapCodec<VeryShortGrassBlock> CODEC = Block.simpleCodec(VeryShortGrassBlock::new);
private static final VoxelShape SHAPE = Block.box(2.0, 0.0, 2.0, 14.0, 8.0, 14.0);
public VeryShortGrassBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public MapCodec<VeryShortGrassBlock> codec() {
return CODEC;
}
@Override
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state) {
return true;
}
@Override
public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, BlockState state) {
return true;
}
@Override
public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) {
level.setBlock(pos, Blocks.SHORT_GRASS.defaultBlockState(), 3);
}
}
@@ -0,0 +1,170 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.ItemInteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.BonemealableBlock;
import net.minecraft.world.level.block.BushBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.phys.BlockHitResult;
import org.jetbrains.annotations.Nullable;
public class VeryTallGrassBlock extends BushBlock implements BonemealableBlock {
public static final MapCodec<VeryTallGrassBlock> CODEC = Block.simpleCodec(VeryTallGrassBlock::new);
public static final EnumProperty<Part> PART = EnumProperty.create("part", Part.class);
public VeryTallGrassBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(PART, Part.LOWER));
}
@Override
public MapCodec<VeryTallGrassBlock> codec() {
return CODEC;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(PART);
}
@Override
protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return switch (state.getValue(PART)) {
case LOWER -> super.canSurvive(state, level, pos);
case MIDDLE -> level.getBlockState(pos.below()).is(this)
&& level.getBlockState(pos.below()).getValue(PART) == Part.LOWER
&& level.getBlockState(pos.above()).is(this)
&& level.getBlockState(pos.above()).getValue(PART) == Part.UPPER;
case UPPER -> level.getBlockState(pos.below()).is(this)
&& level.getBlockState(pos.below()).getValue(PART) == Part.MIDDLE;
};
}
@Override
protected BlockState updateShape(
BlockState state,
Direction direction,
BlockState neighborState,
LevelAccessor level,
BlockPos pos,
BlockPos neighborPos
) {
Part part = state.getValue(PART);
if (part == Part.LOWER && direction == Direction.UP && (!neighborState.is(this) || neighborState.getValue(PART) != Part.MIDDLE)) {
return Blocks.AIR.defaultBlockState();
}
if (part == Part.MIDDLE) {
if (direction == Direction.DOWN && (!neighborState.is(this) || neighborState.getValue(PART) != Part.LOWER)) {
return Blocks.AIR.defaultBlockState();
}
if (direction == Direction.UP && (!neighborState.is(this) || neighborState.getValue(PART) != Part.UPPER)) {
return Blocks.AIR.defaultBlockState();
}
}
if (part == Part.UPPER && direction == Direction.DOWN && (!neighborState.is(this) || neighborState.getValue(PART) != Part.MIDDLE)) {
return Blocks.AIR.defaultBlockState();
}
return state.canSurvive(level, pos) ? super.updateShape(state, direction, neighborState, level, pos, neighborPos) : Blocks.AIR.defaultBlockState();
}
@Override
protected ItemInteractionResult useItemOn(
ItemStack stack,
BlockState state,
Level level,
BlockPos pos,
Player player,
InteractionHand hand,
BlockHitResult hitResult
) {
if (player.getItemInHand(hand).is(Items.BONE_MEAL)) {
popResource(level, pos, new ItemStack(state.getBlock().asItem(), 1));
return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
}
return super.useItemOn(stack, state, level, pos, player, hand, hitResult);
}
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state) {
return false;
}
@Override
public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, BlockState state) {
return false;
}
@Override
public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) {
}
@Override
protected boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
return false;
}
@Nullable
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockPos pos = context.getClickedPos();
Level level = context.getLevel();
if (!level.getBlockState(pos.above()).canBeReplaced(context) || !level.getBlockState(pos.above(2)).canBeReplaced(context)) {
return null;
}
return super.getStateForPlacement(context);
}
@Override
public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable net.minecraft.world.entity.LivingEntity placer, ItemStack stack) {
placeAt(level, pos, Block.UPDATE_ALL);
}
public static void placeAt(LevelAccessor level, BlockPos pos, int flags) {
level.setBlock(pos, defaultState(Part.LOWER), flags);
level.setBlock(pos.above(), defaultState(Part.MIDDLE), flags);
level.setBlock(pos.above(2), defaultState(Part.UPPER), flags);
}
private static BlockState defaultState(Part part) {
return net.minecraft.core.registries.BuiltInRegistries.BLOCK
.get(net.minecraft.resources.ResourceLocation.fromNamespaceAndPath("antarchy", "very_tall_grass"))
.defaultBlockState()
.setValue(PART, part);
}
public enum Part implements StringRepresentable {
LOWER("lower"),
MIDDLE("middle"),
UPPER("upper");
private final String name;
Part(String name) {
this.name = name;
}
@Override
public String getSerializedName() {
return this.name;
}
}
}
@@ -0,0 +1,39 @@
package com.craisinlord.antarchy.content.client;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.mojang.blaze3d.vertex.VertexConsumer;
public final class AlphaVertexConsumerProxy {
private AlphaVertexConsumerProxy() {
}
public static VertexConsumer wrap(VertexConsumer delegate, float alphaScale) {
if (alphaScale >= 0.999F) {
return delegate;
}
final VertexConsumer[] proxyHolder = new VertexConsumer[1];
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object[] forwardedArgs = args;
if ("setColor".equals(method.getName()) && args != null && args.length == 4 && args[3] instanceof Integer alpha) {
forwardedArgs = args.clone();
forwardedArgs[3] = Math.max(0, Math.min(255, Math.round(alpha * alphaScale)));
}
Object result = method.invoke(delegate, forwardedArgs);
return result == delegate ? proxyHolder[0] : result;
}
};
proxyHolder[0] = (VertexConsumer) Proxy.newProxyInstance(
VertexConsumer.class.getClassLoader(),
new Class<?>[] { VertexConsumer.class },
handler
);
return proxyHolder[0];
}
}
@@ -6,6 +6,10 @@ import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel; import software.bernie.geckolib.model.GeoModel;
public class EmperorScorpionModel extends GeoModel<EmperorScorpionEntity> { public class EmperorScorpionModel extends GeoModel<EmperorScorpionEntity> {
public static final ResourceLocation NORMAL_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/emperor_scorpion/emperor_scorpion.png");
public static final ResourceLocation HARDEN_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/emperor_scorpion/emperor_scorpion_harden.png");
public static final ResourceLocation EMISSIVE_TEXTURE = public static final ResourceLocation EMISSIVE_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/emperor_scorpion/emperor_scorpion_emissive.png"); ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/emperor_scorpion/emperor_scorpion_emissive.png");
@@ -17,7 +21,7 @@ public class EmperorScorpionModel extends GeoModel<EmperorScorpionEntity> {
@Override @Override
public ResourceLocation getTextureResource(EmperorScorpionEntity animatable) { public ResourceLocation getTextureResource(EmperorScorpionEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/emperor_scorpion/emperor_scorpion.png"); return NORMAL_TEXTURE;
} }
@Override @Override
@@ -0,0 +1,45 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.GlimmerEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class GlimmerModel extends GeoModel<GlimmerEntity> {
private static final ResourceLocation ADULT_GEO = rl("geo/glimmer.geo.json");
private static final ResourceLocation BABY_GEO = rl("geo/glimmer_baby.geo.json");
private static final ResourceLocation ADULT_ANIM = rl("animations/glimmer.animation.json");
private static final ResourceLocation BABY_ANIM = rl("animations/glimmer_baby.animation.json");
private static final ResourceLocation ADULT_DAY = rl("textures/entity/glimmer/glimmer_day.png");
private static final ResourceLocation ADULT_NIGHT = rl("textures/entity/glimmer/glimmer.png");
private static final ResourceLocation BABY_DAY = rl("textures/entity/glimmer/glimmer_baby_day.png");
private static final ResourceLocation BABY_NIGHT = rl("textures/entity/glimmer/glimmer_baby.png");
public static final ResourceLocation ADULT_EMISSIVE = rl("textures/entity/glimmer/glimmer_emissive.png");
public static final ResourceLocation BABY_EMISSIVE = rl("textures/entity/glimmer/glimmer_baby_emissive.png");
private static ResourceLocation rl(String path) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, path);
}
@Override
public ResourceLocation getModelResource(GlimmerEntity animatable) {
return animatable.isBaby() ? BABY_GEO : ADULT_GEO;
}
@Override
public ResourceLocation getAnimationResource(GlimmerEntity animatable) {
return animatable.isBaby() ? BABY_ANIM : ADULT_ANIM;
}
@Override
public ResourceLocation getTextureResource(GlimmerEntity animatable) {
return textureFor(animatable, animatable.getGlowBlend(0.0F) >= 0.5F);
}
public static ResourceLocation textureFor(GlimmerEntity animatable, boolean glowing) {
if (animatable.isBaby()) {
return glowing ? BABY_NIGHT : BABY_DAY;
}
return glowing ? ADULT_NIGHT : ADULT_DAY;
}
}
@@ -6,6 +6,9 @@ import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel; import software.bernie.geckolib.model.GeoModel;
public class NightmareModel extends GeoModel<NightmareEntity> { public class NightmareModel extends GeoModel<NightmareEntity> {
public static final ResourceLocation EMISSIVE_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/nightmare_emissive.png");
@Override @Override
public ResourceLocation getModelResource(NightmareEntity animatable) { public ResourceLocation getModelResource(NightmareEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/nightmare.geo.json"); return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/nightmare.geo.json");
@@ -0,0 +1,26 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.RollyPollyEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class RollyPollyModel extends GeoModel<RollyPollyEntity> {
private static final ResourceLocation TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/rolly_polly/rolly_polly.png");
@Override
public ResourceLocation getModelResource(RollyPollyEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/rolly_polly.geo.json");
}
@Override
public ResourceLocation getTextureResource(RollyPollyEntity animatable) {
return TEXTURE;
}
@Override
public ResourceLocation getAnimationResource(RollyPollyEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/rolly_polly.animation.json");
}
}
@@ -1,23 +0,0 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.SpitBugEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class SpitBugModel extends GeoModel<SpitBugEntity> {
@Override
public ResourceLocation getModelResource(SpitBugEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/spit_bug.geo.json");
}
@Override
public ResourceLocation getTextureResource(SpitBugEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/spit_bug.png");
}
@Override
public ResourceLocation getAnimationResource(SpitBugEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/spit_bug.animation.json");
}
}
@@ -4,6 +4,8 @@ import com.craisinlord.antarchy.content.client.model.EmperorScorpionModel;
import com.craisinlord.antarchy.content.entity.EmperorScorpionEntity; import com.craisinlord.antarchy.content.entity.EmperorScorpionEntity;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.client.renderer.entity.EntityRendererProvider;
@@ -15,13 +17,22 @@ import software.bernie.geckolib.renderer.GeoEntityRenderer;
import software.bernie.geckolib.renderer.layer.GeoRenderLayer; import software.bernie.geckolib.renderer.layer.GeoRenderLayer;
public class EmperorScorpionRenderer extends GeoEntityRenderer<EmperorScorpionEntity> { public class EmperorScorpionRenderer extends GeoEntityRenderer<EmperorScorpionEntity> {
private static final int CROSSFADE_TICKS = 12;
private final Map<Integer, HardenTransitionState> transitions = new HashMap<>();
public EmperorScorpionRenderer(EntityRendererProvider.Context context) { public EmperorScorpionRenderer(EntityRendererProvider.Context context) {
super(context, new EmperorScorpionModel()); super(context, new EmperorScorpionModel());
this.shadowRadius = 3.0F; this.shadowRadius = 3.0F;
this.addRenderLayer(new EmperorScorpionHardenLayer(this));
this.addRenderLayer(new EmperorScorpionEmissiveLayer(this)); this.addRenderLayer(new EmperorScorpionEmissiveLayer(this));
} }
@Override
public void render(EmperorScorpionEntity entity, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight) {
this.updateTransition(entity);
super.render(entity, entityYaw, partialTick, poseStack, bufferSource, packedLight);
}
@Override @Override
public RenderType getRenderType(EmperorScorpionEntity animatable, ResourceLocation texture, @Nullable MultiBufferSource bufferSource, float partialTick) { public RenderType getRenderType(EmperorScorpionEntity animatable, ResourceLocation texture, @Nullable MultiBufferSource bufferSource, float partialTick) {
return RenderType.entityCutoutNoCull(texture); return RenderType.entityCutoutNoCull(texture);
@@ -57,4 +68,76 @@ public class EmperorScorpionRenderer extends GeoEntityRenderer<EmperorScorpionEn
); );
} }
} }
private void updateTransition(EmperorScorpionEntity entity) {
int phase = entity.getHardenPhaseIndex();
HardenTransitionState state = this.transitions.computeIfAbsent(entity.getId(), ignored ->
new HardenTransitionState(phase, entity.tickCount));
if (state.currentPhase != phase) {
state.currentPhase = phase;
state.transitionStartTick = entity.tickCount;
} else if (phase == 0
&& entity.tickCount - state.transitionStartTick > CROSSFADE_TICKS) {
this.transitions.remove(entity.getId());
}
}
private float getHardenAlpha(EmperorScorpionEntity entity, float partialTick) {
HardenTransitionState state = this.transitions.get(entity.getId());
if (state == null) {
return 0.0F;
}
float elapsed = (entity.tickCount - state.transitionStartTick) + partialTick;
return switch (state.currentPhase) {
case 2 -> Math.max(0.0F, Math.min(1.0F, elapsed / 11.0F));
case 3 -> 1.0F;
case 4 -> Math.max(0.0F, Math.min(1.0F, 1.0F - (elapsed / 20.0F)));
default -> 0.0F;
};
}
private static final class HardenTransitionState {
private int currentPhase;
private int transitionStartTick;
private HardenTransitionState(int currentPhase, int transitionStartTick) {
this.currentPhase = currentPhase;
this.transitionStartTick = transitionStartTick;
}
}
private static final class EmperorScorpionHardenLayer extends GeoRenderLayer<EmperorScorpionEntity> {
private EmperorScorpionHardenLayer(EmperorScorpionRenderer renderer) {
super(renderer);
}
@Override
public void render(PoseStack poseStack, EmperorScorpionEntity animatable, BakedGeoModel bakedModel, @Nullable RenderType renderType,
MultiBufferSource bufferSource, @Nullable VertexConsumer buffer, float partialTick,
int packedLight, int packedOverlay) {
EmperorScorpionRenderer renderer = (EmperorScorpionRenderer) this.getRenderer();
float alpha = renderer.getHardenAlpha(animatable, partialTick);
if (alpha <= 0.0F) {
return;
}
RenderType hardenType = RenderType.entityTranslucent(EmperorScorpionModel.HARDEN_TEXTURE);
VertexConsumer hardenBuffer = bufferSource.getBuffer(hardenType);
int color = ((Math.max(0, Math.min(255, Math.round(alpha * 255.0F))) & 0xFF) << 24) | 0x00FFFFFF;
this.getRenderer().reRender(
bakedModel,
poseStack,
bufferSource,
animatable,
hardenType,
hardenBuffer,
partialTick,
packedLight,
packedOverlay,
color
);
}
}
} }
@@ -0,0 +1,108 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.client.model.GlimmerModel;
import com.craisinlord.antarchy.content.entity.GlimmerEntity;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.Nullable;
import software.bernie.geckolib.cache.object.BakedGeoModel;
import software.bernie.geckolib.renderer.GeoEntityRenderer;
import software.bernie.geckolib.renderer.layer.GeoRenderLayer;
public class GlimmerRenderer extends GeoEntityRenderer<GlimmerEntity> {
private static final float SHADOW_RADIUS = 0.5F;
public GlimmerRenderer(EntityRendererProvider.Context context) {
super(context, new GlimmerModel());
this.shadowRadius = SHADOW_RADIUS;
this.addRenderLayer(new GlimmerCrossfadeLayer(this));
this.addRenderLayer(new GlimmerEmissiveLayer(this));
}
@Override
public RenderType getRenderType(GlimmerEntity animatable, ResourceLocation texture, @Nullable MultiBufferSource bufferSource, float partialTick) {
return RenderType.entityTranslucent(texture);
}
@Override
public void preRender(PoseStack poseStack, GlimmerEntity animatable, BakedGeoModel model, @Nullable MultiBufferSource bufferSource,
@Nullable VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) {
super.preRender(poseStack, animatable, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, colour);
this.shadowRadius = SHADOW_RADIUS;
}
private static final class GlimmerCrossfadeLayer extends GeoRenderLayer<GlimmerEntity> {
private GlimmerCrossfadeLayer(GeoEntityRenderer<GlimmerEntity> renderer) {
super(renderer);
}
@Override
public void render(PoseStack poseStack, GlimmerEntity animatable, BakedGeoModel bakedModel, @Nullable RenderType renderType,
MultiBufferSource bufferSource, @Nullable VertexConsumer buffer, float partialTick,
int packedLight, int packedOverlay) {
float glowBlend = animatable.getGlowBlend(partialTick);
if (glowBlend <= 0.0F || glowBlend >= 1.0F) {
return;
}
boolean baseGlowing = glowBlend >= 0.5F;
float overlayAlpha = baseGlowing ? 1.0F - glowBlend : glowBlend;
if (overlayAlpha <= 0.0F) {
return;
}
ResourceLocation overlayTexture = GlimmerModel.textureFor(animatable, !baseGlowing);
RenderType overlayType = RenderType.entityTranslucent(overlayTexture);
VertexConsumer overlayBuffer = bufferSource.getBuffer(overlayType);
int color = ((Math.max(0, Math.min(255, Math.round(overlayAlpha * 255.0F))) & 0xFF) << 24) | 0x00FFFFFF;
this.getRenderer().reRender(
bakedModel,
poseStack,
bufferSource,
animatable,
overlayType,
overlayBuffer,
partialTick,
packedLight,
packedOverlay,
color
);
}
}
private static final class GlimmerEmissiveLayer extends GeoRenderLayer<GlimmerEntity> {
private GlimmerEmissiveLayer(GeoEntityRenderer<GlimmerEntity> renderer) {
super(renderer);
}
@Override
public void render(PoseStack poseStack, GlimmerEntity animatable, BakedGeoModel bakedModel, @Nullable RenderType renderType,
MultiBufferSource bufferSource, @Nullable VertexConsumer buffer, float partialTick,
int packedLight, int packedOverlay) {
if (!animatable.isGlowingState()) {
return;
}
ResourceLocation texture = animatable.isBaby() ? GlimmerModel.BABY_EMISSIVE : GlimmerModel.ADULT_EMISSIVE;
RenderType emissiveType = RenderType.eyes(texture);
VertexConsumer emissiveBuffer = bufferSource.getBuffer(emissiveType);
this.getRenderer().reRender(
bakedModel,
poseStack,
bufferSource,
animatable,
emissiveType,
emissiveBuffer,
partialTick,
0xF000F0,
OverlayTexture.NO_OVERLAY,
0xFFFFFFFF
);
}
}
}
@@ -2,18 +2,53 @@ package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.client.model.NightmareModel; import com.craisinlord.antarchy.content.client.model.NightmareModel;
import com.craisinlord.antarchy.content.entity.nightmare.NightmareEntity; import com.craisinlord.antarchy.content.entity.nightmare.NightmareEntity;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.EntityRendererProvider; import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.texture.OverlayTexture;
import org.jetbrains.annotations.Nullable;
import software.bernie.geckolib.cache.object.BakedGeoModel;
import software.bernie.geckolib.renderer.GeoEntityRenderer; import software.bernie.geckolib.renderer.GeoEntityRenderer;
import software.bernie.geckolib.renderer.layer.GeoRenderLayer;
public class NightmareRenderer extends GeoEntityRenderer<NightmareEntity> { public class NightmareRenderer extends GeoEntityRenderer<NightmareEntity> {
public NightmareRenderer(EntityRendererProvider.Context context) { public NightmareRenderer(EntityRendererProvider.Context context) {
super(context, new NightmareModel()); super(context, new NightmareModel());
this.shadowRadius = 1.8F; this.shadowRadius = 1.8F;
this.withScale(1.15F); this.withScale(1.15F);
this.addRenderLayer(new NightmareEmissiveLayer(this));
} }
@Override @Override
protected float getDeathMaxRotation(NightmareEntity animatable) { protected float getDeathMaxRotation(NightmareEntity animatable) {
return 0.0F; return 0.0F;
} }
private static final class NightmareEmissiveLayer extends GeoRenderLayer<NightmareEntity> {
private NightmareEmissiveLayer(GeoEntityRenderer<NightmareEntity> renderer) {
super(renderer);
}
@Override
public void render(PoseStack poseStack, NightmareEntity animatable, BakedGeoModel bakedModel, @Nullable RenderType renderType,
MultiBufferSource bufferSource, @Nullable VertexConsumer buffer, float partialTick,
int packedLight, int packedOverlay) {
RenderType emissiveType = RenderType.eyes(NightmareModel.EMISSIVE_TEXTURE);
VertexConsumer emissiveBuffer = bufferSource.getBuffer(emissiveType);
this.getRenderer().reRender(
bakedModel,
poseStack,
bufferSource,
animatable,
emissiveType,
emissiveBuffer,
partialTick,
0xF000F0,
OverlayTexture.NO_OVERLAY,
0xFFFFFFFF
);
}
}
} }
@@ -0,0 +1,13 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.client.model.RollyPollyModel;
import com.craisinlord.antarchy.content.entity.RollyPollyEntity;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import software.bernie.geckolib.renderer.GeoEntityRenderer;
public class RollyPollyRenderer extends GeoEntityRenderer<RollyPollyEntity> {
public RollyPollyRenderer(EntityRendererProvider.Context context) {
super(context, new RollyPollyModel());
this.shadowRadius = 0.5F;
}
}
@@ -1,73 +0,0 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.entity.SpitBugProjectileEntity;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import org.joml.Matrix4f;
public class SpitBugProjectileRenderer extends EntityRenderer<SpitBugProjectileEntity> {
private static final ResourceLocation PROJECTILE_TEXTURE =
ResourceLocation.withDefaultNamespace("textures/entity/enderdragon/dragon_fireball.png");
public SpitBugProjectileRenderer(EntityRendererProvider.Context context) {
super(context);
}
@Override
protected int getBlockLightLevel(SpitBugProjectileEntity entity, BlockPos pos) {
return 15;
}
@Override
public void render(SpitBugProjectileEntity entity, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight) {
poseStack.pushPose();
poseStack.mulPose(this.entityRenderDispatcher.cameraOrientation());
float scale = entity.getRenderScale(partialTick);
poseStack.scale(scale, scale, scale);
VertexConsumer vertexConsumer = buffer.getBuffer(RenderType.entityTranslucent(PROJECTILE_TEXTURE));
PoseStack.Pose pose = poseStack.last();
Matrix4f matrix4f = pose.pose();
float alpha = entity.isLingering() ? 0.78F : 0.95F;
addVertex(vertexConsumer, pose, matrix4f, -0.5F, -0.5F, 0.0F, 1.0F, alpha, packedLight);
addVertex(vertexConsumer, pose, matrix4f, 0.5F, -0.5F, 1.0F, 1.0F, alpha, packedLight);
addVertex(vertexConsumer, pose, matrix4f, 0.5F, 0.5F, 1.0F, 0.0F, alpha, packedLight);
addVertex(vertexConsumer, pose, matrix4f, -0.5F, 0.5F, 0.0F, 0.0F, alpha, packedLight);
poseStack.popPose();
super.render(entity, entityYaw, partialTick, poseStack, buffer, packedLight);
}
private static void addVertex(
VertexConsumer vertexConsumer,
PoseStack.Pose pose,
Matrix4f matrix4f,
float x,
float y,
float u,
float v,
float alpha,
int packedLight
) {
vertexConsumer.addVertex(matrix4f, x, y, 0.0F)
.setColor(0.55F, 1.0F, 0.35F, alpha)
.setUv(u, v)
.setOverlay(OverlayTexture.NO_OVERLAY)
.setLight(packedLight)
.setNormal(pose, 0.0F, 0.0F, 1.0F);
}
@Override
public ResourceLocation getTextureLocation(SpitBugProjectileEntity entity) {
return PROJECTILE_TEXTURE;
}
}
@@ -1,14 +0,0 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.client.model.SpitBugModel;
import com.craisinlord.antarchy.content.entity.SpitBugEntity;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import software.bernie.geckolib.renderer.GeoEntityRenderer;
public class SpitBugRenderer extends GeoEntityRenderer<SpitBugEntity> {
public SpitBugRenderer(EntityRendererProvider.Context context) {
super(context, new SpitBugModel());
this.shadowRadius = 1.6F;
this.withScale(0.85F);
}
}
@@ -0,0 +1,68 @@
package com.craisinlord.antarchy.content.effect;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.GlimmerParticles;
import net.minecraft.core.Holder;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectCategory;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
import net.minecraft.world.entity.ai.attributes.AttributeMap;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.entity.ai.attributes.Attributes;
public final class GlimmersGraceMobEffect extends MobEffect {
private static final ResourceLocation SPEED_MODIFIER_ID =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "glimmers_grace_speed");
private static final ResourceLocation JUMP_MODIFIER_ID =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "glimmers_grace_jump");
private static final ResourceLocation FALL_DAMAGE_MODIFIER_ID =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "glimmers_grace_fall_damage");
public GlimmersGraceMobEffect() {
super(MobEffectCategory.BENEFICIAL, 0x7FDBFF);
}
@Override
public void addAttributeModifiers(AttributeMap attributeMap, int amplifier) {
addModifier(attributeMap, Attributes.MOVEMENT_SPEED, SPEED_MODIFIER_ID, 0.35D * (amplifier + 1));
addModifier(attributeMap, Attributes.JUMP_STRENGTH, JUMP_MODIFIER_ID, 0.5D * (amplifier + 1));
addModifier(attributeMap, Attributes.FALL_DAMAGE_MULTIPLIER, FALL_DAMAGE_MODIFIER_ID, -0.6D * (amplifier + 1));
}
@Override
public void removeAttributeModifiers(AttributeMap attributeMap) {
removeModifier(attributeMap, Attributes.MOVEMENT_SPEED, SPEED_MODIFIER_ID);
removeModifier(attributeMap, Attributes.JUMP_STRENGTH, JUMP_MODIFIER_ID);
removeModifier(attributeMap, Attributes.FALL_DAMAGE_MULTIPLIER, FALL_DAMAGE_MODIFIER_ID);
}
@Override
public boolean shouldApplyEffectTickThisTick(int duration, int amplifier) {
return true;
}
@Override
public boolean applyEffectTick(LivingEntity livingEntity, int amplifier) {
GlimmerParticles.tickAmbient(livingEntity, livingEntity.getDeltaMovement().horizontalDistanceSqr() > 0.01D);
return true;
}
private static void addModifier(AttributeMap attributeMap, Holder<Attribute> attribute, ResourceLocation id, double amount) {
AttributeInstance instance = attributeMap.getInstance(attribute);
if (instance == null) {
return;
}
instance.addTransientModifier(new AttributeModifier(id, amount, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL));
}
private static void removeModifier(AttributeMap attributeMap, Holder<Attribute> attribute, ResourceLocation id) {
AttributeInstance instance = attributeMap.getInstance(attribute);
if (instance == null) {
return;
}
instance.removeModifier(id);
}
}
@@ -19,6 +19,7 @@ import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MobSpawnType; 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.MeleeAttackGoal;
import net.minecraft.world.entity.monster.Monster; import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.ServerLevelAccessor; import net.minecraft.world.level.ServerLevelAccessor;
@@ -51,7 +52,10 @@ public class AlphaMantisEntity extends MantisEntity {
} }
public static boolean checkAlphaMantisSpawnRules(EntityType<AlphaMantisEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { public static boolean checkAlphaMantisSpawnRules(EntityType<AlphaMantisEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
if (spawnReason == MobSpawnType.SPAWN_EGG || spawnReason == MobSpawnType.SPAWNER || spawnReason == MobSpawnType.COMMAND) { if (spawnReason == MobSpawnType.SPAWN_EGG
|| spawnReason == MobSpawnType.SPAWNER
|| spawnReason == MobSpawnType.TRIAL_SPAWNER
|| spawnReason == MobSpawnType.COMMAND) {
return true; return true;
} }
@@ -72,14 +76,12 @@ public class AlphaMantisEntity extends MantisEntity {
return false; return false;
} }
// Only one alpha at a time in the area
if (!level.getLevel().getEntitiesOfClass(AlphaMantisEntity.class, new AABB(pos).inflate(128.0D), Entity::isAlive).isEmpty()) { if (!level.getLevel().getEntitiesOfClass(AlphaMantisEntity.class, new AABB(pos).inflate(128.0D), Entity::isAlive).isEmpty()) {
return false; return false;
} }
boolean ignoreLightLevel = AntarchySettings.mantisIgnoreLightLevel(); boolean ignoreLightLevel = AntarchySettings.mantisIgnoreLightLevel();
// Daytime overworld spawns can't pass the vanilla darkness check, so no light gate here
if (level.getLevel().isDay() && level.getBiome(pos).is(AntarchyTags.Biomes.MANTIS_OVERWORLD_SPAWN_BIOMES)) { if (level.getLevel().isDay() && level.getBiome(pos).is(AntarchyTags.Biomes.MANTIS_OVERWORLD_SPAWN_BIOMES)) {
return level.canSeeSky(pos); return level.canSeeSky(pos);
} }
@@ -91,6 +93,16 @@ public class AlphaMantisEntity extends MantisEntity {
return false; return false;
} }
@Override
protected MeleeAttackGoal createCombatGoal() {
return new MeleeAttackGoal(this, this.getCombatSpeed(), true);
}
@Override
protected double getCombatSpeed() {
return 1.05D;
}
@Override @Override
public void tick() { public void tick() {
super.tick(); super.tick();
@@ -155,10 +167,21 @@ public class AlphaMantisEntity extends MantisEntity {
this.playSound(com.craisinlord.antarchy.content.AntarchySoundEvents.MANTIS_AMBIENT.get(), 2.0F, 0.6F); this.playSound(com.craisinlord.antarchy.content.AntarchySoundEvents.MANTIS_AMBIENT.get(), 2.0F, 0.6F);
} }
@Override
protected void onActiveTarget(LivingEntity target) {
if (this.flyBurstTicks > 0 || this.flyCooldownTicks > 0) {
this.stopFlightBurst();
}
}
@Override
protected boolean shouldStartFlightBurst() {
return false;
}
@Override @Override
public void setTarget(@Nullable LivingEntity target) { public void setTarget(@Nullable LivingEntity target) {
super.setTarget(target); super.setTarget(target);
// A boss that despawns mid-fight is no boss — stay loaded once engaged
if (target != null) { if (target != null) {
this.setPersistenceRequired(); this.setPersistenceRequired();
} }
@@ -25,10 +25,4 @@ public final class AppleCowEntityVariants {
super(entityType, level); super(entityType, level);
} }
} }
public static class HoneyedAppleCow extends AppleCowEntity {
public HoneyedAppleCow(EntityType<? extends Cow> entityType, Level level) {
super(entityType, level);
}
}
} }
@@ -3,6 +3,7 @@ package com.craisinlord.antarchy.content.entity;
import com.craisinlord.antarchy.config.AntarchySettings; import com.craisinlord.antarchy.config.AntarchySettings;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataAccessor;
@@ -12,6 +13,8 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundEvents;
import net.minecraft.tags.FluidTags;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.damagesource.DamageSource;
@@ -23,15 +26,16 @@ import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.Mob;
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.control.MoveControl;
import net.minecraft.world.entity.ai.control.SmoothSwimmingLookControl; import net.minecraft.world.entity.ai.control.SmoothSwimmingLookControl;
import net.minecraft.world.entity.ai.control.SmoothSwimmingMoveControl; import net.minecraft.world.entity.ai.control.SmoothSwimmingMoveControl;
import net.minecraft.world.entity.ai.goal.BreathAirGoal;
import net.minecraft.world.entity.ai.goal.FloatGoal;
import net.minecraft.world.entity.ai.goal.Goal; import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal; import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal; import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
import net.minecraft.world.entity.ai.goal.RandomSwimmingGoal; import net.minecraft.world.entity.ai.goal.RandomSwimmingGoal;
import net.minecraft.world.entity.ai.goal.TryFindWaterGoal; import net.minecraft.world.entity.ai.goal.TryFindWaterGoal;
import net.minecraft.world.entity.ai.navigation.GroundPathNavigation;
import net.minecraft.world.entity.ai.navigation.PathNavigation; import net.minecraft.world.entity.ai.navigation.PathNavigation;
import net.minecraft.world.entity.ai.navigation.WaterBoundPathNavigation; import net.minecraft.world.entity.ai.navigation.WaterBoundPathNavigation;
import net.minecraft.world.entity.animal.Animal; import net.minecraft.world.entity.animal.Animal;
@@ -39,6 +43,7 @@ import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items; import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.pathfinder.PathType;
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.GeoEntity;
@@ -59,18 +64,29 @@ public class DorrieEntity extends Animal implements GeoEntity {
SynchedEntityData.defineId(DorrieEntity.class, EntityDataSerializers.BOOLEAN); SynchedEntityData.defineId(DorrieEntity.class, EntityDataSerializers.BOOLEAN);
private static final EntityDataAccessor<Integer> JUMP_CHARGE = private static final EntityDataAccessor<Integer> JUMP_CHARGE =
SynchedEntityData.defineId(DorrieEntity.class, EntityDataSerializers.INT); SynchedEntityData.defineId(DorrieEntity.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Integer> QUIRK_TICKS =
SynchedEntityData.defineId(DorrieEntity.class, EntityDataSerializers.INT);
private static final int MAX_CHARGE_TICKS = 40; private static final int MAX_CHARGE_TICKS = 40;
private static final float WATER_RIDE_SPEED = 1.26F; private static final float WATER_RIDE_SPEED = 0.78F;
private static final float LAND_BEACH_SPEED = 0.04F; private static final float LAND_BEACH_SPEED = 0.10F;
private static final int QUIRK_DURATION_TICKS = 65;
private static final int MIN_QUIRK_COOLDOWN_TICKS = 140;
private static final int MAX_QUIRK_COOLDOWN_TICKS = 260;
private static final double MOVING_ANIM_THRESHOLD_SQ = 0.0025D;
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle"); private static final RawAnimation IDLE_GROUND_ANIM = RawAnimation.begin().thenLoop("idle_ground");
private static final RawAnimation IDLE_WATER_ANIM = RawAnimation.begin().thenLoop("idle_water");
private static final RawAnimation WALK_ANIM = RawAnimation.begin().thenLoop("walk");
private static final RawAnimation SWIM_ANIM = RawAnimation.begin().thenLoop("swim"); private static final RawAnimation SWIM_ANIM = RawAnimation.begin().thenLoop("swim");
private static final RawAnimation JUMP_START_ANIM = RawAnimation.begin().thenPlay("jump_1"); private static final RawAnimation JUMP_START_ANIM = RawAnimation.begin().thenPlay("jump_start");
private static final RawAnimation JUMP_LOOP_ANIM = RawAnimation.begin().thenLoop("jump_2"); private static final RawAnimation JUMP_LOOP_ANIM = RawAnimation.begin().thenLoop("jump_idle");
private static final RawAnimation JUMP_LAND_ANIM = RawAnimation.begin().thenPlay("jump_3"); private static final RawAnimation JUMP_LAND_ANIM = RawAnimation.begin().thenPlay("jump_end");
private static final RawAnimation QUIRK_ANIM = RawAnimation.begin().thenPlay("quirk");
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this); private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
private final MoveControl landMoveControl;
private final MoveControl waterMoveControl;
private static final int RIDES_TO_TAME = 4; private static final int RIDES_TO_TAME = 4;
private static final int BUCK_DELAY_TICKS = 60; private static final int BUCK_DELAY_TICKS = 60;
@@ -83,11 +99,17 @@ public class DorrieEntity extends Animal implements GeoEntity {
private int rideAttempts = 0; private int rideAttempts = 0;
private int buckTimer = 0; private int buckTimer = 0;
private int swimForwardTicks = 0; private int swimForwardTicks = 0;
private int quirkCooldownTicks = MIN_QUIRK_COOLDOWN_TICKS;
private boolean usingLandNavigation = true;
public DorrieEntity(EntityType<? extends DorrieEntity> entityType, Level level) { public DorrieEntity(EntityType<? extends DorrieEntity> entityType, Level level) {
super(entityType, level); super(entityType, level);
this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 1.0F, true); this.landMoveControl = new MoveControl(this);
this.waterMoveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 1.0F, true);
this.moveControl = this.landMoveControl;
this.lookControl = new SmoothSwimmingLookControl(this, 10); this.lookControl = new SmoothSwimmingLookControl(this, 10);
this.setPathfindingMalus(PathType.WATER, 0.0F);
this.setPathfindingMalus(PathType.WATER_BORDER, 0.0F);
} }
@Override @Override
@@ -96,20 +118,21 @@ public class DorrieEntity extends Animal implements GeoEntity {
builder.define(HAS_SADDLE, false); builder.define(HAS_SADDLE, false);
builder.define(TAMED, false); builder.define(TAMED, false);
builder.define(JUMP_CHARGE, 0); builder.define(JUMP_CHARGE, 0);
builder.define(QUIRK_TICKS, 0);
} }
@Override @Override
protected PathNavigation createNavigation(Level level) { protected PathNavigation createNavigation(Level level) {
return new WaterBoundPathNavigation(this, level); return this.createLandNavigation(level);
} }
@Override @Override
protected void registerGoals() { protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this)); this.goalSelector.addGoal(0, new TryFindWaterGoal(this));
this.goalSelector.addGoal(1, new BreathAirGoal(this)); this.goalSelector.addGoal(1, new HuntCheepGoal(this));
this.goalSelector.addGoal(2, new TryFindWaterGoal(this)); this.goalSelector.addGoal(2, new DolphinSwimGoal());
this.goalSelector.addGoal(3, new HuntCheepGoal(this)); this.goalSelector.addGoal(3, new RandomSwimmingGoal(this, 1.35D, 8));
this.goalSelector.addGoal(4, new RandomSwimmingGoal(this, 1.0D, 10)); this.goalSelector.addGoal(4, new WaterAvoidingRandomStrollGoal(this, 0.72D, 40));
this.goalSelector.addGoal(5, new LookAtPlayerGoal(this, Player.class, 6.0F)); this.goalSelector.addGoal(5, new LookAtPlayerGoal(this, Player.class, 6.0F));
this.goalSelector.addGoal(6, new RandomLookAroundGoal(this)); this.goalSelector.addGoal(6, new RandomLookAroundGoal(this));
} }
@@ -117,7 +140,7 @@ public class DorrieEntity extends Animal implements GeoEntity {
public static AttributeSupplier.Builder createAttributes() { public static AttributeSupplier.Builder createAttributes() {
return Mob.createMobAttributes() return Mob.createMobAttributes()
.add(Attributes.MAX_HEALTH, AntarchySettings.dorrieHealth()) .add(Attributes.MAX_HEALTH, AntarchySettings.dorrieHealth())
.add(Attributes.MOVEMENT_SPEED, 1.0D) .add(Attributes.MOVEMENT_SPEED, 1.15D)
.add(Attributes.FOLLOW_RANGE, 16.0D) .add(Attributes.FOLLOW_RANGE, 16.0D)
.add(Attributes.ATTACK_DAMAGE, 4.0D); .add(Attributes.ATTACK_DAMAGE, 4.0D);
} }
@@ -146,6 +169,14 @@ public class DorrieEntity extends Animal implements GeoEntity {
this.entityData.set(JUMP_CHARGE, charge); this.entityData.set(JUMP_CHARGE, charge);
} }
public int getQuirkTicks() {
return this.entityData.get(QUIRK_TICKS);
}
private void setQuirkTicks(int ticks) {
this.entityData.set(QUIRK_TICKS, ticks);
}
@Override @Override
public void addAdditionalSaveData(CompoundTag tag) { public void addAdditionalSaveData(CompoundTag tag) {
super.addAdditionalSaveData(tag); super.addAdditionalSaveData(tag);
@@ -173,7 +204,18 @@ public class DorrieEntity extends Animal implements GeoEntity {
return InteractionResult.sidedSuccess(this.level().isClientSide); return InteractionResult.sidedSuccess(this.level().isClientSide);
} }
if (this.hasSaddle() && stack.isEmpty() && !player.isPassengerOfSameVehicle(this)) { if (this.hasSaddle() && !player.isPassengerOfSameVehicle(this)) {
if (!stack.isEmpty()) {
return super.mobInteract(player, hand);
}
if (!player.isShiftKeyDown()) {
if (!this.level().isClientSide) {
player.startRiding(this);
}
return InteractionResult.sidedSuccess(this.level().isClientSide);
}
if (!this.level().isClientSide) { if (!this.level().isClientSide) {
this.setSaddle(false); this.setSaddle(false);
this.spawnAtLocation(new ItemStack(Items.SADDLE)); this.spawnAtLocation(new ItemStack(Items.SADDLE));
@@ -193,13 +235,6 @@ public class DorrieEntity extends Animal implements GeoEntity {
return InteractionResult.sidedSuccess(this.level().isClientSide); return InteractionResult.sidedSuccess(this.level().isClientSide);
} }
if (this.hasSaddle() && !player.isPassengerOfSameVehicle(this)) {
if (!this.level().isClientSide) {
player.startRiding(this);
}
return InteractionResult.sidedSuccess(this.level().isClientSide);
}
return super.mobInteract(player, hand); return super.mobInteract(player, hand);
} }
@@ -220,13 +255,20 @@ public class DorrieEntity extends Animal implements GeoEntity {
protected Vec3 getRiddenInput(Player player, Vec3 travelVector) { protected Vec3 getRiddenInput(Player player, Vec3 travelVector) {
float forward = player.zza; float forward = player.zza;
float strafe = player.xxa * 0.5F; float strafe = player.xxa * 0.5F;
return new Vec3(strafe, 0, forward); float pitch = Mth.clamp(player.getXRot(), -60.0F, 60.0F);
double vertical = 0.0D;
if (player.zza > 0.02F) {
vertical = -pitch / 45.0D;
} else if (Math.abs(pitch) > 10.0F) {
vertical = -pitch / 60.0D;
}
return new Vec3(strafe, Mth.clamp(vertical, -1.0D, 1.0D), forward);
} }
@Override @Override
protected float getRiddenSpeed(Player player) { protected float getRiddenSpeed(Player player) {
float speed = (this.isInWater() || this.isInLava()) float speed = (this.isInWater() || this.isInLava())
? WATER_RIDE_SPEED * (1.0F + Math.min(this.swimForwardTicks, 60) * 0.025F) ? WATER_RIDE_SPEED * (1.0F + Math.min(this.swimForwardTicks, 60) * 0.03F)
: LAND_BEACH_SPEED; : LAND_BEACH_SPEED;
return (float) this.getAttributeValue(Attributes.MOVEMENT_SPEED) * speed; return (float) this.getAttributeValue(Attributes.MOVEMENT_SPEED) * speed;
} }
@@ -234,12 +276,17 @@ public class DorrieEntity extends Animal implements GeoEntity {
@Override @Override
public void tick() { public void tick() {
super.tick(); super.tick();
this.updateNavigationMode();
this.setNoGravity(false);
if (this.getControllingPassenger() instanceof Player player) { if (this.getControllingPassenger() instanceof Player player) {
this.setYRot(player.getYRot()); this.setYRot(player.getYRot());
this.yRotO = this.getYRot(); this.yRotO = this.getYRot();
this.yBodyRot = this.getYRot(); this.yBodyRot = this.getYRot();
this.yHeadRot = this.getYRot(); this.yHeadRot = this.getYRot();
if (this.getQuirkTicks() > 0) {
this.setQuirkTicks(0);
}
if (this.isInWater() || this.isInLava()) { if (this.isInWater() || this.isInLava()) {
if (player.zza > 0.05F) { if (player.zza > 0.05F) {
this.swimForwardTicks = Math.min(this.swimForwardTicks + 1, 60); this.swimForwardTicks = Math.min(this.swimForwardTicks + 1, 60);
@@ -275,11 +322,8 @@ public class DorrieEntity extends Animal implements GeoEntity {
setJumpCharge((int) ((chargeTicks / (float) MAX_CHARGE_TICKS) * 100)); setJumpCharge((int) ((chargeTicks / (float) MAX_CHARGE_TICKS) * 100));
} }
if (this.isInWater() && !isLeaping) { if (!this.level().isClientSide) {
Vec3 mov = this.getDeltaMovement(); this.tickQuirkAnimation();
double push = this.isUnderWater() ? 0.07D : 0.015D;
double cappedY = this.isUnderWater() ? 0.3D : 0.05D;
this.setDeltaMovement(mov.x, Math.min(mov.y + push, cappedY), mov.z);
} }
if (landAnimTicks > 0) { if (landAnimTicks > 0) {
@@ -302,17 +346,60 @@ public class DorrieEntity extends Animal implements GeoEntity {
} }
} }
@Override
public void baseTick() {
super.baseTick();
if (this.isInWater() || this.isInLava()) {
this.setAirSupply(this.getMaxAirSupply());
}
}
@Override
public void travel(Vec3 travelVector) {
if (this.getControllingPassenger() instanceof Player rider && this.isVehicle()) {
this.setYRot(rider.getYRot());
this.yRotO = this.getYRot();
this.yBodyRot = this.getYRot();
this.yHeadRot = this.getYRot();
Vec3 riddenInput = this.getRiddenInput(rider, travelVector);
this.setSpeed(this.getRiddenSpeed(rider));
if (this.isInWater() || this.isInLava()) {
this.moveRelative(this.getSpeed(), new Vec3(riddenInput.x, 0.0D, riddenInput.z));
Vec3 motion = this.getDeltaMovement();
double vertical = 0.0D;
if (!this.isLeaping) {
if (this.isUnderWater()) {
vertical = riddenInput.y * 0.025D;
} else if (riddenInput.y < 0.0D) {
vertical = riddenInput.y * 0.02D;
}
}
this.setDeltaMovement(
motion.x * 0.92D,
motion.y * 0.90D + vertical,
motion.z * 0.92D
);
this.move(net.minecraft.world.entity.MoverType.SELF, this.getDeltaMovement());
return;
}
}
super.travel(travelVector);
}
public void releaseJump() { public void releaseJump() {
if (!this.level().isClientSide && isCharging) { if (!this.level().isClientSide && isCharging) {
float power = chargeTicks / (float) MAX_CHARGE_TICKS; float power = chargeTicks / (float) MAX_CHARGE_TICKS;
if (power > 0.05F) { if (power > 0.05F) {
Vec3 look = this.getLookAngle(); Vec3 look = this.getLookAngle();
Vec3 current = this.getDeltaMovement(); Vec3 current = this.getDeltaMovement();
double forwardAdd = power * 0.5D; double forwardAdd = 0.18D + power * 0.42D;
double vertical = 0.55D + power * 0.9D; double vertical = 0.28D + power * 0.62D;
this.setDeltaMovement( this.setDeltaMovement(
current.x + look.x * forwardAdd, current.x + look.x * forwardAdd,
vertical, current.y + vertical,
current.z + look.z * forwardAdd current.z + look.z * forwardAdd
); );
this.hasImpulse = true; this.hasImpulse = true;
@@ -329,9 +416,9 @@ public class DorrieEntity extends Animal implements GeoEntity {
if (this.hasPassenger(passenger)) { if (this.hasPassenger(passenger)) {
Vec3 forward = this.getLookAngle().multiply(1.0D, 0.0D, 1.0D); Vec3 forward = this.getLookAngle().multiply(1.0D, 0.0D, 1.0D);
moveFunction.accept(passenger, moveFunction.accept(passenger,
this.getX() - forward.x * 0.25D, this.getX() - forward.x * 0.65D,
this.getY() + 0.5D, this.getY() + 0.5D,
this.getZ() - forward.z * 0.25D); this.getZ() - forward.z * 0.65D);
} }
} }
@@ -384,13 +471,31 @@ public class DorrieEntity extends Animal implements GeoEntity {
} }
private PlayState mainAnimController(AnimationState<DorrieEntity> state) { private PlayState mainAnimController(AnimationState<DorrieEntity> state) {
state.getController().setAnimationSpeed(1.0D);
if (landAnimTicks > 0) { if (landAnimTicks > 0) {
return state.setAndContinue(JUMP_LAND_ANIM); return state.setAndContinue(JUMP_LAND_ANIM);
} }
if (isLeaping) { if (isLeaping) {
return state.setAndContinue(wasInAir ? JUMP_LOOP_ANIM : JUMP_START_ANIM); return state.setAndContinue(wasInAir ? JUMP_LOOP_ANIM : JUMP_START_ANIM);
} }
return state.setAndContinue(state.isMoving() ? SWIM_ANIM : IDLE_ANIM); if (this.getQuirkTicks() > 0) {
return state.setAndContinue(QUIRK_ANIM);
}
boolean moving = this.isMovingForAnimation(state);
if (this.onGround()) {
if (moving) {
state.getController().setAnimationSpeed(0.75D);
return state.setAndContinue(WALK_ANIM);
}
return state.setAndContinue(IDLE_GROUND_ANIM);
}
if (this.isInWater() || this.isInLava()) {
return state.setAndContinue(moving ? SWIM_ANIM : IDLE_WATER_ANIM);
}
return state.setAndContinue(moving ? SWIM_ANIM : IDLE_GROUND_ANIM);
} }
@Override @Override
@@ -407,6 +512,286 @@ public class DorrieEntity extends Animal implements GeoEntity {
return !stack.isEmpty() && stack.is(BuiltInRegistries.ITEM.getOptional(CHEEP_ITEM_ID).orElse(Items.AIR)); return !stack.isEmpty() && stack.is(BuiltInRegistries.ITEM.getOptional(CHEEP_ITEM_ID).orElse(Items.AIR));
} }
private PathNavigation createLandNavigation(Level level) {
GroundPathNavigation navigation = new GroundPathNavigation(this, level);
navigation.setCanFloat(true);
navigation.setCanOpenDoors(false);
navigation.setCanPassDoors(true);
return navigation;
}
private PathNavigation createWaterNavigation(Level level) {
return new WaterBoundPathNavigation(this, level);
}
private void updateNavigationMode() {
boolean shouldUseLandNavigation = !this.isInWater() && !this.isUnderWater() && !this.isInLava();
if (this.navigation == null || this.usingLandNavigation != shouldUseLandNavigation) {
this.usingLandNavigation = shouldUseLandNavigation;
if (this.navigation != null) {
this.navigation.stop();
}
this.navigation = shouldUseLandNavigation
? this.createLandNavigation(this.level())
: this.createWaterNavigation(this.level());
this.moveControl = shouldUseLandNavigation ? this.landMoveControl : this.waterMoveControl;
}
}
private void tickQuirkAnimation() {
if (this.getQuirkTicks() > 0) {
if (this.canUseQuirkAnimation()) {
this.setQuirkTicks(this.getQuirkTicks() - 1);
} else {
this.setQuirkTicks(0);
this.quirkCooldownTicks = this.nextQuirkCooldown();
}
return;
}
if (this.quirkCooldownTicks > 0) {
this.quirkCooldownTicks--;
return;
}
if (this.canUseQuirkAnimation()) {
this.setQuirkTicks(QUIRK_DURATION_TICKS);
this.quirkCooldownTicks = this.nextQuirkCooldown();
}
}
private int nextQuirkCooldown() {
return MIN_QUIRK_COOLDOWN_TICKS + this.random.nextInt(MAX_QUIRK_COOLDOWN_TICKS - MIN_QUIRK_COOLDOWN_TICKS + 1);
}
private boolean canUseQuirkAnimation() {
return this.isInWater()
&& !this.isUnderWater()
&& this.getControllingPassenger() == null
&& !this.isLeaping
&& this.landAnimTicks <= 0
&& !this.isCharging
&& !this.isMovingForAnimation(null);
}
@Nullable
private Vec3 findWaterSurfaceTarget(double radius, int minYDelta, int maxYDelta) {
int baseY = Mth.floor(this.getY());
for (int attempt = 0; attempt < 12; attempt++) {
double offsetX = (this.random.nextDouble() - 0.5D) * radius * 2.0D;
double offsetZ = (this.random.nextDouble() - 0.5D) * radius * 2.0D;
int x = Mth.floor(this.getX() + offsetX);
int z = Mth.floor(this.getZ() + offsetZ);
Vec3 target = this.findWaterSurfaceTarget(x, z, baseY + minYDelta, baseY + maxYDelta);
if (target != null) {
return target;
}
}
return this.findWaterSurfaceTarget(Mth.floor(this.getX()), Mth.floor(this.getZ()),
baseY + minYDelta, baseY + maxYDelta);
}
@Nullable
private Vec3 findWaterSurfaceTarget(int x, int z, int minY, int maxY) {
int top = Math.min(maxY, this.level().getMaxBuildHeight() - 2);
int bottom = Math.max(minY, this.level().getMinBuildHeight() + 1);
for (int y = top; y >= bottom; y--) {
BlockPos pos = BlockPos.containing(x, y, z);
if (!this.isWaterAt(pos) || this.isWaterAt(pos.above())) {
continue;
}
return new Vec3(x + 0.5D, y + 0.85D, z + 0.5D);
}
return null;
}
@Nullable
private Vec3 findSubmergedTarget(double radius, int minYDelta, int maxYDelta) {
int baseY = Mth.floor(this.getY());
for (int attempt = 0; attempt < 16; attempt++) {
double offsetX = (this.random.nextDouble() - 0.5D) * radius * 2.0D;
double offsetZ = (this.random.nextDouble() - 0.5D) * radius * 2.0D;
int x = Mth.floor(this.getX() + offsetX);
int z = Mth.floor(this.getZ() + offsetZ);
Vec3 target = this.findSubmergedTarget(x, z, baseY + minYDelta, baseY + maxYDelta);
if (target != null) {
return target;
}
}
return this.findSubmergedTarget(Mth.floor(this.getX()), Mth.floor(this.getZ()),
baseY + minYDelta, baseY + maxYDelta);
}
@Nullable
private Vec3 findSubmergedTarget(int x, int z, int minY, int maxY) {
int top = Math.min(maxY, this.level().getMaxBuildHeight() - 2);
int bottom = Math.max(minY, this.level().getMinBuildHeight() + 1);
for (int y = top; y >= bottom; y--) {
BlockPos pos = BlockPos.containing(x, y, z);
if (!this.isWaterAt(pos) || !this.isWaterAt(pos.below())) {
continue;
}
return new Vec3(x + 0.5D, y + 0.3D, z + 0.5D);
}
return null;
}
private boolean isWaterAt(BlockPos pos) {
return this.level().getFluidState(pos).is(FluidTags.WATER);
}
private boolean isMovingForAnimation(@Nullable AnimationState<DorrieEntity> state) {
if (state != null && state.isMoving()) {
return true;
}
if (this.getControllingPassenger() instanceof Player player) {
return Math.abs(player.zza) > 0.05F || Math.abs(player.xxa) > 0.05F;
}
return this.getDeltaMovement().horizontalDistanceSqr() > MOVING_ANIM_THRESHOLD_SQ
|| this.getNavigation().isInProgress();
}
private class DolphinSwimGoal extends Goal {
private static final int COOLDOWN_MIN_TICKS = 120;
private static final int COOLDOWN_MAX_TICKS = 240;
private static final int DIVE_MIN_TICKS = 50;
private static final int DIVE_MAX_TICKS = 110;
private static final int ROAM_MIN_TICKS = 70;
private static final int ROAM_MAX_TICKS = 140;
private static final int TARGET_REFRESH_TICKS = 20;
private static final double AQUATIC_SPEED = 1.15D;
private static final double SEARCH_RADIUS = 12.0D;
@Nullable
private Vec3 targetPos;
private int phaseTicks;
private int targetRefreshTicks;
private int cooldownTicks;
private Phase phase = Phase.ROAM;
DolphinSwimGoal() {
this.setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK));
}
@Override
public boolean canUse() {
if (DorrieEntity.this.level().isClientSide
|| DorrieEntity.this.isVehicle()
|| DorrieEntity.this.getControllingPassenger() != null
|| DorrieEntity.this.isCharging
|| DorrieEntity.this.isLeaping
|| DorrieEntity.this.landAnimTicks > 0
|| DorrieEntity.this.getTarget() != null) {
return false;
}
if (!DorrieEntity.this.isInWater()) {
return false;
}
if (this.cooldownTicks > 0) {
this.cooldownTicks--;
return false;
}
if (DorrieEntity.this.random.nextInt(6) != 0) {
return false;
}
this.targetPos = DorrieEntity.this.isUnderWater()
? DorrieEntity.this.findSubmergedTarget(SEARCH_RADIUS, -5, 2)
: DorrieEntity.this.findSubmergedTarget(SEARCH_RADIUS, -5, 1);
return this.targetPos != null;
}
@Override
public boolean canContinueToUse() {
return this.targetPos != null
&& !DorrieEntity.this.isVehicle()
&& DorrieEntity.this.getControllingPassenger() == null
&& DorrieEntity.this.isAlive()
&& DorrieEntity.this.isInWater();
}
@Override
public void start() {
this.phase = DorrieEntity.this.isUnderWater() ? Phase.ROAM : Phase.DIVE;
this.phaseTicks = this.phase == Phase.DIVE
? DorrieEntity.this.random.nextInt(DIVE_MAX_TICKS - DIVE_MIN_TICKS + 1) + DIVE_MIN_TICKS
: DorrieEntity.this.random.nextInt(ROAM_MAX_TICKS - ROAM_MIN_TICKS + 1) + ROAM_MIN_TICKS;
this.targetRefreshTicks = 0;
if (this.targetPos == null) {
this.targetPos = this.pickTargetForPhase();
}
if (this.targetPos == null) {
this.stop();
}
}
@Override
public void stop() {
this.targetPos = null;
this.phaseTicks = 0;
this.targetRefreshTicks = 0;
DorrieEntity.this.getNavigation().stop();
this.cooldownTicks = DorrieEntity.this.random.nextInt(COOLDOWN_MAX_TICKS - COOLDOWN_MIN_TICKS + 1) + COOLDOWN_MIN_TICKS;
}
@Override
public void tick() {
if (this.targetPos == null) {
this.stop();
return;
}
if (this.phaseTicks > 0) {
this.phaseTicks--;
}
if (this.targetRefreshTicks > 0) {
this.targetRefreshTicks--;
}
if (this.phase == Phase.DIVE && this.phaseTicks <= 0) {
this.phase = Phase.ROAM;
this.phaseTicks = DorrieEntity.this.random.nextInt(ROAM_MAX_TICKS - ROAM_MIN_TICKS + 1) + ROAM_MIN_TICKS;
this.targetPos = this.pickTargetForPhase();
} else if (this.phase == Phase.ROAM && this.phaseTicks <= 0) {
this.phase = Phase.SURFACE;
this.phaseTicks = DorrieEntity.this.random.nextInt(DIVE_MAX_TICKS - DIVE_MIN_TICKS + 1) + DIVE_MIN_TICKS;
this.targetPos = DorrieEntity.this.findWaterSurfaceTarget(SEARCH_RADIUS, -1, 4);
} else if (this.phase == Phase.SURFACE && this.phaseTicks <= 0 && this.isCloseToTarget()) {
this.stop();
return;
}
if (this.targetPos == null || this.targetRefreshTicks <= 0 || this.isCloseToTarget()) {
this.targetPos = this.pickTargetForPhase();
this.targetRefreshTicks = TARGET_REFRESH_TICKS;
}
if (this.targetPos == null) {
this.stop();
return;
}
DorrieEntity.this.getLookControl().setLookAt(this.targetPos.x, this.targetPos.y, this.targetPos.z, 25.0F, 20.0F);
DorrieEntity.this.getNavigation().moveTo(this.targetPos.x, this.targetPos.y, this.targetPos.z, AQUATIC_SPEED);
}
@Nullable
private Vec3 pickTargetForPhase() {
return this.phase == Phase.SURFACE
? DorrieEntity.this.findWaterSurfaceTarget(SEARCH_RADIUS, -1, 4)
: DorrieEntity.this.findSubmergedTarget(SEARCH_RADIUS, -5, 2);
}
private boolean isCloseToTarget() {
return this.targetPos != null && DorrieEntity.this.distanceToSqr(this.targetPos) < 4.0D;
}
private enum Phase {
DIVE,
ROAM,
SURFACE
}
}
private static class HuntCheepGoal extends Goal { private static class HuntCheepGoal extends Goal {
private static final int COOLDOWN_TICKS = 600; private static final int COOLDOWN_TICKS = 600;
private static final double HUNT_RANGE = 16.0D; private static final double HUNT_RANGE = 16.0D;
@@ -1,37 +1,44 @@
package com.craisinlord.antarchy.content.entity; package com.craisinlord.antarchy.content.entity;
import com.craisinlord.antarchy.content.AntarchySoundEvents;
import com.craisinlord.antarchy.Antarchy; import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.AntarchySoundEvents;
import com.craisinlord.antarchy.content.AntarchyObjects; import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.damage.AntarchyDamageSources; import com.craisinlord.antarchy.content.damage.AntarchyDamageSources;
import com.craisinlord.antarchy.content.entity.ScorpionEntity;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
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.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.ServerBossEvent; import net.minecraft.server.level.ServerBossEvent;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvent;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.Difficulty;
import net.minecraft.world.BossEvent; import net.minecraft.world.BossEvent;
import net.minecraft.world.Difficulty;
import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects; import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MobSpawnType; 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.level.levelgen.Heightmap; import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal; import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
import net.minecraft.world.entity.ai.goal.MeleeAttackGoal;
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal; import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
import net.minecraft.world.entity.ai.goal.RandomStrollGoal; import net.minecraft.world.entity.ai.goal.RandomStrollGoal;
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.entity.monster.Monster; import net.minecraft.world.entity.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;
@@ -47,68 +54,127 @@ import software.bernie.geckolib.animation.PlayState;
import software.bernie.geckolib.animation.RawAnimation; import software.bernie.geckolib.animation.RawAnimation;
import software.bernie.geckolib.util.GeckoLibUtil; import software.bernie.geckolib.util.GeckoLibUtil;
public class EmperorScorpionEntity extends Monster implements GeoEntity { import java.util.EnumSet;
private static final byte SNAP_ATTACK_ANIM_EVENT = 4;
private static final byte STING_ATTACK_ANIM_EVENT = 5; public class EmperorScorpionEntity extends Monster implements GeoEntity {
private static final byte AGRO_ANIM_EVENT = 6; private static final byte CLAW_ATTACK_EVENT = 4;
private static final byte STING_ATTACK_EVENT = 5;
private static final EntityDataAccessor<Integer> ANIMATION_STATE =
SynchedEntityData.defineId(EmperorScorpionEntity.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Integer> HARDEN_PHASE =
SynchedEntityData.defineId(EmperorScorpionEntity.class, EntityDataSerializers.INT);
private static final int SNAP_ATTACK_ANIM_TICKS = 23;
private static final int SNAP_ATTACK_HIT_TICK = 12;
private static final int SNAP_ATTACK_COOLDOWN_TICKS = 28;
private static final int STING_ATTACK_ANIM_TICKS = 25;
private static final int STING_ATTACK_HIT_TICK = 13;
private static final int STING_ATTACK_COOLDOWN_TICKS = 60;
private static final int AGRO_ANIM_TICKS = 30;
private static final int DEATH_ANIM_TICKS = 40; private static final int DEATH_ANIM_TICKS = 40;
private static final float STING_DAMAGE = 18.0F; private static final int ANIM_IDLE = 0;
private static final double STING_AOE_RADIUS = 5.0D; private static final int ANIM_WALK = 1;
private static final int POISON_DURATION_TICKS = 300; private static final int ANIM_CLAW_ATTACK = 2;
private static final int WEAKNESS_DURATION_TICKS = 120; private static final int ANIM_STING_ATTACK = 3;
private static final int SUMMON_INTERVAL_TICKS = 140; private static final int ANIM_DEATH = 4;
private static final int MAX_SUMMONED_SCORPIONS = 8; private static final int ANIM_HARDEN_START = 5;
private static final String EMPEROR_SUMMON_TAG = "antarchy_emperor_summoned"; private static final int ANIM_HARDEN_ACTIVE = 6;
private static final int ANIM_HARDEN_END = 7;
private static final double CLAW_LUNGE_SPEED = 0.12D;
private static final double CLAW_LUNGE_LIFT = 0.02D;
private static final double STING_LUNGE_SPEED = 0.08D;
private static final double STING_LUNGE_LIFT = 0.01D;
private static final double CLAW_RANGE = 5.25D;
private static final double STING_RANGE = 5.75D;
private static final int HARDEN_START_TICKS = 11;
private static final int HARDEN_END_TICKS = 20;
private static final int HARDEN_HEAL_INTERVAL_TICKS = 20;
private static final float HARDEN_HEAL_AMOUNT = 2.0F;
private static final int HARDEN_MIN_DURATION_TICKS = 100;
private static final int HARDEN_MAX_DURATION_TICKS = 200;
private static final ResourceKey<Level> THORAXIS_KEY = private static final ResourceKey<Level> THORAXIS_KEY =
ResourceKey.create(Registries.DIMENSION, ResourceKey.create(Registries.DIMENSION,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "thoraxis")); ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "thoraxis"));
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle"); private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
private static final RawAnimation WALK_ANIM = RawAnimation.begin().thenLoop("walk"); private static final RawAnimation WALK_ANIM = RawAnimation.begin().thenLoop("walk");
private static final RawAnimation SNAP_ANIM = RawAnimation.begin().thenPlay("snap"); private static final RawAnimation CLAW_ATTACK_ANIM = RawAnimation.begin().thenPlay("snap");
private static final RawAnimation STING_ANIM = RawAnimation.begin().thenPlay("sting"); private static final RawAnimation STING_ATTACK_ANIM = RawAnimation.begin().thenPlay("sting");
private static final RawAnimation AGRO_ANIM = RawAnimation.begin().thenPlay("agro"); private static final RawAnimation HARDEN_START_ANIM = RawAnimation.begin().thenPlay("harden");
private static final RawAnimation HARDEN_ACTIVE_ANIM = RawAnimation.begin().thenLoop("harden_state");
private static final RawAnimation HARDEN_END_ANIM = RawAnimation.begin().thenPlay("end_of_harden_state");
private static final RawAnimation DEATH_ANIM = RawAnimation.begin().thenPlay("death"); private static final RawAnimation DEATH_ANIM = RawAnimation.begin().thenPlay("death");
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this); private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
private final ServerBossEvent bossEvent = private final ServerBossEvent bossEvent =
new ServerBossEvent(this.getDisplayName(), BossEvent.BossBarColor.PURPLE, BossEvent.BossBarOverlay.PROGRESS); new ServerBossEvent(this.getDisplayName(), BossEvent.BossBarColor.PURPLE, BossEvent.BossBarOverlay.PROGRESS);
private int attackAnimTicks = 0; private int attackAnimTicks;
private int attackHitTick = 0; private int clawCooldownTicks;
private int attackCooldownTicks = 0; private int stingCooldownTicks;
private int stingCooldownTicks = 0; private int hardenCooldownTicks = AntarchySettings.emperorScorpionSummonIntervalTicks();
private int agroAnimTicks = 0; private int hardenCastTicks;
private int summonCooldown = 0; private int hardenCastSpawnTicks;
private boolean attackDamageApplied = false; private int hardenStateTicks;
private boolean stingAttackActive = false; private int hardenDurationTicks;
private boolean hasAgroed = false; private int hardenHealTicks;
private int hardenSummonedScorpions;
private float hardenLockedYaw;
private float hardenLockedPitch;
private boolean attackDamageApplied;
private AttackType currentAttack = AttackType.NONE;
private HardenPhase hardenPhase = HardenPhase.NONE;
@Nullable private LivingEntity attackTarget; @Nullable private LivingEntity attackTarget;
public EmperorScorpionEntity(EntityType<? extends EmperorScorpionEntity> entityType, Level level) { public EmperorScorpionEntity(EntityType<? extends EmperorScorpionEntity> entityType, Level level) {
super(entityType, level); super(entityType, level);
this.xpReward = 25; this.xpReward = AntarchySettings.emperorScorpionXpReward();
this.bossEvent.setDarkenScreen(false); this.bossEvent.setDarkenScreen(false);
} }
public static AttributeSupplier.Builder createAttributes() { public static AttributeSupplier.Builder createAttributes() {
return Monster.createMonsterAttributes() return Monster.createMonsterAttributes()
.add(Attributes.MAX_HEALTH, 400.0D) .add(Attributes.MAX_HEALTH, AntarchySettings.emperorScorpionHealth())
.add(Attributes.MOVEMENT_SPEED, 0.32D) .add(Attributes.MOVEMENT_SPEED, AntarchySettings.emperorScorpionMovementSpeed())
.add(Attributes.ATTACK_DAMAGE, 28.0D) .add(Attributes.ATTACK_DAMAGE, AntarchySettings.emperorScorpionAttackDamage())
.add(Attributes.ARMOR, 25.0D) .add(Attributes.ARMOR, AntarchySettings.emperorScorpionArmor())
.add(Attributes.ARMOR_TOUGHNESS, 10.0D) .add(Attributes.ARMOR_TOUGHNESS, 10.0D)
.add(Attributes.KNOCKBACK_RESISTANCE, 0.8D) .add(Attributes.KNOCKBACK_RESISTANCE, AntarchySettings.emperorScorpionKnockbackResistance())
.add(Attributes.FOLLOW_RANGE, 40.0D); .add(Attributes.FOLLOW_RANGE, AntarchySettings.emperorScorpionFollowRange());
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
builder.define(ANIMATION_STATE, ANIM_IDLE);
builder.define(HARDEN_PHASE, HardenPhase.NONE.ordinal());
}
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this));
this.goalSelector.addGoal(1, new EmperorScorpionCombatGoal());
this.goalSelector.addGoal(5, new RandomStrollGoal(this, 0.8D));
this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 12.0F));
this.goalSelector.addGoal(7, new RandomLookAroundGoal(this));
this.targetSelector.addGoal(1, new HurtByTargetGoal(this));
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
}
@Override
public boolean fireImmune() {
return true;
}
@Override
public boolean hurt(DamageSource source, float amount) {
if (this.isHardenedStateActive()) {
return false;
}
return super.hurt(source, amount);
}
@Override
public boolean isInvulnerableTo(DamageSource source) {
return this.isHardenedStateActive() || super.isInvulnerableTo(source);
}
@Override
public void lavaHurt() {
} }
public static boolean canSpawn(EntityType<EmperorScorpionEntity> entityType, ServerLevelAccessor level, public static boolean canSpawn(EntityType<EmperorScorpionEntity> entityType, ServerLevelAccessor level,
@@ -125,17 +191,6 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
&& Monster.checkMonsterSpawnRules(entityType, level, spawnReason, pos, random); && Monster.checkMonsterSpawnRules(entityType, level, spawnReason, pos, random);
} }
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this));
this.goalSelector.addGoal(1, new EmperorScorpionAttackGoal());
this.goalSelector.addGoal(5, new RandomStrollGoal(this, 0.8D));
this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 12.0F));
this.goalSelector.addGoal(7, new RandomLookAroundGoal(this));
this.targetSelector.addGoal(1, new HurtByTargetGoal(this));
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
}
@Override @Override
public float maxUpStep() { public float maxUpStep() {
return 1.5F; return 1.5F;
@@ -143,185 +198,237 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
@Override @Override
public int getMaxHeadYRot() { public int getMaxHeadYRot() {
return 35; return 40;
} }
@Override @Override
public void tick() { public void tick() {
super.tick(); super.tick();
this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth()); this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth());
if (this.attackCooldownTicks > 0) {
this.attackCooldownTicks--; if (this.clawCooldownTicks > 0) {
this.clawCooldownTicks--;
} }
if (this.stingCooldownTicks > 0) { if (this.stingCooldownTicks > 0) {
this.stingCooldownTicks--; this.stingCooldownTicks--;
} }
if (this.hardenCooldownTicks > 0) {
this.hardenCooldownTicks--;
}
if (this.attackAnimTicks > 0) { if (this.attackAnimTicks > 0) {
if (!this.level().isClientSide) { if (!this.level().isClientSide) {
this.tickAttackWindup(); this.tickActiveAttack();
} }
this.attackAnimTicks--; this.attackAnimTicks--;
if (this.attackAnimTicks <= 0) { if (this.attackAnimTicks <= 0) {
this.resetAttackState(); this.resetAttackState();
} }
} }
if (this.agroAnimTicks > 0) {
this.agroAnimTicks--;
}
if (this.summonCooldown > 0) {
this.summonCooldown--;
}
if (!this.level().isClientSide) { if (!this.level().isClientSide) {
if (this.getTarget() != null) { this.tickHardenState();
if (!this.hasAgroed) {
this.hasAgroed = true;
this.agroAnimTicks = AGRO_ANIM_TICKS;
this.getNavigation().stop();
this.level().broadcastEntityEvent(this, AGRO_ANIM_EVENT);
this.playSound(AntarchySoundEvents.EMPEROR_SCORPION_ROAR.get(), 2.0F, 0.7F);
}
} else {
this.hasAgroed = false;
}
} }
if (this.getTarget() != null this.updateAnimationState();
&& this.summonCooldown <= 0
&& !this.isAttackLocked()
&& this.getHealth() <= this.getMaxHealth() * 0.75F
&& this.level() instanceof ServerLevel serverLevel) {
this.trySummonScorpions(serverLevel);
}
}
private void trySummonScorpions(ServerLevel serverLevel) {
long nearby = serverLevel.getEntitiesOfClass(ScorpionEntity.class, this.getBoundingBox().inflate(16.0D),
scorpion -> scorpion.getTags().contains(EMPEROR_SUMMON_TAG)).size();
this.summonCooldown = SUMMON_INTERVAL_TICKS;
if (nearby >= MAX_SUMMONED_SCORPIONS) {
return;
}
int toSpawn = 2 + this.random.nextInt(2);
EntityType<ScorpionEntity> scorpionType = AntarchyObjects.SCORPION.get();
for (int i = 0; i < toSpawn; i++) {
double offsetX = (this.random.nextDouble() - 0.5D) * 6.0D;
double offsetZ = (this.random.nextDouble() - 0.5D) * 6.0D;
BlockPos xzPos = BlockPos.containing(this.getX() + offsetX, 0, this.getZ() + offsetZ);
BlockPos spawnPos = serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, xzPos);
@Nullable ScorpionEntity scorpion = scorpionType.create(serverLevel);
if (scorpion == null) continue;
scorpion.moveTo(spawnPos.getX() + 0.5D, spawnPos.getY(), spawnPos.getZ() + 0.5D,
this.getYRot(), 0.0F);
scorpion.addTag(EMPEROR_SUMMON_TAG);
scorpion.setTarget(this.getTarget());
scorpion.finalizeSpawn(serverLevel,
serverLevel.getCurrentDifficultyAt(spawnPos),
MobSpawnType.MOB_SUMMONED, null);
serverLevel.addFreshEntity(scorpion);
}
this.playSound(AntarchySoundEvents.EMPEROR_SCORPION_ROAR.get(), 1.2F, 0.75F);
} }
@Override @Override
public boolean doHurtTarget(Entity target) { public boolean doHurtTarget(Entity target) {
return this.performSnapAttack(target);
}
private boolean performSnapAttack(Entity target) {
boolean hurt = super.doHurtTarget(target); boolean hurt = super.doHurtTarget(target);
if (hurt) { if (!hurt) {
this.playSound(AntarchySoundEvents.EMPEROR_SCORPION_ATTACK.get(), 0.9F, 0.95F + this.random.nextFloat() * 0.08F);
}
return hurt;
}
private boolean performStingAttack(Entity target) {
if (!(this.level() instanceof ServerLevel serverLevel)) {
return false; return false;
} }
boolean hurtAny = false; this.playSound(AntarchySoundEvents.EMPEROR_SCORPION_ATTACK.get(), 0.9F, 0.95F + this.random.nextFloat() * 0.08F);
for (LivingEntity living : serverLevel.getEntitiesOfClass(LivingEntity.class, return true;
this.getBoundingBox().inflate(STING_AOE_RADIUS), }
entity -> entity != this
&& entity.isAlive() private boolean doStingAttack(LivingEntity target) {
&& !(entity instanceof EmperorScorpionEntity) boolean hurt;
&& !(entity instanceof ScorpionEntity))) { if (this.level() instanceof net.minecraft.server.level.ServerLevel serverLevel) {
if (living.hurt(AntarchyDamageSources.emperorScorpionSting(serverLevel, this), STING_DAMAGE)) { hurt = target.hurt(
hurtAny = true; AntarchyDamageSources.emperorScorpionSting(serverLevel, this),
int poisonDuration = this.level().getDifficulty() == Difficulty.HARD (float) this.getAttributeValue(Attributes.ATTACK_DAMAGE)
? POISON_DURATION_TICKS * 2 : POISON_DURATION_TICKS; );
living.addEffect(new MobEffectInstance(MobEffects.POISON, poisonDuration, 1)); } else {
living.addEffect(new MobEffectInstance(MobEffects.WEAKNESS, WEAKNESS_DURATION_TICKS, 0)); hurt = target.hurt(this.damageSources().mobAttack(this), (float) this.getAttributeValue(Attributes.ATTACK_DAMAGE));
}
} }
if (hurtAny) {
this.playSound(AntarchySoundEvents.EMPEROR_SCORPION_ATTACK.get(), 1.0F, 0.9F + this.random.nextFloat() * 0.08F); if (!hurt) {
return false;
} }
return hurtAny;
int poisonDuration = this.level().getDifficulty() == Difficulty.HARD
? AntarchySettings.emperorScorpionPoisonTicks() * 2
: AntarchySettings.emperorScorpionPoisonTicks();
target.addEffect(new MobEffectInstance(MobEffects.POISON, poisonDuration, 1));
target.addEffect(new MobEffectInstance(MobEffects.WEAKNESS, AntarchySettings.emperorScorpionWeaknessTicks(), 0));
this.playSound(AntarchySoundEvents.EMPEROR_SCORPION_ATTACK.get(), 1.0F, 0.88F + this.random.nextFloat() * 0.08F);
return true;
} }
private void beginSnapAttack(LivingEntity target) { private void beginAttack(LivingEntity target, AttackType attackType) {
if (this.isHardenSequenceActive()) {
return;
}
this.attackTarget = target; this.attackTarget = target;
this.attackAnimTicks = SNAP_ATTACK_ANIM_TICKS; this.currentAttack = attackType;
this.attackHitTick = SNAP_ATTACK_HIT_TICK; this.attackAnimTicks = attackType.animTicks();
this.attackCooldownTicks = SNAP_ATTACK_COOLDOWN_TICKS;
this.attackDamageApplied = false; this.attackDamageApplied = false;
this.stingAttackActive = false;
this.getNavigation().stop(); this.getNavigation().stop();
this.level().broadcastEntityEvent(this, SNAP_ATTACK_ANIM_EVENT); if (attackType == AttackType.CLAW) {
this.commitLunge(target, 0.42D, 0.10D); this.clawCooldownTicks = AntarchySettings.emperorScorpionClawCooldownTicks();
this.level().broadcastEntityEvent(this, CLAW_ATTACK_EVENT);
this.commitLunge(target, CLAW_LUNGE_SPEED, CLAW_LUNGE_LIFT);
} else if (attackType == AttackType.STING) {
this.stingCooldownTicks = AntarchySettings.emperorScorpionStingCooldownTicks();
this.level().broadcastEntityEvent(this, STING_ATTACK_EVENT);
this.commitLunge(target, STING_LUNGE_SPEED, STING_LUNGE_LIFT);
}
} }
private void beginStingAttack(LivingEntity target) { private void tickActiveAttack() {
this.attackTarget = target; if (this.attackTarget == null || !this.attackTarget.isAlive() || this.isHardenSequenceActive()) {
this.attackAnimTicks = STING_ATTACK_ANIM_TICKS;
this.attackHitTick = STING_ATTACK_HIT_TICK;
this.attackCooldownTicks = STING_ATTACK_COOLDOWN_TICKS;
this.stingCooldownTicks = STING_ATTACK_COOLDOWN_TICKS;
this.attackDamageApplied = false;
this.stingAttackActive = true;
this.getNavigation().stop();
this.level().broadcastEntityEvent(this, STING_ATTACK_ANIM_EVENT);
this.commitLunge(target, 0.55D, 0.14D);
}
private void tickAttackWindup() {
if (this.attackTarget == null || !this.attackTarget.isAlive()) {
this.resetAttackState(); this.resetAttackState();
return; return;
} }
this.getLookControl().setLookAt(this.attackTarget, 30.0F, 30.0F); this.getLookControl().setLookAt(this.attackTarget, 30.0F, 30.0F);
if (!this.attackDamageApplied && this.attackAnimTicks == this.attackHitTick) { if (!this.attackDamageApplied
if (this.stingAttackActive) { && this.attackAnimTicks == this.currentAttack.hitTick()
this.attackDamageApplied = true; && this.canHitAttackTarget(this.attackTarget, this.currentAttack)) {
this.performStingAttack(this.attackTarget); this.attackDamageApplied = true;
} else if (this.distanceToSqr(this.attackTarget) <= this.getAttackReachSqr(this.attackTarget)) { if (this.currentAttack == AttackType.STING) {
this.attackDamageApplied = true; this.doStingAttack(this.attackTarget);
this.performSnapAttack(this.attackTarget); } else {
this.doHurtTarget(this.attackTarget);
} }
} }
if (this.attackAnimTicks <= 0) {
this.resetAttackState();
}
} }
private double getAttackReachSqr(LivingEntity target) { private boolean canHitAttackTarget(LivingEntity target, AttackType attackType) {
double reach = this.getBbWidth() * 1.9D + target.getBbWidth(); double range = attackType == AttackType.STING ? STING_RANGE : CLAW_RANGE;
return reach * reach + 1.5D; return this.distanceToSqr(target) <= range * range && this.hasLineOfSight(target);
} }
private void resetAttackState() { private void resetAttackState() {
this.attackAnimTicks = 0; this.attackAnimTicks = 0;
this.attackHitTick = 0;
this.attackDamageApplied = false; this.attackDamageApplied = false;
this.stingAttackActive = false; this.currentAttack = AttackType.NONE;
this.attackTarget = null; this.attackTarget = null;
} }
private void tickHardenState() {
if (this.getHardenPhase() == HardenPhase.NONE) {
if (this.hardenCooldownTicks <= 0 && this.getTarget() != null && this.getTarget().isAlive()) {
this.beginHardenCast();
}
return;
}
this.getNavigation().stop();
this.setSpeed(0.0F);
this.setZza(0.0F);
switch (this.getHardenPhase()) {
case CASTING -> {
if (this.hardenCastTicks % this.hardenCastSpawnTicks == 0
&& this.hardenSummonedScorpions < AntarchySettings.emperorScorpionMaxSummonedScorpions()) {
this.summonScorpionMinion();
this.hardenSummonedScorpions++;
if (this.hardenSummonedScorpions >= AntarchySettings.emperorScorpionMaxSummonedScorpions()) {
this.beginHardening();
return;
}
}
if (--this.hardenCastTicks <= 0) {
this.beginHardening();
}
}
case START -> {
this.lockHardenRotation();
if (--this.hardenStateTicks <= 0) {
this.beginHardened();
}
}
case ACTIVE -> {
this.lockHardenRotation();
Vec3 motion = this.getDeltaMovement();
this.setDeltaMovement(0.0D, motion.y, 0.0D);
if (--this.hardenDurationTicks <= 0) {
this.beginHardeningEnd();
return;
}
if (--this.hardenHealTicks <= 0) {
this.hardenHealTicks = HARDEN_HEAL_INTERVAL_TICKS;
this.heal(HARDEN_HEAL_AMOUNT);
}
}
case END -> {
this.lockHardenRotation();
Vec3 motion = this.getDeltaMovement();
this.setDeltaMovement(0.0D, motion.y, 0.0D);
if (--this.hardenStateTicks <= 0) {
this.setHardenPhase(HardenPhase.NONE);
this.hardenCooldownTicks = Math.max(1, AntarchySettings.emperorScorpionSummonIntervalTicks());
}
}
}
}
private void beginHardenCast() {
this.setHardenPhase(HardenPhase.CASTING);
this.hardenCastTicks = Math.max(1, AntarchySettings.emperorScorpionSummonIntervalTicks());
this.hardenCastSpawnTicks = Math.max(1, this.hardenCastTicks / Math.max(1, AntarchySettings.emperorScorpionMaxSummonedScorpions()));
this.hardenStateTicks = 0;
this.hardenDurationTicks = 0;
this.hardenHealTicks = 0;
this.hardenSummonedScorpions = 0;
this.resetAttackState();
this.getNavigation().stop();
}
private void beginHardening() {
this.setHardenPhase(HardenPhase.START);
this.hardenStateTicks = HARDEN_START_TICKS;
this.hardenLockedYaw = this.getYRot();
this.hardenLockedPitch = this.getXRot();
this.playSound(AntarchySoundEvents.EMPEROR_SCORPION_ROAR.get(), 1.0F, 0.95F + this.random.nextFloat() * 0.05F);
this.setAggressive(false);
}
private void beginHardened() {
this.setHardenPhase(HardenPhase.ACTIVE);
this.hardenDurationTicks = HARDEN_MIN_DURATION_TICKS + this.random.nextInt(HARDEN_MAX_DURATION_TICKS - HARDEN_MIN_DURATION_TICKS + 1);
this.hardenHealTicks = HARDEN_HEAL_INTERVAL_TICKS;
}
private void beginHardeningEnd() {
this.setHardenPhase(HardenPhase.END);
this.hardenStateTicks = HARDEN_END_TICKS;
this.setAggressive(false);
}
private void summonScorpionMinion() {
if (!(this.level() instanceof ServerLevel serverLevel)) {
return;
}
ScorpionEntity scorpion = AntarchyObjects.SCORPION.get().create(serverLevel);
if (scorpion == null) {
return;
}
Vec3 ring = Vec3.directionFromRotation(0.0F, this.random.nextFloat() * 360.0F)
.scale(2.75D + this.random.nextDouble() * 1.75D);
BlockPos spawnPos = BlockPos.containing(this.getX() + ring.x, this.getY(), this.getZ() + ring.z);
scorpion.moveTo(spawnPos.getX() + 0.5D, spawnPos.getY(), spawnPos.getZ() + 0.5D, this.random.nextFloat() * 360.0F, 0.0F);
scorpion.finalizeSpawn(serverLevel, serverLevel.getCurrentDifficultyAt(spawnPos), MobSpawnType.MOB_SUMMONED, null);
scorpion.setPersistenceRequired();
if (this.getTarget() instanceof LivingEntity target) {
scorpion.setTarget(target);
}
serverLevel.addFreshEntity(scorpion);
}
private void commitLunge(LivingEntity target, double horizontalSpeed, double verticalSpeed) { private void commitLunge(LivingEntity target, double horizontalSpeed, double verticalSpeed) {
Vec3 lunge = target.position().subtract(this.position()); Vec3 lunge = target.position().subtract(this.position());
Vec3 horizontal = new Vec3(lunge.x, 0.0D, lunge.z); Vec3 horizontal = new Vec3(lunge.x, 0.0D, lunge.z);
@@ -333,32 +440,18 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
this.hasImpulse = true; this.hasImpulse = true;
} }
private boolean shouldUseSting(LivingEntity target) {
return this.stingCooldownTicks <= 0
&& this.distanceToSqr(target) <= this.getAttackReachSqr(target) + 2.0D
&& (this.getHealth() <= this.getMaxHealth() * 0.6F || this.random.nextFloat() < 0.45F);
}
private boolean isAttackLocked() {
return this.attackAnimTicks > 0 || this.agroAnimTicks > 0;
}
@Override @Override
public void handleEntityEvent(byte id) { public void handleEntityEvent(byte id) {
if (id == SNAP_ATTACK_ANIM_EVENT) { if (id == CLAW_ATTACK_EVENT) {
this.attackAnimTicks = SNAP_ATTACK_ANIM_TICKS; this.currentAttack = AttackType.CLAW;
this.attackAnimTicks = AntarchySettings.emperorScorpionClawAnimTicks();
this.attackDamageApplied = false; this.attackDamageApplied = false;
this.stingAttackActive = false;
return; return;
} }
if (id == STING_ATTACK_ANIM_EVENT) { if (id == STING_ATTACK_EVENT) {
this.attackAnimTicks = STING_ATTACK_ANIM_TICKS; this.currentAttack = AttackType.STING;
this.attackAnimTicks = AntarchySettings.emperorScorpionStingAnimTicks();
this.attackDamageApplied = false; this.attackDamageApplied = false;
this.stingAttackActive = true;
return;
}
if (id == AGRO_ANIM_EVENT) {
this.agroAnimTicks = AGRO_ANIM_TICKS;
return; return;
} }
super.handleEntityEvent(id); super.handleEntityEvent(id);
@@ -370,19 +463,85 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
} }
private PlayState mainController(AnimationState<EmperorScorpionEntity> state) { private PlayState mainController(AnimationState<EmperorScorpionEntity> state) {
return switch (this.getAnimationState()) {
case ANIM_WALK -> state.setAndContinue(WALK_ANIM);
case ANIM_CLAW_ATTACK -> state.setAndContinue(CLAW_ATTACK_ANIM);
case ANIM_STING_ATTACK -> state.setAndContinue(STING_ATTACK_ANIM);
case ANIM_HARDEN_START -> state.setAndContinue(HARDEN_START_ANIM);
case ANIM_HARDEN_ACTIVE -> state.setAndContinue(HARDEN_ACTIVE_ANIM);
case ANIM_HARDEN_END -> state.setAndContinue(HARDEN_END_ANIM);
case ANIM_DEATH -> state.setAndContinue(DEATH_ANIM);
default -> state.setAndContinue(IDLE_ANIM);
};
}
private int getAnimationState() {
return this.entityData.get(ANIMATION_STATE);
}
private HardenPhase getHardenPhase() {
HardenPhase[] phases = HardenPhase.values();
int phaseOrdinal = this.entityData.get(HARDEN_PHASE);
return phaseOrdinal >= 0 && phaseOrdinal < phases.length ? phases[phaseOrdinal] : HardenPhase.NONE;
}
public int getHardenPhaseIndex() {
return this.entityData.get(HARDEN_PHASE);
}
private void setAnimationState(int animationState) {
this.entityData.set(ANIMATION_STATE, animationState);
}
private void setHardenPhase(HardenPhase phase) {
this.hardenPhase = phase;
this.entityData.set(HARDEN_PHASE, phase.ordinal());
}
private void lockHardenRotation() {
if (!this.isHardenSequenceActive()) {
return;
}
this.setYRot(this.hardenLockedYaw);
this.setYHeadRot(this.hardenLockedYaw);
this.yBodyRot = this.hardenLockedYaw;
this.yBodyRotO = this.hardenLockedYaw;
this.yHeadRotO = this.hardenLockedYaw;
this.setXRot(this.hardenLockedPitch);
this.xRotO = this.hardenLockedPitch;
}
private void updateAnimationState() {
if (this.isDeadOrDying()) { if (this.isDeadOrDying()) {
return state.setAndContinue(DEATH_ANIM); this.setAnimationState(ANIM_DEATH);
return;
}
HardenPhase currentHardenPhase = this.getHardenPhase();
if (currentHardenPhase == HardenPhase.START) {
this.setAnimationState(ANIM_HARDEN_START);
return;
}
if (currentHardenPhase == HardenPhase.ACTIVE) {
this.setAnimationState(ANIM_HARDEN_ACTIVE);
return;
}
if (currentHardenPhase == HardenPhase.END) {
this.setAnimationState(ANIM_HARDEN_END);
return;
} }
if (this.attackAnimTicks > 0) { if (this.attackAnimTicks > 0) {
return state.setAndContinue(this.stingAttackActive ? STING_ANIM : SNAP_ANIM); this.setAnimationState(this.currentAttack == AttackType.STING ? ANIM_STING_ATTACK : ANIM_CLAW_ATTACK);
return;
} }
if (this.agroAnimTicks > 0) { if (currentHardenPhase == HardenPhase.CASTING) {
return state.setAndContinue(AGRO_ANIM); this.setAnimationState(ANIM_IDLE);
return;
} }
if (state.isMoving()) { if (this.getTarget() != null || this.getDeltaMovement().horizontalDistanceSqr() > 1.0E-4D) {
return state.setAndContinue(WALK_ANIM); this.setAnimationState(ANIM_WALK);
return;
} }
return state.setAndContinue(IDLE_ANIM); this.setAnimationState(ANIM_IDLE);
} }
@Override @Override
@@ -419,6 +578,50 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
return 0.8F; return 0.8F;
} }
@Override
public void addAdditionalSaveData(CompoundTag tag) {
super.addAdditionalSaveData(tag);
tag.putInt("HardenPhase", this.hardenPhase.ordinal());
tag.putInt("HardenCooldownTicks", this.hardenCooldownTicks);
tag.putInt("HardenCastTicks", this.hardenCastTicks);
tag.putInt("HardenCastSpawnTicks", this.hardenCastSpawnTicks);
tag.putInt("HardenStateTicks", this.hardenStateTicks);
tag.putInt("HardenDurationTicks", this.hardenDurationTicks);
tag.putInt("HardenHealTicks", this.hardenHealTicks);
tag.putInt("HardenSummonedScorpions", this.hardenSummonedScorpions);
}
@Override
public void readAdditionalSaveData(CompoundTag tag) {
super.readAdditionalSaveData(tag);
if (tag.contains("HardenPhase")) {
int phaseOrdinal = tag.getInt("HardenPhase");
HardenPhase[] phases = HardenPhase.values();
this.setHardenPhase(phaseOrdinal >= 0 && phaseOrdinal < phases.length ? phases[phaseOrdinal] : HardenPhase.NONE);
}
if (tag.contains("HardenCooldownTicks")) {
this.hardenCooldownTicks = tag.getInt("HardenCooldownTicks");
}
if (tag.contains("HardenCastTicks")) {
this.hardenCastTicks = tag.getInt("HardenCastTicks");
}
if (tag.contains("HardenCastSpawnTicks")) {
this.hardenCastSpawnTicks = tag.getInt("HardenCastSpawnTicks");
}
if (tag.contains("HardenStateTicks")) {
this.hardenStateTicks = tag.getInt("HardenStateTicks");
}
if (tag.contains("HardenDurationTicks")) {
this.hardenDurationTicks = tag.getInt("HardenDurationTicks");
}
if (tag.contains("HardenHealTicks")) {
this.hardenHealTicks = tag.getInt("HardenHealTicks");
}
if (tag.contains("HardenSummonedScorpions")) {
this.hardenSummonedScorpions = tag.getInt("HardenSummonedScorpions");
}
}
@Override @Override
public void setCustomName(@Nullable net.minecraft.network.chat.Component name) { public void setCustomName(@Nullable net.minecraft.network.chat.Component name) {
super.setCustomName(name); super.setCustomName(name);
@@ -443,42 +646,157 @@ public class EmperorScorpionEntity extends Monster implements GeoEntity {
this.bossEvent.removeAllPlayers(); this.bossEvent.removeAllPlayers();
} }
private final class EmperorScorpionAttackGoal extends MeleeAttackGoal { private boolean isAttackLocked() {
private EmperorScorpionAttackGoal() { return this.attackAnimTicks > 0;
super(EmperorScorpionEntity.this, 1.15D, true); }
public boolean isHardenSequenceActive() {
return this.getHardenPhase() != HardenPhase.NONE;
}
public boolean isHardenedStateActive() {
HardenPhase currentHardenPhase = this.getHardenPhase();
return currentHardenPhase == HardenPhase.START
|| currentHardenPhase == HardenPhase.ACTIVE
|| currentHardenPhase == HardenPhase.END;
}
public boolean isHardened() {
return this.getHardenPhase() == HardenPhase.ACTIVE;
}
public boolean shouldUseHardenTexture() {
return this.getHardenPhase() == HardenPhase.START
|| this.getHardenPhase() == HardenPhase.ACTIVE
|| this.getHardenPhase() == HardenPhase.END;
}
private final class EmperorScorpionCombatGoal extends Goal {
private static final double CHASE_SPEED = 1.1D;
private EmperorScorpionCombatGoal() {
this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK));
} }
@Override @Override
public void tick() { public boolean canUse() {
if (EmperorScorpionEntity.this.attackTarget != null) { LivingEntity target = EmperorScorpionEntity.this.getTarget();
EmperorScorpionEntity.this.getLookControl().setLookAt( return target != null && target.isAlive() && !EmperorScorpionEntity.this.isHardenSequenceActive();
EmperorScorpionEntity.this.attackTarget, 30.0F, 30.0F);
}
super.tick();
} }
@Override @Override
public boolean canContinueToUse() { public boolean canContinueToUse() {
return EmperorScorpionEntity.this.isAttackLocked() || super.canContinueToUse(); LivingEntity target = EmperorScorpionEntity.this.getTarget();
return (target != null && target.isAlive()) || EmperorScorpionEntity.this.isAttackLocked();
} }
@Override @Override
protected void checkAndPerformAttack(LivingEntity enemy) { public void start() {
EmperorScorpionEntity.this.setAggressive(true);
}
@Override
public void stop() {
EmperorScorpionEntity.this.setAggressive(false);
EmperorScorpionEntity.this.getNavigation().stop();
}
@Override
public void tick() {
LivingEntity target = EmperorScorpionEntity.this.getTarget();
if (target == null) {
EmperorScorpionEntity.this.getNavigation().stop();
return;
}
if (EmperorScorpionEntity.this.isHardenSequenceActive()) {
this.stopMovement();
return;
}
EmperorScorpionEntity.this.getLookControl().setLookAt(target, 30.0F, 30.0F);
if (EmperorScorpionEntity.this.isAttackLocked()) { if (EmperorScorpionEntity.this.isAttackLocked()) {
this.stopMovement();
return; return;
} }
if (this.canPerformAttack(enemy)
&& this.isTimeToAttack() if (!EmperorScorpionEntity.this.hasLineOfSight(target)) {
&& EmperorScorpionEntity.this.attackCooldownTicks <= 0) { EmperorScorpionEntity.this.getNavigation().moveTo(target, CHASE_SPEED);
this.resetAttackCooldown();
if (EmperorScorpionEntity.this.shouldUseSting(enemy)) {
EmperorScorpionEntity.this.beginStingAttack(enemy);
} else {
EmperorScorpionEntity.this.beginSnapAttack(enemy);
}
return; return;
} }
super.checkAndPerformAttack(enemy);
if (!EmperorScorpionEntity.this.isWithinMeleeAttackRange(target)) {
EmperorScorpionEntity.this.getNavigation().moveTo(target, CHASE_SPEED);
return;
}
this.stopMovement();
AttackType attackType = EmperorScorpionEntity.this.selectAttack(target);
if (attackType == AttackType.NONE) {
EmperorScorpionEntity.this.getNavigation().moveTo(target, CHASE_SPEED);
return;
}
EmperorScorpionEntity.this.beginAttack(target, attackType);
}
private void stopMovement() {
EmperorScorpionEntity.this.getNavigation().stop();
EmperorScorpionEntity.this.setSpeed(0.0F);
EmperorScorpionEntity.this.setZza(0.0F);
} }
} }
@Override
public boolean isWithinMeleeAttackRange(LivingEntity target) {
return this.distanceToSqr(target) <= STING_RANGE * STING_RANGE;
}
private AttackType selectAttack(LivingEntity target) {
boolean inClawRange = this.clawCooldownTicks <= 0 && this.distanceToSqr(target) <= CLAW_RANGE * CLAW_RANGE;
boolean inStingRange = this.stingCooldownTicks <= 0 && this.distanceToSqr(target) <= STING_RANGE * STING_RANGE;
boolean canClaw = inClawRange && this.hasLineOfSight(target);
boolean canSting = inStingRange && this.hasLineOfSight(target);
if (canSting && (!canClaw || this.random.nextFloat() < 0.3F)) {
return AttackType.STING;
}
if (canClaw) {
return AttackType.CLAW;
}
if (canSting) {
return AttackType.STING;
}
return AttackType.NONE;
}
private enum AttackType {
NONE,
CLAW,
STING;
private int animTicks() {
return switch (this) {
case CLAW -> AntarchySettings.emperorScorpionClawAnimTicks();
case STING -> AntarchySettings.emperorScorpionStingAnimTicks();
default -> 0;
};
}
private int hitTick() {
return switch (this) {
case CLAW -> AntarchySettings.emperorScorpionClawHitTick();
case STING -> AntarchySettings.emperorScorpionStingHitTick();
default -> 0;
};
}
}
private enum HardenPhase {
NONE,
CASTING,
START,
ACTIVE,
END
}
} }
@@ -0,0 +1,430 @@
package com.craisinlord.antarchy.content.entity;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.AntarchyTags;
import com.craisinlord.antarchy.content.GlimmerParticles;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.AgeableMob;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.entity.SpawnGroupData;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.goal.FloatGoal;
import net.minecraft.world.entity.ai.goal.FollowParentGoal;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
import net.minecraft.world.entity.ai.goal.PanicGoal;
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
import net.minecraft.world.entity.ai.goal.TemptGoal;
import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
import net.minecraft.world.entity.ai.util.DefaultRandomPos;
import net.minecraft.world.entity.animal.Animal;
import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.util.Mth;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.pathfinder.Path;
import net.minecraft.world.phys.Vec3;
import net.minecraft.server.level.ServerLevel;
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 GlimmerEntity extends Animal implements GeoEntity {
private static final EntityDataAccessor<Integer> GLOW_TICKS =
SynchedEntityData.defineId(GlimmerEntity.class, EntityDataSerializers.INT);
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
private static final RawAnimation WALK_ANIM = RawAnimation.begin().thenLoop("walk");
private static final RawAnimation RUN_ANIM = RawAnimation.begin().thenLoop("run");
private static final String QUIRK_CONTROLLER = "quirk_controller";
private static final String QUIRK_TRIGGER = "quirk";
private static final int TRUST_REQUIRED_FEEDS = 3;
private static final int GRACE_DURATION_TICKS = 2400;
private static final int GRACE_COOLDOWN_TICKS = 6000;
private static final int GLOW_LIGHT_THRESHOLD = 7;
private static final int GLOW_CHECK_INTERVAL_TICKS = 20;
private static final int GLOW_TRANSITION_TICKS = 10;
private static final double WALK_SPEED_THRESHOLD_SQR = 0.0009D;
private static final double RUN_SPEED_THRESHOLD_SQR = 0.0035D;
private static final int MIN_QUIRK_COOLDOWN = 20 * 8;
private static final int MAX_QUIRK_COOLDOWN = 20 * 25;
private static final String TRUST_KEY = "GlimmerTrust";
private static final String TRUST_PLAYER_KEY = "Player";
private static final String TRUST_FEED_COUNT_KEY = "FeedCount";
private static final String TRUST_TRUSTED_KEY = "Trusted";
private static final String TRUST_COOLDOWN_KEY = "GraceCooldown";
private static final String GLOWING_SAVE_KEY = "Glowing";
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
private final Map<UUID, TrustEntry> trustByPlayer = new HashMap<>();
private boolean glowing;
private int quirkCooldown = createQuirkCooldown();
public GlimmerEntity(EntityType<? extends GlimmerEntity> entityType, Level level) {
super(entityType, level);
}
public static AttributeSupplier.Builder createAttributes() {
return net.minecraft.world.entity.Mob.createMobAttributes()
.add(Attributes.MAX_HEALTH, AntarchySettings.glimmerHealth())
.add(Attributes.MOVEMENT_SPEED, 0.3D)
.add(Attributes.FOLLOW_RANGE, 24.0D);
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
builder.define(GLOW_TICKS, 0);
}
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this));
this.goalSelector.addGoal(1, new PanicGoal(this, 1.6D));
this.goalSelector.addGoal(2, new TemptGoal(this, 1.1D, Ingredient.of(AntarchyTags.Items.GLIMMER_FOOD), false));
this.goalSelector.addGoal(3, new AvoidUntrustedPlayerGoal(10.0F, 1.15D));
this.goalSelector.addGoal(4, new net.minecraft.world.entity.ai.goal.AvoidEntityGoal<>(this, Monster.class, 8.0F, 1.0D, 1.2D));
this.goalSelector.addGoal(5, new FollowParentGoal(this, 1.25D));
this.goalSelector.addGoal(6, new WaterAvoidingRandomStrollGoal(this, 1.0D));
this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 8.0F));
this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
}
@Override
public boolean isFood(ItemStack stack) {
return stack.is(AntarchyTags.Items.GLIMMER_FOOD);
}
@Override
public GlimmerEntity getBreedOffspring(ServerLevel level, AgeableMob otherParent) {
return null;
}
@Override
public InteractionResult mobInteract(Player player, InteractionHand hand) {
ItemStack stack = player.getItemInHand(hand);
if (stack.is(AntarchyTags.Items.GLIMMER_FOOD)) {
return this.feedGlimmerFood(player, stack, hand);
}
return super.mobInteract(player, hand);
}
private InteractionResult feedGlimmerFood(Player player, ItemStack stack, InteractionHand hand) {
if (this.level().isClientSide) {
return InteractionResult.CONSUME;
}
this.usePlayerItem(player, hand, stack);
this.playSound(SoundEvents.GENERIC_EAT, 1.0F, 1.0F + (this.random.nextFloat() - 0.5F) * 0.2F);
if (!this.isBaby()) {
TrustEntry entry = this.trustByPlayer.computeIfAbsent(player.getUUID(), id -> new TrustEntry());
if (!entry.trusted) {
entry.feedCount++;
if (entry.feedCount >= TRUST_REQUIRED_FEEDS) {
entry.trusted = true;
}
} else if (this.glowing && entry.graceCooldown <= 0) {
player.addEffect(new MobEffectInstance(AntarchyObjects.GLIMMERS_GRACE.get(), GRACE_DURATION_TICKS, 0, false, true, true));
entry.graceCooldown = GRACE_COOLDOWN_TICKS;
}
}
return InteractionResult.SUCCESS;
}
public boolean isTrusted(UUID playerId) {
TrustEntry entry = this.trustByPlayer.get(playerId);
return entry != null && entry.trusted;
}
private boolean hasAnyTrustProgress() {
for (TrustEntry entry : this.trustByPlayer.values()) {
if (entry.trusted || entry.feedCount > 0) {
return true;
}
}
return false;
}
@Override
public boolean isPersistenceRequired() {
return super.isPersistenceRequired() || (!this.isBaby() && this.hasAnyTrustProgress());
}
public boolean isGlowingState() {
return this.getGlowTicks() > 0;
}
public float getGlowBlend(float partialTick) {
return Mth.clamp((this.getGlowTicks() + partialTick) / (float) GLOW_TRANSITION_TICKS, 0.0F, 1.0F);
}
@Override
public void tick() {
super.tick();
if (this.quirkCooldown > 0) {
this.quirkCooldown--;
}
if (!this.level().isClientSide && this.tickCount % GLOW_CHECK_INTERVAL_TICKS == 0) {
this.glowing = this.level().getMaxLocalRawBrightness(this.blockPosition()) <= GLOW_LIGHT_THRESHOLD;
}
if (!this.level().isClientSide) {
int glowTicks = this.getGlowTicks();
if (this.glowing && glowTicks < GLOW_TRANSITION_TICKS) {
this.setGlowTicks(glowTicks + 1);
} else if (!this.glowing && glowTicks > 0) {
this.setGlowTicks(glowTicks - 1);
}
}
if (this.isGlowingState()) {
GlimmerParticles.tickAmbient(this, this.getDeltaMovement().horizontalDistanceSqr() > RUN_SPEED_THRESHOLD_SQR);
}
if (this.level().isClientSide) {
return;
}
for (TrustEntry entry : this.trustByPlayer.values()) {
if (entry.graceCooldown > 0) {
entry.graceCooldown--;
}
}
}
@Override
public void addAdditionalSaveData(CompoundTag tag) {
super.addAdditionalSaveData(tag);
tag.putBoolean(GLOWING_SAVE_KEY, this.glowing);
ListTag trustList = new ListTag();
for (Map.Entry<UUID, TrustEntry> entry : this.trustByPlayer.entrySet()) {
CompoundTag entryTag = new CompoundTag();
entryTag.putUUID(TRUST_PLAYER_KEY, entry.getKey());
entryTag.putInt(TRUST_FEED_COUNT_KEY, entry.getValue().feedCount);
entryTag.putBoolean(TRUST_TRUSTED_KEY, entry.getValue().trusted);
entryTag.putInt(TRUST_COOLDOWN_KEY, entry.getValue().graceCooldown);
trustList.add(entryTag);
}
tag.put(TRUST_KEY, trustList);
}
@Override
public void readAdditionalSaveData(CompoundTag tag) {
super.readAdditionalSaveData(tag);
this.glowing = tag.getBoolean(GLOWING_SAVE_KEY);
this.setGlowTicks(this.glowing ? GLOW_TRANSITION_TICKS : 0);
this.trustByPlayer.clear();
for (net.minecraft.nbt.Tag rawEntry : tag.getList(TRUST_KEY, net.minecraft.nbt.Tag.TAG_COMPOUND)) {
CompoundTag entryTag = (CompoundTag) rawEntry;
TrustEntry entry = new TrustEntry();
entry.feedCount = entryTag.getInt(TRUST_FEED_COUNT_KEY);
entry.trusted = entryTag.getBoolean(TRUST_TRUSTED_KEY);
entry.graceCooldown = entryTag.getInt(TRUST_COOLDOWN_KEY);
this.trustByPlayer.put(entryTag.getUUID(TRUST_PLAYER_KEY), entry);
}
}
@Override
@Nullable
public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData spawnGroupData) {
GlimmerSpawnData glimmerSpawnData = spawnGroupData instanceof GlimmerSpawnData data ? data : new GlimmerSpawnData();
SpawnGroupData result = super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData);
if ((spawnReason == MobSpawnType.NATURAL || spawnReason == MobSpawnType.CHUNK_GENERATION)) {
if (glimmerSpawnData.adultSpawned) {
this.setAge(-24000);
} else {
glimmerSpawnData.adultSpawned = true;
}
}
return result != null ? result : glimmerSpawnData;
}
@Override
public net.minecraft.world.entity.EntityDimensions getDefaultDimensions(net.minecraft.world.entity.Pose pose) {
net.minecraft.world.entity.EntityDimensions dimensions = super.getDefaultDimensions(pose);
if (this.isBaby()) {
return dimensions;
}
return net.minecraft.world.entity.EntityDimensions.scalable(dimensions.width() * 2.0F, dimensions.height() * 2.0F);
}
@Override
protected void ageBoundaryReached() {
super.ageBoundaryReached();
this.refreshDimensions();
}
@Override
protected SoundEvent getAmbientSound() {
return SoundEvents.FOX_AMBIENT;
}
@Override
protected SoundEvent getHurtSound(DamageSource damageSource) {
return SoundEvents.FOX_HURT;
}
@Override
protected SoundEvent getDeathSound() {
return SoundEvents.FOX_DEATH;
}
@Override
protected float getSoundVolume() {
return 0.8F;
}
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
controllers.add(new AnimationController<>(this, "main_controller", 0, this::mainAnimController));
controllers.add(new AnimationController<>(this, QUIRK_CONTROLLER, 0, state -> PlayState.STOP)
.triggerableAnim(QUIRK_TRIGGER, RawAnimation.begin().thenPlay("quirk")));
}
private PlayState mainAnimController(AnimationState<GlimmerEntity> state) {
double speedSqr = this.getDeltaMovement().horizontalDistanceSqr();
if (speedSqr > RUN_SPEED_THRESHOLD_SQR) {
return state.setAndContinue(RUN_ANIM);
}
if (speedSqr > WALK_SPEED_THRESHOLD_SQR) {
return state.setAndContinue(WALK_ANIM);
}
if (this.quirkCooldown <= 0) {
this.quirkCooldown = this.createQuirkCooldown();
this.triggerAnim(QUIRK_CONTROLLER, QUIRK_TRIGGER);
}
return state.setAndContinue(IDLE_ANIM);
}
private int createQuirkCooldown() {
return MIN_QUIRK_COOLDOWN + this.random.nextInt(MAX_QUIRK_COOLDOWN - MIN_QUIRK_COOLDOWN + 1);
}
@Override
public AnimatableInstanceCache getAnimatableInstanceCache() {
return this.geoCache;
}
private int getGlowTicks() {
return this.entityData.get(GLOW_TICKS);
}
private void setGlowTicks(int glowTicks) {
this.entityData.set(GLOW_TICKS, Mth.clamp(glowTicks, 0, GLOW_TRANSITION_TICKS));
}
private static final class TrustEntry {
int feedCount;
boolean trusted;
int graceCooldown;
}
private static final class GlimmerSpawnData implements SpawnGroupData {
private boolean adultSpawned;
}
private final class AvoidUntrustedPlayerGoal extends Goal {
private final float maxDistance;
private final double speedModifier;
private Player avoidTarget;
private Path path;
AvoidUntrustedPlayerGoal(float maxDistance, double speedModifier) {
this.maxDistance = maxDistance;
this.speedModifier = speedModifier;
this.setFlags(EnumSet.of(Flag.MOVE));
}
@Override
public boolean canUse() {
if (GlimmerEntity.this.isBaby()) {
return false;
}
Player nearest = GlimmerEntity.this.level().getNearestPlayer(GlimmerEntity.this, this.maxDistance);
if (nearest == null || nearest.isSpectator() || nearest.isCreative()
|| GlimmerEntity.this.isTrusted(nearest.getUUID())
|| GlimmerEntity.this.distanceToSqr(nearest) > (double) (this.maxDistance * this.maxDistance)) {
return false;
}
Path escapePath = this.findEscapePath(nearest);
if (escapePath == null) {
return false;
}
this.avoidTarget = nearest;
this.path = escapePath;
return true;
}
@Override
public boolean canContinueToUse() {
return this.avoidTarget != null
&& this.avoidTarget.isAlive()
&& !GlimmerEntity.this.isTrusted(this.avoidTarget.getUUID())
&& !GlimmerEntity.this.getNavigation().isDone();
}
@Override
public void start() {
GlimmerEntity.this.getNavigation().moveTo(this.path, this.speedModifier);
}
@Override
public void stop() {
this.avoidTarget = null;
this.path = null;
}
@Nullable
private Path findEscapePath(Player toAvoid) {
Vec3 escapeVec = DefaultRandomPos.getPosAway(GlimmerEntity.this, 16, 7, toAvoid.position());
if (escapeVec == null) {
return null;
}
return GlimmerEntity.this.getNavigation().createPath(BlockPos.containing(escapeVec), 0);
}
}
}
@@ -64,9 +64,9 @@ public class MantisEntity extends Monster implements GeoEntity {
net.minecraft.network.syncher.SynchedEntityData.defineId(MantisEntity.class, net.minecraft.network.syncher.EntityDataSerializers.INT); net.minecraft.network.syncher.SynchedEntityData.defineId(MantisEntity.class, net.minecraft.network.syncher.EntityDataSerializers.INT);
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this); private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
private int attackAnimationTicks; protected int attackAnimationTicks;
private int flyBurstTicks; protected int flyBurstTicks;
private int flyCooldownTicks; protected int flyCooldownTicks;
private int debugLogTicks = 0; private int debugLogTicks = 0;
public MantisEntity(EntityType<? extends MantisEntity> entityType, Level level) { public MantisEntity(EntityType<? extends MantisEntity> entityType, Level level) {
@@ -90,7 +90,10 @@ public class MantisEntity extends Monster implements GeoEntity {
} }
public static boolean canSpawn(EntityType<MantisEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) { public static boolean canSpawn(EntityType<MantisEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
if (spawnReason == MobSpawnType.SPAWN_EGG || spawnReason == MobSpawnType.SPAWNER || spawnReason == MobSpawnType.COMMAND) { if (spawnReason == MobSpawnType.SPAWN_EGG
|| spawnReason == MobSpawnType.SPAWNER
|| spawnReason == MobSpawnType.TRIAL_SPAWNER
|| spawnReason == MobSpawnType.COMMAND) {
return true; return true;
} }
@@ -147,8 +150,8 @@ public class MantisEntity extends Monster implements GeoEntity {
@Override @Override
protected void registerGoals() { protected void registerGoals() {
this.goalSelector.addGoal(1, new FloatGoal(this)); this.goalSelector.addGoal(1, new FloatGoal(this));
this.goalSelector.addGoal(2, new MeleeAttackGoal(this, COMBAT_SPEED, true)); this.goalSelector.addGoal(2, this.createCombatGoal());
this.goalSelector.addGoal(3, new WaterAvoidingRandomStrollGoal(this, WANDER_SPEED)); this.goalSelector.addGoal(3, this.createIdleStrollGoal());
HurtByTargetGoal hurtByTargetGoal = new HurtByTargetGoal(this); HurtByTargetGoal hurtByTargetGoal = new HurtByTargetGoal(this);
this.targetSelector.addGoal(1, hurtByTargetGoal); this.targetSelector.addGoal(1, hurtByTargetGoal);
@@ -156,6 +159,14 @@ public class MantisEntity extends Monster implements GeoEntity {
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 5, true, false, null)); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 5, true, false, null));
} }
protected MeleeAttackGoal createCombatGoal() {
return new MeleeAttackGoal(this, this.getCombatSpeed(), true);
}
protected WaterAvoidingRandomStrollGoal createIdleStrollGoal() {
return new WaterAvoidingRandomStrollGoal(this, WANDER_SPEED);
}
@Override @Override
protected PathNavigation createNavigation(Level level) { protected PathNavigation createNavigation(Level level) {
GroundPathNavigation navigation = new GroundPathNavigation(this, level); GroundPathNavigation navigation = new GroundPathNavigation(this, level);
@@ -206,8 +217,9 @@ public class MantisEntity extends Monster implements GeoEntity {
LivingEntity target = this.getTarget(); LivingEntity target = this.getTarget();
if (target != null && target.isAlive()) { if (target != null && target.isAlive()) {
this.onActiveTarget(target);
this.getLookControl().setLookAt(target, 30.0F, 30.0F); this.getLookControl().setLookAt(target, 30.0F, 30.0F);
} else if (this.flyBurstTicks <= 0 && this.flyCooldownTicks <= 0 && this.onGround() && this.random.nextInt(180) == 0) { } else if (this.shouldStartFlightBurst()) {
this.startFlightBurst(); this.startFlightBurst();
} }
@@ -264,6 +276,26 @@ public class MantisEntity extends Monster implements GeoEntity {
super.setYBodyRot(yBodyRot); super.setYBodyRot(yBodyRot);
} }
protected double getCombatSpeed() {
return COMBAT_SPEED;
}
protected void onActiveTarget(LivingEntity target) {
}
protected boolean shouldStartFlightBurst() {
return this.flyBurstTicks <= 0
&& this.flyCooldownTicks <= 0
&& this.onGround()
&& this.random.nextInt(180) == 0;
}
protected void stopFlightBurst() {
this.flyBurstTicks = 0;
this.flyCooldownTicks = 0;
this.setNoGravity(false);
}
private void startFlightBurst() { private void startFlightBurst() {
this.flyBurstTicks = 40 + this.random.nextInt(30); this.flyBurstTicks = 40 + this.random.nextInt(30);
this.flyCooldownTicks = 160 + this.random.nextInt(80); this.flyCooldownTicks = 160 + this.random.nextInt(80);
@@ -0,0 +1,794 @@
package com.craisinlord.antarchy.content.entity;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.AntarchyTags;
import java.util.EnumSet;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ItemParticleOption;
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.tags.BlockTags;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.AgeableMob;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.PathfinderMob;
import net.minecraft.world.entity.TamableAnimal;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.goal.FloatGoal;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
import net.minecraft.world.entity.ai.goal.MoveToBlockGoal;
import net.minecraft.world.entity.ai.goal.PanicGoal;
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
import net.minecraft.world.entity.ai.goal.TemptGoal;
import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
import net.minecraft.world.entity.ai.util.DefaultRandomPos;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.BedBlock;
import net.minecraft.world.level.block.ComposterBlock;
import net.minecraft.world.level.block.CropBlock;
import net.minecraft.world.level.block.LevelEvent;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import software.bernie.geckolib.animatable.GeoEntity;
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.animation.AnimatableManager;
import software.bernie.geckolib.animation.AnimationController;
import software.bernie.geckolib.animation.AnimationState;
import software.bernie.geckolib.animation.PlayState;
import software.bernie.geckolib.animation.RawAnimation;
import software.bernie.geckolib.util.GeckoLibUtil;
public class RollyPollyEntity extends TamableAnimal implements GeoEntity {
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
private static final RawAnimation WALK_ANIM = RawAnimation.begin().thenLoop("walk");
private static final RawAnimation ROLL_UP_ANIM = RawAnimation.begin().thenPlayAndHold("wheel_mode");
private static final RawAnimation ROLLING_ANIM = RawAnimation.begin().thenLoop("roll");
private static final RawAnimation UNROLL_ANIM = RawAnimation.begin().thenPlay("normal_mode");
private static final int ANIM_NONE = 0;
private static final int ANIM_ROLL_UP = 2;
private static final int ANIM_UNROLL = 4;
// wheel_mode is 0.75s, normal_mode is ~0.42s
private static final int ROLL_UP_TICKS = 15;
private static final int UNROLL_TICKS = 9;
private static final int DEFENSIVE_CURL_TICKS = 100;
private static final int TUMBLE_DAMAGE_INTERVAL_TICKS = 30;
private static final EntityDataAccessor<Integer> ANIMATION_STATE =
SynchedEntityData.defineId(RollyPollyEntity.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Boolean> ROLLED =
SynchedEntityData.defineId(RollyPollyEntity.class, EntityDataSerializers.BOOLEAN);
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
private int rollTransitionTicks;
private boolean unrolling;
private int defensiveCurlTicks;
private int tumbleTicks;
private boolean hasCompost;
public RollyPollyEntity(EntityType<? extends RollyPollyEntity> entityType, Level level) {
super(entityType, level);
}
public static AttributeSupplier.Builder createAttributes() {
return Mob.createMobAttributes()
.add(Attributes.MAX_HEALTH, AntarchySettings.rollyPollyHealth())
.add(Attributes.MOVEMENT_SPEED, AntarchySettings.rollyPollyMovementSpeed())
.add(Attributes.FOLLOW_RANGE, 16.0D);
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
builder.define(ANIMATION_STATE, ANIM_NONE);
builder.define(ROLLED, false);
}
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this));
this.goalSelector.addGoal(1, new PanicGoal(this, 1.4D) {
@Override
public boolean canUse() {
// Curled-up or tamed rolly pollies stand their ground
return !RollyPollyEntity.this.isRolled() && !RollyPollyEntity.this.isTame() && super.canUse();
}
});
this.goalSelector.addGoal(2, new FertilizeCropGoal());
this.goalSelector.addGoal(3, new EatCompostItemGoal());
this.goalSelector.addGoal(4, new SnuggleOnBedGoal());
this.goalSelector.addGoal(5, new TemptGoal(this, 1.1D, Ingredient.of(AntarchyTags.Items.ROLLY_POLLY_FOOD), false) {
@Override
public boolean canUse() {
return !RollyPollyEntity.this.isRolled() && super.canUse();
}
});
this.goalSelector.addGoal(6, new RollingStrollGoal());
this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D) {
@Override
public boolean canUse() {
return !RollyPollyEntity.this.isRolled() && !RollyPollyEntity.this.isVehicle() && super.canUse();
}
});
this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F));
this.goalSelector.addGoal(9, new RandomLookAroundGoal(this));
}
@Override
public boolean isFood(ItemStack stack) {
return stack.is(AntarchyTags.Items.ROLLY_POLLY_FOOD);
}
@Override
public InteractionResult mobInteract(Player player, InteractionHand hand) {
ItemStack stack = player.getItemInHand(hand);
if (this.isFood(stack) && (!this.isTame() || this.getHealth() < this.getMaxHealth())) {
if (!this.level().isClientSide) {
if (!player.getAbilities().instabuild) {
stack.shrink(1);
}
if (!this.isTame()) {
if (this.random.nextInt(AntarchySettings.rollyPollyTameChance()) == 0) {
this.setTame(true, true);
this.setOwnerUUID(player.getUUID());
this.stopDefensiveCurl();
this.setTarget(null);
this.level().broadcastEntityEvent(this, (byte) 7);
} else {
this.level().broadcastEntityEvent(this, (byte) 6);
}
} else {
this.heal(4.0F);
this.level().broadcastEntityEvent(this, (byte) 7);
}
}
return InteractionResult.sidedSuccess(this.level().isClientSide);
}
if (!this.hasCompost && isCompostable(stack)) {
if (!this.level().isClientSide) {
ItemStack eaten = stack.copyWithCount(1);
if (!player.getAbilities().instabuild) {
stack.shrink(1);
}
this.eatCompost(eaten);
}
return InteractionResult.sidedSuccess(this.level().isClientSide);
}
if (this.isFood(stack)) {
return InteractionResult.sidedSuccess(this.level().isClientSide);
}
if (this.isTame() && stack.isEmpty() && !player.isShiftKeyDown() && !player.isPassengerOfSameVehicle(this)) {
if (!this.level().isClientSide) {
player.startRiding(this);
}
return InteractionResult.sidedSuccess(this.level().isClientSide);
}
return super.mobInteract(player, hand);
}
@Override
@Nullable
public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob otherParent) {
return null;
}
private static boolean isCompostable(ItemStack stack) {
return !stack.isEmpty() && ComposterBlock.COMPOSTABLES.containsKey(stack.getItem());
}
private void eatCompost(ItemStack eaten) {
this.hasCompost = true;
this.playSound(this.getEatingSound(eaten), 0.9F, 1.2F);
if (this.level() instanceof ServerLevel serverLevel) {
serverLevel.sendParticles(new ItemParticleOption(ParticleTypes.ITEM, eaten),
this.getX(), this.getY(0.6D), this.getZ(), 6, 0.1D, 0.1D, 0.1D, 0.05D);
}
}
public boolean isRolled() {
return this.entityData.get(ROLLED);
}
private void setRolled(boolean rolled) {
this.entityData.set(ROLLED, rolled);
}
/** Toggles wheel mode; called from the ridden-roll keybind payload. */
public void handleRollToggle(ServerPlayer player) {
if (!this.isTame() || this.getControllingPassenger() != player) {
return;
}
if (this.rollTransitionTicks > 0) {
return;
}
if (this.isRolled()) {
this.startUnroll();
} else {
this.startRollUp();
}
}
private void startRollUp() {
this.setRolled(true);
this.unrolling = false;
this.rollTransitionTicks = ROLL_UP_TICKS;
this.setAnimationState(ANIM_ROLL_UP);
this.playSound(SoundEvents.ARMOR_EQUIP_TURTLE.value(), 0.8F, 1.4F);
}
private void startUnroll() {
this.unrolling = true;
this.rollTransitionTicks = UNROLL_TICKS;
this.setAnimationState(ANIM_UNROLL);
this.playSound(SoundEvents.ARMOR_EQUIP_TURTLE.value(), 0.8F, 1.1F);
}
private void stopDefensiveCurl() {
this.defensiveCurlTicks = 0;
if (this.isRolled() && !this.isVehicle()) {
this.startUnroll();
}
}
@Override
public boolean hurt(DamageSource source, float amount) {
if (this.isRolled()) {
amount *= 0.25F;
}
boolean hurt = super.hurt(source, amount);
// Wild rolly pollies curl up defensively when attacked
if (hurt && !this.level().isClientSide && !this.isTame() && this.isAlive()
&& !this.isRolled() && this.rollTransitionTicks <= 0) {
this.defensiveCurlTicks = DEFENSIVE_CURL_TICKS;
this.startRollUp();
}
return hurt;
}
@Override
public void tick() {
super.tick();
if (this.level().isClientSide) {
return;
}
if (this.rollTransitionTicks > 0) {
this.rollTransitionTicks--;
if (this.rollTransitionTicks <= 0) {
if (this.unrolling) {
this.setRolled(false);
this.unrolling = false;
}
this.setAnimationState(ANIM_NONE);
}
}
if (this.defensiveCurlTicks > 0) {
this.defensiveCurlTicks--;
this.getNavigation().stop();
if (this.defensiveCurlTicks <= 0 && this.isRolled() && !this.isVehicle()) {
this.startUnroll();
}
}
this.tickTumbleDamage();
}
private void tickTumbleDamage() {
if (!this.isRolled() || this.rollTransitionTicks > 0
|| !(this.getControllingPassenger() instanceof Player rider)) {
this.tumbleTicks = 0;
return;
}
boolean moving = this.getDeltaMovement().horizontalDistanceSqr() > 0.003D;
boolean helmeted = !rider.getItemBySlot(EquipmentSlot.HEAD).isEmpty();
if (!moving || helmeted) {
return;
}
if (++this.tumbleTicks >= TUMBLE_DAMAGE_INTERVAL_TICKS) {
this.tumbleTicks = 0;
rider.hurt(this.damageSources().generic(), (float) AntarchySettings.rollyPollyTumbleDamage());
}
}
private int getAnimationState() {
return this.entityData.get(ANIMATION_STATE);
}
private void setAnimationState(int state) {
this.entityData.set(ANIMATION_STATE, state);
}
@Override
@Nullable
public LivingEntity getControllingPassenger() {
if (!this.isTame()) {
return null;
}
Entity passenger = this.getFirstPassenger();
return passenger instanceof LivingEntity living ? living : null;
}
@Override
public boolean canAddPassenger(Entity passenger) {
return this.getPassengers().isEmpty();
}
@Override
protected void positionRider(Entity passenger, MoveFunction moveFunction) {
if (this.hasPassenger(passenger)) {
// When rolled the rider tucks into the center of the ball; otherwise sits on the shell
double yOffset = this.isRolled() ? -0.25D : 0.45D;
moveFunction.accept(passenger, this.getX(), this.getY() + yOffset, this.getZ());
}
}
@Override
public void travel(Vec3 travelVector) {
if (this.defensiveCurlTicks > 0 && !this.isVehicle()) {
super.travel(Vec3.ZERO);
return;
}
super.travel(travelVector);
}
@Override
protected void tickRidden(Player player, Vec3 travelVector) {
super.tickRidden(player, travelVector);
this.setRot(player.getYHeadRot(), player.getXRot() * 0.5F);
this.yRotO = this.yBodyRot = this.yHeadRot = this.getYRot();
}
@Override
protected Vec3 getRiddenInput(Player player, Vec3 travelVector) {
if (this.rollTransitionTicks > 0) {
// Hold still while rolling up / unrolling
return Vec3.ZERO;
}
float forward = player.zza;
float strafe = player.xxa * 0.5F;
if (forward < 0.0F) {
forward *= 0.4F;
}
if (this.isRolled()) {
// Rolling is fast but drifty
strafe *= 0.35F;
}
return new Vec3(strafe, 0.0D, forward);
}
@Override
protected float getRiddenSpeed(Player player) {
return (float) (this.getAttributeValue(Attributes.MOVEMENT_SPEED)
* (this.isRolled() ? AntarchySettings.rollyPollyRollSpeedMultiplier() : 1.0D));
}
@Override
public boolean causeFallDamage(float fallDistance, float multiplier, DamageSource damageSource) {
if (this.isRolled()) {
return false;
}
return super.causeFallDamage(fallDistance, multiplier, damageSource);
}
@Override
public void addAdditionalSaveData(CompoundTag tag) {
super.addAdditionalSaveData(tag);
tag.putBoolean("HasCompost", this.hasCompost);
}
@Override
public void readAdditionalSaveData(CompoundTag tag) {
super.readAdditionalSaveData(tag);
this.hasCompost = tag.getBoolean("HasCompost");
}
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
controllers.add(new AnimationController<>(this, "main_controller", 2, this::mainAnimController));
}
private PlayState mainAnimController(AnimationState<RollyPollyEntity> state) {
AnimationController<RollyPollyEntity> controller = state.getController();
int transition = this.getAnimationState();
if (transition == ANIM_ROLL_UP) {
controller.setAnimationSpeed(1.0D);
return state.setAndContinue(ROLL_UP_ANIM);
}
if (transition == ANIM_UNROLL) {
controller.setAnimationSpeed(1.0D);
return state.setAndContinue(UNROLL_ANIM);
}
if (this.isRolled()) {
if (state.isMoving()) {
controller.setAnimationSpeed(1.0D);
return state.setAndContinue(ROLLING_ANIM);
}
if (controller.getCurrentAnimation() == null) {
controller.setAnimationSpeed(1.0D);
return state.setAndContinue(ROLL_UP_ANIM);
}
controller.setAnimationSpeed(0.0D);
return PlayState.CONTINUE;
}
controller.setAnimationSpeed(1.0D);
return state.setAndContinue(state.isMoving() ? WALK_ANIM : IDLE_ANIM);
}
@Override
public AnimatableInstanceCache getAnimatableInstanceCache() {
return this.geoCache;
}
private class EatCompostItemGoal extends Goal {
@Nullable
private ItemEntity targetItem;
private int scanCooldown;
EatCompostItemGoal() {
this.setFlags(EnumSet.of(Goal.Flag.MOVE));
}
@Override
public boolean canUse() {
if (RollyPollyEntity.this.hasCompost
|| RollyPollyEntity.this.isRolled()
|| RollyPollyEntity.this.isVehicle()
|| RollyPollyEntity.this.defensiveCurlTicks > 0) {
return false;
}
if (this.scanCooldown > 0) {
this.scanCooldown--;
return false;
}
this.scanCooldown = 20;
this.targetItem = this.findNearestCompostItem();
return this.targetItem != null;
}
@Override
public boolean canContinueToUse() {
return !RollyPollyEntity.this.hasCompost
&& !RollyPollyEntity.this.isRolled()
&& !RollyPollyEntity.this.isVehicle()
&& this.targetItem != null
&& this.targetItem.isAlive()
&& isCompostable(this.targetItem.getItem());
}
@Override
public void start() {
if (this.targetItem != null) {
RollyPollyEntity.this.getNavigation().moveTo(this.targetItem, 1.1D);
}
}
@Override
public void stop() {
this.targetItem = null;
RollyPollyEntity.this.getNavigation().stop();
}
@Override
public void tick() {
if (this.targetItem == null) {
return;
}
RollyPollyEntity.this.getLookControl().setLookAt(this.targetItem);
if (RollyPollyEntity.this.tickCount % 10 == 0) {
RollyPollyEntity.this.getNavigation().moveTo(this.targetItem, 1.1D);
}
if (RollyPollyEntity.this.distanceToSqr(this.targetItem) < 2.0D) {
ItemStack stack = this.targetItem.getItem();
ItemStack eaten = stack.copyWithCount(1);
stack.shrink(1);
if (stack.isEmpty()) {
this.targetItem.discard();
} else {
this.targetItem.setItem(stack.copy());
}
RollyPollyEntity.this.eatCompost(eaten);
}
}
@Nullable
private ItemEntity findNearestCompostItem() {
ItemEntity nearest = null;
double nearestDist = Double.MAX_VALUE;
for (ItemEntity item : RollyPollyEntity.this.level().getEntitiesOfClass(ItemEntity.class,
RollyPollyEntity.this.getBoundingBox().inflate(8.0D, 4.0D, 8.0D),
item -> item.isAlive() && isCompostable(item.getItem()))) {
double dist = RollyPollyEntity.this.distanceToSqr(item);
if (dist < nearestDist) {
nearest = item;
nearestDist = dist;
}
}
return nearest;
}
}
private class FertilizeCropGoal extends MoveToBlockGoal {
private static final int ROLL_ON_CROP_TICKS = 20;
private int rollTicks;
FertilizeCropGoal() {
super(RollyPollyEntity.this, 1.1D, 8, 2);
}
@Override
public boolean canUse() {
return RollyPollyEntity.this.hasCompost
&& !RollyPollyEntity.this.isRolled()
&& !RollyPollyEntity.this.isVehicle()
&& RollyPollyEntity.this.defensiveCurlTicks <= 0
&& super.canUse();
}
@Override
public boolean canContinueToUse() {
return RollyPollyEntity.this.hasCompost
&& !RollyPollyEntity.this.isVehicle()
&& super.canContinueToUse();
}
@Override
protected int nextStartTick(PathfinderMob mob) {
return reducedTickDelay(40 + mob.getRandom().nextInt(40));
}
@Override
protected boolean isValidTarget(LevelReader level, BlockPos pos) {
BlockState state = level.getBlockState(pos);
return state.getBlock() instanceof CropBlock crop && !crop.isMaxAge(state);
}
@Override
protected BlockPos getMoveToTarget() {
return this.blockPos;
}
@Override
public double acceptedDistance() {
return 1.75D;
}
@Override
public void start() {
this.rollTicks = 0;
super.start();
}
@Override
public void stop() {
super.stop();
if (RollyPollyEntity.this.isRolled() && RollyPollyEntity.this.rollTransitionTicks <= 0) {
RollyPollyEntity.this.startUnroll();
}
}
@Override
public void tick() {
super.tick();
if (!this.isReachedTarget()) {
this.rollTicks = 0;
return;
}
RollyPollyEntity.this.getNavigation().stop();
if (!RollyPollyEntity.this.isRolled()) {
if (RollyPollyEntity.this.rollTransitionTicks <= 0) {
RollyPollyEntity.this.startRollUp();
}
return;
}
if (RollyPollyEntity.this.rollTransitionTicks > 0) {
return;
}
if (++this.rollTicks >= ROLL_ON_CROP_TICKS) {
this.fertilize();
}
}
private void fertilize() {
if (RollyPollyEntity.this.level() instanceof ServerLevel serverLevel) {
BlockState state = serverLevel.getBlockState(this.blockPos);
if (state.getBlock() instanceof CropBlock crop && !crop.isMaxAge(state)) {
crop.performBonemeal(serverLevel, RollyPollyEntity.this.random, this.blockPos, state);
serverLevel.levelEvent(LevelEvent.PARTICLES_AND_SOUND_PLANT_GROWTH, this.blockPos, 15);
}
}
RollyPollyEntity.this.hasCompost = false;
RollyPollyEntity.this.startUnroll();
}
}
private class RollingStrollGoal extends Goal {
@Nullable
private Vec3 targetPos;
private int rollingTicks;
private int maxRollingTicks;
private boolean startedMoving;
private boolean finished;
RollingStrollGoal() {
this.setFlags(EnumSet.of(Goal.Flag.MOVE));
}
@Override
public boolean canUse() {
if (RollyPollyEntity.this.isRolled()
|| RollyPollyEntity.this.isVehicle()
|| RollyPollyEntity.this.defensiveCurlTicks > 0
|| RollyPollyEntity.this.hasCompost
|| RollyPollyEntity.this.rollTransitionTicks > 0) {
return false;
}
if (RollyPollyEntity.this.getRandom().nextInt(reducedTickDelay(240)) != 0) {
return false;
}
this.targetPos = DefaultRandomPos.getPos(RollyPollyEntity.this, 16, 4);
return this.targetPos != null;
}
@Override
public boolean canContinueToUse() {
return !this.finished
&& this.rollingTicks < this.maxRollingTicks
&& !RollyPollyEntity.this.isVehicle()
&& !RollyPollyEntity.this.hasCompost;
}
@Override
public void start() {
this.rollingTicks = 0;
this.maxRollingTicks = this.adjustedTickDelay(140 + RollyPollyEntity.this.getRandom().nextInt(100));
this.startedMoving = false;
this.finished = false;
RollyPollyEntity.this.startRollUp();
}
@Override
public void stop() {
this.targetPos = null;
RollyPollyEntity.this.getNavigation().stop();
if (RollyPollyEntity.this.isRolled() && RollyPollyEntity.this.rollTransitionTicks <= 0) {
RollyPollyEntity.this.startUnroll();
}
}
@Override
public void tick() {
if (RollyPollyEntity.this.rollTransitionTicks > 0 || this.targetPos == null) {
return;
}
this.rollingTicks++;
if (RollyPollyEntity.this.getNavigation().isDone()) {
if (this.startedMoving) {
this.finished = true;
} else {
RollyPollyEntity.this.getNavigation().moveTo(
this.targetPos.x, this.targetPos.y, this.targetPos.z,
AntarchySettings.rollyPollyRollSpeedMultiplier());
this.startedMoving = true;
}
}
}
}
private class SnuggleOnBedGoal extends Goal {
@Nullable
private Player ownerPlayer;
@Nullable
private BlockPos bedPos;
private int onBedTicks;
SnuggleOnBedGoal() {
this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK, Goal.Flag.JUMP));
}
@Override
public boolean canUse() {
if (!RollyPollyEntity.this.isTame() || RollyPollyEntity.this.isVehicle()) {
return false;
}
if (!(RollyPollyEntity.this.getOwner() instanceof Player player) || !player.isSleeping()) {
return false;
}
if (RollyPollyEntity.this.distanceToSqr(player) > 100.0D) {
return false;
}
BlockPos pos = player.blockPosition();
BlockState stateAt = RollyPollyEntity.this.level().getBlockState(pos);
if (!stateAt.is(BlockTags.BEDS)) {
return false;
}
this.ownerPlayer = player;
this.bedPos = stateAt.getOptionalValue(BedBlock.FACING)
.map(direction -> pos.relative(direction.getOpposite()))
.orElse(pos);
return true;
}
@Override
public boolean canContinueToUse() {
return RollyPollyEntity.this.isTame()
&& !RollyPollyEntity.this.isVehicle()
&& this.ownerPlayer != null
&& this.ownerPlayer.isSleeping()
&& this.bedPos != null;
}
@Override
public void start() {
this.onBedTicks = 0;
}
@Override
public void stop() {
this.ownerPlayer = null;
this.bedPos = null;
this.onBedTicks = 0;
RollyPollyEntity.this.getNavigation().stop();
if (RollyPollyEntity.this.isRolled() && RollyPollyEntity.this.rollTransitionTicks <= 0) {
RollyPollyEntity.this.startUnroll();
}
}
@Override
public void tick() {
if (this.ownerPlayer == null || this.bedPos == null) {
return;
}
if (RollyPollyEntity.this.distanceToSqr(this.ownerPlayer) > 2.5D) {
this.onBedTicks = 0;
if (RollyPollyEntity.this.isRolled()) {
if (RollyPollyEntity.this.rollTransitionTicks <= 0) {
RollyPollyEntity.this.startUnroll();
}
} else {
RollyPollyEntity.this.getNavigation().moveTo(
this.bedPos.getX() + 0.5D, this.bedPos.getY() + 1.0D, this.bedPos.getZ() + 0.5D, 1.1D);
}
return;
}
RollyPollyEntity.this.getNavigation().stop();
if (++this.onBedTicks > this.adjustedTickDelay(16)
&& !RollyPollyEntity.this.isRolled()
&& RollyPollyEntity.this.rollTransitionTicks <= 0) {
RollyPollyEntity.this.startRollUp();
}
}
}
}
@@ -1,265 +0,0 @@
package com.craisinlord.antarchy.content.entity;
import com.craisinlord.antarchy.Antarchy;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.RandomSource;
import net.minecraft.world.Difficulty;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.goal.FloatGoal;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
import net.minecraft.world.entity.ai.goal.MeleeAttackGoal;
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.phys.Vec3;
import software.bernie.geckolib.animatable.GeoEntity;
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.animation.AnimatableManager;
import software.bernie.geckolib.animation.AnimationController;
import software.bernie.geckolib.animation.AnimationState;
import software.bernie.geckolib.animation.PlayState;
import software.bernie.geckolib.animation.RawAnimation;
import software.bernie.geckolib.util.GeckoLibUtil;
import java.util.EnumSet;
public class SpitBugEntity extends Monster implements GeoEntity {
private static final EntityDataAccessor<Integer> SPIT_ANIM_TICKS =
SynchedEntityData.defineId(SpitBugEntity.class, EntityDataSerializers.INT);
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
private static final RawAnimation WALK_ANIM = RawAnimation.begin().thenLoop("walk");
private static final RawAnimation SPIT_ANIM = RawAnimation.begin().thenPlay("spit");
private static final double MAX_HEALTH = 50.0D;
private static final double MOVEMENT_SPEED = 0.23D;
private static final double ATTACK_DAMAGE = 5.0D;
private static final double FOLLOW_RANGE = 24.0D;
private static final double SPIT_RANGE_SQR = 14.0D * 14.0D;
private static final double MELEE_RANGE_SQR = 3.5D * 3.5D;
private static final int SPIT_COOLDOWN_TICKS = 55;
private static final int SPIT_ANIMATION_TICKS = 18;
private static final int SPIT_RELEASE_TICKS = 8;
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
private int spitCooldownTicks;
private int spitAnimationTicks;
private int spitReleaseTicks;
public SpitBugEntity(EntityType<? extends SpitBugEntity> entityType, Level level) {
super(entityType, level);
this.xpReward = 10;
}
public static AttributeSupplier.Builder createAttributes() {
return Mob.createMobAttributes()
.add(Attributes.MAX_HEALTH, MAX_HEALTH)
.add(Attributes.MOVEMENT_SPEED, MOVEMENT_SPEED)
.add(Attributes.ATTACK_DAMAGE, ATTACK_DAMAGE)
.add(Attributes.FOLLOW_RANGE, FOLLOW_RANGE)
.add(Attributes.ARMOR, 4.0D)
.add(Attributes.KNOCKBACK_RESISTANCE, 0.2D);
}
public static boolean canSpawn(EntityType<SpitBugEntity> entityType, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
if (spawnReason == MobSpawnType.SPAWN_EGG || spawnReason == MobSpawnType.SPAWNER || spawnReason == MobSpawnType.COMMAND) {
return true;
}
return level.getDifficulty() != Difficulty.PEACEFUL
&& level.isEmptyBlock(pos)
&& level.isEmptyBlock(pos.above())
&& Monster.checkMonsterSpawnRules(entityType, level, spawnReason, pos, random);
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
builder.define(SPIT_ANIM_TICKS, 0);
}
@Override
protected void registerGoals() {
this.goalSelector.addGoal(0, new FloatGoal(this));
this.goalSelector.addGoal(1, new SpitAttackGoal());
this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 1.0D, false));
this.goalSelector.addGoal(3, new WaterAvoidingRandomStrollGoal(this, 0.9D));
this.goalSelector.addGoal(4, new LookAtPlayerGoal(this, Player.class, 12.0F));
this.goalSelector.addGoal(5, new RandomLookAroundGoal(this));
this.targetSelector.addGoal(1, new HurtByTargetGoal(this));
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
}
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
controllers.add(new AnimationController<>(this, "main_controller", 2, this::mainAnimController));
}
@Override
public AnimatableInstanceCache getAnimatableInstanceCache() {
return this.geoCache;
}
@Override
public void tick() {
super.tick();
if (this.level().isClientSide) {
return;
}
if (this.spitCooldownTicks > 0) {
this.spitCooldownTicks--;
}
if (this.spitAnimationTicks > 0) {
this.spitAnimationTicks--;
this.entityData.set(SPIT_ANIM_TICKS, this.spitAnimationTicks);
if (this.spitReleaseTicks > 0 && --this.spitReleaseTicks == 0) {
this.fireSpitProjectile();
}
}
}
@Override
public boolean doHurtTarget(net.minecraft.world.entity.Entity target) {
boolean hurt = super.doHurtTarget(target);
if (hurt) {
this.playSound(SoundEvents.SPIDER_HURT, 0.7F, 0.8F + this.random.nextFloat() * 0.2F);
}
return hurt;
}
@Override
protected SoundEvent getAmbientSound() {
return SoundEvents.SPIDER_AMBIENT;
}
@Override
protected SoundEvent getHurtSound(DamageSource damageSource) {
return SoundEvents.SPIDER_HURT;
}
@Override
protected SoundEvent getDeathSound() {
return SoundEvents.SPIDER_DEATH;
}
@Override
protected void playStepSound(BlockPos pos, BlockState blockState) {
this.playSound(SoundEvents.SPIDER_STEP, 0.18F, 0.95F);
}
private PlayState mainAnimController(AnimationState<SpitBugEntity> state) {
if (this.entityData.get(SPIT_ANIM_TICKS) > 0) {
return state.setAndContinue(SPIT_ANIM);
}
return state.setAndContinue(state.isMoving() ? WALK_ANIM : IDLE_ANIM);
}
private boolean canSpitAt(LivingEntity target) {
return this.spitCooldownTicks <= 0
&& this.spitAnimationTicks <= 0
&& this.hasLineOfSight(target)
&& this.distanceToSqr(target) <= SPIT_RANGE_SQR
&& this.distanceToSqr(target) > MELEE_RANGE_SQR;
}
private void startSpitAttack() {
this.spitCooldownTicks = SPIT_COOLDOWN_TICKS;
this.spitAnimationTicks = SPIT_ANIMATION_TICKS;
this.spitReleaseTicks = SPIT_RELEASE_TICKS;
this.entityData.set(SPIT_ANIM_TICKS, this.spitAnimationTicks);
}
@SuppressWarnings("unchecked")
private void fireSpitProjectile() {
if (!(this.level() instanceof ServerLevel serverLevel)) {
return;
}
LivingEntity target = this.getTarget();
if (target == null || !target.isAlive()) {
return;
}
EntityType<SpitBugProjectileEntity> projectileType = (EntityType<SpitBugProjectileEntity>) BuiltInRegistries.ENTITY_TYPE.getOptional(
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "spit_bug_projectile")
).orElse(null);
if (projectileType == null) {
return;
}
SpitBugProjectileEntity projectile = new SpitBugProjectileEntity(projectileType, this, serverLevel);
Vec3 origin = this.position()
.add(0.0D, this.getBbHeight() * 0.55D, 0.0D)
.add(this.getViewVector(0.0F).scale(1.35D));
Vec3 aimPoint = target.getEyePosition().add(target.getDeltaMovement().scale(0.45D));
Vec3 direction = aimPoint.subtract(origin).normalize();
projectile.setPos(origin.x, origin.y, origin.z);
projectile.shoot(direction.x, direction.y, direction.z, 1.05F, 0.0F);
serverLevel.addFreshEntity(projectile);
this.playSound(SoundEvents.SLIME_ATTACK, 1.0F, 0.85F + this.random.nextFloat() * 0.15F);
}
private final class SpitAttackGoal extends Goal {
SpitAttackGoal() {
this.setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK));
}
@Override
public boolean canUse() {
LivingEntity target = SpitBugEntity.this.getTarget();
return target != null && target.isAlive();
}
@Override
public boolean canContinueToUse() {
return this.canUse();
}
@Override
public void tick() {
LivingEntity target = SpitBugEntity.this.getTarget();
if (target == null) {
return;
}
SpitBugEntity.this.getLookControl().setLookAt(target, 30.0F, 30.0F);
if (SpitBugEntity.this.canSpitAt(target)) {
SpitBugEntity.this.getNavigation().stop();
SpitBugEntity.this.startSpitAttack();
return;
}
if (SpitBugEntity.this.distanceToSqr(target) > 36.0D || !SpitBugEntity.this.hasLineOfSight(target)) {
SpitBugEntity.this.getNavigation().moveTo(target, 1.0D);
} else {
SpitBugEntity.this.getNavigation().stop();
}
}
}
}
@@ -1,172 +0,0 @@
package com.craisinlord.antarchy.content.entity;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.projectile.ThrowableItemProjectile;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.Vec3;
public class SpitBugProjectileEntity extends ThrowableItemProjectile {
private static final EntityDataAccessor<Boolean> LINGERING =
SynchedEntityData.defineId(SpitBugProjectileEntity.class, EntityDataSerializers.BOOLEAN);
private static final int MAX_FLIGHT_TICKS = 100;
private static final int LINGER_DURATION_TICKS = 300;
private static final int DIRECT_HIT_DAMAGE = 8;
private static final float LINGER_RADIUS = 1.65F;
private boolean lingering;
private int lingeringTicks;
public SpitBugProjectileEntity(EntityType<? extends SpitBugProjectileEntity> entityType, Level level) {
super(entityType, level);
}
public SpitBugProjectileEntity(EntityType<? extends SpitBugProjectileEntity> entityType, LivingEntity owner, Level level) {
super(entityType, owner, level);
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
builder.define(LINGERING, false);
}
@Override
protected Item getDefaultItem() {
return Items.SLIME_BALL;
}
@Override
protected double getDefaultGravity() {
return 0.03D;
}
@Override
public boolean canBeCollidedWith() {
return false;
}
@Override
public boolean isAttackable() {
return false;
}
public boolean isLingering() {
return this.entityData.get(LINGERING);
}
public float getRenderScale(float partialTick) {
if (!this.isLingering()) {
return 0.65F;
}
float progress = Math.min(1.0F, (this.lingeringTicks + partialTick) / 8.0F);
return 0.6F + progress * 0.5F;
}
@Override
public void tick() {
if (this.isLingering()) {
this.tickLingering();
return;
}
super.tick();
if (this.tickCount > MAX_FLIGHT_TICKS) {
this.discard();
return;
}
if (this.level().isClientSide) {
this.level().addParticle(ParticleTypes.ITEM_SLIME, this.getX(), this.getY(), this.getZ(), 0.0D, 0.0D, 0.0D);
}
}
private void tickLingering() {
this.lingeringTicks++;
this.setDeltaMovement(Vec3.ZERO);
if (this.level().isClientSide) {
double radius = 0.4D + this.random.nextDouble() * 0.45D;
this.level().addParticle(
ParticleTypes.ITEM_SLIME,
this.getX() + (this.random.nextDouble() - 0.5D) * radius,
this.getY() + 0.04D,
this.getZ() + (this.random.nextDouble() - 0.5D) * radius,
0.0D,
0.0D,
0.0D
);
return;
}
if (this.lingeringTicks % 4 == 0) {
this.applyLingeringSpit();
}
if (this.lingeringTicks >= LINGER_DURATION_TICKS) {
this.discard();
}
}
private void applyLingeringSpit() {
for (LivingEntity target : this.level().getEntitiesOfClass(
LivingEntity.class,
this.getBoundingBox().inflate(LINGER_RADIUS, 0.6D, LINGER_RADIUS),
entity -> entity.isAlive() && entity != this.getOwner()
)) {
target.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 30, 3, false, true, true));
target.makeStuckInBlock(Blocks.HONEY_BLOCK.defaultBlockState(), new Vec3(0.2D, 0.0D, 0.2D));
}
if (this.level() instanceof ServerLevel serverLevel) {
serverLevel.sendParticles(ParticleTypes.ITEM_SLIME, this.getX(), this.getY() + 0.05D, this.getZ(), 3, 0.45D, 0.02D, 0.45D, 0.0D);
}
}
@Override
protected void onHitEntity(EntityHitResult result) {
if (!this.level().isClientSide && result.getEntity() instanceof LivingEntity livingTarget) {
Entity owner = this.getOwner();
if (owner instanceof LivingEntity livingOwner) {
livingTarget.hurt(this.damageSources().mobProjectile(this, livingOwner), DIRECT_HIT_DAMAGE);
} else {
livingTarget.hurt(this.damageSources().magic(), DIRECT_HIT_DAMAGE);
}
livingTarget.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 80, 3, false, true, true));
livingTarget.makeStuckInBlock(Blocks.HONEY_BLOCK.defaultBlockState(), new Vec3(0.25D, 0.0D, 0.25D));
}
this.beginLingering(result.getLocation());
}
@Override
protected void onHitBlock(BlockHitResult result) {
this.beginLingering(result.getLocation());
}
private void beginLingering(Vec3 location) {
if (this.isLingering()) {
return;
}
this.lingering = true;
this.entityData.set(LINGERING, true);
this.lingeringTicks = 0;
this.noPhysics = true;
this.setPos(location.x, location.y + 0.05D, location.z);
this.setDeltaMovement(Vec3.ZERO);
}
}
@@ -121,6 +121,7 @@ public class ToreterrorEntity extends Monster implements GeoEntity {
private int shootCooldown; private int shootCooldown;
private int jumpCooldown; private int jumpCooldown;
private int spinCooldown; private int spinCooldown;
private int spinRicochetCooldown;
private boolean jumpLaunched; private boolean jumpLaunched;
private boolean jumpAirborne; private boolean jumpAirborne;
private boolean shockwaveApplied; private boolean shockwaveApplied;
@@ -226,6 +227,7 @@ public class ToreterrorEntity extends Monster implements GeoEntity {
if (this.shootCooldown > 0) this.shootCooldown--; if (this.shootCooldown > 0) this.shootCooldown--;
if (this.jumpCooldown > 0) this.jumpCooldown--; if (this.jumpCooldown > 0) this.jumpCooldown--;
if (this.spinCooldown > 0) this.spinCooldown--; if (this.spinCooldown > 0) this.spinCooldown--;
if (this.spinRicochetCooldown > 0) this.spinRicochetCooldown--;
if (this.jumpShakeTicks > 0) { if (this.jumpShakeTicks > 0) {
this.jumpShakeTicks--; this.jumpShakeTicks--;
if (this.jumpShakeTicks <= 0) { if (this.jumpShakeTicks <= 0) {
@@ -574,6 +576,7 @@ public class ToreterrorEntity extends Monster implements GeoEntity {
return true; return true;
} }
this.playSpinRicochetSound();
this.spinStrafeSign *= -1; this.spinStrafeSign *= -1;
Vec3 bounced = rotateHorizontal(direction, this.spinStrafeSign * 35.0D); Vec3 bounced = rotateHorizontal(direction, this.spinStrafeSign * 35.0D);
if (this.trySpinMoves(bounced, true)) { if (this.trySpinMoves(bounced, true)) {
@@ -589,6 +592,14 @@ public class ToreterrorEntity extends Monster implements GeoEntity {
return this.trySpinMoves(reversedBounce, true); return this.trySpinMoves(reversedBounce, true);
} }
private void playSpinRicochetSound() {
if (this.spinRicochetCooldown > 0) {
return;
}
this.spinRicochetCooldown = 6;
this.playSound(AntarchySoundEvents.TORETERROR_RICOCHET.get(), 1.0F, 0.95F + this.random.nextFloat() * 0.1F);
}
private boolean trySpinMoves(Vec3 baseDirection, boolean bounced) { private boolean trySpinMoves(Vec3 baseDirection, boolean bounced) {
Vec3[] attempts = new Vec3[]{ Vec3[] attempts = new Vec3[]{
baseDirection, baseDirection,
@@ -714,7 +725,7 @@ public class ToreterrorEntity extends Monster implements GeoEntity {
if (!(this.level() instanceof ServerLevel serverLevel)) return; if (!(this.level() instanceof ServerLevel serverLevel)) return;
LivingEntity target = this.getTarget(); LivingEntity target = this.getTarget();
if (target == null) return; if (target == null) return;
this.playSound(AntarchySoundEvents.SQUIDZOOKA_FIRE.get(), 0.8F, 0.9F + this.random.nextFloat() * 0.2F); this.playSound(AntarchySoundEvents.WATER_CANNON_FIRE.get(), 0.8F, 0.9F + this.random.nextFloat() * 0.2F);
Vec3 from = new Vec3(this.getX(), this.getEyeY(), this.getZ()); Vec3 from = new Vec3(this.getX(), this.getEyeY(), this.getZ());
Vec3 to = new Vec3(target.getX(), target.getEyeY(), target.getZ()); Vec3 to = new Vec3(target.getX(), target.getEyeY(), target.getZ());
Vec3 baseVel = calcLaunchVelocity(from, to, 1.5); Vec3 baseVel = calcLaunchVelocity(from, to, 1.5);
@@ -916,6 +927,7 @@ public class ToreterrorEntity extends Monster implements GeoEntity {
ToreterrorEntity.this.spinDirection = target == null ToreterrorEntity.this.spinDirection = target == null
? Vec3.ZERO ? Vec3.ZERO
: ToreterrorEntity.this.horizontalDirectionTo(target.position()); : ToreterrorEntity.this.horizontalDirectionTo(target.position());
ToreterrorEntity.this.playSound(AntarchySoundEvents.TORETERROR_SPIN.get(), 1.1F, 0.95F + ToreterrorEntity.this.random.nextFloat() * 0.1F);
} }
@Override @Override
@@ -6,6 +6,8 @@ import com.craisinlord.antarchy.content.AntarchySoundEvents;
import com.craisinlord.antarchy.content.damage.AntarchyDamageSources; import com.craisinlord.antarchy.content.damage.AntarchyDamageSources;
import com.craisinlord.antarchy.content.entity.MissileSquidEntity; import com.craisinlord.antarchy.content.entity.MissileSquidEntity;
import com.craisinlord.antarchy.content.entity.OctopusBombEntity; import com.craisinlord.antarchy.content.entity.OctopusBombEntity;
import com.craisinlord.antarchy.content.entity.multipart.MultipartEntityOwner;
import com.craisinlord.antarchy.content.entity.multipart.MultipartLayout;
import com.craisinlord.antarchy.content.damage.AntarchyDamageTypes; import com.craisinlord.antarchy.content.damage.AntarchyDamageTypes;
import java.util.List; import java.util.List;
@@ -60,7 +62,7 @@ import software.bernie.geckolib.animation.RawAnimation;
import software.bernie.geckolib.animation.keyframe.event.builtin.AutoPlayingSoundKeyframeHandler; import software.bernie.geckolib.animation.keyframe.event.builtin.AutoPlayingSoundKeyframeHandler;
import software.bernie.geckolib.util.GeckoLibUtil; import software.bernie.geckolib.util.GeckoLibUtil;
public class KrakenEntity extends Monster implements GeoEntity { public class KrakenEntity extends Monster implements GeoEntity, MultipartEntityOwner {
private static final EntityDataAccessor<Integer> ATTACK_STATE = SynchedEntityData.defineId(KrakenEntity.class, EntityDataSerializers.INT); private static final EntityDataAccessor<Integer> ATTACK_STATE = SynchedEntityData.defineId(KrakenEntity.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Boolean> ROARING = SynchedEntityData.defineId(KrakenEntity.class, EntityDataSerializers.BOOLEAN); private static final EntityDataAccessor<Boolean> ROARING = SynchedEntityData.defineId(KrakenEntity.class, EntityDataSerializers.BOOLEAN);
private static final EntityDataAccessor<Boolean> PHASE_TWO = SynchedEntityData.defineId(KrakenEntity.class, EntityDataSerializers.BOOLEAN); private static final EntityDataAccessor<Boolean> PHASE_TWO = SynchedEntityData.defineId(KrakenEntity.class, EntityDataSerializers.BOOLEAN);
@@ -74,8 +76,6 @@ public class KrakenEntity extends Monster implements GeoEntity {
private static final String AGGRO_TRIGGERED_KEY = "AggroTriggered"; private static final String AGGRO_TRIGGERED_KEY = "AggroTriggered";
private static final String GRAB_TARGET_KEY = "GrabTarget"; private static final String GRAB_TARGET_KEY = "GrabTarget";
private static final double BOSS_BAR_RANGE = 40.0D;
private static final int ATTACK_NONE = 0; private static final int ATTACK_NONE = 0;
private static final int ATTACK_GRAB = 1; private static final int ATTACK_GRAB = 1;
private static final int ATTACK_SWING_LEFT = 2; private static final int ATTACK_SWING_LEFT = 2;
@@ -127,6 +127,9 @@ public class KrakenEntity extends Monster implements GeoEntity {
private float orbitDirection = 1.0F; private float orbitDirection = 1.0F;
private boolean stormActive; private boolean stormActive;
@Nullable
private Entity[] multipartParts;
public KrakenEntity(EntityType<? extends Monster> entityType, Level level) { public KrakenEntity(EntityType<? extends Monster> entityType, Level level) {
super(entityType, level); super(entityType, level);
this.moveControl = new FlyingMoveControl(this, 20, true); this.moveControl = new FlyingMoveControl(this, 20, true);
@@ -149,6 +152,22 @@ public class KrakenEntity extends Monster implements GeoEntity {
return level.getFluidState(pos).is(FluidTags.WATER) && level.getFluidState(pos.above()).is(FluidTags.WATER); return level.getFluidState(pos).is(FluidTags.WATER) && level.getFluidState(pos.above()).is(FluidTags.WATER);
} }
@Override
public MultipartLayout antarchy$getMultipartLayout() {
return KrakenMultipartLayout.INSTANCE;
}
@Override
@Nullable
public Entity[] antarchy$getMultipartParts() {
return this.multipartParts;
}
@Override
public void antarchy$setMultipartParts(@Nullable Entity[] parts) {
this.multipartParts = parts;
}
@Override @Override
protected void defineSynchedData(SynchedEntityData.Builder builder) { protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder); super.defineSynchedData(builder);
@@ -242,8 +261,19 @@ public class KrakenEntity extends Monster implements GeoEntity {
LivingEntity target = this.getTarget(); LivingEntity target = this.getTarget();
if ((target == null || !target.isAlive()) && this.tickCount % 10 == 0) { if ((target == null || !target.isAlive()) && this.tickCount % 10 == 0) {
Player nearbyPlayer = this.level().getNearestPlayer(this, BOSS_BAR_RANGE); Player nearbyPlayer = null;
if (nearbyPlayer != null && this.canAttack(nearbyPlayer)) { double nearestHorizontalDistanceSqr = Double.MAX_VALUE;
for (Player player : this.level().getEntitiesOfClass(Player.class, this.getBoundingBox().inflate(this.getBossBarRange(), 192.0D, this.getBossBarRange()))) {
if (!player.isAlive() || !this.canAttack(player) || !this.isWithinBossBarRange(player)) {
continue;
}
double horizontalDistanceSqr = this.horizontalDistanceToSqr(player);
if (horizontalDistanceSqr < nearestHorizontalDistanceSqr) {
nearestHorizontalDistanceSqr = horizontalDistanceSqr;
nearbyPlayer = player;
}
}
if (nearbyPlayer != null) {
this.setTarget(nearbyPlayer); this.setTarget(nearbyPlayer);
target = nearbyPlayer; target = nearbyPlayer;
} }
@@ -922,11 +952,12 @@ public class KrakenEntity extends Monster implements GeoEntity {
return; return;
} }
AABB bossBarArea = this.getBoundingBox().inflate(BOSS_BAR_RANGE, 16.0D, BOSS_BAR_RANGE); double bossBarRange = this.getBossBarRange();
AABB bossBarArea = this.getBoundingBox().inflate(bossBarRange, 192.0D, bossBarRange);
List<ServerPlayer> nearbyPlayers = serverLevel.getEntitiesOfClass( List<ServerPlayer> nearbyPlayers = serverLevel.getEntitiesOfClass(
ServerPlayer.class, ServerPlayer.class,
bossBarArea, bossBarArea,
player -> player.isAlive() && this.distanceToSqr(player) <= BOSS_BAR_RANGE * BOSS_BAR_RANGE player -> player.isAlive() && this.isWithinBossBarRange(player)
); );
for (ServerPlayer player : List.copyOf(this.bossEvent.getPlayers())) { for (ServerPlayer player : List.copyOf(this.bossEvent.getPlayers())) {
@@ -944,6 +975,21 @@ public class KrakenEntity extends Monster implements GeoEntity {
this.setKrakenStormActive(!nearbyPlayers.isEmpty()); this.setKrakenStormActive(!nearbyPlayers.isEmpty());
} }
private double getBossBarRange() {
return Math.max(40.0D, com.craisinlord.antarchy.config.AntarchySettings.krakenBossBarRange());
}
private boolean isWithinBossBarRange(Entity entity) {
double bossBarRange = this.getBossBarRange();
return this.horizontalDistanceToSqr(entity) <= bossBarRange * bossBarRange;
}
private double horizontalDistanceToSqr(Entity entity) {
double dx = this.getX() - entity.getX();
double dz = this.getZ() - entity.getZ();
return dx * dx + dz * dz;
}
private void applyPhaseTwoBuffs() { private void applyPhaseTwoBuffs() {
AttributeInstance movementSpeed = this.getAttribute(Attributes.MOVEMENT_SPEED); AttributeInstance movementSpeed = this.getAttribute(Attributes.MOVEMENT_SPEED);
if (movementSpeed != null && !movementSpeed.hasModifier(PHASE_TWO_SPEED_ID)) { if (movementSpeed != null && !movementSpeed.hasModifier(PHASE_TWO_SPEED_ID)) {
@@ -6,43 +6,67 @@ import com.craisinlord.antarchy.content.entity.multipart.MultipartPartDefinition
public final class KrakenMultipartLayout implements MultipartLayout { public final class KrakenMultipartLayout implements MultipartLayout {
public static final KrakenMultipartLayout INSTANCE = new KrakenMultipartLayout(); public static final KrakenMultipartLayout INSTANCE = new KrakenMultipartLayout();
public static final MultipartPartDefinition TENTACLE_MASS = new MultipartPartDefinition(
"tentacle_mass",
7.5F,
14.0F,
0.90F,
-0.35D,
14.00D,
0.00D,
true
);
public static final MultipartPartDefinition HEAD = new MultipartPartDefinition( public static final MultipartPartDefinition HEAD = new MultipartPartDefinition(
"head", "head",
3.0F, 9.0F,
2.8F, 4.0F,
1.00F, 1.00F,
2.15D, 1.50D,
5.35D, 28.00D,
0.00D, 0.00D,
true true
); );
public static final MultipartPartDefinition BACK_HEAD = new MultipartPartDefinition( public static final MultipartPartDefinition BACK_HEAD = new MultipartPartDefinition(
"back_head", "back_head",
4.8F, 5.5F,
4.4F, 4.5F,
1.10F, 1.10F,
0.70D, 0.70D,
6.55D, 31.00D,
0.00D, 0.00D,
true true
); );
public static final MultipartPartDefinition TENTACLE_MASS = new MultipartPartDefinition( public static final MultipartPartDefinition MANTLE = new MultipartPartDefinition(
"tentacle_mass", "mantle",
8.5F, 8.0F,
3.4F, 7.0F,
0.90F, 1.00F,
-0.35D, 0.60D,
1.70D, 34.50D,
0.00D,
true
);
public static final MultipartPartDefinition CREST = new MultipartPartDefinition(
"crest",
4.5F,
4.0F,
1.10F,
0.55D,
41.50D,
0.00D, 0.00D,
true true
); );
private static final MultipartPartDefinition[] PARTS = { private static final MultipartPartDefinition[] PARTS = {
TENTACLE_MASS,
HEAD, HEAD,
BACK_HEAD, BACK_HEAD,
TENTACLE_MASS MANTLE,
CREST
}; };
private KrakenMultipartLayout() { private KrakenMultipartLayout() {
@@ -7,6 +7,9 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
public final class MultipartFramework { public final class MultipartFramework {
private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(MultipartFramework.class);
private static boolean warnedMissingFactory;
public interface PartFactory { public interface PartFactory {
Entity create(MultipartEntityOwner owner, int partIndex, MultipartPartDefinition spec); Entity create(MultipartEntityOwner owner, int partIndex, MultipartPartDefinition spec);
} }
@@ -30,7 +33,6 @@ public final class MultipartFramework {
@Nullable @Nullable
private static PartFactory partFactory; private static PartFactory partFactory;
private static NetworkBridge networkBridge = NOOP_BRIDGE; private static NetworkBridge networkBridge = NOOP_BRIDGE;
private MultipartFramework() { private MultipartFramework() {
} }
@@ -43,6 +45,15 @@ public final class MultipartFramework {
} }
public static Entity[] createMultipartParts(MultipartEntityOwner owner) { public static Entity[] createMultipartParts(MultipartEntityOwner owner) {
if (partFactory == null) {
if (!warnedMissingFactory) {
warnedMissingFactory = true;
LOGGER.warn("Multipart part factory has not been bootstrapped on this platform; "
+ "multipart entities will fall back to their base hitbox only");
}
return new Entity[0];
}
MultipartLayout layout = owner.antarchy$getMultipartLayout(); MultipartLayout layout = owner.antarchy$getMultipartLayout();
MultipartPartDefinition[] parts = layout.parts(); MultipartPartDefinition[] parts = layout.parts();
Entity[] created = new Entity[parts.length]; Entity[] created = new Entity[parts.length];
@@ -65,8 +65,8 @@ public class WaterCannonItem extends ProjectileWeaponItem implements GeoItem {
if (usedTicks % FIRE_INTERVAL_TICKS != 0) return; if (usedTicks % FIRE_INTERVAL_TICKS != 0) return;
level.playSound(null, player.getX(), player.getY(), player.getZ(), level.playSound(null, player.getX(), player.getY(), player.getZ(),
AntarchySoundEvents.SQUIDZOOKA_FIRE.get(), SoundSource.PLAYERS, AntarchySoundEvents.WATER_CANNON_FIRE.get(), SoundSource.PLAYERS,
0.8F, 0.9F + level.getRandom().nextFloat() * 0.2F); 0.22F, 0.9F + level.getRandom().nextFloat() * 0.2F);
if (!level.isClientSide()) { if (!level.isClientSide()) {
WaterBombEntity bomb = new WaterBombEntity(level, player); WaterBombEntity bomb = new WaterBombEntity(level, player);
@@ -0,0 +1,20 @@
package com.craisinlord.antarchy.content.network;
import com.craisinlord.antarchy.Antarchy;
import io.netty.buffer.ByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
/** C2S: the rider pressed the roll keybind — toggle the rolly polly's wheel mode. */
public record RollyPollyRollPayload() implements CustomPacketPayload {
public static final Type<RollyPollyRollPayload> TYPE =
new Type<>(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "rolly_polly_roll"));
public static final StreamCodec<ByteBuf, RollyPollyRollPayload> STREAM_CODEC =
StreamCodec.unit(new RollyPollyRollPayload());
@Override
public Type<RollyPollyRollPayload> type() {
return TYPE;
}
}
@@ -0,0 +1,146 @@
package com.craisinlord.antarchy.content.portal;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.Entity;
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 org.jetbrains.annotations.Nullable;
public final class PermanentPortalManager {
private static final int TELEPORT_DELAY_TICKS = 20;
private static final int ACTIVATION_SEARCH_RADIUS = 2;
private static final Map<UUID, PortalWarmup> WARMUPS = new HashMap<>();
private PermanentPortalManager() {
}
public static void handleSacrifice(LivingEntity entity) {
PermanentPortalType type = PermanentPortalType.fromSacrifice(entity);
if (type == null || !(entity.level() instanceof ServerLevel serverLevel)) {
return;
}
PermanentPortalShape shape = findInactiveShape(serverLevel, entity.getBoundingBox(), type);
if (shape == null) {
return;
}
activatePortal(serverLevel, type, shape, SoundEvents.END_PORTAL_SPAWN, 0.9F, 0.9F);
}
public static boolean tryIgnitePortal(Level level, BlockPos triggerPos, PermanentPortalType type) {
PermanentPortalShape shape = PermanentPortalShape.findInactiveNear(level, triggerPos, type);
if (shape == null) {
return false;
}
if (level instanceof ServerLevel serverLevel) {
activatePortal(serverLevel, type, shape, SoundEvents.FLINTANDSTEEL_USE, 0.9F, 1.0F);
}
return true;
}
public static void handleEntityInsidePortal(Entity entity, PermanentPortalType type) {
if (!(entity.level() instanceof ServerLevel serverLevel) || !type.isEnabled() || entity.isPassenger() || entity.isVehicle()) {
return;
}
if (entity.isOnPortalCooldown()) {
WARMUPS.remove(entity.getUUID());
return;
}
long gameTime = serverLevel.getGameTime();
PortalWarmup warmup = WARMUPS.computeIfAbsent(entity.getUUID(), ignored -> new PortalWarmup());
if (warmup.type != type || warmup.lastSeenTick < gameTime - 1) {
warmup.ticks = 0;
}
warmup.type = type;
if (warmup.lastSeenTick != gameTime) {
warmup.ticks++;
warmup.lastSeenTick = gameTime;
}
if (warmup.ticks < TELEPORT_DELAY_TICKS) {
return;
}
WARMUPS.remove(entity.getUUID());
PermanentPortalTeleporter.teleport(entity, type);
if (entity.level() instanceof ServerLevel currentLevel) {
currentLevel.playSound(null, entity.getX(), entity.getY(), entity.getZ(), SoundEvents.PORTAL_TRAVEL, SoundSource.PLAYERS, 0.8F, 1.0F);
}
}
public static boolean isPortalStillValid(ServerLevel level, BlockPos pos, PermanentPortalType type, Direction.Axis axis) {
PermanentPortalShape shape = PermanentPortalShape.findActive(level, pos, type, axis);
return shape != null && shape.contains(pos);
}
@Nullable
private static PermanentPortalShape findInactiveShape(ServerLevel level, AABB bounds, PermanentPortalType type) {
int minX = (int) Math.floor(bounds.minX + 0.001D) - ACTIVATION_SEARCH_RADIUS;
int minY = (int) Math.floor(bounds.minY + 0.001D) - ACTIVATION_SEARCH_RADIUS;
int minZ = (int) Math.floor(bounds.minZ + 0.001D) - ACTIVATION_SEARCH_RADIUS;
int maxX = (int) Math.floor(bounds.maxX - 0.001D) + ACTIVATION_SEARCH_RADIUS;
int maxY = (int) Math.floor(bounds.maxY - 0.001D) + ACTIVATION_SEARCH_RADIUS;
int maxZ = (int) Math.floor(bounds.maxZ - 0.001D) + ACTIVATION_SEARCH_RADIUS;
for (int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) {
for (int z = minZ; z <= maxZ; z++) {
BlockPos candidate = new BlockPos(x, y, z);
PermanentPortalShape xShape = PermanentPortalShape.findInactive(level, candidate, type, Direction.Axis.X);
if (xShape != null && xShape.intersects(bounds)) {
return xShape;
}
PermanentPortalShape zShape = PermanentPortalShape.findInactive(level, candidate, type, Direction.Axis.Z);
if (zShape != null && zShape.intersects(bounds)) {
return zShape;
}
}
}
}
return null;
}
private static void spawnActivationParticles(ServerLevel level, PermanentPortalType type, Vec3 center) {
switch (type) {
case ELYTHIA -> {
level.sendParticles(ParticleTypes.SPORE_BLOSSOM_AIR, center.x, center.y, center.z, 24, 0.8D, 1.2D, 0.8D, 0.02D);
level.sendParticles(ParticleTypes.HAPPY_VILLAGER, center.x, center.y, center.z, 12, 0.6D, 1.0D, 0.6D, 0.02D);
}
case THORAXIS -> {
level.sendParticles(ParticleTypes.PORTAL, center.x, center.y, center.z, 32, 0.8D, 1.2D, 0.8D, 0.15D);
level.sendParticles(ParticleTypes.REVERSE_PORTAL, center.x, center.y, center.z, 10, 0.5D, 0.8D, 0.5D, 0.01D);
}
case CAVARYN -> {
level.sendParticles(ParticleTypes.MYCELIUM, center.x, center.y, center.z, 24, 0.8D, 1.2D, 0.8D, 0.01D);
level.sendParticles(ParticleTypes.FALLING_SPORE_BLOSSOM, center.x, center.y, center.z, 16, 0.6D, 1.0D, 0.6D, 0.01D);
}
}
}
private static void activatePortal(ServerLevel level, PermanentPortalType type, PermanentPortalShape shape, net.minecraft.sounds.SoundEvent sound, float volume, float pitch) {
shape.fill(level);
Vec3 center = shape.center();
level.playSound(null, center.x, center.y, center.z, sound, SoundSource.BLOCKS, volume, pitch);
spawnActivationParticles(level, type, center);
}
private static final class PortalWarmup {
private PermanentPortalType type;
private long lastSeenTick;
private int ticks;
}
}
@@ -0,0 +1,297 @@
package com.craisinlord.antarchy.content.portal;
import java.util.function.Consumer;
import java.util.function.Predicate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
public final class PermanentPortalShape {
public static final int MIN_WIDTH = 2;
public static final int MIN_HEIGHT = 3;
public static final int MAX_SIZE = 21;
public static final int ACTIVE_SEARCH_RADIUS = 24;
private final PermanentPortalType type;
private final Direction.Axis axis;
private final BlockPos bottomLeft;
private final int width;
private final int height;
private PermanentPortalShape(PermanentPortalType type, Direction.Axis axis, BlockPos bottomLeft, int width, int height) {
this.type = type;
this.axis = axis;
this.bottomLeft = bottomLeft;
this.width = width;
this.height = height;
}
@Nullable
public static PermanentPortalShape findInactive(BlockGetter level, BlockPos interiorPos, PermanentPortalType type, Direction.Axis axis) {
return find(level, interiorPos, type, axis, state -> state.isAir());
}
@Nullable
public static PermanentPortalShape findInactiveNear(BlockGetter level, BlockPos center, PermanentPortalType type) {
for (int x = center.getX() - 2; x <= center.getX() + 2; x++) {
for (int y = center.getY() - 2; y <= center.getY() + 2; y++) {
for (int z = center.getZ() - 2; z <= center.getZ() + 2; z++) {
BlockPos candidate = new BlockPos(x, y, z);
PermanentPortalShape xShape = findInactive(level, candidate, type, Direction.Axis.X);
if (xShape != null) {
return xShape;
}
PermanentPortalShape zShape = findInactive(level, candidate, type, Direction.Axis.Z);
if (zShape != null) {
return zShape;
}
}
}
}
return null;
}
@Nullable
public static PermanentPortalShape findActive(BlockGetter level, BlockPos interiorPos, PermanentPortalType type, Direction.Axis axis) {
Block portalBlock = type.portalBlock();
return find(level, interiorPos, type, axis, state -> state.is(portalBlock));
}
@Nullable
public static PermanentPortalShape findActiveNear(BlockGetter level, BlockPos center, PermanentPortalType type) {
for (int x = center.getX() - ACTIVE_SEARCH_RADIUS; x <= center.getX() + ACTIVE_SEARCH_RADIUS; x++) {
for (int y = center.getY() - ACTIVE_SEARCH_RADIUS; y <= center.getY() + ACTIVE_SEARCH_RADIUS; y++) {
for (int z = center.getZ() - ACTIVE_SEARCH_RADIUS; z <= center.getZ() + ACTIVE_SEARCH_RADIUS; z++) {
BlockPos candidate = new BlockPos(x, y, z);
PermanentPortalShape xShape = findActive(level, candidate, type, Direction.Axis.X);
if (xShape != null) {
return xShape;
}
PermanentPortalShape zShape = findActive(level, candidate, type, Direction.Axis.Z);
if (zShape != null) {
return zShape;
}
}
}
}
return null;
}
@Nullable
private static PermanentPortalShape find(
BlockGetter level,
BlockPos interiorPos,
PermanentPortalType type,
Direction.Axis axis,
Predicate<BlockState> interiorPredicate
) {
if (axis == Direction.Axis.Y || !interiorPredicate.test(level.getBlockState(interiorPos))) {
return null;
}
Direction widthDirection = axis == Direction.Axis.X ? Direction.EAST : Direction.SOUTH;
Direction leftDirection = widthDirection.getOpposite();
BlockPos cursor = interiorPos;
for (int i = 0; i < MAX_SIZE && interiorPredicate.test(level.getBlockState(cursor.below())); i++) {
cursor = cursor.below();
}
for (int i = 0; i < MAX_SIZE && interiorPredicate.test(level.getBlockState(cursor.relative(leftDirection))); i++) {
cursor = cursor.relative(leftDirection);
}
int width = measureWidth(level, cursor, widthDirection, type.frameTag(), interiorPredicate);
if (width < MIN_WIDTH) {
return null;
}
int height = measureHeight(level, cursor, widthDirection, width, type.frameTag(), interiorPredicate);
if (height < MIN_HEIGHT) {
return null;
}
return new PermanentPortalShape(type, axis, cursor.immutable(), width, height);
}
private static int measureWidth(
BlockGetter level,
BlockPos bottomLeft,
Direction widthDirection,
TagKey<Block> frameTag,
Predicate<BlockState> interiorPredicate
) {
if (!level.getBlockState(bottomLeft.relative(widthDirection.getOpposite())).is(frameTag)) {
return 0;
}
int width = 0;
while (width < MAX_SIZE && interiorPredicate.test(level.getBlockState(bottomLeft.relative(widthDirection, width)))) {
if (!level.getBlockState(bottomLeft.relative(widthDirection, width).below()).is(frameTag)) {
return 0;
}
width++;
}
if (width < MIN_WIDTH || width > MAX_SIZE) {
return 0;
}
return level.getBlockState(bottomLeft.relative(widthDirection, width)).is(frameTag) ? width : 0;
}
private static int measureHeight(
BlockGetter level,
BlockPos bottomLeft,
Direction widthDirection,
int width,
TagKey<Block> frameTag,
Predicate<BlockState> interiorPredicate
) {
BlockPos leftFrameBase = bottomLeft.relative(widthDirection.getOpposite());
BlockPos rightFrameBase = bottomLeft.relative(widthDirection, width);
for (int height = 0; height < MAX_SIZE; height++) {
if (!level.getBlockState(leftFrameBase.above(height)).is(frameTag)
|| !level.getBlockState(rightFrameBase.above(height)).is(frameTag)) {
return 0;
}
for (int x = 0; x < width; x++) {
BlockPos interiorPos = bottomLeft.relative(widthDirection, x).above(height);
if (!interiorPredicate.test(level.getBlockState(interiorPos))) {
if (height < MIN_HEIGHT) {
return 0;
}
return hasTopFrame(level, bottomLeft, widthDirection, width, height, frameTag) ? height : 0;
}
}
}
return hasTopFrame(level, bottomLeft, widthDirection, width, MAX_SIZE, frameTag) ? MAX_SIZE : 0;
}
private static boolean hasTopFrame(
BlockGetter level,
BlockPos bottomLeft,
Direction widthDirection,
int width,
int topY,
TagKey<Block> frameTag
) {
for (int x = 0; x < width; x++) {
if (!level.getBlockState(bottomLeft.relative(widthDirection, x).above(topY)).is(frameTag)) {
return false;
}
}
return true;
}
public void fill(ServerLevel level) {
BlockState portalState = this.type.portalBlock().defaultBlockState().setValue(BlockStateProperties.HORIZONTAL_AXIS, this.axis);
this.forEachInterior(pos -> level.setBlock(pos, portalState, Block.UPDATE_ALL));
}
@Nullable
public static PermanentPortalShape create(ServerLevel level, BlockPos bottomLeft, PermanentPortalType type, Direction.Axis axis) {
if (axis == Direction.Axis.Y || !canCreate(level, bottomLeft, type, axis)) {
return null;
}
BlockState frameState = type.platformBlock().defaultBlockState();
BlockState portalState = type.portalBlock().defaultBlockState().setValue(BlockStateProperties.HORIZONTAL_AXIS, axis);
Direction widthDirection = axis == Direction.Axis.X ? Direction.EAST : Direction.SOUTH;
for (int y = -1; y <= 3; y++) {
for (int x = -1; x <= 2; x++) {
BlockPos pos = bottomLeft.relative(widthDirection, x).above(y);
boolean cornerSpot = (x == -1 || x == 2) && (y == -1 || y == 3);
if (cornerSpot) {
continue;
}
if (x == -1 || x == 2 || y == -1 || y == 3) {
level.setBlock(pos, frameState, Block.UPDATE_ALL);
} else {
level.setBlock(pos, portalState, Block.UPDATE_ALL);
}
}
}
return new PermanentPortalShape(type, axis, bottomLeft.immutable(), 2, 3);
}
private static boolean canCreate(BlockGetter level, BlockPos bottomLeft, PermanentPortalType type, Direction.Axis axis) {
Direction widthDirection = axis == Direction.Axis.X ? Direction.EAST : Direction.SOUTH;
Block frameBlock = type.platformBlock();
for (int y = -1; y <= 3; y++) {
for (int x = -1; x <= 2; x++) {
BlockPos pos = bottomLeft.relative(widthDirection, x).above(y);
BlockState state = level.getBlockState(pos);
boolean frameSpot = x == -1 || x == 2 || y == -1 || y == 3;
boolean cornerSpot = (x == -1 || x == 2) && (y == -1 || y == 3);
if (cornerSpot) {
continue;
}
if (frameSpot) {
if (!state.isAir() && !state.is(frameBlock) && !state.canBeReplaced()) {
return false;
}
} else if (!state.isAir() && !state.canBeReplaced() && !state.is(Blocks.AIR)) {
return false;
}
}
}
return true;
}
public boolean contains(BlockPos pos) {
if (pos.getY() < this.bottomLeft.getY() || pos.getY() >= this.bottomLeft.getY() + this.height) {
return false;
}
if (this.axis == Direction.Axis.X) {
return pos.getZ() == this.bottomLeft.getZ()
&& pos.getX() >= this.bottomLeft.getX()
&& pos.getX() < this.bottomLeft.getX() + this.width;
}
return pos.getX() == this.bottomLeft.getX()
&& pos.getZ() >= this.bottomLeft.getZ()
&& pos.getZ() < this.bottomLeft.getZ() + this.width;
}
public boolean intersects(AABB box) {
final boolean[] intersects = {false};
this.forEachInterior(pos -> {
if (box.intersects(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1.0D, pos.getY() + 1.0D, pos.getZ() + 1.0D)) {
intersects[0] = true;
}
});
return intersects[0];
}
public void forEachInterior(Consumer<BlockPos> consumer) {
Direction widthDirection = this.axis == Direction.Axis.X ? Direction.EAST : Direction.SOUTH;
for (int y = 0; y < this.height; y++) {
for (int x = 0; x < this.width; x++) {
consumer.accept(this.bottomLeft.relative(widthDirection, x).above(y));
}
}
}
public Vec3 center() {
if (this.axis == Direction.Axis.X) {
return new Vec3(this.bottomLeft.getX() + (this.width / 2.0D), this.bottomLeft.getY() + (this.height / 2.0D), this.bottomLeft.getZ() + 0.5D);
}
return new Vec3(this.bottomLeft.getX() + 0.5D, this.bottomLeft.getY() + (this.height / 2.0D), this.bottomLeft.getZ() + (this.width / 2.0D));
}
}
@@ -0,0 +1,285 @@
package com.craisinlord.antarchy.content.portal;
import com.craisinlord.antarchy.config.AntarchySettings;
import java.util.LinkedHashSet;
import java.util.Set;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.vehicle.DismountHelper;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.portal.DimensionTransition;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
public final class PermanentPortalTeleporter {
private static final int SEARCH_RADIUS = 24;
private static final int VERTICAL_SEARCH = 24;
private static final int EXISTING_PORTAL_SEARCH_RADIUS = 48;
private PermanentPortalTeleporter() {
}
public static void teleport(Entity entity, PermanentPortalType type) {
if (!(entity.level() instanceof ServerLevel sourceLevel) || !entity.isAlive()) {
return;
}
DimensionTransition transition = createTransition(sourceLevel, entity, entity.blockPosition(), type);
Entity movedEntity = moveEntity(entity, transition);
if (movedEntity != null) {
movedEntity.setPortalCooldown();
}
}
public static DimensionTransition createTransition(ServerLevel sourceLevel, Entity entity, BlockPos portalPos, PermanentPortalType type) {
ServerLevel destination = resolveDestination(sourceLevel, type);
if (destination == null) {
return new DimensionTransition(sourceLevel, entity, DimensionTransition.DO_NOTHING);
}
Vec3 arrival = findArrivalPosition(entity, destination, portalPos, type);
return new DimensionTransition(destination, arrival, Vec3.ZERO, entity.getYRot(), entity.getXRot(), DimensionTransition.PLAY_PORTAL_SOUND);
}
@Nullable
private static ServerLevel resolveDestination(ServerLevel sourceLevel, PermanentPortalType type) {
if (sourceLevel.dimension() == type.primaryDimension()) {
return sourceLevel.getServer().overworld();
}
return sourceLevel.getServer().getLevel(type.primaryDimension());
}
private static Vec3 findArrivalPosition(Entity entity, ServerLevel destination, BlockPos preferredPos, PermanentPortalType type) {
PermanentPortalShape active = PermanentPortalShape.findActiveNear(destination, preferredPos, type);
if (active != null) {
return active.center();
}
Vec3 safe = findSafeArrivalPosition(entity, destination, preferredPos);
if (safe != null) {
PermanentPortalShape nearbyActive = findActiveNearby(destination, BlockPos.containing(safe), type);
if (nearbyActive != null) {
return nearbyActive.center();
}
PermanentPortalShape created = createReturnPortal(destination, safe, type);
if (created != null) {
return created.center();
}
return safe;
}
return createFallbackPlatform(destination, preferredPos, type.platformBlock().defaultBlockState());
}
@Nullable
private static PermanentPortalShape findActiveNearby(ServerLevel level, BlockPos center, PermanentPortalType type) {
for (int radius = 0; radius <= EXISTING_PORTAL_SEARCH_RADIUS; radius++) {
for (int xOff = -radius; xOff <= radius; xOff++) {
for (int yOff = -radius; yOff <= radius; yOff++) {
for (int zOff = -radius; zOff <= radius; zOff++) {
if (radius > 0 && Math.abs(xOff) != radius && Math.abs(yOff) != radius && Math.abs(zOff) != radius) {
continue;
}
BlockPos candidate = center.offset(xOff, yOff, zOff);
PermanentPortalShape xShape = PermanentPortalShape.findActive(level, candidate, type, Direction.Axis.X);
if (xShape != null) {
return xShape;
}
PermanentPortalShape zShape = PermanentPortalShape.findActive(level, candidate, type, Direction.Axis.Z);
if (zShape != null) {
return zShape;
}
}
}
}
}
return null;
}
@Nullable
private static Vec3 findSafeArrivalPosition(Entity entity, ServerLevel destination, BlockPos preferredPos) {
int[] yRange = getDimensionYRange(destination);
if (yRange != null) {
return findSafeArrivalPositionInYRange(entity, destination, preferredPos, yRange[0], yRange[1]);
}
Set<BlockPos> candidates = new LinkedHashSet<>();
addCandidate(candidates, preferredPos);
for (int radius = 0; radius <= SEARCH_RADIUS; radius++) {
for (int xOff = -radius; xOff <= radius; xOff++) {
for (int zOff = -radius; zOff <= radius; zOff++) {
if (radius > 0 && Math.abs(xOff) != radius && Math.abs(zOff) != radius) {
continue;
}
BlockPos horizontalPos = preferredPos.offset(xOff, 0, zOff);
addCandidate(candidates, destination.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, horizontalPos));
addCandidate(candidates, destination.getHeightmapPos(Heightmap.Types.WORLD_SURFACE, horizontalPos));
for (int yOff = 0; yOff <= VERTICAL_SEARCH; yOff++) {
addCandidate(candidates, horizontalPos.above(yOff));
if (yOff > 0) {
addCandidate(candidates, horizontalPos.below(yOff));
}
}
}
}
}
for (BlockPos candidate : candidates) {
Vec3 safe = tryFindSafePosition(entity, destination, candidate);
if (safe != null) {
return safe;
}
}
return null;
}
@Nullable
private static Vec3 findSafeArrivalPositionInYRange(Entity entity, ServerLevel destination, BlockPos preferredPos, int minY, int maxY) {
for (int radius = 0; radius <= SEARCH_RADIUS; radius++) {
for (int xOff = -radius; xOff <= radius; xOff++) {
for (int zOff = -radius; zOff <= radius; zOff++) {
if (radius > 0 && Math.abs(xOff) != radius && Math.abs(zOff) != radius) {
continue;
}
int x = preferredPos.getX() + xOff;
int z = preferredPos.getZ() + zOff;
for (int y = maxY; y >= minY + 1; y--) {
Vec3 safePos = tryFindSafePosition(entity, destination, new BlockPos(x, y, z));
if (safePos != null && safePos.y >= minY && safePos.y <= maxY) {
return safePos;
}
}
}
}
}
return null;
}
private static void addCandidate(Set<BlockPos> candidates, @Nullable BlockPos pos) {
if (pos == null) {
return;
}
candidates.add(pos);
candidates.add(pos.above());
if (pos.getY() > Integer.MIN_VALUE) {
candidates.add(pos.below());
}
}
@Nullable
private static Vec3 tryFindSafePosition(Entity entity, ServerLevel destination, BlockPos candidate) {
Vec3 safe = DismountHelper.findSafeDismountLocation(entity.getType(), destination, candidate, true);
if (safe != null && isValidArrivalPosition(destination, safe)) {
return safe;
}
for (Direction direction : Direction.Plane.HORIZONTAL) {
safe = DismountHelper.findSafeDismountLocation(entity.getType(), destination, candidate.relative(direction), true);
if (safe != null && isValidArrivalPosition(destination, safe)) {
return safe;
}
}
return null;
}
private static Vec3 createFallbackPlatform(ServerLevel destination, BlockPos preferredPos, BlockState platformState) {
int minY = destination.getMinBuildHeight() + 2;
int maxY = destination.getMaxBuildHeight() - 4;
BlockPos center = new BlockPos(preferredPos.getX(), Mth.clamp(preferredPos.getY(), minY, maxY), preferredPos.getZ());
for (int dx = -1; dx <= 1; dx++) {
for (int dz = -1; dz <= 1; dz++) {
destination.setBlock(center.offset(dx, -1, dz), platformState, Block.UPDATE_ALL);
destination.removeBlock(center.offset(dx, 0, dz), false);
destination.removeBlock(center.offset(dx, 1, dz), false);
}
}
return Vec3.atBottomCenterOf(center);
}
@Nullable
private static PermanentPortalShape createReturnPortal(ServerLevel destination, Vec3 safePos, PermanentPortalType type) {
BlockPos preferred = BlockPos.containing(safePos);
int minY = destination.getMinBuildHeight() + 2;
int maxY = destination.getMaxBuildHeight() - 4;
int clampedY = Mth.clamp(preferred.getY(), minY, maxY);
for (int radius = 0; radius <= 4; radius++) {
for (int xOff = -radius; xOff <= radius; xOff++) {
for (int zOff = -radius; zOff <= radius; zOff++) {
if (radius > 0 && Math.abs(xOff) != radius && Math.abs(zOff) != radius) {
continue;
}
BlockPos anchor = new BlockPos(preferred.getX() + xOff, clampedY, preferred.getZ() + zOff);
PermanentPortalShape xShape = PermanentPortalShape.create(destination, anchor, type, Direction.Axis.X);
if (xShape != null) {
return xShape;
}
PermanentPortalShape zShape = PermanentPortalShape.create(destination, anchor, type, Direction.Axis.Z);
if (zShape != null) {
return zShape;
}
}
}
}
return null;
}
@Nullable
private static int[] getDimensionYRange(ServerLevel destination) {
ResourceKey<Level> dim = destination.dimension();
if (dim == AntarchySettings.termiteDestinationDimension()) {
return new int[]{100, 200};
}
if (dim == AntarchySettings.brownAntDestinationDimension()) {
return new int[]{75, 120};
}
return null;
}
private static boolean isValidArrivalPosition(ServerLevel destination, Vec3 safePos) {
BlockPos standPos = BlockPos.containing(safePos);
if (destination.dimension() == AntarchySettings.termiteDestinationDimension()
|| destination.dimension() == AntarchySettings.redAntDestinationDimension()) {
return !destination.getBlockState(standPos.below()).is(net.minecraft.world.level.block.Blocks.BEDROCK);
}
return true;
}
@Nullable
private static Entity moveEntity(Entity entity, DimensionTransition transition) {
ServerLevel destination = transition.newLevel();
Vec3 destinationPos = transition.pos();
if (entity instanceof ServerPlayer player) {
player.teleportTo(destination, destinationPos.x, destinationPos.y, destinationPos.z, player.getYRot(), player.getXRot());
return player;
}
if (entity.level() == destination) {
entity.teleportTo(destinationPos.x, destinationPos.y, destinationPos.z);
return entity;
}
return entity.changeDimension(transition);
}
}
@@ -0,0 +1,111 @@
package com.craisinlord.antarchy.content.portal;
import com.craisinlord.antarchy.content.AntarchyTags;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.entity.ant.BrownAntEntity;
import com.craisinlord.antarchy.content.entity.ant.RedAntEntity;
import com.craisinlord.antarchy.content.entity.ant.TermiteEntity;
import java.util.Objects;
import java.util.function.Supplier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import org.jetbrains.annotations.Nullable;
public enum PermanentPortalType {
ELYTHIA("elythia", AntarchySettings::brownAntDestinationDimension, AntarchySettings::elythiaPortalEnabled, AntarchyTags.Blocks.ELYTHIA_PORTAL_FRAMES) {
@Override
boolean matchesSacrifice(LivingEntity entity) {
return entity instanceof BrownAntEntity;
}
},
THORAXIS("thoraxis", AntarchySettings::redAntDestinationDimension, AntarchySettings::thoraxisPortalEnabled, AntarchyTags.Blocks.THORAXIS_PORTAL_FRAMES) {
@Override
boolean matchesSacrifice(LivingEntity entity) {
return entity instanceof RedAntEntity;
}
},
CAVARYN("cavaryn", AntarchySettings::termiteDestinationDimension, AntarchySettings::cavarynPortalEnabled, AntarchyTags.Blocks.CAVARYN_PORTAL_FRAMES) {
@Override
boolean matchesSacrifice(LivingEntity entity) {
return entity instanceof TermiteEntity;
}
};
private final String id;
private final Supplier<ResourceKey<Level>> primaryDimensionSupplier;
private final Supplier<Boolean> enabledSupplier;
private final TagKey<Block> frameTag;
private Supplier<Block> platformBlockSupplier;
private Supplier<Block> portalBlockSupplier;
PermanentPortalType(String id, Supplier<ResourceKey<Level>> primaryDimensionSupplier, Supplier<Boolean> enabledSupplier, TagKey<Block> frameTag) {
this.id = id;
this.primaryDimensionSupplier = primaryDimensionSupplier;
this.enabledSupplier = enabledSupplier;
this.frameTag = frameTag;
}
public static void bindBlocks(
Supplier<Block> elythiaPlatform,
Supplier<Block> elythiaPortal,
Supplier<Block> thoraxisPlatform,
Supplier<Block> thoraxisPortal,
Supplier<Block> cavarynPlatform,
Supplier<Block> cavarynPortal
) {
ELYTHIA.bind(elythiaPlatform, elythiaPortal);
THORAXIS.bind(thoraxisPlatform, thoraxisPortal);
CAVARYN.bind(cavarynPlatform, cavarynPortal);
}
public static boolean portalsEnabled() {
return AntarchySettings.permanentPortalsEnabled();
}
@Nullable
public static PermanentPortalType fromSacrifice(LivingEntity entity) {
if (!portalsEnabled()) {
return null;
}
for (PermanentPortalType type : values()) {
if (type.isEnabled() && type.matchesSacrifice(entity)) {
return type;
}
}
return null;
}
private void bind(Supplier<Block> platformBlockSupplier, Supplier<Block> portalBlockSupplier) {
this.platformBlockSupplier = Objects.requireNonNull(platformBlockSupplier);
this.portalBlockSupplier = Objects.requireNonNull(portalBlockSupplier);
}
public String id() {
return this.id;
}
public boolean isEnabled() {
return portalsEnabled() && this.enabledSupplier.get();
}
public ResourceKey<Level> primaryDimension() {
return this.primaryDimensionSupplier.get();
}
public TagKey<Block> frameTag() {
return this.frameTag;
}
public Block platformBlock() {
return Objects.requireNonNull(this.platformBlockSupplier, "Platform block supplier not bound for " + this.id).get();
}
public Block portalBlock() {
return Objects.requireNonNull(this.portalBlockSupplier, "Portal block supplier not bound for " + this.id).get();
}
abstract boolean matchesSacrifice(LivingEntity entity);
}
@@ -1,10 +1,16 @@
package com.craisinlord.antarchy.content.worldgen.elythia; package com.craisinlord.antarchy.content.worldgen.elythia;
import com.craisinlord.antarchy.content.AntarchyObjects; import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.sizeablefoliage.content.block.BigBushBlock;
import com.craisinlord.sizeablefoliage.content.block.VeryTallGrassBlock;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.BlockTags; import net.minecraft.tags.BlockTags;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
@@ -16,6 +22,8 @@ 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;
public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> { public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
private static final String SIZEABLE_FOLIAGE_MODID = "sizeable_foliage";
private final Variant variant; private final Variant variant;
public ElythiaFloraFeature(Codec<NoneFeatureConfiguration> codec, Variant variant) { public ElythiaFloraFeature(Codec<NoneFeatureConfiguration> codec, Variant variant) {
@@ -29,8 +37,8 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
RandomSource random = context.random(); RandomSource random = context.random();
BlockPos origin = context.origin(); BlockPos origin = context.origin();
int attempts = switch (this.variant) { int attempts = switch (this.variant) {
case FOREST -> 32; case FOREST -> 185;
case MEADOW -> 80; case MEADOW -> 95;
case TORCHFLOWER_FIELDS -> 60; case TORCHFLOWER_FIELDS -> 60;
case BUTTERFLY_FIELDS -> 150; case BUTTERFLY_FIELDS -> 150;
case FLOWER_FOREST_MILKWEED -> 14; case FLOWER_FOREST_MILKWEED -> 14;
@@ -90,6 +98,10 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
placedAny |= this.placeMilkweedPatch(level, origin, random, AntarchyObjects.PINK_MILKWEED.get()); placedAny |= this.placeMilkweedPatch(level, origin, random, AntarchyObjects.PINK_MILKWEED.get());
} }
if (this.variant == Variant.FOREST) {
placedAny |= this.placeBigBushes(level, origin, random, radius);
}
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;
@@ -116,18 +128,15 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
if (this.variant == Variant.TORCHFLOWER_FIELDS) { if (this.variant == Variant.TORCHFLOWER_FIELDS) {
float roll = random.nextFloat(); float roll = random.nextFloat();
if (roll < 0.14F) { if (roll < 0.14F) {
return placeDouble(level, plantPos, AntarchyObjects.TORCHFLOWER_BUSH.get().defaultBlockState()); return placeDouble(level, plantPos, torchflowerBush().defaultBlockState());
} }
if (roll < 0.58F) { if (roll < 0.58F) {
return placeSingle(level, plantPos, Blocks.TORCHFLOWER); return placeSingle(level, plantPos, Blocks.TORCHFLOWER);
} }
if (roll < 0.82F) { if (roll < 0.94F) {
return placeSingle(level, plantPos, Blocks.SHORT_GRASS); return placeSingle(level, plantPos, Blocks.SHORT_GRASS);
} }
if (roll < 0.94F) { return placeDouble(level, plantPos, Blocks.TALL_GRASS.defaultBlockState());
return placeSingle(level, plantPos, Blocks.FERN);
}
return placeDouble(level, plantPos, Blocks.LARGE_FERN.defaultBlockState());
} }
if (this.variant == Variant.BUTTERFLY_FIELDS) { if (this.variant == Variant.BUTTERFLY_FIELDS) {
@@ -138,14 +147,8 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
if (roll < 0.36F) { if (roll < 0.36F) {
return placeDouble(level, plantPos, AntarchyObjects.PINK_MILKWEED.get().defaultBlockState()); return placeDouble(level, plantPos, AntarchyObjects.PINK_MILKWEED.get().defaultBlockState());
} }
if (roll < 0.62F) {
return placeSingle(level, plantPos, Blocks.SHORT_GRASS);
}
if (roll < 0.84F) { if (roll < 0.84F) {
return placeSingle(level, plantPos, Blocks.FERN); return placeSingle(level, plantPos, Blocks.SHORT_GRASS);
}
if (roll < 0.94F) {
return placeDouble(level, plantPos, Blocks.LARGE_FERN.defaultBlockState());
} }
return placeDouble(level, plantPos, Blocks.TALL_GRASS.defaultBlockState()); return placeDouble(level, plantPos, Blocks.TALL_GRASS.defaultBlockState());
} }
@@ -168,16 +171,120 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
} }
float roll = random.nextFloat(); float roll = random.nextFloat();
if (roll < 0.46F) { if (this.variant == Variant.MEADOW) {
if (roll < 0.34F) {
return placeSingle(level, plantPos, Blocks.SHORT_GRASS);
}
if (roll < 0.78F) {
return placeSingle(level, plantPos, veryShortGrass());
}
if (roll < 0.81F) {
return placeDouble(level, plantPos, Blocks.TALL_GRASS.defaultBlockState());
}
return placeSingle(level, plantPos, veryShortGrass());
}
if (roll < 0.14F) {
return placeSingle(level, plantPos, Blocks.SHORT_GRASS); return placeSingle(level, plantPos, Blocks.SHORT_GRASS);
} }
if (roll < 0.84F) { if (roll < 0.52F) {
return placeSingle(level, plantPos, veryShortGrass());
}
if (roll < 0.72F) {
return placeSingle(level, plantPos, Blocks.FERN); return placeSingle(level, plantPos, Blocks.FERN);
} }
if (roll < 0.94F) { if (roll < 0.80F) {
return placeDouble(level, plantPos, Blocks.LARGE_FERN.defaultBlockState()); return placeDouble(level, plantPos, Blocks.TALL_GRASS.defaultBlockState());
} }
return this.variant != Variant.FOREST && random.nextFloat() < 0.4F && isValidGround(level, groundPos) && placeSingle(level, plantPos, Blocks.SHORT_GRASS); if (roll < 0.84F) {
return placeVeryTall(level, plantPos, veryTallGrass());
}
return placeDouble(level, plantPos, Blocks.LARGE_FERN.defaultBlockState());
}
private static Block veryShortGrass() {
Block block = BuiltInRegistries.BLOCK.get(ResourceLocation.fromNamespaceAndPath(SIZEABLE_FOLIAGE_MODID, "very_short_grass"));
return block == Blocks.AIR ? Blocks.SHORT_GRASS : block;
}
private static Block veryTallGrass() {
Block block = BuiltInRegistries.BLOCK.get(ResourceLocation.fromNamespaceAndPath(SIZEABLE_FOLIAGE_MODID, "very_tall_grass"));
return block == Blocks.AIR ? Blocks.TALL_GRASS : block;
}
private static Block torchflowerBush() {
Block block = BuiltInRegistries.BLOCK.get(ResourceLocation.fromNamespaceAndPath(SIZEABLE_FOLIAGE_MODID, "torchflower_bush"));
return block == Blocks.AIR ? Blocks.TORCHFLOWER : block;
}
private boolean placeBigBushes(WorldGenLevel level, BlockPos origin, RandomSource random, int radius) {
Block bushBlock = BuiltInRegistries.BLOCK.get(ResourceLocation.fromNamespaceAndPath(SIZEABLE_FOLIAGE_MODID, "big_bush"));
if (!(bushBlock instanceof BigBushBlock)) {
return false;
}
boolean placed = false;
int bushAttempts = 12 + random.nextInt(7);
for (int i = 0; i < bushAttempts; i++) {
int x = origin.getX() + 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);
BlockPos plantPos = new BlockPos(x, y, z);
if (!isValidPlantSpot(level, plantPos, plantPos.below())) {
continue;
}
float roll = random.nextFloat();
int age = roll < 0.4F ? 0 : roll < 0.75F ? 1 : 2;
BlockState bushState = bushBlock.defaultBlockState().setValue(BigBushBlock.AGE, age);
if (age > 0) {
bushState = bushState.setValue(BigBushBlock.FACING, Direction.Plane.HORIZONTAL.getRandomDirection(random));
}
if (!isFootprintInsideChunk(origin, plantPos, bushState) || !canPlaceBigBush(level, plantPos, bushState)) {
continue;
}
BigBushBlock.placeBushBlocks(level, plantPos, bushState, 2);
placed = true;
}
return placed;
}
private static boolean isFootprintInsideChunk(BlockPos featureOrigin, BlockPos bushOrigin, BlockState bushState) {
ChunkPos chunk = new ChunkPos(featureOrigin);
int minX = chunk.getMinBlockX() + 1;
int maxX = chunk.getMaxBlockX() - 1;
int minZ = chunk.getMinBlockZ() + 1;
int maxZ = chunk.getMaxBlockZ() - 1;
if (!isWithin(bushOrigin, minX, maxX, minZ, maxZ)) {
return false;
}
for (BlockPos partPos : BigBushBlock.partPositions(bushState, bushOrigin)) {
if (!isWithin(partPos, minX, maxX, minZ, maxZ)) {
return false;
}
}
return true;
}
private static boolean isWithin(BlockPos pos, int minX, int maxX, int minZ, int maxZ) {
return pos.getX() >= minX && pos.getX() <= maxX && pos.getZ() >= minZ && pos.getZ() <= maxZ;
}
private static boolean canPlaceBigBush(WorldGenLevel level, BlockPos originPos, BlockState bushState) {
if (bushState.getValue(BigBushBlock.AGE) == 0) {
return bushState.canSurvive(level, originPos);
}
if (!BigBushBlock.hasFullSupport(bushState, level, originPos)) {
return false;
}
for (BlockPos partPos : BigBushBlock.partPositions(bushState, originPos)) {
if (!isOpenPlantSpot(level, partPos)) {
return false;
}
}
return true;
} }
private static boolean placeSingle(WorldGenLevel level, BlockPos pos, Block block) { private static boolean placeSingle(WorldGenLevel level, BlockPos pos, Block block) {
@@ -197,6 +304,21 @@ public class ElythiaFloraFeature extends Feature<NoneFeatureConfiguration> {
return true; return true;
} }
private static boolean placeVeryTall(WorldGenLevel level, BlockPos pos, Block block) {
if (!(block instanceof VeryTallGrassBlock)) {
return placeDouble(level, pos, Blocks.TALL_GRASS.defaultBlockState());
}
BlockState state = block.defaultBlockState();
if (!isOpenPlantSpot(level, pos)
|| !isOpenPlantSpot(level, pos.above())
|| !isOpenPlantSpot(level, pos.above(2))
|| !state.canSurvive(level, pos)) {
return false;
}
VeryTallGrassBlock.placeAt(level, pos, 2);
return true;
}
private boolean placeTorchflowerPatch(WorldGenLevel level, BlockPos origin, RandomSource random) { private boolean placeTorchflowerPatch(WorldGenLevel level, BlockPos origin, RandomSource random) {
BlockPos patchCenter = sampleSurface(level, origin, random, this.variant == Variant.FOREST ? 8 : 12); BlockPos patchCenter = sampleSurface(level, origin, random, this.variant == Variant.FOREST ? 8 : 12);
if (patchCenter == null) { if (patchCenter == null) {
@@ -0,0 +1,53 @@
package com.craisinlord.antarchy.mixins;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.portal.PermanentPortalManager;
import com.craisinlord.antarchy.content.portal.PermanentPortalType;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.item.FlintAndSteelItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(FlintAndSteelItem.class)
public abstract class FlintAndSteelPortalIgnitionMixin {
@Inject(method = "useOn", at = @At("HEAD"), cancellable = true)
private void antarchy$ignitePermanentPortal(UseOnContext context, CallbackInfoReturnable<InteractionResult> cir) {
if (!AntarchySettings.permanentPortalsEnabled() || !AntarchySettings.permanentPortalsFlintAndSteelEnabled()) {
return;
}
Level level = context.getLevel();
BlockPos clickedPos = context.getClickedPos();
BlockState clickedState = level.getBlockState(clickedPos);
for (PermanentPortalType type : PermanentPortalType.values()) {
if (!type.isEnabled() || !clickedState.is(type.frameTag())) {
continue;
}
if (!PermanentPortalManager.tryIgnitePortal(level, clickedPos, type)) {
continue;
}
if (!level.isClientSide() && context.getPlayer() != null) {
ItemStack stack = context.getItemInHand();
stack.hurtAndBreak(1, context.getPlayer(), handToSlot(context.getHand()));
}
cir.setReturnValue(InteractionResult.sidedSuccess(level.isClientSide()));
return;
}
}
private static EquipmentSlot handToSlot(InteractionHand hand) {
return hand == InteractionHand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND;
}
}
@@ -1,23 +0,0 @@
package com.craisinlord.antarchy.mixins;
import com.craisinlord.antarchy.config.AntarchySettings;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(BlockBehaviour.BlockStateBase.class)
/*
* Makes torchflowers glow when the config is on.
*/
public abstract class TorchflowerBlockStateMixin {
@Inject(method = "getLightEmission", at = @At("HEAD"), cancellable = true)
private void antarchy$makeTorchflowerGlow(CallbackInfoReturnable<Integer> cir) {
BlockState state = (BlockState) (Object) this;
if (AntarchySettings.glowingTorchflowers() && state.is(Blocks.TORCHFLOWER)) {
cir.setReturnValue(10);
}
}
}
@@ -0,0 +1,131 @@
package com.craisinlord.antarchy.mixins.client;
import com.craisinlord.antarchy.config.AntarchySettings;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
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 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.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(GameRenderer.class)
public abstract class GameRendererSwingThroughGrassMixin {
@Shadow
private Minecraft minecraft;
@Shadow
private static HitResult filterHitResult(HitResult hitResult, Vec3 eyePosition, double range) {
throw new AssertionError();
}
@Unique
private Double antarchy$swingThroughReachSq;
@Inject(
method = "pick(Lnet/minecraft/world/entity/Entity;DDF)Lnet/minecraft/world/phys/HitResult;",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/phys/HitResult;getLocation()Lnet/minecraft/world/phys/Vec3;"
),
locals = LocalCapture.CAPTURE_FAILHARD
)
private void antarchy$cacheSwingThroughReach(
Entity entity,
double blockInteractionRange,
double entityInteractionRange,
float partialTick,
CallbackInfoReturnable<HitResult> cir,
double maxRange,
double maxRangeSq,
Vec3 eyePosition,
HitResult hitResult
) {
this.antarchy$swingThroughReachSq = null;
if (!AntarchySettings.swingThroughGrassEnabled()) {
return;
}
if (!(hitResult instanceof BlockHitResult blockHitResult) || hitResult.getType() != HitResult.Type.BLOCK) {
return;
}
ClientLevel level = this.minecraft.level;
if (level == null) {
return;
}
BlockPos blockPos = blockHitResult.getBlockPos();
if (level.getBlockState(blockPos).getCollisionShape(level, blockPos).isEmpty()) {
this.antarchy$swingThroughReachSq = maxRangeSq;
}
}
@ModifyArg(
method = "pick(Lnet/minecraft/world/entity/Entity;DDF)Lnet/minecraft/world/phys/HitResult;",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/projectile/ProjectileUtil;getEntityHitResult(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/AABB;Ljava/util/function/Predicate;D)Lnet/minecraft/world/phys/EntityHitResult;"
),
index = 5
)
private double antarchy$useOriginalReachForEntityRaycast(double rangeSq) {
return this.antarchy$swingThroughReachSq == null ? rangeSq : this.antarchy$swingThroughReachSq;
}
@Inject(
method = "pick(Lnet/minecraft/world/entity/Entity;DDF)Lnet/minecraft/world/phys/HitResult;",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/phys/EntityHitResult;getLocation()Lnet/minecraft/world/phys/Vec3;"
),
cancellable = true,
locals = LocalCapture.CAPTURE_FAILHARD
)
private void antarchy$preferAttackableEntityBehindGrass(
Entity entity,
double blockInteractionRange,
double entityInteractionRange,
float partialTick,
CallbackInfoReturnable<HitResult> cir,
double maxRange,
double maxRangeSq,
Vec3 eyePosition,
HitResult blockHitResult,
double blockHitDistanceSq,
Vec3 viewVector,
Vec3 reachEnd,
float unused,
AABB aabb,
EntityHitResult entityHitResult
) {
if (this.antarchy$swingThroughReachSq == null || entityHitResult == null) {
return;
}
Entity hitEntity = entityHitResult.getEntity();
if (!(hitEntity instanceof LivingEntity)
|| hitEntity.isSpectator()
|| !hitEntity.isAttackable()
|| this.minecraft.player == null
|| hitEntity == this.minecraft.player.getVehicle()) {
return;
}
if (eyePosition.distanceToSqr(hitEntity.position()) < this.antarchy$swingThroughReachSq) {
cir.setReturnValue(filterHitResult(entityHitResult, eyePosition, entityInteractionRange));
}
}
}
@@ -41,8 +41,8 @@ public abstract class MountedVehicleCameraMixin {
} }
if (vehicle instanceof DorrieEntity) { if (vehicle instanceof DorrieEntity) {
args.set(0, (Float) args.get(0) * 1.6F); args.set(0, (Float) args.get(0) * 0.25F);
args.set(1, (Float) args.get(1) + 0.15F); args.set(1, (Float) args.get(1) + 0.1F);
args.set(2, (Float) args.get(2) + 0.55F); args.set(2, (Float) args.get(2) + 0.55F);
} }
} }
@@ -2,7 +2,6 @@
"required": true, "required": true,
"package": "com.craisinlord.antarchy.mixins", "package": "com.craisinlord.antarchy.mixins",
"plugin": "com.craisinlord.antarchy.mixins.AntarchyMixinPlugin", "plugin": "com.craisinlord.antarchy.mixins.AntarchyMixinPlugin",
"refmap": "antarchy.refmap.json",
"compatibilityLevel": "JAVA_21", "compatibilityLevel": "JAVA_21",
"mixins": [ "mixins": [
"AccessorRangedAttribute", "AccessorRangedAttribute",
@@ -12,12 +11,12 @@
"DreamSandLowGravityMixin", "DreamSandLowGravityMixin",
"FireVisualBaseFireBlockMixin", "FireVisualBaseFireBlockMixin",
"FireVisualEntityMixin", "FireVisualEntityMixin",
"FlintAndSteelPortalIgnitionMixin",
"GlowVinesUnderLeavesMixin", "GlowVinesUnderLeavesMixin",
"NightmareSwordDamageMixin", "NightmareSwordDamageMixin",
"ServerPlayerGameModeMixin", "ServerPlayerGameModeMixin",
"SquidzookaEnchantMixin", "SquidzookaEnchantMixin",
"SquidzookaMultishotMixin", "SquidzookaMultishotMixin",
"TorchflowerBlockStateMixin",
"gravity.AbstractArrowGravityMixin", "gravity.AbstractArrowGravityMixin",
"gravity.BucketItemGravityMixin", "gravity.BucketItemGravityMixin",
"gravity.ChunkMapAccessor", "gravity.ChunkMapAccessor",
@@ -51,6 +50,7 @@
"client": [ "client": [
"client.ElythiaSkyMixin", "client.ElythiaSkyMixin",
"client.ElytraModelAccessor", "client.ElytraModelAccessor",
"client.GameRendererSwingThroughGrassMixin",
"client.LightningBoltRendererMixin", "client.LightningBoltRendererMixin",
"client.MountedVehicleCameraMixin", "client.MountedVehicleCameraMixin",
"client.ParalyzedMouseTurnMixin", "client.ParalyzedMouseTurnMixin",
File diff suppressed because it is too large. Load diff
@@ -2,7 +2,7 @@
"format_version": "1.8.0", "format_version": "1.8.0",
"animations": { "animations": {
"lay": { "lay": {
"loop": true, "loop": false,
"animation_length": 2, "animation_length": 2,
"bones": { "bones": {
"head": { "head": {
@@ -1192,4 +1192,4 @@
} }
} }
} }
} }
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -2136,6 +2136,11 @@
"spin_attack": { "spin_attack": {
"loop": true, "loop": true,
"animation_length": 0.2917, "animation_length": 0.2917,
"sound_effects": {
"0.0": {
"effect": "antarchy:toreterror_spin|1.1|0.95"
}
},
"bones": { "bones": {
"R_arm": { "R_arm": {
"rotation": { "rotation": {
@@ -3357,4 +3362,4 @@
} }
} }
} }
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 79 KiB

@@ -1,150 +0,0 @@
{
"multipart": [
{
"apply": {
"model": "antarchy:block/amber_lichen"
},
"when": {
"north": "true"
}
},
{
"apply": {
"model": "antarchy:block/amber_lichen"
},
"when": {
"down": "false",
"east": "false",
"north": "false",
"south": "false",
"up": "false",
"west": "false"
}
},
{
"apply": {
"model": "antarchy:block/amber_lichen",
"uvlock": true,
"y": 90
},
"when": {
"east": "true"
}
},
{
"apply": {
"model": "antarchy:block/amber_lichen",
"uvlock": true,
"y": 90
},
"when": {
"down": "false",
"east": "false",
"north": "false",
"south": "false",
"up": "false",
"west": "false"
}
},
{
"apply": {
"model": "antarchy:block/amber_lichen",
"uvlock": true,
"y": 180
},
"when": {
"south": "true"
}
},
{
"apply": {
"model": "antarchy:block/amber_lichen",
"uvlock": true,
"y": 180
},
"when": {
"down": "false",
"east": "false",
"north": "false",
"south": "false",
"up": "false",
"west": "false"
}
},
{
"apply": {
"model": "antarchy:block/amber_lichen",
"uvlock": true,
"y": 270
},
"when": {
"west": "true"
}
},
{
"apply": {
"model": "antarchy:block/amber_lichen",
"uvlock": true,
"y": 270
},
"when": {
"down": "false",
"east": "false",
"north": "false",
"south": "false",
"up": "false",
"west": "false"
}
},
{
"apply": {
"model": "antarchy:block/amber_lichen",
"uvlock": true,
"x": 270
},
"when": {
"up": "true"
}
},
{
"apply": {
"model": "antarchy:block/amber_lichen",
"uvlock": true,
"x": 270
},
"when": {
"down": "false",
"east": "false",
"north": "false",
"south": "false",
"up": "false",
"west": "false"
}
},
{
"apply": {
"model": "antarchy:block/amber_lichen",
"uvlock": true,
"x": 90
},
"when": {
"down": "true"
}
},
{
"apply": {
"model": "antarchy:block/amber_lichen",
"uvlock": true,
"x": 90
},
"when": {
"down": "false",
"east": "false",
"north": "false",
"south": "false",
"up": "false",
"west": "false"
}
}
]
}
@@ -1,7 +0,0 @@
{
"variants": {
"": {
"model": "antarchy:block/amber_moss_block"
}
}
}
@@ -1,154 +0,0 @@
{
"multipart": [
{
"apply": {
"model": "antarchy:block/amber_moss_carpet"
},
"when": {
"bottom": "true"
}
},
{
"apply": {
"model": "antarchy:block/amber_moss_carpet"
},
"when": {
"bottom": "false",
"east": "none",
"north": "none",
"south": "none",
"west": "none"
}
},
{
"apply": {
"model": "antarchy:block/amber_moss_carpet_side_tall"
},
"when": {
"north": "tall"
}
},
{
"apply": {
"model": "antarchy:block/amber_moss_carpet_side_small"
},
"when": {
"north": "low"
}
},
{
"apply": {
"model": "antarchy:block/amber_moss_carpet_side_tall"
},
"when": {
"bottom": "false",
"east": "none",
"north": "none",
"south": "none",
"west": "none"
}
},
{
"apply": {
"model": "antarchy:block/amber_moss_carpet_side_tall",
"uvlock": true,
"y": 90
},
"when": {
"east": "tall"
}
},
{
"apply": {
"model": "antarchy:block/amber_moss_carpet_side_small",
"uvlock": true,
"y": 90
},
"when": {
"east": "low"
}
},
{
"apply": {
"model": "antarchy:block/amber_moss_carpet_side_tall",
"uvlock": true,
"y": 90
},
"when": {
"bottom": "false",
"east": "none",
"north": "none",
"south": "none",
"west": "none"
}
},
{
"apply": {
"model": "antarchy:block/amber_moss_carpet_side_tall",
"uvlock": true,
"y": 180
},
"when": {
"south": "tall"
}
},
{
"apply": {
"model": "antarchy:block/amber_moss_carpet_side_small",
"uvlock": true,
"y": 180
},
"when": {
"south": "low"
}
},
{
"apply": {
"model": "antarchy:block/amber_moss_carpet_side_tall",
"uvlock": true,
"y": 180
},
"when": {
"bottom": "false",
"east": "none",
"north": "none",
"south": "none",
"west": "none"
}
},
{
"apply": {
"model": "antarchy:block/amber_moss_carpet_side_tall",
"uvlock": true,
"y": 270
},
"when": {
"west": "tall"
}
},
{
"apply": {
"model": "antarchy:block/amber_moss_carpet_side_small",
"uvlock": true,
"y": 270
},
"when": {
"west": "low"
}
},
{
"apply": {
"model": "antarchy:block/amber_moss_carpet_side_tall",
"uvlock": true,
"y": 270
},
"when": {
"bottom": "false",
"east": "none",
"north": "none",
"south": "none",
"west": "none"
}
}
]
}
@@ -0,0 +1,16 @@
{
"variants": {
"age=0,facing=north": { "model": "antarchy:block/big_bush_stage1" },
"age=0,facing=east": { "model": "antarchy:block/big_bush_stage1" },
"age=0,facing=south": { "model": "antarchy:block/big_bush_stage1" },
"age=0,facing=west": { "model": "antarchy:block/big_bush_stage1" },
"age=1,facing=east": { "model": "antarchy:block/big_bush_stage2" },
"age=1,facing=south": { "model": "antarchy:block/big_bush_stage2", "y": 90 },
"age=1,facing=west": { "model": "antarchy:block/big_bush_stage2", "y": 180 },
"age=1,facing=north": { "model": "antarchy:block/big_bush_stage2", "y": 270 },
"age=2,facing=north": { "model": "antarchy:block/big_bush_stage3_bottom" },
"age=2,facing=east": { "model": "antarchy:block/big_bush_stage3_bottom" },
"age=2,facing=south": { "model": "antarchy:block/big_bush_stage3_bottom" },
"age=2,facing=west": { "model": "antarchy:block/big_bush_stage3_bottom" }
}
}
@@ -0,0 +1,6 @@
{
"variants": {
"cap=false": { "model": "antarchy:block/big_bush_part" },
"cap=true": { "model": "antarchy:block/big_bush_stage3_top" }
}
}
@@ -1,7 +0,0 @@
{
"variants": {
"": {
"model": "antarchy:block/bile_vein"
}
}
}
@@ -1,7 +0,0 @@
{
"variants": {
"": {
"model": "antarchy:block/broodstone"
}
}
}
@@ -1,16 +0,0 @@
{
"variants": {
"axis=x": {
"model": "antarchy:block/chiten_block",
"x": 90,
"y": 90
},
"axis=y": {
"model": "antarchy:block/chiten_block"
},
"axis=z": {
"model": "antarchy:block/chiten_block",
"x": 90
}
}
}
@@ -1,14 +0,0 @@
{
"variants": {
"thickness=base,vertical_direction=down": { "model": "antarchy:block/chiten_spike_down_base" },
"thickness=base,vertical_direction=up": { "model": "antarchy:block/chiten_spike_up_base" },
"thickness=frustum,vertical_direction=down": { "model": "antarchy:block/chiten_spike_down_frustum" },
"thickness=frustum,vertical_direction=up": { "model": "antarchy:block/chiten_spike_up_frustum" },
"thickness=middle,vertical_direction=down": { "model": "antarchy:block/chiten_spike_down_middle" },
"thickness=middle,vertical_direction=up": { "model": "antarchy:block/chiten_spike_up_middle" },
"thickness=tip,vertical_direction=down": { "model": "antarchy:block/chiten_spike_down_tip" },
"thickness=tip,vertical_direction=up": { "model": "antarchy:block/chiten_spike_up_tip" },
"thickness=tip_merge,vertical_direction=down": { "model": "antarchy:block/chiten_spike_down_tip_merge" },
"thickness=tip_merge,vertical_direction=up": { "model": "antarchy:block/chiten_spike_up_tip_merge" }
}
}
@@ -1,76 +0,0 @@
{
"variants": {
"eggs=1,hatch=0": [
{ "model": "antarchy:block/creeping_horror_egg_1" },
{ "model": "antarchy:block/creeping_horror_egg_1", "y": 90 },
{ "model": "antarchy:block/creeping_horror_egg_1", "y": 180 },
{ "model": "antarchy:block/creeping_horror_egg_1", "y": 270 }
],
"eggs=1,hatch=1": [
{ "model": "antarchy:block/slightly_cracked_creeping_horror_egg_1" },
{ "model": "antarchy:block/slightly_cracked_creeping_horror_egg_1", "y": 90 },
{ "model": "antarchy:block/slightly_cracked_creeping_horror_egg_1", "y": 180 },
{ "model": "antarchy:block/slightly_cracked_creeping_horror_egg_1", "y": 270 }
],
"eggs=1,hatch=2": [
{ "model": "antarchy:block/very_cracked_creeping_horror_egg_1" },
{ "model": "antarchy:block/very_cracked_creeping_horror_egg_1", "y": 90 },
{ "model": "antarchy:block/very_cracked_creeping_horror_egg_1", "y": 180 },
{ "model": "antarchy:block/very_cracked_creeping_horror_egg_1", "y": 270 }
],
"eggs=2,hatch=0": [
{ "model": "antarchy:block/creeping_horror_egg_2" },
{ "model": "antarchy:block/creeping_horror_egg_2", "y": 90 },
{ "model": "antarchy:block/creeping_horror_egg_2", "y": 180 },
{ "model": "antarchy:block/creeping_horror_egg_2", "y": 270 }
],
"eggs=2,hatch=1": [
{ "model": "antarchy:block/slightly_cracked_creeping_horror_egg_2" },
{ "model": "antarchy:block/slightly_cracked_creeping_horror_egg_2", "y": 90 },
{ "model": "antarchy:block/slightly_cracked_creeping_horror_egg_2", "y": 180 },
{ "model": "antarchy:block/slightly_cracked_creeping_horror_egg_2", "y": 270 }
],
"eggs=2,hatch=2": [
{ "model": "antarchy:block/very_cracked_creeping_horror_egg_2" },
{ "model": "antarchy:block/very_cracked_creeping_horror_egg_2", "y": 90 },
{ "model": "antarchy:block/very_cracked_creeping_horror_egg_2", "y": 180 },
{ "model": "antarchy:block/very_cracked_creeping_horror_egg_2", "y": 270 }
],
"eggs=3,hatch=0": [
{ "model": "antarchy:block/creeping_horror_egg_3" },
{ "model": "antarchy:block/creeping_horror_egg_3", "y": 90 },
{ "model": "antarchy:block/creeping_horror_egg_3", "y": 180 },
{ "model": "antarchy:block/creeping_horror_egg_3", "y": 270 }
],
"eggs=3,hatch=1": [
{ "model": "antarchy:block/slightly_cracked_creeping_horror_egg_3" },
{ "model": "antarchy:block/slightly_cracked_creeping_horror_egg_3", "y": 90 },
{ "model": "antarchy:block/slightly_cracked_creeping_horror_egg_3", "y": 180 },
{ "model": "antarchy:block/slightly_cracked_creeping_horror_egg_3", "y": 270 }
],
"eggs=3,hatch=2": [
{ "model": "antarchy:block/very_cracked_creeping_horror_egg_3" },
{ "model": "antarchy:block/very_cracked_creeping_horror_egg_3", "y": 90 },
{ "model": "antarchy:block/very_cracked_creeping_horror_egg_3", "y": 180 },
{ "model": "antarchy:block/very_cracked_creeping_horror_egg_3", "y": 270 }
],
"eggs=4,hatch=0": [
{ "model": "antarchy:block/creeping_horror_egg_4" },
{ "model": "antarchy:block/creeping_horror_egg_4", "y": 90 },
{ "model": "antarchy:block/creeping_horror_egg_4", "y": 180 },
{ "model": "antarchy:block/creeping_horror_egg_4", "y": 270 }
],
"eggs=4,hatch=1": [
{ "model": "antarchy:block/slightly_cracked_creeping_horror_egg_4" },
{ "model": "antarchy:block/slightly_cracked_creeping_horror_egg_4", "y": 90 },
{ "model": "antarchy:block/slightly_cracked_creeping_horror_egg_4", "y": 180 },
{ "model": "antarchy:block/slightly_cracked_creeping_horror_egg_4", "y": 270 }
],
"eggs=4,hatch=2": [
{ "model": "antarchy:block/very_cracked_creeping_horror_egg_4" },
{ "model": "antarchy:block/very_cracked_creeping_horror_egg_4", "y": 90 },
{ "model": "antarchy:block/very_cracked_creeping_horror_egg_4", "y": 180 },
{ "model": "antarchy:block/very_cracked_creeping_horror_egg_4", "y": 270 }
]
}
}
@@ -1,120 +0,0 @@
{
"multipart": [
{
"apply": {
"model": "antarchy:block/creepvine"
},
"when": {
"north": "true"
}
},
{
"apply": {
"model": "antarchy:block/creepvine"
},
"when": {
"east": "false",
"north": "false",
"south": "false",
"up": "false",
"west": "false"
}
},
{
"apply": {
"model": "antarchy:block/creepvine",
"uvlock": true,
"y": 90
},
"when": {
"east": "true"
}
},
{
"apply": {
"model": "antarchy:block/creepvine",
"uvlock": true,
"y": 90
},
"when": {
"east": "false",
"north": "false",
"south": "false",
"up": "false",
"west": "false"
}
},
{
"apply": {
"model": "antarchy:block/creepvine",
"uvlock": true,
"y": 180
},
"when": {
"south": "true"
}
},
{
"apply": {
"model": "antarchy:block/creepvine",
"uvlock": true,
"y": 180
},
"when": {
"east": "false",
"north": "false",
"south": "false",
"up": "false",
"west": "false"
}
},
{
"apply": {
"model": "antarchy:block/creepvine",
"uvlock": true,
"y": 270
},
"when": {
"west": "true"
}
},
{
"apply": {
"model": "antarchy:block/creepvine",
"uvlock": true,
"y": 270
},
"when": {
"east": "false",
"north": "false",
"south": "false",
"up": "false",
"west": "false"
}
},
{
"apply": {
"model": "antarchy:block/creepvine",
"uvlock": true,
"x": 270
},
"when": {
"up": "true"
}
},
{
"apply": {
"model": "antarchy:block/creepvine",
"uvlock": true,
"x": 270
},
"when": {
"east": "false",
"north": "false",
"south": "false",
"up": "false",
"west": "false"
}
}
]
}
@@ -0,0 +1,6 @@
{
"variants": {
"axis=x": { "model": "antarchy:block/elythia_portal_x" },
"axis=z": { "model": "antarchy:block/elythia_portal_z" }
}
}
@@ -1,76 +0,0 @@
{
"variants": {
"eggs=1,hatch=0": [
{ "model": "antarchy:block/lurking_terror_egg_1" },
{ "model": "antarchy:block/lurking_terror_egg_1", "y": 90 },
{ "model": "antarchy:block/lurking_terror_egg_1", "y": 180 },
{ "model": "antarchy:block/lurking_terror_egg_1", "y": 270 }
],
"eggs=1,hatch=1": [
{ "model": "antarchy:block/slightly_cracked_lurking_terror_egg_1" },
{ "model": "antarchy:block/slightly_cracked_lurking_terror_egg_1", "y": 90 },
{ "model": "antarchy:block/slightly_cracked_lurking_terror_egg_1", "y": 180 },
{ "model": "antarchy:block/slightly_cracked_lurking_terror_egg_1", "y": 270 }
],
"eggs=1,hatch=2": [
{ "model": "antarchy:block/very_cracked_lurking_terror_egg_1" },
{ "model": "antarchy:block/very_cracked_lurking_terror_egg_1", "y": 90 },
{ "model": "antarchy:block/very_cracked_lurking_terror_egg_1", "y": 180 },
{ "model": "antarchy:block/very_cracked_lurking_terror_egg_1", "y": 270 }
],
"eggs=2,hatch=0": [
{ "model": "antarchy:block/lurking_terror_egg_2" },
{ "model": "antarchy:block/lurking_terror_egg_2", "y": 90 },
{ "model": "antarchy:block/lurking_terror_egg_2", "y": 180 },
{ "model": "antarchy:block/lurking_terror_egg_2", "y": 270 }
],
"eggs=2,hatch=1": [
{ "model": "antarchy:block/slightly_cracked_lurking_terror_egg_2" },
{ "model": "antarchy:block/slightly_cracked_lurking_terror_egg_2", "y": 90 },
{ "model": "antarchy:block/slightly_cracked_lurking_terror_egg_2", "y": 180 },
{ "model": "antarchy:block/slightly_cracked_lurking_terror_egg_2", "y": 270 }
],
"eggs=2,hatch=2": [
{ "model": "antarchy:block/very_cracked_lurking_terror_egg_2" },
{ "model": "antarchy:block/very_cracked_lurking_terror_egg_2", "y": 90 },
{ "model": "antarchy:block/very_cracked_lurking_terror_egg_2", "y": 180 },
{ "model": "antarchy:block/very_cracked_lurking_terror_egg_2", "y": 270 }
],
"eggs=3,hatch=0": [
{ "model": "antarchy:block/lurking_terror_egg_3" },
{ "model": "antarchy:block/lurking_terror_egg_3", "y": 90 },
{ "model": "antarchy:block/lurking_terror_egg_3", "y": 180 },
{ "model": "antarchy:block/lurking_terror_egg_3", "y": 270 }
],
"eggs=3,hatch=1": [
{ "model": "antarchy:block/slightly_cracked_lurking_terror_egg_3" },
{ "model": "antarchy:block/slightly_cracked_lurking_terror_egg_3", "y": 90 },
{ "model": "antarchy:block/slightly_cracked_lurking_terror_egg_3", "y": 180 },
{ "model": "antarchy:block/slightly_cracked_lurking_terror_egg_3", "y": 270 }
],
"eggs=3,hatch=2": [
{ "model": "antarchy:block/very_cracked_lurking_terror_egg_3" },
{ "model": "antarchy:block/very_cracked_lurking_terror_egg_3", "y": 90 },
{ "model": "antarchy:block/very_cracked_lurking_terror_egg_3", "y": 180 },
{ "model": "antarchy:block/very_cracked_lurking_terror_egg_3", "y": 270 }
],
"eggs=4,hatch=0": [
{ "model": "antarchy:block/lurking_terror_egg_4" },
{ "model": "antarchy:block/lurking_terror_egg_4", "y": 90 },
{ "model": "antarchy:block/lurking_terror_egg_4", "y": 180 },
{ "model": "antarchy:block/lurking_terror_egg_4", "y": 270 }
],
"eggs=4,hatch=1": [
{ "model": "antarchy:block/slightly_cracked_lurking_terror_egg_4" },
{ "model": "antarchy:block/slightly_cracked_lurking_terror_egg_4", "y": 90 },
{ "model": "antarchy:block/slightly_cracked_lurking_terror_egg_4", "y": 180 },
{ "model": "antarchy:block/slightly_cracked_lurking_terror_egg_4", "y": 270 }
],
"eggs=4,hatch=2": [
{ "model": "antarchy:block/very_cracked_lurking_terror_egg_4" },
{ "model": "antarchy:block/very_cracked_lurking_terror_egg_4", "y": 90 },
{ "model": "antarchy:block/very_cracked_lurking_terror_egg_4", "y": 180 },
{ "model": "antarchy:block/very_cracked_lurking_terror_egg_4", "y": 270 }
]
}
}
@@ -1,7 +0,0 @@
{
"variants": {
"": {
"model": "antarchy:block/myrmite"
}
}
}
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "antarchy:block/ouranwood_vine"
}
}
}
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "antarchy:block/ouranwood_vine_plant"
}
}
}
@@ -1,8 +0,0 @@
{
"variants": {
"facing=north": {"model": "antarchy:block/termite_nest"},
"facing=east": {"model": "antarchy:block/termite_nest", "y": 90},
"facing=south": {"model": "antarchy:block/termite_nest", "y": 180},
"facing=west": {"model": "antarchy:block/termite_nest", "y": 270}
}
}
@@ -0,0 +1,6 @@
{
"variants": {
"axis=x": { "model": "antarchy:block/thoraxis_portal_x" },
"axis=z": { "model": "antarchy:block/thoraxis_portal_z" }
}
}
@@ -0,0 +1,5 @@
{
"variants": {
"": { "model": "antarchy:block/very_short_grass" }
}
}
@@ -0,0 +1,7 @@
{
"variants": {
"part=lower": { "model": "antarchy:block/very_tall_grass_bottom" },
"part=middle": { "model": "antarchy:block/very_tall_grass_middle" },
"part=upper": { "model": "antarchy:block/very_tall_grass_top" }
}
}
@@ -4,247 +4,195 @@
{ {
"description": { "description": {
"identifier": "geometry.unknown", "identifier": "geometry.unknown",
"texture_width": 256, "texture_width": 128,
"texture_height": 256, "texture_height": 256,
"visible_bounds_width": 9, "visible_bounds_width": 7,
"visible_bounds_height": 4.5, "visible_bounds_height": 4.5,
"visible_bounds_offset": [0, 1.75, 0] "visible_bounds_offset": [0, 1.75, 0]
}, },
"bones": [ "bones": [
{ {
"name": "bone", "name": "Dorrie",
"pivot": [0, 8.5, 16.125] "pivot": [0, 0, 0]
},
{
"name": "waist",
"parent": "bone",
"pivot": [0, 8.5, 16.125],
"cubes": [
{"origin": [-10, 1, 15], "size": [20, 19, 6], "uv": [98, 55]}
]
},
{
"name": "tail",
"parent": "waist",
"pivot": [0, 7.83333, 20.83333],
"cubes": [
{"origin": [-7, 2, 21], "size": [14, 17, 17], "uv": [70, 81]}
]
},
{
"name": "tail2",
"parent": "tail",
"pivot": [0, 6.5, 37.5],
"cubes": [
{"origin": [-5, 2, 38], "size": [10, 11, 17], "uv": [62, 115]}
]
},
{
"name": "tail3",
"parent": "tail2",
"pivot": [0, 5.5, 54.5],
"cubes": [
{"origin": [-3, 2, 55], "size": [6, 7, 7], "uv": [34, 163]}
]
}, },
{ {
"name": "body", "name": "body",
"parent": "bone", "parent": "Dorrie",
"pivot": [0, 11.33767, -10.06778], "pivot": [0, 8.2, 4.4]
"cubes": [
{"origin": [-13, 0, -19], "size": [26, 21, 34], "uv": [0, 0]},
{"origin": [-11, 2, -24.6], "size": [22, 21, 13], "pivot": [0, 12.5, -19.6], "rotation": [-12.5, 0, 0], "uv": [0, 81]}
]
}, },
{ {
"name": "neck", "name": "right_arm",
"parent": "body", "parent": "body",
"pivot": [0, 20.33333, -19.1], "pivot": [-8.5, 7.75, -2],
"cubes": [ "cubes": [
{"origin": [-8, 10, -26.6], "size": [16, 16, 15], "uv": [0, 115]} {"origin": [-25.5, 6, -6], "size": [17, 3, 9], "uv": [7, 88]}
] ]
}, },
{ {
"name": "neck2", "name": "right_thumb",
"parent": "neck", "parent": "right_arm",
"pivot": [0, 25.5, -19.1], "pivot": [-23.5, 7, -6],
"cubes": [ "cubes": [
{"origin": [-6, 26, -25.6], "size": [12, 8, 13], "uv": [120, 12]} {"origin": [-25.5, 7, -10], "size": [4, 0, 4], "uv": [20, 72]}
] ]
}, },
{ {
"name": "neck3", "name": "right_finger",
"parent": "neck2", "parent": "right_arm",
"pivot": [0, 34, -19.1], "pivot": [-25.5, 7, -1.5],
"cubes": [ "cubes": [
{"origin": [-5, 34, -24.6], "size": [10, 6, 11], "uv": [0, 146]} {"origin": [-33.5, 7, -6], "size": [8, 0, 9], "uv": [23, 79]}
]
},
{
"name": "head",
"parent": "neck3",
"pivot": [0.025, 40.75, -18.1],
"cubes": [
{"origin": [-6.5, 39, -25.6], "size": [13, 12, 13], "pivot": [-0.5, 44.5, -19.1], "rotation": [10, 0, 0], "uv": [116, 115]},
{"origin": [-4.9, 39, -37.6], "size": [10, 3, 16], "uv": [120, 33]},
{"origin": [-5.5, 42, -30.6], "size": [11, 7, 9], "uv": [100, 156]},
{"origin": [-5.5, 42, -37.6], "size": [11, 7, 8], "inflate": 0.2, "uv": [150, 65]}
]
},
{
"name": "googles",
"parent": "head",
"pivot": [0, 47.45804, -21.34628],
"cubes": [
{"origin": [-5.5, 46.7, -27.4], "size": [11, 3, 1], "inflate": 0.1, "pivot": [0, 47.6, -24.6], "rotation": [9, 0, 0], "uv": [162, 151]},
{"origin": [-7, 45.7, -19.3], "size": [14, 3, 7], "pivot": [-0.5, 44.5, -19.1], "rotation": [10, 0, 0], "uv": [140, 156]},
{"origin": [-7.5, 44.7, -26.6], "size": [15, 5, 8], "pivot": [-0.5, 44.5, -19.1], "rotation": [10, 0, 0], "uv": [150, 52]}
]
},
{
"name": "saddle",
"parent": "body",
"pivot": [4.66667, 18.5, 1.16667],
"cubes": [
{"origin": [-13, 21, -10], "size": [26, 3, 23], "uv": [0, 55]},
{"origin": [-9, 24, -10], "size": [18, 5, 3], "uv": [132, 106]},
{"origin": [-13, 24, 9], "size": [26, 4, 4], "uv": [132, 80]},
{"origin": [-14, -1, 7], "size": [28, 10, 2], "uv": [120, 0]},
{"origin": [-15, 9, 6], "size": [2, 14, 4], "uv": [88, 164]},
{"origin": [13, 9, 6], "size": [2, 14, 4], "uv": [88, 164], "mirror": true},
{"origin": [13, 9, -7], "size": [2, 14, 4], "uv": [88, 164], "mirror": true},
{"origin": [-15, 9, -7], "size": [2, 14, 4], "uv": [88, 164]},
{"origin": [-14, -1, -6], "size": [28, 10, 2], "uv": [120, 0]}
]
},
{
"name": "left_leg",
"parent": "body",
"pivot": [-10.875, 0.875, 13.375],
"rotation": [0, 45, 0],
"cubes": [
{"origin": [-14, 0, 9], "size": [5, 3, 9], "uv": [60, 164]}
]
},
{
"name": "left_leg2",
"parent": "left_leg",
"pivot": [-14.66667, 0.66667, 13.33333]
},
{
"name": "left_leg3",
"parent": "left_leg2",
"pivot": [-14.66667, 0.66667, 13.33333],
"cubes": [
{"origin": [-19, 0, 9], "size": [5, 2, 9], "uv": [140, 166]}
]
},
{
"name": "left_leg4",
"parent": "left_leg3",
"pivot": [-19.25, 0.5, 13.25],
"cubes": [
{"origin": [-27, 0, 9], "size": [8, 1, 9], "uv": [0, 163]},
{"origin": [-30, 0, 9], "size": [3, 1, 8], "uv": [168, 114]}
]
},
{
"name": "right_leg",
"parent": "body",
"pivot": [10.875, 0.875, 13.375],
"rotation": [0, -45, 0],
"cubes": [
{"origin": [9, 0, 9], "size": [5, 3, 9], "uv": [60, 164], "mirror": true}
]
},
{
"name": "right_leg2",
"parent": "right_leg",
"pivot": [14.66667, 0.66667, 13.33333]
},
{
"name": "right_leg3",
"parent": "right_leg2",
"pivot": [14.66667, 0.66667, 13.33333],
"cubes": [
{"origin": [14, 0, 9], "size": [5, 2, 9], "uv": [140, 166], "mirror": true}
]
},
{
"name": "right_leg4",
"parent": "right_leg3",
"pivot": [19.25, 0.5, 13.25],
"cubes": [
{"origin": [19, 0, 9], "size": [8, 1, 9], "uv": [0, 163], "mirror": true},
{"origin": [27, 0, 9], "size": [3, 1, 8], "uv": [168, 114], "mirror": true}
] ]
}, },
{ {
"name": "left_arm", "name": "left_arm",
"parent": "body", "parent": "body",
"pivot": [-12.41667, 1.66667, -9.25], "pivot": [8.5, 7.75, -2],
"cubes": [ "cubes": [
{"origin": [-15, 0, -18], "size": [4, 6, 15], "uv": [62, 143]} {"origin": [8.5, 6, -6], "size": [17, 3, 9], "uv": [7, 88], "mirror": true}
] ]
}, },
{ {
"name": "left_arm2", "name": "left_thumb",
"parent": "left_arm", "parent": "left_arm",
"pivot": [-14.7, 1.4, -9], "pivot": [23.5, 7, -6],
"cubes": [ "cubes": [
{"origin": [-25, 0, -17], "size": [10, 5, 13], "uv": [132, 88]} {"origin": [21.5, 7, -10], "size": [4, 0, 4], "uv": [20, 72], "mirror": true}
] ]
}, },
{ {
"name": "left_arm3", "name": "left_finger",
"parent": "left_arm2", "parent": "left_arm",
"pivot": [-25.125, 1.125, -8.625], "pivot": [25.5, 7, -1.5],
"cubes": [ "cubes": [
{"origin": [-35, 0, -17], "size": [10, 3, 13], "uv": [116, 140]} {"origin": [25.5, 7, -6], "size": [8, 0, 9], "uv": [23, 79], "mirror": true}
] ]
}, },
{ {
"name": "left_arm4", "name": "left_leg",
"parent": "left_arm3",
"pivot": [-35.5, 1, -8],
"cubes": [
{"origin": [-45, 0, -17], "size": [10, 2, 9], "uv": [162, 140]},
{"origin": [-42, 0, -7], "size": [2, 2, 3], "uv": [100, 143]},
{"origin": [-40, 0, -8], "size": [5, 2, 4], "uv": [42, 146]}
]
},
{
"name": "right_arm",
"parent": "body", "parent": "body",
"pivot": [12.41667, 1.66667, -9.25], "pivot": [4.5, 7.75, 18],
"cubes": [ "cubes": [
{"origin": [11, 0, -18], "size": [4, 6, 15], "uv": [62, 143], "mirror": true} {"origin": [4.5, 6, 14], "size": [17, 3, 9], "uv": [7, 88], "mirror": true}
] ]
}, },
{ {
"name": "right_arm2", "name": "left_toe",
"parent": "right_arm", "parent": "left_leg",
"pivot": [14.7, 1.4, -9], "pivot": [19.5, 7, 14],
"cubes": [ "cubes": [
{"origin": [15, 0, -17], "size": [10, 5, 13], "uv": [132, 88], "mirror": true} {"origin": [17.5, 7, 8], "size": [4, 0, 6], "uv": [26, 71], "mirror": true}
] ]
}, },
{ {
"name": "right_arm3", "name": "left_toe2",
"parent": "right_arm2", "parent": "left_leg",
"pivot": [25.125, 1.125, -8.625], "pivot": [21.5, 7, 18.5],
"cubes": [ "cubes": [
{"origin": [25, 0, -17], "size": [10, 3, 13], "uv": [116, 140], "mirror": true} {"origin": [21.5, 7, 14], "size": [10, 0, 9], "uv": [41, 80], "mirror": true}
] ]
}, },
{ {
"name": "right_arm4", "name": "right_leg",
"parent": "right_arm3", "parent": "body",
"pivot": [35.5, 1, -8], "pivot": [-4.5, 7.75, 18],
"cubes": [ "cubes": [
{"origin": [35, 0, -17], "size": [10, 2, 9], "uv": [162, 140], "mirror": true}, {"origin": [-21.5, 6, 14], "size": [17, 3, 9], "uv": [7, 88]}
{"origin": [40, 0, -7], "size": [2, 2, 3], "uv": [100, 143], "mirror": true}, ]
{"origin": [35, 0, -8], "size": [5, 2, 4], "uv": [42, 146], "mirror": true} },
{
"name": "right_toe",
"parent": "right_leg",
"pivot": [-19.5, 7, 14],
"cubes": [
{"origin": [-21.5, 7, 8], "size": [4, 0, 6], "uv": [26, 71]}
]
},
{
"name": "right_toe2",
"parent": "right_leg",
"pivot": [-21.5, 7, 18.5],
"cubes": [
{"origin": [-31.5, 7, 14], "size": [10, 0, 9], "uv": [41, 80]}
]
},
{
"name": "torso",
"parent": "body",
"pivot": [0, 15, 7],
"cubes": [
{"origin": [-11.5, 6, 3], "size": [23, 13, 13], "inflate": 0.1, "uv": [0, 126]},
{"origin": [-10.5, 0, -10], "size": [21, 18, 30], "inflate": 0.1, "uv": [0, 0]},
{"origin": [-15.75, 9, -5], "size": [5, 9, 14], "uv": [73, 125]}
]
},
{
"name": "tail",
"parent": "torso",
"pivot": [0, 12.5, 20],
"cubes": [
{"origin": [-4, 4, 20], "size": [8, 14, 12], "inflate": 0.05, "uv": [0, 100]}
]
},
{
"name": "tail2",
"parent": "tail",
"pivot": [0, 14, 32],
"cubes": [
{"origin": [-4, 10, 32], "size": [8, 8, 12], "uv": [59, 80]}
]
},
{
"name": "neck",
"parent": "torso",
"pivot": [0, 16, -5.175],
"cubes": [
{"origin": [-6, 12, -10.175], "size": [12, 13, 10], "uv": [66, 57]},
{"origin": [-6, 14, -10.175], "size": [12, 13, 10], "inflate": 0.1, "uv": [72, 0]}
]
},
{
"name": "neck2",
"parent": "neck",
"pivot": [0, 25, -5.175],
"cubes": [
{"origin": [-4, 24, -9.175], "size": [8, 8, 8], "uv": [0, 71]}
]
},
{
"name": "head",
"parent": "neck2",
"pivot": [0, 31, -6.00833],
"cubes": [
{"origin": [-5, 31, -11.175], "size": [10, 13, 10], "inflate": 0.1, "uv": [0, 48]},
{"origin": [-8, 31, -9.175], "size": [3, 6, 7], "uv": [40, 60]},
{"origin": [5, 31, -9.175], "size": [3, 6, 7], "uv": [0, 9]},
{"origin": [-5, 33, -15.175], "size": [10, 5, 4], "uv": [76, 48]},
{"origin": [-6, 33, -21.175], "size": [12, 6, 6], "uv": [40, 48]}
]
},
{
"name": "goggle",
"parent": "head",
"pivot": [0, 41, -6.175],
"cubes": [
{"origin": [-6, 37, -12.175], "size": [12, 8, 12], "inflate": 0.1, "uv": [47, 102]}
]
},
{
"name": "eyes_closed",
"parent": "head",
"pivot": [0, 40.95, -8.75],
"cubes": [
{"origin": [-5, 37.95, -10.25], "size": [10, 6, 3], "inflate": 0.1, "uv": [28, 100]}
]
},
{
"name": "jaw",
"parent": "head",
"pivot": [0, 33, -11.175],
"cubes": [
{"origin": [-4, 31, -18.175], "size": [8, 2, 7], "uv": [0, 0]}
] ]
} }
] ]
@@ -0,0 +1,104 @@
{
"format_version": "1.12.0",
"minecraft:geometry": [
{
"description": {
"identifier": "geometry.unknown",
"texture_width": 128,
"texture_height": 128,
"visible_bounds_width": 4,
"visible_bounds_height": 4.5,
"visible_bounds_offset": [0, 1.75, 0]
},
"bones": [
{
"name": "Glimmer",
"pivot": [0, 0, 0]
},
{
"name": "body",
"parent": "Glimmer",
"pivot": [0, 22.2, 0]
},
{
"name": "right_leg",
"parent": "body",
"pivot": [-5, 18.5, -8],
"cubes": [
{"origin": [-7.5, 0, -11.5], "size": [5, 19, 7], "uv": [36, 66]}
]
},
{
"name": "left_leg",
"parent": "body",
"pivot": [5, 18.5, -8],
"cubes": [
{"origin": [2.5, 0, -11.5], "size": [5, 19, 7], "uv": [36, 66], "mirror": true}
]
},
{
"name": "back_right_leg",
"parent": "body",
"pivot": [-5, 18.5, 8],
"cubes": [
{"origin": [-7.5, 0, 4.5], "size": [5, 19, 7], "uv": [36, 66]}
]
},
{
"name": "back_left_leg",
"parent": "body",
"pivot": [5, 18.5, 8],
"cubes": [
{"origin": [2.5, 0, 4.5], "size": [5, 19, 7], "uv": [36, 66], "mirror": true}
]
},
{
"name": "torso",
"parent": "body",
"pivot": [0, 19, 0],
"cubes": [
{"origin": [-6.5, 12, -12], "size": [13, 14, 24], "uv": [0, 0]},
{"origin": [-5.5, 15, 12], "size": [11, 16, 7], "pivot": [0, 23, 14.5], "rotation": [7.5, 0, 0], "uv": [0, 80]}
]
},
{
"name": "neck",
"parent": "torso",
"pivot": [0, 20.5, -11.5],
"cubes": [
{"origin": [-4.5, 14, -16], "size": [9, 19, 7], "uv": [0, 38]}
]
},
{
"name": "head",
"parent": "neck",
"pivot": [0, 33, -12.5],
"cubes": [
{"origin": [-4.5, 33, -17], "size": [9, 9, 9], "inflate": 0.1, "uv": [32, 38]},
{"origin": [-18.5, 41, -12], "size": [18, 14, 0], "uv": [0, 66]},
{"origin": [0.5, 41, -12], "size": [18, 14, 0], "uv": [0, 66], "mirror": true},
{"origin": [-3.5, 33, -22], "size": [7, 5, 5], "uv": [32, 56]}
]
},
{
"name": "right_ear",
"parent": "head",
"pivot": [-4.5, 41.25, -13],
"cubes": [
{"origin": [-9.5, 40, -13], "size": [5, 4, 0], "uv": [25, 38]},
{"origin": [-9.5, 40, -12.975], "size": [5, 4, 0], "uv": [0, 20]}
]
},
{
"name": "left_ear",
"parent": "head",
"pivot": [4.5, 41.25, -13],
"cubes": [
{"origin": [4.5, 40, -12.975], "size": [5, 4, 0], "uv": [0, 20], "mirror": true},
{"origin": [4.5, 40, -13], "size": [5, 4, 0], "uv": [25, 38], "mirror": true}
]
}
]
}
]
}
@@ -0,0 +1,102 @@
{
"format_version": "1.12.0",
"minecraft:geometry": [
{
"description": {
"identifier": "geometry.unknown",
"texture_width": 128,
"texture_height": 128,
"visible_bounds_width": 4,
"visible_bounds_height": 3.5,
"visible_bounds_offset": [0, 1.25, 0]
},
"bones": [
{
"name": "Glimmer",
"pivot": [0, 16.2, 3]
},
{
"name": "body",
"parent": "Glimmer",
"pivot": [0, 16.2, 3]
},
{
"name": "right_leg",
"parent": "body",
"pivot": [-4, 12.5, -5],
"cubes": [
{"origin": [-5.5, 0, -8.5], "size": [4, 13, 5], "uv": [0, 25]}
]
},
{
"name": "left_leg",
"parent": "body",
"pivot": [4, 12.5, -5],
"cubes": [
{"origin": [1.5, 0, -8.5], "size": [4, 13, 5], "uv": [0, 25], "mirror": true}
]
},
{
"name": "back_right_leg",
"parent": "body",
"pivot": [-5, 12.5, 6],
"cubes": [
{"origin": [-6.5, 0, 3.5], "size": [4, 13, 5], "uv": [0, 25]}
]
},
{
"name": "back_left_leg",
"parent": "body",
"pivot": [5, 12.5, 6],
"cubes": [
{"origin": [2.5, 0, 3.5], "size": [4, 13, 5], "uv": [0, 25], "mirror": true}
]
},
{
"name": "torso",
"parent": "body",
"pivot": [0, 13, 3],
"cubes": [
{"origin": [-5, 7, -8], "size": [10, 10, 17], "uv": [58, 0]},
{"origin": [-5.5, 9, 8], "size": [11, 16, 7], "pivot": [0, 17, 17.5], "rotation": [7.5, 0, 0], "uv": [18, 21]}
]
},
{
"name": "neck",
"parent": "torso",
"pivot": [0, 14.5, -8.5],
"cubes": [
{"origin": [-3.5, 8, -13], "size": [7, 14, 7], "uv": [30, 0]}
]
},
{
"name": "head",
"parent": "neck",
"pivot": [0, 21, -9.5],
"cubes": [
{"origin": [-3.5, 21, -14], "size": [7, 8, 8], "inflate": 0.1, "uv": [0, 0]},
{"origin": [-2.5, 21, -19], "size": [5, 4, 5], "uv": [0, 16]}
]
},
{
"name": "right_ear",
"parent": "head",
"pivot": [-3.5, 27.25, -10],
"cubes": [
{"origin": [-7.5, 26, -10], "size": [4, 4, 0], "uv": [53, 0]}
]
},
{
"name": "left_ear",
"parent": "head",
"pivot": [3.5, 27.25, -10],
"cubes": [
{"origin": [3.5, 26, -10], "size": [4, 4, 0], "uv": [53, 0], "mirror": true},
{"origin": [3.5, 26, -9.975], "size": [4, 4, 0], "uv": [61, 0], "mirror": true},
{"origin": [-7.5, 26, -9.975], "size": [4, 4, 0], "uv": [61, 0]}
]
}
]
}
]
}
@@ -1,231 +0,0 @@
{
"format_version": "1.12.0",
"minecraft:geometry": [
{
"description": {
"identifier": "geometry.spitbug",
"texture_width": 256,
"texture_height": 256,
"visible_bounds_width": 6,
"visible_bounds_height": 5.5,
"visible_bounds_offset": [0, 2.25, 0]
},
"bones": [
{
"name": "root",
"pivot": [0, 0, 0]
},
{
"name": "body",
"parent": "root",
"pivot": [0, 36, 0],
"cubes": [
{"origin": [-11.5, 36, -18], "size": [23, 18, 37], "inflate": -0.05, "uv": [0, 103]},
{"origin": [-9.5, 54, -35], "size": [19, 7, 59], "uv": [0, 0]},
{"origin": [-7.5, 54, -52], "size": [15, 7, 17], "uv": [112, 28]},
{"origin": [-6.5, 42, -51.75], "size": [3, 12, 5], "uv": [34, 23]},
{"origin": [3.5, 42, -51.75], "size": [3, 12, 5], "uv": [34, 23], "mirror": true},
{"origin": [-7.5, 52, -52], "size": [15, 2, 0], "uv": [0, 24]},
{"origin": [-7.5, 44, -52], "size": [0, 10, 17], "uv": [5, 29]},
{"origin": [-9.5, 47, -35], "size": [2, 7, 0], "uv": [37, 16]},
{"origin": [-9.5, 45, -35], "size": [0, 9, 17], "uv": [0, 18]},
{"origin": [9.5, 45, -35], "size": [0, 9, 17], "uv": [0, 18], "mirror": true},
{"origin": [7.5, 47, -35], "size": [2, 7, 0], "uv": [37, 16], "mirror": true},
{"origin": [7.5, 44, -52], "size": [0, 10, 17], "uv": [5, 29], "mirror": true},
{"origin": [-11.5, 32.1, -18], "size": [23, 4, 33], "inflate": -0.05, "uv": [0, 66]}
]
},
{
"name": "jaw",
"parent": "body",
"pivot": [-3.07143, 33.92857, -16],
"cubes": [
{"origin": [-8.5, 32, -51], "size": [17, 2, 18], "uv": [97, 0]},
{"origin": [-11.5, 30, -33], "size": [23, 4, 17], "uv": [79, 66]},
{"origin": [-11.5, 34, -33], "size": [0, 8, 17], "uv": [0, -17]},
{"origin": [-11.5, 34, -33], "size": [3, 8, 0], "uv": [0, 8]},
{"origin": [8.5, 34, -33], "size": [3, 8, 0], "uv": [0, 8], "mirror": true},
{"origin": [11.5, 34, -33], "size": [0, 8, 17], "uv": [0, -17], "mirror": true},
{"origin": [-8.5, 34, -51], "size": [0, 8, 18], "uv": [0, -2]},
{"origin": [-4.5, 32.5, -52.575], "size": [3, 8, 4], "pivot": [-3, 36.5, -50.575], "rotation": [22.5, 0, 0], "uv": [35, 0]},
{"origin": [1.5, 32.5, -52.575], "size": [3, 8, 4], "pivot": [3, 36.5, -50.575], "rotation": [22.5, 0, 0], "uv": [35, 0], "mirror": true},
{"origin": [-8.5, 34, -51], "size": [17, 8, 0], "uv": [0, 26]},
{"origin": [8.5, 34, -51], "size": [0, 8, 18], "uv": [0, -2], "mirror": true}
]
},
{
"name": "rightEye",
"parent": "body",
"pivot": [-11, 45.5, -17],
"cubes": [
{"origin": [-12, 45.5, -19], "size": [3, 3, 3], "uv": [83, 114]}
]
},
{
"name": "leftEye",
"parent": "body",
"pivot": [11, 45.5, -17],
"cubes": [
{"origin": [9, 45.5, -19], "size": [3, 3, 3], "uv": [83, 114], "mirror": true}
]
},
{
"name": "rightGrip",
"parent": "body",
"pivot": [-11.5, 54, -16],
"rotation": [0, 0, 90]
},
{
"name": "leftGrip",
"parent": "body",
"pivot": [11.5, 54, -16],
"rotation": [0, 0, -90]
},
{
"name": "backRightThigh",
"parent": "root",
"pivot": [-11.5, 37, 10],
"cubes": [
{"origin": [-20.5, 33, 8], "size": [9, 4, 4], "uv": [83, 120]}
]
},
{
"name": "backRightKnee",
"parent": "backRightThigh",
"pivot": [-20.5, 37, 10],
"rotation": [0, 0, -90],
"cubes": [
{"origin": [-34.5, 32, 7], "size": [14, 5, 6], "inflate": 0.025, "uv": [83, 103]}
]
},
{
"name": "backRightLeg",
"parent": "backRightKnee",
"pivot": [-34.5, 32, 10],
"rotation": [0, 0, 90],
"cubes": [
{"origin": [-53.5, 32, 8], "size": [19, 4, 4], "uv": [97, 20]}
]
},
{
"name": "backRightFoot",
"parent": "backRightLeg",
"pivot": [-53.5, 32, 10],
"rotation": [0, 0, -90],
"cubes": [
{"origin": [-67.5, 30, 9], "size": [14, 2, 2], "inflate": 0.025, "uv": [97, 28]},
{"origin": [-76.5, 30, 10], "size": [9, 2, 0], "uv": [97, 32]}
]
},
{
"name": "backLeftThigh",
"parent": "root",
"pivot": [11.5, 37, 10],
"cubes": [
{"origin": [11.5, 33, 8], "size": [9, 4, 4], "uv": [83, 120]}
]
},
{
"name": "backLeftKnee",
"parent": "backLeftThigh",
"pivot": [20.5, 37, 10],
"rotation": [0, 0, 90],
"cubes": [
{"origin": [20.5, 32, 7], "size": [14, 5, 6], "inflate": 0.025, "uv": [83, 103]}
]
},
{
"name": "backLeftLeg",
"parent": "backLeftKnee",
"pivot": [34.5, 32, 10],
"rotation": [0, 0, -90],
"cubes": [
{"origin": [34.5, 32, 8], "size": [19, 4, 4], "uv": [97, 20]}
]
},
{
"name": "backLeftFoot",
"parent": "backLeftLeg",
"pivot": [53.5, 32, 10],
"rotation": [0, 0, 90],
"cubes": [
{"origin": [53.5, 30, 9], "size": [14, 2, 2], "inflate": 0.025, "uv": [97, 28]},
{"origin": [67.5, 30, 10], "size": [9, 2, 0], "uv": [97, 32], "mirror": true}
]
},
{
"name": "frontRightThigh",
"parent": "root",
"pivot": [-11.5, 37, -10],
"cubes": [
{"origin": [-20.5, 33, -12], "size": [9, 4, 4], "uv": [83, 120]}
]
},
{
"name": "frontRightKnee",
"parent": "frontRightThigh",
"pivot": [-20.5, 37, -10],
"rotation": [0, 0, -90],
"cubes": [
{"origin": [-34.5, 32, -13], "size": [14, 5, 6], "inflate": 0.025, "uv": [83, 103]}
]
},
{
"name": "frontRightLeg",
"parent": "frontRightKnee",
"pivot": [-34.5, 32, -10],
"rotation": [0, 0, 90],
"cubes": [
{"origin": [-53.5, 32, -12], "size": [19, 4, 4], "uv": [97, 20]}
]
},
{
"name": "frontRightFoot",
"parent": "frontRightLeg",
"pivot": [-53.5, 32, -10],
"rotation": [0, 0, -90],
"cubes": [
{"origin": [-67.5, 30, -11], "size": [14, 2, 2], "inflate": 0.025, "uv": [97, 28]},
{"origin": [-76.5, 30, -10], "size": [9, 2, 0], "uv": [97, 32]}
]
},
{
"name": "frontLeftThigh",
"parent": "root",
"pivot": [11.5, 37, -10],
"cubes": [
{"origin": [11.5, 33, -12], "size": [9, 4, 4], "uv": [83, 120]}
]
},
{
"name": "frontLeftKnee",
"parent": "frontLeftThigh",
"pivot": [20.5, 37, -10],
"rotation": [0, 0, 90],
"cubes": [
{"origin": [20.5, 32, -13], "size": [14, 5, 6], "inflate": 0.025, "uv": [83, 103]}
]
},
{
"name": "frontLeftLeg",
"parent": "frontLeftKnee",
"pivot": [34.5, 32, -10],
"rotation": [0, 0, -90],
"cubes": [
{"origin": [34.5, 32, -12], "size": [19, 4, 4], "uv": [97, 20]}
]
},
{
"name": "frontLeftFoot",
"parent": "frontLeftLeg",
"pivot": [53.5, 32, -10],
"rotation": [0, 0, 90],
"cubes": [
{"origin": [53.5, 30, -11], "size": [14, 2, 2], "inflate": 0.025, "uv": [97, 28]},
{"origin": [67.5, 30, -10], "size": [9, 2, 0], "uv": [97, 32], "mirror": true}
]
}
]
}
]
}
@@ -17,30 +17,26 @@
"block.antarchy.ouranwood_button": "Ouranwood Button", "block.antarchy.ouranwood_button": "Ouranwood Button",
"block.antarchy.ouranwood_leaves": "Ouranwood Leaves", "block.antarchy.ouranwood_leaves": "Ouranwood Leaves",
"block.antarchy.ouranwood_acorn": "Ouranwood Acorn", "block.antarchy.ouranwood_acorn": "Ouranwood Acorn",
"block.antarchy.ouranwood_vine": "Ouranwood Vine",
"block.antarchy.ouranwood_sign": "Ouranwood Sign", "block.antarchy.ouranwood_sign": "Ouranwood Sign",
"block.antarchy.ouranwood_hanging_sign": "Ouranwood Hanging Sign", "block.antarchy.ouranwood_hanging_sign": "Ouranwood Hanging Sign",
"block.antarchy.orange_milkweed": "Orange Milkweed", "block.antarchy.orange_milkweed": "Orange Milkweed",
"block.antarchy.pink_milkweed": "Pink Milkweed", "block.antarchy.pink_milkweed": "Pink Milkweed",
"block.antarchy.hushweed": "Hushweed", "block.antarchy.hushweed": "Hushweed",
"block.antarchy.big_bush": "Big Bush",
"block.antarchy.big_bush_part": "Big Bush",
"block.antarchy.very_short_grass": "Very Short Grass",
"block.antarchy.very_tall_grass": "Very Tall Grass",
"block.antarchy.umbral_moss_block": "Umbral Moss Block", "block.antarchy.umbral_moss_block": "Umbral Moss Block",
"block.antarchy.umbral_moss_carpet": "Umbral Moss Carpet", "block.antarchy.umbral_moss_carpet": "Umbral Moss Carpet",
"block.antarchy.amber_moss_block": "Amber Moss Block",
"block.antarchy.amber_moss_carpet": "Amber Moss Carpet",
"block.antarchy.amber_lichen": "Amber Lichen",
"block.antarchy.bile_vein": "Bile Vein",
"block.antarchy.duplicator_sapling": "Duplicator Sapling", "block.antarchy.duplicator_sapling": "Duplicator Sapling",
"block.antarchy.creepvine": "Creepvine",
"block.antarchy.duct_tape": "Duct Tape", "block.antarchy.duct_tape": "Duct Tape",
"block.antarchy.infested_rooted_dirt": "Infested Rooted Dirt", "block.antarchy.infested_rooted_dirt": "Infested Rooted Dirt",
"block.antarchy.infested_coarse_dirt": "Infested Coarse Dirt", "block.antarchy.infested_coarse_dirt": "Infested Coarse Dirt",
"block.antarchy.nyxite": "Nyxite", "block.antarchy.nyxite": "Nyxite",
"block.antarchy.myrmite": "Myrmite",
"block.antarchy.broodstone": "Broodstone",
"block.antarchy.polished_nyxite": "Polished Nyxite", "block.antarchy.polished_nyxite": "Polished Nyxite",
"block.antarchy.chiseled_nyxite": "Chiseled Nyxite", "block.antarchy.chiseled_nyxite": "Chiseled Nyxite",
"block.antarchy.nyxite_bricks": "Nyxite Bricks", "block.antarchy.nyxite_bricks": "Nyxite Bricks",
"block.antarchy.chiten_block": "Chiten Block",
"block.antarchy.chiten_spike": "Chiten Spike",
"block.antarchy.shellstone": "Shellstone", "block.antarchy.shellstone": "Shellstone",
"block.antarchy.polished_shellstone": "Polished Shellstone", "block.antarchy.polished_shellstone": "Polished Shellstone",
"block.antarchy.shellstone_bricks": "Shellstone Bricks", "block.antarchy.shellstone_bricks": "Shellstone Bricks",
@@ -72,7 +68,9 @@
"block.antarchy.nyxite_spike": "Nyxite Spike", "block.antarchy.nyxite_spike": "Nyxite Spike",
"block.antarchy.potent_nyxite": "Potent Nyxite", "block.antarchy.potent_nyxite": "Potent Nyxite",
"block.antarchy.triffid_goo_block": "Triffid Goo Block", "block.antarchy.triffid_goo_block": "Triffid Goo Block",
"block.antarchy.elythia_portal": "Elythia Portal",
"block.antarchy.cloud_block": "Cloud Block", "block.antarchy.cloud_block": "Cloud Block",
"block.antarchy.thoraxis_portal": "Thoraxis Portal",
"block.antarchy.antimetal": "Antimetal", "block.antarchy.antimetal": "Antimetal",
"block.antarchy.polished_antimetal": "Polished Antimetal", "block.antarchy.polished_antimetal": "Polished Antimetal",
"block.antarchy.antimetal_scaffolding": "Antimetal Scaffolding", "block.antarchy.antimetal_scaffolding": "Antimetal Scaffolding",
@@ -101,13 +99,10 @@
"block.antarchy.smooth_dream_sandstone_slab": "Smooth Dream Sandstone Slab", "block.antarchy.smooth_dream_sandstone_slab": "Smooth Dream Sandstone Slab",
"block.antarchy.cut_dream_sandstone_slab": "Cut Dream Sandstone Slab", "block.antarchy.cut_dream_sandstone_slab": "Cut Dream Sandstone Slab",
"block.antarchy.bed_bug_egg": "Bed Bug Egg", "block.antarchy.bed_bug_egg": "Bed Bug Egg",
"block.antarchy.creeping_horror_egg": "Creeping Horror Egg",
"block.antarchy.lurking_terror_egg": "Lurking Terror Egg",
"block.antarchy.wasp_nest": "Wasp Nest", "block.antarchy.wasp_nest": "Wasp Nest",
"block.antarchy.red_ant_nest": "Red Ant Nest", "block.antarchy.red_ant_nest": "Red Ant Nest",
"block.antarchy.brown_ant_nest": "Brown Ant Nest", "block.antarchy.brown_ant_nest": "Brown Ant Nest",
"block.antarchy.rainbow_ant_nest": "Rainbow Ant Nest", "block.antarchy.rainbow_ant_nest": "Rainbow Ant Nest",
"block.antarchy.termite_nest": "Termite Nest",
"block.antarchy.uranium_ore": "Uranium Ore", "block.antarchy.uranium_ore": "Uranium Ore",
"block.antarchy.deepslate_uranium_ore": "Deepslate Uranium Ore", "block.antarchy.deepslate_uranium_ore": "Deepslate Uranium Ore",
"block.antarchy.titanium_ore": "Titanium Ore", "block.antarchy.titanium_ore": "Titanium Ore",
@@ -139,8 +134,8 @@
"entity.antarchy.apple_cow": "Apple Cow", "entity.antarchy.apple_cow": "Apple Cow",
"entity.antarchy.golden_apple_cow": "Golden Apple Cow", "entity.antarchy.golden_apple_cow": "Golden Apple Cow",
"entity.antarchy.enchanted_golden_apple_cow": "Enchanted Golden Apple Cow", "entity.antarchy.enchanted_golden_apple_cow": "Enchanted Golden Apple Cow",
"entity.antarchy.honeyed_apple_cow": "Honeyed Apple Cow",
"entity.antarchy.easter_bunny": "Easter Bunny", "entity.antarchy.easter_bunny": "Easter Bunny",
"entity.antarchy.glimmer": "Glimmer",
"entity.antarchy.flying_squirrel": "Flying Squirrel", "entity.antarchy.flying_squirrel": "Flying Squirrel",
"entity.antarchy.caterpillar": "Caterpillar", "entity.antarchy.caterpillar": "Caterpillar",
"entity.antarchy.butterfly": "Butterfly", "entity.antarchy.butterfly": "Butterfly",
@@ -148,7 +143,6 @@
"entity.antarchy.red_ant": "Red Ant", "entity.antarchy.red_ant": "Red Ant",
"entity.antarchy.brown_ant": "Brown Ant", "entity.antarchy.brown_ant": "Brown Ant",
"entity.antarchy.rainbow_ant": "Rainbow Ant", "entity.antarchy.rainbow_ant": "Rainbow Ant",
"entity.antarchy.termite": "Termite",
"entity.antarchy.diamond_minecart": "The Diamond Minecart", "entity.antarchy.diamond_minecart": "The Diamond Minecart",
"entity.antarchy.dr_trayaurus": "Dr. Trayaurus", "entity.antarchy.dr_trayaurus": "Dr. Trayaurus",
"entity.antarchy.cloud_shark": "Cloud Shark", "entity.antarchy.cloud_shark": "Cloud Shark",
@@ -157,9 +151,6 @@
"entity.antarchy.octopus_bomb": "Octopus Bomb", "entity.antarchy.octopus_bomb": "Octopus Bomb",
"entity.antarchy.nightmare": "Nightmare", "entity.antarchy.nightmare": "Nightmare",
"entity.antarchy.bed_bug": "Bed Bug", "entity.antarchy.bed_bug": "Bed Bug",
"entity.antarchy.stink_bug": "Stink Bug",
"entity.antarchy.jumpy_bug": "Jumpy Bug",
"entity.antarchy.spit_bug": "Spit Bug",
"entity.antarchy.wasp": "Wasp", "entity.antarchy.wasp": "Wasp",
"entity.antarchy.bomber": "Bomber", "entity.antarchy.bomber": "Bomber",
"entity.antarchy.moleworm": "Moleworm", "entity.antarchy.moleworm": "Moleworm",
@@ -169,8 +160,6 @@
"entity.antarchy.triffid": "Triffid", "entity.antarchy.triffid": "Triffid",
"entity.antarchy.toreterror": "Toreterror", "entity.antarchy.toreterror": "Toreterror",
"entity.antarchy.water_bomb": "Water Bomb", "entity.antarchy.water_bomb": "Water Bomb",
"entity.antarchy.creeping_horror": "Creeping Horror",
"entity.antarchy.lurking_terror": "Lurking Terror",
"subtitles.antarchy.mantis_ambient": "Mantis clicks", "subtitles.antarchy.mantis_ambient": "Mantis clicks",
"subtitles.antarchy.mantis_hurt": "Mantis screeches", "subtitles.antarchy.mantis_hurt": "Mantis screeches",
"subtitles.antarchy.mantis_attack": "Mantis snaps", "subtitles.antarchy.mantis_attack": "Mantis snaps",
@@ -178,13 +167,8 @@
"item.antarchy.big_bertha": "Big Bertha", "item.antarchy.big_bertha": "Big Bertha",
"item.antarchy.wasp_nest": "Wasp Nest", "item.antarchy.wasp_nest": "Wasp Nest",
"item.antarchy.stink_bug": "Stink Bug", "item.antarchy.stink_bug": "Stink Bug",
"item.antarchy.creeping_horror_egg": "Creeping Horror Egg",
"item.antarchy.lurking_terror_egg": "Lurking Terror Egg",
"item.antarchy.stink_bug_spawn_egg": "Stink Bug Spawn Egg",
"item.antarchy.wasp_spawn_egg": "Wasp Spawn Egg", "item.antarchy.wasp_spawn_egg": "Wasp Spawn Egg",
"item.antarchy.bomber_spawn_egg": "Bomber Spawn Egg", "item.antarchy.bomber_spawn_egg": "Bomber Spawn Egg",
"item.antarchy.jumpy_bug_spawn_egg": "Jumpy Bug Spawn Egg",
"item.antarchy.spit_bug_spawn_egg": "Spit Bug Spawn Egg",
"item.antarchy.big_bertha_blade": "Big Bertha Blade", "item.antarchy.big_bertha_blade": "Big Bertha Blade",
"item.antarchy.big_bertha_handle": "Big Bertha Handle", "item.antarchy.big_bertha_handle": "Big Bertha Handle",
"item.antarchy.big_bertha_hilt": "Big Bertha Hilt", "item.antarchy.big_bertha_hilt": "Big Bertha Hilt",
@@ -270,23 +254,18 @@
"item.antarchy.polished_antimetal": "Polished Antimetal", "item.antarchy.polished_antimetal": "Polished Antimetal",
"item.antarchy.antimetal_scaffolding": "Antimetal Scaffolding", "item.antarchy.antimetal_scaffolding": "Antimetal Scaffolding",
"item.antarchy.ouranwood_acorn": "Ouranwood Acorn", "item.antarchy.ouranwood_acorn": "Ouranwood Acorn",
"item.antarchy.ouranwood_vine": "Ouranwood Vine",
"item.antarchy.ouranwood_boat": "Ouranwood Boat", "item.antarchy.ouranwood_boat": "Ouranwood Boat",
"item.antarchy.ouranwood_chest_boat": "Ouranwood Chest Boat", "item.antarchy.ouranwood_chest_boat": "Ouranwood Chest Boat",
"item.antarchy.big_bush": "Big Bush",
"item.antarchy.big_bush.tooltip": "Can be bonemealed",
"item.antarchy.very_short_grass": "Very Short Grass",
"item.antarchy.very_tall_grass": "Very Tall Grass",
"item.antarchy.orange_milkweed": "Orange Milkweed", "item.antarchy.orange_milkweed": "Orange Milkweed",
"item.antarchy.pink_milkweed": "Pink Milkweed", "item.antarchy.pink_milkweed": "Pink Milkweed",
"item.antarchy.hushweed": "Hushweed", "item.antarchy.hushweed": "Hushweed",
"item.antarchy.umbral_moss_block": "Umbral Moss Block", "item.antarchy.umbral_moss_block": "Umbral Moss Block",
"item.antarchy.umbral_moss_carpet": "Umbral Moss Carpet", "item.antarchy.umbral_moss_carpet": "Umbral Moss Carpet",
"item.antarchy.amber_moss_block": "Amber Moss Block",
"item.antarchy.amber_moss_carpet": "Amber Moss Carpet",
"item.antarchy.amber_lichen": "Amber Lichen",
"item.antarchy.bile_vein": "Bile Vein",
"item.antarchy.creepvine": "Creepvine",
"item.antarchy.chiten": "Chiten",
"item.antarchy.chiten_block": "Chiten Block",
"item.antarchy.chiten_spike": "Chiten Spike",
"item.antarchy.myrmite": "Myrmite",
"item.antarchy.broodstone": "Broodstone",
"item.antarchy.torchflower_bush": "Torchflower Bush", "item.antarchy.torchflower_bush": "Torchflower Bush",
"block.antarchy.torchflower_bush": "Torchflower Bush", "block.antarchy.torchflower_bush": "Torchflower Bush",
"item.antarchy.mud_pie": "Mud Pie", "item.antarchy.mud_pie": "Mud Pie",
@@ -374,12 +353,11 @@
"item.antarchy.red_ant_spawn_egg": "Red Ant Spawn Egg", "item.antarchy.red_ant_spawn_egg": "Red Ant Spawn Egg",
"item.antarchy.brown_ant_spawn_egg": "Brown Ant Spawn Egg", "item.antarchy.brown_ant_spawn_egg": "Brown Ant Spawn Egg",
"item.antarchy.rainbow_ant_spawn_egg": "Rainbow Ant Spawn Egg", "item.antarchy.rainbow_ant_spawn_egg": "Rainbow Ant Spawn Egg",
"item.antarchy.termite_spawn_egg": "Termite Spawn Egg",
"item.antarchy.golden_apple_cow_spawn_egg": "Golden Apple Cow Spawn Egg", "item.antarchy.golden_apple_cow_spawn_egg": "Golden Apple Cow Spawn Egg",
"item.antarchy.enchanted_golden_apple_cow_spawn_egg": "Enchanted Golden Apple Cow Spawn Egg", "item.antarchy.enchanted_golden_apple_cow_spawn_egg": "Enchanted Golden Apple Cow Spawn Egg",
"item.antarchy.honeyed_apple_cow_spawn_egg": "Honeyed Apple Cow Spawn Egg",
"item.antarchy.dr_trayaurus_spawn_egg": "Dr. Trayaurus Spawn Egg", "item.antarchy.dr_trayaurus_spawn_egg": "Dr. Trayaurus Spawn Egg",
"item.antarchy.easter_bunny_spawn_egg": "Easter Bunny Spawn Egg", "item.antarchy.easter_bunny_spawn_egg": "Easter Bunny Spawn Egg",
"item.antarchy.glimmer_spawn_egg": "Glimmer Spawn Egg",
"item.antarchy.flying_squirrel_spawn_egg": "Flying Squirrel Spawn Egg", "item.antarchy.flying_squirrel_spawn_egg": "Flying Squirrel Spawn Egg",
"item.antarchy.caterpillar_spawn_egg": "Caterpillar Spawn Egg", "item.antarchy.caterpillar_spawn_egg": "Caterpillar Spawn Egg",
"item.antarchy.butterfly_spawn_egg": "Butterfly Spawn Egg", "item.antarchy.butterfly_spawn_egg": "Butterfly Spawn Egg",
@@ -390,10 +368,7 @@
"item.antarchy.octopus_bomb_spawn_egg": "Octopus Bomb Spawn Egg", "item.antarchy.octopus_bomb_spawn_egg": "Octopus Bomb Spawn Egg",
"item.antarchy.nightmare_spawn_egg": "Nightmare Spawn Egg", "item.antarchy.nightmare_spawn_egg": "Nightmare Spawn Egg",
"item.antarchy.toreterror_spawn_egg": "Toreterror Spawn Egg", "item.antarchy.toreterror_spawn_egg": "Toreterror Spawn Egg",
"item.antarchy.creeping_horror_spawn_egg": "Creeping Horror Spawn Egg",
"item.antarchy.lurking_terror_spawn_egg": "Lurking Terror Spawn Egg",
"item.antarchy.water_cannon": "Water Cannon", "item.antarchy.water_cannon": "Water Cannon",
"item.antarchy.primordial_scute": "Primordial Scute",
"item.antarchy.primordial_helmet": "Primordial Helmet", "item.antarchy.primordial_helmet": "Primordial Helmet",
"item.antarchy.primordial_chestplate": "Primordial Chestplate", "item.antarchy.primordial_chestplate": "Primordial Chestplate",
"item.antarchy.primordial_leggings": "Primordial Leggings", "item.antarchy.primordial_leggings": "Primordial Leggings",
@@ -438,6 +413,7 @@
"effect.antarchy.paralyzed": "Paralyzed", "effect.antarchy.paralyzed": "Paralyzed",
"effect.antarchy.inverted": "Inverted", "effect.antarchy.inverted": "Inverted",
"effect.antarchy.stinky": "Stinky", "effect.antarchy.stinky": "Stinky",
"effect.antarchy.glimmers_grace": "Glimmer's Grace",
"effect.antarchy.shrinking": "Shrinking", "effect.antarchy.shrinking": "Shrinking",
"effect.antarchy.growth": "Growth", "effect.antarchy.growth": "Growth",
"effect.antarchy.bloodglass_ward": "Bloodglass Ward", "effect.antarchy.bloodglass_ward": "Bloodglass Ward",
@@ -476,8 +452,6 @@
"advancements.antarchy.fallen_kingdom_castle.description": "Discover the Fallen Kingdom Castle.", "advancements.antarchy.fallen_kingdom_castle.description": "Discover the Fallen Kingdom Castle.",
"advancements.antarchy.fallen_king_crown.title": "Chunks would load when I gave the word...", "advancements.antarchy.fallen_king_crown.title": "Chunks would load when I gave the word...",
"advancements.antarchy.fallen_king_crown.description": "Obtain the Fallen King's Crown.", "advancements.antarchy.fallen_king_crown.description": "Obtain the Fallen King's Crown.",
"advancements.antarchy.visit_cavaryn.title": "You will be Termite-ated",
"advancements.antarchy.visit_cavaryn.description": "Use a termite to reach Cavaryn.",
"advancements.antarchy.the_lab.title": "Hello Everyone, Dan Here!", "advancements.antarchy.the_lab.title": "Hello Everyone, Dan Here!",
"advancements.antarchy.the_lab.description": "Discover Dr. Trayaurus' lab.", "advancements.antarchy.the_lab.description": "Discover Dr. Trayaurus' lab.",
"advancements.antarchy.sweater_dreams.title": "Sweater Dreams", "advancements.antarchy.sweater_dreams.title": "Sweater Dreams",
@@ -514,6 +488,10 @@
"advancements.antarchy.water_cannon_craft.description": "Obtain a Water Cannon.", "advancements.antarchy.water_cannon_craft.description": "Obtain a Water Cannon.",
"advancements.antarchy.kill_toreterror.title": "More like Tore-Terrible Aim!", "advancements.antarchy.kill_toreterror.title": "More like Tore-Terrible Aim!",
"advancements.antarchy.kill_toreterror.description": "Defeat the Toreterror.", "advancements.antarchy.kill_toreterror.description": "Defeat the Toreterror.",
"advancements.antarchy.challenge_games.title": "Challenge Games!",
"advancements.antarchy.challenge_games.description": "Enter the Ruined Arena.",
"advancements.antarchy.bugged_out.title": "Bugged Out",
"advancements.antarchy.bugged_out.description": "Defeat the Alpha Mantis.",
"death.attack.bed_bug_bite": "%1$s got bit by the bed bugs", "death.attack.bed_bug_bite": "%1$s got bit by the bed bugs",
"death.attack.bed_bug_bite.player": "%1$s got bit by the bed bugs while fighting %2$s", "death.attack.bed_bug_bite.player": "%1$s got bit by the bed bugs while fighting %2$s",
"message.antarchy.dread_too_scared_to_sleep": "You are too scared to sleep.", "message.antarchy.dread_too_scared_to_sleep": "You are too scared to sleep.",
@@ -663,15 +641,11 @@
"subtitles.antarchy.toreterror_hurt": "Toreterror hurts", "subtitles.antarchy.toreterror_hurt": "Toreterror hurts",
"subtitles.antarchy.toreterror_death": "Toreterror dies", "subtitles.antarchy.toreterror_death": "Toreterror dies",
"subtitles.antarchy.toreterror_bomber_fire": "Toreterror launches bombers", "subtitles.antarchy.toreterror_bomber_fire": "Toreterror launches bombers",
"subtitles.antarchy.toreterror_spin": "Toreterror spins",
"subtitles.antarchy.toreterror_ricochet": "Toreterror ricochets",
"subtitles.antarchy.water_cannon_fire": "Water Cannon fires",
"subtitles.antarchy.toreterror_jump_up": "Toreterror jumps", "subtitles.antarchy.toreterror_jump_up": "Toreterror jumps",
"subtitles.antarchy.toreterror_jump_land": "Toreterror lands", "subtitles.antarchy.toreterror_jump_land": "Toreterror lands",
"subtitles.antarchy.creeping_horror_growl": "Creeping Horror growls",
"subtitles.antarchy.creeping_horror_hurt": "Creeping Horror hurts",
"subtitles.antarchy.creeping_horror_bite": "Creeping Horror bites",
"subtitles.antarchy.lurking_terror_snarl": "Lurking Terror snarls",
"subtitles.antarchy.lurking_terror_hurt": "Lurking Terror hurts",
"subtitles.antarchy.lurking_terror_bite": "Lurking Terror bites",
"subtitles.antarchy.lurking_terror_fly_loop": "Lurking Terror flies",
"subtitles.antarchy.stinky_fly": "Stinky flies buzz", "subtitles.antarchy.stinky_fly": "Stinky flies buzz",
"item.minecraft.potion.effect.inversion": "Potion of Inversion", "item.minecraft.potion.effect.inversion": "Potion of Inversion",
"item.minecraft.potion.effect.long_inversion": "Potion of Inversion", "item.minecraft.potion.effect.long_inversion": "Potion of Inversion",
@@ -737,53 +711,11 @@
"item.minecraft.lingering_potion.effect.strong_haste": "Lingering Potion of Haste II", "item.minecraft.lingering_potion.effect.strong_haste": "Lingering Potion of Haste II",
"item.minecraft.tipped_arrow.effect.haste": "Arrow of Haste", "item.minecraft.tipped_arrow.effect.haste": "Arrow of Haste",
"item.minecraft.tipped_arrow.effect.strong_haste": "Arrow of Haste II", "item.minecraft.tipped_arrow.effect.strong_haste": "Arrow of Haste II",
"subtitles.antarchy.squidzooka_fire": "Squidzooka fires",
"advancements.antarchy.visit_elythia.title": "InterdimANTsional",
"advancements.antarchy.visit_elythia.description": "Use a brown ant to reach Elythia.",
"advancements.antarchy.visit_thoraxis.title": "Ant-ger Management",
"advancements.antarchy.visit_thoraxis.description": "Use a red ant to reach Thoraxis.",
"advancements.antarchy.visit_cavaryn.title": "You will be Termite-ated",
"advancements.antarchy.visit_cavaryn.description": "Use a termite to reach Cavaryn.",
"advancements.antarchy.ultimate_armor.title": "Ultimate Protection",
"advancements.antarchy.ultimate_armor.description": "Collect the full set of Ultimate Armor.",
"advancements.antarchy.ultimate_bow.title": "Bowhemian Rhapsody",
"advancements.antarchy.ultimate_bow.description": "Obtain an Ultimate Bow.",
"advancements.antarchy.kill_molevore.title": "Moley Poley",
"advancements.antarchy.kill_molevore.description": "Kill a Molevore.",
"advancements.antarchy.water_cannon_craft.title": "Wetter is Better!",
"advancements.antarchy.water_cannon_craft.description": "Obtain a Water Cannon.",
"advancements.antarchy.kill_toreterror.title": "More like Tore-Terrible Aim!",
"advancements.antarchy.kill_toreterror.description": "Defeat the Toreterror.",
"advancements.antarchy.cancel_out.title": "1 - 1 = ?", "advancements.antarchy.cancel_out.title": "1 - 1 = ?",
"advancements.antarchy.cancel_out.description": "Have Growth and Shrinking active at the same time.", "advancements.antarchy.cancel_out.description": "Have Growth and Shrinking active at the same time.",
"death.attack.bed_bug_bite": "%1$s got bit by the bed bugs",
"death.attack.bed_bug_bite.player": "%1$s got bit by the bed bugs while fighting %2$s",
"death.attack.kraken_mauling": "%1$s was dragged under by the Kraken",
"death.attack.kraken_mauling.player": "%1$s was dragged under by the Kraken while fighting %2$s",
"death.attack.kraken_lightning": "%1$s was struck down by the Kraken's storm",
"death.attack.kraken_lightning.player": "%1$s was struck down by the Kraken's storm while fighting %2$s",
"death.attack.nightmare_mauling": "%1$s was devoured by the Nightmare",
"death.attack.nightmare_mauling.player": "%1$s was devoured by the Nightmare while fighting %2$s",
"death.attack.basilisk_bite": "%1$s was swallowed by a Basilisk",
"death.attack.basilisk_bite.player": "%1$s was swallowed by a Basilisk while fighting %2$s",
"death.attack.emperor_scorpion_sting": "%1$s was stung by the Emperor Scorpion",
"death.attack.emperor_scorpion_sting.player": "%1$s was stung by the Emperor Scorpion while fighting %2$s",
"death.attack.cornea_stalk_prick": "%1$s was pricked to death by a Cornea Stalk",
"death.attack.toreterror_spin": "%1$s was beybladed to death by Toreterror",
"death.attack.toreterror_spin.player": "%1$s was beybladed to death by Toreterror",
"death.attack.toreterror_jump": "%1$s was pounded to death by Toreterror",
"death.attack.toreterror_jump.player": "%1$s was pounded to death by Toreterror",
"death.attack.water_soaked": "%1$s was super soaked to death by %2$s",
"death.attack.water_soaked.player": "%1$s was super soaked to death by %2$s",
"entity.antarchy.cheep": "Cheep", "entity.antarchy.cheep": "Cheep",
"entity.antarchy.dorrie": "Dorrie",
"entity.antarchy.hercules_beetle": "Hercules Beetle",
"item.antarchy.cheep": "Cheep", "item.antarchy.cheep": "Cheep",
"item.antarchy.cheep_spawn_egg": "Cheep Spawn Egg", "item.antarchy.cheep_spawn_egg": "Cheep Spawn Egg",
"item.antarchy.dorrie_spawn_egg": "Dorrie Spawn Egg",
"item.antarchy.hercules_beetle_spawn_egg": "Hercules Beetle Spawn Egg",
"key.antarchy.dorrie_charge_jump": "Dorrie: Charge Jump",
"key.antarchy.hercules_beetle_charge": "Hercules Beetle: Charge",
"entity.antarchy.reverie": "Reverie", "entity.antarchy.reverie": "Reverie",
"biome.antarchy.thoraxis": "Thoraxis", "biome.antarchy.thoraxis": "Thoraxis",
"biome.antarchy.nightmare_wastes": "Nightmare Wastes", "biome.antarchy.nightmare_wastes": "Nightmare Wastes",
@@ -791,7 +723,6 @@
"biome.antarchy.lucid_pools": "Lucid Pools", "biome.antarchy.lucid_pools": "Lucid Pools",
"biome.antarchy.dream_dunes": "Dream Dunes", "biome.antarchy.dream_dunes": "Dream Dunes",
"biome.antarchy.cloud_sea": "Cloud Sea", "biome.antarchy.cloud_sea": "Cloud Sea",
"trim_material.antarchy.blood_crystal": "Blood Crystal", "trim_material.antarchy.blood_crystal": "Blood Crystal",
"trim_material.antarchy.nightmare_scale": "Nightmare Scale", "trim_material.antarchy.nightmare_scale": "Nightmare Scale",
"trim_material.antarchy.uranium": "Uranium", "trim_material.antarchy.uranium": "Uranium",
@@ -807,5 +738,58 @@
"advancements.antarchy.squidzooka_craft.title": "Ink and Destroy", "advancements.antarchy.squidzooka_craft.title": "Ink and Destroy",
"advancements.antarchy.squidzooka_craft.description": "Craft a Squidzooka.", "advancements.antarchy.squidzooka_craft.description": "Craft a Squidzooka.",
"advancements.antarchy.gravity_gun_craft.title": "Pick Up Artist", "advancements.antarchy.gravity_gun_craft.title": "Pick Up Artist",
"advancements.antarchy.gravity_gun_craft.description": "Craft a Gravity Gun." "advancements.antarchy.gravity_gun_craft.description": "Craft a Gravity Gun.",
"advancements.antarchy.visit_cavaryn.description": "Use a termite to reach Cavaryn.",
"advancements.antarchy.visit_cavaryn.title": "You will be Termite-ated",
"block.antarchy.amber_lichen": "Amber Lichen",
"block.antarchy.amber_moss_block": "Amber Moss Block",
"block.antarchy.amber_moss_carpet": "Amber Moss Carpet",
"block.antarchy.bile_vein": "Bile Vein",
"block.antarchy.broodstone": "Broodstone",
"block.antarchy.chiten_block": "Chiten Block",
"block.antarchy.chiten_spike": "Chiten Spike",
"block.antarchy.creeping_horror_egg": "Creeping Horror Egg",
"block.antarchy.creepvine": "Creepvine",
"block.antarchy.lurking_terror_egg": "Lurking Terror Egg",
"block.antarchy.myrmite": "Myrmite",
"block.antarchy.termite_nest": "Termite Nest",
"entity.antarchy.creeping_horror": "Creeping Horror",
"entity.antarchy.dorrie": "Dorrie",
"entity.antarchy.hercules_beetle": "Hercules Beetle",
"entity.antarchy.honeyed_apple_cow": "Honeyed Apple Cow",
"entity.antarchy.jumpy_bug": "Jumpy Bug",
"entity.antarchy.lurking_terror": "Lurking Terror",
"entity.antarchy.spit_bug": "Spit Bug",
"entity.antarchy.stink_bug": "Stink Bug",
"entity.antarchy.termite": "Termite",
"item.antarchy.amber_lichen": "Amber Lichen",
"item.antarchy.amber_moss_block": "Amber Moss Block",
"item.antarchy.amber_moss_carpet": "Amber Moss Carpet",
"item.antarchy.bile_vein": "Bile Vein",
"item.antarchy.broodstone": "Broodstone",
"item.antarchy.chiten": "Chiten",
"item.antarchy.chiten_block": "Chiten Block",
"item.antarchy.chiten_spike": "Chiten Spike",
"item.antarchy.creeping_horror_egg": "Creeping Horror Egg",
"item.antarchy.creeping_horror_spawn_egg": "Creeping Horror Spawn Egg",
"item.antarchy.creepvine": "Creepvine",
"item.antarchy.dorrie_spawn_egg": "Dorrie Spawn Egg",
"item.antarchy.hercules_beetle_spawn_egg": "Hercules Beetle Spawn Egg",
"item.antarchy.honeyed_apple_cow_spawn_egg": "Honeyed Apple Cow Spawn Egg",
"item.antarchy.jumpy_bug_spawn_egg": "Jumpy Bug Spawn Egg",
"item.antarchy.lurking_terror_egg": "Lurking Terror Egg",
"item.antarchy.lurking_terror_spawn_egg": "Lurking Terror Spawn Egg",
"item.antarchy.myrmite": "Myrmite",
"item.antarchy.spit_bug_spawn_egg": "Spit Bug Spawn Egg",
"item.antarchy.stink_bug_spawn_egg": "Stink Bug Spawn Egg",
"item.antarchy.termite_spawn_egg": "Termite Spawn Egg",
"key.antarchy.dorrie_charge_jump": "Dorrie: Charge Jump",
"key.antarchy.hercules_beetle_charge": "Hercules Beetle: Charge",
"subtitles.antarchy.creeping_horror_bite": "Creeping Horror bites",
"subtitles.antarchy.creeping_horror_growl": "Creeping Horror growls",
"subtitles.antarchy.creeping_horror_hurt": "Creeping Horror hurts",
"subtitles.antarchy.lurking_terror_bite": "Lurking Terror bites",
"subtitles.antarchy.lurking_terror_fly_loop": "Lurking Terror flies",
"subtitles.antarchy.lurking_terror_hurt": "Lurking Terror hurts",
"subtitles.antarchy.lurking_terror_snarl": "Lurking Terror snarls"
} }
@@ -1,17 +0,0 @@
{
"ambientocclusion": false,
"textures": {
"particle": "antarchy:block/amber_moss/amber_lichen",
"glow_lichen": "antarchy:block/amber_moss/amber_lichen"
},
"elements": [
{
"from": [0, 0, 0.1],
"to": [16, 16, 0.1],
"faces": {
"north": { "uv": [16, 0, 0, 16], "texture": "#glow_lichen" },
"south": { "uv": [0, 0, 16, 16], "texture": "#glow_lichen" }
}
}
]
}
@@ -1,6 +0,0 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "antarchy:block/amber_moss/amber_moss_block"
}
}
@@ -1,6 +0,0 @@
{
"parent": "minecraft:block/carpet",
"textures": {
"wool": "antarchy:block/amber_moss/amber_moss_carpet"
}
}
@@ -1,6 +0,0 @@
{
"parent": "minecraft:block/mossy_carpet_side",
"textures": {
"side": "antarchy:block/amber_moss/amber_moss_carpet"
}
}
@@ -1,18 +0,0 @@
{
"ambientocclusion": true,
"textures": {
"particle": "#side",
"side": "antarchy:block/amber_moss/amber_moss_carpet"
},
"elements": [
{
"from": [0, 0, 0.1],
"to": [16, 16, 0.1],
"shade": true,
"faces": {
"north": {"uv": [16, 0, 0, 16], "texture": "#side"},
"south": {"uv": [0, 0, 16, 16], "texture": "#side"}
}
}
]
}
@@ -0,0 +1,5 @@
{
"textures": {
"particle": "antarchy:block/big_bush/big_bush_stage3"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/tinted_cross",
"textures": {
"cross": "antarchy:block/big_bush/big_bush_stage1"
}
}
@@ -0,0 +1,29 @@
{
"ambientocclusion": false,
"textures": {
"particle": "antarchy:block/big_bush/big_bush_stage2",
"cross": "antarchy:block/big_bush/big_bush_stage2"
},
"elements": [
{
"from": [1.6, 0, 16],
"to": [30.4, 32, 16],
"rotation": { "origin": [16, 16, 16], "axis": "y", "angle": 45, "rescale": true },
"shade": false,
"faces": {
"north": { "uv": [0, 0, 16, 16], "texture": "#cross", "tintindex": 0 },
"south": { "uv": [0, 0, 16, 16], "texture": "#cross", "tintindex": 0 }
}
},
{
"from": [16, 0, 1.6],
"to": [16, 32, 30.4],
"rotation": { "origin": [16, 16, 16], "axis": "y", "angle": 45, "rescale": true },
"shade": false,
"faces": {
"west": { "uv": [0, 0, 16, 16], "texture": "#cross", "tintindex": 0 },
"east": { "uv": [0, 0, 16, 16], "texture": "#cross", "tintindex": 0 }
}
}
]
}
@@ -0,0 +1,29 @@
{
"ambientocclusion": false,
"textures": {
"particle": "antarchy:block/big_bush/big_bush_stage3",
"cross": "antarchy:block/big_bush/big_bush_stage3"
},
"elements": [
{
"from": [-13.6, 0, 8],
"to": [29.6, 32, 8],
"rotation": { "origin": [8, 16, 8], "axis": "y", "angle": 45, "rescale": true },
"shade": false,
"faces": {
"north": { "uv": [0, 5.3333, 16, 16], "texture": "#cross", "tintindex": 0 },
"south": { "uv": [0, 5.3333, 16, 16], "texture": "#cross", "tintindex": 0 }
}
},
{
"from": [8, 0, -13.6],
"to": [8, 32, 29.6],
"rotation": { "origin": [8, 16, 8], "axis": "y", "angle": 45, "rescale": true },
"shade": false,
"faces": {
"west": { "uv": [0, 5.3333, 16, 16], "texture": "#cross", "tintindex": 0 },
"east": { "uv": [0, 5.3333, 16, 16], "texture": "#cross", "tintindex": 0 }
}
}
]
}
@@ -0,0 +1,29 @@
{
"ambientocclusion": false,
"textures": {
"particle": "antarchy:block/big_bush/big_bush_stage3",
"cross": "antarchy:block/big_bush/big_bush_stage3"
},
"elements": [
{
"from": [-13.6, 0, 8],
"to": [29.6, 16, 8],
"rotation": { "origin": [8, 8, 8], "axis": "y", "angle": 45, "rescale": true },
"shade": false,
"faces": {
"north": { "uv": [0, 0, 16, 5.3333], "texture": "#cross", "tintindex": 0 },
"south": { "uv": [0, 0, 16, 5.3333], "texture": "#cross", "tintindex": 0 }
}
},
{
"from": [8, 0, -13.6],
"to": [8, 16, 29.6],
"rotation": { "origin": [8, 8, 8], "axis": "y", "angle": 45, "rescale": true },
"shade": false,
"faces": {
"west": { "uv": [0, 0, 16, 5.3333], "texture": "#cross", "tintindex": 0 },
"east": { "uv": [0, 0, 16, 5.3333], "texture": "#cross", "tintindex": 0 }
}
}
]
}
@@ -1,6 +0,0 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "antarchy:block/bile/bile_vein"
}
}
@@ -1,6 +0,0 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "antarchy:block/broodstone/broodstone"
}
}
Loaded 100 of 335 files, more files were not shown because too many files have changed in this diff. Show more