mirror of
https://github.com/LuckPerms/LuckPerms.git
synced 2024-11-24 11:38:40 +01:00
Improve the way player uuid data is saved/stored. Add a warning message to catch ip forwarding issues
This commit is contained in:
parent
8f30176edd
commit
e4e93b1af1
@ -254,7 +254,7 @@ public class ApiStorage implements me.lucko.luckperms.api.Storage {
|
||||
public CompletableFuture<Boolean> saveUUIDData(@Nonnull String username, @Nonnull UUID uuid) {
|
||||
Objects.requireNonNull(username, "username");
|
||||
Objects.requireNonNull(uuid, "uuid");
|
||||
return this.handle.noBuffer().saveUUIDData(uuid, checkUsername(username))
|
||||
return this.handle.noBuffer().savePlayerData(uuid, checkUsername(username))
|
||||
.thenApply(r -> true)
|
||||
.exceptionally(consumeExceptionToFalse());
|
||||
}
|
||||
@ -263,13 +263,13 @@ public class ApiStorage implements me.lucko.luckperms.api.Storage {
|
||||
@Override
|
||||
public CompletableFuture<UUID> getUUID(@Nonnull String username) {
|
||||
Objects.requireNonNull(username, "username");
|
||||
return this.handle.noBuffer().getUUID(checkUsername(username));
|
||||
return this.handle.noBuffer().getPlayerUuid(checkUsername(username));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CompletableFuture<String> getName(@Nonnull UUID uuid) {
|
||||
Objects.requireNonNull(uuid, "uuid");
|
||||
return this.handle.noBuffer().getName(uuid);
|
||||
return this.handle.noBuffer().getPlayerName(uuid);
|
||||
}
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ public class GroupListMembers extends SubCommand<Group> {
|
||||
if (!matchedUsers.isEmpty()) {
|
||||
LoadingCache<UUID, String> uuidLookups = Caffeine.newBuilder()
|
||||
.build(u -> {
|
||||
String s = plugin.getStorage().getName(u).join();
|
||||
String s = plugin.getStorage().getPlayerName(u).join();
|
||||
if (s == null || s.isEmpty() || s.equals("null")) {
|
||||
s = u.toString();
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ public class LogRecent extends SubCommand<Log> {
|
||||
}
|
||||
}
|
||||
|
||||
uuid = plugin.getStorage().getUUID(target.toLowerCase()).join();
|
||||
uuid = plugin.getStorage().getPlayerUuid(target.toLowerCase()).join();
|
||||
if (uuid == null) {
|
||||
if (!plugin.getConfiguration().get(ConfigKeys.USE_SERVER_UUID_CACHE)) {
|
||||
Message.USER_NOT_FOUND.send(sender, target);
|
||||
|
@ -81,7 +81,7 @@ public class LogUserHistory extends SubCommand<Log> {
|
||||
}
|
||||
}
|
||||
|
||||
uuid = plugin.getStorage().getUUID(target.toLowerCase()).join();
|
||||
uuid = plugin.getStorage().getPlayerUuid(target.toLowerCase()).join();
|
||||
if (uuid == null) {
|
||||
if (!plugin.getConfiguration().get(ConfigKeys.USE_SERVER_UUID_CACHE)) {
|
||||
Message.USER_NOT_FOUND.send(sender, target);
|
||||
|
@ -86,7 +86,7 @@ public class SearchCommand extends SingleCommand {
|
||||
if (!matchedUsers.isEmpty()) {
|
||||
LoadingCache<UUID, String> uuidLookups = Caffeine.newBuilder()
|
||||
.build(u -> {
|
||||
String s = plugin.getStorage().getName(u).join();
|
||||
String s = plugin.getStorage().getPlayerName(u).join();
|
||||
if (s == null || s.isEmpty() || s.equals("null")) {
|
||||
s = u.toString();
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ public class UserClone extends SubCommand<User> {
|
||||
}
|
||||
}
|
||||
|
||||
uuid = plugin.getStorage().getUUID(target.toLowerCase()).join();
|
||||
uuid = plugin.getStorage().getPlayerUuid(target.toLowerCase()).join();
|
||||
if (uuid == null) {
|
||||
if (!plugin.getConfiguration().get(ConfigKeys.USE_SERVER_UUID_CACHE)) {
|
||||
Message.USER_NOT_FOUND.send(sender, target);
|
||||
|
@ -67,6 +67,7 @@ public class UserInfo extends SubCommand<User> {
|
||||
Message.USER_INFO_GENERAL.send(sender,
|
||||
user.getName().orElse("Unknown"),
|
||||
user.getUuid(),
|
||||
user.getUuid().version() == 4 ? "&2mojang" : "&8offline",
|
||||
status.asString(plugin.getLocaleManager()),
|
||||
user.getPrimaryGroup().getValue()
|
||||
);
|
||||
|
@ -96,7 +96,7 @@ public class UserMainCommand extends MainCommand<User, UserIdentifier> {
|
||||
}
|
||||
}
|
||||
|
||||
uuid = plugin.getStorage().getUUID(target.toLowerCase()).join();
|
||||
uuid = plugin.getStorage().getPlayerUuid(target.toLowerCase()).join();
|
||||
if (uuid == null) {
|
||||
if (!plugin.getConfiguration().get(ConfigKeys.USE_SERVER_UUID_CACHE)) {
|
||||
Message.USER_NOT_FOUND.send(sender, target);
|
||||
@ -111,7 +111,7 @@ public class UserMainCommand extends MainCommand<User, UserIdentifier> {
|
||||
}
|
||||
}
|
||||
|
||||
String name = plugin.getStorage().getName(uuid).join();
|
||||
String name = plugin.getStorage().getPlayerName(uuid).join();
|
||||
return UserIdentifier.of(uuid, name);
|
||||
}
|
||||
|
||||
|
@ -72,8 +72,8 @@ import me.lucko.luckperms.common.event.impl.EventUserFirstLogin;
|
||||
import me.lucko.luckperms.common.event.impl.EventUserLoad;
|
||||
import me.lucko.luckperms.common.event.impl.EventUserLoginProcess;
|
||||
import me.lucko.luckperms.common.event.impl.EventUserPromote;
|
||||
import me.lucko.luckperms.common.event.model.EntitySender;
|
||||
import me.lucko.luckperms.common.event.model.SourceEntity;
|
||||
import me.lucko.luckperms.common.event.model.EntitySourceImpl;
|
||||
import me.lucko.luckperms.common.event.model.SenderEntity;
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.model.Track;
|
||||
@ -268,12 +268,12 @@ public final class EventFactory {
|
||||
}
|
||||
|
||||
public void handleUserDemote(User user, Track track, String from, String to, Sender source) {
|
||||
EventUserDemote event = new EventUserDemote(track.getApiDelegate(), new ApiUser(user), from, to, new SourceEntity(new EntitySender(source)));
|
||||
EventUserDemote event = new EventUserDemote(track.getApiDelegate(), new ApiUser(user), from, to, new EntitySourceImpl(new SenderEntity(source)));
|
||||
fireEventAsync(event);
|
||||
}
|
||||
|
||||
public void handleUserPromote(User user, Track track, String from, String to, Sender source) {
|
||||
EventUserPromote event = new EventUserPromote(track.getApiDelegate(), new ApiUser(user), from, to, new SourceEntity(new EntitySender(source)));
|
||||
EventUserPromote event = new EventUserPromote(track.getApiDelegate(), new ApiUser(user), from, to, new EntitySourceImpl(new SenderEntity(source)));
|
||||
fireEventAsync(event);
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ import me.lucko.luckperms.api.Entity;
|
||||
import me.lucko.luckperms.api.LogEntry;
|
||||
import me.lucko.luckperms.api.event.log.LogNotifyEvent;
|
||||
import me.lucko.luckperms.common.event.AbstractEvent;
|
||||
import me.lucko.luckperms.common.event.model.EntitySender;
|
||||
import me.lucko.luckperms.common.event.model.SenderEntity;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@ -56,7 +56,7 @@ public class EventLogNotify extends AbstractEvent implements LogNotifyEvent {
|
||||
@Override
|
||||
public synchronized Entity getNotifiable() {
|
||||
if (this.notifiable == null) {
|
||||
this.notifiable = new EntitySender(this.sender);
|
||||
this.notifiable = new SenderEntity(this.sender);
|
||||
}
|
||||
return this.notifiable;
|
||||
}
|
||||
|
@ -30,10 +30,10 @@ import me.lucko.luckperms.api.event.source.EntitySource;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class SourceEntity implements EntitySource {
|
||||
public class EntitySourceImpl implements EntitySource {
|
||||
private final Entity entity;
|
||||
|
||||
public SourceEntity(Entity entity) {
|
||||
public EntitySourceImpl(Entity entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
@ -51,6 +51,6 @@ public class SourceEntity implements EntitySource {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Sender(type=ENTITY, entity=" + this.entity + ")";
|
||||
return "Source(type=ENTITY, entity=" + this.entity + ")";
|
||||
}
|
||||
}
|
@ -33,10 +33,10 @@ import java.util.UUID;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class EntitySender implements Entity {
|
||||
public class SenderEntity implements Entity {
|
||||
private final Sender sender;
|
||||
|
||||
public EntitySender(Sender sender) {
|
||||
public SenderEntity(Sender sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
@ -67,6 +67,6 @@ public class EntitySender implements Entity {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Sender(type=" + getType() + ", sender=" + this.sender + ")";
|
||||
return "SenderEntity(type=" + getType() + ", sender=" + this.sender + ")";
|
||||
}
|
||||
}
|
@ -29,10 +29,10 @@ import me.lucko.luckperms.api.event.source.Source;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public final class SourceUnknown implements Source {
|
||||
private static final Source INSTANCE = new SourceUnknown();
|
||||
public final class UnknownSource implements Source {
|
||||
private static final Source INSTANCE = new UnknownSource();
|
||||
|
||||
private SourceUnknown() {
|
||||
private UnknownSource() {
|
||||
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import me.lucko.luckperms.common.assignments.AssignmentRule;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.storage.PlayerSaveResult;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@ -61,11 +62,16 @@ public abstract class AbstractConnectionListener implements ConnectionListener {
|
||||
this.plugin.getUserManager().getHouseKeeper().registerUsage(u);
|
||||
|
||||
// save uuid data.
|
||||
String name = this.plugin.getStorage().noBuffer().getName(u).join();
|
||||
if (name == null) {
|
||||
PlayerSaveResult saveResult = this.plugin.getStorage().savePlayerData(u, username).join();
|
||||
if (saveResult.includes(PlayerSaveResult.Status.CLEAN_INSERT)) {
|
||||
this.plugin.getEventFactory().handleUserFirstLogin(u, username);
|
||||
}
|
||||
this.plugin.getStorage().noBuffer().saveUUIDData(u, username);
|
||||
|
||||
if (saveResult.includes(PlayerSaveResult.Status.OTHER_UUIDS_PRESENT_FOR_USERNAME)) {
|
||||
this.plugin.getLogger().warn("LuckPerms already has data for player '" + username + "' - but this data is stored under a different uuid.");
|
||||
this.plugin.getLogger().warn("'" + username + "' has previously used the unique ids " + saveResult.getOtherUuids() + " but is now connecting with '" + u + "'");
|
||||
this.plugin.getLogger().warn("This is usually because the server is not authenticating correctly. If you're using BungeeCord, please ensure that IP-Forwarding is setup correctly!");
|
||||
}
|
||||
|
||||
User user = this.plugin.getStorage().noBuffer().loadUser(u, username).join();
|
||||
if (user == null) {
|
||||
|
@ -309,7 +309,7 @@ public enum Message {
|
||||
|
||||
USER_INFO_GENERAL(
|
||||
"{PREFIX}&b&l> &bUser Info: &f{}" + "\n" +
|
||||
"{PREFIX}&f- &3UUID: &f{}" + "\n" +
|
||||
"{PREFIX}&f- &3UUID: &f{} &7(type: {}&7)" + "\n" +
|
||||
"{PREFIX}&f- &3Status: {}" + "\n" +
|
||||
"{PREFIX}&f- &3Primary Group: &f{}",
|
||||
false
|
||||
|
@ -290,17 +290,17 @@ public class AbstractStorage implements Storage {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> saveUUIDData(UUID uuid, String username) {
|
||||
return makeFuture(() -> this.dao.saveUUIDData(uuid, username));
|
||||
public CompletableFuture<PlayerSaveResult> savePlayerData(UUID uuid, String username) {
|
||||
return makeFuture(() -> this.dao.savePlayerData(uuid, username));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<UUID> getUUID(String username) {
|
||||
return makeFuture(() -> this.dao.getUUID(username));
|
||||
public CompletableFuture<UUID> getPlayerUuid(String username) {
|
||||
return makeFuture(() -> this.dao.getPlayerUuid(username));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<String> getName(UUID uuid) {
|
||||
return makeFuture(() -> this.dao.getName(uuid));
|
||||
public CompletableFuture<String> getPlayerName(UUID uuid) {
|
||||
return makeFuture(() -> this.dao.getPlayerName(uuid));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* 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.common.storage;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Represents the result to a player history save operation
|
||||
*/
|
||||
public final class PlayerSaveResult {
|
||||
private static final PlayerSaveResult CLEAN_INSERT = new PlayerSaveResult(Status.CLEAN_INSERT);
|
||||
private static final PlayerSaveResult NO_CHANGE = new PlayerSaveResult(Status.NO_CHANGE);
|
||||
|
||||
public static PlayerSaveResult cleanInsert() {
|
||||
return CLEAN_INSERT;
|
||||
}
|
||||
|
||||
public static PlayerSaveResult noChange() {
|
||||
return NO_CHANGE;
|
||||
}
|
||||
|
||||
public static PlayerSaveResult usernameUpdated(String oldUsername) {
|
||||
return new PlayerSaveResult(oldUsername, null, Status.USERNAME_UPDATED);
|
||||
}
|
||||
|
||||
public static PlayerSaveResult determineBaseResult(String username, String oldUsername) {
|
||||
PlayerSaveResult result;
|
||||
if (oldUsername == null) {
|
||||
result = PlayerSaveResult.cleanInsert();
|
||||
} else if (oldUsername.equalsIgnoreCase(username)) {
|
||||
result = PlayerSaveResult.noChange();
|
||||
} else {
|
||||
result = PlayerSaveResult.usernameUpdated(oldUsername);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private final Set<Status> status;
|
||||
@Nullable private final String oldUsername;
|
||||
@Nullable private final Set<UUID> otherUuids;
|
||||
|
||||
private PlayerSaveResult(EnumSet<Status> status, @Nullable String oldUsername, @Nullable Set<UUID> otherUuids) {
|
||||
this.status = ImmutableSet.copyOf(status);
|
||||
this.oldUsername = oldUsername;
|
||||
this.otherUuids = otherUuids;
|
||||
}
|
||||
|
||||
private PlayerSaveResult(@Nullable String oldUsername, @Nullable Set<UUID> otherUuids, Status... status) {
|
||||
this(EnumSet.copyOf(Arrays.asList(status)), oldUsername, otherUuids);
|
||||
}
|
||||
|
||||
private PlayerSaveResult(Status... status) {
|
||||
this(null, null, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link PlayerSaveResult} with the {@link Status#OTHER_UUIDS_PRESENT_FOR_USERNAME}
|
||||
* status attached to the state of this result.
|
||||
*
|
||||
* @param otherUuids the other uuids
|
||||
* @return a new result
|
||||
*/
|
||||
public PlayerSaveResult withOtherUuidsPresent(@Nonnull Set<UUID> otherUuids) {
|
||||
EnumSet<Status> status = EnumSet.copyOf(this.status);
|
||||
status.add(Status.OTHER_UUIDS_PRESENT_FOR_USERNAME);
|
||||
return new PlayerSaveResult(status, this.oldUsername, ImmutableSet.copyOf(otherUuids));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status returned by the operation
|
||||
*
|
||||
* @return the status
|
||||
*/
|
||||
public Set<Status> getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets if the result includes a certain status code.
|
||||
*
|
||||
* @param status the status to check for
|
||||
* @return if the result includes the status
|
||||
*/
|
||||
public boolean includes(Status status) {
|
||||
return this.status.contains(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the old username involved in the result
|
||||
*
|
||||
* @return the old username
|
||||
* @see Status#USERNAME_UPDATED
|
||||
*/
|
||||
@Nullable
|
||||
public String getOldUsername() {
|
||||
return this.oldUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the other uuids involved in the result
|
||||
*
|
||||
* @return the other uuids
|
||||
* @see Status#OTHER_UUIDS_PRESENT_FOR_USERNAME
|
||||
*/
|
||||
@Nullable
|
||||
public Set<UUID> getOtherUuids() {
|
||||
return this.otherUuids;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
if (this == that) return true;
|
||||
if (that == null || getClass() != that.getClass()) return false;
|
||||
PlayerSaveResult result = (PlayerSaveResult) that;
|
||||
return Objects.equals(this.status, result.status) &&
|
||||
Objects.equals(this.oldUsername, result.oldUsername) &&
|
||||
Objects.equals(this.otherUuids, result.otherUuids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.status, this.oldUsername, this.otherUuids);
|
||||
}
|
||||
|
||||
/**
|
||||
* The various states the result can take
|
||||
*/
|
||||
public enum Status {
|
||||
|
||||
/**
|
||||
* There was no existing data saved for either the uuid or username
|
||||
*/
|
||||
CLEAN_INSERT,
|
||||
|
||||
/**
|
||||
* There was existing data for the player, no change was needed.
|
||||
*/
|
||||
NO_CHANGE,
|
||||
|
||||
/**
|
||||
* There was already a record for the UUID saved, but it was for a different username.
|
||||
*
|
||||
* <p>This is normal, players are able to change their usernames.</p>
|
||||
*/
|
||||
USERNAME_UPDATED,
|
||||
|
||||
/**
|
||||
* There was already a record for the username saved, but it was under a different uuid.
|
||||
*
|
||||
* <p>This is a bit of a cause for concern. It's possible that "player1" has changed
|
||||
* their username to "player2", and "player3" has changed their username to "player1".
|
||||
* If the original "player1" doesn't join after changing their name, this conflict could
|
||||
* occur.</p>
|
||||
*
|
||||
* <p>However, what's more likely is that the server is not setup to authenticate
|
||||
* correctly. Usually this is a problem with BungeeCord "ip-forwarding", but could be
|
||||
* that the user of the plugin is running a network off a shared database with one
|
||||
* server in online mode and another in offline mode.</p>
|
||||
*/
|
||||
OTHER_UUIDS_PRESENT_FOR_USERNAME,
|
||||
}
|
||||
}
|
@ -99,9 +99,9 @@ public interface Storage {
|
||||
|
||||
CompletableFuture<Void> deleteTrack(Track track, DeletionCause cause);
|
||||
|
||||
CompletableFuture<Void> saveUUIDData(UUID uuid, String username);
|
||||
CompletableFuture<PlayerSaveResult> savePlayerData(UUID uuid, String username);
|
||||
|
||||
CompletableFuture<UUID> getUUID(String username);
|
||||
CompletableFuture<UUID> getPlayerUuid(String username);
|
||||
|
||||
CompletableFuture<String> getName(UUID uuid);
|
||||
CompletableFuture<String> getPlayerName(UUID uuid);
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.Track;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.storage.PlayerSaveResult;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -105,12 +106,12 @@ public abstract class AbstractDao {
|
||||
|
||||
public abstract void deleteTrack(Track track) throws Exception;
|
||||
|
||||
public abstract void saveUUIDData(UUID uuid, String username) throws Exception;
|
||||
public abstract PlayerSaveResult savePlayerData(UUID uuid, String username) throws Exception;
|
||||
|
||||
@Nullable
|
||||
public abstract UUID getUUID(String username) throws Exception;
|
||||
public abstract UUID getPlayerUuid(String username) throws Exception;
|
||||
|
||||
@Nullable
|
||||
public abstract String getName(UUID uuid) throws Exception;
|
||||
public abstract String getPlayerName(UUID uuid) throws Exception;
|
||||
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.Track;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.storage.PlayerSaveResult;
|
||||
import me.lucko.luckperms.common.storage.SplitStorageType;
|
||||
import me.lucko.luckperms.common.storage.StorageType;
|
||||
|
||||
@ -191,17 +192,17 @@ public class SplitStorageDao extends AbstractDao {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveUUIDData(UUID uuid, String username) throws Exception {
|
||||
this.backing.get(this.types.get(SplitStorageType.UUID)).saveUUIDData(uuid, username);
|
||||
public PlayerSaveResult savePlayerData(UUID uuid, String username) throws Exception {
|
||||
return this.backing.get(this.types.get(SplitStorageType.UUID)).savePlayerData(uuid, username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID(String username) throws Exception {
|
||||
return this.backing.get(this.types.get(SplitStorageType.UUID)).getUUID(username);
|
||||
public UUID getPlayerUuid(String username) throws Exception {
|
||||
return this.backing.get(this.types.get(SplitStorageType.UUID)).getPlayerUuid(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(UUID uuid) throws Exception {
|
||||
return this.backing.get(this.types.get(SplitStorageType.UUID)).getName(uuid);
|
||||
public String getPlayerName(UUID uuid) throws Exception {
|
||||
return this.backing.get(this.types.get(SplitStorageType.UUID)).getPlayerName(uuid);
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ import me.lucko.luckperms.common.node.NodeHeldPermission;
|
||||
import me.lucko.luckperms.common.node.NodeModel;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.references.UserIdentifier;
|
||||
import me.lucko.luckperms.common.storage.PlayerSaveResult;
|
||||
import me.lucko.luckperms.common.storage.dao.AbstractDao;
|
||||
import me.lucko.luckperms.common.utils.ImmutableCollectors;
|
||||
import me.lucko.luckperms.common.utils.Uuids;
|
||||
@ -670,17 +671,17 @@ public abstract class ConfigurateDao extends AbstractDao {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveUUIDData(UUID uuid, String username) {
|
||||
this.uuidCache.addMapping(uuid, username);
|
||||
public PlayerSaveResult savePlayerData(UUID uuid, String username) {
|
||||
return this.uuidCache.addMapping(uuid, username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID(String username) {
|
||||
return this.uuidCache.lookup(username);
|
||||
public UUID getPlayerUuid(String username) {
|
||||
return this.uuidCache.lookupUuid(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(UUID uuid) {
|
||||
public String getPlayerName(UUID uuid) {
|
||||
return this.uuidCache.lookupUsername(uuid);
|
||||
}
|
||||
|
||||
|
@ -26,9 +26,12 @@
|
||||
package me.lucko.luckperms.common.storage.dao.file;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import com.google.common.collect.SetMultimap;
|
||||
|
||||
import me.lucko.luckperms.common.utils.DateUtil;
|
||||
import me.lucko.luckperms.common.storage.PlayerSaveResult;
|
||||
import me.lucko.luckperms.common.utils.Uuids;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
@ -36,19 +39,60 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class FileUuidCache {
|
||||
private static final Splitter KV_SPLIT = Splitter.on('=').omitEmptyStrings();
|
||||
private static final Splitter TIME_SPLIT = Splitter.on('|').omitEmptyStrings();
|
||||
private static final Splitter KV_SPLIT = Splitter.on(':').omitEmptyStrings();
|
||||
private static final Splitter LEGACY_KV_SPLIT = Splitter.on('=').omitEmptyStrings();
|
||||
private static final Splitter LEGACY_TIME_SPLIT = Splitter.on('|').omitEmptyStrings();
|
||||
|
||||
// the map for lookups
|
||||
private final Map<String, Map.Entry<UUID, Long>> lookupMap = new ConcurrentHashMap<>();
|
||||
// the lookup map
|
||||
private final LookupMap lookupMap = new LookupMap();
|
||||
|
||||
private static final class LookupMap extends ConcurrentHashMap<UUID, String> {
|
||||
private final SetMultimap<String, UUID> reverse = Multimaps.newSetMultimap(new ConcurrentHashMap<>(), ConcurrentHashMap::newKeySet);
|
||||
|
||||
@Override
|
||||
public String put(UUID key, String value) {
|
||||
String existing = super.put(key, value);
|
||||
|
||||
// check if we need to remove a reverse entry which has been replaced
|
||||
// existing might be null
|
||||
if (!value.equalsIgnoreCase(existing)) {
|
||||
if (existing != null) {
|
||||
this.reverse.remove(existing.toLowerCase(), key);
|
||||
}
|
||||
}
|
||||
|
||||
this.reverse.put(value.toLowerCase(), key);
|
||||
return existing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String remove(Object k) {
|
||||
UUID key = (UUID) k;
|
||||
String username = super.remove(key);
|
||||
if (username != null) {
|
||||
this.reverse.remove(username.toLowerCase(), key);
|
||||
}
|
||||
return username;
|
||||
}
|
||||
|
||||
public String lookupUsername(UUID uuid) {
|
||||
return super.get(uuid);
|
||||
}
|
||||
|
||||
public Set<UUID> lookupUuid(String name) {
|
||||
return this.reverse.get(name.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a mapping to the cache
|
||||
@ -56,8 +100,25 @@ public class FileUuidCache {
|
||||
* @param uuid the uuid of the player
|
||||
* @param username the username of the player
|
||||
*/
|
||||
public void addMapping(UUID uuid, String username) {
|
||||
this.lookupMap.put(username.toLowerCase(), Maps.immutableEntry(uuid, DateUtil.unixSecondsNow()));
|
||||
public PlayerSaveResult addMapping(UUID uuid, String username) {
|
||||
// perform the insert
|
||||
String oldUsername = this.lookupMap.put(uuid, username);
|
||||
|
||||
PlayerSaveResult result = PlayerSaveResult.determineBaseResult(username, oldUsername);
|
||||
|
||||
Set<UUID> conflicting = new HashSet<>(this.lookupMap.lookupUuid(username));
|
||||
conflicting.remove(uuid);
|
||||
|
||||
if (!conflicting.isEmpty()) {
|
||||
// remove the mappings for conflicting uuids
|
||||
for (UUID conflict : conflicting) {
|
||||
this.lookupMap.remove(conflict);
|
||||
}
|
||||
|
||||
result = result.withOtherUuidsPresent(conflicting);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -67,9 +128,9 @@ public class FileUuidCache {
|
||||
* @return a uuid, or null
|
||||
*/
|
||||
@Nullable
|
||||
public UUID lookup(String username) {
|
||||
Map.Entry<UUID, Long> ret = this.lookupMap.get(username.toLowerCase());
|
||||
return ret == null ? null : ret.getKey();
|
||||
public UUID lookupUuid(String username) {
|
||||
Set<UUID> uuids = this.lookupMap.lookupUuid(username);
|
||||
return Iterables.getFirst(uuids, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -79,23 +140,46 @@ public class FileUuidCache {
|
||||
* @return a username, or null
|
||||
*/
|
||||
public String lookupUsername(UUID uuid) {
|
||||
String username = null;
|
||||
Long time = Long.MIN_VALUE;
|
||||
return this.lookupMap.lookupUsername(uuid);
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Map.Entry<UUID, Long>> ent : this.lookupMap.entrySet()) {
|
||||
if (!ent.getValue().getKey().equals(uuid)) {
|
||||
continue;
|
||||
private void loadEntry(String entry) {
|
||||
if (entry.contains(":")) {
|
||||
// new format
|
||||
Iterator<String> parts = KV_SPLIT.split(entry).iterator();
|
||||
|
||||
if (!parts.hasNext()) return;
|
||||
String uuidPart = parts.next();
|
||||
|
||||
if (!parts.hasNext()) return;
|
||||
String usernamePart = parts.next();
|
||||
|
||||
UUID uuid = Uuids.fromString(uuidPart);
|
||||
if (uuid == null) return;
|
||||
|
||||
this.lookupMap.put(uuid, usernamePart);
|
||||
} else if (entry.contains("=")) {
|
||||
// old format
|
||||
Iterator<String> parts = LEGACY_KV_SPLIT.split(entry).iterator();
|
||||
|
||||
if (!parts.hasNext()) return;
|
||||
String usernamePart = parts.next();
|
||||
|
||||
if (!parts.hasNext()) return;
|
||||
String uuidPart = parts.next();
|
||||
|
||||
// contains a time
|
||||
if (uuidPart.contains("|")) {
|
||||
Iterator<String> valueParts = LEGACY_TIME_SPLIT.split(uuidPart).iterator();
|
||||
if (!valueParts.hasNext()) return;
|
||||
uuidPart = valueParts.next();
|
||||
}
|
||||
|
||||
Long t = ent.getValue().getValue();
|
||||
UUID uuid = Uuids.fromString(uuidPart);
|
||||
if (uuid == null) return;
|
||||
|
||||
if (t > time) {
|
||||
time = t;
|
||||
username = ent.getKey();
|
||||
}
|
||||
this.lookupMap.put(uuid, usernamePart);
|
||||
}
|
||||
|
||||
return username;
|
||||
}
|
||||
|
||||
public void load(File file) {
|
||||
@ -104,61 +188,14 @@ public class FileUuidCache {
|
||||
}
|
||||
|
||||
try (BufferedReader reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {
|
||||
|
||||
String entry;
|
||||
while ((entry = reader.readLine()) != null) {
|
||||
entry = entry.trim();
|
||||
if (entry.isEmpty() || entry.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Iterator<String> parts = KV_SPLIT.split(entry).iterator();
|
||||
|
||||
if (!parts.hasNext()) continue;
|
||||
String key = parts.next();
|
||||
|
||||
if (!parts.hasNext()) continue;
|
||||
String value = parts.next();
|
||||
|
||||
UUID uid;
|
||||
Long t;
|
||||
|
||||
// contains a time (backwards compat)
|
||||
if (value.contains("|")) {
|
||||
// try to split and extract the time element from the end.
|
||||
Iterator<String> valueParts = TIME_SPLIT.split(value).iterator();
|
||||
|
||||
if (!valueParts.hasNext()) continue;
|
||||
String uuid = valueParts.next();
|
||||
|
||||
if (!valueParts.hasNext()) continue;
|
||||
String time = valueParts.next();
|
||||
|
||||
try {
|
||||
uid = UUID.fromString(uuid);
|
||||
} catch (IllegalArgumentException e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
t = Long.parseLong(time);
|
||||
} catch (NumberFormatException e) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// just parse from the value
|
||||
try {
|
||||
uid = UUID.fromString(value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
t = 0L;
|
||||
}
|
||||
|
||||
this.lookupMap.put(key, Maps.immutableEntry(uid, t));
|
||||
loadEntry(entry);
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -168,13 +205,11 @@ public class FileUuidCache {
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) {
|
||||
writer.write("# LuckPerms UUID lookup cache");
|
||||
writer.newLine();
|
||||
|
||||
for (Map.Entry<String, Map.Entry<UUID, Long>> ent : this.lookupMap.entrySet()) {
|
||||
String out = ent.getKey() + "=" + ent.getValue().getKey().toString() + "|" + ent.getValue().getValue().toString();
|
||||
for (Map.Entry<UUID, String> ent : this.lookupMap.entrySet()) {
|
||||
String out = ent.getKey() + ":" + ent.getValue();
|
||||
writer.write(out);
|
||||
writer.newLine();
|
||||
}
|
||||
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
|
@ -34,6 +34,7 @@ import com.mongodb.ServerAddress;
|
||||
import com.mongodb.client.MongoCollection;
|
||||
import com.mongodb.client.MongoCursor;
|
||||
import com.mongodb.client.MongoDatabase;
|
||||
import com.mongodb.client.model.Filters;
|
||||
import com.mongodb.client.model.UpdateOptions;
|
||||
|
||||
import me.lucko.luckperms.api.HeldPermission;
|
||||
@ -56,6 +57,7 @@ import me.lucko.luckperms.common.node.NodeHeldPermission;
|
||||
import me.lucko.luckperms.common.node.NodeModel;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.references.UserIdentifier;
|
||||
import me.lucko.luckperms.common.storage.PlayerSaveResult;
|
||||
import me.lucko.luckperms.common.storage.StorageCredentials;
|
||||
import me.lucko.luckperms.common.storage.dao.AbstractDao;
|
||||
|
||||
@ -569,29 +571,53 @@ public class MongoDao extends AbstractDao {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveUUIDData(UUID uuid, String username) {
|
||||
public PlayerSaveResult savePlayerData(UUID uuid, String username) {
|
||||
username = username.toLowerCase();
|
||||
MongoCollection<Document> c = this.database.getCollection(this.prefix + "uuid");
|
||||
c.replaceOne(new Document("_id", uuid), new Document("_id", uuid).append("name", username.toLowerCase()), new UpdateOptions().upsert(true));
|
||||
|
||||
// find any existing mapping
|
||||
String oldUsername = getPlayerName(uuid);
|
||||
|
||||
// do the insert
|
||||
if (!username.equalsIgnoreCase(oldUsername)) {
|
||||
c.replaceOne(new Document("_id", uuid), new Document("_id", uuid).append("name", username), new UpdateOptions().upsert(true));
|
||||
}
|
||||
|
||||
PlayerSaveResult result = PlayerSaveResult.determineBaseResult(username, oldUsername);
|
||||
|
||||
Set<UUID> conflicting = new HashSet<>();
|
||||
try (MongoCursor<Document> cursor = c.find(new Document("name", username)).iterator()) {
|
||||
if (cursor.hasNext()) {
|
||||
conflicting.add(cursor.next().get("_id", UUID.class));
|
||||
}
|
||||
}
|
||||
conflicting.remove(uuid);
|
||||
|
||||
if (!conflicting.isEmpty()) {
|
||||
// remove the mappings for conflicting uuids
|
||||
c.deleteMany(Filters.and(conflicting.stream().map(u -> Filters.eq("_id", u)).collect(Collectors.toList())));
|
||||
result = result.withOtherUuidsPresent(conflicting);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID(String username) {
|
||||
public UUID getPlayerUuid(String username) {
|
||||
MongoCollection<Document> c = this.database.getCollection(this.prefix + "uuid");
|
||||
try (MongoCursor<Document> cursor = c.find(new Document("name", username.toLowerCase())).iterator()) {
|
||||
if (cursor.hasNext()) {
|
||||
return cursor.next().get("_id", UUID.class);
|
||||
}
|
||||
Document doc = c.find(new Document("name", username.toLowerCase())).first();
|
||||
if (doc != null) {
|
||||
return doc.get("_id", UUID.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(UUID uuid) {
|
||||
public String getPlayerName(UUID uuid) {
|
||||
MongoCollection<Document> c = this.database.getCollection(this.prefix + "uuid");
|
||||
try (MongoCursor<Document> cursor = c.find(new Document("_id", uuid)).iterator()) {
|
||||
if (cursor.hasNext()) {
|
||||
return cursor.next().get("name", String.class);
|
||||
}
|
||||
Document doc = c.find(new Document("_id", uuid)).first();
|
||||
if (doc != null) {
|
||||
return doc.get("name", String.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ import me.lucko.luckperms.common.node.NodeHeldPermission;
|
||||
import me.lucko.luckperms.common.node.NodeModel;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.references.UserIdentifier;
|
||||
import me.lucko.luckperms.common.storage.PlayerSaveResult;
|
||||
import me.lucko.luckperms.common.storage.dao.AbstractDao;
|
||||
import me.lucko.luckperms.common.storage.dao.sql.connection.AbstractConnectionFactory;
|
||||
import me.lucko.luckperms.common.storage.dao.sql.connection.file.SQLiteConnectionFactory;
|
||||
@ -68,8 +69,6 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -83,14 +82,15 @@ public class SqlDao extends AbstractDao {
|
||||
private static final String USER_PERMISSIONS_SELECT_DISTINCT = "SELECT DISTINCT uuid FROM {prefix}user_permissions";
|
||||
private static final String USER_PERMISSIONS_SELECT_PERMISSION = "SELECT uuid, value, server, world, expiry, contexts FROM {prefix}user_permissions WHERE permission=?";
|
||||
|
||||
private static final String PLAYER_SELECT = "SELECT username, primary_group FROM {prefix}players WHERE uuid=?";
|
||||
private static final String PLAYER_SELECT_UUID = "SELECT uuid FROM {prefix}players WHERE username=? LIMIT 1";
|
||||
private static final String PLAYER_SELECT_USERNAME = "SELECT username FROM {prefix}players WHERE uuid=? LIMIT 1";
|
||||
private static final String PLAYER_SELECT_PRIMARY_GROUP = "SELECT primary_group FROM {prefix}players WHERE uuid=? LIMIT 1";
|
||||
private static final String PLAYER_SELECT_UUID_BY_USERNAME = "SELECT uuid FROM {prefix}players WHERE username=? LIMIT 1";
|
||||
private static final String PLAYER_SELECT_USERNAME_BY_UUID = "SELECT username FROM {prefix}players WHERE uuid=? LIMIT 1";
|
||||
private static final String PLAYER_UPDATE_USERNAME_FOR_UUID = "UPDATE {prefix}players SET username=? WHERE uuid=?";
|
||||
private static final String PLAYER_INSERT = "INSERT INTO {prefix}players VALUES(?, ?, ?)";
|
||||
private static final String PLAYER_UPDATE = "UPDATE {prefix}players SET username=? WHERE uuid=?";
|
||||
private static final String PLAYER_DELETE = "DELETE FROM {prefix}players WHERE username=? AND NOT uuid=?";
|
||||
private static final String PLAYER_UPDATE_PRIMARY_GROUP = "UPDATE {prefix}players SET primary_group=? WHERE uuid=?";
|
||||
private static final String PLAYER_SELECT_ALL_UUIDS_BY_USERNAME = "SELECT uuid FROM {prefix}players WHERE username=? AND NOT uuid=?";
|
||||
private static final String PLAYER_DELETE_ALL_UUIDS_BY_USERNAME = "DELETE FROM {prefix}players WHERE username=? AND NOT uuid=?";
|
||||
private static final String PLAYER_SELECT_BY_UUID = "SELECT username, primary_group FROM {prefix}players WHERE uuid=?";
|
||||
private static final String PLAYER_SELECT_PRIMARY_GROUP_BY_UUID = "SELECT primary_group FROM {prefix}players WHERE uuid=? LIMIT 1";
|
||||
private static final String PLAYER_UPDATE_PRIMARY_GROUP_BY_UUID = "UPDATE {prefix}players SET primary_group=? WHERE uuid=?";
|
||||
|
||||
private static final String GROUP_PERMISSIONS_SELECT = "SELECT permission, value, server, world, expiry, contexts FROM {prefix}group_permissions WHERE name=?";
|
||||
private static final String GROUP_PERMISSIONS_DELETE = "DELETE FROM {prefix}group_permissions WHERE name=?";
|
||||
@ -295,8 +295,8 @@ public class SqlDao extends AbstractDao {
|
||||
user.getIoLock().lock();
|
||||
try {
|
||||
List<NodeModel> data = new ArrayList<>();
|
||||
AtomicReference<String> primaryGroup = new AtomicReference<>(null);
|
||||
AtomicReference<String> userName = new AtomicReference<>(null);
|
||||
String primaryGroup = null;
|
||||
String userName = null;
|
||||
|
||||
// Collect user permissions
|
||||
try (Connection c = this.provider.getConnection()) {
|
||||
@ -319,27 +319,26 @@ public class SqlDao extends AbstractDao {
|
||||
|
||||
// Collect user meta (username & primary group)
|
||||
try (Connection c = this.provider.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_SELECT))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_SELECT_BY_UUID))) {
|
||||
ps.setString(1, user.getUuid().toString());
|
||||
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
userName.set(rs.getString("username"));
|
||||
primaryGroup.set(rs.getString("primary_group"));
|
||||
userName = rs.getString("username");
|
||||
primaryGroup = rs.getString("primary_group");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update username & primary group
|
||||
String pg = primaryGroup.get();
|
||||
if (pg == null) {
|
||||
pg = NodeFactory.DEFAULT_GROUP_NAME;
|
||||
if (primaryGroup == null) {
|
||||
primaryGroup = NodeFactory.DEFAULT_GROUP_NAME;
|
||||
}
|
||||
user.getPrimaryGroup().setStoredValue(pg);
|
||||
user.getPrimaryGroup().setStoredValue(primaryGroup);
|
||||
|
||||
// Update their username to what was in the storage if the one in the local instance is null
|
||||
user.setName(userName.get(), true);
|
||||
user.setName(userName, true);
|
||||
|
||||
// If the user has any data in storage
|
||||
if (!data.isEmpty()) {
|
||||
@ -378,7 +377,7 @@ public class SqlDao extends AbstractDao {
|
||||
ps.setString(1, user.getUuid().toString());
|
||||
ps.execute();
|
||||
}
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_UPDATE_PRIMARY_GROUP))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_UPDATE_PRIMARY_GROUP_BY_UUID))) {
|
||||
ps.setString(1, NodeFactory.DEFAULT_GROUP_NAME);
|
||||
ps.setString(2, user.getUuid().toString());
|
||||
ps.execute();
|
||||
@ -453,7 +452,7 @@ public class SqlDao extends AbstractDao {
|
||||
try (Connection c = this.provider.getConnection()) {
|
||||
boolean hasPrimaryGroupSaved;
|
||||
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_SELECT_PRIMARY_GROUP))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_SELECT_PRIMARY_GROUP_BY_UUID))) {
|
||||
ps.setString(1, user.getUuid().toString());
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
hasPrimaryGroupSaved = rs.next();
|
||||
@ -462,7 +461,7 @@ public class SqlDao extends AbstractDao {
|
||||
|
||||
if (hasPrimaryGroupSaved) {
|
||||
// update
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_UPDATE_PRIMARY_GROUP))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_UPDATE_PRIMARY_GROUP_BY_UUID))) {
|
||||
ps.setString(1, user.getPrimaryGroup().getStoredValue().orElse(NodeFactory.DEFAULT_GROUP_NAME));
|
||||
ps.setString(2, user.getUuid().toString());
|
||||
ps.execute();
|
||||
@ -772,24 +771,23 @@ public class SqlDao extends AbstractDao {
|
||||
Track track = this.plugin.getTrackManager().getOrMake(name);
|
||||
track.getIoLock().lock();
|
||||
try {
|
||||
AtomicBoolean exists = new AtomicBoolean(false);
|
||||
AtomicReference<String> groups = new AtomicReference<>(null);
|
||||
|
||||
boolean exists = false;
|
||||
String groups = null;
|
||||
try (Connection c = this.provider.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(TRACK_SELECT))) {
|
||||
ps.setString(1, track.getName());
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
exists.set(true);
|
||||
groups.set(rs.getString("groups"));
|
||||
exists = true;
|
||||
groups = rs.getString("groups");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exists.get()) {
|
||||
if (exists) {
|
||||
// Track exists, let's load.
|
||||
track.setGroups(this.gson.fromJson(groups.get(), LIST_STRING_TYPE));
|
||||
track.setGroups(this.gson.fromJson(groups, LIST_STRING_TYPE));
|
||||
} else {
|
||||
String json = this.gson.toJson(track.getGroups());
|
||||
try (Connection c = this.provider.getConnection()) {
|
||||
@ -813,14 +811,13 @@ public class SqlDao extends AbstractDao {
|
||||
track.getIoLock().lock();
|
||||
}
|
||||
try {
|
||||
AtomicReference<String> groups = new AtomicReference<>(null);
|
||||
|
||||
String groups;
|
||||
try (Connection c = this.provider.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(TRACK_SELECT))) {
|
||||
ps.setString(1, name);
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
groups.set(rs.getString("groups"));
|
||||
groups = rs.getString("groups");
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
@ -833,7 +830,7 @@ public class SqlDao extends AbstractDao {
|
||||
track.getIoLock().lock();
|
||||
}
|
||||
|
||||
track.setGroups(this.gson.fromJson(groups.get(), LIST_STRING_TYPE));
|
||||
track.setGroups(this.gson.fromJson(groups, LIST_STRING_TYPE));
|
||||
return Optional.of(track);
|
||||
|
||||
} finally {
|
||||
@ -911,91 +908,91 @@ public class SqlDao extends AbstractDao {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveUUIDData(UUID uuid, String username) throws SQLException {
|
||||
final String u = username.toLowerCase();
|
||||
AtomicReference<String> remoteUserName = new AtomicReference<>(null);
|
||||
public PlayerSaveResult savePlayerData(UUID uuid, String username) throws SQLException {
|
||||
username = username.toLowerCase();
|
||||
|
||||
// cleanup any old values
|
||||
try (Connection c = this.provider.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_DELETE))) {
|
||||
ps.setString(1, u);
|
||||
ps.setString(2, uuid.toString());
|
||||
ps.execute();
|
||||
}
|
||||
}
|
||||
// find any existing mapping
|
||||
String oldUsername = getPlayerName(uuid);
|
||||
|
||||
try (Connection c = this.provider.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_SELECT_USERNAME))) {
|
||||
ps.setString(1, uuid.toString());
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
remoteUserName.set(rs.getString("username"));
|
||||
// do the insert
|
||||
if (!username.equalsIgnoreCase(oldUsername)) {
|
||||
try (Connection c = this.provider.getConnection()) {
|
||||
if (oldUsername != null) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_UPDATE_USERNAME_FOR_UUID))) {
|
||||
ps.setString(1, username);
|
||||
ps.setString(2, uuid.toString());
|
||||
ps.execute();
|
||||
}
|
||||
} else {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_INSERT))) {
|
||||
ps.setString(1, uuid.toString());
|
||||
ps.setString(2, username);
|
||||
ps.setString(3, NodeFactory.DEFAULT_GROUP_NAME);
|
||||
ps.execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (remoteUserName.get() != null) {
|
||||
// the value is already correct
|
||||
if (remoteUserName.get().equals(u)) {
|
||||
return;
|
||||
}
|
||||
PlayerSaveResult result = PlayerSaveResult.determineBaseResult(username, oldUsername);
|
||||
|
||||
Set<UUID> conflicting = new HashSet<>();
|
||||
try (Connection c = this.provider.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_SELECT_ALL_UUIDS_BY_USERNAME))) {
|
||||
ps.setString(1, username);
|
||||
ps.setString(2, uuid.toString());
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
conflicting.add(UUID.fromString(rs.getString("uuid")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!conflicting.isEmpty()) {
|
||||
// remove the mappings for conflicting uuids
|
||||
try (Connection c = this.provider.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_UPDATE))) {
|
||||
ps.setString(1, u);
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_DELETE_ALL_UUIDS_BY_USERNAME))) {
|
||||
ps.setString(1, username);
|
||||
ps.setString(2, uuid.toString());
|
||||
ps.execute();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// first time we've seen this uuid
|
||||
try (Connection c = this.provider.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_INSERT))) {
|
||||
ps.setString(1, uuid.toString());
|
||||
ps.setString(2, u);
|
||||
ps.setString(3, NodeFactory.DEFAULT_GROUP_NAME);
|
||||
ps.execute();
|
||||
}
|
||||
}
|
||||
result = result.withOtherUuidsPresent(conflicting);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID(String username) throws SQLException {
|
||||
final String u = username.toLowerCase();
|
||||
final AtomicReference<UUID> uuid = new AtomicReference<>(null);
|
||||
|
||||
public UUID getPlayerUuid(String username) throws SQLException {
|
||||
username = username.toLowerCase();
|
||||
try (Connection c = this.provider.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_SELECT_UUID))) {
|
||||
ps.setString(1, u);
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_SELECT_UUID_BY_USERNAME))) {
|
||||
ps.setString(1, username);
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
uuid.set(UUID.fromString(rs.getString("uuid")));
|
||||
return UUID.fromString(rs.getString("uuid"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return uuid.get();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(UUID uuid) throws SQLException {
|
||||
final AtomicReference<String> name = new AtomicReference<>(null);
|
||||
|
||||
public String getPlayerName(UUID uuid) throws SQLException {
|
||||
try (Connection c = this.provider.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_SELECT_USERNAME))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.prefix.apply(PLAYER_SELECT_USERNAME_BY_UUID))) {
|
||||
ps.setString(1, uuid.toString());
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
name.set(rs.getString("username"));
|
||||
return rs.getString("username");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return name.get();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,7 +41,7 @@ public final class Uuids {
|
||||
public static final Predicate<String> PREDICATE = s -> parseNullable(s) != null;
|
||||
|
||||
@Nullable
|
||||
private static UUID fromString(String s) {
|
||||
public static UUID fromString(String s) {
|
||||
try {
|
||||
return UUID.fromString(s);
|
||||
} catch (IllegalArgumentException e) {
|
||||
|
Loading…
Reference in New Issue
Block a user