From 8dc456c43e67969dad9971171eab16d15bfaddae Mon Sep 17 00:00:00 2001 From: Focusvity Date: Wed, 6 Mar 2024 22:28:16 +1100 Subject: [PATCH] [WIP] Current progress --- src/main/java/dev/plex/Guilds.java | 57 ++- src/main/java/dev/plex/SQLManager.java | 474 ++++++++++++++++++ .../java/dev/plex/command/GuildCommand.java | 136 ++--- .../java/dev/plex/command/SubCommand.java | 35 ++ .../dev/plex/command/sub/ChatSubCommand.java | 60 --- .../plex/command/sub/CreateSubCommand.java | 57 ++- .../command/sub/DeleteWarpSubCommand.java | 65 +++ .../plex/command/sub/DisbandSubCommand.java | 59 +++ .../dev/plex/command/sub/HomeSubCommand.java | 44 +- .../dev/plex/command/sub/InfoSubCommand.java | 120 +++-- .../plex/command/sub/InviteSubCommand.java | 140 ------ .../dev/plex/command/sub/LeaveSubCommand.java | 69 +++ .../dev/plex/command/sub/MotdSubCommand.java | 74 +++ .../dev/plex/command/sub/OwnerSubCommand.java | 69 --- .../plex/command/sub/PrefixSubCommand.java | 62 +-- .../plex/command/sub/SetHomeSubCommand.java | 73 +-- .../plex/command/sub/SetOwnerSubCommand.java | 65 +++ .../plex/command/sub/SetWarpSubCommand.java | 81 ++- .../plex/command/sub/WarpListSubCommand.java | 62 --- .../dev/plex/command/sub/WarpSubCommand.java | 62 ++- src/main/java/dev/plex/data/GuildData.java | 45 ++ src/main/java/dev/plex/data/MemberData.java | 54 ++ .../java/dev/plex/data/SQLGuildManager.java | 162 ------ src/main/java/dev/plex/data/SQLManager.java | 39 -- src/main/java/dev/plex/guild/Guild.java | 239 +++++++-- src/main/java/dev/plex/guild/GuildHolder.java | 51 -- src/main/java/dev/plex/guild/GuildMember.java | 28 ++ src/main/java/dev/plex/guild/GuildRank.java | 29 ++ src/main/java/dev/plex/guild/GuildWarp.java | 11 + src/main/java/dev/plex/guild/data/Member.java | 20 - .../java/dev/plex/guild/data/Permission.java | 6 - src/main/java/dev/plex/guild/data/Rank.java | 5 - .../dev/plex/handler/ChatHandlerImpl.java | 96 ---- .../java/dev/plex/listener/ChatListener.java | 80 +++ .../java/dev/plex/listener/JoinListener.java | 31 ++ .../java/dev/plex/util/CustomLocation.java | 23 - src/main/java/dev/plex/util/GuildUtil.java | 14 - 37 files changed, 1677 insertions(+), 1120 deletions(-) create mode 100644 src/main/java/dev/plex/SQLManager.java create mode 100644 src/main/java/dev/plex/command/SubCommand.java delete mode 100644 src/main/java/dev/plex/command/sub/ChatSubCommand.java create mode 100644 src/main/java/dev/plex/command/sub/DeleteWarpSubCommand.java create mode 100644 src/main/java/dev/plex/command/sub/DisbandSubCommand.java delete mode 100644 src/main/java/dev/plex/command/sub/InviteSubCommand.java create mode 100644 src/main/java/dev/plex/command/sub/LeaveSubCommand.java create mode 100644 src/main/java/dev/plex/command/sub/MotdSubCommand.java delete mode 100644 src/main/java/dev/plex/command/sub/OwnerSubCommand.java create mode 100644 src/main/java/dev/plex/command/sub/SetOwnerSubCommand.java delete mode 100644 src/main/java/dev/plex/command/sub/WarpListSubCommand.java create mode 100644 src/main/java/dev/plex/data/GuildData.java create mode 100644 src/main/java/dev/plex/data/MemberData.java delete mode 100644 src/main/java/dev/plex/data/SQLGuildManager.java delete mode 100644 src/main/java/dev/plex/data/SQLManager.java delete mode 100644 src/main/java/dev/plex/guild/GuildHolder.java create mode 100644 src/main/java/dev/plex/guild/GuildMember.java create mode 100644 src/main/java/dev/plex/guild/GuildRank.java create mode 100644 src/main/java/dev/plex/guild/GuildWarp.java delete mode 100644 src/main/java/dev/plex/guild/data/Member.java delete mode 100644 src/main/java/dev/plex/guild/data/Permission.java delete mode 100644 src/main/java/dev/plex/guild/data/Rank.java delete mode 100644 src/main/java/dev/plex/handler/ChatHandlerImpl.java create mode 100644 src/main/java/dev/plex/listener/ChatListener.java create mode 100644 src/main/java/dev/plex/listener/JoinListener.java delete mode 100644 src/main/java/dev/plex/util/CustomLocation.java delete mode 100644 src/main/java/dev/plex/util/GuildUtil.java diff --git a/src/main/java/dev/plex/Guilds.java b/src/main/java/dev/plex/Guilds.java index 7be02f8..89f9da7 100644 --- a/src/main/java/dev/plex/Guilds.java +++ b/src/main/java/dev/plex/Guilds.java @@ -2,21 +2,22 @@ package dev.plex; import dev.plex.command.GuildCommand; import dev.plex.config.ModuleConfig; -import dev.plex.data.SQLGuildManager; -import dev.plex.data.SQLManager; -import dev.plex.guild.GuildHolder; +import dev.plex.data.GuildData; +import dev.plex.data.MemberData; +import dev.plex.listener.ChatListener; +import dev.plex.listener.JoinListener; import dev.plex.module.PlexModule; import dev.plex.util.PlexLog; import lombok.Getter; +import org.bukkit.Bukkit; @Getter public class Guilds extends PlexModule { private static Guilds module; - private final GuildHolder guildHolder = new GuildHolder(); - - private SQLGuildManager sqlGuildManager; - + private final SQLManager sqlManager = new SQLManager(); + private final GuildData guildData = new GuildData(); + private final MemberData memberData = new MemberData(); private ModuleConfig config; @Override @@ -30,38 +31,37 @@ public class Guilds extends PlexModule @Override public void enable() { - SQLManager.makeTables(); - sqlGuildManager = new SQLGuildManager(); - sqlGuildManager.getGuilds().whenComplete((guilds, throwable) -> - { - PlexLog.debug("Finished loading {0} guilds", guilds.size()); - guilds.forEach(guildHolder::addGuild); - this.registerCommand(new GuildCommand()); - }); - - //Plex.get().setChat(new ChatHandlerImpl()); - addDefaultMessage("guildsHelpCommand", "======Guild Menu======{0}", "0 - The commands list"); addDefaultMessage("guildsCommandDisplay", "{0} {1}", "0 - The command name", "1 - The command description"); addDefaultMessage("guildCommandNotFound", "'{0}' is not a valid sub command!", "0 - The sub command"); addDefaultMessage("guildNotFound", "You're currently not a part of a guild!"); + addDefaultMessage("guildNotExist", "A guild doesn't exist with the name '{0}'", "0 - Name used to find a guild"); addDefaultMessage("guildInThis", "You're currently a part of this guild!"); addDefaultMessage("alreadyInGuild", "You're currently in a guild. Please do /guild leave if you're a member, or if you're an owner with members, /guild promote then /guild leave, or just an owner, /guild disband."); addDefaultMessage("guildNotOwner", "You're not the owner of this guild!"); + addDefaultMessage("guildNotMod", "You're not a moderator of this guild!"); addDefaultMessage("guildMemberNotFound", "This guild member could not be found!"); + addDefaultMessage("guildAlphanumericName", "Guild names may only be alphanumeric!"); addDefaultMessage("guildOwnerSet", "You have successfully promoted {0} to be the new guild owner. You have been set to a default guild member."); addDefaultMessage("guildPrefixSet", "You have changed the guild prefix to '{0}'", "0 - The new prefix"); addDefaultMessage("guildPrefixCleared", "Your guild's prefix has been cleared."); + addDefaultMessage("guildMotdSet", "You have changed the guild prefix to '{0}'", "0 - The new MOTD"); + addDefaultMessage("guildMotdCleared", "Your guild's MOTD has been cleared."); + addDefaultMessage("guildMotdExceededLimit", "The MOTD character limit is 256 characters!"); + addDefaultMessage("guildWarpAlphanumeric", "Warp names may only contain alphabetical and/or numerical characters."); addDefaultMessage("guildWarpExists", "'{0}' is already an existing warp!", "0 - The warp name"); addDefaultMessage("guildWarpNotFound", "'{0}' is not a valid warp!", "0 - The warp name"); addDefaultMessage("guildWarpCreated", "You have created a warp called '{0}'", "0 - The warp name"); + addDefaultMessage("guildWarpSuccess", "You have warped to '{0}'", "0 - The warp name"); + addDefaultMessage("guildWarpRemoved", "You have removed the '{0}' warp!", "0 - The warp name"); addDefaultMessage("guildHomeRemoved", "You have removed the guild's home!"); addDefaultMessage("guildHomeSet", "You have changed the guild's home!"); addDefaultMessage("guildHomeNotFound", "This guild currently has no home set."); + addDefaultMessage("guildHomeTeleport", "You have teleported to the guild's home!"); addDefaultMessage("guildChatMessage", "[GUILD] {0} {1}", "0 - The player name", "1 - The message"); addDefaultMessage("guildChatToggled", "Your chat has been toggled {0}", "0 - On / Off"); @@ -74,20 +74,35 @@ public class Guilds extends PlexModule addDefaultMessage("guildInviteReceived", "You have received an invite from {0} for the guild {1}[ACCEPT]You may also run /guild invite accept {1} to accept this invite. It will expire in 5 minutes", "0 - The inviter", "1 - The guild name"); addDefaultMessage("guildMemberJoined", "{0} has joined the guild!", "0 - The player who joined"); addDefaultMessage("guildMemberLeft", "{0} has left the guild!", "0 - The player who left"); + addDefaultMessage("guildLeft", "Successfully left the guild"); addDefaultMessage("guildDisbandNeeded", "You need to disband your guild using /guild disband or promote a new owner using /guild owner "); + addDefaultMessage("guildDisbanded", "Your guild has been disbanded."); addDefaultMessage("guildAutoDisbanded", "Auto-disbanding your guild since there were no members"); + addDefaultMessage("guildActionConfirmation", "Are you sure you want to {0}? Type /guild {0} to confirm.", "0 - Action to confirm"); + + sqlManager.createTables(); + sqlManager.getMembers().forEach(memberData::addMember); + sqlManager.getGuilds().forEach(guildData::addGuild); + PlexLog.log("GUILD SIZE: {0}", guildData.getGuilds().size()); + registerListener(new JoinListener()); + registerListener(new ChatListener()); + registerCommand(new GuildCommand()); } @Override public void disable() { - // Unregistering listeners / commands is handled by Plex - this.getGuildHolder().getGuilds().forEach(sqlGuildManager::updateGuild); - //this.getPlex().setChat(new ChatListener.PlexChatRenderer()); + guildData.getGuilds().forEach(sqlManager::updateGuild); + memberData.getMembers().forEach(sqlManager::updateMember); } public static Guilds get() { return module; } + + public static void logException(Throwable t) + { + Bukkit.getScheduler().runTask(get().getPlex(), () -> t.printStackTrace()); + } } diff --git a/src/main/java/dev/plex/SQLManager.java b/src/main/java/dev/plex/SQLManager.java new file mode 100644 index 0000000..09e4afe --- /dev/null +++ b/src/main/java/dev/plex/SQLManager.java @@ -0,0 +1,474 @@ +package dev.plex; + +import com.google.common.collect.Lists; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import dev.plex.guild.Guild; +import dev.plex.guild.GuildMember; +import dev.plex.guild.GuildRank; +import dev.plex.guild.GuildWarp; +import dev.plex.util.PlexLog; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import java.sql.*; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +public class SQLManager +{ + private final Gson GSON = new Gson(); + private final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private final String SELECT_ALL_GUILDS = "select * from guild"; + private final String INSERT_GUILD = "insert into guild (uuid, name, owner_id) values (?, ?, ?)"; + private final String UPDATE_GUILD = "update guild set name = ?, display_name = ?, owner_id = ?, prefix = ?, prefix_enabled = ?, home = ?, motd = ?, privacy = ?, members = ?, moderators = ?, default_rank = ? where uuid = ?"; + private final String DELETE_GUILD_UUID = "delete from guild where uuid = ?"; + private final String DELETE_GUILD_OWNER = "delete from guild where owner_id = ?"; + private final String UPDATE_MEMBER = "update member set chat = ?, prefix = ? where player_uuid = ?"; + private final String[] CREATE_TABLES = new String[] + { + """ + create table if not exists guild ( + uuid varchar(46) primary key, + name text not null, + display_name varchar, + owner_id int not null, + created_at datetime not null default current_timestamp, + prefix varchar(3000), + prefix_enabled boolean default false, + home varchar, + motd varchar, + privacy not null default 'PUBLIC', + members varchar, + moderators varchar, + default_rank text + );""", + """ + create table if not exists member ( + id int auto_increment primary key, + player_uuid varchar(46) not null, + chat boolean default false, + prefix boolean default true + );""", + """ + create table if not exists rank ( + name text not null, + members varchar, + guild_uuid varchar(46) not null + );""", + """ + create table if not exists warp ( + name text not null, + location text not null, + guild_uuid varchar(46) not null + ); + """ + }; + + public void createTables() + { + try (Connection connection = Plex.get().getSqlConnection().getCon()) + { + Arrays.stream(CREATE_TABLES).forEach(table -> + { + try + { + connection.prepareStatement(table).execute(); + } + catch (SQLException ex) + { + Guilds.logException(ex); + } + }); + } + catch (SQLException ex) + { + Guilds.logException(ex); + } + } + + public CompletableFuture insertMember(GuildMember member) + { + return CompletableFuture.supplyAsync(() -> + { + try (Connection connection = Plex.get().getSqlConnection().getCon()) + { + PreparedStatement statement = connection.prepareStatement("insert into member (player_uuid) values (?)"); + statement.setString(1, member.getUuid().toString()); + statement.execute(); + PreparedStatement getId = connection.prepareStatement("select id from member where player_uuid = ?"); + getId.setString(1, member.getUuid().toString()); + ResultSet set = getId.executeQuery(); + if (set.next()) + { + member.setId(set.getInt("id")); + } + else + { + throw new RuntimeException("Missing member id for %s".formatted(member.getPlayer().getName())); + } + return member; + } + catch (SQLException ex) + { + Guilds.logException(ex); + return null; + } + }); + } + + public void insertGuild(Guild guild) + { + CompletableFuture.runAsync(() -> + { + try (Connection connection = Plex.get().getSqlConnection().getCon()) + { + PreparedStatement statement = connection.prepareStatement(INSERT_GUILD); + statement.setString(1, guild.getUuid().toString()); + statement.setString(2, guild.getName()); + statement.setInt(3, guild.getOwner().getId()); + statement.execute(); + } + catch (SQLException ex) + { + Guilds.logException(ex); + } + }); + } + + public void insertWarp(Guild guild, GuildWarp warp) + { + CompletableFuture.runAsync(() -> + { + try (Connection connection = Plex.get().getSqlConnection().getCon()) + { + PreparedStatement statement = connection.prepareStatement("insert into warp values (?, ?, ?)"); + statement.setString(1, warp.getName()); + String location = GSON.toJson(warp.getLocation().serialize(), new TypeToken>() + { + }.getType()); + statement.setString(2, location); + statement.setString(3, guild.getUuid().toString()); + statement.execute(); + } + catch (SQLException ex) + { + Guilds.logException(ex); + } + }); + } + + public void deleteWarp(Guild guild, GuildWarp warp) + { + CompletableFuture.runAsync(() -> + { + try (Connection connection = Plex.get().getSqlConnection().getCon()) + { + PreparedStatement statement = connection.prepareStatement("delete from warp where name = ? and guild_uuid = ?"); + statement.setString(1, warp.getName()); + statement.setString(2, guild.getUuid().toString()); + statement.execute(); + } + catch (SQLException ex) + { + Guilds.logException(ex); + } + }); + } + + public void insertRank(Guild guild, GuildRank rank) + { + CompletableFuture.runAsync(() -> + { + try (Connection connection = Plex.get().getSqlConnection().getCon()) + { + PreparedStatement statement = connection.prepareStatement("insert into rank (name, guild_uuid) values (?, ?)"); + statement.setString(1, rank.getName()); + statement.setString(2, guild.getUuid().toString()); + statement.execute(); + } + catch (SQLException ex) + { + Guilds.logException(ex); + } + }); + } + + public void deleteRank(Guild guild, GuildRank rank) + { + CompletableFuture.runAsync(() -> + { + try (Connection connection = Plex.get().getSqlConnection().getCon()) + { + PreparedStatement statement = connection.prepareStatement("delete from rank where name = ? and guild_uuid = ?"); + statement.setString(1, rank.getName()); + statement.setString(2, guild.getUuid().toString()); + statement.execute(); + } + catch (SQLException ex) + { + Guilds.logException(ex); + } + }); + } + + public void updateDefaultRank(Guild guild, GuildRank rank) + { + CompletableFuture.runAsync(() -> + { + try (Connection connection = Plex.get().getSqlConnection().getCon()) + { + PreparedStatement statement = connection.prepareStatement("update guild set default_rank = ? where uuid = ?"); + statement.setString(1, rank.getName()); + statement.setString(2, guild.getUuid().toString()); + statement.execute(); + } + catch (SQLException ex) + { + Guilds.logException(ex); + } + }); + } + + public void updateGuild(Guild guild) + { + try (Connection connection = Plex.get().getSqlConnection().getCon()) + { + PreparedStatement statement = connection.prepareStatement(UPDATE_GUILD); + statement.setString(1, guild.getName()); + statement.setString(2, guild.getDisplayName()); + statement.setInt(3, guild.getOwner().getId()); + statement.setString(4, guild.getPrefix()); + statement.setBoolean(5, guild.isPrefixEnabled()); + + if (guild.getHome() != null) + { + String home = GSON.toJson(guild.getHome().serialize(), new TypeToken>() + { + }.getType()); + statement.setString(6, home); + } + + statement.setString(7, guild.getMotd()); + statement.setString(8, guild.getPrivacy().name()); + + String members = GSON.toJson(guild.getMemberIDs(), new TypeToken>() + { + }.getType()); + statement.setString(9, members); + + String moderators = GSON.toJson(guild.getModeratorIDs(), new TypeToken>() + { + }.getType()); + statement.setString(10, moderators); + + if (guild.getDefaultRank() != null) + { + statement.setString(11, guild.getDefaultRank().getName()); + } + else + { + statement.setString(11, null); + } + + statement.setString(12, guild.getUuid().toString()); + statement.executeUpdate(); + + guild.getRanks().forEach(rank -> + { + try + { + PreparedStatement rankStatement = connection.prepareStatement("update rank set members = ? where guild_uuid = ? and name = ?"); + String rankMembers = GSON.toJson(rank.getMemberIDs(), new TypeToken>() + { + }.getType()); + rankStatement.setString(1, rankMembers); + rankStatement.setString(2, guild.getUuid().toString()); + rankStatement.setString(3, rank.getName()); + rankStatement.executeUpdate(); + } + catch (SQLException ex) + { + Guilds.logException(ex); + } + }); + } + catch (SQLException ex) + { + Guilds.logException(ex); + } + } + + public void updateMember(GuildMember member) + { + CompletableFuture.runAsync(() -> + { + try (Connection connection = Plex.get().getSqlConnection().getCon()) + { + PreparedStatement statement = connection.prepareStatement(UPDATE_MEMBER); + statement.setBoolean(1, member.isChat()); + statement.setBoolean(2, member.isPrefix()); + statement.setString(3, member.getUuid().toString()); + statement.execute(); + } + catch (SQLException ex) + { + Guilds.logException(ex); + } + }); + } + + public void deleteGuild(Guild guild) + { + CompletableFuture.runAsync(() -> + { + try (Connection connection = Plex.get().getSqlConnection().getCon()) + { + PreparedStatement statement = connection.prepareStatement(DELETE_GUILD_UUID); + statement.setString(1, guild.getUuid().toString()); + statement.execute(); + } + catch (SQLException ex) + { + Guilds.logException(ex); + } + }); + } + + public void deleteGuild(Player player) + { + CompletableFuture.runAsync(() -> + { + try (Connection connection = Plex.get().getSqlConnection().getCon()) + { + PreparedStatement statement = connection.prepareStatement(DELETE_GUILD_OWNER); + GuildMember member = Guilds.get().getMemberData().getMember(player).orElseThrow(); + statement.setInt(1, member.getId()); + statement.execute(); + } + catch (SQLException ex) + { + Guilds.logException(ex); + } + }); + } + + public List getGuilds() + { + List guilds = Lists.newArrayList(); + try (Connection connection = Plex.get().getSqlConnection().getCon()) + { + PreparedStatement guildStatement = connection.prepareStatement(SELECT_ALL_GUILDS); + PreparedStatement rankStatement = connection.prepareStatement("select * from rank where guild_uuid = ?"); + ResultSet set = guildStatement.executeQuery(); + while (set.next()) + { + Guild guild = new Guild(UUID.fromString(set.getString("uuid")), DATE_FORMAT.parse(set.getString("created_at"))); + guild.setName(set.getString("name")); + guild.setDisplayName(set.getString("display_name")); + guild.setOwner(Guilds.get().getMemberData().getMemberByID(set.getInt("owner_id")).orElseThrow()); + + List memberIds = GSON.fromJson(set.getString("members"), new TypeToken>() + { + }.getType()); + if (memberIds != null) + { + guild.setMembers(memberIds.stream().map(i -> Guilds.get().getMemberData().getMemberByID(i).orElseThrow()).toList()); + } + + List moderatorIds = GSON.fromJson(set.getString("moderators"), new TypeToken>() + { + }.getType()); + if (moderatorIds != null) + { + guild.setModerators(moderatorIds.stream().map(i -> Guilds.get().getMemberData().getMemberByID(i).orElseThrow()).collect(Collectors.toList())); + } + + List ranks = Lists.newArrayList(); + rankStatement.setString(1, guild.getUuid().toString()); + ResultSet rankSet = rankStatement.executeQuery(); + while (rankSet.next()) + { + GuildRank rank = new GuildRank(rankSet.getString("name")); + if (rank.getName().equals(set.getString("default_rank"))) + { + guild.setDefaultRank(rank); + break; + } + List rankMemberIds = GSON.fromJson(rankSet.getString("members"), new TypeToken>() + { + }.getType()); + if (rankMemberIds != null) + { + rank.setMembers(rankMemberIds.stream().map(i -> Guilds.get().getMemberData().getMemberByID(i).orElseThrow()).collect(Collectors.toList())); + } + ranks.add(rank); + } + guild.setRanks(ranks); + + List warps = Lists.newArrayList(); + PreparedStatement warpStatement = connection.prepareStatement("select * from warp where guild_uuid = ?"); + warpStatement.setString(1, guild.getUuid().toString()); + ResultSet warpSet = warpStatement.executeQuery(); + while (warpSet.next()) + { + GuildWarp warp = new GuildWarp(warpSet.getString("name"), + Location.deserialize(GSON.fromJson(warpSet.getString("location"), + new TypeToken>() + { + }.getType()))); + warps.add(warp); + } + guild.setWarps(warps); + + guild.setPrefix(set.getString("prefix")); + guild.setPrefixEnabled(set.getBoolean("prefix_enabled")); + guild.setMotd(set.getString("motd")); + + Map serializedLocation = GSON.fromJson(set.getString("home"), new TypeToken>() + { + }.getType()); + if (serializedLocation != null) + { + guild.setHome(Location.deserialize(serializedLocation)); + } + guild.setPrivacy(Guild.Privacy.valueOf(set.getString("privacy"))); + guilds.add(guild); + } + } + catch (SQLException | ParseException ex) + { + Guilds.logException(ex); + } + return guilds; + } + + public List getMembers() + { + List members = Lists.newArrayList(); + try (Connection connection = Plex.get().getSqlConnection().getCon()) + { + PreparedStatement statement = connection.prepareStatement("select * from member"); + ResultSet set = statement.executeQuery(); + while (set.next()) + { + GuildMember member = new GuildMember(UUID.fromString(set.getString("player_uuid"))); + member.setId(set.getInt("id")); + member.setChat(set.getBoolean("chat")); + member.setPrefix(set.getBoolean("prefix")); + members.add(member); + } + } + catch (SQLException ex) + { + Guilds.logException(ex); + } + return members; + } +} diff --git a/src/main/java/dev/plex/command/GuildCommand.java b/src/main/java/dev/plex/command/GuildCommand.java index d5035d9..1691c06 100644 --- a/src/main/java/dev/plex/command/GuildCommand.java +++ b/src/main/java/dev/plex/command/GuildCommand.java @@ -1,165 +1,117 @@ package dev.plex.command; -import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; +import dev.plex.Guilds; +import dev.plex.command.sub.*; import dev.plex.command.annotation.CommandParameters; import dev.plex.command.annotation.CommandPermissions; import dev.plex.command.source.RequiredCommandSource; -import dev.plex.command.sub.*; -import dev.plex.util.GuildUtil; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; -import org.apache.commons.lang3.StringUtils; import org.bukkit.command.CommandSender; -import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Arrays; +import java.util.Collections; import java.util.List; -import java.util.Locale; -@CommandParameters(name = "guild", description = "Guild menu", aliases = "guilds,g") +@CommandParameters(name = "guild", description = "Main guild command", aliases = "guilds,g") @CommandPermissions(permission = "plex.guilds.guild") public class GuildCommand extends PlexCommand { - private final List subCommands = Lists.newArrayList(); + private final List subcommands = Lists.newArrayList(); public GuildCommand() { try { - this.registerSubCommand(new CreateSubCommand()); - this.registerSubCommand(new InfoSubCommand()); - this.registerSubCommand(new PrefixSubCommand()); - this.registerSubCommand(new SetWarpSubCommand()); - this.registerSubCommand(new WarpSubCommand()); - this.registerSubCommand(new WarpListSubCommand()); - this.registerSubCommand(new ChatSubCommand()); - this.registerSubCommand(new SetHomeSubCommand()); - this.registerSubCommand(new HomeSubCommand()); - this.registerSubCommand(new OwnerSubCommand()); - this.registerSubCommand(new InviteSubCommand()); + subcommands.add(new CreateSubCommand()); + subcommands.add(new DeleteWarpSubCommand()); + subcommands.add(new DisbandSubCommand()); + subcommands.add(new HomeSubCommand()); + subcommands.add(new InfoSubCommand()); + subcommands.add(new MotdSubCommand()); + subcommands.add(new PrefixSubCommand()); + subcommands.add(new SetHomeSubCommand()); + subcommands.add(new SetOwnerSubCommand()); + subcommands.add(new SetWarpSubCommand()); + subcommands.add(new WarpSubCommand()); } - catch (Exception e) + catch (Exception ex) { - GuildUtil.throwExceptionSync(e); + Guilds.logException(ex); } } @Override - protected Component execute(@NotNull CommandSender commandSender, @Nullable Player player, @NotNull String[] args) + protected Component execute(@NotNull CommandSender sender, @Nullable Player player, @NotNull String[] args) { if (args.length == 0) { return getSubs(); } - if (args[0].equalsIgnoreCase("help")) - { - if (args.length < 2) - { - return usage("/guild help "); - } - PlexCommand subCommand = getSubCommand(args[1]); - if (subCommand == null) - { - return messageComponent("guildCommandNotFound", args[1]); - } - CommandPermissions permissions = subCommand.getClass().getDeclaredAnnotation(CommandPermissions.class); - return mmString("========").append(mmString("Command Name: " + subCommand.getName())).append(Component.newline()) - .append(mmString("Command Aliases: " + StringUtils.join(subCommand.getAliases(), ", "))).append(Component.newline()) - .append(mmString("Description: " + subCommand.getDescription())).append(Component.newline()) - .append(mmString("Permission: " + permissions.permission())).append(Component.newline()) - .append(mmString("Required Source: " + permissions.source().name())); - } - PlexCommand subCommand = getSubCommand(args[0]); + + SubCommand subCommand = getSubCommand(args[0]); if (subCommand == null) { return messageComponent("guildCommandNotFound", args[0]); } CommandPermissions permissions = subCommand.getClass().getDeclaredAnnotation(CommandPermissions.class); - if (permissions.source() == RequiredCommandSource.CONSOLE && commandSender instanceof Player) + if (permissions.source() == RequiredCommandSource.CONSOLE && sender instanceof Player) { return messageComponent("noPermissionInGame"); } - if (permissions.source() == RequiredCommandSource.IN_GAME && commandSender instanceof ConsoleCommandSender) + if (permissions.source() == RequiredCommandSource.IN_GAME && isConsole(sender)) { return messageComponent("noPermissionConsole"); } - checkPermission(player, permissions.permission()); - - return subCommand.execute(commandSender, player, Arrays.copyOfRange(args, 1, args.length)); - } - - private PlexCommand getSubCommand(String label) - { - return subCommands.stream().filter(cmd -> - { - CommandParameters commandParameters = cmd.getClass().getDeclaredAnnotation(CommandParameters.class); - return commandParameters.name().equalsIgnoreCase(label) || Arrays.stream(commandParameters.aliases().split(",")).anyMatch(s -> s.equalsIgnoreCase(label)); - }).findFirst().orElse(null); - } - - private void registerSubCommand(PlexCommand subCommand) - { - if (!subCommand.getClass().isAnnotationPresent(CommandPermissions.class)) - { - throw new RuntimeException("CommandPermissions annotation for guild sub command " + subCommand.getName() + " could not be found!"); - } - - if (!subCommand.getClass().isAnnotationPresent(CommandParameters.class)) - { - throw new RuntimeException("CommandParameters annotation for guild sub command " + subCommand.getName() + " could not be found!"); - } - this.subCommands.add(subCommand); + checkPermission(sender, permissions.permission()); + return subCommand.run(sender, player, Arrays.copyOfRange(args, 1, args.length)); } @Override - public @NotNull List smartTabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException + public @NotNull List smartTabComplete(@NotNull CommandSender sender, @NotNull String s, @NotNull String[] args) throws IllegalArgumentException { - if (args.length == 1) + if (args.length == 1 && silentCheckPermission(sender, this.getPermission())) { - List possibleCommands = Lists.newArrayList(); - if (!args[0].isEmpty()) - { - subCommands.forEach(plexCommand -> - { - plexCommand.getAliases().stream().filter(s -> s.toLowerCase(Locale.ROOT).startsWith(args[0].toLowerCase(Locale.ROOT))).forEach(possibleCommands::add); - if (plexCommand.getName().toLowerCase(Locale.ROOT).startsWith(args[0].toLowerCase(Locale.ROOT))) - { - possibleCommands.add(plexCommand.getName()); - } - }); - } - return possibleCommands; + return subcommands.stream().map(PlexCommand::getName).toList(); } - if (args.length >= 2) + else if (args.length >= 2) { PlexCommand subCommand = getSubCommand(args[0]); - if (subCommand != null) + if (subCommand != null && silentCheckPermission(sender, subCommand.getPermission())) { - return subCommand.tabComplete(sender, alias, Arrays.copyOfRange(args, 1, args.length)); + return subCommand.smartTabComplete(sender, s, Arrays.copyOfRange(args, 1, args.length)); } } - return ImmutableList.of(); + return Collections.emptyList(); + } + + private SubCommand getSubCommand(String label) + { + return subcommands.stream().filter(cmd -> + { + CommandParameters parameters = cmd.getClass().getDeclaredAnnotation(CommandParameters.class); + return parameters.name().equalsIgnoreCase(label) || Arrays.stream(parameters.aliases().split(",")).anyMatch(s -> s.equalsIgnoreCase(label)); + }).findFirst().orElse(null); } public Component getSubs() { Component commands = Component.empty(); - for (int i = 0; i < this.subCommands.size(); i++) + for (int i = 0; i < this.subcommands.size(); i++) { - commands = commands.append(messageComponent("guildsCommandDisplay", "/guild " + this.subCommands.get(i).getName(), this.subCommands.get(i).getDescription()).clickEvent(ClickEvent.suggestCommand("/guild help " + this.subCommands.get(i).getName()))); - if (i < this.subCommands.size() - 1) + commands = commands.append(messageComponent("guildsCommandDisplay", "/guild " + this.subcommands.get(i).getName(), this.subcommands.get(i).getDescription()).clickEvent(ClickEvent.suggestCommand("/guild help " + this.subcommands.get(i).getName()))); + if (i < this.subcommands.size() - 1) { commands = commands.append(Component.newline()); } } return messageComponent("guildsHelpCommand", commands); } - } diff --git a/src/main/java/dev/plex/command/SubCommand.java b/src/main/java/dev/plex/command/SubCommand.java new file mode 100644 index 0000000..796a7d5 --- /dev/null +++ b/src/main/java/dev/plex/command/SubCommand.java @@ -0,0 +1,35 @@ +package dev.plex.command; + +import dev.plex.command.annotation.CommandParameters; +import dev.plex.command.annotation.CommandPermissions; +import net.kyori.adventure.text.Component; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class SubCommand extends PlexCommand +{ + public SubCommand() + { + super(false); + + if (!getClass().isAnnotationPresent(CommandParameters.class)) + { + throw new RuntimeException("CommandParameters annotation for guild sub command " + getName() + " could not be found!"); + } + + if (!getClass().isAnnotationPresent(CommandPermissions.class)) + { + throw new RuntimeException("CommandPermissions annotation for guild sub command " + getName() + " could not be found!"); + } + } + + @Override + protected Component execute(@NotNull CommandSender commandSender, @Nullable Player player, @NotNull String[] strings) + { + return null; + } + + public abstract Component run(CommandSender sender, Player player, String[] args); +} diff --git a/src/main/java/dev/plex/command/sub/ChatSubCommand.java b/src/main/java/dev/plex/command/sub/ChatSubCommand.java deleted file mode 100644 index 428773c..0000000 --- a/src/main/java/dev/plex/command/sub/ChatSubCommand.java +++ /dev/null @@ -1,60 +0,0 @@ -package dev.plex.command.sub; - -import dev.plex.Guilds; -import dev.plex.command.PlexCommand; -import dev.plex.command.annotation.CommandParameters; -import dev.plex.command.annotation.CommandPermissions; -import dev.plex.command.source.RequiredCommandSource; -import dev.plex.guild.data.Member; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import net.kyori.adventure.text.Component; -import org.apache.commons.lang3.BooleanUtils; -import org.apache.commons.lang3.StringUtils; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -@CommandParameters(name = "chat", usage = "/guild [message]", description = "Toggles guild chat or sends a guild chat message") -@CommandPermissions(source = RequiredCommandSource.IN_GAME, permission = "plex.guilds.chat") -public class ChatSubCommand extends PlexCommand -{ - public ChatSubCommand() - { - super(false); - } - - @Override - protected Component execute(@NotNull CommandSender commandSender, @Nullable Player player, @NotNull String[] args) - { - assert player != null; - Guilds.get().getGuildHolder().getGuild(player.getUniqueId()).ifPresentOrElse(guild -> - { - if (args.length == 0) - { - Member member = guild.getMember(player.getUniqueId()); - member.setChat(!member.isChat()); - send(player, messageComponent("guildChatToggled", BooleanUtils.toStringOnOff(member.isChat()))); - return; - } - guild.getMembers().stream().map(Member::getPlayer).filter(Objects::nonNull).forEach(player1 -> - { - send(player1, messageComponent("guildChatMessage", player.getName(), StringUtils.join(args, " "))); - }); - if (Guilds.get().getConfig().isBoolean("guilds.log-chat-message")) - { - send(Bukkit.getConsoleSender(), messageComponent("guildChatConsoleLog", guild.getName(), guild.getGuildUuid(), player.getName(), StringUtils.join(args, " "))); - } - }, () -> send(player, messageComponent("guildNotFound"))); - return null; - } - - @Override - public @NotNull List smartTabComplete(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] strings) throws IllegalArgumentException - { - return Collections.emptyList(); - } -} diff --git a/src/main/java/dev/plex/command/sub/CreateSubCommand.java b/src/main/java/dev/plex/command/sub/CreateSubCommand.java index ee0598a..2b33078 100644 --- a/src/main/java/dev/plex/command/sub/CreateSubCommand.java +++ b/src/main/java/dev/plex/command/sub/CreateSubCommand.java @@ -2,12 +2,12 @@ package dev.plex.command.sub; import dev.plex.Guilds; import dev.plex.command.PlexCommand; +import dev.plex.command.SubCommand; import dev.plex.command.annotation.CommandParameters; import dev.plex.command.annotation.CommandPermissions; import dev.plex.command.source.RequiredCommandSource; import dev.plex.guild.Guild; -import java.util.Collections; -import java.util.List; +import dev.plex.guild.GuildMember; import net.kyori.adventure.text.Component; import org.apache.commons.lang3.StringUtils; import org.bukkit.command.CommandSender; @@ -15,37 +15,40 @@ import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -@CommandParameters(name = "create", aliases = "make", usage = "/guild ", description = "Creates a guild with a specified name") +import java.util.Collections; +import java.util.List; + +@CommandParameters(name = "create", usage = "/guild ", description = "Create a brand new guild") @CommandPermissions(source = RequiredCommandSource.IN_GAME, permission = "plex.guilds.create") -public class CreateSubCommand extends PlexCommand +public class CreateSubCommand extends SubCommand { - public CreateSubCommand() + @Override + public Component run(@NotNull CommandSender sender, @Nullable Player player, @NotNull String[] args) { - super(false); + if (args.length > 0) + { + assert player != null; + GuildMember member = Guilds.get().getMemberData().getMember(player).orElseThrow(); + if (member.getGuild().isPresent()) + { + return messageComponent("alreadyInGuild"); + } + + String name = StringUtils.join(args, " "); + if (!StringUtils.isAlphanumericSpace(name)) + { + return messageComponent("guildAlphanumericName"); + } + + Guild guild = Guild.create(member, name); + return mmString("Successfully created guild named " + guild.getName()); + } + + return usage(); } @Override - protected Component execute(@NotNull CommandSender commandSender, @Nullable Player player, @NotNull String[] args) - { - if (args.length == 0) - { - return usage(); - } - assert player != null; - if (Guilds.get().getGuildHolder().getGuild(player.getUniqueId()).isPresent()) - { - return messageComponent("alreadyInGuild"); - } - Guilds.get().getSqlGuildManager().insertGuild(Guild.create(player, StringUtils.join(args, " "))).whenComplete((guild, throwable) -> - { - Guilds.get().getGuildHolder().addGuild(guild); - send(player, mmString("Created guild named " + guild.getName())); - }); - return null; - } - - @Override - public @NotNull List smartTabComplete(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] strings) throws IllegalArgumentException + public @NotNull List smartTabComplete(@NotNull CommandSender sender, @NotNull String s, @NotNull String[] args) throws IllegalArgumentException { return Collections.emptyList(); } diff --git a/src/main/java/dev/plex/command/sub/DeleteWarpSubCommand.java b/src/main/java/dev/plex/command/sub/DeleteWarpSubCommand.java new file mode 100644 index 0000000..30ff011 --- /dev/null +++ b/src/main/java/dev/plex/command/sub/DeleteWarpSubCommand.java @@ -0,0 +1,65 @@ +package dev.plex.command.sub; + +import com.google.common.collect.Lists; +import dev.plex.Guilds; +import dev.plex.command.SubCommand; +import dev.plex.command.annotation.CommandParameters; +import dev.plex.command.annotation.CommandPermissions; +import dev.plex.command.source.RequiredCommandSource; +import dev.plex.guild.GuildMember; +import net.kyori.adventure.text.Component; +import org.apache.commons.lang3.StringUtils; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +@CommandParameters(name = "deletewarp", aliases = "delwarp,removewarp", usage = "/guild ", description = "Deletes a guild warp") +@CommandPermissions(source = RequiredCommandSource.IN_GAME, permission = "plex.guilds.deletewarp") +public class DeleteWarpSubCommand extends SubCommand +{ + @Override + public Component run(CommandSender sender, Player player, String[] args) + { + if (args.length == 0) + { + return usage(); + } + + assert player != null; + GuildMember member = Guilds.get().getMemberData().getMember(player).orElseThrow(); + member.getGuild().ifPresentOrElse(guild -> + { + if (!guild.isModerator(member)) + { + send(player, messageComponent("guildNotMod")); + return; + } + + String name = StringUtils.join(args, " ").toLowerCase(); + guild.getWarp(name).ifPresentOrElse(guildWarp -> + { + guild.deleteWarp(guildWarp); + send(player, messageComponent("guildWarpRemoved", name)); + }, + () -> send(player, messageComponent("guildWarpNotFound", name))); + }, + () -> send(player, messageComponent("guildNotFound"))); + return null; + } + + @Override + public @NotNull List smartTabComplete(@NotNull CommandSender sender, @NotNull String s, @NotNull String[] args) throws IllegalArgumentException + { + if (args.length == 1 && silentCheckPermission(sender, getPermission())) + { + GuildMember member = Guilds.get().getMemberData().getMember((Player) sender).orElseThrow(); + List names = Lists.newArrayList(); + member.getGuild().ifPresent(guild -> names.addAll(guild.getWarpNames())); + return names; + } + return Collections.emptyList(); + } +} diff --git a/src/main/java/dev/plex/command/sub/DisbandSubCommand.java b/src/main/java/dev/plex/command/sub/DisbandSubCommand.java new file mode 100644 index 0000000..0135930 --- /dev/null +++ b/src/main/java/dev/plex/command/sub/DisbandSubCommand.java @@ -0,0 +1,59 @@ +package dev.plex.command.sub; + +import com.google.common.collect.Lists; +import dev.plex.Guilds; +import dev.plex.command.SubCommand; +import dev.plex.command.annotation.CommandParameters; +import dev.plex.command.annotation.CommandPermissions; +import dev.plex.command.source.RequiredCommandSource; +import dev.plex.guild.Guild; +import dev.plex.guild.GuildMember; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +@CommandParameters(name = "disband", usage = "/guild ", description = "Disband your guild") +@CommandPermissions(source = RequiredCommandSource.IN_GAME, permission = "plex.guilds.disband") +public class DisbandSubCommand extends SubCommand +{ + private final List confirm = Lists.newArrayList(); + + @Override + public Component run(CommandSender sender, Player player, String[] args) + { + assert player != null; + GuildMember member = Guilds.get().getMemberData().getMember(player).orElseThrow(); + if (member.getGuild().isEmpty()) + { + return messageComponent("guildNotFound"); + } + + Guild guild = member.getGuild().get(); + if (!guild.isOwner(member)) + { + return messageComponent("guildNotOwner"); + } + + if (!confirm.contains(sender)) + { + confirm.add(sender); + Bukkit.getScheduler().runTaskLater(Guilds.get().getPlex(), () -> confirm.remove(sender), 20 * 10); + return messageComponent("guildActionConfirmation", "disband"); + } + + Guilds.get().getGuildData().deleteGuild(member); + confirm.remove(sender); + return messageComponent("guildDisbanded"); + } + + @Override + public @NotNull List smartTabComplete(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] strings) throws IllegalArgumentException + { + return Collections.emptyList(); + } +} diff --git a/src/main/java/dev/plex/command/sub/HomeSubCommand.java b/src/main/java/dev/plex/command/sub/HomeSubCommand.java index a4a7691..1cc5342 100644 --- a/src/main/java/dev/plex/command/sub/HomeSubCommand.java +++ b/src/main/java/dev/plex/command/sub/HomeSubCommand.java @@ -1,45 +1,45 @@ package dev.plex.command.sub; import dev.plex.Guilds; -import dev.plex.command.PlexCommand; +import dev.plex.command.SubCommand; import dev.plex.command.annotation.CommandParameters; import dev.plex.command.annotation.CommandPermissions; import dev.plex.command.source.RequiredCommandSource; -import java.util.Collections; -import java.util.List; +import dev.plex.guild.GuildMember; import net.kyori.adventure.text.Component; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -@CommandParameters(name = "home", aliases = "spawn", usage = "/guild ", description = "Teleports to the guild home") +import java.util.Collections; +import java.util.List; + +@CommandParameters(name = "home", usage = "/guild ", description = "Teleport to your guild's home location") @CommandPermissions(source = RequiredCommandSource.IN_GAME, permission = "plex.guilds.home") -public class HomeSubCommand extends PlexCommand +public class HomeSubCommand extends SubCommand { - public HomeSubCommand() - { - super(false); - } - @Override - protected Component execute(@NotNull CommandSender commandSender, @Nullable Player player, @NotNull String[] args) + public Component run(CommandSender sender, Player player, String[] args) { assert player != null; - Guilds.get().getGuildHolder().getGuild(player.getUniqueId()).ifPresentOrElse(guild -> - { - if (guild.getHome() == null) - { - send(player, messageComponent("guildHomeNotFound")); - return; - } - player.teleportAsync(guild.getHome().toLocation()); - }, () -> send(player, messageComponent("guildNotFound"))); + GuildMember member = Guilds.get().getMemberData().getMember(player).orElseThrow(); + member.getGuild().ifPresentOrElse(guild -> + { + if (guild.getHome() == null) + { + send(player, messageComponent("guildHomeNotFound")); + return; + } + + player.teleportAsync(guild.getHome()); + send(player, messageComponent("guildHomeTeleport")); + }, + () -> send(player, messageComponent("guildNotFound"))); return null; } @Override - public @NotNull List smartTabComplete(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] strings) throws IllegalArgumentException + public @NotNull List smartTabComplete(@NotNull CommandSender sender, @NotNull String s, @NotNull String[] args) throws IllegalArgumentException { return Collections.emptyList(); } diff --git a/src/main/java/dev/plex/command/sub/InfoSubCommand.java b/src/main/java/dev/plex/command/sub/InfoSubCommand.java index 9481422..be204e8 100644 --- a/src/main/java/dev/plex/command/sub/InfoSubCommand.java +++ b/src/main/java/dev/plex/command/sub/InfoSubCommand.java @@ -1,63 +1,105 @@ package dev.plex.command.sub; import dev.plex.Guilds; -import dev.plex.cache.DataUtils; -import dev.plex.command.PlexCommand; +import dev.plex.command.SubCommand; import dev.plex.command.annotation.CommandParameters; import dev.plex.command.annotation.CommandPermissions; -import dev.plex.command.source.RequiredCommandSource; -import java.time.format.DateTimeFormatter; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CompletableFuture; +import dev.plex.guild.Guild; +import dev.plex.guild.GuildMember; import net.kyori.adventure.text.Component; import org.apache.commons.lang3.StringUtils; +import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -@CommandParameters(name = "info", aliases = "information", usage = "/guild ", description = "Shows the guild's information") -@CommandPermissions(source = RequiredCommandSource.IN_GAME, permission = "plex.guilds.info") -public class InfoSubCommand extends PlexCommand +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +@CommandParameters(name = "info", usage = "/guild [name]", description = "Shows your or a specified guild's information") +@CommandPermissions(permission = "plex.guilds.info") +public class InfoSubCommand extends SubCommand { - public InfoSubCommand() - { - super(false); - } - - private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm:ss a"); + private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); @Override - protected Component execute(@NotNull CommandSender commandSender, @Nullable Player player, @NotNull String[] strings) + public Component run(CommandSender sender, Player player, String[] args) { - assert player != null; - CompletableFuture.runAsync(() -> + if (args.length == 0) { - Guilds.get().getGuildHolder().getGuild(player.getUniqueId()).ifPresentOrElse(guild -> + if (isConsole(sender)) { - send(player, mmString("====" + guild.getName() + "====")); - send(player, mmString("")); - try - { - send(player, mmString("Owner: " + DataUtils.getPlayer(guild.getOwner().getUuid(), false).getName())); - } - catch (NullPointerException e) - { - send(player, mmString("Owner: Unable to load cache...")); - } - List members = guild.getMembers().stream().filter(member -> !member.getUuid().equals(guild.getOwner().getUuid())).map(member -> DataUtils.getPlayer(member.getUuid(), false).getName()).toList(); - send(player, mmString("Members (" + members.size() + "): " + StringUtils.join(members, ", "))); - send(player, mmString("Moderators (" + guild.getModerators().size() + "): " + StringUtils.join(guild.getModerators().stream().map(uuid -> DataUtils.getPlayer(uuid, false).getName()).toList(), ", "))); - send(player, mmString("Prefix: " + (guild.getPrefix() == null ? "N/A" : guild.getPrefix()))); - send(player, mmString("Created At: " + formatter.format(guild.getCreatedAt()))); - }, () -> send(player, messageComponent("guildNotFound"))); - }); + return messageComponent("noPermissionConsole"); + } + + assert player != null; + GuildMember member = Guilds.get().getMemberData().getMember(player).orElseThrow(); + member.getGuild().ifPresentOrElse(guild -> + { + Component info = Component.empty() + .append(mmString("====" + guild.getName() + "====")) + .appendNewline() + .append(mmString("UUID: " + guild.getUuid().toString())) + .appendNewline() + .append(mmString("Display Name: " + guild.getDisplayName())) + .appendNewline() + .append(mmString("Owner: " + guild.getOwner().getPlayer().getName())) + .appendNewline() + .append(mmString("Members (" + guild.getMemberNames().size() + "): " + StringUtils.join(guild.getMemberNames(), ", "))) + .appendNewline() + .append(mmString("Moderators (" + guild.getModerators().size() + "): " + StringUtils.join(guild.getModeratorNames(), ", "))) + .appendNewline() + .append(mmString("Privacy: " + guild.getPrivacy().toString())) + .appendNewline() + .append(mmString("Created At: " + dateFormat.format(guild.getCreatedAt()))); + send(player, info); + }, + () -> send(player, messageComponent("guildNotFound"))); + } + else + { + String name = StringUtils.join(args, " "); + Optional optionalGuild; + + Player target = Bukkit.getPlayer(name); + if (target != null) + { + optionalGuild = Guilds.get().getMemberData().getMember(target).orElseThrow().getGuild(); + } + else + { + optionalGuild = Guilds.get().getGuildData().getGuildByName(name); + } + + optionalGuild.ifPresentOrElse(guild -> + { + Component info = Component.empty() + .append(mmString("====" + guild.getName() + "====")) + .appendNewline() + .append(mmString("UUID: " + guild.getUuid().toString())) + .appendNewline() + .append(mmString("Display Name: " + guild.getDisplayName())) + .appendNewline() + .append(mmString("Owner: " + guild.getOwner().getPlayer().getName())) + .appendNewline() + .append(mmString("Members (" + guild.getMemberNames().size() + "): " + StringUtils.join(guild.getMemberNames(), ", "))) + .appendNewline() + .append(mmString("Moderators (" + guild.getModerators().size() + "): " + StringUtils.join(guild.getModeratorNames(), ", "))) + .appendNewline() + .append(mmString("Privacy: " + guild.getPrivacy().toString())) + .appendNewline() + .append(mmString("Created At: " + dateFormat.format(guild.getCreatedAt()))); + send(sender, info); + }, + () -> send(sender, messageComponent("guildNotExist", name))); + } return null; } @Override - public @NotNull List smartTabComplete(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] strings) throws IllegalArgumentException + public @NotNull List smartTabComplete(@NotNull CommandSender sender, @NotNull String s, @NotNull String[] args) throws IllegalArgumentException { return Collections.emptyList(); } diff --git a/src/main/java/dev/plex/command/sub/InviteSubCommand.java b/src/main/java/dev/plex/command/sub/InviteSubCommand.java deleted file mode 100644 index fb3d303..0000000 --- a/src/main/java/dev/plex/command/sub/InviteSubCommand.java +++ /dev/null @@ -1,140 +0,0 @@ -package dev.plex.command.sub; - -import com.google.common.collect.ImmutableList; -import dev.plex.Guilds; -import dev.plex.command.PlexCommand; -import dev.plex.command.annotation.CommandParameters; -import dev.plex.command.annotation.CommandPermissions; -import dev.plex.command.source.RequiredCommandSource; -import dev.plex.guild.Guild; -import dev.plex.guild.GuildHolder; -import dev.plex.guild.data.Member; -import dev.plex.util.PlexLog; -import net.kyori.adventure.text.Component; -import org.apache.commons.lang3.StringUtils; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.Collectors; -// TODO: 5/9/2022 5 minute timeout for invites -// TODO: 5/9/2022 deny command maybe? -// TODO: 5/9/2022 deny members from inviting themselves or existing members in the current guild - -@CommandParameters(name = "invite", aliases = "inv", usage = "/guild ", description = "Invites a player to the guild") -@CommandPermissions(source = RequiredCommandSource.IN_GAME, permission = "plex.guilds.invite") -public class InviteSubCommand extends PlexCommand -{ - public InviteSubCommand() - { - super(false); - } - - @Override - protected Component execute(@NotNull CommandSender commandSender, @Nullable Player player, @NotNull String[] args) - { - if (args.length == 0) - { - return usage(); - } - assert player != null; - if (args[0].equalsIgnoreCase("accept")) - { - if (!GuildHolder.PENDING_INVITES.containsKey(player.getUniqueId())) - { - return messageComponent("guildNoInvite"); - } - String guildName = StringUtils.join(args, " ", 1, args.length); - GuildHolder.PENDING_INVITES.get(player.getUniqueId()).stream().filter(guild -> guild.getName().equalsIgnoreCase(guildName)).findFirst().ifPresentOrElse(guild -> - { - AtomicBoolean continueCheck = new AtomicBoolean(true); - Guilds.get().getGuildHolder().getGuild(player.getUniqueId()).ifPresent(guild1 -> - { - if (guild1.getGuildUuid().equals(guild.getGuildUuid())) - { - send(player, messageComponent("guildInThis")); - continueCheck.set(false); - return; - } - if (guild1.getOwner().getUuid().equals(player.getUniqueId())) - { - if (guild1.getMembers().size() - 1 > 0) - { - send(player, messageComponent("guildDisbandNeeded")); - continueCheck.set(false); - return; - } - else - { - Guilds.get().getSqlGuildManager().deleteGuild(guild1.getGuildUuid()).whenComplete((unused, throwable) -> - { - send(player, messageComponent("guildAutoDisbanded")); - }); - } - } - guild1.getMembers().stream().map(Member::getPlayer).filter(Objects::nonNull).forEach(player1 -> - { - send(player1, messageComponent("guildMemberLeft", player.getName())); - }); - guild1.getMembers().removeIf(member -> member.getUuid().equals(player.getUniqueId())); - }); - if (!continueCheck.get()) - { - return; - } - GuildHolder.PENDING_INVITES.remove(player.getUniqueId()); - guild.addMember(player.getUniqueId()); - guild.getMembers().stream().map(Member::getPlayer).filter(Objects::nonNull).forEach(player1 -> - { - send(player1, messageComponent("guildMemberJoined", player.getName())); - }); - }, () -> send(player, messageComponent("guildNotValidInvite"))); - return null; - } - Guilds.get().getGuildHolder().getGuild(player.getUniqueId()).ifPresentOrElse(guild -> - { - if (!guild.getOwner().getUuid().equals(player.getUniqueId())) - { - send(player, messageComponent("guildNotOwner")); - return; - } - Player target = getNonNullPlayer(args[0]); - boolean invite = GuildHolder.sendInvite(target.getUniqueId(), guild); - if (!invite) - { - send(player, messageComponent("guildInviteExists")); - return; - } - send(player, messageComponent("guildInviteSent", target.getName())); - send(target, messageComponent("guildInviteReceived", player.getName(), guild.getName())); - }, () -> send(player, messageComponent("guildNotFound"))); - return null; - } - - @Override - public @NotNull List smartTabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException - { - if (!(sender instanceof Player player)) - { - return ImmutableList.of(); - } - if (args.length == 0) - { - return ImmutableList.of(); - } - if (args[0].equalsIgnoreCase("accept") && args.length == 2) - { - if (!GuildHolder.PENDING_INVITES.containsKey(player.getUniqueId())) - { - return ImmutableList.of(); - } - PlexLog.debug("Tab Completing moment"); - return GuildHolder.PENDING_INVITES.get(player.getUniqueId()).stream().map(Guild::getName).collect(Collectors.toList()); - } - return ImmutableList.of(); - } -} diff --git a/src/main/java/dev/plex/command/sub/LeaveSubCommand.java b/src/main/java/dev/plex/command/sub/LeaveSubCommand.java new file mode 100644 index 0000000..c807c4b --- /dev/null +++ b/src/main/java/dev/plex/command/sub/LeaveSubCommand.java @@ -0,0 +1,69 @@ +package dev.plex.command.sub; + +import com.google.common.collect.Lists; +import dev.plex.Guilds; +import dev.plex.command.SubCommand; +import dev.plex.command.annotation.CommandParameters; +import dev.plex.command.annotation.CommandPermissions; +import dev.plex.command.source.RequiredCommandSource; +import dev.plex.guild.GuildMember; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +@CommandParameters(name = "leave", usage = "/guild ", description = "Leave the guild you are currently in") +@CommandPermissions(source = RequiredCommandSource.IN_GAME, permission = "plex.guilds.leave") +public class LeaveSubCommand extends SubCommand +{ + private final List confirm = Lists.newArrayList(); + + @Override + public Component run(CommandSender sender, Player player, String[] args) + { + assert player != null; + GuildMember member = Guilds.get().getMemberData().getMember(player).orElseThrow(); + member.getGuild().ifPresentOrElse(guild -> + { + if (guild.isOwner(member) && guild.getMembers().size() > 1) + { + send(player, messageComponent("guildDisbandNeeded")); + return; + } + + if (!confirm.contains(sender)) + { + confirm.add(sender); + Bukkit.getScheduler().runTaskLater(Guilds.get().getPlex(), () -> confirm.remove(sender), 20 * 10); + send(player, messageComponent("guildActionConfirmation", "leave")); + return; + } + + confirm.remove(sender); + + if (guild.isOwner(member) && guild.getMembers().size() == 1) + { + Guilds.get().getGuildData().deleteGuild(member); + send(player, messageComponent("guildAutoDisbanded")); + return; + } + + guild.removeMember(member); + send(player, messageComponent("guildLeft")); + guild.getMembers().stream().map(GuildMember::getPlayer).filter(OfflinePlayer::isOnline).map(OfflinePlayer::getPlayer).forEach(p -> send(p, messageComponent("guildMemberLeft", player.getName()))); + }, + () -> send(player, messageComponent("guildNotFound"))); + return null; + } + + @Override + public @NotNull List smartTabComplete(@NotNull CommandSender sender, @NotNull String s, @NotNull String[] args) throws IllegalArgumentException + { + return Collections.emptyList(); + } +} diff --git a/src/main/java/dev/plex/command/sub/MotdSubCommand.java b/src/main/java/dev/plex/command/sub/MotdSubCommand.java new file mode 100644 index 0000000..d22b558 --- /dev/null +++ b/src/main/java/dev/plex/command/sub/MotdSubCommand.java @@ -0,0 +1,74 @@ +package dev.plex.command.sub; + +import dev.plex.Guilds; +import dev.plex.command.SubCommand; +import dev.plex.command.annotation.CommandParameters; +import dev.plex.command.annotation.CommandPermissions; +import dev.plex.command.source.RequiredCommandSource; +import dev.plex.guild.Guild; +import dev.plex.guild.GuildMember; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.apache.commons.lang3.StringUtils; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +@CommandParameters(name = "motd", usage = "/g | clear>", description = "Set or clear your guild's MOTD") +@CommandPermissions(source = RequiredCommandSource.IN_GAME, permission = "plex.guilds.motd") +public class MotdSubCommand extends SubCommand +{ + + @Override + public Component run(CommandSender sender, Player player, String[] args) + { + assert player != null; + if (args.length > 0) + { + GuildMember member = Guilds.get().getMemberData().getMember(player).orElseThrow(); + if (member.getGuild().isEmpty()) + { + return messageComponent("guildNotFound"); + } + + Guild guild = member.getGuild().get(); + if (!guild.isModerator(member)) + { + return messageComponent("guildNotMod"); + } + + if (args.length == 1 && args[0].equalsIgnoreCase("clear")) + { + guild.setMotd(null); + return messageComponent("guildMotdCleared"); + } + + if (args.length > 1 && args[0].equalsIgnoreCase("set")) + { + String message = StringUtils.join(args, " ", 1, args.length); + if (MiniMessage.miniMessage().stripTags(message).length() > 256) + { + return messageComponent("guildMotdExceededLimit"); + } + + guild.setMotd(message); + return messageComponent("guildMotdSet", mmString(message)); + } + } + return usage(); + } + + @Override + public @NotNull List smartTabComplete(@NotNull CommandSender sender, @NotNull String s, @NotNull String[] args) throws IllegalArgumentException + { + if (args.length == 1) + { + return Arrays.asList("set", "clear"); + } + return Collections.emptyList(); + } +} diff --git a/src/main/java/dev/plex/command/sub/OwnerSubCommand.java b/src/main/java/dev/plex/command/sub/OwnerSubCommand.java deleted file mode 100644 index c9ee507..0000000 --- a/src/main/java/dev/plex/command/sub/OwnerSubCommand.java +++ /dev/null @@ -1,69 +0,0 @@ -package dev.plex.command.sub; - -import dev.plex.Guilds; -import dev.plex.cache.DataUtils; -import dev.plex.command.PlexCommand; -import dev.plex.command.annotation.CommandParameters; -import dev.plex.command.annotation.CommandPermissions; -import dev.plex.command.source.RequiredCommandSource; -import dev.plex.guild.data.Member; -import dev.plex.player.PlexPlayer; -import java.util.Collections; -import java.util.List; -import net.kyori.adventure.text.Component; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -@CommandParameters(name = "owner", aliases = "setowner", usage = "/guild ", description = "Sets the guild owner") -@CommandPermissions(source = RequiredCommandSource.IN_GAME, permission = "plex.guilds.owner") -public class OwnerSubCommand extends PlexCommand -{ - public OwnerSubCommand() - { - super(false); - } - - @Override - protected Component execute(@NotNull CommandSender commandSender, @Nullable Player player, @NotNull String[] args) - { - if (args.length == 0) - { - return usage(); - } - assert player != null; - Guilds.get().getGuildHolder().getGuild(player.getUniqueId()).ifPresentOrElse(guild -> - { - if (!guild.getOwner().getUuid().equals(player.getUniqueId())) - { - send(player, messageComponent("guildNotOwner")); - return; - } - Member memberSender = guild.getMember(player.getUniqueId()); - PlexPlayer plexPlayer = DataUtils.getPlayer(args[0], false); - if (plexPlayer == null) - { - send(player, messageComponent("playerNotFound")); - return; - } - Member member = guild.getMember(plexPlayer.getUuid()); - if (member == null) - { - send(player, messageComponent("guildMemberNotFound")); - return; - } - guild.setOwner(member); - guild.getMembers().remove(member); - guild.getMembers().add(memberSender); - send(player, messageComponent("guildOwnerSet", plexPlayer.getName())); - }, () -> send(player, messageComponent("guildNotFound"))); - return null; - } - - @Override - public @NotNull List smartTabComplete(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] strings) throws IllegalArgumentException - { - return Collections.emptyList(); - } -} diff --git a/src/main/java/dev/plex/command/sub/PrefixSubCommand.java b/src/main/java/dev/plex/command/sub/PrefixSubCommand.java index d6e308e..7187d37 100644 --- a/src/main/java/dev/plex/command/sub/PrefixSubCommand.java +++ b/src/main/java/dev/plex/command/sub/PrefixSubCommand.java @@ -1,58 +1,62 @@ package dev.plex.command.sub; import dev.plex.Guilds; -import dev.plex.command.PlexCommand; +import dev.plex.command.SubCommand; import dev.plex.command.annotation.CommandParameters; import dev.plex.command.annotation.CommandPermissions; import dev.plex.command.source.RequiredCommandSource; +import dev.plex.guild.GuildMember; import dev.plex.util.minimessage.SafeMiniMessage; -import java.util.Collections; -import java.util.List; import net.kyori.adventure.text.Component; import org.apache.commons.lang3.StringUtils; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -@CommandParameters(name = "prefix", aliases = "tag,settag,setprefix", usage = "/guild ", description = "Sets the guild's default prefix") +import java.util.Collections; +import java.util.List; + +@CommandParameters(name = "prefix", aliases = "tag,settag,setprefix", usage = "/guild ", description = "Sets the guild's default prefix") @CommandPermissions(source = RequiredCommandSource.IN_GAME, permission = "plex.guilds.prefix") -public class PrefixSubCommand extends PlexCommand +public class PrefixSubCommand extends SubCommand { - public PrefixSubCommand() - { - super(false); - } - @Override - protected Component execute(@NotNull CommandSender commandSender, @Nullable Player player, @NotNull String[] args) + public Component run(CommandSender sender, Player player, String[] args) { if (args.length == 0) { return usage(); } + assert player != null; - Guilds.get().getGuildHolder().getGuild(player.getUniqueId()).ifPresentOrElse(guild -> - { - if (!guild.getOwner().getUuid().equals(player.getUniqueId())) - { - send(player, messageComponent("guildNotOwner")); - return; - } - if (args[0].equalsIgnoreCase("clear") || args[0].equalsIgnoreCase("off")) - { - guild.setPrefix(null); - send(player, messageComponent("guildPrefixCleared")); - return; - } - guild.setPrefix(StringUtils.join(args, " ")); - send(player, messageComponent("guildPrefixSet", SafeMiniMessage.mmDeserializeWithoutEvents(guild.getPrefix()))); - }, () -> send(player, messageComponent("guildNotFound"))); + GuildMember member = Guilds.get().getMemberData().getMember(player).orElseThrow(); + member.getGuild().ifPresentOrElse(guild -> + { + if (!guild.isModerator(member)) + { + send(player, messageComponent("guildNotMod")); + return; + } + + if (args[0].equalsIgnoreCase("clear")) + { + guild.setPrefix(null); + send(player, messageComponent("guildPrefixCleared")); + return; + } + + String prefix = StringUtils.join(args, " "); + guild.setPrefix(prefix); + prefix = prefix.replace("%rank%", guild.getDefaultRank().getName()).replace("%name%", guild.getDisplayName()); + send(player, messageComponent("guildPrefixSet", SafeMiniMessage.mmDeserializeWithoutEvents(prefix))); + }, + () -> send(player, messageComponent("guildNotFound"))); + return null; } @Override - public @NotNull List smartTabComplete(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] strings) throws IllegalArgumentException + public @NotNull List smartTabComplete(@NotNull CommandSender sender, @NotNull String s, @NotNull String[] args) throws IllegalArgumentException { return Collections.emptyList(); } diff --git a/src/main/java/dev/plex/command/sub/SetHomeSubCommand.java b/src/main/java/dev/plex/command/sub/SetHomeSubCommand.java index 83028c0..5e71ce3 100644 --- a/src/main/java/dev/plex/command/sub/SetHomeSubCommand.java +++ b/src/main/java/dev/plex/command/sub/SetHomeSubCommand.java @@ -1,59 +1,64 @@ package dev.plex.command.sub; import dev.plex.Guilds; -import dev.plex.command.PlexCommand; +import dev.plex.command.SubCommand; import dev.plex.command.annotation.CommandParameters; import dev.plex.command.annotation.CommandPermissions; import dev.plex.command.source.RequiredCommandSource; -import dev.plex.util.CustomLocation; -import java.util.Collections; -import java.util.List; +import dev.plex.guild.GuildMember; import net.kyori.adventure.text.Component; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -@CommandParameters(name = "sethome", aliases = "setspawn", usage = "/guild ", description = "Sets the guild's home") -@CommandPermissions(source = RequiredCommandSource.IN_GAME, permission = "plex.guilds.sethome") -public class SetHomeSubCommand extends PlexCommand -{ - public SetHomeSubCommand() - { - super(false); - } +import java.util.Collections; +import java.util.List; +@CommandParameters(name = "sethome", usage = "/guild [clear]", description = "Set or clear your guild's home location") +@CommandPermissions(source = RequiredCommandSource.IN_GAME, permission = "plex.guilds.sethome") +public class SetHomeSubCommand extends SubCommand +{ @Override - protected Component execute(@NotNull CommandSender commandSender, @Nullable Player player, @NotNull String[] args) + public Component run(@NotNull CommandSender sender, @Nullable Player player, @NotNull String[] args) { assert player != null; - Guilds.get().getGuildHolder().getGuild(player.getUniqueId()).ifPresentOrElse(guild -> - { - if (!guild.getOwner().getUuid().equals(player.getUniqueId())) - { - send(player, messageComponent("guildNotOwner")); - return; - } - if (args.length > 0 && (args[0].equalsIgnoreCase("remove") || args[0].equalsIgnoreCase("unset") || args[0].equalsIgnoreCase("clear"))) - { - if (guild.getHome() == null) + GuildMember member = Guilds.get().getMemberData().getMember(player).orElseThrow(); + member.getGuild().ifPresentOrElse(guild -> { - send(player, messageComponent("guildHomeNotFound")); - return; - } - guild.setHome(null); - send(player, messageComponent("guildHomeRemoved")); - return; - } - guild.setHome(CustomLocation.fromLocation(player.getLocation())); - send(player, messageComponent("guildHomeSet")); - }, () -> send(player, messageComponent("guildNotFound"))); + if (!guild.isOwner(member)) + { + send(player, messageComponent("guildNotOwner")); + return; + } + + if (args.length == 1 && args[0].equalsIgnoreCase("clear")) + { + if (guild.getHome() == null) + { + send(player, messageComponent("guildHomeNotFound")); + return; + } + + guild.setHome(null); + send(player, messageComponent("guildHomeRemoved")); + return; + } + + guild.setHome(player.getLocation()); + send(player, messageComponent("guildHomeSet")); + }, + () -> send(player, messageComponent("guildNotFound"))); return null; } @Override - public @NotNull List smartTabComplete(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] strings) throws IllegalArgumentException + public @NotNull List smartTabComplete(@NotNull CommandSender sender, @NotNull String s, @NotNull String[] args) throws IllegalArgumentException { + if (args.length == 1 && silentCheckPermission(sender, getPermission())) + { + return Collections.singletonList("clear"); + } return Collections.emptyList(); } } diff --git a/src/main/java/dev/plex/command/sub/SetOwnerSubCommand.java b/src/main/java/dev/plex/command/sub/SetOwnerSubCommand.java new file mode 100644 index 0000000..c55661d --- /dev/null +++ b/src/main/java/dev/plex/command/sub/SetOwnerSubCommand.java @@ -0,0 +1,65 @@ +package dev.plex.command.sub; + +import dev.plex.Guilds; +import dev.plex.command.SubCommand; +import dev.plex.command.annotation.CommandParameters; +import dev.plex.command.annotation.CommandPermissions; +import dev.plex.command.source.RequiredCommandSource; +import dev.plex.guild.GuildMember; +import dev.plex.util.PlexUtils; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +@CommandParameters(name = "setowner", usage = "/guild ", description = "Transfer the ownership of your guild to another player") +@CommandPermissions(source = RequiredCommandSource.IN_GAME, permission = "plex.guilds.setowner") +public class SetOwnerSubCommand extends SubCommand +{ + @Override + public Component run(CommandSender sender, Player player, String[] args) + { + if (args.length != 1) + { + return usage(); + } + + assert player != null; + GuildMember member = Guilds.get().getMemberData().getMember(player).orElseThrow(); + member.getGuild().ifPresentOrElse(guild -> + { + if (!guild.isOwner(member)) + { + send(player, messageComponent("guildNotOwner")); + return; + } + + Player target = getNonNullPlayer(args[0]); + GuildMember targetMember = Guilds.get().getMemberData().getMember(target).orElseThrow(); + if (targetMember.getGuild().isEmpty() || !targetMember.getGuild().get().equals(guild)) + { + send(player, messageComponent("guildMemberNotFound")); + return; + } + + guild.setOwner(targetMember); + send(player, messageComponent("guildOwnerSet", target.getName())); + }, + () -> send(player, messageComponent("guildNotFound"))); + return null; + } + + @Override + public @NotNull List smartTabComplete(@NotNull CommandSender sender, @NotNull String s, @NotNull String[] args) throws IllegalArgumentException + { + if (args.length == 1 && silentCheckPermission(sender, getPermission())) + { + return PlexUtils.getPlayerNameList(); + } + return Collections.emptyList(); + } +} diff --git a/src/main/java/dev/plex/command/sub/SetWarpSubCommand.java b/src/main/java/dev/plex/command/sub/SetWarpSubCommand.java index 3550140..77051dd 100644 --- a/src/main/java/dev/plex/command/sub/SetWarpSubCommand.java +++ b/src/main/java/dev/plex/command/sub/SetWarpSubCommand.java @@ -1,69 +1,68 @@ package dev.plex.command.sub; import dev.plex.Guilds; -import dev.plex.command.PlexCommand; +import dev.plex.command.SubCommand; import dev.plex.command.annotation.CommandParameters; import dev.plex.command.annotation.CommandPermissions; import dev.plex.command.source.RequiredCommandSource; -import dev.plex.util.CustomLocation; -import java.util.Collections; -import java.util.List; -import java.util.Locale; +import dev.plex.guild.GuildMember; import net.kyori.adventure.text.Component; import org.apache.commons.lang3.StringUtils; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -@CommandParameters(name = "setwarp", aliases = "makewarp,createwarp", usage = "/guild ", description = "Creates a new warp at player's location with a specified name") +import java.util.Collections; +import java.util.List; + +@CommandParameters(name = "setwarp", aliases = "createwarp", usage = "/guild ", description = "Creates a new guild warp at your location with a specified name") @CommandPermissions(source = RequiredCommandSource.IN_GAME, permission = "plex.guilds.setwarp") -public class SetWarpSubCommand extends PlexCommand +public class SetWarpSubCommand extends SubCommand { - public SetWarpSubCommand() - { - super(false); - } - @Override - protected Component execute(@NotNull CommandSender commandSender, @Nullable Player player, @NotNull String[] args) + public Component run(CommandSender sender, Player player, String[] args) { if (args.length == 0) { return usage(); } + assert player != null; - Guilds.get().getGuildHolder().getGuild(player.getUniqueId()).ifPresentOrElse(guild -> - { - if (!guild.getOwner().getUuid().equals(player.getUniqueId())) - { - send(player, messageComponent("guildNotOwner")); - return; - } - String warpName = StringUtils.join(args, " "); - if (warpName.length() > 16) - { - send(player, mmString("The max length of a warp name is 16 characters!")); - return; - } - if (guild.getWarps().containsKey(warpName.toLowerCase())) - { - send(player, messageComponent("guildWarpExists", warpName)); - return; - } - if (!StringUtils.isAlphanumericSpace(warpName.toLowerCase(Locale.ROOT))) - { - send(player, messageComponent("guildWarpAlphanumeric")); - return; - } - guild.getWarps().put(warpName.toLowerCase(), CustomLocation.fromLocation(player.getLocation())); - send(player, messageComponent("guildWarpCreated", warpName)); - }, () -> send(player, messageComponent("guildNotFound"))); + GuildMember member = Guilds.get().getMemberData().getMember(player).orElseThrow(); + member.getGuild().ifPresentOrElse(guild -> + { + if (!guild.isModerator(member)) + { + send(player, messageComponent("guildNotMod")); + return; + } + + String name = StringUtils.join(args, " ").toLowerCase(); + if (name.length() > 16) + { + send(player, mmString("The max length of a warp name is 16 characters!")); + return; + } + + if (!StringUtils.isAlphanumericSpace(name)) + { + send(player, messageComponent("guildWarpAlphanumeric")); + return; + } + + guild.getWarp(name).ifPresentOrElse(guildWarp -> send(player, messageComponent("guildWarpExists", name)), + () -> + { + guild.createWarp(name, player.getLocation()); + send(player, messageComponent("guildWarpCreated", name)); + }); + }, + () -> send(player, messageComponent("guildNotFound"))); return null; } @Override - public @NotNull List smartTabComplete(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] strings) throws IllegalArgumentException + public @NotNull List smartTabComplete(@NotNull CommandSender sender, @NotNull String s, @NotNull String[] args) throws IllegalArgumentException { return Collections.emptyList(); } diff --git a/src/main/java/dev/plex/command/sub/WarpListSubCommand.java b/src/main/java/dev/plex/command/sub/WarpListSubCommand.java deleted file mode 100644 index 4c50f25..0000000 --- a/src/main/java/dev/plex/command/sub/WarpListSubCommand.java +++ /dev/null @@ -1,62 +0,0 @@ -package dev.plex.command.sub; - -import com.google.common.collect.Lists; -import dev.plex.Guilds; -import dev.plex.command.PlexCommand; -import dev.plex.command.annotation.CommandParameters; -import dev.plex.command.annotation.CommandPermissions; -import dev.plex.command.source.RequiredCommandSource; -import dev.plex.guild.Guild; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import net.kyori.adventure.text.Component; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -@CommandParameters(name = "warps", aliases = "listwarps", usage = "/guild ", description = "Displays a clickable list of warps") -@CommandPermissions(source = RequiredCommandSource.IN_GAME, permission = "plex.guilds.warps") -public class WarpListSubCommand extends PlexCommand -{ - public WarpListSubCommand() - { - super(false); - } - - @Override - protected Component execute(@NotNull CommandSender commandSender, @Nullable Player player, @NotNull String[] args) - { - assert player != null; - Guilds.get().getGuildHolder().getGuild(player.getUniqueId()).ifPresentOrElse(guild -> - { - send(player, getWarps(guild)); - }, () -> send(player, messageComponent("guildNotFound"))); - return null; - } - - public Component getWarps(Guild guild) - { - Set warps = guild.getWarps().keySet(); - - List components = Lists.newArrayList(); - warps.forEach(s -> components.add(mmString("" + s))); - Component parent = mmString("Warps (" + warps.size() + "): "); - for (int i = 0; i < components.size(); i++) - { - parent = parent.append(components.get(i)); - if (i < components.size() - 1) - { - parent = parent.append(mmString(", ")); - } - } - return parent; - } - - @Override - public @NotNull List smartTabComplete(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] strings) throws IllegalArgumentException - { - return Collections.emptyList(); - } -} diff --git a/src/main/java/dev/plex/command/sub/WarpSubCommand.java b/src/main/java/dev/plex/command/sub/WarpSubCommand.java index 7be37f3..46066d2 100644 --- a/src/main/java/dev/plex/command/sub/WarpSubCommand.java +++ b/src/main/java/dev/plex/command/sub/WarpSubCommand.java @@ -1,52 +1,60 @@ package dev.plex.command.sub; +import com.google.common.collect.Lists; import dev.plex.Guilds; -import dev.plex.command.PlexCommand; +import dev.plex.command.SubCommand; import dev.plex.command.annotation.CommandParameters; import dev.plex.command.annotation.CommandPermissions; import dev.plex.command.source.RequiredCommandSource; -import java.util.Collections; -import java.util.List; +import dev.plex.guild.GuildMember; import net.kyori.adventure.text.Component; import org.apache.commons.lang3.StringUtils; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -@CommandParameters(name = "warp", aliases = "goto", usage = "/guild ", description = "Warps to a specified guild warp") +import java.util.Collections; +import java.util.List; + +@CommandParameters(name = "warp", usage = "/guild [name]", description = "List existing warps under your guild or warp to a specified guild warp location") @CommandPermissions(source = RequiredCommandSource.IN_GAME, permission = "plex.guilds.warp") -public class WarpSubCommand extends PlexCommand +public class WarpSubCommand extends SubCommand { - public WarpSubCommand() - { - super(false); - } - @Override - protected Component execute(@NotNull CommandSender commandSender, @Nullable Player player, @NotNull String[] args) + public Component run(CommandSender sender, Player player, String[] args) { - if (args.length == 0) - { - return usage(); - } assert player != null; - Guilds.get().getGuildHolder().getGuild(player.getUniqueId()).ifPresentOrElse(guild -> - { - String warpName = StringUtils.join(args, " "); - if (!guild.getWarps().containsKey(warpName.toLowerCase())) - { - send(player, messageComponent("guildWarpNotFound", warpName)); - return; - } - player.teleportAsync(guild.getWarps().get(warpName.toLowerCase()).toLocation()); - }, () -> send(player, messageComponent("guildNotFound"))); + GuildMember member = Guilds.get().getMemberData().getMember(player).orElseThrow(); + member.getGuild().ifPresentOrElse(guild -> + { + if (args.length == 0) + { + send(player, guild.getWarps()); + return; + } + + String name = StringUtils.join(args, " ").toLowerCase(); + guild.getWarp(name).ifPresentOrElse(warp -> + { + player.teleportAsync(warp.getLocation()); + send(player, messageComponent("guildWarpSuccess", name)); + }, + () -> send(player, messageComponent("guildWarpNotFound", name))); + }, + () -> send(player, messageComponent("guildNotFound"))); return null; } @Override - public @NotNull List smartTabComplete(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] strings) throws IllegalArgumentException + public @NotNull List smartTabComplete(@NotNull CommandSender sender, @NotNull String s, @NotNull String[] args) throws IllegalArgumentException { + if (args.length == 1 && silentCheckPermission(sender, getPermission())) + { + GuildMember member = Guilds.get().getMemberData().getMember((Player) sender).orElseThrow(); + List names = Lists.newArrayList(); + member.getGuild().ifPresent(guild -> names.addAll(guild.getWarpNames())); + return names; + } return Collections.emptyList(); } } diff --git a/src/main/java/dev/plex/data/GuildData.java b/src/main/java/dev/plex/data/GuildData.java new file mode 100644 index 0000000..044586c --- /dev/null +++ b/src/main/java/dev/plex/data/GuildData.java @@ -0,0 +1,45 @@ +package dev.plex.data; + +import com.google.common.collect.Lists; +import dev.plex.Guilds; +import dev.plex.guild.Guild; +import dev.plex.guild.GuildMember; +import lombok.Getter; + +import java.util.List; +import java.util.Optional; + +@Getter +public class GuildData +{ + private final List guilds = Lists.newArrayList(); + + public void addGuild(Guild guild) + { + guilds.add(guild); + } + + public void addNewGuild(Guild guild) + { + Guilds.get().getSqlManager().insertGuild(guild); + addGuild(guild); + } + + public void deleteGuild(GuildMember player) + { + if (guilds.removeIf(g -> g.getOwner().getUuid().equals(player.getUuid()))) + { + Guilds.get().getSqlManager().deleteGuild(player.getPlayer().getPlayer()); + } + } + + public Optional getGuildByName(String name) + { + return guilds.stream().filter(g -> g.getName().equalsIgnoreCase(name)).findFirst(); + } + + public Optional getGuildByMember(GuildMember member) + { + return guilds.stream().filter(g -> g.getMembers().contains(member)).findFirst(); + } +} diff --git a/src/main/java/dev/plex/data/MemberData.java b/src/main/java/dev/plex/data/MemberData.java new file mode 100644 index 0000000..52d076b --- /dev/null +++ b/src/main/java/dev/plex/data/MemberData.java @@ -0,0 +1,54 @@ +package dev.plex.data; + +import com.google.common.collect.Lists; +import dev.plex.Guilds; +import dev.plex.guild.GuildMember; +import lombok.Getter; +import org.bukkit.entity.Player; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; + +@Getter +public class MemberData +{ + private final List members = Lists.newArrayList(); + + public void addMember(GuildMember member) + { + members.add(member); + } + + public GuildMember addNewMember(Player player) + { + AtomicReference memberReference = new AtomicReference<>(new GuildMember(player.getUniqueId())); + Guilds.get().getSqlManager().insertMember(memberReference.get()).whenComplete((m, throwable) -> + { + memberReference.set(m); + addMember(m); + }); + return memberReference.get(); + } + + public Optional getMemberByName(String name) + { + return members.stream().filter(p -> p.getPlayer().getName().equalsIgnoreCase(name)).findFirst(); + } + + public Optional getMemberByUUID(UUID uuid) + { + return members.stream().filter(p -> p.getUuid().equals(uuid)).findFirst(); + } + + public Optional getMemberByID(int id) + { + return members.stream().filter(p -> p.getId() == id).findFirst(); + } + + public Optional getMember(Player player) + { + return getMemberByUUID(player.getUniqueId()); + } +} diff --git a/src/main/java/dev/plex/data/SQLGuildManager.java b/src/main/java/dev/plex/data/SQLGuildManager.java deleted file mode 100644 index ae8ae44..0000000 --- a/src/main/java/dev/plex/data/SQLGuildManager.java +++ /dev/null @@ -1,162 +0,0 @@ -package dev.plex.data; - -import com.google.common.collect.Lists; -import com.google.common.reflect.TypeToken; -import com.google.gson.Gson; -import dev.plex.Plex; -import dev.plex.guild.Guild; -import dev.plex.guild.data.Member; -import dev.plex.util.CustomLocation; -import dev.plex.util.GuildUtil; -import dev.plex.util.PlexLog; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.time.Instant; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; - -public class SQLGuildManager -{ - private static final Gson GSON = new Gson(); - - private static final String SELECT_GUILD = "SELECT * FROM `guilds`"; - private static final String INSERT_GUILD = "INSERT INTO `guilds` (`guildUuid`, `name`, `owner`, `createdAt`, `members`, `moderators`, `prefix`, `motd`, `ranks`, `defaultRank`, `warps`, `home`, `tagEnabled`, `isPublic`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; - private static final String DELETE_GUILD = "DELETE FROM `guilds` WHERE guildUuid=?"; - private static final String UPDATE_GUILD = "UPDATE `guilds` SET name=?, owner=?, members=?, moderators=?, prefix=?, motd=?, ranks=?, defaultRank=?, home=?, warps=?, tagEnabled=?, isPublic=? WHERE guildUuid=?"; - - public CompletableFuture insertGuild(Guild guild) - { - return CompletableFuture.supplyAsync(() -> - { - try (Connection connection = Plex.get().getSqlConnection().getCon()) - { - PreparedStatement statement = connection.prepareStatement(INSERT_GUILD); - statement.setString(1, guild.getGuildUuid().toString()); - statement.setString(2, guild.getName()); - statement.setString(3, GSON.toJson(guild.getOwner())); - statement.setLong(4, guild.getCreatedAt().toInstant().toEpochMilli()); - statement.setString(5, GSON.toJson(guild.getMembers())); - statement.setString(6, GSON.toJson(guild.getModerators().stream().map(UUID::toString).collect(Collectors.toList()))); - statement.setString(7, guild.getPrefix()); - statement.setString(8, guild.getMotd()); - statement.setString(9, GSON.toJson(guild.getRanks())); - statement.setString(10, GSON.toJson(guild.getDefaultRank())); - statement.setString(11, GSON.toJson(guild.getWarps())); - statement.setString(12, GSON.toJson(guild.getHome())); - statement.setBoolean(13, guild.isTagEnabled()); - statement.setBoolean(14, guild.isPublic()); - statement.execute(); - return guild; - } - catch (SQLException e) - { - GuildUtil.throwExceptionSync(e); - return null; - } - }); - } - - public CompletableFuture deleteGuild(UUID uuid) - { - return CompletableFuture.runAsync(() -> - { - try (Connection connection = Plex.get().getSqlConnection().getCon()) - { - PreparedStatement statement = connection.prepareStatement(DELETE_GUILD); - statement.setString(1, uuid.toString()); - statement.execute(); - } - catch (SQLException e) - { - GuildUtil.throwExceptionSync(e); - } - }); - } - - public CompletableFuture updateGuild(Guild guild) - { - return CompletableFuture.supplyAsync(() -> - { - try (Connection connection = Plex.get().getSqlConnection().getCon()) - { - PreparedStatement statement = connection.prepareStatement(UPDATE_GUILD); - statement.setString(1, guild.getName()); - statement.setString(2, GSON.toJson(guild.getOwner())); - statement.setString(3, GSON.toJson(guild.getMembers())); - statement.setString(4, GSON.toJson(guild.getModerators().stream().map(UUID::toString).collect(Collectors.toList()))); - statement.setString(5, guild.getPrefix()); - statement.setString(6, guild.getMotd()); - statement.setString(7, GSON.toJson(guild.getRanks())); - statement.setString(8, GSON.toJson(guild.getDefaultRank())); - statement.setString(9, GSON.toJson(guild.getHome())); - statement.setString(10, GSON.toJson(guild.getWarps())); - statement.setBoolean(11, guild.isTagEnabled()); - statement.setBoolean(12, guild.isPublic()); - statement.setString(13, guild.getGuildUuid().toString()); - statement.executeUpdate(); - return guild; - } - catch (SQLException e) - { - GuildUtil.throwExceptionSync(e); - return null; - } - }); - } - - private List getGuildsSync() - { - List guilds = Lists.newArrayList(); - try (Connection connection = Plex.get().getSqlConnection().getCon()) - { - PreparedStatement statement = connection.prepareStatement(SELECT_GUILD); - ResultSet set = statement.executeQuery(); - while (set.next()) - { - Guild guild = new Guild(UUID.fromString(set.getString("guildUuid")), - ZonedDateTime.ofInstant(Instant.ofEpochMilli(set.getLong("createdAt")), ZoneId.of(Plex.get().config.getString("server.timezone")).getRules().getOffset(Instant.now()))); - guild.setName(set.getString("name")); - guild.setOwner(GSON.fromJson(set.getString("owner"), Member.class)); - List members = new Gson().fromJson(set.getString("members"), new TypeToken>() - { - }.getType()); - members.forEach(guild::addMember); - guild.getModerators().addAll(new Gson().fromJson(set.getString("moderators"), new TypeToken>() - { - }.getType())); - guild.setPrefix(set.getString("prefix")); - guild.setMotd(set.getString("motd")); - guild.setHome(GSON.fromJson(set.getString("home"), CustomLocation.class)); - guild.setTagEnabled(set.getBoolean("tagEnabled")); - Map warps = GSON.fromJson(set.getString("warps"), new TypeToken>() - { - }.getType()); - PlexLog.debug("Loaded {0} warps for {1} guild", warps.size(), guild.getName()); - guild.getWarps().putAll(GSON.fromJson(set.getString("warps"), new TypeToken>() - { - }.getType())); - guild.setPublic(set.getBoolean("isPublic")); - guilds.add(guild); - } - } - catch (SQLException e) - { - GuildUtil.throwExceptionSync(e); - } - return guilds; - } - - public CompletableFuture> getGuilds() - { - return CompletableFuture.supplyAsync(this::getGuildsSync); - } - -} diff --git a/src/main/java/dev/plex/data/SQLManager.java b/src/main/java/dev/plex/data/SQLManager.java deleted file mode 100644 index f932b4b..0000000 --- a/src/main/java/dev/plex/data/SQLManager.java +++ /dev/null @@ -1,39 +0,0 @@ -package dev.plex.data; - -import dev.plex.Plex; - -import java.sql.Connection; -import java.sql.SQLException; - -public class SQLManager -{ - public static void makeTables() - { - try (Connection connection = Plex.get().getSqlConnection().getCon()) - { - connection.prepareStatement( - "CREATE TABLE IF NOT EXISTS `guilds` (" + - "`guildUuid` VARCHAR(46) NOT NULL, " + - "`name` VARCHAR(2000) NOT NULL, " + - "`owner` LONGTEXT NOT NULL, " + - "`createdAt` BIGINT NOT NULL, " + - "`prefix` VARCHAR(2000), " + - "`motd` VARCHAR(3000), " + - "`home` VARCHAR(1000)," + - "`members` LONGTEXT, " + - "`moderators` LONGTEXT, " + - "`ranks` LONGTEXT, " + - "`defaultRank` LONGTEXT, " + - "`warps` LONGTEXT, " + - "`tagEnabled` BOOLEAN, " + - "`isPublic` BOOLEAN, " + - "PRIMARY KEY (`guildUuid`)" + - ");" - ).execute(); - } - catch (SQLException e) - { - e.printStackTrace(); - } - } -} diff --git a/src/main/java/dev/plex/guild/Guild.java b/src/main/java/dev/plex/guild/Guild.java index a1a7f64..800343c 100644 --- a/src/main/java/dev/plex/guild/Guild.java +++ b/src/main/java/dev/plex/guild/Guild.java @@ -1,72 +1,229 @@ package dev.plex.guild; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import dev.plex.Plex; -import dev.plex.guild.data.Member; -import dev.plex.guild.data.Rank; -import dev.plex.util.CustomLocation; -import dev.plex.util.minimessage.SafeMiniMessage; +import dev.plex.Guilds; +import dev.plex.util.PlexUtils; import lombok.Data; +import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; +import java.util.stream.Collectors; @Data public class Guild { - private final UUID guildUuid; - private final ZonedDateTime createdAt; - private final List members = Lists.newArrayList(); - private final List moderators = Lists.newArrayList(); - private final List ranks = Lists.newArrayList(); - private final Map warps = Maps.newHashMap(); + private final UUID uuid; + private final Date createdAt; private String name; - private Member owner; - private String prefix; - private String motd; - private CustomLocation home; - private boolean tagEnabled; - private Rank defaultRank = new Rank("default", null); - private boolean isPublic = false; + private String displayName = null; + private GuildMember owner; + private List members = Lists.newArrayList(); + private List moderators = Lists.newArrayList(); + private List ranks = Lists.newArrayList(); + private List warps = Lists.newArrayList(); + private GuildRank defaultRank = null; + private String prefix = null; + private boolean prefixEnabled = false; + private String motd = null; + private Location home; + private Privacy privacy = Privacy.PUBLIC; + private List pendingInvites = Lists.newArrayList(); - - public static Guild create(Player player, String guildName) + public static Guild create(GuildMember member, String name) { - Guild guild = new Guild(UUID.randomUUID(), ZonedDateTime.now(ZoneId.of(Plex.get().config.getString("server.timezone")))); - guild.setName(PlainTextComponentSerializer.plainText().serialize(SafeMiniMessage.mmDeserialize(guildName))); - guild.setOwner(new Member(player.getUniqueId())); + Guild guild = new Guild(UUID.randomUUID(), new Date()); + guild.setName(name); + guild.setOwner(member); + Guilds.get().getGuildData().addNewGuild(guild); return guild; } - public Member getMember(UUID uuid) + public void chat(Player player, Component message) { - if (owner.getUuid().equals(uuid)) + getMembers().stream().map(GuildMember::getPlayer).filter(OfflinePlayer::isOnline).map(OfflinePlayer::getPlayer).forEach(p -> p.sendMessage(PlexUtils.messageComponent("guildChatMessage", player.getName(), message))); + if (Guilds.get().getConfig().getBoolean("guilds.log-chat-message")) { - return owner; + Bukkit.getConsoleSender().sendMessage(PlexUtils.messageComponent("guildChatConsoleLog", name, uuid, player.getName(), PlainTextComponentSerializer.plainText().serialize(message))); } - return members.stream().filter(m -> m.getUuid().equals(uuid)).findFirst().orElse(null); } - public void addMember(UUID uuid) + public String getDisplayName() { - addMember(new Member(uuid)); + return displayName != null ? displayName : name; } - public void addMember(Member member) + public boolean isOwner(GuildMember member) { - this.members.add(member); + return owner.equals(member); } - public List getMembers() + public void setOwner(GuildMember member) { - List allMembers = Lists.newArrayList(members); - allMembers.add(owner); - return allMembers; + members.add(owner); + members.remove(member); + owner = member; + } + + public boolean isMember(GuildMember member) + { + return getMembers().contains(member); + } + + public void addMember(GuildMember member) + { + members.add(member); + } + + public void removeMember(GuildMember member) + { + members.remove(member); + moderators.remove(member); + } + + public void setMemberRank(GuildMember member, GuildRank rank) + { + rank.addMember(member); + } + + public boolean isModerator(GuildMember member) + { + return moderators.contains(member) || owner.equals(member); + } + + public void addModerator(GuildMember member) + { + moderators.add(member); + } + + public void removeModerator(GuildMember member) + { + moderators.remove(member); + } + + public void createRank(String name) + { + GuildRank rank = new GuildRank(name); + Guilds.get().getSqlManager().insertRank(this, rank); + ranks.add(rank); + } + + public void deleteRank(GuildRank rank) + { + if (rank.equals(defaultRank)) + { + defaultRank = null; + } + + Guilds.get().getSqlManager().deleteRank(this, rank); + ranks.remove(rank); + } + + public void setDefaultRank(GuildRank rank) + { + Guilds.get().getSqlManager().updateDefaultRank(this, rank); + defaultRank = rank; + } + + public List getRanks() + { + List tempRanks = Lists.newArrayList(); + if (defaultRank != null) + { + tempRanks.add(defaultRank); + } + return tempRanks; + } + + public Optional getRankByName(String name) + { + return ranks.stream().filter(rank -> rank.getName().equalsIgnoreCase(name)).findFirst(); + } + + public Optional getRankByMember(GuildMember member) + { + return ranks.stream().filter(rank -> rank.getMembers().contains(member)).findFirst().or(() -> Optional.of(defaultRank)); + } + + public List getRankNames() + { + return getRanks().stream().map(GuildRank::getName).toList(); + } + + public void createWarp(String name, Location location) + { + GuildWarp warp = new GuildWarp(name, location); + Guilds.get().getSqlManager().insertWarp(this, warp); + warps.add(warp); + } + + public void deleteWarp(GuildWarp warp) + { + if (warps.removeIf(w -> w.getName().equals(warp.getName()))) + { + Guilds.get().getSqlManager().deleteWarp(this, warp); + } + } + + public Optional getWarp(String name) + { + return warps.stream().filter(warp -> warp.getName().equalsIgnoreCase(name)).findFirst(); + } + + public Component getWarps() + { + List components = Lists.newArrayList(); + getWarpNames().forEach(s -> components.add(PlexUtils.mmDeserialize("" + s))); + Component parent = PlexUtils.mmDeserialize("Warps (" + warps.size() + "): "); + for (int i = 0; i < components.size(); i++) + { + parent = parent.append(components.get(i)); + if (i < components.size() - 1) + { + parent = parent.append(PlexUtils.mmDeserialize(", ")); + } + } + return parent; + } + + public List getWarpNames() + { + return warps.stream().map(GuildWarp::getName).toList(); + } + + public List getMembers() + { + List temp = Lists.newArrayList(members); + temp.add(owner); + return temp; + } + + public List getMemberNames() + { + return members.stream().map(p -> p.getPlayer().getName()).toList(); + } + + public List getMemberIDs() + { + return members.stream().map(GuildMember::getId).collect(Collectors.toList()); + } + + public List getModeratorNames() + { + return moderators.stream().map(p -> p.getPlayer().getName()).toList(); + } + + public List getModeratorIDs() + { + return moderators.stream().map(GuildMember::getId).toList(); + } + + public enum Privacy + { + PUBLIC, PRIVATE, INVITE_ONLY } } diff --git a/src/main/java/dev/plex/guild/GuildHolder.java b/src/main/java/dev/plex/guild/GuildHolder.java deleted file mode 100644 index 094b7fe..0000000 --- a/src/main/java/dev/plex/guild/GuildHolder.java +++ /dev/null @@ -1,51 +0,0 @@ -package dev.plex.guild; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import dev.plex.guild.data.Member; - -import java.util.*; - -public class GuildHolder -{ - public static final Map> PENDING_INVITES = Maps.newHashMap(); - private static final List GUILDS = Lists.newArrayList(); - - public static boolean sendInvite(UUID uuid, Guild guild) - { - if (PENDING_INVITES.containsKey(uuid) && PENDING_INVITES.get(uuid).stream().anyMatch(guild1 -> guild1.getGuildUuid().equals(guild.getGuildUuid()))) - { - return false; - } - if (PENDING_INVITES.containsKey(uuid)) - { - PENDING_INVITES.get(uuid).add(guild); - } - else - { - PENDING_INVITES.put(uuid, Lists.newArrayList(guild)); - } - return true; - } - - public void addGuild(Guild guild) - { - GUILDS.add(guild); - } - - public void deleteGuild(UUID owner) - { - GUILDS.removeIf(guild -> guild.getOwner().getUuid().equals(owner)); - } - - public Optional getGuild(UUID uuid) - { - return GUILDS.stream().filter(guild -> (guild.getOwner() != null && guild.getOwner().getUuid().equals(uuid)) || guild.getMembers().stream().map(Member::getUuid).toList().contains(uuid)).findFirst(); - } - - public Collection getGuilds() - { - return GUILDS.stream().toList(); - } - -} diff --git a/src/main/java/dev/plex/guild/GuildMember.java b/src/main/java/dev/plex/guild/GuildMember.java new file mode 100644 index 0000000..b68a926 --- /dev/null +++ b/src/main/java/dev/plex/guild/GuildMember.java @@ -0,0 +1,28 @@ +package dev.plex.guild; + +import dev.plex.Guilds; +import lombok.Data; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; + +import java.util.Optional; +import java.util.UUID; + +@Data +public class GuildMember +{ + private final UUID uuid; + private int id = 0; + private boolean chat = false; + private boolean prefix = true; + + public OfflinePlayer getPlayer() + { + return Bukkit.getOfflinePlayer(uuid); + } + + public Optional getGuild() + { + return Guilds.get().getGuildData().getGuildByMember(this); + } +} diff --git a/src/main/java/dev/plex/guild/GuildRank.java b/src/main/java/dev/plex/guild/GuildRank.java new file mode 100644 index 0000000..fa67edc --- /dev/null +++ b/src/main/java/dev/plex/guild/GuildRank.java @@ -0,0 +1,29 @@ +package dev.plex.guild; + +import com.google.common.collect.Lists; +import lombok.Data; + +import java.util.List; +import java.util.stream.Collectors; + +@Data +public class GuildRank +{ + private final String name; + private List members = Lists.newArrayList(); + + public void addMember(GuildMember member) + { + members.add(member); + } + + public List getMemberNames() + { + return getMembers().stream().map(p -> p.getPlayer().getName()).collect(Collectors.toList()); + } + + public List getMemberIDs() + { + return getMembers().stream().map(GuildMember::getId).collect(Collectors.toList()); + } +} diff --git a/src/main/java/dev/plex/guild/GuildWarp.java b/src/main/java/dev/plex/guild/GuildWarp.java new file mode 100644 index 0000000..f4f5659 --- /dev/null +++ b/src/main/java/dev/plex/guild/GuildWarp.java @@ -0,0 +1,11 @@ +package dev.plex.guild; + +import lombok.Data; +import org.bukkit.Location; + +@Data +public class GuildWarp +{ + private final String name; + private final Location location; +} diff --git a/src/main/java/dev/plex/guild/data/Member.java b/src/main/java/dev/plex/guild/data/Member.java deleted file mode 100644 index fa60f6c..0000000 --- a/src/main/java/dev/plex/guild/data/Member.java +++ /dev/null @@ -1,20 +0,0 @@ -package dev.plex.guild.data; - -import lombok.Data; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - -import java.util.UUID; - -@Data -public class Member -{ - private final UUID uuid; - private Rank rank; - private boolean chat, prefix; - - public Player getPlayer() - { - return Bukkit.getPlayer(this.uuid); - } -} diff --git a/src/main/java/dev/plex/guild/data/Permission.java b/src/main/java/dev/plex/guild/data/Permission.java deleted file mode 100644 index fede3e8..0000000 --- a/src/main/java/dev/plex/guild/data/Permission.java +++ /dev/null @@ -1,6 +0,0 @@ -package dev.plex.guild.data; - -public enum Permission -{ - SET_WARP, WARPS, DELETE_WARP, WARP -} diff --git a/src/main/java/dev/plex/guild/data/Rank.java b/src/main/java/dev/plex/guild/data/Rank.java deleted file mode 100644 index 7af27d0..0000000 --- a/src/main/java/dev/plex/guild/data/Rank.java +++ /dev/null @@ -1,5 +0,0 @@ -package dev.plex.guild.data; - -public record Rank(String name, String prefix) -{ -} diff --git a/src/main/java/dev/plex/handler/ChatHandlerImpl.java b/src/main/java/dev/plex/handler/ChatHandlerImpl.java deleted file mode 100644 index 4808304..0000000 --- a/src/main/java/dev/plex/handler/ChatHandlerImpl.java +++ /dev/null @@ -1,96 +0,0 @@ -package dev.plex.handler; - -import dev.plex.Guilds; -import dev.plex.Plex; -import dev.plex.guild.data.Member; -import dev.plex.hook.VaultHook; -import dev.plex.player.PlexPlayer; -import dev.plex.util.PlexUtils; -import dev.plex.util.minimessage.SafeMiniMessage; -import io.papermc.paper.chat.ChatRenderer; -import io.papermc.paper.event.player.AsyncChatEvent; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.TextReplacementConfig; -import net.kyori.adventure.text.event.ClickEvent; -import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.minimessage.MiniMessage; -import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; -import net.kyori.adventure.text.minimessage.tag.standard.StandardTags; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.jetbrains.annotations.NotNull; - -import java.util.Objects; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; - -public class ChatHandlerImpl -{ - private final static TextReplacementConfig URL_REPLACEMENT_CONFIG = TextReplacementConfig.builder().match("(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]").replacement((matchResult, builder) -> Component.empty().content(matchResult.group()).clickEvent(ClickEvent.openUrl(matchResult.group()))).build(); - private final PlexChatRenderer renderer = new PlexChatRenderer(); - - @EventHandler - public void doChat(AsyncChatEvent event) - { - event.renderer(renderer); - Player player = event.getPlayer(); - Guilds.get().getGuildHolder().getGuild(player.getUniqueId()).ifPresent(guild -> - { - Member member = guild.getMember(player.getUniqueId()); - if (member == null) - { - return; - } - if (!member.isChat()) - { - return; - } - guild.getMembers().stream().map(Member::getPlayer).filter(Objects::nonNull).forEach(player1 -> - { - player1.sendMessage(PlexUtils.messageComponent("guildChatMessage", player.getName(), PlainTextComponentSerializer.plainText().serialize(event.message()))); - }); - if (Guilds.get().getConfig().isBoolean("guilds.log-chat-message")) - { - Bukkit.getConsoleSender().sendMessage(PlexUtils.messageComponent("guildChatConsoleLog", guild.getName(), guild.getGuildUuid(), player.getName(), PlainTextComponentSerializer.plainText().serialize(event.message()))); - } - event.setCancelled(true); - }); - } - - public static class PlexChatRenderer implements ChatRenderer - { - @Override - public @NotNull Component render(@NotNull Player source, @NotNull Component sourceDisplayName, @NotNull Component message, @NotNull Audience viewer) - { - String text = PlexUtils.getTextFromComponent(message); - - PlexPlayer plexPlayer = Plex.get().getPlayerCache().getPlexPlayerMap().get(source.getUniqueId()); - Component prefix = VaultHook.getPrefix(plexPlayer); - - AtomicBoolean guildPrefix = new AtomicBoolean(false); - AtomicReference component = new AtomicReference<>(Component.empty()); - Guilds.get().getGuildHolder().getGuild(source.getUniqueId()).ifPresent(guild -> - { - if (guild.getPrefix() != null) - { - component.set(component.get().append(SafeMiniMessage.mmDeserializeWithoutEvents(guild.getPrefix()))); - guildPrefix.set(true); - } - }); - - if (prefix != null) - { - if (guildPrefix.get()) - { - component.set(component.get().append(Component.space())); - } - component.set(component.get().append(prefix)); - } - - return component.get().append(Component.space()).append(PlexUtils.mmDeserialize(Plex.get().config.getString("chat.name-color", "") + MiniMessage.builder().tags(TagResolver.resolver(StandardTags.color(), StandardTags.rainbow(), StandardTags.decorations(), StandardTags.gradient(), StandardTags.transition())).build().serialize(sourceDisplayName))).append(Component.space()).append(Component.text("ยป").color(NamedTextColor.GRAY)).append(Component.space()).append(SafeMiniMessage.mmDeserializeWithoutEvents(text)).replaceText(URL_REPLACEMENT_CONFIG); - } - } -} diff --git a/src/main/java/dev/plex/listener/ChatListener.java b/src/main/java/dev/plex/listener/ChatListener.java new file mode 100644 index 0000000..1016929 --- /dev/null +++ b/src/main/java/dev/plex/listener/ChatListener.java @@ -0,0 +1,80 @@ +package dev.plex.listener; + +import dev.plex.Guilds; +import dev.plex.guild.GuildMember; +import dev.plex.util.minimessage.SafeMiniMessage; +import io.papermc.paper.chat.ChatRenderer; +import io.papermc.paper.event.player.AsyncChatEvent; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.atomic.AtomicReference; + +public class ChatListener extends PlexListener +{ + private GuildChatRenderer guildChatRenderer = null; + + @EventHandler(priority = EventPriority.HIGHEST) + public void onAsyncChat(AsyncChatEvent event) + { + if (event.isCancelled()) + { + return; + } + + if (guildChatRenderer == null) + { + guildChatRenderer = new GuildChatRenderer(event.renderer()); + } + + event.renderer(guildChatRenderer); + + final Player player = event.getPlayer(); + GuildMember member = Guilds.get().getMemberData().getMember(player).orElseThrow(); + member.getGuild().ifPresent(guild -> + { + if (member.isChat()) + { + guild.chat(player, event.message()); + event.setCancelled(true); + } + }); + } + + private record GuildChatRenderer(ChatRenderer renderer) implements ChatRenderer + { + @Override + public @NotNull Component render(@NotNull Player player, @NotNull Component sourceDisplayName, @NotNull Component message, @NotNull Audience audience) + { + Component outcome = Component.empty(); + GuildMember member = Guilds.get().getMemberData().getMember(player).orElseThrow(); + AtomicReference atomicPrefix = new AtomicReference<>(null); + + member.getGuild().ifPresent(guild -> + { + if (guild.isPrefixEnabled()) + { + String rankName = ""; + if (guild.getRankByMember(member).isPresent()) + { + rankName = guild.getRankByMember(member).get().getName(); + } + + atomicPrefix.set(guild.getPrefix().replace("%rank%", rankName).replace("%name%", guild.getDisplayName())); + } + }); + + if (atomicPrefix.get() != null && member.isPrefix()) + { + outcome = outcome.append(SafeMiniMessage.mmDeserializeWithoutEvents(atomicPrefix.get())).append(Component.space()); + } + + outcome = outcome.append(renderer.render(player, sourceDisplayName, message, audience)); + return outcome; + } + } +} diff --git a/src/main/java/dev/plex/listener/JoinListener.java b/src/main/java/dev/plex/listener/JoinListener.java new file mode 100644 index 0000000..a0a8223 --- /dev/null +++ b/src/main/java/dev/plex/listener/JoinListener.java @@ -0,0 +1,31 @@ +package dev.plex.listener; + +import dev.plex.Guilds; +import dev.plex.guild.GuildMember; +import dev.plex.util.PlexUtils; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerJoinEvent; + +public class JoinListener extends PlexListener +{ + @EventHandler(priority = EventPriority.NORMAL) + public void onPlayerJoin(PlayerJoinEvent event) + { + final Player player = event.getPlayer(); + GuildMember member = Guilds.get().getMemberData().getMember(player).orElse(Guilds.get().getMemberData().addNewMember(player)); + if (member == null) + { + throw new RuntimeException("Unable to obtain member data for %s".formatted(player.getName())); + } + + member.getGuild().ifPresent(guild -> + { + if (guild.getMotd() != null) + { + player.sendMessage(PlexUtils.mmDeserialize(guild.getMotd())); + } + }); + } +} diff --git a/src/main/java/dev/plex/util/CustomLocation.java b/src/main/java/dev/plex/util/CustomLocation.java deleted file mode 100644 index 707b660..0000000 --- a/src/main/java/dev/plex/util/CustomLocation.java +++ /dev/null @@ -1,23 +0,0 @@ -package dev.plex.util; - -import lombok.Data; -import org.bukkit.Bukkit; -import org.bukkit.Location; - -@Data -public class CustomLocation -{ - private final String worldName; - private final double x, y, z; - private final float yaw, pitch; - - public static CustomLocation fromLocation(Location location) - { - return new CustomLocation(location.getWorld().getName(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - } - - public Location toLocation() - { - return new Location(Bukkit.getWorld(worldName), x, y, z, yaw, pitch); - } -} diff --git a/src/main/java/dev/plex/util/GuildUtil.java b/src/main/java/dev/plex/util/GuildUtil.java deleted file mode 100644 index 3aaa61e..0000000 --- a/src/main/java/dev/plex/util/GuildUtil.java +++ /dev/null @@ -1,14 +0,0 @@ -package dev.plex.util; - -import dev.plex.Plex; -import org.bukkit.Bukkit; - -public class GuildUtil -{ - - public static void throwExceptionSync(Throwable throwable) - { - Bukkit.getScheduler().runTask(Plex.get(), () -> throwable.printStackTrace()); - } - -}