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()));
if (player != null) {
if (u.getLpPermissible() != null) {
Injector.unInject(player);
Injector.unInject(player); // TODO is this needed?
u.setLpPermissible(null);
}
@ -66,18 +66,17 @@ public class BukkitUserManager extends UserManager implements ContextListener<Pl
}
@Override
public User make(UUID uuid) {
return new BukkitUser(uuid, plugin);
}
@Override
public User make(UUID uuid, String username) {
return new BukkitUser(uuid, username, plugin);
public User apply(UserIdentifier id) {
BukkitUser user = id.getUsername() == null ?
new BukkitUser(id.getUuid(), plugin) :
new BukkitUser(id.getUuid(), id.getUsername(), plugin);
giveDefaultIfNeeded(user, false);
return user;
}
@Override
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(() -> {
Set<UUID> players = plugin.getServer().getOnlinePlayers().stream()
.map(p -> plugin.getUuidCache().getUUID(p.getUniqueId()))

View File

@ -45,13 +45,12 @@ public class BungeeUserManager extends UserManager implements ContextListener<Pr
}
@Override
public User make(UUID uuid) {
return new BungeeUser(uuid, plugin);
}
@Override
public User make(UUID uuid, String username) {
return new BungeeUser(uuid, username, plugin);
public User apply(UserIdentifier id) {
BungeeUser user = id.getUsername() == null ?
new BungeeUser(id.getUuid(), plugin) :
new BungeeUser(id.getUuid(), id.getUsername(), plugin);
giveDefaultIfNeeded(user, false);
return user;
}
@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.LPListener;
import me.lucko.luckperms.api.implementation.internal.*;
import me.lucko.luckperms.users.UserIdentifier;
import java.util.Optional;
import java.util.Set;
@ -149,7 +150,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public boolean isUserLoaded(@NonNull UUID uuid) {
return plugin.getUserManager().isLoaded(uuid);
return plugin.getUserManager().isLoaded(UserIdentifier.of(uuid, null));
}
@Override

View File

@ -63,7 +63,7 @@ public class GroupClone extends SubCommand<Group> {
return CommandResult.LOADING_ERROR;
}
plugin.getGroupManager().copy(group, newGroup);
newGroup.setNodes(group.getNodes());
Message.CLONE_SUCCESS.send(sender, group.getName(), newGroup.getName());
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;
}
plugin.getGroupManager().copy(group, newGroup);
newGroup.setNodes(group.getNodes());
Message.RENAME_SUCCESS.send(sender, group.getName(), newGroup.getName());
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;
}
plugin.getTrackManager().copy(track, newTrack);
newTrack.setGroups(track.getGroups());
Message.CLONE_SUCCESS.send(sender, track.getName(), newTrack.getName());
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;
}
plugin.getTrackManager().copy(track, newTrack);
newTrack.setGroups(track.getGroups());
Message.RENAME_SUCCESS.send(sender, track.getName(), newTrack.getName());
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.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
/**
@ -74,6 +76,9 @@ public abstract class PermissionHolder {
@Getter
private Set<Node> transientNodes = ConcurrentHashMap.newKeySet();
@Getter
private final Lock ioLock = new ReentrantLock();
/**
* Returns a Set of nodes in priority order
* @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> {
private final LuckPermsPlugin plugin;
@Override
public void copy(Group from, Group to) {
to.setNodes(from.getNodes());
}
/**
* Makes a new group object
* @param name The name of the group
* @return a new {@link Group} object
*/
@Override
public Group make(String name) {
public Group apply(String name) {
return new Group(name, plugin);
}
}

View File

