diff --git a/commons/src/main/java/net/swofty/commons/ServiceType.java b/commons/src/main/java/net/swofty/commons/ServiceType.java index 8dfd259b0..c517346bf 100644 --- a/commons/src/main/java/net/swofty/commons/ServiceType.java +++ b/commons/src/main/java/net/swofty/commons/ServiceType.java @@ -12,5 +12,6 @@ public enum ServiceType { FRIEND, PUNISHMENT, ELECTION, + GUILD, ; } diff --git a/commons/src/main/java/net/swofty/commons/guild/GuildData.java b/commons/src/main/java/net/swofty/commons/guild/GuildData.java new file mode 100644 index 000000000..b7cbb595c --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/GuildData.java @@ -0,0 +1,274 @@ +package net.swofty.commons.guild; + +import lombok.Getter; +import lombok.Setter; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.UUID; + +@Getter +@Setter +public class GuildData { + private final UUID guildId; + private String name; + private String tag; + private String tagColor; + private final List members; + private final List ranks; + private long totalGexp; + private int level; + private String motd; + private String description; + private String discordLink; + private boolean listedInFinder; + private boolean slowChat; + private boolean everyoneMuted; + private long everyoneMutedExpiry; + private long createdAt; + + public static final int MAX_MEMBERS = 125; + private static final int MAX_CUSTOM_RANKS = 3; + private static final int TAG_UNLOCK_LEVEL = 5; + + private static final long[] LEVEL_THRESHOLDS = { + 100000, 150000, 250000, 500000, 750000, + 1000000, 1250000, 1500000, 2000000, 2500000, + 2500000, 3000000, 3000000, 3500000, 4000000, + 4500000, 5000000, 5500000, 6000000, 6500000, + 7000000, 7500000, 8000000, 8500000, 9000000, + 10000000, 11000000, 12000000, 13000000, 14000000 + }; + + public GuildData(UUID guildId, String name, UUID masterUuid) { + this.guildId = guildId; + this.name = name; + this.tag = ""; + this.tagColor = "§7"; + this.members = new ArrayList<>(); + this.ranks = new ArrayList<>(List.of( + GuildRank.guildMaster(), + GuildRank.officer(), + GuildRank.member() + )); + this.totalGexp = 0; + this.level = 0; + this.motd = ""; + this.description = ""; + this.discordLink = ""; + this.listedInFinder = true; + this.slowChat = false; + this.everyoneMuted = false; + this.everyoneMutedExpiry = 0; + this.createdAt = System.currentTimeMillis(); + + this.members.add(new GuildMember(masterUuid, "Guild Master", System.currentTimeMillis())); + } + + private GuildData(UUID guildId, String name, String tag, String tagColor, + List members, List ranks, + long totalGexp, int level, String motd, String description, + String discordLink, boolean listedInFinder, boolean slowChat, + boolean everyoneMuted, long everyoneMutedExpiry, long createdAt) { + this.guildId = guildId; + this.name = name; + this.tag = tag; + this.tagColor = tagColor; + this.members = members; + this.ranks = ranks; + this.totalGexp = totalGexp; + this.level = level; + this.motd = motd; + this.description = description; + this.discordLink = discordLink; + this.listedInFinder = listedInFinder; + this.slowChat = slowChat; + this.everyoneMuted = everyoneMuted; + this.everyoneMutedExpiry = everyoneMutedExpiry; + this.createdAt = createdAt; + } + + public UUID getMasterUuid() { + return members.stream() + .filter(m -> m.getRankName().equals("Guild Master")) + .map(GuildMember::getUuid) + .findFirst() + .orElseThrow(); + } + + public GuildMember getMember(UUID uuid) { + return members.stream() + .filter(m -> m.getUuid().equals(uuid)) + .findFirst() + .orElse(null); + } + + public GuildRank getRank(String name) { + return ranks.stream() + .filter(r -> r.getName().equalsIgnoreCase(name)) + .findFirst() + .orElse(null); + } + + public GuildRank getMemberRank(UUID uuid) { + GuildMember member = getMember(uuid); + if (member == null) return null; + return getRank(member.getRankName()); + } + + public boolean isFull() { + return members.size() >= MAX_MEMBERS; + } + + public boolean canAddCustomRank() { + long customCount = ranks.stream().filter(r -> !r.isDefault()).count(); + return customCount < MAX_CUSTOM_RANKS; + } + + public boolean canSetTag() { + return level >= TAG_UNLOCK_LEVEL; + } + + public int getMaxTagLength() { + if (level >= 50) return 7; + return 5; + } + + public boolean canUseSpecialTagChars() { + return level >= 65; + } + + public List getAllMemberUuids() { + return members.stream().map(GuildMember::getUuid).toList(); + } + + public void addGexp(long amount) { + this.totalGexp += amount; + recalculateLevel(); + } + + public long getGexpForLevel(int targetLevel) { + if (targetLevel <= 0) return 0; + int idx = Math.min(targetLevel - 1, LEVEL_THRESHOLDS.length - 1); + return LEVEL_THRESHOLDS[idx]; + } + + private void recalculateLevel() { + long accumulated = 0; + int newLevel = 0; + for (int i = 0; i < 200; i++) { + long needed = getGexpForLevel(i + 1); + accumulated += needed; + if (totalGexp >= accumulated) { + newLevel = i + 1; + } else { + break; + } + } + this.level = newLevel; + } + + public GuildRank getNextRankUp(GuildRank currentRank) { + return ranks.stream() + .filter(r -> r.getPriority() < currentRank.getPriority()) + .max(Comparator.comparingInt(GuildRank::getPriority)) + .orElse(null); + } + + public GuildRank getNextRankDown(GuildRank currentRank) { + return ranks.stream() + .filter(r -> r.getPriority() > currentRank.getPriority()) + .min(Comparator.comparingInt(GuildRank::getPriority)) + .orElse(null); + } + + public Serializer getSerializer() { + return getStaticSerializer(); + } + + public static Serializer getStaticSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildData value) { + JSONObject json = new JSONObject(); + json.put("guildId", value.guildId.toString()); + json.put("name", value.name); + json.put("tag", value.tag); + json.put("tagColor", value.tagColor); + json.put("totalGexp", value.totalGexp); + json.put("level", value.level); + json.put("motd", value.motd); + json.put("description", value.description); + json.put("discordLink", value.discordLink); + json.put("listedInFinder", value.listedInFinder); + json.put("slowChat", value.slowChat); + json.put("everyoneMuted", value.everyoneMuted); + json.put("everyoneMutedExpiry", value.everyoneMutedExpiry); + json.put("createdAt", value.createdAt); + + JSONArray membersArr = new JSONArray(); + Serializer memberSerializer = GuildMember.serializer(); + for (GuildMember m : value.members) { + membersArr.put(new JSONObject(memberSerializer.serialize(m))); + } + json.put("members", membersArr); + + JSONArray ranksArr = new JSONArray(); + Serializer rankSerializer = GuildRank.serializer(); + for (GuildRank r : value.ranks) { + ranksArr.put(new JSONObject(rankSerializer.serialize(r))); + } + json.put("ranks", ranksArr); + + return json.toString(); + } + + @Override + public GuildData deserialize(String json) { + JSONObject obj = new JSONObject(json); + Serializer memberSerializer = GuildMember.serializer(); + Serializer rankSerializer = GuildRank.serializer(); + + List members = new ArrayList<>(); + JSONArray membersArr = obj.getJSONArray("members"); + for (int i = 0; i < membersArr.length(); i++) { + members.add(memberSerializer.deserialize(membersArr.getJSONObject(i).toString())); + } + + List ranks = new ArrayList<>(); + JSONArray ranksArr = obj.getJSONArray("ranks"); + for (int i = 0; i < ranksArr.length(); i++) { + ranks.add(rankSerializer.deserialize(ranksArr.getJSONObject(i).toString())); + } + + return new GuildData( + UUID.fromString(obj.getString("guildId")), + obj.getString("name"), + obj.getString("tag"), + obj.getString("tagColor"), + members, + ranks, + obj.getLong("totalGexp"), + obj.getInt("level"), + obj.getString("motd"), + obj.getString("description"), + obj.getString("discordLink"), + obj.getBoolean("listedInFinder"), + obj.getBoolean("slowChat"), + obj.getBoolean("everyoneMuted"), + obj.getLong("everyoneMutedExpiry"), + obj.getLong("createdAt") + ); + } + + @Override + public GuildData clone(GuildData value) { + return deserialize(serialize(value)); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/GuildEvent.java b/commons/src/main/java/net/swofty/commons/guild/GuildEvent.java new file mode 100644 index 000000000..90adac54c --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/GuildEvent.java @@ -0,0 +1,167 @@ +package net.swofty.commons.guild; + +import lombok.Getter; +import lombok.NonNull; +import net.swofty.commons.protocol.Serializer; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +@Getter +public abstract class GuildEvent { + private final GuildData guild; + + public GuildEvent(GuildData guild) { + this.guild = guild; + } + + public abstract Serializer getSerializer(); + + public List getParticipants() { + return guild != null ? guild.getAllMemberUuids() : List.of(); + } + + public static @NonNull GuildEvent findFromType(String className) { + String[] packageNames = { + "net.swofty.commons.guild.events", + "net.swofty.commons.guild.events.response" + }; + + for (String packageName : packageNames) { + try { + Class clazz = Class.forName(packageName + "." + className); + return createDummyInstance(clazz); + } catch (Exception e) { + // Try next package + } + } + + throw new RuntimeException("Failed to find guild event class: " + className + " in " + Arrays.toString(packageNames)); + } + + @SuppressWarnings("unchecked") + private static GuildEvent createDummyInstance(Class clazz) throws Exception { + String className = clazz.getSimpleName(); + + switch (className) { + case "GuildCreateRequestEvent" -> { + var c = clazz.getDeclaredConstructor(UUID.class, String.class); + return (GuildEvent) c.newInstance(UUID.randomUUID(), ""); + } + case "GuildInviteRequestEvent" -> { + var c = clazz.getDeclaredConstructor(UUID.class, UUID.class); + return (GuildEvent) c.newInstance(UUID.randomUUID(), UUID.randomUUID()); + } + case "GuildAcceptInviteRequestEvent" -> { + var c = clazz.getDeclaredConstructor(UUID.class, UUID.class); + return (GuildEvent) c.newInstance(UUID.randomUUID(), UUID.randomUUID()); + } + case "GuildLeaveRequestEvent" -> { + var c = clazz.getDeclaredConstructor(UUID.class); + return (GuildEvent) c.newInstance(UUID.randomUUID()); + } + case "GuildKickRequestEvent" -> { + var c = clazz.getDeclaredConstructor(UUID.class, UUID.class, String.class); + return (GuildEvent) c.newInstance(UUID.randomUUID(), UUID.randomUUID(), ""); + } + case "GuildDisbandRequestEvent" -> { + var c = clazz.getDeclaredConstructor(UUID.class); + return (GuildEvent) c.newInstance(UUID.randomUUID()); + } + case "GuildPromoteRequestEvent" -> { + var c = clazz.getDeclaredConstructor(UUID.class, UUID.class); + return (GuildEvent) c.newInstance(UUID.randomUUID(), UUID.randomUUID()); + } + case "GuildDemoteRequestEvent" -> { + var c = clazz.getDeclaredConstructor(UUID.class, UUID.class); + return (GuildEvent) c.newInstance(UUID.randomUUID(), UUID.randomUUID()); + } + case "GuildTransferRequestEvent" -> { + var c = clazz.getDeclaredConstructor(UUID.class, UUID.class); + return (GuildEvent) c.newInstance(UUID.randomUUID(), UUID.randomUUID()); + } + case "GuildChatRequestEvent" -> { + var c = clazz.getDeclaredConstructor(UUID.class, String.class, boolean.class); + return (GuildEvent) c.newInstance(UUID.randomUUID(), "", false); + } + case "GuildSettingRequestEvent" -> { + var c = clazz.getDeclaredConstructor(UUID.class, String.class, String.class); + return (GuildEvent) c.newInstance(UUID.randomUUID(), "", ""); + } + case "GuildMuteRequestEvent" -> { + var c = clazz.getDeclaredConstructor(UUID.class, String.class, long.class); + return (GuildEvent) c.newInstance(UUID.randomUUID(), "", 0L); + } + case "GuildUnmuteRequestEvent" -> { + var c = clazz.getDeclaredConstructor(UUID.class, String.class); + return (GuildEvent) c.newInstance(UUID.randomUUID(), ""); + } + case "GuildSetRankRequestEvent" -> { + var c = clazz.getDeclaredConstructor(UUID.class, UUID.class, String.class); + return (GuildEvent) c.newInstance(UUID.randomUUID(), UUID.randomUUID(), ""); + } + case "GuildCreatedResponseEvent" -> { + var dummy = new GuildData(UUID.randomUUID(), "dummy", UUID.randomUUID()); + var c = clazz.getDeclaredConstructor(GuildData.class, UUID.class); + return (GuildEvent) c.newInstance(dummy, UUID.randomUUID()); + } + case "GuildInviteSentResponseEvent" -> { + var dummy = new GuildData(UUID.randomUUID(), "dummy", UUID.randomUUID()); + var c = clazz.getDeclaredConstructor(GuildData.class, UUID.class, UUID.class); + return (GuildEvent) c.newInstance(dummy, UUID.randomUUID(), UUID.randomUUID()); + } + case "GuildMemberJoinedResponseEvent" -> { + var dummy = new GuildData(UUID.randomUUID(), "dummy", UUID.randomUUID()); + var c = clazz.getDeclaredConstructor(GuildData.class, UUID.class); + return (GuildEvent) c.newInstance(dummy, UUID.randomUUID()); + } + case "GuildMemberLeftResponseEvent" -> { + var dummy = new GuildData(UUID.randomUUID(), "dummy", UUID.randomUUID()); + var c = clazz.getDeclaredConstructor(GuildData.class, UUID.class); + return (GuildEvent) c.newInstance(dummy, UUID.randomUUID()); + } + case "GuildMemberKickedResponseEvent" -> { + var dummy = new GuildData(UUID.randomUUID(), "dummy", UUID.randomUUID()); + var c = clazz.getDeclaredConstructor(GuildData.class, UUID.class, UUID.class, String.class); + return (GuildEvent) c.newInstance(dummy, UUID.randomUUID(), UUID.randomUUID(), ""); + } + case "GuildDisbandedResponseEvent" -> { + var dummy = new GuildData(UUID.randomUUID(), "dummy", UUID.randomUUID()); + var c = clazz.getDeclaredConstructor(GuildData.class, UUID.class); + return (GuildEvent) c.newInstance(dummy, UUID.randomUUID()); + } + case "GuildRankChangedResponseEvent" -> { + var dummy = new GuildData(UUID.randomUUID(), "dummy", UUID.randomUUID()); + var c = clazz.getDeclaredConstructor(GuildData.class, UUID.class, UUID.class, String.class, String.class); + return (GuildEvent) c.newInstance(dummy, UUID.randomUUID(), UUID.randomUUID(), "", ""); + } + case "GuildTransferredResponseEvent" -> { + var dummy = new GuildData(UUID.randomUUID(), "dummy", UUID.randomUUID()); + var c = clazz.getDeclaredConstructor(GuildData.class, UUID.class, UUID.class); + return (GuildEvent) c.newInstance(dummy, UUID.randomUUID(), UUID.randomUUID()); + } + case "GuildChatResponseEvent" -> { + var dummy = new GuildData(UUID.randomUUID(), "dummy", UUID.randomUUID()); + var c = clazz.getDeclaredConstructor(GuildData.class, UUID.class, String.class, boolean.class); + return (GuildEvent) c.newInstance(dummy, UUID.randomUUID(), "", false); + } + case "GuildSettingChangedResponseEvent" -> { + var dummy = new GuildData(UUID.randomUUID(), "dummy", UUID.randomUUID()); + var c = clazz.getDeclaredConstructor(GuildData.class, UUID.class, String.class, String.class); + return (GuildEvent) c.newInstance(dummy, UUID.randomUUID(), "", ""); + } + case "GuildMuteChangedResponseEvent" -> { + var dummy = new GuildData(UUID.randomUUID(), "dummy", UUID.randomUUID()); + var c = clazz.getDeclaredConstructor(GuildData.class, UUID.class, String.class, long.class, boolean.class); + return (GuildEvent) c.newInstance(dummy, UUID.randomUUID(), "", 0L, false); + } + case "GuildInviteExpiredResponseEvent" -> { + var dummy = new GuildData(UUID.randomUUID(), "dummy", UUID.randomUUID()); + var c = clazz.getDeclaredConstructor(GuildData.class, UUID.class, UUID.class); + return (GuildEvent) c.newInstance(dummy, UUID.randomUUID(), UUID.randomUUID()); + } + default -> throw new IllegalArgumentException("Unknown guild event class: " + className); + } + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/GuildMember.java b/commons/src/main/java/net/swofty/commons/guild/GuildMember.java new file mode 100644 index 000000000..81232b675 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/GuildMember.java @@ -0,0 +1,88 @@ +package net.swofty.commons.guild; + +import lombok.Getter; +import lombok.Setter; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.UUID; + +@Getter +@Setter +public class GuildMember { + private final UUID uuid; + private String rankName; + private long joinedAt; + private long weeklyGexp; + private long totalGexp; + private long lastLogin; + private boolean notificationsEnabled; + private long mutedUntil; + + public GuildMember(UUID uuid, String rankName, long joinedAt) { + this.uuid = uuid; + this.rankName = rankName; + this.joinedAt = joinedAt; + this.weeklyGexp = 0; + this.totalGexp = 0; + this.lastLogin = System.currentTimeMillis(); + this.notificationsEnabled = true; + this.mutedUntil = 0; + } + + public GuildMember(UUID uuid, String rankName, long joinedAt, long weeklyGexp, + long totalGexp, long lastLogin, boolean notificationsEnabled, long mutedUntil) { + this.uuid = uuid; + this.rankName = rankName; + this.joinedAt = joinedAt; + this.weeklyGexp = weeklyGexp; + this.totalGexp = totalGexp; + this.lastLogin = lastLogin; + this.notificationsEnabled = notificationsEnabled; + this.mutedUntil = mutedUntil; + } + + public boolean isMuted() { + return mutedUntil > System.currentTimeMillis(); + } + + public static Serializer serializer() { + return new Serializer<>() { + @Override + public String serialize(GuildMember value) { + JSONObject json = new JSONObject(); + json.put("uuid", value.uuid.toString()); + json.put("rankName", value.rankName); + json.put("joinedAt", value.joinedAt); + json.put("weeklyGexp", value.weeklyGexp); + json.put("totalGexp", value.totalGexp); + json.put("lastLogin", value.lastLogin); + json.put("notificationsEnabled", value.notificationsEnabled); + json.put("mutedUntil", value.mutedUntil); + return json.toString(); + } + + @Override + public GuildMember deserialize(String json) { + JSONObject obj = new JSONObject(json); + return new GuildMember( + UUID.fromString(obj.getString("uuid")), + obj.getString("rankName"), + obj.getLong("joinedAt"), + obj.getLong("weeklyGexp"), + obj.getLong("totalGexp"), + obj.getLong("lastLogin"), + obj.getBoolean("notificationsEnabled"), + obj.getLong("mutedUntil") + ); + } + + @Override + public GuildMember clone(GuildMember value) { + return new GuildMember(value.uuid, value.rankName, value.joinedAt, + value.weeklyGexp, value.totalGexp, value.lastLogin, + value.notificationsEnabled, value.mutedUntil); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/GuildPermission.java b/commons/src/main/java/net/swofty/commons/guild/GuildPermission.java new file mode 100644 index 000000000..c0db8e63c --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/GuildPermission.java @@ -0,0 +1,16 @@ +package net.swofty.commons.guild; + +public enum GuildPermission { + INVITE, + KICK, + PROMOTE, + DEMOTE, + MODIFY_MOTD, + MODIFY_TAG, + MODIFY_SETTINGS, + OFFICER_CHAT, + MUTE_MEMBERS, + MODIFY_DISCORD, + MODIFY_DESCRIPTION, + MODIFY_GAMES +} diff --git a/commons/src/main/java/net/swofty/commons/guild/GuildRank.java b/commons/src/main/java/net/swofty/commons/guild/GuildRank.java new file mode 100644 index 000000000..396c765c7 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/GuildRank.java @@ -0,0 +1,99 @@ +package net.swofty.commons.guild; + +import lombok.Getter; +import lombok.Setter; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.util.EnumSet; +import java.util.Set; + +@Getter +@Setter +public class GuildRank implements Comparable { + private String name; + private int priority; + private boolean isDefault; + private Set permissions; + + public GuildRank(String name, int priority, boolean isDefault, Set permissions) { + this.name = name; + this.priority = priority; + this.isDefault = isDefault; + this.permissions = permissions; + } + + public boolean hasPermission(GuildPermission permission) { + return permissions.contains(permission); + } + + public boolean isHigherThan(GuildRank other) { + return this.priority < other.priority; + } + + @Override + public int compareTo(GuildRank other) { + return Integer.compare(this.priority, other.priority); + } + + public static GuildRank guildMaster() { + return new GuildRank("Guild Master", 0, true, + EnumSet.allOf(GuildPermission.class)); + } + + public static GuildRank officer() { + return new GuildRank("Officer", 1, true, + EnumSet.of( + GuildPermission.INVITE, + GuildPermission.KICK, + GuildPermission.OFFICER_CHAT, + GuildPermission.MUTE_MEMBERS + )); + } + + public static GuildRank member() { + return new GuildRank("Member", 100, true, + EnumSet.noneOf(GuildPermission.class)); + } + + public static Serializer serializer() { + return new Serializer<>() { + @Override + public String serialize(GuildRank value) { + JSONObject json = new JSONObject(); + json.put("name", value.name); + json.put("priority", value.priority); + json.put("isDefault", value.isDefault); + JSONArray perms = new JSONArray(); + for (GuildPermission perm : value.permissions) { + perms.put(perm.name()); + } + json.put("permissions", perms); + return json.toString(); + } + + @Override + public GuildRank deserialize(String json) { + JSONObject obj = new JSONObject(json); + Set perms = EnumSet.noneOf(GuildPermission.class); + JSONArray permsArray = obj.getJSONArray("permissions"); + for (int i = 0; i < permsArray.length(); i++) { + perms.add(GuildPermission.valueOf(permsArray.getString(i))); + } + return new GuildRank( + obj.getString("name"), + obj.getInt("priority"), + obj.getBoolean("isDefault"), + perms + ); + } + + @Override + public GuildRank clone(GuildRank value) { + return new GuildRank(value.name, value.priority, value.isDefault, + EnumSet.copyOf(value.permissions)); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/GuildResponseEvent.java b/commons/src/main/java/net/swofty/commons/guild/GuildResponseEvent.java new file mode 100644 index 000000000..78c19a45a --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/GuildResponseEvent.java @@ -0,0 +1,7 @@ +package net.swofty.commons.guild; + +public abstract class GuildResponseEvent extends GuildEvent { + public GuildResponseEvent(GuildData guild) { + super(guild); + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/GuildAcceptInviteRequestEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/GuildAcceptInviteRequestEvent.java new file mode 100644 index 000000000..b3a167fdc --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/GuildAcceptInviteRequestEvent.java @@ -0,0 +1,53 @@ +package net.swofty.commons.guild.events; + +import lombok.Getter; +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.List; +import java.util.UUID; + +@Getter +public class GuildAcceptInviteRequestEvent extends GuildEvent { + private final UUID accepter; + private final UUID inviter; + + public GuildAcceptInviteRequestEvent(UUID accepter, UUID inviter) { + super(null); + this.accepter = accepter; + this.inviter = inviter; + } + + @Override + public List getParticipants() { + return List.of(accepter, inviter); + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildAcceptInviteRequestEvent value) { + JSONObject json = new JSONObject(); + json.put("accepter", value.accepter.toString()); + json.put("inviter", value.inviter.toString()); + return json.toString(); + } + + @Override + public GuildAcceptInviteRequestEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + return new GuildAcceptInviteRequestEvent( + UUID.fromString(obj.getString("accepter")), + UUID.fromString(obj.getString("inviter")) + ); + } + + @Override + public GuildAcceptInviteRequestEvent clone(GuildAcceptInviteRequestEvent value) { + return new GuildAcceptInviteRequestEvent(value.accepter, value.inviter); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/GuildChatRequestEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/GuildChatRequestEvent.java new file mode 100644 index 000000000..45ce89950 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/GuildChatRequestEvent.java @@ -0,0 +1,57 @@ +package net.swofty.commons.guild.events; + +import lombok.Getter; +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.List; +import java.util.UUID; + +@Getter +public class GuildChatRequestEvent extends GuildEvent { + private final UUID sender; + private final String message; + private final boolean officerChat; + + public GuildChatRequestEvent(UUID sender, String message, boolean officerChat) { + super(null); + this.sender = sender; + this.message = message; + this.officerChat = officerChat; + } + + @Override + public List getParticipants() { + return List.of(sender); + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildChatRequestEvent value) { + JSONObject json = new JSONObject(); + json.put("sender", value.sender.toString()); + json.put("message", value.message); + json.put("officerChat", value.officerChat); + return json.toString(); + } + + @Override + public GuildChatRequestEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + return new GuildChatRequestEvent( + UUID.fromString(obj.getString("sender")), + obj.getString("message"), + obj.getBoolean("officerChat") + ); + } + + @Override + public GuildChatRequestEvent clone(GuildChatRequestEvent value) { + return new GuildChatRequestEvent(value.sender, value.message, value.officerChat); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/GuildCreateRequestEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/GuildCreateRequestEvent.java new file mode 100644 index 000000000..93e124297 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/GuildCreateRequestEvent.java @@ -0,0 +1,54 @@ +package net.swofty.commons.guild.events; + +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.List; +import java.util.UUID; + +public class GuildCreateRequestEvent extends GuildEvent { + private final UUID creator; + private final String guildName; + + public GuildCreateRequestEvent(UUID creator, String guildName) { + super(null); + this.creator = creator; + this.guildName = guildName; + } + + public UUID getCreator() { return creator; } + public String getGuildName() { return guildName; } + + @Override + public List getParticipants() { + return List.of(creator); + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildCreateRequestEvent value) { + JSONObject json = new JSONObject(); + json.put("creator", value.creator.toString()); + json.put("guildName", value.guildName); + return json.toString(); + } + + @Override + public GuildCreateRequestEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + return new GuildCreateRequestEvent( + UUID.fromString(obj.getString("creator")), + obj.getString("guildName") + ); + } + + @Override + public GuildCreateRequestEvent clone(GuildCreateRequestEvent value) { + return new GuildCreateRequestEvent(value.creator, value.guildName); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/GuildDemoteRequestEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/GuildDemoteRequestEvent.java new file mode 100644 index 000000000..9e84cbdca --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/GuildDemoteRequestEvent.java @@ -0,0 +1,53 @@ +package net.swofty.commons.guild.events; + +import lombok.Getter; +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.List; +import java.util.UUID; + +@Getter +public class GuildDemoteRequestEvent extends GuildEvent { + private final UUID demoter; + private final UUID target; + + public GuildDemoteRequestEvent(UUID demoter, UUID target) { + super(null); + this.demoter = demoter; + this.target = target; + } + + @Override + public List getParticipants() { + return List.of(demoter, target); + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildDemoteRequestEvent value) { + JSONObject json = new JSONObject(); + json.put("demoter", value.demoter.toString()); + json.put("target", value.target.toString()); + return json.toString(); + } + + @Override + public GuildDemoteRequestEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + return new GuildDemoteRequestEvent( + UUID.fromString(obj.getString("demoter")), + UUID.fromString(obj.getString("target")) + ); + } + + @Override + public GuildDemoteRequestEvent clone(GuildDemoteRequestEvent value) { + return new GuildDemoteRequestEvent(value.demoter, value.target); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/GuildDisbandRequestEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/GuildDisbandRequestEvent.java new file mode 100644 index 000000000..d6d2b9f71 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/GuildDisbandRequestEvent.java @@ -0,0 +1,44 @@ +package net.swofty.commons.guild.events; + +import lombok.Getter; +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.List; +import java.util.UUID; + +@Getter +public class GuildDisbandRequestEvent extends GuildEvent { + private final UUID disbander; + + public GuildDisbandRequestEvent(UUID disbander) { + super(null); + this.disbander = disbander; + } + + @Override + public List getParticipants() { + return List.of(disbander); + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildDisbandRequestEvent value) { + return new JSONObject().put("disbander", value.disbander.toString()).toString(); + } + + @Override + public GuildDisbandRequestEvent deserialize(String json) { + return new GuildDisbandRequestEvent(UUID.fromString(new JSONObject(json).getString("disbander"))); + } + + @Override + public GuildDisbandRequestEvent clone(GuildDisbandRequestEvent value) { + return new GuildDisbandRequestEvent(value.disbander); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/GuildInviteRequestEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/GuildInviteRequestEvent.java new file mode 100644 index 000000000..5a63c1e4a --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/GuildInviteRequestEvent.java @@ -0,0 +1,53 @@ +package net.swofty.commons.guild.events; + +import lombok.Getter; +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.List; +import java.util.UUID; + +@Getter +public class GuildInviteRequestEvent extends GuildEvent { + private final UUID inviter; + private final UUID invitee; + + public GuildInviteRequestEvent(UUID inviter, UUID invitee) { + super(null); + this.inviter = inviter; + this.invitee = invitee; + } + + @Override + public List getParticipants() { + return List.of(inviter, invitee); + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildInviteRequestEvent value) { + JSONObject json = new JSONObject(); + json.put("inviter", value.inviter.toString()); + json.put("invitee", value.invitee.toString()); + return json.toString(); + } + + @Override + public GuildInviteRequestEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + return new GuildInviteRequestEvent( + UUID.fromString(obj.getString("inviter")), + UUID.fromString(obj.getString("invitee")) + ); + } + + @Override + public GuildInviteRequestEvent clone(GuildInviteRequestEvent value) { + return new GuildInviteRequestEvent(value.inviter, value.invitee); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/GuildKickRequestEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/GuildKickRequestEvent.java new file mode 100644 index 000000000..fbf5ae80d --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/GuildKickRequestEvent.java @@ -0,0 +1,59 @@ +package net.swofty.commons.guild.events; + +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.List; +import java.util.UUID; + +public class GuildKickRequestEvent extends GuildEvent { + private final UUID kicker; + private final UUID target; + private final String reason; + + public GuildKickRequestEvent(UUID kicker, UUID target, String reason) { + super(null); + this.kicker = kicker; + this.target = target; + this.reason = reason; + } + + public UUID getKicker() { return kicker; } + public UUID getTarget() { return target; } + public String getReason() { return reason; } + + @Override + public List getParticipants() { + return List.of(kicker, target); + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildKickRequestEvent value) { + JSONObject json = new JSONObject(); + json.put("kicker", value.kicker.toString()); + json.put("target", value.target.toString()); + json.put("reason", value.reason); + return json.toString(); + } + + @Override + public GuildKickRequestEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + return new GuildKickRequestEvent( + UUID.fromString(obj.getString("kicker")), + UUID.fromString(obj.getString("target")), + obj.getString("reason") + ); + } + + @Override + public GuildKickRequestEvent clone(GuildKickRequestEvent value) { + return new GuildKickRequestEvent(value.kicker, value.target, value.reason); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/GuildLeaveRequestEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/GuildLeaveRequestEvent.java new file mode 100644 index 000000000..1a57b9f0f --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/GuildLeaveRequestEvent.java @@ -0,0 +1,44 @@ +package net.swofty.commons.guild.events; + +import lombok.Getter; +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.List; +import java.util.UUID; + +@Getter +public class GuildLeaveRequestEvent extends GuildEvent { + private final UUID leaver; + + public GuildLeaveRequestEvent(UUID leaver) { + super(null); + this.leaver = leaver; + } + + @Override + public List getParticipants() { + return List.of(leaver); + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildLeaveRequestEvent value) { + return new JSONObject().put("leaver", value.leaver.toString()).toString(); + } + + @Override + public GuildLeaveRequestEvent deserialize(String json) { + return new GuildLeaveRequestEvent(UUID.fromString(new JSONObject(json).getString("leaver"))); + } + + @Override + public GuildLeaveRequestEvent clone(GuildLeaveRequestEvent value) { + return new GuildLeaveRequestEvent(value.leaver); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/GuildMuteRequestEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/GuildMuteRequestEvent.java new file mode 100644 index 000000000..6140adc30 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/GuildMuteRequestEvent.java @@ -0,0 +1,57 @@ +package net.swofty.commons.guild.events; + +import lombok.Getter; +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.List; +import java.util.UUID; + +@Getter +public class GuildMuteRequestEvent extends GuildEvent { + private final UUID muter; + private final String target; + private final long duration; + + public GuildMuteRequestEvent(UUID muter, String target, long duration) { + super(null); + this.muter = muter; + this.target = target; + this.duration = duration; + } + + @Override + public List getParticipants() { + return List.of(muter); + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildMuteRequestEvent value) { + JSONObject json = new JSONObject(); + json.put("muter", value.muter.toString()); + json.put("target", value.target); + json.put("duration", value.duration); + return json.toString(); + } + + @Override + public GuildMuteRequestEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + return new GuildMuteRequestEvent( + UUID.fromString(obj.getString("muter")), + obj.getString("target"), + obj.getLong("duration") + ); + } + + @Override + public GuildMuteRequestEvent clone(GuildMuteRequestEvent value) { + return new GuildMuteRequestEvent(value.muter, value.target, value.duration); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/GuildPromoteRequestEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/GuildPromoteRequestEvent.java new file mode 100644 index 000000000..acb08d9fb --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/GuildPromoteRequestEvent.java @@ -0,0 +1,53 @@ +package net.swofty.commons.guild.events; + +import lombok.Getter; +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.List; +import java.util.UUID; + +@Getter +public class GuildPromoteRequestEvent extends GuildEvent { + private final UUID promoter; + private final UUID target; + + public GuildPromoteRequestEvent(UUID promoter, UUID target) { + super(null); + this.promoter = promoter; + this.target = target; + } + + @Override + public List getParticipants() { + return List.of(promoter, target); + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildPromoteRequestEvent value) { + JSONObject json = new JSONObject(); + json.put("promoter", value.promoter.toString()); + json.put("target", value.target.toString()); + return json.toString(); + } + + @Override + public GuildPromoteRequestEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + return new GuildPromoteRequestEvent( + UUID.fromString(obj.getString("promoter")), + UUID.fromString(obj.getString("target")) + ); + } + + @Override + public GuildPromoteRequestEvent clone(GuildPromoteRequestEvent value) { + return new GuildPromoteRequestEvent(value.promoter, value.target); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/GuildSetRankRequestEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/GuildSetRankRequestEvent.java new file mode 100644 index 000000000..5bc341e0c --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/GuildSetRankRequestEvent.java @@ -0,0 +1,57 @@ +package net.swofty.commons.guild.events; + +import lombok.Getter; +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.List; +import java.util.UUID; + +@Getter +public class GuildSetRankRequestEvent extends GuildEvent { + private final UUID setter; + private final UUID target; + private final String rankName; + + public GuildSetRankRequestEvent(UUID setter, UUID target, String rankName) { + super(null); + this.setter = setter; + this.target = target; + this.rankName = rankName; + } + + @Override + public List getParticipants() { + return List.of(setter, target); + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildSetRankRequestEvent value) { + JSONObject json = new JSONObject(); + json.put("setter", value.setter.toString()); + json.put("target", value.target.toString()); + json.put("rankName", value.rankName); + return json.toString(); + } + + @Override + public GuildSetRankRequestEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + return new GuildSetRankRequestEvent( + UUID.fromString(obj.getString("setter")), + UUID.fromString(obj.getString("target")), + obj.getString("rankName") + ); + } + + @Override + public GuildSetRankRequestEvent clone(GuildSetRankRequestEvent value) { + return new GuildSetRankRequestEvent(value.setter, value.target, value.rankName); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/GuildSettingRequestEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/GuildSettingRequestEvent.java new file mode 100644 index 000000000..34756c8e1 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/GuildSettingRequestEvent.java @@ -0,0 +1,57 @@ +package net.swofty.commons.guild.events; + +import lombok.Getter; +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.List; +import java.util.UUID; + +@Getter +public class GuildSettingRequestEvent extends GuildEvent { + private final UUID changer; + private final String setting; + private final String value; + + public GuildSettingRequestEvent(UUID changer, String setting, String value) { + super(null); + this.changer = changer; + this.setting = setting; + this.value = value; + } + + @Override + public List getParticipants() { + return List.of(changer); + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildSettingRequestEvent value) { + JSONObject json = new JSONObject(); + json.put("changer", value.changer.toString()); + json.put("setting", value.setting); + json.put("value", value.value); + return json.toString(); + } + + @Override + public GuildSettingRequestEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + return new GuildSettingRequestEvent( + UUID.fromString(obj.getString("changer")), + obj.getString("setting"), + obj.getString("value") + ); + } + + @Override + public GuildSettingRequestEvent clone(GuildSettingRequestEvent val) { + return new GuildSettingRequestEvent(val.changer, val.setting, val.value); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/GuildTransferRequestEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/GuildTransferRequestEvent.java new file mode 100644 index 000000000..de3f94763 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/GuildTransferRequestEvent.java @@ -0,0 +1,53 @@ +package net.swofty.commons.guild.events; + +import lombok.Getter; +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.List; +import java.util.UUID; + +@Getter +public class GuildTransferRequestEvent extends GuildEvent { + private final UUID currentOwner; + private final UUID newOwner; + + public GuildTransferRequestEvent(UUID currentOwner, UUID newOwner) { + super(null); + this.currentOwner = currentOwner; + this.newOwner = newOwner; + } + + @Override + public List getParticipants() { + return List.of(currentOwner, newOwner); + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildTransferRequestEvent value) { + JSONObject json = new JSONObject(); + json.put("currentOwner", value.currentOwner.toString()); + json.put("newOwner", value.newOwner.toString()); + return json.toString(); + } + + @Override + public GuildTransferRequestEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + return new GuildTransferRequestEvent( + UUID.fromString(obj.getString("currentOwner")), + UUID.fromString(obj.getString("newOwner")) + ); + } + + @Override + public GuildTransferRequestEvent clone(GuildTransferRequestEvent value) { + return new GuildTransferRequestEvent(value.currentOwner, value.newOwner); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/GuildUnmuteRequestEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/GuildUnmuteRequestEvent.java new file mode 100644 index 000000000..7271bf7ea --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/GuildUnmuteRequestEvent.java @@ -0,0 +1,53 @@ +package net.swofty.commons.guild.events; + +import lombok.Getter; +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.List; +import java.util.UUID; + +@Getter +public class GuildUnmuteRequestEvent extends GuildEvent { + private final UUID unmuter; + private final String target; + + public GuildUnmuteRequestEvent(UUID unmuter, String target) { + super(null); + this.unmuter = unmuter; + this.target = target; + } + + @Override + public List getParticipants() { + return List.of(unmuter); + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildUnmuteRequestEvent value) { + JSONObject json = new JSONObject(); + json.put("unmuter", value.unmuter.toString()); + json.put("target", value.target); + return json.toString(); + } + + @Override + public GuildUnmuteRequestEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + return new GuildUnmuteRequestEvent( + UUID.fromString(obj.getString("unmuter")), + obj.getString("target") + ); + } + + @Override + public GuildUnmuteRequestEvent clone(GuildUnmuteRequestEvent value) { + return new GuildUnmuteRequestEvent(value.unmuter, value.target); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/response/GuildChatResponseEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildChatResponseEvent.java new file mode 100644 index 000000000..fc3f5492f --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildChatResponseEvent.java @@ -0,0 +1,53 @@ +package net.swofty.commons.guild.events.response; + +import lombok.Getter; +import net.swofty.commons.guild.GuildData; +import net.swofty.commons.guild.GuildResponseEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.UUID; + +@Getter +public class GuildChatResponseEvent extends GuildResponseEvent { + private final UUID sender; + private final String message; + private final boolean officerChat; + + public GuildChatResponseEvent(GuildData guild, UUID sender, String message, boolean officerChat) { + super(guild); + this.sender = sender; + this.message = message; + this.officerChat = officerChat; + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildChatResponseEvent value) { + JSONObject json = new JSONObject(); + json.put("guild", GuildData.getStaticSerializer().serialize(value.getGuild())); + json.put("sender", value.sender.toString()); + json.put("message", value.message); + json.put("officerChat", value.officerChat); + return json.toString(); + } + + @Override + public GuildChatResponseEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + GuildData guild = GuildData.getStaticSerializer().deserialize(obj.getString("guild")); + return new GuildChatResponseEvent(guild, + UUID.fromString(obj.getString("sender")), + obj.getString("message"), + obj.getBoolean("officerChat")); + } + + @Override + public GuildChatResponseEvent clone(GuildChatResponseEvent value) { + return new GuildChatResponseEvent(value.getGuild(), value.sender, value.message, value.officerChat); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/response/GuildCreatedResponseEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildCreatedResponseEvent.java new file mode 100644 index 000000000..8e27d4cb5 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildCreatedResponseEvent.java @@ -0,0 +1,44 @@ +package net.swofty.commons.guild.events.response; + +import lombok.Getter; +import net.swofty.commons.guild.GuildData; +import net.swofty.commons.guild.GuildResponseEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.UUID; + +@Getter +public class GuildCreatedResponseEvent extends GuildResponseEvent { + private final UUID creator; + + public GuildCreatedResponseEvent(GuildData guild, UUID creator) { + super(guild); + this.creator = creator; + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildCreatedResponseEvent value) { + JSONObject json = new JSONObject(); + json.put("guild", GuildData.getStaticSerializer().serialize(value.getGuild())); + json.put("creator", value.creator.toString()); + return json.toString(); + } + + @Override + public GuildCreatedResponseEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + GuildData guild = GuildData.getStaticSerializer().deserialize(obj.getString("guild")); + return new GuildCreatedResponseEvent(guild, UUID.fromString(obj.getString("creator"))); + } + + @Override + public GuildCreatedResponseEvent clone(GuildCreatedResponseEvent value) { + return new GuildCreatedResponseEvent(value.getGuild(), value.creator); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/response/GuildDisbandedResponseEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildDisbandedResponseEvent.java new file mode 100644 index 000000000..4cbb2cbcd --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildDisbandedResponseEvent.java @@ -0,0 +1,44 @@ +package net.swofty.commons.guild.events.response; + +import lombok.Getter; +import net.swofty.commons.guild.GuildData; +import net.swofty.commons.guild.GuildResponseEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.UUID; + +@Getter +public class GuildDisbandedResponseEvent extends GuildResponseEvent { + private final UUID disbander; + + public GuildDisbandedResponseEvent(GuildData guild, UUID disbander) { + super(guild); + this.disbander = disbander; + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildDisbandedResponseEvent value) { + JSONObject json = new JSONObject(); + json.put("guild", GuildData.getStaticSerializer().serialize(value.getGuild())); + json.put("disbander", value.disbander.toString()); + return json.toString(); + } + + @Override + public GuildDisbandedResponseEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + GuildData guild = GuildData.getStaticSerializer().deserialize(obj.getString("guild")); + return new GuildDisbandedResponseEvent(guild, UUID.fromString(obj.getString("disbander"))); + } + + @Override + public GuildDisbandedResponseEvent clone(GuildDisbandedResponseEvent value) { + return new GuildDisbandedResponseEvent(value.getGuild(), value.disbander); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/response/GuildInviteExpiredResponseEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildInviteExpiredResponseEvent.java new file mode 100644 index 000000000..9cfd27774 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildInviteExpiredResponseEvent.java @@ -0,0 +1,55 @@ +package net.swofty.commons.guild.events.response; + +import lombok.Getter; +import net.swofty.commons.guild.GuildData; +import net.swofty.commons.guild.GuildResponseEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.List; +import java.util.UUID; + +@Getter +public class GuildInviteExpiredResponseEvent extends GuildResponseEvent { + private final UUID inviter; + private final UUID invitee; + + public GuildInviteExpiredResponseEvent(GuildData guild, UUID inviter, UUID invitee) { + super(guild); + this.inviter = inviter; + this.invitee = invitee; + } + + @Override + public List getParticipants() { + return List.of(inviter, invitee); + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildInviteExpiredResponseEvent value) { + JSONObject json = new JSONObject(); + json.put("guild", GuildData.getStaticSerializer().serialize(value.getGuild())); + json.put("inviter", value.inviter.toString()); + json.put("invitee", value.invitee.toString()); + return json.toString(); + } + + @Override + public GuildInviteExpiredResponseEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + GuildData guild = GuildData.getStaticSerializer().deserialize(obj.getString("guild")); + return new GuildInviteExpiredResponseEvent(guild, + UUID.fromString(obj.getString("inviter")), + UUID.fromString(obj.getString("invitee"))); + } + + @Override + public GuildInviteExpiredResponseEvent clone(GuildInviteExpiredResponseEvent value) { + return new GuildInviteExpiredResponseEvent(value.getGuild(), value.inviter, value.invitee); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/response/GuildInviteSentResponseEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildInviteSentResponseEvent.java new file mode 100644 index 000000000..048446ccb --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildInviteSentResponseEvent.java @@ -0,0 +1,57 @@ +package net.swofty.commons.guild.events.response; + +import lombok.Getter; +import net.swofty.commons.guild.GuildData; +import net.swofty.commons.guild.GuildResponseEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.List; +import java.util.UUID; + +@Getter +public class GuildInviteSentResponseEvent extends GuildResponseEvent { + private final UUID inviter; + private final UUID invitee; + + public GuildInviteSentResponseEvent(GuildData guild, UUID inviter, UUID invitee) { + super(guild); + this.inviter = inviter; + this.invitee = invitee; + } + + @Override + public List getParticipants() { + List participants = new java.util.ArrayList<>(getGuild().getAllMemberUuids()); + if (!participants.contains(invitee)) participants.add(invitee); + return participants; + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildInviteSentResponseEvent value) { + JSONObject json = new JSONObject(); + json.put("guild", GuildData.getStaticSerializer().serialize(value.getGuild())); + json.put("inviter", value.inviter.toString()); + json.put("invitee", value.invitee.toString()); + return json.toString(); + } + + @Override + public GuildInviteSentResponseEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + GuildData guild = GuildData.getStaticSerializer().deserialize(obj.getString("guild")); + return new GuildInviteSentResponseEvent(guild, + UUID.fromString(obj.getString("inviter")), + UUID.fromString(obj.getString("invitee"))); + } + + @Override + public GuildInviteSentResponseEvent clone(GuildInviteSentResponseEvent value) { + return new GuildInviteSentResponseEvent(value.getGuild(), value.inviter, value.invitee); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/response/GuildMemberJoinedResponseEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildMemberJoinedResponseEvent.java new file mode 100644 index 000000000..8157954cf --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildMemberJoinedResponseEvent.java @@ -0,0 +1,44 @@ +package net.swofty.commons.guild.events.response; + +import lombok.Getter; +import net.swofty.commons.guild.GuildData; +import net.swofty.commons.guild.GuildResponseEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.UUID; + +@Getter +public class GuildMemberJoinedResponseEvent extends GuildResponseEvent { + private final UUID joiner; + + public GuildMemberJoinedResponseEvent(GuildData guild, UUID joiner) { + super(guild); + this.joiner = joiner; + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildMemberJoinedResponseEvent value) { + JSONObject json = new JSONObject(); + json.put("guild", GuildData.getStaticSerializer().serialize(value.getGuild())); + json.put("joiner", value.joiner.toString()); + return json.toString(); + } + + @Override + public GuildMemberJoinedResponseEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + GuildData guild = GuildData.getStaticSerializer().deserialize(obj.getString("guild")); + return new GuildMemberJoinedResponseEvent(guild, UUID.fromString(obj.getString("joiner"))); + } + + @Override + public GuildMemberJoinedResponseEvent clone(GuildMemberJoinedResponseEvent value) { + return new GuildMemberJoinedResponseEvent(value.getGuild(), value.joiner); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/response/GuildMemberKickedResponseEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildMemberKickedResponseEvent.java new file mode 100644 index 000000000..776604e95 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildMemberKickedResponseEvent.java @@ -0,0 +1,61 @@ +package net.swofty.commons.guild.events.response; + +import lombok.Getter; +import net.swofty.commons.guild.GuildData; +import net.swofty.commons.guild.GuildResponseEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.List; +import java.util.UUID; + +@Getter +public class GuildMemberKickedResponseEvent extends GuildResponseEvent { + private final UUID kicker; + private final UUID kicked; + private final String reason; + + public GuildMemberKickedResponseEvent(GuildData guild, UUID kicker, UUID kicked, String reason) { + super(guild); + this.kicker = kicker; + this.kicked = kicked; + this.reason = reason; + } + + @Override + public List getParticipants() { + List participants = new java.util.ArrayList<>(getGuild().getAllMemberUuids()); + if (!participants.contains(kicked)) participants.add(kicked); + return participants; + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildMemberKickedResponseEvent value) { + JSONObject json = new JSONObject(); + json.put("guild", GuildData.getStaticSerializer().serialize(value.getGuild())); + json.put("kicker", value.kicker.toString()); + json.put("kicked", value.kicked.toString()); + json.put("reason", value.reason); + return json.toString(); + } + + @Override + public GuildMemberKickedResponseEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + GuildData guild = GuildData.getStaticSerializer().deserialize(obj.getString("guild")); + return new GuildMemberKickedResponseEvent(guild, + UUID.fromString(obj.getString("kicker")), + UUID.fromString(obj.getString("kicked")), + obj.getString("reason")); + } + + @Override + public GuildMemberKickedResponseEvent clone(GuildMemberKickedResponseEvent value) { + return new GuildMemberKickedResponseEvent(value.getGuild(), value.kicker, value.kicked, value.reason); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/response/GuildMemberLeftResponseEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildMemberLeftResponseEvent.java new file mode 100644 index 000000000..9300d5c92 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildMemberLeftResponseEvent.java @@ -0,0 +1,52 @@ +package net.swofty.commons.guild.events.response; + +import lombok.Getter; +import net.swofty.commons.guild.GuildData; +import net.swofty.commons.guild.GuildResponseEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.List; +import java.util.UUID; + +@Getter +public class GuildMemberLeftResponseEvent extends GuildResponseEvent { + private final UUID leaver; + + public GuildMemberLeftResponseEvent(GuildData guild, UUID leaver) { + super(guild); + this.leaver = leaver; + } + + @Override + public List getParticipants() { + List participants = new java.util.ArrayList<>(getGuild().getAllMemberUuids()); + if (!participants.contains(leaver)) participants.add(leaver); + return participants; + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildMemberLeftResponseEvent value) { + JSONObject json = new JSONObject(); + json.put("guild", GuildData.getStaticSerializer().serialize(value.getGuild())); + json.put("leaver", value.leaver.toString()); + return json.toString(); + } + + @Override + public GuildMemberLeftResponseEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + GuildData guild = GuildData.getStaticSerializer().deserialize(obj.getString("guild")); + return new GuildMemberLeftResponseEvent(guild, UUID.fromString(obj.getString("leaver"))); + } + + @Override + public GuildMemberLeftResponseEvent clone(GuildMemberLeftResponseEvent value) { + return new GuildMemberLeftResponseEvent(value.getGuild(), value.leaver); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/response/GuildMuteChangedResponseEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildMuteChangedResponseEvent.java new file mode 100644 index 000000000..cc8946367 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildMuteChangedResponseEvent.java @@ -0,0 +1,57 @@ +package net.swofty.commons.guild.events.response; + +import lombok.Getter; +import net.swofty.commons.guild.GuildData; +import net.swofty.commons.guild.GuildResponseEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.UUID; + +@Getter +public class GuildMuteChangedResponseEvent extends GuildResponseEvent { + private final UUID muter; + private final String target; + private final long duration; + private final boolean unmute; + + public GuildMuteChangedResponseEvent(GuildData guild, UUID muter, String target, long duration, boolean unmute) { + super(guild); + this.muter = muter; + this.target = target; + this.duration = duration; + this.unmute = unmute; + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildMuteChangedResponseEvent value) { + JSONObject json = new JSONObject(); + json.put("guild", GuildData.getStaticSerializer().serialize(value.getGuild())); + json.put("muter", value.muter.toString()); + json.put("target", value.target); + json.put("duration", value.duration); + json.put("unmute", value.unmute); + return json.toString(); + } + + @Override + public GuildMuteChangedResponseEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + GuildData guild = GuildData.getStaticSerializer().deserialize(obj.getString("guild")); + return new GuildMuteChangedResponseEvent(guild, + UUID.fromString(obj.getString("muter")), + obj.getString("target"), + obj.getLong("duration"), + obj.getBoolean("unmute")); + } + + @Override + public GuildMuteChangedResponseEvent clone(GuildMuteChangedResponseEvent value) { + return new GuildMuteChangedResponseEvent(value.getGuild(), value.muter, value.target, value.duration, value.unmute); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/response/GuildRankChangedResponseEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildRankChangedResponseEvent.java new file mode 100644 index 000000000..b17c4005d --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildRankChangedResponseEvent.java @@ -0,0 +1,57 @@ +package net.swofty.commons.guild.events.response; + +import lombok.Getter; +import net.swofty.commons.guild.GuildData; +import net.swofty.commons.guild.GuildResponseEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.UUID; + +@Getter +public class GuildRankChangedResponseEvent extends GuildResponseEvent { + private final UUID changer; + private final UUID target; + private final String fromRank; + private final String toRank; + + public GuildRankChangedResponseEvent(GuildData guild, UUID changer, UUID target, String fromRank, String toRank) { + super(guild); + this.changer = changer; + this.target = target; + this.fromRank = fromRank; + this.toRank = toRank; + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildRankChangedResponseEvent value) { + JSONObject json = new JSONObject(); + json.put("guild", GuildData.getStaticSerializer().serialize(value.getGuild())); + json.put("changer", value.changer.toString()); + json.put("target", value.target.toString()); + json.put("fromRank", value.fromRank); + json.put("toRank", value.toRank); + return json.toString(); + } + + @Override + public GuildRankChangedResponseEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + GuildData guild = GuildData.getStaticSerializer().deserialize(obj.getString("guild")); + return new GuildRankChangedResponseEvent(guild, + UUID.fromString(obj.getString("changer")), + UUID.fromString(obj.getString("target")), + obj.getString("fromRank"), + obj.getString("toRank")); + } + + @Override + public GuildRankChangedResponseEvent clone(GuildRankChangedResponseEvent value) { + return new GuildRankChangedResponseEvent(value.getGuild(), value.changer, value.target, value.fromRank, value.toRank); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/response/GuildSettingChangedResponseEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildSettingChangedResponseEvent.java new file mode 100644 index 000000000..494a74f15 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildSettingChangedResponseEvent.java @@ -0,0 +1,53 @@ +package net.swofty.commons.guild.events.response; + +import lombok.Getter; +import net.swofty.commons.guild.GuildData; +import net.swofty.commons.guild.GuildResponseEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.UUID; + +@Getter +public class GuildSettingChangedResponseEvent extends GuildResponseEvent { + private final UUID changer; + private final String setting; + private final String value; + + public GuildSettingChangedResponseEvent(GuildData guild, UUID changer, String setting, String value) { + super(guild); + this.changer = changer; + this.setting = setting; + this.value = value; + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildSettingChangedResponseEvent val) { + JSONObject json = new JSONObject(); + json.put("guild", GuildData.getStaticSerializer().serialize(val.getGuild())); + json.put("changer", val.changer.toString()); + json.put("setting", val.setting); + json.put("value", val.value); + return json.toString(); + } + + @Override + public GuildSettingChangedResponseEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + GuildData guild = GuildData.getStaticSerializer().deserialize(obj.getString("guild")); + return new GuildSettingChangedResponseEvent(guild, + UUID.fromString(obj.getString("changer")), + obj.getString("setting"), + obj.getString("value")); + } + + @Override + public GuildSettingChangedResponseEvent clone(GuildSettingChangedResponseEvent val) { + return new GuildSettingChangedResponseEvent(val.getGuild(), val.changer, val.setting, val.value); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/guild/events/response/GuildTransferredResponseEvent.java b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildTransferredResponseEvent.java new file mode 100644 index 000000000..85397059c --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/guild/events/response/GuildTransferredResponseEvent.java @@ -0,0 +1,49 @@ +package net.swofty.commons.guild.events.response; + +import lombok.Getter; +import net.swofty.commons.guild.GuildData; +import net.swofty.commons.guild.GuildResponseEvent; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.UUID; + +@Getter +public class GuildTransferredResponseEvent extends GuildResponseEvent { + private final UUID oldOwner; + private final UUID newOwner; + + public GuildTransferredResponseEvent(GuildData guild, UUID oldOwner, UUID newOwner) { + super(guild); + this.oldOwner = oldOwner; + this.newOwner = newOwner; + } + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GuildTransferredResponseEvent value) { + JSONObject json = new JSONObject(); + json.put("guild", GuildData.getStaticSerializer().serialize(value.getGuild())); + json.put("oldOwner", value.oldOwner.toString()); + json.put("newOwner", value.newOwner.toString()); + return json.toString(); + } + + @Override + public GuildTransferredResponseEvent deserialize(String json) { + JSONObject obj = new JSONObject(json); + GuildData guild = GuildData.getStaticSerializer().deserialize(obj.getString("guild")); + return new GuildTransferredResponseEvent(guild, + UUID.fromString(obj.getString("oldOwner")), + UUID.fromString(obj.getString("newOwner"))); + } + + @Override + public GuildTransferredResponseEvent clone(GuildTransferredResponseEvent value) { + return new GuildTransferredResponseEvent(value.getGuild(), value.oldOwner, value.newOwner); + } + }; + } +} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/guild/GetGuildProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/guild/GetGuildProtocolObject.java new file mode 100644 index 000000000..be186a61e --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/guild/GetGuildProtocolObject.java @@ -0,0 +1,66 @@ +package net.swofty.commons.protocol.objects.guild; + +import net.swofty.commons.guild.GuildData; +import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.UUID; + +public class GetGuildProtocolObject extends ProtocolObject + { + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(GetGuildMessage value) { + return new JSONObject().put("memberUUID", value.memberUUID.toString()).toString(); + } + + @Override + public GetGuildMessage deserialize(String json) { + return new GetGuildMessage(UUID.fromString(new JSONObject(json).getString("memberUUID"))); + } + + @Override + public GetGuildMessage clone(GetGuildMessage value) { + return new GetGuildMessage(value.memberUUID); + } + }; + } + + @Override + public Serializer getReturnSerializer() { + return new Serializer<>() { + @Override + public String serialize(GetGuildResponse value) { + JSONObject json = new JSONObject(); + json.put("hasGuild", value.guild != null); + if (value.guild != null) { + json.put("guild", GuildData.getStaticSerializer().serialize(value.guild)); + } + return json.toString(); + } + + @Override + public GetGuildResponse deserialize(String json) { + JSONObject obj = new JSONObject(json); + if (!obj.getBoolean("hasGuild")) { + return new GetGuildResponse(null); + } + GuildData guild = GuildData.getStaticSerializer().deserialize(obj.getString("guild")); + return new GetGuildResponse(guild); + } + + @Override + public GetGuildResponse clone(GetGuildResponse value) { + return new GetGuildResponse(value.guild); + } + }; + } + + public record GetGuildMessage(UUID memberUUID) { } + public record GetGuildResponse(GuildData guild) { } +} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/guild/IsPlayerInGuildProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/guild/IsPlayerInGuildProtocolObject.java new file mode 100644 index 000000000..09a643f84 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/guild/IsPlayerInGuildProtocolObject.java @@ -0,0 +1,55 @@ +package net.swofty.commons.protocol.objects.guild; + +import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +import java.util.UUID; + +public class IsPlayerInGuildProtocolObject extends ProtocolObject + { + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(IsPlayerInGuildMessage value) { + return new JSONObject().put("playerUUID", value.playerUUID.toString()).toString(); + } + + @Override + public IsPlayerInGuildMessage deserialize(String json) { + return new IsPlayerInGuildMessage(UUID.fromString(new JSONObject(json).getString("playerUUID"))); + } + + @Override + public IsPlayerInGuildMessage clone(IsPlayerInGuildMessage value) { + return new IsPlayerInGuildMessage(value.playerUUID); + } + }; + } + + @Override + public Serializer getReturnSerializer() { + return new Serializer<>() { + @Override + public String serialize(IsPlayerInGuildResponse value) { + return value.isInGuild ? "true" : "false"; + } + + @Override + public IsPlayerInGuildResponse deserialize(String json) { + return new IsPlayerInGuildResponse(json.equals("true")); + } + + @Override + public IsPlayerInGuildResponse clone(IsPlayerInGuildResponse value) { + return new IsPlayerInGuildResponse(value.isInGuild); + } + }; + } + + public record IsPlayerInGuildMessage(UUID playerUUID) { } + public record IsPlayerInGuildResponse(boolean isInGuild) { } +} diff --git a/commons/src/main/java/net/swofty/commons/protocol/objects/guild/SendGuildEventToServiceProtocolObject.java b/commons/src/main/java/net/swofty/commons/protocol/objects/guild/SendGuildEventToServiceProtocolObject.java new file mode 100644 index 000000000..0ab6cb651 --- /dev/null +++ b/commons/src/main/java/net/swofty/commons/protocol/objects/guild/SendGuildEventToServiceProtocolObject.java @@ -0,0 +1,61 @@ +package net.swofty.commons.protocol.objects.guild; + +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.protocol.ProtocolObject; +import net.swofty.commons.protocol.Serializer; +import org.json.JSONObject; + +public class SendGuildEventToServiceProtocolObject extends ProtocolObject + { + + @Override + public Serializer getSerializer() { + return new Serializer<>() { + @Override + public String serialize(SendGuildEventToServiceMessage value) { + JSONObject json = new JSONObject(); + json.put("event", value.event.getSerializer().serialize(value.event)); + json.put("eventType", value.event.getClass().getSimpleName()); + return json.toString(); + } + + @Override + public SendGuildEventToServiceMessage deserialize(String json) { + JSONObject jsonObject = new JSONObject(json); + String eventType = jsonObject.getString("eventType"); + GuildEvent event = GuildEvent.findFromType(eventType); + GuildEvent deserializedEvent = (GuildEvent) event.getSerializer().deserialize(jsonObject.getString("event")); + return new SendGuildEventToServiceMessage(deserializedEvent); + } + + @Override + public SendGuildEventToServiceMessage clone(SendGuildEventToServiceMessage value) { + return new SendGuildEventToServiceMessage(value.event); + } + }; + } + + @Override + public Serializer getReturnSerializer() { + return new Serializer<>() { + @Override + public String serialize(SendGuildEventToServiceResponse value) { + return value.success ? "true" : "false"; + } + + @Override + public SendGuildEventToServiceResponse deserialize(String json) { + return new SendGuildEventToServiceResponse(json.equals("true")); + } + + @Override + public SendGuildEventToServiceResponse clone(SendGuildEventToServiceResponse value) { + return new SendGuildEventToServiceResponse(value.success); + } + }; + } + + public record SendGuildEventToServiceMessage(GuildEvent event) { } + public record SendGuildEventToServiceResponse(boolean success) { } +} diff --git a/commons/src/main/java/net/swofty/commons/service/FromServiceChannels.java b/commons/src/main/java/net/swofty/commons/service/FromServiceChannels.java index 25dbf8cbf..240f9a65a 100644 --- a/commons/src/main/java/net/swofty/commons/service/FromServiceChannels.java +++ b/commons/src/main/java/net/swofty/commons/service/FromServiceChannels.java @@ -17,6 +17,7 @@ public enum FromServiceChannels { DARK_AUCTION_EVENT("dark-auction-event"), TRIGGER_DARK_AUCTION("trigger-dark-auction"), PROPAGATE_FRIEND_EVENT("propagate_friend_event"), + PROPAGATE_GUILD_EVENT("propagate_guild_event"), ; private final String channelName; diff --git a/service.guild/build.gradle.kts b/service.guild/build.gradle.kts new file mode 100644 index 000000000..4e0c7c85c --- /dev/null +++ b/service.guild/build.gradle.kts @@ -0,0 +1,45 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +plugins { + java + application + id("com.gradleup.shadow") version "9.3.1" +} + +group = "net.swofty" +version = "3.0" + +java { + sourceCompatibility = JavaVersion.VERSION_25 + targetCompatibility = JavaVersion.VERSION_25 + toolchain { + languageVersion.set(JavaLanguageVersion.of(25)) + } +} + +repositories { + maven("https://jitpack.io") + mavenCentral() +} + +dependencies { + implementation(project(":service.generic")) + implementation(project(":commons")) + implementation("com.github.ben-manes.caffeine:caffeine:3.2.3") + implementation("org.tinylog:tinylog-api:2.7.0") + implementation("org.tinylog:tinylog-impl:2.7.0") + implementation("org.mongodb:bson:5.6.4") + implementation("org.mongodb:mongodb-driver-sync:5.6.4") +} + +application { + mainClass.set("net.swofty.service.guild.GuildService") +} + +tasks { + named("shadowJar") { + archiveBaseName.set("ServiceGuild") + archiveClassifier.set("") + archiveVersion.set("") + } +} diff --git a/service.guild/src/main/java/net/swofty/service/guild/GuildCache.java b/service.guild/src/main/java/net/swofty/service/guild/GuildCache.java new file mode 100644 index 000000000..ac8bd6efd --- /dev/null +++ b/service.guild/src/main/java/net/swofty/service/guild/GuildCache.java @@ -0,0 +1,655 @@ +package net.swofty.service.guild; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import net.swofty.commons.guild.GuildData; +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.guild.GuildMember; +import net.swofty.commons.guild.GuildPermission; +import net.swofty.commons.guild.GuildRank; +import net.swofty.commons.guild.events.*; +import net.swofty.commons.guild.events.response.*; +import net.swofty.commons.service.FromServiceChannels; +import net.swofty.service.generic.redis.ServiceToServerManager; +import org.json.JSONObject; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +public class GuildCache { + private static final Cache guildCache = Caffeine.newBuilder() + .maximumSize(10_000) + .expireAfterAccess(30, TimeUnit.MINUTES) + .build(); + + private static final Map pendingInvites = new ConcurrentHashMap<>(); + private static final Map lastChatTimestamps = new ConcurrentHashMap<>(); + + public static boolean isInGuild(UUID playerUUID) { + return GuildDatabase.getPlayerGuildId(playerUUID) != null; + } + + public static GuildData getGuildFromPlayer(UUID playerUUID) { + UUID guildId = GuildDatabase.getPlayerGuildId(playerUUID); + if (guildId == null) return null; + return getGuild(guildId); + } + + public static GuildData getGuild(UUID guildId) { + return guildCache.get(guildId, GuildDatabase::getGuild); + } + + public static void handleCreateRequest(GuildCreateRequestEvent event) { + UUID creator = event.getCreator(); + String guildName = event.getGuildName(); + + if (isInGuild(creator)) { + sendErrorToPlayer(creator, "§cYou are already in a guild! Leave your current guild to create a new one."); + return; + } + + if (guildName.length() < 3 || guildName.length() > 30) { + sendErrorToPlayer(creator, "§cGuild name must be between 3 and 30 characters."); + return; + } + + if (GuildDatabase.guildNameExists(guildName)) { + sendErrorToPlayer(creator, "§cA guild with that name already exists!"); + return; + } + + GuildData guild = new GuildData(UUID.randomUUID(), guildName, creator); + persistGuild(guild); + GuildDatabase.mapPlayerToGuild(creator, guild.getGuildId()); + + GuildCreatedResponseEvent response = new GuildCreatedResponseEvent(guild, creator); + sendEvent(response); + } + + public static void handleInviteRequest(GuildInviteRequestEvent event) { + UUID inviter = event.getInviter(); + UUID invitee = event.getInvitee(); + + GuildData guild = getGuildFromPlayer(inviter); + if (guild == null) { + sendErrorToPlayer(inviter, "§cYou are not in a guild!"); + return; + } + + GuildRank inviterRank = guild.getMemberRank(inviter); + if (inviterRank == null || !inviterRank.hasPermission(GuildPermission.INVITE)) { + sendErrorToPlayer(inviter, "§cYou do not have permission to invite players!"); + return; + } + + if (guild.isFull()) { + sendErrorToPlayer(inviter, "§cYour guild is full!"); + return; + } + + if (isInGuild(invitee)) { + sendErrorToPlayer(inviter, "§cThat player is already in a guild!"); + return; + } + + if (pendingInvites.containsKey(invitee)) { + sendErrorToPlayer(inviter, "§cThat player already has a pending guild invite!"); + return; + } + + PendingGuildInvite invite = new PendingGuildInvite(guild.getGuildId(), inviter, invitee); + pendingInvites.put(invitee, invite); + scheduleInviteExpiration(guild.getGuildId(), inviter, invitee, 60000); + + GuildInviteSentResponseEvent response = new GuildInviteSentResponseEvent(guild, inviter, invitee); + sendEvent(response); + } + + public static void handleAcceptInvite(GuildAcceptInviteRequestEvent event) { + UUID accepter = event.getAccepter(); + UUID inviter = event.getInviter(); + + PendingGuildInvite invite = pendingInvites.get(accepter); + if (invite == null || !invite.inviter().equals(inviter)) { + sendErrorToPlayer(accepter, "§cYou don't have a pending invite from that player, or it has expired!"); + return; + } + + if (isInGuild(accepter)) { + sendErrorToPlayer(accepter, "§cYou must leave your current guild before joining another!"); + return; + } + + GuildData guild = getGuild(invite.guildId()); + if (guild == null) { + sendErrorToPlayer(accepter, "§cThe guild no longer exists!"); + pendingInvites.remove(accepter); + return; + } + + if (guild.isFull()) { + sendErrorToPlayer(accepter, "§cThe guild is now full!"); + pendingInvites.remove(accepter); + return; + } + + GuildMember newMember = new GuildMember(accepter, "Member", System.currentTimeMillis()); + guild.getMembers().add(newMember); + pendingInvites.remove(accepter); + + persistGuild(guild); + GuildDatabase.mapPlayerToGuild(accepter, guild.getGuildId()); + + GuildMemberJoinedResponseEvent response = new GuildMemberJoinedResponseEvent(guild, accepter); + sendEvent(response); + } + + public static void handleLeaveRequest(GuildLeaveRequestEvent event) { + UUID leaver = event.getLeaver(); + + GuildData guild = getGuildFromPlayer(leaver); + if (guild == null) { + sendErrorToPlayer(leaver, "§cYou are not in a guild!"); + return; + } + + if (guild.getMasterUuid().equals(leaver)) { + sendErrorToPlayer(leaver, "§cYou cannot leave a guild as the Guild Master! Transfer ownership first or disband the guild."); + return; + } + + GuildMember member = guild.getMember(leaver); + guild.getMembers().remove(member); + + persistGuild(guild); + GuildDatabase.removePlayerMapping(leaver); + + GuildMemberLeftResponseEvent response = new GuildMemberLeftResponseEvent(guild, leaver); + sendEvent(response); + } + + public static void handleKickRequest(GuildKickRequestEvent event) { + UUID kicker = event.getKicker(); + UUID target = event.getTarget(); + String reason = event.getReason(); + + GuildData guild = getGuildFromPlayer(kicker); + if (guild == null) { + sendErrorToPlayer(kicker, "§cYou are not in a guild!"); + return; + } + + GuildRank kickerRank = guild.getMemberRank(kicker); + if (kickerRank == null || !kickerRank.hasPermission(GuildPermission.KICK)) { + sendErrorToPlayer(kicker, "§cYou do not have permission to kick members!"); + return; + } + + GuildMember targetMember = guild.getMember(target); + if (targetMember == null) { + sendErrorToPlayer(kicker, "§cThat player is not in your guild!"); + return; + } + + GuildRank targetRank = guild.getRank(targetMember.getRankName()); + if (targetRank != null && !kickerRank.isHigherThan(targetRank)) { + sendErrorToPlayer(kicker, "§cYou cannot kick someone of equal or higher rank!"); + return; + } + + guild.getMembers().remove(targetMember); + + persistGuild(guild); + GuildDatabase.removePlayerMapping(target); + + GuildMemberKickedResponseEvent response = new GuildMemberKickedResponseEvent(guild, kicker, target, reason); + sendEvent(response); + } + + public static void handleDisbandRequest(GuildDisbandRequestEvent event) { + UUID disbander = event.getDisbander(); + + GuildData guild = getGuildFromPlayer(disbander); + if (guild == null) { + sendErrorToPlayer(disbander, "§cYou are not in a guild!"); + return; + } + + if (!guild.getMasterUuid().equals(disbander)) { + sendErrorToPlayer(disbander, "§cOnly the Guild Master can disband the guild!"); + return; + } + + disbandGuild(guild, disbander); + } + + public static void handlePromoteRequest(GuildPromoteRequestEvent event) { + UUID promoter = event.getPromoter(); + UUID target = event.getTarget(); + + GuildData guild = getGuildFromPlayer(promoter); + if (guild == null) { + sendErrorToPlayer(promoter, "§cYou are not in a guild!"); + return; + } + + GuildRank promoterRank = guild.getMemberRank(promoter); + if (promoterRank == null || !promoterRank.hasPermission(GuildPermission.PROMOTE)) { + sendErrorToPlayer(promoter, "§cYou do not have permission to promote members!"); + return; + } + + GuildMember targetMember = guild.getMember(target); + if (targetMember == null) { + sendErrorToPlayer(promoter, "§cThat player is not in your guild!"); + return; + } + + GuildRank currentRank = guild.getRank(targetMember.getRankName()); + if (currentRank == null) return; + + GuildRank nextRank = guild.getNextRankUp(currentRank); + if (nextRank == null || nextRank.getName().equals("Guild Master")) { + sendErrorToPlayer(promoter, "§cThat player cannot be promoted any further!"); + return; + } + + if (!promoterRank.isHigherThan(nextRank)) { + sendErrorToPlayer(promoter, "§cYou can only promote members to ranks below yours!"); + return; + } + + String oldRank = targetMember.getRankName(); + targetMember.setRankName(nextRank.getName()); + persistGuild(guild); + + GuildRankChangedResponseEvent response = new GuildRankChangedResponseEvent(guild, promoter, target, oldRank, nextRank.getName()); + sendEvent(response); + } + + public static void handleDemoteRequest(GuildDemoteRequestEvent event) { + UUID demoter = event.getDemoter(); + UUID target = event.getTarget(); + + GuildData guild = getGuildFromPlayer(demoter); + if (guild == null) { + sendErrorToPlayer(demoter, "§cYou are not in a guild!"); + return; + } + + GuildRank demoterRank = guild.getMemberRank(demoter); + if (demoterRank == null || !demoterRank.hasPermission(GuildPermission.DEMOTE)) { + sendErrorToPlayer(demoter, "§cYou do not have permission to demote members!"); + return; + } + + GuildMember targetMember = guild.getMember(target); + if (targetMember == null) { + sendErrorToPlayer(demoter, "§cThat player is not in your guild!"); + return; + } + + GuildRank currentRank = guild.getRank(targetMember.getRankName()); + if (currentRank == null) return; + + GuildRank nextRank = guild.getNextRankDown(currentRank); + if (nextRank == null) { + sendErrorToPlayer(demoter, "§cThat player cannot be demoted any further!"); + return; + } + + if (!demoterRank.isHigherThan(currentRank)) { + sendErrorToPlayer(demoter, "§cYou can only demote members of lower rank!"); + return; + } + + String oldRank = targetMember.getRankName(); + targetMember.setRankName(nextRank.getName()); + persistGuild(guild); + + GuildRankChangedResponseEvent response = new GuildRankChangedResponseEvent(guild, demoter, target, oldRank, nextRank.getName()); + sendEvent(response); + } + + public static void handleTransferRequest(GuildTransferRequestEvent event) { + UUID currentOwner = event.getCurrentOwner(); + UUID newOwner = event.getNewOwner(); + + GuildData guild = getGuildFromPlayer(currentOwner); + if (guild == null) { + sendErrorToPlayer(currentOwner, "§cYou are not in a guild!"); + return; + } + + if (!guild.getMasterUuid().equals(currentOwner)) { + sendErrorToPlayer(currentOwner, "§cOnly the Guild Master can transfer ownership!"); + return; + } + + GuildMember newOwnerMember = guild.getMember(newOwner); + if (newOwnerMember == null) { + sendErrorToPlayer(currentOwner, "§cThat player is not in your guild!"); + return; + } + + GuildMember currentOwnerMember = guild.getMember(currentOwner); + currentOwnerMember.setRankName("Officer"); + newOwnerMember.setRankName("Guild Master"); + persistGuild(guild); + + GuildTransferredResponseEvent response = new GuildTransferredResponseEvent(guild, currentOwner, newOwner); + sendEvent(response); + } + + public static void handleChatRequest(GuildChatRequestEvent event) { + UUID sender = event.getSender(); + String message = event.getMessage(); + boolean officerChat = event.isOfficerChat(); + + GuildData guild = getGuildFromPlayer(sender); + if (guild == null) { + sendErrorToPlayer(sender, "§cYou are not in a guild!"); + return; + } + + if (officerChat) { + GuildRank rank = guild.getMemberRank(sender); + if (rank == null || !rank.hasPermission(GuildPermission.OFFICER_CHAT)) { + sendErrorToPlayer(sender, "§cYou do not have permission to use officer chat!"); + return; + } + } + + GuildMember member = guild.getMember(sender); + if (member != null && member.isMuted()) { + sendErrorToPlayer(sender, "§cYou are muted in this guild!"); + return; + } + + if (guild.isEveryoneMuted() && guild.getEveryoneMutedExpiry() > System.currentTimeMillis()) { + GuildRank rank = guild.getMemberRank(sender); + if (rank == null || !rank.hasPermission(GuildPermission.MUTE_MEMBERS)) { + sendErrorToPlayer(sender, "§cGuild chat is currently muted!"); + return; + } + } + + if (guild.isSlowChat()) { + Long lastChat = lastChatTimestamps.get(sender); + if (lastChat != null && System.currentTimeMillis() - lastChat < 10000) { + sendErrorToPlayer(sender, "§cSlow mode is enabled. Please wait before sending another message."); + return; + } + lastChatTimestamps.put(sender, System.currentTimeMillis()); + } + + GuildChatResponseEvent response = new GuildChatResponseEvent(guild, sender, message, officerChat); + sendEvent(response); + } + + public static void handleSettingRequest(GuildSettingRequestEvent event) { + UUID changer = event.getChanger(); + String setting = event.getSetting(); + String value = event.getValue(); + + GuildData guild = getGuildFromPlayer(changer); + if (guild == null) { + sendErrorToPlayer(changer, "§cYou are not in a guild!"); + return; + } + + GuildRank rank = guild.getMemberRank(changer); + if (rank == null) return; + + switch (setting.toLowerCase()) { + case "tag" -> { + if (!rank.hasPermission(GuildPermission.MODIFY_TAG)) { + sendErrorToPlayer(changer, "§cYou do not have permission to change the guild tag!"); + return; + } + if (!guild.canSetTag()) { + sendErrorToPlayer(changer, "§cYour guild must be Level 5 to set a tag!"); + return; + } + if (value.length() > guild.getMaxTagLength()) { + sendErrorToPlayer(changer, "§cTag cannot be longer than " + guild.getMaxTagLength() + " characters!"); + return; + } + guild.setTag(value); + } + case "tagcolor" -> { + if (!rank.hasPermission(GuildPermission.MODIFY_TAG)) { + sendErrorToPlayer(changer, "§cYou do not have permission to change the tag color!"); + return; + } + guild.setTagColor(value); + } + case "motd" -> { + if (!rank.hasPermission(GuildPermission.MODIFY_MOTD)) { + sendErrorToPlayer(changer, "§cYou do not have permission to change the MOTD!"); + return; + } + guild.setMotd(value); + } + case "description" -> { + if (!rank.hasPermission(GuildPermission.MODIFY_DESCRIPTION)) { + sendErrorToPlayer(changer, "§cYou do not have permission to change the description!"); + return; + } + guild.setDescription(value); + } + case "discord" -> { + if (!rank.hasPermission(GuildPermission.MODIFY_DISCORD)) { + sendErrorToPlayer(changer, "§cYou do not have permission to change the discord link!"); + return; + } + guild.setDiscordLink(value); + } + case "rename" -> { + if (!guild.getMasterUuid().equals(changer)) { + sendErrorToPlayer(changer, "§cOnly the Guild Master can rename the guild!"); + return; + } + if (value.length() < 3 || value.length() > 30) { + sendErrorToPlayer(changer, "§cGuild name must be between 3 and 30 characters."); + return; + } + if (GuildDatabase.guildNameExists(value)) { + sendErrorToPlayer(changer, "§cA guild with that name already exists!"); + return; + } + guild.setName(value); + } + case "slow" -> { + if (!rank.hasPermission(GuildPermission.MODIFY_SETTINGS)) { + sendErrorToPlayer(changer, "§cYou do not have permission to modify settings!"); + return; + } + guild.setSlowChat(!guild.isSlowChat()); + value = guild.isSlowChat() ? "enabled" : "disabled"; + } + case "finder" -> { + if (!rank.hasPermission(GuildPermission.MODIFY_SETTINGS)) { + sendErrorToPlayer(changer, "§cYou do not have permission to modify settings!"); + return; + } + guild.setListedInFinder(!guild.isListedInFinder()); + value = guild.isListedInFinder() ? "visible" : "hidden"; + } + default -> { + sendErrorToPlayer(changer, "§cUnknown setting: " + setting); + return; + } + } + + persistGuild(guild); + + GuildSettingChangedResponseEvent response = new GuildSettingChangedResponseEvent(guild, changer, setting, value); + sendEvent(response); + } + + public static void handleMuteRequest(GuildMuteRequestEvent event) { + UUID muter = event.getMuter(); + String target = event.getTarget(); + long duration = event.getDuration(); + + GuildData guild = getGuildFromPlayer(muter); + if (guild == null) { + sendErrorToPlayer(muter, "§cYou are not in a guild!"); + return; + } + + GuildRank muterRank = guild.getMemberRank(muter); + if (muterRank == null || !muterRank.hasPermission(GuildPermission.MUTE_MEMBERS)) { + sendErrorToPlayer(muter, "§cYou do not have permission to mute guild members!"); + return; + } + + if (target.equalsIgnoreCase("everyone")) { + guild.setEveryoneMuted(true); + guild.setEveryoneMutedExpiry(System.currentTimeMillis() + duration); + } else { + UUID targetUUID = UUID.fromString(target); + GuildMember member = guild.getMember(targetUUID); + if (member == null) { + sendErrorToPlayer(muter, "§cThat player is not in your guild!"); + return; + } + member.setMutedUntil(System.currentTimeMillis() + duration); + } + + persistGuild(guild); + + GuildMuteChangedResponseEvent response = new GuildMuteChangedResponseEvent(guild, muter, target, duration, false); + sendEvent(response); + } + + public static void handleUnmuteRequest(GuildUnmuteRequestEvent event) { + UUID unmuter = event.getUnmuter(); + String target = event.getTarget(); + + GuildData guild = getGuildFromPlayer(unmuter); + if (guild == null) { + sendErrorToPlayer(unmuter, "§cYou are not in a guild!"); + return; + } + + GuildRank unmuterRank = guild.getMemberRank(unmuter); + if (unmuterRank == null || !unmuterRank.hasPermission(GuildPermission.MUTE_MEMBERS)) { + sendErrorToPlayer(unmuter, "§cYou do not have permission to unmute guild members!"); + return; + } + + if (target.equalsIgnoreCase("everyone")) { + guild.setEveryoneMuted(false); + guild.setEveryoneMutedExpiry(0); + } else { + UUID targetUUID = UUID.fromString(target); + GuildMember member = guild.getMember(targetUUID); + if (member == null) { + sendErrorToPlayer(unmuter, "§cThat player is not in your guild!"); + return; + } + member.setMutedUntil(0); + } + + persistGuild(guild); + + GuildMuteChangedResponseEvent response = new GuildMuteChangedResponseEvent(guild, unmuter, target, 0, true); + sendEvent(response); + } + + public static void handleSetRankRequest(GuildSetRankRequestEvent event) { + UUID setter = event.getSetter(); + UUID target = event.getTarget(); + String rankName = event.getRankName(); + + GuildData guild = getGuildFromPlayer(setter); + if (guild == null) { + sendErrorToPlayer(setter, "§cYou are not in a guild!"); + return; + } + + if (!guild.getMasterUuid().equals(setter)) { + sendErrorToPlayer(setter, "§cOnly the Guild Master can set ranks directly!"); + return; + } + + GuildMember targetMember = guild.getMember(target); + if (targetMember == null) { + sendErrorToPlayer(setter, "§cThat player is not in your guild!"); + return; + } + + GuildRank newRank = guild.getRank(rankName); + if (newRank == null) { + sendErrorToPlayer(setter, "§cThat rank does not exist!"); + return; + } + + if (newRank.getName().equals("Guild Master")) { + sendErrorToPlayer(setter, "§cUse /guild transfer to transfer Guild Master!"); + return; + } + + String oldRank = targetMember.getRankName(); + targetMember.setRankName(newRank.getName()); + persistGuild(guild); + + GuildRankChangedResponseEvent response = new GuildRankChangedResponseEvent(guild, setter, target, oldRank, newRank.getName()); + sendEvent(response); + } + + private static void disbandGuild(GuildData guild, UUID disbander) { + GuildDisbandedResponseEvent response = new GuildDisbandedResponseEvent(guild, disbander); + sendEvent(response); + + guildCache.invalidate(guild.getGuildId()); + GuildDatabase.deleteGuild(guild.getGuildId()); + } + + private static void sendEvent(GuildEvent event) { + JSONObject message = new JSONObject(); + message.put("eventType", event.getClass().getSimpleName()); + message.put("eventData", event.getSerializer().serialize(event)); + message.put("participants", event.getParticipants()); + + ServiceToServerManager.sendToAllServers(FromServiceChannels.PROPAGATE_GUILD_EVENT, message); + } + + private static void sendErrorToPlayer(UUID playerUUID, String message) { + sendMessageToPlayer(playerUUID, "§9§m-----------------------------------------------------\n" + message + "\n§9§m-----------------------------------------------------"); + } + + private static void sendMessageToPlayer(UUID playerUUID, String message) { + JSONObject messageData = new JSONObject(); + messageData.put("playerUUID", playerUUID.toString()); + messageData.put("message", message); + + ServiceToServerManager.sendToAllServers(FromServiceChannels.SEND_MESSAGE, messageData); + } + + private static void scheduleInviteExpiration(UUID guildId, UUID inviter, UUID invitee, long delayMs) { + CompletableFuture.delayedExecutor(delayMs, TimeUnit.MILLISECONDS).execute(() -> { + PendingGuildInvite invite = pendingInvites.remove(invitee); + if (invite != null) { + GuildData guild = getGuild(guildId); + if (guild != null) { + GuildInviteExpiredResponseEvent response = new GuildInviteExpiredResponseEvent(guild, inviter, invitee); + sendEvent(response); + } + } + }); + } + + private static void persistGuild(GuildData guild) { + guildCache.put(guild.getGuildId(), guild); + GuildDatabase.saveGuild(guild); + } + + public record PendingGuildInvite(UUID guildId, UUID inviter, UUID invitee) { + } +} diff --git a/service.guild/src/main/java/net/swofty/service/guild/GuildDatabase.java b/service.guild/src/main/java/net/swofty/service/guild/GuildDatabase.java new file mode 100644 index 000000000..04ee9a43d --- /dev/null +++ b/service.guild/src/main/java/net/swofty/service/guild/GuildDatabase.java @@ -0,0 +1,141 @@ +package net.swofty.service.guild; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.IndexOptions; +import com.mongodb.client.model.Indexes; +import com.mongodb.client.model.Updates; +import net.swofty.commons.guild.GuildData; +import net.swofty.service.generic.MongoDB; +import org.bson.Document; + +import java.util.UUID; + +public record GuildDatabase(String id) implements MongoDB { + public static MongoClient client; + public static MongoDatabase database; + public static MongoCollection guildCollection; + public static MongoCollection playerGuildCollection; + + @Override + public MongoDB connect(String connectionString) { + ConnectionString cs = new ConnectionString(connectionString); + MongoClientSettings settings = MongoClientSettings.builder().applyConnectionString(cs).build(); + client = MongoClients.create(settings); + + database = client.getDatabase("Minestom"); + guildCollection = database.getCollection("guilds"); + playerGuildCollection = database.getCollection("player-guilds"); + + guildCollection.createIndex(Indexes.ascending("name"), new IndexOptions().unique(true)); + playerGuildCollection.createIndex(Indexes.ascending("guildId")); + return this; + } + + public static GuildData getGuild(UUID guildId) { + Document doc = guildCollection.find(Filters.eq("_id", guildId.toString())).first(); + if (doc == null) return null; + return GuildData.getStaticSerializer().deserialize(doc.getString("data")); + } + + public static void saveGuild(GuildData guild) { + String serialized = guild.getSerializer().serialize(guild); + String guildId = guild.getGuildId().toString(); + + Document query = new Document("_id", guildId); + Document existing = guildCollection.find(query).first(); + + if (existing != null) { + guildCollection.updateOne(query, + Updates.combine( + Updates.set("data", serialized), + Updates.set("name", guild.getName().toLowerCase()) + )); + } else { + Document doc = new Document("_id", guildId); + doc.append("data", serialized); + doc.append("name", guild.getName().toLowerCase()); + guildCollection.insertOne(doc); + } + } + + public static void deleteGuild(UUID guildId) { + guildCollection.deleteOne(Filters.eq("_id", guildId.toString())); + playerGuildCollection.deleteMany(Filters.eq("guildId", guildId.toString())); + } + + public static void mapPlayerToGuild(UUID playerUuid, UUID guildId) { + String playerId = playerUuid.toString(); + Document query = new Document("_id", playerId); + Document existing = playerGuildCollection.find(query).first(); + + if (existing != null) { + playerGuildCollection.updateOne(query, Updates.set("guildId", guildId.toString())); + } else { + Document doc = new Document("_id", playerId); + doc.append("guildId", guildId.toString()); + playerGuildCollection.insertOne(doc); + } + } + + public static void removePlayerMapping(UUID playerUuid) { + playerGuildCollection.deleteOne(Filters.eq("_id", playerUuid.toString())); + } + + public static UUID getPlayerGuildId(UUID playerUuid) { + Document doc = playerGuildCollection.find(Filters.eq("_id", playerUuid.toString())).first(); + if (doc == null) return null; + String guildId = doc.getString("guildId"); + return guildId != null ? UUID.fromString(guildId) : null; + } + + public static boolean guildNameExists(String name) { + return guildCollection.find(Filters.eq("name", name.toLowerCase())).first() != null; + } + + @Override + public void set(String key, Object value) { + insertOrUpdate(key, value); + } + + @Override + public Object get(String key, Object def) { + Document doc = guildCollection.find(Filters.eq("_id", id)).first(); + if (doc == null) return def; + return doc.get(key); + } + + @Override + public void insertOrUpdate(String key, Object value) { + if (exists()) { + Document query = new Document("_id", id); + Document found = guildCollection.find(query).first(); + assert found != null; + guildCollection.updateOne(found, Updates.set(key, value)); + return; + } + Document newDoc = new Document("_id", id); + newDoc.append(key, value); + guildCollection.insertOne(newDoc); + } + + @Override + public boolean remove(String id) { + Document query = new Document("_id", id); + Document found = guildCollection.find(query).first(); + if (found == null) return false; + guildCollection.deleteOne(query); + return true; + } + + @Override + public boolean exists() { + Document query = new Document("_id", id); + return guildCollection.find(query).first() != null; + } +} diff --git a/service.guild/src/main/java/net/swofty/service/guild/GuildService.java b/service.guild/src/main/java/net/swofty/service/guild/GuildService.java new file mode 100644 index 000000000..2bfd2ee98 --- /dev/null +++ b/service.guild/src/main/java/net/swofty/service/guild/GuildService.java @@ -0,0 +1,28 @@ +package net.swofty.service.guild; + +import net.swofty.commons.ServiceType; +import net.swofty.commons.config.ConfigProvider; +import net.swofty.service.generic.SkyBlockService; +import net.swofty.service.generic.redis.ServiceEndpoint; + +import java.util.List; + +public class GuildService implements SkyBlockService { + + static void main() { + String mongoUri = ConfigProvider.settings().getMongodb(); + new GuildDatabase(null).connect(mongoUri); + + SkyBlockService.init(new GuildService()); + } + + @Override + public ServiceType getType() { + return ServiceType.GUILD; + } + + @Override + public List getEndpoints() { + return loopThroughPackage("net.swofty.service.guild.endpoints", ServiceEndpoint.class).toList(); + } +} diff --git a/service.guild/src/main/java/net/swofty/service/guild/endpoints/GetGuildEndpoint.java b/service.guild/src/main/java/net/swofty/service/guild/endpoints/GetGuildEndpoint.java new file mode 100644 index 000000000..27b1817c0 --- /dev/null +++ b/service.guild/src/main/java/net/swofty/service/guild/endpoints/GetGuildEndpoint.java @@ -0,0 +1,25 @@ +package net.swofty.service.guild.endpoints; + +import net.swofty.commons.impl.ServiceProxyRequest; +import net.swofty.commons.protocol.objects.guild.GetGuildProtocolObject; +import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.service.guild.GuildCache; + +public class GetGuildEndpoint implements ServiceEndpoint< + GetGuildProtocolObject.GetGuildMessage, + GetGuildProtocolObject.GetGuildResponse> { + + @Override + public GetGuildProtocolObject associatedProtocolObject() { + return new GetGuildProtocolObject(); + } + + @Override + public GetGuildProtocolObject.GetGuildResponse onMessage( + ServiceProxyRequest message, + GetGuildProtocolObject.GetGuildMessage messageObject) { + return new GetGuildProtocolObject.GetGuildResponse( + GuildCache.getGuildFromPlayer(messageObject.memberUUID()) + ); + } +} diff --git a/service.guild/src/main/java/net/swofty/service/guild/endpoints/GuildEventToServiceEndpoint.java b/service.guild/src/main/java/net/swofty/service/guild/endpoints/GuildEventToServiceEndpoint.java new file mode 100644 index 000000000..b5dbf8ec9 --- /dev/null +++ b/service.guild/src/main/java/net/swofty/service/guild/endpoints/GuildEventToServiceEndpoint.java @@ -0,0 +1,46 @@ +package net.swofty.service.guild.endpoints; + +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.guild.events.*; +import net.swofty.commons.impl.ServiceProxyRequest; +import net.swofty.commons.protocol.objects.guild.SendGuildEventToServiceProtocolObject; +import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.service.guild.GuildCache; + +public class GuildEventToServiceEndpoint implements ServiceEndpoint< + SendGuildEventToServiceProtocolObject.SendGuildEventToServiceMessage, + SendGuildEventToServiceProtocolObject.SendGuildEventToServiceResponse> { + + @Override + public SendGuildEventToServiceProtocolObject associatedProtocolObject() { + return new SendGuildEventToServiceProtocolObject(); + } + + @Override + public SendGuildEventToServiceProtocolObject.SendGuildEventToServiceResponse onMessage( + ServiceProxyRequest message, + SendGuildEventToServiceProtocolObject.SendGuildEventToServiceMessage messageObject) { + GuildEvent event = messageObject.event(); + + switch (event) { + case GuildCreateRequestEvent e -> GuildCache.handleCreateRequest(e); + case GuildInviteRequestEvent e -> GuildCache.handleInviteRequest(e); + case GuildAcceptInviteRequestEvent e -> GuildCache.handleAcceptInvite(e); + case GuildLeaveRequestEvent e -> GuildCache.handleLeaveRequest(e); + case GuildKickRequestEvent e -> GuildCache.handleKickRequest(e); + case GuildDisbandRequestEvent e -> GuildCache.handleDisbandRequest(e); + case GuildPromoteRequestEvent e -> GuildCache.handlePromoteRequest(e); + case GuildDemoteRequestEvent e -> GuildCache.handleDemoteRequest(e); + case GuildTransferRequestEvent e -> GuildCache.handleTransferRequest(e); + case GuildChatRequestEvent e -> GuildCache.handleChatRequest(e); + case GuildSettingRequestEvent e -> GuildCache.handleSettingRequest(e); + case GuildMuteRequestEvent e -> GuildCache.handleMuteRequest(e); + case GuildUnmuteRequestEvent e -> GuildCache.handleUnmuteRequest(e); + case GuildSetRankRequestEvent e -> GuildCache.handleSetRankRequest(e); + default -> + throw new IllegalArgumentException("Unknown guild event type: " + event.getClass().getSimpleName()); + } + + return new SendGuildEventToServiceProtocolObject.SendGuildEventToServiceResponse(true); + } +} diff --git a/service.guild/src/main/java/net/swofty/service/guild/endpoints/IsPlayerInGuildEndpoint.java b/service.guild/src/main/java/net/swofty/service/guild/endpoints/IsPlayerInGuildEndpoint.java new file mode 100644 index 000000000..b142bba1a --- /dev/null +++ b/service.guild/src/main/java/net/swofty/service/guild/endpoints/IsPlayerInGuildEndpoint.java @@ -0,0 +1,25 @@ +package net.swofty.service.guild.endpoints; + +import net.swofty.commons.impl.ServiceProxyRequest; +import net.swofty.commons.protocol.objects.guild.IsPlayerInGuildProtocolObject; +import net.swofty.service.generic.redis.ServiceEndpoint; +import net.swofty.service.guild.GuildCache; + +public class IsPlayerInGuildEndpoint implements ServiceEndpoint< + IsPlayerInGuildProtocolObject.IsPlayerInGuildMessage, + IsPlayerInGuildProtocolObject.IsPlayerInGuildResponse> { + + @Override + public IsPlayerInGuildProtocolObject associatedProtocolObject() { + return new IsPlayerInGuildProtocolObject(); + } + + @Override + public IsPlayerInGuildProtocolObject.IsPlayerInGuildResponse onMessage( + ServiceProxyRequest message, + IsPlayerInGuildProtocolObject.IsPlayerInGuildMessage messageObject) { + return new IsPlayerInGuildProtocolObject.IsPlayerInGuildResponse( + GuildCache.isInGuild(messageObject.playerUUID()) + ); + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index d3db14d90..fd679ef1e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -52,4 +52,5 @@ include(":service.darkauction") include(":service.friend") include(":service.punishment") include(":service.elections") +include(":service.guild") include(":anticheat") diff --git a/type.generic/src/main/java/net/swofty/type/generic/command/commands/GuildCommand.java b/type.generic/src/main/java/net/swofty/type/generic/command/commands/GuildCommand.java new file mode 100644 index 000000000..0da07a2ec --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/command/commands/GuildCommand.java @@ -0,0 +1,221 @@ +package net.swofty.type.generic.command.commands; + +import net.minestom.server.command.builder.arguments.ArgumentString; +import net.minestom.server.command.builder.arguments.ArgumentStringArray; +import net.minestom.server.command.builder.arguments.ArgumentType; +import net.swofty.commons.ServiceType; +import net.swofty.commons.guild.GuildData; +import net.swofty.proxyapi.ProxyService; +import net.swofty.type.generic.command.CommandParameters; +import net.swofty.type.generic.command.HypixelCommand; +import net.swofty.type.generic.guild.GuildManager; +import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.user.categories.Rank; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +@CommandParameters(aliases = "g", + description = "Guild management commands", + usage = "/guild ", + permission = Rank.DEFAULT, + allowsConsole = false) +public class GuildCommand extends HypixelCommand { + private final List pendingCommands = new ArrayList<>(); + + @Override + public void registerUsage(MinestomCommand command) { + ArgumentString subcommand = ArgumentType.String("subcommand"); + ArgumentString argument = ArgumentType.String("argument"); + ProxyService guildService = new ProxyService(ServiceType.GUILD); + + command.addSyntax((sender, context) -> { + showHelp((HypixelPlayer) sender); + }); + + command.addSyntax((sender, context) -> { + if (!permissionCheck(sender)) return; + HypixelPlayer player = (HypixelPlayer) sender; + if (pendingCommands.contains(player.getUuid())) return; + pendingCommands.add(player.getUuid()); + + Thread.startVirtualThread(() -> { + try { + if (!guildService.isOnline().join()) { + player.sendMessage("§cGuild service is currently offline!"); + return; + } + + String sub = context.get(subcommand); + + switch (sub.toLowerCase()) { + case "leave" -> GuildManager.leaveGuild(player); + case "disband" -> GuildManager.disbandGuild(player); + case "list", "info" -> showGuildInfo(player); + case "online" -> showOnlineMembers(player); + case "notifications" -> GuildManager.changeSetting(player, "notifications", "toggle"); + case "mute" -> GuildManager.mutePlayer(player, "everyone", 3600000); + case "unmute" -> GuildManager.unmutePlayer(player, "everyone"); + default -> GuildManager.invitePlayer(player, sub); + } + } finally { + pendingCommands.remove(player.getUuid()); + } + }); + }, subcommand); + + command.addSyntax((sender, context) -> { + if (!permissionCheck(sender)) return; + HypixelPlayer player = (HypixelPlayer) sender; + if (pendingCommands.contains(player.getUuid())) return; + pendingCommands.add(player.getUuid()); + + Thread.startVirtualThread(() -> { + try { + if (!guildService.isOnline().join()) { + player.sendMessage("§cGuild service is currently offline!"); + return; + } + + String sub = context.get(subcommand); + String arg = context.get(argument); + + switch (sub.toLowerCase()) { + case "create" -> GuildManager.createGuild(player, arg); + case "invite" -> GuildManager.invitePlayer(player, arg); + case "accept" -> GuildManager.acceptInvite(player, arg); + case "kick" -> GuildManager.kickPlayer(player, arg, ""); + case "promote" -> GuildManager.promotePlayer(player, arg); + case "demote" -> GuildManager.demotePlayer(player, arg); + case "transfer" -> GuildManager.transferOwnership(player, arg); + case "tag" -> GuildManager.changeSetting(player, "tag", arg); + case "tagcolor" -> GuildManager.changeSetting(player, "tagcolor", arg); + case "rename" -> GuildManager.changeSetting(player, "rename", arg); + case "slow" -> GuildManager.changeSetting(player, "slow", arg); + case "finder" -> GuildManager.changeSetting(player, "finder", arg); + case "chat" -> GuildManager.sendChat(player, arg, false); + case "officerchat", "oc" -> GuildManager.sendChat(player, arg, true); + case "mute" -> GuildManager.mutePlayer(player, arg, 3600000); + case "unmute" -> GuildManager.unmutePlayer(player, arg); + default -> player.sendMessage("§cUnknown guild command. Use /guild for help."); + } + } finally { + pendingCommands.remove(player.getUuid()); + } + }); + }, subcommand, argument); + + command.addSyntax((sender, context) -> { + if (!permissionCheck(sender)) return; + HypixelPlayer player = (HypixelPlayer) sender; + if (pendingCommands.contains(player.getUuid())) return; + pendingCommands.add(player.getUuid()); + + Thread.startVirtualThread(() -> { + try { + if (!guildService.isOnline().join()) { + player.sendMessage("§cGuild service is currently offline!"); + return; + } + + String sub = context.get(subcommand); + String[] args = context.get(new ArgumentStringArray("args")); + String message = String.join(" ", args); + + switch (sub.toLowerCase()) { + case "chat" -> GuildManager.sendChat(player, message, false); + case "officerchat", "oc" -> GuildManager.sendChat(player, message, true); + case "motd" -> GuildManager.changeSetting(player, "motd", message); + case "description" -> GuildManager.changeSetting(player, "description", message); + case "discord" -> GuildManager.changeSetting(player, "discord", message); + case "kick" -> { + if (args.length >= 1) { + String targetName = args[0]; + String reason = args.length > 1 ? String.join(" ", Arrays.copyOfRange(args, 1, args.length)) : ""; + GuildManager.kickPlayer(player, targetName, reason); + } + } + case "setrank" -> { + if (args.length >= 2) { + GuildManager.setRank(player, args[0], args[1]); + } else { + player.sendMessage("§cUsage: /guild setrank "); + } + } + default -> player.sendMessage("§cUnknown guild command. Use /guild for help."); + } + } finally { + pendingCommands.remove(player.getUuid()); + } + }); + }, subcommand, new ArgumentStringArray("args")); + } + + private void showGuildInfo(HypixelPlayer player) { + GuildData guild = GuildManager.getGuildFromPlayer(player); + if (guild == null) { + player.sendMessage("§9§m-----------------------------------------------------"); + player.sendMessage("§cYou are not in a guild!"); + player.sendMessage("§9§m-----------------------------------------------------"); + return; + } + + player.sendMessage("§9§m-----------------------------------------------------"); + player.sendMessage("§6§l" + guild.getName() + (guild.getTag() != null ? " §7[" + guild.getTagColor() + guild.getTag() + "§7]" : "")); + player.sendMessage("§7Level: §a" + guild.getLevel()); + player.sendMessage("§7Members: §a" + guild.getMembers().size() + "/" + GuildData.MAX_MEMBERS); + player.sendMessage("§7GEXP: §a" + guild.getTotalGexp()); + if (guild.getMotd() != null && !guild.getMotd().isEmpty()) { + player.sendMessage("§7MOTD: §f" + guild.getMotd()); + } + if (guild.getDescription() != null && !guild.getDescription().isEmpty()) { + player.sendMessage("§7Description: §f" + guild.getDescription()); + } + player.sendMessage("§9§m-----------------------------------------------------"); + } + + private void showOnlineMembers(HypixelPlayer player) { + GuildData guild = GuildManager.getGuildFromPlayer(player); + if (guild == null) { + player.sendMessage("§9§m-----------------------------------------------------"); + player.sendMessage("§cYou are not in a guild!"); + player.sendMessage("§9§m-----------------------------------------------------"); + return; + } + + player.sendMessage("§9§m-----------------------------------------------------"); + player.sendMessage("§6Guild Members - §a" + guild.getMembers().size()); + String memberList = guild.getMembers().stream() + .map(m -> HypixelPlayer.getDisplayName(m.getUuid())) + .collect(Collectors.joining("§7, ")); + player.sendMessage(memberList); + player.sendMessage("§9§m-----------------------------------------------------"); + } + + private void showHelp(HypixelPlayer player) { + player.sendMessage("§9§m-----------------------------------------------------"); + player.sendMessage("§b§lGuild Commands"); + player.sendMessage("§e/guild create §7- Create a guild"); + player.sendMessage("§e/guild invite §7- Invite a player"); + player.sendMessage("§e/guild accept §7- Accept an invite"); + player.sendMessage("§e/guild leave §7- Leave your guild"); + player.sendMessage("§e/guild kick [reason] §7- Kick a member"); + player.sendMessage("§e/guild promote §7- Promote a member"); + player.sendMessage("§e/guild demote §7- Demote a member"); + player.sendMessage("§e/guild transfer §7- Transfer ownership"); + player.sendMessage("§e/guild setrank §7- Set member rank"); + player.sendMessage("§e/guild disband §7- Disband the guild"); + player.sendMessage("§e/guild chat §7- Send guild chat"); + player.sendMessage("§e/guild officerchat §7- Officer chat"); + player.sendMessage("§e/guild tag §7- Set guild tag"); + player.sendMessage("§e/guild motd §7- Set MOTD"); + player.sendMessage("§e/guild list §7- View guild info"); + player.sendMessage("§e/guild online §7- View online members"); + player.sendMessage("§e/guild mute [player] §7- Mute chat/player"); + player.sendMessage("§e/guild unmute [player] §7- Unmute chat/player"); + player.sendMessage("§9§m-----------------------------------------------------"); + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/guild/GuildManager.java b/type.generic/src/main/java/net/swofty/type/generic/guild/GuildManager.java new file mode 100644 index 000000000..47b41a4d5 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/guild/GuildManager.java @@ -0,0 +1,153 @@ +package net.swofty.type.generic.guild; + +import net.swofty.commons.ServiceType; +import net.swofty.commons.guild.GuildData; +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.guild.events.*; +import net.swofty.commons.protocol.objects.guild.GetGuildProtocolObject; +import net.swofty.commons.protocol.objects.guild.IsPlayerInGuildProtocolObject; +import net.swofty.commons.protocol.objects.guild.SendGuildEventToServiceProtocolObject; +import net.swofty.proxyapi.ProxyService; +import net.swofty.type.generic.data.HypixelDataHandler; +import net.swofty.type.generic.user.HypixelPlayer; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public class GuildManager { + private static final ProxyService guildService = new ProxyService(ServiceType.GUILD); + + public static boolean isInGuild(HypixelPlayer player) { + if (!guildService.isOnline().join()) return false; + return guildService.handleRequest( + new IsPlayerInGuildProtocolObject.IsPlayerInGuildMessage(player.getUuid())) + .thenApply(IsPlayerInGuildProtocolObject.IsPlayerInGuildResponse::isInGuild) + .join(); + } + + public static @Nullable GuildData getGuildFromPlayer(HypixelPlayer player) { + if (!guildService.isOnline().join()) return null; + return guildService.handleRequest( + new GetGuildProtocolObject.GetGuildMessage(player.getUuid())) + .thenApply(GetGuildProtocolObject.GetGuildResponse::guild) + .join(); + } + + public static void createGuild(HypixelPlayer creator, String guildName) { + GuildCreateRequestEvent event = new GuildCreateRequestEvent(creator.getUuid(), guildName); + sendEventToService(event); + } + + public static void invitePlayer(HypixelPlayer inviter, String targetName) { + @Nullable UUID targetUUID = HypixelDataHandler.getPotentialUUIDFromName(targetName); + if (targetUUID == null) { + sendError(inviter, "§cCouldn't find a player with that name!"); + return; + } + GuildInviteRequestEvent event = new GuildInviteRequestEvent(inviter.getUuid(), targetUUID); + sendEventToService(event); + } + + public static void acceptInvite(HypixelPlayer player, String inviterName) { + @Nullable UUID inviterUUID = HypixelDataHandler.getPotentialUUIDFromName(inviterName); + if (inviterUUID == null) { + sendError(player, "§cCouldn't find a player with that name!"); + return; + } + GuildAcceptInviteRequestEvent event = new GuildAcceptInviteRequestEvent(player.getUuid(), inviterUUID); + sendEventToService(event); + } + + public static void leaveGuild(HypixelPlayer player) { + GuildLeaveRequestEvent event = new GuildLeaveRequestEvent(player.getUuid()); + sendEventToService(event); + } + + public static void kickPlayer(HypixelPlayer kicker, String targetName, String reason) { + @Nullable UUID targetUUID = HypixelDataHandler.getPotentialUUIDFromName(targetName); + if (targetUUID == null) { + sendError(kicker, "§cCouldn't find a player with that name!"); + return; + } + GuildKickRequestEvent event = new GuildKickRequestEvent(kicker.getUuid(), targetUUID, reason); + sendEventToService(event); + } + + public static void disbandGuild(HypixelPlayer player) { + GuildDisbandRequestEvent event = new GuildDisbandRequestEvent(player.getUuid()); + sendEventToService(event); + } + + public static void promotePlayer(HypixelPlayer promoter, String targetName) { + @Nullable UUID targetUUID = HypixelDataHandler.getPotentialUUIDFromName(targetName); + if (targetUUID == null) { + sendError(promoter, "§cCouldn't find a player with that name!"); + return; + } + GuildPromoteRequestEvent event = new GuildPromoteRequestEvent(promoter.getUuid(), targetUUID); + sendEventToService(event); + } + + public static void demotePlayer(HypixelPlayer demoter, String targetName) { + @Nullable UUID targetUUID = HypixelDataHandler.getPotentialUUIDFromName(targetName); + if (targetUUID == null) { + sendError(demoter, "§cCouldn't find a player with that name!"); + return; + } + GuildDemoteRequestEvent event = new GuildDemoteRequestEvent(demoter.getUuid(), targetUUID); + sendEventToService(event); + } + + public static void transferOwnership(HypixelPlayer owner, String targetName) { + @Nullable UUID targetUUID = HypixelDataHandler.getPotentialUUIDFromName(targetName); + if (targetUUID == null) { + sendError(owner, "§cCouldn't find a player with that name!"); + return; + } + GuildTransferRequestEvent event = new GuildTransferRequestEvent(owner.getUuid(), targetUUID); + sendEventToService(event); + } + + public static void sendChat(HypixelPlayer player, String message, boolean officerChat) { + GuildChatRequestEvent event = new GuildChatRequestEvent(player.getUuid(), message, officerChat); + sendEventToService(event); + } + + public static void changeSetting(HypixelPlayer player, String setting, String value) { + GuildSettingRequestEvent event = new GuildSettingRequestEvent(player.getUuid(), setting, value); + sendEventToService(event); + } + + public static void mutePlayer(HypixelPlayer muter, String target, long duration) { + GuildMuteRequestEvent event = new GuildMuteRequestEvent(muter.getUuid(), target, duration); + sendEventToService(event); + } + + public static void unmutePlayer(HypixelPlayer unmuter, String target) { + GuildUnmuteRequestEvent event = new GuildUnmuteRequestEvent(unmuter.getUuid(), target); + sendEventToService(event); + } + + public static void setRank(HypixelPlayer setter, String targetName, String rankName) { + @Nullable UUID targetUUID = HypixelDataHandler.getPotentialUUIDFromName(targetName); + if (targetUUID == null) { + sendError(setter, "§cCouldn't find a player with that name!"); + return; + } + GuildSetRankRequestEvent event = new GuildSetRankRequestEvent(setter.getUuid(), targetUUID, rankName); + sendEventToService(event); + } + + private static void sendEventToService(GuildEvent event) { + var message = new SendGuildEventToServiceProtocolObject.SendGuildEventToServiceMessage(event); + guildService.handleRequest(message); + } + + private static void sendError(HypixelPlayer player, String message) { + player.sendMessage("§9§m-----------------------------------------------------"); + player.sendMessage(message); + player.sendMessage("§9§m-----------------------------------------------------"); + } +} diff --git a/type.generic/src/main/java/net/swofty/type/generic/redis/service/RedisPropagateGuildEvent.java b/type.generic/src/main/java/net/swofty/type/generic/redis/service/RedisPropagateGuildEvent.java new file mode 100644 index 000000000..6503ef1f1 --- /dev/null +++ b/type.generic/src/main/java/net/swofty/type/generic/redis/service/RedisPropagateGuildEvent.java @@ -0,0 +1,246 @@ +package net.swofty.type.generic.redis.service; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.swofty.commons.guild.GuildEvent; +import net.swofty.commons.guild.events.response.*; +import net.swofty.commons.service.FromServiceChannels; +import net.swofty.proxyapi.redis.ServiceToClient; +import net.swofty.type.generic.HypixelGenericLoader; +import net.swofty.type.generic.user.HypixelPlayer; +import org.json.JSONArray; +import org.json.JSONObject; +import org.tinylog.Logger; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class RedisPropagateGuildEvent implements ServiceToClient { + + @Override + public FromServiceChannels getChannel() { + return FromServiceChannels.PROPAGATE_GUILD_EVENT; + } + + @Override + public JSONObject onMessage(JSONObject message) { + try { + String eventType = message.getString("eventType"); + String eventData = message.getString("eventData"); + JSONArray participantsArray = message.getJSONArray("participants"); + + List participants = participantsArray.toList().stream() + .map(obj -> UUID.fromString(obj.toString())) + .toList(); + + GuildEvent event = parseEvent(eventType, eventData); + if (event == null) { + return createFailureResponse("Failed to parse event of type: " + eventType); + } + + List playersHandled = handleEventForPlayers(event, participants); + return createSuccessResponse(playersHandled.size(), playersHandled); + } catch (Exception e) { + Logger.error("Failed to handle guild event: " + e.getMessage()); + return createFailureResponse("Exception occurred: " + e.getMessage()); + } + } + + private GuildEvent parseEvent(String eventType, String eventData) { + try { + GuildEvent templateEvent = GuildEvent.findFromType(eventType); + return (GuildEvent) templateEvent.getSerializer().deserialize(eventData); + } catch (Exception e) { + Logger.error(e, "Failed to parse guild event of type: {}", eventType); + return null; + } + } + + private List handleEventForPlayers(GuildEvent event, List participants) { + List playersHandled = new ArrayList<>(); + + for (UUID participantUUID : participants) { + HypixelPlayer player = HypixelGenericLoader.getLoadedPlayers().stream() + .filter(p -> p.getUuid().equals(participantUUID)) + .findFirst() + .orElse(null); + + if (player != null) { + try { + handleEventForPlayer(player, event); + playersHandled.add(participantUUID); + } catch (Exception e) { + Logger.error("Failed to handle guild event for player " + participantUUID + ": " + e.getMessage()); + } + } + } + + return playersHandled; + } + + private void handleEventForPlayer(HypixelPlayer player, GuildEvent event) { + switch (event) { + case GuildCreatedResponseEvent e -> handleCreated(player, e); + case GuildInviteSentResponseEvent e -> handleInviteSent(player, e); + case GuildMemberJoinedResponseEvent e -> handleMemberJoined(player, e); + case GuildMemberLeftResponseEvent e -> handleMemberLeft(player, e); + case GuildMemberKickedResponseEvent e -> handleMemberKicked(player, e); + case GuildDisbandedResponseEvent e -> handleDisbanded(player, e); + case GuildRankChangedResponseEvent e -> handleRankChanged(player, e); + case GuildTransferredResponseEvent e -> handleTransferred(player, e); + case GuildChatResponseEvent e -> handleChat(player, e); + case GuildSettingChangedResponseEvent e -> handleSettingChanged(player, e); + case GuildMuteChangedResponseEvent e -> handleMuteChanged(player, e); + case GuildInviteExpiredResponseEvent e -> handleInviteExpired(player, e); + default -> Logger.warn("Unhandled guild event type: " + event.getClass().getSimpleName()); + } + } + + private void handleCreated(HypixelPlayer player, GuildCreatedResponseEvent event) { + sendMessage(player, "§aYou created the guild §6" + event.getGuild().getName() + "§a!"); + } + + private void handleInviteSent(HypixelPlayer player, GuildInviteSentResponseEvent event) { + if (event.getInvitee().equals(player.getUuid())) { + sendMessage(player, HypixelPlayer.getDisplayName(event.getInviter()) + " §ehas invited you to join their guild §6" + event.getGuild().getName() + "§e!"); + TextComponent component = LegacyComponentSerializer.legacySection().deserialize("§eYou have §c60 §eseconds to accept. §6Click here to join!"); + component = component.hoverEvent(Component.text("§eClick to accept!")); + component = component.clickEvent(ClickEvent.runCommand("/guild accept " + HypixelPlayer.getRawName(event.getInviter()))); + player.sendMessage(component); + } else if (event.getInviter().equals(player.getUuid())) { + sendMessage(player, "§eYou invited " + HypixelPlayer.getDisplayName(event.getInvitee()) + " §eto your guild. They have §c60 §eseconds to accept."); + } + } + + private void handleMemberJoined(HypixelPlayer player, GuildMemberJoinedResponseEvent event) { + if (event.getJoiner().equals(player.getUuid())) { + sendMessage(player, "§aYou joined the guild §6" + event.getGuild().getName() + "§a!"); + } else { + sendMessage(player, HypixelPlayer.getDisplayName(event.getJoiner()) + " §ejoined the guild!"); + } + } + + private void handleMemberLeft(HypixelPlayer player, GuildMemberLeftResponseEvent event) { + if (event.getLeaver().equals(player.getUuid())) { + sendMessage(player, "§eYou left the guild."); + } else { + sendMessage(player, HypixelPlayer.getDisplayName(event.getLeaver()) + " §eleft the guild."); + } + } + + private void handleMemberKicked(HypixelPlayer player, GuildMemberKickedResponseEvent event) { + if (event.getKicked().equals(player.getUuid())) { + String reason = event.getReason() != null && !event.getReason().isEmpty() + ? " §7Reason: §f" + event.getReason() : ""; + sendMessage(player, "§cYou have been kicked from the guild!" + reason); + } else { + sendMessage(player, HypixelPlayer.getDisplayName(event.getKicker()) + " §ekicked " + HypixelPlayer.getDisplayName(event.getKicked()) + " §efrom the guild!"); + } + } + + private void handleDisbanded(HypixelPlayer player, GuildDisbandedResponseEvent event) { + sendMessage(player, HypixelPlayer.getDisplayName(event.getDisbander()) + " §edisbanded the guild!"); + } + + private void handleRankChanged(HypixelPlayer player, GuildRankChangedResponseEvent event) { + if (event.getTarget().equals(player.getUuid())) { + boolean promoted = isPrioritized(event.getFromRank(), event.getToRank()); + String action = promoted ? "§apromoted" : "§cdemoted"; + sendMessage(player, "§eYou were " + action + " §eto §6" + event.getToRank() + "§e!"); + } else { + sendMessage(player, HypixelPlayer.getDisplayName(event.getChanger()) + " §echanged " + HypixelPlayer.getDisplayName(event.getTarget()) + "'s §erank from §6" + event.getFromRank() + " §eto §6" + event.getToRank() + "§e."); + } + } + + private void handleTransferred(HypixelPlayer player, GuildTransferredResponseEvent event) { + if (event.getNewOwner().equals(player.getUuid())) { + sendMessage(player, "§aYou are now the Guild Master!"); + } else { + sendMessage(player, HypixelPlayer.getDisplayName(event.getOldOwner()) + " §etransferred guild ownership to " + HypixelPlayer.getDisplayName(event.getNewOwner()) + "§e!"); + } + } + + private void handleChat(HypixelPlayer player, GuildChatResponseEvent event) { + String prefix = event.isOfficerChat() ? "§3Officer" : "§2Guild"; + String senderName = HypixelPlayer.getDisplayName(event.getSender()); + player.sendMessage(prefix + " > " + senderName + "§f: " + event.getMessage()); + } + + private void handleSettingChanged(HypixelPlayer player, GuildSettingChangedResponseEvent event) { + String changerName = HypixelPlayer.getDisplayName(event.getChanger()); + String settingDisplay = switch (event.getSetting().toLowerCase()) { + case "tag" -> "guild tag to §6" + event.getValue(); + case "tagcolor" -> "tag color to §6" + event.getValue(); + case "motd" -> "the MOTD"; + case "description" -> "the description"; + case "discord" -> "the Discord link"; + case "rename" -> "the guild name to §6" + event.getValue(); + case "slow" -> "slow chat to §6" + event.getValue(); + case "finder" -> "guild finder to §6" + event.getValue(); + default -> event.getSetting() + " to " + event.getValue(); + }; + sendMessage(player, changerName + " §eupdated " + settingDisplay + "§e."); + } + + private void handleMuteChanged(HypixelPlayer player, GuildMuteChangedResponseEvent event) { + String muterName = HypixelPlayer.getDisplayName(event.getMuter()); + if (event.isUnmute()) { + if (event.getTarget().equalsIgnoreCase("everyone")) { + sendMessage(player, muterName + " §eunmuted the guild chat."); + } else { + sendMessage(player, muterName + " §eunmuted " + HypixelPlayer.getDisplayName(UUID.fromString(event.getTarget())) + "§e."); + } + } else { + long minutes = event.getDuration() / 60000; + if (event.getTarget().equalsIgnoreCase("everyone")) { + sendMessage(player, muterName + " §emuted the guild chat for §c" + minutes + " minutes§e."); + } else { + sendMessage(player, muterName + " §emuted " + HypixelPlayer.getDisplayName(UUID.fromString(event.getTarget())) + " §efor §c" + minutes + " minutes§e."); + } + } + } + + private void handleInviteExpired(HypixelPlayer player, GuildInviteExpiredResponseEvent event) { + if (event.getInvitee().equals(player.getUuid())) { + sendMessage(player, "§eThe guild invite from " + HypixelPlayer.getDisplayName(event.getInviter()) + " §ehas expired."); + } else if (event.getInviter().equals(player.getUuid())) { + sendMessage(player, "§eThe guild invite to " + HypixelPlayer.getDisplayName(event.getInvitee()) + " §ehas expired."); + } + } + + private boolean isPrioritized(String fromRank, String toRank) { + return switch (toRank) { + case "Guild Master" -> true; + case "Officer" -> fromRank.equals("Member"); + default -> false; + }; + } + + private void sendMessage(HypixelPlayer player, String message) { + player.sendMessage("§9§m-----------------------------------------------------"); + player.sendMessage(message); + player.sendMessage("§9§m-----------------------------------------------------"); + } + + private JSONObject createSuccessResponse(int playersHandled, List playersHandledUuids) { + JSONObject response = new JSONObject(); + response.put("success", true); + response.put("playersHandled", playersHandled); + JSONArray participantsArray = new JSONArray(); + for (UUID uuid : playersHandledUuids) { + participantsArray.put(uuid.toString()); + } + response.put("playersHandledUUIDs", participantsArray); + return response; + } + + private JSONObject createFailureResponse(String reason) { + JSONObject response = new JSONObject(); + response.put("success", false); + response.put("error", reason); + return response; + } +} diff --git a/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIGuild.java b/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIGuild.java new file mode 100644 index 000000000..a7412823e --- /dev/null +++ b/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIGuild.java @@ -0,0 +1,474 @@ +package net.swofty.type.lobby.gui; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.minestom.server.entity.PlayerSkin; +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.inventory.click.Click; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.swofty.commons.StringUtility; +import net.swofty.commons.guild.GuildData; +import net.swofty.commons.guild.GuildMember; +import net.swofty.type.generic.HypixelGenericLoader; +import net.swofty.type.generic.data.HypixelDataHandler; +import net.swofty.type.generic.data.datapoints.DatapointString; +import net.swofty.type.generic.gui.HypixelSignGUI; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.View; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.generic.guild.GuildManager; +import net.swofty.type.generic.user.HypixelPlayer; +import net.swofty.type.generic.user.categories.Rank; +import org.jetbrains.annotations.Nullable; + +import java.text.NumberFormat; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +public class GUIGuild implements View { + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Guild", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, GuildState state, ViewContext ctx) { + if (state.guild() == null) { + layoutNoGuild(layout, ctx); + } else { + layoutWithGuild(layout, state.guild(), ctx); + } + } + + private void layoutNoGuild(ViewLayout layout, ViewContext ctx) { + HypixelPlayer player = ctx.player(); + int level = player.getExperienceHandler().getLevel(); + int achievementPoints = player.getAchievementHandler().getTotalPoints(); + + layout.slot(2, ItemStackCreator.getStackHead( + player.getFullDisplayName(), + player.getSkin(), + 1, + "§7Hypixel Level: §6" + level, + "§7Achievement Points: §e" + StringUtility.commaify(achievementPoints), + "§7Guild: §bNone" + )); + layout.slot(3, ItemStackCreator.getStackHead( + "§aFriends", + "e063eedb2184354bd43a19deffba51b53dd6b7222f8388caa239cabcdce84", + 1, + "§7View your Hypixel friends' profiles,", + "§7and interact with your online friends!" + )); + layout.slot(4, ItemStackCreator.getStackHead( + "§aParty", + "667963ca1ffdc24a10b397ff8161d0da82d6a3f4788d5f67f1a9f9bfbc1eb1", + 1, + "§7Create a party and join up with", + "§7other players to play games", + "§7together!" + )); + layout.slot(5, ItemStackCreator.getStackHead( + "§aGuild", + "fe8b59f8cce510809427c3843cf575fae8fe6a8b7d1560dd46958d148563815", + 1, + "§7Form a guild with other Hypixel", + "§7players to conquer game modes and", + "§7work towards common Hypixel", + "§7rewards." + )); + layout.slot(6, ItemStackCreator.getStackHead( + "§aRecent Players", + "9993a356809532d696841a37a0549b81b159b79a7b2919cff4e5abdfea83d66", + 1, + "§7View players you have played recent", + "§7games with." + )); + + if (canCreateGuild(player)) { + layout.slot(29, ItemStackCreator.getStack( + "§aCreate Guild", + Material.OAK_SIGN, + 1, + "§7Create a guild with your own tag,", + "§7settings and progression.", + "", + "§eClick to create!" + ), (click, viewCtx) -> new HypixelSignGUI(viewCtx.player()) + .open(new String[]{"Guild Name", "Enter guild name"}) + .thenAccept(name -> { + if (name == null || name.isBlank()) { + return; + } + GuildManager.createGuild(viewCtx.player(), name.trim()); + })); + } else { + layout.slot(29, ItemStackCreator.getStack( + "§cCreate Guild", + Material.OAK_SIGN, + 1, + "§7Only players with §aVIP§6+§7 or higher can", + "§7create guilds, but anybody can join", + "§7them." + )); + } + + layout.slot(31, ItemStackCreator.getStack( + "§aGuild Finder", + Material.PAPER, + 1, + "§7Find a Guild you can join based on", + "§7your favorite games.", + "", + "§eClick to browse!" + )); + layout.slot(33, ItemStackCreator.getStack( + "§aSearch Guilds", + Material.BOOK, + 1, + "§7Click here to search guilds you can", + "§7join on the Hypixel Network website!" + ), (_, context) -> context.player().sendMessage(Component.text("§cThis Feature is not there yet. §aOpen a Pull request HERE to get it added quickly!") + .clickEvent(ClickEvent.openUrl("https://github.com/Swofty-Developments/HypixelSkyBlock")))); + } + + private void layoutWithGuild(ViewLayout layout, GuildData guild, ViewContext ctx) { + HypixelPlayer player = ctx.player(); + NumberFormat nf = NumberFormat.getInstance(); + int level = player.getExperienceHandler().getLevel(); + int achievementPoints = player.getAchievementHandler().getTotalPoints(); + + layout.slot(2, ItemStackCreator.getStackHead( + player.getFullDisplayName(), + player.getSkin(), + 1, + "§7Hypixel Level: §6" + level, + "§7Achievement Points: §e" + StringUtility.commaify(achievementPoints), + "§7Guild: §b" + guild.getName() + )); + layout.slot(3, ItemStackCreator.getStackHead( + "§aFriends", + "e063eedb2184354bd43a19deffba51b53dd6b7222f8388caa239cabcdce84", + 1, + "§7View your Hypixel friends' profiles,", + "§7and interact with your online friends!" + )); + layout.slot(4, ItemStackCreator.getStackHead( + "§aParty", + "667963ca1ffdc24a10b397ff8161d0da82d6a3f4788d5f67f1a9f9bfbc1eb1", + 1, + "§7Create a party and join up with", + "§7other players to play games", + "§7together!" + )); + layout.slot(5, ItemStackCreator.getStackHead( + "§aGuild", + "fe8b59f8cce510809427c3843cf575fae8fe6a8b7d1560dd46958d148563815", + 1, + "§7Form a guild with other Hypixel", + "§7players to conquer game modes and", + "§7work towards common Hypixel", + "§7rewards." + )); + layout.slot(6, ItemStackCreator.getStackHead( + "§aRecent Players", + "9993a356809532d696841a37a0549b81b159b79a7b2919cff4e5abdfea83d66", + 1, + "§7View players you have played recent", + "§7games with." + )); + + GuildMember self = guild.getMember(player.getUuid()); + String rankName = self != null ? self.getRankName() : "Unknown"; + + layout.slot(18, ItemStackCreator.getStack( + "§aInvite Player", + Material.WRITABLE_BOOK, + 1, + "§7Click here to invite a player to your", + "§7Guild." + ), (click, viewCtx) -> new HypixelSignGUI(viewCtx.player()) + .open(new String[]{"Invite Player", "Enter username"}) + .thenAccept(name -> { + if (name == null || name.isBlank()) { + return; + } + GuildManager.invitePlayer(viewCtx.player(), name.trim()); + })); + + layout.slot(19, ItemStackCreator.getStack( + "§aGuild Information", + Material.PAINTING, + 1, + "§7Name: §6" + guild.getName(), + "§7Rank: §6" + rankName, + "§7Daily Exp: §6" + nf.format(0), + "§7Members: §6" + guild.getMembers().size() + "§b/§6" + GuildData.MAX_MEMBERS + )); + + layout.slot(20, ItemStackCreator.getStack( + "§aGuild Settings", + Material.COMPARATOR, + 1, + "§7Edit settings such as your tag,", + "§7permissions and guild finder options", + "", + "§eClick to configure!" + ), (click, viewCtx) -> viewCtx.push(new GUIGuildSettings(), new GUIGuildSettings.GuildSettingsState(guild))); + + layout.slot(21, ItemStackCreator.getStack( + "§aWeekly Guild Quest", + Material.ENCHANTED_BOOK, + 1, + "§eTo complete the quest, Guild Members", + "§eneed to complete Challenges in any", + "§egame.", + "§7Tier 1: §60§7/25", + "§7Tier 2: §60§7/100", + "§7Tier 3: §60§7/500", + "§7Tier 4: §60§7/1500", + "", + "§7Reward: §250,000 Guild Experience", + "§eResets in: 0 hours, 0 minutes" + )); + + long expIntoCurrentLevel = getExpIntoCurrentLevel(guild); + long expNeededForNext = guild.getGexpForLevel(guild.getLevel() + 1); + long expRemaining = Math.max(0, expNeededForNext - expIntoCurrentLevel); + double levelProgress = expNeededForNext <= 0 ? 1.0 : Math.min(1.0, (double) expIntoCurrentLevel / (double) expNeededForNext); + int progressPercent = (int) Math.round(levelProgress * 100.0); + + layout.slot(22, ItemStackCreator.getStack( + "§aGuild Leveling", + Material.BREWING_STAND, + 1, + "§7Guild Level: §6" + guild.getLevel(), + "§6" + guild.getLevel() + " " + createProgressBar(levelProgress, 40) + " §6" + (guild.getLevel() + 1), + "§7Exp until next level: §6" + nf.format(expRemaining) + " §7(§6" + progressPercent + "%§7)", + "", + "§7Today's exp: §6" + nf.format(0), + "§7The guild is earning exp at §6100%§7 rate!", + "", + "§6Today's exp < 200,000 → 100%", + "§7Today's exp >= 200,000 → 10%", + "§7Today's exp >= 250,000 → 3%", + "", + "§eClick to view leveling rewards!" + ), (click, viewCtx) -> viewCtx.push(new GUIGuildLevelingRewards(), GUIGuildLevelingRewards.createState(guild))); + + layout.slot(23, ItemStackCreator.getStack( + "§aGuild Achievements", + Material.DIAMOND, + 1, + "§7Achievements completed: §e" + countCompletedAchievements(guild) + "§7/26", + "", + "§eClick to view!" + ), (click, viewCtx) -> viewCtx.push(new GUIGuildAchievements(), new GUIGuildAchievements.GuildAchievementsState(guild))); + + layout.slot(24, ItemStackCreator.getStackHead( + "§aGuild Discord", + "7873c12bffb5251a0b88d5ae75c7247cb39a75ff1a81cbe4c8a39b311ddeda", + 1, + "§7Your Guild has a Discord", + "§7server that Guild Members can", + "§7join.", + "", + "§eClick to view Invite Link", + "§eRight-click to modify" + ), (click, viewCtx) -> { + if (click.click() instanceof Click.Right) { + new HypixelSignGUI(viewCtx.player()) + .open(new String[]{"Discord Link", "Paste invite URL"}) + .thenAccept(link -> { + if (link == null || link.isBlank()) { + return; + } + GuildManager.changeSetting(viewCtx.player(), "discord", link.trim()); + }); + return; + } + + String discordLink = guild.getDiscordLink(); + if (discordLink == null || discordLink.isBlank()) { + viewCtx.player().sendMessage("§cYour guild does not have a Discord link set."); + return; + } + + viewCtx.player().sendMessage(Component.text("§eClick here to open your guild Discord invite") + .clickEvent(ClickEvent.openUrl(discordLink))); + }); + + layout.slot(25, ItemStackCreator.getStack( + "§aGuild Finder", + Material.PAPER, + 1, + "§7Find a Guild you can join based on", + "§7your favorite games.", + "", + "§eClick to browse!" + )); + + layout.slot(33, ItemStackCreator.getStack( + "§aChange sort", + Material.HOPPER, + 1, + "§7Current sort: §bLast Online", + "§7Sorting order: §bNormal", + "", + "§bLast Online§7: Sorts by who was", + "§7most recently online", + "§bGuild Rank§7: Shows highest Guild", + "§7Rank first", + "§bVeterancy§7: How long they've", + "§7been in the guild", + "§bAlphabetical§7: Show everyone", + "§7listed from A-Z", + "§bAP§7: Sort by Achievement Points", + "§bLevel§7: Sort by Hypixel Level", + "", + "§eLEFT CLICK§7 to change between", + "§7all the available sorting options.", + "", + "§eRIGHT CLICK§7 to reverse the", + "§7current order!" + )); + + layout.slot(34, ItemStackCreator.getStack( + "§aSearch Players", + Material.OAK_SIGN, + 1 + ), (click, viewCtx) -> viewCtx.push(new GUIGuildMembers(), GUIGuildMembers.createState(guild))); + + layout.slot(35, ItemStackCreator.getStack( + "§aNext Page", + Material.ARROW, + 1, + "§eLEFT CLICK§7 to go to the next", + "§7page", + "§eRIGHT CLICK§7 to go to the last", + "§7page", + "§7Page 1/" + Math.max(1, (int) Math.ceil(guild.getMembers().size() / 18.0)) + ), (click, viewCtx) -> viewCtx.push(new GUIGuildMembers(), GUIGuildMembers.createState(guild))); + + int[] previewSlots = {36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53}; + List members = guild.getMembers(); + for (int i = 0; i < previewSlots.length && i < members.size(); i++) { + layout.slot(previewSlots[i], buildMemberPreview(members.get(i))); + } + } + + private boolean canCreateGuild(HypixelPlayer player) { + return player.getRank().isEqualOrHigherThan(Rank.VIP_PLUS); + } + + private ItemStack.Builder buildMemberPreview(GuildMember member) { + UUID uuid = member.getUuid(); + String displayName = HypixelPlayer.getDisplayName(uuid); + String memberSince = formatDuration(System.currentTimeMillis() - member.getJoinedAt()); + + HypixelPlayer loadedPlayer = HypixelGenericLoader.getLoadedPlayers().stream() + .filter(p -> p.getUuid().equals(uuid)) + .findFirst() + .orElse(null); + + String[] lore; + PlayerSkin skin; + + if (loadedPlayer != null) { + lore = new String[]{ + "§7Hypixel Level: §6" + loadedPlayer.getExperienceHandler().getLevel(), + "§7Achievement Points: §e" + StringUtility.commaify(loadedPlayer.getAchievementHandler().getTotalPoints()), + "§7Guild Rank: §b" + member.getRankName(), + "§7Member since: §b" + memberSince, + "", + "§7Online Status: §bOnline" + }; + skin = loadedPlayer.getSkin(); + } else { + lore = new String[]{ + "§7Hypixel Level: §6?", + "§7Achievement Points: §e?", + "§7Guild Rank: §b" + member.getRankName(), + "§7Member since: §b" + memberSince, + "", + "§7Last Online: §bUnknown" + }; + skin = resolveOfflineSkin(uuid); + } + + if (skin != null) { + return ItemStackCreator.getStackHead(displayName, skin, 1, lore); + } + return ItemStackCreator.getStack(displayName, Material.PLAYER_HEAD, 1, lore); + } + + private PlayerSkin resolveOfflineSkin(UUID uuid) { + try { + HypixelDataHandler dataHandler = HypixelDataHandler.getOfOfflinePlayer(uuid); + String texture = dataHandler.get(HypixelDataHandler.Data.SKIN_TEXTURE, DatapointString.class).getValue(); + String signature = dataHandler.get(HypixelDataHandler.Data.SKIN_SIGNATURE, DatapointString.class).getValue(); + if (texture == null || signature == null || texture.equals("null") || signature.equals("null")) { + return null; + } + return new PlayerSkin(texture, signature); + } catch (Exception ignored) { + return null; + } + } + + private long getExpIntoCurrentLevel(GuildData guild) { + long accumulated = 0; + for (int level = 1; level <= guild.getLevel(); level++) { + accumulated += guild.getGexpForLevel(level); + } + return Math.max(0, guild.getTotalGexp() - accumulated); + } + + private int countCompletedAchievements(GuildData guild) { + int completed = 0; + int level = guild.getLevel(); + long gexp = guild.getTotalGexp(); + int memberCount = guild.getMembers().size(); + + int[] prestigeTiers = {20, 40, 60, 80, 100}; + int[] expKingTiers = {50000, 100000, 150000, 200000, 250000, 275000, 300000}; + int[] familyTiers = {5, 15, 30, 40, 50, 60, 70}; + + for (int tier : prestigeTiers) { + if (level >= tier) completed++; + } + for (int tier : expKingTiers) { + if (gexp >= tier) completed++; + } + for (int tier : familyTiers) { + if (memberCount >= tier) completed++; + } + + return completed; + } + + private String createProgressBar(double progress, int length) { + int filled = (int) Math.round(progress * length); + StringBuilder bar = new StringBuilder(); + for (int i = 0; i < length; i++) { + bar.append(i < filled ? "|" : "§7|"); + } + return bar.toString(); + } + + private String formatDuration(long millis) { + long days = TimeUnit.MILLISECONDS.toDays(millis); + long hours = TimeUnit.MILLISECONDS.toHours(millis) % 24; + if (days > 0) return days + " days, " + hours + " hours ago"; + if (hours > 0) return hours + " hours ago"; + return "Just now"; + } + + public record GuildState(@Nullable GuildData guild) { + } +} diff --git a/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIGuildAchievements.java b/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIGuildAchievements.java new file mode 100644 index 000000000..12ad0c218 --- /dev/null +++ b/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIGuildAchievements.java @@ -0,0 +1,91 @@ +package net.swofty.type.lobby.gui; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.commons.guild.GuildData; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.View; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; + +import java.text.NumberFormat; + +public class GUIGuildAchievements implements View { + + private static final int[][] PRESTIGE_TIERS = {{20}, {40}, {60}, {80}, {100}}; + private static final int[] PRESTIGE_SLOTS = {0, 1, 2, 3, 4}; + + private static final int[][] EXP_KING_TIERS = {{50000}, {100000}, {150000}, {200000}, {250000}, {275000}, {300000}}; + private static final int[] EXP_KING_SLOTS = {9, 10, 11, 12, 13, 14, 15}; + + private static final int[][] FAMILY_TIERS = {{5}, {15}, {30}, {40}, {50}, {60}, {70}}; + private static final int[] FAMILY_SLOTS = {27, 28, 29, 30, 31, 32, 33}; + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Guild Achievements", InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, GuildAchievementsState state, ViewContext ctx) { + GuildData guild = state.guild(); + int level = guild.getLevel(); + NumberFormat nf = NumberFormat.getInstance(); + + for (int i = 0; i < PRESTIGE_TIERS.length; i++) { + int required = PRESTIGE_TIERS[i][0]; + boolean achieved = level >= required; + String name = (achieved ? "§a" : "§7") + "Prestige " + toRoman(i + 1); + Material mat = achieved ? Material.EXPERIENCE_BOTTLE : Material.GRAY_DYE; + String progress = "§7Progress: §e" + level + "§7/" + required + (achieved ? " §aACHIEVED" : ""); + layout.slot(PRESTIGE_SLOTS[i], ItemStackCreator.getStack(name, mat, 1, + "§7Reach Guild level " + required, "", progress)); + } + + long gexp = guild.getTotalGexp(); + for (int i = 0; i < EXP_KING_TIERS.length; i++) { + int required = EXP_KING_TIERS[i][0]; + boolean achieved = gexp >= required; + String name = (achieved ? "§a" : "§7") + "Experience Kings " + toRoman(i + 1); + Material mat = achieved ? Material.CLOCK : Material.GRAY_DYE; + String progress = "§7Progress: §e" + nf.format(gexp) + "§7/" + nf.format(required) + (achieved ? " §aACHIEVED" : ""); + layout.slot(EXP_KING_SLOTS[i], ItemStackCreator.getStack(name, mat, 1, + "§7Get " + nf.format(required) + " Guild Exp in one day", "", progress)); + } + + int memberCount = guild.getMembers().size(); + for (int i = 0; i < FAMILY_TIERS.length; i++) { + int required = FAMILY_TIERS[i][0]; + boolean achieved = memberCount >= required; + String name = (achieved ? "§a" : "§7") + "Family " + toRoman(i + 1); + Material mat = achieved ? Material.DIAMOND : Material.GRAY_DYE; + String progress = "§7Progress: §e" + memberCount + "§7/" + required + (achieved ? " §aACHIEVED" : ""); + layout.slot(FAMILY_SLOTS[i], ItemStackCreator.getStack(name, mat, 1, + "§7Have " + required + " guild members online", "§7at the same time!", "", progress)); + } + + layout.slot(49, ItemStackCreator.getStack( + "§aGo Back", + Material.ARROW, + 1, + "§7To Guild" + ), (click, viewCtx) -> viewCtx.navigator().pop()); + } + + private static String toRoman(int num) { + return switch (num) { + case 1 -> "I"; + case 2 -> "II"; + case 3 -> "III"; + case 4 -> "IV"; + case 5 -> "V"; + case 6 -> "VI"; + case 7 -> "VII"; + default -> String.valueOf(num); + }; + } + + public record GuildAchievementsState(GuildData guild) { + } +} diff --git a/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIGuildLevelingRewards.java b/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIGuildLevelingRewards.java new file mode 100644 index 000000000..92692f472 --- /dev/null +++ b/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIGuildLevelingRewards.java @@ -0,0 +1,156 @@ +package net.swofty.type.lobby.gui; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.swofty.commons.guild.GuildData; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.PaginatedView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.generic.user.HypixelPlayer; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.IntStream; + +public class GUIGuildLevelingRewards extends PaginatedView { + + private static final int[] REWARD_SLOTS = IntStream.range(0, 45).toArray(); + + private static final List TEMPLATES = buildTemplates(); + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Guild Leveling Rewards", InventoryType.CHEST_6_ROW); + } + + @Override + protected int[] getPaginatedSlots() { + return REWARD_SLOTS; + } + + @Override + protected int getNextPageSlot() { + return 53; + } + + @Override + protected int getPreviousPageSlot() { + return 45; + } + + @Override + protected void layoutCustom(ViewLayout layout, LevelRewardsState state, ViewContext ctx) { + layout.slot(49, ItemStackCreator.getStack( + "§aGo Back", + Material.ARROW, + 1, + "§7To Guild" + ), (click, viewCtx) -> viewCtx.navigator().pop()); + } + + @Override + protected ItemStack.Builder renderItem(LevelReward reward, int index, HypixelPlayer player) { + Material mat = reward.unlocked() ? reward.material() : (reward.special() ? Material.CLAY_BALL : Material.GRAY_DYE); + String nameColor = reward.unlocked() ? reward.nameColor() : "§7"; + String unlockText = reward.unlocked() + ? "§eUnlocked at level " + reward.level() + : "§eUnlocks at Level " + reward.level(); + + List lore = new ArrayList<>(List.of(reward.description())); + lore.add(""); + lore.add(unlockText); + + return ItemStackCreator.getStack(nameColor + reward.name(), mat, 1, lore.toArray(String[]::new)); + } + + @Override + protected void onItemClick(ClickContext click, ViewContext ctx, LevelReward item, int index) { + } + + @Override + protected boolean shouldFilterFromSearch(LevelRewardsState state, LevelReward item) { + return false; + } + + public static LevelRewardsState createState(GuildData guild) { + int guildLevel = guild.getLevel(); + List rewards = TEMPLATES.stream() + .map(t -> new LevelReward(t.level, t.name, t.nameColor, t.material, t.description, t.special, guildLevel >= t.level)) + .toList(); + return new LevelRewardsState(rewards, 0, guild); + } + + private static List buildTemplates() { + List list = new ArrayList<>(); + int expPercent = 0; + int coinPercent = 0; + + for (int level = 1; level <= 50; level++) { + if (level % 3 == 0) { + coinPercent++; + list.add(new RewardTemplate(level, coinPercent + "% Double Coins", "§6", Material.GOLD_NUGGET, + new String[]{"§7Whenever a Guild Member plays", "§7a game, they have a §6" + coinPercent + "% §7chance", + "§7of getting Double Coins every", "§7time they gain coins."}, false)); + } else { + expPercent++; + list.add(new RewardTemplate(level, expPercent + "% Double Exp", "§3", Material.CYAN_DYE, + new String[]{"§7Whenever a Guild Member plays", "§7a game, they have a §6" + expPercent + "% §7chance", + "§7of getting Double Exp for the", "§7entire game."}, false)); + } + + switch (level) { + case 5 -> list.add(new RewardTemplate(5, "Gray Guild Tag", "§7", Material.LIGHT_GRAY_WOOL, + new String[]{"§7Guild Members can have a Gray", "§7Guild Tag displayed next to", "§7their username in lobbies."}, true)); + case 10 -> list.add(new RewardTemplate(10, "Crits and Magic Particle Packs", "§6", Material.NETHER_STAR, + new String[]{"§7Guild Members have the ability", "§7to use the Crits and Magic", "§7Particle Packs in lobbies."}, true)); + case 15 -> { + list.add(new RewardTemplate(15, "Dark Aqua Guild Tag", "§3", Material.CYAN_WOOL, + new String[]{"§7Guild Members can have a §3Dark", "§3Aqua§7 Guild Tag displayed next", "§7to their username in lobbies."}, true)); + list.add(new RewardTemplate(15, "Tier 1 Forum Icon", "§6", Material.BOOK, + new String[]{"§7All Guild Members receive the", "§7Tier 1 Forum Icon on the", "§7Hypixel Forums."}, true)); + } + case 20 -> list.add(new RewardTemplate(20, "Tier 1 Guild Cloak", "§6", Material.ENCHANTING_TABLE, + new String[]{"§7Guild Members have the ability", "§7to use the Tier 1 Guild Cloak in", "§7lobbies."}, true)); + case 25 -> list.add(new RewardTemplate(25, "Dark Green Guild Tag", "§2", Material.GREEN_WOOL, + new String[]{"§7Guild Members can have a §2Dark", "§2Green§7 Guild Tag displayed next", "§7to their username in lobbies."}, true)); + case 30 -> list.add(new RewardTemplate(30, "Flame and Snow Particle Packs", "§6", Material.NETHER_STAR, + new String[]{"§7Guild Members have the ability", "§7to use the Flame and Snow", "§7Particle Packs in lobbies."}, true)); + case 35 -> list.add(new RewardTemplate(35, "Tier 2 Forum Icon", "§6", Material.BOOK, + new String[]{"§7All Guild Members receive the", "§7Tier 2 Forum Icon on the", "§7Hypixel Forums."}, true)); + case 40 -> list.add(new RewardTemplate(40, "Tier 2 Guild Cloak", "§6", Material.ENCHANTING_TABLE, + new String[]{"§7Guild Members have the ability", "§7to use the Tier 2 Guild Cloak in", "§7lobbies."}, true)); + case 45 -> list.add(new RewardTemplate(45, "Yellow Guild Tag", "§e", Material.YELLOW_WOOL, + new String[]{"§7Guild Members can have a §eYellow", "§7Guild Tag displayed next", "§7to their username in lobbies."}, true)); + case 50 -> list.add(new RewardTemplate(50, "Tier 3 Forum Icon", "§6", Material.BOOK, + new String[]{"§7All Guild Members receive the", "§7Tier 3 Forum Icon on the", "§7Hypixel Forums."}, true)); + } + } + return Collections.unmodifiableList(list); + } + + private record RewardTemplate(int level, String name, String nameColor, Material material, String[] description, + boolean special) { + } + + public record LevelReward(int level, String name, String nameColor, Material material, String[] description, + boolean special, boolean unlocked) { + } + + public record LevelRewardsState(List items, int page, + GuildData guild) implements PaginatedState { + @Override + public PaginatedState withPage(int page) { + return new LevelRewardsState(items, page, guild); + } + + @Override + public PaginatedState withItems(List items) { + return new LevelRewardsState(items, page, guild); + } + } +} \ No newline at end of file diff --git a/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIGuildMembers.java b/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIGuildMembers.java new file mode 100644 index 000000000..ff60a2eb9 --- /dev/null +++ b/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIGuildMembers.java @@ -0,0 +1,107 @@ +package net.swofty.type.lobby.gui; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import net.swofty.commons.guild.GuildData; +import net.swofty.commons.guild.GuildMember; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.PaginatedView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ClickContext; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.generic.user.HypixelPlayer; + +import java.text.NumberFormat; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class GUIGuildMembers extends PaginatedView { + + private static final int[] MEMBER_SLOTS = { + 10, 11, 12, 13, 14, 15, 16, + 19, 20, 21, 22, 23, 24, 25, + 28, 29, 30, 31, 32, 33, 34, + 37, 38, 39, 40, 41, 42, 43 + }; + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Guild Members", InventoryType.CHEST_6_ROW); + } + + @Override + protected int[] getPaginatedSlots() { + return MEMBER_SLOTS; + } + + @Override + protected int getNextPageSlot() { + return 44; + } + + @Override + protected int getPreviousPageSlot() { + return 36; + } + + @Override + protected void layoutCustom(ViewLayout layout, MembersState state, ViewContext ctx) { + layout.slot(49, ItemStackCreator.getStack( + "§aGo Back", + Material.ARROW, + 1, + "§7To Guild" + ), (click, viewCtx) -> viewCtx.navigator().pop()); + } + + @Override + protected ItemStack.Builder renderItem(GuildMember member, int index, HypixelPlayer player) { + String displayName = HypixelPlayer.getDisplayName(member.getUuid()); + NumberFormat nf = NumberFormat.getInstance(); + + return ItemStackCreator.getStack( + displayName, + Material.PLAYER_HEAD, + 1, + "§7Guild Rank: §b" + member.getRankName(), + "§7Member since: §b" + formatDuration(System.currentTimeMillis() - member.getJoinedAt()), + "§7Weekly GEXP: §6" + nf.format(member.getWeeklyGexp()), + "§7Total GEXP: §6" + nf.format(member.getTotalGexp()) + ); + } + + @Override + protected void onItemClick(ClickContext click, ViewContext ctx, GuildMember item, int index) { + } + + @Override + protected boolean shouldFilterFromSearch(MembersState state, GuildMember item) { + return false; + } + + public static MembersState createState(GuildData guild) { + return new MembersState(guild.getMembers(), 0); + } + + private static String formatDuration(long millis) { + long days = TimeUnit.MILLISECONDS.toDays(millis); + long hours = TimeUnit.MILLISECONDS.toHours(millis) % 24; + if (days > 0) return days + " days, " + hours + " hours ago"; + if (hours > 0) return hours + " hours ago"; + return "Just now"; + } + + public record MembersState(List items, int page) implements PaginatedState { + @Override + public PaginatedState withPage(int page) { + return new MembersState(items, page); + } + + @Override + public PaginatedState withItems(List items) { + return new MembersState(items, page); + } + } +} diff --git a/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIGuildSettings.java b/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIGuildSettings.java new file mode 100644 index 000000000..bf15a9774 --- /dev/null +++ b/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIGuildSettings.java @@ -0,0 +1,133 @@ +package net.swofty.type.lobby.gui; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.commons.guild.GuildData; +import net.swofty.type.generic.gui.HypixelSignGUI; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.View; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; +import net.swofty.type.generic.guild.GuildManager; + +import java.util.List; + +public class GUIGuildSettings implements View { + + @Override + public ViewConfiguration configuration() { + return new ViewConfiguration<>("Guild Settings", InventoryType.CHEST_4_ROW); + } + + @Override + public void layout(ViewLayout layout, GuildSettingsState state, ViewContext ctx) { + GuildData guild = state.guild(); + + String currentTag = guild.getTag() != null ? guild.getTag() : "None"; + layout.slot(10, ItemStackCreator.getStack( + "§aGuild Tag", + Material.NAME_TAG, + 1, + "§7Current: §6" + currentTag, + "§7Changes the tag next to your guild", + "§7members' names.", + "", + "§eClick to edit!" + ), (click, viewCtx) -> new HypixelSignGUI(viewCtx.player()) + .open(new String[]{"Guild Tag", "Enter new tag"}) + .thenAccept(value -> { + if (value == null || value.isBlank()) { + return; + } + GuildManager.changeSetting(viewCtx.player(), "tag", value.trim()); + })); + + String tagColor = guild.getTagColor() != null ? guild.getTagColor() : "§7"; + List colors = List.of("§7", "§f", "§a", "§b", "§3", "§6", "§d", "§c", "§e"); + int colorIndex = Math.max(0, colors.indexOf(tagColor)); + String nextColor = colors.get((colorIndex + 1) % colors.size()); + layout.slot(11, ItemStackCreator.getStack( + "§aGuild Tag Color", + Material.RED_DYE, + 1, + "§7Current: " + tagColor + "Sample", + "§7Changes the color of the tag next to", + "§7your guild members' names.", + "", + "§eClick to cycle colors!" + ), (click, viewCtx) -> GuildManager.changeSetting(viewCtx.player(), "tagcolor", nextColor)); + + layout.slot(12, ItemStackCreator.getStack( + "§aGuild Permissions", + Material.COMPARATOR, + 1, + "§7Modify your guild's ranks & their", + "§7permissions.", + "", + "§eClick to edit!" + ), (click, viewCtx) -> viewCtx.player().sendMessage("§cGuild rank permission editor is not available yet.")); + + String finderStatus = guild.isListedInFinder() ? "§aON" : "§cOFF"; + layout.slot(13, ItemStackCreator.getStack( + "§aShown in Guild Finder", + Material.SUNFLOWER, + 1, + "§7Whether or not players can find the", + "§7guild in Guild Finder and request to", + "§7join.", + "§7Currently " + finderStatus, + "", + "§eClick to toggle!" + ), (click, viewCtx) -> GuildManager.changeSetting(viewCtx.player(), "finder", "toggle")); + + layout.slot(14, ItemStackCreator.getStack( + "§aGuild Games", + Material.COMPASS, + 1, + "§7Changes the Guild's list of games", + "§7used in the Guild Finder.", + "", + "§eClick to pick games!" + ), (click, viewCtx) -> viewCtx.player().sendMessage("§cGuild games selector is not available yet.")); + + String description = guild.getDescription() != null && !guild.getDescription().isEmpty() + ? guild.getDescription() : "Not set"; + layout.slot(15, ItemStackCreator.getStack( + "§aGuild Description", + Material.WRITABLE_BOOK, + 1, + "§7Current: §f" + description, + "§7Changes the Guild's description as", + "§7shown in the Guild Finder.", + "", + "§eClick to edit!" + ), (click, viewCtx) -> new HypixelSignGUI(viewCtx.player()) + .open(new String[]{"Description", "Enter description"}) + .thenAccept(value -> { + if (value == null || value.isBlank()) { + return; + } + GuildManager.changeSetting(viewCtx.player(), "description", value.trim()); + })); + + String slowStatus = guild.isSlowChat() ? "§aON" : "§cOFF"; + layout.slot(16, ItemStackCreator.getStack( + "§aPersonal Guild Settings", + Material.ORANGE_DYE, + 1, + "§7Slow Chat: " + slowStatus, + "", + "§eClick to toggle!" + ), (click, viewCtx) -> GuildManager.changeSetting(viewCtx.player(), "slow", "toggle")); + + layout.slot(31, ItemStackCreator.getStack( + "§aGo Back", + Material.ARROW, + 1 + ), (click, viewCtx) -> viewCtx.navigator().pop()); + } + + public record GuildSettingsState(GuildData guild) { + } +} diff --git a/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIMyProfile.java b/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIMyProfile.java index dd1689e41..afc8e10b3 100644 --- a/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIMyProfile.java +++ b/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIMyProfile.java @@ -10,12 +10,13 @@ import net.swofty.type.generic.gui.inventory.ItemStackCreator; import net.swofty.type.generic.gui.inventory.item.GUIClickableItem; import net.swofty.type.generic.gui.inventory.item.GUIItem; +import net.swofty.type.generic.guild.GuildManager; import net.swofty.type.generic.quest.QuestData; import net.swofty.type.generic.user.HypixelPlayer; public class GUIMyProfile extends HypixelInventoryGUI { private static int[] COLOURED_PANE_SLOTS = { - 9, 10, 11, 12, 13, 14, 15, 16, 17 + 9, 10, 11, 12, 13, 14, 15, 16, 17 }; public GUIMyProfile() { @@ -47,12 +48,12 @@ public ItemStack.Builder getItem(HypixelPlayer player) { public ItemStack.Builder getItem(HypixelPlayer player) { String displayName = player.getFullDisplayName(); return ItemStackCreator.getStackHead( - displayName, - player.getSkin(), - 1, - "§7Hypixel Level: §6" + level, - "§7Achievement Points: §e" + StringUtility.commaify(achievementPoints), - "§7Guild: §bNone" + displayName, + player.getSkin(), + 1, + "§7Hypixel Level: §6" + level, + "§7Achievement Points: §e" + StringUtility.commaify(achievementPoints), + "§7Guild: §bNone" ); } }); @@ -60,13 +61,13 @@ public ItemStack.Builder getItem(HypixelPlayer player) { @Override public ItemStack.Builder getItem(HypixelPlayer player) { return ItemStackCreator.getStackHead( - "§aFriends", - "e063eedb2184354bd43a19deffba51b53dd6b7222f8388caa239cabcdce84", - 1, - "§7View your Hypixel friends' profiles,", - "§7and interact with your online friends!", - "", - "§eClick to view!" + "§aFriends", + "e063eedb2184354bd43a19deffba51b53dd6b7222f8388caa239cabcdce84", + 1, + "§7View your Hypixel friends' profiles,", + "§7and interact with your online friends!", + "", + "§eClick to view!" ); } @@ -79,14 +80,14 @@ public void run(InventoryPreClickEvent e, HypixelPlayer player) { @Override public ItemStack.Builder getItem(HypixelPlayer player) { return ItemStackCreator.getStackHead( - "§aParty", - "667963ca1ffdc24a10b397ff8161d0da82d6a3f4788d5f67f1a9f9bfbc1eb1", - 1, - "§7Create a party and join up with", - "§7other players to play games", - "§7together!", - "", - "§eClick to manage!" + "§aParty", + "667963ca1ffdc24a10b397ff8161d0da82d6a3f4788d5f67f1a9f9bfbc1eb1", + 1, + "§7Create a party and join up with", + "§7other players to play games", + "§7together!", + "", + "§eClick to manage!" ); } @@ -95,17 +96,24 @@ public void run(InventoryPreClickEvent e, HypixelPlayer player) { new GUIParty().open(player); } }); - set(new GUIItem(5) { + set(new GUIClickableItem(5) { + @Override + public void run(InventoryPreClickEvent e, HypixelPlayer player) { + Thread.startVirtualThread(() -> { + player.openView(new GUIGuild(), new GUIGuild.GuildState(GuildManager.getGuildFromPlayer(player))); + }); + } + @Override public ItemStack.Builder getItem(HypixelPlayer player) { return ItemStackCreator.getStackHead( - "§aGuild", - "fe8b59f8cce510809427c3843cf575fae8fe6a8b7d1560dd46958d148563815", - 1, - "§7Form a guild with other Hypixel", - "§7players to conquer game modes and", - "§7work towards common Hypixel", - "§7rewards." + "§aGuild", + "fe8b59f8cce510809427c3843cf575fae8fe6a8b7d1560dd46958d148563815", + 1, + "§7Form a guild with other Hypixel", + "§7players to conquer game modes and", + "§7work towards common Hypixel", + "§7rewards." ); } }); @@ -113,11 +121,11 @@ public ItemStack.Builder getItem(HypixelPlayer player) { @Override public ItemStack.Builder getItem(HypixelPlayer player) { return ItemStackCreator.getStackHead( - "§aRecent Players", - "9993a356809532d696841a37a0549b81b159b79a7b2919cff4e5abdfea83d66", - 1, - "§7View players you have played recent", - "§7games with." + "§aRecent Players", + "9993a356809532d696841a37a0549b81b159b79a7b2919cff4e5abdfea83d66", + 1, + "§7View players you have played recent", + "§7games with." ); } }); @@ -125,9 +133,9 @@ public ItemStack.Builder getItem(HypixelPlayer player) { @Override public ItemStack.Builder getItem(HypixelPlayer player) { return ItemStackCreator.getStack( - "§aGo to Housing", - Material.DARK_OAK_DOOR, - 1 + "§aGo to Housing", + Material.DARK_OAK_DOOR, + 1 ); } }); @@ -135,10 +143,10 @@ public ItemStack.Builder getItem(HypixelPlayer player) { @Override public ItemStack.Builder getItem(HypixelPlayer player) { return ItemStackCreator.getStackHead( - "§aSocial Media", - "3685a0be743e9067de95cd8c6d1ba21ab21d37371b3d597211bb75e43279", - 1, - "§7Click to edit your Social Media links." + "§aSocial Media", + "3685a0be743e9067de95cd8c6d1ba21ab21d37371b3d597211bb75e43279", + 1, + "§7Click to edit your Social Media links." ); } }); @@ -146,19 +154,19 @@ public ItemStack.Builder getItem(HypixelPlayer player) { @Override public ItemStack.Builder getItem(HypixelPlayer player) { return ItemStackCreator.getStackHead( - "§aCharacter Information", - player.getSkin(), - 1, - "§7Rank: " + player.getRank().getPrefix().trim(), - "§7Level: §6" + level, - "§7Experience until next Level: §6" + StringUtility.commaify(xpNeeded), - "§7Achievement Points: §e" + StringUtility.commaify(achievementPoints), - "§7Mystery Dust: §b0", - "§7Quests Completed: §60", - "§7Karma: §d0", - "§7Hypixel Gold: §60", - "", - "§eClick to see the Hypixel Store link." + "§aCharacter Information", + player.getSkin(), + 1, + "§7Rank: " + player.getRank().getPrefix().trim(), + "§7Level: §6" + level, + "§7Experience until next Level: §6" + StringUtility.commaify(xpNeeded), + "§7Achievement Points: §e" + StringUtility.commaify(achievementPoints), + "§7Mystery Dust: §b0", + "§7Quests Completed: §60", + "§7Karma: §d0", + "§7Hypixel Gold: §60", + "", + "§eClick to see the Hypixel Store link." ); } }); @@ -166,17 +174,17 @@ public ItemStack.Builder getItem(HypixelPlayer player) { @Override public ItemStack.Builder getItem(HypixelPlayer player) { return ItemStackCreator.getStack( - "§aStats Viewer", - Material.PAPER, - 1, - "§7Showcases your stats for each", - "§7game and an overview of all.", - "", - "§7Players ranked §bMVP §7or higher", - "§7can use §f/stats (username) §7to view", - "§7other players' stats.", - "", - "§eClick to view your stats!" + "§aStats Viewer", + Material.PAPER, + 1, + "§7Showcases your stats for each", + "§7game and an overview of all.", + "", + "§7Players ranked §bMVP §7or higher", + "§7can use §f/stats (username) §7to view", + "§7other players' stats.", + "", + "§eClick to view your stats!" ); } }); @@ -184,14 +192,14 @@ public ItemStack.Builder getItem(HypixelPlayer player) { @Override public ItemStack.Builder getItem(HypixelPlayer player) { return ItemStackCreator.getStack( - "§aCoin Boosters", - Material.POTION, - 1, - "§7Activate your personal and", - "§7network boosters for extra", - "§7coins.", - "", - "§eClick to activate boosters!" + "§aCoin Boosters", + Material.POTION, + 1, + "§7Activate your personal and", + "§7network boosters for extra", + "§7coins.", + "", + "§eClick to activate boosters!" ); } }); @@ -199,18 +207,18 @@ public ItemStack.Builder getItem(HypixelPlayer player) { @Override public ItemStack.Builder getItem(HypixelPlayer player) { return ItemStackCreator.getStack( - "§aCustomize Appearances", - Material.LEATHER_CHESTPLATE, - 1, - "", - "§7Customize the following visual options", - "§7for your player!", - "§f∙ MVP+ Rank Color", - "§f∙ Punch Messages", - "§f∙ Glow", - "§f∙ Status", - "", - "§eClick to view!" + "§aCustomize Appearances", + Material.LEATHER_CHESTPLATE, + 1, + "", + "§7Customize the following visual options", + "§7for your player!", + "§f∙ MVP+ Rank Color", + "§f∙ Punch Messages", + "§f∙ Glow", + "§f∙ Status", + "", + "§eClick to view!" ); } }); @@ -219,15 +227,15 @@ public ItemStack.Builder getItem(HypixelPlayer player) { @Override public ItemStack.Builder getItem(HypixelPlayer player) { return ItemStackCreator.getStack( - "§aAchievements", - Material.DIAMOND, - 1, - "§7Track your progress as you unlock", - "§7Achievements and rack up points.", - "", - "§7Total Points: §e" + StringUtility.commaify(achievementPoints), - "", - "§eClick to view your achievements!" + "§aAchievements", + Material.DIAMOND, + 1, + "§7Track your progress as you unlock", + "§7Achievements and rack up points.", + "", + "§7Total Points: §e" + StringUtility.commaify(achievementPoints), + "", + "§eClick to view your achievements!" ); } @@ -244,20 +252,20 @@ public ItemStack.Builder getItem(HypixelPlayer player) { int progressPercent = (int) (progress * 100); return ItemStackCreator.getStack( - "§aHypixel Leveling", - Material.BREWING_STAND, - 1, - "§7Playing games and completing quests", - "§7will reward you with §3Hypixel", - "§3Experience§7, which is required to", - "§7level up and acquire new perks and", - "§7rewards!", - "", - "§3Hypixel Level §a" + level + " §3" + progressBar + " §3" + progressPercent + "%", - "", - "§7Experience until next level: §3" + StringUtility.commaify(xpNeeded), - "", - "§eClick to see your rewards!" + "§aHypixel Leveling", + Material.BREWING_STAND, + 1, + "§7Playing games and completing quests", + "§7will reward you with §3Hypixel", + "§3Experience§7, which is required to", + "§7level up and acquire new perks and", + "§7rewards!", + "", + "§3Hypixel Level §a" + level + " §3" + progressBar + " §3" + progressPercent + "%", + "", + "§7Experience until next level: §3" + StringUtility.commaify(xpNeeded), + "", + "§eClick to see your rewards!" ); } @@ -273,19 +281,19 @@ public ItemStack.Builder getItem(HypixelPlayer player) { int challengesCompleted = 15 - questData.getRemainingChallenges(); return ItemStackCreator.getStack( - "§aQuests & Challenges", - Material.ENCHANTED_BOOK, - 1, - "§7Completing quests and challenges", - "§7will reward you with §6Coins§7, §3Hypixel", - "§3Experience§7 and more!", - "", - "§7You can complete a maximum of §a15 ", - "§7challenges every day.", - "", - "§7Challenges completed today: §a" + challengesCompleted, - "", - "§eClick to view Quests & Challenges." + "§aQuests & Challenges", + Material.ENCHANTED_BOOK, + 1, + "§7Completing quests and challenges", + "§7will reward you with §6Coins§7, §3Hypixel", + "§3Experience§7 and more!", + "", + "§7You can complete a maximum of §a15 ", + "§7challenges every day.", + "", + "§7Challenges completed today: §a" + challengesCompleted, + "", + "§eClick to view Quests & Challenges." ); } @@ -299,13 +307,13 @@ public void run(InventoryPreClickEvent e, HypixelPlayer player) { @Override public ItemStack.Builder getItem(HypixelPlayer player) { return ItemStackCreator.getStack( - "§aSettings & Visibility", - Material.COMPARATOR, - 1, - "§7Allows you to edit and control", - "§7various personal settings.", - "", - "§eClick to edit your settings!" + "§aSettings & Visibility", + Material.COMPARATOR, + 1, + "§7Allows you to edit and control", + "§7various personal settings.", + "", + "§eClick to edit your settings!" ); } }); @@ -313,12 +321,12 @@ public ItemStack.Builder getItem(HypixelPlayer player) { @Override public ItemStack.Builder getItem(HypixelPlayer player) { return ItemStackCreator.getStack( - "§aRecent Games", - Material.BOOK, - 1, - "§7View your recently played games.", - "", - "§eClick to view!" + "§aRecent Games", + Material.BOOK, + 1, + "§7View your recently played games.", + "", + "§eClick to view!" ); } }); @@ -326,13 +334,13 @@ public ItemStack.Builder getItem(HypixelPlayer player) { @Override public ItemStack.Builder getItem(HypixelPlayer player) { return ItemStackCreator.getStack( - "§aAccount Status", - Material.ANVIL, - 1, - "§7Check your punishment history and", - "§7see where you stand.", - "", - "§eClick to view!" + "§aAccount Status", + Material.ANVIL, + 1, + "§7Check your punishment history and", + "§7see where you stand.", + "", + "§eClick to view!" ); } }); @@ -340,17 +348,17 @@ public ItemStack.Builder getItem(HypixelPlayer player) { @Override public ItemStack.Builder getItem(HypixelPlayer player) { return ItemStackCreator.getStackHead( - "§aSelect Language", - "98daa1e3ed94ff3e33e1d4c6e43f024c47d78a57ba4d38e75e7c9264106", - 1, - "§7Change your language.", - "", - "§7Currently available:", - "§7 ∙ §fEnglish", - "", - "§7More languages coming soon!", - "", - "§eClick to change your language!" + "§aSelect Language", + "98daa1e3ed94ff3e33e1d4c6e43f024c47d78a57ba4d38e75e7c9264106", + 1, + "§7Change your language.", + "", + "§7Currently available:", + "§7 ∙ §fEnglish", + "", + "§7More languages coming soon!", + "", + "§eClick to change your language!" ); } }); @@ -358,15 +366,15 @@ public ItemStack.Builder getItem(HypixelPlayer player) { @Override public ItemStack.Builder getItem(HypixelPlayer player) { return ItemStackCreator.getStack( - "§aHypixel Store", - Material.GOLD_INGOT, - 1, - "§7View the Hypixel Store from right", - "§7here in-game!", - "", - "§7Your Hypixel Gold: §60", - "", - "§eClick to view!" + "§aHypixel Store", + Material.GOLD_INGOT, + 1, + "§7View the Hypixel Store from right", + "§7here in-game!", + "", + "§7Your Hypixel Gold: §60", + "", + "§eClick to view!" ); } }); @@ -374,17 +382,17 @@ public ItemStack.Builder getItem(HypixelPlayer player) { @Override public ItemStack.Builder getItem(HypixelPlayer player) { return ItemStackCreator.getStack( - "§aEvent Shop", - Material.EMERALD, - 1, - "§7Level up during events by playing", - "§7games and completing quests.", - "", - "§7Earn §fEvent Silver §7when you gain an", - "§7Event Level. §fSilver §7can be used to", - "§7purchase event-themed cosmetics!", - "", - "§eClick to view shop!" + "§aEvent Shop", + Material.EMERALD, + 1, + "§7Level up during events by playing", + "§7games and completing quests.", + "", + "§7Earn §fEvent Silver §7when you gain an", + "§7Event Level. §fSilver §7can be used to", + "§7purchase event-themed cosmetics!", + "", + "§eClick to view shop!" ); } }); diff --git a/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIViewPlayer.java b/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIViewPlayer.java new file mode 100644 index 000000000..fd50ae420 --- /dev/null +++ b/type.lobby/src/main/java/net/swofty/type/lobby/gui/GUIViewPlayer.java @@ -0,0 +1,100 @@ +package net.swofty.type.lobby.gui; + +import net.minestom.server.inventory.InventoryType; +import net.minestom.server.item.Material; +import net.swofty.type.generic.gui.inventory.ItemStackCreator; +import net.swofty.type.generic.gui.v2.DefaultState; +import net.swofty.type.generic.gui.v2.StatelessView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; +import net.swofty.type.generic.gui.v2.context.ViewContext; + +public class GUIViewPlayer extends StatelessView { + + @Override + public ViewConfiguration configuration() { + return ViewConfiguration.withString((_, ctx) -> ctx.player().getUsername(), InventoryType.CHEST_6_ROW); + } + + @Override + public void layout(ViewLayout layout, DefaultState state, ViewContext ctx) { + layout.slot(0, ItemStackCreator.getStackHead( + ctx.player().getFullDisplayName(), + ctx.player().getPlayerSkin(), + 1, + "§7Hypixel Level: §6177", + "§7Achievement Points: §e8,505", + "§7Guild: §bNONE" + )); + layout.slot(22, ItemStackCreator.getStackHead( + "§aSocial Media", + "3685a0be743e9067de95cd8c6d1ba21ab21d37371b3d597211bb75e43279", + 1, + "§7Click to view Player's Social Media", + "§7links." + )); + layout.slot(23, ItemStackCreator.getStack( + "§aReport " + ctx.player().getUsername(), + Material.PAPER, + 1 + )); + layout.slot(29, ItemStackCreator.getStackHead( + "§aGift a Rank", + "84e1c42f11383b9dc8e67f2846fa311b16320f2c2ec7e175538dbff1dd94bb7", + 1, + "§7Gift a rank to " + ctx.player().getFullDisplayName() + ".", + "", + "§eClick to gift!" + )); + layout.slot(30, ItemStackCreator.getStack( + "§aInvite to Party", + Material.DIAMOND, + 1, + "§7Click here to invite " + ctx.player().getUsername() + " to a party." + )); + layout.slot(31, ItemStackCreator.getStack( + "§aAdd Friend", + Material.WRITABLE_BOOK, + 1, + "§7Click here to send " + ctx.player().getUsername() + " a friend", + "§7request." + )); + layout.slot(32, ItemStackCreator.getStack( + "§aBlock Player", + Material.HOPPER, + 1, + "§7Click here to add " + ctx.player().getUsername() + " to your", + "§7block list." + )); + layout.slot(33, ItemStackCreator.getStack( + "§aSend Duel Request", + Material.IRON_SWORD, + 1 + )); + layout.slot(39, ItemStackCreator.getStack( + "§aInvite to guild", + Material.GRAY_STAINED_GLASS_PANE, + 1, + "§7You can't invite " + ctx.player().getUsername() + " to your guild", + "§7because they are already in a guild." + )); + layout.slot(40, ItemStackCreator.getStack( + "§aPromote Party Role", + Material.GRAY_STAINED_GLASS_PANE, + 1, + "§7You must be in a party to use this." + )); + layout.slot(41, ItemStackCreator.getStack( + "§aPromote to higher guild rank", + Material.GRAY_STAINED_GLASS_PANE, + 1, + "§7You can't use this because " + ctx.player().getUsername(), + "§7isn't in your guild." + )); + layout.slot(49, ItemStackCreator.getStack( + "§aClose", + Material.ARROW, + 1 + )); + } +} diff --git a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUICreative.java b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUICreative.java index d2d1ab5b2..a0b0d5008 100644 --- a/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUICreative.java +++ b/type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/gui/inventories/GUICreative.java @@ -10,7 +10,11 @@ import net.swofty.type.generic.gui.HypixelSignGUI; import net.swofty.type.generic.gui.inventory.ItemStackCreator; import net.swofty.type.generic.gui.inventory.TranslatableItemStackCreator; -import net.swofty.type.generic.gui.v2.*; +import net.swofty.type.generic.gui.v2.Components; +import net.swofty.type.generic.gui.v2.Layouts; +import net.swofty.type.generic.gui.v2.PaginatedView; +import net.swofty.type.generic.gui.v2.ViewConfiguration; +import net.swofty.type.generic.gui.v2.ViewLayout; import net.swofty.type.generic.gui.v2.context.ClickContext; import net.swofty.type.generic.gui.v2.context.ViewContext; import net.swofty.type.generic.i18n.I18n; @@ -73,8 +77,7 @@ protected int getPreviousPageSlot() { @Override protected void layoutBackground(ViewLayout layout, CreativeState state, ViewContext ctx) { - Components.fill(layout); - layout.filler(Layouts.border(0, 53), ItemStackCreator.createNamedItemStack(Material.BLACK_STAINED_GLASS_PANE, "")); + layout.filler(Layouts.border(0, 53), Components.FILLER); } @Override @@ -137,7 +140,7 @@ protected void onItemClick(ClickContext click, ViewContext ctx, S toGive.setAmount(1); player.addAndUpdateItem(toGive); player.playSound(Sound.sound(Key.key("block.note_block.pling"), Sound.Source.PLAYER, 1.0f, 2.0f)); - player.sendMessage(I18n.string("gui_misc.creative.given_single", l, Map.of("item_name", toGive.getDisplayName()))); + player.sendMessage(I18n.t("gui_misc.creative.given_single", l, Map.of("item_name", toGive.getDisplayName()))); } }