From e6ec825bd2b48ff089e8416fea0bd20cdd9dd8ed Mon Sep 17 00:00:00 2001 From: iceBear67 Date: Wed, 10 Jul 2024 16:56:56 +0800 Subject: [PATCH] add: PingPlayerFeature (#1) fix many bugs, rewrote some message decorators to be refactored --- src/main/java/io/ib67/sfcraft/SFConsts.java | 4 +- .../sfcraft/message/SFMessageDecorator.java | 5 ++ .../message/SimpleMessageDecorator.java | 16 ++++- .../message/feature/PingPlayerFeature.java | 67 +++++++++++++++++++ .../message/feature/ReplaceHelper.java | 28 ++++++++ .../message/feature/SendLocationFeature.java | 23 ++----- 6 files changed, 123 insertions(+), 20 deletions(-) create mode 100644 src/main/java/io/ib67/sfcraft/message/feature/PingPlayerFeature.java create mode 100644 src/main/java/io/ib67/sfcraft/message/feature/ReplaceHelper.java diff --git a/src/main/java/io/ib67/sfcraft/SFConsts.java b/src/main/java/io/ib67/sfcraft/SFConsts.java index be0ef5c..abd185d 100644 --- a/src/main/java/io/ib67/sfcraft/SFConsts.java +++ b/src/main/java/io/ib67/sfcraft/SFConsts.java @@ -7,8 +7,10 @@ import net.minecraft.server.network.ServerPlayerEntity; @UtilityClass public class SFConsts { public static final String SPECIAL_SUDO = "sfcraft.special.state.sudo"; + public static final Permission USE_AT = ofSFCPermission("chat.at",true); + public static final Permission USE_BROADCAST_LOCATION = ofSFCPermission("chat.xyz",true); public static final Permission COMMAND_BACK = ofSFCPermission("command.home", true); - public static final Permission UNLIMITED_COMMAND_BACK = ofSFCPermission("command.home.unlimited", true); + public static final Permission UNLIMITED_COMMAND_BACK = ofSFCPermission("command.home.unlimited", false); public static final Permission COMMAND_ADDWL = ofSFCPermission("command.addwl", false); public static final Permission COMMAND_UNBLOCKSERVER = ofSFCPermission("command.unblockserver", false); diff --git a/src/main/java/io/ib67/sfcraft/message/SFMessageDecorator.java b/src/main/java/io/ib67/sfcraft/message/SFMessageDecorator.java index abb44ea..1824725 100644 --- a/src/main/java/io/ib67/sfcraft/message/SFMessageDecorator.java +++ b/src/main/java/io/ib67/sfcraft/message/SFMessageDecorator.java @@ -1,9 +1,14 @@ package io.ib67.sfcraft.message; +import io.ib67.sfcraft.message.feature.PingPlayerFeature; import io.ib67.sfcraft.message.feature.SendLocationFeature; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; public class SFMessageDecorator extends SimpleMessageDecorator { public SFMessageDecorator() { registerDecorator(new SendLocationFeature()); + registerDecorator(new PingPlayerFeature()); } + } diff --git a/src/main/java/io/ib67/sfcraft/message/SimpleMessageDecorator.java b/src/main/java/io/ib67/sfcraft/message/SimpleMessageDecorator.java index bf9c398..d8240d5 100644 --- a/src/main/java/io/ib67/sfcraft/message/SimpleMessageDecorator.java +++ b/src/main/java/io/ib67/sfcraft/message/SimpleMessageDecorator.java @@ -21,9 +21,21 @@ public class SimpleMessageDecorator implements MessageDecorator { @Override public Text decorate(@Nullable ServerPlayerEntity sender, Text message) { + var targets = new ArrayList(); + targets.add(message); for (MessageDecorator decorator : decorators) { - message = decorator.decorate(sender, message); + var newRd = new ArrayList(); + for (Text target : targets) { + var r = decorator.decorate(sender, target); + var copy = r.copy(); + copy.getSiblings().clear(); + newRd.add(copy); + newRd.addAll(r.getSiblings()); + } + targets = newRd; } - return message; + var result = Text.empty(); + targets.forEach(result::append); + return result; } } diff --git a/src/main/java/io/ib67/sfcraft/message/feature/PingPlayerFeature.java b/src/main/java/io/ib67/sfcraft/message/feature/PingPlayerFeature.java new file mode 100644 index 0000000..ab82e79 --- /dev/null +++ b/src/main/java/io/ib67/sfcraft/message/feature/PingPlayerFeature.java @@ -0,0 +1,67 @@ +package io.ib67.sfcraft.message.feature; + +import io.ib67.sfcraft.SFConsts; +import io.ib67.sfcraft.SFCraft; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.message.MessageDecorator; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvent; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.Text; +import net.minecraft.util.Colors; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.MatchResult; +import java.util.regex.Pattern; + +public class PingPlayerFeature implements MessageDecorator { + private static final Pattern PING = Pattern.compile("(@[\\w]+)?"); + + @Override + public Text decorate(@Nullable ServerPlayerEntity sender, Text message) { + if (sender != null) { + if (!SFConsts.USE_AT.hasPermission(sender)) { + return message; + } + } + var text = message.getLiteralString(); + if (text == null) return message; + var match = PING.matcher(text); + if (!match.find()) return message; + var foundPlayers = new HashSet(); + var names = List.of(SFCraft.getInstance().getServer().getPlayerNames()); + var r = Text.literal(match.replaceAll(it -> this.matchPlayer(it, names, foundPlayers))); + for (PlayerEntity foundPlayer : foundPlayers) { + if (sender != null) { + foundPlayer.sendMessage(Text.literal(sender.getName().getLiteralString() + " 正在叫你。").withColor(Colors.LIGHT_GRAY)); + } + foundPlayer.playSoundToPlayer( + SoundEvent.of(SoundEvents.ENTITY_ITEM_PICKUP.getId()), + SoundCategory.PLAYERS, + 0.8f, + 0.5f + ); + } + return r; + } + + private String matchPlayer(MatchResult match, List playerNames, Set foundPlayers) { + for (int i = 0; i < match.groupCount(); i++) { + var r = match.group(); + if (r.isEmpty()) continue; + final var d = r.substring(1); + return playerNames.stream() + .filter(it -> it.toLowerCase().startsWith(d)) + .peek(it -> foundPlayers.add(SFCraft.getInstance().getServer().getPlayerManager().getPlayer(it))) + .findFirst() + .orElse(r); + } + return ""; + } +} diff --git a/src/main/java/io/ib67/sfcraft/message/feature/ReplaceHelper.java b/src/main/java/io/ib67/sfcraft/message/feature/ReplaceHelper.java new file mode 100644 index 0000000..533768d --- /dev/null +++ b/src/main/java/io/ib67/sfcraft/message/feature/ReplaceHelper.java @@ -0,0 +1,28 @@ +package io.ib67.sfcraft.message.feature; + +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; + +import java.util.Locale; +import java.util.function.Function; + +class ReplaceHelper { + + public static Text replace(ServerPlayerEntity sender, Text message, String s, Function generator) { + var text = message.getLiteralString(); + if (text == null || text.isEmpty()) return message; + text = text.trim(); + var result = Text.literal(""); + var head = 0; + var lowercase = text.toLowerCase(Locale.ROOT); + var i = lowercase.indexOf(s); + while (i != -1) { + result.append(text.substring(0, i).trim()); + result.append(generator.apply(sender)); + head = i + s.length(); + i = lowercase.indexOf(s, head + 1); + } + result.append(text.substring(head).trim()); + return result; + } +} diff --git a/src/main/java/io/ib67/sfcraft/message/feature/SendLocationFeature.java b/src/main/java/io/ib67/sfcraft/message/feature/SendLocationFeature.java index 3b138e6..92a2412 100644 --- a/src/main/java/io/ib67/sfcraft/message/feature/SendLocationFeature.java +++ b/src/main/java/io/ib67/sfcraft/message/feature/SendLocationFeature.java @@ -1,6 +1,7 @@ package io.ib67.sfcraft.message.feature; import io.ib67.sfcraft.Helper; +import io.ib67.sfcraft.SFConsts; import net.minecraft.network.message.MessageDecorator; import net.minecraft.registry.RegistryKey; import net.minecraft.server.network.ServerPlayerEntity; @@ -12,24 +13,12 @@ import org.jetbrains.annotations.Nullable; public class SendLocationFeature implements MessageDecorator { @Override public Text decorate(@Nullable ServerPlayerEntity sender, Text message) { - var text = message.getLiteralString().trim(); - if (text == null) { - return message; + if (sender != null) { + if (!SFConsts.USE_BROADCAST_LOCATION.hasPermission(sender)) { + return message; + } } - if (text.trim().equals(".xyz")) { - return generateLocText(sender); - } - var result = Text.literal(""); - var head = 0; - var i = text.indexOf(".xyz"); - while (i != -1) { - result.append(text.substring(0, i).trim()); - result.append(generateLocText(sender)); - head = i + 4; - i = text.indexOf(".xyz", head + 1); - } - result.append(text.substring(head).trim()); - return result; + return ReplaceHelper.replace(sender, message, ".xyz", SendLocationFeature::generateLocText); } private static Text generateLocText(ServerPlayerEntity sender) {