develop-chatReply #5

Merged
Pupsi merged 11 commits from develop-chatReply into master 2024-10-06 13:52:59 +00:00
11 changed files with 193 additions and 18 deletions
Showing only changes of commit 577e99fcfc - Show all commits

View File

@ -19,6 +19,7 @@ import eu.mhsl.craftattack.spawn.appliances.outlawed.Outlawed;
import eu.mhsl.craftattack.spawn.appliances.panicBan.PanicBan; import eu.mhsl.craftattack.spawn.appliances.panicBan.PanicBan;
import eu.mhsl.craftattack.spawn.appliances.playerlimit.PlayerLimit; import eu.mhsl.craftattack.spawn.appliances.playerlimit.PlayerLimit;
import eu.mhsl.craftattack.spawn.appliances.portableCrafting.PortableCrafting; import eu.mhsl.craftattack.spawn.appliances.portableCrafting.PortableCrafting;
import eu.mhsl.craftattack.spawn.appliances.privateMessage.PrivateMessage;
import eu.mhsl.craftattack.spawn.appliances.projectStart.ProjectStart; import eu.mhsl.craftattack.spawn.appliances.projectStart.ProjectStart;
import eu.mhsl.craftattack.spawn.appliances.report.Report; import eu.mhsl.craftattack.spawn.appliances.report.Report;
import eu.mhsl.craftattack.spawn.appliances.restart.Restart; import eu.mhsl.craftattack.spawn.appliances.restart.Restart;
@ -75,7 +76,8 @@ public final class Main extends JavaPlugin {
new AutoShulker(), new AutoShulker(),
new AntiSignEdit(), new AntiSignEdit(),
new HotbarRefill(), new HotbarRefill(),
new ChatMention() new ChatMention(),
new PrivateMessage()
); );
Main.logger.info("Loading appliances..."); Main.logger.info("Loading appliances...");

View File

