Added AbstractUserClass, fixes
- Fixed ID problem - Fixed connectWith - Other fixes and improvements
This commit is contained in:
parent
ced3bd10a4
commit
1497a487a4
5 changed files with 68 additions and 38 deletions
|
@ -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();
|
||||||
|
}
|
|
@ -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));
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
*
|
*
|
||||||
|
|
|
@ -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());
|
||||||
|
|
Loading…
Reference in a new issue