@ -28,11 +28,15 @@ import lombok.Cleanup;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.core.Node;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.groups.GroupManager;
import me.lucko.luckperms.tracks.Track;
import me.lucko.luckperms.tracks.TrackManager;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.users.UserIdentifier;
import java.io.*;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import static me.lucko.luckperms.core.PermissionHolder.exportToLegacy;
@ -73,138 +77,157 @@ public class JSONDatastore extends FlatfileDatastore {
@Override
public boolean loadUser(UUID uuid, String username) {
User user = plugin.getUserManager().make(uuid, username);
boolean success = false;
File userFile = new File(usersDir, uuid.toString() + ".json");
if (userFile.exists()) {
final String[] name = new String[1];
success = doRead(userFile, reader -> {
reader.beginObject();
reader.nextName(); // uuid record
reader.nextString(); // uuid
reader.nextName(); // name record
name[0] = reader.nextString(); // name
reader.nextName(); // primaryGroup record
user.setPrimaryGroup(reader.nextString()); // primaryGroup
reader.nextName(); //perms
reader.beginObject();
while (reader.hasNext()) {
String node = reader.nextName();
boolean b = reader.nextBoolean();
user.getNodes().add(Node.fromSerialisedNode(node, b));
}
reader.endObject();
reader.endObject();
return true;
});
if (user.getName().equalsIgnoreCase("null")) {
user.setName(name[0]);
} else {
if (!name[0].equals(user.getName())) {
doWrite(userFile, writer -> {
writer.beginObject();
writer.name("uuid").value(user.getUuid().toString());
writer.name("name").value(user.getName());
writer.name("primaryGroup").value(user.getPrimaryGroup());
writer.name("perms");
writer.beginObject();
for (Map.Entry<String, Boolean> e : exportToLegacy(user.getNodes()).entrySet()) {
writer.name(e.getKey()).value(e.getValue().booleanValue());
User user = plugin.getUserManager().getOrMake(UserIdentifier.of(uuid, username));
user.getIoLock().lock();
try {
return call(() -> {
File userFile = new File(usersDir, uuid.toString() + ".json");
if (userFile.exists()) {
return doRead(userFile, reader -> {
reader.beginObject();
reader.nextName(); // uuid record
reader.nextString(); // uuid
reader.nextName(); // name record
String name1 = reader.nextString(); // name
reader.nextName(); // primaryGroup record
user.setPrimaryGroup(reader.nextString()); // primaryGroup
reader.nextName(); // perms
reader.beginObject();
while (reader.hasNext()) {
String node = reader.nextName();
boolean b = reader.nextBoolean();
user.getNodes().add(Node.fromSerialisedNode(node, b));
}
reader.endObject();
reader.endObject();
boolean save = plugin.getUserManager().giveDefaultIfNeeded(user, false);
if (user.getName().equalsIgnoreCase("null")) {
user.setName(name1);
} else {
if (!name1.equals(user.getName())) {
save = true;
}
}
if (save) {
doWrite(userFile, writer -> {
writer.beginObject();
writer.name("uuid").value(user.getUuid().toString());
writer.name("name").value(user.getName());
writer.name("primaryGroup").value(user.getPrimaryGroup());
writer.name("perms");
writer.beginObject();
for (Map.Entry<String, Boolean> e : exportToLegacy(user.getNodes()).entrySet()) {
writer.name(e.getKey()).value(e.getValue().booleanValue());
}
writer.endObject();
writer.endObject();
return true;
});
}
writer.endObject();
writer.endObject();
return true;
});
} else {
if (plugin.getUserManager().shouldSave(user)) {
user.clearNodes();
user.setPrimaryGroup(null);
plugin.getUserManager().giveDefaultIfNeeded(user, false);
}
return true;
}
}
} else {
success = true;
}, false);
} finally {
user.getIoLock().unlock();
}
if (success) plugin.getUserManager().updateOrSet(user);
return success;
}
@Override
public boolean saveUser(User user) {
File userFile = new File(usersDir, user.getUuid().toString() + ".json");
if (!plugin.getUserManager().shouldSave(user)) {
if (userFile.exists()) {
userFile.delete();
}
return true;
}
user.getIoLock().lock();
try {
return call(() -> {
File userFile = new File(usersDir, user.getUuid().toString() + ".json");
if (!plugin.getUserManager().shouldSave(user)) {
if (userFile.exists()) {
userFile.delete();
}
return true;
}
if (!userFile.exists()) {
try {
userFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
if (!userFile.exists()) {
try {
userFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
return doWrite(userFile, writer -> {
writer.beginObject();
writer.name("uuid").value(user.getUuid().toString());
writer.name("name").value(user.getName());
writer.name("primaryGroup").value(user.getPrimaryGroup());
writer.name("perms");
writer.beginObject();
for (Map.Entry<String, Boolean> e : exportToLegacy(user.getNodes()).entrySet()) {
writer.name(e.getKey()).value(e.getValue().booleanValue());
}
writer.endObject();
writer.endObject();
return true;
});
return doWrite(userFile, writer -> {
writer.beginObject();
writer.name("uuid").value(user.getUuid().toString());
writer.name("name").value(user.getName());
writer.name("primaryGroup").value(user.getPrimaryGroup());
writer.name("perms");
writer.beginObject();
for (Map.Entry<String, Boolean> e : exportToLegacy(user.getNodes()).entrySet()) {
writer.name(e.getKey()).value(e.getValue().booleanValue());
}
writer.endObject();
writer.endObject();
return true;
});
}, false);
} finally {
user.getIoLock().unlock();
}
}
@Override
public boolean cleanupUsers() {
File[] files = usersDir.listFiles((dir, name) -> name.endsWith(".json"));
if (files == null) return false;
return call(() -> {
File[] files = usersDir.listFiles((dir, name1) -> name1.endsWith(".json"));
if (files == null) return false;
for (File file : files) {
Map<String, Boolean> nodes = new HashMap<>();
doRead(file, reader -> {
reader.beginObject();
reader.nextName(); // uuid record
reader.nextString(); // uuid
reader.nextName(); // name record
reader.nextString(); // name
reader.nextName(); // primaryGroup record
reader.nextString(); // primaryGroup
reader.nextName(); //perms
reader.beginObject();
while (reader.hasNext()) {
String node = reader.nextName();
boolean b = reader.nextBoolean();
nodes.put(node, b);
for (File file : files) {
Map<String, Boolean> nodes = new HashMap<>();
doRead(file, reader -> {
reader.beginObject();
reader.nextName(); // uuid record
reader.nextString(); // uuid
reader.nextName(); // name record
reader.nextString(); // name
reader.nextName(); // primaryGroup record
reader.nextString(); // primaryGroup
reader.nextName(); //perms
reader.beginObject();
while (reader.hasNext()) {
String node = reader.nextName();
boolean b = reader.nextBoolean();
nodes.put(node, b);
}
reader.endObject();
reader.endObject();
return true;
});
boolean shouldDelete = false;
if (nodes.size() == 1) {
for (Map.Entry<String, Boolean> e : nodes.entrySet()) {
// There's only one
shouldDelete = e.getKey().equalsIgnoreCase("group.default") && e.getValue();
}
}
reader.endObject();
reader.endObject();
return true;
});
boolean shouldDelete = false;
if (nodes.size() == 1) {
for (Map.Entry<String, Boolean> e : nodes.entrySet()) {
// There's only one
shouldDelete = e.getKey().equalsIgnoreCase("group.default") && e.getValue();
if (shouldDelete) {
file.delete();
}
}
if (shouldDelete) {
file.delete();
}
}
return true;
return true;
}, false);
}
@Override
@ -219,82 +242,81 @@ public class JSONDatastore extends FlatfileDatastore {
@Override
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");
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));
}
File groupFile = new File(groupsDir, name + ".json");
if (!groupFile.exists()) {
try {
groupFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
reader.endObject();
reader.endObject();
return true;
});
} else {
try {
groupFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
boolean success = doWrite(groupFile, writer -> {
writer.beginObject();
writer.name("name").value(group.getName());
writer.name("perms");
writer.beginObject();
for (Map.Entry<String, Boolean> e : exportToLegacy(group.getNodes()).entrySet()) {
writer.name(e.getKey()).value(e.getValue().booleanValue());
return doWrite(groupFile, writer -> {
writer.beginObject();
writer.name("name").value(group.getName());
writer.name("perms");
writer.beginObject();
for (Map.Entry<String, Boolean> e : exportToLegacy(group.getNodes()).entrySet()) {
writer.name(e.getKey()).value(e.getValue().booleanValue());
}
writer.endObject();
writer.endObject();
return true;
});
}
writer.endObject();
writer.endObject();
return true;
});
if (!success) return false;
}, false);
} finally {
group.getIoLock().unlock();
}
boolean success = 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;
});
if (success) plugin.getGroupManager().updateOrSet(group);
return success;
}
@Override
public boolean loadGroup(String name) {
Group group = plugin.getGroupManager().make(name);
File groupFile = new File(groupsDir, name + ".json");
if (!groupFile.exists()) {
return false;
Group group = plugin.getGroupManager().getOrMake(name);
group.getIoLock().lock();
try {
return call(() -> {
File groupFile = new File(groupsDir, name + ".json");
return groupFile.exists() && 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;
});
}, false);
} finally {
group.getIoLock().unlock();
}
boolean success = 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;
});
if (success) plugin.getGroupManager().updateOrSet(group);
return success;
}
@Override
@ -305,122 +327,141 @@ public class JSONDatastore extends FlatfileDatastore {
.map(s -> s.substring(0, s.length() - 5))
.collect(Collectors.toList());
plugin.getGroupManager().unloadAll();
groups.forEach(this::loadGroup);
GroupManager gm = plugin.getGroupManager();
gm.getAll().values().stream()
.filter(g -> !groups.contains(g.getName()))
.forEach(gm::unload);
return true;
}
@Override
public boolean saveGroup(Group group) {
File groupFile = new File(groupsDir, group.getName() + ".json");
if (!groupFile.exists()) {
try {
groupFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
group.getIoLock().lock();
try {
return call(() -> {
File groupFile = new File(groupsDir, group.getName() + ".json");
if (!groupFile.exists()) {
try {
groupFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
return doWrite(groupFile, writer -> {
writer.beginObject();
writer.name("name").value(group.getName());
writer.name("perms");
writer.beginObject();
for (Map.Entry<String, Boolean> e : exportToLegacy(group.getNodes()).entrySet()) {
writer.name(e.getKey()).value(e.getValue().booleanValue());
}
writer.endObject();
writer.endObject();
return true;
});
return doWrite(groupFile, writer -> {
writer.beginObject();
writer.name("name").value(group.getName());
writer.name("perms");
writer.beginObject();
for (Map.Entry<String, Boolean> e : exportToLegacy(group.getNodes()).entrySet()) {
writer.name(e.getKey()).value(e.getValue().booleanValue());
}
writer.endObject();
writer.endObject();
return true;
});
}, false);
} finally {
group.getIoLock().unlock();
}
}
@Override
public boolean deleteGroup(Group group) {
File groupFile = new File(groupsDir, group.getName() + ".json");
if (groupFile.exists()) {
groupFile.delete();
group.getIoLock().lock();
try {
return call(() -> {
File groupFile = new File(groupsDir, group.getName() + ".json");
if (groupFile.exists()) {
groupFile.delete();
}
return true;
}, false);
} finally {
group.getIoLock().unlock();
}
return true;
}
@Override
public boolean createAndLoadTrack(String name) {
Track track = plugin.getTrackManager().make(name);
List<String> groups = new ArrayList<>();
Track track = plugin.getTrackManager().getOrMake(name);
track.getIoLock().lock();
try {
return call(() -> {
File trackFile = new File(tracksDir, name + ".json");
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 {
trackFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
File trackFile = new File(tracksDir, name + ".json");
if (!trackFile.exists()) {
try {
trackFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
boolean success = doWrite(trackFile, writer -> {
writer.beginObject();
writer.name("name").value(track.getName());
writer.name("groups");
writer.beginArray();
for (String s : track.getGroups()) {
writer.value(s);
return doWrite(trackFile, writer -> {
writer.beginObject();
writer.name("name").value(track.getName());
writer.name("groups");
writer.beginArray();
for (String s : track.getGroups()) {
writer.value(s);
}
writer.endArray();
writer.endObject();
return true;
});
}
writer.endArray();
writer.endObject();
return true;
});
if (!success) return false;
}, false);
} finally {
track.getIoLock().unlock();
}
boolean success = doRead(trackFile, reader -> {
reader.beginObject();
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
public boolean loadTrack(String name) {
Track track = plugin.getTrackManager().make(name);
List<String> groups = new ArrayList<>();
Track track = plugin.getTrackManager().getOrMake(name);
track.getIoLock().lock();
try {
return call(() -> {
File trackFile = new File(tracksDir, name + ".json");
return trackFile.exists() && doRead(trackFile, reader -> {
reader.beginObject();
reader.nextName(); // name record
reader.nextString(); // name
reader.nextName(); // groups
reader.beginArray();
List<String> groups = new ArrayList<>();
while (reader.hasNext()) {
groups.add(reader.nextString());
}
track.setGroups(groups);
reader.endArray();
reader.endObject();
return true;
});
File trackFile = new File(tracksDir, name + ".json");
if (!trackFile.exists()) {
return false;
}, false);
} finally {
track.getIoLock().unlock();
}
boolean success = doRead(trackFile, reader -> {
reader.beginObject();
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
@ -431,44 +472,71 @@ public class JSONDatastore extends FlatfileDatastore {
.map(s -> s.substring(0, s.length() - 5))
.collect(Collectors.toList());
plugin.getTrackManager().unloadAll();
tracks.forEach(this::loadTrack);
TrackManager tm = plugin.getTrackManager();
tm.getAll().values().stream()
.filter(t -> !tracks.contains(t.getName()))
.forEach(tm::unload);
return true;
}
@Override
public boolean saveTrack(Track track) {
File trackFile = new File(tracksDir, track.getName() + ".json");
if (!trackFile.exists()) {
try {
trackFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
track.getIoLock().lock();
try {
return call(() -> {
File trackFile = new File(tracksDir, track.getName() + ".json");
if (!trackFile.exists()) {
try {
trackFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
return doWrite(trackFile, writer -> {
writer.beginObject();
writer.name("name").value(track.getName());
writer.name("groups");
writer.beginArray();
for (String s : track.getGroups()) {
writer.value(s);
}
writer.endArray();
writer.endObject();
return true;
});
return doWrite(trackFile, writer -> {
writer.beginObject();
writer.name("name").value(track.getName());
writer.name("groups");
writer.beginArray();
for (String s : track.getGroups()) {
writer.value(s);
}
writer.endArray();
writer.endObject();
return true;
});
}, false);
} finally {
track.getIoLock().unlock();
}
}
@Override
public boolean deleteTrack(Track track) {
File trackFile = new File(tracksDir, track.getName() + ".json");
if (trackFile.exists()) {
trackFile.delete();
track.getIoLock().lock();
try {
return call(() -> {
File trackFile = new File(tracksDir, track.getName() + ".json");
if (trackFile.exists()) {
trackFile.delete();
}
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;
}
return true;
}
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.TrackManager;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.users.UserIdentifier;
import org.bson.Document;
import java.util.*;
@ -140,52 +141,77 @@ public class MongoDBDatastore extends Datastore {
@Override
public boolean loadUser(UUID uuid, String username) {
User user = plugin.getUserManager().make(uuid, username);
boolean success = call(() -> {
MongoCollection<Document> c = database.getCollection("users");
User user = plugin.getUserManager().getOrMake(UserIdentifier.of(uuid, username));
user.getIoLock().lock();
try {
return call(() -> {
MongoCollection<Document> c = database.getCollection("users");
try (MongoCursor<Document> cursor = c.find(new Document("_id", user.getUuid())).iterator()) {
if (cursor.hasNext()) {
Document d = cursor.next();
user.setPrimaryGroup(d.getString("primaryGroup"));
user.setNodes(revert((Map<String, Boolean>) d.get("perms")));
try (MongoCursor<Document> cursor = c.find(new Document("_id", user.getUuid())).iterator()) {
if (cursor.hasNext()) {
// User exists, let's load.
Document d = cursor.next();
user.setNodes(revert((Map<String, Boolean>) d.get("perms")));
user.setPrimaryGroup(d.getString("primaryGroup"));
if (user.getName().equalsIgnoreCase("null")) {
user.setName(d.getString("name"));
} else {
if (!d.getString("name").equals(user.getName())) {
boolean save = plugin.getUserManager().giveDefaultIfNeeded(user, false);
if (user.getName().equalsIgnoreCase("null")) {
user.setName(d.getString("name"));
} else {
if (!d.getString("name").equals(user.getName())) {
save = true;
}
}
if (save) {
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;
}, false);
if (success) plugin.getUserManager().updateOrSet(user);
return success;
return true;
}, false);
} finally {
user.getIoLock().unlock();
}
}
@Override
public boolean saveUser(User user) {
if (!plugin.getUserManager().shouldSave(user)) {
return call(() -> {
MongoCollection<Document> c = database.getCollection("users");
return c.deleteOne(new Document("_id", user.getUuid())).wasAcknowledged();
}, false);
user.getIoLock().lock();
try {
return call(() -> {
MongoCollection<Document> c = database.getCollection("users");
return c.deleteOne(new Document("_id", user.getUuid())).wasAcknowledged();
}, false);
} finally {
user.getIoLock().unlock();
}
}
return call(() -> {
MongoCollection<Document> c = database.getCollection("users");
try (MongoCursor<Document> cursor = c.find(new Document("_id", user.getUuid())).iterator()) {
if (!cursor.hasNext()) {
c.insertOne(fromUser(user));
} else {
c.replaceOne(new Document("_id", user.getUuid()), fromUser(user));
user.getIoLock().lock();
try {
return call(() -> {
MongoCollection<Document> c = database.getCollection("users");
try (MongoCursor<Document> cursor = c.find(new Document("_id", user.getUuid())).iterator()) {
if (!cursor.hasNext()) {
c.insertOne(fromUser(user));
} else {
c.replaceOne(new Document("_id", user.getUuid()), fromUser(user));
}
}
}
return true;
}, false);
return true;
}, false);
} finally {
user.getIoLock().unlock();
}
}
@Override
@ -214,85 +240,103 @@ public class MongoDBDatastore extends Datastore {
@Override
public boolean createAndLoadGroup(String name) {
Group group = plugin.getGroupManager().make(name);
boolean success = call(() -> {
MongoCollection<Document> c = database.getCollection("groups");
Group group = plugin.getGroupManager().getOrMake(name);
group.getIoLock().lock();
try {
return call(() -> {
MongoCollection<Document> c = database.getCollection("groups");
try (MongoCursor<Document> cursor = c.find(new Document("_id", group.getName())).iterator()) {
if (!cursor.hasNext()) {
c.insertOne(fromGroup(group));
} else {
Document d = cursor.next();
group.setNodes(revert((Map<String, Boolean>) d.get("perms")));
try (MongoCursor<Document> cursor = c.find(new Document("_id", group.getName())).iterator()) {
if (cursor.hasNext()) {
// Group exists, let's load.
Document d = cursor.next();
group.setNodes(revert((Map<String, Boolean>) d.get("perms")));
} else {
c.insertOne(fromGroup(group));
}
}
}
return true;
}, false);
if (success) plugin.getGroupManager().updateOrSet(group);
return success;
return true;
}, false);
} finally {
group.getIoLock().unlock();
}
}
@Override
public boolean loadGroup(String name) {
Group group = plugin.getGroupManager().make(name);
boolean success = call(() -> {
MongoCollection<Document> c = database.getCollection("groups");
Group group = plugin.getGroupManager().getOrMake(name);
group.getIoLock().lock();
try {
return call(() -> {
MongoCollection<Document> c = database.getCollection("groups");
try (MongoCursor<Document> cursor = c.find(new Document("_id", group.getName())).iterator()) {
if (cursor.hasNext()) {
Document d = cursor.next();
group.setNodes(revert((Map<String, Boolean>) d.get("perms")));
return true;
try (MongoCursor<Document> cursor = c.find(new Document("_id", group.getName())).iterator()) {
if (cursor.hasNext()) {
Document d = cursor.next();
group.setNodes(revert((Map<String, Boolean>) d.get("perms")));
return true;
}
return false;
}
return false;
}
}, false);
if (success) plugin.getGroupManager().updateOrSet(group);
return success;
}, false);
} finally {
group.getIoLock().unlock();
}
}
@Override
public boolean loadAllGroups() {
List<Group> groups = new ArrayList<>();
List<String> groups = new ArrayList<>();
boolean success = call(() -> {
MongoCollection<Document> c = database.getCollection("groups");
boolean b = true;
try (MongoCursor<Document> cursor = c.find().iterator()) {
while (cursor.hasNext()) {
Document d = cursor.next();
Group group = plugin.getGroupManager().make(d.getString("_id"));
group.setNodes(revert((Map<String, Boolean>) d.get("perms")));
groups.add(group);
String name = cursor.next().getString("_id");
if (!loadGroup(name)) {
b = false;
}
groups.add(name);
}
}
return true;
return b;
}, false);
if (success) {
GroupManager gm = plugin.getGroupManager();
gm.unloadAll();
groups.forEach(gm::set);
gm.getAll().values().stream()
.filter(g -> !groups.contains(g.getName()))
.forEach(gm::unload);
}
return success;
}
@Override
public boolean saveGroup(Group group) {
return call(() -> {
MongoCollection<Document> c = database.getCollection("groups");
return c.replaceOne(new Document("_id", group.getName()), fromGroup(group)).wasAcknowledged();
}, false);
group.getIoLock().lock();
try {
return call(() -> {
MongoCollection<Document> c = database.getCollection("groups");
return c.replaceOne(new Document("_id", group.getName()), fromGroup(group)).wasAcknowledged();
}, false);
} finally {
group.getIoLock().unlock();
}
}
@Override
public boolean deleteGroup(Group group) {
boolean success = call(() -> {
MongoCollection<Document> c = database.getCollection("groups");
return c.deleteOne(new Document("_id", group.getName())).wasAcknowledged();
}, false);
group.getIoLock().lock();
boolean success;
try {
success = call(() -> {
MongoCollection<Document> c = database.getCollection("groups");
return c.deleteOne(new Document("_id", group.getName())).wasAcknowledged();
}, false);
} finally {
group.getIoLock().unlock();
}
if (success) plugin.getGroupManager().unload(group);
return success;
@ -300,85 +344,102 @@ public class MongoDBDatastore extends Datastore {
@Override
public boolean createAndLoadTrack(String name) {
Track track = plugin.getTrackManager().make(name);
boolean success = call(() -> {
MongoCollection<Document> c = database.getCollection("tracks");
Track track = plugin.getTrackManager().getOrMake(name);
track.getIoLock().lock();
try {
return call(() -> {
MongoCollection<Document> c = database.getCollection("tracks");
try (MongoCursor<Document> cursor = c.find(new Document("_id", track.getName())).iterator()) {
if (!cursor.hasNext()) {
c.insertOne(fromTrack(track));
} else {
Document d = cursor.next();
track.setGroups((List<String>) d.get("groups"));
try (MongoCursor<Document> cursor = c.find(new Document("_id", track.getName())).iterator()) {
if (!cursor.hasNext()) {
c.insertOne(fromTrack(track));
} else {
Document d = cursor.next();
track.setGroups((List<String>) d.get("groups"));
}
}
}
return true;
}, false);
if (success) plugin.getTrackManager().updateOrSet(track);
return success;
return true;
}, false);
} finally {
track.getIoLock().unlock();
}
}
@Override
public boolean loadTrack(String name) {
Track track = plugin.getTrackManager().make(name);
boolean success = call(() -> {
MongoCollection<Document> c = database.getCollection("tracks");
Track track = plugin.getTrackManager().getOrMake(name);
track.getIoLock().lock();
try {
return call(() -> {
MongoCollection<Document> c = database.getCollection("tracks");
try (MongoCursor<Document> cursor = c.find(new Document("_id", track.getName())).iterator()) {
if (cursor.hasNext()) {
Document d = cursor.next();
track.setGroups((List<String>) d.get("groups"));
return true;
try (MongoCursor<Document> cursor = c.find(new Document("_id", track.getName())).iterator()) {
if (cursor.hasNext()) {
Document d = cursor.next();
track.setGroups((List<String>) d.get("groups"));
return true;
}
return false;
}
return false;
}
}, false);
if (success) plugin.getTrackManager().updateOrSet(track);
return success;
}, false);
} finally {
track.getIoLock().unlock();
}
}
@Override
public boolean loadAllTracks() {
List<Track> tracks = new ArrayList<>();
List<String> tracks = new ArrayList<>();
boolean success = call(() -> {
MongoCollection<Document> c = database.getCollection("tracks");
boolean b = true;
try (MongoCursor<Document> cursor = c.find().iterator()) {
while (cursor.hasNext()) {
Document d = cursor.next();
Track track = plugin.getTrackManager().make(d.getString("_id"));
track.setGroups((List<String>) d.get("groups"));
tracks.add(track);
String name = cursor.next().getString("_id");
if (!loadTrack(name)) {
b = false;
}
tracks.add(name);
}
}
return true;
return b;
}, false);
if (success) {
TrackManager tm = plugin.getTrackManager();
tm.unloadAll();
tracks.forEach(tm::set);
tm.getAll().values().stream()
.filter(t -> !tracks.contains(t.getName()))
.forEach(tm::unload);
}
return success;
}
@Override
public boolean saveTrack(Track track) {
return call(() -> {
MongoCollection<Document> c = database.getCollection("tracks");
return c.replaceOne(new Document("_id", track.getName()), fromTrack(track)).wasAcknowledged();
}, false);
track.getIoLock().lock();
try {
return call(() -> {
MongoCollection<Document> c = database.getCollection("tracks");
return c.replaceOne(new Document("_id", track.getName()), fromTrack(track)).wasAcknowledged();
}, false);
} finally {
track.getIoLock().unlock();
}
}
@Override
public boolean deleteTrack(Track track) {
boolean success = call(() -> {
MongoCollection<Document> c = database.getCollection("tracks");
return c.deleteOne(new Document("_id", track.getName())).wasAcknowledged();
}, false);
track.getIoLock().lock();
boolean success;
try {
success = call(() -> {
MongoCollection<Document> c = database.getCollection("tracks");
return c.deleteOne(new Document("_id", track.getName())).wasAcknowledged();
}, false);
} finally {
track.getIoLock().unlock();
}
if (success) plugin.getTrackManager().unload(track);
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.TrackManager;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.users.UserIdentifier;
import java.lang.reflect.Type;
import java.sql.Connection;
@ -142,20 +143,29 @@ abstract class SQLDatastore extends Datastore {
@Override
public boolean loadUser(UUID uuid, String username) {
User user = plugin.getUserManager().make(uuid, username);
boolean success = runQuery(USER_SELECT,
preparedStatement -> preparedStatement.setString(1, user.getUuid().toString()),
resultSet -> {
if (resultSet.next()) {
// User exists, let's load.
Map<String, Boolean> nodes = gson.fromJson(resultSet.getString("perms"), NM_TYPE);
user.setNodes(nodes);
user.setPrimaryGroup(resultSet.getString("primary_group"));
User user = plugin.getUserManager().getOrMake(UserIdentifier.of(uuid, username));
user.getIoLock().lock();
try {
return runQuery(USER_SELECT,
preparedStatement -> preparedStatement.setString(1, user.getUuid().toString()),
resultSet -> {
if (resultSet.next()) {
// User exists, let's load.
Map<String, Boolean> nodes = gson.fromJson(resultSet.getString("perms"), NM_TYPE);
user.setNodes(nodes);
user.setPrimaryGroup(resultSet.getString("primary_group"));
if (user.getName().equalsIgnoreCase("null")) {
user.setName(resultSet.getString("name"));
} else {
if (!resultSet.getString("name").equals(user.getName())) {
boolean save = plugin.getUserManager().giveDefaultIfNeeded(user, false);
if (user.getName().equalsIgnoreCase("null")) {
user.setName(resultSet.getString("name"));
} else {
if (!resultSet.getString("name").equals(user.getName())) {
save = true;
}
}
if (save) {
runQuery(USER_UPDATE, preparedStatement -> {
preparedStatement.setString(1, user.getName());
preparedStatement.setString(2, user.getPrimaryGroup());
@ -163,47 +173,62 @@ abstract class SQLDatastore extends Datastore {
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;
}
);
if (success) plugin.getUserManager().updateOrSet(user);
return success;
);
} finally {
user.getIoLock().unlock();
}
}
@Override
public boolean saveUser(User user) {
if (!plugin.getUserManager().shouldSave(user)) {
return runQuery(USER_DELETE, preparedStatement -> {
preparedStatement.setString(1, user.getUuid().toString());
});
user.getIoLock().lock();
try {
return runQuery(USER_DELETE, preparedStatement -> {
preparedStatement.setString(1, user.getUuid().toString());
});
} finally {
user.getIoLock().unlock();
}
}
return runQuery(USER_SELECT,
preparedStatement -> preparedStatement.setString(1, user.getUuid().toString()),
resultSet -> {
if (!resultSet.next()) {
// Doesn't already exist, let's insert.
return runQuery(USER_INSERT, preparedStatement -> {
preparedStatement.setString(1, user.getUuid().toString());
preparedStatement.setString(2, user.getName());
preparedStatement.setString(3, user.getPrimaryGroup());
preparedStatement.setString(4, gson.toJson(exportToLegacy(user.getNodes())));
});
user.getIoLock().lock();
try {
return runQuery(USER_SELECT,
preparedStatement -> preparedStatement.setString(1, user.getUuid().toString()),
resultSet -> {
if (!resultSet.next()) {
// Doesn't already exist, let's insert.
return runQuery(USER_INSERT, preparedStatement -> {
preparedStatement.setString(1, user.getUuid().toString());
preparedStatement.setString(2, user.getName());
preparedStatement.setString(3, user.getPrimaryGroup());
preparedStatement.setString(4, gson.toJson(exportToLegacy(user.getNodes())));
});
} else {
// User exists, let's update.
return runQuery(USER_UPDATE, preparedStatement -> {
preparedStatement.setString(1, user.getName());
preparedStatement.setString(2, user.getPrimaryGroup());
preparedStatement.setString(3, gson.toJson(exportToLegacy(user.getNodes())));
preparedStatement.setString(4, user.getUuid().toString());
});
} else {
// User exists, let's update.
return runQuery(USER_UPDATE, preparedStatement -> {
preparedStatement.setString(1, user.getName());
preparedStatement.setString(2, user.getPrimaryGroup());
preparedStatement.setString(3, gson.toJson(exportToLegacy(user.getNodes())));
preparedStatement.setString(4, user.getUuid().toString());
});
}
}
}
);
);
} finally {
user.getIoLock().unlock();
}
}
@Override
@ -230,80 +255,101 @@ abstract class SQLDatastore extends Datastore {
@Override
public boolean createAndLoadGroup(String name) {
Group group = plugin.getGroupManager().make(name);
boolean success = runQuery(GROUP_SELECT,
preparedStatement -> preparedStatement.setString(1, group.getName()),
resultSet -> {
if (!resultSet.next()) {
return runQuery(GROUP_INSERT, preparedStatement -> {
preparedStatement.setString(1, group.getName());
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;
Group group = plugin.getGroupManager().getOrMake(name);
group.getIoLock().lock();
try {
return runQuery(GROUP_SELECT,
preparedStatement -> preparedStatement.setString(1, group.getName()),
resultSet -> {
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 -> {
preparedStatement.setString(1, group.getName());
preparedStatement.setString(2, gson.toJson(exportToLegacy(group.getNodes())));
});
}
}
}
);
if (success) plugin.getGroupManager().updateOrSet(group);
return success;
);
} finally {
group.getIoLock().unlock();
}
}
@Override
public boolean loadGroup(String name) {
Group group = plugin.getGroupManager().make(name);
boolean success = runQuery(GROUP_SELECT,
preparedStatement -> preparedStatement.setString(1, name),
resultSet -> {
if (resultSet.next()) {
Map<String, Boolean> nodes = gson.fromJson(resultSet.getString("perms"), NM_TYPE);
group.setNodes(nodes);
return true;
Group group = plugin.getGroupManager().getOrMake(name);
group.getIoLock().lock();
try {
return runQuery(GROUP_SELECT,
preparedStatement -> preparedStatement.setString(1, name),
resultSet -> {
if (resultSet.next()) {
// Group exists, let's load.
Map<String, Boolean> nodes = gson.fromJson(resultSet.getString("perms"), NM_TYPE);
group.setNodes(nodes);
return true;
}
return false;
}
return false;
}
);
);
} finally {
group.getIoLock().unlock();
}
if (success) plugin.getGroupManager().updateOrSet(group);
return success;
}
@Override
public boolean loadAllGroups() {
List<Group> groups = new ArrayList<>();
List<String> groups = new ArrayList<>();
boolean success = runQuery(GROUP_SELECT_ALL, resultSet -> {
boolean b = true;
while (resultSet.next()) {
Group group = plugin.getGroupManager().make(resultSet.getString("name"));
Map<String, Boolean> nodes = gson.fromJson(resultSet.getString("perms"), NM_TYPE);
group.setNodes(nodes);
groups.add(group);
String name = resultSet.getString("name");
if (!loadGroup(name)) {
b = false;
}
groups.add(name);
}
return true;
return b;
});
if (success) {
GroupManager gm = plugin.getGroupManager();
gm.unloadAll();
groups.forEach(gm::set);
gm.getAll().values().stream()
.filter(g -> !groups.contains(g.getName()))
.forEach(gm::unload);
}
return success;
}
@Override
public boolean saveGroup(Group group) {
return runQuery(GROUP_UPDATE, preparedStatement -> {
preparedStatement.setString(1, gson.toJson(exportToLegacy(group.getNodes())));
preparedStatement.setString(2, group.getName());
});
group.getIoLock().lock();
try {
return runQuery(GROUP_UPDATE, preparedStatement -> {
preparedStatement.setString(1, gson.toJson(exportToLegacy(group.getNodes())));
preparedStatement.setString(2, group.getName());
});
} finally {
group.getIoLock().unlock();
}
}
@Override
public boolean deleteGroup(Group group) {
boolean success = runQuery(GROUP_DELETE, preparedStatement -> {
preparedStatement.setString(1, group.getName());
});
group.getIoLock().lock();
boolean success;
try {
success = runQuery(GROUP_DELETE, preparedStatement -> {
preparedStatement.setString(1, group.getName());
});
} finally {
group.getIoLock().unlock();
}
if (success) plugin.getGroupManager().unload(group);
return success;
@ -311,77 +357,97 @@ abstract class SQLDatastore extends Datastore {
@Override
public boolean createAndLoadTrack(String name) {
Track track = plugin.getTrackManager().make(name);
boolean success = runQuery(TRACK_SELECT,
preparedStatement -> preparedStatement.setString(1, track.getName()),
resultSet -> {
if (!resultSet.next()) {
return runQuery(TRACK_INSERT, preparedStatement -> {
preparedStatement.setString(1, track.getName());
preparedStatement.setString(2, gson.toJson(track.getGroups()));
});
} else {
track.setGroups(gson.fromJson(resultSet.getString("groups"), T_TYPE));
return true;
Track track = plugin.getTrackManager().getOrMake(name);
track.getIoLock().lock();
try {
return runQuery(TRACK_SELECT,
preparedStatement -> preparedStatement.setString(1, track.getName()),
resultSet -> {
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 -> {
preparedStatement.setString(1, track.getName());
preparedStatement.setString(2, gson.toJson(track.getGroups()));
});
}
}
}
);
if (success) plugin.getTrackManager().updateOrSet(track);
return success;
);
} finally {
track.getIoLock().unlock();
}
}
@Override
public boolean loadTrack(String name) {
Track track = plugin.getTrackManager().make(name);
boolean success = runQuery(TRACK_SELECT,
preparedStatement -> preparedStatement.setString(1, name),
resultSet -> {
if (resultSet.next()) {
track.setGroups(gson.fromJson(resultSet.getString("groups"), T_TYPE));
return true;
Track track = plugin.getTrackManager().getOrMake(name);
track.getIoLock().lock();
try {
return runQuery(TRACK_SELECT,
preparedStatement -> preparedStatement.setString(1, name),
resultSet -> {
if (resultSet.next()) {
track.setGroups(gson.fromJson(resultSet.getString("groups"), T_TYPE));
return true;
}
return false;
}
return false;
}
);
if (success) plugin.getTrackManager().updateOrSet(track);
return success;
);
} finally {
track.getIoLock().unlock();
}
}
@Override
public boolean loadAllTracks() {
List<Track> tracks = new ArrayList<>();
List<String> tracks = new ArrayList<>();
boolean success = runQuery(TRACK_SELECT_ALL, resultSet -> {
boolean b = true;
while (resultSet.next()) {
Track track = plugin.getTrackManager().make(resultSet.getString("name"));
track.setGroups(gson.fromJson(resultSet.getString("groups"), T_TYPE));
tracks.add(track);
String name = resultSet.getString("name");
if (!loadTrack(name)) {
b = false;
}
tracks.add(name);
}
return true;
return b;
});
if (success) {
TrackManager tm = plugin.getTrackManager();
tm.unloadAll();
tracks.forEach(tm::set);
tm.getAll().values().stream()
.filter(t -> !tracks.contains(t.getName()))
.forEach(tm::unload);
}
return success;
}
@Override
public boolean saveTrack(Track track) {
return runQuery(TRACK_UPDATE, preparedStatement -> {
preparedStatement.setString(1, gson.toJson(track.getGroups()));
preparedStatement.setString(2, track.getName());
});
track.getIoLock().lock();
try {
return runQuery(TRACK_UPDATE, preparedStatement -> {
preparedStatement.setString(1, gson.toJson(track.getGroups()));
preparedStatement.setString(2, track.getName());
});
} finally {
track.getIoLock().unlock();
}
}
@Override
public boolean deleteTrack(Track track) {
boolean success = runQuery(TRACK_DELETE, preparedStatement -> {
preparedStatement.setString(1, track.getName());
});
track.getIoLock().lock();
boolean success;
try {
success = runQuery(TRACK_DELETE, preparedStatement -> {
preparedStatement.setString(1, track.getName());
});
} finally {
track.getIoLock().unlock();
}
if (success) plugin.getTrackManager().unload(track);
return success;

View File

@ -26,13 +26,17 @@ import lombok.Cleanup;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.core.Node;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.groups.GroupManager;
import me.lucko.luckperms.tracks.Track;
import me.lucko.luckperms.tracks.TrackManager;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.users.UserIdentifier;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import java.io.*;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import static me.lucko.luckperms.core.PermissionHolder.exportToLegacy;
@ -76,96 +80,117 @@ public class YAMLDatastore extends FlatfileDatastore {
@Override
public boolean loadUser(UUID uuid, String username) {
User user = plugin.getUserManager().make(uuid, username);
boolean success = false;
User user = plugin.getUserManager().getOrMake(UserIdentifier.of(uuid, username));
user.getIoLock().lock();
try {
return call(() -> {
File userFile = new File(usersDir, uuid.toString() + ".yml");
if (userFile.exists()) {
return doRead(userFile, values -> {
// User exists, let's load.
String name = (String) values.get("name");
user.setPrimaryGroup((String) values.get("primary-group"));
Map<String, Boolean> perms = (Map<String, Boolean>) values.get("perms");
for (Map.Entry<String, Boolean> e : perms.entrySet()) {
user.getNodes().add(Node.fromSerialisedNode(e.getKey(), e.getValue()));
}
File userFile = new File(usersDir, uuid.toString() + ".yml");
if (userFile.exists()) {
final String[] name = {null};
success = doRead(userFile, values -> {
name[0] = (String) values.get("name");
user.setPrimaryGroup((String) values.get("primary-group"));
Map<String, Boolean> perms = (Map<String, Boolean>) values.get("perms");
for (Map.Entry<String, Boolean> e : perms.entrySet()) {
user.getNodes().add(Node.fromSerialisedNode(e.getKey(), e.getValue()));
boolean save = plugin.getUserManager().giveDefaultIfNeeded(user, false);
if (user.getName().equalsIgnoreCase("null")) {
user.setName(name);
} else {
if (!name.equals(user.getName())) {
save = true;
}
}
if (save) {
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;
}
return true;
});
if (user.getName().equalsIgnoreCase("null")) {
user.setName(name[0]);
} else {
if (!name[0].equals(user.getName())) {
Map<String, Object> values = new HashMap<>();
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 {
success = true;
}, false);
} finally {
user.getIoLock().unlock();
}
if (success) plugin.getUserManager().updateOrSet(user);
return success;
}
@Override
public boolean saveUser(User user) {
File userFile = new File(usersDir, user.getUuid().toString() + ".yml");
if (!plugin.getUserManager().shouldSave(user)) {
if (userFile.exists()) {
userFile.delete();
}
return true;
}
user.getIoLock().lock();
try {
return call(() -> {
File userFile = new File(usersDir, user.getUuid().toString() + ".yml");
if (!plugin.getUserManager().shouldSave(user)) {
if (userFile.exists()) {
userFile.delete();
}
return true;
}
if (!userFile.exists()) {
try {
userFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
if (!userFile.exists()) {
try {
userFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
Map<String, Object> values = new HashMap<>();
values.put("uuid", user.getUuid().toString());
values.put("name", user.getName());
values.put("primary-group", user.getPrimaryGroup());
values.put("perms", exportToLegacy(user.getNodes()));
return doWrite(userFile, values);
Map<String, Object> values = new HashMap<>();
values.put("uuid", user.getUuid().toString());
values.put("name", user.getName());
values.put("primary-group", user.getPrimaryGroup());
values.put("perms", exportToLegacy(user.getNodes()));
return doWrite(userFile, values);
}, false);
} finally {
user.getIoLock().unlock();
}
}
@Override
public boolean cleanupUsers() {
File[] files = usersDir.listFiles((dir, name) -> name.endsWith(".yml"));
if (files == null) return false;
return call(() -> {
File[] files = usersDir.listFiles((dir, name1) -> name1.endsWith(".yml"));
if (files == null) return false;
for (File file : files) {
Map<String, Boolean> nodes = new HashMap<>();
doRead(file, values -> {
Map<String, Boolean> perms = (Map<String, Boolean>) values.get("perms");
nodes.putAll(perms);
return true;
});
for (File file : files) {
Map<String, Boolean> nodes = new HashMap<>();
doRead(file, values -> {
Map<String, Boolean> perms = (Map<String, Boolean>) values.get("perms");
nodes.putAll(perms);
return true;
});
boolean shouldDelete = false;
if (nodes.size() == 1) {
for (Map.Entry<String, Boolean> e : nodes.entrySet()) {
// There's only one
shouldDelete = e.getKey().equalsIgnoreCase("group.default") && e.getValue();
boolean shouldDelete = false;
if (nodes.size() == 1) {
for (Map.Entry<String, Boolean> e : nodes.entrySet()) {
// There's only one
shouldDelete = e.getKey().equalsIgnoreCase("group.default") && e.getValue();
}
}
if (shouldDelete) {
file.delete();
}
}
if (shouldDelete) {
file.delete();
}
}
return true;
return true;
}, false);
}
@Override
@ -180,57 +205,57 @@ public class YAMLDatastore extends FlatfileDatastore {
@Override
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");
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 {
groupFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
File groupFile = new File(groupsDir, name + ".yml");
if (!groupFile.exists()) {
try {
groupFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
Map<String, Object> values = new HashMap<>();
values.put("name", group.getName());
values.put("perms", exportToLegacy(group.getNodes()));
if (!doWrite(groupFile, values)) {
return false;
}
Map<String, Object> values = new HashMap<>();
values.put("name", group.getName());
values.put("perms", exportToLegacy(group.getNodes()));
return doWrite(groupFile, values);
}
}, 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
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");
return groupFile.exists() && 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;
});
File groupFile = new File(groupsDir, name + ".yml");
if (!groupFile.exists()) {
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
@ -241,89 +266,103 @@ public class YAMLDatastore extends FlatfileDatastore {
.map(s -> s.substring(0, s.length() - 4))
.collect(Collectors.toList());
plugin.getGroupManager().unloadAll();
groups.forEach(this::loadGroup);
GroupManager gm = plugin.getGroupManager();
gm.getAll().values().stream()
.filter(g -> !groups.contains(g.getName()))
.forEach(gm::unload);
return true;
}
@Override
public boolean saveGroup(Group group) {
File groupFile = new File(groupsDir, group.getName() + ".yml");
if (!groupFile.exists()) {
try {
groupFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
group.getIoLock().lock();
try {
return call(() -> {
File groupFile = new File(groupsDir, group.getName() + ".yml");
if (!groupFile.exists()) {
try {
groupFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
Map<String, Object> values = new HashMap<>();
values.put("name", group.getName());
values.put("perms", exportToLegacy(group.getNodes()));
return doWrite(groupFile, values);
Map<String, Object> values = new HashMap<>();
values.put("name", group.getName());
values.put("perms", exportToLegacy(group.getNodes()));
return doWrite(groupFile, values);
}, false);
} finally {
group.getIoLock().unlock();
}
}
@Override
public boolean deleteGroup(Group group) {
File groupFile = new File(groupsDir, group.getName() + ".yml");
if (groupFile.exists()) {
groupFile.delete();
group.getIoLock().lock();
try {
return call(() -> {
File groupFile = new File(groupsDir, group.getName() + ".yml");
if (groupFile.exists()) {
groupFile.delete();
}
return true;
}, false);
} finally {
group.getIoLock().unlock();
}
return true;
}
@Override
public boolean createAndLoadTrack(String name) {
Track track = plugin.getTrackManager().make(name);
List<String> groups = new ArrayList<>();
Track track = plugin.getTrackManager().getOrMake(name);
track.getIoLock().lock();
try {
return call(() -> {
File trackFile = new File(tracksDir, name + ".yml");
if (trackFile.exists()) {
return doRead(trackFile, values -> {
track.setGroups((List<String>) values.get("groups"));
return true;
});
} else {
try {
trackFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
File trackFile = new File(tracksDir, name + ".yml");
if (!trackFile.exists()) {
try {
trackFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
Map<String, Object> values = new HashMap<>();
values.put("name", track.getName());
values.put("groups", track.getGroups());
Map<String, Object> values = new HashMap<>();
values.put("name", track.getName());
values.put("groups", track.getGroups());
if (!doWrite(trackFile, values)) {
return false;
}
return doWrite(trackFile, values);
}
}, 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
public boolean loadTrack(String name) {
Track track = plugin.getTrackManager().make(name);
List<String> groups = new ArrayList<>();
File trackFile = new File(tracksDir, name + ".yml");
if (!trackFile.exists()) {
return false;
Track track = plugin.getTrackManager().getOrMake(name);
track.getIoLock().lock();
try {
return call(() -> {
File trackFile = new File(tracksDir, name + ".yml");
return trackFile.exists() && doRead(trackFile, values -> {
track.setGroups((List<String>) values.get("groups"));
return true;
});
}, 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
@ -334,36 +373,63 @@ public class YAMLDatastore extends FlatfileDatastore {
.map(s -> s.substring(0, s.length() - 4))
.collect(Collectors.toList());
plugin.getTrackManager().unloadAll();
tracks.forEach(this::loadTrack);
TrackManager tm = plugin.getTrackManager();
tm.getAll().values().stream()
.filter(t -> !tracks.contains(t.getName()))
.forEach(tm::unload);
return true;
}
@Override
public boolean saveTrack(Track track) {
File trackFile = new File(tracksDir, track.getName() + ".yml");
if (!trackFile.exists()) {
try {
trackFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
track.getIoLock().lock();
try {
return call(() -> {
File trackFile = new File(tracksDir, track.getName() + ".yml");
if (!trackFile.exists()) {
try {
trackFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
Map<String, Object> values = new HashMap<>();
values.put("name", track.getName());
values.put("groups", track.getGroups());
return doWrite(trackFile, values);
Map<String, Object> values = new HashMap<>();
values.put("name", track.getName());
values.put("groups", track.getGroups());
return doWrite(trackFile, values);
}, false);
} finally {
track.getIoLock().unlock();
}
}
@Override
public boolean deleteTrack(Track track) {
File trackFile = new File(tracksDir, track.getName() + ".yml");
if (trackFile.exists()) {
trackFile.delete();
track.getIoLock().lock();
try {
return call(() -> {
File trackFile = new File(tracksDir, track.getName() + ".yml");
if (trackFile.exists()) {
trackFile.delete();
}
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;
}
return true;
}
interface ReadOperation {

View File

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

View File

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

View File

@ -40,7 +40,7 @@ import java.util.UUID;
@ToString(of = {"uuid"})
@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
@ -75,8 +75,8 @@ public abstract class User extends PermissionHolder implements Identifiable<UUID
}
@Override
public UUID getId() {
return uuid;
public UserIdentifier getId() {
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;
@RequiredArgsConstructor
public abstract class UserManager extends AbstractManager<UUID, User> {
public abstract class UserManager extends AbstractManager<UserIdentifier, User> {
private final LuckPermsPlugin plugin;
/**
@ -53,26 +53,15 @@ public abstract class UserManager extends AbstractManager<UUID, User> {
}
}
@Override
public void preSet(User u) {
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();
public User get(UUID uuid) {
return get(UserIdentifier.of(uuid, null));
}
/**
* Set a user to the default group
* @param user the user to give to
*/
public void giveDefaultIfNeeded(User user, boolean save) {
public boolean giveDefaultIfNeeded(User user, boolean save) {
boolean hasGroup = false;
if (user.getPrimaryGroup() != null && !user.getPrimaryGroup().isEmpty()) {
@ -84,18 +73,22 @@ public abstract class UserManager extends AbstractManager<UUID, User> {
}
}
if (!hasGroup) {
user.setPrimaryGroup("default");
try {
user.setPermission("group.default", true);
} catch (ObjectAlreadyHasException ignored) {
ignored.printStackTrace();
}
if (save) {
plugin.getDatastore().saveUser(user, Callback.empty());
}
if (hasGroup) {
return false;
}
user.setPrimaryGroup("default");
try {
user.setPermission("group.default", true);
} catch (ObjectAlreadyHasException ignored) {
ignored.printStackTrace();
}
if (save) {
plugin.getDatastore().saveUser(user, Callback.empty());
}
return true;
}
public boolean shouldSave(User user) {
@ -132,14 +125,6 @@ public abstract class UserManager extends AbstractManager<UUID, 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
*/

View File

@ -26,18 +26,32 @@ import com.google.common.collect.ImmutableMap;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
/**
* An abstract manager class
* @param <I> the class used to identify each object held in this manager
* @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<>();
public final Map<I, T> getAll() {
Map<I, T> map;
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
* @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) {
if (t != null) {
preUnload(t);
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() {
synchronized (objects) {
objects.values().forEach(this::preUnload);
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.simple.SimpleCollection;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.users.UserIdentifier;
import me.lucko.luckperms.users.UserManager;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.PermissionService;
@ -62,7 +63,7 @@ public class UserCollection implements SubjectCollection {
private void load(UUID uuid) {
UUID internal = service.getPlugin().getUuidCache().getUUID(uuid);
if (!manager.isLoaded(internal)) {
if (!manager.isLoaded(UserIdentifier.of(uuid, null))) {
return;
}
@ -82,7 +83,7 @@ public class UserCollection implements SubjectCollection {
return users.get(u);
}
if (manager.isLoaded(u)) {
if (manager.isLoaded(UserIdentifier.of(u, null))) {
load(u);
return users.get(u);
}
@ -108,7 +109,7 @@ public class UserCollection implements SubjectCollection {
public boolean hasRegistered(@NonNull String id) {
try {
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) {
User user = manager.get(id);
return user != null;

View File

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

View File

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