Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ public static void handleRequestsListRequest(FriendRequestsListEvent event) {
}

public static void handlePlayerJoin(UUID playerUuid, String playerName) {
PresenceStorage.upsert(new net.swofty.commons.presence.PresenceInfo(
PresenceStorage.upsertPreservingServer(new net.swofty.commons.presence.PresenceInfo(
playerUuid,
true,
null,
Expand All @@ -376,15 +376,23 @@ public static void handlePlayerJoin(UUID playerUuid, String playerName) {
FriendData playerData = getFriendData(playerUuid);

for (Friend friend : playerData.getFriends()) {
net.swofty.commons.presence.PresenceInfo friendPresence = PresenceStorage.get(friend.getUuid());
if (friendPresence == null || !friendPresence.isOnline()) continue;

FriendData friendData = cachedFriendData.get(friend.getUuid());
if (friendData == null) {
friendData = getFriendData(friend.getUuid());
cachedFriendData.put(friend.getUuid(), friendData);
}

if (friendData != null && friendData.getSettings().isJoinLeaveNotifications()) {
sendEvent(new FriendJoinNotificationEvent(friend.getUuid(), playerUuid, playerName));
}
}
}

public static void handlePlayerLeave(UUID playerUuid, String playerName) {
PresenceStorage.upsert(new net.swofty.commons.presence.PresenceInfo(
PresenceStorage.upsertPreservingServer(new net.swofty.commons.presence.PresenceInfo(
playerUuid,
false,
null,
Expand All @@ -396,7 +404,15 @@ public static void handlePlayerLeave(UUID playerUuid, String playerName) {
if (playerData == null) return;

for (Friend friend : playerData.getFriends()) {
net.swofty.commons.presence.PresenceInfo friendPresence = PresenceStorage.get(friend.getUuid());
if (friendPresence == null || !friendPresence.isOnline()) continue;

FriendData friendData = cachedFriendData.get(friend.getUuid());
if (friendData == null) {
friendData = getFriendData(friend.getUuid());
cachedFriendData.put(friend.getUuid(), friendData);
}

if (friendData != null && friendData.getSettings().isJoinLeaveNotifications()) {
sendEvent(new FriendLeaveNotificationEvent(friend.getUuid(), playerUuid, playerName));
}
Expand Down Expand Up @@ -464,6 +480,9 @@ private static String formatServerDisplay(net.swofty.commons.presence.PresenceIn
String type = info.getServerType();
String id = info.getServerId();
if (type == null && id == null) return null;
if (id != null && id.matches("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$")) {
return type; // hide raw UUIDs; show type only
}
if (type != null && id != null) return type + " - " + id;
return type != null ? type : id;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,38 @@ public static void upsert(PresenceInfo presence) {
presenceByUuid.put(presence.getUuid(), presence);
}

/**
* Upsert presence and return the previous entry (if any).
*/
public static PresenceInfo upsertAndGetPrevious(PresenceInfo presence) {
return presenceByUuid.put(presence.getUuid(), presence);
}

/**
* Upsert presence while preserving non-null server metadata from previous entries.
*/
public static PresenceInfo upsertPreservingServer(PresenceInfo incoming) {
PresenceInfo previous = presenceByUuid.get(incoming.getUuid());
if (previous == null) {
presenceByUuid.put(incoming.getUuid(), incoming);
return null;
}

String serverType = incoming.getServerType() != null ? incoming.getServerType() : previous.getServerType();
String serverId = incoming.getServerId() != null ? incoming.getServerId() : previous.getServerId();
long lastSeen = incoming.getLastSeen() > 0 ? incoming.getLastSeen() : previous.getLastSeen();

PresenceInfo merged = new PresenceInfo(
incoming.getUuid(),
incoming.isOnline(),
serverType,
serverId,
lastSeen
);
presenceByUuid.put(incoming.getUuid(), merged);
return previous;
}

public static List<PresenceInfo> getBulk(Collection<UUID> uuids) {
if (uuids == null || uuids.isEmpty()) return List.of();
return uuids.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,9 @@ public UpdatePresenceProtocolObject.UpdatePresenceResponse onMessage(
UpdatePresenceProtocolObject.UpdatePresenceMessage messageObject) {

PresenceInfo incoming = messageObject.presence();
PresenceInfo previous = PresenceStorage.get(incoming.getUuid());
PresenceInfo previous = PresenceStorage.upsertPreservingServer(incoming);

// Detect state change to trigger friend join/leave notifications
boolean stateChanged = previous == null || previous.isOnline() != incoming.isOnline();
PresenceStorage.upsert(incoming);

if (stateChanged) {
String playerName = FriendCache.getPlayerName(incoming.getUuid());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import net.swofty.type.bedwarsgame.game.Game;
import net.swofty.type.bedwarsgame.game.GameStatus;
import net.swofty.type.bedwarsgame.user.BedWarsPlayer;
import net.swofty.type.generic.chat.StaffChat;
import net.swofty.type.generic.data.datapoints.DatapointChatType;
import net.swofty.type.generic.data.datapoints.DatapointLeaderboardLong;
import net.swofty.type.generic.data.handlers.BedWarsDataHandler;
Expand Down Expand Up @@ -45,6 +46,16 @@ public void run(PlayerChatEvent event) {
String finalMessage = message;

DatapointChatType.Chats chatType = player.getChatType().currentChatType;
if (chatType == DatapointChatType.Chats.STAFF) {
if (!rank.isStaff()) {
player.sendMessage("§cUnknown chat type.");
player.getChatType().switchTo(DatapointChatType.Chats.ALL);
return;
}
StaffChat.sendMessage(player, finalMessage);
return;
}

if (chatType == DatapointChatType.Chats.PARTY) {
if (!PartyManager.isInParty(player)) {
player.sendMessage("§cYou are not in a party and were moved to the ALL channel.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import net.swofty.commons.bedwars.BedwarsLevelColor;
import net.swofty.commons.bedwars.BedwarsLevelUtil;
import net.swofty.type.generic.HypixelGenericLoader;
import net.swofty.type.generic.chat.StaffChat;
import net.swofty.type.generic.data.HypixelDataHandler;
import net.swofty.type.generic.data.datapoints.DatapointChatType;
import net.swofty.type.generic.data.datapoints.DatapointLeaderboardLong;
Expand Down Expand Up @@ -44,6 +45,16 @@ public void run(PlayerChatEvent event) {
String finalMessage = message;

DatapointChatType.Chats chatType = player.getChatType().currentChatType;
if (chatType == DatapointChatType.Chats.STAFF) {
if (!rank.isStaff()) {
player.sendMessage("§cUnknown chat type.");
player.getChatType().switchTo(DatapointChatType.Chats.ALL);
return;
}
StaffChat.sendMessage(player, finalMessage);
return;
}

if (chatType == DatapointChatType.Chats.PARTY) {
if (!PartyManager.isInParty(player)) {
player.sendMessage("§cYou are not in a party and were moved to the ALL channel.");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package net.swofty.type.generic.chat;

import net.swofty.type.generic.HypixelGenericLoader;
import net.swofty.type.generic.command.commands.ChatCommand;
import net.swofty.type.generic.user.HypixelPlayer;

import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

public final class StaffChat {
private StaffChat() {}

public static void sendMessage(HypixelPlayer sender, String message) {
String formatted = "§b[STAFF] " + sender.getRank().getPrefix() + sender.getUsername() + "§f: " + message;
broadcast(formatted, sender.getUuid());
}

public static void sendNotification(String message) {
String formatted = "§b[STAFF] §7" + message;
broadcast(formatted, null);
}

private static void broadcast(String message, UUID senderUuid) {
List<HypixelPlayer> viewers = HypixelGenericLoader.getLoadedPlayers().stream()
.filter(player -> player.getRank().isStaff())
.filter(player -> ChatCommand.isStaffViewEnabled(player.getUuid()) || (senderUuid != null && player.getUuid().equals(senderUuid)))
.collect(Collectors.toList());

for (HypixelPlayer viewer : viewers) {
viewer.sendMessage(message);
}
}
}

Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package net.swofty.type.generic.command.commands;

import net.minestom.server.command.builder.arguments.ArgumentEnum;
import net.minestom.server.command.builder.arguments.ArgumentType;
import net.minestom.server.command.builder.arguments.ArgumentWord;
import net.minestom.server.command.builder.suggestion.SuggestionEntry;
import net.swofty.type.generic.command.CommandParameters;
import net.swofty.type.generic.command.HypixelCommand;
import net.swofty.type.generic.data.datapoints.DatapointChatType;
Expand All @@ -14,15 +15,52 @@
aliases = "chatmode",
allowsConsole = false)
public class ChatCommand extends HypixelCommand {
private static final java.util.concurrent.ConcurrentHashMap<java.util.UUID, Boolean> staffView = new java.util.concurrent.ConcurrentHashMap<>();

@Override
public void registerUsage(MinestomCommand command) {
ArgumentEnum<PickerChatType> chatType = ArgumentType.Enum("type", PickerChatType.class);
ArgumentWord chatType = ArgumentType.Word("type");
chatType.setSuggestionCallback((sender, context, suggestion) -> {
boolean isStaff = sender instanceof HypixelPlayer hp && hp.getRank().isStaff();
suggestion.addEntry(new SuggestionEntry("p"));
suggestion.addEntry(new SuggestionEntry("party"));
suggestion.addEntry(new SuggestionEntry("a"));
suggestion.addEntry(new SuggestionEntry("all"));
if (isStaff) {
suggestion.addEntry(new SuggestionEntry("s"));
suggestion.addEntry(new SuggestionEntry("staff"));
suggestion.addEntry(new SuggestionEntry("staffview"));
suggestion.addEntry(new SuggestionEntry("sv"));
}
});

command.addSyntax((sender, context) -> {
if (!permissionCheck(sender)) return;

PickerChatType type = context.get(chatType);
HypixelPlayer player = (HypixelPlayer) sender;
String raw = context.get(chatType).toLowerCase();

if ((raw.equals("staffview") || raw.equals("sv"))) {
if (!player.getRank().isStaff()) {
sender.sendMessage("§cUnknown chat type.");
return;
}
boolean enabled = staffView.getOrDefault(player.getUuid(), true);
staffView.put(player.getUuid(), !enabled);
sender.sendMessage("§aStaff chat viewing is now " + (!enabled ? "§aenabled" : "§cdisabled"));
return;
}

PickerChatType type = PickerChatType.fromString(raw);
if (type == null) {
sender.sendMessage("§cUnknown chat type.");
return;
}

if (type.getChatType() == DatapointChatType.Chats.STAFF && !player.getRank().isStaff()) {
sender.sendMessage("§cUnknown chat type.");
return;
}

player.getChatType().switchTo(type.getChatType());
sender.sendMessage("§aYou are now in the §6" + type.chatType.name() + " §achannel");
Expand All @@ -33,7 +71,9 @@ enum PickerChatType {
p(DatapointChatType.Chats.PARTY),
party(DatapointChatType.Chats.PARTY),
a(DatapointChatType.Chats.ALL),
all(DatapointChatType.Chats.ALL);
all(DatapointChatType.Chats.ALL),
s(DatapointChatType.Chats.STAFF),
staff(DatapointChatType.Chats.STAFF);

private final DatapointChatType.Chats chatType;

Expand All @@ -44,5 +84,16 @@ enum PickerChatType {
public DatapointChatType.Chats getChatType() {
return chatType;
}

public static PickerChatType fromString(String input) {
for (PickerChatType val : values()) {
if (val.name().equalsIgnoreCase(input)) return val;
}
return null;
}
}

public static boolean isStaffViewEnabled(java.util.UUID uuid) {
return staffView.getOrDefault(uuid, true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package net.swofty.type.generic.command.commands;

import net.minestom.server.command.builder.arguments.ArgumentString;
import net.minestom.server.command.builder.arguments.ArgumentType;
import net.swofty.type.generic.command.CommandParameters;
import net.swofty.type.generic.command.HypixelCommand;
import net.swofty.type.generic.friend.FriendManager;
import net.swofty.type.generic.user.HypixelPlayer;
import net.swofty.type.generic.user.categories.Rank;

@CommandParameters(
aliases = "fl friendlist",
description = "List your friends",
usage = "/fl [page]",
permission = Rank.DEFAULT,
allowsConsole = false
)
public class FriendListCommand extends HypixelCommand {

@Override
public void registerUsage(MinestomCommand command) {
ArgumentString pageArg = ArgumentType.String("page");

// No args -> page 1
command.addSyntax((sender, context) -> {
if (!permissionCheck(sender)) return;
HypixelPlayer player = (HypixelPlayer) sender;
FriendManager.listFriends(player, 1, false);
});

// With page/best
command.addSyntax((sender, context) -> {
if (!permissionCheck(sender)) return;
HypixelPlayer player = (HypixelPlayer) sender;
String arg = context.get(pageArg);

if ("best".equalsIgnoreCase(arg)) {
FriendManager.listFriends(player, 1, true);
return;
}

int page = parsePageNumber(arg);
FriendManager.listFriends(player, page, false);
}, pageArg);
}

private int parsePageNumber(String arg) {
try {
return Math.max(1, Integer.parseInt(arg));
} catch (NumberFormatException e) {
return 1;
}
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public void switchTo(Chats chatType) {

public enum Chats {
ALL,
PARTY
PARTY,
STAFF
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package net.swofty.type.generic.event.actions;

import net.minestom.server.event.player.PlayerSpawnEvent;
import net.swofty.type.generic.chat.StaffChat;
import net.swofty.type.generic.event.EventNodes;
import net.swofty.type.generic.event.HypixelEvent;
import net.swofty.type.generic.event.HypixelEventClass;
import net.swofty.type.generic.user.HypixelPlayer;

public class ActionStaffJoinNotification implements HypixelEventClass {

@HypixelEvent(node = EventNodes.PLAYER, requireDataLoaded = true)
public void run(PlayerSpawnEvent event) {
if (!event.isFirstSpawn()) return;
HypixelPlayer player = (HypixelPlayer) event.getPlayer();
if (!player.getRank().isStaff()) return;

StaffChat.sendNotification(player.getFullDisplayName() + " §7joined.");
}
}


Loading