Initial commit

This commit is contained in:
craisinlord committed 2026-06-22 14:47:55 -05:00
commit cd0af5a1d3
2557 files changed
+271980

No files matched your search

+61
View File
@@ -0,0 +1,61 @@
dependencies {
// We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
// Do NOT use other classes from fabric loader
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
// modImplementation("curse.maven:create-${create_curseforge_id}:${create_curseforge_file_id}")
// modImplementation("curse.maven:selene-499980:4754433")
compileOnly("curse.maven:intapi-${project.intapi_curseforge_id}:${project.intapi_curseforge_file_id_neoforge}")
compileOnly("curse.maven:create-${project.create_curseforge_id_neoforge}:${project.create_curseforge_file_id_neoforge}")
compileOnly("curse.maven:marvel-${project.marvel_curseforge_id}:${project.marvel_curseforge_file_id}")
compileOnly("curse.maven:stellaris-${project.stellaris_curseforge_id}:${project.stellaris_curseforge_file_id}")
compileOnly("curse.maven:aperture-${project.aperture_curseforge_id}:${project.aperture_curseforge_file_id}")
compileOnly("curse.maven:inventory_pets-${project.inventory_pets_curseforge_id}:${project.inventory_pets_curseforge_file_id}")
compileOnly("curse.maven:cataclysm-${project.cataclysm_curseforge_id}:${project.cataclysm_curseforge_file_id}")
compileOnly("curse.maven:iaf-${project.iaf_curseforge_id}:${project.iaf_curseforge_file_id}")
compileOnly("curse.maven:backpack-${project.backpack_curseforge_id}:${project.backpack_curseforge_file_id}")
// compileOnly("curse.maven:regions_unexplored-${project.regions_unexplored_curseforge_id}:${project.regions_unexplored_curseforge_file_id}")
// compileOnly("curse.maven:geckolib-${project.geckolib_curseforge_id}:${project.geckolib_curseforge_file_id}")
compileOnly(files("$rootDir/infinite_dimensions_jars/infinity-2.7.1+1.21.1-neoforge.jar"))
compileOnly(files("$rootDir/infinite_dimensions_jars/infinity-2.7.1+1.21.1-fabric.jar"))
compileOnly(files("$rootDir/infinite_dimensions_jars/infinity-2.7.1+1.21.1-neoforge-sources.jar"))
compileOnly(files("$rootDir/infinite_dimensions_jars/gravity-api-1.0.7-1.20.1.jar"))
compileOnly(files("$rootDir/infinite_dimensions_jars/Cloro's Gravity Gun Mod (Release 1.3.1).jar"))
// compileOnly(files("$rootDir/infinite_dimensions_jars/antarchy-1.0.0+1.21.1-neoforge.jar"))
compileOnly(files("$rootDir/infinite_dimensions_jars/VanillaBackport-neoforge-1.21.1-1.1.7.6.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/sable-neoforge-1.21.1-2.0.3.jar"))
compileOnly("software.bernie.geckolib:geckolib-neoforge-${minecraft_version}:${geckolib_version}")
//
// compileOnly group: 'org.ow2.asm', name: 'asm-tree', version: '9.4'
// 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}"))
}
architectury {
common("fabric", "neoforge")
}
loom {
mixin {
useLegacyMixinAp = true
defaultRefmapName = "antarchy.refmap.json"
}
}
jar {
exclude "architectury.common.json"
manifest {
attributes 'Fabric-Loom-Remap': true
}
}
sourcesJar {
exclude "architectury.common.json"
}
@@ -0,0 +1,17 @@
package com.craisinlord.antarchy;
import com.craisinlord.integrated_api.events.lifecycle.ServerGoingToStartEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Antarchy {
public static final String MODID = "antarchy";
public static final Logger LOGGER = LogManager.getLogger();
public static void init() {
ServerGoingToStartEvent.EVENT.addListener(Antarchy::serverAboutToStart);
}
private static void serverAboutToStart(final ServerGoingToStartEvent event) {
}
}
@@ -0,0 +1,16 @@
package com.craisinlord.antarchy.compat.infinity;
public final class InfinityCompat {
private static InfinityCompatBridge bridge = InfinityCompatBridge.NOOP;
private InfinityCompat() {
}
public static InfinityCompatBridge get() {
return bridge;
}
public static void bind(InfinityCompatBridge compatBridge) {
bridge = compatBridge != null ? compatBridge : InfinityCompatBridge.NOOP;
}
}
@@ -0,0 +1,22 @@
package com.craisinlord.antarchy.compat.infinity;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.RandomSource;
public interface InfinityCompatBridge {
InfinityCompatBridge NOOP = new InfinityCompatBridge() {
};
default boolean isAvailable() {
return false;
}
default ResourceLocation getRandomDimensionId(RandomSource random) {
return null;
}
default boolean requestWarp(ServerPlayer player, ResourceLocation dimensionId) {
return false;
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,31 @@
package com.craisinlord.antarchy.content;
import net.minecraft.advancements.AdvancementHolder;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import org.jetbrains.annotations.Nullable;
public final class AntarchyAdvancements {
private AntarchyAdvancements() {
}
public static boolean award(ServerPlayer player, ResourceLocation advancementId) {
MinecraftServer server = player.serverLevel().getServer();
if (server == null) {
return false;
}
AdvancementHolder holder = server.getAdvancements().get(advancementId);
if (holder == null) {
return false;
}
return player.getAdvancements().award(holder, "impossible");
}
@Nullable
public static AdvancementHolder get(MinecraftServer server, ResourceLocation advancementId) {
return server.getAdvancements().get(advancementId);
}
}
@@ -0,0 +1,286 @@
package com.craisinlord.antarchy.content;
import com.craisinlord.antarchy.content.entity.BedBugEntity;
import com.craisinlord.antarchy.content.entity.BomberEntity;
import com.craisinlord.antarchy.content.entity.ButterflyEntity;
import com.craisinlord.antarchy.content.entity.CaterpillarEntity;
import com.craisinlord.antarchy.content.entity.EasterBunnyEntity;
import com.craisinlord.antarchy.content.entity.HushProjectileEntity;
import com.craisinlord.antarchy.content.entity.TriffidEntity;
import com.craisinlord.antarchy.content.entity.WaspEntity;
import com.craisinlord.antarchy.content.entity.brutalfly.BrutalflyEntity;
import com.craisinlord.antarchy.content.entity.brutalfly.BrutalflyOrbEntity;
import com.craisinlord.antarchy.content.block.entity.HushweedBlockEntity;
import com.craisinlord.antarchy.content.entity.flying_squirrel.FlyingSquirrelEntity;
import com.craisinlord.antarchy.content.entity.MissileSquidEntity;
import com.craisinlord.antarchy.content.entity.kraken.KrakenEntity;
import com.craisinlord.antarchy.content.entity.MolewormEntity;
import com.craisinlord.antarchy.content.entity.MantisEntity;
import com.craisinlord.antarchy.content.entity.ReverieEntity;
import com.craisinlord.antarchy.content.entity.ScorpionEntity;
import com.craisinlord.antarchy.content.block.entity.AntNestBlockEntity;
import com.craisinlord.antarchy.content.block.entity.DreamCampfireBlockEntity;
import com.craisinlord.antarchy.content.block.entity.WaspNestBlockEntity;
import java.util.function.Supplier;
import net.minecraft.core.Holder;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
public final class AntarchyObjects {
private static final Supplier<?> UNBOUND = () -> {
throw new IllegalStateException("Antarchy object supplier was accessed before registration finished");
};
@SuppressWarnings("unchecked")
public static Supplier<EntityType<EasterBunnyEntity>> EASTER_BUNNY = (Supplier<EntityType<EasterBunnyEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<FlyingSquirrelEntity>> FLYING_SQUIRREL = (Supplier<EntityType<FlyingSquirrelEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<KrakenEntity>> KRAKEN = (Supplier<EntityType<KrakenEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<MissileSquidEntity>> MISSILE_SQUID = (Supplier<EntityType<MissileSquidEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<MolewormEntity>> MOLEWORM = (Supplier<EntityType<MolewormEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<MantisEntity>> MANTIS = (Supplier<EntityType<MantisEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<BedBugEntity>> BED_BUG = (Supplier<EntityType<BedBugEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<WaspEntity>> WASP = (Supplier<EntityType<WaspEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<BomberEntity>> BOMBER = (Supplier<EntityType<BomberEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<ScorpionEntity>> SCORPION = (Supplier<EntityType<ScorpionEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<CaterpillarEntity>> CATERPILLAR = (Supplier<EntityType<CaterpillarEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<ButterflyEntity>> BUTTERFLY = (Supplier<EntityType<ButterflyEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<ReverieEntity>> REVERIE = (Supplier<EntityType<ReverieEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<TriffidEntity>> TRIFFID = (Supplier<EntityType<TriffidEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<BrutalflyEntity>> BRUTALFLY = (Supplier<EntityType<BrutalflyEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<BrutalflyOrbEntity>> BRUTALFLY_ORB = (Supplier<EntityType<BrutalflyOrbEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<HushProjectileEntity>> HUSH_PROJECTILE = (Supplier<EntityType<HushProjectileEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> DUPLICATOR_LOG = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> DUPLICATOR_SAPLING = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> DUCT_TAPE = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> INFESTED_ROOTED_DIRT = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> INFESTED_COARSE_DIRT = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> NYXITE = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> CLOUD_BLOCK = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> TRIFFID_GOO_BLOCK = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> PALE_NYXITE = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> NYXITE_SPIKE = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> POTENT_NYXITE = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> ANTIMETAL = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> POLISHED_ANTIMETAL = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> BUDDING_BLOOD_CRYSTAL = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> SMALL_BLOOD_CRYSTAL_BUD = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> MEDIUM_BLOOD_CRYSTAL_BUD = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> LARGE_BLOOD_CRYSTAL_BUD = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> BLOOD_CRYSTAL_CRYSTAL = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Item> OURANWOOD_ACORN = (Supplier<Item>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Item> KRAKEN_TOOTH = (Supplier<Item>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Item> MOGGLES = (Supplier<Item>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Item> REVERIE_BOTTLE = (Supplier<Item>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Holder<MobEffect>> DREAD = (Supplier<Holder<MobEffect>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Holder<Attribute>> DOUBLE_DAMAGE_CHANCE = (Supplier<Holder<Attribute>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Holder<Attribute>> BLOODGLASS_MAX_HEARTS = (Supplier<Holder<Attribute>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Holder<MobEffect>> BLOODGLASS_WARD = (Supplier<Holder<MobEffect>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Holder<MobEffect>> PARALYZED_EFFECT = (Supplier<Holder<MobEffect>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Holder<MobEffect>> INVERTED_EFFECT = (Supplier<Holder<MobEffect>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> OURANWOOD_ACORN_BLOCK = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> MOSSY_OURANWOOD_LOG = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> MOSSY_OURANWOOD_WOOD = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> ORANGE_MILKWEED = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> PINK_MILKWEED = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> TORCHFLOWER_BUSH = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> BED_BUG_EGG = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> WASP_NEST = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> HUSHWEED = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> SQUIRREL_NEST_BLOCK = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<BlockEntityType<AntNestBlockEntity>> ANT_NEST_BLOCK_ENTITY = (Supplier<BlockEntityType<AntNestBlockEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<BlockEntityType<DreamCampfireBlockEntity>> DREAM_CAMPFIRE_BLOCK_ENTITY = (Supplier<BlockEntityType<DreamCampfireBlockEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<BlockEntityType<WaspNestBlockEntity>> WASP_NEST_BLOCK_ENTITY = (Supplier<BlockEntityType<WaspNestBlockEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<BlockEntityType<HushweedBlockEntity>> HUSHWEED_BLOCK_ENTITY = (Supplier<BlockEntityType<HushweedBlockEntity>>) UNBOUND;
private AntarchyObjects() {
}
public static void bind(
Supplier<EntityType<EasterBunnyEntity>> easterBunny,
Supplier<EntityType<FlyingSquirrelEntity>> flyingSquirrel,
Supplier<EntityType<KrakenEntity>> kraken,
Supplier<EntityType<MissileSquidEntity>> missileSquid,
Supplier<EntityType<MolewormEntity>> moleworm,
Supplier<EntityType<MantisEntity>> mantis,
Supplier<EntityType<BedBugEntity>> bedBug,
Supplier<EntityType<WaspEntity>> wasp,
Supplier<EntityType<BomberEntity>> bomber,
Supplier<EntityType<ScorpionEntity>> scorpion,
Supplier<EntityType<CaterpillarEntity>> caterpillar,
Supplier<EntityType<ButterflyEntity>> butterfly,
Supplier<EntityType<ReverieEntity>> reverie,
Supplier<EntityType<TriffidEntity>> triffid,
Supplier<EntityType<BrutalflyEntity>> brutalfly,
Supplier<EntityType<BrutalflyOrbEntity>> brutalflyOrb,
Supplier<EntityType<HushProjectileEntity>> hushProjectile,
Supplier<Block> duplicatorLog,
Supplier<Block> duplicatorSapling,
Supplier<Block> ductTape,
Supplier<Block> infestedRootedDirt,
Supplier<Block> infestedCoarseDirt,
Supplier<Block> nyxite,
Supplier<Block> cloudBlock,
Supplier<Block> triffidGooBlock,
Supplier<Block> paleNyxite,
Supplier<Block> nyxiteSpike,
Supplier<Block> potentNyxite,
Supplier<Block> antimetal,
Supplier<Block> polishedAntimetal,
Supplier<Block> buddingBloodCrystal,
Supplier<Block> smallBloodCrystalBud,
Supplier<Block> mediumBloodCrystalBud,
Supplier<Block> largeBloodCrystalBud,
Supplier<Block> bloodCrystalCrystal,
Supplier<Item> ouranwoodAcorn,
Supplier<Item> krakenTooth,
Supplier<Item> moggles,
Supplier<Item> reverieBottle,
Supplier<Holder<MobEffect>> dread,
Supplier<Holder<MobEffect>> paralyzedEffect,
Supplier<Holder<MobEffect>> invertedEffect,
Supplier<Block> ouranwoodAcornBlock,
Supplier<Block> mossyOuranwoodLog,
Supplier<Block> mossyOuranwoodWood,
Supplier<Block> orangeMilkweed,
Supplier<Block> pinkMilkweed,
Supplier<Block> torchflowerBush,
Supplier<Block> bedBugEggs,
Supplier<Block> waspNest,
Supplier<Block> hushweed,
Supplier<Block> squirrelNestBlock,
Supplier<BlockEntityType<AntNestBlockEntity>> antNestBlockEntity,
Supplier<BlockEntityType<DreamCampfireBlockEntity>> dreamCampfireBlockEntity,
Supplier<BlockEntityType<WaspNestBlockEntity>> waspNestBlockEntity,
Supplier<BlockEntityType<HushweedBlockEntity>> hushweedBlockEntity,
Supplier<Holder<Attribute>> doubleDamageChance,
Supplier<Holder<Attribute>> bloodglassMaxHearts,
Supplier<Holder<MobEffect>> bloodglassWard
) {
EASTER_BUNNY = easterBunny;
FLYING_SQUIRREL = flyingSquirrel;
KRAKEN = kraken;
MISSILE_SQUID = missileSquid;
MOLEWORM = moleworm;
MANTIS = mantis;
BED_BUG = bedBug;
WASP = wasp;
BOMBER = bomber;
SCORPION = scorpion;
CATERPILLAR = caterpillar;
BUTTERFLY = butterfly;
REVERIE = reverie;
TRIFFID = triffid;
BRUTALFLY = brutalfly;
BRUTALFLY_ORB = brutalflyOrb;
HUSH_PROJECTILE = hushProjectile;
DUPLICATOR_LOG = duplicatorLog;
DUPLICATOR_SAPLING = duplicatorSapling;
DUCT_TAPE = ductTape;
INFESTED_ROOTED_DIRT = infestedRootedDirt;
INFESTED_COARSE_DIRT = infestedCoarseDirt;
NYXITE = nyxite;
CLOUD_BLOCK = cloudBlock;
TRIFFID_GOO_BLOCK = triffidGooBlock;
PALE_NYXITE = paleNyxite;
NYXITE_SPIKE = nyxiteSpike;
POTENT_NYXITE = potentNyxite;
ANTIMETAL = antimetal;
POLISHED_ANTIMETAL = polishedAntimetal;
BUDDING_BLOOD_CRYSTAL = buddingBloodCrystal;
SMALL_BLOOD_CRYSTAL_BUD = smallBloodCrystalBud;
MEDIUM_BLOOD_CRYSTAL_BUD = mediumBloodCrystalBud;
LARGE_BLOOD_CRYSTAL_BUD = largeBloodCrystalBud;
BLOOD_CRYSTAL_CRYSTAL = bloodCrystalCrystal;
OURANWOOD_ACORN = ouranwoodAcorn;
KRAKEN_TOOTH = krakenTooth;
MOGGLES = moggles;
REVERIE_BOTTLE = reverieBottle;
DREAD = dread;
PARALYZED_EFFECT = paralyzedEffect;
INVERTED_EFFECT = invertedEffect;
OURANWOOD_ACORN_BLOCK = ouranwoodAcornBlock;
MOSSY_OURANWOOD_LOG = mossyOuranwoodLog;
MOSSY_OURANWOOD_WOOD = mossyOuranwoodWood;
ORANGE_MILKWEED = orangeMilkweed;
PINK_MILKWEED = pinkMilkweed;
TORCHFLOWER_BUSH = torchflowerBush;
BED_BUG_EGG = bedBugEggs;
WASP_NEST = waspNest;
HUSHWEED = hushweed;
SQUIRREL_NEST_BLOCK = squirrelNestBlock;
ANT_NEST_BLOCK_ENTITY = antNestBlockEntity;
DREAM_CAMPFIRE_BLOCK_ENTITY = dreamCampfireBlockEntity;
WASP_NEST_BLOCK_ENTITY = waspNestBlockEntity;
HUSHWEED_BLOCK_ENTITY = hushweedBlockEntity;
DOUBLE_DAMAGE_CHANCE = doubleDamageChance;
BLOODGLASS_MAX_HEARTS = bloodglassMaxHearts;
BLOODGLASS_WARD = bloodglassWard;
}
public static boolean isDuplicatorTreeBlock(BlockState state) {
return state.is(DUPLICATOR_LOG.get()) || state.is(DUPLICATOR_SAPLING.get());
}
}
@@ -0,0 +1,352 @@
package com.craisinlord.antarchy.content;
import java.util.function.Supplier;
import net.minecraft.sounds.SoundEvent;
@SuppressWarnings("unchecked")
public final class AntarchySoundEvents {
private static final Supplier<?> UNBOUND = () -> {
throw new IllegalStateException("Antarchy sound event supplier was accessed before registration finished");
};
public static Supplier<SoundEvent> SQUIDZOOKA_FIRE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> SHRINK_RAY_SOUND = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> GROWTH_RAY_SOUND = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> SIZE_RAY_CHARGE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> ANT_AMBIENT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> ANT_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> ANT_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> ANT_BITE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> ANT_GATHER = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> ANT_NEST = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CLOUD_SHARK_BITE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CLOUD_SHARK_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CLOUD_SHARK_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CLOUD_SHARK_DEATH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CLOUD_SHARK_FLY = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CATERPILLAR_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CATERPILLAR_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CATERPILLAR_CRAWL = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BUTTERFLY_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BRUTALFLY_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BRUTALFLY_DEATH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> ELYTHIA_FIREFLY_AMBIENT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MISSILE_SQUID_AMBIENT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MISSILE_SQUID_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MISSILE_SQUID_DEATH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MISSILE_SQUID_ATTACK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> KRAKEN_FLYING_LOOP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> KRAKEN_FLYING_SIDEWAYS_LOOP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> KRAKEN_ATTACK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> KRAKEN_SPIN = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> KRAKEN_ROAR = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> KRAKEN_SUMMON = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> KRAKEN_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> KRAKEN_DEATH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BASILISK_IDLE_LOOP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BASILISK_SLITHER_LOOP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BASILISK_BITE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BASILISK_HISS = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BASILISK_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BASILISK_DEATH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> THORAXIS_NIGHTMARE_WASTES_AMBIENT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> THORAXIS_NIGHTMARE_WASTES_ADDITIONS = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> THORAXIS_NIGHTMARE_WASTES_MOOD = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> THORAXIS_DREAM_DUNES_AMBIENT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> THORAXIS_DREAM_DUNES_ADDITIONS = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> THORAXIS_DREAM_DUNES_MOOD = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> THORAXIS_LUCID_POOLS_AMBIENT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> THORAXIS_LUCID_POOLS_ADDITIONS = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> THORAXIS_LUCID_POOLS_MOOD = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> LUCID_AMBIENT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> LUCID_FLYING = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> LUCID_ATTACK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> LUCID_BOLT_SOUND = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> LUCID_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> LUCID_DEATH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> REVERIE_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> REVERIE_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> REVERIE_WORRY = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> REVERIE_SAVE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> REVERIE_JOIN_PLAYER = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> REVERIE_ALERT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> FLYING_SQUIRREL_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> FLYING_SQUIRREL_BEG = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> FLYING_SQUIRREL_NUT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> FLYING_SQUIRREL_GLIDE_LOOP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> FLYING_SQUIRREL_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> FLYING_SQUIRREL_DEATH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> NIGHTMARE_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> NIGHTMARE_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> NIGHTMARE_ROAR = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> NIGHTMARE_DEATH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> NIGHTMARE_BITE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> NIGHTMARE_FLAP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TRIFFID_ATTACK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TRIFFID_GRAB = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TRIFFID_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TRIFFID_DEATH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TRIFFID_HISS = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TRIFFID_GROWL = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MANTIS_AMBIENT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MANTIS_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MANTIS_ATTACK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MANTIS_FLY_LOOP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> GRAVITY_GUN_PICKUP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> GRAVITY_GUN_DROP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> GRAVITY_GUN_HOLD_LOOP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> GRAVITY_GUN_LAUNCH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> GRAVITY_GUN_DRYFIRE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BED_BUG_AMBIENT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BED_BUG_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BED_BUG_ATTACK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> WASP_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> WASP_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> WASP_ATTACK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> WASP_DEATH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> SCORPION_AMBIENT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> SCORPION_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> SCORPION_ATTACK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> EMPEROR_SCORPION_AMBIENT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> EMPEROR_SCORPION_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> EMPEROR_SCORPION_ATTACK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> EMPEROR_SCORPION_ROAR = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MOLEWORM_AMBIENT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MOLEWORM_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MOLEWORM_ATTACK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MOLEWORM_DIG = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MOLEVORE_AMBIENT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MOLEVORE_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MOLEVORE_ATTACK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> MOLEVORE_DIG = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> DUCT_TAPE_USE = (Supplier<SoundEvent>) UNBOUND;
private AntarchySoundEvents() {
}
public static void bind(
Supplier<SoundEvent> squidzookaFire,
Supplier<SoundEvent> shrinkRaySound,
Supplier<SoundEvent> growthRaySound,
Supplier<SoundEvent> sizeRayCharge,
Supplier<SoundEvent> antAmbient,
Supplier<SoundEvent> antIdle,
Supplier<SoundEvent> antHurt,
Supplier<SoundEvent> antBite,
Supplier<SoundEvent> antGather,
Supplier<SoundEvent> antNest,
Supplier<SoundEvent> cloudSharkBite,
Supplier<SoundEvent> cloudSharkIdle,
Supplier<SoundEvent> cloudSharkHurt,
Supplier<SoundEvent> cloudSharkDeath,
Supplier<SoundEvent> cloudSharkFly,
Supplier<SoundEvent> caterpillarIdle,
Supplier<SoundEvent> caterpillarHurt,
Supplier<SoundEvent> caterpillarCrawl,
Supplier<SoundEvent> butterflyHurt,
Supplier<SoundEvent> brutalflyIdle,
Supplier<SoundEvent> brutalflyDeath,
Supplier<SoundEvent> elythiaFireflyAmbient,
Supplier<SoundEvent> missileSquidAmbient,
Supplier<SoundEvent> missileSquidHurt,
Supplier<SoundEvent> missileSquidDeath,
Supplier<SoundEvent> missileSquidAttack,
Supplier<SoundEvent> krakenFlyingLoop,
Supplier<SoundEvent> krakenFlyingSidewaysLoop,
Supplier<SoundEvent> krakenAttack,
Supplier<SoundEvent> krakenSpin,
Supplier<SoundEvent> krakenRoar,
Supplier<SoundEvent> krakenSummon,
Supplier<SoundEvent> krakenHurt,
Supplier<SoundEvent> krakenDeath,
Supplier<SoundEvent> basiliskIdleLoop,
Supplier<SoundEvent> basiliskSlitherLoop,
Supplier<SoundEvent> basiliskBite,
Supplier<SoundEvent> basiliskHiss,
Supplier<SoundEvent> basiliskHurt,
Supplier<SoundEvent> basiliskDeath,
Supplier<SoundEvent> thoraxisNightmareWastesAmbient,
Supplier<SoundEvent> thoraxisNightmareWastesAdditions,
Supplier<SoundEvent> thoraxisNightmareWastesMood,
Supplier<SoundEvent> thoraxisDreamDunesAmbient,
Supplier<SoundEvent> thoraxisDreamDunesAdditions,
Supplier<SoundEvent> thoraxisDreamDunesMood,
Supplier<SoundEvent> thoraxisLucidPoolsAmbient,
Supplier<SoundEvent> thoraxisLucidPoolsAdditions,
Supplier<SoundEvent> thoraxisLucidPoolsMood,
Supplier<SoundEvent> lucidAmbient,
Supplier<SoundEvent> lucidFlying,
Supplier<SoundEvent> lucidAttack,
Supplier<SoundEvent> lucidBoltSound,
Supplier<SoundEvent> lucidHurt,
Supplier<SoundEvent> lucidDeath,
Supplier<SoundEvent> reverieIdle,
Supplier<SoundEvent> reverieHurt,
Supplier<SoundEvent> reverieWorry,
Supplier<SoundEvent> reverieSave,
Supplier<SoundEvent> reverieJoinPlayer,
Supplier<SoundEvent> reverieAlert,
Supplier<SoundEvent> flyingSquirrelIdle,
Supplier<SoundEvent> flyingSquirrelBeg,
Supplier<SoundEvent> flyingSquirrelNut,
Supplier<SoundEvent> flyingSquirrelGlideLoop,
Supplier<SoundEvent> flyingSquirrelHurt,
Supplier<SoundEvent> flyingSquirrelDeath,
Supplier<SoundEvent> nightmareIdle,
Supplier<SoundEvent> nightmareHurt,
Supplier<SoundEvent> nightmareRoar,
Supplier<SoundEvent> nightmareDeath,
Supplier<SoundEvent> nightmareBite,
Supplier<SoundEvent> nightmareFlap,
Supplier<SoundEvent> triffidAttack,
Supplier<SoundEvent> triffidGrab,
Supplier<SoundEvent> triffidHurt,
Supplier<SoundEvent> triffidDeath,
Supplier<SoundEvent> triffidHiss,
Supplier<SoundEvent> triffidGrowl,
Supplier<SoundEvent> mantisAmbient,
Supplier<SoundEvent> mantisHurt,
Supplier<SoundEvent> mantisAttack,
Supplier<SoundEvent> mantisFlyLoop,
Supplier<SoundEvent> gravityGunPickup,
Supplier<SoundEvent> gravityGunDrop,
Supplier<SoundEvent> gravityGunHoldLoop,
Supplier<SoundEvent> gravityGunLaunch,
Supplier<SoundEvent> gravityGunDryfire,
Supplier<SoundEvent> bedBugAmbient,
Supplier<SoundEvent> bedBugHurt,
Supplier<SoundEvent> bedBugAttack,
Supplier<SoundEvent> waspIdle,
Supplier<SoundEvent> waspHurt,
Supplier<SoundEvent> waspAttack,
Supplier<SoundEvent> waspDeath,
Supplier<SoundEvent> scorpionAmbient,
Supplier<SoundEvent> scorpionHurt,
Supplier<SoundEvent> scorpionAttack,
Supplier<SoundEvent> emperorScorpionAmbient,
Supplier<SoundEvent> emperorScorpionHurt,
Supplier<SoundEvent> emperorScorpionAttack,
Supplier<SoundEvent> emperorScorpionRoar,
Supplier<SoundEvent> molewormAmbient,
Supplier<SoundEvent> molewormHurt,
Supplier<SoundEvent> molewormAttack,
Supplier<SoundEvent> molewormDig,
Supplier<SoundEvent> molevoreAmbient,
Supplier<SoundEvent> molevoreHurt,
Supplier<SoundEvent> molevoreAttack,
Supplier<SoundEvent> molevoreDig,
Supplier<SoundEvent> ductTapeUse
) {
SQUIDZOOKA_FIRE = squidzookaFire;
SHRINK_RAY_SOUND = shrinkRaySound;
GROWTH_RAY_SOUND = growthRaySound;
SIZE_RAY_CHARGE = sizeRayCharge;
ANT_AMBIENT = antAmbient;
ANT_IDLE = antIdle;
ANT_HURT = antHurt;
ANT_BITE = antBite;
ANT_GATHER = antGather;
ANT_NEST = antNest;
CLOUD_SHARK_BITE = cloudSharkBite;
CLOUD_SHARK_IDLE = cloudSharkIdle;
CLOUD_SHARK_HURT = cloudSharkHurt;
CLOUD_SHARK_DEATH = cloudSharkDeath;
CLOUD_SHARK_FLY = cloudSharkFly;
CATERPILLAR_IDLE = caterpillarIdle;
CATERPILLAR_HURT = caterpillarHurt;
CATERPILLAR_CRAWL = caterpillarCrawl;
BUTTERFLY_HURT = butterflyHurt;
BRUTALFLY_IDLE = brutalflyIdle;
BRUTALFLY_DEATH = brutalflyDeath;
ELYTHIA_FIREFLY_AMBIENT = elythiaFireflyAmbient;
MISSILE_SQUID_AMBIENT = missileSquidAmbient;
MISSILE_SQUID_HURT = missileSquidHurt;
MISSILE_SQUID_DEATH = missileSquidDeath;
MISSILE_SQUID_ATTACK = missileSquidAttack;
KRAKEN_FLYING_LOOP = krakenFlyingLoop;
KRAKEN_FLYING_SIDEWAYS_LOOP = krakenFlyingSidewaysLoop;
KRAKEN_ATTACK = krakenAttack;
KRAKEN_SPIN = krakenSpin;
KRAKEN_ROAR = krakenRoar;
KRAKEN_SUMMON = krakenSummon;
KRAKEN_HURT = krakenHurt;
KRAKEN_DEATH = krakenDeath;
BASILISK_IDLE_LOOP = basiliskIdleLoop;
BASILISK_SLITHER_LOOP = basiliskSlitherLoop;
BASILISK_BITE = basiliskBite;
BASILISK_HISS = basiliskHiss;
BASILISK_HURT = basiliskHurt;
BASILISK_DEATH = basiliskDeath;
THORAXIS_NIGHTMARE_WASTES_AMBIENT = thoraxisNightmareWastesAmbient;
THORAXIS_NIGHTMARE_WASTES_ADDITIONS = thoraxisNightmareWastesAdditions;
THORAXIS_NIGHTMARE_WASTES_MOOD = thoraxisNightmareWastesMood;
THORAXIS_DREAM_DUNES_AMBIENT = thoraxisDreamDunesAmbient;
THORAXIS_DREAM_DUNES_ADDITIONS = thoraxisDreamDunesAdditions;
THORAXIS_DREAM_DUNES_MOOD = thoraxisDreamDunesMood;
THORAXIS_LUCID_POOLS_AMBIENT = thoraxisLucidPoolsAmbient;
THORAXIS_LUCID_POOLS_ADDITIONS = thoraxisLucidPoolsAdditions;
THORAXIS_LUCID_POOLS_MOOD = thoraxisLucidPoolsMood;
LUCID_AMBIENT = lucidAmbient;
LUCID_FLYING = lucidFlying;
LUCID_ATTACK = lucidAttack;
LUCID_BOLT_SOUND = lucidBoltSound;
LUCID_HURT = lucidHurt;
LUCID_DEATH = lucidDeath;
REVERIE_IDLE = reverieIdle;
REVERIE_HURT = reverieHurt;
REVERIE_WORRY = reverieWorry;
REVERIE_SAVE = reverieSave;
REVERIE_JOIN_PLAYER = reverieJoinPlayer;
REVERIE_ALERT = reverieAlert;
FLYING_SQUIRREL_IDLE = flyingSquirrelIdle;
FLYING_SQUIRREL_BEG = flyingSquirrelBeg;
FLYING_SQUIRREL_NUT = flyingSquirrelNut;
FLYING_SQUIRREL_GLIDE_LOOP = flyingSquirrelGlideLoop;
FLYING_SQUIRREL_HURT = flyingSquirrelHurt;
FLYING_SQUIRREL_DEATH = flyingSquirrelDeath;
NIGHTMARE_IDLE = nightmareIdle;
NIGHTMARE_HURT = nightmareHurt;
NIGHTMARE_ROAR = nightmareRoar;
NIGHTMARE_DEATH = nightmareDeath;
NIGHTMARE_BITE = nightmareBite;
NIGHTMARE_FLAP = nightmareFlap;
TRIFFID_ATTACK = triffidAttack;
TRIFFID_GRAB = triffidGrab;
TRIFFID_HURT = triffidHurt;
TRIFFID_DEATH = triffidDeath;
TRIFFID_HISS = triffidHiss;
TRIFFID_GROWL = triffidGrowl;
MANTIS_AMBIENT = mantisAmbient;
MANTIS_HURT = mantisHurt;
MANTIS_ATTACK = mantisAttack;
MANTIS_FLY_LOOP = mantisFlyLoop;
GRAVITY_GUN_PICKUP = gravityGunPickup;
GRAVITY_GUN_DROP = gravityGunDrop;
GRAVITY_GUN_HOLD_LOOP = gravityGunHoldLoop;
GRAVITY_GUN_LAUNCH = gravityGunLaunch;
GRAVITY_GUN_DRYFIRE = gravityGunDryfire;
BED_BUG_AMBIENT = bedBugAmbient;
BED_BUG_HURT = bedBugHurt;
BED_BUG_ATTACK = bedBugAttack;
WASP_IDLE = waspIdle;
WASP_HURT = waspHurt;
WASP_ATTACK = waspAttack;
WASP_DEATH = waspDeath;
SCORPION_AMBIENT = scorpionAmbient;
SCORPION_HURT = scorpionHurt;
SCORPION_ATTACK = scorpionAttack;
EMPEROR_SCORPION_AMBIENT = emperorScorpionAmbient;
EMPEROR_SCORPION_HURT = emperorScorpionHurt;
EMPEROR_SCORPION_ATTACK = emperorScorpionAttack;
EMPEROR_SCORPION_ROAR = emperorScorpionRoar;
MOLEWORM_AMBIENT = molewormAmbient;
MOLEWORM_HURT = molewormHurt;
MOLEWORM_ATTACK = molewormAttack;
MOLEWORM_DIG = molewormDig;
MOLEVORE_AMBIENT = molevoreAmbient;
MOLEVORE_HURT = molevoreHurt;
MOLEVORE_ATTACK = molevoreAttack;
MOLEVORE_DIG = molevoreDig;
DUCT_TAPE_USE = ductTapeUse;
}
}
@@ -0,0 +1,101 @@
package com.craisinlord.antarchy.content;
import com.craisinlord.antarchy.Antarchy;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.tags.TagKey;
import net.minecraft.world.damagesource.DamageType;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.biome.Biome;
public final class AntarchyTags {
private AntarchyTags() {
}
private static ResourceLocation id(String path) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, path);
}
public static final class Blocks {
public static final TagKey<Block> DUPLICATOR_TREE_BLACKLIST = TagKey.create(Registries.BLOCK, id("duplicator_tree_blacklist"));
public static final TagKey<Block> GRAVITY_GUN_BLACKLIST = TagKey.create(Registries.BLOCK, id("gravity_gun_blacklist"));
public static final TagKey<Block> DREAM_FIRE_BASE_BLOCKS = TagKey.create(Registries.BLOCK, id("dream_fire_base_blocks"));
public static final TagKey<Block> POTENT_NYXITE_ACTIVATION_BLOCKS = TagKey.create(Registries.BLOCK, id("potent_nyxite_activation_blocks"));
public static final TagKey<Block> CORNEA_STALK_PLANTABLE = TagKey.create(Registries.BLOCK, id("cornea_stalk_plantable"));
public static final TagKey<Block> MOLEVORE_BREAKABLE_BLOCKS = TagKey.create(Registries.BLOCK, id("molevore_breakable_blocks"));
public static final TagKey<Block> NIGHTMARE_BREAKABLE = TagKey.create(Registries.BLOCK, id("nightmare_breakable"));
public static final TagKey<Block> MOLEVORE_SEE_THROUGH_BLOCKS = TagKey.create(Registries.BLOCK, id("molevore_see_through_blocks"));
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"));
private Blocks() {
}
}
public static final class DamageType {
public static final TagKey<net.minecraft.world.damagesource.DamageType> BYPASSES_BLOODGLASS =
TagKey.create(net.minecraft.core.registries.Registries.DAMAGE_TYPE, ResourceLocation.fromNamespaceAndPath("antarchy", "bypasses_bloodglass"));
private DamageType() {
}
}
public static final class Entities {
public static final TagKey<EntityType<?>> BASILISK_PREY = TagKey.create(Registries.ENTITY_TYPE, id("basilisk_prey"));
public static final TagKey<EntityType<?>> DREAM_SAND_LOW_GRAVITY_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("dream_sand_low_gravity_blacklist"));
public static final TagKey<EntityType<?>> GRAVITY_GUN_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("gravity_gun_blacklist"));
public static final TagKey<EntityType<?>> INVERTED_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("inverted_immune"));
public static final TagKey<EntityType<?>> LUCID_BOLT_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("lucid_bolt_immune"));
public static final TagKey<EntityType<?>> DUCT_TAPE_STICK_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("duct_tape_stick_blacklist"));
public static final TagKey<EntityType<?>> NIGHTMARE_NO_ATTACK = TagKey.create(Registries.ENTITY_TYPE, id("nightmare_no_attack"));
public static final TagKey<EntityType<?>> SIZE_CHANGING_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("size_changing_immune"));
public static final TagKey<EntityType<?>> PARALYSIS_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("paralysis_immune"));
public static final TagKey<EntityType<?>> HUSHWEED_TARGETS = TagKey.create(Registries.ENTITY_TYPE, id("hushweed_targets"));
public static final TagKey<EntityType<?>> TRIFFID_PREY = TagKey.create(Registries.ENTITY_TYPE, id("triffid_prey"));
public static final TagKey<EntityType<?>> SCORPION_WHIP_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("scorpion_whip_immune"));
public static final TagKey<EntityType<?>> SCORPION_WHIP_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("scorpion_whip_blacklist"));
private Entities() {
}
}
public static final class SoundEvents {
public static final TagKey<SoundEvent> DREAD_HALLUCINATION_SOUNDS = TagKey.create(Registries.SOUND_EVENT, id("dread_hallucination_sounds"));
private SoundEvents() {
}
}
public static final class Items {
public static final TagKey<Item> EASTER_BUNNY_SPAWN_EGG_BLACKLIST = TagKey.create(Registries.ITEM, id("easter_bunny_spawn_egg_blacklist"));
public static final TagKey<Item> DUCT_TAPE_BLACKLIST = TagKey.create(Registries.ITEM, id("duct_tape_blacklist"));
public static final TagKey<Item> BROWN_ANT_ACTIVATION_ITEMS = TagKey.create(Registries.ITEM, id("brown_ant_activation_items"));
public static final TagKey<Item> BROWN_ANT_BREEDING_FOODS = TagKey.create(Registries.ITEM, id("brown_ant_breeding_foods"));
public static final TagKey<Item> RED_ANT_ACTIVATION_ITEMS = TagKey.create(Registries.ITEM, id("red_ant_activation_items"));
public static final TagKey<Item> RED_ANT_BREEDING_FOODS = TagKey.create(Registries.ITEM, id("red_ant_breeding_foods"));
public static final TagKey<Item> RAINBOW_ANT_ACTIVATION_ITEMS = TagKey.create(Registries.ITEM, id("rainbow_ant_activation_items"));
public static final TagKey<Item> RAINBOW_ANT_BREEDING_FOODS = TagKey.create(Registries.ITEM, id("rainbow_ant_breeding_foods"));
public static final TagKey<Item> TERMITE_ACTIVATION_ITEMS = TagKey.create(Registries.ITEM, id("termite_activation_items"));
public static final TagKey<Item> TERMITE_FOODS = TagKey.create(Registries.ITEM, id("termite_foods"));
public static final TagKey<Item> TERMITE_BREEDING_FOODS = TagKey.create(Registries.ITEM, id("termite_breeding_foods"));
public static final TagKey<Item> FLYING_SQUIRREL_NUTS = TagKey.create(Registries.ITEM, id("flying_squirrel_nuts"));
public static final TagKey<Item> CATERPILLAR_FOODS = TagKey.create(Registries.ITEM, id("caterpillar_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"));
private Items() {
}
}
public static final class Biomes {
public static final TagKey<Biome> MANTIS_SPAWN_BIOMES = TagKey.create(Registries.BIOME, id("mantis_spawn_biomes"));
public static final TagKey<Biome> MANTIS_OVERWORLD_SPAWN_BIOMES = TagKey.create(Registries.BIOME, id("mantis_overworld_spawn_biomes"));
private Biomes() {
}
}
}
@@ -0,0 +1,42 @@
package com.craisinlord.antarchy.content;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.entity.SizeRayProjectileEntity;
import com.craisinlord.antarchy.content.item.SizeRayItem;
import net.minecraft.core.Direction;
import net.minecraft.core.Position;
import net.minecraft.core.dispenser.BlockSource;
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.DispenserBlock;
public class SizeRayDispenseBehavior extends DefaultDispenseItemBehavior {
@Override
protected ItemStack execute(BlockSource source, ItemStack stack) {
if (!AntarchySettings.sizeChangingRaysEnabled()) {
return super.execute(source, stack);
}
if (!(stack.getItem() instanceof SizeRayItem sizeRayItem)) {
return super.execute(source, stack);
}
Direction direction = source.state().getValue(DispenserBlock.FACING);
Position position = DispenserBlock.getDispensePosition(source);
SizeRayProjectileEntity projectile = sizeRayItem.createProjectile(source.level(), stack);
projectile.setPos(position.x(), position.y(), position.z());
projectile.shoot(direction.getStepX(), direction.getStepY() + 0.1D, direction.getStepZ(), 1.6F, 0.0F);
source.level().addFreshEntity(projectile);
if (stack.isDamageableItem()) {
int nextDamage = stack.getDamageValue() + 1;
if (nextDamage >= stack.getMaxDamage()) {
stack.shrink(1);
} else {
stack.setDamageValue(nextDamage);
}
} else {
stack.shrink(1);
}
return stack;
}
}
@@ -0,0 +1,191 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.block.entity.AntNestBlockEntity;
import com.craisinlord.antarchy.content.entity.ant.BaseAntEntity;
import com.mojang.serialization.MapCodec;
import java.util.List;
import java.util.function.Supplier;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.Registries;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BaseEntityBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.world.item.context.BlockPlaceContext;
public class AntNestBlock extends BaseEntityBlock {
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
private final Supplier<List<EntityType<? extends BaseAntEntity>>> antTypesSupplier;
private final Supplier<? extends BlockEntityType<AntNestBlockEntity>> blockEntityTypeSupplier;
private final int maxOccupants;
private final boolean populateInitialAnts;
private final boolean damageSteppers;
private final MapCodec<AntNestBlock> codec;
public AntNestBlock(
Supplier<? extends EntityType<? extends BaseAntEntity>> antTypeSupplier,
Supplier<? extends BlockEntityType<AntNestBlockEntity>> blockEntityTypeSupplier,
BlockBehaviour.Properties properties
) {
this(() -> List.of(antTypeSupplier.get()), blockEntityTypeSupplier, 7, true, false, properties);
}
public AntNestBlock(
Supplier<? extends EntityType<? extends BaseAntEntity>> antTypeSupplier,
Supplier<? extends BlockEntityType<AntNestBlockEntity>> blockEntityTypeSupplier,
boolean damageSteppers,
BlockBehaviour.Properties properties
) {
this(() -> List.of(antTypeSupplier.get()), blockEntityTypeSupplier, 7, true, damageSteppers, properties);
}
public AntNestBlock(
Supplier<List<EntityType<? extends BaseAntEntity>>> antTypesSupplier,
Supplier<? extends BlockEntityType<AntNestBlockEntity>> blockEntityTypeSupplier,
int maxOccupants,
boolean populateInitialAnts,
boolean damageSteppers,
BlockBehaviour.Properties properties
) {
super(properties);
this.antTypesSupplier = antTypesSupplier;
this.blockEntityTypeSupplier = blockEntityTypeSupplier;
this.maxOccupants = maxOccupants;
this.populateInitialAnts = populateInitialAnts;
this.damageSteppers = damageSteppers;
this.codec = Block.simpleCodec(ignored -> this);
this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH));
}
@Override
public MapCodec<AntNestBlock> codec() {
return this.codec;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite());
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FACING);
}
@Override
protected RenderShape getRenderShape(BlockState state) {
return RenderShape.MODEL;
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new AntNestBlockEntity(pos, state);
}
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
return level.isClientSide
? null
: createTickerHelper(blockEntityType, this.blockEntityTypeSupplier.get(),
(tickLevel, tickPos, tickState, nest) -> {
if (tickLevel instanceof ServerLevel serverLevel) {
AntNestBlockEntity.serverTick(serverLevel, tickPos, tickState, nest);
}
});
}
@Override
public void setPlacedBy(Level level, BlockPos pos, BlockState state, net.minecraft.world.entity.LivingEntity placer, ItemStack stack) {
super.setPlacedBy(level, pos, state, placer, stack);
if (!level.isClientSide && this.populateInitialAnts && level.getBlockEntity(pos) instanceof AntNestBlockEntity nestBlockEntity) {
nestBlockEntity.populateInitialAnts((ServerLevel) level);
}
}
@Override
public ItemStack getCloneItemStack(net.minecraft.world.level.LevelReader level, BlockPos pos, BlockState state) {
ItemStack stack = super.getCloneItemStack(level, pos, state);
if (level instanceof Level actualLevel && actualLevel.getBlockEntity(pos) instanceof AntNestBlockEntity nestBlockEntity) {
BlockItem.setBlockEntityData(stack, AntarchyObjects.ANT_NEST_BLOCK_ENTITY.get(), nestBlockEntity.saveWithoutMetadata(actualLevel.registryAccess()));
}
return stack;
}
@Override
public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, BlockEntity blockEntity, ItemStack stack) {
var silkTouch = level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).getOrThrow(Enchantments.SILK_TOUCH);
boolean hasSilkTouch = EnchantmentHelper.getItemEnchantmentLevel(silkTouch, stack) > 0;
ItemStack droppedNest = hasSilkTouch ? this.getCloneItemStack(level, pos, state) : ItemStack.EMPTY;
super.playerDestroy(level, player, pos, state, blockEntity, stack);
if (hasSilkTouch) {
if (!droppedNest.isEmpty() && level instanceof ServerLevel serverLevel) {
Block.popResource(serverLevel, pos, droppedNest);
}
return;
}
if (blockEntity instanceof AntNestBlockEntity nestBlockEntity && level instanceof ServerLevel serverLevel) {
nestBlockEntity.releaseAll(serverLevel);
}
}
@Override
public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) {
if (this.damageSteppers && entity instanceof LivingEntity && !entity.isSteppingCarefully()) {
entity.hurt(level.damageSources().hotFloor(), 1.0F);
}
super.stepOn(level, pos, state, entity);
}
public boolean canAccept(EntityType<?> antType) {
for (EntityType<? extends BaseAntEntity> supportedType : this.antTypes()) {
if (supportedType == antType) {
return true;
}
}
return false;
}
public int maxOccupants() {
return this.maxOccupants;
}
public boolean shouldPopulateInitialAnts() {
return this.populateInitialAnts;
}
public EntityType<? extends BaseAntEntity> initialAntType(RandomSource random) {
List<EntityType<? extends BaseAntEntity>> antTypes = this.antTypes();
if (antTypes.isEmpty()) {
throw new IllegalStateException("Ant nest block must declare at least one supported ant type");
}
return antTypes.get(random.nextInt(antTypes.size()));
}
private List<EntityType<? extends BaseAntEntity>> antTypes() {
return this.antTypesSupplier.get();
}
}
@@ -0,0 +1,17 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.world.level.block.ScaffoldingBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
public class AntimetalScaffoldingBlock extends ScaffoldingBlock {
public static final MapCodec<AntimetalScaffoldingBlock> CODEC = simpleCodec(AntimetalScaffoldingBlock::new);
// @Override
// public MapCodec<AntimetalScaffoldingBlock> codec() { return CODEC; }
public AntimetalScaffoldingBlock(BlockBehaviour.Properties properties) {
super(properties);
}
}
@@ -0,0 +1,208 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.entity.BedBugEntity;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.entity.ambient.Bat;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.monster.Zombie;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.GameRules;
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.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.IntegerProperty;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class BedBugEggBlock extends Block {
public static final MapCodec<BedBugEggBlock> CODEC = Block.simpleCodec(BedBugEggBlock::new);
public static final IntegerProperty HATCH = BlockStateProperties.HATCH;
public static final IntegerProperty EGGS = BlockStateProperties.EGGS;
private static final int MAX_HATCH = 2;
private static final int MAX_EGGS = 4;
private static final VoxelShape SINGLE_SHAPE = Block.box(3.0D, 0.0D, 3.0D, 13.0D, 7.0D, 13.0D);
private static final VoxelShape MULTI_SHAPE = Block.box(1.0D, 0.0D, 1.0D, 15.0D, 7.0D, 15.0D);
public BedBugEggBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(HATCH, 0).setValue(EGGS, 1));
}
@Override
public MapCodec<BedBugEggBlock> codec() {
return CODEC;
}
@Override
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(EGGS) > 1 ? MULTI_SHAPE : SINGLE_SHAPE;
}
@Override
protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
}
@Override
protected BlockState updateShape(
BlockState state,
Direction direction,
BlockState neighborState,
LevelAccessor level,
BlockPos pos,
BlockPos neighborPos
) {
return state.canSurvive(level, pos) ? super.updateShape(state, direction, neighborState, level, pos, neighborPos) : Blocks.AIR.defaultBlockState();
}
@Override
protected boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
return !context.isSecondaryUseActive()
&& context.getItemInHand().is(this.asItem())
&& state.getValue(EGGS) < MAX_EGGS;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockState existingState = context.getLevel().getBlockState(context.getClickedPos());
if (existingState.is(this)) {
return existingState.setValue(EGGS, Math.min(MAX_EGGS, existingState.getValue(EGGS) + 1));
}
return this.defaultBlockState();
}
@Override
protected boolean isRandomlyTicking(BlockState state) {
return true;
}
@Override
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!this.shouldUpdateHatchLevel(level) || !hasHatchSupport(level, pos)) {
return;
}
int hatch = state.getValue(HATCH);
if (hatch < MAX_HATCH) {
level.setBlock(pos, state.setValue(HATCH, hatch + 1), 2);
level.playSound(null, pos, SoundEvents.TURTLE_EGG_CRACK, SoundSource.BLOCKS, 0.7F, 0.95F + random.nextFloat() * 0.1F);
return;
}
this.hatchEggs(level, pos, state, random);
}
@Override
public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) {
if (!entity.isSteppingCarefully()) {
this.destroyEgg(level, state, pos, entity, 100);
}
super.stepOn(level, pos, state, entity);
}
@Override
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
if (!(entity instanceof Zombie)) {
this.destroyEgg(level, state, pos, entity, 3);
}
super.fallOn(level, state, pos, entity, fallDistance);
}
@Override
protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean isMoving) {
if (hasHatchSupport(level, pos) && !level.isClientSide) {
level.levelEvent(2012, pos, 15);
}
}
@Override
public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, BlockEntity blockEntity, net.minecraft.world.item.ItemStack stack) {
super.playerDestroy(level, player, pos, state, blockEntity, stack);
this.decreaseEggs(level, pos, state);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(HATCH, EGGS);
}
public static boolean hasHatchSupport(BlockGetter level, BlockPos pos) {
return isSupportedGround(level, pos.below());
}
public static boolean isSupportedGround(BlockGetter level, BlockPos pos) {
return level.getBlockState(pos).is(BlockTags.SAND) || level.getBlockState(pos).blocksMotion();
}
private void destroyEgg(Level level, BlockState state, BlockPos pos, Entity entity, int chance) {
if (level.isClientSide || !this.canDestroyEgg(level, entity) || level.random.nextInt(chance) != 0) {
return;
}
level.playSound(null, pos, SoundEvents.TURTLE_EGG_BREAK, SoundSource.BLOCKS, 0.7F, 0.9F + level.random.nextFloat() * 0.2F);
this.decreaseEggs(level, pos, state);
}
private void hatchEggs(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) {
level.removeBlock(pos, false);
level.playSound(null, pos, SoundEvents.TURTLE_EGG_HATCH, SoundSource.BLOCKS, 0.75F, 0.95F + random.nextFloat() * 0.1F);
for (int i = 0; i < state.getValue(EGGS); i++) {
BedBugEntity bedBug = AntarchyObjects.BED_BUG.get().create(level);
if (bedBug == null) {
continue;
}
bedBug.setAge(-24000);
bedBug.setHomeEggPos(pos);
double spawnX = pos.getX() + 0.25D + random.nextDouble() * 0.5D;
double spawnZ = pos.getZ() + 0.25D + random.nextDouble() * 0.5D;
bedBug.moveTo(spawnX, pos.getY() + 0.1D, spawnZ, random.nextFloat() * 360.0F, 0.0F);
level.addFreshEntity(bedBug);
}
}
private void decreaseEggs(Level level, BlockPos pos, BlockState state) {
int eggs = state.getValue(EGGS);
if (eggs <= 1) {
level.destroyBlock(pos, false);
return;
}
level.setBlock(pos, state.setValue(EGGS, eggs - 1), 2);
}
private boolean shouldUpdateHatchLevel(Level level) {
return level.random.nextInt(500) == 0;
}
private boolean canDestroyEgg(Level level, Entity entity) {
if (entity instanceof BedBugEntity || entity instanceof Bat) {
return false;
}
if (entity instanceof net.minecraft.world.entity.LivingEntity) {
return entity instanceof Player || level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
}
return false;
}
}
@@ -0,0 +1,84 @@
package com.craisinlord.antarchy.content.block;
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.level.block.AmethystClusterBlock;
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.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import java.util.function.Supplier;
public class BloodCrystalGrowthBlock extends Block {
private static final Direction[] DIRECTIONS = Direction.values();
private final Supplier<? extends Block> smallBud;
private final Supplier<? extends Block> mediumBud;
private final Supplier<? extends Block> largeBud;
private final Supplier<? extends Block> cluster;
public BloodCrystalGrowthBlock(
Properties properties,
Supplier<? extends Block> smallBud,
Supplier<? extends Block> mediumBud,
Supplier<? extends Block> largeBud,
Supplier<? extends Block> cluster
) {
super(properties);
this.smallBud = smallBud;
this.mediumBud = mediumBud;
this.largeBud = largeBud;
this.cluster = cluster;
}
@Override
protected boolean isRandomlyTicking(BlockState state) {
return !state.is(this.cluster.get());
}
@Override
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (random.nextInt(5) != 0) {
return;
}
Direction direction = DIRECTIONS[random.nextInt(DIRECTIONS.length)];
BlockPos targetPos = pos.relative(direction);
BlockState targetState = level.getBlockState(targetPos);
Block nextBlock = null;
if (canGrowInto(targetState)) {
nextBlock = this.smallBud.get();
} else if (isStage(targetState, this.smallBud.get(), direction)) {
nextBlock = this.mediumBud.get();
} else if (isStage(targetState, this.mediumBud.get(), direction)) {
nextBlock = this.largeBud.get();
} else if (isStage(targetState, this.largeBud.get(), direction)) {
nextBlock = this.cluster.get();
}
if (nextBlock == null) {
return;
}
FluidState fluidState = targetState.getFluidState();
BlockState nextState = nextBlock.defaultBlockState()
.setValue(AmethystClusterBlock.FACING, direction)
.setValue(BlockStateProperties.WATERLOGGED, fluidState.getType() == Fluids.WATER && fluidState.getAmount() == 8);
level.setBlockAndUpdate(targetPos, nextState);
}
private static boolean canGrowInto(BlockState state) {
return state.isAir() || state.is(Blocks.WATER) && state.getFluidState().getAmount() == 8;
}
private static boolean isStage(BlockState state, Block block, Direction direction) {
return state.is(block) && state.hasProperty(AmethystClusterBlock.FACING) && state.getValue(AmethystClusterBlock.FACING) == direction;
}
}
@@ -0,0 +1,84 @@
package com.craisinlord.antarchy.content.block;
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.level.block.AmethystClusterBlock;
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.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import java.util.function.Supplier;
public class BuddingBloodCrystalBlock extends Block {
private static final Direction[] DIRECTIONS = Direction.values();
private final Supplier<? extends Block> smallBud;
private final Supplier<? extends Block> mediumBud;
private final Supplier<? extends Block> largeBud;
private final Supplier<? extends Block> crystal;
public BuddingBloodCrystalBlock(
Properties properties,
Supplier<? extends Block> smallBud,
Supplier<? extends Block> mediumBud,
Supplier<? extends Block> largeBud,
Supplier<? extends Block> crystal
) {
super(properties);
this.smallBud = smallBud;
this.mediumBud = mediumBud;
this.largeBud = largeBud;
this.crystal = crystal;
}
@Override
protected boolean isRandomlyTicking(BlockState state) {
return true;
}
@Override
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (random.nextInt(5) != 0) {
return;
}
Direction direction = DIRECTIONS[random.nextInt(DIRECTIONS.length)];
BlockPos targetPos = pos.relative(direction);
BlockState targetState = level.getBlockState(targetPos);
Block nextBlock = null;
if (canGrowInto(targetState)) {
nextBlock = this.smallBud.get();
} else if (isStage(targetState, this.smallBud.get(), direction)) {
nextBlock = this.mediumBud.get();
} else if (isStage(targetState, this.mediumBud.get(), direction)) {
nextBlock = this.largeBud.get();
} else if (isStage(targetState, this.largeBud.get(), direction)) {
nextBlock = this.crystal.get();
}
if (nextBlock == null) {
return;
}
FluidState fluidState = targetState.getFluidState();
BlockState nextState = nextBlock.defaultBlockState()
.setValue(AmethystClusterBlock.FACING, direction)
.setValue(BlockStateProperties.WATERLOGGED, fluidState.getType() == Fluids.WATER && fluidState.getAmount() == 8);
level.setBlockAndUpdate(targetPos, nextState);
}
private static boolean canGrowInto(BlockState state) {
return state.isAir() || state.is(Blocks.WATER) && state.getFluidState().getAmount() == 8;
}
private static boolean isStage(BlockState state, Block block, Direction direction) {
return state.is(block) && state.hasProperty(AmethystClusterBlock.FACING) && state.getValue(AmethystClusterBlock.FACING) == direction;
}
}
@@ -0,0 +1,86 @@
package com.craisinlord.antarchy.content.block;
import java.util.Optional;
import java.util.function.Supplier;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.LevelReader;
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.BucketPickup;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.EntityCollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jetbrains.annotations.Nullable;
public final class CloudBlock extends Block implements BucketPickup {
private static final VoxelShape EMPTY = Shapes.empty();
private final Supplier<Item> bucketItem;
public CloudBlock(Supplier<Item> bucketItem, BlockBehaviour.Properties properties) {
super(properties);
this.bucketItem = bucketItem;
}
@Override
protected VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
if (context instanceof EntityCollisionContext ecc) {
Entity entity = ecc.getEntity();
if (entity instanceof net.minecraft.world.entity.LivingEntity le && le.isShiftKeyDown()) {
return EMPTY;
}
}
return Shapes.block();
}
@Override
protected VoxelShape getVisualShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return EMPTY;
}
@Override
protected boolean skipRendering(BlockState state, BlockState adjacentBlockState, Direction side) {
return adjacentBlockState.is(this) || super.skipRendering(state, adjacentBlockState, side);
}
@Override
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
entity.causeFallDamage(fallDistance, 0.0F, level.damageSources().fall());
}
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
Vec3 motion = entity.getDeltaMovement();
double slowedY = motion.y < 0.0D ? Math.max(motion.y * 0.4D, -0.08D) : motion.y;
entity.setDeltaMovement(motion.x * 0.92D, slowedY, motion.z * 0.92D);
entity.fallDistance = 0.0F;
}
public ItemStack pickupBlock(@Nullable Player player, LevelAccessor level, BlockPos pos, BlockState state) {
level.setBlock(pos, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), 11);
return new ItemStack(bucketItem.get());
}
@Override
public ItemStack getCloneItemStack(LevelReader level, BlockPos pos, BlockState state) {
return new ItemStack(bucketItem.get());
}
@Override
public Optional<SoundEvent> getPickupSound() {
return Optional.of(SoundEvents.BUCKET_FILL);
}
}
@@ -0,0 +1,184 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.damage.AntarchyDamageSources;
import com.mojang.serialization.MapCodec;
import java.util.Optional;
import com.craisinlord.antarchy.content.AntarchyTags;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.ItemStack;
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.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.BooleanProperty;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.world.item.Item;
import net.minecraft.world.ItemInteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.core.registries.Registries;
public class CorneaStalkBlock extends BushBlock implements BonemealableBlock {
public static final MapCodec<CorneaStalkBlock> CODEC = Block.simpleCodec(CorneaStalkBlock::new);
public static final IntegerProperty AGE = BlockStateProperties.AGE_3;
public static final BooleanProperty HANGING = BlockStateProperties.HANGING;
private static final int MAX_AGE = 3;
private static final int RIPE_AGE = 2;
private static final VoxelShape[] FLOOR_SHAPES = new VoxelShape[] {
Block.box(5.0D, 0.0D, 5.0D, 11.0D, 7.0D, 11.0D),
Block.box(4.0D, 0.0D, 4.0D, 12.0D, 10.0D, 12.0D),
Block.box(3.0D, 0.0D, 3.0D, 13.0D, 13.0D, 13.0D),
Block.box(2.5D, 0.0D, 2.5D, 13.5D, 14.5D, 13.5D)
};
private static final VoxelShape[] HANGING_SHAPES = new VoxelShape[] {
Block.box(5.0D, 9.0D, 5.0D, 11.0D, 16.0D, 11.0D),
Block.box(4.0D, 6.0D, 4.0D, 12.0D, 16.0D, 12.0D),
Block.box(3.0D, 3.0D, 3.0D, 13.0D, 16.0D, 13.0D),
Block.box(2.5D, 1.5D, 2.5D, 13.5D, 16.0D, 13.5D)
};
private static final ResourceLocation CORNEA_EAR_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "cornea_ear");
public CorneaStalkBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(AGE, 0).setValue(HANGING, false));
}
@Override
public MapCodec<CorneaStalkBlock> codec() {
return CODEC;
}
@Override
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(HANGING) ? HANGING_SHAPES[state.getValue(AGE)] : FLOOR_SHAPES[state.getValue(AGE)];
}
@Override
protected boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos) {
return state.is(AntarchyTags.Blocks.CORNEA_STALK_PLANTABLE);
}
@Override
protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
BlockPos supportPos = state.getValue(HANGING) ? pos.above() : pos.below();
return this.mayPlaceOn(level.getBlockState(supportPos), level, supportPos);
}
@Override
protected BlockState updateShape(BlockState state, net.minecraft.core.Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
return state.canSurvive(level, pos) ? super.updateShape(state, direction, neighborState, level, pos, neighborPos) : net.minecraft.world.level.block.Blocks.AIR.defaultBlockState();
}
@Override
protected boolean isRandomlyTicking(BlockState state) {
return state.getValue(AGE) < MAX_AGE;
}
@Override
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
int age = state.getValue(AGE);
if (age >= MAX_AGE) {
return;
}
BlockPos growthEndPos = state.getValue(HANGING) ? pos.below() : pos.above();
if (level.getMaxLocalRawBrightness(growthEndPos) >= 9 && random.nextInt(5) == 0) {
level.setBlock(pos, state.setValue(AGE, age + 1), Block.UPDATE_ALL);
}
}
@Override
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
if (!level.isClientSide && state.getValue(AGE) > 0 && entity instanceof LivingEntity livingEntity && !livingEntity.isSteppingCarefully()) {
livingEntity.hurt(AntarchyDamageSources.corneaStalkPrick(level), 1.0F);
}
super.entityInside(state, level, pos, entity);
}
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state) {
return state.getValue(AGE) < MAX_AGE;
}
@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) {
int age = state.getValue(AGE);
if (age < MAX_AGE) {
level.setBlock(pos, state.setValue(AGE, age + 1), Block.UPDATE_ALL);
}
}
@Override
protected ItemInteractionResult useItemOn(
ItemStack stack,
BlockState state,
Level level,
BlockPos pos,
Player player,
net.minecraft.world.InteractionHand hand,
net.minecraft.world.phys.BlockHitResult hitResult
) {
if (!state.is(this) || state.getValue(AGE) < RIPE_AGE) {
return super.useItemOn(stack, state, level, pos, player, hand, hitResult);
}
if (!level.isClientSide) {
this.dropCorneaFruit(level, pos, level.random);
level.setBlock(pos, state.setValue(AGE, 1), Block.UPDATE_ALL);
}
return ItemInteractionResult.sidedSuccess(level.isClientSide);
}
@Override
public ItemStack getCloneItemStack(LevelReader level, BlockPos pos, BlockState state) {
return BuiltInRegistries.ITEM.getOptional(CORNEA_EAR_ID)
.map(ItemStack::new)
.orElseGet(() -> super.getCloneItemStack(level, pos, state));
}
@Override
public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, net.minecraft.world.level.block.entity.BlockEntity blockEntity, ItemStack stack) {
super.playerDestroy(level, player, pos, state, blockEntity, stack);
var silkTouch = level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).getOrThrow(Enchantments.SILK_TOUCH);
if (EnchantmentHelper.getItemEnchantmentLevel(silkTouch, stack) > 0) {
return;
}
if (state.getValue(AGE) >= RIPE_AGE && level instanceof ServerLevel serverLevel) {
this.dropCorneaFruit(serverLevel, pos, serverLevel.random);
}
}
private void dropCorneaFruit(Level level, BlockPos pos, RandomSource random) {
Optional<Item> item = BuiltInRegistries.ITEM.getOptional(CORNEA_EAR_ID);
item.ifPresent(value -> Block.popResource(level, pos, new ItemStack(value, 1 + random.nextInt(2))));
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(AGE, HANGING);
}
}
@@ -0,0 +1,51 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.block.entity.DreamCampfireBlockEntity;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.CampfireBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.entity.CampfireBlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
public class DreamCampfireBlock extends CampfireBlock {
@SuppressWarnings("rawtypes")
public static final MapCodec<CampfireBlock> CODEC = (MapCodec) simpleCodec(DreamCampfireBlock::new);
public DreamCampfireBlock(BlockBehaviour.Properties properties) {
super(false, 2, properties);
}
@Override
public MapCodec<CampfireBlock> codec() {
return CODEC;
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
DreamCampfireBlockEntity.beginConstruction();
try {
return new DreamCampfireBlockEntity(pos, state);
} finally {
DreamCampfireBlockEntity.endConstruction();
}
}
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
BlockEntityType<DreamCampfireBlockEntity> dreamCampfireType = AntarchyObjects.DREAM_CAMPFIRE_BLOCK_ENTITY.get();
if (level.isClientSide) {
return state.getValue(LIT)
? createTickerHelper(blockEntityType, dreamCampfireType, CampfireBlockEntity::particleTick)
: null;
}
return state.getValue(LIT)
? createTickerHelper(blockEntityType, dreamCampfireType, CampfireBlockEntity::cookTick)
: createTickerHelper(blockEntityType, dreamCampfireType, CampfireBlockEntity::cooldownTick);
}
}
@@ -0,0 +1,38 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyTags;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.SoulFireBlock;
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 DreamCeilingFireBlock extends SoulFireBlock {
private static final VoxelShape SHAPE = Block.box(2.0D, 12.0D, 2.0D, 14.0D, 16.0D, 14.0D);
@SuppressWarnings("rawtypes")
public static final MapCodec<SoulFireBlock> CODEC = (MapCodec) simpleCodec(DreamCeilingFireBlock::new);
public DreamCeilingFireBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public MapCodec<SoulFireBlock> codec() {
return CODEC;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return level.getBlockState(pos.above()).is(AntarchyTags.Blocks.DREAM_FIRE_BASE_BLOCKS);
}
@Override
public VoxelShape getShape(BlockState state, net.minecraft.world.level.BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
}
@@ -0,0 +1,28 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyTags;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.SoulFireBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.LevelReader;
public class DreamFireBlock extends SoulFireBlock {
@SuppressWarnings("rawtypes")
public static final MapCodec<SoulFireBlock> CODEC = (MapCodec) simpleCodec(DreamFireBlock::new);
public DreamFireBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public MapCodec<SoulFireBlock> codec() {
return CODEC;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).is(AntarchyTags.Blocks.DREAM_FIRE_BASE_BLOCKS);
}
}
@@ -0,0 +1,28 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.FallingBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
public class DreamSandBlock extends FallingBlock {
@SuppressWarnings("rawtypes")
public static final MapCodec<FallingBlock> CODEC = (MapCodec) simpleCodec(DreamSandBlock::new);
public DreamSandBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public MapCodec<FallingBlock> codec() {
return CODEC;
}
@Override
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
entity.causeFallDamage(fallDistance, 0.0F, level.damageSources().fall());
}
}
@@ -0,0 +1,36 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.TorchBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
public class DreamTorchBlock extends TorchBlock {
private static final ResourceLocation DREAM_FIRE_FLAME_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "dream_fire_flame");
public DreamTorchBlock(BlockBehaviour.Properties properties) {
super(ParticleTypes.SOUL_FIRE_FLAME, properties);
}
@Override
public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) {
double x = pos.getX() + 0.5D;
double y = pos.getY() + 0.7D;
double z = pos.getZ() + 0.5D;
level.addParticle(ParticleTypes.SMOKE, x, y, z, 0.0D, 0.0D, 0.0D);
level.addParticle(getDreamFlameParticle(), x, y, z, 0.0D, 0.0D, 0.0D);
}
private static ParticleOptions getDreamFlameParticle() {
return BuiltInRegistries.PARTICLE_TYPE.get(DREAM_FIRE_FLAME_ID) instanceof ParticleOptions particleOptions
? particleOptions
: ParticleTypes.SOUL_FIRE_FLAME;
}
}
@@ -0,0 +1,38 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
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.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.WallTorchBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
public class DreamWallTorchBlock extends WallTorchBlock {
private static final ResourceLocation DREAM_FIRE_FLAME_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "dream_fire_flame");
public DreamWallTorchBlock(BlockBehaviour.Properties properties) {
super(ParticleTypes.SOUL_FIRE_FLAME, properties);
}
@Override
public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) {
Direction direction = state.getValue(FACING).getOpposite();
double x = pos.getX() + 0.5D + 0.27D * direction.getStepX();
double y = pos.getY() + 0.92D;
double z = pos.getZ() + 0.5D + 0.27D * direction.getStepZ();
level.addParticle(ParticleTypes.SMOKE, x, y, z, 0.0D, 0.0D, 0.0D);
level.addParticle(getDreamFlameParticle(), x, y, z, 0.0D, 0.0D, 0.0D);
}
private static ParticleOptions getDreamFlameParticle() {
return BuiltInRegistries.PARTICLE_TYPE.get(DREAM_FIRE_FLAME_ID) instanceof ParticleOptions particleOptions
? particleOptions
: ParticleTypes.SOUL_FIRE_FLAME;
}
}
@@ -0,0 +1,538 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.AntarchyAdvancements;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.AntarchySoundEvents;
import com.craisinlord.antarchy.content.AntarchyTags;
import com.mojang.serialization.MapCodec;
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.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.ItemInteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.DiggerItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ShearsItem;
import net.minecraft.world.item.SwordItem;
import net.minecraft.world.item.context.BlockPlaceContext;
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.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.AttachFace;
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.EnumProperty;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public class DuctTapeBlock extends Block {
public static final MapCodec<DuctTapeBlock> CODEC = Block.simpleCodec(DuctTapeBlock::new);
public static final int MAX_USES = 4;
private static final ResourceLocation DUCT_TAPE_ADVANCEMENT_ID = ResourceLocation.fromNamespaceAndPath("antarchy", "duct_tape");
public static final IntegerProperty USES = IntegerProperty.create("uses", 1, MAX_USES);
public static final EnumProperty<AttachFace> FACE = BlockStateProperties.ATTACH_FACE;
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
private static final int TAPE_HEIGHT = 2;
private static final long STICK_SOUND_COOLDOWN_TICKS = 10L;
private static final long TAPE_DECAY_INTERVAL_TICKS = 30L;
private static final double FLOOR_TRIGGER_HEIGHT = 0.30D;
private static final double WALL_TRIGGER_DEPTH = 0.25D;
private static final double TRIGGER_PAD = 0.12D;
private static final double WALL_Y_PAD = 0.12D;
private static final double WALL_SIDE_PAD = 0.08D;
private static final double WALL_INNER_INSET = 0.03D;
private static final double TRIGGER_INFLATE_DEFAULT = 0.15D;
private static final Map<UUID, Long> STICK_SOUND_TIMES = new HashMap<>();
private static final Map<UUID, String> STICK_CONTACT_KEYS = new HashMap<>();
private static final Map<String, Long> TAPE_DECAY_TIMES = new HashMap<>();
private static final Map<UUID, StuckContact> STUCK_ENTITIES = new HashMap<>();
public DuctTapeBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any()
.setValue(USES, MAX_USES)
.setValue(FACE, AttachFace.FLOOR)
.setValue(FACING, Direction.NORTH));
}
@Override
public MapCodec<DuctTapeBlock> codec() {
return CODEC;
}
@Override
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return getShapeFor(state);
}
@Override
protected VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return Shapes.empty();
}
@Override
protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return switch (state.getValue(FACE)) {
case FLOOR -> level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
case WALL -> {
BlockPos supportPos = pos.relative(state.getValue(FACING).getOpposite());
yield level.getBlockState(supportPos).isFaceSturdy(level, supportPos, state.getValue(FACING));
}
default -> false;
};
}
@Override
protected BlockState updateShape(
BlockState state,
Direction direction,
BlockState neighborState,
LevelAccessor level,
BlockPos pos,
BlockPos neighborPos
) {
return state.canSurvive(level, pos) ? super.updateShape(state, direction, neighborState, level, pos, neighborPos) : Blocks.AIR.defaultBlockState();
}
@Override
protected boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
return false;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
Direction clickedFace = context.getClickedFace();
BlockState state = this.defaultBlockState();
if (clickedFace.getAxis().isHorizontal()) {
state = state.setValue(FACE, AttachFace.WALL).setValue(FACING, clickedFace);
} else {
state = state.setValue(FACE, AttachFace.FLOOR).setValue(FACING, context.getHorizontalDirection());
}
return state.canSurvive(context.getLevel(), context.getClickedPos()) ? state : null;
}
@Override
protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
if (!state.is(newState.getBlock())) {
releaseEntitiesForTape(level, pos);
}
super.onRemove(state, level, pos, newState, movedByPiston);
}
@Override
protected ItemInteractionResult useItemOn(
ItemStack stack,
BlockState state,
Level level,
BlockPos pos,
Player player,
InteractionHand hand,
BlockHitResult hitResult
) {
if (stack.is(AntarchyObjects.DUCT_TAPE.get().asItem())) {
return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
}
if (isReleaseTool(stack) && (isStuckToTape(player) || isTouchingTape(level, player))) {
if (!level.isClientSide) {
consumeTapeUse(level, pos, state);
level.playSound(null, pos, SoundEvents.WOOL_BREAK, SoundSource.BLOCKS, 0.8F, 0.9F + level.random.nextFloat() * 0.2F);
}
return ItemInteractionResult.sidedSuccess(level.isClientSide);
}
if (!stack.isDamageableItem() || !stack.isDamaged() || stack.is(AntarchyTags.Items.DUCT_TAPE_BLACKLIST)) {
return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
}
int repairPerUse = Math.max(1, (int) Math.ceil(stack.getMaxDamage() * AntarchySettings.ductTapeRepairPercentPerUse()));
int currentDamage = stack.getDamageValue();
int repairedDamage = Math.min(currentDamage, repairPerUse);
if (repairedDamage <= 0) {
return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
}
if (!level.isClientSide) {
stack.setDamageValue(currentDamage - repairedDamage);
if (!player.getAbilities().instabuild) {
consumeTapeUse(level, pos, state);
}
if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) {
AntarchyAdvancements.award(serverPlayer, DUCT_TAPE_ADVANCEMENT_ID);
}
level.playSound(null, pos, AntarchySoundEvents.DUCT_TAPE_USE.get(), SoundSource.BLOCKS, 0.9F, 0.95F + level.random.nextFloat() * 0.1F);
}
return ItemInteractionResult.sidedSuccess(level.isClientSide);
}
@Override
protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
if (level.isClientSide || entity.isSpectator() || !touchesTape(level, entity, pos, state)) {
return;
}
rememberStuckContact(level, pos, entity);
if (!(entity instanceof ItemEntity)) {
maybeConsumeTapeDecay(level, pos, state);
}
long gameTime = level.getGameTime();
String tapeKey = tapeKey(level, pos);
if (shouldPlayStickSound(entity.getUUID(), tapeKey, gameTime)) {
level.playSound(null, pos, AntarchySoundEvents.DUCT_TAPE_USE.get(), SoundSource.BLOCKS, 0.85F, 0.9F + level.random.nextFloat() * 0.15F);
}
applyStick(state, pos, entity);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(USES, FACE, FACING);
}
private static VoxelShape getShapeFor(BlockState state) {
int depth = switch (state.getValue(USES)) {
case 1 -> 4;
case 2 -> 8;
case 3 -> 12;
default -> 16;
};
return switch (state.getValue(FACE)) {
case FLOOR -> switch (state.getValue(FACING)) {
case NORTH -> Block.box(0.0D, 0.0D, 16.0D - depth, 16.0D, TAPE_HEIGHT, 16.0D);
case SOUTH -> Block.box(0.0D, 0.0D, 0.0D, 16.0D, TAPE_HEIGHT, depth);
case EAST -> Block.box(0.0D, 0.0D, 0.0D, depth, TAPE_HEIGHT, 16.0D);
case WEST -> Block.box(16.0D - depth, 0.0D, 0.0D, 16.0D, TAPE_HEIGHT, 16.0D);
default -> Block.box(0.0D, 0.0D, 0.0D, 16.0D, TAPE_HEIGHT, 16.0D);
};
case WALL -> switch (state.getValue(FACING)) {
case NORTH -> Block.box(0.0D, 16.0D - depth, 16.0D - TAPE_HEIGHT, 16.0D, 16.0D, 16.0D);
case SOUTH -> Block.box(0.0D, 16.0D - depth, 0.0D, 16.0D, 16.0D, TAPE_HEIGHT);
case EAST -> Block.box(0.0D, 16.0D - depth, 0.0D, TAPE_HEIGHT, 16.0D, 16.0D);
case WEST -> Block.box(16.0D - TAPE_HEIGHT, 16.0D - depth, 0.0D, 16.0D, 16.0D, 16.0D);
default -> Block.box(0.0D, 16.0D - depth, 0.0D, TAPE_HEIGHT, 16.0D, 16.0D);
};
default -> Block.box(0.0D, 0.0D, 0.0D, 16.0D, TAPE_HEIGHT, 16.0D);
};
}
private static boolean isReleaseTool(ItemStack stack) {
return stack.getItem() instanceof DiggerItem
|| stack.getItem() instanceof SwordItem
|| stack.getItem() instanceof ShearsItem;
}
private static void consumeTapeUse(Level level, BlockPos pos, BlockState state) {
int remainingUses = state.getValue(USES) - 1;
if (remainingUses > 0) {
level.setBlock(pos, state.setValue(USES, remainingUses), Block.UPDATE_ALL);
return;
}
releaseEntitiesForTape(level, pos);
TAPE_DECAY_TIMES.remove(tapeDecayKey(level, pos));
level.removeBlock(pos, false);
}
private static void removeTape(Level level, BlockPos pos, BlockState state) {
releaseEntitiesForTape(level, pos);
TAPE_DECAY_TIMES.remove(tapeDecayKey(level, pos));
level.removeBlock(pos, false);
}
private static void maybeConsumeTapeDecay(Level level, BlockPos pos, BlockState state) {
long gameTime = level.getGameTime();
String key = tapeDecayKey(level, pos);
Long lastConsumed = TAPE_DECAY_TIMES.get(key);
if (lastConsumed == null) {
TAPE_DECAY_TIMES.put(key, gameTime);
return;
}
if (gameTime - lastConsumed < TAPE_DECAY_INTERVAL_TICKS) {
return;
}
TAPE_DECAY_TIMES.put(key, gameTime);
consumeTapeUse(level, pos, state);
}
public static void tickStuckEntity(Entity entity) {
if (entity == null || entity.level().isClientSide() || isStickyBlacklist(entity)) {
return;
}
if (!entity.isAlive() || entity.isRemoved()) {
releaseEntity(entity);
return;
}
StuckContact contact = STUCK_ENTITIES.get(entity.getUUID());
if (contact != null && isContactValid(entity.level(), contact)) {
BlockPos pos = BlockPos.of(contact.blockPos());
BlockState state = entity.level().getBlockState(pos);
applyStick(state, pos, entity);
if (!(entity instanceof ItemEntity)) {
maybeConsumeTapeDecay(entity.level(), pos, state);
}
return;
}
if (contact != null) {
releaseEntity(entity);
}
TapeHit hit = findTouchedTape(entity.level(), entity);
if (hit == null) {
if (entity.isNoGravity()) {
entity.setNoGravity(false);
}
return;
}
rememberStuckContact(entity.level(), hit.pos(), entity);
applyStick(hit.state(), hit.pos(), entity);
if (!(entity instanceof ItemEntity)) {
maybeConsumeTapeDecay(entity.level(), hit.pos(), hit.state());
}
}
public static boolean isStuckToTape(Entity entity) {
if (entity == null || entity.level().isClientSide() || isStickyBlacklist(entity)) {
return false;
}
StuckContact contact = STUCK_ENTITIES.get(entity.getUUID());
return contact != null && isContactValid(entity.level(), contact);
}
public static boolean isTouchingTape(Entity entity) {
return entity != null && isTouchingTape(entity.level(), entity);
}
public static boolean isTouchingTape(Level level, Entity entity) {
if (isStickyBlacklist(entity)) {
return false;
}
return findTouchedTape(level, entity) != null;
}
private static boolean isStickyBlacklist(Entity entity) {
return entity != null && entity.getType().is(AntarchyTags.Entities.DUCT_TAPE_STICK_BLACKLIST);
}
private static void applyStick(BlockState state, BlockPos pos, Entity entity) {
entity.setDeltaMovement(Vec3.ZERO);
entity.resetFallDistance();
entity.hasImpulse = true;
entity.setNoGravity(true);
Vec3 anchor = getTapeAnchor(state, pos, entity);
entity.setPos(anchor.x, anchor.y, anchor.z);
if (state.getValue(FACE) == AttachFace.FLOOR) {
entity.setOnGround(true);
}
}
private static void rememberStuckContact(Level level, BlockPos pos, Entity entity) {
UUID entityId = entity.getUUID();
String key = tapeKey(level, pos);
StuckContact existing = STUCK_ENTITIES.get(entityId);
if (existing != null && existing.tapeKey().equals(key)) {
return;
}
double offsetX = entity.getX() - pos.getX();
double offsetY = entity.getY() - pos.getY();
double offsetZ = entity.getZ() - pos.getZ();
STUCK_ENTITIES.put(entityId, new StuckContact(
key,
level.dimension().location().toString(),
pos.asLong(),
clamp(offsetX, 0.05D, 0.95D),
clamp(offsetY, 0.0D, 0.98D),
clamp(offsetZ, 0.05D, 0.95D)
));
}
private static Vec3 getTapeAnchor(BlockState state, BlockPos pos, Entity entity) {
StuckContact contact = STUCK_ENTITIES.get(entity.getUUID());
double offsetX = contact != null ? contact.offsetX() : 0.5D;
double offsetY = contact != null ? contact.offsetY() : 0.0D;
double offsetZ = contact != null ? contact.offsetZ() : 0.5D;
double wallOffset = entity instanceof Player ? 0.06D : -0.28D;
double centerX = pos.getX() + 0.5D;
double centerZ = pos.getZ() + 0.5D;
return switch (state.getValue(FACE)) {
case FLOOR -> new Vec3(
pos.getX() + offsetX,
pos.getY() + 0.01D,
pos.getZ() + offsetZ
);
case WALL -> switch (state.getValue(FACING)) {
case NORTH -> new Vec3(centerX, pos.getY() + offsetY, pos.getZ() - wallOffset);
case SOUTH -> new Vec3(centerX, pos.getY() + offsetY, pos.getZ() + 1.0D + wallOffset);
case EAST -> new Vec3(pos.getX() + 1.0D + wallOffset, pos.getY() + offsetY, centerZ);
case WEST -> new Vec3(pos.getX() - wallOffset, pos.getY() + offsetY, centerZ);
default -> new Vec3(centerX, pos.getY() + offsetY, centerZ);
};
default -> new Vec3(pos.getX() + offsetX, pos.getY() + 0.01D, pos.getZ() + offsetZ);
};
}
private static boolean isContactValid(Level level, StuckContact contact) {
if (!level.dimension().location().toString().equals(contact.dimensionId())) {
return false;
}
BlockPos pos = BlockPos.of(contact.blockPos());
BlockState state = level.getBlockState(pos);
return state.getBlock() instanceof DuctTapeBlock
&& tapeKey(level, pos).equals(contact.tapeKey());
}
private static TapeHit findTouchedTape(Level level, Entity entity) {
AABB box = entity.getBoundingBox().inflate(0.30D);
BlockPos min = BlockPos.containing(box.minX, box.minY, box.minZ);
BlockPos max = BlockPos.containing(box.maxX, box.maxY, box.maxZ);
BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos();
for (int x = min.getX(); x <= max.getX(); x++) {
for (int y = min.getY(); y <= max.getY(); y++) {
for (int z = min.getZ(); z <= max.getZ(); z++) {
cursor.set(x, y, z);
BlockState state = level.getBlockState(cursor);
if (state.getBlock() instanceof DuctTapeBlock && touchesTape(level, entity, cursor, state)) {
return new TapeHit(cursor.immutable(), state);
}
}
}
}
return null;
}
private static boolean touchesTape(Level level, Entity entity, BlockPos pos, BlockState state) {
return entity.getBoundingBox().intersects(getStickyTriggerBounds(state, pos));
}
private static AABB getStickyTriggerBounds(BlockState state, BlockPos pos) {
AABB bounds = getShapeFor(state).bounds().move(pos);
return switch (state.getValue(FACE)) {
case FLOOR -> new AABB(
bounds.minX - TRIGGER_PAD,
pos.getY() - 0.02D,
bounds.minZ - TRIGGER_PAD,
bounds.maxX + TRIGGER_PAD,
pos.getY() + FLOOR_TRIGGER_HEIGHT,
bounds.maxZ + TRIGGER_PAD
);
case WALL -> {
yield switch (state.getValue(FACING)) {
case NORTH -> new AABB(bounds.minX - WALL_SIDE_PAD, bounds.minY - WALL_Y_PAD, bounds.minZ - WALL_TRIGGER_DEPTH, bounds.maxX + WALL_SIDE_PAD, bounds.maxY + WALL_Y_PAD, bounds.maxZ + WALL_INNER_INSET);
case SOUTH -> new AABB(bounds.minX - WALL_SIDE_PAD, bounds.minY - WALL_Y_PAD, bounds.minZ - WALL_INNER_INSET, bounds.maxX + WALL_SIDE_PAD, bounds.maxY + WALL_Y_PAD, bounds.maxZ + WALL_TRIGGER_DEPTH);
case EAST -> new AABB(bounds.minX - WALL_TRIGGER_DEPTH, bounds.minY - WALL_Y_PAD, bounds.minZ - WALL_SIDE_PAD, bounds.maxX + WALL_INNER_INSET, bounds.maxY + WALL_Y_PAD, bounds.maxZ + WALL_SIDE_PAD);
case WEST -> new AABB(bounds.minX - WALL_INNER_INSET, bounds.minY - WALL_Y_PAD, bounds.minZ - WALL_SIDE_PAD, bounds.maxX + WALL_TRIGGER_DEPTH, bounds.maxY + WALL_Y_PAD, bounds.maxZ + WALL_SIDE_PAD);
default -> bounds.inflate(TRIGGER_INFLATE_DEFAULT);
};
}
default -> bounds.inflate(TRIGGER_INFLATE_DEFAULT);
};
}
private static void releaseEntitiesForTape(Level level, BlockPos pos) {
String key = tapeKey(level, pos);
AABB searchBox = AABB.unitCubeFromLowerCorner(Vec3.atLowerCornerOf(pos)).inflate(2.0D);
STUCK_ENTITIES.entrySet().removeIf(entry -> {
StuckContact contact = entry.getValue();
if (!key.equals(contact.tapeKey())) {
return false;
}
level.getEntitiesOfClass(Entity.class, searchBox, candidate -> candidate.getUUID().equals(entry.getKey()))
.forEach(candidate -> candidate.setNoGravity(false));
STICK_SOUND_TIMES.remove(entry.getKey());
STICK_CONTACT_KEYS.remove(entry.getKey());
return true;
});
}
private static void releaseEntity(Entity entity) {
if (entity == null) {
return;
}
STUCK_ENTITIES.remove(entity.getUUID());
STICK_SOUND_TIMES.remove(entity.getUUID());
STICK_CONTACT_KEYS.remove(entity.getUUID());
entity.setNoGravity(false);
}
private static String tapeDecayKey(Level level, BlockPos pos) {
return level.dimension().location() + ":" + pos.asLong();
}
private static String tapeKey(Level level, BlockPos pos) {
return level.dimension().location() + ":" + pos.asLong();
}
private static boolean shouldPlayStickSound(UUID entityId, String tapeKey, long gameTime) {
String lastKey = STICK_CONTACT_KEYS.get(entityId);
Long lastContact = STICK_SOUND_TIMES.get(entityId);
if (lastKey == null || !tapeKey.equals(lastKey)) {
STICK_CONTACT_KEYS.put(entityId, tapeKey);
STICK_SOUND_TIMES.put(entityId, gameTime);
return true;
}
if (lastContact == null || gameTime - lastContact > STICK_SOUND_COOLDOWN_TICKS) {
STICK_SOUND_TIMES.put(entityId, gameTime);
return true;
}
return false;
}
private static double clamp(double value, double min, double max) {
return Math.max(min, Math.min(max, value));
}
private record StuckContact(
String tapeKey,
String dimensionId,
long blockPos,
double offsetX,
double offsetY,
double offsetZ
) {
}
private record TapeHit(BlockPos pos, BlockState state) {
}
}
@@ -0,0 +1,37 @@
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.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.RotatedPillarBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
public class DuplicatorLogBlock extends RotatedPillarBlock {
public static final MapCodec<DuplicatorLogBlock> CODEC = Block.simpleCodec(DuplicatorLogBlock::new);
public DuplicatorLogBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public MapCodec<DuplicatorLogBlock> codec() {
return CODEC;
}
@Override
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
DuplicatorTreeLogic.tryDuplicate(level, pos, random);
}
@Override
protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
if (level instanceof ServerLevel serverLevel && !state.is(newState.getBlock())) {
DuplicatorTreeLogic.invalidateCacheNear(serverLevel, pos);
}
super.onRemove(state, level, pos, newState, movedByPiston);
}
}
@@ -0,0 +1,176 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.RandomSource;
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.LeavesBlock;
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.IntegerProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class DuplicatorSaplingBlock extends BushBlock implements BonemealableBlock {
public static final MapCodec<DuplicatorSaplingBlock> CODEC = Block.simpleCodec(DuplicatorSaplingBlock::new);
public static final IntegerProperty STAGE = BlockStateProperties.STAGE;
private static final VoxelShape SHAPE = Block.box(2.0D, 0.0D, 2.0D, 14.0D, 14.0D, 14.0D);
public DuplicatorSaplingBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(STAGE, 0));
}
@Override
public MapCodec<DuplicatorSaplingBlock> codec() {
return CODEC;
}
@Override
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
@Override
protected boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos) {
return state.is(BlockTags.DIRT) || state.is(Blocks.FARMLAND);
}
@Override
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!AntarchySettings.duplicatorTreeEnabled()) {
return;
}
if (level.getMaxLocalRawBrightness(pos.above()) >= 9 && random.nextInt(7) == 0) {
this.advanceTree(level, pos, state, random);
}
}
@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 random.nextFloat() < 0.75F;
}
@Override
public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) {
if (!AntarchySettings.duplicatorTreeEnabled()) {
return;
}
this.advanceTree(level, pos, state, random);
}
private void advanceTree(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) {
if (state.getValue(STAGE) == 0) {
level.setBlock(pos, state.setValue(STAGE, 1), Block.UPDATE_ALL);
return;
}
this.growTree(level, pos);
}
private void growTree(ServerLevel level, BlockPos pos) {
if (!this.canGenerate(level, pos)) {
return;
}
BlockState logState = AntarchyObjects.DUPLICATOR_LOG.get().defaultBlockState();
BlockState leafState = Blocks.OAK_LEAVES.defaultBlockState()
.setValue(LeavesBlock.PERSISTENT, true)
.setValue(LeavesBlock.DISTANCE, 1);
level.setBlock(pos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL);
for (int y = 0; y < 4; y++) {
level.setBlock(pos.above(y), logState, Block.UPDATE_ALL);
}
BlockPos canopyBase = pos.above(3);
for (int x = -2; x <= 2; x++) {
for (int z = -2; z <= 2; z++) {
if (Math.abs(x) == 2 && Math.abs(z) == 2) {
continue;
}
this.placeLeaves(level, canopyBase.offset(x, 0, z), leafState);
this.placeLeaves(level, canopyBase.offset(x, 1, z), leafState);
}
}
this.placeLeaves(level, canopyBase.above(2), leafState);
this.placeLeaves(level, canopyBase.above(1).north(), leafState);
this.placeLeaves(level, canopyBase.above(1).south(), leafState);
this.placeLeaves(level, canopyBase.above(1).east(), leafState);
this.placeLeaves(level, canopyBase.above(1).west(), leafState);
}
private void placeLeaves(ServerLevel level, BlockPos pos, BlockState leafState) {
BlockState existingState = level.getBlockState(pos);
if (existingState.isAir() || existingState.canBeReplaced()) {
level.setBlock(pos, leafState, Block.UPDATE_ALL);
}
}
private boolean canGenerate(ServerLevel level, BlockPos pos) {
for (int y = 0; y <= 6; y++) {
int radius = y >= 3 ? 2 : 1;
for (int x = -radius; x <= radius; x++) {
for (int z = -radius; z <= radius; z++) {
BlockPos checkPos = pos.offset(x, y, z);
BlockState checkState = level.getBlockState(checkPos);
if (!this.canReplaceForTree(pos, checkPos, checkState)) {
return false;
}
}
}
}
return level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
}
private boolean canReplaceForTree(BlockPos saplingPos, BlockPos checkPos, BlockState checkState) {
if (checkPos.equals(saplingPos) && checkState.is(this)) {
return true;
}
return checkState.isAir() || checkState.canBeReplaced();
}
@Override
protected BlockState updateShape(
BlockState state,
Direction direction,
BlockState neighborState,
LevelAccessor level,
BlockPos pos,
BlockPos neighborPos
) {
return state.canSurvive(level, pos) ? super.updateShape(state, direction, neighborState, level, pos, neighborPos) : Blocks.AIR.defaultBlockState();
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(STAGE);
}
}
@@ -0,0 +1,233 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.AntarchyTags;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.WeakHashMap;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.state.BlockState;
public final class DuplicatorTreeLogic {
private static final int SOURCE_RADIUS = 1;
private static final int LOG_SEARCH_RADIUS = 2;
private static final int LOG_SEARCH_BELOW = 5;
private static final int LOG_SEARCH_ABOVE = 1;
// Cache center log pos per chunk. WeakHashMap lets levels be GC'd when unloaded.
private static final WeakHashMap<ServerLevel, HashMap<Long, BlockPos>> CENTER_LOG_CACHE = new WeakHashMap<>();
private DuplicatorTreeLogic() {
}
public static void invalidateCacheNear(ServerLevel level, BlockPos pos) {
HashMap<Long, BlockPos> map = CENTER_LOG_CACHE.get(level);
if (map != null) {
map.remove(ChunkPos.asLong(pos));
}
}
public static void tryDuplicate(ServerLevel level, BlockPos origin, RandomSource random) {
if (!AntarchySettings.duplicatorTreeEnabled()) {
return;
}
if (random.nextInt(10) != 0) {
return;
}
BlockPos centerLogPos = findCenterLog(level, origin);
if (centerLogPos == null) {
return;
}
List<BlockPos> sourceCandidates = collectSourceCandidates(level, centerLogPos);
if (sourceCandidates.isEmpty()) {
return;
}
List<BlockPos> targetCandidates = collectTargetCandidates(level, centerLogPos);
if (targetCandidates.isEmpty()) {
return;
}
BlockPos sourcePos = sourceCandidates.get(random.nextInt(sourceCandidates.size()));
BlockState sourceState = level.getBlockState(sourcePos);
BlockPos targetPos = targetCandidates.get(random.nextInt(targetCandidates.size()));
BlockState placedState = Block.updateFromNeighbourShapes(sourceState, level, targetPos);
if (!placedState.canSurvive(level, targetPos)) {
return;
}
level.setBlock(targetPos, placedState, Block.UPDATE_ALL);
level.levelEvent(2001, targetPos, Block.getId(sourceState));
playDuplicateEffects(level, centerLogPos, sourcePos, targetPos);
}
private static boolean isValidSource(ServerLevel level, BlockPos pos, BlockState state) {
if (state.isAir() || state.is(AntarchyTags.Blocks.DUPLICATOR_TREE_BLACKLIST) || AntarchyObjects.isDuplicatorTreeBlock(state)) {
return false;
}
if (state.getBlock() instanceof EntityBlock || !state.getFluidState().isEmpty()) {
return false;
}
if (state.is(AntarchyObjects.DUCT_TAPE.get())) {
return true;
}
return state.isCollisionShapeFullBlock(level, pos);
}
private static boolean isValidTarget(ServerLevel level, BlockPos pos) {
BlockState targetState = level.getBlockState(pos);
if (!targetState.isAir() && !targetState.canBeReplaced()) {
return false;
}
return level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
}
private static List<BlockPos> collectSourceCandidates(ServerLevel level, BlockPos centerLogPos) {
List<BlockPos> positions = new ArrayList<>();
for (int x = -SOURCE_RADIUS; x <= SOURCE_RADIUS; x++) {
for (int z = -SOURCE_RADIUS; z <= SOURCE_RADIUS; z++) {
if (x == 0 && z == 0) {
continue;
}
BlockPos checkPos = centerLogPos.offset(x, 0, z);
BlockState checkState = level.getBlockState(checkPos);
if (isValidSource(level, checkPos, checkState)) {
positions.add(checkPos);
}
}
}
return positions;
}
private static List<BlockPos> collectTargetCandidates(ServerLevel level, BlockPos centerLogPos) {
List<BlockPos> positions = new ArrayList<>();
for (int x = -SOURCE_RADIUS; x <= SOURCE_RADIUS; x++) {
for (int z = -SOURCE_RADIUS; z <= SOURCE_RADIUS; z++) {
if (x == 0 && z == 0) {
continue;
}
BlockPos checkPos = centerLogPos.offset(x, 0, z);
if (isValidTarget(level, checkPos)) {
positions.add(checkPos);
}
}
}
return positions;
}
private static BlockPos findCenterLog(ServerLevel level, BlockPos origin) {
if (level.getBlockState(origin).is(AntarchyObjects.DUPLICATOR_LOG.get())) {
return descendToBaseLog(level, origin);
}
long chunkKey = ChunkPos.asLong(origin);
HashMap<Long, BlockPos> cache = CENTER_LOG_CACHE.computeIfAbsent(level, k -> new HashMap<>());
BlockPos cached = cache.get(chunkKey);
if (cached != null) {
if (level.getBlockState(cached).is(AntarchyObjects.DUPLICATOR_LOG.get())) {
return cached;
}
cache.remove(chunkKey);
}
BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos();
BlockPos bestPos = null;
int bestDistance = Integer.MAX_VALUE;
for (int y = -LOG_SEARCH_BELOW; y <= LOG_SEARCH_ABOVE; y++) {
for (int x = -LOG_SEARCH_RADIUS; x <= LOG_SEARCH_RADIUS; x++) {
for (int z = -LOG_SEARCH_RADIUS; z <= LOG_SEARCH_RADIUS; z++) {
cursor.setWithOffset(origin, x, y, z);
if (!level.getBlockState(cursor).is(AntarchyObjects.DUPLICATOR_LOG.get())) {
continue;
}
int distance = Math.abs(x) + Math.abs(y) + Math.abs(z);
if (distance < bestDistance) {
bestDistance = distance;
bestPos = cursor.immutable();
}
}
}
}
BlockPos result = bestPos == null ? null : descendToBaseLog(level, bestPos);
if (result != null) {
cache.put(chunkKey, result);
}
return result;
}
private static BlockPos descendToBaseLog(ServerLevel level, BlockPos pos) {
BlockPos.MutableBlockPos cursor = pos.mutable();
while (level.getBlockState(cursor.below()).is(AntarchyObjects.DUPLICATOR_LOG.get())) {
cursor.move(Direction.DOWN);
}
return cursor.immutable();
}
private static void playDuplicateEffects(ServerLevel level, BlockPos centerLogPos, BlockPos sourcePos, BlockPos targetPos) {
level.sendParticles(
ParticleTypes.HAPPY_VILLAGER,
centerLogPos.getX() + 0.5D,
centerLogPos.getY() + 0.9D,
centerLogPos.getZ() + 0.5D,
4,
0.35D,
0.35D,
0.35D,
0.02D
);
level.sendParticles(
ParticleTypes.ENCHANT,
sourcePos.getX() + 0.5D,
sourcePos.getY() + 0.5D,
sourcePos.getZ() + 0.5D,
5,
0.15D,
0.15D,
0.15D,
0.04D
);
level.sendParticles(
ParticleTypes.WAX_ON,
targetPos.getX() + 0.5D,
targetPos.getY() + 0.5D,
targetPos.getZ() + 0.5D,
6,
0.25D,
0.25D,
0.25D,
0.01D
);
level.playSound(null, centerLogPos, SoundEvents.AMETHYST_BLOCK_CHIME, SoundSource.BLOCKS, 0.7F, 1.25F);
level.playSound(null, targetPos, SoundEvents.ALLAY_ITEM_TAKEN, SoundSource.BLOCKS, 0.55F, 0.9F + level.random.nextFloat() * 0.2F);
}
}
@@ -0,0 +1,122 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.block.entity.HushweedBlockEntity;
import com.mojang.serialization.MapCodec;
import java.util.function.Supplier;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.BaseEntityBlock;
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.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jetbrains.annotations.Nullable;
public class HushweedBlock extends BaseEntityBlock {
public static final DirectionProperty FACING = BlockStateProperties.VERTICAL_DIRECTION;
public static final MapCodec<HushweedBlock> CODEC = Block.simpleCodec(HushweedBlock::new);
public HushweedBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.UP));
}
@Override
public MapCodec<HushweedBlock> codec() {
return CODEC;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
Direction facing = context.getClickedFace() == Direction.DOWN ? Direction.DOWN : Direction.UP;
BlockState placed = this.defaultBlockState().setValue(FACING, facing);
if (placed.canSurvive(context.getLevel(), context.getClickedPos())) {
return placed;
}
BlockState fallback = this.defaultBlockState().setValue(FACING, facing.getOpposite());
return fallback.canSurvive(context.getLevel(), context.getClickedPos()) ? fallback : null;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FACING);
}
@Override
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return Blocks.AZALEA.defaultBlockState().getShape(level, pos, context);
}
@Override
protected VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return Blocks.AZALEA.defaultBlockState().getCollisionShape(level, pos, context);
}
@Override
protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
Direction facing = state.getValue(FACING);
BlockPos supportPos = facing == Direction.UP ? pos.below() : pos.above();
Direction supportFace = facing == Direction.UP ? Direction.UP : Direction.DOWN;
return level.getBlockState(supportPos).isFaceSturdy(level, supportPos, supportFace);
}
@Override
protected BlockState updateShape(
BlockState state,
Direction direction,
BlockState neighborState,
net.minecraft.world.level.LevelAccessor level,
BlockPos pos,
BlockPos neighborPos
) {
return state.canSurvive(level, pos) ? super.updateShape(state, direction, neighborState, level, pos, neighborPos) : Blocks.AIR.defaultBlockState();
}
@Override
protected RenderShape getRenderShape(BlockState state) {
return RenderShape.MODEL;
}
@Override
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
if (!level.isClientSide && entity instanceof LivingEntity livingEntity && !livingEntity.isSteppingCarefully()) {
livingEntity.hurt(level.damageSources().sweetBerryBush(), 1.0F);
}
super.entityInside(state, level, pos, entity);
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new HushweedBlockEntity(pos, state);
}
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
Supplier<BlockEntityType<HushweedBlockEntity>> typeSupplier = AntarchyObjects.HUSHWEED_BLOCK_ENTITY;
return level.isClientSide
? null
: createTickerHelper(blockEntityType, typeSupplier.get(),
(tickLevel, tickPos, tickState, blockEntity) -> {
if (tickLevel instanceof net.minecraft.server.level.ServerLevel serverLevel) {
HushweedBlockEntity.serverTick(serverLevel, tickPos, tickState, blockEntity);
}
});
}
}
@@ -0,0 +1,106 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.entity.MolewormEntity;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;
public class InfestedCoarseDirtBlock extends Block {
private final MapCodec<InfestedCoarseDirtBlock> codec;
public InfestedCoarseDirtBlock(BlockBehaviour.Properties properties) {
super(properties);
this.codec = Block.simpleCodec(ignored -> this);
}
@Override
public MapCodec<InfestedCoarseDirtBlock> codec() {
return this.codec;
}
@Override
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (random.nextFloat() < 0.35F) {
this.tryReleaseMoleworm(level, pos);
}
}
@Override
public void stepOn(Level level, BlockPos pos, BlockState state, net.minecraft.world.entity.Entity entity) {
super.stepOn(level, pos, state, entity);
if (!level.isClientSide && entity instanceof Player && level.random.nextFloat() < 0.22F) {
this.tryReleaseMoleworm((ServerLevel) level, pos);
}
}
private void tryReleaseMoleworm(ServerLevel level, BlockPos pos) {
Player nearbyPlayer = level.getNearestPlayer(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, 4.5D, false);
if (nearbyPlayer == null) {
return;
}
BlockPos emergencePos = findEmergencePos(level, pos);
if (emergencePos == null) {
return;
}
if (!(AntarchyObjects.MOLEWORM.get().create(level) instanceof MolewormEntity moleworm)) {
return;
}
moleworm.moveTo(emergencePos.getX() + 0.5D, emergencePos.getY() + 0.05D, emergencePos.getZ() + 0.5D, level.random.nextFloat() * 360.0F, 0.0F);
if (!level.noCollision(moleworm)) {
moleworm.discard();
return;
}
level.setBlock(pos, Blocks.COARSE_DIRT.defaultBlockState(), 3);
level.addFreshEntity(moleworm);
level.playSound(null, emergencePos, SoundEvents.SILVERFISH_STEP, net.minecraft.sounds.SoundSource.BLOCKS, 0.45F, 0.8F + level.random.nextFloat() * 0.25F);
level.sendParticles(net.minecraft.core.particles.ParticleTypes.POOF, pos.getX() + 0.5D, pos.getY() + 0.45D, pos.getZ() + 0.5D, 8, 0.18D, 0.08D, 0.18D, 0.01D);
}
@Nullable
private static BlockPos findEmergencePos(BlockGetter level, BlockPos origin) {
BlockPos[] candidates = new BlockPos[] {
origin.above(),
origin.north(),
origin.south(),
origin.east(),
origin.west(),
origin.north().above(),
origin.south().above(),
origin.east().above(),
origin.west().above()
};
for (BlockPos candidate : candidates) {
if (isOpenStandingSpot(level, candidate)) {
return candidate;
}
}
return null;
}
private static boolean isOpenStandingSpot(BlockGetter level, BlockPos pos) {
BlockState state = level.getBlockState(pos);
BlockState above = level.getBlockState(pos.above());
BlockState below = level.getBlockState(pos.below());
return state.isAir()
&& above.isAir()
&& below.isFaceSturdy(level, pos.below(), Direction.UP);
}
}
@@ -0,0 +1,105 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.entity.MolewormEntity;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;
public class InfestedRootedDirtBlock extends Block {
private final MapCodec<InfestedRootedDirtBlock> codec;
public InfestedRootedDirtBlock(BlockBehaviour.Properties properties) {
super(properties);
this.codec = Block.simpleCodec(ignored -> this);
}
@Override
public MapCodec<InfestedRootedDirtBlock> codec() {
return this.codec;
}
@Override
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (random.nextFloat() < 0.35F) {
this.tryReleaseMoleworm(level, pos);
}
}
@Override
public void stepOn(Level level, BlockPos pos, BlockState state, net.minecraft.world.entity.Entity entity) {
super.stepOn(level, pos, state, entity);
if (!level.isClientSide && entity instanceof Player && level.random.nextFloat() < 0.22F) {
this.tryReleaseMoleworm((ServerLevel) level, pos);
}
}
private void tryReleaseMoleworm(ServerLevel level, BlockPos pos) {
Player nearbyPlayer = level.getNearestPlayer(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, 4.5D, false);
if (nearbyPlayer == null) {
return;
}
BlockPos emergencePos = findEmergencePos(level, pos);
if (emergencePos == null) {
return;
}
if (!(AntarchyObjects.MOLEWORM.get().create(level) instanceof MolewormEntity moleworm)) {
return;
}
moleworm.moveTo(emergencePos.getX() + 0.5D, emergencePos.getY() + 0.05D, emergencePos.getZ() + 0.5D, level.random.nextFloat() * 360.0F, 0.0F);
if (!level.noCollision(moleworm)) {
moleworm.discard();
return;
}
level.setBlock(pos, net.minecraft.world.level.block.Blocks.ROOTED_DIRT.defaultBlockState(), 3);
level.addFreshEntity(moleworm);
level.playSound(null, emergencePos, SoundEvents.SILVERFISH_STEP, net.minecraft.sounds.SoundSource.BLOCKS, 0.45F, 0.8F + level.random.nextFloat() * 0.25F);
level.sendParticles(net.minecraft.core.particles.ParticleTypes.POOF, pos.getX() + 0.5D, pos.getY() + 0.45D, pos.getZ() + 0.5D, 8, 0.18D, 0.08D, 0.18D, 0.01D);
}
@Nullable
private static BlockPos findEmergencePos(BlockGetter level, BlockPos origin) {
BlockPos[] candidates = new BlockPos[] {
origin.above(),
origin.north(),
origin.south(),
origin.east(),
origin.west(),
origin.north().above(),
origin.south().above(),
origin.east().above(),
origin.west().above()
};
for (BlockPos candidate : candidates) {
if (isOpenStandingSpot(level, candidate)) {
return candidate;
}
}
return null;
}
private static boolean isOpenStandingSpot(BlockGetter level, BlockPos pos) {
BlockState state = level.getBlockState(pos);
BlockState above = level.getBlockState(pos.above());
BlockState below = level.getBlockState(pos.below());
return state.isAir()
&& above.isAir()
&& below.isFaceSturdy(level, pos.below(), Direction.UP);
}
}
@@ -0,0 +1,74 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.ItemInteractionResult;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.player.Player;
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.BonemealableBlock;
import net.minecraft.world.level.block.DoublePlantBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.phys.BlockHitResult;
public class MilkweedBlock extends DoublePlantBlock implements BonemealableBlock {
public static final MapCodec<MilkweedBlock> CODEC = Block.simpleCodec(MilkweedBlock::new);
public MilkweedBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any()
.setValue(BlockStateProperties.DOUBLE_BLOCK_HALF, DoubleBlockHalf.LOWER));
}
@Override
public MapCodec<MilkweedBlock> codec() {
return CODEC;
}
@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 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) {
}
@Override
protected boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
return false;
}
}
@@ -0,0 +1,168 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.item.FallingBlockEntity;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.PointedDripstoneBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.DripstoneThickness;
import net.minecraft.world.level.material.Fluids;
public class NyxiteSpikeBlock extends PointedDripstoneBlock {
@SuppressWarnings("rawtypes")
public static final MapCodec<PointedDripstoneBlock> CODEC = (MapCodec) Block.simpleCodec(NyxiteSpikeBlock::new);
public NyxiteSpikeBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public MapCodec<PointedDripstoneBlock> codec() {
return CODEC;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
LevelAccessor level = context.getLevel();
BlockPos pos = context.getClickedPos();
Direction direction = calculateTipDirection(level, pos, context.getNearestLookingVerticalDirection().getOpposite());
if (direction == null) {
return null;
}
boolean mergeTips = !context.isSecondaryUseActive();
DripstoneThickness thickness = calculateDripstoneThickness(level, pos, direction, mergeTips);
if (thickness == null) {
return null;
}
return this.defaultBlockState()
.setValue(TIP_DIRECTION, direction)
.setValue(THICKNESS, thickness)
.setValue(WATERLOGGED, level.getFluidState(pos).getType() == Fluids.WATER);
}
@Override
protected BlockState updateShape(
BlockState state,
Direction direction,
BlockState neighborState,
LevelAccessor level,
BlockPos pos,
BlockPos neighborPos
) {
if (state.getValue(WATERLOGGED)) {
level.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(level));
}
if (direction != Direction.UP && direction != Direction.DOWN) {
return state;
}
Direction tipDirection = state.getValue(TIP_DIRECTION);
if (tipDirection == Direction.DOWN && level.getBlockTicks().hasScheduledTick(pos, this)) {
return state;
}
if (direction == tipDirection.getOpposite() && !this.canSurvive(state, level, pos)) {
if (tipDirection == Direction.DOWN) {
level.scheduleTick(pos, this, 2);
} else {
level.scheduleTick(pos, this, 1);
}
return state;
}
boolean mergeTips = state.getValue(THICKNESS) == DripstoneThickness.TIP_MERGE;
return state.setValue(THICKNESS, calculateDripstoneThickness(level, pos, tipDirection, mergeTips));
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return isValidPointedDripstonePlacement(level, pos, state.getValue(TIP_DIRECTION));
}
@Override
protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (this.canSurvive(state, level, pos)) {
return;
}
if (state.getValue(TIP_DIRECTION) == Direction.DOWN) {
BlockPos.MutableBlockPos root = pos.mutable();
while (isNyxiteSpikeWithDirection(level.getBlockState(root.above()), Direction.DOWN)) {
root.move(Direction.UP);
}
BlockPos.MutableBlockPos cursor = root.mutable();
while (isNyxiteSpikeWithDirection(level.getBlockState(cursor), Direction.DOWN)) {
BlockState fallingState = level.getBlockState(cursor);
if (isNyxiteSpikeWithDirection(fallingState, Direction.DOWN)) {
FallingBlockEntity.fall(level, cursor, fallingState);
}
cursor.move(Direction.DOWN);
}
return;
}
BlockPos.MutableBlockPos cursor = pos.mutable();
while (isNyxiteSpikeWithDirection(level.getBlockState(cursor), Direction.UP)) {
BlockState spikeState = level.getBlockState(cursor);
dropResources(spikeState, level, cursor);
level.removeBlock(cursor, false);
cursor.move(Direction.UP);
}
}
private static Direction calculateTipDirection(LevelReader level, BlockPos pos, Direction preferredDirection) {
if (isValidPointedDripstonePlacement(level, pos, preferredDirection)) {
return preferredDirection;
}
Direction opposite = preferredDirection.getOpposite();
return isValidPointedDripstonePlacement(level, pos, opposite) ? opposite : null;
}
private static DripstoneThickness calculateDripstoneThickness(LevelReader level, BlockPos pos, Direction direction, boolean mergeTips) {
Direction opposite = direction.getOpposite();
BlockState forwardState = level.getBlockState(pos.relative(direction));
if (isNyxiteSpikeWithDirection(forwardState, opposite)) {
return !mergeTips && forwardState.getValue(THICKNESS) != DripstoneThickness.TIP_MERGE
? DripstoneThickness.TIP
: DripstoneThickness.TIP_MERGE;
}
if (!isNyxiteSpikeWithDirection(forwardState, direction)) {
return DripstoneThickness.TIP;
}
DripstoneThickness forwardThickness = forwardState.getValue(THICKNESS);
if (forwardThickness != DripstoneThickness.TIP && forwardThickness != DripstoneThickness.TIP_MERGE) {
BlockState backState = level.getBlockState(pos.relative(opposite));
return !isNyxiteSpikeWithDirection(backState, direction) ? DripstoneThickness.BASE : DripstoneThickness.MIDDLE;
}
return DripstoneThickness.FRUSTUM;
}
private static boolean isValidPointedDripstonePlacement(LevelReader level, BlockPos pos, Direction direction) {
BlockPos supportPos = pos.relative(direction.getOpposite());
BlockState supportState = level.getBlockState(supportPos);
return supportState.isFaceSturdy(level, supportPos, direction) || isNyxiteSpikeWithDirection(supportState, direction);
}
private static boolean isNyxiteSpikeWithDirection(BlockState state, Direction direction) {
return state.is(AntarchyObjects.NYXITE_SPIKE.get()) && state.getValue(TIP_DIRECTION) == direction;
}
}
@@ -0,0 +1,205 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.worldgen.elythia.OuranwoodTreeGrowers;
import com.mojang.serialization.MapCodec;
import java.util.LinkedHashMap;
import java.util.Map;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.RandomSource;
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.BooleanProperty;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class OuranwoodAcornBlock extends BushBlock implements BonemealableBlock {
public static final MapCodec<OuranwoodAcornBlock> CODEC = Block.simpleCodec(OuranwoodAcornBlock::new);
public static final int MAX_STAGE = 2;
public static final BooleanProperty HANGING = BlockStateProperties.HANGING;
public static final IntegerProperty STAGE = IntegerProperty.create("stage", 0, MAX_STAGE);
private static final VoxelShape[] SAPLING_SHAPES = new VoxelShape[] {
Block.box(5.5D, 0.0D, 5.5D, 10.5D, 4.0D, 10.5D),
Block.box(3.5D, 0.0D, 3.5D, 12.5D, 8.0D, 12.5D),
Block.box(2.0D, 0.0D, 2.0D, 14.0D, 12.0D, 14.0D)
};
private static final VoxelShape HANGING_SHAPE = Block.box(4.0D, 2.0D, 4.0D, 12.0D, 16.0D, 12.0D);
public OuranwoodAcornBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(HANGING, false).setValue(STAGE, 0));
}
@Override
public MapCodec<OuranwoodAcornBlock> codec() {
return CODEC;
}
@Override
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
int stage = state.getValue(STAGE);
return state.getValue(HANGING) ? HANGING_SHAPE : SAPLING_SHAPES[stage];
}
@Override
protected boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos) {
return state.is(BlockTags.DIRT) || state.is(Blocks.FARMLAND);
}
@Override
protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
if (state.getValue(HANGING)) {
return level.getBlockState(pos.above()).is(BlockTags.LEAVES);
}
return super.canSurvive(state, level, pos);
}
@Override
protected BlockState updateShape(
BlockState state,
Direction direction,
BlockState neighborState,
LevelAccessor level,
BlockPos pos,
BlockPos neighborPos
) {
return state.canSurvive(level, pos) ? super.updateShape(state, direction, neighborState, level, pos, neighborPos) : Blocks.AIR.defaultBlockState();
}
@Override
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (state.getValue(HANGING)) {
return;
}
if (level.getMaxLocalRawBrightness(pos.above()) >= 9 && random.nextInt(7) == 0) {
this.advanceGrowth(level, pos, state, random);
}
}
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state) {
return !state.getValue(HANGING);
}
@Override
public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, BlockState state) {
return !state.getValue(HANGING) && random.nextFloat() < 0.75F;
}
@Override
public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) {
if (state.getValue(HANGING)) {
return;
}
this.advanceGrowth(level, pos, state, random);
}
private void advanceGrowth(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) {
if (state.getValue(STAGE) < MAX_STAGE) {
level.setBlock(pos, state.setValue(STAGE, state.getValue(STAGE) + 1), Block.UPDATE_ALL);
return;
}
this.growConfiguredTree(level, pos, state, random);
}
private void growConfiguredTree(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) {
Footprint largeFootprint = this.findFootprint(level, pos, 3);
if (largeFootprint != null) {
if (largeFootprint.fullyMatured()) {
this.placeConfiguredTree(level, largeFootprint, OuranwoodTreeGrowers.OURANWOOD_LARGE_TREE, random);
}
return;
}
Footprint mediumFootprint = this.findFootprint(level, pos, 2);
if (mediumFootprint != null) {
if (mediumFootprint.fullyMatured()) {
this.placeConfiguredTree(level, mediumFootprint, OuranwoodTreeGrowers.OURANWOOD_MEDIUM_TREE, random);
}
return;
}
this.placeConfiguredTree(level, new Footprint(pos, Map.of(pos, state)), OuranwoodTreeGrowers.OURANWOOD_YOUNG_TREE, random);
}
private Footprint findFootprint(ServerLevel level, BlockPos pos, int size) {
for (int offsetX = 0; offsetX < size; offsetX++) {
for (int offsetZ = 0; offsetZ < size; offsetZ++) {
BlockPos origin = pos.offset(-offsetX, 0, -offsetZ);
Map<BlockPos, BlockState> blocks = new LinkedHashMap<>();
boolean matches = true;
boolean fullyMatured = true;
for (int x = 0; x < size && matches; x++) {
for (int z = 0; z < size; z++) {
BlockPos checkPos = origin.offset(x, 0, z);
BlockState checkState = level.getBlockState(checkPos);
if (!checkState.is(this) || checkState.getValue(HANGING)) {
matches = false;
break;
}
fullyMatured &= checkState.getValue(STAGE) >= MAX_STAGE;
blocks.put(checkPos, checkState);
}
}
if (matches) {
return new Footprint(origin, blocks, fullyMatured);
}
}
}
return null;
}
private void placeConfiguredTree(ServerLevel level, Footprint footprint, ResourceKey<ConfiguredFeature<?, ?>> featureKey, RandomSource random) {
Holder.Reference<ConfiguredFeature<?, ?>> feature = level.registryAccess()
.lookupOrThrow(Registries.CONFIGURED_FEATURE)
.getOrThrow(featureKey);
for (BlockPos saplingPos : footprint.blocks().keySet()) {
level.removeBlock(saplingPos, false);
}
if (feature.value().place(level, level.getChunkSource().getGenerator(), random, footprint.origin())) {
return;
}
for (Map.Entry<BlockPos, BlockState> entry : footprint.blocks().entrySet()) {
level.setBlock(entry.getKey(), entry.getValue(), Block.UPDATE_ALL);
}
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(HANGING, STAGE);
}
private record Footprint(BlockPos origin, Map<BlockPos, BlockState> blocks, boolean fullyMatured) {
private Footprint(BlockPos origin, Map<BlockPos, BlockState> blocks) {
this(origin, blocks, true);
}
}
}
@@ -0,0 +1,195 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.RandomSource;
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.BonemealableBlock;
import net.minecraft.world.level.block.LeavesBlock;
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.level.block.state.properties.IntegerProperty;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
public class OuranwoodLeavesBlock extends LeavesBlock implements BonemealableBlock {
public static final MapCodec<OuranwoodLeavesBlock> CODEC = Block.simpleCodec(OuranwoodLeavesBlock::new);
/*
* We still include vanilla LeavesBlock.DISTANCE in the state definition because
* LeavesBlock's constructor sets it.
*
* This is the real Ouranwood decay distance.
*/
public static final IntegerProperty OURANWOOD_DISTANCE = IntegerProperty.create("ouranwood_distance", 1, 17);
public static final BooleanProperty PERSISTENT = LeavesBlock.PERSISTENT;
public static final BooleanProperty WATERLOGGED = LeavesBlock.WATERLOGGED;
public static final int OURANWOOD_MAX_DISTANCE = 16;
public static final int OURANWOOD_DECAY_DISTANCE = OURANWOOD_MAX_DISTANCE + 1;
public OuranwoodLeavesBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any()
.setValue(LeavesBlock.DISTANCE, LeavesBlock.DECAY_DISTANCE)
.setValue(OURANWOOD_DISTANCE, OURANWOOD_DECAY_DISTANCE)
.setValue(PERSISTENT, false)
.setValue(WATERLOGGED, false));
}
@Override
public MapCodec<OuranwoodLeavesBlock> codec() {
return CODEC;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(LeavesBlock.DISTANCE, OURANWOOD_DISTANCE, PERSISTENT, WATERLOGGED);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
FluidState fluidState = context.getLevel().getFluidState(context.getClickedPos());
BlockState state = this.defaultBlockState()
.setValue(PERSISTENT, true)
.setValue(WATERLOGGED, fluidState.getType() == Fluids.WATER);
return recalculateDistance(state, context.getLevel(), context.getClickedPos());
}
@Override
protected boolean isRandomlyTicking(BlockState state) {
return decaying(state);
}
@Override
protected boolean decaying(BlockState state) {
return !state.getValue(PERSISTENT)
&& state.getValue(OURANWOOD_DISTANCE) > OURANWOOD_MAX_DISTANCE;
}
@Override
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (decaying(state)) {
dropResources(state, level, pos);
level.removeBlock(pos, false);
}
}
@Override
protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
level.setBlock(pos, recalculateDistance(state, level, pos), Block.UPDATE_ALL);
}
@Override
protected BlockState updateShape(
BlockState state,
Direction direction,
BlockState neighborState,
LevelAccessor level,
BlockPos pos,
BlockPos neighborPos
) {
if (state.getValue(WATERLOGGED)) {
level.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(level));
}
int neighborDistance = Math.min(OURANWOOD_DECAY_DISTANCE, getDistanceAt(neighborState) + 1);
int currentDistance = state.getValue(OURANWOOD_DISTANCE);
if (neighborDistance != 1 || currentDistance != neighborDistance) {
level.scheduleTick(pos, this, 1);
}
return state;
}
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state) {
return this.canGrowHangingAcorn(level, pos);
}
@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) {
if (this.canGrowHangingAcorn(level, pos)) {
level.setBlock(pos.below(), createHangingAcornState(0), Block.UPDATE_ALL);
}
}
private boolean canGrowHangingAcorn(LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).isAir();
}
public static BlockState createHangingAcornState(int stage) {
return AntarchyObjects.OURANWOOD_ACORN_BLOCK.get().defaultBlockState()
.setValue(OuranwoodAcornBlock.HANGING, true)
.setValue(OuranwoodAcornBlock.STAGE, stage);
}
private static BlockState recalculateDistance(BlockState state, LevelReader level, BlockPos pos) {
int bestDistance = OURANWOOD_DECAY_DISTANCE;
BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos();
for (Direction direction : Direction.values()) {
cursor.setWithOffset(pos, direction);
bestDistance = Math.min(bestDistance, getDistanceAt(level.getBlockState(cursor)) + 1);
if (bestDistance == 1) {
break;
}
}
bestDistance = Math.min(OURANWOOD_DECAY_DISTANCE, bestDistance);
return setOuranwoodDistance(state, bestDistance);
}
private static BlockState setOuranwoodDistance(BlockState state, int distance) {
int ouranwoodDistance = Math.max(1, Math.min(OURANWOOD_DECAY_DISTANCE, distance));
int vanillaDistance = Math.min(LeavesBlock.DECAY_DISTANCE, ouranwoodDistance);
return state
.setValue(OURANWOOD_DISTANCE, ouranwoodDistance)
.setValue(LeavesBlock.DISTANCE, vanillaDistance);
}
private static int getDistanceAt(BlockState state) {
if (state.is(BlockTags.LOGS)) {
return 0;
}
if (state.hasProperty(OURANWOOD_DISTANCE)) {
return state.getValue(OURANWOOD_DISTANCE);
}
if (state.hasProperty(LeavesBlock.DISTANCE)) {
return state.getValue(LeavesBlock.DISTANCE);
}
return OURANWOOD_DECAY_DISTANCE;
}
public static BlockState setOuranwoodDistanceForWorldgen(BlockState state, int distance) {
int ouranwoodDistance = Math.max(1, Math.min(OURANWOOD_DECAY_DISTANCE, distance));
int vanillaDistance = Math.min(LeavesBlock.DECAY_DISTANCE, ouranwoodDistance);
return state
.setValue(OURANWOOD_DISTANCE, ouranwoodDistance)
.setValue(LeavesBlock.DISTANCE, vanillaDistance);
}
}
@@ -0,0 +1,24 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import java.util.function.Supplier;
import net.minecraft.world.level.block.RotatedPillarBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.Block;
public class OuranwoodLogBlock extends RotatedPillarBlock {
public static final MapCodec<OuranwoodLogBlock> CODEC = Block.simpleCodec(OuranwoodLogBlock::new);
public OuranwoodLogBlock(BlockBehaviour.Properties properties) {
super(properties);
}
public OuranwoodLogBlock(Supplier<Block> strippedBlock, BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public MapCodec<OuranwoodLogBlock> codec() {
return CODEC;
}
}
@@ -0,0 +1,73 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.entity.flying_squirrel.FlyingSquirrelEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.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.IntegerProperty;
/**
* Invisible world-gen-only marker placed inside a flying squirrel hollow.
* Schedules itself to replace with COARSE_DIRT and spawn squirrels shortly
* after the chunk loads, so entity creation never blocks the gen thread.
* No BlockItem is registered, so this block never appears in creative or JEI.
*/
public class OuranwoodSquirrelNestBlock extends Block {
public static final IntegerProperty SQUIRREL_COUNT = IntegerProperty.create("squirrels", 1, 3);
public OuranwoodSquirrelNestBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(SQUIRREL_COUNT, 1));
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(SQUIRREL_COUNT);
}
@Override
protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
int count = state.getValue(SQUIRREL_COUNT);
for (int i = 0; i < count; i++) {
BlockPos spawnPos = findSpawnPos(level, pos, random);
if (spawnPos == null) continue;
FlyingSquirrelEntity squirrel = AntarchyObjects.FLYING_SQUIRREL.get().create(level);
if (squirrel == null) continue;
squirrel.moveTo(
spawnPos.getX() + 0.2D + random.nextDouble() * 0.6D,
spawnPos.getY() + 0.05D,
spawnPos.getZ() + 0.2D + random.nextDouble() * 0.6D,
random.nextFloat() * 360.0F,
0.0F
);
level.addFreshEntity(squirrel);
}
level.setBlock(pos, Blocks.COARSE_DIRT.defaultBlockState(), Block.UPDATE_ALL);
}
private static BlockPos findSpawnPos(ServerLevel level, BlockPos nestPos, RandomSource random) {
if (level.isEmptyBlock(nestPos.above())) {
return nestPos.above();
}
for (int attempt = 0; attempt < 8; attempt++) {
BlockPos candidate = nestPos.offset(
random.nextInt(3) - 1,
random.nextInt(2),
random.nextInt(3) - 1
);
if (level.isEmptyBlock(candidate) && !level.getBlockState(candidate.below()).canBeReplaced()) {
return candidate;
}
}
return null;
}
}
@@ -0,0 +1,318 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.block.entity.PotentNyxiteBlockEntity;
import com.craisinlord.antarchy.content.block.state.PotentNyxiteState;
import com.craisinlord.antarchy.content.AntarchyTags;
import com.mojang.serialization.MapCodec;
import java.util.function.Supplier;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.SimpleParticleType;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.BaseEntityBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
public class PotentNyxiteBlock extends BaseEntityBlock {
private static final ResourceLocation ANTIWATER_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "antiwater");
private static final ResourceLocation FLOWING_ANTIWATER_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "flowing_antiwater");
private static final ResourceLocation ICHOR_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "ichor");
private static final ResourceLocation FLOWING_ICHOR_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "flowing_ichor");
private static final ResourceLocation HYPNOTIC_GAS_SOUND_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "potent_nyxite_hypnotic_gas");
private static final ResourceLocation HYPNOTIC_GAS_CLOUD_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "hypnotic_gas_cloud");
private static final ResourceLocation HYPNOTIC_GAS_CLOUD_DOWN_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "hypnotic_gas_cloud_down");
public static final EnumProperty<PotentNyxiteState> STATE = EnumProperty.create("state", PotentNyxiteState.class);
private final Supplier<? extends BlockEntityType<PotentNyxiteBlockEntity>> blockEntityTypeSupplier;
private final MapCodec<PotentNyxiteBlock> codec;
public PotentNyxiteBlock(
Supplier<? extends BlockEntityType<PotentNyxiteBlockEntity>> blockEntityTypeSupplier,
BlockBehaviour.Properties properties
) {
super(properties);
this.blockEntityTypeSupplier = blockEntityTypeSupplier;
this.codec = Block.simpleCodec(ignored -> this);
this.registerDefaultState(this.stateDefinition.any().setValue(STATE, PotentNyxiteState.DRY));
}
@Override
public MapCodec<PotentNyxiteBlock> codec() {
return this.codec;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(STATE);
}
@Override
protected RenderShape getRenderShape(BlockState state) {
return RenderShape.MODEL;
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new PotentNyxiteBlockEntity(pos, state, this.blockEntityTypeSupplier);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return this.defaultBlockState().setValue(STATE, resolveState(context.getLevel(), context.getClickedPos(), this.defaultBlockState()));
}
@Override
protected BlockState updateShape(
BlockState state,
Direction direction,
BlockState neighborState,
LevelAccessor level,
BlockPos pos,
BlockPos neighborPos
) {
return state.setValue(STATE, resolveState(level, pos, state));
}
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
return level.isClientSide
? createTickerHelper(blockEntityType, this.blockEntityTypeSupplier.get(), PotentNyxiteBlockEntity::clientTick)
: createTickerHelper(blockEntityType, this.blockEntityTypeSupplier.get(), (tickLevel, tickPos, tickState, blockEntity) -> {
if (tickLevel instanceof ServerLevel serverLevel) {
PotentNyxiteBlockEntity.serverTick(serverLevel, tickPos, tickState, blockEntity);
}
});
}
@Override
protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
super.onPlace(state, level, pos, oldState, movedByPiston);
PotentNyxiteBlockEntity.handleStateActivation(level, pos, state);
}
@Override
public boolean triggerEvent(BlockState state, Level level, BlockPos pos, int id, int param) {
BlockEntity blockEntity = level.getBlockEntity(pos);
if (blockEntity instanceof PotentNyxiteBlockEntity potentNyxiteBlockEntity) {
potentNyxiteBlockEntity.markEruptionStart(level.getGameTime());
}
return true;
}
@Override
public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) {
Direction fluidDirection = getFluidColumnDirection(level, pos);
if (state.getValue(STATE) == PotentNyxiteState.DRY || fluidDirection == null) {
return;
}
Direction eruptionDirection = fluidDirection.getOpposite();
BlockPos particlePos = pos.relative(eruptionDirection);
ResourceLocation particleId = eruptionDirection == Direction.DOWN ? HYPNOTIC_GAS_CLOUD_DOWN_ID : HYPNOTIC_GAS_CLOUD_ID;
spawnHypnoticGasParticlesAt(level, random, particlePos, particleId, eruptionDirection);
if (random.nextBoolean()) {
spawnHypnoticGasParticlesAt(level, random, particlePos, particleId, eruptionDirection);
}
if (random.nextInt(10) == 0) {
level.playLocalSound(
pos.getX() + 0.5D,
pos.getY() + 0.5D,
pos.getZ() + 0.5D,
BuiltInRegistries.SOUND_EVENT.get(HYPNOTIC_GAS_SOUND_ID),
SoundSource.AMBIENT,
1.75F,
1.0F,
false
);
}
}
public static PotentNyxiteState resolveState(LevelAccessor level, BlockPos pos, BlockState state) {
Direction fluidDirection = getFluidColumnDirection(level, pos);
if (fluidDirection == null) {
return hasHypnoticGasFluid(level, pos) ? PotentNyxiteState.WET : PotentNyxiteState.DRY;
}
if (hasContinuousTrigger(level, pos, fluidDirection)) {
return PotentNyxiteState.CONTINUOUS;
}
if (hasPeriodicTrigger(level, pos, fluidDirection)) {
return PotentNyxiteState.DORMANT;
}
return PotentNyxiteState.WET;
}
public static boolean hasPeriodicTrigger(LevelAccessor level, BlockPos pos) {
Direction fluidDirection = getFluidColumnDirection(level, pos);
return fluidDirection != null && hasPeriodicTrigger(level, pos, fluidDirection);
}
public static boolean hasHypnoticGasFluid(LevelAccessor level, BlockPos pos) {
return hasGasFluid(level, pos, Direction.UP) || hasGasFluid(level, pos, Direction.DOWN);
}
public static boolean hasContinuousTrigger(LevelAccessor level, BlockPos pos) {
Direction fluidDirection = getFluidColumnDirection(level, pos);
return fluidDirection != null && hasContinuousTrigger(level, pos, fluidDirection);
}
public static boolean isAntiwater(FluidState fluidState) {
ResourceLocation fluidId = BuiltInRegistries.FLUID.getKey(fluidState.getType());
return ANTIWATER_ID.equals(fluidId) || FLOWING_ANTIWATER_ID.equals(fluidId);
}
public static boolean isIchor(FluidState fluidState) {
ResourceLocation fluidId = BuiltInRegistries.FLUID.getKey(fluidState.getType());
return ICHOR_ID.equals(fluidId) || FLOWING_ICHOR_ID.equals(fluidId);
}
public static Direction getEruptionDirection(LevelAccessor level, BlockPos pos) {
Direction fluidDirection = getFluidColumnDirection(level, pos);
if (fluidDirection != null) {
return fluidDirection.getOpposite();
}
return Direction.UP;
}
public static Direction getFluidColumnDirection(LevelAccessor level, BlockPos pos) {
boolean hasUpFluid = hasValidFluidColumn(level, pos, Direction.UP);
boolean hasDownFluid = hasValidFluidColumn(level, pos, Direction.DOWN);
if (!hasUpFluid && !hasDownFluid) {
return null;
}
if (hasUpFluid && !hasDownFluid) {
return Direction.UP;
}
if (hasDownFluid && !hasUpFluid) {
return Direction.DOWN;
}
boolean hasUpHeat = hasContinuousTrigger(level, pos, Direction.UP);
boolean hasDownHeat = hasContinuousTrigger(level, pos, Direction.DOWN);
if (hasUpHeat && !hasDownHeat) {
return Direction.DOWN;
}
if (hasDownHeat && !hasUpHeat) {
return Direction.UP;
}
boolean hasUpTag = hasPeriodicTrigger(level, pos, Direction.UP);
boolean hasDownTag = hasPeriodicTrigger(level, pos, Direction.DOWN);
if (hasUpTag && !hasDownTag) {
return Direction.DOWN;
}
if (hasDownTag && !hasUpTag) {
return Direction.UP;
}
return Direction.UP;
}
public static boolean hasAntiwaterOnSide(LevelAccessor level, BlockPos pos, Direction direction) {
FluidState fluidState = level.getFluidState(pos.relative(direction));
return fluidState.isSource() && isAntiwater(fluidState);
}
public static boolean hasGasFluid(LevelAccessor level, BlockPos pos, Direction direction) {
FluidState fluidState = level.getFluidState(pos.relative(direction));
return fluidState.isSource() && isAntiwater(fluidState);
}
public static boolean hasPeriodicTrigger(LevelAccessor level, BlockPos pos, Direction direction) {
int fluidBlocks = getFluidColumnDepth(level, pos, direction);
return fluidBlocks > 0
&& level.getBlockState(pos.relative(direction, fluidBlocks + 1)).is(AntarchyTags.Blocks.POTENT_NYXITE_ACTIVATION_BLOCKS);
}
public static boolean hasContinuousTrigger(LevelAccessor level, BlockPos pos, Direction direction) {
int fluidBlocks = getFluidColumnDepth(level, pos, direction);
if (fluidBlocks <= 0) {
return false;
}
FluidState fluidState = level.getFluidState(pos.relative(direction, fluidBlocks + 1));
return fluidState.isSourceOfType(Fluids.LAVA);
}
public static int getFluidColumnDepth(LevelAccessor level, BlockPos pos, Direction direction) {
if (direction != Direction.UP && direction != Direction.DOWN) {
return 0;
}
int depth = 0;
BlockPos.MutableBlockPos cursor = pos.relative(direction).mutable();
while (true) {
FluidState fluidState = level.getFluidState(cursor);
if (!fluidState.isSource() || !isAntiwater(fluidState)) {
break;
}
depth++;
cursor.move(direction);
}
if (depth <= 0) {
return 0;
}
BlockState terminatorState = level.getBlockState(cursor);
FluidState terminatorFluidState = level.getFluidState(cursor);
if (terminatorFluidState.isSourceOfType(Fluids.LAVA) || terminatorState.is(AntarchyTags.Blocks.POTENT_NYXITE_ACTIVATION_BLOCKS)) {
return depth;
}
return 0;
}
private static boolean hasValidFluidColumn(LevelAccessor level, BlockPos pos, Direction direction) {
return getFluidColumnDepth(level, pos, direction) > 0;
}
private static void spawnHypnoticGasParticlesAt(
Level level,
RandomSource random,
BlockPos particlePos,
ResourceLocation particleId,
Direction eruptionDirection
) {
level.addAlwaysVisibleParticle(
simpleParticle(particleId),
particlePos.getX() + 0.2D + random.nextDouble() * 0.6D,
particlePos.getY() + 0.1D + random.nextDouble() * 0.35D,
particlePos.getZ() + 0.2D + random.nextDouble() * 0.6D,
0.0D,
eruptionDirection == Direction.UP ? 0.01D : -0.01D,
0.0D
);
}
private static SimpleParticleType simpleParticle(ResourceLocation id) {
return (SimpleParticleType) BuiltInRegistries.PARTICLE_TYPE.get(id);
}
}
@@ -0,0 +1,82 @@
package com.craisinlord.antarchy.content.block;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
public class SignalSavingBulbBlock extends Block {
public static final BooleanProperty LIT = BlockStateProperties.LIT;
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
public static final IntegerProperty BRIGHTNESS = IntegerProperty.create("brightness", 0, 15);
public SignalSavingBulbBlock(BlockBehaviour.Properties properties) {
super(properties.lightLevel(state -> state.getValue(LIT) ? state.getValue(BRIGHTNESS) : 0));
this.registerDefaultState(this.defaultBlockState()
.setValue(LIT, false)
.setValue(POWERED, false)
.setValue(BRIGHTNESS, 0));
}
@Override
protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean moving) {
if (oldState.getBlock() != state.getBlock() && level instanceof ServerLevel serverLevel) {
this.checkAndFlip(state, serverLevel, pos);
}
}
@Override
protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block block, BlockPos fromPos, boolean moving) {
if (level instanceof ServerLevel serverLevel) {
this.checkAndFlip(state, serverLevel, pos);
}
}
public void checkAndFlip(BlockState state, ServerLevel level, BlockPos pos) {
boolean receiving = level.hasNeighborSignal(pos);
boolean wasPowered = state.getValue(POWERED);
if (receiving == wasPowered) return;
BlockState newState = state;
if (!wasPowered) {
boolean isLit = state.getValue(LIT);
if (!isLit) {
int strength = level.getBestNeighborSignal(pos);
newState = state.setValue(LIT, true).setValue(BRIGHTNESS, Math.max(strength, 1));
level.playSound((Player) null, pos, SoundEvents.COPPER_BULB_TURN_ON, SoundSource.BLOCKS);
} else {
newState = state.setValue(LIT, false).setValue(BRIGHTNESS, 0);
level.playSound((Player) null, pos, SoundEvents.COPPER_BULB_TURN_OFF, SoundSource.BLOCKS);
}
}
level.setBlock(pos, newState.setValue(POWERED, receiving), 3);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(LIT, POWERED, BRIGHTNESS);
}
@Override
protected boolean hasAnalogOutputSignal(BlockState state) {
return true;
}
@Override
protected int getAnalogOutputSignal(BlockState state, Level level, BlockPos pos) {
return state.getValue(LIT) ? state.getValue(BRIGHTNESS) : 0;
}
}
@@ -0,0 +1,18 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
public class TorchflowerBushBlock extends MilkweedBlock {
public static final MapCodec<TorchflowerBushBlock> CODEC = Block.simpleCodec(TorchflowerBushBlock::new);
public TorchflowerBushBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public MapCodec<MilkweedBlock> codec() {
return (MapCodec<MilkweedBlock>) (MapCodec<?>) CODEC;
}
}
@@ -0,0 +1,76 @@
package com.craisinlord.antarchy.content.block;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.EntityCollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public class TriffidGooBlock extends Block {
private static final double BOUNCE_VELOCITY_THRESHOLD = 0.6;
private static final double MAX_SINK_SPEED = 0.05;
private static final double SPRINT_VELOCITY_THRESHOLD = 0.1;
public TriffidGooBlock(BlockBehaviour.Properties properties) {
super(properties);
}
public boolean isStickyBlock(BlockState state) {
return true;
}
public boolean canStickTo(BlockState state, BlockState other) {
return !other.is(Blocks.SLIME_BLOCK) && !other.is(Blocks.HONEY_BLOCK);
}
@Override
protected VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
if (context instanceof EntityCollisionContext ecc) {
Entity entity = ecc.getEntity();
if (entity != null) {
Vec3 delta = entity.getDeltaMovement();
double vy = delta.y;
double hSpeed = Math.sqrt(delta.x * delta.x + delta.z * delta.z);
if (vy <= 0.0 && vy > -BOUNCE_VELOCITY_THRESHOLD && hSpeed < SPRINT_VELOCITY_THRESHOLD) {
return Shapes.empty();
}
}
}
return super.getCollisionShape(state, level, pos, context);
}
@Override
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
Vec3 delta = entity.getDeltaMovement();
if (delta.y < -MAX_SINK_SPEED) {
entity.setDeltaMovement(delta.x * 0.9, -MAX_SINK_SPEED, delta.z * 0.9);
} else {
entity.setDeltaMovement(delta.x * 0.9, delta.y, delta.z * 0.9);
}
entity.fallDistance = 0.0F;
}
@Override
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
entity.causeFallDamage(fallDistance, 0.0F, level.damageSources().fall());
}
@Override
public void updateEntityAfterFallOn(BlockGetter level, Entity entity) {
Vec3 delta = entity.getDeltaMovement();
if (delta.y < 0.0) {
double coefficient = entity instanceof LivingEntity ? 1.0 : 0.8;
entity.setDeltaMovement(delta.x, -delta.y * coefficient, delta.z);
}
}
}
@@ -0,0 +1,54 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.AntarchyTags;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
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.BonemealableBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
public class UmbralMossBlock extends Block implements BonemealableBlock {
public static final MapCodec<UmbralMossBlock> CODEC = Block.simpleCodec(UmbralMossBlock::new);
private static final ResourceKey<ConfiguredFeature<?, ?>> UMBRAL_MOSS_PATCH_BONEMEAL = ResourceKey.create(
Registries.CONFIGURED_FEATURE,
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "umbral_moss_patch_bonemeal")
);
public UmbralMossBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public MapCodec<UmbralMossBlock> codec() {
return CODEC;
}
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state) {
return level.getBlockState(pos.above()).isAir();
}
@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) {
Holder.Reference<ConfiguredFeature<?, ?>> feature = level.registryAccess()
.lookupOrThrow(Registries.CONFIGURED_FEATURE)
.getOrThrow(UMBRAL_MOSS_PATCH_BONEMEAL);
feature.value().place(level, level.getChunkSource().getGenerator(), random, pos);
}
}
@@ -0,0 +1,136 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.BlockGetter;
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.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.WallSide;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public class UmbralMossCarpetBlock extends Block {
public static final MapCodec<UmbralMossCarpetBlock> CODEC = Block.simpleCodec(UmbralMossCarpetBlock::new);
public static final BooleanProperty BOTTOM = BlockStateProperties.BOTTOM;
public static final net.minecraft.world.level.block.state.properties.EnumProperty<WallSide> NORTH_WALL = BlockStateProperties.NORTH_WALL;
public static final net.minecraft.world.level.block.state.properties.EnumProperty<WallSide> EAST_WALL = BlockStateProperties.EAST_WALL;
public static final net.minecraft.world.level.block.state.properties.EnumProperty<WallSide> SOUTH_WALL = BlockStateProperties.SOUTH_WALL;
public static final net.minecraft.world.level.block.state.properties.EnumProperty<WallSide> WEST_WALL = BlockStateProperties.WEST_WALL;
private static final VoxelShape FLOOR_SHAPE = Block.box(0.0D, 0.0D, 0.0D, 16.0D, 1.0D, 16.0D);
private static final VoxelShape NORTH_LOW = Block.box(0.0D, 0.0D, 0.0D, 16.0D, 6.0D, 1.0D);
private static final VoxelShape NORTH_TALL = Block.box(0.0D, 0.0D, 0.0D, 16.0D, 16.0D, 1.0D);
private static final VoxelShape EAST_LOW = Block.box(15.0D, 0.0D, 0.0D, 16.0D, 6.0D, 16.0D);
private static final VoxelShape EAST_TALL = Block.box(15.0D, 0.0D, 0.0D, 16.0D, 16.0D, 16.0D);
private static final VoxelShape SOUTH_LOW = Block.box(0.0D, 0.0D, 15.0D, 16.0D, 6.0D, 16.0D);
private static final VoxelShape SOUTH_TALL = Block.box(0.0D, 0.0D, 15.0D, 16.0D, 16.0D, 16.0D);
private static final VoxelShape WEST_LOW = Block.box(0.0D, 0.0D, 0.0D, 1.0D, 6.0D, 16.0D);
private static final VoxelShape WEST_TALL = Block.box(0.0D, 0.0D, 0.0D, 1.0D, 16.0D, 16.0D);
public UmbralMossCarpetBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any()
.setValue(BOTTOM, true)
.setValue(NORTH_WALL, WallSide.NONE)
.setValue(EAST_WALL, WallSide.NONE)
.setValue(SOUTH_WALL, WallSide.NONE)
.setValue(WEST_WALL, WallSide.NONE));
}
@Override
public MapCodec<UmbralMossCarpetBlock> codec() {
return CODEC;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(BOTTOM, NORTH_WALL, EAST_WALL, SOUTH_WALL, WEST_WALL);
}
@Override
public BlockState getStateForPlacement(net.minecraft.world.item.context.BlockPlaceContext context) {
BlockPos pos = context.getClickedPos();
Direction face = context.getClickedFace();
BlockState state = this.defaultBlockState()
.setValue(BOTTOM, face == Direction.UP)
.setValue(NORTH_WALL, WallSide.NONE)
.setValue(EAST_WALL, WallSide.NONE)
.setValue(SOUTH_WALL, WallSide.NONE)
.setValue(WEST_WALL, WallSide.NONE);
if (!state.getValue(BOTTOM)) {
state = switch (face) {
case NORTH -> state.setValue(NORTH_WALL, WallSide.TALL);
case EAST -> state.setValue(EAST_WALL, WallSide.TALL);
case SOUTH -> state.setValue(SOUTH_WALL, WallSide.TALL);
case WEST -> state.setValue(WEST_WALL, WallSide.TALL);
default -> state;
};
}
return state;
}
@Override
protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
if (state.getValue(BOTTOM)) {
return level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
}
if (supportsWall(level, pos, Direction.NORTH, state.getValue(NORTH_WALL))) {
return true;
}
if (supportsWall(level, pos, Direction.EAST, state.getValue(EAST_WALL))) {
return true;
}
if (supportsWall(level, pos, Direction.SOUTH, state.getValue(SOUTH_WALL))) {
return true;
}
if (supportsWall(level, pos, Direction.WEST, state.getValue(WEST_WALL))) {
return true;
}
return level.getBlockState(pos.above()).isFaceSturdy(level, pos.above(), Direction.DOWN);
}
@Override
protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
return state.canSurvive(level, pos) ? state : net.minecraft.world.level.block.Blocks.AIR.defaultBlockState();
}
@Override
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
if (state.getValue(BOTTOM)) {
return FLOOR_SHAPE;
}
VoxelShape shape = Shapes.empty();
shape = combine(shape, state.getValue(NORTH_WALL), NORTH_LOW, NORTH_TALL);
shape = combine(shape, state.getValue(EAST_WALL), EAST_LOW, EAST_TALL);
shape = combine(shape, state.getValue(SOUTH_WALL), SOUTH_LOW, SOUTH_TALL);
shape = combine(shape, state.getValue(WEST_WALL), WEST_LOW, WEST_TALL);
return shape.isEmpty() ? FLOOR_SHAPE : shape;
}
private static boolean supportsWall(LevelReader level, BlockPos pos, Direction direction, WallSide side) {
if (side == WallSide.NONE) {
return false;
}
BlockPos supportPos = pos.relative(direction);
return level.getBlockState(supportPos).isFaceSturdy(level, supportPos, direction.getOpposite());
}
private static VoxelShape combine(VoxelShape current, WallSide side, VoxelShape lowShape, VoxelShape tallShape) {
if (side == WallSide.NONE) {
return current;
}
return Shapes.or(current, side == WallSide.TALL ? tallShape : lowShape);
}
}
@@ -0,0 +1,122 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.block.entity.WaspNestBlockEntity;
import com.craisinlord.antarchy.content.entity.WaspEntity;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BaseEntityBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import org.jetbrains.annotations.Nullable;
import java.util.function.Supplier;
public class WaspNestBlock extends BaseEntityBlock {
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
private final Supplier<? extends BlockEntityType<WaspNestBlockEntity>> blockEntityTypeSupplier;
private final int maxOccupants;
private final boolean populateInitialWasps;
private final MapCodec<WaspNestBlock> codec;
public WaspNestBlock(
Supplier<? extends BlockEntityType<WaspNestBlockEntity>> blockEntityTypeSupplier,
BlockBehaviour.Properties properties
) {
this(blockEntityTypeSupplier, 4, true, properties);
}
public WaspNestBlock(
Supplier<? extends BlockEntityType<WaspNestBlockEntity>> blockEntityTypeSupplier,
int maxOccupants,
boolean populateInitialWasps,
BlockBehaviour.Properties properties
) {
super(properties);
this.blockEntityTypeSupplier = blockEntityTypeSupplier;
this.maxOccupants = maxOccupants;
this.populateInitialWasps = populateInitialWasps;
this.codec = Block.simpleCodec(ignored -> this);
this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH));
}
@Override
public MapCodec<WaspNestBlock> codec() {
return this.codec;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite());
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FACING);
}
@Override
protected RenderShape getRenderShape(BlockState state) {
return RenderShape.MODEL;
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new WaspNestBlockEntity(pos, state);
}
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
return level.isClientSide
? null
: createTickerHelper(blockEntityType, this.blockEntityTypeSupplier.get(),
(tickLevel, tickPos, tickState, nest) -> {
if (tickLevel instanceof ServerLevel serverLevel) {
WaspNestBlockEntity.serverTick(serverLevel, tickPos, tickState, nest);
}
});
}
@Override
public void setPlacedBy(Level level, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) {
super.setPlacedBy(level, pos, state, placer, stack);
if (!level.isClientSide && this.populateInitialWasps && level.getBlockEntity(pos) instanceof WaspNestBlockEntity nestBlockEntity) {
nestBlockEntity.populateInitialWasps((ServerLevel) level);
}
}
@Override
public BlockState playerWillDestroy(Level level, BlockPos pos, BlockState state, net.minecraft.world.entity.player.Player player) {
if (!level.isClientSide && level.getBlockEntity(pos) instanceof WaspNestBlockEntity nestBlockEntity) {
nestBlockEntity.releaseAll((ServerLevel) level);
}
return super.playerWillDestroy(level, pos, state, player);
}
public int maxOccupants() {
return this.maxOccupants;
}
public boolean shouldPopulateInitialWasps() {
return this.populateInitialWasps;
}
public EntityType<? extends WaspEntity> waspType() {
return com.craisinlord.antarchy.content.AntarchyObjects.WASP.get();
}
}
@@ -0,0 +1,194 @@
package com.craisinlord.antarchy.content.block.entity;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.block.AntNestBlock;
import com.craisinlord.antarchy.content.entity.ant.BaseAntEntity;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
public class AntNestBlockEntity extends BlockEntity {
private static final String STORED_ANTS = "StoredAnts";
private static final String NBT_INITIALIZED = "Initialized";
private static final int RELEASE_COOLDOWN_MIN = 80;
private static final int RELEASE_COOLDOWN_RANGE = 100;
private static final int ENTER_NEST_COOLDOWN = 200;
private static final int INITIAL_ANT_COUNT_MIN = 2;
private static final int INITIAL_ANT_COUNT_RANGE = 4;
private static final double SPAWN_OFFSET_XZ = 0.5D;
private static final double SPAWN_OFFSET_Y = 0.05D;
private final List<StoredAnt> storedAnts = new ArrayList<>();
private int releaseCooldown = RELEASE_COOLDOWN_MIN;
private boolean initialized = false;
public AntNestBlockEntity(BlockPos pos, BlockState blockState) {
super(AntarchyObjects.ANT_NEST_BLOCK_ENTITY.get(), pos, blockState);
}
public static void serverTick(ServerLevel level, BlockPos pos, BlockState state, AntNestBlockEntity nest) {
if (!nest.initialized) {
nest.populateInitialAnts(level);
}
if (level.isNight() || level.isRaining()) {
return;
}
if (nest.storedAnts.isEmpty()) {
return;
}
if (--nest.releaseCooldown > 0) {
return;
}
nest.releaseCooldown = RELEASE_COOLDOWN_MIN + level.random.nextInt(RELEASE_COOLDOWN_RANGE);
nest.releaseOne(level);
}
public void populateInitialAnts(ServerLevel level) {
if (this.initialized) {
return;
}
this.initialized = true;
if (!this.nestBlock().shouldPopulateInitialAnts()) {
return;
}
int amount = INITIAL_ANT_COUNT_MIN + level.random.nextInt(INITIAL_ANT_COUNT_RANGE);
for (int i = 0; i < amount && this.storedAnts.size() < this.maxOccupants(); i++) {
EntityType<?> antType = this.nestBlock().initialAntType(level.random);
this.storedAnts.add(this.createStoredAnt(level, antType));
}
this.setChanged();
}
public boolean canAccept(EntityType<?> antType) {
return this.nestBlock().canAccept(antType) && this.storedAnts.size() < this.maxOccupants();
}
public boolean tryStoreAnt(BaseAntEntity antEntity) {
if (!this.canAccept(antEntity.getType())) {
return false;
}
antEntity.onEnterNest();
CompoundTag antTag = new CompoundTag();
antEntity.addAdditionalSaveData(antTag);
this.storedAnts.add(new StoredAnt(antEntity.getType(), antTag));
this.releaseCooldown = Math.max(this.releaseCooldown, ENTER_NEST_COOLDOWN);
antEntity.discard();
this.setChanged();
return true;
}
public void releaseAll(ServerLevel level) {
while (!this.storedAnts.isEmpty()) {
this.releaseOne(level);
}
}
private void releaseOne(ServerLevel level) {
if (this.storedAnts.isEmpty()) {
return;
}
StoredAnt storedAnt = this.storedAnts.get(0);
BaseAntEntity antEntity = storedAnt.create(level);
if (antEntity == null) {
this.storedAnts.remove(0);
return;
}
BlockPos spawnPos = this.getBlockPos().above();
if (!level.getBlockState(spawnPos).canBeReplaced()) {
return;
}
antEntity.moveTo(spawnPos.getX() + SPAWN_OFFSET_XZ, spawnPos.getY() + SPAWN_OFFSET_Y, spawnPos.getZ() + SPAWN_OFFSET_XZ, level.random.nextFloat() * 360.0F, 0.0F);
if (!level.noCollision(antEntity)) {
return;
}
this.storedAnts.remove(0);
antEntity.setNestPos(this.getBlockPos());
antEntity.onExitNest();
level.addFreshEntity(antEntity);
this.setChanged();
}
private int maxOccupants() {
return this.nestBlock().maxOccupants();
}
private AntNestBlock nestBlock() {
return (AntNestBlock) this.getBlockState().getBlock();
}
private StoredAnt createStoredAnt(ServerLevel level, EntityType<?> antType) {
if (!(antType.create(level) instanceof BaseAntEntity antEntity)) {
return new StoredAnt(antType, new CompoundTag());
}
antEntity.setNestPos(this.getBlockPos());
CompoundTag antTag = new CompoundTag();
antEntity.addAdditionalSaveData(antTag);
return new StoredAnt(antType, antTag);
}
@Override
protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.saveAdditional(tag, registries);
tag.putBoolean(NBT_INITIALIZED, this.initialized);
ListTag listTag = new ListTag();
for (StoredAnt storedAnt : this.storedAnts) {
listTag.add(storedAnt.save());
}
tag.put(STORED_ANTS, listTag);
}
@Override
protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.loadAdditional(tag, registries);
this.initialized = tag.getBoolean(NBT_INITIALIZED);
this.storedAnts.clear();
ListTag listTag = tag.getList(STORED_ANTS, Tag.TAG_COMPOUND);
for (int i = 0; i < listTag.size(); i++) {
this.storedAnts.add(StoredAnt.load(listTag.getCompound(i)));
}
}
private record StoredAnt(EntityType<?> antType, CompoundTag data) {
private CompoundTag save() {
CompoundTag tag = new CompoundTag();
tag.putString("id", BuiltInRegistries.ENTITY_TYPE.getKey(this.antType).toString());
tag.put("data", this.data.copy());
return tag;
}
private static StoredAnt load(CompoundTag tag) {
EntityType<?> antType = BuiltInRegistries.ENTITY_TYPE.getOptional(net.minecraft.resources.ResourceLocation.parse(tag.getString("id"))).orElse(EntityType.SILVERFISH);
return new StoredAnt(antType, tag.getCompound("data"));
}
private BaseAntEntity create(ServerLevel level) {
if (!(this.antType.create(level) instanceof BaseAntEntity antEntity)) {
return null;
}
antEntity.readAdditionalSaveData(this.data.copy());
return antEntity;
}
}
}
@@ -0,0 +1,32 @@
package com.craisinlord.antarchy.content.block.entity;
import com.craisinlord.antarchy.content.AntarchyObjects;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.entity.CampfireBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
public class DreamCampfireBlockEntity extends CampfireBlockEntity {
private static final ThreadLocal<Boolean> CONSTRUCTING_DREAM_CAMPFIRE = ThreadLocal.withInitial(() -> false);
public DreamCampfireBlockEntity(BlockPos pos, BlockState blockState) {
super(pos, blockState);
}
@Override
public BlockEntityType<?> getType() {
return AntarchyObjects.DREAM_CAMPFIRE_BLOCK_ENTITY.get();
}
public static void beginConstruction() {
CONSTRUCTING_DREAM_CAMPFIRE.set(true);
}
public static void endConstruction() {
CONSTRUCTING_DREAM_CAMPFIRE.set(false);
}
public static boolean isConstructingDreamCampfire() {
return CONSTRUCTING_DREAM_CAMPFIRE.get();
}
}
@@ -0,0 +1,69 @@
package com.craisinlord.antarchy.content.block.entity;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.AntarchyTags;
import com.craisinlord.antarchy.content.block.HushweedBlock;
import com.craisinlord.antarchy.content.entity.HushProjectileEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.Difficulty;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
public class HushweedBlockEntity extends BlockEntity {
private static final int COOLDOWN_TICKS = 30;
private static final double ATTACK_RANGE = 8.0D;
private static final double PROJECTILE_CLEARANCE = 1.1D;
private int cooldownTicks;
public HushweedBlockEntity(BlockPos pos, BlockState blockState) {
super(AntarchyObjects.HUSHWEED_BLOCK_ENTITY.get(), pos, blockState);
}
public static void serverTick(ServerLevel level, BlockPos pos, BlockState state, HushweedBlockEntity blockEntity) {
if (level.getDifficulty() == Difficulty.PEACEFUL) {
return;
}
if (blockEntity.cooldownTicks > 0) {
blockEntity.cooldownTicks--;
return;
}
Vec3 center = Vec3.atCenterOf(pos);
LivingEntity target = level.getEntitiesOfClass(
LivingEntity.class,
new AABB(pos).inflate(ATTACK_RANGE),
entity -> entity.isAlive()
&& entity.getType().is(AntarchyTags.Entities.HUSHWEED_TARGETS)
&& (!(entity instanceof Player player) || (!player.isCreative() && !player.isSpectator())))
.stream()
.min(java.util.Comparator.comparingDouble(entity -> entity.distanceToSqr(center)))
.orElse(null);
if (target == null) {
return;
}
Direction facing = state.getValue(HushweedBlock.FACING);
Vec3 spawnPos = facing == Direction.UP
? new Vec3(pos.getX() + 0.5D, pos.getY() + PROJECTILE_CLEARANCE, pos.getZ() + 0.5D)
: new Vec3(pos.getX() + 0.5D, pos.getY() + (1.0D - PROJECTILE_CLEARANCE), pos.getZ() + 0.5D);
Vec3 targetPos = target.getEyePosition().subtract(spawnPos);
if (targetPos.lengthSqr() < 1.0E-6D) {
return;
}
HushProjectileEntity projectile = new HushProjectileEntity(AntarchyObjects.HUSH_PROJECTILE.get(), level);
projectile.setPos(spawnPos.x, spawnPos.y, spawnPos.z);
projectile.setTargetUuid(target.getUUID());
projectile.setDeltaMovement(0.0D, 0.27D, 0.0D);
projectile.setNoGravity(true);
level.addFreshEntity(projectile);
blockEntity.cooldownTicks = COOLDOWN_TICKS;
}
}
@@ -0,0 +1,521 @@
package com.craisinlord.antarchy.content.block.entity;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.block.PotentNyxiteBlock;
import com.craisinlord.antarchy.content.block.state.PotentNyxiteState;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityDirection;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityRotationUtil;
import com.craisinlord.antarchy.content.client.particle.InvertedGeyserParticleOptions;
import java.util.List;
import java.util.function.Predicate;
import java.util.function.Supplier;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Holder;
import net.minecraft.core.particles.ParticleType;
import net.minecraft.core.particles.SimpleParticleType;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntitySelector;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
public class PotentNyxiteBlockEntity extends BlockEntity {
public static final long GEYSER_SALT = -904011478L;
private static final ResourceLocation HYPNOTIC_GAS_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "hypnotic_gas");
private static final ResourceLocation HYPNOTIC_GAS_DOWN_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "hypnotic_gas_down");
private static final ResourceLocation HYPNOTIC_GAS_CLOUD_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "hypnotic_gas_cloud");
private static final ResourceLocation HYPNOTIC_GAS_CLOUD_DOWN_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "hypnotic_gas_cloud_down");
private static final ResourceLocation INVERTED_GEYSER_ERUPTION_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "inverted_geyser_eruption");
private static final ResourceLocation GEYSER_ERUPTION_START_SOUND_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "potent_nyxite_geyser_eruption_start");
private static final ResourceLocation GEYSER_ERUPTION_ACTIVE_SOUND_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "potent_nyxite_geyser_eruption_active");
private static final ResourceLocation GEYSER_CONTINUOUS_START_SOUND_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "potent_nyxite_geyser_continuous_start");
private static final ResourceLocation GEYSER_CONTINUOUS_ACTIVE_SOUND_ID = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "potent_nyxite_geyser_continuous_active");
private static final int MAX_FLUID_COLUMN_STEPS = 5;
private static final Predicate<Entity> EFFECT_PREDICATE = EntitySelector.NO_SPECTATORS.and(EntitySelector.ENTITY_STILL_ALIVE);
private int waitingCountdown = -1;
private long eruptionTick = -1L;
public PotentNyxiteBlockEntity(
BlockPos pos,
BlockState blockState,
Supplier<? extends BlockEntityType<PotentNyxiteBlockEntity>> blockEntityTypeSupplier
) {
super(blockEntityTypeSupplier.get(), pos, blockState);
}
public static void serverTick(ServerLevel level, BlockPos pos, BlockState state, PotentNyxiteBlockEntity blockEntity) {
blockEntity.serverTick(level, pos, state);
}
public static void clientTick(Level level, BlockPos pos, BlockState state, PotentNyxiteBlockEntity blockEntity) {
if (level instanceof ClientLevel clientLevel) {
blockEntity.clientTick(clientLevel, pos, state);
}
}
public static void handleStateActivation(Level level, BlockPos pos, BlockState state) {
PotentNyxiteState stateValue = state.getValue(PotentNyxiteBlock.STATE);
if (stateValue != PotentNyxiteState.ERUPTING && stateValue != PotentNyxiteState.CONTINUOUS) {
return;
}
level.blockEvent(pos, state.getBlock(), 0, 0);
level.playSound(
null,
pos,
BuiltInRegistries.SOUND_EVENT.get(
stateValue == PotentNyxiteState.CONTINUOUS ? GEYSER_CONTINUOUS_START_SOUND_ID : GEYSER_ERUPTION_START_SOUND_ID
),
net.minecraft.sounds.SoundSource.BLOCKS,
2.5F,
1.0F
);
}
public void markEruptionStart(long gameTime) {
this.eruptionTick = gameTime;
}
@Override
public void setLevel(Level level) {
super.setLevel(level);
if (this.eruptionTick == -1L) {
this.eruptionTick = level.getGameTime();
}
}
@Override
protected void saveAdditional(CompoundTag tag, net.minecraft.core.HolderLookup.Provider registries) {
super.saveAdditional(tag, registries);
tag.putInt("countdown", this.waitingCountdown);
tag.putLong("eruption_tick", this.eruptionTick);
}
@Override
protected void loadAdditional(CompoundTag tag, net.minecraft.core.HolderLookup.Provider registries) {
super.loadAdditional(tag, registries);
this.waitingCountdown = tag.getInt("countdown");
this.eruptionTick = tag.getLong("eruption_tick");
}
private void serverTick(ServerLevel level, BlockPos pos, BlockState state) {
if (!(state.getBlock() instanceof PotentNyxiteBlock)) {
return;
}
Direction fluidDirection = PotentNyxiteBlock.getFluidColumnDirection(level, pos);
BlockPos source = fluidDirection == null ? null : findHypnoticGasSourceBlock(level, pos, fluidDirection);
BlockPos adjustedSource = source == null || fluidDirection == null ? null : getAdjustedSource(source, fluidDirection);
if (level.getGameTime() % 30L == 0L && adjustedSource != null) {
applyHypnoticGasEffects(level, adjustedSource, fluidDirection);
}
PotentNyxiteState environmentState = PotentNyxiteBlock.resolveState(level, pos, state);
PotentNyxiteState currentState = state.getValue(PotentNyxiteBlock.STATE);
if (environmentState == PotentNyxiteState.CONTINUOUS) {
if (currentState != PotentNyxiteState.CONTINUOUS) {
BlockState newState = state.setValue(PotentNyxiteBlock.STATE, PotentNyxiteState.CONTINUOUS);
level.setBlock(pos, newState, Block.UPDATE_CLIENTS);
handleStateActivation(level, pos, newState);
this.setChanged();
}
this.waitingCountdown = -1;
launchEntities(level, pos);
return;
}
if (environmentState == PotentNyxiteState.DORMANT) {
if (currentState != PotentNyxiteState.DORMANT && currentState != PotentNyxiteState.ERUPTING) {
level.setBlock(pos, state.setValue(PotentNyxiteBlock.STATE, PotentNyxiteState.DORMANT), Block.UPDATE_CLIENTS);
currentState = PotentNyxiteState.DORMANT;
}
if (source != null && fluidDirection != null && level.getGameTime() % 20L == 0L) {
int fluidBlocks = getFluidBlocks(level, pos, source, fluidDirection);
RandomSource geyserRandom = geyserPositional(level, pos);
if (this.waitingCountdown <= 0) {
if (currentState == PotentNyxiteState.ERUPTING) {
geyserRandom.nextInt();
this.waitingCountdown = Math.max(1, fluidBlocks - 1) + geyserRandom.nextIntBetweenInclusive(1, 2);
} else {
this.waitingCountdown = 10 * Math.max(0, fluidBlocks - 1) + geyserRandom.nextIntBetweenInclusive(15, 30);
}
}
if (this.waitingCountdown > 0) {
this.waitingCountdown--;
}
if (this.waitingCountdown == 0) {
PotentNyxiteState nextState = currentState == PotentNyxiteState.ERUPTING
? PotentNyxiteState.DORMANT
: PotentNyxiteState.ERUPTING;
BlockState newState = state.setValue(PotentNyxiteBlock.STATE, nextState);
level.setBlock(pos, newState, Block.UPDATE_CLIENTS);
if (nextState == PotentNyxiteState.ERUPTING) {
handleStateActivation(level, pos, newState);
level.gameEvent(GameEvent.BLOCK_ACTIVATE, pos, GameEvent.Context.of(newState));
} else {
level.gameEvent(GameEvent.BLOCK_DEACTIVATE, pos, GameEvent.Context.of(newState));
}
currentState = nextState;
this.setChanged();
}
}
if (currentState == PotentNyxiteState.ERUPTING) {
launchEntities(level, pos);
}
return;
}
PotentNyxiteState fallbackState = environmentState == PotentNyxiteState.WET ? PotentNyxiteState.WET : PotentNyxiteState.DRY;
if (currentState != fallbackState) {
level.setBlock(pos, state.setValue(PotentNyxiteBlock.STATE, fallbackState), Block.UPDATE_CLIENTS);
}
this.waitingCountdown = -1;
}
private void clientTick(ClientLevel level, BlockPos pos, BlockState state) {
Direction fluidDirection = PotentNyxiteBlock.getFluidColumnDirection(level, pos);
if (fluidDirection == null) {
return;
}
BlockPos source = findHypnoticGasSourceBlock(level, pos, fluidDirection);
Direction eruptionDirection = PotentNyxiteBlock.getEruptionDirection(level, pos);
if (source != null && level.getGameTime() % 4L == 0L) {
boolean flipped = eruptionDirection == Direction.DOWN;
RandomSource random = level.getRandom();
int count = flipped ? 3 : 4;
Vec3 center = Vec3.atCenterOf(source);
for (int i = 0; i < count; i++) {
double angle = random.nextDouble() * Mth.TWO_PI;
double radius = 0.18D + random.nextDouble() * 0.32D;
double outwardX = Mth.cos((float) angle) * radius;
double outwardZ = Mth.sin((float) angle) * radius;
double x = center.x + outwardX;
double z = center.z + outwardZ;
double y = source.getY() + (flipped ? 0.72D : 0.18D) + random.nextDouble() * 0.20D;
double driftX = outwardX * 0.015D;
double driftY = flipped ? 0.02D : 0.015D;
double driftZ = outwardZ * 0.015D;
level.addAlwaysVisibleParticle(
simpleParticle(flipped ? HYPNOTIC_GAS_DOWN_ID : HYPNOTIC_GAS_ID),
x,
y,
z,
driftX,
driftY,
driftZ
);
}
}
if (source != null && level.getGameTime() % 20L == 0L) {
ResourceLocation cloudParticleId = eruptionDirection == Direction.DOWN
? HYPNOTIC_GAS_CLOUD_DOWN_ID
: HYPNOTIC_GAS_CLOUD_ID;
level.addParticle(simpleParticle(cloudParticleId), source.getX() + 0.5D, source.getY() + 0.5D, source.getZ() + 0.5D, 0.0D, 0.0D, 0.0D);
}
PotentNyxiteState stateValue = state.getValue(PotentNyxiteBlock.STATE);
if ((stateValue == PotentNyxiteState.ERUPTING || stateValue == PotentNyxiteState.CONTINUOUS) && source != null) {
int fluidBlocks = getFluidBlocks(level, pos, source, fluidDirection);
long eruptionTime = level.getGameTime() - this.eruptionTick;
if (eruptionDirection == Direction.DOWN && eruptionTime % 20L == 0L) {
spawnDownwardHypnoticGasTrail(level, source, fluidBlocks);
}
if (eruptionTime % 20L == 0L) {
level.addParticle(
new InvertedGeyserParticleOptions(geyserParticleType(INVERTED_GEYSER_ERUPTION_ID), fluidBlocks, eruptionDirection),
source.getX() + 0.5D,
source.getY(),
source.getZ() + 0.5D,
0.0D,
0.0D,
0.0D
);
}
if (eruptionTime % 40L == 0L) {
level.playLocalSound(
source.getX() + 0.5D,
source.getY() + 0.5D,
source.getZ() + 0.5D,
BuiltInRegistries.SOUND_EVENT.get(
stateValue == PotentNyxiteState.CONTINUOUS ? GEYSER_CONTINUOUS_ACTIVE_SOUND_ID : GEYSER_ERUPTION_ACTIVE_SOUND_ID
),
net.minecraft.sounds.SoundSource.BLOCKS,
1.0F,
1.0F,
false
);
}
}
}
private static void applyHypnoticGasEffects(ServerLevel level, BlockPos source, Direction fluidDirection) {
for (LivingEntity entity : getNearbyLivingEntities(level, source)) {
if (canBeReachedByHypnoticGas(level, source, entity.getEyePosition(), fluidDirection)) {
entity.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 240, 0, true, true));
}
}
}
private void launchEntities(ServerLevel level, BlockPos pos) {
Direction fluidDirection = PotentNyxiteBlock.getFluidColumnDirection(level, pos);
if (fluidDirection == null) {
return;
}
BlockPos source = findHypnoticGasSourceBlock(level, pos, fluidDirection);
if (source == null) {
return;
}
Direction eruptionDirection = PotentNyxiteBlock.getEruptionDirection(level, pos);
int fluidBlocks = getFluidBlocks(level, pos, source, fluidDirection);
int unobstructedBlocks = getUnobstructedBlockCount(level, source, eruptionDirection, fluidBlocks);
if (unobstructedBlocks <= 0) {
return;
}
BlockPos start = source;
BlockPos end = source.relative(eruptionDirection, unobstructedBlocks - 1);
AABB area = new AABB(
Math.min(start.getX(), end.getX()),
Math.min(start.getY(), end.getY()),
Math.min(start.getZ(), end.getZ()),
Math.max(start.getX(), end.getX()) + 1.0D,
Math.max(start.getY(), end.getY()) + 1.0D,
Math.max(start.getZ(), end.getZ()) + 1.0D
);
Vec3 worldPush = new Vec3(0.0D, eruptionDirection.getStepY() * 0.2D, 0.0D);
double velocityThreshold = 0.3D + fluidBlocks * 0.1D;
int invertedDurationTicks = Mth.floor(AntarchySettings.potentNyxiteInvertedDurationSeconds() * 20.0D);
Holder<MobEffect> invertedEffect = AntarchyObjects.INVERTED_EFFECT.get();
for (Entity entity : level.getEntitiesOfClass(Entity.class, area, EFFECT_PREDICATE)) {
if (entity instanceof Player player && player.getAbilities().flying) {
continue;
}
AntarchyGravityDirection gravityDirection = AntarchyGravityApi.getGravityDirection(entity);
Vec3 currentWorldVelocity = gravityDirection.isInverted()
? AntarchyGravityRotationUtil.vecPlayerToWorld(entity.getDeltaMovement(), gravityDirection)
: entity.getDeltaMovement();
double axisVelocity = currentWorldVelocity.y * eruptionDirection.getStepY();
if (axisVelocity <= velocityThreshold) {
Vec3 nextWorldVelocity = currentWorldVelocity.add(worldPush);
entity.setDeltaMovement(
gravityDirection.isInverted()
? AntarchyGravityRotationUtil.vecWorldToPlayer(nextWorldVelocity, gravityDirection)
: nextWorldVelocity
);
entity.hurtMarked = true;
entity.hasImpulse = true;
entity.fallDistance = 0.0F;
}
if (entity instanceof LivingEntity livingEntity) {
livingEntity.addEffect(new MobEffectInstance(invertedEffect, invertedDurationTicks, 0, false, true, true));
}
}
}
private static List<LivingEntity> getNearbyLivingEntities(Level level, BlockPos source) {
AABB aabb = new AABB(source).inflate(2.5D, 0.0D, 2.5D);
return level.getEntitiesOfClass(LivingEntity.class, aabb, entity -> EFFECT_PREDICATE.test(entity));
}
public static RandomSource geyserPositional(ServerLevel level, BlockPos pos) {
return new net.minecraft.world.level.levelgen.XoroshiroRandomSource(level.getSeed() ^ GEYSER_SALT).forkPositional().at(pos);
}
public static BlockPos findHypnoticGasSourceBlock(LevelAccessor level, BlockPos origin, Direction direction) {
if (direction == Direction.DOWN) {
return origin.above();
}
return findLegacyHypnoticGasSourceBlock(level, origin, direction);
}
private static BlockPos findLegacyHypnoticGasSourceBlock(LevelAccessor level, BlockPos origin, Direction direction) {
BlockPos.MutableBlockPos cursor = origin.relative(direction).mutable();
for (int i = 0; i <= MAX_FLUID_COLUMN_STEPS; i++) {
FluidState fluidState = level.getFluidState(cursor);
BlockState blockState = level.getBlockState(cursor);
if (fluidState.isSource() && isHypnoticGasFluid(fluidState) && isGeyserPassableBlock(level, cursor)) {
cursor.move(direction);
continue;
}
if (isGeyserPassableBlock(level, cursor)) {
return cursor.immutable();
}
return null;
}
return null;
}
public static Vec3 pickRandomHypnoticGasSpawnPoint(Level level, BlockPos source) {
RandomSource random = level.getRandom();
Vec3 offset = new Vec3(random.nextFloat() - 0.5F, 0.0D, random.nextFloat() - 0.5F).normalize();
float distance = random.nextFloat() * 3.0F;
return Vec3.atCenterOf(source).add(offset.scale(distance)).subtract(0.0D, 0.25D, 0.0D);
}
public static boolean canBeReachedByHypnoticGas(Level level, BlockPos source, Vec3 pos) {
Direction fluidDirection = isHypnoticGasFluid(level.getFluidState(source.below())) ? Direction.DOWN : Direction.UP;
return canBeReachedByHypnoticGas(level, source, pos, fluidDirection);
}
public static boolean canBeReachedByHypnoticGas(Level level, BlockPos source, Vec3 pos, Direction fluidDirection) {
BlockPos blockPos = BlockPos.containing(pos);
if (!isGeyserPassableBlock(level, blockPos)) {
return false;
}
if (pos.distanceToSqr(Vec3.atCenterOf(source)) > 9.0D) {
return false;
}
if (fluidDirection == Direction.DOWN) {
return haveLineOfSight(level, Vec3.atCenterOf(source), pos);
}
Direction adjacentFluidDirection = findAdjacentFluidDirection(level, source);
if (adjacentFluidDirection == null) {
return false;
}
Vec3 sourceSupport = Vec3.atCenterOf(source.relative(adjacentFluidDirection));
Vec3 targetSupport = pos.add(
adjacentFluidDirection.getStepX(),
adjacentFluidDirection.getStepY(),
adjacentFluidDirection.getStepZ()
);
return isHypnoticGasFluid(level.getFluidState(BlockPos.containing(targetSupport)))
&& haveLineOfSight(level, sourceSupport, targetSupport);
}
public static void spawnHypnoticGasParticle(Level level, Vec3 pos, boolean flipped) {
level.addAlwaysVisibleParticle(simpleParticle(flipped ? HYPNOTIC_GAS_DOWN_ID : HYPNOTIC_GAS_ID), pos.x, pos.y, pos.z, 0.0D, 0.0D, 0.0D);
}
public static void spawnHypnoticGasParticle(Level level, Vec3 pos) {
spawnHypnoticGasParticle(level, pos, false);
}
private static void spawnDownwardHypnoticGasTrail(ClientLevel level, BlockPos source, int fluidBlocks) {
RandomSource random = level.getRandom();
int particleCount = Math.max(3, fluidBlocks + 1);
for (int i = 0; i < particleCount; i++) {
double progress = particleCount == 1 ? 0.0D : (double) i / (double) (particleCount - 1);
double y = source.getY() + 0.35D - progress * Math.max(1, fluidBlocks);
double x = source.getX() + 0.5D + (random.nextDouble() - 0.5D) * 0.35D;
double z = source.getZ() + 0.5D + (random.nextDouble() - 0.5D) * 0.35D;
level.addParticle(simpleParticle(HYPNOTIC_GAS_DOWN_ID), x, y, z, 0.0D, -0.01D, 0.0D);
}
}
private static BlockPos getAdjustedSource(BlockPos source, Direction direction) {
return direction == Direction.DOWN ? source.above() : source;
}
private static Direction findAdjacentFluidDirection(LevelAccessor level, BlockPos source) {
if (isHypnoticGasFluid(level.getFluidState(source.above()))) {
return Direction.UP;
}
if (isHypnoticGasFluid(level.getFluidState(source.below()))) {
return Direction.DOWN;
}
return null;
}
private static int getFluidBlocks(LevelAccessor level, BlockPos origin, BlockPos source, Direction fluidDirection) {
if (fluidDirection == Direction.DOWN) {
return PotentNyxiteBlock.getFluidColumnDepth(level, origin, fluidDirection);
}
return fluidBlocksBetween(origin, source, fluidDirection);
}
private static int fluidBlocksBetween(BlockPos origin, BlockPos source, Direction fluidDirection) {
return Math.max(1, Math.abs(source.getY() - origin.getY()) - 1);
}
private static int getUnobstructedBlockCount(LevelAccessor level, BlockPos start, Direction direction, int fluidBlocks) {
int geyserForceHeight = 6 * Math.max(1, fluidBlocks);
for (int i = 0; i < geyserForceHeight; i++) {
BlockPos currentPos = start.relative(direction, i);
if (!isGeyserPassableBlock(level, currentPos)) {
return i;
}
}
return geyserForceHeight;
}
private static boolean isGeyserPassableBlock(LevelAccessor level, BlockPos pos) {
BlockState state = level.getBlockState(pos);
FluidState fluidState = level.getFluidState(pos);
return state.isAir()
|| (fluidState.isSource() && isHypnoticGasFluid(fluidState))
|| state.getCollisionShape(level, pos).isEmpty();
}
private static boolean isHypnoticGasFluid(FluidState fluidState) {
return PotentNyxiteBlock.isAntiwater(fluidState);
}
private static boolean haveLineOfSight(Level level, Vec3 from, Vec3 to) {
HitResult hitResult = level.clip(new ClipContext(from, to, ClipContext.Block.VISUAL, ClipContext.Fluid.NONE, net.minecraft.world.phys.shapes.CollisionContext.empty()));
return hitResult.getType() != HitResult.Type.BLOCK;
}
private static SimpleParticleType simpleParticle(ResourceLocation id) {
return (SimpleParticleType) BuiltInRegistries.PARTICLE_TYPE.get(id);
}
@SuppressWarnings("unchecked")
private static ParticleType<InvertedGeyserParticleOptions> geyserParticleType(ResourceLocation id) {
return (ParticleType<InvertedGeyserParticleOptions>) BuiltInRegistries.PARTICLE_TYPE.get(id);
}
}
@@ -0,0 +1,213 @@
package com.craisinlord.antarchy.content.block.entity;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.block.WaspNestBlock;
import com.craisinlord.antarchy.content.entity.WaspEntity;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
public class WaspNestBlockEntity extends BlockEntity {
private static final String STORED_WASPS = "StoredWasps";
private static final String PANDA_VARIANT = "PandaVariant";
private static final int PANDA_VARIANT_CHANCE = 20;
private final List<StoredWasp> storedWasps = new ArrayList<>();
private int releaseCooldown = 100;
private boolean initialized = false;
private boolean pandaVariant;
public WaspNestBlockEntity(BlockPos pos, BlockState blockState) {
super(AntarchyObjects.WASP_NEST_BLOCK_ENTITY.get(), pos, blockState);
}
public static void serverTick(ServerLevel level, BlockPos pos, BlockState state, WaspNestBlockEntity nest) {
if (!nest.initialized) {
nest.populateInitialWasps(level);
}
if (level.isNight() || level.isRaining()) {
return;
}
if (nest.storedWasps.isEmpty()) {
return;
}
if (--nest.releaseCooldown > 0) {
return;
}
nest.releaseCooldown = 80 + level.random.nextInt(100);
nest.releaseOne(level);
}
public void populateInitialWasps(ServerLevel level) {
if (this.initialized) {
return;
}
this.initialized = true;
if (!this.nestBlock().shouldPopulateInitialWasps()) {
return;
}
this.pandaVariant = level.random.nextInt(PANDA_VARIANT_CHANCE) == 0;
int amount = 1 + level.random.nextInt(3);
for (int i = 0; i < amount && this.storedWasps.size() < this.maxOccupants(); i++) {
this.storedWasps.add(this.createStoredWasp(level, this.nestBlock().waspType()));
}
this.setChanged();
}
public boolean tryStoreWasp(WaspEntity waspEntity) {
if (this.storedWasps.size() >= this.maxOccupants()) {
return false;
}
waspEntity.setPandaVariant(this.pandaVariant);
CompoundTag waspTag = new CompoundTag();
waspEntity.addAdditionalSaveData(waspTag);
this.storedWasps.add(new StoredWasp(waspEntity.getType(), waspTag));
this.releaseCooldown = Math.max(this.releaseCooldown, 200);
waspEntity.discard();
this.setChanged();
return true;
}
public void releaseAll(ServerLevel level) {
while (!this.storedWasps.isEmpty()) {
this.releaseOne(level);
}
}
private void releaseOne(ServerLevel level) {
if (this.storedWasps.isEmpty()) {
return;
}
StoredWasp storedWasp = this.storedWasps.get(0);
WaspEntity waspEntity = storedWasp.create(level);
if (waspEntity == null) {
this.storedWasps.remove(0);
return;
}
BlockPos spawnPos = this.findReleasePos(level);
if (spawnPos == null) {
this.storedWasps.remove(0);
this.setChanged();
return;
}
waspEntity.moveTo(
spawnPos.getX() + 0.5D,
spawnPos.getY() + 0.05D,
spawnPos.getZ() + 0.5D,
level.random.nextFloat() * 360.0F,
0.0F
);
waspEntity.setHivePos(this.getBlockPos());
if (!level.noCollision(waspEntity)) {
this.storedWasps.remove(0);
this.setChanged();
return;
}
this.storedWasps.remove(0);
level.addFreshEntity(waspEntity);
this.setChanged();
}
private int maxOccupants() {
return this.nestBlock().maxOccupants();
}
private WaspNestBlock nestBlock() {
return (WaspNestBlock) this.getBlockState().getBlock();
}
private BlockPos findReleasePos(ServerLevel level) {
Direction facing = this.getBlockState().getValue(WaspNestBlock.FACING);
BlockPos front = this.getBlockPos().relative(facing);
if (level.getBlockState(front).canBeReplaced() && level.getBlockState(front.above()).canBeReplaced()) {
return front;
}
BlockPos above = this.getBlockPos().above();
if (level.getBlockState(above).canBeReplaced() && level.getBlockState(above.above()).canBeReplaced()) {
return above;
}
return null;
}
private StoredWasp createStoredWasp(ServerLevel level, EntityType<?> waspType) {
if (!(waspType.create(level) instanceof WaspEntity waspEntity)) {
return new StoredWasp(waspType, new CompoundTag());
}
waspEntity.setPandaVariant(this.pandaVariant);
CompoundTag waspTag = new CompoundTag();
waspEntity.addAdditionalSaveData(waspTag);
return new StoredWasp(waspType, waspTag);
}
@Override
protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.saveAdditional(tag, registries);
tag.putBoolean("Initialized", this.initialized);
tag.putBoolean(PANDA_VARIANT, this.pandaVariant);
ListTag listTag = new ListTag();
for (StoredWasp storedWasp : this.storedWasps) {
listTag.add(storedWasp.save());
}
tag.put(STORED_WASPS, listTag);
}
@Override
protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.loadAdditional(tag, registries);
this.initialized = tag.getBoolean("Initialized");
this.pandaVariant = tag.getBoolean(PANDA_VARIANT);
this.storedWasps.clear();
ListTag listTag = tag.getList(STORED_WASPS, Tag.TAG_COMPOUND);
for (int i = 0; i < listTag.size(); i++) {
this.storedWasps.add(StoredWasp.load(listTag.getCompound(i)));
}
}
private record StoredWasp(EntityType<?> waspType, CompoundTag data) {
private CompoundTag save() {
CompoundTag tag = new CompoundTag();
tag.putString("id", BuiltInRegistries.ENTITY_TYPE.getKey(this.waspType).toString());
tag.put("data", this.data.copy());
return tag;
}
private static StoredWasp load(CompoundTag tag) {
EntityType<?> waspType = BuiltInRegistries.ENTITY_TYPE.getOptional(ResourceLocation.parse(tag.getString("id")))
.orElse(AntarchyObjects.WASP.get());
return new StoredWasp(waspType, tag.getCompound("data"));
}
private WaspEntity create(ServerLevel level) {
if (!(this.waspType.create(level) instanceof WaspEntity waspEntity)) {
return null;
}
waspEntity.readAdditionalSaveData(this.data.copy());
return waspEntity;
}
}
}
@@ -0,0 +1,22 @@
package com.craisinlord.antarchy.content.block.state;
import net.minecraft.util.StringRepresentable;
public enum PotentNyxiteState implements StringRepresentable {
DRY("dry"),
WET("wet"),
DORMANT("dormant"),
ERUPTING("erupting"),
CONTINUOUS("continuous");
private final String serializedName;
PotentNyxiteState(String serializedName) {
this.serializedName = serializedName;
}
@Override
public String getSerializedName() {
return this.serializedName;
}
}
@@ -0,0 +1,26 @@
package com.craisinlord.antarchy.content.bloodglass;
public interface BloodglassAccess {
int antarchy$getArmorShieldsActive();
void antarchy$setArmorShieldsActive(int count);
int antarchy$getArmorShieldLostCount();
void antarchy$setArmorShieldLostCount(int count);
int antarchy$getArmorRechargeTimer();
void antarchy$setArmorRechargeTimer(int ticks);
int antarchy$getAppleShieldsActive();
void antarchy$setAppleShieldsActive(int count);
int antarchy$getAppleShieldLostCount();
void antarchy$setAppleShieldLostCount(int count);
int antarchy$getAppleRechargeTimer();
void antarchy$setAppleRechargeTimer(int ticks);
default int antarchy$getTotalShieldsActive() {
return antarchy$getArmorShieldsActive() + antarchy$getAppleShieldsActive();
}
default int antarchy$getTotalShieldsMax() {
return antarchy$getArmorShieldsActive() + antarchy$getArmorShieldLostCount()
+ antarchy$getAppleShieldsActive() + antarchy$getAppleShieldLostCount();
}
}
@@ -0,0 +1,40 @@
package com.craisinlord.antarchy.content.client;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public final class BloodCrystalKatanaTrailClientState {
private static final Map<Integer, Integer> ACTIVE = new HashMap<>();
private BloodCrystalKatanaTrailClientState() {}
public static void trigger(int entityId, int durationTicks) {
if (durationTicks <= 0) {
ACTIVE.remove(entityId);
return;
}
ACTIVE.put(entityId, durationTicks);
}
public static int getRemainingTicks(int entityId) {
return ACTIVE.getOrDefault(entityId, 0);
}
public static void tick() {
Iterator<Map.Entry<Integer, Integer>> iterator = ACTIVE.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Integer, Integer> entry = iterator.next();
int remaining = entry.getValue() - 1;
if (remaining <= 0) {
iterator.remove();
} else {
entry.setValue(remaining);
}
}
}
public static void clear() {
ACTIVE.clear();
}
}
@@ -0,0 +1,16 @@
package com.craisinlord.antarchy.content.client;
public final class BloodglassClientState {
private BloodglassClientState() {}
private static int shieldsActive = 0;
private static int shieldsMax = 0;
public static void update(int active, int max) {
shieldsActive = active;
shieldsMax = max;
}
public static int getShieldsActive() { return shieldsActive; }
public static int getShieldsMax() { return shieldsMax; }
}
@@ -0,0 +1,54 @@
package com.craisinlord.antarchy.content.client;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.util.Mth;
public final class BrutalflyElytraClientState {
private static final Map<Integer, AnimationState> ACTIVE_ANIMATIONS = new ConcurrentHashMap<>();
private BrutalflyElytraClientState() {
}
public static void trigger(int entityId, int durationTicks, float strength) {
if (durationTicks <= 0) {
ACTIVE_ANIMATIONS.remove(entityId);
return;
}
ACTIVE_ANIMATIONS.put(entityId, new AnimationState(durationTicks, durationTicks, strength));
}
public static AnimationState get(int entityId) {
return ACTIVE_ANIMATIONS.get(entityId);
}
public static void tick() {
ACTIVE_ANIMATIONS.entrySet().removeIf(entry -> entry.getValue().tick() <= 0);
}
public static final class AnimationState {
private final int durationTicks;
private int remainingTicks;
private final float strength;
private AnimationState(int durationTicks, int remainingTicks, float strength) {
this.durationTicks = Math.max(1, durationTicks);
this.remainingTicks = Math.max(0, remainingTicks);
this.strength = strength;
}
public float progress(float partialTick) {
float remaining = Mth.clamp(this.remainingTicks - partialTick, 0.0F, (float) this.durationTicks);
return 1.0F - remaining / (float) this.durationTicks;
}
public float strength() {
return this.strength;
}
private int tick() {
this.remainingTicks--;
return this.remainingTicks;
}
}
}
@@ -0,0 +1,27 @@
package com.craisinlord.antarchy.content.client;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public final class ScorpionWhipTetherClientState {
private static final Map<Integer, Integer> TETHERS = new ConcurrentHashMap<>();
private ScorpionWhipTetherClientState() {
}
public static void update(int playerId, int targetId) {
if (targetId < 0) {
TETHERS.remove(playerId);
} else {
TETHERS.put(playerId, targetId);
}
}
public static Map<Integer, Integer> snapshot() {
return Map.copyOf(TETHERS);
}
public static void clear() {
TETHERS.clear();
}
}
@@ -0,0 +1,46 @@
package com.craisinlord.antarchy.content.client;
import com.craisinlord.antarchy.content.weather.ThoraxisWeatherKind;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.Level;
public final class ThoraxisWeatherClientState {
private static final Map<ResourceLocation, ThoraxisWeatherState> STATES = new HashMap<>();
private ThoraxisWeatherClientState() {
}
public static void apply(ResourceLocation dimension, ThoraxisWeatherKind kind, long expiresAt, int anchorX, int anchorY, int anchorZ) {
if (kind == ThoraxisWeatherKind.NONE) {
STATES.remove(dimension);
return;
}
STATES.put(dimension, new ThoraxisWeatherState(kind, expiresAt, new BlockPos(anchorX, anchorY, anchorZ)));
}
public static ThoraxisWeatherState current(Level level) {
if (level == null) {
return null;
}
ThoraxisWeatherState state = STATES.get(level.dimension().location());
if (state == null) {
return null;
}
long now = level.getGameTime();
if (state.expiresAt > 0L && now > state.expiresAt) {
STATES.remove(level.dimension().location());
return null;
}
return state;
}
public record ThoraxisWeatherState(ThoraxisWeatherKind kind, long expiresAt, BlockPos anchor) {
}
}
@@ -0,0 +1,57 @@
package com.craisinlord.antarchy.content.client.hud;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.client.BloodglassClientState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.player.Player;
public final class BloodglassHudRenderer {
private static final ResourceLocation HEART_CONTAINER =
ResourceLocation.withDefaultNamespace("textures/gui/sprites/hud/heart/container.png");
private static final ResourceLocation HEART_FULL =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/gui/sprites/hud/bloodglass_heart.png");
private static final ResourceLocation HEART_CRACKED =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/gui/sprites/hud/bloodglass_heart_cracked.png");
private static final int HEART_SIZE = 9;
private static final int HEART_PITCH = 8;
private BloodglassHudRenderer() {}
public static void render(GuiGraphics gui) {
Minecraft mc = Minecraft.getInstance();
if (mc.options.hideGui) return;
Player player = mc.player;
if (player == null || player.isDeadOrDying()) return;
if (player.isCreative() || player.isSpectator()) return;
int total = BloodglassClientState.getShieldsMax();
if (total <= 0) return;
int active = BloodglassClientState.getShieldsActive();
int w = mc.getWindow().getGuiScaledWidth();
int h = mc.getWindow().getGuiScaledHeight();
int maxHealth = Mth.ceil(player.getMaxHealth());
int absorption = Mth.ceil(player.getAbsorptionAmount());
int healthHearts = Mth.ceil(maxHealth / 2.0f);
int absorptionHearts = Mth.ceil(absorption / 2.0f);
int totalVanillaRows = Mth.ceil((healthHearts + absorptionHearts) / 10.0f);
boolean hasArmor = player.getArmorValue() > 0;
int baseTop = h - 39 - (totalVanillaRows * 10) - (hasArmor ? 10 : 0);
int left = w / 2 - 91;
for (int i = 0; i < total; i++) {
int row = i / 10;
int col = i % 10;
int x = left + col * HEART_PITCH;
int y = baseTop - row * 10;
ResourceLocation tex = (i < active) ? HEART_FULL : HEART_CRACKED;
gui.blit(HEART_CONTAINER, x, y, 0, 0, HEART_SIZE, HEART_SIZE, HEART_SIZE, HEART_SIZE);
gui.blit(tex, x, y, 0, 0, HEART_SIZE, HEART_SIZE, HEART_SIZE, HEART_SIZE);
}
}
}
@@ -0,0 +1,41 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.ant.BaseAntEntity;
import com.craisinlord.antarchy.content.entity.ant.BrownAntEntity;
import com.craisinlord.antarchy.content.entity.ant.RainbowAntEntity;
import com.craisinlord.antarchy.content.entity.ant.RedAntEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class AntModel extends GeoModel<BaseAntEntity> {
private static final ResourceLocation MODEL = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/ant.geo.json");
private static final ResourceLocation ANIMATIONS = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/ant.animation.json");
private static final ResourceLocation BROWN_TEXTURE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/brown_ant.png");
private static final ResourceLocation RED_TEXTURE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/red_ant.png");
private static final ResourceLocation RAINBOW_TEXTURE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/rainbow_ant.png");
@Override
public ResourceLocation getModelResource(BaseAntEntity animatable) {
return MODEL;
}
@Override
public ResourceLocation getTextureResource(BaseAntEntity animatable) {
if (animatable instanceof RedAntEntity) {
return RED_TEXTURE;
}
if (animatable instanceof RainbowAntEntity) {
return RAINBOW_TEXTURE;
}
if (animatable instanceof BrownAntEntity) {
return BROWN_TEXTURE;
}
return BROWN_TEXTURE;
}
@Override
public ResourceLocation getAnimationResource(BaseAntEntity animatable) {
return ANIMATIONS;
}
}
@@ -0,0 +1,70 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.AppleCowEntity;
import com.craisinlord.antarchy.content.entity.AppleCowEntityVariants.EnchantedGoldenAppleCow;
import com.craisinlord.antarchy.content.entity.AppleCowEntityVariants.GoldenAppleCow;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class AppleCowModel extends GeoModel<AppleCowEntity> {
private static final ResourceLocation MODEL =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/apple_cow.geo.json");
private static final ResourceLocation BABY_MODEL =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/baby_apple_cow.geo.json");
private static final ResourceLocation ANIMATION =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/apple_cow.animation.json");
private static final ResourceLocation BABY_ANIMATION =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/baby_apple_cow.animation.json");
private static final ResourceLocation APPLE_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/apple_cow/apple_cow.png");
private static final ResourceLocation APPLE_SHEARED_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/apple_cow/apple_cow_sheared.png");
private static final ResourceLocation BABY_APPLE_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/apple_cow/baby_apple_cow.png");
private static final ResourceLocation GOLDEN_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/apple_cow/golden_apple_cow.png");
private static final ResourceLocation GOLDEN_SHEARED_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/apple_cow/golden_apple_cow_sheared.png");
private static final ResourceLocation BABY_GOLDEN_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/apple_cow/baby_golden_apple_cow.png");
private static final ResourceLocation ENCHANTED_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/apple_cow/enchanted_golden_apple_cow.png");
private static final ResourceLocation ENCHANTED_SHEARED_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/apple_cow/enchanted_golden_apple_cow_sheared.png");
@Override
public ResourceLocation getModelResource(AppleCowEntity animatable) {
return animatable.isBaby() ? BABY_MODEL : MODEL;
}
@Override
public ResourceLocation getTextureResource(AppleCowEntity animatable) {
return textureFor(animatable);
}
@Override
public ResourceLocation getAnimationResource(AppleCowEntity animatable) {
return animatable.isBaby() ? BABY_ANIMATION : ANIMATION;
}
public static ResourceLocation textureFor(AppleCowEntity entity) {
if (entity.isBaby()) {
if (entity instanceof EnchantedGoldenAppleCow) {
return entity.isSheared() ? ENCHANTED_SHEARED_TEXTURE : ENCHANTED_TEXTURE;
}
if (entity instanceof GoldenAppleCow) {
return entity.isSheared() ? GOLDEN_SHEARED_TEXTURE : BABY_GOLDEN_TEXTURE;
}
return entity.isSheared() ? APPLE_SHEARED_TEXTURE : BABY_APPLE_TEXTURE;
}
if (entity instanceof EnchantedGoldenAppleCow) {
return entity.isSheared() ? ENCHANTED_SHEARED_TEXTURE : ENCHANTED_TEXTURE;
}
if (entity instanceof GoldenAppleCow) {
return entity.isSheared() ? GOLDEN_SHEARED_TEXTURE : GOLDEN_TEXTURE;
}
return entity.isSheared() ? APPLE_SHEARED_TEXTURE : APPLE_TEXTURE;
}
}
@@ -0,0 +1,24 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.basilisk.BasiliskEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class BasiliskModel extends GeoModel<BasiliskEntity> {
@Override
public ResourceLocation getModelResource(BasiliskEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/basilisk.geo.json");
}
@Override
public ResourceLocation getTextureResource(BasiliskEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/basilisk.png");
}
@Override
public ResourceLocation getAnimationResource(BasiliskEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/basilisk.animation.json");
}
}
@@ -0,0 +1,23 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.BedBugEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class BedBugModel extends GeoModel<BedBugEntity> {
@Override
public ResourceLocation getModelResource(BedBugEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/bed_bug.geo.json");
}
@Override
public ResourceLocation getTextureResource(BedBugEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/bed_bug.png");
}
@Override
public ResourceLocation getAnimationResource(BedBugEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/bed_bug.animation.json");
}
}
@@ -0,0 +1,23 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.BomberEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class BomberModel extends GeoModel<BomberEntity> {
@Override
public ResourceLocation getModelResource(BomberEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/bomber.geo.json");
}
@Override
public ResourceLocation getTextureResource(BomberEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/bomber.png");
}
@Override
public ResourceLocation getAnimationResource(BomberEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/bomber.animation.json");
}
}
@@ -0,0 +1,62 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.model.geom.ModelLayerLocation;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.model.geom.PartPose;
import net.minecraft.client.model.geom.builders.CubeListBuilder;
import net.minecraft.client.model.geom.builders.LayerDefinition;
import net.minecraft.client.model.geom.builders.MeshDefinition;
import net.minecraft.client.model.geom.builders.PartDefinition;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
public final class BrutalflyElytraModel {
public static final ModelLayerLocation LAYER_LOCATION =
new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "brutalfly_elytra"), "main");
private final ModelPart root;
private final ModelPart leftWing;
private final ModelPart rightWing;
public BrutalflyElytraModel(ModelPart root) {
this.root = root;
this.leftWing = root.getChild("left_wing");
this.rightWing = root.getChild("right_wing");
}
public static LayerDefinition createBodyLayer() {
MeshDefinition meshDefinition = new MeshDefinition();
PartDefinition root = meshDefinition.getRoot();
root.addOrReplaceChild(
"left_wing",
CubeListBuilder.create().texOffs(22, 0).addBox(-10.0F, 0.0F, -1.0F, 10.0F, 20.0F, 2.0F),
PartPose.offset(5.0F, 0.0F, -1.5F)
);
root.addOrReplaceChild(
"right_wing",
CubeListBuilder.create().mirror().texOffs(22, 0).addBox(0.0F, 0.0F, -1.0F, 10.0F, 20.0F, 2.0F),
PartPose.offset(-5.0F, 0.0F, -1.5F)
);
return LayerDefinition.create(meshDefinition, 64, 32);
}
public void setupAnimation(float progress, float strength, boolean crouching) {
float wave = Mth.sin(progress * Mth.PI);
float flap = wave * strength;
float basePitch = crouching ? -0.18F : -0.05F;
float wingSpread = 0.55F;
this.leftWing.xRot = basePitch - flap * 1.2F;
this.rightWing.xRot = basePitch - flap * 1.2F;
this.leftWing.yRot = -wingSpread;
this.rightWing.yRot = -wingSpread;
this.leftWing.zRot = -0.35F - flap * 0.7F;
this.rightWing.zRot = -0.35F - flap * 0.7F;
}
public void renderToBuffer(PoseStack poseStack, VertexConsumer consumer, int packedLight, int overlay) {
this.root.render(poseStack, consumer, packedLight, overlay);
}
}
@@ -0,0 +1,23 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.brutalfly.BrutalflyEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class BrutalflyModel extends GeoModel<BrutalflyEntity> {
@Override
public ResourceLocation getModelResource(BrutalflyEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/brutalfly.geo.json");
}
@Override
public ResourceLocation getTextureResource(BrutalflyEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/brutalfly.png");
}
@Override
public ResourceLocation getAnimationResource(BrutalflyEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/brutalfly.animation.json");
}
}
@@ -0,0 +1,28 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.ButterflyEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class ButterflyModel extends GeoModel<ButterflyEntity> {
private static final String TEXTURE_PATH_PREFIX = "textures/entity/butterfly/butterfly_";
@Override
public ResourceLocation getModelResource(ButterflyEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/butterfly.geo.json");
}
@Override
public ResourceLocation getTextureResource(ButterflyEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(
Antarchy.MODID,
TEXTURE_PATH_PREFIX + animatable.getTextureVariantName() + ".png"
);
}
@Override
public ResourceLocation getAnimationResource(ButterflyEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/butterfly.animation.json");
}
}
@@ -0,0 +1,23 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.CaterpillarEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class CaterpillarModel extends GeoModel<CaterpillarEntity> {
@Override
public ResourceLocation getModelResource(CaterpillarEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/caterpillar.geo.json");
}
@Override
public ResourceLocation getTextureResource(CaterpillarEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/caterpillar.png");
}
@Override
public ResourceLocation getAnimationResource(CaterpillarEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/caterpillar.animation.json");
}
}
@@ -0,0 +1,23 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.cloud_shark.CloudSharkEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class CloudSharkModel extends GeoModel<CloudSharkEntity> {
@Override
public ResourceLocation getModelResource(CloudSharkEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/cloud_shark.geo.json");
}
@Override
public ResourceLocation getTextureResource(CloudSharkEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/cloud_shark.png");
}
@Override
public ResourceLocation getAnimationResource(CloudSharkEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/cloud_shark.animation.json");
}
}
@@ -0,0 +1,23 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.EasterBunnyEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class EasterBunnyModel extends GeoModel<EasterBunnyEntity> {
@Override
public ResourceLocation getModelResource(EasterBunnyEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/easter_bunny.geo.json");
}
@Override
public ResourceLocation getTextureResource(EasterBunnyEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/easter_bunny.png");
}
@Override
public ResourceLocation getAnimationResource(EasterBunnyEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/easter_bunny.animation.json");
}
}
@@ -0,0 +1,24 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.EmperorScorpionEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class EmperorScorpionModel extends GeoModel<EmperorScorpionEntity> {
@Override
public ResourceLocation getModelResource(EmperorScorpionEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/emperor_scorpion.geo.json");
}
@Override
public ResourceLocation getTextureResource(EmperorScorpionEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/emperor_scorpion.png");
}
@Override
public ResourceLocation getAnimationResource(EmperorScorpionEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/emperor_scorpion.animation.json");
}
}
@@ -0,0 +1,67 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.content.entity.flying_squirrel.FlyingSquirrelEntity;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
import software.bernie.geckolib.animation.AnimationState;
import software.bernie.geckolib.cache.object.GeoBone;
import software.bernie.geckolib.model.GeoModel;
public class FlyingSquirrelModel extends GeoModel<FlyingSquirrelEntity> {
private static final ResourceLocation REGULAR_TEXTURE = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/flying_squirrel/flying_squirrel.png");
private static final ResourceLocation BROWN_TEXTURE = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/flying_squirrel/flying_squirrel_brown.png");
private static final ResourceLocation ALBINO_TEXTURE = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/flying_squirrel/flying_squirrel_albino.png");
private static final float SHOULDER_BODY_ROT_X = 65.0F * Mth.DEG_TO_RAD;
private static final float SHOULDER_LEFT_ARM_ROT_Z = 0.0F;
private static final float SHOULDER_RIGHT_ARM_ROT_Z = 0.0F;
private static final float SHOULDER_TAIL_ROT_X = 42.5F * Mth.DEG_TO_RAD;
private static final float SHOULDER_HEAD_ROT_X = -60.0F * Mth.DEG_TO_RAD;
@Override
public ResourceLocation getModelResource(FlyingSquirrelEntity animatable) {
return ResourceLocation.fromNamespaceAndPath("antarchy", "geo/flying_squirrel.geo.json");
}
@Override
public ResourceLocation getTextureResource(FlyingSquirrelEntity animatable) {
return switch (animatable.getTextureVariantName()) {
case "brown" -> BROWN_TEXTURE;
case "albino" -> ALBINO_TEXTURE;
default -> REGULAR_TEXTURE;
};
}
@Override
public ResourceLocation getAnimationResource(FlyingSquirrelEntity animatable) {
return ResourceLocation.fromNamespaceAndPath("antarchy", "animations/flying_squirrel.animation.json");
}
@Override
public void setCustomAnimations(FlyingSquirrelEntity animatable, long instanceId, AnimationState<FlyingSquirrelEntity> animationState) {
super.setCustomAnimations(animatable, instanceId, animationState);
this.getBone("squirrel").ifPresent(root -> root.setScaleX(animatable.shouldMirrorIdleAnimation() ? -1.0F : 1.0F));
if (animatable.isOnShoulder()) {
this.getBone("body").ifPresent(bone -> bone.setRotX(SHOULDER_BODY_ROT_X));
this.getBone("left_arm").ifPresent(bone -> bone.setRotZ(SHOULDER_LEFT_ARM_ROT_Z));
this.getBone("right_arm").ifPresent(bone -> bone.setRotZ(SHOULDER_RIGHT_ARM_ROT_Z));
this.getBone("tail").ifPresent(bone -> bone.setRotX(SHOULDER_TAIL_ROT_X));
this.getBone("head").ifPresent(bone -> {
bone.setRotX(SHOULDER_HEAD_ROT_X);
bone.setPosY(-1.0425F);
bone.setPosZ(-1.31366F);
});
this.getBone("left_flying_part").ifPresent(FlyingSquirrelModel::hideBone);
this.getBone("right_flying_part").ifPresent(FlyingSquirrelModel::hideBone);
this.getBone("left_cheeks").ifPresent(FlyingSquirrelModel::hideBone);
this.getBone("right_cheeks").ifPresent(FlyingSquirrelModel::hideBone);
}
}
private static void hideBone(GeoBone bone) {
bone.setScaleX(0.0F);
bone.setScaleY(0.0F);
bone.setScaleZ(0.0F);
}
}
@@ -0,0 +1,24 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.content.entity.kraken.KrakenEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class KrakenModel extends GeoModel<KrakenEntity> {
@Override
public ResourceLocation getModelResource(KrakenEntity animatable) {
return ResourceLocation.fromNamespaceAndPath("antarchy", "geo/kraken.geo.json");
}
@Override
public ResourceLocation getTextureResource(KrakenEntity animatable) {
return animatable.isPhaseTwo()
? ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/kraken_purple.png")
: ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/kraken.png");
}
@Override
public ResourceLocation getAnimationResource(KrakenEntity animatable) {
return ResourceLocation.fromNamespaceAndPath("antarchy", "animations/kraken.animation.json");
}
}
@@ -0,0 +1,24 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.lucid.LucidEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class LucidModel extends GeoModel<LucidEntity> {
@Override
public ResourceLocation getModelResource(LucidEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/lucid.geo.json");
}
@Override
public ResourceLocation getTextureResource(LucidEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/lucid.png");
}
@Override
public ResourceLocation getAnimationResource(LucidEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/lucid.animation.json");
}
}
@@ -0,0 +1,23 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.MantisEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class MantisModel extends GeoModel<MantisEntity> {
@Override
public ResourceLocation getModelResource(MantisEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/mantis.geo.json");
}
@Override
public ResourceLocation getTextureResource(MantisEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/mantis.png");
}
@Override
public ResourceLocation getAnimationResource(MantisEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/mantis.animation.json");
}
}
@@ -0,0 +1,22 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.content.entity.MissileSquidEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class MissileSquidModel extends GeoModel<MissileSquidEntity> {
@Override
public ResourceLocation getModelResource(MissileSquidEntity animatable) {
return ResourceLocation.fromNamespaceAndPath("antarchy", "geo/missile_squid.geo.json");
}
@Override
public ResourceLocation getTextureResource(MissileSquidEntity animatable) {
return ResourceLocation.fromNamespaceAndPath("antarchy", "textures/entity/missile_squid.png");
}
@Override
public ResourceLocation getAnimationResource(MissileSquidEntity animatable) {
return ResourceLocation.fromNamespaceAndPath("antarchy", "animations/missile_squid.animation.json");
}
}
@@ -0,0 +1,27 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.MolevoreEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class MolevoreModel extends GeoModel<MolevoreEntity> {
private static final ResourceLocation MODEL = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/molevore.geo.json");
private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/molevore.png");
private static final ResourceLocation ANIMATION = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/molevore.animation.json");
@Override
public ResourceLocation getModelResource(MolevoreEntity animatable) {
return MODEL;
}
@Override
public ResourceLocation getTextureResource(MolevoreEntity animatable) {
return TEXTURE;
}
@Override
public ResourceLocation getAnimationResource(MolevoreEntity animatable) {
return ANIMATION;
}
}
@@ -0,0 +1,27 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.MolewormEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class MolewormModel extends GeoModel<MolewormEntity> {
private static final ResourceLocation MODEL = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/moleworm.geo.json");
private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/moleworm.png");
private static final ResourceLocation ANIMATION = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/moleworm.animation.json");
@Override
public ResourceLocation getModelResource(MolewormEntity animatable) {
return MODEL;
}
@Override
public ResourceLocation getTextureResource(MolewormEntity animatable) {
return TEXTURE;
}
@Override
public ResourceLocation getAnimationResource(MolewormEntity animatable) {
return ANIMATION;
}
}
@@ -0,0 +1,23 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.nightmare.NightmareEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class NightmareModel extends GeoModel<NightmareEntity> {
@Override
public ResourceLocation getModelResource(NightmareEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/nightmare.geo.json");
}
@Override
public ResourceLocation getTextureResource(NightmareEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/nightmare.png");
}
@Override
public ResourceLocation getAnimationResource(NightmareEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/nightmare.animation.json");
}
}
@@ -0,0 +1,33 @@
package com.craisinlord.antarchy.content.client.model;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import software.bernie.geckolib.animatable.GeoAnimatable;
import software.bernie.geckolib.model.GeoModel;
public class ResourceBackedGeoItemModel<T extends Item & GeoAnimatable> extends GeoModel<T> {
private final ResourceLocation modelLocation;
private final ResourceLocation textureLocation;
private final ResourceLocation animationLocation;
public ResourceBackedGeoItemModel(ResourceLocation modelLocation, ResourceLocation textureLocation, ResourceLocation animationLocation) {
this.modelLocation = modelLocation;
this.textureLocation = textureLocation;
this.animationLocation = animationLocation;
}
@Override
public ResourceLocation getModelResource(T animatable) {
return this.modelLocation;
}
@Override
public ResourceLocation getTextureResource(T animatable) {
return this.textureLocation;
}
@Override
public ResourceLocation getAnimationResource(T animatable) {
return this.animationLocation;
}
}
@@ -0,0 +1,45 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.ReverieEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class ReverieModel extends GeoModel<ReverieEntity> {
private static final ResourceLocation WHITE_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/reverie/reverie_white.png");
private static final ResourceLocation YELLOW_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/reverie/reverie_yellow.png");
private static final ResourceLocation BLUE_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/reverie/reverie_blue.png");
private static final ResourceLocation PURPLE_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/reverie/reverie_purple.png");
private static final ResourceLocation RED_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/reverie/reverie_red.png");
@Override
public ResourceLocation getModelResource(ReverieEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/reverie.geo.json");
}
@Override
public ResourceLocation getTextureResource(ReverieEntity animatable) {
return textureForMood(animatable.getMood());
}
@Override
public ResourceLocation getAnimationResource(ReverieEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/reverie.animation.json");
}
public static ResourceLocation textureForMood(ReverieEntity.Mood mood) {
return switch (mood) {
case WHITE -> WHITE_TEXTURE;
case YELLOW -> YELLOW_TEXTURE;
case BLUE -> BLUE_TEXTURE;
case PURPLE -> PURPLE_TEXTURE;
case RED -> RED_TEXTURE;
default -> WHITE_TEXTURE;
};
}
}
@@ -0,0 +1,24 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.ScorpionEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class ScorpionModel extends GeoModel<ScorpionEntity> {
@Override
public ResourceLocation getModelResource(ScorpionEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/scorpion.geo.json");
}
@Override
public ResourceLocation getTextureResource(ScorpionEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/scorpion.png");
}
@Override
public ResourceLocation getAnimationResource(ScorpionEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/scorpion.animation.json");
}
}
@@ -0,0 +1,27 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.TriffidEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class TriffidModel extends GeoModel<TriffidEntity> {
private static final ResourceLocation MODEL = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/triffid.geo.json");
private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/triffid.png");
private static final ResourceLocation ANIMATION = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/triffid.animation.json");
@Override
public ResourceLocation getModelResource(TriffidEntity animatable) {
return MODEL;
}
@Override
public ResourceLocation getTextureResource(TriffidEntity animatable) {
return TEXTURE;
}
@Override
public ResourceLocation getAnimationResource(TriffidEntity animatable) {
return ANIMATION;
}
}
@@ -0,0 +1,28 @@
package com.craisinlord.antarchy.content.client.model;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.WaspEntity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class WaspModel extends GeoModel<WaspEntity> {
private static final ResourceLocation DEFAULT_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/wasp.png");
private static final ResourceLocation PANDA_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/wasp_panda.png");
@Override
public ResourceLocation getModelResource(WaspEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/wasp.geo.json");
}
@Override
public ResourceLocation getTextureResource(WaspEntity animatable) {
return animatable.isPandaVariant() ? PANDA_TEXTURE : DEFAULT_TEXTURE;
}
@Override
public ResourceLocation getAnimationResource(WaspEntity animatable) {
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/wasp.animation.json");
}
}
@@ -0,0 +1,49 @@
package com.craisinlord.antarchy.content.client.particle;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.ParticleProvider;
import net.minecraft.client.particle.ParticleRenderType;
import net.minecraft.client.particle.SpriteSet;
import net.minecraft.client.particle.TextureSheetParticle;
import net.minecraft.core.particles.SimpleParticleType;
public final class DreamFlameParticle extends TextureSheetParticle {
private final SpriteSet sprites;
protected DreamFlameParticle(ClientLevel level, double x, double y, double z, double xd, double yd, double zd, SpriteSet sprites) {
super(level, x, y, z, xd, yd, zd);
this.sprites = sprites;
this.friction = 0.96F;
this.xd = xd * 0.01D;
this.yd = yd * 0.01D;
this.zd = zd * 0.01D;
this.quadSize *= 1.25F;
this.lifetime = 8 + this.random.nextInt(4);
this.pickSprite(sprites);
}
@Override
public void tick() {
super.tick();
this.pickSprite(this.sprites);
}
@Override
public ParticleRenderType getRenderType() {
return ParticleRenderType.PARTICLE_SHEET_TRANSLUCENT;
}
public static final class Provider implements ParticleProvider<SimpleParticleType> {
private final SpriteSet sprites;
public Provider(SpriteSet sprites) {
this.sprites = sprites;
}
@Override
public Particle createParticle(SimpleParticleType type, ClientLevel level, double x, double y, double z, double xd, double yd, double zd) {
return new DreamFlameParticle(level, x, y, z, xd, yd, zd, this.sprites);
}
}
}
@@ -0,0 +1,85 @@
package com.craisinlord.antarchy.content.client.particle;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.ParticleProvider;
import net.minecraft.client.particle.ParticleRenderType;
import net.minecraft.client.particle.SpriteSet;
import net.minecraft.client.particle.TextureSheetParticle;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.core.particles.SimpleParticleType;
import net.minecraft.util.Mth;
public final class FireflyParticle extends TextureSheetParticle {
private static final int FADE_TICKS = 8;
private FireflyParticle(ClientLevel level, double x, double y, double z, SpriteSet sprites) {
super(level, x, y, z, 0.0, 0.0, 0.0);
this.setSprite(sprites.get(0, 1));
this.lifetime = 30 + this.random.nextInt(78);
this.quadSize = 0.10F + this.random.nextFloat() * 0.04F;
this.setColor(0.92F, 0.98F, 0.45F);
this.setAlpha(0.0F);
this.yd = 0.004 + this.random.nextDouble() * 0.003;
this.xd = (this.random.nextDouble() - 0.5) * 0.008;
this.zd = (this.random.nextDouble() - 0.5) * 0.008;
this.hasPhysics = false;
}
@Override
public void tick() {
this.xo = this.x;
this.yo = this.y;
this.zo = this.z;
if (this.age >= this.lifetime) {
this.remove();
return;
}
float bobOffset = Mth.sin(this.age * 0.18F) * 0.006F;
this.xd += bobOffset;
this.zd -= bobOffset;
this.xd *= 0.94;
this.yd *= 0.98;
this.zd *= 0.94;
this.move(this.xd, this.yd, this.zd);
float alpha;
if (this.age < FADE_TICKS) {
alpha = (float) this.age / FADE_TICKS;
} else if (this.age > this.lifetime - FADE_TICKS) {
alpha = (float) (this.lifetime - this.age) / FADE_TICKS;
} else {
alpha = 1.0F;
}
this.setAlpha(alpha * 0.85F);
this.age++;
}
@Override
public int getLightColor(float partialTick) {
return LightTexture.FULL_BRIGHT;
}
@Override
public ParticleRenderType getRenderType() {
return ParticleRenderType.PARTICLE_SHEET_TRANSLUCENT;
}
public static final class Provider implements ParticleProvider<SimpleParticleType> {
private final SpriteSet sprites;
public Provider(SpriteSet sprites) {
this.sprites = sprites;
}
@Override
public Particle createParticle(SimpleParticleType type, ClientLevel level, double x, double y, double z, double xd, double yd, double zd) {
return new FireflyParticle(level, x, y, z, this.sprites);
}
}
}
@@ -0,0 +1,51 @@
package com.craisinlord.antarchy.content.client.particle;
import com.craisinlord.antarchy.content.block.entity.PotentNyxiteBlockEntity;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.particle.NoRenderParticle;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.ParticleProvider;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.SimpleParticleType;
import net.minecraft.world.phys.Vec3;
public final class HypnoticGasCloudParticle extends NoRenderParticle {
private final boolean flipped;
public HypnoticGasCloudParticle(ClientLevel level, double x, double y, double z, boolean flipped) {
super(level, x, y, z);
this.flipped = flipped;
this.lifetime = 20;
}
@Override
public void tick() {
super.tick();
if (this.age % 2 != 0) {
return;
}
BlockPos source = BlockPos.containing(this.x, this.y, this.z);
Vec3 spawnPoint = PotentNyxiteBlockEntity.pickRandomHypnoticGasSpawnPoint(this.level, source);
if (PotentNyxiteBlockEntity.canBeReachedByHypnoticGas(this.level, source, spawnPoint)) {
PotentNyxiteBlockEntity.spawnHypnoticGasParticle(this.level, spawnPoint, this.flipped);
}
}
public static final class Provider implements ParticleProvider<SimpleParticleType> {
private final boolean flipped;
public Provider() {
this(false);
}
public Provider(boolean flipped) {
this.flipped = flipped;
}
@Override
public Particle createParticle(SimpleParticleType type, ClientLevel level, double x, double y, double z, double xd, double yd, double zd) {
return new HypnoticGasCloudParticle(level, x, y, z, this.flipped);
}
}
}
@@ -0,0 +1,71 @@
package com.craisinlord.antarchy.content.client.particle;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.particle.BaseAshSmokeParticle;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.ParticleProvider;
import net.minecraft.client.particle.ParticleRenderType;
import net.minecraft.client.particle.SpriteSet;
import net.minecraft.core.particles.SimpleParticleType;
import net.minecraft.util.Mth;
public final class HypnoticGasParticle extends BaseAshSmokeParticle {
private final float fadeOutStartingPoint;
private HypnoticGasParticle(
ClientLevel level,
double x,
double y,
double z,
double xd,
double yd,
double zd,
float scale,
boolean flipped,
SpriteSet sprites
) {
super(level, x, y, z, 0.1F, 0.1F, 0.1F, xd, yd, zd, scale, sprites, 0.3F, 5, -0.02F, true);
this.rCol = 1.0F;
this.gCol = 1.0F;
this.bCol = 1.0F;
if (flipped) {
this.roll = Mth.PI;
this.oRoll = Mth.PI;
}
this.lifetime = (int) (6.0D / (this.random.nextFloat() * 0.5D + 0.5D) * scale);
this.fadeOutStartingPoint = this.lifetime / 2.0F;
}
@Override
public void tick() {
super.tick();
if (this.age > this.fadeOutStartingPoint) {
float agePastFadeStart = this.age - this.fadeOutStartingPoint;
this.setAlpha((this.lifetime - agePastFadeStart) / this.lifetime);
}
}
@Override
public ParticleRenderType getRenderType() {
return ParticleRenderType.PARTICLE_SHEET_TRANSLUCENT;
}
public static final class Provider implements ParticleProvider<SimpleParticleType> {
private final SpriteSet sprites;
private final boolean flipped;
public Provider(SpriteSet sprites) {
this(sprites, false);
}
public Provider(SpriteSet sprites, boolean flipped) {
this.sprites = sprites;
this.flipped = flipped;
}
@Override
public Particle createParticle(SimpleParticleType type, ClientLevel level, double x, double y, double z, double xd, double yd, double zd) {
return new HypnoticGasParticle(level, x, y, z, xd, yd, zd, 3.0F, this.flipped, this.sprites);
}
}
}
@@ -0,0 +1,77 @@
package com.craisinlord.antarchy.content.client.particle;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.particle.BaseAshSmokeParticle;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.ParticleProvider;
import net.minecraft.client.particle.SpriteSet;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
public final class InvertedGeyserBaseParticle extends BaseAshSmokeParticle {
protected InvertedGeyserBaseParticle(
ClientLevel level,
double x,
double y,
double z,
double xd,
double yd,
double zd,
float scale,
float lifetimeScale,
Direction direction,
SpriteSet sprites
) {
super(level, x, y, z, scale, scale, scale, xd, yd, zd, lifetimeScale, sprites, 0.0F, 0, 0.0F, true);
this.friction = 0.725F;
this.rCol = 1.0F;
this.gCol = 1.0F;
this.bCol = 1.0F;
if (direction == Direction.DOWN) {
this.roll = Mth.PI;
this.oRoll = Mth.PI;
}
this.yd = Math.abs(this.yd) * direction.getStepY();
float lifetimeFactor = 0.8F + 0.2F * level.getRandom().nextFloat();
this.lifetime = (int) (25.0F * lifetimeFactor);
}
public static final class Provider implements ParticleProvider<InvertedGeyserBaseParticleOptions> {
private final SpriteSet sprites;
public Provider(SpriteSet sprites) {
this.sprites = sprites;
}
@Override
public Particle createParticle(
InvertedGeyserBaseParticleOptions options,
ClientLevel level,
double x,
double y,
double z,
double xd,
double yd,
double zd
) {
double shiftedX = x + (level.getRandom().nextFloat() - 0.5F) * 0.5F;
double shiftedY = y + (level.getRandom().nextFloat() - 0.5F) * 0.5F + 0.2D * options.direction().getStepY();
double shiftedZ = z + (level.getRandom().nextFloat() - 0.5F) * 0.5F;
float scale = options.burstImpulseBase() + 0.25F + options.fluidBlocks();
float lifetimeScale = 3.0F + 0.125F * options.fluidBlocks();
return new InvertedGeyserBaseParticle(
level,
shiftedX,
shiftedY,
shiftedZ,
xd,
yd,
zd,
scale,
lifetimeScale,
options.direction(),
this.sprites
);
}
}
}
@@ -0,0 +1,62 @@
package com.craisinlord.antarchy.content.client.particle;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.netty.buffer.ByteBuf;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleType;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.util.ExtraCodecs;
public record InvertedGeyserBaseParticleOptions(
ParticleType<InvertedGeyserBaseParticleOptions> type,
int fluidBlocks,
float burstImpulseBase,
Direction direction
) implements ParticleOptions {
private static final Codec<Direction> VERTICAL_DIRECTION_CODEC = Codec.STRING.xmap(
name -> "down".equals(name) ? Direction.DOWN : Direction.UP,
Direction::getName
);
private static final StreamCodec<ByteBuf, Direction> VERTICAL_DIRECTION_STREAM_CODEC =
ByteBufCodecs.STRING_UTF8.map(
name -> "down".equals(name) ? Direction.DOWN : Direction.UP,
Direction::getName
);
public static MapCodec<InvertedGeyserBaseParticleOptions> codec(ParticleType<InvertedGeyserBaseParticleOptions> type) {
return RecordCodecBuilder.mapCodec(instance -> instance.group(
ExtraCodecs.POSITIVE_INT.fieldOf("fluid_blocks").forGetter(InvertedGeyserBaseParticleOptions::fluidBlocks),
Codec.FLOAT.fieldOf("burst_impulse_base").forGetter(InvertedGeyserBaseParticleOptions::burstImpulseBase),
VERTICAL_DIRECTION_CODEC.fieldOf("direction").forGetter(InvertedGeyserBaseParticleOptions::direction)
).apply(instance, (fluidBlocks, burstImpulseBase, direction) ->
new InvertedGeyserBaseParticleOptions(type, fluidBlocks, burstImpulseBase, direction)));
}
public static StreamCodec<? super ByteBuf, InvertedGeyserBaseParticleOptions> streamCodec(ParticleType<InvertedGeyserBaseParticleOptions> type) {
return new StreamCodec<>() {
@Override
public InvertedGeyserBaseParticleOptions decode(ByteBuf buffer) {
int fluidBlocks = ByteBufCodecs.INT.decode(buffer);
float burstImpulseBase = ByteBufCodecs.FLOAT.decode(buffer);
Direction direction = VERTICAL_DIRECTION_STREAM_CODEC.decode(buffer);
return new InvertedGeyserBaseParticleOptions(type, fluidBlocks, burstImpulseBase, direction);
}
@Override
public void encode(ByteBuf buffer, InvertedGeyserBaseParticleOptions value) {
ByteBufCodecs.INT.encode(buffer, value.fluidBlocks());
ByteBufCodecs.FLOAT.encode(buffer, value.burstImpulseBase());
VERTICAL_DIRECTION_STREAM_CODEC.encode(buffer, value.direction());
}
};
}
@Override
public ParticleType<?> getType() {
return this.type;
}
}
@@ -0,0 +1,57 @@
package com.craisinlord.antarchy.content.client.particle;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.netty.buffer.ByteBuf;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleType;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.util.ExtraCodecs;
public record InvertedGeyserParticleOptions(
ParticleType<InvertedGeyserParticleOptions> type,
int fluidBlocks,
Direction direction
) implements ParticleOptions {
private static final Codec<Direction> VERTICAL_DIRECTION_CODEC = Codec.STRING.xmap(
name -> "down".equals(name) ? Direction.DOWN : Direction.UP,
Direction::getName
);
private static final StreamCodec<ByteBuf, Direction> VERTICAL_DIRECTION_STREAM_CODEC =
ByteBufCodecs.STRING_UTF8.map(
name -> "down".equals(name) ? Direction.DOWN : Direction.UP,
Direction::getName
);
public static MapCodec<InvertedGeyserParticleOptions> codec(ParticleType<InvertedGeyserParticleOptions> type) {
return RecordCodecBuilder.mapCodec(instance -> instance.group(
ExtraCodecs.POSITIVE_INT.fieldOf("fluid_blocks").forGetter(InvertedGeyserParticleOptions::fluidBlocks),
VERTICAL_DIRECTION_CODEC.fieldOf("direction").forGetter(InvertedGeyserParticleOptions::direction)
).apply(instance, (fluidBlocks, direction) -> new InvertedGeyserParticleOptions(type, fluidBlocks, direction)));
}
public static StreamCodec<? super ByteBuf, InvertedGeyserParticleOptions> streamCodec(ParticleType<InvertedGeyserParticleOptions> type) {
return new StreamCodec<>() {
@Override
public InvertedGeyserParticleOptions decode(ByteBuf buffer) {
int fluidBlocks = ByteBufCodecs.INT.decode(buffer);
Direction direction = VERTICAL_DIRECTION_STREAM_CODEC.decode(buffer);
return new InvertedGeyserParticleOptions(type, fluidBlocks, direction);
}
@Override
public void encode(ByteBuf buffer, InvertedGeyserParticleOptions value) {
ByteBufCodecs.INT.encode(buffer, value.fluidBlocks());
VERTICAL_DIRECTION_STREAM_CODEC.encode(buffer, value.direction());
}
};
}
@Override
public ParticleType<?> getType() {
return this.type;
}
}
@@ -0,0 +1,114 @@
package com.craisinlord.antarchy.content.client.particle;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.ParticleProvider;
import net.minecraft.client.particle.ParticleRenderType;
import net.minecraft.client.particle.SpriteSet;
import net.minecraft.client.particle.TextureSheetParticle;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
public final class InvertedGeyserPlumeParticle extends TextureSheetParticle {
private final double startY;
private final double limitY;
private final float horizontalSprayX;
private final float horizontalSprayZ;
private final float initialPropulsion;
private final float minSize;
private final float maxSize;
private final SpriteSet sprites;
private final Direction direction;
public InvertedGeyserPlumeParticle(
ClientLevel level,
double x,
double y,
double z,
double xd,
double yd,
double zd,
InvertedGeyserParticleOptions options,
SpriteSet sprites
) {
super(level, x, y, z, xd, yd, zd);
int forceHeight = 5 * Math.max(1, options.fluidBlocks());
this.hasPhysics = true;
this.speedUpWhenYMotionIsBlocked = true;
this.lifetime = forceHeight * 5;
this.yd = 0.0D;
this.startY = y;
this.direction = options.direction();
this.limitY = this.startY + this.direction.getStepY() * (forceHeight - 1);
if (this.direction == Direction.DOWN) {
this.roll = Mth.PI;
this.oRoll = Mth.PI;
}
this.horizontalSprayX = (level.getRandom().nextFloat() - 0.5F) * 0.2F;
this.horizontalSprayZ = (level.getRandom().nextFloat() - 0.5F) * 0.2F;
this.friction = 1.0F;
this.initialPropulsion = (options.fluidBlocks() == 1 ? 1.5F : 1.0F) * forceHeight * 1.45F;
this.gravity = -this.direction.getStepY() * this.initialPropulsion;
float baseSize = this.quadSize * 0.75F;
this.minSize = baseSize * (2.0F + forceHeight / 8.0F);
this.maxSize = baseSize * (3.0F + forceHeight / 8.0F);
this.quadSize = this.minSize;
this.sprites = sprites;
this.setSpriteFromAge(sprites);
}
@Override
public void tick() {
super.tick();
if (!this.removed && hasReachedTerminalState()) {
this.lifetime = Math.min(this.lifetime, this.age + 5);
this.friction = 0.0F;
this.remove();
}
double progress = Mth.clamp((this.y - this.startY) / (this.limitY - this.startY), 0.0D, 1.0D);
double progressCurve = Math.pow(progress, 3.0D);
this.gravity = this.direction.getStepY() * this.initialPropulsion * (float) progressCurve * 0.12F;
this.xd = progress * this.horizontalSprayX;
this.zd = progress * this.horizontalSprayZ;
this.setSpriteFromAge(this.sprites);
this.quadSize = this.minSize + (float) (progress * (this.maxSize - this.minSize));
}
private boolean hasReachedTerminalState() {
if (this.direction == Direction.UP) {
return this.yd < 0.0D || this.y > this.limitY || this.y == this.yo;
}
return this.yd > 0.0D || this.y < this.limitY || this.y == this.yo;
}
@Override
public ParticleRenderType getRenderType() {
return ParticleRenderType.PARTICLE_SHEET_OPAQUE;
}
public static final class Provider implements ParticleProvider<InvertedGeyserParticleOptions> {
private final SpriteSet sprites;
public Provider(SpriteSet sprites) {
this.sprites = sprites;
}
@Override
public Particle createParticle(
InvertedGeyserParticleOptions options,
ClientLevel level,
double x,
double y,
double z,
double xd,
double yd,
double zd
) {
double shiftedX = x + (level.getRandom().nextFloat() - 0.5F) * 0.2F;
double shiftedY = y + level.getRandom().nextFloat() * options.direction().getStepY();
double shiftedZ = z + (level.getRandom().nextFloat() - 0.5F) * 0.2F;
return new InvertedGeyserPlumeParticle(level, shiftedX, shiftedY, shiftedZ, xd, yd, zd, options, this.sprites);
}
}
}
@@ -0,0 +1,13 @@
package com.craisinlord.antarchy.content.client.renderer;
import net.minecraft.world.item.Item;
import software.bernie.geckolib.animatable.GeoAnimatable;
import software.bernie.geckolib.animatable.GeoItem;
import software.bernie.geckolib.model.GeoModel;
import software.bernie.geckolib.renderer.GeoItemRenderer;
public class AnimatedHeldItemRenderer<T extends Item & GeoItem & GeoAnimatable> extends GeoItemRenderer<T> {
public AnimatedHeldItemRenderer(GeoModel<T> model) {
super(model);
}
}
@@ -0,0 +1,45 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.entity.ant.BaseAntEntity;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.Nullable;
import software.bernie.geckolib.cache.object.GeoBone;
import software.bernie.geckolib.renderer.GeoRenderer;
import software.bernie.geckolib.renderer.layer.BlockAndItemGeoLayer;
public class AntCarriedFoodGeoLayer extends BlockAndItemGeoLayer<BaseAntEntity> {
private static final String FOOD_BONE = "head";
public AntCarriedFoodGeoLayer(GeoRenderer<BaseAntEntity> renderer) {
super(renderer);
}
@Override
protected @Nullable ItemStack getStackForBone(GeoBone bone, BaseAntEntity animatable) {
if (!FOOD_BONE.equals(bone.getName())) {
return super.getStackForBone(bone, animatable);
}
ItemStack carriedFood = animatable.getCarriedFood();
return carriedFood.isEmpty() ? super.getStackForBone(bone, animatable) : carriedFood.copy();
}
@Override
protected ItemDisplayContext getTransformTypeForStack(GeoBone bone, ItemStack stack, BaseAntEntity animatable) {
return ItemDisplayContext.FIXED;
}
@Override
protected void renderStackForBone(PoseStack poseStack, GeoBone bone, ItemStack stack, BaseAntEntity animatable, MultiBufferSource bufferSource, float partialTick, int packedLight, int packedOverlay) {
double yOffset = animatable.isDancing() ? -0.055D : -0.04D;
poseStack.translate(0.0D, yOffset, -0.42D);
poseStack.mulPose(Axis.XP.rotationDegrees(90.0F));
poseStack.mulPose(Axis.ZP.rotationDegrees(180.0F));
poseStack.scale(0.4F, 0.4F, 0.4F);
super.renderStackForBone(poseStack, bone, stack, animatable, bufferSource, partialTick, packedLight, packedOverlay);
}
}
@@ -0,0 +1,60 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.entity.ant.BaseAntEntity;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import net.minecraft.client.model.SilverfishModel;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.renderer.entity.RenderLayerParent;
import net.minecraft.client.renderer.entity.layers.RenderLayer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
public class AntCarriedFoodLayer<T extends BaseAntEntity> extends RenderLayer<T, SilverfishModel<T>> {
private final ItemRenderer itemRenderer;
public AntCarriedFoodLayer(RenderLayerParent<T, SilverfishModel<T>> renderer, ItemRenderer itemRenderer) {
super(renderer);
this.itemRenderer = itemRenderer;
}
@Override
public void render(
PoseStack poseStack,
MultiBufferSource buffer,
int packedLight,
T ant,
float limbSwing,
float limbSwingAmount,
float partialTick,
float ageInTicks,
float netHeadYaw,
float headPitch
) {
ItemStack carriedFood = ant.getCarriedFood();
if (carriedFood.isEmpty()) {
return;
}
poseStack.pushPose();
poseStack.translate(0.0F, 0.08F, -0.06F);
poseStack.mulPose(Axis.XP.rotationDegrees(90.0F));
poseStack.mulPose(Axis.ZP.rotationDegrees(180.0F));
poseStack.scale(0.22F, 0.22F, 0.22F);
this.itemRenderer.renderStatic(
ant,
carriedFood,
ItemDisplayContext.FIXED,
false,
poseStack,
buffer,
ant.level(),
packedLight,
OverlayTexture.NO_OVERLAY,
ant.getId()
);
poseStack.popPose();
}
}
@@ -0,0 +1,36 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.client.model.AntModel;
import com.craisinlord.antarchy.content.entity.ant.BaseAntEntity;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import org.jetbrains.annotations.Nullable;
import software.bernie.geckolib.cache.object.BakedGeoModel;
import software.bernie.geckolib.renderer.GeoEntityRenderer;
public class AntRenderer extends GeoEntityRenderer<BaseAntEntity> {
private static final float ADULT_SHADOW_RADIUS = 0.3F;
private static final float ADULT_SCALE = 0.85F;
private static final float BABY_SCALE = 0.5F;
public AntRenderer(EntityRendererProvider.Context context) {
super(context, new AntModel());
this.shadowRadius = ADULT_SHADOW_RADIUS;
this.addRenderLayer(new AntCarriedFoodGeoLayer(this));
}
@Override
public void preRender(PoseStack poseStack, BaseAntEntity 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);
if (animatable.isBaby()) {
poseStack.scale(ADULT_SCALE * BABY_SCALE, ADULT_SCALE * BABY_SCALE, ADULT_SCALE * BABY_SCALE);
this.shadowRadius = ADULT_SHADOW_RADIUS * BABY_SCALE;
} else {
poseStack.scale(ADULT_SCALE, ADULT_SCALE, ADULT_SCALE);
this.shadowRadius = ADULT_SHADOW_RADIUS;
}
}
}
@@ -0,0 +1,344 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.block.LiquidBlockRenderer;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.Vec3;
public final class AntiwaterFluidRenderer {
private static final float SURFACE_NUDGE = 0.001F;
private AntiwaterFluidRenderer() {
}
public static void render(
BlockAndTintGetter level,
BlockPos pos,
VertexConsumer buffer,
BlockState blockState,
FluidState fluidState,
TextureAtlasSprite stillSprite,
TextureAtlasSprite flowSprite,
TextureAtlasSprite overlaySprite,
int tint
) {
float alpha = (tint >> 24 & 255) / 255.0F;
float red = (tint >> 16 & 255) / 255.0F;
float green = (tint >> 8 & 255) / 255.0F;
float blue = (tint & 255) / 255.0F;
BlockState downState = level.getBlockState(pos.below());
FluidState downFluid = downState.getFluidState();
BlockState upState = level.getBlockState(pos.above());
BlockState northState = level.getBlockState(pos.north());
FluidState northFluid = northState.getFluidState();
BlockState southState = level.getBlockState(pos.south());
FluidState southFluid = southState.getFluidState();
BlockState westState = level.getBlockState(pos.west());
FluidState westFluid = westState.getFluidState();
BlockState eastState = level.getBlockState(pos.east());
FluidState eastFluid = eastState.getFluidState();
boolean renderBottomSurface = LiquidBlockRenderer.shouldRenderFace(level, pos, fluidState, blockState, Direction.DOWN, downFluid);
boolean renderNorth = LiquidBlockRenderer.shouldRenderFace(level, pos, fluidState, blockState, Direction.NORTH, northFluid);
boolean renderSouth = LiquidBlockRenderer.shouldRenderFace(level, pos, fluidState, blockState, Direction.SOUTH, southFluid);
boolean renderWest = LiquidBlockRenderer.shouldRenderFace(level, pos, fluidState, blockState, Direction.WEST, westFluid);
boolean renderEast = LiquidBlockRenderer.shouldRenderFace(level, pos, fluidState, blockState, Direction.EAST, eastFluid);
boolean renderAttachedTop = LiquidBlockRenderer.shouldRenderFace(level, pos, fluidState, blockState, Direction.UP, upState.getFluidState());
if (!renderBottomSurface && !renderNorth && !renderSouth && !renderWest && !renderEast && !renderAttachedTop) {
return;
}
float shadeDown = level.getShade(Direction.DOWN, true);
float shadeUp = level.getShade(Direction.UP, true);
float shadeNorth = level.getShade(Direction.NORTH, true);
float shadeWest = level.getShade(Direction.WEST, true);
Fluid fluid = fluidState.getType();
float centerHeight = getHangingHeight(level, fluid, pos, blockState, fluidState);
float neHeight;
float nwHeight;
float seHeight;
float swHeight;
if (centerHeight >= 1.0F) {
neHeight = 1.0F;
nwHeight = 1.0F;
seHeight = 1.0F;
swHeight = 1.0F;
} else {
float northHeight = getHangingHeight(level, fluid, pos.north(), northState, northFluid);
float southHeight = getHangingHeight(level, fluid, pos.south(), southState, southFluid);
float eastHeight = getHangingHeight(level, fluid, pos.east(), eastState, eastFluid);
float westHeight = getHangingHeight(level, fluid, pos.west(), westState, westFluid);
neHeight = calculateAverageHeight(level, fluid, centerHeight, northHeight, eastHeight, pos.north().east());
nwHeight = calculateAverageHeight(level, fluid, centerHeight, northHeight, westHeight, pos.north().west());
seHeight = calculateAverageHeight(level, fluid, centerHeight, southHeight, eastHeight, pos.south().east());
swHeight = calculateAverageHeight(level, fluid, centerHeight, southHeight, westHeight, pos.south().west());
}
float neBottom = 1.0F - neHeight;
float nwBottom = 1.0F - nwHeight;
float seBottom = 1.0F - seHeight;
float swBottom = 1.0F - swHeight;
float x = pos.getX() & 15;
float y = pos.getY() & 15;
float z = pos.getZ() & 15;
float bottomOffset = renderBottomSurface ? SURFACE_NUDGE : 0.0F;
if (renderBottomSurface) {
renderBottomFace(level, pos, buffer, fluidState, flowSprite, stillSprite, alpha, red, green, blue, x, y, z, nwBottom, swBottom, seBottom, neBottom);
}
if (renderAttachedTop) {
float u0 = stillSprite.getU0();
float u1 = stillSprite.getU1();
float v0 = stillSprite.getV0();
float v1 = stillSprite.getV1();
int light = getLightColor(level, pos.above());
float r = shadeUp * red;
float g = shadeUp * green;
float b = shadeUp * blue;
emitDoubleSidedQuad(
buffer,
x, y + 1.0F - SURFACE_NUDGE, z + 1.0F, u0, v1,
x, y + 1.0F - SURFACE_NUDGE, z, u0, v0,
x + 1.0F, y + 1.0F - SURFACE_NUDGE, z, u1, v0,
x + 1.0F, y + 1.0F - SURFACE_NUDGE, z + 1.0F, u1, v1,
r, g, b, alpha, light
);
}
int sideLight = getLightColor(level, pos);
for (Direction direction : Direction.Plane.HORIZONTAL) {
float leftBottom;
float rightBottom;
float x0;
float x1;
float z0;
float z1;
boolean renderSide;
switch (direction) {
case NORTH -> {
leftBottom = nwBottom;
rightBottom = neBottom;
x0 = x;
x1 = x + 1.0F;
z0 = z + SURFACE_NUDGE;
z1 = z + SURFACE_NUDGE;
renderSide = renderNorth;
}
case SOUTH -> {
leftBottom = seBottom;
rightBottom = swBottom;
x0 = x + 1.0F;
x1 = x;
z0 = z + 1.0F - SURFACE_NUDGE;
z1 = z + 1.0F - SURFACE_NUDGE;
renderSide = renderSouth;
}
case WEST -> {
leftBottom = swBottom;
rightBottom = nwBottom;
x0 = x + SURFACE_NUDGE;
x1 = x + SURFACE_NUDGE;
z0 = z + 1.0F;
z1 = z;
renderSide = renderWest;
}
default -> {
leftBottom = neBottom;
rightBottom = seBottom;
x0 = x + 1.0F - SURFACE_NUDGE;
x1 = x + 1.0F - SURFACE_NUDGE;
z0 = z;
z1 = z + 1.0F;
renderSide = renderEast;
}
}
if (!renderSide) {
continue;
}
TextureAtlasSprite sideSprite = flowSprite;
float u0 = sideSprite.getU(0.0F);
float u1 = sideSprite.getU(0.5F);
float lowerVLeft = sideSprite.getV(0.5F);
float lowerVRight = sideSprite.getV(0.5F);
float upperVLeft = sideSprite.getV(leftBottom * 0.5F);
float upperVRight = sideSprite.getV(rightBottom * 0.5F);
float sideShade = direction.getAxis() == Direction.Axis.Z ? shadeNorth : shadeWest;
float r = shadeUp * sideShade * red;
float g = shadeUp * sideShade * green;
float b = shadeUp * sideShade * blue;
vertex(buffer, x0, y + leftBottom, z0, r, g, b, alpha, u0, upperVLeft, sideLight);
vertex(buffer, x1, y + rightBottom, z1, r, g, b, alpha, u1, upperVRight, sideLight);
vertex(buffer, x1, y + 1.0F - bottomOffset, z1, r, g, b, alpha, u1, lowerVRight, sideLight);
vertex(buffer, x0, y + 1.0F - bottomOffset, z0, r, g, b, alpha, u0, lowerVLeft, sideLight);
if (sideSprite != overlaySprite) {
vertex(buffer, x0, y + 1.0F - bottomOffset, z0, r, g, b, alpha, u0, lowerVLeft, sideLight);
vertex(buffer, x1, y + 1.0F - bottomOffset, z1, r, g, b, alpha, u1, lowerVRight, sideLight);
vertex(buffer, x1, y + rightBottom, z1, r, g, b, alpha, u1, upperVRight, sideLight);
vertex(buffer, x0, y + leftBottom, z0, r, g, b, alpha, u0, upperVLeft, sideLight);
}
}
}
private static void renderBottomFace(
BlockAndTintGetter level,
BlockPos pos,
VertexConsumer buffer,
FluidState fluidState,
TextureAtlasSprite flowSprite,
TextureAtlasSprite stillSprite,
float alpha,
float red,
float green,
float blue,
float x,
float y,
float z,
float nwBottom,
float swBottom,
float seBottom,
float neBottom
) {
Vec3 flow = fluidState.getFlow(level, pos);
float u0;
float u1;
float u2;
float u3;
float v0;
float v1;
float v2;
float v3;
if (flow.x == 0.0D && flow.z == 0.0D) {
u0 = stillSprite.getU(0.0F);
v0 = stillSprite.getV(0.0F);
u1 = u0;
v1 = stillSprite.getV(1.0F);
u2 = stillSprite.getU(1.0F);
v2 = v1;
u3 = u2;
v3 = v0;
} else {
float angle = (float) Mth.atan2(flow.z, flow.x) + (float) (Math.PI / 2);
float sin = Mth.sin(angle) * 0.25F;
float cos = Mth.cos(angle) * 0.25F;
u0 = flowSprite.getU(0.5F + (-cos - sin));
v0 = flowSprite.getV(0.5F + (-cos + sin));
u1 = flowSprite.getU(0.5F + (-cos + sin));
v1 = flowSprite.getV(0.5F + (cos + sin));
u2 = flowSprite.getU(0.5F + (cos + sin));
v2 = flowSprite.getV(0.5F + (cos - sin));
u3 = flowSprite.getU(0.5F + (cos - sin));
v3 = flowSprite.getV(0.5F + (-cos - sin));
}
int light = getLightColor(level, pos.below());
float r = level.getShade(Direction.DOWN, true) * red;
float g = level.getShade(Direction.DOWN, true) * green;
float b = level.getShade(Direction.DOWN, true) * blue;
emitDoubleSidedQuad(
buffer,
x, y + nwBottom + SURFACE_NUDGE, z, u0, v0,
x, y + swBottom + SURFACE_NUDGE, z + 1.0F, u1, v1,
x + 1.0F, y + seBottom + SURFACE_NUDGE, z + 1.0F, u2, v2,
x + 1.0F, y + neBottom + SURFACE_NUDGE, z, u3, v3,
r, g, b, alpha, light
);
}
private static void emitDoubleSidedQuad(
VertexConsumer buffer,
float x0, float y0, float z0, float u0, float v0,
float x1, float y1, float z1, float u1, float v1,
float x2, float y2, float z2, float u2, float v2,
float x3, float y3, float z3, float u3, float v3,
float red, float green, float blue, float alpha, int light
) {
vertex(buffer, x0, y0, z0, red, green, blue, alpha, u0, v0, light);
vertex(buffer, x1, y1, z1, red, green, blue, alpha, u1, v1, light);
vertex(buffer, x2, y2, z2, red, green, blue, alpha, u2, v2, light);
vertex(buffer, x3, y3, z3, red, green, blue, alpha, u3, v3, light);
vertex(buffer, x3, y3, z3, red, green, blue, alpha, u3, v3, light);
vertex(buffer, x2, y2, z2, red, green, blue, alpha, u2, v2, light);
vertex(buffer, x1, y1, z1, red, green, blue, alpha, u1, v1, light);
vertex(buffer, x0, y0, z0, red, green, blue, alpha, u0, v0, light);
}
private static float calculateAverageHeight(BlockAndTintGetter level, Fluid fluid, float currentHeight, float height1, float height2, BlockPos pos) {
if (height2 >= 1.0F || height1 >= 1.0F) {
return 1.0F;
}
float[] weighted = new float[2];
if (height2 > 0.0F || height1 > 0.0F) {
float diagonalHeight = getHangingHeight(level, fluid, pos);
if (diagonalHeight >= 1.0F) {
return 1.0F;
}
addWeightedHeight(weighted, diagonalHeight);
}
addWeightedHeight(weighted, currentHeight);
addWeightedHeight(weighted, height2);
addWeightedHeight(weighted, height1);
return weighted[0] / weighted[1];
}
private static void addWeightedHeight(float[] output, float height) {
if (height >= 0.8F) {
output[0] += height * 10.0F;
output[1] += 10.0F;
} else if (height >= 0.0F) {
output[0] += height;
output[1] += 1.0F;
}
}
private static float getHangingHeight(BlockAndTintGetter level, Fluid fluid, BlockPos pos) {
BlockState state = level.getBlockState(pos);
return getHangingHeight(level, fluid, pos, state, state.getFluidState());
}
private static float getHangingHeight(BlockAndTintGetter level, Fluid fluid, BlockPos pos, BlockState blockState, FluidState fluidState) {
if (!fluid.isSame(fluidState.getType())) {
return !blockState.isSolid() ? 0.0F : -1.0F;
}
BlockState belowState = level.getBlockState(pos.below());
return fluid.isSame(belowState.getFluidState().getType())
? 1.0F
: fluidState.getOwnHeight();
}
private static void vertex(VertexConsumer buffer, float x, float y, float z, float red, float green, float blue, float alpha, float u, float v, int light) {
buffer.addVertex(x, y, z)
.setColor(red, green, blue, alpha)
.setUv(u, v)
.setLight(light)
.setNormal(0.0F, -1.0F, 0.0F);
}
private static int getLightColor(BlockAndTintGetter level, BlockPos pos) {
int light = LevelRenderer.getLightColor(level, pos);
int aboveLight = LevelRenderer.getLightColor(level, pos.above());
int block = Math.max(light & 255, aboveLight & 255);
int sky = Math.max((light >> 16) & 255, (aboveLight >> 16) & 255);
return block | (sky << 16);
}
}
@@ -0,0 +1,77 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.client.model.AppleCowModel;
import com.craisinlord.antarchy.content.entity.AppleCowEntity;
import com.craisinlord.antarchy.content.entity.AppleCowEntityVariants.EnchantedGoldenAppleCow;
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.ItemRenderer;
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 AppleCowRenderer extends GeoEntityRenderer<AppleCowEntity> {
private static final float ADULT_SHADOW_RADIUS = 0.7F;
private static final float BABY_SCALE = 0.85F;
public AppleCowRenderer(EntityRendererProvider.Context context) {
super(context, new AppleCowModel());
this.shadowRadius = ADULT_SHADOW_RADIUS;
this.addRenderLayer(new EnchantedLayer(this));
}
@Override
public RenderType getRenderType(AppleCowEntity animatable, ResourceLocation texture, @Nullable MultiBufferSource bufferSource, float partialTick) {
return RenderType.entityCutoutNoCull(texture);
}
@Override
public void preRender(PoseStack poseStack, AppleCowEntity 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);
if (animatable.isBaby()) {
poseStack.scale(BABY_SCALE, BABY_SCALE, BABY_SCALE);
this.shadowRadius = ADULT_SHADOW_RADIUS * BABY_SCALE;
} else {
this.shadowRadius = ADULT_SHADOW_RADIUS;
}
}
private static final class EnchantedLayer extends GeoRenderLayer<AppleCowEntity> {
private EnchantedLayer(AppleCowRenderer renderer) {
super(renderer);
}
@Override
public void render(PoseStack poseStack, AppleCowEntity animatable, BakedGeoModel bakedModel, @Nullable RenderType renderType,
MultiBufferSource bufferSource, @Nullable VertexConsumer buffer, float partialTick,
int packedLight, int packedOverlay) {
if (!(animatable instanceof EnchantedGoldenAppleCow)) {
return;
}
ResourceLocation texture = AppleCowModel.textureFor(animatable);
RenderType foilType = RenderType.entityCutoutNoCull(texture);
VertexConsumer foilBuffer = ItemRenderer.getFoilBufferDirect(bufferSource, foilType, false, true);
this.getRenderer().reRender(
bakedModel,
poseStack,
bufferSource,
animatable,
foilType,
foilBuffer,
partialTick,
packedLight,
OverlayTexture.NO_OVERLAY,
0xFFFFFFFF
);
}
}
}
@@ -0,0 +1,14 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.client.model.BasiliskModel;
import com.craisinlord.antarchy.content.entity.basilisk.BasiliskEntity;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import software.bernie.geckolib.renderer.GeoEntityRenderer;
public class BasiliskRenderer extends GeoEntityRenderer<BasiliskEntity> {
public BasiliskRenderer(EntityRendererProvider.Context context) {
super(context, new BasiliskModel());
this.shadowRadius = 1.0F;
}
}
@@ -0,0 +1,35 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.client.model.BedBugModel;
import com.craisinlord.antarchy.content.entity.BedBugEntity;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import org.jetbrains.annotations.Nullable;
import software.bernie.geckolib.cache.object.BakedGeoModel;
import software.bernie.geckolib.renderer.GeoEntityRenderer;
public class BedBugRenderer extends GeoEntityRenderer<BedBugEntity> {
private static final float ADULT_SCALE = 0.9F;
private static final float BABY_SCALE = 0.38F;
private static final float ADULT_SHADOW_RADIUS = 0.65F;
public BedBugRenderer(EntityRendererProvider.Context context) {
super(context, new BedBugModel());
this.shadowRadius = ADULT_SHADOW_RADIUS;
this.withScale(ADULT_SCALE);
}
@Override
public void preRender(PoseStack poseStack, BedBugEntity 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);
if (animatable.isBaby()) {
poseStack.scale(BABY_SCALE, BABY_SCALE, BABY_SCALE);
this.shadowRadius = ADULT_SHADOW_RADIUS * BABY_SCALE;
} else {
this.shadowRadius = ADULT_SHADOW_RADIUS;
}
}
}
@@ -0,0 +1,68 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.client.model.BomberModel;
import com.craisinlord.antarchy.content.entity.BomberEntity;
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 BomberRenderer extends GeoEntityRenderer<BomberEntity> {
private static final ResourceLocation TEXTURE =
ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/bomber.png");
public BomberRenderer(EntityRendererProvider.Context context) {
super(context, new BomberModel());
this.shadowRadius = 0.12F;
this.addRenderLayer(new BomberFlashLayer(this));
}
@Override
public RenderType getRenderType(BomberEntity animatable, ResourceLocation texture, @Nullable MultiBufferSource bufferSource, float partialTick) {
return RenderType.entityCutoutNoCull(texture);
}
@Override
public void preRender(PoseStack poseStack, BomberEntity 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 = 0.12F;
}
public static final class BomberFlashLayer extends GeoRenderLayer<BomberEntity> {
private BomberFlashLayer(GeoEntityRenderer<BomberEntity> renderer) {
super(renderer);
}
@Override
public void render(PoseStack poseStack, BomberEntity animatable, BakedGeoModel bakedModel, @Nullable RenderType renderType,
MultiBufferSource bufferSource, @Nullable VertexConsumer buffer, float partialTick,
int packedLight, int packedOverlay) {
if (!animatable.isFlashing()) {
return;
}
RenderType flashType = RenderType.eyes(TEXTURE);
VertexConsumer flashBuffer = bufferSource.getBuffer(flashType);
this.getRenderer().reRender(
bakedModel,
poseStack,
bufferSource,
animatable,
flashType,
flashBuffer,
partialTick,
0xF000F0,
OverlayTexture.NO_OVERLAY,
0xFFFFFFFF
);
}
}
}
@@ -0,0 +1,81 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.client.BrutalflyElytraClientState;
import com.craisinlord.antarchy.content.item.BrutalflyElytraItem;
import com.craisinlord.antarchy.mixins.client.ElytraModelAccessor;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.model.ElytraModel;
import net.minecraft.client.model.PlayerModel;
import net.minecraft.client.model.geom.ModelLayers;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
import net.minecraft.client.renderer.entity.RenderLayerParent;
import net.minecraft.client.renderer.entity.layers.RenderLayer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.item.ItemStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.geom.ModelPart;
public final class BrutalflyElytraLayer extends RenderLayer<AbstractClientPlayer, PlayerModel<AbstractClientPlayer>> {
private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath("antarchy", "textures/models/armor/brutalfly_wings.png");
private final ElytraModel<AbstractClientPlayer> model;
public BrutalflyElytraLayer(RenderLayerParent<AbstractClientPlayer, PlayerModel<AbstractClientPlayer>> renderer) {
super(renderer);
this.model = new ElytraModel<>(Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.ELYTRA));
}
@Override
public void render(
PoseStack poseStack,
MultiBufferSource buffer,
int packedLight,
AbstractClientPlayer player,
float limbSwing,
float limbSwingAmount,
float partialTick,
float ageInTicks,
float netHeadYaw,
float headPitch
) {
if (!BrutalflyElytraItem.isWearingBrutalflyElytra(player) || player.isInvisible()) {
return;
}
ItemStack chestStack = player.getItemBySlot(EquipmentSlot.CHEST);
BrutalflyElytraClientState.AnimationState animationState = BrutalflyElytraClientState.get(player.getId());
float progress = animationState != null ? animationState.progress(partialTick) : 0.0F;
poseStack.pushPose();
this.getParentModel().copyPropertiesTo(this.model);
if (player.isCrouching()) {
poseStack.translate(0.0F, 0.0F, 0.125F);
}
this.model.setupAnim(player, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch);
ElytraModelAccessor accessor = (ElytraModelAccessor) (Object) this.model;
ModelPart leftWing = accessor.antarchy$getLeftWing();
ModelPart rightWing = accessor.antarchy$getRightWing();
float strength = animationState != null ? animationState.strength() : 0.0F;
float flap = net.minecraft.util.Mth.sin(progress * net.minecraft.util.Mth.PI);
float liftOffset = flap * (2.8F + strength * 0.8F);
float pitchOffset = flap * (0.35F + strength * 0.12F);
float tipCurl = flap * (0.30F + strength * 0.10F);
leftWing.y -= liftOffset;
rightWing.y -= liftOffset;
leftWing.xRot -= pitchOffset;
rightWing.xRot -= pitchOffset;
leftWing.zRot -= tipCurl;
rightWing.zRot += tipCurl;
VertexConsumer consumer = ItemRenderer.getFoilBufferDirect(buffer, RenderType.armorCutoutNoCull(TEXTURE), false, chestStack.hasFoil());
this.model.renderToBuffer(poseStack, consumer, packedLight, OverlayTexture.NO_OVERLAY);
poseStack.popPose();
}
}
@@ -0,0 +1,89 @@
package com.craisinlord.antarchy.content.client.renderer;
import com.craisinlord.antarchy.content.entity.brutalfly.BrutalflyOrbEntity;
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 BrutalflyOrbRenderer extends EntityRenderer<BrutalflyOrbEntity> {
private static final ResourceLocation ORB_TEXTURE =
ResourceLocation.withDefaultNamespace("textures/entity/enderdragon/dragon_fireball.png");
public BrutalflyOrbRenderer(EntityRendererProvider.Context context) {
super(context);
}
@Override
protected int getBlockLightLevel(BrutalflyOrbEntity entity, BlockPos pos) {
return 15;
}
@Override
public void render(BrutalflyOrbEntity entity, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight) {
poseStack.pushPose();
poseStack.mulPose(this.entityRenderDispatcher.cameraOrientation());
float scale = entity.isLingeringOrb() ? entity.getOrbRadius(partialTick) * 0.38F : 0.8F;
poseStack.scale(scale, scale, scale);
float red;
float green;
float blue;
if (entity.getOrbVariant() == BrutalflyOrbEntity.OrbVariant.POISON) {
red = 0.32F;
green = 0.92F;
blue = 0.26F;
} else {
red = 1.0F;
green = 0.62F;
blue = 0.08F;
}
float alpha = entity.isLingeringOrb() ? 0.72F : 0.95F;
VertexConsumer vertexConsumer = buffer.getBuffer(RenderType.entityTranslucent(ORB_TEXTURE));
PoseStack.Pose pose = poseStack.last();
Matrix4f matrix4f = pose.pose();
addVertex(vertexConsumer, pose, matrix4f, -0.5F, -0.5F, 0.0F, 1.0F, red, green, blue, alpha, packedLight);
addVertex(vertexConsumer, pose, matrix4f, 0.5F, -0.5F, 1.0F, 1.0F, red, green, blue, alpha, packedLight);
addVertex(vertexConsumer, pose, matrix4f, 0.5F, 0.5F, 1.0F, 0.0F, red, green, blue, alpha, packedLight);
addVertex(vertexConsumer, pose, matrix4f, -0.5F, 0.5F, 0.0F, 0.0F, red, green, blue, 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 red,
float green,
float blue,
float alpha,
int packedLight
) {
vertexConsumer.addVertex(matrix4f, x, y, 0.0F)
.setColor(red, green, blue, alpha)
.setUv(u, v)
.setOverlay(OverlayTexture.NO_OVERLAY)
.setLight(packedLight)
.setNormal(pose, 0.0F, 0.0F, 1.0F);
}
@Override
public ResourceLocation getTextureLocation(BrutalflyOrbEntity entity) {
return ORB_TEXTURE;
}
}
Loaded 100 of 2557 files, more files were not shown because too many files have changed in this diff. Show more