Added AbstractUserClass, fixes

- Fixed ID problem
- Fixed connectWith
- Other fixes and improvements
This commit is contained in:
Norbi Peti 2017-04-11 21:15:22 +02:00
parent ced3bd10a4
commit 1497a487a4
5 changed files with 68 additions and 38 deletions

View file

@ -0,0 +1,28 @@
package buttondevteam.lib.player;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specifies a {@link ChromaGamerBase} direct subclass which's abstract. For Minecraft data, use {@link PlayerClass}
*
* @author NorbiPeti
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface AbstractUserClass {
/**
* Indicates which folder should the player files be saved in.
*/
String foldername();
/**
* Indicates the class to create when connecting accounts.
*/
Class<?> prototype();
}

View file

@ -21,7 +21,10 @@ public abstract class ChromaGamerBase implements AutoCloseable {
public static void RegisterPluginUserClass(Class<? extends ChromaGamerBase> userclass) { public static void RegisterPluginUserClass(Class<? extends ChromaGamerBase> userclass) {
if (userclass.isAnnotationPresent(UserClass.class)) if (userclass.isAnnotationPresent(UserClass.class))
playerTypes.put(userclass, userclass.getAnnotation(UserClass.class).foldername()); playerTypes.put(userclass, userclass.getAnnotation(UserClass.class).foldername());
else //<-- Really important else if (userclass.isAnnotationPresent(AbstractUserClass.class))
playerTypes.put(userclass.getAnnotation(AbstractUserClass.class).prototype(),
userclass.getAnnotation(AbstractUserClass.class).foldername());
else // <-- Really important
throw new RuntimeException("Class not registered as a user class! Use @UserClass or TBMCPlayerBase"); throw new RuntimeException("Class not registered as a user class! Use @UserClass or TBMCPlayerBase");
} }
@ -37,24 +40,24 @@ public abstract class ChromaGamerBase implements AutoCloseable {
public static <T extends ChromaGamerBase> String getFolderForType(Class<T> cl) { public static <T extends ChromaGamerBase> String getFolderForType(Class<T> cl) {
if (cl.isAnnotationPresent(UserClass.class)) if (cl.isAnnotationPresent(UserClass.class))
return cl.getAnnotation(UserClass.class).foldername(); return cl.getAnnotation(UserClass.class).foldername();
throw new RuntimeException("Class not registered as a user class! Use @UserClass"); else if (cl.isAnnotationPresent(AbstractUserClass.class))
return cl.getAnnotation(AbstractUserClass.class).foldername();
throw new RuntimeException("Class not registered as a user class! Use @UserClass or @AbstractUserClass");
} }
/** /**
* This method returns the filename for this player data. For example, for Minecraft-related data, use MC UUIDs, for Discord data, use Discord IDs, etc.<br> * This method returns the filename for this player data. For example, for Minecraft-related data, MC UUIDs, for Discord data, use Discord IDs, etc.<br>
* <b>Does not include .yml</b> * <b>Does not include .yml</b>
*/ */
public abstract String getFileName(); public final String getFileName() {
return plugindata.getString(getFolder() + "_id");
}
/** /**
* Use {@link #data()} or {@link #data(String)} where possible; the 'id' must be always set * Use {@link #data()} or {@link #data(String)} where possible; the 'id' must be always set
*/ */
protected YamlConfiguration plugindata; protected YamlConfiguration plugindata;
public String getID() {
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)} * 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)}
* *
@ -69,7 +72,7 @@ public abstract class ChromaGamerBase implements AutoCloseable {
final File file = new File(TBMC_PLAYERS_DIR + folder, fname + ".yml"); final File file = new File(TBMC_PLAYERS_DIR + folder, fname + ".yml");
file.getParentFile().mkdirs(); file.getParentFile().mkdirs();
obj.plugindata = YamlConfiguration.loadConfiguration(file); obj.plugindata = YamlConfiguration.loadConfiguration(file);
obj.plugindata.set(folder + "_id", obj.getID()); obj.plugindata.set(folder + "_id", fname);
return obj; return obj;
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("An error occured while loading a " + cl.getSimpleName() + "!", e); TBMCCoreAPI.SendException("An error occured while loading a " + cl.getSimpleName() + "!", e);
@ -110,13 +113,16 @@ public abstract class ChromaGamerBase implements AutoCloseable {
// Set the ID, go through all linked files and connect them as well // Set the ID, go through all linked files and connect them as well
if (!playerTypes.containsKey(getClass())) if (!playerTypes.containsKey(getClass()))
throw new RuntimeException("Class not registered as a user class! Use TBMCCoreAPI.RegisterUserClass"); 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 = getFolder();
final String ownFolder = user.getFolder(); user.plugindata.set(ownFolder + "_id", plugindata.getString(ownFolder + "_id"));
user.plugindata.set(ownFolder + "_id", plugindata.getString("id")); final String userFolder = user.getFolder();
plugindata.set(userFolder + "_id", user.plugindata.getString(userFolder + "_id"));
Consumer<YamlConfiguration> sync = sourcedata -> { Consumer<YamlConfiguration> sync = sourcedata -> {
final String sourcefolder = sourcedata == plugindata ? ownFolder : user.getFolder(); final String sourcefolder = sourcedata == plugindata ? ownFolder : userFolder;
final String id = sourcedata.getString("id"); final String id = sourcedata.getString(sourcefolder + "_id");
for (Entry<Class<?>, String> entry : playerTypes.entrySet()) { // Set our ID in all files we can find, both from our connections and the new ones for (Entry<Class<?>, String> entry : playerTypes.entrySet()) { // Set our ID in all files we can find, both from our connections and the new ones
if (entry.getKey() == getClass() || entry.getKey() == user.getClass())
continue;
final String otherid = sourcedata.getString(entry.getValue() + "_id"); final String otherid = sourcedata.getString(entry.getValue() + "_id");
if (otherid == null) if (otherid == null)
continue; continue;
@ -157,13 +163,13 @@ public abstract class ChromaGamerBase implements AutoCloseable {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends ChromaGamerBase> T getAs(Class<T> cl) { // TODO: Provide a way to use TBMCPlayerBase's loaded players public <T extends ChromaGamerBase> T getAs(Class<T> cl) { // TODO: Provide a way to use TBMCPlayerBase's loaded players
//System.out.println("getAs cls: " + cl.getSimpleName() + " =? " + getClass().getSimpleName()); // TODO: TMP - Don't be tired when programming
if (cl.getSimpleName().equals(getClass().getSimpleName())) if (cl.getSimpleName().equals(getClass().getSimpleName()))
return (T) this; return (T) this;
String newfolder = getFolderForType(cl); String newfolder = getFolderForType(cl);
if (newfolder == null) if (newfolder == null)
throw new RuntimeException("The specified class " + cl.getSimpleName() + " isn't registered!"); throw new RuntimeException("The specified class " + cl.getSimpleName() + " isn't registered!");
System.out.println("getAs newfolder: " + newfolder); if (newfolder.equals(getFolder())) // If in the same folder, the same filename is used
return getUser(getFileName(), cl);
if (!plugindata.contains(newfolder + "_id")) if (!plugindata.contains(newfolder + "_id"))
return null; return null;
return getUser(plugindata.getString(newfolder + "_id"), cl); return getUser(plugindata.getString(newfolder + "_id"), cl);
@ -173,6 +179,12 @@ public abstract class ChromaGamerBase implements AutoCloseable {
return getFolderForType(getClass()); return getFolderForType(getClass());
} }
private void ThrowIfNoUser() {
if (!getClass().isAnnotationPresent(UserClass.class)
&& !getClass().isAnnotationPresent(AbstractUserClass.class))
throw new RuntimeException("Class not registered as a user class! Use @UserClass");
}
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
private HashMap<String, PlayerData> datamap = new HashMap<>(); private HashMap<String, PlayerData> datamap = new HashMap<>();
@ -183,8 +195,7 @@ public abstract class ChromaGamerBase implements AutoCloseable {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected <T> PlayerData<T> data(String sectionname) { protected <T> PlayerData<T> data(String sectionname) {
if (!getClass().isAnnotationPresent(UserClass.class)) ThrowIfNoUser();
throw new RuntimeException("Class not registered as a user class! Use @UserClass");
String mname = sectionname + "." + new Exception().getStackTrace()[2].getMethodName(); String mname = sectionname + "." + new Exception().getStackTrace()[2].getMethodName();
if (!datamap.containsKey(mname)) if (!datamap.containsKey(mname))
datamap.put(mname, new PlayerData<T>(mname, plugindata)); datamap.put(mname, new PlayerData<T>(mname, plugindata));
@ -198,9 +209,7 @@ public abstract class ChromaGamerBase implements AutoCloseable {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected <T> PlayerData<T> data() { protected <T> PlayerData<T> data() {
//System.out.println("Calling ChromaGamerBase data"); // TODO: TMP - Debugged for hours ThrowIfNoUser();
if (!getClass().isAnnotationPresent(UserClass.class))
throw new RuntimeException("Class not registered as a user class! Use @UserClass");
String mname = new Exception().getStackTrace()[1].getMethodName(); String mname = new Exception().getStackTrace()[1].getMethodName();
if (!datamap.containsKey(mname)) if (!datamap.containsKey(mname))
datamap.put(mname, new PlayerData<T>(mname, plugindata)); datamap.put(mname, new PlayerData<T>(mname, plugindata));
@ -217,8 +226,7 @@ public abstract class ChromaGamerBase implements AutoCloseable {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected <T extends Enum<T>> EnumPlayerData<T> dataEnum(String sectionname, Class<T> cl) { protected <T extends Enum<T>> EnumPlayerData<T> dataEnum(String sectionname, Class<T> cl) {
if (!getClass().isAnnotationPresent(UserClass.class)) ThrowIfNoUser();
throw new RuntimeException("Class not registered as a user class! Use @UserClass");
String mname = sectionname + "." + new Exception().getStackTrace()[2].getMethodName(); String mname = sectionname + "." + new Exception().getStackTrace()[2].getMethodName();
if (!dataenummap.containsKey(mname)) if (!dataenummap.containsKey(mname))
dataenummap.put(mname, new EnumPlayerData<T>(mname, plugindata, cl)); dataenummap.put(mname, new EnumPlayerData<T>(mname, plugindata, cl));
@ -232,8 +240,7 @@ public abstract class ChromaGamerBase implements AutoCloseable {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected <T extends Enum<T>> EnumPlayerData<T> dataEnum(Class<T> cl) { protected <T extends Enum<T>> EnumPlayerData<T> dataEnum(Class<T> cl) {
if (!getClass().isAnnotationPresent(UserClass.class)) ThrowIfNoUser();
throw new RuntimeException("Class not registered as a user class! Use @UserClass");
String mname = new Exception().getStackTrace()[1].getMethodName(); String mname = new Exception().getStackTrace()[1].getMethodName();
if (!dataenummap.containsKey(mname)) if (!dataenummap.containsKey(mname))
dataenummap.put(mname, new EnumPlayerData<T>(mname, plugindata, cl)); dataenummap.put(mname, new EnumPlayerData<T>(mname, plugindata, cl));

View file

@ -17,7 +17,7 @@ import com.palmergames.bukkit.towny.object.TownyUniverse;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
@UserClass(foldername = "minecraft") @AbstractUserClass(foldername = "minecraft", prototype = TBMCPlayer.class)
public abstract class TBMCPlayerBase extends ChromaGamerBase { public abstract class TBMCPlayerBase extends ChromaGamerBase {
protected UUID uuid; protected UUID uuid;
@ -31,19 +31,15 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase {
} }
public UUID getUUID() { public UUID getUUID() {
if (uuid == null)
uuid = UUID.fromString(getFileName());
return uuid; return uuid;
} }
public PlayerData<String> PlayerName() { public PlayerData<String> PlayerName() {
//System.out.println("Calling playername"); // TODO: TMP - The data will only get stored if it's changed
return super.data(); return super.data();
} }
@Override
public String getFileName() {
return getUUID().toString();
}
/** /**
* 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" * 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"
* *
@ -51,7 +47,6 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase {
*/ */
@Override @Override
protected <T> PlayerData<T> data() { protected <T> PlayerData<T> data() {
//System.out.println("Calling TMBCPlayerBase data"); // TODO: TMP - Sigh
return super.data(pluginname); return super.data(pluginname);
} }
@ -78,17 +73,17 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase {
public static <T extends TBMCPlayerBase> T getPlayer(UUID uuid, Class<T> cl) { public static <T extends TBMCPlayerBase> T getPlayer(UUID uuid, Class<T> cl) {
if (playermap.containsKey(uuid + "-" + cl.getSimpleName())) if (playermap.containsKey(uuid + "-" + cl.getSimpleName()))
return (T) playermap.get(uuid + "-" + cl.getSimpleName()); return (T) playermap.get(uuid + "-" + cl.getSimpleName());
//System.out.println("A"); // System.out.println("A");
try { try {
T player; T player;
if (playermap.containsKey(uuid + "-" + TBMCPlayer.class.getSimpleName())) { if (playermap.containsKey(uuid + "-" + TBMCPlayer.class.getSimpleName())) {
//System.out.println("B"); - Don't program when tired // System.out.println("B"); - Don't program when tired
player = cl.newInstance(); player = cl.newInstance();
player.plugindata = playermap.get(uuid + "-" + TBMCPlayer.class.getSimpleName()).plugindata; player.plugindata = playermap.get(uuid + "-" + TBMCPlayer.class.getSimpleName()).plugindata;
playermap.put(uuid + "-" + cl.getSimpleName(), player); // It will get removed on player quit playermap.put(uuid + "-" + cl.getSimpleName(), player); // It will get removed on player quit
} else } else
player = ChromaGamerBase.getUser(uuid.toString(), cl); player = ChromaGamerBase.getUser(uuid.toString(), cl);
//System.out.println("C"); // System.out.println("C");
player.uuid = uuid; player.uuid = uuid;
return player; return player;
} catch (Exception e) { } catch (Exception e) {

View file

@ -7,7 +7,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* Specifies a {@link ChromaGamerBase} direct subclass. For Minecraft data, use {@link PlayerClass} * Specifies a {@link ChromaGamerBase} direct subclass which can be instantiated. For Minecraft data, use {@link PlayerClass}
* *
* @author NorbiPeti * @author NorbiPeti
* *

View file

@ -48,7 +48,7 @@ public class PlayerDataTest extends TestCase {
try (TestPlayerClass p = TBMCPlayerBase.getPlayer(uuid, TestPlayerClass.class)) { try (TestPlayerClass p = TBMCPlayerBase.getPlayer(uuid, TestPlayerClass.class)) {
p.PlayerName().set("Test"); p.PlayerName().set("Test");
assertEquals("Test", p.PlayerName().get()); assertEquals("Test", p.PlayerName().get());
p.testenum().set(TestEnum.A); // TODO: Fix enum saving p.testenum().set(TestEnum.A);
assertEquals(TestEnum.A, p.testenum().get()); assertEquals(TestEnum.A, p.testenum().get());
// p.TestShort().set((short) 5); // p.TestShort().set((short) 5);
// assertEquals((short) 5, (short) (int) p.TestShort().get()); // assertEquals((short) 5, (short) (int) p.TestShort().get());