diff --git a/src/main/java/com/rsscripting/rstaxi/commands/CabCommand.java b/src/main/java/com/rsscripting/rstaxi/commands/CabCommand.java index 443dbf5..644d39f 100644 --- a/src/main/java/com/rsscripting/rstaxi/commands/CabCommand.java +++ b/src/main/java/com/rsscripting/rstaxi/commands/CabCommand.java @@ -5,6 +5,9 @@ import com.rsscripting.rstaxi.RSTaxi; import com.rsscripting.rstaxi.platform.PlatformValidator; import com.rsscripting.rstaxi.stops.StopManager; import com.rsscripting.rstaxi.integrations.BlueMapManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.format.NamedTextColor; import java.sql.SQLException; import java.util.Map; import org.bukkit.command.Command; @@ -55,7 +58,7 @@ public final class CabCommand implements CommandExecutor { return handleRemove(sender, args); } case "list" -> { - return handleList(sender); + return openList(sender); } case "search" -> { return searchCommand.execute(sender, args); @@ -66,7 +69,6 @@ public final class CabCommand implements CommandExecutor { } } - private boolean handleTravel( CommandSender sender, String[] args @@ -88,7 +90,7 @@ public final class CabCommand implements CommandExecutor { } if (args.length == 0) { - sender.sendMessage( + player.sendMessage( plugin.getLanguageManager() .getMessage("general.invalid-usage") ); @@ -96,10 +98,22 @@ public final class CabCommand implements CommandExecutor { } String name = String.join(" ", args).trim(); + boolean allowCrossWorld = plugin.getConfig() + .getBoolean("allow-cross-world", true); try { - StopManager.StopLocation stop = - stopManager.getStopLocation(name); + StopManager.StopLocation stop; + + if (allowCrossWorld && name.contains(":")) { + int separator = name.indexOf(':'); + String worldName = name.substring(0, separator).trim(); + String stopName = name.substring(separator + 1).trim(); + + stop = stopManager.getStopLocation(stopName, worldName); + name = stopName; + } else { + stop = stopManager.getStopLocation(name); + } if (stop == null) { player.sendMessage( @@ -111,6 +125,15 @@ public final class CabCommand implements CommandExecutor { return true; } + if (!allowCrossWorld + && !player.getWorld().getName().equals(stop.world())) { + player.sendMessage( + plugin.getLanguageManager() + .getMessage("general.stop-in-another-world") + ); + return true; + } + World world = Bukkit.getWorld(stop.world()); if (world == null) { @@ -141,7 +164,12 @@ public final class CabCommand implements CommandExecutor { player.sendMessage( plugin.getLanguageManager().getMessage( "teleport.success", - Map.of("stop", stop.name()) + Map.of( + "stop", + allowCrossWorld + ? stop.world() + ":" + stop.name() + : stop.name() + ) ) ); @@ -341,9 +369,7 @@ public final class CabCommand implements CommandExecutor { return true; } - - - private boolean handleList(CommandSender sender) { + public boolean openList(CommandSender sender) { if (!sender.hasPermission("rs-cab.use")) { sender.sendMessage( plugin.getLanguageManager() @@ -352,35 +378,55 @@ public final class CabCommand implements CommandExecutor { return true; } + if (!(sender instanceof Player player)) { + sender.sendMessage( + plugin.getLanguageManager() + .getMessage("general.player-only") + ); + return true; + } + try { var stops = stopManager.getAllStops(); + boolean allowCrossWorld = plugin.getConfig() + .getBoolean("allow-cross-world", true); + + if (!allowCrossWorld) { + String currentWorld = player.getWorld().getName(); + + stops = stops.stream() + .filter(stop -> stop.world().equals(currentWorld)) + .toList(); + } if (stops.isEmpty()) { - sender.sendMessage( + player.sendMessage( plugin.getLanguageManager() .getMessage("general.no-stops") ); return true; } - sender.sendMessage( + player.sendMessage( plugin.getLanguageManager() .getMessage("list.header") ); for (StopManager.StopEntry stop : stops) { - sender.sendMessage( - plugin.getLanguageManager() - .getMessage( - "list.entry", - Map.of( - "icon", stop.icon(), - "stop", stop.name() - ) - ) - ); - } + String displayName = allowCrossWorld + ? stop.world() + ":" + stop.name() + : stop.name(); + String command = "/cab " + stop.name(); + + Component clickableStop = Component.text(displayName) + .color(NamedTextColor.WHITE) + .clickEvent(ClickEvent.runCommand(command)) + .hoverEvent(net.kyori.adventure.text.event.HoverEvent + .showText(Component.text("Click to teleport"))); + + player.sendMessage(clickableStop); + } } catch (SQLException e) { plugin.getLogger().log( @@ -389,17 +435,15 @@ public final class CabCommand implements CommandExecutor { e ); - sender.sendMessage( + player.sendMessage( plugin.getLanguageManager() .getMessage("list.error") ); } - return true; } - private boolean checkPermission( CommandSender sender, String permission diff --git a/src/main/java/com/rsscripting/rstaxi/commands/CabSearchCommand.java b/src/main/java/com/rsscripting/rstaxi/commands/CabSearchCommand.java index b05db37..ccdc6ac 100644 --- a/src/main/java/com/rsscripting/rstaxi/commands/CabSearchCommand.java +++ b/src/main/java/com/rsscripting/rstaxi/commands/CabSearchCommand.java @@ -4,9 +4,12 @@ package com.rsscripting.rstaxi.commands; import com.rsscripting.rstaxi.RSTaxi; import com.rsscripting.rstaxi.stops.StopManager; import java.sql.SQLException; -import java.util.Map; import java.util.Locale; import org.bukkit.command.CommandSender; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; public final class CabSearchCommand { @@ -49,6 +52,17 @@ public final class CabSearchCommand { ? stopManager.searchByIcon(value) : stopManager.searchByName(value); + boolean allowCrossWorld = plugin.getConfig() + .getBoolean("allow-cross-world", true); + + if (!allowCrossWorld && sender instanceof Player player) { + String currentWorld = player.getWorld().getName(); + + stops = stops.stream() + .filter(stop -> stop.world().equals(currentWorld)) + .toList(); + } + if (stops.isEmpty()) { sender.sendMessage( plugin.getLanguageManager() @@ -63,15 +77,23 @@ public final class CabSearchCommand { ); for (StopManager.StopEntry stop : stops) { - sender.sendMessage( - plugin.getLanguageManager().getMessage( - "list.entry", - Map.of( - "icon", stop.icon(), - "stop", stop.name() - ) - ) - ); + String displayName = allowCrossWorld + ? stop.world() + ":" + stop.name() + : stop.name(); + + if (sender instanceof Player) { + Component clickableStop = Component.text(displayName) + .color(NamedTextColor.WHITE) + .clickEvent(ClickEvent.runCommand("/cab " + stop.name())) + .hoverEvent( + net.kyori.adventure.text.event.HoverEvent + .showText(Component.text("Click to teleport")) + ); + + sender.sendMessage(clickableStop); + } else { + sender.sendMessage(displayName); + } } } catch (SQLException e) { plugin.getLogger().log( diff --git a/src/main/java/com/rsscripting/rstaxi/commands/CabTabCompleter.java b/src/main/java/com/rsscripting/rstaxi/commands/CabTabCompleter.java index 4719369..d2cd05d 100644 --- a/src/main/java/com/rsscripting/rstaxi/commands/CabTabCompleter.java +++ b/src/main/java/com/rsscripting/rstaxi/commands/CabTabCompleter.java @@ -40,11 +40,26 @@ public final class CabTabCompleter implements TabCompleter { } String input = args[0].toLowerCase(Locale.ROOT); + boolean allowCrossWorld = plugin.getConfig() + .getBoolean("allow-cross-world", true); + + String currentWorld = sender instanceof org.bukkit.entity.Player player + ? player.getWorld().getName() + : null; for (StopManager.StopEntry stop : getSortedStops()) { - if (stop.name().toLowerCase(Locale.ROOT) - .startsWith(input)) { - suggestions.add(stop.name()); + if (!allowCrossWorld + && currentWorld != null + && !stop.world().equals(currentWorld)) { + continue; + } + + String suggestion = allowCrossWorld + ? stop.world() + ":" + stop.name() + : stop.name(); + + if (suggestion.toLowerCase(Locale.ROOT).startsWith(input)) { + suggestions.add(suggestion); } } diff --git a/src/main/java/com/rsscripting/rstaxi/platform/PlatformProtectionListener.java b/src/main/java/com/rsscripting/rstaxi/platform/PlatformProtectionListener.java index 01f69e5..8283991 100644 --- a/src/main/java/com/rsscripting/rstaxi/platform/PlatformProtectionListener.java +++ b/src/main/java/com/rsscripting/rstaxi/platform/PlatformProtectionListener.java @@ -7,6 +7,10 @@ import org.bukkit.block.Block; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; +import com.rsscripting.rstaxi.commands.CabCommand; +import org.bukkit.entity.Player; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; import java.util.Map; @@ -29,6 +33,38 @@ public final class PlatformProtectionListener implements Listener { this.plugin = plugin; } + @EventHandler + public void onPlatformInteract(PlayerInteractEvent event) { + if (event.getAction() != Action.RIGHT_CLICK_BLOCK) { + return; + } + + Player player = event.getPlayer(); + + if (!player.isSneaking()) { + return; + } + + if (!plugin.getConfig().getBoolean("platform.enabled", true) + || !plugin.getConfig().getBoolean( + "platform.sneak-rightclick-platform", false)) { + return; + } + + Block clicked = event.getClickedBlock(); + + if (clicked == null + || clicked.getType() != getMaterial("platform.target-block") + || !hasRequiredSurroundings(clicked)) { + return; + } + + event.setCancelled(true); + + CabCommand cabCommand = new CabCommand(plugin); + cabCommand.openList(player); + } + @EventHandler public void onBlockBreak(BlockBreakEvent event) { diff --git a/src/main/java/com/rsscripting/rstaxi/stops/StopManager.java b/src/main/java/com/rsscripting/rstaxi/stops/StopManager.java index 370df48..2ba74fd 100644 --- a/src/main/java/com/rsscripting/rstaxi/stops/StopManager.java +++ b/src/main/java/com/rsscripting/rstaxi/stops/StopManager.java @@ -19,8 +19,11 @@ public final class StopManager { this.plugin = plugin; } - public record StopEntry(String name, String icon) { - } + public record StopEntry( + String name, + String icon, + String world + ) {} public record StopLocation( String name, @@ -34,6 +37,40 @@ public final class StopManager { ) { } + public StopLocation getStopLocation(String name, String world) + throws SQLException { + + String sql = """ + SELECT name, icon, world, x, y, z, yaw, pitch + FROM stops + WHERE name = ? AND world = ? + """; + + try (PreparedStatement statement = connection() + .prepareStatement(sql)) { + + statement.setString(1, name); + statement.setString(2, world); + + try (ResultSet results = statement.executeQuery()) { + if (!results.next()) { + return null; + } + + return new StopLocation( + results.getString("name"), + results.getString("icon"), + results.getString("world"), + results.getDouble("x"), + results.getDouble("y"), + results.getDouble("z"), + results.getFloat("yaw"), + results.getFloat("pitch") + ); + } + } + } + public boolean exists(String name) throws SQLException { String sql = "SELECT 1 FROM stops WHERE name = ?"; @@ -126,7 +163,7 @@ public final class StopManager { public List getAllStops() throws SQLException { String sql = """ - SELECT name, icon + SELECT name, icon, world FROM stops ORDER BY name COLLATE NOCASE """; @@ -140,7 +177,8 @@ public final class StopManager { while (results.next()) { stops.add(new StopEntry( results.getString("name"), - results.getString("icon") + results.getString("icon"), + results.getString("world") )); } } @@ -153,9 +191,9 @@ public final class StopManager { throws SQLException { String sql = """ - SELECT name, icon + SELECT name, icon, world FROM stops - WHERE name LIKE ? ESCAPE '\\' + WHERE LOWER(name) LIKE LOWER(?) ORDER BY name COLLATE NOCASE """; @@ -175,7 +213,8 @@ public final class StopManager { while (results.next()) { stops.add(new StopEntry( results.getString("name"), - results.getString("icon") + results.getString("icon"), + results.getString("world") )); } } @@ -188,9 +227,9 @@ public final class StopManager { throws SQLException { String sql = """ - SELECT name, icon + SELECT name, icon, world FROM stops - WHERE icon = ? + WHERE LOWER(icon) = LOWER(?) ORDER BY name COLLATE NOCASE """; @@ -205,7 +244,8 @@ public final class StopManager { while (results.next()) { stops.add(new StopEntry( results.getString("name"), - results.getString("icon") + results.getString("icon"), + results.getString("world") )); } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 7d6e348..93b1c99 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -7,6 +7,11 @@ # Example: en_us, de_de, fr_fr language: "en_us" +# Allow players to travel between different worlds. +# true: Players can travel to stops in any world. +# false: Players can only travel to stops in their current world. +allow-cross-world: true + # Platform Settings. platform: # Determines wether platforms are required before adding a destination @@ -22,6 +27,12 @@ platform: # false: platforms can be broken. protect-platforms: true + # Allow players to sneak + right-click the center block + # of a valid 3x3 taxi platform to open a clickable list of + # taxi stops. + # Requires platform.enabled to be true. + sneak-rightclick-platform: false + #Layout requirement for add a destination if enabled is set to true. layout: north: "OAK_PLANKS" diff --git a/src/main/resources/language/en_us.yml b/src/main/resources/language/en_us.yml index 4311325..e9d7730 100644 --- a/src/main/resources/language/en_us.yml +++ b/src/main/resources/language/en_us.yml @@ -8,6 +8,7 @@ general: invalid-usage: "&cInvalid command usage." unknown-stop: "&cThe stop &e%stop% &cdoes not exist." no-stops: "&eNo taxi stops have been created yet." + stop-in-another-world: "&cStop is in another world, you need to enter that world first." database: connection-success: "&aDatabase connected successfully." @@ -32,7 +33,7 @@ confirmation: list: header: "&6Available Taxi Destinations:" - entry: "&e%icon% &f%stop%" + entry: "&f%stop%" error: "&cUnable to retrieve taxi destinations. Check the server logs." platform: diff --git a/target/RS-Taxi-0.1.0.jar b/target/RS-Taxi-0.1.0.jar index a2b0c2b..1cbae78 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/commands/CabCommand.class b/target/classes/com/rsscripting/rstaxi/commands/CabCommand.class index 8883445..e395122 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/commands/CabSearchCommand.class b/target/classes/com/rsscripting/rstaxi/commands/CabSearchCommand.class index 5295bc9..e501a6a 100644 Binary files a/target/classes/com/rsscripting/rstaxi/commands/CabSearchCommand.class and b/target/classes/com/rsscripting/rstaxi/commands/CabSearchCommand.class differ diff --git a/target/classes/com/rsscripting/rstaxi/commands/CabTabCompleter.class b/target/classes/com/rsscripting/rstaxi/commands/CabTabCompleter.class index 33707b5..e0c8e10 100644 Binary files a/target/classes/com/rsscripting/rstaxi/commands/CabTabCompleter.class and b/target/classes/com/rsscripting/rstaxi/commands/CabTabCompleter.class differ diff --git a/target/classes/com/rsscripting/rstaxi/platform/PlatformProtectionListener.class b/target/classes/com/rsscripting/rstaxi/platform/PlatformProtectionListener.class index 0d655b4..76eca77 100644 Binary files a/target/classes/com/rsscripting/rstaxi/platform/PlatformProtectionListener.class and b/target/classes/com/rsscripting/rstaxi/platform/PlatformProtectionListener.class differ diff --git a/target/classes/com/rsscripting/rstaxi/stops/StopManager$StopEntry.class b/target/classes/com/rsscripting/rstaxi/stops/StopManager$StopEntry.class index ffdb237..da4da1d 100644 Binary files a/target/classes/com/rsscripting/rstaxi/stops/StopManager$StopEntry.class and b/target/classes/com/rsscripting/rstaxi/stops/StopManager$StopEntry.class differ diff --git a/target/classes/com/rsscripting/rstaxi/stops/StopManager$StopLocation.class b/target/classes/com/rsscripting/rstaxi/stops/StopManager$StopLocation.class index 23e3397..d8fd62d 100644 Binary files a/target/classes/com/rsscripting/rstaxi/stops/StopManager$StopLocation.class and b/target/classes/com/rsscripting/rstaxi/stops/StopManager$StopLocation.class differ diff --git a/target/classes/com/rsscripting/rstaxi/stops/StopManager.class b/target/classes/com/rsscripting/rstaxi/stops/StopManager.class index bc80969..5883767 100644 Binary files a/target/classes/com/rsscripting/rstaxi/stops/StopManager.class and b/target/classes/com/rsscripting/rstaxi/stops/StopManager.class differ