Update project
This commit is contained in:
parent
9b9eb2b39b
commit
d723697be8
141
build.gradle
141
build.gradle
@ -1,64 +1,79 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'java'
|
id 'java'
|
||||||
}
|
id 'com.github.johnrengelman.shadow' version '7.1.2'
|
||||||
|
id 'xyz.jpenilla.run-paper' version '2.2.0'
|
||||||
group = 'ru.redguy'
|
}
|
||||||
version = '1.0.0'
|
|
||||||
|
group = 'ru.redguy'
|
||||||
repositories {
|
version = '1.0.0'
|
||||||
maven {
|
|
||||||
name = 'redguy-repo'
|
repositories {
|
||||||
url = 'https://rep.redguy.org/repo/maven-minecraft/'
|
maven {
|
||||||
}
|
name = 'redguy-repo'
|
||||||
mavenCentral()
|
url = 'https://rep.redguy.org/repo/maven-minecraft/'
|
||||||
maven {
|
}
|
||||||
name = 'papermc-repo'
|
mavenCentral()
|
||||||
url = 'https://papermc.io/repo/repository/maven-public/'
|
maven {
|
||||||
}
|
name = 'papermc-repo'
|
||||||
maven {
|
url = 'https://papermc.io/repo/repository/maven-public/'
|
||||||
name = 'sonatype'
|
}
|
||||||
url = 'https://oss.sonatype.org/content/groups/public/'
|
maven {
|
||||||
}
|
name = 'sonatype'
|
||||||
}
|
url = 'https://oss.sonatype.org/content/groups/public/'
|
||||||
|
}
|
||||||
dependencies {
|
}
|
||||||
compileOnly 'com.destroystokyo.paper:paper-api:1.16.5-R0.1-SNAPSHOT'
|
|
||||||
compileOnly 'me.filoghost.chestcommands:chestcommands-api:4.0.3'
|
dependencies {
|
||||||
compileOnly 'net.milkbowl.vault:VaultAPI:1.7'
|
compileOnly 'com.destroystokyo.paper:paper-api:1.16.5-R0.1-SNAPSHOT'
|
||||||
|
compileOnly 'me.filoghost.chestcommands:chestcommands-api:4.0.4'
|
||||||
implementation 'org.jetbrains:annotations:23.0.0'
|
compileOnly 'net.milkbowl.vault:VaultAPI:1.7'
|
||||||
}
|
implementation 'org.jetbrains:annotations:23.0.0'
|
||||||
|
}
|
||||||
def targetJavaVersion = 8
|
|
||||||
java {
|
def targetJavaVersion = 8
|
||||||
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
|
java {
|
||||||
sourceCompatibility = javaVersion
|
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
|
||||||
targetCompatibility = javaVersion
|
sourceCompatibility = javaVersion
|
||||||
if (JavaVersion.current() < javaVersion) {
|
targetCompatibility = javaVersion
|
||||||
toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
|
if (JavaVersion.current() < javaVersion) {
|
||||||
}
|
toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
tasks.withType(JavaCompile).configureEach {
|
|
||||||
if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) {
|
tasks.withType(JavaCompile).configureEach {
|
||||||
options.release = targetJavaVersion
|
if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) {
|
||||||
}
|
options.release = targetJavaVersion
|
||||||
}
|
}
|
||||||
|
}
|
||||||
compileJava.options.encoding = 'UTF-8'
|
|
||||||
|
compileJava.options.encoding = 'UTF-8'
|
||||||
processResources {
|
|
||||||
def props = [version: version]
|
shadowJar {
|
||||||
inputs.properties props
|
archiveClassifier.set('')
|
||||||
filteringCharset 'UTF-8'
|
configurations = [project.configurations.implementation]
|
||||||
filesMatching('plugin.yml') {
|
}
|
||||||
expand props
|
|
||||||
}
|
tasks {
|
||||||
}
|
runServer {
|
||||||
|
minecraftVersion('1.16.5')
|
||||||
jar {
|
|
||||||
configurations.implementation.canBeResolved = true;
|
// Download required plugins
|
||||||
from {
|
downloadPlugins {
|
||||||
configurations.implementation.collect { it.isDirectory() ? it : zipTree(it) }
|
url('https://github.com/MilkBowl/Vault/releases/download/1.7.3/Vault.jar')
|
||||||
}
|
url('https://ci.codemc.io/job/filoghost/job/ChestCommands/lastSuccessfulBuild/artifact/ChestCommands-4.0.5.jar')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processResources {
|
||||||
|
def props = [version: version]
|
||||||
|
inputs.properties props
|
||||||
|
filteringCharset 'UTF-8'
|
||||||
|
filesMatching('plugin.yml') {
|
||||||
|
expand props
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
configurations.implementation.canBeResolved = true;
|
||||||
}
|
}
|
@ -7,6 +7,7 @@ import org.bukkit.plugin.java.JavaPlugin;
|
|||||||
import ru.redguy.dynamicshop.api.ShopItem;
|
import ru.redguy.dynamicshop.api.ShopItem;
|
||||||
import ru.redguy.dynamicshop.commands.AddShopItemCommand;
|
import ru.redguy.dynamicshop.commands.AddShopItemCommand;
|
||||||
import ru.redguy.dynamicshop.commands.ShopCommand;
|
import ru.redguy.dynamicshop.commands.ShopCommand;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public final class DynamicShop extends JavaPlugin {
|
public final class DynamicShop extends JavaPlugin {
|
||||||
|
|
||||||
@ -15,29 +16,43 @@ public final class DynamicShop extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static DynamicShop instance;
|
private static DynamicShop instance;
|
||||||
|
private Economy economy;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
public static DynamicShop getInstance() {
|
public static DynamicShop getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
throw new IllegalStateException("Plugin instance not initialized!");
|
||||||
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Economy econ;
|
public Economy getEconomy() {
|
||||||
|
return economy;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
instance = this;
|
instance = this;
|
||||||
getConfig().set("init",true);
|
|
||||||
saveConfig();
|
// Save default config if it doesn't exist
|
||||||
if(!setupEconomy()) {
|
saveDefaultConfig();
|
||||||
getLogger().warning("Cannot find economy!");
|
|
||||||
|
// Setup economy
|
||||||
|
if (!setupEconomy()) {
|
||||||
|
getLogger().severe("Disabled due to no Vault dependency found!");
|
||||||
|
getServer().getPluginManager().disablePlugin(this);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
getServer().getCommandMap().register("shop","shop",new ShopCommand("shop"));
|
|
||||||
getServer().getCommandMap().register("additem","shop",new AddShopItemCommand("additem"));
|
// Register commands
|
||||||
getServer().getCommandMap().register("reloadshop","shop",new AddShopItemCommand("reloadshop"));
|
registerCommands();
|
||||||
|
|
||||||
|
getLogger().info("DynamicShop has been enabled!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
|
getLogger().info("DynamicShop has been disabled!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean setupEconomy() {
|
private boolean setupEconomy() {
|
||||||
@ -48,7 +63,18 @@ public final class DynamicShop extends JavaPlugin {
|
|||||||
if (rsp == null) {
|
if (rsp == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
econ = rsp.getProvider();
|
economy = rsp.getProvider();
|
||||||
return true;
|
return economy != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerCommands() {
|
||||||
|
try {
|
||||||
|
getServer().getCommandMap().register("shop", "dynamicshop", new ShopCommand("shop"));
|
||||||
|
getServer().getCommandMap().register("additem", "dynamicshop", new AddShopItemCommand("additem"));
|
||||||
|
getServer().getCommandMap().register("reloadshop", "dynamicshop", new AddShopItemCommand("reloadshop"));
|
||||||
|
getLogger().info("Commands registered successfully!");
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().severe("Failed to register commands: " + e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,91 +1,130 @@
|
|||||||
package ru.redguy.dynamicshop.api;
|
package ru.redguy.dynamicshop.api;
|
||||||
|
|
||||||
import org.bukkit.configuration.InvalidConfigurationException;
|
import org.bukkit.configuration.InvalidConfigurationException;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import ru.redguy.dynamicshop.DynamicShop;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import ru.redguy.dynamicshop.DynamicShop;
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
public class Database {
|
import java.util.logging.Level;
|
||||||
private static final Database instance = new Database();
|
|
||||||
|
public class Database {
|
||||||
public static Database getInstance() {
|
private static final Database instance = new Database();
|
||||||
return instance;
|
private final File file;
|
||||||
}
|
private final YamlConfiguration config;
|
||||||
|
private static final String ITEMS_KEY = "items";
|
||||||
private final File file = new File(DynamicShop.getInstance().getDataFolder(), "items.yml");
|
|
||||||
private final YamlConfiguration conf = new YamlConfiguration();
|
private Database() {
|
||||||
|
this.file = new File(DynamicShop.getInstance().getDataFolder(), "items.yml");
|
||||||
public Database() {
|
this.config = new YamlConfiguration();
|
||||||
load();
|
loadDatabase();
|
||||||
save();
|
}
|
||||||
}
|
|
||||||
|
@NotNull
|
||||||
public void load() {
|
public static Database getInstance() {
|
||||||
try {
|
return instance;
|
||||||
conf.load(file);
|
}
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
try {
|
private synchronized void loadDatabase() {
|
||||||
file.createNewFile();
|
try {
|
||||||
} catch (IOException ex) {
|
if (!file.exists()) {
|
||||||
throw new RuntimeException(ex);
|
DynamicShop.getInstance().getDataFolder().mkdirs();
|
||||||
}
|
file.createNewFile();
|
||||||
try {
|
}
|
||||||
conf.load(file);
|
config.load(file);
|
||||||
} catch (IOException | InvalidConfigurationException ex) {
|
} catch (IOException | InvalidConfigurationException e) {
|
||||||
throw new RuntimeException(ex);
|
DynamicShop.getInstance().getLogger().log(Level.SEVERE, "Failed to load database", e);
|
||||||
}
|
throw new RuntimeException("Failed to load database", e);
|
||||||
} catch (IOException | InvalidConfigurationException e) {
|
}
|
||||||
throw new RuntimeException(e);
|
}
|
||||||
}
|
|
||||||
}
|
private synchronized void saveDatabase() {
|
||||||
|
try {
|
||||||
private void save() {
|
config.save(file);
|
||||||
try {
|
} catch (IOException e) {
|
||||||
conf.save(file);
|
DynamicShop.getInstance().getLogger().log(Level.SEVERE, "Failed to save database", e);
|
||||||
} catch (IOException e) {
|
throw new RuntimeException("Failed to save database", e);
|
||||||
throw new RuntimeException(e);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@NotNull
|
||||||
public List<ShopItem> getItems() {
|
public synchronized List<ShopItem> getItems() {
|
||||||
List<?> list = conf.getList("items");
|
List<?> list = config.getList(ITEMS_KEY);
|
||||||
if(list == null) list = new ArrayList<>();
|
if (list == null) {
|
||||||
List<ShopItem> shopItems = new ArrayList<>();
|
return new ArrayList<>();
|
||||||
for (Object o : list) {
|
}
|
||||||
if(o instanceof ShopItem) {
|
|
||||||
shopItems.add((ShopItem) o);
|
List<ShopItem> shopItems = new ArrayList<>();
|
||||||
}
|
for (Object obj : list) {
|
||||||
}
|
if (obj instanceof ShopItem) {
|
||||||
return shopItems;
|
shopItems.add((ShopItem) obj);
|
||||||
}
|
} else {
|
||||||
|
DynamicShop.getInstance().getLogger().warning("Found invalid item in database: " + obj);
|
||||||
public void setItems(List<ShopItem> items) {
|
}
|
||||||
conf.set("items",items);
|
}
|
||||||
save();
|
return Collections.unmodifiableList(shopItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
public synchronized void setItems(@NotNull List<ShopItem> items) {
|
||||||
public ShopItem getItem(int index) {
|
if (items == null) {
|
||||||
List<ShopItem> items = getItems();
|
throw new IllegalArgumentException("Items list cannot be null");
|
||||||
if(items.size()<=index) return null;
|
}
|
||||||
return items.get(index);
|
config.set(ITEMS_KEY, new ArrayList<>(items)); // Create a copy to prevent external modification
|
||||||
}
|
saveDatabase();
|
||||||
|
}
|
||||||
public void setItem(int index, ShopItem item) {
|
|
||||||
List<ShopItem> items = getItems();
|
@Nullable
|
||||||
items.set(index,item);
|
public synchronized ShopItem getItem(int index) {
|
||||||
setItems(items);
|
List<ShopItem> items = getItems();
|
||||||
}
|
if (index < 0 || index >= items.size()) {
|
||||||
|
return null;
|
||||||
public void addItem(ShopItem item) {
|
}
|
||||||
List<ShopItem> items = getItems();
|
return items.get(index).clone(); // Return a clone to prevent modification
|
||||||
items.add(item);
|
}
|
||||||
setItems(items);
|
|
||||||
}
|
public synchronized void setItem(int index, @NotNull ShopItem item) {
|
||||||
}
|
if (item == null) {
|
||||||
|
throw new IllegalArgumentException("Item cannot be null");
|
||||||
|
}
|
||||||
|
List<ShopItem> items = new ArrayList<>(getItems());
|
||||||
|
if (index < 0) {
|
||||||
|
throw new IllegalArgumentException("Index cannot be negative");
|
||||||
|
}
|
||||||
|
if (index >= items.size()) {
|
||||||
|
throw new IllegalArgumentException("Index " + index + " is out of bounds for size " + items.size());
|
||||||
|
}
|
||||||
|
items.set(index, item);
|
||||||
|
setItems(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void addItem(@NotNull ShopItem item) {
|
||||||
|
if (item == null) {
|
||||||
|
throw new IllegalArgumentException("Item cannot be null");
|
||||||
|
}
|
||||||
|
List<ShopItem> items = new ArrayList<>(getItems());
|
||||||
|
items.add(item);
|
||||||
|
setItems(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void removeItem(int index) {
|
||||||
|
List<ShopItem> items = new ArrayList<>(getItems());
|
||||||
|
if (index < 0 || index >= items.size()) {
|
||||||
|
throw new IllegalArgumentException("Index " + index + " is out of bounds for size " + items.size());
|
||||||
|
}
|
||||||
|
items.remove(index);
|
||||||
|
setItems(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void clear() {
|
||||||
|
setItems(new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized int size() {
|
||||||
|
return getItems().size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,73 +1,102 @@
|
|||||||
package ru.redguy.dynamicshop.api;
|
package ru.redguy.dynamicshop.api;
|
||||||
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||||
import org.bukkit.configuration.serialization.SerializableAs;
|
import org.bukkit.configuration.serialization.SerializableAs;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
@SerializableAs("ShopItem")
|
|
||||||
public class ShopItem implements Cloneable, ConfigurationSerializable {
|
@SerializableAs("ShopItem")
|
||||||
private ItemStack item;
|
public class ShopItem implements Cloneable, ConfigurationSerializable {
|
||||||
private double price;
|
private final ItemStack item;
|
||||||
|
private final double price;
|
||||||
public ShopItem(ItemStack item, double price) {
|
|
||||||
this.item = item;
|
/**
|
||||||
this.price = price;
|
* Creates a new shop item
|
||||||
}
|
*
|
||||||
|
* @param item The item to sell
|
||||||
public ItemStack getItem() {
|
* @param price The price of the item
|
||||||
return item;
|
* @throws IllegalArgumentException if item is null or price is negative
|
||||||
}
|
*/
|
||||||
|
public ShopItem(@NotNull ItemStack item, double price) {
|
||||||
public void setItem(ItemStack item) {
|
if (item == null || item.getType() == Material.AIR) {
|
||||||
this.item = item;
|
throw new IllegalArgumentException("Item cannot be null or AIR");
|
||||||
}
|
}
|
||||||
|
if (price < 0) {
|
||||||
public double getPrice() {
|
throw new IllegalArgumentException("Price cannot be negative");
|
||||||
return price;
|
}
|
||||||
}
|
this.item = item.clone(); // Defensive copy
|
||||||
|
this.price = price;
|
||||||
public void setPrice(double price) {
|
}
|
||||||
this.price = price;
|
|
||||||
}
|
/**
|
||||||
|
* Gets the item being sold
|
||||||
@Contract("_ -> new")
|
*
|
||||||
public static @NotNull ShopItem deserialize(@NotNull Map<String, Object> args) {
|
* @return A copy of the item
|
||||||
ItemStack item = new ItemStack(Material.AIR);
|
*/
|
||||||
double price = 0;
|
@NotNull
|
||||||
if(args.containsKey("item")) {
|
public ItemStack getItem() {
|
||||||
item = (ItemStack) args.get("item");
|
return item.clone(); // Return defensive copy
|
||||||
}
|
}
|
||||||
|
|
||||||
if(args.containsKey("price")) {
|
/**
|
||||||
price = (Double) args.get("price");
|
* Gets the price of the item
|
||||||
}
|
*
|
||||||
|
* @return The price
|
||||||
return new ShopItem(item,price);
|
*/
|
||||||
}
|
public double getPrice() {
|
||||||
|
return price;
|
||||||
@Override
|
}
|
||||||
public @NotNull Map<String, Object> serialize() {
|
|
||||||
HashMap<String, Object> map = new HashMap<>();
|
@Contract("_ -> new")
|
||||||
map.put("item",item);
|
public static @NotNull ShopItem deserialize(@NotNull Map<String, Object> args) {
|
||||||
map.put("price",price);
|
ItemStack item = args.containsKey("item") ? (ItemStack) args.get("item") : new ItemStack(Material.AIR);
|
||||||
return map;
|
double price = args.containsKey("price") ? (Double) args.get("price") : 0.0;
|
||||||
}
|
|
||||||
|
return new ShopItem(item, price);
|
||||||
@Override
|
}
|
||||||
public ShopItem clone() {
|
|
||||||
try {
|
@Override
|
||||||
ShopItem clone = (ShopItem) super.clone();
|
public @NotNull Map<String, Object> serialize() {
|
||||||
clone.item = item;
|
Map<String, Object> map = new HashMap<>();
|
||||||
clone.price = price;
|
map.put("item", item);
|
||||||
return clone;
|
map.put("price", price);
|
||||||
} catch (CloneNotSupportedException e) {
|
return map;
|
||||||
throw new AssertionError();
|
}
|
||||||
}
|
|
||||||
}
|
@Override
|
||||||
}
|
public ShopItem clone() {
|
||||||
|
try {
|
||||||
|
return new ShopItem(this.item.clone(), this.price);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new AssertionError("Failed to clone ShopItem: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (!(o instanceof ShopItem)) return false;
|
||||||
|
ShopItem shopItem = (ShopItem) o;
|
||||||
|
return Double.compare(shopItem.price, price) == 0 &&
|
||||||
|
Objects.equals(item, shopItem.item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(item, price);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ShopItem{" +
|
||||||
|
"item=" + item +
|
||||||
|
", price=" + price +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,31 +1,83 @@
|
|||||||
package ru.redguy.dynamicshop.commands;
|
package ru.redguy.dynamicshop.commands;
|
||||||
|
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import ru.redguy.dynamicshop.api.Database;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import ru.redguy.dynamicshop.api.ShopItem;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import ru.redguy.dynamicshop.gui.ShopGuiSell;
|
import ru.redguy.dynamicshop.api.Database;
|
||||||
|
import ru.redguy.dynamicshop.api.ShopItem;
|
||||||
public class AddShopItemCommand extends Command {
|
import ru.redguy.dynamicshop.gui.ShopGuiSell;
|
||||||
public AddShopItemCommand(@NotNull String name) {
|
|
||||||
super(name);
|
import java.util.Collections;
|
||||||
}
|
import java.util.List;
|
||||||
|
|
||||||
@Override
|
public class AddShopItemCommand extends Command {
|
||||||
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
|
public AddShopItemCommand(@NotNull String name) {
|
||||||
if(!(sender instanceof Player)) return true;
|
super(name);
|
||||||
if(!sender.hasPermission("dynshop.add")) return true;
|
this.setDescription("Add an item to the shop");
|
||||||
if(args.length!=1) return true;
|
this.setUsage("§c/additem <price>");
|
||||||
Database.getInstance().addItem(new ShopItem(((Player) sender).getInventory().getItemInMainHand().clone(),Double.parseDouble(args[0].replace(',','.'))));
|
this.setPermission("dynshop.add");
|
||||||
ShopGuiSell.update();
|
}
|
||||||
return true;
|
|
||||||
}
|
@Override
|
||||||
|
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
|
||||||
@Override
|
if (!(sender instanceof Player)) {
|
||||||
public @Nullable String getPermission() {
|
sender.sendMessage(ChatColor.RED + "This command can only be used by players!");
|
||||||
return "dynshop.add";
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
Player player = (Player) sender;
|
||||||
|
|
||||||
|
if (!player.hasPermission("dynshop.add")) {
|
||||||
|
player.sendMessage(ChatColor.RED + "You don't have permission to add items to the shop!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length != 1) {
|
||||||
|
player.sendMessage(this.getUsage());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack itemInHand = player.getInventory().getItemInMainHand();
|
||||||
|
if (itemInHand == null || itemInHand.getType().isAir()) {
|
||||||
|
player.sendMessage(ChatColor.RED + "You must hold an item to add it to the shop!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
double price;
|
||||||
|
try {
|
||||||
|
price = Double.parseDouble(args[0].replace(',', '.'));
|
||||||
|
if (price < 0) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Price cannot be negative!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Invalid price format! Use numbers only.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ShopItem shopItem = new ShopItem(itemInHand.clone(), price);
|
||||||
|
Database.getInstance().addItem(shopItem);
|
||||||
|
ShopGuiSell.update();
|
||||||
|
player.sendMessage(ChatColor.GREEN + "Item successfully added to the shop for " + price + "!");
|
||||||
|
} catch (Exception e) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Failed to add item to the shop: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) {
|
||||||
|
return Collections.emptyList(); // No tab completion for price
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable String getPermission() {
|
||||||
|
return "dynshop.add";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,40 +1,71 @@
|
|||||||
package ru.redguy.dynamicshop.commands;
|
package ru.redguy.dynamicshop.commands;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import ru.redguy.dynamicshop.gui.ShopGuiBuy;
|
import ru.redguy.dynamicshop.gui.ShopGuiBuy;
|
||||||
import ru.redguy.dynamicshop.gui.ShopGuiSell;
|
import ru.redguy.dynamicshop.gui.ShopGuiSell;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.Arrays;
|
||||||
import java.util.stream.Collectors;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
public class ShopCommand extends Command {
|
|
||||||
public ShopCommand(@NotNull String name) {
|
public class ShopCommand extends Command {
|
||||||
super(name);
|
private static final String[] SUBCOMMANDS = {"sell", "buy"};
|
||||||
}
|
|
||||||
|
public ShopCommand(@NotNull String name) {
|
||||||
@Override
|
super(name);
|
||||||
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
|
this.setDescription("Main shop command");
|
||||||
if(args.length!=1) return true;
|
this.setUsage("§c/shop <sell|buy>");
|
||||||
if(sender instanceof Player) {
|
this.setPermission("dynshop.use");
|
||||||
if(args[0].equals("sell")) {
|
}
|
||||||
ShopGuiSell.open((Player) sender);
|
|
||||||
}
|
@Override
|
||||||
if(args[0].equals("buy")) {
|
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
|
||||||
ShopGuiBuy.open((Player) sender);
|
if (!(sender instanceof Player)) {
|
||||||
}
|
sender.sendMessage(ChatColor.RED + "This command can only be used by players!");
|
||||||
}
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
|
Player player = (Player) sender;
|
||||||
@Override
|
|
||||||
public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException {
|
if (!player.hasPermission("dynshop.use")) {
|
||||||
String[] subCommands = {"sell","buy"};
|
player.sendMessage(ChatColor.RED + "You don't have permission to use this command!");
|
||||||
if(args.length!=1) return Lists.newArrayList();
|
return true;
|
||||||
return Arrays.stream(subCommands).filter(s -> s.startsWith(args[0])).collect(Collectors.toList());
|
}
|
||||||
}
|
|
||||||
}
|
if (args.length != 1) {
|
||||||
|
player.sendMessage(this.getUsage());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String subCommand = args[0].toLowerCase();
|
||||||
|
switch (subCommand) {
|
||||||
|
case "sell":
|
||||||
|
ShopGuiSell.open(player);
|
||||||
|
break;
|
||||||
|
case "buy":
|
||||||
|
ShopGuiBuy.open(player);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
player.sendMessage(this.getUsage());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException {
|
||||||
|
if (!(sender instanceof Player) || !sender.hasPermission("dynshop.use") || args.length != 1) {
|
||||||
|
return Lists.newArrayList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Arrays.stream(SUBCOMMANDS)
|
||||||
|
.filter(s -> s.toLowerCase().startsWith(args[0].toLowerCase()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -16,7 +16,6 @@ public class ShopReloadCommand extends Command {
|
|||||||
@Override
|
@Override
|
||||||
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
|
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
|
||||||
if(!sender.hasPermission("dynshop.reload")) return true;
|
if(!sender.hasPermission("dynshop.reload")) return true;
|
||||||
Database.getInstance().load();
|
|
||||||
ShopGuiBuy.update();
|
ShopGuiBuy.update();
|
||||||
ShopGuiSell.update();
|
ShopGuiSell.update();
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,30 +1,64 @@
|
|||||||
package ru.redguy.dynamicshop.gui;
|
package ru.redguy.dynamicshop.gui;
|
||||||
|
|
||||||
import me.filoghost.chestcommands.api.Menu;
|
import me.filoghost.chestcommands.api.Menu;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.ChatColor;
|
||||||
import ru.redguy.dynamicshop.DynamicShop;
|
import org.bukkit.entity.Player;
|
||||||
import ru.redguy.dynamicshop.gui.icons.ItemIconBuy;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.redguy.dynamicshop.DynamicShop;
|
||||||
public class ShopGuiBuy {
|
import ru.redguy.dynamicshop.gui.icons.ItemIconBuy;
|
||||||
private static final Menu menu = Menu.create(DynamicShop.getInstance(),"Магазин | Покупка",6);
|
|
||||||
|
public class ShopGuiBuy {
|
||||||
static {
|
private static final int ROWS = 6;
|
||||||
populateIcons();
|
private static final int COLUMNS = 9;
|
||||||
}
|
private static final int ITEM_ROWS = 3;
|
||||||
|
private static final Menu menu;
|
||||||
public static void open(Player player) {
|
|
||||||
menu.open(player);
|
static {
|
||||||
}
|
try {
|
||||||
|
menu = Menu.create(DynamicShop.getInstance(), ChatColor.DARK_GREEN + "Shop | Buy", ROWS);
|
||||||
public static void update() {
|
populateIcons();
|
||||||
menu.refreshOpenViews();
|
} catch (Exception e) {
|
||||||
}
|
DynamicShop.getInstance().getLogger().severe("Failed to initialize shop buy menu: " + e.getMessage());
|
||||||
|
throw new ExceptionInInitializerError(e);
|
||||||
private static void populateIcons() {
|
}
|
||||||
for (int row = 0; row < 3; row++) {
|
}
|
||||||
for (int id = 0; id < 9; id++) {
|
|
||||||
menu.setIcon(row,id,new ItemIconBuy(row*9+id));
|
private ShopGuiBuy() {
|
||||||
}
|
// Private constructor to prevent instantiation
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
public static void open(@NotNull Player player) {
|
||||||
|
if (player == null) {
|
||||||
|
throw new IllegalArgumentException("Player cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
menu.open(player);
|
||||||
|
} catch (Exception e) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Failed to open shop menu!");
|
||||||
|
DynamicShop.getInstance().getLogger().severe("Failed to open shop buy menu for " + player.getName() + ": " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void update() {
|
||||||
|
try {
|
||||||
|
menu.refreshOpenViews();
|
||||||
|
} catch (Exception e) {
|
||||||
|
DynamicShop.getInstance().getLogger().severe("Failed to update shop buy menu: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void populateIcons() {
|
||||||
|
try {
|
||||||
|
for (int row = 0; row < ITEM_ROWS; row++) {
|
||||||
|
for (int column = 0; column < COLUMNS; column++) {
|
||||||
|
int slot = row * COLUMNS + column;
|
||||||
|
menu.setIcon(row, column, new ItemIconBuy(slot));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
DynamicShop.getInstance().getLogger().severe("Failed to populate shop buy menu icons: " + e.getMessage());
|
||||||
|
throw new RuntimeException("Failed to populate shop buy menu icons", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,30 +1,64 @@
|
|||||||
package ru.redguy.dynamicshop.gui;
|
package ru.redguy.dynamicshop.gui;
|
||||||
|
|
||||||
import me.filoghost.chestcommands.api.Menu;
|
import me.filoghost.chestcommands.api.Menu;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.ChatColor;
|
||||||
import ru.redguy.dynamicshop.DynamicShop;
|
import org.bukkit.entity.Player;
|
||||||
import ru.redguy.dynamicshop.gui.icons.ItemIconSell;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.redguy.dynamicshop.DynamicShop;
|
||||||
public class ShopGuiSell {
|
import ru.redguy.dynamicshop.gui.icons.ItemIconSell;
|
||||||
private static final Menu menu = Menu.create(DynamicShop.getInstance(),"Магазин | Продажа",6);
|
|
||||||
|
public class ShopGuiSell {
|
||||||
static {
|
private static final int ROWS = 6;
|
||||||
populateIcons();
|
private static final int COLUMNS = 9;
|
||||||
}
|
private static final int ITEM_ROWS = 3;
|
||||||
|
private static final Menu menu;
|
||||||
public static void open(Player player) {
|
|
||||||
menu.open(player);
|
static {
|
||||||
}
|
try {
|
||||||
|
menu = Menu.create(DynamicShop.getInstance(), ChatColor.DARK_GREEN + "Shop | Sell", ROWS);
|
||||||
public static void update() {
|
populateIcons();
|
||||||
menu.refreshOpenViews();
|
} catch (Exception e) {
|
||||||
}
|
DynamicShop.getInstance().getLogger().severe("Failed to initialize shop sell menu: " + e.getMessage());
|
||||||
|
throw new ExceptionInInitializerError(e);
|
||||||
private static void populateIcons() {
|
}
|
||||||
for (int row = 0; row < 3; row++) {
|
}
|
||||||
for (int id = 0; id < 9; id++) {
|
|
||||||
menu.setIcon(row,id,new ItemIconSell(row*9+id));
|
private ShopGuiSell() {
|
||||||
}
|
// Private constructor to prevent instantiation
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
public static void open(@NotNull Player player) {
|
||||||
|
if (player == null) {
|
||||||
|
throw new IllegalArgumentException("Player cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
menu.open(player);
|
||||||
|
} catch (Exception e) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Failed to open shop menu!");
|
||||||
|
DynamicShop.getInstance().getLogger().severe("Failed to open shop sell menu for " + player.getName() + ": " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void update() {
|
||||||
|
try {
|
||||||
|
menu.refreshOpenViews();
|
||||||
|
} catch (Exception e) {
|
||||||
|
DynamicShop.getInstance().getLogger().severe("Failed to update shop sell menu: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void populateIcons() {
|
||||||
|
try {
|
||||||
|
for (int row = 0; row < ITEM_ROWS; row++) {
|
||||||
|
for (int column = 0; column < COLUMNS; column++) {
|
||||||
|
int slot = row * COLUMNS + column;
|
||||||
|
menu.setIcon(row, column, new ItemIconSell(slot));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
DynamicShop.getInstance().getLogger().severe("Failed to populate shop sell menu icons: " + e.getMessage());
|
||||||
|
throw new RuntimeException("Failed to populate shop sell menu icons", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,64 +1,133 @@
|
|||||||
package ru.redguy.dynamicshop.gui.icons;
|
package ru.redguy.dynamicshop.gui.icons;
|
||||||
|
|
||||||
import me.filoghost.chestcommands.api.Icon;
|
import me.filoghost.chestcommands.api.Icon;
|
||||||
import me.filoghost.chestcommands.api.MenuView;
|
import me.filoghost.chestcommands.api.MenuView;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.TextColor;
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import ru.redguy.dynamicshop.DynamicShop;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import ru.redguy.dynamicshop.api.Database;
|
import ru.redguy.dynamicshop.DynamicShop;
|
||||||
import ru.redguy.dynamicshop.api.ShopItem;
|
import ru.redguy.dynamicshop.api.Database;
|
||||||
import ru.redguy.dynamicshop.gui.ShopGuiBuy;
|
import ru.redguy.dynamicshop.api.ShopItem;
|
||||||
import ru.redguy.dynamicshop.gui.ShopGuiSell;
|
import ru.redguy.dynamicshop.gui.ShopGuiBuy;
|
||||||
|
import ru.redguy.dynamicshop.gui.ShopGuiSell;
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.RoundingMode;
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.math.RoundingMode;
|
||||||
import java.util.List;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
public class ItemIconBuy implements Icon {
|
import java.util.logging.Level;
|
||||||
private final int index;
|
|
||||||
|
public class ItemIconBuy implements Icon {
|
||||||
public ItemIconBuy(int index) {
|
private static final double PRICE_INCREASE = 0.1;
|
||||||
this.index = index;
|
private static final double PRICE_MARKUP = 1.0;
|
||||||
}
|
private static final int PRICE_DECIMALS = 2;
|
||||||
|
private static final TextColor PRICE_LABEL_COLOR = TextColor.color(255, 255, 255);
|
||||||
@Override
|
private static final TextColor PRICE_VALUE_COLOR = TextColor.color(255, 100, 0);
|
||||||
public @Nullable ItemStack render(@NotNull Player player) {
|
|
||||||
ShopItem item = Database.getInstance().getItem(index);
|
private final int index;
|
||||||
if (item == null) return null;
|
|
||||||
ItemStack stack = item.getItem().clone();
|
public ItemIconBuy(int index) {
|
||||||
if (stack.getType() == Material.AIR) return null;
|
if (index < 0) {
|
||||||
List<Component> lore = new ArrayList<>();
|
throw new IllegalArgumentException("Index cannot be negative");
|
||||||
lore.add(Component.text("Цена: ").color(TextColor.color(255, 255, 255)).append(Component.text(item.getPrice() + 1).color(TextColor.color(255, 100, 0))));
|
}
|
||||||
stack.lore(lore);
|
this.index = index;
|
||||||
return stack;
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public @Nullable ItemStack render(@NotNull Player player) {
|
||||||
public void onClick(@NotNull MenuView menuView, @NotNull Player player) {
|
try {
|
||||||
ShopItem item = Database.getInstance().getItem(index);
|
ShopItem item = Database.getInstance().getItem(index);
|
||||||
if (item == null) return;
|
if (item == null || item.getItem().getType() == Material.AIR) {
|
||||||
if (item.getItem().getType() == Material.AIR) return;
|
return null;
|
||||||
if (!DynamicShop.getInstance().econ.has(player, item.getPrice() + 1)) return;
|
}
|
||||||
|
|
||||||
player.getInventory().addItem(item.getItem().clone());
|
ItemStack stack = item.getItem().clone();
|
||||||
DynamicShop.getInstance().econ.withdrawPlayer(player, item.getPrice() + 1);
|
List<Component> lore = new ArrayList<>();
|
||||||
item.setPrice(round(item.getPrice() + 0.1d, 2));
|
double buyPrice = item.getPrice() + PRICE_MARKUP;
|
||||||
Database.getInstance().setItem(index, item);
|
lore.add(Component.text("Price: ")
|
||||||
ShopGuiSell.update();
|
.color(PRICE_LABEL_COLOR)
|
||||||
ShopGuiBuy.update();
|
.append(Component.text(String.format("%.2f", buyPrice))
|
||||||
}
|
.color(PRICE_VALUE_COLOR)));
|
||||||
|
stack.lore(lore);
|
||||||
public static double round(double value, int places) {
|
return stack;
|
||||||
if (places < 0) throw new IllegalArgumentException();
|
} catch (Exception e) {
|
||||||
|
DynamicShop.getInstance().getLogger().log(Level.SEVERE,
|
||||||
BigDecimal bd = BigDecimal.valueOf(value);
|
"Failed to render buy icon for index " + index, e);
|
||||||
bd = bd.setScale(places, RoundingMode.HALF_DOWN);
|
return null;
|
||||||
return bd.doubleValue();
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public void onClick(@NotNull MenuView menuView, @NotNull Player player) {
|
||||||
|
try {
|
||||||
|
ShopItem item = Database.getInstance().getItem(index);
|
||||||
|
if (!validateTransaction(player, item)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the transaction
|
||||||
|
processTransaction(player, item);
|
||||||
|
|
||||||
|
// Update the item price and refresh menus
|
||||||
|
updateItemPrice(item);
|
||||||
|
refreshMenus();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Failed to process purchase!");
|
||||||
|
DynamicShop.getInstance().getLogger().log(Level.SEVERE,
|
||||||
|
"Failed to process buy transaction for player " + player.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean validateTransaction(@NotNull Player player, @Nullable ShopItem item) {
|
||||||
|
if (item == null || item.getItem().getType() == Material.AIR) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double buyPrice = item.getPrice() + PRICE_MARKUP;
|
||||||
|
if (!DynamicShop.getInstance().getEconomy().has(player, buyPrice)) {
|
||||||
|
player.sendMessage(ChatColor.RED + "You don't have enough money! Need: " +
|
||||||
|
ChatColor.GOLD + String.format("%.2f", buyPrice));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processTransaction(@NotNull Player player, @NotNull ShopItem item) {
|
||||||
|
double buyPrice = item.getPrice() + PRICE_MARKUP;
|
||||||
|
player.getInventory().addItem(item.getItem().clone());
|
||||||
|
DynamicShop.getInstance().getEconomy().withdrawPlayer(player, buyPrice);
|
||||||
|
player.sendMessage(ChatColor.GREEN + "Successfully bought item for " +
|
||||||
|
ChatColor.GOLD + String.format("%.2f", buyPrice));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateItemPrice(@NotNull ShopItem item) {
|
||||||
|
double newPrice = round(item.getPrice() + PRICE_INCREASE, PRICE_DECIMALS);
|
||||||
|
Database.getInstance().setItem(index, new ShopItem(item.getItem(), newPrice));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshMenus() {
|
||||||
|
ShopGuiSell.update();
|
||||||
|
ShopGuiBuy.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double round(double value, int places) {
|
||||||
|
if (places < 0) {
|
||||||
|
throw new IllegalArgumentException("Decimal places cannot be negative");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
BigDecimal bd = BigDecimal.valueOf(value);
|
||||||
|
bd = bd.setScale(places, RoundingMode.HALF_DOWN);
|
||||||
|
return bd.doubleValue();
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new IllegalArgumentException("Failed to round value: " + value, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,65 +1,135 @@
|
|||||||
package ru.redguy.dynamicshop.gui.icons;
|
package ru.redguy.dynamicshop.gui.icons;
|
||||||
|
|
||||||
import me.filoghost.chestcommands.api.Icon;
|
import me.filoghost.chestcommands.api.Icon;
|
||||||
import me.filoghost.chestcommands.api.MenuView;
|
import me.filoghost.chestcommands.api.MenuView;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.TextColor;
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import ru.redguy.dynamicshop.DynamicShop;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import ru.redguy.dynamicshop.api.Database;
|
import ru.redguy.dynamicshop.DynamicShop;
|
||||||
import ru.redguy.dynamicshop.api.ShopItem;
|
import ru.redguy.dynamicshop.api.Database;
|
||||||
import ru.redguy.dynamicshop.gui.ShopGuiBuy;
|
import ru.redguy.dynamicshop.api.ShopItem;
|
||||||
import ru.redguy.dynamicshop.gui.ShopGuiSell;
|
import ru.redguy.dynamicshop.gui.ShopGuiBuy;
|
||||||
|
import ru.redguy.dynamicshop.gui.ShopGuiSell;
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.RoundingMode;
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.math.RoundingMode;
|
||||||
import java.util.List;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
public class ItemIconSell implements Icon {
|
import java.util.logging.Level;
|
||||||
private int index;
|
|
||||||
|
public class ItemIconSell implements Icon {
|
||||||
public ItemIconSell(int index) {
|
private static final double MIN_PRICE = 1.0;
|
||||||
this.index = index;
|
private static final double PRICE_DECREASE = 0.1;
|
||||||
}
|
private static final int PRICE_DECIMALS = 2;
|
||||||
|
private static final TextColor PRICE_LABEL_COLOR = TextColor.color(255, 255, 255);
|
||||||
@Override
|
private static final TextColor PRICE_VALUE_COLOR = TextColor.color(255, 100, 0);
|
||||||
public @Nullable ItemStack render(@NotNull Player player) {
|
|
||||||
ShopItem item = Database.getInstance().getItem(index);
|
private final int index;
|
||||||
if(item == null) return null;
|
|
||||||
ItemStack stack = item.getItem().clone();
|
public ItemIconSell(int index) {
|
||||||
if (stack.getType() == Material.AIR) return null;
|
if (index < 0) {
|
||||||
List<Component> lore = new ArrayList<>();
|
throw new IllegalArgumentException("Index cannot be negative");
|
||||||
lore.add(Component.text("Цена: ").color(TextColor.color(255,255,255)).append(Component.text(item.getPrice()).color(TextColor.color(255,100,0))));
|
}
|
||||||
stack.lore(lore);
|
this.index = index;
|
||||||
return stack;
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public @Nullable ItemStack render(@NotNull Player player) {
|
||||||
public void onClick(@NotNull MenuView menuView, @NotNull Player player) {
|
try {
|
||||||
ShopItem item = Database.getInstance().getItem(index);
|
ShopItem item = Database.getInstance().getItem(index);
|
||||||
if(item == null) return;
|
if (item == null || item.getItem().getType() == Material.AIR) {
|
||||||
if (item.getItem().getType() == Material.AIR) return;
|
return null;
|
||||||
if(!player.getInventory().containsAtLeast(item.getItem().clone(),item.getItem().clone().getAmount())) return;
|
}
|
||||||
if(item.getPrice()<=1) return;
|
|
||||||
|
ItemStack stack = item.getItem().clone();
|
||||||
player.getInventory().removeItem(item.getItem().clone());
|
List<Component> lore = new ArrayList<>();
|
||||||
DynamicShop.getInstance().econ.depositPlayer(player,item.getPrice());
|
lore.add(Component.text("Price: ")
|
||||||
item.setPrice(round(item.getPrice()-0.1d,2));
|
.color(PRICE_LABEL_COLOR)
|
||||||
Database.getInstance().setItem(index,item);
|
.append(Component.text(String.format("%.2f", item.getPrice()))
|
||||||
ShopGuiSell.update();
|
.color(PRICE_VALUE_COLOR)));
|
||||||
ShopGuiBuy.update();
|
stack.lore(lore);
|
||||||
}
|
return stack;
|
||||||
|
} catch (Exception e) {
|
||||||
public static double round(double value, int places) {
|
DynamicShop.getInstance().getLogger().log(Level.SEVERE,
|
||||||
if (places < 0) throw new IllegalArgumentException();
|
"Failed to render sell icon for index " + index, e);
|
||||||
|
return null;
|
||||||
BigDecimal bd = BigDecimal.valueOf(value);
|
}
|
||||||
bd = bd.setScale(places, RoundingMode.HALF_DOWN);
|
}
|
||||||
return bd.doubleValue();
|
|
||||||
}
|
@Override
|
||||||
}
|
public void onClick(@NotNull MenuView menuView, @NotNull Player player) {
|
||||||
|
try {
|
||||||
|
ShopItem item = Database.getInstance().getItem(index);
|
||||||
|
if (!validateTransaction(player, item)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the transaction
|
||||||
|
processTransaction(player, item);
|
||||||
|
|
||||||
|
// Update the item price and refresh menus
|
||||||
|
updateItemPrice(item);
|
||||||
|
refreshMenus();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Failed to process sale!");
|
||||||
|
DynamicShop.getInstance().getLogger().log(Level.SEVERE,
|
||||||
|
"Failed to process sell transaction for player " + player.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean validateTransaction(@NotNull Player player, @Nullable ShopItem item) {
|
||||||
|
if (item == null || item.getItem().getType() == Material.AIR) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.getPrice() <= MIN_PRICE) {
|
||||||
|
player.sendMessage(ChatColor.RED + "Item price is too low!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack requiredItem = item.getItem().clone();
|
||||||
|
if (!player.getInventory().containsAtLeast(requiredItem, requiredItem.getAmount())) {
|
||||||
|
player.sendMessage(ChatColor.RED + "You don't have enough items to sell!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processTransaction(@NotNull Player player, @NotNull ShopItem item) {
|
||||||
|
player.getInventory().removeItem(item.getItem().clone());
|
||||||
|
DynamicShop.getInstance().getEconomy().depositPlayer(player, item.getPrice());
|
||||||
|
player.sendMessage(ChatColor.GREEN + "Successfully sold item for " +
|
||||||
|
ChatColor.GOLD + String.format("%.2f", item.getPrice()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateItemPrice(@NotNull ShopItem item) {
|
||||||
|
double newPrice = round(item.getPrice() - PRICE_DECREASE, PRICE_DECIMALS);
|
||||||
|
Database.getInstance().setItem(index, new ShopItem(item.getItem(), newPrice));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshMenus() {
|
||||||
|
ShopGuiSell.update();
|
||||||
|
ShopGuiBuy.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double round(double value, int places) {
|
||||||
|
if (places < 0) {
|
||||||
|
throw new IllegalArgumentException("Decimal places cannot be negative");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
BigDecimal bd = BigDecimal.valueOf(value);
|
||||||
|
bd = bd.setScale(places, RoundingMode.HALF_DOWN);
|
||||||
|
return bd.doubleValue();
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new IllegalArgumentException("Failed to round value: " + value, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user