From d664f5121477525f898a53bd1c02b9a474b01a07 Mon Sep 17 00:00:00 2001 From: jakub Date: Sun, 5 Apr 2026 11:05:05 +0200 Subject: [PATCH 1/5] =?UTF-8?q?Opravy:=20-=20blokaci=20dal=C5=A1=C3=ADch?= =?UTF-8?q?=20interakc=C3=AD=20z=20pozemkem?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ecoCraftCore/regions/RegionEvents.java | 196 +++++++++++++++++- 1 file changed, 191 insertions(+), 5 deletions(-) diff --git a/src/main/java/xyz/soukup/ecoCraftCore/regions/RegionEvents.java b/src/main/java/xyz/soukup/ecoCraftCore/regions/RegionEvents.java index 151a597..7033ea4 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/regions/RegionEvents.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/regions/RegionEvents.java @@ -1,16 +1,29 @@ package xyz.soukup.ecoCraftCore.regions; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Item; +import org.bukkit.entity.Minecart; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.inventory.InventoryPickupItemEvent; import org.bukkit.event.player.*; +import org.bukkit.event.vehicle.VehicleDestroyEvent; +import org.bukkit.event.vehicle.VehicleEntityCollisionEvent; import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataType; import xyz.soukup.ecoCraftCore.database.objects.Region; import xyz.soukup.ecoCraftCore.database.objects.RegionMember; +import static xyz.soukup.ecoCraftCore.EcoCraftCore.plugin; + public class RegionEvents implements Listener { @EventHandler @@ -40,7 +53,36 @@ public class RegionEvents implements Listener { block.getZ() ); - event.setCancelled(!allowed); + if (allowed){ + return; + } + + event.setCancelled(true); + } + + @EventHandler + public void onPlayerInteractPhysical(PlayerInteractEvent event){ + if (!event.getAction().equals(Action.PHYSICAL)){ + return; + } + + Player player = event.getPlayer(); + Location location = player.getLocation(); + + boolean allowed = isAllowedToInteract( + location.getWorld().getName(), + player, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ() + ); + + if (allowed){ + return; + } + + event.setCancelled(true); + } @EventHandler @@ -55,7 +97,11 @@ public class RegionEvents implements Listener { block.getZ() ); - event.setCancelled(!allowed); + if (allowed){ + return; + } + + event.setCancelled(true); } @EventHandler @@ -71,7 +117,11 @@ public class RegionEvents implements Listener { block.getZ() ); - event.setCancelled(!allowed); + if (allowed){ + return; + } + + event.setCancelled(true); } @EventHandler @@ -86,7 +136,11 @@ public class RegionEvents implements Listener { clickedBlock.getZ() ); - event.setCancelled(!allowed); + if (allowed){ + return; + } + + event.setCancelled(true); } @EventHandler @@ -101,10 +155,142 @@ public class RegionEvents implements Listener { clickedBlock.getZ() ); - event.setCancelled(!allowed); + if (allowed){ + return; + } + + event.setCancelled(true); } + @EventHandler + public void onEntityInteract(PlayerInteractEntityEvent event){ + Entity entity = event.getRightClicked(); + Location location = entity.getLocation(); + + + boolean allowed = isAllowedToInteract( + location.getWorld().getName(), + event.getPlayer(), + location.getBlockX(), + location.getBlockY(), + location.getBlockZ()); + + if (allowed){ + return; + } + + event.setCancelled(true); + } + + @EventHandler + public void onEntityHit(EntityDamageByEntityEvent event){ + + if (!(event.getDamager() instanceof Player player)){ + return; + } + + Entity entity = event.getEntity(); + Location location = entity.getLocation(); + + boolean allowed = isAllowedToInteract( + location.getWorld().getName(), + player, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ()); + + if (allowed){ + return; + } + + event.setCancelled(true); + } + + @EventHandler + public void onMinecartPush(VehicleEntityCollisionEvent event) { + + + if (!(event.getEntity() instanceof Player player)){ + return; + } + + Location location = event.getVehicle().getLocation(); + + boolean allowed = isAllowedToInteract( + location.getWorld().getName(), + player, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ()); + + if (allowed){ + return; + } + + event.setCancelled(true); + } + + //Preventing hopper interaction :P + @EventHandler + public void onDrop(PlayerDropItemEvent event) { + Player player = event.getPlayer(); + Location location = player.getLocation(); + + boolean allowed = isAllowedToInteract( + location.getWorld().getName(), + player, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ()); + + if (allowed){ + return; + } + + Item item = event.getItemDrop(); + item.getPersistentDataContainer().set(new NamespacedKey(plugin, "hopper_stopper"), PersistentDataType.BYTE, (byte) 1); + + } + + @EventHandler + public void onHopperPickup(InventoryPickupItemEvent event) { + Item item = event.getItem(); + + if (!item.getPersistentDataContainer().has(new NamespacedKey(plugin, "hopper_stopper"), PersistentDataType.BYTE)) { + return; + } + + event.setCancelled(true); + } + + @EventHandler + public void onVehicleDestroy(VehicleDestroyEvent event) { + if (!(event.getAttacker() instanceof Player player)){ + return; + } + + Location location = event.getVehicle().getLocation(); + + boolean allowed = isAllowedToInteract( + location.getWorld().getName(), + player, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ()); + + if (allowed){ + return; + } + + event.setCancelled(true); + } + + + + private boolean isAllowedToInteract(String island, Player player, Location location){ + return isAllowedToInteract(island, player, location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } private boolean isAllowedToInteract(String island, Player player, int x, int y, int z){ if (player.isOp()){ From 4f6bfdf26d3190fd4cca4101b6e2893902fe7d91 Mon Sep 17 00:00:00 2001 From: jakub Date: Sun, 5 Apr 2026 18:22:56 +0200 Subject: [PATCH 2/5] Opravy: - confirm menu --- .../xyz/soukup/ecoCraftCore/EcoCraftCore.java | 3 +- .../ecoCraftCore/database/DaoRegistry.java | 2 +- .../ecoCraftCore/database/objects/Shop.java | 18 +++- .../objects}/VirtualChest.java | 47 +++++++++-- .../ecoCraftCore/messages/Messages.java | 3 +- .../soukup/ecoCraftCore/shop/ShopCommand.java | 2 +- .../soukup/ecoCraftCore/shop/ShopLogic.java | 83 ++++++++++++++++++- .../virtualChest/VirtualChestLogic.java | 83 ++++++++++++++++++- src/main/resources/messages.yml | 4 + 9 files changed, 227 insertions(+), 18 deletions(-) rename src/main/java/xyz/soukup/ecoCraftCore/{inventory => database/objects}/VirtualChest.java (70%) diff --git a/src/main/java/xyz/soukup/ecoCraftCore/EcoCraftCore.java b/src/main/java/xyz/soukup/ecoCraftCore/EcoCraftCore.java index aa96cc4..3c6d1d0 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/EcoCraftCore.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/EcoCraftCore.java @@ -6,7 +6,6 @@ import com.infernalsuite.asp.api.AdvancedSlimePaperAPI; import com.infernalsuite.asp.api.world.SlimeWorldInstance; import com.j256.ormlite.dao.DaoManager; import com.j256.ormlite.jdbc.DataSourceConnectionSource; -import com.j256.ormlite.jdbc.JdbcConnectionSource; import com.j256.ormlite.stmt.UpdateBuilder; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.TableUtils; @@ -40,7 +39,7 @@ import xyz.soukup.ecoCraftCore.database.objects.Island; import xyz.soukup.ecoCraftCore.database.objects.Shop; import xyz.soukup.ecoCraftCore.database.objects.Transaction; import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; -import xyz.soukup.ecoCraftCore.inventory.VirtualChest; +import xyz.soukup.ecoCraftCore.database.objects.VirtualChest; import xyz.soukup.ecoCraftCore.positionMarker.MarkerEvent; import xyz.soukup.ecoCraftCore.database.DaoRegistry; import xyz.soukup.ecoCraftCore.messages.Messages; diff --git a/src/main/java/xyz/soukup/ecoCraftCore/database/DaoRegistry.java b/src/main/java/xyz/soukup/ecoCraftCore/database/DaoRegistry.java index 9b62b01..eaf7907 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/database/DaoRegistry.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/database/DaoRegistry.java @@ -2,7 +2,7 @@ package xyz.soukup.ecoCraftCore.database; import com.j256.ormlite.dao.Dao; import xyz.soukup.ecoCraftCore.database.objects.*; -import xyz.soukup.ecoCraftCore.inventory.VirtualChest; +import xyz.soukup.ecoCraftCore.database.objects.VirtualChest; public class DaoRegistry { private static Dao shopDao; diff --git a/src/main/java/xyz/soukup/ecoCraftCore/database/objects/Shop.java b/src/main/java/xyz/soukup/ecoCraftCore/database/objects/Shop.java index 6317a3c..2df895e 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/database/objects/Shop.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/database/objects/Shop.java @@ -102,6 +102,7 @@ public class Shop { this.stock = stock; } + public static Shop findById(int id) { Shop shop = cache.get(id); @@ -116,6 +117,10 @@ public class Shop { } } + public static HashMap getCache(){ + return cache; + } + public void save(){ try { DaoRegistry.getShopDao().createOrUpdate(this); @@ -126,10 +131,21 @@ public class Shop { cache.put(this.id, this); } + public void delete(){ + try { + cache.remove(this.id); + DaoRegistry.getShopDao().delete(this); + } catch (SQLException e) { + throw new RuntimeException(e); + } + + } + public ItemStack getItemStack() { return Converter.itemstackFromString(this.itemStackString); } + public void writeIntoSign(Sign sign){ PDC.set(sign, "shop", this.id); @@ -159,7 +175,7 @@ public class Shop { } - public long getId() { + public int getId() { return id; } diff --git a/src/main/java/xyz/soukup/ecoCraftCore/inventory/VirtualChest.java b/src/main/java/xyz/soukup/ecoCraftCore/database/objects/VirtualChest.java similarity index 70% rename from src/main/java/xyz/soukup/ecoCraftCore/inventory/VirtualChest.java rename to src/main/java/xyz/soukup/ecoCraftCore/database/objects/VirtualChest.java index 5a09a87..4b7ba97 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/inventory/VirtualChest.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/database/objects/VirtualChest.java @@ -1,18 +1,22 @@ -package xyz.soukup.ecoCraftCore.inventory; +package xyz.soukup.ecoCraftCore.database.objects; import com.j256.ormlite.field.DataType; import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.stmt.DeleteBuilder; +import com.j256.ormlite.stmt.QueryBuilder; import com.j256.ormlite.table.DatabaseTable; import org.bukkit.block.Chest; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import xyz.soukup.ecoCraftCore.database.DaoRegistry; +import xyz.soukup.ecoCraftCore.inventory.InventoryUtils; import xyz.soukup.ecoCraftCore.utilities.Converter; import xyz.soukup.ecoCraftCore.utilities.PDC; import java.sql.SQLException; import java.util.HashMap; import java.util.HashSet; +import java.util.List; @DatabaseTable(tableName = "virtual_chests") public class VirtualChest { @@ -29,7 +33,7 @@ public class VirtualChest { private Inventory inventory; private static final HashMap cache = new HashMap<>(); - private static final HashSet cacheChanges = new HashSet<>(); + private static final HashSet changedCached = new HashSet<>(); public VirtualChest(){ @@ -77,7 +81,7 @@ public class VirtualChest { public static void saveCache(){ cache.forEach((key, value) -> { - if (!cacheChanges.contains(key)) return; + if (!changedCached.contains(key)) return; value.databaseSave(); }); @@ -87,7 +91,7 @@ public class VirtualChest { public void save() { cache.put(this.id, this); - cacheChanges.add(this.id); + changedCached.add(this.id); } public void databaseSave(){ @@ -101,7 +105,40 @@ public class VirtualChest { } cache.put(this.id, this); - cacheChanges.remove(this.id); + changedCached.remove(this.id); + } + + public void delete(){ + try { + DaoRegistry.getVirtualChestDao().delete(this); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public void deleteSelfAndShops(){ + QueryBuilder queryBuilder = DaoRegistry.getShopDao().queryBuilder(); + DeleteBuilder deleteBuilder = DaoRegistry.getShopDao().deleteBuilder(); + try { + queryBuilder + .selectColumns("id") + .where() + .eq("virtualChestID", this.id); + + List shops = queryBuilder.query(); + HashMap cache = Shop.getCache(); + + for(Shop shop : shops){ + cache.remove(shop.getId()); + } + + deleteBuilder.where().eq("virtualChestID", this.id); + deleteBuilder.delete(); + + DaoRegistry.getVirtualChestDao().delete(this); + } catch (SQLException e) { + throw new RuntimeException(e); + } } public void setInventory(Inventory inventory) { diff --git a/src/main/java/xyz/soukup/ecoCraftCore/messages/Messages.java b/src/main/java/xyz/soukup/ecoCraftCore/messages/Messages.java index 2371064..cfc7595 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/messages/Messages.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/messages/Messages.java @@ -4,6 +4,7 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.bukkit.command.CommandSender; import org.bukkit.configuration.file.YamlConfiguration; @@ -39,7 +40,7 @@ public class Messages { } public static String getAsString(String key){ - return MiniMessage.miniMessage().serialize(Messages.get(key)); + return LegacyComponentSerializer.legacySection().serialize(Messages.get(key)); } public static Component get(String key, HashMap placeholders){ diff --git a/src/main/java/xyz/soukup/ecoCraftCore/shop/ShopCommand.java b/src/main/java/xyz/soukup/ecoCraftCore/shop/ShopCommand.java index c53fbe0..a7c98d2 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/shop/ShopCommand.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/shop/ShopCommand.java @@ -11,7 +11,7 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import xyz.soukup.ecoCraftCore.positionMarker.MarkerEvent; import xyz.soukup.ecoCraftCore.database.objects.Shop; -import xyz.soukup.ecoCraftCore.inventory.VirtualChest; +import xyz.soukup.ecoCraftCore.database.objects.VirtualChest; import xyz.soukup.ecoCraftCore.inventory.InventoryUtils; import xyz.soukup.ecoCraftCore.messages.Messages; import xyz.soukup.ecoCraftCore.utilities.PDC; diff --git a/src/main/java/xyz/soukup/ecoCraftCore/shop/ShopLogic.java b/src/main/java/xyz/soukup/ecoCraftCore/shop/ShopLogic.java index e9905a6..78a3c0c 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/shop/ShopLogic.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/shop/ShopLogic.java @@ -1,6 +1,8 @@ package xyz.soukup.ecoCraftCore.shop; import com.github.stefvanschie.inventoryframework.gui.GuiItem; import com.github.stefvanschie.inventoryframework.gui.type.ChestGui; +import com.github.stefvanschie.inventoryframework.gui.type.HopperGui; +import com.github.stefvanschie.inventoryframework.pane.OutlinePane; import com.github.stefvanschie.inventoryframework.pane.StaticPane; import io.papermc.paper.dialog.Dialog; import io.papermc.paper.dialog.DialogResponseView; @@ -11,13 +13,16 @@ import io.papermc.paper.registry.data.dialog.input.DialogInput; import io.papermc.paper.registry.data.dialog.type.DialogType; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.event.ClickCallback; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Sign; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; @@ -29,7 +34,7 @@ import xyz.soukup.ecoCraftCore.messages.Messages; import xyz.soukup.ecoCraftCore.database.objects.Account; import xyz.soukup.ecoCraftCore.database.objects.Shop; import xyz.soukup.ecoCraftCore.database.objects.Transaction; -import xyz.soukup.ecoCraftCore.inventory.VirtualChest; +import xyz.soukup.ecoCraftCore.database.objects.VirtualChest; import xyz.soukup.ecoCraftCore.utilities.*; import java.util.HashMap; @@ -87,6 +92,39 @@ public class ShopLogic implements Listener { gui.show(player); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onDestroy(BlockBreakEvent event){ + + if (event.isCancelled()){ + return; + } + + Block block = event.getBlock(); + + if (!(block.getState() instanceof Sign sign)){ + return; + } + + Integer id = PDC.getInteger(sign, "shop"); + + if (id == null){ + return; + } + + Shop shop = Shop.findById(id); + + if (shop == null){ + return; + } + + event.setCancelled(true); + Player player = event.getPlayer(); + HopperGui gui = confirmBreakGui(block, shop); + gui.show(player); + + } public static ChestGui buildShopGui(Player player, Shop shop){ @@ -260,7 +298,7 @@ public class ShopLogic implements Listener { HashMap hashMap = new HashMap<>(); hashMap.put("count", Integer.toString(amount)); hashMap.put("price", String.format("%.2f", price)); - hashMap.put("item", itemStack.displayName().toString()); + hashMap.put("item", PlainTextComponentSerializer.plainText().serialize(itemStack.displayName())); Messages.send(player, "shop.buy", hashMap); @@ -348,9 +386,48 @@ public class ShopLogic implements Listener { HashMap hashMap = new HashMap<>(); hashMap.put("count", Integer.toString(amount)); hashMap.put("price", String.format("%.2f", price)); - hashMap.put("item", itemStack.displayName().toString()); + hashMap.put("item", PlainTextComponentSerializer.plainText().serialize(itemStack.displayName())); Messages.send(player, "shop.sell", hashMap); } + + public static HopperGui confirmBreakGui(Block block, Shop shop){ + HopperGui gui = new HopperGui(Messages.getAsString("menu.destroy-confirmation.title")); + OutlinePane pane = new OutlinePane(0,0, 5, 1); + + gui.setOnGlobalClick(inventoryClickEvent -> { + inventoryClickEvent.setCancelled(true); + }); + + GuiItem confirmButton = new GuiItemBuilder(Material.LIME_WOOL) + .setName(Messages.get("menu.destroy-confirmation.confirm")) + .build(); + + GuiItem cancelButton = new GuiItemBuilder(Material.RED_WOOL) + .setName(Messages.get("menu.destroy-confirmation.cancel")) + .build(); + + cancelButton.setAction(event -> { + event.getClickedInventory().close(); + }); + + confirmButton.setAction(event -> { + destroyShopAndBlock(block, shop); + event.getClickedInventory().close(); + }); + + pane.addItem(confirmButton); + pane.addItem(cancelButton); + + gui.getSlotsComponent().addPane(pane); + + + return gui; + } + + private static void destroyShopAndBlock(Block block, Shop shop){ + block.breakNaturally(); + shop.delete(); + } } diff --git a/src/main/java/xyz/soukup/ecoCraftCore/virtualChest/VirtualChestLogic.java b/src/main/java/xyz/soukup/ecoCraftCore/virtualChest/VirtualChestLogic.java index f84bf9f..14a6627 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/virtualChest/VirtualChestLogic.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/virtualChest/VirtualChestLogic.java @@ -1,17 +1,24 @@ package xyz.soukup.ecoCraftCore.virtualChest; -import org.bukkit.block.Chest; -import org.bukkit.block.DoubleChest; -import org.bukkit.block.TileState; +import com.github.stefvanschie.inventoryframework.gui.GuiItem; +import com.github.stefvanschie.inventoryframework.gui.type.HopperGui; +import com.github.stefvanschie.inventoryframework.pane.OutlinePane; +import org.bukkit.Material; +import org.bukkit.block.*; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.inventory.InventoryMoveItemEvent; import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; -import xyz.soukup.ecoCraftCore.inventory.VirtualChest; +import xyz.soukup.ecoCraftCore.database.objects.Shop; +import xyz.soukup.ecoCraftCore.gui.GuiItemBuilder; +import xyz.soukup.ecoCraftCore.database.objects.VirtualChest; +import xyz.soukup.ecoCraftCore.messages.Messages; import xyz.soukup.ecoCraftCore.utilities.PDC; import java.util.HashMap; @@ -20,6 +27,39 @@ public class VirtualChestLogic implements Listener { public static HashMap openedChests = new HashMap<>(); + @EventHandler(priority = EventPriority.HIGHEST) + public void blockBreak(BlockBreakEvent event){ + Block block = event.getBlock(); + BlockState blockState = block.getState(); + Player player = event.getPlayer(); + + Integer id; + + if (blockState instanceof Chest chest){ + id = PDC.getInteger(chest, "virtual"); + } else if (blockState instanceof DoubleChest doubleChest) { + id = PDC.getInteger((TileState) doubleChest.getRightSide(), "virtual"); + }else { + return; + } + + if (id == null){ + return; + } + + VirtualChest virtualChest = VirtualChest.findById(id); + + if (virtualChest == null){ + return; + } + + event.setCancelled(true); + + HopperGui gui = confirmBreakGui(block, virtualChest); + gui.show(player); + + } + @EventHandler public void chestOpen(InventoryOpenEvent event){ InventoryHolder inventoryHolder = event.getInventory().getHolder(); @@ -143,8 +183,43 @@ public class VirtualChestLogic implements Listener { virtualChest.save(); + } + public static HopperGui confirmBreakGui(Block block, VirtualChest virtualChest){ + HopperGui gui = new HopperGui(Messages.getAsString("menu.destroy-confirmation.title")); + OutlinePane pane = new OutlinePane(0,0, 5, 1); + + gui.setOnGlobalClick(inventoryClickEvent -> { + inventoryClickEvent.setCancelled(true); + }); + + GuiItem confirmButton = new GuiItemBuilder(Material.LIME_WOOL) + .setName(Messages.get("menu.destroy-confirmation.confirm")) + .build(); + + GuiItem cancelButton = new GuiItemBuilder(Material.RED_WOOL) + .setName(Messages.get("menu.destroy-confirmation.cancel")) + .build(); + + cancelButton.setAction(event -> { + event.getClickedInventory().close(); + }); + confirmButton.setAction(event -> { + destroyShopAndBlock(block, virtualChest); + event.getClickedInventory().close(); + }); + pane.addItem(confirmButton); + pane.addItem(cancelButton); + + gui.getSlotsComponent().addPane(pane); + + + return gui; + } + private static void destroyShopAndBlock(Block block, VirtualChest virtualChest){ + block.breakNaturally(); + virtualChest.deleteSelfAndShops(); } } \ No newline at end of file diff --git a/src/main/resources/messages.yml b/src/main/resources/messages.yml index 27f75fc..801f107 100644 --- a/src/main/resources/messages.yml +++ b/src/main/resources/messages.yml @@ -50,6 +50,10 @@ marker: primary: "První pozice označena (,,)" secondary: "Druhá pozice označena (,,)" menu: + destroy-confirmation: + title: "Zníčit obchod?" + confirm: "Ano." + cancel: "Ne." island-selector: title: "Výběr ostrovu" my-islands: "Moje ostrovy" From 375f5983af06d12bdcc7b2683f53586617bee126 Mon Sep 17 00:00:00 2001 From: jakub Date: Tue, 7 Apr 2026 21:36:47 +0200 Subject: [PATCH 3/5] =?UTF-8?q?-=20P=C5=99=C3=ADprava=20men=C3=AD=C4=8Dka?= =?UTF-8?q?=20a=20funkce=20pro=20=C3=BApravu=20cedulek?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xyz/soukup/ecoCraftCore/EcoCraftCore.java | 16 ++- .../messages/JoinLeaveMessageSupress.java | 18 ++++ .../ecoCraftCore/regions/RegionManager.java | 29 ++++++ .../ecoCraftCore/sign/SignEditCommand.java | 99 +++++++++++++++++++ src/main/resources/messages.yml | 16 +++ 5 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 src/main/java/xyz/soukup/ecoCraftCore/messages/JoinLeaveMessageSupress.java create mode 100644 src/main/java/xyz/soukup/ecoCraftCore/sign/SignEditCommand.java diff --git a/src/main/java/xyz/soukup/ecoCraftCore/EcoCraftCore.java b/src/main/java/xyz/soukup/ecoCraftCore/EcoCraftCore.java index 3c6d1d0..ee28dad 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/EcoCraftCore.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/EcoCraftCore.java @@ -24,6 +24,7 @@ import org.jetbrains.annotations.NotNull; import xyz.soukup.ecoCraftCore.database.objects.*; import xyz.soukup.ecoCraftCore.islands.IslandAdminCommand; import xyz.soukup.ecoCraftCore.islands.IslandSelectorCommand; +import xyz.soukup.ecoCraftCore.messages.JoinLeaveMessageSupress; import xyz.soukup.ecoCraftCore.mines.MineCommand; import xyz.soukup.ecoCraftCore.mines.MineWorldManager; import xyz.soukup.ecoCraftCore.money.MoneyCommand; @@ -85,6 +86,7 @@ public final class EcoCraftCore extends JavaPlugin { registerCommands(); registerEvents(); prepareSlimeWorldsSaver(); + prepareWorldInactivityUnloader(); }catch (IOException e) { MineWorldManager.init(); @@ -113,6 +115,7 @@ public final class EcoCraftCore extends JavaPlugin { AdvancedSlimePaperAPI asp = AdvancedSlimePaperAPI.instance(); for (SlimeWorldInstance slimeWorldInstance : asp.getLoadedWorlds()){ + getLogger().info("Saved database world " + slimeWorldInstance.getName()); try { asp.saveWorld(slimeWorldInstance); } catch (IOException e) { @@ -125,7 +128,7 @@ public final class EcoCraftCore extends JavaPlugin { private void prepareWorldInactivityUnloader(){ Bukkit.getScheduler().runTaskTimer(plugin, () -> { - long timeoutMillis = 30 * 60 * 1000; + long timeoutMillis = 6 * 60 * 1000; long now = System.currentTimeMillis(); AdvancedSlimePaperAPI asp = AdvancedSlimePaperAPI.instance(); @@ -148,6 +151,16 @@ public final class EcoCraftCore extends JavaPlugin { if ((now - emptySince) >= timeoutMillis) { Bukkit.unloadWorld(world, true); + getLogger().info("Unloading world " + world.getName() + " due to inactivity"); + try { + UpdateBuilder updateBuilder = DaoRegistry.getIslandDao().updateBuilder(); + updateBuilder.where().eq("uuid", world.getName()); + updateBuilder.updateColumnValue("active_on", ""); + updateBuilder.update(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } @@ -284,6 +297,7 @@ public final class EcoCraftCore extends JavaPlugin { pm.registerEvents(new PreparePlayer(), this); pm.registerEvents(new RegionEvents(), this); pm.registerEvents(new MineWorldManager(), this); + pm.registerEvents(new JoinLeaveMessageSupress(), this); EventManager events = PacketEvents.getAPI().getEventManager(); events.registerListener(new ChunkModifier(this), PacketListenerPriority.NORMAL); diff --git a/src/main/java/xyz/soukup/ecoCraftCore/messages/JoinLeaveMessageSupress.java b/src/main/java/xyz/soukup/ecoCraftCore/messages/JoinLeaveMessageSupress.java new file mode 100644 index 0000000..4b3e318 --- /dev/null +++ b/src/main/java/xyz/soukup/ecoCraftCore/messages/JoinLeaveMessageSupress.java @@ -0,0 +1,18 @@ +package xyz.soukup.ecoCraftCore.messages; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +public class JoinLeaveMessageSupress implements Listener { + @EventHandler + public void onJoin(PlayerJoinEvent event) { + event.joinMessage(null); + } + + @EventHandler + public void onQuit(PlayerQuitEvent event) { + event.quitMessage(null); + } +} diff --git a/src/main/java/xyz/soukup/ecoCraftCore/regions/RegionManager.java b/src/main/java/xyz/soukup/ecoCraftCore/regions/RegionManager.java index 14c480d..63c365c 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/regions/RegionManager.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/regions/RegionManager.java @@ -3,6 +3,7 @@ package xyz.soukup.ecoCraftCore.regions; import org.bukkit.Location; import org.bukkit.entity.Player; import xyz.soukup.ecoCraftCore.database.objects.Region; +import xyz.soukup.ecoCraftCore.database.objects.RegionMember; import xyz.soukup.ecoCraftCore.positionMarker.MarkerEvent; public class RegionManager { @@ -45,4 +46,32 @@ public class RegionManager { return 0; } + + public static boolean isAllowedToInteract(Player player, Location location){ + if (player.isOp()){ + return true; + } + + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + String island = location.getWorld().getName(); + + Region region = Region.findRegion(x, y, z, island); + + if (region == null){ + return false; + } + + String name = player.getName(); + + for (RegionMember regionMember : region.getRegionMembers()){ + + if (regionMember.getMembertype().equals("player") && regionMember.getName().equals(name)){ + return true; + } + } + + return false; + } } diff --git a/src/main/java/xyz/soukup/ecoCraftCore/sign/SignEditCommand.java b/src/main/java/xyz/soukup/ecoCraftCore/sign/SignEditCommand.java new file mode 100644 index 0000000..1d86395 --- /dev/null +++ b/src/main/java/xyz/soukup/ecoCraftCore/sign/SignEditCommand.java @@ -0,0 +1,99 @@ +package xyz.soukup.ecoCraftCore.sign; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; +import io.papermc.paper.dialog.Dialog; +import io.papermc.paper.registry.data.dialog.ActionButton; +import io.papermc.paper.registry.data.dialog.DialogBase; +import io.papermc.paper.registry.data.dialog.action.DialogAction; +import io.papermc.paper.registry.data.dialog.input.DialogInput; +import io.papermc.paper.registry.data.dialog.type.DialogType; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickCallback; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.Sign; +import org.bukkit.block.sign.Side; +import org.bukkit.block.sign.SignSide; +import org.bukkit.entity.Player; +import xyz.soukup.ecoCraftCore.database.objects.Shop; +import xyz.soukup.ecoCraftCore.messages.Messages; +import xyz.soukup.ecoCraftCore.regions.RegionManager; + +import java.util.ArrayList; +import java.util.List; + +public class SignEditCommand { + public static LiteralArgumentBuilder getCommand(){ + return Commands.literal("edit-sign") + .requires(source -> source.getSender() instanceof Player) + .executes(SignEditCommand::openEditMenu); + } + + private static int openEditMenu(CommandContext context){ + Player player = (Player) context.getSource().getSender(); + Block block = player.getTargetBlock(null, 10); + BlockState blockState = block.getState(); + + if (!(blockState instanceof Sign sign)){ + Messages.send(player, "sign-edit.error.not-sign"); + return 1; + } + + Location location = sign.getLocation(); + + if (!RegionManager.isAllowedToInteract(player, location)){ + Messages.send(player, "region.error.not-allowed-to-interact"); + return 1; + } + + + + return 0; + } + + @SuppressWarnings("UnstableApiUsage") + public static Dialog buildEditDialog(Sign sign){ + + SignSide signSide = sign.getSide(Side.FRONT); + List lines = signSide.lines(); + MiniMessage miniMessage = MiniMessage.miniMessage(); + + List actionButtons = new ArrayList<>(); + + actionButtons.add(ActionButton.builder(Messages.get("gui.shop-edit.button.confirm")) + .action(DialogAction.customClick( + (view, audience) -> {audience.closeDialog();}, + ClickCallback.Options.builder().build() + )) + .build()); + + return Dialog.create(builder -> builder.empty() + .base(DialogBase.builder(Messages.get("gui.shop-edit.title")) + .inputs(List.of( + DialogInput.text("line1", Messages.get("gui.sign-edit.inputs.line1")) + .initial(miniMessage.serialize(lines.getFirst())) + .build(), + DialogInput.text("line2", Messages.get("gui.sign-edit.inputs.line2")) + .initial(miniMessage.serialize(lines.get(1))) + .build(), + DialogInput.text("line3", Messages.get("gui.sign-edit.inputs.line3")) + .initial(miniMessage.serialize(lines.get(2))) + .build(), + DialogInput.text("line4", Messages.get("gui.sign-edit.inputs.line4")) + .initial(miniMessage.serialize(lines.get(3))) + .build() + + + )) + .build()) + .type(DialogType.multiAction(actionButtons).build()) + + ); + } + +} diff --git a/src/main/resources/messages.yml b/src/main/resources/messages.yml index 801f107..4c9b324 100644 --- a/src/main/resources/messages.yml +++ b/src/main/resources/messages.yml @@ -16,6 +16,10 @@ region: error: not-marked: "Musíš nejprve označit pozice" not-exist: "Region neexistuje" + not-allowed-to-interact: "Nemáš povolení dělat změny na tomto území" +sign-edit: + error: + not-sign: "Musíš se dívat na cedulku." shop: error: already-shop: "Tato cedule již je obchod" @@ -67,6 +71,18 @@ gui: error: invalid-input: "Vámi zadané hodnoty nejsou platné." all: "Seznam guis: <1>, <2>" + sign-edit: + title: "Editace Cedulky" + inputs: + line1: "1. řádek" + line2: "2. řádek" + line3: "3. řádek" + line4: "4. řádek" + buttons: + confirm: "Potvrdit" + cancel: "Zrušit" + copy: "Kopírovat" + paste: "Vložit" shop-edit: title: "Editace Obchodu" inputs: From b34c89f1c28b69ee7c21c525dbc40768f1892df6 Mon Sep 17 00:00:00 2001 From: jakub Date: Sun, 12 Apr 2026 20:41:42 +0200 Subject: [PATCH 4/5] =?UTF-8?q?-=20P=C5=99=C3=ADprava=20men=C3=AD=C4=8Dka?= =?UTF-8?q?=20a=20funkce=20pro=20=C3=BApravu=20cedulek?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xyz/soukup/ecoCraftCore/EcoCraftCore.java | 2 + .../ecoCraftCore/database/objects/Shop.java | 6 + .../ecoCraftCore/sign/SignEditCommand.java | 124 +++++++++++++++--- src/main/resources/messages.yml | 12 +- 4 files changed, 122 insertions(+), 22 deletions(-) diff --git a/src/main/java/xyz/soukup/ecoCraftCore/EcoCraftCore.java b/src/main/java/xyz/soukup/ecoCraftCore/EcoCraftCore.java index ee28dad..44053db 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/EcoCraftCore.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/EcoCraftCore.java @@ -45,6 +45,7 @@ import xyz.soukup.ecoCraftCore.positionMarker.MarkerEvent; import xyz.soukup.ecoCraftCore.database.DaoRegistry; import xyz.soukup.ecoCraftCore.messages.Messages; import xyz.soukup.ecoCraftCore.shop.ShopLogic; +import xyz.soukup.ecoCraftCore.sign.SignEditCommand; import xyz.soukup.ecoCraftCore.virtualChest.VirtualChestLogic; import java.io.IOException; @@ -284,6 +285,7 @@ public final class EcoCraftCore extends JavaPlugin { lm.registerEventHandler(LifecycleEvents.COMMANDS, event -> event.registrar().register(MarkerCommand.getCommand().build())); lm.registerEventHandler(LifecycleEvents.COMMANDS, event -> event.registrar().register(MoneyCommand.getCommand().build())); lm.registerEventHandler(LifecycleEvents.COMMANDS, event -> event.registrar().register(MineCommand.createCommand().build())); + lm.registerEventHandler(LifecycleEvents.COMMANDS, event -> event.registrar().register(SignEditCommand.getCommand().build())); } private void registerEvents(){ diff --git a/src/main/java/xyz/soukup/ecoCraftCore/database/objects/Shop.java b/src/main/java/xyz/soukup/ecoCraftCore/database/objects/Shop.java index 2df895e..86c53a5 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/database/objects/Shop.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/database/objects/Shop.java @@ -7,6 +7,7 @@ import org.bukkit.block.sign.Side; import org.bukkit.block.sign.SignSide; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.NotNull; import xyz.soukup.ecoCraftCore.database.DaoRegistry; import xyz.soukup.ecoCraftCore.utilities.Converter; @@ -149,6 +150,11 @@ public class Shop { public void writeIntoSign(Sign sign){ PDC.set(sign, "shop", this.id); + if (PDC.getUniversal(sign, "line1", PersistentDataType.STRING) != null){ + sign.update(); + return; + } + Component prices; Component shopType; diff --git a/src/main/java/xyz/soukup/ecoCraftCore/sign/SignEditCommand.java b/src/main/java/xyz/soukup/ecoCraftCore/sign/SignEditCommand.java index 1d86395..3d6b9d3 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/sign/SignEditCommand.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/sign/SignEditCommand.java @@ -5,11 +5,13 @@ import com.mojang.brigadier.context.CommandContext; import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.command.brigadier.Commands; import io.papermc.paper.dialog.Dialog; +import io.papermc.paper.dialog.DialogResponseView; import io.papermc.paper.registry.data.dialog.ActionButton; import io.papermc.paper.registry.data.dialog.DialogBase; import io.papermc.paper.registry.data.dialog.action.DialogAction; import io.papermc.paper.registry.data.dialog.input.DialogInput; import io.papermc.paper.registry.data.dialog.type.DialogType; +import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickCallback; import net.kyori.adventure.text.minimessage.MiniMessage; @@ -20,14 +22,22 @@ import org.bukkit.block.Sign; import org.bukkit.block.sign.Side; import org.bukkit.block.sign.SignSide; import org.bukkit.entity.Player; +import org.bukkit.persistence.PersistentDataType; import xyz.soukup.ecoCraftCore.database.objects.Shop; import xyz.soukup.ecoCraftCore.messages.Messages; import xyz.soukup.ecoCraftCore.regions.RegionManager; +import xyz.soukup.ecoCraftCore.utilities.PDC; +import javax.sound.sampled.Line; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; + public class SignEditCommand { + + private static final HashMap> clipBoard = new HashMap<>(); + public static LiteralArgumentBuilder getCommand(){ return Commands.literal("edit-sign") .requires(source -> source.getSender() instanceof Player) @@ -51,49 +61,127 @@ public class SignEditCommand { return 1; } + Dialog dialog = buildEditDialog(sign, player, null); + player.showDialog(dialog); + return 0; } - @SuppressWarnings("UnstableApiUsage") - public static Dialog buildEditDialog(Sign sign){ - SignSide signSide = sign.getSide(Side.FRONT); - List lines = signSide.lines(); - MiniMessage miniMessage = MiniMessage.miniMessage(); + public static Dialog buildEditDialog(Sign sign, Player player, List lines){ + + if (lines == null){ + lines = getLines(sign); + } List actionButtons = new ArrayList<>(); - actionButtons.add(ActionButton.builder(Messages.get("gui.shop-edit.button.confirm")) - .action(DialogAction.customClick( - (view, audience) -> {audience.closeDialog();}, - ClickCallback.Options.builder().build() - )) + + + actionButtons.add(ActionButton.builder(Messages.get("gui.sign-edit.buttons.copy")) + .action(DialogAction.customClick((view, audience) -> copySignText(view, player, sign), ClickCallback.Options.builder().build())) + .build()); + actionButtons.add(ActionButton.builder(Messages.get("gui.sign-edit.buttons.paste")) + .action(DialogAction.customClick((view, audience) -> pasteSignText(sign, player), ClickCallback.Options.builder().build())) + .build()); + actionButtons.add(ActionButton.builder(Messages.get("gui.sign-edit.buttons.confirm")) + .action(DialogAction.customClick((view, audience) -> editSign(view, sign, player), ClickCallback.Options.builder().build())) + .build()); + actionButtons.add(ActionButton.builder(Messages.get("gui.sign-edit.buttons.cancel")) + .action(DialogAction.customClick((view, audience) -> audience.closeDialog(), ClickCallback.Options.builder().build())) .build()); + + List finalLines = lines; + return Dialog.create(builder -> builder.empty() - .base(DialogBase.builder(Messages.get("gui.shop-edit.title")) + .base(DialogBase.builder(Messages.get("gui.sign-edit.title")) .inputs(List.of( DialogInput.text("line1", Messages.get("gui.sign-edit.inputs.line1")) - .initial(miniMessage.serialize(lines.getFirst())) + .initial(finalLines.getFirst()) + .maxLength(256) .build(), DialogInput.text("line2", Messages.get("gui.sign-edit.inputs.line2")) - .initial(miniMessage.serialize(lines.get(1))) + .initial(finalLines.get(1)) + .maxLength(256) .build(), DialogInput.text("line3", Messages.get("gui.sign-edit.inputs.line3")) - .initial(miniMessage.serialize(lines.get(2))) + .initial(finalLines.get(2)) + .maxLength(256) .build(), DialogInput.text("line4", Messages.get("gui.sign-edit.inputs.line4")) - .initial(miniMessage.serialize(lines.get(3))) + .initial(finalLines.get(3)) + .maxLength(256) .build() - - )) .build()) .type(DialogType.multiAction(actionButtons).build()) - ); } + private static List getLines(Sign sign){ + List lines = new ArrayList<>(); + + if (PDC.getUniversal(sign, "line1", PersistentDataType.STRING) != null){ + for (int i = 1; i<5; i++){ + lines.add((String) PDC.getUniversal(sign, "line" + i,PersistentDataType.STRING)); + } + return lines; + } + + SignSide signSide = sign.getSide(Side.FRONT); + List componentLines = signSide.lines(); + + for (Component componentLine : componentLines){ + lines.add(MiniMessage.miniMessage().serialize(componentLine)); + } + + return lines; + } + + private static void copySignText(DialogResponseView view, Player player, Sign sign){ + List lines = new ArrayList<>(); + + lines.add(view.getText("line1")); + lines.add(view.getText("line2")); + lines.add(view.getText("line3")); + lines.add(view.getText("line4")); + + clipBoard.put(player, lines); + Messages.send(player, "gui.sign-edit.success.copied"); + pasteSignText(sign, player); + } + + + private static void pasteSignText(Sign sign, Player player){ + Dialog dialog = buildEditDialog(sign, player, clipBoard.get(player)); + player.showDialog(dialog); + } + + private static void editSign(DialogResponseView view, Sign sign, Audience audience){ + MiniMessage mm = MiniMessage.miniMessage(); + SignSide signSide = sign.getSide(Side.FRONT); + + List lines = new ArrayList<>(); + + + for (int i = 1; i < 5; i++) { + String key = "line" + i; + String line = view.getText(key); + + if (line == null){ + line = ""; + } + + PDC.setUniversal(sign, key, line, PersistentDataType.STRING); + signSide.line(i-1, mm.deserialize(line)); + + } + sign.update(); + + } + + } diff --git a/src/main/resources/messages.yml b/src/main/resources/messages.yml index 4c9b324..b8f5bcf 100644 --- a/src/main/resources/messages.yml +++ b/src/main/resources/messages.yml @@ -74,15 +74,19 @@ gui: sign-edit: title: "Editace Cedulky" inputs: - line1: "1. řádek" - line2: "2. řádek" - line3: "3. řádek" - line4: "4. řádek" + line1: "1. Linka" + line2: "2. Linka" + line3: "3. Linka" + line4: "4. Linka" + glow: "Zvíraznit text" buttons: confirm: "Potvrdit" cancel: "Zrušit" copy: "Kopírovat" paste: "Vložit" + success: + copied: "Obsah cedulky zkopírován!" + pasted: "Obsah cedulky vložen!" shop-edit: title: "Editace Obchodu" inputs: From 04436cb6abe126f8b65f9377c406e08f5a3e15df Mon Sep 17 00:00:00 2001 From: jakub Date: Tue, 14 Apr 2026 11:42:35 +0200 Subject: [PATCH 5/5] =?UTF-8?q?-=20Zm=C4=9Bna=20biom=C5=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../islands/IslandAdminCommand.java | 25 ++++++++++++++++++- .../ecoCraftCore/islands/IslandManager.java | 12 +++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/main/java/xyz/soukup/ecoCraftCore/islands/IslandAdminCommand.java b/src/main/java/xyz/soukup/ecoCraftCore/islands/IslandAdminCommand.java index 5d7cd81..8af3232 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/islands/IslandAdminCommand.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/islands/IslandAdminCommand.java @@ -9,8 +9,11 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.command.brigadier.Commands; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.block.Biome; import org.bukkit.entity.Player; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; @@ -101,6 +104,15 @@ public class IslandAdminCommand { })) .executes(IslandAdminCommand::loadTemplate)); + LiteralArgumentBuilder setBiome = Commands.literal("biome") + .then(Commands.argument("biome", StringArgumentType.string()) + .suggests(((context, builder) -> { + Registry biomeRegistry = Registry.BIOME; + biomeRegistry.stream().forEach(biome -> builder.suggest(biome.getKey().asString())); + return builder.buildFuture(); + })) + .executes(IslandAdminCommand::setBiome)); + LiteralArgumentBuilder template = Commands.literal("template") .then(Commands.argument("uuid", StringArgumentType.word()) .suggests((context, builder) -> { @@ -165,7 +177,8 @@ public class IslandAdminCommand { .then(spawn) .then(enviroment) .then(expand) - .then(setDefaultIsland); + .then(setDefaultIsland) + .then(setBiome); @@ -202,6 +215,16 @@ public class IslandAdminCommand { return 0; } + private static int setBiome(CommandContext context) { + if (!(context.getSource().getSender() instanceof Player player)) return 0; + IslandManager islandManager = new IslandManager(); + String uuid = player.getWorld().getName(); + islandManager.changeBiome(context.getArgument("biome", String.class), uuid); + Messages.send(player, "island.set-biome.success"); + + return 0; + } + private static int teleport(CommandContext context) { IslandManager islandManager = new IslandManager(); diff --git a/src/main/java/xyz/soukup/ecoCraftCore/islands/IslandManager.java b/src/main/java/xyz/soukup/ecoCraftCore/islands/IslandManager.java index 301594f..34e6594 100644 --- a/src/main/java/xyz/soukup/ecoCraftCore/islands/IslandManager.java +++ b/src/main/java/xyz/soukup/ecoCraftCore/islands/IslandManager.java @@ -270,6 +270,18 @@ public class IslandManager { } } + public void changeBiome(String biome, String uuid){ + SlimeWorld slimeWorld = asp.getLoadedWorld(uuid); + SlimePropertyMap slimePropertyMap = slimeWorld.getPropertyMap(); + slimePropertyMap.setValue(SlimeProperties.DEFAULT_BIOME, biome); + + try { + asp.saveWorld(slimeWorld); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + public void changeEnviroment( String environment, String uuid) { SlimeWorld slimeWorld = asp.getLoadedWorld(uuid); SlimePropertyMap slimePropertyMap = slimeWorld.getPropertyMap();