diff --git a/SchematicSystem/SchematicSystem_21/build.gradle.kts b/SchematicSystem/SchematicSystem_21/build.gradle.kts
new file mode 100644
index 00000000..ea8298e7
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_21/build.gradle.kts
@@ -0,0 +1,32 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+plugins {
+ steamwar.java
+}
+
+dependencies {
+ compileOnly(project(":SpigotCore", "default"))
+ compileOnly(project(":SchematicSystem:SchematicSystem_Core", "default"))
+
+ compileOnly(libs.spigotapi)
+
+ compileOnly(libs.nms21)
+ compileOnly(libs.fawe21)
+}
diff --git a/SchematicSystem/SchematicSystem_21/src/de/steamwar/schematicsystem/autocheck/AutoChecker21.java b/SchematicSystem/SchematicSystem_21/src/de/steamwar/schematicsystem/autocheck/AutoChecker21.java
new file mode 100644
index 00000000..831f7cbc
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_21/src/de/steamwar/schematicsystem/autocheck/AutoChecker21.java
@@ -0,0 +1,133 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2026 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.schematicsystem.autocheck;
+
+import com.sk89q.jnbt.CompoundTag;
+import com.sk89q.worldedit.entity.Entity;
+import com.sk89q.worldedit.extent.clipboard.Clipboard;
+import com.sk89q.worldedit.math.BlockVector3;
+import com.sk89q.worldedit.world.block.BaseBlock;
+import de.steamwar.core.Core;
+import de.steamwar.sql.GameModeConfig;
+import org.bukkit.Material;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class AutoChecker21 implements AutoChecker.IAutoChecker {
+
+ public AutoChecker.BlockScanResult scan(Clipboard clipboard) {
+ AutoChecker.BlockScanResult result = new AutoChecker.BlockScanResult();
+ BlockVector3 min = clipboard.getMinimumPoint();
+ BlockVector3 max = clipboard.getMaximumPoint();
+ for (int x = min.getBlockX(); x <= max.getBlockX(); x++) {
+ for (int y = min.getBlockY(); y <= max.getBlockY(); y++) {
+ for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) {
+ final BaseBlock block = clipboard.getFullBlock(BlockVector3.at(x, y, z));
+ final Material material = Material.matchMaterial(block.getBlockType().getId());
+ if (material == null) {
+ continue;
+ }
+
+ result.getBlockCounts().merge(material, 1, Integer::sum);
+
+ if (AutoCheckerItems.impl.getInventoryMaterials().contains(material)) {
+ checkInventory(result, block, material, new BlockPos(x, y, z));
+ }
+
+ if (x == min.getBlockX() || x == max.getBlockX() || y == max.getBlockY() || z == min.getBlockZ() || z == max.getBlockZ()) {
+ result.getDesignBlocks().computeIfAbsent(material, m -> new ArrayList<>()).add(new BlockPos(x, y, z));
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ private static final Map> itemsInInv = new EnumMap<>(Material.class);
+
+ static {
+ itemsInInv.put(Material.BUCKET, EnumSet.of(Material.DISPENSER));
+ itemsInInv.put(Material.TNT, EnumSet.of(Material.CHEST, Material.BARREL, Material.SHULKER_BOX, Material.BLACK_SHULKER_BOX, Material.BLUE_SHULKER_BOX,
+ Material.BROWN_SHULKER_BOX, Material.CYAN_SHULKER_BOX, Material.GRAY_SHULKER_BOX, Material.GREEN_SHULKER_BOX, Material.LIGHT_BLUE_SHULKER_BOX,
+ Material.LIGHT_GRAY_SHULKER_BOX, Material.LIME_SHULKER_BOX, Material.MAGENTA_SHULKER_BOX, Material.ORANGE_SHULKER_BOX,
+ Material.PINK_SHULKER_BOX, Material.PURPLE_SHULKER_BOX, Material.RED_SHULKER_BOX, Material.WHITE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX));
+ itemsInInv.put(Material.FIRE_CHARGE, EnumSet.of(Material.DISPENSER));
+ itemsInInv.put(Material.ARROW, EnumSet.of(Material.DISPENSER));
+ itemsInInv.put(Material.WIND_CHARGE, EnumSet.of(Material.DISPENSER));
+ AutoCheckerItems.impl.getAllowedMaterialsInInventory().forEach(material -> itemsInInv.put(material, AutoCheckerItems.impl.getInventoryMaterials()));
+ }
+
+ private void checkInventory(AutoChecker.BlockScanResult result, BaseBlock block, Material material, BlockPos pos) {
+ CompoundTag nbt = block.getNbtData();
+ if (nbt == null) {
+ result.getDefunctNbt().add(pos);
+ return;
+ }
+
+
+ if (material == Material.JUKEBOX && nbt.getValue().containsKey("RecordItem")) {
+ result.getRecords().add(pos);
+ return;
+ }
+
+ List items = nbt.getList("Items", CompoundTag.class);
+ if (items.isEmpty())
+ return; // Leeres Inventar
+
+ int counter = 0;
+ for (CompoundTag item : items) {
+ if (!item.containsKey("id")) {
+ result.getDefunctNbt().add(pos);
+ continue;
+ }
+
+ Material itemType = Material.matchMaterial(item.getString("id"));
+ if (itemType == null) // Leere Slots
+ continue;
+
+ if (!itemsInInv.getOrDefault(itemType, EnumSet.noneOf(Material.class)).contains(material)) {
+ result.getForbiddenItems().computeIfAbsent(pos, blockVector3 -> new HashSet<>()).add(itemType);
+ } else if (material == Material.DISPENSER && (itemType == Material.ARROW || itemType == Material.FIRE_CHARGE)) {
+ counter += Core.getVersion() >= 21 ? item.getInt("count") : item.getByte("Count");
+ }
+ if (item.containsKey("tag")) {
+ result.getForbiddenNbt().computeIfAbsent(pos, blockVector3 -> new HashSet<>()).add(itemType);
+ }
+ }
+ result.getDispenserItems().put(pos, counter);
+ }
+
+ @Override
+ public AutoCheckerResult check(Clipboard clipboard, GameModeConfig type) {
+ return AutoCheckerResult.builder().type(type).height(clipboard.getDimensions().getBlockY()).width(clipboard.getDimensions().getBlockX())
+ .depth(clipboard.getDimensions().getBlockZ()).blockScanResult(scan(clipboard))
+ .entities(clipboard.getEntities().stream().map(Entity::getLocation)
+ .map(blockVector3 -> new BlockPos(blockVector3.getBlockX(), blockVector3.getBlockY(), blockVector3.getBlockZ()))
+ .collect(Collectors.toList()))
+ .build();
+ }
+
+ @Override
+ public AutoCheckerResult sizeCheck(Clipboard clipboard, GameModeConfig type) {
+ return AutoCheckerResult.builder().type(type).height(clipboard.getDimensions().getBlockY()).width(clipboard.getDimensions().getBlockX())
+ .depth(clipboard.getDimensions().getBlockZ()).build();
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_21/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems21.java b/SchematicSystem/SchematicSystem_21/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems21.java
new file mode 100644
index 00000000..af50a3fa
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_21/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems21.java
@@ -0,0 +1,49 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the
+ * GNU Affero General Public License as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License along with this program.
+ * If not, see .
+ */
+
+package de.steamwar.schematicsystem.autocheck;
+
+import org.bukkit.Material;
+
+import java.util.EnumSet;
+import java.util.Set;
+
+public class AutoCheckerItems21 implements AutoCheckerItems {
+
+ private static final Set INVENTORY = EnumSet.of(Material.BARREL, Material.BLAST_FURNACE, Material.BREWING_STAND, Material.CAMPFIRE,
+ Material.CHEST, Material.DISPENSER, Material.DROPPER, Material.FURNACE, Material.HOPPER, Material.JUKEBOX, Material.SHULKER_BOX,
+ Material.WHITE_SHULKER_BOX, Material.ORANGE_SHULKER_BOX, Material.MAGENTA_SHULKER_BOX, Material.LIGHT_BLUE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX,
+ Material.LIME_SHULKER_BOX, Material.PINK_SHULKER_BOX, Material.GRAY_SHULKER_BOX, Material.LIGHT_GRAY_SHULKER_BOX, Material.CYAN_SHULKER_BOX,
+ Material.PURPLE_SHULKER_BOX, Material.BLUE_SHULKER_BOX, Material.BROWN_SHULKER_BOX, Material.GREEN_SHULKER_BOX, Material.RED_SHULKER_BOX,
+ Material.BLACK_SHULKER_BOX, Material.SMOKER, Material.TRAPPED_CHEST);
+
+ private static final Set FLOWERS = EnumSet.of(Material.CORNFLOWER, Material.POPPY, Material.FERN, Material.DANDELION, Material.BLUE_ORCHID,
+ Material.ALLIUM, Material.AZURE_BLUET, Material.RED_TULIP, Material.ORANGE_TULIP, Material.WHITE_TULIP, Material.PINK_TULIP, Material.OXEYE_DAISY,
+ Material.LILY_OF_THE_VALLEY, Material.WITHER_ROSE, Material.SUNFLOWER, Material.DIAMOND_HORSE_ARMOR, Material.IRON_HORSE_ARMOR,
+ Material.GOLDEN_HORSE_ARMOR, Material.LEATHER_HORSE_ARMOR, Material.HONEY_BOTTLE, Material.LILAC, Material.ROSE_BUSH, Material.PEONY,
+ Material.TALL_GRASS, Material.LARGE_FERN);
+
+ @Override
+ public Set getInventoryMaterials() {
+ return INVENTORY;
+ }
+
+ @Override
+ public Set getAllowedMaterialsInInventory() {
+ return FLOWERS;
+ }
+}
diff --git a/SchematicSystem/build.gradle.kts b/SchematicSystem/build.gradle.kts
index 65613802..947812e3 100644
--- a/SchematicSystem/build.gradle.kts
+++ b/SchematicSystem/build.gradle.kts
@@ -32,4 +32,5 @@ dependencies {
implementation(project(":SchematicSystem:SchematicSystem_15"))
implementation(project(":SchematicSystem:SchematicSystem_19"))
implementation(project(":SchematicSystem:SchematicSystem_20"))
+ implementation(project(":SchematicSystem:SchematicSystem_21"))
}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 5f364d5b..0862fdce 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -101,7 +101,7 @@ dependencyResolutionManagement {
library("hamcrest", "org.hamcrest:hamcrest:2.2")
library("classindex", "org.atteo.classindex:classindex:3.13")
- library("spigotapi", "org.spigotmc:spigot-api:1.20-R0.1-SNAPSHOT")
+ library("spigotapi", "org.spigotmc:spigot-api:1.21-R0.1-SNAPSHOT")
library("spigotannotations", "org.spigotmc:plugin-annotations:1.2.3-SNAPSHOT")
library("paperapi", "io.papermc.paper:paper-api:1.19.2-R0.1-SNAPSHOT")
library("paperapi21", "io.papermc.paper:paper-api:1.21.6-R0.1-SNAPSHOT")
@@ -222,6 +222,7 @@ include(
"SchematicSystem:SchematicSystem_15",
"SchematicSystem:SchematicSystem_19",
"SchematicSystem:SchematicSystem_20",
+ "SchematicSystem:SchematicSystem_21",
"SchematicSystem:SchematicSystem_Core"
)