From 153425be5ee3018961988ce7e2e44ac307bf646a Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 1 Apr 2017 14:40:54 +0200 Subject: [PATCH] Probably done with player data (#28) - Figured out and finished the annotation - Grouped data by plugin names - Player data is saved as an object automatically determining the type --- .../java/buttondevteam/core/MainPlugin.java | 1 + .../java/buttondevteam/lib/TBMCCoreAPI.java | 8 ++- .../lib/player/ChromaGamerBase.java | 67 +++++++++++++++---- .../buttondevteam/lib/player/PlayerClass.java | 9 +++ .../buttondevteam/lib/player/PlayerData.java | 22 ++++++ .../lib/player/TBMCPlayerBase.java | 50 ++++++++------ .../buttondevteam/lib/player/UserClass.java | 21 ++++++ 7 files changed, 142 insertions(+), 36 deletions(-) create mode 100644 src/main/java/buttondevteam/lib/player/PlayerData.java create mode 100644 src/main/java/buttondevteam/lib/player/UserClass.java diff --git a/src/main/java/buttondevteam/core/MainPlugin.java b/src/main/java/buttondevteam/core/MainPlugin.java index c09b698..1afd61e 100644 --- a/src/main/java/buttondevteam/core/MainPlugin.java +++ b/src/main/java/buttondevteam/core/MainPlugin.java @@ -31,6 +31,7 @@ public class MainPlugin extends JavaPlugin { TBMCChatAPI.AddCommand(this, UpdatePluginCommand.class); TBMCChatAPI.AddCommand(this, ScheduledRestartCommand.class); TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this); + TBMCCoreAPI.RegisterUserClass(TBMCPlayerBase.class); logger.info(pdfFile.getName() + " has been Enabled (V." + pdfFile.getVersion() + ")."); } diff --git a/src/main/java/buttondevteam/lib/TBMCCoreAPI.java b/src/main/java/buttondevteam/lib/TBMCCoreAPI.java index dcb7d60..62c0e37 100644 --- a/src/main/java/buttondevteam/lib/TBMCCoreAPI.java +++ b/src/main/java/buttondevteam/lib/TBMCCoreAPI.java @@ -18,6 +18,7 @@ import org.bukkit.plugin.Plugin; import com.google.gson.*; import buttondevteam.core.MainPlugin; +import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.potato.DebugPotato; public final class TBMCCoreAPI { @@ -83,8 +84,7 @@ public final class TBMCCoreAPI { info(sender, "Updating TBMC plugin: " + correctname + " from " + correctbranch.get()); URL url; final boolean isWindows = System.getProperty("os.name").contains("Windows"); - File result = new File( - "plugins/" + correctname + (isWindows ? ".jar" : ".jar_tmp")); + File result = new File("plugins/" + correctname + (isWindows ? ".jar" : ".jar_tmp")); File finalresult = new File("plugins/" + correctname + ".jar"); try { url = new URL("https://jitpack.io/com/github/TBMCPlugins/" @@ -250,6 +250,10 @@ public final class TBMCCoreAPI { EventExceptionHandler.registerEvents(listener, plugin, new EventExceptionCoreHandler()); } + public static void RegisterUserClass(Class userclass) { + ChromaGamerBase.RegisterPluginUserClass(userclass); + } + /** * Send exceptions that haven't been sent (their events didn't get handled). This method is used by the DiscordPlugin's ready event */ diff --git a/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java b/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java index 2239694..aa64747 100644 --- a/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java +++ b/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java @@ -8,7 +8,6 @@ import java.util.function.Consumer; import org.bukkit.Bukkit; import org.bukkit.configuration.file.YamlConfiguration; - import buttondevteam.lib.TBMCCoreAPI; public abstract class ChromaGamerBase implements AutoCloseable { @@ -17,29 +16,27 @@ 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") + * Used for connecting with every type of user ({@link #connectWith(ChromaGamerBase)}) */ - public static void addPlayerType(Class cl, String folder) { - playerTypes.put(cl, folder); + public static void RegisterPluginUserClass(Class userclass) { + if (userclass.isAnnotationPresent(UserClass.class)) + playerTypes.put(userclass, userclass.getAnnotation(UserClass.class).foldername()); + throw new RuntimeException("Class not registered as a user class! Use @UserClass or TBMCPlayerBase"); } /** - * Returns the folder name for the given player class. If a direct match is not found, it'll look for superclasses. + * Returns the folder name for the given player class. * * @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 + * @throws RuntimeException + * If the class doesn't have the {@link UserClass} annotation. */ public static String getFolderForType(Class 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(); + if (cl.isAnnotationPresent(UserClass.class)) + return cl.getAnnotation(UserClass.class).foldername(); + throw new RuntimeException("Class not registered as a user class! Use @UserClass"); } /** @@ -57,6 +54,13 @@ public abstract class ChromaGamerBase implements AutoCloseable { return plugindata != null ? plugindata.getString("id") : null; } + /*** + * Loads a user from disk and returns the user object. Make sure to use the subclasses' methods, where possible, like {@link TBMCPlayerBase#getPlayer(java.util.UUID, Class)} + * + * @param fname + * @param cl + * @return + */ public static T getUser(String fname, Class cl) { try { T obj = cl.newInstance(); @@ -101,6 +105,8 @@ public abstract class ChromaGamerBase implements AutoCloseable { */ public void connectWith(T user) { // Set the ID, go through all linked files and connect them as well + if (!playerTypes.containsKey(getClass())) + throw new RuntimeException("Class not registered as a user class! Use TBMCCoreAPI.RegisterUserClass"); plugindata.set(user.getFolder() + "_id", user.plugindata.getString("id")); final String ownFolder = user.getFolder(); user.plugindata.set(ownFolder + "_id", plugindata.getString("id")); @@ -159,6 +165,39 @@ public abstract class ChromaGamerBase implements AutoCloseable { return getFolderForType(getClass()); } + @SuppressWarnings("rawtypes") + private HashMap datamap = new HashMap<>(); + + /** + * Use from a data() method, which is in a method with the name of the key. For example, use flair() for the enclosing method of the outer data() to save to and load from "flair" + * + * @return A data object with methods to get and set + */ + @SuppressWarnings("unchecked") + protected PlayerData data(String sectionname) { + if (!getClass().isAnnotationPresent(UserClass.class)) + throw new RuntimeException("Class not registered as a user class! Use @UserClass"); + String mname = sectionname + "." + new Exception().getStackTrace()[1].getMethodName(); + if (!datamap.containsKey(mname)) + datamap.put(mname, new PlayerData(mname, plugindata)); + return datamap.get(mname); + } + + /** + * Use from a method with the name of the key. For example, use flair() for the enclosing method to save to and load from "flair" + * + * @return A data object with methods to get and set + */ + @SuppressWarnings("unchecked") + protected PlayerData data() { + if (!getClass().isAnnotationPresent(UserClass.class)) + throw new RuntimeException("Class not registered as a user class! Use @UserClass"); + String mname = new Exception().getStackTrace()[2].getMethodName(); + if (!datamap.containsKey(mname)) + datamap.put(mname, new PlayerData(mname, plugindata)); + return datamap.get(mname); + } + /** * Get player information. This method calls the {@link TBMCPlayerGetInfoEvent} to get all the player information across the TBMC plugins. * diff --git a/src/main/java/buttondevteam/lib/player/PlayerClass.java b/src/main/java/buttondevteam/lib/player/PlayerClass.java index a543849..4c22784 100644 --- a/src/main/java/buttondevteam/lib/player/PlayerClass.java +++ b/src/main/java/buttondevteam/lib/player/PlayerClass.java @@ -5,8 +5,17 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Specifies a {@link TBMCPlayerBase} direct subclass. For Minecraft data, use {@link UserClass} + * + * @author NorbiPeti + * + */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface PlayerClass { + /** + * Indicates the plugin's name which this player class belongs to. Used to create a section for each plugin. + */ String pluginname(); } diff --git a/src/main/java/buttondevteam/lib/player/PlayerData.java b/src/main/java/buttondevteam/lib/player/PlayerData.java new file mode 100644 index 0000000..f729907 --- /dev/null +++ b/src/main/java/buttondevteam/lib/player/PlayerData.java @@ -0,0 +1,22 @@ +package buttondevteam.lib.player; + +import org.bukkit.configuration.file.YamlConfiguration; + +public class PlayerData { + private String name; + private YamlConfiguration yaml; + + public PlayerData(String name, YamlConfiguration yaml) { + this.name = name; + this.yaml = yaml; + } + + @SuppressWarnings("unchecked") + public T get() { + return (T) yaml.get(name); + } + + public void set(String value) { + yaml.set(name, value); + } +} diff --git a/src/main/java/buttondevteam/lib/player/TBMCPlayerBase.java b/src/main/java/buttondevteam/lib/player/TBMCPlayerBase.java index 954b3e0..87382a5 100644 --- a/src/main/java/buttondevteam/lib/player/TBMCPlayerBase.java +++ b/src/main/java/buttondevteam/lib/player/TBMCPlayerBase.java @@ -17,20 +17,24 @@ import com.palmergames.bukkit.towny.object.TownyUniverse; import buttondevteam.lib.TBMCCoreAPI; +@UserClass(foldername = "minecraft") public abstract class TBMCPlayerBase extends ChromaGamerBase { - private static final String FOLDER_NAME = "minecraft"; protected UUID uuid; + private String pluginname; + + protected TBMCPlayerBase() { + if (getClass().isAnnotationPresent(PlayerClass.class)) + pluginname = getClass().getAnnotation(PlayerClass.class).pluginname(); + throw new RuntimeException("Class not defined as player class! Use @PlayerClass"); + } + public UUID getUUID() { return uuid; } - public String getPlayerName() { - return plugindata.getString("playername", ""); - } - - public void setPlayerName(String value) { - plugindata.set("playername", value); + public PlayerData PlayerName() { + return data(); } @Override @@ -38,8 +42,14 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase { return getUUID().toString(); } - static { - addPlayerType(TBMCPlayerBase.class, FOLDER_NAME); + + /** + * Use from a method with the name of the key. For example, use flair() for the enclosing method to save to and load from "flair" + * + * @return A data object with methods to get and set + */ + protected PlayerData data() { + return super.data(pluginname); } /** @@ -96,7 +106,7 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase { try { player.close(); } catch (Exception e) { - new Exception("Failed to save player data for " + player.getPlayerName(), e).printStackTrace(); + new Exception("Failed to save player data for " + player.PlayerName().get(), e).printStackTrace(); } } @@ -105,14 +115,14 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase { */ public static void joinPlayer(Player p) { TBMCPlayer player = TBMCPlayerBase.getPlayer(p.getUniqueId(), TBMCPlayer.class); - Bukkit.getLogger().info("Loaded player: " + player.getPlayerName()); - if (player.getPlayerName() == null) { - player.setPlayerName(p.getName()); - Bukkit.getLogger().info("Player name saved: " + player.getPlayerName()); - } else if (!p.getName().equals(player.getPlayerName())) { - Bukkit.getLogger().info("Renaming " + player.getPlayerName() + " to " + p.getName()); + Bukkit.getLogger().info("Loaded player: " + player.PlayerName().get()); + if (player.PlayerName().get() == null) { + player.PlayerName().set(p.getName()); + Bukkit.getLogger().info("Player name saved: " + player.PlayerName().get()); + } else if (!p.getName().equals(player.PlayerName().get())) { + Bukkit.getLogger().info("Renaming " + player.PlayerName().get() + " to " + p.getName()); TownyUniverse tu = Towny.getPlugin(Towny.class).getTownyUniverse(); - Resident resident = tu.getResidentMap().get(player.getPlayerName()); + Resident resident = tu.getResidentMap().get(player.PlayerName().get()); if (resident == null) { Bukkit.getLogger().warning("Resident not found - couldn't rename in Towny."); TBMCCoreAPI.sendDebugMessage("Resident not found - couldn't rename in Towny."); @@ -127,7 +137,7 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase { } catch (NotRegisteredException e) { TBMCCoreAPI.SendException("Failed to rename resident, the resident isn't registered.", e); } - player.setPlayerName(p.getName()); + player.PlayerName().set(p.getName()); Bukkit.getLogger().info("Renaming done."); } playermap.put(p.getUniqueId() + "-" + TBMCPlayer.class.getSimpleName(), player); @@ -159,8 +169,8 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase { try { p.close(); } catch (Exception e) { - TBMCCoreAPI.SendException("Error while saving player " + p.getPlayerName() + " (" + p.getFolder() + "/" - + p.getFileName() + ")!", e); + TBMCCoreAPI.SendException("Error while saving player " + p.PlayerName().get() + " (" + p.getFolder() + + "/" + p.getFileName() + ")!", e); } }); } diff --git a/src/main/java/buttondevteam/lib/player/UserClass.java b/src/main/java/buttondevteam/lib/player/UserClass.java new file mode 100644 index 0000000..2f389ac --- /dev/null +++ b/src/main/java/buttondevteam/lib/player/UserClass.java @@ -0,0 +1,21 @@ +package buttondevteam.lib.player; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Specifies a {@link ChromaGamerBase} direct subclass. For Minecraft data, use {@link PlayerClass} + * + * @author NorbiPeti + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface UserClass { + /** + * Indicates which folder should the player files be saved in. + */ + String foldername(); +}