diff --git a/SchematicSystem/SchematicSystem_15/build.gradle.kts b/SchematicSystem/SchematicSystem_15/build.gradle.kts
new file mode 100644
index 00000000..261c40bd
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_15/build.gradle.kts
@@ -0,0 +1,58 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 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 {
+ id("java")
+ id("base")
+}
+
+group = "de.steamwar"
+version = ""
+
+tasks.compileJava {
+ options.encoding = "UTF-8"
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+}
+
+sourceSets {
+ main {
+ java {
+ srcDirs("src/")
+ }
+ resources {
+ srcDirs("src/")
+ exclude("**/*.java", "**/*.kt")
+ }
+ }
+}
+
+dependencies {
+ compileOnly("org.projectlombok:lombok:1.18.32")
+ annotationProcessor("org.projectlombok:lombok:1.18.32")
+
+ compileOnly(project(":SchematicSystem:SchematicSystem_Core"))
+ compileOnly(project(":SpigotCore"))
+
+ compileOnly("de.steamwar:spigot:1.15")
+ compileOnly("de.steamwar:worldedit:1.15")
+}
diff --git a/SchematicSystem/SchematicSystem_15/src/de/steamwar/schematicsystem/autocheck/AutoChecker15.java b/SchematicSystem/SchematicSystem_15/src/de/steamwar/schematicsystem/autocheck/AutoChecker15.java
new file mode 100644
index 00000000..e0823263
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_15/src/de/steamwar/schematicsystem/autocheck/AutoChecker15.java
@@ -0,0 +1,185 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.schematicsystem.CheckSchemType;
+import org.bukkit.Material;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class AutoChecker15 implements AutoChecker.IAutoChecker {
+ 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.HONEY_BOTTLE);
+
+ 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(INVENTORY.contains(material)) {
+ checkInventory(result, block, material, new BlockPos(x, y, z));
+ }
+
+ if(x == 0 || x == max.getBlockX() - 1 || y == max.getBlockY() - 1 || z == 0 || z == max.getBlockZ() - 1) {
+ 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));
+ itemsInInv.put(Material.FIRE_CHARGE, EnumSet.of(Material.DISPENSER));
+ itemsInInv.put(Material.ARROW, EnumSet.of(Material.DISPENSER));
+ FLOWERS.forEach(material -> itemsInInv.put(material, INVENTORY));
+ }
+
+ 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 += 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, CheckSchemType 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, CheckSchemType type) {
+ return AutoCheckerResult.builder()
+ .type(type)
+ .height(clipboard.getDimensions().getBlockY())
+ .width(clipboard.getDimensions().getBlockX())
+ .depth(clipboard.getDimensions().getBlockZ())
+ .build();
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_15/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand15.java b/SchematicSystem/SchematicSystem_15/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand15.java
new file mode 100644
index 00000000..47f58a58
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_15/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand15.java
@@ -0,0 +1,148 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.commands.schematiccommand;
+
+import com.sk89q.jnbt.CompoundTag;
+import com.sk89q.jnbt.CompoundTagBuilder;
+import com.sk89q.jnbt.ListTag;
+import com.sk89q.worldedit.EditSession;
+import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.extent.clipboard.Clipboard;
+import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
+import com.sk89q.worldedit.function.operation.Operations;
+import com.sk89q.worldedit.math.BlockVector3;
+import com.sk89q.worldedit.world.block.BaseBlock;
+import com.sk89q.worldedit.world.block.BlockState;
+import com.sk89q.worldedit.world.block.BlockTypes;
+import de.steamwar.schematicsystem.CheckSchemType;
+import de.steamwar.schematicsystem.autocheck.AutoCheckerResult;
+import de.steamwar.schematicsystem.autocheck.BlockPos;
+import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommand;
+import org.bukkit.Material;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class SchematicCommand15 implements SchematicCommand.ISchematicCommand {
+ @Override
+ public Clipboard fixClipboard(Clipboard clipboard, AutoCheckerResult result, CheckSchemType type) throws Exception {
+ for (BlockPos blockPos : result.getBlockScanResult().getRecords()) {
+ BlockVector3 vector = BlockVector3.at(blockPos.getX(), blockPos.getY(), blockPos.getZ());
+ clipboard.setBlock(vector, clipboard.getFullBlock(vector).toBaseBlock(new CompoundTag(Collections.emptyMap())));
+ }
+
+ Map> toBeCheckedInvs = new HashMap<>();
+
+ toBeCheckedInvs.putAll(result.getBlockScanResult().getForbiddenItems());
+ toBeCheckedInvs.putAll(result.getBlockScanResult().getForbiddenNbt());
+
+ for (Map.Entry> entry: toBeCheckedInvs.entrySet()) {
+ BlockPos pos = entry.getKey();
+ Set materials = entry.getValue();
+ BlockVector3 vector = BlockVector3.at(pos.getX(), pos.getY(), pos.getZ());
+ BaseBlock block = clipboard.getFullBlock(vector);
+ CompoundTag tag = block.getNbtData();
+ CompoundTagBuilder builder = CompoundTagBuilder.create();
+ List list = new ArrayList<>();
+ for (CompoundTag items : tag.getList("Items", CompoundTag.class)) {
+ if(materials.contains(Material.matchMaterial(items.getString("id")))) {
+ continue;
+ }
+
+ if(items.containsKey("tag")) {
+ continue;
+ }
+
+ list.add(items);
+ }
+ builder.put("Items", new ListTag(CompoundTag.class, list));
+ clipboard.setBlock(vector, block.toBaseBlock(builder.build()));
+ }
+
+ if(type.getMaxDispenserItems() > 0 ) {
+ for (Map.Entry entry : result.getBlockScanResult().getDispenserItems().entrySet()) {
+ if(entry.getValue() <= type.getMaxDispenserItems()) {
+ continue;
+ }
+
+ BlockPos pos = entry.getKey();
+ BlockVector3 vector = BlockVector3.at(pos.getX(), pos.getY(), pos.getZ());
+ BaseBlock block = clipboard.getFullBlock(vector);
+ CompoundTag tag = block.getNbtData();
+ CompoundTagBuilder builder = tag.createBuilder();
+ List items = tag.getList("Items", CompoundTag.class);
+ Collections.reverse(items); // To let the first item be in the Dispenser
+ List list = new ArrayList<>();
+ int diff = entry.getValue() - type.getMaxDispenserItems();
+ for (CompoundTag item : items) {
+ if(item == null) {
+ continue;
+ }
+
+ if(diff == 0) {
+ list.add(item);
+ continue;
+ }
+
+ if(diff > item.getByte("Count")) {
+ diff -= item.getByte("Count");
+ continue;
+ }
+
+ item = item.createBuilder().putByte("Count", (byte) (item.getByte("Count") - diff)).build();
+ diff = 0;
+ list.add(item);
+ }
+
+ builder.put("Items", new ListTag(CompoundTag.class, list));
+ clipboard.setBlock(vector, block.toBaseBlock(builder.build()));
+ }
+ }
+
+ if(!result.isLimitedBlocksOK()) {
+ Set toReplace = type.getLimits().entrySet().stream()
+ .filter(setIntegerEntry -> setIntegerEntry.getValue() == 0)
+ .flatMap(setIntegerEntry -> setIntegerEntry.getKey().stream())
+ .map(Material::matchMaterial)
+ .collect(Collectors.toSet());
+ BlockState replaceType = Objects.requireNonNull(toReplace.contains(Material.END_STONE) ? BlockTypes.IRON_BLOCK : BlockTypes.END_STONE).getDefaultState();
+ BlockVector3 min = clipboard.getMinimumPoint();
+ BlockVector3 max = clipboard.getMaximumPoint();
+ for (int i = min.getBlockX(); i <= max.getBlockX(); i++) {
+ for (int j = min.getBlockY(); j <= max.getBlockY(); j++) {
+ for (int k = min.getBlockZ(); k <= max.getBlockZ(); k++) {
+ BlockVector3 vector = BlockVector3.at(i, j, k);
+ BaseBlock block = clipboard.getFullBlock(vector);
+ if(toReplace.contains(Material.matchMaterial(block.getBlockType().getId()))) {
+ clipboard.setBlock(vector, replaceType.toBaseBlock());
+ }
+ }
+ }
+ }
+ }
+
+ return clipboard;
+ }
+
+ @Override
+ public void createCopy(EditSession editSession, Clipboard clipboard) throws WorldEditException {
+ Operations.complete(new ForwardExtentCopy(editSession, clipboard.getRegion(), clipboard, clipboard.getMinimumPoint()));
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_8/build.gradle.kts b/SchematicSystem/SchematicSystem_8/build.gradle.kts
new file mode 100644
index 00000000..14652dc6
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_8/build.gradle.kts
@@ -0,0 +1,58 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 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 {
+ id("java")
+ id("base")
+}
+
+group = "de.steamwar"
+version = ""
+
+tasks.compileJava {
+ options.encoding = "UTF-8"
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+}
+
+sourceSets {
+ main {
+ java {
+ srcDirs("src/")
+ }
+ resources {
+ srcDirs("src/")
+ exclude("**/*.java", "**/*.kt")
+ }
+ }
+}
+
+dependencies {
+ compileOnly("org.projectlombok:lombok:1.18.32")
+ annotationProcessor("org.projectlombok:lombok:1.18.32")
+
+ compileOnly(project(":SchematicSystem:SchematicSystem_Core"))
+ compileOnly(project(":SpigotCore"))
+
+ compileOnly("de.steamwar:spigot:1.8")
+ compileOnly("de.steamwar:worldedit:1.12")
+}
diff --git a/SchematicSystem/SchematicSystem_8/src/de/steamwar/schematicsystem/autocheck/AutoChecker8.java b/SchematicSystem/SchematicSystem_8/src/de/steamwar/schematicsystem/autocheck/AutoChecker8.java
new file mode 100644
index 00000000..1dbc8e44
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_8/src/de/steamwar/schematicsystem/autocheck/AutoChecker8.java
@@ -0,0 +1,174 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.Vector;
+import com.sk89q.worldedit.blocks.BaseBlock;
+import com.sk89q.worldedit.entity.Entity;
+import com.sk89q.worldedit.extent.clipboard.Clipboard;
+import com.sk89q.worldedit.regions.Region;
+import de.steamwar.schematicsystem.CheckSchemType;
+import org.bukkit.Material;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+@SuppressWarnings("deprecation")
+public class AutoChecker8 implements AutoChecker.IAutoChecker {
+ private static final int DISPENSER = Material.DISPENSER.getId();
+ private static final int JUKEBOX = Material.JUKEBOX.getId();
+ private static final int CHEST = Material.CHEST.getId();
+ private static final Set INVENTORY = new HashSet<>();
+ private static final Set FLOWERS;
+
+ static{
+ INVENTORY.add(CHEST);
+ INVENTORY.add(Material.TRAPPED_CHEST.getId());
+ INVENTORY.add(Material.HOPPER.getId());
+ INVENTORY.add(Material.FURNACE.getId());
+ INVENTORY.add(Material.BURNING_FURNACE.getId());
+ INVENTORY.add(JUKEBOX); //RecordItem
+ INVENTORY.add(DISPENSER);
+ INVENTORY.add(Material.DROPPER.getId());
+ INVENTORY.add(Material.ANVIL.getId());
+ INVENTORY.add(Material.BREWING_STAND.getId());
+ for(int i = 219; i <= 234; i++) {
+ INVENTORY.add(i); // ShulkerBoxes
+ }
+
+ Set flowers = new HashSet<>();
+ flowers.add(Material.YELLOW_FLOWER);
+ flowers.add(Material.RED_ROSE);
+ flowers.add(Material.DOUBLE_PLANT);
+ flowers.add(Material.DIAMOND_BARDING);
+ flowers.add(Material.IRON_BARDING);
+ flowers.add(Material.GOLD_BARDING);
+ FLOWERS = flowers;
+ }
+
+ public void scan(AutoChecker.BlockScanResult result, Clipboard clipboard) {
+ Region region = clipboard.getRegion();
+ Vector min = region.getMinimumPoint();
+ Vector max = region.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.getBlock(new Vector(x, y, z));
+ final int blockId = block.getId();
+ final Material material = Material.getMaterial(blockId);
+
+ result.getBlockCounts().merge(material, 1, Integer::sum);
+
+ if(INVENTORY.contains(blockId)){
+ checkInventory(result, block, blockId, new BlockPos(x, y, z));
+ }
+
+ if(x == 0 || x == max.getBlockX() - 1 || y == max.getBlockY() - 1 || z == 0 || z == max.getBlockZ() - 1) {
+ result.getDesignBlocks().computeIfAbsent(material, m -> new ArrayList<>()).add(new BlockPos(x, y, z));
+ }
+ }
+ }
+ }
+ }
+
+ 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));
+ itemsInInv.put(Material.FIREBALL, EnumSet.of(Material.DISPENSER));
+ itemsInInv.put(Material.ARROW, EnumSet.of(Material.DISPENSER));
+ FLOWERS.forEach(material -> itemsInInv.put(material, INVENTORY.stream().map(Material::getMaterial).collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class)))));
+ }
+
+ private static void checkInventory(AutoChecker.BlockScanResult result, BaseBlock block, int blockId, BlockPos pos) {
+ CompoundTag nbt = block.getNbtData();
+ if(nbt == null){
+ result.getDefunctNbt().add(pos);
+ return;
+ }
+
+ if(blockId == 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;
+ }
+
+ String materialName = item.getString("id");
+ if(materialName.contains(":"))
+ materialName = materialName.split(":")[1];
+ materialName = materialName.toUpperCase().replace("SHOVEL", "SPADE");
+ Material itemType = Material.getMaterial(materialName);
+ if(itemType == null && item.getString("id").equals("minecraft:fire_charge"))
+ itemType = Material.FIREBALL;
+ if(itemType == null) //Leere Slots
+ continue;
+
+
+ if(!itemsInInv.getOrDefault(itemType, EnumSet.noneOf(Material.class)).contains(Material.getMaterial(blockId))) {
+ result.getForbiddenItems().computeIfAbsent(pos, blockPos -> new HashSet<>()).add(Material.getMaterial(blockId));
+ } else if(blockId == DISPENSER && (itemType.equals(Material.FIREBALL) || itemType.equals(Material.ARROW))) {
+ counter += item.getByte("Count");
+ }
+ if(item.containsKey("tag")) {
+ result.getForbiddenNbt().computeIfAbsent(pos, blockPos -> new HashSet<>()).add(Material.getMaterial(blockId));
+ }
+ }
+
+ result.getDispenserItems().put(pos, counter);
+ }
+
+ @Override
+ public AutoCheckerResult check(Clipboard clipboard, CheckSchemType type) {
+ AutoChecker.BlockScanResult blockScanResult = new AutoChecker.BlockScanResult();
+ scan(blockScanResult, clipboard);
+
+ return AutoCheckerResult.builder()
+ .type(type)
+ .height(clipboard.getDimensions().getBlockY())
+ .width(clipboard.getDimensions().getBlockX())
+ .depth(clipboard.getDimensions().getBlockZ())
+ .blockScanResult(blockScanResult)
+ .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, CheckSchemType type) {
+ return AutoCheckerResult.builder()
+ .type(type)
+ .height(clipboard.getDimensions().getBlockY())
+ .width(clipboard.getDimensions().getBlockX())
+ .depth(clipboard.getDimensions().getBlockZ())
+ .build();
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_8/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand8.java b/SchematicSystem/SchematicSystem_8/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand8.java
new file mode 100644
index 00000000..ad38643a
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_8/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand8.java
@@ -0,0 +1,42 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.commands.schematiccommand;
+
+import com.sk89q.worldedit.EditSession;
+import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.extent.clipboard.Clipboard;
+import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
+import com.sk89q.worldedit.function.operation.Operations;
+import de.steamwar.schematicsystem.CheckSchemType;
+import de.steamwar.schematicsystem.autocheck.AutoCheckerResult;
+import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommand;
+
+public class SchematicCommand8 implements SchematicCommand.ISchematicCommand {
+
+ @Override
+ public Clipboard fixClipboard(Clipboard clipboard, AutoCheckerResult result, CheckSchemType type) throws Exception {
+ return null;
+ }
+
+ @Override
+ public void createCopy(EditSession editSession, Clipboard clipboard) throws WorldEditException {
+ Operations.complete(new ForwardExtentCopy(editSession, clipboard.getRegion(), clipboard, clipboard.getMinimumPoint()));
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/build.gradle.kts b/SchematicSystem/SchematicSystem_Core/build.gradle.kts
new file mode 100644
index 00000000..f833cb0f
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/build.gradle.kts
@@ -0,0 +1,57 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 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 {
+ id("java")
+ id("base")
+}
+
+group = "de.steamwar"
+version = ""
+
+tasks.compileJava {
+ options.encoding = "UTF-8"
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+}
+
+sourceSets {
+ main {
+ java {
+ srcDirs("src/")
+ }
+ resources {
+ srcDirs("src/")
+ exclude("**/*.java", "**/*.kt")
+ }
+ }
+}
+
+dependencies {
+ compileOnly("org.projectlombok:lombok:1.18.32")
+ annotationProcessor("org.projectlombok:lombok:1.18.32")
+
+ compileOnly(project(":SpigotCore"))
+
+ compileOnly("de.steamwar:spigot:1.15")
+ compileOnly("de.steamwar:worldedit:1.15")
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/SchematicSystem.properties b/SchematicSystem/SchematicSystem_Core/src/SchematicSystem.properties
new file mode 100644
index 00000000..b5e1c15f
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/SchematicSystem.properties
@@ -0,0 +1,264 @@
+#
+# This file is a part of the SteamWar software.
+#
+# Copyright (C) 2023 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 .
+#
+
+PREFIX=§eSchematic§8» §7
+ON=§aon
+OFF=§coff
+CHANGE=§7To change
+CLICK=§7Click
+CLICK_DRAG_ITEM=§7Click or drag item here
+CURRENT=§7Current: {0}
+CONFIRM=§aConfirm
+CANCEL=§cCancel
+
+UTIL_NAME_REQUIRED=§cFolder name required
+UTIL_NAME_TOO_LONG=§cSchematic name too long
+UTIL_NAME_INVALID_CHAR=§cThe specified schema name contains forbidden characters
+UTIL_NAME_FORBIDDEN=§cThe path must not contain \"§l{0}§c\"
+UTIL_LIST_HEAD=§eSchematics §8(§e{0}§8)
+UTIL_LIST_PATH=§7Current path: §e{0}
+UTIL_LIST_BACK=§e../
+UTIL_LIST_BACK_HOVER=§eBack {0}
+UTIL_LIST_DIR=§7§lDIR
+UTIL_LIST_TYPE=§8§l{0}
+UTIL_LIST_BASE=§e
+UTIL_LIST_FROM=§8from §7{0}
+UTIL_LIST_OPEN_DIR=§eShow directory
+UTIL_LIST_OPEN_SCHEM=§eManage schematics
+UTIL_LIST_REMOVE=[Remove]
+UTIL_LIST_REMOVE_HOVER=§7Remove yourself from the directory
+UTIL_LIST_BACK_ARROW=««
+UTIL_LIST_BACK_ARROW_HOVER=§ePrevious page
+UTIL_LIST_NEXT=Page ({0}/{1}) »»
+UTIL_LIST_NEXT_HOVER=§eNext page
+UTIL_INFO_SCHEM=§7Schematic: §e{0}
+UTIL_INFO_NAME=§7Name: §e{0}
+UTIL_INFO_OWNER=§7Owner: §e{0}
+UTIL_INFO_PARENT=§7Directory: §e{0}
+UTIL_INFO_UPDATED=§7Last update: §e{0}
+UTIL_INFO_TYPE=§7Type: §e{0}
+UTIL_INFO_TYPE_DIR=§eDIR
+UTIL_INFO_RANK=§7Rank: §e{0}
+UTIL_INFO_COLOR=§7Color translation: {0}
+UTIL_INFO_REPLAY=§7Replay playback: {0}
+UTIL_INFO_ELO=§7Elo: §e{0}
+UTIL_INFO_FORMAT=§7Format: §e{0}
+UTIL_INFO_STATUS=§cState: §c{0}: {1}
+UTIL_INFO_MEMBER=§7Members: §e{0}
+UTIL_INFO_MEMBER_STRING=Members:
+UTIL_INFO_ACTION_LOAD=(Load)
+UTIL_INFO_ACTION_LOAD_HOVER=§eLoad schematic
+UTIL_INFO_ACTION_DOWNLOAD=(Download)
+UTIL_INFO_ACTION_DOWNLOAD_HOVER=§eDownload schematic
+UTIL_INFO_ACTION_TYPE_HOVER=§eChange schematic type
+UTIL_INFO_ACTION_ADD_HOVER=§eAdd member
+UTIL_INFO_ACTION_REMOVE_HOVER=§eRemove {0}
+UTIL_INFO_ACTION_MOVE_HOVER=§eMove schematic
+UTIL_INFO_ACTION_RENAME_HOVER=§eRename schematic
+UTIL_INFO_ACTION_DELETE=(Delete)
+UTIL_INFO_ACTION_DELETE_HOVER=§eDelete schematic
+UTIL_LOAD_NOT_HERE=§cYou cannot load schematics here
+UTIL_LOAD_NOT_HERE_ALL=§cSchematics cannot be loaded on this build
+UTIL_LOAD_DIR=§cYou cannot load folders
+UTIL_LOAD_DONE=§7Schematic §e{0} loaded
+UTIL_LOAD_NO_DATA=§cNo data could be found in the Schematic
+UTIL_LOAD_ERROR=§cThe schematic could not be loaded
+UTIL_DOWNLOAD_PUNISHED=§cYou are not allowed to download schematics: §f§l{0}
+UTIL_DOWNLOAD_NOT_OWN=§cYou may download only your own schematics
+UTIL_DOWNLOAD_LINK=Your download link:
+UTIL_TYPE_PUNISHED=§cYou are not allowed to submit schematics: §f§l{0}
+UTIL_TYPE_NOT_OWN=§cYou can only submit your own schematics
+UTIL_TYPE_DIR=§cYou cannot submit folders
+UTIL_TYPE_NOT_ASSIGNABLE=§cSchematics cannot be changed for this type
+UTIL_TYPE_ALREADY=§cThe Schematic already has this type
+UTIL_TYPE_DONE=§aChange schematic type
+UTIL_TYPE_FIGHT_ALREADY=§cYou have already submitted this schematic
+UTIL_TYPE_AFTER_DEADLINE=§cSchematics of this type can no longer be submitted. Deadline was: {0}
+UTIL_TYPE_ERROR=§cThe Schematic is not compliant with the rules
+UTIL_TYPE_EXTEND=§aThe preparation server is starting
+UTIL_SUBMIT_TITLE=Extend Schematic
+UTIL_SUBMIT_REPLAY_ON=§aReplay allowed
+UTIL_SUBMIT_REPLAY_OFF=§cReplay locked
+UTIL_SUBMIT_COLOR_ON=§aReplace pink to team color
+UTIL_SUBMIT_COLOR_OFF=§cDo not replace pink
+UTIL_SUBMIT_DIRECT=§eSubmit directly
+UTIL_SUBMIT_DIRECT_DONE=§aThe Schematic will be reviewed in a timely manner
+UTIL_SUBMIT_EXTEND=§eExtend Schematic
+UTIL_SUBMIT_EXTEND_DONE=§aThe preparation server is starting
+UTIL_CHECK_TYPE_NOT_FOUND=§cThe type {0} was not found
+UTIL_CHECK_SUCCESS=§aThe schematic was checked successfully
+
+COMMAND_INVALID_NODE=§cInvalid Schematic
+COMMAND_NOT_OWN=§cYou can only use this command on your own Schematic
+COMMAND_MUST_DIR=§cYou can only use this command on a directory
+COMMAND_MUST_SCHEM=§cYou can only use this command on a Schematic
+COMMAND_ENTER_NAME=Insert name
+COMMAND_PUNISHMENT_NO_SAVE_EXTERNAL=§cYou can not make schematics on other build server
+COMMAND_PUNISHMENT_NO_SAVE=§cSchematics cannot be made on this build
+COMMAND_SAVE_NO_NAME=§cYou must also specify a name for the schematic after the folder
+COMMAND_SAVE_FOLDER=§cSchematic is a folder
+COMMAND_SAVE_NO_OVERWRITE=§cYou must not overwrite this Schematic
+COMMAND_SAVE_CLIPBOARD_EMPTY=§cYour clipboard is empty
+COMMAND_SAVE_ERROR=§cError while saving the Schematic
+COMMAND_SAVE_DONE=Schematic §e{0} §7stored
+COMMAND_SAVE_OVERWRITE=Schematic §e{0} §7overwritten
+COMMAND_SAVE_OVERWRITE_CONFIRM=§cThe Schematic §e{0} §calready exists. Do you want to overwrite it? §e*click*
+COMMAND_SAVE_OVERWRITE_CONFIRM_HOVER=§eOverwrite Schematic
+COMMAND_ADD_PUNISH=§cYou may not add anyone to your schematics: §f§l{0}
+COMMAND_ADD_USER_PUNISHED=§c{0} must not be added to schematics
+COMMAND_ADD_OWN=§cSo please: This is your own Schematic!
+COMMAND_ADD_PUBLIC=§cFor public requests please contact the moderator
+COMMAND_ADD_ALREADY=§c{0} is already added to this schematic
+COMMAND_ADD_ADDED=You now have access to the Schematic §e{0} §7of §e{1}
+COMMAND_ADD_NONE=§cNo player has been added
+COMMAND_ADD_ONE=§7The player §e{0} was added to the schematic
+COMMAND_ADD_MANY=§7The players §e{0} were added to the schematic
+COMMAND_DELMEM_DONE=The player §e{0} §7no longer has access to the Schematic §e{1}
+COMMAND_DELMEM_DELETED=§cYou now no longer have access to the Schematic §e{0} §7of §e{1}
+COMMAND_SEARCH_NOT_A_PLAYER=§cThe player §e{0} §cdoes not exists
+COMMAND_LOCKREPLAY=Replays of fights with {0} can no longer be viewed from now on
+COMMAND_REPLACE_COLOR_OFF=In fights {0} pink blocks are not replaced
+COMMAND_REPLACE_COLOR_ON=In fights {0} pink blocks are replaced
+COMMAND_DIR_DONE=§7Directory §e{0} §7created
+COMMAND_CHANGE_TYPE_SELECT=§eSelect type
+COMMAND_MOVE_RECURSIVE=§cThis only gives mistakes, trust me
+COMMAND_MOVE_DONE=§7The schematic can now be found under §e{0}
+COMMAND_RENAME_DONE=§7The schematic is now called §e{0}
+COMMAND_ADD_TEAM_NOT_IN_TEAM=§cYou are not in any team
+COMMAND_DEL_TEAM_NOT_IN_TEAM=§cYou are not in any team
+COMMAND_DEL_TEAM_NONE=§7No player was removed
+COMMAND_DEL_TEAM_DONE=§7The player §e{0} §7were removed from the Schematic
+COMMAND_CLEAR_MEMBER_DONE=§7All players were removed from the Schematic
+COMMAND_DEL_ALL_MEMBER=§e{0} §7has been removed from §e{1} §7Schematics
+COMMAND_PUBLIC_ON=§aYou are now the public user
+COMMAND_PUBLIC_OFF=§cYou are no longer the public user
+COMMAND_DELETE_NOT_OWN=§cThe schematic is not yours
+COMMAND_DELETE_MEMBER=§aYou have removed yourself from the Schematic
+COMMAND_DELETE_DIR=§aThe folder §e{0}§a is deleted...
+COMMAND_DELETE_DIR_FULL=§cThe folder must be empty to delete it
+COMMAND_DELETE_SCHEM=§aThe Schematic §e{0}§a is deleted...
+COMMAND_CHECK_SELECTION_INCOMPLETE=§cThe selection is incomplete
+COMMAND_CHECK_CLIPBOARD_EMPTY=§cThe clipboard is empty
+COMMAND_FIX_OK=§aThe schematic is already fixed
+COMMAND_FIX_DONE=§aThe schematic has been fixed
+COMMAND_FIX_COULD_NOT_FIX=§cCould not fix this in the schematic
+COMMAND_FIX_MANUAL=manually fix
+COMMAND_FIX_ERROR=§cError while fixing the schematic, please contact a developer
+COMMAND_FIX_WRONG_VERSION=§cThis feature is only available for version 1.15 and greater
+
+HELP_HEADER=§e§lSchematicSystem §8§lHelp
+HELP_VIEW=Find & Load
+HELP_VIEW_HOVER=Search or download schematics
+HELP_VIEW_1=§8/§7schem §einfo §8[§7schematic§8] - §7Shows information about the schematic
+HELP_VIEW_2=§8/§7schem §elist §8- §7Shows you your schematics
+HELP_VIEW_3=§8/§7schem §elist public §8- §7Shows all public schematics
+HELP_VIEW_4=§8/§7schem §esearch §8[§7keyword§8] - §7Searches for matching schematics
+HELP_VIEW_5=§8/§7schem §eload §8[§7schematic§8] - §7Loads a schematic
+HELP_VIEW_6=§8/§7schem §edownload §8[§7schematic§8] - §7Gives you a download link (valid for 1 min)
+HELP_VIEW_7=§8/§7download §8- §7Gives you a download link for your current clipboard (valid for 1 min)
+HELP_VIEW_8=§8/§7schem §echeck §8[§7schematic§8|§7selection§8|§7clipboard§8] [§7schematictype§8] - §7Checks the schematic for errors
+HELP_EDIT=Save & Edit
+HELP_EDIT_HOVER=Modification of schematics and folders
+HELP_EDIT_1=§8/§7schem §esave §8[§7schematic§8] - §7Saves your clipboard as a schematic
+HELP_EDIT_2=§8/§7schem §eordner §8[§7directory§8] - §7Create an empty folder
+HELP_EDIT_3=§8/§7schem §emove §8[§7schematic§8] [§7new path§8] - §7Move a schematic
+HELP_EDIT_4=§8/§7schem §erename §8[§7schematic§8] [§7new path§8] - §7Give the schematic a new name
+HELP_EDIT_5=§8/§7schem §echangetype §8[§7schematic§8] - §7Changes the type of your schematic
+HELP_EDIT_6=§8/§7schem §elockreplay §8[§7schematic§8] - §7Locks replays of the schematic
+HELP_EDIT_7=§8/§7schem §ereplacecolor §8[§7schematic§8] - §7Changes color substitution in the arena
+HELP_EDIT_8=§8/§7schem §edelete §8[§7schematic§8] - §7Deletes a schematic
+HELP_EDIT_9=§8/§7schem §efix §8[§7schematictype§8] - §7Tries to fix the schematic in your clipboard
+HELP_SHARE=Ownership
+HELP_SHARE_HOVER=Share Schematics with others
+HELP_SHARE_1=§8/§7schem §eaddmember §8[§7schematic§8] §8[§7Spieler§8] - §7Adds a player to a schematic
+HELP_SHARE_2=§8/§7schem §edelmember §8[§7schematic§8] §8[§7Spieler§8] - §7Removes a player from a schematic
+HELP_SHARE_3=§8/§7schem §eclearmember §8[§7schematic§8] - §7Removes all players from the schematic
+HELP_SHARE_4=§8/§7schem §edelallmember §8[§7player§8] - §7Removes a player from all your schematics
+HELP_SHARE_5=§8/§7schem §eaddteam §8[§7schematic§8] - §7Add everyone from your team to the schematic
+HELP_SHARE_6=§8/§7schem §edelteam §8[§7schematic§8] - §7Remove everyone from your team from the Schematic
+
+GUI_TITLE=Schematics \{1\}
+GUI_FOLDER_PROPERTIES=§7Directory properties
+GUI_INFO_LOAD=§eLoading
+GUI_INFO_BACK=§eBack
+GUI_INFO_STATUS=§eState {0}
+GUI_INFO_STATUS_LORE=§7{0}
+GUI_INFO_MAT=§e{0}
+GUI_INFO_TYPE=§e{0}
+GUI_INFO_DOWNLOAD=§eDownload
+GUI_INFO_COLOR=Color translation
+GUI_INFO_REPLAY=Replay playback
+GUI_INFO_REPLAY_OFF=§7§lTurn off
+GUI_INFO_REPLAY_TITLE=Lock playback permanently
+GUI_INFO_MEMBER=§eMembers
+GUI_INFO_MOVE=§eMove
+GUI_INFO_RENAME=§eRename
+GUI_INFO_RENAME_TITLE={0} rename
+GUI_INFO_DELETE=§cDelete
+GUI_INFO_MEMBER_FROM=§7Owner §e{0}
+GUI_INFO_MEMBER_REMOVE=§cRemove access
+GUI_CHANGE_TYPE=Change type
+GUI_CHANGE_TYPE_NOT_POSSIBLE=§cThe Schematic is too big
+GUI_CHANGE_TYPE_NOT_POSSIBLE_COLOR=§7{0}
+GUI_DELETE_OWN_DELETED=Schematic §e{0} §7deleted
+GUI_DELETE_OWN_TITLE=Delete {0}
+GUI_DELETE_MEMBER_TITLE=Remove {0}
+GUI_DELETE_MEMBER_DONE=Access to Schematic §e{0} §7removed
+GUI_DELETE_MEMBERS_TITLE=Remove members
+GUI_CHANGE_ITEM=Change item
+
+AUTO_CHECK_RESULT_NOT_LOAD=The schematic could not be loaded
+AUTO_CHECK_RESULT_TOO_WIDE=The schematic is too wide ({0} > {1})
+AUTO_CHECK_RESULT_TOO_LONG=The schematic is too long ({0} > {1})
+AUTO_CHECK_RESULT_TOO_HIGH=The schematic is too high ({0} > {1})
+AUTO_CHECK_RESULT_TOO_MANY_BLOCK=The block {0} was used {1} times too often
+AUTO_CHECK_RESULT_TOO_MANY_BLOCKS=The block combination {0} was used {1} times too often
+AUTO_CHECK_RESULT_TOO_MANY_ALL_BLOCKS=Too many blocks ({0} > {1})
+AUTO_CHECK_RESULT_TOO_MANY_RECORDS=No records allowed ({0} found)
+AUTO_CHECK_RESULT_FORBIDDEN_ITEM=In {0}s the forbidden item {1} {2} times was found
+AUTO_CHECK_RESULT_FORBIDDEN_ITEM_NBT=In {0}s the forbidden item {1} {2} times was found with custom tag
+AUTO_CHECK_RESULT_TOO_MANY_DISPENSER_ITEMS=One launcher contains more than {0} arrows and fireballs
+AUTO_CHECK_RESULT_TOO_MANY_DISPENSERS_ITEMS={0} launchers contains more than {1} arrows and fireballs
+AUTO_CHECK_RESULT_NBTS_WARNING={0} {1}s contain no or incorrect NBT data
+AUTO_CHECK_RESULT_NBT_WARNING=One {0} contains no or incorrect NBT data.
+
+SAFE_NODE_NOT_A_DIR=§cThe selected Schematic is not a folder
+SAFE_NODE_ALREADY_IN_DIRECTORY=§cThe schematic is already available in this folder
+SAFE_NODE_INVALID_NAME=§cThis name is illegal
+SAFE_NODE_NOT_OWNER=§cYou are not the owner of this schematic
+
+DOWNLOAD_ERROR=§cAn error occurred while uploading the schematic
+
+AUTO_CHECKER_RESULT_HEADER=§7---=== (§eAuto-Check: {0}§7) ===---
+AUTO_CHECKER_RESULT_WIDTH =§7Width: §c{0}§7, Max: §e{1}
+AUTO_CHECKER_RESULT_LENGTH=§7Length: §c{0}§7, Max: §e{1}
+AUTO_CHECKER_RESULT_HEIGHT=§7Height: §c{0}§7, Max: §e{1}
+AUTO_CHECKER_RESULT_BLOCKS=§7Blocks: §c{0}§7, Max: §e{1}
+AUTO_CHECKER_RESULT_UNKNOWN_MATERIAL=§7Unknown block: §c{0}
+AUTO_CHECKER_RESULT_TOO_MANY_BLOCK=§7{0}: §c{1}§7, Max: §e{2}
+AUTO_CHECKER_RESULT_FORBIDDEN_BLOCK=§7Forbidden block: §c{0}
+AUTO_CHECKER_RESULT_FORBIDDEN_ITEM=§7Forbidden Item: [{0}, {1}, {2}] -> §c{3}
+AUTO_CHECKER_RESULT_DEFUNCT_NBT=§7Defunct NBT: §7[{0}, {1}, {2}]
+AUTO_CHECKER_RESULT_DESIGN_BLOCK=§7{0} in Design: [{1}, {2}, {3}]
+AUTO_CHECKER_RESULT_ENTITY=§7Entity: §7[{0}, {1}, {2}]
+AUTO_CHECKER_RESULT_RECORD=§7Record: §c[{0}, {1}, {2}]
+AUTO_CHECKER_RESULT_TOO_MANY_DISPENSER_ITEMS=§7Dispenser: §c[{0}, {1}, {2}]§7, §c{3} §7items, Max: §e{4}
+AUTO_CHECKER_RESULT_FORBIDDEN_ITEM_NBT=§7Forbidden Item NBT: [{0}, {1}, {2}] -> §c{3}
+AUTO_CHECKER_RESULT_TELEPORT_HERE=§7Teleport to block
+AUTO_CHECKER_RESULT_AFTER_DEADLINE=§cThe deadline has expired: {0}
\ No newline at end of file
diff --git a/SchematicSystem/SchematicSystem_Core/src/SchematicSystem_de.properties b/SchematicSystem/SchematicSystem_Core/src/SchematicSystem_de.properties
new file mode 100644
index 00000000..cf370bcb
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/SchematicSystem_de.properties
@@ -0,0 +1,243 @@
+#
+# This file is a part of the SteamWar software.
+#
+# Copyright (C) 2023 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 .
+#
+
+ON=§aAn
+OFF=§cAus
+CHANGE=§7Zum Ändern
+CLICK=§7anklicken
+CLICK_DRAG_ITEM=§7anklicken oder hier Item hineinlegen
+CURRENT=§7Aktuell: {0}
+CONFIRM=§aBestätigen
+CANCEL=§cAbbrechen
+
+UTIL_NAME_REQUIRED=§cDeine Ordner brauchen schon einen Namen
+UTIL_NAME_TOO_LONG=§cDer Name der Schematic ist zu lang
+UTIL_NAME_INVALID_CHAR=§cDer angegebene Schematicname enthält verbotene Zeichen
+UTIL_NAME_FORBIDDEN=§cDer Pfad darf nicht \"§l{0}§c\" enthalten
+UTIL_LIST_PATH=§7Aktueller Pfad: §e{0}
+UTIL_LIST_BACK_HOVER=§eZurück gehen {0}
+UTIL_LIST_FROM=§8von §7{0}
+UTIL_LIST_OPEN_DIR=§eOrdner anzeigen
+UTIL_LIST_OPEN_SCHEM=§eSchematic verwalten
+UTIL_LIST_REMOVE=[Entfernen]
+UTIL_LIST_REMOVE_HOVER=§7Entferne dich von dem Ordner
+UTIL_LIST_BACK_ARROW_HOVER=§eVorherige Seite
+UTIL_LIST_NEXT=Seite ({0}/{1}) »»
+UTIL_LIST_NEXT_HOVER=§eNächste Seite
+UTIL_INFO_OWNER=§7Besitzer: §e{0}
+UTIL_INFO_PARENT=§7Ordner: §e{0}
+UTIL_INFO_UPDATED=§7Letzes Update: §e{0}
+UTIL_INFO_TYPE=§7Typ: §e{0}
+UTIL_INFO_RANK=§7Rang: §e{0}
+UTIL_INFO_COLOR=§7Farbersetzung: {0}
+UTIL_INFO_REPLAY=§7Replaywiedergabe: {0}
+UTIL_INFO_STATUS=§cStatus: §c{0}: {1}
+UTIL_INFO_MEMBER=§7Mitglieder: §e{0}
+UTIL_INFO_MEMBER_STRING=Mitglieder:
+UTIL_INFO_ACTION_LOAD=(Laden)
+UTIL_INFO_ACTION_LOAD_HOVER=§eSchematic laden
+UTIL_INFO_ACTION_DOWNLOAD_HOVER=§eSchematic downloaden
+UTIL_INFO_ACTION_TYPE_HOVER=§eSchematic Typ ändern
+UTIL_INFO_ACTION_ADD_HOVER=§eMember hinzufügen
+UTIL_INFO_ACTION_REMOVE_HOVER=§e{0} entfernen
+UTIL_INFO_ACTION_MOVE_HOVER=§eSchematic verschieben
+UTIL_INFO_ACTION_RENAME_HOVER=§eSchematic umbenennen
+UTIL_INFO_ACTION_DELETE=(Löschen)
+UTIL_INFO_ACTION_DELETE_HOVER=§eSchematic löschen
+UTIL_LOAD_NOT_HERE=§cDu kannst hier keine Schematics laden
+UTIL_LOAD_NOT_HERE_ALL=§cAuf diesem Bau können keine Schematics geladen werden
+UTIL_LOAD_DIR=§cDu kannst keine Ordner Laden
+UTIL_LOAD_DONE=§7Schematic §e{0} geladen
+UTIL_LOAD_NO_DATA=§cEs konnte keine Daten in der Schematic gefunden werden
+UTIL_LOAD_ERROR=§cDie Schematic konnte nicht geladen werden
+UTIL_DOWNLOAD_PUNISHED=§cDu darf keine Schematics Downloaden: §f§l{0}
+UTIL_DOWNLOAD_NOT_OWN=§cDu darfst nur deine eigenen Schematics herunterladen
+UTIL_DOWNLOAD_LINK=Dein Download Link:
+UTIL_TYPE_PUNISHED=§cDu darf keine Schematics einsenden: §f§l{0}
+UTIL_TYPE_NOT_OWN=§cDu kannst nur deine eigenen Schematics einsenden
+UTIL_TYPE_DIR=§cDu kannst keine Ordner einsenden
+UTIL_TYPE_NOT_ASSIGNABLE=§cZu diesem Typen können keine Schematics geändert werden
+UTIL_TYPE_ALREADY=§cDie Schematic hat schon diesen Typen
+UTIL_TYPE_DONE=§aSchematictyp geändert
+UTIL_TYPE_FIGHT_ALREADY=§cDu hast diese Schematic bereits eingesendet
+UTIL_TYPE_AFTER_DEADLINE=§cVon diesem Typen können keine Schematics mehr eingesendet werden. Einsendeschluss war: {0}
+UTIL_TYPE_ERROR=§cDie Schematic ist nicht regelkonform
+UTIL_TYPE_EXTEND=§aDer Vorbereitungsserver wird gestartet
+UTIL_SUBMIT_TITLE=Schematic ausfahren
+UTIL_SUBMIT_REPLAY_ON=§aReplay erlaubt
+UTIL_SUBMIT_REPLAY_OFF=§cReplay gesperrt
+UTIL_SUBMIT_COLOR_ON=§aPink zu Teamfarbe ersetzen
+UTIL_SUBMIT_COLOR_OFF=§cPink nicht ersetzen
+UTIL_SUBMIT_DIRECT=§eDirekt einsenden
+UTIL_SUBMIT_DIRECT_DONE=§aDie Schematic wird zeitnah überprüft
+UTIL_SUBMIT_EXTEND=§eSchematic ausfahren
+UTIL_SUBMIT_EXTEND_DONE=§aDer Vorbereitungsserver wird gestartet
+
+COMMAND_INVALID_NODE=§cDie Schematic konnte nicht gefunden werden
+COMMAND_NOT_OWN=§cDas darfst du nur bei deinen eigenen Schematics machen
+COMMAND_MUST_DIR=§cDu musst einen Ordner angeben
+COMMAND_MUST_SCHEM=§cDu musst eine Schematic angeben
+COMMAND_ENTER_NAME=Namen eingeben
+COMMAND_PUNISHMENT_NO_SAVE_EXTERNAL=§cDu kannst nicht auf anderen Baus Schematics machen
+COMMAND_PUNISHMENT_NO_SAVE=§cAuf diesem Bau können keine Schematics gemacht werden
+COMMAND_SAVE_NO_NAME=§cDu must auch einen Namen für die Schematic nach dem Ordner angeben
+COMMAND_SAVE_FOLDER=§cDie Schematic ist ein Ordner
+COMMAND_SAVE_NO_OVERWRITE=§cDu darfst diese Schematic nicht überschreiben
+COMMAND_SAVE_CLIPBOARD_EMPTY=§cDein Clipboard ist leer
+COMMAND_SAVE_ERROR=§cFehler beim Speichern der Schematic
+COMMAND_SAVE_DONE=Schematic §e{0} §7gespeichert
+COMMAND_SAVE_OVERWRITE=Schematic §e{0} §7überschrieben
+COMMAND_SAVE_OVERWRITE_CONFIRM=§cDie Schematic §e{0} §7existiert bereits. Möchtest du sie überschreiben? §e*klick*
+COMMAND_SAVE_OVERWRITE_CONFIRM_HOVER=§eSchematic überschreiben
+COMMAND_ADD_PUNISH=§cDu darfst niemanden auf deine Schematics hinzufügen: §f§l{0}
+COMMAND_ADD_USER_PUNISHED=§c{0} darf nicht auf Schematics hinzugefügt werden
+COMMAND_ADD_OWN=§cAlso bitte: Das ist deine eigene Schematic!
+COMMAND_ADD_PUBLIC=§cFür Public-Anträge bitte bei der Moderation melden
+COMMAND_ADD_ALREADY=§c{0} ist bereits auf diese Schematic geaddet
+COMMAND_ADD_ADDED=Du hast nun Zugriff auf die Schematic §e{0} §7von §e{1}
+COMMAND_ADD_NONE=§cEs wurde kein Spieler hinzugefügt
+COMMAND_ADD_ONE=§7Der Spieler §e{0} wurde auf die Schematic hinzugefügt
+COMMAND_ADD_MANY=§7Die Spieler §e{0} wurden auf die Schematic hinzugefügt
+COMMAND_DELMEM_DONE=Der Spieler §e{0} §7hat nun keinen Zugriff mehr auf die Schematic §e{1}
+COMMAND_DELMEM_DELETED=§cDu hast nun keinen Zugriff mehr auf die Schematic §e{0} §7von §e{1}
+COMMAND_SEARCH_NOT_A_PLAYER=§cDer Spieler §e{0} §cexistiert nicht
+COMMAND_LOCKREPLAY=Replays von Kämpfen mit {0} können ab sofort nicht mehr betrachtet werden
+COMMAND_REPLACE_COLOR_OFF=In Kämpfen {0} werden pinke Blöcke nicht ersetzt
+COMMAND_REPLACE_COLOR_ON=In Kämpfen {0} werden pinke Blöcke ersetzt
+COMMAND_DIR_DONE=§7Ordner §e{0} §7erstellt
+COMMAND_CHANGE_TYPE_SELECT=§eTyp auswählen
+COMMAND_MOVE_RECURSIVE=§cDas gibt nur Fehler, vertrau mir
+COMMAND_MOVE_DONE=§7Die Schematic ist nun unter §e{0} §7zu finden
+COMMAND_RENAME_DONE=§7Die Schematic heißt nun §e{0}
+COMMAND_ADD_TEAM_NOT_IN_TEAM=§cDu bist in keinem Team
+COMMAND_DEL_TEAM_NOT_IN_TEAM=§cDu bist in keinem Team
+COMMAND_DEL_TEAM_NONE=§7Es wurde kein Spieler entfernt
+COMMAND_DEL_TEAM_DONE=§7Der Spieler §e{0} §7wurden von der Schematic entfernt
+COMMAND_CLEAR_MEMBER_DONE=§7Alle Spieler wurden von der Schematic entfernt
+COMMAND_DEL_ALL_MEMBER=§e{0} §7wurde von §e{1} §7Schematics entfernt
+COMMAND_PUBLIC_ON=§aDu bist nun der Public User
+COMMAND_PUBLIC_OFF=§cDu bist nun nicht mehr der Public User
+COMMAND_DELETE_NOT_OWN=§cDie Schematic gehört dir nicht
+COMMAND_DELETE_MEMBER=§aDu hast dich von der Schematic entfernt
+COMMAND_DELETE_DIR=§aDer Ordner §e{0}§a wird gelöscht...
+COMMAND_DELETE_DIR_FULL=§cDer Ordner muss leer sein, um ihn zu löschen
+COMMAND_DELETE_SCHEM=§aDie Schematic §e{0}§a wird gelöscht...
+COMMAND_CHECK_SELECTION_INCOMPLETE=§cDeine Auswahl ist unvollständig
+COMMAND_CHECK_CLIPBOARD_EMPTY=§cDein Clipboard ist leer
+COMMAND_FIX_OK=§aDie Schematic ist bereits gefixt
+COMMAND_FIX_DONE=§aDie Schematic wurde repariert
+COMMAND_FIX_COULD_NOT_FIX=§cKonnte diese nicht sachen in der Schematic reparieren
+COMMAND_FIX_MANUAL=Manuel Fixen
+COMMAND_FIX_ERROR=§cFehler beim Fixen der Schematic, bitte kontaktiere einen Developer
+COMMAND_FIX_WRONG_VERSION=§cDiese Funktion ist nur für Version 1.15 und höher verfügbar
+
+HELP_HEADER=§e§lSchematicSystem §8§lHilfe
+HELP_VIEW=Finden & Laden
+HELP_VIEW_HOVER=Suche oder lade Schematics
+HELP_VIEW_1=§8/§7schem §einfo §8[§7Schematic§8] - §7Zeigt dir Informationen zur Schematic
+HELP_VIEW_2=§8/§7schem §elist §8- §7Zeigt dir deine Schematics an
+HELP_VIEW_3=§8/§7schem §elist public §8- §7Zeigt alle Public-Schematics
+HELP_VIEW_4=§8/§7schem §esearch §8[§7Stichwort§8] - §7Sucht nach passenden Schematics
+HELP_VIEW_5=§8/§7schem §eload §8[§7Schematic§8] - §7Lädt eine Schematic
+HELP_VIEW_6=§8/§7schem §edownload §8[§7Schematic§8] - §7Gibt dir einen Downloadlink (1 min gültig)
+HELP_VIEW_7=§8/§7download §8- §7Gibt dir einen Downloadlink von deinem Clipboard (1 min gültig)
+HELP_VIEW_8=§8/§7schem §echeck §8[§7Schematic§8|§7selection§8|§7clipboard§8] [§7SchematicTyp§8] - §7Überprüft deine Schematic
+HELP_EDIT=Speichern & Bearbeiten
+HELP_EDIT_HOVER=Modifizierung von Schematics und Ordnern
+HELP_EDIT_1=§8/§7schem §esave §8[§7Schematic§8] - §7Speichert dein Clipboard als Schematic
+HELP_EDIT_2=§8/§7schem §eordner §8[§7Ordner§8] - §7Erstelle einen leeren Ordner
+HELP_EDIT_3=§8/§7schem §emove §8[§7Schematic§8] [§7Neuer Pfad§8] - §7Verschiebe eine Schematic
+HELP_EDIT_4=§8/§7schem §erename §8[§7Schematic§8] [§7Neuer Name§8] - §7Gib der Schematic einen neuen Namen
+HELP_EDIT_5=§8/§7schem §echangetype §8[§7Schematic§8] - §7Ändert die Art deiner Schematic
+HELP_EDIT_6=§8/§7schem §elockreplay §8[§7Schematic§8] - §7Sperrt Replays mit der Schematic
+HELP_EDIT_7=§8/§7schem §ereplacecolor §8[§7Schematic§8] - §7Ändert Farbersetzung in der Arena
+HELP_EDIT_8=§8/§7schem §edelete §8[§7Schematic§8] - §7Löscht eine Schematic
+HELP_EDIT_9=§8/§7schem §efix §8[§7SchematicTyp§8] - §7Versucht die Schematic in deinem Clipboard konform zu machen
+HELP_SHARE=Besitzrechte
+HELP_SHARE_HOVER=Schematics mit anderen teilen
+HELP_SHARE_1=§8/§7schem §eaddmember §8[§7Schematic§8] §8[§7Spieler§8] - §7Fügt einen Spieler zu einer Schematic hinzu
+HELP_SHARE_2=§8/§7schem §edelmember §8[§7Schematic§8] §8[§7Spieler§8] - §7Entfernt einen Spieler von einer Schematic
+HELP_SHARE_3=§8/§7schem §eclearmember §8[§7Schematic§8] - §7Entfernt alle Spieler von der Schematic
+HELP_SHARE_4=§8/§7schem §edelallmember §8[§7Spieler§8] - §7Entfernt einen Spieler von allen deinen Schematics
+HELP_SHARE_5=§8/§7schem §eaddteam §8[§7Schematic§8] - §7Füge jeden aus deinem Team auf die Schematic hinzu
+HELP_SHARE_6=§8/§7schem §edelteam §8[§7Schematic§8] - §7Entferne jeden aus deinem Team von der Schematic
+
+GUI_TITLE=Schematics \{1\}
+GUI_FOLDER_PROPERTIES=§7Ordnereigenschaften
+GUI_INFO_LOAD=§eLaden
+GUI_INFO_BACK=§eZurück
+GUI_INFO_STATUS=§eStatus {0}
+GUI_INFO_COLOR=Farbersetzung
+GUI_INFO_REPLAY=Replay Wiedergabe
+GUI_INFO_REPLAY_OFF=§7Zum §lAusschalten
+GUI_INFO_REPLAY_TITLE=Wiedergabe dauerhaft sperren
+GUI_INFO_MEMBER=§eMitglieder
+GUI_INFO_MOVE=§eVerschieben
+GUI_INFO_RENAME=§eUmbenennen
+GUI_INFO_RENAME_TITLE={0} umbenennen
+GUI_INFO_DELETE=§cLöschen
+GUI_INFO_MEMBER_FROM=§7von §e{0}
+GUI_INFO_MEMBER_REMOVE=§cZugriff entfernen
+GUI_CHANGE_TYPE=Typ ändern
+GUI_CHANGE_TYPE_NOT_POSSIBLE=§cDie Schematic ist zu groß
+GUI_DELETE_OWN_DELETED=Schematic §e{0} §7gelöscht
+GUI_DELETE_OWN_TITLE={0} löschen
+GUI_DELETE_MEMBER_TITLE={0} entfernen
+GUI_DELETE_MEMBER_DONE=Zugriff zu Schematic §e{0} §7entfernt
+GUI_DELETE_MEMBERS_TITLE=Mitglieder entfernen
+GUI_CHANGE_ITEM=Item ändern
+
+AUTO_CHECK_RESULT_NOT_LOAD=Die Schematic konnte nicht geladen werden
+AUTO_CHECK_RESULT_TOO_WIDE=Die Schematic ist zu breit ({0} > {1})
+AUTO_CHECK_RESULT_TOO_LONG=Die Schematic ist zu lang ({0} > {1})
+AUTO_CHECK_RESULT_TOO_HIGH=Die Schematic ist zu hoch ({0} > {1})
+AUTO_CHECK_RESULT_TOO_MANY_BLOCK=Der Block {0} wurde {1} mal zu häufig verbaut
+AUTO_CHECK_RESULT_TOO_MANY_BLOCKS=Die Blockkombination {0} wurde {1} mal zu häufig verbaut
+AUTO_CHECK_RESULT_TOO_MANY_ALL_BLOCKS=Zu viele Blöcke ({0} > {1})
+AUTO_CHECK_RESULT_TOO_MANY_RECORDS=Keine Schallplatten erlaubt ({0} gefunden)
+AUTO_CHECK_RESULT_FORBIDDEN_ITEM=In {0}s wurde das verbotene Item {1} {2} mal gefunden
+AUTO_CHECK_RESULT_FORBIDDEN_ITEM_NBT=In {0}s wurde das verbotene Item {1} {2} mal mit Custom-Tag gefunden
+AUTO_CHECK_RESULT_TOO_MANY_DISPENSER_ITEMS=Ein Werfer enthält mehr als {0} Pfeile und Feuerbälle
+AUTO_CHECK_RESULT_TOO_MANY_DISPENSERS_ITEMS={0} Werfer enthält mehr als {1} Pfeile und Feuerbälle
+AUTO_CHECK_RESULT_NBTS_WARNING={0} {1}s enthalten keine oder inkorrekte NBT-Daten
+AUTO_CHECK_RESULT_NBT_WARNING=Ein(e) {0} enthält keine oder inkorrekte NBT-Daten
+
+SAFE_NODE_NOT_A_DIR=§cDie ausgewählte Schematic ist kein Ordner
+SAFE_NODE_ALREADY_IN_DIRECTORY=§cDie Schematic gibt es bereits in diesem Ordner
+SAFE_NODE_INVALID_NAME=§cDieser Name ist unzulässig
+SAFE_NODE_NOT_OWNER=§cDu bist nicht der Besitzer dieser Schematic
+
+DOWNLOAD_ERROR=§cFehler beim Hochladen deines Clipboards
+
+AUTO_CHECKER_RESULT_HEADER=§7---=== (§eAutoPrüfer: {0}§7) ===---
+AUTO_CHECKER_RESULT_WIDTH=§7Breite: §c{0}§7, Max: §e{1}
+AUTO_CHECKER_RESULT_LENGTH=§7Länge: §c{0}§7, Max: §e{1}
+AUTO_CHECKER_RESULT_HEIGHT=§7Höhe: §c{0}§7, Max: §e{1}
+AUTO_CHECKER_RESULT_BLOCKS=§7Blöcke: §c{0}§7, Max: §e{1}
+AUTO_CHECKER_RESULT_UNKNOWN_MATERIAL=§7Unbekannter Block: §c{0}
+AUTO_CHECKER_RESULT_TOO_MANY_BLOCK=§7{0}: §c{1}§7, Max: §e{2}
+AUTO_CHECKER_RESULT_FORBIDDEN_BLOCK=§7Verbotener Block: §c{0}
+AUTO_CHECKER_RESULT_FORBIDDEN_ITEM=§7Verbotener gegenstand: [{0}, {1}, {2}] -> §c{3}
+AUTO_CHECKER_RESULT_DEFUNCT_NBT=§7Keine NBT-Daten: §c[{0}, {1}, {2}]
+AUTO_CHECKER_RESULT_DESIGN_BLOCK=§7{0} im Design: [{1}, {2}, {3}]
+AUTO_CHECKER_RESULT_RECORD=§7Schallplatte: §c[{0}, {1}, {2}]
+AUTO_CHECKER_RESULT_TOO_MANY_DISPENSER_ITEMS=§7Dispenser: §c[{0}, {1}, {2}]§7, §c{3} §7gegenstände, Max: §e{4}
+AUTO_CHECKER_RESULT_FORBIDDEN_ITEM_NBT=§7Verbotene NBT-Daten: [{0}, {1}, {2}] -> §c{3}
+AUTO_CHECKER_RESULT_TELEPORT_HERE=§7Zum block teleportieren
+AUTO_CHECKER_RESULT_AFTER_DEADLINE=§cDer einsendeschluss ist bereits vorbei: {0}
\ No newline at end of file
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/CheckSchemType.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/CheckSchemType.java
new file mode 100644
index 00000000..fead2a47
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/CheckSchemType.java
@@ -0,0 +1,113 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2020 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;
+
+import de.steamwar.sql.SchematicType;
+import lombok.Getter;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import java.io.File;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.util.*;
+
+@Getter
+public class CheckSchemType {
+
+ private static final Map types = new HashMap<>();
+
+ private final int width;
+ private final int height;
+ private final int depth;
+ private final int maxDispenserItems;
+
+ private final Map, Integer> limits;
+ private final int maxBlocks;
+
+ private final Date deadline;
+ private final float maxBlastResistance;
+
+ private CheckSchemType(ConfigurationSection section) {
+ String name = section.getString("Schematic.Type");
+ width = section.getInt("Schematic.Size.x");
+ height = section.getInt("Schematic.Size.y");
+ depth = section.getInt("Schematic.Size.z");
+
+ maxDispenserItems = section.getInt("Schematic.MaxDispenserItems", 128);
+ maxBlocks = section.getInt("Schematic.MaxBlocks", 0);
+
+ maxBlastResistance = (float) section.getDouble("Schematic.MaxDesignBlastResistance", Double.MAX_VALUE);
+
+ limits = new HashMap<>();
+ for(Map, ?> entry : section.getMapList("Schematic.Limited")) {
+ int amount = (Integer) entry.get("Amount");
+ Set materials = new HashSet<>((List) entry.get("Materials"));
+ if(amount == 0) {
+ materials.forEach(material -> limits.put(Collections.singleton(material), 0));
+ } else {
+ limits.put(materials, amount);
+ }
+ }
+
+ String deadlineString = section.getString("deadline", null);
+ if (deadlineString != null) {
+ try {
+ SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm");
+ deadline = dateFormat.parse(deadlineString);
+ } catch (ParseException e) {
+ throw new SecurityException(e.getMessage(), e);
+ }
+ } else {
+ deadline = null;
+ }
+
+ types.put(SchematicType.fromDB(name.toLowerCase()), this);
+ types.put(SchematicType.fromDB("c" + name.toLowerCase()), this);
+ }
+
+ static {
+ File folder = new File(SchematicSystem.getInstance().getDataFolder().getParentFile(), "FightSystem");
+
+ if(folder.exists()) {
+ for(File configFile : folder.listFiles((file, name) -> name.endsWith(".yml") && !name.endsWith(".kits.yml"))) {
+ YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
+ if (!config.isList("CheckQuestions") && config.getBoolean("Schematic.ManualCheck", true))
+ continue;
+
+ new CheckSchemType(config);
+ }
+ }
+ }
+
+ public static CheckSchemType get(SchematicType type){
+ return types.get(type);
+ }
+
+ public Map, Integer> getLimits() {
+ return new HashMap<>(limits);
+ }
+
+ public boolean isAfterDeadline() {
+ return deadline != null && deadline.before(Date.from(Instant.now()));
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/SafeSchematicNode.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/SafeSchematicNode.java
new file mode 100644
index 00000000..449d59d8
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/SafeSchematicNode.java
@@ -0,0 +1,89 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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;
+
+import de.steamwar.sql.SchematicNode;
+import de.steamwar.sql.SteamwarUser;
+import lombok.AllArgsConstructor;
+import lombok.NonNull;
+import org.bukkit.entity.Player;
+
+public class SafeSchematicNode {
+
+ public static Result setParent(@NonNull SteamwarUser user, @NonNull SchematicNode node, SchematicNode newParent) {
+ if(user.getId() != node.getOwner()) {
+ return Result.NOT_OWNER;
+ }
+ if(newParent == null) {
+ if(SchematicNode.list(user, null)
+ .stream().map(SchematicNode::getName).anyMatch(s -> s.equalsIgnoreCase(node.getName()))) {
+ return Result.ALREADY_IN_DIRECTORY;
+ }
+
+ node.setParent(null);
+ } else {
+ if(!newParent.isDir()) {
+ return Result.NOT_A_DIR;
+ }
+
+ if(SchematicNode.list(user, newParent.getId())
+ .stream().map(SchematicNode::getName).anyMatch(s -> s.equalsIgnoreCase(node.getName()))) {
+ return Result.ALREADY_IN_DIRECTORY;
+ }
+
+ node.setParent(newParent.getId());
+ }
+ return Result.DONE;
+ }
+
+ public static Result setName(@NonNull SteamwarUser user, @NonNull SchematicNode node, @NonNull String name) {
+ if(user.getId() != node.getOwner()) {
+ return Result.NOT_OWNER;
+ }
+
+ if(SchematicNode.invalidSchemName(new String[]{name})) {
+ return Result.INVALID_NAME;
+ }
+
+ if(SchematicNode.list(user, node.getParent()).stream().map(SchematicNode::getName).anyMatch(s -> s.equalsIgnoreCase(name))) {
+ return Result.ALREADY_IN_DIRECTORY;
+ }
+
+ node.setName(name);
+ return Result.DONE;
+ }
+
+ @AllArgsConstructor
+ public enum Result {
+ DONE,
+ NOT_A_DIR,
+ ALREADY_IN_DIRECTORY,
+ INVALID_NAME,
+ NOT_OWNER;
+
+ public void sendError(Player player) {
+ SchematicSystem.MESSAGE.send("SAFE_NODE_" + this.name(), player);
+ }
+
+ public boolean isSuccessful() {
+ return this == DONE;
+ }
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/SchematicSystem.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/SchematicSystem.java
new file mode 100644
index 00000000..d6b94807
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/SchematicSystem.java
@@ -0,0 +1,48 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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;
+
+import de.steamwar.message.Message;
+import de.steamwar.schematicsystem.commands.DownloadCommand;
+import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommand;
+import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandInitializer;
+import de.steamwar.schematicsystem.listener.PlayerEventListener;
+import org.bukkit.Bukkit;
+import org.bukkit.plugin.java.JavaPlugin;
+
+public class SchematicSystem extends JavaPlugin {
+ public static final Message MESSAGE = new Message("SchematicSystem", SchematicSystem.class.getClassLoader());
+
+ private static SchematicSystem instance;
+
+ @Override
+ public void onEnable() {
+ instance = this;
+
+ SchematicCommandInitializer.init();
+ new DownloadCommand();
+
+ Bukkit.getPluginManager().registerEvents(new PlayerEventListener(), this);
+ }
+
+ public static SchematicSystem getInstance() {
+ return instance;
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/autocheck/AutoChecker.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/autocheck/AutoChecker.java
new file mode 100644
index 00000000..ef4d9bea
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/autocheck/AutoChecker.java
@@ -0,0 +1,60 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.worldedit.extent.clipboard.Clipboard;
+import de.steamwar.core.VersionDependent;
+import de.steamwar.schematicsystem.CheckSchemType;
+import de.steamwar.schematicsystem.SchematicSystem;
+import lombok.Getter;
+import lombok.ToString;
+import org.bukkit.Material;
+
+import java.util.*;
+
+public class AutoChecker {
+
+ public static AutoCheckerResult check(Clipboard clipboard, CheckSchemType type) {
+ return impl.check(clipboard, type);
+ }
+
+ public static AutoCheckerResult sizeCheck(Clipboard clipboard, CheckSchemType type) {
+ return impl.sizeCheck(clipboard, type);
+ }
+
+ private static final IAutoChecker impl = VersionDependent.getVersionImpl(SchematicSystem.getInstance());
+
+ public interface IAutoChecker {
+ AutoCheckerResult check(Clipboard clipboard, CheckSchemType type);
+ AutoCheckerResult sizeCheck(Clipboard clipboard, CheckSchemType type);
+ }
+
+ @Getter
+ @ToString
+ public static class BlockScanResult {
+ private final Map blockCounts = new EnumMap<>(Material.class);
+ private final List defunctNbt = new ArrayList<>();
+ private final List records = new ArrayList<>();
+ private final Map> designBlocks = new EnumMap<>(Material.class);
+ private final Map dispenserItems = new HashMap<>();
+ private final Map> forbiddenItems = new HashMap<>();
+ private final Map> forbiddenNbt = new HashMap<>();
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/autocheck/AutoCheckerResult.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/autocheck/AutoCheckerResult.java
new file mode 100644
index 00000000..6a708bdf
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/autocheck/AutoCheckerResult.java
@@ -0,0 +1,168 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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 de.steamwar.schematicsystem.CheckSchemType;
+import de.steamwar.schematicsystem.SchematicSystem;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.ToString;
+import net.md_5.bungee.api.chat.ClickEvent;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+
+import java.util.*;
+
+@Builder
+@Getter
+@ToString
+public class AutoCheckerResult {
+ private final CheckSchemType type;
+ private final int width;
+ private final int height;
+ private final int depth;
+ private final AutoChecker.BlockScanResult blockScanResult;
+ private final List entities;
+
+ public boolean isOk() {
+ return blockScanResult.getRecords().isEmpty() &&
+ blockScanResult.getForbiddenItems().isEmpty() &&
+ blockScanResult.getForbiddenNbt().isEmpty() &&
+ isSizeOk() &&
+ isBlockCountOk() &&
+ isLimitedBlocksOK() &&
+ isDispenserItemsOK() &&
+ !type.isAfterDeadline() &&
+ entities.isEmpty() &&
+ isDesignBlastResistanceOK();
+ }
+
+ public boolean fastOk() {
+ return isSizeOk() &&
+ !type.isAfterDeadline();
+ }
+
+ public boolean isDispenserItemsOK() {
+ return blockScanResult.getDispenserItems().values().stream().allMatch(i -> i <= type.getMaxDispenserItems());
+ }
+
+ public boolean hasWarnings() {
+ return blockScanResult.getDefunctNbt().isEmpty();
+ }
+
+ public boolean isSizeOk() {
+ return !isTooWide() && !isTooHigh() && !isTooDeep();
+ }
+
+ public boolean isTooWide() {
+ return width > type.getWidth();
+ }
+
+ public boolean isTooHigh() {
+ return height > type.getHeight();
+ }
+
+ public boolean isTooDeep() {
+ return depth > type.getDepth();
+ }
+
+ public boolean isBlockCountOk() {
+ return type.getMaxBlocks() == 0 || blockScanResult.getBlockCounts().entrySet().stream().filter(entry -> entry.getKey() != Material.AIR).map(Map.Entry::getValue).reduce(Integer::sum).map(i -> i <= type.getMaxBlocks()).orElse(false);
+ }
+
+ public boolean isLimitedBlocksOK() {
+ try {
+ return type.getLimits().entrySet().stream()
+ .map(setIntegerEntry -> setIntegerEntry.getKey().stream().map(Material::getMaterial).map(blockScanResult.getBlockCounts()::get).map(i -> i == null || i <= setIntegerEntry.getValue()).reduce(Boolean::logicalAnd).orElse(false))
+ .reduce(Boolean::logicalAnd).orElse(true);
+ } catch (NullPointerException e) {
+ return false;
+ }
+ }
+
+ public boolean isDesignBlastResistanceOK() {
+ return blockScanResult.getDesignBlocks().keySet().stream().map(Material::getBlastResistance).noneMatch(i -> i > type.getMaxBlastResistance());
+ }
+
+ public void sendErrorMessage(Player p, String schemName) {
+ SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_HEADER", p, schemName);
+ if(isTooWide()) SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_WIDTH", p, width, type.getWidth());
+ if(isTooHigh()) SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_HEIGHT", p, height, type.getHeight());
+ if(isTooDeep()) SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_LENGTH", p, depth, type.getDepth());
+ if(type.getMaxBlocks() != 0 && !isBlockCountOk()) {
+ SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_BLOCKS", p, blockScanResult.getBlockCounts().values().stream().reduce(Integer::sum).orElse(0), type.getMaxBlocks());
+ }
+ if(!isLimitedBlocksOK()) {
+ type.getLimits().forEach((strings, integer) -> {
+ for (String string : strings) {
+ Material mat = Material.matchMaterial(string);
+ if(mat != null && blockScanResult.getBlockCounts().getOrDefault(mat, 0) > integer) {
+ if(integer == 0) {
+ SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_FORBIDDEN_BLOCK", p, mat.name());
+ } else {
+ SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_TOO_MANY_BLOCK", p, mat.name(), blockScanResult.getBlockCounts().getOrDefault(mat, 0), integer);
+ }
+ }
+ }
+ });
+ }
+ blockScanResult.getDispenserItems().entrySet().stream().filter(blockVector3IntegerEntry -> blockVector3IntegerEntry.getValue() > type.getMaxDispenserItems()).forEach(blockVector3IntegerEntry -> {
+ SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_TOO_MANY_DISPENSER_ITEMS", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(blockVector3IntegerEntry.getKey()),
+ blockVector3IntegerEntry.getKey().getBlockX(),
+ blockVector3IntegerEntry.getKey().getBlockY(),
+ blockVector3IntegerEntry.getKey().getBlockZ(),
+ blockVector3IntegerEntry.getValue(),
+ type.getMaxDispenserItems());
+ });
+ blockScanResult.getRecords().forEach(blockVector3 -> {
+ SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_RECORD", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(blockVector3), blockVector3.getBlockX(), blockVector3.getBlockY(), blockVector3.getBlockZ());
+ });
+ blockScanResult.getForbiddenItems().forEach((blockVector3, materials) -> {
+ SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_FORBIDDEN_ITEM", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(blockVector3), blockVector3.getX(), blockVector3.getY(), blockVector3.getZ(), setToString(materials));
+ });
+ blockScanResult.getForbiddenNbt().forEach((blockVector3, materials) -> {
+ SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_FORBIDDEN_ITEM_NBT", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(blockVector3), blockVector3.getX(), blockVector3.getY(), blockVector3.getZ(), setToString(materials));
+ });
+ blockScanResult.getDefunctNbt().forEach(blockVector3 -> {
+ SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_DEFUNCT_NBT", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(blockVector3), blockVector3.getX(), blockVector3.getY(), blockVector3.getZ());
+ });
+ blockScanResult.getDesignBlocks().forEach((material, poss) -> {
+ if(material.getBlastResistance() > type.getMaxBlastResistance()) {
+ poss.forEach(pos -> {
+ SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_DESIGN_BLOCK", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(pos), material.name(), pos.getBlockX(), pos.getBlockY(), pos.getBlockZ());
+ });
+ }
+ });
+ entities.forEach(blockPos -> {
+ SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_ENTITY", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(blockPos), blockPos.getX(), blockPos.getY(), blockPos.getZ());
+ });
+ if(type.isAfterDeadline()) {
+ SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_AFTER_DEADLINE", p, type.getDeadline());
+ }
+ }
+
+ private static ClickEvent tpCommandTo(BlockPos pos) {
+ return new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tp " + pos.getBlockX() + " " + pos.getBlockY() + " " + pos.getBlockZ());
+ }
+
+ private static String setToString(Collection set) {
+ return set.stream().map(material -> material.getKey().getKey()).reduce((s, s2) -> s + "§7, §c" + s2).orElse("");
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/autocheck/BlockPos.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/autocheck/BlockPos.java
new file mode 100644
index 00000000..7dff0dbe
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/autocheck/BlockPos.java
@@ -0,0 +1,50 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2022 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 lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+/*
+ * Can be removed with 1.12 support removal
+ */
+@Getter
+@AllArgsConstructor
+@ToString
+@EqualsAndHashCode
+public class BlockPos {
+ private int x;
+ private int y;
+ private int z;
+
+ public int getBlockX() {
+ return x;
+ }
+
+ public int getBlockY() {
+ return y;
+ }
+
+ public int getBlockZ() {
+ return z;
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/DownloadCommand.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/DownloadCommand.java
new file mode 100644
index 00000000..ff797b67
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/DownloadCommand.java
@@ -0,0 +1,63 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.commands;
+
+import de.steamwar.command.SWCommand;
+import de.steamwar.schematicsystem.SchematicSystem;
+import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils;
+import de.steamwar.sql.*;
+import org.bukkit.entity.Player;
+
+import java.io.IOException;
+
+public class DownloadCommand extends SWCommand {
+ public DownloadCommand() {
+ super("download", "/download");
+ }
+
+ @Register(help = true)
+ public void genericCommand(Player player, String... args) {
+ SteamwarUser user = SteamwarUser.get(player.getUniqueId());
+ SchematicNode copyNode = SchematicNode.getSchematicNode(user.getId(), "//copy", 0);
+ boolean newSchem = false;
+ if(copyNode == null) {
+ copyNode = SchematicNode.createSchematicNode(user.getId(), "//copy", 0, SchematicType.Normal.toDB(), "");
+ newSchem = true;
+ }
+
+ try {
+ new SchematicData(copyNode).saveFromPlayer(player);
+ } catch (IOException e) {
+ SchematicSystem.MESSAGE.send("DOWNLOAD_ERROR", player);
+ if(newSchem) {
+ copyNode.delete();
+ }
+ throw new SecurityException(e);
+ } catch (NoClipboardException e) {
+ SchematicSystem.MESSAGE.send("COMMAND_SAVE_CLIPBOARD_EMPTY", player);
+ if(newSchem) {
+ copyNode.delete();
+ }
+ return;
+ }
+
+ SchematicCommandUtils.download(player, copyNode);
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/GUI.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/GUI.java
new file mode 100644
index 00000000..cd953ed7
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/GUI.java
@@ -0,0 +1,321 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.commands.schematiccommand;
+
+import com.sk89q.worldedit.extent.clipboard.Clipboard;
+import de.steamwar.core.Core;
+import de.steamwar.inventory.*;
+import de.steamwar.schematicsystem.CheckSchemType;
+import de.steamwar.schematicsystem.SafeSchematicNode;
+import de.steamwar.schematicsystem.SchematicSystem;
+import de.steamwar.schematicsystem.autocheck.AutoChecker;
+import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils;
+import de.steamwar.sql.*;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.inventory.ClickType;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+
+import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.*;
+
+public class GUI {
+ private GUI() {}
+
+ public static void list(Player player) {
+ SchematicSelector selector = new SchematicSelector(player, SchematicSelector.selectSchematic(), new SchematicSelectorInjectable() {
+ @Override
+ public String createTitle(Player player) {
+ return SchematicSystem.MESSAGE.parse("GUI_TITLE", player);
+ }
+
+ @Override
+ public void onListRender(SchematicSelector selector, SWListInv inv, SchematicNode parent) {
+ inv.setCallback(-999, (ClickType click) -> {
+ if(parent == null) {
+ player.closeInventory();
+ } else {
+ selector.reOpenDirUp();
+ }
+ });
+ if(parent == null) {
+ inv.setItem(49, Material.AIR, "", clickType -> {});
+ } else {
+ inv.setItem(49, Material.ANVIL, SchematicSystem.MESSAGE.parse("GUI_FOLDER_PROPERTIES", player), clickType -> {
+ info(selector.getPlayer(), parent, selector);
+ });
+ }
+ }
+
+ @Override
+ public AnvilInvCloseAction onAnvilInvCloseAction(SchematicSelector selector) {
+ return AnvilInvCloseAction.REOPEN;
+ }
+ }, node -> {});
+ selector.setCallback(node -> info(player, node, selector));
+ selector.setSingleDirOpen(false);
+ selector.open();
+ }
+
+ private static void setCloseLeftCallback(SWAnvilInv inv, Runnable action) {
+ AtomicBoolean left = new AtomicBoolean(false);
+ inv.addCloseCallback(() -> {
+ if(!left.get()) {
+ Bukkit.getScheduler().runTaskLater(SchematicSystem.getInstance(), action, 1);
+ }
+ });
+ inv.addLeftCallback(() -> {
+ left.set(true);
+ action.run();
+ });
+ }
+
+ private static void info(Player player, SchematicNode node, SchematicSelector back) {
+ SteamwarUser user = getUser(player);
+ SWInventory inv = new SWInventory(player, 9 * 2, node.generateBreadcrumbs());
+ if(!node.isDir()) {
+ inv.setItem(0, SWItem.getMaterial("WOOD_AXE"), SchematicSystem.MESSAGE.parse("GUI_INFO_LOAD", player), click -> {
+ player.closeInventory();
+ SchematicCommandUtils.loadSchem(player, node);
+ });
+ }
+
+ inv.setItem(9, SWItem.getMaterial("LEASH"), SchematicSystem.MESSAGE.parse("GUI_INFO_BACK", player), clickType -> {
+ back.reOpen();
+ });
+
+ if(node.getOwner() == user.getId()){
+ if(!node.isDir() && node.getSchemtype().writeable()){
+ CheckedSchematic.getLastDeclinedOfNode(node.getId()).stream().findFirst().ifPresent(checkedSchematic ->
+ inv.setItem(1, SWItem.getDye(10), (byte) 10, SchematicSystem.MESSAGE.parse("GUI_INFO_STATUS", player, node.getSchemtype().name()), Collections.singletonList(SchematicSystem.MESSAGE.parse("GUI_INFO_STATUS_LORE", player, checkedSchematic.getDeclineReason().replaceAll("&", "§"))), false, click -> {}));
+ }
+ Material mat = SWItem.getMaterial(node.getItem());
+
+ inv.setItemEvent(node.isDir()?7:5, mat, SchematicSystem.MESSAGE.parse("GUI_INFO_MAT", player, mat.name()), Arrays.asList(SchematicSystem.MESSAGE.parse("CHANGE", player), SchematicSystem.MESSAGE.parse("CLICK_DRAG_ITEM", player)), false, event -> {
+ if(event.getCursor() != null && event.getCursor().getType() != Material.AIR) {
+ node.setItem(event.getCursor().getType().name());
+ info(player, node, back);
+ } else {
+ changeItem(player, node, back);
+ }
+ });
+ if(!node.isDir()) {
+ inv.setItem(6, SWItem.getMaterial(node.getSchemtype().getMaterial()), SchematicSystem.MESSAGE.parse("GUI_INFO_TYPE", player, node.getSchemtype().name()), Arrays.asList(SchematicSystem.MESSAGE.parse("CHANGE", player), SchematicSystem.MESSAGE.parse("CLICK", player)), node.getSchemtype().fightType(), click -> {
+ changeType(player, node);
+ });
+ inv.setItem(7, SWItem.getMaterial("MAGENTA_GLAZED_TERRACOTTA"), SchematicSystem.MESSAGE.parse("GUI_INFO_DOWNLOAD", player), click -> {
+ player.closeInventory();
+ SchematicCommandUtils.download(player, node);
+ });
+ if(node.getSchemtype().fightType()) {
+ inv.setItem(14, SWItem.getMaterial(node.replaceColor() ? "PINK_WOOL" : "LIGHT_GRAY_WOOL"), SchematicSystem.MESSAGE.parse("GUI_INFO_COLOR", player), Arrays.asList(SchematicSystem.MESSAGE.parse("CURRENT", player, SchematicSystem.MESSAGE.parse(node.replaceColor()?"ON":"OFF", player)), SchematicSystem.MESSAGE.parse("CHANGE", player), SchematicSystem.MESSAGE.parse("CLICK", player)), false, clickType -> {
+ node.setReplaceColor(!node.replaceColor());
+ info(player, node, back);
+ });
+ inv.setItem(13, SWItem.getMaterial(node.allowReplay() ? "EYE_OF_ENDER" : "ENDER_PEARL"), SchematicSystem.MESSAGE.parse("GUI_INFO_REPLAY", player), Arrays.asList(SchematicSystem.MESSAGE.parse("CURRENT", player, SchematicSystem.MESSAGE.parse(node.allowReplay()?"ON":"OFF", player)), SchematicSystem.MESSAGE.parse("GUI_INFO_REPLAY_OFF", player), SchematicSystem.MESSAGE.parse("CLICK", player)), false, clickType -> {
+ if(node.allowReplay()) {
+ SWInventory confInv = new SWInventory(player, 9, SchematicSystem.MESSAGE.parse("GUI_INFO_REPLAY_TITLE", player));
+ confInv.setItem(0, SWItem.getDye(10), (byte) 10, SchematicSystem.MESSAGE.parse("CONFIRM", player), type -> {
+ node.setAllowReplay(false);
+ info(player, node, back);
+ });
+ confInv.setItem(8, SWItem.getDye(1), (byte) 1, SchematicSystem.MESSAGE.parse("CANCEL", player), type -> {
+ info(player, node, back);
+ });
+ confInv.open();
+ }
+ });
+ }
+ }
+ SWItem skull = SWItem.getPlayerSkull("MHF_STEVE");
+ skull.setCallback(click -> {
+ player.closeInventory();
+ delmembers(player, node);
+ });
+ skull.setName(SchematicSystem.MESSAGE.parse("GUI_INFO_MEMBER", player));
+ inv.setItem(8, skull);
+ inv.setItem(16, Material.NAME_TAG, SchematicSystem.MESSAGE.parse("GUI_INFO_RENAME", player), clickType -> {
+ SWAnvilInv anvilInv = new SWAnvilInv(player, SchematicSystem.MESSAGE.parse("GUI_INFO_RENAME_TITLE", player, node.getName()), node.getName());
+ anvilInv.setItem(mat, Collections.singletonList(Core.MESSAGE.parse("SCHEM_SELECTOR_CLICK_BACK", player)), false);
+ anvilInv.setCallback(s -> {
+ SafeSchematicNode.Result result = SafeSchematicNode.setName(user, node, s);
+ if(result.isSuccessful()) {
+ info(player, SchematicNode.byIdAndUser(user, node.getId()), back);
+ } else {
+ result.sendError(player);
+ }
+ });
+ setCloseLeftCallback(anvilInv, () -> info(player, node, back));
+ anvilInv.open();
+ });
+ if(node.getOwner() != 0) {
+ inv.setItem(17, SWItem.getDye(1), (byte) 1, SchematicSystem.MESSAGE.parse("GUI_INFO_DELETE", player), click -> {
+ delete(player, node, back);
+ });
+ }
+ }else{
+ if(!node.isDir()) {
+ inv.setItem(4, SWItem.getMaterial("CAULDRON_ITEM"), SchematicSystem.MESSAGE.parse("GUI_INFO_TYPE", player, node.getSchemtype().name()), Collections.emptyList(), node.getSchemtype().fightType(), click -> {});
+ }
+
+ SteamwarUser owneruser = SteamwarUser.get(node.getOwner());
+ SWItem skull = SWItem.getPlayerSkull(owneruser.getUserName());
+ skull.setName(SchematicSystem.MESSAGE.parse("GUI_INFO_MEMBER_FROM", player, owneruser.getUserName()));
+ inv.setItem(8, skull.getItemStack(), clickType -> {});
+
+ if(NodeMember.getNodeMember(node.getId(), user.getId()) != null) {
+ inv.setItem(17, SWItem.getDye(1), (byte) 1, SchematicSystem.MESSAGE.parse("GUI_INFO_MEMBER_REMOVE", player), click -> {
+ delete(player, node, back);
+ });
+ }
+ }
+
+ if(node.getOwner() == user.getId() || NodeMember.getNodeMember(node.getId(), user.getId()) != null) {
+ inv.setItem(15, Material.ARROW, SchematicSystem.MESSAGE.parse("GUI_INFO_MOVE", player), clickType -> {
+ SchematicSelector selector = new SchematicSelector(player, SchematicSelector.selectDirectory(), npar -> {
+ if(npar != null && SchematicNode.parentsOfNode(user, npar.getId()).stream().anyMatch(n -> n.getId() == node.getId())) {
+ SchematicSystem.MESSAGE.send("COMMAND_MOVE_RECURSIVE", player);
+ return;
+ }
+ if(node.getOwner() == user.getId()) {
+ SafeSchematicNode.Result result = SafeSchematicNode.setParent(user, node, npar);
+ if(result.isSuccessful()) {
+ info(player, SchematicNode.getSchematicNode(node.getId()), back);
+ } else {
+ result.sendError(player);
+ }
+ } else {
+ NodeMember.getNodeMember(node.getId(), user.getId()).setParentId(Optional.ofNullable(npar).map(SchematicNode::getId).orElse(null));
+ }
+ });
+ selector.open();
+ });
+ }
+
+ inv.setCallback(-999, click -> back.reOpen());
+ inv.open();
+ }
+
+ static void changeType(Player p, SchematicNode schem){
+ Clipboard clipboard = null;
+ try {
+ clipboard = new SchematicData(schem).load();
+ } catch (IOException ignored) { }
+
+ Clipboard finalClipboard = clipboard;
+ List types = SchematicType.values().parallelStream()
+ .filter(SchematicType::isAssignable)
+ .filter(type -> finalClipboard == null || CheckSchemType.get(type) == null || AutoChecker.sizeCheck(finalClipboard, CheckSchemType.get(type)).fastOk())
+ .collect(Collectors.toList());
+
+ List> items = types.stream()
+ .map(type -> new SWListInv.SWListEntry<>(new SWItem(SWItem.getMaterial(type.getMaterial()), type.name(), Collections.emptyList(), type.fightType(), null), type))
+ .collect(Collectors.toList());
+
+ items.addAll(SchematicType.values().stream()
+ .filter(SchematicType::isAssignable)
+ .filter(type -> !types.contains(type))
+ .map(type -> new SWListInv.SWListEntry<>(new SWItem(SWItem.getMaterial(type.getMaterial()), SchematicSystem.MESSAGE.parse("GUI_CHANGE_TYPE_NOT_POSSIBLE_COLOR", p, type.name()), Collections.singletonList(SchematicSystem.MESSAGE.parse("GUI_CHANGE_TYPE_NOT_POSSIBLE", p)), false, null), (SchematicType) null))
+ .collect(Collectors.toList()));
+
+ SWListInv inv = new SWListInv<>(p, SchematicSystem.MESSAGE.parse("GUI_CHANGE_TYPE", p), items, (clickType, schematicType) -> {
+ if(schematicType == null) return;
+ p.closeInventory();
+ SchematicCommandUtils.changeType(p, schem, schematicType, null);
+ });
+ inv.setCallback(-999, (ClickType click) -> p.closeInventory());
+ inv.open();
+ }
+
+ private static void deleteOwn(Player p, SchematicNode schem, SchematicSelector back){
+ SteamwarUser user = getUser(p);
+ SWInventory inv = new SWInventory(p, 9, SchematicSystem.MESSAGE.parse("GUI_DELETE_OWN_TITLE", p, schem.generateBreadcrumbs()));
+ inv.setItem(0, SWItem.getDye(1), (byte) 1, SchematicSystem.MESSAGE.parse("CONFIRM", p), click -> {
+ p.performCommand("schematic delete " + schem.generateBreadcrumbs());
+
+ if(back != null) {
+ if(schem.isDir()) {
+ back.reOpenDirUp();
+ } else {
+ back.reOpen();
+ }
+ }
+ });
+ inv.setItem(8, SWItem.getDye(14), (byte) 14, SchematicSystem.MESSAGE.parse("CANCEL", p), click -> p.closeInventory());
+ inv.setCallback(-999, click -> p.closeInventory());
+ inv.open();
+ }
+
+ private static void deleteMembership(Player p, SchematicNode schem, SchematicSelector back){
+ SteamwarUser user = getUser(p);
+ SWInventory inv = new SWInventory(p, 9, SchematicSystem.MESSAGE.parse("GUI_DELETE_MEMBER_TITLE", p, schem.generateBreadcrumbs()));
+ inv.setItem(0, SWItem.getDye(1), (byte) 1, SchematicSystem.MESSAGE.parse("CONFIRM", p), click -> {
+ NodeMember member = NodeMember.getNodeMember(schem.getId(), user.getId());
+ if(member != null)
+ member.delete();
+ SchematicSystem.MESSAGE.send("GUI_DELETE_MEMBER_DONE", p, schem.generateBreadcrumbs());
+ if(back != null) {
+ if(schem.isDir()) {
+ back.reOpenDirUp();
+ } else {
+ back.reOpen();
+ }
+ }
+ });
+ inv.setItem(8, SWItem.getDye(14), (byte) 14, SchematicSystem.MESSAGE.parse("CANCEL", p), click -> p.closeInventory());
+ inv.setCallback(-999, click -> p.closeInventory());
+ inv.open();
+ }
+
+ static void delete(Player p, SchematicNode schem, SchematicSelector back){
+ if(SteamwarUser.get(p.getUniqueId()).getId() == schem.getOwner())
+ deleteOwn(p, schem, back);
+ else
+ deleteMembership(p, schem, back);
+ }
+
+ static void delmembers(Player p, SchematicNode schem){
+ List> members = new LinkedList<>();
+ for(NodeMember member : schem.getMembers()){
+ SteamwarUser user = SteamwarUser.get(member.getMember());
+ members.add(new SWListInv.SWListEntry<>(SWItem.getPlayerSkull(user.getUserName()), member));
+ }
+
+ SWListInv inv = new SWListInv<>(p, SchematicSystem.MESSAGE.parse("GUI_DELETE_MEMBERS_TITLE", p), members, (clickType, member) -> {
+ member.delete();
+ p.closeInventory();
+ delmembers(p, schem);
+ });
+ inv.setCallback(-999, (ClickType click) -> p.closeInventory());
+ inv.open();
+ }
+
+ private static void changeItem(Player p, SchematicNode schem, SchematicSelector back){
+ UtilGui.openMaterialSelector(p, SchematicSystem.MESSAGE.parse("GUI_CHANGE_ITEM", p), material -> {
+ schem.setItem(material.name());
+ p.closeInventory();
+ info(p, schem, back);
+ });
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand.java
new file mode 100644
index 00000000..b3ecf374
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand.java
@@ -0,0 +1,149 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.commands.schematiccommand;
+
+import com.sk89q.worldedit.*;
+import com.sk89q.worldedit.extent.clipboard.Clipboard;
+import de.steamwar.command.*;
+import de.steamwar.core.VersionDependent;
+import de.steamwar.schematicsystem.CheckSchemType;
+import de.steamwar.schematicsystem.SchematicSystem;
+import de.steamwar.schematicsystem.autocheck.AutoCheckerResult;
+import de.steamwar.sql.*;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandHelp.*;
+import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.*;
+
+@SuppressWarnings("unused")
+public class SchematicCommand extends SWCommand {
+
+ public SchematicCommand() {
+ super("schematic", new String[] {"schem", "/schem", "/schematic"});
+ }
+
+ @Register("help")
+ public void pagedHelp(Player player, HelpPage page) {
+ printHelpPage(player, page);
+ }
+
+ @Register
+ public void genericHelp(Player player, String... args) {
+ printHelpMainPage(player);
+ }
+
+ @Register(value = "togglepublic", noTabComplete = true)
+ public void togglePublicMode(Player player) {
+ SteamwarUser user = SteamwarUser.get(player.getUniqueId());
+ if (!user.hasPerm(UserPerm.MODERATION)) {
+ genericHelp(player);
+ return;
+ }
+
+ if (togglePublic(player)) {
+ SchematicSystem.MESSAGE.send("COMMAND_PUBLIC_ON", player);
+ } else {
+ SchematicSystem.MESSAGE.send("COMMAND_PUBLIC_OFF", player);
+ }
+ }
+
+ @Mapper("publicMapper")
+ public TypeMapper publicNodeTypeMapper() {
+ return SchematicMapper.publicNodeTypeMapper();
+ }
+
+ @Mapper("memberMapper")
+ public static TypeMapper nodeMemberTypeMapper() {
+ return SchematicMapper.nodeMemberTypeMapper();
+ }
+
+ @Mapper("dirMapper")
+ public static TypeMapper dirNodeTypeMapper() {
+ return SchematicMapper.dirNodeTypeMapper();
+ }
+
+ @Mapper("publicDirMapper")
+ public static TypeMapper publicDirNodeTypeMapper() {
+ return SchematicMapper.publicDirNodeTypeMapper();
+ }
+
+ @Mapper("dirStringMapper")
+ public static TypeMapper stringTabMapper() {
+ return SchematicMapper.stringTabMapper();
+ }
+
+ @Mapper("stringMapper")
+ public static TypeMapper stringMapper() {
+ return SchematicMapper.stringMapper();
+ }
+
+ @ClassMapper(SchematicType.class)
+ public static TypeMapper typeTypeMapper() {
+ return SchematicMapper.typeTypeMapper();
+ }
+
+ @AbstractSWCommand.ClassMapper(value = SchematicNode.class, local = true)
+ public static TypeMapper nodeTypeMapper() {
+ return SchematicMapper.nodeTypeMapper();
+ }
+
+ @ClassMapper(value = CheckSchemType.class, local = true)
+ public static TypeMapper checkSchemTypeTypeMapper() {
+ return SchematicMapper.checkSchemTypeTypeMapper();
+ }
+
+ @Override
+ protected void sendMessage(CommandSender sender, String message, Object[] args) {
+ SchematicSystem.MESSAGE.send(message, sender, args);
+ }
+
+ @Validator(value = "isSchemValidator", local = true)
+ public static TypeValidator isSchemValidator() {
+ return SchematicValidator.isSchemValidator();
+ }
+
+ @Validator(value = "isDirValidator", local = true)
+ public static TypeValidator isDirValidator() {
+ return SchematicValidator.isDirValidator();
+ }
+
+ @Validator(value = "isOwnerValidator", local = true)
+ public static TypeValidator isOwnerValidator() {
+ return SchematicValidator.isOwnerValidator();
+ }
+
+ @Validator(value = "isOwnerSchematicValidator", local = true)
+ public static TypeValidator isOwnerSchematicValidator() {
+ return SchematicValidator.isOwnerSchematicValidator();
+ }
+
+ public enum Extend {
+ AUSFAHREN,
+ NORMAL
+ }
+
+ public static final ISchematicCommand impl = VersionDependent.getVersionImpl(SchematicSystem.getInstance());
+
+ public interface ISchematicCommand {
+ Clipboard fixClipboard(Clipboard clipboard, AutoCheckerResult result, CheckSchemType type) throws Exception;
+ void createCopy(EditSession editSession, Clipboard clipboard) throws WorldEditException;
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandHelp.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandHelp.java
new file mode 100644
index 00000000..1cb0ebd8
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandHelp.java
@@ -0,0 +1,92 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.commands.schematiccommand;
+
+import de.steamwar.schematicsystem.SchematicSystem;
+import net.md_5.bungee.api.ChatColor;
+import net.md_5.bungee.api.chat.ClickEvent;
+import net.md_5.bungee.api.chat.HoverEvent;
+import net.md_5.bungee.api.chat.TextComponent;
+import org.bukkit.entity.Player;
+
+public class SchematicCommandHelp {
+ private SchematicCommandHelp() {
+ }
+
+ public static void printHelpMainPage(Player player) {
+ SchematicSystem.MESSAGE.sendPrefixless("HELP_HEADER", player);
+ for (HelpPage page : HelpPage.values()) {
+ TextComponent pageComp = new TextComponent(SchematicSystem.MESSAGE.parse(page.mainText, player));
+ pageComp.setColor(ChatColor.GRAY);
+ pageComp.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.fromLegacyText("§e" + SchematicSystem.MESSAGE.parse(page.hover, player))));
+ pageComp.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem help " + page.name()));
+ player.spigot().sendMessage(pageComp);
+ }
+ }
+
+ public static void printHelpPage(Player player, HelpPage page) {
+ SchematicSystem.MESSAGE.sendPrefixless("HELP_HEADER", player);
+ for (String s : page.content) {
+ SchematicSystem.MESSAGE.sendPrefixless(s, player);
+ }
+ }
+
+ public enum HelpPage {
+ ANSICHT("HELP_VIEW", "HELP_VIEW_HOVER", new String[]{
+ "HELP_VIEW_1",
+ "HELP_VIEW_2",
+ "HELP_VIEW_3",
+ "HELP_VIEW_4",
+ "HELP_VIEW_5",
+ "HELP_VIEW_6",
+ "HELP_VIEW_7",
+ "HELP_VIEW_8"
+ }),
+ BEARBEITUNG("HELP_EDIT", "HELP_EDIT_HOVER", new String[]{
+ "HELP_EDIT_1",
+ "HELP_EDIT_2",
+ "HELP_EDIT_3",
+ "HELP_EDIT_4",
+ "HELP_EDIT_5",
+ "HELP_EDIT_6",
+ "HELP_EDIT_7",
+ "HELP_EDIT_8",
+ "HELP_EDIT_9"
+ }),
+ MEMBER("HELP_SHARE", "HELP_SHARE_HOVER", new String[]{
+ "HELP_SHARE_1",
+ "HELP_SHARE_2",
+ "HELP_SHARE_3",
+ "HELP_SHARE_4",
+ "HELP_SHARE_5",
+ "HELP_SHARE_6"
+ });
+
+ private final String mainText;
+ private final String[] content;
+ private final String hover;
+
+ HelpPage(String mainText, String hover, String[] content) {
+ this.mainText = mainText;
+ this.hover = hover;
+ this.content = content;
+ }
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandInitializer.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandInitializer.java
new file mode 100644
index 00000000..7245ead6
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandInitializer.java
@@ -0,0 +1,36 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.commands.schematiccommand;
+
+import de.steamwar.schematicsystem.SchematicSystem;
+import de.steamwar.schematicsystem.commands.schematiccommand.parts.*;
+
+public class SchematicCommandInitializer {
+
+ public static void init() {
+ new SchematicCommand().setMessage(SchematicSystem.MESSAGE);
+ new CheckPart().setMessage(SchematicSystem.MESSAGE);
+ new MemberPart().setMessage(SchematicSystem.MESSAGE);
+ new ModifyPart().setMessage(SchematicSystem.MESSAGE);
+ new SavePart().setMessage(SchematicSystem.MESSAGE);
+ new SearchPart().setMessage(SchematicSystem.MESSAGE);
+ new ViewPart().setMessage(SchematicSystem.MESSAGE);
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandUtils.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandUtils.java
new file mode 100644
index 00000000..753cd3b9
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandUtils.java
@@ -0,0 +1,505 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.commands.schematiccommand;
+
+import com.sk89q.worldedit.extent.clipboard.Clipboard;
+import de.steamwar.inventory.SWInventory;
+import de.steamwar.inventory.SWItem;
+import de.steamwar.network.NetworkSender;
+import de.steamwar.network.packets.client.PrepareSchemPacket;
+import de.steamwar.providers.BauServerInfo;
+import de.steamwar.schematicsystem.CheckSchemType;
+import de.steamwar.schematicsystem.SchematicSystem;
+import de.steamwar.schematicsystem.autocheck.AutoChecker;
+import de.steamwar.schematicsystem.autocheck.AutoCheckerResult;
+import de.steamwar.sql.*;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.With;
+import net.md_5.bungee.api.ChatColor;
+import net.md_5.bungee.api.chat.ClickEvent;
+import net.md_5.bungee.api.chat.ComponentBuilder;
+import net.md_5.bungee.api.chat.HoverEvent;
+import net.md_5.bungee.api.chat.TextComponent;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.function.IntFunction;
+import java.util.function.UnaryOperator;
+import java.util.logging.Level;
+import java.util.stream.Collectors;
+
+public class SchematicCommandUtils {
+
+ public static final int CHUNK_SIZE = 15;
+ private static final List PUBLIC_TOGGLED = new ArrayList<>();
+ private static final List FORBIDDEN_NAMES = Collections.unmodifiableList(Arrays.asList("public"));
+ private static final Map CACHED_LISTS = new HashMap<>();
+
+
+ private SchematicCommandUtils() {
+ }
+
+ public static boolean invalidSchemName(Player player, String[] layers) {
+ for (String layer : layers) {
+ if (layer.isEmpty()) {
+ SchematicSystem.MESSAGE.send("UTIL_NAME_REQUIRED", player);
+ return true;
+ }
+ if(layer.length() > 64) {
+ SchematicSystem.MESSAGE.send("UTIL_NAME_TOO_LONG", player);
+ return true;
+ }
+ if (layer.contains("/") ||
+ layer.contains("\\") ||
+ layer.contains("<") ||
+ layer.contains(">") ||
+ layer.contains("^") ||
+ layer.contains("°") ||
+ layer.contains("'") ||
+ layer.contains("\"") ||
+ layer.contains(" ")) {
+ SchematicSystem.MESSAGE.send("UTIL_NAME_INVALID_CHAR", player);
+ return true;
+ }
+ if (FORBIDDEN_NAMES.contains(layer.toLowerCase())) {
+ SchematicSystem.MESSAGE.send("UTIL_NAME_FORBIDDEN", player, layer);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static void createCachedSchemList(Player player, List nodes, int chunk, SchematicNode parent, SchematicListBehavior behavior) {
+ CachedSchematicList cachedSchematicList = new CachedSchematicList(nodes, chunk, (int) Math.ceil(nodes.size() / (double) CHUNK_SIZE), parent, behavior.withPageCommandGen((page) -> "/schematic page " + (page - 1)));
+ CACHED_LISTS.put(player, cachedSchematicList);
+ renderSchemlist(player, cachedSchematicList.nodes, chunk, parent, cachedSchematicList.behavior);
+ }
+
+ public static void cachedSchemList(Player player, int chunk) {
+ CACHED_LISTS.computeIfPresent(player, (p, cachedSchematicList) -> {
+ renderSchemlist(player, cachedSchematicList.nodes, chunk, null, cachedSchematicList.behavior);
+ return cachedSchematicList.withPage(chunk);
+ });
+ }
+
+ public static void renderSchemlist(Player player,
+ List nodes,
+ int chunk,
+ SchematicNode parent,
+ SchematicListBehavior behavior) {
+ SteamwarUser user = getUser(player);
+ int pageCount = (int) Math.ceil(nodes.size() / (double) CHUNK_SIZE);
+
+ SchematicSystem.MESSAGE.sendPrefixless("UTIL_LIST_HEAD", player, nodes.size());
+ String breadcrumbs = parent == null ? "" : parent.generateBreadcrumbs();
+ SchematicSystem.MESSAGE.sendPrefixless("UTIL_LIST_PATH", player, (breadcrumbs.isEmpty() ? "/" : breadcrumbs));
+ if (!breadcrumbs.isEmpty()) {
+ String str = breadcrumbs.substring(0, Math.max(0, breadcrumbs.substring(0, breadcrumbs.length() - 1).lastIndexOf("/")));
+ SchematicSystem.MESSAGE.sendPrefixless("UTIL_LIST_BACK", player, SchematicSystem.MESSAGE.parse("UTIL_LIST_BACK_HOVER", player, str), new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem list " + (behavior.isPublics() ? "public" : "") + " " + str));
+ }
+ for (int i = chunk * CHUNK_SIZE; i < nodes.size() && i < (chunk + 1) * CHUNK_SIZE; i++) {
+ SchematicNode node = nodes.get(i);
+
+ StringBuilder nodeString = new StringBuilder();
+
+ if (node.isDir()) {
+ nodeString.append(SchematicSystem.MESSAGE.parse("UTIL_LIST_DIR", player)).append(" ");
+ } else {
+ SchematicType type = node.getSchemtype();
+ if (type != SchematicType.Normal) {
+ nodeString.append(SchematicSystem.MESSAGE.parse("UTIL_LIST_TYPE", player, type.getKuerzel())).append(" ");
+ }
+ }
+ nodeString.append(SchematicSystem.MESSAGE.parse("UTIL_LIST_BASE", player));
+
+ nodeString.append(behavior.getRenderHook().apply(node.getName()));
+
+ if (node.isDir()) {
+ nodeString.append("/");
+ }
+
+ if (node.getOwner() != user.getId()) {
+ nodeString.append(" ").append(SchematicSystem.MESSAGE.parse("UTIL_LIST_FROM", player, SteamwarUser.get(node.getOwner()).getUserName()));
+ }
+ TextComponent schematics = new TextComponent(nodeString.toString());
+
+ if (node.isDir()) {
+ schematics.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(SchematicSystem.MESSAGE.parse("UTIL_LIST_OPEN_DIR", player)).create()));
+ schematics.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem list " + (behavior.isPublics() ? "public " : "") + (behavior.nonCachedBreadcrumbs ? node.generateBreadcrumbs() : breadcrumbs + node.getName() + "/")));
+ } else {
+ schematics.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(SchematicSystem.MESSAGE.parse("UTIL_LIST_OPEN_SCHEM", player)).create()));
+ schematics.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem info " + (behavior.isPublics() ? "public " : "") + (behavior.nonCachedBreadcrumbs ? node.generateBreadcrumbs() : breadcrumbs + node.getName())));
+ }
+
+ player.spigot().sendMessage(schematics);
+ }
+
+ if (parent != null && parent.getOwner() != user.getId() && NodeMember.getNodeMember(parent.getId(), user.getId()) != null) {
+ TextComponent deadd = SchematicSystem.MESSAGE.parseToComponent("UTIL_LIST_REMOVE", false, player);
+ deadd.setColor(ChatColor.RED);
+ deadd.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[] {SchematicSystem.MESSAGE.parseToComponent("UTIL_LIST_REMOVE_HOVER", false, player)}));
+ deadd.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem delete " + parent.generateBreadcrumbs()));
+ player.spigot().sendMessage(deadd);
+ }
+
+ TextComponent beforePage = SchematicSystem.MESSAGE.parseToComponent("UTIL_LIST_BACK_ARROW", false, player);
+ beforePage.addExtra(" ");
+ if (chunk > 0) {
+ beforePage.setColor(ChatColor.YELLOW);
+ beforePage.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[] {SchematicSystem.MESSAGE.parseToComponent("UTIL_LIST_BACK_ARROW_HOVER", false, player)}));
+ beforePage.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, behavior.getPageCommandGen().apply(chunk)));
+ } else {
+ beforePage.setColor(ChatColor.RED);
+ }
+
+ TextComponent nextPage = SchematicSystem.MESSAGE.parseToComponent("UTIL_LIST_NEXT", false, player, chunk + 1, Math.max(pageCount, 1));
+ if (chunk < pageCount - 1) {
+ nextPage.setColor(ChatColor.YELLOW);
+ nextPage.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[] {SchematicSystem.MESSAGE.parseToComponent("UTIL_LIST_NEXT_HOVER", false, player)}));
+ nextPage.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, behavior.getPageCommandGen().apply(chunk + 2)));
+ } else {
+ nextPage.setColor(ChatColor.RED);
+ }
+
+ beforePage.addExtra(nextPage);
+ player.spigot().sendMessage(beforePage);
+ }
+
+ @Getter
+ @Builder(setterPrefix = "set")
+ @With
+ public static class SchematicListBehavior {
+ public static final SchematicListBehavior DEFAULT = SchematicListBehavior.builder().build();
+
+ @Builder.Default private boolean showPath = true;
+ @Builder.Default private boolean publics = false;
+ @Builder.Default private boolean nonCachedBreadcrumbs = false;
+ @Builder.Default private UnaryOperator renderHook = s -> s;
+ @Builder.Default private IntFunction pageCommandGen = value -> "/schem list " + value;
+ }
+
+ public static void printSchemInfo(Player player, SchematicNode node) {
+ SteamwarUser user = getUser(player);
+ SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_SCHEM", player, node.generateBreadcrumbs());
+ if(node.getOwner() == user.getId()) {
+ player.spigot().sendMessage(
+ new ComponentBuilder(SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_NAME", false, player, node.getName()))
+ .event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[] {SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_ACTION_RENAME_HOVER", false, player)}))
+ .event(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/schem rename " + node.generateBreadcrumbs() + " "))
+ .create()
+ );
+ } else {
+ SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_NAME", player, node.getName());
+ }
+ SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_OWNER", player, node.getOwner() == user.getId() ? user.getUserName() : SteamwarUser.get(node.getOwner()).getUserName());
+ if(node.getOwner() == user.getId()) {
+ player.spigot().sendMessage(
+ new ComponentBuilder(SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_PARENT", false, player, node.getParent() == null ? "/" : node.getParentNode().generateBreadcrumbs()))
+ .event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[] {SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_ACTION_MOVE_HOVER", false, player)}))
+ .event(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/schem move " + node.generateBreadcrumbs() + " " + node.generateBreadcrumbs().replace("/" + node.getName(), "")))
+ .create()
+ );
+ } else {
+ SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_PARENT", player, node.getParent() == null ? "/" : node.getParentNode().generateBreadcrumbs());
+ }
+ SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_UPDATED", player, node.getLastUpdate());
+ if (!node.isDir()) {
+ if(node.getOwner() == user.getId()) {
+ player.spigot().sendMessage(
+ new ComponentBuilder(SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_TYPE", false, player, node.getSchemtype().name()))
+ .event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[] {SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_ACTION_TYPE_HOVER", false, player)}))
+ .event(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem changetype " + node.generateBreadcrumbs()))
+ .create()
+ );
+ } else {
+ SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_TYPE", player, node.getSchemtype().name());
+ }
+ if (node.getRank() > 0) {
+ SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_RANK", player, node.getRank());
+ }
+
+ if (node.getSchemtype().fightType()) {
+ SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_COLOR", player, SchematicSystem.MESSAGE.parse(node.replaceColor() ? "ON" : "OFF", player));
+ SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_REPLAY", player, SchematicSystem.MESSAGE.parse(node.allowReplay() ? "ON" : "OFF", player));
+ SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_ELO", player, node.getElo(Season.getSeason()));
+ }
+
+ SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_FORMAT", player, node.getSchemFormat() ? ".schem" : ".schematic");
+ CheckedSchematic.getLastDeclinedOfNode(node.getId()).stream().findFirst().ifPresent(checkedSchematic -> SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_STATUS", player, checkedSchematic.getEndTime(), checkedSchematic.getDeclineReason()));
+ } else {
+ SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_TYPE", player, SchematicSystem.MESSAGE.parse("UTIL_INFO_TYPE_DIR", player));
+ }
+
+
+ if(node.getOwner() == user.getId()) {
+ ComponentBuilder memberBuilder = new ComponentBuilder(SchematicSystem.MESSAGE.parse("UTIL_INFO_MEMBER_STRING", player) + " ").color(ChatColor.GRAY);
+ NodeMember.getNodeMembers(node.getId()).forEach(nodeMember -> {
+ SteamwarUser member = SteamwarUser.get(nodeMember.getMember());
+ memberBuilder.append(member.getUserName())
+ .color(ChatColor.YELLOW)
+ .event(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/schem delmember " + node.generateBreadcrumbs() + " " + member.getUserName()))
+ .event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[]{SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_ACTION_REMOVE_HOVER", false, player, member.getUserName())}))
+ .append(" ", ComponentBuilder.FormatRetention.NONE);
+ });
+ memberBuilder.append("(+)", ComponentBuilder.FormatRetention.NONE)
+ .color(ChatColor.GREEN)
+ .event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[]{SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_ACTION_ADD_HOVER", false, player)}))
+ .event(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/schem addmember " + node.generateBreadcrumbs() + " "));
+ player.spigot().sendMessage(memberBuilder.create());
+ } else {
+ List schematicMembers = new ArrayList<>();
+ NodeMember.getNodeMembers(node.getId()).forEach(nodeMember -> schematicMembers.add(SteamwarUser.get(nodeMember.getMember()).getUserName()));
+ if(!schematicMembers.isEmpty()) {
+ SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_MEMBER", player, schematicMembers.stream().reduce((s, s2) -> s + ", " + s2).orElse(""));
+ }
+ }
+
+ TextComponent base = new TextComponent();
+
+ if (!node.isDir()) {
+ TextComponent load = SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_ACTION_LOAD", false, player);
+ load.setColor(ChatColor.GREEN);
+ load.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[]{SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_ACTION_LOAD_HOVER", false, player)}));
+ load.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem load " + (node.getOwner() == 0 ? "public " : "") + node.generateBreadcrumbs()));
+ base.addExtra(load);
+
+ if (node.getOwner() == user.getId()) {
+ TextComponent download = SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_ACTION_DOWNLOAD", false, player);
+ download.setColor(ChatColor.GOLD);
+ download.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[]{SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_ACTION_DOWNLOAD_HOVER", false, player)}));
+ download.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem download " + node.generateBreadcrumbs()));
+ base.addExtra(download);
+ }
+ }
+
+ if (node.getOwner() != 0) {
+ TextComponent delete = SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_ACTION_DELETE", false, player);
+ delete.setColor(ChatColor.DARK_RED);
+ delete.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[]{SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_ACTION_DELETE_HOVER", false, player)}));
+ delete.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/schem delete " + node.generateBreadcrumbs()));
+ base.addExtra(delete);
+ }
+
+ if (!base.getExtra().isEmpty()) {
+ player.spigot().sendMessage(base);
+ }
+ }
+
+ public static void check(Player player, Clipboard clipboard, CheckSchemType type, String schemName, boolean gui) {
+ AutoCheckerResult result = AutoChecker.check(clipboard, type);
+ if(!result.isOk()) {
+ result.sendErrorMessage(player, schemName);
+ } else {
+ SchematicSystem.MESSAGE.send("UTIL_CHECK_SUCCESS", player, schemName);
+ }
+ }
+
+ public static SchematicNode mkdirs(String[] layers, SteamwarUser user, int minus) {
+ Optional currentNode = Optional.empty();
+ for (int i = 0; i < layers.length - minus; i++) {
+ int finalI = i;
+ List nodes = SchematicNode.list(user, currentNode.map(SchematicNode::getId).orElse(null)).stream()
+ .filter(node -> node.getName().equalsIgnoreCase(layers[finalI]))
+ .collect(Collectors.toList());
+ if (nodes.isEmpty()) {
+ currentNode = Optional.ofNullable(SchematicNode.byIdAndUser(user, SchematicNode.createSchematicDirectory(user.getId(), layers[i], currentNode.map(SchematicNode::getId).orElse(null)).getId()));
+ } else {
+ if(nodes.stream().anyMatch(SchematicNode::isDir)) {
+ currentNode = nodes.stream().filter(SchematicNode::isDir).findFirst();
+ } else {
+ currentNode = Optional.ofNullable(SchematicNode.byIdAndUser(user, SchematicNode.createSchematicDirectory(user.getId(), layers[i] + "-dir-" + System.currentTimeMillis() % 100, currentNode.map(SchematicNode::getId).orElse(null)).getId()));
+ }
+ }
+ }
+ return currentNode.orElse(null);
+ }
+
+ public static SteamwarUser getUser(Player player) {
+ if (PUBLIC_TOGGLED.contains(player)) {
+ return SteamwarUser.get(0);
+ } else {
+ return SteamwarUser.get(player.getUniqueId());
+ }
+ }
+
+ public static boolean togglePublic(Player player) {
+ if (PUBLIC_TOGGLED.contains(player)) {
+ PUBLIC_TOGGLED.remove(player);
+ return false;
+ } else {
+ PUBLIC_TOGGLED.add(player);
+ return true;
+ }
+ }
+
+ public static void turnOffPublic(Player player) {
+ PUBLIC_TOGGLED.remove(player);
+ }
+
+ public static void loadSchem(Player player, SchematicNode node) {
+ SteamwarUser user = getUser(player);
+ if(BauServerInfo.isBauServer() && BauServerInfo.getOwnerId() != user.getId() &&
+ (Punishment.isPunished(user, Punishment.PunishmentType.NoSchemSharing, punishment ->
+ SchematicSystem.MESSAGE.send("UTIL_LOAD_NOT_HERE", player)) ||
+ Punishment.isPunished(SteamwarUser.get(BauServerInfo.getOwnerId()), Punishment.PunishmentType.NoSchemReceiving, punishment ->
+ SchematicSystem.MESSAGE.send("UTIL_LOAD_NOT_HERE_ALL", player)))) {
+ return;
+ }
+ if (node.isDir()) {
+ SchematicSystem.MESSAGE.send("UTIL_LOAD_DIR", player);
+ return;
+ }
+
+ try {
+ new SchematicData(node).loadToPlayer(player);
+ SchematicSystem.MESSAGE.send("UTIL_LOAD_DONE", player, node.getName());
+ Bukkit.getLogger().log(Level.INFO, "{0} has loaded Schematic {1} {2}", new Object[]{player.getName(), node.getId(), node.getName()});
+ } catch (NoClipboardException e) {
+ SchematicSystem.MESSAGE.send("UTIL_LOAD_NO_DATA", player);
+ } catch (Exception e) {
+ SchematicSystem.MESSAGE.send("UTIL_LOAD_ERROR", player);
+ Bukkit.getLogger().log(Level.INFO, e.getMessage(), e);
+ }
+ }
+
+ public static void download(Player player, SchematicNode node) {
+ SteamwarUser user = getUser(player);
+ if (Punishment.isPunished(user, Punishment.PunishmentType.NoSchemSharing, punishment -> {
+ SchematicSystem.MESSAGE.send("UTIL_DOWNLOAD_PUNISHED", player, punishment.getReason());
+ })) {
+ return;
+ }
+ if (node.getOwner() != user.getId()) {
+ SchematicSystem.MESSAGE.send("UTIL_DOWNLOAD_NOT_OWN", player);
+ return;
+ }
+
+ SchematicSystem.MESSAGE.send("UTIL_DOWNLOAD_LINK", player);
+ player.sendMessage(NodeDownload.getLink(node));
+ }
+
+ public static void changeType(Player player, SchematicNode node, SchematicType type, SchematicCommand.Extend extend) {
+ SteamwarUser user = getUser(player);
+ if (Punishment.isPunished(user,
+ Punishment.PunishmentType.NoSchemSubmitting,
+ punishment -> SchematicSystem.MESSAGE.send("UTIL_TYPE_PUNISHED", player, punishment.getReason()))) {
+ return;
+ }
+ if (node.getOwner() != user.getId()) {
+ SchematicSystem.MESSAGE.send("UTIL_TYPE_NOT_OWN", player);
+ return;
+ }
+
+ if (node.isDir()) {
+ SchematicSystem.MESSAGE.send("UTIL_TYPE_DIR", player);
+ return;
+ }
+
+ if (!type.isAssignable()) {
+ SchematicSystem.MESSAGE.send("UTIL_TYPE_NOT_ASSIGNABLE", player);
+ return;
+ }
+
+ if (node.getSchemtype().equals(type)) {
+ SchematicSystem.MESSAGE.send("UTIL_TYPE_ALREADY", player);
+ return;
+ }
+
+ if (type.writeable()) {
+ node.setSchemtype(type);
+ SchematicSystem.MESSAGE.send("UTIL_TYPE_DONE", player);
+ } else if (type.fightType()) {
+ if (node.getSchemtype().check()) {
+ SchematicSystem.MESSAGE.send("UTIL_TYPE_FIGHT_ALREADY", player);
+ return;
+ }
+
+ CheckSchemType checkSchemType = CheckSchemType.get(type);
+ if (checkSchemType.isAfterDeadline()) {
+ SchematicSystem.MESSAGE.send("UTIL_TYPE_AFTER_DEADLINE", player, checkSchemType.getDeadline());
+ return;
+ }
+
+ AutoCheckerResult result = null;
+ try {
+ result = AutoChecker.check(new SchematicData(node).load(), checkSchemType);
+ } catch (IOException e) {
+ SchematicSystem.MESSAGE.send("UTIL_LOAD_ERROR", player);
+ SchematicSystem.getInstance().getLogger().throwing(SchematicCommandUtils.class.getName(), "changeType", e);
+ return;
+ }
+ if (!result.isOk()) {
+ SchematicSystem.MESSAGE.send("UTIL_TYPE_ERROR", player);
+ result.sendErrorMessage(player, node.getName());
+ return;
+ }
+
+ if (extend == null) {
+ submitSchemGUI(player, node, type);
+ } else if (extend == SchematicCommand.Extend.AUSFAHREN) {
+ NetworkSender.send(new PrepareSchemPacket(SteamwarUser.get(player.getUniqueId()).getId(), node.getId(), type.toDB()));
+ SchematicSystem.MESSAGE.send("UTIL_TYPE_EXTEND", player);
+ }
+ }
+ }
+
+ private static void submitSchemGUI(Player player, SchematicNode node, SchematicType type) {
+ SWInventory inv = new SWInventory(player, 9, SchematicSystem.MESSAGE.parse("UTIL_SUBMIT_TITLE", player));
+ inv.setItem(0, SWItem.getMaterial("SIGN"), SchematicSystem.MESSAGE.parse(node.allowReplay()?"UTIL_SUBMIT_REPLAY_ON":"UTIL_SUBMIT_REPLAY_OFF", player), click -> {
+ node.setAllowReplay(!node.allowReplay());
+ submitSchemGUI(player, node, type);
+ });
+ inv.setItem(1, SWItem.getMaterial(node.replaceColor() ? "PINK_WOOL" : "LIGHT_GRAY_WOOL"), SchematicSystem.MESSAGE.parse(node.allowReplay()?"UTIL_SUBMIT_COLOR_ON":"UTIL_SUBMIT_COLOR_OFF", player), click -> {
+ node.setReplaceColor(!node.replaceColor());
+ submitSchemGUI(player, node, type);
+ });
+ inv.setItem(7, SWItem.getDye(7), (byte) 7, SchematicSystem.MESSAGE.parse("UTIL_SUBMIT_DIRECT", player), click -> {
+ node.setSchemtype(type.checkType());
+ SchematicSystem.MESSAGE.send("UTIL_SUBMIT_DIRECT_DONE", player);
+ player.closeInventory();
+ });
+ inv.setItem(8, SWItem.getDye(10), (byte) 10, SchematicSystem.MESSAGE.parse("UTIL_SUBMIT_EXTEND", player), click -> {
+ NetworkSender.send(new PrepareSchemPacket(SteamwarUser.get(player.getUniqueId()).getId(), node.getId(), type.toDB()));
+ SchematicSystem.MESSAGE.send("UTIL_SUBMIT_EXTEND_DONE", player);
+ player.closeInventory();
+ });
+ inv.setCallback(-999, click -> player.closeInventory());
+ inv.open();
+ }
+
+ public static void quitPlayer(Player player) {
+ CACHED_LISTS.remove(player);
+ PUBLIC_TOGGLED.remove(player);
+ }
+
+ @AllArgsConstructor
+ @With
+ static class CachedSchematicList {
+ private List nodes;
+ private int page;
+ private int maxPage;
+ private SchematicNode parent;
+ private SchematicListBehavior behavior;
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicMapper.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicMapper.java
new file mode 100644
index 00000000..bcf60e63
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicMapper.java
@@ -0,0 +1,191 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.commands.schematiccommand;
+
+import de.steamwar.command.TypeMapper;
+import de.steamwar.schematicsystem.CheckSchemType;
+import de.steamwar.sql.NodeMember;
+import de.steamwar.sql.SchematicNode;
+import de.steamwar.sql.SchematicType;
+import de.steamwar.sql.SteamwarUser;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.getUser;
+
+public class SchematicMapper {
+
+ private static final TypeMapper publicCommandTypeMapper = publicNodeTypeMapper();
+
+ public static TypeMapper publicNodeTypeMapper() {
+ return new TypeMapper() {
+ @Override
+ public List tabCompletes(CommandSender commandSender, String[] strings, String s) {
+ return SchematicNode.getNodeTabcomplete(SteamwarUser.get(0), s);
+ }
+
+ @Override
+ public SchematicNode map(CommandSender commandSender, String[] previousArguments, String s) {
+ return SchematicNode.getNodeFromPath(SteamwarUser.get(0), s);
+ }
+ };
+ }
+
+ public static TypeMapper nodeMemberTypeMapper() {
+ return new TypeMapper() {
+ @Override
+ public NodeMember map(CommandSender commandSender, String[] previousArguments, String s) {
+ SchematicNode node = SchematicNode.getNodeFromPath(getUser((Player) commandSender), previousArguments[previousArguments.length - 1]);
+ SteamwarUser user = SteamwarUser.get(s);
+ return NodeMember.getNodeMember(node.getId(), user.getId());
+ }
+
+ @Override
+ public List tabCompletes(CommandSender commandSender, String[] strings, String s) {
+ return Optional.ofNullable(SchematicNode.getNodeFromPath(getUser((Player) commandSender), strings[strings.length - 1]))
+ .map(SchematicNode::getMembers)
+ .map(nodeMembers -> nodeMembers.stream().map(NodeMember::getMember).map(SteamwarUser::get).map(SteamwarUser::getUserName).collect(Collectors.toList()))
+ .orElse(Collections.emptyList());
+ }
+ };
+ }
+
+ public static TypeMapper dirNodeTypeMapper() {
+ return new TypeMapper() {
+ @Override
+ public List tabCompletes(CommandSender commandSender, String[] strings, String s) {
+ List list = SchematicNode.getNodeTabcomplete(getUser((Player) commandSender), s);
+ list.removeIf(s1 -> !s1.endsWith("/"));
+ return list;
+ }
+
+ @Override
+ public SchematicNode map(CommandSender commandSender, String[] previousArguments, String s) {
+ SchematicNode node = SchematicNode.getNodeFromPath(getUser((Player) commandSender), s);
+ if(node.isDir()) {
+ return node;
+ } else {
+ return null;
+ }
+ }
+ };
+ }
+
+ public static TypeMapper publicDirNodeTypeMapper() {
+ return new TypeMapper() {
+ @Override
+ public Collection tabCompletes(CommandSender commandSender, String[] strings, String s) {
+ Collection list = publicCommandTypeMapper.tabCompletes(commandSender, strings, s);
+ list.removeIf(s1 -> !s1.endsWith("/"));
+ return list;
+ }
+
+ @Override
+ public SchematicNode map(CommandSender commandSender, String[] previousArguments, String s) {
+ SchematicNode node = publicCommandTypeMapper.map(commandSender, previousArguments, s);
+ if(node.isDir()) {
+ return node;
+ } else {
+ return null;
+ }
+ }
+ };
+ }
+
+ public static TypeMapper stringTabMapper() {
+ return new TypeMapper() {
+ @Override
+ public List tabCompletes(CommandSender commandSender, String[] strings, String s) {
+ List list = SchematicNode.getNodeTabcomplete(getUser((Player) commandSender), s);
+ list.removeIf(s1 -> !s1.endsWith("/"));
+ return list;
+ }
+
+ @Override
+ public String map(CommandSender commandSender, String[] previousArguments, String s) {
+ return s;
+ }
+ };
+ }
+
+ public static TypeMapper stringMapper() {
+ return new TypeMapper() {
+ @Override
+ public List tabCompletes(CommandSender commandSender, String[] strings, String s) {
+ List list = SchematicNode.getNodeTabcomplete(getUser((Player) commandSender), s);
+ list.add(s);
+ return list;
+ }
+
+ @Override
+ public String map(CommandSender commandSender, String[] previousArguments, String s) {
+ return s;
+ }
+ };
+ }
+
+ public static TypeMapper typeTypeMapper() {
+ return new TypeMapper() {
+ @Override
+ public List tabCompletes(CommandSender commandSender, String[] strings, String s) {
+ return SchematicType.values().stream().filter(SchematicType::isAssignable).map(SchematicType::name).collect(Collectors.toList());
+ }
+
+ @Override
+ public SchematicType map(CommandSender commandSender, String[] previousArguments, String s) {
+ return SchematicType.values().stream().filter(type -> type.name().equals(s)).collect(Collectors.toList()).get(0);
+ }
+ };
+ }
+
+ public static TypeMapper nodeTypeMapper() {
+ return new TypeMapper() {
+ @Override
+ public List tabCompletes(CommandSender commandSender, String[] strings, String s) {
+ return SchematicNode.getNodeTabcomplete(getUser((Player) commandSender), s);
+ }
+
+ @Override
+ public SchematicNode map(CommandSender commandSender, String[] previousArguments, String s) {
+ return SchematicNode.getNodeFromPath(getUser((Player) commandSender), s);
+ }
+ };
+ }
+
+ public static TypeMapper checkSchemTypeTypeMapper() {
+ return new TypeMapper() {
+ @Override
+ public Collection tabCompletes(CommandSender commandSender, String[] strings, String s) {
+ return SchematicType.values().stream().filter(type -> CheckSchemType.get(type) != null).map(SchematicType::name).collect(Collectors.toList());
+ }
+
+ @Override
+ public CheckSchemType map(CommandSender commandSender, String[] previousArguments, String s) {
+ return SchematicType.values().stream().filter(type -> type.name().equalsIgnoreCase(s)).map(CheckSchemType::get).findAny().orElse(null);
+ }
+ };
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicValidator.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicValidator.java
new file mode 100644
index 00000000..e6bff1dd
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicValidator.java
@@ -0,0 +1,94 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.commands.schematiccommand;
+
+import de.steamwar.command.AbstractSWCommand;
+import de.steamwar.command.AbstractValidator;
+import de.steamwar.command.TypeValidator;
+import de.steamwar.sql.SchematicNode;
+import de.steamwar.sql.SteamwarUser;
+import org.bukkit.entity.Player;
+
+public class SchematicValidator {
+
+ private static boolean nodeNullCheck(AbstractValidator.MessageSender messageSender, SchematicNode node) {
+ if (node == null) {
+ messageSender.send("COMMAND_INVALID_NODE");
+ return false;
+ }
+ return true;
+ }
+
+ public static TypeValidator isSchemValidator() {
+ return (commandSender, schematicNode, messageSender) -> {
+ if(!nodeNullCheck(messageSender, schematicNode)) {
+ return false;
+ }
+ if(schematicNode.isDir()) {
+ messageSender.send("COMMAND_MUST_SCHEM");
+ return false;
+ }
+ return true;
+ };
+ }
+
+ public static TypeValidator isDirValidator() {
+ return (commandSender, schematicNode, messageSender) -> {
+ if(!nodeNullCheck(messageSender, schematicNode)) {
+ return false;
+ }
+ if(!schematicNode.isDir()) {
+ messageSender.send("COMMAND_MUST_DIR");
+ return false;
+ }
+ return true;
+ };
+ }
+
+ public static TypeValidator isOwnerValidator() {
+ return (commandSender, schematicNode, messageSender) -> {
+ if(!nodeNullCheck(messageSender, schematicNode)) {
+ return false;
+ }
+ if(schematicNode.getOwner() != SteamwarUser.get(((Player) commandSender).getUniqueId()).getId()) {
+ messageSender.send("COMMAND_NOT_OWN");
+ return false;
+ }
+ return true;
+ };
+ }
+
+ public static TypeValidator isOwnerSchematicValidator() {
+ return (commandSender, schematicNode, messageSender) -> {
+ if(!nodeNullCheck(messageSender, schematicNode)) {
+ return false;
+ }
+ if(schematicNode.getOwner() != SchematicCommandUtils.getUser((Player) commandSender).getId()) {
+ messageSender.send("COMMAND_NOT_OWN");
+ return false;
+ }
+ if(schematicNode.isDir()) {
+ messageSender.send("COMMAND_MUST_SCHEM");
+ return false;
+ }
+ return true;
+ };
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/CheckPart.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/CheckPart.java
new file mode 100644
index 00000000..9f23a795
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/CheckPart.java
@@ -0,0 +1,119 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.commands.schematiccommand.parts;
+
+import com.sk89q.worldedit.*;
+import com.sk89q.worldedit.bukkit.BukkitPlayer;
+import com.sk89q.worldedit.bukkit.BukkitWorld;
+import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
+import com.sk89q.worldedit.extent.clipboard.Clipboard;
+import com.sk89q.worldedit.session.ClipboardHolder;
+import de.steamwar.command.AbstractSWCommand;
+import de.steamwar.command.SWCommand;
+import de.steamwar.core.Core;
+import de.steamwar.schematicsystem.CheckSchemType;
+import de.steamwar.schematicsystem.SchematicSystem;
+import de.steamwar.schematicsystem.autocheck.AutoChecker;
+import de.steamwar.schematicsystem.autocheck.AutoCheckerResult;
+import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommand;
+import de.steamwar.sql.SchematicData;
+import de.steamwar.sql.SchematicNode;
+import org.bukkit.entity.Player;
+
+import java.io.IOException;
+import java.util.logging.Level;
+
+import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.check;
+import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommand.impl;
+
+@AbstractSWCommand.PartOf(SchematicCommand.class)
+public class CheckPart extends SWCommand {
+ public CheckPart() {
+ super(null);
+ }
+
+ @Register("check")
+ public void checkCommand(Player player, @Validator("isOwnerSchematicValidator") SchematicNode node, CheckSchemType type) {
+ try {
+ check(player, new SchematicData(node).load(), type, node.getName(), false);
+ } catch (IOException e) {
+ SchematicSystem.MESSAGE.send("UTIL_LOAD_ERROR", player);
+ }
+ }
+
+ @Register(value = {"check", "clipboard"})
+ public void checkClipboardCommand(Player player, @ErrorMessage("UTIL_CHECK_TYPE_NOT_FOUND") CheckSchemType type) {
+ try {
+ check(player, WorldEdit.getInstance().getSessionManager().findByName(player.getName()).getClipboard().getClipboard(), type, "clipboard", false);
+ } catch (EmptyClipboardException e) {
+ SchematicSystem.MESSAGE.send("COMMAND_CHECK_CLIPBOARD_EMPTY", player);
+ }
+ }
+
+ @Register(value = {"check", "selection"})
+ public void checkSelectionCommand(Player player, @ErrorMessage("UTIL_CHECK_TYPE_NOT_FOUND") CheckSchemType type) {
+ try {
+ Clipboard clipboard = new BlockArrayClipboard(WorldEdit.getInstance().getSessionManager().findByName(player.getName()).getSelection(new BukkitWorld(player.getWorld())));
+ EditSession editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession(new BukkitWorld(player.getWorld()), -1);
+
+ impl.createCopy(editSession, clipboard);
+
+ check(player, clipboard, type, "selection", false);
+ } catch (IncompleteRegionException e) {
+ SchematicSystem.MESSAGE.send("COMMAND_CHECK_SELECTION_INCOMPLETE", player);
+ } catch (WorldEditException e) {
+ SchematicSystem.MESSAGE.send("COMMAND_SAVE_ERROR", player);
+ }
+ }
+
+ @Register("fix")
+ public void fixSchematicCommand(Player player, @ErrorMessage("UTIL_CHECK_TYPE_NOT_FOUND") CheckSchemType type) {
+ if(Core.getVersion() < 15) {
+ SchematicSystem.MESSAGE.send("COMMAND_FIX_WRONG_VERSION", player);
+ return;
+ }
+ Clipboard clipboard;
+ try {
+ clipboard = WorldEdit.getInstance().getSessionManager().findByName(player.getName()).getClipboard().getClipboard();
+ } catch (EmptyClipboardException e) {
+ SchematicSystem.MESSAGE.send("COMMAND_CHECK_CLIPBOARD_EMPTY", player);
+ return;
+ }
+ AutoCheckerResult result = AutoChecker.check(clipboard, type);
+ if(result.isOk()) {
+ SchematicSystem.MESSAGE.send("COMMAND_FIX_OK", player);
+ return;
+ }
+ try {
+ clipboard = impl.fixClipboard(clipboard, result, type);
+ WorldEdit.getInstance().getSessionManager().get(new BukkitPlayer(player)).setClipboard(new ClipboardHolder(clipboard));
+ AutoCheckerResult after = AutoChecker.check(clipboard, type);
+ if(after.isOk()) {
+ SchematicSystem.MESSAGE.send("COMMAND_FIX_DONE", player);
+ } else {
+ after.sendErrorMessage(player, SchematicSystem.MESSAGE.parse("COMMAND_FIX_MANUAL", player));
+ SchematicSystem.MESSAGE.send("COMMAND_FIX_COULD_NOT_FIX", player);
+ }
+ } catch (Exception e) {
+ SchematicSystem.MESSAGE.send("COMMAND_FIX_ERROR", player);
+ SchematicSystem.getInstance().getLogger().log(Level.SEVERE, e.getMessage(), e);
+ }
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/MemberPart.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/MemberPart.java
new file mode 100644
index 00000000..f7f09ac3
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/MemberPart.java
@@ -0,0 +1,173 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.commands.schematiccommand.parts;
+
+import de.steamwar.command.AbstractSWCommand;
+import de.steamwar.command.SWCommand;
+import de.steamwar.schematicsystem.SchematicSystem;
+import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommand;
+import de.steamwar.sql.*;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.getUser;
+import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.mkdirs;
+
+@AbstractSWCommand.PartOf(SchematicCommand.class)
+public class MemberPart extends SWCommand {
+ public MemberPart() {
+ super(null);
+ }
+
+ @Register("addmember")
+ public void addMember(Player player, @Validator("isOwnerValidator") SchematicNode node, SteamwarUser... targets) {
+ SteamwarUser user = getUser(player);
+ if(Punishment.isPunished(user, Punishment.PunishmentType.NoSchemSharing, punishment -> SchematicSystem.MESSAGE.send("COMMAND_ADD_PUNISH", player, punishment.getReason()))) {
+ return;
+ }
+ List added = new ArrayList<>();
+ for (SteamwarUser target: targets) {
+ if(Punishment.isPunished(target,
+ Punishment.PunishmentType.NoSchemReceiving,
+ punishment -> SchematicSystem.MESSAGE.send("COMMAND_ADD_USER_PUNISHED", player, target.getUserName()))) {
+ continue;
+ }
+
+ if (user.getId() == target.getId()) {
+ SchematicSystem.MESSAGE.send("COMMAND_ADD_OWN", player);
+ continue;
+ }
+
+ if (target.getId() == 0) {
+ SchematicSystem.MESSAGE.send("COMMAND_ADD_PUBLIC", player);
+ continue;
+ }
+
+ if (NodeMember.getNodeMember(node.getId(), target.getId()) != null) {
+ SchematicSystem.MESSAGE.send("COMMAND_ADD_ALREADY", player, target.getUserName());
+ continue;
+ }
+
+ NodeMember.createNodeMember(node.getId(), target.getId());
+ added.add(target);
+
+ Player t = Bukkit.getPlayer(target.getUUID());
+ if (t != null) {
+ SchematicSystem.MESSAGE.send("COMMAND_ADD_ADDED", t, node.generateBreadcrumbs(), player.getName());
+ }
+ }
+
+ Optional reduced = added.stream().map(SteamwarUser::getUserName).reduce((s, s2) -> s + ", " + s2);
+ if (reduced.isPresent()) {
+ SchematicSystem.MESSAGE.send(added.size()>1?"COMMAND_ADD_MANY":"COMMAND_ADD_ONE", player, reduced.get());
+ } else {
+ SchematicSystem.MESSAGE.send("COMMAND_ADD_NONE", player);
+ }
+ }
+
+ @Register("delmember")
+ public void delMember(Player player, @Validator("isOwnerValidator") SchematicNode node, @Mapper("memberMapper") NodeMember member) {
+ SteamwarUser user = getUser(player);
+ SteamwarUser target = SteamwarUser.get(member.getMember());
+
+ List nodes = SchematicNode.deepGet(node.getId(), node1 -> node1.getOwner() != user.getId());
+ if (!nodes.isEmpty()) {
+ for (SchematicNode schematicNode : nodes) {
+ SchematicNode newNode = mkdirs(schematicNode.generateBreadcrumbs().split("/"), target, 1);
+ if(SchematicNode.getSchematicNode(schematicNode.getName(), newNode == null ? 0 : newNode.getId()) != null) {
+ schematicNode.setName(schematicNode.getName() + "-" + Instant.now().getEpochSecond() % 1000);
+ }
+ schematicNode.setParent(newNode == null ? null : newNode.getId());
+ }
+ }
+
+ member.delete();
+ SchematicSystem.MESSAGE.send("COMMAND_DELMEM_DONE", player, target.getUserName(), node.generateBreadcrumbs());
+
+ Player t = Bukkit.getPlayer(target.getUUID());
+ if (t != null) {
+ SchematicSystem.MESSAGE.send("COMMAND_DELMEM_DELETED", t, node.getName(), player.getName());
+ }
+ }
+
+ @Register("addteam")
+ public void addTeam(Player player, @Validator("isOwnerValidator") SchematicNode node) {
+ SteamwarUser user = getUser(player);
+ Team team = Team.get(user.getTeam());
+ if (team == null || team.getTeamId() == 0) {
+ SchematicSystem.MESSAGE.send("COMMAND_ADD_TEAM_NOT_IN_TEAM", player);
+ return;
+ }
+
+ addMember(player, node, team.getMembers().stream().map(SteamwarUser::get).filter(steamwarUser -> steamwarUser.getId() != user.getId()).toArray(SteamwarUser[]::new));
+ }
+
+ @Register("delteam")
+ public void remTeam(Player player, @Validator("isOwnerValidator") SchematicNode node) {
+ SteamwarUser user = getUser(player);
+ Team team = Team.get(user.getTeam());
+ if (team == null || team.getTeamId() == 0) {
+ SchematicSystem.MESSAGE.send("COMMAND_DEL_TEAM_NOT_IN_TEAM", player);
+ return;
+ }
+
+ List removed = new ArrayList<>();
+ for (Integer member : team.getMembers()) {
+ if (user.getId() == member) continue;
+ NodeMember nodeMember = NodeMember.getNodeMember(node.getId(), member);
+ if (nodeMember != null) {
+ nodeMember.delete();
+ removed.add(SteamwarUser.get(member).getUserName());
+ }
+ }
+
+ Optional reduced = removed.stream().reduce((s, s2) -> s + ", " + s2);
+ if (reduced.isPresent()) {
+ SchematicSystem.MESSAGE.send("COMMAND_DEL_TEAM_DONE", player, reduced.get());
+ } else {
+ SchematicSystem.MESSAGE.send("COMMAND_DEL_TEAM_NONE", player);
+ }
+ }
+
+ @Register("clearmember")
+ public void clearMember(Player player, @Validator("isOwnerValidator") SchematicNode node) {
+ node.getMembers().forEach(NodeMember::delete);
+ SchematicSystem.MESSAGE.send("COMMAND_CLEAR_MEMBER_DONE", player);
+ }
+
+ @Register("delallmember")
+ public void delAllMember(Player player, SteamwarUser target) {
+ SteamwarUser user = getUser(player);
+ int i = 0;
+ for (NodeMember nodeMember : NodeMember.getSchematics(target.getId())) {
+ SchematicNode node = SchematicNode.getSchematicNode(nodeMember.getNode());
+ if (node.getOwner() == user.getId()) {
+ nodeMember.delete();
+ i++;
+ }
+ }
+ SchematicSystem.MESSAGE.send("COMMAND_DEL_ALL_MEMBER", player, target.getUserName(), i);
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/ModifyPart.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/ModifyPart.java
new file mode 100644
index 00000000..cee2cbc3
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/ModifyPart.java
@@ -0,0 +1,186 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.commands.schematiccommand.parts;
+
+import com.sk89q.worldedit.extent.clipboard.Clipboard;
+import de.steamwar.command.AbstractSWCommand;
+import de.steamwar.command.SWCommand;
+import de.steamwar.schematicsystem.CheckSchemType;
+import de.steamwar.schematicsystem.SafeSchematicNode;
+import de.steamwar.schematicsystem.SchematicSystem;
+import de.steamwar.schematicsystem.autocheck.AutoChecker;
+import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils;
+import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommand;
+import de.steamwar.sql.*;
+import net.md_5.bungee.api.ChatColor;
+import net.md_5.bungee.api.chat.ClickEvent;
+import net.md_5.bungee.api.chat.HoverEvent;
+import net.md_5.bungee.api.chat.TextComponent;
+import org.bukkit.entity.Player;
+
+import java.io.IOException;
+
+import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.*;
+
+@AbstractSWCommand.PartOf(SchematicCommand.class)
+public class ModifyPart extends SWCommand {
+ public ModifyPart() {
+ super(null);
+ }
+
+ @Register("changetype")
+ public void changeType(Player player, @Validator("isOwnerSchematicValidator") SchematicNode node) {
+ TextComponent base = new TextComponent();
+
+ Clipboard clipboard = null;
+ try {
+ clipboard = new SchematicData(node).load();
+ } catch (IOException ignored) { }
+
+ Clipboard finalClipboard = clipboard;
+
+ String breadcrumb = node.generateBreadcrumbs();
+
+ SchematicType.values().parallelStream()
+ .filter(SchematicType::isAssignable)
+ .filter(type -> finalClipboard == null || CheckSchemType.get(type) == null || AutoChecker.sizeCheck(finalClipboard, CheckSchemType.get(type)).fastOk())
+ .forEach(type -> {
+ TextComponent component = new TextComponent(type.name() + " ");
+ component.setColor(ChatColor.GRAY);
+ component.setBold(true);
+ component.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.fromLegacyText(SchematicSystem.MESSAGE.parse("COMMAND_CHANGE_TYPE_SELECT", player))));
+ component.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem changetype " + breadcrumb + " " + type.name()));
+ base.addExtra(component);
+ });
+
+ player.spigot().sendMessage(base);
+ }
+
+ @Register("changetype")
+ public void changeType(Player player, @Validator("isOwnerSchematicValidator") SchematicNode node, SchematicType type) {
+ changeType(player, node, type, null);
+ }
+
+ @Register("changetype")
+ public void changeType(Player player, @Validator("isOwnerSchematicValidator") SchematicNode node, SchematicType type, SchematicCommand.Extend extend) {
+ SchematicCommandUtils.changeType(player, node, type, extend);
+ }
+
+ @Register("move")
+ public void moveToNull(Player player, @ErrorMessage("COMMAND_INVALID_NODE") SchematicNode node) {
+ move(player, node, "/");
+ }
+
+ @Register("move")
+ public void move(Player player, @ErrorMessage("COMMAND_INVALID_NODE") SchematicNode node, @Mapper("dirStringMapper") String name) {
+ SteamwarUser user = getUser(player);
+
+ if (name.equals("/")) {
+ if(node.getOwner() == user.getId()) {
+ node.setParent(null);
+ } else if(NodeMember.getNodeMember(node.getId(), user.getId()) != null) {
+ NodeMember member = NodeMember.getNodeMember(node.getId(), user.getId());
+ member.setParentId(null);
+ } else {
+ SchematicSystem.MESSAGE.send("COMMAND_NOT_OWN", player);
+ return;
+ }
+ } else {
+ if (name.startsWith("/")) name = name.substring(1);
+ if (name.endsWith("/")) name = name.substring(0, name.length() - 1);
+ String[] layers = name.split("/");
+ if (invalidSchemName(player, layers)) return;
+ SchematicNode newNode = mkdirs(layers, user, 0);
+ if(SchematicNode.parentsOfNode(user, newNode.getId()).stream().anyMatch(n -> n.getId() == node.getId())) {
+ SchematicSystem.MESSAGE.send("COMMAND_MOVE_RECURSIVE", player);
+ return;
+ }
+
+ if(node.getOwner() == user.getId()) {
+ SafeSchematicNode.Result result = SafeSchematicNode.setParent(user, node, newNode);
+ if(!result.isSuccessful()) {
+ result.sendError(player);
+ return;
+ }
+ } else if(NodeMember.getNodeMember(node.getId(), user.getId()) != null) {
+ NodeMember member = NodeMember.getNodeMember(node.getId(), user.getId());
+ member.setParentId(newNode.getId());
+ } else {
+ SchematicSystem.MESSAGE.send("COMMAND_NOT_OWN", player);
+ return;
+ }
+ }
+ SchematicSystem.MESSAGE.send("COMMAND_MOVE_DONE", player, SchematicNode.byIdAndUser(user, node.getId()).generateBreadcrumbs());
+ }
+
+ @Register("rename")
+ public void rename(Player player, @Validator("isOwnerValidator") SchematicNode node, String name) {
+ SteamwarUser user = getUser(player);
+ if (invalidSchemName(player, new String[]{name})) {
+ return;
+ }
+ SafeSchematicNode.Result result = SafeSchematicNode.setName(user, node, name);
+ if (!result.isSuccessful()) {
+ result.sendError(player);
+ return;
+ }
+ SchematicSystem.MESSAGE.send("COMMAND_RENAME_DONE", player, node.generateBreadcrumbs());
+ }
+
+ @Register("delete")
+ public void deleteSchem(Player player, SchematicNode node) {
+ SteamwarUser user = SteamwarUser.get(player.getUniqueId());
+ if (node.getOwner() != user.getId()) {
+ NodeMember member = NodeMember.getNodeMember(node.getId(), user.getId());
+ if (member == null) {
+ SchematicSystem.MESSAGE.send("COMMAND_DELETE_NOT_OWN", player);
+ return;
+ }
+ member.delete();
+ SchematicSystem.MESSAGE.send("COMMAND_DELETE_MEMBER", player);
+ return;
+ }
+
+ if (node.isDir()) {
+ if (SchematicNode.getSchematicNodeInNode(node).isEmpty()) {
+ SchematicSystem.MESSAGE.send("COMMAND_DELETE_DIR", player, node.generateBreadcrumbs());
+ node.delete();
+ } else {
+ SchematicSystem.MESSAGE.send("COMMAND_DELETE_DIR_FULL", player);
+ }
+ } else {
+ SchematicSystem.MESSAGE.send("COMMAND_DELETE_SCHEM", player, node.generateBreadcrumbs());
+ node.delete();
+ }
+ }
+
+ @Register("lockreplay")
+ public void lockreplay(Player player, @Validator("isOwnerSchematicValidator") SchematicNode node) {
+ node.setAllowReplay(false);
+ SchematicSystem.MESSAGE.send("COMMAND_LOCKREPLAY", player, node.getName());
+ }
+
+ @Register("replacecolor")
+ public void replacecolor(Player player, @Validator("isOwnerSchematicValidator") SchematicNode node) {
+ boolean state = !node.replaceColor();
+ node.setReplaceColor(state);
+ SchematicSystem.MESSAGE.send(state?"COMMAND_REPLACE_COLOR_ON":"COMMAND_REPLACE_COLOR_OFF", player, node.getName());
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/SavePart.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/SavePart.java
new file mode 100644
index 00000000..31695f73
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/SavePart.java
@@ -0,0 +1,133 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.commands.schematiccommand.parts;
+
+import de.steamwar.command.AbstractSWCommand;
+import de.steamwar.command.SWCommand;
+import de.steamwar.inventory.SWAnvilInv;
+import de.steamwar.inventory.SchematicSelector;
+import de.steamwar.providers.BauServerInfo;
+import de.steamwar.schematicsystem.SchematicSystem;
+import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommand;
+import de.steamwar.sql.*;
+import net.md_5.bungee.api.chat.ClickEvent;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+
+import java.util.logging.Level;
+
+import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.*;
+
+@AbstractSWCommand.PartOf(SchematicCommand.class)
+public class SavePart extends SWCommand {
+
+ public SavePart() {
+ super(null);
+ }
+
+ @Register("save")
+ @Register("s")
+ public void saveSchem(Player player) {
+ SchematicSelector selector = new SchematicSelector(player, SchematicSelector.selectSchematicNode(), schematicNode -> {
+ if(schematicNode == null || schematicNode.isDir()) {
+ SWAnvilInv anvilInv = new SWAnvilInv(player, SchematicSystem.MESSAGE.parse("COMMAND_ENTER_NAME", player));
+ anvilInv.setCallback(s -> saveSchem(player, schematicNode==null?s:(schematicNode.generateBreadcrumbs() + s), true));
+ anvilInv.setItem(Material.CAULDRON);
+ anvilInv.open();
+ } else {
+ saveSchem(player, schematicNode.generateBreadcrumbs(), true);
+ }
+ });
+ selector.setSingleDirOpen(false);
+ selector.open();
+ }
+
+ @Register("save")
+ @Register("s")
+ public void saveSchem(Player player, @AbstractSWCommand.Mapper("stringMapper") String name, @AbstractSWCommand.StaticValue(value = {"", "-f"}, allowISE=true) @AbstractSWCommand.OptionalValue("") boolean overwrite) {
+ SteamwarUser user = getUser(player);
+ if(BauServerInfo.isBauServer() && BauServerInfo.getOwnerId() != user.getId() &&
+ (Punishment.isPunished(user, Punishment.PunishmentType.NoSchemReceiving, punishment ->
+ SchematicSystem.MESSAGE.send("COMMAND_PUNISHMENT_NO_SAVE_EXTERNAL", player)) ||
+ Punishment.isPunished(SteamwarUser.get(BauServerInfo.getOwnerId()), Punishment.PunishmentType.NoSchemSharing, punishment ->
+ SchematicSystem.MESSAGE.send("COMMAND_PUNISHMENT_NO_SAVE", player)))) {
+ return;
+ }
+ if (name.endsWith("/")) {
+ SchematicSystem.MESSAGE.send("COMMAND_SAVE_NO_NAME", player);
+ return;
+ }
+ if (name.startsWith("/")) name = name.substring(1);
+ String[] layers = name.split("/");
+ if (invalidSchemName(player, layers)) return;
+ SchematicNode currentNode = mkdirs(layers, user, 1);
+
+ SchematicNode node = SchematicNode.getNodeFromPath(user, String.join("/", layers));
+ if (node != null) {
+ if(node.isDir()) {
+ SchematicSystem.MESSAGE.send("COMMAND_SAVE_FOLDER", player);
+ return;
+ } else if (!node.getSchemtype().writeable() || node.getOwner() != user.getId()) {
+ SchematicSystem.MESSAGE.send("COMMAND_SAVE_NO_OVERWRITE", player);
+ return;
+ } else if(!overwrite) {
+ SchematicSystem.MESSAGE.send("COMMAND_SAVE_OVERWRITE_CONFIRM", player, SchematicSystem.MESSAGE.parse("COMMAND_SAVE_OVERWRITE_CONFIRM_HOVER", player), new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem s " + name + " -f"), node.generateBreadcrumbs());
+ return;
+ }
+ }
+
+ boolean newSchem = false;
+ if (node == null) {
+ newSchem = true;
+ node = SchematicNode.createSchematic(user.getId(), layers[layers.length - 1], currentNode == null ? 0 : currentNode.getId());
+ }
+
+ try {
+ new SchematicData(node).saveFromPlayer(player);
+ } catch (NoClipboardException e) {
+ SchematicSystem.MESSAGE.send("COMMAND_SAVE_CLIPBOARD_EMPTY", player);
+ if (newSchem)
+ node.delete();
+ return;
+ } catch (Exception ex) {
+ Bukkit.getLogger().log(Level.SEVERE, "Could not save schematic", ex);
+ SchematicSystem.MESSAGE.send("COMMAND_SAVE_ERROR", player);
+ if (newSchem)
+ node.delete();
+ return;
+ }
+
+ SchematicSystem.MESSAGE.send(newSchem?"COMMAND_SAVE_DONE":"COMMAND_SAVE_OVERWRITE", player, node.generateBreadcrumbs());
+ }
+
+ @Register("dir")
+ @Register("ordner")
+ @Register("mkdir")
+ public void mkdir(Player player, @Mapper("dirStringMapper") String name) {
+ SteamwarUser user = getUser(player);
+ if (name.startsWith("/")) name = name.substring(1);
+ if (name.endsWith("/")) name = name.substring(0, name.length() - 1);
+ String[] layers = name.split("/");
+ if (invalidSchemName(player, layers)) return;
+ SchematicNode node = mkdirs(layers, user, 0);
+ SchematicSystem.MESSAGE.send("COMMAND_DIR_DONE", player, node.generateBreadcrumbs());
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/SearchPart.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/SearchPart.java
new file mode 100644
index 00000000..00dfd850
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/SearchPart.java
@@ -0,0 +1,184 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.commands.schematiccommand.parts;
+
+import de.steamwar.command.*;
+import de.steamwar.schematicsystem.SchematicSystem;
+import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils;
+import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommand;
+import de.steamwar.sql.SchematicNode;
+import de.steamwar.sql.SchematicType;
+import de.steamwar.sql.SteamwarUser;
+import org.bukkit.Material;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.createCachedSchemList;
+import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.getUser;
+
+@AbstractSWCommand.PartOf(SchematicCommand.class)
+public class SearchPart extends SWCommand {
+
+ private static final Map> searchMapper = new HashMap<>();
+
+
+ static {
+ searchMapper.put("-type", SWCommandUtils.createMapper(SchematicType.values().stream().map(SchematicType::name).toArray(String[]::new)));
+ searchMapper.put("-owner", SWCommandUtils.createMapper(Function.identity(), (commandSender, s) -> Collections.singletonList(s)));
+ Class> clazz = Material.class;
+ searchMapper.put("-item", SWCommandUtils.createEnumMapper((Class>) clazz));
+ searchMapper.put("-public", null);
+ searchMapper.put("-ignoreCase", null);
+ searchMapper.put("-exclude", SWCommandUtils.createMapper(Function.identity(), (commandSender, s) -> Collections.singletonList(s)));
+ searchMapper.put("-excludeType", SWCommandUtils.createMapper(SchematicType.values().stream().map(SchematicType::name).toArray(String[]::new)));
+ searchMapper.put("-excludeOwner", SWCommandUtils.createMapper(Function.identity(), (commandSender, s) -> Collections.singletonList(s)));
+ }
+
+ public SearchPart() {
+ super(null);
+ }
+
+ public boolean containsCheckCase(String s, String s2, AtomicBoolean isIgnoreCase) {
+ if (isIgnoreCase.get()) {
+ return s.toLowerCase().contains(s2.toLowerCase());
+ }
+ return s.contains(s2);
+ }
+
+ @Register("search")
+ public void schemSearch(Player player, @OptionalValue("1") int page, @Mapper("searchMapper") String... query) {
+ SteamwarUser user = getUser(player);
+ int userId = user.getId();
+ List> predicates = new ArrayList<>();
+ List nameList = new ArrayList<>();
+ int i = 0;
+ AtomicBoolean isIgnoreCase = new AtomicBoolean(false);
+ while (i < query.length) {
+ String current = query[i];
+ if (searchMapper.containsKey(current)) {
+ if (searchMapper.get(current) == null) {
+ switch (current) {
+ case "-public":
+ userId = 0;
+ break;
+ case "-ignoreCase":
+ isIgnoreCase.set(true);
+ break;
+ default:
+ throw new IllegalStateException("Unexpected value: " + current);
+ }
+ } else if (i + 1 < query.length) {
+ int finalI = i;
+ switch (current) {
+ case "-type":
+ predicates.add(node -> !node.isDir() && node.getSchemtype().name().equalsIgnoreCase(query[finalI + 1]));
+ break;
+ case "-item":
+ predicates.add(node -> node.getItem().equalsIgnoreCase(query[finalI + 1]));
+ break;
+ case "-owner":
+ SteamwarUser steamwarUser = SteamwarUser.get(query[finalI + 1]);
+ if (steamwarUser == null) {
+ SchematicSystem.MESSAGE.send("COMMAND_SEARCH_NOT_A_PLAYER", player, query[finalI + 1]);
+ return;
+ }
+ predicates.add(node -> node.getOwner() == steamwarUser.getId());
+ break;
+ case "-exclude":
+ predicates.add(node -> !node.getName().contains(query[finalI + 1]));
+ break;
+ case "-excludeType":
+ predicates.add(node -> !node.isDir() && !node.getSchemtype().name().equalsIgnoreCase(query[finalI + 1]));
+ break;
+ case "-excludeOwner":
+ SteamwarUser steamwarUser1 = SteamwarUser.get(query[finalI + 1]);
+ if (steamwarUser1 == null) {
+ SchematicSystem.MESSAGE.send("COMMAND_SEARCH_NOT_A_PLAYER", player, query[finalI + 1]);
+ return;
+ }
+ predicates.add(node -> node.getOwner() != steamwarUser1.getId());
+ break;
+ default:
+ throw new IllegalStateException("Unexpected value: " + current);
+ }
+ i++;
+ }
+ } else {
+ predicates.add(node -> containsCheckCase(node.getName(), current, isIgnoreCase));
+ nameList.add(current);
+ }
+ i++;
+ }
+
+ List nodes = SchematicNode.getAll(SteamwarUser.get(userId)).stream().filter(node -> {
+ for (Predicate predicate : predicates) {
+ if (!predicate.test(node)) {
+ return false;
+ }
+ }
+ return true;
+ }).collect(Collectors.toList());
+ createCachedSchemList(player, nodes, Math.max(page - 1, 0), null, SchematicCommandUtils.SchematicListBehavior.builder().setPublics(userId == 0).setShowPath(false).setRenderHook(s -> {
+ for (String ss : nameList) {
+ s = s.replace(ss, "§e§l" + ss + "§7");
+ }
+ return "§7" + s;
+ }).setNonCachedBreadcrumbs(true).build());
+ }
+
+ @Mapper(value = "searchMapper", local = true)
+ public TypeMapper searchTypeMapper() {
+ return new TypeMapper() {
+ @Override
+ public String map(CommandSender commandSender, String[] previousArguments, String s) {
+ return s;
+ }
+
+ @Override
+ public Collection tabCompletes(CommandSender commandSender, String[] strings, String s) {
+ if (strings.length == 0) {
+ List list = new ArrayList<>();
+ list.add(s);
+ list.addAll(searchMapper.keySet());
+ return list;
+ }
+ String last = strings[strings.length - 1];
+ if (searchMapper.containsKey(last)) {
+ AbstractTypeMapper mapper = searchMapper.get(last);
+ if (mapper == null) {
+ List list = new ArrayList<>(searchMapper.keySet());
+ list.add(s);
+ return list;
+ }
+ return mapper.tabCompletes(commandSender, strings, s);
+ }
+ List list = new ArrayList<>(searchMapper.keySet());
+ list.add(s);
+ return list;
+ }
+ };
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/ViewPart.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/ViewPart.java
new file mode 100644
index 00000000..60146d4e
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/ViewPart.java
@@ -0,0 +1,98 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.commands.schematiccommand.parts;
+
+import de.steamwar.command.AbstractSWCommand;
+import de.steamwar.command.SWCommand;
+import de.steamwar.schematicsystem.commands.schematiccommand.GUI;
+import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils;
+import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommand;
+import de.steamwar.sql.SchematicNode;
+import de.steamwar.sql.SteamwarUser;
+import org.bukkit.entity.Player;
+
+import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.*;
+
+@AbstractSWCommand.PartOf(SchematicCommand.class)
+public class ViewPart extends SWCommand {
+ public ViewPart() {
+ super(null);
+ }
+
+ @Register("list")
+ @Register({"list", "/"})
+ public void schemList(Player player, @OptionalValue(value = "1", onlyUINIG = true) int page) {
+ createCachedSchemList(player, SchematicNode.list(getUser(player), null), Math.max(page - 1, 0), null, SchematicCommandUtils.SchematicListBehavior.DEFAULT);
+ }
+
+ @Register({"list", "public"})
+ public void schemListPublic(Player player, @Validator("isDirValidator") @Mapper("publicDirMapper") SchematicNode node, @OptionalValue("1") int page) {
+ schemList(player, node, page);
+ }
+
+ @Register({"list", "public"})
+ @Register({"list", "public", "/"})
+ public void schemListPublic(Player player, @OptionalValue(value = "1", onlyUINIG = true) int page) {
+ createCachedSchemList(player, SchematicNode.list(SteamwarUser.get(0), null), Math.max(page - 1, 0), null, SchematicCommandUtils.SchematicListBehavior.builder().setPublics(true).setPageCommandGen(integer -> "/schem list public " + integer).build());
+ }
+
+ @Register("list")
+ public void schemList(Player player, @Validator("isDirValidator") @Mapper("dirMapper") SchematicNode node, @OptionalValue("1") int page) {
+ SteamwarUser user = getUser(player);
+ createCachedSchemList(player, SchematicNode.list(user, node.getId()), Math.max(page - 1, 0), node, SchematicCommandUtils.SchematicListBehavior.builder().setPublics(node.getOwner() == 0).setPageCommandGen(value -> "/schem list " + (node.getOwner()==0?"public ":"") + node.generateBreadcrumbs() + " " + value).build());
+ }
+
+ @Register({"info", "public"})
+ public void schemInfoPublic(Player player, @Mapper("publicMapper") SchematicNode node) {
+ schemInfo(player, SchematicNode.getSchematicNode(node.getId()));
+ }
+
+ @Register("info")
+ public void schemInfo(Player player, @ErrorMessage("COMMAND_INVALID_NODE") SchematicNode node) {
+ printSchemInfo(player, node);
+ }
+
+ @Register(value = "page", noTabComplete = true)
+ public void pageCommand(Player player, int page) {
+ cachedSchemList(player, page);
+ }
+
+ @Register({"l", "public"})
+ @Register({"load", "public"})
+ public void loadSchemPublic(Player player, @Validator("isSchemValidator") @Mapper("publicMapper") SchematicNode node) {
+ loadSchem(player, node);
+ }
+
+ @Register("l")
+ @Register("load")
+ public void loadSchem(Player player, @Validator("isSchemValidator") SchematicNode node) {
+ SchematicCommandUtils.loadSchem(player, node);
+ }
+
+ @Register("gui")
+ public void gui(Player player) {
+ GUI.list(player);
+ }
+
+ @Register("download")
+ public void download(Player player, @Validator("isOwnerSchematicValidator") SchematicNode node) {
+ SchematicCommandUtils.download(player, node);
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/parts.info b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/parts.info
new file mode 100644
index 00000000..7dcd251a
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/parts.info
@@ -0,0 +1,28 @@
+CheckPart:
+ - fix
+ - check
+MemberPart:
+ - addmember
+ - delmember
+ - addteam
+ - delteam
+ - clearmember
+ - delallmember
+ModifyPart:
+ - changetype
+ - move
+ - rename
+ - delete
+ - lockreplay
+ - replacecolor
+SavePart:
+ - save
+ - ordner
+SearchPart:
+ - search
+ViewPart:
+ - list
+ - info
+ - load
+ - gui
+ - download
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/listener/PlayerEventListener.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/listener/PlayerEventListener.java
new file mode 100644
index 00000000..3afb8ddd
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/listener/PlayerEventListener.java
@@ -0,0 +1,33 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2023 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.listener;
+
+import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerQuitEvent;
+
+public class PlayerEventListener implements Listener {
+
+ @EventHandler
+ public void onPlayerQuit(PlayerQuitEvent event) {
+ SchematicCommandUtils.quitPlayer(event.getPlayer());
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/plugin.yml b/SchematicSystem/SchematicSystem_Core/src/plugin.yml
new file mode 100644
index 00000000..40e41e64
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/plugin.yml
@@ -0,0 +1,8 @@
+name: SchematicSystem
+version: "2.1.0"
+authors: [Yaruma3341, Lixfel, Chaoscaot]
+depend: [SpigotCore, WorldEdit]
+main: de.steamwar.schematicsystem.SchematicSystem
+website: steamwar.de
+api-version: "1.13"
+description: Schematic-Frontend
diff --git a/SchematicSystem/build.gradle.kts b/SchematicSystem/build.gradle.kts
new file mode 100644
index 00000000..0c2b5ae6
--- /dev/null
+++ b/SchematicSystem/build.gradle.kts
@@ -0,0 +1,50 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 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 {
+ id("java")
+ id("base")
+
+ id("com.github.johnrengelman.shadow")
+}
+
+group = "de.steamwar"
+version = ""
+
+tasks.compileJava {
+ options.encoding = "UTF-8"
+}
+
+tasks.build {
+ finalizedBy(tasks.shadowJar)
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+}
+
+dependencies {
+ compileOnly("org.projectlombok:lombok:1.18.32")
+ annotationProcessor("org.projectlombok:lombok:1.18.32")
+
+ implementation(project(":SchematicSystem:SchematicSystem_Core"))
+ implementation(project(":SchematicSystem:SchematicSystem_8"))
+ implementation(project(":SchematicSystem:SchematicSystem_15"))
+}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index cc7e386b..c143edd1 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -44,6 +44,11 @@ include("MissileWars")
include("Realtime")
+include("SchematicSystem")
+include("SchematicSystem:SchematicSystem_8")
+include("SchematicSystem:SchematicSystem_15")
+include("SchematicSystem:SchematicSystem_Core")
+
include("SpigotCore")
include("SpigotCore:CRIUDummy")
include("SpigotCore:SpigotCore_8")