diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/api/HMCCosmeticsAPI.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/api/HMCCosmeticsAPI.java index 14919993..00e91bbe 100644 --- a/common/src/main/java/com/hibiscusmc/hmccosmetics/api/HMCCosmeticsAPI.java +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/api/HMCCosmeticsAPI.java @@ -7,9 +7,12 @@ import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetics; import com.hibiscusmc.hmccosmetics.gui.Menu; import com.hibiscusmc.hmccosmetics.gui.Menus; import com.hibiscusmc.hmccosmetics.user.CosmeticUser; +import com.hibiscusmc.hmccosmetics.user.CosmeticUserProvider; import com.hibiscusmc.hmccosmetics.user.CosmeticUsers; +import lombok.Getter; import me.lojosho.hibiscuscommons.nms.NMSHandlers; import org.bukkit.Color; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -145,6 +148,25 @@ public final class HMCCosmeticsAPI { return CosmeticSlot.register(id); } + /** + * Registers a new cosmetic user provider to use to construct {@link CosmeticUser}s. + * + * @param provider the provider to register + * @throws IllegalArgumentException if another plugin has already registered a provider + */ + public static void registerCosmeticUserProvider(final CosmeticUserProvider provider) { + CosmeticUsers.registerProvider(provider); + } + + /** + * Fetch the current {@link CosmeticUserProvider} that is in use. + * + * @return the {@link CosmeticUserProvider} + */ + public static CosmeticUserProvider getCosmeticUserProvider() { + return CosmeticUsers.getProvider(); + } + /** * Retrieves the NMS version of the server as recognized by HMCCosmetics. * diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/listener/PlayerConnectionListener.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/listener/PlayerConnectionListener.java index c0288c8c..a81168e1 100644 --- a/common/src/main/java/com/hibiscusmc/hmccosmetics/listener/PlayerConnectionListener.java +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/listener/PlayerConnectionListener.java @@ -1,6 +1,7 @@ package com.hibiscusmc.hmccosmetics.listener; import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin; +import com.hibiscusmc.hmccosmetics.api.HMCCosmeticsAPI; import com.hibiscusmc.hmccosmetics.api.events.PlayerLoadEvent; import com.hibiscusmc.hmccosmetics.api.events.PlayerPreLoadEvent; import com.hibiscusmc.hmccosmetics.api.events.PlayerUnloadEvent; @@ -10,9 +11,11 @@ import com.hibiscusmc.hmccosmetics.database.Database; import com.hibiscusmc.hmccosmetics.database.UserData; import com.hibiscusmc.hmccosmetics.gui.Menus; import com.hibiscusmc.hmccosmetics.user.CosmeticUser; +import com.hibiscusmc.hmccosmetics.user.CosmeticUserProvider; import com.hibiscusmc.hmccosmetics.user.CosmeticUsers; import com.hibiscusmc.hmccosmetics.user.manager.UserEmoteManager; import com.hibiscusmc.hmccosmetics.util.MessagesUtil; +import lombok.extern.slf4j.Slf4j; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -23,6 +26,7 @@ import org.jetbrains.annotations.NotNull; import java.util.UUID; +@Slf4j public class PlayerConnectionListener implements Listener { @EventHandler(priority = EventPriority.MONITOR) @@ -51,7 +55,7 @@ public class PlayerConnectionListener implements Listener { Database.get(uuid).thenAccept(data -> { if (data == null) return; Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> { - CosmeticUser cosmeticUser = new CosmeticUser(uuid, data); + CosmeticUser cosmeticUser = CosmeticUsers.getProvider().createCosmeticUser(uuid, data); CosmeticUsers.addUser(cosmeticUser); MessagesUtil.sendDebugMessages("Run User Join for " + uuid); @@ -64,6 +68,9 @@ public class PlayerConnectionListener implements Listener { cosmeticUser.updateCosmetic(); }, 4); }); + }).exceptionally(ex -> { + log.error("Unable to load Cosmetic User {}", uuid, ex); + return null; }); }; diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/user/CosmeticUserProvider.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/user/CosmeticUserProvider.java new file mode 100644 index 00000000..39edbad6 --- /dev/null +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/user/CosmeticUserProvider.java @@ -0,0 +1,55 @@ +package com.hibiscusmc.hmccosmetics.user; + +import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin; +import com.hibiscusmc.hmccosmetics.database.UserData; +import org.bukkit.plugin.Plugin; + +import java.util.UUID; + +/** + * Allow custom implementations of a {@link CosmeticUser}. + */ +public interface CosmeticUserProvider { + CosmeticUserProvider DEFAULT = new Default(); + + /** + * Construct the custom {@link CosmeticUser}. + * @param playerId the player uuid + * @param userData the user data associated with the player + * @return the {@link CosmeticUser} + */ + CosmeticUser createCosmeticUser(UUID playerId, UserData userData); + + /** + * Construct the custom {@link CosmeticUser}. + * @param playerId the player uuid + * @return the {@link CosmeticUser} + */ + CosmeticUser createCosmeticUserWithoutData(UUID playerId); + + /** + * Represents the plugin that is providing this {@link CosmeticUserProvider} + * @return the plugin + */ + Plugin getProviderPlugin(); + + /** + * Default implementation. + */ + class Default implements CosmeticUserProvider { + @Override + public CosmeticUser createCosmeticUser(UUID playerId, UserData userData) { + return new CosmeticUser(playerId, userData); + } + + @Override + public CosmeticUser createCosmeticUserWithoutData(UUID playerId) { + return new CosmeticUser(playerId); + } + + @Override + public Plugin getProviderPlugin() { + return HMCCosmeticsPlugin.getInstance(); + } + } +} \ No newline at end of file diff --git a/common/src/main/java/com/hibiscusmc/hmccosmetics/user/CosmeticUsers.java b/common/src/main/java/com/hibiscusmc/hmccosmetics/user/CosmeticUsers.java index 87beb9c4..b9207604 100644 --- a/common/src/main/java/com/hibiscusmc/hmccosmetics/user/CosmeticUsers.java +++ b/common/src/main/java/com/hibiscusmc/hmccosmetics/user/CosmeticUsers.java @@ -2,6 +2,7 @@ package com.hibiscusmc.hmccosmetics.user; import com.google.common.collect.HashBiMap; import com.hibiscusmc.hmccosmetics.util.HMCCServerUtils; +import lombok.Getter; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -11,9 +12,10 @@ import java.util.Set; import java.util.UUID; public class CosmeticUsers { - private static final HashBiMap COSMETIC_USERS = HashBiMap.create(); + private static CosmeticUserProvider PROVIDER = CosmeticUserProvider.DEFAULT; + /** * Adds a user to the Hashmap of stored CosmeticUsers. This will not override an entry if it already exists. If you need to override, delete then add. * @param user The user to add to the HashMap. @@ -72,6 +74,31 @@ public class CosmeticUsers { return COSMETIC_USERS.get(player.getUniqueId()); } + /** + * Register a custom {@link CosmeticUserProvider} to provide your own user implementation to + * be used and queried. + * @param provider the provider to register + * @throws IllegalArgumentException if the provider is already registered by another plugin + */ + public static void registerProvider(final CosmeticUserProvider provider) { + if(PROVIDER != CosmeticUserProvider.DEFAULT) { + throw new IllegalArgumentException("CosmeticUserProvider already registered by %s, this conflicts with %s attempting to register their own.".formatted( + PROVIDER.getProviderPlugin().getName(), + provider.getProviderPlugin().getName() + )); + } + + PROVIDER = provider; + } + + /** + * Fetch the current {@link CosmeticUserProvider} being used. + * @return the current {@link CosmeticUserProvider} being used + */ + public static CosmeticUserProvider getProvider() { + return PROVIDER; + } + /** * Gets all the values for CosmeticUsers to allow you to iterate over everyone. * @return CosmeticUsers in a set. This will never be null, but might be empty.