From b10897c204c73663ec354615e48dd57b77ac2c07 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Tue, 15 Apr 2025 14:59:38 +0200 Subject: [PATCH] Update WorldEditRenderer --- .../de/steamwar/core/WorldEditRenderer20.java | 217 --------------- .../core/WorldEditRendererWrapper20.java | 145 +++++++++++ .../core/renderers/CuboidRegionRenderer.java | 159 ----------- .../core/WorldEditRendererWrapper8.java} | 29 +-- .../de/steamwar/core/WorldEditRenderer9.java | 125 --------- .../core/WorldEditRendererWrapper9.java | 80 ++++++ .../src/de/steamwar/core/Core.java | 50 +++- .../de/steamwar/core/VersionDependent.java | 10 +- .../de/steamwar/core/WorldEditRenderer.java | 169 ++++++++++-- .../core/WorldEditRendererWrapper.java | 47 ++++ .../src/de/steamwar/entity/CAABox.java | 103 ++++++++ .../src/de/steamwar/entity/CAALine.java | 246 ++++++++++++++++++ 12 files changed, 837 insertions(+), 543 deletions(-) delete mode 100644 SpigotCore/SpigotCore_20/src/de/steamwar/core/WorldEditRenderer20.java create mode 100644 SpigotCore/SpigotCore_20/src/de/steamwar/core/WorldEditRendererWrapper20.java delete mode 100644 SpigotCore/SpigotCore_20/src/de/steamwar/core/renderers/CuboidRegionRenderer.java rename SpigotCore/{SpigotCore_20/src/de/steamwar/core/renderers/RegionRenderer.java => SpigotCore_8/src/de/steamwar/core/WorldEditRendererWrapper8.java} (50%) delete mode 100644 SpigotCore/SpigotCore_9/src/de/steamwar/core/WorldEditRenderer9.java create mode 100644 SpigotCore/SpigotCore_9/src/de/steamwar/core/WorldEditRendererWrapper9.java create mode 100644 SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererWrapper.java create mode 100644 SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CAABox.java create mode 100644 SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CAALine.java diff --git a/SpigotCore/SpigotCore_20/src/de/steamwar/core/WorldEditRenderer20.java b/SpigotCore/SpigotCore_20/src/de/steamwar/core/WorldEditRenderer20.java deleted file mode 100644 index d84f4abb..00000000 --- a/SpigotCore/SpigotCore_20/src/de/steamwar/core/WorldEditRenderer20.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * 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.core; - -import com.sk89q.worldedit.EmptyClipboardException; -import com.sk89q.worldedit.IncompleteRegionException; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.regions.RegionSelector; -import com.sk89q.worldedit.world.World; -import de.steamwar.core.renderers.CuboidRegionRenderer; -import de.steamwar.core.renderers.RegionRenderer; -import de.steamwar.entity.REntityServer; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.player.*; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Supplier; - -public class WorldEditRenderer20 implements WorldEditRenderer, Listener { - - private static final Map servers = new HashMap<>(); - private static final Map clipboards = new HashMap<>(); - private static final Map regionSelections = new HashMap<>(); - - private static final Material WAND = FlatteningWrapper.impl.getMaterial("WOOD_AXE"); - - private final WorldEditPlugin we; - - private static final Map, Supplier>> rendererMap = new HashMap<>(); - - static { - rendererMap.put(CuboidRegion.class, CuboidRegionRenderer::new); - } - - public WorldEditRenderer20() { - we = WorldEditWrapper.getWorldEditPlugin(); - Bukkit.getPluginManager().registerEvents(this, Core.getInstance()); - Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> { - for (Player player : Bukkit.getOnlinePlayers()) { - render(player); - } - }, 10, 10); - } - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onPlayerJoin(PlayerJoinEvent event) { - Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { - render(event.getPlayer()); - }, 0); - } - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onPlayerSwapHandItems(PlayerSwapHandItemsEvent event) { - Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { - render(event.getPlayer()); - }, 0); - } - - @EventHandler - public void onPlayerDropItem(PlayerDropItemEvent event) { - Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { - render(event.getPlayer()); - }, 0); - } - - @EventHandler - public void onPlayerItemHeld(PlayerItemHeldEvent event) { - Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { - render(event.getPlayer()); - }, 0); - } - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onBlockBreak(BlockBreakEvent event) { - Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { - render(event.getPlayer()); - }, 0); - } - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onPlayerInteract(PlayerInteractEvent event) { - Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { - render(event.getPlayer()); - }, 0); - } - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onPlayerMove(PlayerMoveEvent event) { - Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { - render(event.getPlayer(), true, false); - }, 0); - } - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onPlayerQuit(PlayerQuitEvent event) { - REntityServer server = servers.remove(event.getPlayer()); - clipboards.remove(event.getPlayer()); - regionSelections.remove(event.getPlayer()); - if (server == null) return; - server.close(); - } - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { - String command = event.getMessage().split(" ")[0]; - command = command.replaceFirst("/", ""); - command = command.toLowerCase(); - if (WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getCommandManager().containsCommand(command)) { - Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { - render(event.getPlayer()); - }, 10); - } - } - - private void render(Player player) { - render(player, true, true); - } - - private void render(Player player, boolean renderClipboard, boolean renderRegionSelection) { - if (player.getInventory().getItemInMainHand().getType() != WAND) { - REntityServer entityServer = servers.remove(player); - clipboards.remove(player); - regionSelections.remove(player); - if (entityServer != null) entityServer.close(); - return; - } - - REntityServer server = servers.computeIfAbsent(player, __ -> { - REntityServer _server = new REntityServer(); - _server.addPlayer(player); - return _server; - }); - - LocalSession session = we.getSession(player); - if (renderClipboard) { - renderClipboard(server, session, player); - } - if (renderRegionSelection) { - renderSelection(server, session, player); - } - } - - @SuppressWarnings("unchecked") - private void renderClipboard(REntityServer server, LocalSession session, Player player) { - try { - Region region = session.getClipboard().getClipboard().getRegion(); - clipboards.compute(player, (__, regionRenderer) -> { - if (regionRenderer != null && !regionRenderer.canDisplay(region)) { - regionRenderer.clear(); - regionRenderer = null; - } - if (regionRenderer == null) { - return rendererMap.getOrDefault(region.getClass(), RegionRenderer.NOOPImpl::new).get(); - } else { - return regionRenderer; - } - }).update(server, region, session.getClipboard(), Material.LIME_CONCRETE.createBlockData()); - } catch (EmptyClipboardException e) { - RegionRenderer regionRenderer = clipboards.remove(player); - if (regionRenderer != null) regionRenderer.clear(); - } - } - - @SuppressWarnings("unchecked") - private void renderSelection(REntityServer server, LocalSession session, Player player) { - World world = session.getSelectionWorld(); - if (world == null) { - return; - } - RegionSelector regionSelector = session.getRegionSelector(world); - try { - Region region = regionSelector.getRegion(); - regionSelections.compute(player, (__, regionRenderer) -> { - if (regionRenderer != null && !regionRenderer.canDisplay(region)) { - regionRenderer.clear(); - regionRenderer = null; - } - if (regionRenderer == null) { - return rendererMap.getOrDefault(region.getClass(), RegionRenderer.NOOPImpl::new).get(); - } else { - return regionRenderer; - } - }).update(server, region, null, Material.PURPLE_CONCRETE.createBlockData()); - } catch (IncompleteRegionException e) { - RegionRenderer regionRenderer = regionSelections.remove(player); - if (regionRenderer != null) regionRenderer.clear(); - } - } -} diff --git a/SpigotCore/SpigotCore_20/src/de/steamwar/core/WorldEditRendererWrapper20.java b/SpigotCore/SpigotCore_20/src/de/steamwar/core/WorldEditRendererWrapper20.java new file mode 100644 index 00000000..5bffe84f --- /dev/null +++ b/SpigotCore/SpigotCore_20/src/de/steamwar/core/WorldEditRendererWrapper20.java @@ -0,0 +1,145 @@ +/* + * 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.core; + +import de.steamwar.entity.CAABox; +import de.steamwar.entity.CAALine; +import de.steamwar.entity.REntityServer; +import org.bukkit.Material; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class WorldEditRendererWrapper20 implements WorldEditRendererWrapper { + + private static final class BoxPair { + private CAABox regionBox; + private CAABox clipboardBox; + + public CAABox get(boolean clipboard) { + if (clipboard) { + return clipboardBox; + } else { + return regionBox; + } + } + + public void set(boolean clipboard, CAABox box) { + if (clipboard) { + this.clipboardBox = box; + } else { + this.regionBox = box; + } + } + + public void die() { + if (clipboardBox != null) { + clipboardBox.die(); + } + if (regionBox != null) { + regionBox.die(); + } + } + } + + private static final Map servers = new HashMap<>(); + private static final Map> boxes = new HashMap<>(); + + @Override + public void draw(Player player, Player owner, boolean clipboard, Vector pos1, Vector pos2) { + REntityServer server = servers.computeIfAbsent(player, __ -> { + REntityServer entityServer = new REntityServer(); + entityServer.addPlayer(player); + return entityServer; + }); + + float width = CAALine.DEFAULT_WIDTH; + if (player != owner) { + width = 1 / 64f; + } + + BlockData block; + if (player == owner) { + if (clipboard) { + block = Material.LIME_CONCRETE.createBlockData(); + } else { + block = Material.PURPLE_CONCRETE.createBlockData(); + } + } else { + block = Material.GRAY_CONCRETE.createBlockData(); + } + + BoxPair boxPair = boxes.computeIfAbsent(player, __ -> new HashMap<>()).computeIfAbsent(owner, __ -> new BoxPair()); + CAABox box = boxPair.get(clipboard); + if (box == null) { + box = new CAABox(server); + boxPair.set(clipboard, box); + } + box.setPos1(null).setPos2(null); + box.setPos1(pos1.toLocation(player.getWorld())); + box.setPos2(pos2.toLocation(player.getWorld())); + box.setWidth(width); + box.setBlock(block); + } + + @Override + public void tick(Player player) { + REntityServer server = servers.get(player); + if (server != null) server.tick(); + } + + @Override + public void hide(Player player, Player owner, boolean clipboard, boolean hide) { + Map pairs = boxes.getOrDefault(player, Collections.emptyMap()); + if (owner != null) { + BoxPair boxPair = pairs.get(owner); + if (boxPair == null) return; + CAABox box = boxPair.get(clipboard); + if (box != null) box.hide(hide); + } else { + pairs.values().forEach(boxPair -> { + CAABox box = boxPair.get(clipboard); + if (box != null) box.hide(hide); + }); + } + } + + @Override + public void remove(Player player) { + Map removed = boxes.remove(player); + if (removed != null) { + removed.values().forEach(boxPair -> { + boxPair.die(); + }); + } + boxes.values().forEach(map -> { + BoxPair boxPair = map.remove(player); + if (boxPair == null) return; + boxPair.die(); + }); + + REntityServer server = servers.remove(player); + if (server != null) server.close(); + } +} diff --git a/SpigotCore/SpigotCore_20/src/de/steamwar/core/renderers/CuboidRegionRenderer.java b/SpigotCore/SpigotCore_20/src/de/steamwar/core/renderers/CuboidRegionRenderer.java deleted file mode 100644 index 70391d3d..00000000 --- a/SpigotCore/SpigotCore_20/src/de/steamwar/core/renderers/CuboidRegionRenderer.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * 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.core.renderers; - -import com.sk89q.worldedit.math.transform.Transform; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.session.ClipboardHolder; -import de.steamwar.core.WorldEditWrapper; -import de.steamwar.entity.RBlockDisplay; -import de.steamwar.entity.REntityServer; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.data.BlockData; -import org.bukkit.entity.Display; -import org.bukkit.entity.Player; -import org.bukkit.util.Transformation; -import org.bukkit.util.Vector; -import org.joml.Quaternionf; -import org.joml.Vector3f; - -public class CuboidRegionRenderer implements RegionRenderer { - - private static final World WORLD = Bukkit.getWorlds().get(0); - private static final float offset = 1 / 1024f; - private static final float width = 1 / 16f; - - private Vector lastA = null; - private Vector lastB = null; - - private RBlockDisplay bd01; - private RBlockDisplay bd02; - private RBlockDisplay bd03; - private RBlockDisplay bd04; - private RBlockDisplay bd05; - private RBlockDisplay bd06; - private RBlockDisplay bd07; - private RBlockDisplay bd08; - private RBlockDisplay bd09; - private RBlockDisplay bd10; - private RBlockDisplay bd11; - private RBlockDisplay bd12; - - @Override - public boolean canDisplay(Region region) { - return region instanceof CuboidRegion; - } - - public void update(REntityServer server, CuboidRegion region, ClipboardHolder holder, BlockData block) { - Vector a; - Vector b; - if (holder != null) { - Player player = server.getPlayers().stream().findFirst().orElse(null); - if (player == null) return; - Vector pos = player.getLocation().toVector(); - Transform transform = holder.getTransform(); - a = WorldEditWrapper.impl.applyTransform(WorldEditWrapper.impl.getMinimum(region).subtract(WorldEditWrapper.impl.getOrigin(holder.getClipboard())), transform).add(pos); - b = WorldEditWrapper.impl.applyTransform(WorldEditWrapper.impl.getMaximum(region).subtract(WorldEditWrapper.impl.getOrigin(holder.getClipboard())), transform).add(pos); - } else { - a = WorldEditWrapper.impl.getMinimum(region); - b = WorldEditWrapper.impl.getMaximum(region); - } - - if (a.equals(lastA) && b.equals(lastB)) { - return; - } - - drawCuboid(server, toBlockVector(a), toBlockVector(b), block); - } - - @Override - public void clear() { - if (bd01 != null) bd01.die(); - if (bd02 != null) bd02.die(); - if (bd03 != null) bd03.die(); - if (bd04 != null) bd04.die(); - if (bd05 != null) bd05.die(); - if (bd06 != null) bd06.die(); - if (bd07 != null) bd07.die(); - if (bd08 != null) bd08.die(); - if (bd09 != null) bd09.die(); - if (bd10 != null) bd10.die(); - if (bd11 != null) bd11.die(); - if (bd12 != null) bd12.die(); - } - - private void drawCuboid(REntityServer server, Vector min, Vector max, BlockData block) { - max.add(new Vector(1 - width, 1 - width, 1 - width)); - - bd01 = drawLine(bd01, server, new Vector(min.getX() - offset, min.getY(), min.getZ()), new Vector(max.getX() + width, min.getY(), min.getZ()), block); - bd02 = drawLine(bd02, server, new Vector(min.getX() - offset, max.getY(), min.getZ()), new Vector(max.getX() + width, max.getY(), min.getZ()), block); - bd03 = drawLine(bd03, server, new Vector(min.getX() - offset, min.getY(), max.getZ()), new Vector(max.getX() + width, min.getY(), max.getZ()), block); - bd04 = drawLine(bd04, server, new Vector(min.getX() - offset, max.getY(), max.getZ()), new Vector(max.getX() + width, max.getY(), max.getZ()), block); - - bd05 = drawLine(bd05, server, new Vector(min.getX(), min.getY() - offset, min.getZ()), new Vector(min.getX(), max.getY() + width, min.getZ()), block); - bd06 = drawLine(bd06, server, new Vector(max.getX(), min.getY() - offset, min.getZ()), new Vector(max.getX(), max.getY() + width, min.getZ()), block); - bd07 = drawLine(bd07, server, new Vector(min.getX(), min.getY() - offset, max.getZ()), new Vector(min.getX(), max.getY() + width, max.getZ()), block); - bd08 = drawLine(bd08, server, new Vector(max.getX(), min.getY() - offset, max.getZ()), new Vector(max.getX(), max.getY() + width, max.getZ()), block); - - bd09 = drawLine(bd09, server, new Vector(min.getX(), min.getY(), min.getZ() - offset), new Vector(min.getX(), min.getY(), max.getZ() + width), block); - bd10 = drawLine(bd10, server, new Vector(max.getX(), min.getY(), min.getZ() - offset), new Vector(max.getX(), min.getY(), max.getZ() + width), block); - bd11 = drawLine(bd11, server, new Vector(min.getX(), max.getY(), min.getZ() - offset), new Vector(min.getX(), max.getY(), max.getZ() + width), block); - bd12 = drawLine(bd12, server, new Vector(max.getX(), max.getY(), min.getZ() - offset), new Vector(max.getX(), max.getY(), max.getZ() + width), block); - } - - private RBlockDisplay drawLine(RBlockDisplay display, REntityServer server, Vector from, Vector to, BlockData block) { - Location spawnLocation = from.clone().add(to).divide(new Vector(2, 2, 2)).toLocation(WORLD); - if (display == null) { - display = new RBlockDisplay(server, spawnLocation); - } - - Vector vector = to.clone().subtract(from); - if (vector.getX() == 0) { - vector.setX(vector.getX() + width + offset * 2); - } - if (vector.getY() == 0) { - vector.setY(vector.getY() + width + offset * 2); - } - if (vector.getZ() == 0) { - vector.setZ(vector.getZ() + width + offset * 2); - } - - Vector transformVec = from.subtract(spawnLocation.toVector()); - transformVec.subtract(new Vector(offset, offset, offset)); - - display.setTransform(new Transformation(toVec3f(transformVec), new Quaternionf(0, 0, 0, 1), toVec3f(vector), new Quaternionf(0, 0, 0, 1))); - display.setBrightness(new Display.Brightness(15, 15)); - display.setBlock(block); - display.move(spawnLocation); - - return display; - } - - private Vector toBlockVector(Vector vector) { - return new Vector(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ()); - } - - private Vector3f toVec3f(Vector vector) { - return new Vector3f((float) vector.getX(), (float) vector.getY(), (float) vector.getZ()); - } -} diff --git a/SpigotCore/SpigotCore_20/src/de/steamwar/core/renderers/RegionRenderer.java b/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditRendererWrapper8.java similarity index 50% rename from SpigotCore/SpigotCore_20/src/de/steamwar/core/renderers/RegionRenderer.java rename to SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditRendererWrapper8.java index 53121deb..1ca68b2d 100644 --- a/SpigotCore/SpigotCore_20/src/de/steamwar/core/renderers/RegionRenderer.java +++ b/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditRendererWrapper8.java @@ -17,31 +17,14 @@ * along with this program. If not, see . */ -package de.steamwar.core.renderers; +package de.steamwar.core; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.session.ClipboardHolder; -import de.steamwar.entity.REntityServer; -import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; -public interface RegionRenderer { +public class WorldEditRendererWrapper8 implements WorldEditRendererWrapper { - boolean canDisplay(Region region); - void update(REntityServer server, R region, ClipboardHolder holder, BlockData block); - void clear(); - - final class NOOPImpl implements RegionRenderer { - @Override - public boolean canDisplay(Region region) { - return false; - } - - @Override - public void update(REntityServer server, Region region, ClipboardHolder holder, BlockData block) { - } - - @Override - public void clear() { - } + @Override + public void draw(Player player, Player owner, boolean clipboard, Vector pos1, Vector pos2) { } } diff --git a/SpigotCore/SpigotCore_9/src/de/steamwar/core/WorldEditRenderer9.java b/SpigotCore/SpigotCore_9/src/de/steamwar/core/WorldEditRenderer9.java deleted file mode 100644 index 971a759c..00000000 --- a/SpigotCore/SpigotCore_9/src/de/steamwar/core/WorldEditRenderer9.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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.core; - -import com.sk89q.worldedit.EmptyClipboardException; -import com.sk89q.worldedit.IncompleteRegionException; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.extent.clipboard.Clipboard; -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 org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.Particle; -import org.bukkit.entity.Player; -import org.bukkit.util.Vector; - -public class WorldEditRenderer9 implements WorldEditRenderer { - - private static final int VIEW_DISTANCE = 64; - private static final int SQ_VIEW_DISTANCE = VIEW_DISTANCE * VIEW_DISTANCE; - - private static final double STEP_SIZE = 0.5; - - private static final Vector ONES = new Vector(1, 1, 1); - - private static final Material WAND = FlatteningWrapper.impl.getMaterial("WOOD_AXE"); - - private final WorldEditPlugin we; - - public WorldEditRenderer9() { - we = WorldEditWrapper.getWorldEditPlugin(); - - Bukkit.getScheduler().runTaskTimer(Core.getInstance(), this::render, 20, 20); - } - - private void render() { - for(Player player : Bukkit.getOnlinePlayers()) { - if(player.getInventory().getItemInMainHand().getType() != WAND) - continue; - - LocalSession session = we.getSession(player); - try { - Clipboard clipboard = session.getClipboard().getClipboard(); - Vector pos = player.getLocation().toVector(); - Region region = clipboard.getRegion(); - Transform transform = session.getClipboard().getTransform(); - Vector a = WorldEditWrapper.impl.applyTransform(WorldEditWrapper.impl.getMinimum(region).subtract(WorldEditWrapper.impl.getOrigin(clipboard)), transform).add(pos); - Vector b = WorldEditWrapper.impl.applyTransform(WorldEditWrapper.impl.getMaximum(region).subtract(WorldEditWrapper.impl.getOrigin(clipboard)), transform).add(pos); - drawCuboid(Vector.getMinimum(a, b), Vector.getMaximum(a, b), TrickyParticleWrapper.impl.getVillagerHappy(), player); - } catch (EmptyClipboardException e) { - //ignore - } - - World world = session.getSelectionWorld(); - if(world != null) { - RegionSelector regionSelector = session.getRegionSelector(world); - try { - Region region = regionSelector.getRegion(); - drawCuboid(WorldEditWrapper.impl.getMinimum(region), WorldEditWrapper.impl.getMaximum(region), Particle.DRAGON_BREATH, player); - } catch (IncompleteRegionException e) { - //ignore - } - } - } - } - - private void drawCuboid(Vector min, Vector max, Particle particle, Player owner) { - max.add(ONES); - - for(double x = min.getBlockX(); x <= max.getBlockX(); x += STEP_SIZE) { - draw(x, min.getBlockY(), min.getBlockZ(), particle, owner); - draw(x, min.getBlockY(), max.getBlockZ(), particle, owner); - draw(x, max.getBlockY(), min.getBlockZ(), particle, owner); - draw(x, max.getBlockY(), max.getBlockZ(), particle, owner); - } - - for(double y = min.getBlockY() + STEP_SIZE; y <= max.getBlockY() - STEP_SIZE; y += STEP_SIZE) { - draw(min.getBlockX(), y, min.getBlockZ(), particle, owner); - draw(min.getBlockX(), y, max.getBlockZ(), particle, owner); - draw(max.getBlockX(), y, min.getBlockZ(), particle, owner); - draw(max.getBlockX(), y, max.getBlockZ(), particle, owner); - } - - for(double z = min.getBlockZ() + STEP_SIZE; z <= max.getBlockZ() - STEP_SIZE; z += STEP_SIZE) { - draw(min.getBlockX(), min.getBlockY(), z, particle, owner); - draw(min.getBlockX(), max.getBlockY(), z, particle, owner); - draw(max.getBlockX(), min.getBlockY(), z, particle, owner); - draw(max.getBlockX(), max.getBlockY(), z, particle, owner); - } - } - - private void draw(double x, double y, double z, Particle particle, Player owner) { - for(Player player : Bukkit.getOnlinePlayers()) { - Location location = player.getLocation(); - double dx = x - location.getX(); - double dy = y - location.getY(); - double dz = z - location.getZ(); - if(dx*dx + dy*dy + dz*dz > SQ_VIEW_DISTANCE) - continue; - - player.spawnParticle(player == owner ? particle : org.bukkit.Particle.TOWN_AURA, x, y, z, 1, 0.0, 0.0, 0.0, 0.0); - } - } -} diff --git a/SpigotCore/SpigotCore_9/src/de/steamwar/core/WorldEditRendererWrapper9.java b/SpigotCore/SpigotCore_9/src/de/steamwar/core/WorldEditRendererWrapper9.java new file mode 100644 index 00000000..6a06be45 --- /dev/null +++ b/SpigotCore/SpigotCore_9/src/de/steamwar/core/WorldEditRendererWrapper9.java @@ -0,0 +1,80 @@ +/* + * 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.core; + +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +public class WorldEditRendererWrapper9 implements WorldEditRendererWrapper { + + private static final int VIEW_DISTANCE = 64; + private static final int SQ_VIEW_DISTANCE = VIEW_DISTANCE * VIEW_DISTANCE; + + private static final double STEP_SIZE = 0.5; + private static final Vector ONES = new Vector(1, 1, 1); + private static final Vector STEPS = new Vector(STEP_SIZE, STEP_SIZE, STEP_SIZE); + + @Override + public void draw(Player player, Player owner, boolean clipboard, Vector min, Vector max) { + max = max.clone().add(ONES); + drawLine(player, owner, clipboard, new Vector(min.getX(), min.getY(), min.getZ()), new Vector(max.getX(), min.getY(), min.getZ())); + drawLine(player, owner, clipboard, new Vector(min.getX(), max.getY(), min.getZ()), new Vector(max.getX(), max.getY(), min.getZ())); + drawLine(player, owner, clipboard, new Vector(min.getX(), min.getY(), max.getZ()), new Vector(max.getX(), min.getY(), max.getZ())); + drawLine(player, owner, clipboard, new Vector(min.getX(), max.getY(), max.getZ()), new Vector(max.getX(), max.getY(), max.getZ())); + + drawLine(player, owner, clipboard, new Vector(min.getX(), min.getY(), min.getZ()), new Vector(min.getX(), max.getY(), min.getZ())); + drawLine(player, owner, clipboard, new Vector(max.getX(), min.getY(), min.getZ()), new Vector(max.getX(), max.getY(), min.getZ())); + drawLine(player, owner, clipboard, new Vector(min.getX(), min.getY(), max.getZ()), new Vector(min.getX(), max.getY(), max.getZ())); + drawLine(player, owner, clipboard, new Vector(max.getX(), min.getY(), max.getZ()), new Vector(max.getX(), max.getY(), max.getZ())); + + drawLine(player, owner, clipboard, new Vector(min.getX(), min.getY(), min.getZ()), new Vector(min.getX(), min.getY(), max.getZ())); + drawLine(player, owner, clipboard, new Vector(max.getX(), min.getY(), min.getZ()), new Vector(max.getX(), min.getY(), max.getZ())); + drawLine(player, owner, clipboard, new Vector(min.getX(), max.getY(), min.getZ()), new Vector(min.getX(), max.getY(), max.getZ())); + drawLine(player, owner, clipboard, new Vector(max.getX(), max.getY(), min.getZ()), new Vector(max.getX(), max.getY(), max.getZ())); + } + + public void drawLine(Player player, Player owner, boolean clipboard, Vector min, Vector max) { + Particle particle; + if (player == owner) { + if (clipboard) { + particle = TrickyParticleWrapper.impl.getVillagerHappy(); + } else { + particle = Particle.DRAGON_BREATH; + } + } else { + particle = Particle.TOWN_AURA; + } + + Vector stepSize = max.clone().subtract(min).normalize().multiply(STEPS); + while (min.getX() <= max.getX() && min.getY() <= max.getY() && min.getZ() <= max.getZ()) { + Location location = player.getLocation(); + double dx = min.getX() - location.getX(); + double dy = min.getY() - location.getY(); + double dz = min.getZ() - location.getZ(); + if (dx * dx + dy * dy + dz * dz > SQ_VIEW_DISTANCE) + continue; + + player.spawnParticle(particle, min.getX(), min.getY(), min.getZ(), 1, 0.0, 0.0, 0.0, 0.0); + min.add(stepSize); + } + } +} diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/Core.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/Core.java index 24b207e8..ca2467b3 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/Core.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/Core.java @@ -20,10 +20,15 @@ package de.steamwar.core; import com.comphenix.tinyprotocol.TinyProtocol; +import com.google.gson.Gson; +import com.google.gson.JsonObject; import de.steamwar.Reflection; import de.steamwar.command.*; import de.steamwar.core.authlib.AuthlibInjector; -import de.steamwar.core.events.*; +import de.steamwar.core.events.AntiNocom; +import de.steamwar.core.events.ChattingEvent; +import de.steamwar.core.events.PlayerJoinedEvent; +import de.steamwar.core.events.WorldLoadEvent; import de.steamwar.message.Message; import de.steamwar.network.NetworkReceiver; import de.steamwar.network.handlers.ServerDataHandler; @@ -32,23 +37,42 @@ import de.steamwar.sql.SteamwarUser; import de.steamwar.sql.internal.Statement; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.plugin.messaging.PluginMessageListener; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.Collection; +import java.util.HashMap; +import java.util.Map; import java.util.logging.Level; -public class Core extends JavaPlugin{ +public class Core extends JavaPlugin implements PluginMessageListener, Listener { public static final Message MESSAGE = new Message("SpigotCore", Core.class.getClassLoader()); + private static final String CHANNEL = "vv:proxy_details"; + private static final Gson GSON = new Gson(); + private static final Map playerVersions = new HashMap<>(); + public static int getVersion(){ return Reflection.MAJOR_VERSION; } + public static int getPlayerVersion(Player player) { + return playerVersions.getOrDefault(player, -1); + } + + public static boolean isBedrockPlayer(Player player) { + return player.getName().startsWith("."); + } + private static JavaPlugin instance; public static JavaPlugin getInstance() { return instance; @@ -67,6 +91,9 @@ public class Core extends JavaPlugin{ @Override public void onEnable() { + this.getServer().getMessenger().registerIncomingPluginChannel(this, CHANNEL, this); + Bukkit.getPluginManager().registerEvents(this, this); + errorHandler = new ErrorHandler(); crashDetector = new CrashDetector(); @@ -103,7 +130,7 @@ public class Core extends JavaPlugin{ new ServerDataHandler(); if(Bukkit.getPluginManager().getPlugin("WorldEdit") != null) - WorldEditRenderer.impl.init(); + new WorldEditRenderer(); Bukkit.getScheduler().runTaskTimer(this, TabCompletionCache::invalidateOldEntries, 20, 20); Bukkit.getScheduler().runTaskTimer(Core.getInstance(), SteamwarUser::clear, 72000, 72000); @@ -122,5 +149,22 @@ public class Core extends JavaPlugin{ errorHandler.unregister(); if(crashDetector.onMainThread()) Statement.closeAll(); + this.getServer().getMessenger().unregisterIncomingPluginChannel(this); + } + + @Override + public void onPluginMessageReceived(String channel, Player player, byte[] bytes) { + if (!channel.equals(CHANNEL)) { + return; + } + + final JsonObject payload = GSON.fromJson(new String(bytes), JsonObject.class); + final String version = payload.get("versionName").getAsString(); + playerVersions.put(player, Integer.parseInt(version.split("-")[0].split("\\.")[1])); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerQuit(PlayerQuitEvent event) { + playerVersions.remove(event.getPlayer()); } } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/VersionDependent.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/VersionDependent.java index 5e8ec241..2fe94ce5 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/VersionDependent.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/VersionDependent.java @@ -31,8 +31,16 @@ public class VersionDependent { } public static T getVersionImpl(Plugin plugin, String className){ + return getVersionImpl(plugin, Core.getVersion(), className); + } + + public static T getVersionImpl(Plugin plugin, int fromVersion){ + return getVersionImpl(plugin, fromVersion, (new Exception()).getStackTrace()[1].getClassName()); + } + + public static T getVersionImpl(Plugin plugin, int fromVersion, String className){ ClassLoader loader = plugin.getClass().getClassLoader(); - for(int version = Core.getVersion(); version >= 8; version--) { + for(int version = fromVersion; version >= 8; version--) { try { return ((Class) Class.forName(className + version, true, loader)).getDeclaredConstructor().newInstance(); } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java index 6b90f1d2..7bf68c99 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java @@ -1,27 +1,166 @@ /* - * This file is a part of the SteamWar software. + * This file is a part of the SteamWar software. * - * Copyright (C) 2020 SteamWar.de-Serverteam + * Copyright (C) 2024 SteamWar.de-Serverteam * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is 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. + * 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 . + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ package de.steamwar.core; -public interface WorldEditRenderer { - WorldEditRenderer impl = VersionDependent.getVersionImpl(Core.getInstance()); +import com.sk89q.worldedit.EmptyClipboardException; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +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 org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.player.*; +import org.bukkit.util.Vector; - default void init() { +public class WorldEditRenderer implements Listener { + + private static final Material WAND = FlatteningWrapper.impl.getMaterial("WOOD_AXE"); + + private final WorldEditPlugin we; + + public WorldEditRenderer() { + we = WorldEditWrapper.getWorldEditPlugin(); + Bukkit.getPluginManager().registerEvents(this, Core.getInstance()); + + Bukkit.getScheduler().runTaskTimer(Core.getInstance(), this::render, 20, 20); + } + + private void render() { + for(Player player : Bukkit.getOnlinePlayers()) { + renderPlayer(player); + } + } + + private void renderPlayer(Player player) { + LocalSession session = we.getSession(player); + renderClipboard(player, session); + renderRegion(player, session); + } + + private void renderClipboard(Player player, LocalSession session) { + try { + Clipboard clipboard = session.getClipboard().getClipboard(); + Vector pos = player.getLocation().toVector(); + Region region = clipboard.getRegion(); + Transform transform = session.getClipboard().getTransform(); + Vector a = WorldEditWrapper.impl.applyTransform(WorldEditWrapper.impl.getMinimum(region).subtract(WorldEditWrapper.impl.getOrigin(clipboard)), transform).add(pos); + Vector b = WorldEditWrapper.impl.applyTransform(WorldEditWrapper.impl.getMaximum(region).subtract(WorldEditWrapper.impl.getOrigin(clipboard)), transform).add(pos); + a = new Vector(a.getBlockX(), a.getBlockY(), a.getBlockZ()); + b = new Vector(b.getBlockX(), b.getBlockY(), b.getBlockZ()); + WorldEditRendererWrapper.impl.hide(player, player, true, false); + drawCuboid(Vector.getMinimum(a, b), Vector.getMaximum(a, b), true, player); + } catch (EmptyClipboardException e) { + WorldEditRendererWrapper.impl.hide(player, player, true, true); + } + } + + private void renderRegion(Player player, LocalSession session) { + World world = session.getSelectionWorld(); + if(world != null) { + RegionSelector regionSelector = session.getRegionSelector(world); + try { + Region region = regionSelector.getRegion(); + WorldEditRendererWrapper.impl.hide(player, player, false, false); + drawCuboid(WorldEditWrapper.impl.getMinimum(region), WorldEditWrapper.impl.getMaximum(region), false, player); + } catch (IncompleteRegionException e) { + WorldEditRendererWrapper.impl.hide(player, player, false, true); + } + } + } + + private void drawCuboid(Vector min, Vector max, boolean clipboard, Player owner) { + for (Player player : Bukkit.getOnlinePlayers()) { + //noinspection deprecation + if(player.getItemInHand().getType() != WAND) { + WorldEditRendererWrapper.impl.hide(player, owner, true, true); + WorldEditRendererWrapper.impl.hide(player, owner, false, true); + } else { + WorldEditRendererWrapper.impl.hide(player, owner, true, false); + WorldEditRendererWrapper.impl.hide(player, owner, false, false); + WorldEditRendererWrapper.safeDraw(player, owner, clipboard, min, max); + } + } + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + renderPlayer(event.getPlayer()); + } + + @EventHandler + public void onPlayerMove(PlayerMoveEvent event) { + WorldEditRendererWrapper.impl.tick(event.getPlayer()); + + renderClipboard(event.getPlayer(), we.getSession(event.getPlayer())); + } + + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) { + renderRegion(event.getPlayer(), we.getSession(event.getPlayer())); + } + + @EventHandler + public void onBlockBreak(BlockBreakEvent event) { + renderRegion(event.getPlayer(), we.getSession(event.getPlayer())); + } + + @EventHandler + public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { + if (event.getMessage().startsWith("//")) { + Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { + LocalSession session = we.getSession(event.getPlayer()); + renderRegion(event.getPlayer(), session); + renderClipboard(event.getPlayer(), session); + }, 5); + } + } + + @EventHandler + public void onPlayerSwapHandItems(PlayerSwapHandItemsEvent event) { + Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { + renderPlayer(event.getPlayer()); + }, 1); + } + + @EventHandler + public void onPlayerDropItem(PlayerDropItemEvent event) { + renderPlayer(event.getPlayer()); + } + + @EventHandler + public void onPlayerItemHeld(PlayerItemHeldEvent event) { + Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { + renderPlayer(event.getPlayer()); + }, 1); + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + WorldEditRendererWrapper.impl.remove(event.getPlayer()); } } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererWrapper.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererWrapper.java new file mode 100644 index 00000000..63380fdc --- /dev/null +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererWrapper.java @@ -0,0 +1,47 @@ +/* + * 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.core; + +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +public interface WorldEditRendererWrapper { + WorldEditRendererWrapper fallback = VersionDependent.getVersionImpl(Core.getInstance(), 9); + WorldEditRendererWrapper impl = VersionDependent.getVersionImpl(Core.getInstance()); + + static void safeDraw(Player player, Player owner, boolean clipboard, Vector pos1, Vector pos2) { + if (Core.isBedrockPlayer(player) || Core.getPlayerVersion(player) < 20) { + fallback.draw(player, owner, clipboard, pos1, pos2); + } else { + impl.draw(player, owner, clipboard, pos1, pos2); + } + } + + void draw(Player player, Player owner, boolean clipboard, Vector pos1, Vector pos2); + + default void tick(Player player) { + } + + default void hide(Player player, Player owner, boolean clipboard, boolean hide) { + } + + default void remove(Player player) { + } +} diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CAABox.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CAABox.java new file mode 100644 index 00000000..80d94c88 --- /dev/null +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CAABox.java @@ -0,0 +1,103 @@ +/* + * 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.entity; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.data.BlockData; +import org.bukkit.util.Vector; + +import java.util.List; + +/** + * Compound Axis Aligned Box (12 CAALine) + */ +public class CAABox extends CEntity { + + public static final float DEFAULT_WIDTH = 1 / 16f; + private float width = DEFAULT_WIDTH; + + private Location pos1; + private Location pos2; + + public CAABox(REntityServer server) { + super(server); + } + + public CAABox setPos1(Location pos1) { + this.pos1 = pos1; + updateAndSpawnLines(); + return this; + } + + public CAABox setPos2(Location pos2) { + this.pos2 = pos2; + updateAndSpawnLines(); + return this; + } + + public CAABox setWidth(float width) { + this.width = width; + updateAndSpawnLines(); + getEntitiesByType(CAALine.class).forEach(haaLine -> { + haaLine.setWidth(width); + }); + return this; + } + + public CAABox setBlock(BlockData blockData) { + getEntitiesByType(CAALine.class).forEach(haaLine -> { + haaLine.setBlock(blockData); + }); + return this; + } + + private void updateAndSpawnLines() { + if (pos1 == null || pos2 == null) return; + if (entities.isEmpty()) { + for (int i = 0; i < 12; i++) { + entities.add(new CAALine(server)); + } + } + + World world = pos1.getWorld(); + Vector min = Vector.getMinimum(pos1.toVector(), pos2.toVector()); + Vector max = Vector.getMaximum(pos1.toVector(), pos2.toVector()) + .add(new Vector(1 - width, 1 - width, 1 - width)); + + List lines = getEntitiesByType(CAALine.class); + lines.forEach(line -> line.setFrom(null).setTo(null)); + + lines.get(0).setFrom(new Vector(min.getX(), min.getY(), min.getZ()).toLocation(world)).setTo(new Vector(max.getX() + width, min.getY(), min.getZ()).toLocation(world)); + lines.get(1).setFrom(new Vector(min.getX(), max.getY(), min.getZ()).toLocation(world)).setTo(new Vector(max.getX() + width, max.getY(), min.getZ()).toLocation(world)); + lines.get(2).setFrom(new Vector(min.getX(), min.getY(), max.getZ()).toLocation(world)).setTo(new Vector(max.getX() + width, min.getY(), max.getZ()).toLocation(world)); + lines.get(3).setFrom(new Vector(min.getX(), max.getY(), max.getZ()).toLocation(world)).setTo(new Vector(max.getX() + width, max.getY(), max.getZ()).toLocation(world)); + + lines.get(4).setFrom(new Vector(min.getX(), min.getY(), min.getZ()).toLocation(world)).setTo(new Vector(min.getX(), max.getY() + width, min.getZ()).toLocation(world)); + lines.get(5).setFrom(new Vector(max.getX(), min.getY(), min.getZ()).toLocation(world)).setTo(new Vector(max.getX(), max.getY() + width, min.getZ()).toLocation(world)); + lines.get(6).setFrom(new Vector(min.getX(), min.getY(), max.getZ()).toLocation(world)).setTo(new Vector(min.getX(), max.getY() + width, max.getZ()).toLocation(world)); + lines.get(7).setFrom(new Vector(max.getX(), min.getY(), max.getZ()).toLocation(world)).setTo(new Vector(max.getX(), max.getY() + width, max.getZ()).toLocation(world)); + + lines.get(8).setFrom(new Vector(min.getX(), min.getY(), min.getZ()).toLocation(world)).setTo(new Vector(min.getX(), min.getY(), max.getZ() + width).toLocation(world)); + lines.get(9).setFrom(new Vector(max.getX(), min.getY(), min.getZ()).toLocation(world)).setTo(new Vector(max.getX(), min.getY(), max.getZ() + width).toLocation(world)); + lines.get(10).setFrom(new Vector(min.getX(), max.getY(), min.getZ()).toLocation(world)).setTo(new Vector(min.getX(), max.getY(), max.getZ() + width).toLocation(world)); + lines.get(11).setFrom(new Vector(max.getX(), max.getY(), min.getZ()).toLocation(world)).setTo(new Vector(max.getX(), max.getY(), max.getZ() + width).toLocation(world)); + } +} diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CAALine.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CAALine.java new file mode 100644 index 00000000..19a6ef9f --- /dev/null +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CAALine.java @@ -0,0 +1,246 @@ +/* + * 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.entity; + +import org.bukkit.Location; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Display; +import org.bukkit.entity.Player; +import org.bukkit.util.Transformation; +import org.bukkit.util.Vector; +import org.joml.Quaternionf; +import org.joml.Vector3f; + +import java.util.Objects; + +public class CAALine extends CEntity { + + public static final float DEFAULT_WIDTH = 1 / 16f; + private static final float offset = 1 / 1024f; + private static final Vector offsetVec = new Vector(offset, offset, offset); + + private Location from; + private Location to; + private float width = DEFAULT_WIDTH; + private BlockData blockData = RBlockDisplay.DEFAULT_BLOCK; + + public CAALine(REntityServer server) { + super(server); + tick(); + } + + public CAALine setFrom(Location from) { + if (Objects.equals(from, this.from)) return this; + this.from = from; + tick(); + return this; + } + + public CAALine setTo(Location to) { + if (Objects.equals(to, this.to)) return this; + this.to = to; + tick(); + return this; + } + + public CAALine setWidth(float width) { + if (this.width == width) return this; + this.width = width; + tick(); + return this; + } + + public CAALine setBlock(BlockData blockData) { + if (this.blockData.equals(blockData)) return this; + if (blockData == null) { + this.blockData = RBlockDisplay.DEFAULT_BLOCK; + } else { + this.blockData = blockData; + } + getEntitiesByType(RBlockDisplay.class).forEach(display -> { + display.setBlock(blockData); + }); + return this; + } + + private boolean hide = false; + + @Override + public void hide(boolean hide) { + if (hide == this.hide) return; + this.hide = hide; + if (hide) { + if (startLine != null) startLine.hide(true); + if (middleLine != null) middleLine.hide(true); + if (endLine != null) endLine.hide(true); + } else { + tick(); + } + } + + @Override + void tick() { + if (from == null || to == null) return; + if (hide) return; + updateStart(); + updateMiddle(); + updateEnd(); + } + + private RBlockDisplay startLine; + private void updateStart() { + Vector vec = to.clone().subtract(from).toVector(); + if (vec.length() > 35) vec.normalize().multiply(35); + + if (startLine == null) { + startLine = new RBlockDisplay(server, new Location(null, 0, 0, 0)); + startLine.setBrightness(new Display.Brightness(15, 15)); + startLine.setViewRange(560); + startLine.setBlock(blockData); + entities.add(startLine); + } else { + startLine.hide(false); + } + + startLine.move(from.clone().subtract(offsetVec)); + startLine.setTransform(new Transformation(new Vector3f(0, 0, 0), new Quaternionf(0, 0, 0, 1), addWidth(vec).toVector3f(), new Quaternionf(0, 0, 0, 1))); + } + + private RBlockDisplay middleLine; + private void updateMiddle() { + Vector vec = to.clone().subtract(from).toVector(); + if (vec.length() <= 70) { + if (middleLine != null) middleLine.hide(true); + return; + } + if (vec.length() > 280) vec.normalize().multiply(280); + else vec = vec.clone().normalize().multiply(vec.length() - 60); + + if (middleLine == null) { + middleLine = new RBlockDisplay(server, new Location(null, 0, 0, 0)); + middleLine.setBrightness(new Display.Brightness(15, 15)); + middleLine.setViewRange(560); + middleLine.setBlock(blockData); + entities.add(middleLine); + } else { + middleLine.hide(false); + } + + Player player = server.getPlayers().stream().findFirst().orElse(null); + if (player == null) return; + + Vector tempVector = vec.clone().normalize().multiply(30); + Location from = this.from.clone().add(tempVector); + Location to = this.to.clone().subtract(tempVector); + + Vector lineVec = to.clone().subtract(from).toVector(); + Vector playerVec = player.getLocation().toVector().subtract(from.toVector()); + double lineVecDotItself = lineVec.dot(lineVec); + Vector projectionVec = lineVec.clone().multiply(lineVec.dot(playerVec)).divide(new Vector(lineVecDotItself, lineVecDotItself, lineVecDotItself)); + + Vector moveVec = from.toVector().add(projectionVec); + if (moveVec.getX() < from.getX()) { + moveVec.setX(from.getX()); + } + if (moveVec.getX() > to.getX()) { + moveVec.setX(to.getX()); + } + if (moveVec.getY() < from.getY()) { + moveVec.setY(from.getY()); + } + if (moveVec.getY() > to.getY()) { + moveVec.setY(to.getY()); + } + if (moveVec.getZ() < from.getZ()) { + moveVec.setZ(from.getZ()); + } + if (moveVec.getZ() > to.getZ()) { + moveVec.setZ(to.getZ()); + } + + Vector translation = vec.clone().divide(new Vector(2, 2, 2)); + translation.setX(-translation.getX()); + translation.setY(-translation.getY()); + translation.setZ(-translation.getZ()); + + Vector first = moveVec.clone().add(translation).subtract(from.toVector()); + if (first.getX() < 0) { + translation.setX(translation.getX() - first.getX()); + } + if (first.getY() < 0) { + translation.setY(translation.getY() - first.getY()); + } + if (first.getZ() < 0) { + translation.setZ(translation.getZ() - first.getZ()); + } + + Vector second = to.toVector().subtract(moveVec.clone().subtract(translation)); + if (second.getX() < 0) { + translation.setX(translation.getX() + second.getX()); + } + if (second.getY() < 0) { + translation.setY(translation.getY() + second.getY()); + } + if (second.getZ() < 0) { + translation.setZ(translation.getZ() + second.getZ()); + } + + middleLine.move(moveVec.toLocation(player.getWorld()).subtract(offsetVec)); + middleLine.setTransform(new Transformation(translation.toVector3f(), new Quaternionf(0, 0, 0, 1), addWidth(vec).toVector3f(), new Quaternionf(0, 0, 0, 1))); + } + + private RBlockDisplay endLine; + private void updateEnd() { + Vector vec = to.clone().subtract(from).toVector(); + if (vec.length() <= 35) { + if (endLine != null) endLine.hide(true); + return; + } + if (vec.length() > 35) vec.normalize().multiply(35); + + if (endLine == null) { + endLine = new RBlockDisplay(server, new Location(null, 0, 0, 0)); + endLine.setBrightness(new Display.Brightness(15, 15)); + endLine.setViewRange(560); + endLine.setBlock(blockData); + entities.add(endLine); + } else { + endLine.hide(false); + } + + endLine.move(to.clone().subtract(offsetVec)); + endLine.setTransform(new Transformation(vec.toVector3f().negate(), new Quaternionf(0, 0, 0, 1), addWidth(vec).toVector3f(), new Quaternionf(0, 0, 0, 1))); + } + + private Vector addWidth(Vector vector) { + vector = vector.clone(); + if (vector.getX() == 0) { + vector.setX(vector.getX() + width); + } + if (vector.getY() == 0) { + vector.setY(vector.getY() + width); + } + if (vector.getZ() == 0) { + vector.setZ(vector.getZ() + width); + } + vector.add(offsetVec).add(offsetVec); + return vector; + } +}