lots of stuff
This commit is contained in:
1 parent
ee9ac93b5e
commit
ea24b19068
5242 files changed
+336231
-112
No files matched your search
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
+27
@@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
+16
@@ -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;
|
||||
}
|
||||
}
|
||||
+37
@@ -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;
|
||||
}
|
||||
}
|
||||
+56
@@ -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);
|
||||
}
|
||||
}
|
||||
+64
@@ -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());
|
||||
}
|
||||
}
|
||||
+98
@@ -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());
|
||||
}
|
||||
}
|
||||
+93
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
+10
@@ -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();
|
||||
}
|
||||
}
|
||||
+496
@@ -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() {
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
@@ -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);
|
||||
}
|
||||
}
|
||||
+87
@@ -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);
|
||||
}
|
||||
}
|
||||
+34
@@ -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);
|
||||
}
|
||||
}
|
||||
+34
@@ -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);
|
||||
}
|
||||
}
|
||||
+35
@@ -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);
|
||||
}
|
||||
}
|
||||
+47
@@ -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);
|
||||
}
|
||||
}
|
||||
+164
@@ -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();
|
||||
}
|
||||
}
|
||||
+47
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+59
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+104
@@ -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;
|
||||
}
|
||||
}
|
||||
+80
@@ -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};
|
||||
}
|
||||
}
|
||||
+112
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
+28
@@ -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);
|
||||
}
|
||||
}
|
||||
+161
@@ -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);
|
||||
}
|
||||
}
|
||||
+206
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
@@ -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;
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package com.craisinlord.antarchy.content.block;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.block.AmethystClusterBlock;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class BloodCrystalGrowthBlock extends Block {
|
||||
private static final Direction[] DIRECTIONS = Direction.values();
|
||||
|
||||
private final Supplier<? extends Block> smallBud;
|
||||
private final Supplier<? extends Block> mediumBud;
|
||||
private final Supplier<? extends Block> largeBud;
|
||||
private final Supplier<? extends Block> cluster;
|
||||
|
||||
public BloodCrystalGrowthBlock(
|
||||
Properties properties,
|
||||
Supplier<? extends Block> smallBud,
|
||||
Supplier<? extends Block> mediumBud,
|
||||
Supplier<? extends Block> largeBud,
|
||||
Supplier<? extends Block> cluster
|
||||
) {
|
||||
super(properties);
|
||||
this.smallBud = smallBud;
|
||||
this.mediumBud = mediumBud;
|
||||
this.largeBud = largeBud;
|
||||
this.cluster = cluster;
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
+48
@@ -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;
|
||||
}
|
||||
}
|
||||
+203
@@ -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);
|
||||
}
|
||||
}
|
||||
+57
@@ -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;
|
||||
}
|
||||
}
|
||||
+70
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -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());
|
||||
}
|
||||
}
|
||||
+109
@@ -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;
|
||||
}
|
||||
}
|
||||
+93
@@ -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);
|
||||
}
|
||||
}
|
||||
+10
@@ -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);
|
||||
}
|
||||
+253
@@ -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) {
|
||||
}
|
||||
}
|
||||
+434
@@ -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);
|
||||
}
|
||||
}
|
||||
+47
@@ -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);
|
||||
}
|
||||
}
|
||||
+130
@@ -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);
|
||||
}
|
||||
}
|
||||
+46
@@ -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);
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package com.craisinlord.antarchy.content.block;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.block.AmethystClusterBlock;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class BuddingBloodCrystalBlock extends Block {
|
||||
private static final Direction[] DIRECTIONS = Direction.values();
|
||||
|
||||
private final Supplier<? extends Block> smallBud;
|
||||
private final Supplier<? extends Block> mediumBud;
|
||||
private final Supplier<? extends Block> largeBud;
|
||||
private final Supplier<? extends Block> crystal;
|
||||
|
||||
public BuddingBloodCrystalBlock(
|
||||
Properties properties,
|
||||
Supplier<? extends Block> smallBud,
|
||||
Supplier<? extends Block> mediumBud,
|
||||
Supplier<? extends Block> largeBud,
|
||||
Supplier<? extends Block> crystal
|
||||
) {
|
||||
super(properties);
|
||||
this.smallBud = smallBud;
|
||||
this.mediumBud = mediumBud;
|
||||
this.largeBud = largeBud;
|
||||
this.crystal = crystal;
|
||||
}
|
||||
|
||||
@Override
|
||||
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()));
|
||||
}
|
||||
}
|
||||
+160
@@ -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);
|
||||
}
|
||||
}
|
||||
+173
@@ -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);
|
||||
}
|
||||
}
|
||||
+178
@@ -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);
|
||||
}
|
||||
}
|
||||
+245
@@ -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;
|
||||
}
|
||||
}
|
||||
+67
@@ -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);
|
||||
}
|
||||
}
|
||||
+84
@@ -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());
|
||||
}
|
||||
}
|
||||
+45
@@ -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);
|
||||
}
|
||||
}
|
||||
+32
@@ -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;
|
||||
}
|
||||
}
|
||||
+53
@@ -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;
|
||||
}
|
||||
}
|
||||
+38
@@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -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());
|
||||
}
|
||||
}
|
||||
+36
@@ -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;
|
||||
}
|
||||
}
|
||||
+38
@@ -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;
|
||||
}
|
||||
}
|
||||
+572
@@ -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) {
|
||||
}
|
||||
}
|
||||
+31
@@ -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);
|
||||
}
|
||||
}
|
||||
+170
@@ -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);
|
||||
}
|
||||
}
|
||||
+233
@@ -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);
|
||||
}
|
||||
}
|
||||
+322
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+109
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+113
@@ -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);
|
||||
}
|
||||
}
|
||||
+64
@@ -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();
|
||||
}
|
||||
}
|
||||
+117
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+100
@@ -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);
|
||||
}
|
||||
}
|
||||
+99
@@ -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);
|
||||
}
|
||||
}
|
||||
+108
@@ -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);
|
||||
}
|
||||
}
|
||||
+161
@@ -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);
|
||||
}
|
||||
}
|
||||
+70
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
+245
@@ -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;
|
||||
}
|
||||
}
|
||||
+227
@@ -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;
|
||||
}
|
||||
}
|
||||
+46
@@ -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();
|
||||
}
|
||||
}
|
||||
+161
@@ -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;
|
||||
}
|
||||
}
|
||||
+199
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+189
@@ -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);
|
||||
}
|
||||
}
|
||||
+19
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package com.craisinlord.antarchy.content.block;
|
||||
|
||||
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||
import com.craisinlord.antarchy.content.entity.flying_squirrel.FlyingSquirrelEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
||||
|
||||
/**
|
||||
* Invisible world-gen-only marker placed inside a flying squirrel hollow.
|
||||
* Schedules itself to replace with COARSE_DIRT and spawn squirrels shortly
|
||||
* after the chunk loads, so entity creation never blocks the gen thread.
|
||||
* No BlockItem is registered, so this block never appears in creative or JEI.
|
||||
*/
|
||||
public class OuranwoodSquirrelNestBlock extends Block {
|
||||
public static final IntegerProperty SQUIRREL_COUNT = IntegerProperty.create("squirrels", 1, 3);
|
||||
|
||||
public OuranwoodSquirrelNestBlock(BlockBehaviour.Properties properties) {
|
||||
super(properties);
|
||||
this.registerDefaultState(this.stateDefinition.any().setValue(SQUIRREL_COUNT, 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||
builder.add(SQUIRREL_COUNT);
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
}
|
||||
+194
@@ -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);
|
||||
}
|
||||
}
|
||||
+128
@@ -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) {
|
||||
}
|
||||
}
|
||||
+68
@@ -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;
|
||||
}
|
||||
}
|
||||
+297
@@ -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);
|
||||
}
|
||||
}
|
||||
+289
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
package com.craisinlord.antarchy.content.block;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||
import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
||||
|
||||
public class SignalSavingBulbBlock extends Block {
|
||||
|
||||
public static final BooleanProperty LIT = BlockStateProperties.LIT;
|
||||
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
|
||||
public static final IntegerProperty BRIGHTNESS = IntegerProperty.create("brightness", 0, 15);
|
||||
|
||||
public SignalSavingBulbBlock(BlockBehaviour.Properties properties) {
|
||||
super(properties.lightLevel(state -> state.getValue(LIT) ? state.getValue(BRIGHTNESS) : 0));
|
||||
this.registerDefaultState(this.defaultBlockState()
|
||||
.setValue(LIT, false)
|
||||
.setValue(POWERED, false)
|
||||
.setValue(BRIGHTNESS, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
}
|
||||
+24
@@ -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;
|
||||
}
|
||||
}
|
||||
+147
@@ -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
Reference in new issue
Block a user