treasure chests
Some checks failed
Build / build (push) Failing after 3s

This commit is contained in:
unurled 2024-04-09 22:00:16 +02:00
parent acc7f076e0
commit c3c82b4478
Signed by: unurled
GPG key ID: FDBC9CBE1F82423F
7 changed files with 285 additions and 96 deletions

View file

@ -1,5 +1,6 @@
package me.unurled.sacredrealms.sr.commands.admin; package me.unurled.sacredrealms.sr.commands.admin;
import static me.unurled.sacredrealms.sr.utils.Component.NOT_PLAYER;
import static me.unurled.sacredrealms.sr.utils.Component.textComp; import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import java.util.List; import java.util.List;
@ -7,6 +8,7 @@ import java.util.Set;
import me.unurled.sacredrealms.sr.components.treasure.Treasure; import me.unurled.sacredrealms.sr.components.treasure.Treasure;
import me.unurled.sacredrealms.sr.components.treasure.TreasureManager; import me.unurled.sacredrealms.sr.components.treasure.TreasureManager;
import me.unurled.sacredrealms.sr.gui.treasure.TreasureGUI; import me.unurled.sacredrealms.sr.gui.treasure.TreasureGUI;
import me.unurled.sacredrealms.sr.managers.Manager;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
@ -22,6 +24,97 @@ public class TreasureCommand implements TabExecutor {
public static final Set<Material> TRANSPARENT = public static final Set<Material> TRANSPARENT =
Set.of(Material.AIR, Material.CAVE_AIR, Material.VOID_AIR, Material.WATER, Material.LAVA); Set.of(Material.AIR, Material.CAVE_AIR, Material.VOID_AIR, Material.WATER, Material.LAVA);
public static final String SR_TREASURE_PERMISSION = "sr.treasure.";
public static final String CREATE = "create";
public static final String MODIFY = "modify";
public static final String LIST = "list";
public static final String DELETE = "delete";
private static void delete(@NotNull CommandSender sender, TreasureManager instance) {
Block block;
if (!(sender instanceof Player p)) {
sender.sendMessage(NOT_PLAYER);
return;
}
block = p.getTargetBlock(TRANSPARENT, 3);
if (block.getBlockData().getMaterial().equals(Material.CHEST)) {
// find the treasure chest
Treasure treasure = instance.findByLocation(block.getLocation());
if (treasure == null) {
sender.sendMessage("No treasure chest found at this location.");
return;
}
// remove the treasure chest
instance.removeTreasure(treasure);
}
}
private static void list(@NotNull CommandSender sender, @NotNull TreasureManager instance) {
sender.sendMessage("Treasures:");
for (Treasure treasure : instance.getTreasures()) {
String s =
String.format(
"<click:run_command:tp %s %s %s>%s</click>x: %s, y: %s, z: %s",
treasure.getLocation().getBlockX(),
treasure.getLocation().getBlockY(),
treasure.getLocation().getBlockZ(),
treasure.getLocation().toString(),
treasure.getLocation().getBlockX(),
treasure.getLocation().getBlockY(),
treasure.getLocation().getBlockZ());
Component text = textComp(s);
sender.sendMessage(text);
}
}
private static void modify(@NotNull CommandSender sender, TreasureManager instance) {
Block block;
if (!(sender instanceof Player p)) {
sender.sendMessage(NOT_PLAYER);
return;
}
block = p.getTargetBlock(TRANSPARENT, 3);
if (block.getBlockData().getMaterial().equals(Material.CHEST)) {
// find the treasure chest
Treasure treasure = instance.findByLocation(block.getLocation());
if (treasure == null) {
sender.sendMessage("No treasure chest found at this location.");
return;
}
// open the GUI
Window window =
Window.single()
.setViewer(p)
.setTitle("Attributes")
.setGui(TreasureGUI.createGui(treasure))
.build();
window.open();
}
}
private static void create(
@NotNull CommandSender sender, @NotNull String @NotNull [] args, TreasureManager instance) {
Block block;
if (!(sender instanceof Player p)) {
sender.sendMessage(NOT_PLAYER);
return;
}
block = p.getTargetBlock(TRANSPARENT, 3);
if (block.getBlockData().getMaterial().equals(Material.CHEST)) {
// create a new treasure chest
Treasure treasure;
if (args.length == 2) {
if (!args[1].startsWith(SR_TREASURE_PERMISSION)) {
p.sendMessage(textComp("<red>Invalid permission node. It must start with sr.treasure."));
return;
}
treasure = new Treasure(instance.getNextId(), block.getLocation(), args[1]);
} else {
treasure = new Treasure(instance.getNextId(), block.getLocation());
}
instance.addTreasure(treasure);
}
}
/** /**
* Executes the given command, returning its success. <br> * Executes the given command, returning its success. <br>
@ -39,97 +132,19 @@ public class TreasureCommand implements TabExecutor {
@NotNull CommandSender sender, @NotNull CommandSender sender,
@NotNull Command command, @NotNull Command command,
@NotNull String label, @NotNull String label,
@NotNull String[] args) { @NotNull String @NotNull [] args) {
// create, modify, list, get, delete // create, modify, list, get, delete
if (args.length == 0) { if (args.length == 0) {
sender.sendMessage("Usage: /treasure <create|modify|list|delete>"); sender.sendMessage("Usage: /treasure <create|modify|list|delete>");
return true; return true;
} }
Block block; final TreasureManager instance = Manager.getInstance(TreasureManager.class);
switch (args[0]) { switch (args[0]) {
case "create" -> { case CREATE -> create(sender, args, instance);
if (!(sender instanceof Player p)) { case MODIFY -> modify(sender, instance);
sender.sendMessage("You must be a player to use this command."); case LIST -> list(sender, instance);
return true; case DELETE -> delete(sender, instance);
} default -> sender.sendMessage("Usage: /treasure <create|modify|list|delete>");
block = p.getTargetBlock(TRANSPARENT, 3);
if (block.getBlockData().getMaterial().equals(Material.CHEST)) {
// create a new treasure chest
Treasure treasure;
if (args.length == 2) {
treasure = new Treasure(block.getLocation(), args[1]);
} else {
treasure = new Treasure(block.getLocation());
}
TreasureManager.getInstance(TreasureManager.class).addTreasure(treasure);
}
}
case "modify" -> {
if (!(sender instanceof Player p)) {
sender.sendMessage("You must be a player to use this command.");
return true;
}
block = p.getTargetBlock(TRANSPARENT, 3);
if (block.getBlockData().getMaterial().equals(Material.CHEST)) {
// find the treasure chest
Treasure treasure =
TreasureManager.getInstance(TreasureManager.class)
.findByLocation(block.getLocation());
if (treasure == null) {
sender.sendMessage("No treasure chest found at this location.");
return true;
}
// open the GUI
Window window =
Window.single()
.setViewer(p)
.setTitle("Attributes")
.setGui(TreasureGUI.createGui(treasure))
.build();
window.open();
}
}
case "list" -> {
sender.sendMessage("Treasures:");
for (Treasure treasure :
TreasureManager.getInstance(TreasureManager.class).getTreasures()) {
String s =
String.format(
"<click:run_command:tp %s %s %s>%s</click>x: %s, y: %s, z: %s",
treasure.getLocation().getBlockX(),
treasure.getLocation().getBlockY(),
treasure.getLocation().getBlockZ(),
treasure.getLocation().toString(),
treasure.getLocation().getBlockX(),
treasure.getLocation().getBlockY(),
treasure.getLocation().getBlockZ());
Component text = textComp(s);
sender.sendMessage(text);
}
}
case "delete" -> {
if (!(sender instanceof Player p)) {
sender.sendMessage("You must be a player to use this command.");
return true;
}
block = p.getTargetBlock(TRANSPARENT, 3);
if (block.getBlockData().getMaterial().equals(Material.CHEST)) {
// find the treasure chest
Treasure treasure =
TreasureManager.getInstance(TreasureManager.class)
.findByLocation(block.getLocation());
if (treasure == null) {
sender.sendMessage("No treasure chest found at this location.");
return true;
}
// remove the treasure chest
TreasureManager.getInstance(TreasureManager.class).removeTreasure(treasure);
}
}
default -> {
sender.sendMessage("Usage: /treasure <create|modify|list|delete>");
return true;
}
} }
return true; return true;
} }
@ -151,7 +166,17 @@ public class TreasureCommand implements TabExecutor {
@NotNull CommandSender sender, @NotNull CommandSender sender,
@NotNull Command command, @NotNull Command command,
@NotNull String label, @NotNull String label,
@NotNull String[] args) { @NotNull String @NotNull [] args) {
if (args.length == 0) {
return List.of(CREATE, MODIFY, LIST, DELETE);
}
if (args.length == 2 && (args[0].equals(CREATE))) {
if (args[1].startsWith(SR_TREASURE_PERMISSION)) {
return List.of();
}
return List.of(SR_TREASURE_PERMISSION);
}
return List.of(); return List.of();
} }
} }

View file

@ -38,6 +38,7 @@ public class SRPlayer {
private Map<Attribute, Map<ItemStack, Double>> itemAttributes = new EnumMap<>(Attribute.class); private Map<Attribute, Map<ItemStack, Double>> itemAttributes = new EnumMap<>(Attribute.class);
@Expose private List<PotionEffect> potionEffects = new ArrayList<>(); @Expose private List<PotionEffect> potionEffects = new ArrayList<>();
@Expose private Inventory inventory = null; @Expose private Inventory inventory = null;
@Expose private List<Integer> treasuresOpened = new ArrayList<>();
public SRPlayer(@NotNull UUID uuid) { public SRPlayer(@NotNull UUID uuid) {
this.uuid = uuid; this.uuid = uuid;
@ -259,4 +260,16 @@ public class SRPlayer {
} }
this.experience = experience; this.experience = experience;
} }
public List<Integer> getTreasuresOpened() {
return treasuresOpened;
}
public boolean hasOpenedTreasure(int id) {
return treasuresOpened.contains(id);
}
public void addTreasureOpened(int id) {
treasuresOpened.add(id);
}
} }

View file

@ -1,12 +1,19 @@
package me.unurled.sacredrealms.sr.components.treasure; package me.unurled.sacredrealms.sr.components.treasure;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
public class Treasure { public class Treasure {
private int id;
/** Chest location */ /** Chest location */
private Location location; private Location location;
@ -16,26 +23,40 @@ public class Treasure {
/** Permission to access this chest */ /** Permission to access this chest */
private String permission; private String permission;
public Treasure() {} public Treasure(int id, Location location) {
this.id = id;
public Treasure(Location location) {
this.location = location; this.location = location;
this.items = new HashMap<>(); this.items = new HashMap<>();
this.permission = ""; this.permission = "";
} }
public Treasure(Location location, String permission) { public Treasure(int id, Location location, String permission) {
this.id = id;
this.location = location; this.location = location;
this.items = new HashMap<>(); this.items = new HashMap<>();
this.permission = permission; this.permission = permission;
} }
public Treasure(Location location, Map<Integer, ItemStack> items, String permission) { public Treasure(int id, Location location, Map<Integer, ItemStack> items, String permission) {
this.id = id;
this.location = location; this.location = location;
this.items = items; this.items = items;
this.permission = permission; this.permission = permission;
} }
/**
* Get the id of the treasure
*
* @return the id of the treasure
*/
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
/** /**
* Get the location of the treasure * Get the location of the treasure
* *
@ -74,4 +95,12 @@ public class Treasure {
public void setPermission(String permission) { public void setPermission(String permission) {
this.permission = permission; this.permission = permission;
} }
public Inventory getInventory() {
Inventory inv = Bukkit.createInventory(null, InventoryType.CHEST, textComp("Treasure"));
for (Map.Entry<Integer, ItemStack> entry : items.entrySet()) {
inv.setItem(entry.getKey(), entry.getValue());
}
return inv;
}
} }

View file

@ -43,7 +43,7 @@ public class TreasureDeserializer implements JsonDeserializer<Treasure> {
.registerTypeAdapter(ItemStack.class, new ItemStackDeserializer()) .registerTypeAdapter(ItemStack.class, new ItemStackDeserializer())
.create(); .create();
try { try {
Integer id = gson.fromJson("id", Integer.class);
String loc = gson.fromJson("location", String.class); String loc = gson.fromJson("location", String.class);
String[] parts = loc.split(","); String[] parts = loc.split(",");
if (parts.length != 6) { if (parts.length != 6) {
@ -65,7 +65,7 @@ public class TreasureDeserializer implements JsonDeserializer<Treasure> {
return null; return null;
} }
return new Treasure(location, item, permission); return new Treasure(id, location, item, permission);
} catch (Exception e) { } catch (Exception e) {
error("Error deserializing treasure: " + e.getMessage()); error("Error deserializing treasure: " + e.getMessage());

View file

@ -1,26 +1,43 @@
package me.unurled.sacredrealms.sr.components.treasure; package me.unurled.sacredrealms.sr.components.treasure;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import io.papermc.paper.event.packet.PlayerChunkLoadEvent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import me.unurled.sacredrealms.sr.components.player.PlayerManager;
import me.unurled.sacredrealms.sr.components.player.SRPlayer;
import me.unurled.sacredrealms.sr.data.DataHandler; import me.unurled.sacredrealms.sr.data.DataHandler;
import me.unurled.sacredrealms.sr.data.DataManager; import me.unurled.sacredrealms.sr.data.DataManager;
import me.unurled.sacredrealms.sr.managers.Manager; import me.unurled.sacredrealms.sr.managers.Manager;
import org.bukkit.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class TreasureManager extends Manager { public class TreasureManager extends Manager {
private final List<Treasure> treasures = new ArrayList<>(); private final List<Treasure> treasures = new ArrayList<>();
private int nextId = 0;
/** Save the data */ /** Save the data */
@Override @Override
public void saveData() { public void saveData() {
// save all treasures // save all treasures
for (Treasure treasure : treasures) { for (Treasure treasure : treasures) {
// serialize treasure // serialize treasure
DataHandler dh = DataManager.getInstance(DataManager.class).getDataHandler(); DataHandler dh = Manager.getInstance(DataManager.class).getDataHandler();
Gson gson = Gson gson =
new GsonBuilder().registerTypeAdapter(Treasure.class, new TreasureSerializer()).create(); new GsonBuilder().registerTypeAdapter(Treasure.class, new TreasureSerializer()).create();
dh.set("treasures." + treasures.indexOf(treasure), gson.toJson(treasure)); dh.set("treasures." + treasures.indexOf(treasure), gson.toJson(treasure));
@ -31,17 +48,18 @@ public class TreasureManager extends Manager {
@Override @Override
public void loadData() { public void loadData() {
// load all treasures // load all treasures
DataHandler dh = DataManager.getInstance(DataManager.class).getDataHandler(); DataHandler dh = Manager.getInstance(DataManager.class).getDataHandler();
Gson gson = Gson gson =
new GsonBuilder().registerTypeAdapter(Treasure.class, new TreasureDeserializer()).create(); new GsonBuilder().registerTypeAdapter(Treasure.class, new TreasureDeserializer()).create();
for (String key : dh.getKeysAll("treasures")) { for (String key : dh.getKeysAll("treasures")) {
// deserialize treasure // deserialize treasure
treasures.add(gson.fromJson(dh.get("treasures." + key), Treasure.class)); addTreasure(gson.fromJson(dh.get("treasures." + key), Treasure.class));
} }
} }
public void addTreasure(Treasure treasure) { public void addTreasure(Treasure treasure) {
treasures.add(treasure); treasures.add(treasure);
nextId = Math.max(nextId, treasure.getId() + 1);
} }
@Nullable @Nullable
@ -54,12 +72,113 @@ public class TreasureManager extends Manager {
return null; return null;
} }
@Nullable
public Treasure findByNearbyPlayer(@NotNull Location loc) {
for (Treasure treasure : treasures) {
if (treasure.getLocation().getWorld() != loc.getWorld()) {
continue;
}
if (treasure.getLocation().distance(loc) < 5) {
return treasure;
}
}
return null;
}
@NotNull @NotNull
public List<Treasure> getTreasures() { public List<Treasure> getTreasures() {
return treasures; return treasures;
} }
public void removeTreasure(@NotNull Treasure treasure) { public void removeTreasure(@NotNull Treasure treasure) {
Chunk chunk = treasure.getLocation().getChunk();
Arrays.stream(chunk.getEntities())
.map(
entity -> {
if (entity instanceof Player p) {
return p;
}
return null;
})
.forEach(
player -> {
if (player != null) {
player.sendBlockChange(treasure.getLocation(), Material.AIR.createBlockData());
}
});
treasures.remove(treasure); treasures.remove(treasure);
} }
public int getNextId() {
return nextId++;
}
@EventHandler
public void onChestOpen(@NotNull PlayerInteractEvent e) {
if (e.hasBlock()) {
Block clickedBlock = e.getClickedBlock();
if (clickedBlock == null
|| !clickedBlock.getBlockData().getMaterial().equals(Material.CHEST)) {
return;
}
onTreasureOpen(e, clickedBlock);
}
}
private void onTreasureOpen(PlayerInteractEvent e, Block clickedBlock) {
// it is a chest, lets loop on all treasure and find if the clicked block is a treasure chest
for (Treasure treasure : treasures) {
if (treasure.getLocation().equals(clickedBlock.getLocation())) {
// it is a treasure chest, lets open it
Player p = e.getPlayer();
if (!p.hasPermission(treasure.getPermission())) {
p.sendMessage("You don't have permission to open this chest");
p.playSound(p.getLocation(), Sound.BLOCK_ANVIL_BREAK, 1f, 0.5f);
e.setCancelled(true);
return;
}
e.setCancelled(true);
p.openInventory(treasure.getInventory());
SRPlayer srPlayer = Manager.getInstance(PlayerManager.class).getPlayer(p.getUniqueId());
if (srPlayer != null) {
srPlayer.addTreasureOpened(treasure.getId());
}
break;
}
}
}
@EventHandler
public void onCloseTreasure(@NotNull InventoryCloseEvent e) {
if (e.getView().title().contains(textComp("Treasure"))) {
Treasure treasure = findByNearbyPlayer(e.getPlayer().getLocation());
if (treasure != null) {
// drop all items to the ground
for (int i = 0; i < treasure.getInventory().getSize(); i++) {
ItemStack item = treasure.getInventory().getItem(i);
if (item != null) {
e.getPlayer().getWorld().dropItemNaturally(e.getPlayer().getLocation(), item);
}
}
Player p = (Player) e.getPlayer();
p.sendBlockChange(treasure.getLocation(), Material.AIR.createBlockData());
}
}
}
@EventHandler
public void onChunkLoad(@NotNull PlayerChunkLoadEvent e) {
Player p = e.getPlayer();
Treasure treasure = findByNearbyPlayer(p.getLocation());
if (treasure != null) {
SRPlayer srPlayer = Manager.getInstance(PlayerManager.class).getPlayer(p.getUniqueId());
if (srPlayer != null && srPlayer.hasOpenedTreasure(treasure.getId())) {
return;
}
// display chest to clientside builds
p.sendBlockChange(treasure.getLocation(), Material.CHEST.createBlockData());
}
}
} }

View file

@ -31,6 +31,7 @@ public class TreasureSerializer implements JsonSerializer<Treasure> {
@Override @Override
public JsonElement serialize(Treasure src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(Treasure src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject obj = new JsonObject(); JsonObject obj = new JsonObject();
obj.add("id", new JsonPrimitive(src.getId()));
obj.add("location", new JsonPrimitive(src.getLocation().toString())); obj.add("location", new JsonPrimitive(src.getLocation().toString()));
obj.add("permission", new JsonPrimitive(src.getPermission())); obj.add("permission", new JsonPrimitive(src.getPermission()));
Gson gson = Gson gson =

View file

@ -14,6 +14,8 @@ import xyz.xenondevs.invui.item.impl.SimpleItem;
public class TreasureGUI { public class TreasureGUI {
private TreasureGUI() {}
@NotNull @NotNull
public static Gui createGui(@NotNull Treasure treasure) { public static Gui createGui(@NotNull Treasure treasure) {
ItemStack itemStack = new ItemStack(Material.GRAY_STAINED_GLASS_PANE); ItemStack itemStack = new ItemStack(Material.GRAY_STAINED_GLASS_PANE);