Luckperms prefix support

This commit is contained in:
NotAlexNoyle committed 2026-06-25 16:45:22 -04:00
1 parent 0de1738130
commit 51300c87fd
7 files changed
+129 -17

No files matched your search

+2 -1
View File
@@ -6,7 +6,7 @@ plugins {
}
group = "de.codecrafter"
version = providers.gradleProperty("version").getOrElse("1.0.0-beta")
version = providers.gradleProperty("version").getOrElse("1.0.0")
val pluginName = "AFK-OG"
val apiVersion = "1.19"
@@ -39,6 +39,7 @@ repositories {
dependencies {
compileOnly("org.purpurmc.purpur:purpur-api:1.19.4-R0.1-SNAPSHOT")
compileOnly("me.clip:placeholderapi:2.12.2")
compileOnly("net.luckperms:api:5.5")
implementation("com.google.code.gson:gson:2.13.2")
}
@@ -8,6 +8,7 @@ package de.codecrafter.smartAfk;
import org.bukkit.plugin.java.JavaPlugin;
import de.codecrafter.smartAfk.commands.AfkCommand;
import de.codecrafter.smartAfk.integrations.LuckPermsHook;
import de.codecrafter.smartAfk.integrations.NoCheatPlusHook;
import de.codecrafter.smartAfk.listeners.AfkListener;
import de.codecrafter.smartAfk.listeners.PlayerJoinListener;
@@ -41,6 +42,9 @@ public final class AFKOG extends JavaPlugin {
// optional NoCheatPlus backstop for combat auto-click detection.
NoCheatPlusHook.register(this, afkManager);
// optional LuckPerms hook for AFK broadcast prefixes.
LuckPermsHook.initialize(this);
if (getServer().getPluginManager().isPluginEnabled("PlaceholderAPI")) {
new AfkPlaceholderExpansion(this).register();
@@ -65,6 +69,8 @@ public final class AFKOG extends JavaPlugin {
getServer().getOnlinePlayers().stream().filter(afkManager::isAfk).forEach(afkManager::unsetAfk);
LuckPermsHook.shutdown();
}
public static AFKOG getPlugin() {
@@ -0,0 +1,90 @@
/*
* This file is part of the Minecraft Smart Afk project.
* Licensed under the MIT License. See the LICENSE file in the project root for full license information.
*/
package de.codecrafter.smartAfk.integrations;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import de.codecrafter.smartAfk.AFKOG;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.LuckPermsProvider;
import net.luckperms.api.cacheddata.CachedMetaData;
/**
* Optional bridge to LuckPerms. When LuckPerms is installed, resolves a player's
* chat prefix (in their current context) for use in AFK broadcast messages.
*
* LuckPerms is a true soft dependency: every method is a no-op returning an empty
* string when LuckPerms is absent, so the plugin runs identically without it. The
* LuckPerms API classes are only touched after the presence check, so the JVM
* never needs them on the classpath when LuckPerms is not installed.
*/
public final class LuckPermsHook {
private static LuckPerms luckPerms;
private LuckPermsHook() {
}
/**
* Caches the LuckPerms API handle if LuckPerms is installed. A no-op otherwise.
*/
public static void initialize(AFKOG plugin) {
if (Bukkit.getPluginManager().getPlugin("LuckPerms") == null) {
return;
}
try {
luckPerms = LuckPermsProvider.get();
plugin.getLogger().info("Hooked into LuckPerms for AFK broadcast prefixes.");
} catch (final IllegalStateException exception) {
luckPerms = null;
plugin.getLogger().warning("LuckPerms is present but its API was unavailable; AFK broadcasts will omit prefixes.");
}
}
/**
* Drops the cached API handle so a plugin disable/reload does not retain the
* LuckPerms classloader.
*/
public static void shutdown() {
luckPerms = null;
}
/**
* Returns the player's prefix in their current context, or an empty string when
* LuckPerms is absent or the player has no prefix. The returned value may carry
* legacy '&'/section color codes set by LuckPerms.
*
* @param player The player whose prefix to resolve.
*/
public static String getPrefix(Player player) {
if (luckPerms == null) {
return "";
}
final CachedMetaData metaData = luckPerms.getPlayerAdapter(Player.class).getMetaData(player);
final String prefix = metaData.getPrefix();
return prefix == null ? "" : prefix;
}
}
@@ -101,8 +101,8 @@ public class AfkConfig {
}
this.afkBroadcastWorlds = worlds;
this.afkBroadcastMessage = config.getString("afk-broadcast-message", "&e%player% &7is now AFK.");
this.afkBroadcastReturnMessage = config.getString("afk-broadcast-return-message", "&e%player% &7is no longer AFK.");
this.afkBroadcastMessage = config.getString("afk-broadcast-message", "%prefix%&e%player% &7is now AFK.");
this.afkBroadcastReturnMessage = config.getString("afk-broadcast-return-message", "%prefix%&e%player% &7is no longer AFK.");
}
@@ -23,6 +23,7 @@ import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import de.codecrafter.smartAfk.AFKOG;
import de.codecrafter.smartAfk.integrations.LuckPermsHook;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextReplacementConfig;
import net.kyori.adventure.text.event.ClickEvent;
@@ -79,12 +80,7 @@ public class AfkManager {
player.sendMessage(legacy(AFKOG.getPrefix() + "&cYou are now AFK."));
final AfkConfig config = AFKOG.getPlugin().getAfkConfig();
if (config.isBroadcastWorld(player.getWorld().getName())) {
final String message = config.getAfkBroadcastMessage().replace("%player%", player.getName());
AFKOG.getPlugin().getServer().broadcast(legacy(AFKOG.getPrefix() + message));
}
broadcastAfk(player, config.getAfkBroadcastMessage());
clearMobTargets(player);
@@ -112,13 +108,30 @@ public class AfkManager {
player.sendMessage(legacy(AFKOG.getPrefix() + "&aYou are no longer AFK."));
final AfkConfig config = AFKOG.getPlugin().getAfkConfig();
if (config.isBroadcastWorld(player.getWorld().getName())) {
broadcastAfk(player, config.getAfkBroadcastReturnMessage());
final String message = config.getAfkBroadcastReturnMessage().replace("%player%", player.getName());
AFKOG.getPlugin().getServer().broadcast(legacy(AFKOG.getPrefix() + message));
}
/**
* Broadcasts {@code template} to the whole server when the player is in a
* configured broadcast world. {@code %prefix%} is replaced with the player's
* LuckPerms prefix (empty when LuckPerms is absent) and {@code %player%} with
* the player name.
*/
private void broadcastAfk(Player player, String template) {
final AfkConfig config = AFKOG.getPlugin().getAfkConfig();
if (!config.isBroadcastWorld(player.getWorld().getName())) {
return;
}
final String message = template
.replace("%prefix%", LuckPermsHook.getPrefix(player))
.replace("%player%", player.getName());
AFKOG.getPlugin().getServer().broadcast(legacy(AFKOG.getPrefix() + message));
}
public boolean isAfk(Player player) {
+6 -4
View File
@@ -20,12 +20,14 @@ afk-broadcast-worlds:
- world_the_end
# message broadcast when a player goes AFK in a whitelisted world.
# supports legacy '&' color codes. %player% is replaced with the player name.
afk-broadcast-message: "&e%player% &7is now AFK."
# supports legacy '&' color codes. %player% is replaced with the player name and
# %prefix% with the player's LuckPerms prefix (empty if LuckPerms is not installed).
afk-broadcast-message: "%prefix%&e%player% &7is now AFK."
# message broadcast when a player stops being AFK in a whitelisted world.
# supports legacy '&' color codes. %player% is replaced with the player name.
afk-broadcast-return-message: "&e%player% &7is no longer AFK."
# supports legacy '&' color codes. %player% is replaced with the player name and
# %prefix% with the player's LuckPerms prefix (empty if LuckPerms is not installed).
afk-broadcast-return-message: "%prefix%&e%player% &7is no longer AFK."
# kick players after this many seconds of true inactivity (no movement, no input).
# set to -1 to disable.
+1 -1
View File
@@ -4,7 +4,7 @@ main: de.codecrafter.smartAfk.AFKOG
api-version: ${apiVersion}
authors: [ Felix_Heidisch, NotAlexNoyle ]
website: https://github.com/true-og/AFK-OG
softdepend: [PlaceholderAPI, NoCheatPlus]
softdepend: [PlaceholderAPI, NoCheatPlus, LuckPerms]
commands:
afk:
description: Toggles the afk state.