More profile stuff

This commit is contained in:
Vankka 2022-02-24 17:09:53 +02:00
parent ee1db84ae0
commit ed674cce8a
No known key found for this signature in database
GPG Key ID: 6E50CB7A29B96AD0
31 changed files with 282 additions and 100 deletions

View File

@ -63,6 +63,7 @@ public interface DiscordSRVApi {
* The profile manager, access the profiles of players and/or users.
* @return the instance of {@link IProfileManager}
*/
@NotNull
IProfileManager profileManager();
/**
@ -177,30 +178,24 @@ public interface DiscordSRVApi {
* DiscordSRV is shutting down.
* @see #isShutdown()
*/
SHUTTING_DOWN(false, true),
SHUTTING_DOWN,
/**
* DiscordSRV has shutdown.
* @see #isShutdown()
*/
SHUTDOWN(false, true),
SHUTDOWN,
;
private final boolean error;
private final boolean shutdown;
Status() {
this(false);
}
Status(boolean error) {
this(error, false);
}
Status(boolean error, boolean shutdown) {
this.error = error;
this.shutdown = shutdown;
}
public boolean isError() {
@ -208,7 +203,7 @@ public interface DiscordSRVApi {
}
public boolean isShutdown() {
return shutdown;
return this == SHUTDOWN || this == SHUTTING_DOWN;
}
public boolean isStartupError() {

View File

@ -23,20 +23,21 @@
package com.discordsrv.api.profile;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
import java.util.UUID;
public interface IProfile {
@Nullable
UUID uniqueId();
@NotNull
Optional<UUID> playerUUID();
@Nullable
Long userId();
@NotNull
Optional<Long> userId();
default boolean isLinked() {
return uniqueId() != null && userId() != null;
return playerUUID().isPresent() && userId().isPresent();
}
}

View File

@ -29,11 +29,11 @@ import java.util.concurrent.CompletableFuture;
public interface IProfileManager {
CompletableFuture<Optional<IProfile>> lookupProfile(UUID playerUUID);
CompletableFuture<? extends IProfile> lookupProfile(UUID playerUUID);
Optional<IProfile> getProfile(UUID playerUUID);
Optional<? extends IProfile> getProfile(UUID playerUUID);
CompletableFuture<Optional<IProfile>> lookupProfile(long userId);
CompletableFuture<? extends IProfile> lookupProfile(long userId);
Optional<IProfile> getProfile(long userId);
Optional<? extends IProfile> getProfile(long userId);
}

View File

@ -26,6 +26,7 @@ import com.discordsrv.bukkit.config.manager.BukkitConnectionConfigManager;
import com.discordsrv.bukkit.console.BukkitConsole;
import com.discordsrv.bukkit.integration.VaultIntegration;
import com.discordsrv.bukkit.listener.BukkitChatListener;
import com.discordsrv.bukkit.listener.BukkitConnectionListener;
import com.discordsrv.bukkit.listener.BukkitDeathListener;
import com.discordsrv.bukkit.listener.BukkitStatusMessageListener;
import com.discordsrv.bukkit.player.BukkitPlayerProvider;
@ -178,6 +179,7 @@ public class BukkitDiscordSRV extends ServerDiscordSRV<BukkitConfig, BukkitConne
// Register listeners
server().getPluginManager().registerEvents(BukkitChatListener.get(this), plugin());
server().getPluginManager().registerEvents(new BukkitConnectionListener(this), plugin());
server().getPluginManager().registerEvents(new BukkitDeathListener(this), plugin());
server().getPluginManager().registerEvents(new BukkitStatusMessageListener(this), plugin());

View File

@ -85,11 +85,7 @@ public abstract class BukkitChatListener implements Listener {
@EventHandler(priority = EventPriority.MONITOR)
public void onAsyncChat(AsyncChatEvent event) {
MinecraftComponent component = PaperComponentUtil.getComponent(discordSRV, event, "message");
publishEvent(
event.getPlayer(),
component,
event.isCancelled()
);
publishEvent(event.getPlayer(), component, event.isCancelled());
}
}

View File

@ -0,0 +1,62 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.bukkit.listener;
import com.discordsrv.bukkit.BukkitDiscordSRV;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent;
public class BukkitConnectionListener implements Listener {
private final BukkitDiscordSRV discordSRV;
public BukkitConnectionListener(BukkitDiscordSRV discordSRV) {
this.discordSRV = discordSRV;
for (Player onlinePlayer : discordSRV.server().getOnlinePlayers()) {
discordSRV.profileManager().loadProfile(onlinePlayer.getUniqueId());
}
}
@EventHandler(priority = EventPriority.NORMAL)
public void onPlayerLoginNormal(PlayerLoginEvent event) {
if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) {
return;
}
discordSRV.profileManager().loadProfile(event.getPlayer().getUniqueId());
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerLoginMonitor(PlayerLoginEvent event) {
if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) {
// Unload in case got blocked after NORMAL
discordSRV.profileManager().unloadProfile(event.getPlayer().getUniqueId());
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerQuit(PlayerQuitEvent event) {
discordSRV.profileManager().unloadProfile(event.getPlayer().getUniqueId());
}
}

View File

@ -20,6 +20,7 @@ package com.discordsrv.bukkit.player;
import com.discordsrv.bukkit.BukkitDiscordSRV;
import com.discordsrv.common.player.IOfflinePlayer;
import com.discordsrv.common.profile.Profile;
import net.kyori.adventure.identity.Identity;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
@ -42,6 +43,11 @@ public class BukkitOfflinePlayer implements IOfflinePlayer {
return offlinePlayer.getName();
}
@Override
public Profile profile() {
return discordSRV.profileManager().getProfile(uniqueId()).orElseThrow(IllegalStateException::new);
}
@Override
public @NotNull Identity identity() {
return identity;

View File

@ -53,7 +53,7 @@ public class BukkitPlayerProvider extends ServerPlayerProvider<BukkitPlayer, Buk
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerLogin(PlayerJoinEvent event) {
public void onPlayerJoin(PlayerJoinEvent event) {
addPlayer(event.getPlayer(), false);
}

View File

@ -22,6 +22,7 @@ import com.discordsrv.bungee.BungeeDiscordSRV;
import com.discordsrv.bungee.component.util.BungeeComponentUtil;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.player.IPlayer;
import com.discordsrv.common.profile.Profile;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
@ -62,6 +63,11 @@ public class BungeePlayer implements IPlayer {
return player.getName();
}
@Override
public Profile profile() {
return discordSRV.profileManager().getProfile(uniqueId()).orElseThrow(IllegalStateException::new);
}
@Override
public @NotNull Identity identity() {
return identity;

View File

@ -23,13 +23,13 @@ import com.discordsrv.api.event.bus.EventBus;
import com.discordsrv.api.event.events.lifecycle.DiscordSRVReloadEvent;
import com.discordsrv.api.event.events.lifecycle.DiscordSRVShuttingDownEvent;
import com.discordsrv.api.module.type.Module;
import com.discordsrv.api.profile.IProfileManager;
import com.discordsrv.common.api.util.ApiInstanceUtil;
import com.discordsrv.common.channel.ChannelConfigHelper;
import com.discordsrv.common.channel.ChannelUpdaterModule;
import com.discordsrv.common.channel.GlobalChannelLookupModule;
import com.discordsrv.common.component.ComponentFactory;
import com.discordsrv.common.config.connection.ConnectionConfig;
import com.discordsrv.common.config.main.LinkedAccountConfig;
import com.discordsrv.common.config.main.MainConfig;
import com.discordsrv.common.config.manager.ConnectionConfigManager;
import com.discordsrv.common.config.manager.MainConfigManager;
@ -46,8 +46,8 @@ import com.discordsrv.common.function.CheckedRunnable;
import com.discordsrv.common.groupsync.GroupSyncModule;
import com.discordsrv.common.integration.LuckPermsIntegration;
import com.discordsrv.common.linking.LinkProvider;
import com.discordsrv.common.linking.LinkStore;
import com.discordsrv.common.linking.impl.MemoryLinker;
import com.discordsrv.common.linking.impl.StorageLinker;
import com.discordsrv.common.logging.adapter.DependencyLoggerAdapter;
import com.discordsrv.common.logging.impl.DependencyLoggingHandler;
import com.discordsrv.common.logging.impl.DiscordSRVLogger;
@ -69,7 +69,6 @@ import org.jetbrains.annotations.NotNull;
import javax.annotation.OverridingMethodsMustInvokeSuper;
import java.util.Locale;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@ -97,10 +96,10 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
// DiscordSRV
private DiscordSRVLogger logger;
private ModuleManager moduleManager;
private ChannelConfigHelper channelConfig;
private Storage storage;
private LinkProvider linkProvider;
private ChannelConfigHelper channelConfig;
private DiscordConnectionManager discordConnectionManager;
// Internal
@ -122,6 +121,7 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
this.componentFactory = new ComponentFactory(this);
this.discordAPI = new DiscordAPIImpl(this);
this.discordConnectionDetails = new DiscordConnectionDetailsImpl(this);
this.channelConfig = new ChannelConfigHelper(this);
}
// DiscordSRVApi
@ -137,7 +137,7 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
}
@Override
public IProfileManager profileManager() {
public @NotNull ProfileManager profileManager() {
return profileManager;
}
@ -327,25 +327,47 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
try {
connectionConfigManager().load();
configManager().load();
// Utility
channelConfig = new ChannelConfigHelper(this);
eventBus().publish(new DiscordSRVReloadEvent(true));
} catch (Throwable t) {
setStatus(Status.FAILED_TO_LOAD_CONFIG);
throw t;
}
// Link provider
LinkedAccountConfig linkedAccountConfig = config().linkedAccounts;
if (linkedAccountConfig != null && linkedAccountConfig.enabled) {
String provider = linkedAccountConfig.provider;
switch (provider) {
case "auto":
case "storage":
linkProvider = new StorageLinker(this);
break;
case "memory": {
linkProvider = new MemoryLinker();
logger().warning("Using memory for linked accounts");
logger().warning("Linked accounts will be lost upon restart");
break;
}
default: {
logger().error("Unknown linked account provider: \"" + provider + "\", linked accounts will not be used");
break;
}
}
} else {
logger().info("Linked accounts are disabled");
}
// Storage
try {
try {
StorageType storageType = getStorageType();
logger().info("Using " + storageType.prettyName() + " as storage");
if (storageType.hikari()) {
DependencyLoader.hikari(this).process(classpathAppender()).get();
}
storage = storageType.storageFunction().apply(this);
storage.initialize();
logger().info("Storage connection successfully established");
} catch (ExecutionException e) {
throw new StorageException(e.getCause());
} catch (StorageException e) {
@ -355,7 +377,7 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
}
} catch (StorageException e) {
e.log(this);
logger().error("Startup cancelled because of storage connection failure");
logger().error("Failed to connect to storage");
setStatus(Status.FAILED_TO_START);
return;
}
@ -363,9 +385,6 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
discordConnectionManager = new JDAConnectionManager(this);
discordConnectionManager.connect().join();
linkProvider = new MemoryLinker();
((LinkStore) linkProvider).link(UUID.fromString("6c983d46-0631-48b8-9baf-5e33eb5ffec4"), 185828288466255874L);
// Placeholder result stringifiers & global contexts
placeholderService().addResultMapper(new ComponentResultStringifier(this));
placeholderService().addGlobalContext(new GlobalTextHandlingContext(this));

View File

@ -37,6 +37,7 @@ import com.discordsrv.common.module.type.AbstractModule;
import com.discordsrv.common.placeholder.PlaceholderServiceImpl;
import com.discordsrv.common.player.provider.AbstractPlayerProvider;
import com.discordsrv.common.plugin.PluginManager;
import com.discordsrv.common.profile.ProfileManager;
import com.discordsrv.common.scheduler.Scheduler;
import com.discordsrv.common.storage.Storage;
import com.github.benmanes.caffeine.cache.Caffeine;
@ -61,6 +62,7 @@ public interface DiscordSRV extends DiscordSRVApi {
PluginManager pluginManager();
OnlineMode onlineMode();
ClasspathAppender classpathAppender();
@NotNull AbstractPlayerProvider<?, ?> playerProvider();
// DiscordSRVApi
@Override
@ -69,11 +71,11 @@ public interface DiscordSRV extends DiscordSRVApi {
@Override
@NotNull
PlaceholderServiceImpl placeholderService();
ProfileManager profileManager();
@Override
@NotNull
AbstractPlayerProvider<?, ?> playerProvider();
PlaceholderServiceImpl placeholderService();
@Override
@NotNull

View File

@ -0,0 +1,35 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.common.config.main;
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
import org.spongepowered.configurate.objectmapping.meta.Comment;
@ConfigSerializable
public class LinkedAccountConfig {
@Comment("Should linked accounts be enabled?")
public boolean enabled = true;
@Comment("The linked account provider\n"
+ "\n"
+ " - auto: Automatically chooses the most suitable linked accounts storage\n"
+ " - storage: Store linked accounts from the configured databased")
public String provider = "auto";
}

View File

@ -43,6 +43,8 @@ public class MainConfig implements Config {
put(ChannelConfig.DEFAULT_KEY, new BaseChannelConfig());
}};
public LinkedAccountConfig linkedAccounts = new LinkedAccountConfig();
public List<ChannelUpdaterConfig> channelUpdaters = new ArrayList<>(Collections.singletonList(new ChannelUpdaterConfig()));
@Comment("Configuration options for group-role synchronization")

View File

@ -23,7 +23,6 @@ import com.discordsrv.api.discord.api.entity.guild.DiscordRole;
import com.discordsrv.api.discord.events.member.role.DiscordMemberRoleAddEvent;
import com.discordsrv.api.discord.events.member.role.DiscordMemberRoleRemoveEvent;
import com.discordsrv.api.event.bus.Subscribe;
import com.discordsrv.api.profile.IProfile;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.main.GroupSyncConfig;
import com.discordsrv.common.debug.DebugGenerateEvent;
@ -166,12 +165,12 @@ public class GroupSyncModule extends AbstractModule<DiscordSRV> {
private CompletableFuture<Long> lookupLinkedAccount(UUID player) {
return discordSRV.profileManager().lookupProfile(player)
.thenApply(profile -> profile.map(IProfile::userId).orElse(null));
.thenApply(profile -> profile.userId().orElse(null));
}
private CompletableFuture<UUID> lookupLinkedAccount(long userId) {
return discordSRV.profileManager().lookupProfile(userId)
.thenApply(profile -> profile.map(IProfile::uniqueId).orElse(null));
.thenApply(profile -> profile.playerUUID().orElse(null));
}
// Permission data helper methods

View File

@ -25,7 +25,7 @@ import java.util.concurrent.CompletableFuture;
public interface LinkStore {
CompletableFuture<Void> link(@NotNull UUID playerUUID, long userId);
CompletableFuture<Void> createLink(@NotNull UUID playerUUID, long userId);
CompletableFuture<Integer> getLinkedAccountCount();
}

View File

@ -43,7 +43,7 @@ public class MemoryLinker implements LinkProvider, LinkStore {
}
@Override
public CompletableFuture<Void> link(@NotNull UUID playerUUID, long userId) {
public CompletableFuture<Void> createLink(@NotNull UUID playerUUID, long userId) {
map.put(playerUUID, userId);
return CompletableFuture.completedFuture(null);
}

View File

@ -31,6 +31,7 @@ public class StorageLinker extends CachedLinkProvider implements LinkProvider, L
public StorageLinker(DiscordSRV discordSRV) {
super(discordSRV);
discordSRV.logger().info("Using storage for linked accounts");
}
@Override
@ -50,9 +51,9 @@ public class StorageLinker extends CachedLinkProvider implements LinkProvider, L
}
@Override
public CompletableFuture<Void> link(@NotNull UUID playerUUID, long userId) {
public CompletableFuture<Void> createLink(@NotNull UUID playerUUID, long userId) {
return CompletableFuture.runAsync(
() -> discordSRV.storage().link(playerUUID, userId),
() -> discordSRV.storage().createLink(playerUUID, userId),
discordSRV.scheduler().executor()
);
}

View File

@ -19,6 +19,7 @@
package com.discordsrv.common.player;
import com.discordsrv.api.placeholder.annotation.Placeholder;
import com.discordsrv.common.profile.Profile;
import net.kyori.adventure.identity.Identified;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
@ -38,4 +39,6 @@ public interface IOfflinePlayer extends Identified {
default UUID uniqueId() {
return identity().uuid();
}
Profile profile();
}

View File

@ -36,7 +36,6 @@ public interface IPlayer extends DiscordSRVPlayer, IOfflinePlayer, ICommandSende
DiscordSRV discordSRV();
@Override
@NotNull
String username();

View File

@ -19,27 +19,28 @@
package com.discordsrv.common.profile;
import com.discordsrv.api.profile.IProfile;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
import java.util.UUID;
public class Profile implements IProfile {
private final UUID uuid;
private final UUID playerUUID;
private final Long userId;
public Profile(UUID uuid, Long userId) {
this.uuid = uuid;
public Profile(UUID playerUUID, Long userId) {
this.playerUUID = playerUUID;
this.userId = userId;
}
@Override
public @Nullable UUID uniqueId() {
return uuid;
public @NotNull Optional<UUID> playerUUID() {
return Optional.ofNullable(playerUUID);
}
@Override
public @Nullable Long userId() {
return userId;
public @NotNull Optional<Long> userId() {
return Optional.ofNullable(userId);
}
}

View File

@ -19,40 +19,64 @@
package com.discordsrv.common.profile;
import com.discordsrv.api.profile.IProfileManager;
import com.discordsrv.api.profile.IProfile;
import com.discordsrv.common.DiscordSRV;
import org.jetbrains.annotations.Blocking;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
public class ProfileManager implements IProfileManager {
private final DiscordSRV discordSRV;
private final Map<UUID, Profile> profiles = new ConcurrentHashMap<>();
private final Map<Long, Profile> discordUserMap = new ConcurrentHashMap<>();
public ProfileManager(DiscordSRV discordSRV) {
this.discordSRV = discordSRV;
}
@Blocking
public void loadProfile(UUID playerUUID) {
Profile profile = lookupProfile(playerUUID).join();
profiles.put(playerUUID, profile);
if (profile.isLinked()) {
discordUserMap.put(profile.userId().orElseThrow(AssertionError::new), profile);
}
}
public void unloadProfile(UUID playerUUID) {
Profile profile = profiles.remove(playerUUID);
if (profile == null) {
return;
}
if (profile.isLinked()) {
discordUserMap.remove(profile.userId().orElseThrow(AssertionError::new));
}
}
@Override
public CompletableFuture<Optional<IProfile>> lookupProfile(UUID playerUUID) {
public CompletableFuture<Profile> lookupProfile(UUID playerUUID) {
return discordSRV.linkProvider().getUserId(playerUUID)
.thenApply(opt -> Optional.of(new Profile(playerUUID, opt.orElse(null))));
.thenApply(opt -> new Profile(playerUUID, opt.orElse(null)));
}
@Override
public Optional<IProfile> getProfile(UUID playerUUID) {
return Optional.empty();
public Optional<Profile> getProfile(UUID playerUUID) {
return Optional.ofNullable(profiles.get(playerUUID));
}
@Override
public CompletableFuture<Optional<IProfile>> lookupProfile(long userId) {
public CompletableFuture<Profile> lookupProfile(long userId) {
return discordSRV.linkProvider().getPlayerUUID(userId)
.thenApply(opt -> Optional.of(new Profile(opt.orElse(null), userId)));
.thenApply(opt -> new Profile(opt.orElse(null), userId));
}
@Override
public Optional<IProfile> getProfile(long userId) {
return Optional.empty();
public Optional<Profile> getProfile(long userId) {
return Optional.ofNullable(discordUserMap.get(userId));
}
}

View File

@ -36,7 +36,7 @@ public interface Storage {
@Nullable
UUID getPlayerUUID(long userId);
void link(@NotNull UUID player, long userId);
void createLink(@NotNull UUID player, long userId);
int getLinkedAccountCount();

View File

@ -26,14 +26,16 @@ import java.util.function.Function;
public enum StorageType {
H2(H2Storage::new, false),
MYSQL(MySQLStorage::new, true);
H2(H2Storage::new, "H2", false),
MYSQL(MySQLStorage::new, "MySQL", true);
private final Function<DiscordSRV, Storage> storageFunction;
private final String prettyName;
private final boolean hikari;
StorageType(Function<DiscordSRV, Storage> storageFunction, boolean hikari) {
StorageType(Function<DiscordSRV, Storage> storageFunction, String prettyName, boolean hikari) {
this.storageFunction = storageFunction;
this.prettyName = prettyName;
this.hikari = hikari;
}
@ -41,6 +43,10 @@ public enum StorageType {
return storageFunction;
}
public String prettyName() {
return prettyName;
}
public boolean hikari() {
return hikari;
}

View File

@ -18,9 +18,11 @@
package com.discordsrv.common.storage.impl.sql;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.exception.StorageException;
import com.discordsrv.common.function.CheckedConsumer;
import com.discordsrv.common.function.CheckedFunction;
import com.discordsrv.common.linking.impl.StorageLinker;
import com.discordsrv.common.storage.Storage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -30,9 +32,15 @@ import java.util.UUID;
public abstract class SQLStorage implements Storage {
protected final DiscordSRV discordSRV;
public SQLStorage(DiscordSRV discordSRV) {
this.discordSRV = discordSRV;
}
public abstract Connection getConnection();
public abstract boolean isAutoCloseConnections();
public abstract void createTables(Connection connection) throws SQLException;
public abstract void createTables(Connection connection, boolean linkedAccounts) throws SQLException;
private void useConnection(CheckedConsumer<Connection> connectionConsumer) throws StorageException {
useConnection(connection -> {
@ -63,7 +71,7 @@ public abstract class SQLStorage implements Storage {
@Override
public void initialize() {
useConnection(this::createTables);
useConnection((CheckedConsumer<Connection>) connection -> createTables(connection, discordSRV.linkProvider() instanceof StorageLinker));
}
@Override
@ -97,7 +105,7 @@ public abstract class SQLStorage implements Storage {
}
@Override
public void link(@NotNull UUID player, long userId) {
public void createLink(@NotNull UUID player, long userId) {
useConnection(connection -> {
try (PreparedStatement statement = connection.prepareStatement("insert into LINKED_ACCOUNTS (PLAYER_UUID, USER_ID) values (?, ?);")) {
statement.setObject(1, player);

View File

@ -34,12 +34,11 @@ import java.util.Properties;
public class H2Storage extends SQLStorage {
private final DiscordSRV discordSRV;
private IsolatedClassLoader classLoader;
private Connection connection;
public H2Storage(DiscordSRV discordSRV) {
this.discordSRV = discordSRV;
super(discordSRV);
}
@Override
@ -101,15 +100,17 @@ public class H2Storage extends SQLStorage {
}
@Override
public void createTables(Connection connection) throws SQLException {
try (Statement statement = connection.createStatement()) {
statement.execute(
"create table if not exists LINKED_ACCOUNTS "
+ "(ID int not null auto_increment, "
+ "PLAYER_UUID varchar(36), "
+ "USER_ID bigint, "
+ "constraint LINKED_ACCOUNTS_PK primary key (ID)"
+ ")");
public void createTables(Connection connection, boolean linkedAccounts) throws SQLException {
if (linkedAccounts) {
try (Statement statement = connection.createStatement()) {
statement.execute(
"create table if not exists LINKED_ACCOUNTS "
+ "(ID int not null auto_increment, "
+ "PLAYER_UUID varchar(36), "
+ "USER_ID bigint, "
+ "constraint LINKED_ACCOUNTS_PK primary key (ID)"
+ ")");
}
}
}
}

View File

@ -31,11 +31,10 @@ import java.sql.SQLException;
public abstract class HikariStorage extends SQLStorage {
protected final DiscordSRV discordSRV;
private HikariDataSource hikariDataSource;
public HikariStorage(DiscordSRV discordSRV) {
this.discordSRV = discordSRV;
super(discordSRV);
}
protected abstract void applyConfiguration(HikariConfig config, StorageConfig storageConfig);

View File

@ -52,15 +52,17 @@ public class MySQLStorage extends HikariStorage {
}
@Override
public void createTables(Connection connection) throws SQLException {
try (Statement statement = connection.createStatement()) {
statement.execute(
"create table if not exists LINKED_ACCOUNTS "
+ "(ID int not null auto_increment, "
+ "PLAYER_UUID varchar(36), "
+ "USER_ID bigint, "
+ "constraint LINKED_ACCOUNTS_PK primary key (ID)"
+ ")");
public void createTables(Connection connection, boolean linkedAccounts) throws SQLException {
if (linkedAccounts) {
try (Statement statement = connection.createStatement()) {
statement.execute(
"create table if not exists LINKED_ACCOUNTS "
+ "(ID int not null auto_increment, "
+ "PLAYER_UUID varchar(36), "
+ "USER_ID bigint, "
+ "constraint LINKED_ACCOUNTS_PK primary key (ID)"
+ ")");
}
}
}

View File

@ -19,15 +19,19 @@
package com.discordsrv.sponge.player;
import com.discordsrv.common.player.IOfflinePlayer;
import com.discordsrv.common.profile.Profile;
import com.discordsrv.sponge.SpongeDiscordSRV;
import net.kyori.adventure.identity.Identity;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.api.entity.living.player.User;
public class SpongeOfflinePlayer implements IOfflinePlayer {
protected final SpongeDiscordSRV discordSRV;
private final User user;
public SpongeOfflinePlayer(User user) {
public SpongeOfflinePlayer(SpongeDiscordSRV discordSRV, User user) {
this.discordSRV = discordSRV;
this.user = user;
}
@ -36,6 +40,11 @@ public class SpongeOfflinePlayer implements IOfflinePlayer {
return user.name();
}
@Override
public Profile profile() {
return discordSRV.profileManager().getProfile(uniqueId()).orElseThrow(IllegalStateException::new);
}
@Override
public @NotNull Identity identity() {
return user.profile();

View File

@ -29,12 +29,10 @@ import org.spongepowered.api.entity.living.player.server.ServerPlayer;
public class SpongePlayer extends SpongeOfflinePlayer implements IPlayer {
private final SpongeDiscordSRV discordSRV;
private final ServerPlayer player;
public SpongePlayer(SpongeDiscordSRV discordSRV, ServerPlayer player) {
super(player.user());
this.discordSRV = discordSRV;
super(discordSRV, player.user());
this.player = player;
}

View File

@ -71,7 +71,7 @@ public class SpongePlayerProvider extends ServerPlayerProvider<SpongePlayer, Spo
// IOfflinePlayer
private IOfflinePlayer convert(User user) {
return new SpongeOfflinePlayer(user);
return new SpongeOfflinePlayer(discordSRV, user);
}
@Override
@ -89,6 +89,6 @@ public class SpongePlayerProvider extends ServerPlayerProvider<SpongePlayer, Spo
}
public IOfflinePlayer offlinePlayer(User user) {
return new SpongeOfflinePlayer(user);
return convert(user);
}
}

View File

@ -20,6 +20,7 @@ package com.discordsrv.velocity.player;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.player.IPlayer;
import com.discordsrv.common.profile.Profile;
import com.discordsrv.velocity.VelocityDiscordSRV;
import com.velocitypowered.api.proxy.Player;
import net.kyori.adventure.audience.Audience;
@ -57,6 +58,11 @@ public class VelocityPlayer implements IPlayer {
return player.getUsername();
}
@Override
public Profile profile() {
return discordSRV.profileManager().getProfile(uniqueId()).orElseThrow(IllegalStateException::new);
}
@Override
public @NotNull Identity identity() {
return player.identity();