Merge pull request #30 from TBMCPlugins/dev
Remade user data managing, added a test
This commit is contained in:
commit
afd1b8dfa2
29 changed files with 828 additions and 624 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -222,3 +222,5 @@ TheButtonAutoFlair/out/artifacts/Autoflair/Autoflair.jar
|
||||||
*.name
|
*.name
|
||||||
.idea/compiler.xml
|
.idea/compiler.xml
|
||||||
*.xml
|
*.xml
|
||||||
|
|
||||||
|
TBMC/
|
||||||
|
|
5
pom.xml
5
pom.xml
|
@ -138,6 +138,11 @@
|
||||||
<artifactId>javassist</artifactId>
|
<artifactId>javassist</artifactId>
|
||||||
<version>3.20.0-GA</version>
|
<version>3.20.0-GA</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-core</artifactId>
|
||||||
|
<version>2.7.20</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<organization>
|
<organization>
|
||||||
<name>TBMCPlugins</name>
|
<name>TBMCPlugins</name>
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
package buttondevteam.core;
|
package buttondevteam.core;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandExecutor;
|
import org.bukkit.command.CommandExecutor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.command.ConsoleCommandSender;
|
|
||||||
import org.bukkit.command.PluginCommand;
|
import org.bukkit.command.PluginCommand;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
|
@ -1,16 +1,23 @@
|
||||||
package buttondevteam.core;
|
package buttondevteam.core;
|
||||||
|
|
||||||
import java.util.Map.Entry;
|
import java.io.File;
|
||||||
import java.util.UUID;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.bukkit.configuration.InvalidConfigurationException;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import org.bukkit.plugin.PluginDescriptionFile;
|
import org.bukkit.plugin.PluginDescriptionFile;
|
||||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
import buttondevteam.lib.TBMCCoreAPI;
|
import buttondevteam.lib.TBMCCoreAPI;
|
||||||
import buttondevteam.lib.TBMCPlayer;
|
|
||||||
import buttondevteam.lib.chat.TBMCChatAPI;
|
import buttondevteam.lib.chat.TBMCChatAPI;
|
||||||
|
import buttondevteam.lib.player.ChromaGamerBase;
|
||||||
|
import buttondevteam.lib.player.TBMCPlayerBase;
|
||||||
import net.milkbowl.vault.permission.Permission;
|
import net.milkbowl.vault.permission.Permission;
|
||||||
|
|
||||||
public class MainPlugin extends JavaPlugin {
|
public class MainPlugin extends JavaPlugin {
|
||||||
|
@ -20,6 +27,7 @@ public class MainPlugin extends JavaPlugin {
|
||||||
|
|
||||||
private PluginDescriptionFile pdfFile;
|
private PluginDescriptionFile pdfFile;
|
||||||
private Logger logger;
|
private Logger logger;
|
||||||
|
private int C = 0, keep = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
|
@ -33,15 +41,53 @@ public class MainPlugin extends JavaPlugin {
|
||||||
TBMCChatAPI.AddCommand(this, UpdatePluginCommand.class);
|
TBMCChatAPI.AddCommand(this, UpdatePluginCommand.class);
|
||||||
TBMCChatAPI.AddCommand(this, ScheduledRestartCommand.class);
|
TBMCChatAPI.AddCommand(this, ScheduledRestartCommand.class);
|
||||||
TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this);
|
TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this);
|
||||||
|
TBMCCoreAPI.RegisterUserClass(TBMCPlayerBase.class);
|
||||||
logger.info(pdfFile.getName() + " has been Enabled (V." + pdfFile.getVersion() + ").");
|
logger.info(pdfFile.getName() + " has been Enabled (V." + pdfFile.getVersion() + ").");
|
||||||
|
Arrays.stream(new File(ChromaGamerBase.TBMC_PLAYERS_DIR).listFiles(f -> !f.isDirectory())).map(f -> {
|
||||||
|
YamlConfiguration yc = new YamlConfiguration();
|
||||||
|
try {
|
||||||
|
yc.load(f);
|
||||||
|
} catch (IOException | InvalidConfigurationException e) {
|
||||||
|
TBMCCoreAPI.SendException("Error while converting player data!", e);
|
||||||
|
}
|
||||||
|
f.delete();
|
||||||
|
return yc;
|
||||||
|
}).forEach(yc -> {
|
||||||
|
try {
|
||||||
|
int flairtime = yc.getInt("flairtime"), fcount = yc.getInt("fcount"), fdeaths = yc.getInt("fdeaths");
|
||||||
|
String flairstate = yc.getString("flairstate");
|
||||||
|
List<String> usernames = yc.getStringList("usernames");
|
||||||
|
boolean flaircheater = yc.getBoolean("flaircheater");
|
||||||
|
final String uuid = yc.getString("uuid");
|
||||||
|
C++;
|
||||||
|
if ((fcount == 0 || fdeaths == 0)
|
||||||
|
&& (flairstate == null || "NoComment".equals(flairstate) || flairtime <= 0))
|
||||||
|
return; // Those who received no Fs yet will also get their stats reset if no flair
|
||||||
|
final File file = new File(ChromaGamerBase.TBMC_PLAYERS_DIR + "minecraft", uuid + ".yml");
|
||||||
|
YamlConfiguration targetyc = YamlConfiguration.loadConfiguration(file);
|
||||||
|
targetyc.set("PlayerName", yc.getString("playername"));
|
||||||
|
targetyc.set("minecraft_id", uuid);
|
||||||
|
ConfigurationSection bc = targetyc.createSection("ButtonChat");
|
||||||
|
bc.set("FlairTime", "NoComment".equals(flairstate) ? -3 : flairtime); // FlairTimeNone: -3
|
||||||
|
bc.set("FCount", fcount);
|
||||||
|
bc.set("FDeaths", fdeaths);
|
||||||
|
bc.set("FlairState", flairstate);
|
||||||
|
bc.set("UserNames", usernames);
|
||||||
|
bc.set("FlairCheater", flaircheater);
|
||||||
|
targetyc.save(file);
|
||||||
|
keep++;
|
||||||
|
} catch (Exception e) {
|
||||||
|
TBMCCoreAPI.SendException("Error while converting player data!", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Bukkit.getScheduler().runTask(this, () -> logger.info("Converted " + keep + " player data from " + C));
|
||||||
|
//TODO: Remove once ran it at least once
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
logger.info("Saving player data...");
|
logger.info("Saving player data...");
|
||||||
for (Entry<UUID, TBMCPlayer> entry : TBMCPlayer.getLoadedPlayers().entrySet()) {
|
TBMCPlayerBase.savePlayers();
|
||||||
TBMCPlayer.savePlayer(entry.getValue());
|
|
||||||
}
|
|
||||||
logger.info("Player data saved.");
|
logger.info("Player data saved.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,23 +6,17 @@ import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
|
||||||
import buttondevteam.lib.TBMCPlayer;
|
import buttondevteam.lib.player.TBMCPlayerBase;
|
||||||
|
|
||||||
public class PlayerListener implements Listener {
|
public class PlayerListener implements Listener {
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
public void OnPlayerJoin(PlayerJoinEvent event) {
|
public void OnPlayerJoin(PlayerJoinEvent event) {
|
||||||
TBMCPlayer player = TBMCPlayer.loadPlayer(event.getPlayer());
|
TBMCPlayerBase.joinPlayer(event.getPlayer());
|
||||||
if (player == null)
|
|
||||||
event.getPlayer().sendMessage("§c[TBMC] Failed to load player data! Please contact a mod.");
|
|
||||||
else
|
|
||||||
TBMCPlayer.joinPlayer(player);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
public void OnPlayerLeave(PlayerQuitEvent event) {
|
public void OnPlayerLeave(PlayerQuitEvent event) {
|
||||||
TBMCPlayer player = TBMCPlayer.getPlayer(event.getPlayer());
|
TBMCPlayerBase.quitPlayer(event.getPlayer());
|
||||||
TBMCPlayer.savePlayer(player);
|
|
||||||
TBMCPlayer.quitPlayer(player);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package buttondevteam.core;
|
package buttondevteam.core;
|
||||||
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.boss.BarColor;
|
import org.bukkit.boss.BarColor;
|
||||||
import org.bukkit.boss.BarFlag;
|
import org.bukkit.boss.BarFlag;
|
||||||
|
@ -51,7 +49,7 @@ public class ScheduledRestartCommand extends TBMCCommandBase {
|
||||||
if (restartcounter % 200 == 0)
|
if (restartcounter % 200 == 0)
|
||||||
Bukkit.broadcastMessage("§c-- The server is restarting in " + restartcounter / 20 + " seconds!");
|
Bukkit.broadcastMessage("§c-- The server is restarting in " + restartcounter / 20 + " seconds!");
|
||||||
restartbar.setProgress(restartcounter / (double) restarttime);
|
restartbar.setProgress(restartcounter / (double) restarttime);
|
||||||
restartbar.setTitle("Server restart in " + restartcounter / 20f);
|
restartbar.setTitle(String.format("Server restart in %f.2", restartcounter / 20f));
|
||||||
/*
|
/*
|
||||||
* if (restartcounter % 20 == 0) System.out.println("Progress: " + restartbar.getProgress());
|
* if (restartcounter % 20 == 0) System.out.println("Progress: " + restartbar.getProgress());
|
||||||
*/
|
*/
|
||||||
|
|
38
src/main/java/buttondevteam/core/TestPrepare.java
Normal file
38
src/main/java/buttondevteam/core/TestPrepare.java
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package buttondevteam.core;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Server;
|
||||||
|
import org.bukkit.plugin.PluginManager;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
|
public class TestPrepare {
|
||||||
|
public static void PrepareServer() {
|
||||||
|
Bukkit.setServer(Mockito.mock(Server.class, new Answer<Object>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||||
|
// System.out.println("Return type: " + invocation.getMethod().getReturnType());
|
||||||
|
// System.out.println(String.class.isAssignableFrom(invocation.getMethod().getReturnType()));
|
||||||
|
if (returns(invocation, String.class))
|
||||||
|
return "test";
|
||||||
|
if (returns(invocation, Logger.class))
|
||||||
|
return Logger.getAnonymousLogger();
|
||||||
|
if (returns(invocation, PluginManager.class))
|
||||||
|
return Mockito.mock(PluginManager.class);
|
||||||
|
if (returns(invocation, Collection.class))
|
||||||
|
return Collections.EMPTY_LIST;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean returns(InvocationOnMock invocation, Class<?> cl) {
|
||||||
|
return cl.isAssignableFrom(invocation.getMethod().getReturnType());
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,8 +18,10 @@ import org.bukkit.plugin.Plugin;
|
||||||
import com.google.gson.*;
|
import com.google.gson.*;
|
||||||
|
|
||||||
import buttondevteam.core.MainPlugin;
|
import buttondevteam.core.MainPlugin;
|
||||||
|
import buttondevteam.lib.player.ChromaGamerBase;
|
||||||
|
import buttondevteam.lib.potato.DebugPotato;
|
||||||
|
|
||||||
public final class TBMCCoreAPI {
|
public class TBMCCoreAPI {
|
||||||
static List<String> coders = new ArrayList<String>() {
|
static List<String> coders = new ArrayList<String>() {
|
||||||
private static final long serialVersionUID = -4462159250738367334L;
|
private static final long serialVersionUID = -4462159250738367334L;
|
||||||
{
|
{
|
||||||
|
@ -82,8 +84,7 @@ public final class TBMCCoreAPI {
|
||||||
info(sender, "Updating TBMC plugin: " + correctname + " from " + correctbranch.get());
|
info(sender, "Updating TBMC plugin: " + correctname + " from " + correctbranch.get());
|
||||||
URL url;
|
URL url;
|
||||||
final boolean isWindows = System.getProperty("os.name").contains("Windows");
|
final boolean isWindows = System.getProperty("os.name").contains("Windows");
|
||||||
File result = new File(
|
File result = new File("plugins/" + correctname + (isWindows ? ".jar" : ".jar_tmp"));
|
||||||
"plugins/" + correctname + (isWindows ? ".jar" : ".jar_tmp"));
|
|
||||||
File finalresult = new File("plugins/" + correctname + ".jar");
|
File finalresult = new File("plugins/" + correctname + ".jar");
|
||||||
try {
|
try {
|
||||||
url = new URL("https://jitpack.io/com/github/TBMCPlugins/"
|
url = new URL("https://jitpack.io/com/github/TBMCPlugins/"
|
||||||
|
@ -249,6 +250,10 @@ public final class TBMCCoreAPI {
|
||||||
EventExceptionHandler.registerEvents(listener, plugin, new EventExceptionCoreHandler());
|
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
|
* Send exceptions that haven't been sent (their events didn't get handled). This method is used by the DiscordPlugin's ready event
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,510 +0,0 @@
|
||||||
package buttondevteam.lib;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.OfflinePlayer;
|
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import com.palmergames.bukkit.towny.Towny;
|
|
||||||
import com.palmergames.bukkit.towny.object.Resident;
|
|
||||||
import com.palmergames.bukkit.towny.object.TownyUniverse;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* The class for holding data common to all TBMC plugins
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* Use {@link #asPluginPlayer(Class)} to get plugin-specific data
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @author Norbi
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class TBMCPlayer implements AutoCloseable {
|
|
||||||
private static final String TBMC_PLAYERS_DIR = "TBMC/players";
|
|
||||||
|
|
||||||
private ConcurrentHashMap<String, Object> data = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Gets a player data entry for the caller plugin returning the desired type.<br>
|
|
||||||
* <i>It will automatically determine the key and the return type.</i><br>
|
|
||||||
* Usage:
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* {@code
|
|
||||||
* public String getPlayerName() {
|
|
||||||
* return getData();
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @return The value or null if not found
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected <T> T getData() {
|
|
||||||
StackTraceElement st = new Exception().getStackTrace()[1];
|
|
||||||
String mname = st.getMethodName();
|
|
||||||
if (!mname.startsWith("get"))
|
|
||||||
throw new UnsupportedOperationException("Can only use getData from a getXYZ method");
|
|
||||||
Object ret = getLoadedPlayers().get(uuid).data.get(mname.substring("get".length()).toLowerCase());
|
|
||||||
if (ret != null && Integer.class.isAssignableFrom(ret.getClass()))
|
|
||||||
throw new UnsupportedOperationException("For integers use getIntData()");
|
|
||||||
if (ret != null && Boolean.class.isAssignableFrom(ret.getClass()))
|
|
||||||
throw new UnsupportedOperationException("For booleans use getBoolData()");
|
|
||||||
return (T) ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a player data entry <i>based on the caller method</i><br>
|
|
||||||
* Usage:
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* {@code
|
|
||||||
* public String setPlayerName(String value) {
|
|
||||||
* return setData(value);
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
* The value to set
|
|
||||||
*/
|
|
||||||
protected void setData(Object value) {
|
|
||||||
StackTraceElement st = new Exception().getStackTrace()[1];
|
|
||||||
String mname = st.getMethodName();
|
|
||||||
if (!mname.startsWith("set"))
|
|
||||||
throw new UnsupportedOperationException("Can only use setData from a setXYZ method");
|
|
||||||
getLoadedPlayers().get(uuid).data.put(mname.substring("set".length()).toLowerCase(), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Gets a player data entry for the caller plugin returning the desired type, <b>which is an enum</b><br>
|
|
||||||
* <i>It will automatically determine the key and the return type.</i><br>
|
|
||||||
* Usage:
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* {@code
|
|
||||||
* public String getSomeEnum() {
|
|
||||||
* return getEnumData();
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @return The value or null if not found
|
|
||||||
*/
|
|
||||||
protected <T extends Enum<T>> T getEnumData(Class<T> cl) {
|
|
||||||
StackTraceElement st = new Exception().getStackTrace()[1];
|
|
||||||
String mname = st.getMethodName();
|
|
||||||
if (!mname.startsWith("get"))
|
|
||||||
throw new UnsupportedOperationException("Can only use getEnumData from a getXYZ method");
|
|
||||||
final String retstr = (String) getLoadedPlayers().get(uuid).data
|
|
||||||
.get(mname.substring("get".length()).toLowerCase());
|
|
||||||
if (retstr != null)
|
|
||||||
return Enum.valueOf(cl, retstr);
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a player data entry <i>based on the caller method</i><br>
|
|
||||||
* Usage:
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* {@code
|
|
||||||
* public String setSomeEnum(SomeEnum value) {
|
|
||||||
* return setEnumData(value);
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
* The value to set
|
|
||||||
*/
|
|
||||||
protected void setEnumData(Enum<?> value) {
|
|
||||||
StackTraceElement st = new Exception().getStackTrace()[1];
|
|
||||||
String mname = st.getMethodName();
|
|
||||||
if (!mname.startsWith("set"))
|
|
||||||
throw new UnsupportedOperationException("Can only use setEnumData from a setXYZ method");
|
|
||||||
getLoadedPlayers().get(uuid).data.put(mname.substring("set".length()).toLowerCase(), value.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Gets a player data entry for the caller plugin returning the desired type, <b>which is a number</b><br>
|
|
||||||
* <i>It will automatically determine the key and the return type.</i><br>
|
|
||||||
* Usage:
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* {@code
|
|
||||||
* public short getNumber() {
|
|
||||||
* return getIntData();
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @return The value or null if not found
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected <T extends Number> Optional<T> getIntData(Class<T> cl) {
|
|
||||||
StackTraceElement st = new Exception().getStackTrace()[1];
|
|
||||||
String mname = st.getMethodName();
|
|
||||||
if (!mname.startsWith("get"))
|
|
||||||
throw new UnsupportedOperationException("Can only use getIntData from a getXYZ method");
|
|
||||||
Object obj = getLoadedPlayers().get(uuid).data.get(mname.substring("get".length()).toLowerCase());
|
|
||||||
if (obj == null)
|
|
||||||
return Optional.empty();
|
|
||||||
if (obj instanceof Short)
|
|
||||||
return Optional.of((T) obj);
|
|
||||||
if (!(Integer.class.isAssignableFrom(obj.getClass())))
|
|
||||||
throw new UnsupportedOperationException("The retrieved object isn't an integer: " + obj);
|
|
||||||
Integer int_ = (Integer) obj;
|
|
||||||
if (Short.class.isAssignableFrom(cl))
|
|
||||||
return Optional.of((T) (Object) int_.shortValue());
|
|
||||||
else
|
|
||||||
return Optional.of((T) (Object) int_);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a player data entry <i>based on the caller method</i><br>
|
|
||||||
* Usage:
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* {@code
|
|
||||||
* public String setNumber(short value) {
|
|
||||||
* return setIntData(value);
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
* The value to set
|
|
||||||
*/
|
|
||||||
protected void setIntData(Number value) {
|
|
||||||
StackTraceElement st = new Exception().getStackTrace()[1];
|
|
||||||
String mname = st.getMethodName();
|
|
||||||
if (!mname.startsWith("set"))
|
|
||||||
throw new UnsupportedOperationException("Can only use setIntData from a setXYZ method");
|
|
||||||
getLoadedPlayers().get(uuid).data.put(mname.substring("set".length()).toLowerCase(), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Gets a player data entry for the caller plugin returning a boolean.<br>
|
|
||||||
* Usage:
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* {@code
|
|
||||||
* public String getFlairCheater() {
|
|
||||||
* return getBoolData();
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @return The value or false if not found
|
|
||||||
*/
|
|
||||||
protected boolean getBoolData() {
|
|
||||||
StackTraceElement st = new Exception().getStackTrace()[1];
|
|
||||||
String mname = st.getMethodName();
|
|
||||||
if (!mname.startsWith("get"))
|
|
||||||
throw new UnsupportedOperationException("Can only use getData from a getXYZ method");
|
|
||||||
Object ret = getLoadedPlayers().get(uuid).data.get(mname.substring("get".length()).toLowerCase());
|
|
||||||
if (ret != null && !Boolean.class.isAssignableFrom(ret.getClass()))
|
|
||||||
throw new UnsupportedOperationException("Not a boolean!");
|
|
||||||
if (ret == null)
|
|
||||||
return false;
|
|
||||||
return (boolean) ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the player's Minecraft name
|
|
||||||
*
|
|
||||||
* @return The player's Minecraft name
|
|
||||||
*/
|
|
||||||
public String getPlayerName() {
|
|
||||||
return getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the player's Minecraft name
|
|
||||||
*
|
|
||||||
* @param playerName
|
|
||||||
* the new name
|
|
||||||
*/
|
|
||||||
public void setPlayerName(String playerName) {
|
|
||||||
setData(playerName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private UUID uuid; // Do not save it in the file
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the player's UUID
|
|
||||||
*
|
|
||||||
* @return The Minecraft UUID of the player
|
|
||||||
*/
|
|
||||||
public UUID getUuid() {
|
|
||||||
return uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ConcurrentHashMap<Class<? extends TBMCPlayer>, TBMCPlayer> playermap = new ConcurrentHashMap<>(); // TODO
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the TBMCPlayer object as a specific plugin player, keeping it's data *
|
|
||||||
*
|
|
||||||
* @param p
|
|
||||||
* Player to get
|
|
||||||
* @param cl
|
|
||||||
* The TBMCPlayer subclass
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T extends TBMCPlayer> T asPluginPlayer(Class<T> cl) {
|
|
||||||
T obj = null;
|
|
||||||
if (playermap.containsKey(cl))
|
|
||||||
return (T) playermap.get(cl);
|
|
||||||
try {
|
|
||||||
obj = cl.newInstance();
|
|
||||||
((TBMCPlayer) obj).uuid = uuid;
|
|
||||||
// ((TBMCPlayer) obj).data.putAll(data);
|
|
||||||
playermap.put(cl, obj);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static HashMap<UUID, TBMCPlayer> LoadedPlayers = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns a TBMC player from their name. Calling this method may return an offline player which will load it, therefore it's highly recommended to use {@link #close()} to unload the
|
|
||||||
* player data. Using try-with-resources may be the easiest way to achieve this. Example:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* {@code
|
|
||||||
* try(TBMCPlayer player = getFromName(p))
|
|
||||||
* {
|
|
||||||
* ...
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* The player's name
|
|
||||||
* @return The {@link TBMCPlayer} object for the player
|
|
||||||
*/
|
|
||||||
public static TBMCPlayer getFromName(String name) {
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
OfflinePlayer p = Bukkit.getOfflinePlayer(name);
|
|
||||||
if (p != null)
|
|
||||||
return getPlayer(p);
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns a TBMC player from a Bukkit player. Calling this method may return an offline player, therefore it's highly recommended to use {@link #close()} to unload the player data.
|
|
||||||
* Using try-with-resources may be the easiest way to achieve this. Example:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* {@code
|
|
||||||
* try(TBMCPlayer player = getPlayer(p))
|
|
||||||
* {
|
|
||||||
* ...
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param p
|
|
||||||
* The Player object
|
|
||||||
* @return The {@link TBMCPlayer} object for the player
|
|
||||||
*/
|
|
||||||
public static TBMCPlayer getPlayer(OfflinePlayer p) {
|
|
||||||
if (TBMCPlayer.getLoadedPlayers().containsKey(p.getUniqueId()))
|
|
||||||
return TBMCPlayer.getLoadedPlayers().get(p.getUniqueId());
|
|
||||||
else
|
|
||||||
return TBMCPlayer.loadPlayer(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns a TBMC player from a player UUID. Calling this method may return an offline player, therefore it's highly recommended to use {@link #close()} to unload the player data.
|
|
||||||
* Using try-with-resources may be the easiest way to achieve this. Example:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* {@code
|
|
||||||
* try(TBMCPlayer player = getPlayer(p))
|
|
||||||
* {
|
|
||||||
* ...
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param p
|
|
||||||
* The Player object
|
|
||||||
* @return The {@link TBMCPlayer} object for the player
|
|
||||||
*/
|
|
||||||
public static TBMCPlayer getPlayer(UUID uuid) {
|
|
||||||
if (TBMCPlayer.getLoadedPlayers().containsKey(uuid))
|
|
||||||
return TBMCPlayer.getLoadedPlayers().get(uuid);
|
|
||||||
else
|
|
||||||
return TBMCPlayer.loadPlayer(Bukkit.getOfflinePlayer(uuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a convenience method for {@link #getPlayer(OfflinePlayer)}.{@link #asPluginPlayer(Class)}.
|
|
||||||
*
|
|
||||||
* See those methods for more information.
|
|
||||||
*
|
|
||||||
* @param p
|
|
||||||
* Player to get
|
|
||||||
* @param cl
|
|
||||||
* The TBMCPlayer subclass
|
|
||||||
* @return The player as a subtype of TBMCPlayer
|
|
||||||
*/
|
|
||||||
public static <T extends TBMCPlayer> T getPlayerAs(OfflinePlayer p, Class<T> cl) {
|
|
||||||
return getPlayer(p).asPluginPlayer(cl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a convenience method for {@link #getPlayer(UUID)}.{@link #asPluginPlayer(Class)}
|
|
||||||
*
|
|
||||||
* See those methods for more information.
|
|
||||||
*
|
|
||||||
* @param uuid
|
|
||||||
* The UUID of the player to get
|
|
||||||
* @param cl
|
|
||||||
* The TBMCPlayer subclass
|
|
||||||
* @return The player as a subtype of TBMCPlayer
|
|
||||||
*/
|
|
||||||
public static <T extends TBMCPlayer> T getPlayerAs(UUID uuid, Class<T> cl) {
|
|
||||||
return getPlayer(uuid).asPluginPlayer(cl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only intended to use from ButtonCore
|
|
||||||
*/
|
|
||||||
public static TBMCPlayer loadPlayer(OfflinePlayer p) {
|
|
||||||
if (getLoadedPlayers().containsKey(p.getUniqueId()))
|
|
||||||
return getLoadedPlayers().get(p.getUniqueId());
|
|
||||||
File file = new File(TBMC_PLAYERS_DIR);
|
|
||||||
file.mkdirs();
|
|
||||||
file = new File(TBMC_PLAYERS_DIR, p.getUniqueId().toString() + ".yml");
|
|
||||||
if (!file.exists())
|
|
||||||
return addPlayer(p);
|
|
||||||
else {
|
|
||||||
final YamlConfiguration yc = new YamlConfiguration();
|
|
||||||
try {
|
|
||||||
yc.load(file);
|
|
||||||
} catch (Exception e) {
|
|
||||||
new Exception("Failed to load player data for " + p.getUniqueId(), e).printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
TBMCPlayer player = new TBMCPlayer();
|
|
||||||
player.uuid = p.getUniqueId();
|
|
||||||
player.data.putAll(yc.getValues(true));
|
|
||||||
getLoadedPlayers().put(p.getUniqueId(), player); // Accessing any value requires it to be in the map
|
|
||||||
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());
|
|
||||||
TownyUniverse tu = Towny.getPlugin(Towny.class).getTownyUniverse();
|
|
||||||
Resident resident = tu.getResidentMap().get(player.getPlayerName());
|
|
||||||
if (resident == null)
|
|
||||||
Bukkit.getLogger().warning("Resident not found - couldn't rename in Towny.");
|
|
||||||
else if (tu.getResidentMap().contains(p.getName()))
|
|
||||||
Bukkit.getLogger().warning("Target resident name is already in use."); // TODO: Handle
|
|
||||||
else
|
|
||||||
resident.setName(p.getName());
|
|
||||||
player.setPlayerName(p.getName());
|
|
||||||
Bukkit.getLogger().info("Renaming done.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load in other plugins
|
|
||||||
Bukkit.getServer().getPluginManager().callEvent(new TBMCPlayerLoadEvent(yc, player));
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only intended to use from ButtonCore
|
|
||||||
*/
|
|
||||||
public static TBMCPlayer addPlayer(OfflinePlayer p) {
|
|
||||||
TBMCPlayer player = new TBMCPlayer();
|
|
||||||
player.uuid = p.getUniqueId();
|
|
||||||
getLoadedPlayers().put(p.getUniqueId(), player); // Accessing any value requires it to be in the map
|
|
||||||
player.setPlayerName(p.getName());
|
|
||||||
Bukkit.getServer().getPluginManager().callEvent(new TBMCPlayerAddEvent(player));
|
|
||||||
savePlayer(player);
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only intended to use from ButtonCore
|
|
||||||
*/
|
|
||||||
public static void savePlayer(TBMCPlayer player) {
|
|
||||||
YamlConfiguration yc = new YamlConfiguration();
|
|
||||||
for (Entry<String, Object> item : player.data.entrySet())
|
|
||||||
yc.set(item.getKey(), item.getValue());
|
|
||||||
Bukkit.getServer().getPluginManager().callEvent(new TBMCPlayerSaveEvent(yc, player));
|
|
||||||
try {
|
|
||||||
yc.save(TBMC_PLAYERS_DIR + "/" + player.uuid + ".yml");
|
|
||||||
} catch (IOException e) {
|
|
||||||
new Exception("Failed to save player data for " + player.getPlayerName(), e).printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only intended to use from ButtonCore
|
|
||||||
*/
|
|
||||||
public static void joinPlayer(TBMCPlayer player) {
|
|
||||||
getLoadedPlayers().put(player.uuid, player);
|
|
||||||
Bukkit.getServer().getPluginManager().callEvent(new TBMCPlayerJoinEvent(player));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only intended to use from ButtonCore
|
|
||||||
*/
|
|
||||||
public static void quitPlayer(TBMCPlayer player) {
|
|
||||||
Bukkit.getServer().getPluginManager().callEvent(new TBMCPlayerQuitEvent(player));
|
|
||||||
getLoadedPlayers().remove(player.uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* By default the player data will only get cleaned from memory when the player quits. Therefore this method must be called when accessing an offline player to clean the player data up. Calling
|
|
||||||
* this method will have no effect on online players.<br>
|
|
||||||
* Therefore, the recommended use is to call it when using {@link #GetPlayer} or use try-with-resources.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
final Player player = Bukkit.getPlayer(uuid);
|
|
||||||
if (player == null || !player.isOnline())
|
|
||||||
getLoadedPlayers().remove(uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HashMap<UUID, TBMCPlayer> getLoadedPlayers() {
|
|
||||||
return LoadedPlayers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get player information. This method calls the {@link TBMCPlayerGetInfoEvent} to get all the player information across the TBMC plugins.
|
|
||||||
*
|
|
||||||
* @param target
|
|
||||||
* The {@link InfoTarget} to return the info for.
|
|
||||||
* @return The player information.
|
|
||||||
*/
|
|
||||||
public String getInfo(InfoTarget target) {
|
|
||||||
TBMCPlayerGetInfoEvent event = new TBMCPlayerGetInfoEvent(this, target);
|
|
||||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
|
||||||
return event.getResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum InfoTarget {
|
|
||||||
MCHover, MCCommand, Discord
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
package buttondevteam.lib;
|
|
||||||
|
|
||||||
import org.bukkit.event.Event;
|
|
||||||
import org.bukkit.event.HandlerList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* This event gets called when a new player joins. After this event, the
|
|
||||||
* {@link TBMCPlayerSaveEvent} will be called.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @author Norbi
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class TBMCPlayerAddEvent extends Event {
|
|
||||||
private static final HandlerList handlers = new HandlerList();
|
|
||||||
|
|
||||||
private TBMCPlayer player;
|
|
||||||
|
|
||||||
public TBMCPlayerAddEvent(TBMCPlayer player) {
|
|
||||||
this.player = player;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TBMCPlayer GetPlayer() {
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HandlerList getHandlers() {
|
|
||||||
return handlers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HandlerList getHandlerList() {
|
|
||||||
return handlers;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
package buttondevteam.lib;
|
|
||||||
|
|
||||||
public abstract class TBMCPlayerBase {
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
public abstract String getFileName();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the folder the file is in. For example, for Minecraft data, this should be "minecraft", for Discord, "discord", etc.
|
|
||||||
*/
|
|
||||||
public abstract String getFolder();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
||||||
|
}
|
262
src/main/java/buttondevteam/lib/player/ChromaGamerBase.java
Normal file
262
src/main/java/buttondevteam/lib/player/ChromaGamerBase.java
Normal file
|
@ -0,0 +1,262 @@
|
||||||
|
package buttondevteam.lib.player;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
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 {
|
||||||
|
public static final String TBMC_PLAYERS_DIR = "TBMC/players/";
|
||||||
|
|
||||||
|
private static final HashMap<Class<?>, String> playerTypes = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for connecting with every type of user ({@link #connectWith(ChromaGamerBase)})
|
||||||
|
*/
|
||||||
|
public static void RegisterPluginUserClass(Class<? extends ChromaGamerBase> userclass) {
|
||||||
|
if (userclass.isAnnotationPresent(UserClass.class))
|
||||||
|
playerTypes.put(userclass, userclass.getAnnotation(UserClass.class).foldername());
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 (cl.isAnnotationPresent(UserClass.class))
|
||||||
|
return cl.getAnnotation(UserClass.class).foldername();
|
||||||
|
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, MC UUIDs, for Discord data, use Discord IDs, etc.<br>
|
||||||
|
* <b>Does not include .yml</b>
|
||||||
|
*/
|
||||||
|
public final String getFileName() {
|
||||||
|
return plugindata.getString(getFolder() + "_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use {@link #data()} or {@link #data(String)} where possible; the 'id' must be always set
|
||||||
|
*/
|
||||||
|
protected YamlConfiguration plugindata;
|
||||||
|
|
||||||
|
/***
|
||||||
|
* 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();
|
||||||
|
final String folder = getFolderForType(cl);
|
||||||
|
final File file = new File(TBMC_PLAYERS_DIR + folder, fname + ".yml");
|
||||||
|
file.getParentFile().mkdirs();
|
||||||
|
obj.plugindata = YamlConfiguration.loadConfiguration(file);
|
||||||
|
obj.plugindata.set(folder + "_id", fname);
|
||||||
|
return obj;
|
||||||
|
} catch (Exception e) {
|
||||||
|
TBMCCoreAPI.SendException("An error occured while loading a " + cl.getSimpleName() + "!", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the player. It'll pass all exceptions to the caller. To automatically handle the exception, use {@link #save()} instead.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void close() throws Exception {
|
||||||
|
if (plugindata.getKeys(false).size() > 0)
|
||||||
|
plugindata.save(new File(TBMC_PLAYERS_DIR + getFolder(), getFileName() + ".yml"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the player. It'll handle all exceptions that may happen. To catch the exception, use {@link #close()} instead.
|
||||||
|
*/
|
||||||
|
public void save() {
|
||||||
|
try {
|
||||||
|
close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
TBMCCoreAPI.SendException("Error while saving player to " + getFolder() + "/" + getFileName() + ".yml!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect two accounts. Do not use for connecting two Minecraft accounts or similar. Also make sure you have the "id" tag set
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
* The account to connect with
|
||||||
|
*/
|
||||||
|
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");
|
||||||
|
final String ownFolder = getFolder();
|
||||||
|
user.plugindata.set(ownFolder + "_id", plugindata.getString(ownFolder + "_id"));
|
||||||
|
final String userFolder = user.getFolder();
|
||||||
|
plugindata.set(userFolder + "_id", user.plugindata.getString(userFolder + "_id"));
|
||||||
|
Consumer<YamlConfiguration> sync = sourcedata -> {
|
||||||
|
final String sourcefolder = sourcedata == plugindata ? ownFolder : userFolder;
|
||||||
|
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
|
||||||
|
if (entry.getKey() == getClass() || entry.getKey() == user.getClass())
|
||||||
|
continue;
|
||||||
|
final String otherid = sourcedata.getString(entry.getValue() + "_id");
|
||||||
|
if (otherid == null)
|
||||||
|
continue;
|
||||||
|
try (@SuppressWarnings("unchecked")
|
||||||
|
ChromaGamerBase cg = getUser(otherid, (Class<T>) entry.getKey())) {
|
||||||
|
cg.plugindata.set(sourcefolder + "_id", id); // Set new IDs
|
||||||
|
for (Entry<Class<?>, String> item : playerTypes.entrySet())
|
||||||
|
if (sourcedata.contains(item.getValue() + "_id"))
|
||||||
|
cg.plugindata.set(item.getValue() + "_id", sourcedata.getString(item.getValue() + "_id")); // Set all existing IDs
|
||||||
|
} catch (Exception e) {
|
||||||
|
TBMCCoreAPI.SendException("Failed to update " + sourcefolder + " ID in player files for " + id
|
||||||
|
+ " in folder with " + entry.getValue() + " id " + otherid + "!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
sync.accept(plugindata);
|
||||||
|
sync.accept(user.plugindata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retunrs the ID for the T typed player object connected with this one or null if no connection found.
|
||||||
|
*
|
||||||
|
* @param cl
|
||||||
|
* The player class to get the ID from
|
||||||
|
* @return The ID or null if not found
|
||||||
|
*/
|
||||||
|
public <T extends ChromaGamerBase> String getConnectedID(Class<T> cl) {
|
||||||
|
return plugindata.getString(getFolderForType(cl) + "_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns this player as a plugin player. This will return a new instance unless the player is online.<br>
|
||||||
|
* Make sure to close both the returned and this object. A try-with-resources block or two can help.<br>
|
||||||
|
*
|
||||||
|
* @param cl
|
||||||
|
* The target player class
|
||||||
|
* @return The player as a {@link T} object or null if not having an account there
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T extends ChromaGamerBase> T getAs(Class<T> cl) { // TODO: Provide a way to use TBMCPlayerBase's loaded players
|
||||||
|
if (cl.getSimpleName().equals(getClass().getSimpleName()))
|
||||||
|
return (T) this;
|
||||||
|
String newfolder = getFolderForType(cl);
|
||||||
|
if (newfolder == null)
|
||||||
|
throw new RuntimeException("The specified class " + cl.getSimpleName() + " isn't registered!");
|
||||||
|
if (newfolder.equals(getFolder())) // If in the same folder, the same filename is used
|
||||||
|
return getUser(getFileName(), cl);
|
||||||
|
if (!plugindata.contains(newfolder + "_id"))
|
||||||
|
return null;
|
||||||
|
return getUser(plugindata.getString(newfolder + "_id"), cl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFolder() {
|
||||||
|
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")
|
||||||
|
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) {
|
||||||
|
ThrowIfNoUser();
|
||||||
|
String mname = sectionname + "." + new Exception().getStackTrace()[2].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() {
|
||||||
|
ThrowIfNoUser();
|
||||||
|
String mname = new Exception().getStackTrace()[1].getMethodName();
|
||||||
|
if (!datamap.containsKey(mname))
|
||||||
|
datamap.put(mname, new PlayerData<T>(mname, plugindata));
|
||||||
|
return datamap.get(mname);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
private HashMap<String, EnumPlayerData> dataenummap = 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 extends Enum<T>> EnumPlayerData<T> dataEnum(String sectionname, Class<T> cl) {
|
||||||
|
ThrowIfNoUser();
|
||||||
|
String mname = sectionname + "." + new Exception().getStackTrace()[2].getMethodName();
|
||||||
|
if (!dataenummap.containsKey(mname))
|
||||||
|
dataenummap.put(mname, new EnumPlayerData<T>(mname, plugindata, cl));
|
||||||
|
return dataenummap.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 extends Enum<T>> EnumPlayerData<T> dataEnum(Class<T> cl) {
|
||||||
|
ThrowIfNoUser();
|
||||||
|
String mname = new Exception().getStackTrace()[1].getMethodName();
|
||||||
|
if (!dataenummap.containsKey(mname))
|
||||||
|
dataenummap.put(mname, new EnumPlayerData<T>(mname, plugindata, cl));
|
||||||
|
return dataenummap.get(mname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get player information. This method calls the {@link TBMCPlayerGetInfoEvent} to get all the player information across the TBMC plugins.
|
||||||
|
*
|
||||||
|
* @param target
|
||||||
|
* The {@link InfoTarget} to return the info for.
|
||||||
|
* @return The player information.
|
||||||
|
*/
|
||||||
|
public String getInfo(InfoTarget target) {
|
||||||
|
TBMCPlayerGetInfoEvent event = new TBMCPlayerGetInfoEvent(this, target);
|
||||||
|
Bukkit.getServer().getPluginManager().callEvent(event);
|
||||||
|
return event.getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum InfoTarget {
|
||||||
|
MCHover, MCCommand, Discord
|
||||||
|
}
|
||||||
|
}
|
29
src/main/java/buttondevteam/lib/player/EnumPlayerData.java
Normal file
29
src/main/java/buttondevteam/lib/player/EnumPlayerData.java
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package buttondevteam.lib.player;
|
||||||
|
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
|
||||||
|
public class EnumPlayerData<T extends Enum<T>> {
|
||||||
|
private PlayerData<String> data;
|
||||||
|
private Class<T> cl;
|
||||||
|
|
||||||
|
public EnumPlayerData(String name, YamlConfiguration yaml, Class<T> cl) {
|
||||||
|
data = new PlayerData<String>(name, yaml);
|
||||||
|
this.cl = cl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T get() {
|
||||||
|
String str = data.get();
|
||||||
|
if (str == null || str.equals(""))
|
||||||
|
return null;
|
||||||
|
return Enum.valueOf(cl, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(T value) {
|
||||||
|
data.set(value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getOrDefault(T def) {
|
||||||
|
T value = get();
|
||||||
|
return value == null ? def : value;
|
||||||
|
}
|
||||||
|
}
|
21
src/main/java/buttondevteam/lib/player/PlayerClass.java
Normal file
21
src/main/java/buttondevteam/lib/player/PlayerClass.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 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();
|
||||||
|
}
|
33
src/main/java/buttondevteam/lib/player/PlayerData.java
Normal file
33
src/main/java/buttondevteam/lib/player/PlayerData.java
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
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() {
|
||||||
|
Object value = yaml.get(name);
|
||||||
|
return (T) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(T value) {
|
||||||
|
yaml.set(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getOrDefault(T def) {
|
||||||
|
T value = get();
|
||||||
|
return value == null ? def : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return get().toString();
|
||||||
|
}
|
||||||
|
}
|
6
src/main/java/buttondevteam/lib/player/TBMCPlayer.java
Normal file
6
src/main/java/buttondevteam/lib/player/TBMCPlayer.java
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package buttondevteam.lib.player;
|
||||||
|
|
||||||
|
@PlayerClass(pluginname = "ButtonCore")
|
||||||
|
public final class TBMCPlayer extends TBMCPlayerBase {
|
||||||
|
|
||||||
|
}
|
220
src/main/java/buttondevteam/lib/player/TBMCPlayerBase.java
Normal file
220
src/main/java/buttondevteam/lib/player/TBMCPlayerBase.java
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
package buttondevteam.lib.player;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import com.palmergames.bukkit.towny.Towny;
|
||||||
|
import com.palmergames.bukkit.towny.exceptions.AlreadyRegisteredException;
|
||||||
|
import com.palmergames.bukkit.towny.exceptions.NotRegisteredException;
|
||||||
|
import com.palmergames.bukkit.towny.object.Resident;
|
||||||
|
import com.palmergames.bukkit.towny.object.TownyUniverse;
|
||||||
|
|
||||||
|
import buttondevteam.lib.TBMCCoreAPI;
|
||||||
|
|
||||||
|
@AbstractUserClass(foldername = "minecraft", prototype = TBMCPlayer.class)
|
||||||
|
public abstract class TBMCPlayerBase extends ChromaGamerBase {
|
||||||
|
protected UUID uuid;
|
||||||
|
|
||||||
|
private String pluginname;
|
||||||
|
|
||||||
|
protected TBMCPlayerBase() {
|
||||||
|
if (getClass().isAnnotationPresent(PlayerClass.class))
|
||||||
|
pluginname = getClass().getAnnotation(PlayerClass.class).pluginname();
|
||||||
|
else
|
||||||
|
throw new RuntimeException("Class not defined as player class! Use @PlayerClass");
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getUUID() {
|
||||||
|
if (uuid == null)
|
||||||
|
uuid = UUID.fromString(getFileName());
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerData<String> PlayerName() {
|
||||||
|
return super.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected <T> PlayerData<T> data() {
|
||||||
|
return super.data(pluginname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected <T extends Enum<T>> EnumPlayerData<T> dataEnum(Class<T> cl) {
|
||||||
|
return super.dataEnum(pluginname, cl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get player as a plugin player
|
||||||
|
*
|
||||||
|
* @param uuid
|
||||||
|
* The UUID of the player to get
|
||||||
|
* @param cl
|
||||||
|
* The type of the player
|
||||||
|
* @return The requested player object
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T extends TBMCPlayerBase> T getPlayer(UUID uuid, Class<T> cl) {
|
||||||
|
if (playermap.containsKey(uuid + "-" + cl.getSimpleName()))
|
||||||
|
return (T) playermap.get(uuid + "-" + cl.getSimpleName());
|
||||||
|
// System.out.println("A");
|
||||||
|
try {
|
||||||
|
T player;
|
||||||
|
if (playermap.containsKey(uuid + "-" + TBMCPlayer.class.getSimpleName())) {
|
||||||
|
// System.out.println("B"); - Don't program when tired
|
||||||
|
player = cl.newInstance();
|
||||||
|
player.plugindata = playermap.get(uuid + "-" + TBMCPlayer.class.getSimpleName()).plugindata;
|
||||||
|
playermap.put(uuid + "-" + cl.getSimpleName(), player); // It will get removed on player quit
|
||||||
|
} else
|
||||||
|
player = ChromaGamerBase.getUser(uuid.toString(), cl);
|
||||||
|
// System.out.println("C");
|
||||||
|
player.uuid = uuid;
|
||||||
|
return player;
|
||||||
|
} catch (Exception e) {
|
||||||
|
TBMCCoreAPI.SendException(
|
||||||
|
"Failed to get player with UUID " + uuid + " and class " + cl.getSimpleName() + "!", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key: UUID-Class
|
||||||
|
*/
|
||||||
|
static final ConcurrentHashMap<String, TBMCPlayerBase> playermap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the TBMCPlayer object as a specific plugin player, keeping it's data<br>
|
||||||
|
* Make sure to use try-with-resources with this to save the data, as it may need to load the file
|
||||||
|
*
|
||||||
|
* @param cl
|
||||||
|
* The TBMCPlayer subclass
|
||||||
|
*/
|
||||||
|
public <T extends TBMCPlayerBase> T asPluginPlayer(Class<T> cl) {
|
||||||
|
return getPlayer(uuid, cl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only intended to use from ButtonCore
|
||||||
|
*/
|
||||||
|
public static void savePlayer(TBMCPlayerBase player) {
|
||||||
|
Bukkit.getServer().getPluginManager().callEvent(new TBMCPlayerSaveEvent(player));
|
||||||
|
try {
|
||||||
|
player.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
new Exception("Failed to save player data for " + player.PlayerName().get(), e).printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only intended to use from ButtonCore
|
||||||
|
*/
|
||||||
|
public static void joinPlayer(Player p) {
|
||||||
|
TBMCPlayer player = TBMCPlayerBase.getPlayer(p.getUniqueId(), TBMCPlayer.class);
|
||||||
|
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.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.");
|
||||||
|
} else if (tu.getResidentMap().contains(p.getName())) {
|
||||||
|
Bukkit.getLogger().warning("Target resident name is already in use."); // TODO: Handle
|
||||||
|
TBMCCoreAPI.sendDebugMessage("Target resident name is already in use.");
|
||||||
|
} else
|
||||||
|
try {
|
||||||
|
TownyUniverse.getDataSource().renamePlayer(resident, p.getName());
|
||||||
|
} catch (AlreadyRegisteredException e) {
|
||||||
|
TBMCCoreAPI.SendException("Failed to rename resident, there's already one with this name.", e);
|
||||||
|
} catch (NotRegisteredException e) {
|
||||||
|
TBMCCoreAPI.SendException("Failed to rename resident, the resident isn't registered.", e);
|
||||||
|
}
|
||||||
|
player.PlayerName().set(p.getName());
|
||||||
|
Bukkit.getLogger().info("Renaming done.");
|
||||||
|
}
|
||||||
|
playermap.put(p.getUniqueId() + "-" + TBMCPlayer.class.getSimpleName(), player);
|
||||||
|
|
||||||
|
// Load in other plugins
|
||||||
|
Bukkit.getServer().getPluginManager().callEvent(new TBMCPlayerLoadEvent(player));
|
||||||
|
Bukkit.getServer().getPluginManager().callEvent(new TBMCPlayerJoinEvent(player));
|
||||||
|
player.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only intended to use from ButtonCore
|
||||||
|
*/
|
||||||
|
public static void quitPlayer(Player p) {
|
||||||
|
final TBMCPlayerBase player = playermap.get(p.getUniqueId() + "-" + TBMCPlayer.class.getSimpleName());
|
||||||
|
player.save();
|
||||||
|
Bukkit.getServer().getPluginManager().callEvent(new TBMCPlayerQuitEvent(player));
|
||||||
|
Iterator<Entry<String, TBMCPlayerBase>> it = playermap.entrySet().iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Entry<String, TBMCPlayerBase> entry = it.next();
|
||||||
|
if (entry.getKey().startsWith(p.getUniqueId().toString()))
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void savePlayers() {
|
||||||
|
playermap.values().stream().forEach(p -> {
|
||||||
|
try {
|
||||||
|
p.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
TBMCCoreAPI.SendException("Error while saving player " + p.PlayerName().get() + " (" + p.getFolder()
|
||||||
|
+ "/" + p.getFileName() + ")!", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns a TBMC player from their name. Calling this method may return an offline player which will load it, therefore it's highly recommended to use {@link #close()} to unload the
|
||||||
|
* player data. Using try-with-resources may be the easiest way to achieve this. Example:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* {@code
|
||||||
|
* try(TBMCPlayer player = getFromName(p))
|
||||||
|
* {
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* The player's name
|
||||||
|
* @return The {@link TBMCPlayer} object for the player
|
||||||
|
*/
|
||||||
|
public static <T extends TBMCPlayerBase> T getFromName(String name, Class<T> cl) {
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
OfflinePlayer p = Bukkit.getOfflinePlayer(name);
|
||||||
|
if (p != null)
|
||||||
|
return getPlayer(p.getUniqueId(), cl);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws Exception {
|
||||||
|
Set<String> keys = plugindata.getKeys(false);
|
||||||
|
if (keys.size() > 1) // PlayerName is always saved, but we don't need a file for just that
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package buttondevteam.lib;
|
package buttondevteam.lib.player;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -7,7 +7,7 @@ import java.util.stream.Collectors;
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
import buttondevteam.lib.TBMCPlayer.InfoTarget;
|
import buttondevteam.lib.player.ChromaGamerBase.InfoTarget;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -20,11 +20,11 @@ import buttondevteam.lib.TBMCPlayer.InfoTarget;
|
||||||
public class TBMCPlayerGetInfoEvent extends Event {
|
public class TBMCPlayerGetInfoEvent extends Event {
|
||||||
private static final HandlerList handlers = new HandlerList();
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
private TBMCPlayer player;
|
private ChromaGamerBase player;
|
||||||
private List<String> infolines;
|
private List<String> infolines;
|
||||||
private TBMCPlayer.InfoTarget target;
|
private InfoTarget target;
|
||||||
|
|
||||||
TBMCPlayerGetInfoEvent(TBMCPlayer player, TBMCPlayer.InfoTarget target) {
|
TBMCPlayerGetInfoEvent(ChromaGamerBase player, InfoTarget target) {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
infolines = new ArrayList<>();
|
infolines = new ArrayList<>();
|
||||||
this.target = target;
|
this.target = target;
|
||||||
|
@ -35,7 +35,7 @@ public class TBMCPlayerGetInfoEvent extends Event {
|
||||||
*
|
*
|
||||||
* @return A player object
|
* @return A player object
|
||||||
*/
|
*/
|
||||||
public TBMCPlayer getPlayer() {
|
public ChromaGamerBase getPlayer() {
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ public class TBMCPlayerGetInfoEvent extends Event {
|
||||||
*
|
*
|
||||||
* @return The target of the information.
|
* @return The target of the information.
|
||||||
*/
|
*/
|
||||||
public TBMCPlayer.InfoTarget getTarget() {
|
public InfoTarget getTarget() {
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package buttondevteam.lib;
|
package buttondevteam.lib.player;
|
||||||
|
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
|
@ -6,13 +6,13 @@ import org.bukkit.event.HandlerList;
|
||||||
public class TBMCPlayerJoinEvent extends Event {
|
public class TBMCPlayerJoinEvent extends Event {
|
||||||
private static final HandlerList handlers = new HandlerList();
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
private TBMCPlayer player;
|
private TBMCPlayerBase player;
|
||||||
|
|
||||||
public TBMCPlayerJoinEvent(TBMCPlayer player) {
|
public TBMCPlayerJoinEvent(TBMCPlayerBase player) {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TBMCPlayer GetPlayer() {
|
public TBMCPlayerBase GetPlayer() {
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,18 @@
|
||||||
package buttondevteam.lib;
|
package buttondevteam.lib.player;
|
||||||
|
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
public class TBMCPlayerLoadEvent extends Event {
|
public class TBMCPlayerLoadEvent extends Event {
|
||||||
private static final HandlerList handlers = new HandlerList();
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
private YamlConfiguration yaml;
|
private TBMCPlayerBase player;
|
||||||
private TBMCPlayer player;
|
|
||||||
|
|
||||||
public TBMCPlayerLoadEvent(YamlConfiguration yaml, TBMCPlayer player) {
|
public TBMCPlayerLoadEvent(TBMCPlayerBase player) {
|
||||||
this.yaml = yaml;
|
|
||||||
this.player = player;
|
this.player = player;
|
||||||
}
|
}
|
||||||
|
|
||||||
public YamlConfiguration GetPlayerConfig() {
|
public TBMCPlayerBase GetPlayer() {
|
||||||
return yaml;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TBMCPlayer GetPlayer() {
|
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package buttondevteam.lib;
|
package buttondevteam.lib.player;
|
||||||
|
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
|
@ -6,13 +6,13 @@ import org.bukkit.event.HandlerList;
|
||||||
public class TBMCPlayerQuitEvent extends Event {
|
public class TBMCPlayerQuitEvent extends Event {
|
||||||
private static final HandlerList handlers = new HandlerList();
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
private TBMCPlayer player;
|
private TBMCPlayerBase player;
|
||||||
|
|
||||||
public TBMCPlayerQuitEvent(TBMCPlayer player) {
|
public TBMCPlayerQuitEvent(TBMCPlayerBase player) {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TBMCPlayer GetPlayer() {
|
public TBMCPlayerBase GetPlayer() {
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,18 @@
|
||||||
package buttondevteam.lib;
|
package buttondevteam.lib.player;
|
||||||
|
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
public class TBMCPlayerSaveEvent extends Event {
|
public class TBMCPlayerSaveEvent extends Event {
|
||||||
private static final HandlerList handlers = new HandlerList();
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
private YamlConfiguration yaml;
|
private TBMCPlayerBase player;
|
||||||
private TBMCPlayer player;
|
|
||||||
|
|
||||||
public TBMCPlayerSaveEvent(YamlConfiguration yaml, TBMCPlayer player) {
|
public TBMCPlayerSaveEvent(TBMCPlayerBase player) {
|
||||||
this.yaml = yaml;
|
|
||||||
this.player = player;
|
this.player = player;
|
||||||
}
|
}
|
||||||
|
|
||||||
public YamlConfiguration GetPlayerConfig() {
|
public TBMCPlayerBase GetPlayer() {
|
||||||
return yaml;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TBMCPlayer GetPlayer() {
|
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package buttondevteam.lib;
|
package buttondevteam.lib.player;
|
||||||
|
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
23
src/main/java/buttondevteam/lib/player/UserClass.java
Normal file
23
src/main/java/buttondevteam/lib/player/UserClass.java
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
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 can be instantiated. For Minecraft data, use {@link PlayerClass}
|
||||||
|
*
|
||||||
|
* @author NorbiPeti
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Inherited
|
||||||
|
public @interface UserClass {
|
||||||
|
/**
|
||||||
|
* Indicates which folder should the player files be saved in.
|
||||||
|
*/
|
||||||
|
String foldername();
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package buttondevteam.lib;
|
package buttondevteam.lib.potato;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
|
@ -1,4 +1,4 @@
|
||||||
package buttondevteam.lib;
|
package buttondevteam.lib.potato;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
46
src/test/java/buttondevteam/core/PlayerDataTest.java
Normal file
46
src/test/java/buttondevteam/core/PlayerDataTest.java
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package buttondevteam.core;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import buttondevteam.core.TestPlayerClass.TestEnum;
|
||||||
|
import buttondevteam.lib.player.TBMCPlayerBase;
|
||||||
|
import junit.framework.Test;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
public class PlayerDataTest extends TestCase {
|
||||||
|
public PlayerDataTest() {
|
||||||
|
super("Player data test");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the suite of tests being tested
|
||||||
|
*/
|
||||||
|
public static Test suite() {
|
||||||
|
return new TestSuite(PlayerDataTest.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testConfig() {
|
||||||
|
TestPrepare.PrepareServer();
|
||||||
|
UUID uuid = new UUID(0L, 0L);
|
||||||
|
try (TestPlayerClass p = TBMCPlayerBase.getPlayer(uuid, TestPlayerClass.class)) {
|
||||||
|
p.PlayerName().set("Test");
|
||||||
|
assertEquals("Test", p.PlayerName().get());
|
||||||
|
p.testenum().set(TestEnum.A);
|
||||||
|
assertEquals(TestEnum.A, p.testenum().get());
|
||||||
|
// p.TestShort().set((short) 5);
|
||||||
|
// assertEquals((short) 5, (short) (int) p.TestShort().get());
|
||||||
|
p.TestBool().set(true);
|
||||||
|
assertEquals(true, (boolean) p.TestBool().get());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
try (TestPlayerClass p = TBMCPlayerBase.getPlayer(uuid, TestPlayerClass.class)) {
|
||||||
|
assertEquals("Test", p.PlayerName().get());
|
||||||
|
assertEquals(TestEnum.A, p.testenum().get());
|
||||||
|
// assertEquals((short) 5, (short) p.TestShort().get());
|
||||||
|
assertEquals(true, (boolean) p.TestBool().get());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
src/test/java/buttondevteam/core/TestPlayerClass.java
Normal file
25
src/test/java/buttondevteam/core/TestPlayerClass.java
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package buttondevteam.core;
|
||||||
|
|
||||||
|
import buttondevteam.lib.player.EnumPlayerData;
|
||||||
|
import buttondevteam.lib.player.PlayerClass;
|
||||||
|
import buttondevteam.lib.player.PlayerData;
|
||||||
|
import buttondevteam.lib.player.TBMCPlayerBase;
|
||||||
|
|
||||||
|
@PlayerClass(pluginname = "TestPlugin")
|
||||||
|
public class TestPlayerClass extends TBMCPlayerBase {
|
||||||
|
public EnumPlayerData<TestEnum> testenum() {
|
||||||
|
return dataEnum(TestEnum.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TestEnum {
|
||||||
|
A, B
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerData<Short> TestShort() {
|
||||||
|
return data();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerData<Boolean> TestBool() {
|
||||||
|
return data();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue