Implement locks to hopefully resolve race conditions with I/O - experimental

This commit is contained in:
Luck 2016-10-01 19:03:05 +01:00
parent b5ece8b5bd
commit 4787361e66
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
22 changed files with 1159 additions and 878 deletions

View File

@ -47,7 +47,7 @@ public class BukkitUserManager extends UserManager implements ContextListener<Pl
Player player = plugin.getServer().getPlayer(plugin.getUuidCache().getExternalUUID(u.getUuid())); Player player = plugin.getServer().getPlayer(plugin.getUuidCache().getExternalUUID(u.getUuid()));
if (player != null) { if (player != null) {
if (u.getLpPermissible() != null) { if (u.getLpPermissible() != null) {
Injector.unInject(player); Injector.unInject(player); // TODO is this needed?
u.setLpPermissible(null); u.setLpPermissible(null);
} }
@ -66,18 +66,17 @@ public class BukkitUserManager extends UserManager implements ContextListener<Pl
} }
@Override @Override
public User make(UUID uuid) { public User apply(UserIdentifier id) {
return new BukkitUser(uuid, plugin); BukkitUser user = id.getUsername() == null ?
} new BukkitUser(id.getUuid(), plugin) :
new BukkitUser(id.getUuid(), id.getUsername(), plugin);
@Override giveDefaultIfNeeded(user, false);
public User make(UUID uuid, String username) { return user;
return new BukkitUser(uuid, username, plugin);
} }
@Override @Override
public void updateAllUsers() { public void updateAllUsers() {
// Sometimes called async, so we need to get the players on the Bukkit thread. // Sometimes called async, as we need to get the players on the Bukkit thread.
plugin.doSync(() -> { plugin.doSync(() -> {
Set<UUID> players = plugin.getServer().getOnlinePlayers().stream() Set<UUID> players = plugin.getServer().getOnlinePlayers().stream()
.map(p -> plugin.getUuidCache().getUUID(p.getUniqueId())) .map(p -> plugin.getUuidCache().getUUID(p.getUniqueId()))

View File

@ -45,13 +45,12 @@ public class BungeeUserManager extends UserManager implements ContextListener<Pr
} }
@Override @Override
public User make(UUID uuid) { public User apply(UserIdentifier id) {
return new BungeeUser(uuid, plugin); BungeeUser user = id.getUsername() == null ?
} new BungeeUser(id.getUuid(), plugin) :
new BungeeUser(id.getUuid(), id.getUsername(), plugin);
@Override giveDefaultIfNeeded(user, false);
public User make(UUID uuid, String username) { return user;
return new BungeeUser(uuid, username, plugin);
} }
@Override @Override

View File

@ -32,6 +32,7 @@ import me.lucko.luckperms.api.context.IContextCalculator;
import me.lucko.luckperms.api.event.LPEvent; import me.lucko.luckperms.api.event.LPEvent;
import me.lucko.luckperms.api.event.LPListener; import me.lucko.luckperms.api.event.LPListener;
import me.lucko.luckperms.api.implementation.internal.*; import me.lucko.luckperms.api.implementation.internal.*;
import me.lucko.luckperms.users.UserIdentifier;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
@ -149,7 +150,7 @@ public class ApiProvider implements LuckPermsApi {
@Override @Override
public boolean isUserLoaded(@NonNull UUID uuid) { public boolean isUserLoaded(@NonNull UUID uuid) {
return plugin.getUserManager().isLoaded(uuid); return plugin.getUserManager().isLoaded(UserIdentifier.of(uuid, null));
} }
@Override @Override

View File

@ -63,7 +63,7 @@ public class GroupClone extends SubCommand<Group> {
return CommandResult.LOADING_ERROR; return CommandResult.LOADING_ERROR;
} }
plugin.getGroupManager().copy(group, newGroup); newGroup.setNodes(group.getNodes());
Message.CLONE_SUCCESS.send(sender, group.getName(), newGroup.getName()); Message.CLONE_SUCCESS.send(sender, group.getName(), newGroup.getName());
LogEntry.build().actor(sender).acted(group).action("clone " + newGroup.getName()).build().submit(plugin, sender); LogEntry.build().actor(sender).acted(group).action("clone " + newGroup.getName()).build().submit(plugin, sender);

View File

@ -68,7 +68,7 @@ public class GroupRename extends SubCommand<Group> {
return CommandResult.FAILURE; return CommandResult.FAILURE;
} }
plugin.getGroupManager().copy(group, newGroup); newGroup.setNodes(group.getNodes());
Message.RENAME_SUCCESS.send(sender, group.getName(), newGroup.getName()); Message.RENAME_SUCCESS.send(sender, group.getName(), newGroup.getName());
LogEntry.build().actor(sender).acted(group).action("rename " + newGroup.getName()).build().submit(plugin, sender); LogEntry.build().actor(sender).acted(group).action("rename " + newGroup.getName()).build().submit(plugin, sender);

View File

@ -63,7 +63,7 @@ public class TrackClone extends SubCommand<Track> {
return CommandResult.LOADING_ERROR; return CommandResult.LOADING_ERROR;
} }
plugin.getTrackManager().copy(track, newTrack); newTrack.setGroups(track.getGroups());
Message.CLONE_SUCCESS.send(sender, track.getName(), newTrack.getName()); Message.CLONE_SUCCESS.send(sender, track.getName(), newTrack.getName());
LogEntry.build().actor(sender).acted(track).action("clone " + newTrack.getName()).build().submit(plugin, sender); LogEntry.build().actor(sender).acted(track).action("clone " + newTrack.getName()).build().submit(plugin, sender);

View File

@ -68,7 +68,7 @@ public class TrackRename extends SubCommand<Track> {
return CommandResult.FAILURE; return CommandResult.FAILURE;
} }
plugin.getTrackManager().copy(track, newTrack); newTrack.setGroups(track.getGroups());
Message.RENAME_SUCCESS.send(sender, track.getName(), newTrack.getName()); Message.RENAME_SUCCESS.send(sender, track.getName(), newTrack.getName());
LogEntry.build().actor(sender).acted(track).action("rename " + newTrack.getName()).build().submit(plugin, sender); LogEntry.build().actor(sender).acted(track).action("rename " + newTrack.getName()).build().submit(plugin, sender);

View File

@ -40,6 +40,8 @@ import me.lucko.luckperms.groups.Group;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -74,6 +76,9 @@ public abstract class PermissionHolder {
@Getter @Getter
private Set<Node> transientNodes = ConcurrentHashMap.newKeySet(); private Set<Node> transientNodes = ConcurrentHashMap.newKeySet();
@Getter
private final Lock ioLock = new ReentrantLock();
/** /**
* Returns a Set of nodes in priority order * Returns a Set of nodes in priority order
* @return the holders transient and permanent nodes * @return the holders transient and permanent nodes

View File

@ -30,18 +30,13 @@ import me.lucko.luckperms.utils.AbstractManager;
public class GroupManager extends AbstractManager<String, Group> { public class GroupManager extends AbstractManager<String, Group> {
private final LuckPermsPlugin plugin; private final LuckPermsPlugin plugin;
@Override
public void copy(Group from, Group to) {
to.setNodes(from.getNodes());
}
/** /**
* Makes a new group object * Makes a new group object
* @param name The name of the group * @param name The name of the group
* @return a new {@link Group} object * @return a new {@link Group} object
*/ */
@Override @Override
public Group make(String name) { public Group apply(String name) {
return new Group(name, plugin); return new Group(name, plugin);
} }
} }

View File

