diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/PistonCalculator.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/PistonCalculator.java index ddc98cd5..5cc4b744 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/PistonCalculator.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/PistonCalculator.java @@ -55,7 +55,13 @@ public class PistonCalculator implements Listener { public void onPlayerInteract(PlayerInteractEvent event) { if (!Permission.BUILD.hasPermission(event.getPlayer())) return; if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; - if (event.hasItem() && event.getItem().getType() != Material.SLIME_BALL) return; + if (event.getItem() == null) {} + else if (event.getItem() != null && event.getItem().getType() == Material.SLIME_BALL) {} + else if (!event.getItem().getType().isBlock()) { + DEBOUNCE.put(event.getPlayer(), System.currentTimeMillis()); + return; + } + else return; if (event.getClickedBlock() == null) return; Block clickedBlock = event.getClickedBlock(); Material blockType = clickedBlock.getType(); diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/worldedit/SelectAdjacent.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/worldedit/SelectAdjacent.java new file mode 100644 index 00000000..7e3ade3c --- /dev/null +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/worldedit/SelectAdjacent.java @@ -0,0 +1,180 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bausystem.features.worldedit; + +import de.steamwar.bausystem.BauSystem; +import de.steamwar.bausystem.region.Point; +import de.steamwar.bausystem.utils.FlatteningWrapper; +import de.steamwar.core.WorldEditRenderer; +import de.steamwar.linkage.Linked; +import de.steamwar.linkage.MinVersion; +import org.bukkit.Bukkit; +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.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.scheduler.BukkitTask; +import org.bukkit.util.Vector; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; + +@Linked +@MinVersion(20) +public class SelectAdjacent implements Listener { + + private Vector[] FACES = { + new Vector(1, 0, 0), + new Vector(-1, 0, 0), + new Vector(0, 1, 0), + new Vector(0, -1, 0), + new Vector(0, 0, 1), + new Vector(0, 0, -1), + + new Vector(1, 1, 0), + new Vector(1, -1, 0), + new Vector(1, 0, 1), + new Vector(1, 0, -1), + new Vector(-1, 1, 0), + new Vector(-1, -1, 0), + new Vector(-1, 0, 1), + new Vector(-1, 0, -1), + new Vector(0, 1, 1), + new Vector(0, 1, -1), + new Vector(0, -1, 1), + new Vector(0, -1, -1), + }; + + private Map selectors = new HashMap<>(); + + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) { + if (!event.hasItem()) return; + if (event.getItem().getType() != Material.WOODEN_AXE) return; + if (!event.getPlayer().isSneaking()) return; + if (event.getAction() != Action.LEFT_CLICK_BLOCK) return; + Selector selector = selectors.get(event.getPlayer()); + if (selector != null) selector.cancel(); + Material material = event.getPlayer().getInventory().getItemInOffHand().getType(); + if (material.isAir()) { + selector = new Selector(event.getClickedBlock(), event.getPlayer(), __ -> true); + } else { + selector = new Selector(event.getClickedBlock(), event.getPlayer(), type -> type == material); + } + selectors.put(event.getPlayer(), selector); + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + Selector selector = selectors.remove(event.getPlayer()); + if (selector != null) selector.cancel(); + } + + private class Selector { + + private static final int MAX_BLOCKS = 500_000; + + private int minX; + private int minY; + private int minZ; + private int maxX; + private int maxY; + private int maxZ; + + private BukkitTask bukkitTask; + private Predicate predicate; + private Set seen = new HashSet<>(); + private Set toCalc = new HashSet<>(); + + public Selector(Block block, Player player, Predicate predicate) { + this.predicate = predicate; + toCalc.add(block.getLocation()); + minX = block.getX(); + minY = block.getY(); + minZ = block.getZ(); + maxX = block.getX(); + maxY = block.getY(); + maxZ = block.getZ(); + + bukkitTask = Bukkit.getScheduler().runTaskTimer(BauSystem.getInstance(), () -> { + run(); + + long volume = (long)(maxX - minX + 1) * (long)(maxY - minY + 1) * (long)(maxZ - minZ + 1); + player.sendTitle("", "§e" + volume + " §7Blocks", 0, 5, 0); + + Point minPoint = new Point(minX, minY, minZ); + Point maxPoint = new Point(maxX, maxY, maxZ); + + FlatteningWrapper.impl.setSelection(player, minPoint, maxPoint); + WorldEditRenderer.renderPlayer(player); + + // boolean finished = toCalc.stream().allMatch(location -> { + // return location.getBlockX() >= minX && location.getBlockY() >= minY && location.getBlockZ() >= minZ && + // location.getBlockX() <= maxX && location.getBlockY() <= maxY && location.getBlockZ() <= maxZ; + // }); + + if (toCalc.isEmpty() || seen.size() > MAX_BLOCKS) { + bukkitTask.cancel(); + player.sendTitle("§aDone", "§e" + volume + " §7Blocks", 0, 20, 5); + } + }, 1, 1); + } + + private void cancel() { + bukkitTask.cancel(); + } + + private void run() { + Set current = toCalc; + toCalc = new HashSet<>(); + + for (Location location : current) { + Block block = location.getBlock(); + if (block.isEmpty() || block.isLiquid()) continue; + if (!predicate.test(block.getType())) continue; + seen.add(location); + + minX = Math.min(minX, location.getBlockX()); + maxX = Math.max(maxX, location.getBlockX()); + minY = Math.min(minY, location.getBlockY()); + maxY = Math.max(maxY, location.getBlockY()); + minZ = Math.min(minZ, location.getBlockZ()); + maxZ = Math.max(maxZ, location.getBlockZ()); + + for (Vector face : FACES) { + Block next = block.getRelative(face.getBlockX(), face.getBlockY(), face.getBlockZ()); + if (next.isEmpty() || next.isLiquid()) continue; + if (!predicate.test(next.getType())) continue; + Location loc = next.getLocation(); + if (seen.contains(loc)) continue; + toCalc.add(loc); + } + } + } + } +} diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java index 225053a2..79c54986 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java @@ -39,11 +39,14 @@ import org.bukkit.util.Vector; public class WorldEditRenderer implements Listener { + private static WorldEditRenderer INSTANCE; + private static final Material WAND = FlatteningWrapper.impl.getMaterial("WOOD_AXE"); private final WorldEditPlugin we; public WorldEditRenderer() { + INSTANCE = this; we = WorldEditWrapper.getWorldEditPlugin(); Bukkit.getPluginManager().registerEvents(this, Core.getInstance()); @@ -54,6 +57,10 @@ public class WorldEditRenderer implements Listener { }, 20, 20); } + public static void renderPlayer(Player player) { + WorldEditRenderer.INSTANCE.renderPlayer(player, false); + } + private void renderPlayer(Player player, boolean scheduled) { LocalSession session = we.getSession(player); renderClipboard(player, session, scheduled); diff --git a/Teamserver/src/de/steamwar/teamserver/Builder.java b/Teamserver/src/de/steamwar/teamserver/Builder.java index 55aeed2d..94dadf8a 100644 --- a/Teamserver/src/de/steamwar/teamserver/Builder.java +++ b/Teamserver/src/de/steamwar/teamserver/Builder.java @@ -19,12 +19,14 @@ package de.steamwar.teamserver; +import de.steamwar.core.Core; import de.steamwar.core.WorldEditRendererCUIEditor; import de.steamwar.message.Message; import de.steamwar.teamserver.command.*; import de.steamwar.teamserver.listener.AxiomHandshakeListener; import de.steamwar.teamserver.listener.FreezeListener; import de.steamwar.teamserver.listener.PlayerChange; +import de.steamwar.teamserver.listener.SelectAdjacent; import org.bukkit.Bukkit; import org.bukkit.GameRule; import org.bukkit.plugin.java.JavaPlugin; @@ -60,6 +62,10 @@ public final class Builder extends JavaPlugin { Bukkit.getWorlds().get(0).setGameRule(GameRule.REDUCED_DEBUG_INFO, false); new WorldEditRendererCUIEditor(); + + if (Core.getVersion() >= 20) { + Bukkit.getPluginManager().registerEvents(new SelectAdjacent(), this); + } } @Override diff --git a/Teamserver/src/de/steamwar/teamserver/listener/SelectAdjacent.java b/Teamserver/src/de/steamwar/teamserver/listener/SelectAdjacent.java new file mode 100644 index 00000000..2fbebbf3 --- /dev/null +++ b/Teamserver/src/de/steamwar/teamserver/listener/SelectAdjacent.java @@ -0,0 +1,177 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.teamserver.listener; + +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; +import com.sk89q.worldedit.world.World; +import de.steamwar.core.WorldEditRenderer; +import de.steamwar.teamserver.Builder; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.scheduler.BukkitTask; +import org.bukkit.util.Vector; + +import java.util.*; +import java.util.function.Predicate; + +public class SelectAdjacent implements Listener { + + private Vector[] FACES = { + new Vector(1, 0, 0), + new Vector(-1, 0, 0), + new Vector(0, 1, 0), + new Vector(0, -1, 0), + new Vector(0, 0, 1), + new Vector(0, 0, -1), + + new Vector(1, 1, 0), + new Vector(1, -1, 0), + new Vector(1, 0, 1), + new Vector(1, 0, -1), + new Vector(-1, 1, 0), + new Vector(-1, -1, 0), + new Vector(-1, 0, 1), + new Vector(-1, 0, -1), + new Vector(0, 1, 1), + new Vector(0, 1, -1), + new Vector(0, -1, 1), + new Vector(0, -1, -1), + }; + + private Map selectors = new HashMap<>(); + + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) { + if (!event.hasItem()) return; + if (event.getItem().getType() != Material.WOODEN_AXE) return; + if (!event.getPlayer().isSneaking()) return; + if (event.getAction() != Action.LEFT_CLICK_BLOCK) return; + Selector selector = selectors.get(event.getPlayer()); + if (selector != null) selector.cancel(); + Material material = event.getPlayer().getInventory().getItemInOffHand().getType(); + if (material.isAir()) { + selector = new Selector(event.getClickedBlock(), event.getPlayer(), __ -> true); + } else { + selector = new Selector(event.getClickedBlock(), event.getPlayer(), type -> type == material); + } + selectors.put(event.getPlayer(), selector); + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + Selector selector = selectors.remove(event.getPlayer()); + if (selector != null) selector.cancel(); + } + + private static final WorldEditPlugin WORLDEDIT_PLUGIN = Objects.requireNonNull((WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit")); + private static final World BUKKITWORLD = new BukkitWorld(Bukkit.getWorlds().get(0)); + + private class Selector { + + private static final int MAX_BLOCKS = 1_000_000; + + private int minX; + private int minY; + private int minZ; + private int maxX; + private int maxY; + private int maxZ; + + private BukkitTask bukkitTask; + private Predicate predicate; + private Set seen = new HashSet<>(); + private Set toCalc = new HashSet<>(); + + public Selector(Block block, Player player, Predicate predicate) { + this.predicate = predicate; + toCalc.add(block.getLocation()); + minX = block.getX(); + minY = block.getY(); + minZ = block.getZ(); + maxX = block.getX(); + maxY = block.getY(); + maxZ = block.getZ(); + + bukkitTask = Bukkit.getScheduler().runTaskTimer(Builder.getInstance(), () -> { + run(); + + long volume = (long)(maxX - minX + 1) * (long)(maxY - minY + 1) * (long)(maxZ - minZ + 1); + player.sendTitle("", "§e" + volume + " §7Blocks", 0, 5, 0); + + WORLDEDIT_PLUGIN.getSession(player).setRegionSelector(BUKKITWORLD, new CuboidRegionSelector(BUKKITWORLD, BlockVector3.at(minX, minY, minZ), BlockVector3.at(maxX, maxY, maxZ))); + WorldEditRenderer.renderPlayer(player); + + // boolean finished = toCalc.stream().allMatch(location -> { + // return location.getBlockX() >= minX && location.getBlockY() >= minY && location.getBlockZ() >= minZ && + // location.getBlockX() <= maxX && location.getBlockY() <= maxY && location.getBlockZ() <= maxZ; + // }); + + if (toCalc.isEmpty() || seen.size() > MAX_BLOCKS) { + bukkitTask.cancel(); + player.sendTitle("§aDone", "§e" + volume + " §7Blocks", 0, 20, 5); + } + }, 1, 1); + } + + private void cancel() { + bukkitTask.cancel(); + } + + private void run() { + Set current = toCalc; + toCalc = new HashSet<>(); + + for (Location location : current) { + Block block = location.getBlock(); + if (block.isEmpty() || block.isLiquid()) continue; + if (!predicate.test(block.getType())) continue; + seen.add(location); + + minX = Math.min(minX, location.getBlockX()); + maxX = Math.max(maxX, location.getBlockX()); + minY = Math.min(minY, location.getBlockY()); + maxY = Math.max(maxY, location.getBlockY()); + minZ = Math.min(minZ, location.getBlockZ()); + maxZ = Math.max(maxZ, location.getBlockZ()); + + for (Vector face : FACES) { + Block next = block.getRelative(face.getBlockX(), face.getBlockY(), face.getBlockZ()); + if (next.isEmpty() || next.isLiquid()) continue; + if (!predicate.test(next.getType())) continue; + Location loc = next.getLocation(); + if (seen.contains(loc)) continue; + toCalc.add(loc); + } + } + } + } +} diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/DiscordBot.java b/VelocityCore/src/de/steamwar/velocitycore/discord/DiscordBot.java index 28cd0c22..ae9decbd 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/discord/DiscordBot.java +++ b/VelocityCore/src/de/steamwar/velocitycore/discord/DiscordBot.java @@ -41,7 +41,6 @@ import net.dv8tion.jda.api.entities.Role; import net.dv8tion.jda.api.entities.emoji.Emoji; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.exceptions.ErrorResponseException; -import net.dv8tion.jda.api.interactions.commands.Command; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.Commands; @@ -49,13 +48,14 @@ import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.components.ActionRow; import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.requests.GatewayIntent; -import net.dv8tion.jda.api.requests.restaction.CommandListUpdateAction; import net.dv8tion.jda.api.utils.MemberCachePolicy; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; import java.awt.*; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; -import java.util.*; +import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; @@ -67,9 +67,10 @@ public class DiscordBot { @Getter private static final Map commands = new HashMap<>(); + private final OptionData commandArgument = new OptionData(OptionType.STRING, ARGUMENT_NAME, "Command arguments", false); public static void withBot(Consumer consumer) { - if(instance != null) + if (instance != null) consumer.accept(instance); } @@ -130,6 +131,7 @@ public class DiscordBot { reply.system("DC_ROLE_ADDED", role.getAsMention()); } })); + new StaticMessageChannel(config.channel("rules"), () -> new MessageCreateBuilder() .setEmbeds(new EmbedBuilder() .setDescription(String.join("\n", config.getRules())) @@ -141,9 +143,10 @@ public class DiscordBot { ActionRow.of(Button.link("https://steamwar.de", "Website"), Button.link("https://steamwar.de/youtube", "YouTube")), ActionRow.of(Button.primary("auth", Emoji.fromUnicode("U+2705")).withLabel("Minecraft verknüpfen")) ), event -> { - if(event.getComponentId().equals("auth")) + if (event.getComponentId().equals("auth")) event.reply("Gebe innerhalb der nächsten 10 Minuten ``/verify " + AuthManager.createDiscordAuthToken(event.getUser()) + "`` auf dem Minecraft Server ein").setEphemeral(true).queue(); }); + List actionRows = new ArrayList<>(); List