Skip to content

Commit

Permalink
Merge branch 'group-chats' into 1.21
Browse files Browse the repository at this point in the history
  • Loading branch information
BasiqueEvangelist committed Aug 6, 2024
2 parents 0aa2c22 + e1cf86b commit 1bd2f4d
Show file tree
Hide file tree
Showing 18 changed files with 466 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ public static void register() {
data.possibleNames().add(buf.readString());
}

if (buf.isReadable())
data.version(buf.readVarInt());

PingSpamClient.SERVER_DATA = data;

responseSender.sendPacket(PingSpamPackets.ANNOUNCE, PacketByteBufs.empty());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class ServerData {

private boolean canPingPlayers;
private final Set<String> possibleNames = CaseInsensitiveUtil.treeSetIgnoringCase();
private int version = 0;

public boolean canPingPlayers() {
return canPingPlayers;
Expand Down Expand Up @@ -47,6 +48,14 @@ public void setPermissions(boolean canPingEveryone, boolean canPingOnline, boole
}
}

public int version() {
return version;
}

public void version(int version) {
this.version = version;
}

public void refreshPermissionsIfNeeded() {
if ((System.nanoTime() - lastRequestTime) > MAX_TIME_SINCE_REQUEST) {
ClientPlayNetworking.send(PingSpamPackets.PULL_PERMISSIONS, PacketByteBufs.empty());
Expand Down
106 changes: 106 additions & 0 deletions src/main/java/me/basiqueevangelist/pingspam/commands/ChatCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package me.basiqueevangelist.pingspam.commands;

import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import me.basiqueevangelist.onedatastore.api.DataStore;
import me.basiqueevangelist.pingspam.PingSpam;
import me.basiqueevangelist.pingspam.utils.GroupChatLogic;
import net.minecraft.command.argument.MessageArgumentType;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;

import java.util.concurrent.CompletableFuture;

import static net.minecraft.server.command.CommandManager.argument;
import static net.minecraft.server.command.CommandManager.literal;

public final class ChatCommand {
private ChatCommand() {

}

public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
dispatcher.register(
literal("pingspam")
.then(literal("chat")
.executes(ChatCommand::clearChat)
.then(argument("group", StringArgumentType.string())
.suggests(ChatCommand::suggestChatGroups)
.executes(ChatCommand::switchChat)
.then(argument("message", MessageArgumentType.message())
.executes(ChatCommand::sendToChat))))
);
}

private static CompletableFuture<Suggestions> suggestChatGroups(CommandContext<ServerCommandSource> ctx, SuggestionsBuilder builder) throws CommandSyntaxException {
ServerCommandSource src = ctx.getSource();

for (var group : DataStore.getFor(src.getServer()).get(PingSpam.GLOBAL_DATA).groups().values()) {
if (!group.hasChat() || !group.members().contains(ctx.getSource().getPlayerOrThrow().getUuid()))
continue;

builder.suggest(SuggestionsUtils.wrapString(group.name()));
}

return builder.buildFuture();
}

private static int switchChat(CommandContext<ServerCommandSource> ctx) throws CommandSyntaxException {
ServerCommandSource src = ctx.getSource();
String groupName = StringArgumentType.getString(ctx, "group");
var group = DataStore.getFor(src.getServer()).get(PingSpam.GLOBAL_DATA).groups().get(groupName);

if (group == null)
throw GroupCommand.NO_SUCH_GROUP.create();

if (!group.hasChat() || !group.members().contains(ctx.getSource().getPlayerOrThrow().getUuid()))
throw GroupCommand.NO_SUCH_GROUP.create();

DataStore.getFor(src.getServer())
.getPlayer(src.getPlayerOrThrow().getUuid(), PingSpam.PLAYER_DATA)
.currentChat(groupName);

src.sendFeedback(() -> Text.literal("Switched to the ")
.formatted(Formatting.GREEN)
.append(Text.literal("@" + groupName)
.formatted(Formatting.YELLOW))
.append(" chat."), false);

return 1;
}

private static int clearChat(CommandContext<ServerCommandSource> ctx) throws CommandSyntaxException {
ServerCommandSource src = ctx.getSource();
DataStore.getFor(src.getServer())
.getPlayer(src.getPlayerOrThrow().getUuid(), PingSpam.PLAYER_DATA)
.currentChat(null);

src.sendFeedback(() -> Text.literal("Switched to the global chat."), false);
return 1;
}

private static int sendToChat(CommandContext<ServerCommandSource> ctx) throws CommandSyntaxException {
ServerCommandSource src = ctx.getSource();
String groupName = StringArgumentType.getString(ctx, "group");
var group = DataStore.getFor(src.getServer()).get(PingSpam.GLOBAL_DATA).groups().get(groupName);

if (group == null)
throw GroupCommand.NO_SUCH_GROUP.create();

ServerPlayerEntity player = ctx.getSource().getPlayerOrThrow();
if (!group.hasChat() || !group.members().contains(player.getUuid()))
throw GroupCommand.NO_SUCH_GROUP.create();

MessageArgumentType.getSignedMessage(ctx, "message", msg -> {
GroupChatLogic.sendIn(player, groupName, msg);
});

return 1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import com.mojang.authlib.GameProfile;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.BoolArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
Expand All @@ -23,7 +24,6 @@
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.regex.Pattern;
Expand All @@ -37,7 +37,7 @@ public class GroupCommand {
private static final DynamicCommandExceptionType NOT_IN_GROUP_OTHER = new DynamicCommandExceptionType(x ->
Text.literal(((GameProfile) x).getName()).append(Text.literal(" isn't in that group")));
private static final SimpleCommandExceptionType NAME_COLLISION = new SimpleCommandExceptionType(Text.literal("That name is already taken"));
private static final SimpleCommandExceptionType NO_SUCH_GROUP = new SimpleCommandExceptionType(Text.literal("No such group"));
public static final SimpleCommandExceptionType NO_SUCH_GROUP = new SimpleCommandExceptionType(Text.literal("No such group"));
private static final SimpleCommandExceptionType INVALID_GROUPNAME = new SimpleCommandExceptionType(Text.literal("Invalid group name"));
private static final Pattern GROUPNAME_PATTERN = Pattern.compile("^[\\w0-9_]{2,16}$", Pattern.UNICODE_CHARACTER_CLASS);

Expand All @@ -58,10 +58,67 @@ public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
.requires(Permissions.require("pingspam.group.player.add", 2))
.then(argument("player", GameProfileArgumentType.gameProfile())
.suggests(CommandUtil::suggestPlayers)
.executes(GroupCommand::removePlayerFromGroup)))))
.executes(GroupCommand::removePlayerFromGroup)))
.then(literal("pingable")
.requires(Permissions.require("pingspam.group.configure", 2))
.then(argument("value", BoolArgumentType.bool())
.executes(GroupCommand::configurePingable)))
.then(literal("haschat")
.requires(Permissions.require("pingspam.group.configure", 2))
.then(argument("value", BoolArgumentType.bool())
.executes(GroupCommand::configureGroupChat)))
))
);
}

