Initial Development

- Add Stop Complete
This commit is contained in:
BigPappa committed 2026-10-11 09:03:11 -05:00
commit 3566555893
31 files changed
+1018

No files matched your search

@@ -0,0 +1,72 @@
package com.rsscripting.rstaxi;
import com.rsscripting.rstaxi.commands.CabCommand;
import com.rsscripting.rstaxi.language.LanguageManager;
import com.rsscripting.rstaxi.database.DatabaseManager;
import org.bukkit.plugin.java.JavaPlugin;
public final class RSTaxi extends JavaPlugin {
private LanguageManager languageManager;
private DatabaseManager databaseManager;
@Override
public void onEnable() {
saveDefaultConfig();
if (!new java.io.File(getDataFolder(), "language/en_us.yml").exists()) {
saveResource("language/en_us.yml", false);
}
languageManager = new LanguageManager(this);
languageManager.load();
databaseManager = new DatabaseManager(this);
try {
databaseManager.connect();
databaseManager.initialize();
} catch (java.sql.SQLException e) {
getLogger().severe("Failed to initialize SQLite database!");
getLogger().severe(e.getMessage());
getServer().getPluginManager().disablePlugin(this);
return;
}
if (getCommand("cab") == null) {
getLogger().severe("Command 'cab' is missing from plugin.yml!");
getServer().getPluginManager().disablePlugin(this);
return;
}
getCommand("cab").setExecutor(new CabCommand(this));
getLogger().info("RS-Taxi has been enabled!");
}
@Override
public void onDisable() {
if (databaseManager != null) {
databaseManager.close();
}
getLogger().info("RS-Taxi has been disabled!");
}
public LanguageManager getLanguageManager() {
return languageManager;
}
public DatabaseManager getDatabaseManager() {
return databaseManager;
}
}
@@ -0,0 +1,211 @@
package com.rsscripting.rstaxi.commands;
import com.rsscripting.rstaxi.RSTaxi;
import com.rsscripting.rstaxi.platform.PlatformValidator;
import com.rsscripting.rstaxi.stops.StopManager;
import java.sql.SQLException;
import java.util.Map;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public final class CabCommand implements CommandExecutor {
private final RSTaxi plugin;
private final PlatformValidator platformValidator;
private final StopManager stopManager;
public CabCommand(RSTaxi plugin) {
this.plugin = plugin;
this.platformValidator = new PlatformValidator(plugin);
this.stopManager = new StopManager(plugin);
}
@Override
public boolean onCommand(
CommandSender sender,
Command command,
String label,
String[] args
) {
if (args.length == 0) {
return handleTravel(sender, args);
}
switch (args[0].toLowerCase()) {
case "add" -> {
return handleAdd(sender, args);
}
case "update" -> {
return handleUpdate(sender, args);
}
case "edit" -> {
return handleEdit(sender, args);
}
case "remove" -> {
return handleRemove(sender, args);
}
case "list" -> {
return handleList(sender);
}
default -> {
return handleTravel(sender, args);
}
}
}
private boolean handleTravel(
CommandSender sender,
String[] args
) {
if (!(sender instanceof Player player)) {
sender.sendMessage(
plugin.getLanguageManager()
.getMessage("general.player-only")
);
return true;
}
if (!player.hasPermission("rs-cab.use")) {
player.sendMessage(
plugin.getLanguageManager()
.getMessage("general.no-permission")
);
return true;
}
// Travel behavior will be implemented in Phase 2.
return true;
}
private boolean handleAdd(
CommandSender sender,
String[] args
) {
if (!sender.hasPermission("rs-cab.add")) {
sender.sendMessage(plugin.getLanguageManager()
.getMessage("general.no-permission"));
return true;
}
if (!(sender instanceof Player player)) {
sender.sendMessage(plugin.getLanguageManager()
.getMessage("general.player-only"));
return true;
}
String arguments = String.join(" ", args)
.substring("add".length()).trim();
String name;
String icon;
if (arguments.startsWith("'")) {
int closingQuote = arguments.indexOf('\'', 1);
if (closingQuote < 2) {
sender.sendMessage(plugin.getLanguageManager()
.getMessage("general.invalid-usage"));
return true;
}
name = arguments.substring(1, closingQuote);
icon = arguments.substring(closingQuote + 1).trim();
} else {
String[] parts = arguments.split("\\s+");
if (parts.length != 2) {
sender.sendMessage(plugin.getLanguageManager()
.getMessage("general.invalid-usage"));
return true;
}
name = parts[0];
icon = parts[1];
}
if (name.isBlank() || icon.isBlank()
|| icon.contains(" ")) {
sender.sendMessage(plugin.getLanguageManager()
.getMessage("general.invalid-usage"));
return true;
}
try {
if (stopManager.exists(name)) {
sender.sendMessage(plugin.getLanguageManager()
.getMessage("stop.already-exists",
Map.of("stop", name)));
return true;
}
if (!platformValidator.isValid(player)) {
sender.sendMessage(plugin.getLanguageManager()
.getMessage("platform.invalid"));
return true;
}
if (stopManager.add(name, icon, player.getLocation())) {
sender.sendMessage(plugin.getLanguageManager()
.getMessage("stop.added",
Map.of("stop", name)));
} else {
sender.sendMessage(plugin.getLanguageManager()
.getMessage("stop.already-exists",
Map.of("stop", name)));
}
} catch (SQLException | IllegalArgumentException e) {
plugin.getLogger().severe(
"Failed to create taxi stop: " + e.getMessage()
);
sender.sendMessage(plugin.getLanguageManager()
.getMessage("stop.creation-error"));
}
return true;
}
private boolean handleUpdate(
CommandSender sender,
String[] args
) {
return checkPermission(sender, "rs-cab.edit");
}
private boolean handleEdit(
CommandSender sender,
String[] args
) {
return checkPermission(sender, "rs-cab.edit");
}
private boolean handleRemove(
CommandSender sender,
String[] args
) {
return checkPermission(sender, "rs-cab.delete");
}
private boolean handleList(CommandSender sender) {
return checkPermission(sender, "rs-cab.use");
}
private boolean checkPermission(
CommandSender sender,
String permission
) {
if (!sender.hasPermission(permission)) {
sender.sendMessage(
plugin.getLanguageManager()
.getMessage("general.no-permission")
);
}
return true;
}
}
@@ -0,0 +1,83 @@
package com.rsscripting.rstaxi.database;
import com.rsscripting.rstaxi.RSTaxi;
import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public final class DatabaseManager {
private final RSTaxi plugin;
private Connection connection;
public DatabaseManager(RSTaxi plugin) {
this.plugin = plugin;
}
public void connect() throws SQLException {
File folder = plugin.getDataFolder();
if (!folder.exists() && !folder.mkdirs()) {
throw new SQLException(
"Could not create plugin data folder."
);
}
File databaseFile = new File(folder, "taxi.db");
String url = "jdbc:sqlite:" + databaseFile.getAbsolutePath();
connection = DriverManager.getConnection(url);
plugin.getLogger().info("SQLite database connected.");
}
public void initialize() throws SQLException {
if (connection == null || connection.isClosed()) {
throw new SQLException("Database is not connected.");
}
String sql = """
CREATE TABLE IF NOT EXISTS stops (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL COLLATE NOCASE UNIQUE,
icon TEXT NOT NULL,
world TEXT NOT NULL,
x REAL NOT NULL,
y REAL NOT NULL,
z REAL NOT NULL,
yaw REAL NOT NULL,
pitch REAL NOT NULL
);
""";
try (Statement statement = connection.createStatement()) {
statement.execute(sql);
}
plugin.getLogger().info("SQLite database initialized.");
}
public Connection getConnection() {
return connection;
}
public void close() {
if (connection == null) {
return;
}
try {
connection.close();
plugin.getLogger().info("SQLite database connection closed.");
} catch (SQLException e) {
plugin.getLogger().severe(
"Failed to close SQLite database: "
+ e.getMessage()
);
}
}
}
@@ -0,0 +1,110 @@
package com.rsscripting.rstaxi.language;
import com.rsscripting.rstaxi.RSTaxi;
import org.bukkit.ChatColor;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.util.Map;
public final class LanguageManager {
private final RSTaxi plugin;
private YamlConfiguration language;
private YamlConfiguration english;
public LanguageManager(RSTaxi plugin) {
this.plugin = plugin;
}
public void load() {
File languageFolder =
new File(plugin.getDataFolder(), "language");
if (!languageFolder.exists() && !languageFolder.mkdirs()) {
plugin.getLogger().severe(
"Could not create the language folder."
);
}
File englishFile =
new File(languageFolder, "en_us.yml");
if (!englishFile.exists()) {
plugin.saveResource("language/en_us.yml", false);
}
english = YamlConfiguration.loadConfiguration(englishFile);
String selected = plugin.getConfig()
.getString("language", "en_us")
.trim();
if (!selected.matches("[a-zA-Z0-9_-]+")) {
plugin.getLogger().warning(
"Invalid language setting. Using en_us."
);
selected = "en_us";
}
File selectedFile =
new File(languageFolder, selected + ".yml");
if (!selectedFile.isFile()) {
plugin.getLogger().warning(
"Language file '" + selected
+ ".yml' was not found. Using en_us."
);
language = english;
return;
}
language = YamlConfiguration.loadConfiguration(selectedFile);
plugin.getLogger().info(
"Loaded language: " + selected
);
}
public String getMessage(String path) {
return getMessage(path, Map.of());
}
public String getMessage(
String path,
Map<String, String> placeholders
) {
String message = language == null
? null
: language.getString(path);
if (message == null && english != null) {
message = english.getString(path);
}
if (message == null) {
plugin.getLogger().warning(
"Missing language message: " + path
);
message = "&cMissing message: " + path;
}
String prefix = language == null
? ""
: language.getString("prefix", "");
if (!path.equals("prefix") && !prefix.isEmpty()) {
message = prefix + message;
}
for (Map.Entry<String, String> entry
: placeholders.entrySet()) {
message = message.replace(
"%" + entry.getKey() + "%",
entry.getValue()
);
}
return ChatColor.translateAlternateColorCodes('&', message);
}
}
@@ -0,0 +1,79 @@
package com.rsscripting.rstaxi.platform;
import com.rsscripting.rstaxi.RSTaxi;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import java.util.Map;
public final class PlatformValidator {
private final RSTaxi plugin;
private static final Map<String, int[]> 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 PlatformValidator(RSTaxi plugin) {
this.plugin = plugin;
}
public boolean isValid(Player player) {
if (!plugin.getConfig().getBoolean("platform.enabled", true)) {
return true;
}
Block center = player.getLocation()
.subtract(0, 1, 0)
.getBlock();
Material target = getConfiguredMaterial(
"platform.target-block"
);
if (center.getType() != target) {
return false;
}
for (Map.Entry<String, int[]> entry : OFFSETS.entrySet()) {
String direction = entry.getKey();
int[] offset = entry.getValue();
Material required = getConfiguredMaterial(
"platform.layout." + direction
);
Block surrounding = center.getRelative(
offset[0], 0, offset[1]
);
if (surrounding.getType() != required) {
return false;
}
}
return true;
}
private Material getConfiguredMaterial(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;
}
}
@@ -0,0 +1,67 @@
package com.rsscripting.rstaxi.stops;
import com.rsscripting.rstaxi.RSTaxi;
import org.bukkit.Location;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public final class StopManager {
private final RSTaxi plugin;
public StopManager(RSTaxi plugin) {
this.plugin = plugin;
}
public boolean exists(String name) throws SQLException {
String sql = "SELECT 1 FROM stops WHERE name = ?";
try (PreparedStatement statement = connection()
.prepareStatement(sql)) {
statement.setString(1, name);
try (ResultSet results = statement.executeQuery()) {
return results.next();
}
}
}
public boolean add(
String name,
String icon,
Location location
) throws SQLException {
String sql = """
INSERT OR IGNORE INTO stops
(name, icon, world, x, y, z, yaw, pitch)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
""";
try (PreparedStatement statement = connection()
.prepareStatement(sql)) {
statement.setString(1, name);
statement.setString(2, icon);
statement.setString(
3, location.getWorld().getName()
);
statement.setDouble(4, location.getX());
statement.setDouble(5, location.getY());
statement.setDouble(6, location.getZ());
statement.setFloat(7, location.getYaw());
statement.setFloat(8, location.getPitch());
return statement.executeUpdate() == 1;
}
}
private Connection connection() {
return plugin.getDatabaseManager().getConnection();
}
}