@ -28,11 +28,15 @@ import lombok.Cleanup;
import me.lucko.luckperms.LuckPermsPlugin; import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.core.Node; import me.lucko.luckperms.core.Node;
import me.lucko.luckperms.groups.Group; import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.groups.GroupManager;
import me.lucko.luckperms.tracks.Track; import me.lucko.luckperms.tracks.Track;
import me.lucko.luckperms.tracks.TrackManager;
import me.lucko.luckperms.users.User; import me.lucko.luckperms.users.User;
import me.lucko.luckperms.users.UserIdentifier;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import java.util.concurrent.Callable;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static me.lucko.luckperms.core.PermissionHolder.exportToLegacy; import static me.lucko.luckperms.core.PermissionHolder.exportToLegacy;
@ -73,37 +77,41 @@ public class JSONDatastore extends FlatfileDatastore {
@Override @Override
public boolean loadUser(UUID uuid, String username) { public boolean loadUser(UUID uuid, String username) {
User user = plugin.getUserManager().make(uuid, username); User user = plugin.getUserManager().getOrMake(UserIdentifier.of(uuid, username));
boolean success = false; user.getIoLock().lock();
try {
return call(() -> {
File userFile = new File(usersDir, uuid.toString() + ".json"); File userFile = new File(usersDir, uuid.toString() + ".json");
if (userFile.exists()) { if (userFile.exists()) {
final String[] name = new String[1]; return doRead(userFile, reader -> {
success = doRead(userFile, reader -> {
reader.beginObject(); reader.beginObject();
reader.nextName(); // uuid record reader.nextName(); // uuid record
reader.nextString(); // uuid reader.nextString(); // uuid
reader.nextName(); // name record reader.nextName(); // name record
name[0] = reader.nextString(); // name String name1 = reader.nextString(); // name
reader.nextName(); // primaryGroup record reader.nextName(); // primaryGroup record
user.setPrimaryGroup(reader.nextString()); // primaryGroup user.setPrimaryGroup(reader.nextString()); // primaryGroup
reader.nextName(); //perms reader.nextName(); // perms
reader.beginObject(); reader.beginObject();
while (reader.hasNext()) { while (reader.hasNext()) {
String node = reader.nextName(); String node = reader.nextName();
boolean b = reader.nextBoolean(); boolean b = reader.nextBoolean();
user.getNodes().add(Node.fromSerialisedNode(node, b)); user.getNodes().add(Node.fromSerialisedNode(node, b));
} }
reader.endObject();
reader.endObject();
reader.endObject(); boolean save = plugin.getUserManager().giveDefaultIfNeeded(user, false);
reader.endObject();
return true;
});
if (user.getName().equalsIgnoreCase("null")) { if (user.getName().equalsIgnoreCase("null")) {
user.setName(name[0]); user.setName(name1);
} else { } else {
if (!name[0].equals(user.getName())) { if (!name1.equals(user.getName())) {
save = true;
}
}
if (save) {
doWrite(userFile, writer -> { doWrite(userFile, writer -> {
writer.beginObject(); writer.beginObject();
writer.name("uuid").value(user.getUuid().toString()); writer.name("uuid").value(user.getUuid().toString());
@ -119,18 +127,27 @@ public class JSONDatastore extends FlatfileDatastore {
return true; return true;
}); });
} }
} return true;
});
} else { } else {
success = true; if (plugin.getUserManager().shouldSave(user)) {
user.clearNodes();
user.setPrimaryGroup(null);
plugin.getUserManager().giveDefaultIfNeeded(user, false);
}
return true;
}
}, false);
} finally {
user.getIoLock().unlock();
} }
if (success) plugin.getUserManager().updateOrSet(user);
return success;
} }
@Override @Override
public boolean saveUser(User user) { public boolean saveUser(User user) {
user.getIoLock().lock();
try {
return call(() -> {
File userFile = new File(usersDir, user.getUuid().toString() + ".json"); File userFile = new File(usersDir, user.getUuid().toString() + ".json");
if (!plugin.getUserManager().shouldSave(user)) { if (!plugin.getUserManager().shouldSave(user)) {
if (userFile.exists()) { if (userFile.exists()) {
@ -162,11 +179,16 @@ public class JSONDatastore extends FlatfileDatastore {
writer.endObject(); writer.endObject();
return true; return true;
}); });
}, false);
} finally {
user.getIoLock().unlock();
}
} }
@Override @Override
public boolean cleanupUsers() { public boolean cleanupUsers() {
File[] files = usersDir.listFiles((dir, name) -> name.endsWith(".json")); return call(() -> {
File[] files = usersDir.listFiles((dir, name1) -> name1.endsWith(".json"));
if (files == null) return false; if (files == null) return false;
for (File file : files) { for (File file : files) {
@ -205,6 +227,7 @@ public class JSONDatastore extends FlatfileDatastore {
} }
} }
return true; return true;
}, false);
} }
@Override @Override
@ -219,10 +242,29 @@ public class JSONDatastore extends FlatfileDatastore {
@Override @Override
public boolean createAndLoadGroup(String name) { public boolean createAndLoadGroup(String name) {
Group group = plugin.getGroupManager().make(name); Group group = plugin.getGroupManager().getOrMake(name);
group.getIoLock().lock();
try {
return call(() -> {
File groupFile = new File(groupsDir, name + ".json"); File groupFile = new File(groupsDir, name + ".json");
if (!groupFile.exists()) { if (groupFile.exists()) {
return doRead(groupFile, reader -> {
reader.beginObject();
reader.nextName(); // name record
reader.nextString(); // name
reader.nextName(); //perms
reader.beginObject();
while (reader.hasNext()) {
String node = reader.nextName();
boolean b = reader.nextBoolean();
group.getNodes().add(Node.fromSerialisedNode(node, b));
}
reader.endObject();
reader.endObject();
return true;
});
} else {
try { try {
groupFile.createNewFile(); groupFile.createNewFile();
} catch (IOException e) { } catch (IOException e) {
@ -230,7 +272,7 @@ public class JSONDatastore extends FlatfileDatastore {
return false; return false;
} }
boolean success = doWrite(groupFile, writer -> { return doWrite(groupFile, writer -> {
writer.beginObject(); writer.beginObject();
writer.name("name").value(group.getName()); writer.name("name").value(group.getName());
writer.name("perms"); writer.name("perms");
@ -242,59 +284,39 @@ public class JSONDatastore extends FlatfileDatastore {
writer.endObject(); writer.endObject();
return true; return true;
}); });
if (!success) return false;
} }
}, false);
boolean success = doRead(groupFile, reader -> { } finally {
reader.beginObject(); group.getIoLock().unlock();
reader.nextName(); // name record
reader.nextString(); // name
reader.nextName(); //perms
reader.beginObject();
while (reader.hasNext()) {
String node = reader.nextName();
boolean b = reader.nextBoolean();
group.getNodes().add(Node.fromSerialisedNode(node, b));
} }
reader.endObject();
reader.endObject();
return true;
});
if (success) plugin.getGroupManager().updateOrSet(group);
return success;
} }
@Override @Override
public boolean loadGroup(String name) { public boolean loadGroup(String name) {
Group group = plugin.getGroupManager().make(name); Group group = plugin.getGroupManager().getOrMake(name);
group.getIoLock().lock();
try {
return call(() -> {
File groupFile = new File(groupsDir, name + ".json"); File groupFile = new File(groupsDir, name + ".json");
if (!groupFile.exists()) { return groupFile.exists() && doRead(groupFile, reader -> {
return false;
}
boolean success = doRead(groupFile, reader -> {
reader.beginObject(); reader.beginObject();
reader.nextName(); // name record reader.nextName(); // name record
reader.nextString(); // name reader.nextString(); // name
reader.nextName(); //perms reader.nextName(); // perms
reader.beginObject(); reader.beginObject();
while (reader.hasNext()) { while (reader.hasNext()) {
String node = reader.nextName(); String node = reader.nextName();
boolean b = reader.nextBoolean(); boolean b = reader.nextBoolean();
group.getNodes().add(Node.fromSerialisedNode(node, b)); group.getNodes().add(Node.fromSerialisedNode(node, b));
} }
reader.endObject(); reader.endObject();
reader.endObject(); reader.endObject();
return true; return true;
}); });
}, false);
if (success) plugin.getGroupManager().updateOrSet(group); } finally {
return success; group.getIoLock().unlock();
}
} }
@Override @Override
@ -305,13 +327,20 @@ public class JSONDatastore extends FlatfileDatastore {
.map(s -> s.substring(0, s.length() - 5)) .map(s -> s.substring(0, s.length() - 5))
.collect(Collectors.toList()); .collect(Collectors.toList());
plugin.getGroupManager().unloadAll();
groups.forEach(this::loadGroup); groups.forEach(this::loadGroup);
GroupManager gm = plugin.getGroupManager();
gm.getAll().values().stream()
.filter(g -> !groups.contains(g.getName()))
.forEach(gm::unload);
return true; return true;
} }
@Override @Override
public boolean saveGroup(Group group) { public boolean saveGroup(Group group) {
group.getIoLock().lock();
try {
return call(() -> {
File groupFile = new File(groupsDir, group.getName() + ".json"); File groupFile = new File(groupsDir, group.getName() + ".json");
if (!groupFile.exists()) { if (!groupFile.exists()) {
try { try {
@ -334,24 +363,52 @@ public class JSONDatastore extends FlatfileDatastore {
writer.endObject(); writer.endObject();
return true; return true;
}); });
}, false);
} finally {
group.getIoLock().unlock();
}
} }
@Override @Override
public boolean deleteGroup(Group group) { public boolean deleteGroup(Group group) {
group.getIoLock().lock();
try {
return call(() -> {
File groupFile = new File(groupsDir, group.getName() + ".json"); File groupFile = new File(groupsDir, group.getName() + ".json");
if (groupFile.exists()) { if (groupFile.exists()) {
groupFile.delete(); groupFile.delete();
} }
return true; return true;
}, false);
} finally {
group.getIoLock().unlock();
}
} }
@Override @Override
public boolean createAndLoadTrack(String name) { public boolean createAndLoadTrack(String name) {
Track track = plugin.getTrackManager().make(name); Track track = plugin.getTrackManager().getOrMake(name);
List<String> groups = new ArrayList<>(); track.getIoLock().lock();
try {
return call(() -> {
File trackFile = new File(tracksDir, name + ".json"); File trackFile = new File(tracksDir, name + ".json");
if (!trackFile.exists()) { if (trackFile.exists()) {
return doRead(trackFile, reader -> {
reader.beginObject();
reader.nextName(); // name record
reader.nextString(); // name
reader.nextName(); // groups record
reader.beginArray();
List<String> groups = new ArrayList<>();
while (reader.hasNext()) {
groups.add(reader.nextString());
}
track.setGroups(groups);
reader.endArray();
reader.endObject();
return true;
});
} else {
try { try {
trackFile.createNewFile(); trackFile.createNewFile();
} catch (IOException e) { } catch (IOException e) {
@ -359,7 +416,7 @@ public class JSONDatastore extends FlatfileDatastore {
return false; return false;
} }
boolean success = doWrite(trackFile, writer -> { return doWrite(trackFile, writer -> {
writer.beginObject(); writer.beginObject();
writer.name("name").value(track.getName()); writer.name("name").value(track.getName());
writer.name("groups"); writer.name("groups");
@ -371,56 +428,40 @@ public class JSONDatastore extends FlatfileDatastore {
writer.endObject(); writer.endObject();
return true; return true;
}); });
if (!success) return false;
} }
}, false);
boolean success = doRead(trackFile, reader -> { } finally {
reader.beginObject(); track.getIoLock().unlock();
reader.nextName(); // name record
reader.nextString(); // name
reader.nextName(); // groups record
reader.beginArray();
while (reader.hasNext()) {
groups.add(reader.nextString());
} }
reader.endArray();
reader.endObject();
return true;
});
track.setGroups(groups);
if (success) plugin.getTrackManager().updateOrSet(track);
return success;
} }
@Override @Override
public boolean loadTrack(String name) { public boolean loadTrack(String name) {
Track track = plugin.getTrackManager().make(name); Track track = plugin.getTrackManager().getOrMake(name);
List<String> groups = new ArrayList<>(); track.getIoLock().lock();
try {
return call(() -> {
File trackFile = new File(tracksDir, name + ".json"); File trackFile = new File(tracksDir, name + ".json");
if (!trackFile.exists()) { return trackFile.exists() && doRead(trackFile, reader -> {
return false;
}
boolean success = doRead(trackFile, reader -> {
reader.beginObject(); reader.beginObject();
reader.nextName(); // name record reader.nextName(); // name record
reader.nextString(); // name reader.nextString(); // name
reader.nextName(); // groups record reader.nextName(); // groups
reader.beginArray(); reader.beginArray();
List<String> groups = new ArrayList<>();
while (reader.hasNext()) { while (reader.hasNext()) {
groups.add(reader.nextString()); groups.add(reader.nextString());
} }
track.setGroups(groups);
reader.endArray(); reader.endArray();
reader.endObject(); reader.endObject();
return true; return true;
}); });
track.setGroups(groups); }, false);
if (success) plugin.getTrackManager().updateOrSet(track); } finally {
return success; track.getIoLock().unlock();
}
} }
@Override @Override
@ -431,13 +472,20 @@ public class JSONDatastore extends FlatfileDatastore {
.map(s -> s.substring(0, s.length() - 5)) .map(s -> s.substring(0, s.length() - 5))
.collect(Collectors.toList()); .collect(Collectors.toList());
plugin.getTrackManager().unloadAll();
tracks.forEach(this::loadTrack); tracks.forEach(this::loadTrack);
TrackManager tm = plugin.getTrackManager();
tm.getAll().values().stream()
.filter(t -> !tracks.contains(t.getName()))
.forEach(tm::unload);
return true; return true;
} }
@Override @Override
public boolean saveTrack(Track track) { public boolean saveTrack(Track track) {
track.getIoLock().lock();
try {
return call(() -> {
File trackFile = new File(tracksDir, track.getName() + ".json"); File trackFile = new File(tracksDir, track.getName() + ".json");
if (!trackFile.exists()) { if (!trackFile.exists()) {
try { try {
@ -460,15 +508,35 @@ public class JSONDatastore extends FlatfileDatastore {
writer.endObject(); writer.endObject();
return true; return true;
}); });
}, false);
} finally {
track.getIoLock().unlock();
}
} }
@Override @Override
public boolean deleteTrack(Track track) { public boolean deleteTrack(Track track) {
track.getIoLock().lock();
try {
return call(() -> {
File trackFile = new File(tracksDir, track.getName() + ".json"); File trackFile = new File(tracksDir, track.getName() + ".json");
if (trackFile.exists()) { if (trackFile.exists()) {
trackFile.delete(); trackFile.delete();
} }
return true; return true;
}, false);
} finally {
track.getIoLock().unlock();
}
}
private static <T> T call(Callable<T> c, T def) {
try {
return c.call();
} catch (Exception e) {
e.printStackTrace();
return def;
}
} }
interface WriteOperation { interface WriteOperation {

View File

@ -39,6 +39,7 @@ import me.lucko.luckperms.storage.DatastoreConfiguration;
import me.lucko.luckperms.tracks.Track; import me.lucko.luckperms.tracks.Track;
import me.lucko.luckperms.tracks.TrackManager; import me.lucko.luckperms.tracks.TrackManager;
import me.lucko.luckperms.users.User; import me.lucko.luckperms.users.User;
import me.lucko.luckperms.users.UserIdentifier;
import org.bson.Document; import org.bson.Document;
import java.util.*; import java.util.*;
@ -140,41 +141,63 @@ public class MongoDBDatastore extends Datastore {
@Override @Override
public boolean loadUser(UUID uuid, String username) { public boolean loadUser(UUID uuid, String username) {
User user = plugin.getUserManager().make(uuid, username); User user = plugin.getUserManager().getOrMake(UserIdentifier.of(uuid, username));
boolean success = call(() -> { user.getIoLock().lock();
try {
return call(() -> {
MongoCollection<Document> c = database.getCollection("users"); MongoCollection<Document> c = database.getCollection("users");
try (MongoCursor<Document> cursor = c.find(new Document("_id", user.getUuid())).iterator()) { try (MongoCursor<Document> cursor = c.find(new Document("_id", user.getUuid())).iterator()) {
if (cursor.hasNext()) { if (cursor.hasNext()) {
// User exists, let's load.
Document d = cursor.next(); Document d = cursor.next();
user.setPrimaryGroup(d.getString("primaryGroup"));
user.setNodes(revert((Map<String, Boolean>) d.get("perms"))); user.setNodes(revert((Map<String, Boolean>) d.get("perms")));
user.setPrimaryGroup(d.getString("primaryGroup"));
boolean save = plugin.getUserManager().giveDefaultIfNeeded(user, false);
if (user.getName().equalsIgnoreCase("null")) { if (user.getName().equalsIgnoreCase("null")) {
user.setName(d.getString("name")); user.setName(d.getString("name"));
} else { } else {
if (!d.getString("name").equals(user.getName())) { if (!d.getString("name").equals(user.getName())) {
save = true;
}
}
if (save) {
c.replaceOne(new Document("_id", user.getUuid()), fromUser(user)); c.replaceOne(new Document("_id", user.getUuid()), fromUser(user));
} }
} else {
if (plugin.getUserManager().shouldSave(user)) {
user.clearNodes();
user.setPrimaryGroup(null);
plugin.getUserManager().giveDefaultIfNeeded(user, false);
} }
} }
} }
return true; return true;
}, false); }, false);
} finally {
if (success) plugin.getUserManager().updateOrSet(user); user.getIoLock().unlock();
return success; }
} }
@Override @Override
public boolean saveUser(User user) { public boolean saveUser(User user) {
if (!plugin.getUserManager().shouldSave(user)) { if (!plugin.getUserManager().shouldSave(user)) {
user.getIoLock().lock();
try {
return call(() -> { return call(() -> {
MongoCollection<Document> c = database.getCollection("users"); MongoCollection<Document> c = database.getCollection("users");
return c.deleteOne(new Document("_id", user.getUuid())).wasAcknowledged(); return c.deleteOne(new Document("_id", user.getUuid())).wasAcknowledged();
}, false); }, false);
} finally {
user.getIoLock().unlock();
}
} }
user.getIoLock().lock();
try {
return call(() -> { return call(() -> {
MongoCollection<Document> c = database.getCollection("users"); MongoCollection<Document> c = database.getCollection("users");
try (MongoCursor<Document> cursor = c.find(new Document("_id", user.getUuid())).iterator()) { try (MongoCursor<Document> cursor = c.find(new Document("_id", user.getUuid())).iterator()) {
@ -186,6 +209,9 @@ public class MongoDBDatastore extends Datastore {
} }
return true; return true;
}, false); }, false);
} finally {
user.getIoLock().unlock();
}
} }
@Override @Override
@ -214,29 +240,34 @@ public class MongoDBDatastore extends Datastore {
@Override @Override
public boolean createAndLoadGroup(String name) { public boolean createAndLoadGroup(String name) {
Group group = plugin.getGroupManager().make(name); Group group = plugin.getGroupManager().getOrMake(name);
boolean success = call(() -> { group.getIoLock().lock();
try {
return call(() -> {
MongoCollection<Document> c = database.getCollection("groups"); MongoCollection<Document> c = database.getCollection("groups");
try (MongoCursor<Document> cursor = c.find(new Document("_id", group.getName())).iterator()) { try (MongoCursor<Document> cursor = c.find(new Document("_id", group.getName())).iterator()) {
if (!cursor.hasNext()) { if (cursor.hasNext()) {
c.insertOne(fromGroup(group)); // Group exists, let's load.
} else {
Document d = cursor.next(); Document d = cursor.next();
group.setNodes(revert((Map<String, Boolean>) d.get("perms"))); group.setNodes(revert((Map<String, Boolean>) d.get("perms")));
} else {
c.insertOne(fromGroup(group));
} }
} }
return true; return true;
}, false); }, false);
} finally {
if (success) plugin.getGroupManager().updateOrSet(group); group.getIoLock().unlock();
return success; }
} }
@Override @Override
public boolean loadGroup(String name) { public boolean loadGroup(String name) {
Group group = plugin.getGroupManager().make(name); Group group = plugin.getGroupManager().getOrMake(name);
boolean success = call(() -> { group.getIoLock().lock();
try {
return call(() -> {
MongoCollection<Document> c = database.getCollection("groups"); MongoCollection<Document> c = database.getCollection("groups");
try (MongoCursor<Document> cursor = c.find(new Document("_id", group.getName())).iterator()) { try (MongoCursor<Document> cursor = c.find(new Document("_id", group.getName())).iterator()) {
@ -248,51 +279,64 @@ public class MongoDBDatastore extends Datastore {
return false; return false;
} }
}, false); }, false);
} finally {
if (success) plugin.getGroupManager().updateOrSet(group); group.getIoLock().unlock();
return success; }
} }
@Override @Override
public boolean loadAllGroups() { public boolean loadAllGroups() {
List<Group> groups = new ArrayList<>(); List<String> groups = new ArrayList<>();
boolean success = call(() -> { boolean success = call(() -> {
MongoCollection<Document> c = database.getCollection("groups"); MongoCollection<Document> c = database.getCollection("groups");
boolean b = true;
try (MongoCursor<Document> cursor = c.find().iterator()) { try (MongoCursor<Document> cursor = c.find().iterator()) {
while (cursor.hasNext()) { while (cursor.hasNext()) {
Document d = cursor.next(); String name = cursor.next().getString("_id");
Group group = plugin.getGroupManager().make(d.getString("_id")); if (!loadGroup(name)) {
group.setNodes(revert((Map<String, Boolean>) d.get("perms"))); b = false;
groups.add(group); }
groups.add(name);
} }
} }
return b;
return true;
}, false); }, false);
if (success) { if (success) {
GroupManager gm = plugin.getGroupManager(); GroupManager gm = plugin.getGroupManager();
gm.unloadAll(); gm.getAll().values().stream()
groups.forEach(gm::set); .filter(g -> !groups.contains(g.getName()))
.forEach(gm::unload);
} }
return success; return success;
} }
@Override @Override
public boolean saveGroup(Group group) { public boolean saveGroup(Group group) {
group.getIoLock().lock();
try {
return call(() -> { return call(() -> {
MongoCollection<Document> c = database.getCollection("groups"); MongoCollection<Document> c = database.getCollection("groups");
return c.replaceOne(new Document("_id", group.getName()), fromGroup(group)).wasAcknowledged(); return c.replaceOne(new Document("_id", group.getName()), fromGroup(group)).wasAcknowledged();
}, false); }, false);
} finally {
group.getIoLock().unlock();
}
} }
@Override @Override
public boolean deleteGroup(Group group) { public boolean deleteGroup(Group group) {
boolean success = call(() -> { group.getIoLock().lock();
boolean success;
try {
success = call(() -> {
MongoCollection<Document> c = database.getCollection("groups"); MongoCollection<Document> c = database.getCollection("groups");
return c.deleteOne(new Document("_id", group.getName())).wasAcknowledged(); return c.deleteOne(new Document("_id", group.getName())).wasAcknowledged();
}, false); }, false);
} finally {
group.getIoLock().unlock();
}
if (success) plugin.getGroupManager().unload(group); if (success) plugin.getGroupManager().unload(group);
return success; return success;
@ -300,8 +344,10 @@ public class MongoDBDatastore extends Datastore {
@Override @Override
public boolean createAndLoadTrack(String name) { public boolean createAndLoadTrack(String name) {
Track track = plugin.getTrackManager().make(name); Track track = plugin.getTrackManager().getOrMake(name);
boolean success = call(() -> { track.getIoLock().lock();
try {
return call(() -> {
MongoCollection<Document> c = database.getCollection("tracks"); MongoCollection<Document> c = database.getCollection("tracks");
try (MongoCursor<Document> cursor = c.find(new Document("_id", track.getName())).iterator()) { try (MongoCursor<Document> cursor = c.find(new Document("_id", track.getName())).iterator()) {
@ -314,15 +360,17 @@ public class MongoDBDatastore extends Datastore {
} }
return true; return true;
}, false); }, false);
} finally {
if (success) plugin.getTrackManager().updateOrSet(track); track.getIoLock().unlock();
return success; }
} }
@Override @Override
public boolean loadTrack(String name) { public boolean loadTrack(String name) {
Track track = plugin.getTrackManager().make(name); Track track = plugin.getTrackManager().getOrMake(name);
boolean success = call(() -> { track.getIoLock().lock();
try {
return call(() -> {
MongoCollection<Document> c = database.getCollection("tracks"); MongoCollection<Document> c = database.getCollection("tracks");
try (MongoCursor<Document> cursor = c.find(new Document("_id", track.getName())).iterator()) { try (MongoCursor<Document> cursor = c.find(new Document("_id", track.getName())).iterator()) {
@ -334,51 +382,64 @@ public class MongoDBDatastore extends Datastore {
return false; return false;
} }
}, false); }, false);
} finally {
if (success) plugin.getTrackManager().updateOrSet(track); track.getIoLock().unlock();
return success; }
} }
@Override @Override
public boolean loadAllTracks() { public boolean loadAllTracks() {
List<Track> tracks = new ArrayList<>(); List<String> tracks = new ArrayList<>();
boolean success = call(() -> { boolean success = call(() -> {
MongoCollection<Document> c = database.getCollection("tracks"); MongoCollection<Document> c = database.getCollection("tracks");
boolean b = true;
try (MongoCursor<Document> cursor = c.find().iterator()) { try (MongoCursor<Document> cursor = c.find().iterator()) {
while (cursor.hasNext()) { while (cursor.hasNext()) {
Document d = cursor.next(); String name = cursor.next().getString("_id");
Track track = plugin.getTrackManager().make(d.getString("_id")); if (!loadTrack(name)) {
track.setGroups((List<String>) d.get("groups")); b = false;
tracks.add(track); }
tracks.add(name);
} }
} }
return b;
return true;
}, false); }, false);
if (success) { if (success) {
TrackManager tm = plugin.getTrackManager(); TrackManager tm = plugin.getTrackManager();
tm.unloadAll(); tm.getAll().values().stream()
tracks.forEach(tm::set); .filter(t -> !tracks.contains(t.getName()))
.forEach(tm::unload);
} }
return success; return success;
} }
@Override @Override
public boolean saveTrack(Track track) { public boolean saveTrack(Track track) {
track.getIoLock().lock();
try {
return call(() -> { return call(() -> {
MongoCollection<Document> c = database.getCollection("tracks"); MongoCollection<Document> c = database.getCollection("tracks");
return c.replaceOne(new Document("_id", track.getName()), fromTrack(track)).wasAcknowledged(); return c.replaceOne(new Document("_id", track.getName()), fromTrack(track)).wasAcknowledged();
}, false); }, false);
} finally {
track.getIoLock().unlock();
}
} }
@Override @Override
public boolean deleteTrack(Track track) { public boolean deleteTrack(Track track) {
boolean success = call(() -> { track.getIoLock().lock();
boolean success;
try {
success = call(() -> {
MongoCollection<Document> c = database.getCollection("tracks"); MongoCollection<Document> c = database.getCollection("tracks");
return c.deleteOne(new Document("_id", track.getName())).wasAcknowledged(); return c.deleteOne(new Document("_id", track.getName())).wasAcknowledged();
}, false); }, false);
} finally {
track.getIoLock().unlock();
}
if (success) plugin.getTrackManager().unload(track); if (success) plugin.getTrackManager().unload(track);
return success; return success;

View File

@ -33,6 +33,7 @@ import me.lucko.luckperms.storage.Datastore;
import me.lucko.luckperms.tracks.Track; import me.lucko.luckperms.tracks.Track;
import me.lucko.luckperms.tracks.TrackManager; import me.lucko.luckperms.tracks.TrackManager;
import me.lucko.luckperms.users.User; import me.lucko.luckperms.users.User;
import me.lucko.luckperms.users.UserIdentifier;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.sql.Connection; import java.sql.Connection;
@ -142,8 +143,10 @@ abstract class SQLDatastore extends Datastore {
@Override @Override
public boolean loadUser(UUID uuid, String username) { public boolean loadUser(UUID uuid, String username) {
User user = plugin.getUserManager().make(uuid, username); User user = plugin.getUserManager().getOrMake(UserIdentifier.of(uuid, username));
boolean success = runQuery(USER_SELECT, user.getIoLock().lock();
try {
return runQuery(USER_SELECT,
preparedStatement -> preparedStatement.setString(1, user.getUuid().toString()), preparedStatement -> preparedStatement.setString(1, user.getUuid().toString()),
resultSet -> { resultSet -> {
if (resultSet.next()) { if (resultSet.next()) {
@ -152,10 +155,17 @@ abstract class SQLDatastore extends Datastore {
user.setNodes(nodes); user.setNodes(nodes);
user.setPrimaryGroup(resultSet.getString("primary_group")); user.setPrimaryGroup(resultSet.getString("primary_group"));
boolean save = plugin.getUserManager().giveDefaultIfNeeded(user, false);
if (user.getName().equalsIgnoreCase("null")) { if (user.getName().equalsIgnoreCase("null")) {
user.setName(resultSet.getString("name")); user.setName(resultSet.getString("name"));
} else { } else {
if (!resultSet.getString("name").equals(user.getName())) { if (!resultSet.getString("name").equals(user.getName())) {
save = true;
}
}
if (save) {
runQuery(USER_UPDATE, preparedStatement -> { runQuery(USER_UPDATE, preparedStatement -> {
preparedStatement.setString(1, user.getName()); preparedStatement.setString(1, user.getName());
preparedStatement.setString(2, user.getPrimaryGroup()); preparedStatement.setString(2, user.getPrimaryGroup());
@ -163,24 +173,36 @@ abstract class SQLDatastore extends Datastore {
preparedStatement.setString(4, user.getUuid().toString()); preparedStatement.setString(4, user.getUuid().toString());
}); });
} }
} else {
if (plugin.getUserManager().shouldSave(user)) {
user.clearNodes();
user.setPrimaryGroup(null);
plugin.getUserManager().giveDefaultIfNeeded(user, false);
} }
} }
return true; return true;
} }
); );
} finally {
if (success) plugin.getUserManager().updateOrSet(user); user.getIoLock().unlock();
return success; }
} }
@Override @Override
public boolean saveUser(User user) { public boolean saveUser(User user) {
if (!plugin.getUserManager().shouldSave(user)) { if (!plugin.getUserManager().shouldSave(user)) {
user.getIoLock().lock();
try {
return runQuery(USER_DELETE, preparedStatement -> { return runQuery(USER_DELETE, preparedStatement -> {
preparedStatement.setString(1, user.getUuid().toString()); preparedStatement.setString(1, user.getUuid().toString());
}); });
} finally {
user.getIoLock().unlock();
}
} }
user.getIoLock().lock();
try {
return runQuery(USER_SELECT, return runQuery(USER_SELECT,
preparedStatement -> preparedStatement.setString(1, user.getUuid().toString()), preparedStatement -> preparedStatement.setString(1, user.getUuid().toString()),
resultSet -> { resultSet -> {
@ -204,6 +226,9 @@ abstract class SQLDatastore extends Datastore {
} }
} }
); );
} finally {
user.getIoLock().unlock();
}
} }
@Override @Override
@ -230,34 +255,40 @@ abstract class SQLDatastore extends Datastore {
@Override @Override
public boolean createAndLoadGroup(String name) { public boolean createAndLoadGroup(String name) {
Group group = plugin.getGroupManager().make(name); Group group = plugin.getGroupManager().getOrMake(name);
boolean success = runQuery(GROUP_SELECT, group.getIoLock().lock();
try {
return runQuery(GROUP_SELECT,
preparedStatement -> preparedStatement.setString(1, group.getName()), preparedStatement -> preparedStatement.setString(1, group.getName()),
resultSet -> { resultSet -> {
if (!resultSet.next()) { if (resultSet.next()) {
// Group exists, let's load.
Map<String, Boolean> nodes = gson.fromJson(resultSet.getString("perms"), NM_TYPE);
group.setNodes(nodes);
return true;
} else {
return runQuery(GROUP_INSERT, preparedStatement -> { return runQuery(GROUP_INSERT, preparedStatement -> {
preparedStatement.setString(1, group.getName()); preparedStatement.setString(1, group.getName());
preparedStatement.setString(2, gson.toJson(exportToLegacy(group.getNodes()))); preparedStatement.setString(2, gson.toJson(exportToLegacy(group.getNodes())));
}); });
} else {
Map<String, Boolean> nodes = gson.fromJson(resultSet.getString("perms"), NM_TYPE);
group.setNodes(nodes);
return true;
} }
} }
); );
} finally {
if (success) plugin.getGroupManager().updateOrSet(group); group.getIoLock().unlock();
return success; }
} }
@Override @Override
public boolean loadGroup(String name) { public boolean loadGroup(String name) {
Group group = plugin.getGroupManager().make(name); Group group = plugin.getGroupManager().getOrMake(name);
boolean success = runQuery(GROUP_SELECT, group.getIoLock().lock();
try {
return runQuery(GROUP_SELECT,
preparedStatement -> preparedStatement.setString(1, name), preparedStatement -> preparedStatement.setString(1, name),
resultSet -> { resultSet -> {
if (resultSet.next()) { if (resultSet.next()) {
// Group exists, let's load.
Map<String, Boolean> nodes = gson.fromJson(resultSet.getString("perms"), NM_TYPE); Map<String, Boolean> nodes = gson.fromJson(resultSet.getString("perms"), NM_TYPE);
group.setNodes(nodes); group.setNodes(nodes);
return true; return true;
@ -265,45 +296,60 @@ abstract class SQLDatastore extends Datastore {
return false; return false;
} }
); );
} finally {
group.getIoLock().unlock();
}
if (success) plugin.getGroupManager().updateOrSet(group);
return success;
} }
@Override @Override
public boolean loadAllGroups() { public boolean loadAllGroups() {
List<Group> groups = new ArrayList<>(); List<String> groups = new ArrayList<>();
boolean success = runQuery(GROUP_SELECT_ALL, resultSet -> { boolean success = runQuery(GROUP_SELECT_ALL, resultSet -> {
boolean b = true;
while (resultSet.next()) { while (resultSet.next()) {
Group group = plugin.getGroupManager().make(resultSet.getString("name")); String name = resultSet.getString("name");
Map<String, Boolean> nodes = gson.fromJson(resultSet.getString("perms"), NM_TYPE); if (!loadGroup(name)) {
group.setNodes(nodes); b = false;
groups.add(group);
} }
return true; groups.add(name);
}
return b;
}); });
if (success) { if (success) {
GroupManager gm = plugin.getGroupManager(); GroupManager gm = plugin.getGroupManager();
gm.unloadAll(); gm.getAll().values().stream()
groups.forEach(gm::set); .filter(g -> !groups.contains(g.getName()))
.forEach(gm::unload);
} }
return success; return success;
} }
@Override @Override
public boolean saveGroup(Group group) { public boolean saveGroup(Group group) {
group.getIoLock().lock();
try {
return runQuery(GROUP_UPDATE, preparedStatement -> { return runQuery(GROUP_UPDATE, preparedStatement -> {
preparedStatement.setString(1, gson.toJson(exportToLegacy(group.getNodes()))); preparedStatement.setString(1, gson.toJson(exportToLegacy(group.getNodes())));
preparedStatement.setString(2, group.getName()); preparedStatement.setString(2, group.getName());
}); });
} finally {
group.getIoLock().unlock();
}
} }
@Override @Override
public boolean deleteGroup(Group group) { public boolean deleteGroup(Group group) {
boolean success = runQuery(GROUP_DELETE, preparedStatement -> { group.getIoLock().lock();
boolean success;
try {
success = runQuery(GROUP_DELETE, preparedStatement -> {
preparedStatement.setString(1, group.getName()); preparedStatement.setString(1, group.getName());
}); });
} finally {
group.getIoLock().unlock();
}
if (success) plugin.getGroupManager().unload(group); if (success) plugin.getGroupManager().unload(group);
return success; return success;
@ -311,30 +357,35 @@ abstract class SQLDatastore extends Datastore {
@Override @Override
public boolean createAndLoadTrack(String name) { public boolean createAndLoadTrack(String name) {
Track track = plugin.getTrackManager().make(name); Track track = plugin.getTrackManager().getOrMake(name);
boolean success = runQuery(TRACK_SELECT, track.getIoLock().lock();
try {
return runQuery(TRACK_SELECT,
preparedStatement -> preparedStatement.setString(1, track.getName()), preparedStatement -> preparedStatement.setString(1, track.getName()),
resultSet -> { resultSet -> {
if (!resultSet.next()) { if (resultSet.next()) {
// Track exists, let's load.
track.setGroups(gson.fromJson(resultSet.getString("groups"), T_TYPE));
return true;
} else {
return runQuery(TRACK_INSERT, preparedStatement -> { return runQuery(TRACK_INSERT, preparedStatement -> {
preparedStatement.setString(1, track.getName()); preparedStatement.setString(1, track.getName());
preparedStatement.setString(2, gson.toJson(track.getGroups())); preparedStatement.setString(2, gson.toJson(track.getGroups()));
}); });
} else {
track.setGroups(gson.fromJson(resultSet.getString("groups"), T_TYPE));
return true;
} }
} }
); );
} finally {
if (success) plugin.getTrackManager().updateOrSet(track); track.getIoLock().unlock();
return success; }
} }
@Override @Override
public boolean loadTrack(String name) { public boolean loadTrack(String name) {
Track track = plugin.getTrackManager().make(name); Track track = plugin.getTrackManager().getOrMake(name);
boolean success = runQuery(TRACK_SELECT, track.getIoLock().lock();
try {
return runQuery(TRACK_SELECT,
preparedStatement -> preparedStatement.setString(1, name), preparedStatement -> preparedStatement.setString(1, name),
resultSet -> { resultSet -> {
if (resultSet.next()) { if (resultSet.next()) {
@ -344,44 +395,59 @@ abstract class SQLDatastore extends Datastore {
return false; return false;
} }
); );
} finally {
if (success) plugin.getTrackManager().updateOrSet(track); track.getIoLock().unlock();
return success; }
} }
@Override @Override
public boolean loadAllTracks() { public boolean loadAllTracks() {
List<Track> tracks = new ArrayList<>(); List<String> tracks = new ArrayList<>();
boolean success = runQuery(TRACK_SELECT_ALL, resultSet -> { boolean success = runQuery(TRACK_SELECT_ALL, resultSet -> {
boolean b = true;
while (resultSet.next()) { while (resultSet.next()) {
Track track = plugin.getTrackManager().make(resultSet.getString("name")); String name = resultSet.getString("name");
track.setGroups(gson.fromJson(resultSet.getString("groups"), T_TYPE)); if (!loadTrack(name)) {
tracks.add(track); b = false;
} }
return true; tracks.add(name);
}
return b;
}); });
if (success) { if (success) {
TrackManager tm = plugin.getTrackManager(); TrackManager tm = plugin.getTrackManager();
tm.unloadAll(); tm.getAll().values().stream()
tracks.forEach(tm::set); .filter(t -> !tracks.contains(t.getName()))
.forEach(tm::unload);
} }
return success; return success;
} }
@Override @Override
public boolean saveTrack(Track track) { public boolean saveTrack(Track track) {
track.getIoLock().lock();
try {
return runQuery(TRACK_UPDATE, preparedStatement -> { return runQuery(TRACK_UPDATE, preparedStatement -> {
preparedStatement.setString(1, gson.toJson(track.getGroups())); preparedStatement.setString(1, gson.toJson(track.getGroups()));
preparedStatement.setString(2, track.getName()); preparedStatement.setString(2, track.getName());
}); });
} finally {
track.getIoLock().unlock();
}
} }
@Override @Override
public boolean deleteTrack(Track track) { public boolean deleteTrack(Track track) {
boolean success = runQuery(TRACK_DELETE, preparedStatement -> { track.getIoLock().lock();
boolean success;
try {
success = runQuery(TRACK_DELETE, preparedStatement -> {
preparedStatement.setString(1, track.getName()); preparedStatement.setString(1, track.getName());
}); });
} finally {
track.getIoLock().unlock();
}
if (success) plugin.getTrackManager().unload(track); if (success) plugin.getTrackManager().unload(track);
return success; return success;

View File

@ -26,13 +26,17 @@ import lombok.Cleanup;
import me.lucko.luckperms.LuckPermsPlugin; import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.core.Node; import me.lucko.luckperms.core.Node;
import me.lucko.luckperms.groups.Group; import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.groups.GroupManager;
import me.lucko.luckperms.tracks.Track; import me.lucko.luckperms.tracks.Track;
import me.lucko.luckperms.tracks.TrackManager;
import me.lucko.luckperms.users.User; import me.lucko.luckperms.users.User;
import me.lucko.luckperms.users.UserIdentifier;
import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import java.util.concurrent.Callable;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static me.lucko.luckperms.core.PermissionHolder.exportToLegacy; import static me.lucko.luckperms.core.PermissionHolder.exportToLegacy;
@ -76,45 +80,60 @@ public class YAMLDatastore extends FlatfileDatastore {
@Override @Override
public boolean loadUser(UUID uuid, String username) { public boolean loadUser(UUID uuid, String username) {
User user = plugin.getUserManager().make(uuid, username); User user = plugin.getUserManager().getOrMake(UserIdentifier.of(uuid, username));
boolean success = false; user.getIoLock().lock();
try {
return call(() -> {
File userFile = new File(usersDir, uuid.toString() + ".yml"); File userFile = new File(usersDir, uuid.toString() + ".yml");
if (userFile.exists()) { if (userFile.exists()) {
final String[] name = {null}; return doRead(userFile, values -> {
success = doRead(userFile, values -> { // User exists, let's load.
name[0] = (String) values.get("name"); String name = (String) values.get("name");
user.setPrimaryGroup((String) values.get("primary-group")); user.setPrimaryGroup((String) values.get("primary-group"));
Map<String, Boolean> perms = (Map<String, Boolean>) values.get("perms"); Map<String, Boolean> perms = (Map<String, Boolean>) values.get("perms");
for (Map.Entry<String, Boolean> e : perms.entrySet()) { for (Map.Entry<String, Boolean> e : perms.entrySet()) {
user.getNodes().add(Node.fromSerialisedNode(e.getKey(), e.getValue())); user.getNodes().add(Node.fromSerialisedNode(e.getKey(), e.getValue()));
} }
return true;
}); boolean save = plugin.getUserManager().giveDefaultIfNeeded(user, false);
if (user.getName().equalsIgnoreCase("null")) { if (user.getName().equalsIgnoreCase("null")) {
user.setName(name[0]); user.setName(name);
} else { } else {
if (!name[0].equals(user.getName())) { if (!name.equals(user.getName())) {
Map<String, Object> values = new HashMap<>(); save = true;
values.put("uuid", user.getUuid().toString());
values.put("name", user.getName());
values.put("primary-group", user.getPrimaryGroup());
values.put("perms", exportToLegacy(user.getNodes()));
doWrite(userFile, values);
} }
} }
} else { if (save) {
success = true; Map<String, Object> data = new HashMap<>();
data.put("uuid", user.getUuid().toString());
data.put("name", user.getName());
data.put("primary-group", user.getPrimaryGroup());
data.put("perms", exportToLegacy(user.getNodes()));
doWrite(userFile, data);
}
return true;
});
} else {
if (plugin.getUserManager().shouldSave(user)) {
user.clearNodes();
user.setPrimaryGroup(null);
plugin.getUserManager().giveDefaultIfNeeded(user, false);
}
return true;
}
}, false);
} finally {
user.getIoLock().unlock();
} }
if (success) plugin.getUserManager().updateOrSet(user);
return success;
} }
@Override @Override
public boolean saveUser(User user) { public boolean saveUser(User user) {
user.getIoLock().lock();
try {
return call(() -> {
File userFile = new File(usersDir, user.getUuid().toString() + ".yml"); File userFile = new File(usersDir, user.getUuid().toString() + ".yml");
if (!plugin.getUserManager().shouldSave(user)) { if (!plugin.getUserManager().shouldSave(user)) {
if (userFile.exists()) { if (userFile.exists()) {
@ -138,11 +157,16 @@ public class YAMLDatastore extends FlatfileDatastore {
values.put("primary-group", user.getPrimaryGroup()); values.put("primary-group", user.getPrimaryGroup());
values.put("perms", exportToLegacy(user.getNodes())); values.put("perms", exportToLegacy(user.getNodes()));
return doWrite(userFile, values); return doWrite(userFile, values);
}, false);
} finally {
user.getIoLock().unlock();
}
} }
@Override @Override
public boolean cleanupUsers() { public boolean cleanupUsers() {
File[] files = usersDir.listFiles((dir, name) -> name.endsWith(".yml")); return call(() -> {
File[] files = usersDir.listFiles((dir, name1) -> name1.endsWith(".yml"));
if (files == null) return false; if (files == null) return false;
for (File file : files) { for (File file : files) {
@ -166,6 +190,7 @@ public class YAMLDatastore extends FlatfileDatastore {
} }
} }
return true; return true;
}, false);
} }
@Override @Override
@ -180,10 +205,20 @@ public class YAMLDatastore extends FlatfileDatastore {
@Override @Override
public boolean createAndLoadGroup(String name) { public boolean createAndLoadGroup(String name) {
Group group = plugin.getGroupManager().make(name); Group group = plugin.getGroupManager().getOrMake(name);
group.getIoLock().lock();
try {
return call(() -> {
File groupFile = new File(groupsDir, name + ".yml"); File groupFile = new File(groupsDir, name + ".yml");
if (!groupFile.exists()) { if (groupFile.exists()) {
return doRead(groupFile, values -> {
Map<String, Boolean> perms = (Map<String, Boolean>) values.get("perms");
for (Map.Entry<String, Boolean> e : perms.entrySet()) {
group.getNodes().add(Node.fromSerialisedNode(e.getKey(), e.getValue()));
}
return true;
});
} else {
try { try {
groupFile.createNewFile(); groupFile.createNewFile();
} catch (IOException e) { } catch (IOException e) {
@ -194,34 +229,22 @@ public class YAMLDatastore extends FlatfileDatastore {
Map<String, Object> values = new HashMap<>(); Map<String, Object> values = new HashMap<>();
values.put("name", group.getName()); values.put("name", group.getName());
values.put("perms", exportToLegacy(group.getNodes())); values.put("perms", exportToLegacy(group.getNodes()));
return doWrite(groupFile, values);
if (!doWrite(groupFile, values)) {
return false;
} }
}, false);
} finally {
group.getIoLock().unlock();
} }
boolean success = doRead(groupFile, values -> {
Map<String, Boolean> perms = (Map<String, Boolean>) values.get("perms");
for (Map.Entry<String, Boolean> e : perms.entrySet()) {
group.getNodes().add(Node.fromSerialisedNode(e.getKey(), e.getValue()));
}
return true;
});
if (success) plugin.getGroupManager().updateOrSet(group);
return success;
} }
@Override @Override
public boolean loadGroup(String name) { public boolean loadGroup(String name) {
Group group = plugin.getGroupManager().make(name); Group group = plugin.getGroupManager().getOrMake(name);
group.getIoLock().lock();
try {
return call(() -> {
File groupFile = new File(groupsDir, name + ".yml"); File groupFile = new File(groupsDir, name + ".yml");
if (!groupFile.exists()) { return groupFile.exists() && doRead(groupFile, values -> {
return false;
}
boolean success = doRead(groupFile, values -> {
Map<String, Boolean> perms = (Map<String, Boolean>) values.get("perms"); Map<String, Boolean> perms = (Map<String, Boolean>) values.get("perms");
for (Map.Entry<String, Boolean> e : perms.entrySet()) { for (Map.Entry<String, Boolean> e : perms.entrySet()) {
group.getNodes().add(Node.fromSerialisedNode(e.getKey(), e.getValue())); group.getNodes().add(Node.fromSerialisedNode(e.getKey(), e.getValue()));
@ -229,8 +252,10 @@ public class YAMLDatastore extends FlatfileDatastore {
return true; return true;
}); });
if (success) plugin.getGroupManager().updateOrSet(group); }, false);
return success; } finally {
group.getIoLock().unlock();
}
} }
@Override @Override
@ -241,13 +266,20 @@ public class YAMLDatastore extends FlatfileDatastore {
.map(s -> s.substring(0, s.length() - 4)) .map(s -> s.substring(0, s.length() - 4))
.collect(Collectors.toList()); .collect(Collectors.toList());
plugin.getGroupManager().unloadAll();
groups.forEach(this::loadGroup); groups.forEach(this::loadGroup);
GroupManager gm = plugin.getGroupManager();
gm.getAll().values().stream()
.filter(g -> !groups.contains(g.getName()))
.forEach(gm::unload);
return true; return true;
} }
@Override @Override
public boolean saveGroup(Group group) { public boolean saveGroup(Group group) {
group.getIoLock().lock();
try {
return call(() -> {
File groupFile = new File(groupsDir, group.getName() + ".yml"); File groupFile = new File(groupsDir, group.getName() + ".yml");
if (!groupFile.exists()) { if (!groupFile.exists()) {
try { try {
@ -262,24 +294,41 @@ public class YAMLDatastore extends FlatfileDatastore {
values.put("name", group.getName()); values.put("name", group.getName());
values.put("perms", exportToLegacy(group.getNodes())); values.put("perms", exportToLegacy(group.getNodes()));
return doWrite(groupFile, values); return doWrite(groupFile, values);
}, false);
} finally {
group.getIoLock().unlock();
}
} }
@Override @Override
public boolean deleteGroup(Group group) { public boolean deleteGroup(Group group) {
group.getIoLock().lock();
try {
return call(() -> {
File groupFile = new File(groupsDir, group.getName() + ".yml"); File groupFile = new File(groupsDir, group.getName() + ".yml");
if (groupFile.exists()) { if (groupFile.exists()) {
groupFile.delete(); groupFile.delete();
} }
return true; return true;
}, false);
} finally {
group.getIoLock().unlock();
}
} }
@Override @Override
public boolean createAndLoadTrack(String name) { public boolean createAndLoadTrack(String name) {
Track track = plugin.getTrackManager().make(name); Track track = plugin.getTrackManager().getOrMake(name);
List<String> groups = new ArrayList<>(); track.getIoLock().lock();
try {
return call(() -> {
File trackFile = new File(tracksDir, name + ".yml"); File trackFile = new File(tracksDir, name + ".yml");
if (!trackFile.exists()) { if (trackFile.exists()) {
return doRead(trackFile, values -> {
track.setGroups((List<String>) values.get("groups"));
return true;
});
} else {
try { try {
trackFile.createNewFile(); trackFile.createNewFile();
} catch (IOException e) { } catch (IOException e) {
@ -291,39 +340,29 @@ public class YAMLDatastore extends FlatfileDatastore {
values.put("name", track.getName()); values.put("name", track.getName());
values.put("groups", track.getGroups()); values.put("groups", track.getGroups());
if (!doWrite(trackFile, values)) { return doWrite(trackFile, values);
return false;
} }
}, false);
} finally {
track.getIoLock().unlock();
} }
boolean success = doRead(trackFile, values -> {
groups.addAll((List<String>) values.get("groups"));
return true;
});
track.setGroups(groups);
if (success) plugin.getTrackManager().updateOrSet(track);
return success;
} }
@Override @Override
public boolean loadTrack(String name) { public boolean loadTrack(String name) {
Track track = plugin.getTrackManager().make(name); Track track = plugin.getTrackManager().getOrMake(name);
List<String> groups = new ArrayList<>(); track.getIoLock().lock();
try {
return call(() -> {
File trackFile = new File(tracksDir, name + ".yml"); File trackFile = new File(tracksDir, name + ".yml");
if (!trackFile.exists()) { return trackFile.exists() && doRead(trackFile, values -> {
return false; track.setGroups((List<String>) values.get("groups"));
}
boolean success = doRead(trackFile, values -> {
groups.addAll((List<String>) values.get("groups"));
return true; return true;
}); });
}, false);
track.setGroups(groups); } finally {
if (success) plugin.getTrackManager().updateOrSet(track); track.getIoLock().unlock();
return success; }
} }
@Override @Override
@ -334,13 +373,20 @@ public class YAMLDatastore extends FlatfileDatastore {
.map(s -> s.substring(0, s.length() - 4)) .map(s -> s.substring(0, s.length() - 4))
.collect(Collectors.toList()); .collect(Collectors.toList());
plugin.getTrackManager().unloadAll();
tracks.forEach(this::loadTrack); tracks.forEach(this::loadTrack);
TrackManager tm = plugin.getTrackManager();
tm.getAll().values().stream()
.filter(t -> !tracks.contains(t.getName()))
.forEach(tm::unload);
return true; return true;
} }
@Override @Override
public boolean saveTrack(Track track) { public boolean saveTrack(Track track) {
track.getIoLock().lock();
try {
return call(() -> {
File trackFile = new File(tracksDir, track.getName() + ".yml"); File trackFile = new File(tracksDir, track.getName() + ".yml");
if (!trackFile.exists()) { if (!trackFile.exists()) {
try { try {
@ -355,15 +401,35 @@ public class YAMLDatastore extends FlatfileDatastore {
values.put("name", track.getName()); values.put("name", track.getName());
values.put("groups", track.getGroups()); values.put("groups", track.getGroups());
return doWrite(trackFile, values); return doWrite(trackFile, values);
}, false);
} finally {
track.getIoLock().unlock();
}
} }
@Override @Override
public boolean deleteTrack(Track track) { public boolean deleteTrack(Track track) {
track.getIoLock().lock();
try {
return call(() -> {
File trackFile = new File(tracksDir, track.getName() + ".yml"); File trackFile = new File(tracksDir, track.getName() + ".yml");
if (trackFile.exists()) { if (trackFile.exists()) {
trackFile.delete(); trackFile.delete();
} }
return true; return true;
}, false);
} finally {
track.getIoLock().unlock();
}
}
private static <T> T call(Callable<T> c, T def) {
try {
return c.call();
} catch (Exception e) {
e.printStackTrace();
return def;
}
} }
interface ReadOperation { interface ReadOperation {

View File

@ -34,6 +34,8 @@ import me.lucko.luckperms.utils.Identifiable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ToString @ToString
@EqualsAndHashCode(of = {"name"}) @EqualsAndHashCode(of = {"name"})
@ -51,6 +53,9 @@ public class Track implements Identifiable<String> {
*/ */
private List<String> groups = Collections.synchronizedList(new ArrayList<>()); private List<String> groups = Collections.synchronizedList(new ArrayList<>());
@Getter
private final Lock ioLock = new ReentrantLock();
@Override @Override
public String getId() { public String getId() {
return name; return name;

View File

@ -40,18 +40,13 @@ public class TrackManager extends AbstractManager<String, Track> {
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} }
@Override
public void copy(Track from, Track to) {
to.setGroups(from.getGroups());
}
/** /**
* Makes a new track object * Makes a new track object
* @param name The name of the track * @param name The name of the track
* @return a new {@link Track} object * @return a new {@link Track} object
*/ */
@Override @Override
public Track make(String name) { public Track apply(String name) {
return new Track(name); return new Track(name);
} }
} }

View File

@ -40,7 +40,7 @@ import java.util.UUID;
@ToString(of = {"uuid"}) @ToString(of = {"uuid"})
@EqualsAndHashCode(of = {"uuid"}, callSuper = false) @EqualsAndHashCode(of = {"uuid"}, callSuper = false)
public abstract class User extends PermissionHolder implements Identifiable<UUID> { public abstract class User extends PermissionHolder implements Identifiable<UserIdentifier> {
/** /**
* The users Mojang UUID * The users Mojang UUID
@ -75,8 +75,8 @@ public abstract class User extends PermissionHolder implements Identifiable<UUID
} }
@Override @Override
public UUID getId() { public UserIdentifier getId() {
return uuid; return UserIdentifier.of(uuid, name);
} }
/** /**

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.users;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
import me.lucko.luckperms.utils.Identifiable;
import java.util.UUID;
@Getter
@ToString
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class UserIdentifier implements Identifiable<UUID> {
public static UserIdentifier of(UUID uuid, String username) {
return new UserIdentifier(uuid, username);
}
private final UUID uuid;
private final String username;
@Override
public UUID getId() {
return getUuid();
}
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof UserIdentifier)) return false;
final UserIdentifier other = (UserIdentifier) o;
final Object thisUuid = this.getUuid();
final Object otherUuid = other.getUuid();
return thisUuid == null ? otherUuid == null : thisUuid.equals(otherUuid);
}
public int hashCode() {
return 59 + (this.getUuid() == null ? 43 : this.getUuid().hashCode());
}
}

View File

@ -34,7 +34,7 @@ import java.util.NoSuchElementException;
import java.util.UUID; import java.util.UUID;
@RequiredArgsConstructor @RequiredArgsConstructor
public abstract class UserManager extends AbstractManager<UUID, User> { public abstract class UserManager extends AbstractManager<UserIdentifier, User> {
private final LuckPermsPlugin plugin; private final LuckPermsPlugin plugin;
/** /**
@ -53,26 +53,15 @@ public abstract class UserManager extends AbstractManager<UUID, User> {
} }
} }
@Override public User get(UUID uuid) {
public void preSet(User u) { return get(UserIdentifier.of(uuid, null));
giveDefaultIfNeeded(u, true);
}
@Override
public void copy(User from, User to) {
if (from.getPrimaryGroup() != null) {
// This isn't just a black user. we shouldn't override in that case.
to.setNodes(from.getNodes());
to.setPrimaryGroup(from.getPrimaryGroup());
}
to.refreshPermissions();
} }
/** /**
* Set a user to the default group * Set a user to the default group
* @param user the user to give to * @param user the user to give to
*/ */
public void giveDefaultIfNeeded(User user, boolean save) { public boolean giveDefaultIfNeeded(User user, boolean save) {
boolean hasGroup = false; boolean hasGroup = false;
if (user.getPrimaryGroup() != null && !user.getPrimaryGroup().isEmpty()) { if (user.getPrimaryGroup() != null && !user.getPrimaryGroup().isEmpty()) {
@ -84,7 +73,10 @@ public abstract class UserManager extends AbstractManager<UUID, User> {
} }
} }
if (!hasGroup) { if (hasGroup) {
return false;
}
user.setPrimaryGroup("default"); user.setPrimaryGroup("default");
try { try {
user.setPermission("group.default", true); user.setPermission("group.default", true);
@ -95,7 +87,8 @@ public abstract class UserManager extends AbstractManager<UUID, User> {
if (save) { if (save) {
plugin.getDatastore().saveUser(user, Callback.empty()); plugin.getDatastore().saveUser(user, Callback.empty());
} }
}
return true;
} }
public boolean shouldSave(User user) { public boolean shouldSave(User user) {
@ -132,14 +125,6 @@ public abstract class UserManager extends AbstractManager<UUID, User> {
*/ */
public abstract void cleanup(User user); public abstract void cleanup(User user);
/**
* Makes a new {@link User} object
* @param uuid The UUID of the user
* @param username The username of the user
* @return a new {@link User} object
*/
public abstract User make(UUID uuid, String username);
/** /**
* Reloads the data of all online users * Reloads the data of all online users
*/ */

View File

@ -26,18 +26,32 @@ import com.google.common.collect.ImmutableMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
/** /**
* An abstract manager class * An abstract manager class
* @param <I> the class used to identify each object held in this manager * @param <I> the class used to identify each object held in this manager
* @param <T> the class this manager is "managing" * @param <T> the class this manager is "managing"
*/ */
public abstract class AbstractManager<I, T extends Identifiable<I>> { public abstract class AbstractManager<I, T extends Identifiable<I>> implements Function<I, T> {
private final Map<I, T> objects = new HashMap<>(); private final Map<I, T> objects = new HashMap<>();
public final Map<I, T> getAll() { public final Map<I, T> getAll() {
Map<I, T> map;
synchronized (objects) { synchronized (objects) {
return ImmutableMap.copyOf(objects); map = ImmutableMap.copyOf(objects);
}
return map;
}
/**
* Get an object by id
* @param id The id to search by
* @return a {@link T} object if the object is loaded or makes and returns a new object
*/
public final T getOrMake(I id) {
synchronized (objects) {
return objects.computeIfAbsent(id, this);
} }
} }
@ -52,38 +66,6 @@ public abstract class AbstractManager<I, T extends Identifiable<I>> {
} }
} }
/**
* Add a object to the loaded objects map
* @param t The object to add
*/
public final void set(T t) {
preSet(t);
synchronized (objects) {
objects.put(t.getId(), t);
}
}
protected void preSet(T t) {
}
/**
* Updates (or sets if the object wasn't already loaded) an object in the objects map
* @param t The object to update or set
*/
public final void updateOrSet(T t) {
synchronized (objects) {
if (!isLoaded(t.getId())) {
// The object isn't already loaded
set(t);
} else {
copy(t, objects.get(t.getId()));
}
}
}
public abstract void copy(T from, T to);
/** /**
* Check to see if a object is loaded or not * Check to see if a object is loaded or not
* @param id The id of the object * @param id The id of the object
@ -101,9 +83,11 @@ public abstract class AbstractManager<I, T extends Identifiable<I>> {
*/ */
public final void unload(T t) { public final void unload(T t) {
if (t != null) { if (t != null) {
preUnload(t);
synchronized (objects) { synchronized (objects) {
objects.remove(t.getId()); objects.computeIfPresent(t.getId(), (i, t1) -> {
preUnload(t1);
return null;
});
} }
} }
} }
@ -117,15 +101,9 @@ public abstract class AbstractManager<I, T extends Identifiable<I>> {
*/ */
public final void unloadAll() { public final void unloadAll() {
synchronized (objects) { synchronized (objects) {
objects.values().forEach(this::preUnload);
objects.clear(); objects.clear();
} }
} }
/**
* Makes a new object
* @param id the id of the object
* @return a new {@link T} object
*/
public abstract T make(I id);
} }

View File

@ -28,6 +28,7 @@ import me.lucko.luckperms.api.sponge.LuckPermsService;
import me.lucko.luckperms.api.sponge.LuckPermsUserSubject; import me.lucko.luckperms.api.sponge.LuckPermsUserSubject;
import me.lucko.luckperms.api.sponge.simple.SimpleCollection; import me.lucko.luckperms.api.sponge.simple.SimpleCollection;
import me.lucko.luckperms.users.User; import me.lucko.luckperms.users.User;
import me.lucko.luckperms.users.UserIdentifier;
import me.lucko.luckperms.users.UserManager; import me.lucko.luckperms.users.UserManager;
import org.spongepowered.api.service.context.Context; import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.PermissionService; import org.spongepowered.api.service.permission.PermissionService;
@ -62,7 +63,7 @@ public class UserCollection implements SubjectCollection {
private void load(UUID uuid) { private void load(UUID uuid) {
UUID internal = service.getPlugin().getUuidCache().getUUID(uuid); UUID internal = service.getPlugin().getUuidCache().getUUID(uuid);
if (!manager.isLoaded(internal)) { if (!manager.isLoaded(UserIdentifier.of(uuid, null))) {
return; return;
} }
@ -82,7 +83,7 @@ public class UserCollection implements SubjectCollection {
return users.get(u); return users.get(u);
} }
if (manager.isLoaded(u)) { if (manager.isLoaded(UserIdentifier.of(u, null))) {
load(u); load(u);
return users.get(u); return users.get(u);
} }
@ -108,7 +109,7 @@ public class UserCollection implements SubjectCollection {
public boolean hasRegistered(@NonNull String id) { public boolean hasRegistered(@NonNull String id) {
try { try {
UUID u = UUID.fromString(id); UUID u = UUID.fromString(id);
return manager.isLoaded(service.getPlugin().getUuidCache().getUUID(u)); return manager.isLoaded(UserIdentifier.of(service.getPlugin().getUuidCache().getUUID(u), null));
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
User user = manager.get(id); User user = manager.get(id);
return user != null; return user != null;

View File

@ -46,13 +46,12 @@ public class SpongeUserManager extends UserManager implements ContextListener<Pl
} }
@Override @Override
public User make(UUID uuid) { public User apply(UserIdentifier id) {
return new SpongeUser(uuid, plugin); SpongeUser user = id.getUsername() == null ?
} new SpongeUser(id.getUuid(), plugin) :
new SpongeUser(id.getUuid(), id.getUsername(), plugin);
@Override giveDefaultIfNeeded(user, false);
public User make(UUID uuid, String username) { return user;
return new SpongeUser(uuid, username, plugin);
} }
@Override @Override

View File

@ -24,8 +24,6 @@ package me.lucko.luckperms.users;
import me.lucko.luckperms.LuckPermsPlugin; import me.lucko.luckperms.LuckPermsPlugin;
import java.util.UUID;
public class StandaloneUserManager extends UserManager { public class StandaloneUserManager extends UserManager {
private final LuckPermsPlugin plugin; private final LuckPermsPlugin plugin;
@ -41,13 +39,12 @@ public class StandaloneUserManager extends UserManager {
} }
@Override @Override
public User make(UUID id) { public User apply(UserIdentifier id) {
return new StandaloneUser(id, plugin); StandaloneUser user = id.getUsername() == null ?
} new StandaloneUser(id.getUuid(), plugin) :
new StandaloneUser(id.getUuid(), id.getUsername(), plugin);
@Override giveDefaultIfNeeded(user, false);
public User make(UUID uuid, String username) { return user;
return new StandaloneUser(uuid, username, plugin);
} }
@Override @Override