diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java index 185293a2..04d11616 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java @@ -19,7 +19,6 @@ package de.steamwar.bausystem.features.simulator; -import com.comphenix.tinyprotocol.TinyProtocol; import de.steamwar.bausystem.BauSystem; import de.steamwar.bausystem.Permission; import de.steamwar.bausystem.SWUtils; @@ -38,63 +37,52 @@ import de.steamwar.bausystem.features.simulator.gui.SimulatorGui; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui; import de.steamwar.bausystem.utils.BauMemberUpdateEvent; import de.steamwar.bausystem.utils.ItemUtils; -import de.steamwar.cursor.RayTraceUtils; +import de.steamwar.core.SWPlayer; +import de.steamwar.cursor.Cursor; import de.steamwar.entity.REntity; import de.steamwar.entity.REntityServer; -import de.steamwar.entity.RFallingBlockEntity; import de.steamwar.inventory.SWAnvilInv; import de.steamwar.linkage.Linked; import lombok.AllArgsConstructor; import lombok.Getter; -import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.BlockFace; 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.Action; -import org.bukkit.event.player.*; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerItemHeldEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerToggleSneakEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; -import java.util.*; -import java.util.function.BiFunction; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; @Linked public class SimulatorCursor implements Listener { - private static final World WORLD = Bukkit.getWorlds().get(0); - - private static Map cursorType = Collections.synchronizedMap(new HashMap<>()); - private static Map cursors = Collections.synchronizedMap(new HashMap<>()); - private static final Set calculating = new HashSet<>(); + private static final Map cursorType = Collections.synchronizedMap(new HashMap<>()); + private static final Map emptyTargetServers = Collections.synchronizedMap(new HashMap<>()); public static boolean isSimulatorItem(ItemStack itemStack) { return ItemUtils.isItem(itemStack, "simulator"); } - public SimulatorCursor() { - BiFunction function = (player, object) -> { - calcCursor(player); - return object; - }; - TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.Pos.class, function); - TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.Rot.class, function); - TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.PosRot.class, function); - } - @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { if (!Permission.BUILD.hasPermission(event.getPlayer())) return; - Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> { - calcCursor(event.getPlayer()); - }, 0); + Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> calcCursor(event.getPlayer()), 0); } @EventHandler @@ -106,9 +94,7 @@ public class SimulatorCursor implements Listener { @EventHandler public void onPlayerItemHeld(PlayerItemHeldEvent event) { if (!Permission.BUILD.hasPermission(event.getPlayer())) return; - Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> { - calcCursor(event.getPlayer()); - }, 1); + Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> calcCursor(event.getPlayer()), 1); } @EventHandler @@ -119,10 +105,7 @@ public class SimulatorCursor implements Listener { @EventHandler public void onPlayerQuit(PlayerQuitEvent event) { cursorType.remove(event.getPlayer()); - cursors.remove(event.getPlayer()); - synchronized (calculating) { - calculating.remove(event.getPlayer()); - } + removeCursor(event.getPlayer()); } private static final Map LAST_SNEAKS = new HashMap<>(); @@ -164,17 +147,10 @@ public class SimulatorCursor implements Listener { } public static void calcCursor(Player player) { - synchronized (calculating) { - if (calculating.contains(player)) return; - calculating.add(player); - } if (!Permission.BUILD.hasPermission(player) || (!isSimulatorItem(player.getInventory().getItemInMainHand()) && !isSimulatorItem(player.getInventory().getItemInOffHand()))) { if (removeCursor(player) || SimulatorWatcher.show(null, player)) { SWUtils.sendToActionbar(player, ""); } - synchronized (calculating) { - calculating.remove(player); - } return; } @@ -183,203 +159,93 @@ public class SimulatorCursor implements Listener { removeCursor(player); SimulatorWatcher.show(null, player); SWUtils.sendToActionbar(player, "§cGenerating Stab"); - synchronized (calculating) { - calculating.remove(player); - } return; } SimulatorWatcher.show(simulator, player); - List entities = SimulatorWatcher.getEntitiesOfSimulator(simulator); - RayTraceUtils.RRayTraceResult rayTraceResult = RayTraceUtils.traceREntity(player, player.getLocation(), entities); - if (rayTraceResult == null) { - removeCursor(player); - if (simulator == null) { - SWUtils.sendToActionbar(player, "§eSelect Simulator"); - } else { - SWUtils.sendToActionbar(player, "§eOpen Simulator"); - } - synchronized (calculating) { - calculating.remove(player); - } - return; - } - - showCursor(player, rayTraceResult, simulator != null); - synchronized (calculating) { - calculating.remove(player); + REntityServer targetServer = simulator == null ? emptyTargetServers.computeIfAbsent(player, __ -> new REntityServer()) : SimulatorWatcher.getEntityServerOfSimulator(simulator); + CursorType type = cursorType.getOrDefault(player, CursorType.TNT); + SWPlayer swPlayer = SWPlayer.of(player); + Optional currentCursor = swPlayer.getComponent(Cursor.class); + Cursor cursor; + if (currentCursor.isEmpty() || currentCursor.get().getTargetServer() != targetServer) { + swPlayer.removeComponent(Cursor.class); + cursor = new Cursor( + targetServer, + player, + Material.GLASS, + type.material, + type.cursorModes, + (location, hitEntity, action) -> handlePlayerClick(player, location, hitEntity, action), + (location, hitEntity) -> sendCursorActionbar(player, SimulatorStorage.getSimulator(player), location != null, hitEntity.isPresent()) + ); + } else { + cursor = currentCursor.get(); + cursor.setCursorMaterial(type.material); + cursor.setAllowedCursorModes(type.cursorModes); } + cursor.renderDeduplicated(); } private static synchronized boolean removeCursor(Player player) { - REntityServer entityServer = cursors.get(player); - boolean hadCursor = entityServer != null && !entityServer.getEntities().isEmpty(); - if (entityServer != null) { - entityServer.getEntities().forEach(REntity::die); + Optional cursor = SWPlayer.of(player).getComponent(Cursor.class); + cursor.ifPresent(__ -> SWPlayer.of(player).removeComponent(Cursor.class)); + REntityServer emptyTargetServer = emptyTargetServers.remove(player); + if (emptyTargetServer != null) { + emptyTargetServer.close(); } - return hadCursor; + return cursor.isPresent(); } - private static synchronized void showCursor(Player player, RayTraceUtils.RRayTraceResult rayTraceResult, boolean hasSimulatorSelected) { - REntityServer entityServer = cursors.computeIfAbsent(player, __ -> { - REntityServer rEntityServer = new REntityServer(); - rEntityServer.addPlayer(player); - return rEntityServer; - }); - - CursorType type = cursorType.getOrDefault(player, CursorType.TNT); - REntity hitEntity = rayTraceResult.getHitEntity(); - Location location = hitEntity != null ? new Vector(hitEntity.getX(), hitEntity.getY(), hitEntity.getZ()).toLocation(WORLD) : - type.position.apply(player, rayTraceResult).toLocation(WORLD); - - Material material = hitEntity != null ? Material.GLASS : type.getMaterial(); - List entities = entityServer.getEntitiesByType(RFallingBlockEntity.class); - entities.removeIf(rFallingBlockEntity -> { - if (rFallingBlockEntity.getMaterial() != material) { - rFallingBlockEntity.die(); - return true; - } - rFallingBlockEntity.move(location); - return false; - }); - if (entities.isEmpty()) { - RFallingBlockEntity rFallingBlockEntity = new RFallingBlockEntity(entityServer, location, material); - rFallingBlockEntity.setNoGravity(true); - if (material == Material.GLASS) { - rFallingBlockEntity.setGlowing(true); - } - } - - if (hasSimulatorSelected) { - if (hitEntity != null) { - SWUtils.sendToActionbar(player, "§eEdit Position"); - } else { - SWUtils.sendToActionbar(player, "§eAdd new " + type.name); - } - } else { + private static void sendCursorActionbar(Player player, Simulator simulator, boolean hasCursorLocation, boolean hasHitEntity) { + if (!hasCursorLocation) { + SWUtils.sendToActionbar(player, simulator == null ? "§eSelect Simulator" : "§eOpen Simulator"); + } else if (simulator == null) { SWUtils.sendToActionbar(player, "§eCreate new Simulator"); - } - } - - public static Vector getPosFree(Player player, RayTraceUtils.RRayTraceResult result) { - Vector pos = result.getHitPosition(); - - BlockFace face = result.getHitBlockFace(); - if (face != null) { - switch (face) { - case DOWN: - pos.setY(pos.getY() - 0.98); - break; - case EAST: - pos.setX(pos.getX() + 0.49); - break; - case WEST: - pos.setX(pos.getX() - 0.49); - break; - case NORTH: - pos.setZ(pos.getZ() - 0.49); - break; - case SOUTH: - pos.setZ(pos.getZ() + 0.49); - break; - default: - break; - } - - if (face.getModY() == 0 && player.isSneaking()) { - pos.setY(pos.getY() - 0.49); - } - } - - if (!player.isSneaking()) { - pos.setX(pos.getBlockX() + 0.5); - if (face == null || face.getModY() == 0) { - pos.setY(pos.getBlockY() + 0.0); - } - pos.setZ(pos.getBlockZ() + 0.5); - } - - return pos; - } - - private static Vector getPosBlockAligned(Player player, RayTraceUtils.RRayTraceResult result) { - Vector pos = result.getHitPosition(); - - BlockFace face = result.getHitBlockFace(); - if (face != null) { - switch (face) { - case DOWN: - pos.setY(pos.getY() - 0.98); - break; - case EAST: - pos.setX(pos.getX() + 0.49); - break; - case WEST: - pos.setX(pos.getX() - 0.49); - break; - case NORTH: - pos.setZ(pos.getZ() - 0.49); - break; - case SOUTH: - pos.setZ(pos.getZ() + 0.49); - break; - default: - break; - } - } - - pos.setX(pos.getBlockX() + 0.5); - if (pos.getY() - pos.getBlockY() != 0 && face == BlockFace.UP) { - pos.setY(pos.getBlockY() + 1.0); + } else if (hasHitEntity) { + SWUtils.sendToActionbar(player, "§eEdit Position"); } else { - pos.setY(pos.getBlockY()); + SWUtils.sendToActionbar(player, "§eAdd new " + cursorType.getOrDefault(player, CursorType.TNT).name); } - pos.setZ(pos.getBlockZ() + 0.5); - return pos; } @Getter @AllArgsConstructor public enum CursorType { - TNT(Material.TNT, Material.GUNPOWDER, SimulatorCursor::getPosFree, "TNT", vector -> new TNTElement(vector).add(new TNTPhase())), - REDSTONE_BLOCK(Material.REDSTONE_BLOCK, Material.REDSTONE, SimulatorCursor::getPosBlockAligned, "Redstone Block", vector -> new RedstoneElement(vector).add(new RedstonePhase())), - OBSERVER(Material.OBSERVER, Material.QUARTZ, SimulatorCursor::getPosBlockAligned, "Observer", vector -> new ObserverElement(vector).add(new ObserverPhase())), + TNT(Material.TNT, Material.GUNPOWDER, List.of(Cursor.CursorMode.FREE), "TNT", vector -> new TNTElement(vector).add(new TNTPhase())), + REDSTONE_BLOCK(Material.REDSTONE_BLOCK, Material.REDSTONE, List.of(Cursor.CursorMode.BLOCK_ALIGNED), "Redstone Block", vector -> new RedstoneElement(vector).add(new RedstonePhase())), + OBSERVER(Material.OBSERVER, Material.QUARTZ, List.of(Cursor.CursorMode.BLOCK_ALIGNED), "Observer", vector -> new ObserverElement(vector).add(new ObserverPhase())), ; public final Material material; public final Material nonSelectedMaterial; - public final BiFunction position; + public final List cursorModes; public final String name; public final Function> elementFunction; } - @EventHandler - public void onPlayerInteract(PlayerInteractEvent event) { - if (!Permission.BUILD.hasPermission(event.getPlayer())) return; - if (!ItemUtils.isItem(event.getItem(), "simulator")) { + private static void handlePlayerClick(Player player, Location cursorLocation, Optional hitEntity, Action action) { + if (!Permission.BUILD.hasPermission(player)) return; + if (!isSimulatorItem(player.getInventory().getItemInMainHand()) && !isSimulatorItem(player.getInventory().getItemInOffHand())) { return; } - event.setCancelled(true); - Player player = event.getPlayer(); Simulator simulator = SimulatorStorage.getSimulator(player); - if (event.getAction() == Action.LEFT_CLICK_BLOCK || event.getAction() == Action.LEFT_CLICK_AIR) { + if (action == Action.LEFT_CLICK_BLOCK || action == Action.LEFT_CLICK_AIR) { if (simulator == null) { return; } - SimulatorExecutor.run(event.getPlayer(), simulator, null); + SimulatorExecutor.run(player, simulator, null); return; } - if (event.getAction() != Action.RIGHT_CLICK_BLOCK && event.getAction() != Action.RIGHT_CLICK_AIR) { + if (action != Action.RIGHT_CLICK_BLOCK && action != Action.RIGHT_CLICK_AIR) { return; } - - RayTraceUtils.RRayTraceResult rayTraceResult = RayTraceUtils.traceREntity(player, player.getLocation(), SimulatorWatcher.getEntitiesOfSimulator(simulator)); if (simulator == null) { - if (rayTraceResult == null) { + if (cursorLocation == null) { SimulatorStorage.openSimulatorSelector(player); } else { SWAnvilInv anvilInv = new SWAnvilInv(player, "Name"); @@ -395,7 +261,7 @@ public class SimulatorCursor implements Listener { } sim = new Simulator(s); SimulatorStorage.addSimulator(s, sim); - createElement(player, rayTraceResult, sim); + createElement(player, cursorLocation, sim); SimulatorStorage.setSimulator(player, sim); }); anvilInv.open(); @@ -403,57 +269,56 @@ public class SimulatorCursor implements Listener { return; } - if (rayTraceResult == null) { + if (cursorLocation == null) { new SimulatorGui(player, simulator).open(); return; } - if (rayTraceResult.getHitEntity() != null) { - REntity hitEntity = rayTraceResult.getHitEntity(); - Vector vector = new Vector(hitEntity.getX(), hitEntity.getY(), hitEntity.getZ()); - List> elements = simulator.getGroups().stream().map(SimulatorGroup::getElements).flatMap(List::stream).filter(element -> { - return element.getWorldPos().distanceSquared(vector) < (1 / 16.0) * (1 / 16.0); - }).collect(Collectors.toList()); - - switch (elements.size()) { - case 0: - return; - case 1: - // Open single element present in Simulator - SimulatorElement element = elements.get(0); - SimulatorGroup group1 = element.getGroup(simulator); - SimulatorBaseGui back = new SimulatorGui(player, simulator); - if (group1.getElements().size() > 1) { - back = new SimulatorGroupGui(player, simulator, group1, back); - } - element.open(player, simulator, group1, back); - break; - default: - List parents = elements.stream().map(e -> e.getGroup(simulator)).distinct().collect(Collectors.toList()); - if (parents.size() == 1) { - // Open multi element present in Simulator in existing group - SimulatorGui simulatorGui = new SimulatorGui(player, simulator); - new SimulatorGroupGui(player, simulator, parents.get(0), simulatorGui).open(); - } else { - // Open multi element present in Simulator in implicit group - SimulatorGroup group2 = new SimulatorGroup(); - group2.setMaterial(null); - group2.getElements().addAll(elements); - SimulatorGui simulatorGui = new SimulatorGui(player, simulator); - new SimulatorGroupGui(player, simulator, group2, simulatorGui).open(); - } - break; - } + if (hitEntity.isPresent()) { + openElement(player, simulator, hitEntity.get()); return; } - // Add new Element to current simulator - createElement(player, rayTraceResult, simulator); + createElement(player, cursorLocation, simulator); } - private void createElement(Player player, RayTraceUtils.RRayTraceResult rayTraceResult, Simulator simulator) { + private static void openElement(Player player, Simulator simulator, REntity hitEntity) { + Vector vector = new Vector(hitEntity.getX(), hitEntity.getY(), hitEntity.getZ()); + List> elements = simulator.getGroups().stream().map(SimulatorGroup::getElements).flatMap(List::stream).filter(element -> { + return element.getWorldPos().distanceSquared(vector) < (1 / 16.0) * (1 / 16.0); + }).collect(Collectors.toList()); + + switch (elements.size()) { + case 0: + return; + case 1: + SimulatorElement element = elements.get(0); + SimulatorGroup group1 = element.getGroup(simulator); + SimulatorBaseGui back = new SimulatorGui(player, simulator); + if (group1.getElements().size() > 1) { + back = new SimulatorGroupGui(player, simulator, group1, back); + } + element.open(player, simulator, group1, back); + break; + default: + List parents = elements.stream().map(e -> e.getGroup(simulator)).distinct().collect(Collectors.toList()); + if (parents.size() == 1) { + SimulatorGui simulatorGui = new SimulatorGui(player, simulator); + new SimulatorGroupGui(player, simulator, parents.get(0), simulatorGui).open(); + } else { + SimulatorGroup group2 = new SimulatorGroup(); + group2.setMaterial(null); + group2.getElements().addAll(elements); + SimulatorGui simulatorGui = new SimulatorGui(player, simulator); + new SimulatorGroupGui(player, simulator, group2, simulatorGui).open(); + } + break; + } + } + + private static void createElement(Player player, Location cursorLocation, Simulator simulator) { CursorType type = cursorType.getOrDefault(player, CursorType.TNT); - Vector vector = type.position.apply(player, rayTraceResult); + Vector vector = cursorLocation.toVector(); if (type == CursorType.REDSTONE_BLOCK) { vector.subtract(new Vector(0.5, 0, 0.5)); } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorWatcher.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorWatcher.java index 3c8ff96f..800c0c73 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorWatcher.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorWatcher.java @@ -124,4 +124,11 @@ public class SimulatorWatcher { } return entityServer.getEntities(); } + + synchronized REntityServer getEntityServerOfSimulator(Simulator simulator) { + if (simulator == null) { + return null; + } + return entityServers.computeIfAbsent(simulator, __ -> createSim(new REntityServer(), simulator)); + } } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/cursor/Cursor.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/cursor/Cursor.java index 61450b67..86973cc5 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/cursor/Cursor.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/cursor/Cursor.java @@ -21,6 +21,7 @@ import java.util.Comparator; import java.util.List; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Predicate; @@ -44,14 +45,22 @@ public class Cursor implements SWPlayer.Component { private List allowedCursorModes; private final Material highlightMaterial; private final TriConsumer, Action> onClick; + private final BiConsumer> onRender; public Cursor(REntityServer targetServer, Player owner, Material highlightMaterial, Material cursorMaterial, List allowedModes, TriConsumer, Action> onClick) { + this(targetServer, owner, highlightMaterial, cursorMaterial, allowedModes, onClick, (location, hitEntity) -> { + }); + } + + public Cursor(REntityServer targetServer, Player owner, Material highlightMaterial, Material cursorMaterial, List allowedModes, TriConsumer, Action> onClick, BiConsumer> onRender) { this.targetServer = targetServer; this.owner = owner; this.highlightMaterial = highlightMaterial; this.cursorMaterial = cursorMaterial; + this.allowedCursorModes = allowedModes; this.onClick = onClick; + this.onRender = onRender; cursorServer = new REntityServer(); cursorServer.addPlayer(owner); @@ -72,6 +81,9 @@ public class Cursor implements SWPlayer.Component { if (cursorEntity != null) cursorEntity.die(); cursorEntity = null; + cursorLocation = null; + hitEntity = null; + onRender.accept(null, Optional.empty()); return; } @@ -101,14 +113,12 @@ public class Cursor implements SWPlayer.Component { cursorEntity.setGlowing(true); } } + onRender.accept(cursorLocation, Optional.ofNullable(hitEntity)); } protected void handlePlayerClick(Action clickAction) { renderDeduplicated(); - - if(cursorLocation != null) { - onClick.accept(this.cursorLocation, Optional.ofNullable(this.hitEntity), clickAction); - } + onClick.accept(this.cursorLocation, Optional.ofNullable(this.hitEntity), clickAction); } @Override