From 227f63c9ffe00f1eba5ec9d3323eb42d3615eb5c Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Tue, 18 Aug 2026 10:39:58 +0200 Subject: [PATCH 01/22] Add AntiPlayerCollision --- .../features/world/AntiPlayerCollision.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/AntiPlayerCollision.java diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/AntiPlayerCollision.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/AntiPlayerCollision.java new file mode 100644 index 000000000..83b5df3ac --- /dev/null +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/AntiPlayerCollision.java @@ -0,0 +1,53 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2026 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bausystem.features.world; + +import de.steamwar.linkage.Linked; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.scoreboard.Scoreboard; +import org.bukkit.scoreboard.Team; + +@Linked +public class AntiPlayerCollision implements Listener { + + private static Team TEAM = getTeam(); + + private static Team getTeam() { + Scoreboard board = Bukkit.getScoreboardManager().getMainScoreboard(); + Team team = board.getTeam("players"); + if (team == null) team = board.registerNewTeam("players"); + team.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER); + return team; + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + TEAM.addPlayer(event.getPlayer()); + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + TEAM.removePlayer(event.getPlayer()); + } +} From cb744f6aa040be96bd4ab5b02999cd4db6554f43 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Tue, 18 Aug 2026 10:48:16 +0200 Subject: [PATCH 02/22] Add AntiPlayerCollision --- .../features/world/AntiPlayerCollision.java | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/AntiPlayerCollision.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/AntiPlayerCollision.java index 83b5df3ac..119dd65db 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/AntiPlayerCollision.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/AntiPlayerCollision.java @@ -20,34 +20,22 @@ package de.steamwar.bausystem.features.world; import de.steamwar.linkage.Linked; -import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.scoreboard.Scoreboard; import org.bukkit.scoreboard.Team; @Linked public class AntiPlayerCollision implements Listener { - private static Team TEAM = getTeam(); - - private static Team getTeam() { - Scoreboard board = Bukkit.getScoreboardManager().getMainScoreboard(); + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerJoin(PlayerJoinEvent event) { + Scoreboard board = event.getPlayer().getScoreboard(); Team team = board.getTeam("players"); if (team == null) team = board.registerNewTeam("players"); team.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER); - return team; - } - - @EventHandler - public void onPlayerJoin(PlayerJoinEvent event) { - TEAM.addPlayer(event.getPlayer()); - } - - @EventHandler - public void onPlayerQuit(PlayerQuitEvent event) { - TEAM.removePlayer(event.getPlayer()); + team.addPlayer(event.getPlayer()); } } From 8575dcac33f0d27d0769005ed98a7826c53ae246 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Wed, 19 Aug 2026 11:06:34 +0200 Subject: [PATCH 03/22] Add WindCharge option to LaunchScript --- .../misslewars/scripts/implemented/LaunchScript.java | 1 + .../de/steamwar/misslewars/scripts/utils/EntityUtils.java | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/MissileWars/src/de/steamwar/misslewars/scripts/implemented/LaunchScript.java b/MissileWars/src/de/steamwar/misslewars/scripts/implemented/LaunchScript.java index e6aa41ca6..9d7c42376 100644 --- a/MissileWars/src/de/steamwar/misslewars/scripts/implemented/LaunchScript.java +++ b/MissileWars/src/de/steamwar/misslewars/scripts/implemented/LaunchScript.java @@ -25,6 +25,7 @@ import de.steamwar.misslewars.scripts.RunnableScriptEvent; import de.steamwar.misslewars.scripts.ScriptedItem; import de.steamwar.misslewars.scripts.utils.EntityUtils; import de.steamwar.misslewars.scripts.utils.EntityUtils.ScriptShortcut; +import org.bukkit.Material; import org.bukkit.entity.Projectile; public class LaunchScript implements RunnableScript { diff --git a/MissileWars/src/de/steamwar/misslewars/scripts/utils/EntityUtils.java b/MissileWars/src/de/steamwar/misslewars/scripts/utils/EntityUtils.java index 72183fa93..9a6b03a41 100644 --- a/MissileWars/src/de/steamwar/misslewars/scripts/utils/EntityUtils.java +++ b/MissileWars/src/de/steamwar/misslewars/scripts/utils/EntityUtils.java @@ -75,6 +75,11 @@ public class EntityUtils { }); case "arrow": return new ScriptShortcut<>(Arrow.class, (jsonObject, entity, runnableScriptEvent) -> setProjectileOptions(entity, jsonObject)); + case "windcharge": + return new ScriptShortcut<>(WindCharge.class, (jsonObject, entity, runnableScriptEvent) -> { + setFireballOptions(entity, jsonObject); + entity.setDirection(runnableScriptEvent.getLocation().getDirection()); + }); } return null; } From 72b70a62e140758740b8a1f42ef72c6dafca3e52 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Wed, 19 Aug 2026 12:05:09 +0200 Subject: [PATCH 04/22] Fix CustomItem --- MissileWars/src/de/steamwar/misslewars/items/CustomItem.java | 1 + 1 file changed, 1 insertion(+) diff --git a/MissileWars/src/de/steamwar/misslewars/items/CustomItem.java b/MissileWars/src/de/steamwar/misslewars/items/CustomItem.java index 9f36760af..5ada1c6db 100644 --- a/MissileWars/src/de/steamwar/misslewars/items/CustomItem.java +++ b/MissileWars/src/de/steamwar/misslewars/items/CustomItem.java @@ -69,6 +69,7 @@ public class CustomItem extends SpecialItem { } for (File itemFile : Objects.requireNonNull(itemsFolder.listFiles())) { if (!itemFile.canRead() || !itemFile.isFile()) continue; + if (!itemFile.getName().endsWith(".json")) continue; try { JsonObject jsonObject = new JsonParser().parse(new FileReader(itemFile)).getAsJsonObject(); new CustomItem(new ScriptedItem(jsonObject)); From 5a52771ec10e2a569dfe963f5549f51157a2bb7f Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Mon, 24 Aug 2026 20:05:58 +0200 Subject: [PATCH 05/22] Improve items for GameModeConfig --- CommonCore/SQL/build.gradle.kts | 5 ++ .../src/de/steamwar/sql/GameModeConfig.java | 68 ++++++++++++++++--- .../SQL/src/de/steamwar/sql/SQLWrapper.java | 17 +++++ FightSystem/FightSystem_Core/src/config.yml | 21 +++++- .../src/SchematicSystem.properties | 2 +- .../src/SchematicSystem_de.properties | 2 +- .../autocheck/AutoChecker.java | 34 ++++------ .../autocheck/AutoCheckerItems.java | 51 -------------- .../autocheck/AutoCheckerResult.java | 34 +++++++--- .../schematiccommand/SchematicCommand.java | 19 ++++-- .../src/de/steamwar/sql/SQLWrapperImpl.java | 42 ++++++++++++ settings.gradle.kts | 6 ++ 12 files changed, 200 insertions(+), 101 deletions(-) delete mode 100644 SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems.java diff --git a/CommonCore/SQL/build.gradle.kts b/CommonCore/SQL/build.gradle.kts index 095287594..8706ecdfa 100644 --- a/CommonCore/SQL/build.gradle.kts +++ b/CommonCore/SQL/build.gradle.kts @@ -19,6 +19,7 @@ plugins { steamwar.kotlin + kotlin("plugin.lombok") } kotlin { @@ -40,4 +41,8 @@ dependencies { compileOnlyApi(libs.exposedDao) compileOnlyApi(libs.exposedJdbc) compileOnlyApi(libs.exposedTime) + testImplementation(kotlin("test")) } +repositories { + mavenCentral() +} \ No newline at end of file diff --git a/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java b/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java index 87c6bdb12..2676dad53 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java +++ b/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java @@ -688,13 +688,6 @@ public final class GameModeConfig { */ public final int MaxBlocks; - /** - * Maximal amount of items per dispenser - * - * @implSpec {@code 128} by default - */ - public final int MaxDispenserItems; - /** * Maximal blast resistance for the blocks * @@ -715,6 +708,42 @@ public final class GameModeConfig { */ public final Map, Integer> Limited; + /** + * Item amount limits per inventory (container) type.
+ * Key: inventory material (e.g. DISPENSER, CHEST, ...). Value: item material -> maximal + * amount of that item allowed to be stored in a single inventory of that type.
+ * An item is only allowed to be placed in an inventory at all if it appears here for that + * inventory's material and item. Every material returned by + * {@link SQLWrapper#getInventoryMaterials()} is always present as a key - with an empty value + * map if not explicitly configured - so every real container is always scanned by the schematic + * checker for forbidden contents, it just allows no items by default.
+ * Configured via the {@code ItemsInInventory} list, entries consisting of {@code Inventories} + * (list of inventory materials or group names - {@code storage} for + * {@link SQLWrapper#getStorageMaterials()}, {@code all} for every material from + * {@link SQLWrapper#getInventoryMaterials()}), {@code Items} (list of item materials, each + * checked independently against {@code Amount} - not summed) and {@code Amount}. + * + * @implSpec No item is allowed in any inventory unless configured here + */ + public final Map> ItemsInInventory; + + /** + * Resolves one {@code Inventories} entry to the concrete inventory materials it denotes: + * {@code storage} for {@link SQLWrapper#getStorageMaterials()}, {@code all} for + * {@link SQLWrapper#getInventoryMaterials()}, or the material itself otherwise. + */ + private Set expandInventoryGroup(YMLWrapper loader, String name) { + switch (name.toUpperCase()) { + case "STORAGE": + return (Set) SQLWrapper.impl.getStorageMaterials(); + case "ALL": + return (Set) SQLWrapper.impl.getInventoryMaterials(); + default: + M material = loader.materialMapper.apply(name.toUpperCase()); + return material != null ? Collections.singleton(material) : Collections.emptySet(); + } + } + private SchematicConfig(YMLWrapper loader) { loaded = loader.canLoad(); Size = new SizeConfig(loader.with("Size")); @@ -731,7 +760,6 @@ public final class GameModeConfig { IgnorePublicOnly = loader.getBoolean("IgnorePublicOnly", false); UnlimitedPrepare = loader.getBoolean("UnlimitedPrepare", false); MaxBlocks = loader.getInt("MaxBlocks", 0); - MaxDispenserItems = loader.getInt("MaxDispenserItems", 128); MaxBlastResistance = loader.getDouble("MaxBlastResistance", Double.MAX_VALUE); MaxDesignBlastResistance = loader.getDouble("MaxDesignBlastResistance", MaxBlastResistance); @@ -753,6 +781,30 @@ public final class GameModeConfig { }); this.Limited = Collections.unmodifiableMap(Limited); + Map> itemsInInventory = new HashMap<>(); + for (Map entry : loader.getMapList("ItemsInInventory")) { + int amount = (Integer) entry.get("Amount"); + List inventories = (List) entry.get("Inventories"); + List items = (List) entry.get("Items"); + for (String inventoryName : inventories) { + for (M inventoryMaterial : expandInventoryGroup(loader, inventoryName)) { + if (inventoryMaterial == null) continue; + Map itemCaps = itemsInInventory.computeIfAbsent(inventoryMaterial, m -> new HashMap<>()); + for (String itemName : items) { + M itemMaterial = loader.materialMapper.apply(itemName.toUpperCase()); + if (itemMaterial == null) continue; + itemCaps.put(itemMaterial, amount); + } + } + } + } + for (M allMaterial : (Set) SQLWrapper.impl.getInventoryMaterials()) { + if (allMaterial == null) continue; + itemsInInventory.computeIfAbsent(allMaterial, m -> new HashMap<>()); + } + this.ItemsInInventory = Collections.unmodifiableMap(itemsInInventory.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> Collections.unmodifiableMap(e.getValue())))); + this.ReplacementsWithoutBlockUpdates = loader.getMap("ReplacementsWithoutBlockUpdates", loader.materialMapper, loader.materialMapper); this.ReplacementsWithBlockUpdates = loader.getMap("ReplacementsWithBlockUpdates", loader.materialMapper, loader.materialMapper); } diff --git a/CommonCore/SQL/src/de/steamwar/sql/SQLWrapper.java b/CommonCore/SQL/src/de/steamwar/sql/SQLWrapper.java index f049f6808..be52e8fbd 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/SQLWrapper.java +++ b/CommonCore/SQL/src/de/steamwar/sql/SQLWrapper.java @@ -24,6 +24,7 @@ import de.steamwar.ImplementationProvider; import java.io.File; import java.util.Collections; import java.util.List; +import java.util.Set; public interface SQLWrapper { SQLWrapper impl = ImplementationProvider.getImpl("de.steamwar.sql.SQLWrapperImpl"); @@ -36,5 +37,21 @@ public interface SQLWrapper { return Collections.emptyList(); } + /** + * Storage-type inventory materials (chests, barrels, shulker boxes of any color) - the + * {@code storage} group usable in {@code GameModeConfig}'s {@code ItemsInInventory}. + */ + default Set getStorageMaterials() { + return Collections.emptySet(); + } + + /** + * Every inventory material - the {@code all} group usable in {@code GameModeConfig}'s + * {@code ItemsInInventory}. Expected to be a superset of {@link #getStorageMaterials()}. + */ + default Set getInventoryMaterials() { + return Collections.emptySet(); + } + void additionalExceptionMetadata(StringBuilder builder); } diff --git a/FightSystem/FightSystem_Core/src/config.yml b/FightSystem/FightSystem_Core/src/config.yml index 185704d56..8987b88a9 100644 --- a/FightSystem/FightSystem_Core/src/config.yml +++ b/FightSystem/FightSystem_Core/src/config.yml @@ -107,8 +107,6 @@ Schematic: UnlimitedPrepare: false # defaults to false if missing # Maximal amount of blocks allowed in the schematic MaxBlocks: 0 # defaults to 0 (ignored) if missing - # Maximal amount of items per dispenser - MaxDispenserItems: 128 # defaults to 128 if missing # Maximal blast resistance for the design blocks MaxDesignBlastResistance: 100000000 # defaults to Double.MAX_VALUE if missing # List of limited material (combinations) @@ -116,6 +114,25 @@ Schematic: Limited: - Materials: [ ] Amount: 0 + # Item amount limits per inventory (container) type. + # An item is only allowed to be placed in an inventory at all if it appears here for that + # inventory's material (a small set of decorative items, e.g. flowers, is always allowed + # everywhere regardless of this list) - NOTHING is allowed in any inventory unless listed here. + # Each entry contains Inventories (list of inventory materials, or a group name - 'storage' for + # chests/barrels/shulker boxes of any color, 'all' for every scanned inventory material including + # dispensers, droppers, hoppers, furnaces, etc.), Items (list of item materials, each checked + # independently against Amount - not summed) and Amount (max stored amount of that item per + # single inventory of that type). + ItemsInInventory: # defaults to none (nothing allowed in any inventory) if missing + - Inventories: [ DISPENSER ] + Items: [ BUCKET ] + Amount: 1 + - Inventories: [ DISPENSER ] + Items: [ ARROW, FIRE_CHARGE ] + Amount: 128 + - Inventories: [ storage ] + Items: [ TNT ] + Amount: 1728 # The name of the game mode presented to the players GameName: WarGear # defaults to WarGear if missing diff --git a/SchematicSystem/src/SchematicSystem.properties b/SchematicSystem/src/SchematicSystem.properties index f9931f97b..c72bcf961 100644 --- a/SchematicSystem/src/SchematicSystem.properties +++ b/SchematicSystem/src/SchematicSystem.properties @@ -269,7 +269,7 @@ 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_TOO_MANY_INVENTORY_ITEMS = §7{6}: §c[{0}, {1}, {2}]§7, §c{3}x {5}§7, 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} diff --git a/SchematicSystem/src/SchematicSystem_de.properties b/SchematicSystem/src/SchematicSystem_de.properties index 466e058a2..d584c602c 100644 --- a/SchematicSystem/src/SchematicSystem_de.properties +++ b/SchematicSystem/src/SchematicSystem_de.properties @@ -248,7 +248,7 @@ AUTO_CHECKER_RESULT_FORBIDDEN_ITEM = §7Verbotener gegenstand: [{0}, {1}, {2}] - 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_TOO_MANY_INVENTORY_ITEMS = §7{6}: §c[{0}, {1}, {2}]§7, §c{3}x {5}§7, 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} diff --git a/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoChecker.java b/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoChecker.java index 6fa2be03b..03d5e1820 100644 --- a/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoChecker.java +++ b/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoChecker.java @@ -75,9 +75,9 @@ public class AutoChecker { BlockPos pos = new BlockPos(x, y, z); - if (AutoCheckerItems.impl.getInventoryMaterials().contains(material)) { + if (type.Schematic.ItemsInInventory.containsKey(material)) { checkInventory(result, block, material, pos, type); - if (result.getDispenserItems().getOrDefault(pos, 0) > 0) { + if (!result.getInventoryItemCounts().getOrDefault(pos, Collections.emptyMap()).isEmpty()) { result.getBlockCounts().merge(material, 1, Integer::sum); } } else { @@ -93,19 +93,6 @@ public class AutoChecker { return result; } - private static final Map> itemsInInv = new EnumMap<>(Material.class); - - static { - itemsInInv.put(Material.BUCKET, EnumSet.of(Material.DISPENSER)); - itemsInInv.put(Material.TNT, EnumSet.of(Material.CHEST, Material.BARREL, Material.SHULKER_BOX, Material.BLACK_SHULKER_BOX, Material.BLUE_SHULKER_BOX, - Material.BROWN_SHULKER_BOX, Material.CYAN_SHULKER_BOX, Material.GRAY_SHULKER_BOX, Material.GREEN_SHULKER_BOX, Material.LIGHT_BLUE_SHULKER_BOX, - Material.LIGHT_GRAY_SHULKER_BOX, Material.LIME_SHULKER_BOX, Material.MAGENTA_SHULKER_BOX, Material.ORANGE_SHULKER_BOX, - Material.PINK_SHULKER_BOX, Material.PURPLE_SHULKER_BOX, Material.RED_SHULKER_BOX, Material.WHITE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX)); - itemsInInv.put(Material.FIRE_CHARGE, EnumSet.of(Material.DISPENSER)); - itemsInInv.put(Material.ARROW, EnumSet.of(Material.DISPENSER)); - AutoCheckerItems.impl.getAllowedMaterialsInInventory().forEach(material -> itemsInInv.put(material, AutoCheckerItems.impl.getInventoryMaterials())); - } - private void checkInventory(AutoChecker.BlockScanResult result, BaseBlock block, Material material, BlockPos pos, GameModeConfig type) { CompoundTag nbt = block.getNbtData(); if (nbt == null) { @@ -122,7 +109,8 @@ public class AutoChecker { List items = nbt.getList("Items", CompoundTag.class); if (items.isEmpty()) return; // Leeres Inventar - int counter = 0; + Map itemCaps = type.Schematic.ItemsInInventory.getOrDefault(material, Collections.emptyMap()); + Map itemCounts = new EnumMap<>(Material.class); int windChargeCount = 0; for (CompoundTag item : items) { if (!item.containsKey("id")) { @@ -136,16 +124,19 @@ public class AutoChecker { if (type.Schematic.Type.getName().equals("wargearseason26") && material == Material.DISPENSER && itemType == Material.WIND_CHARGE) { windChargeCount += item.getInt("count"); - } else if (!itemsInInv.getOrDefault(itemType, EnumSet.noneOf(Material.class)).contains(material)) { + } else if (!itemCaps.containsKey(itemType)) { result.getForbiddenItems().computeIfAbsent(pos, blockVector3 -> new HashSet<>()).add(itemType); - } else if (material == Material.DISPENSER && (itemType == Material.ARROW || itemType == Material.FIRE_CHARGE)) { - counter += item.getInt("count"); + } else { + itemCounts.merge(itemType, item.getInt("count"), Integer::sum); } if (item.containsKey("tag")) { result.getForbiddenNbt().computeIfAbsent(pos, blockVector3 -> new HashSet<>()).add(itemType); } } - result.getDispenserItems().put(pos, counter); + if (!itemCounts.isEmpty()) { + result.getInventoryItemCounts().put(pos, itemCounts); + result.getInventoryBlockType().put(pos, material); + } result.getWindChargeCount().put(pos, windChargeCount); } @@ -156,7 +147,8 @@ public class AutoChecker { 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> inventoryItemCounts = new HashMap<>(); + private final Map inventoryBlockType = new HashMap<>(); private final Map windChargeCount = new HashMap<>(); private final Map> forbiddenItems = new HashMap<>(); private final Map> forbiddenNbt = new HashMap<>(); diff --git a/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems.java b/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems.java deleted file mode 100644 index 122686568..000000000 --- a/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2025 SteamWar.de-Serverteam - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package de.steamwar.schematicsystem.autocheck; - -import org.bukkit.Material; - -import java.util.EnumSet; -import java.util.Set; - -public class AutoCheckerItems { - - public static final AutoCheckerItems impl = new AutoCheckerItems(); - - private static final Set INVENTORY = EnumSet.of(Material.BARREL, Material.BLAST_FURNACE, Material.BREWING_STAND, Material.CAMPFIRE, - Material.CHEST, Material.DISPENSER, Material.DROPPER, Material.FURNACE, Material.HOPPER, Material.JUKEBOX, Material.SHULKER_BOX, - Material.WHITE_SHULKER_BOX, Material.ORANGE_SHULKER_BOX, Material.MAGENTA_SHULKER_BOX, Material.LIGHT_BLUE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX, - Material.LIME_SHULKER_BOX, Material.PINK_SHULKER_BOX, Material.GRAY_SHULKER_BOX, Material.LIGHT_GRAY_SHULKER_BOX, Material.CYAN_SHULKER_BOX, - Material.PURPLE_SHULKER_BOX, Material.BLUE_SHULKER_BOX, Material.BROWN_SHULKER_BOX, Material.GREEN_SHULKER_BOX, Material.RED_SHULKER_BOX, - Material.BLACK_SHULKER_BOX, Material.SMOKER, Material.TRAPPED_CHEST); - - private static final Set FLOWERS = EnumSet.of(Material.CORNFLOWER, Material.POPPY, Material.FERN, Material.DANDELION, Material.BLUE_ORCHID, - Material.ALLIUM, Material.AZURE_BLUET, Material.RED_TULIP, Material.ORANGE_TULIP, Material.WHITE_TULIP, Material.PINK_TULIP, Material.OXEYE_DAISY, - Material.LILY_OF_THE_VALLEY, Material.WITHER_ROSE, Material.SUNFLOWER, Material.DIAMOND_HORSE_ARMOR, Material.IRON_HORSE_ARMOR, - Material.GOLDEN_HORSE_ARMOR, Material.LEATHER_HORSE_ARMOR, Material.HONEY_BOTTLE, Material.LILAC, Material.ROSE_BUSH, Material.PEONY, - Material.TALL_GRASS, Material.LARGE_FERN); - - public Set getInventoryMaterials() { - return INVENTORY; - } - - public Set getAllowedMaterialsInInventory() { - return FLOWERS; - } -} diff --git a/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoCheckerResult.java b/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoCheckerResult.java index a63fb70b2..090530d85 100644 --- a/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoCheckerResult.java +++ b/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoCheckerResult.java @@ -29,6 +29,7 @@ import org.bukkit.Material; import org.bukkit.entity.Player; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -50,7 +51,7 @@ public class AutoCheckerResult { isSizeOk() && isBlockCountOk() && isLimitedBlocksOK() && - isDispenserItemsOK() && + isInventoryItemsOK() && isWindchargeCountOK() && !type.isAfterDeadline() && entities.isEmpty() && @@ -71,8 +72,13 @@ public class AutoCheckerResult { } } - public boolean isDispenserItemsOK() { - return blockScanResult.getDispenserItems().values().stream().allMatch(i -> i <= type.Schematic.MaxDispenserItems); + public boolean isInventoryItemsOK() { + return blockScanResult.getInventoryItemCounts().entrySet().stream().allMatch(posEntry -> { + Material inventory = blockScanResult.getInventoryBlockType().get(posEntry.getKey()); + Map caps = type.Schematic.ItemsInInventory.getOrDefault(inventory, Collections.emptyMap()); + return posEntry.getValue().entrySet().stream() + .allMatch(itemEntry -> itemEntry.getValue() <= caps.getOrDefault(itemEntry.getKey(), Integer.MAX_VALUE)); + }); } public boolean hasWarnings() { @@ -155,13 +161,21 @@ public class AutoCheckerResult { }); } - blockScanResult.getDispenserItems().entrySet().stream().filter(blockVector3IntegerEntry -> blockVector3IntegerEntry.getValue() > type.Schematic.MaxDispenserItems).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.Schematic.MaxDispenserItems); + blockScanResult.getInventoryItemCounts().forEach((pos, itemCounts) -> { + Material inventory = blockScanResult.getInventoryBlockType().get(pos); + Map caps = type.Schematic.ItemsInInventory.getOrDefault(inventory, Collections.emptyMap()); + itemCounts.forEach((itemType, count) -> { + int cap = caps.getOrDefault(itemType, Integer.MAX_VALUE); + if (count <= cap) return; + SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_TOO_MANY_INVENTORY_ITEMS", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(pos), + pos.getBlockX(), + pos.getBlockY(), + pos.getBlockZ(), + count, + cap, + itemType.name(), + inventory.name()); + }); }); blockScanResult.getRecords().forEach(blockVector3 -> { diff --git a/SchematicSystem/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand.java b/SchematicSystem/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand.java index 4e5ecdf7c..ffd14519f 100644 --- a/SchematicSystem/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand.java +++ b/SchematicSystem/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand.java @@ -197,27 +197,32 @@ public class SchematicCommand extends SWCommand { clipboard.setBlock(vector, block.toBaseBlock(builder.build())); } - if (type.Schematic.MaxDispenserItems > 0) { - for (Map.Entry entry : result.getBlockScanResult().getDispenserItems().entrySet()) { - if (entry.getValue() <= type.Schematic.MaxDispenserItems) { + for (Map.Entry> posEntry : result.getBlockScanResult().getInventoryItemCounts().entrySet()) { + BlockPos pos = posEntry.getKey(); + Material inventory = result.getBlockScanResult().getInventoryBlockType().get(pos); + Map caps = type.Schematic.ItemsInInventory.getOrDefault(inventory, Collections.emptyMap()); + + for (Map.Entry itemEntry : posEntry.getValue().entrySet()) { + Material itemType = itemEntry.getKey(); + int cap = caps.getOrDefault(itemType, Integer.MAX_VALUE); + if (itemEntry.getValue() <= cap) { 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 = new ArrayList<>(tag.getList("Items", CompoundTag.class)); - Collections.reverse(items); // To let the first item be in the Dispenser + Collections.reverse(items); // To let the first item be in the inventory List list = new ArrayList<>(); - int diff = entry.getValue() - type.Schematic.MaxDispenserItems; + int diff = itemEntry.getValue() - cap; for (CompoundTag item : items) { if (item == null) { continue; } - if (diff == 0) { + if (diff == 0 || Material.matchMaterial(item.getString("id")) != itemType) { list.add(item); continue; } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SQLWrapperImpl.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SQLWrapperImpl.java index 4cb3f1c28..e8733b32d 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SQLWrapperImpl.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SQLWrapperImpl.java @@ -28,7 +28,10 @@ import org.bukkit.entity.Player; import java.io.File; import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; public class SQLWrapperImpl implements SQLWrapper { @@ -52,6 +55,45 @@ public class SQLWrapperImpl implements SQLWrapper { .collect(Collectors.toList()); } + /** + * Storage-type inventory materials (chests, barrels, shulker boxes of any color). + */ + private static final Set STORAGE_MATERIALS = Collections.unmodifiableSet(EnumSet.of( + Material.CHEST, Material.TRAPPED_CHEST, Material.BARREL, 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 + )); + + /** + * Every inventory material - {@link #STORAGE_MATERIALS} plus the "functional" containers that + * are not storage (dispenser, dropper, hopper, the furnace family, brewing stand, campfire, + * jukebox). Built on top of {@link #STORAGE_MATERIALS} so anything added there is automatically + * included here. + */ + private static final Set INVENTORY_MATERIALS; + + static { + Set materials = EnumSet.copyOf(STORAGE_MATERIALS); + materials.addAll(EnumSet.of( + Material.DISPENSER, Material.DROPPER, Material.HOPPER, + Material.FURNACE, Material.BLAST_FURNACE, Material.SMOKER, + Material.BREWING_STAND, Material.CAMPFIRE, Material.JUKEBOX + )); + INVENTORY_MATERIALS = Collections.unmodifiableSet(materials); + } + + @Override + public Set getStorageMaterials() { + return STORAGE_MATERIALS; + } + + @Override + public Set getInventoryMaterials() { + return INVENTORY_MATERIALS; + } + private static final String SERVER_VERSION = Bukkit.getServer().getVersion(); @Override diff --git a/settings.gradle.kts b/settings.gradle.kts index bbb758e9a..63ec80e5b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -21,6 +21,12 @@ import org.apache.tools.ant.taskdefs.condition.Os import java.net.URI import java.util.* +pluginManagement { + plugins { + kotlin("plugin.lombok") version "2.3.20" + } +} + rootProject.name = "SteamWar" private val isInCi by lazy { Os.isFamily(Os.FAMILY_UNIX) && ProcessBuilder("hostname").start().inputStream.bufferedReader().readText().startsWith("steamwar.de") } From 311437d4516acd713faae1f9e76446d64bcff749 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Mon, 24 Aug 2026 20:22:02 +0200 Subject: [PATCH 06/22] Add ServerLinks to login --- .../listeners/ConnectionListener.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/VelocityCore/src/de/steamwar/velocitycore/listeners/ConnectionListener.java b/VelocityCore/src/de/steamwar/velocitycore/listeners/ConnectionListener.java index 021f65d0b..8f8b30f4a 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/listeners/ConnectionListener.java +++ b/VelocityCore/src/de/steamwar/velocitycore/listeners/ConnectionListener.java @@ -27,6 +27,7 @@ import com.velocitypowered.api.event.player.KickedFromServerEvent; import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.permission.Tristate; import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.util.ServerLink; import de.steamwar.linkage.Linked; import de.steamwar.messages.Chatter; import de.steamwar.messages.Message; @@ -45,9 +46,7 @@ import de.steamwar.velocitycore.mods.ModUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.concurrent.TimeUnit; @Linked @@ -82,6 +81,18 @@ public class ConnectionListener extends BasicListener { @Subscribe public void onPostLogin(PostLoginEvent event) { Player player = event.getPlayer(); + if (player.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_21)) { + List serverLinks = new ArrayList<>(); + serverLinks.add(ServerLink.serverLink(ServerLink.Type.BUG_REPORT, "https://git.steamwar.de/SteamWar/SteamWar/issues/new")); + serverLinks.add(ServerLink.serverLink(ServerLink.Type.COMMUNITY_GUIDELINES, "https://steamwar.de/verhaltensrichtlinien/")); + serverLinks.add(ServerLink.serverLink(ServerLink.Type.SUPPORT, "https://discord.com/channels/690530484920385586/870028487455571999")); + serverLinks.add(ServerLink.serverLink(ServerLink.Type.COMMUNITY, "https://steamwar.de/discord")); + serverLinks.add(ServerLink.serverLink(ServerLink.Type.WEBSITE, "https://steamwar.de/")); + serverLinks.add(ServerLink.serverLink(ServerLink.Type.NEWS, "https://discord.com/channels/690530484920385586/690535200865910794")); + serverLinks.add(ServerLink.serverLink(ServerLink.Type.ANNOUNCEMENTS, "https://discord.com/channels/690530484920385586/690535200865910794")); + player.setServerLinks(serverLinks); + } + SteamwarUser user = SteamwarUser.get(player.getUniqueId()); Chatter chatter = Chatter.of(player); CheckCommand.sendReminder(chatter); From 6476125a3f8ea253335b499136edb6f14188f741 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Mon, 24 Aug 2026 20:22:48 +0200 Subject: [PATCH 07/22] Add ServerLinks to login --- .../listeners/ConnectionListener.java | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/VelocityCore/src/de/steamwar/velocitycore/listeners/ConnectionListener.java b/VelocityCore/src/de/steamwar/velocitycore/listeners/ConnectionListener.java index 8f8b30f4a..edf372f39 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/listeners/ConnectionListener.java +++ b/VelocityCore/src/de/steamwar/velocitycore/listeners/ConnectionListener.java @@ -78,19 +78,25 @@ public class ConnectionListener extends BasicListener { }); } + private static final List SERVER_LINKS = getServerLinks(); + + private static List getServerLinks() { + List serverLinks = new ArrayList<>(); + serverLinks.add(ServerLink.serverLink(ServerLink.Type.BUG_REPORT, "https://git.steamwar.de/SteamWar/SteamWar/issues/new")); + serverLinks.add(ServerLink.serverLink(ServerLink.Type.COMMUNITY_GUIDELINES, "https://steamwar.de/verhaltensrichtlinien/")); + serverLinks.add(ServerLink.serverLink(ServerLink.Type.SUPPORT, "https://discord.com/channels/690530484920385586/870028487455571999")); + serverLinks.add(ServerLink.serverLink(ServerLink.Type.COMMUNITY, "https://steamwar.de/discord")); + serverLinks.add(ServerLink.serverLink(ServerLink.Type.WEBSITE, "https://steamwar.de/")); + serverLinks.add(ServerLink.serverLink(ServerLink.Type.NEWS, "https://discord.com/channels/690530484920385586/690535200865910794")); + serverLinks.add(ServerLink.serverLink(ServerLink.Type.ANNOUNCEMENTS, "https://discord.com/channels/690530484920385586/690535200865910794")); + return serverLinks; + } + @Subscribe public void onPostLogin(PostLoginEvent event) { Player player = event.getPlayer(); if (player.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_21)) { - List serverLinks = new ArrayList<>(); - serverLinks.add(ServerLink.serverLink(ServerLink.Type.BUG_REPORT, "https://git.steamwar.de/SteamWar/SteamWar/issues/new")); - serverLinks.add(ServerLink.serverLink(ServerLink.Type.COMMUNITY_GUIDELINES, "https://steamwar.de/verhaltensrichtlinien/")); - serverLinks.add(ServerLink.serverLink(ServerLink.Type.SUPPORT, "https://discord.com/channels/690530484920385586/870028487455571999")); - serverLinks.add(ServerLink.serverLink(ServerLink.Type.COMMUNITY, "https://steamwar.de/discord")); - serverLinks.add(ServerLink.serverLink(ServerLink.Type.WEBSITE, "https://steamwar.de/")); - serverLinks.add(ServerLink.serverLink(ServerLink.Type.NEWS, "https://discord.com/channels/690530484920385586/690535200865910794")); - serverLinks.add(ServerLink.serverLink(ServerLink.Type.ANNOUNCEMENTS, "https://discord.com/channels/690530484920385586/690535200865910794")); - player.setServerLinks(serverLinks); + player.setServerLinks(SERVER_LINKS); } SteamwarUser user = SteamwarUser.get(player.getUniqueId()); From 38e845b0e4167529cfd56e4a3257d105e88253c7 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Wed, 26 Aug 2026 21:46:45 +0200 Subject: [PATCH 08/22] Improve AutoChecker and GameModeConfig again --- .../src/de/steamwar/sql/GameModeConfig.java | 208 +++++++++++------- .../SQL/src/de/steamwar/sql/SQLWrapper.java | 4 +- .../SQL/src/de/steamwar/sql/YMLWrapper.java | 19 ++ FightSystem/FightSystem_Core/src/config.yml | 37 ++-- .../autocheck/AutoChecker.java | 5 +- .../autocheck/AutoCheckerResult.java | 35 ++- .../schematiccommand/SchematicCommand.java | 9 +- 7 files changed, 187 insertions(+), 130 deletions(-) diff --git a/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java b/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java index 2676dad53..50fba0cc4 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java +++ b/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java @@ -703,46 +703,12 @@ public final class GameModeConfig { public final double MaxDesignBlastResistance; /** - * List of limited material (combinations)
- * List contains tags Amount (integer) and Materials (List of material names in Spigot 1.12 AND Spigot 1.15 format) - */ - public final Map, Integer> Limited; - - /** - * Item amount limits per inventory (container) type.
- * Key: inventory material (e.g. DISPENSER, CHEST, ...). Value: item material -> maximal - * amount of that item allowed to be stored in a single inventory of that type.
- * An item is only allowed to be placed in an inventory at all if it appears here for that - * inventory's material and item. Every material returned by - * {@link SQLWrapper#getInventoryMaterials()} is always present as a key - with an empty value - * map if not explicitly configured - so every real container is always scanned by the schematic - * checker for forbidden contents, it just allows no items by default.
- * Configured via the {@code ItemsInInventory} list, entries consisting of {@code Inventories} - * (list of inventory materials or group names - {@code storage} for - * {@link SQLWrapper#getStorageMaterials()}, {@code all} for every material from - * {@link SQLWrapper#getInventoryMaterials()}), {@code Items} (list of item materials, each - * checked independently against {@code Amount} - not summed) and {@code Amount}. + * List of limited block materials * - * @implSpec No item is allowed in any inventory unless configured here + * @implSpec {@link SQLWrapper#getInventoryMaterials)} are all disallowed by default to have any content but are unlimited in number. + * @implSpec Any Block that has more Blast Resistance than {@link #MaxBlastResistance} will be defaulted to 0. */ - public final Map> ItemsInInventory; - - /** - * Resolves one {@code Inventories} entry to the concrete inventory materials it denotes: - * {@code storage} for {@link SQLWrapper#getStorageMaterials()}, {@code all} for - * {@link SQLWrapper#getInventoryMaterials()}, or the material itself otherwise. - */ - private Set expandInventoryGroup(YMLWrapper loader, String name) { - switch (name.toUpperCase()) { - case "STORAGE": - return (Set) SQLWrapper.impl.getStorageMaterials(); - case "ALL": - return (Set) SQLWrapper.impl.getInventoryMaterials(); - default: - M material = loader.materialMapper.apply(name.toUpperCase()); - return material != null ? Collections.singleton(material) : Collections.emptySet(); - } - } + public final List> Limited; private SchematicConfig(YMLWrapper loader) { loaded = loader.canLoad(); @@ -763,52 +729,142 @@ public final class GameModeConfig { MaxBlastResistance = loader.getDouble("MaxBlastResistance", Double.MAX_VALUE); MaxDesignBlastResistance = loader.getDouble("MaxDesignBlastResistance", MaxBlastResistance); - Map, Integer> Limited = new HashMap<>(); - for (Map entry : loader.getMapList("Limited")) { - int amount = (Integer) entry.get("Amount"); - Set materials = new HashSet<>((List) entry.get("Materials")); - if (amount == 0) { - materials.forEach(material -> { - Limited.put(Collections.singleton(loader.materialMapper.apply(material.toUpperCase())), 0); - }); - } else { - Limited.put(Collections.unmodifiableSet(materials.stream().map(String::toUpperCase).map(loader.materialMapper).collect(Collectors.toSet())), amount); - } + List> limited = new ArrayList<>(); + Set blocks = new HashSet<>(); + for (YMLWrapper limitedLoader : loader.withAsList("Limited")) { + BlockRule blockRule = new BlockRule<>(limitedLoader); + blocks.addAll(blockRule.Blocks); + limited.add(blockRule); } - SQLWrapper.impl.getMaterialWithGreaterBlastResistance(MaxBlastResistance).forEach(material -> { - if (Limited.entrySet().stream().anyMatch(entry -> entry.getKey().contains(material))) return; - Limited.put(Collections.singleton((M) material), 0); - }); - this.Limited = Collections.unmodifiableMap(Limited); - - Map> itemsInInventory = new HashMap<>(); - for (Map entry : loader.getMapList("ItemsInInventory")) { - int amount = (Integer) entry.get("Amount"); - List inventories = (List) entry.get("Inventories"); - List items = (List) entry.get("Items"); - for (String inventoryName : inventories) { - for (M inventoryMaterial : expandInventoryGroup(loader, inventoryName)) { - if (inventoryMaterial == null) continue; - Map itemCaps = itemsInInventory.computeIfAbsent(inventoryMaterial, m -> new HashMap<>()); - for (String itemName : items) { - M itemMaterial = loader.materialMapper.apply(itemName.toUpperCase()); - if (itemMaterial == null) continue; - itemCaps.put(itemMaterial, amount); - } - } - } + for (M material : (List) SQLWrapper.impl.getMaterialWithGreaterBlastResistance(MaxBlastResistance)) { + if (material == null || !blocks.add(material)) continue; + limited.add(new BlockRule<>(material, 0)); } - for (M allMaterial : (Set) SQLWrapper.impl.getInventoryMaterials()) { - if (allMaterial == null) continue; - itemsInInventory.computeIfAbsent(allMaterial, m -> new HashMap<>()); + for (M material : (Set) SQLWrapper.impl.getInventoryMaterials()) { + if (material == null || !blocks.add(material)) continue; + limited.add(new BlockRule<>(material, Integer.MAX_VALUE)); } - this.ItemsInInventory = Collections.unmodifiableMap(itemsInInventory.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> Collections.unmodifiableMap(e.getValue())))); + this.Limited = Collections.unmodifiableList(limited); this.ReplacementsWithoutBlockUpdates = loader.getMap("ReplacementsWithoutBlockUpdates", loader.materialMapper, loader.materialMapper); this.ReplacementsWithBlockUpdates = loader.getMap("ReplacementsWithBlockUpdates", loader.materialMapper, loader.materialMapper); } + public int getMaxCount(M material) { + return Limited.stream() + .filter(rule -> rule.Blocks.contains(material)) + .mapToInt(rule -> rule.MaxCount) + .max() + .orElse(Integer.MAX_VALUE); + } + + public boolean isInventory(M material) { + return Limited.stream() + .filter(rule -> rule.Blocks.contains(material)) + .anyMatch(rule -> rule.Content.loaded); + } + + public Integer getItemAmount(M material, M item) { + return Limited.stream() + .filter(rule -> rule.Blocks.contains(material)) + .filter(rule -> rule.Content.Items.contains(item)) + .mapToInt(rule -> rule.Content.Amount) + .max() + .orElse(0); + } + + @ToString + public static final class BlockRule { + + /** + * The block materials this rule applies to + */ + public final Set Blocks; + + /** + * Maximal amount of Blocks allowed in the schematic + * + * @implSpec {@code 0} by default + */ + public final int MaxCount; + + /** + * The item content filter for Blocks + * + * @implSpec no Items with {@code Amount 0} (denies any item) by default + */ + public final Content Content; + + /** + * Resolves one {@code Materials} entry to the concrete materials it denotes: {@code storage} + * for {@link SQLWrapper#getStorageMaterials()}, {@code all} for + * {@link SQLWrapper#getInventoryMaterials()}, or the material itself otherwise. + */ + private Set expandInventoryGroup(YMLWrapper loader, String name) { + switch (name.toUpperCase()) { + case "STORAGE": + return (Set) SQLWrapper.impl.getStorageMaterials(); + case "INVENTORY": + return (Set) SQLWrapper.impl.getInventoryMaterials(); + default: + M material = loader.materialMapper.apply(name.toUpperCase()); + return material != null ? Collections.singleton(material) : Collections.emptySet(); + } + } + + private BlockRule(YMLWrapper loader) { + List blocks = loader.getStringList("Blocks") + .stream() + .flatMap(value -> expandInventoryGroup(loader, value).stream()) + .collect(Collectors.toList()); + if (blocks.isEmpty()) { // Legacy support + blocks = loader.getMaterialList("Materials"); + } + Blocks = Collections.unmodifiableSet(new HashSet<>(blocks)); + MaxCount = loader.getInt("MaxCount", // Legacy support + loader.getInt("Amount", 0) + ); + Content = new Content<>(loader.with("Content")); + } + + private BlockRule(M block, int maxCount) { + Blocks = Collections.singleton(block); + MaxCount = maxCount; + Content = new Content<>(); + } + + @ToString + public static final class Content { + + public final boolean loaded; + + /** + * Items allowed by this rule + */ + public final Set Items; + + /** + * Maximal amount of an allowed item per single block instance + * + * @implSpec {@code 0} by default + */ + public final int Amount; + + private Content(YMLWrapper loader) { + loaded = loader.canLoad(); + List items = loader.getMaterialList("Items"); + Items = Collections.unmodifiableSet(new HashSet<>(items)); + Amount = loader.getInt("Amount", 0); + } + + private Content() { + loaded = false; + Items = new HashSet<>(); + Amount = 0; + } + } + } + @ToString public static final class SizeConfig { diff --git a/CommonCore/SQL/src/de/steamwar/sql/SQLWrapper.java b/CommonCore/SQL/src/de/steamwar/sql/SQLWrapper.java index be52e8fbd..565687fe7 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/SQLWrapper.java +++ b/CommonCore/SQL/src/de/steamwar/sql/SQLWrapper.java @@ -39,7 +39,7 @@ public interface SQLWrapper { /** * Storage-type inventory materials (chests, barrels, shulker boxes of any color) - the - * {@code storage} group usable in {@code GameModeConfig}'s {@code ItemsInInventory}. + * {@code storage} group usable in {@code GameModeConfig}'s {@code Limited}. */ default Set getStorageMaterials() { return Collections.emptySet(); @@ -47,7 +47,7 @@ public interface SQLWrapper { /** * Every inventory material - the {@code all} group usable in {@code GameModeConfig}'s - * {@code ItemsInInventory}. Expected to be a superset of {@link #getStorageMaterials()}. + * {@code Limited}. Expected to be a superset of {@link #getStorageMaterials()}. */ default Set getInventoryMaterials() { return Collections.emptySet(); diff --git a/CommonCore/SQL/src/de/steamwar/sql/YMLWrapper.java b/CommonCore/SQL/src/de/steamwar/sql/YMLWrapper.java index 567524ff2..87df1352f 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/YMLWrapper.java +++ b/CommonCore/SQL/src/de/steamwar/sql/YMLWrapper.java @@ -76,6 +76,25 @@ final class YMLWrapper { return new YMLWrapper<>(false, Collections.emptyMap(), materialMapper, winconditionMapper); } + public List> withAsList(String path) { + if (document.containsKey(path)) { + Object value = document.get(path); + if (value instanceof List) { + List list = (List) value; + List maps = list.stream() + .filter(Map.class::isInstance) + .map(Map.class::cast) + .collect(Collectors.toList()); + if (maps.size() == list.size()) { + return (List) maps.stream() + .map(map -> new YMLWrapper(true, map, materialMapper, winconditionMapper)) + .collect(Collectors.toList()); + } + } + } + return Collections.emptyList(); + } + public T get(String path, T defaultValue, Function mapper) { Object value = this.document.get(path); if (value == null) return defaultValue; diff --git a/FightSystem/FightSystem_Core/src/config.yml b/FightSystem/FightSystem_Core/src/config.yml index 8987b88a9..dbaf3c336 100644 --- a/FightSystem/FightSystem_Core/src/config.yml +++ b/FightSystem/FightSystem_Core/src/config.yml @@ -109,30 +109,21 @@ Schematic: MaxBlocks: 0 # defaults to 0 (ignored) if missing # Maximal blast resistance for the design blocks MaxDesignBlastResistance: 100000000 # defaults to Double.MAX_VALUE if missing - # List of limited material (combinations) - # List contains tags Amount (integer) and Materials (List of material names in Spigot 1.12 AND Spigot 1.15 format) + # List of limited block materials + # InventoryMaterials are all disallowed by default to have any content but are unlimited in number + # Any Block that has more Blast Resistance than MaxBlastResistance will be defaulted to 0. Limited: - - Materials: [ ] - Amount: 0 - # Item amount limits per inventory (container) type. - # An item is only allowed to be placed in an inventory at all if it appears here for that - # inventory's material (a small set of decorative items, e.g. flowers, is always allowed - # everywhere regardless of this list) - NOTHING is allowed in any inventory unless listed here. - # Each entry contains Inventories (list of inventory materials, or a group name - 'storage' for - # chests/barrels/shulker boxes of any color, 'all' for every scanned inventory material including - # dispensers, droppers, hoppers, furnaces, etc.), Items (list of item materials, each checked - # independently against Amount - not summed) and Amount (max stored amount of that item per - # single inventory of that type). - ItemsInInventory: # defaults to none (nothing allowed in any inventory) if missing - - Inventories: [ DISPENSER ] - Items: [ BUCKET ] - Amount: 1 - - Inventories: [ DISPENSER ] - Items: [ ARROW, FIRE_CHARGE ] - Amount: 128 - - Inventories: [ storage ] - Items: [ TNT ] - Amount: 1728 + - Blocks: [ DISPENSER ] + MaxCount: 64 + - Blocks: [ DISPENSER ] + MaxCount: 16 + Content: + Items: [ ARROW, FIRE_CHARGE ] + Amount: 128 + - Blocks: [ storage ] + Content: + Items: [ TNT ] + Amount: 1728 # The name of the game mode presented to the players GameName: WarGear # defaults to WarGear if missing diff --git a/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoChecker.java b/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoChecker.java index 03d5e1820..cb23bbbdc 100644 --- a/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoChecker.java +++ b/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoChecker.java @@ -75,7 +75,7 @@ public class AutoChecker { BlockPos pos = new BlockPos(x, y, z); - if (type.Schematic.ItemsInInventory.containsKey(material)) { + if (type.Schematic.isInventory(material)) { checkInventory(result, block, material, pos, type); if (!result.getInventoryItemCounts().getOrDefault(pos, Collections.emptyMap()).isEmpty()) { result.getBlockCounts().merge(material, 1, Integer::sum); @@ -109,7 +109,6 @@ public class AutoChecker { List items = nbt.getList("Items", CompoundTag.class); if (items.isEmpty()) return; // Leeres Inventar - Map itemCaps = type.Schematic.ItemsInInventory.getOrDefault(material, Collections.emptyMap()); Map itemCounts = new EnumMap<>(Material.class); int windChargeCount = 0; for (CompoundTag item : items) { @@ -124,7 +123,7 @@ public class AutoChecker { if (type.Schematic.Type.getName().equals("wargearseason26") && material == Material.DISPENSER && itemType == Material.WIND_CHARGE) { windChargeCount += item.getInt("count"); - } else if (!itemCaps.containsKey(itemType)) { + } else if (type.Schematic.getItemAmount(material, itemType) == 0) { result.getForbiddenItems().computeIfAbsent(pos, blockVector3 -> new HashSet<>()).add(itemType); } else { itemCounts.merge(itemType, item.getInt("count"), Integer::sum); diff --git a/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoCheckerResult.java b/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoCheckerResult.java index 090530d85..c59f17aba 100644 --- a/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoCheckerResult.java +++ b/SchematicSystem/src/de/steamwar/schematicsystem/autocheck/AutoCheckerResult.java @@ -29,7 +29,6 @@ import org.bukkit.Material; import org.bukkit.entity.Player; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Map; @@ -75,9 +74,10 @@ public class AutoCheckerResult { public boolean isInventoryItemsOK() { return blockScanResult.getInventoryItemCounts().entrySet().stream().allMatch(posEntry -> { Material inventory = blockScanResult.getInventoryBlockType().get(posEntry.getKey()); - Map caps = type.Schematic.ItemsInInventory.getOrDefault(inventory, Collections.emptyMap()); - return posEntry.getValue().entrySet().stream() - .allMatch(itemEntry -> itemEntry.getValue() <= caps.getOrDefault(itemEntry.getKey(), Integer.MAX_VALUE)); + return posEntry.getValue().entrySet().stream().allMatch(itemEntry -> { + int cap = type.Schematic.getItemAmount(inventory, itemEntry.getKey()); + return itemEntry.getValue() <= cap; + }); }); } @@ -106,13 +106,8 @@ public class AutoCheckerResult { } public boolean isLimitedBlocksOK() { - try { - return type.Schematic.Limited.entrySet().stream() - .map(setIntegerEntry -> setIntegerEntry.getKey().stream().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; - } + return blockScanResult.getBlockCounts().entrySet().stream() + .allMatch(entry -> entry.getValue() <= type.Schematic.getMaxCount(entry.getKey())); } public boolean isDesignBlastResistanceOK() { @@ -136,14 +131,13 @@ public class AutoCheckerResult { SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_BLOCKS", p, blockScanResult.getBlockCounts().values().stream().reduce(Integer::sum).orElse(0), type.Schematic.MaxBlocks); } if (!isLimitedBlocksOK()) { - type.Schematic.Limited.forEach((materials, integer) -> { - for (Material mat : materials) { - 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.getBlockCounts().forEach((mat, count) -> { + int maxCount = type.Schematic.getMaxCount(mat); + if (count > maxCount) { + if (maxCount == 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(), count, maxCount); } } }); @@ -163,9 +157,8 @@ public class AutoCheckerResult { blockScanResult.getInventoryItemCounts().forEach((pos, itemCounts) -> { Material inventory = blockScanResult.getInventoryBlockType().get(pos); - Map caps = type.Schematic.ItemsInInventory.getOrDefault(inventory, Collections.emptyMap()); itemCounts.forEach((itemType, count) -> { - int cap = caps.getOrDefault(itemType, Integer.MAX_VALUE); + int cap = type.Schematic.getItemAmount(inventory, itemType); if (count <= cap) return; SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_TOO_MANY_INVENTORY_ITEMS", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(pos), pos.getBlockX(), diff --git a/SchematicSystem/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand.java b/SchematicSystem/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand.java index ffd14519f..198a36899 100644 --- a/SchematicSystem/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand.java +++ b/SchematicSystem/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand.java @@ -200,11 +200,10 @@ public class SchematicCommand extends SWCommand { for (Map.Entry> posEntry : result.getBlockScanResult().getInventoryItemCounts().entrySet()) { BlockPos pos = posEntry.getKey(); Material inventory = result.getBlockScanResult().getInventoryBlockType().get(pos); - Map caps = type.Schematic.ItemsInInventory.getOrDefault(inventory, Collections.emptyMap()); for (Map.Entry itemEntry : posEntry.getValue().entrySet()) { Material itemType = itemEntry.getKey(); - int cap = caps.getOrDefault(itemType, Integer.MAX_VALUE); + Integer cap = type.Schematic.getItemAmount(inventory, itemType); if (itemEntry.getValue() <= cap) { continue; } @@ -243,9 +242,9 @@ public class SchematicCommand extends SWCommand { } if (!result.isLimitedBlocksOK()) { - Set toReplace = type.Schematic.Limited.entrySet().stream() - .filter(setIntegerEntry -> setIntegerEntry.getValue() == 0) - .flatMap(setIntegerEntry -> setIntegerEntry.getKey().stream()) + Set toReplace = type.Schematic.Limited.stream() + .filter(rule -> rule.MaxCount == 0) + .flatMap(rule -> rule.Blocks.stream()) .collect(Collectors.toSet()); BlockState replaceType = Objects.requireNonNull(toReplace.contains(Material.END_STONE) ? BlockTypes.IRON_BLOCK : BlockTypes.END_STONE).getDefaultState(); BlockVector3 min = clipboard.getMinimumPoint(); From d3c8b6e1c6a2d7dd0d0ec9bc541bbb696619c9e7 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Wed, 26 Aug 2026 22:12:53 +0200 Subject: [PATCH 09/22] Add debug output --- .../src/de/steamwar/fightsystem/listener/Check.java | 1 + 1 file changed, 1 insertion(+) diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java index d5b40ee9a..6f16fd3c8 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java @@ -62,6 +62,7 @@ public class Check implements Listener { SteamwarUser user = SteamwarUser.get(player.getUniqueId()); SchematicNode schem = SchematicNode.getSchematicNode(Config.CheckSchemID); + System.out.println(player + " " + schem + " " + checkPermission(user, schem)); if (checkPermission(user, schem)) return; if (user.getId() == schem.getOwner()) return; From 5236afba1701356b3d7d1c9555c8c88ea6a6079f Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Wed, 26 Aug 2026 22:17:33 +0200 Subject: [PATCH 10/22] Add debug output --- .../src/de/steamwar/fightsystem/listener/Check.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java index 6f16fd3c8..e06281c7a 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java @@ -51,6 +51,7 @@ public class Check implements Listener { .findFirst() .orElse(null); if (gameModeConfig == null) gameModeConfig = GameModeConfig.getDefaults(); + System.out.println(gameModeConfig.GameName + " " + gameModeConfig.Checkers); if (user.hasPerm(UserPerm.ADMINISTRATION)) return true; if (gameModeConfig.Checkers.isEmpty() && user.hasPerm(UserPerm.CHECK)) return true; return gameModeConfig.Checkers.contains(user.getId()); @@ -62,7 +63,7 @@ public class Check implements Listener { SteamwarUser user = SteamwarUser.get(player.getUniqueId()); SchematicNode schem = SchematicNode.getSchematicNode(Config.CheckSchemID); - System.out.println(player + " " + schem + " " + checkPermission(user, schem)); + System.out.println(player + " " + schem.getNodeOwner() + " " + schem.getName() + " " + checkPermission(user, schem)); if (checkPermission(user, schem)) return; if (user.getId() == schem.getOwner()) return; From 8a53aecfac05bb337d27941666748e811b278b5b Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Wed, 26 Aug 2026 22:26:43 +0200 Subject: [PATCH 11/22] Add debug output --- .../src/de/steamwar/fightsystem/listener/Check.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java index e06281c7a..3729775c2 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java @@ -47,7 +47,7 @@ public class Check implements Listener { private boolean checkPermission(SteamwarUser user, SchematicNode schematic) { GameModeConfig gameModeConfig = GameModeConfig.getAll().stream() - .filter(gmc -> gmc.Schematic.Type != null && gmc.Schematic.Type.equals(schematic.getSchemtype())) + .filter(gmc -> gmc.Schematic.Type != null && gmc.Schematic.Type.checkType().name().equals(schematic.getSchemtype().name())) .findFirst() .orElse(null); if (gameModeConfig == null) gameModeConfig = GameModeConfig.getDefaults(); @@ -63,7 +63,7 @@ public class Check implements Listener { SteamwarUser user = SteamwarUser.get(player.getUniqueId()); SchematicNode schem = SchematicNode.getSchematicNode(Config.CheckSchemID); - System.out.println(player + " " + schem.getNodeOwner() + " " + schem.getName() + " " + checkPermission(user, schem)); + System.out.println(player + " " + schem.getNodeOwner() + " " + " " + schem.getSchemtype() + " " + schem.getName()); if (checkPermission(user, schem)) return; if (user.getId() == schem.getOwner()) return; From 97c1da1b2a5bd014cbbb9dd7fd1463a9fb2776b9 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Wed, 26 Aug 2026 22:31:30 +0200 Subject: [PATCH 12/22] Add debug output --- .../src/de/steamwar/fightsystem/listener/Check.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java index 3729775c2..987fda6e3 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java @@ -47,7 +47,7 @@ public class Check implements Listener { private boolean checkPermission(SteamwarUser user, SchematicNode schematic) { GameModeConfig gameModeConfig = GameModeConfig.getAll().stream() - .filter(gmc -> gmc.Schematic.Type != null && gmc.Schematic.Type.checkType().name().equals(schematic.getSchemtype().name())) + .filter(gmc -> gmc.Schematic.Type != null && gmc.Schematic.Type.checkType() != null && schematic.getSchemtype().name().equals(gmc.Schematic.Type.checkType().name())) .findFirst() .orElse(null); if (gameModeConfig == null) gameModeConfig = GameModeConfig.getDefaults(); From d307f890e2a93bc209cf84060d3dbd688a5bc737 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Wed, 26 Aug 2026 22:35:39 +0200 Subject: [PATCH 13/22] Remove debug output --- .../src/de/steamwar/sql/GameModeConfig.java | 33 ++++++++----------- .../steamwar/fightsystem/listener/Check.java | 2 -- .../schematiccommand/SchematicCommand.java | 4 +-- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java b/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java index 50fba0cc4..51fbda837 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java +++ b/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java @@ -733,7 +733,7 @@ public final class GameModeConfig { Set blocks = new HashSet<>(); for (YMLWrapper limitedLoader : loader.withAsList("Limited")) { BlockRule blockRule = new BlockRule<>(limitedLoader); - blocks.addAll(blockRule.Blocks); + blocks.addAll(blockRule.Materials); limited.add(blockRule); } for (M material : (List) SQLWrapper.impl.getMaterialWithGreaterBlastResistance(MaxBlastResistance)) { @@ -752,21 +752,21 @@ public final class GameModeConfig { public int getMaxCount(M material) { return Limited.stream() - .filter(rule -> rule.Blocks.contains(material)) - .mapToInt(rule -> rule.MaxCount) + .filter(rule -> rule.Materials.contains(material)) + .mapToInt(rule -> rule.Amount) .max() .orElse(Integer.MAX_VALUE); } public boolean isInventory(M material) { return Limited.stream() - .filter(rule -> rule.Blocks.contains(material)) + .filter(rule -> rule.Materials.contains(material)) .anyMatch(rule -> rule.Content.loaded); } public Integer getItemAmount(M material, M item) { return Limited.stream() - .filter(rule -> rule.Blocks.contains(material)) + .filter(rule -> rule.Materials.contains(material)) .filter(rule -> rule.Content.Items.contains(item)) .mapToInt(rule -> rule.Content.Amount) .max() @@ -779,14 +779,14 @@ public final class GameModeConfig { /** * The block materials this rule applies to */ - public final Set Blocks; + public final Set Materials; /** * Maximal amount of Blocks allowed in the schematic * * @implSpec {@code 0} by default */ - public final int MaxCount; + public final int Amount; /** * The item content filter for Blocks @@ -813,23 +813,18 @@ public final class GameModeConfig { } private BlockRule(YMLWrapper loader) { - List blocks = loader.getStringList("Blocks") + Set blocks = loader.getStringList("Materials") .stream() .flatMap(value -> expandInventoryGroup(loader, value).stream()) - .collect(Collectors.toList()); - if (blocks.isEmpty()) { // Legacy support - blocks = loader.getMaterialList("Materials"); - } - Blocks = Collections.unmodifiableSet(new HashSet<>(blocks)); - MaxCount = loader.getInt("MaxCount", // Legacy support - loader.getInt("Amount", 0) - ); + .collect(Collectors.toSet()); + Materials = Collections.unmodifiableSet(blocks); + Amount = loader.getInt("Amount", 0); Content = new Content<>(loader.with("Content")); } - private BlockRule(M block, int maxCount) { - Blocks = Collections.singleton(block); - MaxCount = maxCount; + private BlockRule(M block, int amount) { + Materials = Collections.singleton(block); + Amount = amount; Content = new Content<>(); } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java index 987fda6e3..fc7240876 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java @@ -51,7 +51,6 @@ public class Check implements Listener { .findFirst() .orElse(null); if (gameModeConfig == null) gameModeConfig = GameModeConfig.getDefaults(); - System.out.println(gameModeConfig.GameName + " " + gameModeConfig.Checkers); if (user.hasPerm(UserPerm.ADMINISTRATION)) return true; if (gameModeConfig.Checkers.isEmpty() && user.hasPerm(UserPerm.CHECK)) return true; return gameModeConfig.Checkers.contains(user.getId()); @@ -63,7 +62,6 @@ public class Check implements Listener { SteamwarUser user = SteamwarUser.get(player.getUniqueId()); SchematicNode schem = SchematicNode.getSchematicNode(Config.CheckSchemID); - System.out.println(player + " " + schem.getNodeOwner() + " " + " " + schem.getSchemtype() + " " + schem.getName()); if (checkPermission(user, schem)) return; if (user.getId() == schem.getOwner()) return; diff --git a/SchematicSystem/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand.java b/SchematicSystem/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand.java index 198a36899..e0b0b2ce9 100644 --- a/SchematicSystem/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand.java +++ b/SchematicSystem/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommand.java @@ -243,8 +243,8 @@ public class SchematicCommand extends SWCommand { if (!result.isLimitedBlocksOK()) { Set toReplace = type.Schematic.Limited.stream() - .filter(rule -> rule.MaxCount == 0) - .flatMap(rule -> rule.Blocks.stream()) + .filter(rule -> rule.Amount == 0) + .flatMap(rule -> rule.Materials.stream()) .collect(Collectors.toSet()); BlockState replaceType = Objects.requireNonNull(toReplace.contains(Material.END_STONE) ? BlockTypes.IRON_BLOCK : BlockTypes.END_STONE).getDefaultState(); BlockVector3 min = clipboard.getMinimumPoint(); From ea3aad3bd2734e42ef1d88f2764e00d3687d09f4 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Fri, 28 Aug 2026 19:51:31 +0200 Subject: [PATCH 14/22] Initial FightSWCommand --- .../de/steamwar/fightsystem/ArenaMode.java | 1 + .../de/steamwar/fightsystem/FightSystem.java | 3 - .../fightsystem/commands/AkCommand.java | 26 ++--- .../fightsystem/commands/FightSWCommand.java | 95 +++++++++++++++++++ .../fightsystem/commands/GamemodeCommand.java | 84 ++-------------- .../fightsystem/commands/InfoCommand.java | 22 ++--- .../fightsystem/commands/KitCommand.java | 27 ++---- .../fightsystem/commands/LeaveCommand.java | 18 +--- .../commands/LockschemCommand.java | 30 ++---- .../fightsystem/commands/ReadyCommand.java | 18 +--- .../fightsystem/commands/RemoveCommand.java | 26 +---- .../fightsystem/commands/RequestsCommand.java | 21 ++-- .../fightsystem/commands/SkipCommand.java | 18 +--- .../fightsystem/commands/StateCommand.java | 19 +--- .../fightsystem/commands/TBCommand.java | 16 +--- .../fightsystem/commands/TPSWarpCommand.java | 24 +---- .../fightsystem/commands/TechareaCommand.java | 39 ++++---- .../commands/TechhiderbugCommand.java | 16 ++-- .../fightsystem/commands/WGCommand.java | 16 +--- .../fightsystem/commands/WinCommand.java | 39 +++----- .../steamwar/fightsystem/listener/Check.java | 4 + .../fightsystem/states/FightState.java | 3 + .../states/StateDependentCommand.java | 58 ----------- FightSystem/FightSystem_Core/src/plugin.yml | 20 +--- FightSystem/build.gradle.kts | 12 +++ 25 files changed, 239 insertions(+), 416 deletions(-) create mode 100644 FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/FightSWCommand.java delete mode 100644 FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/states/StateDependentCommand.java diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ArenaMode.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ArenaMode.java index e65ce94c6..f430ed72c 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ArenaMode.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/ArenaMode.java @@ -39,6 +39,7 @@ public enum ArenaMode { public static final Set Test = Collections.unmodifiableSet(EnumSet.of(TEST, CHECK)); public static final Set Prepare = Collections.unmodifiableSet(EnumSet.of(PREPARE)); public static final Set Replay = Collections.unmodifiableSet(EnumSet.of(REPLAY, TEST)); + public static final Set TestOrReferee = Collections.unmodifiableSet(EnumSet.of(TEST, CHECK, EVENT)); public static final Set AntiReplay = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(REPLAY))); public static final Set AntiTest = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(TEST, CHECK))); diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java index 06ceac41f..ebfbf7c1f 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java @@ -22,7 +22,6 @@ package de.steamwar.fightsystem; import com.comphenix.tinyprotocol.TinyProtocol; import de.steamwar.core.Core; import de.steamwar.core.WorldEditRendererCUIEditor; -import de.steamwar.fightsystem.commands.TechareaCommand; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.listener.ClickAnalyzer; @@ -127,8 +126,6 @@ public class FightSystem extends JavaPlugin { if (checkSchematicNode.isPrepared()) { Fight.getRedTeam().setSchem(checkSchematicNode, NodeData.getRevisions(checkSchematicNode) - 1); } - - new TechareaCommand(); } else if (Config.mode == ArenaMode.PREPARE) { Fight.getUnrotated().setSchem(SchematicNode.getSchematicNode(Config.PrepareSchemID)); } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/AkCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/AkCommand.java index b1ffede2a..e12099769 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/AkCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/AkCommand.java @@ -24,35 +24,25 @@ import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.fight.Kit; import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.StateDependentCommand; import de.steamwar.linkage.Linked; import de.steamwar.sql.SteamwarUser; import de.steamwar.sql.UserPerm; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @Linked -public class AkCommand implements CommandExecutor { +public class AkCommand extends FightSWCommand { public AkCommand() { - new StateDependentCommand(ArenaMode.Test, FightState.All, "ak", this); + super(ArenaMode.Test, FightState.All, "ak"); } @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!(sender instanceof Player)) { - return false; - } - Player player = (Player) sender; - if (!player.isOp()) return false; + protected boolean hasPerm(Player player, SteamwarUser user) { + return player.isOp() && user.hasPerm(UserPerm.ADMINISTRATION) && Core.getInstance() != FightSystem.getPlugin(); + } - if (!SteamwarUser.get(player.getUniqueId()).hasPerm(UserPerm.ADMINISTRATION) && Core.getInstance() != FightSystem.getPlugin()) { - return false; - } - - Kit.createKit(args[0], player); - return false; + @Register + public void run(@Validator Player player, String name) { + Kit.createKit(name, player); } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/FightSWCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/FightSWCommand.java new file mode 100644 index 000000000..c9563d9d2 --- /dev/null +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/FightSWCommand.java @@ -0,0 +1,95 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2026 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.fightsystem.commands; + +import de.steamwar.command.SWCommand; +import de.steamwar.command.TypeValidator; +import de.steamwar.fightsystem.ArenaMode; +import de.steamwar.fightsystem.states.FightState; +import de.steamwar.fightsystem.states.StateDependent; +import de.steamwar.sql.SteamwarUser; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerCommandSendEvent; + +import java.util.Set; + +public abstract class FightSWCommand extends SWCommand implements Listener { + + private final String command; + private final String[] aliases; + + protected FightSWCommand(Set mode, Set states, String command) { + super(command); + this.command = command; + this.aliases = new String[0]; + stateDependant(mode, states); + } + + protected FightSWCommand(Set mode, Set states, String command, String... aliases) { + super(command, aliases); + this.command = command; + this.aliases = aliases; + stateDependant(mode, states); + } + + private void stateDependant(Set mode, Set states) { + FightSWCommand.this.unregister(); + new StateDependent(mode, states) { + @Override + public void enable() { + System.out.println("--- Enable: " + command); + FightSWCommand.this.register(); + } + + @Override + public void disable() { + System.out.println("--- Disable: " + command); + FightSWCommand.this.unregister(); + } + }.register(); + } + + public static void postFightStateChange() { + for (Player player : Bukkit.getOnlinePlayers()) { + player.updateCommands(); + } + } + + protected boolean hasPerm(Player player, SteamwarUser user) { + return true; + } + + @EventHandler(ignoreCancelled = true) + public final void onPlayerCommandSend(PlayerCommandSendEvent event) { + if (hasPerm(event.getPlayer(), SteamwarUser.get(event.getPlayer().getUniqueId()))) return; + event.getCommands().remove(command); + for (String alias : aliases) { + event.getCommands().remove(alias); + } + } + + @ClassValidator(value = Player.class, local = true) + public final TypeValidator permissionCheck() { + return (sender, value, messageSender) -> hasPerm(value, SteamwarUser.get(value.getUniqueId())); + } +} diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/GamemodeCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/GamemodeCommand.java index 1ac590653..67eabdde6 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/GamemodeCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/GamemodeCommand.java @@ -19,92 +19,28 @@ package de.steamwar.fightsystem.commands; -import com.google.common.collect.ImmutableList; +import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.Config; -import de.steamwar.fightsystem.FightSystem; +import de.steamwar.fightsystem.states.FightState; import de.steamwar.linkage.Linked; -import net.md_5.bungee.api.ChatMessageType; -import org.bukkit.Bukkit; +import de.steamwar.sql.SteamwarUser; import org.bukkit.GameMode; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.command.defaults.BukkitCommand; -import org.bukkit.craftbukkit.CraftServer; import org.bukkit.entity.Player; -import org.bukkit.util.StringUtil; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; @Linked -public class GamemodeCommand extends BukkitCommand { - - private static final List GAMEMODE_NAMES = ImmutableList.of("adventure", "creative", "survival", - "spectator"); +public class GamemodeCommand extends FightSWCommand { public GamemodeCommand() { - super("gamemode"); - List aliases = new ArrayList<>(); - aliases.add("gm"); - this.setAliases(aliases); - - Map knownCommands = ((CraftServer) Bukkit.getServer()).getCommandMap().getKnownCommands(); - knownCommands.remove("gamemode"); - Commands.injectCommand(this); + super(ArenaMode.TestOrReferee, FightState.All, "gamemode", "gm"); } @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!(sender instanceof Player)) { - return false; - } else if (args.length == 0) { - FightSystem.getMessage().sendPrefixless("GAMEMODE_HELP", sender); - return false; - } - - Player p = (Player) sender; - - if (!(Config.test() || Config.isReferee(p))) { - FightSystem.getMessage().sendPrefixless("GAMEMODE_NOT_ALLOWED", p, ChatMessageType.ACTION_BAR); - return false; - } - - GameMode mode = createMode(args[0]); - - if (mode == null) { - FightSystem.getMessage().sendPrefixless("GAMEMODE_UNKNOWN", p, ChatMessageType.ACTION_BAR, args[0]); - return false; - } - - p.setGameMode(mode); - return true; + protected boolean hasPerm(Player player, SteamwarUser user) { + return Config.test() || Config.isReferee(player); } - @SuppressWarnings("deprecation") - private GameMode createMode(String modeArg) { - try { - return GameMode.getByValue(Integer.parseInt(modeArg)); - } catch (NumberFormatException ignored) { - if ((modeArg.equalsIgnoreCase("creative")) || (modeArg.equalsIgnoreCase("c"))) { - return GameMode.CREATIVE; - } else if ((modeArg.equalsIgnoreCase("adventure")) || (modeArg.equalsIgnoreCase("a"))) { - return GameMode.ADVENTURE; - } else if ((modeArg.equalsIgnoreCase("spectator")) || (modeArg.equalsIgnoreCase("sp"))) { - return GameMode.SPECTATOR; - } else if ((modeArg.equalsIgnoreCase("survival")) || (modeArg.equalsIgnoreCase("s"))) { - return GameMode.SURVIVAL; - } - } - return null; + @Register(description = "GAMEMODE_HELP") + public void execute(@Validator Player player, GameMode gameMode) { + player.setGameMode(gameMode); } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) { - if (args.length == 1) { - return StringUtil.copyPartialMatches(args[0], GAMEMODE_NAMES, new ArrayList<>(GAMEMODE_NAMES.size())); - } - return ImmutableList.of(); - } - } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/InfoCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/InfoCommand.java index 4fc8e96ca..5b3717ebc 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/InfoCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/InfoCommand.java @@ -20,34 +20,31 @@ package de.steamwar.fightsystem.commands; import de.steamwar.fightsystem.ArenaMode; +import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightTeam; +import de.steamwar.fightsystem.listener.Check; import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.StateDependentCommand; import de.steamwar.linkage.Linked; import de.steamwar.sql.SchematicNode; import de.steamwar.sql.SteamwarUser; -import de.steamwar.sql.UserPerm; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @Linked -public class InfoCommand implements CommandExecutor { +public class InfoCommand extends FightSWCommand { public InfoCommand() { - new StateDependentCommand(ArenaMode.All, FightState.All, "fightinfo", this); + super(ArenaMode.All, FightState.All, "fightinfo"); } @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!(sender instanceof Player)) return false; - - Player player = (Player) sender; - if (!SteamwarUser.get(player.getUniqueId()).hasPerm(UserPerm.CHECK)) return false; + protected boolean hasPerm(Player player, SteamwarUser user) { + return Check.checkPermission(user, Config.GameModeConfig); + } + @Register + public void run(@Validator Player player) { for (FightTeam team : Fight.teams()) { if (!team.isLeaderless()) { FightSystem.getMessage().send("INFO_LEADER", player, team.getColoredName(), team.getLeader().getEntity().getName()); @@ -58,6 +55,5 @@ public class InfoCommand implements CommandExecutor { FightSystem.getMessage().send("INFO_SCHEMATIC", player, team.getColoredName(), schematic.getName(), SteamwarUser.byId(schematic.getOwner()).getUserName(), schematic.getRank()); } } - return false; } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/KitCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/KitCommand.java index bbbe07cbe..0d6675961 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/KitCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/KitCommand.java @@ -21,32 +21,23 @@ package de.steamwar.fightsystem.commands; import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.StateDependentCommand; import de.steamwar.linkage.Linked; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @Linked -public class KitCommand implements CommandExecutor { +public class KitCommand extends FightSWCommand { public KitCommand() { - new StateDependentCommand(ArenaMode.AntiReplay, FightState.Setup, "kit", this); + super(ArenaMode.AntiReplay, FightState.Setup, "kit"); } - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!(sender instanceof Player)) { - return false; - } - Player player = (Player) sender; + @Register + public void execute(Player player) { + GUI.kitSelection(player, ""); + } - if (args.length != 1) { - GUI.kitSelection(player, ""); - } else { - Commands.kit(player, args[0]); - } - return false; + @Register + public void execute(Player player, String query) { // TODO: TabCompletion of Kit Names! + GUI.kitSelection(player, query); } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/LeaveCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/LeaveCommand.java index 8d63e060d..bd493e424 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/LeaveCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/LeaveCommand.java @@ -21,28 +21,18 @@ package de.steamwar.fightsystem.commands; import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.StateDependentCommand; import de.steamwar.linkage.Linked; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @Linked -public class LeaveCommand implements CommandExecutor { +public class LeaveCommand extends FightSWCommand { public LeaveCommand() { - new StateDependentCommand(ArenaMode.AntiReplay, FightState.Setup, "leave", this); + super(ArenaMode.AntiReplay, FightState.Setup, "leave"); } - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!(sender instanceof Player)) { - return false; - } - Player player = (Player) sender; - + @Register + public void execute(Player player) { Commands.leaveTeam(player); - return false; } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/LockschemCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/LockschemCommand.java index 4487b30fd..eb1633d09 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/LockschemCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/LockschemCommand.java @@ -20,52 +20,42 @@ package de.steamwar.fightsystem.commands; import de.steamwar.fightsystem.ArenaMode; +import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightTeam; +import de.steamwar.fightsystem.listener.Check; import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.StateDependentCommand; import de.steamwar.linkage.Linked; import de.steamwar.sql.SchematicNode; import de.steamwar.sql.SchematicType; import de.steamwar.sql.SteamwarUser; -import de.steamwar.sql.UserPerm; import net.md_5.bungee.api.ChatMessageType; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @Linked -public class LockschemCommand implements CommandExecutor { +public class LockschemCommand extends FightSWCommand { public LockschemCommand() { - new StateDependentCommand(ArenaMode.All, FightState.Schem, "lockschem", this); + super(ArenaMode.All, FightState.Schem, "lockschem"); } @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!(sender instanceof Player)) return false; - Player player = (Player) sender; + protected boolean hasPerm(Player player, SteamwarUser user) { + return Check.checkPermission(user, Config.GameModeConfig); + } - if (!SteamwarUser.get(player.getUniqueId()).hasPerm(UserPerm.CHECK)) return false; - - if (args.length != 1) { - FightSystem.getMessage().sendPrefixless("LOCKSCHEM_HELP", player); - return false; - } - - String teamName = args[0]; + @Register(description = "LOCKSCHEM_HELP") + public void execute(@Validator Player player, String teamName) { FightTeam fightTeam = Fight.getTeamByName(teamName); if (fightTeam == null) { FightSystem.getMessage().sendPrefixless("UNKNOWN_TEAM", player, ChatMessageType.ACTION_BAR); - return false; + return; } SchematicNode.getSchematicNode(fightTeam.getSchematic()).setSchemtype(SchematicType.Normal); FightSystem.getMessage().sendPrefixless("LOCKSCHEM_LOCKED", player, ChatMessageType.ACTION_BAR); fightTeam.broadcastSystem("LOCKSCHEM_LOCKED_BY", player.getName()); - return false; } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/ReadyCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/ReadyCommand.java index 323866399..8d3d1d9f7 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/ReadyCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/ReadyCommand.java @@ -21,28 +21,18 @@ package de.steamwar.fightsystem.commands; import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.StateDependentCommand; import de.steamwar.linkage.Linked; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @Linked -public class ReadyCommand implements CommandExecutor { +public class ReadyCommand extends FightSWCommand { public ReadyCommand() { - new StateDependentCommand(ArenaMode.AntiPrepare, FightState.PostSchemSetup, "ready", this); + super(ArenaMode.AntiPrepare, FightState.PostSchemSetup, "ready"); } - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!(sender instanceof Player)) { - return false; - } - Player player = (Player) sender; - + @Register + public void execute(Player player) { Commands.toggleReady(player); - return false; } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/RemoveCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/RemoveCommand.java index 60c083392..31fd0bcf4 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/RemoveCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/RemoveCommand.java @@ -20,35 +20,19 @@ package de.steamwar.fightsystem.commands; import de.steamwar.fightsystem.ArenaMode; -import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.StateDependentCommand; import de.steamwar.linkage.Linked; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @Linked -public class RemoveCommand implements CommandExecutor { +public class RemoveCommand extends FightSWCommand { public RemoveCommand() { - new StateDependentCommand(ArenaMode.VariableTeams, FightState.Setup, "remove", this); + super(ArenaMode.VariableTeams, FightState.Setup, "remove"); } - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!(sender instanceof Player)) { - return false; - } - Player player = (Player) sender; - - if (args.length != 1) { - FightSystem.getMessage().sendPrefixless("REMOVE_HELP", player); - return false; - } - - Commands.kick(player, args[0]); - return false; + @Register(description = "REMOVE_HELP") + public void execute(Player player, Player teamMember) { + Commands.kick(player, teamMember.getName()); } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/RequestsCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/RequestsCommand.java index 36cb8fba8..9f66106e1 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/RequestsCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/RequestsCommand.java @@ -26,37 +26,28 @@ import de.steamwar.fightsystem.fight.FightPlayer; import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.fight.JoinRequest; import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.StateDependentCommand; import de.steamwar.linkage.Linked; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.function.BiConsumer; @Linked -public class RequestsCommand implements CommandExecutor { +public class RequestsCommand extends FightSWCommand { public RequestsCommand() { - new StateDependentCommand(ArenaMode.VariableTeams, FightState.AntiSpectate, "request", this); - new StateDependentCommand(ArenaMode.VariableTeams, FightState.AntiSpectate, "requests", this); + super(ArenaMode.VariableTeams, FightState.AntiSpectate, "request", "requests"); } - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!(sender instanceof Player)) return false; - Player player = (Player) sender; + @Register + public void execute(Player player) { FightPlayer fp = Fight.getFightPlayer(player); if (fp == null || !(fp.isLeader() || fp.isLiving())) { GUI.joinRequest(player); - return false; + return; } - if (Commands.checkGetLeader(player) == null) return false; - + if (Commands.checkGetLeader(player) == null) return; GUI.chooseJoinRequests(player); - return false; } public static void onJoinRequest(Player player, JoinRequest request, BiConsumer handleJoinRequest) { diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/SkipCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/SkipCommand.java index 3fef2cb53..90b20a700 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/SkipCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/SkipCommand.java @@ -24,32 +24,22 @@ import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.record.PacketProcessor; import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.StateDependentCommand; import de.steamwar.linkage.Linked; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @Linked -public class SkipCommand implements CommandExecutor { +public class SkipCommand extends FightSWCommand { public SkipCommand() { - new StateDependentCommand(ArenaMode.AntiPrepare, ArenaMode.Replay.contains(Config.mode) ? FightState.All : FightState.TeamFix, "skip", this); + super(ArenaMode.AntiPrepare, ArenaMode.Replay.contains(Config.mode) ? FightState.All : FightState.TeamFix, "skip"); } - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!(sender instanceof Player)) { - return false; - } - Player player = (Player) sender; - + @Register + public void execute(Player player) { if (PacketProcessor.isReplaying() && player.getUniqueId().equals(Fight.getBlueTeam().getDesignatedLeader())) { PacketProcessor.currentReplay().skipToSubtitle(); } else { Commands.toggleSkip(player); } - return false; } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/StateCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/StateCommand.java index 338dcd5d8..d23b0f854 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/StateCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/StateCommand.java @@ -21,27 +21,18 @@ package de.steamwar.fightsystem.commands; import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.StateDependentCommand; import de.steamwar.linkage.Linked; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @Linked -public class StateCommand implements CommandExecutor { +public class StateCommand extends FightSWCommand { public StateCommand() { - new StateDependentCommand(ArenaMode.Test, FightState.All, "state", this); + super(ArenaMode.Test, FightState.All, "state"); } - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!(sender instanceof Player)) { - return false; - } - - GUI.state((Player) sender); - return false; + @Register + public void execute(Player player) { + GUI.state(player); } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TBCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TBCommand.java index 2e627e4aa..958ff3835 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TBCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TBCommand.java @@ -22,26 +22,18 @@ package de.steamwar.fightsystem.commands; import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.StateDependentCommand; import de.steamwar.linkage.Linked; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @Linked -public class TBCommand implements CommandExecutor { +public class TBCommand extends FightSWCommand { public TBCommand() { - new StateDependentCommand(ArenaMode.Check, FightState.All, "resettb", this); + super(ArenaMode.Check, FightState.All, "resettb"); } - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!(sender instanceof Player)) { - return false; - } + @Register + public void execute(Player player) { Fight.getRedTeam().pasteSchem(); - return false; } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TPSWarpCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TPSWarpCommand.java index 6ec55acd7..e7f6173c7 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TPSWarpCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TPSWarpCommand.java @@ -20,34 +20,20 @@ package de.steamwar.fightsystem.commands; import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.StateDependentCommand; import de.steamwar.linkage.Linked; import net.minecraft.server.MinecraftServer; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; @Linked -public class TPSWarpCommand implements CommandExecutor { +public class TPSWarpCommand extends FightSWCommand { public TPSWarpCommand() { - new StateDependentCommand(ArenaMode.Prepare, FightState.PostSchemSetup, "tpswarp", this); - new StateDependentCommand(ArenaMode.Prepare, FightState.PostSchemSetup, "tpslimit", this); + super(ArenaMode.Prepare, FightState.PostSchemSetup, "tpswarp", "tpslimit"); } - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - float tps; - try { - tps = Float.parseFloat(args[0]); - } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) { - FightSystem.getMessage().send("TPSWARP_HELP", sender); - return false; - } - + @Register(description = "TPSWARP_HELP") + public void execute(Player player, float tps) { MinecraftServer.getServer().tickRateManager().setTickRate(tps); - FightSystem.getMessage().broadcastActionbar("TPSWARP_SET", tps); - return false; } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TechareaCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TechareaCommand.java index 880e1843e..145f9271e 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TechareaCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TechareaCommand.java @@ -19,42 +19,39 @@ package de.steamwar.fightsystem.commands; -import de.steamwar.command.SWCommand; import de.steamwar.entity.CWireframe; import de.steamwar.entity.REntityServer; +import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.Config; -import de.steamwar.fightsystem.FightSystem; -import org.bukkit.Bukkit; +import de.steamwar.fightsystem.states.FightState; +import de.steamwar.fightsystem.states.OneShotStateDependent; +import de.steamwar.linkage.Linked; import org.bukkit.Material; import org.bukkit.entity.Player; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -public class TechareaCommand extends SWCommand { - private final Map servers = new HashMap<>(); +@Linked +public class TechareaCommand extends FightSWCommand { + private REntityServer entityServer = new REntityServer(); public TechareaCommand() { - super("techarea"); - - Bukkit.getScheduler().runTaskTimer(FightSystem.getPlugin(), () -> servers.forEach((uuid, rEntityServer) -> rEntityServer.tick()), 2, 2); - } - - @Register - public void genericCommand(Player player) { - if (servers.containsKey(player.getUniqueId())) { - servers.get(player.getUniqueId()).close(); - } else { + super(ArenaMode.Check, FightState.All, "techarea"); + new OneShotStateDependent(ArenaMode.Check, FightState.All, () -> { + if (!entityServer.getEntities().isEmpty()) return; REntityServer server = new REntityServer(); CWireframe wireframe = new CWireframe(server); wireframe.setPos1(Config.BlueInsetRegion.getMinLocation(Config.world)); wireframe.setPos2(Config.BlueInsetRegion.getMaxLocation(Config.world).subtract(1, 1, 1)); wireframe.setBlock(Material.RED_CONCRETE.createBlockData()); + }); + } - server.addPlayer(player); - servers.put(player.getUniqueId(), server); + @Register + public void genericCommand(Player player) { + if (entityServer.getPlayers().contains(player)) { + entityServer.removePlayer(player); + } else { + entityServer.addPlayer(player); } } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TechhiderbugCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TechhiderbugCommand.java index 6e89d7274..5527176bb 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TechhiderbugCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TechhiderbugCommand.java @@ -25,27 +25,24 @@ import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.StateDependentCommand; import de.steamwar.linkage.Linked; import de.steamwar.sql.SWException; import org.bukkit.Bukkit; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import java.io.StringWriter; import java.util.Arrays; import java.util.logging.Level; @Linked -public class TechhiderbugCommand implements CommandExecutor { +public class TechhiderbugCommand extends FightSWCommand { public TechhiderbugCommand() { - new StateDependentCommand(ArenaMode.All, FightState.All, "techhiderbug", this); + super(ArenaMode.All, FightState.All, "techhiderbug"); } - @Override - public boolean onCommand(CommandSender sender, Command cmd, String alias, String[] args) { + @Register + public void execute(Player player, String... args) { StringWriter writer = new StringWriter(); try { @@ -76,7 +73,6 @@ public class TechhiderbugCommand implements CommandExecutor { Bukkit.getLogger().log(Level.SEVERE, "Error while generating bug report", e); } - SWException.log("Techhider-Bug reported by " + sender.getName() + ": " + Arrays.toString(args), writer.toString()); - return false; + SWException.log("Techhider-Bug reported by " + player.getName() + ": " + Arrays.toString(args), writer.toString()); } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/WGCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/WGCommand.java index c88ae122c..5be6ea6ff 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/WGCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/WGCommand.java @@ -23,28 +23,20 @@ import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightWorld; import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.StateDependentCommand; import de.steamwar.linkage.Linked; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @Linked -public class WGCommand implements CommandExecutor { +public class WGCommand extends FightSWCommand { public WGCommand() { - new StateDependentCommand(ArenaMode.Check, FightState.All, "resetwg", this); + super(ArenaMode.Check, FightState.All, "resetwg"); } - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!(sender instanceof Player)) { - return false; - } + @Register + public void execute(Player player) { FightWorld.resetWorld(); Fight.getBlueTeam().pasteSchem(); Fight.getRedTeam().pasteSchem(); - return false; } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/WinCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/WinCommand.java index e928faf46..945482fb1 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/WinCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/WinCommand.java @@ -25,49 +25,34 @@ import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.StateDependentCommand; import de.steamwar.linkage.Linked; -import net.md_5.bungee.api.ChatMessageType; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; +import de.steamwar.sql.SteamwarUser; import org.bukkit.entity.Player; @Linked -public class WinCommand implements CommandExecutor { +public class WinCommand extends FightSWCommand { public WinCommand() { - new StateDependentCommand(ArenaMode.Event, FightState.Ingame, "win", this); + super(ArenaMode.Event, FightState.Ingame, "win"); } @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!(sender instanceof Player)) { - return false; - } - Player p = (Player) sender; + protected boolean hasPerm(Player player, SteamwarUser user) { + return Config.isReferee(player); + } - if (!Config.isReferee(p)) { - FightSystem.getMessage().sendPrefixless("NOT_FIGHTLEADER", p, ChatMessageType.ACTION_BAR); - return false; - } - - if (args.length == 0) { - FightSystem.getMessage().sendPrefixless("WIN_HELP", p); - return false; - } - - if (args[0].equalsIgnoreCase("tie")) { + @Register + public void execute(@Validator Player player, String teamName) { + if (teamName.equalsIgnoreCase("tie")) { FightSystem.setSpectateState(null, "Referee", "WIN_FIGHTLEADER"); - return false; + return; } for (FightTeam team : Fight.teams()) { - if (args[0].equalsIgnoreCase(team.getName())) { + if (teamName.equalsIgnoreCase(team.getName())) { FightSystem.setSpectateState(team, "Referee", "WIN_FIGHTLEADER"); - return false; + return; } } - return false; } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java index fc7240876..f8ab148a6 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Check.java @@ -51,6 +51,10 @@ public class Check implements Listener { .findFirst() .orElse(null); if (gameModeConfig == null) gameModeConfig = GameModeConfig.getDefaults(); + return checkPermission(user, gameModeConfig); + } + + public static boolean checkPermission(SteamwarUser user, GameModeConfig gameModeConfig) { if (user.hasPerm(UserPerm.ADMINISTRATION)) return true; if (gameModeConfig.Checkers.isEmpty() && user.hasPerm(UserPerm.CHECK)) return true; return gameModeConfig.Checkers.contains(user.getId()); diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/states/FightState.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/states/FightState.java index c2fe57909..ee1323399 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/states/FightState.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/states/FightState.java @@ -19,6 +19,7 @@ package de.steamwar.fightsystem.states; +import de.steamwar.fightsystem.commands.FightSWCommand; import lombok.Getter; import java.util.*; @@ -62,6 +63,7 @@ public enum FightState { } public static void setFightState(FightState state) { + if (fightState.equals(state)) return; fightState = state; for (Map.Entry feature : stateDependentFeatures.entrySet()) { @@ -77,6 +79,7 @@ public enum FightState { feature.setValue(false); } } + FightSWCommand.postFightStateChange(); } public static boolean setup() { diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/states/StateDependentCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/states/StateDependentCommand.java deleted file mode 100644 index 53ea244ab..000000000 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/states/StateDependentCommand.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2025 SteamWar.de-Serverteam - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package de.steamwar.fightsystem.states; - -import de.steamwar.fightsystem.ArenaMode; -import de.steamwar.fightsystem.FightSystem; -import net.md_5.bungee.api.ChatMessageType; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.PluginCommand; - -import java.util.Set; - -public class StateDependentCommand extends StateDependent { - - private static final CommandExecutor unavailable = (sender, cmd, s, strings) -> { - FightSystem.getMessage().sendPrefixless("COMMAND_CURRENTLY_UNAVAILABLE", sender, ChatMessageType.ACTION_BAR); - return false; - }; - - private final PluginCommand command; - private final CommandExecutor executor; - - public StateDependentCommand(Set mode, Set states, String name, CommandExecutor executor) { - super(mode, states); - this.executor = executor; - this.command = FightSystem.getPlugin().getCommand(name); - assert command != null; - disable(); - register(); - } - - @Override - public void enable() { - command.setExecutor(executor); - } - - @Override - public void disable() { - command.setExecutor(unavailable); - } -} diff --git a/FightSystem/FightSystem_Core/src/plugin.yml b/FightSystem/FightSystem_Core/src/plugin.yml index c2a8393b2..56035ab11 100644 --- a/FightSystem/FightSystem_Core/src/plugin.yml +++ b/FightSystem/FightSystem_Core/src/plugin.yml @@ -10,22 +10,4 @@ depend: - WorldEdit api-version: "1.13" -commands: - ak: - request: - requests: - fightinfo: - leave: - ready: - kit: - remove: - lockschem: - state: - skip: - win: - resetwg: - resettb: - tpslimit: - tpswarp: - techhiderbug: - unrank: \ No newline at end of file +commands: \ No newline at end of file diff --git a/FightSystem/build.gradle.kts b/FightSystem/build.gradle.kts index 7079e0f14..cc5a3957a 100644 --- a/FightSystem/build.gradle.kts +++ b/FightSystem/build.gradle.kts @@ -53,3 +53,15 @@ tasks.register("WarGear21") { config = "WarGear21.yml" jar = "/jars/paper-1.21.6.jar" } + +tasks.register("WarShip21") { + group = "run" + description = "Run a WarShip 1.21 Fight Server" + dependsOn(":SpigotCore:shadowJar") + dependsOn(":FightSystem:shadowJar") + dependsOn(":KotlinCore:shadowJar") + template = "WarShip21" + worldName = "arenas/Artic" + config = "WarShip21.yml" + jar = "/jars/paper-1.21.6.jar" +} From b4487b807917386e424449c1abc44fd4d7a50307 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Sun, 30 Aug 2026 12:00:40 +0200 Subject: [PATCH 15/22] Update doc comment --- CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java b/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java index 51fbda837..17bfccb5a 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java +++ b/CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java @@ -797,7 +797,7 @@ public final class GameModeConfig { /** * Resolves one {@code Materials} entry to the concrete materials it denotes: {@code storage} - * for {@link SQLWrapper#getStorageMaterials()}, {@code all} for + * for {@link SQLWrapper#getStorageMaterials()}, {@code inventory} for * {@link SQLWrapper#getInventoryMaterials()}, or the material itself otherwise. */ private Set expandInventoryGroup(YMLWrapper loader, String name) { From 105eda32e66077119f3d75a22157dbffd0ada8c4 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Sun, 30 Aug 2026 12:15:22 +0200 Subject: [PATCH 16/22] Update CustomMap --- LobbySystem/src/de/steamwar/lobby/map/CustomMap.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/LobbySystem/src/de/steamwar/lobby/map/CustomMap.java b/LobbySystem/src/de/steamwar/lobby/map/CustomMap.java index aaa0ca637..5dd478a77 100644 --- a/LobbySystem/src/de/steamwar/lobby/map/CustomMap.java +++ b/LobbySystem/src/de/steamwar/lobby/map/CustomMap.java @@ -80,9 +80,12 @@ public class CustomMap implements Listener { if (mapFileOrDirectory.isDirectory()) { AtomicReference lastMonth = new AtomicReference<>(LocalDateTime.now().getMonth()); + AtomicReference lastModified = new AtomicReference<>(Long.MAX_VALUE); Bukkit.getScheduler().runTaskTimer(LobbySystem.getInstance(), () -> { + long modified = mapFileOrDirectory.lastModified(); Month current = LocalDateTime.now().getMonth(); - if (!current.equals(lastMonth.get()) || update) { + if (modified > lastModified.get() || !current.equals(lastMonth.get()) || update) { + lastModified.set(modified); lastMonth.set(current); update = false; this.mapFile = new File(mapFileOrDirectory, current.getValue() + ".png"); From a79b00f78f9f014e2f42ef88ceebbc2242da3ee0 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Sun, 30 Aug 2026 12:23:23 +0200 Subject: [PATCH 17/22] Fix EventCommand --- VelocityCore/src/de/steamwar/messages/BungeeCore.properties | 4 ++-- .../src/de/steamwar/velocitycore/commands/EventCommand.java | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/VelocityCore/src/de/steamwar/messages/BungeeCore.properties b/VelocityCore/src/de/steamwar/messages/BungeeCore.properties index a546955fb..25c9004e5 100644 --- a/VelocityCore/src/de/steamwar/messages/BungeeCore.properties +++ b/VelocityCore/src/de/steamwar/messages/BungeeCore.properties @@ -284,8 +284,8 @@ EVENT_COMING_TEAMS = §7 With§8: {0} EVENT_COMING_TEAM = §{0}{1} EVENT_CURRENT_EVENT = §e§l{0} EVENT_CURRENT_FIGHT_1 = §7{0} §{1}{2} -EVENT_CURRENT_FIGHT_VS = §8 vs -EVENT_CURRENT_FIGHT_2 = §{1}{2} +EVENT_CURRENT_FIGHT_VS = '§8 vs ' +EVENT_CURRENT_FIGHT_2 = §{0}{1} EVENT_CURRENT_FIGHT_WIN = §8: §7Victory §{0}{1} EVENT_CURRENT_FIGHT_DRAW = §8: §7Draw EVENT_TEAM_TABLE = §{0}{1}{2} §8 with §e{3} §7points diff --git a/VelocityCore/src/de/steamwar/velocitycore/commands/EventCommand.java b/VelocityCore/src/de/steamwar/velocitycore/commands/EventCommand.java index a775d71c8..3ac39d6f6 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/commands/EventCommand.java +++ b/VelocityCore/src/de/steamwar/velocitycore/commands/EventCommand.java @@ -19,7 +19,6 @@ package de.steamwar.velocitycore.commands; -import com.google.protobuf.MapEntry; import de.steamwar.command.PreviousArguments; import de.steamwar.command.SWCommand; import de.steamwar.command.TypeMapper; @@ -29,18 +28,15 @@ import de.steamwar.messages.Chatter; import de.steamwar.messages.PlayerChatter; import de.steamwar.persistent.Subserver; import de.steamwar.sql.*; -import de.steamwar.sql.Event; import de.steamwar.velocitycore.EventStarter; import de.steamwar.velocitycore.SubserverSystem; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; -import java.awt.*; import java.sql.Timestamp; import java.time.Instant; import java.time.format.DateTimeFormatter; import java.util.*; -import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; From 859238d7fa9e67138dfbec3119b45b2e8b421be7 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Sun, 30 Aug 2026 12:25:34 +0200 Subject: [PATCH 18/22] Disable 'showtable' in EventCommand --- .../src/de/steamwar/velocitycore/commands/EventCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VelocityCore/src/de/steamwar/velocitycore/commands/EventCommand.java b/VelocityCore/src/de/steamwar/velocitycore/commands/EventCommand.java index 3ac39d6f6..e92a12165 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/commands/EventCommand.java +++ b/VelocityCore/src/de/steamwar/velocitycore/commands/EventCommand.java @@ -90,7 +90,7 @@ public class EventCommand extends SWCommand { eventShowFightsPage(sender, currentEvent, 1); } - @Register(value = "showtable", description = "EVENT_SHOW_TABLE_USAGE") + // @Register(value = "showtable", description = "EVENT_SHOW_TABLE_USAGE") public void eventtable(Chatter sender, Event event) { if (!Instant.now().isBefore(event.getEnd().toInstant())) return; From 549f7e555c1f5c436e81754989c403772955ff72 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Sun, 30 Aug 2026 13:04:52 +0200 Subject: [PATCH 19/22] Remove NoTeamServer punishment --- CommonCore/SQL/src/de/steamwar/sql/Punishment.kt | 8 -------- .../src/de/steamwar/messages/BungeeCore.properties | 6 ------ .../src/de/steamwar/messages/BungeeCore_de.properties | 6 ------ .../src/de/steamwar/velocitycore/VelocityCore.java | 1 - 4 files changed, 21 deletions(-) diff --git a/CommonCore/SQL/src/de/steamwar/sql/Punishment.kt b/CommonCore/SQL/src/de/steamwar/sql/Punishment.kt index 8f5f3ed4e..3635ea251 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/Punishment.kt +++ b/CommonCore/SQL/src/de/steamwar/sql/Punishment.kt @@ -183,14 +183,6 @@ class Punishment(id: EntityID) : IntEntity(id) { "UNNOFIGHTSERVER", UserPerm.MODERATION ), - NoTeamServer( - "NOTEAMSERVER_TEAM", - "NOTEAMSERVER_PERMA", - "NOTEAMSERVER_UNTIL", - "UNNOTEAMSERVER_ERROR", - "UNNOTEAMSERVER", - UserPerm.MODERATION - ), Note("NOTE_TEAM", null, null, null, null, UserPerm.PUNISHMENTS, true); fun isMulti() = diff --git a/VelocityCore/src/de/steamwar/messages/BungeeCore.properties b/VelocityCore/src/de/steamwar/messages/BungeeCore.properties index 25c9004e5..6afbaf7e9 100644 --- a/VelocityCore/src/de/steamwar/messages/BungeeCore.properties +++ b/VelocityCore/src/de/steamwar/messages/BungeeCore.properties @@ -202,12 +202,6 @@ NOFIGHTSERVER_UNTIL = §7You are excluded from §e§lfighting§7 §euntil {0}§8 UNNOFIGHTSERVER_ERROR = §cThe player is not excluded from fighting. UNNOFIGHTSERVER = §e{0} §7may now join §e§lfights§7 again§8. -NOTEAMSERVER_TEAM = §e{0} §7was excluded from §e{1} {2} §7from §e§lteam servers§8: §f{3} -NOTEAMSERVER_PERMA = §7You are §epermanently§7 excluded from §e§lteam servers§8: §e{0} -NOTEAMSERVER_UNTIL = §7You are excluded from §e§lteam servers§7 §euntil {0}§8: §e{1} -UNNOTEAMSERVER_ERROR = §cThe player is not excluded from team servers. -UNNOTEAMSERVER = §e{0} §7may now set §e§lteam servers§7 again§8. - NOTE_TEAM = §e{0} §7received a §e§lnote§7 from §e{1} {2}: §f{3} #BugCommand diff --git a/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties b/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties index c284208b9..5921259a9 100644 --- a/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties +++ b/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties @@ -184,12 +184,6 @@ NOFIGHTSERVER_UNTIL = §7Du bist §ebis zum {0} §7vom §e§lKämpfen§7 ausgesc UNNOFIGHTSERVER_ERROR = §cDer Spieler ist nicht vom Kämpfen ausgeschlossen. UNNOFIGHTSERVER = §e{0} §7darf nun wieder §e§lKämpfen§7 beitreten§8. -NOTEAMSERVER_TEAM = §e{0} §7wurde von §e{1} {2} §7vom §e§lTeamserver§7 setzen ausgeschlossen§8: §f{3} -NOTEAMSERVER_PERMA = §7Du bist §epermanent §7vom §e§lTeamserver§7 setzen ausgeschlossen§8: §e{0} -NOTEAMSERVER_UNTIL = §7Du bist §ebis zum {0} §7vom §e§lTeamserver§7 setzen ausgeschlossen§8: §e{1} -UNNOTEAMSERVER_ERROR = §cDer Spieler ist nicht vom Teamserver setzten ausgeschlossen. -UNNOTEAMSERVER = §e{0} §7darf nun wieder §e§lTeamserver§7 setzen§8. - NOTE_TEAM = §e{0} §7erhielt von §e{1} {2} §7die §e§lNotiz§7§8: §f{3} #BugCommand diff --git a/VelocityCore/src/de/steamwar/velocitycore/VelocityCore.java b/VelocityCore/src/de/steamwar/velocitycore/VelocityCore.java index 31866c876..6240f0c0f 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/VelocityCore.java +++ b/VelocityCore/src/de/steamwar/velocitycore/VelocityCore.java @@ -149,7 +149,6 @@ public class VelocityCore implements ReloadablePlugin { new PunishmentCommand("noschemsubmitting", Punishment.PunishmentType.NoSchemSubmitting); new PunishmentCommand("nodev", Punishment.PunishmentType.NoDevServer); new PunishmentCommand("nofight", Punishment.PunishmentType.NoFightServer); - new PunishmentCommand("noteamserver", Punishment.PunishmentType.NoTeamServer); new PunishmentCommand("note", Punishment.PunishmentType.Note); linker = new AbstractLinker<>(this) { From f35c07ab5b39ac202d910e01644086b977394ddf Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Sun, 30 Aug 2026 16:12:32 +0200 Subject: [PATCH 20/22] Fix EventStarter --- VelocityCore/src/de/steamwar/velocitycore/EventStarter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VelocityCore/src/de/steamwar/velocitycore/EventStarter.java b/VelocityCore/src/de/steamwar/velocitycore/EventStarter.java index ce69ce325..5790e53e3 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/EventStarter.java +++ b/VelocityCore/src/de/steamwar/velocitycore/EventStarter.java @@ -86,7 +86,7 @@ public class EventStarter { } }).start(); - command = "/event " + blue.getTeamKuerzel(); + command = "/event team " + blue.getTeamKuerzel(); } else { command = "/" + spectatePorts.get(next.getSpectatePort()); } From ece12df0bcface6adf77e7a9a63c108c1870c85b Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Tue, 1 Sep 2026 10:32:56 +0200 Subject: [PATCH 21/22] Add SteamEdit --- .../src/de/steamwar/bausystem/BauSystem.java | 19 +- .../de/steamwar/fightsystem/FightSystem.java | 5 +- .../fightsystem/record/PacketProcessor.java | 2 +- .../SpigotCore_Main/src/SpigotCore.properties | 24 +- .../src/SpigotCore_de.properties | 19 +- .../de/steamwar/core/worldedit/SteamEdit.java | 73 ++++ .../worldedit/SteamEditSelectAdjacent.java | 116 +++++ .../core/worldedit/SteamEditWand.java | 406 ++++++++++++++++++ .../{ => worldedit}/WorldEditRenderer.java | 14 +- .../WorldEditRendererCUIEditor.java | 79 +++- .../WorldEditRendererFallback.java | 2 +- .../WorldEditRendererWrapper.java | 7 +- .../{ => worldedit}/WorldEditWrapper.java | 5 +- .../src/de/steamwar/inventory/SWItem.java | 12 + .../src/de/steamwar/sql/SchematicData.java | 2 +- .../src/de/steamwar/teamserver/Builder.java | 5 +- 16 files changed, 750 insertions(+), 40 deletions(-) create mode 100644 SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEdit.java create mode 100644 SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEditSelectAdjacent.java create mode 100644 SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEditWand.java rename SpigotCore/SpigotCore_Main/src/de/steamwar/core/{ => worldedit}/WorldEditRenderer.java (94%) rename SpigotCore/SpigotCore_Main/src/de/steamwar/core/{ => worldedit}/WorldEditRendererCUIEditor.java (61%) rename SpigotCore/SpigotCore_Main/src/de/steamwar/core/{ => worldedit}/WorldEditRendererFallback.java (99%) rename SpigotCore/SpigotCore_Main/src/de/steamwar/core/{ => worldedit}/WorldEditRendererWrapper.java (96%) rename SpigotCore/SpigotCore_Main/src/de/steamwar/core/{ => worldedit}/WorldEditWrapper.java (98%) diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/BauSystem.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/BauSystem.java index e1f7b11ab..5a8cac696 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/BauSystem.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/BauSystem.java @@ -32,6 +32,7 @@ import de.steamwar.bausystem.features.tracer.TraceManager; import de.steamwar.bausystem.features.tracer.TraceRecorder; import de.steamwar.bausystem.features.world.BauScoreboard; import de.steamwar.bausystem.linkage.BauGuiItem; +import de.steamwar.bausystem.region.Region; import de.steamwar.bausystem.region.RegionSystem; import de.steamwar.bausystem.utils.ScoreboardElement; import de.steamwar.bausystem.utils.TickManager; @@ -40,8 +41,9 @@ import de.steamwar.command.AbstractValidator; import de.steamwar.command.SWCommandUtils; import de.steamwar.core.CRIUSleepEvent; import de.steamwar.core.Core; -import de.steamwar.core.WorldEditRendererCUIEditor; import de.steamwar.core.WorldIdentifier; +import de.steamwar.core.worldedit.SteamEdit; +import de.steamwar.core.worldedit.WorldEditRendererCUIEditor; import de.steamwar.linkage.AbstractLinker; import de.steamwar.linkage.SpigotLinker; import de.steamwar.message.Message; @@ -49,6 +51,7 @@ import de.steamwar.providers.BauServerInfo; import lombok.Getter; import org.bukkit.Bukkit; import org.bukkit.GameRule; +import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -129,7 +132,19 @@ public class BauSystem extends JavaPlugin implements Listener { TraceManager.instance.init(); TraceRecorder.instance.init(); - new WorldEditRendererCUIEditor(); + SteamEdit.init(); + SteamEdit.ADJACENT_FILTERS = location -> { + Region region = Region.getRegion(location); + Region.Area area; + if (region.getBuildArea().inRegion(location, true)) { + area = region.getBuildArea(); + } else if (region.getTestblockArea().inRegion(location, true)) { + area = region.getTestblockArea(); + } else { + return SteamEdit.AdjacentFilter.ALWAYS; + } + return (x, y, z) -> area.inRegion(new Location(null, x, y, z), true); + }; Bukkit.getWorlds().get(0).setGameRule(GameRule.SEND_COMMAND_FEEDBACK, false); diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java index ebfbf7c1f..c676308e0 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java @@ -21,7 +21,8 @@ package de.steamwar.fightsystem; import com.comphenix.tinyprotocol.TinyProtocol; import de.steamwar.core.Core; -import de.steamwar.core.WorldEditRendererCUIEditor; +import de.steamwar.core.worldedit.SteamEdit; +import de.steamwar.core.worldedit.WorldEditRendererCUIEditor; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.listener.ClickAnalyzer; @@ -107,7 +108,7 @@ public class FightSystem extends JavaPlugin { } }); new OneShotStateDependent(ArenaMode.All, FightState.PreSchemSetup, () -> Fight.playSound(SWSound.BLOCK_NOTE_PLING.getSound(), 100.0f, 2.0f)); - new OneShotStateDependent(ArenaMode.Test, FightState.All, WorldEditRendererCUIEditor::new); + new OneShotStateDependent(ArenaMode.Test, FightState.All, SteamEdit::init); Config.world.setGameRule(GameRule.REDUCED_DEBUG_INFO, ArenaMode.AntiTest.contains(Config.mode)); hullHider = new HullHider(); diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java index 80fcf091c..72d728c67 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java @@ -20,7 +20,7 @@ package de.steamwar.fightsystem.record; import com.sk89q.worldedit.extent.clipboard.Clipboard; -import de.steamwar.core.WorldEditWrapper; +import de.steamwar.core.worldedit.WorldEditWrapper; import de.steamwar.entity.REntity; import de.steamwar.entity.REntityServer; import de.steamwar.entity.RPlayer; diff --git a/SpigotCore/SpigotCore_Main/src/SpigotCore.properties b/SpigotCore/SpigotCore_Main/src/SpigotCore.properties index 443c75831..e7e13eeb2 100644 --- a/SpigotCore/SpigotCore_Main/src/SpigotCore.properties +++ b/SpigotCore/SpigotCore_Main/src/SpigotCore.properties @@ -108,19 +108,33 @@ UNNOSCHEMSUBMITTING = §e{0} §7may now submit §e§lschematics§7 again§8. WORLDEDIT_CUI_TITLE = WorldEdit CUI WORLDEDIT_CUI_TITLE_SUBMENU = WorldEdit CUI - {0} -WORLDEDIT_CUI_SELECTION = Own Selection -WORLDEDIT_CUI_CLIPBOARD = Own Clipboard -WORLDEDIT_CUI_SELECTION_OTHER = Other Selection -WORLDEDIT_CUI_CLIPBOARD_OTHER = Other Clipboard +WORLDEDIT_CUI_SELECTION = Selection +WORLDEDIT_CUI_CLIPBOARD = Clipboard +WORLDEDIT_CUI_CURSOR = Cursor WORLDEDIT_CUI_MATERIAL_NAME = §eWorldEdit {0} WORLDEDIT_CUI_MATERIAL_CLICK = §7Click to edit WORLDEDIT_CUI_WIDTH_NAME = §eWidth {0} +WORLDEDIT_CUI_WIDTH_NAME_DIST = §eRange {0} WORLDEDIT_CUI_WIDTH_LORE = §8> §7{0} WORLDEDIT_CUI_WIDTH_LORE_SELECTED = §8> §e{0} WORLDEDIT_CUI_WIDTH_CLICK = §7Click to change + WORLDEDIT_CUI_WIDTH_HUGE = 1/ 8 Block WORLDEDIT_CUI_WIDTH_LARGE = 1/16 Block WORLDEDIT_CUI_WIDTH_MEDIUM = 1/32 Block -WORLDEDIT_CUI_WIDTH_SLIM = 1/64 Block \ No newline at end of file +WORLDEDIT_CUI_WIDTH_SLIM = 1/64 Block + +WORLDEDIT_CUI_WIDTH_HUGE_DIST = 40 Blocks +WORLDEDIT_CUI_WIDTH_LARGE_DIST = 30 Blocks +WORLDEDIT_CUI_WIDTH_MEDIUM_DIST = 20 Blocks +WORLDEDIT_CUI_WIDTH_SLIM_DIST = 10 Blocks + +WORLDEDIT_CUI_TOOL_SOON = §7Tool cooming soon! +WORLDEDIT_CUI_TOOL_COPY = §eCopy Tool +WORLDEDIT_CUI_TOOL_COPY_LORE = §eClick§8:§7 copy selection +WORLDEDIT_CUI_TOOL_PASTE = §ePaste Tool +WORLDEDIT_CUI_TOOL_PASTE_LORE_1 = §eClick§8:§7 paste clipboard +WORLDEDIT_CUI_TOOL_PASTE_LORE_2 = §eShift §8+§e Click§8:§7 paste clipboard and select +WORLDEDIT_CUI_TOOL_PASTE_LORE_3 = §eDrop§8:§7 paste clipboard at copy origin \ No newline at end of file diff --git a/SpigotCore/SpigotCore_Main/src/SpigotCore_de.properties b/SpigotCore/SpigotCore_Main/src/SpigotCore_de.properties index ba204d5e9..b7cba3c4f 100644 --- a/SpigotCore/SpigotCore_Main/src/SpigotCore_de.properties +++ b/SpigotCore/SpigotCore_Main/src/SpigotCore_de.properties @@ -101,13 +101,20 @@ NOSCHEMSUBMITTING_UNTIL = §7Du bist §ebis zum {0} §7vom §e§lEinsenden von S UNNOSCHEMSUBMITTING_ERROR = §cDer Spieler ist nicht vom Einsenden von Schematics ausgeschlossen. UNNOSCHEMSUBMITTING = §e{0} §7darf nun wieder §e§lSchematis§7 einsenden§8. -WORLDEDIT_CUI_SELECTION = Eigene Auswahl -WORLDEDIT_CUI_CLIPBOARD = Eigene Kopie -WORLDEDIT_CUI_SELECTION_OTHER = Auswahl Anderer -WORLDEDIT_CUI_CLIPBOARD_OTHER = Kopie Anderer +WORLDEDIT_CUI_SELECTION = Auswahl +WORLDEDIT_CUI_CLIPBOARD = Kopie WORLDEDIT_CUI_MATERIAL_NAME = §eWorldEdit {0} WORLDEDIT_CUI_MATERIAL_CLICK = §7Klicke zum Editieren -WORLDEDIT_CUI_WIDTH_NAME = §eDicke - {0} -WORLDEDIT_CUI_WIDTH_CLICK = §7Klicke zum ändern \ No newline at end of file +WORLDEDIT_CUI_WIDTH_NAME = §eKlicke - {0} +WORLDEDIT_CUI_WIDTH_NAME_DIST = Reichweite§e {0} +WORLDEDIT_CUI_WIDTH_CLICK = §7Klicke zum ändern + +WORLDEDIT_CUI_TOOL_SOON = §7Werkzeug kommt in kürze! +WORLDEDIT_CUI_TOOL_COPY = §eCopy Werkzeug +WORLDEDIT_CUI_TOOL_COPY_LORE = §eKlick§8:§7 Auswahl zu kopieren +WORLDEDIT_CUI_TOOL_PASTE = §ePaste Werkzeug +WORLDEDIT_CUI_TOOL_PASTE_LORE_1 = §eKlick§8:§7 Clipboard einzufügen +WORLDEDIT_CUI_TOOL_PASTE_LORE_2 = §eUmschalt §8+§e Klick§8:§7 Clipboard einzufügen und auszuwählen +WORLDEDIT_CUI_TOOL_PASTE_LORE_3 = §eDrop§8:§7 Clipboard am Kopierpunkt einzufügen \ No newline at end of file diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEdit.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEdit.java new file mode 100644 index 000000000..03c7922ef --- /dev/null +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEdit.java @@ -0,0 +1,73 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2026 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.core.worldedit; + +import de.steamwar.command.SWCommand; +import lombok.experimental.UtilityClass; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; + +@UtilityClass +public class SteamEdit { + + private static final AtomicBoolean INITIALIZED = new AtomicBoolean(); + + public static void init() { + INITIALIZED.set(true); + new Command(); + new SteamEditWand(); + new WorldEditRendererCUIEditor(); + } + + public boolean isInitialized() { + return INITIALIZED.get(); + } + + public static Function ADJACENT_FILTERS = location -> AdjacentFilter.ALWAYS; + + public interface AdjacentFilter { + AdjacentFilter ALWAYS = (x, y, z) -> true; + + boolean contains(int x, int y, int z); + } + + private static final class Command extends SWCommand { + + public Command() { + super("steamwand", "steamedit", "steameditwand", "swwand", "sweditwand", "swedit"); + } + + @Register + public void get(Player player) { + if (player.getInventory().contains(SteamEditWand.ITEM)) { + player.getInventory().remove(SteamEditWand.ITEM); + } + ItemStack handItem = player.getInventory().getItemInMainHand(); + player.getInventory().setItemInMainHand(SteamEditWand.ITEM); + if (!handItem.isEmpty()) { + player.getInventory().addItem(handItem); + } + } + } +} diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEditSelectAdjacent.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEditSelectAdjacent.java new file mode 100644 index 000000000..d30752aaf --- /dev/null +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEditSelectAdjacent.java @@ -0,0 +1,116 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2026 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.core.worldedit; + +import com.sk89q.worldedit.math.BlockVector3; +import de.steamwar.core.Core; +import org.bukkit.Location; +import org.bukkit.block.BlockFace; +import org.bukkit.util.Vector; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.stream.Stream; + +public class SteamEditSelectAdjacent { + + private static final BlockFace[] FACES = { + BlockFace.NORTH, + BlockFace.SOUTH, + BlockFace.EAST, + BlockFace.WEST, + BlockFace.UP, + BlockFace.DOWN, + }; + + private Location min; + private Location max; + + private SteamEdit.AdjacentFilter filter; + + private LinkedHashSet frontier = new LinkedHashSet<>(); + + public SteamEditSelectAdjacent(Location origin) { + min = origin.clone(); + max = origin.clone(); + frontier.add(origin); + filter = SteamEdit.ADJACENT_FILTERS.apply(origin); + + long time = System.currentTimeMillis(); + for (int i = 0; i < 500_000 && !frontier.isEmpty(); i++) { + if (System.currentTimeMillis() - time > 1000) break; + expandNext(); + } + + Core.getInstance().getLogger().finer(System.currentTimeMillis() - time + "ms " + frontier.size() + " " + min + " to " + max); + } + + public BlockVector3 pos1() { + return BlockVector3.at(min.getBlockX(), min.getBlockY(), min.getBlockZ()); + } + + public BlockVector3 pos2() { + return BlockVector3.at(max.getBlockX(), max.getBlockY(), max.getBlockZ()); + } + + private boolean inside(Location loc, int offset) { + return loc.getBlockX() >= min.getBlockX() + offset && loc.getBlockX() <= max.getBlockX() - offset && + loc.getBlockY() >= min.getBlockY() + offset && loc.getBlockY() <= max.getBlockY() - offset && + loc.getBlockZ() >= min.getBlockZ() + offset && loc.getBlockZ() <= max.getBlockZ() - offset; + } + + public void expandNext() { + Location location = frontier.removeFirst(); + expand(location); + } + + private void expand(Location loc) { + for (BlockFace face : FACES) { + Vector direction = face.getDirection(); + Location location = loc.clone().add(direction); + if (!filter.contains(location.getBlockX(), location.getBlockY(), location.getBlockZ())) continue; + if (inside(location, 0)) continue; + List layer = Stream.concat(selectFrontier(direction.getBlockX() == 0 ? null : loc.getBlockX(), direction.getBlockY() == 0 ? null : loc.getBlockY(), direction.getBlockZ() == 0 ? null : loc.getBlockZ()) + .map(Location::clone) + .map(l -> l.add(direction)), Stream.of(location)) + .filter(l -> !l.getBlock().isEmpty()) + .filter(l -> !l.getBlock().isLiquid()) + .toList(); + if (layer.isEmpty()) continue; + + if (direction.getBlockX() < 0 || direction.getBlockY() < 0 || direction.getBlockZ() < 0) { + min.add(direction); + } else { + max.add(direction); + } + layer.stream().filter(l -> !inside(l, 1)) + .filter(l -> filter.contains(l.getBlockX(), l.getBlockY(), l.getBlockZ())) + .forEach(frontier::add); + } + } + + private Stream selectFrontier(Integer x, Integer y, Integer z) { + Stream stream = frontier.stream(); + if (x != null) stream = stream.filter(loc -> loc.getBlockX() == x); + if (y != null) stream = stream.filter(loc -> loc.getBlockY() == y); + if (z != null) stream = stream.filter(loc -> loc.getBlockZ() == z); + return stream; + } +} diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEditWand.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEditWand.java new file mode 100644 index 000000000..85b85d580 --- /dev/null +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEditWand.java @@ -0,0 +1,406 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2026 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.core.worldedit; + +import com.comphenix.tinyprotocol.TinyProtocol; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.regions.selector.limit.PermissiveSelectorLimits; +import com.sk89q.worldedit.world.World; +import de.steamwar.core.Core; +import de.steamwar.core.SWPlayer; +import de.steamwar.entity.CWireframe; +import de.steamwar.entity.REntityServer; +import de.steamwar.inventory.SWItem; +import net.minecraft.core.BlockPos; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.*; +import org.bukkit.Bukkit; +import org.bukkit.FluidCollisionMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitTask; +import org.bukkit.util.RayTraceResult; + +import java.util.List; + +public class SteamEditWand implements Listener { + + public static final Material MATERIAL = Material.GOLDEN_AXE; + public static final String NAME = "§eSteam§8Edit §7Wand"; + public static final String[] LORE = { + "§eL-Click§8: §7Set Pos1", + "§eR-Click§8: §7Set Pos2", + "§eShift §8+ §eR-Click§8: §7Set Pos2 or Expand Selection", + "§eM-Click§8: §7Select connected", + "§eSwap-Hands§8: §7Open CUI" + }; + public static final ItemStack ITEM = new SWItem(MATERIAL, NAME).setLore(LORE).getItemStack(); + + private boolean noWand(Player player) { + return player.getInventory().getItemInMainHand().getType() != SteamEditWand.MATERIAL; + } + + private final WorldEditPlugin we; + + SteamEditWand() { + we = WorldEditWrapper.getWorldEditPlugin(); + Bukkit.getPluginManager().registerEvents(this, Core.getInstance()); + + TinyProtocol.instance.addFilter(ServerboundSwingPacket.class, this::leftClick); + TinyProtocol.instance.addFilter(ServerboundInteractPacket.class, (player, packet) -> { + if (packet.isAttack()) { + return leftClick(player, packet); + } else { + return rightClick(player, packet); + } + }); + TinyProtocol.instance.addFilter(ServerboundUseItemPacket.class, this::rightClick); + TinyProtocol.instance.addFilter(ServerboundUseItemOnPacket.class, this::rightClick); + TinyProtocol.instance.addFilter(ServerboundPickItemFromBlockPacket.class, this::middleClick); + TinyProtocol.instance.addFilter(ServerboundPlayerActionPacket.class, this::swapHands); + TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.Pos.class, this::movePlayerPacket); + TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.Rot.class, this::movePlayerPacket); + TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.PosRot.class, this::movePlayerPacket); + + Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> { + for (Player player : Bukkit.getOnlinePlayers()) { + if (noWand(player)) SWPlayer.of(player).removeComponent(SWEditCursor.class); + } + }, 1, 1); + } + + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) { + if (noWand(event.getPlayer())) return; + event.setCancelled(true); + } + + public static class SWEditCursor implements SWPlayer.Component { + private Player player; + private REntityServer entityServer = new REntityServer(); + private CWireframe wireframe; + + @Override + public void onMount(SWPlayer player) { + this.player = player.getPlayer(); + entityServer.addPlayer(player.getPlayer()); + wireframe = new CWireframe(entityServer); + } + + @Override + public void onUnmount(SWPlayer player) { + entityServer.close(); + } + + public void setLocation(Location location) { + float distance = (float) player.getLocation().distanceSquared(location); + wireframe.setPos1And2(location, location); + float width = distance / 1600; + width = ((int) (width * 16)) / 16F; + width = Math.max(width, 1 / 16F); + width = Math.min(width, 1 / 2F); + wireframe.setWidth(width); + wireframe.setBlock(WorldEditRendererCUIEditor.Type.CURSOR.getMaterial(player).createBlockData()); + } + } + + private Packet leftClick(Player player, Packet packet) { + if (noWand(player)) return packet; + if (player.getOpenInventory().getType() != InventoryType.CRAFTING) return packet; + double distance = WorldEditRendererCUIEditor.Type.CURSOR.getWidth(player).blocks; + RayTraceResult result = player.rayTraceBlocks(distance, FluidCollisionMode.NEVER); + if (result == null) return packet; + Block block = result.getHitBlock(); + if (block == null) return packet; + BlockVector3 pos1 = BlockVector3.at(block.getX(), block.getY(), block.getZ()); + setPos1(player, pos1); + return null; + } + + private void setPos1(Player player, BlockVector3 pos1) { + LocalSession session = we.getSession(player); + World world = session.getSelectionWorld(); + if (world == null) return; + selectPos1(session.getRegionSelector(world), player, session, pos1); + } + + private Packet rightClick(Player player, Packet packet) { + if (noWand(player)) return packet; + double distance = WorldEditRendererCUIEditor.Type.CURSOR.getWidth(player).blocks; + RayTraceResult result = player.rayTraceBlocks(distance, FluidCollisionMode.NEVER); + if (result == null) return packet; + Block block = result.getHitBlock(); + if (block == null) return packet; + BlockVector3 pos2 = BlockVector3.at(block.getX(), block.getY(), block.getZ()); + if (!player.isSneaking()) { + setPos2(player, pos2); + } else { + setPos2OrExpand(player, pos2); + } + return null; + } + + private void setPos2(Player player, BlockVector3 pos2) { + LocalSession session = we.getSession(player); + World world = session.getSelectionWorld(); + if (world == null) return; + selectPos2(session.getRegionSelector(world), player, session, pos2); + } + + private void setPos2OrExpand(Player player, BlockVector3 expand) { + LocalSession session = we.getSession(player); + World world = session.getSelectionWorld(); + if (world == null) return; + RegionSelector regionSelector = session.getRegionSelector(world); + + // Only primary set for now + if (!regionSelector.isDefined()) { + selectPos2(session.getRegionSelector(world), player, session, expand); + return; + } + + List vertices = regionSelector.getVertices(); + // Probably not a cuboid selection! + if (vertices.size() > 2) { + selectPos2(session.getRegionSelector(world), player, session, expand); + return; + } + + BlockVector3 pos1 = vertices.get(0); + BlockVector3 pos2 = vertices.get(1); + + BlockVector3 min = pos1.getMinimum(pos2); + BlockVector3 max = pos1.getMaximum(pos2); + if (expand.containedWithin(pos1, pos2)) { + return; + } + + Closer x = Closer.UNKNOWN; + Closer y = Closer.UNKNOWN; + Closer z = Closer.UNKNOWN; + + boolean insideX = min.x() < expand.x() && max.x() > expand.x(); + boolean insideY = min.y() < expand.y() && max.y() > expand.y(); + boolean insideZ = min.z() < expand.z() && max.z() > expand.z(); + + if (insideX) { + // No Change needed + } else if (Math.abs(pos1.x() - expand.x()) > Math.abs(pos2.x() - expand.x())) { + x = Closer.POS2; + } else if (Math.abs(pos1.x() - expand.x()) < Math.abs(pos2.x() - expand.x())) { + x = Closer.POS1; + } + + if (insideY) { + // No Change needed + } else if (Math.abs(pos1.y() - expand.y()) > Math.abs(pos2.y() - expand.y())) { + y = Closer.POS2; + } else if (Math.abs(pos1.y() - expand.y()) < Math.abs(pos2.y() - expand.y())) { + y = Closer.POS1; + } + + if (insideZ) { + // No Change needed + } else if (Math.abs(pos1.z() - expand.z()) > Math.abs(pos2.z() - expand.z())) { + z = Closer.POS2; + } else if (Math.abs(pos1.z() - expand.z()) < Math.abs(pos2.z() - expand.z())) { + z = Closer.POS1; + } + + Closer x1 = Closer.UNKNOWN; + Closer y1 = Closer.UNKNOWN; + Closer z1 = Closer.UNKNOWN; + + if (!insideX && pos1.x() != expand.x() && pos2.x() != expand.x() && x == Closer.UNKNOWN) { + x1 = y.and(z).or(Closer.POS1); + } + if (!insideY && pos1.y() != expand.y() && pos2.y() != expand.y() && y == Closer.UNKNOWN) { + y1 = x.and(z).or(Closer.POS1); + } + if (!insideZ && pos1.z() != expand.z() && pos2.z() != expand.z() && z == Closer.UNKNOWN) { + z1 = x.and(y).or(Closer.POS1); + } + + if (x1 != Closer.UNKNOWN) x = x1; + if (y1 != Closer.UNKNOWN) y = y1; + if (z1 != Closer.UNKNOWN) z = z1; + + boolean p1updated = false; + boolean p2updated = false; + + if (x == Closer.POS1) { + pos1 = pos1.withX(expand.x()); + p1updated = true; + } else if (x == Closer.POS2) { + pos2 = pos2.withX(expand.x()); + p2updated = true; + } + + if (y == Closer.POS1) { + pos1 = pos1.withY(expand.y()); + p1updated = true; + } else if (y == Closer.POS2) { + pos2 = pos2.withY(expand.y()); + p2updated = true; + } + + if (z == Closer.POS1) { + pos1 = pos1.withZ(expand.z()); + p1updated = true; + } else if (z == Closer.POS2) { + pos2 = pos2.withZ(expand.z()); + p2updated = true; + } + + if (p1updated) selectPos1(session.getRegionSelector(world), player, session, pos1); + if (p2updated) selectPos2(session.getRegionSelector(world), player, session, pos2); + } + + private enum Closer { + POS1, + POS2, + UNKNOWN, + ; + + public Closer and(Closer closer) { + if (this == closer) { + return this; + } else if (this == UNKNOWN) { + return closer; + } else if (closer == UNKNOWN) { + return this; + } else { + return UNKNOWN; + } + } + + public Closer or(Closer closer) { + if (this == UNKNOWN) return closer; + return this; + } + } + + private ServerboundPickItemFromBlockPacket middleClick(Player player, ServerboundPickItemFromBlockPacket packet) { + if (noWand(player)) return packet; + LocalSession session = we.getSession(player); + World world = session.getSelectionWorld(); + if (world == null) return packet; + RegionSelector regionSelector = session.getRegionSelector(world); + BlockPos pos = packet.pos(); + SteamEditSelectAdjacent selector = new SteamEditSelectAdjacent(new Location(player.getWorld(), pos.getX(), pos.getY(), pos.getZ())); + selectPos1(regionSelector, player, session, selector.pos1()); + selectPos2(regionSelector, player, session, selector.pos2()); + return null; + } + + private static class Pos1Message implements SWPlayer.Component { + private BukkitTask task; + + public Pos1Message(RegionSelector regionSelector, Player player, LocalSession session, BlockVector3 pos1) { + task = Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { + regionSelector.explainPrimarySelection(BukkitAdapter.adapt(player), session, pos1); + SWPlayer.of(player).removeComponent(Pos1Message.class); + }, 1); + } + + @Override + public void onUnmount(SWPlayer player) { + task.cancel(); + } + } + + private void selectPos1(RegionSelector regionSelector, Player player, LocalSession session, BlockVector3 pos1) { + if (!pos1.equals(regionSelector.getPrimaryPosition())) { + SWPlayer.of(player).setComponent(new Pos1Message(regionSelector, player, session, pos1)); + } + regionSelector.selectPrimary(pos1, PermissiveSelectorLimits.getInstance()); + WorldEditRenderer.renderPlayer(player); + } + + private static class Pos2Message implements SWPlayer.Component { + private BukkitTask task; + + public Pos2Message(RegionSelector regionSelector, Player player, LocalSession session, BlockVector3 pos2) { + task = Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { + regionSelector.explainSecondarySelection(BukkitAdapter.adapt(player), session, pos2); + SWPlayer.of(player).removeComponent(Pos1Message.class); + }, 1); + } + + @Override + public void onUnmount(SWPlayer player) { + task.cancel(); + } + } + + private void selectPos2(RegionSelector regionSelector, Player player, LocalSession session, BlockVector3 pos2) { + if (regionSelector.getVertices().size() == 2 && !pos2.equals(regionSelector.getVertices().get(1))) { + SWPlayer.of(player).setComponent(new Pos2Message(regionSelector, player, session, pos2)); + } + regionSelector.selectSecondary(pos2, PermissiveSelectorLimits.getInstance()); + WorldEditRenderer.renderPlayer(player); + } + + private ServerboundPlayerActionPacket swapHands(Player player, ServerboundPlayerActionPacket packet) { + if (noWand(player)) return packet; + if (packet.getAction() != ServerboundPlayerActionPacket.Action.SWAP_ITEM_WITH_OFFHAND) return packet; + Bukkit.getScheduler().runTask(Core.getInstance(), () -> { + WorldEditRendererCUIEditor.open(player); + }); + return null; + } + + public ServerboundMovePlayerPacket movePlayerPacket(Player player, ServerboundMovePlayerPacket packet) { + SWPlayer swPlayer = SWPlayer.of(player); + + if (noWand(player)) { + swPlayer.removeComponent(SWEditCursor.class); + return packet; + } + + double distance = WorldEditRendererCUIEditor.Type.CURSOR.getWidth(player).blocks; + RayTraceResult result = player.rayTraceBlocks(distance, FluidCollisionMode.NEVER); + Block block = result == null ? null : result.getHitBlock(); + if (result == null || block == null) { + swPlayer.removeComponent(SWEditCursor.class); + return packet; + } + + if (!swPlayer.hasComponent(SWEditCursor.class)) { + swPlayer.setComponent(new SWEditCursor()); + } + + swPlayer.getComponent(SWEditCursor.class).ifPresent(cursor -> { + cursor.setLocation(block.getLocation()); + }); + return packet; + } +} diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditRenderer.java similarity index 94% rename from SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java rename to SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditRenderer.java index 8805327b7..b66c67adc 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditRenderer.java @@ -1,7 +1,7 @@ /* * This file is a part of the SteamWar software. * - * Copyright (C) 2025 SteamWar.de-Serverteam + * Copyright (C) 2026 SteamWar.de-Serverteam * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package de.steamwar.core; +package de.steamwar.core.worldedit; import com.sk89q.worldedit.EmptyClipboardException; import com.sk89q.worldedit.IncompleteRegionException; @@ -28,6 +28,7 @@ import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.world.World; +import de.steamwar.core.Core; import de.steamwar.linkage.Linked; import de.steamwar.linkage.PluginCheck; import org.bukkit.Bukkit; @@ -39,13 +40,15 @@ import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.player.*; import org.bukkit.util.Vector; +import java.util.Set; + @Linked @PluginCheck("FastAsyncWorldEdit") public class WorldEditRenderer implements Listener { private static WorldEditRenderer INSTANCE; - private static final Material WAND = Material.WOODEN_AXE; + private static final Set WANDS = Set.of(Material.WOODEN_AXE, SteamEditWand.MATERIAL); private final WorldEditPlugin we; @@ -102,7 +105,7 @@ public class WorldEditRenderer implements Listener { private void drawCuboid(Vector min, Vector max, boolean scheduled, boolean clipboard, Player owner) { //noinspection deprecation - if (owner.getItemInHand().getType() != WAND) { + if (!WANDS.contains(owner.getItemInHand().getType())) { WorldEditRendererWrapper.impl.hide(owner, true, true); WorldEditRendererWrapper.impl.hide(owner, false, true); } else { @@ -114,7 +117,8 @@ public class WorldEditRenderer implements Listener { @EventHandler public void onPlayerMove(PlayerMoveEvent event) { - if (event.getPlayer().getItemInHand().getType() == WAND) { + //noinspection deprecation + if (WANDS.contains(event.getPlayer().getItemInHand().getType())) { WorldEditRendererWrapper.impl.tick(event.getPlayer()); } renderClipboard(event.getPlayer(), we.getSession(event.getPlayer()), false); diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererCUIEditor.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditRendererCUIEditor.java similarity index 61% rename from SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererCUIEditor.java rename to SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditRendererCUIEditor.java index 8f7d3e2bf..43f716fdd 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererCUIEditor.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditRendererCUIEditor.java @@ -1,7 +1,7 @@ /* * This file is a part of the SteamWar software. * - * Copyright (C) 2025 SteamWar.de-Serverteam + * Copyright (C) 2026 SteamWar.de-Serverteam * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -17,9 +17,11 @@ * along with this program. If not, see . */ -package de.steamwar.core; +package de.steamwar.core.worldedit; import de.steamwar.command.SWCommand; +import de.steamwar.core.CRIUSleepEvent; +import de.steamwar.core.Core; import de.steamwar.inventory.SWInventory; import de.steamwar.inventory.SWItem; import de.steamwar.sql.UserConfig; @@ -30,6 +32,7 @@ import org.bukkit.block.data.type.Light; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.inventory.ClickType; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.inventory.meta.BlockDataMeta; import org.bukkit.inventory.meta.ItemMeta; @@ -59,6 +62,7 @@ public class WorldEditRendererCUIEditor implements Listener { public enum Type { SELECTION("cui_selection_material", "cui_selection_width", Material.PURPLE_CONCRETE, Width.MEDIUM), CLIPBOARD("cui_clipboard_material", "cui_clipboard_width", Material.LIME_CONCRETE, Width.SLIM), + CURSOR("cui_cursor_material", "cui_cursor_range", Material.RED_CONCRETE, Width.SLIM), ; private final Map materialCache = new HashMap<>(); @@ -104,19 +108,27 @@ public class WorldEditRendererCUIEditor implements Listener { @AllArgsConstructor public enum Width { - HUGE(15, "WORLDEDIT_CUI_WIDTH_HUGE", 2 / 16f), - LARGE(8, "WORLDEDIT_CUI_WIDTH_LARGE", 1 / 16f), - MEDIUM(4, "WORLDEDIT_CUI_WIDTH_MEDIUM", 1 / 32f), - SLIM(0, "WORLDEDIT_CUI_WIDTH_SLIM", 1 / 64f); + HUGE(15, "WORLDEDIT_CUI_WIDTH_HUGE", 1 / 8f, 40), + LARGE(8, "WORLDEDIT_CUI_WIDTH_LARGE", 1 / 16f, 30), + MEDIUM(4, "WORLDEDIT_CUI_WIDTH_MEDIUM", 1 / 32f, 20), + SLIM(0, "WORLDEDIT_CUI_WIDTH_SLIM", 1 / 64f, 10); public final int lightLevel; public final String name; - public final float value; + public final float width; + public final int blocks; } + private static Command command = null; + public WorldEditRendererCUIEditor() { Bukkit.getPluginManager().registerEvents(this, Core.getInstance()); - new Command(); + command = new Command(); + } + + public static void open(Player player) { + if (command == null) return; + command.cuiEditor(player); } private static class Command extends SWCommand { @@ -128,8 +140,30 @@ public class WorldEditRendererCUIEditor implements Listener { @Register public void cuiEditor(Player player) { SWInventory inv = new SWInventory(player, 9 * 2, Core.MESSAGE.parse("WORLDEDIT_CUI_TITLE", player)); - setElement(inv, player, 3, "WORLDEDIT_CUI_SELECTION", Type.SELECTION); - setElement(inv, player, 5, "WORLDEDIT_CUI_CLIPBOARD", Type.CLIPBOARD); + if (SteamEdit.isInitialized()) { + setElement(inv, player, 1, "WORLDEDIT_CUI_SELECTION", Type.SELECTION); + setElement(inv, player, 2, "WORLDEDIT_CUI_CLIPBOARD", Type.CLIPBOARD); + setCursor(inv, player, 3, "WORLDEDIT_CUI_CURSOR"); + inv.setItem(5, new SWItem(Material.PAPER, "WORLDEDIT_CUI_TOOL_COPY").setLore("WORLDEDIT_CUI_TOOL_COPY_LORE").translate(player, Core.MESSAGE).getItemStack(), click -> { + player.performCommand("/copy"); + }); + inv.setItem(6, new SWItem(Material.STRUCTURE_VOID, "WORLDEDIT_CUI_TOOL_SOON").translate(player, Core.MESSAGE).getItemStack(), click -> {}); + inv.setItem(7, new SWItem(Material.GRASS_BLOCK, "WORLDEDIT_CUI_TOOL_PASTE").setLore("WORLDEDIT_CUI_TOOL_PASTE_LORE_1", "WORLDEDIT_CUI_TOOL_PASTE_LORE_2", "WORLDEDIT_CUI_TOOL_PASTE_LORE_3").translate(player, Core.MESSAGE).getItemStack(), click -> { + if (click == ClickType.DROP) { + player.performCommand("/paste -o"); + } else if (click == ClickType.SHIFT_LEFT || click == ClickType.SHIFT_RIGHT) { + player.performCommand("/paste -s"); + } else if (click == ClickType.LEFT || click == ClickType.RIGHT) { + player.performCommand("/paste"); + } + }); + inv.setItem(14, new SWItem(Material.STRUCTURE_VOID, "WORLDEDIT_CUI_TOOL_SOON").translate(player, Core.MESSAGE).getItemStack(), click -> {}); + inv.setItem(15, new SWItem(Material.STRUCTURE_VOID, "WORLDEDIT_CUI_TOOL_SOON").translate(player, Core.MESSAGE).getItemStack(), click -> {}); + inv.setItem(16, new SWItem(Material.STRUCTURE_VOID, "WORLDEDIT_CUI_TOOL_SOON").translate(player, Core.MESSAGE).getItemStack(), click -> {}); + } else { + setElement(inv, player, 3, "WORLDEDIT_CUI_SELECTION", Type.SELECTION); + setElement(inv, player, 5, "WORLDEDIT_CUI_CLIPBOARD", Type.CLIPBOARD); + } inv.open(); } @@ -163,6 +197,31 @@ public class WorldEditRendererCUIEditor implements Listener { inv.setItem(index + 9, lightItem); } + private void setCursor(SWInventory inv, Player player, int index, String uiName) { + Material material = Type.CURSOR.getMaterial(player); + Width width = Type.CURSOR.getWidth(player); + + inv.setItem(index, new SWItem(material, Core.MESSAGE.parse("WORLDEDIT_CUI_MATERIAL_NAME", player, Core.MESSAGE.parse(uiName, player)), Arrays.asList(Core.MESSAGE.parse("WORLDEDIT_CUI_MATERIAL_CLICK", player)), false, click -> { + cuiMaterial(player, uiName, Type.CURSOR, material); + })); + + List lore = new ArrayList<>(); + lore.add(Core.MESSAGE.parse("WORLDEDIT_CUI_WIDTH_CLICK", player)); + lore.add(""); + for (Width value : Width.values()) { + if (value == width) { + lore.add(Core.MESSAGE.parse("WORLDEDIT_CUI_WIDTH_LORE_SELECTED", player, Core.MESSAGE.parse(value.name + "_DIST", player))); + } else { + lore.add(Core.MESSAGE.parse("WORLDEDIT_CUI_WIDTH_LORE", player, Core.MESSAGE.parse(value.name + "_DIST", player))); + } + } + SWItem stickItem = new SWItem(Material.STICK, Core.MESSAGE.parse("WORLDEDIT_CUI_WIDTH_NAME_DIST", player, Core.MESSAGE.parse(uiName, player)), lore, false, click -> { + Type.CURSOR.setWidth(player, Width.values()[(width.ordinal() + 1) % Width.values().length]); + setCursor(inv, player, index, uiName); + }).setCustomModelData(1); + inv.setItem(index + 9, stickItem); + } + private final Material[] materials = {Material.WHITE_CONCRETE, Material.LIGHT_GRAY_CONCRETE, Material.GRAY_CONCRETE, Material.BLACK_CONCRETE, Material.BROWN_CONCRETE, Material.RED_CONCRETE, Material.ORANGE_CONCRETE, Material.YELLOW_CONCRETE, Material.LIME_CONCRETE, Material.GREEN_CONCRETE, Material.CYAN_CONCRETE, Material.LIGHT_BLUE_CONCRETE, Material.BLUE_CONCRETE, Material.PURPLE_CONCRETE, Material.MAGENTA_CONCRETE, Material.PINK_CONCRETE, null, Material.BARRIER}; private void cuiMaterial(Player player, String subMenu, Type type, Material currentSelection) { diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererFallback.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditRendererFallback.java similarity index 99% rename from SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererFallback.java rename to SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditRendererFallback.java index 736c2f8a6..99d738857 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererFallback.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditRendererFallback.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package de.steamwar.core; +package de.steamwar.core.worldedit; import org.bukkit.Location; import org.bukkit.Particle; diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererWrapper.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditRendererWrapper.java similarity index 96% rename from SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererWrapper.java rename to SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditRendererWrapper.java index 6d93d0b11..81ed2e2f1 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererWrapper.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditRendererWrapper.java @@ -1,7 +1,7 @@ /* * This file is a part of the SteamWar software. * - * Copyright (C) 2025 SteamWar.de-Serverteam + * Copyright (C) 2026 SteamWar.de-Serverteam * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -17,8 +17,9 @@ * along with this program. If not, see . */ -package de.steamwar.core; +package de.steamwar.core.worldedit; +import de.steamwar.core.PlayerVersion; import de.steamwar.entity.CWireframe; import de.steamwar.entity.REntityServer; import org.bukkit.Material; @@ -82,7 +83,7 @@ public class WorldEditRendererWrapper { }); WorldEditRendererCUIEditor.Type type = clipboard ? WorldEditRendererCUIEditor.Type.CLIPBOARD : WorldEditRendererCUIEditor.Type.SELECTION; - float width = type.getWidth(player).value; + float width = type.getWidth(player).width; Material material = type.getMaterial(player); if (material == Material.BARRIER) { hide(player, clipboard, true); diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditWrapper.java similarity index 98% rename from SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java rename to SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditWrapper.java index d333ff3ff..123870e40 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditWrapper.java @@ -1,7 +1,7 @@ /* * This file is a part of the SteamWar software. * - * Copyright (C) 2025 SteamWar.de-Serverteam + * Copyright (C) 2026 SteamWar.de-Serverteam * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package de.steamwar.core; +package de.steamwar.core.worldedit; import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV2; import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV3; @@ -34,6 +34,7 @@ import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.ClipboardHolder; +import de.steamwar.core.Core; import de.steamwar.sql.NoClipboardException; import de.steamwar.sql.NodeData; import org.bukkit.Bukkit; diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWItem.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWItem.java index 68ec243f2..0a0e0aa41 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWItem.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWItem.java @@ -22,10 +22,12 @@ package de.steamwar.inventory; import com.destroystokyo.paper.profile.PlayerProfile; import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import de.steamwar.message.Message; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.OfflinePlayer; import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -225,4 +227,14 @@ public class SWItem { itemStack.setAmount(count); return this; } + + public SWItem translate(Player player, Message message) { + setName(message.parse(itemMeta.getDisplayName(), player)); + if (itemMeta.hasLore()) { + setLore(itemMeta.getLore().stream() + .map(s -> message.parse(s, player)) + .toList()); + } + return this; + } } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java index 947d1adcc..a603ee792 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java @@ -20,7 +20,7 @@ package de.steamwar.sql; import com.sk89q.worldedit.extent.clipboard.Clipboard; -import de.steamwar.core.WorldEditWrapper; +import de.steamwar.core.worldedit.WorldEditWrapper; import org.bukkit.entity.Player; import java.io.ByteArrayInputStream; diff --git a/Teamserver/src/de/steamwar/teamserver/Builder.java b/Teamserver/src/de/steamwar/teamserver/Builder.java index 7a625bd52..136810ae7 100644 --- a/Teamserver/src/de/steamwar/teamserver/Builder.java +++ b/Teamserver/src/de/steamwar/teamserver/Builder.java @@ -19,7 +19,8 @@ package de.steamwar.teamserver; -import de.steamwar.core.WorldEditRendererCUIEditor; +import de.steamwar.core.worldedit.SteamEdit; +import de.steamwar.core.worldedit.WorldEditRendererCUIEditor; import de.steamwar.linkage.AbstractLinker; import de.steamwar.linkage.SpigotLinker; import de.steamwar.message.Message; @@ -51,7 +52,7 @@ public final class Builder extends JavaPlugin { } Bukkit.getWorlds().get(0).setGameRule(GameRule.REDUCED_DEBUG_INFO, false); - new WorldEditRendererCUIEditor(); + SteamEdit.init(); } @Override From 362468e756074f9f49f777e8d9afebeee285af46 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Tue, 1 Sep 2026 11:12:10 +0200 Subject: [PATCH 22/22] Fix SteamEditWand --- .../worldedit/SteamEditSelectAdjacent.java | 1 + .../core/worldedit/SteamEditWand.java | 4 +-- .../worldedit/WorldEditRendererCUIEditor.java | 30 +++++++++++-------- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEditSelectAdjacent.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEditSelectAdjacent.java index d30752aaf..fd6d07134 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEditSelectAdjacent.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEditSelectAdjacent.java @@ -48,6 +48,7 @@ public class SteamEditSelectAdjacent { private LinkedHashSet frontier = new LinkedHashSet<>(); public SteamEditSelectAdjacent(Location origin) { + // TODO: Fix the flood fill algorithm! min = origin.clone(); max = origin.clone(); frontier.add(origin); diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEditWand.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEditWand.java index 85b85d580..9d42538d8 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEditWand.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/SteamEditWand.java @@ -134,7 +134,7 @@ public class SteamEditWand implements Listener { private Packet leftClick(Player player, Packet packet) { if (noWand(player)) return packet; - if (player.getOpenInventory().getType() != InventoryType.CRAFTING) return packet; + if (player.getOpenInventory().getType() != InventoryType.CREATIVE) return packet; double distance = WorldEditRendererCUIEditor.Type.CURSOR.getWidth(player).blocks; RayTraceResult result = player.rayTraceBlocks(distance, FluidCollisionMode.NEVER); if (result == null) return packet; @@ -373,7 +373,7 @@ public class SteamEditWand implements Listener { if (noWand(player)) return packet; if (packet.getAction() != ServerboundPlayerActionPacket.Action.SWAP_ITEM_WITH_OFFHAND) return packet; Bukkit.getScheduler().runTask(Core.getInstance(), () -> { - WorldEditRendererCUIEditor.open(player); + WorldEditRendererCUIEditor.open(player, true); }); return null; } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditRendererCUIEditor.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditRendererCUIEditor.java index 43f716fdd..032d0fbed 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditRendererCUIEditor.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/worldedit/WorldEditRendererCUIEditor.java @@ -126,9 +126,9 @@ public class WorldEditRendererCUIEditor implements Listener { command = new Command(); } - public static void open(Player player) { + public static void open(Player player, boolean steamEditWand) { if (command == null) return; - command.cuiEditor(player); + command.cuiEditor(player, steamEditWand); } private static class Command extends SWCommand { @@ -139,10 +139,14 @@ public class WorldEditRendererCUIEditor implements Listener { @Register public void cuiEditor(Player player) { + cuiEditor(player, false); + } + + public void cuiEditor(Player player, boolean steamEditWand) { SWInventory inv = new SWInventory(player, 9 * 2, Core.MESSAGE.parse("WORLDEDIT_CUI_TITLE", player)); - if (SteamEdit.isInitialized()) { - setElement(inv, player, 1, "WORLDEDIT_CUI_SELECTION", Type.SELECTION); - setElement(inv, player, 2, "WORLDEDIT_CUI_CLIPBOARD", Type.CLIPBOARD); + if (SteamEdit.isInitialized() && steamEditWand) { + setElement(inv, player, true, 1, "WORLDEDIT_CUI_SELECTION", Type.SELECTION); + setElement(inv, player, true, 2, "WORLDEDIT_CUI_CLIPBOARD", Type.CLIPBOARD); setCursor(inv, player, 3, "WORLDEDIT_CUI_CURSOR"); inv.setItem(5, new SWItem(Material.PAPER, "WORLDEDIT_CUI_TOOL_COPY").setLore("WORLDEDIT_CUI_TOOL_COPY_LORE").translate(player, Core.MESSAGE).getItemStack(), click -> { player.performCommand("/copy"); @@ -161,18 +165,18 @@ public class WorldEditRendererCUIEditor implements Listener { inv.setItem(15, new SWItem(Material.STRUCTURE_VOID, "WORLDEDIT_CUI_TOOL_SOON").translate(player, Core.MESSAGE).getItemStack(), click -> {}); inv.setItem(16, new SWItem(Material.STRUCTURE_VOID, "WORLDEDIT_CUI_TOOL_SOON").translate(player, Core.MESSAGE).getItemStack(), click -> {}); } else { - setElement(inv, player, 3, "WORLDEDIT_CUI_SELECTION", Type.SELECTION); - setElement(inv, player, 5, "WORLDEDIT_CUI_CLIPBOARD", Type.CLIPBOARD); + setElement(inv, player, false, 3, "WORLDEDIT_CUI_SELECTION", Type.SELECTION); + setElement(inv, player, false, 5, "WORLDEDIT_CUI_CLIPBOARD", Type.CLIPBOARD); } inv.open(); } - private void setElement(SWInventory inv, Player player, int index, String uiName, Type type) { + private void setElement(SWInventory inv, Player player, boolean steamEditWand, int index, String uiName, Type type) { Material material = type.getMaterial(player); Width width = type.getWidth(player); inv.setItem(index, new SWItem(material, Core.MESSAGE.parse("WORLDEDIT_CUI_MATERIAL_NAME", player, Core.MESSAGE.parse(uiName, player)), Arrays.asList(Core.MESSAGE.parse("WORLDEDIT_CUI_MATERIAL_CLICK", player)), false, click -> { - cuiMaterial(player, uiName, type, material); + cuiMaterial(player, steamEditWand, uiName, type, material); })); List lore = new ArrayList<>(); @@ -187,7 +191,7 @@ public class WorldEditRendererCUIEditor implements Listener { } SWItem lightItem = new SWItem(Material.LIGHT, Core.MESSAGE.parse("WORLDEDIT_CUI_WIDTH_NAME", player, Core.MESSAGE.parse(uiName, player)), lore, false, click -> { type.setWidth(player, Width.values()[(width.ordinal() + 1) % Width.values().length]); - setElement(inv, player, index, uiName, type); + setElement(inv, player, steamEditWand, index, uiName, type); }); ItemMeta itemMeta = lightItem.getItemMeta(); Light light = (Light) Material.LIGHT.createBlockData(); @@ -202,7 +206,7 @@ public class WorldEditRendererCUIEditor implements Listener { Width width = Type.CURSOR.getWidth(player); inv.setItem(index, new SWItem(material, Core.MESSAGE.parse("WORLDEDIT_CUI_MATERIAL_NAME", player, Core.MESSAGE.parse(uiName, player)), Arrays.asList(Core.MESSAGE.parse("WORLDEDIT_CUI_MATERIAL_CLICK", player)), false, click -> { - cuiMaterial(player, uiName, Type.CURSOR, material); + cuiMaterial(player, true, uiName, Type.CURSOR, material); })); List lore = new ArrayList<>(); @@ -224,14 +228,14 @@ public class WorldEditRendererCUIEditor implements Listener { private final Material[] materials = {Material.WHITE_CONCRETE, Material.LIGHT_GRAY_CONCRETE, Material.GRAY_CONCRETE, Material.BLACK_CONCRETE, Material.BROWN_CONCRETE, Material.RED_CONCRETE, Material.ORANGE_CONCRETE, Material.YELLOW_CONCRETE, Material.LIME_CONCRETE, Material.GREEN_CONCRETE, Material.CYAN_CONCRETE, Material.LIGHT_BLUE_CONCRETE, Material.BLUE_CONCRETE, Material.PURPLE_CONCRETE, Material.MAGENTA_CONCRETE, Material.PINK_CONCRETE, null, Material.BARRIER}; - private void cuiMaterial(Player player, String subMenu, Type type, Material currentSelection) { + private void cuiMaterial(Player player, boolean steamEditWand, String subMenu, Type type, Material currentSelection) { SWInventory inv = new SWInventory(player, 9 * 2, Core.MESSAGE.parse("WORLDEDIT_CUI_TITLE_SUBMENU", player, Core.MESSAGE.parse(subMenu, player))); for (int i = 0; i < materials.length; i++) { Material material = materials[i]; if (material == null) continue; inv.setItem(i, new SWItem(material, "", Collections.emptyList(), material == currentSelection, click -> { type.setMaterial(player, material); - cuiEditor(player); + cuiEditor(player, steamEditWand); })); } inv.open();