From 28fcb2f8d89e2ef3d7201a53a401f72dc66f1a3f Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 21 Jan 2017 19:45:54 +0100 Subject: [PATCH] Making progress on player data --- .../lib/player/ChromaGamerBase.java | 80 +++++++++++++++---- .../lib/player/TBMCPlayerBase.java | 21 +++++ 2 files changed, 86 insertions(+), 15 deletions(-) diff --git a/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java b/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java index 71147d8..c50be0a 100644 --- a/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java +++ b/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java @@ -1,11 +1,8 @@ package buttondevteam.lib.player; import java.io.File; -import java.util.Collections; import java.util.HashMap; -import java.util.Map; import java.util.Map.Entry; -import java.util.function.BiConsumer; import java.util.function.Consumer; import org.bukkit.configuration.file.YamlConfiguration; @@ -17,12 +14,30 @@ public abstract class ChromaGamerBase implements AutoCloseable { private static final HashMap, String> playerTypes = new HashMap<>(); + /** + * Use only if outside Minecraft, and use it to register your plugin's class. + * + * @param cl + * The custom player class + * @param folder + * The folder to store the data in (like "discord") + */ public static void addPlayerType(Class cl, String folder) { playerTypes.put(cl, folder); } + /** + * Returns the folder name for the given player class. If a direct match is not found, it'll look for superclasses. + * + * @param cl + * The class to get the folder from (like {@link TBMCPlayerBase} or one of it's subclasses + * @return The folder name for the given type + */ public static String getFolderForType(Class cl) { - return playerTypes.get(cl); + if (playerTypes.containsKey(cl)) + return playerTypes.get(cl); + return playerTypes.entrySet().stream().filter(e -> e.getKey().isAssignableFrom(cl)).findAny() + .orElseThrow(() -> new RuntimeException("Type not registered as a player type!")).getValue(); } /** @@ -35,10 +50,6 @@ public abstract class ChromaGamerBase implements AutoCloseable { */ protected YamlConfiguration plugindata; - public YamlConfiguration getData() { - return plugindata; - } - public String getID() { return plugindata != null ? plugindata.getString("id") : null; } @@ -47,7 +58,7 @@ public abstract class ChromaGamerBase implements AutoCloseable { try { T obj = cl.newInstance(); obj.plugindata = YamlConfiguration - .loadConfiguration(new File(TBMC_PLAYERS_DIR + playerTypes.get(cl), fname)); + .loadConfiguration(new File(TBMC_PLAYERS_DIR + getFolderForType(cl), fname)); return obj; } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while loading a " + cl.getSimpleName() + "!", e); @@ -60,15 +71,54 @@ public abstract class ChromaGamerBase implements AutoCloseable { plugindata.save(new File(TBMC_PLAYERS_DIR + getFolderForType(getClass()), getFileName())); } + /** + * Connect two accounts. Do not use for connecting two Minecraft accounts or similar. Also make sure you have the "id" tag set + * + * @param user + * The account to connect with + */ public void connectWith(T user) { // Set the ID, go through all linked files and connect them as well - plugindata.set(playerTypes.get(user.getClass()) + "_id", user.plugindata.getString("id")); + plugindata.set(getFolderForType(user.getClass()) + "_id", user.plugindata.getString("id")); final String ownFolder = getFolderForType(getClass()); user.plugindata.set(ownFolder + "_id", plugindata.getString("id")); - BiConsumer sync = (pdata1, pdata2) -> { - for (Entry, String> entry : playerTypes.entrySet()) - if (pdata1.contains(entry.getValue() + "_id", false)) - pdata2.set(entry.getValue() + "_id", pdata1.getString(entry.getValue() + "_id")); - }; // ... + Consumer sync = sourcedata -> { + final String sourcefolder = sourcedata == plugindata ? ownFolder : getFolderForType(user.getClass()); + final String id = sourcedata.getString("id"); + for (Entry, String> entry : playerTypes.entrySet()) { // Set our ID in all files we can find, both from our connections and the new ones + final String otherid = sourcedata.getString(entry.getValue() + "_id"); + if (otherid == null) + continue; + try (@SuppressWarnings("unchecked") + ChromaGamerBase cg = getUser(otherid, (Class) entry.getKey())) { + cg.plugindata.set(sourcefolder + "_id", id); // Set new IDs + for (Entry, String> item : playerTypes.entrySet()) + if (sourcedata.contains(item.getValue() + "_id")) + cg.plugindata.set(item.getValue() + "_id", sourcedata.getString(item.getValue() + "_id")); // Set all existing IDs + } catch (Exception e) { + TBMCCoreAPI.SendException("Failed to update " + sourcefolder + " ID in player files for " + id + + " in folder with " + entry.getValue() + " id " + otherid + "!", e); + } + } + }; + sync.accept(plugindata); + sync.accept(user.plugindata); + } + + /** + * Returns this player as a plugin player. This will return a new instance unless the player is online.
+ * Make sure to close both the returned and this object. A try-with-resources block or two can help.
+ * + * @param cl + * The target player class + * @return The player as a {@link T} object or null if not having an account there + */ + public T getAs(Class cl) { + String newfolder = getFolderForType(cl); + if (newfolder == null) + throw new RuntimeException("The specified class " + cl.getSimpleName() + " isn't registered!"); + if (!plugindata.contains(newfolder + "_id")) + return null; + return getUser(plugindata.getString(newfolder + "_id"), cl); } } diff --git a/src/main/java/buttondevteam/lib/player/TBMCPlayerBase.java b/src/main/java/buttondevteam/lib/player/TBMCPlayerBase.java index 3b0ce71..56360d3 100644 --- a/src/main/java/buttondevteam/lib/player/TBMCPlayerBase.java +++ b/src/main/java/buttondevteam/lib/player/TBMCPlayerBase.java @@ -1,6 +1,7 @@ package buttondevteam.lib.player; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; public abstract class TBMCPlayerBase extends ChromaGamerBase { private static final String FOLDER_NAME = "minecraft"; @@ -28,9 +29,29 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase { addPlayerType(TBMCPlayerBase.class, FOLDER_NAME); } + @SuppressWarnings("unchecked") public static T getPlayer(UUID uuid, Class cl) { + if (playermap.containsKey(uuid + "-" + cl.getSimpleName())) + return (T) playermap.get(uuid + "-" + cl.getSimpleName()); T obj = ChromaGamerBase.getUser(uuid.toString(), cl); obj.uuid = uuid; return obj; } + + /** + * Key: UUID-Class + */ + static final ConcurrentHashMap playermap = new ConcurrentHashMap<>(); + + /** + * Gets the TBMCPlayer object as a specific plugin player, keeping it's data * + * + * @param p + * Player to get + * @param cl + * The TBMCPlayer subclass + */ + public T asPluginPlayer(Class cl) { + return getPlayer(uuid, cl); + } }