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
This commit is contained in:
Norbi Peti 2017-04-01 14:40:54 +02:00
parent 11f13af8cc
commit 153425be5e
7 changed files with 142 additions and 36 deletions

View file

@ -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() + ").");
}

View file

@ -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 <T extends ChromaGamerBase> void RegisterUserClass(Class<T> 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
*/

View file

@ -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<Class<?>, 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 <T extends ChromaGamerBase> void addPlayerType(Class<T> cl, String folder) {
playerTypes.put(cl, folder);
public static void RegisterPluginUserClass(Class<? extends ChromaGamerBase> 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 <T extends ChromaGamerBase> String getFolderForType(Class<T> 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 extends ChromaGamerBase> T getUser(String fname, Class<T> cl) {
try {
T obj = cl.newInstance();
@ -101,6 +105,8 @@ public abstract class ChromaGamerBase implements AutoCloseable {
*/
public <T extends ChromaGamerBase> 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<String, PlayerData> 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 <T> PlayerData<T> 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<T>(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 <T> PlayerData<T> 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<T>(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.
*

View file

@ -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();
}

View file

@ -0,0 +1,22 @@
package buttondevteam.lib.player;
import org.bukkit.configuration.file.YamlConfiguration;
public class PlayerData<T> {
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);
}
}

View file

@ -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<String> 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 <T> PlayerData<T> 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);
}
});
}

View file

@ -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();
}