commit 8e18e96acf5fb58a12772e2cf56681f8586a4cb0 Author: Xelara Networks Date: Mon Jun 8 19:17:10 2026 -0400 first commit diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..05630b6 --- /dev/null +++ b/pom.xml @@ -0,0 +1,104 @@ + + 4.0.0 + + com.bitnix + DirtGuilds + 1.0.0 + jar + DirtGuilds + + + 21 + UTF-8 + + + + + papermc + https://repo.papermc.io/repository/maven-public/ + + + placeholderapi + https://repo.extendedclip.com/content/repositories/placeholderapi/ + + + jitpack.io + https://jitpack.io + + + + + + io.papermc.paper + paper-api + 1.21.8-R0.1-SNAPSHOT + provided + + + + me.clip + placeholderapi + 2.11.6 + provided + + + + com.github.MilkBowl + VaultAPI + 1.7.1 + provided + + + + com.zaxxer + HikariCP + 5.1.0 + + + + org.xerial + sqlite-jdbc + 3.46.0.0 + + + + com.mysql + mysql-connector-j + 9.0.0 + + + + + DirtGuilds + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + 21 + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.5.3 + + + package + + shade + + + false + false + + + + + + + diff --git a/src/main/java/com/bitnix/dirtguilds/DirtGuildsPlugin.java b/src/main/java/com/bitnix/dirtguilds/DirtGuildsPlugin.java new file mode 100644 index 0000000..aa86a44 --- /dev/null +++ b/src/main/java/com/bitnix/dirtguilds/DirtGuildsPlugin.java @@ -0,0 +1,83 @@ +package com.bitnix.dirtguilds; + +import com.bitnix.dirtguilds.command.DirtGuildsCommand; +import com.bitnix.dirtguilds.data.DatabaseManager; +import com.bitnix.dirtguilds.guild.GuildManager; +import com.bitnix.dirtguilds.hook.EconomyHook; +import com.bitnix.dirtguilds.listener.ChatListener; +import com.bitnix.dirtguilds.listener.GuildFriendlyFireListener; +import com.bitnix.dirtguilds.listener.GuiListener; +import com.bitnix.dirtguilds.util.MessageUtil; +import org.bukkit.plugin.java.JavaPlugin; + +public class DirtGuildsPlugin extends JavaPlugin { + + private DatabaseManager databaseManager; + private GuildManager guildManager; + private MessageUtil messageUtil; + private EconomyHook economyHook; + + @Override + public void onEnable() { + saveDefaultConfig(); + + this.messageUtil = new MessageUtil(this); + + this.economyHook = new EconomyHook(this); + boolean economyEnabled = this.economyHook.setup(); + if (economyEnabled) { + getLogger().info("Vault economy hooked successfully."); + } else { + getLogger().warning("Vault economy not found. Guild bank will run in internal-only mode."); + } + + this.databaseManager = new DatabaseManager(this); + this.databaseManager.initialize(); + + this.guildManager = new GuildManager(this, this.databaseManager); + this.guildManager.loadAll(); + + DirtGuildsCommand command = new DirtGuildsCommand(this); + if (getCommand("dirtguilds") != null) { + getCommand("dirtguilds").setExecutor(command); + getCommand("dirtguilds").setTabCompleter(command); + } + + getServer().getPluginManager().registerEvents(new GuiListener(this), this); + getServer().getPluginManager().registerEvents(new ChatListener(this), this); + getServer().getPluginManager().registerEvents(new GuildFriendlyFireListener(this), this); + + getLogger().info("DirtGuilds enabled."); + } + + @Override + public void onDisable() { + getServer().getScheduler().cancelTasks(this); + + if (guildManager != null) { + guildManager.shutdown(); + } + + if (databaseManager != null) { + databaseManager.close(); + } + + getLogger().info("DirtGuilds disabled."); + } + + public DatabaseManager getDatabaseManager() { + return databaseManager; + } + + public GuildManager getGuildManager() { + return guildManager; + } + + public MessageUtil getMessageUtil() { + return messageUtil; + } + + public EconomyHook getEconomyHook() { + return economyHook; + } +} diff --git a/src/main/java/com/bitnix/dirtguilds/command/DirtGuildsCommand.java b/src/main/java/com/bitnix/dirtguilds/command/DirtGuildsCommand.java new file mode 100644 index 0000000..9c1d112 --- /dev/null +++ b/src/main/java/com/bitnix/dirtguilds/command/DirtGuildsCommand.java @@ -0,0 +1,667 @@ +package com.bitnix.dirtguilds.command; + +import com.bitnix.dirtguilds.DirtGuildsPlugin; +import com.bitnix.dirtguilds.guild.Guild; +import com.bitnix.dirtguilds.guild.GuildInvite; +import com.bitnix.dirtguilds.gui.GuildLevelsMenu; +import com.bitnix.dirtguilds.gui.GuildMainMenu; +import com.bitnix.dirtguilds.gui.GuildMembersMenu; +import com.bitnix.dirtguilds.gui.GuildVaultMenu; +import com.bitnix.dirtguilds.util.MessageUtil; +import net.milkbowl.vault.economy.EconomyResponse; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.command.TabExecutor; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.UUID; + +public class DirtGuildsCommand implements TabExecutor, TabCompleter { + + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#,##0.00"); + + private final DirtGuildsPlugin plugin; + + public DirtGuildsCommand(DirtGuildsPlugin plugin) { + this.plugin = plugin; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player player)) { + plugin.getMessageUtil().send(sender, "messages.players-only"); + return true; + } + + if (!player.hasPermission("dirtguilds.use")) { + plugin.getMessageUtil().send(player, "messages.no-permission"); + return true; + } + + if (args.length == 0) { + new GuildMainMenu(plugin).open(player); + return true; + } + + String sub = args[0].toLowerCase(Locale.ROOT); + Guild guild = plugin.getGuildManager().getGuildByPlayer(player.getUniqueId()); + + switch (sub) { + case "create" -> { + if (guild != null) { + plugin.getMessageUtil().send(player, "messages.already-in-guild"); + return true; + } + + if (args.length < 2) { + plugin.getMessageUtil().sendRaw(player, "Usage: /" + label + " create "); + return true; + } + + String name = args[1]; + int min = plugin.getConfig().getInt("settings.min-name-length", 3); + int max = plugin.getConfig().getInt("settings.max-name-length", 16); + + if (name.length() < min || name.length() > max || !name.matches("[A-Za-z0-9_]+")) { + plugin.getMessageUtil().send(player, "messages.invalid-name"); + return true; + } + + if (plugin.getGuildManager().guildNameExists(name)) { + plugin.getMessageUtil().send(player, "messages.name-taken"); + return true; + } + + Guild created = plugin.getGuildManager().createGuild(player.getUniqueId(), name); + plugin.getMessageUtil().send(player, "messages.guild-created", "%guild%", created.getName()); + return true; + } + + case "invite" -> { + if (guild == null) { + plugin.getMessageUtil().send(player, "messages.not-in-guild"); + return true; + } + + if (!guild.canManage(player.getUniqueId()) && !guild.getOwner().equals(player.getUniqueId())) { + plugin.getMessageUtil().send(player, "messages.no-permission"); + return true; + } + + if (args.length < 2) { + plugin.getMessageUtil().sendRaw(player, "Usage: /" + label + " invite "); + return true; + } + + Player target = Bukkit.getPlayerExact(args[1]); + if (target == null) { + plugin.getMessageUtil().send(player, "messages.player-not-found"); + return true; + } + + if (plugin.getGuildManager().isInGuild(target.getUniqueId())) { + plugin.getMessageUtil().send(player, "messages.target-already-in-guild"); + return true; + } + + plugin.getGuildManager().createInvite(target.getUniqueId(), player.getUniqueId(), guild); + plugin.getMessageUtil().send(player, "messages.invite-sent", "%player%", target.getName()); + plugin.getMessageUtil().send(target, "messages.invite-received", "%guild%", guild.getName()); + return true; + } + + case "accept", "join" -> { + if (guild != null) { + plugin.getMessageUtil().send(player, "messages.already-in-guild"); + return true; + } + + if (args.length < 2) { + plugin.getMessageUtil().sendRaw(player, "Usage: /" + label + " accept "); + return true; + } + + Guild targetGuild = plugin.getGuildManager().getGuildByName(args[1]); + if (targetGuild == null) { + plugin.getMessageUtil().send(player, "messages.guild-not-found"); + return true; + } + + GuildInvite invite = plugin.getGuildManager().getInvite(player.getUniqueId(), targetGuild.getId()); + if (invite == null) { + plugin.getMessageUtil().send(player, "messages.no-invite"); + return true; + } + + if (invite.isExpired()) { + plugin.getGuildManager().removeInvite(player.getUniqueId(), targetGuild.getId()); + plugin.getMessageUtil().send(player, "messages.invite-expired"); + return true; + } + + plugin.getGuildManager().addMember(targetGuild, player.getUniqueId()); + plugin.getGuildManager().removeInvite(player.getUniqueId(), targetGuild.getId()); + + plugin.getMessageUtil().send(player, "messages.joined-guild", "%guild%", targetGuild.getName()); + + for (Player online : Bukkit.getOnlinePlayers()) { + Guild onlineGuild = plugin.getGuildManager().getGuildByPlayer(online.getUniqueId()); + if (onlineGuild != null && onlineGuild.getId().equals(targetGuild.getId())) { + plugin.getMessageUtil().send(online, "messages.member-joined", "%player%", player.getName()); + } + } + return true; + } + + case "leave" -> { + if (guild == null) { + plugin.getMessageUtil().send(player, "messages.not-in-guild"); + return true; + } + + if (guild.getOwner().equals(player.getUniqueId())) { + plugin.getGuildManager().deleteGuild(guild); + plugin.getMessageUtil().send(player, "messages.guild-deleted", "%guild%", guild.getName()); + return true; + } + + plugin.getGuildManager().removeMember(guild, player.getUniqueId()); + plugin.getMessageUtil().send(player, "messages.left-guild"); + + for (Player online : Bukkit.getOnlinePlayers()) { + Guild onlineGuild = plugin.getGuildManager().getGuildByPlayer(online.getUniqueId()); + if (onlineGuild != null && onlineGuild.getId().equals(guild.getId())) { + plugin.getMessageUtil().send(online, "messages.member-left", "%player%", player.getName()); + } + } + return true; + } + + case "rename" -> { + if (guild == null) { + plugin.getMessageUtil().send(player, "messages.not-in-guild"); + return true; + } + + if (!guild.getOwner().equals(player.getUniqueId())) { + plugin.getMessageUtil().send(player, "messages.must-be-owner"); + return true; + } + + if (args.length < 2) { + plugin.getMessageUtil().sendRaw(player, "Usage: /" + label + " rename "); + return true; + } + + String newName = args[1]; + int min = plugin.getConfig().getInt("settings.min-name-length", 3); + int max = plugin.getConfig().getInt("settings.max-name-length", 16); + + if (newName.length() < min || newName.length() > max || !newName.matches("[A-Za-z0-9_]+")) { + plugin.getMessageUtil().send(player, "messages.invalid-name"); + return true; + } + + if (!guild.getName().equalsIgnoreCase(newName) && plugin.getGuildManager().guildNameExists(newName)) { + plugin.getMessageUtil().send(player, "messages.name-taken"); + return true; + } + + plugin.getGuildManager().renameGuild(guild, newName); + plugin.getMessageUtil().send(player, "messages.guild-renamed", "%guild%", newName); + return true; + } + + case "prefix" -> { + if (guild == null) { + plugin.getMessageUtil().send(player, "messages.not-in-guild"); + return true; + } + + if (!guild.canManage(player.getUniqueId()) && !guild.getOwner().equals(player.getUniqueId())) { + plugin.getMessageUtil().send(player, "messages.no-permission"); + return true; + } + + if (args.length < 2) { + plugin.getMessageUtil().sendRaw(player, "Usage: /" + label + " prefix "); + return true; + } + + String prefix = args[1]; + plugin.getGuildManager().setPrefix(guild, prefix); + plugin.getMessageUtil().send(player, "messages.prefix-updated"); + return true; + } + + case "ff", "friendlyfire", "pvp" -> { + if (guild == null) { + plugin.getMessageUtil().send(player, "messages.not-in-guild"); + return true; + } + + if (!guild.canManage(player.getUniqueId()) && !guild.getOwner().equals(player.getUniqueId())) { + plugin.getMessageUtil().send(player, "messages.no-permission"); + return true; + } + + boolean enabled = !guild.isFriendlyFire(); + plugin.getGuildManager().setFriendlyFire(guild, enabled); + + if (enabled) { + plugin.getMessageUtil().send(player, "messages.friendly-fire-enabled"); + } else { + plugin.getMessageUtil().send(player, "messages.friendly-fire-disabled"); + } + return true; + } + + case "chat" -> { + if (guild == null) { + plugin.getMessageUtil().send(player, "messages.not-in-guild"); + return true; + } + + boolean enabled = !plugin.getGuildManager().isGuildChatEnabled(player.getUniqueId()); + plugin.getGuildManager().setGuildChatEnabled(player.getUniqueId(), enabled); + + if (enabled) { + plugin.getMessageUtil().send(player, "messages.guild-chat-enabled"); + } else { + plugin.getMessageUtil().send(player, "messages.guild-chat-disabled"); + } + return true; + } + + case "bank" -> { + if (guild == null) { + plugin.getMessageUtil().send(player, "messages.not-in-guild"); + return true; + } + + if (args.length == 1) { + player.sendMessage(MessageUtil.mm(plugin.getMessageUtil().format("messages.prefix") + "Use /guild bank deposit or /guild bank withdraw ")); + return true; + } + + if (args.length < 3) { + plugin.getMessageUtil().sendRaw(player, "Usage: /" + label + " bank "); + return true; + } + + String action = args[1].toLowerCase(Locale.ROOT); + double amount; + + try { + amount = Double.parseDouble(args[2]); + } catch (NumberFormatException exception) { + plugin.getMessageUtil().send(player, "messages.bank-invalid-amount"); + return true; + } + + if (amount <= 0) { + plugin.getMessageUtil().send(player, "messages.bank-invalid-amount"); + return true; + } + + boolean useVault = plugin.getConfig().getBoolean("settings.bank.use-vault", true); + + if (action.equals("deposit")) { + if (useVault) { + if (!plugin.getEconomyHook().isAvailable()) { + plugin.getMessageUtil().send(player, "messages.bank-vault-unavailable"); + return true; + } + + if (plugin.getEconomyHook().getEconomy().getBalance(player) < amount) { + plugin.getMessageUtil().send(player, "messages.bank-player-insufficient-funds"); + return true; + } + + EconomyResponse response = plugin.getEconomyHook().getEconomy().withdrawPlayer(player, amount); + if (!response.transactionSuccess()) { + plugin.getMessageUtil().send(player, "messages.bank-player-insufficient-funds"); + return true; + } + } + + plugin.getGuildManager().deposit(guild, amount); + plugin.getMessageUtil().send(player, "messages.bank-deposit", "%amount%", DECIMAL_FORMAT.format(amount)); + return true; + } + + if (action.equals("withdraw")) { + if (!guild.canManage(player.getUniqueId()) && !guild.getOwner().equals(player.getUniqueId())) { + plugin.getMessageUtil().send(player, "messages.no-permission"); + return true; + } + + if (!plugin.getGuildManager().withdraw(guild, amount)) { + plugin.getMessageUtil().send(player, "messages.bank-insufficient-funds"); + return true; + } + + if (useVault) { + if (!plugin.getEconomyHook().isAvailable()) { + plugin.getGuildManager().deposit(guild, amount); + plugin.getMessageUtil().send(player, "messages.bank-vault-unavailable"); + return true; + } + + EconomyResponse response = plugin.getEconomyHook().getEconomy().depositPlayer(player, amount); + if (!response.transactionSuccess()) { + plugin.getGuildManager().deposit(guild, amount); + plugin.getMessageUtil().send(player, "messages.bank-vault-unavailable"); + return true; + } + } + + plugin.getMessageUtil().send(player, "messages.bank-withdraw", "%amount%", DECIMAL_FORMAT.format(amount)); + return true; + } + + plugin.getMessageUtil().sendRaw(player, "Usage: /" + label + " bank "); + return true; + } + + case "vault" -> { + if (guild == null) { + plugin.getMessageUtil().send(player, "messages.not-in-guild"); + return true; + } + + new GuildVaultMenu(plugin).open(player, guild); + return true; + } + + case "levels", "level" -> { + if (guild == null) { + plugin.getMessageUtil().send(player, "messages.not-in-guild"); + return true; + } + + new GuildLevelsMenu(plugin).open(player, guild); + return true; + } + + case "members" -> { + if (guild == null) { + plugin.getMessageUtil().send(player, "messages.not-in-guild"); + return true; + } + + new GuildMembersMenu(plugin).open(player, guild); + return true; + } + + case "promote" -> { + if (guild == null) { + plugin.getMessageUtil().send(player, "messages.not-in-guild"); + return true; + } + + if (!guild.canManage(player.getUniqueId()) && !guild.getOwner().equals(player.getUniqueId())) { + plugin.getMessageUtil().send(player, "messages.no-permission"); + return true; + } + + if (args.length < 2) { + plugin.getMessageUtil().sendRaw(player, "Usage: /" + label + " promote "); + return true; + } + + OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]); + UUID targetUuid = target.getUniqueId(); + + if (!guild.isMember(targetUuid) || targetUuid.equals(guild.getOwner())) { + plugin.getMessageUtil().send(player, "messages.player-not-found"); + return true; + } + + String current = guild.getRank(targetUuid).toUpperCase(); + String next = switch (current) { + case "MEMBER" -> "MOD"; + case "MOD" -> "ADMIN"; + default -> "ADMIN"; + }; + + plugin.getGuildManager().setMemberRank(guild, targetUuid, next); + String name = target.getName() == null ? targetUuid.toString() : target.getName(); + plugin.getMessageUtil().send(player, "messages.rank-updated", "%player%", name, "%rank%", next); + return true; + } + + case "demote" -> { + if (guild == null) { + plugin.getMessageUtil().send(player, "messages.not-in-guild"); + return true; + } + + if (!guild.canManage(player.getUniqueId()) && !guild.getOwner().equals(player.getUniqueId())) { + plugin.getMessageUtil().send(player, "messages.no-permission"); + return true; + } + + if (args.length < 2) { + plugin.getMessageUtil().sendRaw(player, "Usage: /" + label + " demote "); + return true; + } + + OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]); + UUID targetUuid = target.getUniqueId(); + + if (!guild.isMember(targetUuid) || targetUuid.equals(guild.getOwner())) { + plugin.getMessageUtil().send(player, "messages.player-not-found"); + return true; + } + + String current = guild.getRank(targetUuid).toUpperCase(); + String next = switch (current) { + case "ADMIN" -> "MOD"; + case "MOD" -> "MEMBER"; + default -> "MEMBER"; + }; + + plugin.getGuildManager().setMemberRank(guild, targetUuid, next); + String name = target.getName() == null ? targetUuid.toString() : target.getName(); + plugin.getMessageUtil().send(player, "messages.rank-updated", "%player%", name, "%rank%", next); + return true; + } + + case "kick" -> { + if (guild == null) { + plugin.getMessageUtil().send(player, "messages.not-in-guild"); + return true; + } + + if (!guild.canManage(player.getUniqueId()) && !guild.getOwner().equals(player.getUniqueId())) { + plugin.getMessageUtil().send(player, "messages.no-permission"); + return true; + } + + if (args.length < 2) { + plugin.getMessageUtil().sendRaw(player, "Usage: /" + label + " kick "); + return true; + } + + OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]); + UUID targetUuid = target.getUniqueId(); + + if (!guild.isMember(targetUuid) || targetUuid.equals(guild.getOwner())) { + plugin.getMessageUtil().send(player, "messages.player-not-found"); + return true; + } + + plugin.getGuildManager().removeMember(guild, targetUuid); + String name = target.getName() == null ? targetUuid.toString() : target.getName(); + plugin.getMessageUtil().sendRaw(player, plugin.getMessageUtil().format("messages.prefix") + "Kicked " + name + " from the guild."); + return true; + } + + case "tp" -> { + if (guild == null) { + plugin.getMessageUtil().send(player, "messages.not-in-guild"); + return true; + } + + if (args.length < 2) { + plugin.getMessageUtil().sendRaw(player, "Usage: /" + label + " tp "); + return true; + } + + Player target = Bukkit.getPlayerExact(args[1]); + if (target == null || !guild.isMember(target.getUniqueId())) { + plugin.getMessageUtil().send(player, "messages.teleport-offline"); + return true; + } + + player.teleport(target.getLocation()); + plugin.getMessageUtil().send(player, "messages.teleport-success", "%player%", target.getName()); + return true; + } + + case "inv", "inventory" -> { + if (guild == null) { + plugin.getMessageUtil().send(player, "messages.not-in-guild"); + return true; + } + + if (!guild.canManage(player.getUniqueId()) && !guild.getOwner().equals(player.getUniqueId())) { + plugin.getMessageUtil().send(player, "messages.no-permission"); + return true; + } + + if (args.length < 2) { + plugin.getMessageUtil().sendRaw(player, "Usage: /" + label + " inventory "); + return true; + } + + Player target = Bukkit.getPlayerExact(args[1]); + if (target == null || !guild.isMember(target.getUniqueId())) { + plugin.getMessageUtil().send(player, "messages.player-not-found"); + return true; + } + + Inventory copy = Bukkit.createInventory(null, 54, MessageUtil.mm("Inventory: " + target.getName() + "")); + copy.setContents(target.getInventory().getContents()); + player.openInventory(copy); + plugin.getMessageUtil().send(player, "messages.inventory-opened", "%player%", target.getName()); + return true; + } + + case "reload" -> { + if (!player.hasPermission("dirtguilds.admin")) { + plugin.getMessageUtil().send(player, "messages.no-permission"); + return true; + } + + plugin.reloadConfig(); + plugin.getMessageUtil().send(player, "messages.reload"); + return true; + } + + default -> { + plugin.getMessageUtil().send(player, "messages.unknown-command"); + return true; + } + } + } + + @Override + public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { + List suggestions = new ArrayList<>(); + + if (args.length == 1) { + suggestions.add("create"); + suggestions.add("invite"); + suggestions.add("accept"); + suggestions.add("join"); + suggestions.add("leave"); + suggestions.add("rename"); + suggestions.add("prefix"); + suggestions.add("chat"); + suggestions.add("pvp"); + suggestions.add("bank"); + suggestions.add("vault"); + suggestions.add("level"); + suggestions.add("members"); + suggestions.add("promote"); + suggestions.add("demote"); + suggestions.add("kick"); + suggestions.add("tp"); + suggestions.add("inventory"); + suggestions.add("reload"); + return filter(suggestions, args[0]); + } + + if (args.length == 2 && args[0].equalsIgnoreCase("invite")) { + for (Player player : Bukkit.getOnlinePlayers()) { + suggestions.add(player.getName()); + } + return filter(suggestions, args[1]); + } + + if (args.length == 2 && (args[0].equalsIgnoreCase("accept") || args[0].equalsIgnoreCase("join"))) { + for (Guild guild : plugin.getGuildManager().getAllGuilds()) { + suggestions.add(guild.getName()); + } + return filter(suggestions, args[1]); + } + + if (args.length == 2 && args[0].equalsIgnoreCase("bank")) { + suggestions.add("deposit"); + suggestions.add("withdraw"); + return filter(suggestions, args[1]); + } + + if (args.length == 3 && args[0].equalsIgnoreCase("bank")) { + suggestions.add("100"); + suggestions.add("500"); + suggestions.add("1000"); + suggestions.add("5000"); + return filter(suggestions, args[2]); + } + + if (args.length == 2 && isMemberTargetSubcommand(args[0]) && sender instanceof Player player) { + Guild guild = plugin.getGuildManager().getGuildByPlayer(player.getUniqueId()); + if (guild != null) { + for (UUID uuid : guild.getMemberRanks().keySet()) { + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid); + if (offlinePlayer.getName() != null) { + suggestions.add(offlinePlayer.getName()); + } + } + } + return filter(suggestions, args[1]); + } + + return suggestions; + } + + private boolean isMemberTargetSubcommand(String input) { + String lower = input.toLowerCase(Locale.ROOT); + return lower.equals("promote") + || lower.equals("demote") + || lower.equals("kick") + || lower.equals("tp") + || lower.equals("inventory") + || lower.equals("inv"); + } + + private List filter(List input, String token) { + String lower = token.toLowerCase(Locale.ROOT); + return input.stream() + .filter(value -> value.toLowerCase(Locale.ROOT).startsWith(lower)) + .distinct() + .sorted() + .toList(); + } +} diff --git a/src/main/java/com/bitnix/dirtguilds/data/DatabaseManager.java b/src/main/java/com/bitnix/dirtguilds/data/DatabaseManager.java new file mode 100644 index 0000000..5d19281 --- /dev/null +++ b/src/main/java/com/bitnix/dirtguilds/data/DatabaseManager.java @@ -0,0 +1,101 @@ +package com.bitnix.dirtguilds.data; + +import com.bitnix.dirtguilds.DirtGuildsPlugin; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; + +import java.io.File; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; + +public class DatabaseManager { + + private final DirtGuildsPlugin plugin; + private HikariDataSource dataSource; + + public DatabaseManager(DirtGuildsPlugin plugin) { + this.plugin = plugin; + } + + public void initialize() { + String type = plugin.getConfig().getString("database.type", "SQLITE").toUpperCase(); + + HikariConfig config = new HikariConfig(); + + if (type.equals("MYSQL")) { + String host = plugin.getConfig().getString("database.mysql.host"); + int port = plugin.getConfig().getInt("database.mysql.port"); + String database = plugin.getConfig().getString("database.mysql.database"); + String username = plugin.getConfig().getString("database.mysql.username"); + String password = plugin.getConfig().getString("database.mysql.password"); + String properties = plugin.getConfig().getString("database.mysql.properties", ""); + + config.setJdbcUrl("jdbc:mysql://" + host + ":" + port + "/" + database + properties); + config.setUsername(username); + config.setPassword(password); + config.setMaximumPoolSize(10); + } else { + String fileName = plugin.getConfig().getString("database.sqlite.file", "guilds.db"); + File dbFile = new File(plugin.getDataFolder(), fileName); + + if (!plugin.getDataFolder().exists()) { + plugin.getDataFolder().mkdirs(); + } + + config.setJdbcUrl("jdbc:sqlite:" + dbFile.getAbsolutePath()); + config.setMaximumPoolSize(1); + } + + config.setPoolName("DirtGuildsPool"); + this.dataSource = new HikariDataSource(config); + + createTables(); + } + + private void createTables() { + try (Connection connection = getConnection(); Statement statement = connection.createStatement()) { + statement.executeUpdate(""" + CREATE TABLE IF NOT EXISTS guilds ( + id VARCHAR(36) PRIMARY KEY, + name VARCHAR(32) NOT NULL UNIQUE, + prefix VARCHAR(64) NOT NULL, + owner VARCHAR(36) NOT NULL, + level INT NOT NULL, + bank_balance DOUBLE NOT NULL, + friendly_fire BOOLEAN NOT NULL + ) + """); + + statement.executeUpdate(""" + CREATE TABLE IF NOT EXISTS guild_members ( + guild_id VARCHAR(36) NOT NULL, + player_uuid VARCHAR(36) NOT NULL, + rank_name VARCHAR(32) NOT NULL, + PRIMARY KEY (guild_id, player_uuid) + ) + """); + + statement.executeUpdate(""" + CREATE TABLE IF NOT EXISTS guild_vault_items ( + guild_id VARCHAR(36) NOT NULL, + slot_index INT NOT NULL, + item_data TEXT NOT NULL, + PRIMARY KEY (guild_id, slot_index) + ) + """); + } catch (SQLException exception) { + throw new RuntimeException("Failed to create database tables", exception); + } + } + + public Connection getConnection() throws SQLException { + return dataSource.getConnection(); + } + + public void close() { + if (dataSource != null && !dataSource.isClosed()) { + dataSource.close(); + } + } +} diff --git a/src/main/java/com/bitnix/dirtguilds/gui/GuildBankMenu.java b/src/main/java/com/bitnix/dirtguilds/gui/GuildBankMenu.java new file mode 100644 index 0000000..e5d1564 --- /dev/null +++ b/src/main/java/com/bitnix/dirtguilds/gui/GuildBankMenu.java @@ -0,0 +1,71 @@ +package com.bitnix.dirtguilds.gui; + +import com.bitnix.dirtguilds.DirtGuildsPlugin; +import com.bitnix.dirtguilds.guild.Guild; +import com.bitnix.dirtguilds.util.MessageUtil; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; + +public class GuildBankMenu { + + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#,##0.00"); + + private final DirtGuildsPlugin plugin; + + public GuildBankMenu(DirtGuildsPlugin plugin) { + this.plugin = plugin; + } + + public void open(Player player, Guild guild) { + String title = plugin.getConfig().getString("gui.bank.title", "Guild Bank"); + int size = plugin.getConfig().getInt("gui.bank.size", 27); + + Inventory inventory = Bukkit.createInventory(null, size, MessageUtil.mm(title)); + + inventory.setItem(11, createItem(Material.LIME_DYE, "Deposit 100", List.of( + "Click to deposit 100 into the guild bank." + ))); + + inventory.setItem(13, createItem(Material.GOLD_INGOT, "Bank Balance", List.of( + "Current Balance: " + DECIMAL_FORMAT.format(guild.getBankBalance()) + "" + ))); + + inventory.setItem(15, createItem(Material.RED_DYE, "Withdraw 100", List.of( + "Click to withdraw 100 from the guild bank." + ))); + + inventory.setItem(22, createItem(Material.ARROW, "Back", List.of( + "Return to the main guild menu." + ))); + + player.openInventory(inventory); + } + + private ItemStack createItem(Material material, String name, List loreLines) { + ItemStack item = new ItemStack(material); + ItemMeta meta = item.getItemMeta(); + + if (meta != null) { + meta.displayName(plugin.getMessageUtil().parse(name)); + + List lore = new ArrayList<>(); + for (String line : loreLines) { + lore.add(plugin.getMessageUtil().parse(line)); + } + + meta.lore(lore); + item.setItemMeta(meta); + } + + return item; + } +} diff --git a/src/main/java/com/bitnix/dirtguilds/gui/GuildLevelsMenu.java b/src/main/java/com/bitnix/dirtguilds/gui/GuildLevelsMenu.java new file mode 100644 index 0000000..26166cb --- /dev/null +++ b/src/main/java/com/bitnix/dirtguilds/gui/GuildLevelsMenu.java @@ -0,0 +1,82 @@ +package com.bitnix.dirtguilds.gui; + +import com.bitnix.dirtguilds.DirtGuildsPlugin; +import com.bitnix.dirtguilds.guild.Guild; +import com.bitnix.dirtguilds.util.MessageUtil; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; + +public class GuildLevelsMenu { + + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#,##0.00"); + + private final DirtGuildsPlugin plugin; + + public GuildLevelsMenu(DirtGuildsPlugin plugin) { + this.plugin = plugin; + } + + public void open(Player player, Guild guild) { + String title = plugin.getConfig().getString("gui.levels.title", "Guild Levels"); + int size = plugin.getConfig().getInt("gui.levels.size", 27); + + Inventory inventory = Bukkit.createInventory(null, size, MessageUtil.mm(title)); + + int currentLevel = guild.getLevel(); + int maxLevel = plugin.getGuildManager().getMaxConfiguredLevel(); + double nextCost = plugin.getGuildManager().getNextLevelCost(guild); + + inventory.setItem(11, createItem(Material.EXPERIENCE_BOTTLE, "Current Level", List.of( + "Level: " + currentLevel + "", + "Vault Slots: " + guild.getVaultContents().length + "" + ))); + + if (currentLevel >= maxLevel || nextCost < 0) { + inventory.setItem(13, createItem(Material.BARRIER, "Max Level", List.of( + "Your guild is already max level." + ))); + } else { + int nextVaultSlots = plugin.getGuildManager().getVaultSizeForLevel(currentLevel + 1); + inventory.setItem(13, createItem(Material.EMERALD, "Upgrade Guild", List.of( + "Next Level: " + (currentLevel + 1) + "", + "Cost: " + DECIMAL_FORMAT.format(nextCost) + "", + "Vault Slots: " + nextVaultSlots + "", + "Click to upgrade" + ))); + } + + inventory.setItem(22, createItem(Material.ARROW, "Back", List.of( + "Return to the main menu." + ))); + + player.openInventory(inventory); + } + + private ItemStack createItem(Material material, String name, List loreLines) { + ItemStack item = new ItemStack(material); + ItemMeta meta = item.getItemMeta(); + + if (meta != null) { + meta.displayName(plugin.getMessageUtil().parse(name)); + + List lore = new ArrayList<>(); + for (String line : loreLines) { + lore.add(plugin.getMessageUtil().parse(line)); + } + + meta.lore(lore); + item.setItemMeta(meta); + } + + return item; + } +} diff --git a/src/main/java/com/bitnix/dirtguilds/gui/GuildMainMenu.java b/src/main/java/com/bitnix/dirtguilds/gui/GuildMainMenu.java new file mode 100644 index 0000000..bf7be89 --- /dev/null +++ b/src/main/java/com/bitnix/dirtguilds/gui/GuildMainMenu.java @@ -0,0 +1,101 @@ +package com.bitnix.dirtguilds.gui; + +import com.bitnix.dirtguilds.DirtGuildsPlugin; +import com.bitnix.dirtguilds.guild.Guild; +import com.bitnix.dirtguilds.util.MessageUtil; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; + +public class GuildMainMenu { + + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#,##0.00"); + + private final DirtGuildsPlugin plugin; + + public GuildMainMenu(DirtGuildsPlugin plugin) { + this.plugin = plugin; + } + + public void open(Player player) { + String title = plugin.getConfig().getString("gui.main.title", "DirtGuilds"); + int size = plugin.getConfig().getInt("gui.main.size", 27); + + Inventory inventory = Bukkit.createInventory(null, size, MessageUtil.mm(title)); + Guild guild = plugin.getGuildManager().getGuildByPlayer(player.getUniqueId()); + + if (guild == null) { + inventory.setItem(11, createItem(Material.EMERALD, "Create Guild", List.of( + "Use: /guild create " + ))); + inventory.setItem(15, createItem(Material.WRITABLE_BOOK, "Join Guild", List.of( + "Use: /guild accept " + ))); + } else { + inventory.setItem(10, createItem(Material.NAME_TAG, "Guild Info", List.of( + "Name: " + guild.getName() + "", + "Prefix: " + guild.getPrefix() + "", + "Level: " + guild.getLevel() + "", + "Owner: " + Bukkit.getOfflinePlayer(guild.getOwner()).getName() + "" + ))); + + inventory.setItem(11, createItem(Material.CHEST, "Guild Bank", List.of( + "Balance: " + DECIMAL_FORMAT.format(guild.getBankBalance()) + "", + "Click to open bank menu." + ))); + + inventory.setItem(12, createItem(Material.BARREL, "Guild Vault", List.of( + "Slots: " + guild.getVaultContents().length + "", + "Click to open guild vault." + ))); + + inventory.setItem(13, createItem(Material.EXPERIENCE_BOTTLE, "Guild Levels", List.of( + "Current Level: " + guild.getLevel() + "", + "Click to view upgrades." + ))); + + inventory.setItem(14, createItem(Material.IRON_SWORD, "Friendly Fire", List.of( + guild.isFriendlyFire() ? "Enabled" : "Disabled", + "Click to toggle" + ))); + + inventory.setItem(15, createItem(Material.PLAYER_HEAD, "Members", List.of( + "Members: " + guild.getMemberRanks().size() + "", + "Click to view members" + ))); + + inventory.setItem(16, createItem(Material.PAPER, "Guild Chat", List.of( + plugin.getGuildManager().isGuildChatEnabled(player.getUniqueId()) ? "Enabled" : "Disabled", + "Click to toggle guild chat" + ))); + } + + player.openInventory(inventory); + } + + private ItemStack createItem(Material material, String name, List loreLines) { + ItemStack item = new ItemStack(material); + ItemMeta meta = item.getItemMeta(); + + if (meta != null) { + meta.displayName(plugin.getMessageUtil().parse(name)); + + List lore = new ArrayList<>(); + for (String line : loreLines) { + lore.add(plugin.getMessageUtil().parse(line)); + } + meta.lore(lore); + item.setItemMeta(meta); + } + + return item; + } +} diff --git a/src/main/java/com/bitnix/dirtguilds/gui/GuildMemberManageMenu.java b/src/main/java/com/bitnix/dirtguilds/gui/GuildMemberManageMenu.java new file mode 100644 index 0000000..dfc36c0 --- /dev/null +++ b/src/main/java/com/bitnix/dirtguilds/gui/GuildMemberManageMenu.java @@ -0,0 +1,79 @@ +package com.bitnix.dirtguilds.gui; + +import com.bitnix.dirtguilds.DirtGuildsPlugin; +import com.bitnix.dirtguilds.guild.Guild; +import com.bitnix.dirtguilds.util.MessageUtil; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class GuildMemberManageMenu { + + private final DirtGuildsPlugin plugin; + + public GuildMemberManageMenu(DirtGuildsPlugin plugin) { + this.plugin = plugin; + } + + public void open(Player viewer, Guild guild, UUID targetUuid) { + String title = plugin.getConfig().getString("gui.member-manage.title", "Manage Member"); + int size = plugin.getConfig().getInt("gui.member-manage.size", 27); + + Inventory inventory = Bukkit.createInventory(null, size, MessageUtil.mm(title)); + + OfflinePlayer target = Bukkit.getOfflinePlayer(targetUuid); + String name = target.getName() == null ? targetUuid.toString() : target.getName(); + String rank = guild.getRank(targetUuid); + + inventory.setItem(10, createItem(Material.ENDER_PEARL, "Teleport", List.of( + "Teleport to: " + name + "" + ))); + + inventory.setItem(12, createItem(Material.CHEST, "View Inventory", List.of( + "Open inventory of: " + name + "" + ))); + + inventory.setItem(14, createItem(Material.NAME_TAG, "Cycle Rank", List.of( + "Current Rank: " + rank + "", + "Click to cycle rank." + ))); + + inventory.setItem(16, createItem(Material.BARRIER, "Kick Member", List.of( + "Remove: " + name + "" + ))); + + inventory.setItem(22, createItem(Material.ARROW, "Back", List.of( + "Return to members menu." + ))); + + viewer.openInventory(inventory); + } + + private ItemStack createItem(Material material, String name, List loreLines) { + ItemStack item = new ItemStack(material); + ItemMeta meta = item.getItemMeta(); + + if (meta != null) { + meta.displayName(plugin.getMessageUtil().parse(name)); + + List lore = new ArrayList<>(); + for (String line : loreLines) { + lore.add(plugin.getMessageUtil().parse(line)); + } + + meta.lore(lore); + item.setItemMeta(meta); + } + + return item; + } +} diff --git a/src/main/java/com/bitnix/dirtguilds/gui/GuildMembersMenu.java b/src/main/java/com/bitnix/dirtguilds/gui/GuildMembersMenu.java new file mode 100644 index 0000000..7359e2f --- /dev/null +++ b/src/main/java/com/bitnix/dirtguilds/gui/GuildMembersMenu.java @@ -0,0 +1,94 @@ +package com.bitnix.dirtguilds.gui; + +import com.bitnix.dirtguilds.DirtGuildsPlugin; +import com.bitnix.dirtguilds.guild.Guild; +import com.bitnix.dirtguilds.util.MessageUtil; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.UUID; + +public class GuildMembersMenu { + + private final DirtGuildsPlugin plugin; + + public GuildMembersMenu(DirtGuildsPlugin plugin) { + this.plugin = plugin; + } + + public void open(Player viewer, Guild guild) { + String title = plugin.getConfig().getString("gui.members.title", "Guild Members"); + int size = plugin.getConfig().getInt("gui.members.size", 54); + + Inventory inventory = Bukkit.createInventory(null, size, MessageUtil.mm(title)); + + List members = new ArrayList<>(guild.getMemberRanks().keySet()); + members.sort(Comparator.comparing(uuid -> { + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid); + String name = offlinePlayer.getName(); + return name == null ? uuid.toString() : name.toLowerCase(); + })); + + int slot = 0; + for (UUID memberId : members) { + if (slot >= size - 9) { + break; + } + + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(memberId); + inventory.setItem(slot, createMemberHead(guild, offlinePlayer)); + slot++; + } + + inventory.setItem(size - 5, createBackItem()); + viewer.openInventory(inventory); + } + + private ItemStack createMemberHead(Guild guild, OfflinePlayer offlinePlayer) { + ItemStack item = new ItemStack(Material.PLAYER_HEAD); + SkullMeta meta = (SkullMeta) item.getItemMeta(); + + if (meta != null) { + meta.setOwningPlayer(offlinePlayer); + + String playerName = offlinePlayer.getName() == null ? offlinePlayer.getUniqueId().toString() : offlinePlayer.getName(); + boolean owner = offlinePlayer.getUniqueId().equals(guild.getOwner()); + boolean online = offlinePlayer.isOnline(); + String rank = guild.getRank(offlinePlayer.getUniqueId()); + + meta.displayName(plugin.getMessageUtil().parse( + (owner ? "" : "") + playerName + (owner ? " (Owner)" : "") + )); + + List lore = new ArrayList<>(); + lore.add(plugin.getMessageUtil().parse("Status: " + (online ? "Online" : "Offline"))); + lore.add(plugin.getMessageUtil().parse("Rank: " + rank + "")); + lore.add(plugin.getMessageUtil().parse("UUID:" + offlinePlayer.getUniqueId() + "")); + lore.add(plugin.getMessageUtil().parse("Click to manage member.")); + + meta.lore(lore); + item.setItemMeta(meta); + } + + return item; + } + + private ItemStack createBackItem() { + ItemStack item = new ItemStack(Material.ARROW); + var meta = item.getItemMeta(); + if (meta != null) { + meta.displayName(plugin.getMessageUtil().parse("Back")); + item.setItemMeta(meta); + } + return item; + } +} diff --git a/src/main/java/com/bitnix/dirtguilds/gui/GuildVaultMenu.java b/src/main/java/com/bitnix/dirtguilds/gui/GuildVaultMenu.java new file mode 100644 index 0000000..13b9f12 --- /dev/null +++ b/src/main/java/com/bitnix/dirtguilds/gui/GuildVaultMenu.java @@ -0,0 +1,32 @@ +package com.bitnix.dirtguilds.gui; + +import com.bitnix.dirtguilds.DirtGuildsPlugin; +import com.bitnix.dirtguilds.guild.Guild; +import com.bitnix.dirtguilds.util.MessageUtil; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +public class GuildVaultMenu { + + private final DirtGuildsPlugin plugin; + + public GuildVaultMenu(DirtGuildsPlugin plugin) { + this.plugin = plugin; + } + + public void open(Player player, Guild guild) { + String title = plugin.getConfig().getString("gui.vault.title", "Guild Vault"); + int size = guild.getVaultContents().length; + + Inventory inventory = Bukkit.createInventory(player, size, MessageUtil.mm(title)); + ItemStack[] contents = guild.getVaultContents(); + + for (int i = 0; i < Math.min(size, contents.length); i++) { + inventory.setItem(i, contents[i]); + } + + player.openInventory(inventory); + } +} diff --git a/src/main/java/com/bitnix/dirtguilds/guild/Guild.java b/src/main/java/com/bitnix/dirtguilds/guild/Guild.java new file mode 100644 index 0000000..a564815 --- /dev/null +++ b/src/main/java/com/bitnix/dirtguilds/guild/Guild.java @@ -0,0 +1,123 @@ +package com.bitnix.dirtguilds.guild; + +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class Guild { + + private final UUID id; + private String name; + private String prefix; + private UUID owner; + private int level; + private double bankBalance; + private boolean friendlyFire; + private final Map memberRanks; + private ItemStack[] vaultContents; + + public Guild(UUID id, String name, String prefix, UUID owner, int level, double bankBalance, boolean friendlyFire, Map memberRanks, ItemStack[] vaultContents) { + this.id = id; + this.name = name; + this.prefix = prefix; + this.owner = owner; + this.level = level; + this.bankBalance = bankBalance; + this.friendlyFire = friendlyFire; + this.memberRanks = new HashMap<>(memberRanks); + this.memberRanks.put(owner, "OWNER"); + this.vaultContents = vaultContents == null ? new ItemStack[9] : vaultContents; + } + + public UUID getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPrefix() { + return prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + public UUID getOwner() { + return owner; + } + + public void setOwner(UUID owner) { + this.owner = owner; + this.memberRanks.put(owner, "OWNER"); + } + + public int getLevel() { + return level; + } + + public void setLevel(int level) { + this.level = level; + } + + public double getBankBalance() { + return bankBalance; + } + + public void setBankBalance(double bankBalance) { + this.bankBalance = bankBalance; + } + + public boolean isFriendlyFire() { + return friendlyFire; + } + + public void setFriendlyFire(boolean friendlyFire) { + this.friendlyFire = friendlyFire; + } + + public Map getMemberRanks() { + return memberRanks; + } + + public boolean isMember(UUID uuid) { + return memberRanks.containsKey(uuid); + } + + public void addMember(UUID uuid) { + memberRanks.putIfAbsent(uuid, "MEMBER"); + } + + public void removeMember(UUID uuid) { + memberRanks.remove(uuid); + } + + public String getRank(UUID uuid) { + return memberRanks.getOrDefault(uuid, "MEMBER"); + } + + public void setRank(UUID uuid, String rank) { + memberRanks.put(uuid, rank); + } + + public boolean canManage(UUID uuid) { + String rank = getRank(uuid).toUpperCase(); + return uuid.equals(owner) || rank.equals("OWNER") || rank.equals("ADMIN") || rank.equals("MOD"); + } + + public ItemStack[] getVaultContents() { + return vaultContents; + } + + public void setVaultContents(ItemStack[] vaultContents) { + this.vaultContents = vaultContents; + } +} diff --git a/src/main/java/com/bitnix/dirtguilds/guild/GuildInvite.java b/src/main/java/com/bitnix/dirtguilds/guild/GuildInvite.java new file mode 100644 index 0000000..107b9da --- /dev/null +++ b/src/main/java/com/bitnix/dirtguilds/guild/GuildInvite.java @@ -0,0 +1,38 @@ +package com.bitnix.dirtguilds.guild; + +import java.util.UUID; + +public class GuildInvite { + + private final UUID guildId; + private final UUID target; + private final UUID inviter; + private final long expiresAt; + + public GuildInvite(UUID guildId, UUID target, UUID inviter, long expiresAt) { + this.guildId = guildId; + this.target = target; + this.inviter = inviter; + this.expiresAt = expiresAt; + } + + public UUID getGuildId() { + return guildId; + } + + public UUID getTarget() { + return target; + } + + public UUID getInviter() { + return inviter; + } + + public long getExpiresAt() { + return expiresAt; + } + + public boolean isExpired() { + return System.currentTimeMillis() > expiresAt; + } +} diff --git a/src/main/java/com/bitnix/dirtguilds/guild/GuildManager.java b/src/main/java/com/bitnix/dirtguilds/guild/GuildManager.java new file mode 100644 index 0000000..cb8e15b --- /dev/null +++ b/src/main/java/com/bitnix/dirtguilds/guild/GuildManager.java @@ -0,0 +1,479 @@ +package com.bitnix.dirtguilds.guild; + +import com.bitnix.dirtguilds.DirtGuildsPlugin; +import com.bitnix.dirtguilds.data.DatabaseManager; +import org.bukkit.Bukkit; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.io.BukkitObjectInputStream; +import org.bukkit.util.io.BukkitObjectOutputStream; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.Base64; + +public class GuildManager { + + private final DirtGuildsPlugin plugin; + private final DatabaseManager databaseManager; + + private final Map guildsById; + private final Map guildIdsByLowerName; + private final Map playerGuildMap; + private final Map> invitesByTarget; + private final Set guildChatEnabled; + + public GuildManager(DirtGuildsPlugin plugin, DatabaseManager databaseManager) { + this.plugin = plugin; + this.databaseManager = databaseManager; + this.guildsById = new ConcurrentHashMap<>(); + this.guildIdsByLowerName = new ConcurrentHashMap<>(); + this.playerGuildMap = new ConcurrentHashMap<>(); + this.invitesByTarget = new ConcurrentHashMap<>(); + this.guildChatEnabled = ConcurrentHashMap.newKeySet(); + } + + public void loadAll() { + guildsById.clear(); + guildIdsByLowerName.clear(); + playerGuildMap.clear(); + invitesByTarget.clear(); + guildChatEnabled.clear(); + + try (Connection connection = databaseManager.getConnection()) { + Map> memberMap = new HashMap<>(); + Map vaultMap = new HashMap<>(); + + try (PreparedStatement statement = connection.prepareStatement("SELECT guild_id, player_uuid, rank_name FROM guild_members"); + ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + UUID guildId = UUID.fromString(resultSet.getString("guild_id")); + UUID playerUuid = UUID.fromString(resultSet.getString("player_uuid")); + String rankName = resultSet.getString("rank_name"); + + memberMap.computeIfAbsent(guildId, ignored -> new HashMap<>()).put(playerUuid, rankName); + playerGuildMap.put(playerUuid, guildId); + } + } + + try (PreparedStatement statement = connection.prepareStatement("SELECT guild_id, slot_index, item_data FROM guild_vault_items"); + ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + UUID guildId = UUID.fromString(resultSet.getString("guild_id")); + int slot = resultSet.getInt("slot_index"); + String itemData = resultSet.getString("item_data"); + + ItemStack[] contents = vaultMap.computeIfAbsent(guildId, ignored -> new ItemStack[54]); + contents[slot] = deserializeItem(itemData); + } + } + + try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM guilds"); + ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + UUID id = UUID.fromString(resultSet.getString("id")); + String name = resultSet.getString("name"); + String prefix = resultSet.getString("prefix"); + UUID owner = UUID.fromString(resultSet.getString("owner")); + int level = resultSet.getInt("level"); + double bankBalance = resultSet.getDouble("bank_balance"); + boolean friendlyFire = resultSet.getBoolean("friendly_fire"); + + ItemStack[] vault = vaultMap.getOrDefault(id, new ItemStack[getVaultSizeForLevel(level)]); + Guild guild = new Guild( + id, + name, + prefix, + owner, + level, + bankBalance, + friendlyFire, + memberMap.getOrDefault(id, new HashMap<>()), + normalizeVault(vault, getVaultSizeForLevel(level)) + ); + + guildsById.put(id, guild); + guildIdsByLowerName.put(name.toLowerCase(Locale.ROOT), id); + + for (UUID member : guild.getMemberRanks().keySet()) { + playerGuildMap.put(member, id); + } + } + } + } catch (Exception exception) { + throw new RuntimeException("Failed to load guild data", exception); + } + } + + public Guild getGuildByPlayer(UUID playerUuid) { + UUID guildId = playerGuildMap.get(playerUuid); + return guildId == null ? null : guildsById.get(guildId); + } + + public Guild getGuildByName(String name) { + if (name == null) { + return null; + } + + UUID guildId = guildIdsByLowerName.get(name.toLowerCase(Locale.ROOT)); + return guildId == null ? null : guildsById.get(guildId); + } + + public Guild getGuildById(UUID guildId) { + return guildsById.get(guildId); + } + + public boolean isInGuild(UUID playerUuid) { + return playerGuildMap.containsKey(playerUuid); + } + + public boolean guildNameExists(String name) { + return guildIdsByLowerName.containsKey(name.toLowerCase(Locale.ROOT)); + } + + public Guild createGuild(UUID owner, String name) { + UUID guildId = UUID.randomUUID(); + int defaultLevel = plugin.getConfig().getInt("settings.levels.default-level", 1); + int vaultSize = getVaultSizeForLevel(defaultLevel); + + Guild guild = new Guild( + guildId, + name, + name, + owner, + defaultLevel, + 0.0D, + plugin.getConfig().getBoolean("settings.default-friendly-fire", false), + new HashMap<>(), + new ItemStack[vaultSize] + ); + + guildsById.put(guildId, guild); + guildIdsByLowerName.put(name.toLowerCase(Locale.ROOT), guildId); + playerGuildMap.put(owner, guildId); + + saveGuild(guild); + saveMembers(guild); + saveVault(guild); + return guild; + } + + public void deleteGuild(Guild guild) { + guildsById.remove(guild.getId()); + guildIdsByLowerName.remove(guild.getName().toLowerCase(Locale.ROOT)); + + for (UUID member : new HashSet<>(guild.getMemberRanks().keySet())) { + playerGuildMap.remove(member); + guildChatEnabled.remove(member); + } + + invitesByTarget.values().forEach(list -> list.removeIf(invite -> invite.getGuildId().equals(guild.getId()))); + + try (Connection connection = databaseManager.getConnection()) { + try (PreparedStatement statement = connection.prepareStatement("DELETE FROM guild_members WHERE guild_id = ?")) { + statement.setString(1, guild.getId().toString()); + statement.executeUpdate(); + } + + try (PreparedStatement statement = connection.prepareStatement("DELETE FROM guild_vault_items WHERE guild_id = ?")) { + statement.setString(1, guild.getId().toString()); + statement.executeUpdate(); + } + + try (PreparedStatement statement = connection.prepareStatement("DELETE FROM guilds WHERE id = ?")) { + statement.setString(1, guild.getId().toString()); + statement.executeUpdate(); + } + } catch (SQLException exception) { + throw new RuntimeException("Failed to delete guild", exception); + } + } + + public void renameGuild(Guild guild, String newName) { + guildIdsByLowerName.remove(guild.getName().toLowerCase(Locale.ROOT)); + guild.setName(newName); + guildIdsByLowerName.put(newName.toLowerCase(Locale.ROOT), guild.getId()); + saveGuild(guild); + } + + public void setPrefix(Guild guild, String prefix) { + guild.setPrefix(prefix); + saveGuild(guild); + } + + public void setFriendlyFire(Guild guild, boolean enabled) { + guild.setFriendlyFire(enabled); + saveGuild(guild); + } + + public void addMember(Guild guild, UUID playerUuid) { + guild.addMember(playerUuid); + playerGuildMap.put(playerUuid, guild.getId()); + saveMembers(guild); + } + + public void removeMember(Guild guild, UUID playerUuid) { + guild.removeMember(playerUuid); + playerGuildMap.remove(playerUuid); + guildChatEnabled.remove(playerUuid); + saveMembers(guild); + } + + public void setMemberRank(Guild guild, UUID playerUuid, String rank) { + guild.setRank(playerUuid, rank); + saveMembers(guild); + } + + public void transferOwnership(Guild guild, UUID newOwner) { + guild.setOwner(newOwner); + guild.setRank(newOwner, "OWNER"); + playerGuildMap.put(newOwner, guild.getId()); + saveGuild(guild); + saveMembers(guild); + } + + public void deposit(Guild guild, double amount) { + guild.setBankBalance(guild.getBankBalance() + amount); + saveGuild(guild); + } + + public boolean withdraw(Guild guild, double amount) { + if (guild.getBankBalance() < amount) { + return false; + } + + guild.setBankBalance(guild.getBankBalance() - amount); + saveGuild(guild); + return true; + } + + public boolean upgradeLevel(Guild guild) { + int nextLevel = guild.getLevel() + 1; + ConfigurationSection levelSection = plugin.getConfig().getConfigurationSection("settings.levels.levels." + nextLevel); + if (levelSection == null) { + return false; + } + + double cost = levelSection.getDouble("cost", 0.0D); + if (guild.getBankBalance() < cost) { + return false; + } + + guild.setBankBalance(guild.getBankBalance() - cost); + guild.setLevel(nextLevel); + guild.setVaultContents(normalizeVault(guild.getVaultContents(), getVaultSizeForLevel(nextLevel))); + saveGuild(guild); + saveVault(guild); + return true; + } + + public int getMaxConfiguredLevel() { + ConfigurationSection section = plugin.getConfig().getConfigurationSection("settings.levels.levels"); + if (section == null) { + return 1; + } + + int max = 1; + for (String key : section.getKeys(false)) { + try { + max = Math.max(max, Integer.parseInt(key)); + } catch (NumberFormatException ignored) { + } + } + return max; + } + + public int getVaultSizeForLevel(int level) { + int configured = plugin.getConfig().getInt("settings.levels.levels." + level + ".vault-slots", + plugin.getConfig().getInt("settings.vault.default-size", 9)); + + configured = Math.max(9, configured); + configured = Math.min(plugin.getConfig().getInt("settings.vault.max-size", 54), configured); + + int remainder = configured % 9; + if (remainder != 0) { + configured += (9 - remainder); + } + + return Math.max(9, Math.min(54, configured)); + } + + public double getNextLevelCost(Guild guild) { + return plugin.getConfig().getDouble("settings.levels.levels." + (guild.getLevel() + 1) + ".cost", -1.0D); + } + + public void createInvite(UUID target, UUID inviter, Guild guild) { + long expiresAt = System.currentTimeMillis() + (plugin.getConfig().getLong("settings.invite-expire-seconds", 120L) * 1000L); + GuildInvite invite = new GuildInvite(guild.getId(), target, inviter, expiresAt); + invitesByTarget.computeIfAbsent(target, ignored -> new ArrayList<>()).removeIf(existing -> existing.getGuildId().equals(guild.getId())); + invitesByTarget.computeIfAbsent(target, ignored -> new ArrayList<>()).add(invite); + } + + public GuildInvite getInvite(UUID target, UUID guildId) { + List invites = invitesByTarget.get(target); + if (invites == null) { + return null; + } + + invites.removeIf(GuildInvite::isExpired); + + for (GuildInvite invite : invites) { + if (invite.getGuildId().equals(guildId)) { + return invite; + } + } + + return null; + } + + public void removeInvite(UUID target, UUID guildId) { + List invites = invitesByTarget.get(target); + if (invites == null) { + return; + } + + invites.removeIf(invite -> invite.getGuildId().equals(guildId)); + if (invites.isEmpty()) { + invitesByTarget.remove(target); + } + } + + public boolean isGuildChatEnabled(UUID playerUuid) { + return guildChatEnabled.contains(playerUuid); + } + + public void setGuildChatEnabled(UUID playerUuid, boolean enabled) { + if (enabled) { + guildChatEnabled.add(playerUuid); + } else { + guildChatEnabled.remove(playerUuid); + } + } + + public void saveVaultFromInventory(Guild guild, Inventory inventory) { + ItemStack[] contents = new ItemStack[inventory.getSize()]; + for (int i = 0; i < inventory.getSize(); i++) { + contents[i] = inventory.getItem(i); + } + guild.setVaultContents(contents); + saveVault(guild); + } + + public Collection getAllGuilds() { + return Collections.unmodifiableCollection(guildsById.values()); + } + + private void saveGuild(Guild guild) { + try (Connection connection = databaseManager.getConnection(); + PreparedStatement statement = connection.prepareStatement(""" + INSERT INTO guilds (id, name, prefix, owner, level, bank_balance, friendly_fire) + VALUES (?, ?, ?, ?, ?, ?, ?) + ON CONFLICT(id) DO UPDATE SET + name = excluded.name, + prefix = excluded.prefix, + owner = excluded.owner, + level = excluded.level, + bank_balance = excluded.bank_balance, + friendly_fire = excluded.friendly_fire + """)) { + + statement.setString(1, guild.getId().toString()); + statement.setString(2, guild.getName()); + statement.setString(3, guild.getPrefix()); + statement.setString(4, guild.getOwner().toString()); + statement.setInt(5, guild.getLevel()); + statement.setDouble(6, guild.getBankBalance()); + statement.setBoolean(7, guild.isFriendlyFire()); + statement.executeUpdate(); + } catch (SQLException exception) { + throw new RuntimeException("Failed to save guild", exception); + } + } + + private void saveMembers(Guild guild) { + try (Connection connection = databaseManager.getConnection()) { + try (PreparedStatement delete = connection.prepareStatement("DELETE FROM guild_members WHERE guild_id = ?")) { + delete.setString(1, guild.getId().toString()); + delete.executeUpdate(); + } + + try (PreparedStatement insert = connection.prepareStatement("INSERT INTO guild_members (guild_id, player_uuid, rank_name) VALUES (?, ?, ?)")) { + for (Map.Entry entry : guild.getMemberRanks().entrySet()) { + insert.setString(1, guild.getId().toString()); + insert.setString(2, entry.getKey().toString()); + insert.setString(3, entry.getValue()); + insert.addBatch(); + } + insert.executeBatch(); + } + } catch (SQLException exception) { + throw new RuntimeException("Failed to save guild members", exception); + } + } + + private void saveVault(Guild guild) { + try (Connection connection = databaseManager.getConnection()) { + try (PreparedStatement delete = connection.prepareStatement("DELETE FROM guild_vault_items WHERE guild_id = ?")) { + delete.setString(1, guild.getId().toString()); + delete.executeUpdate(); + } + + try (PreparedStatement insert = connection.prepareStatement("INSERT INTO guild_vault_items (guild_id, slot_index, item_data) VALUES (?, ?, ?)")) { + ItemStack[] contents = guild.getVaultContents(); + for (int i = 0; i < contents.length; i++) { + ItemStack item = contents[i]; + if (item == null) { + continue; + } + + insert.setString(1, guild.getId().toString()); + insert.setInt(2, i); + insert.setString(3, serializeItem(item)); + insert.addBatch(); + } + insert.executeBatch(); + } + } catch (Exception exception) { + throw new RuntimeException("Failed to save guild vault", exception); + } + } + + private String serializeItem(ItemStack item) throws Exception { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream); + dataOutput.writeObject(item); + dataOutput.close(); + return Base64.getEncoder().encodeToString(outputStream.toByteArray()); + } + + private ItemStack deserializeItem(String data) throws Exception { + byte[] bytes = Base64.getDecoder().decode(data); + BukkitObjectInputStream dataInput = new BukkitObjectInputStream(new ByteArrayInputStream(bytes)); + ItemStack item = (ItemStack) dataInput.readObject(); + dataInput.close(); + return item; + } + + private ItemStack[] normalizeVault(ItemStack[] original, int newSize) { + ItemStack[] normalized = new ItemStack[newSize]; + if (original != null) { + System.arraycopy(original, 0, normalized, 0, Math.min(original.length, newSize)); + } + return normalized; + } + + public void shutdown() { + invitesByTarget.clear(); + guildChatEnabled.clear(); + guildsById.clear(); + guildIdsByLowerName.clear(); + playerGuildMap.clear(); + } +} diff --git a/src/main/java/com/bitnix/dirtguilds/hook/EconomyHook.java b/src/main/java/com/bitnix/dirtguilds/hook/EconomyHook.java new file mode 100644 index 0000000..a95dd2a --- /dev/null +++ b/src/main/java/com/bitnix/dirtguilds/hook/EconomyHook.java @@ -0,0 +1,38 @@ +package com.bitnix.dirtguilds.hook; + +import com.bitnix.dirtguilds.DirtGuildsPlugin; +import net.milkbowl.vault.economy.Economy; +import org.bukkit.Bukkit; +import org.bukkit.plugin.RegisteredServiceProvider; + +public class EconomyHook { + + private final DirtGuildsPlugin plugin; + private Economy economy; + + public EconomyHook(DirtGuildsPlugin plugin) { + this.plugin = plugin; + } + + public boolean setup() { + if (Bukkit.getPluginManager().getPlugin("Vault") == null) { + return false; + } + + RegisteredServiceProvider provider = Bukkit.getServicesManager().getRegistration(Economy.class); + if (provider == null) { + return false; + } + + this.economy = provider.getProvider(); + return this.economy != null; + } + + public boolean isAvailable() { + return economy != null; + } + + public Economy getEconomy() { + return economy; + } +} diff --git a/src/main/java/com/bitnix/dirtguilds/listener/ChatListener.java b/src/main/java/com/bitnix/dirtguilds/listener/ChatListener.java new file mode 100644 index 0000000..7347dd9 --- /dev/null +++ b/src/main/java/com/bitnix/dirtguilds/listener/ChatListener.java @@ -0,0 +1,48 @@ +package com.bitnix.dirtguilds.listener; + +import com.bitnix.dirtguilds.DirtGuildsPlugin; +import com.bitnix.dirtguilds.guild.Guild; +import io.papermc.paper.event.player.AsyncChatEvent; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +public class ChatListener implements Listener { + + private final DirtGuildsPlugin plugin; + + public ChatListener(DirtGuildsPlugin plugin) { + this.plugin = plugin; + } + + @EventHandler + public void onChat(AsyncChatEvent event) { + Player player = event.getPlayer(); + + if (!plugin.getGuildManager().isGuildChatEnabled(player.getUniqueId())) { + return; + } + + Guild guild = plugin.getGuildManager().getGuildByPlayer(player.getUniqueId()); + if (guild == null) { + plugin.getGuildManager().setGuildChatEnabled(player.getUniqueId(), false); + return; + } + + event.setCancelled(true); + + Component message = event.message(); + Component format = plugin.getMessageUtil().parse( + "[Guild] " + guild.getPrefix() + " " + player.getName() + ": " + ); + + for (Player online : Bukkit.getOnlinePlayers()) { + Guild targetGuild = plugin.getGuildManager().getGuildByPlayer(online.getUniqueId()); + if (targetGuild != null && targetGuild.getId().equals(guild.getId())) { + online.sendMessage(format.append(message)); + } + } + } +} diff --git a/src/main/java/com/bitnix/dirtguilds/listener/GuiListener.java b/src/main/java/com/bitnix/dirtguilds/listener/GuiListener.java new file mode 100644 index 0000000..38d2ec2 --- /dev/null +++ b/src/main/java/com/bitnix/dirtguilds/listener/GuiListener.java @@ -0,0 +1,369 @@ +package com.bitnix.dirtguilds.listener; + +import com.bitnix.dirtguilds.DirtGuildsPlugin; +import com.bitnix.dirtguilds.gui.GuildBankMenu; +import com.bitnix.dirtguilds.gui.GuildLevelsMenu; +import com.bitnix.dirtguilds.gui.GuildMainMenu; +import com.bitnix.dirtguilds.gui.GuildMemberManageMenu; +import com.bitnix.dirtguilds.gui.GuildMembersMenu; +import com.bitnix.dirtguilds.gui.GuildVaultMenu; +import com.bitnix.dirtguilds.guild.Guild; +import com.bitnix.dirtguilds.util.MessageUtil; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.HumanEntity; +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.inventory.Inventory; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.SkullMeta; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class GuiListener implements Listener { + + private final DirtGuildsPlugin plugin; + private final PlainTextComponentSerializer plainText; + private final Map selectedMemberTargets; + + public GuiListener(DirtGuildsPlugin plugin) { + this.plugin = plugin; + this.plainText = PlainTextComponentSerializer.plainText(); + this.selectedMemberTargets = new HashMap<>(); + } + + @EventHandler + public void onInventoryClick(InventoryClickEvent event) { + if (!(event.getWhoClicked() instanceof Player player)) { + return; + } + + String openedTitle = plainText.serialize(event.getView().title()); + String mainTitle = title("gui.main.title", "DirtGuilds"); + String membersTitle = title("gui.members.title", "Guild Members"); + String memberManageTitle = title("gui.member-manage.title", "Manage Member"); + String bankTitle = title("gui.bank.title", "Guild Bank"); + String vaultTitle = title("gui.vault.title", "Guild Vault"); + String levelsTitle = title("gui.levels.title", "Guild Levels"); + + if (openedTitle.equals(mainTitle)) { + handleMainMenuClick(event, player); + return; + } + + if (openedTitle.equals(membersTitle)) { + handleMembersMenuClick(event, player); + return; + } + + if (openedTitle.equals(memberManageTitle)) { + handleMemberManageMenuClick(event, player); + return; + } + + if (openedTitle.equals(bankTitle)) { + handleBankMenuClick(event, player); + return; + } + + if (openedTitle.equals(vaultTitle)) { + handleVaultMenuClick(event); + return; + } + + if (openedTitle.equals(levelsTitle)) { + handleLevelsMenuClick(event, player); + } + } + + @EventHandler + public void onInventoryClose(InventoryCloseEvent event) { + HumanEntity human = event.getPlayer(); + if (!(human instanceof Player player)) { + return; + } + + String openedTitle = plainText.serialize(event.getView().title()); + String vaultTitle = title("gui.vault.title", "Guild Vault"); + + if (!openedTitle.equals(vaultTitle)) { + return; + } + + Guild guild = plugin.getGuildManager().getGuildByPlayer(player.getUniqueId()); + if (guild == null) { + return; + } + + plugin.getGuildManager().saveVaultFromInventory(guild, event.getInventory()); + } + + private void handleMainMenuClick(InventoryClickEvent event, Player player) { + event.setCancelled(true); + + if (event.getCurrentItem() == null || event.getCurrentItem().getType().isAir()) { + return; + } + + Guild guild = plugin.getGuildManager().getGuildByPlayer(player.getUniqueId()); + + switch (event.getCurrentItem().getType()) { + case EMERALD -> plugin.getMessageUtil().sendRaw(player, "Use /guild create "); + case WRITABLE_BOOK -> plugin.getMessageUtil().sendRaw(player, "Use /guild accept "); + case CHEST -> { + if (guild != null) { + new GuildBankMenu(plugin).open(player, guild); + } + } + case BARREL -> { + if (guild != null) { + new GuildVaultMenu(plugin).open(player, guild); + } + } + case EXPERIENCE_BOTTLE -> { + if (guild != null) { + new GuildLevelsMenu(plugin).open(player, guild); + } + } + case IRON_SWORD -> { + if (guild != null) { + player.closeInventory(); + player.performCommand("guild pvp"); + } + } + case PLAYER_HEAD -> { + if (guild != null) { + new GuildMembersMenu(plugin).open(player, guild); + } + } + case PAPER -> { + if (guild != null) { + player.closeInventory(); + player.performCommand("guild chat"); + } + } + default -> { + } + } + } + + private void handleMembersMenuClick(InventoryClickEvent event, Player player) { + event.setCancelled(true); + + if (event.getCurrentItem() == null || event.getCurrentItem().getType().isAir()) { + return; + } + + Guild guild = plugin.getGuildManager().getGuildByPlayer(player.getUniqueId()); + if (guild == null) { + player.closeInventory(); + return; + } + + if (event.getCurrentItem().getType() == Material.ARROW) { + new GuildMainMenu(plugin).open(player); + return; + } + + if (event.getCurrentItem().getType() != Material.PLAYER_HEAD) { + return; + } + + UUID targetUuid = extractUuidFromItem(event.getCurrentItem().getItemMeta()); + if (targetUuid == null || !guild.isMember(targetUuid)) { + return; + } + + selectedMemberTargets.put(player.getUniqueId(), targetUuid); + new GuildMemberManageMenu(plugin).open(player, guild, targetUuid); + } + + private void handleMemberManageMenuClick(InventoryClickEvent event, Player player) { + event.setCancelled(true); + + if (event.getCurrentItem() == null || event.getCurrentItem().getType().isAir()) { + return; + } + + Guild guild = plugin.getGuildManager().getGuildByPlayer(player.getUniqueId()); + if (guild == null) { + player.closeInventory(); + return; + } + + UUID targetUuid = selectedMemberTargets.get(player.getUniqueId()); + if (targetUuid == null || !guild.isMember(targetUuid)) { + new GuildMembersMenu(plugin).open(player, guild); + return; + } + + if (!guild.canManage(player.getUniqueId()) && !guild.getOwner().equals(player.getUniqueId())) { + plugin.getMessageUtil().send(player, "messages.no-permission"); + return; + } + + switch (event.getCurrentItem().getType()) { + case ENDER_PEARL -> { + Player target = Bukkit.getPlayer(targetUuid); + if (target == null) { + plugin.getMessageUtil().send(player, "messages.teleport-offline"); + return; + } + + player.teleport(target.getLocation()); + plugin.getMessageUtil().send(player, "messages.teleport-success", "%player%", target.getName()); + } + + case CHEST -> { + Player target = Bukkit.getPlayer(targetUuid); + if (target == null) { + plugin.getMessageUtil().send(player, "messages.teleport-offline"); + return; + } + + Inventory copy = Bukkit.createInventory(null, 54, MessageUtil.mm("Inventory: " + target.getName() + "")); + copy.setContents(target.getInventory().getContents()); + player.openInventory(copy); + plugin.getMessageUtil().send(player, "messages.inventory-opened", "%player%", target.getName()); + } + + case NAME_TAG -> { + if (targetUuid.equals(guild.getOwner())) { + return; + } + + String current = guild.getRank(targetUuid).toUpperCase(); + String next = switch (current) { + case "MEMBER" -> "MOD"; + case "MOD" -> "ADMIN"; + case "ADMIN" -> "MEMBER"; + default -> "MEMBER"; + }; + + plugin.getGuildManager().setMemberRank(guild, targetUuid, next); + OfflinePlayer target = Bukkit.getOfflinePlayer(targetUuid); + String name = target.getName() == null ? targetUuid.toString() : target.getName(); + plugin.getMessageUtil().send(player, "messages.rank-updated", "%player%", name, "%rank%", next); + new GuildMemberManageMenu(plugin).open(player, guild, targetUuid); + } + + case BARRIER -> { + if (targetUuid.equals(guild.getOwner())) { + return; + } + + plugin.getGuildManager().removeMember(guild, targetUuid); + selectedMemberTargets.remove(player.getUniqueId()); + new GuildMembersMenu(plugin).open(player, guild); + } + + case ARROW -> new GuildMembersMenu(plugin).open(player, guild); + + default -> { + } + } + } + + private void handleBankMenuClick(InventoryClickEvent event, Player player) { + event.setCancelled(true); + + if (event.getCurrentItem() == null || event.getCurrentItem().getType().isAir()) { + return; + } + + Guild guild = plugin.getGuildManager().getGuildByPlayer(player.getUniqueId()); + if (guild == null) { + player.closeInventory(); + return; + } + + switch (event.getCurrentItem().getType()) { + case LIME_DYE -> { + player.closeInventory(); + player.performCommand("guild bank deposit 100"); + } + case RED_DYE -> { + player.closeInventory(); + player.performCommand("guild bank withdraw 100"); + } + case ARROW -> new GuildMainMenu(plugin).open(player); + default -> { + } + } + } + + private void handleVaultMenuClick(InventoryClickEvent event) { + // Guild vault should be editable, so do not cancel. + } + + private void handleLevelsMenuClick(InventoryClickEvent event, Player player) { + event.setCancelled(true); + + if (event.getCurrentItem() == null || event.getCurrentItem().getType().isAir()) { + return; + } + + Guild guild = plugin.getGuildManager().getGuildByPlayer(player.getUniqueId()); + if (guild == null) { + player.closeInventory(); + return; + } + + switch (event.getCurrentItem().getType()) { + case EMERALD -> { + if (!guild.canManage(player.getUniqueId()) && !guild.getOwner().equals(player.getUniqueId())) { + plugin.getMessageUtil().send(player, "messages.no-permission"); + return; + } + + int oldLevel = guild.getLevel(); + boolean success = plugin.getGuildManager().upgradeLevel(guild); + + if (!success) { + if (oldLevel >= plugin.getGuildManager().getMaxConfiguredLevel()) { + plugin.getMessageUtil().send(player, "messages.level-maxed"); + } else { + plugin.getMessageUtil().send(player, "messages.level-not-enough-money"); + } + return; + } + + plugin.getMessageUtil().send(player, "messages.level-upgraded", "%level%", String.valueOf(guild.getLevel())); + new GuildLevelsMenu(plugin).open(player, guild); + } + case ARROW -> new GuildMainMenu(plugin).open(player); + default -> { + } + } + } + + private UUID extractUuidFromItem(ItemMeta meta) { + if (meta == null || meta.lore() == null) { + return null; + } + + List loreLines = meta.lore().stream().map(plainText::serialize).toList(); + for (String line : loreLines) { + if (line.startsWith("UUID:")) { + try { + return UUID.fromString(line.substring("UUID:".length()).trim()); + } catch (IllegalArgumentException ignored) { + return null; + } + } + } + return null; + } + + private String title(String path, String fallback) { + return plainText.serialize(MessageUtil.mm(plugin.getConfig().getString(path, fallback))); + } +} diff --git a/src/main/java/com/bitnix/dirtguilds/listener/GuildFriendlyFireListener.java b/src/main/java/com/bitnix/dirtguilds/listener/GuildFriendlyFireListener.java new file mode 100644 index 0000000..b689dc4 --- /dev/null +++ b/src/main/java/com/bitnix/dirtguilds/listener/GuildFriendlyFireListener.java @@ -0,0 +1,50 @@ +package com.bitnix.dirtguilds.listener; + +import com.bitnix.dirtguilds.DirtGuildsPlugin; +import com.bitnix.dirtguilds.guild.Guild; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; + +public class GuildFriendlyFireListener implements Listener { + + private final DirtGuildsPlugin plugin; + + public GuildFriendlyFireListener(DirtGuildsPlugin plugin) { + this.plugin = plugin; + } + + @EventHandler + public void onDamage(EntityDamageByEntityEvent event) { + Player attacker = getPlayer(event.getDamager()); + Player victim = getPlayer(event.getEntity()); + + if (attacker == null || victim == null) { + return; + } + + Guild attackerGuild = plugin.getGuildManager().getGuildByPlayer(attacker.getUniqueId()); + Guild victimGuild = plugin.getGuildManager().getGuildByPlayer(victim.getUniqueId()); + + if (attackerGuild == null || victimGuild == null) { + return; + } + + if (!attackerGuild.getId().equals(victimGuild.getId())) { + return; + } + + if (!attackerGuild.isFriendlyFire()) { + event.setCancelled(true); + } + } + + private Player getPlayer(Entity entity) { + if (entity instanceof Player player) { + return player; + } + return null; + } +} diff --git a/src/main/java/com/bitnix/dirtguilds/util/MessageUtil.java b/src/main/java/com/bitnix/dirtguilds/util/MessageUtil.java new file mode 100644 index 0000000..88d4afe --- /dev/null +++ b/src/main/java/com/bitnix/dirtguilds/util/MessageUtil.java @@ -0,0 +1,50 @@ +package com.bitnix.dirtguilds.util; + +import com.bitnix.dirtguilds.DirtGuildsPlugin; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.command.CommandSender; + +public class MessageUtil { + + private static final MiniMessage MINI_MESSAGE = MiniMessage.miniMessage(); + + private final DirtGuildsPlugin plugin; + + public MessageUtil(DirtGuildsPlugin plugin) { + this.plugin = plugin; + } + + public static Component mm(String text) { + if (text == null) { + text = ""; + } + return MINI_MESSAGE.deserialize(text); + } + + public Component parse(String text) { + return mm(text); + } + + public String raw(String path) { + return plugin.getConfig().getString(path, ""); + } + + public String format(String path, String... replacements) { + String text = raw(path); + + for (int i = 0; i + 1 < replacements.length; i += 2) { + text = text.replace(replacements[i], replacements[i + 1]); + } + + return raw("messages.prefix") + text; + } + + public void send(CommandSender sender, String path, String... replacements) { + sender.sendMessage(parse(format(path, replacements))); + } + + public void sendRaw(CommandSender sender, String text) { + sender.sendMessage(parse(text)); + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..b4d4844 --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,123 @@ +database: + type: SQLITE # SQLITE or MYSQL + + sqlite: + file: guilds.db + + mysql: + host: localhost + port: 3306 + database: dirtguilds + username: root + password: change-me + properties: "?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC" + +settings: + invite-expire-seconds: 120 + default-friendly-fire: false + max-name-length: 16 + min-name-length: 3 + + bank: + enabled: true + use-vault: true + + vault: + default-size: 9 + max-size: 54 + + levels: + enabled: true + default-level: 1 + levels: + 1: + cost: 0 + vault-slots: 9 + 2: + cost: 1000 + vault-slots: 18 + 3: + cost: 5000 + vault-slots: 27 + 4: + cost: 15000 + vault-slots: 36 + 5: + cost: 50000 + vault-slots: 54 + +messages: + prefix: "[DirtGuilds] " + + no-permission: "You do not have permission." + players-only: "Only players may use this command." + unknown-command: "Unknown subcommand." + reload: "DirtGuilds reloaded." + prefix-updated: "Guild prefix updated." + + guild-created: "Guild %guild% created." + guild-deleted: "Guild %guild% deleted." + guild-renamed: "Guild renamed to %guild%." + joined-guild: "You joined %guild%." + left-guild: "You left your guild." + already-in-guild: "You are already in a guild." + not-in-guild: "You are not in a guild." + guild-not-found: "Guild not found." + player-not-found: "Player not found." + invite-sent: "Invite sent to %player%." + invite-received: "You were invited to join %guild%. Use /guild accept %guild%." + no-invite: "You do not have an invite for that guild." + member-joined: "%player% joined the guild." + member-left: "%player% left the guild." + invalid-name: "That guild name is invalid." + name-taken: "That guild name is already taken." + must-be-owner: "You must be the guild owner." + must-be-in-guild: "You must be in a guild." + target-already-in-guild: "That player is already in a guild." + invite-expired: "That invite has expired." + friendly-fire-enabled: "Guild friendly fire enabled." + friendly-fire-disabled: "Guild friendly fire disabled." + guild-chat-enabled: "Guild chat enabled." + guild-chat-disabled: "Guild chat disabled." + + bank-deposit: "Deposited %amount% to guild bank." + bank-withdraw: "Withdrew %amount% from guild bank." + bank-invalid-amount: "Invalid amount." + bank-insufficient-funds: "Your guild bank does not have enough funds." + bank-player-insufficient-funds: "You do not have enough money." + bank-vault-unavailable: "Vault economy is not available." + + level-upgraded: "Your guild upgraded to level %level%." + level-maxed: "Your guild is already at max level." + level-not-enough-money: "Your guild bank does not have enough money to level up." + + teleport-success: "Teleported to %player%." + teleport-offline: "That member is offline." + inventory-opened: "Opened inventory of %player%." + + rank-updated: "Updated rank for %player% to %rank%." + +gui: + main: + title: "DirtGuilds" + size: 27 + + members: + title: "Guild Members" + size: 54 + + member-manage: + title: "Manage Member" + size: 27 + + bank: + title: "Guild Bank" + size: 27 + + vault: + title: "Guild Vault" + size: 54 + + levels: + title: "Guild Levels" + size: 27 diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..0251798 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,22 @@ +name: DirtGuilds +version: 1.0.0 +main: com.bitnix.dirtguilds.DirtGuildsPlugin +api-version: '1.21' +authors: [bitnix] +description: GUI-driven guilds plugin for Paper +softdepend: [PlaceholderAPI, Vault] + +commands: + dirtguilds: + description: Main DirtGuilds command + usage: /dirtguilds + aliases: [dg, guild, guilds] + +permissions: + dirtguilds.use: + description: Allows use of DirtGuilds + default: true + + dirtguilds.admin: + description: DirtGuilds admin permission + default: op diff --git a/target/DirtGuilds.jar b/target/DirtGuilds.jar new file mode 100644 index 0000000..2f61ac0 Binary files /dev/null and b/target/DirtGuilds.jar differ diff --git a/target/classes/com/bitnix/dirtguilds/DirtGuildsPlugin.class b/target/classes/com/bitnix/dirtguilds/DirtGuildsPlugin.class new file mode 100644 index 0000000..8b04cde Binary files /dev/null and b/target/classes/com/bitnix/dirtguilds/DirtGuildsPlugin.class differ diff --git a/target/classes/com/bitnix/dirtguilds/command/DirtGuildsCommand.class b/target/classes/com/bitnix/dirtguilds/command/DirtGuildsCommand.class new file mode 100644 index 0000000..5bd3b65 Binary files /dev/null and b/target/classes/com/bitnix/dirtguilds/command/DirtGuildsCommand.class differ diff --git a/target/classes/com/bitnix/dirtguilds/data/DatabaseManager.class b/target/classes/com/bitnix/dirtguilds/data/DatabaseManager.class new file mode 100644 index 0000000..fb36dba Binary files /dev/null and b/target/classes/com/bitnix/dirtguilds/data/DatabaseManager.class differ diff --git a/target/classes/com/bitnix/dirtguilds/gui/GuildBankMenu.class b/target/classes/com/bitnix/dirtguilds/gui/GuildBankMenu.class new file mode 100644 index 0000000..a1b4513 Binary files /dev/null and b/target/classes/com/bitnix/dirtguilds/gui/GuildBankMenu.class differ diff --git a/target/classes/com/bitnix/dirtguilds/gui/GuildLevelsMenu.class b/target/classes/com/bitnix/dirtguilds/gui/GuildLevelsMenu.class new file mode 100644 index 0000000..d456e32 Binary files /dev/null and b/target/classes/com/bitnix/dirtguilds/gui/GuildLevelsMenu.class differ diff --git a/target/classes/com/bitnix/dirtguilds/gui/GuildMainMenu.class b/target/classes/com/bitnix/dirtguilds/gui/GuildMainMenu.class new file mode 100644 index 0000000..ffb3f7e Binary files /dev/null and b/target/classes/com/bitnix/dirtguilds/gui/GuildMainMenu.class differ diff --git a/target/classes/com/bitnix/dirtguilds/gui/GuildMemberManageMenu.class b/target/classes/com/bitnix/dirtguilds/gui/GuildMemberManageMenu.class new file mode 100644 index 0000000..9cbf5df Binary files /dev/null and b/target/classes/com/bitnix/dirtguilds/gui/GuildMemberManageMenu.class differ diff --git a/target/classes/com/bitnix/dirtguilds/gui/GuildMembersMenu.class b/target/classes/com/bitnix/dirtguilds/gui/GuildMembersMenu.class new file mode 100644 index 0000000..b4836ae Binary files /dev/null and b/target/classes/com/bitnix/dirtguilds/gui/GuildMembersMenu.class differ diff --git a/target/classes/com/bitnix/dirtguilds/gui/GuildVaultMenu.class b/target/classes/com/bitnix/dirtguilds/gui/GuildVaultMenu.class new file mode 100644 index 0000000..41275ce Binary files /dev/null and b/target/classes/com/bitnix/dirtguilds/gui/GuildVaultMenu.class differ diff --git a/target/classes/com/bitnix/dirtguilds/guild/Guild.class b/target/classes/com/bitnix/dirtguilds/guild/Guild.class new file mode 100644 index 0000000..903e86a Binary files /dev/null and b/target/classes/com/bitnix/dirtguilds/guild/Guild.class differ diff --git a/target/classes/com/bitnix/dirtguilds/guild/GuildInvite.class b/target/classes/com/bitnix/dirtguilds/guild/GuildInvite.class new file mode 100644 index 0000000..bb172cd Binary files /dev/null and b/target/classes/com/bitnix/dirtguilds/guild/GuildInvite.class differ diff --git a/target/classes/com/bitnix/dirtguilds/guild/GuildManager.class b/target/classes/com/bitnix/dirtguilds/guild/GuildManager.class new file mode 100644 index 0000000..78d3faf Binary files /dev/null and b/target/classes/com/bitnix/dirtguilds/guild/GuildManager.class differ diff --git a/target/classes/com/bitnix/dirtguilds/hook/EconomyHook.class b/target/classes/com/bitnix/dirtguilds/hook/EconomyHook.class new file mode 100644 index 0000000..18c81c6 Binary files /dev/null and b/target/classes/com/bitnix/dirtguilds/hook/EconomyHook.class differ diff --git a/target/classes/com/bitnix/dirtguilds/listener/ChatListener.class b/target/classes/com/bitnix/dirtguilds/listener/ChatListener.class new file mode 100644 index 0000000..5bf13b8 Binary files /dev/null and b/target/classes/com/bitnix/dirtguilds/listener/ChatListener.class differ diff --git a/target/classes/com/bitnix/dirtguilds/listener/GuiListener$1.class b/target/classes/com/bitnix/dirtguilds/listener/GuiListener$1.class new file mode 100644 index 0000000..23bfc9f Binary files /dev/null and b/target/classes/com/bitnix/dirtguilds/listener/GuiListener$1.class differ diff --git a/target/classes/com/bitnix/dirtguilds/listener/GuiListener.class b/target/classes/com/bitnix/dirtguilds/listener/GuiListener.class new file mode 100644 index 0000000..1ccbc6d Binary files /dev/null and b/target/classes/com/bitnix/dirtguilds/listener/GuiListener.class differ diff --git a/target/classes/com/bitnix/dirtguilds/listener/GuildFriendlyFireListener.class b/target/classes/com/bitnix/dirtguilds/listener/GuildFriendlyFireListener.class new file mode 100644 index 0000000..1583414 Binary files /dev/null and b/target/classes/com/bitnix/dirtguilds/listener/GuildFriendlyFireListener.class differ diff --git a/target/classes/com/bitnix/dirtguilds/util/MessageUtil.class b/target/classes/com/bitnix/dirtguilds/util/MessageUtil.class new file mode 100644 index 0000000..3fda9f7 Binary files /dev/null and b/target/classes/com/bitnix/dirtguilds/util/MessageUtil.class differ diff --git a/target/classes/config.yml b/target/classes/config.yml new file mode 100644 index 0000000..b4d4844 --- /dev/null +++ b/target/classes/config.yml @@ -0,0 +1,123 @@ +database: + type: SQLITE # SQLITE or MYSQL + + sqlite: + file: guilds.db + + mysql: + host: localhost + port: 3306 + database: dirtguilds + username: root + password: change-me + properties: "?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC" + +settings: + invite-expire-seconds: 120 + default-friendly-fire: false + max-name-length: 16 + min-name-length: 3 + + bank: + enabled: true + use-vault: true + + vault: + default-size: 9 + max-size: 54 + + levels: + enabled: true + default-level: 1 + levels: + 1: + cost: 0 + vault-slots: 9 + 2: + cost: 1000 + vault-slots: 18 + 3: + cost: 5000 + vault-slots: 27 + 4: + cost: 15000 + vault-slots: 36 + 5: + cost: 50000 + vault-slots: 54 + +messages: + prefix: "[DirtGuilds] " + + no-permission: "You do not have permission." + players-only: "Only players may use this command." + unknown-command: "Unknown subcommand." + reload: "DirtGuilds reloaded." + prefix-updated: "Guild prefix updated." + + guild-created: "Guild %guild% created." + guild-deleted: "Guild %guild% deleted." + guild-renamed: "Guild renamed to %guild%." + joined-guild: "You joined %guild%." + left-guild: "You left your guild." + already-in-guild: "You are already in a guild." + not-in-guild: "You are not in a guild." + guild-not-found: "Guild not found." + player-not-found: "Player not found." + invite-sent: "Invite sent to %player%." + invite-received: "You were invited to join %guild%. Use /guild accept %guild%." + no-invite: "You do not have an invite for that guild." + member-joined: "%player% joined the guild." + member-left: "%player% left the guild." + invalid-name: "That guild name is invalid." + name-taken: "That guild name is already taken." + must-be-owner: "You must be the guild owner." + must-be-in-guild: "You must be in a guild." + target-already-in-guild: "That player is already in a guild." + invite-expired: "That invite has expired." + friendly-fire-enabled: "Guild friendly fire enabled." + friendly-fire-disabled: "Guild friendly fire disabled." + guild-chat-enabled: "Guild chat enabled." + guild-chat-disabled: "Guild chat disabled." + + bank-deposit: "Deposited %amount% to guild bank." + bank-withdraw: "Withdrew %amount% from guild bank." + bank-invalid-amount: "Invalid amount." + bank-insufficient-funds: "Your guild bank does not have enough funds." + bank-player-insufficient-funds: "You do not have enough money." + bank-vault-unavailable: "Vault economy is not available." + + level-upgraded: "Your guild upgraded to level %level%." + level-maxed: "Your guild is already at max level." + level-not-enough-money: "Your guild bank does not have enough money to level up." + + teleport-success: "Teleported to %player%." + teleport-offline: "That member is offline." + inventory-opened: "Opened inventory of %player%." + + rank-updated: "Updated rank for %player% to %rank%." + +gui: + main: + title: "DirtGuilds" + size: 27 + + members: + title: "Guild Members" + size: 54 + + member-manage: + title: "Manage Member" + size: 27 + + bank: + title: "Guild Bank" + size: 27 + + vault: + title: "Guild Vault" + size: 54 + + levels: + title: "Guild Levels" + size: 27 diff --git a/target/classes/plugin.yml b/target/classes/plugin.yml new file mode 100644 index 0000000..0251798 --- /dev/null +++ b/target/classes/plugin.yml @@ -0,0 +1,22 @@ +name: DirtGuilds +version: 1.0.0 +main: com.bitnix.dirtguilds.DirtGuildsPlugin +api-version: '1.21' +authors: [bitnix] +description: GUI-driven guilds plugin for Paper +softdepend: [PlaceholderAPI, Vault] + +commands: + dirtguilds: + description: Main DirtGuilds command + usage: /dirtguilds + aliases: [dg, guild, guilds] + +permissions: + dirtguilds.use: + description: Allows use of DirtGuilds + default: true + + dirtguilds.admin: + description: DirtGuilds admin permission + default: op diff --git a/target/maven-archiver/pom.properties b/target/maven-archiver/pom.properties new file mode 100644 index 0000000..e59999b --- /dev/null +++ b/target/maven-archiver/pom.properties @@ -0,0 +1,5 @@ +#Generated by Maven +#Mon Jun 08 18:24:37 EDT 2026 +artifactId=DirtGuilds +groupId=com.bitnix +version=1.0.0 diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..52df0e8 --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1,18 @@ +com/bitnix/dirtguilds/util/MessageUtil.class +com/bitnix/dirtguilds/DirtGuildsPlugin.class +com/bitnix/dirtguilds/command/DirtGuildsCommand.class +com/bitnix/dirtguilds/listener/GuiListener.class +com/bitnix/dirtguilds/listener/GuiListener$1.class +com/bitnix/dirtguilds/gui/GuildBankMenu.class +com/bitnix/dirtguilds/listener/GuildFriendlyFireListener.class +com/bitnix/dirtguilds/gui/GuildLevelsMenu.class +com/bitnix/dirtguilds/gui/GuildMembersMenu.class +com/bitnix/dirtguilds/gui/GuildMainMenu.class +com/bitnix/dirtguilds/guild/GuildInvite.class +com/bitnix/dirtguilds/data/DatabaseManager.class +com/bitnix/dirtguilds/gui/GuildVaultMenu.class +com/bitnix/dirtguilds/hook/EconomyHook.class +com/bitnix/dirtguilds/gui/GuildMemberManageMenu.class +com/bitnix/dirtguilds/guild/Guild.class +com/bitnix/dirtguilds/listener/ChatListener.class +com/bitnix/dirtguilds/guild/GuildManager.class diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..b4ac347 --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,17 @@ +/home/bitnix/Desktop/DirtGuilds/src/main/java/com/bitnix/dirtguilds/DirtGuildsPlugin.java +/home/bitnix/Desktop/DirtGuilds/src/main/java/com/bitnix/dirtguilds/command/DirtGuildsCommand.java +/home/bitnix/Desktop/DirtGuilds/src/main/java/com/bitnix/dirtguilds/data/DatabaseManager.java +/home/bitnix/Desktop/DirtGuilds/src/main/java/com/bitnix/dirtguilds/gui/GuildBankMenu.java +/home/bitnix/Desktop/DirtGuilds/src/main/java/com/bitnix/dirtguilds/gui/GuildLevelsMenu.java +/home/bitnix/Desktop/DirtGuilds/src/main/java/com/bitnix/dirtguilds/gui/GuildMainMenu.java +/home/bitnix/Desktop/DirtGuilds/src/main/java/com/bitnix/dirtguilds/gui/GuildMemberManageMenu.java +/home/bitnix/Desktop/DirtGuilds/src/main/java/com/bitnix/dirtguilds/gui/GuildMembersMenu.java +/home/bitnix/Desktop/DirtGuilds/src/main/java/com/bitnix/dirtguilds/gui/GuildVaultMenu.java +/home/bitnix/Desktop/DirtGuilds/src/main/java/com/bitnix/dirtguilds/guild/Guild.java +/home/bitnix/Desktop/DirtGuilds/src/main/java/com/bitnix/dirtguilds/guild/GuildInvite.java +/home/bitnix/Desktop/DirtGuilds/src/main/java/com/bitnix/dirtguilds/guild/GuildManager.java +/home/bitnix/Desktop/DirtGuilds/src/main/java/com/bitnix/dirtguilds/hook/EconomyHook.java +/home/bitnix/Desktop/DirtGuilds/src/main/java/com/bitnix/dirtguilds/listener/ChatListener.java +/home/bitnix/Desktop/DirtGuilds/src/main/java/com/bitnix/dirtguilds/listener/GuiListener.java +/home/bitnix/Desktop/DirtGuilds/src/main/java/com/bitnix/dirtguilds/listener/GuildFriendlyFireListener.java +/home/bitnix/Desktop/DirtGuilds/src/main/java/com/bitnix/dirtguilds/util/MessageUtil.java diff --git a/target/original-DirtGuilds.jar b/target/original-DirtGuilds.jar new file mode 100644 index 0000000..9aa1e89 Binary files /dev/null and b/target/original-DirtGuilds.jar differ