diff --git a/.github/nms-groups.yml b/.github/nms-groups.yml
index 6ee5af347..392ee19ac 100644
--- a/.github/nms-groups.yml
+++ b/.github/nms-groups.yml
@@ -44,3 +44,4 @@ java21:
java25:
- "26.1.2" # 26_1_R1
+ - "26.2" # 26_2_R1
diff --git a/NEXT_RELEASE_CHANGELOG.md b/NEXT_RELEASE_CHANGELOG.md
index e69de29bb..ce6cd20b1 100644
--- a/NEXT_RELEASE_CHANGELOG.md
+++ b/NEXT_RELEASE_CHANGELOG.md
@@ -0,0 +1 @@
+- Added support for MC 26.2.
diff --git a/core/pom.xml b/core/pom.xml
index bafe138b9..3551551d9 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -235,7 +235,14 @@
nl.pim16aap2.BigDoors
- v26_R1
+ v26_1_R1
+ 0.1.8.68-SNAPSHOT
+ compile
+
+
+
+ nl.pim16aap2.BigDoors
+ v26_2_R1
0.1.8.68-SNAPSHOT
compile
diff --git a/core/src/main/java/nl/pim16aap2/bigDoors/BigDoors.java b/core/src/main/java/nl/pim16aap2/bigDoors/BigDoors.java
index 889f88d73..839c99fd1 100644
--- a/core/src/main/java/nl/pim16aap2/bigDoors/BigDoors.java
+++ b/core/src/main/java/nl/pim16aap2/bigDoors/BigDoors.java
@@ -15,6 +15,7 @@
import nl.pim16aap2.bigDoors.NMS.FallingBlockFactoryProvider_V1_21_R5;
import nl.pim16aap2.bigDoors.NMS.FallingBlockFactoryProvider_V1_21_R6;
import nl.pim16aap2.bigDoors.NMS.FallingBlockFactoryProvider_V1_21_R7;
+import nl.pim16aap2.bigDoors.NMS.FallingBlockFactoryProvider_V26_2_R1;
import nl.pim16aap2.bigDoors.NMS.FallingBlockFactoryProvider_V26_R1;
import nl.pim16aap2.bigDoors.NMS.FallingBlockFactory_V1_11_R1;
import nl.pim16aap2.bigDoors.NMS.FallingBlockFactory_V1_12_R1;
@@ -930,7 +931,17 @@ public static boolean isOnFlattenedVersion()
case 1:
case 2:
return FallingBlockFactoryProvider_V26_R1.getFactory();
+ default:
+ logger.severe("Unexpected patch version '" + SERVER_VERSION.getPatch() + "' for 26.1.x!");
+ return null;
}
+ case 2:
+ {
+ return FallingBlockFactoryProvider_V26_2_R1.getFactory();
+ }
+ default:
+ logger.severe("Unexpected minor version '" + SERVER_VERSION.getMinor() + "' for 26.x!");
+ return null;
}
}
}
diff --git a/core/src/main/java/nl/pim16aap2/bigDoors/codegeneration/FallbackGeneratorManager.java b/core/src/main/java/nl/pim16aap2/bigDoors/codegeneration/FallbackGeneratorManager.java
index c90c60c3a..18586ad8d 100644
--- a/core/src/main/java/nl/pim16aap2/bigDoors/codegeneration/FallbackGeneratorManager.java
+++ b/core/src/main/java/nl/pim16aap2/bigDoors/codegeneration/FallbackGeneratorManager.java
@@ -55,6 +55,7 @@ private static FallingBlockFactory generateFallingBlockFactory()
try
{
+ ensureReflectionLookupSuccess();
final String mappingsVersion = getMappingsVersion();
final ClassGenerator entityFallingBlockClassGenerator =
new EntityFallingBlockClassGenerator(mappingsVersion);
@@ -106,6 +107,11 @@ private static FallingBlockFactory generateFallingBlockFactory()
}
}
+ private static void ensureReflectionLookupSuccess()
+ {
+ ReflectionRepository.noop();
+ }
+
@SuppressWarnings("unchecked")
private static String getPaperMappingsVersion()
{
diff --git a/core/src/main/java/nl/pim16aap2/bigDoors/codegeneration/ReflectionRepository.java b/core/src/main/java/nl/pim16aap2/bigDoors/codegeneration/ReflectionRepository.java
index a6dd8f2fa..078622183 100644
--- a/core/src/main/java/nl/pim16aap2/bigDoors/codegeneration/ReflectionRepository.java
+++ b/core/src/main/java/nl/pim16aap2/bigDoors/codegeneration/ReflectionRepository.java
@@ -55,6 +55,7 @@ final class ReflectionRepository
public static final Class> classCraftBlockData;
public static final Class> classBlockStateEnum;
public static final Class> classEntityTypes;
+ public static final Class> classEntityType;
public static final Class> classRegistries;
public static final Class> classResourceKey;
public static final Class> classMinecraftKey;
@@ -187,7 +188,8 @@ final class ReflectionRepository
classEnumDirectionAxis = findClass("net.minecraft.core.Direction$Axis").get();
classEnumBlockRotation = findClass("net.minecraft.world.level.block.Rotation").get();
classBlockRotatable = findClass("net.minecraft.world.level.block.RotatedPillarBlock").get();
- classEntityTypes = findClass("net.minecraft.world.entity.EntityType").get();
+ classEntityTypes = findClass("net.minecraft.world.entity.EntityTypes").get();
+ classEntityType = findClass("net.minecraft.world.entity.EntityType").get();
classRegistries = findClass("net.minecraft.core.registries.Registries").get();
classResourceKey = findClass("net.minecraft.resources.ResourceKey").get();
classIWorldReader = findClass("net.minecraft.world.level.LevelReader").get();
@@ -202,7 +204,7 @@ final class ReflectionRepository
.get();
cTorPublicNMSFallingBlockEntity = findConstructor()
.inClass(classEntityFallingBlock)
- .withParameters(classEntityTypes, classNMSWorld)
+ .withParameters(classEntityType, classNMSWorld)
.get();
cTorVec3D = findConstructor()
.inClass(classVec3D)
@@ -565,6 +567,14 @@ final class ReflectionRepository
}
}
+ /**
+ * This method is used to ensure that the static initializer of this class is executed.
+ *
+ * It does nothing and is only used for its side effect of triggering the static initializer.
+ */
+ static void noop() {
+ }
+
private static Method getMethodCraftBockDataFromNMSBlockData()
{
Method method = findMethod()
diff --git a/core/src/main/java/nl/pim16aap2/bigDoors/reflection/asm/ASMUtil.java b/core/src/main/java/nl/pim16aap2/bigDoors/reflection/asm/ASMUtil.java
index 5662c3fd1..0544f82c6 100644
--- a/core/src/main/java/nl/pim16aap2/bigDoors/reflection/asm/ASMUtil.java
+++ b/core/src/main/java/nl/pim16aap2/bigDoors/reflection/asm/ASMUtil.java
@@ -87,10 +87,14 @@ else if (executable instanceof Constructor)
try
{
- return Objects.requireNonNull(
+ StaticFieldFinder staticFieldFinder = Objects.requireNonNull(
ASMUtil.processMethod(executable, null, (a, n, d, s, e) ->
StaticFieldFinder.create(a, n, d, s, e, fieldType, 1))
- ).fields[0];
+ );
+
+ return Objects.requireNonNull(
+ staticFieldFinder.fields[0]
+ );
}
catch (IOException e)
{
diff --git a/core/src/main/java/nl/pim16aap2/bigDoors/util/ResourcePackDetails.java b/core/src/main/java/nl/pim16aap2/bigDoors/util/ResourcePackDetails.java
index 54dd49439..261178158 100644
--- a/core/src/main/java/nl/pim16aap2/bigDoors/util/ResourcePackDetails.java
+++ b/core/src/main/java/nl/pim16aap2/bigDoors/util/ResourcePackDetails.java
@@ -152,8 +152,15 @@ public enum ResourcePackDetails
"https://www.dropbox.com/scl/fi/drls9p9bhg28zbinty3d6/BigDoorsResourcePack-Format84.zip?rlkey=zrulj21mbwz4tzpbyys5pzq1f&st=v3vz19ml&dl=1",
"b10c21defae3548afd124e7dc48de1cfe1fe3ecc",
Semver.of(26, 0, 0),
- Semver.of(26, 1, 1)
- )
+ Semver.of(26, 1, 2)
+ ),
+
+ FORMAT_88(
+ "https://www.dropbox.com/scl/fi/2ucdkpbyhhdr8wzomwnky/BigDoorsResourcePack-Format88.zip?rlkey=7m95e23vxtwqcwkw2atjuivs0&st=9k4wr5gg&dl=1",
+ "57789486b18b0d79de1e0f1ad68047580068ffb5",
+ Semver.of(26, 2, 0),
+ Semver.of(26, 2, 1)
+ ),
;
diff --git a/nms/pom.xml b/nms/pom.xml
index f22e89cd6..dca41f268 100644
--- a/nms/pom.xml
+++ b/nms/pom.xml
@@ -51,7 +51,8 @@
v1_21_R6
v1_21_R7
- v26_R1
+ v26_1_R1
+ v26_2_R1
diff --git a/nms/v26_R1/pom.xml b/nms/v26_1_R1/pom.xml
similarity index 96%
rename from nms/v26_R1/pom.xml
rename to nms/v26_1_R1/pom.xml
index d4bd95a21..6b3250517 100644
--- a/nms/v26_R1/pom.xml
+++ b/nms/v26_1_R1/pom.xml
@@ -2,7 +2,7 @@
4.0.0
jar
- v26_R1
+ v26_1_R1
nl.pim16aap2.BigDoors
diff --git a/nms/v26_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CraftBlockDataFactory.java b/nms/v26_1_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CraftBlockDataFactory_V26_1_R1.java
similarity index 95%
rename from nms/v26_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CraftBlockDataFactory.java
rename to nms/v26_1_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CraftBlockDataFactory_V26_1_R1.java
index d26555a12..04c964d95 100644
--- a/nms/v26_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CraftBlockDataFactory.java
+++ b/nms/v26_1_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CraftBlockDataFactory_V26_1_R1.java
@@ -6,11 +6,11 @@
import java.lang.reflect.Method;
import java.util.function.Function;
-final class CraftBlockDataFactory
+final class CraftBlockDataFactory_V26_1_R1
{
private static final Function FROM_STATE = findFromStateFunction();
- private CraftBlockDataFactory()
+ private CraftBlockDataFactory_V26_1_R1()
{
}
diff --git a/nms/v26_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomCraftFallingBlock_V26_R1.java b/nms/v26_1_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomCraftFallingBlock_V26_R1.java
similarity index 97%
rename from nms/v26_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomCraftFallingBlock_V26_R1.java
rename to nms/v26_1_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomCraftFallingBlock_V26_R1.java
index 6b9cb14b4..ad74f0da0 100644
--- a/nms/v26_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomCraftFallingBlock_V26_R1.java
+++ b/nms/v26_1_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomCraftFallingBlock_V26_R1.java
@@ -87,7 +87,7 @@ public boolean isInWorld()
@Override
public @NotNull BlockData getBlockData()
{
- return CraftBlockDataFactory.fromState(this.getHandle().getBlockState());
+ return CraftBlockDataFactory_V26_1_R1.fromState(this.getHandle().getBlockState());
}
@Override
diff --git a/nms/v26_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomEntityFallingBlockGenerator_V26_R1.java b/nms/v26_1_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomEntityFallingBlockGenerator_V26_R1.java
similarity index 100%
rename from nms/v26_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomEntityFallingBlockGenerator_V26_R1.java
rename to nms/v26_1_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomEntityFallingBlockGenerator_V26_R1.java
diff --git a/nms/v26_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomEntityFallingBlock_V26_R1.java b/nms/v26_1_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomEntityFallingBlock_V26_R1.java
similarity index 100%
rename from nms/v26_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomEntityFallingBlock_V26_R1.java
rename to nms/v26_1_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomEntityFallingBlock_V26_R1.java
diff --git a/nms/v26_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/FallingBlockFactoryProvider_V26_R1.java b/nms/v26_1_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/FallingBlockFactoryProvider_V26_R1.java
similarity index 94%
rename from nms/v26_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/FallingBlockFactoryProvider_V26_R1.java
rename to nms/v26_1_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/FallingBlockFactoryProvider_V26_R1.java
index 63ebea48b..72f0b4c88 100644
--- a/nms/v26_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/FallingBlockFactoryProvider_V26_R1.java
+++ b/nms/v26_1_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/FallingBlockFactoryProvider_V26_R1.java
@@ -30,7 +30,7 @@ private static boolean checkPreconditions()
{
try
{
- return CraftBlockDataFactory.isInitialized();
+ return CraftBlockDataFactory_V26_1_R1.isInitialized();
}
catch (Throwable t)
{
diff --git a/nms/v26_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/FallingBlockFactory_V26_R1.java b/nms/v26_1_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/FallingBlockFactory_V26_R1.java
similarity index 100%
rename from nms/v26_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/FallingBlockFactory_V26_R1.java
rename to nms/v26_1_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/FallingBlockFactory_V26_R1.java
diff --git a/nms/v26_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/NMSBlock_V26_R1.java b/nms/v26_1_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/NMSBlock_V26_R1.java
similarity index 98%
rename from nms/v26_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/NMSBlock_V26_R1.java
rename to nms/v26_1_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/NMSBlock_V26_R1.java
index bdc1902ac..8c0cd91a4 100644
--- a/nms/v26_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/NMSBlock_V26_R1.java
+++ b/nms/v26_1_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/NMSBlock_V26_R1.java
@@ -95,7 +95,7 @@ private void updateBlockData()
private void updateCraftBlockData()
{
- this.craftBlockData = CraftBlockDataFactory.fromState(blockData);
+ this.craftBlockData = CraftBlockDataFactory_V26_1_R1.fromState(blockData);
}
@Override
diff --git a/nms/v26_2_R1/pom.xml b/nms/v26_2_R1/pom.xml
new file mode 100644
index 000000000..805f3d3c6
--- /dev/null
+++ b/nms/v26_2_R1/pom.xml
@@ -0,0 +1,34 @@
+
+
+ 4.0.0
+ jar
+ v26_2_R1
+
+
+ nl.pim16aap2.BigDoors
+ nms
+ 0.1.8.68-SNAPSHOT
+
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+
+ org.spigotmc
+ spigot
+ 26.2-R0.1-SNAPSHOT
+ provided
+
+
+
+ nl.pim16aap2.BigDoors
+ nms-api
+ 0.1.8.68-SNAPSHOT
+ provided
+
+
+
diff --git a/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CraftBlockDataFactory_V26_2_R1.java b/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CraftBlockDataFactory_V26_2_R1.java
new file mode 100644
index 000000000..e6df0bd57
--- /dev/null
+++ b/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CraftBlockDataFactory_V26_2_R1.java
@@ -0,0 +1,63 @@
+package nl.pim16aap2.bigDoors.NMS;
+
+import net.minecraft.world.level.block.state.BlockState;
+import org.bukkit.craftbukkit.block.data.CraftBlockData;
+
+import java.lang.reflect.Method;
+import java.util.function.Function;
+
+final class CraftBlockDataFactory_V26_2_R1
+{
+ private static final Function FROM_STATE = findFromStateFunction();
+
+ private CraftBlockDataFactory_V26_2_R1()
+ {
+ }
+
+ public static CraftBlockData fromState(BlockState state)
+ {
+ return FROM_STATE.apply(state);
+ }
+
+ static boolean isInitialized()
+ {
+ return true;
+ }
+
+ private static Function findFromStateFunction()
+ {
+ // On Spigot, we can use CraftBlockData#fromData(BlockState) without reflection.
+ // On Paper, it's CraftBlockData#createData(BlockState), which is not present in Spigot, so we'll use reflection.
+ try
+ {
+ CraftBlockData.class.getMethod("fromData", BlockState.class);
+ return CraftBlockData::fromData;
+ }
+ catch (NoSuchMethodException ignored)
+ {
+ // Ignored
+ }
+
+ try
+ {
+ Method method = CraftBlockData.class.getMethod("createData", BlockState.class);
+ method.setAccessible(true);
+ return state ->
+ {
+ try
+ {
+ return (CraftBlockData) method.invoke(null, state);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Failed to create block data from state: " + state, e);
+ }
+ };
+ }
+ catch (NoSuchMethodException ignored)
+ {
+ // ignored
+ }
+ throw new IllegalStateException("Failed to find method to create CraftBlockData from state");
+ }
+}
diff --git a/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomCraftFallingBlock_V26_2_R1.java b/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomCraftFallingBlock_V26_2_R1.java
new file mode 100644
index 000000000..25daaa02c
--- /dev/null
+++ b/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomCraftFallingBlock_V26_2_R1.java
@@ -0,0 +1,164 @@
+package nl.pim16aap2.bigDoors.NMS;
+
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.block.data.BlockData;
+import org.bukkit.craftbukkit.CraftServer;
+import org.bukkit.craftbukkit.entity.CraftEntity;
+import org.bukkit.craftbukkit.util.CraftMagicNumbers;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.EntitySnapshot;
+import org.bukkit.entity.FallingBlock;
+import org.bukkit.util.EulerAngle;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NonNull;
+
+@SuppressWarnings("UnstableApiUsage")
+public class CustomCraftFallingBlock_V26_2_R1 extends CraftEntity implements FallingBlock, CustomCraftFallingBlock
+{
+ public CustomCraftFallingBlock_V26_2_R1(final CraftServer server, final CustomEntityFallingBlock_V26_2_R1 entity)
+ {
+ super(server, entity);
+ setVelocity(new Vector(0, 0, 0));
+ setDropItem(false);
+ }
+
+ @Override
+ public CustomEntityFallingBlock_V26_2_R1 getHandle()
+ {
+ return (CustomEntityFallingBlock_V26_2_R1) entity;
+ }
+
+ @Override
+ public boolean isOnGround()
+ {
+ return false;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "CraftFallingBlock";
+ }
+
+ @Override
+ public void setVisibleByDefault(boolean flag)
+ {
+ }
+
+ @Override
+ public boolean isVisibleByDefault()
+ {
+ return true;
+ }
+
+ @Override
+ public boolean isInWorld()
+ {
+ return false;
+ }
+
+ @Override
+ public @NonNull EntitySnapshot createSnapshot()
+ {
+ throw new UnsupportedOperationException("Not implemented for animated blocks!");
+ }
+
+ @Override
+ public @NonNull Entity copy()
+ {
+ throw new UnsupportedOperationException("Not implemented for animated blocks!");
+ }
+
+ @Override
+ public @NonNull Entity copy(@NotNull Location location)
+ {
+ throw new UnsupportedOperationException("Not implemented for animated blocks!");
+ }
+
+ @Override
+ @Deprecated
+ public @NotNull Material getMaterial()
+ {
+ return CraftMagicNumbers.getMaterial(getHandle().getBlockState()).getItemType();
+ }
+
+ @Override
+ public @NotNull BlockData getBlockData()
+ {
+ return CraftBlockDataFactory_V26_2_R1.fromState(this.getHandle().getBlockState());
+ }
+
+ @Override
+ public boolean getDropItem()
+ {
+ return false;
+ }
+
+ @Override
+ public void setDropItem(final boolean drop)
+ {
+ }
+
+ @Override
+ public boolean getCancelDrop()
+ {
+ return true;
+ }
+
+ @Override
+ public void setCancelDrop(boolean b)
+ {
+ }
+
+ @Override
+ public boolean canHurtEntities()
+ {
+ return false;
+ }
+
+ @Override
+ public void setHurtEntities(final boolean hurtEntities)
+ {
+ }
+
+ @Override
+ public float getDamagePerBlock()
+ {
+ return 0;
+ }
+
+ @Override
+ public void setDamagePerBlock(float damage)
+ {
+ }
+
+ @Override
+ public int getMaxDamage()
+ {
+ return 0;
+ }
+
+ @Override
+ public void setMaxDamage(int damage)
+ {
+ }
+
+ @Override
+ public void setTicksLived(final int value)
+ {
+ super.setTicksLived(value);
+ getHandle().setTicksLived(value);
+ }
+
+ @Override
+ public void setHeadPose(EulerAngle pose)
+ {
+ }
+
+ @Override
+ public void setBodyPose(EulerAngle eulerAngle)
+ {
+ }
+}
diff --git a/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomEntityFallingBlockGenerator_V26_2_R1.java b/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomEntityFallingBlockGenerator_V26_2_R1.java
new file mode 100644
index 000000000..75d7760bb
--- /dev/null
+++ b/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomEntityFallingBlockGenerator_V26_2_R1.java
@@ -0,0 +1,27 @@
+package nl.pim16aap2.bigDoors.NMS;
+
+/**
+ * Represents a class that can generate a subclass of {@link CustomEntityFallingBlock_V26_2_R1}.
+ */
+class CustomEntityFallingBlockGenerator_V26_2_R1
+{
+ /**
+ * Gets a {@link FallingBlockFactory_V26_2_R1.CustomEntityFallingBlockFactory} that can be used to create new
+ * {@link CustomEntityFallingBlock_V26_2_R1} instances.
+ *
+ * @return The supplier for new {@link CustomEntityFallingBlock_V26_2_R1} instances.
+ */
+ public FallingBlockFactory_V26_2_R1.CustomEntityFallingBlockFactory getEntityFallingBlockSupplier()
+ {
+ return (world, x, y, z, blockState) -> {
+ try
+ {
+ return new CustomEntityFallingBlock_V26_2_R1(world, x, y, z, blockState);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Failed to create a new CustomEntityFallingBlock instance!", e);
+ }
+ };
+ }
+}
diff --git a/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomEntityFallingBlock_V26_2_R1.java b/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomEntityFallingBlock_V26_2_R1.java
new file mode 100644
index 000000000..f915384f8
--- /dev/null
+++ b/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/CustomEntityFallingBlock_V26_2_R1.java
@@ -0,0 +1,114 @@
+package nl.pim16aap2.bigDoors.NMS;
+
+import net.minecraft.CrashReportCategory;
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.entity.EntityTypes;
+import net.minecraft.world.entity.MoverType;
+import net.minecraft.world.entity.item.FallingBlockEntity;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.storage.ValueInput;
+import net.minecraft.world.level.storage.ValueOutput;
+import net.minecraft.world.phys.Vec3;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.bukkit.event.entity.EntityRemoveEvent;
+import org.jspecify.annotations.NonNull;
+
+public class CustomEntityFallingBlock_V26_2_R1 extends FallingBlockEntity implements CustomEntityFallingBlock
+{
+ // We need to keep our own blockstate as the parent is private without setter.
+ private BlockState blockState;
+ private final CraftWorld world;
+
+ public CustomEntityFallingBlock_V26_2_R1(
+ final org.bukkit.World world,
+ final double spawnX,
+ final double spawnY,
+ final double spawnZ,
+ final BlockState blockState
+ )
+ {
+ super(
+ EntityTypes.FALLING_BLOCK,
+ ((CraftWorld) world).getHandle()
+ );
+
+ this.world = (CraftWorld) world;
+ this.blockState = blockState;
+
+ applyDefaultSettings();
+
+ super.setPos(spawnX, spawnY, spawnZ);
+ super.setStartPos(BlockPos.containing(spawnX, spawnY, spawnZ));
+ super.setDeltaMovement(new Vec3(0.0F, 0.0F, 0.0F));
+
+ spawn();
+ }
+
+ private void applyDefaultSettings()
+ {
+ super.time = 0;
+ super.hurtEntities = false;
+ super.noPhysics = true;
+ super.setNoGravity(true);
+ }
+
+ public void spawn()
+ {
+ this.world.addEntityToWorld(this, CreatureSpawnEvent.SpawnReason.CUSTOM);
+ }
+
+ private void die()
+ {
+ this.discard(EntityRemoveEvent.Cause.PLUGIN);
+ }
+
+ @Override
+ public void tick()
+ {
+ if (this.blockState.isAir())
+ {
+ die();
+ return;
+ }
+
+ move(MoverType.SELF, getDeltaMovement());
+ if (++super.time > 12000)
+ die();
+
+ setDeltaMovement(getDeltaMovement().multiply(0.9800000190734863D, 1.0D, 0.9800000190734863D));
+ }
+
+ @Override
+ protected void addAdditionalSaveData(@NonNull ValueOutput valueOutput)
+ {
+ super.addAdditionalSaveData(valueOutput);
+ applyDefaultSettings();
+ }
+
+ @Override
+ protected void readAdditionalSaveData(@NonNull ValueInput valueInput)
+ {
+ super.readAdditionalSaveData(valueInput);
+ this.blockState = super.getBlockState();
+ setTicksLived(0);
+ }
+
+ @Override
+ public void fillCrashReportCategory(@NonNull CrashReportCategory crashReportCategory)
+ {
+ super.fillCrashReportCategory(crashReportCategory);
+ crashReportCategory.setDetail("Animated BigDoors block with state: ", blockState.toString());
+ }
+
+ @Override
+ public @NonNull BlockState getBlockState()
+ {
+ return blockState;
+ }
+
+ void setTicksLived(int ticks)
+ {
+ this.time = ticks;
+ }
+}
diff --git a/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/FallingBlockFactoryProvider_V26_2_R1.java b/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/FallingBlockFactoryProvider_V26_2_R1.java
new file mode 100644
index 000000000..9908b8fe2
--- /dev/null
+++ b/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/FallingBlockFactoryProvider_V26_2_R1.java
@@ -0,0 +1,41 @@
+package nl.pim16aap2.bigDoors.NMS;
+
+/**
+ * Provides a specialized {@link FallingBlockFactory} for the given version.
+ *
+ * The exact type of {@link FallingBlockFactory} returned depends on the specific build of Spigot/Paper/etc.
+ *
+ * Use {@link #getFactory()} to get a new {@link FallingBlockFactory} instance.
+ */
+public class FallingBlockFactoryProvider_V26_2_R1
+{
+ /**
+ * Creates a new {@link FallingBlockFactory} instance for a specific version of Minecraft for the current server build.
+ *
+ * @return A new {@link FallingBlockFactory} instance.
+ */
+ public static FallingBlockFactory getFactory()
+ {
+ if (!checkPreconditions())
+ {
+ return null;
+ }
+
+ return new FallingBlockFactory_V26_2_R1(
+ new CustomEntityFallingBlockGenerator_V26_2_R1().getEntityFallingBlockSupplier()
+ );
+ }
+
+ private static boolean checkPreconditions()
+ {
+ try
+ {
+ return CraftBlockDataFactory_V26_2_R1.isInitialized();
+ }
+ catch (Throwable t)
+ {
+ t.printStackTrace();
+ return false;
+ }
+ }
+}
diff --git a/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/FallingBlockFactory_V26_2_R1.java b/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/FallingBlockFactory_V26_2_R1.java
new file mode 100644
index 000000000..1b2bdf90d
--- /dev/null
+++ b/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/FallingBlockFactory_V26_2_R1.java
@@ -0,0 +1,68 @@
+package nl.pim16aap2.bigDoors.NMS;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.resources.Identifier;
+import net.minecraft.resources.ResourceKey;
+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.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.craftbukkit.CraftServer;
+import org.bukkit.craftbukkit.CraftWorld;
+
+class FallingBlockFactory_V26_2_R1 implements FallingBlockFactory
+{
+ private final CustomEntityFallingBlockFactory customEntityFallingBlockFactory;
+ private final ResourceKey blockInfoResourceKey;
+
+ FallingBlockFactory_V26_2_R1(CustomEntityFallingBlockFactory customEntityFallingBlockFactory)
+ {
+ this.customEntityFallingBlockFactory = customEntityFallingBlockFactory;
+ this.blockInfoResourceKey = ResourceKey.create(
+ Registries.BLOCK,
+ Identifier.fromNamespaceAndPath("big-doors", "block-info")
+ );
+ }
+
+ @Override
+ public CustomCraftFallingBlock createFallingBlock(Location loc, NMSBlock block, byte matData, Material mat)
+ {
+ final BlockState blockData = ((NMSBlock_V26_2_R1) block).getMyBlockData();
+ final CustomEntityFallingBlock_V26_2_R1 fBlockNMS =
+ customEntityFallingBlockFactory.newEntityFallingBlock(
+ loc.getWorld(),
+ loc.getX(),
+ loc.getY(),
+ loc.getZ(),
+ blockData
+ );
+
+ return new CustomCraftFallingBlock_V26_2_R1((CraftServer) Bukkit.getServer(), fBlockNMS);
+ }
+
+ @Override
+ public NMSBlock nmsBlockFactory(World world, int x, int y, int z)
+ {
+ final BlockBehaviour.Properties blockInfo =
+ BlockBehaviour.Properties.ofFullCopy(((CraftWorld) world).getHandle().getBlockState(new BlockPos(x, y, z)).getBlock()).setId(blockInfoResourceKey);
+ return new NMSBlock_V26_2_R1(world, x, y, z, blockInfo);
+ }
+
+ /**
+ * Factory for creating {@link CustomEntityFallingBlock} instances.
+ */
+ interface CustomEntityFallingBlockFactory
+ {
+ CustomEntityFallingBlock_V26_2_R1 newEntityFallingBlock(
+ World world,
+ double x,
+ double y,
+ double z,
+ BlockState blockData
+ );
+ }
+}
diff --git a/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/NMSBlock_V26_2_R1.java b/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/NMSBlock_V26_2_R1.java
new file mode 100644
index 000000000..e50db555f
--- /dev/null
+++ b/nms/v26_2_R1/src/main/java/nl/pim16aap2/bigDoors/NMS/NMSBlock_V26_2_R1.java
@@ -0,0 +1,249 @@
+package nl.pim16aap2.bigDoors.NMS;
+
+import com.cryptomorin.xseries.XMaterial;
+import com.mojang.serialization.MapCodec;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.world.item.Item;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.RotatedPillarBlock;
+import net.minecraft.world.level.block.Rotation;
+import net.minecraft.world.level.block.state.BlockBehaviour;
+import net.minecraft.world.level.block.state.BlockState;
+import nl.pim16aap2.bigDoors.util.DoorDirection;
+import nl.pim16aap2.bigDoors.util.NMSUtil;
+import nl.pim16aap2.bigDoors.util.RotateDirection;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.block.BlockFace;
+import org.bukkit.block.data.MultipleFacing;
+import org.bukkit.block.data.Waterlogged;
+import org.bukkit.block.data.type.Fence;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.block.data.CraftBlockData;
+import org.jspecify.annotations.NonNull;
+
+import java.util.Objects;
+import java.util.Set;
+
+public class NMSBlock_V26_2_R1 extends BlockBehaviour implements NMSBlock
+{
+ private static final MapCodec extends Block> CODEC =
+ simpleCodec(properties ->
+ {
+ throw new UnsupportedOperationException("Custom block data cannot be deserialized from codec");
+ });
+
+ private BlockState blockData;
+ private CraftBlockData craftBlockData;
+ private final XMaterial xMat;
+ private Location loc;
+
+ public NMSBlock_V26_2_R1(
+ World world,
+ int x,
+ int y,
+ int z,
+ BlockBehaviour.Properties blockInfo
+ )
+ {
+ super(blockInfo);
+
+ loc = new Location(world, x, y, z);
+
+ craftBlockData = (CraftBlockData) world.getBlockAt(x, y, z).getBlockData();
+ if (craftBlockData instanceof Waterlogged)
+ {
+ ((Waterlogged) craftBlockData).setWaterlogged(false);
+ }
+
+ updateBlockData();
+
+ xMat = XMaterial.matchXMaterial(world.getBlockAt(x, y, z).getType().toString()).orElse(XMaterial.BEDROCK);
+ }
+
+ @Override
+ public boolean canRotate()
+ {
+ return craftBlockData instanceof MultipleFacing;
+ }
+
+ @Override
+ public void rotateBlock(RotateDirection rotDir)
+ {
+ Rotation rot;
+ switch (rotDir)
+ {
+ case CLOCKWISE:
+ rot = Rotation.CLOCKWISE_90;
+ break;
+ case COUNTERCLOCKWISE:
+ rot = Rotation.COUNTERCLOCKWISE_90;
+ break;
+ default:
+ rot = Rotation.NONE;
+ }
+ blockData = blockData.rotate(rot);
+ updateCraftBlockData();
+ }
+
+ private void updateBlockData()
+ {
+ blockData = craftBlockData.getState();
+ }
+
+ private void updateCraftBlockData()
+ {
+ this.craftBlockData = CraftBlockDataFactory_V26_2_R1.fromState(blockData);
+ }
+
+ @Override
+ public void putBlock(Location loc)
+ {
+ this.loc = loc;
+
+ if (craftBlockData instanceof MultipleFacing)
+ {
+ updateCraftBlockDataMultipleFacing();
+ }
+
+ final CraftWorld craftWorld = Objects.requireNonNull((CraftWorld) loc.getWorld());
+
+ craftWorld
+ .getHandle()
+ .setBlock(BlockPos.containing(loc.getX(), loc.getY(), loc.getZ()), blockData, 1);
+ }
+
+ private void updateCraftBlockDataMultipleFacing()
+ {
+ final Set allowedFaces = ((MultipleFacing) craftBlockData).getAllowedFaces();
+ allowedFaces.forEach(
+ (blockFace) ->
+ {
+ final org.bukkit.block.Block otherBlock =
+ loc.clone().add(blockFace.getModX(), blockFace.getModY(), blockFace.getModZ()).getBlock();
+ final org.bukkit.block.data.BlockData otherData = otherBlock.getBlockData();
+
+ if (blockFace.equals(BlockFace.UP))
+ {
+ ((MultipleFacing) craftBlockData).setFace(blockFace, true);
+ }
+ else if (otherBlock.getType().isSolid())
+ {
+
+ ((MultipleFacing) craftBlockData).setFace(blockFace, true);
+
+ final boolean isOtherMultipleFacing = otherData instanceof MultipleFacing;
+ final boolean materialMatch = otherBlock.getType().equals(xMat.parseMaterial());
+ final boolean areBothFence = craftBlockData instanceof Fence && otherData instanceof Fence;
+
+ if (isOtherMultipleFacing && (materialMatch || areBothFence))
+ {
+ final Set otherAllowedFaces = ((MultipleFacing) otherData).getAllowedFaces();
+ if (otherAllowedFaces.contains(blockFace.getOppositeFace()))
+ {
+ ((MultipleFacing) otherData).setFace(blockFace.getOppositeFace(), true);
+ otherBlock.setBlockData(otherData);
+ }
+ }
+ }
+ else
+ {
+ ((MultipleFacing) craftBlockData).setFace(blockFace, false);
+ }
+ });
+ this.updateBlockData();
+ }
+
+ @Override
+ public void rotateVerticallyInDirection(DoorDirection openDirection)
+ {
+ NMSUtil.rotateVerticallyInDirection(openDirection, craftBlockData);
+ this.updateBlockData();
+ }
+
+ @Override
+ public void rotateBlockUpDown(boolean ns)
+ {
+ Direction.Axis axis = blockData.getValue(RotatedPillarBlock.AXIS);
+ Direction.Axis newAxis = axis;
+ switch (axis)
+ {
+ case X:
+ newAxis = ns ? Direction.Axis.X : Direction.Axis.Y;
+ break;
+ case Y:
+ newAxis = ns ? Direction.Axis.Z : Direction.Axis.X;
+ break;
+ case Z:
+ newAxis = ns ? Direction.Axis.Y : Direction.Axis.Z;
+ break;
+ }
+ blockData = blockData.setValue(RotatedPillarBlock.AXIS, newAxis);
+ this.updateCraftBlockData();
+ }
+
+ @Override
+ public void rotateCylindrical(RotateDirection rotDir)
+ {
+ if (rotDir.equals(RotateDirection.CLOCKWISE))
+ {
+ blockData = blockData.rotate(Rotation.CLOCKWISE_90);
+ }
+ else
+ {
+ blockData = blockData.rotate(Rotation.COUNTERCLOCKWISE_90);
+ }
+ this.updateCraftBlockData();
+ }
+
+ /**
+ * Gets the BlockState (NMS) of this block.
+ *
+ * @return The BlockState (NMS) of this block.
+ */
+ BlockState getMyBlockData()
+ {
+ return blockData;
+ }
+
+ @Override
+ public String toString()
+ {
+ return blockData.toString();
+ }
+
+ @Override
+ public void deleteOriginalBlock(boolean applyPhysics)
+ {
+ final World world = Objects.requireNonNull(loc.getWorld());
+ if (!applyPhysics)
+ {
+ world.getBlockAt(loc).setType(Material.AIR, false);
+ }
+ else
+ {
+ world.getBlockAt(loc).setType(Material.CAVE_AIR, false);
+ world.getBlockAt(loc).setType(Material.AIR, true);
+ }
+ }
+
+ @Override
+ protected @NonNull MapCodec extends Block> codec()
+ {
+ return CODEC;
+ }
+
+ @Override
+ public @NonNull Item asItem()
+ {
+ throw new UnsupportedOperationException("Custom block data cannot be converted to an item");
+ }
+
+ @Override
+ protected @NonNull Block asBlock()
+ {
+ return this.blockData.getBlock();
+ }
+}
diff --git a/pom.xml b/pom.xml
index 3336f23f5..93276ae84 100644
--- a/pom.xml
+++ b/pom.xml
@@ -48,7 +48,7 @@
3.4.0
3.5.4
- 38decc68d5
+ 27883fb37a
com.github.PimvanderLoos