This commit is contained in:
Bruno Rybársky 2024-08-20 14:30:19 +02:00
parent 346a14c2be
commit 3fbc86e658
15 changed files with 443 additions and 154 deletions

@ -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

@ -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<ItemStack> stack = ItemStack.fromNbt(wrapperLookup, stackElement);
return stack.map(itemStack -> new ItemPrice(buyPrice, sellPrice, itemStack)).orElse(null);
}
}

@ -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();
}
}

@ -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<ServerCommandSource> ctx) {
Item item = ItemStackArgumentType.getItemStackArgument(ctx, "item").getItem();
ItemStack stack = item.getDefaultStack();
return runStack(ctx, stack);
}
private static int runStack(CommandContext<ServerCommandSource> 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<ServerCommandSource> 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;
}
}

@ -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<ServerCommandSource> ctx) {
ServerShop.priceStorage.loadLegacy();
ctx.getSource().sendFeedback(() -> Text.translatable("message.servershop.storage.load"), false);
return 1;
}
public static int save(CommandContext<ServerCommandSource> ctx) {
boolean success = ServerShop.priceStorage.save();
ctx.getSource().sendFeedback(() ->
@ -29,17 +38,28 @@ public class ShopPricesCommand {
}
public static int set(CommandContext<ServerCommandSource> 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<ServerCommandSource> 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<ServerCommandSource> 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) {
ServerShop.priceStorage.setPrices(stack, buyPrice, sellPrice);
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;
}
}
}

@ -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;

@ -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<UUID, Long> balances = new HashMap<>();
private final HashMap<UUID, Long> 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");
}
fileWriter.close();
lock.unlock();
} catch (IOException e) {
lock.unlock();
return false;
}
return true;
NbtCompound nbtCompound = new NbtCompound();
nbtCompound.putUuid("UUID", uuid);
nbtCompound.putLong("Balance", balances.get(uuid));
nbtList.add(nbtCompound);
}
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();
}

@ -0,0 +1,5 @@
package systems.brn.servershop.lib;
public class ItemPriceStorage {
}

@ -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<Item, ItemPrice> prices = new HashMap<>();
public final HashMap<ItemStack, ItemPrice> 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<ItemStack> 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;
}
}

@ -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 {
player.sendMessage(Text.translatable("message.servershop.sell.not_available", itemStack.getName()), true);
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()), overlay);
}
}
}

@ -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<Text> 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<Text> loreList = new ArrayList<>();
if (buyPrice > 0) {
loreList.addFirst(buyLine);
}
if (sellPrice > 0) {
loreList.addFirst(sellLine);
}
newLore = new LoreComponent(loreList);
} else {
List<Text> 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;
}
}
}

@ -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<Item, ItemPrice> filteredPrices = new HashMap<>();
final public HashMap<ItemStack, ItemPrice> 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();
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, player);
buy(itemStack.copy(), player, true);
} else if (type.isRight) { //sell
sell(itemStack, player);
sell(itemStack.copy(), player, true);
}
}
return false;
}
public static ItemStack getItemStack(Map.Entry<Item, ItemPrice> 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<Text> 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<Map.Entry<Item, ItemPrice>> list = new ArrayList<>(filteredPrices.entrySet());
List<Map.Entry<ItemStack, ItemPrice>> list = new ArrayList<>(filteredPrices.entrySet());
if (id < list.size()) {
Map.Entry<Item, ItemPrice> itemPriceEntry = list.get(id);
ItemStack stack = getItemStack(itemPriceEntry);
Map.Entry<ItemStack, ItemPrice> itemPriceEntry = list.get(id);
ItemStack stack = addPrices(itemPriceEntry.getValue());
GuiElementBuilder elementBuilder = new GuiElementBuilder(stack);
return DisplayElement.of(elementBuilder);

@ -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"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

@ -7,7 +7,7 @@
"authors": [],
"contact": {},
"license": "MIT",
"icon": "assets/servershop/icon.png",
"icon": "assets/servershop/textures/icon.png",
"environment": "*",
"entrypoints": {
"main": [