From f5129590777ce049f4c75f6d0fa41854f02eedf1 Mon Sep 17 00:00:00 2001 From: goodroach Date: Mon, 24 Jul 2023 14:09:50 -1000 Subject: [PATCH 1/4] implement node directors --- .../features/directors/AADirectors.java | 4 +- .../features/directors/CannonDirectors.java | 70 ++++++++++++--- .../features/directors/DirectorData.java | 37 ++++++++ .../combat/features/directors/Directors.java | 90 ++++++++++++++----- .../features/tracking/FireballTracking.java | 6 +- .../combat/features/tracking/TNTTracking.java | 6 +- 6 files changed, 167 insertions(+), 46 deletions(-) create mode 100644 src/main/java/net/countercraft/movecraft/combat/features/directors/DirectorData.java diff --git a/src/main/java/net/countercraft/movecraft/combat/features/directors/AADirectors.java b/src/main/java/net/countercraft/movecraft/combat/features/directors/AADirectors.java index 084bb45a..e11e8b0a 100644 --- a/src/main/java/net/countercraft/movecraft/combat/features/directors/AADirectors.java +++ b/src/main/java/net/countercraft/movecraft/combat/features/directors/AADirectors.java @@ -75,7 +75,7 @@ private void processFireball(@NotNull SmallFireball fireball) { if (!(c instanceof PlayerCraft) || !hasDirector((PlayerCraft) c)) return; - Player p = getDirector((PlayerCraft) c); + Player p = null; MovecraftLocation midPoint = c.getHitBox().getMidPoint(); int distX = Math.abs(midPoint.getX() - fireball.getLocation().getBlockX()); @@ -178,7 +178,7 @@ public void onSignClick(@NotNull PlayerInteractEvent e) { } clearDirector(p); - addDirector(foundCraft, p); + addDirector(p, foundCraft, sign.getLine(1), sign.getLine(2), sign.getLine(3)); p.sendMessage(I18nSupport.getInternationalisedString("AADirector - Directing")); } } diff --git a/src/main/java/net/countercraft/movecraft/combat/features/directors/CannonDirectors.java b/src/main/java/net/countercraft/movecraft/combat/features/directors/CannonDirectors.java index f547f0ef..76caf747 100644 --- a/src/main/java/net/countercraft/movecraft/combat/features/directors/CannonDirectors.java +++ b/src/main/java/net/countercraft/movecraft/combat/features/directors/CannonDirectors.java @@ -1,7 +1,6 @@ package net.countercraft.movecraft.combat.features.directors; import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap; -import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.combat.features.tracking.DamageTracking; import net.countercraft.movecraft.combat.localisation.I18nSupport; import net.countercraft.movecraft.combat.utils.DirectorUtils; @@ -14,6 +13,7 @@ import net.countercraft.movecraft.util.MathUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.World; @@ -33,6 +33,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.UUID; @@ -42,6 +44,7 @@ public class CannonDirectors extends Directors implements Listener { public static final NamespacedKey ALLOW_CANNON_DIRECTOR_SIGN = new NamespacedKey("movecraft-combat", "allow_cannon_director_sign"); private static final String HEADER = "Cannon Director"; public static int CannonDirectorDistance = 100; + public static int CannonDirectorNodeDistance = 3; public static int CannonDirectorRange = 120; private final Object2DoubleOpenHashMap tracking = new Object2DoubleOpenHashMap<>(); private long lastCheck = 0; @@ -56,7 +59,8 @@ public static void register() { } public static void load(@NotNull FileConfiguration config) { - CannonDirectorDistance = config.getInt("CannonDirectorsDistance", 100); + CannonDirectorDistance = config.getInt("CannonDirectorDistance", 100); + CannonDirectorNodeDistance = config.getInt("CannonDirectorNodeDistance", 3); CannonDirectorRange = config.getInt("CannonDirectorRange", 120); } @@ -98,16 +102,48 @@ private void processTNT(@NotNull TNTPrimed tnt) { if (!(c instanceof PlayerCraft)) return; - MovecraftLocation midpoint = c.getHitBox().getMidPoint(); - int distX = Math.abs(midpoint.getX() - tnt.getLocation().getBlockX()); - int distY = Math.abs(midpoint.getY() - tnt.getLocation().getBlockY()); - int distZ = Math.abs(midpoint.getZ() - tnt.getLocation().getBlockZ()); - if (!hasDirector((PlayerCraft) c) || distX >= CannonDirectorDistance - || distY >= CannonDirectorDistance || distZ >= CannonDirectorDistance) - return; + HashSet directorDataSet = getDirectorDataSet((PlayerCraft) c); + Player player = null; + Player dominantPlayer = null; + // Adjust the TNT location based on its velocity to make it closer to the firing point. + int ticks = 1; + Location correctedLocation = tnt.getLocation().clone().add(tnt.getVelocity().clone().multiply(-ticks)); + System.out.println("Corrected location at: " + correctedLocation.getBlockX() + ", " + correctedLocation.getBlockY() + ", " + correctedLocation.getBlockZ()); + + for (DirectorData data : directorDataSet) { + if (data.getSelectedSigns().isEmpty()) { + dominantPlayer = data.getPlayer(); + } + } + if (dominantPlayer != null) { + System.out.println("Dominant player is: " + dominantPlayer.getName()); + player = dominantPlayer; + } else { + System.out.println("Dominant player not found, finding others..."); + for (DirectorData data : directorDataSet) { + HashSet locations = getLocations(data); + for (Location location : locations) { + System.out.println("Location of sign: " + location.getBlockX() + ", " + location.getBlockY() + ", " + location.getBlockZ()); + int distX = Math.abs(location.getBlockX() - correctedLocation.getBlockX()); + int distY = Math.abs(location.getBlockY() - correctedLocation.getBlockY()); + int distZ = Math.abs(location.getBlockZ() - correctedLocation.getBlockZ()); + + System.out.println("Node distances are for xyz: " + distX + " , " + distY + " , " + distZ); + + if (distX <= CannonDirectorNodeDistance && distY <= CannonDirectorNodeDistance && distZ <= CannonDirectorNodeDistance) { + player = data.getPlayer(); + System.out.println("Non-dominant player is: " + data.getPlayer()); + break; + } + } + if (player != null) { + System.out.println("Non-dominant player is not null."); + break; + } + } + } - Player p = getDirector((PlayerCraft) c); - if (p == null || p.getInventory().getItemInMainHand().getType() != Directors.DirectorTool) + if (player == null || player.getInventory().getItemInMainHand().getType() != Directors.DirectorTool) return; // Store the speed to add it back in later, since all the values we will be using are "normalized", IE: have a speed of 1 @@ -117,10 +153,10 @@ private void processTNT(@NotNull TNTPrimed tnt) { double horizontalSpeed = tntVector.length(); tntVector = tntVector.normalize(); // you normalize it for comparison with the new direction to see if we are trying to steer too far - Block targetBlock = DirectorUtils.getDirectorBlock(p, CannonDirectorRange); + Block targetBlock = DirectorUtils.getDirectorBlock(player, CannonDirectorRange); Vector targetVector; if (targetBlock == null || targetBlock.getType().equals(Material.AIR)) // the player is looking at nothing, shoot in that general direction - targetVector = p.getLocation().getDirection(); + targetVector = player.getLocation().getDirection(); else // shoot directly at the block the player is looking at (IE: with convergence) targetVector = targetBlock.getLocation().toVector().subtract(tnt.getLocation().toVector()); @@ -208,7 +244,13 @@ public final void onSignClick(@NotNull PlayerInteractEvent e) { } clearDirector(p); - addDirector(foundCraft, p); + DirectorData data = addDirector(p, foundCraft, sign.getLine(1), sign.getLine(2), sign.getLine(3)); + + if (isNodesShared(data)) { + p.sendMessage(ERROR_PREFIX + " " + I18nSupport.getInternationalisedString("CannonDirector - Must Not Share Nodes")); + return; + } + p.sendMessage(I18nSupport.getInternationalisedString("CannonDirector - Directing")); } diff --git a/src/main/java/net/countercraft/movecraft/combat/features/directors/DirectorData.java b/src/main/java/net/countercraft/movecraft/combat/features/directors/DirectorData.java new file mode 100644 index 00000000..56781472 --- /dev/null +++ b/src/main/java/net/countercraft/movecraft/combat/features/directors/DirectorData.java @@ -0,0 +1,37 @@ +package net.countercraft.movecraft.combat.features.directors; + +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.craft.PlayerCraft; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.block.Sign; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class DirectorData { + private Player player; + private PlayerCraft craft; + private List selectedSigns; + + public DirectorData(Player player, PlayerCraft craft, List selectedSigns) { + this.player = player; + this.craft = craft; + this.selectedSigns = selectedSigns; + } + + public Player getPlayer() { + return player; + } + + public PlayerCraft getCraft() { + return craft; + } + + public List getSelectedSigns() { + return selectedSigns; + } +} \ No newline at end of file diff --git a/src/main/java/net/countercraft/movecraft/combat/features/directors/Directors.java b/src/main/java/net/countercraft/movecraft/combat/features/directors/Directors.java index 5ff507f6..872d7e0b 100644 --- a/src/main/java/net/countercraft/movecraft/combat/features/directors/Directors.java +++ b/src/main/java/net/countercraft/movecraft/combat/features/directors/Directors.java @@ -1,25 +1,33 @@ package net.countercraft.movecraft.combat.features.directors; import com.google.common.collect.HashBiMap; +import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.combat.MovecraftCombat; import net.countercraft.movecraft.craft.PlayerCraft; import net.countercraft.movecraft.util.Tags; +import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.Sign; +import org.bukkit.block.data.type.WallSign; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Set; public class Directors extends BukkitRunnable { private static final Set instances = new HashSet<>(); public static Material DirectorTool = null; public static Set Transparent = null; - private final HashBiMap directors = HashBiMap.create(); - + private Map directors = new HashMap<>(); public Directors() { instances.add(this); @@ -60,28 +68,50 @@ public void run() { } + public DirectorData addDirector(Player player, PlayerCraft craft, String line1, String line2, String line3) { + if (directors.containsValue(player)) directors.remove(player); + List selectedLines = new ArrayList<>(); + selectedLines.add(line1); + selectedLines.add(line2); + selectedLines.add(line3); + if (line1.isBlank() && line2.isBlank() && line3.isBlank()) selectedLines.clear(); + DirectorData data = new DirectorData(player, craft, selectedLines); + directors.put(player, data); + System.out.println("New director added: " + directors.get(player).getSelectedSigns()); + System.out.println("Director name: " + directors.get(player).getPlayer()); + return data; + } - public void addDirector(@NotNull PlayerCraft craft, @NotNull Player player) { - if (directors.containsValue(player)) - directors.inverse().remove(player); - - directors.put(craft, player); + public HashSet getDirectorDataSet(PlayerCraft craft) { + HashSet directorDataSet = new HashSet<>(); + for (DirectorData data : directors.values()) { + if (data.getCraft() == craft) directorDataSet.add(data); + } + return directorDataSet; } - public boolean isDirector(@NotNull Player player) { - return directors.containsValue(player); + public boolean hasDirector(PlayerCraft craft) { + if (craft == null) return false; + for (DirectorData data : directors.values()) { + if (data.getCraft() == craft) return true; + } + return false; } - public boolean hasDirector(@NotNull PlayerCraft craft) { - if (!directors.containsKey(craft)) - return false; + public boolean isNodesShared(DirectorData director) { + PlayerCraft craft = director.getCraft(); + List selectedSigns = director.getSelectedSigns(); + return directors.values().stream() + .filter(data -> data != director && data.getCraft() == craft) + .anyMatch(data -> data.getSelectedSigns().stream().anyMatch(selectedSigns::contains)); + } - Player director = directors.get(craft); - return director != null && director.isOnline(); + public boolean isDirector(@NotNull Player player) { + return directors.containsKey(player); } public void removeDirector(@NotNull Player player) { - directors.inverse().remove(player); + directors.remove(player); } public void clearDirector(@NotNull Player player) { @@ -89,12 +119,32 @@ public void clearDirector(@NotNull Player player) { instance.removeDirector(player); } - @Nullable - public Player getDirector(@NotNull PlayerCraft craft) { - Player director = directors.get(craft); - if (director == null || !director.isOnline()) + public HashSet getLocations(DirectorData data) { + if (data.getSelectedSigns().isEmpty() || data.getCraft() == null) { return null; + } + PlayerCraft craft = data.getCraft(); + + HashSet locations = new HashSet<>(); + for (MovecraftLocation location : craft.getHitBox()) { + Block block = craft.getWorld().getBlockAt(location.getX(), location.getY(), location.getZ()); + if (!(block.getState() instanceof Sign)) + continue; - return director; + Sign sign = (Sign) block.getState(); + + if (!sign.getLine(0).equalsIgnoreCase("subcraft rotate")) { + continue; + } + if (sign.getLine(3).isBlank()) { + System.out.println("Sign is blank"); + continue; + } + if (data.getSelectedSigns().contains(sign.getLine(3))) { + System.out.println("Sign found."); + locations.add(block.getLocation()); + } + } + return locations; } } diff --git a/src/main/java/net/countercraft/movecraft/combat/features/tracking/FireballTracking.java b/src/main/java/net/countercraft/movecraft/combat/features/tracking/FireballTracking.java index 4ff27e89..fe83bc06 100644 --- a/src/main/java/net/countercraft/movecraft/combat/features/tracking/FireballTracking.java +++ b/src/main/java/net/countercraft/movecraft/combat/features/tracking/FireballTracking.java @@ -68,11 +68,7 @@ public void onProjectileLaunch(@NotNull ProjectileLaunchEvent e) { PlayerCraft playerCraft = (PlayerCraft) craft; - Player sender; - if (directors.hasDirector(playerCraft)) - sender = directors.getDirector(playerCraft); - else - sender = playerCraft.getPilot(); + Player sender = playerCraft.getPilot(); if (sender == null) return; diff --git a/src/main/java/net/countercraft/movecraft/combat/features/tracking/TNTTracking.java b/src/main/java/net/countercraft/movecraft/combat/features/tracking/TNTTracking.java index 97aaa79a..1fbef9d8 100644 --- a/src/main/java/net/countercraft/movecraft/combat/features/tracking/TNTTracking.java +++ b/src/main/java/net/countercraft/movecraft/combat/features/tracking/TNTTracking.java @@ -133,11 +133,7 @@ public void onBlockDispense(@NotNull BlockDispenseEvent e) { // Report to tracking PlayerCraft playerCraft = (PlayerCraft) craft; - Player sender; - if (directors.hasDirector(playerCraft)) - sender = directors.getDirector(playerCraft); - else - sender = playerCraft.getPilot(); + Player sender = playerCraft.getPilot(); if (sender == null) return; From a15564c63a3d12b638eadf6d6cbf8a8597575d54 Mon Sep 17 00:00:00 2001 From: goodroach Date: Fri, 28 Jul 2023 23:09:09 -1000 Subject: [PATCH 2/4] oops forgot aa directors --- .../features/directors/AADirectors.java | 63 +++++++++++++++---- .../features/directors/CannonDirectors.java | 16 ++--- .../features/directors/DirectorData.java | 8 --- src/main/resources/config.yml | 2 + 4 files changed, 61 insertions(+), 28 deletions(-) diff --git a/src/main/java/net/countercraft/movecraft/combat/features/directors/AADirectors.java b/src/main/java/net/countercraft/movecraft/combat/features/directors/AADirectors.java index e11e8b0a..55ad6eef 100644 --- a/src/main/java/net/countercraft/movecraft/combat/features/directors/AADirectors.java +++ b/src/main/java/net/countercraft/movecraft/combat/features/directors/AADirectors.java @@ -11,6 +11,7 @@ import net.countercraft.movecraft.util.MathUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.World; @@ -27,12 +28,15 @@ import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; +import java.util.HashSet; + import static net.countercraft.movecraft.util.ChatUtils.ERROR_PREFIX; public class AADirectors extends Directors implements Listener { public static final NamespacedKey ALLOW_AA_DIRECTOR_SIGN = new NamespacedKey("movecraft-combat", "allow_aa_director_sign"); private static final String HEADER = "AA Director"; public static int AADirectorDistance = 50; + public static int AADirectorNodeDistance = 3; public static int AADirectorRange = 120; private long lastCheck = 0; @@ -46,6 +50,7 @@ public static void register() { public static void load(@NotNull FileConfiguration config) { AADirectorDistance = config.getInt("AADirectorDistance", 50); + AADirectorNodeDistance = config.getInt("AADirectorNodeDistance", 3); AADirectorRange = config.getInt("AADirectorRange", 120); } @@ -75,28 +80,56 @@ private void processFireball(@NotNull SmallFireball fireball) { if (!(c instanceof PlayerCraft) || !hasDirector((PlayerCraft) c)) return; - Player p = null; + HashSet directorDataSet = getDirectorDataSet((PlayerCraft) c); + Player player = null; + Player dominantPlayer = null; - MovecraftLocation midPoint = c.getHitBox().getMidPoint(); - int distX = Math.abs(midPoint.getX() - fireball.getLocation().getBlockX()); - int distY = Math.abs(midPoint.getY() - fireball.getLocation().getBlockY()); - int distZ = Math.abs(midPoint.getZ() - fireball.getLocation().getBlockZ()); - if (distX > AADirectorDistance || distY > AADirectorDistance || distZ > AADirectorDistance) - return; + for (DirectorData data : directorDataSet) { + if (data.getSelectedSigns().isEmpty()) { + dominantPlayer = data.getPlayer(); + } + } + if (dominantPlayer != null) { + player = dominantPlayer; + } else { + for (DirectorData data : directorDataSet) { + HashSet locations = getLocations(data); + for (Location location : locations) { + int distX = Math.abs(location.getBlockX() - fireball.getLocation().getBlockX()); + int distY = Math.abs(location.getBlockY() - fireball.getLocation().getBlockY()); + int distZ = Math.abs(location.getBlockZ() - fireball.getLocation().getBlockZ()); + + if (distX <= AADirectorNodeDistance && distY <= AADirectorNodeDistance && distZ <= AADirectorNodeDistance) { + player = data.getPlayer(); + break; + } + } + if (player != null) { + break; + } + } + } - fireball.setShooter(p); + if (player == null || player.getInventory().getItemInMainHand().getType() != Directors.DirectorTool) + return; - if (p == null || p.getInventory().getItemInMainHand().getType() != Directors.DirectorTool) + MovecraftLocation midpoint = c.getHitBox().getMidPoint(); + int distX = Math.abs(midpoint.getX() - fireball.getLocation().getBlockX()); + int distY = Math.abs(midpoint.getY() - fireball.getLocation().getBlockY()); + int distZ = Math.abs(midpoint.getZ() - fireball.getLocation().getBlockZ()); + if (distX >= AADirectorDistance || distY >= AADirectorDistance || distZ >= AADirectorDistance) return; + fireball.setShooter(player); + Vector fireballVector = fireball.getVelocity(); double speed = fireballVector.length(); // store the speed to add it back in later, since all the values we will be using are "normalized", IE: have a speed of 1 fireballVector = fireballVector.normalize(); // you normalize it for comparison with the new direction to see if we are trying to steer too far - Block targetBlock = DirectorUtils.getDirectorBlock(p, AADirectorRange); + Block targetBlock = DirectorUtils.getDirectorBlock(player, AADirectorRange); Vector targetVector; if (targetBlock == null || targetBlock.getType().equals(Material.AIR)) // the player is looking at nothing, shoot in that general direction - targetVector = p.getLocation().getDirection(); + targetVector = player.getLocation().getDirection(); else { // shoot directly at the block the player is looking at (IE: with convergence) targetVector = targetBlock.getLocation().toVector().subtract(fireball.getLocation().toVector()); targetVector = targetVector.normalize(); @@ -178,7 +211,13 @@ public void onSignClick(@NotNull PlayerInteractEvent e) { } clearDirector(p); - addDirector(p, foundCraft, sign.getLine(1), sign.getLine(2), sign.getLine(3)); + DirectorData data = addDirector(p, foundCraft, sign.getLine(1), sign.getLine(2), sign.getLine(3)); + + if (isNodesShared(data)) { + p.sendMessage(ERROR_PREFIX + " " + I18nSupport.getInternationalisedString("CannonDirector - Must Not Share Nodes")); + return; + } + p.sendMessage(I18nSupport.getInternationalisedString("AADirector - Directing")); } } diff --git a/src/main/java/net/countercraft/movecraft/combat/features/directors/CannonDirectors.java b/src/main/java/net/countercraft/movecraft/combat/features/directors/CannonDirectors.java index 76caf747..4c0866f9 100644 --- a/src/main/java/net/countercraft/movecraft/combat/features/directors/CannonDirectors.java +++ b/src/main/java/net/countercraft/movecraft/combat/features/directors/CannonDirectors.java @@ -1,6 +1,7 @@ package net.countercraft.movecraft.combat.features.directors; import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap; +import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.combat.features.tracking.DamageTracking; import net.countercraft.movecraft.combat.localisation.I18nSupport; import net.countercraft.movecraft.combat.utils.DirectorUtils; @@ -108,7 +109,6 @@ private void processTNT(@NotNull TNTPrimed tnt) { // Adjust the TNT location based on its velocity to make it closer to the firing point. int ticks = 1; Location correctedLocation = tnt.getLocation().clone().add(tnt.getVelocity().clone().multiply(-ticks)); - System.out.println("Corrected location at: " + correctedLocation.getBlockX() + ", " + correctedLocation.getBlockY() + ", " + correctedLocation.getBlockZ()); for (DirectorData data : directorDataSet) { if (data.getSelectedSigns().isEmpty()) { @@ -116,28 +116,21 @@ private void processTNT(@NotNull TNTPrimed tnt) { } } if (dominantPlayer != null) { - System.out.println("Dominant player is: " + dominantPlayer.getName()); player = dominantPlayer; } else { - System.out.println("Dominant player not found, finding others..."); for (DirectorData data : directorDataSet) { HashSet locations = getLocations(data); for (Location location : locations) { - System.out.println("Location of sign: " + location.getBlockX() + ", " + location.getBlockY() + ", " + location.getBlockZ()); int distX = Math.abs(location.getBlockX() - correctedLocation.getBlockX()); int distY = Math.abs(location.getBlockY() - correctedLocation.getBlockY()); int distZ = Math.abs(location.getBlockZ() - correctedLocation.getBlockZ()); - System.out.println("Node distances are for xyz: " + distX + " , " + distY + " , " + distZ); - if (distX <= CannonDirectorNodeDistance && distY <= CannonDirectorNodeDistance && distZ <= CannonDirectorNodeDistance) { player = data.getPlayer(); - System.out.println("Non-dominant player is: " + data.getPlayer()); break; } } if (player != null) { - System.out.println("Non-dominant player is not null."); break; } } @@ -146,6 +139,13 @@ private void processTNT(@NotNull TNTPrimed tnt) { if (player == null || player.getInventory().getItemInMainHand().getType() != Directors.DirectorTool) return; + MovecraftLocation midpoint = c.getHitBox().getMidPoint(); + int distX = Math.abs(midpoint.getX() - correctedLocation.getBlockX()); + int distY = Math.abs(midpoint.getY() - correctedLocation.getBlockY()); + int distZ = Math.abs(midpoint.getZ() - correctedLocation.getBlockZ()); + if (distX >= CannonDirectorDistance || distY >= CannonDirectorDistance || distZ >= CannonDirectorDistance) + return; + // Store the speed to add it back in later, since all the values we will be using are "normalized", IE: have a speed of 1 // We're only interested in the horizontal speed for now since that's all directors *should* affect. Vector tntVector = tnt.getVelocity(); diff --git a/src/main/java/net/countercraft/movecraft/combat/features/directors/DirectorData.java b/src/main/java/net/countercraft/movecraft/combat/features/directors/DirectorData.java index 56781472..a1f41530 100644 --- a/src/main/java/net/countercraft/movecraft/combat/features/directors/DirectorData.java +++ b/src/main/java/net/countercraft/movecraft/combat/features/directors/DirectorData.java @@ -1,16 +1,8 @@ package net.countercraft.movecraft.combat.features.directors; - -import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.craft.PlayerCraft; -import org.bukkit.Location; -import org.bukkit.block.Block; -import org.bukkit.block.Sign; import org.bukkit.entity.Player; -import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import java.util.Set; public class DirectorData { private Player player; diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index e52edce0..1bc53291 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -5,10 +5,12 @@ Locale: "en" # Language file to load, currently the plugin comes with en and no, # AA Directors AADirectorDistance: 50 # Max range at which fireballs will be redirected +AADirectorNodeDistance: # See node directors AADirectorRange: 120 # Max range at which it will direct to a block vs in the general direction # Cannon Directors CannonDirectorDistance: 100 # Max range at which TNT will be redirected +CannonDirectorNodeDistance: 3 # See node directors CannonDirectorRange: 120 # Max range at which it will direct to a block vs in the general direction # Directors From d96dd3c50f91a3f8cd8e773121e9fed895ee74c8 Mon Sep 17 00:00:00 2001 From: goodroach Date: Fri, 1 Sep 2023 19:39:12 -1000 Subject: [PATCH 3/4] Provide additional checks for sign selection --- .../movecraft/combat/features/directors/AADirectors.java | 2 +- .../movecraft/combat/features/directors/CannonDirectors.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/countercraft/movecraft/combat/features/directors/AADirectors.java b/src/main/java/net/countercraft/movecraft/combat/features/directors/AADirectors.java index 55ad6eef..3dfefd18 100644 --- a/src/main/java/net/countercraft/movecraft/combat/features/directors/AADirectors.java +++ b/src/main/java/net/countercraft/movecraft/combat/features/directors/AADirectors.java @@ -85,7 +85,7 @@ private void processFireball(@NotNull SmallFireball fireball) { Player dominantPlayer = null; for (DirectorData data : directorDataSet) { - if (data.getSelectedSigns().isEmpty()) { + if (data.getSelectedSigns().isEmpty() || getLocations(data).isEmpty()) { dominantPlayer = data.getPlayer(); } } diff --git a/src/main/java/net/countercraft/movecraft/combat/features/directors/CannonDirectors.java b/src/main/java/net/countercraft/movecraft/combat/features/directors/CannonDirectors.java index 4c0866f9..a7298059 100644 --- a/src/main/java/net/countercraft/movecraft/combat/features/directors/CannonDirectors.java +++ b/src/main/java/net/countercraft/movecraft/combat/features/directors/CannonDirectors.java @@ -111,7 +111,7 @@ private void processTNT(@NotNull TNTPrimed tnt) { Location correctedLocation = tnt.getLocation().clone().add(tnt.getVelocity().clone().multiply(-ticks)); for (DirectorData data : directorDataSet) { - if (data.getSelectedSigns().isEmpty()) { + if (data.getSelectedSigns().isEmpty() || getLocations(data).isEmpty()) { dominantPlayer = data.getPlayer(); } } From 71d32c14f26e66f503cc0974246ca4ac60a1bc24 Mon Sep 17 00:00:00 2001 From: goodroach Date: Sat, 7 Oct 2023 23:13:23 -1000 Subject: [PATCH 4/4] optimizations --- .../features/directors/AADirectors.java | 44 +++----- .../features/directors/CannonDirectors.java | 63 +++++------ .../features/directors/DirectorData.java | 58 ++++++++-- .../combat/features/directors/Directors.java | 104 +++++++++--------- src/main/resources/config.yml | 2 +- .../localisation/mcclang_en.properties | 2 + 6 files changed, 144 insertions(+), 129 deletions(-) diff --git a/src/main/java/net/countercraft/movecraft/combat/features/directors/AADirectors.java b/src/main/java/net/countercraft/movecraft/combat/features/directors/AADirectors.java index 3dfefd18..a40fc380 100644 --- a/src/main/java/net/countercraft/movecraft/combat/features/directors/AADirectors.java +++ b/src/main/java/net/countercraft/movecraft/combat/features/directors/AADirectors.java @@ -11,7 +11,6 @@ import net.countercraft.movecraft.util.MathUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; -import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.World; @@ -29,6 +28,7 @@ import org.jetbrains.annotations.NotNull; import java.util.HashSet; +import java.util.Set; import static net.countercraft.movecraft.util.ChatUtils.ERROR_PREFIX; @@ -80,34 +80,23 @@ private void processFireball(@NotNull SmallFireball fireball) { if (!(c instanceof PlayerCraft) || !hasDirector((PlayerCraft) c)) return; - HashSet directorDataSet = getDirectorDataSet((PlayerCraft) c); - Player player = null; + HashSet craftDirectors = getCraftDirectors((PlayerCraft) c); + Player player; Player dominantPlayer = null; - for (DirectorData data : directorDataSet) { - if (data.getSelectedSigns().isEmpty() || getLocations(data).isEmpty()) { + for (DirectorData data : craftDirectors) { + if (data.getSelectedNodes().isEmpty() || data.getSignLocations().isEmpty()) { dominantPlayer = data.getPlayer(); } } if (dominantPlayer != null) { player = dominantPlayer; } else { - for (DirectorData data : directorDataSet) { - HashSet locations = getLocations(data); - for (Location location : locations) { - int distX = Math.abs(location.getBlockX() - fireball.getLocation().getBlockX()); - int distY = Math.abs(location.getBlockY() - fireball.getLocation().getBlockY()); - int distZ = Math.abs(location.getBlockZ() - fireball.getLocation().getBlockZ()); - - if (distX <= AADirectorNodeDistance && distY <= AADirectorNodeDistance && distZ <= AADirectorNodeDistance) { - player = data.getPlayer(); - break; - } - } - if (player != null) { - break; - } - } + player = getClosestDirectorFromProjectile( + craftDirectors, + fireball.getLocation().toVector(), + AADirectorNodeDistance + ); } if (player == null || player.getInventory().getItemInMainHand().getType() != Directors.DirectorTool) @@ -117,7 +106,7 @@ private void processFireball(@NotNull SmallFireball fireball) { int distX = Math.abs(midpoint.getX() - fireball.getLocation().getBlockX()); int distY = Math.abs(midpoint.getY() - fireball.getLocation().getBlockY()); int distZ = Math.abs(midpoint.getZ() - fireball.getLocation().getBlockZ()); - if (distX >= AADirectorDistance || distY >= AADirectorDistance || distZ >= AADirectorDistance) + if (distX*distX + distY*distY + distZ*distZ >= AADirectorDistance*AADirectorDistance) return; fireball.setShooter(player); @@ -210,14 +199,15 @@ public void onSignClick(@NotNull PlayerInteractEvent e) { return; } - clearDirector(p); - DirectorData data = addDirector(p, foundCraft, sign.getLine(1), sign.getLine(2), sign.getLine(3)); - - if (isNodesShared(data)) { - p.sendMessage(ERROR_PREFIX + " " + I18nSupport.getInternationalisedString("CannonDirector - Must Not Share Nodes")); + Set selectedLines = processSign(sign); + if (isNodesShared(selectedLines, foundCraft, p)) { + p.sendMessage(ERROR_PREFIX + " " + I18nSupport.getInternationalisedString("AADirector - Must Not Share Nodes")); return; } + clearDirector(p); + addDirector(p, foundCraft, selectedLines); + p.sendMessage(I18nSupport.getInternationalisedString("AADirector - Directing")); } } diff --git a/src/main/java/net/countercraft/movecraft/combat/features/directors/CannonDirectors.java b/src/main/java/net/countercraft/movecraft/combat/features/directors/CannonDirectors.java index a7298059..0fc8610e 100644 --- a/src/main/java/net/countercraft/movecraft/combat/features/directors/CannonDirectors.java +++ b/src/main/java/net/countercraft/movecraft/combat/features/directors/CannonDirectors.java @@ -20,6 +20,7 @@ import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.Sign; +import org.bukkit.block.data.type.TNT; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import org.bukkit.entity.TNTPrimed; @@ -34,9 +35,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.UUID; import static net.countercraft.movecraft.util.ChatUtils.ERROR_PREFIX; @@ -50,7 +51,6 @@ public class CannonDirectors extends Directors implements Listener { private final Object2DoubleOpenHashMap tracking = new Object2DoubleOpenHashMap<>(); private long lastCheck = 0; - public CannonDirectors() { super(); } @@ -103,47 +103,33 @@ private void processTNT(@NotNull TNTPrimed tnt) { if (!(c instanceof PlayerCraft)) return; - HashSet directorDataSet = getDirectorDataSet((PlayerCraft) c); + // Automatically calibrate the TNT location based on its velocity to make it closer to the firing point. + Location correctedLocation = tnt.getLocation().clone().add(tnt.getVelocity().clone().multiply(-1.2)); + Vector correctedPosition = correctedLocation.toVector(); + + HashSet craftDirectors = getCraftDirectors((PlayerCraft) c); Player player = null; - Player dominantPlayer = null; - // Adjust the TNT location based on its velocity to make it closer to the firing point. - int ticks = 1; - Location correctedLocation = tnt.getLocation().clone().add(tnt.getVelocity().clone().multiply(-ticks)); - - for (DirectorData data : directorDataSet) { - if (data.getSelectedSigns().isEmpty() || getLocations(data).isEmpty()) { - dominantPlayer = data.getPlayer(); + for (DirectorData data : craftDirectors) { + if (data.getSelectedNodes().isEmpty()) { + player = data.getPlayer(); } } - if (dominantPlayer != null) { - player = dominantPlayer; - } else { - for (DirectorData data : directorDataSet) { - HashSet locations = getLocations(data); - for (Location location : locations) { - int distX = Math.abs(location.getBlockX() - correctedLocation.getBlockX()); - int distY = Math.abs(location.getBlockY() - correctedLocation.getBlockY()); - int distZ = Math.abs(location.getBlockZ() - correctedLocation.getBlockZ()); - - if (distX <= CannonDirectorNodeDistance && distY <= CannonDirectorNodeDistance && distZ <= CannonDirectorNodeDistance) { - player = data.getPlayer(); - break; - } - } - if (player != null) { - break; - } - } + if (player == null) { + player = getClosestDirectorFromProjectile( + craftDirectors, + correctedPosition, + CannonDirectorNodeDistance + ); } if (player == null || player.getInventory().getItemInMainHand().getType() != Directors.DirectorTool) return; MovecraftLocation midpoint = c.getHitBox().getMidPoint(); - int distX = Math.abs(midpoint.getX() - correctedLocation.getBlockX()); - int distY = Math.abs(midpoint.getY() - correctedLocation.getBlockY()); - int distZ = Math.abs(midpoint.getZ() - correctedLocation.getBlockZ()); - if (distX >= CannonDirectorDistance || distY >= CannonDirectorDistance || distZ >= CannonDirectorDistance) + int distX = Math.abs(midpoint.getX() - correctedPosition.getBlockX()); + int distY = Math.abs(midpoint.getY() - correctedPosition.getBlockY()); + int distZ = Math.abs(midpoint.getZ() - correctedPosition.getBlockZ()); + if (distX*distX + distY*distY + distZ*distZ >= CannonDirectorDistance*CannonDirectorDistance) return; // Store the speed to add it back in later, since all the values we will be using are "normalized", IE: have a speed of 1 @@ -243,14 +229,15 @@ public final void onSignClick(@NotNull PlayerInteractEvent e) { return; } - clearDirector(p); - DirectorData data = addDirector(p, foundCraft, sign.getLine(1), sign.getLine(2), sign.getLine(3)); - - if (isNodesShared(data)) { + Set selectedLines = processSign(sign); + if (isNodesShared(selectedLines, foundCraft, p)) { p.sendMessage(ERROR_PREFIX + " " + I18nSupport.getInternationalisedString("CannonDirector - Must Not Share Nodes")); return; } + clearDirector(p); + addDirector(p, foundCraft, selectedLines); + p.sendMessage(I18nSupport.getInternationalisedString("CannonDirector - Directing")); } diff --git a/src/main/java/net/countercraft/movecraft/combat/features/directors/DirectorData.java b/src/main/java/net/countercraft/movecraft/combat/features/directors/DirectorData.java index a1f41530..e0bb8fcd 100644 --- a/src/main/java/net/countercraft/movecraft/combat/features/directors/DirectorData.java +++ b/src/main/java/net/countercraft/movecraft/combat/features/directors/DirectorData.java @@ -1,29 +1,71 @@ package net.countercraft.movecraft.combat.features.directors; + +import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.craft.PlayerCraft; +import org.bukkit.block.Block; +import org.bukkit.block.Sign; import org.bukkit.entity.Player; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; -import java.util.List; +import java.util.HashSet; +import java.util.Set; public class DirectorData { - private Player player; - private PlayerCraft craft; - private List selectedSigns; + private final Player player; + private final PlayerCraft craft; + private final Set selectedNodes; + private Set signLocations = new HashSet<>(); + private MovecraftLocation currentLocation; - public DirectorData(Player player, PlayerCraft craft, List selectedSigns) { + public DirectorData(Player player, PlayerCraft craft, Set selectedNodes) { this.player = player; this.craft = craft; - this.selectedSigns = selectedSigns; + this.selectedNodes = selectedNodes; + } + + @NotNull + public Set getSignLocations() { + if (selectedNodes.isEmpty()) return signLocations; + //If the craft stays in the same position, return the already known sign locations. + MovecraftLocation midpoint = craft.getHitBox().getMidPoint(); + if (currentLocation == null) currentLocation = midpoint; + if (currentLocation.equals(midpoint) && !signLocations.isEmpty()) { + return signLocations; + } + + currentLocation = midpoint; + for (MovecraftLocation location : craft.getHitBox()) { + Block block = craft.getWorld().getBlockAt( + location.getX(), + location.getY(), + location.getZ() + ); + if (!(block.getState() instanceof Sign)) continue; + Sign sign = (Sign) block.getState(); + + if (!sign.getLine(0).equalsIgnoreCase("subcraft rotate")) continue; + if (sign.getLine(3).isBlank()) continue; + if (!selectedNodes.contains(sign.getLine(3))) continue; + + Vector relativeVector = sign.getLocation().toVector(); + signLocations.add(relativeVector); + } + return signLocations; } + @NotNull public Player getPlayer() { return player; } + @NotNull public PlayerCraft getCraft() { return craft; } - public List getSelectedSigns() { - return selectedSigns; + @NotNull + public Set getSelectedNodes() { + return selectedNodes; } } \ No newline at end of file diff --git a/src/main/java/net/countercraft/movecraft/combat/features/directors/Directors.java b/src/main/java/net/countercraft/movecraft/combat/features/directors/Directors.java index 872d7e0b..fd6b7042 100644 --- a/src/main/java/net/countercraft/movecraft/combat/features/directors/Directors.java +++ b/src/main/java/net/countercraft/movecraft/combat/features/directors/Directors.java @@ -1,25 +1,19 @@ package net.countercraft.movecraft.combat.features.directors; -import com.google.common.collect.HashBiMap; -import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.combat.MovecraftCombat; import net.countercraft.movecraft.craft.PlayerCraft; import net.countercraft.movecraft.util.Tags; -import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.block.Block; import org.bukkit.block.Sign; -import org.bukkit.block.data.type.WallSign; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; @@ -68,29 +62,23 @@ public void run() { } - public DirectorData addDirector(Player player, PlayerCraft craft, String line1, String line2, String line3) { + public void addDirector(Player player, PlayerCraft craft, Set selectedLines) { if (directors.containsValue(player)) directors.remove(player); - List selectedLines = new ArrayList<>(); - selectedLines.add(line1); - selectedLines.add(line2); - selectedLines.add(line3); - if (line1.isBlank() && line2.isBlank() && line3.isBlank()) selectedLines.clear(); DirectorData data = new DirectorData(player, craft, selectedLines); directors.put(player, data); - System.out.println("New director added: " + directors.get(player).getSelectedSigns()); - System.out.println("Director name: " + directors.get(player).getPlayer()); - return data; } - public HashSet getDirectorDataSet(PlayerCraft craft) { + @NotNull + public HashSet getCraftDirectors(@NotNull PlayerCraft craft) { HashSet directorDataSet = new HashSet<>(); - for (DirectorData data : directors.values()) { - if (data.getCraft() == craft) directorDataSet.add(data); + for (DirectorData directorData : directors.values()) { + if (directorData.getCraft() == craft) directorDataSet.add(directorData); } return directorDataSet; } - public boolean hasDirector(PlayerCraft craft) { + + public boolean hasDirector(@Nullable PlayerCraft craft) { if (craft == null) return false; for (DirectorData data : directors.values()) { if (data.getCraft() == craft) return true; @@ -98,12 +86,46 @@ public boolean hasDirector(PlayerCraft craft) { return false; } - public boolean isNodesShared(DirectorData director) { - PlayerCraft craft = director.getCraft(); - List selectedSigns = director.getSelectedSigns(); - return directors.values().stream() - .filter(data -> data != director && data.getCraft() == craft) - .anyMatch(data -> data.getSelectedSigns().stream().anyMatch(selectedSigns::contains)); + //This ensures that no two director nodes are shared between the director players. + public boolean isNodesShared(Set selectedStrings, PlayerCraft craft, Player player) { + for (DirectorData directorData : getCraftDirectors(craft)) { + if (directorData.getPlayer() == player) continue; + if (selectedStrings.isEmpty()) return false; + Set stringsCopy = new HashSet<>(selectedStrings); + stringsCopy.retainAll(directorData.getSelectedNodes()); + if (!stringsCopy.isEmpty()) return true; + } + return false; + } + + @NotNull + public Set processSign(Sign sign) { + String[] lines = sign.getLines(); + Set selectedLines = new HashSet<>(); + + for (int i = 1; i < lines.length ; i++) { + String line = lines[i].trim(); + if (!line.isBlank()) selectedLines.add(line); + } + + return selectedLines; + } + + @Nullable + public Player getClosestDirectorFromProjectile( + Set directorDataSet, + Vector projectile, + int nodeDistance + ) { + for (DirectorData directorData : directorDataSet) { + for (Vector signLocation : directorData.getSignLocations()) { + // Calculate squared distance. + if (signLocation.distanceSquared(projectile) <= (nodeDistance * nodeDistance)) { + return directorData.getPlayer(); + } + } + } + return null; } public boolean isDirector(@NotNull Player player) { @@ -114,37 +136,9 @@ public void removeDirector(@NotNull Player player) { directors.remove(player); } + //This clears all DirectorData that might be already assigned to the player. public void clearDirector(@NotNull Player player) { for (var instance : instances) instance.removeDirector(player); } - - public HashSet getLocations(DirectorData data) { - if (data.getSelectedSigns().isEmpty() || data.getCraft() == null) { - return null; - } - PlayerCraft craft = data.getCraft(); - - HashSet locations = new HashSet<>(); - for (MovecraftLocation location : craft.getHitBox()) { - Block block = craft.getWorld().getBlockAt(location.getX(), location.getY(), location.getZ()); - if (!(block.getState() instanceof Sign)) - continue; - - Sign sign = (Sign) block.getState(); - - if (!sign.getLine(0).equalsIgnoreCase("subcraft rotate")) { - continue; - } - if (sign.getLine(3).isBlank()) { - System.out.println("Sign is blank"); - continue; - } - if (data.getSelectedSigns().contains(sign.getLine(3))) { - System.out.println("Sign found."); - locations.add(block.getLocation()); - } - } - return locations; - } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 1bc53291..27f7e2db 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -5,7 +5,7 @@ Locale: "en" # Language file to load, currently the plugin comes with en and no, # AA Directors AADirectorDistance: 50 # Max range at which fireballs will be redirected -AADirectorNodeDistance: # See node directors +AADirectorNodeDistance: 3 # See node directors AADirectorRange: 120 # Max range at which it will direct to a block vs in the general direction # Cannon Directors diff --git a/src/main/resources/localisation/mcclang_en.properties b/src/main/resources/localisation/mcclang_en.properties index 3cfbad1a..29d037eb 100644 --- a/src/main/resources/localisation/mcclang_en.properties +++ b/src/main/resources/localisation/mcclang_en.properties @@ -1,11 +1,13 @@ AADirector\ -\ Directing=You are now directing the AA of this craft AADirector\ -\ No\ Longer\ Directing=You are no longer directing the AA of this craft AADirector\ -\ Not\ Allowed\ On\ Craft=AA Director signs are not allowed on this type of craft +AADirector\ -\ Must\ Not\ Share\ Nodes=You must not share nodes with other AA directors Combat\ Release=Combat Release\! Combat\ Release\ Message=Combat releasing is not allowed\! CannonDirector\ -\ Directing=You are now directing the cannons of this craft CannonDirector\ -\ No\ Longer\ Directing=You are no longer directing the cannons of this craft CannonDirector\ -\ Not\ Allowed\ On\ Craft=Cannon Director signs are not allowed on this type of craft +CannonDirector\ -\ Must\ Not\ Share\ Nodes=You must not share nodes with other cannon directors Command\ -\ Must\ Be\ Player=You must be a player to use that command. Command\ -\ Current\ Mode=Current mode Command\ -\ Current\ Setting=Current setting