lots of stuff

This commit is contained in:
craisinlord committed 2026-08-12 09:27:27 -05:00
1 parent ee9ac93b5e
commit ea24b19068
5242 files changed
+336231 -112

No files matched your search

+1
View File
@@ -12,6 +12,7 @@ allprojects {
repositories {
maven { url "https://maven.fabricmc.net/" }
maven { url "https://maven.neoforged.net/releases" }
maven { url "https://maven.architectury.dev/" }
mavenCentral()
maven { url = 'https://maven.quiltmc.org/repository/release' }
maven {
+26
View File
@@ -0,0 +1,26 @@
plugins {
id 'java-library'
}
base {
archivesName = "${mod_id}-common-1.20.1"
}
// Source-only module — each loader module compiles these sources itself.
tasks.named('compileJava').configure {
enabled = false
}
tasks.named('jar').configure {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from sourceSets.main.allJava
from sourceSets.main.resources
}
dependencies {
compileOnly(files("$rootDir/infinite_dimensions_jars/infinity-2.7.2+1.20.1-fabric.jar"))
compileOnly("software.bernie.geckolib:geckolib-fabric-1.20.1:${geckolib_version}")
compileOnly("curse.maven:sizeable_foliage-${sizeable_foliage_curseforge_id_1_20_1}:${sizeable_foliage_curseforge_file_id_1_20_1_fabric}")
compileOnly("curse.maven:intapi-${intapi_curseforge_id}:${intapi_curseforge_file_id_1_20_1_fabric}")
compileOnly("mezz.jei:jei-1.20.1-common-api:${jei_version_1_20_1}")
}
@@ -0,0 +1,19 @@
package com.craisinlord.antarchy;
import com.craisinlord.antarchy.content.util.AttributeRangeInit;
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() {
AttributeRangeInit.apply();
ServerGoingToStartEvent.EVENT.addListener(Antarchy::serverAboutToStart);
}
private static void serverAboutToStart(final ServerGoingToStartEvent event) {
}
}
@@ -0,0 +1,27 @@
package com.craisinlord.antarchy.compat.geckolib;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.entity.LivingEntity;
import software.bernie.geckolib.core.animatable.GeoAnimatable;
import software.bernie.geckolib.core.animation.AnimationController;
public final class AutoPlayingSoundKeyframeHandlerCompat {
private AutoPlayingSoundKeyframeHandlerCompat() {
}
public static <A extends LivingEntity & GeoAnimatable> AnimationController.SoundKeyframeHandler<A> create() {
return event -> {
String[] parts = event.getKeyframeData().getSound().split("\\|");
SoundEvent sound = BuiltInRegistries.SOUND_EVENT.get(new ResourceLocation(parts[0]));
if (sound == null) {
return;
}
float volume = parts.length > 1 ? Float.parseFloat(parts[1]) : 1f;
float pitch = parts.length > 2 ? Float.parseFloat(parts[2]) : 1f;
A animatable = event.getAnimatable();
animatable.level().playSound(null, animatable.getX(), animatable.getY(), animatable.getZ(), sound, animatable.getSoundSource(), volume, pitch);
};
}
}
@@ -0,0 +1,16 @@
package com.craisinlord.antarchy.compat.infinity;
public final class InfinityCompat {
private static InfinityCompatBridge bridge = InfinityCompatBridge.NOOP;
private InfinityCompat() {
}
public static InfinityCompatBridge get() {
return bridge;
}
public static void bind(InfinityCompatBridge compatBridge) {
bridge = compatBridge != null ? compatBridge : InfinityCompatBridge.NOOP;
}
}
@@ -0,0 +1,37 @@
package com.craisinlord.antarchy.compat.infinity;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
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 ResourceLocation getRandomDimensionId(RandomSource random, double easterEggChance) {
return getRandomDimensionId(random);
}
default boolean requestWarp(ServerPlayer player, ResourceLocation dimensionId) {
return false;
}
/**
* Converts an already-ignited vanilla Nether portal frame at {@code anyPortalBlockPos} into a real, permanent
* Infinite Dimensions portal to {@code dimensionId}, generating the dimension first if it doesn't exist yet.
* Mirrors what Infinity itself does when a written book is thrown into a lit portal.
*/
default boolean createPhysicalPortal(ServerLevel level, BlockPos anyPortalBlockPos, ResourceLocation dimensionId) {
return false;
}
}
@@ -0,0 +1,56 @@
package com.craisinlord.antarchy.compat.infinity;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class InfinityCompatVersion {
private static final Pattern VERSION_PARTS = Pattern.compile("(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?");
private static final int REQUIRED_MAJOR = 2;
private static final int REQUIRED_MINOR = 7;
private static final int REQUIRED_PATCH = 2;
private InfinityCompatVersion() {
}
public static boolean isSupported(String version) {
int[] parsed = parse(version);
if (parsed == null) {
return false;
}
if (parsed[0] != REQUIRED_MAJOR) {
return parsed[0] > REQUIRED_MAJOR;
}
if (parsed[1] != REQUIRED_MINOR) {
return parsed[1] > REQUIRED_MINOR;
}
return parsed[2] >= REQUIRED_PATCH;
}
public static String requiredVersion() {
return REQUIRED_MAJOR + "." + REQUIRED_MINOR + "." + REQUIRED_PATCH;
}
private static int[] parse(String version) {
if (version == null || version.isBlank()) {
return null;
}
Matcher matcher = VERSION_PARTS.matcher(version);
if (!matcher.find()) {
return null;
}
return new int[]{
parsePart(matcher.group(1)),
parsePart(matcher.group(2)),
parsePart(matcher.group(3))
};
}
private static int parsePart(String value) {
if (value == null || value.isBlank()) {
return 0;
}
return Integer.parseInt(value);
}
}
@@ -0,0 +1,64 @@
package com.craisinlord.antarchy.compat.jei;
import com.craisinlord.antarchy.Antarchy;
import java.util.List;
import mezz.jei.api.gui.builder.IRecipeLayoutBuilder;
import mezz.jei.api.gui.drawable.IDrawable;
import mezz.jei.api.helpers.IGuiHelper;
import mezz.jei.api.recipe.IFocusGroup;
import mezz.jei.api.recipe.RecipeIngredientRole;
import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.recipe.category.IRecipeCategory;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
public final class AmericanizeJeiRecipeCategory implements IRecipeCategory<AmericanizeJeiRecipeCategory.Recipe> {
public static final RecipeType<Recipe> TYPE = RecipeType.create(Antarchy.MODID, "americanize", Recipe.class);
private final IDrawable icon;
public record Recipe(List<ItemStack> foods, ItemStack hfcs, List<ItemStack> results) {
}
public AmericanizeJeiRecipeCategory(IGuiHelper guiHelper, ItemStack hfcsIcon) {
this.icon = guiHelper.createDrawableItemStack(hfcsIcon);
}
@Override
public RecipeType<Recipe> getRecipeType() {
return TYPE;
}
@Override
public Component getTitle() {
return Component.translatable("jei.antarchy.americanize");
}
@Override
public int getWidth() {
return 78;
}
@Override
public int getHeight() {
return 18;
}
@Override
public IDrawable getIcon() {
return this.icon;
}
@Override
public void setRecipe(IRecipeLayoutBuilder builder, Recipe recipe, IFocusGroup focuses) {
builder.addSlot(RecipeIngredientRole.RENDER_ONLY, 1, 1)
.setStandardSlotBackground()
.addItemStacks(recipe.foods());
builder.addSlot(RecipeIngredientRole.INPUT, 30, 1)
.setStandardSlotBackground()
.addItemStack(recipe.hfcs());
builder.addSlot(RecipeIngredientRole.RENDER_ONLY, 59, 1)
.setStandardSlotBackground()
.addItemStacks(recipe.results());
}
}
@@ -0,0 +1,98 @@
package com.craisinlord.antarchy.compat.jei;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.recipe.AmericanizeRecipe;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.AntarchyTags;
import com.craisinlord.antarchy.content.recipe.CustomBrewingRecipes;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.entity.glimmer.GlimmerVariant;
import com.craisinlord.antarchy.content.item.GlimmerBottleItem;
import java.util.ArrayList;
import java.util.List;
import mezz.jei.api.IModPlugin;
import mezz.jei.api.JeiPlugin;
import mezz.jei.api.constants.RecipeTypes;
import mezz.jei.api.recipe.vanilla.IJeiBrewingRecipe;
import mezz.jei.api.recipe.vanilla.IVanillaRecipeFactory;
import mezz.jei.api.registration.IRecipeCategoryRegistration;
import mezz.jei.api.registration.IRecipeRegistration;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.util.Unit;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
@JeiPlugin
public class AntarchyJeiPlugin implements IModPlugin {
private static final ResourceLocation UID = new ResourceLocation(Antarchy.MODID, "jei_plugin");
@Override
public ResourceLocation getPluginUid() {
return UID;
}
@Override
public void registerCategories(IRecipeCategoryRegistration registration) {
ItemStack hfcs = new ItemStack(CustomBrewingRecipes.highFructoseCornSyrupItem());
registration.addRecipeCategories(new AmericanizeJeiRecipeCategory(registration.getJeiHelpers().getGuiHelper(), hfcs));
}
@Override
public void registerRecipes(IRecipeRegistration registration) {
IVanillaRecipeFactory factory = registration.getVanillaRecipeFactory();
List<IJeiBrewingRecipe> recipes = new ArrayList<>();
recipes.add(factory.createBrewingRecipe(
List.of(new ItemStack(CustomBrewingRecipes.cornItem())),
CustomBrewingRecipes.waterBottleStack(),
new ItemStack(CustomBrewingRecipes.highFructoseCornSyrupItem())));
recipes.add(factory.createBrewingRecipe(
tagItems(CustomBrewingRecipes.rootsTag()),
new ItemStack(CustomBrewingRecipes.highFructoseCornSyrupItem()),
new ItemStack(CustomBrewingRecipes.rootBeerItem())));
ItemStack glimmerBottleInput = GlimmerBottleItem.create(GlimmerVariant.APPLE_COW);
recipes.add(factory.createBrewingRecipe(tagItems(AntarchyTags.Items.GLIMMER_AUGMENT_OURANWOOD_DEER),
glimmerBottleInput, GlimmerBottleItem.create(GlimmerVariant.OURANWOOD_DEER)));
recipes.add(factory.createBrewingRecipe(tagItems(AntarchyTags.Items.GLIMMER_AUGMENT_FROG),
glimmerBottleInput, GlimmerBottleItem.create(GlimmerVariant.FROG)));
recipes.add(factory.createBrewingRecipe(tagItems(AntarchyTags.Items.GLIMMER_AUGMENT_ANT),
glimmerBottleInput, GlimmerBottleItem.create(GlimmerVariant.ANT)));
recipes.add(factory.createBrewingRecipe(tagItems(AntarchyTags.Items.GLIMMER_AUGMENT_ELKA),
glimmerBottleInput, GlimmerBottleItem.create(GlimmerVariant.ELKA)));
ItemStack glimmerBottleDeer = GlimmerBottleItem.create(GlimmerVariant.OURANWOOD_DEER);
recipes.add(factory.createBrewingRecipe(tagItems(AntarchyTags.Items.GLIMMER_AUGMENT_APPLE_COW),
glimmerBottleDeer, GlimmerBottleItem.create(GlimmerVariant.APPLE_COW)));
registration.addRecipes(RecipeTypes.BREWING, recipes);
if (AntarchySettings.americanizingEnabled()) {
registration.addRecipes(AmericanizeJeiRecipeCategory.TYPE, List.of(americanizeDisplay()));
}
}
private static AmericanizeJeiRecipeCategory.Recipe americanizeDisplay() {
List<ItemStack> foods = new ArrayList<>();
List<ItemStack> results = new ArrayList<>();
for (Item item : BuiltInRegistries.ITEM) {
ItemStack stack = new ItemStack(item);
if (AmericanizeRecipe.isEligibleFood(stack)) {
foods.add(stack);
ItemStack result = stack.copyWithCount(1);
AntarchyObjects.AMERICAN_COMPONENT.set(result, Unit.INSTANCE);
results.add(result);
}
}
ItemStack hfcs = new ItemStack(CustomBrewingRecipes.highFructoseCornSyrupItem());
return new AmericanizeJeiRecipeCategory.Recipe(foods, hfcs, results);
}
private static List<ItemStack> tagItems(TagKey<Item> tag) {
return List.of(Ingredient.of(tag).getItems());
}
}
@@ -0,0 +1,93 @@
package com.craisinlord.antarchy.compat.network;
import io.netty.buffer.ByteBuf;
import net.minecraft.network.FriendlyByteBuf;
public final class ByteBufCodecs {
private ByteBufCodecs() {
}
public static final StreamCodec<ByteBuf, Integer> VAR_INT = new StreamCodec<>() {
@Override
public Integer decode(ByteBuf buf) {
return ((FriendlyByteBuf) buf).readVarInt();
}
@Override
public void encode(ByteBuf buf, Integer value) {
((FriendlyByteBuf) buf).writeVarInt(value);
}
};
public static final StreamCodec<ByteBuf, Long> VAR_LONG = new StreamCodec<>() {
@Override
public Long decode(ByteBuf buf) {
return ((FriendlyByteBuf) buf).readVarLong();
}
@Override
public void encode(ByteBuf buf, Long value) {
((FriendlyByteBuf) buf).writeVarLong(value);
}
};
public static final StreamCodec<ByteBuf, Boolean> BOOL = new StreamCodec<>() {
@Override
public Boolean decode(ByteBuf buf) {
return ((FriendlyByteBuf) buf).readBoolean();
}
@Override
public void encode(ByteBuf buf, Boolean value) {
((FriendlyByteBuf) buf).writeBoolean(value);
}
};
public static final StreamCodec<ByteBuf, Byte> BYTE = new StreamCodec<>() {
@Override
public Byte decode(ByteBuf buf) {
return ((FriendlyByteBuf) buf).readByte();
}
@Override
public void encode(ByteBuf buf, Byte value) {
((FriendlyByteBuf) buf).writeByte(value);
}
};
public static final StreamCodec<ByteBuf, Float> FLOAT = new StreamCodec<>() {
@Override
public Float decode(ByteBuf buf) {
return ((FriendlyByteBuf) buf).readFloat();
}
@Override
public void encode(ByteBuf buf, Float value) {
((FriendlyByteBuf) buf).writeFloat(value);
}
};
public static final StreamCodec<ByteBuf, Double> DOUBLE = new StreamCodec<>() {
@Override
public Double decode(ByteBuf buf) {
return ((FriendlyByteBuf) buf).readDouble();
}
@Override
public void encode(ByteBuf buf, Double value) {
((FriendlyByteBuf) buf).writeDouble(value);
}
};
public static final StreamCodec<ByteBuf, String> STRING_UTF8 = new StreamCodec<>() {
@Override
public String decode(ByteBuf buf) {
return ((FriendlyByteBuf) buf).readUtf();
}
@Override
public void encode(ByteBuf buf, String value) {
((FriendlyByteBuf) buf).writeUtf(value);
}
};
}
@@ -0,0 +1,10 @@
package com.craisinlord.antarchy.compat.network;
import net.minecraft.resources.ResourceLocation;
public interface CustomPacketPayload {
Type<? extends CustomPacketPayload> type();
record Type<T extends CustomPacketPayload>(ResourceLocation id) {
}
}
@@ -0,0 +1,204 @@
package com.craisinlord.antarchy.compat.network;
import java.util.function.Function;
public interface StreamCodec<B, V> {
V decode(B buf);
void encode(B buf, V value);
default <O> StreamCodec<B, O> map(Function<V, O> to, Function<O, V> from) {
StreamCodec<B, V> self = this;
return new StreamCodec<>() {
@Override
public O decode(B buf) {
return to.apply(self.decode(buf));
}
@Override
public void encode(B buf, O value) {
self.encode(buf, from.apply(value));
}
};
}
static <B, V> StreamCodec<B, V> unit(V value) {
return new StreamCodec<>() {
@Override
public V decode(B buf) {
return value;
}
@Override
public void encode(B buf, V value2) {
}
};
}
static <B, C1, V> StreamCodec<B, V> composite(
StreamCodec<B, C1> codec1, Function<V, C1> getter1,
Function<C1, V> factory) {
return new StreamCodec<>() {
@Override
public V decode(B buf) {
C1 v1 = codec1.decode(buf);
return factory.apply(v1);
}
@Override
public void encode(B buf, V value) {
codec1.encode(buf, getter1.apply(value));
}
};
}
interface Factory2<C1, C2, V> {
V create(C1 c1, C2 c2);
}
static <B, C1, C2, V> StreamCodec<B, V> composite(
StreamCodec<B, C1> codec1, Function<V, C1> getter1,
StreamCodec<B, C2> codec2, Function<V, C2> getter2,
Factory2<C1, C2, V> factory) {
return new StreamCodec<>() {
@Override
public V decode(B buf) {
C1 v1 = codec1.decode(buf);
C2 v2 = codec2.decode(buf);
return factory.create(v1, v2);
}
@Override
public void encode(B buf, V value) {
codec1.encode(buf, getter1.apply(value));
codec2.encode(buf, getter2.apply(value));
}
};
}
interface Factory3<C1, C2, C3, V> {
V create(C1 c1, C2 c2, C3 c3);
}
static <B, C1, C2, C3, V> StreamCodec<B, V> composite(
StreamCodec<B, C1> codec1, Function<V, C1> getter1,
StreamCodec<B, C2> codec2, Function<V, C2> getter2,
StreamCodec<B, C3> codec3, Function<V, C3> getter3,
Factory3<C1, C2, C3, V> factory) {
return new StreamCodec<>() {
@Override
public V decode(B buf) {
C1 v1 = codec1.decode(buf);
C2 v2 = codec2.decode(buf);
C3 v3 = codec3.decode(buf);
return factory.create(v1, v2, v3);
}
@Override
public void encode(B buf, V value) {
codec1.encode(buf, getter1.apply(value));
codec2.encode(buf, getter2.apply(value));
codec3.encode(buf, getter3.apply(value));
}
};
}
interface Factory4<C1, C2, C3, C4, V> {
V create(C1 c1, C2 c2, C3 c3, C4 c4);
}
static <B, C1, C2, C3, C4, V> StreamCodec<B, V> composite(
StreamCodec<B, C1> codec1, Function<V, C1> getter1,
StreamCodec<B, C2> codec2, Function<V, C2> getter2,
StreamCodec<B, C3> codec3, Function<V, C3> getter3,
StreamCodec<B, C4> codec4, Function<V, C4> getter4,
Factory4<C1, C2, C3, C4, V> factory) {
return new StreamCodec<>() {
@Override
public V decode(B buf) {
C1 v1 = codec1.decode(buf);
C2 v2 = codec2.decode(buf);
C3 v3 = codec3.decode(buf);
C4 v4 = codec4.decode(buf);
return factory.create(v1, v2, v3, v4);
}
@Override
public void encode(B buf, V value) {
codec1.encode(buf, getter1.apply(value));
codec2.encode(buf, getter2.apply(value));
codec3.encode(buf, getter3.apply(value));
codec4.encode(buf, getter4.apply(value));
}
};
}
interface Factory5<C1, C2, C3, C4, C5, V> {
V create(C1 c1, C2 c2, C3 c3, C4 c4, C5 c5);
}
static <B, C1, C2, C3, C4, C5, V> StreamCodec<B, V> composite(
StreamCodec<B, C1> codec1, Function<V, C1> getter1,
StreamCodec<B, C2> codec2, Function<V, C2> getter2,
StreamCodec<B, C3> codec3, Function<V, C3> getter3,
StreamCodec<B, C4> codec4, Function<V, C4> getter4,
StreamCodec<B, C5> codec5, Function<V, C5> getter5,
Factory5<C1, C2, C3, C4, C5, V> factory) {
return new StreamCodec<>() {
@Override
public V decode(B buf) {
C1 v1 = codec1.decode(buf);
C2 v2 = codec2.decode(buf);
C3 v3 = codec3.decode(buf);
C4 v4 = codec4.decode(buf);
C5 v5 = codec5.decode(buf);
return factory.create(v1, v2, v3, v4, v5);
}
@Override
public void encode(B buf, V value) {
codec1.encode(buf, getter1.apply(value));
codec2.encode(buf, getter2.apply(value));
codec3.encode(buf, getter3.apply(value));
codec4.encode(buf, getter4.apply(value));
codec5.encode(buf, getter5.apply(value));
}
};
}
interface Factory6<C1, C2, C3, C4, C5, C6, V> {
V create(C1 c1, C2 c2, C3 c3, C4 c4, C5 c5, C6 c6);
}
static <B, C1, C2, C3, C4, C5, C6, V> StreamCodec<B, V> composite(
StreamCodec<B, C1> codec1, Function<V, C1> getter1,
StreamCodec<B, C2> codec2, Function<V, C2> getter2,
StreamCodec<B, C3> codec3, Function<V, C3> getter3,
StreamCodec<B, C4> codec4, Function<V, C4> getter4,
StreamCodec<B, C5> codec5, Function<V, C5> getter5,
StreamCodec<B, C6> codec6, Function<V, C6> getter6,
Factory6<C1, C2, C3, C4, C5, C6, V> factory) {
return new StreamCodec<>() {
@Override
public V decode(B buf) {
C1 v1 = codec1.decode(buf);
C2 v2 = codec2.decode(buf);
C3 v3 = codec3.decode(buf);
C4 v4 = codec4.decode(buf);
C5 v5 = codec5.decode(buf);
C6 v6 = codec6.decode(buf);
return factory.create(v1, v2, v3, v4, v5, v6);
}
@Override
public void encode(B buf, V value) {
codec1.encode(buf, getter1.apply(value));
codec2.encode(buf, getter2.apply(value));
codec3.encode(buf, getter3.apply(value));
codec4.encode(buf, getter4.apply(value));
codec5.encode(buf, getter5.apply(value));
codec6.encode(buf, getter6.apply(value));
}
};
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,54 @@
package com.craisinlord.antarchy.config;
import com.craisinlord.antarchy.Antarchy;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public final class ConfigResetGuard {
public static final int RESET_GENERATION = 6;
private static final String MARKER_FILE_NAME = ".config_generation";
private ConfigResetGuard() {
}
public static void wipeIfNeeded(Path configDir, Path... configFiles) {
Path markerPath = configDir.resolve(MARKER_FILE_NAME);
if (readGeneration(markerPath) >= RESET_GENERATION) {
return;
}
for (Path configFile : configFiles) {
try {
if (Files.deleteIfExists(configFile)) {
Antarchy.LOGGER.info("Reset config file {} to defaults (config generation {})", configFile, RESET_GENERATION);
}
} catch (IOException e) {
Antarchy.LOGGER.warn("Failed to delete config file {} during config reset", configFile, e);
}
}
writeGeneration(markerPath);
}
private static int readGeneration(Path markerPath) {
if (!Files.exists(markerPath)) {
return 0;
}
try {
return Integer.parseInt(Files.readString(markerPath).trim());
} catch (IOException | NumberFormatException e) {
return 0;
}
}
private static void writeGeneration(Path markerPath) {
try {
Files.createDirectories(markerPath.getParent());
Files.writeString(markerPath, Integer.toString(RESET_GENERATION));
} catch (IOException e) {
Antarchy.LOGGER.warn("Failed to write config generation marker at {}", markerPath, e);
}
}
}
@@ -0,0 +1,28 @@
package com.craisinlord.antarchy.content;
import net.minecraft.world.level.GameRules;
public final class AntarchyGameRules {
public static GameRules.Key<GameRules.BooleanValue> RULE_DO_ANT_GREIFING;
public static GameRules.Key<GameRules.BooleanValue> RULE_DO_HERCULES_BEETLE_GREIFING;
public static GameRules.Key<GameRules.BooleanValue> RULE_DO_TERMITE_GREIFING;
public static GameRules.Key<GameRules.BooleanValue> RULE_DO_CAVARYN_HORDES;
private AntarchyGameRules() {
}
public static void bootstrap(BooleanRuleRegistrar registrar) {
if (RULE_DO_ANT_GREIFING != null) {
return;
}
RULE_DO_ANT_GREIFING = registrar.register("doAntGreifing", GameRules.Category.MOBS, true);
RULE_DO_HERCULES_BEETLE_GREIFING = registrar.register("doHerculesBeetleGreifing", GameRules.Category.MOBS, true);
RULE_DO_TERMITE_GREIFING = registrar.register("doTermiteGreifing", GameRules.Category.MOBS, true);
RULE_DO_CAVARYN_HORDES = registrar.register("doCavarynHordes", GameRules.Category.MOBS, true);
}
@FunctionalInterface
public interface BooleanRuleRegistrar {
GameRules.Key<GameRules.BooleanValue> register(String name, GameRules.Category category, boolean defaultValue);
}
}
@@ -0,0 +1,759 @@
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.HerculesBeetleEntity;
import com.craisinlord.antarchy.content.entity.HushProjectileEntity;
import com.craisinlord.antarchy.content.entity.StinkBugEntity;
import com.craisinlord.antarchy.content.entity.WaterBombEntity;
import com.craisinlord.antarchy.content.entity.TriffidEntity;
import com.craisinlord.antarchy.content.entity.CreepingHorrorEntity;
import com.craisinlord.antarchy.content.entity.LurkingTerrorEntity;
import com.craisinlord.antarchy.content.entity.ToreterrorEntity;
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.OctopusBombEntity;
import com.craisinlord.antarchy.content.entity.kraken.KrakenEntity;
import com.craisinlord.antarchy.content.entity.kraken.KrakensGraspThrownTrident;
import com.craisinlord.antarchy.content.entity.kraken.TentacleEntity;
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.entity.portal.DimensionalTearEntity;
import com.craisinlord.antarchy.content.entity.nightmare.NightmareBiteEntity;
import com.craisinlord.antarchy.content.entity.nightmare.NightmarePortalEntity;
import com.craisinlord.antarchy.content.block.entity.AntNestBlockEntity;
import com.craisinlord.antarchy.content.block.entity.DreamCampfireBlockEntity;
import com.craisinlord.antarchy.content.block.entity.SeashellBlockEntity;
import com.craisinlord.antarchy.content.block.entity.WaspNestBlockEntity;
import java.util.function.Supplier;
import net.minecraft.core.Holder;
import net.minecraft.core.particles.SimpleParticleType;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
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.material.Fluid;
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<TentacleEntity>> TENTACLE = (Supplier<EntityType<TentacleEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<KrakensGraspThrownTrident>> KRAKENS_GRASP_TRIDENT = (Supplier<EntityType<KrakensGraspThrownTrident>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<OctopusBombEntity>> OCTOPUS_BOMB = (Supplier<EntityType<OctopusBombEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<NightmarePortalEntity>> NIGHTMARE_PORTAL = (Supplier<EntityType<NightmarePortalEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<DimensionalTearEntity>> DIMENSIONAL_TEAR = (Supplier<EntityType<DimensionalTearEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<NightmareBiteEntity>> NIGHTMARE_BITE = (Supplier<EntityType<NightmareBiteEntity>>) 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<EntityType<ToreterrorEntity>> TORETERROR = (Supplier<EntityType<ToreterrorEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<WaterBombEntity>> WATER_BOMB = (Supplier<EntityType<WaterBombEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<CreepingHorrorEntity>> CREEPING_HORROR = (Supplier<EntityType<CreepingHorrorEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<LurkingTerrorEntity>> LURKING_TERROR = (Supplier<EntityType<LurkingTerrorEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<StinkBugEntity>> STINK_BUG = (Supplier<EntityType<StinkBugEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.RollyPollyEntity>> ROLLY_POLLY = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.RollyPollyEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.CheepEntity>> CHEEP = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.CheepEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.DorrieEntity>> DORRIE = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.DorrieEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<HerculesBeetleEntity>> HERCULES_BEETLE = (Supplier<EntityType<HerculesBeetleEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.OuranwoodDeerEntity>> OURANWOOD_DEER = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.OuranwoodDeerEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.glimmer.GlimmerEntity>> GLIMMER = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.glimmer.GlimmerEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Item> SPIRIT_APPLE = (Supplier<Item>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<MobEffect> GLIMMERING_EFFECT = (Supplier<MobEffect>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.ElkaEntity>> ELKA = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.ElkaEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Item> PEACH = (Supplier<Item>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Item> CORN = (Supplier<Item>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Item> CORN_SEEDS = (Supplier<Item>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> WILD_CORN = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> STAR_CORAL_BLOCK = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> STAR_CORAL = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> STAR_CORAL_FAN = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Item> RAW_VENISON = (Supplier<Item>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Item> COOKED_VENISON = (Supplier<Item>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Item> COOKED_CORNDOG = (Supplier<Item>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Item> GLIMMER_BOTTLE = (Supplier<Item>) UNBOUND;
public static final com.craisinlord.antarchy.content.component.AntarchyItemComponent<com.craisinlord.antarchy.content.entity.glimmer.GlimmerVariant> GLIMMER_VARIANT_COMPONENT =
com.craisinlord.antarchy.content.component.AntarchyItemComponent.of(
"antarchy_glimmer_variant",
variant -> net.minecraft.nbt.StringTag.valueOf(variant.name()),
tag -> com.craisinlord.antarchy.content.entity.glimmer.GlimmerVariant.byName(tag.getAsString()));
@SuppressWarnings("unchecked")
public static Supplier<MenuType<com.craisinlord.antarchy.content.menu.DorrieInventoryMenu>> DORRIE_INVENTORY_MENU = (Supplier<MenuType<com.craisinlord.antarchy.content.menu.DorrieInventoryMenu>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<net.minecraft.world.item.Item> CHEEP_ITEM = (Supplier<net.minecraft.world.item.Item>) 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> SHELLSTONE = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> POLISHED_SHELLSTONE = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> SHELLSTONE_BRICKS = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> CHISELED_SHELLSTONE = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> MOSSY_SHELLSTONE_BRICKS = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> CRACKED_SHELLSTONE_BRICKS = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> MOSSY_SHELLSTONE_BRICK_STAIRS = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> MOSSY_SHELLSTONE_BRICK_SLAB = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> MOSSY_SHELLSTONE_BRICK_WALL = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> SHELLSTONE_STAIRS = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> SHELLSTONE_SLAB = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> SHELLSTONE_WALL = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> POLISHED_SHELLSTONE_STAIRS = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> POLISHED_SHELLSTONE_SLAB = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> POLISHED_SHELLSTONE_WALL = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> SHELLSTONE_BRICK_STAIRS = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> SHELLSTONE_BRICK_SLAB = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> SHELLSTONE_BRICK_WALL = (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> CHITIN_BLOCK = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> CHITIN_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> KRAKEN_TENTACLE = (Supplier<Item>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Item> KRAKENS_GRASP = (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<Item> CRITTER_CAGE = (Supplier<Item>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Item> STINK_BUG_ITEM = (Supplier<Item>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<MobEffect> DREAD = (Supplier<MobEffect>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Holder<Attribute>> SCALE = (Supplier<Holder<Attribute>>) 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<MobEffect> BLOODGLASS_WARD = (Supplier<MobEffect>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<MobEffect> PARALYZED_EFFECT = (Supplier<MobEffect>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<MobEffect> INVERTED_EFFECT = (Supplier<MobEffect>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<MobEffect> STINKY_EFFECT = (Supplier<MobEffect>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Fluid> LUMEN = (Supplier<Fluid>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Fluid> FLOWING_LUMEN = (Supplier<Fluid>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Item> LUMEN_BUCKET = (Supplier<Item>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> LUMEN_BLOCK = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> LUMEN_FROGLIGHT = (Supplier<Block>) 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> BED_BUG_EGG = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> CREEPING_HORROR_EGGS = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> LURKING_TERROR_EGGS = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> WASP_NEST = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> UMBRAL_MOSS_BLOCK = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> UMBRAL_MOSS_CARPET = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> BLUSH_MOSS_BLOCK = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> BLUSH_MOSS_CARPET = (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<Block> BRUTALFLY_COCOON_SPAWNER = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> GIANT_LILY_PAD = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> LOTUS = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> SEASHELL = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> CRITTER_CAGE_BLOCK = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<Block> LUCID_ANCHOR = (Supplier<Block>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<BlockEntityType<com.craisinlord.antarchy.content.block.entity.LucidAnchorBlockEntity>> LUCID_ANCHOR_BLOCK_ENTITY =
(Supplier<BlockEntityType<com.craisinlord.antarchy.content.block.entity.LucidAnchorBlockEntity>>) 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;
@SuppressWarnings("unchecked")
public static Supplier<BlockEntityType<SeashellBlockEntity>> SEASHELL_BLOCK_ENTITY = (Supplier<BlockEntityType<SeashellBlockEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<BlockEntityType<com.craisinlord.antarchy.content.block.entity.CritterCageBlockEntity>> CRITTER_CAGE_BLOCK_ENTITY =
(Supplier<BlockEntityType<com.craisinlord.antarchy.content.block.entity.CritterCageBlockEntity>>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<SimpleParticleType> STINKY_GAS = (Supplier<SimpleParticleType>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<SimpleParticleType> NIGHTMARE_FIRE_FLAME = (Supplier<SimpleParticleType>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<SimpleParticleType> STINKY_FLY = (Supplier<SimpleParticleType>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<SimpleParticleType> PEACH_LEAVES_PARTICLE = (Supplier<SimpleParticleType>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<SimpleParticleType> LOTUS_POLLEN = (Supplier<SimpleParticleType>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<SimpleParticleType> LUCID_BOLT_IMPACT_SMALL = (Supplier<SimpleParticleType>) UNBOUND;
@SuppressWarnings("unchecked")
public static Supplier<SimpleParticleType> LUCID_BOLT_IMPACT_LARGE = (Supplier<SimpleParticleType>) UNBOUND;
public static final com.craisinlord.antarchy.content.component.AntarchyItemComponent<net.minecraft.util.Unit> AMERICAN_COMPONENT =
com.craisinlord.antarchy.content.component.AntarchyItemComponent.ofMarker("antarchy_american");
@SuppressWarnings("unchecked")
public static Supplier<net.minecraft.world.entity.EntityType<com.craisinlord.antarchy.content.entity.CritterCageProjectileEntity>> CRITTER_CAGE_PROJECTILE =
(Supplier<net.minecraft.world.entity.EntityType<com.craisinlord.antarchy.content.entity.CritterCageProjectileEntity>>) UNBOUND;
public static final com.craisinlord.antarchy.content.component.AntarchyItemComponent<net.minecraft.resources.ResourceLocation> CRITTER_CAGE_ENTITY_TYPE_COMPONENT =
com.craisinlord.antarchy.content.component.AntarchyItemComponent.of(
"antarchy_critter_cage_entity_type",
rl -> net.minecraft.nbt.StringTag.valueOf(rl.toString()),
tag -> new net.minecraft.resources.ResourceLocation(tag.getAsString()));
public static final com.craisinlord.antarchy.content.component.AntarchyItemComponent<Integer> CRITTER_CAGE_PRIMARY_COLOR_COMPONENT =
com.craisinlord.antarchy.content.component.AntarchyItemComponent.ofInt("antarchy_critter_cage_primary_color");
public static final com.craisinlord.antarchy.content.component.AntarchyItemComponent<Integer> CRITTER_CAGE_SECONDARY_COLOR_COMPONENT =
com.craisinlord.antarchy.content.component.AntarchyItemComponent.ofInt("antarchy_critter_cage_secondary_color");
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<EntityType<ToreterrorEntity>> toreterror,
Supplier<EntityType<WaterBombEntity>> waterBomb,
Supplier<EntityType<CreepingHorrorEntity>> creepingHorror,
Supplier<EntityType<LurkingTerrorEntity>> lurkingTerror,
Supplier<EntityType<StinkBugEntity>> stinkBug,
Supplier<EntityType<com.craisinlord.antarchy.content.entity.CheepEntity>> cheep,
Supplier<EntityType<com.craisinlord.antarchy.content.entity.DorrieEntity>> dorrie,
Supplier<Block> duplicatorLog,
Supplier<Block> duplicatorSapling,
Supplier<Block> ductTape,
Supplier<Block> infestedRootedDirt,
Supplier<Block> infestedCoarseDirt,
Supplier<Block> nyxite,
Supplier<Block> shellstone,
Supplier<Block> polishedShellstone,
Supplier<Block> shellstoneBricks,
Supplier<Block> chiseledShellstone,
Supplier<Block> mossyShellstoneBricks,
Supplier<Block> crackedShellstoneBricks,
Supplier<Block> mossyShellstoneBrickStairs,
Supplier<Block> mossyShellstoneBrickSlab,
Supplier<Block> mossyShellstoneBrickWall,
Supplier<Block> shellstoneStairs,
Supplier<Block> shellstoneSlab,
Supplier<Block> shellstoneWall,
Supplier<Block> polishedShellstoneStairs,
Supplier<Block> polishedShellstoneSlab,
Supplier<Block> polishedShellstoneWall,
Supplier<Block> shellstoneBrickStairs,
Supplier<Block> shellstoneBrickSlab,
Supplier<Block> shellstoneBrickWall,
Supplier<Block> cloudBlock,
Supplier<Block> triffidGooBlock,
Supplier<Block> paleNyxite,
Supplier<Block> nyxiteSpike,
Supplier<Block> chitinBlock,
Supplier<Block> chitinSpike,
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<Item> stinkBugItem,
Supplier<MobEffect> dread,
Supplier<MobEffect> paralyzedEffect,
Supplier<MobEffect> invertedEffect,
Supplier<MobEffect> stinkyEffect,
Supplier<Block> ouranwoodAcornBlock,
Supplier<Block> mossyOuranwoodLog,
Supplier<Block> mossyOuranwoodWood,
Supplier<Block> umbralMossBlock,
Supplier<Block> umbralMossCarpet,
Supplier<Block> blushMossBlock,
Supplier<Block> blushMossCarpet,
Supplier<Block> orangeMilkweed,
Supplier<Block> pinkMilkweed,
Supplier<Block> bedBugEggs,
Supplier<Block> creepingHorrorEggs,
Supplier<Block> lurkingTerrorEggs,
Supplier<Block> waspNest,
Supplier<Block> hushweed,
Supplier<Block> squirrelNestBlock,
Supplier<Block> brutalflyCocoonSpawner,
Supplier<Block> giantLilyPad,
Supplier<Block> seashell,
Supplier<BlockEntityType<AntNestBlockEntity>> antNestBlockEntity,
Supplier<BlockEntityType<DreamCampfireBlockEntity>> dreamCampfireBlockEntity,
Supplier<BlockEntityType<WaspNestBlockEntity>> waspNestBlockEntity,
Supplier<BlockEntityType<HushweedBlockEntity>> hushweedBlockEntity,
Supplier<BlockEntityType<SeashellBlockEntity>> seashellBlockEntity,
Supplier<SimpleParticleType> stinkyGas,
Supplier<SimpleParticleType> stinkyFly,
Supplier<SimpleParticleType> peachLeaves,
Supplier<Holder<Attribute>> scale,
Supplier<Holder<Attribute>> doubleDamageChance,
Supplier<Holder<Attribute>> bloodglassMaxHearts,
Supplier<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;
TORETERROR = toreterror;
WATER_BOMB = waterBomb;
CREEPING_HORROR = creepingHorror;
LURKING_TERROR = lurkingTerror;
STINK_BUG = stinkBug;
CHEEP = cheep;
DORRIE = dorrie;
DUPLICATOR_LOG = duplicatorLog;
DUPLICATOR_SAPLING = duplicatorSapling;
DUCT_TAPE = ductTape;
INFESTED_ROOTED_DIRT = infestedRootedDirt;
INFESTED_COARSE_DIRT = infestedCoarseDirt;
NYXITE = nyxite;
SHELLSTONE = shellstone;
POLISHED_SHELLSTONE = polishedShellstone;
SHELLSTONE_BRICKS = shellstoneBricks;
CHISELED_SHELLSTONE = chiseledShellstone;
MOSSY_SHELLSTONE_BRICKS = mossyShellstoneBricks;
CRACKED_SHELLSTONE_BRICKS = crackedShellstoneBricks;
MOSSY_SHELLSTONE_BRICK_STAIRS = mossyShellstoneBrickStairs;
MOSSY_SHELLSTONE_BRICK_SLAB = mossyShellstoneBrickSlab;
MOSSY_SHELLSTONE_BRICK_WALL = mossyShellstoneBrickWall;
SHELLSTONE_STAIRS = shellstoneStairs;
SHELLSTONE_SLAB = shellstoneSlab;
SHELLSTONE_WALL = shellstoneWall;
POLISHED_SHELLSTONE_STAIRS = polishedShellstoneStairs;
POLISHED_SHELLSTONE_SLAB = polishedShellstoneSlab;
POLISHED_SHELLSTONE_WALL = polishedShellstoneWall;
SHELLSTONE_BRICK_STAIRS = shellstoneBrickStairs;
SHELLSTONE_BRICK_SLAB = shellstoneBrickSlab;
SHELLSTONE_BRICK_WALL = shellstoneBrickWall;
CLOUD_BLOCK = cloudBlock;
TRIFFID_GOO_BLOCK = triffidGooBlock;
PALE_NYXITE = paleNyxite;
NYXITE_SPIKE = nyxiteSpike;
CHITIN_BLOCK = chitinBlock;
CHITIN_SPIKE = chitinSpike;
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;
STINK_BUG_ITEM = stinkBugItem;
DREAD = dread;
PARALYZED_EFFECT = paralyzedEffect;
INVERTED_EFFECT = invertedEffect;
STINKY_EFFECT = stinkyEffect;
OURANWOOD_ACORN_BLOCK = ouranwoodAcornBlock;
MOSSY_OURANWOOD_LOG = mossyOuranwoodLog;
MOSSY_OURANWOOD_WOOD = mossyOuranwoodWood;
UMBRAL_MOSS_BLOCK = umbralMossBlock;
UMBRAL_MOSS_CARPET = umbralMossCarpet;
BLUSH_MOSS_BLOCK = blushMossBlock;
BLUSH_MOSS_CARPET = blushMossCarpet;
ORANGE_MILKWEED = orangeMilkweed;
PINK_MILKWEED = pinkMilkweed;
BED_BUG_EGG = bedBugEggs;
CREEPING_HORROR_EGGS = creepingHorrorEggs;
LURKING_TERROR_EGGS = lurkingTerrorEggs;
WASP_NEST = waspNest;
HUSHWEED = hushweed;
SQUIRREL_NEST_BLOCK = squirrelNestBlock;
BRUTALFLY_COCOON_SPAWNER = brutalflyCocoonSpawner;
GIANT_LILY_PAD = giantLilyPad;
SEASHELL = seashell;
ANT_NEST_BLOCK_ENTITY = antNestBlockEntity;
DREAM_CAMPFIRE_BLOCK_ENTITY = dreamCampfireBlockEntity;
WASP_NEST_BLOCK_ENTITY = waspNestBlockEntity;
HUSHWEED_BLOCK_ENTITY = hushweedBlockEntity;
SEASHELL_BLOCK_ENTITY = seashellBlockEntity;
STINKY_GAS = stinkyGas;
STINKY_FLY = stinkyFly;
PEACH_LEAVES_PARTICLE = peachLeaves;
SCALE = scale;
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());
}
public static void setOctopusBomb(Supplier<EntityType<OctopusBombEntity>> supplier) {
OCTOPUS_BOMB = supplier;
}
public static void setTentacle(Supplier<EntityType<TentacleEntity>> supplier) {
TENTACLE = supplier;
}
public static void setNightmarePortal(Supplier<EntityType<NightmarePortalEntity>> supplier) {
NIGHTMARE_PORTAL = supplier;
}
public static void setDimensionalTear(Supplier<EntityType<DimensionalTearEntity>> supplier) {
DIMENSIONAL_TEAR = supplier;
}
public static void setNightmareBite(Supplier<EntityType<NightmareBiteEntity>> supplier) {
NIGHTMARE_BITE = supplier;
}
public static void setLotus(Supplier<Block> supplier) {
LOTUS = supplier;
}
public static void setKrakensGraspTrident(Supplier<EntityType<KrakensGraspThrownTrident>> supplier) {
KRAKENS_GRASP_TRIDENT = supplier;
}
public static void setKrakenTentacle(Supplier<Item> supplier) {
KRAKEN_TENTACLE = supplier;
}
public static void setKrakensGrasp(Supplier<Item> supplier) {
KRAKENS_GRASP = supplier;
}
public static void setHerculesBeetle(Supplier<EntityType<HerculesBeetleEntity>> supplier) {
HERCULES_BEETLE = supplier;
}
public static void setOuranwoodDeer(Supplier<EntityType<com.craisinlord.antarchy.content.entity.OuranwoodDeerEntity>> supplier) {
OURANWOOD_DEER = supplier;
}
public static void setGlimmer(Supplier<EntityType<com.craisinlord.antarchy.content.entity.glimmer.GlimmerEntity>> supplier) {
GLIMMER = supplier;
}
public static void setRollyPolly(Supplier<EntityType<com.craisinlord.antarchy.content.entity.RollyPollyEntity>> supplier) {
ROLLY_POLLY = supplier;
}
public static void setLumen(Supplier<Fluid> supplier) {
LUMEN = supplier;
}
public static void setFlowingLumen(Supplier<Fluid> supplier) {
FLOWING_LUMEN = supplier;
}
public static void setLumenBucket(Supplier<Item> supplier) {
LUMEN_BUCKET = supplier;
}
public static void setLumenBlock(Supplier<Block> supplier) {
LUMEN_BLOCK = supplier;
}
public static void setLumenFroglight(Supplier<Block> supplier) {
LUMEN_FROGLIGHT = supplier;
}
public static void setSpiritApple(Supplier<Item> supplier) {
SPIRIT_APPLE = supplier;
}
public static void setGlimmeringEffect(Supplier<MobEffect> supplier) {
GLIMMERING_EFFECT = supplier;
}
public static void setElka(Supplier<EntityType<com.craisinlord.antarchy.content.entity.ElkaEntity>> supplier) {
ELKA = supplier;
}
public static void setPeach(Supplier<Item> supplier) {
PEACH = supplier;
}
public static void setCorn(Supplier<Item> supplier) {
CORN = supplier;
}
public static void setCornSeeds(Supplier<Item> supplier) {
CORN_SEEDS = supplier;
}
public static void setWildCorn(Supplier<Block> supplier) {
WILD_CORN = supplier;
}
public static void setCritterCageBlock(Supplier<Block> supplier) {
CRITTER_CAGE_BLOCK = supplier;
}
public static void setLucidAnchor(Supplier<Block> supplier) {
LUCID_ANCHOR = supplier;
}
public static void setLucidAnchorBlockEntity(Supplier<BlockEntityType<com.craisinlord.antarchy.content.block.entity.LucidAnchorBlockEntity>> supplier) {
LUCID_ANCHOR_BLOCK_ENTITY = supplier;
}
public static void setStarCoralBlock(Supplier<Block> supplier) {
STAR_CORAL_BLOCK = supplier;
}
public static void setStarCoral(Supplier<Block> supplier) {
STAR_CORAL = supplier;
}
public static void setStarCoralFan(Supplier<Block> supplier) {
STAR_CORAL_FAN = supplier;
}
public static void setRawVenison(Supplier<Item> supplier) {
RAW_VENISON = supplier;
}
public static void setCookedVenison(Supplier<Item> supplier) {
COOKED_VENISON = supplier;
}
public static void setCookedCorndog(Supplier<Item> supplier) {
COOKED_CORNDOG = supplier;
}
public static void setGlimmerBottle(Supplier<Item> supplier) {
GLIMMER_BOTTLE = supplier;
}
public static void setCritterCage(Supplier<Item> supplier) {
CRITTER_CAGE = supplier;
}
public static void setLotusPollen(Supplier<SimpleParticleType> supplier) {
LOTUS_POLLEN = supplier;
}
public static void setNightmareFireFlame(Supplier<SimpleParticleType> supplier) {
NIGHTMARE_FIRE_FLAME = supplier;
}
public static void setLucidBoltImpactSmall(Supplier<SimpleParticleType> supplier) {
LUCID_BOLT_IMPACT_SMALL = supplier;
}
public static void setLucidBoltImpactLarge(Supplier<SimpleParticleType> supplier) {
LUCID_BOLT_IMPACT_LARGE = supplier;
}
public static void setPeachLeavesParticle(Supplier<SimpleParticleType> supplier) {
PEACH_LEAVES_PARTICLE = supplier;
}
public static void setDorrieInventoryMenu(Supplier<MenuType<com.craisinlord.antarchy.content.menu.DorrieInventoryMenu>> supplier) {
DORRIE_INVENTORY_MENU = supplier;
}
public static void setCritterCageBlockEntity(Supplier<BlockEntityType<com.craisinlord.antarchy.content.block.entity.CritterCageBlockEntity>> supplier) {
CRITTER_CAGE_BLOCK_ENTITY = supplier;
}
public static void setCritterCageProjectile(Supplier<net.minecraft.world.entity.EntityType<com.craisinlord.antarchy.content.entity.CritterCageProjectileEntity>> supplier) {
CRITTER_CAGE_PROJECTILE = supplier;
}
public static BlockBehaviour.Properties shellstoneProperties() {
return BlockBehaviour.Properties.copy(Blocks.STONE).requiresCorrectToolForDrops();
}
}
@@ -0,0 +1,496 @@
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> BOMBER_WALK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BOMBER_KNOCK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BOMBER_EXPLODE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TORETERROR_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TORETERROR_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TORETERROR_DEATH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TORETERROR_BOMBER_FIRE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TORETERROR_SPIN = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TORETERROR_RICOCHET = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> WATER_CANNON_FIRE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TORETERROR_JUMP_UP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> TORETERROR_JUMP_LAND = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> STINKY_FLY = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> STINK_BUG_FART = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> STINK_BUG_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CAVARYN_HEARTBEAT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> ROLLY_POLLY_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CREEPING_HORROR_GROWL = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CREEPING_HORROR_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> CREEPING_HORROR_BITE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> LURKING_TERROR_SNARL = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> LURKING_TERROR_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> LURKING_TERROR_BITE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> LURKING_TERROR_FLY_LOOP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> DUCT_TAPE_USE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> HERCULES_BEETLE_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> HERCULES_BEETLE_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> HERCULES_BEETLE_ATTACK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> HERCULES_BEETLE_CRY = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> HERCULES_BEETLE_CHARGE_START = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> HERCULES_BEETLE_KNOCKED_DOWN = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> JUMPY_BUG_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> SPIT_BUG_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> JUMPY_BUG_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> JUMPY_BUG_JUMP = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> SPIT_BUG_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> SPIT_BUG_SPIT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> BRUTALFLY_SPIT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> ROLLY_POLLY_WHEEL_MODE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> ROLLY_POLLY_NORMAL_MODE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> ROLLY_POLLY_ROLL = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> JERRY_YOUNG_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> JERRY_YOUNG_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> JERRY_YOUNG_DEATH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> JERRY_YOUNG_ATTACK = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> JERRY_ADULT_IDLE = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> JERRY_ADULT_HURT = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> JERRY_ADULT_DEATH = (Supplier<SoundEvent>) UNBOUND;
public static Supplier<SoundEvent> JERRY_ADULT_ATTACK = (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> bomberWalk,
Supplier<SoundEvent> bomberKnock,
Supplier<SoundEvent> bomberExplode,
Supplier<SoundEvent> toreterrorIdle,
Supplier<SoundEvent> toreterrorHurt,
Supplier<SoundEvent> toreterrorDeath,
Supplier<SoundEvent> toreterrorBomberFire,
Supplier<SoundEvent> toreterrorSpin,
Supplier<SoundEvent> toreterrorRicochet,
Supplier<SoundEvent> waterCannonFire,
Supplier<SoundEvent> toreterrorJumpUp,
Supplier<SoundEvent> toreterrorJumpLand,
Supplier<SoundEvent> stinkyFly,
Supplier<SoundEvent> stinkBugFart,
Supplier<SoundEvent> stinkBugIdle,
Supplier<SoundEvent> cavarynHeartbeat,
Supplier<SoundEvent> rollyPollyIdle,
Supplier<SoundEvent> creepingHorrorGrowl,
Supplier<SoundEvent> creepingHorrorHurt,
Supplier<SoundEvent> creepingHorrorBite,
Supplier<SoundEvent> lurkingTerrorSnarl,
Supplier<SoundEvent> lurkingTerrorHurt,
Supplier<SoundEvent> lurkingTerrorBite,
Supplier<SoundEvent> lurkingTerrorFlyLoop,
Supplier<SoundEvent> ductTapeUse,
Supplier<SoundEvent> herculesBeetleIdle,
Supplier<SoundEvent> herculesBeetleHurt,
Supplier<SoundEvent> herculesBeetleAttack,
Supplier<SoundEvent> herculesBeetleCry,
Supplier<SoundEvent> herculesBeetleChargeStart,
Supplier<SoundEvent> herculesBeetleKnockedDown,
Supplier<SoundEvent> jumpyBugIdle,
Supplier<SoundEvent> spitBugIdle,
Supplier<SoundEvent> jumpyBugHurt,
Supplier<SoundEvent> jumpyBugJump,
Supplier<SoundEvent> spitBugHurt,
Supplier<SoundEvent> spitBugSpit,
Supplier<SoundEvent> brutalflySpit,
Supplier<SoundEvent> rollyPollyWheelMode,
Supplier<SoundEvent> rollyPollyNormalMode,
Supplier<SoundEvent> rollyPollyRoll,
Supplier<SoundEvent> jerryYoungIdle,
Supplier<SoundEvent> jerryYoungHurt,
Supplier<SoundEvent> jerryYoungDeath,
Supplier<SoundEvent> jerryYoungAttack,
Supplier<SoundEvent> jerryAdultIdle,
Supplier<SoundEvent> jerryAdultHurt,
Supplier<SoundEvent> jerryAdultDeath,
Supplier<SoundEvent> jerryAdultAttack
) {
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;
BOMBER_WALK = bomberWalk;
BOMBER_KNOCK = bomberKnock;
BOMBER_EXPLODE = bomberExplode;
TORETERROR_IDLE = toreterrorIdle;
TORETERROR_HURT = toreterrorHurt;
TORETERROR_DEATH = toreterrorDeath;
TORETERROR_BOMBER_FIRE = toreterrorBomberFire;
TORETERROR_SPIN = toreterrorSpin;
TORETERROR_RICOCHET = toreterrorRicochet;
WATER_CANNON_FIRE = waterCannonFire;
TORETERROR_JUMP_UP = toreterrorJumpUp;
TORETERROR_JUMP_LAND = toreterrorJumpLand;
STINKY_FLY = stinkyFly;
STINK_BUG_FART = stinkBugFart;
STINK_BUG_IDLE = stinkBugIdle;
CAVARYN_HEARTBEAT = cavarynHeartbeat;
ROLLY_POLLY_IDLE = rollyPollyIdle;
CREEPING_HORROR_GROWL = creepingHorrorGrowl;
CREEPING_HORROR_HURT = creepingHorrorHurt;
CREEPING_HORROR_BITE = creepingHorrorBite;
LURKING_TERROR_SNARL = lurkingTerrorSnarl;
LURKING_TERROR_HURT = lurkingTerrorHurt;
LURKING_TERROR_BITE = lurkingTerrorBite;
LURKING_TERROR_FLY_LOOP = lurkingTerrorFlyLoop;
DUCT_TAPE_USE = ductTapeUse;
HERCULES_BEETLE_IDLE = herculesBeetleIdle;
HERCULES_BEETLE_HURT = herculesBeetleHurt;
HERCULES_BEETLE_ATTACK = herculesBeetleAttack;
HERCULES_BEETLE_CRY = herculesBeetleCry;
HERCULES_BEETLE_CHARGE_START = herculesBeetleChargeStart;
HERCULES_BEETLE_KNOCKED_DOWN = herculesBeetleKnockedDown;
JUMPY_BUG_IDLE = jumpyBugIdle;
SPIT_BUG_IDLE = spitBugIdle;
JUMPY_BUG_HURT = jumpyBugHurt;
JUMPY_BUG_JUMP = jumpyBugJump;
SPIT_BUG_HURT = spitBugHurt;
SPIT_BUG_SPIT = spitBugSpit;
BRUTALFLY_SPIT = brutalflySpit;
ROLLY_POLLY_WHEEL_MODE = rollyPollyWheelMode;
ROLLY_POLLY_NORMAL_MODE = rollyPollyNormalMode;
ROLLY_POLLY_ROLL = rollyPollyRoll;
JERRY_YOUNG_IDLE = jerryYoungIdle;
JERRY_YOUNG_HURT = jerryYoungHurt;
JERRY_YOUNG_DEATH = jerryYoungDeath;
JERRY_YOUNG_ATTACK = jerryYoungAttack;
JERRY_ADULT_IDLE = jerryAdultIdle;
JERRY_ADULT_HURT = jerryAdultHurt;
JERRY_ADULT_DEATH = jerryAdultDeath;
JERRY_ADULT_ATTACK = jerryAdultAttack;
}
}
@@ -0,0 +1,146 @@
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;
import net.minecraft.world.level.material.Fluid;
public final class AntarchyTags {
private AntarchyTags() {
}
private static ResourceLocation id(String path) {
return new ResourceLocation(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"));
public static final TagKey<Block> BLUSH_MOSS_REPLACEABLE = TagKey.create(Registries.BLOCK, id("blush_moss_replaceable"));
public static final TagKey<Block> BIOWART_REPLACEABLE = TagKey.create(Registries.BLOCK, id("biowart_replaceable"));
public static final TagKey<Block> BIOWART_TENDRILS_PLANTABLE = TagKey.create(Registries.BLOCK, id("biowart_tendrils_plantable"));
public static final TagKey<Block> HERCULES_BEETLE_CHARGE_IMMUNE_BLOCKS = TagKey.create(Registries.BLOCK, id("hercules_beetle_charge_immune_blocks"));
public static final TagKey<Block> ELYTHIA_PORTAL_FRAMES = TagKey.create(Registries.BLOCK, id("elythia_portal_frames"));
public static final TagKey<Block> THORAXIS_PORTAL_FRAMES = TagKey.create(Registries.BLOCK, id("thoraxis_portal_frames"));
public static final TagKey<Block> CAVARYN_PORTAL_FRAMES = TagKey.create(Registries.BLOCK, id("cavaryn_portal_frames"));
public static final TagKey<Block> RAINBOW_PORTAL_FRAMES = TagKey.create(Registries.BLOCK, id("rainbow_portal_frames"));
public static final TagKey<Block> ROLLY_CAVERN_CARVEABLE = TagKey.create(Registries.BLOCK, id("rolly_cavern_carveable"));
public static final TagKey<Block> MINERS_DREAM_CARVABLE = TagKey.create(Registries.BLOCK, id("miners_dream_carvable"));
public static final TagKey<Block> BLUESTONE_COMPONENTS = TagKey.create(Registries.BLOCK, id("bluestone_components"));
public static final TagKey<Block> BLUESTONE_CONNECTABLE = TagKey.create(Registries.BLOCK, id("bluestone_connectable"));
public static final TagKey<Block> ANTIMETAL_INVERSION_BLOCKS = TagKey.create(Registries.BLOCK, id("antimetal_inversion_blocks"));
public static final TagKey<Block> LUCID_ANCHOR_BASE_BLOCKS = TagKey.create(Registries.BLOCK, id("lucid_anchor_base_blocks"));
public static final TagKey<Block> TIGER_EYE_CAMOUFLAGE_BLACKLIST = TagKey.create(Registries.BLOCK, id("tiger_eye_camouflage_blacklist"));
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, new ResourceLocation("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<?>> CRITTER_CAGE_BLACKLIST = TagKey.create(Registries.ENTITY_TYPE, id("critter_cage_blacklist"));
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<?>> STINKY_REPELLED_HOSTILES = TagKey.create(Registries.ENTITY_TYPE, id("stinky_repelled_hostiles"));
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"));
public static final TagKey<EntityType<?>> LUCID_ANCHOR_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("lucid_anchor_immune"));
public static final TagKey<EntityType<?>> TIGER_EYE_DETECTION_IMMUNE = TagKey.create(Registries.ENTITY_TYPE, id("tiger_eye_detection_immune"));
public static final TagKey<EntityType<?>> DIMENSIONAL_TEAR_COMMON_SPAWNS = TagKey.create(Registries.ENTITY_TYPE, id("dimensional_tear_common_spawns"));
public static final TagKey<EntityType<?>> DIMENSIONAL_TEAR_RARE_SPAWNS = TagKey.create(Registries.ENTITY_TYPE, id("dimensional_tear_rare_spawns"));
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> MULTISHOT_ENCHANTABLE = TagKey.create(Registries.ITEM, id("multishot_enchantable"));
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"));
public static final TagKey<Item> HERCULES_BEETLE_FOOD = TagKey.create(Registries.ITEM, id("hercules_beetle_food"));
public static final TagKey<Item> ROLLY_POLLY_FOOD = TagKey.create(Registries.ITEM, id("rolly_polly_food"));
public static final TagKey<Item> OURANWOOD_DEER_FOOD = TagKey.create(Registries.ITEM, id("ouranwood_deer_food"));
public static final TagKey<Item> GLIMMER_AUGMENT_APPLE_COW = TagKey.create(Registries.ITEM, id("glimmer_augment_apple_cow"));
public static final TagKey<Item> GLIMMER_AUGMENT_OURANWOOD_DEER = TagKey.create(Registries.ITEM, id("glimmer_augment_ouranwood_deer"));
public static final TagKey<Item> GLIMMER_AUGMENT_FROG = TagKey.create(Registries.ITEM, id("glimmer_augment_frog"));
public static final TagKey<Item> GLIMMER_AUGMENT_ANT = TagKey.create(Registries.ITEM, id("glimmer_augment_ant"));
public static final TagKey<Item> GLIMMER_AUGMENT_ELKA = TagKey.create(Registries.ITEM, id("glimmer_augment_elka"));
public static final TagKey<Item> HFCS_CANNOT_AMERICANIZE = TagKey.create(Registries.ITEM, id("hfcs_cannot_americanize"));
public static final TagKey<Item> TIGER_EYE_ARMOR = TagKey.create(Registries.ITEM, id("tigers_eye_armor"));
private Items() {
}
}
public static final class Fluids {
public static final TagKey<Fluid> LUMEN = TagKey.create(Registries.FLUID, id("lumen"));
public static final TagKey<Fluid> GIANT_LILY_PAD_SUPPORTING_FLUIDS = TagKey.create(Registries.FLUID, id("giant_lily_pad_supporting_fluids"));
public static final TagKey<Fluid> ANTIWATER = TagKey.create(Registries.FLUID, id("antiwater"));
private Fluids() {
}
}
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"));
public static final TagKey<Biome> ELYTHIA_FIREFLY_PARTICLE_BIOMES = TagKey.create(Registries.BIOME, id("elythia_firefly_particle_biomes"));
public static final TagKey<Biome> WILD_CORN_SPAWN_BIOMES = TagKey.create(Registries.BIOME, id("wild_corn_spawn_biomes"));
public static final TagKey<Biome> USES_HORDE_SYSTEM = TagKey.create(Registries.BIOME, id("uses_horde_system"));
private Biomes() {
}
}
}
@@ -0,0 +1,31 @@
package com.craisinlord.antarchy.content.advancement;
import net.minecraft.advancements.Advancement;
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;
}
Advancement advancement = server.getAdvancements().getAdvancement(advancementId);
if (advancement == null) {
return false;
}
return player.getAdvancements().award(advancement, "impossible");
}
@Nullable
public static Advancement get(MinecraftServer server, ResourceLocation advancementId) {
return server.getAdvancements().getAdvancement(advancementId);
}
}
@@ -0,0 +1,87 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.minecart.AntimetalRailHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
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.BaseRailBlock;
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.properties.RailShape;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public abstract class AbstractAntimetalRailBlock extends BaseRailBlock {
protected static final VoxelShape CEILING_FLAT_SHAPE = Block.box(0.0D, 14.0D, 0.0D, 16.0D, 16.0D, 16.0D);
protected static final VoxelShape CEILING_SLOPE_SHAPE = Block.box(0.0D, 6.0D, 0.0D, 16.0D, 16.0D, 16.0D);
protected AbstractAntimetalRailBlock(boolean isStraight, BlockBehaviour.Properties properties) {
super(isStraight, properties);
}
public static boolean isAntimetalRail(BlockState state) {
return state.getBlock() instanceof AbstractAntimetalRailBlock;
}
public static boolean hasCeilingSupport(LevelReader level, BlockPos pos) {
return Block.canSupportCenter(level, pos.above(), Direction.DOWN);
}
@Override
public VoxelShape getShape(BlockState state, net.minecraft.world.level.BlockGetter level, BlockPos pos, CollisionContext context) {
RailShape shape = state.getValue(getShapeProperty());
return shape.isAscending() ? CEILING_SLOPE_SHAPE : CEILING_FLAT_SHAPE;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return hasCeilingSupport(level, pos);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
if (context.getClickedFace() != Direction.DOWN && context.getClickedFace() != Direction.UP && !context.replacingClickedOnBlock()) {
return null;
}
if (!hasCeilingSupport(context.getLevel(), context.getClickedPos())) {
return null;
}
return AntimetalRailHelper.getStateForPlacement(this, context);
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
if (!state.canSurvive(level, pos)) {
return Blocks.AIR.defaultBlockState();
}
if (direction != Direction.DOWN && direction != Direction.UP) {
AntimetalRailHelper.updateConnections(this, state, level, pos);
}
return state;
}
@Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
if (!oldState.is(state.getBlock())) {
AntimetalRailHelper.updateConnections(this, state, level, pos);
}
}
@Override
public void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, BlockPos neighborPos, boolean movedByPiston) {
if (level.isClientSide()) {
return;
}
if (!state.canSurvive(level, pos)) {
dropResources(state, level, pos);
level.removeBlock(pos, movedByPiston);
return;
}
AntimetalRailHelper.updateConnections(this, state, level, pos);
}
}
@@ -0,0 +1,34 @@
package com.craisinlord.antarchy.content.block;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
public abstract class AbstractCeilingBluestoneBlock extends Block {
protected AbstractCeilingBluestoneBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return BluestonePlacementHelper.hasCeilingSupport(level, pos);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return BluestonePlacementHelper.canPlaceOnCeiling(context) ? this.defaultBlockState() : null;
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
if (direction == Direction.UP && !state.canSurvive(level, pos)) {
return net.minecraft.world.level.block.Blocks.AIR.defaultBlockState();
}
return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
}
}
@@ -0,0 +1,34 @@
package com.craisinlord.antarchy.content.block;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.DiodeBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
public abstract class AbstractCeilingDiodeBlock extends DiodeBlock {
protected AbstractCeilingDiodeBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return BluestonePlacementHelper.hasCeilingSupport(level, pos);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return BluestonePlacementHelper.canPlaceOnCeiling(context) ? super.getStateForPlacement(context) : null;
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
if (direction == Direction.UP && !state.canSurvive(level, pos)) {
return net.minecraft.world.level.block.Blocks.AIR.defaultBlockState();
}
return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
}
}
@@ -0,0 +1,35 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.fluid.AntarchyFluidChecks;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.GlowLichenBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
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.level.material.Fluids;
public class AmberLichenBlock extends GlowLichenBlock {
public AmberLichenBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public boolean canPlaceLiquid(BlockGetter level, BlockPos pos, BlockState state, Fluid fluid) {
return fluid == Fluids.WATER || AntarchyFluidChecks.isBile(fluid.defaultFluidState());
}
@Override
public boolean placeLiquid(LevelAccessor level, BlockPos pos, BlockState state, FluidState fluidState) {
if (AntarchyFluidChecks.isBile(fluidState)) {
level.setBlock(pos, fluidState.createLegacyBlock(), 3);
return true;
}
return super.placeLiquid(level, pos, state, fluidState);
}
}
@@ -0,0 +1,47 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import com.mojang.serialization.MapCodec;
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.core.BlockPos;
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 AmberMossBlock extends Block implements BonemealableBlock {
private static final ResourceKey<ConfiguredFeature<?, ?>> AMBER_MOSS_PATCH_BONEMEAL = ResourceKey.create(
Registries.CONFIGURED_FEATURE,
new ResourceLocation(Antarchy.MODID, "amber_moss_patch_bonemeal")
);
public AmberMossBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state, boolean isClient) {
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(AMBER_MOSS_PATCH_BONEMEAL);
feature.value().place(level, level.getChunkSource().getGenerator(), random, pos);
}
}
@@ -0,0 +1,164 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.portal.PermanentPortalManager;
import com.craisinlord.antarchy.content.portal.PermanentPortalType;
import com.craisinlord.antarchy.content.portal.PermanentPortalTeleporter;
import com.mojang.serialization.MapCodec;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public final class AntDimensionPortalBlock extends Block {
public static final EnumProperty<Direction.Axis> AXIS = BlockStateProperties.HORIZONTAL_AXIS;
private static final VoxelShape X_SHAPE = Block.box(0.0D, 0.0D, 6.0D, 16.0D, 16.0D, 10.0D);
private static final VoxelShape Z_SHAPE = Block.box(6.0D, 0.0D, 0.0D, 10.0D, 16.0D, 16.0D);
private static final int PORTAL_TRANSITION_TICKS = 20;
private static final Map<UUID, Integer> PORTAL_ENTRY_TICKS = new HashMap<>();
private final PermanentPortalType type;
public AntDimensionPortalBlock(PermanentPortalType type, BlockBehaviour.Properties properties) {
super(properties);
this.type = type;
this.registerDefaultState(this.stateDefinition.any().setValue(AXIS, Direction.Axis.X));
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(AXIS);
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(AXIS) == Direction.Axis.X ? X_SHAPE : Z_SHAPE;
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return Shapes.empty();
}
@Override
public VoxelShape getVisualShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return Shapes.empty();
}
@Override
public VoxelShape getBlockSupportShape(BlockState state, BlockGetter level, BlockPos pos) {
return Shapes.empty();
}
@Override
public RenderShape getRenderShape(BlockState state) {
return RenderShape.MODEL;
}
@Override
public boolean skipRendering(BlockState state, BlockState adjacentBlockState, Direction side) {
return adjacentBlockState.is(this) || super.skipRendering(state, adjacentBlockState, side);
}
@Override
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
if (level.isClientSide() || !entity.isAlive() || !entity.canChangeDimensions() || entity.isOnPortalCooldown()) {
return;
}
if (!(level instanceof ServerLevel serverLevel)) {
return;
}
int ticks = PORTAL_ENTRY_TICKS.merge(entity.getUUID(), 1, Integer::sum);
if (ticks < PORTAL_TRANSITION_TICKS) {
return;
}
PORTAL_ENTRY_TICKS.remove(entity.getUUID());
PermanentPortalTeleporter.teleport(entity, this.type);
}
@Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
super.onPlace(state, level, pos, oldState, movedByPiston);
if (!level.isClientSide() && !state.is(oldState.getBlock())) {
level.scheduleTick(pos, this, 1);
}
}
@Override
public BlockState updateShape(
BlockState state,
Direction direction,
BlockState neighborState,
LevelAccessor level,
BlockPos pos,
BlockPos neighborPos
) {
if (level instanceof ServerLevel serverLevel) {
serverLevel.scheduleTick(pos, this, 1);
}
return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
}
@Override
public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!PermanentPortalManager.isPortalStillValid(level, pos, this.type, state.getValue(AXIS))) {
level.setBlock(pos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL);
}
}
@Override
public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) {
if (random.nextInt(100) == 0) {
level.playLocalSound(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, SoundEvents.PORTAL_AMBIENT, SoundSource.BLOCKS, 0.35F, 0.9F + random.nextFloat() * 0.2F, false);
}
ParticleOptions particle = switch (this.type) {
case ELYTHIA -> ParticleTypes.SPORE_BLOSSOM_AIR;
case THORAXIS -> ParticleTypes.PORTAL;
case CAVARYN -> ParticleTypes.MYCELIUM;
};
for (int i = 0; i < 4; i++) {
double x = pos.getX() + random.nextDouble();
double y = pos.getY() + random.nextDouble();
double z = pos.getZ() + random.nextDouble();
if (state.getValue(AXIS) == Direction.Axis.X) {
z = pos.getZ() + 0.5D + (random.nextDouble() - 0.5D) * 0.25D;
} else {
x = pos.getX() + 0.5D + (random.nextDouble() - 0.5D) * 0.25D;
}
level.addParticle(
particle,
x,
y,
z,
(random.nextDouble() - 0.5D) * 0.2D,
(random.nextDouble() - 0.5D) * 0.2D,
(random.nextDouble() - 0.5D) * 0.2D
);
}
}
}
@@ -0,0 +1,183 @@
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;
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.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH));
}
@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
public 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.BlockGetter 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());
}
return stack;
}
@Override
public void playerDestroy(Level level, Player player, BlockPos pos, BlockState state, BlockEntity blockEntity, ItemStack stack) {
boolean hasSilkTouch = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, stack) > 0;
ItemStack droppedNest = hasSilkTouch ? this.getCloneItemStack(level, pos, state) : ItemStack.EMPTY;
super.playerDestroy(level, player, pos, state, blockEntity, stack);
if (hasSilkTouch) {
if (!droppedNest.isEmpty() && level instanceof ServerLevel serverLevel) {
Block.popResource(serverLevel, pos, droppedNest);
}
return;
}
if (blockEntity instanceof AntNestBlockEntity nestBlockEntity && level instanceof ServerLevel serverLevel) {
nestBlockEntity.releaseAll(serverLevel);
}
}
@Override
public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) {
if (this.damageSteppers && entity instanceof LivingEntity && !entity.isSteppingCarefully()) {
entity.hurt(level.damageSources().hotFloor(), 1.0F);
}
super.stepOn(level, pos, state, entity);
}
public boolean canAccept(EntityType<?> antType) {
for (EntityType<? extends BaseAntEntity> supportedType : this.antTypes()) {
if (supportedType == antType) {
return true;
}
}
return false;
}
public int maxOccupants() {
return this.maxOccupants;
}
public boolean shouldPopulateInitialAnts() {
return this.populateInitialAnts;
}
public EntityType<? extends BaseAntEntity> initialAntType(RandomSource random) {
List<EntityType<? extends BaseAntEntity>> antTypes = this.antTypes();
if (antTypes.isEmpty()) {
throw new IllegalStateException("Ant nest block must declare at least one supported ant type");
}
return antTypes.get(random.nextInt(antTypes.size()));
}
private List<EntityType<? extends BaseAntEntity>> antTypes() {
return this.antTypesSupplier.get();
}
}
@@ -0,0 +1,47 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.entity.UpwardFallingBlockEntity;
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.LevelAccessor;
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;
public class AntigravelBlock extends Block {
public AntigravelBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
super.onPlace(state, level, pos, oldState, movedByPiston);
if (!level.isClientSide) {
level.scheduleTick(pos, this, 2);
}
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
if (direction == Direction.UP) {
level.scheduleTick(pos, this, 2);
}
return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
}
@Override
public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!level.getBlockState(pos).is(this)) {
return;
}
BlockPos abovePos = pos.above();
BlockState above = level.getBlockState(abovePos);
boolean passable = above.isAir() || above.getCollisionShape(level, abovePos).isEmpty();
if (passable) {
UpwardFallingBlockEntity.fallUp(level, pos, state);
}
}
}
@@ -0,0 +1,59 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
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.EnumProperty;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.block.state.properties.RailShape;
public class AntimetalActivatorRailBlock extends AbstractAntimetalRailBlock {
public static final EnumProperty<RailShape> SHAPE = BlockStateProperties.RAIL_SHAPE_STRAIGHT;
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
public AntimetalActivatorRailBlock(BlockBehaviour.Properties properties) {
super(true, properties);
this.registerDefaultState(this.stateDefinition.any().setValue(SHAPE, RailShape.NORTH_SOUTH).setValue(POWERED, false).setValue(WATERLOGGED, false));
}
@Override
public Property<RailShape> getShapeProperty() {
return SHAPE;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(SHAPE, POWERED, WATERLOGGED);
}
@Override
public void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, BlockPos neighborPos, boolean movedByPiston) {
super.neighborChanged(state, level, pos, neighborBlock, neighborPos, movedByPiston);
updatePoweredState(level, pos, level.getBlockState(pos));
}
@Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
super.onPlace(state, level, pos, oldState, movedByPiston);
if (!oldState.is(state.getBlock())) {
updatePoweredState(level, pos, level.getBlockState(pos));
}
}
private void updatePoweredState(Level level, BlockPos pos, BlockState state) {
if (level.isClientSide() || !(state.getBlock() instanceof AntimetalActivatorRailBlock)) {
return;
}
boolean powered = AntimetalPowerHelper.isPoweredWithChain(level, pos, state, SHAPE, AntimetalActivatorRailBlock.class);
if (state.getValue(POWERED) != powered) {
level.setBlock(pos, state.setValue(POWERED, powered), 3);
AntimetalPowerHelper.notifyAllSignalNeighbors(level, pos);
}
}
}
@@ -0,0 +1,104 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.minecart.AntimetalMinecartAccess;
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.Container;
import net.minecraft.world.entity.vehicle.AbstractMinecart;
import net.minecraft.world.inventory.AbstractContainerMenu;
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 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.EnumProperty;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.block.state.properties.RailShape;
import net.minecraft.world.phys.AABB;
import java.util.List;
public class AntimetalDetectorRailBlock extends AbstractAntimetalRailBlock {
public static final EnumProperty<RailShape> SHAPE = BlockStateProperties.RAIL_SHAPE_STRAIGHT;
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
private static final int CHECK_PERIOD = 20;
public AntimetalDetectorRailBlock(BlockBehaviour.Properties properties) {
super(true, properties);
this.registerDefaultState(this.stateDefinition.any().setValue(SHAPE, RailShape.NORTH_SOUTH).setValue(POWERED, false).setValue(WATERLOGGED, false));
}
@Override
public Property<RailShape> getShapeProperty() {
return SHAPE;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(SHAPE, POWERED, WATERLOGGED);
}
@Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
super.onPlace(state, level, pos, oldState, movedByPiston);
if (!oldState.is(state.getBlock()) && !level.isClientSide()) {
level.scheduleTick(pos, this, CHECK_PERIOD);
}
}
@Override
public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
boolean detected = !getDetectedCarts(level, pos).isEmpty();
if (detected != state.getValue(POWERED)) {
level.setBlock(pos, state.setValue(POWERED, detected), 3);
AntimetalPowerHelper.notifyAllSignalNeighbors(level, pos);
}
level.scheduleTick(pos, this, CHECK_PERIOD);
}
private static List<AbstractMinecart> getDetectedCarts(Level level, BlockPos pos) {
AABB box = new AABB(pos.getX(), pos.getY() - 2.0D, pos.getZ(), pos.getX() + 1.0D, pos.getY() + 1.0D, pos.getZ() + 1.0D);
return level.getEntitiesOfClass(AbstractMinecart.class, box, cart ->
cart instanceof AntimetalMinecartAccess access && pos.equals(access.antarchy$getAntimetalRailPos()));
}
@Override
public boolean isSignalSource(BlockState state) {
return true;
}
@Override
public int getSignal(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
return state.getValue(POWERED) ? 15 : 0;
}
@Override
public int getDirectSignal(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
return state.getValue(POWERED) ? 15 : 0;
}
@Override
public boolean hasAnalogOutputSignal(BlockState state) {
return true;
}
@Override
public int getAnalogOutputSignal(BlockState state, Level level, BlockPos pos) {
if (!state.getValue(POWERED)) {
return 0;
}
int best = 0;
for (AbstractMinecart cart : getDetectedCarts(level, pos)) {
if (cart instanceof Container container) {
best = Math.max(best, AbstractContainerMenu.getRedstoneSignalFromContainer(container));
}
}
return best;
}
}
@@ -0,0 +1,80 @@
package com.craisinlord.antarchy.content.block;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
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.state.BlockState;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.level.block.state.properties.RailShape;
public final class AntimetalPowerHelper {
private static final int MAX_POWER_PROPAGATION = 8;
private AntimetalPowerHelper() {
}
public static boolean hasAnySignal(LevelReader level, BlockPos pos) {
if (level instanceof Level realLevel && realLevel.hasNeighborSignal(pos)) {
return true;
}
return BluestoneSignalHelper.getBestNeighborSignal(level, pos) > 0;
}
public static int getBestAnySignal(LevelReader level, BlockPos pos) {
int vanillaSignal = level instanceof Level realLevel ? realLevel.getBestNeighborSignal(pos) : 0;
int bluestoneSignal = BluestoneSignalHelper.getBestNeighborSignal(level, pos);
return Math.max(vanillaSignal, bluestoneSignal);
}
public static void notifyAllSignalNeighbors(Level level, BlockPos pos) {
level.updateNeighborsAt(pos, level.getBlockState(pos).getBlock());
BluestoneSignalHelper.updateBluestoneNeighbors(level, pos);
}
public static boolean isPoweredWithChain(Level level, BlockPos pos, BlockState state, EnumProperty<RailShape> shapeProperty, Class<? extends Block> railClass) {
if (!railClass.isInstance(state.getBlock())) {
return false;
}
if (hasAnySignal(level, pos)) {
return true;
}
RailShape shape = state.getValue(shapeProperty);
for (Direction direction : exitDirections(shape)) {
if (chain(level, pos, direction, shapeProperty, railClass, 1)) {
return true;
}
}
return false;
}
private static boolean chain(Level level, BlockPos pos, Direction direction, EnumProperty<RailShape> shapeProperty, Class<? extends Block> railClass, int distance) {
if (distance > MAX_POWER_PROPAGATION) {
return false;
}
BlockPos[] candidates = {pos.relative(direction), pos.relative(direction).above(), pos.relative(direction).below()};
for (BlockPos candidate : candidates) {
BlockState candidateState = level.getBlockState(candidate);
if (railClass.isInstance(candidateState.getBlock()) && sameAxis(candidateState.getValue(shapeProperty), direction)) {
if (hasAnySignal(level, candidate)) {
return true;
}
if (chain(level, candidate, direction, shapeProperty, railClass, distance + 1)) {
return true;
}
}
}
return false;
}
private static boolean sameAxis(RailShape shape, Direction direction) {
boolean zAxis = shape == RailShape.NORTH_SOUTH || shape == RailShape.ASCENDING_NORTH || shape == RailShape.ASCENDING_SOUTH;
return direction.getAxis() == (zAxis ? Direction.Axis.Z : Direction.Axis.X);
}
private static Direction[] exitDirections(RailShape shape) {
boolean zAxis = shape == RailShape.NORTH_SOUTH || shape == RailShape.ASCENDING_NORTH || shape == RailShape.ASCENDING_SOUTH;
return zAxis ? new Direction[]{Direction.NORTH, Direction.SOUTH} : new Direction[]{Direction.EAST, Direction.WEST};
}
}
@@ -0,0 +1,112 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
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.EnumProperty;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.block.state.properties.RailShape;
public class AntimetalPoweredRailBlock extends AbstractAntimetalRailBlock {
public static final EnumProperty<RailShape> SHAPE = BlockStateProperties.RAIL_SHAPE_STRAIGHT;
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
public AntimetalPoweredRailBlock(BlockBehaviour.Properties properties) {
super(true, properties);
this.registerDefaultState(this.stateDefinition.any().setValue(SHAPE, RailShape.NORTH_SOUTH).setValue(POWERED, false).setValue(WATERLOGGED, false));
}
@Override
public Property<RailShape> getShapeProperty() {
return SHAPE;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(SHAPE, POWERED, WATERLOGGED);
}
@Override
public void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, BlockPos neighborPos, boolean movedByPiston) {
super.neighborChanged(state, level, pos, neighborBlock, neighborPos, movedByPiston);
updatePoweredState(level, pos, level.getBlockState(pos));
}
@Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
super.onPlace(state, level, pos, oldState, movedByPiston);
if (!oldState.is(state.getBlock())) {
updatePoweredState(level, pos, level.getBlockState(pos));
}
}
private void updatePoweredState(Level level, BlockPos pos, BlockState state) {
if (level.isClientSide() || !(state.getBlock() instanceof AntimetalPoweredRailBlock)) {
return;
}
boolean powered = AntimetalPowerHelper.isPoweredWithChain(level, pos, state, SHAPE, AntimetalPoweredRailBlock.class);
if (state.getValue(POWERED) != powered) {
level.setBlock(pos, state.setValue(POWERED, powered), 3);
AntimetalPowerHelper.notifyAllSignalNeighbors(level, pos.below());
AntimetalPowerHelper.notifyAllSignalNeighbors(level, pos.above());
}
}
@Override
public BlockState rotate(BlockState state, net.minecraft.world.level.block.Rotation rotation) {
return switch (rotation) {
case CLOCKWISE_180 -> switch (state.getValue(SHAPE)) {
case NORTH_SOUTH -> state.setValue(SHAPE, RailShape.NORTH_SOUTH);
case EAST_WEST -> state.setValue(SHAPE, RailShape.EAST_WEST);
case ASCENDING_EAST -> state.setValue(SHAPE, RailShape.ASCENDING_WEST);
case ASCENDING_WEST -> state.setValue(SHAPE, RailShape.ASCENDING_EAST);
case ASCENDING_NORTH -> state.setValue(SHAPE, RailShape.ASCENDING_SOUTH);
case ASCENDING_SOUTH -> state.setValue(SHAPE, RailShape.ASCENDING_NORTH);
default -> state;
};
case CLOCKWISE_90 -> switch (state.getValue(SHAPE)) {
case NORTH_SOUTH -> state.setValue(SHAPE, RailShape.EAST_WEST);
case EAST_WEST -> state.setValue(SHAPE, RailShape.NORTH_SOUTH);
case ASCENDING_EAST -> state.setValue(SHAPE, RailShape.ASCENDING_NORTH);
case ASCENDING_WEST -> state.setValue(SHAPE, RailShape.ASCENDING_SOUTH);
case ASCENDING_NORTH -> state.setValue(SHAPE, RailShape.ASCENDING_WEST);
case ASCENDING_SOUTH -> state.setValue(SHAPE, RailShape.ASCENDING_EAST);
default -> state;
};
case COUNTERCLOCKWISE_90 -> switch (state.getValue(SHAPE)) {
case NORTH_SOUTH -> state.setValue(SHAPE, RailShape.EAST_WEST);
case EAST_WEST -> state.setValue(SHAPE, RailShape.NORTH_SOUTH);
case ASCENDING_EAST -> state.setValue(SHAPE, RailShape.ASCENDING_SOUTH);
case ASCENDING_WEST -> state.setValue(SHAPE, RailShape.ASCENDING_NORTH);
case ASCENDING_NORTH -> state.setValue(SHAPE, RailShape.ASCENDING_EAST);
case ASCENDING_SOUTH -> state.setValue(SHAPE, RailShape.ASCENDING_WEST);
default -> state;
};
default -> state;
};
}
@Override
public BlockState mirror(BlockState state, net.minecraft.world.level.block.Mirror mirror) {
RailShape shape = state.getValue(SHAPE);
return switch (mirror) {
case LEFT_RIGHT -> switch (shape) {
case ASCENDING_NORTH -> state.setValue(SHAPE, RailShape.ASCENDING_SOUTH);
case ASCENDING_SOUTH -> state.setValue(SHAPE, RailShape.ASCENDING_NORTH);
default -> state;
};
case FRONT_BACK -> switch (shape) {
case ASCENDING_EAST -> state.setValue(SHAPE, RailShape.ASCENDING_WEST);
case ASCENDING_WEST -> state.setValue(SHAPE, RailShape.ASCENDING_EAST);
default -> state;
};
default -> state;
};
}
}
@@ -0,0 +1,28 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.block.state.properties.RailShape;
public class AntimetalRailBlock extends AbstractAntimetalRailBlock {
public static final EnumProperty<RailShape> SHAPE = BlockStateProperties.RAIL_SHAPE;
public AntimetalRailBlock(BlockBehaviour.Properties properties) {
super(false, properties);
this.registerDefaultState(this.stateDefinition.any().setValue(SHAPE, RailShape.NORTH_SOUTH).setValue(WATERLOGGED, false));
}
@Override
public Property<RailShape> getShapeProperty() {
return SHAPE;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<net.minecraft.world.level.block.Block, net.minecraft.world.level.block.state.BlockState> builder) {
builder.add(SHAPE, WATERLOGGED);
}
}
@@ -0,0 +1,161 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.entity.UpwardFallingBlockEntity;
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
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.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.ScaffoldingBlock;
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.material.Fluids;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public class AntimetalScaffoldingBlock extends ScaffoldingBlock {
public static final BooleanProperty INVERTED = BooleanProperty.create("inverted");
private static final VoxelShape MIRRORED_STABLE_SHAPE;
private static final VoxelShape MIRRORED_UNSTABLE_SHAPE;
static {
VoxelShape frame = Block.box(0.0D, 0.0D, 0.0D, 16.0D, 2.0D, 16.0D);
VoxelShape post1 = Block.box(0.0D, 0.0D, 0.0D, 2.0D, 16.0D, 2.0D);
VoxelShape post2 = Block.box(14.0D, 0.0D, 0.0D, 16.0D, 16.0D, 2.0D);
VoxelShape post3 = Block.box(0.0D, 0.0D, 14.0D, 2.0D, 16.0D, 16.0D);
VoxelShape post4 = Block.box(14.0D, 0.0D, 14.0D, 16.0D, 16.0D, 16.0D);
MIRRORED_STABLE_SHAPE = Shapes.or(frame, post1, post2, post3, post4);
VoxelShape topSlab = Block.box(0.0D, 14.0D, 0.0D, 16.0D, 16.0D, 16.0D);
VoxelShape edge1 = Block.box(0.0D, 14.0D, 0.0D, 2.0D, 16.0D, 16.0D);
VoxelShape edge2 = Block.box(14.0D, 14.0D, 0.0D, 16.0D, 16.0D, 16.0D);
VoxelShape edge3 = Block.box(0.0D, 14.0D, 0.0D, 16.0D, 16.0D, 2.0D);
VoxelShape edge4 = Block.box(0.0D, 14.0D, 14.0D, 16.0D, 16.0D, 16.0D);
MIRRORED_UNSTABLE_SHAPE = Shapes.or(topSlab, MIRRORED_STABLE_SHAPE, edge1, edge2, edge3, edge4);
}
public AntimetalScaffoldingBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any()
.setValue(DISTANCE, 7)
.setValue(WATERLOGGED, false)
.setValue(BOTTOM, false)
.setValue(INVERTED, false));
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(INVERTED);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockPos pos = context.getClickedPos();
Level level = context.getLevel();
boolean inverted = context.getPlayer() != null && AntarchyGravityApi.isGravityInverted(context.getPlayer());
int distance = getDistance(level, pos, inverted);
if (inverted && distance >= 7) {
return null;
}
return this.defaultBlockState()
.setValue(WATERLOGGED, level.getFluidState(pos).getType() == Fluids.WATER)
.setValue(DISTANCE, distance)
.setValue(BOTTOM, antarchy$isBottom(level, pos, distance, inverted))
.setValue(INVERTED, inverted);
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return getDistance(level, pos, state.getValue(INVERTED)) < 7;
}
@Override
public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
boolean inverted = state.getValue(INVERTED);
int distance = getDistance(level, pos, inverted);
BlockState updated = state.setValue(DISTANCE, distance).setValue(BOTTOM, antarchy$isBottom(level, pos, distance, inverted));
if (updated.getValue(DISTANCE) == 7) {
if (state.getValue(DISTANCE) == 7) {
if (inverted) {
UpwardFallingBlockEntity.fallUp(level, pos, updated);
} else {
FallingBlockEntity.fall(level, pos, updated);
}
} else {
level.destroyBlock(pos, true);
}
} else if (state != updated) {
level.setBlock(pos, updated, 3);
}
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
if (!state.getValue(INVERTED)) {
return super.getShape(state, level, pos, context);
}
if (context.isHoldingItem(state.getBlock().asItem())) {
return Shapes.block();
}
return state.getValue(BOTTOM) ? MIRRORED_UNSTABLE_SHAPE : MIRRORED_STABLE_SHAPE;
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
if (!state.getValue(INVERTED)) {
return super.getCollisionShape(state, level, pos, context);
}
return this.getShape(state, level, pos, context);
}
private static boolean antarchy$isMatchingScaffold(BlockState state, boolean inverted) {
return state.getBlock() instanceof AntimetalScaffoldingBlock && state.getValue(INVERTED) == inverted;
}
public static int getDistance(LevelReader level, BlockPos pos, boolean inverted) {
Direction supportDirection = inverted ? Direction.UP : Direction.DOWN;
BlockPos.MutableBlockPos cursor = pos.mutable().move(supportDirection);
BlockState supportNeighbor = level.getBlockState(cursor);
int distance = 7;
if (antarchy$isMatchingScaffold(supportNeighbor, inverted)) {
distance = supportNeighbor.getValue(DISTANCE);
} else if (supportNeighbor.isFaceSturdy(level, cursor, supportDirection.getOpposite())) {
return 0;
}
for (Direction direction : Direction.Plane.HORIZONTAL) {
BlockPos.MutableBlockPos neighborPos = pos.mutable().move(direction);
BlockState neighbor = level.getBlockState(neighborPos);
if (!antarchy$isMatchingScaffold(neighbor, inverted)) {
continue;
}
distance = Math.min(distance, neighbor.getValue(DISTANCE) + 1);
if (distance == 1) {
break;
}
}
return distance;
}
private static boolean antarchy$isBottom(LevelReader level, BlockPos pos, int distance, boolean inverted) {
if (distance <= 0) {
return false;
}
Direction supportDirection = inverted ? Direction.UP : Direction.DOWN;
return !antarchy$isMatchingScaffold(level.getBlockState(pos.relative(supportDirection)), inverted);
}
}
@@ -0,0 +1,206 @@
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 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 VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(EGGS) > 1 ? MULTI_SHAPE : SINGLE_SHAPE;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
}
@Override
public 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
public 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
public boolean isRandomlyTicking(BlockState state) {
return true;
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!this.shouldUpdateHatchLevel(level)) {
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
public 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);
}
}
public void hatchWithNucleus(ServerLevel level, BlockPos pos, BlockState state) {
this.hatchEggs(level, pos, state, level.random);
}
private void decreaseEggs(Level level, BlockPos pos, BlockState state) {
int eggs = state.getValue(EGGS);
if (eggs <= 1) {
level.destroyBlock(pos, false);
return;
}
level.setBlock(pos, state.setValue(EGGS, eggs - 1), 2);
}
private boolean shouldUpdateHatchLevel(Level level) {
return level.random.nextInt(500) == 0;
}
private boolean canDestroyEgg(Level level, Entity entity) {
if (entity instanceof BedBugEntity || entity instanceof Bat) {
return false;
}
if (entity instanceof net.minecraft.world.entity.LivingEntity) {
return entity instanceof Player || level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
}
return false;
}
}
@@ -0,0 +1,77 @@
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.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 java.util.function.Supplier;
public class BiowartBlock extends Block implements BonemealableBlock {
private static Supplier<? extends Block> biowartTendrils;
public BiowartBlock(BlockBehaviour.Properties properties) {
super(properties);
}
public static void bindTendrils(Supplier<? extends Block> tendrilsSupplier) {
biowartTendrils = tendrilsSupplier;
}
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state, boolean isClient) {
return level.getBlockState(pos.above()).isAir() || hasSpreadTarget(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) {
placeTendrils(level, pos);
BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos();
for (int i = 0; i < 28; i++) {
cursor.setWithOffset(pos, random.nextInt(9) - 4, random.nextInt(3) - 1, random.nextInt(9) - 4);
BlockState target = level.getBlockState(cursor);
if (isBiomite(target)) {
level.setBlock(cursor, this.defaultBlockState(), 3);
placeTendrils(level, cursor);
}
}
}
private static boolean hasSpreadTarget(LevelReader level, BlockPos pos) {
BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos();
for (int x = -3; x <= 3; x++) {
for (int y = -1; y <= 1; y++) {
for (int z = -3; z <= 3; z++) {
cursor.setWithOffset(pos, x, y, z);
if (isBiomite(level.getBlockState(cursor))) {
return true;
}
}
}
}
return false;
}
private static boolean isBiomite(BlockState state) {
return state.is(AntarchyTags.Blocks.BIOWART_REPLACEABLE);
}
private static void placeTendrils(ServerLevel level, BlockPos pos) {
if (biowartTendrils != null && level.isEmptyBlock(pos.above())) {
level.setBlock(pos.above(), biowartTendrils.get().defaultBlockState(), 3);
}
}
}
@@ -0,0 +1,36 @@
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.BlockGetter;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.BushBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class BiowartTendrilsBlock extends BushBlock {
private static final VoxelShape SHAPE = Block.box(2.0D, 0.0D, 2.0D, 14.0D, 10.0D, 14.0D);
public BiowartTendrilsBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos) {
return state.is(AntarchyTags.Blocks.BIOWART_TENDRILS_PLANTABLE) || super.mayPlaceOn(state, level, pos);
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return this.mayPlaceOn(level.getBlockState(pos.below()), level, pos.below());
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
}
@@ -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
public boolean isRandomlyTicking(BlockState state) {
return !state.is(this.cluster.get());
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (random.nextInt(5) != 0) {
return;
}
Direction direction = DIRECTIONS[random.nextInt(DIRECTIONS.length)];
BlockPos targetPos = pos.relative(direction);
BlockState targetState = level.getBlockState(targetPos);
Block nextBlock = null;
if (canGrowInto(targetState)) {
nextBlock = this.smallBud.get();
} else if (isStage(targetState, this.smallBud.get(), direction)) {
nextBlock = this.mediumBud.get();
} else if (isStage(targetState, this.mediumBud.get(), direction)) {
nextBlock = this.largeBud.get();
} else if (isStage(targetState, this.largeBud.get(), direction)) {
nextBlock = this.cluster.get();
}
if (nextBlock == null) {
return;
}
FluidState fluidState = targetState.getFluidState();
BlockState nextState = nextBlock.defaultBlockState()
.setValue(AmethystClusterBlock.FACING, direction)
.setValue(BlockStateProperties.WATERLOGGED, fluidState.getType() == Fluids.WATER && fluidState.getAmount() == 8);
level.setBlockAndUpdate(targetPos, nextState);
}
private static boolean canGrowInto(BlockState state) {
return state.isAir() || state.is(Blocks.WATER) && state.getFluidState().getAmount() == 8;
}
private static boolean isStage(BlockState state, Block block, Direction direction) {
return state.is(block) && state.hasProperty(AmethystClusterBlock.FACING) && state.getValue(AmethystClusterBlock.FACING) == direction;
}
}
@@ -0,0 +1,48 @@
package com.craisinlord.antarchy.content.block;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
public class BluestoneBlock extends Block implements BluestoneSignalSource {
public BluestoneBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public boolean isSignalSource(BlockState state) {
return true;
}
@Override
public int getSignal(BlockState state, net.minecraft.world.level.BlockGetter level, BlockPos pos, Direction direction) {
return 15;
}
@Override
public int getDirectSignal(BlockState state, net.minecraft.world.level.BlockGetter level, BlockPos pos, Direction direction) {
return 15;
}
@Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean moving) {
super.onPlace(state, level, pos, oldState, moving);
BluestoneSignalHelper.updateBluestoneNeighbors(level, pos);
}
@Override
public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
super.onRemove(state, level, pos, newState, movedByPiston);
if (!state.is(newState.getBlock())) {
BluestoneSignalHelper.updateBluestoneNeighbors(level, pos);
}
}
@Override
public int getBluestoneSignal(net.minecraft.world.level.LevelReader level, BlockPos pos, BlockState state, Direction direction) {
return 15;
}
}
@@ -0,0 +1,203 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.block.entity.BluestoneComparatorBlockEntity;
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.DustParticleOptions;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.SignalGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.ComparatorBlock;
import net.minecraft.world.level.block.DiodeBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
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.properties.ComparatorMode;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.util.RandomSource;
import net.minecraft.world.ticks.TickPriority;
import org.joml.Vector3f;
public class BluestoneComparatorBlock extends ComparatorBlock {
private static final VoxelShape SHAPE = Block.box(0.0D, 14.0D, 0.0D, 16.0D, 16.0D, 16.0D);
private static final DustParticleOptions BLUESTONE_PARTICLE = new DustParticleOptions(new Vector3f(0.18F, 0.54F, 1.0F), 1.0F);
private final Supplier<? extends BlockEntityType<BluestoneComparatorBlockEntity>> blockEntityTypeSupplier;
public BluestoneComparatorBlock(BlockBehaviour.Properties properties) {
this(properties, null);
}
public BluestoneComparatorBlock(BlockBehaviour.Properties properties, Supplier<? extends BlockEntityType<BluestoneComparatorBlockEntity>> blockEntityTypeSupplier) {
super(properties);
this.blockEntityTypeSupplier = blockEntityTypeSupplier;
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return BluestonePlacementHelper.hasCeilingSupport(level, pos);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return BluestonePlacementHelper.canPlaceOnCeiling(context) ? super.getStateForPlacement(context) : null;
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
if (direction == Direction.UP && !state.canSurvive(level, pos)) {
return net.minecraft.world.level.block.Blocks.AIR.defaultBlockState();
}
return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new BluestoneComparatorBlockEntity(pos, state, this.blockEntityTypeSupplier);
}
@Override
protected int getOutputSignal(BlockGetter level, BlockPos pos, BlockState state) {
BlockEntity blockEntity = level.getBlockEntity(pos);
return blockEntity instanceof BluestoneComparatorBlockEntity comparator ? comparator.getOutputSignal() : 0;
}
@Override
protected int getInputSignal(Level level, BlockPos pos, BlockState state) {
Direction facing = state.getValue(FACING);
BlockPos inputPos = pos.relative(facing);
BlockState inputState = level.getBlockState(inputPos);
int signal = BluestoneSignalHelper.getSignalExcludingRedstoneWire(level, inputPos, facing);
signal = Math.max(signal, this.getDirectBluestoneRearSignal(level, inputPos, inputState, facing));
if (signal < 15 && inputState.isRedstoneConductor(level, inputPos)) {
BlockPos fartherInputPos = inputPos.relative(facing);
BlockState fartherInputState = level.getBlockState(fartherInputPos);
signal = Math.max(signal, BluestoneSignalHelper.getSignalExcludingRedstoneWire(level, fartherInputPos, facing));
signal = Math.max(signal, this.getDirectBluestoneRearSignal(level, fartherInputPos, fartherInputState, facing));
}
return signal;
}
@Override
protected int getAlternateSignal(SignalGetter level, BlockPos pos, BlockState state) {
Direction facing = state.getValue(FACING);
Direction clockwise = facing.getClockWise();
Direction counterClockwise = facing.getCounterClockWise();
int signal = this.getBluestoneSideSignal(level, pos.relative(clockwise), clockwise.getOpposite());
signal = Math.max(signal, this.getBluestoneSideSignal(level, pos.relative(counterClockwise), counterClockwise.getOpposite()));
return signal;
}
private int getBluestoneSideSignal(SignalGetter level, BlockPos pos, Direction direction) {
BlockState neighborState = level.getBlockState(pos);
if (neighborState.getBlock() instanceof BluestoneSignalSource source) {
return source.getBluestoneSignal(level instanceof LevelReader levelReader ? levelReader : null, pos, neighborState, direction);
}
return 0;
}
private int getDirectBluestoneRearSignal(LevelReader level, BlockPos pos, BlockState state, Direction direction) {
if (state.getBlock() instanceof BluestoneSignalSource source) {
return source.getBluestoneSignal(level, pos, state, direction);
}
return BluestoneSignalHelper.getDirectBluestoneSignal(level, pos, direction);
}
@Override
public boolean isSignalSource(BlockState state) {
return true;
}
@Override
protected void checkTickOnNeighbor(Level level, BlockPos pos, BlockState state) {
if (level.getBlockTicks().willTickThisTick(pos, this)) {
return;
}
int outputSignal = this.calculateBluestoneOutputSignal(level, pos, state);
int storedOutputSignal = this.getOutputSignal(level, pos, state);
if (outputSignal != storedOutputSignal || state.getValue(POWERED) != this.shouldTurnOn(level, pos, state)) {
TickPriority tickPriority = this.shouldPrioritize(level, pos, state) ? TickPriority.HIGH : TickPriority.NORMAL;
level.scheduleTick(pos, this, 2, tickPriority);
}
}
@Override
public void tick(BlockState state, net.minecraft.server.level.ServerLevel level, BlockPos pos, RandomSource random) {
this.refreshBluestoneOutputState(level, pos, state);
}
@Override
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, net.minecraft.world.InteractionHand hand, BlockHitResult hitResult) {
if (!player.getAbilities().mayBuild) {
return InteractionResult.PASS;
}
BlockState updated = state.cycle(MODE);
float pitch = updated.getValue(MODE) == ComparatorMode.SUBTRACT ? 0.55F : 0.5F;
level.playSound(player, pos, SoundEvents.COMPARATOR_CLICK, SoundSource.BLOCKS, 0.3F, pitch);
level.setBlock(pos, updated, 2);
this.refreshBluestoneOutputState(level, pos, updated);
return InteractionResult.sidedSuccess(level.isClientSide);
}
private int calculateBluestoneOutputSignal(Level level, BlockPos pos, BlockState state) {
int inputSignal = this.getInputSignal(level, pos, state);
if (inputSignal == 0) {
return 0;
}
int alternateSignal = this.getAlternateSignal(level, pos, state);
if (alternateSignal > inputSignal) {
return 0;
}
return state.getValue(MODE) == ComparatorMode.SUBTRACT ? inputSignal - alternateSignal : inputSignal;
}
private void refreshBluestoneOutputState(Level level, BlockPos pos, BlockState state) {
int outputSignal = this.calculateBluestoneOutputSignal(level, pos, state);
BlockEntity blockEntity = level.getBlockEntity(pos);
int storedOutputSignal = 0;
if (blockEntity instanceof BluestoneComparatorBlockEntity comparator) {
storedOutputSignal = comparator.getOutputSignal();
comparator.setOutputSignal(outputSignal);
}
boolean shouldTurnOn = this.shouldTurnOn(level, pos, state);
boolean powered = state.getValue(DiodeBlock.POWERED);
if (powered != shouldTurnOn) {
state = state.setValue(DiodeBlock.POWERED, shouldTurnOn);
level.setBlock(pos, state, 2);
}
if (storedOutputSignal != outputSignal || powered != shouldTurnOn) {
this.updateNeighborsInFront(level, pos, state);
}
}
@Override
public void animateTick(BlockState state, net.minecraft.world.level.Level level, BlockPos pos, RandomSource random) {
if (!state.getValue(POWERED)) {
return;
}
double x = pos.getX() + 0.5D + (random.nextDouble() - 0.5D) * 0.2D;
double y = pos.getY() + 0.8D;
double z = pos.getZ() + 0.5D + (random.nextDouble() - 0.5D) * 0.2D;
level.addParticle(BLUESTONE_PARTICLE, x, y, z, 0.0D, 0.0D, 0.0D);
}
}
@@ -0,0 +1,57 @@
package com.craisinlord.antarchy.content.block;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.context.BlockPlaceContext;
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;
public class BluestoneLampBlock extends Block {
public static final BooleanProperty LIT = BlockStateProperties.LIT;
public BluestoneLampBlock(BlockBehaviour.Properties properties) {
super(properties);
registerDefaultState(this.stateDefinition.any().setValue(LIT, false));
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(LIT);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return this.defaultBlockState().setValue(LIT, shouldLight(context.getLevel(), context.getClickedPos()));
}
@Override
public void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, BlockPos neighborPos, boolean movedByPiston) {
if (level.isClientSide) {
return;
}
boolean lit = state.getValue(LIT);
boolean powered = shouldLight(level, pos);
if (lit && !powered) {
level.scheduleTick(pos, this, 4);
} else if (!lit && powered) {
level.setBlock(pos, state.setValue(LIT, true), 2);
}
}
@Override
public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (state.getValue(LIT) && !shouldLight(level, pos)) {
level.setBlock(pos, state.setValue(LIT, false), 2);
}
}
private static boolean shouldLight(Level level, BlockPos pos) {
return level.hasNeighborSignal(pos) || BluestoneSignalHelper.getBestNeighborSignal(level, pos) > 0;
}
}
@@ -0,0 +1,70 @@
package com.craisinlord.antarchy.content.block;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.DustParticleOptions;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.RedStoneOreBlock;
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.phys.BlockHitResult;
import org.joml.Vector3f;
public class BluestoneOreBlock extends RedStoneOreBlock {
private static final DustParticleOptions BLUESTONE_PARTICLE = new DustParticleOptions(new Vector3f(0.18F, 0.54F, 1.0F), 1.0F);
public BluestoneOreBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public void attack(BlockState state, Level level, BlockPos pos, Player player) {
activate(state, level, pos);
}
@Override
public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) {
activate(state, level, pos);
}
@Override
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult) {
activate(state, level, pos);
return InteractionResult.sidedSuccess(level.isClientSide);
}
@Override
public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) {
if (state.getValue(BlockStateProperties.LIT)) {
spawnBluestoneParticles(level, pos);
}
}
private static void activate(BlockState state, Level level, BlockPos pos) {
spawnBluestoneParticles(level, pos);
if (!state.getValue(BlockStateProperties.LIT)) {
level.setBlock(pos, state.setValue(BlockStateProperties.LIT, true), 3);
}
}
private static void spawnBluestoneParticles(Level level, BlockPos pos) {
RandomSource random = level.random;
for (Direction direction : Direction.values()) {
BlockPos neighborPos = pos.relative(direction);
if (level.getBlockState(neighborPos).isSolidRender(level, neighborPos)) {
continue;
}
Direction.Axis axis = direction.getAxis();
double x = axis == Direction.Axis.X ? 0.5D + 0.5625D * direction.getStepX() : random.nextFloat();
double y = axis == Direction.Axis.Y ? 0.5D + 0.5625D * direction.getStepY() : random.nextFloat();
double z = axis == Direction.Axis.Z ? 0.5D + 0.5625D * direction.getStepZ() : random.nextFloat();
level.addParticle(BLUESTONE_PARTICLE, pos.getX() + x, pos.getY() + y, pos.getZ() + z, 0.0D, 0.0D, 0.0D);
}
}
}
@@ -0,0 +1,21 @@
package com.craisinlord.antarchy.content.block;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
public final class BluestonePlacementHelper {
private BluestonePlacementHelper() {
}
public static boolean hasCeilingSupport(LevelReader level, BlockPos pos) {
BlockPos supportPos = pos.above();
return Block.canSupportCenter(level, supportPos, Direction.DOWN);
}
public static boolean canPlaceOnCeiling(BlockPlaceContext context) {
return context.getClickedFace() == Direction.DOWN && hasCeilingSupport(context.getLevel(), context.getClickedPos());
}
}
@@ -0,0 +1,109 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.DustParticleOptions;
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.SignalGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.RepeaterBlock;
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;
import net.minecraft.util.RandomSource;
import org.joml.Vector3f;
public class BluestoneRepeaterBlock extends RepeaterBlock {
private static final VoxelShape SHAPE = Block.box(0.0D, 14.0D, 0.0D, 16.0D, 16.0D, 16.0D);
private static final DustParticleOptions BLUESTONE_PARTICLE = new DustParticleOptions(new Vector3f(0.18F, 0.54F, 1.0F), 1.0F);
public BluestoneRepeaterBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return BluestonePlacementHelper.hasCeilingSupport(level, pos);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return BluestonePlacementHelper.canPlaceOnCeiling(context) ? super.getStateForPlacement(context) : null;
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
if (!state.canSurvive(level, pos)) {
return net.minecraft.world.level.block.Blocks.AIR.defaultBlockState();
}
return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
}
@Override
protected int getAlternateSignal(SignalGetter level, BlockPos pos, BlockState state) {
Direction facing = state.getValue(FACING);
Direction clockwise = facing.getClockWise();
Direction counterClockwise = facing.getCounterClockWise();
int signal = this.getBluestoneSideSignal(level, pos.relative(clockwise), clockwise.getOpposite());
signal = Math.max(signal, this.getBluestoneSideSignal(level, pos.relative(counterClockwise), counterClockwise.getOpposite()));
return signal;
}
@Override
protected int getInputSignal(Level level, BlockPos pos, BlockState state) {
Direction facing = state.getValue(FACING);
BlockPos inputPos = pos.relative(facing);
BlockState inputState = level.getBlockState(inputPos);
int signal = BluestoneSignalHelper.getSignalExcludingRedstoneWire(level, inputPos, facing);
if (signal >= 15) {
return signal;
}
if (inputState.getBlock() instanceof BluestoneSignalSource source) {
return Math.max(signal, source.getBluestoneSignal(level, inputPos, inputState, facing));
}
return signal;
}
@Override
public boolean isLocked(LevelReader level, BlockPos pos, BlockState state) {
return this.getAlternateSignal(level, pos, state) > 0;
}
private int getBluestoneSideSignal(SignalGetter level, BlockPos pos, Direction towardThisRepeater) {
BlockState neighborState = level.getBlockState(pos);
if (neighborState.getBlock() instanceof BluestoneRepeaterBlock
&& neighborState.getValue(POWERED)
&& neighborState.getValue(FACING) == towardThisRepeater) {
return 15;
}
return 0;
}
@Override
public boolean isSignalSource(BlockState state) {
return true;
}
@Override
public void animateTick(BlockState state, net.minecraft.world.level.Level level, BlockPos pos, RandomSource random) {
if (!state.getValue(POWERED)) {
return;
}
double x = pos.getX() + 0.5D + (random.nextDouble() - 0.5D) * 0.2D;
double y = pos.getY() + 0.8D;
double z = pos.getZ() + 0.5D + (random.nextDouble() - 0.5D) * 0.2D;
level.addParticle(BLUESTONE_PARTICLE, x, y, z, 0.0D, 0.0D, 0.0D);
}
}
@@ -0,0 +1,20 @@
package com.craisinlord.antarchy.content.block;
import net.minecraft.util.StringRepresentable;
public enum BluestoneSide implements StringRepresentable {
NONE("none"),
SIDE("side"),
DOWN("down");
private final String name;
BluestoneSide(String name) {
this.name = name;
}
@Override
public String getSerializedName() {
return this.name;
}
}
@@ -0,0 +1,93 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyTags;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
public final class BluestoneSignalHelper {
private BluestoneSignalHelper() {
}
public static int getBestNeighborSignal(LevelReader level, BlockPos pos) {
int signal = 0;
for (Direction direction : Direction.values()) {
signal = Math.max(signal, getDirectBluestoneSignal(level, pos.relative(direction), direction));
if (signal >= 15) {
return 15;
}
}
return signal;
}
public static int getDirectBluestoneSignal(LevelReader level, BlockPos pos, Direction direction) {
BlockState state = level.getBlockState(pos);
if (state.getBlock() instanceof BluestoneSignalSource source) {
return source.getBluestoneSignal(level, pos, state, direction);
}
return 0;
}
public static int getWireSignal(LevelReader level, BlockPos pos) {
BlockState state = level.getBlockState(pos);
if (state.getBlock() instanceof BluestoneSignalSource source) {
return source.getBluestoneSignal(level, pos, state, Direction.DOWN);
}
return 0;
}
public static int getSignalExcludingRedstoneWire(LevelReader level, BlockPos pos, Direction direction) {
BlockState state = level.getBlockState(pos);
if (isVanillaRedstoneComponent(state)) {
return 0;
}
int signal = state.getSignal(level, pos, direction);
if (state.isRedstoneConductor(level, pos)) {
signal = Math.max(signal, getDirectSignalToExcludingRedstoneWire(level, pos));
}
return signal;
}
private static int getDirectSignalToExcludingRedstoneWire(BlockGetter level, BlockPos pos) {
int signal = 0;
for (Direction direction : Direction.values()) {
BlockPos neighborPos = pos.relative(direction);
BlockState neighborState = level.getBlockState(neighborPos);
if (isVanillaRedstoneComponent(neighborState)) {
continue;
}
signal = Math.max(signal, neighborState.getDirectSignal(level, neighborPos, direction));
if (signal >= 15) {
return 15;
}
}
return signal;
}
public static boolean canBluestoneConnectTo(BlockState state) {
return state.is(AntarchyTags.Blocks.BLUESTONE_CONNECTABLE);
}
public static boolean isBluestoneComponent(BlockState state) {
return state.is(AntarchyTags.Blocks.BLUESTONE_COMPONENTS);
}
public static void updateBluestoneNeighbors(Level level, BlockPos pos) {
level.updateNeighborsAt(pos, level.getBlockState(pos).getBlock());
for (Direction direction : Direction.values()) {
level.updateNeighborsAt(pos.relative(direction), level.getBlockState(pos).getBlock());
}
}
public static boolean isVanillaRedstoneComponent(BlockState state) {
return state.is(Blocks.REDSTONE_WIRE)
|| state.is(Blocks.REDSTONE_TORCH)
|| state.is(Blocks.REDSTONE_WALL_TORCH)
|| state.is(Blocks.REPEATER)
|| state.is(Blocks.COMPARATOR);
}
}
@@ -0,0 +1,10 @@
package com.craisinlord.antarchy.content.block;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.state.BlockState;
public interface BluestoneSignalSource {
int getBluestoneSignal(LevelReader level, BlockPos pos, BlockState state, Direction direction);
}
@@ -0,0 +1,253 @@
package com.craisinlord.antarchy.content.block;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.DustParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
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.BooleanProperty;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.joml.Vector3f;
public class BluestoneTorchBlock extends Block implements BluestoneSignalSource {
public static final BooleanProperty LIT = BlockStateProperties.LIT;
public static final EnumProperty<AttachFace> FACE = BlockStateProperties.ATTACH_FACE;
public static final DirectionProperty FACING = HorizontalDirectionalBlock.FACING;
private static final VoxelShape CEILING_SHAPE = Block.box(6.0D, 6.0D, 6.0D, 10.0D, 16.0D, 10.0D);
private static final Map<Direction, VoxelShape> WALL_SHAPES = Map.of(
Direction.NORTH, Block.box(5.5D, 3.0D, 11.0D, 10.5D, 13.0D, 16.0D),
Direction.SOUTH, Block.box(5.5D, 3.0D, 0.0D, 10.5D, 13.0D, 5.0D),
Direction.WEST, Block.box(11.0D, 3.0D, 5.5D, 16.0D, 13.0D, 10.5D),
Direction.EAST, Block.box(0.0D, 3.0D, 5.5D, 5.0D, 13.0D, 10.5D)
);
private static final DustParticleOptions BLUESTONE_PARTICLE = new DustParticleOptions(new Vector3f(0.18F, 0.54F, 1.0F), 1.0F);
private static final Map<Level, List<Toggle>> RECENT_TOGGLES = new WeakHashMap<>();
public BluestoneTorchBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.defaultBlockState()
.setValue(LIT, true)
.setValue(FACE, AttachFace.CEILING)
.setValue(FACING, Direction.NORTH));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(FACE) == AttachFace.WALL ? WALL_SHAPES.get(state.getValue(FACING)) : CEILING_SHAPE;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return switch (state.getValue(FACE)) {
case CEILING -> BluestonePlacementHelper.hasCeilingSupport(level, pos);
case WALL -> this.hasWallSupport(level, pos, state.getValue(FACING));
default -> false;
};
}
@Override
public BlockState getStateForPlacement(net.minecraft.world.item.context.BlockPlaceContext context) {
LevelReader level = context.getLevel();
BlockPos pos = context.getClickedPos();
for (Direction direction : context.getNearestLookingDirections()) {
if (direction == Direction.DOWN && BluestonePlacementHelper.hasCeilingSupport(level, pos)) {
return this.defaultBlockState().setValue(FACE, AttachFace.CEILING);
}
if (direction.getAxis().isHorizontal()) {
Direction facing = direction.getOpposite();
BlockState state = this.defaultBlockState().setValue(FACE, AttachFace.WALL).setValue(FACING, facing);
if (state.canSurvive(level, pos)) {
return state;
}
}
}
return null;
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, net.minecraft.world.level.LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
if (!state.canSurvive(level, pos)) {
return net.minecraft.world.level.block.Blocks.AIR.defaultBlockState();
}
return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
}
@Override
public boolean isSignalSource(BlockState state) {
return true;
}
@Override
public int getSignal(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
if (this.isDirectlyPoweringRedstoneWire(level, pos, direction)) {
return 0;
}
if (this.isBlockedOutputDirection(state, direction)) {
return 0;
}
return state.getValue(LIT) ? 15 : 0;
}
@Override
public int getDirectSignal(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
if (!state.getValue(LIT)) {
return 0;
}
if (this.isDirectlyPoweringRedstoneWire(level, pos, direction)) {
return 0;
}
if (state.getValue(FACE) == AttachFace.WALL) {
return direction == Direction.UP ? 15 : 0;
}
return this.isBlockedOutputDirection(state, direction) ? 0 : 15;
}
@Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean moving) {
super.onPlace(state, level, pos, oldState, moving);
BluestoneSignalHelper.updateBluestoneNeighbors(level, pos);
}
@Override
public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
super.onRemove(state, level, pos, newState, movedByPiston);
if (!state.is(newState.getBlock())) {
BluestoneSignalHelper.updateBluestoneNeighbors(level, pos);
}
}
@Override
public void neighborChanged(BlockState state, Level level, BlockPos pos, Block block, BlockPos fromPos, boolean moving) {
if (!level.isClientSide) {
boolean powered = this.hasInputSignal(level, pos, state);
if (state.getValue(LIT) == powered) {
level.scheduleTick(pos, this, 2);
}
}
}
@Override
public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
boolean powered = this.hasInputSignal(level, pos, state);
boolean lit = state.getValue(LIT);
if (lit) {
if (powered) {
level.setBlock(pos, state.setValue(LIT, false), 3);
if (this.isToggledTooFrequently(level, pos, true)) {
level.levelEvent(1502, pos, 0);
level.playSound(null, pos, SoundEvents.REDSTONE_TORCH_BURNOUT, SoundSource.BLOCKS, 0.5F, 2.6F + (level.random.nextFloat() - level.random.nextFloat()) * 0.8F);
level.scheduleTick(pos, this, 160);
}
}
} else if (!powered && !this.isToggledTooFrequently(level, pos, false)) {
level.setBlock(pos, state.setValue(LIT, true), 3);
}
}
@Override
public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) {
if (!state.getValue(LIT)) {
return;
}
double x = pos.getX() + 0.5D;
double y = pos.getY() + (state.getValue(FACE) == AttachFace.CEILING ? 0.3D : 0.35D);
double z = pos.getZ() + 0.5D;
if (state.getValue(FACE) == AttachFace.WALL) {
Direction facing = state.getValue(FACING).getOpposite();
x += 0.27D * facing.getStepX();
z += 0.27D * facing.getStepZ();
}
level.addParticle(ParticleTypes.SMOKE, x, y, z, 0.0D, 0.0D, 0.0D);
level.addParticle(BLUESTONE_PARTICLE, x, y, z, 0.0D, 0.0D, 0.0D);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(LIT, FACE, FACING);
}
@Override
public int getBluestoneSignal(LevelReader level, BlockPos pos, BlockState state, Direction direction) {
return this.isBlockedOutputDirection(state, direction) ? 0 : state.getValue(LIT) ? 15 : 0;
}
@Override
public BlockState rotate(BlockState state, Rotation rotation) {
return state.getValue(FACE) == AttachFace.WALL ? state.setValue(FACING, rotation.rotate(state.getValue(FACING))) : state;
}
@Override
public BlockState mirror(BlockState state, Mirror mirror) {
return state.getValue(FACE) == AttachFace.WALL ? state.rotate(mirror.getRotation(state.getValue(FACING))) : state;
}
private boolean hasInputSignal(Level level, BlockPos pos, BlockState state) {
Direction supportDirection = state.getValue(FACE) == AttachFace.CEILING ? Direction.UP : state.getValue(FACING).getOpposite();
return level.hasSignal(pos.relative(supportDirection), supportDirection);
}
private boolean hasWallSupport(LevelReader level, BlockPos pos, Direction facing) {
BlockPos supportPos = pos.relative(facing.getOpposite());
return level.getBlockState(supportPos).isFaceSturdy(level, supportPos, facing);
}
private boolean isBlockedOutputDirection(BlockState state, Direction direction) {
return this.getBlockedOutputDirection(state) == direction;
}
private boolean isDirectlyPoweringRedstoneWire(BlockGetter level, BlockPos pos, Direction direction) {
return level.getBlockState(pos.relative(direction.getOpposite())).is(Blocks.REDSTONE_WIRE);
}
private Direction getBlockedOutputDirection(BlockState state) {
return state.getValue(FACE) == AttachFace.WALL ? state.getValue(FACING) : Direction.DOWN;
}
private boolean isToggledTooFrequently(Level level, BlockPos pos, boolean addNew) {
List<Toggle> toggles = RECENT_TOGGLES.computeIfAbsent(level, ignored -> new ArrayList<>());
if (addNew) {
toggles.add(new Toggle(pos.immutable(), level.getGameTime()));
}
long cutoff = level.getGameTime() - 60L;
toggles.removeIf(toggle -> toggle.gameTime < cutoff);
int count = 0;
for (Toggle toggle : toggles) {
if (toggle.pos.equals(pos)) {
count++;
if (count >= 8) {
return true;
}
}
}
return false;
}
private record Toggle(BlockPos pos, long gameTime) {
}
}
@@ -0,0 +1,434 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyTags;
import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.MapCodec;
import java.util.Map;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.item.ItemStack;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
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.HorizontalDirectionalBlock;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.RedStoneWireBlock;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.TrapDoorBlock;
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.block.state.properties.IntegerProperty;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public class BluestoneWireBlock extends Block implements BluestoneSignalSource {
public static final EnumProperty<BluestoneSide> NORTH = EnumProperty.create("north", BluestoneSide.class);
public static final EnumProperty<BluestoneSide> EAST = EnumProperty.create("east", BluestoneSide.class);
public static final EnumProperty<BluestoneSide> SOUTH = EnumProperty.create("south", BluestoneSide.class);
public static final EnumProperty<BluestoneSide> WEST = EnumProperty.create("west", BluestoneSide.class);
public static final IntegerProperty POWER = IntegerProperty.create("power", 0, 15);
public static final Map<Direction, EnumProperty<BluestoneSide>> PROPERTY_BY_DIRECTION = ImmutableMap.<Direction, EnumProperty<BluestoneSide>>builder()
.put(Direction.NORTH, NORTH)
.put(Direction.EAST, EAST)
.put(Direction.SOUTH, SOUTH)
.put(Direction.WEST, WEST)
.build();
private static final VoxelShape DOT_SHAPE = Block.box(3.0D, 14.0D, 3.0D, 13.0D, 16.0D, 13.0D);
private static final VoxelShape NORTH_SHAPE = Block.box(3.0D, 14.0D, 0.0D, 13.0D, 16.0D, 13.0D);
private static final VoxelShape SOUTH_SHAPE = Block.box(3.0D, 14.0D, 3.0D, 13.0D, 16.0D, 16.0D);
private static final VoxelShape WEST_SHAPE = Block.box(0.0D, 14.0D, 3.0D, 13.0D, 16.0D, 13.0D);
private static final VoxelShape EAST_SHAPE = Block.box(3.0D, 14.0D, 3.0D, 16.0D, 16.0D, 13.0D);
private static boolean shouldSignal = true;
private final BlockState crossState;
public BluestoneWireBlock() {
this(BlockBehaviour.Properties.of().noCollission().instabreak().sound(SoundType.WOOL));
}
public BluestoneWireBlock(BlockBehaviour.Properties properties) {
super(properties);
BlockState defaultState = this.defaultBlockState()
.setValue(NORTH, BluestoneSide.NONE)
.setValue(EAST, BluestoneSide.NONE)
.setValue(SOUTH, BluestoneSide.NONE)
.setValue(WEST, BluestoneSide.NONE)
.setValue(POWER, 0);
this.registerDefaultState(defaultState);
this.crossState = defaultState
.setValue(NORTH, BluestoneSide.SIDE)
.setValue(EAST, BluestoneSide.SIDE)
.setValue(SOUTH, BluestoneSide.SIDE)
.setValue(WEST, BluestoneSide.SIDE);
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return BluestonePlacementHelper.hasCeilingSupport(level, pos);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
if (!BluestonePlacementHelper.canPlaceOnCeiling(context)) {
return null;
}
return this.updatePowerFromNeighbors(context.getLevel(), context.getClickedPos(), this.calculateShape(context.getLevel(), context.getClickedPos(), this.defaultBlockState()));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
VoxelShape shape = DOT_SHAPE;
if (state.getValue(NORTH) != BluestoneSide.NONE) {
shape = Shapes.or(shape, NORTH_SHAPE);
}
if (state.getValue(EAST) != BluestoneSide.NONE) {
shape = Shapes.or(shape, EAST_SHAPE);
}
if (state.getValue(SOUTH) != BluestoneSide.NONE) {
shape = Shapes.or(shape, SOUTH_SHAPE);
}
if (state.getValue(WEST) != BluestoneSide.NONE) {
shape = Shapes.or(shape, WEST_SHAPE);
}
return shape;
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return Shapes.empty();
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
if (!state.canSurvive(level, pos)) {
return net.minecraft.world.level.block.Blocks.AIR.defaultBlockState();
}
if (direction.getAxis().isHorizontal() || direction == Direction.UP || direction == Direction.DOWN) {
BlockState shaped = this.calculateShape(level, pos, state);
return level instanceof Level actualLevel ? this.updatePowerFromNeighbors(actualLevel, pos, shaped) : shaped;
}
return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
}
@Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean moving) {
if (!oldState.is(state.getBlock())) {
this.notifyNeighborShapes(level, pos);
this.updateNeighbors(level, pos, state);
}
}
@Override
public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
if (!state.is(newState.getBlock())) {
this.notifyNeighborShapes(level, pos);
for (Direction direction : Direction.Plane.HORIZONTAL) {
this.updateNeighborWire(level, pos.relative(direction));
this.updateNeighborWire(level, pos.relative(direction).above());
this.updateNeighborWire(level, pos.relative(direction).below());
}
}
super.onRemove(state, level, pos, newState, movedByPiston);
}
@Override
public void neighborChanged(BlockState state, Level level, BlockPos pos, Block block, BlockPos fromPos, boolean moving) {
if (!level.isClientSide) {
this.updateNeighbors(level, pos, state);
}
}
@Override
public boolean isSignalSource(BlockState state) {
return shouldSignal;
}
@Override
public int getSignal(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
if (!shouldSignal || direction == Direction.UP) {
return 0;
}
if (direction.getAxis().isHorizontal()) {
EnumProperty<BluestoneSide> property = PROPERTY_BY_DIRECTION.get(direction);
if (property != null && state.getValue(property) == BluestoneSide.NONE) {
return 0;
}
}
return state.getValue(POWER);
}
@Override
public int getDirectSignal(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
return this.getSignal(state, level, pos, direction);
}
@Override
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, net.minecraft.world.InteractionHand hand, BlockHitResult hitResult) {
if (!player.getAbilities().mayBuild) {
return InteractionResult.PASS;
}
if (!isCross(state) && !isDot(state)) {
return InteractionResult.PASS;
}
BlockState toggled = isCross(state) ? this.defaultBlockState() : this.crossState;
BlockState updated = toggled.setValue(POWER, state.getValue(POWER));
if (!hasAnyAutomaticConnections(level, pos)) {
if (!updated.equals(state)) {
level.setBlock(pos, updated, 3);
}
return InteractionResult.SUCCESS;
}
updated = this.calculateShape(level, pos, updated);
if (!updated.equals(state)) {
level.setBlock(pos, updated, 3);
this.updateNeighbors(level, pos, updated);
return InteractionResult.SUCCESS;
}
return InteractionResult.PASS;
}
@Override
public ItemStack getCloneItemStack(BlockGetter level, BlockPos pos, BlockState state) {
return new ItemStack(BuiltInRegistries.ITEM.get(new ResourceLocation("antarchy", "bluestone")));
}
@Override
public BlockState rotate(BlockState state, Rotation rotation) {
return switch (rotation) {
case CLOCKWISE_180 -> state.setValue(NORTH, state.getValue(SOUTH))
.setValue(EAST, state.getValue(WEST))
.setValue(SOUTH, state.getValue(NORTH))
.setValue(WEST, state.getValue(EAST));
case COUNTERCLOCKWISE_90 -> state.setValue(NORTH, state.getValue(EAST))
.setValue(EAST, state.getValue(SOUTH))
.setValue(SOUTH, state.getValue(WEST))
.setValue(WEST, state.getValue(NORTH));
case CLOCKWISE_90 -> state.setValue(NORTH, state.getValue(WEST))
.setValue(EAST, state.getValue(NORTH))
.setValue(SOUTH, state.getValue(EAST))
.setValue(WEST, state.getValue(SOUTH));
default -> state;
};
}
@Override
public BlockState mirror(BlockState state, Mirror mirror) {
return switch (mirror) {
case LEFT_RIGHT -> state.setValue(NORTH, state.getValue(SOUTH)).setValue(SOUTH, state.getValue(NORTH));
case FRONT_BACK -> state.setValue(EAST, state.getValue(WEST)).setValue(WEST, state.getValue(EAST));
default -> super.mirror(state, mirror);
};
}
@Override
public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) {
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(NORTH, EAST, SOUTH, WEST, POWER);
}
@Override
public int getBluestoneSignal(LevelReader level, BlockPos pos, BlockState state, Direction direction) {
return direction == Direction.UP ? 0 : state.getValue(POWER);
}
private void updateNeighbors(Level level, BlockPos pos, BlockState state) {
if (!state.is(this)) {
return;
}
BlockState shaped = this.calculateShape(level, pos, state);
BlockState powered = this.updatePowerFromNeighbors(level, pos, shaped);
if (powered.equals(state)) {
return;
}
level.setBlock(pos, powered, 2);
this.notifyNeighborShapes(level, pos);
for (Direction direction : Direction.Plane.HORIZONTAL) {
this.updateNeighborWire(level, pos.relative(direction));
this.updateNeighborWire(level, pos.relative(direction).above());
this.updateNeighborWire(level, pos.relative(direction).below());
}
}
private void updateNeighborWire(Level level, BlockPos pos) {
BlockState neighborState = level.getBlockState(pos);
if (!neighborState.is(this)) {
return;
}
BlockState shaped = this.calculateShape(level, pos, neighborState);
BlockState powered = this.updatePowerFromNeighbors(level, pos, shaped);
if (powered.equals(neighborState)) {
return;
}
level.setBlock(pos, powered, 2);
this.notifyNeighborShapes(level, pos);
}
private void notifyNeighborShapes(Level level, BlockPos pos) {
level.updateNeighborsAt(pos, this);
for (Direction direction : Direction.values()) {
level.updateNeighborsAt(pos.relative(direction), this);
}
}
private BlockState updatePowerFromNeighbors(Level level, BlockPos pos, BlockState state) {
int newPower = this.calculateTargetStrength(level, pos);
return state.getValue(POWER) == newPower ? state : state.setValue(POWER, newPower);
}
private int calculateTargetStrength(Level level, BlockPos pos) {
shouldSignal = false;
int external = this.getExternalSignal(level, pos);
shouldSignal = true;
int neighborWirePower = 0;
boolean openBelowCurrent = !level.getBlockState(pos.below()).isRedstoneConductor(level, pos.below());
for (Direction direction : Direction.Plane.HORIZONTAL) {
BlockPos sidePos = pos.relative(direction);
BlockState sideState = level.getBlockState(sidePos);
neighborWirePower = Math.max(neighborWirePower, BluestoneSignalHelper.getWireSignal(level, sidePos));
if (sideState.isRedstoneConductor(level, sidePos)) {
neighborWirePower = Math.max(neighborWirePower, BluestoneSignalHelper.getWireSignal(level, sidePos.below()));
} else if (openBelowCurrent) {
neighborWirePower = Math.max(neighborWirePower, BluestoneSignalHelper.getWireSignal(level, sidePos.above()));
}
}
return Math.max(external, Math.max(0, neighborWirePower - 1));
}
private int getExternalSignal(Level level, BlockPos pos) {
int signal = 0;
for (Direction direction : Direction.values()) {
BlockPos neighborPos = pos.relative(direction);
BlockState neighborState = level.getBlockState(neighborPos);
if (BluestoneSignalHelper.isVanillaRedstoneComponent(neighborState)) {
continue;
}
if (neighborState.getBlock() instanceof BluestoneWireBlock) {
continue;
}
if (neighborState.getBlock() instanceof BluestoneSignalSource source) {
signal = Math.max(signal, source.getBluestoneSignal(level, neighborPos, neighborState, direction));
if (signal >= 15) {
return 15;
}
continue;
}
signal = Math.max(signal, BluestoneSignalHelper.getSignalExcludingRedstoneWire(level, neighborPos, direction));
if (signal >= 15) {
return 15;
}
}
return signal;
}
private static boolean isCross(BlockState state) {
return state.getValue(NORTH) != BluestoneSide.NONE
&& state.getValue(EAST) != BluestoneSide.NONE
&& state.getValue(SOUTH) != BluestoneSide.NONE
&& state.getValue(WEST) != BluestoneSide.NONE;
}
private static boolean isDot(BlockState state) {
return state.getValue(NORTH) == BluestoneSide.NONE
&& state.getValue(EAST) == BluestoneSide.NONE
&& state.getValue(SOUTH) == BluestoneSide.NONE
&& state.getValue(WEST) == BluestoneSide.NONE;
}
private boolean hasAnyAutomaticConnections(LevelReader level, BlockPos pos) {
return this.getConnectingSide(level, pos, Direction.NORTH) != BluestoneSide.NONE
|| this.getConnectingSide(level, pos, Direction.EAST) != BluestoneSide.NONE
|| this.getConnectingSide(level, pos, Direction.SOUTH) != BluestoneSide.NONE
|| this.getConnectingSide(level, pos, Direction.WEST) != BluestoneSide.NONE;
}
private BlockState calculateShape(LevelReader level, BlockPos pos, BlockState state) {
boolean wasDot = isDot(state);
BlockState result = state.setValue(NORTH, this.getConnectingSide(level, pos, Direction.NORTH))
.setValue(EAST, this.getConnectingSide(level, pos, Direction.EAST))
.setValue(SOUTH, this.getConnectingSide(level, pos, Direction.SOUTH))
.setValue(WEST, this.getConnectingSide(level, pos, Direction.WEST));
if (wasDot && isDot(result)) {
return result;
}
boolean north = result.getValue(NORTH) != BluestoneSide.NONE;
boolean south = result.getValue(SOUTH) != BluestoneSide.NONE;
boolean east = result.getValue(EAST) != BluestoneSide.NONE;
boolean west = result.getValue(WEST) != BluestoneSide.NONE;
boolean northSouthEmpty = !north && !south;
boolean eastWestEmpty = !east && !west;
if (!west && northSouthEmpty) {
result = result.setValue(WEST, BluestoneSide.SIDE);
}
if (!east && northSouthEmpty) {
result = result.setValue(EAST, BluestoneSide.SIDE);
}
if (!north && eastWestEmpty) {
result = result.setValue(NORTH, BluestoneSide.SIDE);
}
if (!south && eastWestEmpty) {
result = result.setValue(SOUTH, BluestoneSide.SIDE);
}
return result;
}
private BluestoneSide getConnectingSide(LevelReader level, BlockPos pos, Direction direction) {
boolean openBelowCurrent = !level.getBlockState(pos.below()).isRedstoneConductor(level, pos.below());
return this.getConnectingSide(level, pos, direction, openBelowCurrent);
}
private BluestoneSide getConnectingSide(LevelReader level, BlockPos pos, Direction direction, boolean openBelowCurrent) {
BlockPos sidePos = pos.relative(direction);
BlockState sideState = level.getBlockState(sidePos);
if (openBelowCurrent) {
boolean canSupportBelow = sideState.getBlock() instanceof TrapDoorBlock
|| Block.canSupportCenter(level, sidePos, Direction.DOWN);
if (canSupportBelow && this.canConnectTo(level.getBlockState(sidePos.below()), direction)) {
return sideState.isFaceSturdy(level, sidePos, direction.getOpposite()) ? BluestoneSide.DOWN : BluestoneSide.SIDE;
}
}
if (this.canConnectTo(sideState, direction)) {
return BluestoneSide.SIDE;
}
if (sideState.isRedstoneConductor(level, sidePos)) {
return BluestoneSide.NONE;
}
BlockPos sidePosAbove = sidePos.above();
return this.canConnectTo(level.getBlockState(sidePosAbove), direction) ? BluestoneSide.SIDE : BluestoneSide.NONE;
}
private boolean canConnectTo(BlockState state, Direction direction) {
if (BluestoneSignalHelper.isVanillaRedstoneComponent(state)) {
return false;
}
if (state.getBlock() instanceof BluestoneWireBlock || state.getBlock() instanceof BluestoneTorchBlock || state.getBlock() instanceof BluestoneBlock) {
return true;
}
if (state.getBlock() instanceof BluestoneRepeaterBlock || state.getBlock() instanceof BluestoneComparatorBlock) {
Direction facing = state.getValue(HorizontalDirectionalBlock.FACING);
return facing == direction || facing == direction.getOpposite();
}
return state.is(AntarchyTags.Blocks.BLUESTONE_CONNECTABLE);
}
}
@@ -0,0 +1,47 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.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 BlushMossBlock extends Block implements BonemealableBlock {
private static final ResourceKey<ConfiguredFeature<?, ?>> BLUSH_MOSS_PATCH_BONEMEAL = ResourceKey.create(
Registries.CONFIGURED_FEATURE,
new ResourceLocation(Antarchy.MODID, "blush_moss_patch_bonemeal")
);
public BlushMossBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state, boolean isClient) {
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(BLUSH_MOSS_PATCH_BONEMEAL);
feature.value().place(level, level.getChunkSource().getGenerator(), random, pos);
}
}
@@ -0,0 +1,130 @@
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 BlushMossCarpetBlock extends Block {
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 BlushMossCarpetBlock(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
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
public 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
public 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
public 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,46 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.entity.brutalfly.BrutalflyEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
public class BrutalflyCocoonSpawnerBlock extends Block {
public BrutalflyCocoonSpawnerBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public RenderShape getRenderShape(BlockState state) {
return RenderShape.INVISIBLE;
}
@Override
public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
level.setBlock(pos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL);
BrutalflyEntity brutalfly = AntarchyObjects.BRUTALFLY.get().create(level);
if (brutalfly == null) {
return;
}
BlockPos anchor = pos.above();
brutalfly.moveTo(
anchor.getX() + 0.5D,
anchor.getY() - 1.5D,
anchor.getZ() + 0.5D,
random.nextFloat() * 360.0F,
0.0F
);
brutalfly.setCocooned(true, anchor);
brutalfly.setHealth(brutalfly.getMaxHealth());
level.addFreshEntity(brutalfly);
}
}
@@ -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
public boolean isRandomlyTicking(BlockState state) {
return true;
}
@Override
public 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,22 @@
package com.craisinlord.antarchy.content.block;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
public class CamelliaBlock extends MilkweedBlock {
public CamelliaBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) {
BlockPos dropPos = state.getValue(BlockStateProperties.DOUBLE_BLOCK_HALF) == DoubleBlockHalf.UPPER ? pos.below() : pos;
popResource(level, dropPos, new ItemStack(this.asItem()));
}
}
@@ -0,0 +1,160 @@
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.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.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 ChitinSpikeBlock extends PointedDripstoneBlock {
@SuppressWarnings("rawtypes")
public ChitinSpikeBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@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
public 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
public 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 (isChitinSpikeWithDirection(level.getBlockState(root.above()), Direction.DOWN)) {
root.move(Direction.UP);
}
BlockPos.MutableBlockPos cursor = root.mutable();
while (isChitinSpikeWithDirection(level.getBlockState(cursor), Direction.DOWN)) {
BlockState fallingState = level.getBlockState(cursor);
if (isChitinSpikeWithDirection(fallingState, Direction.DOWN)) {
net.minecraft.world.entity.item.FallingBlockEntity.fall(level, cursor, fallingState);
}
cursor.move(Direction.DOWN);
}
return;
}
BlockPos.MutableBlockPos cursor = pos.mutable();
while (isChitinSpikeWithDirection(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 (isChitinSpikeWithDirection(forwardState, opposite)) {
return !mergeTips && forwardState.getValue(THICKNESS) != DripstoneThickness.TIP_MERGE
? DripstoneThickness.TIP
: DripstoneThickness.TIP_MERGE;
}
if (!isChitinSpikeWithDirection(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 !isChitinSpikeWithDirection(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) || isChitinSpikeWithDirection(supportState, direction);
}
private static boolean isChitinSpikeWithDirection(BlockState state, Direction direction) {
return state.is(AntarchyObjects.CHITIN_SPIKE.get()) && state.getValue(TIP_DIRECTION) == direction;
}
}
@@ -0,0 +1,97 @@
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
public 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
public VoxelShape getVisualShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return EMPTY;
}
@Override
public boolean skipRendering(BlockState state, BlockState adjacentBlockState, Direction side) {
return adjacentBlockState.is(this) || super.skipRendering(state, adjacentBlockState, side);
}
@Override
public boolean propagatesSkylightDown(BlockState state, BlockGetter level, BlockPos pos) {
return true;
}
@Override
public int getLightBlock(BlockState state, BlockGetter level, BlockPos pos) {
return 0;
}
@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;
}
@Override
public ItemStack pickupBlock(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(BlockGetter level, BlockPos pos, BlockState state) {
return new ItemStack(bucketItem.get());
}
@Override
public Optional<SoundEvent> getPickupSound() {
return Optional.of(SoundEvents.BUCKET_FILL);
}
}
@@ -0,0 +1,173 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import java.util.Optional;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ItemLike;
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.DoubleBlockHalf;
import net.minecraft.world.level.block.state.properties.EnumProperty;
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 CornCropBlock extends BushBlock implements BonemealableBlock {
public static final IntegerProperty AGE = BlockStateProperties.AGE_3;
public static final EnumProperty<DoubleBlockHalf> HALF = BlockStateProperties.DOUBLE_BLOCK_HALF;
private static final int MAX_AGE = 3;
private static final int TALL_AGE = 2;
private static final VoxelShape[] LOWER_SHAPES = new VoxelShape[] {
Block.box(4.0D, 0.0D, 4.0D, 12.0D, 6.0D, 12.0D),
Block.box(3.0D, 0.0D, 3.0D, 13.0D, 11.0D, 13.0D),
Block.box(2.0D, 0.0D, 2.0D, 14.0D, 14.0D, 14.0D),
Block.box(1.0D, 0.0D, 1.0D, 15.0D, 16.0D, 15.0D)
};
private static final VoxelShape[] UPPER_SHAPES = new VoxelShape[] {
Block.box(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D),
Block.box(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D),
Block.box(2.0D, 0.0D, 2.0D, 14.0D, 16.0D, 14.0D),
Block.box(1.0D, 0.0D, 1.0D, 15.0D, 16.0D, 15.0D)
};
private static final ResourceLocation CORN_SEEDS_ID = new ResourceLocation("antarchy", "corn_seeds");
public CornCropBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(AGE, 0).setValue(HALF, DoubleBlockHalf.LOWER));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
int age = state.getValue(AGE);
return state.getValue(HALF) == DoubleBlockHalf.UPPER ? UPPER_SHAPES[age] : LOWER_SHAPES[age];
}
@Override
public boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos) {
return state.is(Blocks.FARMLAND);
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
DoubleBlockHalf half = state.getValue(HALF);
int age = state.getValue(AGE);
if (half == DoubleBlockHalf.UPPER) {
BlockState below = level.getBlockState(pos.below());
return below.is(this) && below.getValue(HALF) == DoubleBlockHalf.LOWER && below.getValue(AGE) >= TALL_AGE;
}
if (!super.canSurvive(state, level, pos)) {
return false;
}
return age < TALL_AGE || level.getBlockState(pos.above()).is(this)
&& level.getBlockState(pos.above()).getValue(HALF) == DoubleBlockHalf.UPPER
&& level.getBlockState(pos.above()).getValue(AGE) == age;
}
@Override
public BlockState updateShape(
BlockState state,
Direction direction,
BlockState neighborState,
LevelAccessor level,
BlockPos pos,
BlockPos neighborPos
) {
if (!state.canSurvive(level, pos)) {
return Blocks.AIR.defaultBlockState();
}
return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
}
@Override
public boolean isRandomlyTicking(BlockState state) {
return state.getValue(HALF) == DoubleBlockHalf.LOWER && state.getValue(AGE) < MAX_AGE;
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (level.getRawBrightness(pos, 0) < 9 || random.nextInt(5) != 0) {
return;
}
this.grow(level, pos, state);
}
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state, boolean isClient) {
BlockPos lowerPos = state.getValue(HALF) == DoubleBlockHalf.UPPER ? pos.below() : pos;
BlockState lowerState = level.getBlockState(lowerPos);
if (!lowerState.is(this) || lowerState.getValue(HALF) != DoubleBlockHalf.LOWER) {
return false;
}
int age = lowerState.getValue(AGE);
return age < MAX_AGE && (age >= TALL_AGE || level.getBlockState(lowerPos.above()).canBeReplaced());
}
@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) {
BlockPos lowerPos = state.getValue(HALF) == DoubleBlockHalf.UPPER ? pos.below() : pos;
BlockState lowerState = level.getBlockState(lowerPos);
if (lowerState.is(this)) {
this.grow(level, lowerPos, lowerState);
}
}
private void grow(ServerLevel level, BlockPos lowerPos, BlockState lowerState) {
int age = lowerState.getValue(AGE);
if (age >= MAX_AGE) {
return;
}
if (age + 1 >= TALL_AGE) {
BlockPos upperPos = lowerPos.above();
if (!level.getBlockState(upperPos).canBeReplaced() && !level.getBlockState(upperPos).is(this)) {
return;
}
}
int newAge = age + 1;
level.setBlock(lowerPos, lowerState.setValue(AGE, newAge), Block.UPDATE_ALL);
if (newAge >= TALL_AGE) {
level.setBlock(lowerPos.above(), this.defaultBlockState().setValue(HALF, DoubleBlockHalf.UPPER).setValue(AGE, newAge), Block.UPDATE_ALL);
}
}
@Override
public ItemStack getCloneItemStack(BlockGetter level, BlockPos pos, BlockState state) {
return new ItemStack(this.getBaseSeedId());
}
protected ItemLike getBaseSeedId() {
Optional<net.minecraft.world.item.Item> item = BuiltInRegistries.ITEM.getOptional(CORN_SEEDS_ID);
return item.orElse(Blocks.AIR.asItem());
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(AGE, HALF);
}
}
@@ -0,0 +1,178 @@
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.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
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.InteractionResult;
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;
public class CorneaStalkBlock extends BushBlock implements BonemealableBlock {
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 = new ResourceLocation("antarchy", "cornea_ear");
public CorneaStalkBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(AGE, 0).setValue(HANGING, false));
}
@Override
public 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
public boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos) {
return state.is(AntarchyTags.Blocks.CORNEA_STALK_PLANTABLE);
}
@Override
public 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
public 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
public boolean isRandomlyTicking(BlockState state) {
return state.getValue(AGE) < MAX_AGE;
}
@Override
public 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, boolean isClient) {
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
public InteractionResult use(
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.use(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);
level.playSound(null, pos, SoundEvents.CAVE_VINES_PICK_BERRIES, SoundSource.BLOCKS, 1.0F, 0.9F + level.random.nextFloat() * 0.2F);
}
return InteractionResult.sidedSuccess(level.isClientSide);
}
@Override
public ItemStack getCloneItemStack(BlockGetter 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);
if (EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, 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,245 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.entity.CreepingHorrorEntity;
import com.craisinlord.antarchy.content.block.AmberMossBlock;
import com.craisinlord.antarchy.content.block.LurkingTerrorEggBlock;
import com.craisinlord.antarchy.content.horde.CavarynHordeManager;
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.sounds.SoundSource;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.ambient.Bat;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.GameRules;
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.entity.BlockEntity;
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 CreepingHorrorEggBlock extends Block {
public static final IntegerProperty HATCH = BlockStateProperties.HATCH;
public static final IntegerProperty EGGS = BlockStateProperties.EGGS;
private static final float PANIC_HATCH_CHANCE = 0.25F;
private static final double HORDE_ACCELERATION_RADIUS = 5.0D;
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 CreepingHorrorEggBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(HATCH, 0).setValue(EGGS, 1));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(EGGS) > 1 ? MULTI_SHAPE : SINGLE_SHAPE;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
}
@Override
public 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
public 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
public boolean isRandomlyTicking(BlockState state) {
return true;
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!this.shouldUpdateHatchLevel(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, state.getValue(EGGS));
}
@Override
public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) {
if (entity instanceof Player && !entity.isSteppingCarefully() && this.destroyEgg(level, state, pos, entity, 100)) {
if (level instanceof ServerLevel serverLevel) {
panicHatchNearby(serverLevel, pos);
}
}
super.stepOn(level, pos, state, entity);
}
@Override
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
this.destroyEgg(level, state, pos, entity, 3);
super.fallOn(level, state, pos, entity, fallDistance);
}
@Override
public 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);
}
private static void panicHatchNearby(ServerLevel level, BlockPos origin) {
int radius = 6;
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
for (int dx = -radius; dx <= radius; dx++) {
for (int dy = -radius; dy <= radius; dy++) {
for (int dz = -radius; dz <= radius; dz++) {
if (dx == 0 && dy == 0 && dz == 0) continue;
mutable.set(origin.getX() + dx, origin.getY() + dy, origin.getZ() + dz);
BlockState nearby = level.getBlockState(mutable);
BlockPos immutable = mutable.immutable();
if (nearby.getBlock() instanceof CreepingHorrorEggBlock b) {
b.hatchPanickedEggs(level, immutable, nearby, level.random);
} else if (nearby.getBlock() instanceof LurkingTerrorEggBlock b) {
b.hatchPanickedEggs(level, immutable, nearby, level.random);
}
}
}
}
}
@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 boolean destroyEgg(Level level, BlockState state, BlockPos pos, Entity entity, int chance) {
if (level.isClientSide || !this.canDestroyEgg(level, entity) || level.random.nextInt(chance) != 0) {
return false;
}
level.playSound(null, pos, SoundEvents.TURTLE_EGG_BREAK, SoundSource.BLOCKS, 0.7F, 0.9F + level.random.nextFloat() * 0.2F);
this.decreaseEggs(level, pos, state);
return true;
}
void hatchPanickedEggs(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) {
int hatchedEggs = rollPanickedEggs(state.getValue(EGGS), random);
if (hatchedEggs <= 0) {
return;
}
this.hatchEggs(level, pos, state, random, hatchedEggs);
}
void hatchEggs(ServerLevel level, BlockPos pos, BlockState state, RandomSource random, int eggsToHatch) {
if (eggsToHatch >= state.getValue(EGGS)) {
level.removeBlock(pos, false);
} else {
level.setBlock(pos, state.setValue(EGGS, state.getValue(EGGS) - eggsToHatch), 2);
}
level.playSound(null, pos, SoundEvents.TURTLE_EGG_HATCH, SoundSource.BLOCKS, 0.75F, 0.95F + random.nextFloat() * 0.1F);
for (int i = 0; i < eggsToHatch; i++) {
CreepingHorrorEntity entity = AntarchyObjects.CREEPING_HORROR.get().create(level);
if (entity == null) {
continue;
}
double spawnX = pos.getX() + 0.25D + random.nextDouble() * 0.5D;
double spawnZ = pos.getZ() + 0.25D + random.nextDouble() * 0.5D;
entity.moveTo(spawnX, pos.getY() + 0.1D, spawnZ, random.nextFloat() * 360.0F, 0.0F);
level.addFreshEntity(entity);
}
}
public void hatchWithNucleus(ServerLevel level, BlockPos pos, BlockState state) {
this.hatchEggs(level, pos, state, level.random, state.getValue(EGGS));
}
private static int rollPanickedEggs(int eggs, RandomSource random) {
int hatchedEggs = 0;
for (int i = 0; i < eggs; i++) {
if (random.nextFloat() < PANIC_HATCH_CHANCE) {
hatchedEggs++;
}
}
return hatchedEggs;
}
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, BlockPos pos) {
if (level instanceof ServerLevel serverLevel
&& CavarynHordeManager.shouldAccelerateNearbyEggHatching(serverLevel, pos, HORDE_ACCELERATION_RADIUS, level.random)) {
return true;
}
boolean onAmberMoss = level.getBlockState(pos.below()).getBlock() instanceof AmberMossBlock;
return level.random.nextInt(onAmberMoss ? 150 : 500) == 0;
}
private boolean canDestroyEgg(Level level, Entity entity) {
if (entity instanceof CreepingHorrorEntity || entity instanceof Bat) {
return false;
}
if (entity instanceof net.minecraft.world.entity.LivingEntity) {
return entity instanceof Player || level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
}
return false;
}
}
@@ -0,0 +1,67 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.VineBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.phys.BlockHitResult;
public class CreepvineBlock extends VineBlock {
public static final BooleanProperty STUNTED = BooleanProperty.create("stunted");
public CreepvineBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.defaultBlockState()
.setValue(NORTH, false)
.setValue(EAST, false)
.setValue(SOUTH, false)
.setValue(WEST, false)
.setValue(UP, false)
.setValue(STUNTED, false));
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (state.getValue(STUNTED)) {
return;
}
super.randomTick(state, level, pos, random);
}
@Override
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult) {
ItemStack stack = player.getItemInHand(hand);
if (!stack.is(Items.SHEARS) || state.getValue(STUNTED)) {
return super.use(state, level, pos, player, hand, hitResult);
}
if (!level.isClientSide) {
level.setBlock(pos, state.setValue(STUNTED, true), Block.UPDATE_ALL);
stack.hurtAndBreak(1, player, p -> p.broadcastBreakEvent(hand));
level.playSound(null, pos, SoundEvents.SHEEP_SHEAR, SoundSource.BLOCKS, 1.0F, 1.0F);
}
return InteractionResult.sidedSuccess(level.isClientSide);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(STUNTED);
}
}
@@ -0,0 +1,84 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.block.entity.CritterCageBlockEntity;
import com.craisinlord.antarchy.content.entity.ant.AntTeleportHelper;
import com.mojang.serialization.MapCodec;
import java.util.List;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.entity.player.Player;
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.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.storage.loot.LootParams;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class CritterCageBlock extends BaseEntityBlock {
private static final VoxelShape SHAPE = Block.box(1.0D, 1.0D, 1.0D, 15.0D, 14.0D, 15.0D);
public CritterCageBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public RenderShape getRenderShape(BlockState state) {
return RenderShape.MODEL;
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new CritterCageBlockEntity(pos, state);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
}
@Override
public ItemStack getCloneItemStack(net.minecraft.world.level.BlockGetter level, BlockPos pos, BlockState state) {
if (level instanceof Level actualLevel && actualLevel.getBlockEntity(pos) instanceof CritterCageBlockEntity blockEntity) {
return blockEntity.toItemStack();
}
return super.getCloneItemStack(level, pos, state);
}
@Override
public List<ItemStack> getDrops(BlockState state, LootParams.Builder params) {
BlockEntity blockEntity = params.getOptionalParameter(LootContextParams.BLOCK_ENTITY);
if (blockEntity instanceof CritterCageBlockEntity critterCageBlockEntity) {
return List.of(critterCageBlockEntity.toItemStack());
}
return super.getDrops(state, params);
}
@Override
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, net.minecraft.world.InteractionHand hand, BlockHitResult hitResult) {
if (!(player instanceof ServerPlayer serverPlayer)) {
return InteractionResult.SUCCESS;
}
if (!(level.getBlockEntity(pos) instanceof CritterCageBlockEntity blockEntity)) {
return InteractionResult.PASS;
}
return AntTeleportHelper.handleCagedAntTeleport(serverPlayer, blockEntity.entityTypeId(), blockEntity.entityData());
}
}
@@ -0,0 +1,45 @@
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 DreamCampfireBlock(BlockBehaviour.Properties properties) {
super(false, 2, properties);
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
DreamCampfireBlockEntity.beginConstruction();
try {
return new DreamCampfireBlockEntity(pos, state);
} finally {
DreamCampfireBlockEntity.endConstruction();
}
}
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
BlockEntityType<DreamCampfireBlockEntity> dreamCampfireType = AntarchyObjects.DREAM_CAMPFIRE_BLOCK_ENTITY.get();
if (level.isClientSide) {
return state.getValue(LIT)
? createTickerHelper(blockEntityType, dreamCampfireType, CampfireBlockEntity::particleTick)
: null;
}
return state.getValue(LIT)
? createTickerHelper(blockEntityType, dreamCampfireType, CampfireBlockEntity::cookTick)
: createTickerHelper(blockEntityType, dreamCampfireType, CampfireBlockEntity::cooldownTick);
}
}
@@ -0,0 +1,32 @@
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 DreamCeilingFireBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@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,53 @@
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.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.TorchBlock;
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 DreamCeilingTorchBlock extends TorchBlock {
private static final ResourceLocation DREAM_FIRE_FLAME_ID = new ResourceLocation(Antarchy.MODID, "dream_fire_flame");
private static final VoxelShape SHAPE = Block.box(6.0D, 6.0D, 6.0D, 10.0D, 16.0D, 10.0D);
public DreamCeilingTorchBlock(BlockBehaviour.Properties properties) {
super(properties, ParticleTypes.SOUL_FIRE_FLAME);
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return Block.canSupportCenter(level, pos.above(), Direction.DOWN);
}
@Override
public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) {
double x = pos.getX() + 0.5D;
double y = pos.getY() + 0.3D;
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.content.AntarchyTags;
import com.craisinlord.antarchy.mixins.AccessorFireBlock;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.FireBlock;
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 FireBlock {
public DreamFireBlock(BlockBehaviour.Properties properties) {
super(properties);
this.copyVanillaFlammability();
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).is(AntarchyTags.Blocks.DREAM_FIRE_BASE_BLOCKS)
|| super.canSurvive(state, level, pos);
}
private void copyVanillaFlammability() {
AccessorFireBlock vanillaFire = (AccessorFireBlock) Blocks.FIRE;
Object2IntMap<net.minecraft.world.level.block.Block> vanillaIgniteOdds = vanillaFire.antarchy$getIgniteOdds();
Object2IntMap<net.minecraft.world.level.block.Block> vanillaBurnOdds = vanillaFire.antarchy$getBurnOdds();
AccessorFireBlock self = (AccessorFireBlock) this;
Object2IntMap<net.minecraft.world.level.block.Block> igniteOdds = self.antarchy$getIgniteOdds();
Object2IntMap<net.minecraft.world.level.block.Block> burnOdds = self.antarchy$getBurnOdds();
for (Object2IntMap.Entry<net.minecraft.world.level.block.Block> entry : vanillaIgniteOdds.object2IntEntrySet()) {
igniteOdds.put(entry.getKey(), entry.getIntValue());
burnOdds.put(entry.getKey(), vanillaBurnOdds.getInt(entry.getKey()));
}
}
}
@@ -0,0 +1,22 @@
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 DreamSandBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@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 = new ResourceLocation(Antarchy.MODID, "dream_fire_flame");
public DreamTorchBlock(BlockBehaviour.Properties properties) {
super(properties, ParticleTypes.SOUL_FIRE_FLAME);
}
@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 = new ResourceLocation(Antarchy.MODID, "dream_fire_flame");
public DreamWallTorchBlock(BlockBehaviour.Properties properties) {
super(properties, ParticleTypes.SOUL_FIRE_FLAME);
}
@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,572 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.config.AntarchySettings;
import com.craisinlord.antarchy.content.advancement.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.InteractionResult;
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 int MAX_USES = 4;
private static final ResourceLocation DUCT_TAPE_ADVANCEMENT_ID = new ResourceLocation("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 int SEARCH_INTERVAL_TICKS = 4;
private static final double SEARCH_MOTION_THRESHOLD_SQR = 1.0E-8D;
private static final double SEARCH_PAD_XZ = Math.max(WALL_TRIGGER_DEPTH, TRIGGER_PAD);
private static final double SEARCH_PAD_Y = FLOOR_TRIGGER_HEIGHT;
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 VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return getShapeFor(state);
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return Shapes.empty();
}
@Override
public 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
public 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
public 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
public 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
public InteractionResult use(
BlockState state,
Level level,
BlockPos pos,
Player player,
InteractionHand hand,
BlockHitResult hitResult
) {
ItemStack stack = player.getItemInHand(hand);
if (stack.is(AntarchyObjects.DUCT_TAPE.get().asItem())) {
return InteractionResult.PASS;
}
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 InteractionResult.sidedSuccess(level.isClientSide);
}
if (!stack.isDamageableItem() || !stack.isDamaged() || stack.is(AntarchyTags.Items.DUCT_TAPE_BLACKLIST)) {
return InteractionResult.PASS;
}
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 InteractionResult.PASS;
}
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 InteractionResult.sidedSuccess(level.isClientSide);
}
@Override
public 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);
}
if (!shouldSearchForTape(entity)) {
return;
}
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;
}
public static boolean shouldTickStuckEntity(Entity entity) {
if (entity == null || entity.level().isClientSide() || isStickyBlacklist(entity)) {
return false;
}
if (!entity.isAlive() || entity.isRemoved()) {
return true;
}
StuckContact contact = STUCK_ENTITIES.get(entity.getUUID());
if (contact != null) {
return true;
}
return shouldSearchForTape(entity);
}
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 boolean shouldSearchForTape(Entity entity) {
Vec3 velocity = entity.getDeltaMovement();
if (velocity.lengthSqr() < SEARCH_MOTION_THRESHOLD_SQR) {
return false;
}
return (entity.tickCount + entity.getId()) % SEARCH_INTERVAL_TICKS == 0;
}
private static TapeHit findTouchedTape(Level level, Entity entity) {
AABB box = entity.getBoundingBox().inflate(SEARCH_PAD_XZ, SEARCH_PAD_Y, SEARCH_PAD_XZ);
BlockPos min = BlockPos.containing(box.minX, box.minY, box.minZ);
BlockPos max = BlockPos.containing(box.maxX, box.maxY, box.maxZ);
if (!level.hasChunksAt(min, max)) {
return null;
}
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.isAir()) {
continue;
}
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,31 @@
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 DuplicatorLogBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
DuplicatorTreeLogic.tryDuplicate(level, pos, random);
}
@Override
public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
if (level instanceof ServerLevel serverLevel && !state.is(newState.getBlock())) {
DuplicatorTreeLogic.invalidateCacheNear(serverLevel, pos);
}
super.onRemove(state, level, pos, newState, movedByPiston);
}
}
@@ -0,0 +1,170 @@
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 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 VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
@Override
public boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos) {
return state.is(BlockTags.DIRT) || state.is(Blocks.FARMLAND);
}
@Override
public 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, boolean isClient) {
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
public 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,322 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.AntarchyTags;
import com.mojang.serialization.MapCodec;
import java.util.EnumMap;
import java.util.Map;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
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.BonemealableBlock;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jetbrains.annotations.Nullable;
public final class GiantLilyPadBlock extends Block implements BonemealableBlock {
public static final EnumProperty<TilePosition> TILE_POSITION = EnumProperty.create("tile_position", TilePosition.class);
public static final EnumProperty<PadRotation> ROTATION = EnumProperty.create("rotation", PadRotation.class);
public static final BooleanProperty HAS_LOTUS = BooleanProperty.create("has_lotus");
private static final VoxelShape SHAPE = Block.box(0.0D, 0.0D, 0.0D, 16.0D, 0.5D, 16.0D);
private static final ThreadLocal<Boolean> REMOVING_STRUCTURE = ThreadLocal.withInitial(() -> false);
private static final Map<TilePosition, Vec2> OFFSETS = createOffsets();
private static final double BOUNCE_FACTOR = 0.35D;
private static final double FORWARD_BOOST_MULTIPLIER = 1.05D;
private static final double MAX_BOOSTED_HORIZONTAL_SPEED = 0.6D;
public GiantLilyPadBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any()
.setValue(TILE_POSITION, TilePosition.CENTER)
.setValue(ROTATION, PadRotation.DEG_0)
.setValue(HAS_LOTUS, false));
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(TILE_POSITION, ROTATION, HAS_LOTUS);
}
@Override
public RenderShape getRenderShape(BlockState state) {
return RenderShape.MODEL;
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return isSupported(level, pos);
}
@Override
public @Nullable BlockState getStateForPlacement(BlockPlaceContext context) {
return this.defaultBlockState()
.setValue(TILE_POSITION, TilePosition.CENTER)
.setValue(ROTATION, rotationForPlacement(context.getClickedPos()));
}
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state, boolean isClient) {
return !structureHasLotus(level, centerFrom(pos, state));
}
@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) {
BlockPos center = centerFrom(pos, state);
if (structureHasLotus(level, center)) {
return;
}
level.setBlock(pos, state.setValue(HAS_LOTUS, true), Block.UPDATE_CLIENTS);
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
if (!state.canSurvive(level, pos)) {
return Blocks.AIR.defaultBlockState();
}
return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
}
@Override
public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
if (!state.is(newState.getBlock()) && !REMOVING_STRUCTURE.get()) {
removeStructure(level, pos, state);
}
super.onRemove(state, level, pos, newState, movedByPiston);
}
@Override
public InteractionResult use(
BlockState state,
Level level,
BlockPos pos,
Player player,
InteractionHand hand,
BlockHitResult hitResult
) {
ItemStack stack = player.getItemInHand(hand);
if (!stack.is(AntarchyObjects.LOTUS.get().asItem()) || structureHasLotus(level, centerFrom(pos, state))) {
return InteractionResult.PASS;
}
if (level.isClientSide) {
return InteractionResult.SUCCESS;
}
level.setBlock(pos, state.setValue(HAS_LOTUS, true), Block.UPDATE_CLIENTS);
if (!player.getAbilities().instabuild) {
stack.shrink(1);
}
level.playSound(null, pos, net.minecraft.sounds.SoundEvents.LILY_PAD_PLACE, SoundSource.BLOCKS, 1.0F, 1.0F);
return InteractionResult.CONSUME;
}
@Override
public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) {
super.stepOn(level, pos, state, entity);
if (!level.isClientSide) {
Vec3 movement = entity.getDeltaMovement();
double horizontalSpeed = movement.horizontalDistance();
if (horizontalSpeed > 0.02D && horizontalSpeed < MAX_BOOSTED_HORIZONTAL_SPEED) {
double boosted = Math.min(horizontalSpeed * FORWARD_BOOST_MULTIPLIER, MAX_BOOSTED_HORIZONTAL_SPEED);
double scale = boosted / horizontalSpeed;
entity.setDeltaMovement(movement.x * scale, movement.y, movement.z * scale);
}
}
}
@Override
public void updateEntityAfterFallOn(BlockGetter level, Entity entity) {
if (entity.isSuppressingBounce()) {
super.updateEntityAfterFallOn(level, entity);
return;
}
Vec3 movement = entity.getDeltaMovement();
if (movement.y < 0.0D) {
double bounce = entity instanceof LivingEntity ? BOUNCE_FACTOR : BOUNCE_FACTOR * 0.7D;
entity.setDeltaMovement(movement.x, -movement.y * bounce, movement.z);
}
}
@Override
public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) {
if (!state.getValue(HAS_LOTUS) || random.nextInt(10) != 0) {
return;
}
double x = pos.getX() + 0.5D + (random.nextDouble() - 0.5D) * 0.6D;
double z = pos.getZ() + 0.5D + (random.nextDouble() - 0.5D) * 0.6D;
double y = pos.getY() + 0.55D;
level.addParticle(AntarchyObjects.LOTUS_POLLEN.get(), x, y, z, 0.0D, 0.015D, 0.0D);
}
public static boolean canPlaceStructure(LevelAccessor level, BlockPos centerPos) {
for (TilePosition tilePosition : TilePosition.values()) {
BlockPos partPos = positionFor(centerPos, tilePosition);
if (!level.isEmptyBlock(partPos) || !isSupported(level, partPos)) {
return false;
}
}
return true;
}
public static void placeStructure(LevelAccessor level, BlockPos centerPos, PadRotation rotation) {
for (TilePosition tilePosition : TilePosition.values()) {
BlockPos partPos = positionFor(centerPos, tilePosition);
BlockState partState = AntarchyObjects.GIANT_LILY_PAD.get().defaultBlockState()
.setValue(TILE_POSITION, tilePosition)
.setValue(ROTATION, rotation)
.setValue(HAS_LOTUS, false);
level.setBlock(partPos, partState, Block.UPDATE_CLIENTS);
}
}
public static PadRotation rotationForPlacement(BlockPos pos) {
long seed = pos.asLong() ^ Long.rotateLeft(pos.asLong(), 17);
RandomSource random = RandomSource.create(seed);
return PadRotation.values()[random.nextInt(4)];
}
private static boolean isSupported(LevelReader level, BlockPos pos) {
return level.getFluidState(pos.below()).is(AntarchyTags.Fluids.GIANT_LILY_PAD_SUPPORTING_FLUIDS)
&& level.getFluidState(pos).isEmpty();
}
private static void removeStructure(Level level, BlockPos pos, BlockState state) {
BlockPos center = centerFrom(pos, state);
boolean shouldDropLotus = structureHasLotus(level, center) && !state.getValue(HAS_LOTUS);
REMOVING_STRUCTURE.set(true);
try {
for (TilePosition tilePosition : TilePosition.values()) {
BlockPos partPos = positionFor(center, tilePosition);
if (partPos.equals(pos)) {
continue;
}
BlockState partState = level.getBlockState(partPos);
if (partState.is(AntarchyObjects.GIANT_LILY_PAD.get())) {
level.removeBlock(partPos, false);
}
}
} finally {
REMOVING_STRUCTURE.set(false);
}
if (shouldDropLotus && !level.isClientSide) {
popResource(level, pos, new ItemStack(AntarchyObjects.LOTUS.get()));
}
}
private static boolean structureHasLotus(LevelReader level, BlockPos center) {
for (TilePosition tilePosition : TilePosition.values()) {
BlockState state = level.getBlockState(positionFor(center, tilePosition));
if (state.is(AntarchyObjects.GIANT_LILY_PAD.get()) && state.getValue(HAS_LOTUS)) {
return true;
}
}
return false;
}
private static BlockPos centerFrom(BlockPos pos, BlockState state) {
Vec2 offset = OFFSETS.get(state.getValue(TILE_POSITION));
return pos.offset((int) -offset.x, 0, (int) -offset.y);
}
private static BlockPos positionFor(BlockPos center, TilePosition tilePosition) {
Vec2 offset = OFFSETS.get(tilePosition);
return center.offset((int) offset.x, 0, (int) offset.y);
}
private static Map<TilePosition, Vec2> createOffsets() {
Map<TilePosition, Vec2> offsets = new EnumMap<>(TilePosition.class);
offsets.put(TilePosition.TOP_LEFT, new Vec2(-1, -1));
offsets.put(TilePosition.TOP_MIDDLE, new Vec2(0, -1));
offsets.put(TilePosition.TOP_RIGHT, new Vec2(1, -1));
offsets.put(TilePosition.MIDDLE_LEFT, new Vec2(-1, 0));
offsets.put(TilePosition.CENTER, new Vec2(0, 0));
offsets.put(TilePosition.MIDDLE_RIGHT, new Vec2(1, 0));
offsets.put(TilePosition.BOTTOM_LEFT, new Vec2(-1, 1));
offsets.put(TilePosition.BOTTOM_MIDDLE, new Vec2(0, 1));
offsets.put(TilePosition.BOTTOM_RIGHT, new Vec2(1, 1));
return offsets;
}
public enum TilePosition implements StringRepresentable {
TOP_LEFT("top_left"),
TOP_MIDDLE("top_middle"),
TOP_RIGHT("top_right"),
MIDDLE_LEFT("middle_left"),
CENTER("center"),
MIDDLE_RIGHT("middle_right"),
BOTTOM_LEFT("bottom_left"),
BOTTOM_MIDDLE("bottom_middle"),
BOTTOM_RIGHT("bottom_right");
private final String name;
TilePosition(String name) {
this.name = name;
}
@Override
public String getSerializedName() {
return this.name;
}
}
public enum PadRotation implements StringRepresentable {
DEG_0("0"),
DEG_90("90"),
DEG_180("180"),
DEG_270("270");
private final String name;
PadRotation(String name) {
this.name = name;
}
@Override
public String getSerializedName() {
return this.name;
}
}
}
@@ -0,0 +1,109 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.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.tags.BlockTags;
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.BushBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class GlowcapMushroomBlock extends BushBlock implements BonemealableBlock {
private static final VoxelShape SHAPE = Block.box(3.9D, 0.0D, 3.9D, 12.1D, 12.0D, 12.1D);
private static final ResourceKey<ConfiguredFeature<?, ?>> HUGE_GLOWCAP_MUSHROOM = ResourceKey.create(
Registries.CONFIGURED_FEATURE,
new ResourceLocation(Antarchy.MODID, "huge_glowcap_mushroom")
);
private static final int SPREAD_ATTEMPTS = 4;
private static final int MAX_LIGHT_LEVEL = 13;
public GlowcapMushroomBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public VoxelShape getShape(BlockState state, net.minecraft.world.level.BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
@Override
public boolean mayPlaceOn(BlockState state, net.minecraft.world.level.BlockGetter level, BlockPos pos) {
return state.is(BlockTags.MUSHROOM_GROW_BLOCK) || state.isFaceSturdy(level, pos, Direction.UP);
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
BlockPos belowPos = pos.below();
BlockState below = level.getBlockState(belowPos);
return this.mayPlaceOn(below, level, belowPos) && (below.is(BlockTags.MUSHROOM_GROW_BLOCK) || level.getRawBrightness(pos, 0) < MAX_LIGHT_LEVEL);
}
@Override
public boolean isRandomlyTicking(BlockState state) {
return true;
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (random.nextInt(25) != 0) {
return;
}
int spreadRange = 4;
BlockPos targetPos = pos;
for (int i = 0; i < SPREAD_ATTEMPTS; i++) {
targetPos = pos.offset(
random.nextInt(spreadRange * 2 + 1) - spreadRange,
random.nextInt(3) - 1,
random.nextInt(spreadRange * 2 + 1) - spreadRange
);
if (level.isEmptyBlock(targetPos) && canSpreadTo(level, targetPos)) {
level.setBlock(targetPos, this.defaultBlockState(), 2);
break;
}
}
}
private boolean canSpreadTo(ServerLevel level, BlockPos pos) {
if (level.getRawBrightness(pos, 0) > MAX_LIGHT_LEVEL) {
return false;
}
BlockState below = level.getBlockState(pos.below());
return this.mayPlaceOn(below, level, pos.below());
}
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state, boolean isClient) {
return true;
}
@Override
public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, BlockState state) {
return random.nextFloat() < 0.4F;
}
@Override
public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) {
Holder.Reference<ConfiguredFeature<?, ?>> feature = level.registryAccess()
.lookupOrThrow(Registries.CONFIGURED_FEATURE)
.getOrThrow(HUGE_GLOWCAP_MUSHROOM);
level.removeBlock(pos, false);
if (!feature.value().place(level, level.getChunkSource().getGenerator(), random, pos)) {
level.setBlock(pos, state, 3);
}
}
}
@@ -0,0 +1,113 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.Level;
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.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
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.BooleanProperty;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class HangingCreeprootsBlock extends BushBlock {
public static final IntegerProperty DISTANCE = IntegerProperty.create("distance", 0, 4);
public static final BooleanProperty BOTTOM = BooleanProperty.create("bottom");
public static final BooleanProperty STUNTED = BooleanProperty.create("stunted");
private static final int MAX_DISTANCE = 4;
private static final VoxelShape SHAPE = Block.box(4.0D, 0.0D, 4.0D, 12.0D, 16.0D, 12.0D);
public HangingCreeprootsBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(DISTANCE, 0).setValue(BOTTOM, true).setValue(STUNTED, false));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
@Override
public boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos) {
return state.is(this) || state.isFaceSturdy(level, pos, Direction.DOWN);
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
BlockPos abovePos = pos.above();
return this.mayPlaceOn(level.getBlockState(abovePos), level, abovePos);
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
if (!state.canSurvive(level, pos)) {
return net.minecraft.world.level.block.Blocks.AIR.defaultBlockState();
}
if (direction == Direction.DOWN) {
boolean bottom = !neighborState.is(this);
if (bottom != state.getValue(BOTTOM)) {
state = state.setValue(BOTTOM, bottom);
}
}
return state;
}
@Override
public boolean isRandomlyTicking(BlockState state) {
return state.getValue(BOTTOM) && !state.getValue(STUNTED) && state.getValue(DISTANCE) < MAX_DISTANCE;
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (state.getValue(STUNTED) || !state.getValue(BOTTOM) || state.getValue(DISTANCE) >= MAX_DISTANCE) {
return;
}
BlockPos belowPos = pos.below();
if (random.nextInt(4) != 0 || !level.getBlockState(belowPos).isAir()) {
return;
}
int distance = state.getValue(DISTANCE);
level.setBlock(pos, state.setValue(BOTTOM, false), Block.UPDATE_CLIENTS);
level.setBlock(belowPos, this.defaultBlockState().setValue(DISTANCE, distance + 1).setValue(BOTTOM, true), Block.UPDATE_ALL);
}
@Override
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult) {
ItemStack stack = player.getItemInHand(hand);
if (!stack.is(Items.SHEARS) || state.getValue(STUNTED)) {
return super.use(state, level, pos, player, hand, hitResult);
}
if (!level.isClientSide) {
level.setBlock(pos, state.setValue(STUNTED, true), Block.UPDATE_ALL);
stack.hurtAndBreak(1, player, p -> p.broadcastBreakEvent(hand));
level.playSound(null, pos, SoundEvents.SHEEP_SHEAR, SoundSource.BLOCKS, 1.0F, 1.0F);
}
return InteractionResult.sidedSuccess(level.isClientSide);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(DISTANCE, BOTTOM, STUNTED);
}
}
@@ -0,0 +1,64 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.BushBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public class HangingPeachBlock extends BushBlock {
private static final ResourceLocation PEACH_LEAVES_ID = new ResourceLocation(Antarchy.MODID, "peach_leaves");
private static final ResourceLocation PEACH_ITEM_ID = new ResourceLocation(Antarchy.MODID, "peach");
private static final VoxelShape SHAPE = Block.box(4.0D, 2.0D, 4.0D, 12.0D, 16.0D, 12.0D);
public HangingPeachBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return Shapes.empty();
}
@Override
public ItemStack getCloneItemStack(BlockGetter level, BlockPos pos, BlockState state) {
return new ItemStack(BuiltInRegistries.ITEM.getOptional(PEACH_ITEM_ID).orElse(Blocks.AIR.asItem()));
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
BlockState above = level.getBlockState(pos.above());
return above.is(BuiltInRegistries.BLOCK.getOptional(PEACH_LEAVES_ID).orElse(Blocks.AIR));
}
@Override
public 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();
}
}
@@ -0,0 +1,117 @@
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 {
private static final VoxelShape SHAPE = Block.box(4.0D, 0.0D, 4.0D, 12.0D, 18.0D, 12.0D);
public static final DirectionProperty FACING = BlockStateProperties.VERTICAL_DIRECTION;
public HushweedBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.UP));
}
@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
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
@Override
public 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
public 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
public RenderShape getRenderShape(BlockState state) {
return RenderShape.MODEL;
}
@Override
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
if (!level.isClientSide && entity instanceof LivingEntity livingEntity && !livingEntity.isSteppingCarefully()) {
livingEntity.hurt(level.damageSources().sweetBerryBush(), 1.0F);
}
super.entityInside(state, level, pos, entity);
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new HushweedBlockEntity(pos, state);
}
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
Supplier<BlockEntityType<HushweedBlockEntity>> typeSupplier = AntarchyObjects.HUSHWEED_BLOCK_ENTITY;
return level.isClientSide
? null
: createTickerHelper(blockEntityType, typeSupplier.get(),
(tickLevel, tickPos, tickState, blockEntity) -> {
if (tickLevel instanceof net.minecraft.server.level.ServerLevel serverLevel) {
HushweedBlockEntity.serverTick(serverLevel, tickPos, tickState, blockEntity);
}
});
}
}
@@ -0,0 +1,100 @@
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 {
public InfestedCoarseDirtBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public 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;
}
MolewormEntity moleworm = AntarchyObjects.MOLEWORM.get().create(level);
if (moleworm == null) {
return;
}
moleworm.moveTo(emergencePos.getX() + 0.5D, emergencePos.getY() + 0.05D, emergencePos.getZ() + 0.5D, level.random.nextFloat() * 360.0F, 0.0F);
if (!level.noCollision(moleworm)) {
moleworm.discard();
return;
}
level.setBlock(pos, Blocks.COARSE_DIRT.defaultBlockState(), 3);
level.addFreshEntity(moleworm);
level.playSound(null, emergencePos, SoundEvents.SILVERFISH_STEP, net.minecraft.sounds.SoundSource.BLOCKS, 0.45F, 0.8F + level.random.nextFloat() * 0.25F);
level.sendParticles(net.minecraft.core.particles.ParticleTypes.POOF, pos.getX() + 0.5D, pos.getY() + 0.45D, pos.getZ() + 0.5D, 8, 0.18D, 0.08D, 0.18D, 0.01D);
}
@Nullable
private static BlockPos findEmergencePos(BlockGetter level, BlockPos origin) {
BlockPos[] candidates = new BlockPos[] {
origin.above(),
origin.north(),
origin.south(),
origin.east(),
origin.west(),
origin.north().above(),
origin.south().above(),
origin.east().above(),
origin.west().above()
};
for (BlockPos candidate : candidates) {
if (isOpenStandingSpot(level, candidate)) {
return candidate;
}
}
return null;
}
private static boolean isOpenStandingSpot(BlockGetter level, BlockPos pos) {
BlockState state = level.getBlockState(pos);
BlockState above = level.getBlockState(pos.above());
BlockState below = level.getBlockState(pos.below());
return state.isAir()
&& above.isAir()
&& below.isFaceSturdy(level, pos.below(), Direction.UP);
}
}
@@ -0,0 +1,99 @@
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 {
public InfestedRootedDirtBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public 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;
}
MolewormEntity moleworm = AntarchyObjects.MOLEWORM.get().create(level);
if (moleworm == null) {
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,108 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.JerryEntity;
import com.craisinlord.antarchy.content.horde.CavarynHordeManager;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.context.BlockPlaceContext;
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.Blocks;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class JerryEggBlock extends Block {
public static final BooleanProperty ROTATED = BooleanProperty.create("rotated");
private static final ResourceLocation JERRY_ID = new ResourceLocation(Antarchy.MODID, "jerry");
private static final int HATCH_CHECK_INTERVAL = 1200;
private static final double HORDE_ACCELERATION_RADIUS = 5.0D;
private static final VoxelShape SHAPE = Block.box(1.5D, 0.0D, 1.5D, 14.5D, 16.0D, 14.5D);
public JerryEggBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(ROTATED, false));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return this.defaultBlockState().setValue(ROTATED, context.getHorizontalDirection().getAxis() == Direction.Axis.X);
}
@Override
public BlockState rotate(BlockState state, Rotation rotation) {
return rotation == Rotation.CLOCKWISE_90 || rotation == Rotation.COUNTERCLOCKWISE_90
? state.setValue(ROTATED, !state.getValue(ROTATED))
: state;
}
@Override
public BlockState mirror(BlockState state, Mirror mirror) {
return state;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
}
@Override
public 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
public boolean isRandomlyTicking(BlockState state) {
return true;
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!CavarynHordeManager.shouldAccelerateNearbyEggHatching(level, pos, HORDE_ACCELERATION_RADIUS, random)
&& random.nextInt(HATCH_CHECK_INTERVAL) != 0) {
return;
}
this.hatch(level, pos, random);
}
public void hatchWithNucleus(ServerLevel level, BlockPos pos) {
this.hatch(level, pos, level.random);
}
private void hatch(ServerLevel level, BlockPos pos, RandomSource random) {
EntityType<?> entityType = BuiltInRegistries.ENTITY_TYPE.get(JERRY_ID);
if (entityType.create(level) instanceof JerryEntity jerry) {
jerry.setStage(JerryEntity.Stage.INFANT);
jerry.moveTo(pos.getX() + 0.5D, pos.getY() + 0.15D, pos.getZ() + 0.5D, random.nextFloat() * 360.0F, 0.0F);
level.addFreshEntity(jerry);
level.destroyBlock(pos, false);
level.playSound(null, pos, SoundEvents.TURTLE_EGG_HATCH, SoundSource.HOSTILE, 0.8F, 0.8F + random.nextFloat() * 0.2F);
}
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(ROTATED);
}
}
@@ -0,0 +1,161 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.JumpyBugEntity;
import com.craisinlord.antarchy.content.horde.CavarynHordeManager;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.EntityType;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.player.Player;
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.Mirror;
import net.minecraft.world.level.block.Rotation;
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;
public class JumpyBugEggBlock extends Block {
public static final IntegerProperty HATCH = BlockStateProperties.HATCH;
public static final BooleanProperty HANGING = BlockStateProperties.HANGING;
public static final BooleanProperty ROTATED = BooleanProperty.create("rotated");
private static final int MAX_HATCH = 2;
private static final double PLAYER_PROXIMITY_RADIUS = 12.0D;
private static final double HORDE_ACCELERATION_RADIUS = 5.0D;
private static final float PLAYER_PROXIMITY_HATCH_CHANCE = 0.25F;
private static final int PLAYER_PROXIMITY_CHECK_INTERVAL = 200;
private static final VoxelShape FLOOR_SHAPE = Block.box(1.5D, 0.0D, 1.5D, 14.5D, 16.0D, 14.5D);
private static final VoxelShape CEILING_SHAPE = Block.box(1.5D, 0.0D, 1.5D, 14.5D, 16.0D, 14.5D);
private static final ResourceLocation JUMPY_BUG_ID = new ResourceLocation(Antarchy.MODID, "jumpy_bug");
public JumpyBugEggBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(HATCH, 0).setValue(HANGING, false).setValue(ROTATED, false));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(HANGING) ? CEILING_SHAPE : FLOOR_SHAPE;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
boolean hanging = context.getClickedFace() == Direction.DOWN
|| (context.getClickedFace() != Direction.UP && !canSupportFloor(context.getLevel(), context.getClickedPos()) && canSupportCeiling(context.getLevel(), context.getClickedPos()));
boolean rotated = context.getHorizontalDirection().getAxis() == Direction.Axis.X;
return this.defaultBlockState().setValue(HANGING, hanging).setValue(ROTATED, rotated);
}
@Override
public BlockState rotate(BlockState state, Rotation rotation) {
return rotation == Rotation.CLOCKWISE_90 || rotation == Rotation.COUNTERCLOCKWISE_90
? state.setValue(ROTATED, !state.getValue(ROTATED))
: state;
}
@Override
public BlockState mirror(BlockState state, Mirror mirror) {
return state;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return state.getValue(HANGING) ? canSupportCeiling(level, pos) : canSupportFloor(level, pos);
}
@Override
public 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();
}
private static boolean canSupportFloor(LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
}
private static boolean canSupportCeiling(LevelReader level, BlockPos pos) {
return level.getBlockState(pos.above()).isFaceSturdy(level, pos.above(), Direction.DOWN);
}
@Override
public boolean isRandomlyTicking(BlockState state) {
return true;
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!this.shouldUpdateHatchLevel(level, pos, state)) {
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.hatch(level, pos, random);
}
private boolean shouldUpdateHatchLevel(Level level, BlockPos pos, BlockState state) {
if (level instanceof ServerLevel serverLevel
&& CavarynHordeManager.shouldAccelerateNearbyEggHatching(serverLevel, pos, HORDE_ACCELERATION_RADIUS, level.random)) {
return true;
}
if (level.random.nextInt(PLAYER_PROXIMITY_CHECK_INTERVAL) == 0) {
Player nearbyPlayer = level.getNearestPlayer(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, PLAYER_PROXIMITY_RADIUS, false);
if (nearbyPlayer != null && level.random.nextFloat() < PLAYER_PROXIMITY_HATCH_CHANCE) {
return true;
}
}
BlockPos checkPos = state.getValue(HANGING) ? pos.above() : pos.below();
boolean onAmberMoss = level.getBlockState(checkPos).getBlock() instanceof AmberMossBlock;
return level.random.nextInt(onAmberMoss ? 150 : 500) == 0;
}
private void hatch(ServerLevel level, BlockPos pos, RandomSource random) {
level.removeBlock(pos, false);
level.playSound(null, pos, SoundEvents.TURTLE_EGG_HATCH, SoundSource.BLOCKS, 0.75F, 0.95F + random.nextFloat() * 0.1F);
@SuppressWarnings("unchecked")
EntityType<JumpyBugEntity> jumpyBugType = (EntityType<JumpyBugEntity>) (EntityType<?>) BuiltInRegistries.ENTITY_TYPE.getOptional(JUMPY_BUG_ID).orElse(null);
if (jumpyBugType == null) {
return;
}
JumpyBugEntity entity = jumpyBugType.create(level);
if (entity == null) {
return;
}
double spawnX = pos.getX() + 0.25D + random.nextDouble() * 0.5D;
double spawnZ = pos.getZ() + 0.25D + random.nextDouble() * 0.5D;
entity.moveTo(spawnX, pos.getY() + 0.1D, spawnZ, random.nextFloat() * 360.0F, 0.0F);
level.addFreshEntity(entity);
}
public void hatchWithNucleus(ServerLevel level, BlockPos pos) {
this.hatch(level, pos, level.random);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(HATCH, HANGING, ROTATED);
}
}
@@ -0,0 +1,100 @@
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.util.RandomSource;
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.RenderShape;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class LotusBlock extends Block {
public static final BooleanProperty HANGING = BlockStateProperties.HANGING;
private static final VoxelShape SHAPE_STANDING = Block.box(3.0D, 0.0D, 3.0D, 13.0D, 6.5D, 13.0D);
private static final VoxelShape SHAPE_HANGING = Block.box(3.0D, 9.5D, 3.0D, 13.0D, 16.0D, 13.0D);
public LotusBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(HANGING, false));
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(HANGING);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
Level level = context.getLevel();
BlockPos pos = context.getClickedPos();
boolean canHang = canSurvive(this.defaultBlockState().setValue(HANGING, true), level, pos);
boolean canStand = canSurvive(this.defaultBlockState().setValue(HANGING, false), level, pos);
if (context.getClickedFace() == Direction.DOWN && canHang) {
return this.defaultBlockState().setValue(HANGING, true);
}
if (canStand) {
return this.defaultBlockState().setValue(HANGING, false);
}
return canHang ? this.defaultBlockState().setValue(HANGING, true) : null;
}
@Override
public RenderShape getRenderShape(BlockState state) {
return RenderShape.MODEL;
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(HANGING) ? SHAPE_HANGING : SHAPE_STANDING;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
if (state.getValue(HANGING)) {
BlockPos abovePos = pos.above();
return level.getBlockState(abovePos).isFaceSturdy(level, abovePos, Direction.DOWN);
}
BlockPos belowPos = pos.below();
return level.getBlockState(belowPos).isFaceSturdy(level, belowPos, Direction.UP);
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
Direction supportDirection = state.getValue(HANGING) ? Direction.UP : Direction.DOWN;
if (direction == supportDirection && !state.canSurvive(level, pos)) {
return Blocks.AIR.defaultBlockState();
}
return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
}
@Override
public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) {
if (random.nextInt(10) != 0) {
return;
}
double x = pos.getX() + 0.5D + (random.nextDouble() - 0.5D) * 0.6D;
double z = pos.getZ() + 0.5D + (random.nextDouble() - 0.5D) * 0.6D;
double y = state.getValue(HANGING) ? pos.getY() + 0.2D : pos.getY() + 0.8D;
double motionY = state.getValue(HANGING) ? -0.02D : 0.015D;
level.addParticle(AntarchyObjects.LOTUS_POLLEN.get(), x, y, z, 0.0D, motionY, 0.0D);
}
}
@@ -0,0 +1,70 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.block.entity.LucidAnchorBlockEntity;
import net.minecraft.core.BlockPos;
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.BooleanProperty;
public class LucidAnchorBlock extends BaseEntityBlock {
public static final BooleanProperty ACTIVE = BlockStateProperties.LIT;
public LucidAnchorBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(ACTIVE, false));
}
@Override
public void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(ACTIVE);
}
@Override
public RenderShape getRenderShape(BlockState state) {
return RenderShape.MODEL;
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new LucidAnchorBlockEntity(pos, state);
}
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
return level.isClientSide
? null
: createTickerHelper(blockEntityType, AntarchyObjects.LUCID_ANCHOR_BLOCK_ENTITY.get(), (tickLevel, tickPos, tickState, blockEntity) -> {
if (tickLevel instanceof net.minecraft.server.level.ServerLevel serverLevel) {
LucidAnchorBlockEntity.serverTick(serverLevel, tickPos, tickState, blockEntity);
}
});
}
@Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
super.onPlace(state, level, pos, oldState, movedByPiston);
markStructureDirty(level, pos);
}
@Override
public void neighborChanged(BlockState state, Level level, BlockPos pos, Block block, BlockPos neighborPos, boolean movedByPiston) {
super.neighborChanged(state, level, pos, block, neighborPos, movedByPiston);
markStructureDirty(level, pos);
}
private static void markStructureDirty(Level level, BlockPos pos) {
if (level.getBlockEntity(pos) instanceof LucidAnchorBlockEntity lucidAnchor) {
lucidAnchor.markStructureDirty();
}
}
}
@@ -0,0 +1,245 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.entity.LurkingTerrorEntity;
import com.craisinlord.antarchy.content.block.AmberMossBlock;
import com.craisinlord.antarchy.content.block.CreepingHorrorEggBlock;
import com.craisinlord.antarchy.content.horde.CavarynHordeManager;
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.sounds.SoundSource;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.ambient.Bat;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.GameRules;
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.entity.BlockEntity;
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 LurkingTerrorEggBlock extends Block {
public static final IntegerProperty HATCH = BlockStateProperties.HATCH;
public static final IntegerProperty EGGS = BlockStateProperties.EGGS;
private static final float PANIC_HATCH_CHANCE = 0.25F;
private static final double HORDE_ACCELERATION_RADIUS = 5.0D;
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 LurkingTerrorEggBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(HATCH, 0).setValue(EGGS, 1));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(EGGS) > 1 ? MULTI_SHAPE : SINGLE_SHAPE;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
}
@Override
public 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
public 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
public boolean isRandomlyTicking(BlockState state) {
return true;
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!this.shouldUpdateHatchLevel(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, state.getValue(EGGS));
}
@Override
public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) {
if (entity instanceof Player && !entity.isSteppingCarefully() && this.destroyEgg(level, state, pos, entity, 100)) {
if (level instanceof ServerLevel serverLevel) {
panicHatchNearby(serverLevel, pos);
}
}
super.stepOn(level, pos, state, entity);
}
@Override
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
this.destroyEgg(level, state, pos, entity, 3);
super.fallOn(level, state, pos, entity, fallDistance);
}
@Override
public 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);
}
private static void panicHatchNearby(ServerLevel level, BlockPos origin) {
int radius = 6;
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
for (int dx = -radius; dx <= radius; dx++) {
for (int dy = -radius; dy <= radius; dy++) {
for (int dz = -radius; dz <= radius; dz++) {
if (dx == 0 && dy == 0 && dz == 0) continue;
mutable.set(origin.getX() + dx, origin.getY() + dy, origin.getZ() + dz);
BlockState nearby = level.getBlockState(mutable);
BlockPos immutable = mutable.immutable();
if (nearby.getBlock() instanceof LurkingTerrorEggBlock b) {
b.hatchPanickedEggs(level, immutable, nearby, level.random);
} else if (nearby.getBlock() instanceof CreepingHorrorEggBlock b) {
b.hatchPanickedEggs(level, immutable, nearby, level.random);
}
}
}
}
}
@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 boolean destroyEgg(Level level, BlockState state, BlockPos pos, Entity entity, int chance) {
if (level.isClientSide || !this.canDestroyEgg(level, entity) || level.random.nextInt(chance) != 0) {
return false;
}
level.playSound(null, pos, SoundEvents.TURTLE_EGG_BREAK, SoundSource.BLOCKS, 0.7F, 0.9F + level.random.nextFloat() * 0.2F);
this.decreaseEggs(level, pos, state);
return true;
}
void hatchPanickedEggs(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) {
int hatchedEggs = rollPanickedEggs(state.getValue(EGGS), random);
if (hatchedEggs <= 0) {
return;
}
this.hatchEggs(level, pos, state, random, hatchedEggs);
}
void hatchEggs(ServerLevel level, BlockPos pos, BlockState state, RandomSource random, int eggsToHatch) {
if (eggsToHatch >= state.getValue(EGGS)) {
level.removeBlock(pos, false);
} else {
level.setBlock(pos, state.setValue(EGGS, state.getValue(EGGS) - eggsToHatch), 2);
}
level.playSound(null, pos, SoundEvents.TURTLE_EGG_HATCH, SoundSource.BLOCKS, 0.75F, 0.95F + random.nextFloat() * 0.1F);
for (int i = 0; i < eggsToHatch; i++) {
LurkingTerrorEntity entity = AntarchyObjects.LURKING_TERROR.get().create(level);
if (entity == null) {
continue;
}
double spawnX = pos.getX() + 0.25D + random.nextDouble() * 0.5D;
double spawnZ = pos.getZ() + 0.25D + random.nextDouble() * 0.5D;
entity.moveTo(spawnX, pos.getY() + 0.1D, spawnZ, random.nextFloat() * 360.0F, 0.0F);
level.addFreshEntity(entity);
}
}
public void hatchWithNucleus(ServerLevel level, BlockPos pos, BlockState state) {
this.hatchEggs(level, pos, state, level.random, state.getValue(EGGS));
}
private static int rollPanickedEggs(int eggs, RandomSource random) {
int hatchedEggs = 0;
for (int i = 0; i < eggs; i++) {
if (random.nextFloat() < PANIC_HATCH_CHANCE) {
hatchedEggs++;
}
}
return hatchedEggs;
}
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, BlockPos pos) {
if (level instanceof ServerLevel serverLevel
&& CavarynHordeManager.shouldAccelerateNearbyEggHatching(serverLevel, pos, HORDE_ACCELERATION_RADIUS, level.random)) {
return true;
}
boolean onAmberMoss = level.getBlockState(pos.below()).getBlock() instanceof AmberMossBlock;
return level.random.nextInt(onAmberMoss ? 150 : 500) == 0;
}
private boolean canDestroyEgg(Level level, Entity entity) {
if (entity instanceof LurkingTerrorEntity || entity instanceof Bat) {
return false;
}
if (entity instanceof net.minecraft.world.entity.LivingEntity) {
return entity instanceof Player || level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
}
return false;
}
}
@@ -0,0 +1,67 @@
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.InteractionResult;
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 MilkweedBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any()
.setValue(BlockStateProperties.DOUBLE_BLOCK_HALF, DoubleBlockHalf.LOWER));
}
@Override
public InteractionResult use(
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 InteractionResult.PASS;
}
return super.use(state, level, pos, player, hand, hitResult);
}
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state, boolean isClient) {
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
public boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
return false;
}
}
@@ -0,0 +1,227 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
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.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.BooleanProperty;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class MoltingVinesBlock extends BushBlock implements BonemealableBlock {
public static final EnumProperty<Direction> GROWTH_DIRECTION = EnumProperty.create("growth_direction", Direction.class, Direction.UP, Direction.DOWN);
public static final BooleanProperty TOP_CAP = BooleanProperty.create("top_cap");
public static final BooleanProperty BOTTOM_CAP = BooleanProperty.create("bottom_cap");
public static final BooleanProperty BROODFRUIT = BooleanProperty.create("broodfruit");
public static final BooleanProperty STUNTED = BooleanProperty.create("stunted");
public static final IntegerProperty DISTANCE = IntegerProperty.create("distance", 0, 6);
private static final int MAX_DISTANCE = 6;
private static final int NATURAL_FRUIT_CHANCE = 40;
private static final VoxelShape SHAPE = Block.box(5.0D, 0.0D, 5.0D, 11.0D, 16.0D, 11.0D);
private static final ResourceLocation BROODFRUIT_ITEM_ID = new ResourceLocation("antarchy", "broodfruit");
public MoltingVinesBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any()
.setValue(GROWTH_DIRECTION, Direction.DOWN)
.setValue(TOP_CAP, false)
.setValue(BOTTOM_CAP, true)
.setValue(BROODFRUIT, false)
.setValue(STUNTED, false)
.setValue(DISTANCE, 0));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockGetter level = context.getLevel();
BlockPos pos = context.getClickedPos();
Direction growthDirection = resolveGrowthDirection(level, pos);
return computeState(this.defaultBlockState().setValue(GROWTH_DIRECTION, growthDirection).setValue(DISTANCE, 0), level, pos);
}
private Direction resolveGrowthDirection(BlockGetter level, BlockPos pos) {
BlockState belowState = level.getBlockState(pos.below());
if (belowState.is(this) && belowState.getValue(GROWTH_DIRECTION) == Direction.UP) {
return Direction.UP;
}
BlockState aboveState = level.getBlockState(pos.above());
if (aboveState.is(this) && aboveState.getValue(GROWTH_DIRECTION) == Direction.DOWN) {
return Direction.DOWN;
}
return hasSturdyAnchor(level, pos, Direction.UP) ? Direction.DOWN : Direction.UP;
}
private static boolean hasSturdyAnchor(BlockGetter level, BlockPos pos, Direction towardAnchor) {
BlockPos anchorPos = pos.relative(towardAnchor);
BlockState anchorState = level.getBlockState(anchorPos);
return anchorState.isFaceSturdy(level, anchorPos, towardAnchor.getOpposite());
}
@Override
public boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos) {
return state.is(this) || state.isFaceSturdy(level, pos, Direction.DOWN) || state.isFaceSturdy(level, pos, Direction.UP);
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
Direction anchorDirection = state.getValue(GROWTH_DIRECTION).getOpposite();
BlockPos anchorPos = pos.relative(anchorDirection);
BlockState anchorState = level.getBlockState(anchorPos);
if (anchorState.is(this)) {
return true;
}
return anchorState.isFaceSturdy(level, anchorPos, anchorDirection.getOpposite());
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
if (!state.canSurvive(level, pos)) {
return net.minecraft.world.level.block.Blocks.AIR.defaultBlockState();
}
if (direction == Direction.UP || direction == Direction.DOWN) {
return computeState(state, level, pos);
}
return state;
}
private static BlockState computeState(BlockState state, BlockGetter level, BlockPos pos) {
boolean aboveIsSame = level.getBlockState(pos.above()).is(state.getBlock());
boolean belowIsSame = level.getBlockState(pos.below()).is(state.getBlock());
Direction growthDirection = state.getValue(GROWTH_DIRECTION);
boolean topCap = growthDirection == Direction.UP && !aboveIsSame;
boolean bottomCap = growthDirection == Direction.DOWN && !belowIsSame;
state = state.setValue(TOP_CAP, topCap).setValue(BOTTOM_CAP, bottomCap);
if (topCap || bottomCap) {
state = state.setValue(BROODFRUIT, false);
}
return state;
}
@Override
public boolean isRandomlyTicking(BlockState state) {
return !state.getValue(STUNTED);
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (state.getValue(STUNTED)) {
return;
}
boolean isTip = state.getValue(GROWTH_DIRECTION) == Direction.DOWN ? state.getValue(BOTTOM_CAP) : state.getValue(TOP_CAP);
if (isTip && state.getValue(DISTANCE) < MAX_DISTANCE && random.nextInt(6) == 0) {
BlockPos growPos = pos.relative(state.getValue(GROWTH_DIRECTION));
if (level.getBlockState(growPos).isAir()) {
BlockState grownState = this.defaultBlockState()
.setValue(GROWTH_DIRECTION, state.getValue(GROWTH_DIRECTION))
.setValue(DISTANCE, state.getValue(DISTANCE) + 1);
level.setBlock(growPos, grownState, Block.UPDATE_ALL);
BlockState posState = level.getBlockState(pos);
if (posState.is(this)) {
level.setBlock(pos, computeState(posState, level, pos), Block.UPDATE_CLIENTS);
}
BlockState growState = level.getBlockState(growPos);
if (growState.is(this)) {
level.setBlock(growPos, computeState(growState, level, growPos), Block.UPDATE_CLIENTS);
}
}
}
if (!state.getValue(TOP_CAP) && !state.getValue(BOTTOM_CAP) && !state.getValue(BROODFRUIT) && random.nextInt(NATURAL_FRUIT_CHANCE) == 0) {
level.setBlock(pos, state.setValue(BROODFRUIT, true), Block.UPDATE_ALL);
}
}
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state, boolean isClient) {
return !state.getValue(TOP_CAP) && !state.getValue(BOTTOM_CAP) && !state.getValue(BROODFRUIT);
}
@Override
public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, BlockState state) {
return true;
}
@Override
public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) {
level.setBlock(pos, state.setValue(BROODFRUIT, true), Block.UPDATE_ALL);
}
@Override
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult) {
ItemStack stack = player.getItemInHand(hand);
if (stack.is(Items.SHEARS) && !state.getValue(STUNTED)) {
if (!level.isClientSide) {
level.setBlock(pos, state.setValue(STUNTED, true), Block.UPDATE_ALL);
stack.hurtAndBreak(1, player, p -> p.broadcastBreakEvent(hand));
level.playSound(null, pos, SoundEvents.SHEEP_SHEAR, SoundSource.BLOCKS, 1.0F, 1.0F);
}
return InteractionResult.sidedSuccess(level.isClientSide);
}
if (!state.getValue(BROODFRUIT)) {
return super.use(state, level, pos, player, hand, hitResult);
}
if (!level.isClientSide) {
BuiltInRegistries.ITEM.getOptional(BROODFRUIT_ITEM_ID).ifPresent(item -> harvestFruit(level, pos, item));
level.setBlock(pos, state.setValue(BROODFRUIT, false), Block.UPDATE_ALL);
level.playSound(null, pos, SoundEvents.CAVE_VINES_PICK_BERRIES, SoundSource.BLOCKS, 1.0F, 0.9F + level.random.nextFloat() * 0.2F);
}
return InteractionResult.sidedSuccess(level.isClientSide);
}
private static void harvestFruit(Level level, BlockPos pos, Item item) {
Block.popResource(level, pos, new ItemStack(item, 1));
}
@Override
public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
if (!level.isClientSide && state.getValue(BROODFRUIT) && !state.is(newState.getBlock())) {
BuiltInRegistries.ITEM.getOptional(BROODFRUIT_ITEM_ID).ifPresent(item -> harvestFruit(level, pos, item));
}
super.onRemove(state, level, pos, newState, movedByPiston);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(GROWTH_DIRECTION, TOP_CAP, BOTTOM_CAP, BROODFRUIT, STUNTED, DISTANCE);
}
}
@@ -0,0 +1,52 @@
package com.craisinlord.antarchy.content.block;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.GlowLichenBlock;
import net.minecraft.world.level.block.MultifaceBlock;
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.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public class MucusBlock extends GlowLichenBlock {
private static final VoxelShape DOWN_COLLISION_SHAPE = Shapes.box(0.0D, 0.0D, 0.0D, 1.0D, 0.0625D, 1.0D);
private static final double SLIDE_ACCELERATION = 0.025D;
private static final double SLIDE_MAX_SPEED = 0.6D;
private static final double SLIDE_MIN_SPEED = 0.02D;
public MucusBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(MultifaceBlock.getFaceProperty(Direction.DOWN)) ? DOWN_COLLISION_SHAPE : Shapes.empty();
}
@Override
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
super.entityInside(state, level, pos, entity);
if (level.isClientSide || !state.getValue(MultifaceBlock.getFaceProperty(Direction.DOWN))) {
return;
}
Vec3 delta = entity.getDeltaMovement();
Vec3 horizontal = new Vec3(delta.x, 0.0D, delta.z);
double speed = horizontal.length();
if (speed < SLIDE_MIN_SPEED) {
return;
}
Vec3 direction = horizontal.scale(1.0D / speed);
double boostedSpeed = Math.min(speed + SLIDE_ACCELERATION, SLIDE_MAX_SPEED);
entity.setDeltaMovement(direction.x * boostedSpeed, delta.y, direction.z * boostedSpeed);
entity.hurtMarked = true;
entity.hasImpulse = true;
}
}
@@ -0,0 +1,46 @@
package com.craisinlord.antarchy.content.block;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.BushBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class NadirSaplingBlock extends BushBlock {
private static final VoxelShape SHAPE = Block.box(2.0D, 0.0D, 2.0D, 14.0D, 12.0D, 14.0D);
public NadirSaplingBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public 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
public 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();
}
}
@@ -0,0 +1,161 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.entity.UpwardFallingBlockEntity;
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.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 NyxiteSpikeBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@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
public 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
public 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);
UpwardFallingBlockEntity.fallUp(level, cursor, spikeState);
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,199 @@
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 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 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
public boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos) {
return state.is(BlockTags.DIRT) || state.is(Blocks.FARMLAND);
}
@Override
public 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
public 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
public 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, boolean isClient) {
return !state.getValue(HANGING);
}
@Override
public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, BlockState state) {
return !state.getValue(HANGING) && random.nextFloat() < 0.75F;
}
@Override
public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) {
if (state.getValue(HANGING)) {
return;
}
this.advanceGrowth(level, pos, state, random);
}
private void advanceGrowth(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) {
if (state.getValue(STAGE) < MAX_STAGE) {
level.setBlock(pos, state.setValue(STAGE, state.getValue(STAGE) + 1), Block.UPDATE_ALL);
return;
}
this.growConfiguredTree(level, pos, state, random);
}
private void growConfiguredTree(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) {
Footprint largeFootprint = this.findFootprint(level, pos, 3);
if (largeFootprint != null) {
if (largeFootprint.fullyMatured()) {
this.placeConfiguredTree(level, largeFootprint, OuranwoodTreeGrowers.OURANWOOD_LARGE_TREE, random);
}
return;
}
Footprint mediumFootprint = this.findFootprint(level, pos, 2);
if (mediumFootprint != null) {
if (mediumFootprint.fullyMatured()) {
this.placeConfiguredTree(level, mediumFootprint, OuranwoodTreeGrowers.OURANWOOD_MEDIUM_TREE, random);
}
return;
}
this.placeConfiguredTree(level, new Footprint(pos, Map.of(pos, state)), OuranwoodTreeGrowers.OURANWOOD_YOUNG_TREE, random);
}
private Footprint findFootprint(ServerLevel level, BlockPos pos, int size) {
for (int offsetX = 0; offsetX < size; offsetX++) {
for (int offsetZ = 0; offsetZ < size; offsetZ++) {
BlockPos origin = pos.offset(-offsetX, 0, -offsetZ);
Map<BlockPos, BlockState> blocks = new LinkedHashMap<>();
boolean matches = true;
boolean fullyMatured = true;
for (int x = 0; x < size && matches; x++) {
for (int z = 0; z < size; z++) {
BlockPos checkPos = origin.offset(x, 0, z);
BlockState checkState = level.getBlockState(checkPos);
if (!checkState.is(this) || checkState.getValue(HANGING)) {
matches = false;
break;
}
fullyMatured &= checkState.getValue(STAGE) >= MAX_STAGE;
blocks.put(checkPos, checkState);
}
}
if (matches) {
return new Footprint(origin, blocks, fullyMatured);
}
}
}
return null;
}
private void placeConfiguredTree(ServerLevel level, Footprint footprint, ResourceKey<ConfiguredFeature<?, ?>> featureKey, RandomSource random) {
Holder.Reference<ConfiguredFeature<?, ?>> feature = level.registryAccess()
.lookupOrThrow(Registries.CONFIGURED_FEATURE)
.getOrThrow(featureKey);
for (BlockPos saplingPos : footprint.blocks().keySet()) {
level.removeBlock(saplingPos, false);
}
if (feature.value().place(level, level.getChunkSource().getGenerator(), random, footprint.origin())) {
return;
}
for (Map.Entry<BlockPos, BlockState> entry : footprint.blocks().entrySet()) {
level.setBlock(entry.getKey(), entry.getValue(), Block.UPDATE_ALL);
}
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(HANGING, STAGE);
}
private record Footprint(BlockPos origin, Map<BlockPos, BlockState> blocks, boolean fullyMatured) {
private Footprint(BlockPos origin, Map<BlockPos, BlockState> blocks) {
this(origin, blocks, true);
}
}
}
@@ -0,0 +1,189 @@
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 {
/*
* 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
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
public 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
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (decaying(state)) {
dropResources(state, level, pos);
level.removeBlock(pos, false);
}
}
@Override
public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
level.setBlock(pos, recalculateDistance(state, level, pos), Block.UPDATE_ALL);
}
@Override
public 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, boolean isClient) {
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,19 @@
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 OuranwoodLogBlock(BlockBehaviour.Properties properties) {
super(properties);
}
public OuranwoodLogBlock(Supplier<Block> strippedBlock, BlockBehaviour.Properties properties) {
super(properties);
}
}
@@ -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
public 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,194 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.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 PeachLeavesBlock extends LeavesBlock implements BonemealableBlock {
private static final ResourceLocation HANGING_PEACH_ID = new ResourceLocation(Antarchy.MODID, "hanging_peach");
public static final IntegerProperty PEACH_DISTANCE = IntegerProperty.create("peach_distance", 1, 13);
public static final BooleanProperty PERSISTENT = LeavesBlock.PERSISTENT;
public static final BooleanProperty WATERLOGGED = LeavesBlock.WATERLOGGED;
public static final int PEACH_MAX_DISTANCE = 12;
public static final int PEACH_DECAY_DISTANCE = PEACH_MAX_DISTANCE + 1;
public PeachLeavesBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any()
.setValue(DISTANCE, DECAY_DISTANCE)
.setValue(PEACH_DISTANCE, PEACH_DECAY_DISTANCE)
.setValue(PERSISTENT, false)
.setValue(WATERLOGGED, false));
}
@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 void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(LeavesBlock.DISTANCE, PEACH_DISTANCE, PERSISTENT, WATERLOGGED);
}
@Override
public boolean isRandomlyTicking(BlockState state) {
return decaying(state);
}
@Override
protected boolean decaying(BlockState state) {
return !state.getValue(PERSISTENT) && state.getValue(PEACH_DISTANCE) > PEACH_MAX_DISTANCE;
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (decaying(state)) {
dropResources(state, level, pos);
level.removeBlock(pos, false);
}
}
@Override
public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
level.setBlock(pos, recalculateDistance(state, level, pos), Block.UPDATE_ALL);
}
@Override
public 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(PEACH_DECAY_DISTANCE, getDistanceAt(neighborState) + 1);
int currentDistance = state.getValue(PEACH_DISTANCE);
if (neighborDistance != 1 || currentDistance != neighborDistance) {
level.scheduleTick(pos, this, 1);
}
return state;
}
@Override
public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) {
if (random.nextInt(18) != 0) {
return;
}
level.addParticle(
AntarchyObjects.PEACH_LEAVES_PARTICLE.get(),
pos.getX() + random.nextDouble(),
pos.getY() + random.nextDouble(),
pos.getZ() + random.nextDouble(),
0.0D,
-0.02D,
0.0D
);
}
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state, boolean isClient) {
return level.getBlockState(pos.below()).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) {
if (!level.getBlockState(pos.below()).isAir()) {
return;
}
level.setBlock(pos.below(), createHangingPeachState(), Block.UPDATE_ALL);
}
public static BlockState createHangingPeachState() {
return BuiltInRegistries.BLOCK.getOptional(HANGING_PEACH_ID)
.map(Block::defaultBlockState)
.orElseThrow(() -> new IllegalStateException("Missing hanging peach block: " + HANGING_PEACH_ID));
}
private static BlockState recalculateDistance(BlockState state, LevelReader level, BlockPos pos) {
int bestDistance = PEACH_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;
}
}
return setPeachDistance(state, Math.min(PEACH_DECAY_DISTANCE, bestDistance));
}
private static BlockState setPeachDistance(BlockState state, int distance) {
int peachDistance = Math.max(1, Math.min(PEACH_DECAY_DISTANCE, distance));
int vanillaDistance = Math.min(LeavesBlock.DECAY_DISTANCE, peachDistance);
return state
.setValue(PEACH_DISTANCE, peachDistance)
.setValue(LeavesBlock.DISTANCE, vanillaDistance);
}
private static int getDistanceAt(BlockState state) {
if (state.is(BlockTags.LOGS)) {
return 0;
}
if (state.hasProperty(PEACH_DISTANCE)) {
return state.getValue(PEACH_DISTANCE);
}
if (state.hasProperty(LeavesBlock.DISTANCE)) {
return state.getValue(LeavesBlock.DISTANCE);
}
return PEACH_DECAY_DISTANCE;
}
public static BlockState setPeachDistanceForWorldgen(BlockState state, int distance) {
int peachDistance = Math.max(1, Math.min(PEACH_DECAY_DISTANCE, distance));
int vanillaDistance = Math.min(LeavesBlock.DECAY_DISTANCE, peachDistance);
return state
.setValue(PEACH_DISTANCE, peachDistance)
.setValue(LeavesBlock.DISTANCE, vanillaDistance);
}
}
@@ -0,0 +1,128 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.worldgen.elythia.PeachTreeGrowers;
import com.mojang.serialization.MapCodec;
import java.util.LinkedHashMap;
import java.util.Map;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
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.levelgen.feature.ConfiguredFeature;
public class PeachSaplingBlock extends BushBlock implements BonemealableBlock {
public PeachSaplingBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (level.getMaxLocalRawBrightness(pos.above()) >= 9 && random.nextInt(7) == 0) {
this.growConfiguredTree(level, pos, state, random);
}
}
@Override
public 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)
: Blocks.AIR.defaultBlockState();
}
@Override
public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state, boolean isClient) {
return true;
}
@Override
public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, BlockState state) {
return random.nextFloat() < 0.45F;
}
@Override
public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) {
this.growConfiguredTree(level, pos, state, random);
}
private void growConfiguredTree(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) {
Footprint largeFootprint = this.findFootprint(level, pos);
if (largeFootprint != null) {
this.placeConfiguredTree(level, largeFootprint, PeachTreeGrowers.PEACH_LARGE_TREE, random);
return;
}
this.placeConfiguredTree(level, new Footprint(pos, Map.of(pos, state)), PeachTreeGrowers.PEACH_TREE, random);
}
private Footprint findFootprint(ServerLevel level, BlockPos pos) {
for (int offsetX = 0; offsetX < 2; offsetX++) {
for (int offsetZ = 0; offsetZ < 2; offsetZ++) {
BlockPos origin = pos.offset(-offsetX, 0, -offsetZ);
Map<BlockPos, BlockState> blocks = new LinkedHashMap<>();
boolean matches = true;
for (int x = 0; x < 2 && matches; x++) {
for (int z = 0; z < 2; z++) {
BlockPos checkPos = origin.offset(x, 0, z);
BlockState checkState = level.getBlockState(checkPos);
if (!checkState.is(this)) {
matches = false;
break;
}
blocks.put(checkPos, checkState);
}
}
if (matches) {
return new Footprint(origin, blocks);
}
}
}
return null;
}
private void placeConfiguredTree(
ServerLevel level,
Footprint footprint,
net.minecraft.resources.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);
}
}
private record Footprint(BlockPos origin, Map<BlockPos, BlockState> blocks) {
}
}
@@ -0,0 +1,68 @@
package com.craisinlord.antarchy.content.block;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.PressurePlateBlock;
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.BlockSetType;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class PolishedNyxitePressurePlateBlock extends PressurePlateBlock {
public static final BooleanProperty CEILING = BooleanProperty.create("ceiling");
private static final VoxelShape CEILING_SHAPE = Block.box(1.0D, 15.0D, 1.0D, 15.0D, 16.0D, 15.0D);
private static final VoxelShape CEILING_PRESSED_SHAPE = Block.box(1.0D, 15.5D, 1.0D, 15.0D, 16.0D, 15.0D);
private static final AABB CEILING_TOUCH_AABB = new AABB(0.0625D, 0.75D, 0.0625D, 0.9375D, 1.0D, 0.9375D);
public PolishedNyxitePressurePlateBlock(BlockSetType type, BlockBehaviour.Properties properties) {
super(Sensitivity.EVERYTHING, properties, type);
this.registerDefaultState(this.stateDefinition.any().setValue(POWERED, false).setValue(CEILING, false));
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(CEILING);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
boolean ceiling = context.getClickedFace() == Direction.DOWN;
return this.defaultBlockState().setValue(CEILING, ceiling);
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return state.getValue(CEILING)
? Block.canSupportCenter(level, pos.above(), Direction.DOWN)
: super.canSurvive(state, level, pos);
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
if (!state.getValue(CEILING)) {
return super.getShape(state, level, pos, context);
}
return state.getValue(POWERED) ? CEILING_PRESSED_SHAPE : CEILING_SHAPE;
}
@Override
protected int getSignalStrength(Level level, BlockPos pos) {
BlockState state = level.getBlockState(pos);
if (!state.getValue(CEILING)) {
return super.getSignalStrength(level, pos);
}
return getEntityCount(level, CEILING_TOUCH_AABB.move(pos), Entity.class) > 0 ? 15 : 0;
}
}
@@ -0,0 +1,297 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.block.entity.PotentNyxiteBlockEntity;
import com.craisinlord.antarchy.content.block.state.PotentNyxiteState;
import com.craisinlord.antarchy.content.AntarchyTags;
import com.craisinlord.antarchy.content.fluid.AntarchyFluidChecks;
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 HYPNOTIC_GAS_SOUND_ID = new ResourceLocation("antarchy", "potent_nyxite_hypnotic_gas");
private static final ResourceLocation HYPNOTIC_GAS_CLOUD_ID = new ResourceLocation("antarchy", "hypnotic_gas_cloud");
private static final ResourceLocation HYPNOTIC_GAS_CLOUD_DOWN_ID = new ResourceLocation("antarchy", "hypnotic_gas_cloud_down");
public static final EnumProperty<PotentNyxiteState> STATE = EnumProperty.create("state", PotentNyxiteState.class);
private final Supplier<? extends BlockEntityType<PotentNyxiteBlockEntity>> blockEntityTypeSupplier;
public PotentNyxiteBlock(
Supplier<? extends BlockEntityType<PotentNyxiteBlockEntity>> blockEntityTypeSupplier,
BlockBehaviour.Properties properties
) {
super(properties);
this.blockEntityTypeSupplier = blockEntityTypeSupplier;
this.registerDefaultState(this.stateDefinition.any().setValue(STATE, PotentNyxiteState.DRY));
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(STATE);
}
@Override
public 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
public 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
public 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 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() && AntarchyFluidChecks.isAntiwater(fluidState);
}
public static boolean hasGasFluid(LevelAccessor level, BlockPos pos, Direction direction) {
FluidState fluidState = level.getFluidState(pos.relative(direction));
return fluidState.isSource() && AntarchyFluidChecks.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 (!AntarchyFluidChecks.isAntiwater(fluidState)) {
break;
}
depth++;
cursor.move(direction);
}
if (depth <= 0) {
return 0;
}
BlockState terminatorState = level.getBlockState(cursor);
FluidState terminatorFluidState = level.getFluidState(cursor);
if (terminatorFluidState.isSourceOfType(Fluids.LAVA) || terminatorState.is(AntarchyTags.Blocks.POTENT_NYXITE_ACTIVATION_BLOCKS)) {
return depth;
}
return 0;
}
private static boolean hasValidFluidColumn(LevelAccessor level, BlockPos pos, Direction direction) {
return getFluidColumnDepth(level, pos, direction) > 0;
}
private static void spawnHypnoticGasParticlesAt(
Level level,
RandomSource random,
BlockPos particlePos,
ResourceLocation particleId,
Direction eruptionDirection
) {
level.addAlwaysVisibleParticle(
simpleParticle(particleId),
particlePos.getX() + 0.2D + random.nextDouble() * 0.6D,
particlePos.getY() + 0.1D + random.nextDouble() * 0.35D,
particlePos.getZ() + 0.2D + random.nextDouble() * 0.6D,
0.0D,
eruptionDirection == Direction.UP ? 0.01D : -0.01D,
0.0D
);
}
private static SimpleParticleType simpleParticle(ResourceLocation id) {
return (SimpleParticleType) BuiltInRegistries.PARTICLE_TYPE.get(id);
}
}
@@ -0,0 +1,289 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.content.AntarchyObjects;
import com.craisinlord.antarchy.content.block.entity.SeashellBlockEntity;
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.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
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.BaseEntityBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.SimpleWaterloggedBlock;
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.BooleanProperty;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jetbrains.annotations.Nullable;
public final class SeashellBlock extends BaseEntityBlock implements SimpleWaterloggedBlock {
public static final DirectionProperty FACING = HorizontalDirectionalBlock.FACING;
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
private static final double SHELL_MIN = 1.0D;
private static final double SHELL_MAX = 15.0D;
private static final double SHELL_HEIGHT = 4.333333D;
private static final double COLLISION_FORWARD_OFFSET = 1.0D;
private static final VoxelShape OUTLINE_SHAPE = Block.box(SHELL_MIN, 0.0D, SHELL_MIN, SHELL_MAX, SHELL_HEIGHT, SHELL_MAX);
public SeashellBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any()
.setValue(FACING, Direction.NORTH)
.setValue(POWERED, false)
.setValue(WATERLOGGED, false));
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FACING, POWERED, WATERLOGGED);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
FluidState fluidState = context.getLevel().getFluidState(context.getClickedPos());
boolean powered = context.getLevel().hasNeighborSignal(context.getClickedPos());
return this.defaultBlockState()
.setValue(FACING, context.getHorizontalDirection().getOpposite())
.setValue(POWERED, powered)
.setValue(WATERLOGGED, fluidState.getType() == Fluids.WATER);
}
@Override
public RenderShape getRenderShape(BlockState state) {
return RenderShape.ENTITYBLOCK_ANIMATED;
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return OUTLINE_SHAPE;
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return collisionShape(state.getValue(FACING));
}
@Override
public VoxelShape getOcclusionShape(BlockState state, BlockGetter level, BlockPos pos) {
return OUTLINE_SHAPE;
}
@Override
public BlockState rotate(BlockState state, net.minecraft.world.level.block.Rotation rotation) {
return state.setValue(FACING, rotation.rotate(state.getValue(FACING)));
}
@Override
public BlockState mirror(BlockState state, net.minecraft.world.level.block.Mirror mirror) {
return state.rotate(mirror.getRotation(state.getValue(FACING)));
}
@Override
public FluidState getFluidState(BlockState state) {
return state.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(state);
}
@Override
public 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 (!state.canSurvive(level, pos)) {
return Blocks.AIR.defaultBlockState();
}
if (level instanceof Level actualLevel && !actualLevel.isClientSide) {
this.updatePowerState(actualLevel, pos, state);
}
return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
}
@Override
public void neighborChanged(
BlockState state,
Level level,
BlockPos pos,
Block block,
BlockPos neighborPos,
boolean movedByPiston
) {
super.neighborChanged(state, level, pos, block, neighborPos, movedByPiston);
if (!level.isClientSide) {
this.updatePowerState(level, pos, state);
}
}
@Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
super.onPlace(state, level, pos, oldState, movedByPiston);
if (!level.isClientSide) {
this.updatePowerState(level, pos, state);
}
}
@Override
public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
if (!state.is(newState.getBlock()) && level.getBlockEntity(pos) instanceof SeashellBlockEntity seashell) {
seashell.dropContents(level, pos);
}
super.onRemove(state, level, pos, newState, movedByPiston);
}
@Override
public InteractionResult use(
BlockState state,
Level level,
BlockPos pos,
Player player,
InteractionHand hand,
BlockHitResult hitResult
) {
ItemStack stack = player.getItemInHand(hand);
if (!(level.getBlockEntity(pos) instanceof SeashellBlockEntity seashell)) {
return InteractionResult.PASS;
}
if (player.isShiftKeyDown()) {
if (level.isClientSide) {
return InteractionResult.SUCCESS;
}
if (seashell.closeManually()) {
level.playSound(null, pos, SoundEvents.CHEST_CLOSE, SoundSource.BLOCKS, 0.6F, 0.95F + level.random.nextFloat() * 0.1F);
return InteractionResult.CONSUME;
}
return InteractionResult.PASS;
}
if (!seashell.isEffectivelyOpen()) {
if (level.isClientSide) {
return InteractionResult.SUCCESS;
}
if (seashell.openManually()) {
level.playSound(null, pos, SoundEvents.CHEST_OPEN, SoundSource.BLOCKS, 0.6F, 0.95F + level.random.nextFloat() * 0.1F);
return InteractionResult.CONSUME;
}
return InteractionResult.PASS;
}
if (stack.isEmpty() && !seashell.hasAnyContents()) {
if (level.isClientSide) {
return InteractionResult.SUCCESS;
}
if (seashell.closeManually()) {
level.playSound(null, pos, SoundEvents.CHEST_CLOSE, SoundSource.BLOCKS, 0.6F, 0.95F + level.random.nextFloat() * 0.1F);
return InteractionResult.CONSUME;
}
return InteractionResult.PASS;
}
if (!stack.isEmpty()) {
if (level.isClientSide) {
return seashell.canAcceptItem(player, stack) ? InteractionResult.SUCCESS : InteractionResult.PASS;
}
if (seashell.tryInsert(player, hand, stack)) {
level.playSound(null, pos, SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, 0.6F, 0.95F + level.random.nextFloat() * 0.1F);
return InteractionResult.CONSUME;
}
return InteractionResult.PASS;
}
if (level.isClientSide) {
return seashell.hasAnyContents() ? InteractionResult.SUCCESS : InteractionResult.PASS;
}
if (seashell.tryRemove(player, hand)) {
level.playSound(null, pos, SoundEvents.ITEM_FRAME_REMOVE_ITEM, SoundSource.BLOCKS, 0.6F, 0.95F + level.random.nextFloat() * 0.1F);
return InteractionResult.CONSUME;
}
return InteractionResult.PASS;
}
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new SeashellBlockEntity(pos, state);
}
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
return level.isClientSide
? createTickerHelper(blockEntityType, AntarchyObjects.SEASHELL_BLOCK_ENTITY.get(), SeashellBlockEntity::clientTick)
: createTickerHelper(blockEntityType, AntarchyObjects.SEASHELL_BLOCK_ENTITY.get(), SeashellBlockEntity::serverTick);
}
private void updatePowerState(Level level, BlockPos pos, BlockState state) {
boolean powered = level.hasNeighborSignal(pos);
if (state.getValue(POWERED) == powered) {
if (level.getBlockEntity(pos) instanceof SeashellBlockEntity seashell) {
seashell.syncVisualState(powered);
}
return;
}
BlockState updatedState = state.setValue(POWERED, powered);
level.setBlock(pos, updatedState, Block.UPDATE_ALL);
if (level.getBlockEntity(pos) instanceof SeashellBlockEntity seashell) {
if (seashell.onPowerStateChanged(powered)) {
level.playSound(null, pos, powered ? SoundEvents.CHEST_OPEN : SoundEvents.CHEST_CLOSE, SoundSource.BLOCKS, 0.6F, 0.95F + level.random.nextFloat() * 0.1F);
}
}
}
private static VoxelShape collisionShape(Direction facing) {
return switch (facing) {
case NORTH -> Block.box(SHELL_MIN, 0.0D, SHELL_MIN - COLLISION_FORWARD_OFFSET, SHELL_MAX, SHELL_HEIGHT, SHELL_MAX - COLLISION_FORWARD_OFFSET);
case SOUTH -> Block.box(SHELL_MIN, 0.0D, SHELL_MIN + COLLISION_FORWARD_OFFSET, SHELL_MAX, SHELL_HEIGHT, SHELL_MAX + COLLISION_FORWARD_OFFSET);
case WEST -> Block.box(SHELL_MIN - COLLISION_FORWARD_OFFSET, 0.0D, SHELL_MIN, SHELL_MAX - COLLISION_FORWARD_OFFSET, SHELL_HEIGHT, SHELL_MAX);
case EAST -> Block.box(SHELL_MIN + COLLISION_FORWARD_OFFSET, 0.0D, SHELL_MIN, SHELL_MAX + COLLISION_FORWARD_OFFSET, SHELL_HEIGHT, SHELL_MAX);
default -> OUTLINE_SHAPE;
};
}
}
@@ -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
public 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
public 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.LEVER_CLICK, SoundSource.BLOCKS);
} else {
newState = state.setValue(LIT, false).setValue(BRIGHTNESS, 0);
level.playSound((Player) null, pos, SoundEvents.LEVER_CLICK, 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
public boolean hasAnalogOutputSignal(BlockState state) {
return true;
}
@Override
public int getAnalogOutputSignal(BlockState state, Level level, BlockPos pos) {
return state.getValue(LIT) ? state.getValue(BRIGHTNESS) : 0;
}
}
@@ -0,0 +1,24 @@
package com.craisinlord.antarchy.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.BushBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class SpiderLilyBlock extends BushBlock {
private static final VoxelShape SHAPE = Block.box(5.0D, 0.0D, 5.0D, 11.0D, 10.0D, 11.0D);
public SpiderLilyBlock(BlockBehaviour.Properties properties) {
super(properties);
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
}
@@ -0,0 +1,147 @@
package com.craisinlord.antarchy.content.block;
import com.craisinlord.antarchy.Antarchy;
import com.craisinlord.antarchy.content.entity.SpitBugEntity;
import com.craisinlord.antarchy.content.horde.CavarynHordeManager;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.player.Player;
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.Mirror;
import net.minecraft.world.level.block.Rotation;
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;
public class SpitBugEggBlock extends Block {
public static final IntegerProperty HATCH = BlockStateProperties.HATCH;
public static final BooleanProperty ROTATED = BooleanProperty.create("rotated");
private static final int MAX_HATCH = 2;
private static final double PLAYER_PROXIMITY_RADIUS = 12.0D;
private static final double HORDE_ACCELERATION_RADIUS = 5.0D;
private static final float PLAYER_PROXIMITY_HATCH_CHANCE = 0.25F;
private static final int PLAYER_PROXIMITY_CHECK_INTERVAL = 200;
private static final VoxelShape SHAPE = Block.box(1.5D, 0.0D, 1.5D, 14.5D, 16.0D, 14.5D);
private static final ResourceLocation SPIT_BUG_ID = new ResourceLocation(Antarchy.MODID, "spit_bug");
public SpitBugEggBlock(BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(HATCH, 0).setValue(ROTATED, false));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return this.defaultBlockState().setValue(ROTATED, context.getHorizontalDirection().getAxis() == Direction.Axis.X);
}
@Override
public BlockState rotate(BlockState state, Rotation rotation) {
return rotation == Rotation.CLOCKWISE_90 || rotation == Rotation.COUNTERCLOCKWISE_90
? state.setValue(ROTATED, !state.getValue(ROTATED))
: state;
}
@Override
public BlockState mirror(BlockState state, Mirror mirror) {
return state;
}
@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
return level.getBlockState(pos.below()).isFaceSturdy(level, pos.below(), Direction.UP);
}
@Override
public 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
public boolean isRandomlyTicking(BlockState state) {
return true;
}
@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!this.shouldUpdateHatchLevel(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.hatch(level, pos, random);
}
private boolean shouldUpdateHatchLevel(Level level, BlockPos pos) {
if (level instanceof ServerLevel serverLevel
&& CavarynHordeManager.shouldAccelerateNearbyEggHatching(serverLevel, pos, HORDE_ACCELERATION_RADIUS, level.random)) {
return true;
}
if (level.random.nextInt(PLAYER_PROXIMITY_CHECK_INTERVAL) == 0) {
Player nearbyPlayer = level.getNearestPlayer(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, PLAYER_PROXIMITY_RADIUS, false);
if (nearbyPlayer != null && level.random.nextFloat() < PLAYER_PROXIMITY_HATCH_CHANCE) {
return true;
}
}
boolean onAmberMoss = level.getBlockState(pos.below()).getBlock() instanceof AmberMossBlock;
return level.random.nextInt(onAmberMoss ? 150 : 500) == 0;
}
private void hatch(ServerLevel level, BlockPos pos, RandomSource random) {
level.removeBlock(pos, false);
level.playSound(null, pos, SoundEvents.TURTLE_EGG_HATCH, SoundSource.BLOCKS, 0.75F, 0.95F + random.nextFloat() * 0.1F);
@SuppressWarnings("unchecked")
EntityType<SpitBugEntity> spitBugType = (EntityType<SpitBugEntity>) (EntityType<?>) BuiltInRegistries.ENTITY_TYPE.getOptional(SPIT_BUG_ID).orElse(null);
if (spitBugType == null) {
return;
}
SpitBugEntity entity = spitBugType.create(level);
if (entity == null) {
return;
}
double spawnX = pos.getX() + 0.25D + random.nextDouble() * 0.5D;
double spawnZ = pos.getZ() + 0.25D + random.nextDouble() * 0.5D;
entity.moveTo(spawnX, pos.getY() + 0.1D, spawnZ, random.nextFloat() * 360.0F, 0.0F);
level.addFreshEntity(entity);
}
public void hatchWithNucleus(ServerLevel level, BlockPos pos) {
this.hatch(level, pos, level.random);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(HATCH, ROTATED);
}
}
Loaded 100 of 5242 files, more files were not shown because too many files have changed in this diff. Show more