private static int configurePingable(CommandContext<ServerCommandSource> ctx) throws CommandSyntaxException {
ServerCommandSource src = ctx.getSource();
String groupName = StringArgumentType.getString(ctx, "group");
var group = DataStore.getFor(src.getServer()).get(PingSpam.GLOBAL_DATA).groups().get(groupName);

if (group == null)
throw NO_SUCH_GROUP.create();

boolean value = BoolArgumentType.getBool(ctx, "value");
boolean old = group.isPingable();
group.isPingable(value);

if (old && !value) {
if (!NameLogic.isValidName(src.getServer(), groupName, false))
ServerNetworkLogic.removePossibleName(src.getServer().getPlayerManager(), groupName);
} else if (!old && value) {
ServerNetworkLogic.addPossibleName(src.getServer().getPlayerManager(), groupName);
}

src.sendFeedback(() -> Text.literal((value ? "Enabled" : "Disabled") + " pinging of ")
.formatted(Formatting.GREEN)
.append(Text.literal("@" + groupName)
.formatted(Formatting.YELLOW))
.append("."), true);

return 1;
}

private static int configureGroupChat(CommandContext<ServerCommandSource> ctx) throws CommandSyntaxException {
ServerCommandSource src = ctx.getSource();
String groupName = StringArgumentType.getString(ctx, "group");
var group = DataStore.getFor(src.getServer()).get(PingSpam.GLOBAL_DATA).groups().get(groupName);

if (group == null)
throw NO_SUCH_GROUP.create();

boolean value = BoolArgumentType.getBool(ctx, "value");
group.hasChat(value);

src.sendFeedback(() -> Text.literal((value ? "Enabled" : "Disabled") + " group chat for ")
.formatted(Formatting.GREEN)
.append(Text.literal("@" + groupName)
.formatted(Formatting.YELLOW))
.append("."), true);

return 1;
}

private static CompletableFuture<Suggestions> suggestGroups(CommandContext<ServerCommandSource> ctx, SuggestionsBuilder builder) {
ServerCommandSource src = ctx.getSource();

Expand All @@ -75,24 +132,24 @@ private static CompletableFuture<Suggestions> suggestGroups(CommandContext<Serve
private static int listPlayersInGroup(CommandContext<ServerCommandSource> ctx) throws CommandSyntaxException {
ServerCommandSource src = ctx.getSource();
String groupName = StringArgumentType.getString(ctx, "group");
List<UUID> players = DataStore.getFor(src.getServer()).get(PingSpam.GLOBAL_DATA).groups().get(groupName);
var group = DataStore.getFor(src.getServer()).get(PingSpam.GLOBAL_DATA).groups().get(groupName);

if (players == null)
if (group == null)
throw NO_SUCH_GROUP.create();

StringBuilder headerBuilder = new StringBuilder();
StringBuilder contentBuilder = new StringBuilder();
headerBuilder.append(" has ");
headerBuilder.append(players.size());
headerBuilder.append(group.members().size());
headerBuilder.append(" player");

if (players.size() != 1)
if (group.members().size() != 1)
headerBuilder.append("s");

if (players.size() > 0) {
if (group.members().size() > 0) {
headerBuilder.append(": ");
boolean isFirst = true;
for (UUID playerId : players) {
for (UUID playerId : group.members()) {
if (!isFirst)
contentBuilder.append(", ");
isFirst = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public static void register(CommandDispatcher<ServerCommandSource> dispatcher, C
PingSoundCommand.register(dispatcher);
PingIgnoreCommand.register(dispatcher);
GroupCommand.register(dispatcher);
ChatCommand.register(dispatcher);

dispatcher.register(
literal("pingspam")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

public class PingspamGlobalData implements ComponentInstance {
private final static Logger LOGGER = LoggerFactory.getLogger("Pingspam/PingspamGlobalData");
private final Map<String, List<UUID>> groups = CaseInsensitiveUtil.mapIgnoringCase();
private final Map<String, PingspamGroupData> groups = CaseInsensitiveUtil.mapIgnoringCase();
private final DataStore store;

public PingspamGlobalData(DataStore store) {
Expand Down Expand Up @@ -87,47 +85,56 @@ public void wasMissing() {
public void fromTag(NbtCompound tag) {
var groupsTag = tag.getCompound("Groups");
for (String groupName : groupsTag.getKeys()) {
var groupTag = groupsTag.getList(groupName, NbtElement.INT_ARRAY_TYPE);
groups.put(groupName, new ArrayList<>());
var group = new PingspamGroupData(groupName);
groups.put(groupName, group);
var groupTag = groupsTag.get(groupName);

for (NbtElement playerTag : groupTag) {
addPlayerToGroup(groupName, NbtHelper.toUuid(playerTag));
if (groupTag instanceof NbtList liste) {
for (NbtElement playerTag : liste) {
group.members.add(NbtHelper.toUuid(playerTag));
}
} else if (groupTag instanceof NbtCompound compound) {
group.fromTag(compound);
}

propagateGroup(group);
}

}

public Map<String, List<UUID>> groups() {
public Map<String, PingspamGroupData> groups() {
return groups;
}

private void propagateGroup(PingspamGroupData group) {
for (var memberId : group.members()) {
store.getPlayer(memberId, PingSpam.PLAYER_DATA).groups().add(group.name());
}
}

public void addPlayerToGroup(String group, UUID playerId) {
groups.computeIfAbsent(group, unused -> new ArrayList<>()).add(playerId);
groups.computeIfAbsent(group, PingspamGroupData::new).members.add(playerId);
store.getPlayer(playerId, PingSpam.PLAYER_DATA).groups().add(group);
}

public void removePlayerFromGroup(String group, UUID playerId) {
store.getPlayer(playerId, PingSpam.PLAYER_DATA).groups().remove(group);

List<UUID> playersInGroup = groups.get(group);
PingspamGroupData groupData = groups.get(group);

if (playersInGroup == null) return;
if (groupData == null) return;

playersInGroup.remove(playerId);
groupData.members.remove(playerId);

if (playersInGroup.size() == 0) groups.remove(group);
if (groupData.members().size() == 0) groups.remove(group);
}

@Override
public NbtCompound toTag(NbtCompound tag) {
var groupsTag = new NbtCompound();
tag.put("Groups", groupsTag);
for (var entry : groups.entrySet()) {
var groupTag = new NbtList();
groupsTag.put(entry.getKey(), groupTag);

for (UUID playerId : entry.getValue()) {
groupTag.add(NbtHelper.fromUuid(playerId));
}
groupsTag.put(entry.getKey(), entry.getValue().toTag(new NbtCompound()));
}

return tag;
Expand Down
Loading

0 comments on commit 1bd2f4d

Please sign in to comment.