From cf4431326eda7178f1196aaaedf7fde1af60f920 Mon Sep 17 00:00:00 2001 From: Len <40720638+destro174@users.noreply.github.com> Date: Sat, 13 Aug 2022 15:22:00 +0200 Subject: [PATCH] rework some stuff --- .gitignore | 4 +- build.gradle.kts | 87 +++++++-- settings.gradle.kts | 3 - .../com/alttd/playershops/PlayerShops.java | 20 +- .../com/alttd/playershops/config/Config.java | 18 +- .../playershops/config/DatabaseConfig.java | 10 +- .../playershops/config/MessageConfig.java | 9 - .../playershops/config/ShopTypeConfig.java | 24 +++ .../alttd/playershops/database/Database.java | 118 ------------ .../playershops/database/ShopQueries.java | 151 --------------- .../events/PlayerCreateShopEvent.java | 4 +- .../events/PlayerDestroyShopEvent.java | 4 +- .../events/PlayerExchangeShopEvent.java | 4 +- .../events/PlayerInitializeShopEvent.java | 4 +- .../events/ShopBalanceChangeEvent.java | 4 +- .../alttd/playershops/events/ShopEvent.java | 8 +- .../playershops/handler/ShopHandler.java | 48 ++--- .../playershops/listener/BlockListener.java | 83 ++++++++ .../playershops/listener/PlayerListener.java | 22 ++- .../playershops/listener/ShopListener.java | 13 +- .../alttd/playershops/shop/AbstractShop.java | 105 ---------- .../alttd/playershops/shop/BarterShop.java | 24 --- .../com/alttd/playershops/shop/BuyShop.java | 23 --- .../alttd/playershops/shop/GambleShop.java | 27 --- .../alttd/playershops/shop/PlayerShop.java | 151 +++++++++++++++ .../com/alttd/playershops/shop/SellShop.java | 24 --- .../alttd/playershops/shop/ShopAction.java | 8 + .../com/alttd/playershops/shop/ShopInfo.java | 4 + .../shop/ShopTransactionError.java | 10 - .../com/alttd/playershops/shop/ShopType.java | 20 +- .../playershops/storage/DatabaseManager.java | 180 ++++++++++++++++++ .../playershops/storage/StorageManager.java | 4 + .../storage/database/Database.java | 117 ++++++++++++ .../storage/database/DatabaseQuery.java | 41 ++++ .../storage/database/ShopQueries.java | 149 +++++++++++++++ .../com/alttd/playershops/utils/ShopUtil.java | 152 +++++++++++++++ 36 files changed, 1080 insertions(+), 597 deletions(-) delete mode 100644 src/main/java/com/alttd/playershops/database/Database.java delete mode 100644 src/main/java/com/alttd/playershops/database/ShopQueries.java create mode 100644 src/main/java/com/alttd/playershops/listener/BlockListener.java delete mode 100644 src/main/java/com/alttd/playershops/shop/AbstractShop.java delete mode 100644 src/main/java/com/alttd/playershops/shop/BarterShop.java delete mode 100644 src/main/java/com/alttd/playershops/shop/BuyShop.java delete mode 100644 src/main/java/com/alttd/playershops/shop/GambleShop.java create mode 100644 src/main/java/com/alttd/playershops/shop/PlayerShop.java delete mode 100644 src/main/java/com/alttd/playershops/shop/SellShop.java create mode 100644 src/main/java/com/alttd/playershops/shop/ShopAction.java create mode 100644 src/main/java/com/alttd/playershops/shop/ShopInfo.java delete mode 100755 src/main/java/com/alttd/playershops/shop/ShopTransactionError.java create mode 100644 src/main/java/com/alttd/playershops/storage/DatabaseManager.java create mode 100644 src/main/java/com/alttd/playershops/storage/StorageManager.java create mode 100644 src/main/java/com/alttd/playershops/storage/database/Database.java create mode 100644 src/main/java/com/alttd/playershops/storage/database/DatabaseQuery.java create mode 100644 src/main/java/com/alttd/playershops/storage/database/ShopQueries.java create mode 100644 src/main/java/com/alttd/playershops/utils/ShopUtil.java diff --git a/.gitignore b/.gitignore index fd4ec93..6790c8d 100644 --- a/.gitignore +++ b/.gitignore @@ -46,4 +46,6 @@ out/ # Linux temp files *~ -!gradle/wrapper/gradle-wrapper.jar \ No newline at end of file +!gradle/wrapper/gradle-wrapper.jar +/run/ +/lib/ diff --git a/build.gradle.kts b/build.gradle.kts index 1fa9fdb..3ccb8fc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,35 +1,51 @@ import java.io.ByteArrayOutputStream +import java.io.FileOutputStream +import java.net.URL +import net.minecrell.pluginyml.bukkit.BukkitPluginDescription plugins { id("java") id("net.minecrell.plugin-yml.bukkit") version "0.5.1" id("com.github.johnrengelman.shadow") version "7.1.0" + id("xyz.jpenilla.run-paper") version "1.0.6" } -allprojects { - group = "com.alttd.playershops" - version = "1.0-SNAPSHOT" - description = "Player Shop plugin for Altitude." +group = "com.alttd.playershops" +version = "1.0-SNAPSHOT" +description = "Player Shop plugin for Altitude." - apply() +apply() - java { - toolchain { - languageVersion.set(JavaLanguageVersion.of(17)) - } - } - - tasks { - withType { - options.encoding = Charsets.UTF_8.name() - } - - withType { - options.encoding = Charsets.UTF_8.name() - } +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) } } +tasks { + withType { + options.encoding = Charsets.UTF_8.name() + } + + withType { + options.encoding = Charsets.UTF_8.name() + } + + runServer { + val fileName = "./run/galaxy.jar" + var file = File(fileName) + if (!file.parentFile.exists()) { + file.parentFile.mkdirs() + } + if (!file.exists()) { + download("https://repo.destro.xyz/snapshots/com/alttd/Galaxy-Server/Galaxy-paperclip-1.19.2-R0.1-SNAPSHOT-reobf.jar", fileName) + } + serverJar(file) + minecraftVersion("1.19.2") + } +} + + dependencies { compileOnly("com.alttd:Galaxy-API:1.18.2-R0.1-SNAPSHOT") compileOnly("com.github.milkbowl:VaultAPI:1.7") { @@ -50,11 +66,42 @@ fun gitCommit(): String { return String(os.toByteArray()).trim() } +fun download(link: String, path: String) { + URL(link).openStream().use { input -> + FileOutputStream(File(path)).use { output -> + input.copyTo(output) + } + } +} + bukkit { name = rootProject.name main = "$group.${rootProject.name}" version = "${rootProject.version}-${gitCommit()}" - apiVersion = "1.18" + apiVersion = "1.19" authors = listOf("destro174") depend = listOf("Vault") + + permissions { + register("playershops.admin") { + description = "Admin permission for the ${rootProject.name} plugin." + default = BukkitPluginDescription.Permission.Default.FALSE + } + register("playershops.shoplimit") { + description = "Base permission to allow per player shop limits." + default = BukkitPluginDescription.Permission.Default.FALSE + } + register("playershops.shop.create") { + description = "Allows players to create shops." + default = BukkitPluginDescription.Permission.Default.FALSE + } + register("playershops.shop.break") { + description = "Allows players to break shops." + default = BukkitPluginDescription.Permission.Default.FALSE + } + register("playershops.shop.break.other") { + description = "Allows players to break other players shops." + default = BukkitPluginDescription.Permission.Default.FALSE + } + } } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index f8050ed..71eb4e9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,8 +1,5 @@ rootProject.name = "PlayerShops" -include(":api") -include(":plugin") - dependencyResolutionManagement { repositories { mavenCentral() diff --git a/src/main/java/com/alttd/playershops/PlayerShops.java b/src/main/java/com/alttd/playershops/PlayerShops.java index 7e73b5c..59ee1fa 100644 --- a/src/main/java/com/alttd/playershops/PlayerShops.java +++ b/src/main/java/com/alttd/playershops/PlayerShops.java @@ -1,10 +1,13 @@ package com.alttd.playershops; import com.alttd.playershops.config.Config; +import com.alttd.playershops.config.DatabaseConfig; import com.alttd.playershops.config.MessageConfig; import com.alttd.playershops.handler.ShopHandler; +import com.alttd.playershops.listener.BlockListener; import com.alttd.playershops.listener.PlayerListener; import com.alttd.playershops.listener.ShopListener; +import com.alttd.playershops.shop.ShopType; import lombok.Getter; import net.milkbowl.vault.economy.Economy; import org.bukkit.Bukkit; @@ -22,6 +25,7 @@ public class PlayerShops extends JavaPlugin { private ShopListener shopListener; private PlayerListener playerListener; + private BlockListener blockListener; public void onEnable() { instance = this; @@ -33,10 +37,15 @@ public class PlayerShops extends JavaPlugin { Bukkit.getLogger().info("Hooked into Vault economy provided by " + econ.getName()); reloadConfigs(); + shopHandler = new ShopHandler(instance); + registerListeners(); registerCommands(); + } - shopHandler = new ShopHandler(instance); + public void onDisable() { + unRegisterListeners(); + Bukkit.getScheduler().cancelTasks(this); } private boolean setupEconomy() { @@ -60,11 +69,13 @@ public class PlayerShops extends JavaPlugin { private void registerListeners() { shopListener = new ShopListener(this); playerListener = new PlayerListener(this); + blockListener = new BlockListener(this); } - private void UnregisterListeners() { + private void unRegisterListeners() { shopListener.unregister(); playerListener.unregister(); + blockListener.unregister(); } private void registerCommands() { @@ -76,6 +87,11 @@ public class PlayerShops extends JavaPlugin { public void reloadConfigs() { Config.reload(); MessageConfig.reload(); + DatabaseConfig.reload(); + + for (ShopType shopType : ShopType.values()) { + // preload ShopType to get the configs active + } } } diff --git a/src/main/java/com/alttd/playershops/config/Config.java b/src/main/java/com/alttd/playershops/config/Config.java index 08f65bf..51d0717 100644 --- a/src/main/java/com/alttd/playershops/config/Config.java +++ b/src/main/java/com/alttd/playershops/config/Config.java @@ -1,22 +1,19 @@ package com.alttd.playershops.config; import com.alttd.galaxy.configuration.AbstractConfiguration; -import com.alttd.playershops.shop.ShopType; import java.io.File; -import java.util.HashMap; @SuppressWarnings("unused") public class Config extends AbstractConfiguration { - public static File configPath = new File(System.getProperty("user.home") + File.separator + "share" + File.separator + "configs" + File.separator + "com/alttd/playershops"); + public static File configPath = new File(System.getProperty("user.home") + File.separator + "share" + File.separator + "configs" + File.separator + "playershops"); private Config() { super(Config.configPath, "config"); } static Config config; static int version; - static HashMap shopTypeConfigs; public static void reload() { config = new Config(); @@ -25,11 +22,6 @@ public class Config extends AbstractConfiguration { config.set("config-version", 1); config.readConfig(Config.class, null); - - shopTypeConfigs = new HashMap<>(); - for (ShopType shopType : ShopType.values()) { - shopTypeConfigs.put(shopType, new ShopTypeConfig(shopType.toString())); - } } public static int shopLimit = 100; @@ -37,15 +29,9 @@ public class Config extends AbstractConfiguration { public static String shopCreationWord = "[SHOP]"; private static void shopSettings() { String path = "shop-settings."; - shopLimit = config.getInt(path + "player-shop-limit", shopLimit); + shopLimit = config.getInt(path + "default-shop-limit", shopLimit); usePermissionShopLimit = config.getBoolean(path + "use-permission-based-shop-limit", usePermissionShopLimit); shopCreationWord = config.getString(path + "creation-word", shopCreationWord); } - public static String shopLimitPermission = "shop.buildlimit"; - private static void permissionSettings() { - String path = "permission."; - shopLimitPermission = config.getString(path + "build-limit", shopLimitPermission); - } - } diff --git a/src/main/java/com/alttd/playershops/config/DatabaseConfig.java b/src/main/java/com/alttd/playershops/config/DatabaseConfig.java index 5e31be9..5777aa7 100644 --- a/src/main/java/com/alttd/playershops/config/DatabaseConfig.java +++ b/src/main/java/com/alttd/playershops/config/DatabaseConfig.java @@ -26,7 +26,7 @@ public class DatabaseConfig extends AbstractConfiguration { public static String DRIVER = "mysql"; public static String IP = "localhost"; public static String PORT = "3306"; - public static String DATABASE_NAME = "AltitudeQuests"; + public static String DATABASE_NAME = "PlayerShops"; public static String USERNAME = "root"; public static String PASSWORD = "root"; @@ -38,4 +38,12 @@ public class DatabaseConfig extends AbstractConfiguration { USERNAME = config.getString("database.username", USERNAME); PASSWORD = config.getString("database.password", PASSWORD); } + + // Time in seconds between database tasks + public static int queueDelay = 5; + public static int maxDatabaseConnections = 10; + private static void databaseSettings() { + queueDelay = config.getInt("database.queue.delay" , queueDelay); + maxDatabaseConnections = config.getInt("database.maximum-connections" , maxDatabaseConnections); + } } diff --git a/src/main/java/com/alttd/playershops/config/MessageConfig.java b/src/main/java/com/alttd/playershops/config/MessageConfig.java index e65e161..dfcb5f3 100644 --- a/src/main/java/com/alttd/playershops/config/MessageConfig.java +++ b/src/main/java/com/alttd/playershops/config/MessageConfig.java @@ -1,9 +1,6 @@ package com.alttd.playershops.config; import com.alttd.galaxy.configuration.AbstractConfiguration; -import com.alttd.playershops.shop.ShopType; - -import java.util.HashMap; public class MessageConfig extends AbstractConfiguration { @@ -13,7 +10,6 @@ public class MessageConfig extends AbstractConfiguration { static MessageConfig config; static int version; - static HashMap shopTypeConfigs; public static void reload() { config = new MessageConfig(); @@ -22,11 +18,6 @@ public class MessageConfig extends AbstractConfiguration { config.set("config-version", 1); config.readConfig(Config.class, null); - - shopTypeConfigs = new HashMap<>(); - for (ShopType shopType : ShopType.values()) { - shopTypeConfigs.put(shopType, new ShopTypeConfig(shopType.toString())); - } } public static String SHOP_ALREADY_EXISTS = "This block is already a Shop"; diff --git a/src/main/java/com/alttd/playershops/config/ShopTypeConfig.java b/src/main/java/com/alttd/playershops/config/ShopTypeConfig.java index e86fd7b..7cb7e37 100644 --- a/src/main/java/com/alttd/playershops/config/ShopTypeConfig.java +++ b/src/main/java/com/alttd/playershops/config/ShopTypeConfig.java @@ -1,5 +1,11 @@ package com.alttd.playershops.config; +import io.leangen.geantyref.TypeToken; +import org.spongepowered.configurate.serialize.SerializationException; + +import java.util.ArrayList; +import java.util.List; + public class ShopTypeConfig { private final String shopType; @@ -27,4 +33,22 @@ public class ShopTypeConfig { Config.config.getNode(defaultPath + path).getString(def)); } + private List getStringList(String path, List def) { + try { + set(defaultPath + path, def); + return Config.config.getNode(configPath + path).getList(TypeToken.get(String.class), + Config.config.getNode(defaultPath + path).getList(TypeToken.get(String.class), def)); + } catch(SerializationException ignore) {} + return new ArrayList<>(); + } + + public List activeSignLines = List.of("[Shop]", "", "", ""); + public List inActiveSignLines = List.of("[Shop]", "right click", "to manage", ""); + public List expiredSignLines = List.of("[Shop]", "expired", "", ""); + private void textSettings() { + activeSignLines = getStringList("sign.active-lines", activeSignLines); + inActiveSignLines = getStringList("sign.inactive-lines", inActiveSignLines); + expiredSignLines = getStringList("sign.expired-lines", expiredSignLines); + } + } diff --git a/src/main/java/com/alttd/playershops/database/Database.java b/src/main/java/com/alttd/playershops/database/Database.java deleted file mode 100644 index ebebe39..0000000 --- a/src/main/java/com/alttd/playershops/database/Database.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.alttd.playershops.database; - -import com.alttd.playershops.PlayerShops; -import com.alttd.playershops.config.DatabaseConfig; -import com.alttd.playershops.utils.Logger; -import org.bukkit.Bukkit; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; - -public class Database { - - private static Database instance = null; - private Connection connection = null; - - private Database() {} - - public static Database getDatabase(){ - if (instance == null) - { - instance = new Database(); - instance.init(); - } - return (instance); - } - - protected void init() { - try { - openConnection(); - } catch (SQLException e) { - e.printStackTrace(); - } - - //Run all create table functions - for (Method method : Database.class.getDeclaredMethods()) { - if (Modifier.isPrivate(method.getModifiers())) { - if (method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE) { - try { - method.setAccessible(true); - method.invoke(instance); - } catch (InvocationTargetException ex) { - throw new RuntimeException(ex.getCause()); - } catch (Exception ex) { - Logger.severe("Error invoking " + method + "."); - ex.printStackTrace(); - } - } - } - } - } - - /** - * Opens the connection if it's not already open. - * @throws SQLException If it can't create the connection. - */ - private void openConnection() throws SQLException { - if (connection != null && !connection.isClosed()) { - return; - } - - synchronized (this) { - if (connection != null && !connection.isClosed()) { - return; - } - try { - Class.forName("com.mysql.cj.jdbc.Driver"); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - - connection = DriverManager.getConnection( - "jdbc:mysql://" + DatabaseConfig.IP + ":" + DatabaseConfig.PORT + "/" + DatabaseConfig.DATABASE_NAME + - "?autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true", - DatabaseConfig.USERNAME, DatabaseConfig.PASSWORD); - } - } - - public Connection getConnection() { - try { - openConnection(); - } catch (SQLException e) { - e.printStackTrace(); - } - return connection; - } - - private static void createShopTable() { - try { - String sql = "CREATE TABLE IF NOT EXISTS shops(" + - "id INT NOT NULL AUTO_INCREMENT, " + - "owner_name VARCHAR(16) NOT NULL, " + - "owner_uuid VARCHAR(36) NOT NULL, " + - "shop_type VARCHAR(36) NOT NULL, " + - "server VARCHAR(16) NOT NULL, " + - "container_location VARCHAR(256), " + - "sign_location VARCHAR(256), " + - "price DOUBLE NOT NULL, " + - "amount INT NOT NULL, " + - "balance DOUBLE NOT NULL, " + - "item_one TEXT, " + - "item_two TEXT, " + - "last_transaction BIGINT, " + - "PRIMARY KEY (id)" + - ")"; - getDatabase().getConnection().prepareStatement(sql).executeUpdate(); - } catch (SQLException e) { - e.printStackTrace(); - Logger.severe("Error while trying to create shop table"); - Logger.severe("Shutting down PlayerShops"); - Bukkit.getPluginManager().disablePlugin(PlayerShops.getInstance()); - } - } - -} diff --git a/src/main/java/com/alttd/playershops/database/ShopQueries.java b/src/main/java/com/alttd/playershops/database/ShopQueries.java deleted file mode 100644 index 26dd6eb..0000000 --- a/src/main/java/com/alttd/playershops/database/ShopQueries.java +++ /dev/null @@ -1,151 +0,0 @@ -package com.alttd.playershops.database; - -import com.alttd.playershops.shop.AbstractShop; -import com.alttd.playershops.shop.ShopType; -import com.alttd.playershops.utils.AMath; -import com.alttd.playershops.utils.Logger; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.inventory.ItemStack; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -public class ShopQueries { - - public static boolean saveShop(AbstractShop shop) { - String sql = "INSERT INTO shops " + - "(id, owner_name, owner_uuid, shop_type, server, container_location, sign_location, " + - "price, amount, balance, item_one, item_two, last_transaction)" + - "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + - "ON DUPLICATE KEY UPDATE owner_name = ?, owner_uuid = ?, shop_type = ?, server = ?, " + - "container_location = ?, sign_location = ?, price = ?, amount = ?, balance = ?, " + - "item_one = ?, item_two = ?, last_transaction = ?"; - try { - PreparedStatement statement = Database.getDatabase().getConnection().prepareStatement(sql); - - statement.setInt(1, shop.getId()); - statement.setString(2, shop.getOwnerName()); - statement.setString(3, shop.getOwnerUUID().toString()); - statement.setString(4, shop.getServer()); - statement.setString(5, shop.getType().toString()); - statement.setString(6, locationToString(shop.getContainerLocation())); - statement.setString(7, locationToString(shop.getSignLocation())); - statement.setDouble(8, shop.getPrice()); - statement.setInt(9, shop.getAmount()); - statement.setDouble(10, shop.getBalance()); - statement.setBytes(11, shop.getItemStack().serializeAsBytes()); - statement.setBytes(12, shop.getSecondaryItem().serializeAsBytes()); - statement.setLong(13, shop.getLastTransaction()); - //repeat everything except id for update - statement.setString(14, shop.getOwnerName()); - statement.setString(15, shop.getOwnerUUID().toString()); - statement.setString(16, shop.getServer()); - statement.setString(17, shop.getType().toString()); - statement.setString(18, locationToString(shop.getContainerLocation())); - statement.setString(19, locationToString(shop.getSignLocation())); - statement.setDouble(20, shop.getPrice()); - statement.setInt(21, shop.getAmount()); - statement.setDouble(22, shop.getBalance()); - statement.setBytes(23, shop.getItemStack().serializeAsBytes()); - statement.setBytes(24, shop.getSecondaryItem().serializeAsBytes()); - statement.setLong(25, shop.getLastTransaction()); - - return statement.executeUpdate() == 1; - } catch (SQLException e) { - e.printStackTrace(); - } - return false; - } - - public static AbstractShop loadShop(int id) { - String sql = "SELECT * FROM shops WHERE id = ?"; - try { - PreparedStatement statement = Database.getDatabase().getConnection().prepareStatement(sql); - - statement.setInt(1, id); - ResultSet resultSet = statement.executeQuery(); - if (resultSet.next()) - return shopFromResultSet(resultSet); - } catch (SQLException e) { - e.printStackTrace(); - } - return null; - } - - public static List loadShops() { - String sql = "SELECT * FROM shops"; - ArrayList shops = new ArrayList<>(); - try { - PreparedStatement statement = Database.getDatabase().getConnection().prepareStatement(sql); - - ResultSet resultSet = statement.executeQuery(); - while (resultSet.next()) { - AbstractShop shop = shopFromResultSet(resultSet); - if (shop == null) { - Logger.warn("Tried to load a shop but failed [" + resultSet + "]"); - continue; - } - shops.add(shop); - } - } catch (SQLException e) { - e.printStackTrace(); - } - return shops; - } - - /** - * Loads a shop from a result set, does not iterate - * @param resultSet Result set to load from - * @return A shop - * @throws SQLException if data is missing or formatted incorrectly - */ - private static AbstractShop shopFromResultSet(ResultSet resultSet) throws SQLException { - int id = resultSet.getInt("id"); - String ownerName = resultSet.getString("owner_name"); - UUID ownerUuid = UUID.fromString(resultSet.getString("owner_uuid")); - ShopType shopType = ShopType.valueOf(resultSet.getString("shop_type")); - String server = resultSet.getString("server"); - Location containerLocation = stringToLocation(resultSet.getString("container_location")); - Location signLocation = stringToLocation(resultSet.getString("sign_location")); - double price = resultSet.getDouble("price"); - int amount = resultSet.getInt("amount"); - double balance = resultSet.getDouble("balance"); - ItemStack itemOne = ItemStack.deserializeBytes(resultSet.getBytes("item_one")); - ItemStack itemTwo = ItemStack.deserializeBytes(resultSet.getBytes("item_two")); - long lastTransaction = resultSet.getLong("last_transaction"); - - if (containerLocation == null || signLocation == null) - return null; - - return AbstractShop.create(id, ownerName, ownerUuid, shopType, server, containerLocation, signLocation, - price, amount, balance, itemOne, itemTwo, lastTransaction); - } - - private static String locationToString(Location location) { - return location.getWorld() + ":" + - AMath.round(location.getX(), 1) + ":" + - AMath.round(location.getY(), 1) + ":" + - AMath.round(location.getZ(), 1); - } - - private static Location stringToLocation(String string) { - String[] split = string.split(":"); - if (split.length != 4) { - Logger.warn("Unable to load location [" + string + "] due to invalid format"); - return null; - } - - try { - return new Location(Bukkit.getWorld(split[0]), - Double.parseDouble(split[1]), Double.parseDouble(split[2]), Double.parseDouble(split[3])); - } catch (NumberFormatException e) { - Logger.warn("Unable to load location [" + string + "] due to invalid format"); - return null; - } - } -} diff --git a/src/main/java/com/alttd/playershops/events/PlayerCreateShopEvent.java b/src/main/java/com/alttd/playershops/events/PlayerCreateShopEvent.java index 827bdde..a446d32 100644 --- a/src/main/java/com/alttd/playershops/events/PlayerCreateShopEvent.java +++ b/src/main/java/com/alttd/playershops/events/PlayerCreateShopEvent.java @@ -1,6 +1,6 @@ package com.alttd.playershops.events; -import com.alttd.playershops.shop.AbstractShop; +import com.alttd.playershops.shop.PlayerShop; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; @@ -9,7 +9,7 @@ public class PlayerCreateShopEvent extends ShopEvent { private static final HandlerList handlers = new HandlerList(); private final Player player; - public PlayerCreateShopEvent(Player player, AbstractShop shop) { + public PlayerCreateShopEvent(Player player, PlayerShop shop) { super(shop); this.player = player; } diff --git a/src/main/java/com/alttd/playershops/events/PlayerDestroyShopEvent.java b/src/main/java/com/alttd/playershops/events/PlayerDestroyShopEvent.java index 9f3f53a..e1b7d25 100644 --- a/src/main/java/com/alttd/playershops/events/PlayerDestroyShopEvent.java +++ b/src/main/java/com/alttd/playershops/events/PlayerDestroyShopEvent.java @@ -1,6 +1,6 @@ package com.alttd.playershops.events; -import com.alttd.playershops.shop.AbstractShop; +import com.alttd.playershops.shop.PlayerShop; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; @@ -10,7 +10,7 @@ public class PlayerDestroyShopEvent extends ShopEvent { private static final HandlerList handlers = new HandlerList(); private final Player player; - public PlayerDestroyShopEvent(Player player, AbstractShop shop) { + public PlayerDestroyShopEvent(Player player, PlayerShop shop) { super(shop); this.player = player; } diff --git a/src/main/java/com/alttd/playershops/events/PlayerExchangeShopEvent.java b/src/main/java/com/alttd/playershops/events/PlayerExchangeShopEvent.java index 588b24d..7c9e1e6 100644 --- a/src/main/java/com/alttd/playershops/events/PlayerExchangeShopEvent.java +++ b/src/main/java/com/alttd/playershops/events/PlayerExchangeShopEvent.java @@ -1,6 +1,6 @@ package com.alttd.playershops.events; -import com.alttd.playershops.shop.AbstractShop; +import com.alttd.playershops.shop.PlayerShop; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; @@ -10,7 +10,7 @@ public class PlayerExchangeShopEvent extends ShopEvent { private static final HandlerList handlers = new HandlerList(); private final Player player; - public PlayerExchangeShopEvent(Player player, AbstractShop shop) { + public PlayerExchangeShopEvent(Player player, PlayerShop shop) { super(shop); this.player = player; } diff --git a/src/main/java/com/alttd/playershops/events/PlayerInitializeShopEvent.java b/src/main/java/com/alttd/playershops/events/PlayerInitializeShopEvent.java index 1cadb05..9fca108 100644 --- a/src/main/java/com/alttd/playershops/events/PlayerInitializeShopEvent.java +++ b/src/main/java/com/alttd/playershops/events/PlayerInitializeShopEvent.java @@ -1,6 +1,6 @@ package com.alttd.playershops.events; -import com.alttd.playershops.shop.AbstractShop; +import com.alttd.playershops.shop.PlayerShop; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; @@ -10,7 +10,7 @@ public class PlayerInitializeShopEvent extends ShopEvent { private static final HandlerList handlers = new HandlerList(); private final Player player; - public PlayerInitializeShopEvent(Player player, AbstractShop shop) { + public PlayerInitializeShopEvent(Player player, PlayerShop shop) { super(shop); this.player = player; } diff --git a/src/main/java/com/alttd/playershops/events/ShopBalanceChangeEvent.java b/src/main/java/com/alttd/playershops/events/ShopBalanceChangeEvent.java index 10fad83..31c5703 100644 --- a/src/main/java/com/alttd/playershops/events/ShopBalanceChangeEvent.java +++ b/src/main/java/com/alttd/playershops/events/ShopBalanceChangeEvent.java @@ -1,6 +1,6 @@ package com.alttd.playershops.events; -import com.alttd.playershops.shop.AbstractShop; +import com.alttd.playershops.shop.PlayerShop; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; @@ -8,7 +8,7 @@ public class ShopBalanceChangeEvent extends ShopEvent { private static final HandlerList handlers = new HandlerList(); private final ChangeReason changeReason; - public ShopBalanceChangeEvent(AbstractShop shop, ChangeReason reason) { + public ShopBalanceChangeEvent(PlayerShop shop, ChangeReason reason) { super(shop); this.changeReason = reason; } diff --git a/src/main/java/com/alttd/playershops/events/ShopEvent.java b/src/main/java/com/alttd/playershops/events/ShopEvent.java index 2da3c18..7504607 100644 --- a/src/main/java/com/alttd/playershops/events/ShopEvent.java +++ b/src/main/java/com/alttd/playershops/events/ShopEvent.java @@ -1,19 +1,19 @@ package com.alttd.playershops.events; -import com.alttd.playershops.shop.AbstractShop; +import com.alttd.playershops.shop.PlayerShop; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; public abstract class ShopEvent extends Event implements Cancellable { private boolean cancelled; - private final AbstractShop shop; + private final PlayerShop shop; - public ShopEvent(AbstractShop shop) { + public ShopEvent(PlayerShop shop) { this.shop = shop; } - public AbstractShop getShop() { + public PlayerShop getShop() { return shop; } diff --git a/src/main/java/com/alttd/playershops/handler/ShopHandler.java b/src/main/java/com/alttd/playershops/handler/ShopHandler.java index 53a93bc..d4db6c6 100644 --- a/src/main/java/com/alttd/playershops/handler/ShopHandler.java +++ b/src/main/java/com/alttd/playershops/handler/ShopHandler.java @@ -2,9 +2,7 @@ package com.alttd.playershops.handler; import com.alttd.playershops.PlayerShops; import com.alttd.playershops.config.Config; -import com.alttd.playershops.events.PlayerCreateShopEvent; -import com.alttd.playershops.shop.AbstractShop; -import com.alttd.playershops.shop.ShopType; +import com.alttd.playershops.shop.PlayerShop; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import lombok.Getter; @@ -12,7 +10,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Tag; import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; import java.util.*; @@ -24,7 +21,7 @@ public class ShopHandler { @Getter private final Object2IntMap shopBuildLimits; @Getter - private final Map shopLocation; + private final Map shopLocation; @Getter private final ArrayList shopMaterials; @@ -34,9 +31,10 @@ public class ShopHandler { shopBuildLimits = new Object2IntOpenHashMap<>(); shopBuildLimits.defaultReturnValue(Config.shopLimit); shopMaterials = new ArrayList<>(); // TODO move into parent method where materials are loaded in. + shopMaterials.add(Material.BARREL); } - public AbstractShop getShop(Location location) { + public PlayerShop getShop(Location location) { Location newLocation = new Location(location.getWorld(), location.getBlockX(), location.getBlockY(), location.getBlockZ()); return shopLocation.get(newLocation); @@ -46,7 +44,7 @@ public class ShopHandler { return getShop(location) != null; } - public Collection getShops() { + public Collection getShops() { return Collections.unmodifiableCollection(shopLocation.values()); } @@ -69,44 +67,34 @@ public class ShopHandler { return shopMaterials.contains(block.getType()); } - public List getShops(UUID uuid) { - List shops = new ArrayList<>(); - for (AbstractShop shop : shopLocation.values()) { + public List getShops(UUID uuid) { + List shops = new ArrayList<>(); + for (PlayerShop shop : shopLocation.values()) { if (shop.getOwnerUUID().equals(uuid)) shops.add(shop); } return shops; } - public AbstractShop getShopBySignLocation(Location signLocation) { - for (AbstractShop shop : shopLocation.values()) { + public PlayerShop getShopBySignLocation(Location signLocation) { + for (PlayerShop shop : shopLocation.values()) { if (shop.getSignLocation().equals(signLocation)) return shop; } return null; } - public AbstractShop getShopNearBlock(Block block) { - BlockFace[] faces = {BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}; - for (BlockFace face : faces) { - if (this.isShopMaterial(block.getRelative(face))) { - Block blockRelative = block.getRelative(face); - if (isShop(blockRelative.getLocation())) - return getShop(blockRelative.getLocation()); - } - } - return null; + public void addShop(PlayerShop shop) { + shopLocation.put(shop.getShopLocation(), shop); } - public AbstractShop createShop(Location signLocation, Player player, double price, int amount, ShopType shopType) { - AbstractShop shop = AbstractShop.create(signLocation, player.getUniqueId(), price, amount, shopType); + public boolean canPlayerBreakShop(Player player, PlayerShop shop) { + if (player.getUniqueId().equals(shop.getOwnerUUID()) && player.hasPermission("playershops.shop.break")) + return true; - PlayerCreateShopEvent playerCreateShopEvent = new PlayerCreateShopEvent(player, shop); - plugin.getServer().getPluginManager().callEvent(playerCreateShopEvent); + if (player.hasPermission("playershops.shop.break.other")) + return true; - if(playerCreateShopEvent.isCancelled()) - return null; - - return shop; + return false; } } diff --git a/src/main/java/com/alttd/playershops/listener/BlockListener.java b/src/main/java/com/alttd/playershops/listener/BlockListener.java new file mode 100644 index 0000000..53d0fa8 --- /dev/null +++ b/src/main/java/com/alttd/playershops/listener/BlockListener.java @@ -0,0 +1,83 @@ +package com.alttd.playershops.listener; + +import com.alttd.playershops.PlayerShops; +import com.alttd.playershops.config.Config; +import com.alttd.playershops.config.MessageConfig; +import com.alttd.playershops.handler.ShopHandler; +import com.alttd.playershops.shop.PlayerShop; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.bukkit.Tag; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.Sign; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Directional; +import org.bukkit.block.data.Rotatable; +import org.bukkit.block.data.type.WallSign; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.permissions.PermissionAttachmentInfo; + +import java.util.UUID; + +public class BlockListener extends EventListener { + + private final PlayerShops plugin; + ShopHandler shopHandler; + + public BlockListener(PlayerShops plugin) { + this.plugin = plugin; + this.register(this.plugin); + shopHandler = plugin.getShopHandler(); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onInventoryHolderBlockBreak(BlockBreakEvent event) { + if(!this.isRegistered) + return; + Block block = event.getBlock(); + + if (!(block.getState() instanceof InventoryHolder inventoryHolder)) + return; + + PlayerShop shop = shopHandler.getShop(block.getLocation()); + if (shop == null) + return; + + event.setCancelled(!shopHandler.canPlayerBreakShop(event.getPlayer(), shop)); + + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onSignBlockBreak(BlockBreakEvent event) { + if(!this.isRegistered) + return; + // this is going to be heavy, add a cache shopsignlocation <-> Shop? + Block block = event.getBlock(); + + if (!(block.getState() instanceof Sign)) + return; + + BlockFace facing; + BlockData data = block.getState().getBlockData(); + if (data instanceof WallSign) { + facing = ((Directional) data).getFacing(); + } else { + facing = ((Rotatable) data).getRotation(); + } + + Block relativeBlock = block.getRelative(facing.getOppositeFace()); + PlayerShop shop = shopHandler.getShop(relativeBlock.getLocation()); + if (shop == null) + return; + + event.setCancelled(!shopHandler.canPlayerBreakShop(event.getPlayer(), shop)); + } +} diff --git a/src/main/java/com/alttd/playershops/listener/PlayerListener.java b/src/main/java/com/alttd/playershops/listener/PlayerListener.java index 5da955f..53e7c81 100644 --- a/src/main/java/com/alttd/playershops/listener/PlayerListener.java +++ b/src/main/java/com/alttd/playershops/listener/PlayerListener.java @@ -4,7 +4,7 @@ import com.alttd.playershops.PlayerShops; import com.alttd.playershops.config.Config; import com.alttd.playershops.config.MessageConfig; import com.alttd.playershops.handler.ShopHandler; -import com.alttd.playershops.shop.AbstractShop; +import com.alttd.playershops.shop.PlayerShop; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; @@ -27,20 +27,21 @@ import java.util.UUID; public class PlayerListener extends EventListener { private final PlayerShops plugin; + ShopHandler shopHandler; public PlayerListener(PlayerShops plugin) { this.plugin = plugin; this.register(this.plugin); + shopHandler = plugin.getShopHandler(); } @EventHandler(ignoreCancelled = true) - public void onPlayerJoin(PlayerJoinEvent event) { + public void PlayerJoinEvent(PlayerJoinEvent event) { if(!this.isRegistered || !Config.usePermissionShopLimit) return; Player player = event.getPlayer(); - if (!player.hasPermission(Config.shopLimitPermission)) return; + if (!player.hasPermission("playershops.shoplimit")) return; - ShopHandler shopHandler = plugin.getShopHandler(); UUID uuid = player.getUniqueId(); // early return to not check this all the time, if this changes by rankup etc handle it in another event @@ -68,7 +69,7 @@ public class PlayerListener extends EventListener { if (!(block.getState() instanceof Sign)) return; - AbstractShop shop = plugin.getShopHandler().getShop(block.getLocation()); + PlayerShop shop = shopHandler.getShop(block.getLocation()); if(shop == null) return; if(shop.isInitialized()) event.setCancelled(true); @@ -77,7 +78,7 @@ public class PlayerListener extends EventListener { @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onShopCreation(SignChangeEvent event) { Block b = event.getBlock(); - + Player player = event.getPlayer(); if (!(b.getState() instanceof Sign)) return; @@ -90,7 +91,6 @@ public class PlayerListener extends EventListener { } Block bRelative = b.getRelative(facing.getOppositeFace()); - ShopHandler shopHandler = plugin.getShopHandler(); if (shopHandler.isShopMaterial(bRelative)) { Sign signBlock = (Sign) b.getState(); @@ -101,8 +101,8 @@ public class PlayerListener extends EventListener { if (!signLineString.equalsIgnoreCase(Config.shopCreationWord)) return; - AbstractShop shop = shopHandler.getShop(bRelative.getLocation()); - Player player = event.getPlayer(); + PlayerShop shop = shopHandler.getShop(bRelative.getLocation()); +// Player player = event.getPlayer(); if(shop != null) { event.setCancelled(true); player.sendMiniMessage(MessageConfig.SHOP_ALREADY_EXISTS, null); @@ -110,7 +110,7 @@ public class PlayerListener extends EventListener { } UUID playerUUID = player.getUniqueId(); - if (!player.hasPermission("shop.create")) { + if (!player.hasPermission("playershops.shop.create")) { event.setCancelled(true); player.sendMiniMessage(MessageConfig.NO_SHOP_CREATE_PERMISSION, null); return; @@ -125,7 +125,9 @@ public class PlayerListener extends EventListener { return; } + PlayerShop playerShop = new PlayerShop(bRelative.getLocation(), signBlock.getLocation(), player); // TODO instance shopCreationManagement + shopHandler.addShop(playerShop); } } diff --git a/src/main/java/com/alttd/playershops/listener/ShopListener.java b/src/main/java/com/alttd/playershops/listener/ShopListener.java index 46151e9..6a48f34 100644 --- a/src/main/java/com/alttd/playershops/listener/ShopListener.java +++ b/src/main/java/com/alttd/playershops/listener/ShopListener.java @@ -1,7 +1,8 @@ package com.alttd.playershops.listener; import com.alttd.playershops.PlayerShops; -import com.alttd.playershops.shop.AbstractShop; +import com.alttd.playershops.handler.ShopHandler; +import com.alttd.playershops.shop.PlayerShop; import org.bukkit.Location; import org.bukkit.Tag; import org.bukkit.block.Block; @@ -13,10 +14,12 @@ import java.util.Iterator; public class ShopListener extends EventListener { private final PlayerShops plugin; + ShopHandler shopHandler; public ShopListener(PlayerShops plugin) { this.plugin = plugin; this.register(this.plugin); + shopHandler = plugin.getShopHandler(); } @EventHandler(ignoreCancelled = true) @@ -25,15 +28,15 @@ public class ShopListener extends EventListener { // This might be heavy when tnt is chained, would it be better to expand the unbreakable block api in galaxy and use that? // No need for slow bukkit events eating up cpu and memory Iterator blockIterator = event.blockList().iterator(); - AbstractShop shop = null; + PlayerShop shop = null; while (blockIterator.hasNext()) { Block block = blockIterator.next(); Location location = block.getLocation(); if (Tag.WALL_SIGNS.isTagged(block.getType())) { - shop = plugin.getShopHandler().getShopBySignLocation(location); - } else if (plugin.getShopHandler().isShopMaterial(block)) { - shop = plugin.getShopHandler().getShop(location); + shop = shopHandler.getShopBySignLocation(location); + } else if (shopHandler.isShopMaterial(block)) { + shop = shopHandler.getShop(location); } if (shop != null) { diff --git a/src/main/java/com/alttd/playershops/shop/AbstractShop.java b/src/main/java/com/alttd/playershops/shop/AbstractShop.java deleted file mode 100644 index ea91e28..0000000 --- a/src/main/java/com/alttd/playershops/shop/AbstractShop.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.alttd.playershops.shop; - -import lombok.Getter; -import lombok.Setter; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.block.data.Directional; -import org.bukkit.inventory.ItemStack; - -import java.util.UUID; - -public abstract class AbstractShop { - - @Getter - private int id; - private String ownerName; - @Getter - private UUID ownerUUID; - @Getter @Setter - private ShopType type; - @Getter - private Location signLocation; - @Getter - private Location containerLocation; - @Getter - private String server; - @Getter @Setter - private double price; - @Getter @Setter - private int amount; - @Getter @Setter - private double balance; - @Getter @Setter - private ItemStack itemStack; - @Getter @Setter - private ItemStack secondaryItem; - @Getter @Setter - private long lastTransaction; - - protected boolean initialized; - - AbstractShop(Location signLocation, UUID uuid, double price, int amount) { - this.signLocation = signLocation; - if (signLocation != null) { - Directional sign = (Directional) signLocation.getBlock().getState().getBlockData(); - this.containerLocation = signLocation.getBlock().getRelative(sign.getFacing().getOppositeFace()).getLocation(); - } - this.ownerUUID = uuid; - ownerName = getOwnerName(); - this.price = price; - this.amount = amount; - this.server = Bukkit.getServerName(); - } - - AbstractShop(int id, String ownerName, UUID ownerUUID, String server, - Location containerLocation, Location signLocation, double price, int amount, - double balance, ItemStack itemOne, ItemStack itemTwo, long lastTransaction) { - this.id = id; - this.ownerName = ownerName; - this.ownerUUID = ownerUUID; - this.server = server; - this.containerLocation = containerLocation; - this.signLocation = signLocation; - this.price = price; - this.amount = amount; - this.balance = balance; - this.itemStack = itemOne; - this.secondaryItem = itemTwo; - this.lastTransaction = lastTransaction; - } - - public static AbstractShop create(Location signLocation, UUID player, double price, int amount, ShopType shopType) { - return switch (shopType) { - case SELL -> new SellShop(signLocation, player, price, amount); - case BUY -> new BuyShop(signLocation, player, price, amount); - case GAMBLE -> new GambleShop(signLocation, player, price, amount); - case BARTER -> new BarterShop(signLocation, player, price, amount); - }; - } - - public static AbstractShop create(int id, String ownerName, UUID ownerUUID, ShopType shopType, String server, - Location containerLocation, Location signLocation, double price, int amount, - double balance, ItemStack itemOne, ItemStack itemTwo, long lastTransaction) { - return switch (shopType) { - case SELL -> new SellShop(id, ownerName, ownerUUID, server, containerLocation, signLocation, price, amount, balance, itemOne, itemTwo, lastTransaction); - case BUY -> new BuyShop(id, ownerName, ownerUUID, server, containerLocation, signLocation, price, amount, balance, itemOne, itemTwo, lastTransaction); - case GAMBLE -> new GambleShop(id, ownerName, ownerUUID, server, containerLocation, signLocation, price, amount, balance, itemOne, itemTwo, lastTransaction); - case BARTER -> new BarterShop(id, ownerName, ownerUUID, server, containerLocation, signLocation, price, amount, balance, itemOne, itemTwo, lastTransaction); - }; - } - - public String getOwnerName() { - if(this.ownerName != null) return ownerName; - if (this.getOwnerUUID() != null) { - ownerName = Bukkit.getOfflinePlayer(this.getOwnerUUID()).getName(); - return ownerName; - } - return ChatColor.RED + "[CLOSED]"; - } - - public boolean isInitialized() { - return initialized; - } -} diff --git a/src/main/java/com/alttd/playershops/shop/BarterShop.java b/src/main/java/com/alttd/playershops/shop/BarterShop.java deleted file mode 100644 index 97c972c..0000000 --- a/src/main/java/com/alttd/playershops/shop/BarterShop.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.alttd.playershops.shop; - -import org.bukkit.Location; -import org.bukkit.inventory.ItemStack; - -import java.util.UUID; - -public class BarterShop extends AbstractShop { - - public BarterShop(Location location, UUID player, double price, int amount) { - super(location, player, price, amount); - - this.setType(ShopType.BARTER); - } - - public BarterShop(int id, String ownerName, UUID ownerUUID, String server, - Location containerLocation, Location signLocation, double price, int amount, - double balance, ItemStack itemOne, ItemStack itemTwo, long lastTransaction) { - super(id, ownerName, ownerUUID, server, containerLocation, signLocation, price, amount, - balance, itemOne, itemTwo, lastTransaction); - this.setType(ShopType.BARTER); - } - -} diff --git a/src/main/java/com/alttd/playershops/shop/BuyShop.java b/src/main/java/com/alttd/playershops/shop/BuyShop.java deleted file mode 100644 index a324410..0000000 --- a/src/main/java/com/alttd/playershops/shop/BuyShop.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.alttd.playershops.shop; - -import org.bukkit.Location; -import org.bukkit.inventory.ItemStack; - -import java.util.UUID; - -public class BuyShop extends AbstractShop { - - public BuyShop(Location location, UUID player, double price, int amount) { - super(location, player, price, amount); - - this.setType(ShopType.BUY); - } - - public BuyShop(int id, String ownerName, UUID ownerUUID, String server, - Location containerLocation, Location signLocation, double price, int amount, - double balance, ItemStack itemOne, ItemStack itemTwo, long lastTransaction) { - super(id, ownerName, ownerUUID, server, containerLocation, signLocation, price, amount, - balance, itemOne, itemTwo, lastTransaction); - this.setType(ShopType.BUY); - } -} diff --git a/src/main/java/com/alttd/playershops/shop/GambleShop.java b/src/main/java/com/alttd/playershops/shop/GambleShop.java deleted file mode 100644 index 8968a11..0000000 --- a/src/main/java/com/alttd/playershops/shop/GambleShop.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.alttd.playershops.shop; - -import org.bukkit.Location; -import org.bukkit.inventory.ItemStack; - -import java.util.UUID; - -public class GambleShop extends AbstractShop { - - private ItemStack gambleItem; - - public GambleShop(Location location, UUID player, double price, int amount) { - super(location, player, price, amount); - - this.setType(ShopType.GAMBLE); - this.gambleItem = this.getItemStack(); - } - - public GambleShop(int id, String ownerName, UUID ownerUUID, String server, - Location containerLocation, Location signLocation, double price, int amount, - double balance, ItemStack itemOne, ItemStack itemTwo, long lastTransaction) { - super(id, ownerName, ownerUUID, server, containerLocation, signLocation, price, amount, - balance, itemOne, itemTwo, lastTransaction); - this.setType(ShopType.GAMBLE); - } - -} diff --git a/src/main/java/com/alttd/playershops/shop/PlayerShop.java b/src/main/java/com/alttd/playershops/shop/PlayerShop.java new file mode 100644 index 0000000..e932556 --- /dev/null +++ b/src/main/java/com/alttd/playershops/shop/PlayerShop.java @@ -0,0 +1,151 @@ +package com.alttd.playershops.shop; + +import com.alttd.playershops.PlayerShops; +import com.alttd.playershops.utils.ShopUtil; +import lombok.Getter; +import lombok.Setter; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import org.bukkit.Location; +import org.bukkit.block.Sign; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.List; +import java.util.UUID; + +public class PlayerShop { + + @Getter + private int id; + @Getter @Setter // TODO a way to check if the player changed name and update if needed + private String ownerName; + @Getter + private UUID ownerUUID; + @Getter @Setter + private ShopType type = ShopType.DEFAULT; + @Getter + private final Location signLocation; + @Getter + private final Location shopLocation; + @Getter + private String server; + @Getter @Setter + private double price; + @Getter @Setter + private int amount; + @Getter @Setter + private double balance; + @Getter @Setter + private ItemStack itemStack; + @Getter @Setter + private long lastTransaction; + + public PlayerShop(Location shopLocation, Location signLocation, Player player) { + this(shopLocation, signLocation, player.getUniqueId(), player.getName()); + } + + public PlayerShop(Location shopLocation, Location signLocation, UUID uuid, String playerName) { + this.shopLocation = shopLocation; + this.signLocation = signLocation; + this.ownerUUID = uuid; + this.ownerName = playerName; + updateSign(); + } + + public static PlayerShop create(int id, String ownerName, UUID ownerUUID, ShopType shopType, String server, + Location shopLocation, Location signLocation, double price, int amount, + double balance, ItemStack item, long lastTransaction) { + PlayerShop playerShop = new PlayerShop(shopLocation, signLocation, ownerUUID, ownerName); + + playerShop.id = id; + playerShop.type = shopType; + playerShop.server = server; + playerShop.price = price; + playerShop.amount = amount; + playerShop.balance = balance; + playerShop.itemStack = item; + playerShop.lastTransaction = lastTransaction; + + return playerShop; + } + + public int getRemainingStock() { + return ShopUtil.countItems(getInventory(), getItemStack()); + } + + public int getRemainingSpace() { + return ShopUtil.countSpace(getInventory(), getItemStack()); + } + + public boolean matches(ItemStack item) { + return ShopUtil.matches(getItemStack(), item); + } + + public void remove(ItemStack item, int amount) { + Inventory inv = getInventory(); + int remains = amount; + while (remains > 0) { + int stackSize = Math.min(remains, item.getMaxStackSize()); + item.setAmount(stackSize); + inv.removeItem(item); + remains = remains - stackSize; + } + } + + public void add(ItemStack item, int amount) { + Inventory inv = getInventory(); + int remains = amount; + while (remains > 0) { + int stackSize = Math.min(remains, item.getMaxStackSize()); + item.setAmount(stackSize); + inv.addItem(item); + remains = remains - stackSize; + } + } + + public void setOwner(Player player) { + ownerUUID = player.getUniqueId(); + ownerName = player.getName(); + } + + public Inventory getInventory() { + // Could use a check if the block is still an InventoryHolder. + InventoryHolder container = (InventoryHolder) shopLocation.getBlock().getState(); + return container.getInventory(); + } + + public boolean isInitialized() { + return type != ShopType.DEFAULT; + } + + public void updateSign() { + + new BukkitRunnable() { + public void run() { + + Sign signBlock = (Sign) signLocation.getBlock().getState(); + MiniMessage miniMessage = MiniMessage.miniMessage(); + List signLines; + TagResolver tagResolver = TagResolver.resolver( + Placeholder.unparsed("ownername", getOwnerName()), + Placeholder.unparsed("price", String.valueOf(getPrice())), + Placeholder.unparsed("amount", String.valueOf(getAmount())) + ); + if (!isInitialized()) { + signLines = type.getShopTypeConfig().inActiveSignLines; + } else { + signLines = type.getShopTypeConfig().activeSignLines; + } + for (int i = 0; i < 4; i++) { + signBlock.line(i, miniMessage.deserialize(signLines.get(i), tagResolver)); + } + signBlock.update(true); + } + }.runTaskLater(PlayerShops.getInstance(), 2L); + } +} diff --git a/src/main/java/com/alttd/playershops/shop/SellShop.java b/src/main/java/com/alttd/playershops/shop/SellShop.java deleted file mode 100644 index 38e1ad3..0000000 --- a/src/main/java/com/alttd/playershops/shop/SellShop.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.alttd.playershops.shop; - -import org.bukkit.Location; -import org.bukkit.inventory.ItemStack; - -import java.util.UUID; - -public class SellShop extends AbstractShop { - - public SellShop(Location location, UUID player, double price, int amount) { - super(location, player, price, amount); - - this.setType(ShopType.SELL); - } - - public SellShop(int id, String ownerName, UUID ownerUUID, String server, - Location containerLocation, Location signLocation, double price, int amount, - double balance, ItemStack itemOne, ItemStack itemTwo, long lastTransaction) { - super(id, ownerName, ownerUUID, server, containerLocation, signLocation, price, amount, - balance, itemOne, itemTwo, lastTransaction); - this.setType(ShopType.SELL); - } - -} diff --git a/src/main/java/com/alttd/playershops/shop/ShopAction.java b/src/main/java/com/alttd/playershops/shop/ShopAction.java new file mode 100644 index 0000000..9b4fa4e --- /dev/null +++ b/src/main/java/com/alttd/playershops/shop/ShopAction.java @@ -0,0 +1,8 @@ +package com.alttd.playershops.shop; + +public enum ShopAction { + BUY, + SELL, + CREATE, + CANCELLED; +} diff --git a/src/main/java/com/alttd/playershops/shop/ShopInfo.java b/src/main/java/com/alttd/playershops/shop/ShopInfo.java new file mode 100644 index 0000000..38e4f24 --- /dev/null +++ b/src/main/java/com/alttd/playershops/shop/ShopInfo.java @@ -0,0 +1,4 @@ +package com.alttd.playershops.shop; + +public class ShopInfo { +} diff --git a/src/main/java/com/alttd/playershops/shop/ShopTransactionError.java b/src/main/java/com/alttd/playershops/shop/ShopTransactionError.java deleted file mode 100755 index 5affe5a..0000000 --- a/src/main/java/com/alttd/playershops/shop/ShopTransactionError.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.alttd.playershops.shop; - -public enum ShopTransactionError { - CANCELLED, - INSUFFICIENT_FUNDS_SHOP, - INSUFFICIENT_FUNDS_PLAYER, - INVENTORY_FULL_SHOP, - INVENTORY_FULL_PLAYER, - NONE; -} diff --git a/src/main/java/com/alttd/playershops/shop/ShopType.java b/src/main/java/com/alttd/playershops/shop/ShopType.java index 1916207..e6d378d 100644 --- a/src/main/java/com/alttd/playershops/shop/ShopType.java +++ b/src/main/java/com/alttd/playershops/shop/ShopType.java @@ -1,10 +1,22 @@ package com.alttd.playershops.shop; +import com.alttd.playershops.config.ShopTypeConfig; + public enum ShopType { - SELL, - BUY, - GAMBLE, - BARTER; + + DEFAULT(), + SELL(), + BUY(), + GAMBLE(); + + private ShopTypeConfig shopTypeConfig; + ShopType() { + this.shopTypeConfig = new ShopTypeConfig(this.toString()); + } + + public ShopTypeConfig getShopTypeConfig() { + return shopTypeConfig; + } @Override public String toString() { diff --git a/src/main/java/com/alttd/playershops/storage/DatabaseManager.java b/src/main/java/com/alttd/playershops/storage/DatabaseManager.java new file mode 100644 index 0000000..84e1541 --- /dev/null +++ b/src/main/java/com/alttd/playershops/storage/DatabaseManager.java @@ -0,0 +1,180 @@ +package com.alttd.playershops.storage; + +import com.alttd.playershops.PlayerShops; +import com.alttd.playershops.config.DatabaseConfig; +import com.alttd.playershops.storage.database.DatabaseQuery; +import lombok.Getter; +import org.bukkit.scheduler.BukkitRunnable; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.LinkedBlockingQueue; + +public class DatabaseManager { + + DatabaseQueue databaseQueue; + private final List CONNECTIONPOOL = new ArrayList<>(); + + public DatabaseManager(PlayerShops playerShops) { + databaseQueue = new DatabaseQueue(this); + int delay = DatabaseConfig.queueDelay * 20; + databaseQueue.runTaskTimerAsynchronously(playerShops, delay, delay); + } + + private DatabaseConnection getConnection() { + for (int i = 0; i < DatabaseConfig.maxDatabaseConnections; i++) { + DatabaseConnection connection = CONNECTIONPOOL.get(i); + if (connection == null) { + return genConnection(i); + } else if (!connection.isActive()) { + if (connection.isValid()) { + return connection; + } else { + connection.close(); + return genConnection(i); + } + } + } + + // This will cause an infinite running loop, throw an exception or wait for a connection to be available? + return getConnection(); + } + + private DatabaseConnection genConnection(int index) { + DatabaseConnection connection = new DatabaseConnection(); + CONNECTIONPOOL.set(index, connection); + + return connection; + } + + class DatabaseConnection implements AutoCloseable { + private Connection connection; + private volatile boolean isActive; + + DatabaseConnection() { + try { + openConnection(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + private synchronized void openConnection() throws SQLException { + if (connection != null && !connection.isClosed()) { + return; + } + + synchronized (this) { + if (connection != null && !connection.isClosed()) { + return; + } + try { + Class.forName("com.mysql.cj.jdbc.Driver"); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + + connection = DriverManager.getConnection( + "jdbc:mysql://" + DatabaseConfig.IP + ":" + DatabaseConfig.PORT + "/" + DatabaseConfig.DATABASE_NAME + + "?autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true", + DatabaseConfig.USERNAME, DatabaseConfig.PASSWORD); + } + } + + public synchronized Connection getConnection() { + try { + openConnection(); + } catch (SQLException e) { + e.printStackTrace(); + } + + return connection; + } + + public synchronized boolean isValid() { + try { + return !connection.isClosed() && connection.isValid(8000); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + + synchronized void setActive(boolean active) { + isActive = active; + } + + public synchronized boolean isActive() { + return isActive; + } + + @Override + public synchronized void close() { + try { + if (!connection.isClosed()) { + if (!connection.getAutoCommit()) { + connection.commit(); + } + connection.close(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + } + + class DatabaseQueue extends BukkitRunnable { + + private final DatabaseManager databaseManager; + + DatabaseQueue(DatabaseManager databaseManager) { + this.databaseManager = databaseManager; + } + @Getter + private static final Queue databaseQueryQueue = new LinkedBlockingQueue<>(); + + @Override + public void run() { + runTask(); + } + + public synchronized void runTask() { + if (databaseQueryQueue.isEmpty()) + return; + + DatabaseConnection databaseConnection = databaseManager.getConnection(); + Connection connection = databaseConnection.getConnection(); + + try { + connection.setAutoCommit(false); + while (!databaseQueryQueue.isEmpty()) { + if (!databaseConnection.isValid()) + return; + + DatabaseQuery databaseQuery = databaseQueryQueue.poll(); + if (databaseQuery == null) + return; + + databaseQuery.execute(connection); + } + if (!connection.getAutoCommit()) { + connection.commit(); + connection.setAutoCommit(true); + } + } catch (SQLException e) { + e.printStackTrace(); + } finally { + databaseConnection.setActive(false); + } + + } + } + + + +} diff --git a/src/main/java/com/alttd/playershops/storage/StorageManager.java b/src/main/java/com/alttd/playershops/storage/StorageManager.java new file mode 100644 index 0000000..af37ae2 --- /dev/null +++ b/src/main/java/com/alttd/playershops/storage/StorageManager.java @@ -0,0 +1,4 @@ +package com.alttd.playershops.storage; + +public class StorageManager { +} diff --git a/src/main/java/com/alttd/playershops/storage/database/Database.java b/src/main/java/com/alttd/playershops/storage/database/Database.java new file mode 100644 index 0000000..8c41356 --- /dev/null +++ b/src/main/java/com/alttd/playershops/storage/database/Database.java @@ -0,0 +1,117 @@ +package com.alttd.playershops.storage.database; + +import com.alttd.playershops.PlayerShops; +import com.alttd.playershops.config.DatabaseConfig; +import com.alttd.playershops.utils.Logger; +import org.bukkit.Bukkit; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public class Database { +// +// private static Database instance = null; +// private Connection connection = null; +// +// private Database() {} +// +// public static Database getDatabase(){ +// if (instance == null) +// { +// instance = new Database(); +// instance.init(); +// } +// return (instance); +// } +// +// protected void init() { +// try { +// openConnection(); +// } catch (SQLException e) { +// e.printStackTrace(); +// } +// +// //Run all create table functions +// for (Method method : Database.class.getDeclaredMethods()) { +// if (Modifier.isPrivate(method.getModifiers())) { +// if (method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE) { +// try { +// method.setAccessible(true); +// method.invoke(instance); +// } catch (InvocationTargetException ex) { +// throw new RuntimeException(ex.getCause()); +// } catch (Exception ex) { +// Logger.severe("Error invoking " + method + "."); +// ex.printStackTrace(); +// } +// } +// } +// } +// } +// +// /** +// * Opens the connection if it's not already open. +// * @throws SQLException If it can't create the connection. +// */ +// private void openConnection() throws SQLException { +// if (connection != null && !connection.isClosed()) { +// return; +// } +// +// synchronized (this) { +// if (connection != null && !connection.isClosed()) { +// return; +// } +// try { +// Class.forName("com.mysql.cj.jdbc.Driver"); +// } catch (ClassNotFoundException e) { +// e.printStackTrace(); +// } +// +// connection = DriverManager.getConnection( +// "jdbc:mysql://" + DatabaseConfig.IP + ":" + DatabaseConfig.PORT + "/" + DatabaseConfig.DATABASE_NAME + +// "?autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true", +// DatabaseConfig.USERNAME, DatabaseConfig.PASSWORD); +// } +// } +// +// public Connection getConnection() { +// try { +// openConnection(); +// } catch (SQLException e) { +// e.printStackTrace(); +// } +// return connection; +// } +// +// private static void createShopTable() { +// try { +// String sql = "CREATE TABLE IF NOT EXISTS shops(" + +// "id INT NOT NULL AUTO_INCREMENT, " + +// "owner_name VARCHAR(16) NOT NULL, " + +// "owner_uuid VARCHAR(36) NOT NULL, " + +// "shop_type VARCHAR(36) NOT NULL, " + +// "server VARCHAR(16) NOT NULL, " + +// "container_location VARCHAR(256), " + +// "sign_location VARCHAR(256), " + +// "price DOUBLE NOT NULL, " + +// "amount INT NOT NULL, " + +// "balance DOUBLE NOT NULL, " + +// "item_one TEXT, " + +// "last_transaction BIGINT, " + +// "PRIMARY KEY (id)" + +// ")"; +// getDatabase().getConnection().prepareStatement(sql).executeUpdate(); +// } catch (SQLException e) { +// e.printStackTrace(); +// Logger.severe("Error while trying to create shop table"); +// Logger.severe("Shutting down PlayerShops"); +// Bukkit.getPluginManager().disablePlugin(PlayerShops.getInstance()); +// } +// } + +} diff --git a/src/main/java/com/alttd/playershops/storage/database/DatabaseQuery.java b/src/main/java/com/alttd/playershops/storage/database/DatabaseQuery.java new file mode 100644 index 0000000..1b1af1a --- /dev/null +++ b/src/main/java/com/alttd/playershops/storage/database/DatabaseQuery.java @@ -0,0 +1,41 @@ +package com.alttd.playershops.storage.database; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public class DatabaseQuery { + + private final String statement; + private final DatabaseTask databaseTask; + + public DatabaseQuery(String statement, DatabaseTask databaseTask) { + this.statement = statement; + this.databaseTask = databaseTask; + } + + public DatabaseQuery(String statement) { + this(statement, ps -> {}); + } + + public void execute(Connection connection) { + try (PreparedStatement preparedStatement = connection.prepareStatement(statement)) { + databaseTask.edit(preparedStatement); + preparedStatement.execute(); + databaseTask.onSuccess(); + } catch (SQLException e) { + databaseTask.onFailure(e); + } + } + + public interface DatabaseTask { + + void edit(PreparedStatement preparedStatement); + + default void onSuccess() {}; + + default void onFailure(SQLException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/alttd/playershops/storage/database/ShopQueries.java b/src/main/java/com/alttd/playershops/storage/database/ShopQueries.java new file mode 100644 index 0000000..d87d059 --- /dev/null +++ b/src/main/java/com/alttd/playershops/storage/database/ShopQueries.java @@ -0,0 +1,149 @@ +package com.alttd.playershops.storage.database; + +import com.alttd.playershops.shop.PlayerShop; +import com.alttd.playershops.shop.ShopType; +import com.alttd.playershops.utils.AMath; +import com.alttd.playershops.utils.Logger; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.inventory.ItemStack; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class ShopQueries { +// +// public static boolean saveShop(PlayerShop shop) { +// String sql = "INSERT INTO shops " + +// "(id, owner_name, owner_uuid, shop_type, server, container_location, sign_location, " + +// "price, amount, balance, item_one, item_two, last_transaction)" + +// "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + +// "ON DUPLICATE KEY UPDATE owner_name = ?, owner_uuid = ?, shop_type = ?, server = ?, " + +// "container_location = ?, sign_location = ?, price = ?, amount = ?, balance = ?, " + +// "item_one = ?, last_transaction = ?"; +// try { +// PreparedStatement statement = Database.getDatabase().getConnection().prepareStatement(sql); +// +// statement.setInt(1, shop.getId()); +// statement.setString(2, shop.getOwnerName()); +// statement.setString(3, shop.getOwnerUUID().toString()); +// statement.setString(4, shop.getServer()); +// statement.setString(5, shop.getType().toString()); +// statement.setString(6, locationToString(shop.getShopLocation())); +// statement.setString(7, locationToString(shop.getSignLocation())); +// statement.setDouble(8, shop.getPrice()); +// statement.setInt(9, shop.getAmount()); +// statement.setDouble(10, shop.getBalance()); +// statement.setBytes(11, shop.getItemStack().serializeAsBytes()); +// statement.setLong(12, shop.getLastTransaction()); +// //repeat everything except id for update +// statement.setString(13, shop.getOwnerName()); +// statement.setString(14, shop.getOwnerUUID().toString()); +// statement.setString(15, shop.getServer()); +// statement.setString(16, shop.getType().toString()); +// statement.setString(17, locationToString(shop.getShopLocation())); +// statement.setString(18, locationToString(shop.getSignLocation())); +// statement.setDouble(19, shop.getPrice()); +// statement.setInt(20, shop.getAmount()); +// statement.setDouble(21, shop.getBalance()); +// statement.setBytes(22, shop.getItemStack().serializeAsBytes()); +// statement.setLong(23, shop.getLastTransaction()); +// +// return statement.executeUpdate() == 1; +// } catch (SQLException e) { +// e.printStackTrace(); +// } +// return false; +// } +// +// public static PlayerShop loadShop(int id) { +// String sql = "SELECT * FROM shops WHERE id = ?"; +// try { +// PreparedStatement statement = Database.getDatabase().getConnection().prepareStatement(sql); +// +// statement.setInt(1, id); +// ResultSet resultSet = statement.executeQuery(); +// if (resultSet.next()) +// return shopFromResultSet(resultSet); +// } catch (SQLException e) { +// e.printStackTrace(); +// } +// return null; +// } +// +// public static List loadShops() { +// String sql = "SELECT * FROM shops"; +// ArrayList shops = new ArrayList<>(); +// try { +// PreparedStatement statement = Database.getDatabase().getConnection().prepareStatement(sql); +// +// ResultSet resultSet = statement.executeQuery(); +// while (resultSet.next()) { +// PlayerShop shop = shopFromResultSet(resultSet); +// if (shop == null) { +// Logger.warn("Tried to load a shop but failed [" + resultSet + "]"); +// continue; +// } +// shops.add(shop); +// } +// } catch (SQLException e) { +// e.printStackTrace(); +// } +// return shops; +// } +// +// /** +// * Loads a shop from a result set, does not iterate +// * @param resultSet Result set to load from +// * @return A shop +// * @throws SQLException if data is missing or formatted incorrectly +// */ +// private static PlayerShop shopFromResultSet(ResultSet resultSet) throws SQLException { +// int id = resultSet.getInt("id"); +// String ownerName = resultSet.getString("owner_name"); +// UUID ownerUuid = UUID.fromString(resultSet.getString("owner_uuid")); +// ShopType shopType = ShopType.valueOf(resultSet.getString("shop_type")); +// String server = resultSet.getString("server"); +// Location containerLocation = stringToLocation(resultSet.getString("container_location")); +// Location signLocation = stringToLocation(resultSet.getString("sign_location")); +// double price = resultSet.getDouble("price"); +// int amount = resultSet.getInt("amount"); +// double balance = resultSet.getDouble("balance"); +// ItemStack itemOne = ItemStack.deserializeBytes(resultSet.getBytes("item_one")); +//// ItemStack itemTwo = ItemStack.deserializeBytes(resultSet.getBytes("item_two")); +// long lastTransaction = resultSet.getLong("last_transaction"); +// +// if (containerLocation == null || signLocation == null) +// return null; +// +// return PlayerShop.create(id, ownerName, ownerUuid, shopType, server, containerLocation, signLocation, +// price, amount, balance, itemOne, lastTransaction); +// } +// +// private static String locationToString(Location location) { +// return location.getWorld() + ":" + +// AMath.round(location.getX(), 1) + ":" + +// AMath.round(location.getY(), 1) + ":" + +// AMath.round(location.getZ(), 1); +// } +// +// private static Location stringToLocation(String string) { +// String[] split = string.split(":"); +// if (split.length != 4) { +// Logger.warn("Unable to load location [" + string + "] due to invalid format"); +// return null; +// } +// +// try { +// return new Location(Bukkit.getWorld(split[0]), +// Double.parseDouble(split[1]), Double.parseDouble(split[2]), Double.parseDouble(split[3])); +// } catch (NumberFormatException e) { +// Logger.warn("Unable to load location [" + string + "] due to invalid format"); +// return null; +// } +// } +} diff --git a/src/main/java/com/alttd/playershops/utils/ShopUtil.java b/src/main/java/com/alttd/playershops/utils/ShopUtil.java new file mode 100644 index 0000000..c085887 --- /dev/null +++ b/src/main/java/com/alttd/playershops/utils/ShopUtil.java @@ -0,0 +1,152 @@ +package com.alttd.playershops.utils; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; + +import java.util.Map; + +public class ShopUtil { + + /** + * Counts the number of items in the given inventory where + * Util.matches(inventory item, item) is true. + * + * @param inv + * The inventory to search + * @param item + * The ItemStack to search for + * @return The number of items that match in this inventory. + */ + public static int countItems(Inventory inv, ItemStack item) { + int items = 0; + for (ItemStack iStack : inv.getContents()) { + if (iStack == null) + continue; + if (ShopUtil.matches(item, iStack)) { + items += iStack.getAmount(); + } + } + return items; + } + + /** + * Returns true if the given location is loaded or not. + * + * @param loc + * The location + * @return true if the given location is loaded or not. + */ + public static boolean isLoaded(Location loc) { + // System.out.println("Checking isLoaded(Location loc)"); + if (loc.getWorld() == null) { + // System.out.println("Is not loaded. (No world)"); + return false; + } + // Calculate the chunks coordinates. These are 1,2,3 for each chunk, NOT + // location rounded to the nearest 16. + int x = (int) Math.floor((loc.getBlockX()) / 16.0); + int z = (int) Math.floor((loc.getBlockZ()) / 16.0); + if (loc.getWorld().isChunkLoaded(x, z)) { + // System.out.println("Chunk is loaded " + x + ", " + z); + return true; + } else { + // System.out.println("Chunk is NOT loaded " + x + ", " + z); + return false; + } + } + + /** + * Compares two items to each other. Returns true if they match. + * + * @param stack1 + * The first item stack + * @param stack2 + * The second item stack + * @return true if the itemstacks match. (Material, durability, enchants, name) + */ + public static boolean matches(ItemStack stack1, ItemStack stack2) { + if (stack1 == stack2) + return true; // Referring to the same thing, or both are null. + if (stack1 == null || stack2 == null) + return false; // One of them is null (Can't be both, see above) + if (stack1.getType() != stack2.getType()) + return false; // Not the same material + if (stack1.getDurability() != stack2.getDurability()) + return false; // Not the same durability + if (!stack1.getEnchantments().equals(stack2.getEnchantments())) + return false; // They have the same enchants + if (stack1.getItemMeta().hasDisplayName() || stack2.getItemMeta().hasDisplayName()) { + if (stack1.getItemMeta().hasDisplayName() && stack2.getItemMeta().hasDisplayName()) { + if (!stack1.getItemMeta().getDisplayName().equals(stack2.getItemMeta().getDisplayName())) { + return false; // items have different display name + } + } else { + return false; // one of the item stacks have a display name + } + } + try { + Class.forName("org.bukkit.inventory.meta.EnchantmentStorageMeta"); + boolean book1 = stack1.getItemMeta() instanceof EnchantmentStorageMeta; + boolean book2 = stack2.getItemMeta() instanceof EnchantmentStorageMeta; + if (book1 != book2) + return false;// One has enchantment meta, the other does not. + if (book1 == true) { // They are the same here (both true or both + // false). So if one is true, the other is + // true. + Map ench1 = ((EnchantmentStorageMeta) stack1.getItemMeta()).getStoredEnchants(); + Map ench2 = ((EnchantmentStorageMeta) stack2.getItemMeta()).getStoredEnchants(); + if (!ench1.equals(ench2)) + return false; // Enchants aren't the same. + } + } catch (ClassNotFoundException e) { + } + return true; + } + + /** + * Returns the number of items that can be given to the inventory safely. + * + * @param inv + * The inventory to count + * @param item + * The item. Material, durabiltiy and enchants must + * match for 'stackability' to occur. + * @return The number of items that can be given to the inventory safely. + */ + public static int countSpace(Inventory inv, ItemStack item) { + int space = 0; + + try { + ItemStack[] contents = inv.getContents(); + for (ItemStack iStack : contents) { + if (iStack == null || iStack.getType() == Material.AIR) { + space += item.getMaxStackSize(); + } else if (matches(item, iStack)) { + space += item.getMaxStackSize() - iStack.getAmount(); + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + return space; + } + + public static String serialize(ItemStack itemStack) { + YamlConfiguration cfg = new YamlConfiguration(); + cfg.set("item", itemStack); + return cfg.saveToString(); + } + + public static ItemStack deserialize(String config) throws InvalidConfigurationException { + YamlConfiguration cfg = new YamlConfiguration(); + cfg.loadFromString(config); + ItemStack stack = cfg.getItemStack("item"); + return stack; + } +}