@ -1,6 +1,8 @@
package eu.mhsl.craftattack.spawn.appliances.chatMention; package eu.mhsl.craftattack.spawn.appliances.chatMention;
import eu.mhsl.craftattack.spawn.Main;
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener; import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
import eu.mhsl.craftattack.spawn.appliances.chatMessages.ChatMessages;
import eu.mhsl.craftattack.spawn.appliances.settings.Settings; import eu.mhsl.craftattack.spawn.appliances.settings.Settings;
import eu.mhsl.craftattack.spawn.appliances.settings.settings.ChatMentionSetting; import eu.mhsl.craftattack.spawn.appliances.settings.settings.ChatMentionSetting;
import io.papermc.paper.event.player.AsyncChatDecorateEvent; import io.papermc.paper.event.player.AsyncChatDecorateEvent;
@ -8,6 +10,7 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerJoinEvent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -22,6 +25,7 @@ public class ChatMentionListener extends ApplianceListener<ChatMention> {
ChatMentionSetting.ChatMentionConfig config = Settings.instance() ChatMentionSetting.ChatMentionConfig config = Settings.instance()
.getSetting(event.player(), Settings.Key.ChatMentions, ChatMentionSetting.ChatMentionConfig.class); .getSetting(event.player(), Settings.Key.ChatMentions, ChatMentionSetting.ChatMentionConfig.class);
ChatMessages chatMessages = Main.instance().getAppliance(ChatMessages.class);
Component result = words.stream() Component result = words.stream()
.map(word -> { .map(word -> {
@ -29,10 +33,11 @@ public class ChatMentionListener extends ApplianceListener<ChatMention> {
boolean isPlayer = getAppliance().getPlayerNames().contains(wordWithoutAnnotation); boolean isPlayer = getAppliance().getPlayerNames().contains(wordWithoutAnnotation);
if(isPlayer && config.applyMentions()) { if(isPlayer && config.applyMentions()) {
mentioned.add(wordWithoutAnnotation); mentioned.add(wordWithoutAnnotation);
return Component.text( Component mention = Component.text(
getAppliance().formatPlayer(wordWithoutAnnotation), getAppliance().formatPlayer(wordWithoutAnnotation),
NamedTextColor.GOLD NamedTextColor.GOLD
); );
return chatMessages.addReportActions(mention, wordWithoutAnnotation);
} else { } else {
return Component.text(word); return Component.text(word);
} }
@ -43,4 +48,9 @@ public class ChatMentionListener extends ApplianceListener<ChatMention> {
getAppliance().notifyPlayers(mentioned); getAppliance().notifyPlayers(mentioned);
event.result(result); event.result(result);
} }
@EventHandler
public void onJoin(PlayerJoinEvent event) {
getAppliance().refreshPlayers();
}
} }

View File

@ -13,11 +13,13 @@ import java.util.List;
public class ChatMessages extends Appliance { public class ChatMessages extends Appliance {
public Component getReportablePlayerName(Player player) { public Component getReportablePlayerName(Player player) {
return Component return addReportActions(player.displayName(), player.getName());
.text("") }
.append(player.displayName())
public Component addReportActions(Component message, String username) {
return message
.hoverEvent(HoverEvent.showText(Component.text("Klicke, um diesen Spieler zu reporten").color(NamedTextColor.GOLD))) .hoverEvent(HoverEvent.showText(Component.text("Klicke, um diesen Spieler zu reporten").color(NamedTextColor.GOLD)))
.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/report " + player.getName() + " ")); .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.SUGGEST_COMMAND, String.format("/report %s ", username)));
} }
@Override @Override

View File

@ -0,0 +1,93 @@
package eu.mhsl.craftattack.spawn.appliances.privateMessage;
import eu.mhsl.craftattack.spawn.Main;
import eu.mhsl.craftattack.spawn.appliance.Appliance;
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
import eu.mhsl.craftattack.spawn.appliances.chatMessages.ChatMessages;
import eu.mhsl.craftattack.spawn.appliances.privateMessage.commands.PrivateMessageCommand;
import eu.mhsl.craftattack.spawn.appliances.privateMessage.commands.PrivateReplyCommand;
import eu.mhsl.craftattack.spawn.util.LimitedSizedList;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.stream.Collectors;
public class PrivateMessage extends Appliance {
public final int targetChangeTimeout = 30;
private record Conversation(UUID target, Long lastSet) {}
private final Map<Player, LimitedSizedList<Conversation>> replyMapping = new WeakHashMap<>();
public void reply(Player sender, String message) {
Conversation senderConversation = this.replyMapping.get(sender).getLast();
Pupsi marked this conversation as resolved Outdated

die null checks überall sind nicht schön, es macht vielleicht eher sinn am anfang einmal zu prüfen ob ein Eintrag vorhanden ist und wenn nicht ne leere Liste zu initialisieren..

this.replyMapping.computeIfNotPresent(() -> new ArrayList<>());

die null checks überall sind nicht schön, es macht vielleicht eher sinn am anfang einmal zu prüfen ob ein Eintrag vorhanden ist und wenn nicht ne leere Liste zu initialisieren.. `this.replyMapping.computeIfNotPresent(() -> new ArrayList<>());`
if(senderConversation == null) throw new ApplianceCommand.Error("Du kannst nicht auf eine konversation antworten, da keine vorhanden ist.");
Pupsi marked this conversation as resolved Outdated

hier wird ganz oft this.replyMapping.get(sender) verwendet, rausziehen in eine eigene variable z.B. replyMap = this.replyMapping.get(sender)

hier wird ganz oft `this.replyMapping.get(sender)` verwendet, rausziehen in eine eigene variable z.B. `replyMap = this.replyMapping.get(sender)`
// if(!senderConversation.isChecked && senderConversation.lastSet > System.currentTimeMillis() - targetChangeTimeout) {
// throw new ApplianceCommand.Error("ziel geändedrt.......");
// }
Player target = Bukkit.getPlayer(senderConversation.target);
if(target == null) throw new ApplianceCommand.Error("Der Spieler ist nicht mehr verfügbar.");
sendWhisper(sender, new ResolvedPmUserArguments(target, message));
}
public void sendWhisper(Player sender, ResolvedPmUserArguments userArguments) {
MineTec marked this conversation as resolved Outdated

das kann noch über tooOldConversations und dort verwendet werden, auch bei dem removeAll

das kann noch über tooOldConversations und dort verwendet werden, auch bei dem removeAll
// this.replyMapping.put(
// sender,
// new Conversation(
// userArguments.receiver.getUniqueId(),
// System.currentTimeMillis()
// )
// );
// this.replyMapping.put(
// userArguments.receiver,
// new Conversation(
Pupsi marked this conversation as resolved
Review

initialisierung und sofortig bedingtes überschreiben würde ich als bad practice einstufen...

Umschreiben zu

Component currentTargetComponent = currentTargetPlayer != null
    ? Main.instance().getAppliance(ChatMessages.class).getReportablePlayerName(currentTargetPlayer)
    : Component.text("niemandem.");
initialisierung und sofortig bedingtes überschreiben würde ich als bad practice einstufen... Umschreiben zu ``` Component currentTargetComponent = currentTargetPlayer != null ? Main.instance().getAppliance(ChatMessages.class).getReportablePlayerName(currentTargetPlayer) : Component.text("niemandem."); ```
// sender.getUniqueId(),
// System.currentTimeMillis()
// )
// );
ChatMessages chatMessages = Main.instance().getAppliance(ChatMessages.class);
Component privatePrefix = Component.text("[Privat] ", NamedTextColor.LIGHT_PURPLE);
sender.sendMessage(
Component.text()
.append(privatePrefix.clickEvent(ClickEvent.suggestCommand(String.format("/msg %s ", userArguments.receiver.getName()))))
.append(sender.displayName())
.append(Component.text(" zu ", NamedTextColor.GRAY))
.append(chatMessages.getReportablePlayerName(userArguments.receiver))
.append(Component.text(" > ", NamedTextColor.GRAY))
.append(Component.text(userArguments.message))
Pupsi marked this conversation as resolved Outdated

this.sendWhisper

this.sendWhisper
);
userArguments.receiver.sendMessage(
Component.text()
.append(privatePrefix.clickEvent(ClickEvent.suggestCommand(String.format("/msg %s ", sender.getName()))))
Pupsi marked this conversation as resolved Outdated

das senden einzelner messages ist problematisch...

in der theorie könnten andere messages welche parallel gesendet werden so zwischen die messages rutschen. Außerdem ist jeder sendMessage aufruf ein eigenes paket, welches an den Spieler gesendet wird.

die Aufrufe sollten zusammengezogen werden zu einem einzelnen aufruf, leerzeilen können mit .appendNewLine eingefügt werden.

Hier bietet sich ggf der ComponentBuilder an, dieser kann mit Component.text() erstellt werden.

Anschließend kann darauf mit component.append(otherComponent) gearbeitet werden. Zum schluss dann sender.sendMessage(component.build())

das senden einzelner messages ist problematisch... in der theorie könnten andere messages welche parallel gesendet werden so zwischen die messages rutschen. Außerdem ist jeder sendMessage aufruf ein eigenes paket, welches an den Spieler gesendet wird. die Aufrufe sollten zusammengezogen werden zu einem einzelnen aufruf, leerzeilen können mit `.appendNewLine` eingefügt werden. Hier bietet sich ggf der ComponentBuilder an, dieser kann mit `Component.text()` erstellt werden. Anschließend kann darauf mit `component.append(otherComponent)` gearbeitet werden. Zum schluss dann `sender.sendMessage(component.build())`
.append(chatMessages.getReportablePlayerName(sender))
.append(Component.text(" zu ", NamedTextColor.GRAY))
.append(userArguments.receiver.displayName())
.append(Component.text(" > ", NamedTextColor.GRAY))
.append(Component.text(userArguments.message))
);
Pupsi marked this conversation as resolved Outdated

"erhalten" statt "bekommen" klingt denke ich besser

"erhalten" statt "bekommen" klingt denke ich besser
}
public record ResolvedPmUserArguments(Player receiver, String message) {}
public ResolvedPmUserArguments resolveImplicit(String[] args) {
Pupsi marked this conversation as resolved Outdated

hier steht die gleiche logik wie in zeile 58

lässt sich das vielleicht schlau kombinieren, dass du oldConversations schon oben erstellst und die andere prüfung auf der bestehenden Liste dann ausführst?

hier steht die gleiche logik wie in zeile 58 lässt sich das vielleicht schlau kombinieren, dass du oldConversations schon oben erstellst und die andere prüfung auf der bestehenden Liste dann ausführst?
if(args.length < 2) throw new ApplianceCommand.Error("Es muss ein Spieler sowie eine Nachricht angegeben werden.");
List<String> arguments = List.of(args);
Player targetPlayer = Bukkit.getPlayer(arguments.getFirst());
Pupsi marked this conversation as resolved
Review

gibt es einen Grund warum die Variable hier außerhalb allokiert wird aber nur innerhalb des if statements genutzt wird?

gibt es einen Grund warum die Variable hier außerhalb allokiert wird aber nur innerhalb des if statements genutzt wird?
if(targetPlayer == null) throw new ApplianceCommand.Error(String.format("Der Spieler %s konnte nicht gefunden werden.", arguments.getFirst()));
String message = arguments.stream().skip(1).collect(Collectors.joining(" "));
return new ResolvedPmUserArguments(targetPlayer, message);
}
@Override
protected @NotNull List<ApplianceCommand<?>> commands() {
return List.of(
new PrivateMessageCommand(),
new PrivateReplyCommand()
);
}
}

View File

@ -0,0 +1,18 @@
package eu.mhsl.craftattack.spawn.appliances.privateMessage.commands;
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
import eu.mhsl.craftattack.spawn.appliances.privateMessage.PrivateMessage;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public class PrivateMessageCommand extends ApplianceCommand.PlayerChecked<PrivateMessage> {
public PrivateMessageCommand() {
super("msg");
}
@Override
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
getAppliance().sendWhisper(getPlayer(), getAppliance().resolveImplicit(args));
}
}

View File

@ -0,0 +1,18 @@
package eu.mhsl.craftattack.spawn.appliances.privateMessage.commands;
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
import eu.mhsl.craftattack.spawn.appliances.privateMessage.PrivateMessage;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public class PrivateReplyCommand extends ApplianceCommand.PlayerChecked<PrivateMessage> {
public PrivateReplyCommand() {
super("r");
}
@Override
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
getAppliance().reply(getPlayer(), String.join(" ", args));
}
}

View File

@ -43,7 +43,10 @@ public class Whitelist extends Appliance {
public void integrityCheck(Player player) throws DisconnectInfo.Throwable { public void integrityCheck(Player player) throws DisconnectInfo.Throwable {
try { try {
Main.instance().getLogger().info(String.format("Running integrityCheck for %s", player.getName())); Main.instance().getLogger().info(String.format("Running integrityCheck for %s", player.getName()));
UserData user = this.fetchUserData(player.getUniqueId()); boolean overrideCheck = localConfig().getBoolean("overrideIntegrityCheck", false);
UserData user = overrideCheck
? new UserData(player.getUniqueId(), player.getName(), "", "", 0L, 0L)
: this.fetchUserData(player.getUniqueId());
if(timestampRelevant(user.banned_until)) { if(timestampRelevant(user.banned_until)) {
Instant bannedDate = new Date(user.banned_until * 1000L) Instant bannedDate = new Date(user.banned_until * 1000L)
@ -63,12 +66,9 @@ public class Whitelist extends Appliance {
Main.instance().getAppliance(Outlawed.class).updateForcedStatus(player, timestampRelevant(user.outlawed_until)); Main.instance().getAppliance(Outlawed.class).updateForcedStatus(player, timestampRelevant(user.outlawed_until));
String purePlayerName; String purePlayerName = Floodgate.isBedrock(player)
if(Floodgate.isBedrock(player)) { ? Floodgate.getBedrockPlayer(player).getUsername()
purePlayerName = Floodgate.getBedrockPlayer(player).getUsername(); : player.getName();
} else {
purePlayerName = player.getName();
}
if(!user.username.trim().equalsIgnoreCase(purePlayerName)) if(!user.username.trim().equalsIgnoreCase(purePlayerName))
throw new DisconnectInfo.Throwable( throw new DisconnectInfo.Throwable(
@ -100,8 +100,7 @@ public class Whitelist extends Appliance {
URIBuilder uriBuilder = new URIBuilder(apiEndpoint); URIBuilder uriBuilder = new URIBuilder(apiEndpoint);
uriBuilder.addParameter("uuid", uuid.toString()); uriBuilder.addParameter("uuid", uuid.toString());
try { try(HttpClient client = HttpClient.newHttpClient()) {
HttpClient client = HttpClient.newHttpClient();
HttpRequest httpRequest = HttpRequest.newBuilder() HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(uriBuilder.build()) .uri(uriBuilder.build())
.header("Content-Type", "application/json") .header("Content-Type", "application/json")

View File

@ -0,0 +1,27 @@
package eu.mhsl.craftattack.spawn.util;
import java.util.ArrayList;
public class LimitedSizedList<T> extends ArrayList<T> {
Pupsi marked this conversation as resolved Outdated

wenn die Klasse nicht mehr verwendet wird kann sie raus

wenn die Klasse nicht mehr verwendet wird kann sie raus
private final int maxSize;
public LimitedSizedList(int size){
this.maxSize = size;
}
public boolean add(T element){
boolean r = super.add(element);
if (size() > maxSize){
removeRange(0, size() - maxSize);
}
return r;
}
public T getYoungest() {
return get(size() - 1);
}
public T getOldest() {
return get(0);
}
}

View File

@ -9,6 +9,7 @@ import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.time.Duration; import java.time.Duration;
import java.util.logging.Level;
public class NetworkMonitor { public class NetworkMonitor {
private long previousRxBytes = 0; private long previousRxBytes = 0;
@ -78,7 +79,9 @@ public class NetworkMonitor {
String content = new String(Files.readAllBytes(Paths.get(path))); String content = new String(Files.readAllBytes(Paths.get(path)));
return Long.parseLong(content.trim()); return Long.parseLong(content.trim());
} catch(IOException e) { } catch(IOException e) {
throw new RuntimeException("Failed recieving Network statistic", e); Main.logger().log(Level.SEVERE, "Statistics are only supported on Linux! Is tablist.interface config set correctly?");
this.stop();
throw new RuntimeException("Failed reading network statistic", e);
} }
} }
} }

View File

@ -42,9 +42,10 @@ help:
spawn: "Der Weltspawn befindet sich bei x:0 y:0 z:0" spawn: "Der Weltspawn befindet sich bei x:0 y:0 z:0"
playerLimit: playerLimit:
maxPlayers: 0 maxPlayers: 100
whitelist: whitelist:
overrideIntegrityCheck: false
api: https://mhsl.eu/craftattack/api/user api: https://mhsl.eu/craftattack/api/user
tablist: tablist:

View File

@ -37,3 +37,5 @@ commands:
panicBan: panicBan:
vogelfrei: vogelfrei:
settings: settings:
msg:
r: