Player data upgrade complete

Auto-save for each user
ConfigData stuff
Removed player events
This commit is contained in:
Norbi Peti 2020-10-24 23:47:33 +02:00
parent 83ecf7717f
commit 132eba7db6
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
13 changed files with 77 additions and 298 deletions

View file

@ -122,7 +122,7 @@ public class MainPlugin extends ButtonPlugin {
? TBMCPlayer.getPlayer(new UUID(0, 0), TBMCPlayer.class) : null)); //Console & cmdblocks ? TBMCPlayer.getPlayer(new UUID(0, 0), TBMCPlayer.class) : null)); //Console & cmdblocks
ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof Player ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof Player
? TBMCPlayer.getPlayer(((Player) sender).getUniqueId(), TBMCPlayer.class) : null)); //Players, has higher priority ? TBMCPlayer.getPlayer(((Player) sender).getUniqueId(), TBMCPlayer.class) : null)); //Players, has higher priority
TBMCCoreAPI.RegisterUserClass(TBMCPlayerBase.class); TBMCCoreAPI.RegisterUserClass(TBMCPlayerBase.class, TBMCPlayer::new);
TBMCChatAPI.RegisterChatChannel(Channel.GlobalChat = new Channel("§fg§f", Color.White, "g", null)); //The /ooc ID has moved to the config TBMCChatAPI.RegisterChatChannel(Channel.GlobalChat = new Channel("§fg§f", Color.White, "g", null)); //The /ooc ID has moved to the config
TBMCChatAPI.RegisterChatChannel( TBMCChatAPI.RegisterChatChannel(
Channel.AdminChat = new Channel("§cADMIN§f", Color.Red, "a", Channel.inGroupFilter(null))); Channel.AdminChat = new Channel("§cADMIN§f", Color.Red, "a", Channel.inGroupFilter(null)));
@ -153,7 +153,7 @@ public class MainPlugin extends ButtonPlugin {
@Override @Override
public void pluginDisable() { public void pluginDisable() {
logger.info("Saving player data..."); logger.info("Saving player data...");
TBMCPlayerBase.savePlayers(); ChromaGamerBase.saveUsers();
logger.info("Player data saved."); logger.info("Player data saved.");
} }

View file

@ -1,5 +1,6 @@
package buttondevteam.core; package buttondevteam.core;
import buttondevteam.core.component.towny.TownyComponent;
import buttondevteam.lib.*; import buttondevteam.lib.*;
import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.ButtonPlugin;
import buttondevteam.lib.chat.ChatMessage; import buttondevteam.lib.chat.ChatMessage;
@ -28,12 +29,21 @@ public class PlayerListener implements Listener {
@EventHandler(priority = EventPriority.NORMAL) @EventHandler(priority = EventPriority.NORMAL)
public void OnPlayerJoin(PlayerJoinEvent event) { public void OnPlayerJoin(PlayerJoinEvent event) {
TBMCPlayerBase.joinPlayer(event.getPlayer()); var p = event.getPlayer();
TBMCPlayer player = TBMCPlayerBase.getPlayer(p.getUniqueId(), TBMCPlayer.class);
if (player.PlayerName().get() == null) {
player.PlayerName().set(p.getName());
MainPlugin.Instance.getLogger().info("Player name saved: " + player.PlayerName().get());
} else if (!p.getName().equals(player.PlayerName().get())) {
TownyComponent.renameInTowny(player.PlayerName().get(), p.getName());
MainPlugin.Instance.getLogger().info(player.PlayerName().get() + " renamed to " + p.getName());
player.PlayerName().set(p.getName());
}
} }
@EventHandler(priority = EventPriority.NORMAL) @EventHandler(priority = EventPriority.NORMAL)
public void OnPlayerLeave(PlayerQuitEvent event) { public void OnPlayerLeave(PlayerQuitEvent event) {
TBMCPlayerBase.quitPlayer(event.getPlayer()); TBMCPlayerBase.getPlayer(event.getPlayer().getUniqueId(), TBMCPlayer.class).uncache();
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
@ -65,7 +75,7 @@ public class PlayerListener implements Listener {
val ev = new TBMCCommandPreprocessEvent(sender, ch.orElse(Channel.GlobalChat), message, rtr.score, rtr.groupID);*/ val ev = new TBMCCommandPreprocessEvent(sender, ch.orElse(Channel.GlobalChat), message, rtr.score, rtr.groupID);*/
val cg = ChromaGamerBase.getFromSender(sender); val cg = ChromaGamerBase.getFromSender(sender);
if (cg == null) throw new RuntimeException("Couldn't get user from sender for " + sender.getName() + "!"); if (cg == null) throw new RuntimeException("Couldn't get user from sender for " + sender.getName() + "!");
val ev = new TBMCCommandPreprocessEvent(sender, cg.channel().get(), message, sender); val ev = new TBMCCommandPreprocessEvent(sender, cg.channel.get(), message, sender);
Bukkit.getPluginManager().callEvent(ev); Bukkit.getPluginManager().callEvent(ev);
if (ev.isCancelled()) if (ev.isCancelled())
event.setCancelled(true); //Cancel the original event event.setCancelled(true); //Cancel the original event

View file

@ -59,17 +59,17 @@ public class ChannelComponent extends Component {
return; return;
} }
if (message == null) { if (message == null) {
Channel oldch = user.channel().get(); Channel oldch = user.channel.get();
if (oldch instanceof ChatRoom) if (oldch instanceof ChatRoom)
((ChatRoom) oldch).leaveRoom(sender); ((ChatRoom) oldch).leaveRoom(sender);
if (oldch.equals(channel)) if (oldch.equals(channel))
user.channel().set(Channel.GlobalChat); user.channel.set(Channel.GlobalChat);
else { else {
user.channel().set(channel); user.channel.set(channel);
if (channel instanceof ChatRoom) if (channel instanceof ChatRoom)
((ChatRoom) channel).joinRoom(sender); ((ChatRoom) channel).joinRoom(sender);
} }
sender.sendMessage("§6You are now talking in: §b" + user.channel().get().DisplayName().get()); sender.sendMessage("§6You are now talking in: §b" + user.channel.get().DisplayName().get());
} else } else
TBMCChatAPI.SendChatMessage(ChatMessage.builder(sender, user, message).fromCommand(true) TBMCChatAPI.SendChatMessage(ChatMessage.builder(sender, user, message).fromCommand(true)
.permCheck(senderMC.getPermCheck()).build(), channel); .permCheck(senderMC.getPermCheck()).build(), channel);

View file

@ -17,6 +17,7 @@ import java.net.URLConnection;
import java.util.*; import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier;
public class TBMCCoreAPI { public class TBMCCoreAPI {
static final List<String> coders = new ArrayList<String>() { static final List<String> coders = new ArrayList<String>() {
@ -129,8 +130,8 @@ public class TBMCCoreAPI {
EventExceptionHandler.registerEvents(listener, plugin, eventExceptionCoreHandler); EventExceptionHandler.registerEvents(listener, plugin, eventExceptionCoreHandler);
} }
public static <T extends ChromaGamerBase> void RegisterUserClass(Class<T> userclass) { public static <T extends ChromaGamerBase> void RegisterUserClass(Class<T> userclass, Supplier<T> constructor) {
ChromaGamerBase.RegisterPluginUserClass(userclass); ChromaGamerBase.RegisterPluginUserClass(userclass, constructor);
} }
/** /**

View file

@ -250,7 +250,7 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
return true; return true;
} }
//System.out.println("Executing " + label + " which is actually " + command.getName()); //System.out.println("Executing " + label + " which is actually " + command.getName());
handleCommand(new Command2MCSender(sender, user.channel().get(), sender), handleCommand(new Command2MCSender(sender, user.channel.get(), sender),
("/" + command.getName() + " " + String.join(" ", args)).trim(), false); ///trim(): remove space if there are no args ("/" + command.getName() + " " + String.join(" ", args)).trim(), false); ///trim(): remove space if there are no args
return true; return true;
} }

View file

@ -22,7 +22,7 @@ public class TBMCChatAPI {
* @return The event cancelled state * @return The event cancelled state
*/ */
public static boolean SendChatMessage(ChatMessage cm) { public static boolean SendChatMessage(ChatMessage cm) {
return SendChatMessage(cm, cm.getUser().channel().get()); return SendChatMessage(cm, cm.getUser().channel.get());
} }
/** /**

View file

@ -102,7 +102,10 @@ public abstract class ChromaGamerBase {
obj.plugindata = YamlConfiguration.loadConfiguration(file); obj.plugindata = YamlConfiguration.loadConfiguration(file);
obj.plugindata.set(folder + "_id", fname); obj.plugindata.set(folder + "_id", fname);
obj.init(); obj.init();
userCache.computeIfAbsent(cl, key -> new HashMap<>()).put(fname, obj); synchronized (userCache) {
userCache.computeIfAbsent(cl, key -> new HashMap<>()).put(fname, obj);
}
obj.scheduleUncache();
return obj; return obj;
} }
@ -130,10 +133,16 @@ public abstract class ChromaGamerBase {
return null; return null;
} }
public static void saveUsers() {
for (var users : userCache.values())
for (var user : users.values())
ConfigData.saveNow(user.plugindata); //Calls save()
}
/** /**
* Saves the player. It'll handle all exceptions that may happen. * Saves the player. It'll handle all exceptions that may happen. Called automatically.
*/ */
private final void save() { protected void save() {
try { try {
if (plugindata.getKeys(false).size() > 0) if (plugindata.getKeys(false).size() > 0)
plugindata.save(new File(TBMC_PLAYERS_DIR + getFolder(), getFileName() + ".yml")); plugindata.save(new File(TBMC_PLAYERS_DIR + getFolder(), getFileName() + ".yml"));
@ -142,6 +151,18 @@ public abstract class ChromaGamerBase {
} }
} }
public void uncache() {
synchronized (userCache) {
var c = userCache.get(getClass());
if (c != null) if (c.remove(getFileName()) != this)
throw new IllegalStateException("A different player instance was cached!");
}
}
protected void scheduleUncache() {
Bukkit.getScheduler().runTaskLaterAsynchronously(MainPlugin.Instance, this::uncache, 2 * 60 * 60 * 20); //2 hours
}
/** /**
* Connect two accounts. Do not use for connecting two Minecraft accounts or similar. Also make sure you have the "id" tag set * Connect two accounts. Do not use for connecting two Minecraft accounts or similar. Also make sure you have the "id" tag set
* *
@ -243,6 +264,6 @@ public abstract class ChromaGamerBase {
//----------------------------------------------------------------- //-----------------------------------------------------------------
public final ConfigData<Channel> channel = getConfig().getData("channel", Channel.GlobalChat, public final ConfigData<Channel> channel = config.getData("channel", Channel.GlobalChat,
id -> Channel.getChannels().filter(ch -> ch.ID.equalsIgnoreCase((String) id)).findAny().orElse(null), ch -> ch.ID); id -> Channel.getChannels().filter(ch -> ch.ID.equalsIgnoreCase((String) id)).findAny().orElse(null), ch -> ch.ID);
} }

View file

@ -1,37 +0,0 @@
package buttondevteam.lib.player;
import org.bukkit.configuration.file.YamlConfiguration;
public class PlayerData<T> {
private final String name;
private final YamlConfiguration yaml;
private final T def;
public PlayerData(String name, YamlConfiguration yaml, T def) {
this.name = name;
this.yaml = yaml;
this.def = def;
}
@SuppressWarnings("unchecked")
// @Deprecated - What was once enforced (2 days ago from now) vanished now
public T get() {
Object value = yaml.get(name, def);
if (value instanceof Integer) {
if (def instanceof Short) // If the default is Short the value must be as well because both are T
return (T) (Short) ((Integer) value).shortValue();
if (def instanceof Long)
return (T) (Long) ((Integer) value).longValue();
}
return (T) value;
}
public void set(T value) {
yaml.set(name, value);
}
@Override
public String toString() {
return get().toString();
}
}

View file

@ -1,33 +1,21 @@
package buttondevteam.lib.player; package buttondevteam.lib.player;
import buttondevteam.core.MainPlugin; import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.core.component.towny.TownyComponent; import buttondevteam.lib.architecture.IHaveConfig;
import buttondevteam.lib.TBMCCoreAPI; import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@AbstractUserClass(foldername = "minecraft", prototype = TBMCPlayer.class) @AbstractUserClass(foldername = "minecraft", prototype = TBMCPlayer.class)
@TBMCPlayerEnforcer @TBMCPlayerEnforcer
public abstract class TBMCPlayerBase extends ChromaGamerBase { public abstract class TBMCPlayerBase extends ChromaGamerBase {
protected UUID uuid; protected UUID uuid;
private final String pluginname; @Getter
private final IHaveConfig config = new IHaveConfig(this::save);
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");
var section = plugindata.getConfigurationSection(pluginname);
if (section == null) section = plugindata.createSection(pluginname);
config.reset(section);
}
public UUID getUUID() { public UUID getUUID() {
if (uuid == null) if (uuid == null)
@ -35,28 +23,8 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase {
return uuid; return uuid;
} }
public PlayerData<String> PlayerName() { public ConfigData<String> PlayerName() {
return super.data(null); return config.getData("PlayerName", "");
}
/**
* 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(T def) {
return super.data(pluginname, def);
}
/**
* 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, T def) {
return super.dataEnum(pluginname, cl, def);
} }
/** /**
@ -66,93 +34,31 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase {
* @param cl The type of the player * @param cl The type of the player
* @return The requested player object * @return The requested player object
*/ */
@SuppressWarnings("unchecked")
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())) var player = ChromaGamerBase.getUser(uuid.toString(), cl);
return (T) playermap.get(uuid + "-" + cl.getSimpleName()); if (player.uuid.equals(uuid))
try { throw new IllegalStateException("Player UUID differs after converting from and to string...");
T player; return player;
if (playermap.containsKey(uuid + "-" + TBMCPlayer.class.getSimpleName())) {
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);
player.uuid = uuid;
return player;
} catch (Exception e) {
TBMCCoreAPI.SendException("Failed to get player with UUID " + uuid + " and class " + cl.getSimpleName() + "!", e, MainPlugin.Instance);
return null;
}
} }
/** @Override
* Key: UUID-Class public void init() {
*/ super.init();
private static final ConcurrentHashMap<String, TBMCPlayerBase> playermap = new ConcurrentHashMap<>(); uuid = UUID.fromString(getFileName());
/** String pluginname;
* Gets the TBMCPlayer object as a specific plugin player, keeping it's data<br> if (getClass().isAnnotationPresent(PlayerClass.class))
* Make sure to use try-with-resources with this to save the data, as it may need to load the file pluginname = getClass().getAnnotation(PlayerClass.class).pluginname();
* else
* @param cl The TBMCPlayer subclass throw new RuntimeException("Class not defined as player class! Use @PlayerClass");
*/
public <T extends TBMCPlayerBase> T asPluginPlayer(Class<T> cl) { var section = super.plugindata.getConfigurationSection(pluginname);
return getPlayer(uuid, cl); if (section == null) section = super.plugindata.createSection(pluginname);
config.reset(section);
} }
/** @Override
* Only intended to use from ButtonCore protected void scheduleUncache() { //Don't schedule it, it will happen on quit
*/
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);
if (player.PlayerName().get() == null) {
player.PlayerName().set(p.getName());
MainPlugin.Instance.getLogger().info("Player name saved: " + player.PlayerName().get());
} else if (!p.getName().equals(player.PlayerName().get())) {
TownyComponent.renameInTowny(player.PlayerName().get(), p.getName());
MainPlugin.Instance.getLogger().info(player.PlayerName().get() + " renamed to " + p.getName());
player.PlayerName().set(p.getName());
}
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, p));
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, p));
playermap.entrySet().removeIf(entry -> entry.getKey().startsWith(p.getUniqueId().toString()));
}
public static void savePlayers() {
playermap.values().forEach(p -> {
try {
p.close();
} catch (Exception e) {
TBMCCoreAPI.SendException("Error while saving player " + p.PlayerName().get() + " (" + p.getFolder()
+ "/" + p.getFileName() + ")!", e, MainPlugin.Instance);
}
});
} }
/** /**
@ -180,9 +86,9 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase {
} }
@Override @Override
public void close() throws Exception { protected void save() {
Set<String> keys = plugindata.getKeys(false); Set<String> keys = plugindata.getKeys(false);
if (keys.size() > 1) // PlayerName is always saved, but we don't need a file for just that if (keys.size() > 1) // PlayerName is always saved, but we don't need a file for just that
super.close(); super.save();
} }
} }

View file

@ -1,34 +0,0 @@
package buttondevteam.lib.player;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public class TBMCPlayerJoinEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private final TBMCPlayerBase player;
private final Player player_;
public TBMCPlayerJoinEvent(TBMCPlayerBase player, Player player_) {
this.player = player;
this.player_ = player_;
}
public TBMCPlayerBase GetPlayer() {
return player;
}
public Player getPlayer() { // :P
return player_;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View file

@ -1,27 +0,0 @@
package buttondevteam.lib.player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public class TBMCPlayerLoadEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private final TBMCPlayerBase player;
public TBMCPlayerLoadEvent(TBMCPlayerBase player) {
this.player = player;
}
public TBMCPlayerBase GetPlayer() {
return player;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View file

@ -1,34 +0,0 @@
package buttondevteam.lib.player;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public class TBMCPlayerQuitEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private final TBMCPlayerBase player;
private final Player player_;
public TBMCPlayerQuitEvent(TBMCPlayerBase player, Player player_) {
this.player = player;
this.player_ = player_;
}
public TBMCPlayerBase GetPlayer() {
return player;
}
public Player getPlayer() {
return player_;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View file

@ -1,27 +0,0 @@
package buttondevteam.lib.player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public class TBMCPlayerSaveEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private final TBMCPlayerBase player;
public TBMCPlayerSaveEvent(TBMCPlayerBase player) {
this.player = player;
}
public TBMCPlayerBase GetPlayer() {
return player;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}