Merge pull request #10 from Freezy-Studios/dev

Dev
This commit is contained in:
DaTTV 2025-02-18 19:26:44 +01:00 committed by GitHub
commit 12ec3c4347
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 942 additions and 49 deletions

1
.idea/modules.xml generated
View file

@ -2,6 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/modules/BlazeSMP.main.iml" filepath="$PROJECT_DIR$/.idea/modules/BlazeSMP.main.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/me.freezy.plugins.papermc.BlazeSMP.main.iml" filepath="$PROJECT_DIR$/.idea/modules/me.freezy.plugins.papermc.BlazeSMP.main.iml" />
</modules>
</component>

View file

@ -1,10 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="AdditionalModuleElements">
<content url="file://$MODULE_DIR$/../../build/generated/sources/annotationProcessor/java/main">
<sourceFolder url="file://$MODULE_DIR$/../../build/generated/sources/annotationProcessor/java/main" isTestSource="false" generated="true" />
</content>
</component>
<component name="FacetManager">
<facet type="minecraft" name="Minecraft">
<configuration>

View file

@ -1,8 +1,10 @@
package me.freezy.plugins.papermc.blazesmp;
import lombok.Getter;
import me.freezy.plugins.papermc.blazesmp.command.ClaimCommand;
import me.freezy.plugins.papermc.blazesmp.command.ClanCommand;
import me.freezy.plugins.papermc.blazesmp.listener.JoinListener;
import me.freezy.plugins.papermc.blazesmp.command.ReportCommand;
import me.freezy.plugins.papermc.blazesmp.listener.*;
import me.freezy.plugins.papermc.blazesmp.module.manager.Clans;
import me.freezy.plugins.papermc.blazesmp.module.manager.Homes;
import me.freezy.plugins.papermc.blazesmp.module.manager.ProtectedBlocks;
@ -60,11 +62,17 @@ public final class BlazeSMP extends JavaPlugin {
this.log.info("Registering Commands...");
new ClanCommand().register();
new ReportCommand().register();
new ClaimCommand().register();
this.log.info("Registered Commands!");
this.log.info("Registering EventListeners...");
PluginManager pm = getServer().getPluginManager();
pm.registerEvents(new JoinListener(), this);
pm.registerEvents(new PlayerJoinListener(), this);
pm.registerEvents(new PlayerChatListener(), this);
pm.registerEvents(new PlayerCommandBlockerListener(), this);
pm.registerEvents(new PlayerClaimListener(), this);
pm.registerEvents(new ChunkInventoryManager(), this);
this.log.info("Registered EventListeners!");
this.log.info("Starting Timer tasks...");

View file

@ -0,0 +1,93 @@
package me.freezy.plugins.papermc.blazesmp.command;
import me.freezy.plugins.papermc.blazesmp.BlazeSMP;
import me.freezy.plugins.papermc.blazesmp.command.util.SimpleCommand;
import me.freezy.plugins.papermc.blazesmp.listener.ChunkInventoryManager;
import me.freezy.plugins.papermc.blazesmp.module.Clan;
import me.freezy.plugins.papermc.blazesmp.module.manager.Clans;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Chunk;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public class ClaimCommand extends SimpleCommand {
private final Clans clans;
public ClaimCommand() {
super("claim", List.of("unclaim"));
this.clans = BlazeSMP.getInstance().getClans();
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage(MiniMessage.miniMessage().deserialize("<red>You must be a player to use this command!"));
return true;
}
UUID playerUUID = player.getUniqueId();
if (!clans.isInClan(playerUUID)) {
player.sendMessage(MiniMessage.miniMessage().deserialize("<red>You must be in a clan to claim/unclaim chunks!"));
return true;
} else {
if (label.equalsIgnoreCase("claim")) {
if (args.length != 0 && args[0].equalsIgnoreCase("see")) {
ChunkInventoryManager.openInv(player);
return true;
}
Clan playerClan = clans.getClanByMember(playerUUID);
LinkedHashMap<UUID, LinkedList<Chunk>> existingClaims=clans.getClanChunks(playerClan);
if (!existingClaims.containsKey(playerUUID)) {
existingClaims.put(playerUUID, new LinkedList<>());
}
LinkedList<Chunk> playerClaims = existingClaims.get(playerUUID);
int MAX_CLAIMS = 50;
if (playerClaims.size() >= MAX_CLAIMS) {
player.sendMessage(MiniMessage.miniMessage().deserialize("<red>You have reached the maximum amount of claims!"));
} else {
Chunk playerChunk = player.getLocation().getChunk();
if (clans.isChunkClaimed(playerChunk)) {
player.sendMessage(MiniMessage.miniMessage().deserialize("<red>This chunk is already claimed!"));
} else {
playerClaims.add(playerChunk);
player.sendMessage(MiniMessage.miniMessage().deserialize("<green>Claimed chunk!"));
existingClaims.put(playerUUID, playerClaims);
clans.setClanChunks(playerClan, existingClaims);
playerClan.save();
clans.saveAllClans();
}
}
return true;
} else if (label.equalsIgnoreCase("unclaim")) {
Clan playerClan = clans.getClanByMember(playerUUID);
LinkedHashMap<UUID, LinkedList<Chunk>> existingClaims=clans.getClanChunks(playerClan);
if (existingClaims.containsKey(playerUUID)) {
LinkedList<Chunk> playerClaims = existingClaims.get(playerUUID);
Chunk playerChunk = player.getLocation().getChunk();
if (playerClaims.contains(playerChunk)) {
playerClaims.remove(playerChunk);
player.sendMessage(MiniMessage.miniMessage().deserialize("<green>Unclaimed chunk!"));
existingClaims.put(playerUUID, playerClaims);
clans.setClanChunks(playerClan, existingClaims);
playerClan.save();
clans.saveAllClans();
} else {
player.sendMessage(MiniMessage.miniMessage().deserialize("<red>You do not own this chunk!"));
}
return true;
}
}
}
return false;
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
return List.of();
}
}

View file

@ -76,6 +76,27 @@ public class ClanCommand extends SimpleCommand {
player.sendMessage(miniMessage().deserialize("<color:green>Clan created successfully!</color>"));
return true;
}
case "chat" -> {
if (!clans.isInClan(playerUUID)) {
player.sendMessage(miniMessage().deserialize("<color:red>You are not in a clan!</color>"));
return true;
}
Clan clan = clans.getClanByMember(playerUUID);
if (args.length < 2) {
player.sendMessage(miniMessage().deserialize("<color:red>Usage: /clan chat <message></color>"));
return true;
}
String message = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
Component chatMessage = miniMessage().deserialize(
String.format("<color:#10abc7>[Clan] %s:</color> <color:#ff8800>%s</color>", player.getName(), message));
for (UUID mem : clan.getMembers()) {
Player member = Bukkit.getPlayer(mem);
if (member != null && member.isOnline()) {
member.sendMessage(chatMessage);
}
}
return true;
}
// ========== JOIN ==========
case "join" -> {
@ -797,18 +818,18 @@ public class ClanCommand extends SimpleCommand {
// Erste Ebene der Subcommands
if (args.length == 1) {
if (clans.isLeader(playerUUID)) {
return Stream.of("info", "invite", "kick", "transfer", "promote",
return Stream.of("info", "chat", "invite", "kick", "transfer", "promote",
"demote", "disband", "leave", "accept", "deny",
"modify", "list")
.filter(s -> s.startsWith(args[0]))
.collect(Collectors.toList());
} else if (clans.isVice(playerUUID)) {
return Stream.of("info", "invite", "kick", "demote",
return Stream.of("info", "chat", "invite", "kick", "demote",
"leave", "accept", "deny", "list")
.filter(s -> s.startsWith(args[0]))
.collect(Collectors.toList());
} else if (clans.isMember(playerUUID)) {
return Stream.of("info", "leave", "list")
return Stream.of("info", "chat", "leave", "list")
.filter(s -> s.startsWith(args[0]))
.collect(Collectors.toList());
} else {

View file

@ -0,0 +1,115 @@
package me.freezy.plugins.papermc.blazesmp.command;
import me.freezy.plugins.papermc.blazesmp.BlazeSMP;
import me.freezy.plugins.papermc.blazesmp.command.util.SimpleCommand;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
public class ReportCommand extends SimpleCommand {
MiniMessage miniMessage = MiniMessage.miniMessage();
public ReportCommand() {
super("report");
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, @NotNull String[] args) {
if (!(sender instanceof Player reporter)) {
sender.sendMessage(miniMessage.deserialize("<b><i><color:#ff002f>Du darfst das nicht</color></i></b>"));
return true;
}
if (args.length < 2) {
sender.sendMessage(miniMessage.deserialize("<i><color:#ff0048>Benutze bitte:</color> <color:#ff00ee>/report</color> <blue><Spieler></blue> <dark_green><Grund></dark_green></i>"));
return true;
}
OfflinePlayer reportedPlayer = Bukkit.getOfflinePlayer(args[0]);
if (!reportedPlayer.hasPlayedBefore() && !reportedPlayer.isOnline()) {
reporter.sendMessage(miniMessage.deserialize("<color:#ff002f>Der Spieler existiert nicht oder war noch nie online!</color>"));
return true;
}
String reason = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
reporter.sendMessage(miniMessage.deserialize(String.format("<green>Du hast</green> <white><b>%s</b></white> <green>erfolgreich wegen</green> <light_purple><i>%s</i></light_purple> <green>gemeldet</green>", reportedPlayer.getName(), reason)));
sendReportToDiscord(reporter.getName(), reportedPlayer.getName(), reason, reporter.getUniqueId());
return true;
}
private void sendReportToDiscord(String reporter, String reported, String reason, UUID reporterUUID) {
try {
String thumbnailUrl = "http://209.25.141.65:40018/v1/head/getHead/";
String jsonPayload = "{"
+ "\"username\": \"ReportBot\","
+ "\"embeds\": [{"
+ "\"title\": \"Neuer Report\","
+ "\"color\": 16711680," // Red color
+ "\"thumbnail\": {\"url\": \"" + thumbnailUrl+reporterUUID.toString() + "\"}," // Thumbnail
+ "\"fields\": ["
+ "{\"name\": \"Reporter\", \"value\": \"" + reporter + "\", \"inline\": true},"
+ "{\"name\": \"Gemeldeter Spieler\", \"value\": \"" + reported + "\", \"inline\": true},"
+ "{\"name\": \"Grund\", \"value\": \"" + reason + "\", \"inline\": false}"
+ "]"
+ "}]"
+ "}";
HttpURLConnection connection = getHttpURLConnection(jsonPayload);
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_NO_CONTENT || responseCode == HttpURLConnection.HTTP_OK) {
System.out.println("Report sent to Discord successfully!");
} else {
System.out.println("Failed to send report to Discord. Response code: " + responseCode);
}
connection.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
private static @NotNull HttpURLConnection getHttpURLConnection(String jsonPayload) throws IOException {
String webhookUrl = BlazeSMP.getInstance().getConfig().getString("discord-report-webhook");
assert webhookUrl != null;
URL url = new URL(webhookUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
try (OutputStream os = connection.getOutputStream()) {
byte[] input = jsonPayload.getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}
return connection;
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length == 1) {
return Bukkit.getOnlinePlayers().stream()
.map(Player::getName)
.filter(name -> name.startsWith(args[0]))
.collect(Collectors.toList());
}
return List.of();
}
}

View file

@ -7,8 +7,8 @@ import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Objects;
import java.util.logging.Logger;
@SuppressWarnings("ALL")
public abstract class SimpleCommand implements CommandExecutor, TabExecutor {
protected static Logger logger = Logger.getLogger(BlazeSMP.class.getName());
@ -17,43 +17,37 @@ public abstract class SimpleCommand implements CommandExecutor, TabExecutor {
protected final String description;
protected final List<String> alias;
protected final String usage;
protected final String permissionMessage;
protected final String permission;
public SimpleCommand(String command) {
this(command, null, null, null, null, null);
this(command, null, null, null, null);
}
public SimpleCommand(String command, String usage) {
this(command, usage, null, null, null, null);
this(command, usage, null, null, null);
}
public SimpleCommand(String command, List<String> alias) {
this(command, null, null, null, alias);
}
public SimpleCommand(String command, String usage, String description) {
this(command, usage, description, null, null, null);
this(command, usage, description, null, null);
}
public SimpleCommand(String command, String usage, String description, List<String> alias) {
this(command, usage, description, null, null, alias);
this(command, usage, description, null, alias);
}
public SimpleCommand(String command, String usage, String description, String permissionMessage) {
this(command, usage, description, permissionMessage, null, null);
}
public SimpleCommand(String command, String usage, String description, String permissionMessage, String permission) {
this(command, usage, description, permissionMessage, permission, null);
public SimpleCommand(String command, String usage, String description, String permission) {
this(command, usage, description, permission, null);
}
public SimpleCommand(String command, String usage, String description, String permission, List<String> alias) {
this(command, usage, description, null, permission, alias);
}
public SimpleCommand(String command, String usage, String description, String permissionMessage, String permission, List<String> alias) {
this.command = command;
this.description = description;
this.alias = alias;
this.usage = usage;
this.permissionMessage = permissionMessage;
this.permission = permission;
}
@ -62,7 +56,6 @@ public abstract class SimpleCommand implements CommandExecutor, TabExecutor {
if (this.alias != null) cmd.setAliases(this.alias);
if (this.description != null) cmd.setDescription(this.description);
if (this.usage != null) cmd.setUsage(this.usage);
if (this.permissionMessage != null) cmd.setPermissionMessage(this.permissionMessage);
if (this.permission != null) cmd.setPermission(this.permission);
getCommandMap().register("blazesmp", cmd);
cmd.setExecutor(this);
@ -104,11 +97,11 @@ public abstract class SimpleCommand implements CommandExecutor, TabExecutor {
}
@Override
public List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, String[] args) {
public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, String[] args) {
if (exe != null) {
return exe.onTabComplete(sender, this, alias, args);
return Objects.requireNonNull(exe.onTabComplete(sender, this, alias, args));
}
return null;
return List.of();
}
}
}

View file

@ -0,0 +1,201 @@
package me.freezy.plugins.papermc.blazesmp.listener;
import me.freezy.plugins.papermc.blazesmp.BlazeSMP;
import me.freezy.plugins.papermc.blazesmp.module.Clan;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import java.util.*;
public class ChunkInventoryManager implements Listener {
// Speichert pro Spieler den aktuellen Seitenindex
private final PaginatedData paginatedData = new PaginatedData();
public static void openInv(Player player) {
Clan clan = BlazeSMP.getInstance().getClans().getClanByMember(player.getUniqueId());
if (clan == null) {
player.sendMessage(MiniMessage.miniMessage().deserialize("<red>Du bist in keinem Clan.</red>"));
return;
}
new ChunkInventoryManager().chunksInv(player, clan);
}
/**
* Öffnet das Clan-Chunks-Inventar für den Spieler.
* Die Chunks des Clans werden als Kopf-Items (PLAYER_HEAD) angezeigt.
*
* @param player Der Spieler, der das Inventar öffnet.
* @param clan Der Clan, dessen Chunks angezeigt werden sollen.
*/
private void chunksInv(Player player, Clan clan) {
// Erstelle eine Liste der Map-Einträge (Chunk -> Besitzer UUID) aus dem Clan
List<Map.Entry<Chunk, java.util.UUID>> chunkEntries = new ArrayList<>(clan.getChunkOwnerMap().entrySet());
int itemsPerPage = 45; // Plätze 0-44 für Items, untere Reihe für Navigation
int totalPages = (int) Math.ceil(chunkEntries.size() / (double) itemsPerPage);
int currentPage = 0;
paginatedData.setPage(player.getUniqueId(), currentPage);
openChunksMenu(player, chunkEntries, currentPage, totalPages, itemsPerPage, clan);
}
/**
* Baut das Inventar basierend auf der aktuellen Seite auf und öffnet es für den Spieler.
*
* @param player Der Spieler, der das Inventar sieht.
* @param chunkEntries Liste der Clan-Chunks (als Map.Entry von Chunk und Besitzer UUID).
* @param currentPage Aktuelle Seite.
* @param totalPages Gesamtzahl der Seiten.
* @param itemsPerPage Items pro Seite (hier 45).
* @param clan Der Clan, dessen Chunks angezeigt werden.
*/
private void openChunksMenu(Player player, List<Map.Entry<Chunk, java.util.UUID>> chunkEntries,
int currentPage, int totalPages, int itemsPerPage,
Clan clan) {
// Erstelle ein 54-Slot Inventar mit farbigem Titel (Adventure Component)
Component title = MiniMessage.miniMessage().deserialize("<gold>Clan Chunks</gold>");
Inventory inv = Bukkit.createInventory(null, 54, title);
// Berechne Start- und Endindex für die aktuelle Seite
int startIndex = currentPage * itemsPerPage;
int endIndex = Math.min(startIndex + itemsPerPage, chunkEntries.size());
// Füge für jeden Chunk ein Kopf-Item hinzu
for (int i = startIndex; i < endIndex; i++) {
Map.Entry<Chunk, UUID> entry = chunkEntries.get(i);
Chunk chunk = entry.getKey();
UUID ownerUUID = entry.getValue();
OfflinePlayer ownerPlayer = Bukkit.getOfflinePlayer(ownerUUID);
// Erstelle ein Kopf-Item
ItemStack head = new ItemStack(Material.PLAYER_HEAD);
SkullMeta skullMeta = (SkullMeta) head.getItemMeta();
skullMeta.setOwningPlayer(ownerPlayer);
// Titel als Component und dann in reinen Text umwandeln, falls nötig
Component itemName = MiniMessage.miniMessage().deserialize("<aqua>Chunk [" + chunk.getX() + ", " + chunk.getZ() + "]</aqua>");
skullMeta.displayName(itemName);
List<Component> lore = new ArrayList<>();
lore.add(MiniMessage.miniMessage().deserialize("<gray>World: " + chunk.getWorld().getName() + "</gray>"));
lore.add(MiniMessage.miniMessage().deserialize("<gray>Owner: " + ownerPlayer.getName() + "</gray>"));
lore.add(MiniMessage.miniMessage().deserialize("<gray>Index: " + (i + 1) + "</gray>"));
skullMeta.lore(lore);
head.setItemMeta(skullMeta);
// Platziere das Item in den Slots 0 bis 44
inv.setItem(i - startIndex, head);
}
// Navigation: Falls mehrere Seiten vorhanden sind, füge Navigations-Buttons in der untersten Reihe hinzu
if (totalPages > 1) {
// Vorherige Seite (Slot 45)
if (currentPage > 0) {
ItemStack prev = new ItemStack(Material.ARROW);
prev.editMeta(meta -> meta.displayName(MiniMessage.miniMessage().deserialize("<green>Previous Page</green>")));
inv.setItem(45, prev);
}
// Nächste Seite (Slot 53)
if (currentPage < totalPages - 1) {
ItemStack next = new ItemStack(Material.ARROW);
next.editMeta(meta -> meta.displayName(MiniMessage.miniMessage().deserialize("<green>Next Page</green>")));
inv.setItem(53, next);
}
}
// Öffne das Inventar für den Spieler
player.openInventory(inv);
}
// Listener für Inventarklicks mit Paper-Event (Adventure Components)
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
if (!(event.getWhoClicked() instanceof Player player)) return;
// Verwende Paper's getView() um den Titel als Component zu erhalten
Component invTitle = event.getView().title();
Component expectedTitle = MiniMessage.miniMessage().deserialize("<gold>Inv Chunks Bust</gold>");
// Vergleiche die reinen Texte der Components
if (!PlainTextComponentSerializer.plainText().serialize(invTitle)
.equals(PlainTextComponentSerializer.plainText().serialize(expectedTitle))) {
return;
}
event.setCancelled(true); // Standardverhalten verhindern
ItemStack clickedItem = event.getCurrentItem();
if (clickedItem == null || !clickedItem.hasItemMeta()) return;
// Holen des angezeigten Namens als reiner Text
Component itemNameComp = clickedItem.getItemMeta().displayName();
assert itemNameComp != null;
String displayName = PlainTextComponentSerializer.plainText().serialize(itemNameComp);
// Hole den Clan des Spielers (angenommen, der Spieler ist in einem Clan)
me.freezy.plugins.papermc.blazesmp.module.Clan clan = BlazeSMP.getInstance().getClans().getClanByMember(player.getUniqueId());
if (clan == null) return;
// Hole alle Einträge (Chunks) des Clans
List<Map.Entry<Chunk, java.util.UUID>> chunkEntries = new ArrayList<>(clan.getChunkOwnerMap().entrySet());
int itemsPerPage = 45;
int totalPages = (int) Math.ceil(chunkEntries.size() / (double) itemsPerPage);
int currentPage = paginatedData.getPage(player.getUniqueId());
// Navigation behandeln
if (displayName.contains("Previous Page")) {
if (currentPage > 0) {
currentPage--;
paginatedData.setPage(player.getUniqueId(), currentPage);
openChunksMenu(player, chunkEntries, currentPage, totalPages, itemsPerPage, clan);
}
} else if (displayName.contains("Next Page")) {
if (currentPage < totalPages - 1) {
currentPage++;
paginatedData.setPage(player.getUniqueId(), currentPage);
openChunksMenu(player, chunkEntries, currentPage, totalPages, itemsPerPage, clan);
}
} else {
// Reagiere auf Klicks auf einzelne Chunk-Items
player.sendMessage(MiniMessage.miniMessage().deserialize("<yellow>Du hast Chunk-Item: " + displayName + " angeklickt.</yellow>"));
}
}
// Listener, um die gespeicherten Seiteninformationen aufzuräumen
@EventHandler
public void onInventoryClose(InventoryCloseEvent event) {
if (!(event.getPlayer() instanceof Player player)) return;
paginatedData.removePage(player.getUniqueId());
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
paginatedData.removePage(event.getPlayer().getUniqueId());
}
/**
* Hilfsklasse zur Verwaltung der aktuellen Seite pro Spieler.
*/
private static class PaginatedData {
private final Map<UUID, Integer> playerPages = new HashMap<>();
public void setPage(UUID playerUUID, int page) {
playerPages.put(playerUUID, page);
}
public int getPage(UUID playerUUID) {
return playerPages.getOrDefault(playerUUID, 1);
}
public void removePage(UUID playerUUID) {
playerPages.remove(playerUUID);
}
}
}

View file

@ -0,0 +1,37 @@
package me.freezy.plugins.papermc.blazesmp.listener;
import io.papermc.paper.event.player.AsyncChatEvent;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.scoreboard.Team;
public class PlayerChatListener implements Listener {
@EventHandler
public void onChat(AsyncChatEvent event) {
Player player = event.getPlayer();
Team team = player.getScoreboard().getEntryTeam(player.getName());
Component prefix = Component.empty();
Component suffix = Component.empty();
if (team != null) {
team.prefix();
prefix = team.prefix();
team.suffix();
suffix = team.suffix();
}
Component messageComponent = event.message();
Component chatComponent = Component.empty()
.append(prefix)
.append(Component.text(player.getName()))
.append(suffix)
.append(Component.text(": "))
.append(messageComponent);
event.renderer((source, sourceDisplayName, msg, viewer) -> chatComponent);
}
}

View file

@ -0,0 +1,123 @@
package me.freezy.plugins.papermc.blazesmp.listener;
import me.freezy.plugins.papermc.blazesmp.BlazeSMP;
import me.freezy.plugins.papermc.blazesmp.module.Clan;
import me.freezy.plugins.papermc.blazesmp.module.manager.Clans;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerMoveEvent;
public class PlayerClaimListener implements Listener {
@EventHandler
public void onBlockBreak(BlockBreakEvent event) {
Location location = event.getBlock().getLocation();
Chunk chunk = location.getChunk();
Clans clans = BlazeSMP.getInstance().getClans();
Clan clan = clans.getClanByChunk(chunk);
if (clan != null) {
if (clans.isInClan(event.getPlayer().getUniqueId(), clan)) {
return;
}
event.setCancelled(true);
}
}
@EventHandler
public void onBlockPlace(BlockPlaceEvent event) {
Location location = event.getBlock().getLocation();
Chunk chunk = location.getChunk();
Clans clans = BlazeSMP.getInstance().getClans();
Clan clan = clans.getClanByChunk(chunk);
if (clan != null) {
if (clans.isInClan(event.getPlayer().getUniqueId(), clan)) {
return;
}
event.setCancelled(true);
}
}
@EventHandler
public void onPlayerInteractEvent(PlayerInteractEvent event) {
Location location = event.getPlayer().getLocation();
Chunk chunk = location.getChunk();
Clans clans = BlazeSMP.getInstance().getClans();
Clan clan = clans.getClanByChunk(chunk);
if (clan != null) {
if (clans.isInClan(event.getPlayer().getUniqueId(), clan)) {
return;
}
event.setCancelled(true);
}
}
@EventHandler
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
Location location = event.getPlayer().getLocation();
Chunk chunk = location.getChunk();
Clans clans = BlazeSMP.getInstance().getClans();
Clan clan = clans.getClanByChunk(chunk);
if (clan != null) {
if (clans.isInClan(event.getPlayer().getUniqueId(), clan)) {
return;
}
event.setCancelled(true);
}
}
@EventHandler
public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event) {
Location location = event.getPlayer().getLocation();
Chunk chunk = location.getChunk();
Clans clans = BlazeSMP.getInstance().getClans();
Clan clan = clans.getClanByChunk(chunk);
if (clan != null) {
if (clans.isInClan(event.getPlayer().getUniqueId(), clan)) {
return;
}
event.setCancelled(true);
}
}
@EventHandler
public void onEnterClanClaim(PlayerMoveEvent event) {
Chunk fromChunk = event.getFrom().getChunk();
Chunk toChunk = event.getTo().getChunk();
if (fromChunk.equals(toChunk)) {
return;
}
Player player = event.getPlayer();
Clans clans = BlazeSMP.getInstance().getClans();
Clan oldClan = clans.getClanByChunk(fromChunk);
Clan newClan = clans.getClanByChunk(toChunk);
if (oldClan != null && (!oldClan.equals(newClan))) {
player.sendActionBar(
MiniMessage.miniMessage().deserialize(
"<red>You left the claim of <white>" + oldClan.getName() + "</white>!</red>"
)
);
}
if (newClan != null && (!newClan.equals(oldClan))) {
player.sendActionBar(
MiniMessage.miniMessage().deserialize(
"<red>Territory of <white>" + newClan.getName() + "</white> - <white>" +
Bukkit.getOfflinePlayer(newClan.getChunkOwnerMap().get(toChunk)).getName() +
"!</white></red>"
)
);
}
}
}

View file

@ -0,0 +1,227 @@
package me.freezy.plugins.papermc.blazesmp.listener;
import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
public class PlayerCommandBlockerListener implements Listener {
private final Set<String> blockedCommands = new LinkedHashSet<>(Arrays.asList(
"/bukkit:?",
"/?",
"/bukkit:about",
"/about",
"/bukkit:help",
"/help",
"/bukkit:pl",
"/pl",
"/bukkit:plugins",
"/plugins",
"/bukkit:reload",
"/reload",
"/bukkit:rl",
"/rl",
"/bukkit:timings",
"/timings",
"/bukkit:ver",
"/ver",
"/bukkit:version",
"/version",
"/paper:callback",
"/callback",
"/paper:mspt",
"/mspt",
"/paper:paper",
"/paper",
"/paper:spark",
"/spark",
"/minecraft:advancement",
"/advancement",
"/minecraft:attribute",
"/attribute",
"/minecraft:ban",
"/ban",
"/minecraft:ban-ip",
"/ban-ip",
"/minecraft:banlist",
"/banlist",
"/minecraft:bossbar",
"/bossbar",
"/minecraft:clear",
"/clear",
"/minecraft:clone",
"/clone",
"/minecraft:damage",
"/damage",
"/minecraft:data",
"/data",
"/minecraft:datapack",
"/datapack",
"/minecraft:difficulty",
"/difficulty",
"/minecraft:effect",
"/effect",
"/minecraft:enchant",
"/enchant",
"/minecraft:execute",
"/execute",
"/minecraft:experience",
"/experience",
"/minecraft:fill",
"/fill",
"/minecraft:fillbiome",
"/fillbiome",
"/minecraft:foreload",
"/foreload",
"/minecraft:gamerule",
"/gamerule",
"/minecraft:give",
"/give",
"/minecraft:help",
"/help",
"/minecraft:item",
"/item",
"/minecraft:jfr",
"/jfr",
"/minecraft:kick",
"/kick",
"/minecraft:kill",
"/kill",
"/minecraft:list",
"/list",
"/minecraft:locate",
"/locate",
"/minecraft:loot",
"/loot",
"/minecraft:me",
"/me",
"/minecraft:op",
"/op",
"/minecraft:pardon",
"/pardon",
"/minecraft:pardon-ip",
"/pardon-ip",
"/minecraft:particle",
"/particle",
"/minecraft:perf",
"/perf",
"/minecraft:place",
"/place",
"/minecraft:playsound",
"/playsound",
"/minecraft:random",
"/random",
"/minecraft:recipe",
"/recipe",
"/minecraft:reload",
"/reload",
"/minecraft:ride",
"/ride",
"/minecraft:rotate",
"/rotate",
"/minecraft:save-all",
"/save-all",
"/minecraft:save-off",
"/save-off",
"/minecraft:save-on",
"/save-on",
"/minecraft:say",
"/say",
"/minecraft:schedule",
"/schedule",
"/minecraft:scoreboard",
"/scoreboard",
"/minecraft:seed",
"/seed",
"/minecraft:setblock",
"/setblock",
"/minecraft:setidletimeout",
"/setidletimeout",
"/minecraft:setworldspawn",
"/setworldspawn",
"/minecraft:spawnpoint",
"/spawnpoint",
"/minecraft:spectate",
"/spectate",
"/minecraft:tag",
"/tag",
"/minecraft:team",
"/team",
"/minecraft:teammsg",
"/teammsg",
"/minecraft:teleport",
"/teleport",
"/minecraft:tellraw",
"/tellraw",
"/minecraft:tick",
"/tick",
"/minecraft:time",
"/time",
"/minecraft:title",
"/title",
"/minecraft:tm",
"/tm",
"/minecraft:tp",
"/tp",
"/minecraft:transfer",
"/transfer",
"/minecraft:trigger",
"/trigger",
"/minecraft:weather",
"/weather",
"/minecraft:whitelist",
"/whitelist",
"/minecraft:worldborder",
"/worldborder",
"/minecraft:xp",
"/xp",
"/icanhasbukkit"
));
private boolean isBlocked(String input) {
String normalized = input.toLowerCase().trim();
for (String blocked : blockedCommands) {
blocked = blocked.toLowerCase().trim();
if (normalized.equals(blocked) || normalized.startsWith(blocked + " ")) {
return true;
}
}
return false;
}
@EventHandler
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
Player player = event.getPlayer();
if (player.isOp()) return; // OPs werden nicht blockiert
String message = event.getMessage();
if (isBlocked(message)) {
event.setCancelled(true);
// Zeige den blockierten Befehl als Hinweis (hier der erste Teil der Nachricht)
String blockedPart = message.split(" ")[0];
player.sendMessage(MiniMessage.miniMessage().deserialize(
"<red>Unknown or incomplete command, see below for error\n<u>" + blockedPart + "</u><i> <--[HERE]</i>"
));
}
}
@EventHandler
public void onTabComplete(AsyncTabCompleteEvent event) {
Player player = (Player) event.getSender();
if (player.isOp()) return; // OPs erhalten weiterhin Tab-Vorschläge
String buffer = event.getBuffer();
if (isBlocked(buffer)) {
// Alle Tab-Vorschläge entfernen und das Event abbrechen,
// wenn der eingegebene Befehl blockiert ist.
event.getCompletions().clear();
event.setCancelled(true);
}
}
}

View file

@ -1,15 +1,18 @@
package me.freezy.plugins.papermc.blazesmp.listener;
import me.freezy.plugins.papermc.blazesmp.manager.PlayerManager;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
public class JoinListener implements Listener {
public class PlayerJoinListener implements Listener {
@EventHandler
public void onJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
new PlayerManager().setPlayerTeam(player);
event.joinMessage(MiniMessage.miniMessage().deserialize("<gray>[<green>+</green>]</gray> <reset>").append(player.teamDisplayName()));
}
}

View file

@ -5,6 +5,7 @@ import me.freezy.plugins.papermc.blazesmp.module.Clan;
import me.freezy.plugins.papermc.blazesmp.module.manager.Clans;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scoreboard.Scoreboard;
import org.bukkit.scoreboard.Team;
@ -63,14 +64,28 @@ public class PlayerManager {
"<color:dark_gray>[</color><gradient:#747e80:#828d8f><b>Player</b></gradient><color:dark_gray>]</color> "
)
);
if (clans.isInClan(playerUUID)) {
if (clans.isLeader(playerUUID)) {
prefix = prefix.append(MiniMessage.miniMessage().deserialize("<color:red>*</color>"));
} else if (clans.isVice(playerUUID)) {
prefix = prefix.append(MiniMessage.miniMessage().deserialize("<color:light_purple>*</color>"));
}
}
team.prefix(prefix);
Clan clan = clans.getClanByMember(playerUUID);
Component suffix;
if (clan != null) {
team.suffix(Component.text(" ").append(clan.getTag()));
suffix = (Component.text(" ").append(clan.getTag()));
} else {
team.suffix(Component.empty());
suffix = (Component.empty());
}
team.suffix();
team.addEntity(player);
team.addEntry(player.getName());
Component displayName = prefix.append(Component.text(player.getName())).append(suffix);
player.playerListName(displayName);
player.displayName(displayName);
}
private String generateRandomString(int length) {

View file

@ -32,7 +32,6 @@ public class Clan {
@Setter private UUID leaderUUID;
@Setter private UUID viceUUID;
private final LinkedList<UUID> members;
private final LinkedList<Chunk> chunks;
private final LinkedHashMap<Chunk, UUID> chunkOwnerMap;
private int chunkAmount;
@ -43,22 +42,20 @@ public class Clan {
this.leaderUUID = leaderUUID;
this.viceUUID = null;
this.members = new LinkedList<>();
this.chunks = new LinkedList<>();
this.chunkOwnerMap = new LinkedHashMap<>();
this.chunkAmount = 0;
}
public Clan(UUID clanUUID, String name, Component tag, UUID leaderUUID, UUID viceUUID,
LinkedList<UUID> members, LinkedList<Chunk> chunks, LinkedHashMap<Chunk, UUID> chunkOwnerMap) {
LinkedList<UUID> members, LinkedHashMap<Chunk, UUID> chunkOwnerMap) {
this.uuid = clanUUID;
this.name = name;
this.tag = tag;
this.leaderUUID = leaderUUID;
this.viceUUID = viceUUID;
this.members = members;
this.chunks = chunks;
this.chunkOwnerMap = chunkOwnerMap;
this.chunkAmount = chunks.size();
this.chunkAmount = chunkOwnerMap.size();
}
/**
@ -94,7 +91,6 @@ public class Clan {
}
// Process chunks with world information
LinkedList<Chunk> chunkList = new LinkedList<>();
LinkedHashMap<Chunk, UUID> chunkOwnerMap = new LinkedHashMap<>();
if (jsonClan.chunks != null && jsonClan.chunks.locations != null) {
for (LocationJson loc : jsonClan.chunks.locations) {
@ -106,14 +102,13 @@ public class Clan {
int x = Integer.parseInt(loc.x);
int z = Integer.parseInt(loc.z);
Chunk chunk = world.getChunkAt(x, z);
chunkList.add(chunk);
UUID ownerUUID = (loc.owner == null || loc.owner.isEmpty()) ? null : UUID.fromString(loc.owner);
chunkOwnerMap.put(chunk, ownerUUID);
}
}
Clan clan = new Clan(uuid, jsonClan.name, tagComponent, leader, vice, memberUUIDs, chunkList, chunkOwnerMap);
clan.chunkAmount = (jsonClan.chunks != null) ? jsonClan.chunks.amount : chunkList.size();
Clan clan = new Clan(uuid, jsonClan.name, tagComponent, leader, vice, memberUUIDs, chunkOwnerMap);
clan.chunkAmount = (jsonClan.chunks != null) ? jsonClan.chunks.amount : chunkOwnerMap.size();
return clan;
} catch (IOException e) {
LOGGER.severe("Error loading clan: " + e.getMessage());
@ -136,8 +131,6 @@ public class Clan {
this.viceUUID = loaded.viceUUID;
this.members.clear();
this.members.addAll(loaded.members);
this.chunks.clear();
this.chunks.addAll(loaded.chunks);
this.chunkOwnerMap.clear();
this.chunkOwnerMap.putAll(loaded.chunkOwnerMap);
this.chunkAmount = loaded.chunkAmount;
@ -158,7 +151,7 @@ public class Clan {
jsonClan.chunks = new ChunksJson();
jsonClan.chunks.amount = this.chunkAmount;
jsonClan.chunks.locations = new LinkedList<>();
for (Chunk chunk : this.chunks) {
for (Chunk chunk : this.chunkOwnerMap.keySet()) {
LocationJson loc = new LocationJson();
// Assuming the owner mapping may be null
UUID owner = this.chunkOwnerMap.getOrDefault(chunk, null);

View file

@ -2,12 +2,16 @@ package me.freezy.plugins.papermc.blazesmp.module.manager;
import lombok.Getter;
import me.freezy.plugins.papermc.blazesmp.module.Clan;
import org.bukkit.Chunk;
import java.io.File;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Logger;
@SuppressWarnings("unused")
@Getter
public class Clans {
private static final Logger LOGGER = Logger.getLogger("ClanManager");
@ -31,7 +35,11 @@ public class Clans {
File dir = new File(CLAN_STORAGE_PATH);
if (!dir.exists()) {
LOGGER.info("Clan storage directory does not exist. Creating directory...");
dir.mkdirs();
if (!dir.mkdirs()) {
LOGGER.warning("Failed to create clan storage directory.");
} else {
LOGGER.info("Created clan storage directory.");
}
return;
}
File[] files = dir.listFiles((file, name) -> name.endsWith(".json"));
@ -123,6 +131,33 @@ public class Clans {
}
}
public LinkedHashMap<UUID, LinkedList<Chunk>> getClanChunks(Clan clan) {
LinkedHashMap<UUID, LinkedList<Chunk>> clanChunks = new LinkedHashMap<>();
for (Map.Entry<Chunk, UUID> entry : clan.getChunkOwnerMap().entrySet()) {
UUID ownerUUID = entry.getValue();
Chunk chunk = entry.getKey();
if (!clanChunks.containsKey(ownerUUID)) {
clanChunks.put(ownerUUID, new LinkedList<>());
}
clanChunks.get(ownerUUID).add(chunk);
}
return clanChunks;
}
public LinkedList<Chunk> getPlayerChunks(UUID playerUUID) {
LinkedList<Chunk> playerChunks = new LinkedList<>();
for (Clan clan : clans) {
if (clan.getChunkOwnerMap().containsValue(playerUUID)) {
for (Map.Entry<Chunk, UUID> entry : clan.getChunkOwnerMap().entrySet()) {
if (entry.getValue().equals(playerUUID)) {
playerChunks.add(entry.getKey());
}
}
}
}
return playerChunks;
}
public boolean isLeader(UUID playerUUID) {
for (Clan clan : clans) {
if (clan.getLeaderUUID().equals(playerUUID)) {
@ -159,6 +194,10 @@ public class Clans {
return false;
}
public boolean isInClan(UUID playerUUID,Clan clan) {
return clan.getMembers().contains(playerUUID) || clan.getLeaderUUID().equals(playerUUID) || (clan.getViceUUID() != null && clan.getViceUUID().equals(playerUUID));
}
public Clan getClanByMember(UUID playerUUID) {
for (Clan clan : clans) {
if (clan.getMembers().contains(playerUUID) || clan.getLeaderUUID().equals(playerUUID) || (clan.getViceUUID() != null && clan.getViceUUID().equals(playerUUID))) {
@ -167,4 +206,32 @@ public class Clans {
}
return null;
}
public void setClanChunks(Clan playerClan, LinkedHashMap<UUID, LinkedList<Chunk>> existingClaims) {
for (Map.Entry<UUID, LinkedList<Chunk>> entry : existingClaims.entrySet()) {
UUID ownerUUID = entry.getKey();
LinkedList<Chunk> chunks = entry.getValue();
for (Chunk chunk : chunks) {
playerClan.getChunkOwnerMap().put(chunk, ownerUUID);
}
}
playerClan.save();
}
public Clan getClanByChunk(Chunk chunk) {
for (Clan clan : clans) {
if (clan.getChunkOwnerMap().containsKey(chunk)) {
return clan;
}
}
return null;
}
public boolean isChunkClaimed(Chunk chunk) {
for (Clan clan : clans) {
if (clan.getChunkOwnerMap().containsKey(chunk)) {
return true;
}
}
return false;
}
}

View file

@ -1,2 +1,3 @@
op-prefix: '<color:dark_gray>[</color><gradient:#ffa600:#ffb700><b>Team</b></gradient><color:dark_gray>]</color> '
player-prefix: '<color:dark_gray>[</color><gradient:#747e80:#828d8f><b>Player</b></gradient><color:dark_gray>]</color> '
discord-report-webhook: 'https://discord.com/api/webhooks/1234567890/abcdefghijklmnopqrstuvwxyz'