diff --git a/Chroma-Core/pom.xml b/Chroma-Core/pom.xml
index 219be89..104f341 100755
--- a/Chroma-Core/pom.xml
+++ b/Chroma-Core/pom.xml
@@ -248,7 +248,7 @@
github
UTF-8
1.0.1
- 1.8.10
+ 1.8.20
https://github.com/TBMCPlugins/mvn-repo
diff --git a/Chroma-Core/src/main/java/buttondevteam/core/MainPlugin.kt b/Chroma-Core/src/main/java/buttondevteam/core/MainPlugin.kt
index a830b9f..7628897 100755
--- a/Chroma-Core/src/main/java/buttondevteam/core/MainPlugin.kt
+++ b/Chroma-Core/src/main/java/buttondevteam/core/MainPlugin.kt
@@ -26,17 +26,10 @@ import org.bukkit.command.Command
import org.bukkit.command.CommandSender
import org.bukkit.command.ConsoleCommandSender
import org.bukkit.entity.Player
-import org.bukkit.plugin.Plugin
-import java.io.File
-import java.io.IOException
-import java.nio.file.Files
import java.util.*
-import java.util.function.Function
import java.util.function.Supplier
-import java.util.logging.Logger
class MainPlugin : ButtonPlugin() {
- private var logger: Logger? = null
private var economy: Economy? = null
/**
@@ -45,12 +38,6 @@ class MainPlugin : ButtonPlugin() {
*/
var isChatHandlerEnabled = true
- /**
- * Sets whether the plugin should write a list of installed plugins in a txt file.
- * It can be useful if some other software needs to know the plugins.
- */
- private val writePluginList = iConfig.getData("writePluginList", false)
-
/**
* The chat format to use for messages from other platforms if Chroma-Chat is not installed.
*/
@@ -68,12 +55,11 @@ class MainPlugin : ButtonPlugin() {
*/
val prioritizeCustomCommands = iConfig.getData("prioritizeCustomCommands", false)
public override fun pluginEnable() {
- Instance = this
+ instance = this
val pdf = description
- logger = getLogger()
if (!setupPermissions()) throw NullPointerException("No permission plugin found!")
if (!setupEconomy()) //Though Essentials always provides economy, but we don't require Essentials
- getLogger().warning("No economy plugin found! Components using economy will not be registered.")
+ logger.warning("No economy plugin found! Components using economy will not be registered.")
saveConfig()
registerComponent(this, RestartComponent())
registerComponent(this, ChannelComponent())
@@ -125,31 +111,20 @@ class MainPlugin : ButtonPlugin() {
TBMCChatAPI.RegisterChatChannel(ChatRoom("§aGREEN§f", Color.Green, "green"))
TBMCChatAPI.RegisterChatChannel(ChatRoom("§bBLUE§f", Color.Blue, "blue"))
TBMCChatAPI.RegisterChatChannel(ChatRoom("§5PURPLE§f", Color.DarkPurple, "purple"))
- val playerSupplier = Supplier { Bukkit.getOnlinePlayers().map { obj: Player -> obj.name }.asIterable() }
- command2MC.addParamConverter(OfflinePlayer::class.java, { name: String? ->
- Bukkit.getOfflinePlayer(
- name!!
- )
- }, "Player not found!", playerSupplier)
- command2MC.addParamConverter(
- Player::class.java, Function { name: String ->
- Bukkit.getPlayer(name)
- }, "Online player not found!", playerSupplier
+ val playerSupplier = Supplier { Bukkit.getOnlinePlayers().map { obj -> obj.name }.asIterable() }
+ command2MC.addParamConverter(
+ OfflinePlayer::class.java,
+ { name -> Bukkit.getOfflinePlayer(name) },
+ "Player not found!",
+ playerSupplier
)
- if (writePluginList.get()) {
- try {
- Files.write(File("plugins", "plugins.txt").toPath(), Iterable {
- Arrays.stream(Bukkit.getPluginManager().plugins)
- .map { p: Plugin -> p.dataFolder.name as CharSequence }
- .iterator()
- })
- } catch (e: IOException) {
- TBMCCoreAPI.SendException("Failed to write plugin list!", e, this)
- }
- }
- if (server.pluginManager.isPluginEnabled("Essentials")) ess = getPlugin(
- Essentials::class.java
+ command2MC.addParamConverter(
+ Player::class.java,
+ { name -> Bukkit.getPlayer(name) },
+ "Online player not found!",
+ playerSupplier
)
+ if (server.pluginManager.isPluginEnabled("Essentials")) ess = getPlugin(Essentials::class.java)
logger!!.info(pdf.name + " has been Enabled (V." + pdf.version + ") Test: " + test.get() + ".")
}
@@ -182,8 +157,7 @@ class MainPlugin : ButtonPlugin() {
}
companion object {
- @JvmField
- var Instance: MainPlugin = null
+ lateinit var instance: MainPlugin
@JvmField
var permission: Permission? = null
diff --git a/Chroma-Core/src/main/java/buttondevteam/core/component/channel/ChannelComponent.kt b/Chroma-Core/src/main/java/buttondevteam/core/component/channel/ChannelComponent.kt
index 7735410..deea2e9 100644
--- a/Chroma-Core/src/main/java/buttondevteam/core/component/channel/ChannelComponent.kt
+++ b/Chroma-Core/src/main/java/buttondevteam/core/component/channel/ChannelComponent.kt
@@ -1,83 +1,69 @@
-package buttondevteam.core.component.channel;
+package buttondevteam.core.component.channel
-import buttondevteam.lib.ChromaUtils;
-import buttondevteam.lib.TBMCSystemChatEvent;
-import buttondevteam.lib.architecture.Component;
-import buttondevteam.lib.chat.*;
-import buttondevteam.lib.player.ChromaGamerBase;
-import lombok.RequiredArgsConstructor;
-import org.bukkit.plugin.java.JavaPlugin;
+import buttondevteam.core.MainPlugin
+import buttondevteam.lib.ChromaUtils
+import buttondevteam.lib.TBMCSystemChatEvent.BroadcastTarget
+import buttondevteam.lib.architecture.Component
+import buttondevteam.lib.chat.*
+import buttondevteam.lib.chat.Command2.*
+import buttondevteam.lib.player.ChromaGamerBase
+import org.bukkit.plugin.java.JavaPlugin
/**
* Manages chat channels. If disabled, only global channels will be registered.
*/
-public class ChannelComponent extends Component {
- static TBMCSystemChatEvent.BroadcastTarget roomJoinLeave;
+class ChannelComponent : Component() {
+ override fun register(plugin: JavaPlugin) {
+ super.register(plugin)
+ roomJoinLeave = BroadcastTarget.add("roomJoinLeave") //Even if it's disabled, global channels continue to work
+ }
- @Override
- protected void register(JavaPlugin plugin) {
- super.register(plugin);
- roomJoinLeave = TBMCSystemChatEvent.BroadcastTarget.add("roomJoinLeave"); //Even if it's disabled, global channels continue to work
- }
+ override fun unregister(plugin: JavaPlugin) {
+ super.unregister(plugin)
+ BroadcastTarget.remove(roomJoinLeave)
+ roomJoinLeave = null
+ }
- @Override
- protected void unregister(JavaPlugin plugin) {
- super.unregister(plugin);
- TBMCSystemChatEvent.BroadcastTarget.remove(roomJoinLeave);
- roomJoinLeave = null;
- }
+ override fun enable() {}
+ override fun disable() {}
+ fun registerChannelCommand(channel: Channel) {
+ if (!ChromaUtils.isTest()) registerCommand(ChannelCommand(channel))
+ }
- @Override
- protected void enable() {
- }
+ @CommandClass
+ private class ChannelCommand(private val channel: Channel) : ICommand2MC() {
+ override fun getCommandPath(): String {
+ return channel.identifier
+ }
- @Override
- protected void disable() {
- }
+ override fun getCommandPaths(): Array {
+ return channel.extraIdentifiers.get().toTypedArray()
+ }
- void registerChannelCommand(Channel channel) {
- if (!ChromaUtils.isTest())
- registerCommand(new ChannelCommand(channel));
- }
+ @Subcommand
+ fun def(senderMC: Command2MCSender, @OptionalArg @TextArg message: String?) {
+ val sender = senderMC.sender
+ val user = ChromaGamerBase.getFromSender(sender)
+ if (user == null) {
+ sender.sendMessage("§cYou can't use channels from this platform.")
+ return
+ }
+ if (message == null) {
+ val oldch = user.channel.get()
+ if (oldch is ChatRoom) oldch.leaveRoom(sender)
+ if (oldch == channel) user.channel.set(Channel.GlobalChat) else {
+ user.channel.set(channel)
+ if (channel is ChatRoom) channel.joinRoom(sender)
+ }
+ sender.sendMessage("§6You are now talking in: §b" + user.channel.get().displayName.get())
+ } else TBMCChatAPI.SendChatMessage(
+ ChatMessage.builder(sender, user, message).fromCommand(true)
+ .permCheck(senderMC.permCheck).build(), channel
+ )
+ }
+ }
- @CommandClass
- @RequiredArgsConstructor
- private static class ChannelCommand extends ICommand2MC {
- private final Channel channel;
-
- @Override
- public String getCommandPath() {
- return channel.identifier;
- }
-
- @Override
- public String[] getCommandPaths() {
- return channel.extraIdentifiers.get();
- }
-
- @Command2.Subcommand
- public void def(Command2MCSender senderMC, @Command2.OptionalArg @Command2.TextArg String message) {
- var sender = senderMC.getSender();
- var user = ChromaGamerBase.getFromSender(sender);
- if (user == null) {
- sender.sendMessage("§cYou can't use channels from this platform.");
- return;
- }
- if (message == null) {
- Channel oldch = user.channel.get();
- if (oldch instanceof ChatRoom)
- ((ChatRoom) oldch).leaveRoom(sender);
- if (oldch.equals(channel))
- user.channel.set(Channel.GlobalChat);
- else {
- user.channel.set(channel);
- if (channel instanceof ChatRoom)
- ((ChatRoom) channel).joinRoom(sender);
- }
- sender.sendMessage("§6You are now talking in: §b" + user.channel.get().displayName.get());
- } else
- TBMCChatAPI.SendChatMessage(ChatMessage.builder(sender, user, message).fromCommand(true)
- .permCheck(senderMC.getPermCheck()).build(), channel);
- }
- }
-}
+ companion object {
+ var roomJoinLeave: BroadcastTarget? = null
+ }
+}
\ No newline at end of file
diff --git a/Chroma-Core/src/main/java/buttondevteam/core/component/members/MemberCommand.java b/Chroma-Core/src/main/java/buttondevteam/core/component/members/MemberCommand.java
index 1d7fd87..318a52c 100644
--- a/Chroma-Core/src/main/java/buttondevteam/core/component/members/MemberCommand.java
+++ b/Chroma-Core/src/main/java/buttondevteam/core/component/members/MemberCommand.java
@@ -33,7 +33,7 @@ public class MemberCommand extends ICommand2MC {
}
public boolean addRemove(CommandSender sender, OfflinePlayer op, boolean add) {
- Bukkit.getScheduler().runTaskAsynchronously(MainPlugin.Instance, () -> {
+ Bukkit.getScheduler().runTaskAsynchronously(MainPlugin.instance, () -> {
if (!op.hasPlayedBefore()) {
sender.sendMessage("§cCannot find player or haven't played before.");
return;
diff --git a/Chroma-Core/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java b/Chroma-Core/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java
index e798091..6ccb05c 100755
--- a/Chroma-Core/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java
+++ b/Chroma-Core/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java
@@ -51,7 +51,7 @@ public class ScheduledRestartCommand extends ICommand2MC {
sender.sendMessage("Scheduled restart in " + seconds);
ScheduledServerRestartEvent e = new ScheduledServerRestartEvent(restarttime, this);
Bukkit.getPluginManager().callEvent(e);
- restarttask = Bukkit.getScheduler().runTaskTimer(MainPlugin.Instance, () -> {
+ restarttask = Bukkit.getScheduler().runTaskTimer(MainPlugin.instance, () -> {
if (restartCounter < 0) {
restarttask.cancel();
restartbar.getPlayers().forEach(p -> restartbar.removePlayer(p));
diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/ChromaUtils.java b/Chroma-Core/src/main/java/buttondevteam/lib/ChromaUtils.java
index ef818c9..da43f2d 100644
--- a/Chroma-Core/src/main/java/buttondevteam/lib/ChromaUtils.java
+++ b/Chroma-Core/src/main/java/buttondevteam/lib/ChromaUtils.java
@@ -81,7 +81,7 @@ public final class ChromaUtils {
*/
public static T doItAsync(Supplier what, T def) {
if (Bukkit.isPrimaryThread())
- Bukkit.getScheduler().runTaskAsynchronously(MainPlugin.Instance, what::get);
+ Bukkit.getScheduler().runTaskAsynchronously(MainPlugin.instance, what::get);
else
return what.get();
return def;
diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/TBMCCoreAPI.java b/Chroma-Core/src/main/java/buttondevteam/lib/TBMCCoreAPI.java
index aa83020..8c8c05a 100755
--- a/Chroma-Core/src/main/java/buttondevteam/lib/TBMCCoreAPI.java
+++ b/Chroma-Core/src/main/java/buttondevteam/lib/TBMCCoreAPI.java
@@ -170,7 +170,7 @@ public class TBMCCoreAPI {
}
public static boolean IsTestServer() {
- if (MainPlugin.Instance == null) return true;
- return MainPlugin.Instance.test.get();
+ if (MainPlugin.instance == null) return true;
+ return MainPlugin.instance.test.get();
}
}
\ No newline at end of file
diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ConfigData.kt b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ConfigData.kt
index b2c3006..d9d871f 100644
--- a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ConfigData.kt
+++ b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ConfigData.kt
@@ -67,9 +67,9 @@ class ConfigData internal constructor(
return getter.apply(convert(`val`, pdef)).also { value = it }
}
- override fun set(value: T?) {
+ override fun set(value: T?) { // TODO: Have a separate method for removing the value from the config and make this non-nullable
if (readOnly) return //Safety for Discord channel/role data
- val `val` = value?.let { setter.apply(value) }
+ val `val` = value?.let { setter.apply(it) }
setInternal(`val`)
this.value = value
}
@@ -89,14 +89,14 @@ class ConfigData internal constructor(
val sa = config.saveAction
val root = cc.root
if (root == null) {
- MainPlugin.Instance.logger.warning("Attempted to save config with no root! Name: ${config.config.name}")
+ MainPlugin.instance.logger.warning("Attempted to save config with no root! Name: ${config.config.name}")
return
}
if (!saveTasks.containsKey(cc.root)) {
synchronized(saveTasks) {
saveTasks.put(
root,
- SaveTask(Bukkit.getScheduler().runTaskLaterAsynchronously(MainPlugin.Instance, {
+ SaveTask(Bukkit.getScheduler().runTaskLaterAsynchronously(MainPlugin.instance, {
synchronized(saveTasks) {
saveTasks.remove(root)
sa.run()
diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/IHaveConfig.kt b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/IHaveConfig.kt
index 7ef3f09..eaa767d 100644
--- a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/IHaveConfig.kt
+++ b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/IHaveConfig.kt
@@ -179,7 +179,7 @@ class IHaveConfig(
.filter(Predicate> { obj: ConfigData? -> Objects.nonNull(obj) })
.collect(Collectors.toList())
} else {
- if (TBMCCoreAPI.IsTestServer()) MainPlugin.Instance.logger.warning(
+ if (TBMCCoreAPI.IsTestServer()) MainPlugin.instance.logger.warning(
"Method " + mName + " returns a config but its parameters are unknown: " + Arrays.toString(
m.parameterTypes
)
@@ -187,7 +187,7 @@ class IHaveConfig(
continue
}
for (c in configList) {
- if (c.path.length == 0) c.setPath(mName) else if (c.path != mName) MainPlugin.Instance.logger.warning(
+ if (c.path.length == 0) c.setPath(mName) else if (c.path != mName) MainPlugin.instance.logger.warning(
"Config name does not match: " + c.path + " instead of " + mName
)
c.get() //Saves the default value if needed - also checks validity
diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ListConfigData.kt b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ListConfigData.kt
index 41860fa..e17e009 100644
--- a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ListConfigData.kt
+++ b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ListConfigData.kt
@@ -23,7 +23,7 @@ class ListConfigData internal constructor(
listConfig.reset()
}
- override fun get(): List? {
+ override fun get(): List {
return listConfig.get()
}
diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.kt b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.kt
index 91e42ce..b9a8f75 100644
--- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.kt
+++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.kt
@@ -94,7 +94,7 @@ abstract class Command2, TP : Command2Sender>(
return false // Unknown command
}
//Needed because permission checking may load the (perhaps offline) sender's file which is disallowed on the main thread
- Bukkit.getScheduler().runTaskAsynchronously(MainPlugin.Instance) { _ ->
+ Bukkit.getScheduler().runTaskAsynchronously(MainPlugin.instance) { _ ->
try {
dispatcher.execute(results)
} catch (e: CommandSyntaxException) {
@@ -103,7 +103,7 @@ abstract class Command2, TP : Command2Sender>(
TBMCCoreAPI.SendException(
"Command execution failed for sender " + sender.name + "(" + sender.javaClass.canonicalName + ") and message " + commandline,
e,
- MainPlugin.Instance
+ MainPlugin.instance
)
}
}
@@ -140,7 +140,7 @@ abstract class Command2, TP : Command2Sender>(
lastNode.addChild(getExecutableNode(meth, command, ann, remainingPath, CommandArgumentHelpManager(command), fullPath))
if (mainCommandNode == null) mainCommandNode = mainNode
else if (mainNode!!.name != mainCommandNode.name) {
- MainPlugin.Instance.logger.warning("Multiple commands are defined in the same class! This is not supported. Class: " + command.javaClass.simpleName)
+ MainPlugin.instance.logger.warning("Multiple commands are defined in the same class! This is not supported. Class: " + command.javaClass.simpleName)
}
}
if (mainCommandNode == null) {
diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.kt b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.kt
index 08289ee..98a3508 100644
--- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.kt
+++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.kt
@@ -170,8 +170,9 @@ class Command2MC : Command2('/', true), Listener
val i = commandline.indexOf(' ')
val mainpath = commandline.substring(1, if (i == -1) commandline.length else i) //Without the slash
//Our commands aren't PluginCommands, unless it's specified in the plugin.yml
- return if ((!checkPlugin || (MainPlugin.Instance.prioritizeCustomCommands.get() == true))
- || Bukkit.getPluginCommand(mainpath)?.let { it.plugin is ButtonPlugin } != false)
+ return if ((!checkPlugin || (MainPlugin.instance.prioritizeCustomCommands.get() == true))
+ || Bukkit.getPluginCommand(mainpath)?.let { it.plugin is ButtonPlugin } != false
+ )
super.handleCommand(sender, commandline) else false
}
@@ -207,7 +208,11 @@ class Command2MC : Command2('/', true), Listener
private fun executeCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean {
val user = ChromaGamerBase.getFromSender(sender)
if (user == null) {
- TBMCCoreAPI.SendException("Failed to run Bukkit command for user!", Throwable("No Chroma user found"), MainPlugin.Instance)
+ TBMCCoreAPI.SendException(
+ "Failed to run Bukkit command for user!",
+ Throwable("No Chroma user found"),
+ MainPlugin.instance
+ )
sender.sendMessage("§cAn internal error occurred.")
return true
}
@@ -250,9 +255,16 @@ class Command2MC : Command2('/', true), Listener
private fun registerTabcomplete(command2MC: ICommand2MC, commandNode: LiteralCommandNode, bukkitCommand: Command) {
if (commodore == null) {
- commodore = CommodoreProvider.getCommodore(MainPlugin.Instance) //Register all to the Core, it's easier
- commodore.register(LiteralArgumentBuilder.literal("un").redirect(RequiredArgumentBuilder.argument("unsomething",
- StringArgumentType.word()).suggests { context: CommandContext?, builder: SuggestionsBuilder -> builder.suggest("untest").buildFuture() }.build()))
+ commodore = CommodoreProvider.getCommodore(MainPlugin.instance) //Register all to the Core, it's easier
+ commodore.register(LiteralArgumentBuilder.literal("un")
+ .redirect(RequiredArgumentBuilder.argument(
+ "unsomething",
+ StringArgumentType.word()
+ ).suggests { context: CommandContext?, builder: SuggestionsBuilder ->
+ builder.suggest("untest").buildFuture()
+ }.build()
+ )
+ )
}
commodore!!.dispatcher.root.getChild(commandNode.name) // TODO: Probably unnecessary
val customTCmethods = Arrays.stream(command2MC.javaClass.declaredMethods) //val doesn't recognize the type arguments
diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/commands/CommandArgumentHelpManager.kt b/Chroma-Core/src/main/java/buttondevteam/lib/chat/commands/CommandArgumentHelpManager.kt
index f59ff29..74381d2 100644
--- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/commands/CommandArgumentHelpManager.kt
+++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/commands/CommandArgumentHelpManager.kt
@@ -32,18 +32,18 @@ class CommandArgumentHelpManager, TP : Command2Sender>(comman
TBMCCoreAPI.SendException(
"Error while getting command data!",
Exception("Resource not found!"),
- MainPlugin.Instance
+ MainPlugin.instance
)
return@use
}
val config = YamlConfiguration.loadConfiguration(InputStreamReader(str))
commandConfig = config.getConfigurationSection(commandClass.canonicalName.replace('$', '.'))
if (commandConfig == null) {
- MainPlugin.Instance.logger.warning("Failed to get command data for $commandClass! Make sure to use 'clean install' when building the project.")
+ MainPlugin.instance.logger.warning("Failed to get command data for $commandClass! Make sure to use 'clean install' when building the project.")
}
}
} catch (e: IOException) {
- TBMCCoreAPI.SendException("Error while getting command data!", e, MainPlugin.Instance)
+ TBMCCoreAPI.SendException("Error while getting command data!", e, MainPlugin.instance)
}
}
@@ -56,7 +56,7 @@ class CommandArgumentHelpManager, TP : Command2Sender>(comman
fun getParameterHelpForMethod(method: Method): String? {
val cs = commandConfig?.getConfigurationSection(method.name)
if (cs == null) {
- MainPlugin.Instance.logger.warning("Failed to get command data for $method! Make sure to use 'clean install' when building the project.")
+ MainPlugin.instance.logger.warning("Failed to get command data for $method! Make sure to use 'clean install' when building the project.")
return null
}
val mname = cs.getString("method")
@@ -68,7 +68,7 @@ class CommandArgumentHelpManager, TP : Command2Sender>(comman
} else TBMCCoreAPI.SendException(
"Error while getting command data for $method!",
Exception("Method '$method' != $mname or params is $params"),
- MainPlugin.Instance
+ MainPlugin.instance
)
return null
}
diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/player/ChromaGamerBase.kt b/Chroma-Core/src/main/java/buttondevteam/lib/player/ChromaGamerBase.kt
index bb523d0..e209380 100755
--- a/Chroma-Core/src/main/java/buttondevteam/lib/player/ChromaGamerBase.kt
+++ b/Chroma-Core/src/main/java/buttondevteam/lib/player/ChromaGamerBase.kt
@@ -1,317 +1,327 @@
-package buttondevteam.lib.player;
+package buttondevteam.lib.player
-import buttondevteam.core.MainPlugin;
-import buttondevteam.core.component.channel.Channel;
-import buttondevteam.lib.TBMCCoreAPI;
-import buttondevteam.lib.architecture.ConfigData;
-import buttondevteam.lib.architecture.IHaveConfig;
-import lombok.Getter;
-import lombok.val;
-import org.bukkit.Bukkit;
-import org.bukkit.command.CommandSender;
-import org.bukkit.configuration.file.YamlConfiguration;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.Supplier;
+import buttondevteam.core.MainPlugin
+import buttondevteam.core.component.channel.Channel
+import buttondevteam.core.component.channel.Channel.Companion.getChannels
+import buttondevteam.lib.TBMCCoreAPI
+import buttondevteam.lib.architecture.ConfigData
+import buttondevteam.lib.architecture.ConfigData.Companion.saveNow
+import buttondevteam.lib.architecture.IHaveConfig
+import org.bukkit.Bukkit
+import org.bukkit.command.CommandSender
+import org.bukkit.configuration.file.YamlConfiguration
+import java.io.File
+import java.util.*
+import java.util.function.Consumer
+import java.util.function.Function
+import java.util.function.Supplier
@ChromaGamerEnforcer
-public abstract class ChromaGamerBase {
- private static final String TBMC_PLAYERS_DIR = "TBMC/players/";
- private static final ArrayList>> senderConverters = new ArrayList<>();
- /**
- * Holds data per user class
- */
- private static final HashMap, StaticUserData>> staticDataMap = new HashMap<>();
+abstract class ChromaGamerBase {
+ lateinit var config: IHaveConfig
- /**
- * Use {@link #getConfig()} where possible; the 'id' must be always set
- */
- //protected YamlConfiguration plugindata;
+ @JvmField
+ protected var commonUserData: CommonUserData<*>? = null
+ protected open fun init() {
+ config.reset(commonUserData!!.playerData)
+ }
- @Getter
- protected final IHaveConfig config = new IHaveConfig(this::save);
- protected CommonUserData> commonUserData;
+ protected fun updateUserConfig() {}
- /**
- * Used for connecting with every type of user ({@link #connectWith(ChromaGamerBase)}) and to init the configs.
- * Also, to construct an instance if an abstract class is provided.
- */
- public static void RegisterPluginUserClass(Class userclass, Supplier constructor) {
- Class extends T> cl;
- String folderName;
- if (userclass.isAnnotationPresent(UserClass.class)) {
- cl = userclass;
- folderName = userclass.getAnnotation(UserClass.class).foldername();
- } else if (userclass.isAnnotationPresent(AbstractUserClass.class)) {
- var ucl = userclass.getAnnotation(AbstractUserClass.class).prototype();
- if (!userclass.isAssignableFrom(ucl))
- throw new RuntimeException("The prototype class (" + ucl.getSimpleName() + ") must be a subclass of the userclass parameter (" + userclass.getSimpleName() + ")!");
- //noinspection unchecked
- cl = (Class extends T>) ucl;
- folderName = userclass.getAnnotation(AbstractUserClass.class).foldername();
- } else // <-- Really important
- throw new RuntimeException("Class not registered as a user class! Use @UserClass or TBMCPlayerBase");
- var sud = new StaticUserData(folderName);
- sud.getConstructors().put(cl, constructor);
- sud.getConstructors().put(userclass, constructor); // Alawys register abstract and prototype class (TBMCPlayerBase and TBMCPlayer)
- staticDataMap.put(userclass, sud);
- }
+ /**
+ * Saves the player. It'll handle all exceptions that may happen. Called automatically.
+ */
+ protected open fun save() {
+ try {
+ if (commonUserData!!.playerData.getKeys(false).size > 0) commonUserData!!.playerData.save(
+ File(
+ TBMC_PLAYERS_DIR + folder, fileName + ".yml"
+ )
+ )
+ } catch (e: Exception) {
+ TBMCCoreAPI.SendException(
+ "Error while saving player to " + folder + "/" + fileName + ".yml!",
+ e,
+ MainPlugin.instance
+ )
+ }
+ }
- /**
- * 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 String getFolderForType(Class 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");
- }
+ /**
+ * Removes the user from the cache. This will be called automatically after some time by default.
+ */
+ fun uncache() {
+ val userCache: HashMap, out ChromaGamerBase> = commonUserData!!.userCache
+ synchronized(userCache) { if (userCache.containsKey(javaClass)) check(userCache.remove(javaClass) === this) { "A different player instance was cached!" } }
+ }
- /**
- * Returns the player class for the given folder name.
- *
- * @param foldername The folder to get the class from (like "minecraft")
- * @return The type for the given folder name or null if not found
- */
- public static Class extends ChromaGamerBase> getTypeForFolder(String foldername) {
- synchronized (staticDataMap) {
- return staticDataMap.entrySet().stream().filter(e -> e.getValue().getFolder().equalsIgnoreCase(foldername))
- .map(Map.Entry::getKey).findAny().orElse(null);
- }
- }
+ protected open fun scheduleUncache() {
+ Bukkit.getScheduler().runTaskLaterAsynchronously(
+ MainPlugin.instance,
+ Runnable { uncache() },
+ (2 * 60 * 60 * 20).toLong()
+ ) //2 hours
+ }
- /***
- * Retrieves a user from cache or loads it from disk.
- *
- * @param fname Filename without .yml, the user's identifier for that type
- * @param cl User class
- * @return The user object
- */
- public static synchronized T getUser(String fname, Class cl) {
- StaticUserData> staticUserData = null;
- for (var sud : staticDataMap.entrySet()) {
- if (sud.getKey().isAssignableFrom(cl)) {
- staticUserData = sud.getValue();
- break;
- }
- }
- if (staticUserData == null)
- throw new RuntimeException("User class not registered! Use @UserClass or @AbstractUserClass");
- var commonUserData = staticUserData.getUserDataMap().get(fname);
- if (commonUserData == null) {
- final String folder = staticUserData.getFolder();
- final File file = new File(TBMC_PLAYERS_DIR + folder, fname + ".yml");
- file.getParentFile().mkdirs();
- var playerData = YamlConfiguration.loadConfiguration(file);
- commonUserData = new CommonUserData<>(playerData);
- playerData.set(staticUserData.getFolder() + "_id", fname);
- staticUserData.getUserDataMap().put(fname, commonUserData);
- }
- if (commonUserData.getUserCache().containsKey(cl))
- return (T) commonUserData.getUserCache().get(cl);
- T obj;
- if (staticUserData.getConstructors().containsKey(cl))
- //noinspection unchecked
- obj = (T) staticUserData.getConstructors().get(cl).get();
- else {
- try {
- obj = cl.getConstructor().newInstance();
- } catch (Exception e) {
- throw new RuntimeException("Failed to create new instance of user of type " + cl.getSimpleName() + "!", e);
- }
- }
- obj.commonUserData = commonUserData;
- obj.init();
- obj.scheduleUncache();
- return obj;
- }
+ /**
+ * 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
+ */
+ fun connectWith(user: T) {
+ // Set the ID, go through all linked files and connect them as well
+ val ownFolder = folder
+ val userFolder = user!!.folder
+ if (ownFolder.equals(
+ userFolder,
+ ignoreCase = true
+ )
+ ) throw RuntimeException("Do not connect two accounts of the same type! Type: $ownFolder")
+ val ownData = commonUserData!!.playerData
+ val userData = user.commonUserData!!.playerData
+ userData[ownFolder + "_id"] = ownData.getString(ownFolder + "_id")
+ ownData[userFolder + "_id"] = userData.getString(userFolder + "_id")
+ config.signalChange()
+ user.config.signalChange()
+ val sync = Consumer { sourcedata: YamlConfiguration ->
+ val sourcefolder = if (sourcedata === ownData) ownFolder else userFolder
+ val id = sourcedata.getString(sourcefolder + "_id")!!
+ for ((key, value) in staticDataMap) { // Set our ID in all files we can find, both from our connections and the new ones
+ if (key == javaClass || key == user.javaClass) continue
+ val entryFolder = value.folder
+ val otherid = sourcedata.getString(entryFolder + "_id") ?: continue
+ val cg = getUser(otherid, key)!!
+ val cgData = cg.commonUserData!!.playerData
+ cgData[sourcefolder + "_id"] = id // Set new IDs
+ for ((_, value1) in staticDataMap) {
+ val itemFolder = value1.folder
+ if (sourcedata.contains(itemFolder + "_id")) {
+ cgData[itemFolder + "_id"] = sourcedata.getString(itemFolder + "_id") // Set all existing IDs
+ }
+ }
+ cg.config.signalChange()
+ }
+ }
+ sync.accept(ownData)
+ sync.accept(userData)
+ }
- /**
- * Adds a converter to the start of the list.
- *
- * @param converter The converter that returns an object corresponding to the sender or null, if it's not the right type.
- */
- public static void addConverter(Function> converter) {
- senderConverters.add(0, converter);
- }
+ /**
+ * Returns 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
+ */
+ fun getConnectedID(cl: Class): String {
+ return commonUserData!!.playerData.getString(getFolderForType(cl) + "_id")!!
+ }
- /**
- * Get from the given sender. the object's type will depend on the sender's type. May be null, but shouldn't be.
- *
- * @param sender The sender to use
- * @return A user as returned by a converter or null if none can supply it
- */
- public static ChromaGamerBase getFromSender(CommandSender sender) { // TODO: Use Command2Sender
- for (val converter : senderConverters) {
- val ocg = converter.apply(sender);
- if (ocg.isPresent())
- return ocg.get();
- }
- return null;
- }
+ /**
+ * Returns a player instance of the given type that represents the same player. This will return a new instance unless the player is cached.
+ * If the class is a subclass of the current class then the same ID is used, otherwise, a connected ID is used, if found.
+ *
+ * @param cl The target player class
+ * @return The player as a [T] object or null if the user doesn't have an account there
+ */
+ fun getAs(cl: Class): T? {
+ if (cl.simpleName == javaClass.simpleName) return this as T
+ val newfolder = getFolderForType(cl)
+ ?: throw RuntimeException("The specified class " + cl.simpleName + " isn't registered!")
+ if (newfolder == folder) // If in the same folder, the same filename is used
+ return getUser(fileName, cl)
+ val playerData = commonUserData!!.playerData
+ return if (!playerData.contains(newfolder + "_id")) null else getUser(
+ playerData.getString(newfolder + "_id")!!,
+ cl
+ )
+ }
- public static void saveUsers() {
- synchronized (staticDataMap) {
- for (var sud : staticDataMap.values())
- for (var cud : sud.getUserDataMap().values())
- ConfigData.saveNow(cud.getPlayerData()); //Calls save()
- }
- }
+ val fileName: String
+ /**
+ * This method returns the filename for this player data. For example, for Minecraft-related data, MC UUIDs, for Discord data, Discord IDs, etc.
+ * **Does not include .yml**
+ */
+ get() = commonUserData!!.playerData.getString(folder + "_id")!!
+ val folder: String
+ /**
+ * This method returns the folder that this player data is stored in. For example: "minecraft".
+ */
+ get() = getFolderForType(javaClass)
- protected void init() {
- config.reset(commonUserData.getPlayerData());
- }
+ /**
+ * Get player information. This method calls the [TBMCPlayerGetInfoEvent] to get all the player information across the TBMC plugins.
+ *
+ * @param target The [InfoTarget] to return the info for.
+ * @return The player information.
+ */
+ fun getInfo(target: InfoTarget?): String {
+ val event = TBMCPlayerGetInfoEvent(this, target)
+ Bukkit.getServer().pluginManager.callEvent(event)
+ return event.result
+ }
- /**
- * Saves the player. It'll handle all exceptions that may happen. Called automatically.
- */
- protected void save() {
- try {
- if (commonUserData.getPlayerData().getKeys(false).size() > 0)
- commonUserData.getPlayerData().save(new File(TBMC_PLAYERS_DIR + getFolder(), getFileName() + ".yml"));
- } catch (Exception e) {
- TBMCCoreAPI.SendException("Error while saving player to " + getFolder() + "/" + getFileName() + ".yml!", e, MainPlugin.Instance);
- }
- }
+ enum class InfoTarget {
+ MCHover, MCCommand, Discord
+ }
- /**
- * Removes the user from the cache. This will be called automatically after some time by default.
- */
- public void uncache() {
- final var userCache = commonUserData.getUserCache();
- //noinspection SynchronizationOnLocalVariableOrMethodParameter
- synchronized (userCache) {
- if (userCache.containsKey(getClass()))
- if (userCache.remove(getClass()) != this)
- throw new IllegalStateException("A different player instance was cached!");
- }
- }
+ //-----------------------------------------------------------------
+ @JvmField
+ val channel: ConfigData = config.getData("channel", Channel.GlobalChat,
+ { id ->
+ getChannels().filter { ch: Channel -> ch.identifier.equals(id as String, ignoreCase = true) }
+ .findAny().orElse(null)
+ }) { ch -> ch.ID }
- protected void scheduleUncache() {
- Bukkit.getScheduler().runTaskLaterAsynchronously(MainPlugin.Instance, this::uncache, 2 * 60 * 60 * 20); //2 hours
- }
+ companion object {
+ private const val TBMC_PLAYERS_DIR = "TBMC/players/"
+ private val senderConverters = ArrayList>>()
- /**
- * 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 final void connectWith(T user) {
- // Set the ID, go through all linked files and connect them as well
- final String ownFolder = getFolder();
- final String userFolder = user.getFolder();
- if (ownFolder.equalsIgnoreCase(userFolder))
- throw new RuntimeException("Do not connect two accounts of the same type! Type: " + ownFolder);
- var ownData = commonUserData.getPlayerData();
- var userData = user.commonUserData.getPlayerData();
- userData.set(ownFolder + "_id", ownData.getString(ownFolder + "_id"));
- ownData.set(userFolder + "_id", userData.getString(userFolder + "_id"));
- config.signalChange();
- user.config.signalChange();
- Consumer sync = sourcedata -> {
- final String sourcefolder = sourcedata == ownData ? ownFolder : userFolder;
- final String id = sourcedata.getString(sourcefolder + "_id");
- for (val entry : staticDataMap.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;
- var entryFolder = entry.getValue().getFolder();
- final String otherid = sourcedata.getString(entryFolder + "_id");
- if (otherid == null)
- continue;
- ChromaGamerBase cg = getUser(otherid, entry.getKey());
- var cgData = cg.commonUserData.getPlayerData();
- cgData.set(sourcefolder + "_id", id); // Set new IDs
- for (val item : staticDataMap.entrySet()) {
- var itemFolder = item.getValue().getFolder();
- if (sourcedata.contains(itemFolder + "_id")) {
- cgData.set(itemFolder + "_id", sourcedata.getString(itemFolder + "_id")); // Set all existing IDs
- }
- }
- cg.config.signalChange();
- }
- };
- sync.accept(ownData);
- sync.accept(userData);
- }
+ /**
+ * Holds data per user class
+ */
+ private val staticDataMap = HashMap, StaticUserData<*>>()
- /**
- * Returns 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 final String getConnectedID(Class cl) {
- return commonUserData.getPlayerData().getString(getFolderForType(cl) + "_id");
- }
+ /**
+ * Used for connecting with every type of user ([.connectWith]) and to init the configs.
+ * Also, to construct an instance if an abstract class is provided.
+ */
+ @JvmStatic
+ fun RegisterPluginUserClass(userclass: Class, constructor: Supplier?) {
+ val cl: Class
+ val folderName: String
+ if (userclass.isAnnotationPresent(UserClass::class.java)) {
+ cl = userclass
+ folderName = userclass.getAnnotation(UserClass::class.java).foldername
+ } else if (userclass.isAnnotationPresent(AbstractUserClass::class.java)) {
+ val ucl: Class = userclass.getAnnotation(
+ AbstractUserClass::class.java
+ ).prototype
+ if (!userclass.isAssignableFrom(ucl)) throw RuntimeException("The prototype class (" + ucl.simpleName + ") must be a subclass of the userclass parameter (" + userclass.simpleName + ")!")
+ cl = ucl as Class
+ folderName = userclass.getAnnotation(AbstractUserClass::class.java).foldername
+ } else throw RuntimeException("Class not registered as a user class! Use @UserClass or TBMCPlayerBase")
+ val sud = StaticUserData(folderName)
+ sud.constructors[cl] = constructor
+ sud.constructors[userclass] =
+ constructor // Alawys register abstract and prototype class (TBMCPlayerBase and TBMCPlayer)
+ staticDataMap[userclass] = sud
+ }
- /**
- * Returns a player instance of the given type that represents the same player. This will return a new instance unless the player is cached.
- * If the class is a subclass of the current class then the same ID is used, otherwise, a connected ID is used, if found.
- *
- * @param cl The target player class
- * @return The player as a {@link T} object or null if the user doesn't have an account there
- */
- @SuppressWarnings("unchecked")
- @Nullable
- public final T getAs(Class cl) {
- 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);
- var playerData = commonUserData.getPlayerData();
- if (!playerData.contains(newfolder + "_id"))
- return null;
- return getUser(playerData.getString(newfolder + "_id"), cl);
- }
+ /**
+ * Returns the folder name for the given player class.
+ *
+ * @param cl The class to get the folder from (like [TBMCPlayerBase] or one of it's subclasses)
+ * @return The folder name for the given type
+ * @throws RuntimeException If the class doesn't have the [UserClass] annotation.
+ */
+ fun getFolderForType(cl: Class): String {
+ if (cl.isAnnotationPresent(UserClass::class.java)) return cl.getAnnotation(UserClass::class.java).foldername else if (cl.isAnnotationPresent(
+ AbstractUserClass::class.java
+ )
+ ) return cl.getAnnotation(AbstractUserClass::class.java).foldername
+ throw 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, Discord IDs, etc.
- * Does not include .yml
- */
- public final String getFileName() {
- return commonUserData.getPlayerData().getString(getFolder() + "_id");
- }
+ /**
+ * Returns the player class for the given folder name.
+ *
+ * @param foldername The folder to get the class from (like "minecraft")
+ * @return The type for the given folder name or null if not found
+ */
+ fun getTypeForFolder(foldername: String?): Class {
+ synchronized(staticDataMap) {
+ return staticDataMap.entries.stream()
+ .filter { (_, value): Map.Entry, StaticUserData<*>> ->
+ value.folder.equals(
+ foldername,
+ ignoreCase = true
+ )
+ }
+ .map { (key, value) -> java.util.Map.Entry.key }.findAny().orElse(null)
+ }
+ }
- /**
- * This method returns the folder that this player data is stored in. For example: "minecraft".
- */
- public final String getFolder() {
- return getFolderForType(getClass());
- }
+ /***
+ * Retrieves a user from cache or loads it from disk.
+ *
+ * @param fname Filename without .yml, the user's identifier for that type
+ * @param cl User class
+ * @return The user object
+ */
+ @JvmStatic
+ @Synchronized
+ fun getUser(fname: String, cl: Class): T {
+ val staticUserData: StaticUserData<*> = staticDataMap.entries
+ .filter { (key, _) -> key.isAssignableFrom(cl) }
+ .map { (_, value) -> value }
+ .firstOrNull()
+ ?: throw RuntimeException("User class not registered! Use @UserClass or @AbstractUserClass")
- /**
- * 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 final String getInfo(InfoTarget target) {
- TBMCPlayerGetInfoEvent event = new TBMCPlayerGetInfoEvent(this, target);
- Bukkit.getServer().getPluginManager().callEvent(event);
- return event.getResult();
- }
+ @Suppress("UNCHECKED_CAST")
+ val commonUserData: CommonUserData = (staticUserData.userDataMap[fname]
+ ?: run {
+ val folder = staticUserData.folder
+ val file = File(TBMC_PLAYERS_DIR + folder, "$fname.yml")
+ file.parentFile.mkdirs()
+ val playerData = YamlConfiguration.loadConfiguration(file)
+ playerData[staticUserData.folder + "_id"] = fname
+ CommonUserData(playerData)
+ }.also { staticUserData.userDataMap[fname] = it }) as CommonUserData
- public enum InfoTarget {
- MCHover, MCCommand, Discord
- }
+ return if (commonUserData.userCache.containsKey(cl)) commonUserData.userCache[cl] as T
+ else {
+ val obj = createNewUser(cl, staticUserData, commonUserData)
+ commonUserData.userCache[cl] = obj
+ obj
+ }
+ }
- //-----------------------------------------------------------------
+ private fun createNewUser(
+ cl: Class,
+ staticUserData: StaticUserData<*>,
+ commonUserData: CommonUserData<*>
+ ): T {
+ @Suppress("UNCHECKED_CAST")
+ val obj = staticUserData.constructors[cl]?.get() as T? ?: run {
+ try {
+ cl.getConstructor().newInstance()
+ } catch (e: Exception) {
+ throw RuntimeException("Failed to create new instance of user of type ${cl.simpleName}!", e)
+ }
+ }
+ obj.commonUserData = commonUserData
+ obj.init()
+ obj.scheduleUncache()
+ return obj
+ }
- public final ConfigData channel = config.getData("channel", Channel.GlobalChat,
- id -> Channel.getChannels().filter(ch -> ch.identifier.equalsIgnoreCase((String) id)).findAny().orElse(null), ch -> ch.ID);
-}
+ /**
+ * Adds a converter to the start of the list.
+ *
+ * @param converter The converter that returns an object corresponding to the sender or null, if it's not the right type.
+ */
+ fun addConverter(converter: Function>) {
+ senderConverters.add(0, converter)
+ }
+
+ /**
+ * Get from the given sender. the object's type will depend on the sender's type. May be null, but shouldn't be.
+ *
+ * @param sender The sender to use
+ * @return A user as returned by a converter or null if none can supply it
+ */
+ fun getFromSender(sender: CommandSender): ChromaGamerBase? { // TODO: Use Command2Sender
+ for (converter in senderConverters) {
+ val ocg = converter.apply(sender)
+ if (ocg.isPresent) return ocg.get()
+ }
+ return null
+ }
+
+ fun saveUsers() {
+ synchronized(staticDataMap) {
+ for (sud in staticDataMap.values) for (cud in sud.userDataMap.values) saveNow(cud.playerData) //Calls save()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/player/CommonUserData.kt b/Chroma-Core/src/main/java/buttondevteam/lib/player/CommonUserData.kt
index a9b912a..53ff2bb 100644
--- a/Chroma-Core/src/main/java/buttondevteam/lib/player/CommonUserData.kt
+++ b/Chroma-Core/src/main/java/buttondevteam/lib/player/CommonUserData.kt
@@ -1,19 +1,13 @@
-package buttondevteam.lib.player;
+package buttondevteam.lib.player
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-import org.bukkit.configuration.file.YamlConfiguration;
-
-import java.util.HashMap;
+import org.bukkit.configuration.file.YamlConfiguration
/**
* Per user, regardless of actual type
*
* @param The user class, may be abstract
- */
-@Getter
-@RequiredArgsConstructor
-public class CommonUserData {
- private final HashMap, ? extends T> userCache = new HashMap<>();
- private final YamlConfiguration playerData;
-}
+ */
+class CommonUserData(@JvmField val playerData: YamlConfiguration) {
+ @JvmField
+ val userCache: HashMap, out T> = HashMap()
+}
\ No newline at end of file
diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/player/TBMCPlayerBase.java b/Chroma-Core/src/main/java/buttondevteam/lib/player/TBMCPlayerBase.java
index 6f27346..87da8f7 100755
--- a/Chroma-Core/src/main/java/buttondevteam/lib/player/TBMCPlayerBase.java
+++ b/Chroma-Core/src/main/java/buttondevteam/lib/player/TBMCPlayerBase.java
@@ -49,7 +49,7 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase {
else
throw new RuntimeException("Class not defined as player class! Use @PlayerClass");
- var playerData = commonUserData.getPlayerData();
+ var playerData = commonUserData.playerData;
var section = playerData.getConfigurationSection(pluginname);
if (section == null) section = playerData.createSection(pluginname);
config.reset(section);
@@ -76,7 +76,7 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase {
@Override
protected void save() {
- Set keys = commonUserData.getPlayerData().getKeys(false);
+ Set keys = commonUserData.playerData.getKeys(false);
if (keys.size() > 1) // PlayerName is always saved, but we don't need a file for just that
super.save();
}