Remade user data managing, added a test #30
7 changed files with 142 additions and 36 deletions
|
@ -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() + ").");
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
22
src/main/java/buttondevteam/lib/player/PlayerData.java
Normal file
22
src/main/java/buttondevteam/lib/player/PlayerData.java
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
21
src/main/java/buttondevteam/lib/player/UserClass.java
Normal file
21
src/main/java/buttondevteam/lib/player/UserClass.java
Normal 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();
|
||||
}
|
Loading…
Reference in a new issue