diff --git a/bukkit/compatibility/build.gradle.kts b/bukkit/compatibility/build.gradle.kts index 05d1dc29f..8a7807cc9 100644 --- a/bukkit/compatibility/build.gradle.kts +++ b/bukkit/compatibility/build.gradle.kts @@ -32,6 +32,8 @@ dependencies { // MMOItems compileOnly("net.Indyuce:MMOItems-API:6.10-SNAPSHOT") compileOnly("io.lumine:MythicLib-dist:1.6.2-SNAPSHOT") + // LuckPerms + compileOnly("net.luckperms:api:5.4") } java { diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/permission/LuckPermsEventListeners.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/permission/LuckPermsEventListeners.java new file mode 100644 index 000000000..b08ce9481 --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/permission/LuckPermsEventListeners.java @@ -0,0 +1,85 @@ +package net.momirealms.craftengine.bukkit.compatibility.permission; + +import net.luckperms.api.LuckPerms; +import net.luckperms.api.event.EventBus; +import net.luckperms.api.event.EventSubscription; +import net.luckperms.api.event.group.GroupDataRecalculateEvent; +import net.luckperms.api.event.user.UserDataRecalculateEvent; +import net.luckperms.api.model.user.User; +import net.momirealms.craftengine.core.plugin.scheduler.SchedulerAdapter; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; +import java.util.logging.Level; + +public class LuckPermsEventListeners { + private final JavaPlugin plugin; + private final LuckPerms luckPerms; + private final BiConsumer consumer; + private final SchedulerAdapter scheduler; + private final List> subscriptions = new ArrayList<>(); + + public LuckPermsEventListeners(JavaPlugin plugin, BiConsumer consumer, SchedulerAdapter scheduler) { + this.plugin = plugin; + this.consumer = consumer; + this.scheduler = scheduler; + RegisteredServiceProvider provider = Bukkit.getServicesManager().getRegistration(LuckPerms.class); + if (provider != null) { + this.luckPerms = provider.getProvider(); + EventBus eventBus = this.luckPerms.getEventBus(); + EventSubscription onUserPermissionChangeSubscription = + eventBus.subscribe( + plugin, + UserDataRecalculateEvent.class, + this::onUserPermissionChange + ); + EventSubscription onGroupPermissionChangeSubscription = + eventBus.subscribe( + plugin, + GroupDataRecalculateEvent.class, + this::onGroupPermissionChange + ); + this.subscriptions.add(onUserPermissionChangeSubscription); + this.subscriptions.add(onGroupPermissionChangeSubscription); + } else luckPerms = null; + } + + public void unregisterListeners() { + for (EventSubscription subscription : this.subscriptions) { + try { + subscription.close(); + } catch (Exception e) { + this.plugin.getLogger().log(Level.WARNING,"Failed to close event subscription", e); + } + } + this.subscriptions.clear(); + } + + private void onUserPermissionChange(UserDataRecalculateEvent event) { + this.consumer.accept(event.getUser().getUniqueId(), true); + } + + private void onGroupPermissionChange(GroupDataRecalculateEvent event) { + this.scheduler.asyncLater(() -> { + String groupName = event.getGroup().getName(); + Bukkit.getOnlinePlayers().forEach(player -> { + UUID playerUUID = player.getUniqueId(); + User onlineUser = this.luckPerms.getUserManager().getUser(playerUUID); + if (onlineUser == null) return; + boolean isInGroup = onlineUser.getInheritedGroups(onlineUser.getQueryOptions()) + .parallelStream() + .anyMatch(g -> g.getName().equals(groupName)); + if (isInGroup) { + this.consumer.accept(playerUUID, false); + } + }); + }, 1L, TimeUnit.SECONDS); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java index 91eb5f378..682084cbb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java @@ -5,7 +5,7 @@ import com.google.gson.JsonObject; import io.papermc.paper.event.player.AsyncChatCommandDecorateEvent; import io.papermc.paper.event.player.AsyncChatDecorateEvent; import net.kyori.adventure.text.Component; -import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.compatibility.permission.LuckPermsEventListeners; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils; @@ -14,7 +14,6 @@ import net.momirealms.craftengine.core.font.*; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; -import net.momirealms.craftengine.core.util.CharacterUtils; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -32,10 +31,13 @@ import org.bukkit.inventory.meta.BookMeta; import org.bukkit.inventory.view.AnvilView; import java.lang.reflect.InvocationTargetException; -import java.util.*; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; public class BukkitFontManager extends AbstractFontManager implements Listener { private final BukkitCraftEngine plugin; + private LuckPermsEventListeners luckPermsEventListeners; public BukkitFontManager(BukkitCraftEngine plugin) { super(plugin); @@ -45,12 +47,20 @@ public class BukkitFontManager extends AbstractFontManager implements Listener { @Override public void delayedInit() { Bukkit.getPluginManager().registerEvents(this, plugin.bootstrap()); + if (this.plugin.isPluginEnabled("LuckPerms")) { + luckPermsEventListeners = new LuckPermsEventListeners( + plugin.bootstrap(), this::refreshEmojiSuggestions, plugin.scheduler() + ); + } } @Override public void disable() { super.disable(); HandlerList.unregisterAll(this); + if (luckPermsEventListeners != null && this.plugin.isPluginEnabled("LuckPerms")) { + luckPermsEventListeners.unregisterListeners(); + } } @Override @@ -64,23 +74,39 @@ public class BukkitFontManager extends AbstractFontManager implements Listener { }); } - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.LOWEST) public void onPlayerJoin(PlayerJoinEvent event) { - Player player = event.getPlayer(); - this.addEmojiSuggestions(player); + plugin.scheduler().async().execute(() -> { + Player player = event.getPlayer(); + this.addEmojiSuggestions(player); + }); + } + + public void refreshEmojiSuggestions(UUID playerUUID, boolean isAsync) { + if (isAsync) { + plugin.scheduler().async().execute(() -> { + Player player = Bukkit.getPlayer(playerUUID); + if (player == null) return; + player.removeCustomChatCompletions(oldCachedEmojiSuggestions); + this.addEmojiSuggestions(player); + }); + } else { + Player player = Bukkit.getPlayer(playerUUID); + if (player == null) return; + player.removeCustomChatCompletions(oldCachedEmojiSuggestions); + this.addEmojiSuggestions(player); + } } private void addEmojiSuggestions(Player player) { - List hasPermissions = new ArrayList<>(); - List cachedEmojiSuggestions = this.cachedEmojiSuggestions(); - for (String keyword : cachedEmojiSuggestions) { - Emoji emoji = super.emojiMapper.get(keyword); - if (emoji == null) continue; - if (emoji.permission() != null && !player.hasPermission(Objects.requireNonNull(emoji.permission()))) { - continue; - } - hasPermissions.add(keyword); - } + List hasPermissions = cachedEmojiSuggestions().parallelStream() + .filter(keyword -> { + Emoji emoji = super.emojiMapper.get(keyword); + if (emoji == null) return false; + String permission = emoji.permission(); + return permission == null || player.hasPermission(permission); + }) + .collect(Collectors.toList()); player.addCustomChatCompletions(hasPermissions); }