diff --git a/README.md b/README.md index ffb126d..35637cf 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,13 @@ # BetterPreview -Previews chat previes client-side to improve privacy, stability, and performance. +Processes chat previews client-side to improve privacy, stability, and performance. + +Must be installed on both client and server to work. Currently supports Fabric clients and Spigot servers. **Minecraft Version:** 1.19 + +## Supported Chat Plugins + +- [EssentialsChat](https://essentialsx.net/) + +More to come diff --git a/bp-spigot/build.gradle b/bp-spigot/build.gradle index b58305e..cbf7860 100644 --- a/bp-spigot/build.gradle +++ b/bp-spigot/build.gradle @@ -22,6 +22,9 @@ dependencies { compileOnly 'org.spigotmc:spigot-api:1.19-R0.1-SNAPSHOT' implementation "net.kyori:adventure-platform-bukkit:4.1.2-SNAPSHOT" + + // Some code from the Essentials project included, licensed under GPL3 + // https://github.com/EssentialsX/Essentials } processResources { diff --git a/bp-spigot/src/main/java/com/tisawesomeness/betterpreview/spigot/BetterPreviewSpigot.java b/bp-spigot/src/main/java/com/tisawesomeness/betterpreview/spigot/BetterPreviewSpigot.java index f27f1c0..46eb2a2 100644 --- a/bp-spigot/src/main/java/com/tisawesomeness/betterpreview/spigot/BetterPreviewSpigot.java +++ b/bp-spigot/src/main/java/com/tisawesomeness/betterpreview/spigot/BetterPreviewSpigot.java @@ -1,23 +1,30 @@ package com.tisawesomeness.betterpreview.spigot; import com.tisawesomeness.betterpreview.BetterPreview; -import com.tisawesomeness.betterpreview.format.ChatFormatter; -import com.tisawesomeness.betterpreview.format.ClassicFormatter; import com.tisawesomeness.betterpreview.format.FormatterRegistry; +import com.tisawesomeness.betterpreview.spigot.adapter.EssentialsChatAdapter; +import com.tisawesomeness.betterpreview.spigot.adapter.FormatAdapter; import io.netty.buffer.Unpooled; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.Nullable; public class BetterPreviewSpigot extends JavaPlugin { public static final String CHANNEL = BetterPreview.CHANNEL.asString(); - // Dummy example for now - private final ChatFormatter chatFormatter = new ClassicFormatter('&'); + private @Nullable FormatAdapter adapter; @Override public void onEnable() { + boolean hasEssentialsChat = Bukkit.getPluginManager().getPlugin("EssentialsChat") != null; + if (hasEssentialsChat) { + adapter = new EssentialsChatAdapter(); + getLogger().info("Found chat plugin: EssentialsChat"); + } + getServer().getMessenger().registerOutgoingPluginChannel(this, CHANNEL); getServer().getPluginManager().registerEvents(new JoinListener(this), this); } @@ -28,13 +35,13 @@ public void onDisable() { } public void sendFormatter(Player player) { - player.sendPluginMessage(this, CHANNEL, getFormatterData()); - } - private byte[] getFormatterData() { - var buf = Unpooled.buffer(); - FormatterRegistry.write(buf, chatFormatter); - assert buf.hasArray(); - return buf.array(); + if (adapter != null) { + var buf = Unpooled.buffer(); + var formatter = adapter.buildChatFormatter(player); + FormatterRegistry.write(buf, formatter); + assert buf.hasArray(); + player.sendPluginMessage(this, CHANNEL, buf.array()); + } } } diff --git a/bp-spigot/src/main/java/com/tisawesomeness/betterpreview/spigot/Util.java b/bp-spigot/src/main/java/com/tisawesomeness/betterpreview/spigot/Util.java new file mode 100644 index 0000000..a75d0f3 --- /dev/null +++ b/bp-spigot/src/main/java/com/tisawesomeness/betterpreview/spigot/Util.java @@ -0,0 +1,40 @@ +package com.tisawesomeness.betterpreview.spigot; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +public class Util { + + // Permission checker that supports wildcards without needing Vault + // Adapted from EssentialsChat + // https://github.com/EssentialsX/Essentials/blob/2.x/Essentials/src/main/java/com/earth2me/essentials/perm/impl/SuperpermsHandler.java + + /** + * Checks if the player has the given permission, checking wildcards. + * Use {@link Player#isPermissionSet(String)} to check if a permission is set. + * @param player the player to check + * @param permission the permission to check + * @return whether the player has the permission + */ + public static boolean hasPermission(Player player, String permission) { + String perm = permission; + String permToCheck = permission; + int idx; + while (true) { + if (player.isPermissionSet(permToCheck) || isDeniedToOps(permToCheck)) { + return player.hasPermission(permToCheck); + } + idx = perm.lastIndexOf('.'); + if (idx < 1) { + return player.hasPermission("*"); + } + perm = perm.substring(0, idx); + permToCheck = perm + ".*"; + } + } + private static boolean isDeniedToOps(String node) { + var perm = Bukkit.getServer().getPluginManager().getPermission(node); + return perm != null && !perm.getDefault().getValue(true); + } + +} diff --git a/bp-spigot/src/main/java/com/tisawesomeness/betterpreview/spigot/adapter/EssentialsChatAdapter.java b/bp-spigot/src/main/java/com/tisawesomeness/betterpreview/spigot/adapter/EssentialsChatAdapter.java new file mode 100644 index 0000000..4ea37cf --- /dev/null +++ b/bp-spigot/src/main/java/com/tisawesomeness/betterpreview/spigot/adapter/EssentialsChatAdapter.java @@ -0,0 +1,55 @@ +package com.tisawesomeness.betterpreview.spigot.adapter; + +import com.tisawesomeness.betterpreview.format.ChatFormatter; +import com.tisawesomeness.betterpreview.format.ClassicFormatter; +import com.tisawesomeness.betterpreview.spigot.Util; + +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.entity.Player; + +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Set; + +public class EssentialsChatAdapter implements FormatAdapter { + + private static final String BASE_PERMISSION = "essentials.chat"; + private static final Set FORMAT_DECORATIONS = EnumSet.of( + TextDecoration.BOLD, + TextDecoration.ITALIC, + TextDecoration.STRIKETHROUGH, + TextDecoration.UNDERLINED + ); + + @Override + public ChatFormatter buildChatFormatter(Player player) { + var colors = new HashSet(); + if (Util.hasPermission(player, BASE_PERMISSION + ".color")) { + colors.addAll(ClassicFormatter.ALL_NAMED_COLORS); + } + for (var color : ClassicFormatter.ALL_NAMED_COLORS) { + String perm = BASE_PERMISSION + "." + color.toString(); + if (player.isPermissionSet(perm)) { + if (Util.hasPermission(player, perm)) { + colors.add(color); + } else { + colors.remove(color); + } + } + } + + var decorations = EnumSet.noneOf(TextDecoration.class); + boolean resetAllowed = false; + if (Util.hasPermission(player, BASE_PERMISSION + ".format")) { + decorations.addAll(FORMAT_DECORATIONS); + resetAllowed = true; + } + if (Util.hasPermission(player, BASE_PERMISSION + ".magic")) { + decorations.add(TextDecoration.OBFUSCATED); + } + + return new ClassicFormatter('&', colors, decorations, resetAllowed); + } + +} diff --git a/bp-spigot/src/main/java/com/tisawesomeness/betterpreview/spigot/adapter/FormatAdapter.java b/bp-spigot/src/main/java/com/tisawesomeness/betterpreview/spigot/adapter/FormatAdapter.java new file mode 100644 index 0000000..fd44fa1 --- /dev/null +++ b/bp-spigot/src/main/java/com/tisawesomeness/betterpreview/spigot/adapter/FormatAdapter.java @@ -0,0 +1,19 @@ +package com.tisawesomeness.betterpreview.spigot.adapter; + +import com.tisawesomeness.betterpreview.format.ChatFormatter; + +import org.bukkit.entity.Player; + +/** + * Adapts a plugin's chat system to a BetterPreview chat formatter. + */ +public interface FormatAdapter { + + /** + * Builds a chat formatter for the player based on the player's permissions and the chat plugin config. + * @param player the player who will be sent the formatter + * @return the formatter + */ + ChatFormatter buildChatFormatter(Player player); + +} diff --git a/bp-spigot/src/main/resources/plugin.yml b/bp-spigot/src/main/resources/plugin.yml index 4b1dc92..139e198 100644 --- a/bp-spigot/src/main/resources/plugin.yml +++ b/bp-spigot/src/main/resources/plugin.yml @@ -2,4 +2,5 @@ name: BetterPreview version: '${version}' main: com.tisawesomeness.betterpreview.spigot.BetterPreviewSpigot api-version: 1.19 -authors: [ Tis_awesomeness ] \ No newline at end of file +authors: [ Tis_awesomeness ] +softdepend: [ EssentialsChat ] \ No newline at end of file