diff --git a/src/main/java/com/rsscripting/rstaxi/RSTaxi.java b/src/main/java/com/rsscripting/rstaxi/RSTaxi.java index ed9ad81..d15fc93 100644 --- a/src/main/java/com/rsscripting/rstaxi/RSTaxi.java +++ b/src/main/java/com/rsscripting/rstaxi/RSTaxi.java @@ -6,6 +6,7 @@ import com.rsscripting.rstaxi.commands.CabTabCompleter; import com.rsscripting.rstaxi.language.LanguageManager; import com.rsscripting.rstaxi.database.DatabaseManager; import com.rsscripting.rstaxi.integrations.BlueMapManager; +import com.rsscripting.rstaxi.platform.PlatformProtectionListener; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.Bukkit; @@ -45,6 +46,9 @@ public final class RSTaxi extends JavaPlugin { return; } + getServer().getPluginManager().registerEvents( + new PlatformProtectionListener(this), this); + getCommand("cab").setExecutor(new CabCommand(this)); getCommand("cab").setTabCompleter(new CabTabCompleter(this)); diff --git a/src/main/java/com/rsscripting/rstaxi/commands/CabCommand.java b/src/main/java/com/rsscripting/rstaxi/commands/CabCommand.java index 14297b1..443dbf5 100644 --- a/src/main/java/com/rsscripting/rstaxi/commands/CabCommand.java +++ b/src/main/java/com/rsscripting/rstaxi/commands/CabCommand.java @@ -192,8 +192,13 @@ public final class CabCommand implements CommandExecutor { return true; } - name = arguments.substring(1, closingQuote); + name = arguments.substring(1, closingQuote).trim(); icon = arguments.substring(closingQuote + 1).trim(); + + if (icon.startsWith("'") || icon.startsWith("\"")) { + icon = icon.substring(1).trim(); + } + } else { String[] parts = arguments.split("\\s+"); diff --git a/src/main/java/com/rsscripting/rstaxi/commands/CabTabCompleter.java b/src/main/java/com/rsscripting/rstaxi/commands/CabTabCompleter.java index e9b5333..4719369 100644 --- a/src/main/java/com/rsscripting/rstaxi/commands/CabTabCompleter.java +++ b/src/main/java/com/rsscripting/rstaxi/commands/CabTabCompleter.java @@ -51,6 +51,59 @@ public final class CabTabCompleter implements TabCompleter { return suggestions; } + + // /cab add + if (args[0].equalsIgnoreCase("add")) { + if (!sender.hasPermission("rs-cab.add")) { + return suggestions; + } + + int iconIndex = 2; + + // Detect a quoted destination that contains spaces. + if (args.length >= 2 + && (args[1].startsWith("'") + || args[1].startsWith("\""))) { + + char quote = args[1].charAt(0); + int closingIndex = -1; + + for (int i = 1; i < args.length; i++) { + int quotePosition = args[i].lastIndexOf(quote); + + // Ignore the opening quote at the beginning of the destination. + if (quotePosition > 0) { + closingIndex = i; + break; + } + } + + // Destination is not finished yet. + if (closingIndex == -1) { + return suggestions; + } + + iconIndex = closingIndex + 1; + } + + // Only suggest icons when the cursor is in the icon argument. + if (args.length != iconIndex + 1) { + return suggestions; + } + + String input = args[iconIndex].toLowerCase(Locale.ROOT); + + for (String icon : + plugin.getBlueMapManager().getAvailableIcons()) { + if (icon.toLowerCase(Locale.ROOT).startsWith(input)) { + suggestions.add(icon); + } + } + + return suggestions; + } + + // /cab remove if (args[0].equalsIgnoreCase("remove")) { if (!sender.hasPermission("rs-cab.delete")) { diff --git a/src/main/java/com/rsscripting/rstaxi/integrations/BlueMapManager.java b/src/main/java/com/rsscripting/rstaxi/integrations/BlueMapManager.java index e47fdb3..dc2991c 100644 --- a/src/main/java/com/rsscripting/rstaxi/integrations/BlueMapManager.java +++ b/src/main/java/com/rsscripting/rstaxi/integrations/BlueMapManager.java @@ -12,6 +12,14 @@ import java.nio.charset.StandardCharsets; import java.sql.SQLException; import java.util.Locale; import java.util.UUID; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; public final class BlueMapManager { @@ -85,6 +93,7 @@ public final class BlueMapManager { stop.y(), stop.z() ) + .icon(stop.icon(), 8, 8) .build(); markerSet.getMarkers().put(markerId, marker); @@ -161,6 +170,7 @@ public final class BlueMapManager { stop.y(), stop.z() ) + .icon(stop.icon(), 8, 8) .build(); markerSet.getMarkers().put(markerId, marker); @@ -205,4 +215,51 @@ public final class BlueMapManager { }); } + + public List getAvailableIcons() { + Set supportedExtensions = Set.of( + ".png", ".jpg", ".jpeg", ".svg", ".webp", ".gif" + ); + + return BlueMapAPI.getInstance() + .map(api -> { + Path assetsDirectory = api.getWebApp() + .getWebRoot() + .resolve("assets"); + + if (!Files.isDirectory(assetsDirectory)) { + return List.of(); + } + + try (Stream paths = Files.walk(assetsDirectory)) { + return paths + .filter(Files::isRegularFile) + .filter(path -> { + String fileName = path.getFileName() + .toString() + .toLowerCase(Locale.ROOT); + + return supportedExtensions.stream() + .anyMatch(fileName::endsWith); + }) + .map(path -> api.getWebApp() + .getWebRoot() + .relativize(path) + .toString() + .replace('\\', '/')) + .sorted(String.CASE_INSENSITIVE_ORDER) + .toList(); + + } catch (IOException e) { + plugin.getLogger().warning( + "Could not scan BlueMap assets: " + + e.getMessage() + ); + return List.of(); + } + }) + .orElseGet(List::of); + } + + } diff --git a/src/main/java/com/rsscripting/rstaxi/platform/PlatformProtectionListener.java b/src/main/java/com/rsscripting/rstaxi/platform/PlatformProtectionListener.java new file mode 100644 index 0000000..01f69e5 --- /dev/null +++ b/src/main/java/com/rsscripting/rstaxi/platform/PlatformProtectionListener.java @@ -0,0 +1,104 @@ + +package com.rsscripting.rstaxi.platform; + +import com.rsscripting.rstaxi.RSTaxi; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; + +import java.util.Map; + +public final class PlatformProtectionListener implements Listener { + + private final RSTaxi plugin; + + private static final Map OFFSETS = Map.of( + "north", new int[]{0, -1}, + "northeast", new int[]{1, -1}, + "east", new int[]{1, 0}, + "southeast", new int[]{1, 1}, + "south", new int[]{0, 1}, + "southwest", new int[]{-1, 1}, + "west", new int[]{-1, 0}, + "northwest", new int[]{-1, -1} + ); + + public PlatformProtectionListener(RSTaxi plugin) { + this.plugin = plugin; + } + + @EventHandler + public void onBlockBreak(BlockBreakEvent event) { + + if (!plugin.getConfig().getBoolean( + "platform.protect-platforms", true)) { + return; + } + + Block block = event.getBlock(); + + if (isPlatformBlock(block)) { + event.setCancelled(true); + } + } + + private boolean isPlatformBlock(Block block) { + + Material target = getMaterial("platform.target-block"); + + // Is this the center target block? + if (block.getType() == target + && hasRequiredSurroundings(block)) { + return true; + } + + // Could this block be one of the eight surrounding blocks? + for (int[] offset : OFFSETS.values()) { + + Block possibleCenter = block.getRelative( + -offset[0], 0, -offset[1]); + + if (possibleCenter.getType() == target + && hasRequiredSurroundings(possibleCenter)) { + return true; + } + } + + return false; + } + + private boolean hasRequiredSurroundings(Block center) { + + for (Map.Entry entry : OFFSETS.entrySet()) { + + Material required = getMaterial( + "platform.layout." + entry.getKey()); + + int[] offset = entry.getValue(); + + Block surrounding = center.getRelative( + offset[0], 0, offset[1]); + + if (surrounding.getType() != required) { + return false; + } + } + + return true; + } + + private Material getMaterial(String path) { + + String name = plugin.getConfig().getString(path, ""); + Material material = Material.matchMaterial(name); + + if (material == null || !material.isBlock()) { + throw new IllegalArgumentException( + "Invalid platform material at " + path + ": " + name); + } + + return material; + } +} diff --git a/src/main/java/com/rsscripting/rstaxi/stops/StopManager.java b/src/main/java/com/rsscripting/rstaxi/stops/StopManager.java index a4b9758..370df48 100644 --- a/src/main/java/com/rsscripting/rstaxi/stops/StopManager.java +++ b/src/main/java/com/rsscripting/rstaxi/stops/StopManager.java @@ -24,6 +24,7 @@ public final class StopManager { public record StopLocation( String name, + String icon, String world, double x, double y, @@ -52,7 +53,7 @@ public final class StopManager { throws SQLException { String sql = """ - SELECT name, world, x, y, z, yaw, pitch + SELECT name, icon, world, x, y, z, yaw, pitch FROM stops WHERE name = ? """; @@ -69,6 +70,7 @@ public final class StopManager { return new StopLocation( results.getString("name"), + results.getString("icon"), results.getString("world"), results.getDouble("x"), results.getDouble("y"), diff --git a/target/RS-Taxi-0.1.0.jar b/target/RS-Taxi-0.1.0.jar index 31c1c2b..a2b0c2b 100644 Binary files a/target/RS-Taxi-0.1.0.jar and b/target/RS-Taxi-0.1.0.jar differ diff --git a/target/classes/com/rsscripting/rstaxi/RSTaxi.class b/target/classes/com/rsscripting/rstaxi/RSTaxi.class index 3680f7d..b1ba09f 100644 Binary files a/target/classes/com/rsscripting/rstaxi/RSTaxi.class and b/target/classes/com/rsscripting/rstaxi/RSTaxi.class differ diff --git a/target/classes/com/rsscripting/rstaxi/commands/CabCommand.class b/target/classes/com/rsscripting/rstaxi/commands/CabCommand.class index dde157b..8883445 100644 Binary files a/target/classes/com/rsscripting/rstaxi/commands/CabCommand.class and b/target/classes/com/rsscripting/rstaxi/commands/CabCommand.class differ diff --git a/target/classes/com/rsscripting/rstaxi/stops/StopManager.class b/target/classes/com/rsscripting/rstaxi/stops/StopManager.class index 3ba7a4a..bc80969 100644 Binary files a/target/classes/com/rsscripting/rstaxi/stops/StopManager.class and b/target/classes/com/rsscripting/rstaxi/stops/StopManager.class differ diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst index e1e13fc..836df9d 100644 --- a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -8,4 +8,5 @@ com\rsscripting\rstaxi\language\LanguageManager.class com\rsscripting\rstaxi\stops\StopManager.class com\rsscripting\rstaxi\platform\PlatformValidator.class com\rsscripting\rstaxi\RSTaxi.class +com\rsscripting\rstaxi\platform\PlatformProtectionListener.class com\rsscripting\rstaxi\commands\CabTabCompleter.class diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst index 86678f9..ff9a0de 100644 --- a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -4,6 +4,7 @@ C:\Users\russe\IdeaProjects\RS-Taxi\src\main\java\com\rsscripting\rstaxi\command C:\Users\russe\IdeaProjects\RS-Taxi\src\main\java\com\rsscripting\rstaxi\database\DatabaseManager.java C:\Users\russe\IdeaProjects\RS-Taxi\src\main\java\com\rsscripting\rstaxi\integrations\BlueMapManager.java C:\Users\russe\IdeaProjects\RS-Taxi\src\main\java\com\rsscripting\rstaxi\language\LanguageManager.java +C:\Users\russe\IdeaProjects\RS-Taxi\src\main\java\com\rsscripting\rstaxi\platform\PlatformProtectionListener.java C:\Users\russe\IdeaProjects\RS-Taxi\src\main\java\com\rsscripting\rstaxi\platform\PlatformValidator.java C:\Users\russe\IdeaProjects\RS-Taxi\src\main\java\com\rsscripting\rstaxi\RSTaxi.java C:\Users\russe\IdeaProjects\RS-Taxi\src\main\java\com\rsscripting\rstaxi\stops\StopManager.java