Initial commit
This commit is contained in:
commit
cd0af5a1d3
2557 files changed
+271980
No files matched your search
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
plugins {
|
||||
id "architectury-plugin" version "3.4-SNAPSHOT"
|
||||
id "dev.architectury.loom" version "1.7-SNAPSHOT" apply false
|
||||
// id "com.modrinth.minotaur" version "2.+"
|
||||
id "com.matthewprenger.cursegradle" version "1.4.0"
|
||||
id "me.modmuss50.mod-publish-plugin" version "0.5.1"
|
||||
}
|
||||
|
||||
architectury {
|
||||
minecraft = rootProject.minecraft_version
|
||||
}
|
||||
|
||||
subprojects {
|
||||
apply plugin: "dev.architectury.loom"
|
||||
// apply plugin: "com.modrinth.minotaur"
|
||||
apply plugin: "me.modmuss50.mod-publish-plugin"
|
||||
apply plugin: "com.matthewprenger.cursegradle"
|
||||
|
||||
version = "${rootProject.mod_version}+${rootProject.minecraft_version}-${name}"
|
||||
|
||||
loom {
|
||||
silentMojangMappingsLicense()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
|
||||
mappings loom.officialMojangMappings()
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
apply plugin: "java"
|
||||
apply plugin: "architectury-plugin"
|
||||
apply plugin: "maven-publish"
|
||||
|
||||
archivesBaseName = rootProject.modid
|
||||
version = "${rootProject.mod_version}+${rootProject.minecraft_version}-${name}"
|
||||
group = rootProject.maven_group
|
||||
|
||||
repositories {
|
||||
maven { url "https://maven.fabricmc.net/" }
|
||||
maven { url "https://maven.neoforged.net/releases" }
|
||||
mavenCentral()
|
||||
maven { url = 'https://maven.quiltmc.org/repository/release' }
|
||||
maven {
|
||||
url = 'https://maven.cafeteria.dev/releases'
|
||||
content {
|
||||
includeGroup 'dev.cafeteria'
|
||||
}
|
||||
}
|
||||
exclusiveContent {
|
||||
forRepository {
|
||||
maven {
|
||||
name = "GeckoLib"
|
||||
url = "https://dl.cloudsmith.io/public/geckolib3/geckolib/maven/"
|
||||
}
|
||||
}
|
||||
filter {
|
||||
includeGroup("software.bernie.geckolib")
|
||||
}
|
||||
}
|
||||
maven { url "https://nexus.resourcefulbees.com/repository/telepathicgrunt/" }
|
||||
maven { url "https://maven.architectury.dev/" }
|
||||
maven { url "https://maven.shedaniel.me" }
|
||||
maven { url "https://jitpack.io" }
|
||||
maven { url "https://www.cursemaven.com" }
|
||||
maven { url "https://api.modrinth.com/maven/" }
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.encoding = "UTF-8"
|
||||
options.release = 21
|
||||
}
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(21)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
+22
@@ -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();
|
||||
}
|
||||
}
|
||||
+17
@@ -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;
|
||||
}
|
||||
}
|
||||
+84
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+84
@@ -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);
|
||||
}
|
||||
}
|
||||
+38
@@ -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);
|
||||
}
|
||||
}
|
||||
+176
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+106
@@ -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);
|
||||
}
|
||||
}
|
||||
+105
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+195
@@ -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;
|
||||
}
|
||||
}
|
||||
+73
@@ -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);
|
||||
}
|
||||
}
|
||||
+82
@@ -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);
|
||||
}
|
||||
}
|
||||
+136
@@ -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();
|
||||
}
|
||||
}
|
||||
+194
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -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();
|
||||
}
|
||||
}
|
||||
+69
@@ -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;
|
||||
}
|
||||
}
|
||||
+521
@@ -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);
|
||||
}
|
||||
}
|
||||
+213
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -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;
|
||||
}
|
||||
}
|
||||
+26
@@ -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();
|
||||
}
|
||||
}
|
||||
+40
@@ -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();
|
||||
}
|
||||
}
|
||||
+16
@@ -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; }
|
||||
}
|
||||
+54
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
@@ -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();
|
||||
}
|
||||
}
|
||||
+46
@@ -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) {
|
||||
}
|
||||
}
|
||||
+57
@@ -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");
|
||||
}
|
||||
}
|
||||
+62
@@ -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);
|
||||
}
|
||||
}
|
||||
+23
@@ -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");
|
||||
}
|
||||
}
|
||||
+28
@@ -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");
|
||||
}
|
||||
}
|
||||
+23
@@ -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");
|
||||
}
|
||||
}
|
||||
+23
@@ -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");
|
||||
}
|
||||
}
|
||||
+23
@@ -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");
|
||||
}
|
||||
}
|
||||
+24
@@ -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");
|
||||
}
|
||||
}
|
||||
+67
@@ -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");
|
||||
}
|
||||
}
|
||||
+22
@@ -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;
|
||||
}
|
||||
}
|
||||
+23
@@ -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");
|
||||
}
|
||||
}
|
||||
+33
@@ -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");
|
||||
}
|
||||
}
|
||||
+49
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+85
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+51
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+71
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+77
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+62
@@ -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;
|
||||
}
|
||||
}
|
||||
+57
@@ -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;
|
||||
}
|
||||
}
|
||||
+114
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -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);
|
||||
}
|
||||
}
|
||||
+45
@@ -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);
|
||||
}
|
||||
}
|
||||
+60
@@ -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();
|
||||
}
|
||||
}
|
||||
+36
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+344
@@ -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);
|
||||
}
|
||||
}
|
||||
+77
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
@@ -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;
|
||||
}
|
||||
}
|
||||
+35
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+68
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 2557 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user