Convert PermissionAttachment to use ConcurrentMap, and do refreshPermissions async

This commit is contained in:
Luck 2016-08-22 22:39:40 +01:00
parent 41fca40a36
commit 7a4135319f
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
6 changed files with 63 additions and 43 deletions

View File

@ -30,6 +30,9 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.*;
import org.bukkit.permissions.PermissionAttachment;
import java.util.concurrent.ConcurrentHashMap;
class BukkitListener extends AbstractListener implements Listener {
private final LPBukkitPlugin plugin;
@ -62,7 +65,15 @@ class BukkitListener extends AbstractListener implements Listener {
if (user instanceof BukkitUser) {
BukkitUser u = (BukkitUser) user;
u.setAttachment(player.addAttachment(plugin));
PermissionAttachment attachment = player.addAttachment(plugin);
try {
BukkitUser.getPermissionsField().set(attachment, new ConcurrentHashMap<>());
} catch (Throwable t) {
t.printStackTrace();
}
u.setAttachment(attachment);
}
user.refreshPermissions();
@ -71,16 +82,19 @@ class BukkitListener extends AbstractListener implements Listener {
@EventHandler
public void onPlayerJoin(PlayerJoinEvent e) {
// Refresh permissions again
plugin.getUserManager().getWorldCache().put(e.getPlayer().getUniqueId(), e.getPlayer().getWorld().getName());
refreshPlayer(e.getPlayer().getUniqueId());
}
@EventHandler
public void onPlayerChangedWorld(PlayerChangedWorldEvent e) {
plugin.getUserManager().getWorldCache().put(e.getPlayer().getUniqueId(), e.getPlayer().getWorld().getName());
refreshPlayer(e.getPlayer().getUniqueId());
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent e) {
plugin.getUserManager().getWorldCache().remove(e.getPlayer().getUniqueId());
onLeave(e.getPlayer().getUniqueId());
}
}

View File

@ -39,7 +39,6 @@ import me.lucko.luckperms.storage.Datastore;
import me.lucko.luckperms.storage.StorageFactory;
import me.lucko.luckperms.tracks.TrackManager;
import me.lucko.luckperms.users.BukkitUserManager;
import me.lucko.luckperms.users.UserManager;
import me.lucko.luckperms.utils.LogFactory;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.Player;
@ -49,13 +48,14 @@ import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@Getter
public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
private final Set<UUID> ignoringLogs = new HashSet<>();
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
private LPConfiguration configuration;
private UserManager userManager;
private BukkitUserManager userManager;
private GroupManager groupManager;
private TrackManager trackManager;
private Datastore datastore;

View File

@ -27,7 +27,6 @@ import lombok.Setter;
import me.lucko.luckperms.LPBukkitPlugin;
import me.lucko.luckperms.api.event.events.UserPermissionRefreshEvent;
import me.lucko.luckperms.api.implementation.internal.UserLink;
import org.bukkit.entity.Player;
import org.bukkit.permissions.PermissionAttachment;
import java.lang.reflect.Field;
@ -36,7 +35,7 @@ import java.util.UUID;
public class BukkitUser extends User {
private static Field permissionsField = null;
private static Field getPermissionsField() {
public static Field getPermissionsField() {
if (permissionsField == null) {
try {
permissionsField = PermissionAttachment.class.getDeclaredField("permissions");
@ -68,46 +67,42 @@ public class BukkitUser extends User {
@SuppressWarnings("unchecked")
@Override
public void refreshPermissions() {
plugin.doSync(() -> {
final Player player = plugin.getServer().getPlayer(plugin.getUuidCache().getExternalUUID(getUuid()));
if (player == null) return;
if (attachment == null) {
getPlugin().getLog().severe("User " + getName() + " does not have a permissions attachment defined.");
}
if (attachment == null) {
getPlugin().getLog().warn("User " + getName() + " does not have a permissions attachment defined.");
setAttachment(player.addAttachment(plugin));
}
// Calculate the permissions that should be applied
Map<String, Boolean> toApply = getLocalPermissions(getPlugin().getConfiguration().getServer(), plugin.getUserManager().getWorldCache().get(getUuid()), null);
// Calculate the permissions that should be applied
Map<String, Boolean> toApply = getLocalPermissions(getPlugin().getConfiguration().getServer(), player.getWorld().getName(), null);
try {
// Existing is thread-safe, hopefully
Map<String, Boolean> existing = (Map<String, Boolean>) getPermissionsField().get(attachment);
try {
Map<String, Boolean> existing = (Map<String, Boolean>) getPermissionsField().get(attachment);
boolean different = false;
if (toApply.size() != existing.size()) {
different = true;
} else {
for (Map.Entry<String, Boolean> e : existing.entrySet()) {
if (toApply.containsKey(e.getKey()) && toApply.get(e.getKey()) == e.getValue()) {
continue;
}
different = true;
break;
boolean different = false;
if (toApply.size() != existing.size()) {
different = true;
} else {
for (Map.Entry<String, Boolean> e : existing.entrySet()) {
if (toApply.containsKey(e.getKey()) && toApply.get(e.getKey()) == e.getValue()) {
continue;
}
different = true;
break;
}
if (!different) return;
// Faster than recalculating permissions after each PermissionAttachment#setPermission
existing.clear();
existing.putAll(toApply);
attachment.getPermissible().recalculatePermissions();
} catch (Exception e) {
e.printStackTrace();
}
plugin.getApiProvider().fireEventAsync(new UserPermissionRefreshEvent(new UserLink(this)));
});
if (!different) return;
// Faster than recalculating permissions after each PermissionAttachment#setPermission
existing.clear();
existing.putAll(toApply);
attachment.getPermissible().recalculatePermissions();
} catch (Exception e) {
e.printStackTrace();
}
plugin.getApiProvider().fireEventAsync(new UserPermissionRefreshEvent(new UserLink(this)));
}
}

View File

@ -22,16 +22,22 @@
package me.lucko.luckperms.users;
import lombok.Getter;
import me.lucko.luckperms.LPBukkitPlugin;
import org.bukkit.entity.Player;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class BukkitUserManager extends UserManager {
private final LPBukkitPlugin plugin;
@Getter
private final Map<UUID, String> worldCache = new ConcurrentHashMap<>();
public BukkitUserManager(LPBukkitPlugin plugin) {
super(plugin);
this.plugin = plugin;

View File

@ -44,13 +44,17 @@ import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Plugin;
import java.io.File;
import java.util.*;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Getter
public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
private final Set<UUID> ignoringLogs = new HashSet<>();
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
private LPConfiguration configuration;
private UserManager userManager;
private GroupManager groupManager;

View File

@ -60,6 +60,7 @@ import org.spongepowered.api.text.Text;
import java.io.File;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@ -79,7 +80,7 @@ public class LPSpongePlugin implements LuckPermsPlugin {
private Scheduler scheduler = Sponge.getScheduler();
private final Set<UUID> ignoringLogs = new HashSet<>();
private final Set<UUID> ignoringLogs = ConcurrentHashMap.newKeySet();
private LPConfiguration configuration;
private UserManager userManager;
private GroupManager groupManager;