From 3fbc86e658d014d8bee9f0ce4690b1b571df2e11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Ryb=C3=A1rsky?= Date: Tue, 20 Aug 2024 14:30:19 +0200 Subject: [PATCH] Updatee --- gradle.properties | 2 +- .../systems/brn/servershop/ItemPrice.java | 37 ++++- .../systems/brn/servershop/ServerShop.java | 17 ++- .../brn/servershop/commands/PriceCommand.java | 55 +++++++ .../commands/ShopPricesCommand.java | 42 ++++-- .../servershop/commands/StoreCommands.java | 8 +- .../brn/servershop/lib/BalanceManager.java | 97 +++++++----- .../brn/servershop/lib/ItemPriceStorage.java | 5 + .../brn/servershop/lib/PriceStorage.java | 142 +++++++++++++----- .../brn/servershop/lib/ShopFunctions.java | 38 ++--- .../java/systems/brn/servershop/lib/Util.java | 77 ++++++++++ .../brn/servershop/screens/ShopScreen.java | 65 +++----- .../assets/servershop/lang/en_us.json | 10 +- .../assets/servershop/textures/icon.png | Bin 0 -> 44538 bytes src/main/resources/fabric.mod.json | 2 +- 15 files changed, 443 insertions(+), 154 deletions(-) create mode 100644 src/main/java/systems/brn/servershop/commands/PriceCommand.java create mode 100644 src/main/java/systems/brn/servershop/lib/ItemPriceStorage.java create mode 100644 src/main/resources/assets/servershop/textures/icon.png diff --git a/gradle.properties b/gradle.properties index 54bb45d..ff14496 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.21.1 yarn_mappings=1.21.1+build.3 loader_version=0.16.2 # Mod Properties -mod_version=1.0 +mod_version=1.2 maven_group=systems.brn archives_base_name=servershop # Dependencies diff --git a/src/main/java/systems/brn/servershop/ItemPrice.java b/src/main/java/systems/brn/servershop/ItemPrice.java index 0fa163e..9233860 100644 --- a/src/main/java/systems/brn/servershop/ItemPrice.java +++ b/src/main/java/systems/brn/servershop/ItemPrice.java @@ -1,6 +1,37 @@ package systems.brn.servershop; -public record ItemPrice( - int buyPrice, int sellPrice -) { +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.registry.RegistryWrapper; + +import java.util.Optional; + +public record ItemPrice(int buyPrice, int sellPrice, ItemStack stack) { + + + public NbtCompound toNbt(RegistryWrapper.WrapperLookup wrapperLookup) { + NbtCompound nbt = new NbtCompound(); + nbt.putInt("BuyPrice", this.buyPrice); + nbt.putInt("SellPrice", this.sellPrice); + + // Serialize the ItemStack to NBT and add it to the compound + NbtElement stackNbt = stack.encode(wrapperLookup); + nbt.put("ItemStack", stackNbt); // Adds the ItemStack's NBT data to the main NBT compound + + return nbt; + } + + public static ItemPrice fromNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup wrapperLookup) { + int buyPrice = nbt.getInt("BuyPrice"); + int sellPrice = nbt.getInt("SellPrice"); + + // Deserialize the ItemStack from the NBT + NbtElement stackElement = nbt.get("ItemStack"); + + Optional stack = ItemStack.fromNbt(wrapperLookup, stackElement); + return stack.map(itemStack -> new ItemPrice(buyPrice, sellPrice, itemStack)).orElse(null); + + } + } diff --git a/src/main/java/systems/brn/servershop/ServerShop.java b/src/main/java/systems/brn/servershop/ServerShop.java index 716cb52..f3cbeb9 100644 --- a/src/main/java/systems/brn/servershop/ServerShop.java +++ b/src/main/java/systems/brn/servershop/ServerShop.java @@ -47,7 +47,7 @@ public class ServerShop implements ModInitializer { private void onPlayerJoin(ServerPlayNetworkHandler serverPlayNetworkHandler, PacketSender packetSender, MinecraftServer server) { if (packetSender instanceof ServerPlayerEntity player) { - balanceManager.onJoin(player); + balanceManager.setBalance(player, 0L); } } @@ -94,6 +94,13 @@ public class ServerShop implements ModInitializer { ) ) ) + .then(literal("setHand") + .then(argument("buyprice", IntegerArgumentType.integer()) + .then(argument("sellprice", IntegerArgumentType.integer()) + .executes(ShopPricesCommand::setHand) + ) + ) + ) ); dispatcher.register(literal("buy") @@ -110,6 +117,12 @@ public class ServerShop implements ModInitializer { .executes(StoreCommands::sellOne) ) ); + dispatcher.register(literal("price") + .then(argument("item", ItemStackArgumentType.itemStack(commandRegistryAccess)) + .executes(PriceCommand::run) + ) + .executes(PriceCommand::runHand) + ); } @@ -119,6 +132,6 @@ public class ServerShop implements ModInitializer { } private void onServerStopped(MinecraftServer server) { - balanceManager.saveBalance(); + balanceManager.saveBalances(); } } diff --git a/src/main/java/systems/brn/servershop/commands/PriceCommand.java b/src/main/java/systems/brn/servershop/commands/PriceCommand.java new file mode 100644 index 0000000..2a425a7 --- /dev/null +++ b/src/main/java/systems/brn/servershop/commands/PriceCommand.java @@ -0,0 +1,55 @@ +package systems.brn.servershop.commands; + +import com.mojang.brigadier.context.CommandContext; +import net.minecraft.command.argument.ItemStackArgumentType; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import org.jetbrains.annotations.NotNull; +import systems.brn.servershop.ItemPrice; + +import static systems.brn.servershop.ServerShop.priceStorage; + +public class PriceCommand { + public static int run(CommandContext ctx) { + Item item = ItemStackArgumentType.getItemStackArgument(ctx, "item").getItem(); + ItemStack stack = item.getDefaultStack(); + return runStack(ctx, stack); + } + + private static int runStack(CommandContext ctx, ItemStack stack) { + ItemPrice itemPrice = priceStorage.getPrices(stack); + ServerCommandSource src = ctx.getSource(); + int buyPrice = itemPrice.buyPrice(); + int sellPrice = itemPrice.sellPrice(); + String itemName = stack.getItem().toString(); + Text text = getText(buyPrice, sellPrice, itemName); + src.sendFeedback(() -> text, false); + return 0; + } + + public static int runHand(CommandContext ctx) { + ServerPlayerEntity player = ctx.getSource().getPlayer(); + if (player != null) { + ItemStack stack = player.getMainHandStack(); + return runStack(ctx, stack); + } + return 1; + } + + private static @NotNull Text getText(int buyPrice, int sellPrice, String itemName) { + Text text; + if (buyPrice > 0 && sellPrice > 0) { + text = Text.translatable("message.servershop.price.both", itemName, buyPrice, sellPrice); + } else if (buyPrice > 0) { + text = Text.translatable("message.servershop.price.buy", itemName, buyPrice); + } else if (sellPrice > 0) { + text = Text.translatable("message.servershop.price.sell", itemName, sellPrice); + } else { + text = Text.translatable("message.servershop.price.neither", itemName); + } + return text; + } +} diff --git a/src/main/java/systems/brn/servershop/commands/ShopPricesCommand.java b/src/main/java/systems/brn/servershop/commands/ShopPricesCommand.java index 5a9879f..dcd0f96 100644 --- a/src/main/java/systems/brn/servershop/commands/ShopPricesCommand.java +++ b/src/main/java/systems/brn/servershop/commands/ShopPricesCommand.java @@ -3,8 +3,11 @@ package systems.brn.servershop.commands; import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.context.CommandContext; import net.minecraft.command.argument.ItemStackArgumentType; -import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; import systems.brn.servershop.ServerShop; @@ -15,6 +18,12 @@ public class ShopPricesCommand { return 1; } + public static int loadLegacy(CommandContext ctx) { + ServerShop.priceStorage.loadLegacy(); + ctx.getSource().sendFeedback(() -> Text.translatable("message.servershop.storage.load"), false); + return 1; + } + public static int save(CommandContext ctx) { boolean success = ServerShop.priceStorage.save(); ctx.getSource().sendFeedback(() -> @@ -29,17 +38,28 @@ public class ShopPricesCommand { } public static int set(CommandContext ctx) { - Item item = ItemStackArgumentType.getItemStackArgument(ctx, "item").getItem(); + ItemStack stack = ItemStackArgumentType.getItemStackArgument(ctx, "item").getItem().getDefaultStack(); + return setStack(ctx, stack); + } + + public static int setHand(CommandContext ctx) { + ServerPlayerEntity player = ctx.getSource().getPlayer(); + if (player != null) { + ItemStack stack = player.getMainHandStack().copy(); + if (!stack.isEmpty()) { + return setStack(ctx, stack); + } + + } + return 1; + } + + private static int setStack(CommandContext ctx, ItemStack stack) { + String itemName = stack.getItem().toString(); int buyPrice = IntegerArgumentType.getInteger(ctx, "buyprice"); int sellPrice = IntegerArgumentType.getInteger(ctx, "sellprice"); - String itemName = item.toString(); - boolean success = ServerShop.priceStorage.setPrices(item, buyPrice, sellPrice); - if (success) { - ctx.getSource().sendFeedback(() -> Text.translatable("message.servershop.storage.set", itemName, buyPrice, sellPrice), false); - return 1; - } else { - ctx.getSource().sendFeedback(() -> Text.translatable("message.servershop.storage.set_fail", itemName), false); - return 0; - } + ServerShop.priceStorage.setPrices(stack, buyPrice, sellPrice); + ctx.getSource().sendFeedback(() -> Text.translatable("message.servershop.storage.set", itemName, buyPrice, sellPrice), false); + return 0; } } diff --git a/src/main/java/systems/brn/servershop/commands/StoreCommands.java b/src/main/java/systems/brn/servershop/commands/StoreCommands.java index 1e9dc11..f9c5161 100644 --- a/src/main/java/systems/brn/servershop/commands/StoreCommands.java +++ b/src/main/java/systems/brn/servershop/commands/StoreCommands.java @@ -18,7 +18,7 @@ public class StoreCommands { ItemStack itemStack = new ItemStack(item, count); ServerPlayerEntity player = ctx.getSource().getPlayer(); if (player != null) { - buy(itemStack, player); + buy(itemStack, player, false); return 0; } return 1; @@ -29,7 +29,7 @@ public class StoreCommands { ItemStack itemStack = new ItemStack(item); ServerPlayerEntity player = ctx.getSource().getPlayer(); if (player != null) { - buy(itemStack, player); + buy(itemStack, player, false); return 0; } return 1; @@ -41,7 +41,7 @@ public class StoreCommands { ItemStack itemStack = new ItemStack(item, count); ServerPlayerEntity player = ctx.getSource().getPlayer(); if (player != null) { - sell(itemStack, player); + sell(itemStack, player, false); return 0; } return 1; @@ -52,7 +52,7 @@ public class StoreCommands { ItemStack itemStack = new ItemStack(item); ServerPlayerEntity player = ctx.getSource().getPlayer(); if (player != null) { - sell(itemStack, player); + sell(itemStack, player, false); return 0; } return 1; diff --git a/src/main/java/systems/brn/servershop/lib/BalanceManager.java b/src/main/java/systems/brn/servershop/lib/BalanceManager.java index 6a0a09a..101b409 100644 --- a/src/main/java/systems/brn/servershop/lib/BalanceManager.java +++ b/src/main/java/systems/brn/servershop/lib/BalanceManager.java @@ -1,36 +1,35 @@ package systems.brn.servershop.lib; +import net.minecraft.nbt.*; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; +import net.minecraft.util.Identifier; import net.minecraft.util.WorldSavePath; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileWriter; -import java.io.IOException; +import java.io.*; import java.util.HashMap; +import java.util.Optional; import java.util.Scanner; import java.util.UUID; import java.util.concurrent.locks.ReentrantLock; public class BalanceManager { - final private HashMap balances = new HashMap<>(); + private final HashMap balances = new HashMap<>(); public final MinecraftServer server; - public final File balanceStorageFile; + private final File balanceStorageFile; + private final File balanceStorageCSVFile; private static final ReentrantLock lock = new ReentrantLock(); // Lock for in-memory operations public BalanceManager(MinecraftServer server) { this.server = server; - balanceStorageFile = server.getSavePath(WorldSavePath.ROOT).resolve("balances.csv").toFile(); - loadBalance(); + balanceStorageFile = server.getSavePath(WorldSavePath.ROOT).resolve("balances.dat").toFile(); + balanceStorageCSVFile = server.getSavePath(WorldSavePath.ROOT).resolve("balances.csv").toFile(); + loadBalances(); } public long getBalance(UUID uuid) { - if (balances.containsKey(uuid)) { - return balances.get(uuid); - } - return 0L; + return balances.getOrDefault(uuid, 0L); } public long getBalance(ServerPlayerEntity player) { @@ -38,8 +37,8 @@ public class BalanceManager { } public void addBalance(UUID uuid, long amount) { - balances.put(uuid, amount + getBalance(uuid)); - saveBalance(); + balances.put(uuid, getBalance(uuid) + amount); + saveBalances(); } public void addBalance(ServerPlayerEntity player, long amount) { @@ -49,11 +48,12 @@ public class BalanceManager { public void removeBalance(UUID uuid, long amount) { balances.put(uuid, getBalance(uuid) - amount); - saveBalance(); + saveBalances(); } public void setBalance(UUID uuid, long amount) { - balances.put(uuid, getBalance(uuid) + amount); + balances.put(uuid, amount); + saveBalances(); } public void setBalance(ServerPlayerEntity player, long amount) { @@ -66,37 +66,63 @@ public class BalanceManager { announceBalance(player, true); } - public boolean saveBalance() { + public void saveBalances() { lock.lock(); try { - FileWriter fileWriter = new FileWriter(balanceStorageFile, false); + NbtList nbtList = new NbtList(); for (UUID uuid : balances.keySet()) { - long balance = getBalance(uuid); - fileWriter.write(uuid.toString() + "," + balance + "\n"); + NbtCompound nbtCompound = new NbtCompound(); + nbtCompound.putUuid("UUID", uuid); + nbtCompound.putLong("Balance", balances.get(uuid)); + nbtList.add(nbtCompound); } - fileWriter.close(); - lock.unlock(); - } catch (IOException e) { - lock.unlock(); - return false; - } - return true; - } - public void onJoin(ServerPlayerEntity player) { - UUID uuid = player.getUuid(); - if (!balances.containsKey(uuid)) { - balances.put(uuid, 0L); + NbtCompound root = new NbtCompound(); + root.put("Balances", nbtList); + + try (FileOutputStream fos = new FileOutputStream(balanceStorageFile); + DataOutputStream dos = new DataOutputStream(fos)) { + NbtIo.write(root, dos); + } + } catch (IOException ignored) { + } finally { + lock.unlock(); } } - public void loadBalance() { + public void loadBalances() { + lock.lock(); + if (balanceStorageFile.exists()) { + try { + NbtCompound root = NbtIo.read(balanceStorageFile.toPath()); + if (root != null) { + NbtList nbtList = root.getList("Balances", 10); + + for (NbtElement element : nbtList) { + if (element instanceof NbtCompound nbt) { + UUID uuid = nbt.getUuid("UUID"); + long balance = nbt.getLong("Balance"); + balances.put(uuid, balance); + } + } + } + } catch ( + IOException ignored) { + } finally { + lock.unlock(); + } + } else { + loadLegacy(); + } + } + + public void loadLegacy() { lock.lock(); if (!balances.isEmpty()) { balances.clear(); } try { - Scanner scanner = new Scanner(balanceStorageFile); + Scanner scanner = new Scanner(balanceStorageCSVFile); while (scanner.hasNextLine()) { String line = scanner.nextLine(); String[] lineParts = line.split(","); @@ -106,9 +132,10 @@ public class BalanceManager { balances.put(uuid, amount); } } + saveBalances(); } catch (FileNotFoundException ignored) { - saveBalance(); + saveBalances(); } lock.unlock(); } diff --git a/src/main/java/systems/brn/servershop/lib/ItemPriceStorage.java b/src/main/java/systems/brn/servershop/lib/ItemPriceStorage.java new file mode 100644 index 0000000..9c24da3 --- /dev/null +++ b/src/main/java/systems/brn/servershop/lib/ItemPriceStorage.java @@ -0,0 +1,5 @@ +package systems.brn.servershop.lib; + +public class ItemPriceStorage { + +} diff --git a/src/main/java/systems/brn/servershop/lib/PriceStorage.java b/src/main/java/systems/brn/servershop/lib/PriceStorage.java index 6c8ee6a..d031f15 100644 --- a/src/main/java/systems/brn/servershop/lib/PriceStorage.java +++ b/src/main/java/systems/brn/servershop/lib/PriceStorage.java @@ -1,57 +1,148 @@ package systems.brn.servershop.lib; import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.*; import net.minecraft.registry.Registries; +import net.minecraft.registry.RegistryWrapper; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.world.ServerWorld; import net.minecraft.util.Identifier; import net.minecraft.util.WorldSavePath; import systems.brn.servershop.ItemPrice; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileWriter; -import java.io.IOException; +import java.io.*; import java.util.HashMap; +import java.util.Optional; import java.util.Scanner; public class PriceStorage { public final MinecraftServer server; public final File priceStorageFile; + public final File priceStorageCSVFile; + public RegistryWrapper.WrapperLookup wrapperLookup; public PriceStorage(MinecraftServer server) { this.server = server; - priceStorageFile = server.getSavePath(WorldSavePath.ROOT).resolve("prices.csv").toFile(); + priceStorageFile = server.getSavePath(WorldSavePath.ROOT).resolve("prices.dat").toFile(); + priceStorageCSVFile = server.getSavePath(WorldSavePath.ROOT).resolve("prices.csv").toFile(); + wrapperLookup = null; + for (ServerWorld world : server.getWorlds()) { + wrapperLookup = world.getRegistryManager(); + break; + } + load(); } - public final HashMap prices = new HashMap<>(); + public final HashMap prices = new HashMap<>(); public void generateEmpty() { if (!prices.isEmpty()) { prices.clear(); } for (Item item : Registries.ITEM) { - ItemPrice itemPrice = new ItemPrice(0, 0); - prices.put(item, itemPrice); + ItemPrice itemPrice = new ItemPrice(0, 0, item.getDefaultStack()); + prices.put(item.getDefaultStack(), itemPrice); } } - public boolean setPrices(Item item, int buyPrice, int sellPrice) { - if (prices.containsKey(item)) { - prices.remove(item); - prices.put(item, new ItemPrice(buyPrice, sellPrice)); - return true; + public void setPrices(ItemStack inStack, int buyPrice, int sellPrice) { + boolean found = false; + for (ItemStack priceStack : prices.keySet()) { + if (ItemStack.areItemsAndComponentsEqual(inStack, priceStack)) { + prices.put(priceStack, new ItemPrice(buyPrice, sellPrice, priceStack)); + found = true; + break; + } } - return false; + if (!found) { + prices.put(inStack, new ItemPrice(buyPrice, sellPrice, inStack)); + } + } + + public ItemPrice getPrices(ItemStack inStack) { + for (ItemStack priceStack : prices.keySet()) { + if (ItemStack.areItemsAndComponentsEqual(inStack, priceStack)) { + return prices.get(priceStack); + } + } + return new ItemPrice(0, 0, inStack.copy()); } public void load() { + if (wrapperLookup == null) { + return; + } + prices.clear(); + + try { + NbtCompound nbtCompound = NbtIo.read(priceStorageFile.toPath()); + if (nbtCompound != null && nbtCompound.contains("Prices") && priceStorageFile.exists()) { + NbtList nbtList = nbtCompound.getList("Prices", 10); // 10 is the type ID for NbtCompound + for (NbtElement element : nbtList) { + if (element instanceof NbtCompound nbt) { + // Deserialize the ItemStack from the NbtCompound + NbtCompound stackNbt = nbt.getCompound("ItemStack"); + Optional stackTemp = ItemStack.fromNbt(wrapperLookup, stackNbt); + if (stackTemp.isPresent()) { + ItemStack stack = stackTemp.get(); + // Retrieve the buy and sell prices + int buyPrice = nbt.getInt("BuyPrice"); + int sellPrice = nbt.getInt("SellPrice"); + if(sellPrice > buyPrice && buyPrice != 0) { + buyPrice = sellPrice; + } + // Add the deserialized ItemStack and ItemPrice to the prices map + prices.put(stack, new ItemPrice(buyPrice, sellPrice, stack)); + } + } + } + } else { + loadLegacy(); + save(); + } + } catch (IOException e) { + generateEmpty(); + save(); + } + } + + public boolean save() { + if (wrapperLookup == null) { + return false; + } + NbtList nbtList = new NbtList(); + + for (ItemStack stack : prices.keySet()) { + ItemPrice itemPrice = prices.get(stack); + if (!stack.isEmpty()) { + nbtList.add(itemPrice.toNbt(wrapperLookup)); + } + } + + NbtCompound nbtCompound = new NbtCompound(); + nbtCompound.put("Prices", nbtList); + + // Write the NbtList to a file + try (FileOutputStream fos = new FileOutputStream(priceStorageFile)) { + DataOutputStream dos = new DataOutputStream(fos); + NbtIo.write(nbtCompound, dos); + } catch (IOException e) { + return false; + } + + return true; + } + + + public void loadLegacy() { if (!prices.isEmpty()) { prices.clear(); } try { - Scanner scanner = new Scanner(priceStorageFile); + Scanner scanner = new Scanner(priceStorageCSVFile); while (scanner.hasNextLine()) { String line = scanner.nextLine(); String[] lineParts = line.split(","); @@ -63,32 +154,13 @@ public class PriceStorage { int buyPrice = Integer.parseInt(lineParts[1]); int sellPrice = Integer.parseInt(lineParts[2]); Item item = Registries.ITEM.get(itemIdentifier); - prices.put(item, new ItemPrice(buyPrice, sellPrice)); + prices.put(item.getDefaultStack(), new ItemPrice(buyPrice, sellPrice, item.getDefaultStack())); } } } } catch (FileNotFoundException ignored) { generateEmpty(); - save(); } } - - public boolean save() { - try { - FileWriter fileWriter = new FileWriter(priceStorageFile, false); - for (Item item : prices.keySet()) { - ItemPrice itemPrice = prices.get(item); - String itemName = item.toString(); - int buyPrice = itemPrice.buyPrice(); - int sellPrice = itemPrice.sellPrice(); - fileWriter.write(itemName + "," + buyPrice + "," + sellPrice + "\n"); - } - fileWriter.close(); - } catch (IOException e) { - return false; - } - return true; - } - } diff --git a/src/main/java/systems/brn/servershop/lib/ShopFunctions.java b/src/main/java/systems/brn/servershop/lib/ShopFunctions.java index 892a6f6..aa4be2e 100644 --- a/src/main/java/systems/brn/servershop/lib/ShopFunctions.java +++ b/src/main/java/systems/brn/servershop/lib/ShopFunctions.java @@ -1,6 +1,5 @@ package systems.brn.servershop.lib; -import net.minecraft.command.argument.ItemStackArgumentType; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -13,10 +12,9 @@ import static systems.brn.servershop.ServerShop.priceStorage; import static systems.brn.servershop.lib.Util.*; public class ShopFunctions { - public static void buy(ItemStack itemStack, ServerPlayerEntity player) { - Item item = itemStack.getItem(); + public static void buy(ItemStack itemStack, ServerPlayerEntity player, boolean overlay) { PlayerInventory playerInventory = player.getInventory(); - ItemPrice price = priceStorage.prices.getOrDefault(item, new ItemPrice(0, 0)); + ItemPrice price = priceStorage.getPrices(itemStack); int buyPrice = price.buyPrice() * itemStack.getCount(); long playerBalance = balanceManager.getBalance(player); if (buyPrice > 0) { @@ -26,34 +24,36 @@ public class ShopFunctions { int toDeduce = buyPrice - (price.buyPrice() * remaining.getCount()); int boughtCount = itemStack.getCount() - remaining.getCount(); balanceManager.removeBalance(player, toDeduce); - player.sendMessage(Text.translatable("message.servershop.buy.success", boughtCount, itemStack.getName(), toDeduce), true); + playerBalance = balanceManager.getBalance(player); + player.sendMessage(Text.translatable("message.servershop.buy.success", boughtCount, itemStack.getName(), toDeduce, playerBalance), overlay); } else { - player.sendMessage(Text.translatable("message.servershop.buy.inventory"), true); + player.sendMessage(Text.translatable("message.servershop.buy.inventory"), overlay); } } else { - player.sendMessage(Text.translatable("message.servershop.buy.not_enough", buyPrice, playerBalance, buyPrice - playerBalance), true); + player.sendMessage(Text.translatable("message.servershop.buy.not_enough", buyPrice, playerBalance, buyPrice - playerBalance), overlay); } } else { - player.sendMessage(Text.translatable("message.servershop.buy.not_available", itemStack.getName()), true); + player.sendMessage(Text.translatable("message.servershop.buy.not_available", itemStack.getName()), overlay); } } - public static void sell(ItemStack itemStack, ServerPlayerEntity player) { - Item item = itemStack.getItem(); + public static void sell(ItemStack itemStack, ServerPlayerEntity player, boolean overlay) { PlayerInventory playerInventory = player.getInventory(); - ItemPrice price = priceStorage.prices.getOrDefault(item, new ItemPrice(0, 0)); + ItemPrice price = priceStorage.getPrices(itemStack); int sellPrice = price.sellPrice(); if (sellPrice > 0) { - int removed = removeFromInventory(playerInventory, itemStack.copy(), itemStack.getCount()); - if (removed == 0) { - player.sendMessage(Text.translatable("message.servershop.sell.not_enough"), true); - } - int toAdd = sellPrice * (itemStack.getCount() - removed); - int soldCount = itemStack.getCount() - removed; + int remaining = removeFromInventory(playerInventory, itemStack.copy(), itemStack.getCount()); + int toAdd = sellPrice * (itemStack.getCount() - remaining); + int soldCount = itemStack.getCount() - remaining; balanceManager.addBalance(player, toAdd); - player.sendMessage(Text.translatable("message.servershop.sell.success", soldCount, itemStack.getName(), toAdd), true); + if (soldCount == 0) { + player.sendMessage(Text.translatable("message.servershop.sell.not_enough"), overlay); + } else { + long playerBalance = balanceManager.getBalance(player); + player.sendMessage(Text.translatable("message.servershop.sell.success", soldCount, itemStack.getName(), toAdd, playerBalance), overlay); + } } else { - player.sendMessage(Text.translatable("message.servershop.sell.not_available", itemStack.getName()), true); + player.sendMessage(Text.translatable("message.servershop.sell.not_available", itemStack.getName()), overlay); } } } diff --git a/src/main/java/systems/brn/servershop/lib/Util.java b/src/main/java/systems/brn/servershop/lib/Util.java index c36cac3..4554238 100644 --- a/src/main/java/systems/brn/servershop/lib/Util.java +++ b/src/main/java/systems/brn/servershop/lib/Util.java @@ -1,11 +1,24 @@ package systems.brn.servershop.lib; +import eu.pb4.polymer.core.api.other.PolymerComponent; +import net.minecraft.component.ComponentType; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.LoreComponent; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.Inventory; import net.minecraft.item.ItemStack; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import net.minecraft.text.*; +import net.minecraft.util.Formatting; import net.minecraft.util.Identifier; +import systems.brn.servershop.ItemPrice; import systems.brn.servershop.ServerShop; +import java.util.ArrayList; +import java.util.List; +import java.util.function.UnaryOperator; + public class Util { public static Identifier id(String path) { @@ -99,4 +112,68 @@ public class Util { return stack; } + + public static ItemStack removePrices(ItemStack stack) { + LoreComponent oldLore = stack.get(DataComponentTypes.LORE); + + if (oldLore != null) { + ItemStack newStack = stack.copy(); + ArrayList filteredLines = new ArrayList<>(); + for (Text text : oldLore.styledLines()) { + if (text instanceof MutableText mutableText) { + TextContent textContent = mutableText.getContent(); + if (textContent instanceof TranslatableTextContent translatableTextContent) { + String key = translatableTextContent.getKey(); + if (!key.equals("gui.servershop.item.buyprice") && !key.equals("gui.servershop.item.sellprice")) { + filteredLines.add(text); + } + } + } + } + LoreComponent newLore = new LoreComponent(filteredLines); + + newStack.set(DataComponentTypes.LORE, newLore); + return newStack; + } else { + return stack; + } + } + + public static ItemStack addPrices(ItemPrice price) { + ItemStack stack = price.stack(); + int buyPrice = price.buyPrice(); + int sellPrice = price.sellPrice(); + int count = stack.getCount(); + if (count > 0) { + ItemStack newStack = stack.copy(); + LoreComponent lore = stack.get(DataComponentTypes.LORE); + Text buyLine = Text.translatable("gui.servershop.item.buyprice", buyPrice).setStyle(Style.EMPTY.withColor(Formatting.DARK_GREEN).withItalic(true)); + Text sellLine = Text.translatable("gui.servershop.item.sellprice", sellPrice).setStyle(Style.EMPTY.withColor(Formatting.AQUA).withItalic(true)); + + LoreComponent newLore; + if (lore == null) { + List loreList = new ArrayList<>(); + if (buyPrice > 0) { + loreList.addFirst(buyLine); + } + if (sellPrice > 0) { + loreList.addFirst(sellLine); + } + newLore = new LoreComponent(loreList); + } else { + List newLines = new ArrayList<>(lore.lines()); + if (buyPrice > 0) { + newLines.addFirst(buyLine); + } + if (sellPrice > 0) { + newLines.addFirst(sellLine); + } + newLore = new LoreComponent(newLines); + } + newStack.set(DataComponentTypes.LORE, newLore); + return newStack; + } else { + return stack; + } + } } diff --git a/src/main/java/systems/brn/servershop/screens/ShopScreen.java b/src/main/java/systems/brn/servershop/screens/ShopScreen.java index e318f59..42aa301 100644 --- a/src/main/java/systems/brn/servershop/screens/ShopScreen.java +++ b/src/main/java/systems/brn/servershop/screens/ShopScreen.java @@ -3,10 +3,6 @@ package systems.brn.servershop.screens; import eu.pb4.sgui.api.ClickType; import eu.pb4.sgui.api.elements.GuiElementBuilder; import eu.pb4.sgui.api.elements.GuiElementInterface; -import net.minecraft.component.DataComponentTypes; -import net.minecraft.component.type.LoreComponent; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.screen.slot.SlotActionType; @@ -16,11 +12,9 @@ import net.minecraft.util.Formatting; import systems.brn.servershop.ItemPrice; import systems.brn.servershop.ServerShop; import systems.brn.servershop.lib.PagedGui; -import systems.brn.servershop.lib.ShopFunctions; import java.util.*; -import static systems.brn.servershop.ServerShop.balanceManager; import static systems.brn.servershop.lib.ShopFunctions.buy; import static systems.brn.servershop.lib.ShopFunctions.sell; import static systems.brn.servershop.lib.Util.*; @@ -29,7 +23,7 @@ public class ShopScreen extends PagedGui { public String searchQuery = ""; - final public HashMap filteredPrices = new HashMap<>(); + final public HashMap filteredPrices = new HashMap<>(); public ShopScreen(ServerPlayerEntity player) { super(player, null); @@ -50,12 +44,12 @@ public class ShopScreen extends PagedGui { public void filterPrices() { filteredPrices.clear(); - for (Item item : ServerShop.priceStorage.prices.keySet()) { - String itemName = item.toString(); + for (ItemStack stack : ServerShop.priceStorage.prices.keySet()) { + String itemName = stack.getItem().toString(); if (itemName.contains(searchQuery)) { - ItemPrice price = ServerShop.priceStorage.prices.get(item); + ItemPrice price = ServerShop.priceStorage.getPrices(stack); if (price.buyPrice() > 0 || price.sellPrice() > 0) { - filteredPrices.put(item, price); + filteredPrices.put(stack, price); } } } @@ -74,45 +68,36 @@ public class ShopScreen extends PagedGui { @Override public boolean onClick(int index, ClickType type, SlotActionType action, GuiElementInterface element) { - Item item = element.getItemStack().getItem(); - ItemStack itemStack = item.getDefaultStack(); - if (type.shift) { - itemStack.setCount(itemStack.getMaxCount()); - } - if (type.isLeft) { //buy - buy(itemStack, player); + ItemStack cursorStack = getPlayer().currentScreenHandler.getCursorStack(); + if (!cursorStack.isEmpty()) { + sell(cursorStack, player, true); + } else { + ItemStack itemStack = removePrices(element.getItemStack()); + if (type.shift) { + itemStack.setCount(itemStack.getMaxCount()); + } + if (type.isLeft) { //buy + buy(itemStack.copy(), player, true); - } else if (type.isRight) { //sell - sell(itemStack, player); + } else if (type.isRight) { //sell + sell(itemStack.copy(), player, true); + } } return false; } - public static ItemStack getItemStack(Map.Entry price) { - ItemPrice itemPrice = price.getValue(); - Item item = price.getKey(); - int buyPrice = itemPrice.buyPrice(); - int sellPrice = itemPrice.sellPrice(); - ItemStack stack = item.getDefaultStack(); - LoreComponent originalLore = stack.getOrDefault(DataComponentTypes.LORE, new LoreComponent(List.of())); - - ArrayList lore = new ArrayList<>(originalLore.lines()); - if (buyPrice > 0) { - lore.add(Text.translatable("gui.servershop.item.buyprice", buyPrice)); - } - if (sellPrice > 0) { - lore.add(Text.translatable("gui.servershop.item.sellprice", sellPrice)); - } - stack.set(DataComponentTypes.LORE, new LoreComponent(lore)); - return stack; + @Override + public boolean insertItem(ItemStack stack, int startIndex, int endIndex, boolean fromLast) { + sell(stack, player, true); + return super.insertItem(stack, startIndex, endIndex, fromLast); } @Override protected DisplayElement getElement(int id) { - List> list = new ArrayList<>(filteredPrices.entrySet()); + List> list = new ArrayList<>(filteredPrices.entrySet()); if (id < list.size()) { - Map.Entry itemPriceEntry = list.get(id); - ItemStack stack = getItemStack(itemPriceEntry); + Map.Entry itemPriceEntry = list.get(id); + ItemStack stack = addPrices(itemPriceEntry.getValue()); GuiElementBuilder elementBuilder = new GuiElementBuilder(stack); return DisplayElement.of(elementBuilder); diff --git a/src/main/resources/assets/servershop/lang/en_us.json b/src/main/resources/assets/servershop/lang/en_us.json index 58e6c71..09db1c8 100644 --- a/src/main/resources/assets/servershop/lang/en_us.json +++ b/src/main/resources/assets/servershop/lang/en_us.json @@ -16,9 +16,13 @@ "message.servershop.balance.set_other": "%s now has %d on his account", "message.servershop.buy.not_enough": "You don't have enough money (%d>%d), you need %d more", "message.servershop.buy.inventory": "You don't have enough inventory space", - "message.servershop.buy.success": "You bought %d %s for %d", + "message.servershop.buy.success": "You bought %d %s for %d, now you have %d", "message.servershop.buy.not_available": "This item (%s) is not available for buying", "message.servershop.sell.not_enough": "You don't have this item", - "message.servershop.sell.success": "You sold %d %s for %d", - "message.servershop.sell.not_available": "This item (%s) is not available for sale" + "message.servershop.sell.success": "You sold %d %s for %d, now you have %d", + "message.servershop.sell.not_available": "This item (%s) is not available for sale", + "message.servershop.price.both" : "This item (%s) can be bought for %d and sold for %d", + "message.servershop.price.buy" : "This item (%s) can be bought for %d and can't be sold", + "message.servershop.price.sell" : "This item (%s) can be sold for %d and can't bought", + "message.servershop.price.neither" : "This item (%s) can't be bought or sold" } \ No newline at end of file diff --git a/src/main/resources/assets/servershop/textures/icon.png b/src/main/resources/assets/servershop/textures/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ca9ae887e1bb3bf6215ac3330245f70412f6f835 GIT binary patch literal 44538 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