Skip to content

Commit 4ec4cd0

Browse files
committed
Enhance permission checks to support offline users
1 parent 55c8117 commit 4ec4cd0

File tree

2 files changed

+114
-25
lines changed

2 files changed

+114
-25
lines changed

AdvancedCore/src/main/java/com/bencodez/advancedcore/api/permissions/LuckPermsHandle.java

Lines changed: 92 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,46 +2,123 @@
22

33
import java.util.UUID;
44
import java.util.concurrent.CompletableFuture;
5-
import java.util.concurrent.ExecutionException;
65
import java.util.concurrent.TimeUnit;
7-
import java.util.concurrent.TimeoutException;
86

97
import org.bukkit.Bukkit;
8+
import org.bukkit.entity.Player;
109
import org.bukkit.plugin.RegisteredServiceProvider;
1110

1211
import com.bencodez.advancedcore.AdvancedCorePlugin;
1312

1413
import lombok.Getter;
1514
import net.luckperms.api.LuckPerms;
1615
import net.luckperms.api.model.user.User;
16+
import net.luckperms.api.query.QueryOptions;
1717

1818
public class LuckPermsHandle {
1919
@Getter
20-
LuckPerms api = null;
20+
private LuckPerms api;
2121

22+
public void load(AdvancedCorePlugin plugin) {
23+
RegisteredServiceProvider<LuckPerms> provider = Bukkit.getServicesManager().getRegistration(LuckPerms.class);
24+
if (provider != null) {
25+
api = provider.getProvider();
26+
plugin.getLogger().info("Loaded LuckPerms hook!");
27+
}
28+
}
29+
30+
public boolean luckpermsApiLoaded() {
31+
return api != null;
32+
}
33+
34+
/**
35+
* Synchronous permission check.
36+
*
37+
* - If player is online, uses Bukkit (fast). - If player is offline, requires
38+
* LuckPerms User load.
39+
*
40+
* IMPORTANT: This method will NOT block the main thread. If called on the main
41+
* thread for an offline user, it returns false.
42+
*/
2243
public boolean hasPermission(UUID uuid, String permission) {
44+
if (api == null) {
45+
return false;
46+
}
47+
48+
// Handle your "!perm" convention
49+
boolean negate = permission.startsWith("!");
50+
if (negate) {
51+
permission = permission.substring(1);
52+
}
53+
54+
// Online fast path (and best context accuracy)
55+
Player player = Bukkit.getPlayer(uuid);
56+
if (player != null) {
57+
boolean has = player.hasPermission(permission);
58+
return negate ? !has : has;
59+
}
60+
61+
// Offline: do NOT block main thread
62+
if (Bukkit.isPrimaryThread()) {
63+
// If you want: plugin.getLogger().fine(...) here, but you don't have plugin in
64+
// this class right now.
65+
return negate; // treat missing as false, so negation returns true? Usually NOT desired.
66+
// I'd recommend: return false; (see note below)
67+
}
68+
69+
// We're async here, safe to wait briefly
2370
User user = api.getUserManager().getUser(uuid);
2471
if (user == null) {
25-
CompletableFuture<User> loadedUser = api.getUserManager().loadUser(uuid);
2672
try {
27-
user = loadedUser.get(10, TimeUnit.SECONDS);
28-
} catch (InterruptedException | ExecutionException | TimeoutException e) {
29-
e.printStackTrace();
73+
user = api.getUserManager().loadUser(uuid).get(10, TimeUnit.SECONDS);
74+
} catch (Exception e) {
3075
return false;
3176
}
3277
}
33-
return user.getCachedData().getPermissionData().checkPermission(permission).asBoolean();
78+
79+
boolean has = checkUserPermission(user, permission, null);
80+
return negate ? !has : has;
3481
}
3582

36-
public void load(AdvancedCorePlugin plugin) {
37-
RegisteredServiceProvider<LuckPerms> provider = Bukkit.getServicesManager().getRegistration(LuckPerms.class);
38-
if (provider != null) {
39-
api = provider.getProvider();
40-
plugin.getLogger().info("Loaded LuckPerms hook!");
83+
/**
84+
* Async permission check for offline users. Safe to call from the main thread.
85+
*/
86+
public CompletableFuture<Boolean> hasPermissionAsync(UUID uuid, String permission) {
87+
if (api == null) {
88+
return CompletableFuture.completedFuture(false);
4189
}
90+
91+
boolean negate = permission.startsWith("!");
92+
if (negate) {
93+
permission = permission.substring(1);
94+
}
95+
96+
// Online fast path
97+
Player player = Bukkit.getPlayer(uuid);
98+
if (player != null) {
99+
boolean has = player.hasPermission(permission);
100+
return CompletableFuture.completedFuture(negate ? !has : has);
101+
}
102+
103+
final String permFinal = permission;
104+
return api.getUserManager().loadUser(uuid).thenApply(user -> {
105+
if (user == null) {
106+
return false;
107+
}
108+
boolean has = checkUserPermission(user, permFinal, null);
109+
return negate ? !has : has;
110+
});
42111
}
43112

44-
public boolean luckpermsApiLoaded() {
45-
return api != null;
113+
private boolean checkUserPermission(User user, String permission, Player playerContext) {
114+
QueryOptions options;
115+
116+
if (playerContext != null) {
117+
options = api.getContextManager().getQueryOptions(playerContext);
118+
} else {
119+
options = api.getContextManager().getStaticQueryOptions();
120+
}
121+
122+
return user.getCachedData().getPermissionData(options).checkPermission(permission).asBoolean();
46123
}
47124
}

AdvancedCore/src/main/java/com/bencodez/advancedcore/api/user/AdvancedCoreUser.java

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -687,19 +687,31 @@ public boolean hasLoggedOnBefore() {
687687
}
688688

689689
public boolean hasPermission(String perm) {
690+
boolean negate = perm != null && perm.startsWith("!");
691+
if (negate) {
692+
perm = perm.substring(1);
693+
}
694+
690695
Player player = getPlayer();
691696
if (!plugin.getOptions().isOnlineMode() && player == null) {
692697
player = Bukkit.getPlayer(getPlayerName());
693698
}
694-
if (player == null) {
695-
plugin.debug("Unable to get player for permission check for " + getPlayerName() + "/" + getUUID());
696-
return false;
699+
700+
// Online fast path
701+
if (player != null) {
702+
boolean has = player.hasPermission(perm);
703+
return negate ? !has : has;
697704
}
698-
if (perm.startsWith("!")) {
699-
perm = perm.substring(1);
700-
return !player.hasPermission(perm);
705+
706+
// Offline path: LuckPerms (if available)
707+
if (plugin.getLuckPermsHandle() != null && plugin.getLuckPermsHandle().luckpermsApiLoaded()) {
708+
boolean has = plugin.getLuckPermsHandle().hasPermission(getJavaUUID(), perm);
709+
return negate ? !has : has;
701710
}
702-
return player.hasPermission(perm);
711+
712+
plugin.debug("Unable to get player for permission check for " + getPlayerName() + "/" + getUUID()
713+
+ " (offline and no LuckPerms hook)");
714+
return false;
703715
}
704716

705717
public boolean isBanned() {
@@ -1198,10 +1210,10 @@ public void setUnClaimedChoice(ArrayList<String> rewards) {
11981210
public void setUserInputMethod(InputMethod method) {
11991211
setInputMethod(method.toString());
12001212
}
1201-
1213+
12021214
@Deprecated
1203-
public void dontCache() {
1204-
userDataFetchMode = UserDataFetchMode.NO_CACHE;
1215+
public void dontCache() {
1216+
userDataFetchMode = UserDataFetchMode.NO_CACHE;
12051217
}
12061218

12071219
/**

0 commit comments

Comments
 (0)